1768Speter /* Copyright (c) 1979 Regents of the University of California */ 2768Speter 3*3851Speter static char sccsid[] = "@(#)proc.c 1.9 06/04/81"; 4768Speter 5768Speter #include "whoami.h" 6768Speter #ifdef OBJ 7768Speter /* 8768Speter * and the rest of the file 9768Speter */ 10768Speter #include "0.h" 11768Speter #include "tree.h" 12768Speter #include "opcode.h" 13768Speter #include "objfmt.h" 14768Speter 15768Speter /* 16768Speter * The following array is used to determine which classes may be read 17768Speter * from textfiles. It is indexed by the return value from classify. 18768Speter */ 19768Speter #define rdops(x) rdxxxx[(x)-(TFIRST)] 20768Speter 21768Speter int rdxxxx[] = { 22768Speter 0, /* -7 file types */ 23768Speter 0, /* -6 record types */ 24768Speter 0, /* -5 array types */ 25768Speter O_READE, /* -4 scalar types */ 26768Speter 0, /* -3 pointer types */ 27768Speter 0, /* -2 set types */ 28768Speter 0, /* -1 string types */ 29768Speter 0, /* 0 nil, no type */ 30768Speter O_READE, /* 1 boolean */ 31768Speter O_READC, /* 2 character */ 32768Speter O_READ4, /* 3 integer */ 33768Speter O_READ8 /* 4 real */ 34768Speter }; 35768Speter 36768Speter /* 37768Speter * Proc handles procedure calls. 38768Speter * Non-builtin procedures are "buck-passed" to func (with a flag 39768Speter * indicating that they are actually procedures. 40768Speter * builtin procedures are handled here. 41768Speter */ 42768Speter proc(r) 43768Speter int *r; 44768Speter { 45768Speter register struct nl *p; 46768Speter register int *alv, *al, op; 47768Speter struct nl *filetype, *ap; 48768Speter int argc, *argv, typ, fmtspec, strfmt, stkcnt, *file; 49768Speter char fmt, format[20], *strptr; 50768Speter int prec, field, strnglen, fmtlen, fmtstart, pu; 51768Speter int *pua, *pui, *puz; 52768Speter int i, j, k; 53768Speter int itemwidth; 543226Smckusic struct tmps soffset; 55*3851Speter struct nl *tempnlp; 56768Speter 57768Speter #define CONPREC 4 58768Speter #define VARPREC 8 59768Speter #define CONWIDTH 1 60768Speter #define VARWIDTH 2 61768Speter #define SKIP 16 62768Speter 63768Speter /* 64768Speter * Verify that the name is 65768Speter * defined and is that of a 66768Speter * procedure. 67768Speter */ 68768Speter p = lookup(r[2]); 69768Speter if (p == NIL) { 70768Speter rvlist(r[3]); 71768Speter return; 72768Speter } 731198Speter if (p->class != PROC && p->class != FPROC) { 74768Speter error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]); 75768Speter rvlist(r[3]); 76768Speter return; 77768Speter } 78768Speter argv = r[3]; 79768Speter 80768Speter /* 81768Speter * Call handles user defined 82768Speter * procedures and functions. 83768Speter */ 84768Speter if (bn != 0) { 85768Speter call(p, argv, PROC, bn); 86768Speter return; 87768Speter } 88768Speter 89768Speter /* 90768Speter * Call to built-in procedure. 91768Speter * Count the arguments. 92768Speter */ 93768Speter argc = 0; 94768Speter for (al = argv; al != NIL; al = al[2]) 95768Speter argc++; 96768Speter 97768Speter /* 98768Speter * Switch on the operator 99768Speter * associated with the built-in 100768Speter * procedure in the namelist 101768Speter */ 102768Speter op = p->value[0] &~ NSTAND; 103768Speter if (opt('s') && (p->value[0] & NSTAND)) { 104768Speter standard(); 105768Speter error("%s is a nonstandard procedure", p->symbol); 106768Speter } 107768Speter switch (op) { 108768Speter 109768Speter case O_ABORT: 110768Speter if (argc != 0) 111768Speter error("null takes no arguments"); 112768Speter return; 113768Speter 114768Speter case O_FLUSH: 115768Speter if (argc == 0) { 116768Speter put(1, O_MESSAGE); 117768Speter return; 118768Speter } 119768Speter if (argc != 1) { 120768Speter error("flush takes at most one argument"); 121768Speter return; 122768Speter } 1232073Smckusic ap = stklval(argv[1], NIL , LREQ ); 124768Speter if (ap == NIL) 125768Speter return; 126768Speter if (ap->class != FILET) { 127768Speter error("flush's argument must be a file, not %s", nameof(ap)); 128768Speter return; 129768Speter } 130768Speter put(1, op); 131768Speter return; 132768Speter 133768Speter case O_MESSAGE: 134768Speter case O_WRITEF: 135768Speter case O_WRITLN: 136768Speter /* 137768Speter * Set up default file "output"'s type 138768Speter */ 139768Speter file = NIL; 140768Speter filetype = nl+T1CHAR; 141768Speter /* 142768Speter * Determine the file implied 143768Speter * for the write and generate 144768Speter * code to make it the active file. 145768Speter */ 146768Speter if (op == O_MESSAGE) { 147768Speter /* 148768Speter * For message, all that matters 149768Speter * is that the filetype is 150768Speter * a character file. 151768Speter * Thus "output" will suit us fine. 152768Speter */ 153768Speter put(1, O_MESSAGE); 154768Speter } else if (argv != NIL && (al = argv[1])[0] != T_WEXP) { 155768Speter /* 156768Speter * If there is a first argument which has 157768Speter * no write widths, then it is potentially 158768Speter * a file name. 159768Speter */ 160768Speter codeoff(); 161768Speter ap = stkrval(argv[1], NIL , RREQ ); 162768Speter codeon(); 163768Speter if (ap == NIL) 164768Speter argv = argv[2]; 165768Speter if (ap != NIL && ap->class == FILET) { 166768Speter /* 167768Speter * Got "write(f, ...", make 168768Speter * f the active file, and save 169768Speter * it and its type for use in 170768Speter * processing the rest of the 171768Speter * arguments to write. 172768Speter */ 173768Speter file = argv[1]; 174768Speter filetype = ap->type; 1752073Smckusic stklval(argv[1], NIL , LREQ ); 176768Speter put(1, O_UNIT); 177768Speter /* 178768Speter * Skip over the first argument 179768Speter */ 180768Speter argv = argv[2]; 181768Speter argc--; 182768Speter } else 183768Speter /* 184768Speter * Set up for writing on 185768Speter * standard output. 186768Speter */ 187768Speter put(1, O_UNITOUT); 188768Speter } else 189768Speter put(1, O_UNITOUT); 190768Speter /* 191768Speter * Loop and process each 192768Speter * of the arguments. 193768Speter */ 194768Speter for (; argv != NIL; argv = argv[2]) { 195768Speter /* 196768Speter * fmtspec indicates the type (CONstant or VARiable) 197768Speter * and number (none, WIDTH, and/or PRECision) 198768Speter * of the fields in the printf format for this 199768Speter * output variable. 2003172Smckusic * stkcnt is the number of bytes pushed on the stack 201768Speter * fmt is the format output indicator (D, E, F, O, X, S) 202768Speter * fmtstart = 0 for leading blank; = 1 for no blank 203768Speter */ 204768Speter fmtspec = NIL; 205768Speter stkcnt = 0; 206768Speter fmt = 'D'; 207768Speter fmtstart = 1; 208768Speter al = argv[1]; 209768Speter if (al == NIL) 210768Speter continue; 211768Speter if (al[0] == T_WEXP) 212768Speter alv = al[1]; 213768Speter else 214768Speter alv = al; 215768Speter if (alv == NIL) 216768Speter continue; 217768Speter codeoff(); 218768Speter ap = stkrval(alv, NIL , RREQ ); 219768Speter codeon(); 220768Speter if (ap == NIL) 221768Speter continue; 222768Speter typ = classify(ap); 223768Speter if (al[0] == T_WEXP) { 224768Speter /* 225768Speter * Handle width expressions. 226768Speter * The basic game here is that width 227768Speter * expressions get evaluated. If they 228768Speter * are constant, the value is placed 229768Speter * directly in the format string. 230768Speter * Otherwise the value is pushed onto 231768Speter * the stack and an indirection is 232768Speter * put into the format string. 233768Speter */ 234768Speter if (al[3] == OCT) 235768Speter fmt = 'O'; 236768Speter else if (al[3] == HEX) 237768Speter fmt = 'X'; 238768Speter else if (al[3] != NIL) { 239768Speter /* 240768Speter * Evaluate second format spec 241768Speter */ 242768Speter if ( constval(al[3]) 243768Speter && isa( con.ctype , "i" ) ) { 244768Speter fmtspec += CONPREC; 245768Speter prec = con.crval; 246768Speter } else { 247768Speter fmtspec += VARPREC; 248768Speter } 249768Speter fmt = 'f'; 250768Speter switch ( typ ) { 251768Speter case TINT: 252768Speter if ( opt( 's' ) ) { 253768Speter standard(); 254768Speter error("Writing %ss with two write widths is non-standard", clnames[typ]); 255768Speter } 256768Speter /* and fall through */ 257768Speter case TDOUBLE: 258768Speter break; 259768Speter default: 260768Speter error("Cannot write %ss with two write widths", clnames[typ]); 261768Speter continue; 262768Speter } 263768Speter } 264768Speter /* 265768Speter * Evaluate first format spec 266768Speter */ 267768Speter if (al[2] != NIL) { 268768Speter if ( constval(al[2]) 269768Speter && isa( con.ctype , "i" ) ) { 270768Speter fmtspec += CONWIDTH; 271768Speter field = con.crval; 272768Speter } else { 273768Speter fmtspec += VARWIDTH; 274768Speter } 275768Speter } 276768Speter if ((fmtspec & CONPREC) && prec < 0 || 277768Speter (fmtspec & CONWIDTH) && field < 0) { 278768Speter error("Negative widths are not allowed"); 279768Speter continue; 280768Speter } 2813179Smckusic if ( opt('s') && 2823179Smckusic ((fmtspec & CONPREC) && prec == 0 || 2833179Smckusic (fmtspec & CONWIDTH) && field == 0)) { 2843179Smckusic standard(); 2853179Smckusic error("Zero widths are non-standard"); 2863179Smckusic } 287768Speter } 288768Speter if (filetype != nl+T1CHAR) { 289768Speter if (fmt == 'O' || fmt == 'X') { 290768Speter error("Oct/hex allowed only on text files"); 291768Speter continue; 292768Speter } 293768Speter if (fmtspec) { 294768Speter error("Write widths allowed only on text files"); 295768Speter continue; 296768Speter } 297768Speter /* 298768Speter * Generalized write, i.e. 299768Speter * to a non-textfile. 300768Speter */ 3012073Smckusic stklval(file, NIL , LREQ ); 302768Speter put(1, O_FNIL); 303768Speter /* 304768Speter * file^ := ... 305768Speter */ 306768Speter ap = rvalue(argv[1], NIL); 307768Speter if (ap == NIL) 308768Speter continue; 309768Speter if (incompat(ap, filetype, argv[1])) { 310768Speter cerror("Type mismatch in write to non-text file"); 311768Speter continue; 312768Speter } 313768Speter convert(ap, filetype); 314768Speter put(2, O_AS, width(filetype)); 315768Speter /* 316768Speter * put(file) 317768Speter */ 318768Speter put(1, O_PUT); 319768Speter continue; 320768Speter } 321768Speter /* 322768Speter * Write to a textfile 323768Speter * 324768Speter * Evaluate the expression 325768Speter * to be written. 326768Speter */ 327768Speter if (fmt == 'O' || fmt == 'X') { 328768Speter if (opt('s')) { 329768Speter standard(); 330768Speter error("Oct and hex are non-standard"); 331768Speter } 332768Speter if (typ == TSTR || typ == TDOUBLE) { 333768Speter error("Can't write %ss with oct/hex", clnames[typ]); 334768Speter continue; 335768Speter } 336768Speter if (typ == TCHAR || typ == TBOOL) 337768Speter typ = TINT; 338768Speter } 339768Speter /* 340768Speter * Place the arguement on the stack. If there is 341768Speter * no format specified by the programmer, implement 342768Speter * the default. 343768Speter */ 344768Speter switch (typ) { 345768Speter case TINT: 346768Speter if (fmt != 'f') { 347768Speter ap = stkrval(alv, NIL , RREQ ); 3483172Smckusic stkcnt += sizeof(long); 349768Speter } else { 350768Speter ap = stkrval(alv, NIL , RREQ ); 351768Speter put(1, O_ITOD); 3523172Smckusic stkcnt += sizeof(double); 353768Speter typ = TDOUBLE; 354768Speter goto tdouble; 355768Speter } 356768Speter if (fmtspec == NIL) { 357768Speter if (fmt == 'D') 358768Speter field = 10; 359768Speter else if (fmt == 'X') 360768Speter field = 8; 361768Speter else if (fmt == 'O') 362768Speter field = 11; 363768Speter else 364768Speter panic("fmt1"); 365768Speter fmtspec = CONWIDTH; 366768Speter } 367768Speter break; 368768Speter case TCHAR: 369768Speter tchar: 3702073Smckusic if (fmtspec == NIL) { 3712073Smckusic put(1, O_FILE); 3722073Smckusic ap = stkrval(alv, NIL , RREQ ); 3733172Smckusic convert(nl + T4INT, INT_TYP); 3743172Smckusic put(2, O_WRITEC, 3753172Smckusic sizeof(char *) + sizeof(int)); 3762073Smckusic fmtspec = SKIP; 3772073Smckusic break; 3782073Smckusic } 379768Speter ap = stkrval(alv, NIL , RREQ ); 3803172Smckusic convert(nl + T4INT, INT_TYP); 3813172Smckusic stkcnt += sizeof(int); 382768Speter fmt = 'c'; 383768Speter break; 384768Speter case TSCAL: 3851628Speter warning(); 386768Speter if (opt('s')) { 387768Speter standard(); 388768Speter } 3891628Speter error("Writing scalars to text files is non-standard"); 390768Speter case TBOOL: 391768Speter stkrval(alv, NIL , RREQ ); 3923076Smckusic put(2, O_NAM, (long)listnames(ap)); 3933172Smckusic stkcnt += sizeof(char *); 394768Speter fmt = 's'; 395768Speter break; 396768Speter case TDOUBLE: 397768Speter ap = stkrval(alv, TDOUBLE , RREQ ); 3983172Smckusic stkcnt += sizeof(double); 399768Speter tdouble: 400768Speter switch (fmtspec) { 401768Speter case NIL: 4023076Smckusic # ifdef DEC11 4033076Smckusic field = 21; 4043076Smckusic # else 4053076Smckusic field = 22; 4063076Smckusic # endif DEC11 407768Speter prec = 14; 4083076Smckusic fmt = 'e'; 409768Speter fmtspec = CONWIDTH + CONPREC; 410768Speter break; 411768Speter case CONWIDTH: 412768Speter if (--field < 1) 413768Speter field = 1; 4143076Smckusic # ifdef DEC11 4153076Smckusic prec = field - 7; 4163076Smckusic # else 4173076Smckusic prec = field - 8; 4183076Smckusic # endif DEC11 419768Speter if (prec < 1) 420768Speter prec = 1; 421768Speter fmtspec += CONPREC; 4223076Smckusic fmt = 'e'; 423768Speter break; 424768Speter case CONWIDTH + CONPREC: 425768Speter case CONWIDTH + VARPREC: 426768Speter if (--field < 1) 427768Speter field = 1; 428768Speter } 429768Speter format[0] = ' '; 430768Speter fmtstart = 0; 431768Speter break; 432768Speter case TSTR: 433768Speter constval( alv ); 434768Speter switch ( classify( con.ctype ) ) { 435768Speter case TCHAR: 436768Speter typ = TCHAR; 437768Speter goto tchar; 438768Speter case TSTR: 439768Speter strptr = con.cpval; 440768Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 441768Speter strptr = con.cpval; 442768Speter break; 443768Speter default: 444768Speter strnglen = width(ap); 445768Speter break; 446768Speter } 447768Speter fmt = 's'; 448768Speter strfmt = fmtspec; 449768Speter if (fmtspec == NIL) { 450768Speter fmtspec = SKIP; 451768Speter break; 452768Speter } 453768Speter if (fmtspec & CONWIDTH) { 454768Speter if (field <= strnglen) { 455768Speter fmtspec = SKIP; 456768Speter break; 457768Speter } else 458768Speter field -= strnglen; 459768Speter } 460768Speter /* 461768Speter * push string to implement leading blank padding 462768Speter */ 463768Speter put(2, O_LVCON, 2); 464768Speter putstr("", 0); 4653172Smckusic stkcnt += sizeof(char *); 466768Speter break; 467768Speter default: 468768Speter error("Can't write %ss to a text file", clnames[typ]); 469768Speter continue; 470768Speter } 471768Speter /* 472768Speter * If there is a variable precision, evaluate it onto 473768Speter * the stack 474768Speter */ 475768Speter if (fmtspec & VARPREC) { 476768Speter ap = stkrval(al[3], NIL , RREQ ); 477768Speter if (ap == NIL) 478768Speter continue; 479768Speter if (isnta(ap,"i")) { 480768Speter error("Second write width must be integer, not %s", nameof(ap)); 481768Speter continue; 482768Speter } 483768Speter if ( opt( 't' ) ) { 484768Speter put(3, O_MAX, 0, 0); 485768Speter } 4863172Smckusic convert(nl+T4INT, INT_TYP); 4873172Smckusic stkcnt += sizeof(int); 488768Speter } 489768Speter /* 490768Speter * If there is a variable width, evaluate it onto 491768Speter * the stack 492768Speter */ 493768Speter if (fmtspec & VARWIDTH) { 494768Speter if ( ( typ == TDOUBLE && fmtspec == VARWIDTH ) 495768Speter || typ == TSTR ) { 4963226Smckusic soffset = sizes[cbn].curtmps; 497*3851Speter tempnlp = tmpalloc(sizeof(long), 4983226Smckusic nl+T4INT, REGOK); 499*3851Speter put(2, O_LV | cbn << 8 + INDX, 500*3851Speter tempnlp -> value[ NL_OFFS ] ); 501768Speter } 502768Speter ap = stkrval(al[2], NIL , RREQ ); 503768Speter if (ap == NIL) 504768Speter continue; 505768Speter if (isnta(ap,"i")) { 506768Speter error("First write width must be integer, not %s", nameof(ap)); 507768Speter continue; 508768Speter } 509768Speter /* 510768Speter * Perform special processing on widths based 511768Speter * on data type 512768Speter */ 513768Speter switch (typ) { 514768Speter case TDOUBLE: 515768Speter if (fmtspec == VARWIDTH) { 5163076Smckusic fmt = 'e'; 517768Speter put(1, O_AS4); 518*3851Speter put(2, O_RV4 | cbn << 8 + INDX, 519*3851Speter tempnlp -> value[NL_OFFS] ); 5203076Smckusic # ifdef DEC11 5213076Smckusic put(3, O_MAX, 8, 1); 5223076Smckusic # else 5233076Smckusic put(3, O_MAX, 9, 1); 5243076Smckusic # endif DEC11 5253172Smckusic convert(nl+T4INT, INT_TYP); 5263172Smckusic stkcnt += sizeof(int); 527*3851Speter put(2, O_RV4 | cbn << 8 + INDX, 528*3851Speter tempnlp->value[NL_OFFS] ); 529768Speter fmtspec += VARPREC; 5303226Smckusic tmpfree(&soffset); 531768Speter } 532768Speter put(3, O_MAX, 1, 1); 533768Speter break; 534768Speter case TSTR: 535768Speter put(1, O_AS4); 536*3851Speter put(2, O_RV4 | cbn << 8 + INDX, 537*3851Speter tempnlp -> value[ NL_OFFS ] ); 538768Speter put(3, O_MAX, strnglen, 0); 539768Speter break; 540768Speter default: 541768Speter if ( opt( 't' ) ) { 542768Speter put(3, O_MAX, 0, 0); 543768Speter } 544768Speter break; 545768Speter } 5463172Smckusic convert(nl+T4INT, INT_TYP); 5473172Smckusic stkcnt += sizeof(int); 548768Speter } 549768Speter /* 550768Speter * Generate the format string 551768Speter */ 552768Speter switch (fmtspec) { 553768Speter default: 554768Speter panic("fmt2"); 555768Speter case SKIP: 556768Speter break; 5572073Smckusic case NIL: 5582073Smckusic sprintf(&format[1], "%%%c", fmt); 5592073Smckusic goto fmtgen; 560768Speter case CONWIDTH: 5613076Smckusic sprintf(&format[1], "%%%d%c", field, fmt); 562768Speter goto fmtgen; 563768Speter case VARWIDTH: 564768Speter sprintf(&format[1], "%%*%c", fmt); 565768Speter goto fmtgen; 566768Speter case CONWIDTH + CONPREC: 5673076Smckusic sprintf(&format[1], "%%%d.%d%c", field, prec, fmt); 568768Speter goto fmtgen; 569768Speter case CONWIDTH + VARPREC: 5703076Smckusic sprintf(&format[1], "%%%d.*%c", field, fmt); 571768Speter goto fmtgen; 572768Speter case VARWIDTH + CONPREC: 5733076Smckusic sprintf(&format[1], "%%*.%d%c", prec, fmt); 574768Speter goto fmtgen; 575768Speter case VARWIDTH + VARPREC: 576768Speter sprintf(&format[1], "%%*.*%c", fmt); 577768Speter fmtgen: 578768Speter fmtlen = lenstr(&format[fmtstart], 0); 579768Speter put(2, O_LVCON, fmtlen); 580768Speter putstr(&format[fmtstart], 0); 581768Speter put(1, O_FILE); 5823172Smckusic stkcnt += 2 * sizeof(char *); 583768Speter put(2, O_WRITEF, stkcnt); 584768Speter } 585768Speter /* 586768Speter * Write the string after its blank padding 587768Speter */ 588768Speter if (typ == TSTR) { 589768Speter put(1, O_FILE); 5903172Smckusic put(2, CON_INT, 1); 591768Speter if (strfmt & VARWIDTH) { 592*3851Speter put(2, O_RV4 | cbn << 8 + INDX , 593*3851Speter tempnlp -> value[ NL_OFFS ] ); 594768Speter put(2, O_MIN, strnglen); 5953172Smckusic convert(nl+T4INT, INT_TYP); 5963226Smckusic tmpfree(&soffset); 597768Speter } else { 598768Speter if ((fmtspec & SKIP) && 599768Speter (strfmt & CONWIDTH)) { 600768Speter strnglen = field; 601768Speter } 6023172Smckusic put(2, CON_INT, strnglen); 603768Speter } 604768Speter ap = stkrval(alv, NIL , RREQ ); 6053172Smckusic put(2, O_WRITES, 6063172Smckusic 2 * sizeof(char *) + 2 * sizeof(int)); 607768Speter } 608768Speter } 609768Speter /* 610768Speter * Done with arguments. 611768Speter * Handle writeln and 612768Speter * insufficent number of args. 613768Speter */ 614768Speter switch (p->value[0] &~ NSTAND) { 615768Speter case O_WRITEF: 616768Speter if (argc == 0) 617768Speter error("Write requires an argument"); 618768Speter break; 619768Speter case O_MESSAGE: 620768Speter if (argc == 0) 621768Speter error("Message requires an argument"); 622768Speter case O_WRITLN: 623768Speter if (filetype != nl+T1CHAR) 624768Speter error("Can't 'writeln' a non text file"); 625768Speter put(1, O_WRITLN); 626768Speter break; 627768Speter } 628768Speter return; 629768Speter 630768Speter case O_READ4: 631768Speter case O_READLN: 632768Speter /* 633768Speter * Set up default 634768Speter * file "input". 635768Speter */ 636768Speter file = NIL; 637768Speter filetype = nl+T1CHAR; 638768Speter /* 639768Speter * Determine the file implied 640768Speter * for the read and generate 641768Speter * code to make it the active file. 642768Speter */ 643768Speter if (argv != NIL) { 644768Speter codeoff(); 645768Speter ap = stkrval(argv[1], NIL , RREQ ); 646768Speter codeon(); 647768Speter if (ap == NIL) 648768Speter argv = argv[2]; 649768Speter if (ap != NIL && ap->class == FILET) { 650768Speter /* 651768Speter * Got "read(f, ...", make 652768Speter * f the active file, and save 653768Speter * it and its type for use in 654768Speter * processing the rest of the 655768Speter * arguments to read. 656768Speter */ 657768Speter file = argv[1]; 658768Speter filetype = ap->type; 6592073Smckusic stklval(argv[1], NIL , LREQ ); 660768Speter put(1, O_UNIT); 661768Speter argv = argv[2]; 662768Speter argc--; 663768Speter } else { 664768Speter /* 665768Speter * Default is read from 666768Speter * standard input. 667768Speter */ 668768Speter put(1, O_UNITINP); 669768Speter input->nl_flags |= NUSED; 670768Speter } 671768Speter } else { 672768Speter put(1, O_UNITINP); 673768Speter input->nl_flags |= NUSED; 674768Speter } 675768Speter /* 676768Speter * Loop and process each 677768Speter * of the arguments. 678768Speter */ 679768Speter for (; argv != NIL; argv = argv[2]) { 680768Speter /* 681768Speter * Get the address of the target 682768Speter * on the stack. 683768Speter */ 684768Speter al = argv[1]; 685768Speter if (al == NIL) 686768Speter continue; 687768Speter if (al[0] != T_VAR) { 688768Speter error("Arguments to %s must be variables, not expressions", p->symbol); 689768Speter continue; 690768Speter } 691768Speter ap = stklval(al, MOD|ASGN|NOUSE); 692768Speter if (ap == NIL) 693768Speter continue; 694768Speter if (filetype != nl+T1CHAR) { 695768Speter /* 696768Speter * Generalized read, i.e. 697768Speter * from a non-textfile. 698768Speter */ 699768Speter if (incompat(filetype, ap, argv[1] )) { 700768Speter error("Type mismatch in read from non-text file"); 701768Speter continue; 702768Speter } 703768Speter /* 704768Speter * var := file ^; 705768Speter */ 706768Speter if (file != NIL) 7072073Smckusic stklval(file, NIL , LREQ ); 708768Speter else /* Magic */ 7093076Smckusic put(2, PTR_RV, (int)input->value[0]); 710768Speter put(1, O_FNIL); 711768Speter put(2, O_IND, width(filetype)); 712768Speter convert(filetype, ap); 713768Speter if (isa(ap, "bsci")) 714768Speter rangechk(ap, ap); 715768Speter put(2, O_AS, width(ap)); 716768Speter /* 717768Speter * get(file); 718768Speter */ 719768Speter put(1, O_GET); 720768Speter continue; 721768Speter } 722768Speter typ = classify(ap); 723768Speter op = rdops(typ); 724768Speter if (op == NIL) { 725768Speter error("Can't read %ss from a text file", clnames[typ]); 726768Speter continue; 727768Speter } 728768Speter if (op != O_READE) 729768Speter put(1, op); 730768Speter else { 7313076Smckusic put(2, op, (long)listnames(ap)); 7321628Speter warning(); 733768Speter if (opt('s')) { 734768Speter standard(); 735768Speter } 7361628Speter error("Reading scalars from text files is non-standard"); 737768Speter } 738768Speter /* 739768Speter * Data read is on the stack. 740768Speter * Assign it. 741768Speter */ 742768Speter if (op != O_READ8 && op != O_READE) 743768Speter rangechk(ap, op == O_READC ? ap : nl+T4INT); 744768Speter gen(O_AS2, O_AS2, width(ap), 745768Speter op == O_READ8 ? 8 : op == O_READ4 ? 4 : 2); 746768Speter } 747768Speter /* 748768Speter * Done with arguments. 749768Speter * Handle readln and 750768Speter * insufficient number of args. 751768Speter */ 752768Speter if (p->value[0] == O_READLN) { 753768Speter if (filetype != nl+T1CHAR) 754768Speter error("Can't 'readln' a non text file"); 755768Speter put(1, O_READLN); 756768Speter } 757768Speter else if (argc == 0) 758768Speter error("read requires an argument"); 759768Speter return; 760768Speter 761768Speter case O_GET: 762768Speter case O_PUT: 763768Speter if (argc != 1) { 764768Speter error("%s expects one argument", p->symbol); 765768Speter return; 766768Speter } 7672073Smckusic ap = stklval(argv[1], NIL , LREQ ); 768768Speter if (ap == NIL) 769768Speter return; 770768Speter if (ap->class != FILET) { 771768Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 772768Speter return; 773768Speter } 774768Speter put(1, O_UNIT); 775768Speter put(1, op); 776768Speter return; 777768Speter 778768Speter case O_RESET: 779768Speter case O_REWRITE: 780768Speter if (argc == 0 || argc > 2) { 781768Speter error("%s expects one or two arguments", p->symbol); 782768Speter return; 783768Speter } 784768Speter if (opt('s') && argc == 2) { 785768Speter standard(); 786768Speter error("Two argument forms of reset and rewrite are non-standard"); 787768Speter } 7882073Smckusic codeoff(); 789768Speter ap = stklval(argv[1], MOD|NOUSE); 7902073Smckusic codeon(); 791768Speter if (ap == NIL) 792768Speter return; 793768Speter if (ap->class != FILET) { 794768Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 795768Speter return; 796768Speter } 7972073Smckusic put(2, O_CON24, text(ap) ? 0: width(ap->type)); 798768Speter if (argc == 2) { 799768Speter /* 800768Speter * Optional second argument 801768Speter * is a string name of a 802768Speter * UNIX (R) file to be associated. 803768Speter */ 804768Speter al = argv[2]; 8052073Smckusic codeoff(); 806768Speter al = stkrval(al[1], NOFLAGS , RREQ ); 8072073Smckusic codeon(); 808768Speter if (al == NIL) 809768Speter return; 810768Speter if (classify(al) != TSTR) { 811768Speter error("Second argument to %s must be a string, not %s", p->symbol, nameof(al)); 812768Speter return; 813768Speter } 8142073Smckusic put(2, O_CON24, width(al)); 8152073Smckusic al = argv[2]; 8162073Smckusic al = stkrval(al[1], NOFLAGS , RREQ ); 817768Speter } else { 8182073Smckusic put(2, O_CON24, 0); 8193076Smckusic put(2, PTR_CON, NIL); 820768Speter } 8212073Smckusic ap = stklval(argv[1], MOD|NOUSE); 822768Speter put(1, op); 823768Speter return; 824768Speter 825768Speter case O_NEW: 826768Speter case O_DISPOSE: 827768Speter if (argc == 0) { 828768Speter error("%s expects at least one argument", p->symbol); 829768Speter return; 830768Speter } 831768Speter ap = stklval(argv[1], op == O_NEW ? ( MOD | NOUSE ) : MOD ); 832768Speter if (ap == NIL) 833768Speter return; 834768Speter if (ap->class != PTR) { 835768Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 836768Speter return; 837768Speter } 838768Speter ap = ap->type; 839768Speter if (ap == NIL) 840768Speter return; 841768Speter argv = argv[2]; 842768Speter if (argv != NIL) { 843768Speter if (ap->class != RECORD) { 844768Speter error("Record required when specifying variant tags"); 845768Speter return; 846768Speter } 847768Speter for (; argv != NIL; argv = argv[2]) { 848768Speter if (ap->ptr[NL_VARNT] == NIL) { 849768Speter error("Too many tag fields"); 850768Speter return; 851768Speter } 852768Speter if (!isconst(argv[1])) { 853768Speter error("Second and successive arguments to %s must be constants", p->symbol); 854768Speter return; 855768Speter } 856768Speter gconst(argv[1]); 857768Speter if (con.ctype == NIL) 858768Speter return; 859768Speter if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) { 860768Speter cerror("Specified tag constant type clashed with variant case selector type"); 861768Speter return; 862768Speter } 863768Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 864768Speter if (ap->range[0] == con.crval) 865768Speter break; 866768Speter if (ap == NIL) { 867768Speter error("No variant case label value equals specified constant value"); 868768Speter return; 869768Speter } 870768Speter ap = ap->ptr[NL_VTOREC]; 871768Speter } 872768Speter } 873768Speter put(2, op, width(ap)); 874768Speter return; 875768Speter 876768Speter case O_DATE: 877768Speter case O_TIME: 878768Speter if (argc != 1) { 879768Speter error("%s expects one argument", p->symbol); 880768Speter return; 881768Speter } 882768Speter ap = stklval(argv[1], MOD|NOUSE); 883768Speter if (ap == NIL) 884768Speter return; 885768Speter if (classify(ap) != TSTR || width(ap) != 10) { 886768Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 887768Speter return; 888768Speter } 889768Speter put(1, op); 890768Speter return; 891768Speter 892768Speter case O_HALT: 893768Speter if (argc != 0) { 894768Speter error("halt takes no arguments"); 895768Speter return; 896768Speter } 897768Speter put(1, op); 898768Speter noreach = 1; 899768Speter return; 900768Speter 901768Speter case O_ARGV: 902768Speter if (argc != 2) { 903768Speter error("argv takes two arguments"); 904768Speter return; 905768Speter } 906768Speter ap = stkrval(argv[1], NIL , RREQ ); 907768Speter if (ap == NIL) 908768Speter return; 909768Speter if (isnta(ap, "i")) { 910768Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 911768Speter return; 912768Speter } 913768Speter al = argv[2]; 914768Speter ap = stklval(al[1], MOD|NOUSE); 915768Speter if (ap == NIL) 916768Speter return; 917768Speter if (classify(ap) != TSTR) { 918768Speter error("argv's second argument must be a string, not %s", nameof(ap)); 919768Speter return; 920768Speter } 921768Speter put(2, op, width(ap)); 922768Speter return; 923768Speter 924768Speter case O_STLIM: 925768Speter if (argc != 1) { 926768Speter error("stlimit requires one argument"); 927768Speter return; 928768Speter } 929768Speter ap = stkrval(argv[1], NIL , RREQ ); 930768Speter if (ap == NIL) 931768Speter return; 932768Speter if (isnta(ap, "i")) { 933768Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 934768Speter return; 935768Speter } 936768Speter if (width(ap) != 4) 937768Speter put(1, O_STOI); 938768Speter put(1, op); 939768Speter return; 940768Speter 941768Speter case O_REMOVE: 942768Speter if (argc != 1) { 943768Speter error("remove expects one argument"); 944768Speter return; 945768Speter } 9462073Smckusic codeoff(); 947768Speter ap = stkrval(argv[1], NOFLAGS , RREQ ); 9482073Smckusic codeon(); 949768Speter if (ap == NIL) 950768Speter return; 951768Speter if (classify(ap) != TSTR) { 952768Speter error("remove's argument must be a string, not %s", nameof(ap)); 953768Speter return; 954768Speter } 955768Speter put(2, O_CON24, width(ap)); 9562073Smckusic ap = stkrval(argv[1], NOFLAGS , RREQ ); 957768Speter put(1, op); 958768Speter return; 959768Speter 960768Speter case O_LLIMIT: 961768Speter if (argc != 2) { 962768Speter error("linelimit expects two arguments"); 963768Speter return; 964768Speter } 965768Speter al = argv[2]; 966768Speter ap = stkrval(al[1], NIL , RREQ ); 967768Speter if (ap == NIL) 968768Speter return; 969768Speter if (isnta(ap, "i")) { 970768Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 971768Speter return; 972768Speter } 9732073Smckusic ap = stklval(argv[1], NOFLAGS|NOUSE); 9742073Smckusic if (ap == NIL) 9752073Smckusic return; 9762073Smckusic if (!text(ap)) { 9772073Smckusic error("linelimit's first argument must be a text file, not %s", nameof(ap)); 9782073Smckusic return; 9792073Smckusic } 980768Speter put(1, op); 981768Speter return; 982768Speter case O_PAGE: 983768Speter if (argc != 1) { 984768Speter error("page expects one argument"); 985768Speter return; 986768Speter } 9872073Smckusic ap = stklval(argv[1], NIL , LREQ ); 988768Speter if (ap == NIL) 989768Speter return; 990768Speter if (!text(ap)) { 991768Speter error("Argument to page must be a text file, not %s", nameof(ap)); 992768Speter return; 993768Speter } 994768Speter put(1, O_UNIT); 995768Speter put(1, op); 996768Speter return; 997768Speter 998768Speter case O_PACK: 999768Speter if (argc != 3) { 1000768Speter error("pack expects three arguments"); 1001768Speter return; 1002768Speter } 1003768Speter pu = "pack(a,i,z)"; 10043076Smckusic pua = argv[1]; 10053076Smckusic al = argv[2]; 10063076Smckusic pui = al[1]; 10073076Smckusic alv = al[2]; 10083076Smckusic puz = alv[1]; 1009768Speter goto packunp; 1010768Speter case O_UNPACK: 1011768Speter if (argc != 3) { 1012768Speter error("unpack expects three arguments"); 1013768Speter return; 1014768Speter } 1015768Speter pu = "unpack(z,a,i)"; 10163076Smckusic puz = argv[1]; 10173076Smckusic al = argv[2]; 10183076Smckusic pua = al[1]; 10193076Smckusic alv = al[2]; 10203076Smckusic pui = alv[1]; 1021768Speter packunp: 10222073Smckusic codeoff(); 1023768Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 10242073Smckusic al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 10252073Smckusic codeon(); 1026768Speter if (ap == NIL) 1027768Speter return; 1028768Speter if (ap->class != ARRAY) { 1029768Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 1030768Speter return; 1031768Speter } 1032768Speter if (al->class != ARRAY) { 1033768Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 1034768Speter return; 1035768Speter } 1036768Speter if (al->type == NIL || ap->type == NIL) 1037768Speter return; 1038768Speter if (al->type != ap->type) { 1039768Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 1040768Speter return; 1041768Speter } 1042768Speter k = width(al); 1043768Speter itemwidth = width(ap->type); 1044768Speter ap = ap->chain; 1045768Speter al = al->chain; 1046768Speter if (ap->chain != NIL || al->chain != NIL) { 1047768Speter error("%s requires a and z to be single dimension arrays", pu); 1048768Speter return; 1049768Speter } 1050768Speter if (ap == NIL || al == NIL) 1051768Speter return; 1052768Speter /* 1053768Speter * al is the range for z i.e. u..v 1054768Speter * ap is the range for a i.e. m..n 1055768Speter * i will be n-m+1 1056768Speter * j will be v-u+1 1057768Speter */ 1058768Speter i = ap->range[1] - ap->range[0] + 1; 1059768Speter j = al->range[1] - al->range[0] + 1; 1060768Speter if (i < j) { 1061768Speter error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i); 1062768Speter return; 1063768Speter } 1064768Speter /* 1065768Speter * get n-m-(v-u) and m for the interpreter 1066768Speter */ 1067768Speter i -= j; 1068768Speter j = ap->range[0]; 10692073Smckusic put(2, O_CON24, k); 10702073Smckusic put(2, O_CON24, i); 10712073Smckusic put(2, O_CON24, j); 10722073Smckusic put(2, O_CON24, itemwidth); 10732073Smckusic al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 10742073Smckusic ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 10752073Smckusic ap = stkrval((int *) pui, NLNIL , RREQ ); 10762073Smckusic if (ap == NIL) 10772073Smckusic return; 10782073Smckusic put(1, op); 1079768Speter return; 1080768Speter case 0: 1081768Speter error("%s is an unimplemented 6400 extension", p->symbol); 1082768Speter return; 1083768Speter 1084768Speter default: 1085768Speter panic("proc case"); 1086768Speter } 1087768Speter } 1088768Speter #endif OBJ 1089