]>
git.cameronkatri.com Git - bsdgames-darwin.git/blob - larn/io.c
2 static char rcsid
[] = "$NetBSD: io.c,v 1.4 1995/04/24 12:23:57 cgd Exp $";
5 /* io.c Larn is copyrighted 1986 by Noah Morgan.
7 * Below are the functions in this file:
9 * setupvt100() Subroutine to set up terminal in correct mode for game
10 * clearvt100() Subroutine to clean up terminal when the game is over
11 * getchar() Routine to read in one character from the terminal
12 * scbr() Function to set cbreak -echo for the terminal
13 * sncbr() Function to set -cbreak echo for the terminal
14 * newgame() Subroutine to save the initial time and seed rnd()
16 * FILE OUTPUT ROUTINES
18 * lprintf(format,args . . .) printf to the output buffer
19 * lprint(integer) send binary integer to output buffer
20 * lwrite(buf,len) write a buffer to the output buffer
21 * lprcat(str) sent string to output buffer
23 * FILE OUTPUT MACROS (in header.h)
25 * lprc(character) put the character into the output buffer
29 * long lgetc() read one character from input buffer
30 * long lrint() read one integer from input buffer
31 * lrfill(address,number) put input bytes into a buffer
32 * char *lgetw() get a whitespace ended word from input
33 * char *lgetl() get a \n or EOF ended line from input
35 * FILE OPEN / CLOSE ROUTINES
37 * lcreat(filename) create a new file for write
38 * lopen(filename) open a file for read
39 * lappend(filename) open for append to an existing file
40 * lrclose() close the input file
41 * lwclose() close output file
42 * lflush() flush the output buffer
46 * cursor(x,y) position cursor at [x,y]
47 * cursors() position cursor at [1,24] (saves memory)
48 * cl_line(x,y) Clear line at [1,y] and leave cursor at [x,y]
49 * cl_up(x,y) Clear screen from [x,1] to current line.
50 * cl_dn(x,y) Clear screen from [1,y] to end of display.
51 * standout(str) Print the string in standout mode.
52 * set_score_output() Called when output should be literally printed.
53 ** putchar(ch) Print one character in decoded output buffer.
54 ** flush_buf() Flush buffer with decoded output.
55 ** init_term() Terminal initialization -- setup termcap info
56 ** char *tmcapcnv(sd,ss) Routine to convert VT100 \33's to termcap format
57 * beep() Routine to emit a beep if enabled (see no-beep in .larnopts)
59 * Note: ** entries are available only in termcap mode.
65 #ifdef SYSV /* system III or system V */
68 #define stty(_a,_b) ioctl(_a,TCSETA,_b)
69 #define gtty(_a,_b) ioctl(_a,TCGETA,_b)
70 static int rawflg
= 0;
71 static char saveeof
,saveeol
;
72 #define doraw(_a) if(!rawflg){++rawflg;saveeof=_a.c_cc[VMIN];saveeol=_a.c_cc[VTIME];}\
73 _a.c_cc[VMIN]=1;_a.c_cc[VTIME]=1;_a.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL)
74 #define unraw(_a) _a.c_cc[VMIN]=saveeof;_a.c_cc[VTIME]=saveeol;_a.c_lflag |= ICANON|ECHO|ECHOE|ECHOK|ECHONL
79 #define CBREAK RAW /* V7 has no CBREAK */
82 #define doraw(_a) (_a.sg_flags |= CBREAK,_a.sg_flags &= ~ECHO)
83 #define unraw(_a) (_a.sg_flags &= ~CBREAK,_a.sg_flags |= ECHO)
87 #ifndef NOVARARGS /* if we have varargs */
89 #else NOVARARGS /* if we don't have varargs */
90 typedef char *va_list;
91 #define va_dcl int va_alist;
92 #define va_start(plist) plist = (char *) &va_alist
94 #define va_arg(plist,mode) ((mode *)(plist += sizeof(mode)))[-1]
97 #define LINBUFSIZE 128 /* size of the lgetw() and lgetl() buffer */
98 int lfd
; /* output file numbers */
99 int fd
; /* input file numbers */
100 static struct sgttyb ttx
; /* storage for the tty modes */
101 static int ipoint
=MAXIBUF
,iepoint
=MAXIBUF
; /* input buffering pointers */
102 static char lgetwbuf
[LINBUFSIZE
]; /* get line (word) buffer */
105 * setupvt100() Subroutine to set up terminal in correct mode for game
107 * Attributes off, clear screen, set scrolling region, set tty mode
111 clear(); setscroll(); scbr(); /* system("stty cbreak -echo"); */
115 * clearvt100() Subroutine to clean up terminal when the game is over
117 * Attributes off, clear screen, unset scrolling region, restore tty mode
121 resetscroll(); clear(); sncbr(); /* system("stty -cbreak echo"); */
125 * getchar() Routine to read in one character from the terminal
133 lflush(); /* be sure output buffer is flushed */
134 read(0,&byt
,1); /* get byte from terminal */
139 * scbr() Function to set cbreak -echo for the terminal
141 * like: system("stty cbreak -echo")
145 gtty(0,&ttx
); doraw(ttx
); stty(0,&ttx
);
149 * sncbr() Function to set -cbreak echo for the terminal
151 * like: system("stty -cbreak echo")
155 gtty(0,&ttx
); unraw(ttx
); stty(0,&ttx
);
159 * newgame() Subroutine to save the initial time and seed rnd()
163 register long *p
,*pe
;
164 for (p
=c
,pe
=c
+100; p
<pe
; *p
++ =0);
165 time(&initialtime
); srand(initialtime
);
166 lcreat((char*)0); /* open buffering for output to terminal */
170 * lprintf(format,args . . .) printf to the output buffer
174 * Enter with the format string in "format", as per printf() usage
175 * and any needed arguments following it
176 * Note: lprintf() only supports %s, %c and %d, with width modifier and left
177 * or right justification.
178 * No correct checking for output buffer overflow is done, but flushes
179 * are done beforehand if needed.
180 * Returns nothing of value.
189 str
= str2
; /* to make lint happy */
197 str
= str2
; /* to make lint happy */
204 va_list ap
; /* pointer for variable argument list */
206 register char *outb
,*tmpb
;
207 register long wide
,left
,cont
,n
; /* data for lprintf */
208 char db
[12]; /* %d buffer in lprintf */
210 va_start(ap
); /* initialize the var args pointer */
211 fmt
= va_arg(ap
, char *); /* pointer to format string */
212 if (lpnt
>= lpend
) lflush();
217 if (*fmt
) *outb
++ = *fmt
++; else { lpnt
=outb
; return; }
218 wide
= 0; left
= 1; cont
=1;
222 case 'd': n
= va_arg(ap
, long);
223 if (n
<0) { n
= -n
; *outb
++ = '-'; if (wide
) --wide
; }
224 tmpb
= db
+11; *tmpb
= (char)(n
% 10 + '0');
225 while (n
>9) *(--tmpb
) = (char)((n
/= 10) % 10 + '0');
226 if (wide
==0) while (tmpb
< db
+12) *outb
++ = *tmpb
++;
230 if (left
) while (wide
-- > 0) *outb
++ = ' ';
231 while (tmpb
< db
+12) *outb
++ = *tmpb
++;
232 if (left
==0) while (wide
-- > 0) *outb
++ = ' ';
236 case 's': tmpb
= va_arg(ap
, char *);
237 if (wide
==0) { while (*outb
++ = *tmpb
++); --outb
; }
240 n
= wide
- strlen(tmpb
);
241 if (left
) while (n
-- > 0) *outb
++ = ' ';
242 while (*outb
++ = *tmpb
++); --outb
;
243 if (left
==0) while (n
-- > 0) *outb
++ = ' ';
247 case 'c': *outb
++ = va_arg(ap
, int); cont
=0; break;
258 case '9': wide
= 10*wide
+ *fmt
- '0'; break;
260 case '-': left
= 0; break;
262 default: *outb
++ = *fmt
; cont
=0; break;
271 * lprint(long-integer) send binary integer to output buffer
274 * +---------+---------+---------+---------+
276 * | order | | | order |
277 * | byte | | | byte |
278 * +---------+---------+---------+---------+
279 * 31 --- 24 23 --- 16 15 --- 8 7 --- 0
281 * The save order is low order first, to high order (4 bytes total)
282 * and is written to be system independent.
283 * No checking for output buffer overflow is done, but flushes if needed!
284 * Returns nothing of value.
289 if (lpnt
>= lpend
) lflush();
290 *lpnt
++ = 255 & x
; *lpnt
++ = 255 & (x
>>8);
291 *lpnt
++ = 255 & (x
>>16); *lpnt
++ = 255 & (x
>>24);
295 * lwrite(buf,len) write a buffer to the output buffer
299 * Enter with the address and number of bytes to write out
300 * Returns nothing of value
308 if (len
> 399) /* don't copy data if can just write it */
315 for (str
=buf
; len
>0; --len
)
324 if (lpnt
>= lpend
) lflush(); /* if buffer is full flush it */
325 num2
= lpbuf
+BUFBIG
-lpnt
; /* # bytes left in output buffer */
326 if (num2
> len
) num2
=len
;
327 str
= lpnt
; len
-= num2
;
328 while (num2
--) *str
++ = *buf
++; /* copy in the bytes */
334 * long lgetc() Read one character from input buffer
336 * Returns 0 if EOF, otherwise the character
341 if (ipoint
!= iepoint
) return(inbuffer
[ipoint
++]);
342 if (iepoint
!=MAXIBUF
) return(0);
343 if ((i
=read(fd
,inbuffer
,MAXIBUF
))<=0)
345 if (i
!=0) write(1,"error reading from input file\n",30);
346 iepoint
= ipoint
= 0; return(0);
348 ipoint
=1; iepoint
=i
; return(*inbuffer
);
352 * long lrint() Read one integer from input buffer
354 * +---------+---------+---------+---------+
356 * | order | | | order |
357 * | byte | | | byte |
358 * +---------+---------+---------+---------+
359 * 31 --- 24 23 --- 16 15 --- 8 7 --- 0
361 * The save order is low order first, to high order (4 bytes total)
362 * Returns the int read
366 register unsigned long i
;
367 i
= 255 & lgetc(); i
|= (255 & lgetc()) << 8;
368 i
|= (255 & lgetc()) << 16; i
|= (255 & lgetc()) << 24;
373 * lrfill(address,number) put input bytes into a buffer
377 * Reads "number" bytes into the buffer pointed to by "address".
378 * Returns nothing of value
388 if (iepoint
== ipoint
)
390 if (num
>5) /* fast way */
392 if (read(fd
,adr
,num
) != num
)
393 write(2,"error reading from input file\n",30);
396 else { *adr
++ = lgetc(); --num
; }
400 num2
= iepoint
-ipoint
; /* # of bytes left in the buffer */
401 if (num2
> num
) num2
=num
;
402 pnt
= inbuffer
+ipoint
; num
-= num2
; ipoint
+= num2
;
403 while (num2
--) *adr
++ = *pnt
++;
409 * char *lgetw() Get a whitespace ended word from input
411 * Returns pointer to a buffer that contains word. If EOF, returns a NULL
415 register char *lgp
,cc
;
416 register int n
=LINBUFSIZE
,quote
=0;
418 do cc
=lgetc(); while ((cc
<= 32) && (cc
> NULL
)); /* eat whitespace */
419 for ( ; ; --n
,cc
=lgetc())
421 if ((cc
==NULL
) && (lgp
==lgetwbuf
)) return(NULL
); /* EOF */
422 if ((n
<=1) || ((cc
<=32) && (quote
==0))) { *lgp
=NULL
; return(lgetwbuf
); }
423 if (cc
!= '"') *lgp
++ = cc
; else quote
^= 1;
428 * char *lgetl() Function to read in a line ended by newline or EOF
430 * Returns pointer to a buffer that contains the line. If EOF, returns NULL
434 register int i
=LINBUFSIZE
,ch
;
435 register char *str
=lgetwbuf
;
438 if ((*str
++ = ch
= lgetc()) == NULL
)
440 if (str
== lgetwbuf
+1) return(NULL
); /* EOF */
441 ot
: *str
= NULL
; return(lgetwbuf
); /* line ended by EOF */
443 if ((ch
=='\n') || (i
<=1)) goto ot
; /* line ended by \n */
448 * lcreat(filename) Create a new file for write
451 * lcreat((char*)0); means to the terminal
452 * Returns -1 if error, otherwise the file descriptor opened.
457 lpnt
= lpbuf
; lpend
= lpbuf
+BUFBIG
;
458 if (str
==NULL
) return(lfd
=1);
459 if ((lfd
=creat(str
,0644)) < 0)
461 lfd
=1; lprintf("error creating file <%s>\n",str
); lflush(); return(-1);
467 * lopen(filename) Open a file for read
470 * lopen(0) means from the terminal
471 * Returns -1 if error, otherwise the file descriptor opened.
476 ipoint
= iepoint
= MAXIBUF
;
477 if (str
==NULL
) return(fd
=0);
478 if ((fd
=open(str
,0)) < 0)
480 lwclose(); lfd
=1; lpnt
=lpbuf
; return(-1);
486 * lappend(filename) Open for append to an existing file
489 * lappend(0) means to the terminal
490 * Returns -1 if error, otherwise the file descriptor opened.
495 lpnt
= lpbuf
; lpend
= lpbuf
+BUFBIG
;
496 if (str
==NULL
) return(lfd
=1);
497 if ((lfd
=open(str
,2)) < 0)
501 lseek(lfd
,0,2); /* seek to end of file */
506 * lrclose() close the input file
508 * Returns nothing of value.
512 if (fd
> 0) close(fd
);
516 * lwclose() close output file flushing if needed
518 * Returns nothing of value.
522 lflush(); if (lfd
> 2) close(lfd
);
526 * lprcat(string) append a string to the output buffer
527 * avoids calls to lprintf (time consuming)
533 if (lpnt
>= lpend
) lflush();
535 while (*str2
++ = *str
++);
541 * cursor(x,y) Subroutine to set the cursor position
543 * x and y are the cursor coordinates, and lpbuff is the output buffer where
544 * escape sequence will be placed.
546 static char *y_num
[]= { "\33[","\33[","\33[2","\33[3","\33[4","\33[5","\33[6",
547 "\33[7","\33[8","\33[9","\33[10","\33[11","\33[12","\33[13","\33[14",
548 "\33[15","\33[16","\33[17","\33[18","\33[19","\33[20","\33[21","\33[22",
551 static char *x_num
[]= { "H","H",";2H",";3H",";4H",";5H",";6H",";7H",";8H",";9H",
552 ";10H",";11H",";12H",";13H",";14H",";15H",";16H",";17H",";18H",";19H",
553 ";20H",";21H",";22H",";23H",";24H",";25H",";26H",";27H",";28H",";29H",
554 ";30H",";31H",";32H",";33H",";34H",";35H",";36H",";37H",";38H",";39H",
555 ";40H",";41H",";42H",";43H",";44H",";45H",";46H",";47H",";48H",";49H",
556 ";50H",";51H",";52H",";53H",";54H",";55H",";56H",";57H",";58H",";59H",
557 ";60H",";61H",";62H",";63H",";64H",";65H",";66H",";67H",";68H",";69H",
558 ";70H",";71H",";72H",";73H",";74H",";75H",";76H",";77H",";78H",";79H",
565 if (lpnt
>= lpend
) lflush();
567 p
= y_num
[y
]; /* get the string to print */
568 while (*p
) *lpnt
++ = *p
++; /* print the string */
570 p
= x_num
[x
]; /* get the string to print */
571 while (*p
) *lpnt
++ = *p
++; /* print the string */
575 * cursor(x,y) Put cursor at specified coordinates staring at [1,1] (termcap)
580 if (lpnt
>= lpend
) lflush ();
582 *lpnt
++ = CURSOR
; *lpnt
++ = x
; *lpnt
++ = y
;
587 * Routine to position cursor at beginning of 24th line
596 * Warning: ringing the bell is control code 7. Don't use in defines.
597 * Don't change the order of these defines.
598 * Also used in helpfiles. Codes used in helpfiles should be \E[1 to \E[7 with
602 static char cap
[256];
603 char *CM
, *CE
, *CD
, *CL
, *SO
, *SE
, *AL
, *DL
;/* Termcap capabilities */
604 static char *outbuf
=0; /* translated output buffer */
609 * init_term() Terminal initialization -- setup termcap info
614 char *capptr
= cap
+10;
617 switch (tgetent(termbuf
, term
= getenv("TERM")))
620 write(2, "Cannot open termcap file.\n", 26); exit();
622 write(2, "Cannot find entry of ", 21);
623 write(2, term
, strlen (term
));
624 write(2, " in termcap\n", 12);
628 CM
= tgetstr("cm", &capptr
); /* Cursor motion */
629 CE
= tgetstr("ce", &capptr
); /* Clear to eoln */
630 CL
= tgetstr("cl", &capptr
); /* Clear screen */
633 AL
= tgetstr("al", &capptr
); /* Insert line */
634 DL
= tgetstr("dl", &capptr
); /* Delete line */
635 SO
= tgetstr("so", &capptr
); /* Begin standout mode */
636 SE
= tgetstr("se", &capptr
); /* End standout mode */
637 CD
= tgetstr("cd", &capptr
); /* Clear to end of display */
639 if (!CM
) /* can't find cursor motion entry */
641 write(2, "Sorry, for a ",13); write(2, term
, strlen(term
));
642 write(2, ", I can't find the cursor motion entry in termcap\n",50);
645 if (!CE
) /* can't find clear to end of line entry */
647 write(2, "Sorry, for a ",13); write(2, term
, strlen(term
));
648 write(2,", I can't find the clear to end of line entry in termcap\n",57);
651 if (!CL
) /* can't find clear entire screen entry */
653 write(2, "Sorry, for a ",13); write(2, term
, strlen(term
));
654 write(2, ", I can't find the clear entire screen entry in termcap\n",56);
657 if ((outbuf
=malloc(BUFBIG
+16))==0) /* get memory for decoded output buffer*/
659 write(2,"Error malloc'ing memory for decoded output buffer\n",50);
660 died(-285); /* malloc() failure */
666 * cl_line(x,y) Clear the whole line indicated by 'y' and leave cursor at [x,y]
672 cursor(x
,y
); lprcat("\33[2K");
674 cursor(1,y
); *lpnt
++ = CL_LINE
; cursor(x
,y
);
679 * cl_up(x,y) Clear screen from [x,1] to current position. Leave cursor at [x,y]
685 cursor(x
,y
); lprcat("\33[1J\33[2K");
689 for (i
=1; i
<=y
; i
++) { *lpnt
++ = CL_LINE
; *lpnt
++ = '\n'; }
695 * cl_dn(x,y) Clear screen from [1,y] to end of display. Leave cursor at [x,y]
701 cursor(x
,y
); lprcat("\33[J\33[2K");
708 for (i
=y
; i
<=24; i
++) { *lpnt
++ = CL_LINE
; if (i
!=24) *lpnt
++ = '\n'; }
718 * standout(str) Print the argument string in inverse video (standout mode).
737 * set_score_output() Called when output should be literally printed.
745 * lflush() Flush the output buffer
747 * Returns nothing of value.
748 * for termcap version: Flush output in output buffer according to output
749 * status as indicated by `enable_scroll'
752 static int scrline
=18; /* line # for wraparound instead of scrolling if no DL */
760 if ((lpoint
= lpnt
- lpbuf
) > 0)
763 c
[BYTESOUT
] += lpoint
;
765 if (enable_scroll
<= -1)
768 if (write(lfd
,lpbuf
,lpoint
) != lpoint
)
769 write(2,"error writing to output file\n",29);
770 lpnt
= lpbuf
; /* point back to beginning of buffer */
773 for (str
= lpbuf
; str
< lpnt
; str
++)
775 if (*str
>=32) { putchar (*str
); curx
++; }
778 case CLEAR
: tputs (CL
, 0, putchar
); curx
= cury
= 0;
781 case CL_LINE
: tputs (CE
, 0, putchar
);
784 case CL_DOWN
: tputs (CD
, 0, putchar
);
787 case ST_START
: tputs (SO
, 0, putchar
);
790 case ST_END
: tputs (SE
, 0, putchar
);
793 case CURSOR
: curx
= *++str
- 1; cury
= *++str
- 1;
794 tputs (tgoto (CM
, curx
, cury
), 0, putchar
);
797 case '\n': if ((cury
== 23) && enable_scroll
)
799 if (!DL
|| !AL
) /* wraparound or scroll? */
801 if (++scrline
> 23) scrline
=19;
803 if (++scrline
> 23) scrline
=19;
804 tputs (tgoto (CM
, 0, scrline
), 0, putchar
);
805 tputs (CE
, 0, putchar
);
807 if (--scrline
< 19) scrline
=23;
808 tputs (tgoto (CM
, 0, scrline
), 0, putchar
);
809 tputs (CE
, 0, putchar
);
813 tputs (tgoto (CM
, 0, 19), 0, putchar
);
814 tputs (DL
, 0, putchar
);
815 tputs (tgoto (CM
, 0, 23), 0, putchar
);
816 /* tputs (AL, 0, putchar); */
821 putchar ('\n'); cury
++;
826 default: putchar (*str
); curx
++;
831 flush_buf(); /* flush real output buffer now */
835 * lflush() flush the output buffer
837 * Returns nothing of value.
842 if ((lpoint
= lpnt
- lpbuf
) > 0)
845 c
[BYTESOUT
] += lpoint
;
847 if (write(lfd
,lpbuf
,lpoint
) != lpoint
)
848 write(2,"error writing to output file\n",29);
850 lpnt
= lpbuf
; /* point back to beginning of buffer */
857 * putchar(ch) Print one character in decoded output buffer.
862 outbuf
[vindex
++] = c
;
863 if (vindex
>= BUFBIG
) flush_buf();
867 * flush_buf() Flush buffer with decoded output.
871 if (vindex
) write(lfd
, outbuf
, vindex
);
876 * char *tmcapcnv(sd,ss) Routine to convert VT100 escapes to termcap format
878 * Processes only the \33[#m sequence (converts . files for termcap use
880 char *tmcapcnv(sd
,ss
)
881 register char *sd
,*ss
;
883 register int tmstate
=0; /* 0=normal, 1=\33 2=[ 3=# */
884 char tmdigit
=0; /* the # in \33[#m */
889 case 0: if (*ss
=='\33') { tmstate
++; break; }
893 case 1: if (*ss
!='[') goto ign
;
896 case 2: if (isdigit(*ss
)) { tmdigit
= *ss
-'0'; tmstate
++; break; }
897 if (*ss
== 'm') { *sd
++ = ST_END
; goto ign2
; }
899 case 3: if (*ss
== 'm')
901 if (tmdigit
) *sd
++ = ST_START
;
909 *sd
=0; /* NULL terminator */
915 * beep() Routine to emit a beep if enabled (see no-beep in .larnopts)
919 if (!nobeep
) *lpnt
++ = '\7';