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