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