$title('FILE AND I/O MODULE')
file:
do;

/*

  modified  3/26/81  R. Silberstein
  modified  3/28/81  R. Silberstein
  modified  3/30/81  R. Silberstein
  modified  4/7/81   R. Silberstein
  modified  4/16/81  R. Silberstein
  modified  6/16/81  R. Silberstein
  modified  9/14/81  R. Silberstein

 */

/*
        This is the modules to perform BYTE i/o to      
        the following 5 logical devices:                        

                source   - file
                include  - file
                hex      - file
                symbol   - file
                print    - file

        Each of the logical files may be assigned to the
        following physical devices :

                null     (not legal for source and include file)
                console
                printer  (not legal for source and include file)
                disk

        The module defines the following set
        of public subroutines:

                INSOURCEBYTE         - read 1 byte from source file
                ININCLUDEBYTE        - read 1 byte from include file
                OUTHEXBYTE (ch)      - write 1 byte to hex file
                OUTSYMBOLBYTE (ch)   - write 1 byte to symbol file
                OUTPRINTBYTE (ch)    - write 1 byte to print file

                OPENSOURCE           - open source file
                OPENINCLUDE          - open include file
                OPENHEX              - open hex file
                OPENSYMBOL           - open symbol file
                OPENPRINT            - open print file
                REWINDSOURCE         - rewind source file

                CLOSESOURCE          - close source file
                CLOSEINCLUDE         - close include file
                CLOSEHEX             - close hex file
                CLOSESYMBOL          - close symbol file
                CLOSEPRINT           - close print file

        In addition, 2 subroutines to set up the correct
        file names and routing to correct physical device
        are included. These are:

                FILESETUP
                I$FILESETUP

        The "filesetup" routine sets up the source, hex, symbol
        and print files by scanning the user command tail of the
        program activating line. The format of the command line
        is described in the program format section of the user's
        manual. The routine also initiates the global string array
        "SOURCENAME" with the source file name, this array to be
        used later by the printout module.

        The "ifilesetup" sets up the format of the include file
        given by the INCLUDE command of the assembler.

*/

$include (:f1:macro.lit)
$include (:f1:struc.lit)
$include (:f1:dev.lit)
$include (:f1:io.ext)
$include (:f1:subr1.ext)
$include (:f1:subr2.ext)
$INCLUDE (:F1:TEXT.EXT)
$include (:f1:global.ext)

dcl
diskunit                byte,

nulltype        lit     '0',    /* subroutine "devicetype" */
consoletype     lit     '1',
printertype     lit     '2',
disktype        lit     '3',

dr              lit     '0',    /* drive code in fcb block */
fn              lit     '1',    /* filename in fcb block */
ft              lit     '9',    /* filetype in fcb block */
ex              lit     '12',   /* file extension number */
s2              lit     '14',
nr              lit     '32',   /* file record number */
dollar          lit     '''$''',

asmdefault(3)   byte data ('A86'),   /* different file types */
hexdefault(3)   byte data ('H86'),
lstdefault(3)   byte data ('LST'),
symdefault(3)   byte data ('SYM'),

sourcefile      file$i$structure,
includefile     file$i$structure,
hexfile         file$o$structure,
printfile       file$o$structure,
symbolfile      file$o$structure;

clearfcb: proc(fcbpt,defaultpt);
  dcl
  (fcbpt,defaultpt) addr,
  dest based  fcbpt (1) byte;
  CALL FILL (0, 33, FCBPT);
  CALL FILL (' ', 8, FCBPT+FN);
  call copy(3,defaultpt,.dest(ft));
end clearfcb;

clearcontrol: procedure(point,defaultptr);
  dcl (point,defaultptr) addr,
      x based point file$o$structure;
  call clearfcb(.x.fcbblock,defaultptr);
  x.disk=diskunit;
end clearcontrol;

devicetype: proc(ch) byte;
  dcl ch byte;
  if ch=null then return nulltype;
  if ch=console then return consoletype;
  if ch=printer then return printertype;
  return disktype;
end devicetype;

disk$select: procedure(disk);
  dcl disk byte;
  if diskunit <> disk then$do
    diskunit=disk;
    call select$disk(diskunit);
  end$if;
end disk$select;

inbyte: proc (ptr) byte;
  dcl ptr addr,
      x based ptr file$i$structure,
      ch byte,
      i  addr;

  i=x.bufptr;
  if i=length(x.buffer) then$do
    i=0;
    call disk$select(x.disk);
    do while i < length(x.buffer);
      call SET$DMA$ADDRESS (.x.buffer(i));
      IF (CH := READ$RECORD (.X.FCBBLOCK)) <> 0 THEN$DO
        IF CH = 1 THEN$DO
          X.BUFFER (I) = END$OF$FILE;
          I = LENGTH (X.BUFFER);
        ELSE$DO
          CALL FILEABORT (.X, .DISKREADERRTEXT);
        END$IF;
      else$do
        i=i+128;
      end$if;
    end$while;
    i=0;
  end$if;
  ch=x.buffer(i);
  x.bufptr=i+1;
  return ch;
