|
|
1.1 ! root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */ ! 2: static char rcsid[] = "$Header: edit.c,v 2.5 85/08/22 16:01:43 timo Exp $"; ! 3: ! 4: /* ! 5: * B editor -- Read unit from file. ! 6: */ ! 7: ! 8: #include <ctype.h> ! 9: ! 10: #include "b.h" ! 11: #include "feat.h" ! 12: #include "erro.h" ! 13: #include "bobj.h" ! 14: #include "node.h" ! 15: #include "tabl.h" ! 16: #include "gram.h" ! 17: #include "supr.h" ! 18: #include "queu.h" ! 19: ! 20: string unixerror(); ! 21: ! 22: /* ! 23: * TABSIZE sets the number of spaces equivalent to a tab character ! 24: * read from the input; INDENT sets the number of spaces for one indentation ! 25: * level. ! 26: * The definitions here are unrelated to the definition of TABS ! 27: * in eval.h (used by show.c and eval.c). The definition here only ! 28: * defines how many spaces must be equivalenced to a tab stop when read ! 29: * from a file; tab stops must be caused by editing a unit with another ! 30: * editor (vi, ed, ex, emacs), since "save.c" always writes spaces, ! 31: * not tabs. The value '4' is best suited for people at the CWI who ! 32: * may have workspaces with units edited with the previous version of ! 33: * the B editor, which emitted a tab for each indentation level (and ! 34: * assumed 4 spaces for a tab stop on input). ! 35: * ! 36: * The variables 'spacesused' and 'tabsused' are kept to see if mixed use ! 37: * of spaces and tabs was made; this can cause indentation errors. ! 38: */ ! 39: ! 40: #ifdef CWI ! 41: #define TABSIZE 4 ! 42: #else ! 43: #define TABSIZE 8 ! 44: #endif ! 45: ! 46: #define INDENT 4 ! 47: ! 48: Hidden bool spacesused; ! 49: Hidden bool tabsused; ! 50: ! 51: ! 52: /* ! 53: * Read (edit) parse tree from file into the focus. ! 54: * Rather ad hoc, we use ins_string for each line ! 55: * and do some magic tricks to get the indentation right ! 56: * (most of the time). ! 57: * If line > 0, position the focus at that line, if possible; ! 58: * otherwise the focus is left at the end of the inserted text. ! 59: */ ! 60: ! 61: Visible bool ! 62: edit(ep, filename, line) ! 63: register environ *ep; ! 64: string filename; ! 65: int line; ! 66: { ! 67: int lines = 0; ! 68: register FILE *fp = fopen(filename, "r"); ! 69: register int c; ! 70: char buf[BUFSIZ]; ! 71: auto string cp; ! 72: auto queue q = Qnil; ! 73: ! 74: if (!fp) { ! 75: error("%s", unixerror(filename)); ! 76: return No; ! 77: } ! 78: ! 79: spacesused = tabsused = No; ! 80: do { ! 81: do { ! 82: for (cp = buf; cp < buf + sizeof buf - 1; ++cp) { ! 83: c = getc(fp); ! 84: if (c == EOF || c == '\n') ! 85: break; ! 86: if (c < ' ' || c >= 0177) ! 87: c = ' '; ! 88: *cp = c; ! 89: } ! 90: if (cp > buf) { ! 91: *cp = 0; ! 92: if (!ins_string(ep, buf, &q, 0) || !emptyqueue(q)) { ! 93: qrelease(q); ! 94: error(EDIT_BAD); ! 95: fclose(fp); ! 96: return No; ! 97: } ! 98: qrelease(q); ! 99: } ! 100: } while (c != EOF && c != '\n'); ! 101: ++lines; ! 102: if (c != EOF && !editindentation(ep, fp)) { ! 103: fclose(fp); ! 104: return No; ! 105: } ! 106: } while (c != EOF); ! 107: fclose(fp); ! 108: if (ep->mode == FHOLE || ep->mode == VHOLE && (ep->s1&1)) { ! 109: cp = ""; ! 110: soften(ep, &cp, 0); ! 111: } ! 112: if (lines > 1 && line > 0) { ! 113: gotoyx(ep, line-1, 0); ! 114: oneline(ep); ! 115: } ! 116: if (spacesused && tabsused) ! 117: error(EDIT_TABS); ! 118: return Yes; ! 119: } ! 120: ! 121: ! 122: /* ! 123: * Do all the footwork required to get the indentation proper. ! 124: */ ! 125: ! 126: Hidden Procedure ! 127: editindentation(ep, fp) ! 128: register environ *ep; ! 129: register FILE *fp; ! 130: { ! 131: register int tabs = 0; ! 132: auto int level; ! 133: register int c; ! 134: ! 135: while ((c = getc(fp)) == ' ' || c == '\t') { ! 136: if (c == ' ') { ! 137: spacesused = Yes; ! 138: ++tabs; ! 139: } ! 140: else { ! 141: tabsused = Yes; ! 142: tabs = (tabs/TABSIZE + 1)*TABSIZE; ! 143: } ! 144: } ! 145: ungetc(c, fp); ! 146: if (c == EOF || c == '\n') ! 147: return Yes; ! 148: tabs = (tabs+(INDENT/2))/INDENT; /* Transform to tab stops */ ! 149: if (!ins_newline(ep)) { ! 150: #ifndef NDEBUG ! 151: debug("[Burp! Can't insert a newline.]"); ! 152: #endif NDEBUG ! 153: return No; ! 154: } ! 155: level = Level(ep->focus); ! 156: for (; tabs < level; --level) { ! 157: if (!ins_newline(ep)) { ! 158: #ifndef NDEBUG ! 159: debug("[Burp, burp! Can't decrease indentation.]"); ! 160: #endif NDEBUG ! 161: return No; ! 162: } ! 163: } ! 164: fixit(ep); ! 165: return Yes; ! 166: } ! 167: ! 168: ! 169: /* ------------------------------------------------------------ */ ! 170: ! 171: #ifdef SAVEBUF ! 172: ! 173: /* ! 174: * Read the next non-space character. ! 175: */ ! 176: ! 177: Hidden int ! 178: skipsp(fp) ! 179: register FILE *fp; ! 180: { ! 181: register int c; ! 182: ! 183: do { ! 184: c = getc(fp); ! 185: } while (c == ' '); ! 186: return c; ! 187: } ! 188: ! 189: ! 190: /* ! 191: * Read a text in standard B format when the initial quote has already ! 192: * been read. ! 193: */ ! 194: ! 195: Hidden value ! 196: readtext(fp, quote) ! 197: register FILE *fp; ! 198: register char quote; ! 199: { ! 200: auto value v = Vnil; ! 201: char buf[BUFSIZ]; ! 202: register string cp = buf; ! 203: register int c; ! 204: auto int i; ! 205: ! 206: for (; ; ++cp) { ! 207: c = getc(fp); ! 208: if (!isascii(c) || c != ' ' && !isprint(c)) { ! 209: if (c == EOF) ! 210: debug("readtext: EOF"); ! 211: else ! 212: debug("readtext: bad char (0%02o)", c); ! 213: release(v); ! 214: return Vnil; /* Bad character or EOF */ ! 215: } ! 216: if (c == quote) { ! 217: c = getc(fp); ! 218: if (c != quote) { ! 219: ungetc(c, fp); ! 220: break; ! 221: } ! 222: } ! 223: else if (c == '`') { ! 224: c = skipsp(fp); ! 225: if (c == '$') { ! 226: i = 0; ! 227: if (fscanf(fp, "%d", &i) != 1 ! 228: || i == 0 || !isascii(i)) { ! 229: debug("readtext: error in conversion"); ! 230: release(v); ! 231: return Vnil; ! 232: } ! 233: c = skipsp(fp); ! 234: } ! 235: else ! 236: i = '`'; ! 237: if (c != '`') { ! 238: if (c == EOF) ! 239: debug("readtext: EOF in conversion"); ! 240: else ! 241: debug("readtext: bad char in conversion (0%o)", c); ! 242: release(v); ! 243: return Vnil; ! 244: } ! 245: c = i; ! 246: } ! 247: if (cp >= &buf[sizeof buf - 1]) { ! 248: *cp = 0; ! 249: if (v) ! 250: concato(&v, buf); ! 251: else ! 252: v = mk_text(buf); ! 253: cp = buf; ! 254: } ! 255: *cp = c; ! 256: } ! 257: *cp = 0; ! 258: if (!v) ! 259: return mk_text(buf); ! 260: concato(&v, buf); ! 261: return v; ! 262: } ! 263: ! 264: ! 265: Hidden int ! 266: readsym(fp) ! 267: register FILE *fp; ! 268: { ! 269: register int c; ! 270: char buf[100]; ! 271: register string bufp; ! 272: ! 273: for (bufp = buf; ; ++bufp) { ! 274: c = getc(fp); ! 275: if (c == EOF) ! 276: return -1; ! 277: if (!isascii(c) || !isalnum(c) && c != '_') { ! 278: if (ungetc(c, fp) == EOF) ! 279: syserr("readsym: ungetc failed"); ! 280: break; ! 281: } ! 282: *bufp = c; ! 283: } ! 284: *bufp = 0; ! 285: if (isdigit(buf[0])) ! 286: return atoi(buf); ! 287: if (strcmp(buf, "Required") == 0) /***** Compatibility hack *****/ ! 288: return Hole; ! 289: return nametosym(buf); ! 290: } ! 291: ! 292: ! 293: /* ! 294: * Read a node in internal format (recursively). ! 295: * Return nil pointer if EOF or error. ! 296: */ ! 297: ! 298: Hidden node ! 299: readnode(fp) ! 300: FILE *fp; ! 301: { ! 302: int c; ! 303: int nch; ! 304: node ch[MAXCHILD]; ! 305: node n; ! 306: int sym; ! 307: ! 308: c = skipsp(fp); ! 309: switch (c) { ! 310: case EOF: ! 311: return Nnil; /* EOF hit */ ! 312: ! 313: case '(': ! 314: sym = readsym(fp); ! 315: if (sym < 0) { ! 316: debug("readnode: missing symbol"); ! 317: return Nnil; /* No number as first item */ ! 318: } ! 319: if (sym < 0 || sym > Hole) { ! 320: debug("readnode: bad symbol (%d)", sym); ! 321: return Nnil; ! 322: } ! 323: nch = 0; ! 324: while ((c = skipsp(fp)) == ',' && nch < MAXCHILD) { ! 325: n = readnode(fp); ! 326: if (!n) { ! 327: for (; nch > 0; --nch) ! 328: noderelease(ch[nch-1]); ! 329: return Nnil; /* Error encountered in child */ ! 330: } ! 331: ch[nch] = n; ! 332: ++nch; ! 333: } ! 334: if (c != ')') { ! 335: if (c == ',') ! 336: debug("readnode: node too long (sym=%d)", sym); ! 337: else ! 338: debug("readnode: no ')' where expected (sym=%d)", sym); ! 339: for (; nch > 0; --nch) ! 340: noderelease(ch[nch-1]); ! 341: return Nnil; /* Not terminated with ')' or too many children */ ! 342: } ! 343: if (nch == 0) ! 344: return gram(sym); /* Saves space for Optional/Hole nodes */ ! 345: return newnode(nch, sym, ch); ! 346: ! 347: case '\'': ! 348: case '"': ! 349: return (node) readtext(fp, c); ! 350: ! 351: default: ! 352: debug("readnode: bad initial character"); ! 353: return Nnil; /* Bad initial character */ ! 354: } ! 355: } ! 356: ! 357: ! 358: /* ! 359: * Read a node written in a more or less internal format. ! 360: */ ! 361: ! 362: Visible value ! 363: editqueue(filename) ! 364: string filename; ! 365: { ! 366: register FILE *fp = fopen(filename, "r"); ! 367: auto queue q = Qnil; ! 368: register node n; ! 369: ! 370: if (!fp) ! 371: return Vnil; ! 372: do { ! 373: n = readnode(fp); ! 374: if (!n) ! 375: break; /* EOF or error */ ! 376: addtoqueue(&q, n); ! 377: noderelease(n); ! 378: } while (skipsp(fp) == '\n'); ! 379: fclose(fp); ! 380: return (value)q; ! 381: } ! 382: #endif SAVEBUF
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.