xref: /csrg-svn/usr.bin/pascal/src/pcproc.c (revision 9139)
1766Speter /* Copyright (c) 1979 Regents of the University of California */
2766Speter 
3*9139Smckusick static	char sccsid[] = "@(#)pcproc.c 1.13 11/12/82";
4766Speter 
5766Speter #include "whoami.h"
6766Speter #ifdef PC
7766Speter     /*
8766Speter      * and to the end of the file
9766Speter      */
10766Speter #include "0.h"
11766Speter #include "tree.h"
12766Speter #include "opcode.h"
13766Speter #include	"pc.h"
14766Speter #include	"pcops.h"
15766Speter 
16766Speter /*
17766Speter  * The following array is used to determine which classes may be read
18766Speter  * from textfiles. It is indexed by the return value from classify.
19766Speter  */
20766Speter #define rdops(x) rdxxxx[(x)-(TFIRST)]
21766Speter 
22766Speter int rdxxxx[] = {
23766Speter 	0,		/* -7 file types */
24766Speter 	0,		/* -6 record types */
25766Speter 	0,		/* -5 array types */
26766Speter 	O_READE,	/* -4 scalar types */
27766Speter 	0,		/* -3 pointer types */
28766Speter 	0,		/* -2 set types */
29766Speter 	0,		/* -1 string types */
30766Speter 	0,		/*  0 nil, no type */
31766Speter 	O_READE,	/*  1 boolean */
32766Speter 	O_READC,	/*  2 character */
33766Speter 	O_READ4,	/*  3 integer */
34766Speter 	O_READ8		/*  4 real */
35766Speter };
36766Speter 
37766Speter /*
38766Speter  * Proc handles procedure calls.
39766Speter  * Non-builtin procedures are "buck-passed" to func (with a flag
40766Speter  * indicating that they are actually procedures.
41766Speter  * builtin procedures are handled here.
42766Speter  */
43766Speter pcproc(r)
44766Speter 	int *r;
45766Speter {
46766Speter 	register struct nl *p;
47766Speter 	register int *alv, *al, op;
48766Speter 	struct nl *filetype, *ap;
49766Speter 	int argc, *argv, typ, fmtspec, strfmt, stkcnt, *file;
507967Smckusick 	char fmt, format[20], *strptr, *cmd;
51766Speter 	int prec, field, strnglen, fmtlen, fmtstart, pu;
52766Speter 	int *pua, *pui, *puz;
53766Speter 	int i, j, k;
54766Speter 	int itemwidth;
553833Speter 	char		*readname;
563833Speter 	struct nl	*tempnlp;
573833Speter 	long		readtype;
583833Speter 	struct tmps	soffset;
59766Speter 
60766Speter #define	CONPREC 4
61766Speter #define	VARPREC 8
62766Speter #define	CONWIDTH 1
63766Speter #define	VARWIDTH 2
64766Speter #define SKIP 16
65766Speter 
66766Speter 	/*
67766Speter 	 * Verify that the name is
68766Speter 	 * defined and is that of a
69766Speter 	 * procedure.
70766Speter 	 */
71766Speter 	p = lookup(r[2]);
72766Speter 	if (p == NIL) {
73766Speter 		rvlist(r[3]);
74766Speter 		return;
75766Speter 	}
761197Speter 	if (p->class != PROC && p->class != FPROC) {
77766Speter 		error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]);
78766Speter 		rvlist(r[3]);
79766Speter 		return;
80766Speter 	}
81766Speter 	argv = r[3];
82766Speter 
83766Speter 	/*
84766Speter 	 * Call handles user defined
85766Speter 	 * procedures and functions.
86766Speter 	 */
87766Speter 	if (bn != 0) {
88766Speter 		call(p, argv, PROC, bn);
89766Speter 		return;
90766Speter 	}
91766Speter 
92766Speter 	/*
93766Speter 	 * Call to built-in procedure.
94766Speter 	 * Count the arguments.
95766Speter 	 */
96766Speter 	argc = 0;
97766Speter 	for (al = argv; al != NIL; al = al[2])
98766Speter 		argc++;
99766Speter 
100766Speter 	/*
101766Speter 	 * Switch on the operator
102766Speter 	 * associated with the built-in
103766Speter 	 * procedure in the namelist
104766Speter 	 */
105766Speter 	op = p->value[0] &~ NSTAND;
106766Speter 	if (opt('s') && (p->value[0] & NSTAND)) {
107766Speter 		standard();
108766Speter 		error("%s is a nonstandard procedure", p->symbol);
109766Speter 	}
110766Speter 	switch (op) {
111766Speter 
112766Speter 	case O_ABORT:
113766Speter 		if (argc != 0)
114766Speter 			error("null takes no arguments");
115766Speter 		return;
116766Speter 
117766Speter 	case O_FLUSH:
118766Speter 		if (argc == 0) {
119766Speter 			putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" );
120766Speter 			putop( P2UNARY P2CALL , P2INT );
121766Speter 			putdot( filename , line );
122766Speter 			return;
123766Speter 		}
124766Speter 		if (argc != 1) {
125766Speter 			error("flush takes at most one argument");
126766Speter 			return;
127766Speter 		}
128766Speter 		putleaf( P2ICON , 0 , 0
129766Speter 			, ADDTYPE( P2FTN | P2INT , P2PTR )
130766Speter 			, "_FLUSH" );
131766Speter 		ap = stklval(argv[1], NOFLAGS);
132766Speter 		if (ap == NIL)
133766Speter 			return;
134766Speter 		if (ap->class != FILET) {
135766Speter 			error("flush's argument must be a file, not %s", nameof(ap));
136766Speter 			return;
137766Speter 		}
138766Speter 		putop( P2CALL , P2INT );
139766Speter 		putdot( filename , line );
140766Speter 		return;
141766Speter 
142766Speter 	case O_MESSAGE:
143766Speter 	case O_WRITEF:
144766Speter 	case O_WRITLN:
145766Speter 		/*
146766Speter 		 * Set up default file "output"'s type
147766Speter 		 */
148766Speter 		file = NIL;
149766Speter 		filetype = nl+T1CHAR;
150766Speter 		/*
151766Speter 		 * Determine the file implied
152766Speter 		 * for the write and generate
153766Speter 		 * code to make it the active file.
154766Speter 		 */
155766Speter 		if (op == O_MESSAGE) {
156766Speter 			/*
157766Speter 			 * For message, all that matters
158766Speter 			 * is that the filetype is
159766Speter 			 * a character file.
160766Speter 			 * Thus "output" will suit us fine.
161766Speter 			 */
162766Speter 			putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" );
163766Speter 			putop( P2UNARY P2CALL , P2INT );
164766Speter 			putdot( filename , line );
1653833Speter 			putRV( 0 , cbn , CURFILEOFFSET , NLOCAL ,
1663833Speter 				P2PTR|P2STRTY );
1673833Speter 			putLV( "__err" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY );
168766Speter 			putop( P2ASSIGN , P2PTR|P2STRTY );
169766Speter 			putdot( filename , line );
170766Speter 		} else if (argv != NIL && (al = argv[1])[0] != T_WEXP) {
171766Speter 			/*
172766Speter 			 * If there is a first argument which has
173766Speter 			 * no write widths, then it is potentially
174766Speter 			 * a file name.
175766Speter 			 */
176766Speter 			codeoff();
177766Speter 			ap = stkrval(argv[1], NIL , RREQ );
178766Speter 			codeon();
179766Speter 			if (ap == NIL)
180766Speter 				argv = argv[2];
181766Speter 			if (ap != NIL && ap->class == FILET) {
182766Speter 				/*
183766Speter 				 * Got "write(f, ...", make
184766Speter 				 * f the active file, and save
185766Speter 				 * it and its type for use in
186766Speter 				 * processing the rest of the
187766Speter 				 * arguments to write.
188766Speter 				 */
1893833Speter 				putRV( 0 , cbn , CURFILEOFFSET , NLOCAL ,
1903833Speter 					P2PTR|P2STRTY );
191766Speter 				putleaf( P2ICON , 0 , 0
192766Speter 				    , ADDTYPE( P2FTN | P2INT , P2PTR )
193766Speter 				    , "_UNIT" );
194766Speter 				file = argv[1];
195766Speter 				filetype = ap->type;
196766Speter 				stklval(argv[1], NOFLAGS);
197766Speter 				putop( P2CALL , P2INT );
198766Speter 				putop( P2ASSIGN , P2PTR|P2STRTY );
199766Speter 				putdot( filename , line );
200766Speter 				/*
201766Speter 				 * Skip over the first argument
202766Speter 				 */
203766Speter 				argv = argv[2];
204766Speter 				argc--;
205766Speter 			} else {
206766Speter 				/*
207766Speter 				 * Set up for writing on
208766Speter 				 * standard output.
209766Speter 				 */
2103833Speter 				putRV( 0, cbn , CURFILEOFFSET ,
2113833Speter 					NLOCAL , P2PTR|P2STRTY );
2123833Speter 				putLV( "_output" , 0 , 0 , NGLOBAL ,
2133833Speter 					P2PTR|P2STRTY );
214766Speter 				putop( P2ASSIGN , P2PTR|P2STRTY );
215766Speter 				putdot( filename , line );
2167954Speter 				output->nl_flags |= NUSED;
217766Speter 			}
218766Speter 		} else {
2193833Speter 			putRV( 0, cbn , CURFILEOFFSET , NLOCAL ,
2203833Speter 				P2PTR|P2STRTY );
2213833Speter 			putLV( "_output" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY );
222766Speter 			putop( P2ASSIGN , P2PTR|P2STRTY );
223766Speter 			putdot( filename , line );
2247954Speter 			output->nl_flags |= NUSED;
225766Speter 		}
226766Speter 		/*
227766Speter 		 * Loop and process each
228766Speter 		 * of the arguments.
229766Speter 		 */
230766Speter 		for (; argv != NIL; argv = argv[2]) {
231766Speter 			/*
232766Speter 			 * fmtspec indicates the type (CONstant or VARiable)
233766Speter 			 *	and number (none, WIDTH, and/or PRECision)
234766Speter 			 *	of the fields in the printf format for this
235766Speter 			 *	output variable.
236766Speter 			 * stkcnt is the number of longs pushed on the stack
237766Speter 			 * fmt is the format output indicator (D, E, F, O, X, S)
238766Speter 			 * fmtstart = 0 for leading blank; = 1 for no blank
239766Speter 			 */
240766Speter 			fmtspec = NIL;
241766Speter 			stkcnt = 0;
242766Speter 			fmt = 'D';
243766Speter 			fmtstart = 1;
244766Speter 			al = argv[1];
245766Speter 			if (al == NIL)
246766Speter 				continue;
247766Speter 			if (al[0] == T_WEXP)
248766Speter 				alv = al[1];
249766Speter 			else
250766Speter 				alv = al;
251766Speter 			if (alv == NIL)
252766Speter 				continue;
253766Speter 			codeoff();
254766Speter 			ap = stkrval(alv, NIL , RREQ );
255766Speter 			codeon();
256766Speter 			if (ap == NIL)
257766Speter 				continue;
258766Speter 			typ = classify(ap);
259766Speter 			if (al[0] == T_WEXP) {
260766Speter 				/*
261766Speter 				 * Handle width expressions.
262766Speter 				 * The basic game here is that width
263766Speter 				 * expressions get evaluated. If they
264766Speter 				 * are constant, the value is placed
265766Speter 				 * directly in the format string.
266766Speter 				 * Otherwise the value is pushed onto
267766Speter 				 * the stack and an indirection is
268766Speter 				 * put into the format string.
269766Speter 				 */
270766Speter 				if (al[3] == OCT)
271766Speter 					fmt = 'O';
272766Speter 				else if (al[3] == HEX)
273766Speter 					fmt = 'X';
274766Speter 				else if (al[3] != NIL) {
275766Speter 					/*
276766Speter 					 * Evaluate second format spec
277766Speter 					 */
278766Speter 					if ( constval(al[3])
279766Speter 					    && isa( con.ctype , "i" ) ) {
280766Speter 						fmtspec += CONPREC;
281766Speter 						prec = con.crval;
282766Speter 					} else {
283766Speter 						fmtspec += VARPREC;
284766Speter 					}
285766Speter 					fmt = 'f';
286766Speter 					switch ( typ ) {
287766Speter 					case TINT:
288766Speter 						if ( opt( 's' ) ) {
289766Speter 						    standard();
290766Speter 						    error("Writing %ss with two write widths is non-standard", clnames[typ]);
291766Speter 						}
292766Speter 						/* and fall through */
293766Speter 					case TDOUBLE:
294766Speter 						break;
295766Speter 					default:
296766Speter 						error("Cannot write %ss with two write widths", clnames[typ]);
297766Speter 						continue;
298766Speter 					}
299766Speter 				}
300766Speter 				/*
301766Speter 				 * Evaluate first format spec
302766Speter 				 */
303766Speter 				if (al[2] != NIL) {
304766Speter 					if ( constval(al[2])
305766Speter 					    && isa( con.ctype , "i" ) ) {
306766Speter 						fmtspec += CONWIDTH;
307766Speter 						field = con.crval;
308766Speter 					} else {
309766Speter 						fmtspec += VARWIDTH;
310766Speter 					}
311766Speter 				}
312766Speter 				if ((fmtspec & CONPREC) && prec < 0 ||
313766Speter 				    (fmtspec & CONWIDTH) && field < 0) {
314766Speter 					error("Negative widths are not allowed");
315766Speter 					continue;
316766Speter 				}
3173180Smckusic 				if ( opt('s') &&
3183180Smckusic 				    ((fmtspec & CONPREC) && prec == 0 ||
3193180Smckusic 				    (fmtspec & CONWIDTH) && field == 0)) {
3203180Smckusic 					standard();
3213180Smckusic 					error("Zero widths are non-standard");
3223180Smckusic 				}
323766Speter 			}
324766Speter 			if (filetype != nl+T1CHAR) {
325766Speter 				if (fmt == 'O' || fmt == 'X') {
326766Speter 					error("Oct/hex allowed only on text files");
327766Speter 					continue;
328766Speter 				}
329766Speter 				if (fmtspec) {
330766Speter 					error("Write widths allowed only on text files");
331766Speter 					continue;
332766Speter 				}
333766Speter 				/*
334766Speter 				 * Generalized write, i.e.
335766Speter 				 * to a non-textfile.
336766Speter 				 */
337766Speter 				putleaf( P2ICON , 0 , 0
338766Speter 				    , ADDTYPE(
339766Speter 					ADDTYPE(
340766Speter 					    ADDTYPE( p2type( filetype )
341766Speter 						    , P2PTR )
342766Speter 					    , P2FTN )
343766Speter 					, P2PTR )
344766Speter 				    , "_FNIL" );
345766Speter 				stklval(file, NOFLAGS);
346766Speter 				putop( P2CALL
347766Speter 				    , ADDTYPE( p2type( filetype ) , P2PTR ) );
348766Speter 				putop( P2UNARY P2MUL , p2type( filetype ) );
349766Speter 				/*
350766Speter 				 * file^ := ...
351766Speter 				 */
352766Speter 				switch ( classify( filetype ) ) {
353766Speter 				    case TBOOL:
354766Speter 				    case TCHAR:
355766Speter 				    case TINT:
356766Speter 				    case TSCAL:
3574589Speter 					precheck( filetype , "_RANG4"  , "_RSNG4" );
358766Speter 					    /* and fall through */
359766Speter 				    case TDOUBLE:
360766Speter 				    case TPTR:
361766Speter 					ap = rvalue( argv[1] , filetype , RREQ );
362766Speter 					break;
363766Speter 				    default:
364766Speter 					ap = rvalue( argv[1] , filetype , LREQ );
365766Speter 					break;
366766Speter 				}
367766Speter 				if (ap == NIL)
368766Speter 					continue;
369766Speter 				if (incompat(ap, filetype, argv[1])) {
370766Speter 					cerror("Type mismatch in write to non-text file");
371766Speter 					continue;
372766Speter 				}
373766Speter 				switch ( classify( filetype ) ) {
374766Speter 				    case TBOOL:
375766Speter 				    case TCHAR:
376766Speter 				    case TINT:
377766Speter 				    case TSCAL:
378766Speter 					    postcheck( filetype );
379766Speter 						/* and fall through */
380766Speter 				    case TDOUBLE:
381766Speter 				    case TPTR:
382766Speter 					    putop( P2ASSIGN , p2type( filetype ) );
383766Speter 					    putdot( filename , line );
384766Speter 					    break;
385766Speter 				    default:
386766Speter 					    putstrop( P2STASG
387766Speter 							, p2type( filetype )
388766Speter 							, lwidth( filetype )
389766Speter 							, align( filetype ) );
390766Speter 					    putdot( filename , line );
391766Speter 					    break;
392766Speter 				}
393766Speter 				/*
394766Speter 				 * put(file)
395766Speter 				 */
396766Speter 				putleaf( P2ICON , 0 , 0
397766Speter 				    , ADDTYPE( P2FTN | P2INT , P2PTR )
398766Speter 				    , "_PUT" );
3993833Speter 				putRV( 0 , cbn , CURFILEOFFSET , NLOCAL ,
4003833Speter 					P2PTR|P2STRTY );
401766Speter 				putop( P2CALL , P2INT );
402766Speter 				putdot( filename , line );
403766Speter 				continue;
404766Speter 			}
405766Speter 			/*
406766Speter 			 * Write to a textfile
407766Speter 			 *
408766Speter 			 * Evaluate the expression
409766Speter 			 * to be written.
410766Speter 			 */
411766Speter 			if (fmt == 'O' || fmt == 'X') {
412766Speter 				if (opt('s')) {
413766Speter 					standard();
414766Speter 					error("Oct and hex are non-standard");
415766Speter 				}
416766Speter 				if (typ == TSTR || typ == TDOUBLE) {
417766Speter 					error("Can't write %ss with oct/hex", clnames[typ]);
418766Speter 					continue;
419766Speter 				}
420766Speter 				if (typ == TCHAR || typ == TBOOL)
421766Speter 					typ = TINT;
422766Speter 			}
423766Speter 			/*
424766Speter 			 * If there is no format specified by the programmer,
425766Speter 			 * implement the default.
426766Speter 			 */
427766Speter 			switch (typ) {
4286540Smckusick 			case TPTR:
4296540Smckusick 				warning();
4306540Smckusick 				if (opt('s')) {
4316540Smckusick 					standard();
4326540Smckusick 				}
4336540Smckusick 				error("Writing %ss to text files is non-standard",
4346540Smckusick 				    clnames[typ]);
4356540Smckusick 				/* and fall through */
436766Speter 			case TINT:
437766Speter 				if (fmt == 'f') {
438766Speter 					typ = TDOUBLE;
439766Speter 					goto tdouble;
440766Speter 				}
441766Speter 				if (fmtspec == NIL) {
442766Speter 					if (fmt == 'D')
443766Speter 						field = 10;
444766Speter 					else if (fmt == 'X')
445766Speter 						field = 8;
446766Speter 					else if (fmt == 'O')
447766Speter 						field = 11;
448766Speter 					else
449766Speter 						panic("fmt1");
450766Speter 					fmtspec = CONWIDTH;
451766Speter 				}
452766Speter 				break;
453766Speter 			case TCHAR:
454766Speter 			     tchar:
455766Speter 				fmt = 'c';
456766Speter 				break;
457766Speter 			case TSCAL:
4581629Speter 				warning();
459766Speter 				if (opt('s')) {
460766Speter 					standard();
461766Speter 				}
4626540Smckusick 				error("Writing %ss to text files is non-standard",
4636540Smckusick 				    clnames[typ]);
464766Speter 			case TBOOL:
465766Speter 				fmt = 's';
466766Speter 				break;
467766Speter 			case TDOUBLE:
468766Speter 			     tdouble:
469766Speter 				switch (fmtspec) {
470766Speter 				case NIL:
471766Speter 					field = 21;
472766Speter 					prec = 14;
4733225Smckusic 					fmt = 'e';
474766Speter 					fmtspec = CONWIDTH + CONPREC;
475766Speter 					break;
476766Speter 				case CONWIDTH:
477766Speter 					if (--field < 1)
478766Speter 						field = 1;
479766Speter 					prec = field - 7;
480766Speter 					if (prec < 1)
481766Speter 						prec = 1;
482766Speter 					fmtspec += CONPREC;
4833225Smckusic 					fmt = 'e';
484766Speter 					break;
485766Speter 				case VARWIDTH:
486766Speter 					fmtspec += VARPREC;
4873225Smckusic 					fmt = 'e';
488766Speter 					break;
489766Speter 				case CONWIDTH + CONPREC:
490766Speter 				case CONWIDTH + VARPREC:
491766Speter 					if (--field < 1)
492766Speter 						field = 1;
493766Speter 				}
494766Speter 				format[0] = ' ';
4958025Smckusick 				fmtstart = 1;
496766Speter 				break;
497766Speter 			case TSTR:
498766Speter 				constval( alv );
499766Speter 				switch ( classify( con.ctype ) ) {
500766Speter 				    case TCHAR:
501766Speter 					typ = TCHAR;
502766Speter 					goto tchar;
503766Speter 				    case TSTR:
504766Speter 					strptr = con.cpval;
505766Speter 					for (strnglen = 0;  *strptr++;  strnglen++) /* void */;
506766Speter 					strptr = con.cpval;
507766Speter 					break;
508766Speter 				    default:
509766Speter 					strnglen = width(ap);
510766Speter 					break;
511766Speter 				}
512766Speter 				fmt = 's';
513766Speter 				strfmt = fmtspec;
514766Speter 				if (fmtspec == NIL) {
515766Speter 					fmtspec = SKIP;
516766Speter 					break;
517766Speter 				}
518766Speter 				if (fmtspec & CONWIDTH) {
519766Speter 					if (field <= strnglen)
520766Speter 						fmtspec = SKIP;
521766Speter 					else
522766Speter 						field -= strnglen;
523766Speter 				}
524766Speter 				break;
525766Speter 			default:
526766Speter 				error("Can't write %ss to a text file", clnames[typ]);
527766Speter 				continue;
528766Speter 			}
529766Speter 			/*
530766Speter 			 * Generate the format string
531766Speter 			 */
532766Speter 			switch (fmtspec) {
533766Speter 			default:
534766Speter 				panic("fmt2");
535766Speter 			case NIL:
536766Speter 				if (fmt == 'c') {
537766Speter 					if ( opt( 't' ) ) {
538766Speter 					    putleaf( P2ICON , 0 , 0
539766Speter 						, ADDTYPE( P2FTN|P2INT , P2PTR )
540766Speter 						, "_WRITEC" );
5413833Speter 					    putRV( 0 , cbn , CURFILEOFFSET ,
5423833Speter 						    NLOCAL , P2PTR|P2STRTY );
543766Speter 					    stkrval( alv , NIL , RREQ );
544766Speter 					    putop( P2LISTOP , P2INT );
545766Speter 					} else {
546766Speter 					    putleaf( P2ICON , 0 , 0
547766Speter 						, ADDTYPE( P2FTN|P2INT , P2PTR )
548766Speter 						, "_fputc" );
549766Speter 					    stkrval( alv , NIL , RREQ );
550766Speter 					}
551766Speter 					putleaf( P2ICON , 0 , 0
552766Speter 					    , ADDTYPE( P2FTN | P2INT , P2PTR )
553766Speter 					    , "_ACTFILE" );
5543833Speter 					putRV( 0, cbn , CURFILEOFFSET ,
5553833Speter 						NLOCAL , P2PTR|P2STRTY );
556766Speter 					putop( P2CALL , P2INT );
557766Speter 					putop( P2LISTOP , P2INT );
558766Speter 					putop( P2CALL , P2INT );
559766Speter 					putdot( filename , line );
560766Speter 				} else  {
561766Speter 					sprintf(&format[1], "%%%c", fmt);
562766Speter 					goto fmtgen;
563766Speter 				}
564766Speter 			case SKIP:
565766Speter 				break;
566766Speter 			case CONWIDTH:
567766Speter 				sprintf(&format[1], "%%%1D%c", field, fmt);
568766Speter 				goto fmtgen;
569766Speter 			case VARWIDTH:
570766Speter 				sprintf(&format[1], "%%*%c", fmt);
571766Speter 				goto fmtgen;
572766Speter 			case CONWIDTH + CONPREC:
573766Speter 				sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt);
574766Speter 				goto fmtgen;
575766Speter 			case CONWIDTH + VARPREC:
576766Speter 				sprintf(&format[1], "%%%1D.*%c", field, fmt);
577766Speter 				goto fmtgen;
578766Speter 			case VARWIDTH + CONPREC:
579766Speter 				sprintf(&format[1], "%%*.%1D%c", prec, fmt);
580766Speter 				goto fmtgen;
581766Speter 			case VARWIDTH + VARPREC:
582766Speter 				sprintf(&format[1], "%%*.*%c", fmt);
583766Speter 			fmtgen:
584766Speter 				if ( opt( 't' ) ) {
585766Speter 				    putleaf( P2ICON , 0 , 0
586766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
587766Speter 					, "_WRITEF" );
5883833Speter 				    putRV( 0 , cbn , CURFILEOFFSET ,
5893833Speter 					    NLOCAL , P2PTR|P2STRTY );
590766Speter 				    putleaf( P2ICON , 0 , 0
591766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
592766Speter 					, "_ACTFILE" );
5933833Speter 				    putRV( 0 , cbn , CURFILEOFFSET ,
5943833Speter 					    NLOCAL , P2PTR|P2STRTY );
595766Speter 				    putop( P2CALL , P2INT );
596766Speter 				    putop( P2LISTOP , P2INT );
597766Speter 				} else {
598766Speter 				    putleaf( P2ICON , 0 , 0
599766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
600766Speter 					, "_fprintf" );
601766Speter 				    putleaf( P2ICON , 0 , 0
602766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
603766Speter 					, "_ACTFILE" );
6043833Speter 				    putRV( 0 , cbn , CURFILEOFFSET ,
6053833Speter 					    NLOCAL , P2PTR|P2STRTY );
606766Speter 				    putop( P2CALL , P2INT );
607766Speter 				}
608766Speter 				putCONG( &format[ fmtstart ]
609766Speter 					, strlen( &format[ fmtstart ] )
610766Speter 					, LREQ );
611766Speter 				putop( P2LISTOP , P2INT );
612766Speter 				if ( fmtspec & VARWIDTH ) {
613766Speter 					/*
614766Speter 					 * either
615766Speter 					 *	,(temp=width,MAX(temp,...)),
616766Speter 					 * or
617766Speter 					 *	, MAX( width , ... ) ,
618766Speter 					 */
619766Speter 				    if ( ( typ == TDOUBLE && al[3] == NIL )
620766Speter 					|| typ == TSTR ) {
6213225Smckusic 					soffset = sizes[cbn].curtmps;
6223833Speter 					tempnlp = tmpalloc(sizeof(long),
6233225Smckusic 						nl+T4INT, REGOK);
6243833Speter 					putRV( 0 , cbn ,
6253833Speter 					    tempnlp -> value[ NL_OFFS ] ,
6263833Speter 					    tempnlp -> extra_flags , P2INT );
627766Speter 					ap = stkrval( al[2] , NIL , RREQ );
628766Speter 					putop( P2ASSIGN , P2INT );
629766Speter 					putleaf( P2ICON , 0 , 0
630766Speter 					    , ADDTYPE( P2FTN | P2INT , P2PTR )
631766Speter 					    , "_MAX" );
6323833Speter 					putRV( 0 , cbn ,
6333833Speter 					    tempnlp -> value[ NL_OFFS ] ,
6343833Speter 					    tempnlp -> extra_flags , P2INT );
635766Speter 				    } else {
636766Speter 					if (opt('t')
637766Speter 					    || typ == TSTR || typ == TDOUBLE) {
638766Speter 					    putleaf( P2ICON , 0 , 0
639766Speter 						,ADDTYPE( P2FTN | P2INT, P2PTR )
640766Speter 						,"_MAX" );
641766Speter 					}
642766Speter 					ap = stkrval( al[2] , NIL , RREQ );
643766Speter 				    }
644766Speter 				    if (ap == NIL)
645766Speter 					    continue;
646766Speter 				    if (isnta(ap,"i")) {
647766Speter 					    error("First write width must be integer, not %s", nameof(ap));
648766Speter 					    continue;
649766Speter 				    }
650766Speter 				    switch ( typ ) {
651766Speter 				    case TDOUBLE:
652766Speter 					putleaf( P2ICON , 1 , 0 , P2INT , 0 );
653766Speter 					putop( P2LISTOP , P2INT );
654766Speter 					putleaf( P2ICON , 1 , 0 , P2INT , 0 );
655766Speter 					putop( P2LISTOP , P2INT );
656766Speter 					putop( P2CALL , P2INT );
657766Speter 					if ( al[3] == NIL ) {
658766Speter 						/*
659766Speter 						 * finish up the comma op
660766Speter 						 */
661766Speter 					    putop( P2COMOP , P2INT );
662766Speter 					    fmtspec &= ~VARPREC;
663766Speter 					    putop( P2LISTOP , P2INT );
664766Speter 					    putleaf( P2ICON , 0 , 0
665766Speter 						, ADDTYPE( P2FTN | P2INT , P2PTR )
666766Speter 						, "_MAX" );
6673833Speter 					    putRV( 0 , cbn ,
6683833Speter 						tempnlp -> value[ NL_OFFS ] ,
6693833Speter 						tempnlp -> extra_flags ,
6703833Speter 						P2INT );
6713225Smckusic 					    tmpfree(&soffset);
672766Speter 					    putleaf( P2ICON , 8 , 0 , P2INT , 0 );
673766Speter 					    putop( P2LISTOP , P2INT );
674766Speter 					    putleaf( P2ICON , 1 , 0 , P2INT , 0 );
675766Speter 					    putop( P2LISTOP , P2INT );
676766Speter 					    putop( P2CALL , P2INT );
677766Speter 					}
678766Speter 					putop( P2LISTOP , P2INT );
679766Speter 					break;
680766Speter 				    case TSTR:
681766Speter 					putleaf( P2ICON , strnglen , 0 , P2INT , 0 );
682766Speter 					putop( P2LISTOP , P2INT );
683766Speter 					putleaf( P2ICON , 0 , 0 , P2INT , 0 );
684766Speter 					putop( P2LISTOP , P2INT );
685766Speter 					putop( P2CALL , P2INT );
686766Speter 					putop( P2COMOP , P2INT );
687766Speter 					putop( P2LISTOP , P2INT );
688766Speter 					break;
689766Speter 				    default:
690766Speter 					if (opt('t')) {
691766Speter 					    putleaf( P2ICON , 0 , 0 , P2INT , 0 );
692766Speter 					    putop( P2LISTOP , P2INT );
693766Speter 					    putleaf( P2ICON , 0 , 0 , P2INT , 0 );
694766Speter 					    putop( P2LISTOP , P2INT );
695766Speter 					    putop( P2CALL , P2INT );
696766Speter 					}
697766Speter 					putop( P2LISTOP , P2INT );
698766Speter 					break;
699766Speter 				    }
700766Speter 				}
701766Speter 				/*
702766Speter 				 * If there is a variable precision,
703766Speter 				 * evaluate it
704766Speter 				 */
705766Speter 				if (fmtspec & VARPREC) {
706766Speter 					if (opt('t')) {
707766Speter 					putleaf( P2ICON , 0 , 0
708766Speter 					    , ADDTYPE( P2FTN | P2INT , P2PTR )
709766Speter 					    , "_MAX" );
710766Speter 					}
711766Speter 					ap = stkrval( al[3] , NIL , RREQ );
712766Speter 					if (ap == NIL)
713766Speter 						continue;
714766Speter 					if (isnta(ap,"i")) {
715766Speter 						error("Second write width must be integer, not %s", nameof(ap));
716766Speter 						continue;
717766Speter 					}
718766Speter 					if (opt('t')) {
719766Speter 					    putleaf( P2ICON , 0 , 0 , P2INT , 0 );
720766Speter 					    putop( P2LISTOP , P2INT );
721766Speter 					    putleaf( P2ICON , 0 , 0 , P2INT , 0 );
722766Speter 					    putop( P2LISTOP , P2INT );
723766Speter 					    putop( P2CALL , P2INT );
724766Speter 					}
725766Speter 				 	putop( P2LISTOP , P2INT );
726766Speter 				}
727766Speter 				/*
728766Speter 				 * evaluate the thing we want printed.
729766Speter 				 */
730766Speter 				switch ( typ ) {
7316540Smckusick 				case TPTR:
732766Speter 				case TCHAR:
733766Speter 				case TINT:
734766Speter 				    stkrval( alv , NIL , RREQ );
735766Speter 				    putop( P2LISTOP , P2INT );
736766Speter 				    break;
737766Speter 				case TDOUBLE:
738766Speter 				    ap = stkrval( alv , NIL , RREQ );
739766Speter 				    if ( isnta( ap , "d" ) ) {
740766Speter 					putop( P2SCONV , P2DOUBLE );
741766Speter 				    }
742766Speter 				    putop( P2LISTOP , P2INT );
743766Speter 				    break;
744766Speter 				case TSCAL:
745766Speter 				case TBOOL:
746766Speter 				    putleaf( P2ICON , 0 , 0
747766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
748766Speter 					, "_NAM" );
749766Speter 				    ap = stkrval( alv , NIL , RREQ );
750766Speter 				    sprintf( format , PREFIXFORMAT , LABELPREFIX
751766Speter 					    , listnames( ap ) );
752766Speter 				    putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR
753766Speter 					    , format );
754766Speter 				    putop( P2LISTOP , P2INT );
755766Speter 				    putop( P2CALL , P2INT );
756766Speter 				    putop( P2LISTOP , P2INT );
757766Speter 				    break;
758766Speter 				case TSTR:
759766Speter 				    putCONG( "" , 0 , LREQ );
760766Speter 				    putop( P2LISTOP , P2INT );
761766Speter 				    break;
7626540Smckusick 				default:
7636540Smckusick 				    panic("fmt3");
7646540Smckusick 				    break;
765766Speter 				}
766766Speter 				putop( P2CALL , P2INT );
767766Speter 				putdot( filename , line );
768766Speter 			}
769766Speter 			/*
770766Speter 			 * Write the string after its blank padding
771766Speter 			 */
772766Speter 			if (typ == TSTR ) {
773766Speter 				if ( opt( 't' ) ) {
774766Speter 				    putleaf( P2ICON , 0 , 0
775766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
776766Speter 					, "_WRITES" );
7773833Speter 				    putRV( 0 , cbn , CURFILEOFFSET ,
7783833Speter 					    NLOCAL , P2PTR|P2STRTY );
779766Speter 				    ap = stkrval(alv, NIL , RREQ );
780766Speter 				    putop( P2LISTOP , P2INT );
781766Speter 				} else {
782766Speter 				    putleaf( P2ICON , 0 , 0
783766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
784766Speter 					, "_fwrite" );
785766Speter 				    ap = stkrval(alv, NIL , RREQ );
786766Speter 				}
787766Speter 				if (strfmt & VARWIDTH) {
788766Speter 					    /*
789766Speter 					     *	min, inline expanded as
790766Speter 					     *	temp < len ? temp : len
791766Speter 					     */
7923833Speter 					putRV( 0 , cbn ,
7933833Speter 					    tempnlp -> value[ NL_OFFS ] ,
7943833Speter 					    tempnlp -> extra_flags , P2INT );
795766Speter 					putleaf( P2ICON , strnglen , 0 , P2INT , 0 );
796766Speter 					putop( P2LT , P2INT );
7973833Speter 					putRV( 0 , cbn ,
7983833Speter 					    tempnlp -> value[ NL_OFFS ] ,
7993833Speter 					    tempnlp -> extra_flags , P2INT );
800766Speter 					putleaf( P2ICON , strnglen , 0 , P2INT , 0 );
801766Speter 					putop( P2COLON , P2INT );
802766Speter 					putop( P2QUEST , P2INT );
8033225Smckusic 					tmpfree(&soffset);
804766Speter 				} else {
805766Speter 					if (   ( fmtspec & SKIP )
806766Speter 					    && ( strfmt & CONWIDTH ) ) {
807766Speter 						strnglen = field;
808766Speter 					}
809766Speter 					putleaf( P2ICON , strnglen , 0 , P2INT , 0 );
810766Speter 				}
811766Speter 				putop( P2LISTOP , P2INT );
812766Speter 				putleaf( P2ICON , 1 , 0 , P2INT , 0 );
813766Speter 				putop( P2LISTOP , P2INT );
814766Speter 				putleaf( P2ICON , 0 , 0
815766Speter 				    , ADDTYPE( P2FTN | P2INT , P2PTR )
816766Speter 				    , "_ACTFILE" );
8173833Speter 				putRV( 0, cbn , CURFILEOFFSET , NLOCAL ,
8183833Speter 					P2PTR|P2STRTY );
819766Speter 				putop( P2CALL , P2INT );
820766Speter 				putop( P2LISTOP , P2INT );
821766Speter 				putop( P2CALL , P2INT );
822766Speter 				putdot( filename , line );
823766Speter 			}
824766Speter 		}
825766Speter 		/*
826766Speter 		 * Done with arguments.
827766Speter 		 * Handle writeln and
828766Speter 		 * insufficent number of args.
829766Speter 		 */
830766Speter 		switch (p->value[0] &~ NSTAND) {
831766Speter 			case O_WRITEF:
832766Speter 				if (argc == 0)
833766Speter 					error("Write requires an argument");
834766Speter 				break;
835766Speter 			case O_MESSAGE:
836766Speter 				if (argc == 0)
837766Speter 					error("Message requires an argument");
838766Speter 			case O_WRITLN:
839766Speter 				if (filetype != nl+T1CHAR)
840766Speter 					error("Can't 'writeln' a non text file");
841766Speter 				if ( opt( 't' ) ) {
842766Speter 				    putleaf( P2ICON , 0 , 0
843766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
844766Speter 					, "_WRITLN" );
8453833Speter 				    putRV( 0 , cbn , CURFILEOFFSET ,
8463833Speter 					    NLOCAL , P2PTR|P2STRTY );
847766Speter 				} else {
848766Speter 				    putleaf( P2ICON , 0 , 0
849766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
850766Speter 					, "_fputc" );
851766Speter 				    putleaf( P2ICON , '\n' , 0 , P2CHAR , 0 );
852766Speter 				    putleaf( P2ICON , 0 , 0
853766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
854766Speter 					, "_ACTFILE" );
8553833Speter 				    putRV( 0 , cbn , CURFILEOFFSET ,
8563833Speter 					    NLOCAL , P2PTR|P2STRTY );
857766Speter 				    putop( P2CALL , P2INT );
858766Speter 				    putop( P2LISTOP , P2INT );
859766Speter 				}
860766Speter 				putop( P2CALL , P2INT );
861766Speter 				putdot( filename , line );
862766Speter 				break;
863766Speter 		}
864766Speter 		return;
865766Speter 
866766Speter 	case O_READ4:
867766Speter 	case O_READLN:
868766Speter 		/*
869766Speter 		 * Set up default
870766Speter 		 * file "input".
871766Speter 		 */
872766Speter 		file = NIL;
873766Speter 		filetype = nl+T1CHAR;
874766Speter 		/*
875766Speter 		 * Determine the file implied
876766Speter 		 * for the read and generate
877766Speter 		 * code to make it the active file.
878766Speter 		 */
879766Speter 		if (argv != NIL) {
880766Speter 			codeoff();
881766Speter 			ap = stkrval(argv[1], NIL , RREQ );
882766Speter 			codeon();
883766Speter 			if (ap == NIL)
884766Speter 				argv = argv[2];
885766Speter 			if (ap != NIL && ap->class == FILET) {
886766Speter 				/*
887766Speter 				 * Got "read(f, ...", make
888766Speter 				 * f the active file, and save
889766Speter 				 * it and its type for use in
890766Speter 				 * processing the rest of the
891766Speter 				 * arguments to read.
892766Speter 				 */
893766Speter 				file = argv[1];
894766Speter 				filetype = ap->type;
8953833Speter 				putRV( 0, cbn , CURFILEOFFSET , NLOCAL ,
8963833Speter 					P2PTR|P2STRTY );
897766Speter 				putleaf( P2ICON , 0 , 0
898766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
899766Speter 					, "_UNIT" );
900766Speter 				stklval(argv[1], NOFLAGS);
901766Speter 				putop( P2CALL , P2INT );
902766Speter 				putop( P2ASSIGN , P2PTR|P2STRTY );
903766Speter 				putdot( filename , line );
904766Speter 				argv = argv[2];
905766Speter 				argc--;
906766Speter 			} else {
907766Speter 				/*
908766Speter 				 * Default is read from
909766Speter 				 * standard input.
910766Speter 				 */
9113833Speter 				putRV( 0, cbn , CURFILEOFFSET , NLOCAL ,
9123833Speter 					P2PTR|P2STRTY );
9133833Speter 				putLV( "_input" , 0 , 0 , NGLOBAL ,
9143833Speter 					P2PTR|P2STRTY );
915766Speter 				putop( P2ASSIGN , P2PTR|P2STRTY );
916766Speter 				putdot( filename , line );
917766Speter 				input->nl_flags |= NUSED;
918766Speter 			}
919766Speter 		} else {
9203833Speter 			putRV( 0, cbn , CURFILEOFFSET , NLOCAL ,
9213833Speter 				P2PTR|P2STRTY );
9223833Speter 			putLV( "_input" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY );
923766Speter 			putop( P2ASSIGN , P2PTR|P2STRTY );
924766Speter 			putdot( filename , line );
925766Speter 			input->nl_flags |= NUSED;
926766Speter 		}
927766Speter 		/*
928766Speter 		 * Loop and process each
929766Speter 		 * of the arguments.
930766Speter 		 */
931766Speter 		for (; argv != NIL; argv = argv[2]) {
932766Speter 			/*
933766Speter 			 * Get the address of the target
934766Speter 			 * on the stack.
935766Speter 			 */
936766Speter 			al = argv[1];
937766Speter 			if (al == NIL)
938766Speter 				continue;
939766Speter 			if (al[0] != T_VAR) {
940766Speter 				error("Arguments to %s must be variables, not expressions", p->symbol);
941766Speter 				continue;
942766Speter 			}
943766Speter 			codeoff();
944766Speter 			ap = stklval(al, MOD|ASGN|NOUSE);
945766Speter 			codeon();
946766Speter 			if (ap == NIL)
947766Speter 				continue;
948766Speter 			if (filetype != nl+T1CHAR) {
949766Speter 				/*
950766Speter 				 * Generalized read, i.e.
951766Speter 				 * from a non-textfile.
952766Speter 				 */
953766Speter 				if (incompat(filetype, ap, argv[1] )) {
954766Speter 					error("Type mismatch in read from non-text file");
955766Speter 					continue;
956766Speter 				}
957766Speter 				/*
958766Speter 				 * var := file ^;
959766Speter 				 */
960766Speter 				ap = lvalue( al , MOD | ASGN | NOUSE , RREQ );
961766Speter 				if ( isa( ap , "bsci" ) ) {
962766Speter 					precheck( ap , "_RANG4" , "_RSNG4" );
963766Speter 				}
964766Speter 				putleaf( P2ICON , 0 , 0
965766Speter 				    , ADDTYPE(
966766Speter 					ADDTYPE(
967766Speter 					    ADDTYPE(
968766Speter 						p2type( filetype ) , P2PTR )
969766Speter 					    , P2FTN )
970766Speter 					, P2PTR )
971766Speter 				    , "_FNIL" );
972766Speter 				if (file != NIL)
973766Speter 					stklval(file, NOFLAGS);
974766Speter 				else /* Magic */
9753833Speter 					putRV( "_input" , 0 , 0 , NGLOBAL ,
9763833Speter 						P2PTR | P2STRTY );
977766Speter 				putop( P2CALL , P2INT );
978766Speter 				switch ( classify( filetype ) ) {
979766Speter 				    case TBOOL:
980766Speter 				    case TCHAR:
981766Speter 				    case TINT:
982766Speter 				    case TSCAL:
983766Speter 				    case TDOUBLE:
984766Speter 				    case TPTR:
985766Speter 					putop( P2UNARY P2MUL
986766Speter 						, p2type( filetype ) );
987766Speter 				}
988766Speter 				switch ( classify( filetype ) ) {
989766Speter 				    case TBOOL:
990766Speter 				    case TCHAR:
991766Speter 				    case TINT:
992766Speter 				    case TSCAL:
993766Speter 					    postcheck( ap );
994766Speter 						/* and fall through */
995766Speter 				    case TDOUBLE:
996766Speter 				    case TPTR:
997766Speter 					    putop( P2ASSIGN , p2type( ap ) );
998766Speter 					    putdot( filename , line );
999766Speter 					    break;
1000766Speter 				    default:
1001766Speter 					    putstrop( P2STASG
1002766Speter 							, p2type( ap )
1003766Speter 							, lwidth( ap )
1004766Speter 							, align( ap ) );
1005766Speter 					    putdot( filename , line );
1006766Speter 					    break;
1007766Speter 				}
1008766Speter 				/*
1009766Speter 				 * get(file);
1010766Speter 				 */
1011766Speter 				putleaf( P2ICON , 0 , 0
1012766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
1013766Speter 					, "_GET" );
10143833Speter 				putRV( 0 , cbn , CURFILEOFFSET , NLOCAL ,
10153833Speter 					P2PTR|P2STRTY );
1016766Speter 				putop( P2CALL , P2INT );
1017766Speter 				putdot( filename , line );
1018766Speter 				continue;
1019766Speter 			}
1020766Speter 			    /*
1021766Speter 			     *	if you get to here, you are reading from
1022766Speter 			     *	a text file.  only possiblities are:
1023766Speter 			     *	character, integer, real, or scalar.
1024766Speter 			     *	read( f , foo , ... ) is done as
1025766Speter 			     *	foo := read( f ) with rangechecking
1026766Speter 			     *	if appropriate.
1027766Speter 			     */
1028766Speter 			typ = classify(ap);
1029766Speter 			op = rdops(typ);
1030766Speter 			if (op == NIL) {
1031766Speter 				error("Can't read %ss from a text file", clnames[typ]);
1032766Speter 				continue;
1033766Speter 			}
1034766Speter 			    /*
1035766Speter 			     *	left hand side of foo := read( f )
1036766Speter 			     */
1037766Speter 			ap = lvalue( al , MOD|ASGN|NOUSE , RREQ );
1038766Speter 			if ( isa( ap , "bsci" ) ) {
1039766Speter 			    precheck( ap , "_RANG4" , "_RSNG4" );
1040766Speter 			}
1041766Speter 			switch ( op ) {
1042766Speter 			    case O_READC:
1043766Speter 				readname = "_READC";
1044766Speter 				readtype = P2INT;
1045766Speter 				break;
1046766Speter 			    case O_READ4:
1047766Speter 				readname = "_READ4";
1048766Speter 				readtype = P2INT;
1049766Speter 				break;
1050766Speter 			    case O_READ8:
1051766Speter 				readname = "_READ8";
1052766Speter 				readtype = P2DOUBLE;
1053766Speter 				break;
1054766Speter 			    case O_READE:
1055766Speter 				readname = "_READE";
1056766Speter 				readtype = P2INT;
1057766Speter 				break;
1058766Speter 			}
1059766Speter 			putleaf( P2ICON , 0 , 0
1060766Speter 				, ADDTYPE( P2FTN | readtype , P2PTR )
1061766Speter 				, readname );
10623833Speter 			putRV( 0 , cbn , CURFILEOFFSET , NLOCAL ,
10633833Speter 				P2PTR|P2STRTY );
1064766Speter 			if ( op == O_READE ) {
1065766Speter 				sprintf( format , PREFIXFORMAT , LABELPREFIX
1066766Speter 					, listnames( ap ) );
1067766Speter 				putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR
1068766Speter 					, format );
1069766Speter 				putop( P2LISTOP , P2INT );
10701629Speter 				warning();
1071766Speter 				if (opt('s')) {
1072766Speter 					standard();
1073766Speter 				}
10741629Speter 				error("Reading scalars from text files is non-standard");
1075766Speter 			}
1076766Speter 			putop( P2CALL , readtype );
1077766Speter 			if ( isa( ap , "bcsi" ) ) {
1078766Speter 			    postcheck( ap );
1079766Speter 			}
1080766Speter 			putop( P2ASSIGN , p2type( ap ) );
1081766Speter 			putdot( filename , line );
1082766Speter 		}
1083766Speter 		/*
1084766Speter 		 * Done with arguments.
1085766Speter 		 * Handle readln and
1086766Speter 		 * insufficient number of args.
1087766Speter 		 */
1088766Speter 		if (p->value[0] == O_READLN) {
1089766Speter 			if (filetype != nl+T1CHAR)
1090766Speter 				error("Can't 'readln' a non text file");
1091766Speter 			putleaf( P2ICON , 0 , 0
1092766Speter 				, ADDTYPE( P2FTN | P2INT , P2PTR )
1093766Speter 				, "_READLN" );
10943833Speter 			putRV( 0 , cbn , CURFILEOFFSET , NLOCAL ,
10953833Speter 				P2PTR|P2STRTY );
1096766Speter 			putop( P2CALL , P2INT );
1097766Speter 			putdot( filename , line );
1098766Speter 		} else if (argc == 0)
1099766Speter 			error("read requires an argument");
1100766Speter 		return;
1101766Speter 
1102766Speter 	case O_GET:
1103766Speter 	case O_PUT:
1104766Speter 		if (argc != 1) {
1105766Speter 			error("%s expects one argument", p->symbol);
1106766Speter 			return;
1107766Speter 		}
11083833Speter 		putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY );
1109766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1110766Speter 			, "_UNIT" );
1111766Speter 		ap = stklval(argv[1], NOFLAGS);
1112766Speter 		if (ap == NIL)
1113766Speter 			return;
1114766Speter 		if (ap->class != FILET) {
1115766Speter 			error("Argument to %s must be a file, not %s", p->symbol, nameof(ap));
1116766Speter 			return;
1117766Speter 		}
1118766Speter 		putop( P2CALL , P2INT );
1119766Speter 		putop( P2ASSIGN , P2PTR|P2STRTY );
1120766Speter 		putdot( filename , line );
1121766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1122766Speter 			, op == O_GET ? "_GET" : "_PUT" );
11233833Speter 		putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY );
1124766Speter 		putop( P2CALL , P2INT );
1125766Speter 		putdot( filename , line );
1126766Speter 		return;
1127766Speter 
1128766Speter 	case O_RESET:
1129766Speter 	case O_REWRITE:
1130766Speter 		if (argc == 0 || argc > 2) {
1131766Speter 			error("%s expects one or two arguments", p->symbol);
1132766Speter 			return;
1133766Speter 		}
1134766Speter 		if (opt('s') && argc == 2) {
1135766Speter 			standard();
1136766Speter 			error("Two argument forms of reset and rewrite are non-standard");
1137766Speter 		}
1138766Speter 		putleaf( P2ICON , 0 , 0 , P2INT
1139766Speter 			, op == O_RESET ? "_RESET" : "_REWRITE" );
1140766Speter 		ap = stklval(argv[1], MOD|NOUSE);
1141766Speter 		if (ap == NIL)
1142766Speter 			return;
1143766Speter 		if (ap->class != FILET) {
1144766Speter 			error("First argument to %s must be a file, not %s", p->symbol, nameof(ap));
1145766Speter 			return;
1146766Speter 		}
1147766Speter 		if (argc == 2) {
1148766Speter 			/*
1149766Speter 			 * Optional second argument
1150766Speter 			 * is a string name of a
1151766Speter 			 * UNIX (R) file to be associated.
1152766Speter 			 */
1153766Speter 			al = argv[2];
1154766Speter 			al = stkrval(al[1], NOFLAGS , RREQ );
1155766Speter 			if (al == NIL)
1156766Speter 				return;
1157766Speter 			if (classify(al) != TSTR) {
1158766Speter 				error("Second argument to %s must be a string, not %s", p->symbol, nameof(al));
1159766Speter 				return;
1160766Speter 			}
1161766Speter 			strnglen = width(al);
1162766Speter 		} else {
1163766Speter 			putleaf( P2ICON , 0 , 0 , P2INT , 0 );
1164766Speter 			strnglen = 0;
1165766Speter 		}
1166766Speter 		putop( P2LISTOP , P2INT );
1167766Speter 		putleaf( P2ICON , strnglen , 0 , P2INT , 0 );
1168766Speter 		putop( P2LISTOP , P2INT );
1169766Speter 		putleaf( P2ICON , text(ap) ? 0: width(ap->type) , 0 , P2INT , 0 );
1170766Speter 		putop( P2LISTOP , P2INT );
1171766Speter 		putop( P2CALL , P2INT );
1172766Speter 		putdot( filename , line );
1173766Speter 		return;
1174766Speter 
1175766Speter 	case O_NEW:
1176766Speter 	case O_DISPOSE:
1177766Speter 		if (argc == 0) {
1178766Speter 			error("%s expects at least one argument", p->symbol);
1179766Speter 			return;
1180766Speter 		}
1181*9139Smckusick 		alv = argv[1];
11827967Smckusick 		codeoff();
1183*9139Smckusick 		ap = stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD );
11847967Smckusick 		codeon();
1185766Speter 		if (ap == NIL)
1186766Speter 			return;
1187766Speter 		if (ap->class != PTR) {
1188766Speter 			error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap));
1189766Speter 			return;
1190766Speter 		}
1191766Speter 		ap = ap->type;
1192766Speter 		if (ap == NIL)
1193766Speter 			return;
1194*9139Smckusick 		if (op == O_NEW)
1195*9139Smckusick 			cmd = "_NEW";
1196*9139Smckusick 		else /* op == O_DISPOSE */
11977967Smckusick 			if ((ap->nl_flags & NFILES) != 0)
11987967Smckusick 				cmd = "_DFDISPOSE";
11997967Smckusick 			else
12007967Smckusick 				cmd = "_DISPOSE";
12017967Smckusick 		putleaf( P2ICON, 0, 0, ADDTYPE( P2FTN | P2INT , P2PTR ), cmd);
1202*9139Smckusick 		stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD );
1203766Speter 		argv = argv[2];
1204766Speter 		if (argv != NIL) {
1205766Speter 			if (ap->class != RECORD) {
1206766Speter 				error("Record required when specifying variant tags");
1207766Speter 				return;
1208766Speter 			}
1209766Speter 			for (; argv != NIL; argv = argv[2]) {
1210766Speter 				if (ap->ptr[NL_VARNT] == NIL) {
1211766Speter 					error("Too many tag fields");
1212766Speter 					return;
1213766Speter 				}
1214766Speter 				if (!isconst(argv[1])) {
1215766Speter 					error("Second and successive arguments to %s must be constants", p->symbol);
1216766Speter 					return;
1217766Speter 				}
1218766Speter 				gconst(argv[1]);
1219766Speter 				if (con.ctype == NIL)
1220766Speter 					return;
1221766Speter 				if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) {
1222766Speter 					cerror("Specified tag constant type clashed with variant case selector type");
1223766Speter 					return;
1224766Speter 				}
1225766Speter 				for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain)
1226766Speter 					if (ap->range[0] == con.crval)
1227766Speter 						break;
1228766Speter 				if (ap == NIL) {
1229766Speter 					error("No variant case label value equals specified constant value");
1230766Speter 					return;
1231766Speter 				}
1232766Speter 				ap = ap->ptr[NL_VTOREC];
1233766Speter 			}
1234766Speter 		}
1235766Speter 		putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 );
1236766Speter 		putop( P2LISTOP , P2INT );
1237766Speter 		putop( P2CALL , P2INT );
1238766Speter 		putdot( filename , line );
1239*9139Smckusick 		if (opt('t') && op == O_NEW) {
1240*9139Smckusick 		    putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1241*9139Smckusick 			    , "_blkclr" );
1242*9139Smckusick 		    stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD );
1243*9139Smckusick 		    putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 );
1244*9139Smckusick 		    putop( P2LISTOP , P2INT );
1245*9139Smckusick 		    putop( P2CALL , P2INT );
1246*9139Smckusick 		    putdot( filename , line );
1247*9139Smckusick 		}
1248766Speter 		return;
1249766Speter 
1250766Speter 	case O_DATE:
1251766Speter 	case O_TIME:
1252766Speter 		if (argc != 1) {
1253766Speter 			error("%s expects one argument", p->symbol);
1254766Speter 			return;
1255766Speter 		}
1256766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1257766Speter 			, op == O_DATE ? "_DATE" : "_TIME" );
1258766Speter 		ap = stklval(argv[1], MOD|NOUSE);
1259766Speter 		if (ap == NIL)
1260766Speter 			return;
1261766Speter 		if (classify(ap) != TSTR || width(ap) != 10) {
1262766Speter 			error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap));
1263766Speter 			return;
1264766Speter 		}
1265766Speter 		putop( P2CALL , P2INT );
1266766Speter 		putdot( filename , line );
1267766Speter 		return;
1268766Speter 
1269766Speter 	case O_HALT:
1270766Speter 		if (argc != 0) {
1271766Speter 			error("halt takes no arguments");
1272766Speter 			return;
1273766Speter 		}
1274766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1275766Speter 			, "_HALT" );
1276766Speter 
1277766Speter 		putop( P2UNARY P2CALL , P2INT );
1278766Speter 		putdot( filename , line );
1279766Speter 		noreach = 1;
1280766Speter 		return;
1281766Speter 
1282766Speter 	case O_ARGV:
1283766Speter 		if (argc != 2) {
1284766Speter 			error("argv takes two arguments");
1285766Speter 			return;
1286766Speter 		}
1287766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1288766Speter 			, "_ARGV" );
1289766Speter 		ap = stkrval(argv[1], NIL , RREQ );
1290766Speter 		if (ap == NIL)
1291766Speter 			return;
1292766Speter 		if (isnta(ap, "i")) {
1293766Speter 			error("argv's first argument must be an integer, not %s", nameof(ap));
1294766Speter 			return;
1295766Speter 		}
1296766Speter 		al = argv[2];
1297766Speter 		ap = stklval(al[1], MOD|NOUSE);
1298766Speter 		if (ap == NIL)
1299766Speter 			return;
1300766Speter 		if (classify(ap) != TSTR) {
1301766Speter 			error("argv's second argument must be a string, not %s", nameof(ap));
1302766Speter 			return;
1303766Speter 		}
1304766Speter 		putop( P2LISTOP , P2INT );
1305766Speter 		putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 );
1306766Speter 		putop( P2LISTOP , P2INT );
1307766Speter 		putop( P2CALL , P2INT );
1308766Speter 		putdot( filename , line );
1309766Speter 		return;
1310766Speter 
1311766Speter 	case O_STLIM:
1312766Speter 		if (argc != 1) {
1313766Speter 			error("stlimit requires one argument");
1314766Speter 			return;
1315766Speter 		}
1316766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1317766Speter 			, "_STLIM" );
1318766Speter 		ap = stkrval(argv[1], NIL , RREQ );
1319766Speter 		if (ap == NIL)
1320766Speter 			return;
1321766Speter 		if (isnta(ap, "i")) {
1322766Speter 			error("stlimit's argument must be an integer, not %s", nameof(ap));
1323766Speter 			return;
1324766Speter 		}
1325766Speter 		putop( P2CALL , P2INT );
1326766Speter 		putdot( filename , line );
1327766Speter 		return;
1328766Speter 
1329766Speter 	case O_REMOVE:
1330766Speter 		if (argc != 1) {
1331766Speter 			error("remove expects one argument");
1332766Speter 			return;
1333766Speter 		}
1334766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1335766Speter 			, "_REMOVE" );
1336766Speter 		ap = stkrval(argv[1], NOFLAGS , RREQ );
1337766Speter 		if (ap == NIL)
1338766Speter 			return;
1339766Speter 		if (classify(ap) != TSTR) {
1340766Speter 			error("remove's argument must be a string, not %s", nameof(ap));
1341766Speter 			return;
1342766Speter 		}
1343766Speter 		putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 );
1344766Speter 		putop( P2LISTOP , P2INT );
1345766Speter 		putop( P2CALL , P2INT );
1346766Speter 		putdot( filename , line );
1347766Speter 		return;
1348766Speter 
1349766Speter 	case O_LLIMIT:
1350766Speter 		if (argc != 2) {
1351766Speter 			error("linelimit expects two arguments");
1352766Speter 			return;
1353766Speter 		}
1354766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1355766Speter 			, "_LLIMIT" );
1356766Speter 		ap = stklval(argv[1], NOFLAGS|NOUSE);
1357766Speter 		if (ap == NIL)
1358766Speter 			return;
1359766Speter 		if (!text(ap)) {
1360766Speter 			error("linelimit's first argument must be a text file, not %s", nameof(ap));
1361766Speter 			return;
1362766Speter 		}
1363766Speter 		al = argv[2];
1364766Speter 		ap = stkrval(al[1], NIL , RREQ );
1365766Speter 		if (ap == NIL)
1366766Speter 			return;
1367766Speter 		if (isnta(ap, "i")) {
1368766Speter 			error("linelimit's second argument must be an integer, not %s", nameof(ap));
1369766Speter 			return;
1370766Speter 		}
1371766Speter 		putop( P2LISTOP , P2INT );
1372766Speter 		putop( P2CALL , P2INT );
1373766Speter 		putdot( filename , line );
1374766Speter 		return;
1375766Speter 	case O_PAGE:
1376766Speter 		if (argc != 1) {
1377766Speter 			error("page expects one argument");
1378766Speter 			return;
1379766Speter 		}
13803833Speter 		putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY );
1381766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1382766Speter 			, "_UNIT" );
1383766Speter 		ap = stklval(argv[1], NOFLAGS);
1384766Speter 		if (ap == NIL)
1385766Speter 			return;
1386766Speter 		if (!text(ap)) {
1387766Speter 			error("Argument to page must be a text file, not %s", nameof(ap));
1388766Speter 			return;
1389766Speter 		}
1390766Speter 		putop( P2CALL , P2INT );
1391766Speter 		putop( P2ASSIGN , P2PTR|P2STRTY );
1392766Speter 		putdot( filename , line );
1393766Speter 		if ( opt( 't' ) ) {
1394766Speter 		    putleaf( P2ICON , 0 , 0
1395766Speter 			, ADDTYPE( P2FTN | P2INT , P2PTR )
1396766Speter 			, "_PAGE" );
13973833Speter 		    putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY );
1398766Speter 		} else {
1399766Speter 		    putleaf( P2ICON , 0 , 0
1400766Speter 			, ADDTYPE( P2FTN | P2INT , P2PTR )
1401766Speter 			, "_fputc" );
1402766Speter 		    putleaf( P2ICON , '\f' , 0 , P2CHAR , 0 );
1403766Speter 		    putleaf( P2ICON , 0 , 0
1404766Speter 			, ADDTYPE( P2FTN | P2INT , P2PTR )
1405766Speter 			, "_ACTFILE" );
14063833Speter 		    putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY );
1407766Speter 		    putop( P2CALL , P2INT );
1408766Speter 		    putop( P2LISTOP , P2INT );
1409766Speter 		}
1410766Speter 		putop( P2CALL , P2INT );
1411766Speter 		putdot( filename , line );
1412766Speter 		return;
1413766Speter 
14147928Smckusick 	case O_ASRT:
14157928Smckusick 		if (!opt('t'))
14167928Smckusick 			return;
14177928Smckusick 		if (argc == 0 || argc > 2) {
14187928Smckusick 			error("Assert expects one or two arguments");
14197928Smckusick 			return;
14207928Smckusick 		}
1421*9139Smckusick 		if (argc == 2)
1422*9139Smckusick 			cmd = "_ASRTS";
1423*9139Smckusick 		else
1424*9139Smckusick 			cmd = "_ASRT";
14257928Smckusick 		putleaf( P2ICON , 0 , 0
1426*9139Smckusick 		    , ADDTYPE( P2FTN | P2INT , P2PTR ) , cmd );
14277928Smckusick 		ap = stkrval(argv[1], NIL , RREQ );
14287928Smckusick 		if (ap == NIL)
14297928Smckusick 			return;
14307928Smckusick 		if (isnta(ap, "b"))
14317928Smckusick 			error("Assert expression must be Boolean, not %ss", nameof(ap));
14327928Smckusick 		if (argc == 2) {
14337928Smckusick 			/*
14347928Smckusick 			 * Optional second argument is a string specifying
14357928Smckusick 			 * why the assertion failed.
14367928Smckusick 			 */
14377928Smckusick 			al = argv[2];
14387928Smckusick 			al = stkrval(al[1], NIL , RREQ );
14397928Smckusick 			if (al == NIL)
14407928Smckusick 				return;
14417928Smckusick 			if (classify(al) != TSTR) {
14427928Smckusick 				error("Second argument to assert must be a string, not %s", nameof(al));
14437928Smckusick 				return;
14447928Smckusick 			}
1445*9139Smckusick 			putop( P2LISTOP , P2INT );
14467928Smckusick 		}
14477928Smckusick 		putop( P2CALL , P2INT );
14487928Smckusick 		putdot( filename , line );
14497928Smckusick 		return;
14507928Smckusick 
1451766Speter 	case O_PACK:
1452766Speter 		if (argc != 3) {
1453766Speter 			error("pack expects three arguments");
1454766Speter 			return;
1455766Speter 		}
1456766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1457766Speter 			, "_PACK" );
1458766Speter 		pu = "pack(a,i,z)";
1459766Speter 		pua = (al = argv)[1];
1460766Speter 		pui = (al = al[2])[1];
1461766Speter 		puz = (al = al[2])[1];
1462766Speter 		goto packunp;
1463766Speter 	case O_UNPACK:
1464766Speter 		if (argc != 3) {
1465766Speter 			error("unpack expects three arguments");
1466766Speter 			return;
1467766Speter 		}
1468766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1469766Speter 			, "_UNPACK" );
1470766Speter 		pu = "unpack(z,a,i)";
1471766Speter 		puz = (al = argv)[1];
1472766Speter 		pua = (al = al[2])[1];
1473766Speter 		pui = (al = al[2])[1];
1474766Speter packunp:
1475766Speter 		ap = stkrval((int *) pui, NLNIL , RREQ );
1476766Speter 		if (ap == NIL)
1477766Speter 			return;
1478766Speter 		ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE);
1479766Speter 		if (ap == NIL)
1480766Speter 			return;
1481766Speter 		if (ap->class != ARRAY) {
1482766Speter 			error("%s requires a to be an unpacked array, not %s", pu, nameof(ap));
1483766Speter 			return;
1484766Speter 		}
1485766Speter 		putop( P2LISTOP , P2INT );
1486766Speter 		al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE);
1487766Speter 		if (al->class != ARRAY) {
1488766Speter 			error("%s requires z to be a packed array, not %s", pu, nameof(ap));
1489766Speter 			return;
1490766Speter 		}
1491766Speter 		if (al->type == NIL || ap->type == NIL)
1492766Speter 			return;
1493766Speter 		if (al->type != ap->type) {
1494766Speter 			error("%s requires a and z to be arrays of the same type", pu, nameof(ap));
1495766Speter 			return;
1496766Speter 		}
1497766Speter 		putop( P2LISTOP , P2INT );
1498766Speter 		k = width(al);
1499766Speter 		itemwidth = width(ap->type);
1500766Speter 		ap = ap->chain;
1501766Speter 		al = al->chain;
1502766Speter 		if (ap->chain != NIL || al->chain != NIL) {
1503766Speter 			error("%s requires a and z to be single dimension arrays", pu);
1504766Speter 			return;
1505766Speter 		}
1506766Speter 		if (ap == NIL || al == NIL)
1507766Speter 			return;
1508766Speter 		/*
1509766Speter 		 * al is the range for z i.e. u..v
1510766Speter 		 * ap is the range for a i.e. m..n
1511766Speter 		 * i will be n-m+1
1512766Speter 		 * j will be v-u+1
1513766Speter 		 */
1514766Speter 		i = ap->range[1] - ap->range[0] + 1;
1515766Speter 		j = al->range[1] - al->range[0] + 1;
1516766Speter 		if (i < j) {
1517766Speter 			error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i);
1518766Speter 			return;
1519766Speter 		}
1520766Speter 		/*
1521766Speter 		 * get n-m-(v-u) and m for the interpreter
1522766Speter 		 */
1523766Speter 		i -= j;
1524766Speter 		j = ap->range[0];
1525766Speter 		putleaf( P2ICON , itemwidth , 0 , P2INT , 0 );
1526766Speter 		putop( P2LISTOP , P2INT );
1527766Speter 		putleaf( P2ICON , j , 0 , P2INT , 0 );
1528766Speter 		putop( P2LISTOP , P2INT );
1529766Speter 		putleaf( P2ICON , i , 0 , P2INT , 0 );
1530766Speter 		putop( P2LISTOP , P2INT );
1531766Speter 		putleaf( P2ICON , k , 0 , P2INT , 0 );
1532766Speter 		putop( P2LISTOP , P2INT );
1533766Speter 		putop( P2CALL , P2INT );
1534766Speter 		putdot( filename , line );
1535766Speter 		return;
1536766Speter 	case 0:
15377928Smckusick 		error("%s is an unimplemented extension", p->symbol);
1538766Speter 		return;
1539766Speter 
1540766Speter 	default:
1541766Speter 		panic("proc case");
1542766Speter 	}
1543766Speter }
1544766Speter #endif PC
1545