1768Speter /* Copyright (c) 1979 Regents of the University of California */ 2768Speter 3*8538Speter static char sccsid[] = "@(#)proc.c 1.15 10/14/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--; 182*8538Speter } else { 183768Speter /* 184768Speter * Set up for writing on 185768Speter * standard output. 186768Speter */ 187768Speter put(1, O_UNITOUT); 1887953Speter output->nl_flags |= NUSED; 189*8538Speter } 190*8538Speter } else { 191768Speter put(1, O_UNITOUT); 1927953Speter output->nl_flags |= NUSED; 193*8538Speter } 194768Speter /* 195768Speter * Loop and process each 196768Speter * of the arguments. 197768Speter */ 198768Speter for (; argv != NIL; argv = argv[2]) { 199768Speter /* 200768Speter * fmtspec indicates the type (CONstant or VARiable) 201768Speter * and number (none, WIDTH, and/or PRECision) 202768Speter * of the fields in the printf format for this 203768Speter * output variable. 2043172Smckusic * stkcnt is the number of bytes pushed on the stack 205768Speter * fmt is the format output indicator (D, E, F, O, X, S) 206768Speter * fmtstart = 0 for leading blank; = 1 for no blank 207768Speter */ 208768Speter fmtspec = NIL; 209768Speter stkcnt = 0; 210768Speter fmt = 'D'; 211768Speter fmtstart = 1; 212768Speter al = argv[1]; 213768Speter if (al == NIL) 214768Speter continue; 215768Speter if (al[0] == T_WEXP) 216768Speter alv = al[1]; 217768Speter else 218768Speter alv = al; 219768Speter if (alv == NIL) 220768Speter continue; 221768Speter codeoff(); 222768Speter ap = stkrval(alv, NIL , RREQ ); 223768Speter codeon(); 224768Speter if (ap == NIL) 225768Speter continue; 226768Speter typ = classify(ap); 227768Speter if (al[0] == T_WEXP) { 228768Speter /* 229768Speter * Handle width expressions. 230768Speter * The basic game here is that width 231768Speter * expressions get evaluated. If they 232768Speter * are constant, the value is placed 233768Speter * directly in the format string. 234768Speter * Otherwise the value is pushed onto 235768Speter * the stack and an indirection is 236768Speter * put into the format string. 237768Speter */ 238768Speter if (al[3] == OCT) 239768Speter fmt = 'O'; 240768Speter else if (al[3] == HEX) 241768Speter fmt = 'X'; 242768Speter else if (al[3] != NIL) { 243768Speter /* 244768Speter * Evaluate second format spec 245768Speter */ 246768Speter if ( constval(al[3]) 247768Speter && isa( con.ctype , "i" ) ) { 248768Speter fmtspec += CONPREC; 249768Speter prec = con.crval; 250768Speter } else { 251768Speter fmtspec += VARPREC; 252768Speter } 253768Speter fmt = 'f'; 254768Speter switch ( typ ) { 255768Speter case TINT: 256768Speter if ( opt( 's' ) ) { 257768Speter standard(); 258768Speter error("Writing %ss with two write widths is non-standard", clnames[typ]); 259768Speter } 260768Speter /* and fall through */ 261768Speter case TDOUBLE: 262768Speter break; 263768Speter default: 264768Speter error("Cannot write %ss with two write widths", clnames[typ]); 265768Speter continue; 266768Speter } 267768Speter } 268768Speter /* 269768Speter * Evaluate first format spec 270768Speter */ 271768Speter if (al[2] != NIL) { 272768Speter if ( constval(al[2]) 273768Speter && isa( con.ctype , "i" ) ) { 274768Speter fmtspec += CONWIDTH; 275768Speter field = con.crval; 276768Speter } else { 277768Speter fmtspec += VARWIDTH; 278768Speter } 279768Speter } 280768Speter if ((fmtspec & CONPREC) && prec < 0 || 281768Speter (fmtspec & CONWIDTH) && field < 0) { 282768Speter error("Negative widths are not allowed"); 283768Speter continue; 284768Speter } 2853179Smckusic if ( opt('s') && 2863179Smckusic ((fmtspec & CONPREC) && prec == 0 || 2873179Smckusic (fmtspec & CONWIDTH) && field == 0)) { 2883179Smckusic standard(); 2893179Smckusic error("Zero widths are non-standard"); 2903179Smckusic } 291768Speter } 292768Speter if (filetype != nl+T1CHAR) { 293768Speter if (fmt == 'O' || fmt == 'X') { 294768Speter error("Oct/hex allowed only on text files"); 295768Speter continue; 296768Speter } 297768Speter if (fmtspec) { 298768Speter error("Write widths allowed only on text files"); 299768Speter continue; 300768Speter } 301768Speter /* 302768Speter * Generalized write, i.e. 303768Speter * to a non-textfile. 304768Speter */ 3052073Smckusic stklval(file, NIL , LREQ ); 306768Speter put(1, O_FNIL); 307768Speter /* 308768Speter * file^ := ... 309768Speter */ 310768Speter ap = rvalue(argv[1], NIL); 311768Speter if (ap == NIL) 312768Speter continue; 313768Speter if (incompat(ap, filetype, argv[1])) { 314768Speter cerror("Type mismatch in write to non-text file"); 315768Speter continue; 316768Speter } 317768Speter convert(ap, filetype); 318768Speter put(2, O_AS, width(filetype)); 319768Speter /* 320768Speter * put(file) 321768Speter */ 322768Speter put(1, O_PUT); 323768Speter continue; 324768Speter } 325768Speter /* 326768Speter * Write to a textfile 327768Speter * 328768Speter * Evaluate the expression 329768Speter * to be written. 330768Speter */ 331768Speter if (fmt == 'O' || fmt == 'X') { 332768Speter if (opt('s')) { 333768Speter standard(); 334768Speter error("Oct and hex are non-standard"); 335768Speter } 336768Speter if (typ == TSTR || typ == TDOUBLE) { 337768Speter error("Can't write %ss with oct/hex", clnames[typ]); 338768Speter continue; 339768Speter } 340768Speter if (typ == TCHAR || typ == TBOOL) 341768Speter typ = TINT; 342768Speter } 343768Speter /* 344768Speter * Place the arguement on the stack. If there is 345768Speter * no format specified by the programmer, implement 346768Speter * the default. 347768Speter */ 348768Speter switch (typ) { 3496542Smckusick case TPTR: 3506542Smckusick warning(); 3516542Smckusick if (opt('s')) { 3526542Smckusick standard(); 3536542Smckusick } 3546542Smckusick error("Writing %ss to text files is non-standard", 3556542Smckusick clnames[typ]); 3566542Smckusick /* and fall through */ 357768Speter case TINT: 358768Speter if (fmt != 'f') { 359768Speter ap = stkrval(alv, NIL , RREQ ); 3603172Smckusic stkcnt += sizeof(long); 361768Speter } else { 362768Speter ap = stkrval(alv, NIL , RREQ ); 363768Speter put(1, O_ITOD); 3643172Smckusic stkcnt += sizeof(double); 365768Speter typ = TDOUBLE; 366768Speter goto tdouble; 367768Speter } 368768Speter if (fmtspec == NIL) { 369768Speter if (fmt == 'D') 370768Speter field = 10; 371768Speter else if (fmt == 'X') 372768Speter field = 8; 373768Speter else if (fmt == 'O') 374768Speter field = 11; 375768Speter else 376768Speter panic("fmt1"); 377768Speter fmtspec = CONWIDTH; 378768Speter } 379768Speter break; 380768Speter case TCHAR: 381768Speter tchar: 3822073Smckusic if (fmtspec == NIL) { 3832073Smckusic put(1, O_FILE); 3842073Smckusic ap = stkrval(alv, NIL , RREQ ); 3853172Smckusic convert(nl + T4INT, INT_TYP); 3863172Smckusic put(2, O_WRITEC, 3873172Smckusic sizeof(char *) + sizeof(int)); 3882073Smckusic fmtspec = SKIP; 3892073Smckusic break; 3902073Smckusic } 391768Speter ap = stkrval(alv, NIL , RREQ ); 3923172Smckusic convert(nl + T4INT, INT_TYP); 3933172Smckusic stkcnt += sizeof(int); 394768Speter fmt = 'c'; 395768Speter break; 396768Speter case TSCAL: 3971628Speter warning(); 398768Speter if (opt('s')) { 399768Speter standard(); 400768Speter } 4016542Smckusick error("Writing %ss to text files is non-standard", 4026542Smckusick clnames[typ]); 4036542Smckusick /* and fall through */ 404768Speter case TBOOL: 405768Speter stkrval(alv, NIL , RREQ ); 4063076Smckusic put(2, O_NAM, (long)listnames(ap)); 4073172Smckusic stkcnt += sizeof(char *); 408768Speter fmt = 's'; 409768Speter break; 410768Speter case TDOUBLE: 411768Speter ap = stkrval(alv, TDOUBLE , RREQ ); 4123172Smckusic stkcnt += sizeof(double); 413768Speter tdouble: 414768Speter switch (fmtspec) { 415768Speter case NIL: 4163076Smckusic # ifdef DEC11 4173076Smckusic field = 21; 4183076Smckusic # else 4193076Smckusic field = 22; 4203076Smckusic # endif DEC11 421768Speter prec = 14; 4223076Smckusic fmt = 'e'; 423768Speter fmtspec = CONWIDTH + CONPREC; 424768Speter break; 425768Speter case CONWIDTH: 426768Speter if (--field < 1) 427768Speter field = 1; 4283076Smckusic # ifdef DEC11 4293076Smckusic prec = field - 7; 4303076Smckusic # else 4313076Smckusic prec = field - 8; 4323076Smckusic # endif DEC11 433768Speter if (prec < 1) 434768Speter prec = 1; 435768Speter fmtspec += CONPREC; 4363076Smckusic fmt = 'e'; 437768Speter break; 438768Speter case CONWIDTH + CONPREC: 439768Speter case CONWIDTH + VARPREC: 440768Speter if (--field < 1) 441768Speter field = 1; 442768Speter } 443768Speter format[0] = ' '; 4448026Smckusick fmtstart = 1; 445768Speter break; 446768Speter case TSTR: 447768Speter constval( alv ); 448768Speter switch ( classify( con.ctype ) ) { 449768Speter case TCHAR: 450768Speter typ = TCHAR; 451768Speter goto tchar; 452768Speter case TSTR: 453768Speter strptr = con.cpval; 454768Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 455768Speter strptr = con.cpval; 456768Speter break; 457768Speter default: 458768Speter strnglen = width(ap); 459768Speter break; 460768Speter } 461768Speter fmt = 's'; 462768Speter strfmt = fmtspec; 463768Speter if (fmtspec == NIL) { 464768Speter fmtspec = SKIP; 465768Speter break; 466768Speter } 467768Speter if (fmtspec & CONWIDTH) { 468768Speter if (field <= strnglen) { 469768Speter fmtspec = SKIP; 470768Speter break; 471768Speter } else 472768Speter field -= strnglen; 473768Speter } 474768Speter /* 475768Speter * push string to implement leading blank padding 476768Speter */ 477768Speter put(2, O_LVCON, 2); 478768Speter putstr("", 0); 4793172Smckusic stkcnt += sizeof(char *); 480768Speter break; 481768Speter default: 482768Speter error("Can't write %ss to a text file", clnames[typ]); 483768Speter continue; 484768Speter } 485768Speter /* 486768Speter * If there is a variable precision, evaluate it onto 487768Speter * the stack 488768Speter */ 489768Speter if (fmtspec & VARPREC) { 490768Speter ap = stkrval(al[3], NIL , RREQ ); 491768Speter if (ap == NIL) 492768Speter continue; 493768Speter if (isnta(ap,"i")) { 494768Speter error("Second write width must be integer, not %s", nameof(ap)); 495768Speter continue; 496768Speter } 497768Speter if ( opt( 't' ) ) { 498768Speter put(3, O_MAX, 0, 0); 499768Speter } 5003172Smckusic convert(nl+T4INT, INT_TYP); 5013172Smckusic stkcnt += sizeof(int); 502768Speter } 503768Speter /* 504768Speter * If there is a variable width, evaluate it onto 505768Speter * the stack 506768Speter */ 507768Speter if (fmtspec & VARWIDTH) { 508768Speter if ( ( typ == TDOUBLE && fmtspec == VARWIDTH ) 509768Speter || typ == TSTR ) { 5103226Smckusic soffset = sizes[cbn].curtmps; 5113851Speter tempnlp = tmpalloc(sizeof(long), 5123226Smckusic nl+T4INT, REGOK); 5133851Speter put(2, O_LV | cbn << 8 + INDX, 5143851Speter tempnlp -> value[ NL_OFFS ] ); 515768Speter } 516768Speter ap = stkrval(al[2], NIL , RREQ ); 517768Speter if (ap == NIL) 518768Speter continue; 519768Speter if (isnta(ap,"i")) { 520768Speter error("First write width must be integer, not %s", nameof(ap)); 521768Speter continue; 522768Speter } 523768Speter /* 524768Speter * Perform special processing on widths based 525768Speter * on data type 526768Speter */ 527768Speter switch (typ) { 528768Speter case TDOUBLE: 529768Speter if (fmtspec == VARWIDTH) { 5303076Smckusic fmt = 'e'; 531768Speter put(1, O_AS4); 5323851Speter put(2, O_RV4 | cbn << 8 + INDX, 5333851Speter tempnlp -> value[NL_OFFS] ); 5343076Smckusic # ifdef DEC11 5353076Smckusic put(3, O_MAX, 8, 1); 5363076Smckusic # else 5373076Smckusic put(3, O_MAX, 9, 1); 5383076Smckusic # endif DEC11 5393172Smckusic convert(nl+T4INT, INT_TYP); 5403172Smckusic stkcnt += sizeof(int); 5413851Speter put(2, O_RV4 | cbn << 8 + INDX, 5423851Speter tempnlp->value[NL_OFFS] ); 543768Speter fmtspec += VARPREC; 5443226Smckusic tmpfree(&soffset); 545768Speter } 546768Speter put(3, O_MAX, 1, 1); 547768Speter break; 548768Speter case TSTR: 549768Speter put(1, O_AS4); 5503851Speter put(2, O_RV4 | cbn << 8 + INDX, 5513851Speter tempnlp -> value[ NL_OFFS ] ); 552768Speter put(3, O_MAX, strnglen, 0); 553768Speter break; 554768Speter default: 555768Speter if ( opt( 't' ) ) { 556768Speter put(3, O_MAX, 0, 0); 557768Speter } 558768Speter break; 559768Speter } 5603172Smckusic convert(nl+T4INT, INT_TYP); 5613172Smckusic stkcnt += sizeof(int); 562768Speter } 563768Speter /* 564768Speter * Generate the format string 565768Speter */ 566768Speter switch (fmtspec) { 567768Speter default: 568768Speter panic("fmt2"); 569768Speter case SKIP: 570768Speter break; 5712073Smckusic case NIL: 5722073Smckusic sprintf(&format[1], "%%%c", fmt); 5732073Smckusic goto fmtgen; 574768Speter case CONWIDTH: 5753076Smckusic sprintf(&format[1], "%%%d%c", field, fmt); 576768Speter goto fmtgen; 577768Speter case VARWIDTH: 578768Speter sprintf(&format[1], "%%*%c", fmt); 579768Speter goto fmtgen; 580768Speter case CONWIDTH + CONPREC: 5813076Smckusic sprintf(&format[1], "%%%d.%d%c", field, prec, fmt); 582768Speter goto fmtgen; 583768Speter case CONWIDTH + VARPREC: 5843076Smckusic sprintf(&format[1], "%%%d.*%c", field, fmt); 585768Speter goto fmtgen; 586768Speter case VARWIDTH + CONPREC: 5873076Smckusic sprintf(&format[1], "%%*.%d%c", prec, fmt); 588768Speter goto fmtgen; 589768Speter case VARWIDTH + VARPREC: 590768Speter sprintf(&format[1], "%%*.*%c", fmt); 591768Speter fmtgen: 592768Speter fmtlen = lenstr(&format[fmtstart], 0); 593768Speter put(2, O_LVCON, fmtlen); 594768Speter putstr(&format[fmtstart], 0); 595768Speter put(1, O_FILE); 5963172Smckusic stkcnt += 2 * sizeof(char *); 597768Speter put(2, O_WRITEF, stkcnt); 598768Speter } 599768Speter /* 600768Speter * Write the string after its blank padding 601768Speter */ 602768Speter if (typ == TSTR) { 603768Speter put(1, O_FILE); 6043172Smckusic put(2, CON_INT, 1); 605768Speter if (strfmt & VARWIDTH) { 6063851Speter put(2, O_RV4 | cbn << 8 + INDX , 6073851Speter tempnlp -> value[ NL_OFFS ] ); 608768Speter put(2, O_MIN, strnglen); 6093172Smckusic convert(nl+T4INT, INT_TYP); 6103226Smckusic tmpfree(&soffset); 611768Speter } else { 612768Speter if ((fmtspec & SKIP) && 613768Speter (strfmt & CONWIDTH)) { 614768Speter strnglen = field; 615768Speter } 6163172Smckusic put(2, CON_INT, strnglen); 617768Speter } 618768Speter ap = stkrval(alv, NIL , RREQ ); 6193172Smckusic put(2, O_WRITES, 6203172Smckusic 2 * sizeof(char *) + 2 * sizeof(int)); 621768Speter } 622768Speter } 623768Speter /* 624768Speter * Done with arguments. 625768Speter * Handle writeln and 626768Speter * insufficent number of args. 627768Speter */ 628768Speter switch (p->value[0] &~ NSTAND) { 629768Speter case O_WRITEF: 630768Speter if (argc == 0) 631768Speter error("Write requires an argument"); 632768Speter break; 633768Speter case O_MESSAGE: 634768Speter if (argc == 0) 635768Speter error("Message requires an argument"); 636768Speter case O_WRITLN: 637768Speter if (filetype != nl+T1CHAR) 638768Speter error("Can't 'writeln' a non text file"); 639768Speter put(1, O_WRITLN); 640768Speter break; 641768Speter } 642768Speter return; 643768Speter 644768Speter case O_READ4: 645768Speter case O_READLN: 646768Speter /* 647768Speter * Set up default 648768Speter * file "input". 649768Speter */ 650768Speter file = NIL; 651768Speter filetype = nl+T1CHAR; 652768Speter /* 653768Speter * Determine the file implied 654768Speter * for the read and generate 655768Speter * code to make it the active file. 656768Speter */ 657768Speter if (argv != NIL) { 658768Speter codeoff(); 659768Speter ap = stkrval(argv[1], NIL , RREQ ); 660768Speter codeon(); 661768Speter if (ap == NIL) 662768Speter argv = argv[2]; 663768Speter if (ap != NIL && ap->class == FILET) { 664768Speter /* 665768Speter * Got "read(f, ...", make 666768Speter * f the active file, and save 667768Speter * it and its type for use in 668768Speter * processing the rest of the 669768Speter * arguments to read. 670768Speter */ 671768Speter file = argv[1]; 672768Speter filetype = ap->type; 6732073Smckusic stklval(argv[1], NIL , LREQ ); 674768Speter put(1, O_UNIT); 675768Speter argv = argv[2]; 676768Speter argc--; 677768Speter } else { 678768Speter /* 679768Speter * Default is read from 680768Speter * standard input. 681768Speter */ 682768Speter put(1, O_UNITINP); 683768Speter input->nl_flags |= NUSED; 684768Speter } 685768Speter } else { 686768Speter put(1, O_UNITINP); 687768Speter input->nl_flags |= NUSED; 688768Speter } 689768Speter /* 690768Speter * Loop and process each 691768Speter * of the arguments. 692768Speter */ 693768Speter for (; argv != NIL; argv = argv[2]) { 694768Speter /* 695768Speter * Get the address of the target 696768Speter * on the stack. 697768Speter */ 698768Speter al = argv[1]; 699768Speter if (al == NIL) 700768Speter continue; 701768Speter if (al[0] != T_VAR) { 702768Speter error("Arguments to %s must be variables, not expressions", p->symbol); 703768Speter continue; 704768Speter } 705768Speter ap = stklval(al, MOD|ASGN|NOUSE); 706768Speter if (ap == NIL) 707768Speter continue; 708768Speter if (filetype != nl+T1CHAR) { 709768Speter /* 710768Speter * Generalized read, i.e. 711768Speter * from a non-textfile. 712768Speter */ 713768Speter if (incompat(filetype, ap, argv[1] )) { 714768Speter error("Type mismatch in read from non-text file"); 715768Speter continue; 716768Speter } 717768Speter /* 718768Speter * var := file ^; 719768Speter */ 720768Speter if (file != NIL) 7212073Smckusic stklval(file, NIL , LREQ ); 722768Speter else /* Magic */ 7233076Smckusic put(2, PTR_RV, (int)input->value[0]); 724768Speter put(1, O_FNIL); 725768Speter put(2, O_IND, width(filetype)); 726768Speter convert(filetype, ap); 727768Speter if (isa(ap, "bsci")) 728768Speter rangechk(ap, ap); 729768Speter put(2, O_AS, width(ap)); 730768Speter /* 731768Speter * get(file); 732768Speter */ 733768Speter put(1, O_GET); 734768Speter continue; 735768Speter } 736768Speter typ = classify(ap); 737768Speter op = rdops(typ); 738768Speter if (op == NIL) { 739768Speter error("Can't read %ss from a text file", clnames[typ]); 740768Speter continue; 741768Speter } 742768Speter if (op != O_READE) 743768Speter put(1, op); 744768Speter else { 7453076Smckusic put(2, op, (long)listnames(ap)); 7461628Speter warning(); 747768Speter if (opt('s')) { 748768Speter standard(); 749768Speter } 7501628Speter error("Reading scalars from text files is non-standard"); 751768Speter } 752768Speter /* 753768Speter * Data read is on the stack. 754768Speter * Assign it. 755768Speter */ 756768Speter if (op != O_READ8 && op != O_READE) 757768Speter rangechk(ap, op == O_READC ? ap : nl+T4INT); 758768Speter gen(O_AS2, O_AS2, width(ap), 759768Speter op == O_READ8 ? 8 : op == O_READ4 ? 4 : 2); 760768Speter } 761768Speter /* 762768Speter * Done with arguments. 763768Speter * Handle readln and 764768Speter * insufficient number of args. 765768Speter */ 766768Speter if (p->value[0] == O_READLN) { 767768Speter if (filetype != nl+T1CHAR) 768768Speter error("Can't 'readln' a non text file"); 769768Speter put(1, O_READLN); 770768Speter } 771768Speter else if (argc == 0) 772768Speter error("read requires an argument"); 773768Speter return; 774768Speter 775768Speter case O_GET: 776768Speter case O_PUT: 777768Speter if (argc != 1) { 778768Speter error("%s expects one argument", p->symbol); 779768Speter return; 780768Speter } 7812073Smckusic ap = stklval(argv[1], NIL , LREQ ); 782768Speter if (ap == NIL) 783768Speter return; 784768Speter if (ap->class != FILET) { 785768Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 786768Speter return; 787768Speter } 788768Speter put(1, O_UNIT); 789768Speter put(1, op); 790768Speter return; 791768Speter 792768Speter case O_RESET: 793768Speter case O_REWRITE: 794768Speter if (argc == 0 || argc > 2) { 795768Speter error("%s expects one or two arguments", p->symbol); 796768Speter return; 797768Speter } 798768Speter if (opt('s') && argc == 2) { 799768Speter standard(); 800768Speter error("Two argument forms of reset and rewrite are non-standard"); 801768Speter } 8022073Smckusic codeoff(); 803768Speter ap = stklval(argv[1], MOD|NOUSE); 8042073Smckusic codeon(); 805768Speter if (ap == NIL) 806768Speter return; 807768Speter if (ap->class != FILET) { 808768Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 809768Speter return; 810768Speter } 8112073Smckusic put(2, O_CON24, text(ap) ? 0: width(ap->type)); 812768Speter if (argc == 2) { 813768Speter /* 814768Speter * Optional second argument 815768Speter * is a string name of a 816768Speter * UNIX (R) file to be associated. 817768Speter */ 818768Speter al = argv[2]; 8192073Smckusic codeoff(); 820768Speter al = stkrval(al[1], NOFLAGS , RREQ ); 8212073Smckusic codeon(); 822768Speter if (al == NIL) 823768Speter return; 824768Speter if (classify(al) != TSTR) { 825768Speter error("Second argument to %s must be a string, not %s", p->symbol, nameof(al)); 826768Speter return; 827768Speter } 8282073Smckusic put(2, O_CON24, width(al)); 8292073Smckusic al = argv[2]; 8302073Smckusic al = stkrval(al[1], NOFLAGS , RREQ ); 831768Speter } else { 8322073Smckusic put(2, O_CON24, 0); 8333076Smckusic put(2, PTR_CON, NIL); 834768Speter } 8352073Smckusic ap = stklval(argv[1], MOD|NOUSE); 836768Speter put(1, op); 837768Speter return; 838768Speter 839768Speter case O_NEW: 840768Speter case O_DISPOSE: 841768Speter if (argc == 0) { 842768Speter error("%s expects at least one argument", p->symbol); 843768Speter return; 844768Speter } 845768Speter ap = stklval(argv[1], op == O_NEW ? ( MOD | NOUSE ) : MOD ); 846768Speter if (ap == NIL) 847768Speter return; 848768Speter if (ap->class != PTR) { 849768Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 850768Speter return; 851768Speter } 852768Speter ap = ap->type; 853768Speter if (ap == NIL) 854768Speter return; 8557966Smckusick if ((ap->nl_flags & NFILES) && op == O_DISPOSE) 8567966Smckusick op = O_DFDISP; 857768Speter argv = argv[2]; 858768Speter if (argv != NIL) { 859768Speter if (ap->class != RECORD) { 860768Speter error("Record required when specifying variant tags"); 861768Speter return; 862768Speter } 863768Speter for (; argv != NIL; argv = argv[2]) { 864768Speter if (ap->ptr[NL_VARNT] == NIL) { 865768Speter error("Too many tag fields"); 866768Speter return; 867768Speter } 868768Speter if (!isconst(argv[1])) { 869768Speter error("Second and successive arguments to %s must be constants", p->symbol); 870768Speter return; 871768Speter } 872768Speter gconst(argv[1]); 873768Speter if (con.ctype == NIL) 874768Speter return; 875768Speter if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) { 876768Speter cerror("Specified tag constant type clashed with variant case selector type"); 877768Speter return; 878768Speter } 879768Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 880768Speter if (ap->range[0] == con.crval) 881768Speter break; 882768Speter if (ap == NIL) { 883768Speter error("No variant case label value equals specified constant value"); 884768Speter return; 885768Speter } 886768Speter ap = ap->ptr[NL_VTOREC]; 887768Speter } 888768Speter } 889768Speter put(2, op, width(ap)); 890768Speter return; 891768Speter 892768Speter case O_DATE: 893768Speter case O_TIME: 894768Speter if (argc != 1) { 895768Speter error("%s expects one argument", p->symbol); 896768Speter return; 897768Speter } 898768Speter ap = stklval(argv[1], MOD|NOUSE); 899768Speter if (ap == NIL) 900768Speter return; 901768Speter if (classify(ap) != TSTR || width(ap) != 10) { 902768Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 903768Speter return; 904768Speter } 905768Speter put(1, op); 906768Speter return; 907768Speter 908768Speter case O_HALT: 909768Speter if (argc != 0) { 910768Speter error("halt takes no arguments"); 911768Speter return; 912768Speter } 913768Speter put(1, op); 914768Speter noreach = 1; 915768Speter return; 916768Speter 917768Speter case O_ARGV: 918768Speter if (argc != 2) { 919768Speter error("argv takes two arguments"); 920768Speter return; 921768Speter } 922768Speter ap = stkrval(argv[1], NIL , RREQ ); 923768Speter if (ap == NIL) 924768Speter return; 925768Speter if (isnta(ap, "i")) { 926768Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 927768Speter return; 928768Speter } 929768Speter al = argv[2]; 930768Speter ap = stklval(al[1], MOD|NOUSE); 931768Speter if (ap == NIL) 932768Speter return; 933768Speter if (classify(ap) != TSTR) { 934768Speter error("argv's second argument must be a string, not %s", nameof(ap)); 935768Speter return; 936768Speter } 937768Speter put(2, op, width(ap)); 938768Speter return; 939768Speter 940768Speter case O_STLIM: 941768Speter if (argc != 1) { 942768Speter error("stlimit requires one argument"); 943768Speter return; 944768Speter } 945768Speter ap = stkrval(argv[1], NIL , RREQ ); 946768Speter if (ap == NIL) 947768Speter return; 948768Speter if (isnta(ap, "i")) { 949768Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 950768Speter return; 951768Speter } 952768Speter if (width(ap) != 4) 953768Speter put(1, O_STOI); 954768Speter put(1, op); 955768Speter return; 956768Speter 957768Speter case O_REMOVE: 958768Speter if (argc != 1) { 959768Speter error("remove expects one argument"); 960768Speter return; 961768Speter } 9622073Smckusic codeoff(); 963768Speter ap = stkrval(argv[1], NOFLAGS , RREQ ); 9642073Smckusic codeon(); 965768Speter if (ap == NIL) 966768Speter return; 967768Speter if (classify(ap) != TSTR) { 968768Speter error("remove's argument must be a string, not %s", nameof(ap)); 969768Speter return; 970768Speter } 971768Speter put(2, O_CON24, width(ap)); 9722073Smckusic ap = stkrval(argv[1], NOFLAGS , RREQ ); 973768Speter put(1, op); 974768Speter return; 975768Speter 976768Speter case O_LLIMIT: 977768Speter if (argc != 2) { 978768Speter error("linelimit expects two arguments"); 979768Speter return; 980768Speter } 981768Speter al = argv[2]; 982768Speter ap = stkrval(al[1], NIL , RREQ ); 983768Speter if (ap == NIL) 984768Speter return; 985768Speter if (isnta(ap, "i")) { 986768Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 987768Speter return; 988768Speter } 9892073Smckusic ap = stklval(argv[1], NOFLAGS|NOUSE); 9902073Smckusic if (ap == NIL) 9912073Smckusic return; 9922073Smckusic if (!text(ap)) { 9932073Smckusic error("linelimit's first argument must be a text file, not %s", nameof(ap)); 9942073Smckusic return; 9952073Smckusic } 996768Speter put(1, op); 997768Speter return; 998768Speter case O_PAGE: 999768Speter if (argc != 1) { 1000768Speter error("page expects one argument"); 1001768Speter return; 1002768Speter } 10032073Smckusic ap = stklval(argv[1], NIL , LREQ ); 1004768Speter if (ap == NIL) 1005768Speter return; 1006768Speter if (!text(ap)) { 1007768Speter error("Argument to page must be a text file, not %s", nameof(ap)); 1008768Speter return; 1009768Speter } 1010768Speter put(1, O_UNIT); 1011768Speter put(1, op); 1012768Speter return; 1013768Speter 10147928Smckusick case O_ASRT: 10157928Smckusick if (!opt('t')) 10167928Smckusick return; 10177928Smckusick if (argc == 0 || argc > 2) { 10187928Smckusick error("Assert expects one or two arguments"); 10197928Smckusick return; 10207928Smckusick } 10217928Smckusick if (argc == 2) { 10227928Smckusick /* 10237928Smckusick * Optional second argument is a string specifying 10247928Smckusick * why the assertion failed. 10257928Smckusick */ 10267928Smckusick al = argv[2]; 10277928Smckusick al = stkrval(al[1], NIL , RREQ ); 10287928Smckusick if (al == NIL) 10297928Smckusick return; 10307928Smckusick if (classify(al) != TSTR) { 10317928Smckusick error("Second argument to assert must be a string, not %s", nameof(al)); 10327928Smckusick return; 10337928Smckusick } 10347928Smckusick } else { 10357928Smckusick put(2, PTR_CON, NIL); 10367928Smckusick } 10377928Smckusick ap = stkrval(argv[1], NIL , RREQ ); 10387928Smckusick if (ap == NIL) 10397928Smckusick return; 10407928Smckusick if (isnta(ap, "b")) 10417928Smckusick error("Assert expression must be Boolean, not %ss", nameof(ap)); 10427928Smckusick put(1, O_ASRT); 10437928Smckusick return; 10447928Smckusick 1045768Speter case O_PACK: 1046768Speter if (argc != 3) { 1047768Speter error("pack expects three arguments"); 1048768Speter return; 1049768Speter } 1050768Speter pu = "pack(a,i,z)"; 10513076Smckusic pua = argv[1]; 10523076Smckusic al = argv[2]; 10533076Smckusic pui = al[1]; 10543076Smckusic alv = al[2]; 10553076Smckusic puz = alv[1]; 1056768Speter goto packunp; 1057768Speter case O_UNPACK: 1058768Speter if (argc != 3) { 1059768Speter error("unpack expects three arguments"); 1060768Speter return; 1061768Speter } 1062768Speter pu = "unpack(z,a,i)"; 10633076Smckusic puz = argv[1]; 10643076Smckusic al = argv[2]; 10653076Smckusic pua = al[1]; 10663076Smckusic alv = al[2]; 10673076Smckusic pui = alv[1]; 1068768Speter packunp: 10692073Smckusic codeoff(); 1070768Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 10712073Smckusic al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 10722073Smckusic codeon(); 1073768Speter if (ap == NIL) 1074768Speter return; 1075768Speter if (ap->class != ARRAY) { 1076768Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 1077768Speter return; 1078768Speter } 1079768Speter if (al->class != ARRAY) { 1080768Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 1081768Speter return; 1082768Speter } 1083768Speter if (al->type == NIL || ap->type == NIL) 1084768Speter return; 1085768Speter if (al->type != ap->type) { 1086768Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 1087768Speter return; 1088768Speter } 1089768Speter k = width(al); 1090768Speter itemwidth = width(ap->type); 1091768Speter ap = ap->chain; 1092768Speter al = al->chain; 1093768Speter if (ap->chain != NIL || al->chain != NIL) { 1094768Speter error("%s requires a and z to be single dimension arrays", pu); 1095768Speter return; 1096768Speter } 1097768Speter if (ap == NIL || al == NIL) 1098768Speter return; 1099768Speter /* 1100768Speter * al is the range for z i.e. u..v 1101768Speter * ap is the range for a i.e. m..n 1102768Speter * i will be n-m+1 1103768Speter * j will be v-u+1 1104768Speter */ 1105768Speter i = ap->range[1] - ap->range[0] + 1; 1106768Speter j = al->range[1] - al->range[0] + 1; 1107768Speter if (i < j) { 1108768Speter error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i); 1109768Speter return; 1110768Speter } 1111768Speter /* 1112768Speter * get n-m-(v-u) and m for the interpreter 1113768Speter */ 1114768Speter i -= j; 1115768Speter j = ap->range[0]; 11162073Smckusic put(2, O_CON24, k); 11172073Smckusic put(2, O_CON24, i); 11182073Smckusic put(2, O_CON24, j); 11192073Smckusic put(2, O_CON24, itemwidth); 11202073Smckusic al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 11212073Smckusic ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 11222073Smckusic ap = stkrval((int *) pui, NLNIL , RREQ ); 11232073Smckusic if (ap == NIL) 11242073Smckusic return; 11252073Smckusic put(1, op); 1126768Speter return; 1127768Speter case 0: 11287928Smckusick error("%s is an unimplemented extension", p->symbol); 1129768Speter return; 1130768Speter 1131768Speter default: 1132768Speter panic("proc case"); 1133768Speter } 1134768Speter } 1135768Speter #endif OBJ 1136