|
|
1.1 root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
2: /* $Header: b2sou.c,v 1.1 84/06/28 00:49:20 timo Exp $ */
3:
4: /* Sources: maintaining units and values on external files */
5: #include "b.h"
6: #include "b0con.h"
7: #include "b1mem.h" /* shouldn't really */
8: #include "b1obj.h"
9: #include "b2env.h"
10: #include "b2scr.h"
11: #include "b2err.h"
12: #include "b2key.h"
13: #include "b2syn.h"
14: #include "b2sem.h"
15: #include "b2fil.h"
16: #include "b2sou.h"
17:
18: /************************** UNITS ************************************/
19:
20: value defunits, aster, global;
21:
22: Hidden value* unit_defn(fn) value fn; {
23: return envassoc(defunits, fn);
24: }
25:
26: Visible Procedure def_unit(u, un, ut) value u, un; literal ut; {
27: value fn= f_uname(un, ut);
28: e_replace(u, &defunits, fn);
29: release(fn);
30: }
31:
32: Visible value unit_info(un, ut) value un; literal ut; {
33: value fn= f_uname(un, ut);
34: value *aa= unit_defn(fn);
35: if (aa == Pnil) syserr("undefined function");
36: release(fn);
37: return *aa;
38: }
39:
40: Hidden bool is_loaded(un, ut, aa) value un, **aa; literal ut; {
41: value fn= f_uname(un, ut); txptr tx0, txstart0;
42: *aa= unit_defn(fn);
43: if (*aa != Pnil) { release(fn); return Yes; } /*already loaded*/
44: release(iname);
45: iname= fn;
46: ifile= fopen(strval(iname), "r");
47: if (ifile == NULL) {
48: vs_ifile();
49: return No;
50: }
51: tx0= tx; txstart0= txstart;
52: open_stream();
53: Eof= Eof0= No;
54: ilev(Yes); findceol();
55: get_unit(Yes);
56: *aa= unit_defn(iname);
57: if ((*aa) == Pnil) {
58: uname= un; /*utype= ???*/
59: parerr("filename and unit name incompatible","");
60: }
61: close_stream(tx0, txstart0);
62: fclose(ifile);
63: vs_ifile();
64: Eof= Eof0= No;
65: return Yes;
66: }
67:
68: Visible bool is_unit(un, ut, aa) value un, **aa; literal ut; {
69: context c; bool is;
70: sv_context(&c);
71: cntxt= In_unit;
72: is= is_loaded(un, ut, aa);
73: set_context(&c);
74: return is;
75: }
76:
77: #define DISCARD "the unit name is already in use; should the old unit be discarded?"
78: #define CANT_WRITE "cannot open file for editing; you need write permission in directory"
79: #define CANT_READ "unable to find file"
80:
81: Visible bool unit() {
82: txptr tx0= tx; value name, fname; literal type; FILE *ofile;
83: if (atkw(HOW_TO) || atkw(YIELD) || atkw(TEST)) {
84: tx= tx0;
85: uheading(aster, &name, &type);
86: fname= f_uname(name, type);
87: if (unit_defn(fname) != Pnil) {
88: if (is_intended(DISCARD)) free_unit(fname);
89: else { tx= ceol; release(fname); release(name);
90: return Yes;
91: }
92: }
93: if (interactive) {
94: ofile= fopen(strval(fname), "w");
95: if (ofile == NULL) error(CANT_WRITE);
96: while (Char(tx) != Eotc) putc(Char(tx++), ofile);
97: tx--;
98: fclose(ofile);
99: ed_unit(name, type, fname);
100: } else get_unit(No);
101: release(name); release(fname);
102: return Yes;
103: } else return No;
104: }
105:
106: #define On_file Vnil
107:
108: value last_tname= Vnil, last_tfname= Vnil; /*target*/
109:
110: Visible Procedure special() {
111: switch(Char(tx++)) {
112: case ':': ediuni(); break;
113: case '=': editar(); break;
114: case '!': shellcmd(); break;
115: default: syserr("edit");
116: }
117: }
118:
119:
120: #define FnSwitch(X) {release(fname); type= X; fname= f_uname(name, X);}
121:
122: #define MONADIC \
123: "the unit name is in use both for a monadic and a dyadic version;\n\
124: *** do you want to edit the monadic version?"
125:
126: Hidden Procedure ediuni() {
127: value name, fname; literal type;
128: Skipsp(tx);
129: if (Char(tx) == ':') {
130: lst_uhds();
131: To_eol(tx);
132: return;
133: }
134: if (Ceol(tx)) {
135: if (erruname == Vnil)
136: parerr("no current unit name known", "");
137: name= copy(erruname);
138: type= errutype;
139: fname= f_uname(name, type);
140: } else if (Cap(Char(tx))) {
141: name= keyword(ceol);
142: type= FHW;
143: fname= f_uname(name, FHW);
144: } else if (Letter(Char(tx))) {
145: name= tag(); type= FZR;
146: fname= f_uname(name, FZR);
147: if (!f_exists(fname)) {
148: bool is_mon, is_dya;
149: FnSwitch(FMN);
150: is_mon= f_exists(fname);
151: FnSwitch(FDY);
152: is_dya= f_exists(fname);
153: if (is_mon && (!is_dya || is_intended(MONADIC)))
154: FnSwitch(FMN);
155: }
156: } else parerr("I find nothing editible here", "");
157: To_eol(tx);
158: if (!f_exists(fname)) pprerr("no such unit in this workspace","");
159: ens_filed(fname);
160: ed_unit(name, type, fname); release(name); release(fname);
161: }
162:
163: Forward bool still_there();
164: Forward intlet err_line();
165:
166: /* Edit a unit.
167: It is possible that the user messes things up with the w command:
168: this is not checked. However it is allowed to rename the unit,
169: or delete it completely. If the file is empty, the unit is disposed of.
170: Otherwise, uheading is used to work out the name and adicity:
171: if these have changed, the new unit is written out to a new file,
172: and the original is written back. Thus the original is not lost.
173: Inability to find the file at all leads to the main_loop,
174: so that nothing is changed. */
175:
176: Hidden Procedure ed_unit(name, type, fname) value name, fname; literal type; {
177: intlet el= err_line(name); value nname, nfname, sname; literal ntype;
178: sname= f_save(fname); /*in case the unit gets renamed*/
179: f_edit(fname, el);
180: if (still_there(fname)) {
181: ilev(Yes); findceol();
182: uheading(name, &nname, &ntype);
183: nfname= f_uname(nname, ntype);
184: if (compare(fname, nfname) != 0) { /* unit heading was changed */
185: f_rename(fname, nfname); f_rename(sname, fname);
186: release(erruname); erruname= copy(nname);
187: errutype= ntype;
188: } else {
189: release(erruname); erruname= copy(name);
190: errutype= type;
191: f_delete(sname);
192: }
193: release(nname); release(nfname);
194: get_unit(Yes); /* file is still open */
195: } else {
196: free_unit(fname);
197: f_delete(sname);
198: release(erruname); erruname= Vnil; errlino= 0;
199: }
200: release(sname);
201: inistreams();
202: }
203:
204: Hidden Procedure uheading(oname, nname, ntype) value oname, *nname; literal *ntype; {
205: context ic; bool hu= No;
206: sv_context(&ic);
207: cntxt= In_unit; uname= oname;
208: lino= 1;
209: if ((hu= atkw(HOW_TO)) || atkw(YIELD) || atkw(TEST)) {
210: if (cur_ilev != 0) parerr("unit starts with indentation", "");
211: if (hu) {
212: uname= keyword(ceol); utype= FHW;
213: } else {
214: literal adic;
215: ytu_heading(&uname, &adic, ceol, No);
216: utype= (adic == Zer ? FZR : adic == Mon ? FMN : FDY);
217: }
218: *nname= uname; /*should really be n=copy(u); release(u);*/
219: *ntype= utype;
220: set_context(&ic);
221: } else parerr("no HOW'TO, YIELD or TEST where expected", "");
222: }
223:
224: Hidden bool still_there(fname) value fname; {
225: /* Find out if the file exists, and is not empty.
226: Some editors don't allow a file to be edited to empty,
227: but insist it should be at least one empty line.
228: Because it is hard to unget 2 chars, an initial empty line
229: may be disregarded, but this is not harmful. */
230: int k;
231: ifile= fopen(strval(fname), "r");
232: if (ifile == NULL) {
233: vs_ifile();
234: error(CANT_READ);
235: }
236: if ((k= getc(ifile)) == EOF || (k == '\n' && (k= getc(ifile)) == EOF)) {
237: fclose(ifile);
238: f_delete(fname);
239: vs_ifile();
240: return No;
241: }
242: ungetc(k, ifile);
243: return Yes;
244: }
245:
246: Hidden Procedure ens_filed(fname) value fname; {
247: value *aa= unit_defn(fname); how *du;
248: if (aa != Pnil) {
249: du= How_to(*aa);
250: if (du->filed == No) {
251: txptr ux= du->fux, lux= du->lux;
252: FILE *ofile= fopen(strval(fname), "w");
253: if (ofile == NULL) error(CANT_WRITE);
254: while (ux < lux) {
255: char c= *ux++;
256: putc(c == Eouc ? '\n' : c, ofile);
257: }
258: fclose(ofile);
259: du->filed= Yes;
260: }
261: }
262: }
263:
264: Hidden intlet err_line(name) value name; {
265: intlet el;
266: if (errlino == 0 || compare(erruname, name) != 0) return 0;
267: el= errlino; errlino= 0;
268: return el;
269: }
270:
271: Hidden Procedure free_unit(fname) value fname; {
272: e_delete(&defunits, fname);
273: }
274:
275: Hidden Procedure shellcmd() {
276: system(tx);
277: To_eol(tx);
278: }
279:
280: /************************** VALUES ***************************************/
281: /* The permanent environment in the old format was kept as a single file */
282: /* but this caused slow start ups if the file was big. */
283: /* Thus the new version stores each permanent target on a separate file, */
284: /* that furthermore is only loaded on demand. */
285: /* To achieve this, a directory is kept of the permanent tags and their */
286: /* file names. Care has to be taken that user interrupts occurring in */
287: /* the middle of an update of this directory do the least harm. */
288: /* Having the directory refer to a non-existent file is considered less */
289: /* harmful than leaving a file around that can never be accessed, for */
290: /* instance, so a file is deleted before its directory entry, */
291: /* and so forth. */
292: /*************************************************************************/
293:
294: value b_perm; /*The table that maps tags to their file names*/
295:
296: Visible bool is_tloaded(name, aa) value name, **aa; {
297: return No; /*for now*/
298: }
299:
300: Hidden bool new_tname(name, fname) value name, *fname; {
301: value *aa;
302: if (in_env(b_perm, name, &aa)) {
303: *fname= copy(*aa);
304: return No;
305: } else {
306: *fname= f_tname(name);
307: e_replace(*fname, &b_perm, name);
308: return Yes;
309: }
310: }
311:
312: Hidden Procedure editar() {
313: value name, fname;
314: Skipsp(tx);
315: if (Char(tx) == '=') {
316: lst_ttgs();
317: To_eol(tx);
318: return;
319: }
320: if (Ceol(tx)) {
321: if (last_tfname == Vnil)
322: parerr("no current target name known", "");
323: fname= copy(last_tfname);
324: name= copy(last_tname);
325: } else if (Letter(Char(tx))) {
326: name= tag();
327: VOID new_tname(name, &fname);
328: } else parerr("I find nothing editible here", "");
329: if (!f_exists(fname)) pprerr("no such target in this workspace","");
330: ens_tfiled(name, fname);
331: ed_target(name, fname); release(fname); release(name);
332: }
333:
334: Hidden Procedure lst_ttgs() {
335: int k, len;
336: len= length(prmnv->tab);
337: k_Over_len {
338: writ(*key(prmnv->tab, k));
339: wri_space();
340: }
341: newline();
342: }
343:
344: Hidden Procedure ed_target(name, fname) value name, fname; {
345: /* Edit a target. The value in the target is written to the file,
346: and then removed from the internal permanent environment so that
347: if a syntax error occurs when reading the value back, the value is
348: absent from the internal permanent environment.
349: Thus when editing the file to correct the syntax error, the
350: file doesn't get overwritten.
351: The contents may be completely deleted in which case the target is
352: deleted.
353: */
354: value v, p; context c; bool wia;
355: f_edit(fname, 0);
356: if (still_there(fname)) {
357: release(last_tfname); last_tfname= copy(fname);
358: release(last_tname); last_tname= copy(name);
359: fclose(ifile); /*since still_there leaves it open*/
360: sv_context(&c); wia= interactive;
361: cntxt= In_value;
362: getval(fname, &v);
363: /* p= mk_per(v);
364: */p=v; e_replace(p, &prmnv->tab, name);
365: set_context(&c); interactive= wia;
366: vs_ifile();
367: release(p);
368: /* release(v);
369: */ } else {
370: e_delete(&prmnv->tab, name);
371: e_delete(&b_perm, name);
372: release(last_tfname); release(last_tname);
373: last_tfname= Vnil; last_tname= Vnil;
374: }
375: f_delete(fname);
376: }
377:
378: Hidden Procedure ens_tfiled(name, fname) value name, fname; {
379: value p, *aa;
380: if (in_env(prmnv->tab, name, &aa) && !Is_filed(*aa)) {
381: putval(fname, *aa, No);
382: p= mk_per(Vnil);
383: e_replace(p, &prmnv->tab, name);
384: release(p);
385: }
386: }
387:
388: Hidden Procedure getval(nm, v) value nm, *v; {
389: char *buf= Nil; int k;
390: release(iname);
391: iname= copy(nm);
392: ifile= fopen(strval(iname), "r");
393: if (ifile != NULL) {
394: interactive= No;
395: alino= 0; xeq= Yes; active_reads= 0; /*CHANGE*/
396: buf= getmem((unsigned)(f_size(ifile)+2)*sizeof(char));
397: if (buf == Nil) syserr("can't get buffer to read file");
398: *(txend= buf)= Eotc; tx= ceol= txend+1;
399: while ((k= getc(ifile)) != EOF)
400: if (k != '\n') *ceol++= k;
401: *ceol= '\n'; alino= 1; *v= expr(ceol);
402: fclose(ifile);
403: if (buf != Nil) freemem(buf);
404: } else error(CANT_READ);
405: }
406:
407: Visible Procedure getprmnv() {
408: value fn= mk_text(".prmnv");
409: cntxt= In_prmnv;
410: if (f_exists(fn)) { /* convert from old to new format */
411: getval(fn, &prmnv->tab);
412: b_perm= mk_elt();
413: /* putprmnv();
414: f_delete(fn); /*after writing the new one, for safety*/
415: /* */ release(fn);
416: } else {
417: prmnv->tab= mk_elt();
418: b_perm= mk_elt();
419: /* release(fn);
420: fn= mk_text(".b_perm");
421: if (f_exists(fn)) {
422: getval(fn, &b_perm);
423: create_prmnv();
424: } else {
425: b_perm= mk_elt();
426: prmnv->tab= mk_elt();
427: }
428: */ release(fn);
429: }
430: }
431:
432: Hidden Procedure putval(nm, v, silently) value nm, v; bool silently; {
433: FILE *ofile;
434: ofile= fopen(strval(nm), "w");
435: if (ofile != NULL) {
436: redirect(ofile);
437: wri(v, No, No, Yes); newline();
438: fclose(ofile);
439: redirect(stdout);
440: } else if (!silently) error(CANT_WRITE);
441: }
442:
443: Visible Procedure putprmnv() {
444: bool changed= No; value fn;
445: value pt1, pt2; env c;
446: int k, len= length(prmnv->tab);
447:
448: ignsigs(); /*because files are created before the directory is written*/
449: pt1= prmnv->tab; pt2= prmnvtab; c= curnv;
450: setprmnv();
451: k_Over_len {
452: value v= copy(*assoc(prmnv->tab, k));
453: if (!Is_filed(v)) {
454: /* value t= copy(*key(prmnv->tab, k));
455: wri_target(t, v, &changed);
456: release(t);
457: */}else{e_delete(&prmnv->tab, *key(prmnv->tab, k));
458: }
459: release(v);
460: }
461: fn= mk_text(".prmnv");
462: putval(fn, prmnv->tab, Yes);
463: release(fn);
464: if (changed) {
465: fn= mk_text(".b_perm");
466: putval(fn, b_perm, Yes);
467: release(fn);
468: }
469: prmnv->tab= pt1; prmnvtab= pt2; curnv= c; /* kludgy */
470: re_sigs();
471: }
472:
473: Hidden Procedure wri_target(t, v, changed) value t, v; bool* changed; {
474: value fn, p;
475: bool new= new_tname(t, &fn);
476: if (new) *changed= Yes;
477: putval(fn, v, Yes);
478: p= mk_per(v);
479: e_replace(p, &prmnv->tab, t); /*after writing file*/
480: release(p); release(fn);
481: }
482:
483: Hidden Procedure create_prmnv() {
484: value p= mk_per(Vnil);
485: int k, len= length(b_perm);
486:
487: k_Over_len {
488: e_replace(copy(p), &prmnv->tab, *key(b_perm, k));
489: }
490: release(p);
491: }
492:
493: Visible Procedure initsou() {
494: defunits= mk_elt();
495: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.