xref: /csrg-svn/usr.bin/pascal/src/pcproc.c (revision 15934)
1766Speter /* Copyright (c) 1979 Regents of the University of California */
2766Speter 
3*15934Smckusick #ifndef lint
4*15934Smckusick static	char sccsid[] = "@(#)pcproc.c 1.21.1.1 02/04/84";
5*15934Smckusick #endif
6766Speter 
7766Speter #include "whoami.h"
8766Speter #ifdef PC
9766Speter     /*
10766Speter      * and to the end of the file
11766Speter      */
12766Speter #include "0.h"
13766Speter #include "tree.h"
1410372Speter #include "objfmt.h"
15766Speter #include "opcode.h"
1610372Speter #include "pc.h"
1710372Speter #include "pcops.h"
1811333Speter #include "tmps.h"
19*15934Smckusick #include "tree_ty.h"
20766Speter 
21766Speter /*
2211883Smckusick  * The constant EXPOSIZE specifies the number of digits in the exponent
2311883Smckusick  * of real numbers.
2411883Smckusick  *
259229Smckusick  * The constant REALSPC defines the amount of forced padding preceeding
269229Smckusick  * real numbers when they are printed. If REALSPC == 0, then no padding
279229Smckusick  * is added, REALSPC == 1 adds one extra blank irregardless of the width
289229Smckusick  * specified by the user.
299229Smckusick  *
309229Smckusick  * N.B. - Values greater than one require program mods.
319229Smckusick  */
3211883Smckusick #define EXPOSIZE	2
3311883Smckusick #define	REALSPC		0
349229Smckusick 
359229Smckusick /*
36766Speter  * The following array is used to determine which classes may be read
37766Speter  * from textfiles. It is indexed by the return value from classify.
38766Speter  */
39766Speter #define rdops(x) rdxxxx[(x)-(TFIRST)]
40766Speter 
41766Speter int rdxxxx[] = {
42766Speter 	0,		/* -7 file types */
43766Speter 	0,		/* -6 record types */
44766Speter 	0,		/* -5 array types */
45766Speter 	O_READE,	/* -4 scalar types */
46766Speter 	0,		/* -3 pointer types */
47766Speter 	0,		/* -2 set types */
48766Speter 	0,		/* -1 string types */
49766Speter 	0,		/*  0 nil, no type */
50766Speter 	O_READE,	/*  1 boolean */
51766Speter 	O_READC,	/*  2 character */
52766Speter 	O_READ4,	/*  3 integer */
53766Speter 	O_READ8		/*  4 real */
54766Speter };
55766Speter 
56766Speter /*
57766Speter  * Proc handles procedure calls.
58766Speter  * Non-builtin procedures are "buck-passed" to func (with a flag
59766Speter  * indicating that they are actually procedures.
60766Speter  * builtin procedures are handled here.
61766Speter  */
62766Speter pcproc(r)
63*15934Smckusick 	struct tnode *r;	/* T_PCALL */
64766Speter {
65766Speter 	register struct nl *p;
66*15934Smckusick 	register struct tnode *alv, *al;
67*15934Smckusick 	register op;
68766Speter 	struct nl *filetype, *ap;
69*15934Smckusick 	int argc, typ, fmtspec, strfmt;
70*15934Smckusick 	struct tnode *argv, *file;
717967Smckusick 	char fmt, format[20], *strptr, *cmd;
72*15934Smckusick 	int prec, field, strnglen, fmtstart;
73*15934Smckusick 	char *pu;
74*15934Smckusick 	struct tnode *pua, *pui, *puz;
75766Speter 	int i, j, k;
76766Speter 	int itemwidth;
773833Speter 	char		*readname;
783833Speter 	struct nl	*tempnlp;
793833Speter 	long		readtype;
803833Speter 	struct tmps	soffset;
81766Speter 
82766Speter #define	CONPREC 4
83766Speter #define	VARPREC 8
84766Speter #define	CONWIDTH 1
85766Speter #define	VARWIDTH 2
86766Speter #define SKIP 16
87766Speter 
88766Speter 	/*
89766Speter 	 * Verify that the name is
90766Speter 	 * defined and is that of a
91766Speter 	 * procedure.
92766Speter 	 */
93*15934Smckusick 	p = lookup(r->pcall_node.proc_id);
94*15934Smckusick 	if (p == NLNIL) {
95*15934Smckusick 		rvlist(r->pcall_node.arg);
96766Speter 		return;
97766Speter 	}
981197Speter 	if (p->class != PROC && p->class != FPROC) {
99766Speter 		error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]);
100*15934Smckusick 		rvlist(r->pcall_node.arg);
101766Speter 		return;
102766Speter 	}
103*15934Smckusick 	argv = r->pcall_node.arg;
104766Speter 
105766Speter 	/*
106766Speter 	 * Call handles user defined
107766Speter 	 * procedures and functions.
108766Speter 	 */
109766Speter 	if (bn != 0) {
110*15934Smckusick 		(void) call(p, argv, PROC, bn);
111766Speter 		return;
112766Speter 	}
113766Speter 
114766Speter 	/*
115766Speter 	 * Call to built-in procedure.
116766Speter 	 * Count the arguments.
117766Speter 	 */
118766Speter 	argc = 0;
119*15934Smckusick 	for (al = argv; al != TR_NIL; al = al->list_node.next)
120766Speter 		argc++;
121766Speter 
122766Speter 	/*
123766Speter 	 * Switch on the operator
124766Speter 	 * associated with the built-in
125766Speter 	 * procedure in the namelist
126766Speter 	 */
127766Speter 	op = p->value[0] &~ NSTAND;
128766Speter 	if (opt('s') && (p->value[0] & NSTAND)) {
129766Speter 		standard();
130766Speter 		error("%s is a nonstandard procedure", p->symbol);
131766Speter 	}
132766Speter 	switch (op) {
133766Speter 
134766Speter 	case O_ABORT:
135766Speter 		if (argc != 0)
136766Speter 			error("null takes no arguments");
137766Speter 		return;
138766Speter 
139766Speter 	case O_FLUSH:
140766Speter 		if (argc == 0) {
141766Speter 			putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" );
142766Speter 			putop( P2UNARY P2CALL , P2INT );
143766Speter 			putdot( filename , line );
144766Speter 			return;
145766Speter 		}
146766Speter 		if (argc != 1) {
147766Speter 			error("flush takes at most one argument");
148766Speter 			return;
149766Speter 		}
150766Speter 		putleaf( P2ICON , 0 , 0
151766Speter 			, ADDTYPE( P2FTN | P2INT , P2PTR )
152766Speter 			, "_FLUSH" );
153*15934Smckusick 		ap = stklval(argv->list_node.list, NOFLAGS);
154*15934Smckusick 		if (ap == NLNIL)
155766Speter 			return;
156766Speter 		if (ap->class != FILET) {
157766Speter 			error("flush's argument must be a file, not %s", nameof(ap));
158766Speter 			return;
159766Speter 		}
160766Speter 		putop( P2CALL , P2INT );
161766Speter 		putdot( filename , line );
162766Speter 		return;
163766Speter 
164766Speter 	case O_MESSAGE:
165766Speter 	case O_WRITEF:
166766Speter 	case O_WRITLN:
167766Speter 		/*
168766Speter 		 * Set up default file "output"'s type
169766Speter 		 */
170766Speter 		file = NIL;
171766Speter 		filetype = nl+T1CHAR;
172766Speter 		/*
173766Speter 		 * Determine the file implied
174766Speter 		 * for the write and generate
175766Speter 		 * code to make it the active file.
176766Speter 		 */
177766Speter 		if (op == O_MESSAGE) {
178766Speter 			/*
179766Speter 			 * For message, all that matters
180766Speter 			 * is that the filetype is
181766Speter 			 * a character file.
182766Speter 			 * Thus "output" will suit us fine.
183766Speter 			 */
184766Speter 			putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" );
185766Speter 			putop( P2UNARY P2CALL , P2INT );
186766Speter 			putdot( filename , line );
187*15934Smckusick 			putRV( (char *) 0 , cbn , CURFILEOFFSET , NLOCAL ,
1883833Speter 				P2PTR|P2STRTY );
1893833Speter 			putLV( "__err" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY );
190766Speter 			putop( P2ASSIGN , P2PTR|P2STRTY );
191766Speter 			putdot( filename , line );
192*15934Smckusick 		} else if (argv != TR_NIL && (al = argv->list_node.list)->tag !=
193*15934Smckusick 					T_WEXP) {
194766Speter 			/*
195766Speter 			 * If there is a first argument which has
196766Speter 			 * no write widths, then it is potentially
197766Speter 			 * a file name.
198766Speter 			 */
199766Speter 			codeoff();
200*15934Smckusick 			ap = stkrval(argv->list_node.list, NLNIL, (long) RREQ );
201766Speter 			codeon();
202*15934Smckusick 			if (ap == NLNIL)
203*15934Smckusick 				argv = argv->list_node.next;
204766Speter 			if (ap != NIL && ap->class == FILET) {
205766Speter 				/*
206766Speter 				 * Got "write(f, ...", make
207766Speter 				 * f the active file, and save
208766Speter 				 * it and its type for use in
209766Speter 				 * processing the rest of the
210766Speter 				 * arguments to write.
211766Speter 				 */
212*15934Smckusick 				putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL ,
2133833Speter 					P2PTR|P2STRTY );
214766Speter 				putleaf( P2ICON , 0 , 0
215766Speter 				    , ADDTYPE( P2FTN | P2INT , P2PTR )
216766Speter 				    , "_UNIT" );
217*15934Smckusick 				file = argv->list_node.list;
218766Speter 				filetype = ap->type;
219*15934Smckusick 				(void) stklval(argv->list_node.list, NOFLAGS);
220766Speter 				putop( P2CALL , P2INT );
221766Speter 				putop( P2ASSIGN , P2PTR|P2STRTY );
222766Speter 				putdot( filename , line );
223766Speter 				/*
224766Speter 				 * Skip over the first argument
225766Speter 				 */
226*15934Smckusick 				argv = argv->list_node.next;
227766Speter 				argc--;
228766Speter 			} else {
229766Speter 				/*
230766Speter 				 * Set up for writing on
231766Speter 				 * standard output.
232766Speter 				 */
233*15934Smckusick 				putRV((char *) 0, cbn , CURFILEOFFSET ,
2343833Speter 					NLOCAL , P2PTR|P2STRTY );
2353833Speter 				putLV( "_output" , 0 , 0 , NGLOBAL ,
2363833Speter 					P2PTR|P2STRTY );
237766Speter 				putop( P2ASSIGN , P2PTR|P2STRTY );
238766Speter 				putdot( filename , line );
2397954Speter 				output->nl_flags |= NUSED;
240766Speter 			}
241766Speter 		} else {
242*15934Smckusick 			putRV((char *) 0, cbn , CURFILEOFFSET , NLOCAL ,
2433833Speter 				P2PTR|P2STRTY );
2443833Speter 			putLV( "_output" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY );
245766Speter 			putop( P2ASSIGN , P2PTR|P2STRTY );
246766Speter 			putdot( filename , line );
2477954Speter 			output->nl_flags |= NUSED;
248766Speter 		}
249766Speter 		/*
250766Speter 		 * Loop and process each
251766Speter 		 * of the arguments.
252766Speter 		 */
253*15934Smckusick 		for (; argv != TR_NIL; argv = argv->list_node.next) {
254766Speter 			/*
255766Speter 			 * fmtspec indicates the type (CONstant or VARiable)
256766Speter 			 *	and number (none, WIDTH, and/or PRECision)
257766Speter 			 *	of the fields in the printf format for this
258766Speter 			 *	output variable.
259766Speter 			 * fmt is the format output indicator (D, E, F, O, X, S)
260766Speter 			 * fmtstart = 0 for leading blank; = 1 for no blank
261766Speter 			 */
262766Speter 			fmtspec = NIL;
263766Speter 			fmt = 'D';
264766Speter 			fmtstart = 1;
265*15934Smckusick 			al = argv->list_node.list;
266766Speter 			if (al == NIL)
267766Speter 				continue;
268*15934Smckusick 			if (al->tag == T_WEXP)
269*15934Smckusick 				alv = al->wexpr_node.expr1;
270766Speter 			else
271766Speter 				alv = al;
272*15934Smckusick 			if (alv == TR_NIL)
273766Speter 				continue;
274766Speter 			codeoff();
275*15934Smckusick 			ap = stkrval(alv, NLNIL , (long) RREQ );
276766Speter 			codeon();
277*15934Smckusick 			if (ap == NLNIL)
278766Speter 				continue;
279766Speter 			typ = classify(ap);
280*15934Smckusick 			if (al->tag == T_WEXP) {
281766Speter 				/*
282766Speter 				 * Handle width expressions.
283766Speter 				 * The basic game here is that width
284766Speter 				 * expressions get evaluated. If they
285766Speter 				 * are constant, the value is placed
286766Speter 				 * directly in the format string.
287766Speter 				 * Otherwise the value is pushed onto
288766Speter 				 * the stack and an indirection is
289766Speter 				 * put into the format string.
290766Speter 				 */
291*15934Smckusick 				if (al->wexpr_node.expr3 ==
292*15934Smckusick 						(struct tnode *) OCT)
293766Speter 					fmt = 'O';
294*15934Smckusick 				else if (al->wexpr_node.expr3 ==
295*15934Smckusick 						(struct tnode *) HEX)
296766Speter 					fmt = 'X';
297*15934Smckusick 				else if (al->wexpr_node.expr3 != TR_NIL) {
298766Speter 					/*
299766Speter 					 * Evaluate second format spec
300766Speter 					 */
301*15934Smckusick 					if ( constval(al->wexpr_node.expr3)
302766Speter 					    && isa( con.ctype , "i" ) ) {
303766Speter 						fmtspec += CONPREC;
304766Speter 						prec = con.crval;
305766Speter 					} else {
306766Speter 						fmtspec += VARPREC;
307766Speter 					}
308766Speter 					fmt = 'f';
309766Speter 					switch ( typ ) {
310766Speter 					case TINT:
311766Speter 						if ( opt( 's' ) ) {
312766Speter 						    standard();
313766Speter 						    error("Writing %ss with two write widths is non-standard", clnames[typ]);
314766Speter 						}
315766Speter 						/* and fall through */
316766Speter 					case TDOUBLE:
317766Speter 						break;
318766Speter 					default:
319766Speter 						error("Cannot write %ss with two write widths", clnames[typ]);
320766Speter 						continue;
321766Speter 					}
322766Speter 				}
323766Speter 				/*
324766Speter 				 * Evaluate first format spec
325766Speter 				 */
326*15934Smckusick 				if (al->wexpr_node.expr2 != TR_NIL) {
327*15934Smckusick 					if ( constval(al->wexpr_node.expr2)
328766Speter 					    && isa( con.ctype , "i" ) ) {
329766Speter 						fmtspec += CONWIDTH;
330766Speter 						field = con.crval;
331766Speter 					} else {
332766Speter 						fmtspec += VARWIDTH;
333766Speter 					}
334766Speter 				}
335766Speter 				if ((fmtspec & CONPREC) && prec < 0 ||
336766Speter 				    (fmtspec & CONWIDTH) && field < 0) {
337766Speter 					error("Negative widths are not allowed");
338766Speter 					continue;
339766Speter 				}
3403180Smckusic 				if ( opt('s') &&
3413180Smckusic 				    ((fmtspec & CONPREC) && prec == 0 ||
3423180Smckusic 				    (fmtspec & CONWIDTH) && field == 0)) {
3433180Smckusic 					standard();
3443180Smckusic 					error("Zero widths are non-standard");
3453180Smckusic 				}
346766Speter 			}
347766Speter 			if (filetype != nl+T1CHAR) {
348766Speter 				if (fmt == 'O' || fmt == 'X') {
349766Speter 					error("Oct/hex allowed only on text files");
350766Speter 					continue;
351766Speter 				}
352766Speter 				if (fmtspec) {
353766Speter 					error("Write widths allowed only on text files");
354766Speter 					continue;
355766Speter 				}
356766Speter 				/*
357766Speter 				 * Generalized write, i.e.
358766Speter 				 * to a non-textfile.
359766Speter 				 */
360766Speter 				putleaf( P2ICON , 0 , 0
361*15934Smckusick 				    , (int) (ADDTYPE(
362766Speter 					ADDTYPE(
363766Speter 					    ADDTYPE( p2type( filetype )
364766Speter 						    , P2PTR )
365766Speter 					    , P2FTN )
366*15934Smckusick 					, P2PTR ))
367766Speter 				    , "_FNIL" );
368*15934Smckusick 				(void) stklval(file, NOFLAGS);
369766Speter 				putop( P2CALL
370766Speter 				    , ADDTYPE( p2type( filetype ) , P2PTR ) );
371766Speter 				putop( P2UNARY P2MUL , p2type( filetype ) );
372766Speter 				/*
373766Speter 				 * file^ := ...
374766Speter 				 */
375766Speter 				switch ( classify( filetype ) ) {
376766Speter 				    case TBOOL:
377766Speter 				    case TCHAR:
378766Speter 				    case TINT:
379766Speter 				    case TSCAL:
3804589Speter 					precheck( filetype , "_RANG4"  , "_RSNG4" );
381766Speter 					    /* and fall through */
382766Speter 				    case TDOUBLE:
383766Speter 				    case TPTR:
384*15934Smckusick 					ap = rvalue( argv->list_node.list , filetype , RREQ );
385766Speter 					break;
386766Speter 				    default:
387*15934Smckusick 					ap = rvalue( argv->list_node.list , filetype , LREQ );
388766Speter 					break;
389766Speter 				}
390766Speter 				if (ap == NIL)
391766Speter 					continue;
392*15934Smckusick 				if (incompat(ap, filetype, argv->list_node.list)) {
393766Speter 					cerror("Type mismatch in write to non-text file");
394766Speter 					continue;
395766Speter 				}
396766Speter 				switch ( classify( filetype ) ) {
397766Speter 				    case TBOOL:
398766Speter 				    case TCHAR:
399766Speter 				    case TINT:
400766Speter 				    case TSCAL:
40110373Speter 					    postcheck(filetype, ap);
40210373Speter 					    sconv(p2type(ap), p2type(filetype));
403766Speter 						/* and fall through */
404766Speter 				    case TDOUBLE:
405766Speter 				    case TPTR:
406766Speter 					    putop( P2ASSIGN , p2type( filetype ) );
407766Speter 					    putdot( filename , line );
408766Speter 					    break;
409766Speter 				    default:
41011856Speter 					    putstrop(P2STASG,
41111856Speter 						    ADDTYPE(p2type(filetype),
41211856Speter 							    P2PTR),
413*15934Smckusick 						    (int) lwidth(filetype),
41411856Speter 						    align(filetype));
415766Speter 					    putdot( filename , line );
416766Speter 					    break;
417766Speter 				}
418766Speter 				/*
419766Speter 				 * put(file)
420766Speter 				 */
421766Speter 				putleaf( P2ICON , 0 , 0
422766Speter 				    , ADDTYPE( P2FTN | P2INT , P2PTR )
423766Speter 				    , "_PUT" );
424*15934Smckusick 				putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL ,
4253833Speter 					P2PTR|P2STRTY );
426766Speter 				putop( P2CALL , P2INT );
427766Speter 				putdot( filename , line );
428766Speter 				continue;
429766Speter 			}
430766Speter 			/*
431766Speter 			 * Write to a textfile
432766Speter 			 *
433766Speter 			 * Evaluate the expression
434766Speter 			 * to be written.
435766Speter 			 */
436766Speter 			if (fmt == 'O' || fmt == 'X') {
437766Speter 				if (opt('s')) {
438766Speter 					standard();
439766Speter 					error("Oct and hex are non-standard");
440766Speter 				}
441766Speter 				if (typ == TSTR || typ == TDOUBLE) {
442766Speter 					error("Can't write %ss with oct/hex", clnames[typ]);
443766Speter 					continue;
444766Speter 				}
445766Speter 				if (typ == TCHAR || typ == TBOOL)
446766Speter 					typ = TINT;
447766Speter 			}
448766Speter 			/*
449766Speter 			 * If there is no format specified by the programmer,
450766Speter 			 * implement the default.
451766Speter 			 */
452766Speter 			switch (typ) {
4536540Smckusick 			case TPTR:
4546540Smckusick 				warning();
4556540Smckusick 				if (opt('s')) {
4566540Smckusick 					standard();
4576540Smckusick 				}
4586540Smckusick 				error("Writing %ss to text files is non-standard",
4596540Smckusick 				    clnames[typ]);
4606540Smckusick 				/* and fall through */
461766Speter 			case TINT:
462766Speter 				if (fmt == 'f') {
463766Speter 					typ = TDOUBLE;
464766Speter 					goto tdouble;
465766Speter 				}
466766Speter 				if (fmtspec == NIL) {
467766Speter 					if (fmt == 'D')
468766Speter 						field = 10;
469766Speter 					else if (fmt == 'X')
470766Speter 						field = 8;
471766Speter 					else if (fmt == 'O')
472766Speter 						field = 11;
473766Speter 					else
474766Speter 						panic("fmt1");
475766Speter 					fmtspec = CONWIDTH;
476766Speter 				}
477766Speter 				break;
478766Speter 			case TCHAR:
479766Speter 			     tchar:
480766Speter 				fmt = 'c';
481766Speter 				break;
482766Speter 			case TSCAL:
4831629Speter 				warning();
484766Speter 				if (opt('s')) {
485766Speter 					standard();
486766Speter 				}
4876540Smckusick 				error("Writing %ss to text files is non-standard",
4886540Smckusick 				    clnames[typ]);
489766Speter 			case TBOOL:
490766Speter 				fmt = 's';
491766Speter 				break;
492766Speter 			case TDOUBLE:
493766Speter 			     tdouble:
494766Speter 				switch (fmtspec) {
495766Speter 				case NIL:
49611883Smckusick 					field = 14 + (5 + EXPOSIZE);
49711883Smckusick 				        prec = field - (5 + EXPOSIZE);
4983225Smckusic 					fmt = 'e';
499766Speter 					fmtspec = CONWIDTH + CONPREC;
500766Speter 					break;
501766Speter 				case CONWIDTH:
5029229Smckusick 					field -= REALSPC;
5039229Smckusick 					if (field < 1)
504766Speter 						field = 1;
50511883Smckusick 				        prec = field - (5 + EXPOSIZE);
506766Speter 					if (prec < 1)
507766Speter 						prec = 1;
508766Speter 					fmtspec += CONPREC;
5093225Smckusic 					fmt = 'e';
510766Speter 					break;
511766Speter 				case VARWIDTH:
512766Speter 					fmtspec += VARPREC;
5133225Smckusic 					fmt = 'e';
514766Speter 					break;
515766Speter 				case CONWIDTH + CONPREC:
516766Speter 				case CONWIDTH + VARPREC:
5179229Smckusick 					field -= REALSPC;
5189229Smckusick 					if (field < 1)
519766Speter 						field = 1;
520766Speter 				}
521766Speter 				format[0] = ' ';
5229229Smckusick 				fmtstart = 1 - REALSPC;
523766Speter 				break;
524766Speter 			case TSTR:
525*15934Smckusick 				(void) constval( alv );
526766Speter 				switch ( classify( con.ctype ) ) {
527766Speter 				    case TCHAR:
528766Speter 					typ = TCHAR;
529766Speter 					goto tchar;
530766Speter 				    case TSTR:
531766Speter 					strptr = con.cpval;
532766Speter 					for (strnglen = 0;  *strptr++;  strnglen++) /* void */;
533766Speter 					strptr = con.cpval;
534766Speter 					break;
535766Speter 				    default:
536766Speter 					strnglen = width(ap);
537766Speter 					break;
538766Speter 				}
539766Speter 				fmt = 's';
540766Speter 				strfmt = fmtspec;
541766Speter 				if (fmtspec == NIL) {
542766Speter 					fmtspec = SKIP;
543766Speter 					break;
544766Speter 				}
545766Speter 				if (fmtspec & CONWIDTH) {
546766Speter 					if (field <= strnglen)
547766Speter 						fmtspec = SKIP;
548766Speter 					else
549766Speter 						field -= strnglen;
550766Speter 				}
551766Speter 				break;
552766Speter 			default:
553766Speter 				error("Can't write %ss to a text file", clnames[typ]);
554766Speter 				continue;
555766Speter 			}
556766Speter 			/*
557766Speter 			 * Generate the format string
558766Speter 			 */
559766Speter 			switch (fmtspec) {
560766Speter 			default:
561766Speter 				panic("fmt2");
562766Speter 			case NIL:
563766Speter 				if (fmt == 'c') {
564766Speter 					if ( opt( 't' ) ) {
565766Speter 					    putleaf( P2ICON , 0 , 0
566766Speter 						, ADDTYPE( P2FTN|P2INT , P2PTR )
567766Speter 						, "_WRITEC" );
568*15934Smckusick 					    putRV((char *) 0 , cbn , CURFILEOFFSET ,
5693833Speter 						    NLOCAL , P2PTR|P2STRTY );
570*15934Smckusick 					    (void) stkrval( alv , NLNIL , (long) RREQ );
571766Speter 					    putop( P2LISTOP , P2INT );
572766Speter 					} else {
573766Speter 					    putleaf( P2ICON , 0 , 0
574766Speter 						, ADDTYPE( P2FTN|P2INT , P2PTR )
575766Speter 						, "_fputc" );
576*15934Smckusick 					    (void) stkrval( alv , NLNIL ,
577*15934Smckusick 							(long) RREQ );
578766Speter 					}
579766Speter 					putleaf( P2ICON , 0 , 0
580766Speter 					    , ADDTYPE( P2FTN | P2INT , P2PTR )
581766Speter 					    , "_ACTFILE" );
582*15934Smckusick 					putRV((char *) 0, cbn , CURFILEOFFSET ,
5833833Speter 						NLOCAL , P2PTR|P2STRTY );
584766Speter 					putop( P2CALL , P2INT );
585766Speter 					putop( P2LISTOP , P2INT );
586766Speter 					putop( P2CALL , P2INT );
587766Speter 					putdot( filename , line );
588766Speter 				} else  {
589766Speter 					sprintf(&format[1], "%%%c", fmt);
590766Speter 					goto fmtgen;
591766Speter 				}
592766Speter 			case SKIP:
593766Speter 				break;
594766Speter 			case CONWIDTH:
595766Speter 				sprintf(&format[1], "%%%1D%c", field, fmt);
596766Speter 				goto fmtgen;
597766Speter 			case VARWIDTH:
598766Speter 				sprintf(&format[1], "%%*%c", fmt);
599766Speter 				goto fmtgen;
600766Speter 			case CONWIDTH + CONPREC:
601766Speter 				sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt);
602766Speter 				goto fmtgen;
603766Speter 			case CONWIDTH + VARPREC:
604766Speter 				sprintf(&format[1], "%%%1D.*%c", field, fmt);
605766Speter 				goto fmtgen;
606766Speter 			case VARWIDTH + CONPREC:
607766Speter 				sprintf(&format[1], "%%*.%1D%c", prec, fmt);
608766Speter 				goto fmtgen;
609766Speter 			case VARWIDTH + VARPREC:
610766Speter 				sprintf(&format[1], "%%*.*%c", fmt);
611766Speter 			fmtgen:
612766Speter 				if ( opt( 't' ) ) {
613766Speter 				    putleaf( P2ICON , 0 , 0
614766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
615766Speter 					, "_WRITEF" );
616*15934Smckusick 				    putRV((char *) 0 , cbn , CURFILEOFFSET ,
6173833Speter 					    NLOCAL , P2PTR|P2STRTY );
618766Speter 				    putleaf( P2ICON , 0 , 0
619766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
620766Speter 					, "_ACTFILE" );
621*15934Smckusick 				    putRV((char *) 0 , cbn , CURFILEOFFSET ,
6223833Speter 					    NLOCAL , P2PTR|P2STRTY );
623766Speter 				    putop( P2CALL , P2INT );
624766Speter 				    putop( P2LISTOP , P2INT );
625766Speter 				} else {
626766Speter 				    putleaf( P2ICON , 0 , 0
627766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
628766Speter 					, "_fprintf" );
629766Speter 				    putleaf( P2ICON , 0 , 0
630766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
631766Speter 					, "_ACTFILE" );
632*15934Smckusick 				    putRV((char *) 0 , cbn , CURFILEOFFSET ,
6333833Speter 					    NLOCAL , P2PTR|P2STRTY );
634766Speter 				    putop( P2CALL , P2INT );
635766Speter 				}
636766Speter 				putCONG( &format[ fmtstart ]
637766Speter 					, strlen( &format[ fmtstart ] )
638766Speter 					, LREQ );
639766Speter 				putop( P2LISTOP , P2INT );
640766Speter 				if ( fmtspec & VARWIDTH ) {
641766Speter 					/*
642766Speter 					 * either
643766Speter 					 *	,(temp=width,MAX(temp,...)),
644766Speter 					 * or
645766Speter 					 *	, MAX( width , ... ) ,
646766Speter 					 */
647*15934Smckusick 				    if ( ( typ == TDOUBLE &&
648*15934Smckusick 						al->wexpr_node.expr3 == TR_NIL )
649766Speter 					|| typ == TSTR ) {
6503225Smckusic 					soffset = sizes[cbn].curtmps;
651*15934Smckusick 					tempnlp = tmpalloc((long) (sizeof(long)),
6523225Smckusic 						nl+T4INT, REGOK);
653*15934Smckusick 					putRV((char *) 0 , cbn ,
6543833Speter 					    tempnlp -> value[ NL_OFFS ] ,
6553833Speter 					    tempnlp -> extra_flags , P2INT );
656*15934Smckusick 					ap = stkrval( al->wexpr_node.expr2 ,
657*15934Smckusick 						NLNIL , (long) RREQ );
658766Speter 					putop( P2ASSIGN , P2INT );
659766Speter 					putleaf( P2ICON , 0 , 0
660766Speter 					    , ADDTYPE( P2FTN | P2INT , P2PTR )
661766Speter 					    , "_MAX" );
662*15934Smckusick 					putRV((char *) 0 , cbn ,
6633833Speter 					    tempnlp -> value[ NL_OFFS ] ,
6643833Speter 					    tempnlp -> extra_flags , P2INT );
665766Speter 				    } else {
666766Speter 					if (opt('t')
667766Speter 					    || typ == TSTR || typ == TDOUBLE) {
668766Speter 					    putleaf( P2ICON , 0 , 0
669766Speter 						,ADDTYPE( P2FTN | P2INT, P2PTR )
670766Speter 						,"_MAX" );
671766Speter 					}
672*15934Smckusick 					ap = stkrval( al->wexpr_node.expr2,
673*15934Smckusick 						NLNIL , (long) RREQ );
674766Speter 				    }
675*15934Smckusick 				    if (ap == NLNIL)
676766Speter 					    continue;
677766Speter 				    if (isnta(ap,"i")) {
678766Speter 					    error("First write width must be integer, not %s", nameof(ap));
679766Speter 					    continue;
680766Speter 				    }
681766Speter 				    switch ( typ ) {
682766Speter 				    case TDOUBLE:
683*15934Smckusick 					putleaf( P2ICON , REALSPC , 0 , P2INT , (char *) 0 );
684766Speter 					putop( P2LISTOP , P2INT );
685*15934Smckusick 					putleaf( P2ICON , 1 , 0 , P2INT , (char *) 0 );
686766Speter 					putop( P2LISTOP , P2INT );
687766Speter 					putop( P2CALL , P2INT );
688*15934Smckusick 					if ( al->wexpr_node.expr3 == TR_NIL ) {
689766Speter 						/*
690766Speter 						 * finish up the comma op
691766Speter 						 */
692766Speter 					    putop( P2COMOP , P2INT );
693766Speter 					    fmtspec &= ~VARPREC;
694766Speter 					    putop( P2LISTOP , P2INT );
695766Speter 					    putleaf( P2ICON , 0 , 0
696766Speter 						, ADDTYPE( P2FTN | P2INT , P2PTR )
697766Speter 						, "_MAX" );
698*15934Smckusick 					    putRV((char *) 0 , cbn ,
6993833Speter 						tempnlp -> value[ NL_OFFS ] ,
7003833Speter 						tempnlp -> extra_flags ,
7013833Speter 						P2INT );
702*15934Smckusick 					    tmpfree(&soffset);
70311883Smckusick 					    putleaf( P2ICON ,
70411883Smckusick 						5 + EXPOSIZE + REALSPC ,
705*15934Smckusick 						0 , P2INT , (char *) 0 );
706766Speter 					    putop( P2LISTOP , P2INT );
707*15934Smckusick 					    putleaf( P2ICON , 1 , 0 , P2INT , (char *) 0 );
708766Speter 					    putop( P2LISTOP , P2INT );
709766Speter 					    putop( P2CALL , P2INT );
710766Speter 					}
711766Speter 					putop( P2LISTOP , P2INT );
712766Speter 					break;
713766Speter 				    case TSTR:
714*15934Smckusick 					putleaf( P2ICON , strnglen , 0 , P2INT , (char *) 0 );
715766Speter 					putop( P2LISTOP , P2INT );
716*15934Smckusick 					putleaf( P2ICON , 0 , 0 , P2INT , (char *) 0 );
717766Speter 					putop( P2LISTOP , P2INT );
718766Speter 					putop( P2CALL , P2INT );
719766Speter 					putop( P2COMOP , P2INT );
720766Speter 					putop( P2LISTOP , P2INT );
721766Speter 					break;
722766Speter 				    default:
723766Speter 					if (opt('t')) {
724*15934Smckusick 					    putleaf( P2ICON , 0 , 0 , P2INT , (char *) 0 );
725766Speter 					    putop( P2LISTOP , P2INT );
726*15934Smckusick 					    putleaf( P2ICON , 0 , 0 , P2INT , (char *) 0 );
727766Speter 					    putop( P2LISTOP , P2INT );
728766Speter 					    putop( P2CALL , P2INT );
729766Speter 					}
730766Speter 					putop( P2LISTOP , P2INT );
731766Speter 					break;
732766Speter 				    }
733766Speter 				}
734766Speter 				/*
735766Speter 				 * If there is a variable precision,
736766Speter 				 * evaluate it
737766Speter 				 */
738766Speter 				if (fmtspec & VARPREC) {
739766Speter 					if (opt('t')) {
740766Speter 					putleaf( P2ICON , 0 , 0
741766Speter 					    , ADDTYPE( P2FTN | P2INT , P2PTR )
742766Speter 					    , "_MAX" );
743766Speter 					}
744*15934Smckusick 					ap = stkrval( al->wexpr_node.expr3 ,
745*15934Smckusick 						NLNIL , (long) RREQ );
746766Speter 					if (ap == NIL)
747766Speter 						continue;
748766Speter 					if (isnta(ap,"i")) {
749766Speter 						error("Second write width must be integer, not %s", nameof(ap));
750766Speter 						continue;
751766Speter 					}
752766Speter 					if (opt('t')) {
753*15934Smckusick 					    putleaf( P2ICON , 0 , 0 , P2INT , (char *) 0 );
754766Speter 					    putop( P2LISTOP , P2INT );
755*15934Smckusick 					    putleaf( P2ICON , 0 , 0 , P2INT , (char *) 0 );
756766Speter 					    putop( P2LISTOP , P2INT );
757766Speter 					    putop( P2CALL , P2INT );
758766Speter 					}
759766Speter 				 	putop( P2LISTOP , P2INT );
760766Speter 				}
761766Speter 				/*
762766Speter 				 * evaluate the thing we want printed.
763766Speter 				 */
764766Speter 				switch ( typ ) {
7656540Smckusick 				case TPTR:
766766Speter 				case TCHAR:
767766Speter 				case TINT:
768*15934Smckusick 				    (void) stkrval( alv , NLNIL , (long) RREQ );
769766Speter 				    putop( P2LISTOP , P2INT );
770766Speter 				    break;
771766Speter 				case TDOUBLE:
772*15934Smckusick 				    ap = stkrval( alv , NLNIL , (long) RREQ );
77310373Speter 				    if (isnta(ap, "d")) {
77410373Speter 					sconv(p2type(ap), P2DOUBLE);
775766Speter 				    }
776766Speter 				    putop( P2LISTOP , P2INT );
777766Speter 				    break;
778766Speter 				case TSCAL:
779766Speter 				case TBOOL:
780766Speter 				    putleaf( P2ICON , 0 , 0
781766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
782766Speter 					, "_NAM" );
783*15934Smckusick 				    ap = stkrval( alv , NLNIL , (long) RREQ );
784766Speter 				    sprintf( format , PREFIXFORMAT , LABELPREFIX
785766Speter 					    , listnames( ap ) );
786*15934Smckusick 				    putleaf( P2ICON , 0 , 0 ,
787*15934Smckusick 					(int) (P2PTR | P2CHAR), format );
788766Speter 				    putop( P2LISTOP , P2INT );
789766Speter 				    putop( P2CALL , P2INT );
790766Speter 				    putop( P2LISTOP , P2INT );
791766Speter 				    break;
792766Speter 				case TSTR:
793766Speter 				    putCONG( "" , 0 , LREQ );
794766Speter 				    putop( P2LISTOP , P2INT );
795766Speter 				    break;
7966540Smckusick 				default:
7976540Smckusick 				    panic("fmt3");
7986540Smckusick 				    break;
799766Speter 				}
800766Speter 				putop( P2CALL , P2INT );
801766Speter 				putdot( filename , line );
802766Speter 			}
803766Speter 			/*
804766Speter 			 * Write the string after its blank padding
805766Speter 			 */
806766Speter 			if (typ == TSTR ) {
807766Speter 				if ( opt( 't' ) ) {
808766Speter 				    putleaf( P2ICON , 0 , 0
809766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
810766Speter 					, "_WRITES" );
811*15934Smckusick 				    putRV((char *) 0 , cbn , CURFILEOFFSET ,
8123833Speter 					    NLOCAL , P2PTR|P2STRTY );
813*15934Smckusick 				    ap = stkrval(alv, NLNIL , (long) RREQ );
814766Speter 				    putop( P2LISTOP , P2INT );
815766Speter 				} else {
816766Speter 				    putleaf( P2ICON , 0 , 0
817766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
818766Speter 					, "_fwrite" );
819*15934Smckusick 				    ap = stkrval(alv, NLNIL , (long) RREQ );
820766Speter 				}
821766Speter 				if (strfmt & VARWIDTH) {
822766Speter 					    /*
823766Speter 					     *	min, inline expanded as
824766Speter 					     *	temp < len ? temp : len
825766Speter 					     */
826*15934Smckusick 					putRV((char *) 0 , cbn ,
8273833Speter 					    tempnlp -> value[ NL_OFFS ] ,
8283833Speter 					    tempnlp -> extra_flags , P2INT );
829*15934Smckusick 					putleaf( P2ICON , strnglen , 0 , P2INT , (char *) 0 );
830766Speter 					putop( P2LT , P2INT );
831*15934Smckusick 					putRV((char *) 0 , cbn ,
8323833Speter 					    tempnlp -> value[ NL_OFFS ] ,
8333833Speter 					    tempnlp -> extra_flags , P2INT );
834*15934Smckusick 					putleaf( P2ICON , strnglen , 0 , P2INT , (char *) 0 );
835766Speter 					putop( P2COLON , P2INT );
836766Speter 					putop( P2QUEST , P2INT );
837*15934Smckusick 					tmpfree(&soffset);
838766Speter 				} else {
839766Speter 					if (   ( fmtspec & SKIP )
840766Speter 					    && ( strfmt & CONWIDTH ) ) {
841766Speter 						strnglen = field;
842766Speter 					}
843*15934Smckusick 					putleaf( P2ICON , strnglen , 0 , P2INT , (char *) 0 );
844766Speter 				}
845766Speter 				putop( P2LISTOP , P2INT );
846*15934Smckusick 				putleaf( P2ICON , 1 , 0 , P2INT , (char *) 0 );
847766Speter 				putop( P2LISTOP , P2INT );
848766Speter 				putleaf( P2ICON , 0 , 0
849766Speter 				    , ADDTYPE( P2FTN | P2INT , P2PTR )
850766Speter 				    , "_ACTFILE" );
851*15934Smckusick 				putRV((char *) 0, cbn , CURFILEOFFSET , NLOCAL ,
8523833Speter 					P2PTR|P2STRTY );
853766Speter 				putop( P2CALL , P2INT );
854766Speter 				putop( P2LISTOP , P2INT );
855766Speter 				putop( P2CALL , P2INT );
856766Speter 				putdot( filename , line );
857766Speter 			}
858766Speter 		}
859766Speter 		/*
860766Speter 		 * Done with arguments.
861766Speter 		 * Handle writeln and
862766Speter 		 * insufficent number of args.
863766Speter 		 */
864766Speter 		switch (p->value[0] &~ NSTAND) {
865766Speter 			case O_WRITEF:
866766Speter 				if (argc == 0)
867766Speter 					error("Write requires an argument");
868766Speter 				break;
869766Speter 			case O_MESSAGE:
870766Speter 				if (argc == 0)
871766Speter 					error("Message requires an argument");
872766Speter 			case O_WRITLN:
873766Speter 				if (filetype != nl+T1CHAR)
874766Speter 					error("Can't 'writeln' a non text file");
875766Speter 				if ( opt( 't' ) ) {
876766Speter 				    putleaf( P2ICON , 0 , 0
877766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
878766Speter 					, "_WRITLN" );
879*15934Smckusick 				    putRV((char *) 0 , cbn , CURFILEOFFSET ,
8803833Speter 					    NLOCAL , P2PTR|P2STRTY );
881766Speter 				} else {
882766Speter 				    putleaf( P2ICON , 0 , 0
883766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
884766Speter 					, "_fputc" );
885*15934Smckusick 				    putleaf( P2ICON , '\n' , 0 , (int) P2CHAR , (char *) 0 );
886766Speter 				    putleaf( P2ICON , 0 , 0
887766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
888766Speter 					, "_ACTFILE" );
889*15934Smckusick 				    putRV((char *) 0 , cbn , CURFILEOFFSET ,
8903833Speter 					    NLOCAL , P2PTR|P2STRTY );
891766Speter 				    putop( P2CALL , P2INT );
892766Speter 				    putop( P2LISTOP , P2INT );
893766Speter 				}
894766Speter 				putop( P2CALL , P2INT );
895766Speter 				putdot( filename , line );
896766Speter 				break;
897766Speter 		}
898766Speter 		return;
899766Speter 
900766Speter 	case O_READ4:
901766Speter 	case O_READLN:
902766Speter 		/*
903766Speter 		 * Set up default
904766Speter 		 * file "input".
905766Speter 		 */
906766Speter 		file = NIL;
907766Speter 		filetype = nl+T1CHAR;
908766Speter 		/*
909766Speter 		 * Determine the file implied
910766Speter 		 * for the read and generate
911766Speter 		 * code to make it the active file.
912766Speter 		 */
913*15934Smckusick 		if (argv != TR_NIL) {
914766Speter 			codeoff();
915*15934Smckusick 			ap = stkrval(argv->list_node.list, NLNIL, (long) RREQ );
916766Speter 			codeon();
917*15934Smckusick 			if (ap == NLNIL)
918*15934Smckusick 				argv = argv->list_node.next;
919*15934Smckusick 			if (ap != NLNIL && ap->class == FILET) {
920766Speter 				/*
921766Speter 				 * Got "read(f, ...", make
922766Speter 				 * f the active file, and save
923766Speter 				 * it and its type for use in
924766Speter 				 * processing the rest of the
925766Speter 				 * arguments to read.
926766Speter 				 */
927*15934Smckusick 				file = argv->list_node.list;
928766Speter 				filetype = ap->type;
929*15934Smckusick 				putRV((char *) 0, cbn , CURFILEOFFSET , NLOCAL ,
9303833Speter 					P2PTR|P2STRTY );
931766Speter 				putleaf( P2ICON , 0 , 0
932766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
933766Speter 					, "_UNIT" );
934*15934Smckusick 				(void) stklval(argv->list_node.list, NOFLAGS);
935766Speter 				putop( P2CALL , P2INT );
936766Speter 				putop( P2ASSIGN , P2PTR|P2STRTY );
937766Speter 				putdot( filename , line );
938*15934Smckusick 				argv = argv->list_node.next;
939766Speter 				argc--;
940766Speter 			} else {
941766Speter 				/*
942766Speter 				 * Default is read from
943766Speter 				 * standard input.
944766Speter 				 */
945*15934Smckusick 				putRV((char *) 0, cbn , CURFILEOFFSET , NLOCAL ,
9463833Speter 					P2PTR|P2STRTY );
9473833Speter 				putLV( "_input" , 0 , 0 , NGLOBAL ,
9483833Speter 					P2PTR|P2STRTY );
949766Speter 				putop( P2ASSIGN , P2PTR|P2STRTY );
950766Speter 				putdot( filename , line );
951766Speter 				input->nl_flags |= NUSED;
952766Speter 			}
953766Speter 		} else {
954*15934Smckusick 			putRV((char *) 0, cbn , CURFILEOFFSET , NLOCAL ,
9553833Speter 				P2PTR|P2STRTY );
9563833Speter 			putLV( "_input" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY );
957766Speter 			putop( P2ASSIGN , P2PTR|P2STRTY );
958766Speter 			putdot( filename , line );
959766Speter 			input->nl_flags |= NUSED;
960766Speter 		}
961766Speter 		/*
962766Speter 		 * Loop and process each
963766Speter 		 * of the arguments.
964766Speter 		 */
965*15934Smckusick 		for (; argv != TR_NIL; argv = argv->list_node.next) {
966766Speter 			/*
967766Speter 			 * Get the address of the target
968766Speter 			 * on the stack.
969766Speter 			 */
970*15934Smckusick 			al = argv->list_node.list;
971*15934Smckusick 			if (al == TR_NIL)
972766Speter 				continue;
973*15934Smckusick 			if (al->tag != T_VAR) {
974766Speter 				error("Arguments to %s must be variables, not expressions", p->symbol);
975766Speter 				continue;
976766Speter 			}
977766Speter 			codeoff();
978766Speter 			ap = stklval(al, MOD|ASGN|NOUSE);
979766Speter 			codeon();
980*15934Smckusick 			if (ap == NLNIL)
981766Speter 				continue;
982766Speter 			if (filetype != nl+T1CHAR) {
983766Speter 				/*
984766Speter 				 * Generalized read, i.e.
985766Speter 				 * from a non-textfile.
986766Speter 				 */
987*15934Smckusick 				if (incompat(filetype, ap, argv->list_node.list )) {
988766Speter 					error("Type mismatch in read from non-text file");
989766Speter 					continue;
990766Speter 				}
991766Speter 				/*
992766Speter 				 * var := file ^;
993766Speter 				 */
994766Speter 				ap = lvalue( al , MOD | ASGN | NOUSE , RREQ );
995766Speter 				if ( isa( ap , "bsci" ) ) {
996766Speter 					precheck( ap , "_RANG4" , "_RSNG4" );
997766Speter 				}
998766Speter 				putleaf( P2ICON , 0 , 0
999*15934Smckusick 				    , (int) (ADDTYPE(
1000766Speter 					ADDTYPE(
1001766Speter 					    ADDTYPE(
1002766Speter 						p2type( filetype ) , P2PTR )
1003766Speter 					    , P2FTN )
1004*15934Smckusick 					, P2PTR ))
1005766Speter 				    , "_FNIL" );
1006766Speter 				if (file != NIL)
1007*15934Smckusick 					(void) stklval(file, NOFLAGS);
1008766Speter 				else /* Magic */
10093833Speter 					putRV( "_input" , 0 , 0 , NGLOBAL ,
10103833Speter 						P2PTR | P2STRTY );
101110668Speter 				putop(P2CALL, ADDTYPE(p2type(filetype), P2PTR));
1012766Speter 				switch ( classify( filetype ) ) {
1013766Speter 				    case TBOOL:
1014766Speter 				    case TCHAR:
1015766Speter 				    case TINT:
1016766Speter 				    case TSCAL:
1017766Speter 				    case TDOUBLE:
1018766Speter 				    case TPTR:
1019766Speter 					putop( P2UNARY P2MUL
1020766Speter 						, p2type( filetype ) );
1021766Speter 				}
1022766Speter 				switch ( classify( filetype ) ) {
1023766Speter 				    case TBOOL:
1024766Speter 				    case TCHAR:
1025766Speter 				    case TINT:
1026766Speter 				    case TSCAL:
102710373Speter 					    postcheck(ap, filetype);
102810373Speter 					    sconv(p2type(filetype), p2type(ap));
1029766Speter 						/* and fall through */
1030766Speter 				    case TDOUBLE:
1031766Speter 				    case TPTR:
1032766Speter 					    putop( P2ASSIGN , p2type( ap ) );
1033766Speter 					    putdot( filename , line );
1034766Speter 					    break;
1035766Speter 				    default:
103611856Speter 					    putstrop(P2STASG,
103711856Speter 						    ADDTYPE(p2type(ap), P2PTR),
1038*15934Smckusick 						    (int) lwidth(ap),
103911856Speter 						    align(ap));
1040766Speter 					    putdot( filename , line );
1041766Speter 					    break;
1042766Speter 				}
1043766Speter 				/*
1044766Speter 				 * get(file);
1045766Speter 				 */
1046766Speter 				putleaf( P2ICON , 0 , 0
1047766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
1048766Speter 					, "_GET" );
1049*15934Smckusick 				putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL ,
10503833Speter 					P2PTR|P2STRTY );
1051766Speter 				putop( P2CALL , P2INT );
1052766Speter 				putdot( filename , line );
1053766Speter 				continue;
1054766Speter 			}
1055766Speter 			    /*
1056766Speter 			     *	if you get to here, you are reading from
1057766Speter 			     *	a text file.  only possiblities are:
1058766Speter 			     *	character, integer, real, or scalar.
1059766Speter 			     *	read( f , foo , ... ) is done as
1060766Speter 			     *	foo := read( f ) with rangechecking
1061766Speter 			     *	if appropriate.
1062766Speter 			     */
1063766Speter 			typ = classify(ap);
1064766Speter 			op = rdops(typ);
1065766Speter 			if (op == NIL) {
1066766Speter 				error("Can't read %ss from a text file", clnames[typ]);
1067766Speter 				continue;
1068766Speter 			}
1069766Speter 			    /*
1070766Speter 			     *	left hand side of foo := read( f )
1071766Speter 			     */
1072766Speter 			ap = lvalue( al , MOD|ASGN|NOUSE , RREQ );
1073766Speter 			if ( isa( ap , "bsci" ) ) {
1074766Speter 			    precheck( ap , "_RANG4" , "_RSNG4" );
1075766Speter 			}
1076766Speter 			switch ( op ) {
1077766Speter 			    case O_READC:
1078766Speter 				readname = "_READC";
1079766Speter 				readtype = P2INT;
1080766Speter 				break;
1081766Speter 			    case O_READ4:
1082766Speter 				readname = "_READ4";
1083766Speter 				readtype = P2INT;
1084766Speter 				break;
1085766Speter 			    case O_READ8:
1086766Speter 				readname = "_READ8";
1087766Speter 				readtype = P2DOUBLE;
1088766Speter 				break;
1089766Speter 			    case O_READE:
1090766Speter 				readname = "_READE";
1091766Speter 				readtype = P2INT;
1092766Speter 				break;
1093766Speter 			}
1094766Speter 			putleaf( P2ICON , 0 , 0
1095*15934Smckusick 				, (int) ADDTYPE( P2FTN | readtype , P2PTR )
1096766Speter 				, readname );
1097*15934Smckusick 			putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL ,
10983833Speter 				P2PTR|P2STRTY );
1099766Speter 			if ( op == O_READE ) {
1100766Speter 				sprintf( format , PREFIXFORMAT , LABELPREFIX
1101766Speter 					, listnames( ap ) );
1102*15934Smckusick 				putleaf( P2ICON , 0, 0, (int) (P2PTR | P2CHAR),
1103*15934Smckusick 					format );
1104766Speter 				putop( P2LISTOP , P2INT );
11051629Speter 				warning();
1106766Speter 				if (opt('s')) {
1107766Speter 					standard();
1108766Speter 				}
11091629Speter 				error("Reading scalars from text files is non-standard");
1110766Speter 			}
1111*15934Smckusick 			putop( P2CALL , (int) readtype );
1112766Speter 			if ( isa( ap , "bcsi" ) ) {
111310373Speter 			    postcheck(ap, readtype==P2INT?nl+T4INT:nl+TDOUBLE);
1114766Speter 			}
1115*15934Smckusick 			sconv((int) readtype, p2type(ap));
1116766Speter 			putop( P2ASSIGN , p2type( ap ) );
1117766Speter 			putdot( filename , line );
1118766Speter 		}
1119766Speter 		/*
1120766Speter 		 * Done with arguments.
1121766Speter 		 * Handle readln and
1122766Speter 		 * insufficient number of args.
1123766Speter 		 */
1124766Speter 		if (p->value[0] == O_READLN) {
1125766Speter 			if (filetype != nl+T1CHAR)
1126766Speter 				error("Can't 'readln' a non text file");
1127766Speter 			putleaf( P2ICON , 0 , 0
1128*15934Smckusick 				, (int) ADDTYPE( P2FTN | P2INT , P2PTR )
1129766Speter 				, "_READLN" );
1130*15934Smckusick 			putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL ,
11313833Speter 				P2PTR|P2STRTY );
1132766Speter 			putop( P2CALL , P2INT );
1133766Speter 			putdot( filename , line );
1134766Speter 		} else if (argc == 0)
1135766Speter 			error("read requires an argument");
1136766Speter 		return;
1137766Speter 
1138766Speter 	case O_GET:
1139766Speter 	case O_PUT:
1140766Speter 		if (argc != 1) {
1141766Speter 			error("%s expects one argument", p->symbol);
1142766Speter 			return;
1143766Speter 		}
1144*15934Smckusick 		putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY );
1145766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1146766Speter 			, "_UNIT" );
1147*15934Smckusick 		ap = stklval(argv->list_node.list, NOFLAGS);
1148*15934Smckusick 		if (ap == NLNIL)
1149766Speter 			return;
1150766Speter 		if (ap->class != FILET) {
1151766Speter 			error("Argument to %s must be a file, not %s", p->symbol, nameof(ap));
1152766Speter 			return;
1153766Speter 		}
1154766Speter 		putop( P2CALL , P2INT );
1155766Speter 		putop( P2ASSIGN , P2PTR|P2STRTY );
1156766Speter 		putdot( filename , line );
1157766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1158766Speter 			, op == O_GET ? "_GET" : "_PUT" );
1159*15934Smckusick 		putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY );
1160766Speter 		putop( P2CALL , P2INT );
1161766Speter 		putdot( filename , line );
1162766Speter 		return;
1163766Speter 
1164766Speter 	case O_RESET:
1165766Speter 	case O_REWRITE:
1166766Speter 		if (argc == 0 || argc > 2) {
1167766Speter 			error("%s expects one or two arguments", p->symbol);
1168766Speter 			return;
1169766Speter 		}
1170766Speter 		if (opt('s') && argc == 2) {
1171766Speter 			standard();
1172766Speter 			error("Two argument forms of reset and rewrite are non-standard");
1173766Speter 		}
1174766Speter 		putleaf( P2ICON , 0 , 0 , P2INT
1175766Speter 			, op == O_RESET ? "_RESET" : "_REWRITE" );
1176*15934Smckusick 		ap = stklval(argv->list_node.list, MOD|NOUSE);
1177*15934Smckusick 		if (ap == NLNIL)
1178766Speter 			return;
1179766Speter 		if (ap->class != FILET) {
1180766Speter 			error("First argument to %s must be a file, not %s", p->symbol, nameof(ap));
1181766Speter 			return;
1182766Speter 		}
1183766Speter 		if (argc == 2) {
1184766Speter 			/*
1185766Speter 			 * Optional second argument
1186766Speter 			 * is a string name of a
1187766Speter 			 * UNIX (R) file to be associated.
1188766Speter 			 */
1189*15934Smckusick 			al = argv->list_node.next;
1190*15934Smckusick 			al = (struct tnode *) stkrval(al->list_node.list,
1191*15934Smckusick 					NLNIL , (long) RREQ );
1192*15934Smckusick 			if (al == TR_NIL)
1193766Speter 				return;
1194*15934Smckusick 			if (classify((struct nl *) al) != TSTR) {
1195*15934Smckusick 				error("Second argument to %s must be a string, not %s", p->symbol, nameof((struct nl *) al));
1196766Speter 				return;
1197766Speter 			}
1198*15934Smckusick 			strnglen = width((struct nl *) al);
1199766Speter 		} else {
1200*15934Smckusick 			putleaf( P2ICON , 0 , 0 , P2INT , (char *) 0 );
1201766Speter 			strnglen = 0;
1202766Speter 		}
1203766Speter 		putop( P2LISTOP , P2INT );
1204*15934Smckusick 		putleaf( P2ICON , strnglen , 0 , P2INT , (char *) 0 );
1205766Speter 		putop( P2LISTOP , P2INT );
1206*15934Smckusick 		putleaf( P2ICON , text(ap) ? 0: width(ap->type) , 0 , P2INT , (char *) 0 );
1207766Speter 		putop( P2LISTOP , P2INT );
1208766Speter 		putop( P2CALL , P2INT );
1209766Speter 		putdot( filename , line );
1210766Speter 		return;
1211766Speter 
1212766Speter 	case O_NEW:
1213766Speter 	case O_DISPOSE:
1214766Speter 		if (argc == 0) {
1215766Speter 			error("%s expects at least one argument", p->symbol);
1216766Speter 			return;
1217766Speter 		}
1218*15934Smckusick 		alv = argv->list_node.list;
12197967Smckusick 		codeoff();
12209139Smckusick 		ap = stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD );
12217967Smckusick 		codeon();
1222*15934Smckusick 		if (ap == NLNIL)
1223766Speter 			return;
1224766Speter 		if (ap->class != PTR) {
1225766Speter 			error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap));
1226766Speter 			return;
1227766Speter 		}
1228766Speter 		ap = ap->type;
1229*15934Smckusick 		if (ap == NLNIL)
1230766Speter 			return;
12319139Smckusick 		if (op == O_NEW)
12329139Smckusick 			cmd = "_NEW";
12339139Smckusick 		else /* op == O_DISPOSE */
12347967Smckusick 			if ((ap->nl_flags & NFILES) != 0)
12357967Smckusick 				cmd = "_DFDISPOSE";
12367967Smckusick 			else
12377967Smckusick 				cmd = "_DISPOSE";
12387967Smckusick 		putleaf( P2ICON, 0, 0, ADDTYPE( P2FTN | P2INT , P2PTR ), cmd);
1239*15934Smckusick 		(void) stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD );
1240*15934Smckusick 		argv = argv->list_node.next;
1241*15934Smckusick 		if (argv != TR_NIL) {
1242766Speter 			if (ap->class != RECORD) {
1243766Speter 				error("Record required when specifying variant tags");
1244766Speter 				return;
1245766Speter 			}
1246*15934Smckusick 			for (; argv != TR_NIL; argv = argv->list_node.next) {
1247766Speter 				if (ap->ptr[NL_VARNT] == NIL) {
1248766Speter 					error("Too many tag fields");
1249766Speter 					return;
1250766Speter 				}
1251*15934Smckusick 				if (!isconst(argv->list_node.list)) {
1252766Speter 					error("Second and successive arguments to %s must be constants", p->symbol);
1253766Speter 					return;
1254766Speter 				}
1255*15934Smckusick 				gconst(argv->list_node.list);
1256766Speter 				if (con.ctype == NIL)
1257766Speter 					return;
1258*15934Smckusick 				if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , TR_NIL )) {
1259766Speter 					cerror("Specified tag constant type clashed with variant case selector type");
1260766Speter 					return;
1261766Speter 				}
1262766Speter 				for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain)
1263766Speter 					if (ap->range[0] == con.crval)
1264766Speter 						break;
1265766Speter 				if (ap == NIL) {
1266766Speter 					error("No variant case label value equals specified constant value");
1267766Speter 					return;
1268766Speter 				}
1269766Speter 				ap = ap->ptr[NL_VTOREC];
1270766Speter 			}
1271766Speter 		}
1272*15934Smckusick 		putleaf( P2ICON , width( ap ) , 0 , P2INT , (char *) 0 );
1273766Speter 		putop( P2LISTOP , P2INT );
1274766Speter 		putop( P2CALL , P2INT );
1275766Speter 		putdot( filename , line );
12769139Smckusick 		if (opt('t') && op == O_NEW) {
12779139Smckusick 		    putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
12789139Smckusick 			    , "_blkclr" );
1279*15934Smckusick 		    (void) stkrval(alv, NLNIL , (long) RREQ );
1280*15934Smckusick 		    putleaf( P2ICON , width( ap ) , 0 , P2INT , (char *) 0 );
12819139Smckusick 		    putop( P2LISTOP , P2INT );
12829139Smckusick 		    putop( P2CALL , P2INT );
12839139Smckusick 		    putdot( filename , line );
12849139Smckusick 		}
1285766Speter 		return;
1286766Speter 
1287766Speter 	case O_DATE:
1288766Speter 	case O_TIME:
1289766Speter 		if (argc != 1) {
1290766Speter 			error("%s expects one argument", p->symbol);
1291766Speter 			return;
1292766Speter 		}
1293766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1294766Speter 			, op == O_DATE ? "_DATE" : "_TIME" );
1295*15934Smckusick 		ap = stklval(argv->list_node.list, MOD|NOUSE);
1296766Speter 		if (ap == NIL)
1297766Speter 			return;
1298766Speter 		if (classify(ap) != TSTR || width(ap) != 10) {
1299766Speter 			error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap));
1300766Speter 			return;
1301766Speter 		}
1302766Speter 		putop( P2CALL , P2INT );
1303766Speter 		putdot( filename , line );
1304766Speter 		return;
1305766Speter 
1306766Speter 	case O_HALT:
1307766Speter 		if (argc != 0) {
1308766Speter 			error("halt takes no arguments");
1309766Speter 			return;
1310766Speter 		}
1311766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1312766Speter 			, "_HALT" );
1313766Speter 
1314766Speter 		putop( P2UNARY P2CALL , P2INT );
1315766Speter 		putdot( filename , line );
1316*15934Smckusick 		noreach = TRUE;
1317766Speter 		return;
1318766Speter 
1319766Speter 	case O_ARGV:
1320766Speter 		if (argc != 2) {
1321766Speter 			error("argv takes two arguments");
1322766Speter 			return;
1323766Speter 		}
1324766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1325766Speter 			, "_ARGV" );
1326*15934Smckusick 		ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ );
1327*15934Smckusick 		if (ap == NLNIL)
1328766Speter 			return;
1329766Speter 		if (isnta(ap, "i")) {
1330766Speter 			error("argv's first argument must be an integer, not %s", nameof(ap));
1331766Speter 			return;
1332766Speter 		}
1333*15934Smckusick 		al = argv->list_node.next;
1334*15934Smckusick 		ap = stklval(al->list_node.list, MOD|NOUSE);
1335*15934Smckusick 		if (ap == NLNIL)
1336766Speter 			return;
1337766Speter 		if (classify(ap) != TSTR) {
1338766Speter 			error("argv's second argument must be a string, not %s", nameof(ap));
1339766Speter 			return;
1340766Speter 		}
1341766Speter 		putop( P2LISTOP , P2INT );
1342*15934Smckusick 		putleaf( P2ICON , width( ap ) , 0 , P2INT , (char *) 0 );
1343766Speter 		putop( P2LISTOP , P2INT );
1344766Speter 		putop( P2CALL , P2INT );
1345766Speter 		putdot( filename , line );
1346766Speter 		return;
1347766Speter 
1348766Speter 	case O_STLIM:
1349766Speter 		if (argc != 1) {
1350766Speter 			error("stlimit requires one argument");
1351766Speter 			return;
1352766Speter 		}
1353766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1354766Speter 			, "_STLIM" );
1355*15934Smckusick 		ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ );
1356*15934Smckusick 		if (ap == NLNIL)
1357766Speter 			return;
1358766Speter 		if (isnta(ap, "i")) {
1359766Speter 			error("stlimit's argument must be an integer, not %s", nameof(ap));
1360766Speter 			return;
1361766Speter 		}
1362766Speter 		putop( P2CALL , P2INT );
1363766Speter 		putdot( filename , line );
1364766Speter 		return;
1365766Speter 
1366766Speter 	case O_REMOVE:
1367766Speter 		if (argc != 1) {
1368766Speter 			error("remove expects one argument");
1369766Speter 			return;
1370766Speter 		}
1371766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1372766Speter 			, "_REMOVE" );
1373*15934Smckusick 		ap = stkrval(argv->list_node.list, NLNIL, (long) RREQ );
1374*15934Smckusick 		if (ap == NLNIL)
1375766Speter 			return;
1376766Speter 		if (classify(ap) != TSTR) {
1377766Speter 			error("remove's argument must be a string, not %s", nameof(ap));
1378766Speter 			return;
1379766Speter 		}
1380*15934Smckusick 		putleaf( P2ICON , width( ap ) , 0 , P2INT , (char *) 0 );
1381766Speter 		putop( P2LISTOP , P2INT );
1382766Speter 		putop( P2CALL , P2INT );
1383766Speter 		putdot( filename , line );
1384766Speter 		return;
1385766Speter 
1386766Speter 	case O_LLIMIT:
1387766Speter 		if (argc != 2) {
1388766Speter 			error("linelimit expects two arguments");
1389766Speter 			return;
1390766Speter 		}
1391766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1392766Speter 			, "_LLIMIT" );
1393*15934Smckusick 		ap = stklval(argv->list_node.list, NOFLAGS|NOUSE);
1394*15934Smckusick 		if (ap == NLNIL)
1395766Speter 			return;
1396766Speter 		if (!text(ap)) {
1397766Speter 			error("linelimit's first argument must be a text file, not %s", nameof(ap));
1398766Speter 			return;
1399766Speter 		}
1400*15934Smckusick 		al = argv->list_node.next;
1401*15934Smckusick 		ap = stkrval(al->list_node.list, NLNIL , (long) RREQ );
1402*15934Smckusick 		if (ap == NLNIL)
1403766Speter 			return;
1404766Speter 		if (isnta(ap, "i")) {
1405766Speter 			error("linelimit's second argument must be an integer, not %s", nameof(ap));
1406766Speter 			return;
1407766Speter 		}
1408766Speter 		putop( P2LISTOP , P2INT );
1409766Speter 		putop( P2CALL , P2INT );
1410766Speter 		putdot( filename , line );
1411766Speter 		return;
1412766Speter 	case O_PAGE:
1413766Speter 		if (argc != 1) {
1414766Speter 			error("page expects one argument");
1415766Speter 			return;
1416766Speter 		}
1417*15934Smckusick 		putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY );
1418766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1419766Speter 			, "_UNIT" );
1420*15934Smckusick 		ap = stklval(argv->list_node.list, NOFLAGS);
1421*15934Smckusick 		if (ap == NLNIL)
1422766Speter 			return;
1423766Speter 		if (!text(ap)) {
1424766Speter 			error("Argument to page must be a text file, not %s", nameof(ap));
1425766Speter 			return;
1426766Speter 		}
1427766Speter 		putop( P2CALL , P2INT );
1428766Speter 		putop( P2ASSIGN , P2PTR|P2STRTY );
1429766Speter 		putdot( filename , line );
1430766Speter 		if ( opt( 't' ) ) {
1431766Speter 		    putleaf( P2ICON , 0 , 0
1432766Speter 			, ADDTYPE( P2FTN | P2INT , P2PTR )
1433766Speter 			, "_PAGE" );
1434*15934Smckusick 		    putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY );
1435766Speter 		} else {
1436766Speter 		    putleaf( P2ICON , 0 , 0
1437766Speter 			, ADDTYPE( P2FTN | P2INT , P2PTR )
1438766Speter 			, "_fputc" );
1439*15934Smckusick 		    putleaf( P2ICON , '\f' , 0 , (int) P2CHAR , (char *) 0 );
1440766Speter 		    putleaf( P2ICON , 0 , 0
1441766Speter 			, ADDTYPE( P2FTN | P2INT , P2PTR )
1442766Speter 			, "_ACTFILE" );
1443*15934Smckusick 		    putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY );
1444766Speter 		    putop( P2CALL , P2INT );
1445766Speter 		    putop( P2LISTOP , P2INT );
1446766Speter 		}
1447766Speter 		putop( P2CALL , P2INT );
1448766Speter 		putdot( filename , line );
1449766Speter 		return;
1450766Speter 
14517928Smckusick 	case O_ASRT:
14527928Smckusick 		if (!opt('t'))
14537928Smckusick 			return;
14547928Smckusick 		if (argc == 0 || argc > 2) {
14557928Smckusick 			error("Assert expects one or two arguments");
14567928Smckusick 			return;
14577928Smckusick 		}
14589139Smckusick 		if (argc == 2)
14599139Smckusick 			cmd = "_ASRTS";
14609139Smckusick 		else
14619139Smckusick 			cmd = "_ASRT";
14627928Smckusick 		putleaf( P2ICON , 0 , 0
14639139Smckusick 		    , ADDTYPE( P2FTN | P2INT , P2PTR ) , cmd );
1464*15934Smckusick 		ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ );
1465*15934Smckusick 		if (ap == NLNIL)
14667928Smckusick 			return;
14677928Smckusick 		if (isnta(ap, "b"))
14687928Smckusick 			error("Assert expression must be Boolean, not %ss", nameof(ap));
14697928Smckusick 		if (argc == 2) {
14707928Smckusick 			/*
14717928Smckusick 			 * Optional second argument is a string specifying
14727928Smckusick 			 * why the assertion failed.
14737928Smckusick 			 */
1474*15934Smckusick 			al = argv->list_node.next;
1475*15934Smckusick 			al = (struct tnode *) stkrval(al->list_node.list, NLNIL , (long) RREQ );
1476*15934Smckusick 			if (al == TR_NIL)
14777928Smckusick 				return;
1478*15934Smckusick 			if (classify((struct nl *) al) != TSTR) {
1479*15934Smckusick 				error("Second argument to assert must be a string, not %s", nameof((struct nl *) al));
14807928Smckusick 				return;
14817928Smckusick 			}
14829139Smckusick 			putop( P2LISTOP , P2INT );
14837928Smckusick 		}
14847928Smckusick 		putop( P2CALL , P2INT );
14857928Smckusick 		putdot( filename , line );
14867928Smckusick 		return;
14877928Smckusick 
1488766Speter 	case O_PACK:
1489766Speter 		if (argc != 3) {
1490766Speter 			error("pack expects three arguments");
1491766Speter 			return;
1492766Speter 		}
1493766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1494766Speter 			, "_PACK" );
1495766Speter 		pu = "pack(a,i,z)";
1496*15934Smckusick 		pua = (al = argv)->list_node.list;
1497*15934Smckusick 		pui = (al = al->list_node.next)->list_node.list;
1498*15934Smckusick 		puz = (al = al->list_node.next)->list_node.list;
1499766Speter 		goto packunp;
1500766Speter 	case O_UNPACK:
1501766Speter 		if (argc != 3) {
1502766Speter 			error("unpack expects three arguments");
1503766Speter 			return;
1504766Speter 		}
1505766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1506766Speter 			, "_UNPACK" );
1507766Speter 		pu = "unpack(z,a,i)";
1508*15934Smckusick 		puz = (al = argv)->list_node.list;
1509*15934Smckusick 		pua = (al = al->list_node.next)->list_node.list;
1510*15934Smckusick 		pui = (al = al->list_node.next)->list_node.list;
1511766Speter packunp:
1512*15934Smckusick 		ap = stkrval(pui, NLNIL , (long) RREQ );
1513766Speter 		if (ap == NIL)
1514766Speter 			return;
1515766Speter 		ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE);
1516766Speter 		if (ap == NIL)
1517766Speter 			return;
1518766Speter 		if (ap->class != ARRAY) {
1519766Speter 			error("%s requires a to be an unpacked array, not %s", pu, nameof(ap));
1520766Speter 			return;
1521766Speter 		}
1522766Speter 		putop( P2LISTOP , P2INT );
1523*15934Smckusick 		al = (struct tnode *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE);
1524*15934Smckusick 		if (((struct nl *) al)->class != ARRAY) {
1525766Speter 			error("%s requires z to be a packed array, not %s", pu, nameof(ap));
1526766Speter 			return;
1527766Speter 		}
1528*15934Smckusick 		if (((struct nl *) al)->type == NIL ||
1529*15934Smckusick 			((struct nl *) ap)->type == NIL)
1530766Speter 			return;
1531*15934Smckusick 		if (((struct nl *) al)->type != ((struct nl *) ap)->type) {
1532766Speter 			error("%s requires a and z to be arrays of the same type", pu, nameof(ap));
1533766Speter 			return;
1534766Speter 		}
1535766Speter 		putop( P2LISTOP , P2INT );
1536*15934Smckusick 		k = width((struct nl *) al);
1537766Speter 		itemwidth = width(ap->type);
1538766Speter 		ap = ap->chain;
1539*15934Smckusick 		al = ((struct tnode *) ((struct nl *) al)->chain);
1540*15934Smckusick 		if (ap->chain != NIL || ((struct nl *) al)->chain != NIL) {
1541766Speter 			error("%s requires a and z to be single dimension arrays", pu);
1542766Speter 			return;
1543766Speter 		}
1544766Speter 		if (ap == NIL || al == NIL)
1545766Speter 			return;
1546766Speter 		/*
1547766Speter 		 * al is the range for z i.e. u..v
1548766Speter 		 * ap is the range for a i.e. m..n
1549766Speter 		 * i will be n-m+1
1550766Speter 		 * j will be v-u+1
1551766Speter 		 */
1552766Speter 		i = ap->range[1] - ap->range[0] + 1;
1553*15934Smckusick 		j = ((struct nl *) al)->range[1] -
1554*15934Smckusick 			((struct nl *) al)->range[0] + 1;
1555766Speter 		if (i < j) {
1556*15934Smckusick 			error("%s cannot have more elements in a (%d) than in z (%d)", pu, (char *) j, (char *) i);
1557766Speter 			return;
1558766Speter 		}
1559766Speter 		/*
1560766Speter 		 * get n-m-(v-u) and m for the interpreter
1561766Speter 		 */
1562766Speter 		i -= j;
1563766Speter 		j = ap->range[0];
1564*15934Smckusick 		putleaf( P2ICON , itemwidth , 0 , P2INT , (char *) 0 );
1565766Speter 		putop( P2LISTOP , P2INT );
1566*15934Smckusick 		putleaf( P2ICON , j , 0 , P2INT , (char *) 0 );
1567766Speter 		putop( P2LISTOP , P2INT );
1568*15934Smckusick 		putleaf( P2ICON , i , 0 , P2INT , (char *) 0 );
1569766Speter 		putop( P2LISTOP , P2INT );
1570*15934Smckusick 		putleaf( P2ICON , k , 0 , P2INT , (char *) 0 );
1571766Speter 		putop( P2LISTOP , P2INT );
1572766Speter 		putop( P2CALL , P2INT );
1573766Speter 		putdot( filename , line );
1574766Speter 		return;
1575766Speter 	case 0:
15767928Smckusick 		error("%s is an unimplemented extension", p->symbol);
1577766Speter 		return;
1578766Speter 
1579766Speter 	default:
1580766Speter 		panic("proc case");
1581766Speter 	}
1582766Speter }
1583766Speter #endif PC
1584