listen.c revision efc6f628e15de95bcd13e4f0ee223cb42115d520
1/*
2 * Listener loop for subsystem library libss.a.
3 *
4 *	$Header$
5 *	$Locker$
6 *
7 * Copyright 1987, 1988 by MIT Student Information Processing Board
8 *
9 * Permission to use, copy, modify, and distribute this software and
10 * its documentation for any purpose is hereby granted, provided that
11 * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
12 * advertising or publicity pertaining to distribution of the software
13 * without specific, written prior permission.  M.I.T. and the
14 * M.I.T. S.I.P.B. make no representations about the suitability of
15 * this software for any purpose.  It is provided "as is" without
16 * express or implied warranty.
17 */
18
19#include "ss_internal.h"
20#include <stdio.h>
21#include <setjmp.h>
22#include <signal.h>
23#include <sys/param.h>
24
25typedef void sigret_t;
26
27static ss_data *current_info;
28static jmp_buf listen_jmpb;
29static sigret_t (*sig_cont)(int);
30
31static sigret_t print_prompt(int sig __SS_ATTR((unused)))
32{
33    if (current_info->redisplay)
34	    (*current_info->redisplay)();
35    else {
36	    (void) fputs(current_info->prompt, stdout);
37	    (void) fflush(stdout);
38    }
39}
40
41static sigret_t listen_int_handler(int sig __SS_ATTR((unused)))
42{
43    putc('\n', stdout);
44    signal(SIGINT, listen_int_handler);
45    longjmp(listen_jmpb, 1);
46}
47
48int ss_listen (int sci_idx)
49{
50    char *cp;
51    ss_data *info;
52    sigret_t (*sig_int)(int), (*old_sig_cont)(int);
53    char input[BUFSIZ];
54    sigset_t omask, igmask;
55    int code;
56    jmp_buf old_jmpb;
57    ss_data *old_info = current_info;
58    char *line;
59
60    current_info = info = ss_info(sci_idx);
61    sig_cont = (sigret_t (*)(int)) 0;
62    info->abort = 0;
63    sigemptyset(&igmask);
64    sigaddset(&igmask, SIGINT);
65    sigprocmask(SIG_BLOCK, &igmask, &omask);
66    memcpy(old_jmpb, listen_jmpb, sizeof(jmp_buf));
67    sig_int = signal(SIGINT, listen_int_handler);
68    setjmp(listen_jmpb);
69    sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
70
71    while(!info->abort) {
72	old_sig_cont = sig_cont;
73	sig_cont = signal(SIGCONT, print_prompt);
74	if (sig_cont == print_prompt)
75	    sig_cont = old_sig_cont;
76	if (info->readline) {
77		line = (*info->readline)(current_info->prompt);
78	} else {
79		print_prompt(0);
80		if (fgets(input, BUFSIZ, stdin) == input)
81			line = input;
82		else
83			line = NULL;
84
85		input[BUFSIZ-1] = 0;
86	}
87	if (line == NULL) {
88		code = SS_ET_EOF;
89		(void) signal(SIGCONT, sig_cont);
90		goto egress;
91	}
92
93	cp = strchr(line, '\n');
94	if (cp) {
95	    *cp = '\0';
96	    if (cp == line)
97		continue;
98	}
99	(void) signal(SIGCONT, sig_cont);
100	if (info->add_history)
101		(*info->add_history)(line);
102
103	code = ss_execute_line (sci_idx, line);
104	if (code == SS_ET_COMMAND_NOT_FOUND) {
105	    register char *c = line;
106	    while (*c == ' ' || *c == '\t')
107		c++;
108	    cp = strchr (c, ' ');
109	    if (cp)
110		*cp = '\0';
111	    cp = strchr (c, '\t');
112	    if (cp)
113		*cp = '\0';
114	    ss_error (sci_idx, 0,
115		    "Unknown request \"%s\".  Type \"?\" for a request list.",
116		       c);
117	}
118	if (info->readline)
119		free(line);
120    }
121    code = 0;
122egress:
123    (void) signal(SIGINT, sig_int);
124    memcpy(listen_jmpb, old_jmpb, sizeof(jmp_buf));
125    current_info = old_info;
126    return code;
127}
128
129void ss_abort_subsystem(int sci_idx, int code)
130{
131    ss_info(sci_idx)->abort = 1;
132    ss_info(sci_idx)->exit_status = code;
133
134}
135
136void ss_quit(int argc __SS_ATTR((unused)),
137	     const char * const *argv __SS_ATTR((unused)),
138	     int sci_idx, pointer infop __SS_ATTR((unused)))
139{
140    ss_abort_subsystem(sci_idx, 0);
141}
142
143#ifdef HAVE_DLOPEN
144#define get_request(tbl,idx)    ((tbl) -> requests + (idx))
145
146static char *cmd_generator(const char *text, int state)
147{
148	static int	len;
149	static ss_request_table **rqtbl;
150	static int	curr_rqt;
151	static char const * const * name;
152	ss_request_entry *request;
153	char		*ret;
154
155	if (state == 0) {
156		len = strlen(text);
157		rqtbl = current_info->rqt_tables;
158		if (!rqtbl || !*rqtbl)
159			return 0;
160		curr_rqt = 0;
161		name = 0;
162	}
163
164	while (1) {
165		if (!name || !*name) {
166			request = get_request(*rqtbl, curr_rqt++);
167			name = request->command_names;
168			if (!name) {
169				rqtbl++;
170				if (*rqtbl) {
171					curr_rqt = 0;
172					continue;
173				} else
174					break;
175			}
176		}
177		if (strncmp(*name, text, len) == 0) {
178			ret = malloc(strlen(*name)+1);
179			if (ret)
180				strcpy(ret, *name);
181			name++;
182			return ret;
183		}
184		name++;
185	}
186
187	return 0;
188}
189
190char **ss_rl_completion(const char *text, int start,
191			int end __SS_ATTR((unused)))
192{
193	if ((start == 0) && current_info->rl_completion_matches)
194		return (*current_info->rl_completion_matches)
195			(text, cmd_generator);
196	return 0;
197}
198#endif
199
200