1768Speter /* Copyright (c) 1979 Regents of the University of California */ 2768Speter 3*7928Smckusick static char sccsid[] = "@(#)proc.c 1.11 08/27/82"; 4768Speter 5768Speter #include "whoami.h" 6768Speter #ifdef OBJ 7768Speter /* 8768Speter * and the rest of the file 9768Speter */ 10768Speter #include "0.h" 11768Speter #include "tree.h" 12768Speter #include "opcode.h" 13768Speter #include "objfmt.h" 14768Speter 15768Speter /* 16768Speter * The following array is used to determine which classes may be read 17768Speter * from textfiles. It is indexed by the return value from classify. 18768Speter */ 19768Speter #define rdops(x) rdxxxx[(x)-(TFIRST)] 20768Speter 21768Speter int rdxxxx[] = { 22768Speter 0, /* -7 file types */ 23768Speter 0, /* -6 record types */ 24768Speter 0, /* -5 array types */ 25768Speter O_READE, /* -4 scalar types */ 26768Speter 0, /* -3 pointer types */ 27768Speter 0, /* -2 set types */ 28768Speter 0, /* -1 string types */ 29768Speter 0, /* 0 nil, no type */ 30768Speter O_READE, /* 1 boolean */ 31768Speter O_READC, /* 2 character */ 32768Speter O_READ4, /* 3 integer */ 33768Speter O_READ8 /* 4 real */ 34768Speter }; 35768Speter 36768Speter /* 37768Speter * Proc handles procedure calls. 38768Speter * Non-builtin procedures are "buck-passed" to func (with a flag 39768Speter * indicating that they are actually procedures. 40768Speter * builtin procedures are handled here. 41768Speter */ 42768Speter proc(r) 43768Speter int *r; 44768Speter { 45768Speter register struct nl *p; 46768Speter register int *alv, *al, op; 47768Speter struct nl *filetype, *ap; 48768Speter int argc, *argv, typ, fmtspec, strfmt, stkcnt, *file; 49768Speter char fmt, format[20], *strptr; 50768Speter int prec, field, strnglen, fmtlen, fmtstart, pu; 51768Speter int *pua, *pui, *puz; 52768Speter int i, j, k; 53768Speter int itemwidth; 543226Smckusic struct tmps soffset; 553851Speter struct nl *tempnlp; 56768Speter 57768Speter #define CONPREC 4 58768Speter #define VARPREC 8 59768Speter #define CONWIDTH 1 60768Speter #define VARWIDTH 2 61768Speter #define SKIP 16 62768Speter 63768Speter /* 64768Speter * Verify that the name is 65768Speter * defined and is that of a 66768Speter * procedure. 67768Speter */ 68768Speter p = lookup(r[2]); 69768Speter if (p == NIL) { 70768Speter rvlist(r[3]); 71768Speter return; 72768Speter } 731198Speter if (p->class != PROC && p->class != FPROC) { 74768Speter error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]); 75768Speter rvlist(r[3]); 76768Speter return; 77768Speter } 78768Speter argv = r[3]; 79768Speter 80768Speter /* 81768Speter * Call handles user defined 82768Speter * procedures and functions. 83768Speter */ 84768Speter if (bn != 0) { 85768Speter call(p, argv, PROC, bn); 86768Speter return; 87768Speter } 88768Speter 89768Speter /* 90768Speter * Call to built-in procedure. 91768Speter * Count the arguments. 92768Speter */ 93768Speter argc = 0; 94768Speter for (al = argv; al != NIL; al = al[2]) 95768Speter argc++; 96768Speter 97768Speter /* 98768Speter * Switch on the operator 99768Speter * associated with the built-in 100768Speter * procedure in the namelist 101768Speter */ 102768Speter op = p->value[0] &~ NSTAND; 103768Speter if (opt('s') && (p->value[0] & NSTAND)) { 104768Speter standard(); 105768Speter error("%s is a nonstandard procedure", p->symbol); 106768Speter } 107768Speter switch (op) { 108768Speter 109768Speter case O_ABORT: 110768Speter if (argc != 0) 111768Speter error("null takes no arguments"); 112768Speter return; 113768Speter 114768Speter case O_FLUSH: 115768Speter if (argc == 0) { 116768Speter put(1, O_MESSAGE); 117768Speter return; 118768Speter } 119768Speter if (argc != 1) { 120768Speter error("flush takes at most one argument"); 121768Speter return; 122768Speter } 1232073Smckusic ap = stklval(argv[1], NIL , LREQ ); 124768Speter if (ap == NIL) 125768Speter return; 126768Speter if (ap->class != FILET) { 127768Speter error("flush's argument must be a file, not %s", nameof(ap)); 128768Speter return; 129768Speter } 130768Speter put(1, op); 131768Speter return; 132768Speter 133768Speter case O_MESSAGE: 134768Speter case O_WRITEF: 135768Speter case O_WRITLN: 136768Speter /* 137768Speter * Set up default file "output"'s type 138768Speter */ 139768Speter file = NIL; 140768Speter filetype = nl+T1CHAR; 141768Speter /* 142768Speter * Determine the file implied 143768Speter * for the write and generate 144768Speter * code to make it the active file. 145768Speter */ 146768Speter if (op == O_MESSAGE) { 147768Speter /* 148768Speter * For message, all that matters 149768Speter * is that the filetype is 150768Speter * a character file. 151768Speter * Thus "output" will suit us fine. 152768Speter */ 153768Speter put(1, O_MESSAGE); 154768Speter } else if (argv != NIL && (al = argv[1])[0] != T_WEXP) { 155768Speter /* 156768Speter * If there is a first argument which has 157768Speter * no write widths, then it is potentially 158768Speter * a file name. 159768Speter */ 160768Speter codeoff(); 161768Speter ap = stkrval(argv[1], NIL , RREQ ); 162768Speter codeon(); 163768Speter if (ap == NIL) 164768Speter argv = argv[2]; 165768Speter if (ap != NIL && ap->class == FILET) { 166768Speter /* 167768Speter * Got "write(f, ...", make 168768Speter * f the active file, and save 169768Speter * it and its type for use in 170768Speter * processing the rest of the 171768Speter * arguments to write. 172768Speter */ 173768Speter file = argv[1]; 174768Speter filetype = ap->type; 1752073Smckusic stklval(argv[1], NIL , LREQ ); 176768Speter put(1, O_UNIT); 177768Speter /* 178768Speter * Skip over the first argument 179768Speter */ 180768Speter argv = argv[2]; 181768Speter argc--; 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) { 3456542Smckusick case TPTR: 3466542Smckusick warning(); 3476542Smckusick if (opt('s')) { 3486542Smckusick standard(); 3496542Smckusick } 3506542Smckusick error("Writing %ss to text files is non-standard", 3516542Smckusick clnames[typ]); 3526542Smckusick /* and fall through */ 353768Speter case TINT: 354768Speter if (fmt != 'f') { 355768Speter ap = stkrval(alv, NIL , RREQ ); 3563172Smckusic stkcnt += sizeof(long); 357768Speter } else { 358768Speter ap = stkrval(alv, NIL , RREQ ); 359768Speter put(1, O_ITOD); 3603172Smckusic stkcnt += sizeof(double); 361768Speter typ = TDOUBLE; 362768Speter goto tdouble; 363768Speter } 364768Speter if (fmtspec == NIL) { 365768Speter if (fmt == 'D') 366768Speter field = 10; 367768Speter else if (fmt == 'X') 368768Speter field = 8; 369768Speter else if (fmt == 'O') 370768Speter field = 11; 371768Speter else 372768Speter panic("fmt1"); 373768Speter fmtspec = CONWIDTH; 374768Speter } 375768Speter break; 376768Speter case TCHAR: 377768Speter tchar: 3782073Smckusic if (fmtspec == NIL) { 3792073Smckusic put(1, O_FILE); 3802073Smckusic ap = stkrval(alv, NIL , RREQ ); 3813172Smckusic convert(nl + T4INT, INT_TYP); 3823172Smckusic put(2, O_WRITEC, 3833172Smckusic sizeof(char *) + sizeof(int)); 3842073Smckusic fmtspec = SKIP; 3852073Smckusic break; 3862073Smckusic } 387768Speter ap = stkrval(alv, NIL , RREQ ); 3883172Smckusic convert(nl + T4INT, INT_TYP); 3893172Smckusic stkcnt += sizeof(int); 390768Speter fmt = 'c'; 391768Speter break; 392768Speter case TSCAL: 3931628Speter warning(); 394768Speter if (opt('s')) { 395768Speter standard(); 396768Speter } 3976542Smckusick error("Writing %ss to text files is non-standard", 3986542Smckusick clnames[typ]); 3996542Smckusick /* and fall through */ 400768Speter case TBOOL: 401768Speter stkrval(alv, NIL , RREQ ); 4023076Smckusic put(2, O_NAM, (long)listnames(ap)); 4033172Smckusic stkcnt += sizeof(char *); 404768Speter fmt = 's'; 405768Speter break; 406768Speter case TDOUBLE: 407768Speter ap = stkrval(alv, TDOUBLE , RREQ ); 4083172Smckusic stkcnt += sizeof(double); 409768Speter tdouble: 410768Speter switch (fmtspec) { 411768Speter case NIL: 4123076Smckusic # ifdef DEC11 4133076Smckusic field = 21; 4143076Smckusic # else 4153076Smckusic field = 22; 4163076Smckusic # endif DEC11 417768Speter prec = 14; 4183076Smckusic fmt = 'e'; 419768Speter fmtspec = CONWIDTH + CONPREC; 420768Speter break; 421768Speter case CONWIDTH: 422768Speter if (--field < 1) 423768Speter field = 1; 4243076Smckusic # ifdef DEC11 4253076Smckusic prec = field - 7; 4263076Smckusic # else 4273076Smckusic prec = field - 8; 4283076Smckusic # endif DEC11 429768Speter if (prec < 1) 430768Speter prec = 1; 431768Speter fmtspec += CONPREC; 4323076Smckusic fmt = 'e'; 433768Speter break; 434768Speter case CONWIDTH + CONPREC: 435768Speter case CONWIDTH + VARPREC: 436768Speter if (--field < 1) 437768Speter field = 1; 438768Speter } 439768Speter format[0] = ' '; 440768Speter fmtstart = 0; 441768Speter break; 442768Speter case TSTR: 443768Speter constval( alv ); 444768Speter switch ( classify( con.ctype ) ) { 445768Speter case TCHAR: 446768Speter typ = TCHAR; 447768Speter goto tchar; 448768Speter case TSTR: 449768Speter strptr = con.cpval; 450768Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 451768Speter strptr = con.cpval; 452768Speter break; 453768Speter default: 454768Speter strnglen = width(ap); 455768Speter break; 456768Speter } 457768Speter fmt = 's'; 458768Speter strfmt = fmtspec; 459768Speter if (fmtspec == NIL) { 460768Speter fmtspec = SKIP; 461768Speter break; 462768Speter } 463768Speter if (fmtspec & CONWIDTH) { 464768Speter if (field <= strnglen) { 465768Speter fmtspec = SKIP; 466768Speter break; 467768Speter } else 468768Speter field -= strnglen; 469768Speter } 470768Speter /* 471768Speter * push string to implement leading blank padding 472768Speter */ 473768Speter put(2, O_LVCON, 2); 474768Speter putstr("", 0); 4753172Smckusic stkcnt += sizeof(char *); 476768Speter break; 477768Speter default: 478768Speter error("Can't write %ss to a text file", clnames[typ]); 479768Speter continue; 480768Speter } 481768Speter /* 482768Speter * If there is a variable precision, evaluate it onto 483768Speter * the stack 484768Speter */ 485768Speter if (fmtspec & VARPREC) { 486768Speter ap = stkrval(al[3], NIL , RREQ ); 487768Speter if (ap == NIL) 488768Speter continue; 489768Speter if (isnta(ap,"i")) { 490768Speter error("Second write width must be integer, not %s", nameof(ap)); 491768Speter continue; 492768Speter } 493768Speter if ( opt( 't' ) ) { 494768Speter put(3, O_MAX, 0, 0); 495768Speter } 4963172Smckusic convert(nl+T4INT, INT_TYP); 4973172Smckusic stkcnt += sizeof(int); 498768Speter } 499768Speter /* 500768Speter * If there is a variable width, evaluate it onto 501768Speter * the stack 502768Speter */ 503768Speter if (fmtspec & VARWIDTH) { 504768Speter if ( ( typ == TDOUBLE && fmtspec == VARWIDTH ) 505768Speter || typ == TSTR ) { 5063226Smckusic soffset = sizes[cbn].curtmps; 5073851Speter tempnlp = tmpalloc(sizeof(long), 5083226Smckusic nl+T4INT, REGOK); 5093851Speter put(2, O_LV | cbn << 8 + INDX, 5103851Speter tempnlp -> value[ NL_OFFS ] ); 511768Speter } 512768Speter ap = stkrval(al[2], NIL , RREQ ); 513768Speter if (ap == NIL) 514768Speter continue; 515768Speter if (isnta(ap,"i")) { 516768Speter error("First write width must be integer, not %s", nameof(ap)); 517768Speter continue; 518768Speter } 519768Speter /* 520768Speter * Perform special processing on widths based 521768Speter * on data type 522768Speter */ 523768Speter switch (typ) { 524768Speter case TDOUBLE: 525768Speter if (fmtspec == VARWIDTH) { 5263076Smckusic fmt = 'e'; 527768Speter put(1, O_AS4); 5283851Speter put(2, O_RV4 | cbn << 8 + INDX, 5293851Speter tempnlp -> value[NL_OFFS] ); 5303076Smckusic # ifdef DEC11 5313076Smckusic put(3, O_MAX, 8, 1); 5323076Smckusic # else 5333076Smckusic put(3, O_MAX, 9, 1); 5343076Smckusic # endif DEC11 5353172Smckusic convert(nl+T4INT, INT_TYP); 5363172Smckusic stkcnt += sizeof(int); 5373851Speter put(2, O_RV4 | cbn << 8 + INDX, 5383851Speter tempnlp->value[NL_OFFS] ); 539768Speter fmtspec += VARPREC; 5403226Smckusic tmpfree(&soffset); 541768Speter } 542768Speter put(3, O_MAX, 1, 1); 543768Speter break; 544768Speter case TSTR: 545768Speter put(1, O_AS4); 5463851Speter put(2, O_RV4 | cbn << 8 + INDX, 5473851Speter tempnlp -> value[ NL_OFFS ] ); 548768Speter put(3, O_MAX, strnglen, 0); 549768Speter break; 550768Speter default: 551768Speter if ( opt( 't' ) ) { 552768Speter put(3, O_MAX, 0, 0); 553768Speter } 554768Speter break; 555768Speter } 5563172Smckusic convert(nl+T4INT, INT_TYP); 5573172Smckusic stkcnt += sizeof(int); 558768Speter } 559768Speter /* 560768Speter * Generate the format string 561768Speter */ 562768Speter switch (fmtspec) { 563768Speter default: 564768Speter panic("fmt2"); 565768Speter case SKIP: 566768Speter break; 5672073Smckusic case NIL: 5682073Smckusic sprintf(&format[1], "%%%c", fmt); 5692073Smckusic goto fmtgen; 570768Speter case CONWIDTH: 5713076Smckusic sprintf(&format[1], "%%%d%c", field, fmt); 572768Speter goto fmtgen; 573768Speter case VARWIDTH: 574768Speter sprintf(&format[1], "%%*%c", fmt); 575768Speter goto fmtgen; 576768Speter case CONWIDTH + CONPREC: 5773076Smckusic sprintf(&format[1], "%%%d.%d%c", field, prec, fmt); 578768Speter goto fmtgen; 579768Speter case CONWIDTH + VARPREC: 5803076Smckusic sprintf(&format[1], "%%%d.*%c", field, fmt); 581768Speter goto fmtgen; 582768Speter case VARWIDTH + CONPREC: 5833076Smckusic sprintf(&format[1], "%%*.%d%c", prec, fmt); 584768Speter goto fmtgen; 585768Speter case VARWIDTH + VARPREC: 586768Speter sprintf(&format[1], "%%*.*%c", fmt); 587768Speter fmtgen: 588768Speter fmtlen = lenstr(&format[fmtstart], 0); 589768Speter put(2, O_LVCON, fmtlen); 590768Speter putstr(&format[fmtstart], 0); 591768Speter put(1, O_FILE); 5923172Smckusic stkcnt += 2 * sizeof(char *); 593768Speter put(2, O_WRITEF, stkcnt); 594768Speter } 595768Speter /* 596768Speter * Write the string after its blank padding 597768Speter */ 598768Speter if (typ == TSTR) { 599768Speter put(1, O_FILE); 6003172Smckusic put(2, CON_INT, 1); 601768Speter if (strfmt & VARWIDTH) { 6023851Speter put(2, O_RV4 | cbn << 8 + INDX , 6033851Speter tempnlp -> value[ NL_OFFS ] ); 604768Speter put(2, O_MIN, strnglen); 6053172Smckusic convert(nl+T4INT, INT_TYP); 6063226Smckusic tmpfree(&soffset); 607768Speter } else { 608768Speter if ((fmtspec & SKIP) && 609768Speter (strfmt & CONWIDTH)) { 610768Speter strnglen = field; 611768Speter } 6123172Smckusic put(2, CON_INT, strnglen); 613768Speter } 614768Speter ap = stkrval(alv, NIL , RREQ ); 6153172Smckusic put(2, O_WRITES, 6163172Smckusic 2 * sizeof(char *) + 2 * sizeof(int)); 617768Speter } 618768Speter } 619768Speter /* 620768Speter * Done with arguments. 621768Speter * Handle writeln and 622768Speter * insufficent number of args. 623768Speter */ 624768Speter switch (p->value[0] &~ NSTAND) { 625768Speter case O_WRITEF: 626768Speter if (argc == 0) 627768Speter error("Write requires an argument"); 628768Speter break; 629768Speter case O_MESSAGE: 630768Speter if (argc == 0) 631768Speter error("Message requires an argument"); 632768Speter case O_WRITLN: 633768Speter if (filetype != nl+T1CHAR) 634768Speter error("Can't 'writeln' a non text file"); 635768Speter put(1, O_WRITLN); 636768Speter break; 637768Speter } 638768Speter return; 639768Speter 640768Speter case O_READ4: 641768Speter case O_READLN: 642768Speter /* 643768Speter * Set up default 644768Speter * file "input". 645768Speter */ 646768Speter file = NIL; 647768Speter filetype = nl+T1CHAR; 648768Speter /* 649768Speter * Determine the file implied 650768Speter * for the read and generate 651768Speter * code to make it the active file. 652768Speter */ 653768Speter if (argv != NIL) { 654768Speter codeoff(); 655768Speter ap = stkrval(argv[1], NIL , RREQ ); 656768Speter codeon(); 657768Speter if (ap == NIL) 658768Speter argv = argv[2]; 659768Speter if (ap != NIL && ap->class == FILET) { 660768Speter /* 661768Speter * Got "read(f, ...", make 662768Speter * f the active file, and save 663768Speter * it and its type for use in 664768Speter * processing the rest of the 665768Speter * arguments to read. 666768Speter */ 667768Speter file = argv[1]; 668768Speter filetype = ap->type; 6692073Smckusic stklval(argv[1], NIL , LREQ ); 670768Speter put(1, O_UNIT); 671768Speter argv = argv[2]; 672768Speter argc--; 673768Speter } else { 674768Speter /* 675768Speter * Default is read from 676768Speter * standard input. 677768Speter */ 678768Speter put(1, O_UNITINP); 679768Speter input->nl_flags |= NUSED; 680768Speter } 681768Speter } else { 682768Speter put(1, O_UNITINP); 683768Speter input->nl_flags |= NUSED; 684768Speter } 685768Speter /* 686768Speter * Loop and process each 687768Speter * of the arguments. 688768Speter */ 689768Speter for (; argv != NIL; argv = argv[2]) { 690768Speter /* 691768Speter * Get the address of the target 692768Speter * on the stack. 693768Speter */ 694768Speter al = argv[1]; 695768Speter if (al == NIL) 696768Speter continue; 697768Speter if (al[0] != T_VAR) { 698768Speter error("Arguments to %s must be variables, not expressions", p->symbol); 699768Speter continue; 700768Speter } 701768Speter ap = stklval(al, MOD|ASGN|NOUSE); 702768Speter if (ap == NIL) 703768Speter continue; 704768Speter if (filetype != nl+T1CHAR) { 705768Speter /* 706768Speter * Generalized read, i.e. 707768Speter * from a non-textfile. 708768Speter */ 709768Speter if (incompat(filetype, ap, argv[1] )) { 710768Speter error("Type mismatch in read from non-text file"); 711768Speter continue; 712768Speter } 713768Speter /* 714768Speter * var := file ^; 715768Speter */ 716768Speter if (file != NIL) 7172073Smckusic stklval(file, NIL , LREQ ); 718768Speter else /* Magic */ 7193076Smckusic put(2, PTR_RV, (int)input->value[0]); 720768Speter put(1, O_FNIL); 721768Speter put(2, O_IND, width(filetype)); 722768Speter convert(filetype, ap); 723768Speter if (isa(ap, "bsci")) 724768Speter rangechk(ap, ap); 725768Speter put(2, O_AS, width(ap)); 726768Speter /* 727768Speter * get(file); 728768Speter */ 729768Speter put(1, O_GET); 730768Speter continue; 731768Speter } 732768Speter typ = classify(ap); 733768Speter op = rdops(typ); 734768Speter if (op == NIL) { 735768Speter error("Can't read %ss from a text file", clnames[typ]); 736768Speter continue; 737768Speter } 738768Speter if (op != O_READE) 739768Speter put(1, op); 740768Speter else { 7413076Smckusic put(2, op, (long)listnames(ap)); 7421628Speter warning(); 743768Speter if (opt('s')) { 744768Speter standard(); 745768Speter } 7461628Speter error("Reading scalars from text files is non-standard"); 747768Speter } 748768Speter /* 749768Speter * Data read is on the stack. 750768Speter * Assign it. 751768Speter */ 752768Speter if (op != O_READ8 && op != O_READE) 753768Speter rangechk(ap, op == O_READC ? ap : nl+T4INT); 754768Speter gen(O_AS2, O_AS2, width(ap), 755768Speter op == O_READ8 ? 8 : op == O_READ4 ? 4 : 2); 756768Speter } 757768Speter /* 758768Speter * Done with arguments. 759768Speter * Handle readln and 760768Speter * insufficient number of args. 761768Speter */ 762768Speter if (p->value[0] == O_READLN) { 763768Speter if (filetype != nl+T1CHAR) 764768Speter error("Can't 'readln' a non text file"); 765768Speter put(1, O_READLN); 766768Speter } 767768Speter else if (argc == 0) 768768Speter error("read requires an argument"); 769768Speter return; 770768Speter 771768Speter case O_GET: 772768Speter case O_PUT: 773768Speter if (argc != 1) { 774768Speter error("%s expects one argument", p->symbol); 775768Speter return; 776768Speter } 7772073Smckusic ap = stklval(argv[1], NIL , LREQ ); 778768Speter if (ap == NIL) 779768Speter return; 780768Speter if (ap->class != FILET) { 781768Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 782768Speter return; 783768Speter } 784768Speter put(1, O_UNIT); 785768Speter put(1, op); 786768Speter return; 787768Speter 788768Speter case O_RESET: 789768Speter case O_REWRITE: 790768Speter if (argc == 0 || argc > 2) { 791768Speter error("%s expects one or two arguments", p->symbol); 792768Speter return; 793768Speter } 794768Speter if (opt('s') && argc == 2) { 795768Speter standard(); 796768Speter error("Two argument forms of reset and rewrite are non-standard"); 797768Speter } 7982073Smckusic codeoff(); 799768Speter ap = stklval(argv[1], MOD|NOUSE); 8002073Smckusic codeon(); 801768Speter if (ap == NIL) 802768Speter return; 803768Speter if (ap->class != FILET) { 804768Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 805768Speter return; 806768Speter } 8072073Smckusic put(2, O_CON24, text(ap) ? 0: width(ap->type)); 808768Speter if (argc == 2) { 809768Speter /* 810768Speter * Optional second argument 811768Speter * is a string name of a 812768Speter * UNIX (R) file to be associated. 813768Speter */ 814768Speter al = argv[2]; 8152073Smckusic codeoff(); 816768Speter al = stkrval(al[1], NOFLAGS , RREQ ); 8172073Smckusic codeon(); 818768Speter if (al == NIL) 819768Speter return; 820768Speter if (classify(al) != TSTR) { 821768Speter error("Second argument to %s must be a string, not %s", p->symbol, nameof(al)); 822768Speter return; 823768Speter } 8242073Smckusic put(2, O_CON24, width(al)); 8252073Smckusic al = argv[2]; 8262073Smckusic al = stkrval(al[1], NOFLAGS , RREQ ); 827768Speter } else { 8282073Smckusic put(2, O_CON24, 0); 8293076Smckusic put(2, PTR_CON, NIL); 830768Speter } 8312073Smckusic ap = stklval(argv[1], MOD|NOUSE); 832768Speter put(1, op); 833768Speter return; 834768Speter 835768Speter case O_NEW: 836768Speter case O_DISPOSE: 837768Speter if (argc == 0) { 838768Speter error("%s expects at least one argument", p->symbol); 839768Speter return; 840768Speter } 841768Speter ap = stklval(argv[1], op == O_NEW ? ( MOD | NOUSE ) : MOD ); 842768Speter if (ap == NIL) 843768Speter return; 844768Speter if (ap->class != PTR) { 845768Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 846768Speter return; 847768Speter } 848768Speter ap = ap->type; 849768Speter if (ap == NIL) 850768Speter return; 851768Speter argv = argv[2]; 852768Speter if (argv != NIL) { 853768Speter if (ap->class != RECORD) { 854768Speter error("Record required when specifying variant tags"); 855768Speter return; 856768Speter } 857768Speter for (; argv != NIL; argv = argv[2]) { 858768Speter if (ap->ptr[NL_VARNT] == NIL) { 859768Speter error("Too many tag fields"); 860768Speter return; 861768Speter } 862768Speter if (!isconst(argv[1])) { 863768Speter error("Second and successive arguments to %s must be constants", p->symbol); 864768Speter return; 865768Speter } 866768Speter gconst(argv[1]); 867768Speter if (con.ctype == NIL) 868768Speter return; 869768Speter if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) { 870768Speter cerror("Specified tag constant type clashed with variant case selector type"); 871768Speter return; 872768Speter } 873768Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 874768Speter if (ap->range[0] == con.crval) 875768Speter break; 876768Speter if (ap == NIL) { 877768Speter error("No variant case label value equals specified constant value"); 878768Speter return; 879768Speter } 880768Speter ap = ap->ptr[NL_VTOREC]; 881768Speter } 882768Speter } 883768Speter put(2, op, width(ap)); 884768Speter return; 885768Speter 886768Speter case O_DATE: 887768Speter case O_TIME: 888768Speter if (argc != 1) { 889768Speter error("%s expects one argument", p->symbol); 890768Speter return; 891768Speter } 892768Speter ap = stklval(argv[1], MOD|NOUSE); 893768Speter if (ap == NIL) 894768Speter return; 895768Speter if (classify(ap) != TSTR || width(ap) != 10) { 896768Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 897768Speter return; 898768Speter } 899768Speter put(1, op); 900768Speter return; 901768Speter 902768Speter case O_HALT: 903768Speter if (argc != 0) { 904768Speter error("halt takes no arguments"); 905768Speter return; 906768Speter } 907768Speter put(1, op); 908768Speter noreach = 1; 909768Speter return; 910768Speter 911768Speter case O_ARGV: 912768Speter if (argc != 2) { 913768Speter error("argv takes two arguments"); 914768Speter return; 915768Speter } 916768Speter ap = stkrval(argv[1], NIL , RREQ ); 917768Speter if (ap == NIL) 918768Speter return; 919768Speter if (isnta(ap, "i")) { 920768Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 921768Speter return; 922768Speter } 923768Speter al = argv[2]; 924768Speter ap = stklval(al[1], MOD|NOUSE); 925768Speter if (ap == NIL) 926768Speter return; 927768Speter if (classify(ap) != TSTR) { 928768Speter error("argv's second argument must be a string, not %s", nameof(ap)); 929768Speter return; 930768Speter } 931768Speter put(2, op, width(ap)); 932768Speter return; 933768Speter 934768Speter case O_STLIM: 935768Speter if (argc != 1) { 936768Speter error("stlimit requires one argument"); 937768Speter return; 938768Speter } 939768Speter ap = stkrval(argv[1], NIL , RREQ ); 940768Speter if (ap == NIL) 941768Speter return; 942768Speter if (isnta(ap, "i")) { 943768Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 944768Speter return; 945768Speter } 946768Speter if (width(ap) != 4) 947768Speter put(1, O_STOI); 948768Speter put(1, op); 949768Speter return; 950768Speter 951768Speter case O_REMOVE: 952768Speter if (argc != 1) { 953768Speter error("remove expects one argument"); 954768Speter return; 955768Speter } 9562073Smckusic codeoff(); 957768Speter ap = stkrval(argv[1], NOFLAGS , RREQ ); 9582073Smckusic codeon(); 959768Speter if (ap == NIL) 960768Speter return; 961768Speter if (classify(ap) != TSTR) { 962768Speter error("remove's argument must be a string, not %s", nameof(ap)); 963768Speter return; 964768Speter } 965768Speter put(2, O_CON24, width(ap)); 9662073Smckusic ap = stkrval(argv[1], NOFLAGS , RREQ ); 967768Speter put(1, op); 968768Speter return; 969768Speter 970768Speter case O_LLIMIT: 971768Speter if (argc != 2) { 972768Speter error("linelimit expects two arguments"); 973768Speter return; 974768Speter } 975768Speter al = argv[2]; 976768Speter ap = stkrval(al[1], NIL , RREQ ); 977768Speter if (ap == NIL) 978768Speter return; 979768Speter if (isnta(ap, "i")) { 980768Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 981768Speter return; 982768Speter } 9832073Smckusic ap = stklval(argv[1], NOFLAGS|NOUSE); 9842073Smckusic if (ap == NIL) 9852073Smckusic return; 9862073Smckusic if (!text(ap)) { 9872073Smckusic error("linelimit's first argument must be a text file, not %s", nameof(ap)); 9882073Smckusic return; 9892073Smckusic } 990768Speter put(1, op); 991768Speter return; 992768Speter case O_PAGE: 993768Speter if (argc != 1) { 994768Speter error("page expects one argument"); 995768Speter return; 996768Speter } 9972073Smckusic ap = stklval(argv[1], NIL , LREQ ); 998768Speter if (ap == NIL) 999768Speter return; 1000768Speter if (!text(ap)) { 1001768Speter error("Argument to page must be a text file, not %s", nameof(ap)); 1002768Speter return; 1003768Speter } 1004768Speter put(1, O_UNIT); 1005768Speter put(1, op); 1006768Speter return; 1007768Speter 1008*7928Smckusick case O_ASRT: 1009*7928Smckusick if (!opt('t')) 1010*7928Smckusick return; 1011*7928Smckusick if (argc == 0 || argc > 2) { 1012*7928Smckusick error("Assert expects one or two arguments"); 1013*7928Smckusick return; 1014*7928Smckusick } 1015*7928Smckusick if (argc == 2) { 1016*7928Smckusick /* 1017*7928Smckusick * Optional second argument is a string specifying 1018*7928Smckusick * why the assertion failed. 1019*7928Smckusick */ 1020*7928Smckusick al = argv[2]; 1021*7928Smckusick al = stkrval(al[1], NIL , RREQ ); 1022*7928Smckusick if (al == NIL) 1023*7928Smckusick return; 1024*7928Smckusick if (classify(al) != TSTR) { 1025*7928Smckusick error("Second argument to assert must be a string, not %s", nameof(al)); 1026*7928Smckusick return; 1027*7928Smckusick } 1028*7928Smckusick } else { 1029*7928Smckusick put(2, PTR_CON, NIL); 1030*7928Smckusick } 1031*7928Smckusick ap = stkrval(argv[1], NIL , RREQ ); 1032*7928Smckusick if (ap == NIL) 1033*7928Smckusick return; 1034*7928Smckusick if (isnta(ap, "b")) 1035*7928Smckusick error("Assert expression must be Boolean, not %ss", nameof(ap)); 1036*7928Smckusick put(1, O_ASRT); 1037*7928Smckusick return; 1038*7928Smckusick 1039768Speter case O_PACK: 1040768Speter if (argc != 3) { 1041768Speter error("pack expects three arguments"); 1042768Speter return; 1043768Speter } 1044768Speter pu = "pack(a,i,z)"; 10453076Smckusic pua = argv[1]; 10463076Smckusic al = argv[2]; 10473076Smckusic pui = al[1]; 10483076Smckusic alv = al[2]; 10493076Smckusic puz = alv[1]; 1050768Speter goto packunp; 1051768Speter case O_UNPACK: 1052768Speter if (argc != 3) { 1053768Speter error("unpack expects three arguments"); 1054768Speter return; 1055768Speter } 1056768Speter pu = "unpack(z,a,i)"; 10573076Smckusic puz = argv[1]; 10583076Smckusic al = argv[2]; 10593076Smckusic pua = al[1]; 10603076Smckusic alv = al[2]; 10613076Smckusic pui = alv[1]; 1062768Speter packunp: 10632073Smckusic codeoff(); 1064768Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 10652073Smckusic al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 10662073Smckusic codeon(); 1067768Speter if (ap == NIL) 1068768Speter return; 1069768Speter if (ap->class != ARRAY) { 1070768Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 1071768Speter return; 1072768Speter } 1073768Speter if (al->class != ARRAY) { 1074768Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 1075768Speter return; 1076768Speter } 1077768Speter if (al->type == NIL || ap->type == NIL) 1078768Speter return; 1079768Speter if (al->type != ap->type) { 1080768Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 1081768Speter return; 1082768Speter } 1083768Speter k = width(al); 1084768Speter itemwidth = width(ap->type); 1085768Speter ap = ap->chain; 1086768Speter al = al->chain; 1087768Speter if (ap->chain != NIL || al->chain != NIL) { 1088768Speter error("%s requires a and z to be single dimension arrays", pu); 1089768Speter return; 1090768Speter } 1091768Speter if (ap == NIL || al == NIL) 1092768Speter return; 1093768Speter /* 1094768Speter * al is the range for z i.e. u..v 1095768Speter * ap is the range for a i.e. m..n 1096768Speter * i will be n-m+1 1097768Speter * j will be v-u+1 1098768Speter */ 1099768Speter i = ap->range[1] - ap->range[0] + 1; 1100768Speter j = al->range[1] - al->range[0] + 1; 1101768Speter if (i < j) { 1102768Speter error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i); 1103768Speter return; 1104768Speter } 1105768Speter /* 1106768Speter * get n-m-(v-u) and m for the interpreter 1107768Speter */ 1108768Speter i -= j; 1109768Speter j = ap->range[0]; 11102073Smckusic put(2, O_CON24, k); 11112073Smckusic put(2, O_CON24, i); 11122073Smckusic put(2, O_CON24, j); 11132073Smckusic put(2, O_CON24, itemwidth); 11142073Smckusic al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 11152073Smckusic ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 11162073Smckusic ap = stkrval((int *) pui, NLNIL , RREQ ); 11172073Smckusic if (ap == NIL) 11182073Smckusic return; 11192073Smckusic put(1, op); 1120768Speter return; 1121768Speter case 0: 1122*7928Smckusick error("%s is an unimplemented extension", p->symbol); 1123768Speter return; 1124768Speter 1125768Speter default: 1126768Speter panic("proc case"); 1127768Speter } 1128768Speter } 1129768Speter #endif OBJ 1130