1766Speter /* Copyright (c) 1979 Regents of the University of California */ 2766Speter 315934Smckusick #ifndef lint 4*15935Smckusick static char sccsid[] = "@(#)pcproc.c 1.23 02/04/84"; 515934Smckusick #endif 6766Speter 7766Speter #include "whoami.h" 8766Speter #ifdef PC 9766Speter /* 10766Speter * and to the end of the file 11766Speter */ 12766Speter #include "0.h" 13766Speter #include "tree.h" 1410372Speter #include "objfmt.h" 15766Speter #include "opcode.h" 1610372Speter #include "pc.h" 1710372Speter #include "pcops.h" 1811333Speter #include "tmps.h" 1915934Smckusick #include "tree_ty.h" 20766Speter 21766Speter /* 2211883Smckusick * The constant EXPOSIZE specifies the number of digits in the exponent 2311883Smckusick * of real numbers. 2411883Smckusick * 259229Smckusick * The constant REALSPC defines the amount of forced padding preceeding 269229Smckusick * real numbers when they are printed. If REALSPC == 0, then no padding 279229Smckusick * is added, REALSPC == 1 adds one extra blank irregardless of the width 289229Smckusick * specified by the user. 299229Smckusick * 309229Smckusick * N.B. - Values greater than one require program mods. 319229Smckusick */ 3211883Smckusick #define EXPOSIZE 2 3311883Smckusick #define REALSPC 0 349229Smckusick 359229Smckusick /* 36766Speter * The following array is used to determine which classes may be read 37766Speter * from textfiles. It is indexed by the return value from classify. 38766Speter */ 39766Speter #define rdops(x) rdxxxx[(x)-(TFIRST)] 40766Speter 41766Speter int rdxxxx[] = { 42766Speter 0, /* -7 file types */ 43766Speter 0, /* -6 record types */ 44766Speter 0, /* -5 array types */ 45766Speter O_READE, /* -4 scalar types */ 46766Speter 0, /* -3 pointer types */ 47766Speter 0, /* -2 set types */ 48766Speter 0, /* -1 string types */ 49766Speter 0, /* 0 nil, no type */ 50766Speter O_READE, /* 1 boolean */ 51766Speter O_READC, /* 2 character */ 52766Speter O_READ4, /* 3 integer */ 53766Speter O_READ8 /* 4 real */ 54766Speter }; 55766Speter 56766Speter /* 57766Speter * Proc handles procedure calls. 58766Speter * Non-builtin procedures are "buck-passed" to func (with a flag 59766Speter * indicating that they are actually procedures. 60766Speter * builtin procedures are handled here. 61766Speter */ 62766Speter pcproc(r) 6315934Smckusick struct tnode *r; /* T_PCALL */ 64766Speter { 65766Speter register struct nl *p; 6615934Smckusick register struct tnode *alv, *al; 6715934Smckusick register op; 68766Speter struct nl *filetype, *ap; 6915934Smckusick int argc, typ, fmtspec, strfmt; 7015934Smckusick struct tnode *argv, *file; 717967Smckusick char fmt, format[20], *strptr, *cmd; 7215934Smckusick int prec, field, strnglen, fmtstart; 7315934Smckusick char *pu; 7415934Smckusick struct tnode *pua, *pui, *puz; 75766Speter int i, j, k; 76766Speter int itemwidth; 773833Speter char *readname; 783833Speter struct nl *tempnlp; 793833Speter long readtype; 803833Speter struct tmps soffset; 81*15935Smckusick bool soffset_flag; 82766Speter 83766Speter #define CONPREC 4 84766Speter #define VARPREC 8 85766Speter #define CONWIDTH 1 86766Speter #define VARWIDTH 2 87766Speter #define SKIP 16 88766Speter 89766Speter /* 90766Speter * Verify that the name is 91766Speter * defined and is that of a 92766Speter * procedure. 93766Speter */ 9415934Smckusick p = lookup(r->pcall_node.proc_id); 9515934Smckusick if (p == NLNIL) { 9615934Smckusick rvlist(r->pcall_node.arg); 97766Speter return; 98766Speter } 991197Speter if (p->class != PROC && p->class != FPROC) { 100766Speter error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]); 10115934Smckusick rvlist(r->pcall_node.arg); 102766Speter return; 103766Speter } 10415934Smckusick argv = r->pcall_node.arg; 105766Speter 106766Speter /* 107766Speter * Call handles user defined 108766Speter * procedures and functions. 109766Speter */ 110766Speter if (bn != 0) { 11115934Smckusick (void) call(p, argv, PROC, bn); 112766Speter return; 113766Speter } 114766Speter 115766Speter /* 116766Speter * Call to built-in procedure. 117766Speter * Count the arguments. 118766Speter */ 119766Speter argc = 0; 12015934Smckusick for (al = argv; al != TR_NIL; al = al->list_node.next) 121766Speter argc++; 122766Speter 123766Speter /* 124766Speter * Switch on the operator 125766Speter * associated with the built-in 126766Speter * procedure in the namelist 127766Speter */ 128766Speter op = p->value[0] &~ NSTAND; 129766Speter if (opt('s') && (p->value[0] & NSTAND)) { 130766Speter standard(); 131766Speter error("%s is a nonstandard procedure", p->symbol); 132766Speter } 133766Speter switch (op) { 134766Speter 135766Speter case O_ABORT: 136766Speter if (argc != 0) 137766Speter error("null takes no arguments"); 138766Speter return; 139766Speter 140766Speter case O_FLUSH: 141766Speter if (argc == 0) { 142766Speter putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" ); 143766Speter putop( P2UNARY P2CALL , P2INT ); 144766Speter putdot( filename , line ); 145766Speter return; 146766Speter } 147766Speter if (argc != 1) { 148766Speter error("flush takes at most one argument"); 149766Speter return; 150766Speter } 151766Speter putleaf( P2ICON , 0 , 0 152766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 153766Speter , "_FLUSH" ); 15415934Smckusick ap = stklval(argv->list_node.list, NOFLAGS); 15515934Smckusick if (ap == NLNIL) 156766Speter return; 157766Speter if (ap->class != FILET) { 158766Speter error("flush's argument must be a file, not %s", nameof(ap)); 159766Speter return; 160766Speter } 161766Speter putop( P2CALL , P2INT ); 162766Speter putdot( filename , line ); 163766Speter return; 164766Speter 165766Speter case O_MESSAGE: 166766Speter case O_WRITEF: 167766Speter case O_WRITLN: 168766Speter /* 169766Speter * Set up default file "output"'s type 170766Speter */ 171766Speter file = NIL; 172766Speter filetype = nl+T1CHAR; 173766Speter /* 174766Speter * Determine the file implied 175766Speter * for the write and generate 176766Speter * code to make it the active file. 177766Speter */ 178766Speter if (op == O_MESSAGE) { 179766Speter /* 180766Speter * For message, all that matters 181766Speter * is that the filetype is 182766Speter * a character file. 183766Speter * Thus "output" will suit us fine. 184766Speter */ 185766Speter putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" ); 186766Speter putop( P2UNARY P2CALL , P2INT ); 187766Speter putdot( filename , line ); 18815934Smckusick putRV( (char *) 0 , cbn , CURFILEOFFSET , NLOCAL , 1893833Speter P2PTR|P2STRTY ); 1903833Speter putLV( "__err" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 191766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 192766Speter putdot( filename , line ); 19315934Smckusick } else if (argv != TR_NIL && (al = argv->list_node.list)->tag != 19415934Smckusick T_WEXP) { 195766Speter /* 196766Speter * If there is a first argument which has 197766Speter * no write widths, then it is potentially 198766Speter * a file name. 199766Speter */ 200766Speter codeoff(); 20115934Smckusick ap = stkrval(argv->list_node.list, NLNIL, (long) RREQ ); 202766Speter codeon(); 20315934Smckusick if (ap == NLNIL) 20415934Smckusick argv = argv->list_node.next; 205766Speter if (ap != NIL && ap->class == FILET) { 206766Speter /* 207766Speter * Got "write(f, ...", make 208766Speter * f the active file, and save 209766Speter * it and its type for use in 210766Speter * processing the rest of the 211766Speter * arguments to write. 212766Speter */ 21315934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , 2143833Speter P2PTR|P2STRTY ); 215766Speter putleaf( P2ICON , 0 , 0 216766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 217766Speter , "_UNIT" ); 21815934Smckusick file = argv->list_node.list; 219766Speter filetype = ap->type; 22015934Smckusick (void) stklval(argv->list_node.list, NOFLAGS); 221766Speter putop( P2CALL , P2INT ); 222766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 223766Speter putdot( filename , line ); 224766Speter /* 225766Speter * Skip over the first argument 226766Speter */ 22715934Smckusick argv = argv->list_node.next; 228766Speter argc--; 229766Speter } else { 230766Speter /* 231766Speter * Set up for writing on 232766Speter * standard output. 233766Speter */ 23415934Smckusick putRV((char *) 0, cbn , CURFILEOFFSET , 2353833Speter NLOCAL , P2PTR|P2STRTY ); 2363833Speter putLV( "_output" , 0 , 0 , NGLOBAL , 2373833Speter P2PTR|P2STRTY ); 238766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 239766Speter putdot( filename , line ); 2407954Speter output->nl_flags |= NUSED; 241766Speter } 242766Speter } else { 24315934Smckusick putRV((char *) 0, cbn , CURFILEOFFSET , NLOCAL , 2443833Speter P2PTR|P2STRTY ); 2453833Speter putLV( "_output" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 246766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 247766Speter putdot( filename , line ); 2487954Speter output->nl_flags |= NUSED; 249766Speter } 250766Speter /* 251766Speter * Loop and process each 252766Speter * of the arguments. 253766Speter */ 25415934Smckusick for (; argv != TR_NIL; argv = argv->list_node.next) { 255*15935Smckusick soffset_flag = FALSE; 256766Speter /* 257766Speter * fmtspec indicates the type (CONstant or VARiable) 258766Speter * and number (none, WIDTH, and/or PRECision) 259766Speter * of the fields in the printf format for this 260766Speter * output variable. 261766Speter * fmt is the format output indicator (D, E, F, O, X, S) 262766Speter * fmtstart = 0 for leading blank; = 1 for no blank 263766Speter */ 264766Speter fmtspec = NIL; 265766Speter fmt = 'D'; 266766Speter fmtstart = 1; 26715934Smckusick al = argv->list_node.list; 268766Speter if (al == NIL) 269766Speter continue; 27015934Smckusick if (al->tag == T_WEXP) 27115934Smckusick alv = al->wexpr_node.expr1; 272766Speter else 273766Speter alv = al; 27415934Smckusick if (alv == TR_NIL) 275766Speter continue; 276766Speter codeoff(); 27715934Smckusick ap = stkrval(alv, NLNIL , (long) RREQ ); 278766Speter codeon(); 27915934Smckusick if (ap == NLNIL) 280766Speter continue; 281766Speter typ = classify(ap); 28215934Smckusick if (al->tag == T_WEXP) { 283766Speter /* 284766Speter * Handle width expressions. 285766Speter * The basic game here is that width 286766Speter * expressions get evaluated. If they 287766Speter * are constant, the value is placed 288766Speter * directly in the format string. 289766Speter * Otherwise the value is pushed onto 290766Speter * the stack and an indirection is 291766Speter * put into the format string. 292766Speter */ 29315934Smckusick if (al->wexpr_node.expr3 == 29415934Smckusick (struct tnode *) OCT) 295766Speter fmt = 'O'; 29615934Smckusick else if (al->wexpr_node.expr3 == 29715934Smckusick (struct tnode *) HEX) 298766Speter fmt = 'X'; 29915934Smckusick else if (al->wexpr_node.expr3 != TR_NIL) { 300766Speter /* 301766Speter * Evaluate second format spec 302766Speter */ 30315934Smckusick if ( constval(al->wexpr_node.expr3) 304766Speter && isa( con.ctype , "i" ) ) { 305766Speter fmtspec += CONPREC; 306766Speter prec = con.crval; 307766Speter } else { 308766Speter fmtspec += VARPREC; 309766Speter } 310766Speter fmt = 'f'; 311766Speter switch ( typ ) { 312766Speter case TINT: 313766Speter if ( opt( 's' ) ) { 314766Speter standard(); 315766Speter error("Writing %ss with two write widths is non-standard", clnames[typ]); 316766Speter } 317766Speter /* and fall through */ 318766Speter case TDOUBLE: 319766Speter break; 320766Speter default: 321766Speter error("Cannot write %ss with two write widths", clnames[typ]); 322766Speter continue; 323766Speter } 324766Speter } 325766Speter /* 326766Speter * Evaluate first format spec 327766Speter */ 32815934Smckusick if (al->wexpr_node.expr2 != TR_NIL) { 32915934Smckusick if ( constval(al->wexpr_node.expr2) 330766Speter && isa( con.ctype , "i" ) ) { 331766Speter fmtspec += CONWIDTH; 332766Speter field = con.crval; 333766Speter } else { 334766Speter fmtspec += VARWIDTH; 335766Speter } 336766Speter } 337766Speter if ((fmtspec & CONPREC) && prec < 0 || 338766Speter (fmtspec & CONWIDTH) && field < 0) { 339766Speter error("Negative widths are not allowed"); 340766Speter continue; 341766Speter } 3423180Smckusic if ( opt('s') && 3433180Smckusic ((fmtspec & CONPREC) && prec == 0 || 3443180Smckusic (fmtspec & CONWIDTH) && field == 0)) { 3453180Smckusic standard(); 3463180Smckusic error("Zero widths are non-standard"); 3473180Smckusic } 348766Speter } 349766Speter if (filetype != nl+T1CHAR) { 350766Speter if (fmt == 'O' || fmt == 'X') { 351766Speter error("Oct/hex allowed only on text files"); 352766Speter continue; 353766Speter } 354766Speter if (fmtspec) { 355766Speter error("Write widths allowed only on text files"); 356766Speter continue; 357766Speter } 358766Speter /* 359766Speter * Generalized write, i.e. 360766Speter * to a non-textfile. 361766Speter */ 362766Speter putleaf( P2ICON , 0 , 0 36315934Smckusick , (int) (ADDTYPE( 364766Speter ADDTYPE( 365766Speter ADDTYPE( p2type( filetype ) 366766Speter , P2PTR ) 367766Speter , P2FTN ) 36815934Smckusick , P2PTR )) 369766Speter , "_FNIL" ); 37015934Smckusick (void) stklval(file, NOFLAGS); 371766Speter putop( P2CALL 372766Speter , ADDTYPE( p2type( filetype ) , P2PTR ) ); 373766Speter putop( P2UNARY P2MUL , p2type( filetype ) ); 374766Speter /* 375766Speter * file^ := ... 376766Speter */ 377766Speter switch ( classify( filetype ) ) { 378766Speter case TBOOL: 379766Speter case TCHAR: 380766Speter case TINT: 381766Speter case TSCAL: 3824589Speter precheck( filetype , "_RANG4" , "_RSNG4" ); 383766Speter /* and fall through */ 384766Speter case TDOUBLE: 385766Speter case TPTR: 38615934Smckusick ap = rvalue( argv->list_node.list , filetype , RREQ ); 387766Speter break; 388766Speter default: 38915934Smckusick ap = rvalue( argv->list_node.list , filetype , LREQ ); 390766Speter break; 391766Speter } 392766Speter if (ap == NIL) 393766Speter continue; 39415934Smckusick if (incompat(ap, filetype, argv->list_node.list)) { 395766Speter cerror("Type mismatch in write to non-text file"); 396766Speter continue; 397766Speter } 398766Speter switch ( classify( filetype ) ) { 399766Speter case TBOOL: 400766Speter case TCHAR: 401766Speter case TINT: 402766Speter case TSCAL: 40310373Speter postcheck(filetype, ap); 40410373Speter sconv(p2type(ap), p2type(filetype)); 405766Speter /* and fall through */ 406766Speter case TDOUBLE: 407766Speter case TPTR: 408766Speter putop( P2ASSIGN , p2type( filetype ) ); 409766Speter putdot( filename , line ); 410766Speter break; 411766Speter default: 41211856Speter putstrop(P2STASG, 41311856Speter ADDTYPE(p2type(filetype), 41411856Speter P2PTR), 41515934Smckusick (int) lwidth(filetype), 41611856Speter align(filetype)); 417766Speter putdot( filename , line ); 418766Speter break; 419766Speter } 420766Speter /* 421766Speter * put(file) 422766Speter */ 423766Speter putleaf( P2ICON , 0 , 0 424766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 425766Speter , "_PUT" ); 42615934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , 4273833Speter P2PTR|P2STRTY ); 428766Speter putop( P2CALL , P2INT ); 429766Speter putdot( filename , line ); 430766Speter continue; 431766Speter } 432766Speter /* 433766Speter * Write to a textfile 434766Speter * 435766Speter * Evaluate the expression 436766Speter * to be written. 437766Speter */ 438766Speter if (fmt == 'O' || fmt == 'X') { 439766Speter if (opt('s')) { 440766Speter standard(); 441766Speter error("Oct and hex are non-standard"); 442766Speter } 443766Speter if (typ == TSTR || typ == TDOUBLE) { 444766Speter error("Can't write %ss with oct/hex", clnames[typ]); 445766Speter continue; 446766Speter } 447766Speter if (typ == TCHAR || typ == TBOOL) 448766Speter typ = TINT; 449766Speter } 450766Speter /* 451766Speter * If there is no format specified by the programmer, 452766Speter * implement the default. 453766Speter */ 454766Speter switch (typ) { 4556540Smckusick case TPTR: 4566540Smckusick warning(); 4576540Smckusick if (opt('s')) { 4586540Smckusick standard(); 4596540Smckusick } 4606540Smckusick error("Writing %ss to text files is non-standard", 4616540Smckusick clnames[typ]); 4626540Smckusick /* and fall through */ 463766Speter case TINT: 464766Speter if (fmt == 'f') { 465766Speter typ = TDOUBLE; 466766Speter goto tdouble; 467766Speter } 468766Speter if (fmtspec == NIL) { 469766Speter if (fmt == 'D') 470766Speter field = 10; 471766Speter else if (fmt == 'X') 472766Speter field = 8; 473766Speter else if (fmt == 'O') 474766Speter field = 11; 475766Speter else 476766Speter panic("fmt1"); 477766Speter fmtspec = CONWIDTH; 478766Speter } 479766Speter break; 480766Speter case TCHAR: 481766Speter tchar: 482766Speter fmt = 'c'; 483766Speter break; 484766Speter case TSCAL: 4851629Speter warning(); 486766Speter if (opt('s')) { 487766Speter standard(); 488766Speter } 4896540Smckusick error("Writing %ss to text files is non-standard", 4906540Smckusick clnames[typ]); 491766Speter case TBOOL: 492766Speter fmt = 's'; 493766Speter break; 494766Speter case TDOUBLE: 495766Speter tdouble: 496766Speter switch (fmtspec) { 497766Speter case NIL: 49811883Smckusick field = 14 + (5 + EXPOSIZE); 49911883Smckusick prec = field - (5 + EXPOSIZE); 5003225Smckusic fmt = 'e'; 501766Speter fmtspec = CONWIDTH + CONPREC; 502766Speter break; 503766Speter case CONWIDTH: 5049229Smckusick field -= REALSPC; 5059229Smckusick if (field < 1) 506766Speter field = 1; 50711883Smckusick prec = field - (5 + EXPOSIZE); 508766Speter if (prec < 1) 509766Speter prec = 1; 510766Speter fmtspec += CONPREC; 5113225Smckusic fmt = 'e'; 512766Speter break; 513766Speter case VARWIDTH: 514766Speter fmtspec += VARPREC; 5153225Smckusic fmt = 'e'; 516766Speter break; 517766Speter case CONWIDTH + CONPREC: 518766Speter case CONWIDTH + VARPREC: 5199229Smckusick field -= REALSPC; 5209229Smckusick if (field < 1) 521766Speter field = 1; 522766Speter } 523766Speter format[0] = ' '; 5249229Smckusick fmtstart = 1 - REALSPC; 525766Speter break; 526766Speter case TSTR: 52715934Smckusick (void) constval( alv ); 528766Speter switch ( classify( con.ctype ) ) { 529766Speter case TCHAR: 530766Speter typ = TCHAR; 531766Speter goto tchar; 532766Speter case TSTR: 533766Speter strptr = con.cpval; 534766Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 535766Speter strptr = con.cpval; 536766Speter break; 537766Speter default: 538766Speter strnglen = width(ap); 539766Speter break; 540766Speter } 541766Speter fmt = 's'; 542766Speter strfmt = fmtspec; 543766Speter if (fmtspec == NIL) { 544766Speter fmtspec = SKIP; 545766Speter break; 546766Speter } 547766Speter if (fmtspec & CONWIDTH) { 548766Speter if (field <= strnglen) 549766Speter fmtspec = SKIP; 550766Speter else 551766Speter field -= strnglen; 552766Speter } 553766Speter break; 554766Speter default: 555766Speter error("Can't write %ss to a text file", clnames[typ]); 556766Speter continue; 557766Speter } 558766Speter /* 559766Speter * Generate the format string 560766Speter */ 561766Speter switch (fmtspec) { 562766Speter default: 563766Speter panic("fmt2"); 564766Speter case NIL: 565766Speter if (fmt == 'c') { 566766Speter if ( opt( 't' ) ) { 567766Speter putleaf( P2ICON , 0 , 0 568766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 569766Speter , "_WRITEC" ); 57015934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , 5713833Speter NLOCAL , P2PTR|P2STRTY ); 57215934Smckusick (void) stkrval( alv , NLNIL , (long) RREQ ); 573766Speter putop( P2LISTOP , P2INT ); 574766Speter } else { 575766Speter putleaf( P2ICON , 0 , 0 576766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 577766Speter , "_fputc" ); 57815934Smckusick (void) stkrval( alv , NLNIL , 57915934Smckusick (long) RREQ ); 580766Speter } 581766Speter putleaf( P2ICON , 0 , 0 582766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 583766Speter , "_ACTFILE" ); 58415934Smckusick putRV((char *) 0, cbn , CURFILEOFFSET , 5853833Speter NLOCAL , P2PTR|P2STRTY ); 586766Speter putop( P2CALL , P2INT ); 587766Speter putop( P2LISTOP , P2INT ); 588766Speter putop( P2CALL , P2INT ); 589766Speter putdot( filename , line ); 590766Speter } else { 591766Speter sprintf(&format[1], "%%%c", fmt); 592766Speter goto fmtgen; 593766Speter } 594766Speter case SKIP: 595766Speter break; 596766Speter case CONWIDTH: 597766Speter sprintf(&format[1], "%%%1D%c", field, fmt); 598766Speter goto fmtgen; 599766Speter case VARWIDTH: 600766Speter sprintf(&format[1], "%%*%c", fmt); 601766Speter goto fmtgen; 602766Speter case CONWIDTH + CONPREC: 603766Speter sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt); 604766Speter goto fmtgen; 605766Speter case CONWIDTH + VARPREC: 606766Speter sprintf(&format[1], "%%%1D.*%c", field, fmt); 607766Speter goto fmtgen; 608766Speter case VARWIDTH + CONPREC: 609766Speter sprintf(&format[1], "%%*.%1D%c", prec, fmt); 610766Speter goto fmtgen; 611766Speter case VARWIDTH + VARPREC: 612766Speter sprintf(&format[1], "%%*.*%c", fmt); 613766Speter fmtgen: 614766Speter if ( opt( 't' ) ) { 615766Speter putleaf( P2ICON , 0 , 0 616766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 617766Speter , "_WRITEF" ); 61815934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , 6193833Speter NLOCAL , P2PTR|P2STRTY ); 620766Speter putleaf( P2ICON , 0 , 0 621766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 622766Speter , "_ACTFILE" ); 62315934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , 6243833Speter NLOCAL , P2PTR|P2STRTY ); 625766Speter putop( P2CALL , P2INT ); 626766Speter putop( P2LISTOP , P2INT ); 627766Speter } else { 628766Speter putleaf( P2ICON , 0 , 0 629766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 630766Speter , "_fprintf" ); 631766Speter putleaf( P2ICON , 0 , 0 632766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 633766Speter , "_ACTFILE" ); 63415934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , 6353833Speter NLOCAL , P2PTR|P2STRTY ); 636766Speter putop( P2CALL , P2INT ); 637766Speter } 638766Speter putCONG( &format[ fmtstart ] 639766Speter , strlen( &format[ fmtstart ] ) 640766Speter , LREQ ); 641766Speter putop( P2LISTOP , P2INT ); 642766Speter if ( fmtspec & VARWIDTH ) { 643766Speter /* 644766Speter * either 645766Speter * ,(temp=width,MAX(temp,...)), 646766Speter * or 647766Speter * , MAX( width , ... ) , 648766Speter */ 64915934Smckusick if ( ( typ == TDOUBLE && 65015934Smckusick al->wexpr_node.expr3 == TR_NIL ) 651766Speter || typ == TSTR ) { 652*15935Smckusick soffset_flag = TRUE; 6533225Smckusic soffset = sizes[cbn].curtmps; 65415934Smckusick tempnlp = tmpalloc((long) (sizeof(long)), 6553225Smckusic nl+T4INT, REGOK); 65615934Smckusick putRV((char *) 0 , cbn , 6573833Speter tempnlp -> value[ NL_OFFS ] , 6583833Speter tempnlp -> extra_flags , P2INT ); 65915934Smckusick ap = stkrval( al->wexpr_node.expr2 , 66015934Smckusick NLNIL , (long) RREQ ); 661766Speter putop( P2ASSIGN , P2INT ); 662766Speter putleaf( P2ICON , 0 , 0 663766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 664766Speter , "_MAX" ); 66515934Smckusick putRV((char *) 0 , cbn , 6663833Speter tempnlp -> value[ NL_OFFS ] , 6673833Speter tempnlp -> extra_flags , P2INT ); 668766Speter } else { 669766Speter if (opt('t') 670766Speter || typ == TSTR || typ == TDOUBLE) { 671766Speter putleaf( P2ICON , 0 , 0 672766Speter ,ADDTYPE( P2FTN | P2INT, P2PTR ) 673766Speter ,"_MAX" ); 674766Speter } 67515934Smckusick ap = stkrval( al->wexpr_node.expr2, 67615934Smckusick NLNIL , (long) RREQ ); 677766Speter } 67815934Smckusick if (ap == NLNIL) 679766Speter continue; 680766Speter if (isnta(ap,"i")) { 681766Speter error("First write width must be integer, not %s", nameof(ap)); 682766Speter continue; 683766Speter } 684766Speter switch ( typ ) { 685766Speter case TDOUBLE: 68615934Smckusick putleaf( P2ICON , REALSPC , 0 , P2INT , (char *) 0 ); 687766Speter putop( P2LISTOP , P2INT ); 68815934Smckusick putleaf( P2ICON , 1 , 0 , P2INT , (char *) 0 ); 689766Speter putop( P2LISTOP , P2INT ); 690766Speter putop( P2CALL , P2INT ); 69115934Smckusick if ( al->wexpr_node.expr3 == TR_NIL ) { 692766Speter /* 693766Speter * finish up the comma op 694766Speter */ 695766Speter putop( P2COMOP , P2INT ); 696766Speter fmtspec &= ~VARPREC; 697766Speter putop( P2LISTOP , P2INT ); 698766Speter putleaf( P2ICON , 0 , 0 699766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 700766Speter , "_MAX" ); 70115934Smckusick putRV((char *) 0 , cbn , 7023833Speter tempnlp -> value[ NL_OFFS ] , 7033833Speter tempnlp -> extra_flags , 7043833Speter P2INT ); 70511883Smckusick putleaf( P2ICON , 70611883Smckusick 5 + EXPOSIZE + REALSPC , 70715934Smckusick 0 , P2INT , (char *) 0 ); 708766Speter putop( P2LISTOP , P2INT ); 70915934Smckusick putleaf( P2ICON , 1 , 0 , P2INT , (char *) 0 ); 710766Speter putop( P2LISTOP , P2INT ); 711766Speter putop( P2CALL , P2INT ); 712766Speter } 713766Speter putop( P2LISTOP , P2INT ); 714766Speter break; 715766Speter case TSTR: 71615934Smckusick putleaf( P2ICON , strnglen , 0 , P2INT , (char *) 0 ); 717766Speter putop( P2LISTOP , P2INT ); 71815934Smckusick putleaf( P2ICON , 0 , 0 , P2INT , (char *) 0 ); 719766Speter putop( P2LISTOP , P2INT ); 720766Speter putop( P2CALL , P2INT ); 721766Speter putop( P2COMOP , P2INT ); 722766Speter putop( P2LISTOP , P2INT ); 723766Speter break; 724766Speter default: 725766Speter if (opt('t')) { 72615934Smckusick putleaf( P2ICON , 0 , 0 , P2INT , (char *) 0 ); 727766Speter putop( P2LISTOP , P2INT ); 72815934Smckusick putleaf( P2ICON , 0 , 0 , P2INT , (char *) 0 ); 729766Speter putop( P2LISTOP , P2INT ); 730766Speter putop( P2CALL , P2INT ); 731766Speter } 732766Speter putop( P2LISTOP , P2INT ); 733766Speter break; 734766Speter } 735766Speter } 736766Speter /* 737766Speter * If there is a variable precision, 738766Speter * evaluate it 739766Speter */ 740766Speter if (fmtspec & VARPREC) { 741766Speter if (opt('t')) { 742766Speter putleaf( P2ICON , 0 , 0 743766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 744766Speter , "_MAX" ); 745766Speter } 74615934Smckusick ap = stkrval( al->wexpr_node.expr3 , 74715934Smckusick NLNIL , (long) RREQ ); 748766Speter if (ap == NIL) 749766Speter continue; 750766Speter if (isnta(ap,"i")) { 751766Speter error("Second write width must be integer, not %s", nameof(ap)); 752766Speter continue; 753766Speter } 754766Speter if (opt('t')) { 75515934Smckusick putleaf( P2ICON , 0 , 0 , P2INT , (char *) 0 ); 756766Speter putop( P2LISTOP , P2INT ); 75715934Smckusick putleaf( P2ICON , 0 , 0 , P2INT , (char *) 0 ); 758766Speter putop( P2LISTOP , P2INT ); 759766Speter putop( P2CALL , P2INT ); 760766Speter } 761766Speter putop( P2LISTOP , P2INT ); 762766Speter } 763766Speter /* 764766Speter * evaluate the thing we want printed. 765766Speter */ 766766Speter switch ( typ ) { 7676540Smckusick case TPTR: 768766Speter case TCHAR: 769766Speter case TINT: 77015934Smckusick (void) stkrval( alv , NLNIL , (long) RREQ ); 771766Speter putop( P2LISTOP , P2INT ); 772766Speter break; 773766Speter case TDOUBLE: 77415934Smckusick ap = stkrval( alv , NLNIL , (long) RREQ ); 77510373Speter if (isnta(ap, "d")) { 77610373Speter sconv(p2type(ap), P2DOUBLE); 777766Speter } 778766Speter putop( P2LISTOP , P2INT ); 779766Speter break; 780766Speter case TSCAL: 781766Speter case TBOOL: 782766Speter putleaf( P2ICON , 0 , 0 783766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 784766Speter , "_NAM" ); 78515934Smckusick ap = stkrval( alv , NLNIL , (long) RREQ ); 786766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 787766Speter , listnames( ap ) ); 78815934Smckusick putleaf( P2ICON , 0 , 0 , 78915934Smckusick (int) (P2PTR | P2CHAR), format ); 790766Speter putop( P2LISTOP , P2INT ); 791766Speter putop( P2CALL , P2INT ); 792766Speter putop( P2LISTOP , P2INT ); 793766Speter break; 794766Speter case TSTR: 795766Speter putCONG( "" , 0 , LREQ ); 796766Speter putop( P2LISTOP , P2INT ); 797766Speter break; 7986540Smckusick default: 7996540Smckusick panic("fmt3"); 8006540Smckusick break; 801766Speter } 802766Speter putop( P2CALL , P2INT ); 803766Speter putdot( filename , line ); 804766Speter } 805766Speter /* 806766Speter * Write the string after its blank padding 807766Speter */ 808766Speter if (typ == TSTR ) { 809766Speter if ( opt( 't' ) ) { 810766Speter putleaf( P2ICON , 0 , 0 811766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 812766Speter , "_WRITES" ); 81315934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , 8143833Speter NLOCAL , P2PTR|P2STRTY ); 81515934Smckusick ap = stkrval(alv, NLNIL , (long) RREQ ); 816766Speter putop( P2LISTOP , P2INT ); 817766Speter } else { 818766Speter putleaf( P2ICON , 0 , 0 819766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 820766Speter , "_fwrite" ); 82115934Smckusick ap = stkrval(alv, NLNIL , (long) RREQ ); 822766Speter } 823766Speter if (strfmt & VARWIDTH) { 824766Speter /* 825766Speter * min, inline expanded as 826766Speter * temp < len ? temp : len 827766Speter */ 82815934Smckusick putRV((char *) 0 , cbn , 8293833Speter tempnlp -> value[ NL_OFFS ] , 8303833Speter tempnlp -> extra_flags , P2INT ); 83115934Smckusick putleaf( P2ICON , strnglen , 0 , P2INT , (char *) 0 ); 832766Speter putop( P2LT , P2INT ); 83315934Smckusick putRV((char *) 0 , cbn , 8343833Speter tempnlp -> value[ NL_OFFS ] , 8353833Speter tempnlp -> extra_flags , P2INT ); 83615934Smckusick putleaf( P2ICON , strnglen , 0 , P2INT , (char *) 0 ); 837766Speter putop( P2COLON , P2INT ); 838766Speter putop( P2QUEST , P2INT ); 839766Speter } else { 840766Speter if ( ( fmtspec & SKIP ) 841766Speter && ( strfmt & CONWIDTH ) ) { 842766Speter strnglen = field; 843766Speter } 84415934Smckusick putleaf( P2ICON , strnglen , 0 , P2INT , (char *) 0 ); 845766Speter } 846766Speter putop( P2LISTOP , P2INT ); 84715934Smckusick putleaf( P2ICON , 1 , 0 , P2INT , (char *) 0 ); 848766Speter putop( P2LISTOP , P2INT ); 849766Speter putleaf( P2ICON , 0 , 0 850766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 851766Speter , "_ACTFILE" ); 85215934Smckusick putRV((char *) 0, cbn , CURFILEOFFSET , NLOCAL , 8533833Speter P2PTR|P2STRTY ); 854766Speter putop( P2CALL , P2INT ); 855766Speter putop( P2LISTOP , P2INT ); 856766Speter putop( P2CALL , P2INT ); 857766Speter putdot( filename , line ); 858766Speter } 859*15935Smckusick if (soffset_flag) { 860*15935Smckusick tmpfree(&soffset); 861*15935Smckusick soffset_flag = FALSE; 862*15935Smckusick } 863766Speter } 864766Speter /* 865766Speter * Done with arguments. 866766Speter * Handle writeln and 867766Speter * insufficent number of args. 868766Speter */ 869766Speter switch (p->value[0] &~ NSTAND) { 870766Speter case O_WRITEF: 871766Speter if (argc == 0) 872766Speter error("Write requires an argument"); 873766Speter break; 874766Speter case O_MESSAGE: 875766Speter if (argc == 0) 876766Speter error("Message requires an argument"); 877766Speter case O_WRITLN: 878766Speter if (filetype != nl+T1CHAR) 879766Speter error("Can't 'writeln' a non text file"); 880766Speter if ( opt( 't' ) ) { 881766Speter putleaf( P2ICON , 0 , 0 882766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 883766Speter , "_WRITLN" ); 88415934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , 8853833Speter NLOCAL , P2PTR|P2STRTY ); 886766Speter } else { 887766Speter putleaf( P2ICON , 0 , 0 888766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 889766Speter , "_fputc" ); 89015934Smckusick putleaf( P2ICON , '\n' , 0 , (int) P2CHAR , (char *) 0 ); 891766Speter putleaf( P2ICON , 0 , 0 892766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 893766Speter , "_ACTFILE" ); 89415934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , 8953833Speter NLOCAL , P2PTR|P2STRTY ); 896766Speter putop( P2CALL , P2INT ); 897766Speter putop( P2LISTOP , P2INT ); 898766Speter } 899766Speter putop( P2CALL , P2INT ); 900766Speter putdot( filename , line ); 901766Speter break; 902766Speter } 903766Speter return; 904766Speter 905766Speter case O_READ4: 906766Speter case O_READLN: 907766Speter /* 908766Speter * Set up default 909766Speter * file "input". 910766Speter */ 911766Speter file = NIL; 912766Speter filetype = nl+T1CHAR; 913766Speter /* 914766Speter * Determine the file implied 915766Speter * for the read and generate 916766Speter * code to make it the active file. 917766Speter */ 91815934Smckusick if (argv != TR_NIL) { 919766Speter codeoff(); 92015934Smckusick ap = stkrval(argv->list_node.list, NLNIL, (long) RREQ ); 921766Speter codeon(); 92215934Smckusick if (ap == NLNIL) 92315934Smckusick argv = argv->list_node.next; 92415934Smckusick if (ap != NLNIL && ap->class == FILET) { 925766Speter /* 926766Speter * Got "read(f, ...", make 927766Speter * f the active file, and save 928766Speter * it and its type for use in 929766Speter * processing the rest of the 930766Speter * arguments to read. 931766Speter */ 93215934Smckusick file = argv->list_node.list; 933766Speter filetype = ap->type; 93415934Smckusick putRV((char *) 0, cbn , CURFILEOFFSET , NLOCAL , 9353833Speter P2PTR|P2STRTY ); 936766Speter putleaf( P2ICON , 0 , 0 937766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 938766Speter , "_UNIT" ); 93915934Smckusick (void) stklval(argv->list_node.list, NOFLAGS); 940766Speter putop( P2CALL , P2INT ); 941766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 942766Speter putdot( filename , line ); 94315934Smckusick argv = argv->list_node.next; 944766Speter argc--; 945766Speter } else { 946766Speter /* 947766Speter * Default is read from 948766Speter * standard input. 949766Speter */ 95015934Smckusick putRV((char *) 0, cbn , CURFILEOFFSET , NLOCAL , 9513833Speter P2PTR|P2STRTY ); 9523833Speter putLV( "_input" , 0 , 0 , NGLOBAL , 9533833Speter P2PTR|P2STRTY ); 954766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 955766Speter putdot( filename , line ); 956766Speter input->nl_flags |= NUSED; 957766Speter } 958766Speter } else { 95915934Smckusick putRV((char *) 0, cbn , CURFILEOFFSET , NLOCAL , 9603833Speter P2PTR|P2STRTY ); 9613833Speter putLV( "_input" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 962766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 963766Speter putdot( filename , line ); 964766Speter input->nl_flags |= NUSED; 965766Speter } 966766Speter /* 967766Speter * Loop and process each 968766Speter * of the arguments. 969766Speter */ 97015934Smckusick for (; argv != TR_NIL; argv = argv->list_node.next) { 971766Speter /* 972766Speter * Get the address of the target 973766Speter * on the stack. 974766Speter */ 97515934Smckusick al = argv->list_node.list; 97615934Smckusick if (al == TR_NIL) 977766Speter continue; 97815934Smckusick if (al->tag != T_VAR) { 979766Speter error("Arguments to %s must be variables, not expressions", p->symbol); 980766Speter continue; 981766Speter } 982766Speter codeoff(); 983766Speter ap = stklval(al, MOD|ASGN|NOUSE); 984766Speter codeon(); 98515934Smckusick if (ap == NLNIL) 986766Speter continue; 987766Speter if (filetype != nl+T1CHAR) { 988766Speter /* 989766Speter * Generalized read, i.e. 990766Speter * from a non-textfile. 991766Speter */ 99215934Smckusick if (incompat(filetype, ap, argv->list_node.list )) { 993766Speter error("Type mismatch in read from non-text file"); 994766Speter continue; 995766Speter } 996766Speter /* 997766Speter * var := file ^; 998766Speter */ 999766Speter ap = lvalue( al , MOD | ASGN | NOUSE , RREQ ); 1000766Speter if ( isa( ap , "bsci" ) ) { 1001766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 1002766Speter } 1003766Speter putleaf( P2ICON , 0 , 0 100415934Smckusick , (int) (ADDTYPE( 1005766Speter ADDTYPE( 1006766Speter ADDTYPE( 1007766Speter p2type( filetype ) , P2PTR ) 1008766Speter , P2FTN ) 100915934Smckusick , P2PTR )) 1010766Speter , "_FNIL" ); 1011766Speter if (file != NIL) 101215934Smckusick (void) stklval(file, NOFLAGS); 1013766Speter else /* Magic */ 10143833Speter putRV( "_input" , 0 , 0 , NGLOBAL , 10153833Speter P2PTR | P2STRTY ); 101610668Speter putop(P2CALL, ADDTYPE(p2type(filetype), P2PTR)); 1017766Speter switch ( classify( filetype ) ) { 1018766Speter case TBOOL: 1019766Speter case TCHAR: 1020766Speter case TINT: 1021766Speter case TSCAL: 1022766Speter case TDOUBLE: 1023766Speter case TPTR: 1024766Speter putop( P2UNARY P2MUL 1025766Speter , p2type( filetype ) ); 1026766Speter } 1027766Speter switch ( classify( filetype ) ) { 1028766Speter case TBOOL: 1029766Speter case TCHAR: 1030766Speter case TINT: 1031766Speter case TSCAL: 103210373Speter postcheck(ap, filetype); 103310373Speter sconv(p2type(filetype), p2type(ap)); 1034766Speter /* and fall through */ 1035766Speter case TDOUBLE: 1036766Speter case TPTR: 1037766Speter putop( P2ASSIGN , p2type( ap ) ); 1038766Speter putdot( filename , line ); 1039766Speter break; 1040766Speter default: 104111856Speter putstrop(P2STASG, 104211856Speter ADDTYPE(p2type(ap), P2PTR), 104315934Smckusick (int) lwidth(ap), 104411856Speter align(ap)); 1045766Speter putdot( filename , line ); 1046766Speter break; 1047766Speter } 1048766Speter /* 1049766Speter * get(file); 1050766Speter */ 1051766Speter putleaf( P2ICON , 0 , 0 1052766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1053766Speter , "_GET" ); 105415934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , 10553833Speter P2PTR|P2STRTY ); 1056766Speter putop( P2CALL , P2INT ); 1057766Speter putdot( filename , line ); 1058766Speter continue; 1059766Speter } 1060766Speter /* 1061766Speter * if you get to here, you are reading from 1062766Speter * a text file. only possiblities are: 1063766Speter * character, integer, real, or scalar. 1064766Speter * read( f , foo , ... ) is done as 1065766Speter * foo := read( f ) with rangechecking 1066766Speter * if appropriate. 1067766Speter */ 1068766Speter typ = classify(ap); 1069766Speter op = rdops(typ); 1070766Speter if (op == NIL) { 1071766Speter error("Can't read %ss from a text file", clnames[typ]); 1072766Speter continue; 1073766Speter } 1074766Speter /* 1075766Speter * left hand side of foo := read( f ) 1076766Speter */ 1077766Speter ap = lvalue( al , MOD|ASGN|NOUSE , RREQ ); 1078766Speter if ( isa( ap , "bsci" ) ) { 1079766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 1080766Speter } 1081766Speter switch ( op ) { 1082766Speter case O_READC: 1083766Speter readname = "_READC"; 1084766Speter readtype = P2INT; 1085766Speter break; 1086766Speter case O_READ4: 1087766Speter readname = "_READ4"; 1088766Speter readtype = P2INT; 1089766Speter break; 1090766Speter case O_READ8: 1091766Speter readname = "_READ8"; 1092766Speter readtype = P2DOUBLE; 1093766Speter break; 1094766Speter case O_READE: 1095766Speter readname = "_READE"; 1096766Speter readtype = P2INT; 1097766Speter break; 1098766Speter } 1099766Speter putleaf( P2ICON , 0 , 0 110015934Smckusick , (int) ADDTYPE( P2FTN | readtype , P2PTR ) 1101766Speter , readname ); 110215934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , 11033833Speter P2PTR|P2STRTY ); 1104766Speter if ( op == O_READE ) { 1105766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 1106766Speter , listnames( ap ) ); 110715934Smckusick putleaf( P2ICON , 0, 0, (int) (P2PTR | P2CHAR), 110815934Smckusick format ); 1109766Speter putop( P2LISTOP , P2INT ); 11101629Speter warning(); 1111766Speter if (opt('s')) { 1112766Speter standard(); 1113766Speter } 11141629Speter error("Reading scalars from text files is non-standard"); 1115766Speter } 111615934Smckusick putop( P2CALL , (int) readtype ); 1117766Speter if ( isa( ap , "bcsi" ) ) { 111810373Speter postcheck(ap, readtype==P2INT?nl+T4INT:nl+TDOUBLE); 1119766Speter } 112015934Smckusick sconv((int) readtype, p2type(ap)); 1121766Speter putop( P2ASSIGN , p2type( ap ) ); 1122766Speter putdot( filename , line ); 1123766Speter } 1124766Speter /* 1125766Speter * Done with arguments. 1126766Speter * Handle readln and 1127766Speter * insufficient number of args. 1128766Speter */ 1129766Speter if (p->value[0] == O_READLN) { 1130766Speter if (filetype != nl+T1CHAR) 1131766Speter error("Can't 'readln' a non text file"); 1132766Speter putleaf( P2ICON , 0 , 0 113315934Smckusick , (int) ADDTYPE( P2FTN | P2INT , P2PTR ) 1134766Speter , "_READLN" ); 113515934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , 11363833Speter P2PTR|P2STRTY ); 1137766Speter putop( P2CALL , P2INT ); 1138766Speter putdot( filename , line ); 1139766Speter } else if (argc == 0) 1140766Speter error("read requires an argument"); 1141766Speter return; 1142766Speter 1143766Speter case O_GET: 1144766Speter case O_PUT: 1145766Speter if (argc != 1) { 1146766Speter error("%s expects one argument", p->symbol); 1147766Speter return; 1148766Speter } 114915934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1150766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1151766Speter , "_UNIT" ); 115215934Smckusick ap = stklval(argv->list_node.list, NOFLAGS); 115315934Smckusick if (ap == NLNIL) 1154766Speter return; 1155766Speter if (ap->class != FILET) { 1156766Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1157766Speter return; 1158766Speter } 1159766Speter putop( P2CALL , P2INT ); 1160766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1161766Speter putdot( filename , line ); 1162766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1163766Speter , op == O_GET ? "_GET" : "_PUT" ); 116415934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1165766Speter putop( P2CALL , P2INT ); 1166766Speter putdot( filename , line ); 1167766Speter return; 1168766Speter 1169766Speter case O_RESET: 1170766Speter case O_REWRITE: 1171766Speter if (argc == 0 || argc > 2) { 1172766Speter error("%s expects one or two arguments", p->symbol); 1173766Speter return; 1174766Speter } 1175766Speter if (opt('s') && argc == 2) { 1176766Speter standard(); 1177766Speter error("Two argument forms of reset and rewrite are non-standard"); 1178766Speter } 1179766Speter putleaf( P2ICON , 0 , 0 , P2INT 1180766Speter , op == O_RESET ? "_RESET" : "_REWRITE" ); 118115934Smckusick ap = stklval(argv->list_node.list, MOD|NOUSE); 118215934Smckusick if (ap == NLNIL) 1183766Speter return; 1184766Speter if (ap->class != FILET) { 1185766Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1186766Speter return; 1187766Speter } 1188766Speter if (argc == 2) { 1189766Speter /* 1190766Speter * Optional second argument 1191766Speter * is a string name of a 1192766Speter * UNIX (R) file to be associated. 1193766Speter */ 119415934Smckusick al = argv->list_node.next; 119515934Smckusick al = (struct tnode *) stkrval(al->list_node.list, 119615934Smckusick NLNIL , (long) RREQ ); 119715934Smckusick if (al == TR_NIL) 1198766Speter return; 119915934Smckusick if (classify((struct nl *) al) != TSTR) { 120015934Smckusick error("Second argument to %s must be a string, not %s", p->symbol, nameof((struct nl *) al)); 1201766Speter return; 1202766Speter } 120315934Smckusick strnglen = width((struct nl *) al); 1204766Speter } else { 120515934Smckusick putleaf( P2ICON , 0 , 0 , P2INT , (char *) 0 ); 1206766Speter strnglen = 0; 1207766Speter } 1208766Speter putop( P2LISTOP , P2INT ); 120915934Smckusick putleaf( P2ICON , strnglen , 0 , P2INT , (char *) 0 ); 1210766Speter putop( P2LISTOP , P2INT ); 121115934Smckusick putleaf( P2ICON , text(ap) ? 0: width(ap->type) , 0 , P2INT , (char *) 0 ); 1212766Speter putop( P2LISTOP , P2INT ); 1213766Speter putop( P2CALL , P2INT ); 1214766Speter putdot( filename , line ); 1215766Speter return; 1216766Speter 1217766Speter case O_NEW: 1218766Speter case O_DISPOSE: 1219766Speter if (argc == 0) { 1220766Speter error("%s expects at least one argument", p->symbol); 1221766Speter return; 1222766Speter } 122315934Smckusick alv = argv->list_node.list; 12247967Smckusick codeoff(); 12259139Smckusick ap = stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD ); 12267967Smckusick codeon(); 122715934Smckusick if (ap == NLNIL) 1228766Speter return; 1229766Speter if (ap->class != PTR) { 1230766Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 1231766Speter return; 1232766Speter } 1233766Speter ap = ap->type; 123415934Smckusick if (ap == NLNIL) 1235766Speter return; 12369139Smckusick if (op == O_NEW) 12379139Smckusick cmd = "_NEW"; 12389139Smckusick else /* op == O_DISPOSE */ 12397967Smckusick if ((ap->nl_flags & NFILES) != 0) 12407967Smckusick cmd = "_DFDISPOSE"; 12417967Smckusick else 12427967Smckusick cmd = "_DISPOSE"; 12437967Smckusick putleaf( P2ICON, 0, 0, ADDTYPE( P2FTN | P2INT , P2PTR ), cmd); 124415934Smckusick (void) stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD ); 124515934Smckusick argv = argv->list_node.next; 124615934Smckusick if (argv != TR_NIL) { 1247766Speter if (ap->class != RECORD) { 1248766Speter error("Record required when specifying variant tags"); 1249766Speter return; 1250766Speter } 125115934Smckusick for (; argv != TR_NIL; argv = argv->list_node.next) { 1252766Speter if (ap->ptr[NL_VARNT] == NIL) { 1253766Speter error("Too many tag fields"); 1254766Speter return; 1255766Speter } 125615934Smckusick if (!isconst(argv->list_node.list)) { 1257766Speter error("Second and successive arguments to %s must be constants", p->symbol); 1258766Speter return; 1259766Speter } 126015934Smckusick gconst(argv->list_node.list); 1261766Speter if (con.ctype == NIL) 1262766Speter return; 126315934Smckusick if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , TR_NIL )) { 1264766Speter cerror("Specified tag constant type clashed with variant case selector type"); 1265766Speter return; 1266766Speter } 1267766Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 1268766Speter if (ap->range[0] == con.crval) 1269766Speter break; 1270766Speter if (ap == NIL) { 1271766Speter error("No variant case label value equals specified constant value"); 1272766Speter return; 1273766Speter } 1274766Speter ap = ap->ptr[NL_VTOREC]; 1275766Speter } 1276766Speter } 127715934Smckusick putleaf( P2ICON , width( ap ) , 0 , P2INT , (char *) 0 ); 1278766Speter putop( P2LISTOP , P2INT ); 1279766Speter putop( P2CALL , P2INT ); 1280766Speter putdot( filename , line ); 12819139Smckusick if (opt('t') && op == O_NEW) { 12829139Smckusick putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 12839139Smckusick , "_blkclr" ); 128415934Smckusick (void) stkrval(alv, NLNIL , (long) RREQ ); 128515934Smckusick putleaf( P2ICON , width( ap ) , 0 , P2INT , (char *) 0 ); 12869139Smckusick putop( P2LISTOP , P2INT ); 12879139Smckusick putop( P2CALL , P2INT ); 12889139Smckusick putdot( filename , line ); 12899139Smckusick } 1290766Speter return; 1291766Speter 1292766Speter case O_DATE: 1293766Speter case O_TIME: 1294766Speter if (argc != 1) { 1295766Speter error("%s expects one argument", p->symbol); 1296766Speter return; 1297766Speter } 1298766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1299766Speter , op == O_DATE ? "_DATE" : "_TIME" ); 130015934Smckusick ap = stklval(argv->list_node.list, MOD|NOUSE); 1301766Speter if (ap == NIL) 1302766Speter return; 1303766Speter if (classify(ap) != TSTR || width(ap) != 10) { 1304766Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 1305766Speter return; 1306766Speter } 1307766Speter putop( P2CALL , P2INT ); 1308766Speter putdot( filename , line ); 1309766Speter return; 1310766Speter 1311766Speter case O_HALT: 1312766Speter if (argc != 0) { 1313766Speter error("halt takes no arguments"); 1314766Speter return; 1315766Speter } 1316766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1317766Speter , "_HALT" ); 1318766Speter 1319766Speter putop( P2UNARY P2CALL , P2INT ); 1320766Speter putdot( filename , line ); 132115934Smckusick noreach = TRUE; 1322766Speter return; 1323766Speter 1324766Speter case O_ARGV: 1325766Speter if (argc != 2) { 1326766Speter error("argv takes two arguments"); 1327766Speter return; 1328766Speter } 1329766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1330766Speter , "_ARGV" ); 133115934Smckusick ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ ); 133215934Smckusick if (ap == NLNIL) 1333766Speter return; 1334766Speter if (isnta(ap, "i")) { 1335766Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 1336766Speter return; 1337766Speter } 133815934Smckusick al = argv->list_node.next; 133915934Smckusick ap = stklval(al->list_node.list, MOD|NOUSE); 134015934Smckusick if (ap == NLNIL) 1341766Speter return; 1342766Speter if (classify(ap) != TSTR) { 1343766Speter error("argv's second argument must be a string, not %s", nameof(ap)); 1344766Speter return; 1345766Speter } 1346766Speter putop( P2LISTOP , P2INT ); 134715934Smckusick putleaf( P2ICON , width( ap ) , 0 , P2INT , (char *) 0 ); 1348766Speter putop( P2LISTOP , P2INT ); 1349766Speter putop( P2CALL , P2INT ); 1350766Speter putdot( filename , line ); 1351766Speter return; 1352766Speter 1353766Speter case O_STLIM: 1354766Speter if (argc != 1) { 1355766Speter error("stlimit requires one argument"); 1356766Speter return; 1357766Speter } 1358766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1359766Speter , "_STLIM" ); 136015934Smckusick ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ ); 136115934Smckusick if (ap == NLNIL) 1362766Speter return; 1363766Speter if (isnta(ap, "i")) { 1364766Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 1365766Speter return; 1366766Speter } 1367766Speter putop( P2CALL , P2INT ); 1368766Speter putdot( filename , line ); 1369766Speter return; 1370766Speter 1371766Speter case O_REMOVE: 1372766Speter if (argc != 1) { 1373766Speter error("remove expects one argument"); 1374766Speter return; 1375766Speter } 1376766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1377766Speter , "_REMOVE" ); 137815934Smckusick ap = stkrval(argv->list_node.list, NLNIL, (long) RREQ ); 137915934Smckusick if (ap == NLNIL) 1380766Speter return; 1381766Speter if (classify(ap) != TSTR) { 1382766Speter error("remove's argument must be a string, not %s", nameof(ap)); 1383766Speter return; 1384766Speter } 138515934Smckusick putleaf( P2ICON , width( ap ) , 0 , P2INT , (char *) 0 ); 1386766Speter putop( P2LISTOP , P2INT ); 1387766Speter putop( P2CALL , P2INT ); 1388766Speter putdot( filename , line ); 1389766Speter return; 1390766Speter 1391766Speter case O_LLIMIT: 1392766Speter if (argc != 2) { 1393766Speter error("linelimit expects two arguments"); 1394766Speter return; 1395766Speter } 1396766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1397766Speter , "_LLIMIT" ); 139815934Smckusick ap = stklval(argv->list_node.list, NOFLAGS|NOUSE); 139915934Smckusick if (ap == NLNIL) 1400766Speter return; 1401766Speter if (!text(ap)) { 1402766Speter error("linelimit's first argument must be a text file, not %s", nameof(ap)); 1403766Speter return; 1404766Speter } 140515934Smckusick al = argv->list_node.next; 140615934Smckusick ap = stkrval(al->list_node.list, NLNIL , (long) RREQ ); 140715934Smckusick if (ap == NLNIL) 1408766Speter return; 1409766Speter if (isnta(ap, "i")) { 1410766Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 1411766Speter return; 1412766Speter } 1413766Speter putop( P2LISTOP , P2INT ); 1414766Speter putop( P2CALL , P2INT ); 1415766Speter putdot( filename , line ); 1416766Speter return; 1417766Speter case O_PAGE: 1418766Speter if (argc != 1) { 1419766Speter error("page expects one argument"); 1420766Speter return; 1421766Speter } 142215934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1423766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1424766Speter , "_UNIT" ); 142515934Smckusick ap = stklval(argv->list_node.list, NOFLAGS); 142615934Smckusick if (ap == NLNIL) 1427766Speter return; 1428766Speter if (!text(ap)) { 1429766Speter error("Argument to page must be a text file, not %s", nameof(ap)); 1430766Speter return; 1431766Speter } 1432766Speter putop( P2CALL , P2INT ); 1433766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1434766Speter putdot( filename , line ); 1435766Speter if ( opt( 't' ) ) { 1436766Speter putleaf( P2ICON , 0 , 0 1437766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1438766Speter , "_PAGE" ); 143915934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1440766Speter } else { 1441766Speter putleaf( P2ICON , 0 , 0 1442766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1443766Speter , "_fputc" ); 144415934Smckusick putleaf( P2ICON , '\f' , 0 , (int) P2CHAR , (char *) 0 ); 1445766Speter putleaf( P2ICON , 0 , 0 1446766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1447766Speter , "_ACTFILE" ); 144815934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1449766Speter putop( P2CALL , P2INT ); 1450766Speter putop( P2LISTOP , P2INT ); 1451766Speter } 1452766Speter putop( P2CALL , P2INT ); 1453766Speter putdot( filename , line ); 1454766Speter return; 1455766Speter 14567928Smckusick case O_ASRT: 14577928Smckusick if (!opt('t')) 14587928Smckusick return; 14597928Smckusick if (argc == 0 || argc > 2) { 14607928Smckusick error("Assert expects one or two arguments"); 14617928Smckusick return; 14627928Smckusick } 14639139Smckusick if (argc == 2) 14649139Smckusick cmd = "_ASRTS"; 14659139Smckusick else 14669139Smckusick cmd = "_ASRT"; 14677928Smckusick putleaf( P2ICON , 0 , 0 14689139Smckusick , ADDTYPE( P2FTN | P2INT , P2PTR ) , cmd ); 146915934Smckusick ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ ); 147015934Smckusick if (ap == NLNIL) 14717928Smckusick return; 14727928Smckusick if (isnta(ap, "b")) 14737928Smckusick error("Assert expression must be Boolean, not %ss", nameof(ap)); 14747928Smckusick if (argc == 2) { 14757928Smckusick /* 14767928Smckusick * Optional second argument is a string specifying 14777928Smckusick * why the assertion failed. 14787928Smckusick */ 147915934Smckusick al = argv->list_node.next; 148015934Smckusick al = (struct tnode *) stkrval(al->list_node.list, NLNIL , (long) RREQ ); 148115934Smckusick if (al == TR_NIL) 14827928Smckusick return; 148315934Smckusick if (classify((struct nl *) al) != TSTR) { 148415934Smckusick error("Second argument to assert must be a string, not %s", nameof((struct nl *) al)); 14857928Smckusick return; 14867928Smckusick } 14879139Smckusick putop( P2LISTOP , P2INT ); 14887928Smckusick } 14897928Smckusick putop( P2CALL , P2INT ); 14907928Smckusick putdot( filename , line ); 14917928Smckusick return; 14927928Smckusick 1493766Speter case O_PACK: 1494766Speter if (argc != 3) { 1495766Speter error("pack expects three arguments"); 1496766Speter return; 1497766Speter } 1498766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1499766Speter , "_PACK" ); 1500766Speter pu = "pack(a,i,z)"; 150115934Smckusick pua = (al = argv)->list_node.list; 150215934Smckusick pui = (al = al->list_node.next)->list_node.list; 150315934Smckusick puz = (al = al->list_node.next)->list_node.list; 1504766Speter goto packunp; 1505766Speter case O_UNPACK: 1506766Speter if (argc != 3) { 1507766Speter error("unpack expects three arguments"); 1508766Speter return; 1509766Speter } 1510766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1511766Speter , "_UNPACK" ); 1512766Speter pu = "unpack(z,a,i)"; 151315934Smckusick puz = (al = argv)->list_node.list; 151415934Smckusick pua = (al = al->list_node.next)->list_node.list; 151515934Smckusick pui = (al = al->list_node.next)->list_node.list; 1516766Speter packunp: 151715934Smckusick ap = stkrval(pui, NLNIL , (long) RREQ ); 1518766Speter if (ap == NIL) 1519766Speter return; 1520766Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 1521766Speter if (ap == NIL) 1522766Speter return; 1523766Speter if (ap->class != ARRAY) { 1524766Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 1525766Speter return; 1526766Speter } 1527766Speter putop( P2LISTOP , P2INT ); 152815934Smckusick al = (struct tnode *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 152915934Smckusick if (((struct nl *) al)->class != ARRAY) { 1530766Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 1531766Speter return; 1532766Speter } 153315934Smckusick if (((struct nl *) al)->type == NIL || 153415934Smckusick ((struct nl *) ap)->type == NIL) 1535766Speter return; 153615934Smckusick if (((struct nl *) al)->type != ((struct nl *) ap)->type) { 1537766Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 1538766Speter return; 1539766Speter } 1540766Speter putop( P2LISTOP , P2INT ); 154115934Smckusick k = width((struct nl *) al); 1542766Speter itemwidth = width(ap->type); 1543766Speter ap = ap->chain; 154415934Smckusick al = ((struct tnode *) ((struct nl *) al)->chain); 154515934Smckusick if (ap->chain != NIL || ((struct nl *) al)->chain != NIL) { 1546766Speter error("%s requires a and z to be single dimension arrays", pu); 1547766Speter return; 1548766Speter } 1549766Speter if (ap == NIL || al == NIL) 1550766Speter return; 1551766Speter /* 1552766Speter * al is the range for z i.e. u..v 1553766Speter * ap is the range for a i.e. m..n 1554766Speter * i will be n-m+1 1555766Speter * j will be v-u+1 1556766Speter */ 1557766Speter i = ap->range[1] - ap->range[0] + 1; 155815934Smckusick j = ((struct nl *) al)->range[1] - 155915934Smckusick ((struct nl *) al)->range[0] + 1; 1560766Speter if (i < j) { 156115934Smckusick error("%s cannot have more elements in a (%d) than in z (%d)", pu, (char *) j, (char *) i); 1562766Speter return; 1563766Speter } 1564766Speter /* 1565766Speter * get n-m-(v-u) and m for the interpreter 1566766Speter */ 1567766Speter i -= j; 1568766Speter j = ap->range[0]; 156915934Smckusick putleaf( P2ICON , itemwidth , 0 , P2INT , (char *) 0 ); 1570766Speter putop( P2LISTOP , P2INT ); 157115934Smckusick putleaf( P2ICON , j , 0 , P2INT , (char *) 0 ); 1572766Speter putop( P2LISTOP , P2INT ); 157315934Smckusick putleaf( P2ICON , i , 0 , P2INT , (char *) 0 ); 1574766Speter putop( P2LISTOP , P2INT ); 157515934Smckusick putleaf( P2ICON , k , 0 , P2INT , (char *) 0 ); 1576766Speter putop( P2LISTOP , P2INT ); 1577766Speter putop( P2CALL , P2INT ); 1578766Speter putdot( filename , line ); 1579766Speter return; 1580766Speter case 0: 15817928Smckusick error("%s is an unimplemented extension", p->symbol); 1582766Speter return; 1583766Speter 1584766Speter default: 1585766Speter panic("proc case"); 1586766Speter } 1587766Speter } 1588766Speter #endif PC 1589