1766Speter /* Copyright (c) 1979 Regents of the University of California */ 2766Speter 3*15934Smckusick #ifndef lint 4*15934Smckusick static char sccsid[] = "@(#)pcproc.c 1.21.1.1 02/04/84"; 5*15934Smckusick #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" 19*15934Smckusick #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) 63*15934Smckusick struct tnode *r; /* T_PCALL */ 64766Speter { 65766Speter register struct nl *p; 66*15934Smckusick register struct tnode *alv, *al; 67*15934Smckusick register op; 68766Speter struct nl *filetype, *ap; 69*15934Smckusick int argc, typ, fmtspec, strfmt; 70*15934Smckusick struct tnode *argv, *file; 717967Smckusick char fmt, format[20], *strptr, *cmd; 72*15934Smckusick int prec, field, strnglen, fmtstart; 73*15934Smckusick char *pu; 74*15934Smckusick 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; 81766Speter 82766Speter #define CONPREC 4 83766Speter #define VARPREC 8 84766Speter #define CONWIDTH 1 85766Speter #define VARWIDTH 2 86766Speter #define SKIP 16 87766Speter 88766Speter /* 89766Speter * Verify that the name is 90766Speter * defined and is that of a 91766Speter * procedure. 92766Speter */ 93*15934Smckusick p = lookup(r->pcall_node.proc_id); 94*15934Smckusick if (p == NLNIL) { 95*15934Smckusick rvlist(r->pcall_node.arg); 96766Speter return; 97766Speter } 981197Speter if (p->class != PROC && p->class != FPROC) { 99766Speter error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]); 100*15934Smckusick rvlist(r->pcall_node.arg); 101766Speter return; 102766Speter } 103*15934Smckusick argv = r->pcall_node.arg; 104766Speter 105766Speter /* 106766Speter * Call handles user defined 107766Speter * procedures and functions. 108766Speter */ 109766Speter if (bn != 0) { 110*15934Smckusick (void) call(p, argv, PROC, bn); 111766Speter return; 112766Speter } 113766Speter 114766Speter /* 115766Speter * Call to built-in procedure. 116766Speter * Count the arguments. 117766Speter */ 118766Speter argc = 0; 119*15934Smckusick for (al = argv; al != TR_NIL; al = al->list_node.next) 120766Speter argc++; 121766Speter 122766Speter /* 123766Speter * Switch on the operator 124766Speter * associated with the built-in 125766Speter * procedure in the namelist 126766Speter */ 127766Speter op = p->value[0] &~ NSTAND; 128766Speter if (opt('s') && (p->value[0] & NSTAND)) { 129766Speter standard(); 130766Speter error("%s is a nonstandard procedure", p->symbol); 131766Speter } 132766Speter switch (op) { 133766Speter 134766Speter case O_ABORT: 135766Speter if (argc != 0) 136766Speter error("null takes no arguments"); 137766Speter return; 138766Speter 139766Speter case O_FLUSH: 140766Speter if (argc == 0) { 141766Speter putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" ); 142766Speter putop( P2UNARY P2CALL , P2INT ); 143766Speter putdot( filename , line ); 144766Speter return; 145766Speter } 146766Speter if (argc != 1) { 147766Speter error("flush takes at most one argument"); 148766Speter return; 149766Speter } 150766Speter putleaf( P2ICON , 0 , 0 151766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 152766Speter , "_FLUSH" ); 153*15934Smckusick ap = stklval(argv->list_node.list, NOFLAGS); 154*15934Smckusick if (ap == NLNIL) 155766Speter return; 156766Speter if (ap->class != FILET) { 157766Speter error("flush's argument must be a file, not %s", nameof(ap)); 158766Speter return; 159766Speter } 160766Speter putop( P2CALL , P2INT ); 161766Speter putdot( filename , line ); 162766Speter return; 163766Speter 164766Speter case O_MESSAGE: 165766Speter case O_WRITEF: 166766Speter case O_WRITLN: 167766Speter /* 168766Speter * Set up default file "output"'s type 169766Speter */ 170766Speter file = NIL; 171766Speter filetype = nl+T1CHAR; 172766Speter /* 173766Speter * Determine the file implied 174766Speter * for the write and generate 175766Speter * code to make it the active file. 176766Speter */ 177766Speter if (op == O_MESSAGE) { 178766Speter /* 179766Speter * For message, all that matters 180766Speter * is that the filetype is 181766Speter * a character file. 182766Speter * Thus "output" will suit us fine. 183766Speter */ 184766Speter putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" ); 185766Speter putop( P2UNARY P2CALL , P2INT ); 186766Speter putdot( filename , line ); 187*15934Smckusick putRV( (char *) 0 , cbn , CURFILEOFFSET , NLOCAL , 1883833Speter P2PTR|P2STRTY ); 1893833Speter putLV( "__err" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 190766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 191766Speter putdot( filename , line ); 192*15934Smckusick } else if (argv != TR_NIL && (al = argv->list_node.list)->tag != 193*15934Smckusick T_WEXP) { 194766Speter /* 195766Speter * If there is a first argument which has 196766Speter * no write widths, then it is potentially 197766Speter * a file name. 198766Speter */ 199766Speter codeoff(); 200*15934Smckusick ap = stkrval(argv->list_node.list, NLNIL, (long) RREQ ); 201766Speter codeon(); 202*15934Smckusick if (ap == NLNIL) 203*15934Smckusick argv = argv->list_node.next; 204766Speter if (ap != NIL && ap->class == FILET) { 205766Speter /* 206766Speter * Got "write(f, ...", make 207766Speter * f the active file, and save 208766Speter * it and its type for use in 209766Speter * processing the rest of the 210766Speter * arguments to write. 211766Speter */ 212*15934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , 2133833Speter P2PTR|P2STRTY ); 214766Speter putleaf( P2ICON , 0 , 0 215766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 216766Speter , "_UNIT" ); 217*15934Smckusick file = argv->list_node.list; 218766Speter filetype = ap->type; 219*15934Smckusick (void) stklval(argv->list_node.list, NOFLAGS); 220766Speter putop( P2CALL , P2INT ); 221766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 222766Speter putdot( filename , line ); 223766Speter /* 224766Speter * Skip over the first argument 225766Speter */ 226*15934Smckusick argv = argv->list_node.next; 227766Speter argc--; 228766Speter } else { 229766Speter /* 230766Speter * Set up for writing on 231766Speter * standard output. 232766Speter */ 233*15934Smckusick putRV((char *) 0, cbn , CURFILEOFFSET , 2343833Speter NLOCAL , P2PTR|P2STRTY ); 2353833Speter putLV( "_output" , 0 , 0 , NGLOBAL , 2363833Speter P2PTR|P2STRTY ); 237766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 238766Speter putdot( filename , line ); 2397954Speter output->nl_flags |= NUSED; 240766Speter } 241766Speter } else { 242*15934Smckusick putRV((char *) 0, cbn , CURFILEOFFSET , NLOCAL , 2433833Speter P2PTR|P2STRTY ); 2443833Speter putLV( "_output" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 245766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 246766Speter putdot( filename , line ); 2477954Speter output->nl_flags |= NUSED; 248766Speter } 249766Speter /* 250766Speter * Loop and process each 251766Speter * of the arguments. 252766Speter */ 253*15934Smckusick for (; argv != TR_NIL; argv = argv->list_node.next) { 254766Speter /* 255766Speter * fmtspec indicates the type (CONstant or VARiable) 256766Speter * and number (none, WIDTH, and/or PRECision) 257766Speter * of the fields in the printf format for this 258766Speter * output variable. 259766Speter * fmt is the format output indicator (D, E, F, O, X, S) 260766Speter * fmtstart = 0 for leading blank; = 1 for no blank 261766Speter */ 262766Speter fmtspec = NIL; 263766Speter fmt = 'D'; 264766Speter fmtstart = 1; 265*15934Smckusick al = argv->list_node.list; 266766Speter if (al == NIL) 267766Speter continue; 268*15934Smckusick if (al->tag == T_WEXP) 269*15934Smckusick alv = al->wexpr_node.expr1; 270766Speter else 271766Speter alv = al; 272*15934Smckusick if (alv == TR_NIL) 273766Speter continue; 274766Speter codeoff(); 275*15934Smckusick ap = stkrval(alv, NLNIL , (long) RREQ ); 276766Speter codeon(); 277*15934Smckusick if (ap == NLNIL) 278766Speter continue; 279766Speter typ = classify(ap); 280*15934Smckusick if (al->tag == T_WEXP) { 281766Speter /* 282766Speter * Handle width expressions. 283766Speter * The basic game here is that width 284766Speter * expressions get evaluated. If they 285766Speter * are constant, the value is placed 286766Speter * directly in the format string. 287766Speter * Otherwise the value is pushed onto 288766Speter * the stack and an indirection is 289766Speter * put into the format string. 290766Speter */ 291*15934Smckusick if (al->wexpr_node.expr3 == 292*15934Smckusick (struct tnode *) OCT) 293766Speter fmt = 'O'; 294*15934Smckusick else if (al->wexpr_node.expr3 == 295*15934Smckusick (struct tnode *) HEX) 296766Speter fmt = 'X'; 297*15934Smckusick else if (al->wexpr_node.expr3 != TR_NIL) { 298766Speter /* 299766Speter * Evaluate second format spec 300766Speter */ 301*15934Smckusick if ( constval(al->wexpr_node.expr3) 302766Speter && isa( con.ctype , "i" ) ) { 303766Speter fmtspec += CONPREC; 304766Speter prec = con.crval; 305766Speter } else { 306766Speter fmtspec += VARPREC; 307766Speter } 308766Speter fmt = 'f'; 309766Speter switch ( typ ) { 310766Speter case TINT: 311766Speter if ( opt( 's' ) ) { 312766Speter standard(); 313766Speter error("Writing %ss with two write widths is non-standard", clnames[typ]); 314766Speter } 315766Speter /* and fall through */ 316766Speter case TDOUBLE: 317766Speter break; 318766Speter default: 319766Speter error("Cannot write %ss with two write widths", clnames[typ]); 320766Speter continue; 321766Speter } 322766Speter } 323766Speter /* 324766Speter * Evaluate first format spec 325766Speter */ 326*15934Smckusick if (al->wexpr_node.expr2 != TR_NIL) { 327*15934Smckusick if ( constval(al->wexpr_node.expr2) 328766Speter && isa( con.ctype , "i" ) ) { 329766Speter fmtspec += CONWIDTH; 330766Speter field = con.crval; 331766Speter } else { 332766Speter fmtspec += VARWIDTH; 333766Speter } 334766Speter } 335766Speter if ((fmtspec & CONPREC) && prec < 0 || 336766Speter (fmtspec & CONWIDTH) && field < 0) { 337766Speter error("Negative widths are not allowed"); 338766Speter continue; 339766Speter } 3403180Smckusic if ( opt('s') && 3413180Smckusic ((fmtspec & CONPREC) && prec == 0 || 3423180Smckusic (fmtspec & CONWIDTH) && field == 0)) { 3433180Smckusic standard(); 3443180Smckusic error("Zero widths are non-standard"); 3453180Smckusic } 346766Speter } 347766Speter if (filetype != nl+T1CHAR) { 348766Speter if (fmt == 'O' || fmt == 'X') { 349766Speter error("Oct/hex allowed only on text files"); 350766Speter continue; 351766Speter } 352766Speter if (fmtspec) { 353766Speter error("Write widths allowed only on text files"); 354766Speter continue; 355766Speter } 356766Speter /* 357766Speter * Generalized write, i.e. 358766Speter * to a non-textfile. 359766Speter */ 360766Speter putleaf( P2ICON , 0 , 0 361*15934Smckusick , (int) (ADDTYPE( 362766Speter ADDTYPE( 363766Speter ADDTYPE( p2type( filetype ) 364766Speter , P2PTR ) 365766Speter , P2FTN ) 366*15934Smckusick , P2PTR )) 367766Speter , "_FNIL" ); 368*15934Smckusick (void) stklval(file, NOFLAGS); 369766Speter putop( P2CALL 370766Speter , ADDTYPE( p2type( filetype ) , P2PTR ) ); 371766Speter putop( P2UNARY P2MUL , p2type( filetype ) ); 372766Speter /* 373766Speter * file^ := ... 374766Speter */ 375766Speter switch ( classify( filetype ) ) { 376766Speter case TBOOL: 377766Speter case TCHAR: 378766Speter case TINT: 379766Speter case TSCAL: 3804589Speter precheck( filetype , "_RANG4" , "_RSNG4" ); 381766Speter /* and fall through */ 382766Speter case TDOUBLE: 383766Speter case TPTR: 384*15934Smckusick ap = rvalue( argv->list_node.list , filetype , RREQ ); 385766Speter break; 386766Speter default: 387*15934Smckusick ap = rvalue( argv->list_node.list , filetype , LREQ ); 388766Speter break; 389766Speter } 390766Speter if (ap == NIL) 391766Speter continue; 392*15934Smckusick if (incompat(ap, filetype, argv->list_node.list)) { 393766Speter cerror("Type mismatch in write to non-text file"); 394766Speter continue; 395766Speter } 396766Speter switch ( classify( filetype ) ) { 397766Speter case TBOOL: 398766Speter case TCHAR: 399766Speter case TINT: 400766Speter case TSCAL: 40110373Speter postcheck(filetype, ap); 40210373Speter sconv(p2type(ap), p2type(filetype)); 403766Speter /* and fall through */ 404766Speter case TDOUBLE: 405766Speter case TPTR: 406766Speter putop( P2ASSIGN , p2type( filetype ) ); 407766Speter putdot( filename , line ); 408766Speter break; 409766Speter default: 41011856Speter putstrop(P2STASG, 41111856Speter ADDTYPE(p2type(filetype), 41211856Speter P2PTR), 413*15934Smckusick (int) lwidth(filetype), 41411856Speter align(filetype)); 415766Speter putdot( filename , line ); 416766Speter break; 417766Speter } 418766Speter /* 419766Speter * put(file) 420766Speter */ 421766Speter putleaf( P2ICON , 0 , 0 422766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 423766Speter , "_PUT" ); 424*15934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , 4253833Speter P2PTR|P2STRTY ); 426766Speter putop( P2CALL , P2INT ); 427766Speter putdot( filename , line ); 428766Speter continue; 429766Speter } 430766Speter /* 431766Speter * Write to a textfile 432766Speter * 433766Speter * Evaluate the expression 434766Speter * to be written. 435766Speter */ 436766Speter if (fmt == 'O' || fmt == 'X') { 437766Speter if (opt('s')) { 438766Speter standard(); 439766Speter error("Oct and hex are non-standard"); 440766Speter } 441766Speter if (typ == TSTR || typ == TDOUBLE) { 442766Speter error("Can't write %ss with oct/hex", clnames[typ]); 443766Speter continue; 444766Speter } 445766Speter if (typ == TCHAR || typ == TBOOL) 446766Speter typ = TINT; 447766Speter } 448766Speter /* 449766Speter * If there is no format specified by the programmer, 450766Speter * implement the default. 451766Speter */ 452766Speter switch (typ) { 4536540Smckusick case TPTR: 4546540Smckusick warning(); 4556540Smckusick if (opt('s')) { 4566540Smckusick standard(); 4576540Smckusick } 4586540Smckusick error("Writing %ss to text files is non-standard", 4596540Smckusick clnames[typ]); 4606540Smckusick /* and fall through */ 461766Speter case TINT: 462766Speter if (fmt == 'f') { 463766Speter typ = TDOUBLE; 464766Speter goto tdouble; 465766Speter } 466766Speter if (fmtspec == NIL) { 467766Speter if (fmt == 'D') 468766Speter field = 10; 469766Speter else if (fmt == 'X') 470766Speter field = 8; 471766Speter else if (fmt == 'O') 472766Speter field = 11; 473766Speter else 474766Speter panic("fmt1"); 475766Speter fmtspec = CONWIDTH; 476766Speter } 477766Speter break; 478766Speter case TCHAR: 479766Speter tchar: 480766Speter fmt = 'c'; 481766Speter break; 482766Speter case TSCAL: 4831629Speter warning(); 484766Speter if (opt('s')) { 485766Speter standard(); 486766Speter } 4876540Smckusick error("Writing %ss to text files is non-standard", 4886540Smckusick clnames[typ]); 489766Speter case TBOOL: 490766Speter fmt = 's'; 491766Speter break; 492766Speter case TDOUBLE: 493766Speter tdouble: 494766Speter switch (fmtspec) { 495766Speter case NIL: 49611883Smckusick field = 14 + (5 + EXPOSIZE); 49711883Smckusick prec = field - (5 + EXPOSIZE); 4983225Smckusic fmt = 'e'; 499766Speter fmtspec = CONWIDTH + CONPREC; 500766Speter break; 501766Speter case CONWIDTH: 5029229Smckusick field -= REALSPC; 5039229Smckusick if (field < 1) 504766Speter field = 1; 50511883Smckusick prec = field - (5 + EXPOSIZE); 506766Speter if (prec < 1) 507766Speter prec = 1; 508766Speter fmtspec += CONPREC; 5093225Smckusic fmt = 'e'; 510766Speter break; 511766Speter case VARWIDTH: 512766Speter fmtspec += VARPREC; 5133225Smckusic fmt = 'e'; 514766Speter break; 515766Speter case CONWIDTH + CONPREC: 516766Speter case CONWIDTH + VARPREC: 5179229Smckusick field -= REALSPC; 5189229Smckusick if (field < 1) 519766Speter field = 1; 520766Speter } 521766Speter format[0] = ' '; 5229229Smckusick fmtstart = 1 - REALSPC; 523766Speter break; 524766Speter case TSTR: 525*15934Smckusick (void) constval( alv ); 526766Speter switch ( classify( con.ctype ) ) { 527766Speter case TCHAR: 528766Speter typ = TCHAR; 529766Speter goto tchar; 530766Speter case TSTR: 531766Speter strptr = con.cpval; 532766Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 533766Speter strptr = con.cpval; 534766Speter break; 535766Speter default: 536766Speter strnglen = width(ap); 537766Speter break; 538766Speter } 539766Speter fmt = 's'; 540766Speter strfmt = fmtspec; 541766Speter if (fmtspec == NIL) { 542766Speter fmtspec = SKIP; 543766Speter break; 544766Speter } 545766Speter if (fmtspec & CONWIDTH) { 546766Speter if (field <= strnglen) 547766Speter fmtspec = SKIP; 548766Speter else 549766Speter field -= strnglen; 550766Speter } 551766Speter break; 552766Speter default: 553766Speter error("Can't write %ss to a text file", clnames[typ]); 554766Speter continue; 555766Speter } 556766Speter /* 557766Speter * Generate the format string 558766Speter */ 559766Speter switch (fmtspec) { 560766Speter default: 561766Speter panic("fmt2"); 562766Speter case NIL: 563766Speter if (fmt == 'c') { 564766Speter if ( opt( 't' ) ) { 565766Speter putleaf( P2ICON , 0 , 0 566766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 567766Speter , "_WRITEC" ); 568*15934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , 5693833Speter NLOCAL , P2PTR|P2STRTY ); 570*15934Smckusick (void) stkrval( alv , NLNIL , (long) RREQ ); 571766Speter putop( P2LISTOP , P2INT ); 572766Speter } else { 573766Speter putleaf( P2ICON , 0 , 0 574766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 575766Speter , "_fputc" ); 576*15934Smckusick (void) stkrval( alv , NLNIL , 577*15934Smckusick (long) RREQ ); 578766Speter } 579766Speter putleaf( P2ICON , 0 , 0 580766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 581766Speter , "_ACTFILE" ); 582*15934Smckusick putRV((char *) 0, cbn , CURFILEOFFSET , 5833833Speter NLOCAL , P2PTR|P2STRTY ); 584766Speter putop( P2CALL , P2INT ); 585766Speter putop( P2LISTOP , P2INT ); 586766Speter putop( P2CALL , P2INT ); 587766Speter putdot( filename , line ); 588766Speter } else { 589766Speter sprintf(&format[1], "%%%c", fmt); 590766Speter goto fmtgen; 591766Speter } 592766Speter case SKIP: 593766Speter break; 594766Speter case CONWIDTH: 595766Speter sprintf(&format[1], "%%%1D%c", field, fmt); 596766Speter goto fmtgen; 597766Speter case VARWIDTH: 598766Speter sprintf(&format[1], "%%*%c", fmt); 599766Speter goto fmtgen; 600766Speter case CONWIDTH + CONPREC: 601766Speter sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt); 602766Speter goto fmtgen; 603766Speter case CONWIDTH + VARPREC: 604766Speter sprintf(&format[1], "%%%1D.*%c", field, fmt); 605766Speter goto fmtgen; 606766Speter case VARWIDTH + CONPREC: 607766Speter sprintf(&format[1], "%%*.%1D%c", prec, fmt); 608766Speter goto fmtgen; 609766Speter case VARWIDTH + VARPREC: 610766Speter sprintf(&format[1], "%%*.*%c", fmt); 611766Speter fmtgen: 612766Speter if ( opt( 't' ) ) { 613766Speter putleaf( P2ICON , 0 , 0 614766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 615766Speter , "_WRITEF" ); 616*15934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , 6173833Speter NLOCAL , P2PTR|P2STRTY ); 618766Speter putleaf( P2ICON , 0 , 0 619766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 620766Speter , "_ACTFILE" ); 621*15934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , 6223833Speter NLOCAL , P2PTR|P2STRTY ); 623766Speter putop( P2CALL , P2INT ); 624766Speter putop( P2LISTOP , P2INT ); 625766Speter } else { 626766Speter putleaf( P2ICON , 0 , 0 627766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 628766Speter , "_fprintf" ); 629766Speter putleaf( P2ICON , 0 , 0 630766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 631766Speter , "_ACTFILE" ); 632*15934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , 6333833Speter NLOCAL , P2PTR|P2STRTY ); 634766Speter putop( P2CALL , P2INT ); 635766Speter } 636766Speter putCONG( &format[ fmtstart ] 637766Speter , strlen( &format[ fmtstart ] ) 638766Speter , LREQ ); 639766Speter putop( P2LISTOP , P2INT ); 640766Speter if ( fmtspec & VARWIDTH ) { 641766Speter /* 642766Speter * either 643766Speter * ,(temp=width,MAX(temp,...)), 644766Speter * or 645766Speter * , MAX( width , ... ) , 646766Speter */ 647*15934Smckusick if ( ( typ == TDOUBLE && 648*15934Smckusick al->wexpr_node.expr3 == TR_NIL ) 649766Speter || typ == TSTR ) { 6503225Smckusic soffset = sizes[cbn].curtmps; 651*15934Smckusick tempnlp = tmpalloc((long) (sizeof(long)), 6523225Smckusic nl+T4INT, REGOK); 653*15934Smckusick putRV((char *) 0 , cbn , 6543833Speter tempnlp -> value[ NL_OFFS ] , 6553833Speter tempnlp -> extra_flags , P2INT ); 656*15934Smckusick ap = stkrval( al->wexpr_node.expr2 , 657*15934Smckusick NLNIL , (long) RREQ ); 658766Speter putop( P2ASSIGN , P2INT ); 659766Speter putleaf( P2ICON , 0 , 0 660766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 661766Speter , "_MAX" ); 662*15934Smckusick putRV((char *) 0 , cbn , 6633833Speter tempnlp -> value[ NL_OFFS ] , 6643833Speter tempnlp -> extra_flags , P2INT ); 665766Speter } else { 666766Speter if (opt('t') 667766Speter || typ == TSTR || typ == TDOUBLE) { 668766Speter putleaf( P2ICON , 0 , 0 669766Speter ,ADDTYPE( P2FTN | P2INT, P2PTR ) 670766Speter ,"_MAX" ); 671766Speter } 672*15934Smckusick ap = stkrval( al->wexpr_node.expr2, 673*15934Smckusick NLNIL , (long) RREQ ); 674766Speter } 675*15934Smckusick if (ap == NLNIL) 676766Speter continue; 677766Speter if (isnta(ap,"i")) { 678766Speter error("First write width must be integer, not %s", nameof(ap)); 679766Speter continue; 680766Speter } 681766Speter switch ( typ ) { 682766Speter case TDOUBLE: 683*15934Smckusick putleaf( P2ICON , REALSPC , 0 , P2INT , (char *) 0 ); 684766Speter putop( P2LISTOP , P2INT ); 685*15934Smckusick putleaf( P2ICON , 1 , 0 , P2INT , (char *) 0 ); 686766Speter putop( P2LISTOP , P2INT ); 687766Speter putop( P2CALL , P2INT ); 688*15934Smckusick if ( al->wexpr_node.expr3 == TR_NIL ) { 689766Speter /* 690766Speter * finish up the comma op 691766Speter */ 692766Speter putop( P2COMOP , P2INT ); 693766Speter fmtspec &= ~VARPREC; 694766Speter putop( P2LISTOP , P2INT ); 695766Speter putleaf( P2ICON , 0 , 0 696766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 697766Speter , "_MAX" ); 698*15934Smckusick putRV((char *) 0 , cbn , 6993833Speter tempnlp -> value[ NL_OFFS ] , 7003833Speter tempnlp -> extra_flags , 7013833Speter P2INT ); 702*15934Smckusick tmpfree(&soffset); 70311883Smckusick putleaf( P2ICON , 70411883Smckusick 5 + EXPOSIZE + REALSPC , 705*15934Smckusick 0 , P2INT , (char *) 0 ); 706766Speter putop( P2LISTOP , P2INT ); 707*15934Smckusick putleaf( P2ICON , 1 , 0 , P2INT , (char *) 0 ); 708766Speter putop( P2LISTOP , P2INT ); 709766Speter putop( P2CALL , P2INT ); 710766Speter } 711766Speter putop( P2LISTOP , P2INT ); 712766Speter break; 713766Speter case TSTR: 714*15934Smckusick putleaf( P2ICON , strnglen , 0 , P2INT , (char *) 0 ); 715766Speter putop( P2LISTOP , P2INT ); 716*15934Smckusick putleaf( P2ICON , 0 , 0 , P2INT , (char *) 0 ); 717766Speter putop( P2LISTOP , P2INT ); 718766Speter putop( P2CALL , P2INT ); 719766Speter putop( P2COMOP , P2INT ); 720766Speter putop( P2LISTOP , P2INT ); 721766Speter break; 722766Speter default: 723766Speter if (opt('t')) { 724*15934Smckusick putleaf( P2ICON , 0 , 0 , P2INT , (char *) 0 ); 725766Speter putop( P2LISTOP , P2INT ); 726*15934Smckusick putleaf( P2ICON , 0 , 0 , P2INT , (char *) 0 ); 727766Speter putop( P2LISTOP , P2INT ); 728766Speter putop( P2CALL , P2INT ); 729766Speter } 730766Speter putop( P2LISTOP , P2INT ); 731766Speter break; 732766Speter } 733766Speter } 734766Speter /* 735766Speter * If there is a variable precision, 736766Speter * evaluate it 737766Speter */ 738766Speter if (fmtspec & VARPREC) { 739766Speter if (opt('t')) { 740766Speter putleaf( P2ICON , 0 , 0 741766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 742766Speter , "_MAX" ); 743766Speter } 744*15934Smckusick ap = stkrval( al->wexpr_node.expr3 , 745*15934Smckusick NLNIL , (long) RREQ ); 746766Speter if (ap == NIL) 747766Speter continue; 748766Speter if (isnta(ap,"i")) { 749766Speter error("Second write width must be integer, not %s", nameof(ap)); 750766Speter continue; 751766Speter } 752766Speter if (opt('t')) { 753*15934Smckusick putleaf( P2ICON , 0 , 0 , P2INT , (char *) 0 ); 754766Speter putop( P2LISTOP , P2INT ); 755*15934Smckusick putleaf( P2ICON , 0 , 0 , P2INT , (char *) 0 ); 756766Speter putop( P2LISTOP , P2INT ); 757766Speter putop( P2CALL , P2INT ); 758766Speter } 759766Speter putop( P2LISTOP , P2INT ); 760766Speter } 761766Speter /* 762766Speter * evaluate the thing we want printed. 763766Speter */ 764766Speter switch ( typ ) { 7656540Smckusick case TPTR: 766766Speter case TCHAR: 767766Speter case TINT: 768*15934Smckusick (void) stkrval( alv , NLNIL , (long) RREQ ); 769766Speter putop( P2LISTOP , P2INT ); 770766Speter break; 771766Speter case TDOUBLE: 772*15934Smckusick ap = stkrval( alv , NLNIL , (long) RREQ ); 77310373Speter if (isnta(ap, "d")) { 77410373Speter sconv(p2type(ap), P2DOUBLE); 775766Speter } 776766Speter putop( P2LISTOP , P2INT ); 777766Speter break; 778766Speter case TSCAL: 779766Speter case TBOOL: 780766Speter putleaf( P2ICON , 0 , 0 781766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 782766Speter , "_NAM" ); 783*15934Smckusick ap = stkrval( alv , NLNIL , (long) RREQ ); 784766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 785766Speter , listnames( ap ) ); 786*15934Smckusick putleaf( P2ICON , 0 , 0 , 787*15934Smckusick (int) (P2PTR | P2CHAR), format ); 788766Speter putop( P2LISTOP , P2INT ); 789766Speter putop( P2CALL , P2INT ); 790766Speter putop( P2LISTOP , P2INT ); 791766Speter break; 792766Speter case TSTR: 793766Speter putCONG( "" , 0 , LREQ ); 794766Speter putop( P2LISTOP , P2INT ); 795766Speter break; 7966540Smckusick default: 7976540Smckusick panic("fmt3"); 7986540Smckusick break; 799766Speter } 800766Speter putop( P2CALL , P2INT ); 801766Speter putdot( filename , line ); 802766Speter } 803766Speter /* 804766Speter * Write the string after its blank padding 805766Speter */ 806766Speter if (typ == TSTR ) { 807766Speter if ( opt( 't' ) ) { 808766Speter putleaf( P2ICON , 0 , 0 809766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 810766Speter , "_WRITES" ); 811*15934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , 8123833Speter NLOCAL , P2PTR|P2STRTY ); 813*15934Smckusick ap = stkrval(alv, NLNIL , (long) RREQ ); 814766Speter putop( P2LISTOP , P2INT ); 815766Speter } else { 816766Speter putleaf( P2ICON , 0 , 0 817766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 818766Speter , "_fwrite" ); 819*15934Smckusick ap = stkrval(alv, NLNIL , (long) RREQ ); 820766Speter } 821766Speter if (strfmt & VARWIDTH) { 822766Speter /* 823766Speter * min, inline expanded as 824766Speter * temp < len ? temp : len 825766Speter */ 826*15934Smckusick putRV((char *) 0 , cbn , 8273833Speter tempnlp -> value[ NL_OFFS ] , 8283833Speter tempnlp -> extra_flags , P2INT ); 829*15934Smckusick putleaf( P2ICON , strnglen , 0 , P2INT , (char *) 0 ); 830766Speter putop( P2LT , P2INT ); 831*15934Smckusick putRV((char *) 0 , cbn , 8323833Speter tempnlp -> value[ NL_OFFS ] , 8333833Speter tempnlp -> extra_flags , P2INT ); 834*15934Smckusick putleaf( P2ICON , strnglen , 0 , P2INT , (char *) 0 ); 835766Speter putop( P2COLON , P2INT ); 836766Speter putop( P2QUEST , P2INT ); 837*15934Smckusick tmpfree(&soffset); 838766Speter } else { 839766Speter if ( ( fmtspec & SKIP ) 840766Speter && ( strfmt & CONWIDTH ) ) { 841766Speter strnglen = field; 842766Speter } 843*15934Smckusick putleaf( P2ICON , strnglen , 0 , P2INT , (char *) 0 ); 844766Speter } 845766Speter putop( P2LISTOP , P2INT ); 846*15934Smckusick putleaf( P2ICON , 1 , 0 , P2INT , (char *) 0 ); 847766Speter putop( P2LISTOP , P2INT ); 848766Speter putleaf( P2ICON , 0 , 0 849766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 850766Speter , "_ACTFILE" ); 851*15934Smckusick putRV((char *) 0, cbn , CURFILEOFFSET , NLOCAL , 8523833Speter P2PTR|P2STRTY ); 853766Speter putop( P2CALL , P2INT ); 854766Speter putop( P2LISTOP , P2INT ); 855766Speter putop( P2CALL , P2INT ); 856766Speter putdot( filename , line ); 857766Speter } 858766Speter } 859766Speter /* 860766Speter * Done with arguments. 861766Speter * Handle writeln and 862766Speter * insufficent number of args. 863766Speter */ 864766Speter switch (p->value[0] &~ NSTAND) { 865766Speter case O_WRITEF: 866766Speter if (argc == 0) 867766Speter error("Write requires an argument"); 868766Speter break; 869766Speter case O_MESSAGE: 870766Speter if (argc == 0) 871766Speter error("Message requires an argument"); 872766Speter case O_WRITLN: 873766Speter if (filetype != nl+T1CHAR) 874766Speter error("Can't 'writeln' a non text file"); 875766Speter if ( opt( 't' ) ) { 876766Speter putleaf( P2ICON , 0 , 0 877766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 878766Speter , "_WRITLN" ); 879*15934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , 8803833Speter NLOCAL , P2PTR|P2STRTY ); 881766Speter } else { 882766Speter putleaf( P2ICON , 0 , 0 883766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 884766Speter , "_fputc" ); 885*15934Smckusick putleaf( P2ICON , '\n' , 0 , (int) P2CHAR , (char *) 0 ); 886766Speter putleaf( P2ICON , 0 , 0 887766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 888766Speter , "_ACTFILE" ); 889*15934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , 8903833Speter NLOCAL , P2PTR|P2STRTY ); 891766Speter putop( P2CALL , P2INT ); 892766Speter putop( P2LISTOP , P2INT ); 893766Speter } 894766Speter putop( P2CALL , P2INT ); 895766Speter putdot( filename , line ); 896766Speter break; 897766Speter } 898766Speter return; 899766Speter 900766Speter case O_READ4: 901766Speter case O_READLN: 902766Speter /* 903766Speter * Set up default 904766Speter * file "input". 905766Speter */ 906766Speter file = NIL; 907766Speter filetype = nl+T1CHAR; 908766Speter /* 909766Speter * Determine the file implied 910766Speter * for the read and generate 911766Speter * code to make it the active file. 912766Speter */ 913*15934Smckusick if (argv != TR_NIL) { 914766Speter codeoff(); 915*15934Smckusick ap = stkrval(argv->list_node.list, NLNIL, (long) RREQ ); 916766Speter codeon(); 917*15934Smckusick if (ap == NLNIL) 918*15934Smckusick argv = argv->list_node.next; 919*15934Smckusick if (ap != NLNIL && ap->class == FILET) { 920766Speter /* 921766Speter * Got "read(f, ...", make 922766Speter * f the active file, and save 923766Speter * it and its type for use in 924766Speter * processing the rest of the 925766Speter * arguments to read. 926766Speter */ 927*15934Smckusick file = argv->list_node.list; 928766Speter filetype = ap->type; 929*15934Smckusick putRV((char *) 0, cbn , CURFILEOFFSET , NLOCAL , 9303833Speter P2PTR|P2STRTY ); 931766Speter putleaf( P2ICON , 0 , 0 932766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 933766Speter , "_UNIT" ); 934*15934Smckusick (void) stklval(argv->list_node.list, NOFLAGS); 935766Speter putop( P2CALL , P2INT ); 936766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 937766Speter putdot( filename , line ); 938*15934Smckusick argv = argv->list_node.next; 939766Speter argc--; 940766Speter } else { 941766Speter /* 942766Speter * Default is read from 943766Speter * standard input. 944766Speter */ 945*15934Smckusick putRV((char *) 0, cbn , CURFILEOFFSET , NLOCAL , 9463833Speter P2PTR|P2STRTY ); 9473833Speter putLV( "_input" , 0 , 0 , NGLOBAL , 9483833Speter P2PTR|P2STRTY ); 949766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 950766Speter putdot( filename , line ); 951766Speter input->nl_flags |= NUSED; 952766Speter } 953766Speter } else { 954*15934Smckusick putRV((char *) 0, cbn , CURFILEOFFSET , NLOCAL , 9553833Speter P2PTR|P2STRTY ); 9563833Speter putLV( "_input" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 957766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 958766Speter putdot( filename , line ); 959766Speter input->nl_flags |= NUSED; 960766Speter } 961766Speter /* 962766Speter * Loop and process each 963766Speter * of the arguments. 964766Speter */ 965*15934Smckusick for (; argv != TR_NIL; argv = argv->list_node.next) { 966766Speter /* 967766Speter * Get the address of the target 968766Speter * on the stack. 969766Speter */ 970*15934Smckusick al = argv->list_node.list; 971*15934Smckusick if (al == TR_NIL) 972766Speter continue; 973*15934Smckusick if (al->tag != T_VAR) { 974766Speter error("Arguments to %s must be variables, not expressions", p->symbol); 975766Speter continue; 976766Speter } 977766Speter codeoff(); 978766Speter ap = stklval(al, MOD|ASGN|NOUSE); 979766Speter codeon(); 980*15934Smckusick if (ap == NLNIL) 981766Speter continue; 982766Speter if (filetype != nl+T1CHAR) { 983766Speter /* 984766Speter * Generalized read, i.e. 985766Speter * from a non-textfile. 986766Speter */ 987*15934Smckusick if (incompat(filetype, ap, argv->list_node.list )) { 988766Speter error("Type mismatch in read from non-text file"); 989766Speter continue; 990766Speter } 991766Speter /* 992766Speter * var := file ^; 993766Speter */ 994766Speter ap = lvalue( al , MOD | ASGN | NOUSE , RREQ ); 995766Speter if ( isa( ap , "bsci" ) ) { 996766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 997766Speter } 998766Speter putleaf( P2ICON , 0 , 0 999*15934Smckusick , (int) (ADDTYPE( 1000766Speter ADDTYPE( 1001766Speter ADDTYPE( 1002766Speter p2type( filetype ) , P2PTR ) 1003766Speter , P2FTN ) 1004*15934Smckusick , P2PTR )) 1005766Speter , "_FNIL" ); 1006766Speter if (file != NIL) 1007*15934Smckusick (void) stklval(file, NOFLAGS); 1008766Speter else /* Magic */ 10093833Speter putRV( "_input" , 0 , 0 , NGLOBAL , 10103833Speter P2PTR | P2STRTY ); 101110668Speter putop(P2CALL, ADDTYPE(p2type(filetype), P2PTR)); 1012766Speter switch ( classify( filetype ) ) { 1013766Speter case TBOOL: 1014766Speter case TCHAR: 1015766Speter case TINT: 1016766Speter case TSCAL: 1017766Speter case TDOUBLE: 1018766Speter case TPTR: 1019766Speter putop( P2UNARY P2MUL 1020766Speter , p2type( filetype ) ); 1021766Speter } 1022766Speter switch ( classify( filetype ) ) { 1023766Speter case TBOOL: 1024766Speter case TCHAR: 1025766Speter case TINT: 1026766Speter case TSCAL: 102710373Speter postcheck(ap, filetype); 102810373Speter sconv(p2type(filetype), p2type(ap)); 1029766Speter /* and fall through */ 1030766Speter case TDOUBLE: 1031766Speter case TPTR: 1032766Speter putop( P2ASSIGN , p2type( ap ) ); 1033766Speter putdot( filename , line ); 1034766Speter break; 1035766Speter default: 103611856Speter putstrop(P2STASG, 103711856Speter ADDTYPE(p2type(ap), P2PTR), 1038*15934Smckusick (int) lwidth(ap), 103911856Speter align(ap)); 1040766Speter putdot( filename , line ); 1041766Speter break; 1042766Speter } 1043766Speter /* 1044766Speter * get(file); 1045766Speter */ 1046766Speter putleaf( P2ICON , 0 , 0 1047766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1048766Speter , "_GET" ); 1049*15934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , 10503833Speter P2PTR|P2STRTY ); 1051766Speter putop( P2CALL , P2INT ); 1052766Speter putdot( filename , line ); 1053766Speter continue; 1054766Speter } 1055766Speter /* 1056766Speter * if you get to here, you are reading from 1057766Speter * a text file. only possiblities are: 1058766Speter * character, integer, real, or scalar. 1059766Speter * read( f , foo , ... ) is done as 1060766Speter * foo := read( f ) with rangechecking 1061766Speter * if appropriate. 1062766Speter */ 1063766Speter typ = classify(ap); 1064766Speter op = rdops(typ); 1065766Speter if (op == NIL) { 1066766Speter error("Can't read %ss from a text file", clnames[typ]); 1067766Speter continue; 1068766Speter } 1069766Speter /* 1070766Speter * left hand side of foo := read( f ) 1071766Speter */ 1072766Speter ap = lvalue( al , MOD|ASGN|NOUSE , RREQ ); 1073766Speter if ( isa( ap , "bsci" ) ) { 1074766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 1075766Speter } 1076766Speter switch ( op ) { 1077766Speter case O_READC: 1078766Speter readname = "_READC"; 1079766Speter readtype = P2INT; 1080766Speter break; 1081766Speter case O_READ4: 1082766Speter readname = "_READ4"; 1083766Speter readtype = P2INT; 1084766Speter break; 1085766Speter case O_READ8: 1086766Speter readname = "_READ8"; 1087766Speter readtype = P2DOUBLE; 1088766Speter break; 1089766Speter case O_READE: 1090766Speter readname = "_READE"; 1091766Speter readtype = P2INT; 1092766Speter break; 1093766Speter } 1094766Speter putleaf( P2ICON , 0 , 0 1095*15934Smckusick , (int) ADDTYPE( P2FTN | readtype , P2PTR ) 1096766Speter , readname ); 1097*15934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , 10983833Speter P2PTR|P2STRTY ); 1099766Speter if ( op == O_READE ) { 1100766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 1101766Speter , listnames( ap ) ); 1102*15934Smckusick putleaf( P2ICON , 0, 0, (int) (P2PTR | P2CHAR), 1103*15934Smckusick format ); 1104766Speter putop( P2LISTOP , P2INT ); 11051629Speter warning(); 1106766Speter if (opt('s')) { 1107766Speter standard(); 1108766Speter } 11091629Speter error("Reading scalars from text files is non-standard"); 1110766Speter } 1111*15934Smckusick putop( P2CALL , (int) readtype ); 1112766Speter if ( isa( ap , "bcsi" ) ) { 111310373Speter postcheck(ap, readtype==P2INT?nl+T4INT:nl+TDOUBLE); 1114766Speter } 1115*15934Smckusick sconv((int) readtype, p2type(ap)); 1116766Speter putop( P2ASSIGN , p2type( ap ) ); 1117766Speter putdot( filename , line ); 1118766Speter } 1119766Speter /* 1120766Speter * Done with arguments. 1121766Speter * Handle readln and 1122766Speter * insufficient number of args. 1123766Speter */ 1124766Speter if (p->value[0] == O_READLN) { 1125766Speter if (filetype != nl+T1CHAR) 1126766Speter error("Can't 'readln' a non text file"); 1127766Speter putleaf( P2ICON , 0 , 0 1128*15934Smckusick , (int) ADDTYPE( P2FTN | P2INT , P2PTR ) 1129766Speter , "_READLN" ); 1130*15934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , 11313833Speter P2PTR|P2STRTY ); 1132766Speter putop( P2CALL , P2INT ); 1133766Speter putdot( filename , line ); 1134766Speter } else if (argc == 0) 1135766Speter error("read requires an argument"); 1136766Speter return; 1137766Speter 1138766Speter case O_GET: 1139766Speter case O_PUT: 1140766Speter if (argc != 1) { 1141766Speter error("%s expects one argument", p->symbol); 1142766Speter return; 1143766Speter } 1144*15934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1145766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1146766Speter , "_UNIT" ); 1147*15934Smckusick ap = stklval(argv->list_node.list, NOFLAGS); 1148*15934Smckusick if (ap == NLNIL) 1149766Speter return; 1150766Speter if (ap->class != FILET) { 1151766Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1152766Speter return; 1153766Speter } 1154766Speter putop( P2CALL , P2INT ); 1155766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1156766Speter putdot( filename , line ); 1157766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1158766Speter , op == O_GET ? "_GET" : "_PUT" ); 1159*15934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1160766Speter putop( P2CALL , P2INT ); 1161766Speter putdot( filename , line ); 1162766Speter return; 1163766Speter 1164766Speter case O_RESET: 1165766Speter case O_REWRITE: 1166766Speter if (argc == 0 || argc > 2) { 1167766Speter error("%s expects one or two arguments", p->symbol); 1168766Speter return; 1169766Speter } 1170766Speter if (opt('s') && argc == 2) { 1171766Speter standard(); 1172766Speter error("Two argument forms of reset and rewrite are non-standard"); 1173766Speter } 1174766Speter putleaf( P2ICON , 0 , 0 , P2INT 1175766Speter , op == O_RESET ? "_RESET" : "_REWRITE" ); 1176*15934Smckusick ap = stklval(argv->list_node.list, MOD|NOUSE); 1177*15934Smckusick if (ap == NLNIL) 1178766Speter return; 1179766Speter if (ap->class != FILET) { 1180766Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1181766Speter return; 1182766Speter } 1183766Speter if (argc == 2) { 1184766Speter /* 1185766Speter * Optional second argument 1186766Speter * is a string name of a 1187766Speter * UNIX (R) file to be associated. 1188766Speter */ 1189*15934Smckusick al = argv->list_node.next; 1190*15934Smckusick al = (struct tnode *) stkrval(al->list_node.list, 1191*15934Smckusick NLNIL , (long) RREQ ); 1192*15934Smckusick if (al == TR_NIL) 1193766Speter return; 1194*15934Smckusick if (classify((struct nl *) al) != TSTR) { 1195*15934Smckusick error("Second argument to %s must be a string, not %s", p->symbol, nameof((struct nl *) al)); 1196766Speter return; 1197766Speter } 1198*15934Smckusick strnglen = width((struct nl *) al); 1199766Speter } else { 1200*15934Smckusick putleaf( P2ICON , 0 , 0 , P2INT , (char *) 0 ); 1201766Speter strnglen = 0; 1202766Speter } 1203766Speter putop( P2LISTOP , P2INT ); 1204*15934Smckusick putleaf( P2ICON , strnglen , 0 , P2INT , (char *) 0 ); 1205766Speter putop( P2LISTOP , P2INT ); 1206*15934Smckusick putleaf( P2ICON , text(ap) ? 0: width(ap->type) , 0 , P2INT , (char *) 0 ); 1207766Speter putop( P2LISTOP , P2INT ); 1208766Speter putop( P2CALL , P2INT ); 1209766Speter putdot( filename , line ); 1210766Speter return; 1211766Speter 1212766Speter case O_NEW: 1213766Speter case O_DISPOSE: 1214766Speter if (argc == 0) { 1215766Speter error("%s expects at least one argument", p->symbol); 1216766Speter return; 1217766Speter } 1218*15934Smckusick alv = argv->list_node.list; 12197967Smckusick codeoff(); 12209139Smckusick ap = stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD ); 12217967Smckusick codeon(); 1222*15934Smckusick if (ap == NLNIL) 1223766Speter return; 1224766Speter if (ap->class != PTR) { 1225766Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 1226766Speter return; 1227766Speter } 1228766Speter ap = ap->type; 1229*15934Smckusick if (ap == NLNIL) 1230766Speter return; 12319139Smckusick if (op == O_NEW) 12329139Smckusick cmd = "_NEW"; 12339139Smckusick else /* op == O_DISPOSE */ 12347967Smckusick if ((ap->nl_flags & NFILES) != 0) 12357967Smckusick cmd = "_DFDISPOSE"; 12367967Smckusick else 12377967Smckusick cmd = "_DISPOSE"; 12387967Smckusick putleaf( P2ICON, 0, 0, ADDTYPE( P2FTN | P2INT , P2PTR ), cmd); 1239*15934Smckusick (void) stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD ); 1240*15934Smckusick argv = argv->list_node.next; 1241*15934Smckusick if (argv != TR_NIL) { 1242766Speter if (ap->class != RECORD) { 1243766Speter error("Record required when specifying variant tags"); 1244766Speter return; 1245766Speter } 1246*15934Smckusick for (; argv != TR_NIL; argv = argv->list_node.next) { 1247766Speter if (ap->ptr[NL_VARNT] == NIL) { 1248766Speter error("Too many tag fields"); 1249766Speter return; 1250766Speter } 1251*15934Smckusick if (!isconst(argv->list_node.list)) { 1252766Speter error("Second and successive arguments to %s must be constants", p->symbol); 1253766Speter return; 1254766Speter } 1255*15934Smckusick gconst(argv->list_node.list); 1256766Speter if (con.ctype == NIL) 1257766Speter return; 1258*15934Smckusick if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , TR_NIL )) { 1259766Speter cerror("Specified tag constant type clashed with variant case selector type"); 1260766Speter return; 1261766Speter } 1262766Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 1263766Speter if (ap->range[0] == con.crval) 1264766Speter break; 1265766Speter if (ap == NIL) { 1266766Speter error("No variant case label value equals specified constant value"); 1267766Speter return; 1268766Speter } 1269766Speter ap = ap->ptr[NL_VTOREC]; 1270766Speter } 1271766Speter } 1272*15934Smckusick putleaf( P2ICON , width( ap ) , 0 , P2INT , (char *) 0 ); 1273766Speter putop( P2LISTOP , P2INT ); 1274766Speter putop( P2CALL , P2INT ); 1275766Speter putdot( filename , line ); 12769139Smckusick if (opt('t') && op == O_NEW) { 12779139Smckusick putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 12789139Smckusick , "_blkclr" ); 1279*15934Smckusick (void) stkrval(alv, NLNIL , (long) RREQ ); 1280*15934Smckusick putleaf( P2ICON , width( ap ) , 0 , P2INT , (char *) 0 ); 12819139Smckusick putop( P2LISTOP , P2INT ); 12829139Smckusick putop( P2CALL , P2INT ); 12839139Smckusick putdot( filename , line ); 12849139Smckusick } 1285766Speter return; 1286766Speter 1287766Speter case O_DATE: 1288766Speter case O_TIME: 1289766Speter if (argc != 1) { 1290766Speter error("%s expects one argument", p->symbol); 1291766Speter return; 1292766Speter } 1293766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1294766Speter , op == O_DATE ? "_DATE" : "_TIME" ); 1295*15934Smckusick ap = stklval(argv->list_node.list, MOD|NOUSE); 1296766Speter if (ap == NIL) 1297766Speter return; 1298766Speter if (classify(ap) != TSTR || width(ap) != 10) { 1299766Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 1300766Speter return; 1301766Speter } 1302766Speter putop( P2CALL , P2INT ); 1303766Speter putdot( filename , line ); 1304766Speter return; 1305766Speter 1306766Speter case O_HALT: 1307766Speter if (argc != 0) { 1308766Speter error("halt takes no arguments"); 1309766Speter return; 1310766Speter } 1311766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1312766Speter , "_HALT" ); 1313766Speter 1314766Speter putop( P2UNARY P2CALL , P2INT ); 1315766Speter putdot( filename , line ); 1316*15934Smckusick noreach = TRUE; 1317766Speter return; 1318766Speter 1319766Speter case O_ARGV: 1320766Speter if (argc != 2) { 1321766Speter error("argv takes two arguments"); 1322766Speter return; 1323766Speter } 1324766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1325766Speter , "_ARGV" ); 1326*15934Smckusick ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ ); 1327*15934Smckusick if (ap == NLNIL) 1328766Speter return; 1329766Speter if (isnta(ap, "i")) { 1330766Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 1331766Speter return; 1332766Speter } 1333*15934Smckusick al = argv->list_node.next; 1334*15934Smckusick ap = stklval(al->list_node.list, MOD|NOUSE); 1335*15934Smckusick if (ap == NLNIL) 1336766Speter return; 1337766Speter if (classify(ap) != TSTR) { 1338766Speter error("argv's second argument must be a string, not %s", nameof(ap)); 1339766Speter return; 1340766Speter } 1341766Speter putop( P2LISTOP , P2INT ); 1342*15934Smckusick putleaf( P2ICON , width( ap ) , 0 , P2INT , (char *) 0 ); 1343766Speter putop( P2LISTOP , P2INT ); 1344766Speter putop( P2CALL , P2INT ); 1345766Speter putdot( filename , line ); 1346766Speter return; 1347766Speter 1348766Speter case O_STLIM: 1349766Speter if (argc != 1) { 1350766Speter error("stlimit requires one argument"); 1351766Speter return; 1352766Speter } 1353766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1354766Speter , "_STLIM" ); 1355*15934Smckusick ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ ); 1356*15934Smckusick if (ap == NLNIL) 1357766Speter return; 1358766Speter if (isnta(ap, "i")) { 1359766Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 1360766Speter return; 1361766Speter } 1362766Speter putop( P2CALL , P2INT ); 1363766Speter putdot( filename , line ); 1364766Speter return; 1365766Speter 1366766Speter case O_REMOVE: 1367766Speter if (argc != 1) { 1368766Speter error("remove expects one argument"); 1369766Speter return; 1370766Speter } 1371766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1372766Speter , "_REMOVE" ); 1373*15934Smckusick ap = stkrval(argv->list_node.list, NLNIL, (long) RREQ ); 1374*15934Smckusick if (ap == NLNIL) 1375766Speter return; 1376766Speter if (classify(ap) != TSTR) { 1377766Speter error("remove's argument must be a string, not %s", nameof(ap)); 1378766Speter return; 1379766Speter } 1380*15934Smckusick putleaf( P2ICON , width( ap ) , 0 , P2INT , (char *) 0 ); 1381766Speter putop( P2LISTOP , P2INT ); 1382766Speter putop( P2CALL , P2INT ); 1383766Speter putdot( filename , line ); 1384766Speter return; 1385766Speter 1386766Speter case O_LLIMIT: 1387766Speter if (argc != 2) { 1388766Speter error("linelimit expects two arguments"); 1389766Speter return; 1390766Speter } 1391766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1392766Speter , "_LLIMIT" ); 1393*15934Smckusick ap = stklval(argv->list_node.list, NOFLAGS|NOUSE); 1394*15934Smckusick if (ap == NLNIL) 1395766Speter return; 1396766Speter if (!text(ap)) { 1397766Speter error("linelimit's first argument must be a text file, not %s", nameof(ap)); 1398766Speter return; 1399766Speter } 1400*15934Smckusick al = argv->list_node.next; 1401*15934Smckusick ap = stkrval(al->list_node.list, NLNIL , (long) RREQ ); 1402*15934Smckusick if (ap == NLNIL) 1403766Speter return; 1404766Speter if (isnta(ap, "i")) { 1405766Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 1406766Speter return; 1407766Speter } 1408766Speter putop( P2LISTOP , P2INT ); 1409766Speter putop( P2CALL , P2INT ); 1410766Speter putdot( filename , line ); 1411766Speter return; 1412766Speter case O_PAGE: 1413766Speter if (argc != 1) { 1414766Speter error("page expects one argument"); 1415766Speter return; 1416766Speter } 1417*15934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1418766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1419766Speter , "_UNIT" ); 1420*15934Smckusick ap = stklval(argv->list_node.list, NOFLAGS); 1421*15934Smckusick if (ap == NLNIL) 1422766Speter return; 1423766Speter if (!text(ap)) { 1424766Speter error("Argument to page must be a text file, not %s", nameof(ap)); 1425766Speter return; 1426766Speter } 1427766Speter putop( P2CALL , P2INT ); 1428766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1429766Speter putdot( filename , line ); 1430766Speter if ( opt( 't' ) ) { 1431766Speter putleaf( P2ICON , 0 , 0 1432766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1433766Speter , "_PAGE" ); 1434*15934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1435766Speter } else { 1436766Speter putleaf( P2ICON , 0 , 0 1437766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1438766Speter , "_fputc" ); 1439*15934Smckusick putleaf( P2ICON , '\f' , 0 , (int) P2CHAR , (char *) 0 ); 1440766Speter putleaf( P2ICON , 0 , 0 1441766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1442766Speter , "_ACTFILE" ); 1443*15934Smckusick putRV((char *) 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1444766Speter putop( P2CALL , P2INT ); 1445766Speter putop( P2LISTOP , P2INT ); 1446766Speter } 1447766Speter putop( P2CALL , P2INT ); 1448766Speter putdot( filename , line ); 1449766Speter return; 1450766Speter 14517928Smckusick case O_ASRT: 14527928Smckusick if (!opt('t')) 14537928Smckusick return; 14547928Smckusick if (argc == 0 || argc > 2) { 14557928Smckusick error("Assert expects one or two arguments"); 14567928Smckusick return; 14577928Smckusick } 14589139Smckusick if (argc == 2) 14599139Smckusick cmd = "_ASRTS"; 14609139Smckusick else 14619139Smckusick cmd = "_ASRT"; 14627928Smckusick putleaf( P2ICON , 0 , 0 14639139Smckusick , ADDTYPE( P2FTN | P2INT , P2PTR ) , cmd ); 1464*15934Smckusick ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ ); 1465*15934Smckusick if (ap == NLNIL) 14667928Smckusick return; 14677928Smckusick if (isnta(ap, "b")) 14687928Smckusick error("Assert expression must be Boolean, not %ss", nameof(ap)); 14697928Smckusick if (argc == 2) { 14707928Smckusick /* 14717928Smckusick * Optional second argument is a string specifying 14727928Smckusick * why the assertion failed. 14737928Smckusick */ 1474*15934Smckusick al = argv->list_node.next; 1475*15934Smckusick al = (struct tnode *) stkrval(al->list_node.list, NLNIL , (long) RREQ ); 1476*15934Smckusick if (al == TR_NIL) 14777928Smckusick return; 1478*15934Smckusick if (classify((struct nl *) al) != TSTR) { 1479*15934Smckusick error("Second argument to assert must be a string, not %s", nameof((struct nl *) al)); 14807928Smckusick return; 14817928Smckusick } 14829139Smckusick putop( P2LISTOP , P2INT ); 14837928Smckusick } 14847928Smckusick putop( P2CALL , P2INT ); 14857928Smckusick putdot( filename , line ); 14867928Smckusick return; 14877928Smckusick 1488766Speter case O_PACK: 1489766Speter if (argc != 3) { 1490766Speter error("pack expects three arguments"); 1491766Speter return; 1492766Speter } 1493766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1494766Speter , "_PACK" ); 1495766Speter pu = "pack(a,i,z)"; 1496*15934Smckusick pua = (al = argv)->list_node.list; 1497*15934Smckusick pui = (al = al->list_node.next)->list_node.list; 1498*15934Smckusick puz = (al = al->list_node.next)->list_node.list; 1499766Speter goto packunp; 1500766Speter case O_UNPACK: 1501766Speter if (argc != 3) { 1502766Speter error("unpack expects three arguments"); 1503766Speter return; 1504766Speter } 1505766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1506766Speter , "_UNPACK" ); 1507766Speter pu = "unpack(z,a,i)"; 1508*15934Smckusick puz = (al = argv)->list_node.list; 1509*15934Smckusick pua = (al = al->list_node.next)->list_node.list; 1510*15934Smckusick pui = (al = al->list_node.next)->list_node.list; 1511766Speter packunp: 1512*15934Smckusick ap = stkrval(pui, NLNIL , (long) RREQ ); 1513766Speter if (ap == NIL) 1514766Speter return; 1515766Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 1516766Speter if (ap == NIL) 1517766Speter return; 1518766Speter if (ap->class != ARRAY) { 1519766Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 1520766Speter return; 1521766Speter } 1522766Speter putop( P2LISTOP , P2INT ); 1523*15934Smckusick al = (struct tnode *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 1524*15934Smckusick if (((struct nl *) al)->class != ARRAY) { 1525766Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 1526766Speter return; 1527766Speter } 1528*15934Smckusick if (((struct nl *) al)->type == NIL || 1529*15934Smckusick ((struct nl *) ap)->type == NIL) 1530766Speter return; 1531*15934Smckusick if (((struct nl *) al)->type != ((struct nl *) ap)->type) { 1532766Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 1533766Speter return; 1534766Speter } 1535766Speter putop( P2LISTOP , P2INT ); 1536*15934Smckusick k = width((struct nl *) al); 1537766Speter itemwidth = width(ap->type); 1538766Speter ap = ap->chain; 1539*15934Smckusick al = ((struct tnode *) ((struct nl *) al)->chain); 1540*15934Smckusick if (ap->chain != NIL || ((struct nl *) al)->chain != NIL) { 1541766Speter error("%s requires a and z to be single dimension arrays", pu); 1542766Speter return; 1543766Speter } 1544766Speter if (ap == NIL || al == NIL) 1545766Speter return; 1546766Speter /* 1547766Speter * al is the range for z i.e. u..v 1548766Speter * ap is the range for a i.e. m..n 1549766Speter * i will be n-m+1 1550766Speter * j will be v-u+1 1551766Speter */ 1552766Speter i = ap->range[1] - ap->range[0] + 1; 1553*15934Smckusick j = ((struct nl *) al)->range[1] - 1554*15934Smckusick ((struct nl *) al)->range[0] + 1; 1555766Speter if (i < j) { 1556*15934Smckusick error("%s cannot have more elements in a (%d) than in z (%d)", pu, (char *) j, (char *) i); 1557766Speter return; 1558766Speter } 1559766Speter /* 1560766Speter * get n-m-(v-u) and m for the interpreter 1561766Speter */ 1562766Speter i -= j; 1563766Speter j = ap->range[0]; 1564*15934Smckusick putleaf( P2ICON , itemwidth , 0 , P2INT , (char *) 0 ); 1565766Speter putop( P2LISTOP , P2INT ); 1566*15934Smckusick putleaf( P2ICON , j , 0 , P2INT , (char *) 0 ); 1567766Speter putop( P2LISTOP , P2INT ); 1568*15934Smckusick putleaf( P2ICON , i , 0 , P2INT , (char *) 0 ); 1569766Speter putop( P2LISTOP , P2INT ); 1570*15934Smckusick putleaf( P2ICON , k , 0 , P2INT , (char *) 0 ); 1571766Speter putop( P2LISTOP , P2INT ); 1572766Speter putop( P2CALL , P2INT ); 1573766Speter putdot( filename , line ); 1574766Speter return; 1575766Speter case 0: 15767928Smckusick error("%s is an unimplemented extension", p->symbol); 1577766Speter return; 1578766Speter 1579766Speter default: 1580766Speter panic("proc case"); 1581766Speter } 1582766Speter } 1583766Speter #endif PC 1584