1766Speter /* Copyright (c) 1979 Regents of the University of California */ 2766Speter 3*11856Speter static char sccsid[] = "@(#)pcproc.c 1.20 04/06/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" 1611333Speter #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: 399*11856Speter putstrop(P2STASG, 400*11856Speter ADDTYPE(p2type(filetype), 401*11856Speter P2PTR), 402*11856Speter lwidth(filetype), 403*11856Speter align(filetype)); 404766Speter putdot( filename , line ); 405766Speter break; 406766Speter } 407766Speter /* 408766Speter * put(file) 409766Speter */ 410766Speter putleaf( P2ICON , 0 , 0 411766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 412766Speter , "_PUT" ); 4133833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 4143833Speter P2PTR|P2STRTY ); 415766Speter putop( P2CALL , P2INT ); 416766Speter putdot( filename , line ); 417766Speter continue; 418766Speter } 419766Speter /* 420766Speter * Write to a textfile 421766Speter * 422766Speter * Evaluate the expression 423766Speter * to be written. 424766Speter */ 425766Speter if (fmt == 'O' || fmt == 'X') { 426766Speter if (opt('s')) { 427766Speter standard(); 428766Speter error("Oct and hex are non-standard"); 429766Speter } 430766Speter if (typ == TSTR || typ == TDOUBLE) { 431766Speter error("Can't write %ss with oct/hex", clnames[typ]); 432766Speter continue; 433766Speter } 434766Speter if (typ == TCHAR || typ == TBOOL) 435766Speter typ = TINT; 436766Speter } 437766Speter /* 438766Speter * If there is no format specified by the programmer, 439766Speter * implement the default. 440766Speter */ 441766Speter switch (typ) { 4426540Smckusick case TPTR: 4436540Smckusick warning(); 4446540Smckusick if (opt('s')) { 4456540Smckusick standard(); 4466540Smckusick } 4476540Smckusick error("Writing %ss to text files is non-standard", 4486540Smckusick clnames[typ]); 4496540Smckusick /* and fall through */ 450766Speter case TINT: 451766Speter if (fmt == 'f') { 452766Speter typ = TDOUBLE; 453766Speter goto tdouble; 454766Speter } 455766Speter if (fmtspec == NIL) { 456766Speter if (fmt == 'D') 457766Speter field = 10; 458766Speter else if (fmt == 'X') 459766Speter field = 8; 460766Speter else if (fmt == 'O') 461766Speter field = 11; 462766Speter else 463766Speter panic("fmt1"); 464766Speter fmtspec = CONWIDTH; 465766Speter } 466766Speter break; 467766Speter case TCHAR: 468766Speter tchar: 469766Speter fmt = 'c'; 470766Speter break; 471766Speter case TSCAL: 4721629Speter warning(); 473766Speter if (opt('s')) { 474766Speter standard(); 475766Speter } 4766540Smckusick error("Writing %ss to text files is non-standard", 4776540Smckusick clnames[typ]); 478766Speter case TBOOL: 479766Speter fmt = 's'; 480766Speter break; 481766Speter case TDOUBLE: 482766Speter tdouble: 483766Speter switch (fmtspec) { 484766Speter case NIL: 485766Speter field = 21; 486766Speter prec = 14; 4873225Smckusic fmt = 'e'; 488766Speter fmtspec = CONWIDTH + CONPREC; 489766Speter break; 490766Speter case CONWIDTH: 4919229Smckusick field -= REALSPC; 4929229Smckusick if (field < 1) 493766Speter field = 1; 494766Speter prec = field - 7; 495766Speter if (prec < 1) 496766Speter prec = 1; 497766Speter fmtspec += CONPREC; 4983225Smckusic fmt = 'e'; 499766Speter break; 500766Speter case VARWIDTH: 501766Speter fmtspec += VARPREC; 5023225Smckusic fmt = 'e'; 503766Speter break; 504766Speter case CONWIDTH + CONPREC: 505766Speter case CONWIDTH + VARPREC: 5069229Smckusick field -= REALSPC; 5079229Smckusick if (field < 1) 508766Speter field = 1; 509766Speter } 510766Speter format[0] = ' '; 5119229Smckusick fmtstart = 1 - REALSPC; 512766Speter break; 513766Speter case TSTR: 514766Speter constval( alv ); 515766Speter switch ( classify( con.ctype ) ) { 516766Speter case TCHAR: 517766Speter typ = TCHAR; 518766Speter goto tchar; 519766Speter case TSTR: 520766Speter strptr = con.cpval; 521766Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 522766Speter strptr = con.cpval; 523766Speter break; 524766Speter default: 525766Speter strnglen = width(ap); 526766Speter break; 527766Speter } 528766Speter fmt = 's'; 529766Speter strfmt = fmtspec; 530766Speter if (fmtspec == NIL) { 531766Speter fmtspec = SKIP; 532766Speter break; 533766Speter } 534766Speter if (fmtspec & CONWIDTH) { 535766Speter if (field <= strnglen) 536766Speter fmtspec = SKIP; 537766Speter else 538766Speter field -= strnglen; 539766Speter } 540766Speter break; 541766Speter default: 542766Speter error("Can't write %ss to a text file", clnames[typ]); 543766Speter continue; 544766Speter } 545766Speter /* 546766Speter * Generate the format string 547766Speter */ 548766Speter switch (fmtspec) { 549766Speter default: 550766Speter panic("fmt2"); 551766Speter case NIL: 552766Speter if (fmt == 'c') { 553766Speter if ( opt( 't' ) ) { 554766Speter putleaf( P2ICON , 0 , 0 555766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 556766Speter , "_WRITEC" ); 5573833Speter putRV( 0 , cbn , CURFILEOFFSET , 5583833Speter NLOCAL , P2PTR|P2STRTY ); 559766Speter stkrval( alv , NIL , RREQ ); 560766Speter putop( P2LISTOP , P2INT ); 561766Speter } else { 562766Speter putleaf( P2ICON , 0 , 0 563766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 564766Speter , "_fputc" ); 565766Speter stkrval( alv , NIL , RREQ ); 566766Speter } 567766Speter putleaf( P2ICON , 0 , 0 568766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 569766Speter , "_ACTFILE" ); 5703833Speter putRV( 0, cbn , CURFILEOFFSET , 5713833Speter NLOCAL , P2PTR|P2STRTY ); 572766Speter putop( P2CALL , P2INT ); 573766Speter putop( P2LISTOP , P2INT ); 574766Speter putop( P2CALL , P2INT ); 575766Speter putdot( filename , line ); 576766Speter } else { 577766Speter sprintf(&format[1], "%%%c", fmt); 578766Speter goto fmtgen; 579766Speter } 580766Speter case SKIP: 581766Speter break; 582766Speter case CONWIDTH: 583766Speter sprintf(&format[1], "%%%1D%c", field, fmt); 584766Speter goto fmtgen; 585766Speter case VARWIDTH: 586766Speter sprintf(&format[1], "%%*%c", fmt); 587766Speter goto fmtgen; 588766Speter case CONWIDTH + CONPREC: 589766Speter sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt); 590766Speter goto fmtgen; 591766Speter case CONWIDTH + VARPREC: 592766Speter sprintf(&format[1], "%%%1D.*%c", field, fmt); 593766Speter goto fmtgen; 594766Speter case VARWIDTH + CONPREC: 595766Speter sprintf(&format[1], "%%*.%1D%c", prec, fmt); 596766Speter goto fmtgen; 597766Speter case VARWIDTH + VARPREC: 598766Speter sprintf(&format[1], "%%*.*%c", fmt); 599766Speter fmtgen: 600766Speter if ( opt( 't' ) ) { 601766Speter putleaf( P2ICON , 0 , 0 602766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 603766Speter , "_WRITEF" ); 6043833Speter putRV( 0 , cbn , CURFILEOFFSET , 6053833Speter NLOCAL , P2PTR|P2STRTY ); 606766Speter putleaf( P2ICON , 0 , 0 607766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 608766Speter , "_ACTFILE" ); 6093833Speter putRV( 0 , cbn , CURFILEOFFSET , 6103833Speter NLOCAL , P2PTR|P2STRTY ); 611766Speter putop( P2CALL , P2INT ); 612766Speter putop( P2LISTOP , P2INT ); 613766Speter } else { 614766Speter putleaf( P2ICON , 0 , 0 615766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 616766Speter , "_fprintf" ); 617766Speter putleaf( P2ICON , 0 , 0 618766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 619766Speter , "_ACTFILE" ); 6203833Speter putRV( 0 , cbn , CURFILEOFFSET , 6213833Speter NLOCAL , P2PTR|P2STRTY ); 622766Speter putop( P2CALL , P2INT ); 623766Speter } 624766Speter putCONG( &format[ fmtstart ] 625766Speter , strlen( &format[ fmtstart ] ) 626766Speter , LREQ ); 627766Speter putop( P2LISTOP , P2INT ); 628766Speter if ( fmtspec & VARWIDTH ) { 629766Speter /* 630766Speter * either 631766Speter * ,(temp=width,MAX(temp,...)), 632766Speter * or 633766Speter * , MAX( width , ... ) , 634766Speter */ 635766Speter if ( ( typ == TDOUBLE && al[3] == NIL ) 636766Speter || typ == TSTR ) { 6373225Smckusic soffset = sizes[cbn].curtmps; 6383833Speter tempnlp = tmpalloc(sizeof(long), 6393225Smckusic nl+T4INT, REGOK); 6403833Speter putRV( 0 , cbn , 6413833Speter tempnlp -> value[ NL_OFFS ] , 6423833Speter tempnlp -> extra_flags , P2INT ); 643766Speter ap = stkrval( al[2] , NIL , RREQ ); 644766Speter putop( P2ASSIGN , P2INT ); 645766Speter putleaf( P2ICON , 0 , 0 646766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 647766Speter , "_MAX" ); 6483833Speter putRV( 0 , cbn , 6493833Speter tempnlp -> value[ NL_OFFS ] , 6503833Speter tempnlp -> extra_flags , P2INT ); 651766Speter } else { 652766Speter if (opt('t') 653766Speter || typ == TSTR || typ == TDOUBLE) { 654766Speter putleaf( P2ICON , 0 , 0 655766Speter ,ADDTYPE( P2FTN | P2INT, P2PTR ) 656766Speter ,"_MAX" ); 657766Speter } 658766Speter ap = stkrval( al[2] , NIL , RREQ ); 659766Speter } 660766Speter if (ap == NIL) 661766Speter continue; 662766Speter if (isnta(ap,"i")) { 663766Speter error("First write width must be integer, not %s", nameof(ap)); 664766Speter continue; 665766Speter } 666766Speter switch ( typ ) { 667766Speter case TDOUBLE: 6689229Smckusick putleaf( P2ICON , REALSPC , 0 , P2INT , 0 ); 669766Speter putop( P2LISTOP , P2INT ); 670766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 671766Speter putop( P2LISTOP , P2INT ); 672766Speter putop( P2CALL , P2INT ); 673766Speter if ( al[3] == NIL ) { 674766Speter /* 675766Speter * finish up the comma op 676766Speter */ 677766Speter putop( P2COMOP , P2INT ); 678766Speter fmtspec &= ~VARPREC; 679766Speter putop( P2LISTOP , P2INT ); 680766Speter putleaf( P2ICON , 0 , 0 681766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 682766Speter , "_MAX" ); 6833833Speter putRV( 0 , cbn , 6843833Speter tempnlp -> value[ NL_OFFS ] , 6853833Speter tempnlp -> extra_flags , 6863833Speter P2INT ); 6873225Smckusic tmpfree(&soffset); 6889229Smckusick putleaf( P2ICON , 7 + REALSPC , 0 , P2INT , 0 ); 689766Speter putop( P2LISTOP , P2INT ); 690766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 691766Speter putop( P2LISTOP , P2INT ); 692766Speter putop( P2CALL , P2INT ); 693766Speter } 694766Speter putop( P2LISTOP , P2INT ); 695766Speter break; 696766Speter case TSTR: 697766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 698766Speter putop( P2LISTOP , P2INT ); 699766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 700766Speter putop( P2LISTOP , P2INT ); 701766Speter putop( P2CALL , P2INT ); 702766Speter putop( P2COMOP , P2INT ); 703766Speter putop( P2LISTOP , P2INT ); 704766Speter break; 705766Speter default: 706766Speter if (opt('t')) { 707766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 708766Speter putop( P2LISTOP , P2INT ); 709766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 710766Speter putop( P2LISTOP , P2INT ); 711766Speter putop( P2CALL , P2INT ); 712766Speter } 713766Speter putop( P2LISTOP , P2INT ); 714766Speter break; 715766Speter } 716766Speter } 717766Speter /* 718766Speter * If there is a variable precision, 719766Speter * evaluate it 720766Speter */ 721766Speter if (fmtspec & VARPREC) { 722766Speter if (opt('t')) { 723766Speter putleaf( P2ICON , 0 , 0 724766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 725766Speter , "_MAX" ); 726766Speter } 727766Speter ap = stkrval( al[3] , NIL , RREQ ); 728766Speter if (ap == NIL) 729766Speter continue; 730766Speter if (isnta(ap,"i")) { 731766Speter error("Second write width must be integer, not %s", nameof(ap)); 732766Speter continue; 733766Speter } 734766Speter if (opt('t')) { 735766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 736766Speter putop( P2LISTOP , P2INT ); 737766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 738766Speter putop( P2LISTOP , P2INT ); 739766Speter putop( P2CALL , P2INT ); 740766Speter } 741766Speter putop( P2LISTOP , P2INT ); 742766Speter } 743766Speter /* 744766Speter * evaluate the thing we want printed. 745766Speter */ 746766Speter switch ( typ ) { 7476540Smckusick case TPTR: 748766Speter case TCHAR: 749766Speter case TINT: 750766Speter stkrval( alv , NIL , RREQ ); 751766Speter putop( P2LISTOP , P2INT ); 752766Speter break; 753766Speter case TDOUBLE: 754766Speter ap = stkrval( alv , NIL , RREQ ); 75510373Speter if (isnta(ap, "d")) { 75610373Speter sconv(p2type(ap), P2DOUBLE); 757766Speter } 758766Speter putop( P2LISTOP , P2INT ); 759766Speter break; 760766Speter case TSCAL: 761766Speter case TBOOL: 762766Speter putleaf( P2ICON , 0 , 0 763766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 764766Speter , "_NAM" ); 765766Speter ap = stkrval( alv , NIL , RREQ ); 766766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 767766Speter , listnames( ap ) ); 768766Speter putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR 769766Speter , format ); 770766Speter putop( P2LISTOP , P2INT ); 771766Speter putop( P2CALL , P2INT ); 772766Speter putop( P2LISTOP , P2INT ); 773766Speter break; 774766Speter case TSTR: 775766Speter putCONG( "" , 0 , LREQ ); 776766Speter putop( P2LISTOP , P2INT ); 777766Speter break; 7786540Smckusick default: 7796540Smckusick panic("fmt3"); 7806540Smckusick break; 781766Speter } 782766Speter putop( P2CALL , P2INT ); 783766Speter putdot( filename , line ); 784766Speter } 785766Speter /* 786766Speter * Write the string after its blank padding 787766Speter */ 788766Speter if (typ == TSTR ) { 789766Speter if ( opt( 't' ) ) { 790766Speter putleaf( P2ICON , 0 , 0 791766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 792766Speter , "_WRITES" ); 7933833Speter putRV( 0 , cbn , CURFILEOFFSET , 7943833Speter NLOCAL , P2PTR|P2STRTY ); 795766Speter ap = stkrval(alv, NIL , RREQ ); 796766Speter putop( P2LISTOP , P2INT ); 797766Speter } else { 798766Speter putleaf( P2ICON , 0 , 0 799766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 800766Speter , "_fwrite" ); 801766Speter ap = stkrval(alv, NIL , RREQ ); 802766Speter } 803766Speter if (strfmt & VARWIDTH) { 804766Speter /* 805766Speter * min, inline expanded as 806766Speter * temp < len ? temp : len 807766Speter */ 8083833Speter putRV( 0 , cbn , 8093833Speter tempnlp -> value[ NL_OFFS ] , 8103833Speter tempnlp -> extra_flags , P2INT ); 811766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 812766Speter putop( P2LT , P2INT ); 8133833Speter putRV( 0 , cbn , 8143833Speter tempnlp -> value[ NL_OFFS ] , 8153833Speter tempnlp -> extra_flags , P2INT ); 816766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 817766Speter putop( P2COLON , P2INT ); 818766Speter putop( P2QUEST , P2INT ); 8193225Smckusic tmpfree(&soffset); 820766Speter } else { 821766Speter if ( ( fmtspec & SKIP ) 822766Speter && ( strfmt & CONWIDTH ) ) { 823766Speter strnglen = field; 824766Speter } 825766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 826766Speter } 827766Speter putop( P2LISTOP , P2INT ); 828766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 829766Speter putop( P2LISTOP , P2INT ); 830766Speter putleaf( P2ICON , 0 , 0 831766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 832766Speter , "_ACTFILE" ); 8333833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 8343833Speter P2PTR|P2STRTY ); 835766Speter putop( P2CALL , P2INT ); 836766Speter putop( P2LISTOP , P2INT ); 837766Speter putop( P2CALL , P2INT ); 838766Speter putdot( filename , line ); 839766Speter } 840766Speter } 841766Speter /* 842766Speter * Done with arguments. 843766Speter * Handle writeln and 844766Speter * insufficent number of args. 845766Speter */ 846766Speter switch (p->value[0] &~ NSTAND) { 847766Speter case O_WRITEF: 848766Speter if (argc == 0) 849766Speter error("Write requires an argument"); 850766Speter break; 851766Speter case O_MESSAGE: 852766Speter if (argc == 0) 853766Speter error("Message requires an argument"); 854766Speter case O_WRITLN: 855766Speter if (filetype != nl+T1CHAR) 856766Speter error("Can't 'writeln' a non text file"); 857766Speter if ( opt( 't' ) ) { 858766Speter putleaf( P2ICON , 0 , 0 859766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 860766Speter , "_WRITLN" ); 8613833Speter putRV( 0 , cbn , CURFILEOFFSET , 8623833Speter NLOCAL , P2PTR|P2STRTY ); 863766Speter } else { 864766Speter putleaf( P2ICON , 0 , 0 865766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 866766Speter , "_fputc" ); 867766Speter putleaf( P2ICON , '\n' , 0 , P2CHAR , 0 ); 868766Speter putleaf( P2ICON , 0 , 0 869766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 870766Speter , "_ACTFILE" ); 8713833Speter putRV( 0 , cbn , CURFILEOFFSET , 8723833Speter NLOCAL , P2PTR|P2STRTY ); 873766Speter putop( P2CALL , P2INT ); 874766Speter putop( P2LISTOP , P2INT ); 875766Speter } 876766Speter putop( P2CALL , P2INT ); 877766Speter putdot( filename , line ); 878766Speter break; 879766Speter } 880766Speter return; 881766Speter 882766Speter case O_READ4: 883766Speter case O_READLN: 884766Speter /* 885766Speter * Set up default 886766Speter * file "input". 887766Speter */ 888766Speter file = NIL; 889766Speter filetype = nl+T1CHAR; 890766Speter /* 891766Speter * Determine the file implied 892766Speter * for the read and generate 893766Speter * code to make it the active file. 894766Speter */ 895766Speter if (argv != NIL) { 896766Speter codeoff(); 897766Speter ap = stkrval(argv[1], NIL , RREQ ); 898766Speter codeon(); 899766Speter if (ap == NIL) 900766Speter argv = argv[2]; 901766Speter if (ap != NIL && ap->class == FILET) { 902766Speter /* 903766Speter * Got "read(f, ...", make 904766Speter * f the active file, and save 905766Speter * it and its type for use in 906766Speter * processing the rest of the 907766Speter * arguments to read. 908766Speter */ 909766Speter file = argv[1]; 910766Speter filetype = ap->type; 9113833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 9123833Speter P2PTR|P2STRTY ); 913766Speter putleaf( P2ICON , 0 , 0 914766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 915766Speter , "_UNIT" ); 916766Speter stklval(argv[1], NOFLAGS); 917766Speter putop( P2CALL , P2INT ); 918766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 919766Speter putdot( filename , line ); 920766Speter argv = argv[2]; 921766Speter argc--; 922766Speter } else { 923766Speter /* 924766Speter * Default is read from 925766Speter * standard input. 926766Speter */ 9273833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 9283833Speter P2PTR|P2STRTY ); 9293833Speter putLV( "_input" , 0 , 0 , NGLOBAL , 9303833Speter P2PTR|P2STRTY ); 931766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 932766Speter putdot( filename , line ); 933766Speter input->nl_flags |= NUSED; 934766Speter } 935766Speter } else { 9363833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 9373833Speter P2PTR|P2STRTY ); 9383833Speter putLV( "_input" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 939766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 940766Speter putdot( filename , line ); 941766Speter input->nl_flags |= NUSED; 942766Speter } 943766Speter /* 944766Speter * Loop and process each 945766Speter * of the arguments. 946766Speter */ 947766Speter for (; argv != NIL; argv = argv[2]) { 948766Speter /* 949766Speter * Get the address of the target 950766Speter * on the stack. 951766Speter */ 952766Speter al = argv[1]; 953766Speter if (al == NIL) 954766Speter continue; 955766Speter if (al[0] != T_VAR) { 956766Speter error("Arguments to %s must be variables, not expressions", p->symbol); 957766Speter continue; 958766Speter } 959766Speter codeoff(); 960766Speter ap = stklval(al, MOD|ASGN|NOUSE); 961766Speter codeon(); 962766Speter if (ap == NIL) 963766Speter continue; 964766Speter if (filetype != nl+T1CHAR) { 965766Speter /* 966766Speter * Generalized read, i.e. 967766Speter * from a non-textfile. 968766Speter */ 969766Speter if (incompat(filetype, ap, argv[1] )) { 970766Speter error("Type mismatch in read from non-text file"); 971766Speter continue; 972766Speter } 973766Speter /* 974766Speter * var := file ^; 975766Speter */ 976766Speter ap = lvalue( al , MOD | ASGN | NOUSE , RREQ ); 977766Speter if ( isa( ap , "bsci" ) ) { 978766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 979766Speter } 980766Speter putleaf( P2ICON , 0 , 0 981766Speter , ADDTYPE( 982766Speter ADDTYPE( 983766Speter ADDTYPE( 984766Speter p2type( filetype ) , P2PTR ) 985766Speter , P2FTN ) 986766Speter , P2PTR ) 987766Speter , "_FNIL" ); 988766Speter if (file != NIL) 989766Speter stklval(file, NOFLAGS); 990766Speter else /* Magic */ 9913833Speter putRV( "_input" , 0 , 0 , NGLOBAL , 9923833Speter P2PTR | P2STRTY ); 99310668Speter putop(P2CALL, ADDTYPE(p2type(filetype), P2PTR)); 994766Speter switch ( classify( filetype ) ) { 995766Speter case TBOOL: 996766Speter case TCHAR: 997766Speter case TINT: 998766Speter case TSCAL: 999766Speter case TDOUBLE: 1000766Speter case TPTR: 1001766Speter putop( P2UNARY P2MUL 1002766Speter , p2type( filetype ) ); 1003766Speter } 1004766Speter switch ( classify( filetype ) ) { 1005766Speter case TBOOL: 1006766Speter case TCHAR: 1007766Speter case TINT: 1008766Speter case TSCAL: 100910373Speter postcheck(ap, filetype); 101010373Speter sconv(p2type(filetype), p2type(ap)); 1011766Speter /* and fall through */ 1012766Speter case TDOUBLE: 1013766Speter case TPTR: 1014766Speter putop( P2ASSIGN , p2type( ap ) ); 1015766Speter putdot( filename , line ); 1016766Speter break; 1017766Speter default: 1018*11856Speter putstrop(P2STASG, 1019*11856Speter ADDTYPE(p2type(ap), P2PTR), 1020*11856Speter lwidth(ap), 1021*11856Speter align(ap)); 1022766Speter putdot( filename , line ); 1023766Speter break; 1024766Speter } 1025766Speter /* 1026766Speter * get(file); 1027766Speter */ 1028766Speter putleaf( P2ICON , 0 , 0 1029766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1030766Speter , "_GET" ); 10313833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 10323833Speter P2PTR|P2STRTY ); 1033766Speter putop( P2CALL , P2INT ); 1034766Speter putdot( filename , line ); 1035766Speter continue; 1036766Speter } 1037766Speter /* 1038766Speter * if you get to here, you are reading from 1039766Speter * a text file. only possiblities are: 1040766Speter * character, integer, real, or scalar. 1041766Speter * read( f , foo , ... ) is done as 1042766Speter * foo := read( f ) with rangechecking 1043766Speter * if appropriate. 1044766Speter */ 1045766Speter typ = classify(ap); 1046766Speter op = rdops(typ); 1047766Speter if (op == NIL) { 1048766Speter error("Can't read %ss from a text file", clnames[typ]); 1049766Speter continue; 1050766Speter } 1051766Speter /* 1052766Speter * left hand side of foo := read( f ) 1053766Speter */ 1054766Speter ap = lvalue( al , MOD|ASGN|NOUSE , RREQ ); 1055766Speter if ( isa( ap , "bsci" ) ) { 1056766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 1057766Speter } 1058766Speter switch ( op ) { 1059766Speter case O_READC: 1060766Speter readname = "_READC"; 1061766Speter readtype = P2INT; 1062766Speter break; 1063766Speter case O_READ4: 1064766Speter readname = "_READ4"; 1065766Speter readtype = P2INT; 1066766Speter break; 1067766Speter case O_READ8: 1068766Speter readname = "_READ8"; 1069766Speter readtype = P2DOUBLE; 1070766Speter break; 1071766Speter case O_READE: 1072766Speter readname = "_READE"; 1073766Speter readtype = P2INT; 1074766Speter break; 1075766Speter } 1076766Speter putleaf( P2ICON , 0 , 0 1077766Speter , ADDTYPE( P2FTN | readtype , P2PTR ) 1078766Speter , readname ); 10793833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 10803833Speter P2PTR|P2STRTY ); 1081766Speter if ( op == O_READE ) { 1082766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 1083766Speter , listnames( ap ) ); 1084766Speter putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR 1085766Speter , format ); 1086766Speter putop( P2LISTOP , P2INT ); 10871629Speter warning(); 1088766Speter if (opt('s')) { 1089766Speter standard(); 1090766Speter } 10911629Speter error("Reading scalars from text files is non-standard"); 1092766Speter } 1093766Speter putop( P2CALL , readtype ); 1094766Speter if ( isa( ap , "bcsi" ) ) { 109510373Speter postcheck(ap, readtype==P2INT?nl+T4INT:nl+TDOUBLE); 1096766Speter } 109710373Speter sconv(readtype, p2type(ap)); 1098766Speter putop( P2ASSIGN , p2type( ap ) ); 1099766Speter putdot( filename , line ); 1100766Speter } 1101766Speter /* 1102766Speter * Done with arguments. 1103766Speter * Handle readln and 1104766Speter * insufficient number of args. 1105766Speter */ 1106766Speter if (p->value[0] == O_READLN) { 1107766Speter if (filetype != nl+T1CHAR) 1108766Speter error("Can't 'readln' a non text file"); 1109766Speter putleaf( P2ICON , 0 , 0 1110766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1111766Speter , "_READLN" ); 11123833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 11133833Speter P2PTR|P2STRTY ); 1114766Speter putop( P2CALL , P2INT ); 1115766Speter putdot( filename , line ); 1116766Speter } else if (argc == 0) 1117766Speter error("read requires an argument"); 1118766Speter return; 1119766Speter 1120766Speter case O_GET: 1121766Speter case O_PUT: 1122766Speter if (argc != 1) { 1123766Speter error("%s expects one argument", p->symbol); 1124766Speter return; 1125766Speter } 11263833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1127766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1128766Speter , "_UNIT" ); 1129766Speter ap = stklval(argv[1], NOFLAGS); 1130766Speter if (ap == NIL) 1131766Speter return; 1132766Speter if (ap->class != FILET) { 1133766Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1134766Speter return; 1135766Speter } 1136766Speter putop( P2CALL , P2INT ); 1137766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1138766Speter putdot( filename , line ); 1139766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1140766Speter , op == O_GET ? "_GET" : "_PUT" ); 11413833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1142766Speter putop( P2CALL , P2INT ); 1143766Speter putdot( filename , line ); 1144766Speter return; 1145766Speter 1146766Speter case O_RESET: 1147766Speter case O_REWRITE: 1148766Speter if (argc == 0 || argc > 2) { 1149766Speter error("%s expects one or two arguments", p->symbol); 1150766Speter return; 1151766Speter } 1152766Speter if (opt('s') && argc == 2) { 1153766Speter standard(); 1154766Speter error("Two argument forms of reset and rewrite are non-standard"); 1155766Speter } 1156766Speter putleaf( P2ICON , 0 , 0 , P2INT 1157766Speter , op == O_RESET ? "_RESET" : "_REWRITE" ); 1158766Speter ap = stklval(argv[1], MOD|NOUSE); 1159766Speter if (ap == NIL) 1160766Speter return; 1161766Speter if (ap->class != FILET) { 1162766Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1163766Speter return; 1164766Speter } 1165766Speter if (argc == 2) { 1166766Speter /* 1167766Speter * Optional second argument 1168766Speter * is a string name of a 1169766Speter * UNIX (R) file to be associated. 1170766Speter */ 1171766Speter al = argv[2]; 1172766Speter al = stkrval(al[1], NOFLAGS , RREQ ); 1173766Speter if (al == NIL) 1174766Speter return; 1175766Speter if (classify(al) != TSTR) { 1176766Speter error("Second argument to %s must be a string, not %s", p->symbol, nameof(al)); 1177766Speter return; 1178766Speter } 1179766Speter strnglen = width(al); 1180766Speter } else { 1181766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 1182766Speter strnglen = 0; 1183766Speter } 1184766Speter putop( P2LISTOP , P2INT ); 1185766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 1186766Speter putop( P2LISTOP , P2INT ); 1187766Speter putleaf( P2ICON , text(ap) ? 0: width(ap->type) , 0 , P2INT , 0 ); 1188766Speter putop( P2LISTOP , P2INT ); 1189766Speter putop( P2CALL , P2INT ); 1190766Speter putdot( filename , line ); 1191766Speter return; 1192766Speter 1193766Speter case O_NEW: 1194766Speter case O_DISPOSE: 1195766Speter if (argc == 0) { 1196766Speter error("%s expects at least one argument", p->symbol); 1197766Speter return; 1198766Speter } 11999139Smckusick alv = argv[1]; 12007967Smckusick codeoff(); 12019139Smckusick ap = stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD ); 12027967Smckusick codeon(); 1203766Speter if (ap == NIL) 1204766Speter return; 1205766Speter if (ap->class != PTR) { 1206766Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 1207766Speter return; 1208766Speter } 1209766Speter ap = ap->type; 1210766Speter if (ap == NIL) 1211766Speter return; 12129139Smckusick if (op == O_NEW) 12139139Smckusick cmd = "_NEW"; 12149139Smckusick else /* op == O_DISPOSE */ 12157967Smckusick if ((ap->nl_flags & NFILES) != 0) 12167967Smckusick cmd = "_DFDISPOSE"; 12177967Smckusick else 12187967Smckusick cmd = "_DISPOSE"; 12197967Smckusick putleaf( P2ICON, 0, 0, ADDTYPE( P2FTN | P2INT , P2PTR ), cmd); 12209139Smckusick stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD ); 1221766Speter argv = argv[2]; 1222766Speter if (argv != NIL) { 1223766Speter if (ap->class != RECORD) { 1224766Speter error("Record required when specifying variant tags"); 1225766Speter return; 1226766Speter } 1227766Speter for (; argv != NIL; argv = argv[2]) { 1228766Speter if (ap->ptr[NL_VARNT] == NIL) { 1229766Speter error("Too many tag fields"); 1230766Speter return; 1231766Speter } 1232766Speter if (!isconst(argv[1])) { 1233766Speter error("Second and successive arguments to %s must be constants", p->symbol); 1234766Speter return; 1235766Speter } 1236766Speter gconst(argv[1]); 1237766Speter if (con.ctype == NIL) 1238766Speter return; 1239766Speter if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) { 1240766Speter cerror("Specified tag constant type clashed with variant case selector type"); 1241766Speter return; 1242766Speter } 1243766Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 1244766Speter if (ap->range[0] == con.crval) 1245766Speter break; 1246766Speter if (ap == NIL) { 1247766Speter error("No variant case label value equals specified constant value"); 1248766Speter return; 1249766Speter } 1250766Speter ap = ap->ptr[NL_VTOREC]; 1251766Speter } 1252766Speter } 1253766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1254766Speter putop( P2LISTOP , P2INT ); 1255766Speter putop( P2CALL , P2INT ); 1256766Speter putdot( filename , line ); 12579139Smckusick if (opt('t') && op == O_NEW) { 12589139Smckusick putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 12599139Smckusick , "_blkclr" ); 12609264Smckusick stkrval(alv, NIL , RREQ ); 12619139Smckusick putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 12629139Smckusick putop( P2LISTOP , P2INT ); 12639139Smckusick putop( P2CALL , P2INT ); 12649139Smckusick putdot( filename , line ); 12659139Smckusick } 1266766Speter return; 1267766Speter 1268766Speter case O_DATE: 1269766Speter case O_TIME: 1270766Speter if (argc != 1) { 1271766Speter error("%s expects one argument", p->symbol); 1272766Speter return; 1273766Speter } 1274766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1275766Speter , op == O_DATE ? "_DATE" : "_TIME" ); 1276766Speter ap = stklval(argv[1], MOD|NOUSE); 1277766Speter if (ap == NIL) 1278766Speter return; 1279766Speter if (classify(ap) != TSTR || width(ap) != 10) { 1280766Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 1281766Speter return; 1282766Speter } 1283766Speter putop( P2CALL , P2INT ); 1284766Speter putdot( filename , line ); 1285766Speter return; 1286766Speter 1287766Speter case O_HALT: 1288766Speter if (argc != 0) { 1289766Speter error("halt takes no arguments"); 1290766Speter return; 1291766Speter } 1292766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1293766Speter , "_HALT" ); 1294766Speter 1295766Speter putop( P2UNARY P2CALL , P2INT ); 1296766Speter putdot( filename , line ); 1297766Speter noreach = 1; 1298766Speter return; 1299766Speter 1300766Speter case O_ARGV: 1301766Speter if (argc != 2) { 1302766Speter error("argv takes two arguments"); 1303766Speter return; 1304766Speter } 1305766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1306766Speter , "_ARGV" ); 1307766Speter ap = stkrval(argv[1], NIL , RREQ ); 1308766Speter if (ap == NIL) 1309766Speter return; 1310766Speter if (isnta(ap, "i")) { 1311766Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 1312766Speter return; 1313766Speter } 1314766Speter al = argv[2]; 1315766Speter ap = stklval(al[1], MOD|NOUSE); 1316766Speter if (ap == NIL) 1317766Speter return; 1318766Speter if (classify(ap) != TSTR) { 1319766Speter error("argv's second argument must be a string, not %s", nameof(ap)); 1320766Speter return; 1321766Speter } 1322766Speter putop( P2LISTOP , P2INT ); 1323766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1324766Speter putop( P2LISTOP , P2INT ); 1325766Speter putop( P2CALL , P2INT ); 1326766Speter putdot( filename , line ); 1327766Speter return; 1328766Speter 1329766Speter case O_STLIM: 1330766Speter if (argc != 1) { 1331766Speter error("stlimit requires one argument"); 1332766Speter return; 1333766Speter } 1334766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1335766Speter , "_STLIM" ); 1336766Speter ap = stkrval(argv[1], NIL , RREQ ); 1337766Speter if (ap == NIL) 1338766Speter return; 1339766Speter if (isnta(ap, "i")) { 1340766Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 1341766Speter return; 1342766Speter } 1343766Speter putop( P2CALL , P2INT ); 1344766Speter putdot( filename , line ); 1345766Speter return; 1346766Speter 1347766Speter case O_REMOVE: 1348766Speter if (argc != 1) { 1349766Speter error("remove expects one argument"); 1350766Speter return; 1351766Speter } 1352766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1353766Speter , "_REMOVE" ); 1354766Speter ap = stkrval(argv[1], NOFLAGS , RREQ ); 1355766Speter if (ap == NIL) 1356766Speter return; 1357766Speter if (classify(ap) != TSTR) { 1358766Speter error("remove's argument must be a string, not %s", nameof(ap)); 1359766Speter return; 1360766Speter } 1361766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1362766Speter putop( P2LISTOP , P2INT ); 1363766Speter putop( P2CALL , P2INT ); 1364766Speter putdot( filename , line ); 1365766Speter return; 1366766Speter 1367766Speter case O_LLIMIT: 1368766Speter if (argc != 2) { 1369766Speter error("linelimit expects two arguments"); 1370766Speter return; 1371766Speter } 1372766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1373766Speter , "_LLIMIT" ); 1374766Speter ap = stklval(argv[1], NOFLAGS|NOUSE); 1375766Speter if (ap == NIL) 1376766Speter return; 1377766Speter if (!text(ap)) { 1378766Speter error("linelimit's first argument must be a text file, not %s", nameof(ap)); 1379766Speter return; 1380766Speter } 1381766Speter al = argv[2]; 1382766Speter ap = stkrval(al[1], NIL , RREQ ); 1383766Speter if (ap == NIL) 1384766Speter return; 1385766Speter if (isnta(ap, "i")) { 1386766Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 1387766Speter return; 1388766Speter } 1389766Speter putop( P2LISTOP , P2INT ); 1390766Speter putop( P2CALL , P2INT ); 1391766Speter putdot( filename , line ); 1392766Speter return; 1393766Speter case O_PAGE: 1394766Speter if (argc != 1) { 1395766Speter error("page expects one argument"); 1396766Speter return; 1397766Speter } 13983833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1399766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1400766Speter , "_UNIT" ); 1401766Speter ap = stklval(argv[1], NOFLAGS); 1402766Speter if (ap == NIL) 1403766Speter return; 1404766Speter if (!text(ap)) { 1405766Speter error("Argument to page must be a text file, not %s", nameof(ap)); 1406766Speter return; 1407766Speter } 1408766Speter putop( P2CALL , P2INT ); 1409766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1410766Speter putdot( filename , line ); 1411766Speter if ( opt( 't' ) ) { 1412766Speter putleaf( P2ICON , 0 , 0 1413766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1414766Speter , "_PAGE" ); 14153833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1416766Speter } else { 1417766Speter putleaf( P2ICON , 0 , 0 1418766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1419766Speter , "_fputc" ); 1420766Speter putleaf( P2ICON , '\f' , 0 , P2CHAR , 0 ); 1421766Speter putleaf( P2ICON , 0 , 0 1422766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1423766Speter , "_ACTFILE" ); 14243833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1425766Speter putop( P2CALL , P2INT ); 1426766Speter putop( P2LISTOP , P2INT ); 1427766Speter } 1428766Speter putop( P2CALL , P2INT ); 1429766Speter putdot( filename , line ); 1430766Speter return; 1431766Speter 14327928Smckusick case O_ASRT: 14337928Smckusick if (!opt('t')) 14347928Smckusick return; 14357928Smckusick if (argc == 0 || argc > 2) { 14367928Smckusick error("Assert expects one or two arguments"); 14377928Smckusick return; 14387928Smckusick } 14399139Smckusick if (argc == 2) 14409139Smckusick cmd = "_ASRTS"; 14419139Smckusick else 14429139Smckusick cmd = "_ASRT"; 14437928Smckusick putleaf( P2ICON , 0 , 0 14449139Smckusick , ADDTYPE( P2FTN | P2INT , P2PTR ) , cmd ); 14457928Smckusick ap = stkrval(argv[1], NIL , RREQ ); 14467928Smckusick if (ap == NIL) 14477928Smckusick return; 14487928Smckusick if (isnta(ap, "b")) 14497928Smckusick error("Assert expression must be Boolean, not %ss", nameof(ap)); 14507928Smckusick if (argc == 2) { 14517928Smckusick /* 14527928Smckusick * Optional second argument is a string specifying 14537928Smckusick * why the assertion failed. 14547928Smckusick */ 14557928Smckusick al = argv[2]; 14567928Smckusick al = stkrval(al[1], NIL , RREQ ); 14577928Smckusick if (al == NIL) 14587928Smckusick return; 14597928Smckusick if (classify(al) != TSTR) { 14607928Smckusick error("Second argument to assert must be a string, not %s", nameof(al)); 14617928Smckusick return; 14627928Smckusick } 14639139Smckusick putop( P2LISTOP , P2INT ); 14647928Smckusick } 14657928Smckusick putop( P2CALL , P2INT ); 14667928Smckusick putdot( filename , line ); 14677928Smckusick return; 14687928Smckusick 1469766Speter case O_PACK: 1470766Speter if (argc != 3) { 1471766Speter error("pack expects three arguments"); 1472766Speter return; 1473766Speter } 1474766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1475766Speter , "_PACK" ); 1476766Speter pu = "pack(a,i,z)"; 1477766Speter pua = (al = argv)[1]; 1478766Speter pui = (al = al[2])[1]; 1479766Speter puz = (al = al[2])[1]; 1480766Speter goto packunp; 1481766Speter case O_UNPACK: 1482766Speter if (argc != 3) { 1483766Speter error("unpack expects three arguments"); 1484766Speter return; 1485766Speter } 1486766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1487766Speter , "_UNPACK" ); 1488766Speter pu = "unpack(z,a,i)"; 1489766Speter puz = (al = argv)[1]; 1490766Speter pua = (al = al[2])[1]; 1491766Speter pui = (al = al[2])[1]; 1492766Speter packunp: 1493766Speter ap = stkrval((int *) pui, NLNIL , RREQ ); 1494766Speter if (ap == NIL) 1495766Speter return; 1496766Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 1497766Speter if (ap == NIL) 1498766Speter return; 1499766Speter if (ap->class != ARRAY) { 1500766Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 1501766Speter return; 1502766Speter } 1503766Speter putop( P2LISTOP , P2INT ); 1504766Speter al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 1505766Speter if (al->class != ARRAY) { 1506766Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 1507766Speter return; 1508766Speter } 1509766Speter if (al->type == NIL || ap->type == NIL) 1510766Speter return; 1511766Speter if (al->type != ap->type) { 1512766Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 1513766Speter return; 1514766Speter } 1515766Speter putop( P2LISTOP , P2INT ); 1516766Speter k = width(al); 1517766Speter itemwidth = width(ap->type); 1518766Speter ap = ap->chain; 1519766Speter al = al->chain; 1520766Speter if (ap->chain != NIL || al->chain != NIL) { 1521766Speter error("%s requires a and z to be single dimension arrays", pu); 1522766Speter return; 1523766Speter } 1524766Speter if (ap == NIL || al == NIL) 1525766Speter return; 1526766Speter /* 1527766Speter * al is the range for z i.e. u..v 1528766Speter * ap is the range for a i.e. m..n 1529766Speter * i will be n-m+1 1530766Speter * j will be v-u+1 1531766Speter */ 1532766Speter i = ap->range[1] - ap->range[0] + 1; 1533766Speter j = al->range[1] - al->range[0] + 1; 1534766Speter if (i < j) { 1535766Speter error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i); 1536766Speter return; 1537766Speter } 1538766Speter /* 1539766Speter * get n-m-(v-u) and m for the interpreter 1540766Speter */ 1541766Speter i -= j; 1542766Speter j = ap->range[0]; 1543766Speter putleaf( P2ICON , itemwidth , 0 , P2INT , 0 ); 1544766Speter putop( P2LISTOP , P2INT ); 1545766Speter putleaf( P2ICON , j , 0 , P2INT , 0 ); 1546766Speter putop( P2LISTOP , P2INT ); 1547766Speter putleaf( P2ICON , i , 0 , P2INT , 0 ); 1548766Speter putop( P2LISTOP , P2INT ); 1549766Speter putleaf( P2ICON , k , 0 , P2INT , 0 ); 1550766Speter putop( P2LISTOP , P2INT ); 1551766Speter putop( P2CALL , P2INT ); 1552766Speter putdot( filename , line ); 1553766Speter return; 1554766Speter case 0: 15557928Smckusick error("%s is an unimplemented extension", p->symbol); 1556766Speter return; 1557766Speter 1558766Speter default: 1559766Speter panic("proc case"); 1560766Speter } 1561766Speter } 1562766Speter #endif PC 1563