1768Speter /* Copyright (c) 1979 Regents of the University of California */ 2768Speter 3*7966Smckusick static char sccsid[] = "@(#)proc.c 1.13 08/29/82"; 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; 543226Smckusic struct tmps soffset; 553851Speter struct nl *tempnlp; 56768Speter 57768Speter #define CONPREC 4 58768Speter #define VARPREC 8 59768Speter #define CONWIDTH 1 60768Speter #define VARWIDTH 2 61768Speter #define SKIP 16 62768Speter 63768Speter /* 64768Speter * Verify that the name is 65768Speter * defined and is that of a 66768Speter * procedure. 67768Speter */ 68768Speter p = lookup(r[2]); 69768Speter if (p == NIL) { 70768Speter rvlist(r[3]); 71768Speter return; 72768Speter } 731198Speter if (p->class != PROC && p->class != FPROC) { 74768Speter error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]); 75768Speter rvlist(r[3]); 76768Speter return; 77768Speter } 78768Speter argv = r[3]; 79768Speter 80768Speter /* 81768Speter * Call handles user defined 82768Speter * procedures and functions. 83768Speter */ 84768Speter if (bn != 0) { 85768Speter call(p, argv, PROC, bn); 86768Speter return; 87768Speter } 88768Speter 89768Speter /* 90768Speter * Call to built-in procedure. 91768Speter * Count the arguments. 92768Speter */ 93768Speter argc = 0; 94768Speter for (al = argv; al != NIL; al = al[2]) 95768Speter argc++; 96768Speter 97768Speter /* 98768Speter * Switch on the operator 99768Speter * associated with the built-in 100768Speter * procedure in the namelist 101768Speter */ 102768Speter op = p->value[0] &~ NSTAND; 103768Speter if (opt('s') && (p->value[0] & NSTAND)) { 104768Speter standard(); 105768Speter error("%s is a nonstandard procedure", p->symbol); 106768Speter } 107768Speter switch (op) { 108768Speter 109768Speter case O_ABORT: 110768Speter if (argc != 0) 111768Speter error("null takes no arguments"); 112768Speter return; 113768Speter 114768Speter case O_FLUSH: 115768Speter if (argc == 0) { 116768Speter put(1, O_MESSAGE); 117768Speter return; 118768Speter } 119768Speter if (argc != 1) { 120768Speter error("flush takes at most one argument"); 121768Speter return; 122768Speter } 1232073Smckusic ap = stklval(argv[1], NIL , LREQ ); 124768Speter if (ap == NIL) 125768Speter return; 126768Speter if (ap->class != FILET) { 127768Speter error("flush's argument must be a file, not %s", nameof(ap)); 128768Speter return; 129768Speter } 130768Speter put(1, op); 131768Speter return; 132768Speter 133768Speter case O_MESSAGE: 134768Speter case O_WRITEF: 135768Speter case O_WRITLN: 136768Speter /* 137768Speter * Set up default file "output"'s type 138768Speter */ 139768Speter file = NIL; 140768Speter filetype = nl+T1CHAR; 141768Speter /* 142768Speter * Determine the file implied 143768Speter * for the write and generate 144768Speter * code to make it the active file. 145768Speter */ 146768Speter if (op == O_MESSAGE) { 147768Speter /* 148768Speter * For message, all that matters 149768Speter * is that the filetype is 150768Speter * a character file. 151768Speter * Thus "output" will suit us fine. 152768Speter */ 153768Speter put(1, O_MESSAGE); 154768Speter } else if (argv != NIL && (al = argv[1])[0] != T_WEXP) { 155768Speter /* 156768Speter * If there is a first argument which has 157768Speter * no write widths, then it is potentially 158768Speter * a file name. 159768Speter */ 160768Speter codeoff(); 161768Speter ap = stkrval(argv[1], NIL , RREQ ); 162768Speter codeon(); 163768Speter if (ap == NIL) 164768Speter argv = argv[2]; 165768Speter if (ap != NIL && ap->class == FILET) { 166768Speter /* 167768Speter * Got "write(f, ...", make 168768Speter * f the active file, and save 169768Speter * it and its type for use in 170768Speter * processing the rest of the 171768Speter * arguments to write. 172768Speter */ 173768Speter file = argv[1]; 174768Speter filetype = ap->type; 1752073Smckusic stklval(argv[1], NIL , LREQ ); 176768Speter put(1, O_UNIT); 177768Speter /* 178768Speter * Skip over the first argument 179768Speter */ 180768Speter argv = argv[2]; 181768Speter argc--; 182768Speter } else 183768Speter /* 184768Speter * Set up for writing on 185768Speter * standard output. 186768Speter */ 187768Speter put(1, O_UNITOUT); 1887953Speter output->nl_flags |= NUSED; 189768Speter } else 190768Speter put(1, O_UNITOUT); 1917953Speter output->nl_flags |= NUSED; 192768Speter /* 193768Speter * Loop and process each 194768Speter * of the arguments. 195768Speter */ 196768Speter for (; argv != NIL; argv = argv[2]) { 197768Speter /* 198768Speter * fmtspec indicates the type (CONstant or VARiable) 199768Speter * and number (none, WIDTH, and/or PRECision) 200768Speter * of the fields in the printf format for this 201768Speter * output variable. 2023172Smckusic * stkcnt is the number of bytes pushed on the stack 203768Speter * fmt is the format output indicator (D, E, F, O, X, S) 204768Speter * fmtstart = 0 for leading blank; = 1 for no blank 205768Speter */ 206768Speter fmtspec = NIL; 207768Speter stkcnt = 0; 208768Speter fmt = 'D'; 209768Speter fmtstart = 1; 210768Speter al = argv[1]; 211768Speter if (al == NIL) 212768Speter continue; 213768Speter if (al[0] == T_WEXP) 214768Speter alv = al[1]; 215768Speter else 216768Speter alv = al; 217768Speter if (alv == NIL) 218768Speter continue; 219768Speter codeoff(); 220768Speter ap = stkrval(alv, NIL , RREQ ); 221768Speter codeon(); 222768Speter if (ap == NIL) 223768Speter continue; 224768Speter typ = classify(ap); 225768Speter if (al[0] == T_WEXP) { 226768Speter /* 227768Speter * Handle width expressions. 228768Speter * The basic game here is that width 229768Speter * expressions get evaluated. If they 230768Speter * are constant, the value is placed 231768Speter * directly in the format string. 232768Speter * Otherwise the value is pushed onto 233768Speter * the stack and an indirection is 234768Speter * put into the format string. 235768Speter */ 236768Speter if (al[3] == OCT) 237768Speter fmt = 'O'; 238768Speter else if (al[3] == HEX) 239768Speter fmt = 'X'; 240768Speter else if (al[3] != NIL) { 241768Speter /* 242768Speter * Evaluate second format spec 243768Speter */ 244768Speter if ( constval(al[3]) 245768Speter && isa( con.ctype , "i" ) ) { 246768Speter fmtspec += CONPREC; 247768Speter prec = con.crval; 248768Speter } else { 249768Speter fmtspec += VARPREC; 250768Speter } 251768Speter fmt = 'f'; 252768Speter switch ( typ ) { 253768Speter case TINT: 254768Speter if ( opt( 's' ) ) { 255768Speter standard(); 256768Speter error("Writing %ss with two write widths is non-standard", clnames[typ]); 257768Speter } 258768Speter /* and fall through */ 259768Speter case TDOUBLE: 260768Speter break; 261768Speter default: 262768Speter error("Cannot write %ss with two write widths", clnames[typ]); 263768Speter continue; 264768Speter } 265768Speter } 266768Speter /* 267768Speter * Evaluate first format spec 268768Speter */ 269768Speter if (al[2] != NIL) { 270768Speter if ( constval(al[2]) 271768Speter && isa( con.ctype , "i" ) ) { 272768Speter fmtspec += CONWIDTH; 273768Speter field = con.crval; 274768Speter } else { 275768Speter fmtspec += VARWIDTH; 276768Speter } 277768Speter } 278768Speter if ((fmtspec & CONPREC) && prec < 0 || 279768Speter (fmtspec & CONWIDTH) && field < 0) { 280768Speter error("Negative widths are not allowed"); 281768Speter continue; 282768Speter } 2833179Smckusic if ( opt('s') && 2843179Smckusic ((fmtspec & CONPREC) && prec == 0 || 2853179Smckusic (fmtspec & CONWIDTH) && field == 0)) { 2863179Smckusic standard(); 2873179Smckusic error("Zero widths are non-standard"); 2883179Smckusic } 289768Speter } 290768Speter if (filetype != nl+T1CHAR) { 291768Speter if (fmt == 'O' || fmt == 'X') { 292768Speter error("Oct/hex allowed only on text files"); 293768Speter continue; 294768Speter } 295768Speter if (fmtspec) { 296768Speter error("Write widths allowed only on text files"); 297768Speter continue; 298768Speter } 299768Speter /* 300768Speter * Generalized write, i.e. 301768Speter * to a non-textfile. 302768Speter */ 3032073Smckusic stklval(file, NIL , LREQ ); 304768Speter put(1, O_FNIL); 305768Speter /* 306768Speter * file^ := ... 307768Speter */ 308768Speter ap = rvalue(argv[1], NIL); 309768Speter if (ap == NIL) 310768Speter continue; 311768Speter if (incompat(ap, filetype, argv[1])) { 312768Speter cerror("Type mismatch in write to non-text file"); 313768Speter continue; 314768Speter } 315768Speter convert(ap, filetype); 316768Speter put(2, O_AS, width(filetype)); 317768Speter /* 318768Speter * put(file) 319768Speter */ 320768Speter put(1, O_PUT); 321768Speter continue; 322768Speter } 323768Speter /* 324768Speter * Write to a textfile 325768Speter * 326768Speter * Evaluate the expression 327768Speter * to be written. 328768Speter */ 329768Speter if (fmt == 'O' || fmt == 'X') { 330768Speter if (opt('s')) { 331768Speter standard(); 332768Speter error("Oct and hex are non-standard"); 333768Speter } 334768Speter if (typ == TSTR || typ == TDOUBLE) { 335768Speter error("Can't write %ss with oct/hex", clnames[typ]); 336768Speter continue; 337768Speter } 338768Speter if (typ == TCHAR || typ == TBOOL) 339768Speter typ = TINT; 340768Speter } 341768Speter /* 342768Speter * Place the arguement on the stack. If there is 343768Speter * no format specified by the programmer, implement 344768Speter * the default. 345768Speter */ 346768Speter switch (typ) { 3476542Smckusick case TPTR: 3486542Smckusick warning(); 3496542Smckusick if (opt('s')) { 3506542Smckusick standard(); 3516542Smckusick } 3526542Smckusick error("Writing %ss to text files is non-standard", 3536542Smckusick clnames[typ]); 3546542Smckusick /* and fall through */ 355768Speter case TINT: 356768Speter if (fmt != 'f') { 357768Speter ap = stkrval(alv, NIL , RREQ ); 3583172Smckusic stkcnt += sizeof(long); 359768Speter } else { 360768Speter ap = stkrval(alv, NIL , RREQ ); 361768Speter put(1, O_ITOD); 3623172Smckusic stkcnt += sizeof(double); 363768Speter typ = TDOUBLE; 364768Speter goto tdouble; 365768Speter } 366768Speter if (fmtspec == NIL) { 367768Speter if (fmt == 'D') 368768Speter field = 10; 369768Speter else if (fmt == 'X') 370768Speter field = 8; 371768Speter else if (fmt == 'O') 372768Speter field = 11; 373768Speter else 374768Speter panic("fmt1"); 375768Speter fmtspec = CONWIDTH; 376768Speter } 377768Speter break; 378768Speter case TCHAR: 379768Speter tchar: 3802073Smckusic if (fmtspec == NIL) { 3812073Smckusic put(1, O_FILE); 3822073Smckusic ap = stkrval(alv, NIL , RREQ ); 3833172Smckusic convert(nl + T4INT, INT_TYP); 3843172Smckusic put(2, O_WRITEC, 3853172Smckusic sizeof(char *) + sizeof(int)); 3862073Smckusic fmtspec = SKIP; 3872073Smckusic break; 3882073Smckusic } 389768Speter ap = stkrval(alv, NIL , RREQ ); 3903172Smckusic convert(nl + T4INT, INT_TYP); 3913172Smckusic stkcnt += sizeof(int); 392768Speter fmt = 'c'; 393768Speter break; 394768Speter case TSCAL: 3951628Speter warning(); 396768Speter if (opt('s')) { 397768Speter standard(); 398768Speter } 3996542Smckusick error("Writing %ss to text files is non-standard", 4006542Smckusick clnames[typ]); 4016542Smckusick /* and fall through */ 402768Speter case TBOOL: 403768Speter stkrval(alv, NIL , RREQ ); 4043076Smckusic put(2, O_NAM, (long)listnames(ap)); 4053172Smckusic stkcnt += sizeof(char *); 406768Speter fmt = 's'; 407768Speter break; 408768Speter case TDOUBLE: 409768Speter ap = stkrval(alv, TDOUBLE , RREQ ); 4103172Smckusic stkcnt += sizeof(double); 411768Speter tdouble: 412768Speter switch (fmtspec) { 413768Speter case NIL: 4143076Smckusic # ifdef DEC11 4153076Smckusic field = 21; 4163076Smckusic # else 4173076Smckusic field = 22; 4183076Smckusic # endif DEC11 419768Speter prec = 14; 4203076Smckusic fmt = 'e'; 421768Speter fmtspec = CONWIDTH + CONPREC; 422768Speter break; 423768Speter case CONWIDTH: 424768Speter if (--field < 1) 425768Speter field = 1; 4263076Smckusic # ifdef DEC11 4273076Smckusic prec = field - 7; 4283076Smckusic # else 4293076Smckusic prec = field - 8; 4303076Smckusic # endif DEC11 431768Speter if (prec < 1) 432768Speter prec = 1; 433768Speter fmtspec += CONPREC; 4343076Smckusic fmt = 'e'; 435768Speter break; 436768Speter case CONWIDTH + CONPREC: 437768Speter case CONWIDTH + VARPREC: 438768Speter if (--field < 1) 439768Speter field = 1; 440768Speter } 441768Speter format[0] = ' '; 442768Speter fmtstart = 0; 443768Speter break; 444768Speter case TSTR: 445768Speter constval( alv ); 446768Speter switch ( classify( con.ctype ) ) { 447768Speter case TCHAR: 448768Speter typ = TCHAR; 449768Speter goto tchar; 450768Speter case TSTR: 451768Speter strptr = con.cpval; 452768Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 453768Speter strptr = con.cpval; 454768Speter break; 455768Speter default: 456768Speter strnglen = width(ap); 457768Speter break; 458768Speter } 459768Speter fmt = 's'; 460768Speter strfmt = fmtspec; 461768Speter if (fmtspec == NIL) { 462768Speter fmtspec = SKIP; 463768Speter break; 464768Speter } 465768Speter if (fmtspec & CONWIDTH) { 466768Speter if (field <= strnglen) { 467768Speter fmtspec = SKIP; 468768Speter break; 469768Speter } else 470768Speter field -= strnglen; 471768Speter } 472768Speter /* 473768Speter * push string to implement leading blank padding 474768Speter */ 475768Speter put(2, O_LVCON, 2); 476768Speter putstr("", 0); 4773172Smckusic stkcnt += sizeof(char *); 478768Speter break; 479768Speter default: 480768Speter error("Can't write %ss to a text file", clnames[typ]); 481768Speter continue; 482768Speter } 483768Speter /* 484768Speter * If there is a variable precision, evaluate it onto 485768Speter * the stack 486768Speter */ 487768Speter if (fmtspec & VARPREC) { 488768Speter ap = stkrval(al[3], NIL , RREQ ); 489768Speter if (ap == NIL) 490768Speter continue; 491768Speter if (isnta(ap,"i")) { 492768Speter error("Second write width must be integer, not %s", nameof(ap)); 493768Speter continue; 494768Speter } 495768Speter if ( opt( 't' ) ) { 496768Speter put(3, O_MAX, 0, 0); 497768Speter } 4983172Smckusic convert(nl+T4INT, INT_TYP); 4993172Smckusic stkcnt += sizeof(int); 500768Speter } 501768Speter /* 502768Speter * If there is a variable width, evaluate it onto 503768Speter * the stack 504768Speter */ 505768Speter if (fmtspec & VARWIDTH) { 506768Speter if ( ( typ == TDOUBLE && fmtspec == VARWIDTH ) 507768Speter || typ == TSTR ) { 5083226Smckusic soffset = sizes[cbn].curtmps; 5093851Speter tempnlp = tmpalloc(sizeof(long), 5103226Smckusic nl+T4INT, REGOK); 5113851Speter put(2, O_LV | cbn << 8 + INDX, 5123851Speter tempnlp -> value[ NL_OFFS ] ); 513768Speter } 514768Speter ap = stkrval(al[2], NIL , RREQ ); 515768Speter if (ap == NIL) 516768Speter continue; 517768Speter if (isnta(ap,"i")) { 518768Speter error("First write width must be integer, not %s", nameof(ap)); 519768Speter continue; 520768Speter } 521768Speter /* 522768Speter * Perform special processing on widths based 523768Speter * on data type 524768Speter */ 525768Speter switch (typ) { 526768Speter case TDOUBLE: 527768Speter if (fmtspec == VARWIDTH) { 5283076Smckusic fmt = 'e'; 529768Speter put(1, O_AS4); 5303851Speter put(2, O_RV4 | cbn << 8 + INDX, 5313851Speter tempnlp -> value[NL_OFFS] ); 5323076Smckusic # ifdef DEC11 5333076Smckusic put(3, O_MAX, 8, 1); 5343076Smckusic # else 5353076Smckusic put(3, O_MAX, 9, 1); 5363076Smckusic # endif DEC11 5373172Smckusic convert(nl+T4INT, INT_TYP); 5383172Smckusic stkcnt += sizeof(int); 5393851Speter put(2, O_RV4 | cbn << 8 + INDX, 5403851Speter tempnlp->value[NL_OFFS] ); 541768Speter fmtspec += VARPREC; 5423226Smckusic tmpfree(&soffset); 543768Speter } 544768Speter put(3, O_MAX, 1, 1); 545768Speter break; 546768Speter case TSTR: 547768Speter put(1, O_AS4); 5483851Speter put(2, O_RV4 | cbn << 8 + INDX, 5493851Speter tempnlp -> value[ NL_OFFS ] ); 550768Speter put(3, O_MAX, strnglen, 0); 551768Speter break; 552768Speter default: 553768Speter if ( opt( 't' ) ) { 554768Speter put(3, O_MAX, 0, 0); 555768Speter } 556768Speter break; 557768Speter } 5583172Smckusic convert(nl+T4INT, INT_TYP); 5593172Smckusic stkcnt += sizeof(int); 560768Speter } 561768Speter /* 562768Speter * Generate the format string 563768Speter */ 564768Speter switch (fmtspec) { 565768Speter default: 566768Speter panic("fmt2"); 567768Speter case SKIP: 568768Speter break; 5692073Smckusic case NIL: 5702073Smckusic sprintf(&format[1], "%%%c", fmt); 5712073Smckusic goto fmtgen; 572768Speter case CONWIDTH: 5733076Smckusic sprintf(&format[1], "%%%d%c", field, fmt); 574768Speter goto fmtgen; 575768Speter case VARWIDTH: 576768Speter sprintf(&format[1], "%%*%c", fmt); 577768Speter goto fmtgen; 578768Speter case CONWIDTH + CONPREC: 5793076Smckusic sprintf(&format[1], "%%%d.%d%c", field, prec, fmt); 580768Speter goto fmtgen; 581768Speter case CONWIDTH + VARPREC: 5823076Smckusic sprintf(&format[1], "%%%d.*%c", field, fmt); 583768Speter goto fmtgen; 584768Speter case VARWIDTH + CONPREC: 5853076Smckusic sprintf(&format[1], "%%*.%d%c", prec, fmt); 586768Speter goto fmtgen; 587768Speter case VARWIDTH + VARPREC: 588768Speter sprintf(&format[1], "%%*.*%c", fmt); 589768Speter fmtgen: 590768Speter fmtlen = lenstr(&format[fmtstart], 0); 591768Speter put(2, O_LVCON, fmtlen); 592768Speter putstr(&format[fmtstart], 0); 593768Speter put(1, O_FILE); 5943172Smckusic stkcnt += 2 * sizeof(char *); 595768Speter put(2, O_WRITEF, stkcnt); 596768Speter } 597768Speter /* 598768Speter * Write the string after its blank padding 599768Speter */ 600768Speter if (typ == TSTR) { 601768Speter put(1, O_FILE); 6023172Smckusic put(2, CON_INT, 1); 603768Speter if (strfmt & VARWIDTH) { 6043851Speter put(2, O_RV4 | cbn << 8 + INDX , 6053851Speter tempnlp -> value[ NL_OFFS ] ); 606768Speter put(2, O_MIN, strnglen); 6073172Smckusic convert(nl+T4INT, INT_TYP); 6083226Smckusic tmpfree(&soffset); 609768Speter } else { 610768Speter if ((fmtspec & SKIP) && 611768Speter (strfmt & CONWIDTH)) { 612768Speter strnglen = field; 613768Speter } 6143172Smckusic put(2, CON_INT, strnglen); 615768Speter } 616768Speter ap = stkrval(alv, NIL , RREQ ); 6173172Smckusic put(2, O_WRITES, 6183172Smckusic 2 * sizeof(char *) + 2 * sizeof(int)); 619768Speter } 620768Speter } 621768Speter /* 622768Speter * Done with arguments. 623768Speter * Handle writeln and 624768Speter * insufficent number of args. 625768Speter */ 626768Speter switch (p->value[0] &~ NSTAND) { 627768Speter case O_WRITEF: 628768Speter if (argc == 0) 629768Speter error("Write requires an argument"); 630768Speter break; 631768Speter case O_MESSAGE: 632768Speter if (argc == 0) 633768Speter error("Message requires an argument"); 634768Speter case O_WRITLN: 635768Speter if (filetype != nl+T1CHAR) 636768Speter error("Can't 'writeln' a non text file"); 637768Speter put(1, O_WRITLN); 638768Speter break; 639768Speter } 640768Speter return; 641768Speter 642768Speter case O_READ4: 643768Speter case O_READLN: 644768Speter /* 645768Speter * Set up default 646768Speter * file "input". 647768Speter */ 648768Speter file = NIL; 649768Speter filetype = nl+T1CHAR; 650768Speter /* 651768Speter * Determine the file implied 652768Speter * for the read and generate 653768Speter * code to make it the active file. 654768Speter */ 655768Speter if (argv != NIL) { 656768Speter codeoff(); 657768Speter ap = stkrval(argv[1], NIL , RREQ ); 658768Speter codeon(); 659768Speter if (ap == NIL) 660768Speter argv = argv[2]; 661768Speter if (ap != NIL && ap->class == FILET) { 662768Speter /* 663768Speter * Got "read(f, ...", make 664768Speter * f the active file, and save 665768Speter * it and its type for use in 666768Speter * processing the rest of the 667768Speter * arguments to read. 668768Speter */ 669768Speter file = argv[1]; 670768Speter filetype = ap->type; 6712073Smckusic stklval(argv[1], NIL , LREQ ); 672768Speter put(1, O_UNIT); 673768Speter argv = argv[2]; 674768Speter argc--; 675768Speter } else { 676768Speter /* 677768Speter * Default is read from 678768Speter * standard input. 679768Speter */ 680768Speter put(1, O_UNITINP); 681768Speter input->nl_flags |= NUSED; 682768Speter } 683768Speter } else { 684768Speter put(1, O_UNITINP); 685768Speter input->nl_flags |= NUSED; 686768Speter } 687768Speter /* 688768Speter * Loop and process each 689768Speter * of the arguments. 690768Speter */ 691768Speter for (; argv != NIL; argv = argv[2]) { 692768Speter /* 693768Speter * Get the address of the target 694768Speter * on the stack. 695768Speter */ 696768Speter al = argv[1]; 697768Speter if (al == NIL) 698768Speter continue; 699768Speter if (al[0] != T_VAR) { 700768Speter error("Arguments to %s must be variables, not expressions", p->symbol); 701768Speter continue; 702768Speter } 703768Speter ap = stklval(al, MOD|ASGN|NOUSE); 704768Speter if (ap == NIL) 705768Speter continue; 706768Speter if (filetype != nl+T1CHAR) { 707768Speter /* 708768Speter * Generalized read, i.e. 709768Speter * from a non-textfile. 710768Speter */ 711768Speter if (incompat(filetype, ap, argv[1] )) { 712768Speter error("Type mismatch in read from non-text file"); 713768Speter continue; 714768Speter } 715768Speter /* 716768Speter * var := file ^; 717768Speter */ 718768Speter if (file != NIL) 7192073Smckusic stklval(file, NIL , LREQ ); 720768Speter else /* Magic */ 7213076Smckusic put(2, PTR_RV, (int)input->value[0]); 722768Speter put(1, O_FNIL); 723768Speter put(2, O_IND, width(filetype)); 724768Speter convert(filetype, ap); 725768Speter if (isa(ap, "bsci")) 726768Speter rangechk(ap, ap); 727768Speter put(2, O_AS, width(ap)); 728768Speter /* 729768Speter * get(file); 730768Speter */ 731768Speter put(1, O_GET); 732768Speter continue; 733768Speter } 734768Speter typ = classify(ap); 735768Speter op = rdops(typ); 736768Speter if (op == NIL) { 737768Speter error("Can't read %ss from a text file", clnames[typ]); 738768Speter continue; 739768Speter } 740768Speter if (op != O_READE) 741768Speter put(1, op); 742768Speter else { 7433076Smckusic put(2, op, (long)listnames(ap)); 7441628Speter warning(); 745768Speter if (opt('s')) { 746768Speter standard(); 747768Speter } 7481628Speter error("Reading scalars from text files is non-standard"); 749768Speter } 750768Speter /* 751768Speter * Data read is on the stack. 752768Speter * Assign it. 753768Speter */ 754768Speter if (op != O_READ8 && op != O_READE) 755768Speter rangechk(ap, op == O_READC ? ap : nl+T4INT); 756768Speter gen(O_AS2, O_AS2, width(ap), 757768Speter op == O_READ8 ? 8 : op == O_READ4 ? 4 : 2); 758768Speter } 759768Speter /* 760768Speter * Done with arguments. 761768Speter * Handle readln and 762768Speter * insufficient number of args. 763768Speter */ 764768Speter if (p->value[0] == O_READLN) { 765768Speter if (filetype != nl+T1CHAR) 766768Speter error("Can't 'readln' a non text file"); 767768Speter put(1, O_READLN); 768768Speter } 769768Speter else if (argc == 0) 770768Speter error("read requires an argument"); 771768Speter return; 772768Speter 773768Speter case O_GET: 774768Speter case O_PUT: 775768Speter if (argc != 1) { 776768Speter error("%s expects one argument", p->symbol); 777768Speter return; 778768Speter } 7792073Smckusic ap = stklval(argv[1], NIL , LREQ ); 780768Speter if (ap == NIL) 781768Speter return; 782768Speter if (ap->class != FILET) { 783768Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 784768Speter return; 785768Speter } 786768Speter put(1, O_UNIT); 787768Speter put(1, op); 788768Speter return; 789768Speter 790768Speter case O_RESET: 791768Speter case O_REWRITE: 792768Speter if (argc == 0 || argc > 2) { 793768Speter error("%s expects one or two arguments", p->symbol); 794768Speter return; 795768Speter } 796768Speter if (opt('s') && argc == 2) { 797768Speter standard(); 798768Speter error("Two argument forms of reset and rewrite are non-standard"); 799768Speter } 8002073Smckusic codeoff(); 801768Speter ap = stklval(argv[1], MOD|NOUSE); 8022073Smckusic codeon(); 803768Speter if (ap == NIL) 804768Speter return; 805768Speter if (ap->class != FILET) { 806768Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 807768Speter return; 808768Speter } 8092073Smckusic put(2, O_CON24, text(ap) ? 0: width(ap->type)); 810768Speter if (argc == 2) { 811768Speter /* 812768Speter * Optional second argument 813768Speter * is a string name of a 814768Speter * UNIX (R) file to be associated. 815768Speter */ 816768Speter al = argv[2]; 8172073Smckusic codeoff(); 818768Speter al = stkrval(al[1], NOFLAGS , RREQ ); 8192073Smckusic codeon(); 820768Speter if (al == NIL) 821768Speter return; 822768Speter if (classify(al) != TSTR) { 823768Speter error("Second argument to %s must be a string, not %s", p->symbol, nameof(al)); 824768Speter return; 825768Speter } 8262073Smckusic put(2, O_CON24, width(al)); 8272073Smckusic al = argv[2]; 8282073Smckusic al = stkrval(al[1], NOFLAGS , RREQ ); 829768Speter } else { 8302073Smckusic put(2, O_CON24, 0); 8313076Smckusic put(2, PTR_CON, NIL); 832768Speter } 8332073Smckusic ap = stklval(argv[1], MOD|NOUSE); 834768Speter put(1, op); 835768Speter return; 836768Speter 837768Speter case O_NEW: 838768Speter case O_DISPOSE: 839768Speter if (argc == 0) { 840768Speter error("%s expects at least one argument", p->symbol); 841768Speter return; 842768Speter } 843768Speter ap = stklval(argv[1], op == O_NEW ? ( MOD | NOUSE ) : MOD ); 844768Speter if (ap == NIL) 845768Speter return; 846768Speter if (ap->class != PTR) { 847768Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 848768Speter return; 849768Speter } 850768Speter ap = ap->type; 851768Speter if (ap == NIL) 852768Speter return; 853*7966Smckusick if ((ap->nl_flags & NFILES) && op == O_DISPOSE) 854*7966Smckusick op = O_DFDISP; 855768Speter argv = argv[2]; 856768Speter if (argv != NIL) { 857768Speter if (ap->class != RECORD) { 858768Speter error("Record required when specifying variant tags"); 859768Speter return; 860768Speter } 861768Speter for (; argv != NIL; argv = argv[2]) { 862768Speter if (ap->ptr[NL_VARNT] == NIL) { 863768Speter error("Too many tag fields"); 864768Speter return; 865768Speter } 866768Speter if (!isconst(argv[1])) { 867768Speter error("Second and successive arguments to %s must be constants", p->symbol); 868768Speter return; 869768Speter } 870768Speter gconst(argv[1]); 871768Speter if (con.ctype == NIL) 872768Speter return; 873768Speter if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) { 874768Speter cerror("Specified tag constant type clashed with variant case selector type"); 875768Speter return; 876768Speter } 877768Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 878768Speter if (ap->range[0] == con.crval) 879768Speter break; 880768Speter if (ap == NIL) { 881768Speter error("No variant case label value equals specified constant value"); 882768Speter return; 883768Speter } 884768Speter ap = ap->ptr[NL_VTOREC]; 885768Speter } 886768Speter } 887768Speter put(2, op, width(ap)); 888768Speter return; 889768Speter 890768Speter case O_DATE: 891768Speter case O_TIME: 892768Speter if (argc != 1) { 893768Speter error("%s expects one argument", p->symbol); 894768Speter return; 895768Speter } 896768Speter ap = stklval(argv[1], MOD|NOUSE); 897768Speter if (ap == NIL) 898768Speter return; 899768Speter if (classify(ap) != TSTR || width(ap) != 10) { 900768Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 901768Speter return; 902768Speter } 903768Speter put(1, op); 904768Speter return; 905768Speter 906768Speter case O_HALT: 907768Speter if (argc != 0) { 908768Speter error("halt takes no arguments"); 909768Speter return; 910768Speter } 911768Speter put(1, op); 912768Speter noreach = 1; 913768Speter return; 914768Speter 915768Speter case O_ARGV: 916768Speter if (argc != 2) { 917768Speter error("argv takes two arguments"); 918768Speter return; 919768Speter } 920768Speter ap = stkrval(argv[1], NIL , RREQ ); 921768Speter if (ap == NIL) 922768Speter return; 923768Speter if (isnta(ap, "i")) { 924768Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 925768Speter return; 926768Speter } 927768Speter al = argv[2]; 928768Speter ap = stklval(al[1], MOD|NOUSE); 929768Speter if (ap == NIL) 930768Speter return; 931768Speter if (classify(ap) != TSTR) { 932768Speter error("argv's second argument must be a string, not %s", nameof(ap)); 933768Speter return; 934768Speter } 935768Speter put(2, op, width(ap)); 936768Speter return; 937768Speter 938768Speter case O_STLIM: 939768Speter if (argc != 1) { 940768Speter error("stlimit requires one argument"); 941768Speter return; 942768Speter } 943768Speter ap = stkrval(argv[1], NIL , RREQ ); 944768Speter if (ap == NIL) 945768Speter return; 946768Speter if (isnta(ap, "i")) { 947768Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 948768Speter return; 949768Speter } 950768Speter if (width(ap) != 4) 951768Speter put(1, O_STOI); 952768Speter put(1, op); 953768Speter return; 954768Speter 955768Speter case O_REMOVE: 956768Speter if (argc != 1) { 957768Speter error("remove expects one argument"); 958768Speter return; 959768Speter } 9602073Smckusic codeoff(); 961768Speter ap = stkrval(argv[1], NOFLAGS , RREQ ); 9622073Smckusic codeon(); 963768Speter if (ap == NIL) 964768Speter return; 965768Speter if (classify(ap) != TSTR) { 966768Speter error("remove's argument must be a string, not %s", nameof(ap)); 967768Speter return; 968768Speter } 969768Speter put(2, O_CON24, width(ap)); 9702073Smckusic ap = stkrval(argv[1], NOFLAGS , RREQ ); 971768Speter put(1, op); 972768Speter return; 973768Speter 974768Speter case O_LLIMIT: 975768Speter if (argc != 2) { 976768Speter error("linelimit expects two arguments"); 977768Speter return; 978768Speter } 979768Speter al = argv[2]; 980768Speter ap = stkrval(al[1], NIL , RREQ ); 981768Speter if (ap == NIL) 982768Speter return; 983768Speter if (isnta(ap, "i")) { 984768Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 985768Speter return; 986768Speter } 9872073Smckusic ap = stklval(argv[1], NOFLAGS|NOUSE); 9882073Smckusic if (ap == NIL) 9892073Smckusic return; 9902073Smckusic if (!text(ap)) { 9912073Smckusic error("linelimit's first argument must be a text file, not %s", nameof(ap)); 9922073Smckusic return; 9932073Smckusic } 994768Speter put(1, op); 995768Speter return; 996768Speter case O_PAGE: 997768Speter if (argc != 1) { 998768Speter error("page expects one argument"); 999768Speter return; 1000768Speter } 10012073Smckusic ap = stklval(argv[1], NIL , LREQ ); 1002768Speter if (ap == NIL) 1003768Speter return; 1004768Speter if (!text(ap)) { 1005768Speter error("Argument to page must be a text file, not %s", nameof(ap)); 1006768Speter return; 1007768Speter } 1008768Speter put(1, O_UNIT); 1009768Speter put(1, op); 1010768Speter return; 1011768Speter 10127928Smckusick case O_ASRT: 10137928Smckusick if (!opt('t')) 10147928Smckusick return; 10157928Smckusick if (argc == 0 || argc > 2) { 10167928Smckusick error("Assert expects one or two arguments"); 10177928Smckusick return; 10187928Smckusick } 10197928Smckusick if (argc == 2) { 10207928Smckusick /* 10217928Smckusick * Optional second argument is a string specifying 10227928Smckusick * why the assertion failed. 10237928Smckusick */ 10247928Smckusick al = argv[2]; 10257928Smckusick al = stkrval(al[1], NIL , RREQ ); 10267928Smckusick if (al == NIL) 10277928Smckusick return; 10287928Smckusick if (classify(al) != TSTR) { 10297928Smckusick error("Second argument to assert must be a string, not %s", nameof(al)); 10307928Smckusick return; 10317928Smckusick } 10327928Smckusick } else { 10337928Smckusick put(2, PTR_CON, NIL); 10347928Smckusick } 10357928Smckusick ap = stkrval(argv[1], NIL , RREQ ); 10367928Smckusick if (ap == NIL) 10377928Smckusick return; 10387928Smckusick if (isnta(ap, "b")) 10397928Smckusick error("Assert expression must be Boolean, not %ss", nameof(ap)); 10407928Smckusick put(1, O_ASRT); 10417928Smckusick return; 10427928Smckusick 1043768Speter case O_PACK: 1044768Speter if (argc != 3) { 1045768Speter error("pack expects three arguments"); 1046768Speter return; 1047768Speter } 1048768Speter pu = "pack(a,i,z)"; 10493076Smckusic pua = argv[1]; 10503076Smckusic al = argv[2]; 10513076Smckusic pui = al[1]; 10523076Smckusic alv = al[2]; 10533076Smckusic puz = alv[1]; 1054768Speter goto packunp; 1055768Speter case O_UNPACK: 1056768Speter if (argc != 3) { 1057768Speter error("unpack expects three arguments"); 1058768Speter return; 1059768Speter } 1060768Speter pu = "unpack(z,a,i)"; 10613076Smckusic puz = argv[1]; 10623076Smckusic al = argv[2]; 10633076Smckusic pua = al[1]; 10643076Smckusic alv = al[2]; 10653076Smckusic pui = alv[1]; 1066768Speter packunp: 10672073Smckusic codeoff(); 1068768Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 10692073Smckusic al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 10702073Smckusic codeon(); 1071768Speter if (ap == NIL) 1072768Speter return; 1073768Speter if (ap->class != ARRAY) { 1074768Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 1075768Speter return; 1076768Speter } 1077768Speter if (al->class != ARRAY) { 1078768Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 1079768Speter return; 1080768Speter } 1081768Speter if (al->type == NIL || ap->type == NIL) 1082768Speter return; 1083768Speter if (al->type != ap->type) { 1084768Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 1085768Speter return; 1086768Speter } 1087768Speter k = width(al); 1088768Speter itemwidth = width(ap->type); 1089768Speter ap = ap->chain; 1090768Speter al = al->chain; 1091768Speter if (ap->chain != NIL || al->chain != NIL) { 1092768Speter error("%s requires a and z to be single dimension arrays", pu); 1093768Speter return; 1094768Speter } 1095768Speter if (ap == NIL || al == NIL) 1096768Speter return; 1097768Speter /* 1098768Speter * al is the range for z i.e. u..v 1099768Speter * ap is the range for a i.e. m..n 1100768Speter * i will be n-m+1 1101768Speter * j will be v-u+1 1102768Speter */ 1103768Speter i = ap->range[1] - ap->range[0] + 1; 1104768Speter j = al->range[1] - al->range[0] + 1; 1105768Speter if (i < j) { 1106768Speter error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i); 1107768Speter return; 1108768Speter } 1109768Speter /* 1110768Speter * get n-m-(v-u) and m for the interpreter 1111768Speter */ 1112768Speter i -= j; 1113768Speter j = ap->range[0]; 11142073Smckusic put(2, O_CON24, k); 11152073Smckusic put(2, O_CON24, i); 11162073Smckusic put(2, O_CON24, j); 11172073Smckusic put(2, O_CON24, itemwidth); 11182073Smckusic al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 11192073Smckusic ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 11202073Smckusic ap = stkrval((int *) pui, NLNIL , RREQ ); 11212073Smckusic if (ap == NIL) 11222073Smckusic return; 11232073Smckusic put(1, op); 1124768Speter return; 1125768Speter case 0: 11267928Smckusick error("%s is an unimplemented extension", p->symbol); 1127768Speter return; 1128768Speter 1129768Speter default: 1130768Speter panic("proc case"); 1131768Speter } 1132768Speter } 1133768Speter #endif OBJ 1134