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