end inbyte;

FLUSHBUFFER: PROCEDURE (PTR);
  DECLARE (PTR, I) ADDRESS, X BASED PTR FILE$O$STRUCTURE;

    call disk$select(x.disk);
    i=0;
    do while i < x.bufptr;
      call SET$DMA$ADDRESS (.x.buffer(i));
      IF WRITE$RECORD (.X.FCBBLOCK) > 0 THEN
        CALL FILEABORT (.X, .DISKWRITEERRTXT);
      i=i+128;
    end$while;
END FLUSHBUFFER;

outbyte: proc(ch,ptr);
  dcl ch byte,
      ptr addr,
      x based ptr file$o$structure,
      i  addr;

  do case devicetype(x.disk);

    /* null */
    do; end;       /* do nothing */

    /* console */
    call write$console(ch);

    /* printer */
    call write$list(ch);

    /* disk file */
    do;
    i=x.bufptr;
    if i=length(x.buffer) then$do
      CALL FLUSHBUFFER (PTR);
      i=0;
    end$if;
    x.buffer(i)=ch;
    x.bufptr=i+1;
    end;
  end$case;
end outbyte;

open$input: proc (ptr);
  dcl ptr addr,
      x based ptr file$i$structure;

  x.bufptr=length(x.buffer);
  call disk$select(x.disk);
  IF LOW (VERSION) >= 30H THEN$DO
    IF OPEN$RO$FILE (.X.FCBBLOCK) <> 0FFH THEN RETURN;
  ELSE$DO
    IF OPEN$FILE (.X.FCBBLOCK) <> 0FFH THEN RETURN;
  END$IF;
  CALL FILEABORT (.X, .OPENERRTEXT);
end open$input;

open$output: proc(ptr);
  dcl ptr addr,
      x based ptr file$o$structure;

  if devicetype(x.disk)=disktype then$do
    x.bufptr=0;
    call disk$select(x.disk);
    CALL delete$file(.x.fcbblock);
    if create$file(.x.fcbblock) = 0ffh then
      CALL FILEABORT (.X, .MAKEERRTEXT);
  end$if;
end open$output;

outputclose: proc(ptr);
  dcl ptr addr,
      x based ptr file$o$structure;

  if devicetype(x.disk)=disktype then$do
    call outbyte(end$of$file,.x);
    CALL FLUSHBUFFER (PTR);
    IF CLOSE$FILE (.X.FCBBLOCK) = 0FFH THEN
      CALL FILEABORT (.X, .CLOSEERRTEXT);
  end$if;
end outputclose;

INPUT$CLOSE: PROCEDURE (PTR);
  DECLARE PTR ADDRESS, X BASED PTR FILE$I$STRUCTURE;
  CALL DISK$SELECT (X.DISK);
  CALL SET$DMA$ADDRESS (.X.BUFFER);
  IF CLOSE$FILE (.X.FCBBLOCK) THEN;
END INPUT$CLOSE;

outhexbyte: proc(ch) public;
  dcl ch byte;
  call outbyte(ch,.hex$file);
end outhexbyte;

outprintbyte: proc(ch) public;
  dcl ch byte;
  if printfile.disk=console then$do
    call write$console(ch);
  else$do
    if error$printed then call write$console(ch);
    call outbyte(ch,.printfile);
  end$if;
end outprintbyte;

outsymbolbyte: proc(ch) public;
  dcl ch byte;
  call outbyte(ch,.symbolfile);
end outsymbolbyte;

insourcebyte: proc byte public;
  return inbyte(.sourcefile);
end insourcebyte;

inincludebyte: proc byte public;
  return inbyte(.includefile);
end inincludebyte;

opensource: proc public;
  CALL open$input(.sourcefile);
end opensource;

openinclude: proc public;
  CALL open$input(.includefile);
end openinclude;

openhex: proc public;
  CALL open$output(.hexfile);
end openhex;

openprint: proc public;
  CALL open$output(.printfile);
end openprint;

opensymbol: proc public;
  CALL open$output(.symbolfile);
end opensymbol;

close$source: proc public;
  call input$close (.source$file);
end close$source;

rewindsource: proc public;
  sourcefile.fcbblock(nr)=0;
  sourcefile.bufptr=length(sourcefile.buffer);
  if sourcefile.fcbblock(ex) <> 0 then$do
    sourcefile.fcbblock(ex)=0;
    sourcefile.fcbblock(s2)=0;
    CALL opensource;
  end$if;
end rewindsource;

close$include: proc public;
  call input$close (.include$file);
end close$include;

