xref: /netbsd/bin/csh/err.c (revision de40008d)
1 /* $NetBSD: err.c,v 1.25 2022/04/08 10:17:52 andvar Exp $ */
2 
3 /*-
4  * Copyright (c) 1980, 1991, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)err.c	8.1 (Berkeley) 5/31/93";
36 #else
37 __RCSID("$NetBSD: err.c,v 1.25 2022/04/08 10:17:52 andvar Exp $");
38 #endif
39 #endif /* not lint */
40 
41 #include <sys/types.h>
42 
43 #include <stdarg.h>
44 #include <stdlib.h>
45 #include <unistd.h>
46 
47 #include "csh.h"
48 #include "extern.h"
49 
50 char *seterr = NULL;	/* Holds last error if there was one */
51 
52 #define ERR_FLAGS	((int)0xf0000000)
53 #define ERR_NAME	0x10000000
54 #define ERR_SILENT	0x20000000
55 #define ERR_OLD		0x40000000
56 
57 static const char *errorlist[] =
58 {
59 #define ERR_SYNTAX	0
60     "Syntax Error",
61 #define ERR_NOTALLOWED	1
62     "%s is not allowed",
63 #define ERR_WTOOLONG	2
64     "Word too long",
65 #define ERR_LTOOLONG	3
66     "$< line too long",
67 #define ERR_DOLZERO	4
68     "No file for $0",
69 #define ERR_DOLQUEST	5
70     "$? not allowed here",
71 #define ERR_INCBR	6
72     "Incomplete [] modifier",
73 #define ERR_EXPORD	7
74     "$ expansion must end before ]",
75 #define ERR_BADMOD	8
76     "Bad : modifier in $ (%c)",
77 #define ERR_SUBSCRIPT	9
78     "Subscript error",
79 #define ERR_BADNUM	10
80     "Badly formed number",
81 #define ERR_NOMORE	11
82     "No more words",
83 #define ERR_FILENAME	12
84     "Missing file name",
85 #define ERR_GLOB	13
86     "Internal glob error",
87 #define ERR_COMMAND	14
88     "Command not found",
89 #define ERR_TOOFEW	15
90     "Too few arguments",
91 #define ERR_TOOMANY	16
92     "Too many arguments",
93 #define ERR_DANGER	17
94     "Too dangerous to alias that",
95 #define ERR_EMPTYIF	18
96     "Empty if",
97 #define ERR_IMPRTHEN	19
98     "Improper then",
99 #define ERR_NOPAREN	20
100     "Words not parenthesized",
101 #define ERR_NOTFOUND	21
102     "%s not found",
103 #define ERR_MASK	22
104     "Improper mask",
105 #define ERR_LIMIT	23
106     "No such limit",
107 #define ERR_TOOLARGE	24
108     "Argument too large",
109 #define ERR_SCALEF	25
110     "Improper or unknown scale factor",
111 #define ERR_UNDVAR	26
112     "Undefined variable",
113 #define ERR_DEEP	27
114     "Directory stack not that deep",
115 #define ERR_BADSIG	28
116     "Bad signal number",
117 #define ERR_UNKSIG	29
118     "Unknown signal; kill -l lists signals",
119 #define ERR_VARBEGIN	30
120     "Variable name must begin with a letter",
121 #define ERR_VARTOOLONG	31
122     "Variable name too long",
123 #define ERR_VARALNUM	32
124     "Variable name must contain alphanumeric characters",
125 #define ERR_JOBCONTROL	33
126     "No job control in this shell",
127 #define ERR_EXPRESSION	34
128     "Expression Syntax",
129 #define ERR_NOHOMEDIR	35
130     "No home directory",
131 #define ERR_CANTCHANGE	36
132     "Can't change to home directory",
133 #define ERR_NULLCOM	37
134     "Invalid null command",
135 #define ERR_ASSIGN	38
136     "Assignment missing expression",
137 #define ERR_UNKNOWNOP	39
138     "Unknown operator",
139 #define ERR_AMBIG	40
140     "Ambiguous",
141 #define ERR_EXISTS	41
142     "%s: File exists",
143 #define ERR_INTR	42
144     "Interrupted",
145 #define ERR_RANGE	43
146     "Subscript out of range",
147 #define ERR_OVERFLOW	44
148     "Line overflow",
149 #define ERR_VARMOD	45
150     "Unknown variable modifier",
151 #define ERR_NOSUCHJOB	46
152     "No such job",
153 #define ERR_TERMINAL	47
154     "Can't from terminal",
155 #define ERR_NOTWHILE	48
156     "Not in while/foreach",
157 #define ERR_NOPROC	49
158     "No more processes",
159 #define ERR_NOMATCH	50
160     "No match",
161 #define ERR_MISSING	51
162     "Missing %c",
163 #define ERR_UNMATCHED	52
164     "Unmatched %c",
165 #define ERR_NOMEM	53
166     "Out of memory",
167 #define ERR_PIPE	54
168     "Can't make pipe",
169 #define ERR_SYSTEM	55
170     "%s: %s",
171 #define ERR_STRING	56
172     "%s",
173 #define ERR_JOBS	57
174     "usage: jobs [ -lZ ]",
175 #define ERR_JOBARGS	58
176     "Arguments should be jobs or process id's",
177 #define ERR_JOBCUR	59
178     "No current job",
179 #define ERR_JOBPREV	60
180     "No previous job",
181 #define ERR_JOBPAT	61
182     "No job matches pattern",
183 #define ERR_NESTING	62
184     "Fork nesting > %d; maybe `...` loop",
185 #define ERR_JOBCTRLSUB	63
186     "No job control in subshells",
187 #define ERR_BADPLPS	64
188     "Badly placed ()'s",
189 #define ERR_STOPPED	65
190     "%sThere are suspended jobs",
191 #define ERR_NODIR	66
192     "No other directory",
193 #define ERR_EMPTY	67
194     "Directory stack empty",
195 #define ERR_BADDIR	68
196     "Bad directory",
197 #define ERR_DIRUS	69
198     "usage: %s [-lvn]%s",
199 #define ERR_HFLAG	70
200     "No operand for -h flag",
201 #define ERR_NOTLOGIN	71
202     "Not a login shell",
203 #define ERR_DIV0	72
204     "Division by 0",
205 #define ERR_MOD0	73
206     "Mod by 0",
207 #define ERR_BADSCALE	74
208     "Bad scaling; did you mean \"%s\"?",
209 #define ERR_SUSPLOG	75
210     "Can't suspend a login shell (yet)",
211 #define ERR_UNKUSER	76
212     "Unknown user: %s",
213 #define ERR_NOHOME	77
214     "No $home variable set",
215 #define ERR_HISTUS	78
216     "usage: history [-rh] [# number of events]",
217 #define ERR_SPDOLLT	79
218     "$, ! or < not allowed with $# or $?",
219 #define ERR_NEWLINE	80
220     "Newline in variable name",
221 #define ERR_SPSTAR	81
222     "* not allowed with $# or $?",
223 #define ERR_DIGIT	82
224     "$?<digit> or $#<digit> not allowed",
225 #define ERR_VARILL	83
226     "Illegal variable name",
227 #define ERR_NLINDEX	84
228     "Newline in variable index",
229 #define ERR_EXPOVFL	85
230     "Expansion buffer overflow",
231 #define ERR_VARSYN	86
232     "Variable syntax",
233 #define ERR_BADBANG	87
234     "Bad ! form",
235 #define ERR_NOSUBST	88
236     "No previous substitute",
237 #define ERR_BADSUBST	89
238     "Bad substitute",
239 #define ERR_LHS		90
240     "No previous left hand side",
241 #define ERR_RHSLONG	91
242     "Right hand side too long",
243 #define ERR_BADBANGMOD	92
244     "Bad ! modifier: %c",
245 #define ERR_MODFAIL	93
246     "Modifier failed",
247 #define ERR_SUBOVFL	94
248     "Substitution buffer overflow",
249 #define ERR_BADBANGARG	95
250     "Bad ! arg selector",
251 #define ERR_NOSEARCH	96
252     "No prev search",
253 #define ERR_NOEVENT	97
254     "%s: Event not found",
255 #define ERR_TOOMANYRP	98
256     "Too many )'s",
257 #define ERR_TOOMANYLP	99
258     "Too many ('s",
259 #define ERR_BADPLP	100
260     "Badly placed (",
261 #define ERR_MISRED	101
262     "Missing name for redirect",
263 #define ERR_OUTRED	102
264     "Ambiguous output redirect",
265 #define ERR_REDPAR	103
266     "Can't << within ()'s",
267 #define ERR_INRED	104
268     "Ambiguous input redirect",
269 #define ERR_ALIASLOOP	105
270     "Alias loop",
271 #define ERR_HISTLOOP	106
272     "!# History loop",
273 #define ERR_ARCH        107
274     "%s: %s. Wrong Architecture",
275 #define ERR_FILEINQ	108
276     "Malformed file inquiry",
277 #define ERR_SELOVFL	109
278     "Selector overflow",
279 #define ERR_INVALID	110
280     "Invalid Error"
281 };
282 
283 /*
284  * The parser and scanner set up errors for later by calling seterr,
285  * which sets the variable err as a side effect; later to be tested,
286  * e.g. in process.
287  */
288 void
seterror(int id,...)289 seterror(int id, ...)
290 {
291     if (seterr == 0) {
292 	char berr[BUFSIZE];
293 	va_list va;
294 
295 	va_start(va, id);
296 	if (id < 0 || id >= (int)(sizeof(errorlist) / sizeof(errorlist[0])) - 1)
297 	    id = ERR_INVALID;
298 	(void)vsnprintf(berr, sizeof(berr), errorlist[id], va);
299 	va_end(va);
300 
301 	seterr = strsave(berr);
302     }
303 }
304 
305 /*
306  * Print the error with the given id.
307  *
308  * Special ids:
309  *	ERR_SILENT: Print nothing.
310  *	ERR_OLD: Print the previously set error if one was there.
311  *	         otherwise return.
312  *	ERR_NAME: If this bit is set, print the name of the function
313  *		  in bname
314  *
315  * This routine always resets or exits.  The flag haderr
316  * is set so the routine who catches the unwind can propagate
317  * it if they want.
318  *
319  * Note that any open files at the point of error will eventually
320  * be closed in the routine process in sh.c which is the only
321  * place error unwinds are ever caught.
322  */
323 void
stderror(int id,...)324 stderror(int id, ...)
325 {
326     va_list va;
327     Char **v;
328     int flags;
329 
330     flags = id & ERR_FLAGS;
331     id &= ~ERR_FLAGS;
332 
333     if ((flags & ERR_OLD) && seterr == NULL)
334 	abort();
335 
336     if (id < 0 || id > (int)(sizeof(errorlist) / sizeof(errorlist[0])))
337 	id = ERR_INVALID;
338 
339     (void)fflush(cshout);
340     (void)fflush(csherr);
341     haderr = 1;			/* Now to diagnostic output */
342     timflg = 0;			/* This isn't otherwise reset */
343 
344 
345     if (!(flags & ERR_SILENT)) {
346 	if (flags & ERR_NAME)
347 	    (void)fprintf(csherr, "%s: ", bname);
348 	if ((flags & ERR_OLD))
349 	    /* Old error. */
350 	    (void)fprintf(csherr, "%s.\n", seterr);
351 	else {
352 	    va_start(va, id);
353 	    (void)vfprintf(csherr, errorlist[id], va);
354 	    va_end(va);
355 	    (void)fprintf(csherr, ".\n");
356 	}
357     }
358 
359     if (seterr) {
360 	free(seterr);
361 	seterr = NULL;
362     }
363 
364     if ((v = pargv) != NULL)
365 	pargv = 0, blkfree(v);
366     if ((v = gargv) != NULL)
367 	gargv = 0, blkfree(v);
368 
369     (void)fflush(cshout);
370     (void)fflush(csherr);
371     didfds = 0;			/* Forget about 0,1,2 */
372     /*
373      * Go away if -e or we are a child shell
374      */
375     if (exiterr || child)
376 	xexit(1);
377 
378     /*
379      * Reset the state of the input. This buffered seek to end of file will
380      * also clear the while/foreach stack.
381      */
382     btoeof();
383 
384     set(STRstatus, Strsave(STR1));
385     if (tpgrp > 0)
386 	(void)tcsetpgrp(FSHTTY, tpgrp);
387     reset();			/* Unwind */
388 }
389