1 /* @(#)hashcmd.c	1.34 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.34 19/11/19 Copyright 1986-2019 J. Schilling";
6 #endif
7 /*
8  *	bsh - 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 #include <schily/stdio.h>
27 #include "bsh.h"
28 #include "node.h"
29 #include "str.h"
30 #include "strsubs.h"
31 #include "abbtab.h"
32 #include "abbrev.h"
33 #include "ctype.h"
34 #include <schily/stdlib.h>
35 #include <schily/fcntl.h>		/* To get F_GETFD/F_SETFD */
36 
37 extern	abidx_t	deftab;		/* Variable is defined in abbrev.c */
38 
39 extern	int	delim;
40 extern	int	ttyflg;
41 extern	int	MVERSION;
42 extern	int	mVERSION;
43 extern	char	dVERSION[];
44 extern	char	*initav0;
45 extern	char	*cmdfname;
46 extern	Tnode	*lastcmd;	/* Used by ancient #e command */
47 
48 EXPORT	void	hashcmd		__PR((FILE ** std));
49 LOCAL	void	shcmd		__PR((FILE ** std, char *name));
50 LOCAL	void	abballusage	__PR((FILE ** std));
51 LOCAL	void	abbusage	__PR((FILE ** std, int cmd));
52 LOCAL	char	*nameok		__PR((char *n));
53 
54 /*
55  * Parse and execute a hashmark command
56  */
57 EXPORT void
hashcmd(std)58 hashcmd(std)
59 	FILE	*std[];
60 {
61 	int	cmd;
62 	char	*name;
63 	char	*name2;
64 	char	*val;
65 	int	bflg = 0;
66 	int	delflg = 0;
67 	int	histflg = 0;
68 	abidx_t	tab = deftab;
69 
70 	quote();
71 	cmd = nextch();						/* First skip '#' */
72 	skipwhite();
73 	if (!ttyflg && (iswhite(cmd) || argend(nl, 0)))		/* Kommentar */
74 		cmd = ' ';
75 	else
76 		cmd = tolower(delim);
77 	if (cmd != ' ' && argend(nl, 0)) {
78 		fprintf(std[2], relmsg, MVERSION, mVERSION, dVERSION, HOST_CPU, HOST_VENDOR, HOST_OS);
79 
80 		unquote();
81 		return;
82 	} else if (cmd == 'b') {
83 		bflg = AB_BEGIN;
84 	}
85 
86 	if (cmd == '!') {
87 		nextch();
88 	} else if (cmd != ' ') {
89 		nextch();
90 		while (!argend(spaces, 0)) {
91 			delim = tolower(delim);
92 			switch (delim) {
93 
94 			case 'g':
95 				tab = GLOBAL_AB;
96 				break;
97 			case 'l':
98 				tab = LOCAL_AB;
99 				break;
100 			case 'b':
101 				if (cmd == 'p') {
102 					bflg = AB_BEGIN;
103 					break;
104 				}
105 				goto err;
106 			case 'a':
107 				if (cmd == 'p') {
108 					bflg = 0;
109 					break;
110 				}
111 				goto err;
112 			case 'd':
113 				if (cmd == 'x')
114 					delflg++;
115 				break;
116 			case 'h':
117 				if (cmd == 'l') {
118 					histflg = AB_HISTORY;
119 					break;
120 				}
121 			default:
122 			err:
123 				berror("%s", ebadmodifier);
124 				abbusage(std, cmd);
125 				eatline();
126 				return;
127 			}
128 			nextch();
129 		}
130 	}
131 	skipwhite();
132 	if (cmd != ' ')
133 		name = pstring(spaces, 0);	/* Get next word */
134 	else
135 		name = NULL;
136 	if (name != NULL && streql(name, helpname)) {
137 		free(name);
138 		abbusage(std, cmd);
139 		eatline();
140 		return;
141 	}
142 	switch (cmd) {
143 
144 	case 'a':
145 	case 'b':
146 	case 'p':
147 		if (nameok(name)) {
148 			skipwhite();
149 			val = pstring(nl, 0);
150 			if (val == NULL)
151 				val = makestr(nullstr);
152 			if (cmd == 'p')
153 				ab_push(tab, makestr(name), val, bflg);
154 			else
155 				ab_insert(tab, makestr(name), val, bflg);
156 		}
157 		else
158 			abbusage(std, cmd);
159 		break;
160 	case 'd':
161 		if (nameok(name)) {
162 			do {
163 				if (name == NULL)
164 					break;
165 				ab_delete(tab, name, AB_NOFLAG);
166 				free(name);
167 				skipwhite();
168 			} while ((name = pstring(spaces, 0)) != NULL);
169 		}
170 		else
171 			abbusage(std, cmd);
172 		break;
173 	case 'e':
174 		eatline();
175 		execute(lastcmd, 0, gstd);
176 		return;
177 	case 'l':
178 		if (name == NULL) {
179 			ab_dump(tab, std[1], histflg);
180 		} else {
181 			do {
182 				ab_list(tab, name, std[1], histflg);
183 				free(name);
184 				skipwhite();
185 			} while ((name = pstring(spaces, 0)) != NULL);
186 		}
187 		break;
188 	case 'v':
189 		if (name != NULL) {
190 			if (streql(name, on)) {
191 				vflg = TRUE;
192 			} else if (streql(name, off)) {
193 				vflg = FALSE;
194 			} else {
195 				berror(ebadopt, "v", name);
196 				abbusage(std, cmd);
197 			}
198 		}
199 		else
200 			fprintf(std[1], "Verbose %s.\n", vflg?on:off);
201 		break;
202 	case 's':
203 		deftab = tab;
204 		fprintf(std[1], "Default: %s\n",
205 				deftab == GLOBAL_AB?
206 				globalname:localname);
207 		break;
208 	case '?':
209 	case 'h':
210 		abballusage(std);
211 		break;
212 	case 'q':
213 		delim = EOF;
214 		break;
215 	case 'x':
216 		if (name == NULL) {
217 			ev_list(std[1]);
218 		} else {
219 			if (!strchr(name, '=')) {
220 				if (delflg) {
221 					ev_delete(name);
222 				} else if ((val = getcurenv(name)) != NULL) {
223 					fprintf(std[1], "%s=%s\n", name, val);
224 					break;
225 				}
226 			} else {
227 				val = pstring(nl, 0);
228 				name2 = concat(name, val, (char *)NULL);
229 				free(name);
230 				if (val)
231 					free(val);
232 				ev_insert(name2);
233 			}
234 		}
235 		break;
236 	case '!':
237 		if (ttyflg) {
238 			berror("%s", eshonly);
239 			abbusage(std, cmd);
240 			break;
241 		}
242 		if (name == NULL)
243 			break;
244 		if (streql(fbasename(name), fbasename(initav0))) {
245 			break;
246 		}
247 		if (cmdfname != NULL)	/* Can do this only on commandfiles */
248 			shcmd(std, name);
249 		break;
250 	case ' ':
251 		break;	/* Kommentar */
252 	default:
253 		berror("%s", enocmd);
254 		abballusage(std);
255 		break;
256 	}
257 	if (name)
258 		free(name);
259 	eatline();
260 }
261 
262 LOCAL void
shcmd(std,name)263 shcmd(std, name)
264 	FILE	*std[];
265 	char	*name;
266 {
267 	register int	i;
268 	register Tnode	*lst;
269 	register Tnode	*lp;
270 		Argvec	*vp;
271 
272 	lst = lp = allocnode(STRING, (Tnode *) name, (Tnode *) NULL);
273 	while ((lp->tn_right.tn_node = pword()) != NULL)
274 		lp = lp->tn_right.tn_node;
275 	vav[0] = cmdfname;
276 	for (i = 0; i < vac; i++) {
277 		lp->tn_right.tn_node = allocnode(STRING, (Tnode *) vav[i],
278 							(Tnode *) NULL);
279 		lp = lp->tn_right.tn_node;
280 	}
281 
282 #ifndef	F_SETFD
283 	/*
284 	 * If we canno set the close on exec() flag, we need
285 	 * to close the files manually.
286 	 */
287 	fclose(cmdfp);
288 	if (protfile != (FILE *)NULL)
289 		fclose(protfile);
290 #endif
291 	vp = scan(lst);
292 	start(vp, std, 0);	/* no return */
293 }
294 
295 LOCAL void
abballusage(std)296 abballusage(std)
297 	register FILE	*std[];
298 {
299 	register int	i;
300 
301 	for (i = 0; abbtab[i].a_c != '\0'; i++) {
302 		fprintf(std[2], "%s\n", abbtab[i].a_msg);
303 	}
304 }
305 
306 LOCAL void
abbusage(std,cmd)307 abbusage(std, cmd)
308 		FILE	*std[];
309 	register int	cmd;
310 {
311 	register int i;
312 
313 	for (i = 0; abbtab[i].a_c != '\0'; i++) {
314 		if (abbtab[i].a_c == cmd) {
315 			fprintf(std[2], "%s%s\n", usage, abbtab[i].a_msg);
316 			break;
317 		}
318 	}
319 	if (abbtab[i].a_c == '\0') {
320 		fprintf(std[2], "%s\n", enocmd);
321 		abballusage(std);
322 	}
323 }
324 
325 LOCAL char *
nameok(n)326 nameok(n)
327 	char	*n;
328 {
329 	if (n == NULL)
330 		berror("%s", emissabbrev);
331 	return (n);
332 }
333