|
|
1.1 root 1: /* Copyright (c) 1979 Regents of the University of California */
2:
3: static char sccsid[] = "@(#)pcproc.c 1.3 10/28/80";
4:
5: #include "whoami.h"
6: #ifdef PC
7: /*
8: * and to the end of the file
9: */
10: #include "0.h"
11: #include "tree.h"
12: #include "opcode.h"
13: #include "pc.h"
14: #include "pcops.h"
15:
16: /*
17: * The following array is used to determine which classes may be read
18: * from textfiles. It is indexed by the return value from classify.
19: */
20: #define rdops(x) rdxxxx[(x)-(TFIRST)]
21:
22: int rdxxxx[] = {
23: 0, /* -7 file types */
24: 0, /* -6 record types */
25: 0, /* -5 array types */
26: O_READE, /* -4 scalar types */
27: 0, /* -3 pointer types */
28: 0, /* -2 set types */
29: 0, /* -1 string types */
30: 0, /* 0 nil, no type */
31: O_READE, /* 1 boolean */
32: O_READC, /* 2 character */
33: O_READ4, /* 3 integer */
34: O_READ8 /* 4 real */
35: };
36:
37: /*
38: * Proc handles procedure calls.
39: * Non-builtin procedures are "buck-passed" to func (with a flag
40: * indicating that they are actually procedures.
41: * builtin procedures are handled here.
42: */
43: pcproc(r)
44: int *r;
45: {
46: register struct nl *p;
47: register int *alv, *al, op;
48: struct nl *filetype, *ap;
49: int argc, *argv, typ, fmtspec, strfmt, stkcnt, *file;
50: char fmt, format[20], *strptr;
51: int prec, field, strnglen, fmtlen, fmtstart, pu;
52: int *pua, *pui, *puz;
53: int i, j, k;
54: int itemwidth;
55: char *readname;
56: long tempoff;
57: long readtype;
58:
59: #define CONPREC 4
60: #define VARPREC 8
61: #define CONWIDTH 1
62: #define VARWIDTH 2
63: #define SKIP 16
64:
65: /*
66: * Verify that the name is
67: * defined and is that of a
68: * procedure.
69: */
70: p = lookup(r[2]);
71: if (p == NIL) {
72: rvlist(r[3]);
73: return;
74: }
75: if (p->class != PROC && p->class != FPROC) {
76: error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]);
77: rvlist(r[3]);
78: return;
79: }
80: argv = r[3];
81:
82: /*
83: * Call handles user defined
84: * procedures and functions.
85: */
86: if (bn != 0) {
87: call(p, argv, PROC, bn);
88: return;
89: }
90:
91: /*
92: * Call to built-in procedure.
93: * Count the arguments.
94: */
95: argc = 0;
96: for (al = argv; al != NIL; al = al[2])
97: argc++;
98:
99: /*
100: * Switch on the operator
101: * associated with the built-in
102: * procedure in the namelist
103: */
104: op = p->value[0] &~ NSTAND;
105: if (opt('s') && (p->value[0] & NSTAND)) {
106: standard();
107: error("%s is a nonstandard procedure", p->symbol);
108: }
109: switch (op) {
110:
111: case O_ABORT:
112: if (argc != 0)
113: error("null takes no arguments");
114: return;
115:
116: case O_FLUSH:
117: if (argc == 0) {
118: putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" );
119: putop( P2UNARY P2CALL , P2INT );
120: putdot( filename , line );
121: return;
122: }
123: if (argc != 1) {
124: error("flush takes at most one argument");
125: return;
126: }
127: putleaf( P2ICON , 0 , 0
128: , ADDTYPE( P2FTN | P2INT , P2PTR )
129: , "_FLUSH" );
130: ap = stklval(argv[1], NOFLAGS);
131: if (ap == NIL)
132: return;
133: if (ap->class != FILET) {
134: error("flush's argument must be a file, not %s", nameof(ap));
135: return;
136: }
137: putop( P2CALL , P2INT );
138: putdot( filename , line );
139: return;
140:
141: case O_MESSAGE:
142: case O_WRITEF:
143: case O_WRITLN:
144: /*
145: * Set up default file "output"'s type
146: */
147: file = NIL;
148: filetype = nl+T1CHAR;
149: /*
150: * Determine the file implied
151: * for the write and generate
152: * code to make it the active file.
153: */
154: if (op == O_MESSAGE) {
155: /*
156: * For message, all that matters
157: * is that the filetype is
158: * a character file.
159: * Thus "output" will suit us fine.
160: */
161: putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" );
162: putop( P2UNARY P2CALL , P2INT );
163: putdot( filename , line );
164: putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY );
165: putLV( "__err" , 0 , 0 , P2PTR|P2STRTY );
166: putop( P2ASSIGN , P2PTR|P2STRTY );
167: putdot( filename , line );
168: } else if (argv != NIL && (al = argv[1])[0] != T_WEXP) {
169: /*
170: * If there is a first argument which has
171: * no write widths, then it is potentially
172: * a file name.
173: */
174: codeoff();
175: ap = stkrval(argv[1], NIL , RREQ );
176: codeon();
177: if (ap == NIL)
178: argv = argv[2];
179: if (ap != NIL && ap->class == FILET) {
180: /*
181: * Got "write(f, ...", make
182: * f the active file, and save
183: * it and its type for use in
184: * processing the rest of the
185: * arguments to write.
186: */
187: putRV( 0 , cbn , CURFILEOFFSET
188: , P2PTR|P2STRTY );
189: putleaf( P2ICON , 0 , 0
190: , ADDTYPE( P2FTN | P2INT , P2PTR )
191: , "_UNIT" );
192: file = argv[1];
193: filetype = ap->type;
194: stklval(argv[1], NOFLAGS);
195: putop( P2CALL , P2INT );
196: putop( P2ASSIGN , P2PTR|P2STRTY );
197: putdot( filename , line );
198: /*
199: * Skip over the first argument
200: */
201: argv = argv[2];
202: argc--;
203: } else {
204: /*
205: * Set up for writing on
206: * standard output.
207: */
208: putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY );
209: putLV( "_output" , 0 , 0 , P2PTR|P2STRTY );
210: putop( P2ASSIGN , P2PTR|P2STRTY );
211: putdot( filename , line );
212: }
213: } else {
214: putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY );
215: putLV( "_output" , 0 , 0 , P2PTR|P2STRTY );
216: putop( P2ASSIGN , P2PTR|P2STRTY );
217: putdot( filename , line );
218: }
219: /*
220: * Loop and process each
221: * of the arguments.
222: */
223: for (; argv != NIL; argv = argv[2]) {
224: /*
225: * fmtspec indicates the type (CONstant or VARiable)
226: * and number (none, WIDTH, and/or PRECision)
227: * of the fields in the printf format for this
228: * output variable.
229: * stkcnt is the number of longs pushed on the stack
230: * fmt is the format output indicator (D, E, F, O, X, S)
231: * fmtstart = 0 for leading blank; = 1 for no blank
232: */
233: fmtspec = NIL;
234: stkcnt = 0;
235: fmt = 'D';
236: fmtstart = 1;
237: al = argv[1];
238: if (al == NIL)
239: continue;
240: if (al[0] == T_WEXP)
241: alv = al[1];
242: else
243: alv = al;
244: if (alv == NIL)
245: continue;
246: codeoff();
247: ap = stkrval(alv, NIL , RREQ );
248: codeon();
249: if (ap == NIL)
250: continue;
251: typ = classify(ap);
252: if (al[0] == T_WEXP) {
253: /*
254: * Handle width expressions.
255: * The basic game here is that width
256: * expressions get evaluated. If they
257: * are constant, the value is placed
258: * directly in the format string.
259: * Otherwise the value is pushed onto
260: * the stack and an indirection is
261: * put into the format string.
262: */
263: if (al[3] == OCT)
264: fmt = 'O';
265: else if (al[3] == HEX)
266: fmt = 'X';
267: else if (al[3] != NIL) {
268: /*
269: * Evaluate second format spec
270: */
271: if ( constval(al[3])
272: && isa( con.ctype , "i" ) ) {
273: fmtspec += CONPREC;
274: prec = con.crval;
275: } else {
276: fmtspec += VARPREC;
277: }
278: fmt = 'f';
279: switch ( typ ) {
280: case TINT:
281: if ( opt( 's' ) ) {
282: standard();
283: error("Writing %ss with two write widths is non-standard", clnames[typ]);
284: }
285: /* and fall through */
286: case TDOUBLE:
287: break;
288: default:
289: error("Cannot write %ss with two write widths", clnames[typ]);
290: continue;
291: }
292: }
293: /*
294: * Evaluate first format spec
295: */
296: if (al[2] != NIL) {
297: if ( constval(al[2])
298: && isa( con.ctype , "i" ) ) {
299: fmtspec += CONWIDTH;
300: field = con.crval;
301: } else {
302: fmtspec += VARWIDTH;
303: }
304: }
305: if ((fmtspec & CONPREC) && prec < 0 ||
306: (fmtspec & CONWIDTH) && field < 0) {
307: error("Negative widths are not allowed");
308: continue;
309: }
310: }
311: if (filetype != nl+T1CHAR) {
312: if (fmt == 'O' || fmt == 'X') {
313: error("Oct/hex allowed only on text files");
314: continue;
315: }
316: if (fmtspec) {
317: error("Write widths allowed only on text files");
318: continue;
319: }
320: /*
321: * Generalized write, i.e.
322: * to a non-textfile.
323: */
324: putleaf( P2ICON , 0 , 0
325: , ADDTYPE(
326: ADDTYPE(
327: ADDTYPE( p2type( filetype )
328: , P2PTR )
329: , P2FTN )
330: , P2PTR )
331: , "_FNIL" );
332: stklval(file, NOFLAGS);
333: putop( P2CALL
334: , ADDTYPE( p2type( filetype ) , P2PTR ) );
335: putop( P2UNARY P2MUL , p2type( filetype ) );
336: /*
337: * file^ := ...
338: */
339: switch ( classify( filetype ) ) {
340: case TBOOL:
341: case TCHAR:
342: case TINT:
343: case TSCAL:
344: precheck( filetype , "_RANG4" , "_RSGN4" );
345: /* and fall through */
346: case TDOUBLE:
347: case TPTR:
348: ap = rvalue( argv[1] , filetype , RREQ );
349: break;
350: default:
351: ap = rvalue( argv[1] , filetype , LREQ );
352: break;
353: }
354: if (ap == NIL)
355: continue;
356: if (incompat(ap, filetype, argv[1])) {
357: cerror("Type mismatch in write to non-text file");
358: continue;
359: }
360: switch ( classify( filetype ) ) {
361: case TBOOL:
362: case TCHAR:
363: case TINT:
364: case TSCAL:
365: postcheck( filetype );
366: /* and fall through */
367: case TDOUBLE:
368: case TPTR:
369: putop( P2ASSIGN , p2type( filetype ) );
370: putdot( filename , line );
371: break;
372: default:
373: putstrop( P2STASG
374: , p2type( filetype )
375: , lwidth( filetype )
376: , align( filetype ) );
377: putdot( filename , line );
378: break;
379: }
380: /*
381: * put(file)
382: */
383: putleaf( P2ICON , 0 , 0
384: , ADDTYPE( P2FTN | P2INT , P2PTR )
385: , "_PUT" );
386: putRV( 0 , cbn , CURFILEOFFSET
387: , P2PTR|P2STRTY );
388: putop( P2CALL , P2INT );
389: putdot( filename , line );
390: continue;
391: }
392: /*
393: * Write to a textfile
394: *
395: * Evaluate the expression
396: * to be written.
397: */
398: if (fmt == 'O' || fmt == 'X') {
399: if (opt('s')) {
400: standard();
401: error("Oct and hex are non-standard");
402: }
403: if (typ == TSTR || typ == TDOUBLE) {
404: error("Can't write %ss with oct/hex", clnames[typ]);
405: continue;
406: }
407: if (typ == TCHAR || typ == TBOOL)
408: typ = TINT;
409: }
410: /*
411: * If there is no format specified by the programmer,
412: * implement the default.
413: */
414: switch (typ) {
415: case TINT:
416: if (fmt == 'f') {
417: typ = TDOUBLE;
418: goto tdouble;
419: }
420: if (fmtspec == NIL) {
421: if (fmt == 'D')
422: field = 10;
423: else if (fmt == 'X')
424: field = 8;
425: else if (fmt == 'O')
426: field = 11;
427: else
428: panic("fmt1");
429: fmtspec = CONWIDTH;
430: }
431: break;
432: case TCHAR:
433: tchar:
434: fmt = 'c';
435: break;
436: case TSCAL:
437: warning();
438: if (opt('s')) {
439: standard();
440: }
441: error("Writing scalars to text files is non-standard");
442: case TBOOL:
443: fmt = 's';
444: break;
445: case TDOUBLE:
446: tdouble:
447: switch (fmtspec) {
448: case NIL:
449: field = 21;
450: prec = 14;
451: fmt = 'E';
452: fmtspec = CONWIDTH + CONPREC;
453: break;
454: case CONWIDTH:
455: if (--field < 1)
456: field = 1;
457: prec = field - 7;
458: if (prec < 1)
459: prec = 1;
460: fmtspec += CONPREC;
461: fmt = 'E';
462: break;
463: case VARWIDTH:
464: fmtspec += VARPREC;
465: fmt = 'E';
466: break;
467: case CONWIDTH + CONPREC:
468: case CONWIDTH + VARPREC:
469: if (--field < 1)
470: field = 1;
471: }
472: format[0] = ' ';
473: fmtstart = 0;
474: break;
475: case TSTR:
476: constval( alv );
477: switch ( classify( con.ctype ) ) {
478: case TCHAR:
479: typ = TCHAR;
480: goto tchar;
481: case TSTR:
482: strptr = con.cpval;
483: for (strnglen = 0; *strptr++; strnglen++) /* void */;
484: strptr = con.cpval;
485: break;
486: default:
487: strnglen = width(ap);
488: break;
489: }
490: fmt = 's';
491: strfmt = fmtspec;
492: if (fmtspec == NIL) {
493: fmtspec = SKIP;
494: break;
495: }
496: if (fmtspec & CONWIDTH) {
497: if (field <= strnglen)
498: fmtspec = SKIP;
499: else
500: field -= strnglen;
501: }
502: break;
503: default:
504: error("Can't write %ss to a text file", clnames[typ]);
505: continue;
506: }
507: /*
508: * Generate the format string
509: */
510: switch (fmtspec) {
511: default:
512: panic("fmt2");
513: case NIL:
514: if (fmt == 'c') {
515: if ( opt( 't' ) ) {
516: putleaf( P2ICON , 0 , 0
517: , ADDTYPE( P2FTN|P2INT , P2PTR )
518: , "_WRITEC" );
519: putRV( 0 , cbn , CURFILEOFFSET
520: , P2PTR|P2STRTY );
521: stkrval( alv , NIL , RREQ );
522: putop( P2LISTOP , P2INT );
523: } else {
524: putleaf( P2ICON , 0 , 0
525: , ADDTYPE( P2FTN|P2INT , P2PTR )
526: , "_fputc" );
527: stkrval( alv , NIL , RREQ );
528: }
529: putleaf( P2ICON , 0 , 0
530: , ADDTYPE( P2FTN | P2INT , P2PTR )
531: , "_ACTFILE" );
532: putRV( 0, cbn , CURFILEOFFSET
533: , P2PTR|P2STRTY );
534: putop( P2CALL , P2INT );
535: putop( P2LISTOP , P2INT );
536: putop( P2CALL , P2INT );
537: putdot( filename , line );
538: } else {
539: sprintf(&format[1], "%%%c", fmt);
540: goto fmtgen;
541: }
542: case SKIP:
543: break;
544: case CONWIDTH:
545: sprintf(&format[1], "%%%1D%c", field, fmt);
546: goto fmtgen;
547: case VARWIDTH:
548: sprintf(&format[1], "%%*%c", fmt);
549: goto fmtgen;
550: case CONWIDTH + CONPREC:
551: sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt);
552: goto fmtgen;
553: case CONWIDTH + VARPREC:
554: sprintf(&format[1], "%%%1D.*%c", field, fmt);
555: goto fmtgen;
556: case VARWIDTH + CONPREC:
557: sprintf(&format[1], "%%*.%1D%c", prec, fmt);
558: goto fmtgen;
559: case VARWIDTH + VARPREC:
560: sprintf(&format[1], "%%*.*%c", fmt);
561: fmtgen:
562: if ( opt( 't' ) ) {
563: putleaf( P2ICON , 0 , 0
564: , ADDTYPE( P2FTN | P2INT , P2PTR )
565: , "_WRITEF" );
566: putRV( 0 , cbn , CURFILEOFFSET
567: , P2PTR|P2STRTY );
568: putleaf( P2ICON , 0 , 0
569: , ADDTYPE( P2FTN | P2INT , P2PTR )
570: , "_ACTFILE" );
571: putRV( 0 , cbn , CURFILEOFFSET
572: , P2PTR|P2STRTY );
573: putop( P2CALL , P2INT );
574: putop( P2LISTOP , P2INT );
575: } else {
576: putleaf( P2ICON , 0 , 0
577: , ADDTYPE( P2FTN | P2INT , P2PTR )
578: , "_fprintf" );
579: putleaf( P2ICON , 0 , 0
580: , ADDTYPE( P2FTN | P2INT , P2PTR )
581: , "_ACTFILE" );
582: putRV( 0 , cbn , CURFILEOFFSET
583: , P2PTR|P2STRTY );
584: putop( P2CALL , P2INT );
585: }
586: putCONG( &format[ fmtstart ]
587: , strlen( &format[ fmtstart ] )
588: , LREQ );
589: putop( P2LISTOP , P2INT );
590: if ( fmtspec & VARWIDTH ) {
591: /*
592: * either
593: * ,(temp=width,MAX(temp,...)),
594: * or
595: * , MAX( width , ... ) ,
596: */
597: if ( ( typ == TDOUBLE && al[3] == NIL )
598: || typ == TSTR ) {
599: sizes[ cbn ].om_off -= sizeof( int );
600: tempoff = sizes[ cbn ].om_off;
601: putlbracket( ftnno , -tempoff );
602: if ( tempoff < sizes[ cbn ].om_max ) {
603: sizes[ cbn ].om_max = tempoff;
604: }
605: putRV( 0 , cbn , tempoff , P2INT );
606: ap = stkrval( al[2] , NIL , RREQ );
607: putop( P2ASSIGN , P2INT );
608: putleaf( P2ICON , 0 , 0
609: , ADDTYPE( P2FTN | P2INT , P2PTR )
610: , "_MAX" );
611: putRV( 0 , cbn , tempoff , P2INT );
612: } else {
613: if (opt('t')
614: || typ == TSTR || typ == TDOUBLE) {
615: putleaf( P2ICON , 0 , 0
616: ,ADDTYPE( P2FTN | P2INT, P2PTR )
617: ,"_MAX" );
618: }
619: ap = stkrval( al[2] , NIL , RREQ );
620: }
621: if (ap == NIL)
622: continue;
623: if (isnta(ap,"i")) {
624: error("First write width must be integer, not %s", nameof(ap));
625: continue;
626: }
627: switch ( typ ) {
628: case TDOUBLE:
629: putleaf( P2ICON , 1 , 0 , P2INT , 0 );
630: putop( P2LISTOP , P2INT );
631: putleaf( P2ICON , 1 , 0 , P2INT , 0 );
632: putop( P2LISTOP , P2INT );
633: putop( P2CALL , P2INT );
634: if ( al[3] == NIL ) {
635: /*
636: * finish up the comma op
637: */
638: putop( P2COMOP , P2INT );
639: fmtspec &= ~VARPREC;
640: putop( P2LISTOP , P2INT );
641: putleaf( P2ICON , 0 , 0
642: , ADDTYPE( P2FTN | P2INT , P2PTR )
643: , "_MAX" );
644: putRV( 0 , cbn , tempoff , P2INT );
645: sizes[ cbn ].om_off += sizeof( int );
646: putleaf( P2ICON , 8 , 0 , P2INT , 0 );
647: putop( P2LISTOP , P2INT );
648: putleaf( P2ICON , 1 , 0 , P2INT , 0 );
649: putop( P2LISTOP , P2INT );
650: putop( P2CALL , P2INT );
651: }
652: putop( P2LISTOP , P2INT );
653: break;
654: case TSTR:
655: putleaf( P2ICON , strnglen , 0 , P2INT , 0 );
656: putop( P2LISTOP , P2INT );
657: putleaf( P2ICON , 0 , 0 , P2INT , 0 );
658: putop( P2LISTOP , P2INT );
659: putop( P2CALL , P2INT );
660: putop( P2COMOP , P2INT );
661: putop( P2LISTOP , P2INT );
662: break;
663: default:
664: if (opt('t')) {
665: putleaf( P2ICON , 0 , 0 , P2INT , 0 );
666: putop( P2LISTOP , P2INT );
667: putleaf( P2ICON , 0 , 0 , P2INT , 0 );
668: putop( P2LISTOP , P2INT );
669: putop( P2CALL , P2INT );
670: }
671: putop( P2LISTOP , P2INT );
672: break;
673: }
674: }
675: /*
676: * If there is a variable precision,
677: * evaluate it
678: */
679: if (fmtspec & VARPREC) {
680: if (opt('t')) {
681: putleaf( P2ICON , 0 , 0
682: , ADDTYPE( P2FTN | P2INT , P2PTR )
683: , "_MAX" );
684: }
685: ap = stkrval( al[3] , NIL , RREQ );
686: if (ap == NIL)
687: continue;
688: if (isnta(ap,"i")) {
689: error("Second write width must be integer, not %s", nameof(ap));
690: continue;
691: }
692: if (opt('t')) {
693: putleaf( P2ICON , 0 , 0 , P2INT , 0 );
694: putop( P2LISTOP , P2INT );
695: putleaf( P2ICON , 0 , 0 , P2INT , 0 );
696: putop( P2LISTOP , P2INT );
697: putop( P2CALL , P2INT );
698: }
699: putop( P2LISTOP , P2INT );
700: }
701: /*
702: * evaluate the thing we want printed.
703: */
704: switch ( typ ) {
705: case TCHAR:
706: case TINT:
707: stkrval( alv , NIL , RREQ );
708: putop( P2LISTOP , P2INT );
709: break;
710: case TDOUBLE:
711: ap = stkrval( alv , NIL , RREQ );
712: if ( isnta( ap , "d" ) ) {
713: putop( P2SCONV , P2DOUBLE );
714: }
715: putop( P2LISTOP , P2INT );
716: break;
717: case TSCAL:
718: case TBOOL:
719: putleaf( P2ICON , 0 , 0
720: , ADDTYPE( P2FTN | P2INT , P2PTR )
721: , "_NAM" );
722: ap = stkrval( alv , NIL , RREQ );
723: sprintf( format , PREFIXFORMAT , LABELPREFIX
724: , listnames( ap ) );
725: putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR
726: , format );
727: putop( P2LISTOP , P2INT );
728: putop( P2CALL , P2INT );
729: putop( P2LISTOP , P2INT );
730: break;
731: case TSTR:
732: putCONG( "" , 0 , LREQ );
733: putop( P2LISTOP , P2INT );
734: break;
735: }
736: putop( P2CALL , P2INT );
737: putdot( filename , line );
738: }
739: /*
740: * Write the string after its blank padding
741: */
742: if (typ == TSTR ) {
743: if ( opt( 't' ) ) {
744: putleaf( P2ICON , 0 , 0
745: , ADDTYPE( P2FTN | P2INT , P2PTR )
746: , "_WRITES" );
747: putRV( 0 , cbn , CURFILEOFFSET
748: , P2PTR|P2STRTY );
749: ap = stkrval(alv, NIL , RREQ );
750: putop( P2LISTOP , P2INT );
751: } else {
752: putleaf( P2ICON , 0 , 0
753: , ADDTYPE( P2FTN | P2INT , P2PTR )
754: , "_fwrite" );
755: ap = stkrval(alv, NIL , RREQ );
756: }
757: if (strfmt & VARWIDTH) {
758: /*
759: * min, inline expanded as
760: * temp < len ? temp : len
761: */
762: putRV( 0 , cbn , tempoff , P2INT );
763: putleaf( P2ICON , strnglen , 0 , P2INT , 0 );
764: putop( P2LT , P2INT );
765: putRV( 0 , cbn , tempoff , P2INT );
766: putleaf( P2ICON , strnglen , 0 , P2INT , 0 );
767: putop( P2COLON , P2INT );
768: putop( P2QUEST , P2INT );
769: } else {
770: if ( ( fmtspec & SKIP )
771: && ( strfmt & CONWIDTH ) ) {
772: strnglen = field;
773: }
774: putleaf( P2ICON , strnglen , 0 , P2INT , 0 );
775: }
776: putop( P2LISTOP , P2INT );
777: putleaf( P2ICON , 1 , 0 , P2INT , 0 );
778: putop( P2LISTOP , P2INT );
779: putleaf( P2ICON , 0 , 0
780: , ADDTYPE( P2FTN | P2INT , P2PTR )
781: , "_ACTFILE" );
782: putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY );
783: putop( P2CALL , P2INT );
784: putop( P2LISTOP , P2INT );
785: putop( P2CALL , P2INT );
786: putdot( filename , line );
787: }
788: }
789: /*
790: * Done with arguments.
791: * Handle writeln and
792: * insufficent number of args.
793: */
794: switch (p->value[0] &~ NSTAND) {
795: case O_WRITEF:
796: if (argc == 0)
797: error("Write requires an argument");
798: break;
799: case O_MESSAGE:
800: if (argc == 0)
801: error("Message requires an argument");
802: case O_WRITLN:
803: if (filetype != nl+T1CHAR)
804: error("Can't 'writeln' a non text file");
805: if ( opt( 't' ) ) {
806: putleaf( P2ICON , 0 , 0
807: , ADDTYPE( P2FTN | P2INT , P2PTR )
808: , "_WRITLN" );
809: putRV( 0 , cbn , CURFILEOFFSET
810: , P2PTR|P2STRTY );
811: } else {
812: putleaf( P2ICON , 0 , 0
813: , ADDTYPE( P2FTN | P2INT , P2PTR )
814: , "_fputc" );
815: putleaf( P2ICON , '\n' , 0 , P2CHAR , 0 );
816: putleaf( P2ICON , 0 , 0
817: , ADDTYPE( P2FTN | P2INT , P2PTR )
818: , "_ACTFILE" );
819: putRV( 0 , cbn , CURFILEOFFSET
820: , P2PTR|P2STRTY );
821: putop( P2CALL , P2INT );
822: putop( P2LISTOP , P2INT );
823: }
824: putop( P2CALL , P2INT );
825: putdot( filename , line );
826: break;
827: }
828: return;
829:
830: case O_READ4:
831: case O_READLN:
832: /*
833: * Set up default
834: * file "input".
835: */
836: file = NIL;
837: filetype = nl+T1CHAR;
838: /*
839: * Determine the file implied
840: * for the read and generate
841: * code to make it the active file.
842: */
843: if (argv != NIL) {
844: codeoff();
845: ap = stkrval(argv[1], NIL , RREQ );
846: codeon();
847: if (ap == NIL)
848: argv = argv[2];
849: if (ap != NIL && ap->class == FILET) {
850: /*
851: * Got "read(f, ...", make
852: * f the active file, and save
853: * it and its type for use in
854: * processing the rest of the
855: * arguments to read.
856: */
857: file = argv[1];
858: filetype = ap->type;
859: putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY );
860: putleaf( P2ICON , 0 , 0
861: , ADDTYPE( P2FTN | P2INT , P2PTR )
862: , "_UNIT" );
863: stklval(argv[1], NOFLAGS);
864: putop( P2CALL , P2INT );
865: putop( P2ASSIGN , P2PTR|P2STRTY );
866: putdot( filename , line );
867: argv = argv[2];
868: argc--;
869: } else {
870: /*
871: * Default is read from
872: * standard input.
873: */
874: putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY );
875: putLV( "_input" , 0 , 0 , P2PTR|P2STRTY );
876: putop( P2ASSIGN , P2PTR|P2STRTY );
877: putdot( filename , line );
878: input->nl_flags |= NUSED;
879: }
880: } else {
881: putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY );
882: putLV( "_input" , 0 , 0 , P2PTR|P2STRTY );
883: putop( P2ASSIGN , P2PTR|P2STRTY );
884: putdot( filename , line );
885: input->nl_flags |= NUSED;
886: }
887: /*
888: * Loop and process each
889: * of the arguments.
890: */
891: for (; argv != NIL; argv = argv[2]) {
892: /*
893: * Get the address of the target
894: * on the stack.
895: */
896: al = argv[1];
897: if (al == NIL)
898: continue;
899: if (al[0] != T_VAR) {
900: error("Arguments to %s must be variables, not expressions", p->symbol);
901: continue;
902: }
903: codeoff();
904: ap = stklval(al, MOD|ASGN|NOUSE);
905: codeon();
906: if (ap == NIL)
907: continue;
908: if (filetype != nl+T1CHAR) {
909: /*
910: * Generalized read, i.e.
911: * from a non-textfile.
912: */
913: if (incompat(filetype, ap, argv[1] )) {
914: error("Type mismatch in read from non-text file");
915: continue;
916: }
917: /*
918: * var := file ^;
919: */
920: ap = lvalue( al , MOD | ASGN | NOUSE , RREQ );
921: if ( isa( ap , "bsci" ) ) {
922: precheck( ap , "_RANG4" , "_RSNG4" );
923: }
924: putleaf( P2ICON , 0 , 0
925: , ADDTYPE(
926: ADDTYPE(
927: ADDTYPE(
928: p2type( filetype ) , P2PTR )
929: , P2FTN )
930: , P2PTR )
931: , "_FNIL" );
932: if (file != NIL)
933: stklval(file, NOFLAGS);
934: else /* Magic */
935: putRV( "_input" , 0 , 0
936: , P2PTR | P2STRTY );
937: putop( P2CALL , P2INT );
938: switch ( classify( filetype ) ) {
939: case TBOOL:
940: case TCHAR:
941: case TINT:
942: case TSCAL:
943: case TDOUBLE:
944: case TPTR:
945: putop( P2UNARY P2MUL
946: , p2type( filetype ) );
947: }
948: switch ( classify( filetype ) ) {
949: case TBOOL:
950: case TCHAR:
951: case TINT:
952: case TSCAL:
953: postcheck( ap );
954: /* and fall through */
955: case TDOUBLE:
956: case TPTR:
957: putop( P2ASSIGN , p2type( ap ) );
958: putdot( filename , line );
959: break;
960: default:
961: putstrop( P2STASG
962: , p2type( ap )
963: , lwidth( ap )
964: , align( ap ) );
965: putdot( filename , line );
966: break;
967: }
968: /*
969: * get(file);
970: */
971: putleaf( P2ICON , 0 , 0
972: , ADDTYPE( P2FTN | P2INT , P2PTR )
973: , "_GET" );
974: putRV( 0 , cbn , CURFILEOFFSET
975: , P2PTR|P2STRTY );
976: putop( P2CALL , P2INT );
977: putdot( filename , line );
978: continue;
979: }
980: /*
981: * if you get to here, you are reading from
982: * a text file. only possiblities are:
983: * character, integer, real, or scalar.
984: * read( f , foo , ... ) is done as
985: * foo := read( f ) with rangechecking
986: * if appropriate.
987: */
988: typ = classify(ap);
989: op = rdops(typ);
990: if (op == NIL) {
991: error("Can't read %ss from a text file", clnames[typ]);
992: continue;
993: }
994: /*
995: * left hand side of foo := read( f )
996: */
997: ap = lvalue( al , MOD|ASGN|NOUSE , RREQ );
998: if ( isa( ap , "bsci" ) ) {
999: precheck( ap , "_RANG4" , "_RSNG4" );
1000: }
1001: switch ( op ) {
1002: case O_READC:
1003: readname = "_READC";
1004: readtype = P2INT;
1005: break;
1006: case O_READ4:
1007: readname = "_READ4";
1008: readtype = P2INT;
1009: break;
1010: case O_READ8:
1011: readname = "_READ8";
1012: readtype = P2DOUBLE;
1013: break;
1014: case O_READE:
1015: readname = "_READE";
1016: readtype = P2INT;
1017: break;
1018: }
1019: putleaf( P2ICON , 0 , 0
1020: , ADDTYPE( P2FTN | readtype , P2PTR )
1021: , readname );
1022: putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY );
1023: if ( op == O_READE ) {
1024: sprintf( format , PREFIXFORMAT , LABELPREFIX
1025: , listnames( ap ) );
1026: putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR
1027: , format );
1028: putop( P2LISTOP , P2INT );
1029: warning();
1030: if (opt('s')) {
1031: standard();
1032: }
1033: error("Reading scalars from text files is non-standard");
1034: }
1035: putop( P2CALL , readtype );
1036: if ( isa( ap , "bcsi" ) ) {
1037: postcheck( ap );
1038: }
1039: putop( P2ASSIGN , p2type( ap ) );
1040: putdot( filename , line );
1041: }
1042: /*
1043: * Done with arguments.
1044: * Handle readln and
1045: * insufficient number of args.
1046: */
1047: if (p->value[0] == O_READLN) {
1048: if (filetype != nl+T1CHAR)
1049: error("Can't 'readln' a non text file");
1050: putleaf( P2ICON , 0 , 0
1051: , ADDTYPE( P2FTN | P2INT , P2PTR )
1052: , "_READLN" );
1053: putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY );
1054: putop( P2CALL , P2INT );
1055: putdot( filename , line );
1056: } else if (argc == 0)
1057: error("read requires an argument");
1058: return;
1059:
1060: case O_GET:
1061: case O_PUT:
1062: if (argc != 1) {
1063: error("%s expects one argument", p->symbol);
1064: return;
1065: }
1066: putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY );
1067: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1068: , "_UNIT" );
1069: ap = stklval(argv[1], NOFLAGS);
1070: if (ap == NIL)
1071: return;
1072: if (ap->class != FILET) {
1073: error("Argument to %s must be a file, not %s", p->symbol, nameof(ap));
1074: return;
1075: }
1076: putop( P2CALL , P2INT );
1077: putop( P2ASSIGN , P2PTR|P2STRTY );
1078: putdot( filename , line );
1079: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1080: , op == O_GET ? "_GET" : "_PUT" );
1081: putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY );
1082: putop( P2CALL , P2INT );
1083: putdot( filename , line );
1084: return;
1085:
1086: case O_RESET:
1087: case O_REWRITE:
1088: if (argc == 0 || argc > 2) {
1089: error("%s expects one or two arguments", p->symbol);
1090: return;
1091: }
1092: if (opt('s') && argc == 2) {
1093: standard();
1094: error("Two argument forms of reset and rewrite are non-standard");
1095: }
1096: putleaf( P2ICON , 0 , 0 , P2INT
1097: , op == O_RESET ? "_RESET" : "_REWRITE" );
1098: ap = stklval(argv[1], MOD|NOUSE);
1099: if (ap == NIL)
1100: return;
1101: if (ap->class != FILET) {
1102: error("First argument to %s must be a file, not %s", p->symbol, nameof(ap));
1103: return;
1104: }
1105: if (argc == 2) {
1106: /*
1107: * Optional second argument
1108: * is a string name of a
1109: * UNIX (R) file to be associated.
1110: */
1111: al = argv[2];
1112: al = stkrval(al[1], NOFLAGS , RREQ );
1113: if (al == NIL)
1114: return;
1115: if (classify(al) != TSTR) {
1116: error("Second argument to %s must be a string, not %s", p->symbol, nameof(al));
1117: return;
1118: }
1119: strnglen = width(al);
1120: } else {
1121: putleaf( P2ICON , 0 , 0 , P2INT , 0 );
1122: strnglen = 0;
1123: }
1124: putop( P2LISTOP , P2INT );
1125: putleaf( P2ICON , strnglen , 0 , P2INT , 0 );
1126: putop( P2LISTOP , P2INT );
1127: putleaf( P2ICON , text(ap) ? 0: width(ap->type) , 0 , P2INT , 0 );
1128: putop( P2LISTOP , P2INT );
1129: putop( P2CALL , P2INT );
1130: putdot( filename , line );
1131: return;
1132:
1133: case O_NEW:
1134: case O_DISPOSE:
1135: if (argc == 0) {
1136: error("%s expects at least one argument", p->symbol);
1137: return;
1138: }
1139: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1140: , op == O_DISPOSE ? "_DISPOSE" :
1141: opt('t') ? "_NEWZ" : "_NEW" );
1142: ap = stklval(argv[1], op == O_NEW ? ( MOD | NOUSE ) : MOD );
1143: if (ap == NIL)
1144: return;
1145: if (ap->class != PTR) {
1146: error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap));
1147: return;
1148: }
1149: ap = ap->type;
1150: if (ap == NIL)
1151: return;
1152: argv = argv[2];
1153: if (argv != NIL) {
1154: if (ap->class != RECORD) {
1155: error("Record required when specifying variant tags");
1156: return;
1157: }
1158: for (; argv != NIL; argv = argv[2]) {
1159: if (ap->ptr[NL_VARNT] == NIL) {
1160: error("Too many tag fields");
1161: return;
1162: }
1163: if (!isconst(argv[1])) {
1164: error("Second and successive arguments to %s must be constants", p->symbol);
1165: return;
1166: }
1167: gconst(argv[1]);
1168: if (con.ctype == NIL)
1169: return;
1170: if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) {
1171: cerror("Specified tag constant type clashed with variant case selector type");
1172: return;
1173: }
1174: for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain)
1175: if (ap->range[0] == con.crval)
1176: break;
1177: if (ap == NIL) {
1178: error("No variant case label value equals specified constant value");
1179: return;
1180: }
1181: ap = ap->ptr[NL_VTOREC];
1182: }
1183: }
1184: putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 );
1185: putop( P2LISTOP , P2INT );
1186: putop( P2CALL , P2INT );
1187: putdot( filename , line );
1188: return;
1189:
1190: case O_DATE:
1191: case O_TIME:
1192: if (argc != 1) {
1193: error("%s expects one argument", p->symbol);
1194: return;
1195: }
1196: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1197: , op == O_DATE ? "_DATE" : "_TIME" );
1198: ap = stklval(argv[1], MOD|NOUSE);
1199: if (ap == NIL)
1200: return;
1201: if (classify(ap) != TSTR || width(ap) != 10) {
1202: error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap));
1203: return;
1204: }
1205: putop( P2CALL , P2INT );
1206: putdot( filename , line );
1207: return;
1208:
1209: case O_HALT:
1210: if (argc != 0) {
1211: error("halt takes no arguments");
1212: return;
1213: }
1214: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1215: , "_HALT" );
1216:
1217: putop( P2UNARY P2CALL , P2INT );
1218: putdot( filename , line );
1219: noreach = 1;
1220: return;
1221:
1222: case O_ARGV:
1223: if (argc != 2) {
1224: error("argv takes two arguments");
1225: return;
1226: }
1227: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1228: , "_ARGV" );
1229: ap = stkrval(argv[1], NIL , RREQ );
1230: if (ap == NIL)
1231: return;
1232: if (isnta(ap, "i")) {
1233: error("argv's first argument must be an integer, not %s", nameof(ap));
1234: return;
1235: }
1236: al = argv[2];
1237: ap = stklval(al[1], MOD|NOUSE);
1238: if (ap == NIL)
1239: return;
1240: if (classify(ap) != TSTR) {
1241: error("argv's second argument must be a string, not %s", nameof(ap));
1242: return;
1243: }
1244: putop( P2LISTOP , P2INT );
1245: putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 );
1246: putop( P2LISTOP , P2INT );
1247: putop( P2CALL , P2INT );
1248: putdot( filename , line );
1249: return;
1250:
1251: case O_STLIM:
1252: if (argc != 1) {
1253: error("stlimit requires one argument");
1254: return;
1255: }
1256: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1257: , "_STLIM" );
1258: ap = stkrval(argv[1], NIL , RREQ );
1259: if (ap == NIL)
1260: return;
1261: if (isnta(ap, "i")) {
1262: error("stlimit's argument must be an integer, not %s", nameof(ap));
1263: return;
1264: }
1265: putop( P2CALL , P2INT );
1266: putdot( filename , line );
1267: return;
1268:
1269: case O_REMOVE:
1270: if (argc != 1) {
1271: error("remove expects one argument");
1272: return;
1273: }
1274: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1275: , "_REMOVE" );
1276: ap = stkrval(argv[1], NOFLAGS , RREQ );
1277: if (ap == NIL)
1278: return;
1279: if (classify(ap) != TSTR) {
1280: error("remove's argument must be a string, not %s", nameof(ap));
1281: return;
1282: }
1283: putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 );
1284: putop( P2LISTOP , P2INT );
1285: putop( P2CALL , P2INT );
1286: putdot( filename , line );
1287: return;
1288:
1289: case O_LLIMIT:
1290: if (argc != 2) {
1291: error("linelimit expects two arguments");
1292: return;
1293: }
1294: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1295: , "_LLIMIT" );
1296: ap = stklval(argv[1], NOFLAGS|NOUSE);
1297: if (ap == NIL)
1298: return;
1299: if (!text(ap)) {
1300: error("linelimit's first argument must be a text file, not %s", nameof(ap));
1301: return;
1302: }
1303: al = argv[2];
1304: ap = stkrval(al[1], NIL , RREQ );
1305: if (ap == NIL)
1306: return;
1307: if (isnta(ap, "i")) {
1308: error("linelimit's second argument must be an integer, not %s", nameof(ap));
1309: return;
1310: }
1311: putop( P2LISTOP , P2INT );
1312: putop( P2CALL , P2INT );
1313: putdot( filename , line );
1314: return;
1315: case O_PAGE:
1316: if (argc != 1) {
1317: error("page expects one argument");
1318: return;
1319: }
1320: putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY );
1321: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1322: , "_UNIT" );
1323: ap = stklval(argv[1], NOFLAGS);
1324: if (ap == NIL)
1325: return;
1326: if (!text(ap)) {
1327: error("Argument to page must be a text file, not %s", nameof(ap));
1328: return;
1329: }
1330: putop( P2CALL , P2INT );
1331: putop( P2ASSIGN , P2PTR|P2STRTY );
1332: putdot( filename , line );
1333: if ( opt( 't' ) ) {
1334: putleaf( P2ICON , 0 , 0
1335: , ADDTYPE( P2FTN | P2INT , P2PTR )
1336: , "_PAGE" );
1337: putRV( 0 , cbn , CURFILEOFFSET
1338: , P2PTR|P2STRTY );
1339: } else {
1340: putleaf( P2ICON , 0 , 0
1341: , ADDTYPE( P2FTN | P2INT , P2PTR )
1342: , "_fputc" );
1343: putleaf( P2ICON , '\f' , 0 , P2CHAR , 0 );
1344: putleaf( P2ICON , 0 , 0
1345: , ADDTYPE( P2FTN | P2INT , P2PTR )
1346: , "_ACTFILE" );
1347: putRV( 0 , cbn , CURFILEOFFSET
1348: , P2PTR|P2STRTY );
1349: putop( P2CALL , P2INT );
1350: putop( P2LISTOP , P2INT );
1351: }
1352: putop( P2CALL , P2INT );
1353: putdot( filename , line );
1354: return;
1355:
1356: case O_PACK:
1357: if (argc != 3) {
1358: error("pack expects three arguments");
1359: return;
1360: }
1361: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1362: , "_PACK" );
1363: pu = "pack(a,i,z)";
1364: pua = (al = argv)[1];
1365: pui = (al = al[2])[1];
1366: puz = (al = al[2])[1];
1367: goto packunp;
1368: case O_UNPACK:
1369: if (argc != 3) {
1370: error("unpack expects three arguments");
1371: return;
1372: }
1373: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1374: , "_UNPACK" );
1375: pu = "unpack(z,a,i)";
1376: puz = (al = argv)[1];
1377: pua = (al = al[2])[1];
1378: pui = (al = al[2])[1];
1379: packunp:
1380: ap = stkrval((int *) pui, NLNIL , RREQ );
1381: if (ap == NIL)
1382: return;
1383: ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE);
1384: if (ap == NIL)
1385: return;
1386: if (ap->class != ARRAY) {
1387: error("%s requires a to be an unpacked array, not %s", pu, nameof(ap));
1388: return;
1389: }
1390: putop( P2LISTOP , P2INT );
1391: al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE);
1392: if (al->class != ARRAY) {
1393: error("%s requires z to be a packed array, not %s", pu, nameof(ap));
1394: return;
1395: }
1396: if (al->type == NIL || ap->type == NIL)
1397: return;
1398: if (al->type != ap->type) {
1399: error("%s requires a and z to be arrays of the same type", pu, nameof(ap));
1400: return;
1401: }
1402: putop( P2LISTOP , P2INT );
1403: k = width(al);
1404: itemwidth = width(ap->type);
1405: ap = ap->chain;
1406: al = al->chain;
1407: if (ap->chain != NIL || al->chain != NIL) {
1408: error("%s requires a and z to be single dimension arrays", pu);
1409: return;
1410: }
1411: if (ap == NIL || al == NIL)
1412: return;
1413: /*
1414: * al is the range for z i.e. u..v
1415: * ap is the range for a i.e. m..n
1416: * i will be n-m+1
1417: * j will be v-u+1
1418: */
1419: i = ap->range[1] - ap->range[0] + 1;
1420: j = al->range[1] - al->range[0] + 1;
1421: if (i < j) {
1422: error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i);
1423: return;
1424: }
1425: /*
1426: * get n-m-(v-u) and m for the interpreter
1427: */
1428: i -= j;
1429: j = ap->range[0];
1430: putleaf( P2ICON , itemwidth , 0 , P2INT , 0 );
1431: putop( P2LISTOP , P2INT );
1432: putleaf( P2ICON , j , 0 , P2INT , 0 );
1433: putop( P2LISTOP , P2INT );
1434: putleaf( P2ICON , i , 0 , P2INT , 0 );
1435: putop( P2LISTOP , P2INT );
1436: putleaf( P2ICON , k , 0 , P2INT , 0 );
1437: putop( P2LISTOP , P2INT );
1438: putop( P2CALL , P2INT );
1439: putdot( filename , line );
1440: return;
1441: case 0:
1442: error("%s is an unimplemented 6400 extension", p->symbol);
1443: return;
1444:
1445: default:
1446: panic("proc case");
1447: }
1448: }
1449: #endif PC
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.