|
|
1.1 root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2:
3: /*
4: $Header: b3err.c,v 1.4 85/08/22 16:57:50 timo Exp $
5: */
6:
7: /* B error message handling */
8:
9: /* There are two kinds of errors:
10: 1) parsing, when the line in error is in a buffer
11: 2) execution, when the line in error is a parse-tree, and must
12: therefore be reconstructed.
13: */
14:
15: /* All error messages are collected in a file, both to save data space
16: and to ease translation to other languages. The English version
17: of the database can be recreated from the program sources by scanning
18: for the pattern "MESS(". This is a macro whose first argument is
19: the message number and whose second number is the message string;
20: this macro expands to only the message number which is passed to
21: the error routines. The error routines then dig the message from
22: the error message file, or just print the number if the file can't be
23: opened. There is also a way to pass a message that is determined
24: at runtime.
25: */
26:
27: #include "b.h"
28: #include "b0fea.h"
29: #include "b0fil.h"
30: #include "b1obj.h"
31: #include "b2syn.h"
32: #include "b3env.h"
33: #include "b3fil.h"
34: #include "b3err.h"
35: #include "b3scr.h"
36: #include "b3sig.h"
37: #include "b3sou.h"
38:
39: Visible bool still_ok, interrupted;
40:
41: Visible parsetree curline= Vnil;
42: Visible value curlino;
43: Visible context how_context, act_context;
44:
45: FILE *errfile; /* The first thing a visible routine must do is set this */
46: /* usually by calling line() */
47:
48: #define Interactive (errfile == stderr)
49:
50: /*********************************************************************/
51:
52: /* While we are reading the Messages file, we build an index.
53: probe[k] contains the first message number found in block k.
54: blocks are BUFSIZ in size. */
55:
56: #define FILESIZE 12916 /* Approximated current size of Messages file */
57: #define MAXPROBE (10 + FILESIZE/BUFSIZ) /* Allow some growth */
58:
59: Hidden short probe[MAXPROBE];
60: Hidden int nprobes= 1;
61:
62: Hidden FILE *messfp;
63: Hidden string savedmess;
64:
65: Visible int MESSMAKE(mess) string mess; {
66: savedmess= mess;
67: return -1;
68: }
69:
70: Visible string getmess(nr) int nr; {
71: int last, c; char *cp= NULL;
72: static char buf[80]; bool new; int block; long ftell();
73: char *filename;
74: if (nr == 0) return "";
75: if (nr < 0) { return savedmess; }
76: if (messfp == NULL)
77: messfp= fopen(messfile, "r");
78: if (messfp) {
79: for (block= nprobes-1; block > 0; --block) {
80: if (probe[block] <= nr)
81: break;
82: }
83: new= block == nprobes-1;
84: fseek(messfp, (long)block*BUFSIZ, 0);
85: last= 0;
86: while (last < nr) {
87: if (new) block= ftell(messfp) / BUFSIZ;
88: if (fgets(buf, sizeof buf, messfp) == NULL) break;
89: last= atoi(buf);
90: if (last <= 0)
91: continue;
92: if (new && block >= nprobes && nprobes < MAXPROBE) {
93: probe[block]= last;
94: nprobes= block+1;
95: }
96: }
97: if (last == nr) {
98: cp= index(buf, '\n');
99: if (cp != NULL) *cp = '\0'; /* strip terminating \n */
100: cp= buf;
101: cp= index(buf, '\t');
102: if (cp != NULL) return cp+1;
103: }
104: }
105: sprintf(buf, " (error %d) ", nr);
106: return buf;
107: }
108:
109: Hidden Procedure prmess(nr) int nr; {
110: errmess(getmess(nr));
111: }
112:
113: /*********************************************************************/
114:
115: Hidden Procedure putch(c) char c; {
116: putc(c, errfile);
117: }
118:
119: Hidden Procedure line() {
120: #ifdef EXT_COMMAND
121: e_done();
122: #endif
123: fflush(stdout);
124: if (cntxt == In_read) {
125: if (rd_interactive) {
126: errfile= stderr; at_nwl= Yes;
127: } else errfile= stdout;
128: } else if (interactive) errfile= stderr;
129: else errfile= stdout;
130: if (!at_nwl) putch('\n');
131: at_nwl= Yes;
132: }
133:
134: Hidden Procedure errmess(m) string m; {
135: fputs(m, errfile);
136: }
137:
138: #ifdef NOT_USED
139: Hidden Procedure core_dump() {
140: errmess("*** Core-dump for inspection purposes: ");
141: fflush(stdout);
142: dump();
143: }
144: #endif
145:
146: Hidden Procedure prname(name) value name; {
147: if (Is_text(name)) {
148: still_ok= Yes;
149: writ(name);
150: still_ok= No;
151: }
152: }
153:
154: Visible value erruname= Vnil;
155: Visible intlet errlino= 0;
156:
157: Hidden intlet pr_line(at) bool at; {
158: /*prints the line that tx is in, with an arrow pointing to the column
159: that tx is at.
160: */
161: txptr lx= fcol(); intlet ap= -1, p= 0; char c; txptr ax= tx;
162: if (!at) do ax--; while (Space(Char(ax)));
163: while (!Eol(lx) && Char(lx) != Eotc) {
164: if (lx == ax) ap= p;
165: c= *lx++;
166: if (c == '\t') {
167: do { putch(' '); } while (((++p)%4)!=0);
168: } else { putch(c); p++; }
169: }
170: putch('\n');
171: if (ap < 0) ap= p;
172: for (p= 0; p < ap+4; p++) putch(' ');
173: errmess("^\n");
174: }
175:
176: Hidden bool sh_lino(lino) intlet lino; {
177: switch (cntxt) {
178: case In_command:
179: case In_read:
180: case In_edval:
181: case In_tarval:
182: case In_prmnv: return No;
183: case In_unit: return lino != 1;
184: default: return Yes;
185: }
186: }
187:
188:
189: Hidden Procedure show_line(in_node, at, node, line_no)
190: bool in_node, at; parsetree node; int line_no;
191: {
192: if (sh_lino(line_no))
193: fprintf(errfile, " in line %d of your ", line_no);
194: else
195: errmess(" in your ");
196: switch (cntxt) {
197: case In_command: errmess("command"); break;
198: case In_read: errmess("expression to be read"); break;
199: case In_edval: errmess("edited value"); break;
200: case In_tarval: errmess("target value"); break;
201: case In_unit: errmess("unit ");
202: release(erruname);
203: if (Is_text(uname)) {
204: value name; literal type;
205: p_name_type(uname, &name, &type);
206: prname(name); release(name);
207: erruname= copy(uname);
208: errlino= line_no;
209: } else erruname= Vnil;
210: break;
211: case In_prmnv: errmess("permanent environment"); break;
212: default: errmess("???\n"); return;
213: }
214: errmess("\n");
215: if (!in_node || node != Vnil) errmess(" ");
216: if (in_node) display(errfile, node, Yes);
217: else pr_line(at);
218: }
219:
220: Hidden bool unit_file() {
221: value *aa;
222: return cntxt == In_unit && Is_text(uname) && p_exists(uname, &aa);
223: }
224:
225: Hidden Procedure show_where(in_node, at, node)
226: bool in_node, at; parsetree node; {
227:
228: int line_no= in_node ? intval(curlino) : lino;
229: if (cntxt == In_formal) { /*can only happen when in_node*/
230: context cc;
231: sv_context(&cc);
232: set_context(&how_context);
233: copy(uname);
234: show_line(Yes, Yes, curline, intval(curlino));
235: errmess("*** originating");
236: set_context(&act_context);
237: copy(uname);
238: show_line(Yes, Yes, curline, intval(curlino));
239: set_context(&cc);
240: } else
241: show_line(in_node, at, node, line_no);
242: if (!Interactive && !unit_file()) {
243: fprintf(errfile,
244: "*** (detected after reading %d input line%s of your input file ",
245: f_lino, f_lino == 1 ? "" : "s");
246: if (iname == Vnil) errmess("standard input");
247: else prname(iname);
248: errmess(")\n");
249: }
250: }
251:
252: Hidden Procedure fatal(m, in_node) int m; bool in_node; {
253: line();
254: errmess("*** Sorry, B system malfunction");
255: show_where(in_node, Yes, curline);
256: errmess("*** The problem is: ");
257: prmess(m); errmess("\n");
258: errmess("*** Please save pertinent data for inspection by B guru\n");
259: bye(-1);
260: }
261:
262: Visible Procedure syserr(m) int m; {
263: fatal(m, Yes);
264: }
265:
266: #ifdef EXT_COMMAND
267: Visible Procedure psyserr(m) int m; {
268: fatal(m, No);
269: }
270: #endif
271:
272: Visible Procedure memexh() {
273: line();
274: errmess("*** Sorry, memory exhausted");
275: /* show_where(Yes, Yes); don't know if in node or not; to fix */ errmess("\n");
276: errmess("*** Get your boss to buy a larger computer\n");
277: bye(-1);
278: }
279:
280: Hidden Procedure fix_files() {
281: if (ifile != stdin) fclose(ifile);
282: if (f_interactive(stdin) || filtered) {
283: interactive= Yes;
284: release(iname);
285: iname = Vnil;
286: ifile = stdin;
287: sv_ifile= ifile;
288: Eof= No;
289: }
290: }
291:
292: Hidden Procedure message(m1, m2, v, m3, in_node, at)
293: string m1; int m2, m3; value v; bool in_node, at; {
294: still_ok= No;
295: line();
296: errmess(m1);
297: show_where(in_node, at, curline);
298: errmess("*** The problem is: ");
299: prmess(m2);
300: if (v != Vnil) errmess(strval(v));
301: prmess(m3);
302: errmess("\n");
303: at_nwl=Yes;
304: }
305:
306: Visible Procedure pprerr(m) int m; {
307: if (still_ok)
308: message("*** There's something I don't understand", m, Vnil, 0, No, No);
309: }
310:
311: Visible Procedure pprerr2(tag, m) value tag; int m; {
312: if (still_ok)
313: message("*** There's something I don't understand", 0, tag, m, No, No);
314: }
315:
316: Visible Procedure parerr2(m, ss) int m, ss; {
317: if (still_ok)
318: message("*** There's something I don't understand", m, Vnil, ss, No, Yes);
319: }
320:
321: Visible Procedure parerr(m) int m; {
322: parerr2(m, 0);
323: }
324:
325: Visible Procedure fixerr3(m1, v, m2) value v; int m1, m2; {
326: if (still_ok)
327: message("*** There's something I can't resolve", m1, v, m2, Yes, Yes);
328: }
329:
330: Visible Procedure fixerr2(v, m) value v; int m; {
331: fixerr3(0, v, m);
332: }
333:
334: Visible Procedure fixerr(m) int m; {
335: fixerr3(0, Vnil, m);
336: }
337:
338: Visible Procedure error3(m1, v, m2) value v; int m1, m2; {
339: message("*** Can't cope with problem", m1, v, m2, Yes, No);
340: }
341:
342: Visible Procedure error2(m, v) int m; value v; {
343: error3(m, v, 0);
344: }
345:
346: Visible Procedure error(m) int m; {
347: error3(m, Vnil, 0);
348: }
349:
350: Visible Procedure checkerr() {
351: still_ok= No;
352: line();
353: errmess("*** Your check failed");
354: show_where(Yes, No, curline);
355: at_nwl= Yes;
356: }
357:
358: #ifdef SIGNAL
359:
360: Visible Procedure int_signal() {
361: interrupted= Yes; still_ok= No;
362: if (cntxt == In_prmnv) exit(-1);
363: if (!interactive) fix_files();
364: if (!interactive) bye(1);
365: line(); fflush(stdout);
366: errmess("*** interrupted\n");
367: #ifndef INTEGRATION
368: if (filtered) errmess("\177");
369: #endif
370: if (cntxt == In_read) {
371: set_context(&read_context);
372: copy(uname);
373: }
374: at_nwl= Yes;
375: }
376:
377: #endif SIGNAL
378:
379: Visible bool bugs= No, testing= No, tracing= No;
380:
381: #ifdef NOT_USED
382: Visible Procedure debug(m) string m; {
383: if (bugs) {
384: line();
385: errmess("*** Debugging ");
386: show_where(Yes, Yes, curline);
387: fprintf(errfile, "*** %s\n", m);
388: at_nwl= Yes;
389: }
390: }
391: #endif
392:
393: #ifdef EXT_COMMAND
394:
395: /* User-callable error message */
396: Visible Procedure e_error(mesg) value mesg; {
397: value v= convert(mesg, Yes, Yes);
398: message("*** Halted", 0, v, 0, Yes, No);
399: release(v);
400: }
401:
402: #endif
403:
404: Visible Procedure bye(ex) int ex; {
405: #ifdef EXT_COMMAND
406: e_done();
407: #endif
408: at_nwl= Yes;
409: putprmnv();
410: endall();
411: if (ex == 0) {
412: term_mem();
413: endmem();
414: }
415: #ifdef IBMPC
416: memstat("at end");
417: #endif IBMPC
418: exit(ex);
419: }
420:
421: Visible Procedure initerr() {
422: still_ok= Yes; interrupted= No; curline= Vnil; curlino= zero;
423: }
424:
425:
426: #define HZ 60 /* 4.2BSD: not line frequency but historical constant */
427:
428: showtime(whence)
429: string whence;
430: {
431: #ifdef TIMING
432: static long total[2];
433: long buf[4];
434: extern bool timing; /* Set in b3mai.c by -T option */
435:
436: if (!timing) return;
437: times(buf);
438: line();
439: fprintf(errfile, "*** Times %s: user %.2f sys %.2f (total %.2f %.2f)\n",
440: whence,
441: (float)(buf[0]-total[0])/HZ, (float)(buf[1]-total[1])/HZ,
442: (float)total[0]/HZ, (float)total[1]/HZ
443: );
444: total[0]= buf[0]; total[1]= buf[1];
445: #endif TIMING
446: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.