|
|
1.1 root 1: /* Copyright (c) 1979 Regents of the University of California */
2:
3: static char sccsid[] = "@(#)proc.c 1.3 10/28/80";
4:
5: #include "whoami.h"
6: #ifdef OBJ
7: /*
8: * and the rest of the file
9: */
10: #include "0.h"
11: #include "tree.h"
12: #include "opcode.h"
13: #include "objfmt.h"
14:
15: /*
16: * The following array is used to determine which classes may be read
17: * from textfiles. It is indexed by the return value from classify.
18: */
19: #define rdops(x) rdxxxx[(x)-(TFIRST)]
20:
21: int rdxxxx[] = {
22: 0, /* -7 file types */
23: 0, /* -6 record types */
24: 0, /* -5 array types */
25: O_READE, /* -4 scalar types */
26: 0, /* -3 pointer types */
27: 0, /* -2 set types */
28: 0, /* -1 string types */
29: 0, /* 0 nil, no type */
30: O_READE, /* 1 boolean */
31: O_READC, /* 2 character */
32: O_READ4, /* 3 integer */
33: O_READ8 /* 4 real */
34: };
35:
36: /*
37: * Proc handles procedure calls.
38: * Non-builtin procedures are "buck-passed" to func (with a flag
39: * indicating that they are actually procedures.
40: * builtin procedures are handled here.
41: */
42: proc(r)
43: int *r;
44: {
45: register struct nl *p;
46: register int *alv, *al, op;
47: struct nl *filetype, *ap;
48: int argc, *argv, typ, fmtspec, strfmt, stkcnt, *file;
49: char fmt, format[20], *strptr;
50: int prec, field, strnglen, fmtlen, fmtstart, pu;
51: int *pua, *pui, *puz;
52: int i, j, k;
53: int itemwidth;
54:
55: #define CONPREC 4
56: #define VARPREC 8
57: #define CONWIDTH 1
58: #define VARWIDTH 2
59: #define SKIP 16
60:
61: /*
62: * Verify that the name is
63: * defined and is that of a
64: * procedure.
65: */
66: p = lookup(r[2]);
67: if (p == NIL) {
68: rvlist(r[3]);
69: return;
70: }
71: if (p->class != PROC && p->class != FPROC) {
72: error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]);
73: rvlist(r[3]);
74: return;
75: }
76: argv = r[3];
77:
78: /*
79: * Call handles user defined
80: * procedures and functions.
81: */
82: if (bn != 0) {
83: call(p, argv, PROC, bn);
84: return;
85: }
86:
87: /*
88: * Call to built-in procedure.
89: * Count the arguments.
90: */
91: argc = 0;
92: for (al = argv; al != NIL; al = al[2])
93: argc++;
94:
95: /*
96: * Switch on the operator
97: * associated with the built-in
98: * procedure in the namelist
99: */
100: op = p->value[0] &~ NSTAND;
101: if (opt('s') && (p->value[0] & NSTAND)) {
102: standard();
103: error("%s is a nonstandard procedure", p->symbol);
104: }
105: switch (op) {
106:
107: case O_ABORT:
108: if (argc != 0)
109: error("null takes no arguments");
110: return;
111:
112: case O_FLUSH:
113: if (argc == 0) {
114: put(1, O_MESSAGE);
115: return;
116: }
117: if (argc != 1) {
118: error("flush takes at most one argument");
119: return;
120: }
121: ap = stkrval(argv[1], NIL , RREQ );
122: if (ap == NIL)
123: return;
124: if (ap->class != FILET) {
125: error("flush's argument must be a file, not %s", nameof(ap));
126: return;
127: }
128: put(1, op);
129: return;
130:
131: case O_MESSAGE:
132: case O_WRITEF:
133: case O_WRITLN:
134: /*
135: * Set up default file "output"'s type
136: */
137: file = NIL;
138: filetype = nl+T1CHAR;
139: /*
140: * Determine the file implied
141: * for the write and generate
142: * code to make it the active file.
143: */
144: if (op == O_MESSAGE) {
145: /*
146: * For message, all that matters
147: * is that the filetype is
148: * a character file.
149: * Thus "output" will suit us fine.
150: */
151: put(1, O_MESSAGE);
152: } else if (argv != NIL && (al = argv[1])[0] != T_WEXP) {
153: /*
154: * If there is a first argument which has
155: * no write widths, then it is potentially
156: * a file name.
157: */
158: codeoff();
159: ap = stkrval(argv[1], NIL , RREQ );
160: codeon();
161: if (ap == NIL)
162: argv = argv[2];
163: if (ap != NIL && ap->class == FILET) {
164: /*
165: * Got "write(f, ...", make
166: * f the active file, and save
167: * it and its type for use in
168: * processing the rest of the
169: * arguments to write.
170: */
171: file = argv[1];
172: filetype = ap->type;
173: stkrval(argv[1], NIL , RREQ );
174: put(1, O_UNIT);
175: /*
176: * Skip over the first argument
177: */
178: argv = argv[2];
179: argc--;
180: } else
181: /*
182: * Set up for writing on
183: * standard output.
184: */
185: put(1, O_UNITOUT);
186: } else
187: put(1, O_UNITOUT);
188: /*
189: * Loop and process each
190: * of the arguments.
191: */
192: for (; argv != NIL; argv = argv[2]) {
193: /*
194: * fmtspec indicates the type (CONstant or VARiable)
195: * and number (none, WIDTH, and/or PRECision)
196: * of the fields in the printf format for this
197: * output variable.
198: * stkcnt is the number of longs pushed on the stack
199: * fmt is the format output indicator (D, E, F, O, X, S)
200: * fmtstart = 0 for leading blank; = 1 for no blank
201: */
202: fmtspec = NIL;
203: stkcnt = 0;
204: fmt = 'D';
205: fmtstart = 1;
206: al = argv[1];
207: if (al == NIL)
208: continue;
209: if (al[0] == T_WEXP)
210: alv = al[1];
211: else
212: alv = al;
213: if (alv == NIL)
214: continue;
215: codeoff();
216: ap = stkrval(alv, NIL , RREQ );
217: codeon();
218: if (ap == NIL)
219: continue;
220: typ = classify(ap);
221: if (al[0] == T_WEXP) {
222: /*
223: * Handle width expressions.
224: * The basic game here is that width
225: * expressions get evaluated. If they
226: * are constant, the value is placed
227: * directly in the format string.
228: * Otherwise the value is pushed onto
229: * the stack and an indirection is
230: * put into the format string.
231: */
232: if (al[3] == OCT)
233: fmt = 'O';
234: else if (al[3] == HEX)
235: fmt = 'X';
236: else if (al[3] != NIL) {
237: /*
238: * Evaluate second format spec
239: */
240: if ( constval(al[3])
241: && isa( con.ctype , "i" ) ) {
242: fmtspec += CONPREC;
243: prec = con.crval;
244: } else {
245: fmtspec += VARPREC;
246: }
247: fmt = 'f';
248: switch ( typ ) {
249: case TINT:
250: if ( opt( 's' ) ) {
251: standard();
252: error("Writing %ss with two write widths is non-standard", clnames[typ]);
253: }
254: /* and fall through */
255: case TDOUBLE:
256: break;
257: default:
258: error("Cannot write %ss with two write widths", clnames[typ]);
259: continue;
260: }
261: }
262: /*
263: * Evaluate first format spec
264: */
265: if (al[2] != NIL) {
266: if ( constval(al[2])
267: && isa( con.ctype , "i" ) ) {
268: fmtspec += CONWIDTH;
269: field = con.crval;
270: } else {
271: fmtspec += VARWIDTH;
272: }
273: }
274: if ((fmtspec & CONPREC) && prec < 0 ||
275: (fmtspec & CONWIDTH) && field < 0) {
276: error("Negative widths are not allowed");
277: continue;
278: }
279: }
280: if (filetype != nl+T1CHAR) {
281: if (fmt == 'O' || fmt == 'X') {
282: error("Oct/hex allowed only on text files");
283: continue;
284: }
285: if (fmtspec) {
286: error("Write widths allowed only on text files");
287: continue;
288: }
289: /*
290: * Generalized write, i.e.
291: * to a non-textfile.
292: */
293: stkrval(file, NIL , RREQ );
294: put(1, O_FNIL);
295: /*
296: * file^ := ...
297: */
298: ap = rvalue(argv[1], NIL);
299: if (ap == NIL)
300: continue;
301: if (incompat(ap, filetype, argv[1])) {
302: cerror("Type mismatch in write to non-text file");
303: continue;
304: }
305: convert(ap, filetype);
306: put(2, O_AS, width(filetype));
307: /*
308: * put(file)
309: */
310: put(1, O_PUT);
311: continue;
312: }
313: /*
314: * Write to a textfile
315: *
316: * Evaluate the expression
317: * to be written.
318: */
319: if (fmt == 'O' || fmt == 'X') {
320: if (opt('s')) {
321: standard();
322: error("Oct and hex are non-standard");
323: }
324: if (typ == TSTR || typ == TDOUBLE) {
325: error("Can't write %ss with oct/hex", clnames[typ]);
326: continue;
327: }
328: if (typ == TCHAR || typ == TBOOL)
329: typ = TINT;
330: }
331: /*
332: * Place the arguement on the stack. If there is
333: * no format specified by the programmer, implement
334: * the default.
335: */
336: switch (typ) {
337: case TINT:
338: if (fmt != 'f') {
339: ap = stkrval(alv, NIL , RREQ );
340: stkcnt++;
341: } else {
342: ap = stkrval(alv, NIL , RREQ );
343: put(1, O_ITOD);
344: stkcnt += 2;
345: typ = TDOUBLE;
346: goto tdouble;
347: }
348: if (fmtspec == NIL) {
349: if (fmt == 'D')
350: field = 10;
351: else if (fmt == 'X')
352: field = 8;
353: else if (fmt == 'O')
354: field = 11;
355: else
356: panic("fmt1");
357: fmtspec = CONWIDTH;
358: }
359: break;
360: case TCHAR:
361: tchar:
362: ap = stkrval(alv, NIL , RREQ );
363: stkcnt++;
364: fmt = 'c';
365: break;
366: case TSCAL:
367: warning();
368: if (opt('s')) {
369: standard();
370: }
371: error("Writing scalars to text files is non-standard");
372: case TBOOL:
373: stkrval(alv, NIL , RREQ );
374: put(2, O_NAM, listnames(ap));
375: stkcnt++;
376: fmt = 's';
377: break;
378: case TDOUBLE:
379: ap = stkrval(alv, TDOUBLE , RREQ );
380: stkcnt += 2;
381: tdouble:
382: switch (fmtspec) {
383: case NIL:
384: field = 21;
385: prec = 14;
386: fmt = 'E';
387: fmtspec = CONWIDTH + CONPREC;
388: break;
389: case CONWIDTH:
390: if (--field < 1)
391: field = 1;
392: prec = field - 7;
393: if (prec < 1)
394: prec = 1;
395: fmtspec += CONPREC;
396: fmt = 'E';
397: break;
398: case CONWIDTH + CONPREC:
399: case CONWIDTH + VARPREC:
400: if (--field < 1)
401: field = 1;
402: }
403: format[0] = ' ';
404: fmtstart = 0;
405: break;
406: case TSTR:
407: constval( alv );
408: switch ( classify( con.ctype ) ) {
409: case TCHAR:
410: typ = TCHAR;
411: goto tchar;
412: case TSTR:
413: strptr = con.cpval;
414: for (strnglen = 0; *strptr++; strnglen++) /* void */;
415: strptr = con.cpval;
416: break;
417: default:
418: strnglen = width(ap);
419: break;
420: }
421: fmt = 's';
422: strfmt = fmtspec;
423: if (fmtspec == NIL) {
424: fmtspec = SKIP;
425: break;
426: }
427: if (fmtspec & CONWIDTH) {
428: if (field <= strnglen) {
429: fmtspec = SKIP;
430: break;
431: } else
432: field -= strnglen;
433: }
434: /*
435: * push string to implement leading blank padding
436: */
437: put(2, O_LVCON, 2);
438: putstr("", 0);
439: stkcnt++;
440: break;
441: default:
442: error("Can't write %ss to a text file", clnames[typ]);
443: continue;
444: }
445: /*
446: * If there is a variable precision, evaluate it onto
447: * the stack
448: */
449: if (fmtspec & VARPREC) {
450: ap = stkrval(al[3], NIL , RREQ );
451: if (ap == NIL)
452: continue;
453: if (isnta(ap,"i")) {
454: error("Second write width must be integer, not %s", nameof(ap));
455: continue;
456: }
457: if ( opt( 't' ) ) {
458: put(3, O_MAX, 0, 0);
459: }
460: stkcnt++;
461: }
462: /*
463: * If there is a variable width, evaluate it onto
464: * the stack
465: */
466: if (fmtspec & VARWIDTH) {
467: if ( ( typ == TDOUBLE && fmtspec == VARWIDTH )
468: || typ == TSTR ) {
469: i = sizes[cbn].om_off -= sizeof(int);
470: if (i < sizes[cbn].om_max)
471: sizes[cbn].om_max = i;
472: put(2, O_LV | cbn << 8 + INDX, i);
473: }
474: ap = stkrval(al[2], NIL , RREQ );
475: if (ap == NIL)
476: continue;
477: if (isnta(ap,"i")) {
478: error("First write width must be integer, not %s", nameof(ap));
479: continue;
480: }
481: stkcnt++;
482: /*
483: * Perform special processing on widths based
484: * on data type
485: */
486: switch (typ) {
487: case TDOUBLE:
488: if (fmtspec == VARWIDTH) {
489: fmt = 'E';
490: put(1, O_AS4);
491: put(2, O_RV4 | cbn << 8 + INDX, i);
492: put(3, O_MAX, 8, 1);
493: put(2, O_RV4 | cbn << 8 + INDX, i);
494: stkcnt++;
495: fmtspec += VARPREC;
496: }
497: put(3, O_MAX, 1, 1);
498: break;
499: case TSTR:
500: put(1, O_AS4);
501: put(2, O_RV4 | cbn << 8 + INDX, i);
502: put(3, O_MAX, strnglen, 0);
503: break;
504: default:
505: if ( opt( 't' ) ) {
506: put(3, O_MAX, 0, 0);
507: }
508: break;
509: }
510: }
511: /*
512: * Generate the format string
513: */
514: switch (fmtspec) {
515: default:
516: panic("fmt2");
517: case NIL:
518: if (fmt == 'c')
519: put(1, O_WRITEC);
520: else {
521: sprintf(&format[1], "%%%c", fmt);
522: goto fmtgen;
523: }
524: case SKIP:
525: break;
526: case CONWIDTH:
527: sprintf(&format[1], "%%%1D%c", field, fmt);
528: goto fmtgen;
529: case VARWIDTH:
530: sprintf(&format[1], "%%*%c", fmt);
531: goto fmtgen;
532: case CONWIDTH + CONPREC:
533: sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt);
534: goto fmtgen;
535: case CONWIDTH + VARPREC:
536: sprintf(&format[1], "%%%1D.*%c", field, fmt);
537: goto fmtgen;
538: case VARWIDTH + CONPREC:
539: sprintf(&format[1], "%%*.%1D%c", prec, fmt);
540: goto fmtgen;
541: case VARWIDTH + VARPREC:
542: sprintf(&format[1], "%%*.*%c", fmt);
543: fmtgen:
544: fmtlen = lenstr(&format[fmtstart], 0);
545: put(2, O_LVCON, fmtlen);
546: putstr(&format[fmtstart], 0);
547: put(1, O_FILE);
548: stkcnt += 2;
549: put(2, O_WRITEF, stkcnt);
550: }
551: /*
552: * Write the string after its blank padding
553: */
554: if (typ == TSTR) {
555: put(1, O_FILE);
556: put(2, O_CON24, 1);
557: if (strfmt & VARWIDTH) {
558: put(2, O_RV4 | cbn << 8 + INDX , i );
559: put(2, O_MIN, strnglen);
560: } else {
561: if ((fmtspec & SKIP) &&
562: (strfmt & CONWIDTH)) {
563: strnglen = field;
564: }
565: put(2, O_CON24, strnglen);
566: }
567: ap = stkrval(alv, NIL , RREQ );
568: put(1, O_WRITES);
569: }
570: }
571: /*
572: * Done with arguments.
573: * Handle writeln and
574: * insufficent number of args.
575: */
576: switch (p->value[0] &~ NSTAND) {
577: case O_WRITEF:
578: if (argc == 0)
579: error("Write requires an argument");
580: break;
581: case O_MESSAGE:
582: if (argc == 0)
583: error("Message requires an argument");
584: case O_WRITLN:
585: if (filetype != nl+T1CHAR)
586: error("Can't 'writeln' a non text file");
587: put(1, O_WRITLN);
588: break;
589: }
590: return;
591:
592: case O_READ4:
593: case O_READLN:
594: /*
595: * Set up default
596: * file "input".
597: */
598: file = NIL;
599: filetype = nl+T1CHAR;
600: /*
601: * Determine the file implied
602: * for the read and generate
603: * code to make it the active file.
604: */
605: if (argv != NIL) {
606: codeoff();
607: ap = stkrval(argv[1], NIL , RREQ );
608: codeon();
609: if (ap == NIL)
610: argv = argv[2];
611: if (ap != NIL && ap->class == FILET) {
612: /*
613: * Got "read(f, ...", make
614: * f the active file, and save
615: * it and its type for use in
616: * processing the rest of the
617: * arguments to read.
618: */
619: file = argv[1];
620: filetype = ap->type;
621: stkrval(argv[1], NIL , RREQ );
622: put(1, O_UNIT);
623: argv = argv[2];
624: argc--;
625: } else {
626: /*
627: * Default is read from
628: * standard input.
629: */
630: put(1, O_UNITINP);
631: input->nl_flags |= NUSED;
632: }
633: } else {
634: put(1, O_UNITINP);
635: input->nl_flags |= NUSED;
636: }
637: /*
638: * Loop and process each
639: * of the arguments.
640: */
641: for (; argv != NIL; argv = argv[2]) {
642: /*
643: * Get the address of the target
644: * on the stack.
645: */
646: al = argv[1];
647: if (al == NIL)
648: continue;
649: if (al[0] != T_VAR) {
650: error("Arguments to %s must be variables, not expressions", p->symbol);
651: continue;
652: }
653: ap = stklval(al, MOD|ASGN|NOUSE);
654: if (ap == NIL)
655: continue;
656: if (filetype != nl+T1CHAR) {
657: /*
658: * Generalized read, i.e.
659: * from a non-textfile.
660: */
661: if (incompat(filetype, ap, argv[1] )) {
662: error("Type mismatch in read from non-text file");
663: continue;
664: }
665: /*
666: * var := file ^;
667: */
668: if (file != NIL)
669: stkrval(file, NIL , RREQ );
670: else /* Magic */
671: put(2, O_RV2, input->value[0]);
672: put(1, O_FNIL);
673: put(2, O_IND, width(filetype));
674: convert(filetype, ap);
675: if (isa(ap, "bsci"))
676: rangechk(ap, ap);
677: put(2, O_AS, width(ap));
678: /*
679: * get(file);
680: */
681: put(1, O_GET);
682: continue;
683: }
684: typ = classify(ap);
685: op = rdops(typ);
686: if (op == NIL) {
687: error("Can't read %ss from a text file", clnames[typ]);
688: continue;
689: }
690: if (op != O_READE)
691: put(1, op);
692: else {
693: put(2, op, listnames(ap));
694: warning();
695: if (opt('s')) {
696: standard();
697: }
698: error("Reading scalars from text files is non-standard");
699: }
700: /*
701: * Data read is on the stack.
702: * Assign it.
703: */
704: if (op != O_READ8 && op != O_READE)
705: rangechk(ap, op == O_READC ? ap : nl+T4INT);
706: gen(O_AS2, O_AS2, width(ap),
707: op == O_READ8 ? 8 : op == O_READ4 ? 4 : 2);
708: }
709: /*
710: * Done with arguments.
711: * Handle readln and
712: * insufficient number of args.
713: */
714: if (p->value[0] == O_READLN) {
715: if (filetype != nl+T1CHAR)
716: error("Can't 'readln' a non text file");
717: put(1, O_READLN);
718: }
719: else if (argc == 0)
720: error("read requires an argument");
721: return;
722:
723: case O_GET:
724: case O_PUT:
725: if (argc != 1) {
726: error("%s expects one argument", p->symbol);
727: return;
728: }
729: ap = stkrval(argv[1], NIL , RREQ );
730: if (ap == NIL)
731: return;
732: if (ap->class != FILET) {
733: error("Argument to %s must be a file, not %s", p->symbol, nameof(ap));
734: return;
735: }
736: put(1, O_UNIT);
737: put(1, op);
738: return;
739:
740: case O_RESET:
741: case O_REWRITE:
742: if (argc == 0 || argc > 2) {
743: error("%s expects one or two arguments", p->symbol);
744: return;
745: }
746: if (opt('s') && argc == 2) {
747: standard();
748: error("Two argument forms of reset and rewrite are non-standard");
749: }
750: ap = stklval(argv[1], MOD|NOUSE);
751: if (ap == NIL)
752: return;
753: if (ap->class != FILET) {
754: error("First argument to %s must be a file, not %s", p->symbol, nameof(ap));
755: return;
756: }
757: if (argc == 2) {
758: /*
759: * Optional second argument
760: * is a string name of a
761: * UNIX (R) file to be associated.
762: */
763: al = argv[2];
764: al = stkrval(al[1], NOFLAGS , RREQ );
765: if (al == NIL)
766: return;
767: if (classify(al) != TSTR) {
768: error("Second argument to %s must be a string, not %s", p->symbol, nameof(al));
769: return;
770: }
771: strnglen = width(al);
772: } else {
773: put(2, O_CON24, NIL);
774: strnglen = 0;
775: }
776: put(2, O_CON24, strnglen);
777: put(2, O_CON24, text(ap) ? 0: width(ap->type));
778: put(1, op);
779: return;
780:
781: case O_NEW:
782: case O_DISPOSE:
783: if (argc == 0) {
784: error("%s expects at least one argument", p->symbol);
785: return;
786: }
787: ap = stklval(argv[1], op == O_NEW ? ( MOD | NOUSE ) : MOD );
788: if (ap == NIL)
789: return;
790: if (ap->class != PTR) {
791: error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap));
792: return;
793: }
794: ap = ap->type;
795: if (ap == NIL)
796: return;
797: argv = argv[2];
798: if (argv != NIL) {
799: if (ap->class != RECORD) {
800: error("Record required when specifying variant tags");
801: return;
802: }
803: for (; argv != NIL; argv = argv[2]) {
804: if (ap->ptr[NL_VARNT] == NIL) {
805: error("Too many tag fields");
806: return;
807: }
808: if (!isconst(argv[1])) {
809: error("Second and successive arguments to %s must be constants", p->symbol);
810: return;
811: }
812: gconst(argv[1]);
813: if (con.ctype == NIL)
814: return;
815: if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) {
816: cerror("Specified tag constant type clashed with variant case selector type");
817: return;
818: }
819: for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain)
820: if (ap->range[0] == con.crval)
821: break;
822: if (ap == NIL) {
823: error("No variant case label value equals specified constant value");
824: return;
825: }
826: ap = ap->ptr[NL_VTOREC];
827: }
828: }
829: put(2, op, width(ap));
830: return;
831:
832: case O_DATE:
833: case O_TIME:
834: if (argc != 1) {
835: error("%s expects one argument", p->symbol);
836: return;
837: }
838: ap = stklval(argv[1], MOD|NOUSE);
839: if (ap == NIL)
840: return;
841: if (classify(ap) != TSTR || width(ap) != 10) {
842: error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap));
843: return;
844: }
845: put(1, op);
846: return;
847:
848: case O_HALT:
849: if (argc != 0) {
850: error("halt takes no arguments");
851: return;
852: }
853: put(1, op);
854: noreach = 1;
855: return;
856:
857: case O_ARGV:
858: if (argc != 2) {
859: error("argv takes two arguments");
860: return;
861: }
862: ap = stkrval(argv[1], NIL , RREQ );
863: if (ap == NIL)
864: return;
865: if (isnta(ap, "i")) {
866: error("argv's first argument must be an integer, not %s", nameof(ap));
867: return;
868: }
869: al = argv[2];
870: ap = stklval(al[1], MOD|NOUSE);
871: if (ap == NIL)
872: return;
873: if (classify(ap) != TSTR) {
874: error("argv's second argument must be a string, not %s", nameof(ap));
875: return;
876: }
877: put(2, op, width(ap));
878: return;
879:
880: case O_STLIM:
881: if (argc != 1) {
882: error("stlimit requires one argument");
883: return;
884: }
885: ap = stkrval(argv[1], NIL , RREQ );
886: if (ap == NIL)
887: return;
888: if (isnta(ap, "i")) {
889: error("stlimit's argument must be an integer, not %s", nameof(ap));
890: return;
891: }
892: if (width(ap) != 4)
893: put(1, O_STOI);
894: put(1, op);
895: return;
896:
897: case O_REMOVE:
898: if (argc != 1) {
899: error("remove expects one argument");
900: return;
901: }
902: ap = stkrval(argv[1], NOFLAGS , RREQ );
903: if (ap == NIL)
904: return;
905: if (classify(ap) != TSTR) {
906: error("remove's argument must be a string, not %s", nameof(ap));
907: return;
908: }
909: put(2, O_CON24, width(ap));
910: put(1, op);
911: return;
912:
913: case O_LLIMIT:
914: if (argc != 2) {
915: error("linelimit expects two arguments");
916: return;
917: }
918: ap = stklval(argv[1], NOFLAGS|NOUSE);
919: if (ap == NIL)
920: return;
921: if (!text(ap)) {
922: error("linelimit's first argument must be a text file, not %s", nameof(ap));
923: return;
924: }
925: al = argv[2];
926: ap = stkrval(al[1], NIL , RREQ );
927: if (ap == NIL)
928: return;
929: if (isnta(ap, "i")) {
930: error("linelimit's second argument must be an integer, not %s", nameof(ap));
931: return;
932: }
933: put(1, op);
934: return;
935: case O_PAGE:
936: if (argc != 1) {
937: error("page expects one argument");
938: return;
939: }
940: ap = stkrval(argv[1], NIL , RREQ );
941: if (ap == NIL)
942: return;
943: if (!text(ap)) {
944: error("Argument to page must be a text file, not %s", nameof(ap));
945: return;
946: }
947: put(1, O_UNIT);
948: put(1, op);
949: return;
950:
951: case O_PACK:
952: if (argc != 3) {
953: error("pack expects three arguments");
954: return;
955: }
956: pu = "pack(a,i,z)";
957: pua = (al = argv)[1];
958: pui = (al = al[2])[1];
959: puz = (al = al[2])[1];
960: goto packunp;
961: case O_UNPACK:
962: if (argc != 3) {
963: error("unpack expects three arguments");
964: return;
965: }
966: pu = "unpack(z,a,i)";
967: puz = (al = argv)[1];
968: pua = (al = al[2])[1];
969: pui = (al = al[2])[1];
970: packunp:
971: ap = stkrval((int *) pui, NLNIL , RREQ );
972: if (ap == NIL)
973: return;
974: ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE);
975: if (ap == NIL)
976: return;
977: if (ap->class != ARRAY) {
978: error("%s requires a to be an unpacked array, not %s", pu, nameof(ap));
979: return;
980: }
981: al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE);
982: if (al->class != ARRAY) {
983: error("%s requires z to be a packed array, not %s", pu, nameof(ap));
984: return;
985: }
986: if (al->type == NIL || ap->type == NIL)
987: return;
988: if (al->type != ap->type) {
989: error("%s requires a and z to be arrays of the same type", pu, nameof(ap));
990: return;
991: }
992: k = width(al);
993: itemwidth = width(ap->type);
994: ap = ap->chain;
995: al = al->chain;
996: if (ap->chain != NIL || al->chain != NIL) {
997: error("%s requires a and z to be single dimension arrays", pu);
998: return;
999: }
1000: if (ap == NIL || al == NIL)
1001: return;
1002: /*
1003: * al is the range for z i.e. u..v
1004: * ap is the range for a i.e. m..n
1005: * i will be n-m+1
1006: * j will be v-u+1
1007: */
1008: i = ap->range[1] - ap->range[0] + 1;
1009: j = al->range[1] - al->range[0] + 1;
1010: if (i < j) {
1011: error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i);
1012: return;
1013: }
1014: /*
1015: * get n-m-(v-u) and m for the interpreter
1016: */
1017: i -= j;
1018: j = ap->range[0];
1019: put(5, op, itemwidth , j, i, k);
1020: return;
1021: case 0:
1022: error("%s is an unimplemented 6400 extension", p->symbol);
1023: return;
1024:
1025: default:
1026: panic("proc case");
1027: }
1028: }
1029: #endif OBJ
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.