xref: /csrg-svn/usr.bin/pascal/src/proc.c (revision 16417)
1768Speter /* Copyright (c) 1979 Regents of the University of California */
2768Speter 
314740Sthien #ifndef lint
4*16417Speter static char sccsid[] = "@(#)proc.c 2.2 04/26/84";
514740Sthien #endif
6768Speter 
7768Speter #include "whoami.h"
8768Speter #ifdef OBJ
9768Speter     /*
10768Speter      *	and the rest of the file
11768Speter      */
12768Speter #include "0.h"
13768Speter #include "tree.h"
14768Speter #include "opcode.h"
15768Speter #include "objfmt.h"
1611327Speter #include "tmps.h"
1714740Sthien #include "tree_ty.h"
18768Speter 
19768Speter /*
2011882Smckusick  * The constant EXPOSIZE specifies the number of digits in the exponent
2111882Smckusick  * of real numbers.
2211882Smckusick  *
239230Smckusick  * The constant REALSPC defines the amount of forced padding preceeding
249230Smckusick  * real numbers when they are printed. If REALSPC == 0, then no padding
259230Smckusick  * is added, REALSPC == 1 adds one extra blank irregardless of the width
269230Smckusick  * specified by the user.
279230Smckusick  *
289230Smckusick  * N.B. - Values greater than one require program mods.
299230Smckusick  */
3011882Smckusick #define EXPOSIZE	2
3111882Smckusick #define	REALSPC		0
329230Smckusick 
339230Smckusick /*
34768Speter  * The following array is used to determine which classes may be read
35768Speter  * from textfiles. It is indexed by the return value from classify.
36768Speter  */
37768Speter #define rdops(x) rdxxxx[(x)-(TFIRST)]
38768Speter 
39768Speter int rdxxxx[] = {
40768Speter 	0,		/* -7 file types */
41768Speter 	0,		/* -6 record types */
42768Speter 	0,		/* -5 array types */
43768Speter 	O_READE,	/* -4 scalar types */
44768Speter 	0,		/* -3 pointer types */
45768Speter 	0,		/* -2 set types */
46768Speter 	0,		/* -1 string types */
47768Speter 	0,		/*  0 nil, no type */
48768Speter 	O_READE,	/*  1 boolean */
49768Speter 	O_READC,	/*  2 character */
50768Speter 	O_READ4,	/*  3 integer */
51768Speter 	O_READ8		/*  4 real */
52768Speter };
53768Speter 
54768Speter /*
55768Speter  * Proc handles procedure calls.
56768Speter  * Non-builtin procedures are "buck-passed" to func (with a flag
57768Speter  * indicating that they are actually procedures.
58768Speter  * builtin procedures are handled here.
59768Speter  */
60768Speter proc(r)
6114740Sthien 	struct tnode *r;
62768Speter {
63768Speter 	register struct nl *p;
6414740Sthien 	register struct tnode *alv, *al;
6514740Sthien  	register int op;
6614740Sthien 	struct nl *filetype, *ap, *al1;
6714740Sthien 	int argc, typ, fmtspec, strfmt, stkcnt;
6814740Sthien 	struct tnode *argv;
6914740Sthien 	char fmt, format[20], *strptr, *pu;
7014740Sthien 	int prec, field, strnglen, fmtlen, fmtstart;
7114740Sthien 	struct tnode *pua, *pui, *puz, *file;
72768Speter 	int i, j, k;
73768Speter 	int itemwidth;
743226Smckusic 	struct tmps soffset;
753851Speter 	struct nl	*tempnlp;
76768Speter 
77768Speter #define	CONPREC 4
78768Speter #define	VARPREC 8
79768Speter #define	CONWIDTH 1
80768Speter #define	VARWIDTH 2
81768Speter #define SKIP 16
82768Speter 
83768Speter 	/*
84768Speter 	 * Verify that the name is
85768Speter 	 * defined and is that of a
86768Speter 	 * procedure.
87768Speter 	 */
8814740Sthien 	p = lookup(r->pcall_node.proc_id);
89768Speter 	if (p == NIL) {
9014740Sthien 		rvlist(r->pcall_node.arg);
91768Speter 		return;
92768Speter 	}
931198Speter 	if (p->class != PROC && p->class != FPROC) {
94768Speter 		error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]);
9514740Sthien 		rvlist(r->pcall_node.arg);
96768Speter 		return;
97768Speter 	}
9814740Sthien 	argv = r->pcall_node.arg;
99768Speter 
100768Speter 	/*
101768Speter 	 * Call handles user defined
102768Speter 	 * procedures and functions.
103768Speter 	 */
104768Speter 	if (bn != 0) {
10514740Sthien 		(void) call(p, argv, PROC, bn);
106768Speter 		return;
107768Speter 	}
108768Speter 
109768Speter 	/*
110768Speter 	 * Call to built-in procedure.
111768Speter 	 * Count the arguments.
112768Speter 	 */
113768Speter 	argc = 0;
11414740Sthien 	for (al = argv; al != TR_NIL; al = al->list_node.next)
115768Speter 		argc++;
116768Speter 
117768Speter 	/*
118768Speter 	 * Switch on the operator
119768Speter 	 * associated with the built-in
120768Speter 	 * procedure in the namelist
121768Speter 	 */
122768Speter 	op = p->value[0] &~ NSTAND;
123768Speter 	if (opt('s') && (p->value[0] & NSTAND)) {
124768Speter 		standard();
125768Speter 		error("%s is a nonstandard procedure", p->symbol);
126768Speter 	}
127768Speter 	switch (op) {
128768Speter 
129768Speter 	case O_ABORT:
130768Speter 		if (argc != 0)
131768Speter 			error("null takes no arguments");
132768Speter 		return;
133768Speter 
134768Speter 	case O_FLUSH:
135768Speter 		if (argc == 0) {
13614740Sthien 			(void) put(1, O_MESSAGE);
137768Speter 			return;
138768Speter 		}
139768Speter 		if (argc != 1) {
140768Speter 			error("flush takes at most one argument");
141768Speter 			return;
142768Speter 		}
14314740Sthien 		ap = stklval(argv->list_node.list, NIL );
14414740Sthien 		if (ap == NLNIL)
145768Speter 			return;
146768Speter 		if (ap->class != FILET) {
147768Speter 			error("flush's argument must be a file, not %s", nameof(ap));
148768Speter 			return;
149768Speter 		}
15014740Sthien 		(void) put(1, op);
151768Speter 		return;
152768Speter 
153768Speter 	case O_MESSAGE:
154768Speter 	case O_WRITEF:
155768Speter 	case O_WRITLN:
156768Speter 		/*
157768Speter 		 * Set up default file "output"'s type
158768Speter 		 */
159768Speter 		file = NIL;
160768Speter 		filetype = nl+T1CHAR;
161768Speter 		/*
162768Speter 		 * Determine the file implied
163768Speter 		 * for the write and generate
164768Speter 		 * code to make it the active file.
165768Speter 		 */
166768Speter 		if (op == O_MESSAGE) {
167768Speter 			/*
168768Speter 			 * For message, all that matters
169768Speter 			 * is that the filetype is
170768Speter 			 * a character file.
171768Speter 			 * Thus "output" will suit us fine.
172768Speter 			 */
17314740Sthien 			(void) put(1, O_MESSAGE);
17414740Sthien 		} else if (argv != TR_NIL && (al = argv->list_node.list)->tag !=
17514740Sthien 					T_WEXP) {
176768Speter 			/*
177768Speter 			 * If there is a first argument which has
178768Speter 			 * no write widths, then it is potentially
179768Speter 			 * a file name.
180768Speter 			 */
181768Speter 			codeoff();
18214740Sthien 			ap = stkrval(argv->list_node.list, NLNIL, (long) RREQ );
183768Speter 			codeon();
18414740Sthien 			if (ap == NLNIL)
18514740Sthien 				argv = argv->list_node.next;
18614740Sthien 			if (ap != NLNIL && ap->class == FILET) {
187768Speter 				/*
188768Speter 				 * Got "write(f, ...", make
189768Speter 				 * f the active file, and save
190768Speter 				 * it and its type for use in
191768Speter 				 * processing the rest of the
192768Speter 				 * arguments to write.
193768Speter 				 */
19414740Sthien 				file = argv->list_node.list;
195768Speter 				filetype = ap->type;
19614740Sthien 				(void) stklval(argv->list_node.list, NIL );
19714740Sthien 				(void) put(1, O_UNIT);
198768Speter 				/*
199768Speter 				 * Skip over the first argument
200768Speter 				 */
20114740Sthien 				argv = argv->list_node.next;
202768Speter 				argc--;
2038538Speter 			} else {
204768Speter 				/*
205768Speter 				 * Set up for writing on
206768Speter 				 * standard output.
207768Speter 				 */
20814740Sthien 				(void) put(1, O_UNITOUT);
2097953Speter 				output->nl_flags |= NUSED;
2108538Speter 			}
2118538Speter 		} else {
21214740Sthien 			(void) put(1, O_UNITOUT);
2137953Speter 			output->nl_flags |= NUSED;
2148538Speter 		}
215768Speter 		/*
216768Speter 		 * Loop and process each
217768Speter 		 * of the arguments.
218768Speter 		 */
21914740Sthien 		for (; argv != TR_NIL; argv = argv->list_node.next) {
220768Speter 			/*
221768Speter 			 * fmtspec indicates the type (CONstant or VARiable)
222768Speter 			 *	and number (none, WIDTH, and/or PRECision)
223768Speter 			 *	of the fields in the printf format for this
224768Speter 			 *	output variable.
2253172Smckusic 			 * stkcnt is the number of bytes pushed on the stack
226768Speter 			 * fmt is the format output indicator (D, E, F, O, X, S)
227768Speter 			 * fmtstart = 0 for leading blank; = 1 for no blank
228768Speter 			 */
229768Speter 			fmtspec = NIL;
230768Speter 			stkcnt = 0;
231768Speter 			fmt = 'D';
232768Speter 			fmtstart = 1;
23314740Sthien 			al = argv->list_node.list;
23414740Sthien 			if (al == TR_NIL)
235768Speter 				continue;
23614740Sthien 			if (al->tag == T_WEXP)
23714740Sthien 				alv = al->wexpr_node.expr1;
238768Speter 			else
239768Speter 				alv = al;
24014740Sthien 			if (alv == TR_NIL)
241768Speter 				continue;
242768Speter 			codeoff();
24314740Sthien 			ap = stkrval(alv, NLNIL , (long) RREQ );
244768Speter 			codeon();
24514740Sthien 			if (ap == NLNIL)
246768Speter 				continue;
247768Speter 			typ = classify(ap);
24814740Sthien 			if (al->tag == T_WEXP) {
249768Speter 				/*
250768Speter 				 * Handle width expressions.
251768Speter 				 * The basic game here is that width
252768Speter 				 * expressions get evaluated. If they
253768Speter 				 * are constant, the value is placed
254768Speter 				 * directly in the format string.
255768Speter 				 * Otherwise the value is pushed onto
256768Speter 				 * the stack and an indirection is
257768Speter 				 * put into the format string.
258768Speter 				 */
25914740Sthien 				if (al->wexpr_node.expr3 ==
26014740Sthien 						(struct tnode *) OCT)
261768Speter 					fmt = 'O';
26214740Sthien 				else if (al->wexpr_node.expr3 ==
26314740Sthien 						(struct tnode *) HEX)
264768Speter 					fmt = 'X';
26514740Sthien 				else if (al->wexpr_node.expr3 != TR_NIL) {
266768Speter 					/*
267768Speter 					 * Evaluate second format spec
268768Speter 					 */
26914740Sthien 					if ( constval(al->wexpr_node.expr3)
270768Speter 					    && isa( con.ctype , "i" ) ) {
271768Speter 						fmtspec += CONPREC;
272768Speter 						prec = con.crval;
273768Speter 					} else {
274768Speter 						fmtspec += VARPREC;
275768Speter 					}
276768Speter 					fmt = 'f';
277768Speter 					switch ( typ ) {
278768Speter 					case TINT:
279768Speter 						if ( opt( 's' ) ) {
280768Speter 						    standard();
281768Speter 						    error("Writing %ss with two write widths is non-standard", clnames[typ]);
282768Speter 						}
283768Speter 						/* and fall through */
284768Speter 					case TDOUBLE:
285768Speter 						break;
286768Speter 					default:
287768Speter 						error("Cannot write %ss with two write widths", clnames[typ]);
288768Speter 						continue;
289768Speter 					}
290768Speter 				}
291768Speter 				/*
292768Speter 				 * Evaluate first format spec
293768Speter 				 */
29414740Sthien 				if (al->wexpr_node.expr2 != TR_NIL) {
29514740Sthien 					if ( constval(al->wexpr_node.expr2)
296768Speter 					    && isa( con.ctype , "i" ) ) {
297768Speter 						fmtspec += CONWIDTH;
298768Speter 						field = con.crval;
299768Speter 					} else {
300768Speter 						fmtspec += VARWIDTH;
301768Speter 					}
302768Speter 				}
303768Speter 				if ((fmtspec & CONPREC) && prec < 0 ||
304768Speter 				    (fmtspec & CONWIDTH) && field < 0) {
305768Speter 					error("Negative widths are not allowed");
306768Speter 					continue;
307768Speter 				}
3083179Smckusic 				if ( opt('s') &&
3093179Smckusic 				    ((fmtspec & CONPREC) && prec == 0 ||
3103179Smckusic 				    (fmtspec & CONWIDTH) && field == 0)) {
3113179Smckusic 					standard();
3123179Smckusic 					error("Zero widths are non-standard");
3133179Smckusic 				}
314768Speter 			}
315768Speter 			if (filetype != nl+T1CHAR) {
316768Speter 				if (fmt == 'O' || fmt == 'X') {
317768Speter 					error("Oct/hex allowed only on text files");
318768Speter 					continue;
319768Speter 				}
320768Speter 				if (fmtspec) {
321768Speter 					error("Write widths allowed only on text files");
322768Speter 					continue;
323768Speter 				}
324768Speter 				/*
325768Speter 				 * Generalized write, i.e.
326768Speter 				 * to a non-textfile.
327768Speter 				 */
32814740Sthien 				(void) stklval(file, NIL );
32914740Sthien 				(void) put(1, O_FNIL);
330768Speter 				/*
331768Speter 				 * file^ := ...
332768Speter 				 */
33314740Sthien 				ap = rvalue(argv->list_node.list, NLNIL, LREQ);
33414740Sthien 				if (ap == NLNIL)
335768Speter 					continue;
33614740Sthien 				if (incompat(ap, filetype,
33714740Sthien 						argv->list_node.list)) {
338768Speter 					cerror("Type mismatch in write to non-text file");
339768Speter 					continue;
340768Speter 				}
341768Speter 				convert(ap, filetype);
34214740Sthien 				(void) put(2, O_AS, width(filetype));
343768Speter 				/*
344768Speter 				 * put(file)
345768Speter 				 */
34614740Sthien 				(void) put(1, O_PUT);
347768Speter 				continue;
348768Speter 			}
349768Speter 			/*
350768Speter 			 * Write to a textfile
351768Speter 			 *
352768Speter 			 * Evaluate the expression
353768Speter 			 * to be written.
354768Speter 			 */
355768Speter 			if (fmt == 'O' || fmt == 'X') {
356768Speter 				if (opt('s')) {
357768Speter 					standard();
358768Speter 					error("Oct and hex are non-standard");
359768Speter 				}
360768Speter 				if (typ == TSTR || typ == TDOUBLE) {
361768Speter 					error("Can't write %ss with oct/hex", clnames[typ]);
362768Speter 					continue;
363768Speter 				}
364768Speter 				if (typ == TCHAR || typ == TBOOL)
365768Speter 					typ = TINT;
366768Speter 			}
367768Speter 			/*
368768Speter 			 * Place the arguement on the stack. If there is
369768Speter 			 * no format specified by the programmer, implement
370768Speter 			 * the default.
371768Speter 			 */
372768Speter 			switch (typ) {
3736542Smckusick 			case TPTR:
3746542Smckusick 				warning();
3756542Smckusick 				if (opt('s')) {
3766542Smckusick 					standard();
3776542Smckusick 				}
3786542Smckusick 				error("Writing %ss to text files is non-standard",
3796542Smckusick 				    clnames[typ]);
3806542Smckusick 				/* and fall through */
381768Speter 			case TINT:
382768Speter 				if (fmt != 'f') {
38314740Sthien 					ap = stkrval(alv, NLNIL, (long) RREQ );
3843172Smckusic 					stkcnt += sizeof(long);
385768Speter 				} else {
38614740Sthien 					ap = stkrval(alv, NLNIL, (long) RREQ );
38714740Sthien 					(void) put(1, O_ITOD);
3883172Smckusic 					stkcnt += sizeof(double);
389768Speter 					typ = TDOUBLE;
390768Speter 					goto tdouble;
391768Speter 				}
392768Speter 				if (fmtspec == NIL) {
393768Speter 					if (fmt == 'D')
394768Speter 						field = 10;
395768Speter 					else if (fmt == 'X')
396768Speter 						field = 8;
397768Speter 					else if (fmt == 'O')
398768Speter 						field = 11;
399768Speter 					else
400768Speter 						panic("fmt1");
401768Speter 					fmtspec = CONWIDTH;
402768Speter 				}
403768Speter 				break;
404768Speter 			case TCHAR:
405768Speter 			     tchar:
4062073Smckusic 				if (fmtspec == NIL) {
40714740Sthien 					(void) put(1, O_FILE);
40814740Sthien 					ap = stkrval(alv, NLNIL, (long) RREQ );
4093172Smckusic 					convert(nl + T4INT, INT_TYP);
41014740Sthien 					(void) put(2, O_WRITEC,
4113172Smckusic 						sizeof(char *) + sizeof(int));
4122073Smckusic 					fmtspec = SKIP;
4132073Smckusic 					break;
4142073Smckusic 				}
41514740Sthien 				ap = stkrval(alv, NLNIL , (long) RREQ );
4163172Smckusic 				convert(nl + T4INT, INT_TYP);
4173172Smckusic 				stkcnt += sizeof(int);
418768Speter 				fmt = 'c';
419768Speter 				break;
420768Speter 			case TSCAL:
4211628Speter 				warning();
422768Speter 				if (opt('s')) {
423768Speter 					standard();
424768Speter 				}
4256542Smckusick 				error("Writing %ss to text files is non-standard",
4266542Smckusick 				    clnames[typ]);
4276542Smckusick 				/* and fall through */
428768Speter 			case TBOOL:
42914740Sthien 				(void) stkrval(alv, NLNIL , (long) RREQ );
43014740Sthien 				(void) put(2, O_NAM, (long)listnames(ap));
4313172Smckusic 				stkcnt += sizeof(char *);
432768Speter 				fmt = 's';
433768Speter 				break;
434768Speter 			case TDOUBLE:
43514740Sthien 				ap = stkrval(alv, (struct nl *) TDOUBLE , (long) RREQ );
4363172Smckusic 				stkcnt += sizeof(double);
437768Speter 			     tdouble:
438768Speter 				switch (fmtspec) {
439768Speter 				case NIL:
44011882Smckusick 					field = 14 + (5 + EXPOSIZE);
44111882Smckusick 				        prec = field - (5 + EXPOSIZE);
4423076Smckusic 					fmt = 'e';
443768Speter 					fmtspec = CONWIDTH + CONPREC;
444768Speter 					break;
445768Speter 				case CONWIDTH:
4469230Smckusick 					field -= REALSPC;
4479230Smckusick 					if (field < 1)
448768Speter 						field = 1;
44911882Smckusick 				        prec = field - (5 + EXPOSIZE);
450768Speter 					if (prec < 1)
451768Speter 						prec = 1;
452768Speter 					fmtspec += CONPREC;
4533076Smckusic 					fmt = 'e';
454768Speter 					break;
455768Speter 				case CONWIDTH + CONPREC:
456768Speter 				case CONWIDTH + VARPREC:
4579230Smckusick 					field -= REALSPC;
4589230Smckusick 					if (field < 1)
459768Speter 						field = 1;
460768Speter 				}
461768Speter 				format[0] = ' ';
4629230Smckusick 				fmtstart = 1 - REALSPC;
463768Speter 				break;
464768Speter 			case TSTR:
46514740Sthien 				(void) constval( alv );
466768Speter 				switch ( classify( con.ctype ) ) {
467768Speter 				    case TCHAR:
468768Speter 					typ = TCHAR;
469768Speter 					goto tchar;
470768Speter 				    case TSTR:
471768Speter 					strptr = con.cpval;
472768Speter 					for (strnglen = 0;  *strptr++;  strnglen++) /* void */;
473768Speter 					strptr = con.cpval;
474768Speter 					break;
475768Speter 				    default:
476768Speter 					strnglen = width(ap);
477768Speter 					break;
478768Speter 				}
479768Speter 				fmt = 's';
480768Speter 				strfmt = fmtspec;
481768Speter 				if (fmtspec == NIL) {
482768Speter 					fmtspec = SKIP;
483768Speter 					break;
484768Speter 				}
485768Speter 				if (fmtspec & CONWIDTH) {
486768Speter 					if (field <= strnglen) {
487768Speter 						fmtspec = SKIP;
488768Speter 						break;
489768Speter 					} else
490768Speter 						field -= strnglen;
491768Speter 				}
492768Speter 				/*
493768Speter 				 * push string to implement leading blank padding
494768Speter 				 */
49514740Sthien 				(void) put(2, O_LVCON, 2);
496768Speter 				putstr("", 0);
4973172Smckusic 				stkcnt += sizeof(char *);
498768Speter 				break;
499768Speter 			default:
500768Speter 				error("Can't write %ss to a text file", clnames[typ]);
501768Speter 				continue;
502768Speter 			}
503768Speter 			/*
504768Speter 			 * If there is a variable precision, evaluate it onto
505768Speter 			 * the stack
506768Speter 			 */
507768Speter 			if (fmtspec & VARPREC) {
50814740Sthien 				ap = stkrval(al->wexpr_node.expr3, NLNIL ,
50914740Sthien 						(long) RREQ );
510768Speter 				if (ap == NIL)
511768Speter 					continue;
512768Speter 				if (isnta(ap,"i")) {
513768Speter 					error("Second write width must be integer, not %s", nameof(ap));
514768Speter 					continue;
515768Speter 				}
516768Speter 				if ( opt( 't' ) ) {
51714740Sthien 				    (void) put(3, O_MAX, 0, 0);
518768Speter 				}
5193172Smckusic 				convert(nl+T4INT, INT_TYP);
5203172Smckusic 				stkcnt += sizeof(int);
521768Speter 			}
522768Speter 			/*
523768Speter 			 * If there is a variable width, evaluate it onto
524768Speter 			 * the stack
525768Speter 			 */
526768Speter 			if (fmtspec & VARWIDTH) {
527768Speter 				if ( ( typ == TDOUBLE && fmtspec == VARWIDTH )
528768Speter 				    || typ == TSTR ) {
5293226Smckusic 					soffset = sizes[cbn].curtmps;
53014740Sthien 					tempnlp = tmpalloc((long) (sizeof(long)),
5313226Smckusic 						nl+T4INT, REGOK);
53214740Sthien 					(void) put(2, O_LV | cbn << 8 + INDX,
5333851Speter 					    tempnlp -> value[ NL_OFFS ] );
534768Speter 				}
53514740Sthien 				ap = stkrval(al->wexpr_node.expr2, NLNIL, (long) RREQ );
536768Speter 				if (ap == NIL)
537768Speter 					continue;
538768Speter 				if (isnta(ap,"i")) {
539768Speter 					error("First write width must be integer, not %s", nameof(ap));
540768Speter 					continue;
541768Speter 				}
542768Speter 				/*
543768Speter 				 * Perform special processing on widths based
544768Speter 				 * on data type
545768Speter 				 */
546768Speter 				switch (typ) {
547768Speter 				case TDOUBLE:
548768Speter 					if (fmtspec == VARWIDTH) {
5493076Smckusic 						fmt = 'e';
55014740Sthien 						(void) put(1, O_AS4);
55114740Sthien 						(void) put(2, O_RV4 | cbn << 8 + INDX,
5523851Speter 						    tempnlp -> value[NL_OFFS] );
55314740Sthien 					        (void) put(3, O_MAX,
55411882Smckusick 						    5 + EXPOSIZE + REALSPC, 1);
5553172Smckusic 						convert(nl+T4INT, INT_TYP);
5563172Smckusic 						stkcnt += sizeof(int);
55714740Sthien 						(void) put(2, O_RV4 | cbn << 8 + INDX,
5583851Speter 						    tempnlp->value[NL_OFFS] );
559768Speter 						fmtspec += VARPREC;
5603226Smckusic 						tmpfree(&soffset);
561768Speter 					}
56214740Sthien 					(void) put(3, O_MAX, REALSPC, 1);
563768Speter 					break;
564768Speter 				case TSTR:
56514740Sthien 					(void) put(1, O_AS4);
56614740Sthien 					(void) put(2, O_RV4 | cbn << 8 + INDX,
5673851Speter 					    tempnlp -> value[ NL_OFFS ] );
56814740Sthien 					(void) put(3, O_MAX, strnglen, 0);
569768Speter 					break;
570768Speter 				default:
571768Speter 					if ( opt( 't' ) ) {
57214740Sthien 					    (void) put(3, O_MAX, 0, 0);
573768Speter 					}
574768Speter 					break;
575768Speter 				}
5763172Smckusic 				convert(nl+T4INT, INT_TYP);
5773172Smckusic 				stkcnt += sizeof(int);
578768Speter 			}
579768Speter 			/*
580768Speter 			 * Generate the format string
581768Speter 			 */
582768Speter 			switch (fmtspec) {
583768Speter 			default:
584768Speter 				panic("fmt2");
585768Speter 			case SKIP:
586768Speter 				break;
5872073Smckusic 			case NIL:
5882073Smckusic 				sprintf(&format[1], "%%%c", fmt);
5892073Smckusic 				goto fmtgen;
590768Speter 			case CONWIDTH:
5913076Smckusic 				sprintf(&format[1], "%%%d%c", field, fmt);
592768Speter 				goto fmtgen;
593768Speter 			case VARWIDTH:
594768Speter 				sprintf(&format[1], "%%*%c", fmt);
595768Speter 				goto fmtgen;
596768Speter 			case CONWIDTH + CONPREC:
5973076Smckusic 				sprintf(&format[1], "%%%d.%d%c", field, prec, fmt);
598768Speter 				goto fmtgen;
599768Speter 			case CONWIDTH + VARPREC:
6003076Smckusic 				sprintf(&format[1], "%%%d.*%c", field, fmt);
601768Speter 				goto fmtgen;
602768Speter 			case VARWIDTH + CONPREC:
6033076Smckusic 				sprintf(&format[1], "%%*.%d%c", prec, fmt);
604768Speter 				goto fmtgen;
605768Speter 			case VARWIDTH + VARPREC:
606768Speter 				sprintf(&format[1], "%%*.*%c", fmt);
607768Speter 			fmtgen:
608768Speter 				fmtlen = lenstr(&format[fmtstart], 0);
60914740Sthien 				(void) put(2, O_LVCON, fmtlen);
610768Speter 				putstr(&format[fmtstart], 0);
61114740Sthien 				(void) put(1, O_FILE);
6123172Smckusic 				stkcnt += 2 * sizeof(char *);
61314740Sthien 				(void) put(2, O_WRITEF, stkcnt);
614768Speter 			}
615768Speter 			/*
616768Speter 			 * Write the string after its blank padding
617768Speter 			 */
618768Speter 			if (typ == TSTR) {
61914740Sthien 				(void) put(1, O_FILE);
62014740Sthien 				(void) put(2, CON_INT, 1);
621768Speter 				if (strfmt & VARWIDTH) {
62214740Sthien 					(void) put(2, O_RV4 | cbn << 8 + INDX ,
6233851Speter 					    tempnlp -> value[ NL_OFFS ] );
62414740Sthien 					(void) put(2, O_MIN, strnglen);
6253172Smckusic 					convert(nl+T4INT, INT_TYP);
6263226Smckusic 					tmpfree(&soffset);
627768Speter 				} else {
628768Speter 					if ((fmtspec & SKIP) &&
629768Speter 					   (strfmt & CONWIDTH)) {
630768Speter 						strnglen = field;
631768Speter 					}
63214740Sthien 					(void) put(2, CON_INT, strnglen);
633768Speter 				}
63414740Sthien 				ap = stkrval(alv, NLNIL , (long) RREQ );
63514740Sthien 				(void) put(2, O_WRITES,
6363172Smckusic 					2 * sizeof(char *) + 2 * sizeof(int));
637768Speter 			}
638768Speter 		}
639768Speter 		/*
640768Speter 		 * Done with arguments.
641768Speter 		 * Handle writeln and
642768Speter 		 * insufficent number of args.
643768Speter 		 */
644768Speter 		switch (p->value[0] &~ NSTAND) {
645768Speter 			case O_WRITEF:
646768Speter 				if (argc == 0)
647768Speter 					error("Write requires an argument");
648768Speter 				break;
649768Speter 			case O_MESSAGE:
650768Speter 				if (argc == 0)
651768Speter 					error("Message requires an argument");
652768Speter 			case O_WRITLN:
653768Speter 				if (filetype != nl+T1CHAR)
654768Speter 					error("Can't 'writeln' a non text file");
65514740Sthien 				(void) put(1, O_WRITLN);
656768Speter 				break;
657768Speter 		}
658768Speter 		return;
659768Speter 
660768Speter 	case O_READ4:
661768Speter 	case O_READLN:
662768Speter 		/*
663768Speter 		 * Set up default
664768Speter 		 * file "input".
665768Speter 		 */
666768Speter 		file = NIL;
667768Speter 		filetype = nl+T1CHAR;
668768Speter 		/*
669768Speter 		 * Determine the file implied
670768Speter 		 * for the read and generate
671768Speter 		 * code to make it the active file.
672768Speter 		 */
67314740Sthien 		if (argv != TR_NIL) {
674768Speter 			codeoff();
67514740Sthien 			ap = stkrval(argv->list_node.list, NLNIL, (long) RREQ );
676768Speter 			codeon();
67714740Sthien 			if (ap == NLNIL)
67814740Sthien 				argv = argv->list_node.next;
67914740Sthien 			if (ap != NLNIL && ap->class == FILET) {
680768Speter 				/*
681768Speter 				 * Got "read(f, ...", make
682768Speter 				 * f the active file, and save
683768Speter 				 * it and its type for use in
684768Speter 				 * processing the rest of the
685768Speter 				 * arguments to read.
686768Speter 				 */
68714740Sthien 				file = argv->list_node.list;
688768Speter 				filetype = ap->type;
68914740Sthien 				(void) stklval(argv->list_node.list, NIL );
69014740Sthien 				(void) put(1, O_UNIT);
69114740Sthien 				argv = argv->list_node.next;
692768Speter 				argc--;
693768Speter 			} else {
694768Speter 				/*
695768Speter 				 * Default is read from
696768Speter 				 * standard input.
697768Speter 				 */
69814740Sthien 				(void) put(1, O_UNITINP);
699768Speter 				input->nl_flags |= NUSED;
700768Speter 			}
701768Speter 		} else {
70214740Sthien 			(void) put(1, O_UNITINP);
703768Speter 			input->nl_flags |= NUSED;
704768Speter 		}
705768Speter 		/*
706768Speter 		 * Loop and process each
707768Speter 		 * of the arguments.
708768Speter 		 */
70914740Sthien 		for (; argv != TR_NIL; argv = argv->list_node.next) {
710768Speter 			/*
711768Speter 			 * Get the address of the target
712768Speter 			 * on the stack.
713768Speter 			 */
71414740Sthien 			al = argv->list_node.list;
71514740Sthien 			if (al == TR_NIL)
716768Speter 				continue;
71714740Sthien 			if (al->tag != T_VAR) {
718768Speter 				error("Arguments to %s must be variables, not expressions", p->symbol);
719768Speter 				continue;
720768Speter 			}
721768Speter 			ap = stklval(al, MOD|ASGN|NOUSE);
72214740Sthien 			if (ap == NLNIL)
723768Speter 				continue;
724768Speter 			if (filetype != nl+T1CHAR) {
725768Speter 				/*
726768Speter 				 * Generalized read, i.e.
727768Speter 				 * from a non-textfile.
728768Speter 				 */
72914740Sthien 				if (incompat(filetype, ap,
73014740Sthien 					argv->list_node.list )) {
731768Speter 					error("Type mismatch in read from non-text file");
732768Speter 					continue;
733768Speter 				}
734768Speter 				/*
735768Speter 				 * var := file ^;
736768Speter 				 */
737768Speter 				if (file != NIL)
738*16417Speter 				    (void) stklval(file, NIL);
739768Speter 				else /* Magic */
740*16417Speter 				    (void) put(2, PTR_RV, (int)input->value[0]);
74114740Sthien 				(void) put(1, O_FNIL);
742*16417Speter 				if (isa(filetype, "bcsi")) {
743*16417Speter 				    int filewidth = width(filetype);
744*16417Speter 
745*16417Speter 				    switch (filewidth) {
746*16417Speter 					case 4:
747*16417Speter 					    (void) put(1, O_IND4);
748*16417Speter 					    break;
749*16417Speter 					case 2:
750*16417Speter 					    (void) put(1, O_IND2);
751*16417Speter 					    break;
752*16417Speter 					case 1:
753*16417Speter 					    (void) put(1, O_IND1);
754*16417Speter 					    break;
755*16417Speter 					default:
756*16417Speter 					    (void) put(2, O_IND, filewidth);
757*16417Speter 				    }
758*16417Speter 				    convert(filetype, ap);
759*16417Speter 				    rangechk(ap, ap);
760*16417Speter 				    (void) gen(O_AS2, O_AS2,
761*16417Speter 					    filewidth, width(ap));
762*16417Speter 				} else {
763*16417Speter 				    (void) put(2, O_IND, width(filetype));
764*16417Speter 				    convert(filetype, ap);
765*16417Speter 				    (void) put(2, O_AS, width(ap));
766*16417Speter 				}
767768Speter 				/*
768768Speter 				 * get(file);
769768Speter 				 */
77014740Sthien 				(void) put(1, O_GET);
771768Speter 				continue;
772768Speter 			}
773768Speter 			typ = classify(ap);
774768Speter 			op = rdops(typ);
775768Speter 			if (op == NIL) {
776768Speter 				error("Can't read %ss from a text file", clnames[typ]);
777768Speter 				continue;
778768Speter 			}
779768Speter 			if (op != O_READE)
78014740Sthien 				(void) put(1, op);
781768Speter 			else {
78214740Sthien 				(void) put(2, op, (long)listnames(ap));
7831628Speter 				warning();
784768Speter 				if (opt('s')) {
785768Speter 					standard();
786768Speter 				}
7871628Speter 				error("Reading scalars from text files is non-standard");
788768Speter 			}
789768Speter 			/*
790768Speter 			 * Data read is on the stack.
791768Speter 			 * Assign it.
792768Speter 			 */
793768Speter 			if (op != O_READ8 && op != O_READE)
794768Speter 				rangechk(ap, op == O_READC ? ap : nl+T4INT);
79514740Sthien 			(void) gen(O_AS2, O_AS2, width(ap),
796768Speter 				op == O_READ8 ? 8 : op == O_READ4 ? 4 : 2);
797768Speter 		}
798768Speter 		/*
799768Speter 		 * Done with arguments.
800768Speter 		 * Handle readln and
801768Speter 		 * insufficient number of args.
802768Speter 		 */
803768Speter 		if (p->value[0] == O_READLN) {
804768Speter 			if (filetype != nl+T1CHAR)
805768Speter 				error("Can't 'readln' a non text file");
80614740Sthien 			(void) put(1, O_READLN);
807768Speter 		}
808768Speter 		else if (argc == 0)
809768Speter 			error("read requires an argument");
810768Speter 		return;
811768Speter 
812768Speter 	case O_GET:
813768Speter 	case O_PUT:
814768Speter 		if (argc != 1) {
815768Speter 			error("%s expects one argument", p->symbol);
816768Speter 			return;
817768Speter 		}
81814740Sthien 		ap = stklval(argv->list_node.list, NIL );
81914740Sthien 		if (ap == NLNIL)
820768Speter 			return;
821768Speter 		if (ap->class != FILET) {
822768Speter 			error("Argument to %s must be a file, not %s", p->symbol, nameof(ap));
823768Speter 			return;
824768Speter 		}
82514740Sthien 		(void) put(1, O_UNIT);
82614740Sthien 		(void) put(1, op);
827768Speter 		return;
828768Speter 
829768Speter 	case O_RESET:
830768Speter 	case O_REWRITE:
831768Speter 		if (argc == 0 || argc > 2) {
832768Speter 			error("%s expects one or two arguments", p->symbol);
833768Speter 			return;
834768Speter 		}
835768Speter 		if (opt('s') && argc == 2) {
836768Speter 			standard();
837768Speter 			error("Two argument forms of reset and rewrite are non-standard");
838768Speter 		}
8392073Smckusic 		codeoff();
84014740Sthien 		ap = stklval(argv->list_node.list, MOD|NOUSE);
8412073Smckusic 		codeon();
84214740Sthien 		if (ap == NLNIL)
843768Speter 			return;
844768Speter 		if (ap->class != FILET) {
845768Speter 			error("First argument to %s must be a file, not %s", p->symbol, nameof(ap));
846768Speter 			return;
847768Speter 		}
84814740Sthien 		(void) put(2, O_CON24, text(ap) ? 0: width(ap->type));
849768Speter 		if (argc == 2) {
850768Speter 			/*
851768Speter 			 * Optional second argument
852768Speter 			 * is a string name of a
853768Speter 			 * UNIX (R) file to be associated.
854768Speter 			 */
85514740Sthien 			al = argv->list_node.next;
8562073Smckusic 			codeoff();
85714740Sthien 			al = (struct tnode *) stkrval(al->list_node.list,
85814740Sthien 					(struct nl *) NOFLAGS , (long) RREQ );
8592073Smckusic 			codeon();
86014740Sthien 			if (al == TR_NIL)
861768Speter 				return;
86214740Sthien 			if (classify((struct nl *) al) != TSTR) {
86314740Sthien 				error("Second argument to %s must be a string, not %s", p->symbol, nameof((struct nl *) al));
864768Speter 				return;
865768Speter 			}
86614740Sthien 			(void) put(2, O_CON24, width((struct nl *) al));
86714740Sthien 			al = argv->list_node.next;
86814740Sthien 			al = (struct tnode *) stkrval(al->list_node.list,
86914740Sthien 					(struct nl *) NOFLAGS , (long) RREQ );
870768Speter 		} else {
87114740Sthien 			(void) put(2, O_CON24, 0);
87214740Sthien 			(void) put(2, PTR_CON, NIL);
873768Speter 		}
87414740Sthien 		ap = stklval(argv->list_node.list, MOD|NOUSE);
87514740Sthien 		(void) put(1, op);
876768Speter 		return;
877768Speter 
878768Speter 	case O_NEW:
879768Speter 	case O_DISPOSE:
880768Speter 		if (argc == 0) {
881768Speter 			error("%s expects at least one argument", p->symbol);
882768Speter 			return;
883768Speter 		}
88414740Sthien 		ap = stklval(argv->list_node.list,
88514740Sthien 				op == O_NEW ? ( MOD | NOUSE ) : MOD );
88614740Sthien 		if (ap == NLNIL)
887768Speter 			return;
888768Speter 		if (ap->class != PTR) {
889768Speter 			error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap));
890768Speter 			return;
891768Speter 		}
892768Speter 		ap = ap->type;
893768Speter 		if (ap == NIL)
894768Speter 			return;
8957966Smckusick 		if ((ap->nl_flags & NFILES) && op == O_DISPOSE)
8967966Smckusick 			op = O_DFDISP;
89714740Sthien 		argv = argv->list_node.next;
89814740Sthien 		if (argv != TR_NIL) {
899768Speter 			if (ap->class != RECORD) {
900768Speter 				error("Record required when specifying variant tags");
901768Speter 				return;
902768Speter 			}
90314740Sthien 			for (; argv != TR_NIL; argv = argv->list_node.next) {
904768Speter 				if (ap->ptr[NL_VARNT] == NIL) {
905768Speter 					error("Too many tag fields");
906768Speter 					return;
907768Speter 				}
90814740Sthien 				if (!isconst(argv->list_node.list)) {
909768Speter 					error("Second and successive arguments to %s must be constants", p->symbol);
910768Speter 					return;
911768Speter 				}
91214740Sthien 				gconst(argv->list_node.list);
913768Speter 				if (con.ctype == NIL)
914768Speter 					return;
91514740Sthien 				if (incompat(con.ctype, (
91614740Sthien 					ap->ptr[NL_TAG])->type , TR_NIL )) {
917768Speter 					cerror("Specified tag constant type clashed with variant case selector type");
918768Speter 					return;
919768Speter 				}
920768Speter 				for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain)
921768Speter 					if (ap->range[0] == con.crval)
922768Speter 						break;
923768Speter 				if (ap == NIL) {
924768Speter 					error("No variant case label value equals specified constant value");
925768Speter 					return;
926768Speter 				}
927768Speter 				ap = ap->ptr[NL_VTOREC];
928768Speter 			}
929768Speter 		}
93014740Sthien 		(void) put(2, op, width(ap));
931768Speter 		return;
932768Speter 
933768Speter 	case O_DATE:
934768Speter 	case O_TIME:
935768Speter 		if (argc != 1) {
936768Speter 			error("%s expects one argument", p->symbol);
937768Speter 			return;
938768Speter 		}
93914740Sthien 		ap = stklval(argv->list_node.list, MOD|NOUSE);
94014740Sthien 		if (ap == NLNIL)
941768Speter 			return;
942768Speter 		if (classify(ap) != TSTR || width(ap) != 10) {
943768Speter 			error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap));
944768Speter 			return;
945768Speter 		}
94614740Sthien 		(void) put(1, op);
947768Speter 		return;
948768Speter 
949768Speter 	case O_HALT:
950768Speter 		if (argc != 0) {
951768Speter 			error("halt takes no arguments");
952768Speter 			return;
953768Speter 		}
95414740Sthien 		(void) put(1, op);
95514740Sthien 		noreach = TRUE; /* used to be 1 */
956768Speter 		return;
957768Speter 
958768Speter 	case O_ARGV:
959768Speter 		if (argc != 2) {
960768Speter 			error("argv takes two arguments");
961768Speter 			return;
962768Speter 		}
96314740Sthien 		ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ );
96414740Sthien 		if (ap == NLNIL)
965768Speter 			return;
966768Speter 		if (isnta(ap, "i")) {
967768Speter 			error("argv's first argument must be an integer, not %s", nameof(ap));
968768Speter 			return;
969768Speter 		}
97014740Sthien 		al = argv->list_node.next;
97114740Sthien 		ap = stklval(al->list_node.list, MOD|NOUSE);
97214740Sthien 		if (ap == NLNIL)
973768Speter 			return;
974768Speter 		if (classify(ap) != TSTR) {
975768Speter 			error("argv's second argument must be a string, not %s", nameof(ap));
976768Speter 			return;
977768Speter 		}
97814740Sthien 		(void) put(2, op, width(ap));
979768Speter 		return;
980768Speter 
981768Speter 	case O_STLIM:
982768Speter 		if (argc != 1) {
983768Speter 			error("stlimit requires one argument");
984768Speter 			return;
985768Speter 		}
98614740Sthien 		ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ );
98714740Sthien 		if (ap == NLNIL)
988768Speter 			return;
989768Speter 		if (isnta(ap, "i")) {
990768Speter 			error("stlimit's argument must be an integer, not %s", nameof(ap));
991768Speter 			return;
992768Speter 		}
993768Speter 		if (width(ap) != 4)
99414740Sthien 			(void) put(1, O_STOI);
99514740Sthien 		(void) put(1, op);
996768Speter 		return;
997768Speter 
998768Speter 	case O_REMOVE:
999768Speter 		if (argc != 1) {
1000768Speter 			error("remove expects one argument");
1001768Speter 			return;
1002768Speter 		}
10032073Smckusic 		codeoff();
100414740Sthien 		ap = stkrval(argv->list_node.list, (struct nl *) NOFLAGS,
100514740Sthien 				(long) RREQ );
10062073Smckusic 		codeon();
100714740Sthien 		if (ap == NLNIL)
1008768Speter 			return;
1009768Speter 		if (classify(ap) != TSTR) {
1010768Speter 			error("remove's argument must be a string, not %s", nameof(ap));
1011768Speter 			return;
1012768Speter 		}
101314740Sthien 		(void) put(2, O_CON24, width(ap));
101414740Sthien 		ap = stkrval(argv->list_node.list, (struct nl *) NOFLAGS,
101514740Sthien 				(long) RREQ );
101614740Sthien 		(void) put(1, op);
1017768Speter 		return;
1018768Speter 
1019768Speter 	case O_LLIMIT:
1020768Speter 		if (argc != 2) {
1021768Speter 			error("linelimit expects two arguments");
1022768Speter 			return;
1023768Speter 		}
102414740Sthien 		al = argv->list_node.next;
102514740Sthien 		ap = stkrval(al->list_node.list, NLNIL , (long) RREQ );
1026768Speter 		if (ap == NIL)
1027768Speter 			return;
1028768Speter 		if (isnta(ap, "i")) {
1029768Speter 			error("linelimit's second argument must be an integer, not %s", nameof(ap));
1030768Speter 			return;
1031768Speter 		}
103214740Sthien 		ap = stklval(argv->list_node.list, NOFLAGS|NOUSE);
103314740Sthien 		if (ap == NLNIL)
10342073Smckusic 			return;
10352073Smckusic 		if (!text(ap)) {
10362073Smckusic 			error("linelimit's first argument must be a text file, not %s", nameof(ap));
10372073Smckusic 			return;
10382073Smckusic 		}
103914740Sthien 		(void) put(1, op);
1040768Speter 		return;
1041768Speter 	case O_PAGE:
1042768Speter 		if (argc != 1) {
1043768Speter 			error("page expects one argument");
1044768Speter 			return;
1045768Speter 		}
104614740Sthien 		ap = stklval(argv->list_node.list, NIL );
104714740Sthien 		if (ap == NLNIL)
1048768Speter 			return;
1049768Speter 		if (!text(ap)) {
1050768Speter 			error("Argument to page must be a text file, not %s", nameof(ap));
1051768Speter 			return;
1052768Speter 		}
105314740Sthien 		(void) put(1, O_UNIT);
105414740Sthien 		(void) put(1, op);
1055768Speter 		return;
1056768Speter 
10577928Smckusick 	case O_ASRT:
10587928Smckusick 		if (!opt('t'))
10597928Smckusick 			return;
10607928Smckusick 		if (argc == 0 || argc > 2) {
10617928Smckusick 			error("Assert expects one or two arguments");
10627928Smckusick 			return;
10637928Smckusick 		}
10647928Smckusick 		if (argc == 2) {
10657928Smckusick 			/*
10667928Smckusick 			 * Optional second argument is a string specifying
10677928Smckusick 			 * why the assertion failed.
10687928Smckusick 			 */
106914740Sthien 			al = argv->list_node.next;
107014740Sthien 			al1 =  stkrval(al->list_node.list, NLNIL , (long) RREQ );
107114740Sthien 			if (al1 == NIL)
10727928Smckusick 				return;
107314740Sthien 			if (classify(al1) != TSTR) {
107414740Sthien 				error("Second argument to assert must be a string, not %s", nameof(al1));
10757928Smckusick 				return;
10767928Smckusick 			}
10777928Smckusick 		} else {
107814740Sthien 			(void) put(2, PTR_CON, NIL);
10797928Smckusick 		}
108014740Sthien 		ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ );
10817928Smckusick 		if (ap == NIL)
10827928Smckusick 			return;
10837928Smckusick 		if (isnta(ap, "b"))
10847928Smckusick 			error("Assert expression must be Boolean, not %ss", nameof(ap));
108514740Sthien 		(void) put(1, O_ASRT);
10867928Smckusick 		return;
10877928Smckusick 
1088768Speter 	case O_PACK:
1089768Speter 		if (argc != 3) {
1090768Speter 			error("pack expects three arguments");
1091768Speter 			return;
1092768Speter 		}
1093768Speter 		pu = "pack(a,i,z)";
109414740Sthien 		pua = argv->list_node.list;
109514740Sthien 		al = argv->list_node.next;
109614740Sthien 		pui = al->list_node.list;
109714740Sthien 		alv = al->list_node.next;
109814740Sthien 		puz = alv->list_node.list;
1099768Speter 		goto packunp;
1100768Speter 	case O_UNPACK:
1101768Speter 		if (argc != 3) {
1102768Speter 			error("unpack expects three arguments");
1103768Speter 			return;
1104768Speter 		}
1105768Speter 		pu = "unpack(z,a,i)";
110614740Sthien 		puz = argv->list_node.list;
110714740Sthien 		al = argv->list_node.next;
110814740Sthien 		pua = al->list_node.list;
110914740Sthien 		alv = al->list_node.next;
111014740Sthien 		pui = alv->list_node.list;
1111768Speter packunp:
11122073Smckusic 		codeoff();
1113768Speter 		ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE);
111414740Sthien 		al1 = stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE);
11152073Smckusic 		codeon();
1116768Speter 		if (ap == NIL)
1117768Speter 			return;
1118768Speter 		if (ap->class != ARRAY) {
1119768Speter 			error("%s requires a to be an unpacked array, not %s", pu, nameof(ap));
1120768Speter 			return;
1121768Speter 		}
112214740Sthien 		if (al1->class != ARRAY) {
1123768Speter 			error("%s requires z to be a packed array, not %s", pu, nameof(ap));
1124768Speter 			return;
1125768Speter 		}
112614740Sthien 		if (al1->type == NIL || ap->type == NIL)
1127768Speter 			return;
112814740Sthien 		if (al1->type != ap->type) {
1129768Speter 			error("%s requires a and z to be arrays of the same type", pu, nameof(ap));
1130768Speter 			return;
1131768Speter 		}
113214740Sthien 		k = width(al1);
1133768Speter 		itemwidth = width(ap->type);
1134768Speter 		ap = ap->chain;
113514740Sthien 		al1 = al1->chain;
113614740Sthien 		if (ap->chain != NIL || al1->chain != NIL) {
1137768Speter 			error("%s requires a and z to be single dimension arrays", pu);
1138768Speter 			return;
1139768Speter 		}
114014740Sthien 		if (ap == NIL || al1 == NIL)
1141768Speter 			return;
1142768Speter 		/*
114314740Sthien 		 * al1 is the range for z i.e. u..v
1144768Speter 		 * ap is the range for a i.e. m..n
1145768Speter 		 * i will be n-m+1
1146768Speter 		 * j will be v-u+1
1147768Speter 		 */
1148768Speter 		i = ap->range[1] - ap->range[0] + 1;
114914740Sthien 		j = al1->range[1] - al1->range[0] + 1;
1150768Speter 		if (i < j) {
115114740Sthien 			error("%s cannot have more elements in a (%d) than in z (%d)", pu, (char *) j, (char *) i);
1152768Speter 			return;
1153768Speter 		}
1154768Speter 		/*
1155768Speter 		 * get n-m-(v-u) and m for the interpreter
1156768Speter 		 */
1157768Speter 		i -= j;
1158768Speter 		j = ap->range[0];
115914740Sthien 		(void) put(2, O_CON24, k);
116014740Sthien 		(void) put(2, O_CON24, i);
116114740Sthien 		(void) put(2, O_CON24, j);
116214740Sthien 		(void) put(2, O_CON24, itemwidth);
116314740Sthien 		al1 = stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE);
11642073Smckusic 		ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE);
116514740Sthien 		ap = stkrval(pui, NLNIL , (long) RREQ );
11662073Smckusic 		if (ap == NIL)
11672073Smckusic 			return;
116814740Sthien 		(void) put(1, op);
1169768Speter 		return;
1170768Speter 	case 0:
11717928Smckusick 		error("%s is an unimplemented extension", p->symbol);
1172768Speter 		return;
1173768Speter 
1174768Speter 	default:
1175768Speter 		panic("proc case");
1176768Speter 	}
1177768Speter }
1178768Speter #endif OBJ
1179