1768Speter /* Copyright (c) 1979 Regents of the University of California */ 2768Speter 3*3076Smckusic static char sccsid[] = "@(#)proc.c 1.5 03/08/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 } 1212073Smckusic 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; 1732073Smckusic 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 */ 2932073Smckusic 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: 3622073Smckusic if (fmtspec == NIL) { 3632073Smckusic put(1, O_FILE); 3642073Smckusic ap = stkrval(alv, NIL , RREQ ); 3652073Smckusic put(1, O_WRITEC); 3662073Smckusic fmtspec = SKIP; 3672073Smckusic break; 3682073Smckusic } 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 ); 381*3076Smckusic put(2, O_NAM, (long)listnames(ap)); 382*3076Smckusic # ifdef PDP11 383*3076Smckusic put(2, O_CON2, 0); /* long align ptr */ 384*3076Smckusic # endif PDP11 385768Speter stkcnt++; 386768Speter fmt = 's'; 387768Speter break; 388768Speter case TDOUBLE: 389768Speter ap = stkrval(alv, TDOUBLE , RREQ ); 390768Speter stkcnt += 2; 391768Speter tdouble: 392768Speter switch (fmtspec) { 393768Speter case NIL: 394*3076Smckusic # ifdef DEC11 395*3076Smckusic field = 21; 396*3076Smckusic # else 397*3076Smckusic field = 22; 398*3076Smckusic # endif DEC11 399768Speter prec = 14; 400*3076Smckusic fmt = 'e'; 401768Speter fmtspec = CONWIDTH + CONPREC; 402768Speter break; 403768Speter case CONWIDTH: 404768Speter if (--field < 1) 405768Speter field = 1; 406*3076Smckusic # ifdef DEC11 407*3076Smckusic prec = field - 7; 408*3076Smckusic # else 409*3076Smckusic prec = field - 8; 410*3076Smckusic # endif DEC11 411768Speter if (prec < 1) 412768Speter prec = 1; 413768Speter fmtspec += CONPREC; 414*3076Smckusic fmt = 'e'; 415768Speter break; 416768Speter case CONWIDTH + CONPREC: 417768Speter case CONWIDTH + VARPREC: 418768Speter if (--field < 1) 419768Speter field = 1; 420768Speter } 421768Speter format[0] = ' '; 422768Speter fmtstart = 0; 423768Speter break; 424768Speter case TSTR: 425768Speter constval( alv ); 426768Speter switch ( classify( con.ctype ) ) { 427768Speter case TCHAR: 428768Speter typ = TCHAR; 429768Speter goto tchar; 430768Speter case TSTR: 431768Speter strptr = con.cpval; 432768Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 433768Speter strptr = con.cpval; 434768Speter break; 435768Speter default: 436768Speter strnglen = width(ap); 437768Speter break; 438768Speter } 439768Speter fmt = 's'; 440768Speter strfmt = fmtspec; 441768Speter if (fmtspec == NIL) { 442768Speter fmtspec = SKIP; 443768Speter break; 444768Speter } 445768Speter if (fmtspec & CONWIDTH) { 446768Speter if (field <= strnglen) { 447768Speter fmtspec = SKIP; 448768Speter break; 449768Speter } else 450768Speter field -= strnglen; 451768Speter } 452768Speter /* 453768Speter * push string to implement leading blank padding 454768Speter */ 455768Speter put(2, O_LVCON, 2); 456768Speter putstr("", 0); 457*3076Smckusic # ifdef PDP11 458*3076Smckusic put(2, O_CON2, 0); /* long align ptr */ 459*3076Smckusic # endif PDP11 460768Speter stkcnt++; 461768Speter break; 462768Speter default: 463768Speter error("Can't write %ss to a text file", clnames[typ]); 464768Speter continue; 465768Speter } 466768Speter /* 467768Speter * If there is a variable precision, evaluate it onto 468768Speter * the stack 469768Speter */ 470768Speter if (fmtspec & VARPREC) { 471768Speter ap = stkrval(al[3], NIL , RREQ ); 472768Speter if (ap == NIL) 473768Speter continue; 474768Speter if (isnta(ap,"i")) { 475768Speter error("Second write width must be integer, not %s", nameof(ap)); 476768Speter continue; 477768Speter } 478768Speter if ( opt( 't' ) ) { 479768Speter put(3, O_MAX, 0, 0); 480768Speter } 481768Speter stkcnt++; 482768Speter } 483768Speter /* 484768Speter * If there is a variable width, evaluate it onto 485768Speter * the stack 486768Speter */ 487768Speter if (fmtspec & VARWIDTH) { 488768Speter if ( ( typ == TDOUBLE && fmtspec == VARWIDTH ) 489768Speter || typ == TSTR ) { 490*3076Smckusic i = sizes[cbn].om_off -= sizeof(long); 491768Speter if (i < sizes[cbn].om_max) 492768Speter sizes[cbn].om_max = i; 493768Speter put(2, O_LV | cbn << 8 + INDX, i); 494768Speter } 495768Speter ap = stkrval(al[2], NIL , RREQ ); 496768Speter if (ap == NIL) 497768Speter continue; 498768Speter if (isnta(ap,"i")) { 499768Speter error("First write width must be integer, not %s", nameof(ap)); 500768Speter continue; 501768Speter } 502768Speter stkcnt++; 503768Speter /* 504768Speter * Perform special processing on widths based 505768Speter * on data type 506768Speter */ 507768Speter switch (typ) { 508768Speter case TDOUBLE: 509768Speter if (fmtspec == VARWIDTH) { 510*3076Smckusic fmt = 'e'; 511768Speter put(1, O_AS4); 512768Speter put(2, O_RV4 | cbn << 8 + INDX, i); 513*3076Smckusic # ifdef DEC11 514*3076Smckusic put(3, O_MAX, 8, 1); 515*3076Smckusic # else 516*3076Smckusic put(3, O_MAX, 9, 1); 517*3076Smckusic # endif DEC11 518768Speter put(2, O_RV4 | cbn << 8 + INDX, i); 519768Speter stkcnt++; 520768Speter fmtspec += VARPREC; 521768Speter } 522768Speter put(3, O_MAX, 1, 1); 523768Speter break; 524768Speter case TSTR: 525768Speter put(1, O_AS4); 526768Speter put(2, O_RV4 | cbn << 8 + INDX, i); 527768Speter put(3, O_MAX, strnglen, 0); 528768Speter break; 529768Speter default: 530768Speter if ( opt( 't' ) ) { 531768Speter put(3, O_MAX, 0, 0); 532768Speter } 533768Speter break; 534768Speter } 535768Speter } 536768Speter /* 537768Speter * Generate the format string 538768Speter */ 539768Speter switch (fmtspec) { 540768Speter default: 541768Speter panic("fmt2"); 542768Speter case SKIP: 543768Speter break; 5442073Smckusic case NIL: 5452073Smckusic sprintf(&format[1], "%%%c", fmt); 5462073Smckusic goto fmtgen; 547768Speter case CONWIDTH: 548*3076Smckusic sprintf(&format[1], "%%%d%c", field, fmt); 549768Speter goto fmtgen; 550768Speter case VARWIDTH: 551768Speter sprintf(&format[1], "%%*%c", fmt); 552768Speter goto fmtgen; 553768Speter case CONWIDTH + CONPREC: 554*3076Smckusic sprintf(&format[1], "%%%d.%d%c", field, prec, fmt); 555768Speter goto fmtgen; 556768Speter case CONWIDTH + VARPREC: 557*3076Smckusic sprintf(&format[1], "%%%d.*%c", field, fmt); 558768Speter goto fmtgen; 559768Speter case VARWIDTH + CONPREC: 560*3076Smckusic sprintf(&format[1], "%%*.%d%c", prec, fmt); 561768Speter goto fmtgen; 562768Speter case VARWIDTH + VARPREC: 563768Speter sprintf(&format[1], "%%*.*%c", fmt); 564768Speter fmtgen: 565768Speter fmtlen = lenstr(&format[fmtstart], 0); 566768Speter put(2, O_LVCON, fmtlen); 567768Speter putstr(&format[fmtstart], 0); 568768Speter put(1, O_FILE); 569768Speter stkcnt += 2; 570768Speter put(2, O_WRITEF, stkcnt); 571768Speter } 572768Speter /* 573768Speter * Write the string after its blank padding 574768Speter */ 575768Speter if (typ == TSTR) { 576768Speter put(1, O_FILE); 577768Speter put(2, O_CON24, 1); 578768Speter if (strfmt & VARWIDTH) { 579768Speter put(2, O_RV4 | cbn << 8 + INDX , i ); 580768Speter put(2, O_MIN, strnglen); 581768Speter } else { 582768Speter if ((fmtspec & SKIP) && 583768Speter (strfmt & CONWIDTH)) { 584768Speter strnglen = field; 585768Speter } 586768Speter put(2, O_CON24, strnglen); 587768Speter } 588768Speter ap = stkrval(alv, NIL , RREQ ); 589768Speter put(1, O_WRITES); 590768Speter } 591768Speter } 592768Speter /* 593768Speter * Done with arguments. 594768Speter * Handle writeln and 595768Speter * insufficent number of args. 596768Speter */ 597768Speter switch (p->value[0] &~ NSTAND) { 598768Speter case O_WRITEF: 599768Speter if (argc == 0) 600768Speter error("Write requires an argument"); 601768Speter break; 602768Speter case O_MESSAGE: 603768Speter if (argc == 0) 604768Speter error("Message requires an argument"); 605768Speter case O_WRITLN: 606768Speter if (filetype != nl+T1CHAR) 607768Speter error("Can't 'writeln' a non text file"); 608768Speter put(1, O_WRITLN); 609768Speter break; 610768Speter } 611768Speter return; 612768Speter 613768Speter case O_READ4: 614768Speter case O_READLN: 615768Speter /* 616768Speter * Set up default 617768Speter * file "input". 618768Speter */ 619768Speter file = NIL; 620768Speter filetype = nl+T1CHAR; 621768Speter /* 622768Speter * Determine the file implied 623768Speter * for the read and generate 624768Speter * code to make it the active file. 625768Speter */ 626768Speter if (argv != NIL) { 627768Speter codeoff(); 628768Speter ap = stkrval(argv[1], NIL , RREQ ); 629768Speter codeon(); 630768Speter if (ap == NIL) 631768Speter argv = argv[2]; 632768Speter if (ap != NIL && ap->class == FILET) { 633768Speter /* 634768Speter * Got "read(f, ...", make 635768Speter * f the active file, and save 636768Speter * it and its type for use in 637768Speter * processing the rest of the 638768Speter * arguments to read. 639768Speter */ 640768Speter file = argv[1]; 641768Speter filetype = ap->type; 6422073Smckusic stklval(argv[1], NIL , LREQ ); 643768Speter put(1, O_UNIT); 644768Speter argv = argv[2]; 645768Speter argc--; 646768Speter } else { 647768Speter /* 648768Speter * Default is read from 649768Speter * standard input. 650768Speter */ 651768Speter put(1, O_UNITINP); 652768Speter input->nl_flags |= NUSED; 653768Speter } 654768Speter } else { 655768Speter put(1, O_UNITINP); 656768Speter input->nl_flags |= NUSED; 657768Speter } 658768Speter /* 659768Speter * Loop and process each 660768Speter * of the arguments. 661768Speter */ 662768Speter for (; argv != NIL; argv = argv[2]) { 663768Speter /* 664768Speter * Get the address of the target 665768Speter * on the stack. 666768Speter */ 667768Speter al = argv[1]; 668768Speter if (al == NIL) 669768Speter continue; 670768Speter if (al[0] != T_VAR) { 671768Speter error("Arguments to %s must be variables, not expressions", p->symbol); 672768Speter continue; 673768Speter } 674768Speter ap = stklval(al, MOD|ASGN|NOUSE); 675768Speter if (ap == NIL) 676768Speter continue; 677768Speter if (filetype != nl+T1CHAR) { 678768Speter /* 679768Speter * Generalized read, i.e. 680768Speter * from a non-textfile. 681768Speter */ 682768Speter if (incompat(filetype, ap, argv[1] )) { 683768Speter error("Type mismatch in read from non-text file"); 684768Speter continue; 685768Speter } 686768Speter /* 687768Speter * var := file ^; 688768Speter */ 689768Speter if (file != NIL) 6902073Smckusic stklval(file, NIL , LREQ ); 691768Speter else /* Magic */ 692*3076Smckusic put(2, PTR_RV, (int)input->value[0]); 693768Speter put(1, O_FNIL); 694768Speter put(2, O_IND, width(filetype)); 695768Speter convert(filetype, ap); 696768Speter if (isa(ap, "bsci")) 697768Speter rangechk(ap, ap); 698768Speter put(2, O_AS, width(ap)); 699768Speter /* 700768Speter * get(file); 701768Speter */ 702768Speter put(1, O_GET); 703768Speter continue; 704768Speter } 705768Speter typ = classify(ap); 706768Speter op = rdops(typ); 707768Speter if (op == NIL) { 708768Speter error("Can't read %ss from a text file", clnames[typ]); 709768Speter continue; 710768Speter } 711768Speter if (op != O_READE) 712768Speter put(1, op); 713768Speter else { 714*3076Smckusic put(2, op, (long)listnames(ap)); 7151628Speter warning(); 716768Speter if (opt('s')) { 717768Speter standard(); 718768Speter } 7191628Speter error("Reading scalars from text files is non-standard"); 720768Speter } 721768Speter /* 722768Speter * Data read is on the stack. 723768Speter * Assign it. 724768Speter */ 725768Speter if (op != O_READ8 && op != O_READE) 726768Speter rangechk(ap, op == O_READC ? ap : nl+T4INT); 727768Speter gen(O_AS2, O_AS2, width(ap), 728768Speter op == O_READ8 ? 8 : op == O_READ4 ? 4 : 2); 729768Speter } 730768Speter /* 731768Speter * Done with arguments. 732768Speter * Handle readln and 733768Speter * insufficient number of args. 734768Speter */ 735768Speter if (p->value[0] == O_READLN) { 736768Speter if (filetype != nl+T1CHAR) 737768Speter error("Can't 'readln' a non text file"); 738768Speter put(1, O_READLN); 739768Speter } 740768Speter else if (argc == 0) 741768Speter error("read requires an argument"); 742768Speter return; 743768Speter 744768Speter case O_GET: 745768Speter case O_PUT: 746768Speter if (argc != 1) { 747768Speter error("%s expects one argument", p->symbol); 748768Speter return; 749768Speter } 7502073Smckusic ap = stklval(argv[1], NIL , LREQ ); 751768Speter if (ap == NIL) 752768Speter return; 753768Speter if (ap->class != FILET) { 754768Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 755768Speter return; 756768Speter } 757768Speter put(1, O_UNIT); 758768Speter put(1, op); 759768Speter return; 760768Speter 761768Speter case O_RESET: 762768Speter case O_REWRITE: 763768Speter if (argc == 0 || argc > 2) { 764768Speter error("%s expects one or two arguments", p->symbol); 765768Speter return; 766768Speter } 767768Speter if (opt('s') && argc == 2) { 768768Speter standard(); 769768Speter error("Two argument forms of reset and rewrite are non-standard"); 770768Speter } 7712073Smckusic codeoff(); 772768Speter ap = stklval(argv[1], MOD|NOUSE); 7732073Smckusic codeon(); 774768Speter if (ap == NIL) 775768Speter return; 776768Speter if (ap->class != FILET) { 777768Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 778768Speter return; 779768Speter } 7802073Smckusic put(2, O_CON24, text(ap) ? 0: width(ap->type)); 781768Speter if (argc == 2) { 782768Speter /* 783768Speter * Optional second argument 784768Speter * is a string name of a 785768Speter * UNIX (R) file to be associated. 786768Speter */ 787768Speter al = argv[2]; 7882073Smckusic codeoff(); 789768Speter al = stkrval(al[1], NOFLAGS , RREQ ); 7902073Smckusic codeon(); 791768Speter if (al == NIL) 792768Speter return; 793768Speter if (classify(al) != TSTR) { 794768Speter error("Second argument to %s must be a string, not %s", p->symbol, nameof(al)); 795768Speter return; 796768Speter } 7972073Smckusic put(2, O_CON24, width(al)); 7982073Smckusic al = argv[2]; 7992073Smckusic al = stkrval(al[1], NOFLAGS , RREQ ); 800768Speter } else { 8012073Smckusic put(2, O_CON24, 0); 802*3076Smckusic put(2, PTR_CON, NIL); 803768Speter } 8042073Smckusic ap = stklval(argv[1], MOD|NOUSE); 805768Speter put(1, op); 806768Speter return; 807768Speter 808768Speter case O_NEW: 809768Speter case O_DISPOSE: 810768Speter if (argc == 0) { 811768Speter error("%s expects at least one argument", p->symbol); 812768Speter return; 813768Speter } 814768Speter ap = stklval(argv[1], op == O_NEW ? ( MOD | NOUSE ) : MOD ); 815768Speter if (ap == NIL) 816768Speter return; 817768Speter if (ap->class != PTR) { 818768Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 819768Speter return; 820768Speter } 821768Speter ap = ap->type; 822768Speter if (ap == NIL) 823768Speter return; 824768Speter argv = argv[2]; 825768Speter if (argv != NIL) { 826768Speter if (ap->class != RECORD) { 827768Speter error("Record required when specifying variant tags"); 828768Speter return; 829768Speter } 830768Speter for (; argv != NIL; argv = argv[2]) { 831768Speter if (ap->ptr[NL_VARNT] == NIL) { 832768Speter error("Too many tag fields"); 833768Speter return; 834768Speter } 835768Speter if (!isconst(argv[1])) { 836768Speter error("Second and successive arguments to %s must be constants", p->symbol); 837768Speter return; 838768Speter } 839768Speter gconst(argv[1]); 840768Speter if (con.ctype == NIL) 841768Speter return; 842768Speter if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) { 843768Speter cerror("Specified tag constant type clashed with variant case selector type"); 844768Speter return; 845768Speter } 846768Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 847768Speter if (ap->range[0] == con.crval) 848768Speter break; 849768Speter if (ap == NIL) { 850768Speter error("No variant case label value equals specified constant value"); 851768Speter return; 852768Speter } 853768Speter ap = ap->ptr[NL_VTOREC]; 854768Speter } 855768Speter } 856768Speter put(2, op, width(ap)); 857768Speter return; 858768Speter 859768Speter case O_DATE: 860768Speter case O_TIME: 861768Speter if (argc != 1) { 862768Speter error("%s expects one argument", p->symbol); 863768Speter return; 864768Speter } 865768Speter ap = stklval(argv[1], MOD|NOUSE); 866768Speter if (ap == NIL) 867768Speter return; 868768Speter if (classify(ap) != TSTR || width(ap) != 10) { 869768Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 870768Speter return; 871768Speter } 872768Speter put(1, op); 873768Speter return; 874768Speter 875768Speter case O_HALT: 876768Speter if (argc != 0) { 877768Speter error("halt takes no arguments"); 878768Speter return; 879768Speter } 880768Speter put(1, op); 881768Speter noreach = 1; 882768Speter return; 883768Speter 884768Speter case O_ARGV: 885768Speter if (argc != 2) { 886768Speter error("argv takes two arguments"); 887768Speter return; 888768Speter } 889768Speter ap = stkrval(argv[1], NIL , RREQ ); 890768Speter if (ap == NIL) 891768Speter return; 892768Speter if (isnta(ap, "i")) { 893768Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 894768Speter return; 895768Speter } 896768Speter al = argv[2]; 897768Speter ap = stklval(al[1], MOD|NOUSE); 898768Speter if (ap == NIL) 899768Speter return; 900768Speter if (classify(ap) != TSTR) { 901768Speter error("argv's second argument must be a string, not %s", nameof(ap)); 902768Speter return; 903768Speter } 904768Speter put(2, op, width(ap)); 905768Speter return; 906768Speter 907768Speter case O_STLIM: 908768Speter if (argc != 1) { 909768Speter error("stlimit requires one argument"); 910768Speter return; 911768Speter } 912768Speter ap = stkrval(argv[1], NIL , RREQ ); 913768Speter if (ap == NIL) 914768Speter return; 915768Speter if (isnta(ap, "i")) { 916768Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 917768Speter return; 918768Speter } 919768Speter if (width(ap) != 4) 920768Speter put(1, O_STOI); 921768Speter put(1, op); 922768Speter return; 923768Speter 924768Speter case O_REMOVE: 925768Speter if (argc != 1) { 926768Speter error("remove expects one argument"); 927768Speter return; 928768Speter } 9292073Smckusic codeoff(); 930768Speter ap = stkrval(argv[1], NOFLAGS , RREQ ); 9312073Smckusic codeon(); 932768Speter if (ap == NIL) 933768Speter return; 934768Speter if (classify(ap) != TSTR) { 935768Speter error("remove's argument must be a string, not %s", nameof(ap)); 936768Speter return; 937768Speter } 938768Speter put(2, O_CON24, width(ap)); 9392073Smckusic ap = stkrval(argv[1], NOFLAGS , RREQ ); 940768Speter put(1, op); 941768Speter return; 942768Speter 943768Speter case O_LLIMIT: 944768Speter if (argc != 2) { 945768Speter error("linelimit expects two arguments"); 946768Speter return; 947768Speter } 948768Speter al = argv[2]; 949768Speter ap = stkrval(al[1], NIL , RREQ ); 950768Speter if (ap == NIL) 951768Speter return; 952768Speter if (isnta(ap, "i")) { 953768Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 954768Speter return; 955768Speter } 9562073Smckusic ap = stklval(argv[1], NOFLAGS|NOUSE); 9572073Smckusic if (ap == NIL) 9582073Smckusic return; 9592073Smckusic if (!text(ap)) { 9602073Smckusic error("linelimit's first argument must be a text file, not %s", nameof(ap)); 9612073Smckusic return; 9622073Smckusic } 963768Speter put(1, op); 964768Speter return; 965768Speter case O_PAGE: 966768Speter if (argc != 1) { 967768Speter error("page expects one argument"); 968768Speter return; 969768Speter } 9702073Smckusic ap = stklval(argv[1], NIL , LREQ ); 971768Speter if (ap == NIL) 972768Speter return; 973768Speter if (!text(ap)) { 974768Speter error("Argument to page must be a text file, not %s", nameof(ap)); 975768Speter return; 976768Speter } 977768Speter put(1, O_UNIT); 978768Speter put(1, op); 979768Speter return; 980768Speter 981768Speter case O_PACK: 982768Speter if (argc != 3) { 983768Speter error("pack expects three arguments"); 984768Speter return; 985768Speter } 986768Speter pu = "pack(a,i,z)"; 987*3076Smckusic pua = argv[1]; 988*3076Smckusic al = argv[2]; 989*3076Smckusic pui = al[1]; 990*3076Smckusic alv = al[2]; 991*3076Smckusic puz = alv[1]; 992768Speter goto packunp; 993768Speter case O_UNPACK: 994768Speter if (argc != 3) { 995768Speter error("unpack expects three arguments"); 996768Speter return; 997768Speter } 998768Speter pu = "unpack(z,a,i)"; 999*3076Smckusic puz = argv[1]; 1000*3076Smckusic al = argv[2]; 1001*3076Smckusic pua = al[1]; 1002*3076Smckusic alv = al[2]; 1003*3076Smckusic pui = alv[1]; 1004768Speter packunp: 10052073Smckusic codeoff(); 1006768Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 10072073Smckusic al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 10082073Smckusic codeon(); 1009768Speter if (ap == NIL) 1010768Speter return; 1011768Speter if (ap->class != ARRAY) { 1012768Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 1013768Speter return; 1014768Speter } 1015768Speter if (al->class != ARRAY) { 1016768Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 1017768Speter return; 1018768Speter } 1019768Speter if (al->type == NIL || ap->type == NIL) 1020768Speter return; 1021768Speter if (al->type != ap->type) { 1022768Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 1023768Speter return; 1024768Speter } 1025768Speter k = width(al); 1026768Speter itemwidth = width(ap->type); 1027768Speter ap = ap->chain; 1028768Speter al = al->chain; 1029768Speter if (ap->chain != NIL || al->chain != NIL) { 1030768Speter error("%s requires a and z to be single dimension arrays", pu); 1031768Speter return; 1032768Speter } 1033768Speter if (ap == NIL || al == NIL) 1034768Speter return; 1035768Speter /* 1036768Speter * al is the range for z i.e. u..v 1037768Speter * ap is the range for a i.e. m..n 1038768Speter * i will be n-m+1 1039768Speter * j will be v-u+1 1040768Speter */ 1041768Speter i = ap->range[1] - ap->range[0] + 1; 1042768Speter j = al->range[1] - al->range[0] + 1; 1043768Speter if (i < j) { 1044768Speter error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i); 1045768Speter return; 1046768Speter } 1047768Speter /* 1048768Speter * get n-m-(v-u) and m for the interpreter 1049768Speter */ 1050768Speter i -= j; 1051768Speter j = ap->range[0]; 10522073Smckusic put(2, O_CON24, k); 10532073Smckusic put(2, O_CON24, i); 10542073Smckusic put(2, O_CON24, j); 10552073Smckusic put(2, O_CON24, itemwidth); 10562073Smckusic al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 10572073Smckusic ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 10582073Smckusic ap = stkrval((int *) pui, NLNIL , RREQ ); 10592073Smckusic if (ap == NIL) 10602073Smckusic return; 10612073Smckusic put(1, op); 1062768Speter return; 1063768Speter case 0: 1064768Speter error("%s is an unimplemented 6400 extension", p->symbol); 1065768Speter return; 1066768Speter 1067768Speter default: 1068768Speter panic("proc case"); 1069768Speter } 1070768Speter } 1071768Speter #endif OBJ 1072