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