1 /* $NetBSD: io.c,v 1.31 2024/03/26 20:50:29 andvar Exp $ */
2
3 /*
4 * io.c Larn is copyrighted 1986 by Noah Morgan.
5 *
6 * Below are the functions in this file:
7 *
8 * setupvt100() Subroutine to set up terminal in correct mode for game
9 * clearvt100() Subroutine to clean up terminal when the game is over
10 * ttgetch() Routine to read in one character from the terminal
11 * scbr() Function to set cbreak -echo for the terminal
12 * sncbr() Function to set -cbreak echo for the terminal
13 * newgame() Subroutine to save the initial time and seed rnd()
14 *
15 * FILE OUTPUT ROUTINES
16 *
17 * lprintf(format,args . . .) printf to the output buffer
18 * lprint(integer) send binary integer to output buffer
19 * lwrite(buf,len) write a buffer to the output buffer
20 * lprcat(str) append a string to the output buffer
21 *
22 * FILE OUTPUT MACROS (in header.h)
23 *
24 * lprc(character) put the character into the output buffer
25 *
26 * FILE INPUT ROUTINES
27 *
28 * long lgetc() read one character from input buffer
29 * long larn_lrint() read one integer from input buffer
30 * lrfill(address,number) put input bytes into a buffer char
31 * *lgetw() get a whitespace ended word from
32 * input char *lgetl() get a \n or EOF ended line from input
33 *
34 * FILE OPEN / CLOSE ROUTINES
35 *
36 * lcreat(filename) create a new file for write
37 * lopen(filename) open a file for read
38 * lappend(filename) open for append to an existing file
39 * lrclose() close the input file
40 * lwclose() close output file
41 * lflush() flush the output buffer
42 *
43 * Other Routines
44 *
45 * cursor(x,y) position cursor at [x,y]
46 * cursors() position cursor at [1,24] (saves memory)
47 * cl_line(x,y) clear line at [1,y] and leave cursor at [x,y]
48 * cl_up(x,y) clear screen from [x,1] to current line
49 * cl_dn(x,y) clear screen from [1,y] to end of display
50 * standout(str) print the string in standout mode
51 * set_score_output() called when output should be literally printed
52 * ttputch(ch) print one character in decoded output buffer
53 * flush_buf() flush buffer with decoded output
54 * init_term() terminal initialization -- setup termcap info
55 * char *tmcapcnv(sd,ss) routine to convert VT100 \33's to termcap format
56 * beep() routine to emit a beep if enabled
57 * (see no-beep in .larnopts)
58 *
59 * Note: ** entries are available only in termcap mode.
60 */
61 #include <sys/cdefs.h>
62 #ifndef lint
63 __RCSID("$NetBSD: io.c,v 1.31 2024/03/26 20:50:29 andvar Exp $");
64 #endif /* not lint */
65
66 #include "header.h"
67 #include "extern.h"
68 #include <string.h>
69 #include <unistd.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <time.h>
73 #include <term.h>
74 #include <fcntl.h>
75 #include <errno.h>
76 #include <ctype.h>
77
78 #ifdef TERMIO
79 #include <termio.h>
80 #define sgttyb termio
81 #define stty(_a,_b) ioctl(_a,TCSETA,_b)
82 #define gtty(_a,_b) ioctl(_a,TCGETA,_b)
83 #endif
84 #ifdef TERMIOS
85 #include <termios.h>
86 #define sgttyb termios
87 #define stty(_a,_b) tcsetattr(_a,TCSADRAIN,_b)
88 #define gtty(_a,_b) tcgetattr(_a,_b)
89 #endif
90
91 #if defined(TERMIO) || defined(TERMIOS)
92 static int rawflg = 0;
93 static char saveeof, saveeol;
94 #define doraw(_a) \
95 if(!rawflg) { \
96 ++rawflg; \
97 saveeof = _a.c_cc[VMIN]; \
98 saveeol = _a.c_cc[VTIME]; \
99 } \
100 _a.c_cc[VMIN] = 1; \
101 _a.c_cc[VTIME] = 1; \
102 _a.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL)
103 #define unraw(_a) \
104 _a.c_cc[VMIN] = saveeof; \
105 _a.c_cc[VTIME] = saveeol; \
106 _a.c_lflag |= ICANON|ECHO|ECHOE|ECHOK|ECHONL
107
108 #else /* not TERMIO or TERMIOS */
109
110 #ifndef BSD
111 #define CBREAK RAW /* V7 has no CBREAK */
112 #endif
113
114 #define doraw(_a) (_a.sg_flags |= CBREAK,_a.sg_flags &= ~ECHO)
115 #define unraw(_a) (_a.sg_flags &= ~CBREAK,_a.sg_flags |= ECHO)
116 #include <sgtty.h>
117 #endif /* not TERMIO or TERMIOS */
118
119 #ifndef NOVARARGS /* if we have varargs */
120 #include <stdarg.h>
121 #else /* NOVARARGS */ /* if we don't have varargs */
122 typedef char *va_list;
123 #define va_dcl int va_alist;
124 #define va_start(plist) plist = (char *) &va_alist
125 #define va_end(plist)
126 #define va_arg(plist,mode) ((mode *)(plist += sizeof(mode)))[-1]
127 #endif /* NOVARARGS */
128
129 static int ttputch(int ch);
130 static void flush_buf(void);
131
132 #define LINBUFSIZE 128 /* size of the lgetw() and lgetl() buffer */
133 int io_outfd; /* output file numbers */
134 int io_infd; /* input file numbers */
135 static struct sgttyb ttx;/* storage for the tty modes */
136 static int ipoint = MAXIBUF, iepoint = MAXIBUF; /* input buffering
137 * pointers */
138 static char lgetwbuf[LINBUFSIZE]; /* get line (word) buffer */
139
140 /*
141 * setupvt100() Subroutine to set up terminal in correct mode for game
142 *
143 * Attributes off, clear screen, set scrolling region, set tty mode
144 */
145 void
setupvt100(void)146 setupvt100(void)
147 {
148 clear();
149 setscroll();
150 scbr(); /* system("stty cbreak -echo"); */
151 }
152
153 /*
154 * clearvt100() Subroutine to clean up terminal when the game is over
155 *
156 * Attributes off, clear screen, unset scrolling region, restore tty mode
157 */
158 void
clearvt100(void)159 clearvt100(void)
160 {
161 resetscroll();
162 clear();
163 sncbr(); /* system("stty -cbreak echo"); */
164 }
165
166 /*
167 * ttgetch() Routine to read in one character from the terminal
168 */
169 int
ttgetch(void)170 ttgetch(void)
171 {
172 char byt;
173 #ifdef EXTRA
174 c[BYTESIN]++;
175 #endif
176 lflush(); /* be sure output buffer is flushed */
177 read(0, &byt, 1); /* get byte from terminal */
178 return (byt);
179 }
180
181 /*
182 * scbr() Function to set cbreak -echo for the terminal
183 *
184 * like: system("stty cbreak -echo")
185 */
186 void
scbr(void)187 scbr(void)
188 {
189 gtty(0, &ttx);
190 doraw(ttx);
191 stty(0, &ttx);
192 }
193
194 /*
195 * sncbr() Function to set -cbreak echo for the terminal
196 *
197 * like: system("stty -cbreak echo")
198 */
199 void
sncbr(void)200 sncbr(void)
201 {
202 gtty(0, &ttx);
203 unraw(ttx);
204 stty(0, &ttx);
205 }
206
207 /*
208 * newgame() Subroutine to save the initial time and seed rnd()
209 */
210 void
newgame(void)211 newgame(void)
212 {
213 long *p, *pe;
214 for (p = c, pe = c + 100; p < pe; *p++ = 0);
215 time(&initialtime);
216 seedrand(initialtime);
217 srandom(initialtime);
218 lcreat((char *) 0); /* open buffering for output to terminal */
219 }
220
221 /*
222 * lprintf(format,args . . .) printf to the output buffer
223 * char *format;
224 * ??? args . . .
225 *
226 * Enter with the format string in "format", as per printf() usage
227 * and any needed arguments following it
228 * Note: lprintf() only supports %s, %c and %d, with width modifier and left
229 * or right justification.
230 * No correct checking for output buffer overflow is done, but flushes
231 * are done beforehand if needed.
232 * Returns nothing of value.
233 */
234 void
lprintf(const char * fmt,...)235 lprintf(const char *fmt, ...)
236 {
237 va_list ap;
238 char buf[BUFBIG/2];
239
240 va_start(ap, fmt);
241 vsnprintf(buf, sizeof(buf), fmt, ap);
242 va_end(ap);
243
244 if (lpnt >= lpend)
245 lflush();
246
247 lprcat(buf);
248 }
249
250 /*
251 * lprint(long-integer) send binary integer to output buffer
252 * long integer;
253 *
254 * +---------+---------+---------+---------+
255 * | high | | | low |
256 * | order | | | order |
257 * | byte | | | byte |
258 * +---------+---------+---------+---------+
259 * 31 --- 24 23 --- 16 15 --- 8 7 --- 0
260 *
261 * The save order is low order first, to high order (4 bytes total)
262 * and is written to be system independent.
263 * No checking for output buffer overflow is done, but flushes if needed!
264 * Returns nothing of value.
265 */
266 void
lprint(long x)267 lprint(long x)
268 {
269 if (lpnt >= lpend)
270 lflush();
271 *lpnt++ = 255 & x;
272 *lpnt++ = 255 & (x >> 8);
273 *lpnt++ = 255 & (x >> 16);
274 *lpnt++ = 255 & (x >> 24);
275 }
276
277 /*
278 * lwrite(buf,len) write a buffer to the output buffer
279 * char *buf;
280 * int len;
281 *
282 * Enter with the address and number of bytes to write out
283 * Returns nothing of value
284 */
285 void
lwrite(char * buf,int len)286 lwrite(char *buf, int len)
287 {
288 char *s;
289 u_char *t;
290 int num2;
291
292 if (len > 399) { /* don't copy data if can just write it */
293 #ifdef EXTRA
294 c[BYTESOUT] += len;
295 #endif
296
297 #ifndef VT100
298 for (s = buf; len > 0; --len)
299 lprc(*s++);
300 #else /* VT100 */
301 lflush();
302 write(io_outfd, buf, len);
303 #endif /* VT100 */
304 } else
305 while (len) {
306 if (lpnt >= lpend)
307 lflush(); /* if buffer is full flush it */
308 num2 = lpbuf + BUFBIG - lpnt; /* # bytes left in
309 * output buffer */
310 if (num2 > len)
311 num2 = len;
312 t = lpnt;
313 len -= num2;
314 while (num2--)
315 *t++ = *buf++; /* copy in the bytes */
316 lpnt = t;
317 }
318 }
319
320 /*
321 * long lgetc() Read one character from input buffer
322 *
323 * Returns 0 if EOF, otherwise the character
324 */
325 long
lgetc(void)326 lgetc(void)
327 {
328 int i;
329 if (ipoint != iepoint)
330 return (inbuffer[ipoint++]);
331 if (iepoint != MAXIBUF)
332 return (0);
333 if ((i = read(io_infd, inbuffer, MAXIBUF)) <= 0) {
334 if (i != 0)
335 write(1, "error reading from input file\n", 30);
336 iepoint = ipoint = 0;
337 return (0);
338 }
339 ipoint = 1;
340 iepoint = i;
341 return (*inbuffer);
342 }
343
344 /*
345 * long lrint() Read one integer from input buffer
346 *
347 * +---------+---------+---------+---------+
348 * | high | | | low |
349 * | order | | | order |
350 * | byte | | | byte |
351 * +---------+---------+---------+---------+
352 * 31 --- 24 23 --- 16 15 --- 8 7 --- 0
353 *
354 * The save order is low order first, to high order (4 bytes total)
355 * Returns the int read
356 */
357 long
larn_lrint(void)358 larn_lrint(void)
359 {
360 unsigned long i;
361 i = 255 & lgetc();
362 i |= (255 & lgetc()) << 8;
363 i |= (255 & lgetc()) << 16;
364 i |= (255 & lgetc()) << 24;
365 return (i);
366 }
367
368 /*
369 * lrfill(address,number) put input bytes into a buffer
370 * char *address;
371 * int number;
372 *
373 * Reads "number" bytes into the buffer pointed to by "address".
374 * Returns nothing of value
375 */
376 void
lrfill(char * adr,int num)377 lrfill(char *adr, int num)
378 {
379 u_char *pnt;
380 int num2;
381
382 while (num) {
383 if (iepoint == ipoint) {
384 if (num > 5) { /* fast way */
385 if (read(io_infd, adr, num) != num)
386 write(2, "error reading from input file\n", 30);
387 num = 0;
388 } else {
389 *adr++ = lgetc();
390 --num;
391 }
392 } else {
393 num2 = iepoint - ipoint; /* # of bytes left in
394 * the buffer */
395 if (num2 > num)
396 num2 = num;
397 pnt = inbuffer + ipoint;
398 num -= num2;
399 ipoint += num2;
400 while (num2--)
401 *adr++ = *pnt++;
402 }
403 }
404 }
405
406 /*
407 * char *lgetw() Get a whitespace ended word from input
408 *
409 * Returns pointer to a buffer that contains word. If EOF, returns a NULL
410 */
411 char *
lgetw(void)412 lgetw(void)
413 {
414 char *lgp, cc;
415 int n = LINBUFSIZE, quote = 0;
416 lgp = lgetwbuf;
417 do
418 cc = lgetc();
419 while ((cc <= 32) && (cc > '\0')); /* eat whitespace */
420 for (;; --n, cc = lgetc()) {
421 if ((cc == '\0') && (lgp == lgetwbuf))
422 return (NULL); /* EOF */
423 if ((n <= 1) || ((cc <= 32) && (quote == 0))) {
424 *lgp = '\0';
425 return (lgetwbuf);
426 }
427 if (cc != '"')
428 *lgp++ = cc;
429 else
430 quote ^= 1;
431 }
432 }
433
434 /*
435 * char *lgetl() Function to read in a line ended by newline or EOF
436 *
437 * Returns pointer to a buffer that contains the line. If EOF, returns NULL
438 */
439 char *
lgetl(void)440 lgetl(void)
441 {
442 int i = LINBUFSIZE, ch;
443 char *str = lgetwbuf;
444 for (;; --i) {
445 if ((*str++ = ch = lgetc()) == '\0') {
446 if (str == lgetwbuf + 1)
447 return (NULL); /* EOF */
448 ot: *str = '\0';
449 return (lgetwbuf); /* line ended by EOF */
450 }
451 if ((ch == '\n') || (i <= 1))
452 goto ot;/* line ended by \n */
453 }
454 }
455
456 /*
457 * lcreat(filename) Create a new file for write
458 * char *filename;
459 *
460 * lcreat((char*)0); means to the terminal
461 * Returns -1 if error, otherwise the file descriptor opened.
462 */
463 int
lcreat(char * str)464 lcreat(char *str)
465 {
466 lflush();
467 lpnt = lpbuf;
468 lpend = lpbuf + BUFBIG;
469 if (str == NULL)
470 return (io_outfd = 1);
471 if ((io_outfd = creat(str, 0644)) < 0) {
472 io_outfd = 1;
473 lprintf("error creating file <%s>: %s\n", str,
474 strerror(errno));
475 lflush();
476 return (-1);
477 }
478 return (io_outfd);
479 }
480
481 /*
482 * lopen(filename) Open a file for read
483 * char *filename;
484 *
485 * lopen(0) means from the terminal
486 * Returns -1 if error, otherwise the file descriptor opened.
487 */
488 int
lopen(char * str)489 lopen(char *str)
490 {
491 ipoint = iepoint = MAXIBUF;
492 if (str == NULL)
493 return (io_infd = 0);
494 if ((io_infd = open(str, O_RDONLY)) < 0) {
495 lwclose();
496 io_outfd = 1;
497 lpnt = lpbuf;
498 return (-1);
499 }
500 return (io_infd);
501 }
502
503 /*
504 * lappend(filename) Open for append to an existing file
505 * char *filename;
506 *
507 * lappend(0) means to the terminal
508 * Returns -1 if error, otherwise the file descriptor opened.
509 */
510 int
lappend(char * str)511 lappend(char *str)
512 {
513 lpnt = lpbuf;
514 lpend = lpbuf + BUFBIG;
515 if (str == NULL)
516 return (io_outfd = 1);
517 if ((io_outfd = open(str, 2)) < 0) {
518 io_outfd = 1;
519 return (-1);
520 }
521 lseek(io_outfd, 0, SEEK_END); /* seek to end of file */
522 return (io_outfd);
523 }
524
525 /*
526 * lrclose() close the input file
527 *
528 * Returns nothing of value.
529 */
530 void
lrclose(void)531 lrclose(void)
532 {
533 if (io_infd > 0) {
534 close(io_infd);
535 io_infd = 0;
536 }
537 }
538
539 /*
540 * lwclose() close output file flushing if needed
541 *
542 * Returns nothing of value.
543 */
544 void
lwclose(void)545 lwclose(void)
546 {
547 lflush();
548 if (io_outfd > 2) {
549 close(io_outfd);
550 io_outfd = 1;
551 }
552 }
553
554 /*
555 * lprcat(string) append a string to the output buffer
556 * avoids calls to lprintf (time consuming)
557 */
558 void
lprcat(const char * str)559 lprcat(const char *str)
560 {
561 u_char *str2;
562 if (lpnt >= lpend)
563 lflush();
564 str2 = lpnt;
565 while ((*str2++ = *str++) != '\0')
566 continue;
567 lpnt = str2 - 1;
568 }
569
570 #ifdef VT100
571 /*
572 * cursor(x,y) Subroutine to set the cursor position
573 *
574 * x and y are the cursor coordinates, and lpbuff is the output buffer where
575 * escape sequence will be placed.
576 */
577 static char *y_num[] = {
578 "\33[", "\33[", "\33[2", "\33[3", "\33[4", "\33[5", "\33[6",
579 "\33[7", "\33[8", "\33[9", "\33[10", "\33[11", "\33[12", "\33[13", "\33[14",
580 "\33[15", "\33[16", "\33[17", "\33[18", "\33[19", "\33[20", "\33[21", "\33[22",
581 "\33[23", "\33[24"};
582
583 static char *x_num[] = {
584 "H", "H", ";2H", ";3H", ";4H", ";5H", ";6H", ";7H", ";8H", ";9H",
585 ";10H", ";11H", ";12H", ";13H", ";14H", ";15H", ";16H", ";17H", ";18H", ";19H",
586 ";20H", ";21H", ";22H", ";23H", ";24H", ";25H", ";26H", ";27H", ";28H", ";29H",
587 ";30H", ";31H", ";32H", ";33H", ";34H", ";35H", ";36H", ";37H", ";38H", ";39H",
588 ";40H", ";41H", ";42H", ";43H", ";44H", ";45H", ";46H", ";47H", ";48H", ";49H",
589 ";50H", ";51H", ";52H", ";53H", ";54H", ";55H", ";56H", ";57H", ";58H", ";59H",
590 ";60H", ";61H", ";62H", ";63H", ";64H", ";65H", ";66H", ";67H", ";68H", ";69H",
591 ";70H", ";71H", ";72H", ";73H", ";74H", ";75H", ";76H", ";77H", ";78H", ";79H",
592 ";80H"};
593
594 void
cursor(x,y)595 cursor(x, y)
596 int x, y;
597 {
598 char *p;
599 if (lpnt >= lpend)
600 lflush();
601
602 p = y_num[y]; /* get the string to print */
603 while (*p)
604 *lpnt++ = *p++; /* print the string */
605
606 p = x_num[x]; /* get the string to print */
607 while (*p)
608 *lpnt++ = *p++; /* print the string */
609 }
610 #else /* VT100 */
611 /*
612 * cursor(x,y) Put cursor at specified coordinates staring at [1,1] (termcap)
613 */
614 void
cursor(int x,int y)615 cursor(int x, int y)
616 {
617 if (lpnt >= lpend)
618 lflush();
619
620 *lpnt++ = CURSOR;
621 *lpnt++ = x;
622 *lpnt++ = y;
623 }
624 #endif /* VT100 */
625
626 /*
627 * Routine to position cursor at beginning of 24th line
628 */
629 void
cursors(void)630 cursors(void)
631 {
632 cursor(1, 24);
633 }
634
635 #ifndef VT100
636 /*
637 * Warning: ringing the bell is control code 7. Don't use in defines.
638 * Don't change the order of these defines.
639 * Also used in helpfiles. Codes used in helpfiles should be \E[1 to \E[7 with
640 * obvious meanings.
641 */
642
643 static char *outbuf = 0; /* translated output buffer */
644 /*
645 * init_term() Terminal initialization -- setup termcap info
646 */
647 void
init_term(void)648 init_term(void)
649 {
650 setupterm(NULL, 0, NULL); /* will exit if invalid term */
651 if (!cursor_address) {
652 fprintf(stderr, "term does not have cursor_address.\n");
653 exit(1);
654 }
655 if (!clr_eol) {
656 fprintf(stderr, "term does not have clr_eol.\n");
657 exit(1);
658 }
659 if (!clear_screen) {
660 fprintf(stderr, "term does not have clear_screen.\n");
661 exit(1);
662 }
663 if ((outbuf = malloc(BUFBIG + 16)) == 0) { /* get memory for
664 * decoded output buffer */
665 fprintf(stderr, "Error malloc'ing memory for decoded output buffer\n");
666 died(-285); /* malloc() failure */
667 }
668
669 }
670 #endif /* VT100 */
671
672 /*
673 * cl_line(x,y) Clear the whole line indicated by 'y' and leave cursor at [x,y]
674 */
675 void
cl_line(int x,int y)676 cl_line(int x, int y)
677 {
678 #ifdef VT100
679 cursor(x, y);
680 lprcat("\33[2K");
681 #else /* VT100 */
682 cursor(1, y);
683 *lpnt++ = CL_LINE;
684 cursor(x, y);
685 #endif /* VT100 */
686 }
687
688 /*
689 * cl_up(x,y) Clear screen from [x,1] to current position. Leave cursor at [x,y]
690 */
691 void
cl_up(int x,int y)692 cl_up(int x, int y)
693 {
694 #ifdef VT100
695 cursor(x, y);
696 lprcat("\33[1J\33[2K");
697 #else /* VT100 */
698 int i;
699 cursor(1, 1);
700 for (i = 1; i <= y; i++) {
701 *lpnt++ = CL_LINE;
702 *lpnt++ = '\n';
703 }
704 cursor(x, y);
705 #endif /* VT100 */
706 }
707
708 /*
709 * cl_dn(x,y) Clear screen from [1,y] to end of display. Leave cursor at [x,y]
710 */
711 void
cl_dn(int x,int y)712 cl_dn(int x, int y)
713 {
714 #ifdef VT100
715 cursor(x, y);
716 lprcat("\33[J\33[2K");
717 #else /* VT100 */
718 int i;
719 cursor(1, y);
720 if (!clr_eos) {
721 *lpnt++ = CL_LINE;
722 for (i = y; i <= 24; i++) {
723 *lpnt++ = CL_LINE;
724 if (i != 24)
725 *lpnt++ = '\n';
726 }
727 cursor(x, y);
728 } else
729 *lpnt++ = CL_DOWN;
730 cursor(x, y);
731 #endif /* VT100 */
732 }
733
734 /*
735 * standout(str) Print the argument string in inverse video (standout mode).
736 */
737 void
standout(const char * str)738 standout(const char *str)
739 {
740 #ifdef VT100
741 setbold();
742 while (*str)
743 *lpnt++ = *str++;
744 resetbold();
745 #else /* VT100 */
746 *lpnt++ = ST_START;
747 while (*str)
748 *lpnt++ = *str++;
749 *lpnt++ = ST_END;
750 #endif /* VT100 */
751 }
752
753 /*
754 * set_score_output() Called when output should be literally printed.
755 */
756 void
set_score_output(void)757 set_score_output(void)
758 {
759 enable_scroll = -1;
760 }
761
762 /*
763 * lflush() Flush the output buffer
764 *
765 * Returns nothing of value.
766 * for termcap version: Flush output in output buffer according to output
767 * status as indicated by `enable_scroll'
768 */
769 #ifndef VT100
770 static int scrline = 18; /* line # for wraparound instead of scrolling
771 * if no DL */
772 void
lflush(void)773 lflush(void)
774 {
775 int lpoint;
776 u_char *str;
777 static int curx = 0;
778 static int cury = 0;
779
780 if ((lpoint = lpnt - lpbuf) > 0) {
781 #ifdef EXTRA
782 c[BYTESOUT] += lpoint;
783 #endif
784 if (enable_scroll <= -1) {
785 flush_buf();
786 if (write(io_outfd, lpbuf, lpoint) != lpoint)
787 write(2, "error writing to output file\n", 29);
788 lpnt = lpbuf; /* point back to beginning of buffer */
789 return;
790 }
791 for (str = lpbuf; str < lpnt; str++) {
792 if (*str >= 32) {
793 ttputch(*str);
794 curx++;
795 } else
796 switch (*str) {
797 case CLEAR:
798 tputs(clear_screen, 0, ttputch);
799 curx = cury = 0;
800 break;
801
802 case CL_LINE:
803 tputs(clr_eol, 0, ttputch);
804 break;
805
806 case CL_DOWN:
807 tputs(clr_eos, 0, ttputch);
808 break;
809
810 case ST_START:
811 tputs(enter_standout_mode, 0, ttputch);
812 break;
813
814 case ST_END:
815 tputs(exit_standout_mode, 0, ttputch);
816 break;
817
818 case CURSOR:
819 curx = *++str - 1;
820 cury = *++str - 1;
821 tputs(tiparm(cursor_address,
822 cury, curx), 0, ttputch);
823 break;
824
825 case '\n':
826 if ((cury == 23) && enable_scroll) {
827 if (!delete_line ||
828 !insert_line)
829 { /* wraparound or scroll? */
830 if (++scrline > 23)
831 scrline = 19;
832
833 if (++scrline > 23)
834 scrline = 19;
835 tputs(tiparm(
836 cursor_address,
837 scrline, 0),
838 0, ttputch);
839 tputs(clr_eol, 0,
840 ttputch);
841
842 if (--scrline < 19)
843 scrline = 23;
844 tputs(tiparm(
845 cursor_address,
846 scrline, 0),
847 0, ttputch);
848 tputs(clr_eol, 0,
849 ttputch);
850 } else {
851 tputs(tiparm(
852 cursor_address,
853 19, 0),
854 0, ttputch);
855 tputs(delete_line, 0,
856 ttputch);
857 tputs(tiparm(
858 cursor_address,
859 23, 0),
860 0, ttputch);
861 /*
862 * tputs (AL, 0,
863 * ttputch);
864 */
865 }
866 } else {
867 ttputch('\n');
868 cury++;
869 }
870 curx = 0;
871 break;
872
873 default:
874 ttputch(*str);
875 curx++;
876 };
877 }
878 }
879 lpnt = lpbuf;
880 flush_buf(); /* flush real output buffer now */
881 }
882 #else /* VT100 */
883 /*
884 * lflush() flush the output buffer
885 *
886 * Returns nothing of value.
887 */
888 void
lflush()889 lflush()
890 {
891 int lpoint;
892 if ((lpoint = lpnt - lpbuf) > 0) {
893 #ifdef EXTRA
894 c[BYTESOUT] += lpoint;
895 #endif
896 if (write(io_outfd, lpbuf, lpoint) != lpoint)
897 write(2, "error writing to output file\n", 29);
898 }
899 lpnt = lpbuf; /* point back to beginning of buffer */
900 }
901 #endif /* VT100 */
902
903 #ifndef VT100
904 static int vindex = 0;
905 /*
906 * ttputch(ch) Print one character in decoded output buffer.
907 */
908 static int
ttputch(int ch)909 ttputch(int ch)
910 {
911 outbuf[vindex++] = ch;
912 if (vindex >= BUFBIG)
913 flush_buf();
914 return (0);
915 }
916
917 /*
918 * flush_buf() Flush buffer with decoded output.
919 */
920 static void
flush_buf(void)921 flush_buf(void)
922 {
923 if (vindex)
924 write(io_outfd, outbuf, vindex);
925 vindex = 0;
926 }
927
928 /*
929 * char *tmcapcnv(sd,ss) Routine to convert VT100 escapes to termcap
930 * format
931 * Processes only the \33[#m sequence (converts . files for termcap use
932 */
933 char *
tmcapcnv(char * sd,char * ss)934 tmcapcnv(char *sd, char *ss)
935 {
936 int tmstate = 0; /* 0=normal, 1=\33 2=[ 3=# */
937 char tmdigit = 0; /* the # in \33[#m */
938 while (*ss) {
939 switch (tmstate) {
940 case 0:
941 if (*ss == '\33') {
942 tmstate++;
943 break;
944 }
945 ign: *sd++ = *ss;
946 ign2: tmstate = 0;
947 break;
948 case 1:
949 if (*ss != '[')
950 goto ign;
951 tmstate++;
952 break;
953 case 2:
954 if (isdigit((u_char)*ss)) {
955 tmdigit = *ss - '0';
956 tmstate++;
957 break;
958 }
959 if (*ss == 'm') {
960 *sd++ = ST_END;
961 goto ign2;
962 }
963 goto ign;
964 case 3:
965 if (*ss == 'm') {
966 if (tmdigit)
967 *sd++ = ST_START;
968 else
969 *sd++ = ST_END;
970 goto ign2;
971 }
972 default:
973 goto ign;
974 };
975 ss++;
976 }
977 *sd = 0; /* NULL terminator */
978 return (sd);
979 }
980 #endif /* VT100 */
981
982 /*
983 * beep() Routine to emit a beep if enabled (see no-beep in .larnopts)
984 */
985 void
beep(void)986 beep(void)
987 {
988 if (!nobeep)
989 *lpnt++ = '\7';
990 }
991