1768Speter /* Copyright (c) 1979 Regents of the University of California */ 2768Speter 3*11327Speter static char sccsid[] = "@(#)proc.c 1.17 02/28/83"; 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" 14*11327Speter #include "tmps.h" 15768Speter 16768Speter /* 179230Smckusick * The constant REALSPC defines the amount of forced padding preceeding 189230Smckusick * real numbers when they are printed. If REALSPC == 0, then no padding 199230Smckusick * is added, REALSPC == 1 adds one extra blank irregardless of the width 209230Smckusick * specified by the user. 219230Smckusick * 229230Smckusick * N.B. - Values greater than one require program mods. 239230Smckusick */ 249230Smckusick #define REALSPC 0 259230Smckusick 269230Smckusick /* 27768Speter * The following array is used to determine which classes may be read 28768Speter * from textfiles. It is indexed by the return value from classify. 29768Speter */ 30768Speter #define rdops(x) rdxxxx[(x)-(TFIRST)] 31768Speter 32768Speter int rdxxxx[] = { 33768Speter 0, /* -7 file types */ 34768Speter 0, /* -6 record types */ 35768Speter 0, /* -5 array types */ 36768Speter O_READE, /* -4 scalar types */ 37768Speter 0, /* -3 pointer types */ 38768Speter 0, /* -2 set types */ 39768Speter 0, /* -1 string types */ 40768Speter 0, /* 0 nil, no type */ 41768Speter O_READE, /* 1 boolean */ 42768Speter O_READC, /* 2 character */ 43768Speter O_READ4, /* 3 integer */ 44768Speter O_READ8 /* 4 real */ 45768Speter }; 46768Speter 47768Speter /* 48768Speter * Proc handles procedure calls. 49768Speter * Non-builtin procedures are "buck-passed" to func (with a flag 50768Speter * indicating that they are actually procedures. 51768Speter * builtin procedures are handled here. 52768Speter */ 53768Speter proc(r) 54768Speter int *r; 55768Speter { 56768Speter register struct nl *p; 57768Speter register int *alv, *al, op; 58768Speter struct nl *filetype, *ap; 59768Speter int argc, *argv, typ, fmtspec, strfmt, stkcnt, *file; 60768Speter char fmt, format[20], *strptr; 61768Speter int prec, field, strnglen, fmtlen, fmtstart, pu; 62768Speter int *pua, *pui, *puz; 63768Speter int i, j, k; 64768Speter int itemwidth; 653226Smckusic struct tmps soffset; 663851Speter struct nl *tempnlp; 67768Speter 68768Speter #define CONPREC 4 69768Speter #define VARPREC 8 70768Speter #define CONWIDTH 1 71768Speter #define VARWIDTH 2 72768Speter #define SKIP 16 73768Speter 74768Speter /* 75768Speter * Verify that the name is 76768Speter * defined and is that of a 77768Speter * procedure. 78768Speter */ 79768Speter p = lookup(r[2]); 80768Speter if (p == NIL) { 81768Speter rvlist(r[3]); 82768Speter return; 83768Speter } 841198Speter if (p->class != PROC && p->class != FPROC) { 85768Speter error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]); 86768Speter rvlist(r[3]); 87768Speter return; 88768Speter } 89768Speter argv = r[3]; 90768Speter 91768Speter /* 92768Speter * Call handles user defined 93768Speter * procedures and functions. 94768Speter */ 95768Speter if (bn != 0) { 96768Speter call(p, argv, PROC, bn); 97768Speter return; 98768Speter } 99768Speter 100768Speter /* 101768Speter * Call to built-in procedure. 102768Speter * Count the arguments. 103768Speter */ 104768Speter argc = 0; 105768Speter for (al = argv; al != NIL; al = al[2]) 106768Speter argc++; 107768Speter 108768Speter /* 109768Speter * Switch on the operator 110768Speter * associated with the built-in 111768Speter * procedure in the namelist 112768Speter */ 113768Speter op = p->value[0] &~ NSTAND; 114768Speter if (opt('s') && (p->value[0] & NSTAND)) { 115768Speter standard(); 116768Speter error("%s is a nonstandard procedure", p->symbol); 117768Speter } 118768Speter switch (op) { 119768Speter 120768Speter case O_ABORT: 121768Speter if (argc != 0) 122768Speter error("null takes no arguments"); 123768Speter return; 124768Speter 125768Speter case O_FLUSH: 126768Speter if (argc == 0) { 127768Speter put(1, O_MESSAGE); 128768Speter return; 129768Speter } 130768Speter if (argc != 1) { 131768Speter error("flush takes at most one argument"); 132768Speter return; 133768Speter } 1342073Smckusic ap = stklval(argv[1], NIL , LREQ ); 135768Speter if (ap == NIL) 136768Speter return; 137768Speter if (ap->class != FILET) { 138768Speter error("flush's argument must be a file, not %s", nameof(ap)); 139768Speter return; 140768Speter } 141768Speter put(1, op); 142768Speter return; 143768Speter 144768Speter case O_MESSAGE: 145768Speter case O_WRITEF: 146768Speter case O_WRITLN: 147768Speter /* 148768Speter * Set up default file "output"'s type 149768Speter */ 150768Speter file = NIL; 151768Speter filetype = nl+T1CHAR; 152768Speter /* 153768Speter * Determine the file implied 154768Speter * for the write and generate 155768Speter * code to make it the active file. 156768Speter */ 157768Speter if (op == O_MESSAGE) { 158768Speter /* 159768Speter * For message, all that matters 160768Speter * is that the filetype is 161768Speter * a character file. 162768Speter * Thus "output" will suit us fine. 163768Speter */ 164768Speter put(1, O_MESSAGE); 165768Speter } else if (argv != NIL && (al = argv[1])[0] != T_WEXP) { 166768Speter /* 167768Speter * If there is a first argument which has 168768Speter * no write widths, then it is potentially 169768Speter * a file name. 170768Speter */ 171768Speter codeoff(); 172768Speter ap = stkrval(argv[1], NIL , RREQ ); 173768Speter codeon(); 174768Speter if (ap == NIL) 175768Speter argv = argv[2]; 176768Speter if (ap != NIL && ap->class == FILET) { 177768Speter /* 178768Speter * Got "write(f, ...", make 179768Speter * f the active file, and save 180768Speter * it and its type for use in 181768Speter * processing the rest of the 182768Speter * arguments to write. 183768Speter */ 184768Speter file = argv[1]; 185768Speter filetype = ap->type; 1862073Smckusic stklval(argv[1], NIL , LREQ ); 187768Speter put(1, O_UNIT); 188768Speter /* 189768Speter * Skip over the first argument 190768Speter */ 191768Speter argv = argv[2]; 192768Speter argc--; 1938538Speter } else { 194768Speter /* 195768Speter * Set up for writing on 196768Speter * standard output. 197768Speter */ 198768Speter put(1, O_UNITOUT); 1997953Speter output->nl_flags |= NUSED; 2008538Speter } 2018538Speter } else { 202768Speter put(1, O_UNITOUT); 2037953Speter output->nl_flags |= NUSED; 2048538Speter } 205768Speter /* 206768Speter * Loop and process each 207768Speter * of the arguments. 208768Speter */ 209768Speter for (; argv != NIL; argv = argv[2]) { 210768Speter /* 211768Speter * fmtspec indicates the type (CONstant or VARiable) 212768Speter * and number (none, WIDTH, and/or PRECision) 213768Speter * of the fields in the printf format for this 214768Speter * output variable. 2153172Smckusic * stkcnt is the number of bytes pushed on the stack 216768Speter * fmt is the format output indicator (D, E, F, O, X, S) 217768Speter * fmtstart = 0 for leading blank; = 1 for no blank 218768Speter */ 219768Speter fmtspec = NIL; 220768Speter stkcnt = 0; 221768Speter fmt = 'D'; 222768Speter fmtstart = 1; 223768Speter al = argv[1]; 224768Speter if (al == NIL) 225768Speter continue; 226768Speter if (al[0] == T_WEXP) 227768Speter alv = al[1]; 228768Speter else 229768Speter alv = al; 230768Speter if (alv == NIL) 231768Speter continue; 232768Speter codeoff(); 233768Speter ap = stkrval(alv, NIL , RREQ ); 234768Speter codeon(); 235768Speter if (ap == NIL) 236768Speter continue; 237768Speter typ = classify(ap); 238768Speter if (al[0] == T_WEXP) { 239768Speter /* 240768Speter * Handle width expressions. 241768Speter * The basic game here is that width 242768Speter * expressions get evaluated. If they 243768Speter * are constant, the value is placed 244768Speter * directly in the format string. 245768Speter * Otherwise the value is pushed onto 246768Speter * the stack and an indirection is 247768Speter * put into the format string. 248768Speter */ 249768Speter if (al[3] == OCT) 250768Speter fmt = 'O'; 251768Speter else if (al[3] == HEX) 252768Speter fmt = 'X'; 253768Speter else if (al[3] != NIL) { 254768Speter /* 255768Speter * Evaluate second format spec 256768Speter */ 257768Speter if ( constval(al[3]) 258768Speter && isa( con.ctype , "i" ) ) { 259768Speter fmtspec += CONPREC; 260768Speter prec = con.crval; 261768Speter } else { 262768Speter fmtspec += VARPREC; 263768Speter } 264768Speter fmt = 'f'; 265768Speter switch ( typ ) { 266768Speter case TINT: 267768Speter if ( opt( 's' ) ) { 268768Speter standard(); 269768Speter error("Writing %ss with two write widths is non-standard", clnames[typ]); 270768Speter } 271768Speter /* and fall through */ 272768Speter case TDOUBLE: 273768Speter break; 274768Speter default: 275768Speter error("Cannot write %ss with two write widths", clnames[typ]); 276768Speter continue; 277768Speter } 278768Speter } 279768Speter /* 280768Speter * Evaluate first format spec 281768Speter */ 282768Speter if (al[2] != NIL) { 283768Speter if ( constval(al[2]) 284768Speter && isa( con.ctype , "i" ) ) { 285768Speter fmtspec += CONWIDTH; 286768Speter field = con.crval; 287768Speter } else { 288768Speter fmtspec += VARWIDTH; 289768Speter } 290768Speter } 291768Speter if ((fmtspec & CONPREC) && prec < 0 || 292768Speter (fmtspec & CONWIDTH) && field < 0) { 293768Speter error("Negative widths are not allowed"); 294768Speter continue; 295768Speter } 2963179Smckusic if ( opt('s') && 2973179Smckusic ((fmtspec & CONPREC) && prec == 0 || 2983179Smckusic (fmtspec & CONWIDTH) && field == 0)) { 2993179Smckusic standard(); 3003179Smckusic error("Zero widths are non-standard"); 3013179Smckusic } 302768Speter } 303768Speter if (filetype != nl+T1CHAR) { 304768Speter if (fmt == 'O' || fmt == 'X') { 305768Speter error("Oct/hex allowed only on text files"); 306768Speter continue; 307768Speter } 308768Speter if (fmtspec) { 309768Speter error("Write widths allowed only on text files"); 310768Speter continue; 311768Speter } 312768Speter /* 313768Speter * Generalized write, i.e. 314768Speter * to a non-textfile. 315768Speter */ 3162073Smckusic stklval(file, NIL , LREQ ); 317768Speter put(1, O_FNIL); 318768Speter /* 319768Speter * file^ := ... 320768Speter */ 321768Speter ap = rvalue(argv[1], NIL); 322768Speter if (ap == NIL) 323768Speter continue; 324768Speter if (incompat(ap, filetype, argv[1])) { 325768Speter cerror("Type mismatch in write to non-text file"); 326768Speter continue; 327768Speter } 328768Speter convert(ap, filetype); 329768Speter put(2, O_AS, width(filetype)); 330768Speter /* 331768Speter * put(file) 332768Speter */ 333768Speter put(1, O_PUT); 334768Speter continue; 335768Speter } 336768Speter /* 337768Speter * Write to a textfile 338768Speter * 339768Speter * Evaluate the expression 340768Speter * to be written. 341768Speter */ 342768Speter if (fmt == 'O' || fmt == 'X') { 343768Speter if (opt('s')) { 344768Speter standard(); 345768Speter error("Oct and hex are non-standard"); 346768Speter } 347768Speter if (typ == TSTR || typ == TDOUBLE) { 348768Speter error("Can't write %ss with oct/hex", clnames[typ]); 349768Speter continue; 350768Speter } 351768Speter if (typ == TCHAR || typ == TBOOL) 352768Speter typ = TINT; 353768Speter } 354768Speter /* 355768Speter * Place the arguement on the stack. If there is 356768Speter * no format specified by the programmer, implement 357768Speter * the default. 358768Speter */ 359768Speter switch (typ) { 3606542Smckusick case TPTR: 3616542Smckusick warning(); 3626542Smckusick if (opt('s')) { 3636542Smckusick standard(); 3646542Smckusick } 3656542Smckusick error("Writing %ss to text files is non-standard", 3666542Smckusick clnames[typ]); 3676542Smckusick /* and fall through */ 368768Speter case TINT: 369768Speter if (fmt != 'f') { 370768Speter ap = stkrval(alv, NIL , RREQ ); 3713172Smckusic stkcnt += sizeof(long); 372768Speter } else { 373768Speter ap = stkrval(alv, NIL , RREQ ); 374768Speter put(1, O_ITOD); 3753172Smckusic stkcnt += sizeof(double); 376768Speter typ = TDOUBLE; 377768Speter goto tdouble; 378768Speter } 379768Speter if (fmtspec == NIL) { 380768Speter if (fmt == 'D') 381768Speter field = 10; 382768Speter else if (fmt == 'X') 383768Speter field = 8; 384768Speter else if (fmt == 'O') 385768Speter field = 11; 386768Speter else 387768Speter panic("fmt1"); 388768Speter fmtspec = CONWIDTH; 389768Speter } 390768Speter break; 391768Speter case TCHAR: 392768Speter tchar: 3932073Smckusic if (fmtspec == NIL) { 3942073Smckusic put(1, O_FILE); 3952073Smckusic ap = stkrval(alv, NIL , RREQ ); 3963172Smckusic convert(nl + T4INT, INT_TYP); 3973172Smckusic put(2, O_WRITEC, 3983172Smckusic sizeof(char *) + sizeof(int)); 3992073Smckusic fmtspec = SKIP; 4002073Smckusic break; 4012073Smckusic } 402768Speter ap = stkrval(alv, NIL , RREQ ); 4033172Smckusic convert(nl + T4INT, INT_TYP); 4043172Smckusic stkcnt += sizeof(int); 405768Speter fmt = 'c'; 406768Speter break; 407768Speter case TSCAL: 4081628Speter warning(); 409768Speter if (opt('s')) { 410768Speter standard(); 411768Speter } 4126542Smckusick error("Writing %ss to text files is non-standard", 4136542Smckusick clnames[typ]); 4146542Smckusick /* and fall through */ 415768Speter case TBOOL: 416768Speter stkrval(alv, NIL , RREQ ); 4173076Smckusic put(2, O_NAM, (long)listnames(ap)); 4183172Smckusic stkcnt += sizeof(char *); 419768Speter fmt = 's'; 420768Speter break; 421768Speter case TDOUBLE: 422768Speter ap = stkrval(alv, TDOUBLE , RREQ ); 4233172Smckusic stkcnt += sizeof(double); 424768Speter tdouble: 425768Speter switch (fmtspec) { 426768Speter case NIL: 4273076Smckusic # ifdef DEC11 4283076Smckusic field = 21; 4293076Smckusic # else 4303076Smckusic field = 22; 4313076Smckusic # endif DEC11 432768Speter prec = 14; 4333076Smckusic fmt = 'e'; 434768Speter fmtspec = CONWIDTH + CONPREC; 435768Speter break; 436768Speter case CONWIDTH: 4379230Smckusick field -= REALSPC; 4389230Smckusick if (field < 1) 439768Speter field = 1; 4403076Smckusic # ifdef DEC11 4413076Smckusic prec = field - 7; 4423076Smckusic # else 4433076Smckusic prec = field - 8; 4443076Smckusic # endif DEC11 445768Speter if (prec < 1) 446768Speter prec = 1; 447768Speter fmtspec += CONPREC; 4483076Smckusic fmt = 'e'; 449768Speter break; 450768Speter case CONWIDTH + CONPREC: 451768Speter case CONWIDTH + VARPREC: 4529230Smckusick field -= REALSPC; 4539230Smckusick if (field < 1) 454768Speter field = 1; 455768Speter } 456768Speter format[0] = ' '; 4579230Smckusick fmtstart = 1 - REALSPC; 458768Speter break; 459768Speter case TSTR: 460768Speter constval( alv ); 461768Speter switch ( classify( con.ctype ) ) { 462768Speter case TCHAR: 463768Speter typ = TCHAR; 464768Speter goto tchar; 465768Speter case TSTR: 466768Speter strptr = con.cpval; 467768Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 468768Speter strptr = con.cpval; 469768Speter break; 470768Speter default: 471768Speter strnglen = width(ap); 472768Speter break; 473768Speter } 474768Speter fmt = 's'; 475768Speter strfmt = fmtspec; 476768Speter if (fmtspec == NIL) { 477768Speter fmtspec = SKIP; 478768Speter break; 479768Speter } 480768Speter if (fmtspec & CONWIDTH) { 481768Speter if (field <= strnglen) { 482768Speter fmtspec = SKIP; 483768Speter break; 484768Speter } else 485768Speter field -= strnglen; 486768Speter } 487768Speter /* 488768Speter * push string to implement leading blank padding 489768Speter */ 490768Speter put(2, O_LVCON, 2); 491768Speter putstr("", 0); 4923172Smckusic stkcnt += sizeof(char *); 493768Speter break; 494768Speter default: 495768Speter error("Can't write %ss to a text file", clnames[typ]); 496768Speter continue; 497768Speter } 498768Speter /* 499768Speter * If there is a variable precision, evaluate it onto 500768Speter * the stack 501768Speter */ 502768Speter if (fmtspec & VARPREC) { 503768Speter ap = stkrval(al[3], NIL , RREQ ); 504768Speter if (ap == NIL) 505768Speter continue; 506768Speter if (isnta(ap,"i")) { 507768Speter error("Second write width must be integer, not %s", nameof(ap)); 508768Speter continue; 509768Speter } 510768Speter if ( opt( 't' ) ) { 511768Speter put(3, O_MAX, 0, 0); 512768Speter } 5133172Smckusic convert(nl+T4INT, INT_TYP); 5143172Smckusic stkcnt += sizeof(int); 515768Speter } 516768Speter /* 517768Speter * If there is a variable width, evaluate it onto 518768Speter * the stack 519768Speter */ 520768Speter if (fmtspec & VARWIDTH) { 521768Speter if ( ( typ == TDOUBLE && fmtspec == VARWIDTH ) 522768Speter || typ == TSTR ) { 5233226Smckusic soffset = sizes[cbn].curtmps; 5243851Speter tempnlp = tmpalloc(sizeof(long), 5253226Smckusic nl+T4INT, REGOK); 5263851Speter put(2, O_LV | cbn << 8 + INDX, 5273851Speter tempnlp -> value[ NL_OFFS ] ); 528768Speter } 529768Speter ap = stkrval(al[2], NIL , RREQ ); 530768Speter if (ap == NIL) 531768Speter continue; 532768Speter if (isnta(ap,"i")) { 533768Speter error("First write width must be integer, not %s", nameof(ap)); 534768Speter continue; 535768Speter } 536768Speter /* 537768Speter * Perform special processing on widths based 538768Speter * on data type 539768Speter */ 540768Speter switch (typ) { 541768Speter case TDOUBLE: 542768Speter if (fmtspec == VARWIDTH) { 5433076Smckusic fmt = 'e'; 544768Speter put(1, O_AS4); 5453851Speter put(2, O_RV4 | cbn << 8 + INDX, 5463851Speter tempnlp -> value[NL_OFFS] ); 5473076Smckusic # ifdef DEC11 5489230Smckusick put(3, O_MAX, 7 + REALSPC, 1); 5493076Smckusic # else 5509230Smckusick put(3, O_MAX, 8 + REALSPC, 1); 5513076Smckusic # endif DEC11 5523172Smckusic convert(nl+T4INT, INT_TYP); 5533172Smckusic stkcnt += sizeof(int); 5543851Speter put(2, O_RV4 | cbn << 8 + INDX, 5553851Speter tempnlp->value[NL_OFFS] ); 556768Speter fmtspec += VARPREC; 5573226Smckusic tmpfree(&soffset); 558768Speter } 5599230Smckusick put(3, O_MAX, REALSPC, 1); 560768Speter break; 561768Speter case TSTR: 562768Speter put(1, O_AS4); 5633851Speter put(2, O_RV4 | cbn << 8 + INDX, 5643851Speter tempnlp -> value[ NL_OFFS ] ); 565768Speter put(3, O_MAX, strnglen, 0); 566768Speter break; 567768Speter default: 568768Speter if ( opt( 't' ) ) { 569768Speter put(3, O_MAX, 0, 0); 570768Speter } 571768Speter break; 572768Speter } 5733172Smckusic convert(nl+T4INT, INT_TYP); 5743172Smckusic stkcnt += sizeof(int); 575768Speter } 576768Speter /* 577768Speter * Generate the format string 578768Speter */ 579768Speter switch (fmtspec) { 580768Speter default: 581768Speter panic("fmt2"); 582768Speter case SKIP: 583768Speter break; 5842073Smckusic case NIL: 5852073Smckusic sprintf(&format[1], "%%%c", fmt); 5862073Smckusic goto fmtgen; 587768Speter case CONWIDTH: 5883076Smckusic sprintf(&format[1], "%%%d%c", field, fmt); 589768Speter goto fmtgen; 590768Speter case VARWIDTH: 591768Speter sprintf(&format[1], "%%*%c", fmt); 592768Speter goto fmtgen; 593768Speter case CONWIDTH + CONPREC: 5943076Smckusic sprintf(&format[1], "%%%d.%d%c", field, prec, fmt); 595768Speter goto fmtgen; 596768Speter case CONWIDTH + VARPREC: 5973076Smckusic sprintf(&format[1], "%%%d.*%c", field, fmt); 598768Speter goto fmtgen; 599768Speter case VARWIDTH + CONPREC: 6003076Smckusic sprintf(&format[1], "%%*.%d%c", prec, fmt); 601768Speter goto fmtgen; 602768Speter case VARWIDTH + VARPREC: 603768Speter sprintf(&format[1], "%%*.*%c", fmt); 604768Speter fmtgen: 605768Speter fmtlen = lenstr(&format[fmtstart], 0); 606768Speter put(2, O_LVCON, fmtlen); 607768Speter putstr(&format[fmtstart], 0); 608768Speter put(1, O_FILE); 6093172Smckusic stkcnt += 2 * sizeof(char *); 610768Speter put(2, O_WRITEF, stkcnt); 611768Speter } 612768Speter /* 613768Speter * Write the string after its blank padding 614768Speter */ 615768Speter if (typ == TSTR) { 616768Speter put(1, O_FILE); 6173172Smckusic put(2, CON_INT, 1); 618768Speter if (strfmt & VARWIDTH) { 6193851Speter put(2, O_RV4 | cbn << 8 + INDX , 6203851Speter tempnlp -> value[ NL_OFFS ] ); 621768Speter put(2, O_MIN, strnglen); 6223172Smckusic convert(nl+T4INT, INT_TYP); 6233226Smckusic tmpfree(&soffset); 624768Speter } else { 625768Speter if ((fmtspec & SKIP) && 626768Speter (strfmt & CONWIDTH)) { 627768Speter strnglen = field; 628768Speter } 6293172Smckusic put(2, CON_INT, strnglen); 630768Speter } 631768Speter ap = stkrval(alv, NIL , RREQ ); 6323172Smckusic put(2, O_WRITES, 6333172Smckusic 2 * sizeof(char *) + 2 * sizeof(int)); 634768Speter } 635768Speter } 636768Speter /* 637768Speter * Done with arguments. 638768Speter * Handle writeln and 639768Speter * insufficent number of args. 640768Speter */ 641768Speter switch (p->value[0] &~ NSTAND) { 642768Speter case O_WRITEF: 643768Speter if (argc == 0) 644768Speter error("Write requires an argument"); 645768Speter break; 646768Speter case O_MESSAGE: 647768Speter if (argc == 0) 648768Speter error("Message requires an argument"); 649768Speter case O_WRITLN: 650768Speter if (filetype != nl+T1CHAR) 651768Speter error("Can't 'writeln' a non text file"); 652768Speter put(1, O_WRITLN); 653768Speter break; 654768Speter } 655768Speter return; 656768Speter 657768Speter case O_READ4: 658768Speter case O_READLN: 659768Speter /* 660768Speter * Set up default 661768Speter * file "input". 662768Speter */ 663768Speter file = NIL; 664768Speter filetype = nl+T1CHAR; 665768Speter /* 666768Speter * Determine the file implied 667768Speter * for the read and generate 668768Speter * code to make it the active file. 669768Speter */ 670768Speter if (argv != NIL) { 671768Speter codeoff(); 672768Speter ap = stkrval(argv[1], NIL , RREQ ); 673768Speter codeon(); 674768Speter if (ap == NIL) 675768Speter argv = argv[2]; 676768Speter if (ap != NIL && ap->class == FILET) { 677768Speter /* 678768Speter * Got "read(f, ...", make 679768Speter * f the active file, and save 680768Speter * it and its type for use in 681768Speter * processing the rest of the 682768Speter * arguments to read. 683768Speter */ 684768Speter file = argv[1]; 685768Speter filetype = ap->type; 6862073Smckusic stklval(argv[1], NIL , LREQ ); 687768Speter put(1, O_UNIT); 688768Speter argv = argv[2]; 689768Speter argc--; 690768Speter } else { 691768Speter /* 692768Speter * Default is read from 693768Speter * standard input. 694768Speter */ 695768Speter put(1, O_UNITINP); 696768Speter input->nl_flags |= NUSED; 697768Speter } 698768Speter } else { 699768Speter put(1, O_UNITINP); 700768Speter input->nl_flags |= NUSED; 701768Speter } 702768Speter /* 703768Speter * Loop and process each 704768Speter * of the arguments. 705768Speter */ 706768Speter for (; argv != NIL; argv = argv[2]) { 707768Speter /* 708768Speter * Get the address of the target 709768Speter * on the stack. 710768Speter */ 711768Speter al = argv[1]; 712768Speter if (al == NIL) 713768Speter continue; 714768Speter if (al[0] != T_VAR) { 715768Speter error("Arguments to %s must be variables, not expressions", p->symbol); 716768Speter continue; 717768Speter } 718768Speter ap = stklval(al, MOD|ASGN|NOUSE); 719768Speter if (ap == NIL) 720768Speter continue; 721768Speter if (filetype != nl+T1CHAR) { 722768Speter /* 723768Speter * Generalized read, i.e. 724768Speter * from a non-textfile. 725768Speter */ 726768Speter if (incompat(filetype, ap, argv[1] )) { 727768Speter error("Type mismatch in read from non-text file"); 728768Speter continue; 729768Speter } 730768Speter /* 731768Speter * var := file ^; 732768Speter */ 733768Speter if (file != NIL) 7342073Smckusic stklval(file, NIL , LREQ ); 735768Speter else /* Magic */ 7363076Smckusic put(2, PTR_RV, (int)input->value[0]); 737768Speter put(1, O_FNIL); 738768Speter put(2, O_IND, width(filetype)); 739768Speter convert(filetype, ap); 740768Speter if (isa(ap, "bsci")) 741768Speter rangechk(ap, ap); 742768Speter put(2, O_AS, width(ap)); 743768Speter /* 744768Speter * get(file); 745768Speter */ 746768Speter put(1, O_GET); 747768Speter continue; 748768Speter } 749768Speter typ = classify(ap); 750768Speter op = rdops(typ); 751768Speter if (op == NIL) { 752768Speter error("Can't read %ss from a text file", clnames[typ]); 753768Speter continue; 754768Speter } 755768Speter if (op != O_READE) 756768Speter put(1, op); 757768Speter else { 7583076Smckusic put(2, op, (long)listnames(ap)); 7591628Speter warning(); 760768Speter if (opt('s')) { 761768Speter standard(); 762768Speter } 7631628Speter error("Reading scalars from text files is non-standard"); 764768Speter } 765768Speter /* 766768Speter * Data read is on the stack. 767768Speter * Assign it. 768768Speter */ 769768Speter if (op != O_READ8 && op != O_READE) 770768Speter rangechk(ap, op == O_READC ? ap : nl+T4INT); 771768Speter gen(O_AS2, O_AS2, width(ap), 772768Speter op == O_READ8 ? 8 : op == O_READ4 ? 4 : 2); 773768Speter } 774768Speter /* 775768Speter * Done with arguments. 776768Speter * Handle readln and 777768Speter * insufficient number of args. 778768Speter */ 779768Speter if (p->value[0] == O_READLN) { 780768Speter if (filetype != nl+T1CHAR) 781768Speter error("Can't 'readln' a non text file"); 782768Speter put(1, O_READLN); 783768Speter } 784768Speter else if (argc == 0) 785768Speter error("read requires an argument"); 786768Speter return; 787768Speter 788768Speter case O_GET: 789768Speter case O_PUT: 790768Speter if (argc != 1) { 791768Speter error("%s expects one argument", p->symbol); 792768Speter return; 793768Speter } 7942073Smckusic ap = stklval(argv[1], NIL , LREQ ); 795768Speter if (ap == NIL) 796768Speter return; 797768Speter if (ap->class != FILET) { 798768Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 799768Speter return; 800768Speter } 801768Speter put(1, O_UNIT); 802768Speter put(1, op); 803768Speter return; 804768Speter 805768Speter case O_RESET: 806768Speter case O_REWRITE: 807768Speter if (argc == 0 || argc > 2) { 808768Speter error("%s expects one or two arguments", p->symbol); 809768Speter return; 810768Speter } 811768Speter if (opt('s') && argc == 2) { 812768Speter standard(); 813768Speter error("Two argument forms of reset and rewrite are non-standard"); 814768Speter } 8152073Smckusic codeoff(); 816768Speter ap = stklval(argv[1], MOD|NOUSE); 8172073Smckusic codeon(); 818768Speter if (ap == NIL) 819768Speter return; 820768Speter if (ap->class != FILET) { 821768Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 822768Speter return; 823768Speter } 8242073Smckusic put(2, O_CON24, text(ap) ? 0: width(ap->type)); 825768Speter if (argc == 2) { 826768Speter /* 827768Speter * Optional second argument 828768Speter * is a string name of a 829768Speter * UNIX (R) file to be associated. 830768Speter */ 831768Speter al = argv[2]; 8322073Smckusic codeoff(); 833768Speter al = stkrval(al[1], NOFLAGS , RREQ ); 8342073Smckusic codeon(); 835768Speter if (al == NIL) 836768Speter return; 837768Speter if (classify(al) != TSTR) { 838768Speter error("Second argument to %s must be a string, not %s", p->symbol, nameof(al)); 839768Speter return; 840768Speter } 8412073Smckusic put(2, O_CON24, width(al)); 8422073Smckusic al = argv[2]; 8432073Smckusic al = stkrval(al[1], NOFLAGS , RREQ ); 844768Speter } else { 8452073Smckusic put(2, O_CON24, 0); 8463076Smckusic put(2, PTR_CON, NIL); 847768Speter } 8482073Smckusic ap = stklval(argv[1], MOD|NOUSE); 849768Speter put(1, op); 850768Speter return; 851768Speter 852768Speter case O_NEW: 853768Speter case O_DISPOSE: 854768Speter if (argc == 0) { 855768Speter error("%s expects at least one argument", p->symbol); 856768Speter return; 857768Speter } 858768Speter ap = stklval(argv[1], op == O_NEW ? ( MOD | NOUSE ) : MOD ); 859768Speter if (ap == NIL) 860768Speter return; 861768Speter if (ap->class != PTR) { 862768Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 863768Speter return; 864768Speter } 865768Speter ap = ap->type; 866768Speter if (ap == NIL) 867768Speter return; 8687966Smckusick if ((ap->nl_flags & NFILES) && op == O_DISPOSE) 8697966Smckusick op = O_DFDISP; 870768Speter argv = argv[2]; 871768Speter if (argv != NIL) { 872768Speter if (ap->class != RECORD) { 873768Speter error("Record required when specifying variant tags"); 874768Speter return; 875768Speter } 876768Speter for (; argv != NIL; argv = argv[2]) { 877768Speter if (ap->ptr[NL_VARNT] == NIL) { 878768Speter error("Too many tag fields"); 879768Speter return; 880768Speter } 881768Speter if (!isconst(argv[1])) { 882768Speter error("Second and successive arguments to %s must be constants", p->symbol); 883768Speter return; 884768Speter } 885768Speter gconst(argv[1]); 886768Speter if (con.ctype == NIL) 887768Speter return; 888768Speter if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) { 889768Speter cerror("Specified tag constant type clashed with variant case selector type"); 890768Speter return; 891768Speter } 892768Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 893768Speter if (ap->range[0] == con.crval) 894768Speter break; 895768Speter if (ap == NIL) { 896768Speter error("No variant case label value equals specified constant value"); 897768Speter return; 898768Speter } 899768Speter ap = ap->ptr[NL_VTOREC]; 900768Speter } 901768Speter } 902768Speter put(2, op, width(ap)); 903768Speter return; 904768Speter 905768Speter case O_DATE: 906768Speter case O_TIME: 907768Speter if (argc != 1) { 908768Speter error("%s expects one argument", p->symbol); 909768Speter return; 910768Speter } 911768Speter ap = stklval(argv[1], MOD|NOUSE); 912768Speter if (ap == NIL) 913768Speter return; 914768Speter if (classify(ap) != TSTR || width(ap) != 10) { 915768Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 916768Speter return; 917768Speter } 918768Speter put(1, op); 919768Speter return; 920768Speter 921768Speter case O_HALT: 922768Speter if (argc != 0) { 923768Speter error("halt takes no arguments"); 924768Speter return; 925768Speter } 926768Speter put(1, op); 927768Speter noreach = 1; 928768Speter return; 929768Speter 930768Speter case O_ARGV: 931768Speter if (argc != 2) { 932768Speter error("argv takes two arguments"); 933768Speter return; 934768Speter } 935768Speter ap = stkrval(argv[1], NIL , RREQ ); 936768Speter if (ap == NIL) 937768Speter return; 938768Speter if (isnta(ap, "i")) { 939768Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 940768Speter return; 941768Speter } 942768Speter al = argv[2]; 943768Speter ap = stklval(al[1], MOD|NOUSE); 944768Speter if (ap == NIL) 945768Speter return; 946768Speter if (classify(ap) != TSTR) { 947768Speter error("argv's second argument must be a string, not %s", nameof(ap)); 948768Speter return; 949768Speter } 950768Speter put(2, op, width(ap)); 951768Speter return; 952768Speter 953768Speter case O_STLIM: 954768Speter if (argc != 1) { 955768Speter error("stlimit requires one argument"); 956768Speter return; 957768Speter } 958768Speter ap = stkrval(argv[1], NIL , RREQ ); 959768Speter if (ap == NIL) 960768Speter return; 961768Speter if (isnta(ap, "i")) { 962768Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 963768Speter return; 964768Speter } 965768Speter if (width(ap) != 4) 966768Speter put(1, O_STOI); 967768Speter put(1, op); 968768Speter return; 969768Speter 970768Speter case O_REMOVE: 971768Speter if (argc != 1) { 972768Speter error("remove expects one argument"); 973768Speter return; 974768Speter } 9752073Smckusic codeoff(); 976768Speter ap = stkrval(argv[1], NOFLAGS , RREQ ); 9772073Smckusic codeon(); 978768Speter if (ap == NIL) 979768Speter return; 980768Speter if (classify(ap) != TSTR) { 981768Speter error("remove's argument must be a string, not %s", nameof(ap)); 982768Speter return; 983768Speter } 984768Speter put(2, O_CON24, width(ap)); 9852073Smckusic ap = stkrval(argv[1], NOFLAGS , RREQ ); 986768Speter put(1, op); 987768Speter return; 988768Speter 989768Speter case O_LLIMIT: 990768Speter if (argc != 2) { 991768Speter error("linelimit expects two arguments"); 992768Speter return; 993768Speter } 994768Speter al = argv[2]; 995768Speter ap = stkrval(al[1], NIL , RREQ ); 996768Speter if (ap == NIL) 997768Speter return; 998768Speter if (isnta(ap, "i")) { 999768Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 1000768Speter return; 1001768Speter } 10022073Smckusic ap = stklval(argv[1], NOFLAGS|NOUSE); 10032073Smckusic if (ap == NIL) 10042073Smckusic return; 10052073Smckusic if (!text(ap)) { 10062073Smckusic error("linelimit's first argument must be a text file, not %s", nameof(ap)); 10072073Smckusic return; 10082073Smckusic } 1009768Speter put(1, op); 1010768Speter return; 1011768Speter case O_PAGE: 1012768Speter if (argc != 1) { 1013768Speter error("page expects one argument"); 1014768Speter return; 1015768Speter } 10162073Smckusic ap = stklval(argv[1], NIL , LREQ ); 1017768Speter if (ap == NIL) 1018768Speter return; 1019768Speter if (!text(ap)) { 1020768Speter error("Argument to page must be a text file, not %s", nameof(ap)); 1021768Speter return; 1022768Speter } 1023768Speter put(1, O_UNIT); 1024768Speter put(1, op); 1025768Speter return; 1026768Speter 10277928Smckusick case O_ASRT: 10287928Smckusick if (!opt('t')) 10297928Smckusick return; 10307928Smckusick if (argc == 0 || argc > 2) { 10317928Smckusick error("Assert expects one or two arguments"); 10327928Smckusick return; 10337928Smckusick } 10347928Smckusick if (argc == 2) { 10357928Smckusick /* 10367928Smckusick * Optional second argument is a string specifying 10377928Smckusick * why the assertion failed. 10387928Smckusick */ 10397928Smckusick al = argv[2]; 10407928Smckusick al = stkrval(al[1], NIL , RREQ ); 10417928Smckusick if (al == NIL) 10427928Smckusick return; 10437928Smckusick if (classify(al) != TSTR) { 10447928Smckusick error("Second argument to assert must be a string, not %s", nameof(al)); 10457928Smckusick return; 10467928Smckusick } 10477928Smckusick } else { 10487928Smckusick put(2, PTR_CON, NIL); 10497928Smckusick } 10507928Smckusick ap = stkrval(argv[1], NIL , RREQ ); 10517928Smckusick if (ap == NIL) 10527928Smckusick return; 10537928Smckusick if (isnta(ap, "b")) 10547928Smckusick error("Assert expression must be Boolean, not %ss", nameof(ap)); 10557928Smckusick put(1, O_ASRT); 10567928Smckusick return; 10577928Smckusick 1058768Speter case O_PACK: 1059768Speter if (argc != 3) { 1060768Speter error("pack expects three arguments"); 1061768Speter return; 1062768Speter } 1063768Speter pu = "pack(a,i,z)"; 10643076Smckusic pua = argv[1]; 10653076Smckusic al = argv[2]; 10663076Smckusic pui = al[1]; 10673076Smckusic alv = al[2]; 10683076Smckusic puz = alv[1]; 1069768Speter goto packunp; 1070768Speter case O_UNPACK: 1071768Speter if (argc != 3) { 1072768Speter error("unpack expects three arguments"); 1073768Speter return; 1074768Speter } 1075768Speter pu = "unpack(z,a,i)"; 10763076Smckusic puz = argv[1]; 10773076Smckusic al = argv[2]; 10783076Smckusic pua = al[1]; 10793076Smckusic alv = al[2]; 10803076Smckusic pui = alv[1]; 1081768Speter packunp: 10822073Smckusic codeoff(); 1083768Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 10842073Smckusic al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 10852073Smckusic codeon(); 1086768Speter if (ap == NIL) 1087768Speter return; 1088768Speter if (ap->class != ARRAY) { 1089768Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 1090768Speter return; 1091768Speter } 1092768Speter if (al->class != ARRAY) { 1093768Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 1094768Speter return; 1095768Speter } 1096768Speter if (al->type == NIL || ap->type == NIL) 1097768Speter return; 1098768Speter if (al->type != ap->type) { 1099768Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 1100768Speter return; 1101768Speter } 1102768Speter k = width(al); 1103768Speter itemwidth = width(ap->type); 1104768Speter ap = ap->chain; 1105768Speter al = al->chain; 1106768Speter if (ap->chain != NIL || al->chain != NIL) { 1107768Speter error("%s requires a and z to be single dimension arrays", pu); 1108768Speter return; 1109768Speter } 1110768Speter if (ap == NIL || al == NIL) 1111768Speter return; 1112768Speter /* 1113768Speter * al is the range for z i.e. u..v 1114768Speter * ap is the range for a i.e. m..n 1115768Speter * i will be n-m+1 1116768Speter * j will be v-u+1 1117768Speter */ 1118768Speter i = ap->range[1] - ap->range[0] + 1; 1119768Speter j = al->range[1] - al->range[0] + 1; 1120768Speter if (i < j) { 1121768Speter error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i); 1122768Speter return; 1123768Speter } 1124768Speter /* 1125768Speter * get n-m-(v-u) and m for the interpreter 1126768Speter */ 1127768Speter i -= j; 1128768Speter j = ap->range[0]; 11292073Smckusic put(2, O_CON24, k); 11302073Smckusic put(2, O_CON24, i); 11312073Smckusic put(2, O_CON24, j); 11322073Smckusic put(2, O_CON24, itemwidth); 11332073Smckusic al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 11342073Smckusic ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 11352073Smckusic ap = stkrval((int *) pui, NLNIL , RREQ ); 11362073Smckusic if (ap == NIL) 11372073Smckusic return; 11382073Smckusic put(1, op); 1139768Speter return; 1140768Speter case 0: 11417928Smckusick error("%s is an unimplemented extension", p->symbol); 1142768Speter return; 1143768Speter 1144768Speter default: 1145768Speter panic("proc case"); 1146768Speter } 1147768Speter } 1148768Speter #endif OBJ 1149