xref: /csrg-svn/usr.bin/pascal/src/proc.c (revision 3226)
1768Speter /* Copyright (c) 1979 Regents of the University of California */
2768Speter 
3*3226Smckusic static char sccsid[] = "@(#)proc.c 1.8 03/11/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;
54*3226Smckusic 	struct tmps soffset;
55768Speter 
56768Speter #define	CONPREC 4
57768Speter #define	VARPREC 8
58768Speter #define	CONWIDTH 1
59768Speter #define	VARWIDTH 2
60768Speter #define SKIP 16
61768Speter 
62768Speter 	/*
63768Speter 	 * Verify that the name is
64768Speter 	 * defined and is that of a
65768Speter 	 * procedure.
66768Speter 	 */
67768Speter 	p = lookup(r[2]);
68768Speter 	if (p == NIL) {
69768Speter 		rvlist(r[3]);
70768Speter 		return;
71768Speter 	}
721198Speter 	if (p->class != PROC && p->class != FPROC) {
73768Speter 		error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]);
74768Speter 		rvlist(r[3]);
75768Speter 		return;
76768Speter 	}
77768Speter 	argv = r[3];
78768Speter 
79768Speter 	/*
80768Speter 	 * Call handles user defined
81768Speter 	 * procedures and functions.
82768Speter 	 */
83768Speter 	if (bn != 0) {
84768Speter 		call(p, argv, PROC, bn);
85768Speter 		return;
86768Speter 	}
87768Speter 
88768Speter 	/*
89768Speter 	 * Call to built-in procedure.
90768Speter 	 * Count the arguments.
91768Speter 	 */
92768Speter 	argc = 0;
93768Speter 	for (al = argv; al != NIL; al = al[2])
94768Speter 		argc++;
95768Speter 
96768Speter 	/*
97768Speter 	 * Switch on the operator
98768Speter 	 * associated with the built-in
99768Speter 	 * procedure in the namelist
100768Speter 	 */
101768Speter 	op = p->value[0] &~ NSTAND;
102768Speter 	if (opt('s') && (p->value[0] & NSTAND)) {
103768Speter 		standard();
104768Speter 		error("%s is a nonstandard procedure", p->symbol);
105768Speter 	}
106768Speter 	switch (op) {
107768Speter 
108768Speter 	case O_ABORT:
109768Speter 		if (argc != 0)
110768Speter 			error("null takes no arguments");
111768Speter 		return;
112768Speter 
113768Speter 	case O_FLUSH:
114768Speter 		if (argc == 0) {
115768Speter 			put(1, O_MESSAGE);
116768Speter 			return;
117768Speter 		}
118768Speter 		if (argc != 1) {
119768Speter 			error("flush takes at most one argument");
120768Speter 			return;
121768Speter 		}
1222073Smckusic 		ap = stklval(argv[1], NIL , LREQ );
123768Speter 		if (ap == NIL)
124768Speter 			return;
125768Speter 		if (ap->class != FILET) {
126768Speter 			error("flush's argument must be a file, not %s", nameof(ap));
127768Speter 			return;
128768Speter 		}
129768Speter 		put(1, op);
130768Speter 		return;
131768Speter 
132768Speter 	case O_MESSAGE:
133768Speter 	case O_WRITEF:
134768Speter 	case O_WRITLN:
135768Speter 		/*
136768Speter 		 * Set up default file "output"'s type
137768Speter 		 */
138768Speter 		file = NIL;
139768Speter 		filetype = nl+T1CHAR;
140768Speter 		/*
141768Speter 		 * Determine the file implied
142768Speter 		 * for the write and generate
143768Speter 		 * code to make it the active file.
144768Speter 		 */
145768Speter 		if (op == O_MESSAGE) {
146768Speter 			/*
147768Speter 			 * For message, all that matters
148768Speter 			 * is that the filetype is
149768Speter 			 * a character file.
150768Speter 			 * Thus "output" will suit us fine.
151768Speter 			 */
152768Speter 			put(1, O_MESSAGE);
153768Speter 		} else if (argv != NIL && (al = argv[1])[0] != T_WEXP) {
154768Speter 			/*
155768Speter 			 * If there is a first argument which has
156768Speter 			 * no write widths, then it is potentially
157768Speter 			 * a file name.
158768Speter 			 */
159768Speter 			codeoff();
160768Speter 			ap = stkrval(argv[1], NIL , RREQ );
161768Speter 			codeon();
162768Speter 			if (ap == NIL)
163768Speter 				argv = argv[2];
164768Speter 			if (ap != NIL && ap->class == FILET) {
165768Speter 				/*
166768Speter 				 * Got "write(f, ...", make
167768Speter 				 * f the active file, and save
168768Speter 				 * it and its type for use in
169768Speter 				 * processing the rest of the
170768Speter 				 * arguments to write.
171768Speter 				 */
172768Speter 				file = argv[1];
173768Speter 				filetype = ap->type;
1742073Smckusic 				stklval(argv[1], NIL , LREQ );
175768Speter 				put(1, O_UNIT);
176768Speter 				/*
177768Speter 				 * Skip over the first argument
178768Speter 				 */
179768Speter 				argv = argv[2];
180768Speter 				argc--;
181768Speter 			} else
182768Speter 				/*
183768Speter 				 * Set up for writing on
184768Speter 				 * standard output.
185768Speter 				 */
186768Speter 				put(1, O_UNITOUT);
187768Speter 		} else
188768Speter 			put(1, O_UNITOUT);
189768Speter 		/*
190768Speter 		 * Loop and process each
191768Speter 		 * of the arguments.
192768Speter 		 */
193768Speter 		for (; argv != NIL; argv = argv[2]) {
194768Speter 			/*
195768Speter 			 * fmtspec indicates the type (CONstant or VARiable)
196768Speter 			 *	and number (none, WIDTH, and/or PRECision)
197768Speter 			 *	of the fields in the printf format for this
198768Speter 			 *	output variable.
1993172Smckusic 			 * stkcnt is the number of bytes pushed on the stack
200768Speter 			 * fmt is the format output indicator (D, E, F, O, X, S)
201768Speter 			 * fmtstart = 0 for leading blank; = 1 for no blank
202768Speter 			 */
203768Speter 			fmtspec = NIL;
204768Speter 			stkcnt = 0;
205768Speter 			fmt = 'D';
206768Speter 			fmtstart = 1;
207768Speter 			al = argv[1];
208768Speter 			if (al == NIL)
209768Speter 				continue;
210768Speter 			if (al[0] == T_WEXP)
211768Speter 				alv = al[1];
212768Speter 			else
213768Speter 				alv = al;
214768Speter 			if (alv == NIL)
215768Speter 				continue;
216768Speter 			codeoff();
217768Speter 			ap = stkrval(alv, NIL , RREQ );
218768Speter 			codeon();
219768Speter 			if (ap == NIL)
220768Speter 				continue;
221768Speter 			typ = classify(ap);
222768Speter 			if (al[0] == T_WEXP) {
223768Speter 				/*
224768Speter 				 * Handle width expressions.
225768Speter 				 * The basic game here is that width
226768Speter 				 * expressions get evaluated. If they
227768Speter 				 * are constant, the value is placed
228768Speter 				 * directly in the format string.
229768Speter 				 * Otherwise the value is pushed onto
230768Speter 				 * the stack and an indirection is
231768Speter 				 * put into the format string.
232768Speter 				 */
233768Speter 				if (al[3] == OCT)
234768Speter 					fmt = 'O';
235768Speter 				else if (al[3] == HEX)
236768Speter 					fmt = 'X';
237768Speter 				else if (al[3] != NIL) {
238768Speter 					/*
239768Speter 					 * Evaluate second format spec
240768Speter 					 */
241768Speter 					if ( constval(al[3])
242768Speter 					    && isa( con.ctype , "i" ) ) {
243768Speter 						fmtspec += CONPREC;
244768Speter 						prec = con.crval;
245768Speter 					} else {
246768Speter 						fmtspec += VARPREC;
247768Speter 					}
248768Speter 					fmt = 'f';
249768Speter 					switch ( typ ) {
250768Speter 					case TINT:
251768Speter 						if ( opt( 's' ) ) {
252768Speter 						    standard();
253768Speter 						    error("Writing %ss with two write widths is non-standard", clnames[typ]);
254768Speter 						}
255768Speter 						/* and fall through */
256768Speter 					case TDOUBLE:
257768Speter 						break;
258768Speter 					default:
259768Speter 						error("Cannot write %ss with two write widths", clnames[typ]);
260768Speter 						continue;
261768Speter 					}
262768Speter 				}
263768Speter 				/*
264768Speter 				 * Evaluate first format spec
265768Speter 				 */
266768Speter 				if (al[2] != NIL) {
267768Speter 					if ( constval(al[2])
268768Speter 					    && isa( con.ctype , "i" ) ) {
269768Speter 						fmtspec += CONWIDTH;
270768Speter 						field = con.crval;
271768Speter 					} else {
272768Speter 						fmtspec += VARWIDTH;
273768Speter 					}
274768Speter 				}
275768Speter 				if ((fmtspec & CONPREC) && prec < 0 ||
276768Speter 				    (fmtspec & CONWIDTH) && field < 0) {
277768Speter 					error("Negative widths are not allowed");
278768Speter 					continue;
279768Speter 				}
2803179Smckusic 				if ( opt('s') &&
2813179Smckusic 				    ((fmtspec & CONPREC) && prec == 0 ||
2823179Smckusic 				    (fmtspec & CONWIDTH) && field == 0)) {
2833179Smckusic 					standard();
2843179Smckusic 					error("Zero widths are non-standard");
2853179Smckusic 				}
286768Speter 			}
287768Speter 			if (filetype != nl+T1CHAR) {
288768Speter 				if (fmt == 'O' || fmt == 'X') {
289768Speter 					error("Oct/hex allowed only on text files");
290768Speter 					continue;
291768Speter 				}
292768Speter 				if (fmtspec) {
293768Speter 					error("Write widths allowed only on text files");
294768Speter 					continue;
295768Speter 				}
296768Speter 				/*
297768Speter 				 * Generalized write, i.e.
298768Speter 				 * to a non-textfile.
299768Speter 				 */
3002073Smckusic 				stklval(file, NIL , LREQ );
301768Speter 				put(1, O_FNIL);
302768Speter 				/*
303768Speter 				 * file^ := ...
304768Speter 				 */
305768Speter 				ap = rvalue(argv[1], NIL);
306768Speter 				if (ap == NIL)
307768Speter 					continue;
308768Speter 				if (incompat(ap, filetype, argv[1])) {
309768Speter 					cerror("Type mismatch in write to non-text file");
310768Speter 					continue;
311768Speter 				}
312768Speter 				convert(ap, filetype);
313768Speter 				put(2, O_AS, width(filetype));
314768Speter 				/*
315768Speter 				 * put(file)
316768Speter 				 */
317768Speter 				put(1, O_PUT);
318768Speter 				continue;
319768Speter 			}
320768Speter 			/*
321768Speter 			 * Write to a textfile
322768Speter 			 *
323768Speter 			 * Evaluate the expression
324768Speter 			 * to be written.
325768Speter 			 */
326768Speter 			if (fmt == 'O' || fmt == 'X') {
327768Speter 				if (opt('s')) {
328768Speter 					standard();
329768Speter 					error("Oct and hex are non-standard");
330768Speter 				}
331768Speter 				if (typ == TSTR || typ == TDOUBLE) {
332768Speter 					error("Can't write %ss with oct/hex", clnames[typ]);
333768Speter 					continue;
334768Speter 				}
335768Speter 				if (typ == TCHAR || typ == TBOOL)
336768Speter 					typ = TINT;
337768Speter 			}
338768Speter 			/*
339768Speter 			 * Place the arguement on the stack. If there is
340768Speter 			 * no format specified by the programmer, implement
341768Speter 			 * the default.
342768Speter 			 */
343768Speter 			switch (typ) {
344768Speter 			case TINT:
345768Speter 				if (fmt != 'f') {
346768Speter 					ap = stkrval(alv, NIL , RREQ );
3473172Smckusic 					stkcnt += sizeof(long);
348768Speter 				} else {
349768Speter 					ap = stkrval(alv, NIL , RREQ );
350768Speter 					put(1, O_ITOD);
3513172Smckusic 					stkcnt += sizeof(double);
352768Speter 					typ = TDOUBLE;
353768Speter 					goto tdouble;
354768Speter 				}
355768Speter 				if (fmtspec == NIL) {
356768Speter 					if (fmt == 'D')
357768Speter 						field = 10;
358768Speter 					else if (fmt == 'X')
359768Speter 						field = 8;
360768Speter 					else if (fmt == 'O')
361768Speter 						field = 11;
362768Speter 					else
363768Speter 						panic("fmt1");
364768Speter 					fmtspec = CONWIDTH;
365768Speter 				}
366768Speter 				break;
367768Speter 			case TCHAR:
368768Speter 			     tchar:
3692073Smckusic 				if (fmtspec == NIL) {
3702073Smckusic 					put(1, O_FILE);
3712073Smckusic 					ap = stkrval(alv, NIL , RREQ );
3723172Smckusic 					convert(nl + T4INT, INT_TYP);
3733172Smckusic 					put(2, O_WRITEC,
3743172Smckusic 						sizeof(char *) + sizeof(int));
3752073Smckusic 					fmtspec = SKIP;
3762073Smckusic 					break;
3772073Smckusic 				}
378768Speter 				ap = stkrval(alv, NIL , RREQ );
3793172Smckusic 				convert(nl + T4INT, INT_TYP);
3803172Smckusic 				stkcnt += sizeof(int);
381768Speter 				fmt = 'c';
382768Speter 				break;
383768Speter 			case TSCAL:
3841628Speter 				warning();
385768Speter 				if (opt('s')) {
386768Speter 					standard();
387768Speter 				}
3881628Speter 				error("Writing scalars to text files is non-standard");
389768Speter 			case TBOOL:
390768Speter 				stkrval(alv, NIL , RREQ );
3913076Smckusic 				put(2, O_NAM, (long)listnames(ap));
3923172Smckusic 				stkcnt += sizeof(char *);
393768Speter 				fmt = 's';
394768Speter 				break;
395768Speter 			case TDOUBLE:
396768Speter 				ap = stkrval(alv, TDOUBLE , RREQ );
3973172Smckusic 				stkcnt += sizeof(double);
398768Speter 			     tdouble:
399768Speter 				switch (fmtspec) {
400768Speter 				case NIL:
4013076Smckusic #					ifdef DEC11
4023076Smckusic 					    field = 21;
4033076Smckusic #					else
4043076Smckusic 					    field = 22;
4053076Smckusic #					endif DEC11
406768Speter 					prec = 14;
4073076Smckusic 					fmt = 'e';
408768Speter 					fmtspec = CONWIDTH + CONPREC;
409768Speter 					break;
410768Speter 				case CONWIDTH:
411768Speter 					if (--field < 1)
412768Speter 						field = 1;
4133076Smckusic #					ifdef DEC11
4143076Smckusic 					    prec = field - 7;
4153076Smckusic #					else
4163076Smckusic 					    prec = field - 8;
4173076Smckusic #					endif DEC11
418768Speter 					if (prec < 1)
419768Speter 						prec = 1;
420768Speter 					fmtspec += CONPREC;
4213076Smckusic 					fmt = 'e';
422768Speter 					break;
423768Speter 				case CONWIDTH + CONPREC:
424768Speter 				case CONWIDTH + VARPREC:
425768Speter 					if (--field < 1)
426768Speter 						field = 1;
427768Speter 				}
428768Speter 				format[0] = ' ';
429768Speter 				fmtstart = 0;
430768Speter 				break;
431768Speter 			case TSTR:
432768Speter 				constval( alv );
433768Speter 				switch ( classify( con.ctype ) ) {
434768Speter 				    case TCHAR:
435768Speter 					typ = TCHAR;
436768Speter 					goto tchar;
437768Speter 				    case TSTR:
438768Speter 					strptr = con.cpval;
439768Speter 					for (strnglen = 0;  *strptr++;  strnglen++) /* void */;
440768Speter 					strptr = con.cpval;
441768Speter 					break;
442768Speter 				    default:
443768Speter 					strnglen = width(ap);
444768Speter 					break;
445768Speter 				}
446768Speter 				fmt = 's';
447768Speter 				strfmt = fmtspec;
448768Speter 				if (fmtspec == NIL) {
449768Speter 					fmtspec = SKIP;
450768Speter 					break;
451768Speter 				}
452768Speter 				if (fmtspec & CONWIDTH) {
453768Speter 					if (field <= strnglen) {
454768Speter 						fmtspec = SKIP;
455768Speter 						break;
456768Speter 					} else
457768Speter 						field -= strnglen;
458768Speter 				}
459768Speter 				/*
460768Speter 				 * push string to implement leading blank padding
461768Speter 				 */
462768Speter 				put(2, O_LVCON, 2);
463768Speter 				putstr("", 0);
4643172Smckusic 				stkcnt += sizeof(char *);
465768Speter 				break;
466768Speter 			default:
467768Speter 				error("Can't write %ss to a text file", clnames[typ]);
468768Speter 				continue;
469768Speter 			}
470768Speter 			/*
471768Speter 			 * If there is a variable precision, evaluate it onto
472768Speter 			 * the stack
473768Speter 			 */
474768Speter 			if (fmtspec & VARPREC) {
475768Speter 				ap = stkrval(al[3], NIL , RREQ );
476768Speter 				if (ap == NIL)
477768Speter 					continue;
478768Speter 				if (isnta(ap,"i")) {
479768Speter 					error("Second write width must be integer, not %s", nameof(ap));
480768Speter 					continue;
481768Speter 				}
482768Speter 				if ( opt( 't' ) ) {
483768Speter 				    put(3, O_MAX, 0, 0);
484768Speter 				}
4853172Smckusic 				convert(nl+T4INT, INT_TYP);
4863172Smckusic 				stkcnt += sizeof(int);
487768Speter 			}
488768Speter 			/*
489768Speter 			 * If there is a variable width, evaluate it onto
490768Speter 			 * the stack
491768Speter 			 */
492768Speter 			if (fmtspec & VARWIDTH) {
493768Speter 				if ( ( typ == TDOUBLE && fmtspec == VARWIDTH )
494768Speter 				    || typ == TSTR ) {
495*3226Smckusic 					soffset = sizes[cbn].curtmps;
496*3226Smckusic 					i = tmpalloc(sizeof(long),
497*3226Smckusic 						nl+T4INT, REGOK);
498768Speter 					put(2, O_LV | cbn << 8 + INDX, i);
499768Speter 				}
500768Speter 				ap = stkrval(al[2], NIL , RREQ );
501768Speter 				if (ap == NIL)
502768Speter 					continue;
503768Speter 				if (isnta(ap,"i")) {
504768Speter 					error("First write width must be integer, not %s", nameof(ap));
505768Speter 					continue;
506768Speter 				}
507768Speter 				/*
508768Speter 				 * Perform special processing on widths based
509768Speter 				 * on data type
510768Speter 				 */
511768Speter 				switch (typ) {
512768Speter 				case TDOUBLE:
513768Speter 					if (fmtspec == VARWIDTH) {
5143076Smckusic 						fmt = 'e';
515768Speter 						put(1, O_AS4);
516768Speter 						put(2, O_RV4 | cbn << 8 + INDX, i);
5173076Smckusic #						ifdef DEC11
5183076Smckusic 						    put(3, O_MAX, 8, 1);
5193076Smckusic #						else
5203076Smckusic 						    put(3, O_MAX, 9, 1);
5213076Smckusic #						endif DEC11
5223172Smckusic 						convert(nl+T4INT, INT_TYP);
5233172Smckusic 						stkcnt += sizeof(int);
524768Speter 						put(2, O_RV4 | cbn << 8 + INDX, i);
525768Speter 						fmtspec += VARPREC;
526*3226Smckusic 						tmpfree(&soffset);
527768Speter 					}
528768Speter 					put(3, O_MAX, 1, 1);
529768Speter 					break;
530768Speter 				case TSTR:
531768Speter 					put(1, O_AS4);
532768Speter 					put(2, O_RV4 | cbn << 8 + INDX, i);
533768Speter 					put(3, O_MAX, strnglen, 0);
534768Speter 					break;
535768Speter 				default:
536768Speter 					if ( opt( 't' ) ) {
537768Speter 					    put(3, O_MAX, 0, 0);
538768Speter 					}
539768Speter 					break;
540768Speter 				}
5413172Smckusic 				convert(nl+T4INT, INT_TYP);
5423172Smckusic 				stkcnt += sizeof(int);
543768Speter 			}
544768Speter 			/*
545768Speter 			 * Generate the format string
546768Speter 			 */
547768Speter 			switch (fmtspec) {
548768Speter 			default:
549768Speter 				panic("fmt2");
550768Speter 			case SKIP:
551768Speter 				break;
5522073Smckusic 			case NIL:
5532073Smckusic 				sprintf(&format[1], "%%%c", fmt);
5542073Smckusic 				goto fmtgen;
555768Speter 			case CONWIDTH:
5563076Smckusic 				sprintf(&format[1], "%%%d%c", field, fmt);
557768Speter 				goto fmtgen;
558768Speter 			case VARWIDTH:
559768Speter 				sprintf(&format[1], "%%*%c", fmt);
560768Speter 				goto fmtgen;
561768Speter 			case CONWIDTH + CONPREC:
5623076Smckusic 				sprintf(&format[1], "%%%d.%d%c", field, prec, fmt);
563768Speter 				goto fmtgen;
564768Speter 			case CONWIDTH + VARPREC:
5653076Smckusic 				sprintf(&format[1], "%%%d.*%c", field, fmt);
566768Speter 				goto fmtgen;
567768Speter 			case VARWIDTH + CONPREC:
5683076Smckusic 				sprintf(&format[1], "%%*.%d%c", prec, fmt);
569768Speter 				goto fmtgen;
570768Speter 			case VARWIDTH + VARPREC:
571768Speter 				sprintf(&format[1], "%%*.*%c", fmt);
572768Speter 			fmtgen:
573768Speter 				fmtlen = lenstr(&format[fmtstart], 0);
574768Speter 				put(2, O_LVCON, fmtlen);
575768Speter 				putstr(&format[fmtstart], 0);
576768Speter 				put(1, O_FILE);
5773172Smckusic 				stkcnt += 2 * sizeof(char *);
578768Speter 				put(2, O_WRITEF, stkcnt);
579768Speter 			}
580768Speter 			/*
581768Speter 			 * Write the string after its blank padding
582768Speter 			 */
583768Speter 			if (typ == TSTR) {
584768Speter 				put(1, O_FILE);
5853172Smckusic 				put(2, CON_INT, 1);
586768Speter 				if (strfmt & VARWIDTH) {
587768Speter 					put(2, O_RV4 | cbn << 8 + INDX , i );
588768Speter 					put(2, O_MIN, strnglen);
5893172Smckusic 					convert(nl+T4INT, INT_TYP);
590*3226Smckusic 					tmpfree(&soffset);
591768Speter 				} else {
592768Speter 					if ((fmtspec & SKIP) &&
593768Speter 					   (strfmt & CONWIDTH)) {
594768Speter 						strnglen = field;
595768Speter 					}
5963172Smckusic 					put(2, CON_INT, strnglen);
597768Speter 				}
598768Speter 				ap = stkrval(alv, NIL , RREQ );
5993172Smckusic 				put(2, O_WRITES,
6003172Smckusic 					2 * sizeof(char *) + 2 * sizeof(int));
601768Speter 			}
602768Speter 		}
603768Speter 		/*
604768Speter 		 * Done with arguments.
605768Speter 		 * Handle writeln and
606768Speter 		 * insufficent number of args.
607768Speter 		 */
608768Speter 		switch (p->value[0] &~ NSTAND) {
609768Speter 			case O_WRITEF:
610768Speter 				if (argc == 0)
611768Speter 					error("Write requires an argument");
612768Speter 				break;
613768Speter 			case O_MESSAGE:
614768Speter 				if (argc == 0)
615768Speter 					error("Message requires an argument");
616768Speter 			case O_WRITLN:
617768Speter 				if (filetype != nl+T1CHAR)
618768Speter 					error("Can't 'writeln' a non text file");
619768Speter 				put(1, O_WRITLN);
620768Speter 				break;
621768Speter 		}
622768Speter 		return;
623768Speter 
624768Speter 	case O_READ4:
625768Speter 	case O_READLN:
626768Speter 		/*
627768Speter 		 * Set up default
628768Speter 		 * file "input".
629768Speter 		 */
630768Speter 		file = NIL;
631768Speter 		filetype = nl+T1CHAR;
632768Speter 		/*
633768Speter 		 * Determine the file implied
634768Speter 		 * for the read and generate
635768Speter 		 * code to make it the active file.
636768Speter 		 */
637768Speter 		if (argv != NIL) {
638768Speter 			codeoff();
639768Speter 			ap = stkrval(argv[1], NIL , RREQ );
640768Speter 			codeon();
641768Speter 			if (ap == NIL)
642768Speter 				argv = argv[2];
643768Speter 			if (ap != NIL && ap->class == FILET) {
644768Speter 				/*
645768Speter 				 * Got "read(f, ...", make
646768Speter 				 * f the active file, and save
647768Speter 				 * it and its type for use in
648768Speter 				 * processing the rest of the
649768Speter 				 * arguments to read.
650768Speter 				 */
651768Speter 				file = argv[1];
652768Speter 				filetype = ap->type;
6532073Smckusic 				stklval(argv[1], NIL , LREQ );
654768Speter 				put(1, O_UNIT);
655768Speter 				argv = argv[2];
656768Speter 				argc--;
657768Speter 			} else {
658768Speter 				/*
659768Speter 				 * Default is read from
660768Speter 				 * standard input.
661768Speter 				 */
662768Speter 				put(1, O_UNITINP);
663768Speter 				input->nl_flags |= NUSED;
664768Speter 			}
665768Speter 		} else {
666768Speter 			put(1, O_UNITINP);
667768Speter 			input->nl_flags |= NUSED;
668768Speter 		}
669768Speter 		/*
670768Speter 		 * Loop and process each
671768Speter 		 * of the arguments.
672768Speter 		 */
673768Speter 		for (; argv != NIL; argv = argv[2]) {
674768Speter 			/*
675768Speter 			 * Get the address of the target
676768Speter 			 * on the stack.
677768Speter 			 */
678768Speter 			al = argv[1];
679768Speter 			if (al == NIL)
680768Speter 				continue;
681768Speter 			if (al[0] != T_VAR) {
682768Speter 				error("Arguments to %s must be variables, not expressions", p->symbol);
683768Speter 				continue;
684768Speter 			}
685768Speter 			ap = stklval(al, MOD|ASGN|NOUSE);
686768Speter 			if (ap == NIL)
687768Speter 				continue;
688768Speter 			if (filetype != nl+T1CHAR) {
689768Speter 				/*
690768Speter 				 * Generalized read, i.e.
691768Speter 				 * from a non-textfile.
692768Speter 				 */
693768Speter 				if (incompat(filetype, ap, argv[1] )) {
694768Speter 					error("Type mismatch in read from non-text file");
695768Speter 					continue;
696768Speter 				}
697768Speter 				/*
698768Speter 				 * var := file ^;
699768Speter 				 */
700768Speter 				if (file != NIL)
7012073Smckusic 					stklval(file, NIL , LREQ );
702768Speter 				else /* Magic */
7033076Smckusic 					put(2, PTR_RV, (int)input->value[0]);
704768Speter 				put(1, O_FNIL);
705768Speter 				put(2, O_IND, width(filetype));
706768Speter 				convert(filetype, ap);
707768Speter 				if (isa(ap, "bsci"))
708768Speter 					rangechk(ap, ap);
709768Speter 				put(2, O_AS, width(ap));
710768Speter 				/*
711768Speter 				 * get(file);
712768Speter 				 */
713768Speter 				put(1, O_GET);
714768Speter 				continue;
715768Speter 			}
716768Speter 			typ = classify(ap);
717768Speter 			op = rdops(typ);
718768Speter 			if (op == NIL) {
719768Speter 				error("Can't read %ss from a text file", clnames[typ]);
720768Speter 				continue;
721768Speter 			}
722768Speter 			if (op != O_READE)
723768Speter 				put(1, op);
724768Speter 			else {
7253076Smckusic 				put(2, op, (long)listnames(ap));
7261628Speter 				warning();
727768Speter 				if (opt('s')) {
728768Speter 					standard();
729768Speter 				}
7301628Speter 				error("Reading scalars from text files is non-standard");
731768Speter 			}
732768Speter 			/*
733768Speter 			 * Data read is on the stack.
734768Speter 			 * Assign it.
735768Speter 			 */
736768Speter 			if (op != O_READ8 && op != O_READE)
737768Speter 				rangechk(ap, op == O_READC ? ap : nl+T4INT);
738768Speter 			gen(O_AS2, O_AS2, width(ap),
739768Speter 				op == O_READ8 ? 8 : op == O_READ4 ? 4 : 2);
740768Speter 		}
741768Speter 		/*
742768Speter 		 * Done with arguments.
743768Speter 		 * Handle readln and
744768Speter 		 * insufficient number of args.
745768Speter 		 */
746768Speter 		if (p->value[0] == O_READLN) {
747768Speter 			if (filetype != nl+T1CHAR)
748768Speter 				error("Can't 'readln' a non text file");
749768Speter 			put(1, O_READLN);
750768Speter 		}
751768Speter 		else if (argc == 0)
752768Speter 			error("read requires an argument");
753768Speter 		return;
754768Speter 
755768Speter 	case O_GET:
756768Speter 	case O_PUT:
757768Speter 		if (argc != 1) {
758768Speter 			error("%s expects one argument", p->symbol);
759768Speter 			return;
760768Speter 		}
7612073Smckusic 		ap = stklval(argv[1], NIL , LREQ );
762768Speter 		if (ap == NIL)
763768Speter 			return;
764768Speter 		if (ap->class != FILET) {
765768Speter 			error("Argument to %s must be a file, not %s", p->symbol, nameof(ap));
766768Speter 			return;
767768Speter 		}
768768Speter 		put(1, O_UNIT);
769768Speter 		put(1, op);
770768Speter 		return;
771768Speter 
772768Speter 	case O_RESET:
773768Speter 	case O_REWRITE:
774768Speter 		if (argc == 0 || argc > 2) {
775768Speter 			error("%s expects one or two arguments", p->symbol);
776768Speter 			return;
777768Speter 		}
778768Speter 		if (opt('s') && argc == 2) {
779768Speter 			standard();
780768Speter 			error("Two argument forms of reset and rewrite are non-standard");
781768Speter 		}
7822073Smckusic 		codeoff();
783768Speter 		ap = stklval(argv[1], MOD|NOUSE);
7842073Smckusic 		codeon();
785768Speter 		if (ap == NIL)
786768Speter 			return;
787768Speter 		if (ap->class != FILET) {
788768Speter 			error("First argument to %s must be a file, not %s", p->symbol, nameof(ap));
789768Speter 			return;
790768Speter 		}
7912073Smckusic 		put(2, O_CON24, text(ap) ? 0: width(ap->type));
792768Speter 		if (argc == 2) {
793768Speter 			/*
794768Speter 			 * Optional second argument
795768Speter 			 * is a string name of a
796768Speter 			 * UNIX (R) file to be associated.
797768Speter 			 */
798768Speter 			al = argv[2];
7992073Smckusic 			codeoff();
800768Speter 			al = stkrval(al[1], NOFLAGS , RREQ );
8012073Smckusic 			codeon();
802768Speter 			if (al == NIL)
803768Speter 				return;
804768Speter 			if (classify(al) != TSTR) {
805768Speter 				error("Second argument to %s must be a string, not %s", p->symbol, nameof(al));
806768Speter 				return;
807768Speter 			}
8082073Smckusic 			put(2, O_CON24, width(al));
8092073Smckusic 			al = argv[2];
8102073Smckusic 			al = stkrval(al[1], NOFLAGS , RREQ );
811768Speter 		} else {
8122073Smckusic 			put(2, O_CON24, 0);
8133076Smckusic 			put(2, PTR_CON, NIL);
814768Speter 		}
8152073Smckusic 		ap = stklval(argv[1], MOD|NOUSE);
816768Speter 		put(1, op);
817768Speter 		return;
818768Speter 
819768Speter 	case O_NEW:
820768Speter 	case O_DISPOSE:
821768Speter 		if (argc == 0) {
822768Speter 			error("%s expects at least one argument", p->symbol);
823768Speter 			return;
824768Speter 		}
825768Speter 		ap = stklval(argv[1], op == O_NEW ? ( MOD | NOUSE ) : MOD );
826768Speter 		if (ap == NIL)
827768Speter 			return;
828768Speter 		if (ap->class != PTR) {
829768Speter 			error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap));
830768Speter 			return;
831768Speter 		}
832768Speter 		ap = ap->type;
833768Speter 		if (ap == NIL)
834768Speter 			return;
835768Speter 		argv = argv[2];
836768Speter 		if (argv != NIL) {
837768Speter 			if (ap->class != RECORD) {
838768Speter 				error("Record required when specifying variant tags");
839768Speter 				return;
840768Speter 			}
841768Speter 			for (; argv != NIL; argv = argv[2]) {
842768Speter 				if (ap->ptr[NL_VARNT] == NIL) {
843768Speter 					error("Too many tag fields");
844768Speter 					return;
845768Speter 				}
846768Speter 				if (!isconst(argv[1])) {
847768Speter 					error("Second and successive arguments to %s must be constants", p->symbol);
848768Speter 					return;
849768Speter 				}
850768Speter 				gconst(argv[1]);
851768Speter 				if (con.ctype == NIL)
852768Speter 					return;
853768Speter 				if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) {
854768Speter 					cerror("Specified tag constant type clashed with variant case selector type");
855768Speter 					return;
856768Speter 				}
857768Speter 				for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain)
858768Speter 					if (ap->range[0] == con.crval)
859768Speter 						break;
860768Speter 				if (ap == NIL) {
861768Speter 					error("No variant case label value equals specified constant value");
862768Speter 					return;
863768Speter 				}
864768Speter 				ap = ap->ptr[NL_VTOREC];
865768Speter 			}
866768Speter 		}
867768Speter 		put(2, op, width(ap));
868768Speter 		return;
869768Speter 
870768Speter 	case O_DATE:
871768Speter 	case O_TIME:
872768Speter 		if (argc != 1) {
873768Speter 			error("%s expects one argument", p->symbol);
874768Speter 			return;
875768Speter 		}
876768Speter 		ap = stklval(argv[1], MOD|NOUSE);
877768Speter 		if (ap == NIL)
878768Speter 			return;
879768Speter 		if (classify(ap) != TSTR || width(ap) != 10) {
880768Speter 			error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap));
881768Speter 			return;
882768Speter 		}
883768Speter 		put(1, op);
884768Speter 		return;
885768Speter 
886768Speter 	case O_HALT:
887768Speter 		if (argc != 0) {
888768Speter 			error("halt takes no arguments");
889768Speter 			return;
890768Speter 		}
891768Speter 		put(1, op);
892768Speter 		noreach = 1;
893768Speter 		return;
894768Speter 
895768Speter 	case O_ARGV:
896768Speter 		if (argc != 2) {
897768Speter 			error("argv takes two arguments");
898768Speter 			return;
899768Speter 		}
900768Speter 		ap = stkrval(argv[1], NIL , RREQ );
901768Speter 		if (ap == NIL)
902768Speter 			return;
903768Speter 		if (isnta(ap, "i")) {
904768Speter 			error("argv's first argument must be an integer, not %s", nameof(ap));
905768Speter 			return;
906768Speter 		}
907768Speter 		al = argv[2];
908768Speter 		ap = stklval(al[1], MOD|NOUSE);
909768Speter 		if (ap == NIL)
910768Speter 			return;
911768Speter 		if (classify(ap) != TSTR) {
912768Speter 			error("argv's second argument must be a string, not %s", nameof(ap));
913768Speter 			return;
914768Speter 		}
915768Speter 		put(2, op, width(ap));
916768Speter 		return;
917768Speter 
918768Speter 	case O_STLIM:
919768Speter 		if (argc != 1) {
920768Speter 			error("stlimit requires one argument");
921768Speter 			return;
922768Speter 		}
923768Speter 		ap = stkrval(argv[1], NIL , RREQ );
924768Speter 		if (ap == NIL)
925768Speter 			return;
926768Speter 		if (isnta(ap, "i")) {
927768Speter 			error("stlimit's argument must be an integer, not %s", nameof(ap));
928768Speter 			return;
929768Speter 		}
930768Speter 		if (width(ap) != 4)
931768Speter 			put(1, O_STOI);
932768Speter 		put(1, op);
933768Speter 		return;
934768Speter 
935768Speter 	case O_REMOVE:
936768Speter 		if (argc != 1) {
937768Speter 			error("remove expects one argument");
938768Speter 			return;
939768Speter 		}
9402073Smckusic 		codeoff();
941768Speter 		ap = stkrval(argv[1], NOFLAGS , RREQ );
9422073Smckusic 		codeon();
943768Speter 		if (ap == NIL)
944768Speter 			return;
945768Speter 		if (classify(ap) != TSTR) {
946768Speter 			error("remove's argument must be a string, not %s", nameof(ap));
947768Speter 			return;
948768Speter 		}
949768Speter 		put(2, O_CON24, width(ap));
9502073Smckusic 		ap = stkrval(argv[1], NOFLAGS , RREQ );
951768Speter 		put(1, op);
952768Speter 		return;
953768Speter 
954768Speter 	case O_LLIMIT:
955768Speter 		if (argc != 2) {
956768Speter 			error("linelimit expects two arguments");
957768Speter 			return;
958768Speter 		}
959768Speter 		al = argv[2];
960768Speter 		ap = stkrval(al[1], NIL , RREQ );
961768Speter 		if (ap == NIL)
962768Speter 			return;
963768Speter 		if (isnta(ap, "i")) {
964768Speter 			error("linelimit's second argument must be an integer, not %s", nameof(ap));
965768Speter 			return;
966768Speter 		}
9672073Smckusic 		ap = stklval(argv[1], NOFLAGS|NOUSE);
9682073Smckusic 		if (ap == NIL)
9692073Smckusic 			return;
9702073Smckusic 		if (!text(ap)) {
9712073Smckusic 			error("linelimit's first argument must be a text file, not %s", nameof(ap));
9722073Smckusic 			return;
9732073Smckusic 		}
974768Speter 		put(1, op);
975768Speter 		return;
976768Speter 	case O_PAGE:
977768Speter 		if (argc != 1) {
978768Speter 			error("page expects one argument");
979768Speter 			return;
980768Speter 		}
9812073Smckusic 		ap = stklval(argv[1], NIL , LREQ );
982768Speter 		if (ap == NIL)
983768Speter 			return;
984768Speter 		if (!text(ap)) {
985768Speter 			error("Argument to page must be a text file, not %s", nameof(ap));
986768Speter 			return;
987768Speter 		}
988768Speter 		put(1, O_UNIT);
989768Speter 		put(1, op);
990768Speter 		return;
991768Speter 
992768Speter 	case O_PACK:
993768Speter 		if (argc != 3) {
994768Speter 			error("pack expects three arguments");
995768Speter 			return;
996768Speter 		}
997768Speter 		pu = "pack(a,i,z)";
9983076Smckusic 		pua = argv[1];
9993076Smckusic 		al = argv[2];
10003076Smckusic 		pui = al[1];
10013076Smckusic 		alv = al[2];
10023076Smckusic 		puz = alv[1];
1003768Speter 		goto packunp;
1004768Speter 	case O_UNPACK:
1005768Speter 		if (argc != 3) {
1006768Speter 			error("unpack expects three arguments");
1007768Speter 			return;
1008768Speter 		}
1009768Speter 		pu = "unpack(z,a,i)";
10103076Smckusic 		puz = argv[1];
10113076Smckusic 		al = argv[2];
10123076Smckusic 		pua = al[1];
10133076Smckusic 		alv = al[2];
10143076Smckusic 		pui = alv[1];
1015768Speter packunp:
10162073Smckusic 		codeoff();
1017768Speter 		ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE);
10182073Smckusic 		al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE);
10192073Smckusic 		codeon();
1020768Speter 		if (ap == NIL)
1021768Speter 			return;
1022768Speter 		if (ap->class != ARRAY) {
1023768Speter 			error("%s requires a to be an unpacked array, not %s", pu, nameof(ap));
1024768Speter 			return;
1025768Speter 		}
1026768Speter 		if (al->class != ARRAY) {
1027768Speter 			error("%s requires z to be a packed array, not %s", pu, nameof(ap));
1028768Speter 			return;
1029768Speter 		}
1030768Speter 		if (al->type == NIL || ap->type == NIL)
1031768Speter 			return;
1032768Speter 		if (al->type != ap->type) {
1033768Speter 			error("%s requires a and z to be arrays of the same type", pu, nameof(ap));
1034768Speter 			return;
1035768Speter 		}
1036768Speter 		k = width(al);
1037768Speter 		itemwidth = width(ap->type);
1038768Speter 		ap = ap->chain;
1039768Speter 		al = al->chain;
1040768Speter 		if (ap->chain != NIL || al->chain != NIL) {
1041768Speter 			error("%s requires a and z to be single dimension arrays", pu);
1042768Speter 			return;
1043768Speter 		}
1044768Speter 		if (ap == NIL || al == NIL)
1045768Speter 			return;
1046768Speter 		/*
1047768Speter 		 * al is the range for z i.e. u..v
1048768Speter 		 * ap is the range for a i.e. m..n
1049768Speter 		 * i will be n-m+1
1050768Speter 		 * j will be v-u+1
1051768Speter 		 */
1052768Speter 		i = ap->range[1] - ap->range[0] + 1;
1053768Speter 		j = al->range[1] - al->range[0] + 1;
1054768Speter 		if (i < j) {
1055768Speter 			error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i);
1056768Speter 			return;
1057768Speter 		}
1058768Speter 		/*
1059768Speter 		 * get n-m-(v-u) and m for the interpreter
1060768Speter 		 */
1061768Speter 		i -= j;
1062768Speter 		j = ap->range[0];
10632073Smckusic 		put(2, O_CON24, k);
10642073Smckusic 		put(2, O_CON24, i);
10652073Smckusic 		put(2, O_CON24, j);
10662073Smckusic 		put(2, O_CON24, itemwidth);
10672073Smckusic 		al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE);
10682073Smckusic 		ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE);
10692073Smckusic 		ap = stkrval((int *) pui, NLNIL , RREQ );
10702073Smckusic 		if (ap == NIL)
10712073Smckusic 			return;
10722073Smckusic 		put(1, op);
1073768Speter 		return;
1074768Speter 	case 0:
1075768Speter 		error("%s is an unimplemented 6400 extension", p->symbol);
1076768Speter 		return;
1077768Speter 
1078768Speter 	default:
1079768Speter 		panic("proc case");
1080768Speter 	}
1081768Speter }
1082768Speter #endif OBJ
1083