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