1 /* 2 * Copyright (c) 1993, 1994 Theo de Raadt 3 * All rights reserved. 4 * 5 * Per Lindqvist <pgd@compuram.bbt.se> supplied an almost fully working 6 * set of true clist functions that this is very loosely based on. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Theo de Raadt. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * $Id: tty_subr.c,v 1.7 1994/05/25 10:00:26 deraadt Exp $ 34 */ 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/buf.h> 39 #include <sys/ioctl.h> 40 #include <sys/tty.h> 41 #include <sys/clist.h> 42 #include <sys/malloc.h> 43 44 /* 45 * At compile time, choose: 46 * There are two ways the TTY_QUOTE bit can be stored. If QBITS is 47 * defined we allocate an array of bits -- 1/8th as much memory but 48 * setbit(), clrbit(), and isset() take more cpu. If QBITS is 49 * undefined, we just use an array of bytes. 50 * 51 * If TTY_QUOTE functionality isn't required by a line discipline, 52 * it can free c_cq and set it to NULL. This speeds things up, 53 * and also does not use any extra memory. This is useful for (say) 54 * a SLIP line discipline that wants a 32K ring buffer for data 55 * but doesn't need quoting. 56 */ 57 #define QBITS 58 59 #ifdef QBITS 60 #define QMEM(n) ((((n)-1)/NBBY)+1) 61 #else 62 #define QMEM(n) (n) 63 #endif 64 65 66 /* 67 * Initialize clists. 68 */ 69 void 70 cinit() 71 { 72 } 73 74 /* 75 * Initialize a particular clist. Ok, they are really ring buffers, 76 * of the specified length, with/without quoting support. 77 */ 78 int 79 clalloc(clp, size, quot) 80 struct clist *clp; 81 int size; 82 int quot; 83 { 84 85 MALLOC(clp->c_cs, u_char *, size, M_TTYS, M_WAITOK); 86 if (!clp->c_cs) 87 return (-1); 88 bzero(clp->c_cs, size); 89 90 if(quot) { 91 MALLOC(clp->c_cq, u_char *, QMEM(size), M_TTYS, M_WAITOK); 92 if (!clp->c_cq) { 93 FREE(clp->c_cs, M_TTYS); 94 return (-1); 95 } 96 bzero(clp->c_cs, QMEM(size)); 97 } else 98 clp->c_cq = (u_char *)0; 99 100 clp->c_cf = clp->c_cl = (u_char *)0; 101 clp->c_ce = clp->c_cs + size; 102 clp->c_cn = size; 103 clp->c_cc = 0; 104 return (0); 105 } 106 107 void 108 clfree(clp) 109 struct clist *clp; 110 { 111 if(clp->c_cs) 112 FREE(clp->c_cs, M_TTYS); 113 if(clp->c_cq) 114 FREE(clp->c_cq, M_TTYS); 115 clp->c_cs = clp->c_cq = (u_char *)0; 116 } 117 118 119 /* 120 * Get a character from a clist. 121 */ 122 int 123 getc(clp) 124 struct clist *clp; 125 { 126 register int c = -1; 127 int s; 128 129 s = spltty(); 130 if (clp->c_cc == 0) 131 goto out; 132 133 c = *clp->c_cf & 0xff; 134 if (clp->c_cq) { 135 #ifdef QBITS 136 if (isset(clp->c_cq, clp->c_cf - clp->c_cs) ) 137 c |= TTY_QUOTE; 138 #else 139 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) 140 c |= TTY_QUOTE; 141 #endif 142 } 143 if (++clp->c_cf == clp->c_ce) 144 clp->c_cf = clp->c_cs; 145 if (--clp->c_cc == 0) 146 clp->c_cf = clp->c_cl = (u_char *)0; 147 out: 148 splx(s); 149 return c; 150 } 151 152 /* 153 * Copy clist to buffer. 154 * Return number of bytes moved. 155 */ 156 int 157 q_to_b(clp, cp, count) 158 struct clist *clp; 159 u_char *cp; 160 int count; 161 { 162 register int cc; 163 u_char *p = cp; 164 int s; 165 166 s = spltty(); 167 /* optimize this while loop */ 168 while (count > 0 && clp->c_cc > 0) { 169 cc = clp->c_cl - clp->c_cf; 170 if (clp->c_cf >= clp->c_cl) 171 cc = clp->c_ce - clp->c_cf; 172 if (cc > count) 173 cc = count; 174 bcopy(clp->c_cf, p, cc); 175 count -= cc; 176 p += cc; 177 clp->c_cc -= cc; 178 clp->c_cf += cc; 179 if (clp->c_cf == clp->c_ce) 180 clp->c_cf = clp->c_cs; 181 } 182 if (clp->c_cc == 0) 183 clp->c_cf = clp->c_cl = (u_char *)0; 184 splx(s); 185 return p - cp; 186 } 187 188 /* 189 * Return count of contiguous characters in clist. 190 * Stop counting if flag&character is non-null. 191 */ 192 ndqb(clp, flag) 193 struct clist *clp; 194 int flag; 195 { 196 int count = 0; 197 register int i; 198 register int cc; 199 int s; 200 201 s = spltty(); 202 if ((cc = clp->c_cc) == 0) 203 goto out; 204 205 if (flag == 0) { 206 count = clp->c_cl - clp->c_cf; 207 if (count < 0) 208 count = clp->c_ce - clp->c_cf; 209 goto out; 210 } 211 212 i = clp->c_cf - clp->c_cs; 213 if(flag & TTY_QUOTE) { 214 while (cc-- > 0 && (clp->c_cs[i++] & (flag & ~TTY_QUOTE)) && 215 !isset(clp->c_cq, i)) { 216 count++; 217 if (i == clp->c_cn) 218 break; 219 } 220 } else { 221 while (cc-- > 0 && (clp->c_cs[i++] & flag)) { 222 count++; 223 if (i == clp->c_cn) 224 break; 225 } 226 } 227 out: 228 splx(s); 229 return count; 230 } 231 232 /* 233 * Flush count bytes from clist. 234 */ 235 void 236 ndflush(clp, count) 237 struct clist *clp; 238 int count; 239 { 240 register int cc; 241 int s; 242 243 s = spltty(); 244 if (count == clp->c_cc) { 245 clp->c_cc = 0; 246 clp->c_cf = clp->c_cl = (u_char *)0; 247 goto out; 248 } 249 /* optimize this while loop */ 250 while (count > 0 && clp->c_cc > 0) { 251 cc = clp->c_cl - clp->c_cf; 252 if (clp->c_cf >= clp->c_cl) 253 cc = clp->c_ce - clp->c_cf; 254 if (cc > count) 255 cc = count; 256 count -= cc; 257 clp->c_cc -= cc; 258 clp->c_cf += cc; 259 if (clp->c_cf == clp->c_ce) 260 clp->c_cf = clp->c_cs; 261 } 262 if (clp->c_cc == 0) 263 clp->c_cf = clp->c_cl = (u_char *)0; 264 out: 265 splx(s); 266 } 267 268 /* 269 * Put a character into the output queue. 270 */ 271 int 272 putc(c, clp) 273 int c; 274 struct clist *clp; 275 { 276 register u_char *q; 277 register int i; 278 int r = -1; 279 int s; 280 281 s = spltty(); 282 if (clp->c_cc == clp->c_cn) 283 goto out; 284 285 if (clp->c_cc == 0) { 286 if (!clp->c_cs) { 287 #if defined(DIAGNOSTIC) || 1 288 printf("putc: required clalloc\n"); 289 #endif 290 if(clalloc(clp, 1024, 1)) { 291 out: 292 splx(s); 293 return -1; 294 } 295 } 296 clp->c_cf = clp->c_cl = clp->c_cs; 297 } 298 299 *clp->c_cl = c & 0xff; 300 i = clp->c_cl - clp->c_cs; 301 if (clp->c_cq) { 302 #ifdef QBITS 303 if (c & TTY_QUOTE) 304 setbit(clp->c_cq, i); 305 else 306 clrbit(clp->c_cq, i); 307 #else 308 q = clp->c_cq + i; 309 *q = (c & TTY_QUOTE) ? 1 : 0; 310 #endif 311 } 312 clp->c_cc++; 313 clp->c_cl++; 314 if (clp->c_cl == clp->c_ce) 315 clp->c_cl = clp->c_cs; 316 splx(s); 317 return 0; 318 } 319 320 #ifdef QBITS 321 /* 322 * optimized version of 323 * 324 * for (i = 0; i < len; i++) 325 * clrbit(cp, off + len); 326 */ 327 void 328 clrbits(cp, off, len) 329 u_char *cp; 330 int off; 331 int len; 332 { 333 int sby, sbi, eby, ebi; 334 register int i; 335 u_char mask; 336 337 if(len==1) { 338 clrbit(cp, off); 339 return; 340 } 341 342 sby = off / NBBY; 343 sbi = off % NBBY; 344 eby = (off+len) / NBBY; 345 ebi = (off+len) % NBBY; 346 if (sby == eby) { 347 mask = ((1 << (ebi - sbi)) - 1) << sbi; 348 cp[sby] &= ~mask; 349 } else { 350 mask = (1<<sbi) - 1; 351 cp[sby++] &= mask; 352 353 mask = (1<<ebi) - 1; 354 cp[eby] &= ~mask; 355 356 for (i = sby; i < eby; i++) 357 cp[i] = 0x00; 358 } 359 } 360 #endif 361 362 /* 363 * Copy buffer to clist. 364 * Return number of bytes not transfered. 365 */ 366 int 367 b_to_q(cp, count, clp) 368 u_char *cp; 369 int count; 370 struct clist *clp; 371 { 372 register int i, cc; 373 register u_char *p = cp; 374 int off, s; 375 376 if (count <= 0) 377 return 0; 378 379 s = spltty(); 380 if (clp->c_cc == clp->c_cn) 381 goto out; 382 383 if (clp->c_cc == 0) { 384 if (!clp->c_cs) { 385 #if defined(DIAGNOSTIC) || 1 386 printf("b_to_q: required clalloc\n"); 387 #endif 388 if(clalloc(clp, 1024, 1)) 389 goto out; 390 } 391 clp->c_cf = clp->c_cl = clp->c_cs; 392 } 393 394 /* optimize this while loop */ 395 while (count > 0 && clp->c_cc < clp->c_cn) { 396 cc = clp->c_ce - clp->c_cl; 397 if (clp->c_cf > clp->c_cl) 398 cc = clp->c_cf - clp->c_cl; 399 if (cc > count) 400 cc = count; 401 bcopy(p, clp->c_cl, cc); 402 if (clp->c_cq) { 403 #ifdef QBITS 404 clrbits(clp->c_cq, clp->c_cl - clp->c_cs, cc); 405 #else 406 bzero(clp->c_cl - clp->c_cs + clp->c_cq, cc); 407 #endif 408 } 409 p += cc; 410 count -= cc; 411 clp->c_cc += cc; 412 clp->c_cl += cc; 413 if (clp->c_cl == clp->c_ce) 414 clp->c_cl = clp->c_cs; 415 } 416 out: 417 splx(s); 418 return count; 419 } 420 421 static int cc; 422 423 /* 424 * Given a non-NULL pointer into the clist return the pointer 425 * to the next character in the list or return NULL if no more chars. 426 * 427 * Callers must not allow getc's to happen between firstc's and getc's 428 * so that the pointer becomes invalid. Note that interrupts are NOT 429 * masked. 430 */ 431 u_char * 432 nextc(clp, cp, c) 433 struct clist *clp; 434 register u_char *cp; 435 int *c; 436 { 437 438 if (clp->c_cf == cp) { 439 /* 440 * First time initialization. 441 */ 442 cc = clp->c_cc; 443 } 444 if (cc == 0 || cp == NULL) 445 return NULL; 446 if (--cc == 0) 447 return NULL; 448 if (++cp == clp->c_ce) 449 cp = clp->c_cs; 450 *c = *cp & 0xff; 451 if (clp->c_cq) { 452 #ifdef QBITS 453 if (isset(clp->c_cq, cp - clp->c_cs)) 454 *c |= TTY_QUOTE; 455 #else 456 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) 457 *c |= TTY_QUOTE; 458 #endif 459 } 460 return cp; 461 } 462 463 /* 464 * Given a non-NULL pointer into the clist return the pointer 465 * to the first character in the list or return NULL if no more chars. 466 * 467 * Callers must not allow getc's to happen between firstc's and getc's 468 * so that the pointer becomes invalid. Note that interrupts are NOT 469 * masked. 470 * 471 * *c is set to the NEXT character 472 */ 473 u_char * 474 firstc(clp, c) 475 struct clist *clp; 476 int *c; 477 { 478 int empty = 0; 479 register u_char *cp; 480 register int i; 481 482 cc = clp->c_cc; 483 if (cc == 0) 484 return NULL; 485 cp = clp->c_cf; 486 *c = *cp & 0xff; 487 if(clp->c_cq) { 488 #ifdef QBITS 489 if (isset(clp->c_cq, cp - clp->c_cs)) 490 *c |= TTY_QUOTE; 491 #else 492 if (*(cp - clp->c_cs + clp->c_cq)) 493 *c |= TTY_QUOTE; 494 #endif 495 } 496 return clp->c_cf; 497 } 498 499 /* 500 * Remove the last character in the clist and return it. 501 */ 502 int 503 unputc(clp) 504 struct clist *clp; 505 { 506 unsigned int c = -1; 507 int s; 508 509 s = spltty(); 510 if (clp->c_cc == 0) 511 goto out; 512 513 if (clp->c_cl == clp->c_cs) 514 clp->c_cl = clp->c_ce - 1; 515 else 516 --clp->c_cl; 517 clp->c_cc--; 518 519 c = *clp->c_cl & 0xff; 520 if (clp->c_cq) { 521 #ifdef QBITS 522 if (isset(clp->c_cq, clp->c_cl - clp->c_cs)) 523 c |= TTY_QUOTE; 524 #else 525 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) 526 c |= TTY_QUOTE; 527 #endif 528 } 529 if (clp->c_cc == 0) 530 clp->c_cf = clp->c_cl = (u_char *)0; 531 out: 532 splx(s); 533 return c; 534 } 535 536 /* 537 * Put the chars in the from queue on the end of the to queue. 538 */ 539 void 540 catq(from, to) 541 struct clist *from, *to; 542 { 543 int c; 544 545 while ((c = getc(from)) != -1) 546 putc(c, to); 547 } 548