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