xref: /csrg-svn/usr.bin/pascal/src/proc.c (revision 22186)
1*22186Sdist /*
2*22186Sdist  * Copyright (c) 1980 Regents of the University of California.
3*22186Sdist  * All rights reserved.  The Berkeley software License Agreement
4*22186Sdist  * specifies the terms and conditions for redistribution.
5*22186Sdist  */
6768Speter 
714740Sthien #ifndef lint
8*22186Sdist static char sccsid[] = "@(#)proc.c	5.1 (Berkeley) 06/05/85";
9*22186Sdist #endif not lint
10768Speter 
11768Speter #include "whoami.h"
12768Speter #ifdef OBJ
13768Speter     /*
14768Speter      *	and the rest of the file
15768Speter      */
16768Speter #include "0.h"
17768Speter #include "tree.h"
18768Speter #include "opcode.h"
19768Speter #include "objfmt.h"
2011327Speter #include "tmps.h"
2114740Sthien #include "tree_ty.h"
22768Speter 
23768Speter /*
2411882Smckusick  * The constant EXPOSIZE specifies the number of digits in the exponent
2511882Smckusick  * of real numbers.
2611882Smckusick  *
279230Smckusick  * The constant REALSPC defines the amount of forced padding preceeding
289230Smckusick  * real numbers when they are printed. If REALSPC == 0, then no padding
299230Smckusick  * is added, REALSPC == 1 adds one extra blank irregardless of the width
309230Smckusick  * specified by the user.
319230Smckusick  *
329230Smckusick  * N.B. - Values greater than one require program mods.
339230Smckusick  */
3411882Smckusick #define EXPOSIZE	2
3511882Smckusick #define	REALSPC		0
369230Smckusick 
379230Smckusick /*
38768Speter  * The following array is used to determine which classes may be read
39768Speter  * from textfiles. It is indexed by the return value from classify.
40768Speter  */
41768Speter #define rdops(x) rdxxxx[(x)-(TFIRST)]
42768Speter 
43768Speter int rdxxxx[] = {
44768Speter 	0,		/* -7 file types */
45768Speter 	0,		/* -6 record types */
46768Speter 	0,		/* -5 array types */
47768Speter 	O_READE,	/* -4 scalar types */
48768Speter 	0,		/* -3 pointer types */
49768Speter 	0,		/* -2 set types */
50768Speter 	0,		/* -1 string types */
51768Speter 	0,		/*  0 nil, no type */
52768Speter 	O_READE,	/*  1 boolean */
53768Speter 	O_READC,	/*  2 character */
54768Speter 	O_READ4,	/*  3 integer */
55768Speter 	O_READ8		/*  4 real */
56768Speter };
57768Speter 
58768Speter /*
59768Speter  * Proc handles procedure calls.
60768Speter  * Non-builtin procedures are "buck-passed" to func (with a flag
61768Speter  * indicating that they are actually procedures.
62768Speter  * builtin procedures are handled here.
63768Speter  */
64768Speter proc(r)
6514740Sthien 	struct tnode *r;
66768Speter {
67768Speter 	register struct nl *p;
6814740Sthien 	register struct tnode *alv, *al;
6914740Sthien  	register int op;
7014740Sthien 	struct nl *filetype, *ap, *al1;
7114740Sthien 	int argc, typ, fmtspec, strfmt, stkcnt;
7214740Sthien 	struct tnode *argv;
7314740Sthien 	char fmt, format[20], *strptr, *pu;
7414740Sthien 	int prec, field, strnglen, fmtlen, fmtstart;
7514740Sthien 	struct tnode *pua, *pui, *puz, *file;
76768Speter 	int i, j, k;
77768Speter 	int itemwidth;
783226Smckusic 	struct tmps soffset;
793851Speter 	struct nl	*tempnlp;
80768Speter 
81768Speter #define	CONPREC 4
82768Speter #define	VARPREC 8
83768Speter #define	CONWIDTH 1
84768Speter #define	VARWIDTH 2
85768Speter #define SKIP 16
86768Speter 
87768Speter 	/*
88768Speter 	 * Verify that the name is
89768Speter 	 * defined and is that of a
90768Speter 	 * procedure.
91768Speter 	 */
9214740Sthien 	p = lookup(r->pcall_node.proc_id);
93768Speter 	if (p == NIL) {
9414740Sthien 		rvlist(r->pcall_node.arg);
95768Speter 		return;
96768Speter 	}
971198Speter 	if (p->class != PROC && p->class != FPROC) {
98768Speter 		error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]);
9914740Sthien 		rvlist(r->pcall_node.arg);
100768Speter 		return;
101768Speter 	}
10214740Sthien 	argv = r->pcall_node.arg;
103768Speter 
104768Speter 	/*
105768Speter 	 * Call handles user defined
106768Speter 	 * procedures and functions.
107768Speter 	 */
108768Speter 	if (bn != 0) {
10914740Sthien 		(void) call(p, argv, PROC, bn);
110768Speter 		return;
111768Speter 	}
112768Speter 
113768Speter 	/*
114768Speter 	 * Call to built-in procedure.
115768Speter 	 * Count the arguments.
116768Speter 	 */
117768Speter 	argc = 0;
11814740Sthien 	for (al = argv; al != TR_NIL; al = al->list_node.next)
119768Speter 		argc++;
120768Speter 
121768Speter 	/*
122768Speter 	 * Switch on the operator
123768Speter 	 * associated with the built-in
124768Speter 	 * procedure in the namelist
125768Speter 	 */
126768Speter 	op = p->value[0] &~ NSTAND;
127768Speter 	if (opt('s') && (p->value[0] & NSTAND)) {
128768Speter 		standard();
129768Speter 		error("%s is a nonstandard procedure", p->symbol);
130768Speter 	}
131768Speter 	switch (op) {
132768Speter 
133768Speter 	case O_ABORT:
134768Speter 		if (argc != 0)
135768Speter 			error("null takes no arguments");
136768Speter 		return;
137768Speter 
138768Speter 	case O_FLUSH:
139768Speter 		if (argc == 0) {
14014740Sthien 			(void) put(1, O_MESSAGE);
141768Speter 			return;
142768Speter 		}
143768Speter 		if (argc != 1) {
144768Speter 			error("flush takes at most one argument");
145768Speter 			return;
146768Speter 		}
14714740Sthien 		ap = stklval(argv->list_node.list, NIL );
14814740Sthien 		if (ap == NLNIL)
149768Speter 			return;
150768Speter 		if (ap->class != FILET) {
151768Speter 			error("flush's argument must be a file, not %s", nameof(ap));
152768Speter 			return;
153768Speter 		}
15414740Sthien 		(void) put(1, op);
155768Speter 		return;
156768Speter 
157768Speter 	case O_MESSAGE:
158768Speter 	case O_WRITEF:
159768Speter 	case O_WRITLN:
160768Speter 		/*
161768Speter 		 * Set up default file "output"'s type
162768Speter 		 */
163768Speter 		file = NIL;
164768Speter 		filetype = nl+T1CHAR;
165768Speter 		/*
166768Speter 		 * Determine the file implied
167768Speter 		 * for the write and generate
168768Speter 		 * code to make it the active file.
169768Speter 		 */
170768Speter 		if (op == O_MESSAGE) {
171768Speter 			/*
172768Speter 			 * For message, all that matters
173768Speter 			 * is that the filetype is
174768Speter 			 * a character file.
175768Speter 			 * Thus "output" will suit us fine.
176768Speter 			 */
17714740Sthien 			(void) put(1, O_MESSAGE);
17814740Sthien 		} else if (argv != TR_NIL && (al = argv->list_node.list)->tag !=
17914740Sthien 					T_WEXP) {
180768Speter 			/*
181768Speter 			 * If there is a first argument which has
182768Speter 			 * no write widths, then it is potentially
183768Speter 			 * a file name.
184768Speter 			 */
185768Speter 			codeoff();
18614740Sthien 			ap = stkrval(argv->list_node.list, NLNIL, (long) RREQ );
187768Speter 			codeon();
18814740Sthien 			if (ap == NLNIL)
18914740Sthien 				argv = argv->list_node.next;
19014740Sthien 			if (ap != NLNIL && ap->class == FILET) {
191768Speter 				/*
192768Speter 				 * Got "write(f, ...", make
193768Speter 				 * f the active file, and save
194768Speter 				 * it and its type for use in
195768Speter 				 * processing the rest of the
196768Speter 				 * arguments to write.
197768Speter 				 */
19814740Sthien 				file = argv->list_node.list;
199768Speter 				filetype = ap->type;
20014740Sthien 				(void) stklval(argv->list_node.list, NIL );
20114740Sthien 				(void) put(1, O_UNIT);
202768Speter 				/*
203768Speter 				 * Skip over the first argument
204768Speter 				 */
20514740Sthien 				argv = argv->list_node.next;
206768Speter 				argc--;
2078538Speter 			} else {
208768Speter 				/*
209768Speter 				 * Set up for writing on
210768Speter 				 * standard output.
211768Speter 				 */
21214740Sthien 				(void) put(1, O_UNITOUT);
2137953Speter 				output->nl_flags |= NUSED;
2148538Speter 			}
2158538Speter 		} else {
21614740Sthien 			(void) put(1, O_UNITOUT);
2177953Speter 			output->nl_flags |= NUSED;
2188538Speter 		}
219768Speter 		/*
220768Speter 		 * Loop and process each
221768Speter 		 * of the arguments.
222768Speter 		 */
22314740Sthien 		for (; argv != TR_NIL; argv = argv->list_node.next) {
224768Speter 			/*
225768Speter 			 * fmtspec indicates the type (CONstant or VARiable)
226768Speter 			 *	and number (none, WIDTH, and/or PRECision)
227768Speter 			 *	of the fields in the printf format for this
228768Speter 			 *	output variable.
2293172Smckusic 			 * stkcnt is the number of bytes pushed on the stack
230768Speter 			 * fmt is the format output indicator (D, E, F, O, X, S)
231768Speter 			 * fmtstart = 0 for leading blank; = 1 for no blank
232768Speter 			 */
233768Speter 			fmtspec = NIL;
234768Speter 			stkcnt = 0;
235768Speter 			fmt = 'D';
236768Speter 			fmtstart = 1;
23714740Sthien 			al = argv->list_node.list;
23814740Sthien 			if (al == TR_NIL)
239768Speter 				continue;
24014740Sthien 			if (al->tag == T_WEXP)
24114740Sthien 				alv = al->wexpr_node.expr1;
242768Speter 			else
243768Speter 				alv = al;
24414740Sthien 			if (alv == TR_NIL)
245768Speter 				continue;
246768Speter 			codeoff();
24714740Sthien 			ap = stkrval(alv, NLNIL , (long) RREQ );
248768Speter 			codeon();
24914740Sthien 			if (ap == NLNIL)
250768Speter 				continue;
251768Speter 			typ = classify(ap);
25214740Sthien 			if (al->tag == T_WEXP) {
253768Speter 				/*
254768Speter 				 * Handle width expressions.
255768Speter 				 * The basic game here is that width
256768Speter 				 * expressions get evaluated. If they
257768Speter 				 * are constant, the value is placed
258768Speter 				 * directly in the format string.
259768Speter 				 * Otherwise the value is pushed onto
260768Speter 				 * the stack and an indirection is
261768Speter 				 * put into the format string.
262768Speter 				 */
26314740Sthien 				if (al->wexpr_node.expr3 ==
26414740Sthien 						(struct tnode *) OCT)
265768Speter 					fmt = 'O';
26614740Sthien 				else if (al->wexpr_node.expr3 ==
26714740Sthien 						(struct tnode *) HEX)
268768Speter 					fmt = 'X';
26914740Sthien 				else if (al->wexpr_node.expr3 != TR_NIL) {
270768Speter 					/*
271768Speter 					 * Evaluate second format spec
272768Speter 					 */
27314740Sthien 					if ( constval(al->wexpr_node.expr3)
274768Speter 					    && isa( con.ctype , "i" ) ) {
275768Speter 						fmtspec += CONPREC;
276768Speter 						prec = con.crval;
277768Speter 					} else {
278768Speter 						fmtspec += VARPREC;
279768Speter 					}
280768Speter 					fmt = 'f';
281768Speter 					switch ( typ ) {
282768Speter 					case TINT:
283768Speter 						if ( opt( 's' ) ) {
284768Speter 						    standard();
285768Speter 						    error("Writing %ss with two write widths is non-standard", clnames[typ]);
286768Speter 						}
287768Speter 						/* and fall through */
288768Speter 					case TDOUBLE:
289768Speter 						break;
290768Speter 					default:
291768Speter 						error("Cannot write %ss with two write widths", clnames[typ]);
292768Speter 						continue;
293768Speter 					}
294768Speter 				}
295768Speter 				/*
296768Speter 				 * Evaluate first format spec
297768Speter 				 */
29814740Sthien 				if (al->wexpr_node.expr2 != TR_NIL) {
29914740Sthien 					if ( constval(al->wexpr_node.expr2)
300768Speter 					    && isa( con.ctype , "i" ) ) {
301768Speter 						fmtspec += CONWIDTH;
302768Speter 						field = con.crval;
303768Speter 					} else {
304768Speter 						fmtspec += VARWIDTH;
305768Speter 					}
306768Speter 				}
307768Speter 				if ((fmtspec & CONPREC) && prec < 0 ||
308768Speter 				    (fmtspec & CONWIDTH) && field < 0) {
309768Speter 					error("Negative widths are not allowed");
310768Speter 					continue;
311768Speter 				}
3123179Smckusic 				if ( opt('s') &&
3133179Smckusic 				    ((fmtspec & CONPREC) && prec == 0 ||
3143179Smckusic 				    (fmtspec & CONWIDTH) && field == 0)) {
3153179Smckusic 					standard();
3163179Smckusic 					error("Zero widths are non-standard");
3173179Smckusic 				}
318768Speter 			}
319768Speter 			if (filetype != nl+T1CHAR) {
320768Speter 				if (fmt == 'O' || fmt == 'X') {
321768Speter 					error("Oct/hex allowed only on text files");
322768Speter 					continue;
323768Speter 				}
324768Speter 				if (fmtspec) {
325768Speter 					error("Write widths allowed only on text files");
326768Speter 					continue;
327768Speter 				}
328768Speter 				/*
329768Speter 				 * Generalized write, i.e.
330768Speter 				 * to a non-textfile.
331768Speter 				 */
33214740Sthien 				(void) stklval(file, NIL );
33314740Sthien 				(void) put(1, O_FNIL);
334768Speter 				/*
335768Speter 				 * file^ := ...
336768Speter 				 */
33714740Sthien 				ap = rvalue(argv->list_node.list, NLNIL, LREQ);
33814740Sthien 				if (ap == NLNIL)
339768Speter 					continue;
34014740Sthien 				if (incompat(ap, filetype,
34114740Sthien 						argv->list_node.list)) {
342768Speter 					cerror("Type mismatch in write to non-text file");
343768Speter 					continue;
344768Speter 				}
345768Speter 				convert(ap, filetype);
34614740Sthien 				(void) put(2, O_AS, width(filetype));
347768Speter 				/*
348768Speter 				 * put(file)
349768Speter 				 */
35014740Sthien 				(void) put(1, O_PUT);
351768Speter 				continue;
352768Speter 			}
353768Speter 			/*
354768Speter 			 * Write to a textfile
355768Speter 			 *
356768Speter 			 * Evaluate the expression
357768Speter 			 * to be written.
358768Speter 			 */
359768Speter 			if (fmt == 'O' || fmt == 'X') {
360768Speter 				if (opt('s')) {
361768Speter 					standard();
362768Speter 					error("Oct and hex are non-standard");
363768Speter 				}
364768Speter 				if (typ == TSTR || typ == TDOUBLE) {
365768Speter 					error("Can't write %ss with oct/hex", clnames[typ]);
366768Speter 					continue;
367768Speter 				}
368768Speter 				if (typ == TCHAR || typ == TBOOL)
369768Speter 					typ = TINT;
370768Speter 			}
371768Speter 			/*
372768Speter 			 * Place the arguement on the stack. If there is
373768Speter 			 * no format specified by the programmer, implement
374768Speter 			 * the default.
375768Speter 			 */
376768Speter 			switch (typ) {
3776542Smckusick 			case TPTR:
3786542Smckusick 				warning();
3796542Smckusick 				if (opt('s')) {
3806542Smckusick 					standard();
3816542Smckusick 				}
3826542Smckusick 				error("Writing %ss to text files is non-standard",
3836542Smckusick 				    clnames[typ]);
3846542Smckusick 				/* and fall through */
385768Speter 			case TINT:
386768Speter 				if (fmt != 'f') {
38714740Sthien 					ap = stkrval(alv, NLNIL, (long) RREQ );
3883172Smckusic 					stkcnt += sizeof(long);
389768Speter 				} else {
39014740Sthien 					ap = stkrval(alv, NLNIL, (long) RREQ );
39114740Sthien 					(void) put(1, O_ITOD);
3923172Smckusic 					stkcnt += sizeof(double);
393768Speter 					typ = TDOUBLE;
394768Speter 					goto tdouble;
395768Speter 				}
396768Speter 				if (fmtspec == NIL) {
397768Speter 					if (fmt == 'D')
398768Speter 						field = 10;
399768Speter 					else if (fmt == 'X')
400768Speter 						field = 8;
401768Speter 					else if (fmt == 'O')
402768Speter 						field = 11;
403768Speter 					else
404768Speter 						panic("fmt1");
405768Speter 					fmtspec = CONWIDTH;
406768Speter 				}
407768Speter 				break;
408768Speter 			case TCHAR:
409768Speter 			     tchar:
4102073Smckusic 				if (fmtspec == NIL) {
41114740Sthien 					(void) put(1, O_FILE);
41214740Sthien 					ap = stkrval(alv, NLNIL, (long) RREQ );
4133172Smckusic 					convert(nl + T4INT, INT_TYP);
41414740Sthien 					(void) put(2, O_WRITEC,
4153172Smckusic 						sizeof(char *) + sizeof(int));
4162073Smckusic 					fmtspec = SKIP;
4172073Smckusic 					break;
4182073Smckusic 				}
41914740Sthien 				ap = stkrval(alv, NLNIL , (long) RREQ );
4203172Smckusic 				convert(nl + T4INT, INT_TYP);
4213172Smckusic 				stkcnt += sizeof(int);
422768Speter 				fmt = 'c';
423768Speter 				break;
424768Speter 			case TSCAL:
4251628Speter 				warning();
426768Speter 				if (opt('s')) {
427768Speter 					standard();
428768Speter 				}
4296542Smckusick 				error("Writing %ss to text files is non-standard",
4306542Smckusick 				    clnames[typ]);
4316542Smckusick 				/* and fall through */
432768Speter 			case TBOOL:
43314740Sthien 				(void) stkrval(alv, NLNIL , (long) RREQ );
43414740Sthien 				(void) put(2, O_NAM, (long)listnames(ap));
4353172Smckusic 				stkcnt += sizeof(char *);
436768Speter 				fmt = 's';
437768Speter 				break;
438768Speter 			case TDOUBLE:
43914740Sthien 				ap = stkrval(alv, (struct nl *) TDOUBLE , (long) RREQ );
4403172Smckusic 				stkcnt += sizeof(double);
441768Speter 			     tdouble:
442768Speter 				switch (fmtspec) {
443768Speter 				case NIL:
44411882Smckusick 					field = 14 + (5 + EXPOSIZE);
44511882Smckusick 				        prec = field - (5 + EXPOSIZE);
4463076Smckusic 					fmt = 'e';
447768Speter 					fmtspec = CONWIDTH + CONPREC;
448768Speter 					break;
449768Speter 				case CONWIDTH:
4509230Smckusick 					field -= REALSPC;
4519230Smckusick 					if (field < 1)
452768Speter 						field = 1;
45311882Smckusick 				        prec = field - (5 + EXPOSIZE);
454768Speter 					if (prec < 1)
455768Speter 						prec = 1;
456768Speter 					fmtspec += CONPREC;
4573076Smckusic 					fmt = 'e';
458768Speter 					break;
459768Speter 				case CONWIDTH + CONPREC:
460768Speter 				case CONWIDTH + VARPREC:
4619230Smckusick 					field -= REALSPC;
4629230Smckusick 					if (field < 1)
463768Speter 						field = 1;
464768Speter 				}
465768Speter 				format[0] = ' ';
4669230Smckusick 				fmtstart = 1 - REALSPC;
467768Speter 				break;
468768Speter 			case TSTR:
46914740Sthien 				(void) constval( alv );
470768Speter 				switch ( classify( con.ctype ) ) {
471768Speter 				    case TCHAR:
472768Speter 					typ = TCHAR;
473768Speter 					goto tchar;
474768Speter 				    case TSTR:
475768Speter 					strptr = con.cpval;
476768Speter 					for (strnglen = 0;  *strptr++;  strnglen++) /* void */;
477768Speter 					strptr = con.cpval;
478768Speter 					break;
479768Speter 				    default:
480768Speter 					strnglen = width(ap);
481768Speter 					break;
482768Speter 				}
483768Speter 				fmt = 's';
484768Speter 				strfmt = fmtspec;
485768Speter 				if (fmtspec == NIL) {
486768Speter 					fmtspec = SKIP;
487768Speter 					break;
488768Speter 				}
489768Speter 				if (fmtspec & CONWIDTH) {
490768Speter 					if (field <= strnglen) {
491768Speter 						fmtspec = SKIP;
492768Speter 						break;
493768Speter 					} else
494768Speter 						field -= strnglen;
495768Speter 				}
496768Speter 				/*
497768Speter 				 * push string to implement leading blank padding
498768Speter 				 */
49914740Sthien 				(void) put(2, O_LVCON, 2);
500768Speter 				putstr("", 0);
5013172Smckusic 				stkcnt += sizeof(char *);
502768Speter 				break;
503768Speter 			default:
504768Speter 				error("Can't write %ss to a text file", clnames[typ]);
505768Speter 				continue;
506768Speter 			}
507768Speter 			/*
508768Speter 			 * If there is a variable precision, evaluate it onto
509768Speter 			 * the stack
510768Speter 			 */
511768Speter 			if (fmtspec & VARPREC) {
51214740Sthien 				ap = stkrval(al->wexpr_node.expr3, NLNIL ,
51314740Sthien 						(long) RREQ );
514768Speter 				if (ap == NIL)
515768Speter 					continue;
516768Speter 				if (isnta(ap,"i")) {
517768Speter 					error("Second write width must be integer, not %s", nameof(ap));
518768Speter 					continue;
519768Speter 				}
520768Speter 				if ( opt( 't' ) ) {
52114740Sthien 				    (void) put(3, O_MAX, 0, 0);
522768Speter 				}
5233172Smckusic 				convert(nl+T4INT, INT_TYP);
5243172Smckusic 				stkcnt += sizeof(int);
525768Speter 			}
526768Speter 			/*
527768Speter 			 * If there is a variable width, evaluate it onto
528768Speter 			 * the stack
529768Speter 			 */
530768Speter 			if (fmtspec & VARWIDTH) {
531768Speter 				if ( ( typ == TDOUBLE && fmtspec == VARWIDTH )
532768Speter 				    || typ == TSTR ) {
5333226Smckusic 					soffset = sizes[cbn].curtmps;
53414740Sthien 					tempnlp = tmpalloc((long) (sizeof(long)),
5353226Smckusic 						nl+T4INT, REGOK);
53614740Sthien 					(void) put(2, O_LV | cbn << 8 + INDX,
5373851Speter 					    tempnlp -> value[ NL_OFFS ] );
538768Speter 				}
53914740Sthien 				ap = stkrval(al->wexpr_node.expr2, NLNIL, (long) RREQ );
540768Speter 				if (ap == NIL)
541768Speter 					continue;
542768Speter 				if (isnta(ap,"i")) {
543768Speter 					error("First write width must be integer, not %s", nameof(ap));
544768Speter 					continue;
545768Speter 				}
546768Speter 				/*
547768Speter 				 * Perform special processing on widths based
548768Speter 				 * on data type
549768Speter 				 */
550768Speter 				switch (typ) {
551768Speter 				case TDOUBLE:
552768Speter 					if (fmtspec == VARWIDTH) {
5533076Smckusic 						fmt = 'e';
55414740Sthien 						(void) put(1, O_AS4);
55514740Sthien 						(void) put(2, O_RV4 | cbn << 8 + INDX,
5563851Speter 						    tempnlp -> value[NL_OFFS] );
55714740Sthien 					        (void) put(3, O_MAX,
55811882Smckusick 						    5 + EXPOSIZE + REALSPC, 1);
5593172Smckusic 						convert(nl+T4INT, INT_TYP);
5603172Smckusic 						stkcnt += sizeof(int);
56114740Sthien 						(void) put(2, O_RV4 | cbn << 8 + INDX,
5623851Speter 						    tempnlp->value[NL_OFFS] );
563768Speter 						fmtspec += VARPREC;
5643226Smckusic 						tmpfree(&soffset);
565768Speter 					}
56614740Sthien 					(void) put(3, O_MAX, REALSPC, 1);
567768Speter 					break;
568768Speter 				case TSTR:
56914740Sthien 					(void) put(1, O_AS4);
57014740Sthien 					(void) put(2, O_RV4 | cbn << 8 + INDX,
5713851Speter 					    tempnlp -> value[ NL_OFFS ] );
57214740Sthien 					(void) put(3, O_MAX, strnglen, 0);
573768Speter 					break;
574768Speter 				default:
575768Speter 					if ( opt( 't' ) ) {
57614740Sthien 					    (void) put(3, O_MAX, 0, 0);
577768Speter 					}
578768Speter 					break;
579768Speter 				}
5803172Smckusic 				convert(nl+T4INT, INT_TYP);
5813172Smckusic 				stkcnt += sizeof(int);
582768Speter 			}
583768Speter 			/*
584768Speter 			 * Generate the format string
585768Speter 			 */
586768Speter 			switch (fmtspec) {
587768Speter 			default:
588768Speter 				panic("fmt2");
589768Speter 			case SKIP:
590768Speter 				break;
5912073Smckusic 			case NIL:
5922073Smckusic 				sprintf(&format[1], "%%%c", fmt);
5932073Smckusic 				goto fmtgen;
594768Speter 			case CONWIDTH:
5953076Smckusic 				sprintf(&format[1], "%%%d%c", field, fmt);
596768Speter 				goto fmtgen;
597768Speter 			case VARWIDTH:
598768Speter 				sprintf(&format[1], "%%*%c", fmt);
599768Speter 				goto fmtgen;
600768Speter 			case CONWIDTH + CONPREC:
6013076Smckusic 				sprintf(&format[1], "%%%d.%d%c", field, prec, fmt);
602768Speter 				goto fmtgen;
603768Speter 			case CONWIDTH + VARPREC:
6043076Smckusic 				sprintf(&format[1], "%%%d.*%c", field, fmt);
605768Speter 				goto fmtgen;
606768Speter 			case VARWIDTH + CONPREC:
6073076Smckusic 				sprintf(&format[1], "%%*.%d%c", prec, fmt);
608768Speter 				goto fmtgen;
609768Speter 			case VARWIDTH + VARPREC:
610768Speter 				sprintf(&format[1], "%%*.*%c", fmt);
611768Speter 			fmtgen:
612768Speter 				fmtlen = lenstr(&format[fmtstart], 0);
61314740Sthien 				(void) put(2, O_LVCON, fmtlen);
614768Speter 				putstr(&format[fmtstart], 0);
61514740Sthien 				(void) put(1, O_FILE);
6163172Smckusic 				stkcnt += 2 * sizeof(char *);
61714740Sthien 				(void) put(2, O_WRITEF, stkcnt);
618768Speter 			}
619768Speter 			/*
620768Speter 			 * Write the string after its blank padding
621768Speter 			 */
622768Speter 			if (typ == TSTR) {
62314740Sthien 				(void) put(1, O_FILE);
62414740Sthien 				(void) put(2, CON_INT, 1);
625768Speter 				if (strfmt & VARWIDTH) {
62614740Sthien 					(void) put(2, O_RV4 | cbn << 8 + INDX ,
6273851Speter 					    tempnlp -> value[ NL_OFFS ] );
62814740Sthien 					(void) put(2, O_MIN, strnglen);
6293172Smckusic 					convert(nl+T4INT, INT_TYP);
6303226Smckusic 					tmpfree(&soffset);
631768Speter 				} else {
632768Speter 					if ((fmtspec & SKIP) &&
633768Speter 					   (strfmt & CONWIDTH)) {
634768Speter 						strnglen = field;
635768Speter 					}
63614740Sthien 					(void) put(2, CON_INT, strnglen);
637768Speter 				}
63814740Sthien 				ap = stkrval(alv, NLNIL , (long) RREQ );
63914740Sthien 				(void) put(2, O_WRITES,
6403172Smckusic 					2 * sizeof(char *) + 2 * sizeof(int));
641768Speter 			}
642768Speter 		}
643768Speter 		/*
644768Speter 		 * Done with arguments.
645768Speter 		 * Handle writeln and
646768Speter 		 * insufficent number of args.
647768Speter 		 */
648768Speter 		switch (p->value[0] &~ NSTAND) {
649768Speter 			case O_WRITEF:
650768Speter 				if (argc == 0)
651768Speter 					error("Write requires an argument");
652768Speter 				break;
653768Speter 			case O_MESSAGE:
654768Speter 				if (argc == 0)
655768Speter 					error("Message requires an argument");
656768Speter 			case O_WRITLN:
657768Speter 				if (filetype != nl+T1CHAR)
658768Speter 					error("Can't 'writeln' a non text file");
65914740Sthien 				(void) put(1, O_WRITLN);
660768Speter 				break;
661768Speter 		}
662768Speter 		return;
663768Speter 
664768Speter 	case O_READ4:
665768Speter 	case O_READLN:
666768Speter 		/*
667768Speter 		 * Set up default
668768Speter 		 * file "input".
669768Speter 		 */
670768Speter 		file = NIL;
671768Speter 		filetype = nl+T1CHAR;
672768Speter 		/*
673768Speter 		 * Determine the file implied
674768Speter 		 * for the read and generate
675768Speter 		 * code to make it the active file.
676768Speter 		 */
67714740Sthien 		if (argv != TR_NIL) {
678768Speter 			codeoff();
67914740Sthien 			ap = stkrval(argv->list_node.list, NLNIL, (long) RREQ );
680768Speter 			codeon();
68114740Sthien 			if (ap == NLNIL)
68214740Sthien 				argv = argv->list_node.next;
68314740Sthien 			if (ap != NLNIL && ap->class == FILET) {
684768Speter 				/*
685768Speter 				 * Got "read(f, ...", make
686768Speter 				 * f the active file, and save
687768Speter 				 * it and its type for use in
688768Speter 				 * processing the rest of the
689768Speter 				 * arguments to read.
690768Speter 				 */
69114740Sthien 				file = argv->list_node.list;
692768Speter 				filetype = ap->type;
69314740Sthien 				(void) stklval(argv->list_node.list, NIL );
69414740Sthien 				(void) put(1, O_UNIT);
69514740Sthien 				argv = argv->list_node.next;
696768Speter 				argc--;
697768Speter 			} else {
698768Speter 				/*
699768Speter 				 * Default is read from
700768Speter 				 * standard input.
701768Speter 				 */
70214740Sthien 				(void) put(1, O_UNITINP);
703768Speter 				input->nl_flags |= NUSED;
704768Speter 			}
705768Speter 		} else {
70614740Sthien 			(void) put(1, O_UNITINP);
707768Speter 			input->nl_flags |= NUSED;
708768Speter 		}
709768Speter 		/*
710768Speter 		 * Loop and process each
711768Speter 		 * of the arguments.
712768Speter 		 */
71314740Sthien 		for (; argv != TR_NIL; argv = argv->list_node.next) {
714768Speter 			/*
715768Speter 			 * Get the address of the target
716768Speter 			 * on the stack.
717768Speter 			 */
71814740Sthien 			al = argv->list_node.list;
71914740Sthien 			if (al == TR_NIL)
720768Speter 				continue;
72114740Sthien 			if (al->tag != T_VAR) {
722768Speter 				error("Arguments to %s must be variables, not expressions", p->symbol);
723768Speter 				continue;
724768Speter 			}
725768Speter 			ap = stklval(al, MOD|ASGN|NOUSE);
72614740Sthien 			if (ap == NLNIL)
727768Speter 				continue;
728768Speter 			if (filetype != nl+T1CHAR) {
729768Speter 				/*
730768Speter 				 * Generalized read, i.e.
731768Speter 				 * from a non-textfile.
732768Speter 				 */
73314740Sthien 				if (incompat(filetype, ap,
73414740Sthien 					argv->list_node.list )) {
735768Speter 					error("Type mismatch in read from non-text file");
736768Speter 					continue;
737768Speter 				}
738768Speter 				/*
739768Speter 				 * var := file ^;
740768Speter 				 */
741768Speter 				if (file != NIL)
74216417Speter 				    (void) stklval(file, NIL);
743768Speter 				else /* Magic */
74416417Speter 				    (void) put(2, PTR_RV, (int)input->value[0]);
74514740Sthien 				(void) put(1, O_FNIL);
74616417Speter 				if (isa(filetype, "bcsi")) {
74716417Speter 				    int filewidth = width(filetype);
74816417Speter 
74916417Speter 				    switch (filewidth) {
75016417Speter 					case 4:
75116417Speter 					    (void) put(1, O_IND4);
75216417Speter 					    break;
75316417Speter 					case 2:
75416417Speter 					    (void) put(1, O_IND2);
75516417Speter 					    break;
75616417Speter 					case 1:
75716417Speter 					    (void) put(1, O_IND1);
75816417Speter 					    break;
75916417Speter 					default:
76016417Speter 					    (void) put(2, O_IND, filewidth);
76116417Speter 				    }
76216417Speter 				    convert(filetype, ap);
76316417Speter 				    rangechk(ap, ap);
76416417Speter 				    (void) gen(O_AS2, O_AS2,
76516417Speter 					    filewidth, width(ap));
76616417Speter 				} else {
76716417Speter 				    (void) put(2, O_IND, width(filetype));
76816417Speter 				    convert(filetype, ap);
76916417Speter 				    (void) put(2, O_AS, width(ap));
77016417Speter 				}
771768Speter 				/*
772768Speter 				 * get(file);
773768Speter 				 */
77414740Sthien 				(void) put(1, O_GET);
775768Speter 				continue;
776768Speter 			}
777768Speter 			typ = classify(ap);
778768Speter 			op = rdops(typ);
779768Speter 			if (op == NIL) {
780768Speter 				error("Can't read %ss from a text file", clnames[typ]);
781768Speter 				continue;
782768Speter 			}
783768Speter 			if (op != O_READE)
78414740Sthien 				(void) put(1, op);
785768Speter 			else {
78614740Sthien 				(void) put(2, op, (long)listnames(ap));
7871628Speter 				warning();
788768Speter 				if (opt('s')) {
789768Speter 					standard();
790768Speter 				}
7911628Speter 				error("Reading scalars from text files is non-standard");
792768Speter 			}
793768Speter 			/*
794768Speter 			 * Data read is on the stack.
795768Speter 			 * Assign it.
796768Speter 			 */
797768Speter 			if (op != O_READ8 && op != O_READE)
798768Speter 				rangechk(ap, op == O_READC ? ap : nl+T4INT);
79914740Sthien 			(void) gen(O_AS2, O_AS2, width(ap),
800768Speter 				op == O_READ8 ? 8 : op == O_READ4 ? 4 : 2);
801768Speter 		}
802768Speter 		/*
803768Speter 		 * Done with arguments.
804768Speter 		 * Handle readln and
805768Speter 		 * insufficient number of args.
806768Speter 		 */
807768Speter 		if (p->value[0] == O_READLN) {
808768Speter 			if (filetype != nl+T1CHAR)
809768Speter 				error("Can't 'readln' a non text file");
81014740Sthien 			(void) put(1, O_READLN);
811768Speter 		}
812768Speter 		else if (argc == 0)
813768Speter 			error("read requires an argument");
814768Speter 		return;
815768Speter 
816768Speter 	case O_GET:
817768Speter 	case O_PUT:
818768Speter 		if (argc != 1) {
819768Speter 			error("%s expects one argument", p->symbol);
820768Speter 			return;
821768Speter 		}
82214740Sthien 		ap = stklval(argv->list_node.list, NIL );
82314740Sthien 		if (ap == NLNIL)
824768Speter 			return;
825768Speter 		if (ap->class != FILET) {
826768Speter 			error("Argument to %s must be a file, not %s", p->symbol, nameof(ap));
827768Speter 			return;
828768Speter 		}
82914740Sthien 		(void) put(1, O_UNIT);
83014740Sthien 		(void) put(1, op);
831768Speter 		return;
832768Speter 
833768Speter 	case O_RESET:
834768Speter 	case O_REWRITE:
835768Speter 		if (argc == 0 || argc > 2) {
836768Speter 			error("%s expects one or two arguments", p->symbol);
837768Speter 			return;
838768Speter 		}
839768Speter 		if (opt('s') && argc == 2) {
840768Speter 			standard();
841768Speter 			error("Two argument forms of reset and rewrite are non-standard");
842768Speter 		}
8432073Smckusic 		codeoff();
84414740Sthien 		ap = stklval(argv->list_node.list, MOD|NOUSE);
8452073Smckusic 		codeon();
84614740Sthien 		if (ap == NLNIL)
847768Speter 			return;
848768Speter 		if (ap->class != FILET) {
849768Speter 			error("First argument to %s must be a file, not %s", p->symbol, nameof(ap));
850768Speter 			return;
851768Speter 		}
85214740Sthien 		(void) put(2, O_CON24, text(ap) ? 0: width(ap->type));
853768Speter 		if (argc == 2) {
854768Speter 			/*
855768Speter 			 * Optional second argument
856768Speter 			 * is a string name of a
857768Speter 			 * UNIX (R) file to be associated.
858768Speter 			 */
85914740Sthien 			al = argv->list_node.next;
8602073Smckusic 			codeoff();
86114740Sthien 			al = (struct tnode *) stkrval(al->list_node.list,
86214740Sthien 					(struct nl *) NOFLAGS , (long) RREQ );
8632073Smckusic 			codeon();
86414740Sthien 			if (al == TR_NIL)
865768Speter 				return;
86614740Sthien 			if (classify((struct nl *) al) != TSTR) {
86714740Sthien 				error("Second argument to %s must be a string, not %s", p->symbol, nameof((struct nl *) al));
868768Speter 				return;
869768Speter 			}
87014740Sthien 			(void) put(2, O_CON24, width((struct nl *) al));
87114740Sthien 			al = argv->list_node.next;
87214740Sthien 			al = (struct tnode *) stkrval(al->list_node.list,
87314740Sthien 					(struct nl *) NOFLAGS , (long) RREQ );
874768Speter 		} else {
87514740Sthien 			(void) put(2, O_CON24, 0);
87614740Sthien 			(void) put(2, PTR_CON, NIL);
877768Speter 		}
87814740Sthien 		ap = stklval(argv->list_node.list, MOD|NOUSE);
87914740Sthien 		(void) put(1, op);
880768Speter 		return;
881768Speter 
882768Speter 	case O_NEW:
883768Speter 	case O_DISPOSE:
884768Speter 		if (argc == 0) {
885768Speter 			error("%s expects at least one argument", p->symbol);
886768Speter 			return;
887768Speter 		}
88814740Sthien 		ap = stklval(argv->list_node.list,
88914740Sthien 				op == O_NEW ? ( MOD | NOUSE ) : MOD );
89014740Sthien 		if (ap == NLNIL)
891768Speter 			return;
892768Speter 		if (ap->class != PTR) {
893768Speter 			error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap));
894768Speter 			return;
895768Speter 		}
896768Speter 		ap = ap->type;
897768Speter 		if (ap == NIL)
898768Speter 			return;
8997966Smckusick 		if ((ap->nl_flags & NFILES) && op == O_DISPOSE)
9007966Smckusick 			op = O_DFDISP;
90114740Sthien 		argv = argv->list_node.next;
90214740Sthien 		if (argv != TR_NIL) {
903768Speter 			if (ap->class != RECORD) {
904768Speter 				error("Record required when specifying variant tags");
905768Speter 				return;
906768Speter 			}
90714740Sthien 			for (; argv != TR_NIL; argv = argv->list_node.next) {
908768Speter 				if (ap->ptr[NL_VARNT] == NIL) {
909768Speter 					error("Too many tag fields");
910768Speter 					return;
911768Speter 				}
91214740Sthien 				if (!isconst(argv->list_node.list)) {
913768Speter 					error("Second and successive arguments to %s must be constants", p->symbol);
914768Speter 					return;
915768Speter 				}
91614740Sthien 				gconst(argv->list_node.list);
917768Speter 				if (con.ctype == NIL)
918768Speter 					return;
91914740Sthien 				if (incompat(con.ctype, (
92014740Sthien 					ap->ptr[NL_TAG])->type , TR_NIL )) {
921768Speter 					cerror("Specified tag constant type clashed with variant case selector type");
922768Speter 					return;
923768Speter 				}
924768Speter 				for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain)
925768Speter 					if (ap->range[0] == con.crval)
926768Speter 						break;
927768Speter 				if (ap == NIL) {
928768Speter 					error("No variant case label value equals specified constant value");
929768Speter 					return;
930768Speter 				}
931768Speter 				ap = ap->ptr[NL_VTOREC];
932768Speter 			}
933768Speter 		}
93414740Sthien 		(void) put(2, op, width(ap));
935768Speter 		return;
936768Speter 
937768Speter 	case O_DATE:
938768Speter 	case O_TIME:
939768Speter 		if (argc != 1) {
940768Speter 			error("%s expects one argument", p->symbol);
941768Speter 			return;
942768Speter 		}
94314740Sthien 		ap = stklval(argv->list_node.list, MOD|NOUSE);
94414740Sthien 		if (ap == NLNIL)
945768Speter 			return;
946768Speter 		if (classify(ap) != TSTR || width(ap) != 10) {
947768Speter 			error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap));
948768Speter 			return;
949768Speter 		}
95014740Sthien 		(void) put(1, op);
951768Speter 		return;
952768Speter 
953768Speter 	case O_HALT:
954768Speter 		if (argc != 0) {
955768Speter 			error("halt takes no arguments");
956768Speter 			return;
957768Speter 		}
95814740Sthien 		(void) put(1, op);
95914740Sthien 		noreach = TRUE; /* used to be 1 */
960768Speter 		return;
961768Speter 
962768Speter 	case O_ARGV:
963768Speter 		if (argc != 2) {
964768Speter 			error("argv takes two arguments");
965768Speter 			return;
966768Speter 		}
96714740Sthien 		ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ );
96814740Sthien 		if (ap == NLNIL)
969768Speter 			return;
970768Speter 		if (isnta(ap, "i")) {
971768Speter 			error("argv's first argument must be an integer, not %s", nameof(ap));
972768Speter 			return;
973768Speter 		}
97414740Sthien 		al = argv->list_node.next;
97514740Sthien 		ap = stklval(al->list_node.list, MOD|NOUSE);
97614740Sthien 		if (ap == NLNIL)
977768Speter 			return;
978768Speter 		if (classify(ap) != TSTR) {
979768Speter 			error("argv's second argument must be a string, not %s", nameof(ap));
980768Speter 			return;
981768Speter 		}
98214740Sthien 		(void) put(2, op, width(ap));
983768Speter 		return;
984768Speter 
985768Speter 	case O_STLIM:
986768Speter 		if (argc != 1) {
987768Speter 			error("stlimit requires one argument");
988768Speter 			return;
989768Speter 		}
99014740Sthien 		ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ );
99114740Sthien 		if (ap == NLNIL)
992768Speter 			return;
993768Speter 		if (isnta(ap, "i")) {
994768Speter 			error("stlimit's argument must be an integer, not %s", nameof(ap));
995768Speter 			return;
996768Speter 		}
997768Speter 		if (width(ap) != 4)
99814740Sthien 			(void) put(1, O_STOI);
99914740Sthien 		(void) put(1, op);
1000768Speter 		return;
1001768Speter 
1002768Speter 	case O_REMOVE:
1003768Speter 		if (argc != 1) {
1004768Speter 			error("remove expects one argument");
1005768Speter 			return;
1006768Speter 		}
10072073Smckusic 		codeoff();
100814740Sthien 		ap = stkrval(argv->list_node.list, (struct nl *) NOFLAGS,
100914740Sthien 				(long) RREQ );
10102073Smckusic 		codeon();
101114740Sthien 		if (ap == NLNIL)
1012768Speter 			return;
1013768Speter 		if (classify(ap) != TSTR) {
1014768Speter 			error("remove's argument must be a string, not %s", nameof(ap));
1015768Speter 			return;
1016768Speter 		}
101714740Sthien 		(void) put(2, O_CON24, width(ap));
101814740Sthien 		ap = stkrval(argv->list_node.list, (struct nl *) NOFLAGS,
101914740Sthien 				(long) RREQ );
102014740Sthien 		(void) put(1, op);
1021768Speter 		return;
1022768Speter 
1023768Speter 	case O_LLIMIT:
1024768Speter 		if (argc != 2) {
1025768Speter 			error("linelimit expects two arguments");
1026768Speter 			return;
1027768Speter 		}
102814740Sthien 		al = argv->list_node.next;
102914740Sthien 		ap = stkrval(al->list_node.list, NLNIL , (long) RREQ );
1030768Speter 		if (ap == NIL)
1031768Speter 			return;
1032768Speter 		if (isnta(ap, "i")) {
1033768Speter 			error("linelimit's second argument must be an integer, not %s", nameof(ap));
1034768Speter 			return;
1035768Speter 		}
103614740Sthien 		ap = stklval(argv->list_node.list, NOFLAGS|NOUSE);
103714740Sthien 		if (ap == NLNIL)
10382073Smckusic 			return;
10392073Smckusic 		if (!text(ap)) {
10402073Smckusic 			error("linelimit's first argument must be a text file, not %s", nameof(ap));
10412073Smckusic 			return;
10422073Smckusic 		}
104314740Sthien 		(void) put(1, op);
1044768Speter 		return;
1045768Speter 	case O_PAGE:
1046768Speter 		if (argc != 1) {
1047768Speter 			error("page expects one argument");
1048768Speter 			return;
1049768Speter 		}
105014740Sthien 		ap = stklval(argv->list_node.list, NIL );
105114740Sthien 		if (ap == NLNIL)
1052768Speter 			return;
1053768Speter 		if (!text(ap)) {
1054768Speter 			error("Argument to page must be a text file, not %s", nameof(ap));
1055768Speter 			return;
1056768Speter 		}
105714740Sthien 		(void) put(1, O_UNIT);
105814740Sthien 		(void) put(1, op);
1059768Speter 		return;
1060768Speter 
10617928Smckusick 	case O_ASRT:
10627928Smckusick 		if (!opt('t'))
10637928Smckusick 			return;
10647928Smckusick 		if (argc == 0 || argc > 2) {
10657928Smckusick 			error("Assert expects one or two arguments");
10667928Smckusick 			return;
10677928Smckusick 		}
10687928Smckusick 		if (argc == 2) {
10697928Smckusick 			/*
10707928Smckusick 			 * Optional second argument is a string specifying
10717928Smckusick 			 * why the assertion failed.
10727928Smckusick 			 */
107314740Sthien 			al = argv->list_node.next;
107414740Sthien 			al1 =  stkrval(al->list_node.list, NLNIL , (long) RREQ );
107514740Sthien 			if (al1 == NIL)
10767928Smckusick 				return;
107714740Sthien 			if (classify(al1) != TSTR) {
107814740Sthien 				error("Second argument to assert must be a string, not %s", nameof(al1));
10797928Smckusick 				return;
10807928Smckusick 			}
10817928Smckusick 		} else {
108214740Sthien 			(void) put(2, PTR_CON, NIL);
10837928Smckusick 		}
108414740Sthien 		ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ );
10857928Smckusick 		if (ap == NIL)
10867928Smckusick 			return;
10877928Smckusick 		if (isnta(ap, "b"))
10887928Smckusick 			error("Assert expression must be Boolean, not %ss", nameof(ap));
108914740Sthien 		(void) put(1, O_ASRT);
10907928Smckusick 		return;
10917928Smckusick 
1092768Speter 	case O_PACK:
1093768Speter 		if (argc != 3) {
1094768Speter 			error("pack expects three arguments");
1095768Speter 			return;
1096768Speter 		}
1097768Speter 		pu = "pack(a,i,z)";
109814740Sthien 		pua = argv->list_node.list;
109914740Sthien 		al = argv->list_node.next;
110014740Sthien 		pui = al->list_node.list;
110114740Sthien 		alv = al->list_node.next;
110214740Sthien 		puz = alv->list_node.list;
1103768Speter 		goto packunp;
1104768Speter 	case O_UNPACK:
1105768Speter 		if (argc != 3) {
1106768Speter 			error("unpack expects three arguments");
1107768Speter 			return;
1108768Speter 		}
1109768Speter 		pu = "unpack(z,a,i)";
111014740Sthien 		puz = argv->list_node.list;
111114740Sthien 		al = argv->list_node.next;
111214740Sthien 		pua = al->list_node.list;
111314740Sthien 		alv = al->list_node.next;
111414740Sthien 		pui = alv->list_node.list;
1115768Speter packunp:
11162073Smckusic 		codeoff();
1117768Speter 		ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE);
111814740Sthien 		al1 = stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE);
11192073Smckusic 		codeon();
1120768Speter 		if (ap == NIL)
1121768Speter 			return;
1122768Speter 		if (ap->class != ARRAY) {
1123768Speter 			error("%s requires a to be an unpacked array, not %s", pu, nameof(ap));
1124768Speter 			return;
1125768Speter 		}
112614740Sthien 		if (al1->class != ARRAY) {
1127768Speter 			error("%s requires z to be a packed array, not %s", pu, nameof(ap));
1128768Speter 			return;
1129768Speter 		}
113014740Sthien 		if (al1->type == NIL || ap->type == NIL)
1131768Speter 			return;
113214740Sthien 		if (al1->type != ap->type) {
1133768Speter 			error("%s requires a and z to be arrays of the same type", pu, nameof(ap));
1134768Speter 			return;
1135768Speter 		}
113614740Sthien 		k = width(al1);
1137768Speter 		itemwidth = width(ap->type);
1138768Speter 		ap = ap->chain;
113914740Sthien 		al1 = al1->chain;
114014740Sthien 		if (ap->chain != NIL || al1->chain != NIL) {
1141768Speter 			error("%s requires a and z to be single dimension arrays", pu);
1142768Speter 			return;
1143768Speter 		}
114414740Sthien 		if (ap == NIL || al1 == NIL)
1145768Speter 			return;
1146768Speter 		/*
114714740Sthien 		 * al1 is the range for z i.e. u..v
1148768Speter 		 * ap is the range for a i.e. m..n
1149768Speter 		 * i will be n-m+1
1150768Speter 		 * j will be v-u+1
1151768Speter 		 */
1152768Speter 		i = ap->range[1] - ap->range[0] + 1;
115314740Sthien 		j = al1->range[1] - al1->range[0] + 1;
1154768Speter 		if (i < j) {
115514740Sthien 			error("%s cannot have more elements in a (%d) than in z (%d)", pu, (char *) j, (char *) i);
1156768Speter 			return;
1157768Speter 		}
1158768Speter 		/*
1159768Speter 		 * get n-m-(v-u) and m for the interpreter
1160768Speter 		 */
1161768Speter 		i -= j;
1162768Speter 		j = ap->range[0];
116314740Sthien 		(void) put(2, O_CON24, k);
116414740Sthien 		(void) put(2, O_CON24, i);
116514740Sthien 		(void) put(2, O_CON24, j);
116614740Sthien 		(void) put(2, O_CON24, itemwidth);
116714740Sthien 		al1 = stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE);
11682073Smckusic 		ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE);
116914740Sthien 		ap = stkrval(pui, NLNIL , (long) RREQ );
11702073Smckusic 		if (ap == NIL)
11712073Smckusic 			return;
117214740Sthien 		(void) put(1, op);
1173768Speter 		return;
1174768Speter 	case 0:
11757928Smckusick 		error("%s is an unimplemented extension", p->symbol);
1176768Speter 		return;
1177768Speter 
1178768Speter 	default:
1179768Speter 		panic("proc case");
1180768Speter 	}
1181768Speter }
1182768Speter #endif OBJ
1183