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