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.1 1993/07/12 11:35:18 mycroft Exp $ 23 */ 24 25 #include "param.h" 26 #include "systm.h" 27 #include "buf.h" 28 #include "ioctl.h" 29 #include "tty.h" 30 #include "clist.h" 31 #include "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, u_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, u_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 = (u_char *)0; 88 89 clp->c_cf = clp->c_cl = (u_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 = (u_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 = (u_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 u_char *cp; 149 int count; 150 { 151 register int cc; 152 u_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 = (u_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 || flag == 0) 192 goto out; 193 194 i = clp->c_cf - clp->c_cs; 195 while (cc-- > 0 && (clp->c_cs[i++] & flag) == 0) { 196 count++; 197 if (i == clp->c_cn) 198 break; 199 } 200 out: 201 splx(s); 202 return count; 203 } 204 205 /* 206 * Flush count bytes from clist. 207 */ 208 void 209 ndflush(clp, count) 210 struct clist *clp; 211 int count; 212 { 213 register int cc; 214 int s; 215 216 s = spltty(); 217 if (count == clp->c_cc) { 218 clp->c_cc = 0; 219 clp->c_cf = clp->c_cl = (u_char *)0; 220 goto out; 221 } 222 /* optimize this while loop */ 223 while (count > 0 && clp->c_cc > 0) { 224 cc = clp->c_cl - clp->c_cf; 225 if (clp->c_cf >= clp->c_cl) 226 cc = clp->c_ce - clp->c_cf; 227 if (cc > count) 228 cc = count; 229 count -= cc; 230 clp->c_cc -= cc; 231 clp->c_cf += cc; 232 if (clp->c_cf == clp->c_ce) 233 clp->c_cf = clp->c_cs; 234 } 235 if (clp->c_cc == 0) 236 clp->c_cf = clp->c_cl = (u_char *)0; 237 out: 238 splx(s); 239 } 240 241 /* 242 * Put a character into the output queue. 243 */ 244 int 245 putc(c, clp) 246 int c; 247 struct clist *clp; 248 { 249 register u_char *q; 250 register int i; 251 int r = -1; 252 int s; 253 254 s = spltty(); 255 if (clp->c_cc == clp->c_cn) 256 goto out; 257 258 if (clp->c_cc == 0) { 259 if (!clp->c_cs) { 260 #if defined(DIAGNOSTIC) || 1 261 printf("b_to_q: required clalloc\n"); 262 #endif 263 if(clalloc(clp, 1024, 1)) { 264 out: 265 splx(s); 266 return -1; 267 } 268 } 269 clp->c_cf = clp->c_cl = clp->c_cs; 270 } 271 272 *clp->c_cl = c & 0xff; 273 i = clp->c_cl - clp->c_cs; 274 if (clp->c_cq) { 275 #ifdef QBITS 276 if (c & TTY_QUOTE) 277 setbit(clp->c_cq, i); 278 else 279 clrbit(clp->c_cq, i); 280 #else 281 q = clp->c_cq + i; 282 *q = (c & TTY_QUOTE) ? 1 : 0; 283 #endif 284 } 285 clp->c_cc++; 286 clp->c_cl++; 287 if (clp->c_cl == clp->c_ce) 288 clp->c_cl = clp->c_cs; 289 splx(s); 290 return 0; 291 } 292 293 #ifdef QBITS 294 /* 295 * optimized version of 296 * 297 * for (i = 0; i < len; i++) 298 * clrbit(cp, off + len); 299 */ 300 void 301 clrbits(cp, off, len) 302 u_char *cp; 303 int off; 304 int len; 305 { 306 int sby, sbi, eby, ebi; 307 register int i; 308 u_char mask; 309 310 if(len==1) { 311 clrbit(cp, off); 312 return; 313 } 314 315 sby = off / NBBY; 316 sbi = off % NBBY; 317 eby = (off+len) / NBBY; 318 ebi = (off+len) % NBBY; 319 if (sby == eby) { 320 mask = ((1 << (ebi - sbi)) - 1) << sbi; 321 cp[sby] &= ~mask; 322 } else { 323 mask = (1<<sbi) - 1; 324 cp[sby++] &= mask; 325 326 mask = (1<<ebi) - 1; 327 cp[eby] &= ~mask; 328 329 for (i = sby; i < eby; i++) 330 cp[i] = 0x00; 331 } 332 } 333 #endif 334 335 /* 336 * Copy buffer to clist. 337 * Return number of bytes not transfered. 338 */ 339 int 340 b_to_q(cp, count, clp) 341 u_char *cp; 342 int count; 343 struct clist *clp; 344 { 345 register int i, cc; 346 register u_char *p = cp; 347 int off, s; 348 349 if (count <= 0) 350 return 0; 351 352 s = spltty(); 353 if (clp->c_cc == clp->c_cn) 354 goto out; 355 356 if (clp->c_cc == 0) { 357 if (!clp->c_cs) { 358 #if defined(DIAGNOSTIC) || 1 359 printf("b_to_q: required clalloc\n"); 360 #endif 361 if(clalloc(clp, 1024, 1)) 362 goto out; 363 } 364 clp->c_cf = clp->c_cl = clp->c_cs; 365 } 366 367 /* optimize this while loop */ 368 while (count > 0 && clp->c_cc < clp->c_cn) { 369 cc = clp->c_ce - clp->c_cl; 370 if (clp->c_cf > clp->c_cl) 371 cc = clp->c_cf - clp->c_cl; 372 if (cc > count) 373 cc = count; 374 bcopy(p, clp->c_cl, cc); 375 if (clp->c_cq) { 376 #ifdef QBITS 377 clrbits(clp->c_cq, clp->c_cl - clp->c_cs, cc); 378 #else 379 bzero(clp->c_cl - clp->c_cs + clp->c_cq, cc); 380 #endif 381 } 382 p += cc; 383 count -= cc; 384 clp->c_cc += cc; 385 clp->c_cl += cc; 386 if (clp->c_cl == clp->c_ce) 387 clp->c_cl = clp->c_cs; 388 } 389 out: 390 splx(s); 391 return count; 392 } 393 394 static int cc; 395 396 /* 397 * Given a non-NULL pointer into the clist return the pointer 398 * to the next character in the list or return NULL if no more chars. 399 * 400 * Callers must not allow getc's to happen between firstc's and getc's 401 * so that the pointer becomes invalid. Note that interrupts are NOT 402 * masked. 403 */ 404 u_char * 405 nextc(clp, cp, c) 406 struct clist *clp; 407 register u_char *cp; 408 int *c; 409 { 410 411 if (clp->c_cf == cp) { 412 /* 413 * First time initialization. 414 */ 415 cc = clp->c_cc; 416 } 417 if (cc == 0 || cp == NULL) 418 return NULL; 419 if (--cc == 0) 420 return NULL; 421 if (++cp == clp->c_ce) 422 cp = clp->c_cs; 423 *c = *cp & 0xff; 424 if (clp->c_cq) { 425 #ifdef QBITS 426 if (isset(clp->c_cq, cp - clp->c_cs)) 427 *c |= TTY_QUOTE; 428 #else 429 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) 430 *c |= TTY_QUOTE; 431 #endif 432 } 433 return cp; 434 } 435 436 /* 437 * Given a non-NULL pointer into the clist return the pointer 438 * to the first character in the list or return NULL if no more chars. 439 * 440 * Callers must not allow getc's to happen between firstc's and getc's 441 * so that the pointer becomes invalid. Note that interrupts are NOT 442 * masked. 443 * 444 * *c is set to the NEXT character 445 */ 446 u_char * 447 firstc(clp, c) 448 struct clist *clp; 449 int *c; 450 { 451 int empty = 0; 452 register u_char *cp; 453 register int i; 454 455 cc = clp->c_cc; 456 if (cc == 0) 457 return NULL; 458 cp = clp->c_cf; 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 (*(cp - clp->c_cs + clp->c_cq)) 466 *c |= TTY_QUOTE; 467 #endif 468 } 469 return clp->c_cf; 470 } 471 472 /* 473 * Remove the last character in the clist and return it. 474 */ 475 int 476 unputc(clp) 477 struct clist *clp; 478 { 479 unsigned int c = -1; 480 int s; 481 482 s = spltty(); 483 if (clp->c_cc == 0) 484 goto out; 485 486 if (clp->c_cl == clp->c_cs) 487 clp->c_cl = clp->c_ce - 1; 488 else 489 --clp->c_cl; 490 clp->c_cc--; 491 492 c = *clp->c_cl & 0xff; 493 if (clp->c_cq) { 494 #ifdef QBITS 495 if (isset(clp->c_cq, clp->c_cl - clp->c_cs)) 496 c |= TTY_QUOTE; 497 #else 498 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) 499 c | TTY_QUOTE; 500 #endif 501 } 502 if (clp->c_cc == 0) 503 clp->c_cf = clp->c_cl = (u_char *)0; 504 out: 505 splx(s); 506 return c; 507 } 508 509 /* 510 * Put the chars in the from queue on the end of the to queue. 511 */ 512 void 513 catq(from, to) 514 struct clist *from, *to; 515 { 516 int c; 517 518 while ((c = getc(from)) != -1) 519 putc(c, to); 520 } 521