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