1768Speter /* Copyright (c) 1979 Regents of the University of California */ 2768Speter 3*2073Smckusic static char sccsid[] = "@(#)proc.c 1.4 01/06/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; 54768Speter 55768Speter #define CONPREC 4 56768Speter #define VARPREC 8 57768Speter #define CONWIDTH 1 58768Speter #define VARWIDTH 2 59768Speter #define SKIP 16 60768Speter 61768Speter /* 62768Speter * Verify that the name is 63768Speter * defined and is that of a 64768Speter * procedure. 65768Speter */ 66768Speter p = lookup(r[2]); 67768Speter if (p == NIL) { 68768Speter rvlist(r[3]); 69768Speter return; 70768Speter } 711198Speter if (p->class != PROC && p->class != FPROC) { 72768Speter error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]); 73768Speter rvlist(r[3]); 74768Speter return; 75768Speter } 76768Speter argv = r[3]; 77768Speter 78768Speter /* 79768Speter * Call handles user defined 80768Speter * procedures and functions. 81768Speter */ 82768Speter if (bn != 0) { 83768Speter call(p, argv, PROC, bn); 84768Speter return; 85768Speter } 86768Speter 87768Speter /* 88768Speter * Call to built-in procedure. 89768Speter * Count the arguments. 90768Speter */ 91768Speter argc = 0; 92768Speter for (al = argv; al != NIL; al = al[2]) 93768Speter argc++; 94768Speter 95768Speter /* 96768Speter * Switch on the operator 97768Speter * associated with the built-in 98768Speter * procedure in the namelist 99768Speter */ 100768Speter op = p->value[0] &~ NSTAND; 101768Speter if (opt('s') && (p->value[0] & NSTAND)) { 102768Speter standard(); 103768Speter error("%s is a nonstandard procedure", p->symbol); 104768Speter } 105768Speter switch (op) { 106768Speter 107768Speter case O_ABORT: 108768Speter if (argc != 0) 109768Speter error("null takes no arguments"); 110768Speter return; 111768Speter 112768Speter case O_FLUSH: 113768Speter if (argc == 0) { 114768Speter put(1, O_MESSAGE); 115768Speter return; 116768Speter } 117768Speter if (argc != 1) { 118768Speter error("flush takes at most one argument"); 119768Speter return; 120768Speter } 121*2073Smckusic ap = stklval(argv[1], NIL , LREQ ); 122768Speter if (ap == NIL) 123768Speter return; 124768Speter if (ap->class != FILET) { 125768Speter error("flush's argument must be a file, not %s", nameof(ap)); 126768Speter return; 127768Speter } 128768Speter put(1, op); 129768Speter return; 130768Speter 131768Speter case O_MESSAGE: 132768Speter case O_WRITEF: 133768Speter case O_WRITLN: 134768Speter /* 135768Speter * Set up default file "output"'s type 136768Speter */ 137768Speter file = NIL; 138768Speter filetype = nl+T1CHAR; 139768Speter /* 140768Speter * Determine the file implied 141768Speter * for the write and generate 142768Speter * code to make it the active file. 143768Speter */ 144768Speter if (op == O_MESSAGE) { 145768Speter /* 146768Speter * For message, all that matters 147768Speter * is that the filetype is 148768Speter * a character file. 149768Speter * Thus "output" will suit us fine. 150768Speter */ 151768Speter put(1, O_MESSAGE); 152768Speter } else if (argv != NIL && (al = argv[1])[0] != T_WEXP) { 153768Speter /* 154768Speter * If there is a first argument which has 155768Speter * no write widths, then it is potentially 156768Speter * a file name. 157768Speter */ 158768Speter codeoff(); 159768Speter ap = stkrval(argv[1], NIL , RREQ ); 160768Speter codeon(); 161768Speter if (ap == NIL) 162768Speter argv = argv[2]; 163768Speter if (ap != NIL && ap->class == FILET) { 164768Speter /* 165768Speter * Got "write(f, ...", make 166768Speter * f the active file, and save 167768Speter * it and its type for use in 168768Speter * processing the rest of the 169768Speter * arguments to write. 170768Speter */ 171768Speter file = argv[1]; 172768Speter filetype = ap->type; 173*2073Smckusic stklval(argv[1], NIL , LREQ ); 174768Speter put(1, O_UNIT); 175768Speter /* 176768Speter * Skip over the first argument 177768Speter */ 178768Speter argv = argv[2]; 179768Speter argc--; 180768Speter } else 181768Speter /* 182768Speter * Set up for writing on 183768Speter * standard output. 184768Speter */ 185768Speter put(1, O_UNITOUT); 186768Speter } else 187768Speter put(1, O_UNITOUT); 188768Speter /* 189768Speter * Loop and process each 190768Speter * of the arguments. 191768Speter */ 192768Speter for (; argv != NIL; argv = argv[2]) { 193768Speter /* 194768Speter * fmtspec indicates the type (CONstant or VARiable) 195768Speter * and number (none, WIDTH, and/or PRECision) 196768Speter * of the fields in the printf format for this 197768Speter * output variable. 198768Speter * stkcnt is the number of longs pushed on the stack 199768Speter * fmt is the format output indicator (D, E, F, O, X, S) 200768Speter * fmtstart = 0 for leading blank; = 1 for no blank 201768Speter */ 202768Speter fmtspec = NIL; 203768Speter stkcnt = 0; 204768Speter fmt = 'D'; 205768Speter fmtstart = 1; 206768Speter al = argv[1]; 207768Speter if (al == NIL) 208768Speter continue; 209768Speter if (al[0] == T_WEXP) 210768Speter alv = al[1]; 211768Speter else 212768Speter alv = al; 213768Speter if (alv == NIL) 214768Speter continue; 215768Speter codeoff(); 216768Speter ap = stkrval(alv, NIL , RREQ ); 217768Speter codeon(); 218768Speter if (ap == NIL) 219768Speter continue; 220768Speter typ = classify(ap); 221768Speter if (al[0] == T_WEXP) { 222768Speter /* 223768Speter * Handle width expressions. 224768Speter * The basic game here is that width 225768Speter * expressions get evaluated. If they 226768Speter * are constant, the value is placed 227768Speter * directly in the format string. 228768Speter * Otherwise the value is pushed onto 229768Speter * the stack and an indirection is 230768Speter * put into the format string. 231768Speter */ 232768Speter if (al[3] == OCT) 233768Speter fmt = 'O'; 234768Speter else if (al[3] == HEX) 235768Speter fmt = 'X'; 236768Speter else if (al[3] != NIL) { 237768Speter /* 238768Speter * Evaluate second format spec 239768Speter */ 240768Speter if ( constval(al[3]) 241768Speter && isa( con.ctype , "i" ) ) { 242768Speter fmtspec += CONPREC; 243768Speter prec = con.crval; 244768Speter } else { 245768Speter fmtspec += VARPREC; 246768Speter } 247768Speter fmt = 'f'; 248768Speter switch ( typ ) { 249768Speter case TINT: 250768Speter if ( opt( 's' ) ) { 251768Speter standard(); 252768Speter error("Writing %ss with two write widths is non-standard", clnames[typ]); 253768Speter } 254768Speter /* and fall through */ 255768Speter case TDOUBLE: 256768Speter break; 257768Speter default: 258768Speter error("Cannot write %ss with two write widths", clnames[typ]); 259768Speter continue; 260768Speter } 261768Speter } 262768Speter /* 263768Speter * Evaluate first format spec 264768Speter */ 265768Speter if (al[2] != NIL) { 266768Speter if ( constval(al[2]) 267768Speter && isa( con.ctype , "i" ) ) { 268768Speter fmtspec += CONWIDTH; 269768Speter field = con.crval; 270768Speter } else { 271768Speter fmtspec += VARWIDTH; 272768Speter } 273768Speter } 274768Speter if ((fmtspec & CONPREC) && prec < 0 || 275768Speter (fmtspec & CONWIDTH) && field < 0) { 276768Speter error("Negative widths are not allowed"); 277768Speter continue; 278768Speter } 279768Speter } 280768Speter if (filetype != nl+T1CHAR) { 281768Speter if (fmt == 'O' || fmt == 'X') { 282768Speter error("Oct/hex allowed only on text files"); 283768Speter continue; 284768Speter } 285768Speter if (fmtspec) { 286768Speter error("Write widths allowed only on text files"); 287768Speter continue; 288768Speter } 289768Speter /* 290768Speter * Generalized write, i.e. 291768Speter * to a non-textfile. 292768Speter */ 293*2073Smckusic stklval(file, NIL , LREQ ); 294768Speter put(1, O_FNIL); 295768Speter /* 296768Speter * file^ := ... 297768Speter */ 298768Speter ap = rvalue(argv[1], NIL); 299768Speter if (ap == NIL) 300768Speter continue; 301768Speter if (incompat(ap, filetype, argv[1])) { 302768Speter cerror("Type mismatch in write to non-text file"); 303768Speter continue; 304768Speter } 305768Speter convert(ap, filetype); 306768Speter put(2, O_AS, width(filetype)); 307768Speter /* 308768Speter * put(file) 309768Speter */ 310768Speter put(1, O_PUT); 311768Speter continue; 312768Speter } 313768Speter /* 314768Speter * Write to a textfile 315768Speter * 316768Speter * Evaluate the expression 317768Speter * to be written. 318768Speter */ 319768Speter if (fmt == 'O' || fmt == 'X') { 320768Speter if (opt('s')) { 321768Speter standard(); 322768Speter error("Oct and hex are non-standard"); 323768Speter } 324768Speter if (typ == TSTR || typ == TDOUBLE) { 325768Speter error("Can't write %ss with oct/hex", clnames[typ]); 326768Speter continue; 327768Speter } 328768Speter if (typ == TCHAR || typ == TBOOL) 329768Speter typ = TINT; 330768Speter } 331768Speter /* 332768Speter * Place the arguement on the stack. If there is 333768Speter * no format specified by the programmer, implement 334768Speter * the default. 335768Speter */ 336768Speter switch (typ) { 337768Speter case TINT: 338768Speter if (fmt != 'f') { 339768Speter ap = stkrval(alv, NIL , RREQ ); 340768Speter stkcnt++; 341768Speter } else { 342768Speter ap = stkrval(alv, NIL , RREQ ); 343768Speter put(1, O_ITOD); 344768Speter stkcnt += 2; 345768Speter typ = TDOUBLE; 346768Speter goto tdouble; 347768Speter } 348768Speter if (fmtspec == NIL) { 349768Speter if (fmt == 'D') 350768Speter field = 10; 351768Speter else if (fmt == 'X') 352768Speter field = 8; 353768Speter else if (fmt == 'O') 354768Speter field = 11; 355768Speter else 356768Speter panic("fmt1"); 357768Speter fmtspec = CONWIDTH; 358768Speter } 359768Speter break; 360768Speter case TCHAR: 361768Speter tchar: 362*2073Smckusic if (fmtspec == NIL) { 363*2073Smckusic put(1, O_FILE); 364*2073Smckusic ap = stkrval(alv, NIL , RREQ ); 365*2073Smckusic put(1, O_WRITEC); 366*2073Smckusic fmtspec = SKIP; 367*2073Smckusic break; 368*2073Smckusic } 369768Speter ap = stkrval(alv, NIL , RREQ ); 370768Speter stkcnt++; 371768Speter fmt = 'c'; 372768Speter break; 373768Speter case TSCAL: 3741628Speter warning(); 375768Speter if (opt('s')) { 376768Speter standard(); 377768Speter } 3781628Speter error("Writing scalars to text files is non-standard"); 379768Speter case TBOOL: 380768Speter stkrval(alv, NIL , RREQ ); 381768Speter put(2, O_NAM, listnames(ap)); 382768Speter stkcnt++; 383768Speter fmt = 's'; 384768Speter break; 385768Speter case TDOUBLE: 386768Speter ap = stkrval(alv, TDOUBLE , RREQ ); 387768Speter stkcnt += 2; 388768Speter tdouble: 389768Speter switch (fmtspec) { 390768Speter case NIL: 391768Speter field = 21; 392768Speter prec = 14; 393768Speter fmt = 'E'; 394768Speter fmtspec = CONWIDTH + CONPREC; 395768Speter break; 396768Speter case CONWIDTH: 397768Speter if (--field < 1) 398768Speter field = 1; 399768Speter prec = field - 7; 400768Speter if (prec < 1) 401768Speter prec = 1; 402768Speter fmtspec += CONPREC; 403768Speter fmt = 'E'; 404768Speter break; 405768Speter case CONWIDTH + CONPREC: 406768Speter case CONWIDTH + VARPREC: 407768Speter if (--field < 1) 408768Speter field = 1; 409768Speter } 410768Speter format[0] = ' '; 411768Speter fmtstart = 0; 412768Speter break; 413768Speter case TSTR: 414768Speter constval( alv ); 415768Speter switch ( classify( con.ctype ) ) { 416768Speter case TCHAR: 417768Speter typ = TCHAR; 418768Speter goto tchar; 419768Speter case TSTR: 420768Speter strptr = con.cpval; 421768Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 422768Speter strptr = con.cpval; 423768Speter break; 424768Speter default: 425768Speter strnglen = width(ap); 426768Speter break; 427768Speter } 428768Speter fmt = 's'; 429768Speter strfmt = fmtspec; 430768Speter if (fmtspec == NIL) { 431768Speter fmtspec = SKIP; 432768Speter break; 433768Speter } 434768Speter if (fmtspec & CONWIDTH) { 435768Speter if (field <= strnglen) { 436768Speter fmtspec = SKIP; 437768Speter break; 438768Speter } else 439768Speter field -= strnglen; 440768Speter } 441768Speter /* 442768Speter * push string to implement leading blank padding 443768Speter */ 444768Speter put(2, O_LVCON, 2); 445768Speter putstr("", 0); 446768Speter stkcnt++; 447768Speter break; 448768Speter default: 449768Speter error("Can't write %ss to a text file", clnames[typ]); 450768Speter continue; 451768Speter } 452768Speter /* 453768Speter * If there is a variable precision, evaluate it onto 454768Speter * the stack 455768Speter */ 456768Speter if (fmtspec & VARPREC) { 457768Speter ap = stkrval(al[3], NIL , RREQ ); 458768Speter if (ap == NIL) 459768Speter continue; 460768Speter if (isnta(ap,"i")) { 461768Speter error("Second write width must be integer, not %s", nameof(ap)); 462768Speter continue; 463768Speter } 464768Speter if ( opt( 't' ) ) { 465768Speter put(3, O_MAX, 0, 0); 466768Speter } 467768Speter stkcnt++; 468768Speter } 469768Speter /* 470768Speter * If there is a variable width, evaluate it onto 471768Speter * the stack 472768Speter */ 473768Speter if (fmtspec & VARWIDTH) { 474768Speter if ( ( typ == TDOUBLE && fmtspec == VARWIDTH ) 475768Speter || typ == TSTR ) { 476768Speter i = sizes[cbn].om_off -= sizeof(int); 477768Speter if (i < sizes[cbn].om_max) 478768Speter sizes[cbn].om_max = i; 479768Speter put(2, O_LV | cbn << 8 + INDX, i); 480768Speter } 481768Speter ap = stkrval(al[2], NIL , RREQ ); 482768Speter if (ap == NIL) 483768Speter continue; 484768Speter if (isnta(ap,"i")) { 485768Speter error("First write width must be integer, not %s", nameof(ap)); 486768Speter continue; 487768Speter } 488768Speter stkcnt++; 489768Speter /* 490768Speter * Perform special processing on widths based 491768Speter * on data type 492768Speter */ 493768Speter switch (typ) { 494768Speter case TDOUBLE: 495768Speter if (fmtspec == VARWIDTH) { 496768Speter fmt = 'E'; 497768Speter put(1, O_AS4); 498768Speter put(2, O_RV4 | cbn << 8 + INDX, i); 499768Speter put(3, O_MAX, 8, 1); 500768Speter put(2, O_RV4 | cbn << 8 + INDX, i); 501768Speter stkcnt++; 502768Speter fmtspec += VARPREC; 503768Speter } 504768Speter put(3, O_MAX, 1, 1); 505768Speter break; 506768Speter case TSTR: 507768Speter put(1, O_AS4); 508768Speter put(2, O_RV4 | cbn << 8 + INDX, i); 509768Speter put(3, O_MAX, strnglen, 0); 510768Speter break; 511768Speter default: 512768Speter if ( opt( 't' ) ) { 513768Speter put(3, O_MAX, 0, 0); 514768Speter } 515768Speter break; 516768Speter } 517768Speter } 518768Speter /* 519768Speter * Generate the format string 520768Speter */ 521768Speter switch (fmtspec) { 522768Speter default: 523768Speter panic("fmt2"); 524768Speter case SKIP: 525768Speter break; 526*2073Smckusic case NIL: 527*2073Smckusic sprintf(&format[1], "%%%c", fmt); 528*2073Smckusic goto fmtgen; 529768Speter case CONWIDTH: 530768Speter sprintf(&format[1], "%%%1D%c", field, fmt); 531768Speter goto fmtgen; 532768Speter case VARWIDTH: 533768Speter sprintf(&format[1], "%%*%c", fmt); 534768Speter goto fmtgen; 535768Speter case CONWIDTH + CONPREC: 536768Speter sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt); 537768Speter goto fmtgen; 538768Speter case CONWIDTH + VARPREC: 539768Speter sprintf(&format[1], "%%%1D.*%c", field, fmt); 540768Speter goto fmtgen; 541768Speter case VARWIDTH + CONPREC: 542768Speter sprintf(&format[1], "%%*.%1D%c", prec, fmt); 543768Speter goto fmtgen; 544768Speter case VARWIDTH + VARPREC: 545768Speter sprintf(&format[1], "%%*.*%c", fmt); 546768Speter fmtgen: 547768Speter fmtlen = lenstr(&format[fmtstart], 0); 548768Speter put(2, O_LVCON, fmtlen); 549768Speter putstr(&format[fmtstart], 0); 550768Speter put(1, O_FILE); 551768Speter stkcnt += 2; 552768Speter put(2, O_WRITEF, stkcnt); 553768Speter } 554768Speter /* 555768Speter * Write the string after its blank padding 556768Speter */ 557768Speter if (typ == TSTR) { 558768Speter put(1, O_FILE); 559768Speter put(2, O_CON24, 1); 560768Speter if (strfmt & VARWIDTH) { 561768Speter put(2, O_RV4 | cbn << 8 + INDX , i ); 562768Speter put(2, O_MIN, strnglen); 563768Speter } else { 564768Speter if ((fmtspec & SKIP) && 565768Speter (strfmt & CONWIDTH)) { 566768Speter strnglen = field; 567768Speter } 568768Speter put(2, O_CON24, strnglen); 569768Speter } 570768Speter ap = stkrval(alv, NIL , RREQ ); 571768Speter put(1, O_WRITES); 572768Speter } 573768Speter } 574768Speter /* 575768Speter * Done with arguments. 576768Speter * Handle writeln and 577768Speter * insufficent number of args. 578768Speter */ 579768Speter switch (p->value[0] &~ NSTAND) { 580768Speter case O_WRITEF: 581768Speter if (argc == 0) 582768Speter error("Write requires an argument"); 583768Speter break; 584768Speter case O_MESSAGE: 585768Speter if (argc == 0) 586768Speter error("Message requires an argument"); 587768Speter case O_WRITLN: 588768Speter if (filetype != nl+T1CHAR) 589768Speter error("Can't 'writeln' a non text file"); 590768Speter put(1, O_WRITLN); 591768Speter break; 592768Speter } 593768Speter return; 594768Speter 595768Speter case O_READ4: 596768Speter case O_READLN: 597768Speter /* 598768Speter * Set up default 599768Speter * file "input". 600768Speter */ 601768Speter file = NIL; 602768Speter filetype = nl+T1CHAR; 603768Speter /* 604768Speter * Determine the file implied 605768Speter * for the read and generate 606768Speter * code to make it the active file. 607768Speter */ 608768Speter if (argv != NIL) { 609768Speter codeoff(); 610768Speter ap = stkrval(argv[1], NIL , RREQ ); 611768Speter codeon(); 612768Speter if (ap == NIL) 613768Speter argv = argv[2]; 614768Speter if (ap != NIL && ap->class == FILET) { 615768Speter /* 616768Speter * Got "read(f, ...", make 617768Speter * f the active file, and save 618768Speter * it and its type for use in 619768Speter * processing the rest of the 620768Speter * arguments to read. 621768Speter */ 622768Speter file = argv[1]; 623768Speter filetype = ap->type; 624*2073Smckusic stklval(argv[1], NIL , LREQ ); 625768Speter put(1, O_UNIT); 626768Speter argv = argv[2]; 627768Speter argc--; 628768Speter } else { 629768Speter /* 630768Speter * Default is read from 631768Speter * standard input. 632768Speter */ 633768Speter put(1, O_UNITINP); 634768Speter input->nl_flags |= NUSED; 635768Speter } 636768Speter } else { 637768Speter put(1, O_UNITINP); 638768Speter input->nl_flags |= NUSED; 639768Speter } 640768Speter /* 641768Speter * Loop and process each 642768Speter * of the arguments. 643768Speter */ 644768Speter for (; argv != NIL; argv = argv[2]) { 645768Speter /* 646768Speter * Get the address of the target 647768Speter * on the stack. 648768Speter */ 649768Speter al = argv[1]; 650768Speter if (al == NIL) 651768Speter continue; 652768Speter if (al[0] != T_VAR) { 653768Speter error("Arguments to %s must be variables, not expressions", p->symbol); 654768Speter continue; 655768Speter } 656768Speter ap = stklval(al, MOD|ASGN|NOUSE); 657768Speter if (ap == NIL) 658768Speter continue; 659768Speter if (filetype != nl+T1CHAR) { 660768Speter /* 661768Speter * Generalized read, i.e. 662768Speter * from a non-textfile. 663768Speter */ 664768Speter if (incompat(filetype, ap, argv[1] )) { 665768Speter error("Type mismatch in read from non-text file"); 666768Speter continue; 667768Speter } 668768Speter /* 669768Speter * var := file ^; 670768Speter */ 671768Speter if (file != NIL) 672*2073Smckusic stklval(file, NIL , LREQ ); 673768Speter else /* Magic */ 674*2073Smckusic put(2, PTR_RV, input->value[0]); 675768Speter put(1, O_FNIL); 676768Speter put(2, O_IND, width(filetype)); 677768Speter convert(filetype, ap); 678768Speter if (isa(ap, "bsci")) 679768Speter rangechk(ap, ap); 680768Speter put(2, O_AS, width(ap)); 681768Speter /* 682768Speter * get(file); 683768Speter */ 684768Speter put(1, O_GET); 685768Speter continue; 686768Speter } 687768Speter typ = classify(ap); 688768Speter op = rdops(typ); 689768Speter if (op == NIL) { 690768Speter error("Can't read %ss from a text file", clnames[typ]); 691768Speter continue; 692768Speter } 693768Speter if (op != O_READE) 694768Speter put(1, op); 695768Speter else { 696768Speter put(2, op, listnames(ap)); 6971628Speter warning(); 698768Speter if (opt('s')) { 699768Speter standard(); 700768Speter } 7011628Speter error("Reading scalars from text files is non-standard"); 702768Speter } 703768Speter /* 704768Speter * Data read is on the stack. 705768Speter * Assign it. 706768Speter */ 707768Speter if (op != O_READ8 && op != O_READE) 708768Speter rangechk(ap, op == O_READC ? ap : nl+T4INT); 709768Speter gen(O_AS2, O_AS2, width(ap), 710768Speter op == O_READ8 ? 8 : op == O_READ4 ? 4 : 2); 711768Speter } 712768Speter /* 713768Speter * Done with arguments. 714768Speter * Handle readln and 715768Speter * insufficient number of args. 716768Speter */ 717768Speter if (p->value[0] == O_READLN) { 718768Speter if (filetype != nl+T1CHAR) 719768Speter error("Can't 'readln' a non text file"); 720768Speter put(1, O_READLN); 721768Speter } 722768Speter else if (argc == 0) 723768Speter error("read requires an argument"); 724768Speter return; 725768Speter 726768Speter case O_GET: 727768Speter case O_PUT: 728768Speter if (argc != 1) { 729768Speter error("%s expects one argument", p->symbol); 730768Speter return; 731768Speter } 732*2073Smckusic ap = stklval(argv[1], NIL , LREQ ); 733768Speter if (ap == NIL) 734768Speter return; 735768Speter if (ap->class != FILET) { 736768Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 737768Speter return; 738768Speter } 739768Speter put(1, O_UNIT); 740768Speter put(1, op); 741768Speter return; 742768Speter 743768Speter case O_RESET: 744768Speter case O_REWRITE: 745768Speter if (argc == 0 || argc > 2) { 746768Speter error("%s expects one or two arguments", p->symbol); 747768Speter return; 748768Speter } 749768Speter if (opt('s') && argc == 2) { 750768Speter standard(); 751768Speter error("Two argument forms of reset and rewrite are non-standard"); 752768Speter } 753*2073Smckusic codeoff(); 754768Speter ap = stklval(argv[1], MOD|NOUSE); 755*2073Smckusic codeon(); 756768Speter if (ap == NIL) 757768Speter return; 758768Speter if (ap->class != FILET) { 759768Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 760768Speter return; 761768Speter } 762*2073Smckusic put(2, O_CON24, text(ap) ? 0: width(ap->type)); 763768Speter if (argc == 2) { 764768Speter /* 765768Speter * Optional second argument 766768Speter * is a string name of a 767768Speter * UNIX (R) file to be associated. 768768Speter */ 769768Speter al = argv[2]; 770*2073Smckusic codeoff(); 771768Speter al = stkrval(al[1], NOFLAGS , RREQ ); 772*2073Smckusic codeon(); 773768Speter if (al == NIL) 774768Speter return; 775768Speter if (classify(al) != TSTR) { 776768Speter error("Second argument to %s must be a string, not %s", p->symbol, nameof(al)); 777768Speter return; 778768Speter } 779*2073Smckusic put(2, O_CON24, width(al)); 780*2073Smckusic al = argv[2]; 781*2073Smckusic al = stkrval(al[1], NOFLAGS , RREQ ); 782768Speter } else { 783*2073Smckusic put(2, O_CON24, 0); 784768Speter put(2, O_CON24, NIL); 785768Speter } 786*2073Smckusic ap = stklval(argv[1], MOD|NOUSE); 787768Speter put(1, op); 788768Speter return; 789768Speter 790768Speter case O_NEW: 791768Speter case O_DISPOSE: 792768Speter if (argc == 0) { 793768Speter error("%s expects at least one argument", p->symbol); 794768Speter return; 795768Speter } 796768Speter ap = stklval(argv[1], op == O_NEW ? ( MOD | NOUSE ) : MOD ); 797768Speter if (ap == NIL) 798768Speter return; 799768Speter if (ap->class != PTR) { 800768Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 801768Speter return; 802768Speter } 803768Speter ap = ap->type; 804768Speter if (ap == NIL) 805768Speter return; 806768Speter argv = argv[2]; 807768Speter if (argv != NIL) { 808768Speter if (ap->class != RECORD) { 809768Speter error("Record required when specifying variant tags"); 810768Speter return; 811768Speter } 812768Speter for (; argv != NIL; argv = argv[2]) { 813768Speter if (ap->ptr[NL_VARNT] == NIL) { 814768Speter error("Too many tag fields"); 815768Speter return; 816768Speter } 817768Speter if (!isconst(argv[1])) { 818768Speter error("Second and successive arguments to %s must be constants", p->symbol); 819768Speter return; 820768Speter } 821768Speter gconst(argv[1]); 822768Speter if (con.ctype == NIL) 823768Speter return; 824768Speter if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) { 825768Speter cerror("Specified tag constant type clashed with variant case selector type"); 826768Speter return; 827768Speter } 828768Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 829768Speter if (ap->range[0] == con.crval) 830768Speter break; 831768Speter if (ap == NIL) { 832768Speter error("No variant case label value equals specified constant value"); 833768Speter return; 834768Speter } 835768Speter ap = ap->ptr[NL_VTOREC]; 836768Speter } 837768Speter } 838768Speter put(2, op, width(ap)); 839768Speter return; 840768Speter 841768Speter case O_DATE: 842768Speter case O_TIME: 843768Speter if (argc != 1) { 844768Speter error("%s expects one argument", p->symbol); 845768Speter return; 846768Speter } 847768Speter ap = stklval(argv[1], MOD|NOUSE); 848768Speter if (ap == NIL) 849768Speter return; 850768Speter if (classify(ap) != TSTR || width(ap) != 10) { 851768Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 852768Speter return; 853768Speter } 854768Speter put(1, op); 855768Speter return; 856768Speter 857768Speter case O_HALT: 858768Speter if (argc != 0) { 859768Speter error("halt takes no arguments"); 860768Speter return; 861768Speter } 862768Speter put(1, op); 863768Speter noreach = 1; 864768Speter return; 865768Speter 866768Speter case O_ARGV: 867768Speter if (argc != 2) { 868768Speter error("argv takes two arguments"); 869768Speter return; 870768Speter } 871768Speter ap = stkrval(argv[1], NIL , RREQ ); 872768Speter if (ap == NIL) 873768Speter return; 874768Speter if (isnta(ap, "i")) { 875768Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 876768Speter return; 877768Speter } 878768Speter al = argv[2]; 879768Speter ap = stklval(al[1], MOD|NOUSE); 880768Speter if (ap == NIL) 881768Speter return; 882768Speter if (classify(ap) != TSTR) { 883768Speter error("argv's second argument must be a string, not %s", nameof(ap)); 884768Speter return; 885768Speter } 886768Speter put(2, op, width(ap)); 887768Speter return; 888768Speter 889768Speter case O_STLIM: 890768Speter if (argc != 1) { 891768Speter error("stlimit requires one argument"); 892768Speter return; 893768Speter } 894768Speter ap = stkrval(argv[1], NIL , RREQ ); 895768Speter if (ap == NIL) 896768Speter return; 897768Speter if (isnta(ap, "i")) { 898768Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 899768Speter return; 900768Speter } 901768Speter if (width(ap) != 4) 902768Speter put(1, O_STOI); 903768Speter put(1, op); 904768Speter return; 905768Speter 906768Speter case O_REMOVE: 907768Speter if (argc != 1) { 908768Speter error("remove expects one argument"); 909768Speter return; 910768Speter } 911*2073Smckusic codeoff(); 912768Speter ap = stkrval(argv[1], NOFLAGS , RREQ ); 913*2073Smckusic codeon(); 914768Speter if (ap == NIL) 915768Speter return; 916768Speter if (classify(ap) != TSTR) { 917768Speter error("remove's argument must be a string, not %s", nameof(ap)); 918768Speter return; 919768Speter } 920768Speter put(2, O_CON24, width(ap)); 921*2073Smckusic ap = stkrval(argv[1], NOFLAGS , RREQ ); 922768Speter put(1, op); 923768Speter return; 924768Speter 925768Speter case O_LLIMIT: 926768Speter if (argc != 2) { 927768Speter error("linelimit expects two arguments"); 928768Speter return; 929768Speter } 930768Speter al = argv[2]; 931768Speter ap = stkrval(al[1], NIL , RREQ ); 932768Speter if (ap == NIL) 933768Speter return; 934768Speter if (isnta(ap, "i")) { 935768Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 936768Speter return; 937768Speter } 938*2073Smckusic ap = stklval(argv[1], NOFLAGS|NOUSE); 939*2073Smckusic if (ap == NIL) 940*2073Smckusic return; 941*2073Smckusic if (!text(ap)) { 942*2073Smckusic error("linelimit's first argument must be a text file, not %s", nameof(ap)); 943*2073Smckusic return; 944*2073Smckusic } 945768Speter put(1, op); 946768Speter return; 947768Speter case O_PAGE: 948768Speter if (argc != 1) { 949768Speter error("page expects one argument"); 950768Speter return; 951768Speter } 952*2073Smckusic ap = stklval(argv[1], NIL , LREQ ); 953768Speter if (ap == NIL) 954768Speter return; 955768Speter if (!text(ap)) { 956768Speter error("Argument to page must be a text file, not %s", nameof(ap)); 957768Speter return; 958768Speter } 959768Speter put(1, O_UNIT); 960768Speter put(1, op); 961768Speter return; 962768Speter 963768Speter case O_PACK: 964768Speter if (argc != 3) { 965768Speter error("pack expects three arguments"); 966768Speter return; 967768Speter } 968768Speter pu = "pack(a,i,z)"; 969768Speter pua = (al = argv)[1]; 970768Speter pui = (al = al[2])[1]; 971768Speter puz = (al = al[2])[1]; 972768Speter goto packunp; 973768Speter case O_UNPACK: 974768Speter if (argc != 3) { 975768Speter error("unpack expects three arguments"); 976768Speter return; 977768Speter } 978768Speter pu = "unpack(z,a,i)"; 979768Speter puz = (al = argv)[1]; 980768Speter pua = (al = al[2])[1]; 981768Speter pui = (al = al[2])[1]; 982768Speter packunp: 983*2073Smckusic codeoff(); 984768Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 985*2073Smckusic al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 986*2073Smckusic codeon(); 987768Speter if (ap == NIL) 988768Speter return; 989768Speter if (ap->class != ARRAY) { 990768Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 991768Speter return; 992768Speter } 993768Speter if (al->class != ARRAY) { 994768Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 995768Speter return; 996768Speter } 997768Speter if (al->type == NIL || ap->type == NIL) 998768Speter return; 999768Speter if (al->type != ap->type) { 1000768Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 1001768Speter return; 1002768Speter } 1003768Speter k = width(al); 1004768Speter itemwidth = width(ap->type); 1005768Speter ap = ap->chain; 1006768Speter al = al->chain; 1007768Speter if (ap->chain != NIL || al->chain != NIL) { 1008768Speter error("%s requires a and z to be single dimension arrays", pu); 1009768Speter return; 1010768Speter } 1011768Speter if (ap == NIL || al == NIL) 1012768Speter return; 1013768Speter /* 1014768Speter * al is the range for z i.e. u..v 1015768Speter * ap is the range for a i.e. m..n 1016768Speter * i will be n-m+1 1017768Speter * j will be v-u+1 1018768Speter */ 1019768Speter i = ap->range[1] - ap->range[0] + 1; 1020768Speter j = al->range[1] - al->range[0] + 1; 1021768Speter if (i < j) { 1022768Speter error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i); 1023768Speter return; 1024768Speter } 1025768Speter /* 1026768Speter * get n-m-(v-u) and m for the interpreter 1027768Speter */ 1028768Speter i -= j; 1029768Speter j = ap->range[0]; 1030*2073Smckusic put(2, O_CON24, k); 1031*2073Smckusic put(2, O_CON24, i); 1032*2073Smckusic put(2, O_CON24, j); 1033*2073Smckusic put(2, O_CON24, itemwidth); 1034*2073Smckusic al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 1035*2073Smckusic ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 1036*2073Smckusic ap = stkrval((int *) pui, NLNIL , RREQ ); 1037*2073Smckusic if (ap == NIL) 1038*2073Smckusic return; 1039*2073Smckusic put(1, op); 1040768Speter return; 1041768Speter case 0: 1042768Speter error("%s is an unimplemented 6400 extension", p->symbol); 1043768Speter return; 1044768Speter 1045768Speter default: 1046768Speter panic("proc case"); 1047768Speter } 1048768Speter } 1049768Speter #endif OBJ 1050