Commit | Line | Data |
---|---|---|
25a197fc C |
1 | /* $Header: term.c,v 4.3.1.2 85/05/16 16:45:35 lwall Exp $ |
2 | * | |
3 | * $Log: term.c,v $ | |
4 | * Revision 4.3.1.2 85/05/16 16:45:35 lwall | |
5 | * Forced \r to \n on input. | |
6 | * Fix for terminfo braindamage regarding bc emulation. | |
7 | * | |
8 | * Revision 4.3.1.1 85/05/10 11:41:03 lwall | |
9 | * Branch for patches. | |
10 | * | |
11 | * Revision 4.3 85/05/01 11:51:10 lwall | |
12 | * Baseline for release with 4.3bsd. | |
13 | * | |
14 | */ | |
15 | ||
16 | #include "EXTERN.h" | |
17 | #include "common.h" | |
18 | #include "util.h" | |
19 | #include "final.h" | |
20 | #include "help.h" | |
21 | #include "cheat.h" | |
22 | #include "intrp.h" | |
23 | #include "INTERN.h" | |
24 | #include "term.h" | |
25 | ||
26 | char ERASECH; /* rubout character */ | |
27 | char KILLCH; /* line delete character */ | |
28 | char tcarea[TCSIZE]; /* area for "compiled" termcap strings */ | |
29 | ||
30 | /* guarantee capability pointer != Nullch */ | |
31 | /* (I believe terminfo will ignore the &tmpaddr argument.) */ | |
32 | ||
33 | #define Tgetstr(key) ((tmpstr = tgetstr(key,&tmpaddr)) ? tmpstr : nullstr) | |
34 | ||
35 | #ifdef PUSHBACK | |
36 | struct keymap { | |
37 | char km_type[128]; | |
38 | union km_union { | |
39 | struct keymap *km_km; | |
40 | char *km_str; | |
41 | } km_ptr[128]; | |
42 | }; | |
43 | ||
44 | #define KM_NOTHIN 0 | |
45 | #define KM_STRING 1 | |
46 | #define KM_KEYMAP 2 | |
47 | #define KM_BOGUS 3 | |
48 | ||
49 | #define KM_TMASK 3 | |
50 | #define KM_GSHIFT 4 | |
51 | #define KM_GMASK 7 | |
52 | ||
53 | typedef struct keymap KEYMAP; | |
54 | ||
55 | KEYMAP *topmap INIT(Null(KEYMAP*)); | |
56 | ||
57 | void mac_init(); | |
58 | KEYMAP *newkeymap(); | |
59 | void show_keymap(); | |
60 | void pushstring(); | |
61 | #endif | |
62 | ||
63 | /* terminal initialization */ | |
64 | ||
65 | void | |
66 | term_init() | |
67 | { | |
68 | savetty(); /* remember current tty state */ | |
69 | ||
70 | #ifdef TERMIO | |
71 | ospeed = _tty.c_cflag & CBAUD; /* for tputs() */ | |
72 | ERASECH = _tty.c_cc[VERASE]; /* for finish_command() */ | |
73 | KILLCH = _tty.c_cc[VKILL]; /* for finish_command() */ | |
74 | #else | |
75 | ospeed = _tty.sg_ospeed; /* for tputs() */ | |
76 | ERASECH = _tty.sg_erase; /* for finish_command() */ | |
77 | KILLCH = _tty.sg_kill; /* for finish_command() */ | |
78 | #endif | |
79 | ||
80 | /* The following could be a table but I can't be sure that there isn't */ | |
81 | /* some degree of sparsity out there in the world. */ | |
82 | ||
83 | switch (ospeed) { /* 1 second of padding */ | |
84 | #ifdef BEXTA | |
85 | case BEXTA: just_a_sec = 1920; break; | |
86 | #else | |
87 | #ifdef B19200 | |
88 | case B19200: just_a_sec = 1920; break; | |
89 | #endif | |
90 | #endif | |
91 | case B9600: just_a_sec = 960; break; | |
92 | case B4800: just_a_sec = 480; break; | |
93 | case B2400: just_a_sec = 240; break; | |
94 | case B1800: just_a_sec = 180; break; | |
95 | case B1200: just_a_sec = 120; break; | |
96 | case B600: just_a_sec = 60; break; | |
97 | case B300: just_a_sec = 30; break; | |
98 | /* do I really have to type the rest of this??? */ | |
99 | case B200: just_a_sec = 20; break; | |
100 | case B150: just_a_sec = 15; break; | |
101 | case B134: just_a_sec = 13; break; | |
102 | case B110: just_a_sec = 11; break; | |
103 | case B75: just_a_sec = 8; break; | |
104 | case B50: just_a_sec = 5; break; | |
105 | default: just_a_sec = 960; break; | |
106 | /* if we are running detached I */ | |
107 | } /* don't want to know about it! */ | |
108 | } | |
109 | ||
110 | /* set terminal characteristics */ | |
111 | ||
112 | void | |
113 | term_set(tcbuf) | |
114 | char *tcbuf; /* temp area for "uncompiled" termcap entry */ | |
115 | { | |
116 | char *tmpaddr; /* must not be register */ | |
117 | register char *tmpstr; | |
118 | char *tgetstr(); | |
119 | char *s; | |
120 | int status; | |
121 | ||
122 | #ifdef PENDING | |
123 | #ifndef FIONREAD | |
124 | /* do no delay reads on something that always gets closed on exit */ | |
125 | ||
126 | devtty = open("/dev/tty",0); | |
127 | if (devtty < 0) { | |
128 | printf(cantopen,"/dev/tty") FLUSH; | |
129 | finalize(1); | |
130 | } | |
131 | fcntl(devtty,F_SETFL,O_NDELAY); | |
132 | #endif | |
133 | #endif | |
134 | ||
135 | /* get all that good termcap stuff */ | |
136 | ||
137 | #ifdef HAVETERMLIB | |
138 | status = tgetent(tcbuf,getenv("TERM")); /* get termcap entry */ | |
139 | if (status < 1) { | |
140 | #ifdef VERBOSE | |
141 | printf("No termcap %s found.\n", status ? "file" : "entry") FLUSH; | |
142 | #else | |
143 | fputs("Termcap botch\n",stdout) FLUSH | |
144 | #endif | |
145 | finalize(1); | |
146 | } | |
147 | tmpaddr = tcarea; /* set up strange tgetstr pointer */ | |
148 | s = Tgetstr("pc"); /* get pad character */ | |
149 | PC = *s; /* get it where tputs wants it */ | |
150 | if (!tgetflag("bs")) { /* is backspace not used? */ | |
151 | BC = Tgetstr("bc"); /* find out what is */ | |
152 | if (BC == nullstr) /* terminfo grok's 'bs' but not 'bc' */ | |
153 | BC = Tgetstr("le"); | |
154 | } else | |
155 | BC = "\b"; /* make a backspace handy */ | |
156 | UP = Tgetstr("up"); /* move up a line */ | |
157 | if (!*UP) /* no UP string? */ | |
158 | marking = 0; /* disable any marking */ | |
159 | if (muck_up_clear) /* this is for weird HPs */ | |
160 | CL = "\n\n\n\n"; | |
161 | else | |
162 | CL = Tgetstr("cl"); /* get clear string */ | |
163 | CE = Tgetstr("ce"); /* clear to end of line string */ | |
164 | #ifdef CLEAREOL | |
165 | CM = Tgetstr("cm"); /* cursor motion - PWP */ | |
166 | HO = Tgetstr("ho"); /* home cursor if no CM - PWP */ | |
167 | CD = Tgetstr("cd"); /* clear to end of display - PWP */ | |
168 | if (!*CE || !*CD || (!*CM && !*HO)) /* can we CE, CD, and home? */ | |
169 | can_home_clear = FALSE; /* no, so disable use of clear eol */ | |
170 | #endif CLEAREOL | |
171 | SO = Tgetstr("so"); /* begin standout */ | |
172 | SE = Tgetstr("se"); /* end standout */ | |
173 | if ((SG = tgetnum("sg"))<0) | |
174 | SG = 0; /* blanks left by SG, SE */ | |
175 | US = Tgetstr("us"); /* start underline */ | |
176 | UE = Tgetstr("ue"); /* end underline */ | |
177 | if ((UG = tgetnum("ug"))<0) | |
178 | UG = 0; /* blanks left by US, UE */ | |
179 | if (*US) | |
180 | UC = nullstr; /* UC must not be NULL */ | |
181 | else | |
182 | UC = Tgetstr("uc"); /* underline a character */ | |
183 | if (!*US && !*UC) { /* no underline mode? */ | |
184 | US = SO; /* substitute standout mode */ | |
185 | UE = SE; | |
186 | UG = SG; | |
187 | } | |
188 | LINES = tgetnum("li"); /* lines per page */ | |
189 | COLS = tgetnum("co"); /* columns on page */ | |
190 | AM = tgetflag("am"); /* terminal wraps automatically? */ | |
191 | XN = tgetflag("xn"); /* then eats next newline? */ | |
192 | VB = Tgetstr("vb"); | |
193 | if (!*VB) | |
194 | VB = "\007"; | |
195 | CR = Tgetstr("cr"); | |
196 | if (!*CR) { | |
197 | if (tgetflag("nc") && *UP) { | |
198 | CR = safemalloc((MEM_SIZE)strlen(UP)+2); | |
199 | sprintf(CR,"%s\r",UP); | |
200 | } | |
201 | else | |
202 | CR = "\r"; | |
203 | } | |
204 | #else | |
205 | ?????? /* Roll your own... */ | |
206 | #endif | |
207 | if (LINES > 0) { /* is this a crt? */ | |
208 | if (!initlines) /* no -i? */ | |
209 | if (ospeed >= B9600) /* whole page at >= 9600 baud */ | |
210 | initlines = LINES; | |
211 | else if (ospeed >= B4800) /* 16 lines at 4800 */ | |
212 | initlines = 16; | |
213 | else /* otherwise just header */ | |
214 | initlines = 8; | |
215 | } | |
216 | else { /* not a crt */ | |
217 | LINES = 30000; /* so don't page */ | |
218 | CL = "\n\n"; /* put a couple of lines between */ | |
219 | if (!initlines) /* make initlines reasonable */ | |
220 | initlines = 8; | |
221 | } | |
222 | if (COLS <= 0) | |
223 | COLS = 80; | |
224 | noecho(); /* turn off echo */ | |
225 | crmode(); /* enter cbreak mode */ | |
226 | ||
227 | #ifdef PUSHBACK | |
228 | mac_init(tcbuf); | |
229 | #endif | |
230 | } | |
231 | ||
232 | #ifdef PUSHBACK | |
233 | void | |
234 | mac_init(tcbuf) | |
235 | char *tcbuf; | |
236 | { | |
237 | char tmpbuf[1024]; | |
238 | ||
239 | tmpfp = fopen(filexp(getval("RNMACRO",RNMACRO)),"r"); | |
240 | if (tmpfp != Nullfp) { | |
241 | while (fgets(tcbuf,1024,tmpfp) != Nullch) { | |
242 | mac_line(tcbuf,tmpbuf,(sizeof tmpbuf)); | |
243 | } | |
244 | fclose(tmpfp); | |
245 | } | |
246 | } | |
247 | ||
248 | void | |
249 | mac_line(line,tmpbuf,tbsize) | |
250 | char *line; | |
251 | char *tmpbuf; | |
252 | int tbsize; | |
253 | { | |
254 | register char *s, *m; | |
255 | register KEYMAP *curmap; | |
256 | register int ch; | |
257 | register int garbage = 0; | |
258 | static char override[] = "\nkeymap overrides string\n"; | |
259 | ||
260 | if (topmap == Null(KEYMAP*)) | |
261 | topmap = newkeymap(); | |
262 | if (*line == '#' || *line == '\n') | |
263 | return; | |
264 | if (line[ch = strlen(line)-1] == '\n') | |
265 | line[ch] = '\0'; | |
266 | m = dointerp(tmpbuf,tbsize,line," \t"); | |
267 | if (!*m) | |
268 | return; | |
269 | while (*m == ' ' || *m == '\t') m++; | |
270 | for (s=tmpbuf,curmap=topmap; *s; s++) { | |
271 | ch = *s & 0177; | |
272 | if (s[1] == '+' && isdigit(s[2])) { | |
273 | s += 2; | |
274 | garbage = (*s & KM_GMASK) << KM_GSHIFT; | |
275 | } | |
276 | else | |
277 | garbage = 0; | |
278 | if (s[1]) { | |
279 | if ((curmap->km_type[ch] & KM_TMASK) == KM_STRING) { | |
280 | puts(override,stdout) FLUSH; | |
281 | free(curmap->km_ptr[ch].km_str); | |
282 | curmap->km_ptr[ch].km_str = Nullch; | |
283 | } | |
284 | curmap->km_type[ch] = KM_KEYMAP + garbage; | |
285 | if (curmap->km_ptr[ch].km_km == Null(KEYMAP*)) | |
286 | curmap->km_ptr[ch].km_km = newkeymap(); | |
287 | curmap = curmap->km_ptr[ch].km_km; | |
288 | } | |
289 | else { | |
290 | if ((curmap->km_type[ch] & KM_TMASK) == KM_KEYMAP) | |
291 | puts(override,stdout) FLUSH; | |
292 | else { | |
293 | curmap->km_type[ch] = KM_STRING + garbage; | |
294 | curmap->km_ptr[ch].km_str = savestr(m); | |
295 | } | |
296 | } | |
297 | } | |
298 | } | |
299 | ||
300 | KEYMAP* | |
301 | newkeymap() | |
302 | { | |
303 | register int i; | |
304 | register KEYMAP *map; | |
305 | ||
306 | #ifndef lint | |
307 | map = (KEYMAP*)safemalloc(sizeof(KEYMAP)); | |
308 | #else | |
309 | map = Null(KEYMAP*); | |
310 | #endif lint | |
311 | for (i=127; i>=0; --i) { | |
312 | map->km_ptr[i].km_km = Null(KEYMAP*); | |
313 | map->km_type[i] = KM_NOTHIN; | |
314 | } | |
315 | return map; | |
316 | } | |
317 | ||
318 | void | |
319 | show_macros() | |
320 | { | |
321 | char prebuf[64]; | |
322 | ||
323 | if (topmap != Null(KEYMAP*)) { | |
324 | print_lines("Macros:\n",STANDOUT); | |
325 | *prebuf = '\0'; | |
326 | show_keymap(topmap,prebuf); | |
327 | } | |
328 | } | |
329 | ||
330 | void | |
331 | show_keymap(curmap,prefix) | |
332 | register KEYMAP *curmap; | |
333 | char *prefix; | |
334 | { | |
335 | register int i; | |
336 | register char *next = prefix + strlen(prefix); | |
337 | register int kt; | |
338 | ||
339 | for (i=0; i<128; i++) { | |
340 | if (kt = curmap->km_type[i]) { | |
341 | if (i < ' ') | |
342 | sprintf(next,"^%c",i+64); | |
343 | else if (i == ' ') | |
344 | strcpy(next,"\\040"); | |
345 | else if (i == 127) | |
346 | strcpy(next,"^?"); | |
347 | else | |
348 | sprintf(next,"%c",i); | |
349 | if ((kt >> KM_GSHIFT) & KM_GMASK) { | |
350 | sprintf(cmd_buf,"+%d", (kt >> KM_GSHIFT) & KM_GMASK); | |
351 | strcat(next,cmd_buf); | |
352 | } | |
353 | switch (kt & KM_TMASK) { | |
354 | case KM_NOTHIN: | |
355 | sprintf(cmd_buf,"%s %c\n",prefix,i); | |
356 | print_lines(cmd_buf,NOMARKING); | |
357 | break; | |
358 | case KM_KEYMAP: | |
359 | show_keymap(curmap->km_ptr[(char)i].km_km, prefix); | |
360 | break; | |
361 | case KM_STRING: | |
362 | sprintf(cmd_buf,"%s %s\n",prefix,curmap->km_ptr[i].km_str); | |
363 | print_lines(cmd_buf,NOMARKING); | |
364 | break; | |
365 | case KM_BOGUS: | |
366 | sprintf(cmd_buf,"%s BOGUS\n",prefix); | |
367 | print_lines(cmd_buf,STANDOUT); | |
368 | break; | |
369 | } | |
370 | } | |
371 | } | |
372 | } | |
373 | ||
374 | #endif | |
375 | ||
376 | /* routine to pass to tputs */ | |
377 | ||
378 | char | |
379 | putchr(ch) | |
380 | register char ch; | |
381 | { | |
382 | putchar(ch); | |
383 | #ifdef lint | |
384 | ch = Null(char); | |
385 | ch = ch; | |
386 | #endif | |
387 | } | |
388 | ||
389 | /* input the 2nd and succeeding characters of a multi-character command */ | |
390 | /* returns TRUE if command finished, FALSE if they rubbed out first character */ | |
391 | ||
392 | bool | |
393 | finish_command(donewline) | |
394 | int donewline; | |
395 | { | |
396 | register char *s; | |
397 | register bool quoteone = FALSE; | |
398 | ||
399 | s = buf; | |
400 | if (s[1] != FINISHCMD) /* someone faking up a command? */ | |
401 | return TRUE; | |
402 | do { | |
403 | top: | |
404 | if (*s < ' ') { | |
405 | putchar('^'); | |
406 | putchar(*s | 64); | |
407 | } | |
408 | else if (*s == '\177') { | |
409 | putchar('^'); | |
410 | putchar('?'); | |
411 | } | |
412 | else | |
413 | putchar(*s); /* echo previous character */ | |
414 | s++; | |
415 | re_read: | |
416 | fflush(stdout); | |
417 | getcmd(s); | |
418 | if (quoteone) { | |
419 | quoteone = FALSE; | |
420 | continue; | |
421 | } | |
422 | if (errno || *s == Ctl('l')) { | |
423 | *s = Ctl('r'); /* force rewrite on CONT */ | |
424 | } | |
425 | if (*s == '\033') { /* substitution desired? */ | |
426 | #ifdef ESCSUBS | |
427 | char tmpbuf[4], *cpybuf; | |
428 | ||
429 | tmpbuf[0] = '%'; | |
430 | read_tty(&tmpbuf[1],1); | |
431 | #ifdef RAWONLY | |
432 | tmpbuf[1] &= 0177; | |
433 | #endif | |
434 | tmpbuf[2] = '\0'; | |
435 | if (tmpbuf[1] == 'h') { | |
436 | (void) help_subs(); | |
437 | *s = '\0'; | |
438 | reprint(); | |
439 | goto re_read; | |
440 | } | |
441 | else if (tmpbuf[1] == '\033') { | |
442 | *s = '\0'; | |
443 | cpybuf = savestr(buf); | |
444 | interp(buf, (sizeof buf), cpybuf); | |
445 | free(cpybuf); | |
446 | s = buf + strlen(buf); | |
447 | reprint(); | |
448 | goto re_read; | |
449 | } | |
450 | else { | |
451 | interp(s,(sizeof buf) - (s-buf),tmpbuf); | |
452 | fputs(s,stdout); | |
453 | s += strlen(s); | |
454 | } | |
455 | goto re_read; | |
456 | #else | |
457 | notincl("^["); | |
458 | *s = '\0'; | |
459 | reprint(); | |
460 | goto re_read; | |
461 | #endif | |
462 | } | |
463 | else if (*s == ERASECH) { /* they want to rubout a char? */ | |
464 | rubout(); | |
465 | s--; /* discount the char rubbed out */ | |
466 | if (*s < ' ' || *s == '\177') | |
467 | rubout(); | |
468 | if (s == buf) { /* entire string gone? */ | |
469 | fflush(stdout); /* return to single char command mode */ | |
470 | return FALSE; | |
471 | } | |
472 | else | |
473 | goto re_read; | |
474 | } | |
475 | else if (*s == KILLCH) { /* wipe out the whole line? */ | |
476 | while (s-- != buf) { /* emulate that many ERASEs */ | |
477 | rubout(); | |
478 | if (*s < ' ' || *s == '\177') | |
479 | rubout(); | |
480 | } | |
481 | fflush(stdout); | |
482 | return FALSE; /* return to single char mode */ | |
483 | } | |
484 | #ifdef WORDERASE | |
485 | else if (*s == Ctl('w')) { /* wipe out one word? */ | |
486 | *s-- = ' '; | |
487 | while (!isspace(*s) || isspace(s[1])) { | |
488 | rubout(); | |
489 | if (s-- == buf) { | |
490 | fflush(stdout); | |
491 | return FALSE; /* return to single char mode */ | |
492 | } | |
493 | if (*s < ' ' || *s == '\177') | |
494 | rubout(); | |
495 | } | |
496 | s++; | |
497 | goto re_read; | |
498 | } | |
499 | #endif | |
500 | else if (*s == Ctl('r')) { | |
501 | *s = '\0'; | |
502 | reprint(); | |
503 | goto re_read; | |
504 | } | |
505 | else if (*s == Ctl('v')) { | |
506 | putchar('^'); | |
507 | backspace(); | |
508 | fflush(stdout); | |
509 | getcmd(s); | |
510 | goto top; | |
511 | } | |
512 | else if (*s == '\\') { | |
513 | quoteone = TRUE; | |
514 | } | |
515 | } while (*s != '\n'); /* till a newline (not echoed) */ | |
516 | *s = '\0'; /* terminate the string nicely */ | |
517 | if (donewline) | |
518 | putchar('\n') FLUSH; | |
519 | return TRUE; /* say we succeeded */ | |
520 | } | |
521 | ||
522 | /* discard any characters typed ahead */ | |
523 | ||
524 | void | |
525 | eat_typeahead() | |
526 | { | |
527 | #ifdef PUSHBACK | |
528 | if (!typeahead && nextin==nextout) /* cancel only keyboard stuff */ | |
529 | #else | |
530 | if (!typeahead) | |
531 | #endif | |
532 | { | |
533 | #ifdef PENDING | |
534 | while (input_pending()) | |
535 | read_tty(buf,sizeof(buf)); | |
536 | #else /* this is probably v7 */ | |
537 | ioctl(_tty_ch,TIOCSETP,&_tty); | |
538 | #endif | |
539 | } | |
540 | } | |
541 | ||
542 | void | |
543 | settle_down() | |
544 | { | |
545 | dingaling(); | |
546 | fflush(stdout); | |
547 | sleep(1); | |
548 | #ifdef PUSHBACK | |
549 | nextout = nextin; /* empty circlebuf */ | |
550 | #endif | |
551 | eat_typeahead(); | |
552 | } | |
553 | ||
554 | #ifdef PUSHBACK | |
555 | /* read a character from the terminal, with multi-character pushback */ | |
556 | ||
557 | int | |
558 | read_tty(addr,size) | |
559 | char *addr; | |
560 | int size; | |
561 | { | |
562 | if (nextout != nextin) { | |
563 | *addr = circlebuf[nextout++]; | |
564 | nextout %= PUSHSIZE; | |
565 | return 1; | |
566 | } | |
567 | else { | |
568 | size = read(0,addr,size); | |
569 | #ifdef RAWONLY | |
570 | *addr &= 0177; | |
571 | #endif | |
572 | return size; | |
573 | } | |
574 | } | |
575 | ||
576 | #ifdef PENDING | |
577 | #ifndef FIONREAD | |
578 | int | |
579 | circfill() | |
580 | { | |
581 | register int howmany = read(devtty,circlebuf+nextin,1); | |
582 | ||
583 | if (howmany) { | |
584 | nextin += howmany; | |
585 | nextin %= PUSHSIZE; | |
586 | } | |
587 | return howmany; | |
588 | } | |
589 | #endif PENDING | |
590 | #endif FIONREAD | |
591 | ||
592 | void | |
593 | pushchar(c) | |
594 | char c; | |
595 | { | |
596 | nextout--; | |
597 | if (nextout < 0) | |
598 | nextout = PUSHSIZE - 1; | |
599 | if (nextout == nextin) { | |
600 | fputs("\npushback buffer overflow\n",stdout) FLUSH; | |
601 | sig_catcher(0); | |
602 | } | |
603 | circlebuf[nextout] = c; | |
604 | } | |
605 | ||
606 | #else PUSHBACK | |
607 | #ifndef read_tty | |
608 | /* read a character from the terminal, with hacks for O_NDELAY reads */ | |
609 | ||
610 | int | |
611 | read_tty(addr,size) | |
612 | char *addr; | |
613 | int size; | |
614 | { | |
615 | if (is_input) { | |
616 | *addr = pending_ch; | |
617 | is_input = FALSE; | |
618 | return 1; | |
619 | } | |
620 | else { | |
621 | size = read(0,addr,size) | |
622 | #ifdef RAWONLY | |
623 | *addr &= 0177; | |
624 | #endif | |
625 | return size; | |
626 | } | |
627 | } | |
628 | #endif read_tty | |
629 | #endif PUSHBACK | |
630 | ||
631 | /* print an underlined string, one way or another */ | |
632 | ||
633 | void | |
634 | underprint(s) | |
635 | register char *s; | |
636 | { | |
637 | assert(UC); | |
638 | if (*UC) { /* char by char underline? */ | |
639 | while (*s) { | |
640 | if (*s < ' ') { | |
641 | putchar('^'); | |
642 | backspace();/* back up over it */ | |
643 | underchar();/* and do the underline */ | |
644 | putchar(*s+64); | |
645 | backspace();/* back up over it */ | |
646 | underchar();/* and do the underline */ | |
647 | } | |
648 | else { | |
649 | putchar(*s); | |
650 | backspace();/* back up over it */ | |
651 | underchar();/* and do the underline */ | |
652 | } | |
653 | s++; | |
654 | } | |
655 | } | |
656 | else { /* start and stop underline */ | |
657 | underline(); /* start underlining */ | |
658 | while (*s) { | |
659 | if (*s < ' ') { | |
660 | putchar('^'); | |
661 | putchar(*s+64); | |
662 | } | |
663 | else | |
664 | putchar(*s); | |
665 | s++; | |
666 | } | |
667 | un_underline(); /* stop underlining */ | |
668 | } | |
669 | } | |
670 | ||
671 | /* keep screen from flashing strangely on magic cookie terminals */ | |
672 | ||
673 | #ifdef NOFIREWORKS | |
674 | void | |
675 | no_sofire() | |
676 | { | |
677 | if (*UP && *SE) { /* should we disable fireworks? */ | |
678 | putchar('\n'); | |
679 | un_standout(); | |
680 | up_line(); | |
681 | carriage_return(); | |
682 | } | |
683 | } | |
684 | ||
685 | void | |
686 | no_ulfire() | |
687 | { | |
688 | if (*UP && *US) { /* should we disable fireworks? */ | |
689 | putchar('\n'); | |
690 | un_underline(); | |
691 | up_line(); | |
692 | carriage_return(); | |
693 | } | |
694 | } | |
695 | #endif | |
696 | ||
697 | /* get a character into a buffer */ | |
698 | ||
699 | void | |
700 | getcmd(whatbuf) | |
701 | register char *whatbuf; | |
702 | { | |
703 | #ifdef PUSHBACK | |
704 | register KEYMAP *curmap; | |
705 | register int i; | |
706 | bool no_macros; | |
707 | int times = 0; /* loop detector */ | |
708 | char scrchar; | |
709 | ||
710 | tryagain: | |
711 | curmap = topmap; | |
712 | no_macros = (whatbuf != buf && nextin == nextout); | |
713 | #endif | |
714 | for (;;) { | |
715 | int_count = 0; | |
716 | errno = 0; | |
717 | if (read_tty(whatbuf,1) < 0 && !errno) | |
718 | errno = EINTR; | |
719 | if (errno && errno != EINTR) { | |
720 | perror(readerr); | |
721 | sig_catcher(0); | |
722 | } | |
723 | #ifdef PUSHBACK | |
724 | if (*whatbuf & 0200 || no_macros) { | |
725 | *whatbuf &= 0177; | |
726 | goto got_canonical; | |
727 | } | |
728 | if (curmap == Null(KEYMAP*)) | |
729 | goto got_canonical; | |
730 | for (i = (curmap->km_type[*whatbuf] >> KM_GSHIFT) & KM_GMASK; i; --i){ | |
731 | read_tty(&scrchar,1); | |
732 | } | |
733 | switch (curmap->km_type[*whatbuf] & KM_TMASK) { | |
734 | case KM_NOTHIN: /* no entry? */ | |
735 | if (curmap == topmap) /* unmapped canonical */ | |
736 | goto got_canonical; | |
737 | settle_down(); | |
738 | goto tryagain; | |
739 | case KM_KEYMAP: /* another keymap? */ | |
740 | curmap = curmap->km_ptr[*whatbuf].km_km; | |
741 | assert(curmap != Null(KEYMAP*)); | |
742 | break; | |
743 | case KM_STRING: /* a string? */ | |
744 | pushstring(curmap->km_ptr[*whatbuf].km_str); | |
745 | if (++times > 20) { /* loop? */ | |
746 | fputs("\nmacro loop?\n",stdout); | |
747 | settle_down(); | |
748 | } | |
749 | no_macros = FALSE; | |
750 | goto tryagain; | |
751 | } | |
752 | #else | |
753 | #ifdef RAWONLY | |
754 | *whatbuf &= 0177; | |
755 | #endif | |
756 | break; | |
757 | #endif | |
758 | } | |
759 | ||
760 | got_canonical: | |
761 | #ifndef TERMIO | |
762 | if (*whatbuf == '\r') | |
763 | *whatbuf = '\n'; | |
764 | #endif | |
765 | if (whatbuf == buf) | |
766 | whatbuf[1] = FINISHCMD; /* tell finish_command to work */ | |
767 | } | |
768 | ||
769 | #ifdef PUSHBACK | |
770 | void | |
771 | pushstring(str) | |
772 | char *str; | |
773 | { | |
774 | register int i; | |
775 | char tmpbuf[PUSHSIZE]; | |
776 | register char *s = tmpbuf; | |
777 | ||
778 | assert(str != Nullch); | |
779 | interp(s,PUSHSIZE,str); | |
780 | for (i = strlen(s)-1; i >= 0; --i) { | |
781 | s[i] ^= 0200; | |
782 | pushchar(s[i]); | |
783 | } | |
784 | } | |
785 | #endif | |
786 | ||
787 | int | |
788 | get_anything() | |
789 | { | |
790 | char tmpbuf[2]; | |
791 | ||
792 | reask_anything: | |
793 | unflush_output(); /* disable any ^O in effect */ | |
794 | standout(); | |
795 | #ifdef VERBOSE | |
796 | IF(verbose) | |
797 | fputs("[Type space to continue] ",stdout); | |
798 | ELSE | |
799 | #endif | |
800 | #ifdef TERSE | |
801 | fputs("[MORE] ",stdout); | |
802 | #endif | |
803 | un_standout(); | |
804 | fflush(stdout); | |
805 | eat_typeahead(); | |
806 | if (int_count) { | |
807 | return -1; | |
808 | } | |
809 | collect_subjects(); /* loads subject cache until */ | |
810 | /* input is pending */ | |
811 | getcmd(tmpbuf); | |
812 | if (errno || *tmpbuf == '\f') { | |
813 | putchar('\n') FLUSH; /* if return from stop signal */ | |
814 | goto reask_anything; /* give them a prompt again */ | |
815 | } | |
816 | if (*tmpbuf == 'h') { | |
817 | #ifdef VERBOSE | |
818 | IF(verbose) | |
819 | fputs("\nType q to quit or space to continue.\n",stdout) FLUSH; | |
820 | ELSE | |
821 | #endif | |
822 | #ifdef TERSE | |
823 | fputs("\nq to quit, space to continue.\n",stdout) FLUSH; | |
824 | #endif | |
825 | goto reask_anything; | |
826 | } | |
827 | else if (*tmpbuf != ' ' && *tmpbuf != '\n') { | |
828 | carriage_return(); | |
829 | erase_eol(); /* erase the prompt */ | |
830 | return *tmpbuf == 'q' ? -1 : *tmpbuf; | |
831 | } | |
832 | if (*tmpbuf == '\n') { | |
833 | page_line = LINES - 1; | |
834 | carriage_return(); | |
835 | erase_eol(); | |
836 | } | |
837 | else { | |
838 | page_line = 1; | |
839 | if (erase_screen) /* -e? */ | |
840 | clear(); /* clear screen */ | |
841 | else { | |
842 | carriage_return(); | |
843 | erase_eol(); /* erase the prompt */ | |
844 | } | |
845 | } | |
846 | return 0; | |
847 | } | |
848 | ||
849 | void | |
850 | in_char(prompt) | |
851 | char *prompt; | |
852 | { | |
853 | char oldmode = mode; | |
854 | ||
855 | reask_in_char: | |
856 | unflush_output(); /* disable any ^O in effect */ | |
857 | fputs(prompt,stdout); | |
858 | fflush(stdout); | |
859 | eat_typeahead(); | |
860 | mode = 'm'; | |
861 | getcmd(buf); | |
862 | if (errno || *buf == '\f') { | |
863 | putchar('\n') FLUSH; /* if return from stop signal */ | |
864 | goto reask_in_char; /* give them a prompt again */ | |
865 | } | |
866 | mode = oldmode; | |
867 | } | |
868 | ||
869 | int | |
870 | print_lines(what_to_print,hilite) | |
871 | char *what_to_print; | |
872 | int hilite; | |
873 | { | |
874 | register char *s; | |
875 | register int i; | |
876 | ||
877 | if (page_line < 0) /* they do not want to see this? */ | |
878 | return -1; | |
879 | for (s=what_to_print; *s; ) { | |
880 | if (page_line >= LINES || int_count) { | |
881 | if (i = -1, int_count || (i = get_anything())) { | |
882 | page_line = -1; /* disable further print_lines */ | |
883 | return i; | |
884 | } | |
885 | } | |
886 | page_line++; | |
887 | if (hilite == STANDOUT) { | |
888 | #ifdef NOFIREWORKS | |
889 | if (erase_screen) | |
890 | no_sofire(); | |
891 | #endif | |
892 | standout(); | |
893 | } | |
894 | else if (hilite == UNDERLINE) { | |
895 | #ifdef NOFIREWORKS | |
896 | if (erase_screen) | |
897 | no_ulfire(); | |
898 | #endif | |
899 | underline(); | |
900 | } | |
901 | for (i=0; i<COLS; i++) { | |
902 | if (!*s) | |
903 | break; | |
904 | if (*s >= ' ') | |
905 | putchar(*s); | |
906 | else if (*s == '\t') { | |
907 | putchar(*s); | |
908 | i = ((i+8) & ~7) - 1; | |
909 | } | |
910 | else if (*s == '\n') { | |
911 | i = 32000; | |
912 | } | |
913 | else { | |
914 | i++; | |
915 | putchar('^'); | |
916 | putchar(*s + 64); | |
917 | } | |
918 | s++; | |
919 | } | |
920 | if (i) { | |
921 | if (hilite == STANDOUT) | |
922 | un_standout(); | |
923 | else if (hilite == UNDERLINE) | |
924 | un_underline(); | |
925 | if (AM && i == COLS) | |
926 | fflush(stdout); | |
927 | else | |
928 | putchar('\n') FLUSH; | |
929 | } | |
930 | } | |
931 | return 0; | |
932 | } | |
933 | ||
934 | void | |
935 | page_init() | |
936 | { | |
937 | page_line = 1; | |
938 | if (erase_screen) | |
939 | clear(); | |
940 | else | |
941 | putchar('\n') FLUSH; | |
942 | } | |
943 | ||
944 | void | |
945 | pad(num) | |
946 | int num; | |
947 | { | |
948 | register int i; | |
949 | ||
950 | for (i = num; i; --i) | |
951 | putchar(PC); | |
952 | fflush(stdout); | |
953 | } | |
954 | ||
955 | /* echo the command just typed */ | |
956 | ||
957 | #ifdef VERIFY | |
958 | void | |
959 | printcmd() | |
960 | { | |
961 | if (verify && buf[1] == FINISHCMD) { | |
962 | if (*buf < ' ') { | |
963 | putchar('^'); | |
964 | putchar(*buf | 64); | |
965 | backspace(); | |
966 | backspace(); | |
967 | } | |
968 | else { | |
969 | putchar(*buf); | |
970 | backspace(); | |
971 | } | |
972 | fflush(stdout); | |
973 | } | |
974 | } | |
975 | #endif | |
976 | ||
977 | void | |
978 | rubout() | |
979 | { | |
980 | backspace(); /* do the old backspace, */ | |
981 | putchar(' '); /* space, */ | |
982 | backspace(); /* backspace trick */ | |
983 | } | |
984 | ||
985 | void | |
986 | reprint() | |
987 | { | |
988 | register char *s; | |
989 | ||
990 | fputs("^R\n",stdout) FLUSH; | |
991 | for (s = buf; *s; s++) { | |
992 | if (*s < ' ') { | |
993 | putchar('^'); | |
994 | putchar(*s | 64); | |
995 | } | |
996 | else | |
997 | putchar(*s); | |
998 | } | |
999 | } | |
1000 | ||
1001 | #ifdef CLEAREOL | |
1002 | /* start of additions by Paul Placeway (PWP) */ | |
1003 | ||
1004 | void | |
1005 | home_cursor() | |
1006 | { | |
1007 | char *tgoto(); | |
1008 | ||
1009 | if (!*HO) { /* no home sequence? */ | |
1010 | if (!*CM) { /* no cursor motion either? */ | |
1011 | fputs ("\n\n\n", stdout); | |
1012 | return; /* forget it. */ | |
1013 | } | |
1014 | tputs (tgoto (CM, 0, 0), 1, putchr); /* go to home via CM */ | |
1015 | return; | |
1016 | } | |
1017 | else { /* we have home sequence */ | |
1018 | tputs (HO, 1, putchr); /* home via HO */ | |
1019 | } | |
1020 | } | |
1021 | #endif CLEAREOL |