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