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