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