closehex: proc public;
  call outputclose(.hexfile);
end closehex;

closeprint: proc public;
  call outputclose(.printfile);
end closeprint;

closesymbol: proc public;
  call outputclose(.symbolfile);
end closesymbol;

i$file$setup: proc(dev,filnam,filtyp) public;
  dcl dev byte,(filnam,filtyp) addr;
  call clearcontrol(.includefile,filtyp);
  includefile.disk=dev;
  call copy(8,filnam,.includefile.fcbblock(fn));
end i$file$setup;

filesetup:      proc    byte public;
  dcl

  ch            byte,           /* pick up character */
  i             byte,           /* counter */
  noleft        byte,           /* no of characters left in tbuff */
  bpt           byte,           /* index of tbuff */
  exitvalue     byte,           /* exitvalue of subroutine */
  flag          byte;           /* program logic flag */

  nextch: proc byte;
    if noleft > 0 then$do
      ch=tbuff(bpt);
      noleft=noleft-1;
      bpt=bpt+1;
    else$do
      ch=cr;
    end$if;
    return ch;
  end nextch;

  getdsk: procedure (p);
    declare p address, dsk based p byte;
      ch=upper(nextch);  /* test selected disk drive */
      if letter(ch) then$do
        dsk=ch-'A';
        if dsk > validdisk then
            if dsk < console then
                exitvalue = false;	/* invalid drive */
      else$do
         exitvalue=false;
         noleft=0;
      end$if;
  end getdsk;

  exitvalue=true;

                                /* save current disk */
  default$drive,diskunit=interrogate$disk;
                                     /* enter user selected disk */
  if fcb(dr) <> 0 then$do
    call selectdisk(diskunit:=fcb(dr)-1);
  end$if;

                               /* clear control blocks */
  call clearcontrol(.sourcefile,.asmdefault);
  call clearcontrol(.hexfile,.hexdefault);
  call clearcontrol(.printfile,.lstdefault);
  call clearcontrol(.symbolfile,.symdefault);
  call copy(8,.fcb(fn),.sourcefile.fcbblock(fn));
  call copy(8,.fcb(fn),.hexfile.fcbblock(fn));
  call copy(8,.fcb(fn),.printfile.fcbblock(fn));
  call copy(8,.fcb(fn),.symbolfile.fcbblock(fn));

  if FCB (FT) <> SPACE then$do       /* pick up specified source file type */
    call copy(3,.fcb(ft),.sourcefile.fcbblock(ft));
  end$if;

/* Move source file name to SOURCENAME */

  CALL FILL (SPACE, LENGTH (SOURCENAME), .SOURCENAME);
  i=0;
  do while i<8 and (sourcename(i):=sourcefile.fcbblock(fn+i)) <> space;
    i=i+1;
  end$while;
  sourcename(i)='.';
  i=i+1;
  call copy(3,.sourcefile.fcbblock(ft),.sourcename(i));

  /* Test if file parameters */

  noleft=tbuff(0);
  bpt=1;
  FLAG = FALSE;
  IF FCB16 (1) <> SPACE THEN$DO
    IF FCB16 (1) <> DOLLAR THEN$DO
      EXITVALUE = FALSE;
    ELSE$DO
      DO WHILE (NOLEFT > 0) AND (NEXTCH <> DOLLAR);
      END$WHILE;
      FLAG = TRUE;
    END$IF;
  END$IF;

  if flag then$do

    /* file parameters present - pick them up */

    do while noleft > 0;
      if (ch:=upper(nextch)) <> space then$do

          /* A-parameter */
          IF CH = 'A' THEN call getdsk(.sourcefile.disk);

          /* H-parameter */
          ELSE IF CH = 'H' THEN call getdsk(.hexfile.disk);

          /* P-parameter */
          ELSE IF CH = 'P' THEN call getdsk(.printfile.disk);

          /* S-parameter */
          ELSE IF CH = 'S' THEN call getdsk(.symbolfile.disk);

          /* F-parameter */
          ELSE IF CH = 'F' THEN$DO
            if (ch:=upper(nextch)) = 'I' then$do
              intel$hex$on=true;
            else$do
              if ch= 'D' then$do
                intel$hex$on=false;
              else$do
                exitvalue=false;
                noleft=0;
              endif;
            endif;
          END$IF;

          /* error,no legal parameter */
          ELSE
            DO;
              exitvalue=false;
              noleft=0;
            END$DO;

      end$if;
    end$while;
  end$if;

  printdevice=printfile.disk;  /* set global printdevice flag */
  SYMBOLDEVICE = SYMBOLFILE.DISK;
  INCLUDE$DEFAULT = SOURCEFILE.DISK;

     /* input must be from a disk file */

  if devicetype(sourcefile.disk) <> disktype then$do
    exitvalue=false;
  end$if;

  return exitvalue;

end filesetup;

end file;
