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