1768Speter /* Copyright (c) 1979 Regents of the University of California */ 2768Speter 3*1628Speter static char sccsid[] = "@(#)proc.c 1.3 10/28/80"; 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 } 121768Speter ap = stkrval(argv[1], NIL , RREQ ); 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; 173768Speter stkrval(argv[1], NIL , RREQ ); 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 */ 293768Speter stkrval(file, NIL , RREQ ); 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: 362768Speter ap = stkrval(alv, NIL , RREQ ); 363768Speter stkcnt++; 364768Speter fmt = 'c'; 365768Speter break; 366768Speter case TSCAL: 367*1628Speter warning(); 368768Speter if (opt('s')) { 369768Speter standard(); 370768Speter } 371*1628Speter error("Writing scalars to text files is non-standard"); 372768Speter case TBOOL: 373768Speter stkrval(alv, NIL , RREQ ); 374768Speter put(2, O_NAM, listnames(ap)); 375768Speter stkcnt++; 376768Speter fmt = 's'; 377768Speter break; 378768Speter case TDOUBLE: 379768Speter ap = stkrval(alv, TDOUBLE , RREQ ); 380768Speter stkcnt += 2; 381768Speter tdouble: 382768Speter switch (fmtspec) { 383768Speter case NIL: 384768Speter field = 21; 385768Speter prec = 14; 386768Speter fmt = 'E'; 387768Speter fmtspec = CONWIDTH + CONPREC; 388768Speter break; 389768Speter case CONWIDTH: 390768Speter if (--field < 1) 391768Speter field = 1; 392768Speter prec = field - 7; 393768Speter if (prec < 1) 394768Speter prec = 1; 395768Speter fmtspec += CONPREC; 396768Speter fmt = 'E'; 397768Speter break; 398768Speter case CONWIDTH + CONPREC: 399768Speter case CONWIDTH + VARPREC: 400768Speter if (--field < 1) 401768Speter field = 1; 402768Speter } 403768Speter format[0] = ' '; 404768Speter fmtstart = 0; 405768Speter break; 406768Speter case TSTR: 407768Speter constval( alv ); 408768Speter switch ( classify( con.ctype ) ) { 409768Speter case TCHAR: 410768Speter typ = TCHAR; 411768Speter goto tchar; 412768Speter case TSTR: 413768Speter strptr = con.cpval; 414768Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 415768Speter strptr = con.cpval; 416768Speter break; 417768Speter default: 418768Speter strnglen = width(ap); 419768Speter break; 420768Speter } 421768Speter fmt = 's'; 422768Speter strfmt = fmtspec; 423768Speter if (fmtspec == NIL) { 424768Speter fmtspec = SKIP; 425768Speter break; 426768Speter } 427768Speter if (fmtspec & CONWIDTH) { 428768Speter if (field <= strnglen) { 429768Speter fmtspec = SKIP; 430768Speter break; 431768Speter } else 432768Speter field -= strnglen; 433768Speter } 434768Speter /* 435768Speter * push string to implement leading blank padding 436768Speter */ 437768Speter put(2, O_LVCON, 2); 438768Speter putstr("", 0); 439768Speter stkcnt++; 440768Speter break; 441768Speter default: 442768Speter error("Can't write %ss to a text file", clnames[typ]); 443768Speter continue; 444768Speter } 445768Speter /* 446768Speter * If there is a variable precision, evaluate it onto 447768Speter * the stack 448768Speter */ 449768Speter if (fmtspec & VARPREC) { 450768Speter ap = stkrval(al[3], NIL , RREQ ); 451768Speter if (ap == NIL) 452768Speter continue; 453768Speter if (isnta(ap,"i")) { 454768Speter error("Second write width must be integer, not %s", nameof(ap)); 455768Speter continue; 456768Speter } 457768Speter if ( opt( 't' ) ) { 458768Speter put(3, O_MAX, 0, 0); 459768Speter } 460768Speter stkcnt++; 461768Speter } 462768Speter /* 463768Speter * If there is a variable width, evaluate it onto 464768Speter * the stack 465768Speter */ 466768Speter if (fmtspec & VARWIDTH) { 467768Speter if ( ( typ == TDOUBLE && fmtspec == VARWIDTH ) 468768Speter || typ == TSTR ) { 469768Speter i = sizes[cbn].om_off -= sizeof(int); 470768Speter if (i < sizes[cbn].om_max) 471768Speter sizes[cbn].om_max = i; 472768Speter put(2, O_LV | cbn << 8 + INDX, i); 473768Speter } 474768Speter ap = stkrval(al[2], NIL , RREQ ); 475768Speter if (ap == NIL) 476768Speter continue; 477768Speter if (isnta(ap,"i")) { 478768Speter error("First write width must be integer, not %s", nameof(ap)); 479768Speter continue; 480768Speter } 481768Speter stkcnt++; 482768Speter /* 483768Speter * Perform special processing on widths based 484768Speter * on data type 485768Speter */ 486768Speter switch (typ) { 487768Speter case TDOUBLE: 488768Speter if (fmtspec == VARWIDTH) { 489768Speter fmt = 'E'; 490768Speter put(1, O_AS4); 491768Speter put(2, O_RV4 | cbn << 8 + INDX, i); 492768Speter put(3, O_MAX, 8, 1); 493768Speter put(2, O_RV4 | cbn << 8 + INDX, i); 494768Speter stkcnt++; 495768Speter fmtspec += VARPREC; 496768Speter } 497768Speter put(3, O_MAX, 1, 1); 498768Speter break; 499768Speter case TSTR: 500768Speter put(1, O_AS4); 501768Speter put(2, O_RV4 | cbn << 8 + INDX, i); 502768Speter put(3, O_MAX, strnglen, 0); 503768Speter break; 504768Speter default: 505768Speter if ( opt( 't' ) ) { 506768Speter put(3, O_MAX, 0, 0); 507768Speter } 508768Speter break; 509768Speter } 510768Speter } 511768Speter /* 512768Speter * Generate the format string 513768Speter */ 514768Speter switch (fmtspec) { 515768Speter default: 516768Speter panic("fmt2"); 517768Speter case NIL: 518768Speter if (fmt == 'c') 519768Speter put(1, O_WRITEC); 520768Speter else { 521768Speter sprintf(&format[1], "%%%c", fmt); 522768Speter goto fmtgen; 523768Speter } 524768Speter case SKIP: 525768Speter break; 526768Speter case CONWIDTH: 527768Speter sprintf(&format[1], "%%%1D%c", field, fmt); 528768Speter goto fmtgen; 529768Speter case VARWIDTH: 530768Speter sprintf(&format[1], "%%*%c", fmt); 531768Speter goto fmtgen; 532768Speter case CONWIDTH + CONPREC: 533768Speter sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt); 534768Speter goto fmtgen; 535768Speter case CONWIDTH + VARPREC: 536768Speter sprintf(&format[1], "%%%1D.*%c", field, fmt); 537768Speter goto fmtgen; 538768Speter case VARWIDTH + CONPREC: 539768Speter sprintf(&format[1], "%%*.%1D%c", prec, fmt); 540768Speter goto fmtgen; 541768Speter case VARWIDTH + VARPREC: 542768Speter sprintf(&format[1], "%%*.*%c", fmt); 543768Speter fmtgen: 544768Speter fmtlen = lenstr(&format[fmtstart], 0); 545768Speter put(2, O_LVCON, fmtlen); 546768Speter putstr(&format[fmtstart], 0); 547768Speter put(1, O_FILE); 548768Speter stkcnt += 2; 549768Speter put(2, O_WRITEF, stkcnt); 550768Speter } 551768Speter /* 552768Speter * Write the string after its blank padding 553768Speter */ 554768Speter if (typ == TSTR) { 555768Speter put(1, O_FILE); 556768Speter put(2, O_CON24, 1); 557768Speter if (strfmt & VARWIDTH) { 558768Speter put(2, O_RV4 | cbn << 8 + INDX , i ); 559768Speter put(2, O_MIN, strnglen); 560768Speter } else { 561768Speter if ((fmtspec & SKIP) && 562768Speter (strfmt & CONWIDTH)) { 563768Speter strnglen = field; 564768Speter } 565768Speter put(2, O_CON24, strnglen); 566768Speter } 567768Speter ap = stkrval(alv, NIL , RREQ ); 568768Speter put(1, O_WRITES); 569768Speter } 570768Speter } 571768Speter /* 572768Speter * Done with arguments. 573768Speter * Handle writeln and 574768Speter * insufficent number of args. 575768Speter */ 576768Speter switch (p->value[0] &~ NSTAND) { 577768Speter case O_WRITEF: 578768Speter if (argc == 0) 579768Speter error("Write requires an argument"); 580768Speter break; 581768Speter case O_MESSAGE: 582768Speter if (argc == 0) 583768Speter error("Message requires an argument"); 584768Speter case O_WRITLN: 585768Speter if (filetype != nl+T1CHAR) 586768Speter error("Can't 'writeln' a non text file"); 587768Speter put(1, O_WRITLN); 588768Speter break; 589768Speter } 590768Speter return; 591768Speter 592768Speter case O_READ4: 593768Speter case O_READLN: 594768Speter /* 595768Speter * Set up default 596768Speter * file "input". 597768Speter */ 598768Speter file = NIL; 599768Speter filetype = nl+T1CHAR; 600768Speter /* 601768Speter * Determine the file implied 602768Speter * for the read and generate 603768Speter * code to make it the active file. 604768Speter */ 605768Speter if (argv != NIL) { 606768Speter codeoff(); 607768Speter ap = stkrval(argv[1], NIL , RREQ ); 608768Speter codeon(); 609768Speter if (ap == NIL) 610768Speter argv = argv[2]; 611768Speter if (ap != NIL && ap->class == FILET) { 612768Speter /* 613768Speter * Got "read(f, ...", make 614768Speter * f the active file, and save 615768Speter * it and its type for use in 616768Speter * processing the rest of the 617768Speter * arguments to read. 618768Speter */ 619768Speter file = argv[1]; 620768Speter filetype = ap->type; 621768Speter stkrval(argv[1], NIL , RREQ ); 622768Speter put(1, O_UNIT); 623768Speter argv = argv[2]; 624768Speter argc--; 625768Speter } else { 626768Speter /* 627768Speter * Default is read from 628768Speter * standard input. 629768Speter */ 630768Speter put(1, O_UNITINP); 631768Speter input->nl_flags |= NUSED; 632768Speter } 633768Speter } else { 634768Speter put(1, O_UNITINP); 635768Speter input->nl_flags |= NUSED; 636768Speter } 637768Speter /* 638768Speter * Loop and process each 639768Speter * of the arguments. 640768Speter */ 641768Speter for (; argv != NIL; argv = argv[2]) { 642768Speter /* 643768Speter * Get the address of the target 644768Speter * on the stack. 645768Speter */ 646768Speter al = argv[1]; 647768Speter if (al == NIL) 648768Speter continue; 649768Speter if (al[0] != T_VAR) { 650768Speter error("Arguments to %s must be variables, not expressions", p->symbol); 651768Speter continue; 652768Speter } 653768Speter ap = stklval(al, MOD|ASGN|NOUSE); 654768Speter if (ap == NIL) 655768Speter continue; 656768Speter if (filetype != nl+T1CHAR) { 657768Speter /* 658768Speter * Generalized read, i.e. 659768Speter * from a non-textfile. 660768Speter */ 661768Speter if (incompat(filetype, ap, argv[1] )) { 662768Speter error("Type mismatch in read from non-text file"); 663768Speter continue; 664768Speter } 665768Speter /* 666768Speter * var := file ^; 667768Speter */ 668768Speter if (file != NIL) 669768Speter stkrval(file, NIL , RREQ ); 670768Speter else /* Magic */ 671768Speter put(2, O_RV2, input->value[0]); 672768Speter put(1, O_FNIL); 673768Speter put(2, O_IND, width(filetype)); 674768Speter convert(filetype, ap); 675768Speter if (isa(ap, "bsci")) 676768Speter rangechk(ap, ap); 677768Speter put(2, O_AS, width(ap)); 678768Speter /* 679768Speter * get(file); 680768Speter */ 681768Speter put(1, O_GET); 682768Speter continue; 683768Speter } 684768Speter typ = classify(ap); 685768Speter op = rdops(typ); 686768Speter if (op == NIL) { 687768Speter error("Can't read %ss from a text file", clnames[typ]); 688768Speter continue; 689768Speter } 690768Speter if (op != O_READE) 691768Speter put(1, op); 692768Speter else { 693768Speter put(2, op, listnames(ap)); 694*1628Speter warning(); 695768Speter if (opt('s')) { 696768Speter standard(); 697768Speter } 698*1628Speter error("Reading scalars from text files is non-standard"); 699768Speter } 700768Speter /* 701768Speter * Data read is on the stack. 702768Speter * Assign it. 703768Speter */ 704768Speter if (op != O_READ8 && op != O_READE) 705768Speter rangechk(ap, op == O_READC ? ap : nl+T4INT); 706768Speter gen(O_AS2, O_AS2, width(ap), 707768Speter op == O_READ8 ? 8 : op == O_READ4 ? 4 : 2); 708768Speter } 709768Speter /* 710768Speter * Done with arguments. 711768Speter * Handle readln and 712768Speter * insufficient number of args. 713768Speter */ 714768Speter if (p->value[0] == O_READLN) { 715768Speter if (filetype != nl+T1CHAR) 716768Speter error("Can't 'readln' a non text file"); 717768Speter put(1, O_READLN); 718768Speter } 719768Speter else if (argc == 0) 720768Speter error("read requires an argument"); 721768Speter return; 722768Speter 723768Speter case O_GET: 724768Speter case O_PUT: 725768Speter if (argc != 1) { 726768Speter error("%s expects one argument", p->symbol); 727768Speter return; 728768Speter } 729768Speter ap = stkrval(argv[1], NIL , RREQ ); 730768Speter if (ap == NIL) 731768Speter return; 732768Speter if (ap->class != FILET) { 733768Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 734768Speter return; 735768Speter } 736768Speter put(1, O_UNIT); 737768Speter put(1, op); 738768Speter return; 739768Speter 740768Speter case O_RESET: 741768Speter case O_REWRITE: 742768Speter if (argc == 0 || argc > 2) { 743768Speter error("%s expects one or two arguments", p->symbol); 744768Speter return; 745768Speter } 746768Speter if (opt('s') && argc == 2) { 747768Speter standard(); 748768Speter error("Two argument forms of reset and rewrite are non-standard"); 749768Speter } 750768Speter ap = stklval(argv[1], MOD|NOUSE); 751768Speter if (ap == NIL) 752768Speter return; 753768Speter if (ap->class != FILET) { 754768Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 755768Speter return; 756768Speter } 757768Speter if (argc == 2) { 758768Speter /* 759768Speter * Optional second argument 760768Speter * is a string name of a 761768Speter * UNIX (R) file to be associated. 762768Speter */ 763768Speter al = argv[2]; 764768Speter al = stkrval(al[1], NOFLAGS , RREQ ); 765768Speter if (al == NIL) 766768Speter return; 767768Speter if (classify(al) != TSTR) { 768768Speter error("Second argument to %s must be a string, not %s", p->symbol, nameof(al)); 769768Speter return; 770768Speter } 771768Speter strnglen = width(al); 772768Speter } else { 773768Speter put(2, O_CON24, NIL); 774768Speter strnglen = 0; 775768Speter } 776768Speter put(2, O_CON24, strnglen); 777768Speter put(2, O_CON24, text(ap) ? 0: width(ap->type)); 778768Speter put(1, op); 779768Speter return; 780768Speter 781768Speter case O_NEW: 782768Speter case O_DISPOSE: 783768Speter if (argc == 0) { 784768Speter error("%s expects at least one argument", p->symbol); 785768Speter return; 786768Speter } 787768Speter ap = stklval(argv[1], op == O_NEW ? ( MOD | NOUSE ) : MOD ); 788768Speter if (ap == NIL) 789768Speter return; 790768Speter if (ap->class != PTR) { 791768Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 792768Speter return; 793768Speter } 794768Speter ap = ap->type; 795768Speter if (ap == NIL) 796768Speter return; 797768Speter argv = argv[2]; 798768Speter if (argv != NIL) { 799768Speter if (ap->class != RECORD) { 800768Speter error("Record required when specifying variant tags"); 801768Speter return; 802768Speter } 803768Speter for (; argv != NIL; argv = argv[2]) { 804768Speter if (ap->ptr[NL_VARNT] == NIL) { 805768Speter error("Too many tag fields"); 806768Speter return; 807768Speter } 808768Speter if (!isconst(argv[1])) { 809768Speter error("Second and successive arguments to %s must be constants", p->symbol); 810768Speter return; 811768Speter } 812768Speter gconst(argv[1]); 813768Speter if (con.ctype == NIL) 814768Speter return; 815768Speter if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) { 816768Speter cerror("Specified tag constant type clashed with variant case selector type"); 817768Speter return; 818768Speter } 819768Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 820768Speter if (ap->range[0] == con.crval) 821768Speter break; 822768Speter if (ap == NIL) { 823768Speter error("No variant case label value equals specified constant value"); 824768Speter return; 825768Speter } 826768Speter ap = ap->ptr[NL_VTOREC]; 827768Speter } 828768Speter } 829768Speter put(2, op, width(ap)); 830768Speter return; 831768Speter 832768Speter case O_DATE: 833768Speter case O_TIME: 834768Speter if (argc != 1) { 835768Speter error("%s expects one argument", p->symbol); 836768Speter return; 837768Speter } 838768Speter ap = stklval(argv[1], MOD|NOUSE); 839768Speter if (ap == NIL) 840768Speter return; 841768Speter if (classify(ap) != TSTR || width(ap) != 10) { 842768Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 843768Speter return; 844768Speter } 845768Speter put(1, op); 846768Speter return; 847768Speter 848768Speter case O_HALT: 849768Speter if (argc != 0) { 850768Speter error("halt takes no arguments"); 851768Speter return; 852768Speter } 853768Speter put(1, op); 854768Speter noreach = 1; 855768Speter return; 856768Speter 857768Speter case O_ARGV: 858768Speter if (argc != 2) { 859768Speter error("argv takes two arguments"); 860768Speter return; 861768Speter } 862768Speter ap = stkrval(argv[1], NIL , RREQ ); 863768Speter if (ap == NIL) 864768Speter return; 865768Speter if (isnta(ap, "i")) { 866768Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 867768Speter return; 868768Speter } 869768Speter al = argv[2]; 870768Speter ap = stklval(al[1], MOD|NOUSE); 871768Speter if (ap == NIL) 872768Speter return; 873768Speter if (classify(ap) != TSTR) { 874768Speter error("argv's second argument must be a string, not %s", nameof(ap)); 875768Speter return; 876768Speter } 877768Speter put(2, op, width(ap)); 878768Speter return; 879768Speter 880768Speter case O_STLIM: 881768Speter if (argc != 1) { 882768Speter error("stlimit requires one argument"); 883768Speter return; 884768Speter } 885768Speter ap = stkrval(argv[1], NIL , RREQ ); 886768Speter if (ap == NIL) 887768Speter return; 888768Speter if (isnta(ap, "i")) { 889768Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 890768Speter return; 891768Speter } 892768Speter if (width(ap) != 4) 893768Speter put(1, O_STOI); 894768Speter put(1, op); 895768Speter return; 896768Speter 897768Speter case O_REMOVE: 898768Speter if (argc != 1) { 899768Speter error("remove expects one argument"); 900768Speter return; 901768Speter } 902768Speter ap = stkrval(argv[1], NOFLAGS , RREQ ); 903768Speter if (ap == NIL) 904768Speter return; 905768Speter if (classify(ap) != TSTR) { 906768Speter error("remove's argument must be a string, not %s", nameof(ap)); 907768Speter return; 908768Speter } 909768Speter put(2, O_CON24, width(ap)); 910768Speter put(1, op); 911768Speter return; 912768Speter 913768Speter case O_LLIMIT: 914768Speter if (argc != 2) { 915768Speter error("linelimit expects two arguments"); 916768Speter return; 917768Speter } 918768Speter ap = stklval(argv[1], NOFLAGS|NOUSE); 919768Speter if (ap == NIL) 920768Speter return; 921768Speter if (!text(ap)) { 922768Speter error("linelimit's first argument must be a text file, not %s", nameof(ap)); 923768Speter return; 924768Speter } 925768Speter al = argv[2]; 926768Speter ap = stkrval(al[1], NIL , RREQ ); 927768Speter if (ap == NIL) 928768Speter return; 929768Speter if (isnta(ap, "i")) { 930768Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 931768Speter return; 932768Speter } 933768Speter put(1, op); 934768Speter return; 935768Speter case O_PAGE: 936768Speter if (argc != 1) { 937768Speter error("page expects one argument"); 938768Speter return; 939768Speter } 940768Speter ap = stkrval(argv[1], NIL , RREQ ); 941768Speter if (ap == NIL) 942768Speter return; 943768Speter if (!text(ap)) { 944768Speter error("Argument to page must be a text file, not %s", nameof(ap)); 945768Speter return; 946768Speter } 947768Speter put(1, O_UNIT); 948768Speter put(1, op); 949768Speter return; 950768Speter 951768Speter case O_PACK: 952768Speter if (argc != 3) { 953768Speter error("pack expects three arguments"); 954768Speter return; 955768Speter } 956768Speter pu = "pack(a,i,z)"; 957768Speter pua = (al = argv)[1]; 958768Speter pui = (al = al[2])[1]; 959768Speter puz = (al = al[2])[1]; 960768Speter goto packunp; 961768Speter case O_UNPACK: 962768Speter if (argc != 3) { 963768Speter error("unpack expects three arguments"); 964768Speter return; 965768Speter } 966768Speter pu = "unpack(z,a,i)"; 967768Speter puz = (al = argv)[1]; 968768Speter pua = (al = al[2])[1]; 969768Speter pui = (al = al[2])[1]; 970768Speter packunp: 971768Speter ap = stkrval((int *) pui, NLNIL , RREQ ); 972768Speter if (ap == NIL) 973768Speter return; 974768Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 975768Speter if (ap == NIL) 976768Speter return; 977768Speter if (ap->class != ARRAY) { 978768Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 979768Speter return; 980768Speter } 981768Speter al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 982768Speter if (al->class != ARRAY) { 983768Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 984768Speter return; 985768Speter } 986768Speter if (al->type == NIL || ap->type == NIL) 987768Speter return; 988768Speter if (al->type != ap->type) { 989768Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 990768Speter return; 991768Speter } 992768Speter k = width(al); 993768Speter itemwidth = width(ap->type); 994768Speter ap = ap->chain; 995768Speter al = al->chain; 996768Speter if (ap->chain != NIL || al->chain != NIL) { 997768Speter error("%s requires a and z to be single dimension arrays", pu); 998768Speter return; 999768Speter } 1000768Speter if (ap == NIL || al == NIL) 1001768Speter return; 1002768Speter /* 1003768Speter * al is the range for z i.e. u..v 1004768Speter * ap is the range for a i.e. m..n 1005768Speter * i will be n-m+1 1006768Speter * j will be v-u+1 1007768Speter */ 1008768Speter i = ap->range[1] - ap->range[0] + 1; 1009768Speter j = al->range[1] - al->range[0] + 1; 1010768Speter if (i < j) { 1011768Speter error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i); 1012768Speter return; 1013768Speter } 1014768Speter /* 1015768Speter * get n-m-(v-u) and m for the interpreter 1016768Speter */ 1017768Speter i -= j; 1018768Speter j = ap->range[0]; 1019768Speter put(5, op, itemwidth , j, i, k); 1020768Speter return; 1021768Speter case 0: 1022768Speter error("%s is an unimplemented 6400 extension", p->symbol); 1023768Speter return; 1024768Speter 1025768Speter default: 1026768Speter panic("proc case"); 1027768Speter } 1028768Speter } 1029768Speter #endif OBJ 1030