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

Defined functions

edit defined in line 61; used 1 times
editindentation defined in line 126; used 1 times
editqueue defined in line 362; used 3 times
readnode defined in line 298; used 2 times
readsym defined in line 265; used 1 times
readtext defined in line 195; used 1 times
skipsp defined in line 177; used 5 times

Defined variables

rcsid defined in line 2; never used
spacesused defined in line 48; used 3 times
tabsused defined in line 49; used 3 times

Defined macros

INDENT defined in line 46; used 2 times
  • in line 148(2)
TABSIZE defined in line 43; used 2 times
  • in line 142(2)
Last modified: 1985-08-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3307
Valid CSS Valid XHTML 1.0 Strict