1 /* @(#)hashcmd.c	1.9 19/11/19 Copyright 1986-2019 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)hashcmd.c	1.9 19/11/19 Copyright 1986-2019 J. Schilling";
6 #endif
7 /*
8  *	Commands dealing with #<letter> commands
9  *
10  *	Copyright (c) 1986-2019 J. Schilling
11  */
12 /*
13  * The contents of this file are subject to the terms of the
14  * Common Development and Distribution License, Version 1.0 only
15  * (the "License").  You may not use this file except in compliance
16  * with the License.
17  *
18  * See the file CDDL.Schily.txt in this distribution for details.
19  * A copy of the CDDL is also available via the Internet at
20  * http://www.opensource.org/licenses/cddl1.txt
21  *
22  * When distributing Covered Code, include this CDDL HEADER in each
23  * file and include the License file CDDL.Schily.txt from this distribution.
24  */
25 
26 #ifdef	DO_HASHCMDS
27 
28 #include "defs.h"
29 #include "hashtab.h"
30 #include "abbrev.h"
31 
32 #undef	tolower
33 #define	tolower(c)	(((c) >= 'A' && (c) <= 'Z') ? (c) + ('a'-'A') : (c))
34 
35 extern	abidx_t	deftab;		/* Variable is defined in abbrev.c */
36 
37 LOCAL	int	delim;
38 
39 EXPORT	void	hashcmd		__PR((void));
40 LOCAL	void	abballusage	__PR((void));
41 LOCAL	void	abbusage	__PR((int cmdc));
42 LOCAL	int	nextch		__PR((void));
43 LOCAL	int	skipwhite	__PR((void));
44 LOCAL	void	eatline		__PR((void));
45 LOCAL	char	*pstring	__PR((int spc));
46 LOCAL	char	*nameok		__PR((char *n));
47 LOCAL	void	herror		__PR((char *s));
48 
49 /*
50  * Parse and execute a hashmark command
51  */
52 EXPORT void
hashcmd()53 hashcmd()
54 {
55 	int	cmdc;
56 	char	*name;
57 	char	*val;
58 	int	bflg = 0;
59 	int	histflg = 0;
60 	abidx_t	tab = deftab;
61 
62 	cmdc = nextch();				/* First skip '#' */
63 	skipwhite();
64 	if (!isatty(standin->fdes) && (space(cmdc) || eolchar(delim)))
65 		cmdc = ' ';				/* # in script: ign. */
66 	else
67 		cmdc = tolower(delim);
68 	if (cmdc != ' ' && eolchar(delim)) {
69 		prversion();
70 		return;
71 	} else if (cmdc == 'b') {
72 		bflg = AB_BEGIN;
73 	}
74 
75 	if (cmdc == '!') {
76 		nextch();
77 	} else if (cmdc != ' ') {
78 		nextch();
79 		while (!(space(delim) || eolchar(delim))) {
80 			delim = tolower(delim);
81 			switch (delim) {
82 
83 			case 'g':
84 				tab = GLOBAL_AB;
85 				break;
86 			case 'l':
87 				tab = LOCAL_AB;
88 				break;
89 			case 'b':
90 				if (cmdc == 'p') {
91 					bflg = AB_BEGIN;
92 					break;
93 				}
94 				goto err;
95 			case 'a':
96 				if (cmdc == 'p') {
97 					bflg = 0;
98 					break;
99 				}
100 				goto err;
101 			case 'h':
102 				if (cmdc == 'l') {
103 					histflg = AB_HISTORY;
104 					break;
105 				}
106 			default:
107 			err:
108 				herror("Bad modifier");
109 				abbusage(cmdc);
110 				eatline();
111 				return;
112 			}
113 			nextch();
114 		}
115 	}
116 	skipwhite();
117 	if (cmdc != ' ')
118 		name = pstring(TRUE);	/* Get next word */
119 	else
120 		name = NULL;
121 	if (name != NULL && eq(name, "-help")) {
122 		free(name);
123 		abbusage(cmdc);
124 		eatline();
125 		return;
126 	}
127 	switch (cmdc) {
128 
129 	case 'a':
130 	case 'b':
131 	case 'p':
132 		if (nameok(name)) {
133 			skipwhite();
134 			val = pstring(FALSE);
135 			if (val == NULL)
136 				val = (char *)make(UC nullstr);
137 			if (cmdc == 'p')
138 				ab_push(tab, C make(UC name), val, bflg);
139 			else
140 				ab_insert(tab, C make(UC name), val, bflg);
141 		} else {
142 			abbusage(cmdc);
143 		}
144 		break;
145 	case 'd':
146 		if (nameok(name)) {
147 			do {
148 				if (name == NULL)
149 					break;
150 				ab_delete(tab, name, AB_NOFLAG);
151 				free(name);
152 				skipwhite();
153 			} while ((name = pstring(TRUE)) != NULL);
154 		} else {
155 			abbusage(cmdc);
156 		}
157 		break;
158 	case 'l':
159 		if (name == NULL) {
160 			ab_dump(tab, STDOUT_FILENO, histflg);
161 		} else {
162 			do {
163 				ab_list(tab, name, STDOUT_FILENO, histflg);
164 				free(name);
165 				skipwhite();
166 			} while ((name = pstring(TRUE)) != NULL);
167 		}
168 		flushb();
169 		break;
170 	case 's':
171 		deftab = tab;
172 		prs_buff(_gettext("Default: "));
173 		prs_buff(UC(deftab == GLOBAL_AB?globalname:localname));
174 		prc_buff(NL);
175 		flushb();
176 		break;
177 	case '?':
178 	case 'h':
179 		abballusage();
180 		break;
181 	case '!':	/* This shell always ignores #! */
182 	case ' ':
183 		break;	/* Kommentar */
184 		/*
185 		 * We do not implement all commands from the original concept
186 		 * in the UNOS command interpreter. The original did support
187 		 * the following additional commands:
188 		 *
189 		 * #!	Manage other interpreters in scripts at user level.
190 		 * #e	re-execute the parsed tree from the last command.
191 		 * #q	quit the shell.
192 		 * #v	switch on/off command verbosity similar to "set -x".
193 		 * #x	manage the environemt variables.
194 		 *
195 		 * So keep in mind that the command characters from the list
196 		 * above should not be used for future extensions.
197 		 */
198 	default:
199 		herror("Unknown command");
200 		abballusage();
201 		break;
202 	}
203 	if (name)
204 		free(name);
205 	eatline();
206 }
207 
208 LOCAL void
abballusage()209 abballusage()
210 {
211 	register int	i;
212 	int	save_fd = setb(STDERR_FILENO);
213 
214 	for (i = 0; abbtab[i].a_c != '\0'; i++) {
215 		prs_buff(UC abbtab[i].a_msg);
216 		prc_buff(NL);
217 	}
218 	flushb();
219 	(void) setb(save_fd);
220 }
221 
222 LOCAL void
abbusage(cmdc)223 abbusage(cmdc)
224 	register int	cmdc;
225 {
226 	register int i;
227 
228 	for (i = 0; abbtab[i].a_c != '\0'; i++) {
229 		if (abbtab[i].a_c == cmdc) {
230 			int	save_fd = setb(STDERR_FILENO);
231 
232 			prs_buff(_gettext("Usage: "));
233 			prs_buff(_gettext(abbtab[i].a_msg));
234 			prc_buff(NL);
235 			flushb();
236 			(void) setb(save_fd);
237 			break;
238 		}
239 	}
240 	if (abbtab[i].a_c == '\0') {
241 		int	save_fd = setb(STDERR_FILENO);
242 
243 		prs_buff(_gettext("Unknown command."));
244 		prc_buff(NL);
245 		flushb();
246 		(void) setb(save_fd);
247 		abballusage();
248 	}
249 }
250 
251 LOCAL int
nextch()252 nextch()
253 {
254 	return (delim = readwc());
255 }
256 
257 LOCAL int
skipwhite()258 skipwhite()
259 {
260 	while (delim && space(delim))
261 		nextch();
262 	return (delim);
263 }
264 
265 LOCAL void
eatline()266 eatline()
267 {
268 	while (!eolchar(delim))
269 		nextch();
270 }
271 
272 LOCAL char *
pstring(spc)273 pstring(spc)
274 	int	spc;
275 {
276 	char	buf[1024];
277 	char	*p = buf;
278 
279 	if (eolchar(delim))
280 		return (NULL);
281 
282 	while (!eolchar(delim)) {
283 		if (spc && space(delim))
284 			break;
285 		if (p >= &buf[sizeof (buf) - MULTI_BYTE_MAX - 1]) {
286 			herror("Argument too long");
287 			eatline();
288 			return (NULL);
289 		}
290 		p = (char *)movstr(readw(delim), UC p);
291 		nextch();
292 	}
293 	*p = '\0';
294 	return ((char *)make(UC buf));
295 }
296 
297 LOCAL char *
nameok(n)298 nameok(n)
299 	char	*n;
300 {
301 	if (n == NULL)
302 		herror("Missing alias name");
303 	return (n);
304 }
305 
306 LOCAL void
herror(s)307 herror(s)
308 	char	*s;
309 {
310 	int	save_fd = setb(STDERR_FILENO);
311 
312 	prs_buff(_gettext(s));
313 	prc_buff('.');
314 	prc_buff(NL);
315 	flushb();
316 	(void) setb(save_fd);
317 }
318 #endif	/* DO_HASHCMDS */
319