1 /* $NetBSD: tty_subr.c,v 1.11 1994/10/30 21:48:03 cgd 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 #ifdef REAL_CLISTS 42 #include <sys/clist.h> 43 #endif 44 #include <sys/malloc.h> 45 46 /* 47 * At compile time, choose: 48 * There are two ways the TTY_QUOTE bit can be stored. If QBITS is 49 * defined we allocate an array of bits -- 1/8th as much memory but 50 * setbit(), clrbit(), and isset() take more cpu. If QBITS is 51 * undefined, we just use an array of bytes. 52 * 53 * If TTY_QUOTE functionality isn't required by a line discipline, 54 * it can free c_cq and set it to NULL. This speeds things up, 55 * and also does not use any extra memory. This is useful for (say) 56 * a SLIP line discipline that wants a 32K ring buffer for data 57 * but doesn't need quoting. 58 */ 59 #define QBITS 60 61 #ifdef QBITS 62 #define QMEM(n) ((((n)-1)/NBBY)+1) 63 #else 64 #define QMEM(n) (n) 65 #endif 66 67 68 /* 69 * Initialize clists. 70 */ 71 void 72 cinit() 73 { 74 } 75 76 /* 77 * Initialize a particular clist. Ok, they are really ring buffers, 78 * of the specified length, with/without quoting support. 79 */ 80 int 81 clalloc(clp, size, quot) 82 struct clist *clp; 83 int size; 84 int quot; 85 { 86 87 MALLOC(clp->c_cs, u_char *, size, M_TTYS, M_WAITOK); 88 if (!clp->c_cs) 89 return (-1); 90 bzero(clp->c_cs, size); 91 92 if(quot) { 93 MALLOC(clp->c_cq, u_char *, QMEM(size), M_TTYS, M_WAITOK); 94 if (!clp->c_cq) { 95 FREE(clp->c_cs, M_TTYS); 96 return (-1); 97 } 98 bzero(clp->c_cs, QMEM(size)); 99 } else 100 clp->c_cq = (u_char *)0; 101 102 clp->c_cf = clp->c_cl = (u_char *)0; 103 clp->c_ce = clp->c_cs + size; 104 clp->c_cn = size; 105 clp->c_cc = 0; 106 return (0); 107 } 108 109 void 110 clfree(clp) 111 struct clist *clp; 112 { 113 if(clp->c_cs) 114 FREE(clp->c_cs, M_TTYS); 115 if(clp->c_cq) 116 FREE(clp->c_cq, M_TTYS); 117 clp->c_cs = clp->c_cq = (u_char *)0; 118 } 119 120 121 /* 122 * Get a character from a clist. 123 */ 124 int 125 getc(clp) 126 struct clist *clp; 127 { 128 register int c = -1; 129 int s; 130 131 s = spltty(); 132 if (clp->c_cc == 0) 133 goto out; 134 135 c = *clp->c_cf & 0xff; 136 if (clp->c_cq) { 137 #ifdef QBITS 138 if (isset(clp->c_cq, clp->c_cf - clp->c_cs) ) 139 c |= TTY_QUOTE; 140 #else 141 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) 142 c |= TTY_QUOTE; 143 #endif 144 } 145 if (++clp->c_cf == clp->c_ce) 146 clp->c_cf = clp->c_cs; 147 if (--clp->c_cc == 0) 148 clp->c_cf = clp->c_cl = (u_char *)0; 149 out: 150 splx(s); 151 return c; 152 } 153 154 /* 155 * Copy clist to buffer. 156 * Return number of bytes moved. 157 */ 158 int 159 q_to_b(clp, cp, count) 160 struct clist *clp; 161 u_char *cp; 162 int count; 163 { 164 register int cc; 165 u_char *p = cp; 166 int s; 167 168 s = spltty(); 169 /* optimize this while loop */ 170 while (count > 0 && clp->c_cc > 0) { 171 cc = clp->c_cl - clp->c_cf; 172 if (clp->c_cf >= clp->c_cl) 173 cc = clp->c_ce - clp->c_cf; 174 if (cc > count) 175 cc = count; 176 bcopy(clp->c_cf, p, cc); 177 count -= cc; 178 p += cc; 179 clp->c_cc -= cc; 180 clp->c_cf += cc; 181 if (clp->c_cf == clp->c_ce) 182 clp->c_cf = clp->c_cs; 183 } 184 if (clp->c_cc == 0) 185 clp->c_cf = clp->c_cl = (u_char *)0; 186 splx(s); 187 return p - cp; 188 } 189 190 /* 191 * Return count of contiguous characters in clist. 192 * Stop counting if flag&character is non-null. 193 */ 194 ndqb(clp, flag) 195 struct clist *clp; 196 int flag; 197 { 198 int count = 0; 199 register int i; 200 register int cc; 201 int s; 202 203 s = spltty(); 204 if ((cc = clp->c_cc) == 0) 205 goto out; 206 207 if (flag == 0) { 208 count = clp->c_cl - clp->c_cf; 209 if (count <= 0) 210 count = clp->c_ce - clp->c_cf; 211 goto out; 212 } 213 214 i = clp->c_cf - clp->c_cs; 215 if (flag & TTY_QUOTE) { 216 while (cc-- > 0 && !(clp->c_cs[i++] & (flag & ~TTY_QUOTE) || 217 isset(clp->c_cq, i))) { 218 count++; 219 if (i == clp->c_cn) 220 break; 221 } 222 } else { 223 while (cc-- > 0 && !(clp->c_cs[i++] & flag)) { 224 count++; 225 if (i == clp->c_cn) 226 break; 227 } 228 } 229 out: 230 splx(s); 231 return count; 232 } 233 234 /* 235 * Flush count bytes from clist. 236 */ 237 void 238 ndflush(clp, count) 239 struct clist *clp; 240 int count; 241 { 242 register int cc; 243 int s; 244 245 s = spltty(); 246 if (count == clp->c_cc) { 247 clp->c_cc = 0; 248 clp->c_cf = clp->c_cl = (u_char *)0; 249 goto out; 250 } 251 /* optimize this while loop */ 252 while (count > 0 && clp->c_cc > 0) { 253 cc = clp->c_cl - clp->c_cf; 254 if (clp->c_cf >= clp->c_cl) 255 cc = clp->c_ce - clp->c_cf; 256 if (cc > count) 257 cc = count; 258 count -= cc; 259 clp->c_cc -= cc; 260 clp->c_cf += cc; 261 if (clp->c_cf == clp->c_ce) 262 clp->c_cf = clp->c_cs; 263 } 264 if (clp->c_cc == 0) 265 clp->c_cf = clp->c_cl = (u_char *)0; 266 out: 267 splx(s); 268 } 269 270 /* 271 * Put a character into the output queue. 272 */ 273 int 274 putc(c, clp) 275 int c; 276 struct clist *clp; 277 { 278 register u_char *q; 279 register int i; 280 int r = -1; 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 register 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 u_char *cp; 371 int count; 372 struct clist *clp; 373 { 374 register int i, cc; 375 register u_char *p = cp; 376 int off, 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 bcopy(p, clp->c_cl, cc); 404 if (clp->c_cq) { 405 #ifdef QBITS 406 clrbits(clp->c_cq, clp->c_cl - clp->c_cs, cc); 407 #else 408 bzero(clp->c_cl - clp->c_cs + clp->c_cq, 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 register 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 int empty = 0; 481 register u_char *cp; 482 register int i; 483 484 cc = clp->c_cc; 485 if (cc == 0) 486 return NULL; 487 cp = clp->c_cf; 488 *c = *cp & 0xff; 489 if(clp->c_cq) { 490 #ifdef QBITS 491 if (isset(clp->c_cq, cp - clp->c_cs)) 492 *c |= TTY_QUOTE; 493 #else 494 if (*(cp - clp->c_cs + clp->c_cq)) 495 *c |= TTY_QUOTE; 496 #endif 497 } 498 return clp->c_cf; 499 } 500 501 /* 502 * Remove the last character in the clist and return it. 503 */ 504 int 505 unputc(clp) 506 struct clist *clp; 507 { 508 unsigned int c = -1; 509 int s; 510 511 s = spltty(); 512 if (clp->c_cc == 0) 513 goto out; 514 515 if (clp->c_cl == clp->c_cs) 516 clp->c_cl = clp->c_ce - 1; 517 else 518 --clp->c_cl; 519 clp->c_cc--; 520 521 c = *clp->c_cl & 0xff; 522 if (clp->c_cq) { 523 #ifdef QBITS 524 if (isset(clp->c_cq, clp->c_cl - clp->c_cs)) 525 c |= TTY_QUOTE; 526 #else 527 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) 528 c |= TTY_QUOTE; 529 #endif 530 } 531 if (clp->c_cc == 0) 532 clp->c_cf = clp->c_cl = (u_char *)0; 533 out: 534 splx(s); 535 return c; 536 } 537 538 /* 539 * Put the chars in the from queue on the end of the to queue. 540 */ 541 void 542 catq(from, to) 543 struct clist *from, *to; 544 { 545 int c; 546 547 while ((c = getc(from)) != -1) 548 putc(c, to); 549 } 550