xref: /csrg-svn/usr.bin/pascal/src/proc.c (revision 62213)
148116Sbostic /*-
2*62213Sbostic  * Copyright (c) 1980, 1993
3*62213Sbostic  *	The Regents of the University of California.  All rights reserved.
448116Sbostic  *
548116Sbostic  * %sccs.include.redist.c%
622186Sdist  */
7768Speter 
814740Sthien #ifndef lint
9*62213Sbostic static char sccsid[] = "@(#)proc.c	8.1 (Berkeley) 06/06/93";
1048116Sbostic #endif /* not lint */
11768Speter 
12768Speter #include "whoami.h"
13768Speter #ifdef OBJ
14768Speter     /*
15768Speter      *	and the rest of the file
16768Speter      */
17768Speter #include "0.h"
18768Speter #include "tree.h"
19768Speter #include "opcode.h"
20768Speter #include "objfmt.h"
2111327Speter #include "tmps.h"
2214740Sthien #include "tree_ty.h"
23768Speter 
24768Speter /*
2511882Smckusick  * The constant EXPOSIZE specifies the number of digits in the exponent
2611882Smckusick  * of real numbers.
2711882Smckusick  *
289230Smckusick  * The constant REALSPC defines the amount of forced padding preceeding
299230Smckusick  * real numbers when they are printed. If REALSPC == 0, then no padding
309230Smckusick  * is added, REALSPC == 1 adds one extra blank irregardless of the width
319230Smckusick  * specified by the user.
329230Smckusick  *
339230Smckusick  * N.B. - Values greater than one require program mods.
349230Smckusick  */
3511882Smckusick #define EXPOSIZE	2
3611882Smckusick #define	REALSPC		0
379230Smckusick 
389230Smckusick /*
39768Speter  * The following array is used to determine which classes may be read
40768Speter  * from textfiles. It is indexed by the return value from classify.
41768Speter  */
42768Speter #define rdops(x) rdxxxx[(x)-(TFIRST)]
43768Speter 
44768Speter int rdxxxx[] = {
45768Speter 	0,		/* -7 file types */
46768Speter 	0,		/* -6 record types */
47768Speter 	0,		/* -5 array types */
48768Speter 	O_READE,	/* -4 scalar types */
49768Speter 	0,		/* -3 pointer types */
50768Speter 	0,		/* -2 set types */
51768Speter 	0,		/* -1 string types */
52768Speter 	0,		/*  0 nil, no type */
53768Speter 	O_READE,	/*  1 boolean */
54768Speter 	O_READC,	/*  2 character */
55768Speter 	O_READ4,	/*  3 integer */
56768Speter 	O_READ8		/*  4 real */
57768Speter };
58768Speter 
59768Speter /*
60768Speter  * Proc handles procedure calls.
61768Speter  * Non-builtin procedures are "buck-passed" to func (with a flag
62768Speter  * indicating that they are actually procedures.
63768Speter  * builtin procedures are handled here.
64768Speter  */
65768Speter proc(r)
6614740Sthien 	struct tnode *r;
67768Speter {
68768Speter 	register struct nl *p;
6914740Sthien 	register struct tnode *alv, *al;
7014740Sthien  	register int op;
7114740Sthien 	struct nl *filetype, *ap, *al1;
7214740Sthien 	int argc, typ, fmtspec, strfmt, stkcnt;
7314740Sthien 	struct tnode *argv;
7414740Sthien 	char fmt, format[20], *strptr, *pu;
7514740Sthien 	int prec, field, strnglen, fmtlen, fmtstart;
7614740Sthien 	struct tnode *pua, *pui, *puz, *file;
77768Speter 	int i, j, k;
78768Speter 	int itemwidth;
793226Smckusic 	struct tmps soffset;
803851Speter 	struct nl	*tempnlp;
81768Speter 
82768Speter #define	CONPREC 4
83768Speter #define	VARPREC 8
84768Speter #define	CONWIDTH 1
85768Speter #define	VARWIDTH 2
86768Speter #define SKIP 16
87768Speter 
88768Speter 	/*
89768Speter 	 * Verify that the name is
90768Speter 	 * defined and is that of a
91768Speter 	 * procedure.
92768Speter 	 */
9314740Sthien 	p = lookup(r->pcall_node.proc_id);
94768Speter 	if (p == NIL) {
9514740Sthien 		rvlist(r->pcall_node.arg);
96768Speter 		return;
97768Speter 	}
981198Speter 	if (p->class != PROC && p->class != FPROC) {
99768Speter 		error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]);
10014740Sthien 		rvlist(r->pcall_node.arg);
101768Speter 		return;
102768Speter 	}
10314740Sthien 	argv = r->pcall_node.arg;
104768Speter 
105768Speter 	/*
106768Speter 	 * Call handles user defined
107768Speter 	 * procedures and functions.
108768Speter 	 */
109768Speter 	if (bn != 0) {
11014740Sthien 		(void) call(p, argv, PROC, bn);
111768Speter 		return;
112768Speter 	}
113768Speter 
114768Speter 	/*
115768Speter 	 * Call to built-in procedure.
116768Speter 	 * Count the arguments.
117768Speter 	 */
118768Speter 	argc = 0;
11914740Sthien 	for (al = argv; al != TR_NIL; al = al->list_node.next)
120768Speter 		argc++;
121768Speter 
122768Speter 	/*
123768Speter 	 * Switch on the operator
124768Speter 	 * associated with the built-in
125768Speter 	 * procedure in the namelist
126768Speter 	 */
127768Speter 	op = p->value[0] &~ NSTAND;
128768Speter 	if (opt('s') && (p->value[0] & NSTAND)) {
129768Speter 		standard();
130768Speter 		error("%s is a nonstandard procedure", p->symbol);
131768Speter 	}
132768Speter 	switch (op) {
133768Speter 
134768Speter 	case O_ABORT:
135768Speter 		if (argc != 0)
136768Speter 			error("null takes no arguments");
137768Speter 		return;
138768Speter 
139768Speter 	case O_FLUSH:
140768Speter 		if (argc == 0) {
14114740Sthien 			(void) put(1, O_MESSAGE);
142768Speter 			return;
143768Speter 		}
144768Speter 		if (argc != 1) {
145768Speter 			error("flush takes at most one argument");
146768Speter 			return;
147768Speter 		}
14814740Sthien 		ap = stklval(argv->list_node.list, NIL );
14914740Sthien 		if (ap == NLNIL)
150768Speter 			return;
151768Speter 		if (ap->class != FILET) {
152768Speter 			error("flush's argument must be a file, not %s", nameof(ap));
153768Speter 			return;
154768Speter 		}
15514740Sthien 		(void) put(1, op);
156768Speter 		return;
157768Speter 
158768Speter 	case O_MESSAGE:
159768Speter 	case O_WRITEF:
160768Speter 	case O_WRITLN:
161768Speter 		/*
162768Speter 		 * Set up default file "output"'s type
163768Speter 		 */
164768Speter 		file = NIL;
165768Speter 		filetype = nl+T1CHAR;
166768Speter 		/*
167768Speter 		 * Determine the file implied
168768Speter 		 * for the write and generate
169768Speter 		 * code to make it the active file.
170768Speter 		 */
171768Speter 		if (op == O_MESSAGE) {
172768Speter 			/*
173768Speter 			 * For message, all that matters
174768Speter 			 * is that the filetype is
175768Speter 			 * a character file.
176768Speter 			 * Thus "output" will suit us fine.
177768Speter 			 */
17814740Sthien 			(void) put(1, O_MESSAGE);
17914740Sthien 		} else if (argv != TR_NIL && (al = argv->list_node.list)->tag !=
18014740Sthien 					T_WEXP) {
181768Speter 			/*
182768Speter 			 * If there is a first argument which has
183768Speter 			 * no write widths, then it is potentially
184768Speter 			 * a file name.
185768Speter 			 */
186768Speter 			codeoff();
18714740Sthien 			ap = stkrval(argv->list_node.list, NLNIL, (long) RREQ );
188768Speter 			codeon();
18914740Sthien 			if (ap == NLNIL)
19014740Sthien 				argv = argv->list_node.next;
19114740Sthien 			if (ap != NLNIL && ap->class == FILET) {
192768Speter 				/*
193768Speter 				 * Got "write(f, ...", make
194768Speter 				 * f the active file, and save
195768Speter 				 * it and its type for use in
196768Speter 				 * processing the rest of the
197768Speter 				 * arguments to write.
198768Speter 				 */
19914740Sthien 				file = argv->list_node.list;
200768Speter 				filetype = ap->type;
20114740Sthien 				(void) stklval(argv->list_node.list, NIL );
20214740Sthien 				(void) put(1, O_UNIT);
203768Speter 				/*
204768Speter 				 * Skip over the first argument
205768Speter 				 */
20614740Sthien 				argv = argv->list_node.next;
207768Speter 				argc--;
2088538Speter 			} else {
209768Speter 				/*
210768Speter 				 * Set up for writing on
211768Speter 				 * standard output.
212768Speter 				 */
21314740Sthien 				(void) put(1, O_UNITOUT);
2147953Speter 				output->nl_flags |= NUSED;
2158538Speter 			}
2168538Speter 		} else {
21714740Sthien 			(void) put(1, O_UNITOUT);
2187953Speter 			output->nl_flags |= NUSED;
2198538Speter 		}
220768Speter 		/*
221768Speter 		 * Loop and process each
222768Speter 		 * of the arguments.
223768Speter 		 */
22414740Sthien 		for (; argv != TR_NIL; argv = argv->list_node.next) {
225768Speter 			/*
226768Speter 			 * fmtspec indicates the type (CONstant or VARiable)
227768Speter 			 *	and number (none, WIDTH, and/or PRECision)
228768Speter 			 *	of the fields in the printf format for this
229768Speter 			 *	output variable.
2303172Smckusic 			 * stkcnt is the number of bytes pushed on the stack
231768Speter 			 * fmt is the format output indicator (D, E, F, O, X, S)
232768Speter 			 * fmtstart = 0 for leading blank; = 1 for no blank
233768Speter 			 */
234768Speter 			fmtspec = NIL;
235768Speter 			stkcnt = 0;
236768Speter 			fmt = 'D';
237768Speter 			fmtstart = 1;
23814740Sthien 			al = argv->list_node.list;
23914740Sthien 			if (al == TR_NIL)
240768Speter 				continue;
24114740Sthien 			if (al->tag == T_WEXP)
24214740Sthien 				alv = al->wexpr_node.expr1;
243768Speter 			else
244768Speter 				alv = al;
24514740Sthien 			if (alv == TR_NIL)
246768Speter 				continue;
247768Speter 			codeoff();
24814740Sthien 			ap = stkrval(alv, NLNIL , (long) RREQ );
249768Speter 			codeon();
25014740Sthien 			if (ap == NLNIL)
251768Speter 				continue;
252768Speter 			typ = classify(ap);
25314740Sthien 			if (al->tag == T_WEXP) {
254768Speter 				/*
255768Speter 				 * Handle width expressions.
256768Speter 				 * The basic game here is that width
257768Speter 				 * expressions get evaluated. If they
258768Speter 				 * are constant, the value is placed
259768Speter 				 * directly in the format string.
260768Speter 				 * Otherwise the value is pushed onto
261768Speter 				 * the stack and an indirection is
262768Speter 				 * put into the format string.
263768Speter 				 */
26414740Sthien 				if (al->wexpr_node.expr3 ==
26514740Sthien 						(struct tnode *) OCT)
266768Speter 					fmt = 'O';
26714740Sthien 				else if (al->wexpr_node.expr3 ==
26814740Sthien 						(struct tnode *) HEX)
269768Speter 					fmt = 'X';
27014740Sthien 				else if (al->wexpr_node.expr3 != TR_NIL) {
271768Speter 					/*
272768Speter 					 * Evaluate second format spec
273768Speter 					 */
27414740Sthien 					if ( constval(al->wexpr_node.expr3)
275768Speter 					    && isa( con.ctype , "i" ) ) {
276768Speter 						fmtspec += CONPREC;
277768Speter 						prec = con.crval;
278768Speter 					} else {
279768Speter 						fmtspec += VARPREC;
280768Speter 					}
281768Speter 					fmt = 'f';
282768Speter 					switch ( typ ) {
283768Speter 					case TINT:
284768Speter 						if ( opt( 's' ) ) {
285768Speter 						    standard();
286768Speter 						    error("Writing %ss with two write widths is non-standard", clnames[typ]);
287768Speter 						}
288768Speter 						/* and fall through */
289768Speter 					case TDOUBLE:
290768Speter 						break;
291768Speter 					default:
292768Speter 						error("Cannot write %ss with two write widths", clnames[typ]);
293768Speter 						continue;
294768Speter 					}
295768Speter 				}
296768Speter 				/*
297768Speter 				 * Evaluate first format spec
298768Speter 				 */
29914740Sthien 				if (al->wexpr_node.expr2 != TR_NIL) {
30014740Sthien 					if ( constval(al->wexpr_node.expr2)
301768Speter 					    && isa( con.ctype , "i" ) ) {
302768Speter 						fmtspec += CONWIDTH;
303768Speter 						field = con.crval;
304768Speter 					} else {
305768Speter 						fmtspec += VARWIDTH;
306768Speter 					}
307768Speter 				}
308768Speter 				if ((fmtspec & CONPREC) && prec < 0 ||
309768Speter 				    (fmtspec & CONWIDTH) && field < 0) {
310768Speter 					error("Negative widths are not allowed");
311768Speter 					continue;
312768Speter 				}
3133179Smckusic 				if ( opt('s') &&
3143179Smckusic 				    ((fmtspec & CONPREC) && prec == 0 ||
3153179Smckusic 				    (fmtspec & CONWIDTH) && field == 0)) {
3163179Smckusic 					standard();
3173179Smckusic 					error("Zero widths are non-standard");
3183179Smckusic 				}
319768Speter 			}
320768Speter 			if (filetype != nl+T1CHAR) {
321768Speter 				if (fmt == 'O' || fmt == 'X') {
322768Speter 					error("Oct/hex allowed only on text files");
323768Speter 					continue;
324768Speter 				}
325768Speter 				if (fmtspec) {
326768Speter 					error("Write widths allowed only on text files");
327768Speter 					continue;
328768Speter 				}
329768Speter 				/*
330768Speter 				 * Generalized write, i.e.
331768Speter 				 * to a non-textfile.
332768Speter 				 */
33314740Sthien 				(void) stklval(file, NIL );
33414740Sthien 				(void) put(1, O_FNIL);
335768Speter 				/*
336768Speter 				 * file^ := ...
337768Speter 				 */
33814740Sthien 				ap = rvalue(argv->list_node.list, NLNIL, LREQ);
33914740Sthien 				if (ap == NLNIL)
340768Speter 					continue;
34114740Sthien 				if (incompat(ap, filetype,
34214740Sthien 						argv->list_node.list)) {
343768Speter 					cerror("Type mismatch in write to non-text file");
344768Speter 					continue;
345768Speter 				}
346768Speter 				convert(ap, filetype);
34714740Sthien 				(void) put(2, O_AS, width(filetype));
348768Speter 				/*
349768Speter 				 * put(file)
350768Speter 				 */
35114740Sthien 				(void) put(1, O_PUT);
352768Speter 				continue;
353768Speter 			}
354768Speter 			/*
355768Speter 			 * Write to a textfile
356768Speter 			 *
357768Speter 			 * Evaluate the expression
358768Speter 			 * to be written.
359768Speter 			 */
360768Speter 			if (fmt == 'O' || fmt == 'X') {
361768Speter 				if (opt('s')) {
362768Speter 					standard();
363768Speter 					error("Oct and hex are non-standard");
364768Speter 				}
365768Speter 				if (typ == TSTR || typ == TDOUBLE) {
366768Speter 					error("Can't write %ss with oct/hex", clnames[typ]);
367768Speter 					continue;
368768Speter 				}
369768Speter 				if (typ == TCHAR || typ == TBOOL)
370768Speter 					typ = TINT;
371768Speter 			}
372768Speter 			/*
373768Speter 			 * Place the arguement on the stack. If there is
374768Speter 			 * no format specified by the programmer, implement
375768Speter 			 * the default.
376768Speter 			 */
377768Speter 			switch (typ) {
3786542Smckusick 			case TPTR:
3796542Smckusick 				warning();
3806542Smckusick 				if (opt('s')) {
3816542Smckusick 					standard();
3826542Smckusick 				}
3836542Smckusick 				error("Writing %ss to text files is non-standard",
3846542Smckusick 				    clnames[typ]);
3856542Smckusick 				/* and fall through */
386768Speter 			case TINT:
387768Speter 				if (fmt != 'f') {
38814740Sthien 					ap = stkrval(alv, NLNIL, (long) RREQ );
3893172Smckusic 					stkcnt += sizeof(long);
390768Speter 				} else {
39114740Sthien 					ap = stkrval(alv, NLNIL, (long) RREQ );
39214740Sthien 					(void) put(1, O_ITOD);
3933172Smckusic 					stkcnt += sizeof(double);
394768Speter 					typ = TDOUBLE;
395768Speter 					goto tdouble;
396768Speter 				}
397768Speter 				if (fmtspec == NIL) {
398768Speter 					if (fmt == 'D')
399768Speter 						field = 10;
400768Speter 					else if (fmt == 'X')
401768Speter 						field = 8;
402768Speter 					else if (fmt == 'O')
403768Speter 						field = 11;
404768Speter 					else
405768Speter 						panic("fmt1");
406768Speter 					fmtspec = CONWIDTH;
407768Speter 				}
408768Speter 				break;
409768Speter 			case TCHAR:
410768Speter 			     tchar:
4112073Smckusic 				if (fmtspec == NIL) {
41214740Sthien 					(void) put(1, O_FILE);
41314740Sthien 					ap = stkrval(alv, NLNIL, (long) RREQ );
4143172Smckusic 					convert(nl + T4INT, INT_TYP);
41514740Sthien 					(void) put(2, O_WRITEC,
4163172Smckusic 						sizeof(char *) + sizeof(int));
4172073Smckusic 					fmtspec = SKIP;
4182073Smckusic 					break;
4192073Smckusic 				}
42014740Sthien 				ap = stkrval(alv, NLNIL , (long) RREQ );
4213172Smckusic 				convert(nl + T4INT, INT_TYP);
4223172Smckusic 				stkcnt += sizeof(int);
423768Speter 				fmt = 'c';
424768Speter 				break;
425768Speter 			case TSCAL:
4261628Speter 				warning();
427768Speter 				if (opt('s')) {
428768Speter 					standard();
429768Speter 				}
4306542Smckusick 				error("Writing %ss to text files is non-standard",
4316542Smckusick 				    clnames[typ]);
4326542Smckusick 				/* and fall through */
433768Speter 			case TBOOL:
43414740Sthien 				(void) stkrval(alv, NLNIL , (long) RREQ );
43514740Sthien 				(void) put(2, O_NAM, (long)listnames(ap));
4363172Smckusic 				stkcnt += sizeof(char *);
437768Speter 				fmt = 's';
438768Speter 				break;
439768Speter 			case TDOUBLE:
44014740Sthien 				ap = stkrval(alv, (struct nl *) TDOUBLE , (long) RREQ );
4413172Smckusic 				stkcnt += sizeof(double);
442768Speter 			     tdouble:
443768Speter 				switch (fmtspec) {
444768Speter 				case NIL:
44511882Smckusick 					field = 14 + (5 + EXPOSIZE);
44611882Smckusick 				        prec = field - (5 + EXPOSIZE);
4473076Smckusic 					fmt = 'e';
448768Speter 					fmtspec = CONWIDTH + CONPREC;
449768Speter 					break;
450768Speter 				case CONWIDTH:
4519230Smckusick 					field -= REALSPC;
4529230Smckusick 					if (field < 1)
453768Speter 						field = 1;
45411882Smckusick 				        prec = field - (5 + EXPOSIZE);
455768Speter 					if (prec < 1)
456768Speter 						prec = 1;
457768Speter 					fmtspec += CONPREC;
4583076Smckusic 					fmt = 'e';
459768Speter 					break;
460768Speter 				case CONWIDTH + CONPREC:
461768Speter 				case CONWIDTH + VARPREC:
4629230Smckusick 					field -= REALSPC;
4639230Smckusick 					if (field < 1)
464768Speter 						field = 1;
465768Speter 				}
466768Speter 				format[0] = ' ';
4679230Smckusick 				fmtstart = 1 - REALSPC;
468768Speter 				break;
469768Speter 			case TSTR:
47014740Sthien 				(void) constval( alv );
471768Speter 				switch ( classify( con.ctype ) ) {
472768Speter 				    case TCHAR:
473768Speter 					typ = TCHAR;
474768Speter 					goto tchar;
475768Speter 				    case TSTR:
476768Speter 					strptr = con.cpval;
477768Speter 					for (strnglen = 0;  *strptr++;  strnglen++) /* void */;
478768Speter 					strptr = con.cpval;
479768Speter 					break;
480768Speter 				    default:
481768Speter 					strnglen = width(ap);
482768Speter 					break;
483768Speter 				}
484768Speter 				fmt = 's';
485768Speter 				strfmt = fmtspec;
486768Speter 				if (fmtspec == NIL) {
487768Speter 					fmtspec = SKIP;
488768Speter 					break;
489768Speter 				}
490768Speter 				if (fmtspec & CONWIDTH) {
491768Speter 					if (field <= strnglen) {
492768Speter 						fmtspec = SKIP;
493768Speter 						break;
494768Speter 					} else
495768Speter 						field -= strnglen;
496768Speter 				}
497768Speter 				/*
498768Speter 				 * push string to implement leading blank padding
499768Speter 				 */
50014740Sthien 				(void) put(2, O_LVCON, 2);
501768Speter 				putstr("", 0);
5023172Smckusic 				stkcnt += sizeof(char *);
503768Speter 				break;
504768Speter 			default:
505768Speter 				error("Can't write %ss to a text file", clnames[typ]);
506768Speter 				continue;
507768Speter 			}
508768Speter 			/*
509768Speter 			 * If there is a variable precision, evaluate it onto
510768Speter 			 * the stack
511768Speter 			 */
512768Speter 			if (fmtspec & VARPREC) {
51314740Sthien 				ap = stkrval(al->wexpr_node.expr3, NLNIL ,
51414740Sthien 						(long) RREQ );
515768Speter 				if (ap == NIL)
516768Speter 					continue;
517768Speter 				if (isnta(ap,"i")) {
518768Speter 					error("Second write width must be integer, not %s", nameof(ap));
519768Speter 					continue;
520768Speter 				}
521768Speter 				if ( opt( 't' ) ) {
52214740Sthien 				    (void) put(3, O_MAX, 0, 0);
523768Speter 				}
5243172Smckusic 				convert(nl+T4INT, INT_TYP);
5253172Smckusic 				stkcnt += sizeof(int);
526768Speter 			}
527768Speter 			/*
528768Speter 			 * If there is a variable width, evaluate it onto
529768Speter 			 * the stack
530768Speter 			 */
531768Speter 			if (fmtspec & VARWIDTH) {
532768Speter 				if ( ( typ == TDOUBLE && fmtspec == VARWIDTH )
533768Speter 				    || typ == TSTR ) {
5343226Smckusic 					soffset = sizes[cbn].curtmps;
53514740Sthien 					tempnlp = tmpalloc((long) (sizeof(long)),
5363226Smckusic 						nl+T4INT, REGOK);
53714740Sthien 					(void) put(2, O_LV | cbn << 8 + INDX,
5383851Speter 					    tempnlp -> value[ NL_OFFS ] );
539768Speter 				}
54014740Sthien 				ap = stkrval(al->wexpr_node.expr2, NLNIL, (long) RREQ );
541768Speter 				if (ap == NIL)
542768Speter 					continue;
543768Speter 				if (isnta(ap,"i")) {
544768Speter 					error("First write width must be integer, not %s", nameof(ap));
545768Speter 					continue;
546768Speter 				}
547768Speter 				/*
548768Speter 				 * Perform special processing on widths based
549768Speter 				 * on data type
550768Speter 				 */
551768Speter 				switch (typ) {
552768Speter 				case TDOUBLE:
553768Speter 					if (fmtspec == VARWIDTH) {
5543076Smckusic 						fmt = 'e';
55514740Sthien 						(void) put(1, O_AS4);
55614740Sthien 						(void) put(2, O_RV4 | cbn << 8 + INDX,
5573851Speter 						    tempnlp -> value[NL_OFFS] );
55814740Sthien 					        (void) put(3, O_MAX,
55911882Smckusick 						    5 + EXPOSIZE + REALSPC, 1);
5603172Smckusic 						convert(nl+T4INT, INT_TYP);
5613172Smckusic 						stkcnt += sizeof(int);
56214740Sthien 						(void) put(2, O_RV4 | cbn << 8 + INDX,
5633851Speter 						    tempnlp->value[NL_OFFS] );
564768Speter 						fmtspec += VARPREC;
5653226Smckusic 						tmpfree(&soffset);
566768Speter 					}
56714740Sthien 					(void) put(3, O_MAX, REALSPC, 1);
568768Speter 					break;
569768Speter 				case TSTR:
57014740Sthien 					(void) put(1, O_AS4);
57114740Sthien 					(void) put(2, O_RV4 | cbn << 8 + INDX,
5723851Speter 					    tempnlp -> value[ NL_OFFS ] );
57314740Sthien 					(void) put(3, O_MAX, strnglen, 0);
574768Speter 					break;
575768Speter 				default:
576768Speter 					if ( opt( 't' ) ) {
57714740Sthien 					    (void) put(3, O_MAX, 0, 0);
578768Speter 					}
579768Speter 					break;
580768Speter 				}
5813172Smckusic 				convert(nl+T4INT, INT_TYP);
5823172Smckusic 				stkcnt += sizeof(int);
583768Speter 			}
584768Speter 			/*
585768Speter 			 * Generate the format string
586768Speter 			 */
587768Speter 			switch (fmtspec) {
588768Speter 			default:
589768Speter 				panic("fmt2");
590768Speter 			case SKIP:
591768Speter 				break;
5922073Smckusic 			case NIL:
5932073Smckusic 				sprintf(&format[1], "%%%c", fmt);
5942073Smckusic 				goto fmtgen;
595768Speter 			case CONWIDTH:
5963076Smckusic 				sprintf(&format[1], "%%%d%c", field, fmt);
597768Speter 				goto fmtgen;
598768Speter 			case VARWIDTH:
599768Speter 				sprintf(&format[1], "%%*%c", fmt);
600768Speter 				goto fmtgen;
601768Speter 			case CONWIDTH + CONPREC:
6023076Smckusic 				sprintf(&format[1], "%%%d.%d%c", field, prec, fmt);
603768Speter 				goto fmtgen;
604768Speter 			case CONWIDTH + VARPREC:
6053076Smckusic 				sprintf(&format[1], "%%%d.*%c", field, fmt);
606768Speter 				goto fmtgen;
607768Speter 			case VARWIDTH + CONPREC:
6083076Smckusic 				sprintf(&format[1], "%%*.%d%c", prec, fmt);
609768Speter 				goto fmtgen;
610768Speter 			case VARWIDTH + VARPREC:
611768Speter 				sprintf(&format[1], "%%*.*%c", fmt);
612768Speter 			fmtgen:
613768Speter 				fmtlen = lenstr(&format[fmtstart], 0);
61414740Sthien 				(void) put(2, O_LVCON, fmtlen);
615768Speter 				putstr(&format[fmtstart], 0);
61614740Sthien 				(void) put(1, O_FILE);
6173172Smckusic 				stkcnt += 2 * sizeof(char *);
61814740Sthien 				(void) put(2, O_WRITEF, stkcnt);
619768Speter 			}
620768Speter 			/*
621768Speter 			 * Write the string after its blank padding
622768Speter 			 */
623768Speter 			if (typ == TSTR) {
62414740Sthien 				(void) put(1, O_FILE);
62514740Sthien 				(void) put(2, CON_INT, 1);
626768Speter 				if (strfmt & VARWIDTH) {
62714740Sthien 					(void) put(2, O_RV4 | cbn << 8 + INDX ,
6283851Speter 					    tempnlp -> value[ NL_OFFS ] );
62914740Sthien 					(void) put(2, O_MIN, strnglen);
6303172Smckusic 					convert(nl+T4INT, INT_TYP);
6313226Smckusic 					tmpfree(&soffset);
632768Speter 				} else {
633768Speter 					if ((fmtspec & SKIP) &&
634768Speter 					   (strfmt & CONWIDTH)) {
635768Speter 						strnglen = field;
636768Speter 					}
63714740Sthien 					(void) put(2, CON_INT, strnglen);
638768Speter 				}
63914740Sthien 				ap = stkrval(alv, NLNIL , (long) RREQ );
64014740Sthien 				(void) put(2, O_WRITES,
6413172Smckusic 					2 * sizeof(char *) + 2 * sizeof(int));
642768Speter 			}
643768Speter 		}
644768Speter 		/*
645768Speter 		 * Done with arguments.
646768Speter 		 * Handle writeln and
647768Speter 		 * insufficent number of args.
648768Speter 		 */
649768Speter 		switch (p->value[0] &~ NSTAND) {
650768Speter 			case O_WRITEF:
651768Speter 				if (argc == 0)
652768Speter 					error("Write requires an argument");
653768Speter 				break;
654768Speter 			case O_MESSAGE:
655768Speter 				if (argc == 0)
656768Speter 					error("Message requires an argument");
657768Speter 			case O_WRITLN:
658768Speter 				if (filetype != nl+T1CHAR)
659768Speter 					error("Can't 'writeln' a non text file");
66014740Sthien 				(void) put(1, O_WRITLN);
661768Speter 				break;
662768Speter 		}
663768Speter 		return;
664768Speter 
665768Speter 	case O_READ4:
666768Speter 	case O_READLN:
667768Speter 		/*
668768Speter 		 * Set up default
669768Speter 		 * file "input".
670768Speter 		 */
671768Speter 		file = NIL;
672768Speter 		filetype = nl+T1CHAR;
673768Speter 		/*
674768Speter 		 * Determine the file implied
675768Speter 		 * for the read and generate
676768Speter 		 * code to make it the active file.
677768Speter 		 */
67814740Sthien 		if (argv != TR_NIL) {
679768Speter 			codeoff();
68014740Sthien 			ap = stkrval(argv->list_node.list, NLNIL, (long) RREQ );
681768Speter 			codeon();
68214740Sthien 			if (ap == NLNIL)
68314740Sthien 				argv = argv->list_node.next;
68414740Sthien 			if (ap != NLNIL && ap->class == FILET) {
685768Speter 				/*
686768Speter 				 * Got "read(f, ...", make
687768Speter 				 * f the active file, and save
688768Speter 				 * it and its type for use in
689768Speter 				 * processing the rest of the
690768Speter 				 * arguments to read.
691768Speter 				 */
69214740Sthien 				file = argv->list_node.list;
693768Speter 				filetype = ap->type;
69414740Sthien 				(void) stklval(argv->list_node.list, NIL );
69514740Sthien 				(void) put(1, O_UNIT);
69614740Sthien 				argv = argv->list_node.next;
697768Speter 				argc--;
698768Speter 			} else {
699768Speter 				/*
700768Speter 				 * Default is read from
701768Speter 				 * standard input.
702768Speter 				 */
70314740Sthien 				(void) put(1, O_UNITINP);
704768Speter 				input->nl_flags |= NUSED;
705768Speter 			}
706768Speter 		} else {
70714740Sthien 			(void) put(1, O_UNITINP);
708768Speter 			input->nl_flags |= NUSED;
709768Speter 		}
710768Speter 		/*
711768Speter 		 * Loop and process each
712768Speter 		 * of the arguments.
713768Speter 		 */
71414740Sthien 		for (; argv != TR_NIL; argv = argv->list_node.next) {
715768Speter 			/*
716768Speter 			 * Get the address of the target
717768Speter 			 * on the stack.
718768Speter 			 */
71914740Sthien 			al = argv->list_node.list;
72014740Sthien 			if (al == TR_NIL)
721768Speter 				continue;
72214740Sthien 			if (al->tag != T_VAR) {
723768Speter 				error("Arguments to %s must be variables, not expressions", p->symbol);
724768Speter 				continue;
725768Speter 			}
726768Speter 			ap = stklval(al, MOD|ASGN|NOUSE);
72714740Sthien 			if (ap == NLNIL)
728768Speter 				continue;
729768Speter 			if (filetype != nl+T1CHAR) {
730768Speter 				/*
731768Speter 				 * Generalized read, i.e.
732768Speter 				 * from a non-textfile.
733768Speter 				 */
73414740Sthien 				if (incompat(filetype, ap,
73514740Sthien 					argv->list_node.list )) {
736768Speter 					error("Type mismatch in read from non-text file");
737768Speter 					continue;
738768Speter 				}
739768Speter 				/*
740768Speter 				 * var := file ^;
741768Speter 				 */
742768Speter 				if (file != NIL)
74316417Speter 				    (void) stklval(file, NIL);
744768Speter 				else /* Magic */
74516417Speter 				    (void) put(2, PTR_RV, (int)input->value[0]);
74614740Sthien 				(void) put(1, O_FNIL);
74716417Speter 				if (isa(filetype, "bcsi")) {
74816417Speter 				    int filewidth = width(filetype);
74916417Speter 
75016417Speter 				    switch (filewidth) {
75116417Speter 					case 4:
75216417Speter 					    (void) put(1, O_IND4);
75316417Speter 					    break;
75416417Speter 					case 2:
75516417Speter 					    (void) put(1, O_IND2);
75616417Speter 					    break;
75716417Speter 					case 1:
75816417Speter 					    (void) put(1, O_IND1);
75916417Speter 					    break;
76016417Speter 					default:
76116417Speter 					    (void) put(2, O_IND, filewidth);
76216417Speter 				    }
76316417Speter 				    convert(filetype, ap);
76416417Speter 				    rangechk(ap, ap);
76516417Speter 				    (void) gen(O_AS2, O_AS2,
76616417Speter 					    filewidth, width(ap));
76716417Speter 				} else {
76816417Speter 				    (void) put(2, O_IND, width(filetype));
76916417Speter 				    convert(filetype, ap);
77016417Speter 				    (void) put(2, O_AS, width(ap));
77116417Speter 				}
772768Speter 				/*
773768Speter 				 * get(file);
774768Speter 				 */
77514740Sthien 				(void) put(1, O_GET);
776768Speter 				continue;
777768Speter 			}
778768Speter 			typ = classify(ap);
779768Speter 			op = rdops(typ);
780768Speter 			if (op == NIL) {
781768Speter 				error("Can't read %ss from a text file", clnames[typ]);
782768Speter 				continue;
783768Speter 			}
784768Speter 			if (op != O_READE)
78514740Sthien 				(void) put(1, op);
786768Speter 			else {
78714740Sthien 				(void) put(2, op, (long)listnames(ap));
7881628Speter 				warning();
789768Speter 				if (opt('s')) {
790768Speter 					standard();
791768Speter 				}
7921628Speter 				error("Reading scalars from text files is non-standard");
793768Speter 			}
794768Speter 			/*
795768Speter 			 * Data read is on the stack.
796768Speter 			 * Assign it.
797768Speter 			 */
798768Speter 			if (op != O_READ8 && op != O_READE)
799768Speter 				rangechk(ap, op == O_READC ? ap : nl+T4INT);
80014740Sthien 			(void) gen(O_AS2, O_AS2, width(ap),
801768Speter 				op == O_READ8 ? 8 : op == O_READ4 ? 4 : 2);
802768Speter 		}
803768Speter 		/*
804768Speter 		 * Done with arguments.
805768Speter 		 * Handle readln and
806768Speter 		 * insufficient number of args.
807768Speter 		 */
808768Speter 		if (p->value[0] == O_READLN) {
809768Speter 			if (filetype != nl+T1CHAR)
810768Speter 				error("Can't 'readln' a non text file");
81114740Sthien 			(void) put(1, O_READLN);
812768Speter 		}
813768Speter 		else if (argc == 0)
814768Speter 			error("read requires an argument");
815768Speter 		return;
816768Speter 
817768Speter 	case O_GET:
818768Speter 	case O_PUT:
819768Speter 		if (argc != 1) {
820768Speter 			error("%s expects one argument", p->symbol);
821768Speter 			return;
822768Speter 		}
82314740Sthien 		ap = stklval(argv->list_node.list, NIL );
82414740Sthien 		if (ap == NLNIL)
825768Speter 			return;
826768Speter 		if (ap->class != FILET) {
827768Speter 			error("Argument to %s must be a file, not %s", p->symbol, nameof(ap));
828768Speter 			return;
829768Speter 		}
83014740Sthien 		(void) put(1, O_UNIT);
83114740Sthien 		(void) put(1, op);
832768Speter 		return;
833768Speter 
834768Speter 	case O_RESET:
835768Speter 	case O_REWRITE:
836768Speter 		if (argc == 0 || argc > 2) {
837768Speter 			error("%s expects one or two arguments", p->symbol);
838768Speter 			return;
839768Speter 		}
840768Speter 		if (opt('s') && argc == 2) {
841768Speter 			standard();
842768Speter 			error("Two argument forms of reset and rewrite are non-standard");
843768Speter 		}
8442073Smckusic 		codeoff();
84514740Sthien 		ap = stklval(argv->list_node.list, MOD|NOUSE);
8462073Smckusic 		codeon();
84714740Sthien 		if (ap == NLNIL)
848768Speter 			return;
849768Speter 		if (ap->class != FILET) {
850768Speter 			error("First argument to %s must be a file, not %s", p->symbol, nameof(ap));
851768Speter 			return;
852768Speter 		}
85314740Sthien 		(void) put(2, O_CON24, text(ap) ? 0: width(ap->type));
854768Speter 		if (argc == 2) {
855768Speter 			/*
856768Speter 			 * Optional second argument
857768Speter 			 * is a string name of a
858768Speter 			 * UNIX (R) file to be associated.
859768Speter 			 */
86014740Sthien 			al = argv->list_node.next;
8612073Smckusic 			codeoff();
86214740Sthien 			al = (struct tnode *) stkrval(al->list_node.list,
86314740Sthien 					(struct nl *) NOFLAGS , (long) RREQ );
8642073Smckusic 			codeon();
86514740Sthien 			if (al == TR_NIL)
866768Speter 				return;
86714740Sthien 			if (classify((struct nl *) al) != TSTR) {
86814740Sthien 				error("Second argument to %s must be a string, not %s", p->symbol, nameof((struct nl *) al));
869768Speter 				return;
870768Speter 			}
87114740Sthien 			(void) put(2, O_CON24, width((struct nl *) al));
87214740Sthien 			al = argv->list_node.next;
87314740Sthien 			al = (struct tnode *) stkrval(al->list_node.list,
87414740Sthien 					(struct nl *) NOFLAGS , (long) RREQ );
875768Speter 		} else {
87614740Sthien 			(void) put(2, O_CON24, 0);
87714740Sthien 			(void) put(2, PTR_CON, NIL);
878768Speter 		}
87914740Sthien 		ap = stklval(argv->list_node.list, MOD|NOUSE);
88014740Sthien 		(void) put(1, op);
881768Speter 		return;
882768Speter 
883768Speter 	case O_NEW:
884768Speter 	case O_DISPOSE:
885768Speter 		if (argc == 0) {
886768Speter 			error("%s expects at least one argument", p->symbol);
887768Speter 			return;
888768Speter 		}
88914740Sthien 		ap = stklval(argv->list_node.list,
89014740Sthien 				op == O_NEW ? ( MOD | NOUSE ) : MOD );
89114740Sthien 		if (ap == NLNIL)
892768Speter 			return;
893768Speter 		if (ap->class != PTR) {
894768Speter 			error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap));
895768Speter 			return;
896768Speter 		}
897768Speter 		ap = ap->type;
898768Speter 		if (ap == NIL)
899768Speter 			return;
9007966Smckusick 		if ((ap->nl_flags & NFILES) && op == O_DISPOSE)
9017966Smckusick 			op = O_DFDISP;
90214740Sthien 		argv = argv->list_node.next;
90314740Sthien 		if (argv != TR_NIL) {
904768Speter 			if (ap->class != RECORD) {
905768Speter 				error("Record required when specifying variant tags");
906768Speter 				return;
907768Speter 			}
90814740Sthien 			for (; argv != TR_NIL; argv = argv->list_node.next) {
909768Speter 				if (ap->ptr[NL_VARNT] == NIL) {
910768Speter 					error("Too many tag fields");
911768Speter 					return;
912768Speter 				}
91314740Sthien 				if (!isconst(argv->list_node.list)) {
914768Speter 					error("Second and successive arguments to %s must be constants", p->symbol);
915768Speter 					return;
916768Speter 				}
91714740Sthien 				gconst(argv->list_node.list);
918768Speter 				if (con.ctype == NIL)
919768Speter 					return;
92014740Sthien 				if (incompat(con.ctype, (
92114740Sthien 					ap->ptr[NL_TAG])->type , TR_NIL )) {
922768Speter 					cerror("Specified tag constant type clashed with variant case selector type");
923768Speter 					return;
924768Speter 				}
925768Speter 				for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain)
926768Speter 					if (ap->range[0] == con.crval)
927768Speter 						break;
928768Speter 				if (ap == NIL) {
929768Speter 					error("No variant case label value equals specified constant value");
930768Speter 					return;
931768Speter 				}
932768Speter 				ap = ap->ptr[NL_VTOREC];
933768Speter 			}
934768Speter 		}
93514740Sthien 		(void) put(2, op, width(ap));
936768Speter 		return;
937768Speter 
938768Speter 	case O_DATE:
939768Speter 	case O_TIME:
940768Speter 		if (argc != 1) {
941768Speter 			error("%s expects one argument", p->symbol);
942768Speter 			return;
943768Speter 		}
94414740Sthien 		ap = stklval(argv->list_node.list, MOD|NOUSE);
94514740Sthien 		if (ap == NLNIL)
946768Speter 			return;
947768Speter 		if (classify(ap) != TSTR || width(ap) != 10) {
948768Speter 			error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap));
949768Speter 			return;
950768Speter 		}
95114740Sthien 		(void) put(1, op);
952768Speter 		return;
953768Speter 
954768Speter 	case O_HALT:
955768Speter 		if (argc != 0) {
956768Speter 			error("halt takes no arguments");
957768Speter 			return;
958768Speter 		}
95914740Sthien 		(void) put(1, op);
96014740Sthien 		noreach = TRUE; /* used to be 1 */
961768Speter 		return;
962768Speter 
963768Speter 	case O_ARGV:
964768Speter 		if (argc != 2) {
965768Speter 			error("argv takes two arguments");
966768Speter 			return;
967768Speter 		}
96814740Sthien 		ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ );
96914740Sthien 		if (ap == NLNIL)
970768Speter 			return;
971768Speter 		if (isnta(ap, "i")) {
972768Speter 			error("argv's first argument must be an integer, not %s", nameof(ap));
973768Speter 			return;
974768Speter 		}
97514740Sthien 		al = argv->list_node.next;
97614740Sthien 		ap = stklval(al->list_node.list, MOD|NOUSE);
97714740Sthien 		if (ap == NLNIL)
978768Speter 			return;
979768Speter 		if (classify(ap) != TSTR) {
980768Speter 			error("argv's second argument must be a string, not %s", nameof(ap));
981768Speter 			return;
982768Speter 		}
98314740Sthien 		(void) put(2, op, width(ap));
984768Speter 		return;
985768Speter 
986768Speter 	case O_STLIM:
987768Speter 		if (argc != 1) {
988768Speter 			error("stlimit requires one argument");
989768Speter 			return;
990768Speter 		}
99114740Sthien 		ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ );
99214740Sthien 		if (ap == NLNIL)
993768Speter 			return;
994768Speter 		if (isnta(ap, "i")) {
995768Speter 			error("stlimit's argument must be an integer, not %s", nameof(ap));
996768Speter 			return;
997768Speter 		}
998768Speter 		if (width(ap) != 4)
99914740Sthien 			(void) put(1, O_STOI);
100014740Sthien 		(void) put(1, op);
1001768Speter 		return;
1002768Speter 
1003768Speter 	case O_REMOVE:
1004768Speter 		if (argc != 1) {
1005768Speter 			error("remove expects one argument");
1006768Speter 			return;
1007768Speter 		}
10082073Smckusic 		codeoff();
100914740Sthien 		ap = stkrval(argv->list_node.list, (struct nl *) NOFLAGS,
101014740Sthien 				(long) RREQ );
10112073Smckusic 		codeon();
101214740Sthien 		if (ap == NLNIL)
1013768Speter 			return;
1014768Speter 		if (classify(ap) != TSTR) {
1015768Speter 			error("remove's argument must be a string, not %s", nameof(ap));
1016768Speter 			return;
1017768Speter 		}
101814740Sthien 		(void) put(2, O_CON24, width(ap));
101914740Sthien 		ap = stkrval(argv->list_node.list, (struct nl *) NOFLAGS,
102014740Sthien 				(long) RREQ );
102114740Sthien 		(void) put(1, op);
1022768Speter 		return;
1023768Speter 
1024768Speter 	case O_LLIMIT:
1025768Speter 		if (argc != 2) {
1026768Speter 			error("linelimit expects two arguments");
1027768Speter 			return;
1028768Speter 		}
102914740Sthien 		al = argv->list_node.next;
103014740Sthien 		ap = stkrval(al->list_node.list, NLNIL , (long) RREQ );
1031768Speter 		if (ap == NIL)
1032768Speter 			return;
1033768Speter 		if (isnta(ap, "i")) {
1034768Speter 			error("linelimit's second argument must be an integer, not %s", nameof(ap));
1035768Speter 			return;
1036768Speter 		}
103714740Sthien 		ap = stklval(argv->list_node.list, NOFLAGS|NOUSE);
103814740Sthien 		if (ap == NLNIL)
10392073Smckusic 			return;
10402073Smckusic 		if (!text(ap)) {
10412073Smckusic 			error("linelimit's first argument must be a text file, not %s", nameof(ap));
10422073Smckusic 			return;
10432073Smckusic 		}
104414740Sthien 		(void) put(1, op);
1045768Speter 		return;
1046768Speter 	case O_PAGE:
1047768Speter 		if (argc != 1) {
1048768Speter 			error("page expects one argument");
1049768Speter 			return;
1050768Speter 		}
105114740Sthien 		ap = stklval(argv->list_node.list, NIL );
105214740Sthien 		if (ap == NLNIL)
1053768Speter 			return;
1054768Speter 		if (!text(ap)) {
1055768Speter 			error("Argument to page must be a text file, not %s", nameof(ap));
1056768Speter 			return;
1057768Speter 		}
105814740Sthien 		(void) put(1, O_UNIT);
105914740Sthien 		(void) put(1, op);
1060768Speter 		return;
1061768Speter 
10627928Smckusick 	case O_ASRT:
10637928Smckusick 		if (!opt('t'))
10647928Smckusick 			return;
10657928Smckusick 		if (argc == 0 || argc > 2) {
10667928Smckusick 			error("Assert expects one or two arguments");
10677928Smckusick 			return;
10687928Smckusick 		}
10697928Smckusick 		if (argc == 2) {
10707928Smckusick 			/*
10717928Smckusick 			 * Optional second argument is a string specifying
10727928Smckusick 			 * why the assertion failed.
10737928Smckusick 			 */
107414740Sthien 			al = argv->list_node.next;
107514740Sthien 			al1 =  stkrval(al->list_node.list, NLNIL , (long) RREQ );
107614740Sthien 			if (al1 == NIL)
10777928Smckusick 				return;
107814740Sthien 			if (classify(al1) != TSTR) {
107914740Sthien 				error("Second argument to assert must be a string, not %s", nameof(al1));
10807928Smckusick 				return;
10817928Smckusick 			}
10827928Smckusick 		} else {
108314740Sthien 			(void) put(2, PTR_CON, NIL);
10847928Smckusick 		}
108514740Sthien 		ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ );
10867928Smckusick 		if (ap == NIL)
10877928Smckusick 			return;
10887928Smckusick 		if (isnta(ap, "b"))
10897928Smckusick 			error("Assert expression must be Boolean, not %ss", nameof(ap));
109014740Sthien 		(void) put(1, O_ASRT);
10917928Smckusick 		return;
10927928Smckusick 
1093768Speter 	case O_PACK:
1094768Speter 		if (argc != 3) {
1095768Speter 			error("pack expects three arguments");
1096768Speter 			return;
1097768Speter 		}
1098768Speter 		pu = "pack(a,i,z)";
109914740Sthien 		pua = argv->list_node.list;
110014740Sthien 		al = argv->list_node.next;
110114740Sthien 		pui = al->list_node.list;
110214740Sthien 		alv = al->list_node.next;
110314740Sthien 		puz = alv->list_node.list;
1104768Speter 		goto packunp;
1105768Speter 	case O_UNPACK:
1106768Speter 		if (argc != 3) {
1107768Speter 			error("unpack expects three arguments");
1108768Speter 			return;
1109768Speter 		}
1110768Speter 		pu = "unpack(z,a,i)";
111114740Sthien 		puz = argv->list_node.list;
111214740Sthien 		al = argv->list_node.next;
111314740Sthien 		pua = al->list_node.list;
111414740Sthien 		alv = al->list_node.next;
111514740Sthien 		pui = alv->list_node.list;
1116768Speter packunp:
11172073Smckusic 		codeoff();
1118768Speter 		ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE);
111914740Sthien 		al1 = stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE);
11202073Smckusic 		codeon();
1121768Speter 		if (ap == NIL)
1122768Speter 			return;
1123768Speter 		if (ap->class != ARRAY) {
1124768Speter 			error("%s requires a to be an unpacked array, not %s", pu, nameof(ap));
1125768Speter 			return;
1126768Speter 		}
112714740Sthien 		if (al1->class != ARRAY) {
1128768Speter 			error("%s requires z to be a packed array, not %s", pu, nameof(ap));
1129768Speter 			return;
1130768Speter 		}
113114740Sthien 		if (al1->type == NIL || ap->type == NIL)
1132768Speter 			return;
113314740Sthien 		if (al1->type != ap->type) {
1134768Speter 			error("%s requires a and z to be arrays of the same type", pu, nameof(ap));
1135768Speter 			return;
1136768Speter 		}
113714740Sthien 		k = width(al1);
1138768Speter 		itemwidth = width(ap->type);
1139768Speter 		ap = ap->chain;
114014740Sthien 		al1 = al1->chain;
114114740Sthien 		if (ap->chain != NIL || al1->chain != NIL) {
1142768Speter 			error("%s requires a and z to be single dimension arrays", pu);
1143768Speter 			return;
1144768Speter 		}
114514740Sthien 		if (ap == NIL || al1 == NIL)
1146768Speter 			return;
1147768Speter 		/*
114814740Sthien 		 * al1 is the range for z i.e. u..v
1149768Speter 		 * ap is the range for a i.e. m..n
1150768Speter 		 * i will be n-m+1
1151768Speter 		 * j will be v-u+1
1152768Speter 		 */
1153768Speter 		i = ap->range[1] - ap->range[0] + 1;
115414740Sthien 		j = al1->range[1] - al1->range[0] + 1;
1155768Speter 		if (i < j) {
115614740Sthien 			error("%s cannot have more elements in a (%d) than in z (%d)", pu, (char *) j, (char *) i);
1157768Speter 			return;
1158768Speter 		}
1159768Speter 		/*
1160768Speter 		 * get n-m-(v-u) and m for the interpreter
1161768Speter 		 */
1162768Speter 		i -= j;
1163768Speter 		j = ap->range[0];
116414740Sthien 		(void) put(2, O_CON24, k);
116514740Sthien 		(void) put(2, O_CON24, i);
116614740Sthien 		(void) put(2, O_CON24, j);
116714740Sthien 		(void) put(2, O_CON24, itemwidth);
116814740Sthien 		al1 = stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE);
11692073Smckusic 		ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE);
117014740Sthien 		ap = stkrval(pui, NLNIL , (long) RREQ );
11712073Smckusic 		if (ap == NIL)
11722073Smckusic 			return;
117314740Sthien 		(void) put(1, op);
1174768Speter 		return;
1175768Speter 	case 0:
11767928Smckusick 		error("%s is an unimplemented extension", p->symbol);
1177768Speter 		return;
1178768Speter 
1179768Speter 	default:
1180768Speter 		panic("proc case");
1181768Speter 	}
1182768Speter }
1183768Speter #endif OBJ
1184