1 /* 2 * Copyright (c) 1982, 1986 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)tty_subr.c 7.6 (Berkeley) 03/17/91 7 */ 8 9 #include "param.h" 10 #include "systm.h" 11 #include "buf.h" 12 #include "ioctl.h" 13 #include "tty.h" 14 #include "clist.h" 15 16 char cwaiting; 17 18 #define setquote(cp) \ 19 setbit(((char *)((int)(cp)&~CROUND)+sizeof(struct cblock *)), \ 20 (int)(cp)&CROUND) 21 #define isquote(cp) \ 22 isset(((char *)((int)(cp)&~CROUND)+sizeof(struct cblock *)), \ 23 (int)(cp)&CROUND) 24 #define cbptr(x) ((struct cblock *)(x)) 25 26 /* 27 * Initialize clist by freeing all character blocks. 28 */ 29 cinit() 30 { 31 register int ccp; 32 register struct cblock *cp; 33 34 ccp = (int) cfree; 35 ccp = (ccp + CROUND) & ~CROUND; 36 for(cp = (struct cblock *) ccp; cp < &cfree[nclist - 1]; cp++) { 37 cp->c_next = cfreelist; 38 cfreelist = cp; 39 cfreecount += CBSIZE; 40 } 41 } 42 43 /* 44 * Character list get/put 45 */ 46 getc(p) 47 register struct clist *p; 48 { 49 register struct cblock *bp; 50 register int c, s; 51 52 s = spltty(); 53 if (p->c_cc <= 0) { 54 c = -1; 55 p->c_cc = 0; 56 p->c_cf = p->c_cl = NULL; 57 } else { 58 c = *p->c_cf & 0377; 59 if (isquote(p->c_cf)) 60 c |= TTY_QUOTE; 61 p->c_cf++; 62 if (--p->c_cc<=0) { 63 bp = cbptr(p->c_cf-1); 64 bp = cbptr((int)bp & ~CROUND); 65 p->c_cf = NULL; 66 p->c_cl = NULL; 67 bp->c_next = cfreelist; 68 cfreelist = bp; 69 cfreecount += CBSIZE; 70 if (cwaiting) { 71 wakeup(&cwaiting); 72 cwaiting = 0; 73 } 74 } else if (((int)p->c_cf & CROUND) == 0){ 75 bp = cbptr(p->c_cf); 76 bp--; 77 p->c_cf = bp->c_next->c_info; 78 bp->c_next = cfreelist; 79 cfreelist = bp; 80 cfreecount += CBSIZE; 81 if (cwaiting) { 82 wakeup(&cwaiting); 83 cwaiting = 0; 84 } 85 } 86 } 87 splx(s); 88 return (c); 89 } 90 91 /* 92 * copy clist to buffer. 93 * return number of bytes moved. 94 */ 95 q_to_b(q, cp, cc) 96 register struct clist *q; 97 register char *cp; 98 { 99 register struct cblock *bp; 100 register int s; 101 register nc; 102 char *acp; 103 104 if (cc <= 0) 105 return (0); 106 s = spltty(); 107 if (q->c_cc <= 0) { 108 q->c_cc = 0; 109 q->c_cf = q->c_cl = NULL; 110 splx(s); 111 return (0); 112 } 113 acp = cp; 114 115 while (cc) { 116 nc = sizeof (struct cblock) - ((int)q->c_cf & CROUND); 117 nc = MIN(nc, cc); 118 nc = MIN(nc, q->c_cc); 119 (void) bcopy(q->c_cf, cp, (unsigned)nc); 120 q->c_cf += nc; 121 q->c_cc -= nc; 122 cc -= nc; 123 cp += nc; 124 if (q->c_cc <= 0) { 125 bp = cbptr(q->c_cf - 1); 126 bp = cbptr((int)bp & ~CROUND); 127 q->c_cf = q->c_cl = NULL; 128 bp->c_next = cfreelist; 129 cfreelist = bp; 130 cfreecount += CBSIZE; 131 if (cwaiting) { 132 wakeup(&cwaiting); 133 cwaiting = 0; 134 } 135 break; 136 } 137 if (((int)q->c_cf & CROUND) == 0) { 138 bp = cbptr(q->c_cf); 139 bp--; 140 q->c_cf = bp->c_next->c_info; 141 bp->c_next = cfreelist; 142 cfreelist = bp; 143 cfreecount += CBSIZE; 144 if (cwaiting) { 145 wakeup(&cwaiting); 146 cwaiting = 0; 147 } 148 } 149 } 150 splx(s); 151 return (cp-acp); 152 } 153 154 /* 155 * Return count of contiguous characters 156 * in clist starting at q->c_cf. 157 * Stop counting if flag&character is non-null. 158 */ 159 ndqb(q, flag) 160 register struct clist *q; 161 { 162 register cc; 163 int s; 164 165 s = spltty(); 166 if (q->c_cc <= 0) { 167 cc = -q->c_cc; 168 goto out; 169 } 170 cc = ((int)q->c_cf + CBSIZE) & ~CROUND; 171 cc -= (int)q->c_cf; 172 if (q->c_cc < cc) 173 cc = q->c_cc; 174 if (flag) { 175 register char *p, *end; 176 177 p = q->c_cf; 178 end = p; 179 end += cc; 180 while (p < end) { 181 if (*p & flag) { 182 cc = (int)p; 183 cc -= (int)q->c_cf; 184 break; 185 } 186 p++; 187 } 188 } 189 out: 190 splx(s); 191 return (cc); 192 } 193 194 /* 195 * Flush cc bytes from q. 196 */ 197 ndflush(q, cc) 198 register struct clist *q; 199 register cc; 200 { 201 register struct cblock *bp; 202 char *end; 203 int rem, s; 204 205 s = spltty(); 206 if (q->c_cc <= 0) 207 goto out; 208 while (cc>0 && q->c_cc) { 209 bp = cbptr((int)q->c_cf & ~CROUND); 210 if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) { 211 end = q->c_cl; 212 } else { 213 end = (char *)((int)bp + sizeof (struct cblock)); 214 } 215 rem = end - q->c_cf; 216 if (cc >= rem) { 217 cc -= rem; 218 q->c_cc -= rem; 219 q->c_cf = bp->c_next->c_info; 220 bp->c_next = cfreelist; 221 cfreelist = bp; 222 cfreecount += CBSIZE; 223 if (cwaiting) { 224 wakeup(&cwaiting); 225 cwaiting = 0; 226 } 227 } else { 228 q->c_cc -= cc; 229 q->c_cf += cc; 230 if (q->c_cc <= 0) { 231 bp->c_next = cfreelist; 232 cfreelist = bp; 233 cfreecount += CBSIZE; 234 if (cwaiting) { 235 wakeup(&cwaiting); 236 cwaiting = 0; 237 } 238 } 239 break; 240 } 241 } 242 if (q->c_cc <= 0) { 243 q->c_cf = q->c_cl = NULL; 244 q->c_cc = 0; 245 } 246 out: 247 splx(s); 248 } 249 250 251 putc(c, p) 252 register struct clist *p; 253 { 254 register struct cblock *bp; 255 register char *cp; 256 register s; 257 258 s = spltty(); 259 if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) { /* no cblocks yet */ 260 if ((bp = cfreelist) == NULL) { 261 splx(s); 262 return (-1); 263 } 264 cfreelist = bp->c_next; 265 cfreecount -= CBSIZE; 266 bp->c_next = NULL; 267 bzero(bp->c_quote, CBQSIZE); 268 p->c_cf = cp = bp->c_info; 269 } else if (((int)cp & CROUND) == 0) { 270 bp = cbptr(cp) - 1; /* pointer arith */ 271 if ((bp->c_next = cfreelist) == NULL) { 272 splx(s); 273 return (-1); 274 } 275 bp = bp->c_next; 276 cfreelist = bp->c_next; 277 cfreecount -= CBSIZE; 278 bp->c_next = NULL; 279 cp = bp->c_info; 280 } 281 if (c&TTY_QUOTE) 282 setquote(cp); 283 *cp++ = c; 284 p->c_cc++; 285 p->c_cl = cp; 286 splx(s); 287 return (0); 288 } 289 290 /* 291 * copy buffer to clist. 292 * return number of bytes not transfered. 293 */ 294 b_to_q(cp, cc, q) 295 register char *cp; 296 struct clist *q; 297 register int cc; 298 { 299 register char *cq; 300 register struct cblock *bp; 301 register s, nc; 302 int acc; 303 304 if (cc <= 0) 305 return (0); 306 acc = cc; 307 s = spltty(); 308 if ((cq = q->c_cl) == NULL || q->c_cc < 0) { 309 if ((bp = cfreelist) == NULL) 310 goto out; 311 cfreelist = bp->c_next; 312 cfreecount -= CBSIZE; 313 bzero(bp->c_quote, CBQSIZE); 314 bp->c_next = NULL; 315 q->c_cf = cq = bp->c_info; 316 } 317 318 while (cc) { 319 if (((int)cq & CROUND) == 0) { 320 bp = cbptr(cq) - 1; 321 if ((bp->c_next = cfreelist) == NULL) 322 goto out; 323 bp = bp->c_next; 324 cfreelist = bp->c_next; 325 cfreecount -= CBSIZE; 326 bzero(bp->c_quote, CBQSIZE); 327 bp->c_next = NULL; 328 cq = bp->c_info; 329 } 330 nc = MIN(cc, sizeof (struct cblock) - ((int)cq & CROUND)); 331 (void) bcopy(cp, cq, (unsigned)nc); 332 cp += nc; 333 cq += nc; 334 cc -= nc; 335 } 336 out: 337 q->c_cl = cq; 338 q->c_cc += acc - cc; 339 splx(s); 340 return (cc); 341 } 342 343 /* 344 * Given a non-NULL pointter into the list (like c_cf which 345 * always points to a real character if non-NULL) return the pointer 346 * to the next character in the list or return NULL if no more chars. 347 * 348 * Callers must not allow getc's to happen between nextc's so that the 349 * pointer becomes invalid. Note that interrupts are NOT masked. 350 */ 351 char * 352 nextc(p, cp, c) 353 register struct clist *p; 354 register char *cp; 355 register int *c; 356 { 357 358 if (p->c_cc && ++cp != p->c_cl) { 359 if (((int)cp & CROUND) == 0) { 360 cp = (cbptr(cp))[-1].c_next->c_info; 361 } 362 *c = *cp; 363 if (isquote(cp)) 364 *c |= TTY_QUOTE; 365 return (cp); 366 } 367 return (0); 368 } 369 370 /* 371 * Remove the last character in the list and return it. 372 */ 373 unputc(p) 374 register struct clist *p; 375 { 376 register struct cblock *bp; 377 register int c, s; 378 struct cblock *obp; 379 380 s = spltty(); 381 if (p->c_cc <= 0) 382 c = -1; 383 else { 384 c = *--p->c_cl; 385 if (isquote(p->c_cl)) 386 c |= TTY_QUOTE; 387 if (--p->c_cc <= 0) { 388 bp = cbptr(p->c_cl); 389 bp = cbptr((int)bp & ~CROUND); 390 p->c_cl = p->c_cf = NULL; 391 bp->c_next = cfreelist; 392 cfreelist = bp; 393 cfreecount += CBSIZE; 394 } else if (p->c_cl == (cbptr((int)p->c_cl & ~CROUND))->c_info) { 395 p->c_cl = (char *)((int)p->c_cl & ~CROUND); 396 397 bp = cbptr(p->c_cf); 398 bp = cbptr((int)bp & ~CROUND); 399 while (bp->c_next != cbptr(p->c_cl)) 400 bp = bp->c_next; 401 obp = bp; 402 p->c_cl = (char *)(bp + 1); 403 bp = bp->c_next; 404 bp->c_next = cfreelist; 405 cfreelist = bp; 406 cfreecount += CBSIZE; 407 obp->c_next = NULL; 408 } 409 } 410 splx(s); 411 return (c); 412 } 413 414 /* 415 * Put the chars in the from que 416 * on the end of the to que. 417 */ 418 catq(from, to) 419 struct clist *from, *to; 420 { 421 #ifdef notdef 422 char bbuf[CBSIZE*4]; 423 #endif 424 register s, c; 425 426 s = spltty(); 427 if (to->c_cc == 0) { 428 *to = *from; 429 from->c_cc = 0; 430 from->c_cf = NULL; 431 from->c_cl = NULL; 432 splx(s); 433 return; 434 } 435 splx(s); 436 #ifdef notdef 437 while (from->c_cc > 0) { 438 c = q_to_b(from, bbuf, sizeof bbuf); 439 (void) b_to_q(bbuf, c, to); 440 } 441 #endif 442 /* XXX - FIX */ 443 while ((c = getc(from)) >= 0) 444 putc(c, to); 445 } 446 447 #ifdef unneeded 448 /* 449 * Integer (short) get/put using clists. 450 */ 451 typedef u_short word_t; 452 453 getw(p) 454 register struct clist *p; 455 { 456 register int s, c; 457 register struct cblock *bp; 458 459 if (p->c_cc <= 1) 460 return(-1); 461 if (p->c_cc & 01) { 462 c = getc(p); 463 #if BYTE_ORDER == LITTLE_ENDIAN 464 return (c | (getc(p)<<8)); 465 #else 466 return (getc(p) | (c<<8)); 467 #endif 468 } 469 s = spltty(); 470 #if BYTE_ORDER == LITTLE_ENDIAN 471 c = (((u_char *)p->c_cf)[0] << 8) | ((u_char *)p->c_cf)[1]; 472 #else 473 c = (((u_char *)p->c_cf)[1] << 8) | ((u_char *)p->c_cf)[0]; 474 #endif 475 p->c_cf += sizeof (word_t); 476 p->c_cc -= sizeof (word_t); 477 if (p->c_cc <= 0) { 478 bp = cbptr(p->c_cf-1); 479 bp = cbptr((int)bp & ~CROUND); 480 p->c_cf = NULL; 481 p->c_cl = NULL; 482 bp->c_next = cfreelist; 483 cfreelist = bp; 484 cfreecount += CBSIZE; 485 if (cwaiting) { 486 wakeup(&cwaiting); 487 cwaiting = 0; 488 } 489 } else if (((int)p->c_cf & CROUND) == 0) { 490 bp = cbptr(p->c_cf); 491 bp--; 492 p->c_cf = bp->c_next->c_info; 493 bp->c_next = cfreelist; 494 cfreelist = bp; 495 cfreecount += CBSIZE; 496 if (cwaiting) { 497 wakeup(&cwaiting); 498 cwaiting = 0; 499 } 500 } 501 splx(s); 502 return (c); 503 } 504 505 putw(c, p) 506 register struct clist *p; 507 word_t c; 508 { 509 register s; 510 register struct cblock *bp; 511 register char *cp; 512 513 s = spltty(); 514 if (cfreelist==NULL) { 515 splx(s); 516 return(-1); 517 } 518 if (p->c_cc & 01) { 519 #if BYTE_ORDER == LITTLE_ENDIAN 520 (void) putc(c, p); 521 (void) putc(c>>8, p); 522 #else 523 (void) putc(c>>8, p); 524 (void) putc(c, p); 525 #endif 526 } else { 527 if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) { 528 if ((bp = cfreelist) == NULL) { 529 splx(s); 530 return (-1); 531 } 532 cfreelist = bp->c_next; 533 cfreecount -= CBSIZE; 534 bp->c_next = NULL; 535 p->c_cf = cp = bp->c_info; 536 } else if (((int)cp & CROUND) == 0) { 537 bp = cbptr(cp) - 1; 538 if ((bp->c_next = cfreelist) == NULL) { 539 splx(s); 540 return (-1); 541 } 542 bp = bp->c_next; 543 cfreelist = bp->c_next; 544 cfreecount -= CBSIZE; 545 bp->c_next = NULL; 546 cp = bp->c_info; 547 } 548 #if defined(vax) 549 *(word_t *)cp = c; 550 #else 551 ((u_char *)cp)[0] = c>>8; 552 ((u_char *)cp)[1] = c; 553 #endif 554 p->c_cl = cp + sizeof (word_t); 555 p->c_cc += sizeof (word_t); 556 } 557 splx(s); 558 return (0); 559 } 560 #endif unneeded 561