xref: /csrg-svn/usr.bin/pascal/src/pcproc.c (revision 3180)
1766Speter /* Copyright (c) 1979 Regents of the University of California */
2766Speter 
3*3180Smckusic static	char sccsid[] = "@(#)pcproc.c 1.4 03/10/81";
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;
50766Speter 	char fmt, format[20], *strptr;
51766Speter 	int prec, field, strnglen, fmtlen, fmtstart, pu;
52766Speter 	int *pua, *pui, *puz;
53766Speter 	int i, j, k;
54766Speter 	int itemwidth;
55766Speter 	char	*readname;
56766Speter 	long	tempoff;
57766Speter 	long	readtype;
58766Speter 
59766Speter #define	CONPREC 4
60766Speter #define	VARPREC 8
61766Speter #define	CONWIDTH 1
62766Speter #define	VARWIDTH 2
63766Speter #define SKIP 16
64766Speter 
65766Speter 	/*
66766Speter 	 * Verify that the name is
67766Speter 	 * defined and is that of a
68766Speter 	 * procedure.
69766Speter 	 */
70766Speter 	p = lookup(r[2]);
71766Speter 	if (p == NIL) {
72766Speter 		rvlist(r[3]);
73766Speter 		return;
74766Speter 	}
751197Speter 	if (p->class != PROC && p->class != FPROC) {
76766Speter 		error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]);
77766Speter 		rvlist(r[3]);
78766Speter 		return;
79766Speter 	}
80766Speter 	argv = r[3];
81766Speter 
82766Speter 	/*
83766Speter 	 * Call handles user defined
84766Speter 	 * procedures and functions.
85766Speter 	 */
86766Speter 	if (bn != 0) {
87766Speter 		call(p, argv, PROC, bn);
88766Speter 		return;
89766Speter 	}
90766Speter 
91766Speter 	/*
92766Speter 	 * Call to built-in procedure.
93766Speter 	 * Count the arguments.
94766Speter 	 */
95766Speter 	argc = 0;
96766Speter 	for (al = argv; al != NIL; al = al[2])
97766Speter 		argc++;
98766Speter 
99766Speter 	/*
100766Speter 	 * Switch on the operator
101766Speter 	 * associated with the built-in
102766Speter 	 * procedure in the namelist
103766Speter 	 */
104766Speter 	op = p->value[0] &~ NSTAND;
105766Speter 	if (opt('s') && (p->value[0] & NSTAND)) {
106766Speter 		standard();
107766Speter 		error("%s is a nonstandard procedure", p->symbol);
108766Speter 	}
109766Speter 	switch (op) {
110766Speter 
111766Speter 	case O_ABORT:
112766Speter 		if (argc != 0)
113766Speter 			error("null takes no arguments");
114766Speter 		return;
115766Speter 
116766Speter 	case O_FLUSH:
117766Speter 		if (argc == 0) {
118766Speter 			putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" );
119766Speter 			putop( P2UNARY P2CALL , P2INT );
120766Speter 			putdot( filename , line );
121766Speter 			return;
122766Speter 		}
123766Speter 		if (argc != 1) {
124766Speter 			error("flush takes at most one argument");
125766Speter 			return;
126766Speter 		}
127766Speter 		putleaf( P2ICON , 0 , 0
128766Speter 			, ADDTYPE( P2FTN | P2INT , P2PTR )
129766Speter 			, "_FLUSH" );
130766Speter 		ap = stklval(argv[1], NOFLAGS);
131766Speter 		if (ap == NIL)
132766Speter 			return;
133766Speter 		if (ap->class != FILET) {
134766Speter 			error("flush's argument must be a file, not %s", nameof(ap));
135766Speter 			return;
136766Speter 		}
137766Speter 		putop( P2CALL , P2INT );
138766Speter 		putdot( filename , line );
139766Speter 		return;
140766Speter 
141766Speter 	case O_MESSAGE:
142766Speter 	case O_WRITEF:
143766Speter 	case O_WRITLN:
144766Speter 		/*
145766Speter 		 * Set up default file "output"'s type
146766Speter 		 */
147766Speter 		file = NIL;
148766Speter 		filetype = nl+T1CHAR;
149766Speter 		/*
150766Speter 		 * Determine the file implied
151766Speter 		 * for the write and generate
152766Speter 		 * code to make it the active file.
153766Speter 		 */
154766Speter 		if (op == O_MESSAGE) {
155766Speter 			/*
156766Speter 			 * For message, all that matters
157766Speter 			 * is that the filetype is
158766Speter 			 * a character file.
159766Speter 			 * Thus "output" will suit us fine.
160766Speter 			 */
161766Speter 			putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" );
162766Speter 			putop( P2UNARY P2CALL , P2INT );
163766Speter 			putdot( filename , line );
164766Speter 			putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY );
165766Speter 			putLV( "__err" , 0 , 0 , P2PTR|P2STRTY );
166766Speter 			putop( P2ASSIGN , P2PTR|P2STRTY );
167766Speter 			putdot( filename , line );
168766Speter 		} else if (argv != NIL && (al = argv[1])[0] != T_WEXP) {
169766Speter 			/*
170766Speter 			 * If there is a first argument which has
171766Speter 			 * no write widths, then it is potentially
172766Speter 			 * a file name.
173766Speter 			 */
174766Speter 			codeoff();
175766Speter 			ap = stkrval(argv[1], NIL , RREQ );
176766Speter 			codeon();
177766Speter 			if (ap == NIL)
178766Speter 				argv = argv[2];
179766Speter 			if (ap != NIL && ap->class == FILET) {
180766Speter 				/*
181766Speter 				 * Got "write(f, ...", make
182766Speter 				 * f the active file, and save
183766Speter 				 * it and its type for use in
184766Speter 				 * processing the rest of the
185766Speter 				 * arguments to write.
186766Speter 				 */
187766Speter 				putRV( 0 , cbn , CURFILEOFFSET
188766Speter 					, P2PTR|P2STRTY );
189766Speter 				putleaf( P2ICON , 0 , 0
190766Speter 				    , ADDTYPE( P2FTN | P2INT , P2PTR )
191766Speter 				    , "_UNIT" );
192766Speter 				file = argv[1];
193766Speter 				filetype = ap->type;
194766Speter 				stklval(argv[1], NOFLAGS);
195766Speter 				putop( P2CALL , P2INT );
196766Speter 				putop( P2ASSIGN , P2PTR|P2STRTY );
197766Speter 				putdot( filename , line );
198766Speter 				/*
199766Speter 				 * Skip over the first argument
200766Speter 				 */
201766Speter 				argv = argv[2];
202766Speter 				argc--;
203766Speter 			} else {
204766Speter 				/*
205766Speter 				 * Set up for writing on
206766Speter 				 * standard output.
207766Speter 				 */
208766Speter 				putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY );
209766Speter 				putLV( "_output" , 0 , 0 , P2PTR|P2STRTY );
210766Speter 				putop( P2ASSIGN , P2PTR|P2STRTY );
211766Speter 				putdot( filename , line );
212766Speter 			}
213766Speter 		} else {
214766Speter 			putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY );
215766Speter 			putLV( "_output" , 0 , 0 , P2PTR|P2STRTY );
216766Speter 			putop( P2ASSIGN , P2PTR|P2STRTY );
217766Speter 			putdot( filename , line );
218766Speter 		}
219766Speter 		/*
220766Speter 		 * Loop and process each
221766Speter 		 * of the arguments.
222766Speter 		 */
223766Speter 		for (; argv != NIL; argv = argv[2]) {
224766Speter 			/*
225766Speter 			 * fmtspec indicates the type (CONstant or VARiable)
226766Speter 			 *	and number (none, WIDTH, and/or PRECision)
227766Speter 			 *	of the fields in the printf format for this
228766Speter 			 *	output variable.
229766Speter 			 * stkcnt is the number of longs pushed on the stack
230766Speter 			 * fmt is the format output indicator (D, E, F, O, X, S)
231766Speter 			 * fmtstart = 0 for leading blank; = 1 for no blank
232766Speter 			 */
233766Speter 			fmtspec = NIL;
234766Speter 			stkcnt = 0;
235766Speter 			fmt = 'D';
236766Speter 			fmtstart = 1;
237766Speter 			al = argv[1];
238766Speter 			if (al == NIL)
239766Speter 				continue;
240766Speter 			if (al[0] == T_WEXP)
241766Speter 				alv = al[1];
242766Speter 			else
243766Speter 				alv = al;
244766Speter 			if (alv == NIL)
245766Speter 				continue;
246766Speter 			codeoff();
247766Speter 			ap = stkrval(alv, NIL , RREQ );
248766Speter 			codeon();
249766Speter 			if (ap == NIL)
250766Speter 				continue;
251766Speter 			typ = classify(ap);
252766Speter 			if (al[0] == T_WEXP) {
253766Speter 				/*
254766Speter 				 * Handle width expressions.
255766Speter 				 * The basic game here is that width
256766Speter 				 * expressions get evaluated. If they
257766Speter 				 * are constant, the value is placed
258766Speter 				 * directly in the format string.
259766Speter 				 * Otherwise the value is pushed onto
260766Speter 				 * the stack and an indirection is
261766Speter 				 * put into the format string.
262766Speter 				 */
263766Speter 				if (al[3] == OCT)
264766Speter 					fmt = 'O';
265766Speter 				else if (al[3] == HEX)
266766Speter 					fmt = 'X';
267766Speter 				else if (al[3] != NIL) {
268766Speter 					/*
269766Speter 					 * Evaluate second format spec
270766Speter 					 */
271766Speter 					if ( constval(al[3])
272766Speter 					    && isa( con.ctype , "i" ) ) {
273766Speter 						fmtspec += CONPREC;
274766Speter 						prec = con.crval;
275766Speter 					} else {
276766Speter 						fmtspec += VARPREC;
277766Speter 					}
278766Speter 					fmt = 'f';
279766Speter 					switch ( typ ) {
280766Speter 					case TINT:
281766Speter 						if ( opt( 's' ) ) {
282766Speter 						    standard();
283766Speter 						    error("Writing %ss with two write widths is non-standard", clnames[typ]);
284766Speter 						}
285766Speter 						/* and fall through */
286766Speter 					case TDOUBLE:
287766Speter 						break;
288766Speter 					default:
289766Speter 						error("Cannot write %ss with two write widths", clnames[typ]);
290766Speter 						continue;
291766Speter 					}
292766Speter 				}
293766Speter 				/*
294766Speter 				 * Evaluate first format spec
295766Speter 				 */
296766Speter 				if (al[2] != NIL) {
297766Speter 					if ( constval(al[2])
298766Speter 					    && isa( con.ctype , "i" ) ) {
299766Speter 						fmtspec += CONWIDTH;
300766Speter 						field = con.crval;
301766Speter 					} else {
302766Speter 						fmtspec += VARWIDTH;
303766Speter 					}
304766Speter 				}
305766Speter 				if ((fmtspec & CONPREC) && prec < 0 ||
306766Speter 				    (fmtspec & CONWIDTH) && field < 0) {
307766Speter 					error("Negative widths are not allowed");
308766Speter 					continue;
309766Speter 				}
310*3180Smckusic 				if ( opt('s') &&
311*3180Smckusic 				    ((fmtspec & CONPREC) && prec == 0 ||
312*3180Smckusic 				    (fmtspec & CONWIDTH) && field == 0)) {
313*3180Smckusic 					standard();
314*3180Smckusic 					error("Zero widths are non-standard");
315*3180Smckusic 				}
316766Speter 			}
317766Speter 			if (filetype != nl+T1CHAR) {
318766Speter 				if (fmt == 'O' || fmt == 'X') {
319766Speter 					error("Oct/hex allowed only on text files");
320766Speter 					continue;
321766Speter 				}
322766Speter 				if (fmtspec) {
323766Speter 					error("Write widths allowed only on text files");
324766Speter 					continue;
325766Speter 				}
326766Speter 				/*
327766Speter 				 * Generalized write, i.e.
328766Speter 				 * to a non-textfile.
329766Speter 				 */
330766Speter 				putleaf( P2ICON , 0 , 0
331766Speter 				    , ADDTYPE(
332766Speter 					ADDTYPE(
333766Speter 					    ADDTYPE( p2type( filetype )
334766Speter 						    , P2PTR )
335766Speter 					    , P2FTN )
336766Speter 					, P2PTR )
337766Speter 				    , "_FNIL" );
338766Speter 				stklval(file, NOFLAGS);
339766Speter 				putop( P2CALL
340766Speter 				    , ADDTYPE( p2type( filetype ) , P2PTR ) );
341766Speter 				putop( P2UNARY P2MUL , p2type( filetype ) );
342766Speter 				/*
343766Speter 				 * file^ := ...
344766Speter 				 */
345766Speter 				switch ( classify( filetype ) ) {
346766Speter 				    case TBOOL:
347766Speter 				    case TCHAR:
348766Speter 				    case TINT:
349766Speter 				    case TSCAL:
350766Speter 					precheck( filetype , "_RANG4"  , "_RSGN4" );
351766Speter 					    /* and fall through */
352766Speter 				    case TDOUBLE:
353766Speter 				    case TPTR:
354766Speter 					ap = rvalue( argv[1] , filetype , RREQ );
355766Speter 					break;
356766Speter 				    default:
357766Speter 					ap = rvalue( argv[1] , filetype , LREQ );
358766Speter 					break;
359766Speter 				}
360766Speter 				if (ap == NIL)
361766Speter 					continue;
362766Speter 				if (incompat(ap, filetype, argv[1])) {
363766Speter 					cerror("Type mismatch in write to non-text file");
364766Speter 					continue;
365766Speter 				}
366766Speter 				switch ( classify( filetype ) ) {
367766Speter 				    case TBOOL:
368766Speter 				    case TCHAR:
369766Speter 				    case TINT:
370766Speter 				    case TSCAL:
371766Speter 					    postcheck( filetype );
372766Speter 						/* and fall through */
373766Speter 				    case TDOUBLE:
374766Speter 				    case TPTR:
375766Speter 					    putop( P2ASSIGN , p2type( filetype ) );
376766Speter 					    putdot( filename , line );
377766Speter 					    break;
378766Speter 				    default:
379766Speter 					    putstrop( P2STASG
380766Speter 							, p2type( filetype )
381766Speter 							, lwidth( filetype )
382766Speter 							, align( filetype ) );
383766Speter 					    putdot( filename , line );
384766Speter 					    break;
385766Speter 				}
386766Speter 				/*
387766Speter 				 * put(file)
388766Speter 				 */
389766Speter 				putleaf( P2ICON , 0 , 0
390766Speter 				    , ADDTYPE( P2FTN | P2INT , P2PTR )
391766Speter 				    , "_PUT" );
392766Speter 				putRV( 0 , cbn , CURFILEOFFSET
393766Speter 					, P2PTR|P2STRTY );
394766Speter 				putop( P2CALL , P2INT );
395766Speter 				putdot( filename , line );
396766Speter 				continue;
397766Speter 			}
398766Speter 			/*
399766Speter 			 * Write to a textfile
400766Speter 			 *
401766Speter 			 * Evaluate the expression
402766Speter 			 * to be written.
403766Speter 			 */
404766Speter 			if (fmt == 'O' || fmt == 'X') {
405766Speter 				if (opt('s')) {
406766Speter 					standard();
407766Speter 					error("Oct and hex are non-standard");
408766Speter 				}
409766Speter 				if (typ == TSTR || typ == TDOUBLE) {
410766Speter 					error("Can't write %ss with oct/hex", clnames[typ]);
411766Speter 					continue;
412766Speter 				}
413766Speter 				if (typ == TCHAR || typ == TBOOL)
414766Speter 					typ = TINT;
415766Speter 			}
416766Speter 			/*
417766Speter 			 * If there is no format specified by the programmer,
418766Speter 			 * implement the default.
419766Speter 			 */
420766Speter 			switch (typ) {
421766Speter 			case TINT:
422766Speter 				if (fmt == 'f') {
423766Speter 					typ = TDOUBLE;
424766Speter 					goto tdouble;
425766Speter 				}
426766Speter 				if (fmtspec == NIL) {
427766Speter 					if (fmt == 'D')
428766Speter 						field = 10;
429766Speter 					else if (fmt == 'X')
430766Speter 						field = 8;
431766Speter 					else if (fmt == 'O')
432766Speter 						field = 11;
433766Speter 					else
434766Speter 						panic("fmt1");
435766Speter 					fmtspec = CONWIDTH;
436766Speter 				}
437766Speter 				break;
438766Speter 			case TCHAR:
439766Speter 			     tchar:
440766Speter 				fmt = 'c';
441766Speter 				break;
442766Speter 			case TSCAL:
4431629Speter 				warning();
444766Speter 				if (opt('s')) {
445766Speter 					standard();
446766Speter 				}
4471629Speter 				error("Writing scalars to text files is non-standard");
448766Speter 			case TBOOL:
449766Speter 				fmt = 's';
450766Speter 				break;
451766Speter 			case TDOUBLE:
452766Speter 			     tdouble:
453766Speter 				switch (fmtspec) {
454766Speter 				case NIL:
455766Speter 					field = 21;
456766Speter 					prec = 14;
457766Speter 					fmt = 'E';
458766Speter 					fmtspec = CONWIDTH + CONPREC;
459766Speter 					break;
460766Speter 				case CONWIDTH:
461766Speter 					if (--field < 1)
462766Speter 						field = 1;
463766Speter 					prec = field - 7;
464766Speter 					if (prec < 1)
465766Speter 						prec = 1;
466766Speter 					fmtspec += CONPREC;
467766Speter 					fmt = 'E';
468766Speter 					break;
469766Speter 				case VARWIDTH:
470766Speter 					fmtspec += VARPREC;
471766Speter 					fmt = 'E';
472766Speter 					break;
473766Speter 				case CONWIDTH + CONPREC:
474766Speter 				case CONWIDTH + VARPREC:
475766Speter 					if (--field < 1)
476766Speter 						field = 1;
477766Speter 				}
478766Speter 				format[0] = ' ';
479766Speter 				fmtstart = 0;
480766Speter 				break;
481766Speter 			case TSTR:
482766Speter 				constval( alv );
483766Speter 				switch ( classify( con.ctype ) ) {
484766Speter 				    case TCHAR:
485766Speter 					typ = TCHAR;
486766Speter 					goto tchar;
487766Speter 				    case TSTR:
488766Speter 					strptr = con.cpval;
489766Speter 					for (strnglen = 0;  *strptr++;  strnglen++) /* void */;
490766Speter 					strptr = con.cpval;
491766Speter 					break;
492766Speter 				    default:
493766Speter 					strnglen = width(ap);
494766Speter 					break;
495766Speter 				}
496766Speter 				fmt = 's';
497766Speter 				strfmt = fmtspec;
498766Speter 				if (fmtspec == NIL) {
499766Speter 					fmtspec = SKIP;
500766Speter 					break;
501766Speter 				}
502766Speter 				if (fmtspec & CONWIDTH) {
503766Speter 					if (field <= strnglen)
504766Speter 						fmtspec = SKIP;
505766Speter 					else
506766Speter 						field -= strnglen;
507766Speter 				}
508766Speter 				break;
509766Speter 			default:
510766Speter 				error("Can't write %ss to a text file", clnames[typ]);
511766Speter 				continue;
512766Speter 			}
513766Speter 			/*
514766Speter 			 * Generate the format string
515766Speter 			 */
516766Speter 			switch (fmtspec) {
517766Speter 			default:
518766Speter 				panic("fmt2");
519766Speter 			case NIL:
520766Speter 				if (fmt == 'c') {
521766Speter 					if ( opt( 't' ) ) {
522766Speter 					    putleaf( P2ICON , 0 , 0
523766Speter 						, ADDTYPE( P2FTN|P2INT , P2PTR )
524766Speter 						, "_WRITEC" );
525766Speter 					    putRV( 0 , cbn , CURFILEOFFSET
526766Speter 						    , P2PTR|P2STRTY );
527766Speter 					    stkrval( alv , NIL , RREQ );
528766Speter 					    putop( P2LISTOP , P2INT );
529766Speter 					} else {
530766Speter 					    putleaf( P2ICON , 0 , 0
531766Speter 						, ADDTYPE( P2FTN|P2INT , P2PTR )
532766Speter 						, "_fputc" );
533766Speter 					    stkrval( alv , NIL , RREQ );
534766Speter 					}
535766Speter 					putleaf( P2ICON , 0 , 0
536766Speter 					    , ADDTYPE( P2FTN | P2INT , P2PTR )
537766Speter 					    , "_ACTFILE" );
538766Speter 					putRV( 0, cbn , CURFILEOFFSET
539766Speter 						, P2PTR|P2STRTY );
540766Speter 					putop( P2CALL , P2INT );
541766Speter 					putop( P2LISTOP , P2INT );
542766Speter 					putop( P2CALL , P2INT );
543766Speter 					putdot( filename , line );
544766Speter 				} else  {
545766Speter 					sprintf(&format[1], "%%%c", fmt);
546766Speter 					goto fmtgen;
547766Speter 				}
548766Speter 			case SKIP:
549766Speter 				break;
550766Speter 			case CONWIDTH:
551766Speter 				sprintf(&format[1], "%%%1D%c", field, fmt);
552766Speter 				goto fmtgen;
553766Speter 			case VARWIDTH:
554766Speter 				sprintf(&format[1], "%%*%c", fmt);
555766Speter 				goto fmtgen;
556766Speter 			case CONWIDTH + CONPREC:
557766Speter 				sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt);
558766Speter 				goto fmtgen;
559766Speter 			case CONWIDTH + VARPREC:
560766Speter 				sprintf(&format[1], "%%%1D.*%c", field, fmt);
561766Speter 				goto fmtgen;
562766Speter 			case VARWIDTH + CONPREC:
563766Speter 				sprintf(&format[1], "%%*.%1D%c", prec, fmt);
564766Speter 				goto fmtgen;
565766Speter 			case VARWIDTH + VARPREC:
566766Speter 				sprintf(&format[1], "%%*.*%c", fmt);
567766Speter 			fmtgen:
568766Speter 				if ( opt( 't' ) ) {
569766Speter 				    putleaf( P2ICON , 0 , 0
570766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
571766Speter 					, "_WRITEF" );
572766Speter 				    putRV( 0 , cbn , CURFILEOFFSET
573766Speter 					    , P2PTR|P2STRTY );
574766Speter 				    putleaf( P2ICON , 0 , 0
575766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
576766Speter 					, "_ACTFILE" );
577766Speter 				    putRV( 0 , cbn , CURFILEOFFSET
578766Speter 					    , P2PTR|P2STRTY );
579766Speter 				    putop( P2CALL , P2INT );
580766Speter 				    putop( P2LISTOP , P2INT );
581766Speter 				} else {
582766Speter 				    putleaf( P2ICON , 0 , 0
583766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
584766Speter 					, "_fprintf" );
585766Speter 				    putleaf( P2ICON , 0 , 0
586766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
587766Speter 					, "_ACTFILE" );
588766Speter 				    putRV( 0 , cbn , CURFILEOFFSET
589766Speter 					    , P2PTR|P2STRTY );
590766Speter 				    putop( P2CALL , P2INT );
591766Speter 				}
592766Speter 				putCONG( &format[ fmtstart ]
593766Speter 					, strlen( &format[ fmtstart ] )
594766Speter 					, LREQ );
595766Speter 				putop( P2LISTOP , P2INT );
596766Speter 				if ( fmtspec & VARWIDTH ) {
597766Speter 					/*
598766Speter 					 * either
599766Speter 					 *	,(temp=width,MAX(temp,...)),
600766Speter 					 * or
601766Speter 					 *	, MAX( width , ... ) ,
602766Speter 					 */
603766Speter 				    if ( ( typ == TDOUBLE && al[3] == NIL )
604766Speter 					|| typ == TSTR ) {
605766Speter 					sizes[ cbn ].om_off -= sizeof( int );
606766Speter 					tempoff = sizes[ cbn ].om_off;
607766Speter 					putlbracket( ftnno , -tempoff );
608766Speter 					if ( tempoff < sizes[ cbn ].om_max ) {
609766Speter 					    sizes[ cbn ].om_max = tempoff;
610766Speter 					}
611766Speter 					putRV( 0 , cbn , tempoff , P2INT );
612766Speter 					ap = stkrval( al[2] , NIL , RREQ );
613766Speter 					putop( P2ASSIGN , P2INT );
614766Speter 					putleaf( P2ICON , 0 , 0
615766Speter 					    , ADDTYPE( P2FTN | P2INT , P2PTR )
616766Speter 					    , "_MAX" );
617766Speter 					putRV( 0 , cbn , tempoff , P2INT );
618766Speter 				    } else {
619766Speter 					if (opt('t')
620766Speter 					    || typ == TSTR || typ == TDOUBLE) {
621766Speter 					    putleaf( P2ICON , 0 , 0
622766Speter 						,ADDTYPE( P2FTN | P2INT, P2PTR )
623766Speter 						,"_MAX" );
624766Speter 					}
625766Speter 					ap = stkrval( al[2] , NIL , RREQ );
626766Speter 				    }
627766Speter 				    if (ap == NIL)
628766Speter 					    continue;
629766Speter 				    if (isnta(ap,"i")) {
630766Speter 					    error("First write width must be integer, not %s", nameof(ap));
631766Speter 					    continue;
632766Speter 				    }
633766Speter 				    switch ( typ ) {
634766Speter 				    case TDOUBLE:
635766Speter 					putleaf( P2ICON , 1 , 0 , P2INT , 0 );
636766Speter 					putop( P2LISTOP , P2INT );
637766Speter 					putleaf( P2ICON , 1 , 0 , P2INT , 0 );
638766Speter 					putop( P2LISTOP , P2INT );
639766Speter 					putop( P2CALL , P2INT );
640766Speter 					if ( al[3] == NIL ) {
641766Speter 						/*
642766Speter 						 * finish up the comma op
643766Speter 						 */
644766Speter 					    putop( P2COMOP , P2INT );
645766Speter 					    fmtspec &= ~VARPREC;
646766Speter 					    putop( P2LISTOP , P2INT );
647766Speter 					    putleaf( P2ICON , 0 , 0
648766Speter 						, ADDTYPE( P2FTN | P2INT , P2PTR )
649766Speter 						, "_MAX" );
650766Speter 					    putRV( 0 , cbn , tempoff , P2INT );
651766Speter 					    sizes[ cbn ].om_off += sizeof( int );
652766Speter 					    putleaf( P2ICON , 8 , 0 , P2INT , 0 );
653766Speter 					    putop( P2LISTOP , P2INT );
654766Speter 					    putleaf( P2ICON , 1 , 0 , P2INT , 0 );
655766Speter 					    putop( P2LISTOP , P2INT );
656766Speter 					    putop( P2CALL , P2INT );
657766Speter 					}
658766Speter 					putop( P2LISTOP , P2INT );
659766Speter 					break;
660766Speter 				    case TSTR:
661766Speter 					putleaf( P2ICON , strnglen , 0 , P2INT , 0 );
662766Speter 					putop( P2LISTOP , P2INT );
663766Speter 					putleaf( P2ICON , 0 , 0 , P2INT , 0 );
664766Speter 					putop( P2LISTOP , P2INT );
665766Speter 					putop( P2CALL , P2INT );
666766Speter 					putop( P2COMOP , P2INT );
667766Speter 					putop( P2LISTOP , P2INT );
668766Speter 					break;
669766Speter 				    default:
670766Speter 					if (opt('t')) {
671766Speter 					    putleaf( P2ICON , 0 , 0 , P2INT , 0 );
672766Speter 					    putop( P2LISTOP , P2INT );
673766Speter 					    putleaf( P2ICON , 0 , 0 , P2INT , 0 );
674766Speter 					    putop( P2LISTOP , P2INT );
675766Speter 					    putop( P2CALL , P2INT );
676766Speter 					}
677766Speter 					putop( P2LISTOP , P2INT );
678766Speter 					break;
679766Speter 				    }
680766Speter 				}
681766Speter 				/*
682766Speter 				 * If there is a variable precision,
683766Speter 				 * evaluate it
684766Speter 				 */
685766Speter 				if (fmtspec & VARPREC) {
686766Speter 					if (opt('t')) {
687766Speter 					putleaf( P2ICON , 0 , 0
688766Speter 					    , ADDTYPE( P2FTN | P2INT , P2PTR )
689766Speter 					    , "_MAX" );
690766Speter 					}
691766Speter 					ap = stkrval( al[3] , NIL , RREQ );
692766Speter 					if (ap == NIL)
693766Speter 						continue;
694766Speter 					if (isnta(ap,"i")) {
695766Speter 						error("Second write width must be integer, not %s", nameof(ap));
696766Speter 						continue;
697766Speter 					}
698766Speter 					if (opt('t')) {
699766Speter 					    putleaf( P2ICON , 0 , 0 , P2INT , 0 );
700766Speter 					    putop( P2LISTOP , P2INT );
701766Speter 					    putleaf( P2ICON , 0 , 0 , P2INT , 0 );
702766Speter 					    putop( P2LISTOP , P2INT );
703766Speter 					    putop( P2CALL , P2INT );
704766Speter 					}
705766Speter 				 	putop( P2LISTOP , P2INT );
706766Speter 				}
707766Speter 				/*
708766Speter 				 * evaluate the thing we want printed.
709766Speter 				 */
710766Speter 				switch ( typ ) {
711766Speter 				case TCHAR:
712766Speter 				case TINT:
713766Speter 				    stkrval( alv , NIL , RREQ );
714766Speter 				    putop( P2LISTOP , P2INT );
715766Speter 				    break;
716766Speter 				case TDOUBLE:
717766Speter 				    ap = stkrval( alv , NIL , RREQ );
718766Speter 				    if ( isnta( ap , "d" ) ) {
719766Speter 					putop( P2SCONV , P2DOUBLE );
720766Speter 				    }
721766Speter 				    putop( P2LISTOP , P2INT );
722766Speter 				    break;
723766Speter 				case TSCAL:
724766Speter 				case TBOOL:
725766Speter 				    putleaf( P2ICON , 0 , 0
726766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
727766Speter 					, "_NAM" );
728766Speter 				    ap = stkrval( alv , NIL , RREQ );
729766Speter 				    sprintf( format , PREFIXFORMAT , LABELPREFIX
730766Speter 					    , listnames( ap ) );
731766Speter 				    putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR
732766Speter 					    , format );
733766Speter 				    putop( P2LISTOP , P2INT );
734766Speter 				    putop( P2CALL , P2INT );
735766Speter 				    putop( P2LISTOP , P2INT );
736766Speter 				    break;
737766Speter 				case TSTR:
738766Speter 				    putCONG( "" , 0 , LREQ );
739766Speter 				    putop( P2LISTOP , P2INT );
740766Speter 				    break;
741766Speter 				}
742766Speter 				putop( P2CALL , P2INT );
743766Speter 				putdot( filename , line );
744766Speter 			}
745766Speter 			/*
746766Speter 			 * Write the string after its blank padding
747766Speter 			 */
748766Speter 			if (typ == TSTR ) {
749766Speter 				if ( opt( 't' ) ) {
750766Speter 				    putleaf( P2ICON , 0 , 0
751766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
752766Speter 					, "_WRITES" );
753766Speter 				    putRV( 0 , cbn , CURFILEOFFSET
754766Speter 					    , P2PTR|P2STRTY );
755766Speter 				    ap = stkrval(alv, NIL , RREQ );
756766Speter 				    putop( P2LISTOP , P2INT );
757766Speter 				} else {
758766Speter 				    putleaf( P2ICON , 0 , 0
759766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
760766Speter 					, "_fwrite" );
761766Speter 				    ap = stkrval(alv, NIL , RREQ );
762766Speter 				}
763766Speter 				if (strfmt & VARWIDTH) {
764766Speter 					    /*
765766Speter 					     *	min, inline expanded as
766766Speter 					     *	temp < len ? temp : len
767766Speter 					     */
768766Speter 					putRV( 0 , cbn , tempoff , P2INT );
769766Speter 					putleaf( P2ICON , strnglen , 0 , P2INT , 0 );
770766Speter 					putop( P2LT , P2INT );
771766Speter 					putRV( 0 , cbn , tempoff , P2INT );
772766Speter 					putleaf( P2ICON , strnglen , 0 , P2INT , 0 );
773766Speter 					putop( P2COLON , P2INT );
774766Speter 					putop( P2QUEST , P2INT );
775766Speter 				} else {
776766Speter 					if (   ( fmtspec & SKIP )
777766Speter 					    && ( strfmt & CONWIDTH ) ) {
778766Speter 						strnglen = field;
779766Speter 					}
780766Speter 					putleaf( P2ICON , strnglen , 0 , P2INT , 0 );
781766Speter 				}
782766Speter 				putop( P2LISTOP , P2INT );
783766Speter 				putleaf( P2ICON , 1 , 0 , P2INT , 0 );
784766Speter 				putop( P2LISTOP , P2INT );
785766Speter 				putleaf( P2ICON , 0 , 0
786766Speter 				    , ADDTYPE( P2FTN | P2INT , P2PTR )
787766Speter 				    , "_ACTFILE" );
788766Speter 				putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY );
789766Speter 				putop( P2CALL , P2INT );
790766Speter 				putop( P2LISTOP , P2INT );
791766Speter 				putop( P2CALL , P2INT );
792766Speter 				putdot( filename , line );
793766Speter 			}
794766Speter 		}
795766Speter 		/*
796766Speter 		 * Done with arguments.
797766Speter 		 * Handle writeln and
798766Speter 		 * insufficent number of args.
799766Speter 		 */
800766Speter 		switch (p->value[0] &~ NSTAND) {
801766Speter 			case O_WRITEF:
802766Speter 				if (argc == 0)
803766Speter 					error("Write requires an argument");
804766Speter 				break;
805766Speter 			case O_MESSAGE:
806766Speter 				if (argc == 0)
807766Speter 					error("Message requires an argument");
808766Speter 			case O_WRITLN:
809766Speter 				if (filetype != nl+T1CHAR)
810766Speter 					error("Can't 'writeln' a non text file");
811766Speter 				if ( opt( 't' ) ) {
812766Speter 				    putleaf( P2ICON , 0 , 0
813766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
814766Speter 					, "_WRITLN" );
815766Speter 				    putRV( 0 , cbn , CURFILEOFFSET
816766Speter 					    , P2PTR|P2STRTY );
817766Speter 				} else {
818766Speter 				    putleaf( P2ICON , 0 , 0
819766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
820766Speter 					, "_fputc" );
821766Speter 				    putleaf( P2ICON , '\n' , 0 , P2CHAR , 0 );
822766Speter 				    putleaf( P2ICON , 0 , 0
823766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
824766Speter 					, "_ACTFILE" );
825766Speter 				    putRV( 0 , cbn , CURFILEOFFSET
826766Speter 					    , P2PTR|P2STRTY );
827766Speter 				    putop( P2CALL , P2INT );
828766Speter 				    putop( P2LISTOP , P2INT );
829766Speter 				}
830766Speter 				putop( P2CALL , P2INT );
831766Speter 				putdot( filename , line );
832766Speter 				break;
833766Speter 		}
834766Speter 		return;
835766Speter 
836766Speter 	case O_READ4:
837766Speter 	case O_READLN:
838766Speter 		/*
839766Speter 		 * Set up default
840766Speter 		 * file "input".
841766Speter 		 */
842766Speter 		file = NIL;
843766Speter 		filetype = nl+T1CHAR;
844766Speter 		/*
845766Speter 		 * Determine the file implied
846766Speter 		 * for the read and generate
847766Speter 		 * code to make it the active file.
848766Speter 		 */
849766Speter 		if (argv != NIL) {
850766Speter 			codeoff();
851766Speter 			ap = stkrval(argv[1], NIL , RREQ );
852766Speter 			codeon();
853766Speter 			if (ap == NIL)
854766Speter 				argv = argv[2];
855766Speter 			if (ap != NIL && ap->class == FILET) {
856766Speter 				/*
857766Speter 				 * Got "read(f, ...", make
858766Speter 				 * f the active file, and save
859766Speter 				 * it and its type for use in
860766Speter 				 * processing the rest of the
861766Speter 				 * arguments to read.
862766Speter 				 */
863766Speter 				file = argv[1];
864766Speter 				filetype = ap->type;
865766Speter 				putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY );
866766Speter 				putleaf( P2ICON , 0 , 0
867766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
868766Speter 					, "_UNIT" );
869766Speter 				stklval(argv[1], NOFLAGS);
870766Speter 				putop( P2CALL , P2INT );
871766Speter 				putop( P2ASSIGN , P2PTR|P2STRTY );
872766Speter 				putdot( filename , line );
873766Speter 				argv = argv[2];
874766Speter 				argc--;
875766Speter 			} else {
876766Speter 				/*
877766Speter 				 * Default is read from
878766Speter 				 * standard input.
879766Speter 				 */
880766Speter 				putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY );
881766Speter 				putLV( "_input" , 0 , 0 , P2PTR|P2STRTY );
882766Speter 				putop( P2ASSIGN , P2PTR|P2STRTY );
883766Speter 				putdot( filename , line );
884766Speter 				input->nl_flags |= NUSED;
885766Speter 			}
886766Speter 		} else {
887766Speter 			putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY );
888766Speter 			putLV( "_input" , 0 , 0 , P2PTR|P2STRTY );
889766Speter 			putop( P2ASSIGN , P2PTR|P2STRTY );
890766Speter 			putdot( filename , line );
891766Speter 			input->nl_flags |= NUSED;
892766Speter 		}
893766Speter 		/*
894766Speter 		 * Loop and process each
895766Speter 		 * of the arguments.
896766Speter 		 */
897766Speter 		for (; argv != NIL; argv = argv[2]) {
898766Speter 			/*
899766Speter 			 * Get the address of the target
900766Speter 			 * on the stack.
901766Speter 			 */
902766Speter 			al = argv[1];
903766Speter 			if (al == NIL)
904766Speter 				continue;
905766Speter 			if (al[0] != T_VAR) {
906766Speter 				error("Arguments to %s must be variables, not expressions", p->symbol);
907766Speter 				continue;
908766Speter 			}
909766Speter 			codeoff();
910766Speter 			ap = stklval(al, MOD|ASGN|NOUSE);
911766Speter 			codeon();
912766Speter 			if (ap == NIL)
913766Speter 				continue;
914766Speter 			if (filetype != nl+T1CHAR) {
915766Speter 				/*
916766Speter 				 * Generalized read, i.e.
917766Speter 				 * from a non-textfile.
918766Speter 				 */
919766Speter 				if (incompat(filetype, ap, argv[1] )) {
920766Speter 					error("Type mismatch in read from non-text file");
921766Speter 					continue;
922766Speter 				}
923766Speter 				/*
924766Speter 				 * var := file ^;
925766Speter 				 */
926766Speter 				ap = lvalue( al , MOD | ASGN | NOUSE , RREQ );
927766Speter 				if ( isa( ap , "bsci" ) ) {
928766Speter 					precheck( ap , "_RANG4" , "_RSNG4" );
929766Speter 				}
930766Speter 				putleaf( P2ICON , 0 , 0
931766Speter 				    , ADDTYPE(
932766Speter 					ADDTYPE(
933766Speter 					    ADDTYPE(
934766Speter 						p2type( filetype ) , P2PTR )
935766Speter 					    , P2FTN )
936766Speter 					, P2PTR )
937766Speter 				    , "_FNIL" );
938766Speter 				if (file != NIL)
939766Speter 					stklval(file, NOFLAGS);
940766Speter 				else /* Magic */
941766Speter 					putRV( "_input" , 0 , 0
942766Speter 						, P2PTR | P2STRTY );
943766Speter 				putop( P2CALL , P2INT );
944766Speter 				switch ( classify( filetype ) ) {
945766Speter 				    case TBOOL:
946766Speter 				    case TCHAR:
947766Speter 				    case TINT:
948766Speter 				    case TSCAL:
949766Speter 				    case TDOUBLE:
950766Speter 				    case TPTR:
951766Speter 					putop( P2UNARY P2MUL
952766Speter 						, p2type( filetype ) );
953766Speter 				}
954766Speter 				switch ( classify( filetype ) ) {
955766Speter 				    case TBOOL:
956766Speter 				    case TCHAR:
957766Speter 				    case TINT:
958766Speter 				    case TSCAL:
959766Speter 					    postcheck( ap );
960766Speter 						/* and fall through */
961766Speter 				    case TDOUBLE:
962766Speter 				    case TPTR:
963766Speter 					    putop( P2ASSIGN , p2type( ap ) );
964766Speter 					    putdot( filename , line );
965766Speter 					    break;
966766Speter 				    default:
967766Speter 					    putstrop( P2STASG
968766Speter 							, p2type( ap )
969766Speter 							, lwidth( ap )
970766Speter 							, align( ap ) );
971766Speter 					    putdot( filename , line );
972766Speter 					    break;
973766Speter 				}
974766Speter 				/*
975766Speter 				 * get(file);
976766Speter 				 */
977766Speter 				putleaf( P2ICON , 0 , 0
978766Speter 					, ADDTYPE( P2FTN | P2INT , P2PTR )
979766Speter 					, "_GET" );
980766Speter 				putRV( 0 , cbn , CURFILEOFFSET
981766Speter 					, P2PTR|P2STRTY );
982766Speter 				putop( P2CALL , P2INT );
983766Speter 				putdot( filename , line );
984766Speter 				continue;
985766Speter 			}
986766Speter 			    /*
987766Speter 			     *	if you get to here, you are reading from
988766Speter 			     *	a text file.  only possiblities are:
989766Speter 			     *	character, integer, real, or scalar.
990766Speter 			     *	read( f , foo , ... ) is done as
991766Speter 			     *	foo := read( f ) with rangechecking
992766Speter 			     *	if appropriate.
993766Speter 			     */
994766Speter 			typ = classify(ap);
995766Speter 			op = rdops(typ);
996766Speter 			if (op == NIL) {
997766Speter 				error("Can't read %ss from a text file", clnames[typ]);
998766Speter 				continue;
999766Speter 			}
1000766Speter 			    /*
1001766Speter 			     *	left hand side of foo := read( f )
1002766Speter 			     */
1003766Speter 			ap = lvalue( al , MOD|ASGN|NOUSE , RREQ );
1004766Speter 			if ( isa( ap , "bsci" ) ) {
1005766Speter 			    precheck( ap , "_RANG4" , "_RSNG4" );
1006766Speter 			}
1007766Speter 			switch ( op ) {
1008766Speter 			    case O_READC:
1009766Speter 				readname = "_READC";
1010766Speter 				readtype = P2INT;
1011766Speter 				break;
1012766Speter 			    case O_READ4:
1013766Speter 				readname = "_READ4";
1014766Speter 				readtype = P2INT;
1015766Speter 				break;
1016766Speter 			    case O_READ8:
1017766Speter 				readname = "_READ8";
1018766Speter 				readtype = P2DOUBLE;
1019766Speter 				break;
1020766Speter 			    case O_READE:
1021766Speter 				readname = "_READE";
1022766Speter 				readtype = P2INT;
1023766Speter 				break;
1024766Speter 			}
1025766Speter 			putleaf( P2ICON , 0 , 0
1026766Speter 				, ADDTYPE( P2FTN | readtype , P2PTR )
1027766Speter 				, readname );
1028766Speter 			putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY );
1029766Speter 			if ( op == O_READE ) {
1030766Speter 				sprintf( format , PREFIXFORMAT , LABELPREFIX
1031766Speter 					, listnames( ap ) );
1032766Speter 				putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR
1033766Speter 					, format );
1034766Speter 				putop( P2LISTOP , P2INT );
10351629Speter 				warning();
1036766Speter 				if (opt('s')) {
1037766Speter 					standard();
1038766Speter 				}
10391629Speter 				error("Reading scalars from text files is non-standard");
1040766Speter 			}
1041766Speter 			putop( P2CALL , readtype );
1042766Speter 			if ( isa( ap , "bcsi" ) ) {
1043766Speter 			    postcheck( ap );
1044766Speter 			}
1045766Speter 			putop( P2ASSIGN , p2type( ap ) );
1046766Speter 			putdot( filename , line );
1047766Speter 		}
1048766Speter 		/*
1049766Speter 		 * Done with arguments.
1050766Speter 		 * Handle readln and
1051766Speter 		 * insufficient number of args.
1052766Speter 		 */
1053766Speter 		if (p->value[0] == O_READLN) {
1054766Speter 			if (filetype != nl+T1CHAR)
1055766Speter 				error("Can't 'readln' a non text file");
1056766Speter 			putleaf( P2ICON , 0 , 0
1057766Speter 				, ADDTYPE( P2FTN | P2INT , P2PTR )
1058766Speter 				, "_READLN" );
1059766Speter 			putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY );
1060766Speter 			putop( P2CALL , P2INT );
1061766Speter 			putdot( filename , line );
1062766Speter 		} else if (argc == 0)
1063766Speter 			error("read requires an argument");
1064766Speter 		return;
1065766Speter 
1066766Speter 	case O_GET:
1067766Speter 	case O_PUT:
1068766Speter 		if (argc != 1) {
1069766Speter 			error("%s expects one argument", p->symbol);
1070766Speter 			return;
1071766Speter 		}
1072766Speter 		putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY );
1073766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1074766Speter 			, "_UNIT" );
1075766Speter 		ap = stklval(argv[1], NOFLAGS);
1076766Speter 		if (ap == NIL)
1077766Speter 			return;
1078766Speter 		if (ap->class != FILET) {
1079766Speter 			error("Argument to %s must be a file, not %s", p->symbol, nameof(ap));
1080766Speter 			return;
1081766Speter 		}
1082766Speter 		putop( P2CALL , P2INT );
1083766Speter 		putop( P2ASSIGN , P2PTR|P2STRTY );
1084766Speter 		putdot( filename , line );
1085766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1086766Speter 			, op == O_GET ? "_GET" : "_PUT" );
1087766Speter 		putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY );
1088766Speter 		putop( P2CALL , P2INT );
1089766Speter 		putdot( filename , line );
1090766Speter 		return;
1091766Speter 
1092766Speter 	case O_RESET:
1093766Speter 	case O_REWRITE:
1094766Speter 		if (argc == 0 || argc > 2) {
1095766Speter 			error("%s expects one or two arguments", p->symbol);
1096766Speter 			return;
1097766Speter 		}
1098766Speter 		if (opt('s') && argc == 2) {
1099766Speter 			standard();
1100766Speter 			error("Two argument forms of reset and rewrite are non-standard");
1101766Speter 		}
1102766Speter 		putleaf( P2ICON , 0 , 0 , P2INT
1103766Speter 			, op == O_RESET ? "_RESET" : "_REWRITE" );
1104766Speter 		ap = stklval(argv[1], MOD|NOUSE);
1105766Speter 		if (ap == NIL)
1106766Speter 			return;
1107766Speter 		if (ap->class != FILET) {
1108766Speter 			error("First argument to %s must be a file, not %s", p->symbol, nameof(ap));
1109766Speter 			return;
1110766Speter 		}
1111766Speter 		if (argc == 2) {
1112766Speter 			/*
1113766Speter 			 * Optional second argument
1114766Speter 			 * is a string name of a
1115766Speter 			 * UNIX (R) file to be associated.
1116766Speter 			 */
1117766Speter 			al = argv[2];
1118766Speter 			al = stkrval(al[1], NOFLAGS , RREQ );
1119766Speter 			if (al == NIL)
1120766Speter 				return;
1121766Speter 			if (classify(al) != TSTR) {
1122766Speter 				error("Second argument to %s must be a string, not %s", p->symbol, nameof(al));
1123766Speter 				return;
1124766Speter 			}
1125766Speter 			strnglen = width(al);
1126766Speter 		} else {
1127766Speter 			putleaf( P2ICON , 0 , 0 , P2INT , 0 );
1128766Speter 			strnglen = 0;
1129766Speter 		}
1130766Speter 		putop( P2LISTOP , P2INT );
1131766Speter 		putleaf( P2ICON , strnglen , 0 , P2INT , 0 );
1132766Speter 		putop( P2LISTOP , P2INT );
1133766Speter 		putleaf( P2ICON , text(ap) ? 0: width(ap->type) , 0 , P2INT , 0 );
1134766Speter 		putop( P2LISTOP , P2INT );
1135766Speter 		putop( P2CALL , P2INT );
1136766Speter 		putdot( filename , line );
1137766Speter 		return;
1138766Speter 
1139766Speter 	case O_NEW:
1140766Speter 	case O_DISPOSE:
1141766Speter 		if (argc == 0) {
1142766Speter 			error("%s expects at least one argument", p->symbol);
1143766Speter 			return;
1144766Speter 		}
1145766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1146766Speter 			, op == O_DISPOSE ? "_DISPOSE" :
1147766Speter 				opt('t') ? "_NEWZ" : "_NEW" );
1148766Speter 		ap = stklval(argv[1], op == O_NEW ? ( MOD | NOUSE ) : MOD );
1149766Speter 		if (ap == NIL)
1150766Speter 			return;
1151766Speter 		if (ap->class != PTR) {
1152766Speter 			error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap));
1153766Speter 			return;
1154766Speter 		}
1155766Speter 		ap = ap->type;
1156766Speter 		if (ap == NIL)
1157766Speter 			return;
1158766Speter 		argv = argv[2];
1159766Speter 		if (argv != NIL) {
1160766Speter 			if (ap->class != RECORD) {
1161766Speter 				error("Record required when specifying variant tags");
1162766Speter 				return;
1163766Speter 			}
1164766Speter 			for (; argv != NIL; argv = argv[2]) {
1165766Speter 				if (ap->ptr[NL_VARNT] == NIL) {
1166766Speter 					error("Too many tag fields");
1167766Speter 					return;
1168766Speter 				}
1169766Speter 				if (!isconst(argv[1])) {
1170766Speter 					error("Second and successive arguments to %s must be constants", p->symbol);
1171766Speter 					return;
1172766Speter 				}
1173766Speter 				gconst(argv[1]);
1174766Speter 				if (con.ctype == NIL)
1175766Speter 					return;
1176766Speter 				if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) {
1177766Speter 					cerror("Specified tag constant type clashed with variant case selector type");
1178766Speter 					return;
1179766Speter 				}
1180766Speter 				for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain)
1181766Speter 					if (ap->range[0] == con.crval)
1182766Speter 						break;
1183766Speter 				if (ap == NIL) {
1184766Speter 					error("No variant case label value equals specified constant value");
1185766Speter 					return;
1186766Speter 				}
1187766Speter 				ap = ap->ptr[NL_VTOREC];
1188766Speter 			}
1189766Speter 		}
1190766Speter 		putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 );
1191766Speter 		putop( P2LISTOP , P2INT );
1192766Speter 		putop( P2CALL , P2INT );
1193766Speter 		putdot( filename , line );
1194766Speter 		return;
1195766Speter 
1196766Speter 	case O_DATE:
1197766Speter 	case O_TIME:
1198766Speter 		if (argc != 1) {
1199766Speter 			error("%s expects one argument", p->symbol);
1200766Speter 			return;
1201766Speter 		}
1202766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1203766Speter 			, op == O_DATE ? "_DATE" : "_TIME" );
1204766Speter 		ap = stklval(argv[1], MOD|NOUSE);
1205766Speter 		if (ap == NIL)
1206766Speter 			return;
1207766Speter 		if (classify(ap) != TSTR || width(ap) != 10) {
1208766Speter 			error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap));
1209766Speter 			return;
1210766Speter 		}
1211766Speter 		putop( P2CALL , P2INT );
1212766Speter 		putdot( filename , line );
1213766Speter 		return;
1214766Speter 
1215766Speter 	case O_HALT:
1216766Speter 		if (argc != 0) {
1217766Speter 			error("halt takes no arguments");
1218766Speter 			return;
1219766Speter 		}
1220766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1221766Speter 			, "_HALT" );
1222766Speter 
1223766Speter 		putop( P2UNARY P2CALL , P2INT );
1224766Speter 		putdot( filename , line );
1225766Speter 		noreach = 1;
1226766Speter 		return;
1227766Speter 
1228766Speter 	case O_ARGV:
1229766Speter 		if (argc != 2) {
1230766Speter 			error("argv takes two arguments");
1231766Speter 			return;
1232766Speter 		}
1233766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1234766Speter 			, "_ARGV" );
1235766Speter 		ap = stkrval(argv[1], NIL , RREQ );
1236766Speter 		if (ap == NIL)
1237766Speter 			return;
1238766Speter 		if (isnta(ap, "i")) {
1239766Speter 			error("argv's first argument must be an integer, not %s", nameof(ap));
1240766Speter 			return;
1241766Speter 		}
1242766Speter 		al = argv[2];
1243766Speter 		ap = stklval(al[1], MOD|NOUSE);
1244766Speter 		if (ap == NIL)
1245766Speter 			return;
1246766Speter 		if (classify(ap) != TSTR) {
1247766Speter 			error("argv's second argument must be a string, not %s", nameof(ap));
1248766Speter 			return;
1249766Speter 		}
1250766Speter 		putop( P2LISTOP , P2INT );
1251766Speter 		putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 );
1252766Speter 		putop( P2LISTOP , P2INT );
1253766Speter 		putop( P2CALL , P2INT );
1254766Speter 		putdot( filename , line );
1255766Speter 		return;
1256766Speter 
1257766Speter 	case O_STLIM:
1258766Speter 		if (argc != 1) {
1259766Speter 			error("stlimit requires one argument");
1260766Speter 			return;
1261766Speter 		}
1262766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1263766Speter 			, "_STLIM" );
1264766Speter 		ap = stkrval(argv[1], NIL , RREQ );
1265766Speter 		if (ap == NIL)
1266766Speter 			return;
1267766Speter 		if (isnta(ap, "i")) {
1268766Speter 			error("stlimit's argument must be an integer, not %s", nameof(ap));
1269766Speter 			return;
1270766Speter 		}
1271766Speter 		putop( P2CALL , P2INT );
1272766Speter 		putdot( filename , line );
1273766Speter 		return;
1274766Speter 
1275766Speter 	case O_REMOVE:
1276766Speter 		if (argc != 1) {
1277766Speter 			error("remove expects one argument");
1278766Speter 			return;
1279766Speter 		}
1280766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1281766Speter 			, "_REMOVE" );
1282766Speter 		ap = stkrval(argv[1], NOFLAGS , RREQ );
1283766Speter 		if (ap == NIL)
1284766Speter 			return;
1285766Speter 		if (classify(ap) != TSTR) {
1286766Speter 			error("remove's argument must be a string, not %s", nameof(ap));
1287766Speter 			return;
1288766Speter 		}
1289766Speter 		putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 );
1290766Speter 		putop( P2LISTOP , P2INT );
1291766Speter 		putop( P2CALL , P2INT );
1292766Speter 		putdot( filename , line );
1293766Speter 		return;
1294766Speter 
1295766Speter 	case O_LLIMIT:
1296766Speter 		if (argc != 2) {
1297766Speter 			error("linelimit expects two arguments");
1298766Speter 			return;
1299766Speter 		}
1300766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1301766Speter 			, "_LLIMIT" );
1302766Speter 		ap = stklval(argv[1], NOFLAGS|NOUSE);
1303766Speter 		if (ap == NIL)
1304766Speter 			return;
1305766Speter 		if (!text(ap)) {
1306766Speter 			error("linelimit's first argument must be a text file, not %s", nameof(ap));
1307766Speter 			return;
1308766Speter 		}
1309766Speter 		al = argv[2];
1310766Speter 		ap = stkrval(al[1], NIL , RREQ );
1311766Speter 		if (ap == NIL)
1312766Speter 			return;
1313766Speter 		if (isnta(ap, "i")) {
1314766Speter 			error("linelimit's second argument must be an integer, not %s", nameof(ap));
1315766Speter 			return;
1316766Speter 		}
1317766Speter 		putop( P2LISTOP , P2INT );
1318766Speter 		putop( P2CALL , P2INT );
1319766Speter 		putdot( filename , line );
1320766Speter 		return;
1321766Speter 	case O_PAGE:
1322766Speter 		if (argc != 1) {
1323766Speter 			error("page expects one argument");
1324766Speter 			return;
1325766Speter 		}
1326766Speter 		putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY );
1327766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1328766Speter 			, "_UNIT" );
1329766Speter 		ap = stklval(argv[1], NOFLAGS);
1330766Speter 		if (ap == NIL)
1331766Speter 			return;
1332766Speter 		if (!text(ap)) {
1333766Speter 			error("Argument to page must be a text file, not %s", nameof(ap));
1334766Speter 			return;
1335766Speter 		}
1336766Speter 		putop( P2CALL , P2INT );
1337766Speter 		putop( P2ASSIGN , P2PTR|P2STRTY );
1338766Speter 		putdot( filename , line );
1339766Speter 		if ( opt( 't' ) ) {
1340766Speter 		    putleaf( P2ICON , 0 , 0
1341766Speter 			, ADDTYPE( P2FTN | P2INT , P2PTR )
1342766Speter 			, "_PAGE" );
1343766Speter 		    putRV( 0 , cbn , CURFILEOFFSET
1344766Speter 			    , P2PTR|P2STRTY );
1345766Speter 		} else {
1346766Speter 		    putleaf( P2ICON , 0 , 0
1347766Speter 			, ADDTYPE( P2FTN | P2INT , P2PTR )
1348766Speter 			, "_fputc" );
1349766Speter 		    putleaf( P2ICON , '\f' , 0 , P2CHAR , 0 );
1350766Speter 		    putleaf( P2ICON , 0 , 0
1351766Speter 			, ADDTYPE( P2FTN | P2INT , P2PTR )
1352766Speter 			, "_ACTFILE" );
1353766Speter 		    putRV( 0 , cbn , CURFILEOFFSET
1354766Speter 			    , P2PTR|P2STRTY );
1355766Speter 		    putop( P2CALL , P2INT );
1356766Speter 		    putop( P2LISTOP , P2INT );
1357766Speter 		}
1358766Speter 		putop( P2CALL , P2INT );
1359766Speter 		putdot( filename , line );
1360766Speter 		return;
1361766Speter 
1362766Speter 	case O_PACK:
1363766Speter 		if (argc != 3) {
1364766Speter 			error("pack expects three arguments");
1365766Speter 			return;
1366766Speter 		}
1367766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1368766Speter 			, "_PACK" );
1369766Speter 		pu = "pack(a,i,z)";
1370766Speter 		pua = (al = argv)[1];
1371766Speter 		pui = (al = al[2])[1];
1372766Speter 		puz = (al = al[2])[1];
1373766Speter 		goto packunp;
1374766Speter 	case O_UNPACK:
1375766Speter 		if (argc != 3) {
1376766Speter 			error("unpack expects three arguments");
1377766Speter 			return;
1378766Speter 		}
1379766Speter 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1380766Speter 			, "_UNPACK" );
1381766Speter 		pu = "unpack(z,a,i)";
1382766Speter 		puz = (al = argv)[1];
1383766Speter 		pua = (al = al[2])[1];
1384766Speter 		pui = (al = al[2])[1];
1385766Speter packunp:
1386766Speter 		ap = stkrval((int *) pui, NLNIL , RREQ );
1387766Speter 		if (ap == NIL)
1388766Speter 			return;
1389766Speter 		ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE);
1390766Speter 		if (ap == NIL)
1391766Speter 			return;
1392766Speter 		if (ap->class != ARRAY) {
1393766Speter 			error("%s requires a to be an unpacked array, not %s", pu, nameof(ap));
1394766Speter 			return;
1395766Speter 		}
1396766Speter 		putop( P2LISTOP , P2INT );
1397766Speter 		al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE);
1398766Speter 		if (al->class != ARRAY) {
1399766Speter 			error("%s requires z to be a packed array, not %s", pu, nameof(ap));
1400766Speter 			return;
1401766Speter 		}
1402766Speter 		if (al->type == NIL || ap->type == NIL)
1403766Speter 			return;
1404766Speter 		if (al->type != ap->type) {
1405766Speter 			error("%s requires a and z to be arrays of the same type", pu, nameof(ap));
1406766Speter 			return;
1407766Speter 		}
1408766Speter 		putop( P2LISTOP , P2INT );
1409766Speter 		k = width(al);
1410766Speter 		itemwidth = width(ap->type);
1411766Speter 		ap = ap->chain;
1412766Speter 		al = al->chain;
1413766Speter 		if (ap->chain != NIL || al->chain != NIL) {
1414766Speter 			error("%s requires a and z to be single dimension arrays", pu);
1415766Speter 			return;
1416766Speter 		}
1417766Speter 		if (ap == NIL || al == NIL)
1418766Speter 			return;
1419766Speter 		/*
1420766Speter 		 * al is the range for z i.e. u..v
1421766Speter 		 * ap is the range for a i.e. m..n
1422766Speter 		 * i will be n-m+1
1423766Speter 		 * j will be v-u+1
1424766Speter 		 */
1425766Speter 		i = ap->range[1] - ap->range[0] + 1;
1426766Speter 		j = al->range[1] - al->range[0] + 1;
1427766Speter 		if (i < j) {
1428766Speter 			error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i);
1429766Speter 			return;
1430766Speter 		}
1431766Speter 		/*
1432766Speter 		 * get n-m-(v-u) and m for the interpreter
1433766Speter 		 */
1434766Speter 		i -= j;
1435766Speter 		j = ap->range[0];
1436766Speter 		putleaf( P2ICON , itemwidth , 0 , P2INT , 0 );
1437766Speter 		putop( P2LISTOP , P2INT );
1438766Speter 		putleaf( P2ICON , j , 0 , P2INT , 0 );
1439766Speter 		putop( P2LISTOP , P2INT );
1440766Speter 		putleaf( P2ICON , i , 0 , P2INT , 0 );
1441766Speter 		putop( P2LISTOP , P2INT );
1442766Speter 		putleaf( P2ICON , k , 0 , P2INT , 0 );
1443766Speter 		putop( P2LISTOP , P2INT );
1444766Speter 		putop( P2CALL , P2INT );
1445766Speter 		putdot( filename , line );
1446766Speter 		return;
1447766Speter 	case 0:
1448766Speter 		error("%s is an unimplemented 6400 extension", p->symbol);
1449766Speter 		return;
1450766Speter 
1451766Speter 	default:
1452766Speter 		panic("proc case");
1453766Speter 	}
1454766Speter }
1455766Speter #endif PC
1456