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

Defined functions

checkerr defined in line 350; used 1 times
core_dump defined in line 139; never used
debug defined in line 382; never used
e_error defined in line 396; never used
errmess defined in line 134; used 31 times
error defined in line 346; used 151 times
fatal defined in line 252; used 2 times
fix_files defined in line 280; used 1 times
fixerr2 defined in line 330; used 11 times
fixerr3 defined in line 325; used 8 times
getmess defined in line 70; used 1 times
initerr defined in line 421; used 1 times
int_signal defined in line 360; used 1 times
line defined in line 119; used 7 times
memexh defined in line 272; used 2 times
message defined in line 292; used 6 times
parerr2 defined in line 316; used 6 times
pprerr2 defined in line 311; used 7 times
pr_line defined in line 157; used 1 times
prmess defined in line 109; used 3 times
prname defined in line 146; used 2 times
psyserr defined in line 267; used 1 times
putch defined in line 115; used 5 times
sh_lino defined in line 176; used 1 times
show_line defined in line 189; used 3 times
show_where defined in line 225; used 4 times
showtime defined in line 428; used 5 times
syserr defined in line 262; used 101 times
unit_file defined in line 220; used 1 times

Defined variables

Hidden defined in line 225; never used
Procedure defined in line 225; never used
curline defined in line 41; used 7 times
curlino defined in line 42; used 4 times
errlino defined in line 155; used 1 times
erruname defined in line 154; used 3 times
interrupted defined in line 39; used 2 times
nprobes defined in line 60; used 5 times
probe defined in line 59; used 2 times
savedmess defined in line 63; used 2 times
still_ok defined in line 39; used 10 times

Defined macros

FILESIZE defined in line 56; used 1 times
  • in line 57
HZ defined in line 426; used 4 times
Interactive defined in line 48; used 1 times
MAXPROBE defined in line 57; used 2 times
Last modified: 1985-08-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2583
Valid CSS Valid XHTML 1.0 Strict