1 /*- 2 * Copyright (c) 1980 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.proprietary.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)io.c 5.5 (Berkeley) 04/12/91"; 10 #endif /* not lint */ 11 12 /* 13 * io.c 14 * 15 * Routines to generate code for I/O statements. 16 * Some corrections and improvements due to David Wasley, U. C. Berkeley 17 * 18 * University of Utah CS Dept modification history: 19 * 20 * $Header: io.c,v 5.3 86/03/04 17:45:33 donn Exp $ 21 * $Log: io.c,v $ 22 * Revision 5.3 86/03/04 17:45:33 donn 23 * Change the order of length and offset code in startrw() -- always emit 24 * the memoffset first, since it may define a temporary which is used in 25 * the length expression. 26 * 27 * Revision 5.2 85/12/19 17:22:35 donn 28 * Don't permit more than one 'positional iocontrol' parameter unless we 29 * are doing a READ or a WRITE. 30 * 31 * Revision 5.1 85/08/10 03:47:42 donn 32 * 4.3 alpha 33 * 34 * Revision 2.4 85/02/23 21:09:02 donn 35 * Jerry Berkman's compiled format fixes move setfmt into a separate file. 36 * 37 * Revision 2.3 85/01/10 22:33:41 donn 38 * Added some strategic cpexpr()s to prevent memory management bugs. 39 * 40 * Revision 2.2 84/08/04 21:15:47 donn 41 * Removed code that creates extra statement labels, per Jerry Berkman's 42 * fixes to make ASSIGNs work right. 43 * 44 * Revision 2.1 84/07/19 12:03:33 donn 45 * Changed comment headers for UofU. 46 * 47 * Revision 1.2 84/02/26 06:35:57 donn 48 * Added Berkeley changes necessary for shortening offsets to data. 49 * 50 */ 51 52 /* TEMPORARY */ 53 #define TYIOINT TYLONG 54 #define SZIOINT SZLONG 55 56 #include "defs.h" 57 #include "io.h" 58 59 60 LOCAL char ioroutine[XL+1]; 61 62 LOCAL int ioendlab; 63 LOCAL int ioerrlab; 64 LOCAL int endbit; 65 LOCAL int errbit; 66 LOCAL int jumplab; 67 LOCAL int skiplab; 68 LOCAL int ioformatted; 69 LOCAL int statstruct = NO; 70 LOCAL ftnint blklen; 71 72 LOCAL offsetlist *mkiodata(); 73 74 75 #define UNFORMATTED 0 76 #define FORMATTED 1 77 #define LISTDIRECTED 2 78 #define NAMEDIRECTED 3 79 80 #define V(z) ioc[z].iocval 81 82 #define IOALL 07777 83 84 LOCAL struct Ioclist 85 { 86 char *iocname; 87 int iotype; 88 expptr iocval; 89 } ioc[ ] = 90 { 91 { "", 0 }, 92 { "unit", IOALL }, 93 { "fmt", M(IOREAD) | M(IOWRITE) }, 94 { "err", IOALL }, 95 { "end", M(IOREAD) }, 96 { "iostat", IOALL }, 97 { "rec", M(IOREAD) | M(IOWRITE) }, 98 { "recl", M(IOOPEN) | M(IOINQUIRE) }, 99 { "file", M(IOOPEN) | M(IOINQUIRE) }, 100 { "status", M(IOOPEN) | M(IOCLOSE) }, 101 { "access", M(IOOPEN) | M(IOINQUIRE) }, 102 { "form", M(IOOPEN) | M(IOINQUIRE) }, 103 { "blank", M(IOOPEN) | M(IOINQUIRE) }, 104 { "exist", M(IOINQUIRE) }, 105 { "opened", M(IOINQUIRE) }, 106 { "number", M(IOINQUIRE) }, 107 { "named", M(IOINQUIRE) }, 108 { "name", M(IOINQUIRE) }, 109 { "sequential", M(IOINQUIRE) }, 110 { "direct", M(IOINQUIRE) }, 111 { "formatted", M(IOINQUIRE) }, 112 { "unformatted", M(IOINQUIRE) }, 113 { "nextrec", M(IOINQUIRE) } 114 } ; 115 116 #define NIOS (sizeof(ioc)/sizeof(struct Ioclist) - 1) 117 #define MAXIO SZFLAG + 10*SZIOINT + 15*SZADDR 118 119 #define IOSUNIT 1 120 #define IOSFMT 2 121 #define IOSERR 3 122 #define IOSEND 4 123 #define IOSIOSTAT 5 124 #define IOSREC 6 125 #define IOSRECL 7 126 #define IOSFILE 8 127 #define IOSSTATUS 9 128 #define IOSACCESS 10 129 #define IOSFORM 11 130 #define IOSBLANK 12 131 #define IOSEXISTS 13 132 #define IOSOPENED 14 133 #define IOSNUMBER 15 134 #define IOSNAMED 16 135 #define IOSNAME 17 136 #define IOSSEQUENTIAL 18 137 #define IOSDIRECT 19 138 #define IOSFORMATTED 20 139 #define IOSUNFORMATTED 21 140 #define IOSNEXTREC 22 141 142 #define IOSTP V(IOSIOSTAT) 143 144 145 /* offsets in generated structures */ 146 147 #define SZFLAG SZIOINT 148 149 /* offsets for external READ and WRITE statements */ 150 151 #define XERR 0 152 #define XUNIT SZFLAG 153 #define XEND SZFLAG + SZIOINT 154 #define XFMT 2*SZFLAG + SZIOINT 155 #define XREC 2*SZFLAG + SZIOINT + SZADDR 156 #define XRLEN 2*SZFLAG + 2*SZADDR 157 #define XRNUM 2*SZFLAG + 2*SZADDR + SZIOINT 158 159 /* offsets for internal READ and WRITE statements */ 160 161 #define XIERR 0 162 #define XIUNIT SZFLAG 163 #define XIEND SZFLAG + SZADDR 164 #define XIFMT 2*SZFLAG + SZADDR 165 #define XIRLEN 2*SZFLAG + 2*SZADDR 166 #define XIRNUM 2*SZFLAG + 2*SZADDR + SZIOINT 167 #define XIREC 2*SZFLAG + 2*SZADDR + 2*SZIOINT 168 169 /* offsets for OPEN statements */ 170 171 #define XFNAME SZFLAG + SZIOINT 172 #define XFNAMELEN SZFLAG + SZIOINT + SZADDR 173 #define XSTATUS SZFLAG + 2*SZIOINT + SZADDR 174 #define XACCESS SZFLAG + 2*SZIOINT + 2*SZADDR 175 #define XFORMATTED SZFLAG + 2*SZIOINT + 3*SZADDR 176 #define XRECLEN SZFLAG + 2*SZIOINT + 4*SZADDR 177 #define XBLANK SZFLAG + 3*SZIOINT + 4*SZADDR 178 179 /* offset for CLOSE statement */ 180 181 #define XCLSTATUS SZFLAG + SZIOINT 182 183 /* offsets for INQUIRE statement */ 184 185 #define XFILE SZFLAG + SZIOINT 186 #define XFILELEN SZFLAG + SZIOINT + SZADDR 187 #define XEXISTS SZFLAG + 2*SZIOINT + SZADDR 188 #define XOPEN SZFLAG + 2*SZIOINT + 2*SZADDR 189 #define XNUMBER SZFLAG + 2*SZIOINT + 3*SZADDR 190 #define XNAMED SZFLAG + 2*SZIOINT + 4*SZADDR 191 #define XNAME SZFLAG + 2*SZIOINT + 5*SZADDR 192 #define XNAMELEN SZFLAG + 2*SZIOINT + 6*SZADDR 193 #define XQACCESS SZFLAG + 3*SZIOINT + 6*SZADDR 194 #define XQACCLEN SZFLAG + 3*SZIOINT + 7*SZADDR 195 #define XSEQ SZFLAG + 4*SZIOINT + 7*SZADDR 196 #define XSEQLEN SZFLAG + 4*SZIOINT + 8*SZADDR 197 #define XDIRECT SZFLAG + 5*SZIOINT + 8*SZADDR 198 #define XDIRLEN SZFLAG + 5*SZIOINT + 9*SZADDR 199 #define XFORM SZFLAG + 6*SZIOINT + 9*SZADDR 200 #define XFORMLEN SZFLAG + 6*SZIOINT + 10*SZADDR 201 #define XFMTED SZFLAG + 7*SZIOINT + 10*SZADDR 202 #define XFMTEDLEN SZFLAG + 7*SZIOINT + 11*SZADDR 203 #define XUNFMT SZFLAG + 8*SZIOINT + 11*SZADDR 204 #define XUNFMTLEN SZFLAG + 8*SZIOINT + 12*SZADDR 205 #define XQRECL SZFLAG + 9*SZIOINT + 12*SZADDR 206 #define XNEXTREC SZFLAG + 9*SZIOINT + 13*SZADDR 207 #define XQBLANK SZFLAG + 9*SZIOINT + 14*SZADDR 208 #define XQBLANKLEN SZFLAG + 9*SZIOINT + 15*SZADDR 209 210 fmtstmt(lp) 211 register struct Labelblock *lp; 212 { 213 if(lp == NULL) 214 { 215 execerr("unlabeled format statement" , CNULL); 216 return(-1); 217 } 218 if(lp->labtype == LABUNKNOWN) 219 lp->labtype = LABFORMAT; 220 else if(lp->labtype != LABFORMAT) 221 { 222 execerr("bad format number", CNULL); 223 return(-1); 224 } 225 return(lp->labelno); 226 } 227 228 229 230 startioctl() 231 { 232 register int i; 233 234 inioctl = YES; 235 nioctl = 0; 236 ioformatted = UNFORMATTED; 237 for(i = 1 ; i<=NIOS ; ++i) 238 V(i) = NULL; 239 } 240 241 242 243 endioctl() 244 { 245 int i; 246 expptr p; 247 248 inioctl = NO; 249 250 /* set up for error recovery */ 251 252 ioerrlab = ioendlab = skiplab = jumplab = 0; 253 254 if(p = V(IOSEND)) 255 if(ISICON(p)) 256 ioendlab = execlab(p->constblock.constant.ci) ->labelno; 257 else 258 err("bad end= clause"); 259 260 if(p = V(IOSERR)) 261 if(ISICON(p)) 262 ioerrlab = execlab(p->constblock.constant.ci) ->labelno; 263 else 264 err("bad err= clause"); 265 266 if(IOSTP) 267 if(IOSTP->tag!=TADDR || ! ISINT(IOSTP->addrblock.vtype) ) 268 { 269 err("iostat must be an integer variable"); 270 frexpr(IOSTP); 271 IOSTP = NULL; 272 } 273 274 if(iostmt == IOREAD) 275 { 276 if(IOSTP) 277 { 278 if(ioerrlab && ioendlab && ioerrlab==ioendlab) 279 jumplab = ioerrlab; 280 else 281 skiplab = jumplab = newlabel(); 282 } 283 else { 284 if(ioerrlab && ioendlab && ioerrlab!=ioendlab) 285 { 286 IOSTP = (expptr) mktemp(TYINT, PNULL); 287 skiplab = jumplab = newlabel(); 288 } 289 else 290 jumplab = (ioerrlab ? ioerrlab : ioendlab); 291 } 292 } 293 else if(iostmt == IOWRITE) 294 { 295 if(IOSTP && !ioerrlab) 296 skiplab = jumplab = newlabel(); 297 else 298 jumplab = ioerrlab; 299 } 300 else 301 jumplab = ioerrlab; 302 303 endbit = IOSTP!=NULL || ioendlab!=0; /* for use in startrw() */ 304 errbit = IOSTP!=NULL || ioerrlab!=0; 305 if(iostmt!=IOREAD && iostmt!=IOWRITE) 306 { 307 if(ioblkp == NULL) 308 ioblkp = autovar( (MAXIO+SZIOINT-1)/SZIOINT , TYIOINT, PNULL); 309 ioset(TYIOINT, XERR, ICON(errbit)); 310 } 311 312 switch(iostmt) 313 { 314 case IOOPEN: 315 dofopen(); break; 316 317 case IOCLOSE: 318 dofclose(); break; 319 320 case IOINQUIRE: 321 dofinquire(); break; 322 323 case IOBACKSPACE: 324 dofmove("f_back"); break; 325 326 case IOREWIND: 327 dofmove("f_rew"); break; 328 329 case IOENDFILE: 330 dofmove("f_end"); break; 331 332 case IOREAD: 333 case IOWRITE: 334 startrw(); break; 335 336 default: 337 fatali("impossible iostmt %d", iostmt); 338 } 339 for(i = 1 ; i<=NIOS ; ++i) 340 if(i!=IOSIOSTAT && V(i)!=NULL) 341 frexpr(V(i)); 342 } 343 344 345 346 iocname() 347 { 348 register int i; 349 int found, mask; 350 351 found = 0; 352 mask = M(iostmt); 353 for(i = 1 ; i <= NIOS ; ++i) 354 if(toklen==strlen(ioc[i].iocname) && eqn(toklen, token, ioc[i].iocname)) 355 if(ioc[i].iotype & mask) 356 return(i); 357 else found = i; 358 if(found) 359 errstr("invalid control %s for statement", ioc[found].iocname); 360 else 361 errstr("unknown iocontrol %s", varstr(toklen, token) ); 362 return(IOSBAD); 363 } 364 365 366 ioclause(n, p) 367 register int n; 368 register expptr p; 369 { 370 struct Ioclist *iocp; 371 372 ++nioctl; 373 if(n == IOSBAD) 374 return; 375 if(n == IOSPOSITIONAL) 376 { 377 if(nioctl > IOSFMT || 378 nioctl > IOSUNIT && !(iostmt == IOREAD || iostmt == IOWRITE)) 379 { 380 err("illegal positional iocontrol"); 381 return; 382 } 383 n = nioctl; 384 } 385 386 if(p == NULL) 387 { 388 if(n == IOSUNIT) 389 p = (expptr) (iostmt==IOREAD ? IOSTDIN : IOSTDOUT); 390 else if(n != IOSFMT) 391 { 392 err("illegal * iocontrol"); 393 return; 394 } 395 } 396 if(n == IOSFMT) 397 ioformatted = (p==NULL ? LISTDIRECTED : FORMATTED); 398 399 iocp = & ioc[n]; 400 if(iocp->iocval == NULL) 401 { 402 p = (expptr) cpexpr(p); 403 if(n!=IOSFMT && ( n!=IOSUNIT || (p!=NULL && p->headblock.vtype!=TYCHAR) ) ) 404 p = fixtype(p); 405 if(p!=NULL && ISCONST(p) && p->constblock.vtype==TYCHAR) 406 p = (expptr) putconst(p); 407 iocp->iocval = p; 408 } 409 else 410 errstr("iocontrol %s repeated", iocp->iocname); 411 } 412 413 /* io list item */ 414 415 doio(list) 416 chainp list; 417 { 418 expptr call0(); 419 420 if(ioformatted == NAMEDIRECTED) 421 { 422 if(list) 423 err("no I/O list allowed in NAMELIST read/write"); 424 } 425 else 426 { 427 doiolist(list); 428 ioroutine[0] = 'e'; 429 putiocall( call0(TYINT, ioroutine) ); 430 } 431 } 432 433 434 435 436 437 LOCAL doiolist(p0) 438 chainp p0; 439 { 440 chainp p; 441 register tagptr q; 442 register expptr qe; 443 register Namep qn; 444 Addrp tp, mkscalar(); 445 int range; 446 expptr expr; 447 448 for (p = p0 ; p ; p = p->nextp) 449 { 450 q = p->datap; 451 if(q->tag == TIMPLDO) 452 { 453 exdo(range=newlabel(), q->impldoblock.impdospec); 454 doiolist(q->impldoblock.datalist); 455 enddo(range); 456 free( (charptr) q); 457 } 458 else { 459 if(q->tag==TPRIM && q->primblock.argsp==NULL 460 && q->primblock.namep->vdim!=NULL) 461 { 462 vardcl(qn = q->primblock.namep); 463 if(qn->vdim->nelt) 464 putio( fixtype(cpexpr(qn->vdim->nelt)), 465 mkscalar(qn) ); 466 else 467 err("attempt to i/o array of unknown size"); 468 } 469 else if(q->tag==TPRIM && q->primblock.argsp==NULL && 470 (qe = (expptr) memversion(q->primblock.namep)) ) 471 putio(ICON(1),qe); 472 else if( (qe = fixtype(cpexpr(q)))->tag==TADDR) 473 putio(ICON(1), qe); 474 else if(qe->headblock.vtype != TYERROR) 475 { 476 if(iostmt == IOWRITE) 477 { 478 ftnint lencat(); 479 expptr qvl; 480 qvl = NULL; 481 if( ISCHAR(qe) ) 482 { 483 qvl = (expptr) 484 cpexpr(qe->headblock.vleng); 485 tp = mktemp(qe->headblock.vtype, 486 ICON(lencat(qe))); 487 } 488 else 489 tp = mktemp(qe->headblock.vtype, 490 qe->headblock.vleng); 491 if (optimflag) 492 { 493 expr = mkexpr(OPASSIGN,cpexpr(tp),qe); 494 optbuff (SKEQ,expr,0,0); 495 } 496 else 497 puteq (cpexpr(tp),qe); 498 if(qvl) /* put right length on block */ 499 { 500 frexpr(tp->vleng); 501 tp->vleng = qvl; 502 } 503 putio(ICON(1), tp); 504 } 505 else 506 err("non-left side in READ list"); 507 } 508 frexpr(q); 509 } 510 } 511 frchain( &p0 ); 512 } 513 514 515 516 517 518 LOCAL putio(nelt, addr) 519 expptr nelt; 520 register expptr addr; 521 { 522 int type; 523 register expptr q; 524 525 type = addr->headblock.vtype; 526 if(ioformatted!=LISTDIRECTED && ISCOMPLEX(type) ) 527 { 528 nelt = mkexpr(OPSTAR, ICON(2), nelt); 529 type -= (TYCOMPLEX-TYREAL); 530 } 531 532 /* pass a length with every item. for noncharacter data, fake one */ 533 if(type != TYCHAR) 534 { 535 addr->headblock.vtype = TYCHAR; 536 addr->headblock.vleng = ICON( typesize[type] ); 537 } 538 539 nelt = fixtype( mkconv(TYLENG,nelt) ); 540 if(ioformatted == LISTDIRECTED) 541 q = call3(TYINT, "do_lio", mkconv(TYLONG, ICON(type)), nelt, addr); 542 else 543 q = call2(TYINT, (ioformatted==FORMATTED ? "do_fio" : "do_uio"), 544 nelt, addr); 545 putiocall(q); 546 } 547 548 549 550 551 endio() 552 { 553 if(skiplab) 554 { 555 if (optimflag) 556 optbuff (SKLABEL, 0, skiplab, 0); 557 else 558 putlabel (skiplab); 559 if(ioendlab) 560 { 561 expptr test; 562 test = mkexpr(OPGE, cpexpr(IOSTP), ICON(0)); 563 if (optimflag) 564 optbuff (SKIOIFN,test,ioendlab,0); 565 else 566 putif (test,ioendlab); 567 } 568 if(ioerrlab) 569 { 570 expptr test; 571 test = mkexpr 572 ( ((iostmt==IOREAD||iostmt==IOWRITE) ? OPLE : OPEQ), 573 cpexpr(IOSTP), ICON(0)); 574 if (optimflag) 575 optbuff (SKIOIFN,test,ioerrlab,0); 576 else 577 putif (test,ioerrlab); 578 } 579 } 580 if(IOSTP) 581 frexpr(IOSTP); 582 } 583 584 585 586 LOCAL putiocall(q) 587 register expptr q; 588 { 589 if(IOSTP) 590 { 591 q->headblock.vtype = TYINT; 592 q = fixexpr( mkexpr(OPASSIGN, cpexpr(IOSTP), q)); 593 } 594 595 if(jumplab) 596 if (optimflag) 597 optbuff (SKIOIFN,mkexpr(OPEQ,q,ICON(0)),jumplab,0); 598 else 599 putif (mkexpr(OPEQ,q,ICON(0)),jumplab); 600 else 601 if (optimflag) 602 optbuff (SKEQ, q, 0, 0); 603 else 604 putexpr(q); 605 } 606 607 startrw() 608 { 609 register expptr p; 610 register Namep np; 611 register Addrp unitp, fmtp, recp, tioblkp; 612 register expptr nump; 613 register ioblock *t; 614 Addrp mkscalar(); 615 expptr mkaddcon(); 616 int k; 617 flag intfile, sequential, ok, varfmt; 618 619 /* First look at all the parameters and determine what is to be done */ 620 621 ok = YES; 622 statstruct = YES; 623 624 intfile = NO; 625 if(p = V(IOSUNIT)) 626 { 627 if( ISINT(p->headblock.vtype) ) 628 unitp = (Addrp) cpexpr(p); 629 else if(p->headblock.vtype == TYCHAR) 630 { 631 intfile = YES; 632 if(p->tag==TPRIM && p->primblock.argsp==NULL && 633 (np = p->primblock.namep)->vdim!=NULL) 634 { 635 vardcl(np); 636 if(np->vdim->nelt) 637 { 638 nump = (expptr) cpexpr(np->vdim->nelt); 639 if( ! ISCONST(nump) ) 640 statstruct = NO; 641 } 642 else 643 { 644 err("attempt to use internal unit array of unknown size"); 645 ok = NO; 646 nump = ICON(1); 647 } 648 unitp = mkscalar(np); 649 } 650 else { 651 nump = ICON(1); 652 unitp = (Addrp) fixtype(cpexpr(p)); 653 } 654 if(! isstatic(unitp) ) 655 statstruct = NO; 656 } 657 else 658 { 659 err("bad unit specifier type"); 660 ok = NO; 661 } 662 } 663 else 664 { 665 err("bad unit specifier"); 666 ok = NO; 667 } 668 669 sequential = YES; 670 if(p = V(IOSREC)) 671 if( ISINT(p->headblock.vtype) ) 672 { 673 recp = (Addrp) cpexpr(p); 674 sequential = NO; 675 } 676 else { 677 err("bad REC= clause"); 678 ok = NO; 679 } 680 else 681 recp = NULL; 682 683 684 varfmt = YES; 685 fmtp = NULL; 686 if(p = V(IOSFMT)) 687 { 688 if(p->tag==TPRIM && p->primblock.argsp==NULL) 689 { 690 np = p->primblock.namep; 691 if(np->vclass == CLNAMELIST) 692 { 693 ioformatted = NAMEDIRECTED; 694 fmtp = (Addrp) fixtype(cpexpr(p)); 695 goto endfmt; 696 } 697 vardcl(np); 698 if(np->vdim) 699 { 700 if( ! ONEOF(np->vstg, MSKSTATIC) ) 701 statstruct = NO; 702 fmtp = mkscalar(np); 703 goto endfmt; 704 } 705 if( ISINT(np->vtype) ) /* ASSIGNed label */ 706 { 707 statstruct = NO; 708 varfmt = NO; 709 fmtp = (Addrp) fixtype(cpexpr(p)); 710 goto endfmt; 711 } 712 } 713 p = V(IOSFMT) = fixtype(p); 714 if(p->headblock.vtype == TYCHAR) 715 { 716 if (p->tag == TCONST) p = (expptr) putconst(p); 717 if( ! isstatic(p) ) 718 statstruct = NO; 719 fmtp = (Addrp) cpexpr(p); 720 } 721 else if( ISICON(p) ) 722 { 723 if( (k = fmtstmt( mklabel(p->constblock.constant.ci) )) > 0 ) 724 { 725 fmtp = (Addrp) mkaddcon(k); 726 varfmt = NO; 727 } 728 else 729 ioformatted = UNFORMATTED; 730 } 731 else { 732 err("bad format descriptor"); 733 ioformatted = UNFORMATTED; 734 ok = NO; 735 } 736 } 737 else 738 fmtp = NULL; 739 740 endfmt: 741 if(intfile && ioformatted==UNFORMATTED) 742 { 743 err("unformatted internal I/O not allowed"); 744 ok = NO; 745 } 746 if(!sequential && ioformatted==LISTDIRECTED) 747 { 748 err("direct list-directed I/O not allowed"); 749 ok = NO; 750 } 751 if(!sequential && ioformatted==NAMEDIRECTED) 752 { 753 err("direct namelist I/O not allowed"); 754 ok = NO; 755 } 756 757 if( ! ok ) 758 return; 759 760 if (optimflag && ISCONST (fmtp)) 761 fmtp = putconst ( (expptr) fmtp); 762 763 /* 764 Now put out the I/O structure, statically if all the clauses 765 are constants, dynamically otherwise 766 */ 767 768 if(statstruct) 769 { 770 tioblkp = ioblkp; 771 ioblkp = ALLOC(Addrblock); 772 ioblkp->tag = TADDR; 773 ioblkp->vtype = TYIOINT; 774 ioblkp->vclass = CLVAR; 775 ioblkp->vstg = STGINIT; 776 ioblkp->memno = ++lastvarno; 777 ioblkp->memoffset = ICON(0); 778 blklen = (intfile ? XIREC+SZIOINT : 779 (sequential ? XFMT+SZADDR : XRNUM+SZIOINT) ); 780 t = ALLOC(IoBlock); 781 t->blkno = ioblkp->memno; 782 t->len = blklen; 783 t->next = iodata; 784 iodata = t; 785 } 786 else if(ioblkp == NULL) 787 ioblkp = autovar( (MAXIO+SZIOINT-1)/SZIOINT , TYIOINT, PNULL); 788 789 ioset(TYIOINT, XERR, ICON(errbit)); 790 if(iostmt == IOREAD) 791 ioset(TYIOINT, (intfile ? XIEND : XEND), ICON(endbit) ); 792 793 if(intfile) 794 { 795 ioset(TYIOINT, XIRNUM, nump); 796 ioseta(XIUNIT, cpexpr(unitp)); 797 ioset(TYIOINT, XIRLEN, cpexpr(unitp->vleng) ); 798 frexpr(unitp); 799 } 800 else 801 ioset(TYIOINT, XUNIT, (expptr) unitp); 802 803 if(recp) 804 ioset(TYIOINT, (intfile ? XIREC : XREC) , (expptr) recp); 805 806 if(varfmt) 807 ioseta( intfile ? XIFMT : XFMT , fmtp); 808 else 809 ioset(TYADDR, intfile ? XIFMT : XFMT, (expptr) fmtp); 810 811 ioroutine[0] = 's'; 812 ioroutine[1] = '_'; 813 ioroutine[2] = (iostmt==IOREAD ? 'r' : 'w'); 814 ioroutine[3] = (sequential ? 's' : 'd'); 815 ioroutine[4] = "ufln" [ioformatted]; 816 ioroutine[5] = (intfile ? 'i' : 'e'); 817 ioroutine[6] = '\0'; 818 819 putiocall( call1(TYINT, ioroutine, cpexpr(ioblkp) )); 820 821 if(statstruct) 822 { 823 frexpr(ioblkp); 824 ioblkp = tioblkp; 825 statstruct = NO; 826 } 827 } 828 829 830 831 LOCAL dofopen() 832 { 833 register expptr p; 834 835 if( (p = V(IOSUNIT)) && ISINT(p->headblock.vtype) ) 836 ioset(TYIOINT, XUNIT, cpexpr(p) ); 837 else 838 err("bad unit in open"); 839 if( (p = V(IOSFILE)) ) 840 if(p->headblock.vtype == TYCHAR) 841 ioset(TYIOINT, XFNAMELEN, cpexpr(p->headblock.vleng) ); 842 else 843 err("bad file in open"); 844 845 iosetc(XFNAME, p); 846 847 if(p = V(IOSRECL)) 848 if( ISINT(p->headblock.vtype) ) 849 ioset(TYIOINT, XRECLEN, cpexpr(p) ); 850 else 851 err("bad recl"); 852 else 853 ioset(TYIOINT, XRECLEN, ICON(0) ); 854 855 iosetc(XSTATUS, V(IOSSTATUS)); 856 iosetc(XACCESS, V(IOSACCESS)); 857 iosetc(XFORMATTED, V(IOSFORM)); 858 iosetc(XBLANK, V(IOSBLANK)); 859 860 putiocall( call1(TYINT, "f_open", cpexpr(ioblkp) )); 861 } 862 863 864 LOCAL dofclose() 865 { 866 register expptr p; 867 868 if( (p = V(IOSUNIT)) && ISINT(p->headblock.vtype) ) 869 { 870 ioset(TYIOINT, XUNIT, cpexpr(p) ); 871 iosetc(XCLSTATUS, V(IOSSTATUS)); 872 putiocall( call1(TYINT, "f_clos", cpexpr(ioblkp)) ); 873 } 874 else 875 err("bad unit in close statement"); 876 } 877 878 879 LOCAL dofinquire() 880 { 881 register expptr p; 882 if(p = V(IOSUNIT)) 883 { 884 if( V(IOSFILE) ) 885 err("inquire by unit or by file, not both"); 886 ioset(TYIOINT, XUNIT, cpexpr(p) ); 887 } 888 else if( ! V(IOSFILE) ) 889 err("must inquire by unit or by file"); 890 iosetlc(IOSFILE, XFILE, XFILELEN); 891 iosetip(IOSEXISTS, XEXISTS); 892 iosetip(IOSOPENED, XOPEN); 893 iosetip(IOSNUMBER, XNUMBER); 894 iosetip(IOSNAMED, XNAMED); 895 iosetlc(IOSNAME, XNAME, XNAMELEN); 896 iosetlc(IOSACCESS, XQACCESS, XQACCLEN); 897 iosetlc(IOSSEQUENTIAL, XSEQ, XSEQLEN); 898 iosetlc(IOSDIRECT, XDIRECT, XDIRLEN); 899 iosetlc(IOSFORM, XFORM, XFORMLEN); 900 iosetlc(IOSFORMATTED, XFMTED, XFMTEDLEN); 901 iosetlc(IOSUNFORMATTED, XUNFMT, XUNFMTLEN); 902 iosetip(IOSRECL, XQRECL); 903 iosetip(IOSNEXTREC, XNEXTREC); 904 iosetlc(IOSBLANK, XQBLANK, XQBLANKLEN); 905 906 putiocall( call1(TYINT, "f_inqu", cpexpr(ioblkp) )); 907 } 908 909 910 911 LOCAL dofmove(subname) 912 char *subname; 913 { 914 register expptr p; 915 916 if( (p = V(IOSUNIT)) && ISINT(p->headblock.vtype) ) 917 { 918 ioset(TYIOINT, XUNIT, cpexpr(p) ); 919 putiocall( call1(TYINT, subname, cpexpr(ioblkp) )); 920 } 921 else 922 err("bad unit in I/O motion statement"); 923 } 924 925 926 927 LOCAL 928 ioset(type, offset, p) 929 int type; 930 int offset; 931 register expptr p; 932 { 933 static char *badoffset = "badoffset in ioset"; 934 935 register Addrp q; 936 register offsetlist *op; 937 938 q = (Addrp) cpexpr(ioblkp); 939 q->vtype = type; 940 q->memoffset = fixtype( mkexpr(OPPLUS, q->memoffset, ICON(offset)) ); 941 942 if (statstruct && ISCONST(p)) 943 { 944 if (!ISICON(q->memoffset)) 945 fatal(badoffset); 946 947 op = mkiodata(q->memno, q->memoffset->constblock.constant.ci, blklen); 948 if (op->tag != 0) 949 fatal(badoffset); 950 951 if (type == TYADDR) 952 { 953 op->tag = NDLABEL; 954 op->val.label = p->constblock.constant.ci; 955 } 956 else 957 { 958 op->tag = NDDATA; 959 op->val.cp = (Constp) convconst(type, 0, p); 960 } 961 962 frexpr((tagptr) p); 963 frexpr((tagptr) q); 964 } 965 else 966 if (optimflag) 967 optbuff (SKEQ, mkexpr(OPASSIGN,q,p), 0,0); 968 else 969 puteq (q,p); 970 971 return; 972 } 973 974 975 976 977 LOCAL iosetc(offset, p) 978 int offset; 979 register expptr p; 980 { 981 if(p == NULL) 982 ioset(TYADDR, offset, ICON(0) ); 983 else if(p->headblock.vtype == TYCHAR) 984 ioset(TYADDR, offset, addrof(cpexpr(p) )); 985 else 986 err("non-character control clause"); 987 } 988 989 990 991 LOCAL ioseta(offset, p) 992 int offset; 993 register Addrp p; 994 { 995 static char *badoffset = "bad offset in ioseta"; 996 997 int blkno; 998 register offsetlist *op; 999 1000 if(statstruct) 1001 { 1002 blkno = ioblkp->memno; 1003 op = mkiodata(blkno, offset, blklen); 1004 if (op->tag != 0) 1005 fatal(badoffset); 1006 1007 if (p == NULL) 1008 op->tag = NDNULL; 1009 else if (p->tag == TADDR) 1010 { 1011 op->tag = NDADDR; 1012 op->val.addr.stg = p->vstg; 1013 op->val.addr.memno = p->memno; 1014 op->val.addr.offset = p->memoffset->constblock.constant.ci; 1015 } 1016 else 1017 badtag("ioseta", p->tag); 1018 } 1019 else 1020 ioset(TYADDR, offset, p ? addrof(p) : ICON(0) ); 1021 1022 return; 1023 } 1024 1025 1026 1027 1028 LOCAL iosetip(i, offset) 1029 int i, offset; 1030 { 1031 register expptr p; 1032 1033 if(p = V(i)) 1034 if(p->tag==TADDR && 1035 ONEOF(p->addrblock.vtype, M(TYLONG)|M(TYLOGICAL)) ) 1036 ioset(TYADDR, offset, addrof(cpexpr(p)) ); 1037 else 1038 errstr("impossible inquire parameter %s", ioc[i].iocname); 1039 else 1040 ioset(TYADDR, offset, ICON(0) ); 1041 } 1042 1043 1044 1045 LOCAL iosetlc(i, offp, offl) 1046 int i, offp, offl; 1047 { 1048 register expptr p; 1049 if( (p = V(i)) && p->headblock.vtype==TYCHAR) 1050 ioset(TYIOINT, offl, cpexpr(p->headblock.vleng) ); 1051 iosetc(offp, p); 1052 } 1053 1054 1055 LOCAL offsetlist * 1056 mkiodata(blkno, offset, len) 1057 int blkno; 1058 ftnint offset; 1059 ftnint len; 1060 { 1061 register offsetlist *p, *q; 1062 register ioblock *t; 1063 register int found; 1064 1065 found = NO; 1066 t = iodata; 1067 1068 while (found == NO && t != NULL) 1069 { 1070 if (t->blkno == blkno) 1071 found = YES; 1072 else 1073 t = t->next; 1074 } 1075 1076 if (found == NO) 1077 { 1078 t = ALLOC(IoBlock); 1079 t->blkno = blkno; 1080 t->next = iodata; 1081 iodata = t; 1082 } 1083 1084 if (len > t->len) 1085 t->len = len; 1086 1087 p = t->olist; 1088 1089 if (p == NULL) 1090 { 1091 p = ALLOC(OffsetList); 1092 p->next = NULL; 1093 p->offset = offset; 1094 t->olist = p; 1095 return (p); 1096 } 1097 1098 for (;;) 1099 { 1100 if (p->offset == offset) 1101 return (p); 1102 else if (p->next != NULL && 1103 p->next->offset <= offset) 1104 p = p->next; 1105 else 1106 { 1107 q = ALLOC(OffsetList); 1108 q->next = p->next; 1109 p->next = q; 1110 q->offset = offset; 1111 return (q); 1112 } 1113 } 1114 } 1115 1116 1117 outiodata() 1118 { 1119 static char *varfmt = "v.%d:\n"; 1120 1121 register ioblock *p; 1122 register ioblock *t; 1123 1124 if (iodata == NULL) return; 1125 1126 p = iodata; 1127 1128 while (p != NULL) 1129 { 1130 pralign(ALIDOUBLE); 1131 fprintf(initfile, varfmt, p->blkno); 1132 outolist(p->olist, p->len); 1133 1134 t = p; 1135 p = t->next; 1136 free((char *) t); 1137 } 1138 1139 iodata = NULL; 1140 return; 1141 } 1142 1143 1144 1145 LOCAL 1146 outolist(op, len) 1147 register offsetlist *op; 1148 register int len; 1149 { 1150 static char *overlap = "overlapping i/o fields in outolist"; 1151 static char *toolong = "offset too large in outolist"; 1152 1153 register offsetlist *t; 1154 register ftnint clen; 1155 register Constp cp; 1156 register int type; 1157 1158 clen = 0; 1159 1160 while (op != NULL) 1161 { 1162 if (clen > op->offset) 1163 fatal(overlap); 1164 1165 if (clen < op->offset) 1166 { 1167 prspace(op->offset - clen); 1168 clen = op->offset; 1169 } 1170 1171 switch (op->tag) 1172 { 1173 default: 1174 badtag("outolist", op->tag); 1175 1176 case NDDATA: 1177 cp = op->val.cp; 1178 type = cp->vtype; 1179 if (type != TYIOINT) 1180 badtype("outolist", type); 1181 prconi(initfile, type, cp->constant.ci); 1182 clen += typesize[type]; 1183 frexpr((tagptr) cp); 1184 break; 1185 1186 case NDLABEL: 1187 prcona(initfile, op->val.label); 1188 clen += typesize[TYADDR]; 1189 break; 1190 1191 case NDADDR: 1192 praddr(initfile, op->val.addr.stg, op->val.addr.memno, 1193 op->val.addr.offset); 1194 clen += typesize[TYADDR]; 1195 break; 1196 1197 case NDNULL: 1198 praddr(initfile, STGNULL, 0, (ftnint) 0); 1199 clen += typesize[TYADDR]; 1200 break; 1201 } 1202 1203 t = op; 1204 op = t->next; 1205 free((char *) t); 1206 } 1207 1208 if (clen > len) 1209 fatal(toolong); 1210 1211 if (clen < len) 1212 prspace(len - clen); 1213 1214 return; 1215 } 1216