1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* util/ss/listen.c */
3 /*
4  * Copyright 1987, 1988 by MIT Student Information Processing Board
5  *
6  * For copyright information, see copyright.h.
7  */
8 
9 #include "copyright.h"
10 #include "ss_internal.h"
11 #include <stdio.h>
12 #include <setjmp.h>
13 #include <signal.h>
14 #include <termios.h>
15 #include <sys/param.h>
16 
17 #if defined(HAVE_LIBEDIT)
18 #include <editline/readline.h>
19 #elif defined(HAVE_READLINE)
20 #include <readline/readline.h>
21 #include <readline/history.h>
22 #else
23 #define NO_READLINE
24 #endif
25 
26 static ss_data *current_info;
27 static jmp_buf listen_jmpb;
28 
29 #ifdef NO_READLINE
30 /* Dumb replacement for readline when we don't have support for a real one. */
readline(const char * prompt)31 static char *readline(const char *prompt)
32 {
33     struct termios termbuf;
34     char input[BUFSIZ];
35 
36     /* Make sure we don't buffer anything beyond the line read. */
37     setvbuf(stdin, 0, _IONBF, 0);
38 
39     if (tcgetattr(STDIN_FILENO, &termbuf) == 0) {
40         termbuf.c_lflag |= ICANON|ISIG|ECHO;
41         tcsetattr(STDIN_FILENO, TCSANOW, &termbuf);
42     }
43     printf("%s", prompt);
44     fflush(stdout);
45     if (fgets(input, BUFSIZ, stdin) == NULL)
46         return NULL;
47     input[strcspn(input, "\r\n")] = '\0';
48     return strdup(input);
49 }
50 
51 /* No-op replacement for add_history() when we have no readline support. */
add_history(const char * line)52 static void add_history(const char *line)
53 {
54 }
55 #endif
56 
listen_int_handler(signo)57 static RETSIGTYPE listen_int_handler(signo)
58     int signo;
59 {
60     putc('\n', stdout);
61     longjmp(listen_jmpb, 1);
62 }
63 
ss_listen(sci_idx)64 int ss_listen (sci_idx)
65     int sci_idx;
66 {
67     char *cp;
68     ss_data *info;
69     char *input;
70     int code;
71     jmp_buf old_jmpb;
72     ss_data *old_info = current_info;
73 #ifdef POSIX_SIGNALS
74     struct sigaction isig, csig, nsig, osig;
75     sigset_t nmask, omask;
76 #else
77     RETSIGTYPE (*sig_cont)();
78     RETSIGTYPE (*sig_int)(), (*old_sig_cont)();
79     int mask;
80 #endif
81 
82     current_info = info = ss_info(sci_idx);
83     info->abort = 0;
84 
85 #ifdef POSIX_SIGNALS
86     csig.sa_handler = (RETSIGTYPE (*)())0;
87     sigemptyset(&nmask);
88     sigaddset(&nmask, SIGINT);
89     sigprocmask(SIG_BLOCK, &nmask, &omask);
90 #else
91     sig_cont = (RETSIGTYPE (*)())0;
92     mask = sigblock(sigmask(SIGINT));
93 #endif
94 
95     memcpy(old_jmpb, listen_jmpb, sizeof(jmp_buf));
96 
97 #ifdef POSIX_SIGNALS
98     nsig.sa_handler = listen_int_handler;
99     sigemptyset(&nsig.sa_mask);
100     nsig.sa_flags = 0;
101     sigaction(SIGINT, &nsig, &isig);
102 #else
103     sig_int = signal(SIGINT, listen_int_handler);
104 #endif
105 
106     setjmp(listen_jmpb);
107 
108 #ifdef POSIX_SIGNALS
109     sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0);
110 #else
111     (void) sigsetmask(mask);
112 #endif
113     while(!info->abort) {
114 #ifdef POSIX_SIGNALS
115         nsig.sa_handler = listen_int_handler;   /* fgets is not signal-safe */
116         osig = csig;
117         sigaction(SIGCONT, &nsig, &csig);
118         if ((RETSIGTYPE (*)())csig.sa_handler==(RETSIGTYPE (*)())listen_int_handler)
119             csig = osig;
120 #else
121         old_sig_cont = sig_cont;
122         sig_cont = signal(SIGCONT, listen_int_handler);
123         if (sig_cont == listen_int_handler)
124             sig_cont = old_sig_cont;
125 #endif
126 
127         input = readline(current_info->prompt);
128         if (input == NULL) {
129             code = SS_ET_EOF;
130             goto egress;
131         }
132         add_history(input);
133 
134 #ifdef POSIX_SIGNALS
135         sigaction(SIGCONT, &csig, (struct sigaction *)0);
136 #else
137         (void) signal(SIGCONT, sig_cont);
138 #endif
139 
140         code = ss_execute_line (sci_idx, input);
141         if (code == SS_ET_COMMAND_NOT_FOUND) {
142             char *c = input;
143             while (*c == ' ' || *c == '\t')
144                 c++;
145             cp = strchr (c, ' ');
146             if (cp)
147                 *cp = '\0';
148             cp = strchr (c, '\t');
149             if (cp)
150                 *cp = '\0';
151             ss_error (sci_idx, 0,
152                       "Unknown request \"%s\".  Type \"?\" for a request list.",
153                       c);
154         }
155         free(input);
156     }
157     code = 0;
158 egress:
159 #ifdef POSIX_SIGNALS
160     sigaction(SIGINT, &isig, (struct sigaction *)0);
161 #else
162     (void) signal(SIGINT, sig_int);
163 #endif
164     memcpy(listen_jmpb, old_jmpb, sizeof(jmp_buf));
165     current_info = old_info;
166     return code;
167 }
168 
ss_abort_subsystem(sci_idx,code)169 void ss_abort_subsystem(sci_idx, code)
170     int sci_idx;
171     int code;
172 {
173     ss_info(sci_idx)->abort = 1;
174     ss_info(sci_idx)->exit_status = code;
175 
176 }
177 
ss_quit(argc,argv,sci_idx,infop)178 void ss_quit(argc, argv, sci_idx, infop)
179     int argc;
180     char const * const *argv;
181     int sci_idx;
182     pointer infop;
183 {
184     ss_abort_subsystem(sci_idx, 0);
185 }
186