1 /* unixio.c */
2
3 #include "ztypes.h"
4
5 #if !defined(BSD) || !defined(SYSTEM_FIVE) || !defined(POSIX)
6 #define BSD
7 #endif /* !defined(BSD) || !defined(SYSTEM_FIVE) || !defined(POSIX) */
8
9 #if defined(BSD)
10 #include <sgtty.h>
11 #endif /* defined(BSD) */
12 #if defined(SYSTEM_FIVE)
13 #include <termio.h>
14 #endif /* defined(SYSTEM_FIVE)
15 #if defined(POSIX)
16 #include <termios.h>
17 #endif /* defined(POSIX) */
18
19 #include <signal.h>
20 #include <sys/types.h>
21 #include <sys/time.h>
22
23 static int screen_inited = 0;
24
25 static int current_row = 1;
26 static int current_col = 1;
27
28 static int saved_row;
29 static int saved_col;
30
31 static int cursor_saved = OFF;
32
33 static char tcbuf[1024];
34 static char cmbuf[1024];
35 static char *cmbufp;
36
37 static char *CE, *CL, *CM, *CS, *DL, *MD, *ME, *MR, *SE, *SO, *TE, *TI, *UE, *US;
38
39 #define GET_TC_STR(p1, p2) if ((p1 = tgetstr (p2, &cmbufp)) == NULL) p1 = ""
40
41 #define BELL 7
42
43 static void outc ();
44 static void display_string ();
45 static int wait_for_char ();
46 static int read_key ();
47 static void set_cbreak_mode ();
48 static void rundown ();
49
50 extern int tgetent ();
51 extern int tgetnum ();
52 extern char *tgetstr ();
53 extern char *tgoto ();
54 extern void tputs ();
55
outc(c)56 static void outc (c)
57 int c;
58 {
59
60 putchar (c);
61
62 }/* outc */
63
initialize_screen()64 void initialize_screen ()
65 {
66 char *term;
67 struct winsize winsz;
68 int row, col;
69
70 if ((term = getenv ("TERM")) == NULL)
71 fatal ("No TERM environment variable");
72
73 if (tgetent (tcbuf, term) <= 0)
74 fatal ("No termcap entry for this terminal");
75
76 cmbufp = cmbuf;
77
78 GET_TC_STR (CE, "ce");
79 GET_TC_STR (CL, "cl");
80 GET_TC_STR (CM, "cm");
81 GET_TC_STR (CS, "cs");
82 GET_TC_STR (DL, "dl");
83 GET_TC_STR (MD, "md");
84 GET_TC_STR (ME, "me");
85 GET_TC_STR (MR, "mr");
86 GET_TC_STR (SE, "se");
87 GET_TC_STR (SO, "so");
88 GET_TC_STR (TE, "te");
89 GET_TC_STR (TI, "ti");
90 GET_TC_STR (UE, "ue");
91 GET_TC_STR (US, "us");
92
93 if (ioctl(fileno(stdin), TIOCGWINSZ, &winsz) < 0) {
94 /* old seventies way of getting the screen size */
95 if (screen_cols == 0 && (screen_cols = tgetnum ("co")) == -1)
96 screen_cols = DEFAULT_COLS;
97
98 if (screen_rows == 0 && (screen_rows = tgetnum ("li")) == -1)
99 screen_rows = DEFAULT_ROWS;
100 }
101 else {
102 /* sparkly new way -- ap1i */
103 screen_cols = winsz.ws_col;
104 if (screen_cols <= 0)
105 screen_cols = DEFAULT_COLS;
106 screen_rows = winsz.ws_row;
107 if (screen_rows <= 0)
108 screen_rows = DEFAULT_ROWS;
109 }
110
111 if (*MD == '\0' || *ME == '\0' || *MR == '\0') {
112 MD = SO;
113 ME = SE;
114 MR = SO;
115 }
116
117 if (*UE == '\0' || *US == '\0') {
118 UE = SE;
119 US = SO;
120 }
121
122 screen_inited = 1;
123 tputs (TI, 1, outc);
124
125 clear_screen ();
126
127 row = screen_rows / 2;
128 col = (screen_cols - (sizeof ("The story is loading...") - 1)) / 2;
129 move_cursor (row, col);
130 display_string ("The story is loading...");
131
132 h_interpreter = INTERP_MSDOS;
133
134 set_cbreak_mode (1);
135
136 }/* initialize_screen */
137
restart_screen()138 void restart_screen ()
139 {
140
141 cursor_saved = OFF;
142
143 if (h_type < V4)
144 set_byte (H_CONFIG, (get_byte (H_CONFIG) | CONFIG_WINDOWS));
145 else
146 set_byte (H_CONFIG, (get_byte (H_CONFIG) | CONFIG_EMPHASIS | CONFIG_WINDOWS));
147
148 /* Force graphics off as we can't do them */
149
150 set_word (H_FLAGS, (get_word (H_FLAGS) & (~GRAPHICS_FLAG)));
151
152 }/* restart_screen */
153
reset_screen()154 void reset_screen ()
155 {
156 if (!screen_inited)
157 return;
158
159 delete_status_window ();
160 select_text_window ();
161 set_attribute (NORMAL);
162
163 set_cbreak_mode (0);
164
165 tputs (TE, 1, outc);
166 screen_inited = 0;
167
168 }/* reset_screen */
169
clear_screen()170 void clear_screen ()
171 {
172
173 tputs (CL, 1, outc);
174 current_row = 1;
175 current_col = 1;
176
177 }/* clear_screen */
178
select_status_window()179 void select_status_window ()
180 {
181
182 save_cursor_position ();
183
184 }/* select_status_window */
185
select_text_window()186 void select_text_window ()
187 {
188
189 restore_cursor_position ();
190
191 }/* select_text_window */
192
create_status_window()193 void create_status_window ()
194 {
195 int row, col;
196
197 if (*CS) {
198 get_cursor_position (&row, &col);
199
200 tputs (tgoto (CS, screen_rows - 1, status_size), 1, outc);
201
202 move_cursor (row, col);
203 }
204
205 }/* create_status_window */
206
delete_status_window()207 void delete_status_window ()
208 {
209 int row, col;
210
211 if (*CS) {
212 get_cursor_position (&row, &col);
213
214 tputs (tgoto (CS, screen_rows - 1, 0), 1, outc);
215
216 move_cursor (row, col);
217 }
218
219 }/* delete_status_window */
220
clear_line()221 void clear_line ()
222 {
223
224 tputs (CE, 1, outc);
225
226 }/* clear_line */
227
clear_text_window()228 void clear_text_window ()
229 {
230 int i, row, col;
231
232 get_cursor_position (&row, &col);
233
234 for (i = status_size + 1; i <= screen_rows; i++) {
235 move_cursor (i, 1);
236 clear_line ();
237 }
238
239 move_cursor (row, col);
240
241 }/* clear_text_window */
242
clear_status_window()243 void clear_status_window ()
244 {
245 int i, row, col;
246
247 get_cursor_position (&row, &col);
248
249 for (i = status_size; i; i--) {
250 move_cursor (i, 1);
251 clear_line ();
252 }
253
254 move_cursor (row, col);
255
256 }/* clear_status_window */
257
move_cursor(row,col)258 void move_cursor (row, col)
259 int row;
260 int col;
261 {
262
263 tputs (tgoto (CM, col - 1, row - 1), 1, outc);
264 current_row = row;
265 current_col = col;
266
267 }/* move_cursor */
268
get_cursor_position(row,col)269 void get_cursor_position (row, col)
270 int *row;
271 int *col;
272 {
273
274 *row = current_row;
275 *col = current_col;
276
277 }/* get_cursor_position */
278
save_cursor_position()279 void save_cursor_position ()
280 {
281
282 if (cursor_saved == OFF) {
283 get_cursor_position (&saved_row, &saved_col);
284 cursor_saved = ON;
285 }
286
287 }/* save_cursor_position */
288
restore_cursor_position()289 void restore_cursor_position ()
290 {
291
292 if (cursor_saved == ON) {
293 move_cursor (saved_row, saved_col);
294 cursor_saved = OFF;
295 }
296
297 }/* restore_cursor_position */
298
set_attribute(attribute)299 void set_attribute (attribute)
300 int attribute;
301 {
302
303 if (attribute == NORMAL) {
304 tputs (ME, 1, outc);
305 tputs (UE, 1, outc);
306 }
307
308 if (attribute & REVERSE)
309 tputs (MR, 1, outc);
310
311 if (attribute & BOLD)
312 tputs (MD, 1, outc);
313
314 if (attribute & EMPHASIS)
315 tputs (US, 1, outc);
316
317 if (attribute & FIXED_FONT)
318 ;
319
320 }/* set_attribute */
321
display_string(s)322 static void display_string (s)
323 char *s;
324 {
325
326 while (*s)
327 display_char (*s++);
328
329 }/* display_string */
330
display_char(c)331 void display_char (c)
332 int c;
333 {
334
335 outc (c);
336
337 if (++current_col > screen_cols)
338 current_col = screen_cols;
339
340 }/* display_char */
341
scroll_line()342 void scroll_line ()
343 {
344 int row, col;
345
346 get_cursor_position (&row, &col);
347
348 if (*CS || row < screen_rows) {
349 display_char ('\n');
350 } else {
351 move_cursor (status_size + 1, 1);
352 tputs (DL, 1, outc);
353 move_cursor (row, 1);
354 }
355
356 current_col = 1;
357 if (++current_row > screen_rows)
358 current_row = screen_rows;
359
360 }/* scroll_line */
361
input_character(timeout)362 int input_character (timeout)
363 int timeout;
364 {
365 struct timeval tv;
366 struct timezone tz;
367
368 gettimeofday (&tv, &tz);
369
370 tv.tv_sec += timeout;
371
372 fflush (stdout);
373
374 if (timeout && wait_for_char (&tv))
375 return (-1);
376
377 return (read_key ());
378
379 }/* input_character */
380
input_line(buflen,buffer,timeout,read_size)381 int input_line (buflen, buffer, timeout, read_size)
382 int buflen;
383 char *buffer;
384 int timeout;
385 int *read_size;
386 {
387 struct timeval tv;
388 struct timezone tz;
389 int c, row, col;
390
391 gettimeofday (&tv, &tz);
392
393 tv.tv_sec += timeout;
394
395 for ( ; ; ) {
396
397 /* Read a single keystroke */
398
399 fflush (stdout);
400
401 if (timeout && wait_for_char (&tv))
402 return (-1);
403 c = read_key ();
404
405 if (c == '\b') {
406
407 /* Delete key action */
408
409 if (*read_size == 0) {
410
411 /* Ring bell if line is empty */
412
413 outc (BELL);
414
415 } else {
416
417 /* Decrement read count */
418
419 (*read_size)--;
420
421 /* Erase last character typed */
422
423 get_cursor_position (&row, &col);
424 move_cursor (row, --col);
425 display_char (' ');
426 move_cursor (row, col);
427 }
428
429 } else {
430
431 /* Normal key action */
432
433 if (*read_size == (buflen - 1)) {
434
435 /* Ring bell if buffer is full */
436
437 outc (BELL);
438
439 } else {
440
441 /* Scroll line if return key pressed */
442
443 if (c == '\n') {
444 scroll_line ();
445 return (c);
446 } else {
447
448 /* Put key in buffer and display it */
449
450 buffer[(*read_size)++] = (char) c;
451 display_char (c);
452 }
453 }
454 }
455 }
456
457 }/* input_line */
458
wait_for_char(timeout)459 static int wait_for_char (timeout)
460 struct timeval *timeout;
461 {
462 int nfds, status;
463 fd_set readfds;
464 struct timeval tv;
465 struct timezone tz;
466
467 gettimeofday (&tv, &tz);
468
469 if (tv.tv_sec >= timeout->tv_sec && tv.tv_usec >= timeout->tv_usec)
470 return (-1);
471
472 tv.tv_sec = timeout->tv_sec - tv.tv_sec;
473 if (timeout->tv_usec < tv.tv_usec) {
474 tv.tv_sec--;
475 tv.tv_usec = (timeout->tv_usec + 1000000) - tv.tv_usec;
476 } else
477 tv.tv_usec = timeout->tv_usec - tv.tv_usec;
478
479 nfds = getdtablesize ();
480 FD_ZERO (&readfds);
481 FD_SET (fileno (stdin), &readfds);
482
483 status = select (nfds, &readfds, NULL, NULL, &tv);
484 if (status < 0) {
485 perror ("select");
486 return (-1);
487 }
488
489 if (status == 0)
490 return (-1);
491 else
492 return (0);
493
494 }/* wait_for_char */
495
read_key()496 static int read_key ()
497 {
498 int c;
499
500 c = getchar ();
501
502 if (c == 127)
503 c = '\b';
504 else if (c == '\r')
505 c = '\n';
506
507 return (c);
508
509 }/* read_key */
510
set_cbreak_mode(mode)511 static void set_cbreak_mode (mode)
512 int mode;
513 {
514 int status;
515 #if defined(BSD)
516 struct sgttyb new_tty;
517 static struct sgttyb old_tty;
518 #endif /* defined(BSD) */
519 #if defined(SYSTEM_FIVE)
520 struct termio new_termio;
521 static struct termio old_termio;
522 #endif /* defined(SYSTEM_FIVE) */
523 #if defined(POSIX)
524 struct termios new_termios;
525 static struct termios old_termios;
526 #endif /* defined(POSIX) */
527
528 #if defined(BSD)
529 status = ioctl (fileno (stdin), (mode) ? TIOCGETP : TIOCSETP, &old_tty);
530 #endif /* defined(BSD) */
531 #if defined(SYSTEM_FIVE)
532 status = ioctl (fileno (stdin), (mode) ? TCGETA : TCSETA, &old_termio);
533 #endif /* defined(SYSTEM_FIVE) */
534 #if defined(POSIX)
535 if (mode)
536 status = tcgetattr (fileno (stdin), &old_termios);
537 else
538 status = tcsetattr (fileno (stdin), TCSANOW, &old_termios);
539 #endif /* defined(POSIX) */
540 if (status) {
541 perror ("ioctl");
542 exit (1);
543 }
544
545 if (mode) {
546 signal (SIGINT, rundown);
547 signal (SIGTERM, rundown);
548 }
549
550 if (mode) {
551 #if defined(BSD)
552 status = ioctl (fileno (stdin), TIOCGETP, &new_tty);
553 #endif /* defined(BSD) */
554 #if defined(SYSTEM_FIVE)
555 status = ioctl (fileno (stdin), TCGETA, &new_termio);
556 #endif /* defined(SYSTEM_FIVE) */
557 #if defined(POSIX)
558 status = tcgetattr (fileno (stdin), &new_termios);
559 #endif /* defined(POSIX) */
560 if (status) {
561 perror ("ioctl");
562 exit (1);
563 }
564
565 #if defined(BSD)
566 new_tty.sg_flags |= CBREAK;
567 new_tty.sg_flags &= ~ECHO;
568 #endif /* defined(BSD) */
569 #if defined(SYSTEM_FIVE)
570 new_termio.c_lflag &= ~(ICANON | ECHO);
571 #endif /* defined(SYSTEM_FIVE) */
572 #if defined(POSIX)
573 new_termios.c_lflag &= ~(ICANON | ECHO);
574 #endif /* defined(POSIX) */
575
576 #if defined(BSD)
577 status = ioctl (fileno (stdin), TIOCSETP, &new_tty);
578 #endif /* defined(BSD) */
579 #if defined(SYSTEM_FIVE)
580 status = ioctl (fileno (stdin), TCSETA, &new_termio);
581 #endif /* defined(SYSTEM_FIVE) */
582 #if defined(POSIX)
583 status = tcsetattr (fileno (stdin), TCSANOW, &new_termios);
584 #endif /* defined(POSIX) */
585 if (status) {
586 perror ("ioctl");
587 exit (1);
588 }
589 }
590
591 if (mode == 0) {
592 signal (SIGINT, SIG_DFL);
593 signal (SIGTERM, SIG_DFL);
594 }
595
596 }/* set_cbreak_mode */
597
rundown()598 static void rundown ()
599 {
600
601 unload_cache ();
602 close_story ();
603 close_script ();
604 reset_screen ();
605
606 }/* rundown */
607