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