1 /* $NetBSD: tty_subr.c,v 1.13 1996/02/09 19:00:43 christos 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 void cinit __P((void)); 68 int ndqb __P((struct clist *, int)); 69 int putc __P((int, struct clist *)); 70 #ifdef QBITS 71 void clrbits __P((u_char *, int, int)); 72 #endif 73 int b_to_q __P((u_char *, int, struct clist *)); 74 u_char *firstc __P((struct clist *, int *)); 75 76 /* 77 * Initialize clists. 78 */ 79 void 80 cinit() 81 { 82 } 83 84 /* 85 * Initialize a particular clist. Ok, they are really ring buffers, 86 * of the specified length, with/without quoting support. 87 */ 88 int 89 clalloc(clp, size, quot) 90 struct clist *clp; 91 int size; 92 int quot; 93 { 94 95 MALLOC(clp->c_cs, u_char *, size, M_TTYS, M_WAITOK); 96 if (!clp->c_cs) 97 return (-1); 98 bzero(clp->c_cs, size); 99 100 if(quot) { 101 MALLOC(clp->c_cq, u_char *, QMEM(size), M_TTYS, M_WAITOK); 102 if (!clp->c_cq) { 103 FREE(clp->c_cs, M_TTYS); 104 return (-1); 105 } 106 bzero(clp->c_cs, QMEM(size)); 107 } else 108 clp->c_cq = (u_char *)0; 109 110 clp->c_cf = clp->c_cl = (u_char *)0; 111 clp->c_ce = clp->c_cs + size; 112 clp->c_cn = size; 113 clp->c_cc = 0; 114 return (0); 115 } 116 117 void 118 clfree(clp) 119 struct clist *clp; 120 { 121 if(clp->c_cs) 122 FREE(clp->c_cs, M_TTYS); 123 if(clp->c_cq) 124 FREE(clp->c_cq, M_TTYS); 125 clp->c_cs = clp->c_cq = (u_char *)0; 126 } 127 128 129 /* 130 * Get a character from a clist. 131 */ 132 int 133 getc(clp) 134 struct clist *clp; 135 { 136 register int c = -1; 137 int s; 138 139 s = spltty(); 140 if (clp->c_cc == 0) 141 goto out; 142 143 c = *clp->c_cf & 0xff; 144 if (clp->c_cq) { 145 #ifdef QBITS 146 if (isset(clp->c_cq, clp->c_cf - clp->c_cs) ) 147 c |= TTY_QUOTE; 148 #else 149 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) 150 c |= TTY_QUOTE; 151 #endif 152 } 153 if (++clp->c_cf == clp->c_ce) 154 clp->c_cf = clp->c_cs; 155 if (--clp->c_cc == 0) 156 clp->c_cf = clp->c_cl = (u_char *)0; 157 out: 158 splx(s); 159 return c; 160 } 161 162 /* 163 * Copy clist to buffer. 164 * Return number of bytes moved. 165 */ 166 int 167 q_to_b(clp, cp, count) 168 struct clist *clp; 169 u_char *cp; 170 int count; 171 { 172 register int cc; 173 u_char *p = cp; 174 int s; 175 176 s = spltty(); 177 /* optimize this while loop */ 178 while (count > 0 && clp->c_cc > 0) { 179 cc = clp->c_cl - clp->c_cf; 180 if (clp->c_cf >= clp->c_cl) 181 cc = clp->c_ce - clp->c_cf; 182 if (cc > count) 183 cc = count; 184 bcopy(clp->c_cf, p, cc); 185 count -= cc; 186 p += cc; 187 clp->c_cc -= cc; 188 clp->c_cf += cc; 189 if (clp->c_cf == clp->c_ce) 190 clp->c_cf = clp->c_cs; 191 } 192 if (clp->c_cc == 0) 193 clp->c_cf = clp->c_cl = (u_char *)0; 194 splx(s); 195 return p - cp; 196 } 197 198 /* 199 * Return count of contiguous characters in clist. 200 * Stop counting if flag&character is non-null. 201 */ 202 int 203 ndqb(clp, flag) 204 struct clist *clp; 205 int flag; 206 { 207 int count = 0; 208 register int i; 209 register int cc; 210 int s; 211 212 s = spltty(); 213 if ((cc = clp->c_cc) == 0) 214 goto out; 215 216 if (flag == 0) { 217 count = clp->c_cl - clp->c_cf; 218 if (count <= 0) 219 count = clp->c_ce - clp->c_cf; 220 goto out; 221 } 222 223 i = clp->c_cf - clp->c_cs; 224 if (flag & TTY_QUOTE) { 225 while (cc-- > 0 && !(clp->c_cs[i++] & (flag & ~TTY_QUOTE) || 226 isset(clp->c_cq, i))) { 227 count++; 228 if (i == clp->c_cn) 229 break; 230 } 231 } else { 232 while (cc-- > 0 && !(clp->c_cs[i++] & flag)) { 233 count++; 234 if (i == clp->c_cn) 235 break; 236 } 237 } 238 out: 239 splx(s); 240 return count; 241 } 242 243 /* 244 * Flush count bytes from clist. 245 */ 246 void 247 ndflush(clp, count) 248 struct clist *clp; 249 int count; 250 { 251 register int cc; 252 int s; 253 254 s = spltty(); 255 if (count == clp->c_cc) { 256 clp->c_cc = 0; 257 clp->c_cf = clp->c_cl = (u_char *)0; 258 goto out; 259 } 260 /* optimize this while loop */ 261 while (count > 0 && clp->c_cc > 0) { 262 cc = clp->c_cl - clp->c_cf; 263 if (clp->c_cf >= clp->c_cl) 264 cc = clp->c_ce - clp->c_cf; 265 if (cc > count) 266 cc = count; 267 count -= cc; 268 clp->c_cc -= cc; 269 clp->c_cf += cc; 270 if (clp->c_cf == clp->c_ce) 271 clp->c_cf = clp->c_cs; 272 } 273 if (clp->c_cc == 0) 274 clp->c_cf = clp->c_cl = (u_char *)0; 275 out: 276 splx(s); 277 } 278 279 /* 280 * Put a character into the output queue. 281 */ 282 int 283 putc(c, clp) 284 int c; 285 struct clist *clp; 286 { 287 register int i; 288 int s; 289 290 s = spltty(); 291 if (clp->c_cc == clp->c_cn) 292 goto out; 293 294 if (clp->c_cc == 0) { 295 if (!clp->c_cs) { 296 #if defined(DIAGNOSTIC) || 1 297 printf("putc: required clalloc\n"); 298 #endif 299 if(clalloc(clp, 1024, 1)) { 300 out: 301 splx(s); 302 return -1; 303 } 304 } 305 clp->c_cf = clp->c_cl = clp->c_cs; 306 } 307 308 *clp->c_cl = c & 0xff; 309 i = clp->c_cl - clp->c_cs; 310 if (clp->c_cq) { 311 #ifdef QBITS 312 if (c & TTY_QUOTE) 313 setbit(clp->c_cq, i); 314 else 315 clrbit(clp->c_cq, i); 316 #else 317 q = clp->c_cq + i; 318 *q = (c & TTY_QUOTE) ? 1 : 0; 319 #endif 320 } 321 clp->c_cc++; 322 clp->c_cl++; 323 if (clp->c_cl == clp->c_ce) 324 clp->c_cl = clp->c_cs; 325 splx(s); 326 return 0; 327 } 328 329 #ifdef QBITS 330 /* 331 * optimized version of 332 * 333 * for (i = 0; i < len; i++) 334 * clrbit(cp, off + len); 335 */ 336 void 337 clrbits(cp, off, len) 338 u_char *cp; 339 int off; 340 int len; 341 { 342 int sby, sbi, eby, ebi; 343 register int i; 344 u_char mask; 345 346 if(len==1) { 347 clrbit(cp, off); 348 return; 349 } 350 351 sby = off / NBBY; 352 sbi = off % NBBY; 353 eby = (off+len) / NBBY; 354 ebi = (off+len) % NBBY; 355 if (sby == eby) { 356 mask = ((1 << (ebi - sbi)) - 1) << sbi; 357 cp[sby] &= ~mask; 358 } else { 359 mask = (1<<sbi) - 1; 360 cp[sby++] &= mask; 361 362 mask = (1<<ebi) - 1; 363 cp[eby] &= ~mask; 364 365 for (i = sby; i < eby; i++) 366 cp[i] = 0x00; 367 } 368 } 369 #endif 370 371 /* 372 * Copy buffer to clist. 373 * Return number of bytes not transfered. 374 */ 375 int 376 b_to_q(cp, count, clp) 377 u_char *cp; 378 int count; 379 struct clist *clp; 380 { 381 register int cc; 382 register u_char *p = cp; 383 int s; 384 385 if (count <= 0) 386 return 0; 387 388 s = spltty(); 389 if (clp->c_cc == clp->c_cn) 390 goto out; 391 392 if (clp->c_cc == 0) { 393 if (!clp->c_cs) { 394 #if defined(DIAGNOSTIC) || 1 395 printf("b_to_q: required clalloc\n"); 396 #endif 397 if(clalloc(clp, 1024, 1)) 398 goto out; 399 } 400 clp->c_cf = clp->c_cl = clp->c_cs; 401 } 402 403 /* optimize this while loop */ 404 while (count > 0 && clp->c_cc < clp->c_cn) { 405 cc = clp->c_ce - clp->c_cl; 406 if (clp->c_cf > clp->c_cl) 407 cc = clp->c_cf - clp->c_cl; 408 if (cc > count) 409 cc = count; 410 bcopy(p, clp->c_cl, cc); 411 if (clp->c_cq) { 412 #ifdef QBITS 413 clrbits(clp->c_cq, clp->c_cl - clp->c_cs, cc); 414 #else 415 bzero(clp->c_cl - clp->c_cs + clp->c_cq, cc); 416 #endif 417 } 418 p += cc; 419 count -= cc; 420 clp->c_cc += cc; 421 clp->c_cl += cc; 422 if (clp->c_cl == clp->c_ce) 423 clp->c_cl = clp->c_cs; 424 } 425 out: 426 splx(s); 427 return count; 428 } 429 430 static int cc; 431 432 /* 433 * Given a non-NULL pointer into the clist return the pointer 434 * to the next character in the list or return NULL if no more chars. 435 * 436 * Callers must not allow getc's to happen between firstc's and getc's 437 * so that the pointer becomes invalid. Note that interrupts are NOT 438 * masked. 439 */ 440 u_char * 441 nextc(clp, cp, c) 442 struct clist *clp; 443 register u_char *cp; 444 int *c; 445 { 446 447 if (clp->c_cf == cp) { 448 /* 449 * First time initialization. 450 */ 451 cc = clp->c_cc; 452 } 453 if (cc == 0 || cp == NULL) 454 return NULL; 455 if (--cc == 0) 456 return NULL; 457 if (++cp == clp->c_ce) 458 cp = clp->c_cs; 459 *c = *cp & 0xff; 460 if (clp->c_cq) { 461 #ifdef QBITS 462 if (isset(clp->c_cq, cp - clp->c_cs)) 463 *c |= TTY_QUOTE; 464 #else 465 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) 466 *c |= TTY_QUOTE; 467 #endif 468 } 469 return cp; 470 } 471 472 /* 473 * Given a non-NULL pointer into the clist return the pointer 474 * to the first character in the list or return NULL if no more chars. 475 * 476 * Callers must not allow getc's to happen between firstc's and getc's 477 * so that the pointer becomes invalid. Note that interrupts are NOT 478 * masked. 479 * 480 * *c is set to the NEXT character 481 */ 482 u_char * 483 firstc(clp, c) 484 struct clist *clp; 485 int *c; 486 { 487 register u_char *cp; 488 489 cc = clp->c_cc; 490 if (cc == 0) 491 return NULL; 492 cp = clp->c_cf; 493 *c = *cp & 0xff; 494 if(clp->c_cq) { 495 #ifdef QBITS 496 if (isset(clp->c_cq, cp - clp->c_cs)) 497 *c |= TTY_QUOTE; 498 #else 499 if (*(cp - clp->c_cs + clp->c_cq)) 500 *c |= TTY_QUOTE; 501 #endif 502 } 503 return clp->c_cf; 504 } 505 506 /* 507 * Remove the last character in the clist and return it. 508 */ 509 int 510 unputc(clp) 511 struct clist *clp; 512 { 513 unsigned int c = -1; 514 int s; 515 516 s = spltty(); 517 if (clp->c_cc == 0) 518 goto out; 519 520 if (clp->c_cl == clp->c_cs) 521 clp->c_cl = clp->c_ce - 1; 522 else 523 --clp->c_cl; 524 clp->c_cc--; 525 526 c = *clp->c_cl & 0xff; 527 if (clp->c_cq) { 528 #ifdef QBITS 529 if (isset(clp->c_cq, clp->c_cl - clp->c_cs)) 530 c |= TTY_QUOTE; 531 #else 532 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) 533 c |= TTY_QUOTE; 534 #endif 535 } 536 if (clp->c_cc == 0) 537 clp->c_cf = clp->c_cl = (u_char *)0; 538 out: 539 splx(s); 540 return c; 541 } 542 543 /* 544 * Put the chars in the from queue on the end of the to queue. 545 */ 546 void 547 catq(from, to) 548 struct clist *from, *to; 549 { 550 int c; 551 552 while ((c = getc(from)) != -1) 553 putc(c, to); 554 } 555