1768Speter /* Copyright (c) 1979 Regents of the University of California */ 2768Speter 3*11882Smckusick static char sccsid[] = "@(#)proc.c 1.18 04/08/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" 1411327Speter #include "tmps.h" 15768Speter 16768Speter /* 17*11882Smckusick * The constant EXPOSIZE specifies the number of digits in the exponent 18*11882Smckusick * of real numbers. 19*11882Smckusick * 209230Smckusick * The constant REALSPC defines the amount of forced padding preceeding 219230Smckusick * real numbers when they are printed. If REALSPC == 0, then no padding 229230Smckusick * is added, REALSPC == 1 adds one extra blank irregardless of the width 239230Smckusick * specified by the user. 249230Smckusick * 259230Smckusick * N.B. - Values greater than one require program mods. 269230Smckusick */ 27*11882Smckusick #define EXPOSIZE 2 28*11882Smckusick #define REALSPC 0 299230Smckusick 309230Smckusick /* 31768Speter * The following array is used to determine which classes may be read 32768Speter * from textfiles. It is indexed by the return value from classify. 33768Speter */ 34768Speter #define rdops(x) rdxxxx[(x)-(TFIRST)] 35768Speter 36768Speter int rdxxxx[] = { 37768Speter 0, /* -7 file types */ 38768Speter 0, /* -6 record types */ 39768Speter 0, /* -5 array types */ 40768Speter O_READE, /* -4 scalar types */ 41768Speter 0, /* -3 pointer types */ 42768Speter 0, /* -2 set types */ 43768Speter 0, /* -1 string types */ 44768Speter 0, /* 0 nil, no type */ 45768Speter O_READE, /* 1 boolean */ 46768Speter O_READC, /* 2 character */ 47768Speter O_READ4, /* 3 integer */ 48768Speter O_READ8 /* 4 real */ 49768Speter }; 50768Speter 51768Speter /* 52768Speter * Proc handles procedure calls. 53768Speter * Non-builtin procedures are "buck-passed" to func (with a flag 54768Speter * indicating that they are actually procedures. 55768Speter * builtin procedures are handled here. 56768Speter */ 57768Speter proc(r) 58768Speter int *r; 59768Speter { 60768Speter register struct nl *p; 61768Speter register int *alv, *al, op; 62768Speter struct nl *filetype, *ap; 63768Speter int argc, *argv, typ, fmtspec, strfmt, stkcnt, *file; 64768Speter char fmt, format[20], *strptr; 65768Speter int prec, field, strnglen, fmtlen, fmtstart, pu; 66768Speter int *pua, *pui, *puz; 67768Speter int i, j, k; 68768Speter int itemwidth; 693226Smckusic struct tmps soffset; 703851Speter struct nl *tempnlp; 71768Speter 72768Speter #define CONPREC 4 73768Speter #define VARPREC 8 74768Speter #define CONWIDTH 1 75768Speter #define VARWIDTH 2 76768Speter #define SKIP 16 77768Speter 78768Speter /* 79768Speter * Verify that the name is 80768Speter * defined and is that of a 81768Speter * procedure. 82768Speter */ 83768Speter p = lookup(r[2]); 84768Speter if (p == NIL) { 85768Speter rvlist(r[3]); 86768Speter return; 87768Speter } 881198Speter if (p->class != PROC && p->class != FPROC) { 89768Speter error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]); 90768Speter rvlist(r[3]); 91768Speter return; 92768Speter } 93768Speter argv = r[3]; 94768Speter 95768Speter /* 96768Speter * Call handles user defined 97768Speter * procedures and functions. 98768Speter */ 99768Speter if (bn != 0) { 100768Speter call(p, argv, PROC, bn); 101768Speter return; 102768Speter } 103768Speter 104768Speter /* 105768Speter * Call to built-in procedure. 106768Speter * Count the arguments. 107768Speter */ 108768Speter argc = 0; 109768Speter for (al = argv; al != NIL; al = al[2]) 110768Speter argc++; 111768Speter 112768Speter /* 113768Speter * Switch on the operator 114768Speter * associated with the built-in 115768Speter * procedure in the namelist 116768Speter */ 117768Speter op = p->value[0] &~ NSTAND; 118768Speter if (opt('s') && (p->value[0] & NSTAND)) { 119768Speter standard(); 120768Speter error("%s is a nonstandard procedure", p->symbol); 121768Speter } 122768Speter switch (op) { 123768Speter 124768Speter case O_ABORT: 125768Speter if (argc != 0) 126768Speter error("null takes no arguments"); 127768Speter return; 128768Speter 129768Speter case O_FLUSH: 130768Speter if (argc == 0) { 131768Speter put(1, O_MESSAGE); 132768Speter return; 133768Speter } 134768Speter if (argc != 1) { 135768Speter error("flush takes at most one argument"); 136768Speter return; 137768Speter } 1382073Smckusic ap = stklval(argv[1], NIL , LREQ ); 139768Speter if (ap == NIL) 140768Speter return; 141768Speter if (ap->class != FILET) { 142768Speter error("flush's argument must be a file, not %s", nameof(ap)); 143768Speter return; 144768Speter } 145768Speter put(1, op); 146768Speter return; 147768Speter 148768Speter case O_MESSAGE: 149768Speter case O_WRITEF: 150768Speter case O_WRITLN: 151768Speter /* 152768Speter * Set up default file "output"'s type 153768Speter */ 154768Speter file = NIL; 155768Speter filetype = nl+T1CHAR; 156768Speter /* 157768Speter * Determine the file implied 158768Speter * for the write and generate 159768Speter * code to make it the active file. 160768Speter */ 161768Speter if (op == O_MESSAGE) { 162768Speter /* 163768Speter * For message, all that matters 164768Speter * is that the filetype is 165768Speter * a character file. 166768Speter * Thus "output" will suit us fine. 167768Speter */ 168768Speter put(1, O_MESSAGE); 169768Speter } else if (argv != NIL && (al = argv[1])[0] != T_WEXP) { 170768Speter /* 171768Speter * If there is a first argument which has 172768Speter * no write widths, then it is potentially 173768Speter * a file name. 174768Speter */ 175768Speter codeoff(); 176768Speter ap = stkrval(argv[1], NIL , RREQ ); 177768Speter codeon(); 178768Speter if (ap == NIL) 179768Speter argv = argv[2]; 180768Speter if (ap != NIL && ap->class == FILET) { 181768Speter /* 182768Speter * Got "write(f, ...", make 183768Speter * f the active file, and save 184768Speter * it and its type for use in 185768Speter * processing the rest of the 186768Speter * arguments to write. 187768Speter */ 188768Speter file = argv[1]; 189768Speter filetype = ap->type; 1902073Smckusic stklval(argv[1], NIL , LREQ ); 191768Speter put(1, O_UNIT); 192768Speter /* 193768Speter * Skip over the first argument 194768Speter */ 195768Speter argv = argv[2]; 196768Speter argc--; 1978538Speter } else { 198768Speter /* 199768Speter * Set up for writing on 200768Speter * standard output. 201768Speter */ 202768Speter put(1, O_UNITOUT); 2037953Speter output->nl_flags |= NUSED; 2048538Speter } 2058538Speter } else { 206768Speter put(1, O_UNITOUT); 2077953Speter output->nl_flags |= NUSED; 2088538Speter } 209768Speter /* 210768Speter * Loop and process each 211768Speter * of the arguments. 212768Speter */ 213768Speter for (; argv != NIL; argv = argv[2]) { 214768Speter /* 215768Speter * fmtspec indicates the type (CONstant or VARiable) 216768Speter * and number (none, WIDTH, and/or PRECision) 217768Speter * of the fields in the printf format for this 218768Speter * output variable. 2193172Smckusic * stkcnt is the number of bytes pushed on the stack 220768Speter * fmt is the format output indicator (D, E, F, O, X, S) 221768Speter * fmtstart = 0 for leading blank; = 1 for no blank 222768Speter */ 223768Speter fmtspec = NIL; 224768Speter stkcnt = 0; 225768Speter fmt = 'D'; 226768Speter fmtstart = 1; 227768Speter al = argv[1]; 228768Speter if (al == NIL) 229768Speter continue; 230768Speter if (al[0] == T_WEXP) 231768Speter alv = al[1]; 232768Speter else 233768Speter alv = al; 234768Speter if (alv == NIL) 235768Speter continue; 236768Speter codeoff(); 237768Speter ap = stkrval(alv, NIL , RREQ ); 238768Speter codeon(); 239768Speter if (ap == NIL) 240768Speter continue; 241768Speter typ = classify(ap); 242768Speter if (al[0] == T_WEXP) { 243768Speter /* 244768Speter * Handle width expressions. 245768Speter * The basic game here is that width 246768Speter * expressions get evaluated. If they 247768Speter * are constant, the value is placed 248768Speter * directly in the format string. 249768Speter * Otherwise the value is pushed onto 250768Speter * the stack and an indirection is 251768Speter * put into the format string. 252768Speter */ 253768Speter if (al[3] == OCT) 254768Speter fmt = 'O'; 255768Speter else if (al[3] == HEX) 256768Speter fmt = 'X'; 257768Speter else if (al[3] != NIL) { 258768Speter /* 259768Speter * Evaluate second format spec 260768Speter */ 261768Speter if ( constval(al[3]) 262768Speter && isa( con.ctype , "i" ) ) { 263768Speter fmtspec += CONPREC; 264768Speter prec = con.crval; 265768Speter } else { 266768Speter fmtspec += VARPREC; 267768Speter } 268768Speter fmt = 'f'; 269768Speter switch ( typ ) { 270768Speter case TINT: 271768Speter if ( opt( 's' ) ) { 272768Speter standard(); 273768Speter error("Writing %ss with two write widths is non-standard", clnames[typ]); 274768Speter } 275768Speter /* and fall through */ 276768Speter case TDOUBLE: 277768Speter break; 278768Speter default: 279768Speter error("Cannot write %ss with two write widths", clnames[typ]); 280768Speter continue; 281768Speter } 282768Speter } 283768Speter /* 284768Speter * Evaluate first format spec 285768Speter */ 286768Speter if (al[2] != NIL) { 287768Speter if ( constval(al[2]) 288768Speter && isa( con.ctype , "i" ) ) { 289768Speter fmtspec += CONWIDTH; 290768Speter field = con.crval; 291768Speter } else { 292768Speter fmtspec += VARWIDTH; 293768Speter } 294768Speter } 295768Speter if ((fmtspec & CONPREC) && prec < 0 || 296768Speter (fmtspec & CONWIDTH) && field < 0) { 297768Speter error("Negative widths are not allowed"); 298768Speter continue; 299768Speter } 3003179Smckusic if ( opt('s') && 3013179Smckusic ((fmtspec & CONPREC) && prec == 0 || 3023179Smckusic (fmtspec & CONWIDTH) && field == 0)) { 3033179Smckusic standard(); 3043179Smckusic error("Zero widths are non-standard"); 3053179Smckusic } 306768Speter } 307768Speter if (filetype != nl+T1CHAR) { 308768Speter if (fmt == 'O' || fmt == 'X') { 309768Speter error("Oct/hex allowed only on text files"); 310768Speter continue; 311768Speter } 312768Speter if (fmtspec) { 313768Speter error("Write widths allowed only on text files"); 314768Speter continue; 315768Speter } 316768Speter /* 317768Speter * Generalized write, i.e. 318768Speter * to a non-textfile. 319768Speter */ 3202073Smckusic stklval(file, NIL , LREQ ); 321768Speter put(1, O_FNIL); 322768Speter /* 323768Speter * file^ := ... 324768Speter */ 325768Speter ap = rvalue(argv[1], NIL); 326768Speter if (ap == NIL) 327768Speter continue; 328768Speter if (incompat(ap, filetype, argv[1])) { 329768Speter cerror("Type mismatch in write to non-text file"); 330768Speter continue; 331768Speter } 332768Speter convert(ap, filetype); 333768Speter put(2, O_AS, width(filetype)); 334768Speter /* 335768Speter * put(file) 336768Speter */ 337768Speter put(1, O_PUT); 338768Speter continue; 339768Speter } 340768Speter /* 341768Speter * Write to a textfile 342768Speter * 343768Speter * Evaluate the expression 344768Speter * to be written. 345768Speter */ 346768Speter if (fmt == 'O' || fmt == 'X') { 347768Speter if (opt('s')) { 348768Speter standard(); 349768Speter error("Oct and hex are non-standard"); 350768Speter } 351768Speter if (typ == TSTR || typ == TDOUBLE) { 352768Speter error("Can't write %ss with oct/hex", clnames[typ]); 353768Speter continue; 354768Speter } 355768Speter if (typ == TCHAR || typ == TBOOL) 356768Speter typ = TINT; 357768Speter } 358768Speter /* 359768Speter * Place the arguement on the stack. If there is 360768Speter * no format specified by the programmer, implement 361768Speter * the default. 362768Speter */ 363768Speter switch (typ) { 3646542Smckusick case TPTR: 3656542Smckusick warning(); 3666542Smckusick if (opt('s')) { 3676542Smckusick standard(); 3686542Smckusick } 3696542Smckusick error("Writing %ss to text files is non-standard", 3706542Smckusick clnames[typ]); 3716542Smckusick /* and fall through */ 372768Speter case TINT: 373768Speter if (fmt != 'f') { 374768Speter ap = stkrval(alv, NIL , RREQ ); 3753172Smckusic stkcnt += sizeof(long); 376768Speter } else { 377768Speter ap = stkrval(alv, NIL , RREQ ); 378768Speter put(1, O_ITOD); 3793172Smckusic stkcnt += sizeof(double); 380768Speter typ = TDOUBLE; 381768Speter goto tdouble; 382768Speter } 383768Speter if (fmtspec == NIL) { 384768Speter if (fmt == 'D') 385768Speter field = 10; 386768Speter else if (fmt == 'X') 387768Speter field = 8; 388768Speter else if (fmt == 'O') 389768Speter field = 11; 390768Speter else 391768Speter panic("fmt1"); 392768Speter fmtspec = CONWIDTH; 393768Speter } 394768Speter break; 395768Speter case TCHAR: 396768Speter tchar: 3972073Smckusic if (fmtspec == NIL) { 3982073Smckusic put(1, O_FILE); 3992073Smckusic ap = stkrval(alv, NIL , RREQ ); 4003172Smckusic convert(nl + T4INT, INT_TYP); 4013172Smckusic put(2, O_WRITEC, 4023172Smckusic sizeof(char *) + sizeof(int)); 4032073Smckusic fmtspec = SKIP; 4042073Smckusic break; 4052073Smckusic } 406768Speter ap = stkrval(alv, NIL , RREQ ); 4073172Smckusic convert(nl + T4INT, INT_TYP); 4083172Smckusic stkcnt += sizeof(int); 409768Speter fmt = 'c'; 410768Speter break; 411768Speter case TSCAL: 4121628Speter warning(); 413768Speter if (opt('s')) { 414768Speter standard(); 415768Speter } 4166542Smckusick error("Writing %ss to text files is non-standard", 4176542Smckusick clnames[typ]); 4186542Smckusick /* and fall through */ 419768Speter case TBOOL: 420768Speter stkrval(alv, NIL , RREQ ); 4213076Smckusic put(2, O_NAM, (long)listnames(ap)); 4223172Smckusic stkcnt += sizeof(char *); 423768Speter fmt = 's'; 424768Speter break; 425768Speter case TDOUBLE: 426768Speter ap = stkrval(alv, TDOUBLE , RREQ ); 4273172Smckusic stkcnt += sizeof(double); 428768Speter tdouble: 429768Speter switch (fmtspec) { 430768Speter case NIL: 431*11882Smckusick field = 14 + (5 + EXPOSIZE); 432*11882Smckusick prec = field - (5 + EXPOSIZE); 4333076Smckusic fmt = 'e'; 434768Speter fmtspec = CONWIDTH + CONPREC; 435768Speter break; 436768Speter case CONWIDTH: 4379230Smckusick field -= REALSPC; 4389230Smckusick if (field < 1) 439768Speter field = 1; 440*11882Smckusick prec = field - (5 + EXPOSIZE); 441768Speter if (prec < 1) 442768Speter prec = 1; 443768Speter fmtspec += CONPREC; 4443076Smckusic fmt = 'e'; 445768Speter break; 446768Speter case CONWIDTH + CONPREC: 447768Speter case CONWIDTH + VARPREC: 4489230Smckusick field -= REALSPC; 4499230Smckusick if (field < 1) 450768Speter field = 1; 451768Speter } 452768Speter format[0] = ' '; 4539230Smckusick fmtstart = 1 - REALSPC; 454768Speter break; 455768Speter case TSTR: 456768Speter constval( alv ); 457768Speter switch ( classify( con.ctype ) ) { 458768Speter case TCHAR: 459768Speter typ = TCHAR; 460768Speter goto tchar; 461768Speter case TSTR: 462768Speter strptr = con.cpval; 463768Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 464768Speter strptr = con.cpval; 465768Speter break; 466768Speter default: 467768Speter strnglen = width(ap); 468768Speter break; 469768Speter } 470768Speter fmt = 's'; 471768Speter strfmt = fmtspec; 472768Speter if (fmtspec == NIL) { 473768Speter fmtspec = SKIP; 474768Speter break; 475768Speter } 476768Speter if (fmtspec & CONWIDTH) { 477768Speter if (field <= strnglen) { 478768Speter fmtspec = SKIP; 479768Speter break; 480768Speter } else 481768Speter field -= strnglen; 482768Speter } 483768Speter /* 484768Speter * push string to implement leading blank padding 485768Speter */ 486768Speter put(2, O_LVCON, 2); 487768Speter putstr("", 0); 4883172Smckusic stkcnt += sizeof(char *); 489768Speter break; 490768Speter default: 491768Speter error("Can't write %ss to a text file", clnames[typ]); 492768Speter continue; 493768Speter } 494768Speter /* 495768Speter * If there is a variable precision, evaluate it onto 496768Speter * the stack 497768Speter */ 498768Speter if (fmtspec & VARPREC) { 499768Speter ap = stkrval(al[3], NIL , RREQ ); 500768Speter if (ap == NIL) 501768Speter continue; 502768Speter if (isnta(ap,"i")) { 503768Speter error("Second write width must be integer, not %s", nameof(ap)); 504768Speter continue; 505768Speter } 506768Speter if ( opt( 't' ) ) { 507768Speter put(3, O_MAX, 0, 0); 508768Speter } 5093172Smckusic convert(nl+T4INT, INT_TYP); 5103172Smckusic stkcnt += sizeof(int); 511768Speter } 512768Speter /* 513768Speter * If there is a variable width, evaluate it onto 514768Speter * the stack 515768Speter */ 516768Speter if (fmtspec & VARWIDTH) { 517768Speter if ( ( typ == TDOUBLE && fmtspec == VARWIDTH ) 518768Speter || typ == TSTR ) { 5193226Smckusic soffset = sizes[cbn].curtmps; 5203851Speter tempnlp = tmpalloc(sizeof(long), 5213226Smckusic nl+T4INT, REGOK); 5223851Speter put(2, O_LV | cbn << 8 + INDX, 5233851Speter tempnlp -> value[ NL_OFFS ] ); 524768Speter } 525768Speter ap = stkrval(al[2], NIL , RREQ ); 526768Speter if (ap == NIL) 527768Speter continue; 528768Speter if (isnta(ap,"i")) { 529768Speter error("First write width must be integer, not %s", nameof(ap)); 530768Speter continue; 531768Speter } 532768Speter /* 533768Speter * Perform special processing on widths based 534768Speter * on data type 535768Speter */ 536768Speter switch (typ) { 537768Speter case TDOUBLE: 538768Speter if (fmtspec == VARWIDTH) { 5393076Smckusic fmt = 'e'; 540768Speter put(1, O_AS4); 5413851Speter put(2, O_RV4 | cbn << 8 + INDX, 5423851Speter tempnlp -> value[NL_OFFS] ); 543*11882Smckusick put(3, O_MAX, 544*11882Smckusick 5 + EXPOSIZE + REALSPC, 1); 5453172Smckusic convert(nl+T4INT, INT_TYP); 5463172Smckusic stkcnt += sizeof(int); 5473851Speter put(2, O_RV4 | cbn << 8 + INDX, 5483851Speter tempnlp->value[NL_OFFS] ); 549768Speter fmtspec += VARPREC; 5503226Smckusic tmpfree(&soffset); 551768Speter } 5529230Smckusick put(3, O_MAX, REALSPC, 1); 553768Speter break; 554768Speter case TSTR: 555768Speter put(1, O_AS4); 5563851Speter put(2, O_RV4 | cbn << 8 + INDX, 5573851Speter tempnlp -> value[ NL_OFFS ] ); 558768Speter put(3, O_MAX, strnglen, 0); 559768Speter break; 560768Speter default: 561768Speter if ( opt( 't' ) ) { 562768Speter put(3, O_MAX, 0, 0); 563768Speter } 564768Speter break; 565768Speter } 5663172Smckusic convert(nl+T4INT, INT_TYP); 5673172Smckusic stkcnt += sizeof(int); 568768Speter } 569768Speter /* 570768Speter * Generate the format string 571768Speter */ 572768Speter switch (fmtspec) { 573768Speter default: 574768Speter panic("fmt2"); 575768Speter case SKIP: 576768Speter break; 5772073Smckusic case NIL: 5782073Smckusic sprintf(&format[1], "%%%c", fmt); 5792073Smckusic goto fmtgen; 580768Speter case CONWIDTH: 5813076Smckusic sprintf(&format[1], "%%%d%c", field, fmt); 582768Speter goto fmtgen; 583768Speter case VARWIDTH: 584768Speter sprintf(&format[1], "%%*%c", fmt); 585768Speter goto fmtgen; 586768Speter case CONWIDTH + CONPREC: 5873076Smckusic sprintf(&format[1], "%%%d.%d%c", field, prec, fmt); 588768Speter goto fmtgen; 589768Speter case CONWIDTH + VARPREC: 5903076Smckusic sprintf(&format[1], "%%%d.*%c", field, fmt); 591768Speter goto fmtgen; 592768Speter case VARWIDTH + CONPREC: 5933076Smckusic sprintf(&format[1], "%%*.%d%c", prec, fmt); 594768Speter goto fmtgen; 595768Speter case VARWIDTH + VARPREC: 596768Speter sprintf(&format[1], "%%*.*%c", fmt); 597768Speter fmtgen: 598768Speter fmtlen = lenstr(&format[fmtstart], 0); 599768Speter put(2, O_LVCON, fmtlen); 600768Speter putstr(&format[fmtstart], 0); 601768Speter put(1, O_FILE); 6023172Smckusic stkcnt += 2 * sizeof(char *); 603768Speter put(2, O_WRITEF, stkcnt); 604768Speter } 605768Speter /* 606768Speter * Write the string after its blank padding 607768Speter */ 608768Speter if (typ == TSTR) { 609768Speter put(1, O_FILE); 6103172Smckusic put(2, CON_INT, 1); 611768Speter if (strfmt & VARWIDTH) { 6123851Speter put(2, O_RV4 | cbn << 8 + INDX , 6133851Speter tempnlp -> value[ NL_OFFS ] ); 614768Speter put(2, O_MIN, strnglen); 6153172Smckusic convert(nl+T4INT, INT_TYP); 6163226Smckusic tmpfree(&soffset); 617768Speter } else { 618768Speter if ((fmtspec & SKIP) && 619768Speter (strfmt & CONWIDTH)) { 620768Speter strnglen = field; 621768Speter } 6223172Smckusic put(2, CON_INT, strnglen); 623768Speter } 624768Speter ap = stkrval(alv, NIL , RREQ ); 6253172Smckusic put(2, O_WRITES, 6263172Smckusic 2 * sizeof(char *) + 2 * sizeof(int)); 627768Speter } 628768Speter } 629768Speter /* 630768Speter * Done with arguments. 631768Speter * Handle writeln and 632768Speter * insufficent number of args. 633768Speter */ 634768Speter switch (p->value[0] &~ NSTAND) { 635768Speter case O_WRITEF: 636768Speter if (argc == 0) 637768Speter error("Write requires an argument"); 638768Speter break; 639768Speter case O_MESSAGE: 640768Speter if (argc == 0) 641768Speter error("Message requires an argument"); 642768Speter case O_WRITLN: 643768Speter if (filetype != nl+T1CHAR) 644768Speter error("Can't 'writeln' a non text file"); 645768Speter put(1, O_WRITLN); 646768Speter break; 647768Speter } 648768Speter return; 649768Speter 650768Speter case O_READ4: 651768Speter case O_READLN: 652768Speter /* 653768Speter * Set up default 654768Speter * file "input". 655768Speter */ 656768Speter file = NIL; 657768Speter filetype = nl+T1CHAR; 658768Speter /* 659768Speter * Determine the file implied 660768Speter * for the read and generate 661768Speter * code to make it the active file. 662768Speter */ 663768Speter if (argv != NIL) { 664768Speter codeoff(); 665768Speter ap = stkrval(argv[1], NIL , RREQ ); 666768Speter codeon(); 667768Speter if (ap == NIL) 668768Speter argv = argv[2]; 669768Speter if (ap != NIL && ap->class == FILET) { 670768Speter /* 671768Speter * Got "read(f, ...", make 672768Speter * f the active file, and save 673768Speter * it and its type for use in 674768Speter * processing the rest of the 675768Speter * arguments to read. 676768Speter */ 677768Speter file = argv[1]; 678768Speter filetype = ap->type; 6792073Smckusic stklval(argv[1], NIL , LREQ ); 680768Speter put(1, O_UNIT); 681768Speter argv = argv[2]; 682768Speter argc--; 683768Speter } else { 684768Speter /* 685768Speter * Default is read from 686768Speter * standard input. 687768Speter */ 688768Speter put(1, O_UNITINP); 689768Speter input->nl_flags |= NUSED; 690768Speter } 691768Speter } else { 692768Speter put(1, O_UNITINP); 693768Speter input->nl_flags |= NUSED; 694768Speter } 695768Speter /* 696768Speter * Loop and process each 697768Speter * of the arguments. 698768Speter */ 699768Speter for (; argv != NIL; argv = argv[2]) { 700768Speter /* 701768Speter * Get the address of the target 702768Speter * on the stack. 703768Speter */ 704768Speter al = argv[1]; 705768Speter if (al == NIL) 706768Speter continue; 707768Speter if (al[0] != T_VAR) { 708768Speter error("Arguments to %s must be variables, not expressions", p->symbol); 709768Speter continue; 710768Speter } 711768Speter ap = stklval(al, MOD|ASGN|NOUSE); 712768Speter if (ap == NIL) 713768Speter continue; 714768Speter if (filetype != nl+T1CHAR) { 715768Speter /* 716768Speter * Generalized read, i.e. 717768Speter * from a non-textfile. 718768Speter */ 719768Speter if (incompat(filetype, ap, argv[1] )) { 720768Speter error("Type mismatch in read from non-text file"); 721768Speter continue; 722768Speter } 723768Speter /* 724768Speter * var := file ^; 725768Speter */ 726768Speter if (file != NIL) 7272073Smckusic stklval(file, NIL , LREQ ); 728768Speter else /* Magic */ 7293076Smckusic put(2, PTR_RV, (int)input->value[0]); 730768Speter put(1, O_FNIL); 731768Speter put(2, O_IND, width(filetype)); 732768Speter convert(filetype, ap); 733768Speter if (isa(ap, "bsci")) 734768Speter rangechk(ap, ap); 735768Speter put(2, O_AS, width(ap)); 736768Speter /* 737768Speter * get(file); 738768Speter */ 739768Speter put(1, O_GET); 740768Speter continue; 741768Speter } 742768Speter typ = classify(ap); 743768Speter op = rdops(typ); 744768Speter if (op == NIL) { 745768Speter error("Can't read %ss from a text file", clnames[typ]); 746768Speter continue; 747768Speter } 748768Speter if (op != O_READE) 749768Speter put(1, op); 750768Speter else { 7513076Smckusic put(2, op, (long)listnames(ap)); 7521628Speter warning(); 753768Speter if (opt('s')) { 754768Speter standard(); 755768Speter } 7561628Speter error("Reading scalars from text files is non-standard"); 757768Speter } 758768Speter /* 759768Speter * Data read is on the stack. 760768Speter * Assign it. 761768Speter */ 762768Speter if (op != O_READ8 && op != O_READE) 763768Speter rangechk(ap, op == O_READC ? ap : nl+T4INT); 764768Speter gen(O_AS2, O_AS2, width(ap), 765768Speter op == O_READ8 ? 8 : op == O_READ4 ? 4 : 2); 766768Speter } 767768Speter /* 768768Speter * Done with arguments. 769768Speter * Handle readln and 770768Speter * insufficient number of args. 771768Speter */ 772768Speter if (p->value[0] == O_READLN) { 773768Speter if (filetype != nl+T1CHAR) 774768Speter error("Can't 'readln' a non text file"); 775768Speter put(1, O_READLN); 776768Speter } 777768Speter else if (argc == 0) 778768Speter error("read requires an argument"); 779768Speter return; 780768Speter 781768Speter case O_GET: 782768Speter case O_PUT: 783768Speter if (argc != 1) { 784768Speter error("%s expects one argument", p->symbol); 785768Speter return; 786768Speter } 7872073Smckusic ap = stklval(argv[1], NIL , LREQ ); 788768Speter if (ap == NIL) 789768Speter return; 790768Speter if (ap->class != FILET) { 791768Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 792768Speter return; 793768Speter } 794768Speter put(1, O_UNIT); 795768Speter put(1, op); 796768Speter return; 797768Speter 798768Speter case O_RESET: 799768Speter case O_REWRITE: 800768Speter if (argc == 0 || argc > 2) { 801768Speter error("%s expects one or two arguments", p->symbol); 802768Speter return; 803768Speter } 804768Speter if (opt('s') && argc == 2) { 805768Speter standard(); 806768Speter error("Two argument forms of reset and rewrite are non-standard"); 807768Speter } 8082073Smckusic codeoff(); 809768Speter ap = stklval(argv[1], MOD|NOUSE); 8102073Smckusic codeon(); 811768Speter if (ap == NIL) 812768Speter return; 813768Speter if (ap->class != FILET) { 814768Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 815768Speter return; 816768Speter } 8172073Smckusic put(2, O_CON24, text(ap) ? 0: width(ap->type)); 818768Speter if (argc == 2) { 819768Speter /* 820768Speter * Optional second argument 821768Speter * is a string name of a 822768Speter * UNIX (R) file to be associated. 823768Speter */ 824768Speter al = argv[2]; 8252073Smckusic codeoff(); 826768Speter al = stkrval(al[1], NOFLAGS , RREQ ); 8272073Smckusic codeon(); 828768Speter if (al == NIL) 829768Speter return; 830768Speter if (classify(al) != TSTR) { 831768Speter error("Second argument to %s must be a string, not %s", p->symbol, nameof(al)); 832768Speter return; 833768Speter } 8342073Smckusic put(2, O_CON24, width(al)); 8352073Smckusic al = argv[2]; 8362073Smckusic al = stkrval(al[1], NOFLAGS , RREQ ); 837768Speter } else { 8382073Smckusic put(2, O_CON24, 0); 8393076Smckusic put(2, PTR_CON, NIL); 840768Speter } 8412073Smckusic ap = stklval(argv[1], MOD|NOUSE); 842768Speter put(1, op); 843768Speter return; 844768Speter 845768Speter case O_NEW: 846768Speter case O_DISPOSE: 847768Speter if (argc == 0) { 848768Speter error("%s expects at least one argument", p->symbol); 849768Speter return; 850768Speter } 851768Speter ap = stklval(argv[1], op == O_NEW ? ( MOD | NOUSE ) : MOD ); 852768Speter if (ap == NIL) 853768Speter return; 854768Speter if (ap->class != PTR) { 855768Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 856768Speter return; 857768Speter } 858768Speter ap = ap->type; 859768Speter if (ap == NIL) 860768Speter return; 8617966Smckusick if ((ap->nl_flags & NFILES) && op == O_DISPOSE) 8627966Smckusick op = O_DFDISP; 863768Speter argv = argv[2]; 864768Speter if (argv != NIL) { 865768Speter if (ap->class != RECORD) { 866768Speter error("Record required when specifying variant tags"); 867768Speter return; 868768Speter } 869768Speter for (; argv != NIL; argv = argv[2]) { 870768Speter if (ap->ptr[NL_VARNT] == NIL) { 871768Speter error("Too many tag fields"); 872768Speter return; 873768Speter } 874768Speter if (!isconst(argv[1])) { 875768Speter error("Second and successive arguments to %s must be constants", p->symbol); 876768Speter return; 877768Speter } 878768Speter gconst(argv[1]); 879768Speter if (con.ctype == NIL) 880768Speter return; 881768Speter if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) { 882768Speter cerror("Specified tag constant type clashed with variant case selector type"); 883768Speter return; 884768Speter } 885768Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 886768Speter if (ap->range[0] == con.crval) 887768Speter break; 888768Speter if (ap == NIL) { 889768Speter error("No variant case label value equals specified constant value"); 890768Speter return; 891768Speter } 892768Speter ap = ap->ptr[NL_VTOREC]; 893768Speter } 894768Speter } 895768Speter put(2, op, width(ap)); 896768Speter return; 897768Speter 898768Speter case O_DATE: 899768Speter case O_TIME: 900768Speter if (argc != 1) { 901768Speter error("%s expects one argument", p->symbol); 902768Speter return; 903768Speter } 904768Speter ap = stklval(argv[1], MOD|NOUSE); 905768Speter if (ap == NIL) 906768Speter return; 907768Speter if (classify(ap) != TSTR || width(ap) != 10) { 908768Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 909768Speter return; 910768Speter } 911768Speter put(1, op); 912768Speter return; 913768Speter 914768Speter case O_HALT: 915768Speter if (argc != 0) { 916768Speter error("halt takes no arguments"); 917768Speter return; 918768Speter } 919768Speter put(1, op); 920768Speter noreach = 1; 921768Speter return; 922768Speter 923768Speter case O_ARGV: 924768Speter if (argc != 2) { 925768Speter error("argv takes two arguments"); 926768Speter return; 927768Speter } 928768Speter ap = stkrval(argv[1], NIL , RREQ ); 929768Speter if (ap == NIL) 930768Speter return; 931768Speter if (isnta(ap, "i")) { 932768Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 933768Speter return; 934768Speter } 935768Speter al = argv[2]; 936768Speter ap = stklval(al[1], MOD|NOUSE); 937768Speter if (ap == NIL) 938768Speter return; 939768Speter if (classify(ap) != TSTR) { 940768Speter error("argv's second argument must be a string, not %s", nameof(ap)); 941768Speter return; 942768Speter } 943768Speter put(2, op, width(ap)); 944768Speter return; 945768Speter 946768Speter case O_STLIM: 947768Speter if (argc != 1) { 948768Speter error("stlimit requires one argument"); 949768Speter return; 950768Speter } 951768Speter ap = stkrval(argv[1], NIL , RREQ ); 952768Speter if (ap == NIL) 953768Speter return; 954768Speter if (isnta(ap, "i")) { 955768Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 956768Speter return; 957768Speter } 958768Speter if (width(ap) != 4) 959768Speter put(1, O_STOI); 960768Speter put(1, op); 961768Speter return; 962768Speter 963768Speter case O_REMOVE: 964768Speter if (argc != 1) { 965768Speter error("remove expects one argument"); 966768Speter return; 967768Speter } 9682073Smckusic codeoff(); 969768Speter ap = stkrval(argv[1], NOFLAGS , RREQ ); 9702073Smckusic codeon(); 971768Speter if (ap == NIL) 972768Speter return; 973768Speter if (classify(ap) != TSTR) { 974768Speter error("remove's argument must be a string, not %s", nameof(ap)); 975768Speter return; 976768Speter } 977768Speter put(2, O_CON24, width(ap)); 9782073Smckusic ap = stkrval(argv[1], NOFLAGS , RREQ ); 979768Speter put(1, op); 980768Speter return; 981768Speter 982768Speter case O_LLIMIT: 983768Speter if (argc != 2) { 984768Speter error("linelimit expects two arguments"); 985768Speter return; 986768Speter } 987768Speter al = argv[2]; 988768Speter ap = stkrval(al[1], NIL , RREQ ); 989768Speter if (ap == NIL) 990768Speter return; 991768Speter if (isnta(ap, "i")) { 992768Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 993768Speter return; 994768Speter } 9952073Smckusic ap = stklval(argv[1], NOFLAGS|NOUSE); 9962073Smckusic if (ap == NIL) 9972073Smckusic return; 9982073Smckusic if (!text(ap)) { 9992073Smckusic error("linelimit's first argument must be a text file, not %s", nameof(ap)); 10002073Smckusic return; 10012073Smckusic } 1002768Speter put(1, op); 1003768Speter return; 1004768Speter case O_PAGE: 1005768Speter if (argc != 1) { 1006768Speter error("page expects one argument"); 1007768Speter return; 1008768Speter } 10092073Smckusic ap = stklval(argv[1], NIL , LREQ ); 1010768Speter if (ap == NIL) 1011768Speter return; 1012768Speter if (!text(ap)) { 1013768Speter error("Argument to page must be a text file, not %s", nameof(ap)); 1014768Speter return; 1015768Speter } 1016768Speter put(1, O_UNIT); 1017768Speter put(1, op); 1018768Speter return; 1019768Speter 10207928Smckusick case O_ASRT: 10217928Smckusick if (!opt('t')) 10227928Smckusick return; 10237928Smckusick if (argc == 0 || argc > 2) { 10247928Smckusick error("Assert expects one or two arguments"); 10257928Smckusick return; 10267928Smckusick } 10277928Smckusick if (argc == 2) { 10287928Smckusick /* 10297928Smckusick * Optional second argument is a string specifying 10307928Smckusick * why the assertion failed. 10317928Smckusick */ 10327928Smckusick al = argv[2]; 10337928Smckusick al = stkrval(al[1], NIL , RREQ ); 10347928Smckusick if (al == NIL) 10357928Smckusick return; 10367928Smckusick if (classify(al) != TSTR) { 10377928Smckusick error("Second argument to assert must be a string, not %s", nameof(al)); 10387928Smckusick return; 10397928Smckusick } 10407928Smckusick } else { 10417928Smckusick put(2, PTR_CON, NIL); 10427928Smckusick } 10437928Smckusick ap = stkrval(argv[1], NIL , RREQ ); 10447928Smckusick if (ap == NIL) 10457928Smckusick return; 10467928Smckusick if (isnta(ap, "b")) 10477928Smckusick error("Assert expression must be Boolean, not %ss", nameof(ap)); 10487928Smckusick put(1, O_ASRT); 10497928Smckusick return; 10507928Smckusick 1051768Speter case O_PACK: 1052768Speter if (argc != 3) { 1053768Speter error("pack expects three arguments"); 1054768Speter return; 1055768Speter } 1056768Speter pu = "pack(a,i,z)"; 10573076Smckusic pua = argv[1]; 10583076Smckusic al = argv[2]; 10593076Smckusic pui = al[1]; 10603076Smckusic alv = al[2]; 10613076Smckusic puz = alv[1]; 1062768Speter goto packunp; 1063768Speter case O_UNPACK: 1064768Speter if (argc != 3) { 1065768Speter error("unpack expects three arguments"); 1066768Speter return; 1067768Speter } 1068768Speter pu = "unpack(z,a,i)"; 10693076Smckusic puz = argv[1]; 10703076Smckusic al = argv[2]; 10713076Smckusic pua = al[1]; 10723076Smckusic alv = al[2]; 10733076Smckusic pui = alv[1]; 1074768Speter packunp: 10752073Smckusic codeoff(); 1076768Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 10772073Smckusic al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 10782073Smckusic codeon(); 1079768Speter if (ap == NIL) 1080768Speter return; 1081768Speter if (ap->class != ARRAY) { 1082768Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 1083768Speter return; 1084768Speter } 1085768Speter if (al->class != ARRAY) { 1086768Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 1087768Speter return; 1088768Speter } 1089768Speter if (al->type == NIL || ap->type == NIL) 1090768Speter return; 1091768Speter if (al->type != ap->type) { 1092768Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 1093768Speter return; 1094768Speter } 1095768Speter k = width(al); 1096768Speter itemwidth = width(ap->type); 1097768Speter ap = ap->chain; 1098768Speter al = al->chain; 1099768Speter if (ap->chain != NIL || al->chain != NIL) { 1100768Speter error("%s requires a and z to be single dimension arrays", pu); 1101768Speter return; 1102768Speter } 1103768Speter if (ap == NIL || al == NIL) 1104768Speter return; 1105768Speter /* 1106768Speter * al is the range for z i.e. u..v 1107768Speter * ap is the range for a i.e. m..n 1108768Speter * i will be n-m+1 1109768Speter * j will be v-u+1 1110768Speter */ 1111768Speter i = ap->range[1] - ap->range[0] + 1; 1112768Speter j = al->range[1] - al->range[0] + 1; 1113768Speter if (i < j) { 1114768Speter error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i); 1115768Speter return; 1116768Speter } 1117768Speter /* 1118768Speter * get n-m-(v-u) and m for the interpreter 1119768Speter */ 1120768Speter i -= j; 1121768Speter j = ap->range[0]; 11222073Smckusic put(2, O_CON24, k); 11232073Smckusic put(2, O_CON24, i); 11242073Smckusic put(2, O_CON24, j); 11252073Smckusic put(2, O_CON24, itemwidth); 11262073Smckusic al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 11272073Smckusic ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 11282073Smckusic ap = stkrval((int *) pui, NLNIL , RREQ ); 11292073Smckusic if (ap == NIL) 11302073Smckusic return; 11312073Smckusic put(1, op); 1132768Speter return; 1133768Speter case 0: 11347928Smckusick error("%s is an unimplemented extension", p->symbol); 1135768Speter return; 1136768Speter 1137768Speter default: 1138768Speter panic("proc case"); 1139768Speter } 1140768Speter } 1141768Speter #endif OBJ 1142