update from Rick Macklem to generate proper error messages
[unix-history] / usr / src / sys / kern / tty_subr.c
CommitLineData
da7c5cc6 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
da7c5cc6
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
e39f9ea6 6 * @(#)tty_subr.c 7.4 (Berkeley) %G%
da7c5cc6 7 */
8f6119af 8
94368568
JB
9#include "param.h"
10#include "systm.h"
94368568 11#include "buf.h"
3358b36b 12#include "ioctl.h"
94368568
JB
13#include "tty.h"
14#include "clist.h"
11bd398c 15
48575cec 16char cwaiting;
11bd398c 17
e39f9ea6
MT
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
11bd398c
BJ
26/*
27 * Character list get/put
28 */
29getc(p)
88a7a62a 30 register struct clist *p;
11bd398c
BJ
31{
32 register struct cblock *bp;
33 register int c, s;
34
a8170d5d 35 s = spltty();
11bd398c
BJ
36 if (p->c_cc <= 0) {
37 c = -1;
38 p->c_cc = 0;
39 p->c_cf = p->c_cl = NULL;
40 } else {
e39f9ea6
MT
41 c = *p->c_cf & 0377;
42 if (isquote(p->c_cf))
43 c |= TTY_QUOTE;
44 p->c_cf++;
11bd398c 45 if (--p->c_cc<=0) {
e39f9ea6
MT
46 bp = cbptr(p->c_cf-1);
47 bp = cbptr((int)bp & ~CROUND);
11bd398c
BJ
48 p->c_cf = NULL;
49 p->c_cl = NULL;
50 bp->c_next = cfreelist;
51 cfreelist = bp;
48575cec
BJ
52 cfreecount += CBSIZE;
53 if (cwaiting) {
54 wakeup(&cwaiting);
55 cwaiting = 0;
56 }
11bd398c 57 } else if (((int)p->c_cf & CROUND) == 0){
e39f9ea6 58 bp = cbptr(p->c_cf);
11bd398c
BJ
59 bp--;
60 p->c_cf = bp->c_next->c_info;
61 bp->c_next = cfreelist;
62 cfreelist = bp;
48575cec
BJ
63 cfreecount += CBSIZE;
64 if (cwaiting) {
65 wakeup(&cwaiting);
66 cwaiting = 0;
67 }
11bd398c
BJ
68 }
69 }
70 splx(s);
01b0e233 71 return (c);
11bd398c
BJ
72}
73
74/*
75 * copy clist to buffer.
76 * return number of bytes moved.
77 */
78q_to_b(q, cp, cc)
961945a8
SL
79 register struct clist *q;
80 register char *cp;
11bd398c
BJ
81{
82 register struct cblock *bp;
83 register int s;
a8170d5d 84 register nc;
11bd398c
BJ
85 char *acp;
86
87 if (cc <= 0)
01b0e233 88 return (0);
a8170d5d 89 s = spltty();
11bd398c
BJ
90 if (q->c_cc <= 0) {
91 q->c_cc = 0;
92 q->c_cf = q->c_cl = NULL;
48575cec 93 splx(s);
01b0e233 94 return (0);
11bd398c
BJ
95 }
96 acp = cp;
11bd398c 97
a8170d5d 98 while (cc) {
01b0e233 99 nc = sizeof (struct cblock) - ((int)q->c_cf & CROUND);
a8170d5d
MK
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) {
e39f9ea6
MT
108 bp = cbptr(q->c_cf - 1);
109 bp = cbptr((int)bp & ~CROUND);
11bd398c
BJ
110 q->c_cf = q->c_cl = NULL;
111 bp->c_next = cfreelist;
112 cfreelist = bp;
48575cec
BJ
113 cfreecount += CBSIZE;
114 if (cwaiting) {
115 wakeup(&cwaiting);
116 cwaiting = 0;
117 }
11bd398c
BJ
118 break;
119 }
120 if (((int)q->c_cf & CROUND) == 0) {
e39f9ea6 121 bp = cbptr(q->c_cf);
11bd398c
BJ
122 bp--;
123 q->c_cf = bp->c_next->c_info;
124 bp->c_next = cfreelist;
125 cfreelist = bp;
48575cec
BJ
126 cfreecount += CBSIZE;
127 if (cwaiting) {
128 wakeup(&cwaiting);
129 cwaiting = 0;
130 }
11bd398c
BJ
131 }
132 }
133 splx(s);
01b0e233 134 return (cp-acp);
11bd398c
BJ
135}
136
11bd398c
BJ
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 */
142ndqb(q, flag)
961945a8 143 register struct clist *q;
11bd398c 144{
961945a8
SL
145 register cc;
146 int s;
11bd398c 147
a8170d5d 148 s = spltty();
11bd398c
BJ
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) {
48575cec
BJ
165 cc = (int)p;
166 cc -= (int)q->c_cf;
11bd398c
BJ
167 break;
168 }
169 p++;
170 }
171 }
172out:
173 splx(s);
01b0e233 174 return (cc);
11bd398c
BJ
175}
176
11bd398c 177/*
48575cec 178 * Flush cc bytes from q.
11bd398c
BJ
179 */
180ndflush(q, cc)
88a7a62a
SL
181 register struct clist *q;
182 register cc;
11bd398c 183{
88a7a62a
SL
184 register struct cblock *bp;
185 char *end;
186 int rem, s;
11bd398c 187
a8170d5d 188 s = spltty();
01b0e233 189 if (q->c_cc <= 0)
11bd398c 190 goto out;
48575cec 191 while (cc>0 && q->c_cc) {
e39f9ea6 192 bp = cbptr((int)q->c_cf & ~CROUND);
48575cec
BJ
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;
11bd398c 202 q->c_cf = bp->c_next->c_info;
48575cec
BJ
203 bp->c_next = cfreelist;
204 cfreelist = bp;
205 cfreecount += CBSIZE;
206 if (cwaiting) {
207 wakeup(&cwaiting);
208 cwaiting = 0;
209 }
11bd398c 210 } else {
48575cec
BJ
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;
11bd398c 223 }
48575cec
BJ
224 }
225 if (q->c_cc <= 0) {
11bd398c 226 q->c_cf = q->c_cl = NULL;
48575cec 227 q->c_cc = 0;
11bd398c
BJ
228 }
229out:
230 splx(s);
231}
b8f09f36 232
48575cec 233
11bd398c 234putc(c, p)
88a7a62a 235 register struct clist *p;
11bd398c
BJ
236{
237 register struct cblock *bp;
238 register char *cp;
239 register s;
240
a8170d5d 241 s = spltty();
e39f9ea6 242 if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) { /* no cblocks yet */
11bd398c
BJ
243 if ((bp = cfreelist) == NULL) {
244 splx(s);
01b0e233 245 return (-1);
11bd398c
BJ
246 }
247 cfreelist = bp->c_next;
48575cec 248 cfreecount -= CBSIZE;
11bd398c 249 bp->c_next = NULL;
e39f9ea6 250 bzero(bp->c_quote, CBQSIZE);
11bd398c
BJ
251 p->c_cf = cp = bp->c_info;
252 } else if (((int)cp & CROUND) == 0) {
e39f9ea6 253 bp = cbptr(cp) - 1; /* pointer arith */
11bd398c
BJ
254 if ((bp->c_next = cfreelist) == NULL) {
255 splx(s);
01b0e233 256 return (-1);
11bd398c
BJ
257 }
258 bp = bp->c_next;
259 cfreelist = bp->c_next;
48575cec 260 cfreecount -= CBSIZE;
11bd398c
BJ
261 bp->c_next = NULL;
262 cp = bp->c_info;
263 }
e39f9ea6
MT
264 if (c&TTY_QUOTE)
265 setquote(cp);
11bd398c
BJ
266 *cp++ = c;
267 p->c_cc++;
268 p->c_cl = cp;
269 splx(s);
01b0e233 270 return (0);
11bd398c
BJ
271}
272
11bd398c
BJ
273/*
274 * copy buffer to clist.
275 * return number of bytes not transfered.
276 */
277b_to_q(cp, cc, q)
88a7a62a
SL
278 register char *cp;
279 struct clist *q;
280 register int cc;
11bd398c
BJ
281{
282 register char *cq;
283 register struct cblock *bp;
a8170d5d
MK
284 register s, nc;
285 int acc;
11bd398c
BJ
286
287 if (cc <= 0)
01b0e233 288 return (0);
a8170d5d
MK
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;
e39f9ea6 296 bzero(bp->c_quote, CBQSIZE);
a8170d5d
MK
297 bp->c_next = NULL;
298 q->c_cf = cq = bp->c_info;
299 }
300
301 while (cc) {
11bd398c 302 if (((int)cq & CROUND) == 0) {
e39f9ea6 303 bp = cbptr(cq) - 1;
a8170d5d
MK
304 if ((bp->c_next = cfreelist) == NULL)
305 goto out;
11bd398c
BJ
306 bp = bp->c_next;
307 cfreelist = bp->c_next;
48575cec 308 cfreecount -= CBSIZE;
e39f9ea6 309 bzero(bp->c_quote, CBQSIZE);
11bd398c 310 bp->c_next = NULL;
a8170d5d 311 cq = bp->c_info;
11bd398c 312 }
01b0e233 313 nc = MIN(cc, sizeof (struct cblock) - ((int)cq & CROUND));
a8170d5d
MK
314 (void) bcopy(cp, cq, (unsigned)nc);
315 cp += nc;
316 cq += nc;
317 cc -= nc;
11bd398c 318 }
a8170d5d
MK
319out:
320 q->c_cl = cq;
321 q->c_cc += acc - cc;
322 splx(s);
42cc3b3d 323 return (cc);
11bd398c
BJ
324}
325
b8f09f36
BJ
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 */
334char *
e39f9ea6 335nextc(p, cp, c)
88a7a62a
SL
336 register struct clist *p;
337 register char *cp;
e39f9ea6 338 register int *c;
b8f09f36
BJ
339{
340
341 if (p->c_cc && ++cp != p->c_cl) {
e39f9ea6
MT
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;
b8f09f36
BJ
348 return (cp);
349 }
350 return (0);
351}
352
353/*
354 * Remove the last character in the list and return it.
355 */
356unputc(p)
88a7a62a 357 register struct clist *p;
b8f09f36
BJ
358{
359 register struct cblock *bp;
360 register int c, s;
361 struct cblock *obp;
e39f9ea6 362 register int first = 1;
b8f09f36 363
a8170d5d 364 s = spltty();
b8f09f36
BJ
365 if (p->c_cc <= 0)
366 c = -1;
367 else {
368 c = *--p->c_cl;
e39f9ea6
MT
369 if (isquote(p->c_cl))
370 c |= TTY_QUOTE;
b8f09f36 371 if (--p->c_cc <= 0) {
e39f9ea6
MT
372 bp = cbptr(p->c_cl);
373 bp = cbptr((int)bp & ~CROUND);
b8f09f36
BJ
374 p->c_cl = p->c_cf = NULL;
375 bp->c_next = cfreelist;
376 cfreelist = bp;
48575cec 377 cfreecount += CBSIZE;
e39f9ea6 378 } else if (p->c_cl == (cbptr((int)p->c_cl & ~CROUND))->c_info) {
b8f09f36 379 p->c_cl = (char *)((int)p->c_cl & ~CROUND);
e39f9ea6
MT
380
381 bp = cbptr(p->c_cf);
382 bp = cbptr((int)bp & ~CROUND);
383 while (bp->c_next != cbptr(p->c_cl))
b8f09f36
BJ
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;
48575cec 390 cfreecount += CBSIZE;
b8f09f36
BJ
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.
b8f09f36
BJ
401 */
402catq(from, to)
88a7a62a 403 struct clist *from, *to;
b8f09f36 404{
e39f9ea6 405#ifdef notdef
a8170d5d 406 char bbuf[CBSIZE*4];
e39f9ea6 407#endif
a8170d5d
MK
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);
e39f9ea6 420#ifdef notdef
a8170d5d
MK
421 while (from->c_cc > 0) {
422 c = q_to_b(from, bbuf, sizeof bbuf);
423 (void) b_to_q(bbuf, c, to);
424 }
e39f9ea6
MT
425#endif
426 /* XXX - FIX */
427 while ((c = getc(from)) >= 0)
428 putc(c, to);
b8f09f36
BJ
429}
430
a8170d5d 431#ifdef unneeded
11bd398c 432/*
01b0e233 433 * Integer (short) get/put using clists.
11bd398c 434 */
a8170d5d 435typedef u_short word_t;
961945a8 436
11bd398c 437getw(p)
d0b37068 438 register struct clist *p;
11bd398c 439{
a8170d5d
MK
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);
c6d44403 447#if BYTE_ORDER == LITTLE_ENDIAN
01b0e233
MK
448 return (c | (getc(p)<<8));
449#else
450 return (getc(p) | (c<<8));
451#endif
a8170d5d
MK
452 }
453 s = spltty();
e39f9ea6 454#if BYTE_ORDER == LITTLE_ENDIAN
fb1db32c 455 c = (((u_char *)p->c_cf)[0] << 8) | ((u_char *)p->c_cf)[1];
01b0e233
MK
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);
a8170d5d 461 if (p->c_cc <= 0) {
e39f9ea6
MT
462 bp = cbptr(p->c_cf-1);
463 bp = cbptr((int)bp & ~CROUND);
a8170d5d
MK
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) {
e39f9ea6 474 bp = cbptr(p->c_cf);
a8170d5d
MK
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);
11bd398c 487}
48575cec 488
11bd398c 489putw(c, p)
d0b37068 490 register struct clist *p;
a8170d5d 491 word_t c;
11bd398c
BJ
492{
493 register s;
a8170d5d
MK
494 register struct cblock *bp;
495 register char *cp;
11bd398c 496
a8170d5d 497 s = spltty();
11bd398c
BJ
498 if (cfreelist==NULL) {
499 splx(s);
500 return(-1);
501 }
a8170d5d 502 if (p->c_cc & 01) {
c6d44403 503#if BYTE_ORDER == LITTLE_ENDIAN
a8170d5d
MK
504 (void) putc(c, p);
505 (void) putc(c>>8, p);
01b0e233
MK
506#else
507 (void) putc(c>>8, p);
508 (void) putc(c, p);
509#endif
a8170d5d
MK
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) {
e39f9ea6 521 bp = cbptr(cp) - 1;
a8170d5d
MK
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 }
01b0e233 532#if defined(vax)
a8170d5d 533 *(word_t *)cp = c;
01b0e233
MK
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);
a8170d5d 540 }
11bd398c 541 splx(s);
961945a8 542 return (0);
11bd398c 543}
a8170d5d 544#endif unneeded