|
|
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.