xref: /csrg-svn/usr.bin/pascal/src/proc.c (revision 2073)
1768Speter /* Copyright (c) 1979 Regents of the University of California */
2768Speter 
3*2073Smckusic static	char sccsid[] = "@(#)proc.c 1.4 01/06/81";
4768Speter 
5768Speter #include "whoami.h"
6768Speter #ifdef OBJ
7768Speter     /*
8768Speter      *	and the rest of the file
9768Speter      */
10768Speter #include "0.h"
11768Speter #include "tree.h"
12768Speter #include "opcode.h"
13768Speter #include "objfmt.h"
14768Speter 
15768Speter /*
16768Speter  * The following array is used to determine which classes may be read
17768Speter  * from textfiles. It is indexed by the return value from classify.
18768Speter  */
19768Speter #define rdops(x) rdxxxx[(x)-(TFIRST)]
20768Speter 
21768Speter int rdxxxx[] = {
22768Speter 	0,		/* -7 file types */
23768Speter 	0,		/* -6 record types */
24768Speter 	0,		/* -5 array types */
25768Speter 	O_READE,	/* -4 scalar types */
26768Speter 	0,		/* -3 pointer types */
27768Speter 	0,		/* -2 set types */
28768Speter 	0,		/* -1 string types */
29768Speter 	0,		/*  0 nil, no type */
30768Speter 	O_READE,	/*  1 boolean */
31768Speter 	O_READC,	/*  2 character */
32768Speter 	O_READ4,	/*  3 integer */
33768Speter 	O_READ8		/*  4 real */
34768Speter };
35768Speter 
36768Speter /*
37768Speter  * Proc handles procedure calls.
38768Speter  * Non-builtin procedures are "buck-passed" to func (with a flag
39768Speter  * indicating that they are actually procedures.
40768Speter  * builtin procedures are handled here.
41768Speter  */
42768Speter proc(r)
43768Speter 	int *r;
44768Speter {
45768Speter 	register struct nl *p;
46768Speter 	register int *alv, *al, op;
47768Speter 	struct nl *filetype, *ap;
48768Speter 	int argc, *argv, typ, fmtspec, strfmt, stkcnt, *file;
49768Speter 	char fmt, format[20], *strptr;
50768Speter 	int prec, field, strnglen, fmtlen, fmtstart, pu;
51768Speter 	int *pua, *pui, *puz;
52768Speter 	int i, j, k;
53768Speter 	int itemwidth;
54768Speter 
55768Speter #define	CONPREC 4
56768Speter #define	VARPREC 8
57768Speter #define	CONWIDTH 1
58768Speter #define	VARWIDTH 2
59768Speter #define SKIP 16
60768Speter 
61768Speter 	/*
62768Speter 	 * Verify that the name is
63768Speter 	 * defined and is that of a
64768Speter 	 * procedure.
65768Speter 	 */
66768Speter 	p = lookup(r[2]);
67768Speter 	if (p == NIL) {
68768Speter 		rvlist(r[3]);
69768Speter 		return;
70768Speter 	}
711198Speter 	if (p->class != PROC && p->class != FPROC) {
72768Speter 		error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]);
73768Speter 		rvlist(r[3]);
74768Speter 		return;
75768Speter 	}
76768Speter 	argv = r[3];
77768Speter 
78768Speter 	/*
79768Speter 	 * Call handles user defined
80768Speter 	 * procedures and functions.
81768Speter 	 */
82768Speter 	if (bn != 0) {
83768Speter 		call(p, argv, PROC, bn);
84768Speter 		return;
85768Speter 	}
86768Speter 
87768Speter 	/*
88768Speter 	 * Call to built-in procedure.
89768Speter 	 * Count the arguments.
90768Speter 	 */
91768Speter 	argc = 0;
92768Speter 	for (al = argv; al != NIL; al = al[2])
93768Speter 		argc++;
94768Speter 
95768Speter 	/*
96768Speter 	 * Switch on the operator
97768Speter 	 * associated with the built-in
98768Speter 	 * procedure in the namelist
99768Speter 	 */
100768Speter 	op = p->value[0] &~ NSTAND;
101768Speter 	if (opt('s') && (p->value[0] & NSTAND)) {
102768Speter 		standard();
103768Speter 		error("%s is a nonstandard procedure", p->symbol);
104768Speter 	}
105768Speter 	switch (op) {
106768Speter 
107768Speter 	case O_ABORT:
108768Speter 		if (argc != 0)
109768Speter 			error("null takes no arguments");
110768Speter 		return;
111768Speter 
112768Speter 	case O_FLUSH:
113768Speter 		if (argc == 0) {
114768Speter 			put(1, O_MESSAGE);
115768Speter 			return;
116768Speter 		}
117768Speter 		if (argc != 1) {
118768Speter 			error("flush takes at most one argument");
119768Speter 			return;
120768Speter 		}
121*2073Smckusic 		ap = stklval(argv[1], NIL , LREQ );
122768Speter 		if (ap == NIL)
123768Speter 			return;
124768Speter 		if (ap->class != FILET) {
125768Speter 			error("flush's argument must be a file, not %s", nameof(ap));
126768Speter 			return;
127768Speter 		}
128768Speter 		put(1, op);
129768Speter 		return;
130768Speter 
131768Speter 	case O_MESSAGE:
132768Speter 	case O_WRITEF:
133768Speter 	case O_WRITLN:
134768Speter 		/*
135768Speter 		 * Set up default file "output"'s type
136768Speter 		 */
137768Speter 		file = NIL;
138768Speter 		filetype = nl+T1CHAR;
139768Speter 		/*
140768Speter 		 * Determine the file implied
141768Speter 		 * for the write and generate
142768Speter 		 * code to make it the active file.
143768Speter 		 */
144768Speter 		if (op == O_MESSAGE) {
145768Speter 			/*
146768Speter 			 * For message, all that matters
147768Speter 			 * is that the filetype is
148768Speter 			 * a character file.
149768Speter 			 * Thus "output" will suit us fine.
150768Speter 			 */
151768Speter 			put(1, O_MESSAGE);
152768Speter 		} else if (argv != NIL && (al = argv[1])[0] != T_WEXP) {
153768Speter 			/*
154768Speter 			 * If there is a first argument which has
155768Speter 			 * no write widths, then it is potentially
156768Speter 			 * a file name.
157768Speter 			 */
158768Speter 			codeoff();
159768Speter 			ap = stkrval(argv[1], NIL , RREQ );
160768Speter 			codeon();
161768Speter 			if (ap == NIL)
162768Speter 				argv = argv[2];
163768Speter 			if (ap != NIL && ap->class == FILET) {
164768Speter 				/*
165768Speter 				 * Got "write(f, ...", make
166768Speter 				 * f the active file, and save
167768Speter 				 * it and its type for use in
168768Speter 				 * processing the rest of the
169768Speter 				 * arguments to write.
170768Speter 				 */
171768Speter 				file = argv[1];
172768Speter 				filetype = ap->type;
173*2073Smckusic 				stklval(argv[1], NIL , LREQ );
174768Speter 				put(1, O_UNIT);
175768Speter 				/*
176768Speter 				 * Skip over the first argument
177768Speter 				 */
178768Speter 				argv = argv[2];
179768Speter 				argc--;
180768Speter 			} else
181768Speter 				/*
182768Speter 				 * Set up for writing on
183768Speter 				 * standard output.
184768Speter 				 */
185768Speter 				put(1, O_UNITOUT);
186768Speter 		} else
187768Speter 			put(1, O_UNITOUT);
188768Speter 		/*
189768Speter 		 * Loop and process each
190768Speter 		 * of the arguments.
191768Speter 		 */
192768Speter 		for (; argv != NIL; argv = argv[2]) {
193768Speter 			/*
194768Speter 			 * fmtspec indicates the type (CONstant or VARiable)
195768Speter 			 *	and number (none, WIDTH, and/or PRECision)
196768Speter 			 *	of the fields in the printf format for this
197768Speter 			 *	output variable.
198768Speter 			 * stkcnt is the number of longs pushed on the stack
199768Speter 			 * fmt is the format output indicator (D, E, F, O, X, S)
200768Speter 			 * fmtstart = 0 for leading blank; = 1 for no blank
201768Speter 			 */
202768Speter 			fmtspec = NIL;
203768Speter 			stkcnt = 0;
204768Speter 			fmt = 'D';
205768Speter 			fmtstart = 1;
206768Speter 			al = argv[1];
207768Speter 			if (al == NIL)
208768Speter 				continue;
209768Speter 			if (al[0] == T_WEXP)
210768Speter 				alv = al[1];
211768Speter 			else
212768Speter 				alv = al;
213768Speter 			if (alv == NIL)
214768Speter 				continue;
215768Speter 			codeoff();
216768Speter 			ap = stkrval(alv, NIL , RREQ );
217768Speter 			codeon();
218768Speter 			if (ap == NIL)
219768Speter 				continue;
220768Speter 			typ = classify(ap);
221768Speter 			if (al[0] == T_WEXP) {
222768Speter 				/*
223768Speter 				 * Handle width expressions.
224768Speter 				 * The basic game here is that width
225768Speter 				 * expressions get evaluated. If they
226768Speter 				 * are constant, the value is placed
227768Speter 				 * directly in the format string.
228768Speter 				 * Otherwise the value is pushed onto
229768Speter 				 * the stack and an indirection is
230768Speter 				 * put into the format string.
231768Speter 				 */
232768Speter 				if (al[3] == OCT)
233768Speter 					fmt = 'O';
234768Speter 				else if (al[3] == HEX)
235768Speter 					fmt = 'X';
236768Speter 				else if (al[3] != NIL) {
237768Speter 					/*
238768Speter 					 * Evaluate second format spec
239768Speter 					 */
240768Speter 					if ( constval(al[3])
241768Speter 					    && isa( con.ctype , "i" ) ) {
242768Speter 						fmtspec += CONPREC;
243768Speter 						prec = con.crval;
244768Speter 					} else {
245768Speter 						fmtspec += VARPREC;
246768Speter 					}
247768Speter 					fmt = 'f';
248768Speter 					switch ( typ ) {
249768Speter 					case TINT:
250768Speter 						if ( opt( 's' ) ) {
251768Speter 						    standard();
252768Speter 						    error("Writing %ss with two write widths is non-standard", clnames[typ]);
253768Speter 						}
254768Speter 						/* and fall through */
255768Speter 					case TDOUBLE:
256768Speter 						break;
257768Speter 					default:
258768Speter 						error("Cannot write %ss with two write widths", clnames[typ]);
259768Speter 						continue;
260768Speter 					}
261768Speter 				}
262768Speter 				/*
263768Speter 				 * Evaluate first format spec
264768Speter 				 */
265768Speter 				if (al[2] != NIL) {
266768Speter 					if ( constval(al[2])
267768Speter 					    && isa( con.ctype , "i" ) ) {
268768Speter 						fmtspec += CONWIDTH;
269768Speter 						field = con.crval;
270768Speter 					} else {
271768Speter 						fmtspec += VARWIDTH;
272768Speter 					}
273768Speter 				}
274768Speter 				if ((fmtspec & CONPREC) && prec < 0 ||
275768Speter 				    (fmtspec & CONWIDTH) && field < 0) {
276768Speter 					error("Negative widths are not allowed");
277768Speter 					continue;
278768Speter 				}
279768Speter 			}
280768Speter 			if (filetype != nl+T1CHAR) {
281768Speter 				if (fmt == 'O' || fmt == 'X') {
282768Speter 					error("Oct/hex allowed only on text files");
283768Speter 					continue;
284768Speter 				}
285768Speter 				if (fmtspec) {
286768Speter 					error("Write widths allowed only on text files");
287768Speter 					continue;
288768Speter 				}
289768Speter 				/*
290768Speter 				 * Generalized write, i.e.
291768Speter 				 * to a non-textfile.
292768Speter 				 */
293*2073Smckusic 				stklval(file, NIL , LREQ );
294768Speter 				put(1, O_FNIL);
295768Speter 				/*
296768Speter 				 * file^ := ...
297768Speter 				 */
298768Speter 				ap = rvalue(argv[1], NIL);
299768Speter 				if (ap == NIL)
300768Speter 					continue;
301768Speter 				if (incompat(ap, filetype, argv[1])) {
302768Speter 					cerror("Type mismatch in write to non-text file");
303768Speter 					continue;
304768Speter 				}
305768Speter 				convert(ap, filetype);
306768Speter 				put(2, O_AS, width(filetype));
307768Speter 				/*
308768Speter 				 * put(file)
309768Speter 				 */
310768Speter 				put(1, O_PUT);
311768Speter 				continue;
312768Speter 			}
313768Speter 			/*
314768Speter 			 * Write to a textfile
315768Speter 			 *
316768Speter 			 * Evaluate the expression
317768Speter 			 * to be written.
318768Speter 			 */
319768Speter 			if (fmt == 'O' || fmt == 'X') {
320768Speter 				if (opt('s')) {
321768Speter 					standard();
322768Speter 					error("Oct and hex are non-standard");
323768Speter 				}
324768Speter 				if (typ == TSTR || typ == TDOUBLE) {
325768Speter 					error("Can't write %ss with oct/hex", clnames[typ]);
326768Speter 					continue;
327768Speter 				}
328768Speter 				if (typ == TCHAR || typ == TBOOL)
329768Speter 					typ = TINT;
330768Speter 			}
331768Speter 			/*
332768Speter 			 * Place the arguement on the stack. If there is
333768Speter 			 * no format specified by the programmer, implement
334768Speter 			 * the default.
335768Speter 			 */
336768Speter 			switch (typ) {
337768Speter 			case TINT:
338768Speter 				if (fmt != 'f') {
339768Speter 					ap = stkrval(alv, NIL , RREQ );
340768Speter 					stkcnt++;
341768Speter 				} else {
342768Speter 					ap = stkrval(alv, NIL , RREQ );
343768Speter 					put(1, O_ITOD);
344768Speter 					stkcnt += 2;
345768Speter 					typ = TDOUBLE;
346768Speter 					goto tdouble;
347768Speter 				}
348768Speter 				if (fmtspec == NIL) {
349768Speter 					if (fmt == 'D')
350768Speter 						field = 10;
351768Speter 					else if (fmt == 'X')
352768Speter 						field = 8;
353768Speter 					else if (fmt == 'O')
354768Speter 						field = 11;
355768Speter 					else
356768Speter 						panic("fmt1");
357768Speter 					fmtspec = CONWIDTH;
358768Speter 				}
359768Speter 				break;
360768Speter 			case TCHAR:
361768Speter 			     tchar:
362*2073Smckusic 				if (fmtspec == NIL) {
363*2073Smckusic 					put(1, O_FILE);
364*2073Smckusic 					ap = stkrval(alv, NIL , RREQ );
365*2073Smckusic 					put(1, O_WRITEC);
366*2073Smckusic 					fmtspec = SKIP;
367*2073Smckusic 					break;
368*2073Smckusic 				}
369768Speter 				ap = stkrval(alv, NIL , RREQ );
370768Speter 				stkcnt++;
371768Speter 				fmt = 'c';
372768Speter 				break;
373768Speter 			case TSCAL:
3741628Speter 				warning();
375768Speter 				if (opt('s')) {
376768Speter 					standard();
377768Speter 				}
3781628Speter 				error("Writing scalars to text files is non-standard");
379768Speter 			case TBOOL:
380768Speter 				stkrval(alv, NIL , RREQ );
381768Speter 				put(2, O_NAM, listnames(ap));
382768Speter 				stkcnt++;
383768Speter 				fmt = 's';
384768Speter 				break;
385768Speter 			case TDOUBLE:
386768Speter 				ap = stkrval(alv, TDOUBLE , RREQ );
387768Speter 				stkcnt += 2;
388768Speter 			     tdouble:
389768Speter 				switch (fmtspec) {
390768Speter 				case NIL:
391768Speter 					field = 21;
392768Speter 					prec = 14;
393768Speter 					fmt = 'E';
394768Speter 					fmtspec = CONWIDTH + CONPREC;
395768Speter 					break;
396768Speter 				case CONWIDTH:
397768Speter 					if (--field < 1)
398768Speter 						field = 1;
399768Speter 					prec = field - 7;
400768Speter 					if (prec < 1)
401768Speter 						prec = 1;
402768Speter 					fmtspec += CONPREC;
403768Speter 					fmt = 'E';
404768Speter 					break;
405768Speter 				case CONWIDTH + CONPREC:
406768Speter 				case CONWIDTH + VARPREC:
407768Speter 					if (--field < 1)
408768Speter 						field = 1;
409768Speter 				}
410768Speter 				format[0] = ' ';
411768Speter 				fmtstart = 0;
412768Speter 				break;
413768Speter 			case TSTR:
414768Speter 				constval( alv );
415768Speter 				switch ( classify( con.ctype ) ) {
416768Speter 				    case TCHAR:
417768Speter 					typ = TCHAR;
418768Speter 					goto tchar;
419768Speter 				    case TSTR:
420768Speter 					strptr = con.cpval;
421768Speter 					for (strnglen = 0;  *strptr++;  strnglen++) /* void */;
422768Speter 					strptr = con.cpval;
423768Speter 					break;
424768Speter 				    default:
425768Speter 					strnglen = width(ap);
426768Speter 					break;
427768Speter 				}
428768Speter 				fmt = 's';
429768Speter 				strfmt = fmtspec;
430768Speter 				if (fmtspec == NIL) {
431768Speter 					fmtspec = SKIP;
432768Speter 					break;
433768Speter 				}
434768Speter 				if (fmtspec & CONWIDTH) {
435768Speter 					if (field <= strnglen) {
436768Speter 						fmtspec = SKIP;
437768Speter 						break;
438768Speter 					} else
439768Speter 						field -= strnglen;
440768Speter 				}
441768Speter 				/*
442768Speter 				 * push string to implement leading blank padding
443768Speter 				 */
444768Speter 				put(2, O_LVCON, 2);
445768Speter 				putstr("", 0);
446768Speter 				stkcnt++;
447768Speter 				break;
448768Speter 			default:
449768Speter 				error("Can't write %ss to a text file", clnames[typ]);
450768Speter 				continue;
451768Speter 			}
452768Speter 			/*
453768Speter 			 * If there is a variable precision, evaluate it onto
454768Speter 			 * the stack
455768Speter 			 */
456768Speter 			if (fmtspec & VARPREC) {
457768Speter 				ap = stkrval(al[3], NIL , RREQ );
458768Speter 				if (ap == NIL)
459768Speter 					continue;
460768Speter 				if (isnta(ap,"i")) {
461768Speter 					error("Second write width must be integer, not %s", nameof(ap));
462768Speter 					continue;
463768Speter 				}
464768Speter 				if ( opt( 't' ) ) {
465768Speter 				    put(3, O_MAX, 0, 0);
466768Speter 				}
467768Speter 				stkcnt++;
468768Speter 			}
469768Speter 			/*
470768Speter 			 * If there is a variable width, evaluate it onto
471768Speter 			 * the stack
472768Speter 			 */
473768Speter 			if (fmtspec & VARWIDTH) {
474768Speter 				if ( ( typ == TDOUBLE && fmtspec == VARWIDTH )
475768Speter 				    || typ == TSTR ) {
476768Speter 					i = sizes[cbn].om_off -= sizeof(int);
477768Speter 					if (i < sizes[cbn].om_max)
478768Speter 						sizes[cbn].om_max = i;
479768Speter 					put(2, O_LV | cbn << 8 + INDX, i);
480768Speter 				}
481768Speter 				ap = stkrval(al[2], NIL , RREQ );
482768Speter 				if (ap == NIL)
483768Speter 					continue;
484768Speter 				if (isnta(ap,"i")) {
485768Speter 					error("First write width must be integer, not %s", nameof(ap));
486768Speter 					continue;
487768Speter 				}
488768Speter 				stkcnt++;
489768Speter 				/*
490768Speter 				 * Perform special processing on widths based
491768Speter 				 * on data type
492768Speter 				 */
493768Speter 				switch (typ) {
494768Speter 				case TDOUBLE:
495768Speter 					if (fmtspec == VARWIDTH) {
496768Speter 						fmt = 'E';
497768Speter 						put(1, O_AS4);
498768Speter 						put(2, O_RV4 | cbn << 8 + INDX, i);
499768Speter 						put(3, O_MAX, 8, 1);
500768Speter 						put(2, O_RV4 | cbn << 8 + INDX, i);
501768Speter 						stkcnt++;
502768Speter 						fmtspec += VARPREC;
503768Speter 					}
504768Speter 					put(3, O_MAX, 1, 1);
505768Speter 					break;
506768Speter 				case TSTR:
507768Speter 					put(1, O_AS4);
508768Speter 					put(2, O_RV4 | cbn << 8 + INDX, i);
509768Speter 					put(3, O_MAX, strnglen, 0);
510768Speter 					break;
511768Speter 				default:
512768Speter 					if ( opt( 't' ) ) {
513768Speter 					    put(3, O_MAX, 0, 0);
514768Speter 					}
515768Speter 					break;
516768Speter 				}
517768Speter 			}
518768Speter 			/*
519768Speter 			 * Generate the format string
520768Speter 			 */
521768Speter 			switch (fmtspec) {
522768Speter 			default:
523768Speter 				panic("fmt2");
524768Speter 			case SKIP:
525768Speter 				break;
526*2073Smckusic 			case NIL:
527*2073Smckusic 				sprintf(&format[1], "%%%c", fmt);
528*2073Smckusic 				goto fmtgen;
529768Speter 			case CONWIDTH:
530768Speter 				sprintf(&format[1], "%%%1D%c", field, fmt);
531768Speter 				goto fmtgen;
532768Speter 			case VARWIDTH:
533768Speter 				sprintf(&format[1], "%%*%c", fmt);
534768Speter 				goto fmtgen;
535768Speter 			case CONWIDTH + CONPREC:
536768Speter 				sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt);
537768Speter 				goto fmtgen;
538768Speter 			case CONWIDTH + VARPREC:
539768Speter 				sprintf(&format[1], "%%%1D.*%c", field, fmt);
540768Speter 				goto fmtgen;
541768Speter 			case VARWIDTH + CONPREC:
542768Speter 				sprintf(&format[1], "%%*.%1D%c", prec, fmt);
543768Speter 				goto fmtgen;
544768Speter 			case VARWIDTH + VARPREC:
545768Speter 				sprintf(&format[1], "%%*.*%c", fmt);
546768Speter 			fmtgen:
547768Speter 				fmtlen = lenstr(&format[fmtstart], 0);
548768Speter 				put(2, O_LVCON, fmtlen);
549768Speter 				putstr(&format[fmtstart], 0);
550768Speter 				put(1, O_FILE);
551768Speter 				stkcnt += 2;
552768Speter 				put(2, O_WRITEF, stkcnt);
553768Speter 			}
554768Speter 			/*
555768Speter 			 * Write the string after its blank padding
556768Speter 			 */
557768Speter 			if (typ == TSTR) {
558768Speter 				put(1, O_FILE);
559768Speter 				put(2, O_CON24, 1);
560768Speter 				if (strfmt & VARWIDTH) {
561768Speter 					put(2, O_RV4 | cbn << 8 + INDX , i );
562768Speter 					put(2, O_MIN, strnglen);
563768Speter 				} else {
564768Speter 					if ((fmtspec & SKIP) &&
565768Speter 					   (strfmt & CONWIDTH)) {
566768Speter 						strnglen = field;
567768Speter 					}
568768Speter 					put(2, O_CON24, strnglen);
569768Speter 				}
570768Speter 				ap = stkrval(alv, NIL , RREQ );
571768Speter 				put(1, O_WRITES);
572768Speter 			}
573768Speter 		}
574768Speter 		/*
575768Speter 		 * Done with arguments.
576768Speter 		 * Handle writeln and
577768Speter 		 * insufficent number of args.
578768Speter 		 */
579768Speter 		switch (p->value[0] &~ NSTAND) {
580768Speter 			case O_WRITEF:
581768Speter 				if (argc == 0)
582768Speter 					error("Write requires an argument");
583768Speter 				break;
584768Speter 			case O_MESSAGE:
585768Speter 				if (argc == 0)
586768Speter 					error("Message requires an argument");
587768Speter 			case O_WRITLN:
588768Speter 				if (filetype != nl+T1CHAR)
589768Speter 					error("Can't 'writeln' a non text file");
590768Speter 				put(1, O_WRITLN);
591768Speter 				break;
592768Speter 		}
593768Speter 		return;
594768Speter 
595768Speter 	case O_READ4:
596768Speter 	case O_READLN:
597768Speter 		/*
598768Speter 		 * Set up default
599768Speter 		 * file "input".
600768Speter 		 */
601768Speter 		file = NIL;
602768Speter 		filetype = nl+T1CHAR;
603768Speter 		/*
604768Speter 		 * Determine the file implied
605768Speter 		 * for the read and generate
606768Speter 		 * code to make it the active file.
607768Speter 		 */
608768Speter 		if (argv != NIL) {
609768Speter 			codeoff();
610768Speter 			ap = stkrval(argv[1], NIL , RREQ );
611768Speter 			codeon();
612768Speter 			if (ap == NIL)
613768Speter 				argv = argv[2];
614768Speter 			if (ap != NIL && ap->class == FILET) {
615768Speter 				/*
616768Speter 				 * Got "read(f, ...", make
617768Speter 				 * f the active file, and save
618768Speter 				 * it and its type for use in
619768Speter 				 * processing the rest of the
620768Speter 				 * arguments to read.
621768Speter 				 */
622768Speter 				file = argv[1];
623768Speter 				filetype = ap->type;
624*2073Smckusic 				stklval(argv[1], NIL , LREQ );
625768Speter 				put(1, O_UNIT);
626768Speter 				argv = argv[2];
627768Speter 				argc--;
628768Speter 			} else {
629768Speter 				/*
630768Speter 				 * Default is read from
631768Speter 				 * standard input.
632768Speter 				 */
633768Speter 				put(1, O_UNITINP);
634768Speter 				input->nl_flags |= NUSED;
635768Speter 			}
636768Speter 		} else {
637768Speter 			put(1, O_UNITINP);
638768Speter 			input->nl_flags |= NUSED;
639768Speter 		}
640768Speter 		/*
641768Speter 		 * Loop and process each
642768Speter 		 * of the arguments.
643768Speter 		 */
644768Speter 		for (; argv != NIL; argv = argv[2]) {
645768Speter 			/*
646768Speter 			 * Get the address of the target
647768Speter 			 * on the stack.
648768Speter 			 */
649768Speter 			al = argv[1];
650768Speter 			if (al == NIL)
651768Speter 				continue;
652768Speter 			if (al[0] != T_VAR) {
653768Speter 				error("Arguments to %s must be variables, not expressions", p->symbol);
654768Speter 				continue;
655768Speter 			}
656768Speter 			ap = stklval(al, MOD|ASGN|NOUSE);
657768Speter 			if (ap == NIL)
658768Speter 				continue;
659768Speter 			if (filetype != nl+T1CHAR) {
660768Speter 				/*
661768Speter 				 * Generalized read, i.e.
662768Speter 				 * from a non-textfile.
663768Speter 				 */
664768Speter 				if (incompat(filetype, ap, argv[1] )) {
665768Speter 					error("Type mismatch in read from non-text file");
666768Speter 					continue;
667768Speter 				}
668768Speter 				/*
669768Speter 				 * var := file ^;
670768Speter 				 */
671768Speter 				if (file != NIL)
672*2073Smckusic 					stklval(file, NIL , LREQ );
673768Speter 				else /* Magic */
674*2073Smckusic 					put(2, PTR_RV, input->value[0]);
675768Speter 				put(1, O_FNIL);
676768Speter 				put(2, O_IND, width(filetype));
677768Speter 				convert(filetype, ap);
678768Speter 				if (isa(ap, "bsci"))
679768Speter 					rangechk(ap, ap);
680768Speter 				put(2, O_AS, width(ap));
681768Speter 				/*
682768Speter 				 * get(file);
683768Speter 				 */
684768Speter 				put(1, O_GET);
685768Speter 				continue;
686768Speter 			}
687768Speter 			typ = classify(ap);
688768Speter 			op = rdops(typ);
689768Speter 			if (op == NIL) {
690768Speter 				error("Can't read %ss from a text file", clnames[typ]);
691768Speter 				continue;
692768Speter 			}
693768Speter 			if (op != O_READE)
694768Speter 				put(1, op);
695768Speter 			else {
696768Speter 				put(2, op, listnames(ap));
6971628Speter 				warning();
698768Speter 				if (opt('s')) {
699768Speter 					standard();
700768Speter 				}
7011628Speter 				error("Reading scalars from text files is non-standard");
702768Speter 			}
703768Speter 			/*
704768Speter 			 * Data read is on the stack.
705768Speter 			 * Assign it.
706768Speter 			 */
707768Speter 			if (op != O_READ8 && op != O_READE)
708768Speter 				rangechk(ap, op == O_READC ? ap : nl+T4INT);
709768Speter 			gen(O_AS2, O_AS2, width(ap),
710768Speter 				op == O_READ8 ? 8 : op == O_READ4 ? 4 : 2);
711768Speter 		}
712768Speter 		/*
713768Speter 		 * Done with arguments.
714768Speter 		 * Handle readln and
715768Speter 		 * insufficient number of args.
716768Speter 		 */
717768Speter 		if (p->value[0] == O_READLN) {
718768Speter 			if (filetype != nl+T1CHAR)
719768Speter 				error("Can't 'readln' a non text file");
720768Speter 			put(1, O_READLN);
721768Speter 		}
722768Speter 		else if (argc == 0)
723768Speter 			error("read requires an argument");
724768Speter 		return;
725768Speter 
726768Speter 	case O_GET:
727768Speter 	case O_PUT:
728768Speter 		if (argc != 1) {
729768Speter 			error("%s expects one argument", p->symbol);
730768Speter 			return;
731768Speter 		}
732*2073Smckusic 		ap = stklval(argv[1], NIL , LREQ );
733768Speter 		if (ap == NIL)
734768Speter 			return;
735768Speter 		if (ap->class != FILET) {
736768Speter 			error("Argument to %s must be a file, not %s", p->symbol, nameof(ap));
737768Speter 			return;
738768Speter 		}
739768Speter 		put(1, O_UNIT);
740768Speter 		put(1, op);
741768Speter 		return;
742768Speter 
743768Speter 	case O_RESET:
744768Speter 	case O_REWRITE:
745768Speter 		if (argc == 0 || argc > 2) {
746768Speter 			error("%s expects one or two arguments", p->symbol);
747768Speter 			return;
748768Speter 		}
749768Speter 		if (opt('s') && argc == 2) {
750768Speter 			standard();
751768Speter 			error("Two argument forms of reset and rewrite are non-standard");
752768Speter 		}
753*2073Smckusic 		codeoff();
754768Speter 		ap = stklval(argv[1], MOD|NOUSE);
755*2073Smckusic 		codeon();
756768Speter 		if (ap == NIL)
757768Speter 			return;
758768Speter 		if (ap->class != FILET) {
759768Speter 			error("First argument to %s must be a file, not %s", p->symbol, nameof(ap));
760768Speter 			return;
761768Speter 		}
762*2073Smckusic 		put(2, O_CON24, text(ap) ? 0: width(ap->type));
763768Speter 		if (argc == 2) {
764768Speter 			/*
765768Speter 			 * Optional second argument
766768Speter 			 * is a string name of a
767768Speter 			 * UNIX (R) file to be associated.
768768Speter 			 */
769768Speter 			al = argv[2];
770*2073Smckusic 			codeoff();
771768Speter 			al = stkrval(al[1], NOFLAGS , RREQ );
772*2073Smckusic 			codeon();
773768Speter 			if (al == NIL)
774768Speter 				return;
775768Speter 			if (classify(al) != TSTR) {
776768Speter 				error("Second argument to %s must be a string, not %s", p->symbol, nameof(al));
777768Speter 				return;
778768Speter 			}
779*2073Smckusic 			put(2, O_CON24, width(al));
780*2073Smckusic 			al = argv[2];
781*2073Smckusic 			al = stkrval(al[1], NOFLAGS , RREQ );
782768Speter 		} else {
783*2073Smckusic 			put(2, O_CON24, 0);
784768Speter 			put(2, O_CON24, NIL);
785768Speter 		}
786*2073Smckusic 		ap = stklval(argv[1], MOD|NOUSE);
787768Speter 		put(1, op);
788768Speter 		return;
789768Speter 
790768Speter 	case O_NEW:
791768Speter 	case O_DISPOSE:
792768Speter 		if (argc == 0) {
793768Speter 			error("%s expects at least one argument", p->symbol);
794768Speter 			return;
795768Speter 		}
796768Speter 		ap = stklval(argv[1], op == O_NEW ? ( MOD | NOUSE ) : MOD );
797768Speter 		if (ap == NIL)
798768Speter 			return;
799768Speter 		if (ap->class != PTR) {
800768Speter 			error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap));
801768Speter 			return;
802768Speter 		}
803768Speter 		ap = ap->type;
804768Speter 		if (ap == NIL)
805768Speter 			return;
806768Speter 		argv = argv[2];
807768Speter 		if (argv != NIL) {
808768Speter 			if (ap->class != RECORD) {
809768Speter 				error("Record required when specifying variant tags");
810768Speter 				return;
811768Speter 			}
812768Speter 			for (; argv != NIL; argv = argv[2]) {
813768Speter 				if (ap->ptr[NL_VARNT] == NIL) {
814768Speter 					error("Too many tag fields");
815768Speter 					return;
816768Speter 				}
817768Speter 				if (!isconst(argv[1])) {
818768Speter 					error("Second and successive arguments to %s must be constants", p->symbol);
819768Speter 					return;
820768Speter 				}
821768Speter 				gconst(argv[1]);
822768Speter 				if (con.ctype == NIL)
823768Speter 					return;
824768Speter 				if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) {
825768Speter 					cerror("Specified tag constant type clashed with variant case selector type");
826768Speter 					return;
827768Speter 				}
828768Speter 				for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain)
829768Speter 					if (ap->range[0] == con.crval)
830768Speter 						break;
831768Speter 				if (ap == NIL) {
832768Speter 					error("No variant case label value equals specified constant value");
833768Speter 					return;
834768Speter 				}
835768Speter 				ap = ap->ptr[NL_VTOREC];
836768Speter 			}
837768Speter 		}
838768Speter 		put(2, op, width(ap));
839768Speter 		return;
840768Speter 
841768Speter 	case O_DATE:
842768Speter 	case O_TIME:
843768Speter 		if (argc != 1) {
844768Speter 			error("%s expects one argument", p->symbol);
845768Speter 			return;
846768Speter 		}
847768Speter 		ap = stklval(argv[1], MOD|NOUSE);
848768Speter 		if (ap == NIL)
849768Speter 			return;
850768Speter 		if (classify(ap) != TSTR || width(ap) != 10) {
851768Speter 			error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap));
852768Speter 			return;
853768Speter 		}
854768Speter 		put(1, op);
855768Speter 		return;
856768Speter 
857768Speter 	case O_HALT:
858768Speter 		if (argc != 0) {
859768Speter 			error("halt takes no arguments");
860768Speter 			return;
861768Speter 		}
862768Speter 		put(1, op);
863768Speter 		noreach = 1;
864768Speter 		return;
865768Speter 
866768Speter 	case O_ARGV:
867768Speter 		if (argc != 2) {
868768Speter 			error("argv takes two arguments");
869768Speter 			return;
870768Speter 		}
871768Speter 		ap = stkrval(argv[1], NIL , RREQ );
872768Speter 		if (ap == NIL)
873768Speter 			return;
874768Speter 		if (isnta(ap, "i")) {
875768Speter 			error("argv's first argument must be an integer, not %s", nameof(ap));
876768Speter 			return;
877768Speter 		}
878768Speter 		al = argv[2];
879768Speter 		ap = stklval(al[1], MOD|NOUSE);
880768Speter 		if (ap == NIL)
881768Speter 			return;
882768Speter 		if (classify(ap) != TSTR) {
883768Speter 			error("argv's second argument must be a string, not %s", nameof(ap));
884768Speter 			return;
885768Speter 		}
886768Speter 		put(2, op, width(ap));
887768Speter 		return;
888768Speter 
889768Speter 	case O_STLIM:
890768Speter 		if (argc != 1) {
891768Speter 			error("stlimit requires one argument");
892768Speter 			return;
893768Speter 		}
894768Speter 		ap = stkrval(argv[1], NIL , RREQ );
895768Speter 		if (ap == NIL)
896768Speter 			return;
897768Speter 		if (isnta(ap, "i")) {
898768Speter 			error("stlimit's argument must be an integer, not %s", nameof(ap));
899768Speter 			return;
900768Speter 		}
901768Speter 		if (width(ap) != 4)
902768Speter 			put(1, O_STOI);
903768Speter 		put(1, op);
904768Speter 		return;
905768Speter 
906768Speter 	case O_REMOVE:
907768Speter 		if (argc != 1) {
908768Speter 			error("remove expects one argument");
909768Speter 			return;
910768Speter 		}
911*2073Smckusic 		codeoff();
912768Speter 		ap = stkrval(argv[1], NOFLAGS , RREQ );
913*2073Smckusic 		codeon();
914768Speter 		if (ap == NIL)
915768Speter 			return;
916768Speter 		if (classify(ap) != TSTR) {
917768Speter 			error("remove's argument must be a string, not %s", nameof(ap));
918768Speter 			return;
919768Speter 		}
920768Speter 		put(2, O_CON24, width(ap));
921*2073Smckusic 		ap = stkrval(argv[1], NOFLAGS , RREQ );
922768Speter 		put(1, op);
923768Speter 		return;
924768Speter 
925768Speter 	case O_LLIMIT:
926768Speter 		if (argc != 2) {
927768Speter 			error("linelimit expects two arguments");
928768Speter 			return;
929768Speter 		}
930768Speter 		al = argv[2];
931768Speter 		ap = stkrval(al[1], NIL , RREQ );
932768Speter 		if (ap == NIL)
933768Speter 			return;
934768Speter 		if (isnta(ap, "i")) {
935768Speter 			error("linelimit's second argument must be an integer, not %s", nameof(ap));
936768Speter 			return;
937768Speter 		}
938*2073Smckusic 		ap = stklval(argv[1], NOFLAGS|NOUSE);
939*2073Smckusic 		if (ap == NIL)
940*2073Smckusic 			return;
941*2073Smckusic 		if (!text(ap)) {
942*2073Smckusic 			error("linelimit's first argument must be a text file, not %s", nameof(ap));
943*2073Smckusic 			return;
944*2073Smckusic 		}
945768Speter 		put(1, op);
946768Speter 		return;
947768Speter 	case O_PAGE:
948768Speter 		if (argc != 1) {
949768Speter 			error("page expects one argument");
950768Speter 			return;
951768Speter 		}
952*2073Smckusic 		ap = stklval(argv[1], NIL , LREQ );
953768Speter 		if (ap == NIL)
954768Speter 			return;
955768Speter 		if (!text(ap)) {
956768Speter 			error("Argument to page must be a text file, not %s", nameof(ap));
957768Speter 			return;
958768Speter 		}
959768Speter 		put(1, O_UNIT);
960768Speter 		put(1, op);
961768Speter 		return;
962768Speter 
963768Speter 	case O_PACK:
964768Speter 		if (argc != 3) {
965768Speter 			error("pack expects three arguments");
966768Speter 			return;
967768Speter 		}
968768Speter 		pu = "pack(a,i,z)";
969768Speter 		pua = (al = argv)[1];
970768Speter 		pui = (al = al[2])[1];
971768Speter 		puz = (al = al[2])[1];
972768Speter 		goto packunp;
973768Speter 	case O_UNPACK:
974768Speter 		if (argc != 3) {
975768Speter 			error("unpack expects three arguments");
976768Speter 			return;
977768Speter 		}
978768Speter 		pu = "unpack(z,a,i)";
979768Speter 		puz = (al = argv)[1];
980768Speter 		pua = (al = al[2])[1];
981768Speter 		pui = (al = al[2])[1];
982768Speter packunp:
983*2073Smckusic 		codeoff();
984768Speter 		ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE);
985*2073Smckusic 		al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE);
986*2073Smckusic 		codeon();
987768Speter 		if (ap == NIL)
988768Speter 			return;
989768Speter 		if (ap->class != ARRAY) {
990768Speter 			error("%s requires a to be an unpacked array, not %s", pu, nameof(ap));
991768Speter 			return;
992768Speter 		}
993768Speter 		if (al->class != ARRAY) {
994768Speter 			error("%s requires z to be a packed array, not %s", pu, nameof(ap));
995768Speter 			return;
996768Speter 		}
997768Speter 		if (al->type == NIL || ap->type == NIL)
998768Speter 			return;
999768Speter 		if (al->type != ap->type) {
1000768Speter 			error("%s requires a and z to be arrays of the same type", pu, nameof(ap));
1001768Speter 			return;
1002768Speter 		}
1003768Speter 		k = width(al);
1004768Speter 		itemwidth = width(ap->type);
1005768Speter 		ap = ap->chain;
1006768Speter 		al = al->chain;
1007768Speter 		if (ap->chain != NIL || al->chain != NIL) {
1008768Speter 			error("%s requires a and z to be single dimension arrays", pu);
1009768Speter 			return;
1010768Speter 		}
1011768Speter 		if (ap == NIL || al == NIL)
1012768Speter 			return;
1013768Speter 		/*
1014768Speter 		 * al is the range for z i.e. u..v
1015768Speter 		 * ap is the range for a i.e. m..n
1016768Speter 		 * i will be n-m+1
1017768Speter 		 * j will be v-u+1
1018768Speter 		 */
1019768Speter 		i = ap->range[1] - ap->range[0] + 1;
1020768Speter 		j = al->range[1] - al->range[0] + 1;
1021768Speter 		if (i < j) {
1022768Speter 			error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i);
1023768Speter 			return;
1024768Speter 		}
1025768Speter 		/*
1026768Speter 		 * get n-m-(v-u) and m for the interpreter
1027768Speter 		 */
1028768Speter 		i -= j;
1029768Speter 		j = ap->range[0];
1030*2073Smckusic 		put(2, O_CON24, k);
1031*2073Smckusic 		put(2, O_CON24, i);
1032*2073Smckusic 		put(2, O_CON24, j);
1033*2073Smckusic 		put(2, O_CON24, itemwidth);
1034*2073Smckusic 		al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE);
1035*2073Smckusic 		ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE);
1036*2073Smckusic 		ap = stkrval((int *) pui, NLNIL , RREQ );
1037*2073Smckusic 		if (ap == NIL)
1038*2073Smckusic 			return;
1039*2073Smckusic 		put(1, op);
1040768Speter 		return;
1041768Speter 	case 0:
1042768Speter 		error("%s is an unimplemented 6400 extension", p->symbol);
1043768Speter 		return;
1044768Speter 
1045768Speter 	default:
1046768Speter 		panic("proc case");
1047768Speter 	}
1048768Speter }
1049768Speter #endif OBJ
1050