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