listen.c revision d1154eb460efe588eaed3d439c1caaca149fa362
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 "config.h"
20#include "ss_internal.h"
21#include <stdio.h>
22#include <setjmp.h>
23#include <signal.h>
24#include <sys/param.h>
25
26typedef void sigret_t;
27
28static ss_data *current_info;
29static jmp_buf listen_jmpb;
30static sigret_t (*sig_cont)(int);
31
32static sigret_t print_prompt(int sig __SS_ATTR((unused)))
33{
34    if (current_info->redisplay)
35	    (*current_info->redisplay)();
36    else {
37	    (void) fputs(current_info->prompt, stdout);
38	    (void) fflush(stdout);
39    }
40}
41
42static sigret_t listen_int_handler(int sig __SS_ATTR((unused)))
43{
44    putc('\n', stdout);
45    signal(SIGINT, listen_int_handler);
46    longjmp(listen_jmpb, 1);
47}
48
49int ss_listen (int sci_idx)
50{
51    char *cp;
52    ss_data *info;
53    sigret_t (*sig_int)(int), (*old_sig_cont)(int);
54    char input[BUFSIZ];
55    sigset_t omask, igmask;
56    int code;
57    jmp_buf old_jmpb;
58    ss_data *old_info = current_info;
59    char *line;
60
61    current_info = info = ss_info(sci_idx);
62    sig_cont = (sigret_t (*)(int)) 0;
63    info->abort = 0;
64    sigemptyset(&igmask);
65    sigaddset(&igmask, SIGINT);
66    sigprocmask(SIG_BLOCK, &igmask, &omask);
67    memcpy(old_jmpb, listen_jmpb, sizeof(jmp_buf));
68    sig_int = signal(SIGINT, listen_int_handler);
69    setjmp(listen_jmpb);
70    sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
71
72    while(!info->abort) {
73	old_sig_cont = sig_cont;
74	sig_cont = signal(SIGCONT, print_prompt);
75	if (sig_cont == print_prompt)
76	    sig_cont = old_sig_cont;
77	if (info->readline) {
78		line = (*info->readline)(current_info->prompt);
79	} else {
80		print_prompt(0);
81		if (fgets(input, BUFSIZ, stdin) == input)
82			line = input;
83		else
84			line = NULL;
85
86		input[BUFSIZ-1] = 0;
87	}
88	if (line == NULL) {
89		code = SS_ET_EOF;
90		(void) signal(SIGCONT, sig_cont);
91		goto egress;
92	}
93
94	cp = strchr(line, '\n');
95	if (cp) {
96	    *cp = '\0';
97	    if (cp == line)
98		continue;
99	}
100	(void) signal(SIGCONT, sig_cont);
101	if (info->add_history)
102		(*info->add_history)(line);
103
104	code = ss_execute_line (sci_idx, line);
105	if (code == SS_ET_COMMAND_NOT_FOUND) {
106	    register char *c = line;
107	    while (*c == ' ' || *c == '\t')
108		c++;
109	    cp = strchr (c, ' ');
110	    if (cp)
111		*cp = '\0';
112	    cp = strchr (c, '\t');
113	    if (cp)
114		*cp = '\0';
115	    ss_error (sci_idx, 0,
116		    "Unknown request \"%s\".  Type \"?\" for a request list.",
117		       c);
118	}
119	if (info->readline)
120		free(line);
121    }
122    code = 0;
123egress:
124    (void) signal(SIGINT, sig_int);
125    memcpy(listen_jmpb, old_jmpb, sizeof(jmp_buf));
126    current_info = old_info;
127    return code;
128}
129
130void ss_abort_subsystem(int sci_idx, int code)
131{
132    ss_info(sci_idx)->abort = 1;
133    ss_info(sci_idx)->exit_status = code;
134
135}
136
137void ss_quit(int argc __SS_ATTR((unused)),
138	     const char * const *argv __SS_ATTR((unused)),
139	     int sci_idx, pointer infop __SS_ATTR((unused)))
140{
141    ss_abort_subsystem(sci_idx, 0);
142}
143
144#ifdef HAVE_DLOPEN
145#define get_request(tbl,idx)    ((tbl) -> requests + (idx))
146
147static char *cmd_generator(const char *text, int state)
148{
149	static int	len;
150	static ss_request_table **rqtbl;
151	static int	curr_rqt;
152	static char const * const * name;
153	ss_request_entry *request;
154	char		*ret;
155
156	if (state == 0) {
157		len = strlen(text);
158		rqtbl = current_info->rqt_tables;
159		if (!rqtbl || !*rqtbl)
160			return 0;
161		curr_rqt = 0;
162		name = 0;
163	}
164
165	while (1) {
166		if (!name || !*name) {
167			request = get_request(*rqtbl, curr_rqt++);
168			name = request->command_names;
169			if (!name) {
170				rqtbl++;
171				if (*rqtbl) {
172					curr_rqt = 0;
173					continue;
174				} else
175					break;
176			}
177		}
178		if (strncmp(*name, text, len) == 0) {
179			ret = malloc(strlen(*name)+1);
180			if (ret)
181				strcpy(ret, *name);
182			name++;
183			return ret;
184		}
185		name++;
186	}
187
188	return 0;
189}
190
191char **ss_rl_completion(const char *text, int start,
192			int end __SS_ATTR((unused)))
193{
194	if ((start == 0) && current_info->rl_completion_matches)
195		return (*current_info->rl_completion_matches)
196			(text, cmd_generator);
197	return 0;
198}
199#endif
200
201