1766Speter /* Copyright (c) 1979 Regents of the University of California */ 2766Speter 3*11333Speter static char sccsid[] = "@(#)pcproc.c 1.19 02/28/83"; 4766Speter 5766Speter #include "whoami.h" 6766Speter #ifdef PC 7766Speter /* 8766Speter * and to the end of the file 9766Speter */ 10766Speter #include "0.h" 11766Speter #include "tree.h" 1210372Speter #include "objfmt.h" 13766Speter #include "opcode.h" 1410372Speter #include "pc.h" 1510372Speter #include "pcops.h" 16*11333Speter #include "tmps.h" 17766Speter 18766Speter /* 199229Smckusick * The constant REALSPC defines the amount of forced padding preceeding 209229Smckusick * real numbers when they are printed. If REALSPC == 0, then no padding 219229Smckusick * is added, REALSPC == 1 adds one extra blank irregardless of the width 229229Smckusick * specified by the user. 239229Smckusick * 249229Smckusick * N.B. - Values greater than one require program mods. 259229Smckusick */ 269229Smckusick #define REALSPC 0 279229Smckusick 289229Smckusick /* 29766Speter * The following array is used to determine which classes may be read 30766Speter * from textfiles. It is indexed by the return value from classify. 31766Speter */ 32766Speter #define rdops(x) rdxxxx[(x)-(TFIRST)] 33766Speter 34766Speter int rdxxxx[] = { 35766Speter 0, /* -7 file types */ 36766Speter 0, /* -6 record types */ 37766Speter 0, /* -5 array types */ 38766Speter O_READE, /* -4 scalar types */ 39766Speter 0, /* -3 pointer types */ 40766Speter 0, /* -2 set types */ 41766Speter 0, /* -1 string types */ 42766Speter 0, /* 0 nil, no type */ 43766Speter O_READE, /* 1 boolean */ 44766Speter O_READC, /* 2 character */ 45766Speter O_READ4, /* 3 integer */ 46766Speter O_READ8 /* 4 real */ 47766Speter }; 48766Speter 49766Speter /* 50766Speter * Proc handles procedure calls. 51766Speter * Non-builtin procedures are "buck-passed" to func (with a flag 52766Speter * indicating that they are actually procedures. 53766Speter * builtin procedures are handled here. 54766Speter */ 55766Speter pcproc(r) 56766Speter int *r; 57766Speter { 58766Speter register struct nl *p; 59766Speter register int *alv, *al, op; 60766Speter struct nl *filetype, *ap; 61766Speter int argc, *argv, typ, fmtspec, strfmt, stkcnt, *file; 627967Smckusick char fmt, format[20], *strptr, *cmd; 63766Speter int prec, field, strnglen, fmtlen, fmtstart, pu; 64766Speter int *pua, *pui, *puz; 65766Speter int i, j, k; 66766Speter int itemwidth; 673833Speter char *readname; 683833Speter struct nl *tempnlp; 693833Speter long readtype; 703833Speter struct tmps soffset; 71766Speter 72766Speter #define CONPREC 4 73766Speter #define VARPREC 8 74766Speter #define CONWIDTH 1 75766Speter #define VARWIDTH 2 76766Speter #define SKIP 16 77766Speter 78766Speter /* 79766Speter * Verify that the name is 80766Speter * defined and is that of a 81766Speter * procedure. 82766Speter */ 83766Speter p = lookup(r[2]); 84766Speter if (p == NIL) { 85766Speter rvlist(r[3]); 86766Speter return; 87766Speter } 881197Speter if (p->class != PROC && p->class != FPROC) { 89766Speter error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]); 90766Speter rvlist(r[3]); 91766Speter return; 92766Speter } 93766Speter argv = r[3]; 94766Speter 95766Speter /* 96766Speter * Call handles user defined 97766Speter * procedures and functions. 98766Speter */ 99766Speter if (bn != 0) { 100766Speter call(p, argv, PROC, bn); 101766Speter return; 102766Speter } 103766Speter 104766Speter /* 105766Speter * Call to built-in procedure. 106766Speter * Count the arguments. 107766Speter */ 108766Speter argc = 0; 109766Speter for (al = argv; al != NIL; al = al[2]) 110766Speter argc++; 111766Speter 112766Speter /* 113766Speter * Switch on the operator 114766Speter * associated with the built-in 115766Speter * procedure in the namelist 116766Speter */ 117766Speter op = p->value[0] &~ NSTAND; 118766Speter if (opt('s') && (p->value[0] & NSTAND)) { 119766Speter standard(); 120766Speter error("%s is a nonstandard procedure", p->symbol); 121766Speter } 122766Speter switch (op) { 123766Speter 124766Speter case O_ABORT: 125766Speter if (argc != 0) 126766Speter error("null takes no arguments"); 127766Speter return; 128766Speter 129766Speter case O_FLUSH: 130766Speter if (argc == 0) { 131766Speter putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" ); 132766Speter putop( P2UNARY P2CALL , P2INT ); 133766Speter putdot( filename , line ); 134766Speter return; 135766Speter } 136766Speter if (argc != 1) { 137766Speter error("flush takes at most one argument"); 138766Speter return; 139766Speter } 140766Speter putleaf( P2ICON , 0 , 0 141766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 142766Speter , "_FLUSH" ); 143766Speter ap = stklval(argv[1], NOFLAGS); 144766Speter if (ap == NIL) 145766Speter return; 146766Speter if (ap->class != FILET) { 147766Speter error("flush's argument must be a file, not %s", nameof(ap)); 148766Speter return; 149766Speter } 150766Speter putop( P2CALL , P2INT ); 151766Speter putdot( filename , line ); 152766Speter return; 153766Speter 154766Speter case O_MESSAGE: 155766Speter case O_WRITEF: 156766Speter case O_WRITLN: 157766Speter /* 158766Speter * Set up default file "output"'s type 159766Speter */ 160766Speter file = NIL; 161766Speter filetype = nl+T1CHAR; 162766Speter /* 163766Speter * Determine the file implied 164766Speter * for the write and generate 165766Speter * code to make it the active file. 166766Speter */ 167766Speter if (op == O_MESSAGE) { 168766Speter /* 169766Speter * For message, all that matters 170766Speter * is that the filetype is 171766Speter * a character file. 172766Speter * Thus "output" will suit us fine. 173766Speter */ 174766Speter putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" ); 175766Speter putop( P2UNARY P2CALL , P2INT ); 176766Speter putdot( filename , line ); 1773833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 1783833Speter P2PTR|P2STRTY ); 1793833Speter putLV( "__err" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 180766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 181766Speter putdot( filename , line ); 182766Speter } else if (argv != NIL && (al = argv[1])[0] != T_WEXP) { 183766Speter /* 184766Speter * If there is a first argument which has 185766Speter * no write widths, then it is potentially 186766Speter * a file name. 187766Speter */ 188766Speter codeoff(); 189766Speter ap = stkrval(argv[1], NIL , RREQ ); 190766Speter codeon(); 191766Speter if (ap == NIL) 192766Speter argv = argv[2]; 193766Speter if (ap != NIL && ap->class == FILET) { 194766Speter /* 195766Speter * Got "write(f, ...", make 196766Speter * f the active file, and save 197766Speter * it and its type for use in 198766Speter * processing the rest of the 199766Speter * arguments to write. 200766Speter */ 2013833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 2023833Speter P2PTR|P2STRTY ); 203766Speter putleaf( P2ICON , 0 , 0 204766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 205766Speter , "_UNIT" ); 206766Speter file = argv[1]; 207766Speter filetype = ap->type; 208766Speter stklval(argv[1], NOFLAGS); 209766Speter putop( P2CALL , P2INT ); 210766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 211766Speter putdot( filename , line ); 212766Speter /* 213766Speter * Skip over the first argument 214766Speter */ 215766Speter argv = argv[2]; 216766Speter argc--; 217766Speter } else { 218766Speter /* 219766Speter * Set up for writing on 220766Speter * standard output. 221766Speter */ 2223833Speter putRV( 0, cbn , CURFILEOFFSET , 2233833Speter NLOCAL , P2PTR|P2STRTY ); 2243833Speter putLV( "_output" , 0 , 0 , NGLOBAL , 2253833Speter P2PTR|P2STRTY ); 226766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 227766Speter putdot( filename , line ); 2287954Speter output->nl_flags |= NUSED; 229766Speter } 230766Speter } else { 2313833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 2323833Speter P2PTR|P2STRTY ); 2333833Speter putLV( "_output" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 234766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 235766Speter putdot( filename , line ); 2367954Speter output->nl_flags |= NUSED; 237766Speter } 238766Speter /* 239766Speter * Loop and process each 240766Speter * of the arguments. 241766Speter */ 242766Speter for (; argv != NIL; argv = argv[2]) { 243766Speter /* 244766Speter * fmtspec indicates the type (CONstant or VARiable) 245766Speter * and number (none, WIDTH, and/or PRECision) 246766Speter * of the fields in the printf format for this 247766Speter * output variable. 248766Speter * stkcnt is the number of longs pushed on the stack 249766Speter * fmt is the format output indicator (D, E, F, O, X, S) 250766Speter * fmtstart = 0 for leading blank; = 1 for no blank 251766Speter */ 252766Speter fmtspec = NIL; 253766Speter stkcnt = 0; 254766Speter fmt = 'D'; 255766Speter fmtstart = 1; 256766Speter al = argv[1]; 257766Speter if (al == NIL) 258766Speter continue; 259766Speter if (al[0] == T_WEXP) 260766Speter alv = al[1]; 261766Speter else 262766Speter alv = al; 263766Speter if (alv == NIL) 264766Speter continue; 265766Speter codeoff(); 266766Speter ap = stkrval(alv, NIL , RREQ ); 267766Speter codeon(); 268766Speter if (ap == NIL) 269766Speter continue; 270766Speter typ = classify(ap); 271766Speter if (al[0] == T_WEXP) { 272766Speter /* 273766Speter * Handle width expressions. 274766Speter * The basic game here is that width 275766Speter * expressions get evaluated. If they 276766Speter * are constant, the value is placed 277766Speter * directly in the format string. 278766Speter * Otherwise the value is pushed onto 279766Speter * the stack and an indirection is 280766Speter * put into the format string. 281766Speter */ 282766Speter if (al[3] == OCT) 283766Speter fmt = 'O'; 284766Speter else if (al[3] == HEX) 285766Speter fmt = 'X'; 286766Speter else if (al[3] != NIL) { 287766Speter /* 288766Speter * Evaluate second format spec 289766Speter */ 290766Speter if ( constval(al[3]) 291766Speter && isa( con.ctype , "i" ) ) { 292766Speter fmtspec += CONPREC; 293766Speter prec = con.crval; 294766Speter } else { 295766Speter fmtspec += VARPREC; 296766Speter } 297766Speter fmt = 'f'; 298766Speter switch ( typ ) { 299766Speter case TINT: 300766Speter if ( opt( 's' ) ) { 301766Speter standard(); 302766Speter error("Writing %ss with two write widths is non-standard", clnames[typ]); 303766Speter } 304766Speter /* and fall through */ 305766Speter case TDOUBLE: 306766Speter break; 307766Speter default: 308766Speter error("Cannot write %ss with two write widths", clnames[typ]); 309766Speter continue; 310766Speter } 311766Speter } 312766Speter /* 313766Speter * Evaluate first format spec 314766Speter */ 315766Speter if (al[2] != NIL) { 316766Speter if ( constval(al[2]) 317766Speter && isa( con.ctype , "i" ) ) { 318766Speter fmtspec += CONWIDTH; 319766Speter field = con.crval; 320766Speter } else { 321766Speter fmtspec += VARWIDTH; 322766Speter } 323766Speter } 324766Speter if ((fmtspec & CONPREC) && prec < 0 || 325766Speter (fmtspec & CONWIDTH) && field < 0) { 326766Speter error("Negative widths are not allowed"); 327766Speter continue; 328766Speter } 3293180Smckusic if ( opt('s') && 3303180Smckusic ((fmtspec & CONPREC) && prec == 0 || 3313180Smckusic (fmtspec & CONWIDTH) && field == 0)) { 3323180Smckusic standard(); 3333180Smckusic error("Zero widths are non-standard"); 3343180Smckusic } 335766Speter } 336766Speter if (filetype != nl+T1CHAR) { 337766Speter if (fmt == 'O' || fmt == 'X') { 338766Speter error("Oct/hex allowed only on text files"); 339766Speter continue; 340766Speter } 341766Speter if (fmtspec) { 342766Speter error("Write widths allowed only on text files"); 343766Speter continue; 344766Speter } 345766Speter /* 346766Speter * Generalized write, i.e. 347766Speter * to a non-textfile. 348766Speter */ 349766Speter putleaf( P2ICON , 0 , 0 350766Speter , ADDTYPE( 351766Speter ADDTYPE( 352766Speter ADDTYPE( p2type( filetype ) 353766Speter , P2PTR ) 354766Speter , P2FTN ) 355766Speter , P2PTR ) 356766Speter , "_FNIL" ); 357766Speter stklval(file, NOFLAGS); 358766Speter putop( P2CALL 359766Speter , ADDTYPE( p2type( filetype ) , P2PTR ) ); 360766Speter putop( P2UNARY P2MUL , p2type( filetype ) ); 361766Speter /* 362766Speter * file^ := ... 363766Speter */ 364766Speter switch ( classify( filetype ) ) { 365766Speter case TBOOL: 366766Speter case TCHAR: 367766Speter case TINT: 368766Speter case TSCAL: 3694589Speter precheck( filetype , "_RANG4" , "_RSNG4" ); 370766Speter /* and fall through */ 371766Speter case TDOUBLE: 372766Speter case TPTR: 373766Speter ap = rvalue( argv[1] , filetype , RREQ ); 374766Speter break; 375766Speter default: 376766Speter ap = rvalue( argv[1] , filetype , LREQ ); 377766Speter break; 378766Speter } 379766Speter if (ap == NIL) 380766Speter continue; 381766Speter if (incompat(ap, filetype, argv[1])) { 382766Speter cerror("Type mismatch in write to non-text file"); 383766Speter continue; 384766Speter } 385766Speter switch ( classify( filetype ) ) { 386766Speter case TBOOL: 387766Speter case TCHAR: 388766Speter case TINT: 389766Speter case TSCAL: 39010373Speter postcheck(filetype, ap); 39110373Speter sconv(p2type(ap), p2type(filetype)); 392766Speter /* and fall through */ 393766Speter case TDOUBLE: 394766Speter case TPTR: 395766Speter putop( P2ASSIGN , p2type( filetype ) ); 396766Speter putdot( filename , line ); 397766Speter break; 398766Speter default: 399766Speter putstrop( P2STASG 400766Speter , p2type( filetype ) 401766Speter , lwidth( filetype ) 402766Speter , align( filetype ) ); 403766Speter putdot( filename , line ); 404766Speter break; 405766Speter } 406766Speter /* 407766Speter * put(file) 408766Speter */ 409766Speter putleaf( P2ICON , 0 , 0 410766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 411766Speter , "_PUT" ); 4123833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 4133833Speter P2PTR|P2STRTY ); 414766Speter putop( P2CALL , P2INT ); 415766Speter putdot( filename , line ); 416766Speter continue; 417766Speter } 418766Speter /* 419766Speter * Write to a textfile 420766Speter * 421766Speter * Evaluate the expression 422766Speter * to be written. 423766Speter */ 424766Speter if (fmt == 'O' || fmt == 'X') { 425766Speter if (opt('s')) { 426766Speter standard(); 427766Speter error("Oct and hex are non-standard"); 428766Speter } 429766Speter if (typ == TSTR || typ == TDOUBLE) { 430766Speter error("Can't write %ss with oct/hex", clnames[typ]); 431766Speter continue; 432766Speter } 433766Speter if (typ == TCHAR || typ == TBOOL) 434766Speter typ = TINT; 435766Speter } 436766Speter /* 437766Speter * If there is no format specified by the programmer, 438766Speter * implement the default. 439766Speter */ 440766Speter switch (typ) { 4416540Smckusick case TPTR: 4426540Smckusick warning(); 4436540Smckusick if (opt('s')) { 4446540Smckusick standard(); 4456540Smckusick } 4466540Smckusick error("Writing %ss to text files is non-standard", 4476540Smckusick clnames[typ]); 4486540Smckusick /* and fall through */ 449766Speter case TINT: 450766Speter if (fmt == 'f') { 451766Speter typ = TDOUBLE; 452766Speter goto tdouble; 453766Speter } 454766Speter if (fmtspec == NIL) { 455766Speter if (fmt == 'D') 456766Speter field = 10; 457766Speter else if (fmt == 'X') 458766Speter field = 8; 459766Speter else if (fmt == 'O') 460766Speter field = 11; 461766Speter else 462766Speter panic("fmt1"); 463766Speter fmtspec = CONWIDTH; 464766Speter } 465766Speter break; 466766Speter case TCHAR: 467766Speter tchar: 468766Speter fmt = 'c'; 469766Speter break; 470766Speter case TSCAL: 4711629Speter warning(); 472766Speter if (opt('s')) { 473766Speter standard(); 474766Speter } 4756540Smckusick error("Writing %ss to text files is non-standard", 4766540Smckusick clnames[typ]); 477766Speter case TBOOL: 478766Speter fmt = 's'; 479766Speter break; 480766Speter case TDOUBLE: 481766Speter tdouble: 482766Speter switch (fmtspec) { 483766Speter case NIL: 484766Speter field = 21; 485766Speter prec = 14; 4863225Smckusic fmt = 'e'; 487766Speter fmtspec = CONWIDTH + CONPREC; 488766Speter break; 489766Speter case CONWIDTH: 4909229Smckusick field -= REALSPC; 4919229Smckusick if (field < 1) 492766Speter field = 1; 493766Speter prec = field - 7; 494766Speter if (prec < 1) 495766Speter prec = 1; 496766Speter fmtspec += CONPREC; 4973225Smckusic fmt = 'e'; 498766Speter break; 499766Speter case VARWIDTH: 500766Speter fmtspec += VARPREC; 5013225Smckusic fmt = 'e'; 502766Speter break; 503766Speter case CONWIDTH + CONPREC: 504766Speter case CONWIDTH + VARPREC: 5059229Smckusick field -= REALSPC; 5069229Smckusick if (field < 1) 507766Speter field = 1; 508766Speter } 509766Speter format[0] = ' '; 5109229Smckusick fmtstart = 1 - REALSPC; 511766Speter break; 512766Speter case TSTR: 513766Speter constval( alv ); 514766Speter switch ( classify( con.ctype ) ) { 515766Speter case TCHAR: 516766Speter typ = TCHAR; 517766Speter goto tchar; 518766Speter case TSTR: 519766Speter strptr = con.cpval; 520766Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 521766Speter strptr = con.cpval; 522766Speter break; 523766Speter default: 524766Speter strnglen = width(ap); 525766Speter break; 526766Speter } 527766Speter fmt = 's'; 528766Speter strfmt = fmtspec; 529766Speter if (fmtspec == NIL) { 530766Speter fmtspec = SKIP; 531766Speter break; 532766Speter } 533766Speter if (fmtspec & CONWIDTH) { 534766Speter if (field <= strnglen) 535766Speter fmtspec = SKIP; 536766Speter else 537766Speter field -= strnglen; 538766Speter } 539766Speter break; 540766Speter default: 541766Speter error("Can't write %ss to a text file", clnames[typ]); 542766Speter continue; 543766Speter } 544766Speter /* 545766Speter * Generate the format string 546766Speter */ 547766Speter switch (fmtspec) { 548766Speter default: 549766Speter panic("fmt2"); 550766Speter case NIL: 551766Speter if (fmt == 'c') { 552766Speter if ( opt( 't' ) ) { 553766Speter putleaf( P2ICON , 0 , 0 554766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 555766Speter , "_WRITEC" ); 5563833Speter putRV( 0 , cbn , CURFILEOFFSET , 5573833Speter NLOCAL , P2PTR|P2STRTY ); 558766Speter stkrval( alv , NIL , RREQ ); 559766Speter putop( P2LISTOP , P2INT ); 560766Speter } else { 561766Speter putleaf( P2ICON , 0 , 0 562766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 563766Speter , "_fputc" ); 564766Speter stkrval( alv , NIL , RREQ ); 565766Speter } 566766Speter putleaf( P2ICON , 0 , 0 567766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 568766Speter , "_ACTFILE" ); 5693833Speter putRV( 0, cbn , CURFILEOFFSET , 5703833Speter NLOCAL , P2PTR|P2STRTY ); 571766Speter putop( P2CALL , P2INT ); 572766Speter putop( P2LISTOP , P2INT ); 573766Speter putop( P2CALL , P2INT ); 574766Speter putdot( filename , line ); 575766Speter } else { 576766Speter sprintf(&format[1], "%%%c", fmt); 577766Speter goto fmtgen; 578766Speter } 579766Speter case SKIP: 580766Speter break; 581766Speter case CONWIDTH: 582766Speter sprintf(&format[1], "%%%1D%c", field, fmt); 583766Speter goto fmtgen; 584766Speter case VARWIDTH: 585766Speter sprintf(&format[1], "%%*%c", fmt); 586766Speter goto fmtgen; 587766Speter case CONWIDTH + CONPREC: 588766Speter sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt); 589766Speter goto fmtgen; 590766Speter case CONWIDTH + VARPREC: 591766Speter sprintf(&format[1], "%%%1D.*%c", field, fmt); 592766Speter goto fmtgen; 593766Speter case VARWIDTH + CONPREC: 594766Speter sprintf(&format[1], "%%*.%1D%c", prec, fmt); 595766Speter goto fmtgen; 596766Speter case VARWIDTH + VARPREC: 597766Speter sprintf(&format[1], "%%*.*%c", fmt); 598766Speter fmtgen: 599766Speter if ( opt( 't' ) ) { 600766Speter putleaf( P2ICON , 0 , 0 601766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 602766Speter , "_WRITEF" ); 6033833Speter putRV( 0 , cbn , CURFILEOFFSET , 6043833Speter NLOCAL , P2PTR|P2STRTY ); 605766Speter putleaf( P2ICON , 0 , 0 606766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 607766Speter , "_ACTFILE" ); 6083833Speter putRV( 0 , cbn , CURFILEOFFSET , 6093833Speter NLOCAL , P2PTR|P2STRTY ); 610766Speter putop( P2CALL , P2INT ); 611766Speter putop( P2LISTOP , P2INT ); 612766Speter } else { 613766Speter putleaf( P2ICON , 0 , 0 614766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 615766Speter , "_fprintf" ); 616766Speter putleaf( P2ICON , 0 , 0 617766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 618766Speter , "_ACTFILE" ); 6193833Speter putRV( 0 , cbn , CURFILEOFFSET , 6203833Speter NLOCAL , P2PTR|P2STRTY ); 621766Speter putop( P2CALL , P2INT ); 622766Speter } 623766Speter putCONG( &format[ fmtstart ] 624766Speter , strlen( &format[ fmtstart ] ) 625766Speter , LREQ ); 626766Speter putop( P2LISTOP , P2INT ); 627766Speter if ( fmtspec & VARWIDTH ) { 628766Speter /* 629766Speter * either 630766Speter * ,(temp=width,MAX(temp,...)), 631766Speter * or 632766Speter * , MAX( width , ... ) , 633766Speter */ 634766Speter if ( ( typ == TDOUBLE && al[3] == NIL ) 635766Speter || typ == TSTR ) { 6363225Smckusic soffset = sizes[cbn].curtmps; 6373833Speter tempnlp = tmpalloc(sizeof(long), 6383225Smckusic nl+T4INT, REGOK); 6393833Speter putRV( 0 , cbn , 6403833Speter tempnlp -> value[ NL_OFFS ] , 6413833Speter tempnlp -> extra_flags , P2INT ); 642766Speter ap = stkrval( al[2] , NIL , RREQ ); 643766Speter putop( P2ASSIGN , P2INT ); 644766Speter putleaf( P2ICON , 0 , 0 645766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 646766Speter , "_MAX" ); 6473833Speter putRV( 0 , cbn , 6483833Speter tempnlp -> value[ NL_OFFS ] , 6493833Speter tempnlp -> extra_flags , P2INT ); 650766Speter } else { 651766Speter if (opt('t') 652766Speter || typ == TSTR || typ == TDOUBLE) { 653766Speter putleaf( P2ICON , 0 , 0 654766Speter ,ADDTYPE( P2FTN | P2INT, P2PTR ) 655766Speter ,"_MAX" ); 656766Speter } 657766Speter ap = stkrval( al[2] , NIL , RREQ ); 658766Speter } 659766Speter if (ap == NIL) 660766Speter continue; 661766Speter if (isnta(ap,"i")) { 662766Speter error("First write width must be integer, not %s", nameof(ap)); 663766Speter continue; 664766Speter } 665766Speter switch ( typ ) { 666766Speter case TDOUBLE: 6679229Smckusick putleaf( P2ICON , REALSPC , 0 , P2INT , 0 ); 668766Speter putop( P2LISTOP , P2INT ); 669766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 670766Speter putop( P2LISTOP , P2INT ); 671766Speter putop( P2CALL , P2INT ); 672766Speter if ( al[3] == NIL ) { 673766Speter /* 674766Speter * finish up the comma op 675766Speter */ 676766Speter putop( P2COMOP , P2INT ); 677766Speter fmtspec &= ~VARPREC; 678766Speter putop( P2LISTOP , P2INT ); 679766Speter putleaf( P2ICON , 0 , 0 680766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 681766Speter , "_MAX" ); 6823833Speter putRV( 0 , cbn , 6833833Speter tempnlp -> value[ NL_OFFS ] , 6843833Speter tempnlp -> extra_flags , 6853833Speter P2INT ); 6863225Smckusic tmpfree(&soffset); 6879229Smckusick putleaf( P2ICON , 7 + REALSPC , 0 , P2INT , 0 ); 688766Speter putop( P2LISTOP , P2INT ); 689766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 690766Speter putop( P2LISTOP , P2INT ); 691766Speter putop( P2CALL , P2INT ); 692766Speter } 693766Speter putop( P2LISTOP , P2INT ); 694766Speter break; 695766Speter case TSTR: 696766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 697766Speter putop( P2LISTOP , P2INT ); 698766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 699766Speter putop( P2LISTOP , P2INT ); 700766Speter putop( P2CALL , P2INT ); 701766Speter putop( P2COMOP , P2INT ); 702766Speter putop( P2LISTOP , P2INT ); 703766Speter break; 704766Speter default: 705766Speter if (opt('t')) { 706766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 707766Speter putop( P2LISTOP , P2INT ); 708766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 709766Speter putop( P2LISTOP , P2INT ); 710766Speter putop( P2CALL , P2INT ); 711766Speter } 712766Speter putop( P2LISTOP , P2INT ); 713766Speter break; 714766Speter } 715766Speter } 716766Speter /* 717766Speter * If there is a variable precision, 718766Speter * evaluate it 719766Speter */ 720766Speter if (fmtspec & VARPREC) { 721766Speter if (opt('t')) { 722766Speter putleaf( P2ICON , 0 , 0 723766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 724766Speter , "_MAX" ); 725766Speter } 726766Speter ap = stkrval( al[3] , NIL , RREQ ); 727766Speter if (ap == NIL) 728766Speter continue; 729766Speter if (isnta(ap,"i")) { 730766Speter error("Second write width must be integer, not %s", nameof(ap)); 731766Speter continue; 732766Speter } 733766Speter if (opt('t')) { 734766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 735766Speter putop( P2LISTOP , P2INT ); 736766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 737766Speter putop( P2LISTOP , P2INT ); 738766Speter putop( P2CALL , P2INT ); 739766Speter } 740766Speter putop( P2LISTOP , P2INT ); 741766Speter } 742766Speter /* 743766Speter * evaluate the thing we want printed. 744766Speter */ 745766Speter switch ( typ ) { 7466540Smckusick case TPTR: 747766Speter case TCHAR: 748766Speter case TINT: 749766Speter stkrval( alv , NIL , RREQ ); 750766Speter putop( P2LISTOP , P2INT ); 751766Speter break; 752766Speter case TDOUBLE: 753766Speter ap = stkrval( alv , NIL , RREQ ); 75410373Speter if (isnta(ap, "d")) { 75510373Speter sconv(p2type(ap), P2DOUBLE); 756766Speter } 757766Speter putop( P2LISTOP , P2INT ); 758766Speter break; 759766Speter case TSCAL: 760766Speter case TBOOL: 761766Speter putleaf( P2ICON , 0 , 0 762766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 763766Speter , "_NAM" ); 764766Speter ap = stkrval( alv , NIL , RREQ ); 765766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 766766Speter , listnames( ap ) ); 767766Speter putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR 768766Speter , format ); 769766Speter putop( P2LISTOP , P2INT ); 770766Speter putop( P2CALL , P2INT ); 771766Speter putop( P2LISTOP , P2INT ); 772766Speter break; 773766Speter case TSTR: 774766Speter putCONG( "" , 0 , LREQ ); 775766Speter putop( P2LISTOP , P2INT ); 776766Speter break; 7776540Smckusick default: 7786540Smckusick panic("fmt3"); 7796540Smckusick break; 780766Speter } 781766Speter putop( P2CALL , P2INT ); 782766Speter putdot( filename , line ); 783766Speter } 784766Speter /* 785766Speter * Write the string after its blank padding 786766Speter */ 787766Speter if (typ == TSTR ) { 788766Speter if ( opt( 't' ) ) { 789766Speter putleaf( P2ICON , 0 , 0 790766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 791766Speter , "_WRITES" ); 7923833Speter putRV( 0 , cbn , CURFILEOFFSET , 7933833Speter NLOCAL , P2PTR|P2STRTY ); 794766Speter ap = stkrval(alv, NIL , RREQ ); 795766Speter putop( P2LISTOP , P2INT ); 796766Speter } else { 797766Speter putleaf( P2ICON , 0 , 0 798766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 799766Speter , "_fwrite" ); 800766Speter ap = stkrval(alv, NIL , RREQ ); 801766Speter } 802766Speter if (strfmt & VARWIDTH) { 803766Speter /* 804766Speter * min, inline expanded as 805766Speter * temp < len ? temp : len 806766Speter */ 8073833Speter putRV( 0 , cbn , 8083833Speter tempnlp -> value[ NL_OFFS ] , 8093833Speter tempnlp -> extra_flags , P2INT ); 810766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 811766Speter putop( P2LT , P2INT ); 8123833Speter putRV( 0 , cbn , 8133833Speter tempnlp -> value[ NL_OFFS ] , 8143833Speter tempnlp -> extra_flags , P2INT ); 815766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 816766Speter putop( P2COLON , P2INT ); 817766Speter putop( P2QUEST , P2INT ); 8183225Smckusic tmpfree(&soffset); 819766Speter } else { 820766Speter if ( ( fmtspec & SKIP ) 821766Speter && ( strfmt & CONWIDTH ) ) { 822766Speter strnglen = field; 823766Speter } 824766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 825766Speter } 826766Speter putop( P2LISTOP , P2INT ); 827766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 828766Speter putop( P2LISTOP , P2INT ); 829766Speter putleaf( P2ICON , 0 , 0 830766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 831766Speter , "_ACTFILE" ); 8323833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 8333833Speter P2PTR|P2STRTY ); 834766Speter putop( P2CALL , P2INT ); 835766Speter putop( P2LISTOP , P2INT ); 836766Speter putop( P2CALL , P2INT ); 837766Speter putdot( filename , line ); 838766Speter } 839766Speter } 840766Speter /* 841766Speter * Done with arguments. 842766Speter * Handle writeln and 843766Speter * insufficent number of args. 844766Speter */ 845766Speter switch (p->value[0] &~ NSTAND) { 846766Speter case O_WRITEF: 847766Speter if (argc == 0) 848766Speter error("Write requires an argument"); 849766Speter break; 850766Speter case O_MESSAGE: 851766Speter if (argc == 0) 852766Speter error("Message requires an argument"); 853766Speter case O_WRITLN: 854766Speter if (filetype != nl+T1CHAR) 855766Speter error("Can't 'writeln' a non text file"); 856766Speter if ( opt( 't' ) ) { 857766Speter putleaf( P2ICON , 0 , 0 858766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 859766Speter , "_WRITLN" ); 8603833Speter putRV( 0 , cbn , CURFILEOFFSET , 8613833Speter NLOCAL , P2PTR|P2STRTY ); 862766Speter } else { 863766Speter putleaf( P2ICON , 0 , 0 864766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 865766Speter , "_fputc" ); 866766Speter putleaf( P2ICON , '\n' , 0 , P2CHAR , 0 ); 867766Speter putleaf( P2ICON , 0 , 0 868766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 869766Speter , "_ACTFILE" ); 8703833Speter putRV( 0 , cbn , CURFILEOFFSET , 8713833Speter NLOCAL , P2PTR|P2STRTY ); 872766Speter putop( P2CALL , P2INT ); 873766Speter putop( P2LISTOP , P2INT ); 874766Speter } 875766Speter putop( P2CALL , P2INT ); 876766Speter putdot( filename , line ); 877766Speter break; 878766Speter } 879766Speter return; 880766Speter 881766Speter case O_READ4: 882766Speter case O_READLN: 883766Speter /* 884766Speter * Set up default 885766Speter * file "input". 886766Speter */ 887766Speter file = NIL; 888766Speter filetype = nl+T1CHAR; 889766Speter /* 890766Speter * Determine the file implied 891766Speter * for the read and generate 892766Speter * code to make it the active file. 893766Speter */ 894766Speter if (argv != NIL) { 895766Speter codeoff(); 896766Speter ap = stkrval(argv[1], NIL , RREQ ); 897766Speter codeon(); 898766Speter if (ap == NIL) 899766Speter argv = argv[2]; 900766Speter if (ap != NIL && ap->class == FILET) { 901766Speter /* 902766Speter * Got "read(f, ...", make 903766Speter * f the active file, and save 904766Speter * it and its type for use in 905766Speter * processing the rest of the 906766Speter * arguments to read. 907766Speter */ 908766Speter file = argv[1]; 909766Speter filetype = ap->type; 9103833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 9113833Speter P2PTR|P2STRTY ); 912766Speter putleaf( P2ICON , 0 , 0 913766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 914766Speter , "_UNIT" ); 915766Speter stklval(argv[1], NOFLAGS); 916766Speter putop( P2CALL , P2INT ); 917766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 918766Speter putdot( filename , line ); 919766Speter argv = argv[2]; 920766Speter argc--; 921766Speter } else { 922766Speter /* 923766Speter * Default is read from 924766Speter * standard input. 925766Speter */ 9263833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 9273833Speter P2PTR|P2STRTY ); 9283833Speter putLV( "_input" , 0 , 0 , NGLOBAL , 9293833Speter P2PTR|P2STRTY ); 930766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 931766Speter putdot( filename , line ); 932766Speter input->nl_flags |= NUSED; 933766Speter } 934766Speter } else { 9353833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 9363833Speter P2PTR|P2STRTY ); 9373833Speter putLV( "_input" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 938766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 939766Speter putdot( filename , line ); 940766Speter input->nl_flags |= NUSED; 941766Speter } 942766Speter /* 943766Speter * Loop and process each 944766Speter * of the arguments. 945766Speter */ 946766Speter for (; argv != NIL; argv = argv[2]) { 947766Speter /* 948766Speter * Get the address of the target 949766Speter * on the stack. 950766Speter */ 951766Speter al = argv[1]; 952766Speter if (al == NIL) 953766Speter continue; 954766Speter if (al[0] != T_VAR) { 955766Speter error("Arguments to %s must be variables, not expressions", p->symbol); 956766Speter continue; 957766Speter } 958766Speter codeoff(); 959766Speter ap = stklval(al, MOD|ASGN|NOUSE); 960766Speter codeon(); 961766Speter if (ap == NIL) 962766Speter continue; 963766Speter if (filetype != nl+T1CHAR) { 964766Speter /* 965766Speter * Generalized read, i.e. 966766Speter * from a non-textfile. 967766Speter */ 968766Speter if (incompat(filetype, ap, argv[1] )) { 969766Speter error("Type mismatch in read from non-text file"); 970766Speter continue; 971766Speter } 972766Speter /* 973766Speter * var := file ^; 974766Speter */ 975766Speter ap = lvalue( al , MOD | ASGN | NOUSE , RREQ ); 976766Speter if ( isa( ap , "bsci" ) ) { 977766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 978766Speter } 979766Speter putleaf( P2ICON , 0 , 0 980766Speter , ADDTYPE( 981766Speter ADDTYPE( 982766Speter ADDTYPE( 983766Speter p2type( filetype ) , P2PTR ) 984766Speter , P2FTN ) 985766Speter , P2PTR ) 986766Speter , "_FNIL" ); 987766Speter if (file != NIL) 988766Speter stklval(file, NOFLAGS); 989766Speter else /* Magic */ 9903833Speter putRV( "_input" , 0 , 0 , NGLOBAL , 9913833Speter P2PTR | P2STRTY ); 99210668Speter putop(P2CALL, ADDTYPE(p2type(filetype), P2PTR)); 993766Speter switch ( classify( filetype ) ) { 994766Speter case TBOOL: 995766Speter case TCHAR: 996766Speter case TINT: 997766Speter case TSCAL: 998766Speter case TDOUBLE: 999766Speter case TPTR: 1000766Speter putop( P2UNARY P2MUL 1001766Speter , p2type( filetype ) ); 1002766Speter } 1003766Speter switch ( classify( filetype ) ) { 1004766Speter case TBOOL: 1005766Speter case TCHAR: 1006766Speter case TINT: 1007766Speter case TSCAL: 100810373Speter postcheck(ap, filetype); 100910373Speter sconv(p2type(filetype), p2type(ap)); 1010766Speter /* and fall through */ 1011766Speter case TDOUBLE: 1012766Speter case TPTR: 1013766Speter putop( P2ASSIGN , p2type( ap ) ); 1014766Speter putdot( filename , line ); 1015766Speter break; 1016766Speter default: 1017766Speter putstrop( P2STASG 1018766Speter , p2type( ap ) 1019766Speter , lwidth( ap ) 1020766Speter , align( ap ) ); 1021766Speter putdot( filename , line ); 1022766Speter break; 1023766Speter } 1024766Speter /* 1025766Speter * get(file); 1026766Speter */ 1027766Speter putleaf( P2ICON , 0 , 0 1028766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1029766Speter , "_GET" ); 10303833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 10313833Speter P2PTR|P2STRTY ); 1032766Speter putop( P2CALL , P2INT ); 1033766Speter putdot( filename , line ); 1034766Speter continue; 1035766Speter } 1036766Speter /* 1037766Speter * if you get to here, you are reading from 1038766Speter * a text file. only possiblities are: 1039766Speter * character, integer, real, or scalar. 1040766Speter * read( f , foo , ... ) is done as 1041766Speter * foo := read( f ) with rangechecking 1042766Speter * if appropriate. 1043766Speter */ 1044766Speter typ = classify(ap); 1045766Speter op = rdops(typ); 1046766Speter if (op == NIL) { 1047766Speter error("Can't read %ss from a text file", clnames[typ]); 1048766Speter continue; 1049766Speter } 1050766Speter /* 1051766Speter * left hand side of foo := read( f ) 1052766Speter */ 1053766Speter ap = lvalue( al , MOD|ASGN|NOUSE , RREQ ); 1054766Speter if ( isa( ap , "bsci" ) ) { 1055766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 1056766Speter } 1057766Speter switch ( op ) { 1058766Speter case O_READC: 1059766Speter readname = "_READC"; 1060766Speter readtype = P2INT; 1061766Speter break; 1062766Speter case O_READ4: 1063766Speter readname = "_READ4"; 1064766Speter readtype = P2INT; 1065766Speter break; 1066766Speter case O_READ8: 1067766Speter readname = "_READ8"; 1068766Speter readtype = P2DOUBLE; 1069766Speter break; 1070766Speter case O_READE: 1071766Speter readname = "_READE"; 1072766Speter readtype = P2INT; 1073766Speter break; 1074766Speter } 1075766Speter putleaf( P2ICON , 0 , 0 1076766Speter , ADDTYPE( P2FTN | readtype , P2PTR ) 1077766Speter , readname ); 10783833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 10793833Speter P2PTR|P2STRTY ); 1080766Speter if ( op == O_READE ) { 1081766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 1082766Speter , listnames( ap ) ); 1083766Speter putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR 1084766Speter , format ); 1085766Speter putop( P2LISTOP , P2INT ); 10861629Speter warning(); 1087766Speter if (opt('s')) { 1088766Speter standard(); 1089766Speter } 10901629Speter error("Reading scalars from text files is non-standard"); 1091766Speter } 1092766Speter putop( P2CALL , readtype ); 1093766Speter if ( isa( ap , "bcsi" ) ) { 109410373Speter postcheck(ap, readtype==P2INT?nl+T4INT:nl+TDOUBLE); 1095766Speter } 109610373Speter sconv(readtype, p2type(ap)); 1097766Speter putop( P2ASSIGN , p2type( ap ) ); 1098766Speter putdot( filename , line ); 1099766Speter } 1100766Speter /* 1101766Speter * Done with arguments. 1102766Speter * Handle readln and 1103766Speter * insufficient number of args. 1104766Speter */ 1105766Speter if (p->value[0] == O_READLN) { 1106766Speter if (filetype != nl+T1CHAR) 1107766Speter error("Can't 'readln' a non text file"); 1108766Speter putleaf( P2ICON , 0 , 0 1109766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1110766Speter , "_READLN" ); 11113833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 11123833Speter P2PTR|P2STRTY ); 1113766Speter putop( P2CALL , P2INT ); 1114766Speter putdot( filename , line ); 1115766Speter } else if (argc == 0) 1116766Speter error("read requires an argument"); 1117766Speter return; 1118766Speter 1119766Speter case O_GET: 1120766Speter case O_PUT: 1121766Speter if (argc != 1) { 1122766Speter error("%s expects one argument", p->symbol); 1123766Speter return; 1124766Speter } 11253833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1126766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1127766Speter , "_UNIT" ); 1128766Speter ap = stklval(argv[1], NOFLAGS); 1129766Speter if (ap == NIL) 1130766Speter return; 1131766Speter if (ap->class != FILET) { 1132766Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1133766Speter return; 1134766Speter } 1135766Speter putop( P2CALL , P2INT ); 1136766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1137766Speter putdot( filename , line ); 1138766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1139766Speter , op == O_GET ? "_GET" : "_PUT" ); 11403833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1141766Speter putop( P2CALL , P2INT ); 1142766Speter putdot( filename , line ); 1143766Speter return; 1144766Speter 1145766Speter case O_RESET: 1146766Speter case O_REWRITE: 1147766Speter if (argc == 0 || argc > 2) { 1148766Speter error("%s expects one or two arguments", p->symbol); 1149766Speter return; 1150766Speter } 1151766Speter if (opt('s') && argc == 2) { 1152766Speter standard(); 1153766Speter error("Two argument forms of reset and rewrite are non-standard"); 1154766Speter } 1155766Speter putleaf( P2ICON , 0 , 0 , P2INT 1156766Speter , op == O_RESET ? "_RESET" : "_REWRITE" ); 1157766Speter ap = stklval(argv[1], MOD|NOUSE); 1158766Speter if (ap == NIL) 1159766Speter return; 1160766Speter if (ap->class != FILET) { 1161766Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1162766Speter return; 1163766Speter } 1164766Speter if (argc == 2) { 1165766Speter /* 1166766Speter * Optional second argument 1167766Speter * is a string name of a 1168766Speter * UNIX (R) file to be associated. 1169766Speter */ 1170766Speter al = argv[2]; 1171766Speter al = stkrval(al[1], NOFLAGS , RREQ ); 1172766Speter if (al == NIL) 1173766Speter return; 1174766Speter if (classify(al) != TSTR) { 1175766Speter error("Second argument to %s must be a string, not %s", p->symbol, nameof(al)); 1176766Speter return; 1177766Speter } 1178766Speter strnglen = width(al); 1179766Speter } else { 1180766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 1181766Speter strnglen = 0; 1182766Speter } 1183766Speter putop( P2LISTOP , P2INT ); 1184766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 1185766Speter putop( P2LISTOP , P2INT ); 1186766Speter putleaf( P2ICON , text(ap) ? 0: width(ap->type) , 0 , P2INT , 0 ); 1187766Speter putop( P2LISTOP , P2INT ); 1188766Speter putop( P2CALL , P2INT ); 1189766Speter putdot( filename , line ); 1190766Speter return; 1191766Speter 1192766Speter case O_NEW: 1193766Speter case O_DISPOSE: 1194766Speter if (argc == 0) { 1195766Speter error("%s expects at least one argument", p->symbol); 1196766Speter return; 1197766Speter } 11989139Smckusick alv = argv[1]; 11997967Smckusick codeoff(); 12009139Smckusick ap = stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD ); 12017967Smckusick codeon(); 1202766Speter if (ap == NIL) 1203766Speter return; 1204766Speter if (ap->class != PTR) { 1205766Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 1206766Speter return; 1207766Speter } 1208766Speter ap = ap->type; 1209766Speter if (ap == NIL) 1210766Speter return; 12119139Smckusick if (op == O_NEW) 12129139Smckusick cmd = "_NEW"; 12139139Smckusick else /* op == O_DISPOSE */ 12147967Smckusick if ((ap->nl_flags & NFILES) != 0) 12157967Smckusick cmd = "_DFDISPOSE"; 12167967Smckusick else 12177967Smckusick cmd = "_DISPOSE"; 12187967Smckusick putleaf( P2ICON, 0, 0, ADDTYPE( P2FTN | P2INT , P2PTR ), cmd); 12199139Smckusick stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD ); 1220766Speter argv = argv[2]; 1221766Speter if (argv != NIL) { 1222766Speter if (ap->class != RECORD) { 1223766Speter error("Record required when specifying variant tags"); 1224766Speter return; 1225766Speter } 1226766Speter for (; argv != NIL; argv = argv[2]) { 1227766Speter if (ap->ptr[NL_VARNT] == NIL) { 1228766Speter error("Too many tag fields"); 1229766Speter return; 1230766Speter } 1231766Speter if (!isconst(argv[1])) { 1232766Speter error("Second and successive arguments to %s must be constants", p->symbol); 1233766Speter return; 1234766Speter } 1235766Speter gconst(argv[1]); 1236766Speter if (con.ctype == NIL) 1237766Speter return; 1238766Speter if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) { 1239766Speter cerror("Specified tag constant type clashed with variant case selector type"); 1240766Speter return; 1241766Speter } 1242766Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 1243766Speter if (ap->range[0] == con.crval) 1244766Speter break; 1245766Speter if (ap == NIL) { 1246766Speter error("No variant case label value equals specified constant value"); 1247766Speter return; 1248766Speter } 1249766Speter ap = ap->ptr[NL_VTOREC]; 1250766Speter } 1251766Speter } 1252766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1253766Speter putop( P2LISTOP , P2INT ); 1254766Speter putop( P2CALL , P2INT ); 1255766Speter putdot( filename , line ); 12569139Smckusick if (opt('t') && op == O_NEW) { 12579139Smckusick putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 12589139Smckusick , "_blkclr" ); 12599264Smckusick stkrval(alv, NIL , RREQ ); 12609139Smckusick putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 12619139Smckusick putop( P2LISTOP , P2INT ); 12629139Smckusick putop( P2CALL , P2INT ); 12639139Smckusick putdot( filename , line ); 12649139Smckusick } 1265766Speter return; 1266766Speter 1267766Speter case O_DATE: 1268766Speter case O_TIME: 1269766Speter if (argc != 1) { 1270766Speter error("%s expects one argument", p->symbol); 1271766Speter return; 1272766Speter } 1273766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1274766Speter , op == O_DATE ? "_DATE" : "_TIME" ); 1275766Speter ap = stklval(argv[1], MOD|NOUSE); 1276766Speter if (ap == NIL) 1277766Speter return; 1278766Speter if (classify(ap) != TSTR || width(ap) != 10) { 1279766Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 1280766Speter return; 1281766Speter } 1282766Speter putop( P2CALL , P2INT ); 1283766Speter putdot( filename , line ); 1284766Speter return; 1285766Speter 1286766Speter case O_HALT: 1287766Speter if (argc != 0) { 1288766Speter error("halt takes no arguments"); 1289766Speter return; 1290766Speter } 1291766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1292766Speter , "_HALT" ); 1293766Speter 1294766Speter putop( P2UNARY P2CALL , P2INT ); 1295766Speter putdot( filename , line ); 1296766Speter noreach = 1; 1297766Speter return; 1298766Speter 1299766Speter case O_ARGV: 1300766Speter if (argc != 2) { 1301766Speter error("argv takes two arguments"); 1302766Speter return; 1303766Speter } 1304766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1305766Speter , "_ARGV" ); 1306766Speter ap = stkrval(argv[1], NIL , RREQ ); 1307766Speter if (ap == NIL) 1308766Speter return; 1309766Speter if (isnta(ap, "i")) { 1310766Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 1311766Speter return; 1312766Speter } 1313766Speter al = argv[2]; 1314766Speter ap = stklval(al[1], MOD|NOUSE); 1315766Speter if (ap == NIL) 1316766Speter return; 1317766Speter if (classify(ap) != TSTR) { 1318766Speter error("argv's second argument must be a string, not %s", nameof(ap)); 1319766Speter return; 1320766Speter } 1321766Speter putop( P2LISTOP , P2INT ); 1322766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1323766Speter putop( P2LISTOP , P2INT ); 1324766Speter putop( P2CALL , P2INT ); 1325766Speter putdot( filename , line ); 1326766Speter return; 1327766Speter 1328766Speter case O_STLIM: 1329766Speter if (argc != 1) { 1330766Speter error("stlimit requires one argument"); 1331766Speter return; 1332766Speter } 1333766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1334766Speter , "_STLIM" ); 1335766Speter ap = stkrval(argv[1], NIL , RREQ ); 1336766Speter if (ap == NIL) 1337766Speter return; 1338766Speter if (isnta(ap, "i")) { 1339766Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 1340766Speter return; 1341766Speter } 1342766Speter putop( P2CALL , P2INT ); 1343766Speter putdot( filename , line ); 1344766Speter return; 1345766Speter 1346766Speter case O_REMOVE: 1347766Speter if (argc != 1) { 1348766Speter error("remove expects one argument"); 1349766Speter return; 1350766Speter } 1351766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1352766Speter , "_REMOVE" ); 1353766Speter ap = stkrval(argv[1], NOFLAGS , RREQ ); 1354766Speter if (ap == NIL) 1355766Speter return; 1356766Speter if (classify(ap) != TSTR) { 1357766Speter error("remove's argument must be a string, not %s", nameof(ap)); 1358766Speter return; 1359766Speter } 1360766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1361766Speter putop( P2LISTOP , P2INT ); 1362766Speter putop( P2CALL , P2INT ); 1363766Speter putdot( filename , line ); 1364766Speter return; 1365766Speter 1366766Speter case O_LLIMIT: 1367766Speter if (argc != 2) { 1368766Speter error("linelimit expects two arguments"); 1369766Speter return; 1370766Speter } 1371766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1372766Speter , "_LLIMIT" ); 1373766Speter ap = stklval(argv[1], NOFLAGS|NOUSE); 1374766Speter if (ap == NIL) 1375766Speter return; 1376766Speter if (!text(ap)) { 1377766Speter error("linelimit's first argument must be a text file, not %s", nameof(ap)); 1378766Speter return; 1379766Speter } 1380766Speter al = argv[2]; 1381766Speter ap = stkrval(al[1], NIL , RREQ ); 1382766Speter if (ap == NIL) 1383766Speter return; 1384766Speter if (isnta(ap, "i")) { 1385766Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 1386766Speter return; 1387766Speter } 1388766Speter putop( P2LISTOP , P2INT ); 1389766Speter putop( P2CALL , P2INT ); 1390766Speter putdot( filename , line ); 1391766Speter return; 1392766Speter case O_PAGE: 1393766Speter if (argc != 1) { 1394766Speter error("page expects one argument"); 1395766Speter return; 1396766Speter } 13973833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1398766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1399766Speter , "_UNIT" ); 1400766Speter ap = stklval(argv[1], NOFLAGS); 1401766Speter if (ap == NIL) 1402766Speter return; 1403766Speter if (!text(ap)) { 1404766Speter error("Argument to page must be a text file, not %s", nameof(ap)); 1405766Speter return; 1406766Speter } 1407766Speter putop( P2CALL , P2INT ); 1408766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1409766Speter putdot( filename , line ); 1410766Speter if ( opt( 't' ) ) { 1411766Speter putleaf( P2ICON , 0 , 0 1412766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1413766Speter , "_PAGE" ); 14143833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1415766Speter } else { 1416766Speter putleaf( P2ICON , 0 , 0 1417766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1418766Speter , "_fputc" ); 1419766Speter putleaf( P2ICON , '\f' , 0 , P2CHAR , 0 ); 1420766Speter putleaf( P2ICON , 0 , 0 1421766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1422766Speter , "_ACTFILE" ); 14233833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1424766Speter putop( P2CALL , P2INT ); 1425766Speter putop( P2LISTOP , P2INT ); 1426766Speter } 1427766Speter putop( P2CALL , P2INT ); 1428766Speter putdot( filename , line ); 1429766Speter return; 1430766Speter 14317928Smckusick case O_ASRT: 14327928Smckusick if (!opt('t')) 14337928Smckusick return; 14347928Smckusick if (argc == 0 || argc > 2) { 14357928Smckusick error("Assert expects one or two arguments"); 14367928Smckusick return; 14377928Smckusick } 14389139Smckusick if (argc == 2) 14399139Smckusick cmd = "_ASRTS"; 14409139Smckusick else 14419139Smckusick cmd = "_ASRT"; 14427928Smckusick putleaf( P2ICON , 0 , 0 14439139Smckusick , ADDTYPE( P2FTN | P2INT , P2PTR ) , cmd ); 14447928Smckusick ap = stkrval(argv[1], NIL , RREQ ); 14457928Smckusick if (ap == NIL) 14467928Smckusick return; 14477928Smckusick if (isnta(ap, "b")) 14487928Smckusick error("Assert expression must be Boolean, not %ss", nameof(ap)); 14497928Smckusick if (argc == 2) { 14507928Smckusick /* 14517928Smckusick * Optional second argument is a string specifying 14527928Smckusick * why the assertion failed. 14537928Smckusick */ 14547928Smckusick al = argv[2]; 14557928Smckusick al = stkrval(al[1], NIL , RREQ ); 14567928Smckusick if (al == NIL) 14577928Smckusick return; 14587928Smckusick if (classify(al) != TSTR) { 14597928Smckusick error("Second argument to assert must be a string, not %s", nameof(al)); 14607928Smckusick return; 14617928Smckusick } 14629139Smckusick putop( P2LISTOP , P2INT ); 14637928Smckusick } 14647928Smckusick putop( P2CALL , P2INT ); 14657928Smckusick putdot( filename , line ); 14667928Smckusick return; 14677928Smckusick 1468766Speter case O_PACK: 1469766Speter if (argc != 3) { 1470766Speter error("pack expects three arguments"); 1471766Speter return; 1472766Speter } 1473766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1474766Speter , "_PACK" ); 1475766Speter pu = "pack(a,i,z)"; 1476766Speter pua = (al = argv)[1]; 1477766Speter pui = (al = al[2])[1]; 1478766Speter puz = (al = al[2])[1]; 1479766Speter goto packunp; 1480766Speter case O_UNPACK: 1481766Speter if (argc != 3) { 1482766Speter error("unpack expects three arguments"); 1483766Speter return; 1484766Speter } 1485766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1486766Speter , "_UNPACK" ); 1487766Speter pu = "unpack(z,a,i)"; 1488766Speter puz = (al = argv)[1]; 1489766Speter pua = (al = al[2])[1]; 1490766Speter pui = (al = al[2])[1]; 1491766Speter packunp: 1492766Speter ap = stkrval((int *) pui, NLNIL , RREQ ); 1493766Speter if (ap == NIL) 1494766Speter return; 1495766Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 1496766Speter if (ap == NIL) 1497766Speter return; 1498766Speter if (ap->class != ARRAY) { 1499766Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 1500766Speter return; 1501766Speter } 1502766Speter putop( P2LISTOP , P2INT ); 1503766Speter al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 1504766Speter if (al->class != ARRAY) { 1505766Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 1506766Speter return; 1507766Speter } 1508766Speter if (al->type == NIL || ap->type == NIL) 1509766Speter return; 1510766Speter if (al->type != ap->type) { 1511766Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 1512766Speter return; 1513766Speter } 1514766Speter putop( P2LISTOP , P2INT ); 1515766Speter k = width(al); 1516766Speter itemwidth = width(ap->type); 1517766Speter ap = ap->chain; 1518766Speter al = al->chain; 1519766Speter if (ap->chain != NIL || al->chain != NIL) { 1520766Speter error("%s requires a and z to be single dimension arrays", pu); 1521766Speter return; 1522766Speter } 1523766Speter if (ap == NIL || al == NIL) 1524766Speter return; 1525766Speter /* 1526766Speter * al is the range for z i.e. u..v 1527766Speter * ap is the range for a i.e. m..n 1528766Speter * i will be n-m+1 1529766Speter * j will be v-u+1 1530766Speter */ 1531766Speter i = ap->range[1] - ap->range[0] + 1; 1532766Speter j = al->range[1] - al->range[0] + 1; 1533766Speter if (i < j) { 1534766Speter error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i); 1535766Speter return; 1536766Speter } 1537766Speter /* 1538766Speter * get n-m-(v-u) and m for the interpreter 1539766Speter */ 1540766Speter i -= j; 1541766Speter j = ap->range[0]; 1542766Speter putleaf( P2ICON , itemwidth , 0 , P2INT , 0 ); 1543766Speter putop( P2LISTOP , P2INT ); 1544766Speter putleaf( P2ICON , j , 0 , P2INT , 0 ); 1545766Speter putop( P2LISTOP , P2INT ); 1546766Speter putleaf( P2ICON , i , 0 , P2INT , 0 ); 1547766Speter putop( P2LISTOP , P2INT ); 1548766Speter putleaf( P2ICON , k , 0 , P2INT , 0 ); 1549766Speter putop( P2LISTOP , P2INT ); 1550766Speter putop( P2CALL , P2INT ); 1551766Speter putdot( filename , line ); 1552766Speter return; 1553766Speter case 0: 15547928Smckusick error("%s is an unimplemented extension", p->symbol); 1555766Speter return; 1556766Speter 1557766Speter default: 1558766Speter panic("proc case"); 1559766Speter } 1560766Speter } 1561766Speter #endif PC 1562