|
|
1.1 root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2:
3: /*
4: $Header: b3scr.c,v 1.4 85/08/22 16:58:54 timo Exp $
5: */
6:
7: /* B input/output handling */
8:
9: #include "b.h"
10: #include "b0fea.h"
11: #include "b1mem.h"
12: #include "b1obj.h"
13: #include "b0con.h" /*for CLEAR_EOF*/
14: #include "b2nod.h"
15: #include "b2syn.h"
16: #include "b2par.h"
17: #include "b3scr.h"
18: #include "b3err.h"
19: #include "b3fil.h"
20: #include "b3typ.h"
21: #include "b3env.h"
22: #include "b3sem.h"
23: #include "b3int.h"
24: #ifdef SETJMP
25: #include <setjmp.h>
26: #endif
27:
28: Visible bool interactive;
29: Visible bool rd_interactive;
30: Visible value iname= Vnil; /* input name */
31: Visible bool filtered= No;
32: Visible bool outeractive;
33: #ifdef SETJMP
34: Visible bool awaiting_input= No;
35: Visible jmp_buf read_interrupt;
36: #endif
37: Visible bool at_nwl= Yes; /*Yes if currently at the start of an output line*/
38: Hidden bool woa, wnwl; /*was outeractive, was at_nwl */
39: Hidden bool last_was_text= No; /*Yes if last value written was a text*/
40:
41: Visible bool Eof;
42: FILE *ofile= stdout;
43: FILE *ifile; /* input file */
44: FILE *sv_ifile; /* copy of ifile for restoring after reading unit */
45:
46: /******************************* Output *******************************/
47:
48: #ifndef INTEGRATION
49:
50: Hidden Procedure putch(c) char c; {
51: if (still_ok) {
52: putc(c, ofile);
53: if (c == '\n') at_nwl= Yes;
54: else at_nwl= No;
55: }
56: }
57:
58: #else
59:
60: Hidden int ocol; /* Current output column */
61:
62: Hidden Procedure putch(c) char c; {
63: if (still_ok) {
64: putc(c, ofile);
65: if (c == '\n') { at_nwl= Yes; ocol= 0; }
66: else {
67: if (at_nwl) { ocol= 0; at_nwl= No;}
68: ++ocol;
69: }
70: }
71: }
72:
73: #endif
74:
75: Visible Procedure newline() {
76: putch('\n');
77: fflush(stdout);
78: }
79:
80: Hidden Procedure line() {
81: if (!at_nwl) newline();
82: }
83:
84: Visible Procedure wri_space() {
85: putch(' ');
86: }
87:
88: Visible Procedure writ(v) value v; {
89: wri(v, Yes, Yes, No);
90: fflush(stdout);
91: }
92:
93: #define Putch_sp() {if (!perm) putch(' ');}
94:
95: Hidden int intsize(v) value v; {
96: value s= size(v); int len=0;
97: if (large(s)) error(MESS(3800, "value too big to output"));
98: else len= intval(s);
99: release(s);
100: return len;
101: }
102:
103: Hidden bool lwt;
104:
105: Visible Procedure wri(v, coll, outer, perm) value v; bool coll, outer, perm; {
106: if (outer && !at_nwl && (!Is_text(v) || !last_was_text)
107: && (!Is_compound(v) || !coll)) putch(' ');
108: lwt= No;
109: if (Is_number(v)) {
110: if (perm) printnum(ofile, v);
111: else {
112: string cp= convnum(v);
113: while(*cp && still_ok) putch(*cp++);
114: }
115: } else if (Is_text(v)) {
116: #ifndef INTEGRATION
117: wrtext(putch, v, outer ? '\0' : '"');
118: #else
119: value ch; char c; int k, len= Length(v);
120: #define QUOTE '"'
121: if (!outer) putch(QUOTE);
122: for (k=0; k<len && still_ok; k++) {
123: ch= thof(k+1, v);
124: putch(c= charval(ch));
125: if (!outer && (c == QUOTE || c == '`'))
126: putch(c);
127: release(ch);
128: }
129: if (!outer) putch(QUOTE);
130: #endif
131: lwt= outer;
132: } else if (Is_compound(v)) {
133: intlet k, len= Nfields(v);
134: outer&= coll;
135: if (!coll) putch('(');
136: for (k=0; k<len && still_ok; k++) {
137: wri(*Field(v, k), No, outer, perm);
138: if (!Lastfield(k)) {
139: if (!outer){
140: putch(',');
141: Putch_sp();
142: }
143: }
144: }
145: if (!coll) putch(')');
146: } else if (Is_list(v) || Is_ELT(v)) {
147: value ve; int k, len= intsize(v);
148: putch('{');
149: for (k=0; k<len && still_ok; k++) {
150: wri(ve= thof(k+1, v), No, No, perm);
151: release(ve);
152: if (!Last(k)) {
153: putch(';');
154: Putch_sp();
155: }
156: }
157: putch('}');
158: } else if (Is_table(v)) {
159: int k, len= intsize(v);
160: putch('{');
161: for (k=0; k<len && still_ok; k++) {
162: putch('['); wri(*key(v, k), Yes, No, perm);
163: putch(']'); putch(':'); Putch_sp();
164: wri(*assoc(v, k), No, No, perm);
165: if (!Last(k)) {
166: putch(';');
167: Putch_sp();
168: }
169: }
170: putch('}');
171: } else {
172: if (bugs || testing) { putch('?'); putch(Type(v)); putch('?'); }
173: else syserr(MESS(3801, "writing value of unknown type"));
174: }
175: last_was_text= lwt;
176: #ifdef IBMPC
177: if (interrupted) clearerr(ofile);
178: #endif
179: }
180:
181: /***************************** Input ****************************************/
182:
183: Hidden char cmbuf[CMBUFSIZE]; /* for commands */
184: Hidden char rdbuf[RDBUFSIZE]; /* for READ EG/RAW */
185:
186: #ifndef INTEGRATION
187: Visible string cmd_prompt= ">>> "; /* commands */
188: Visible string eg_prompt= "?\b"; /* READ EG */
189: Visible string raw_prompt= "?\b"; /* READ RAW */
190: Visible string qn_prompt= "?\b"; /* questions */
191: #else
192: Hidden literal cmd_prompt= '>'; /* commands */
193: Hidden literal eg_prompt= 'E'; /* READ EG */
194: Hidden literal raw_prompt= 'R'; /* READ RAW */
195: Hidden literal qn_prompt= 'Y'; /* questions */
196: Visible literal unit_prompt= ':'; /* units */
197: Visible literal tar_prompt= '='; /* targets */
198: #endif
199:
200: /* Read a line; EOF only allowed if not interactive, in which case eof set */
201: /* Returns the line input */
202: /* This is the only place where a long jump is necessary */
203: /* In other places, interrupts are just like procedure calls, and checks */
204: /* of still_ok and interrupted suffice: eventually the stack unwinds to the*/
205: /* main loop in imm_command(). Here though, an interrupt must actually */
206: /* terminate the read. Hence the bool awaiting_input indicating if the */
207: /* long jump is necessary or not */
208:
209: #ifndef INTEGRATION
210:
211: Hidden txptr read_line(should_prompt, prompt, cmd, eof, eof_message)
212: bool should_prompt, cmd, *eof; string prompt, eof_message; {
213: txptr buf, rp, bufend; intlet k; bool got= No;
214: FILE *f;
215: *eof= No;
216: if (cmd) { buf= cmbuf; bufend= &cmbuf[CMBUFSIZE-2]; }
217: else { buf= rdbuf; bufend= &rdbuf[RDBUFSIZE-2]; }
218: #ifdef SETJMP
219: if (setjmp(read_interrupt) != 0) {
220: awaiting_input= No;
221: return buf;
222: }
223: #endif
224: while (!got) {
225: rp= buf;
226: #ifdef SETJMP
227: awaiting_input= Yes;
228: #endif
229: if (should_prompt) {
230: if (cmd) {
231: if (outeractive) {
232: line();
233: at_nwl= No;
234: }
235: }
236: fprintf(stderr, prompt); fflush(stderr);
237: f= stdin;
238: } else {
239: f= ifile;
240: }
241: while ((k= getc(f)) != EOF && k != '\n') {
242: *rp++= k;
243: if (rp >= bufend) syserr(MESS(3802, "buffer overflow"));
244: }
245: #ifdef SETJMP
246: awaiting_input= No;
247: #endif
248: got= Yes; *rp++= '\n'; *rp= '\0';
249: if (k == EOF) {
250: if (should_prompt) {
251: if (filtered) {
252: bye(0); /*Editor has died*/
253: } else {
254: fprintf(stderr, "\r*** %s\n", eof_message);
255: CLEAR_EOF;
256: if (outeractive) at_nwl= Yes;
257: got= No;
258: }
259: } else *eof= Yes;
260: }
261: }
262: if (should_prompt && outeractive && k == '\n') at_nwl= Yes;
263: return buf;
264: }
265:
266: #else INTEGRATION
267:
268: Hidden intlet
269: rd_fileline(nbuf, file, nbufend)
270: string nbuf, nbufend;
271: FILE *file;
272: {
273: intlet k;
274: while ((k= getc(file)) != EOF && k != '\n') {
275: *nbuf++= k;
276: if (nbuf >= nbufend)
277: syserr(MESS(3803, "buffer overflow rd_fileline()"));
278: }
279: *nbuf++= '\n'; *nbuf= '\0';
280: return k;
281: }
282:
283: Hidden intlet
284: rd_bufline(nbuf, obuf, nbufend)
285: string nbuf, *obuf, nbufend;
286: {
287: while (**obuf && **obuf != '\n') {
288: *nbuf++= **obuf; ++*obuf;
289: if (nbuf >= nbufend)
290: syserr(MESS(3804, "buffer overflow rd_bufline()"));
291: }
292: *nbuf++= '\n'; *nbuf= '\0';
293: if (**obuf) { ++*obuf; return '\n';}
294: else return EOF;
295: }
296:
297: Hidden string edcmdbuf;
298:
299: Hidden txptr
300: read_line(should_prompt, prompt, cmd, eof, eof_message)
301: bool should_prompt, cmd, *eof; literal prompt; string eof_message;
302: {
303: txptr buf, rp, bufend; intlet k, indent= 0; bool got= No;
304: static string pedcmdbuf;
305: if (prompt == eg_prompt || prompt == raw_prompt) indent= ocol;
306: *eof= No;
307: if (cmd) { buf= cmbuf; bufend= &cmbuf[CMBUFSIZE-2]; }
308: else { buf= rdbuf; bufend= &rdbuf[RDBUFSIZE-2]; }
309: #ifdef SETJMP
310: if (setjmp(read_interrupt) != 0) {
311: awaiting_input= No;
312: return buf;
313: }
314: #endif
315: while (!got) {
316: rp= buf; got= Yes;
317: #ifdef SETJMP
318: awaiting_input= Yes;
319: #endif
320: if (!should_prompt) {
321: k= rd_fileline(rp, ifile, bufend);
322: if (k == EOF) *eof= Yes;
323: } else {
324: if (!edcmdbuf) {
325: if (cmd && outeractive) { line(); at_nwl= No; }
326: btop(&edcmdbuf, 0, prompt, indent);
327: pedcmdbuf= edcmdbuf;
328: }
329: k= rd_bufline(rp, &pedcmdbuf, bufend);
330: if (k == EOF) {
331: freemem((ptr) edcmdbuf);
332: edcmdbuf= (string) NULL;
333: if (prompt != '>') got= No;
334: }
335: }
336: #ifdef SETJMP
337: awaiting_input= No;
338: #endif
339: }
340:
341: if (should_prompt && outeractive && k == '\n') at_nwl= Yes;
342: return buf;
343: }
344:
345: #endif INTEGRATION
346:
347: /* Rather over-fancy routine to ask the user a question */
348: /* Will anybody discover that you're only given 4 chances? */
349:
350: Hidden char USE_YES_OR_NO[]=
351: "Answer with yes or no (or use interrupt to duck the question)";
352:
353: Hidden char LAST_CHANCE[]=
354: "This is your last chance. Take it. I really don't know what you want.\n\
355: So answer the question";
356:
357: Hidden char NO_THEN[]=
358: "Well, I shall assume that your refusal to answer the question means no!";
359:
360: Visible bool is_intended(m) string m; {
361: char answer; intlet try; txptr tp; bool eof;
362: if (!interactive) return Yes;
363: if (outeractive) line();
364: for (try= 1; try<=4; try++){
365: if (try == 1 || try == 3) fprintf(stderr, "*** %s\n", m);
366: tp= read_line(Yes, qn_prompt, No, &eof, USE_YES_OR_NO);
367: skipsp(&tp);
368: answer= Char(tp);
369: if (answer == 'y' || answer == 'Y') return Yes;
370: if (answer == 'n' || answer == 'N') return No;
371: if (outeractive) line();
372: fprintf(stderr, "*** %s\n",
373: try == 1 ? "Please answer with yes or no" :
374: try == 2 ? "Just yes or no, please" :
375: try == 3 ? LAST_CHANCE :
376: NO_THEN);
377: } /* end for */
378: return No;
379: }
380:
381: /* Read_eg uses evaluation but it shouldn't.
382: Wait for a more general mechanism. */
383:
384: Visible Procedure read_eg(l, t) loc l; btype t; {
385: context c; parsetree code;
386: parsetree r= NilTree; value rv= Vnil; btype rt= Vnil;
387: envtab svprmnvtab= Vnil;
388: txptr fcol_save= first_col, tx_save= tx;
389: do {
390: still_ok= Yes;
391: sv_context(&c);
392: if (cntxt != In_read) {
393: release(read_context.uname);
394: sv_context(&read_context);
395: }
396: svprmnvtab= prmnvtab == Vnil ? Vnil : prmnv->tab;
397: /* save scratch-pad copy because of following setprmnv() */
398: setprmnv();
399: cntxt= In_read;
400: first_col= tx= read_line(rd_interactive, eg_prompt, No,
401: &Eof, "use interrupt to abort READ command");
402: if (still_ok && Eof)
403: error(MESS(3805, "End of file encountered during READ command"));
404: if (!rd_interactive) f_lino++;
405: if (still_ok) {
406: findceol();
407: r= expr(ceol);
408: if (still_ok) fix_nodes(&r, &code);
409: rv= evalthread(code); release(r);
410: rt= still_ok ? valtype(rv) : Vnil;
411: if (svprmnvtab != Vnil) {
412: prmnvtab= prmnv->tab;
413: prmnv->tab= svprmnvtab;
414: }
415: set_context(&c);
416: if (still_ok) must_agree(t, rt,
417: MESS(3806, "type of expression does not agree with that of EG sample"));
418: release(rt);
419: }
420: if (!still_ok && rd_interactive && !interrupted)
421: fprintf(stderr, "*** Please try again\n");
422: } while (!interrupted && !still_ok && rd_interactive);
423: if (still_ok) put(rv, l);
424: first_col= fcol_save;
425: tx= tx_save;
426: release(rv);
427: }
428:
429: Visible Procedure read_raw(l) loc l; {
430: value r; bool eof;
431: txptr line= read_line(rd_interactive, raw_prompt, No, &eof,
432: "use interrupt to abort READ t RAW");
433: if (still_ok && eof) error(MESS(3807, "End of file encountered during READ t RAW"));
434: if (!rd_interactive) f_lino++;
435: if (still_ok) {
436: txptr rp= line;
437: while (*rp != '\n') rp++;
438: *rp= '\0';
439: r= mk_text(line);
440: put(r, l);
441: release(r);
442: }
443: }
444:
445: Visible txptr getline() {
446: bool should_prompt=
447: interactive && sv_ifile == ifile;
448: return read_line(should_prompt, cmd_prompt, Yes, &Eof,
449: "use QUIT to end session");
450: }
451:
452: /******************************* Files ******************************/
453:
454: Visible Procedure redirect(of) FILE *of; {
455: ofile= of;
456: if (of == stdout) {
457: outeractive= woa;
458: at_nwl= wnwl;
459: } else {
460: woa= outeractive; outeractive= No;
461: wnwl= at_nwl; at_nwl= Yes;
462: }
463: }
464:
465: Visible Procedure vs_ifile() {
466: ifile= sv_ifile;
467: }
468:
469: Visible Procedure re_screen() {
470: sv_ifile= ifile;
471: interactive= f_interactive(ifile) || (ifile == stdin && filtered);
472: Eof= No;
473: }
474:
475: /* initscr is a reserved name of CURSES */
476: Visible Procedure init_scr() {
477: outeractive= f_interactive(stdout) || filtered;
478: rd_interactive= f_interactive(stdin) || filtered;
479: rdbuf[0]= '\n'; tx= rdbuf;
480: }
481:
482: Visible Procedure
483: endscr()
484: {
485: #ifdef INTEGRATION
486: if (edcmdbuf) {
487: freemem((ptr) edcmdbuf);
488: edcmdbuf= (string) NULL;
489: }
490: #endif
491: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.