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: }