1768Speter /* Copyright (c) 1979 Regents of the University of California */ 2768Speter 3*3226Smckusic static char sccsid[] = "@(#)proc.c 1.8 03/11/81"; 4768Speter 5768Speter #include "whoami.h" 6768Speter #ifdef OBJ 7768Speter /* 8768Speter * and the rest of the file 9768Speter */ 10768Speter #include "0.h" 11768Speter #include "tree.h" 12768Speter #include "opcode.h" 13768Speter #include "objfmt.h" 14768Speter 15768Speter /* 16768Speter * The following array is used to determine which classes may be read 17768Speter * from textfiles. It is indexed by the return value from classify. 18768Speter */ 19768Speter #define rdops(x) rdxxxx[(x)-(TFIRST)] 20768Speter 21768Speter int rdxxxx[] = { 22768Speter 0, /* -7 file types */ 23768Speter 0, /* -6 record types */ 24768Speter 0, /* -5 array types */ 25768Speter O_READE, /* -4 scalar types */ 26768Speter 0, /* -3 pointer types */ 27768Speter 0, /* -2 set types */ 28768Speter 0, /* -1 string types */ 29768Speter 0, /* 0 nil, no type */ 30768Speter O_READE, /* 1 boolean */ 31768Speter O_READC, /* 2 character */ 32768Speter O_READ4, /* 3 integer */ 33768Speter O_READ8 /* 4 real */ 34768Speter }; 35768Speter 36768Speter /* 37768Speter * Proc handles procedure calls. 38768Speter * Non-builtin procedures are "buck-passed" to func (with a flag 39768Speter * indicating that they are actually procedures. 40768Speter * builtin procedures are handled here. 41768Speter */ 42768Speter proc(r) 43768Speter int *r; 44768Speter { 45768Speter register struct nl *p; 46768Speter register int *alv, *al, op; 47768Speter struct nl *filetype, *ap; 48768Speter int argc, *argv, typ, fmtspec, strfmt, stkcnt, *file; 49768Speter char fmt, format[20], *strptr; 50768Speter int prec, field, strnglen, fmtlen, fmtstart, pu; 51768Speter int *pua, *pui, *puz; 52768Speter int i, j, k; 53768Speter int itemwidth; 54*3226Smckusic struct tmps soffset; 55768Speter 56768Speter #define CONPREC 4 57768Speter #define VARPREC 8 58768Speter #define CONWIDTH 1 59768Speter #define VARWIDTH 2 60768Speter #define SKIP 16 61768Speter 62768Speter /* 63768Speter * Verify that the name is 64768Speter * defined and is that of a 65768Speter * procedure. 66768Speter */ 67768Speter p = lookup(r[2]); 68768Speter if (p == NIL) { 69768Speter rvlist(r[3]); 70768Speter return; 71768Speter } 721198Speter if (p->class != PROC && p->class != FPROC) { 73768Speter error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]); 74768Speter rvlist(r[3]); 75768Speter return; 76768Speter } 77768Speter argv = r[3]; 78768Speter 79768Speter /* 80768Speter * Call handles user defined 81768Speter * procedures and functions. 82768Speter */ 83768Speter if (bn != 0) { 84768Speter call(p, argv, PROC, bn); 85768Speter return; 86768Speter } 87768Speter 88768Speter /* 89768Speter * Call to built-in procedure. 90768Speter * Count the arguments. 91768Speter */ 92768Speter argc = 0; 93768Speter for (al = argv; al != NIL; al = al[2]) 94768Speter argc++; 95768Speter 96768Speter /* 97768Speter * Switch on the operator 98768Speter * associated with the built-in 99768Speter * procedure in the namelist 100768Speter */ 101768Speter op = p->value[0] &~ NSTAND; 102768Speter if (opt('s') && (p->value[0] & NSTAND)) { 103768Speter standard(); 104768Speter error("%s is a nonstandard procedure", p->symbol); 105768Speter } 106768Speter switch (op) { 107768Speter 108768Speter case O_ABORT: 109768Speter if (argc != 0) 110768Speter error("null takes no arguments"); 111768Speter return; 112768Speter 113768Speter case O_FLUSH: 114768Speter if (argc == 0) { 115768Speter put(1, O_MESSAGE); 116768Speter return; 117768Speter } 118768Speter if (argc != 1) { 119768Speter error("flush takes at most one argument"); 120768Speter return; 121768Speter } 1222073Smckusic ap = stklval(argv[1], NIL , LREQ ); 123768Speter if (ap == NIL) 124768Speter return; 125768Speter if (ap->class != FILET) { 126768Speter error("flush's argument must be a file, not %s", nameof(ap)); 127768Speter return; 128768Speter } 129768Speter put(1, op); 130768Speter return; 131768Speter 132768Speter case O_MESSAGE: 133768Speter case O_WRITEF: 134768Speter case O_WRITLN: 135768Speter /* 136768Speter * Set up default file "output"'s type 137768Speter */ 138768Speter file = NIL; 139768Speter filetype = nl+T1CHAR; 140768Speter /* 141768Speter * Determine the file implied 142768Speter * for the write and generate 143768Speter * code to make it the active file. 144768Speter */ 145768Speter if (op == O_MESSAGE) { 146768Speter /* 147768Speter * For message, all that matters 148768Speter * is that the filetype is 149768Speter * a character file. 150768Speter * Thus "output" will suit us fine. 151768Speter */ 152768Speter put(1, O_MESSAGE); 153768Speter } else if (argv != NIL && (al = argv[1])[0] != T_WEXP) { 154768Speter /* 155768Speter * If there is a first argument which has 156768Speter * no write widths, then it is potentially 157768Speter * a file name. 158768Speter */ 159768Speter codeoff(); 160768Speter ap = stkrval(argv[1], NIL , RREQ ); 161768Speter codeon(); 162768Speter if (ap == NIL) 163768Speter argv = argv[2]; 164768Speter if (ap != NIL && ap->class == FILET) { 165768Speter /* 166768Speter * Got "write(f, ...", make 167768Speter * f the active file, and save 168768Speter * it and its type for use in 169768Speter * processing the rest of the 170768Speter * arguments to write. 171768Speter */ 172768Speter file = argv[1]; 173768Speter filetype = ap->type; 1742073Smckusic stklval(argv[1], NIL , LREQ ); 175768Speter put(1, O_UNIT); 176768Speter /* 177768Speter * Skip over the first argument 178768Speter */ 179768Speter argv = argv[2]; 180768Speter argc--; 181768Speter } else 182768Speter /* 183768Speter * Set up for writing on 184768Speter * standard output. 185768Speter */ 186768Speter put(1, O_UNITOUT); 187768Speter } else 188768Speter put(1, O_UNITOUT); 189768Speter /* 190768Speter * Loop and process each 191768Speter * of the arguments. 192768Speter */ 193768Speter for (; argv != NIL; argv = argv[2]) { 194768Speter /* 195768Speter * fmtspec indicates the type (CONstant or VARiable) 196768Speter * and number (none, WIDTH, and/or PRECision) 197768Speter * of the fields in the printf format for this 198768Speter * output variable. 1993172Smckusic * stkcnt is the number of bytes pushed on the stack 200768Speter * fmt is the format output indicator (D, E, F, O, X, S) 201768Speter * fmtstart = 0 for leading blank; = 1 for no blank 202768Speter */ 203768Speter fmtspec = NIL; 204768Speter stkcnt = 0; 205768Speter fmt = 'D'; 206768Speter fmtstart = 1; 207768Speter al = argv[1]; 208768Speter if (al == NIL) 209768Speter continue; 210768Speter if (al[0] == T_WEXP) 211768Speter alv = al[1]; 212768Speter else 213768Speter alv = al; 214768Speter if (alv == NIL) 215768Speter continue; 216768Speter codeoff(); 217768Speter ap = stkrval(alv, NIL , RREQ ); 218768Speter codeon(); 219768Speter if (ap == NIL) 220768Speter continue; 221768Speter typ = classify(ap); 222768Speter if (al[0] == T_WEXP) { 223768Speter /* 224768Speter * Handle width expressions. 225768Speter * The basic game here is that width 226768Speter * expressions get evaluated. If they 227768Speter * are constant, the value is placed 228768Speter * directly in the format string. 229768Speter * Otherwise the value is pushed onto 230768Speter * the stack and an indirection is 231768Speter * put into the format string. 232768Speter */ 233768Speter if (al[3] == OCT) 234768Speter fmt = 'O'; 235768Speter else if (al[3] == HEX) 236768Speter fmt = 'X'; 237768Speter else if (al[3] != NIL) { 238768Speter /* 239768Speter * Evaluate second format spec 240768Speter */ 241768Speter if ( constval(al[3]) 242768Speter && isa( con.ctype , "i" ) ) { 243768Speter fmtspec += CONPREC; 244768Speter prec = con.crval; 245768Speter } else { 246768Speter fmtspec += VARPREC; 247768Speter } 248768Speter fmt = 'f'; 249768Speter switch ( typ ) { 250768Speter case TINT: 251768Speter if ( opt( 's' ) ) { 252768Speter standard(); 253768Speter error("Writing %ss with two write widths is non-standard", clnames[typ]); 254768Speter } 255768Speter /* and fall through */ 256768Speter case TDOUBLE: 257768Speter break; 258768Speter default: 259768Speter error("Cannot write %ss with two write widths", clnames[typ]); 260768Speter continue; 261768Speter } 262768Speter } 263768Speter /* 264768Speter * Evaluate first format spec 265768Speter */ 266768Speter if (al[2] != NIL) { 267768Speter if ( constval(al[2]) 268768Speter && isa( con.ctype , "i" ) ) { 269768Speter fmtspec += CONWIDTH; 270768Speter field = con.crval; 271768Speter } else { 272768Speter fmtspec += VARWIDTH; 273768Speter } 274768Speter } 275768Speter if ((fmtspec & CONPREC) && prec < 0 || 276768Speter (fmtspec & CONWIDTH) && field < 0) { 277768Speter error("Negative widths are not allowed"); 278768Speter continue; 279768Speter } 2803179Smckusic if ( opt('s') && 2813179Smckusic ((fmtspec & CONPREC) && prec == 0 || 2823179Smckusic (fmtspec & CONWIDTH) && field == 0)) { 2833179Smckusic standard(); 2843179Smckusic error("Zero widths are non-standard"); 2853179Smckusic } 286768Speter } 287768Speter if (filetype != nl+T1CHAR) { 288768Speter if (fmt == 'O' || fmt == 'X') { 289768Speter error("Oct/hex allowed only on text files"); 290768Speter continue; 291768Speter } 292768Speter if (fmtspec) { 293768Speter error("Write widths allowed only on text files"); 294768Speter continue; 295768Speter } 296768Speter /* 297768Speter * Generalized write, i.e. 298768Speter * to a non-textfile. 299768Speter */ 3002073Smckusic stklval(file, NIL , LREQ ); 301768Speter put(1, O_FNIL); 302768Speter /* 303768Speter * file^ := ... 304768Speter */ 305768Speter ap = rvalue(argv[1], NIL); 306768Speter if (ap == NIL) 307768Speter continue; 308768Speter if (incompat(ap, filetype, argv[1])) { 309768Speter cerror("Type mismatch in write to non-text file"); 310768Speter continue; 311768Speter } 312768Speter convert(ap, filetype); 313768Speter put(2, O_AS, width(filetype)); 314768Speter /* 315768Speter * put(file) 316768Speter */ 317768Speter put(1, O_PUT); 318768Speter continue; 319768Speter } 320768Speter /* 321768Speter * Write to a textfile 322768Speter * 323768Speter * Evaluate the expression 324768Speter * to be written. 325768Speter */ 326768Speter if (fmt == 'O' || fmt == 'X') { 327768Speter if (opt('s')) { 328768Speter standard(); 329768Speter error("Oct and hex are non-standard"); 330768Speter } 331768Speter if (typ == TSTR || typ == TDOUBLE) { 332768Speter error("Can't write %ss with oct/hex", clnames[typ]); 333768Speter continue; 334768Speter } 335768Speter if (typ == TCHAR || typ == TBOOL) 336768Speter typ = TINT; 337768Speter } 338768Speter /* 339768Speter * Place the arguement on the stack. If there is 340768Speter * no format specified by the programmer, implement 341768Speter * the default. 342768Speter */ 343768Speter switch (typ) { 344768Speter case TINT: 345768Speter if (fmt != 'f') { 346768Speter ap = stkrval(alv, NIL , RREQ ); 3473172Smckusic stkcnt += sizeof(long); 348768Speter } else { 349768Speter ap = stkrval(alv, NIL , RREQ ); 350768Speter put(1, O_ITOD); 3513172Smckusic stkcnt += sizeof(double); 352768Speter typ = TDOUBLE; 353768Speter goto tdouble; 354768Speter } 355768Speter if (fmtspec == NIL) { 356768Speter if (fmt == 'D') 357768Speter field = 10; 358768Speter else if (fmt == 'X') 359768Speter field = 8; 360768Speter else if (fmt == 'O') 361768Speter field = 11; 362768Speter else 363768Speter panic("fmt1"); 364768Speter fmtspec = CONWIDTH; 365768Speter } 366768Speter break; 367768Speter case TCHAR: 368768Speter tchar: 3692073Smckusic if (fmtspec == NIL) { 3702073Smckusic put(1, O_FILE); 3712073Smckusic ap = stkrval(alv, NIL , RREQ ); 3723172Smckusic convert(nl + T4INT, INT_TYP); 3733172Smckusic put(2, O_WRITEC, 3743172Smckusic sizeof(char *) + sizeof(int)); 3752073Smckusic fmtspec = SKIP; 3762073Smckusic break; 3772073Smckusic } 378768Speter ap = stkrval(alv, NIL , RREQ ); 3793172Smckusic convert(nl + T4INT, INT_TYP); 3803172Smckusic stkcnt += sizeof(int); 381768Speter fmt = 'c'; 382768Speter break; 383768Speter case TSCAL: 3841628Speter warning(); 385768Speter if (opt('s')) { 386768Speter standard(); 387768Speter } 3881628Speter error("Writing scalars to text files is non-standard"); 389768Speter case TBOOL: 390768Speter stkrval(alv, NIL , RREQ ); 3913076Smckusic put(2, O_NAM, (long)listnames(ap)); 3923172Smckusic stkcnt += sizeof(char *); 393768Speter fmt = 's'; 394768Speter break; 395768Speter case TDOUBLE: 396768Speter ap = stkrval(alv, TDOUBLE , RREQ ); 3973172Smckusic stkcnt += sizeof(double); 398768Speter tdouble: 399768Speter switch (fmtspec) { 400768Speter case NIL: 4013076Smckusic # ifdef DEC11 4023076Smckusic field = 21; 4033076Smckusic # else 4043076Smckusic field = 22; 4053076Smckusic # endif DEC11 406768Speter prec = 14; 4073076Smckusic fmt = 'e'; 408768Speter fmtspec = CONWIDTH + CONPREC; 409768Speter break; 410768Speter case CONWIDTH: 411768Speter if (--field < 1) 412768Speter field = 1; 4133076Smckusic # ifdef DEC11 4143076Smckusic prec = field - 7; 4153076Smckusic # else 4163076Smckusic prec = field - 8; 4173076Smckusic # endif DEC11 418768Speter if (prec < 1) 419768Speter prec = 1; 420768Speter fmtspec += CONPREC; 4213076Smckusic fmt = 'e'; 422768Speter break; 423768Speter case CONWIDTH + CONPREC: 424768Speter case CONWIDTH + VARPREC: 425768Speter if (--field < 1) 426768Speter field = 1; 427768Speter } 428768Speter format[0] = ' '; 429768Speter fmtstart = 0; 430768Speter break; 431768Speter case TSTR: 432768Speter constval( alv ); 433768Speter switch ( classify( con.ctype ) ) { 434768Speter case TCHAR: 435768Speter typ = TCHAR; 436768Speter goto tchar; 437768Speter case TSTR: 438768Speter strptr = con.cpval; 439768Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 440768Speter strptr = con.cpval; 441768Speter break; 442768Speter default: 443768Speter strnglen = width(ap); 444768Speter break; 445768Speter } 446768Speter fmt = 's'; 447768Speter strfmt = fmtspec; 448768Speter if (fmtspec == NIL) { 449768Speter fmtspec = SKIP; 450768Speter break; 451768Speter } 452768Speter if (fmtspec & CONWIDTH) { 453768Speter if (field <= strnglen) { 454768Speter fmtspec = SKIP; 455768Speter break; 456768Speter } else 457768Speter field -= strnglen; 458768Speter } 459768Speter /* 460768Speter * push string to implement leading blank padding 461768Speter */ 462768Speter put(2, O_LVCON, 2); 463768Speter putstr("", 0); 4643172Smckusic stkcnt += sizeof(char *); 465768Speter break; 466768Speter default: 467768Speter error("Can't write %ss to a text file", clnames[typ]); 468768Speter continue; 469768Speter } 470768Speter /* 471768Speter * If there is a variable precision, evaluate it onto 472768Speter * the stack 473768Speter */ 474768Speter if (fmtspec & VARPREC) { 475768Speter ap = stkrval(al[3], NIL , RREQ ); 476768Speter if (ap == NIL) 477768Speter continue; 478768Speter if (isnta(ap,"i")) { 479768Speter error("Second write width must be integer, not %s", nameof(ap)); 480768Speter continue; 481768Speter } 482768Speter if ( opt( 't' ) ) { 483768Speter put(3, O_MAX, 0, 0); 484768Speter } 4853172Smckusic convert(nl+T4INT, INT_TYP); 4863172Smckusic stkcnt += sizeof(int); 487768Speter } 488768Speter /* 489768Speter * If there is a variable width, evaluate it onto 490768Speter * the stack 491768Speter */ 492768Speter if (fmtspec & VARWIDTH) { 493768Speter if ( ( typ == TDOUBLE && fmtspec == VARWIDTH ) 494768Speter || typ == TSTR ) { 495*3226Smckusic soffset = sizes[cbn].curtmps; 496*3226Smckusic i = tmpalloc(sizeof(long), 497*3226Smckusic nl+T4INT, REGOK); 498768Speter put(2, O_LV | cbn << 8 + INDX, i); 499768Speter } 500768Speter ap = stkrval(al[2], NIL , RREQ ); 501768Speter if (ap == NIL) 502768Speter continue; 503768Speter if (isnta(ap,"i")) { 504768Speter error("First write width must be integer, not %s", nameof(ap)); 505768Speter continue; 506768Speter } 507768Speter /* 508768Speter * Perform special processing on widths based 509768Speter * on data type 510768Speter */ 511768Speter switch (typ) { 512768Speter case TDOUBLE: 513768Speter if (fmtspec == VARWIDTH) { 5143076Smckusic fmt = 'e'; 515768Speter put(1, O_AS4); 516768Speter put(2, O_RV4 | cbn << 8 + INDX, i); 5173076Smckusic # ifdef DEC11 5183076Smckusic put(3, O_MAX, 8, 1); 5193076Smckusic # else 5203076Smckusic put(3, O_MAX, 9, 1); 5213076Smckusic # endif DEC11 5223172Smckusic convert(nl+T4INT, INT_TYP); 5233172Smckusic stkcnt += sizeof(int); 524768Speter put(2, O_RV4 | cbn << 8 + INDX, i); 525768Speter fmtspec += VARPREC; 526*3226Smckusic tmpfree(&soffset); 527768Speter } 528768Speter put(3, O_MAX, 1, 1); 529768Speter break; 530768Speter case TSTR: 531768Speter put(1, O_AS4); 532768Speter put(2, O_RV4 | cbn << 8 + INDX, i); 533768Speter put(3, O_MAX, strnglen, 0); 534768Speter break; 535768Speter default: 536768Speter if ( opt( 't' ) ) { 537768Speter put(3, O_MAX, 0, 0); 538768Speter } 539768Speter break; 540768Speter } 5413172Smckusic convert(nl+T4INT, INT_TYP); 5423172Smckusic stkcnt += sizeof(int); 543768Speter } 544768Speter /* 545768Speter * Generate the format string 546768Speter */ 547768Speter switch (fmtspec) { 548768Speter default: 549768Speter panic("fmt2"); 550768Speter case SKIP: 551768Speter break; 5522073Smckusic case NIL: 5532073Smckusic sprintf(&format[1], "%%%c", fmt); 5542073Smckusic goto fmtgen; 555768Speter case CONWIDTH: 5563076Smckusic sprintf(&format[1], "%%%d%c", field, fmt); 557768Speter goto fmtgen; 558768Speter case VARWIDTH: 559768Speter sprintf(&format[1], "%%*%c", fmt); 560768Speter goto fmtgen; 561768Speter case CONWIDTH + CONPREC: 5623076Smckusic sprintf(&format[1], "%%%d.%d%c", field, prec, fmt); 563768Speter goto fmtgen; 564768Speter case CONWIDTH + VARPREC: 5653076Smckusic sprintf(&format[1], "%%%d.*%c", field, fmt); 566768Speter goto fmtgen; 567768Speter case VARWIDTH + CONPREC: 5683076Smckusic sprintf(&format[1], "%%*.%d%c", prec, fmt); 569768Speter goto fmtgen; 570768Speter case VARWIDTH + VARPREC: 571768Speter sprintf(&format[1], "%%*.*%c", fmt); 572768Speter fmtgen: 573768Speter fmtlen = lenstr(&format[fmtstart], 0); 574768Speter put(2, O_LVCON, fmtlen); 575768Speter putstr(&format[fmtstart], 0); 576768Speter put(1, O_FILE); 5773172Smckusic stkcnt += 2 * sizeof(char *); 578768Speter put(2, O_WRITEF, stkcnt); 579768Speter } 580768Speter /* 581768Speter * Write the string after its blank padding 582768Speter */ 583768Speter if (typ == TSTR) { 584768Speter put(1, O_FILE); 5853172Smckusic put(2, CON_INT, 1); 586768Speter if (strfmt & VARWIDTH) { 587768Speter put(2, O_RV4 | cbn << 8 + INDX , i ); 588768Speter put(2, O_MIN, strnglen); 5893172Smckusic convert(nl+T4INT, INT_TYP); 590*3226Smckusic tmpfree(&soffset); 591768Speter } else { 592768Speter if ((fmtspec & SKIP) && 593768Speter (strfmt & CONWIDTH)) { 594768Speter strnglen = field; 595768Speter } 5963172Smckusic put(2, CON_INT, strnglen); 597768Speter } 598768Speter ap = stkrval(alv, NIL , RREQ ); 5993172Smckusic put(2, O_WRITES, 6003172Smckusic 2 * sizeof(char *) + 2 * sizeof(int)); 601768Speter } 602768Speter } 603768Speter /* 604768Speter * Done with arguments. 605768Speter * Handle writeln and 606768Speter * insufficent number of args. 607768Speter */ 608768Speter switch (p->value[0] &~ NSTAND) { 609768Speter case O_WRITEF: 610768Speter if (argc == 0) 611768Speter error("Write requires an argument"); 612768Speter break; 613768Speter case O_MESSAGE: 614768Speter if (argc == 0) 615768Speter error("Message requires an argument"); 616768Speter case O_WRITLN: 617768Speter if (filetype != nl+T1CHAR) 618768Speter error("Can't 'writeln' a non text file"); 619768Speter put(1, O_WRITLN); 620768Speter break; 621768Speter } 622768Speter return; 623768Speter 624768Speter case O_READ4: 625768Speter case O_READLN: 626768Speter /* 627768Speter * Set up default 628768Speter * file "input". 629768Speter */ 630768Speter file = NIL; 631768Speter filetype = nl+T1CHAR; 632768Speter /* 633768Speter * Determine the file implied 634768Speter * for the read and generate 635768Speter * code to make it the active file. 636768Speter */ 637768Speter if (argv != NIL) { 638768Speter codeoff(); 639768Speter ap = stkrval(argv[1], NIL , RREQ ); 640768Speter codeon(); 641768Speter if (ap == NIL) 642768Speter argv = argv[2]; 643768Speter if (ap != NIL && ap->class == FILET) { 644768Speter /* 645768Speter * Got "read(f, ...", make 646768Speter * f the active file, and save 647768Speter * it and its type for use in 648768Speter * processing the rest of the 649768Speter * arguments to read. 650768Speter */ 651768Speter file = argv[1]; 652768Speter filetype = ap->type; 6532073Smckusic stklval(argv[1], NIL , LREQ ); 654768Speter put(1, O_UNIT); 655768Speter argv = argv[2]; 656768Speter argc--; 657768Speter } else { 658768Speter /* 659768Speter * Default is read from 660768Speter * standard input. 661768Speter */ 662768Speter put(1, O_UNITINP); 663768Speter input->nl_flags |= NUSED; 664768Speter } 665768Speter } else { 666768Speter put(1, O_UNITINP); 667768Speter input->nl_flags |= NUSED; 668768Speter } 669768Speter /* 670768Speter * Loop and process each 671768Speter * of the arguments. 672768Speter */ 673768Speter for (; argv != NIL; argv = argv[2]) { 674768Speter /* 675768Speter * Get the address of the target 676768Speter * on the stack. 677768Speter */ 678768Speter al = argv[1]; 679768Speter if (al == NIL) 680768Speter continue; 681768Speter if (al[0] != T_VAR) { 682768Speter error("Arguments to %s must be variables, not expressions", p->symbol); 683768Speter continue; 684768Speter } 685768Speter ap = stklval(al, MOD|ASGN|NOUSE); 686768Speter if (ap == NIL) 687768Speter continue; 688768Speter if (filetype != nl+T1CHAR) { 689768Speter /* 690768Speter * Generalized read, i.e. 691768Speter * from a non-textfile. 692768Speter */ 693768Speter if (incompat(filetype, ap, argv[1] )) { 694768Speter error("Type mismatch in read from non-text file"); 695768Speter continue; 696768Speter } 697768Speter /* 698768Speter * var := file ^; 699768Speter */ 700768Speter if (file != NIL) 7012073Smckusic stklval(file, NIL , LREQ ); 702768Speter else /* Magic */ 7033076Smckusic put(2, PTR_RV, (int)input->value[0]); 704768Speter put(1, O_FNIL); 705768Speter put(2, O_IND, width(filetype)); 706768Speter convert(filetype, ap); 707768Speter if (isa(ap, "bsci")) 708768Speter rangechk(ap, ap); 709768Speter put(2, O_AS, width(ap)); 710768Speter /* 711768Speter * get(file); 712768Speter */ 713768Speter put(1, O_GET); 714768Speter continue; 715768Speter } 716768Speter typ = classify(ap); 717768Speter op = rdops(typ); 718768Speter if (op == NIL) { 719768Speter error("Can't read %ss from a text file", clnames[typ]); 720768Speter continue; 721768Speter } 722768Speter if (op != O_READE) 723768Speter put(1, op); 724768Speter else { 7253076Smckusic put(2, op, (long)listnames(ap)); 7261628Speter warning(); 727768Speter if (opt('s')) { 728768Speter standard(); 729768Speter } 7301628Speter error("Reading scalars from text files is non-standard"); 731768Speter } 732768Speter /* 733768Speter * Data read is on the stack. 734768Speter * Assign it. 735768Speter */ 736768Speter if (op != O_READ8 && op != O_READE) 737768Speter rangechk(ap, op == O_READC ? ap : nl+T4INT); 738768Speter gen(O_AS2, O_AS2, width(ap), 739768Speter op == O_READ8 ? 8 : op == O_READ4 ? 4 : 2); 740768Speter } 741768Speter /* 742768Speter * Done with arguments. 743768Speter * Handle readln and 744768Speter * insufficient number of args. 745768Speter */ 746768Speter if (p->value[0] == O_READLN) { 747768Speter if (filetype != nl+T1CHAR) 748768Speter error("Can't 'readln' a non text file"); 749768Speter put(1, O_READLN); 750768Speter } 751768Speter else if (argc == 0) 752768Speter error("read requires an argument"); 753768Speter return; 754768Speter 755768Speter case O_GET: 756768Speter case O_PUT: 757768Speter if (argc != 1) { 758768Speter error("%s expects one argument", p->symbol); 759768Speter return; 760768Speter } 7612073Smckusic ap = stklval(argv[1], NIL , LREQ ); 762768Speter if (ap == NIL) 763768Speter return; 764768Speter if (ap->class != FILET) { 765768Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 766768Speter return; 767768Speter } 768768Speter put(1, O_UNIT); 769768Speter put(1, op); 770768Speter return; 771768Speter 772768Speter case O_RESET: 773768Speter case O_REWRITE: 774768Speter if (argc == 0 || argc > 2) { 775768Speter error("%s expects one or two arguments", p->symbol); 776768Speter return; 777768Speter } 778768Speter if (opt('s') && argc == 2) { 779768Speter standard(); 780768Speter error("Two argument forms of reset and rewrite are non-standard"); 781768Speter } 7822073Smckusic codeoff(); 783768Speter ap = stklval(argv[1], MOD|NOUSE); 7842073Smckusic codeon(); 785768Speter if (ap == NIL) 786768Speter return; 787768Speter if (ap->class != FILET) { 788768Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 789768Speter return; 790768Speter } 7912073Smckusic put(2, O_CON24, text(ap) ? 0: width(ap->type)); 792768Speter if (argc == 2) { 793768Speter /* 794768Speter * Optional second argument 795768Speter * is a string name of a 796768Speter * UNIX (R) file to be associated. 797768Speter */ 798768Speter al = argv[2]; 7992073Smckusic codeoff(); 800768Speter al = stkrval(al[1], NOFLAGS , RREQ ); 8012073Smckusic codeon(); 802768Speter if (al == NIL) 803768Speter return; 804768Speter if (classify(al) != TSTR) { 805768Speter error("Second argument to %s must be a string, not %s", p->symbol, nameof(al)); 806768Speter return; 807768Speter } 8082073Smckusic put(2, O_CON24, width(al)); 8092073Smckusic al = argv[2]; 8102073Smckusic al = stkrval(al[1], NOFLAGS , RREQ ); 811768Speter } else { 8122073Smckusic put(2, O_CON24, 0); 8133076Smckusic put(2, PTR_CON, NIL); 814768Speter } 8152073Smckusic ap = stklval(argv[1], MOD|NOUSE); 816768Speter put(1, op); 817768Speter return; 818768Speter 819768Speter case O_NEW: 820768Speter case O_DISPOSE: 821768Speter if (argc == 0) { 822768Speter error("%s expects at least one argument", p->symbol); 823768Speter return; 824768Speter } 825768Speter ap = stklval(argv[1], op == O_NEW ? ( MOD | NOUSE ) : MOD ); 826768Speter if (ap == NIL) 827768Speter return; 828768Speter if (ap->class != PTR) { 829768Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 830768Speter return; 831768Speter } 832768Speter ap = ap->type; 833768Speter if (ap == NIL) 834768Speter return; 835768Speter argv = argv[2]; 836768Speter if (argv != NIL) { 837768Speter if (ap->class != RECORD) { 838768Speter error("Record required when specifying variant tags"); 839768Speter return; 840768Speter } 841768Speter for (; argv != NIL; argv = argv[2]) { 842768Speter if (ap->ptr[NL_VARNT] == NIL) { 843768Speter error("Too many tag fields"); 844768Speter return; 845768Speter } 846768Speter if (!isconst(argv[1])) { 847768Speter error("Second and successive arguments to %s must be constants", p->symbol); 848768Speter return; 849768Speter } 850768Speter gconst(argv[1]); 851768Speter if (con.ctype == NIL) 852768Speter return; 853768Speter if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) { 854768Speter cerror("Specified tag constant type clashed with variant case selector type"); 855768Speter return; 856768Speter } 857768Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 858768Speter if (ap->range[0] == con.crval) 859768Speter break; 860768Speter if (ap == NIL) { 861768Speter error("No variant case label value equals specified constant value"); 862768Speter return; 863768Speter } 864768Speter ap = ap->ptr[NL_VTOREC]; 865768Speter } 866768Speter } 867768Speter put(2, op, width(ap)); 868768Speter return; 869768Speter 870768Speter case O_DATE: 871768Speter case O_TIME: 872768Speter if (argc != 1) { 873768Speter error("%s expects one argument", p->symbol); 874768Speter return; 875768Speter } 876768Speter ap = stklval(argv[1], MOD|NOUSE); 877768Speter if (ap == NIL) 878768Speter return; 879768Speter if (classify(ap) != TSTR || width(ap) != 10) { 880768Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 881768Speter return; 882768Speter } 883768Speter put(1, op); 884768Speter return; 885768Speter 886768Speter case O_HALT: 887768Speter if (argc != 0) { 888768Speter error("halt takes no arguments"); 889768Speter return; 890768Speter } 891768Speter put(1, op); 892768Speter noreach = 1; 893768Speter return; 894768Speter 895768Speter case O_ARGV: 896768Speter if (argc != 2) { 897768Speter error("argv takes two arguments"); 898768Speter return; 899768Speter } 900768Speter ap = stkrval(argv[1], NIL , RREQ ); 901768Speter if (ap == NIL) 902768Speter return; 903768Speter if (isnta(ap, "i")) { 904768Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 905768Speter return; 906768Speter } 907768Speter al = argv[2]; 908768Speter ap = stklval(al[1], MOD|NOUSE); 909768Speter if (ap == NIL) 910768Speter return; 911768Speter if (classify(ap) != TSTR) { 912768Speter error("argv's second argument must be a string, not %s", nameof(ap)); 913768Speter return; 914768Speter } 915768Speter put(2, op, width(ap)); 916768Speter return; 917768Speter 918768Speter case O_STLIM: 919768Speter if (argc != 1) { 920768Speter error("stlimit requires one argument"); 921768Speter return; 922768Speter } 923768Speter ap = stkrval(argv[1], NIL , RREQ ); 924768Speter if (ap == NIL) 925768Speter return; 926768Speter if (isnta(ap, "i")) { 927768Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 928768Speter return; 929768Speter } 930768Speter if (width(ap) != 4) 931768Speter put(1, O_STOI); 932768Speter put(1, op); 933768Speter return; 934768Speter 935768Speter case O_REMOVE: 936768Speter if (argc != 1) { 937768Speter error("remove expects one argument"); 938768Speter return; 939768Speter } 9402073Smckusic codeoff(); 941768Speter ap = stkrval(argv[1], NOFLAGS , RREQ ); 9422073Smckusic codeon(); 943768Speter if (ap == NIL) 944768Speter return; 945768Speter if (classify(ap) != TSTR) { 946768Speter error("remove's argument must be a string, not %s", nameof(ap)); 947768Speter return; 948768Speter } 949768Speter put(2, O_CON24, width(ap)); 9502073Smckusic ap = stkrval(argv[1], NOFLAGS , RREQ ); 951768Speter put(1, op); 952768Speter return; 953768Speter 954768Speter case O_LLIMIT: 955768Speter if (argc != 2) { 956768Speter error("linelimit expects two arguments"); 957768Speter return; 958768Speter } 959768Speter al = argv[2]; 960768Speter ap = stkrval(al[1], NIL , RREQ ); 961768Speter if (ap == NIL) 962768Speter return; 963768Speter if (isnta(ap, "i")) { 964768Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 965768Speter return; 966768Speter } 9672073Smckusic ap = stklval(argv[1], NOFLAGS|NOUSE); 9682073Smckusic if (ap == NIL) 9692073Smckusic return; 9702073Smckusic if (!text(ap)) { 9712073Smckusic error("linelimit's first argument must be a text file, not %s", nameof(ap)); 9722073Smckusic return; 9732073Smckusic } 974768Speter put(1, op); 975768Speter return; 976768Speter case O_PAGE: 977768Speter if (argc != 1) { 978768Speter error("page expects one argument"); 979768Speter return; 980768Speter } 9812073Smckusic ap = stklval(argv[1], NIL , LREQ ); 982768Speter if (ap == NIL) 983768Speter return; 984768Speter if (!text(ap)) { 985768Speter error("Argument to page must be a text file, not %s", nameof(ap)); 986768Speter return; 987768Speter } 988768Speter put(1, O_UNIT); 989768Speter put(1, op); 990768Speter return; 991768Speter 992768Speter case O_PACK: 993768Speter if (argc != 3) { 994768Speter error("pack expects three arguments"); 995768Speter return; 996768Speter } 997768Speter pu = "pack(a,i,z)"; 9983076Smckusic pua = argv[1]; 9993076Smckusic al = argv[2]; 10003076Smckusic pui = al[1]; 10013076Smckusic alv = al[2]; 10023076Smckusic puz = alv[1]; 1003768Speter goto packunp; 1004768Speter case O_UNPACK: 1005768Speter if (argc != 3) { 1006768Speter error("unpack expects three arguments"); 1007768Speter return; 1008768Speter } 1009768Speter pu = "unpack(z,a,i)"; 10103076Smckusic puz = argv[1]; 10113076Smckusic al = argv[2]; 10123076Smckusic pua = al[1]; 10133076Smckusic alv = al[2]; 10143076Smckusic pui = alv[1]; 1015768Speter packunp: 10162073Smckusic codeoff(); 1017768Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 10182073Smckusic al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 10192073Smckusic codeon(); 1020768Speter if (ap == NIL) 1021768Speter return; 1022768Speter if (ap->class != ARRAY) { 1023768Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 1024768Speter return; 1025768Speter } 1026768Speter if (al->class != ARRAY) { 1027768Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 1028768Speter return; 1029768Speter } 1030768Speter if (al->type == NIL || ap->type == NIL) 1031768Speter return; 1032768Speter if (al->type != ap->type) { 1033768Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 1034768Speter return; 1035768Speter } 1036768Speter k = width(al); 1037768Speter itemwidth = width(ap->type); 1038768Speter ap = ap->chain; 1039768Speter al = al->chain; 1040768Speter if (ap->chain != NIL || al->chain != NIL) { 1041768Speter error("%s requires a and z to be single dimension arrays", pu); 1042768Speter return; 1043768Speter } 1044768Speter if (ap == NIL || al == NIL) 1045768Speter return; 1046768Speter /* 1047768Speter * al is the range for z i.e. u..v 1048768Speter * ap is the range for a i.e. m..n 1049768Speter * i will be n-m+1 1050768Speter * j will be v-u+1 1051768Speter */ 1052768Speter i = ap->range[1] - ap->range[0] + 1; 1053768Speter j = al->range[1] - al->range[0] + 1; 1054768Speter if (i < j) { 1055768Speter error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i); 1056768Speter return; 1057768Speter } 1058768Speter /* 1059768Speter * get n-m-(v-u) and m for the interpreter 1060768Speter */ 1061768Speter i -= j; 1062768Speter j = ap->range[0]; 10632073Smckusic put(2, O_CON24, k); 10642073Smckusic put(2, O_CON24, i); 10652073Smckusic put(2, O_CON24, j); 10662073Smckusic put(2, O_CON24, itemwidth); 10672073Smckusic al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 10682073Smckusic ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 10692073Smckusic ap = stkrval((int *) pui, NLNIL , RREQ ); 10702073Smckusic if (ap == NIL) 10712073Smckusic return; 10722073Smckusic put(1, op); 1073768Speter return; 1074768Speter case 0: 1075768Speter error("%s is an unimplemented 6400 extension", p->symbol); 1076768Speter return; 1077768Speter 1078768Speter default: 1079768Speter panic("proc case"); 1080768Speter } 1081768Speter } 1082768Speter #endif OBJ 1083