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