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