.........................................................................
.;             >>>>> Please put the title here <<<<<
.laser
.topmargin 1"
.margin 1"
.bottommargin 1"
.hlt bold
.; pick one of the fonts, and comment out or erase the one you don't want
.;font helvetica
.font times
.point 9.4285
.leading 1
.symbol on
.bl |
.; The following rulers work for Times-Roman and Helvetica
.; Three columns per page (2 1/16")
..................................<
AAA
by SDH

_Simple File I/O on a Random File_

  Hello assembler junkies!  This is
the second session of the AAA  that
deals with file I/O. This month  we
will  discuss a simple program that
reads in  a  random  file  that was
just  made via the _.CREATE_  command
and clears  each block of the file.
This program  is quite handy if you
want  to make sure  each  block  of
your (new)  random  file  does  not
contain any extraineous (sp?) data.
  Before we look at the program for
this  month,  let's  take  a closer
look at the DDB and discover a  new
feature  of  the  DDB that has  not
been covered. This feature involves
the  D.WRK area of  the  DDB.  This
area  is  where  AMOS  loads in the
following upon a LOOKUP: the _number
of blocks_ of the file (the  word at
D.WRK+2),  the _active bytes of  the
last block_  (the  word at D.WRK+6),
and the _first block  number_  of the
file  (the  word at D.WRK+12). Time
for a closer look.
  The   first   word   at   D.WRK+2
contains  the  number of blocks  in
the file. We will  use  this number
as  our counter when we clear  each
block   of  our  random  file.  The
second piece  of  data,  the _active
bytes_,  has  two different  formats
depending  on  if   the   file   is 
sequential  or  random.  If it is a
sequential  file, then this   value
contains the  "pointer" to the last
used byte in the  last block of the
file, also known as the end-of-file
(eof). If it is a random file, then
this  value  will  contain   a  -1,
represented  as 177777 octal,  FFFF
hex.  Finally,  the  last  word  at
D.WRK+12  (octal)  always  contains
the first block of the file whether
it is random or sequential in type.
  Notice that if you want to decide
whether or  not a file is random or
not, all you  need to do is examine
the word at D.WRK+6.  If  it is the
-1,  then  by  golly,  the file  is
random. If it is not, then  it must
be  sequential. Notice that if  the
file  type  is  random, then we may
easily find out how many blocks the
file  occupies by  reading  in  the
word at  D.WRK+2.  Finally, to gain
access to the first  block  of  any
file  type,  we  simply read in the
word  at  D.WRK+12  (you  may  also
access  the block number at D.REC+2
if you so desire).
  One more  note  before we look at
the   program.  When  reading   and
writing   to    random  files,  the
procedure is as  follows: read in a
block into memory,  perform work on
the  block,  and  then  write  this
block back out to disk in  the same
location when the block was read.
 _CLRAND Byte-by-Byte_
  Let's  examine  a  program called
CLRAND that will clear  each  block
of  a  random  file.  Many  of  the
instructions contained in this file
have   been   covered   in  earlier
sessions,  so if you are  a  little
lost, please  refer to the previous
AAA submissions for details. 
 _PHDR-1,0,PH$REE!PH$REU!PH$OPR_
  Here  is  the  same  old  program
header  but with a new added twist.
Notice that  there  is  a  new flag
contained   in  the  header  -  the
_PH$OPR_ flag.  This will indicate to
AMOS that the user  of this program
_must_  be  logged  into   the   OPR:
account  before  the  program  will
run, similar to the DSKANA, DSKDDT,
and other OPR: AMOS programs.
 _.OFINI
 .OFDEF  IDDB,D.DDB
 .OFSIZ  IMPSIZ_
  This  is  where  we reserve space
for our Dataset Driver  Block (DDB)
by defining a variable called  IDDB
and giving this variable a size  of
D.DDB. D.DDB is  equal to 150 octal
bytes. It is these bytes that allow
space   for  all  the   information
necessary  to perform file I/O. The
variable IDDB  will  exist  in  the
user  memory  partition of the user
executing CLRAND.
 _BYP_
  This monitor call will bypass all
"whitespace"  on  the  input  line.
Whitespace consists  of  all spaces
following the CLRAND command  up to
the first non-blank character (a CR
or  a  LF is a non-blank character,
by the way). This has the effect of
incrementing the input line pointer
address  register  A2  to the first
non-blank  character following  the
program name.
 _LIN_
 _BNE  INOK_
  After passing  by the whitespace,
we now check and see if we are at a
line termination  character  like a
CR  or  a  LF. The LIN monitor call
will cause the  zero  flag  of  the
status  register  to  be set if the
character  pointed to by  A2  is  a
line termination character. The BNE
to the label  INOK will happen only
if  A2 does not  point  to  a  line
termination character.
 _LEA  A1,IDDB(A3)
 FSPEC @A1
 INIT @A1
 LOOKUP @A1
 BNE  NOFILE_
  LEA  A1,IDDB(A3)  will  Load  the
Effective  Address into the address
register  A1  the  memory  location
pointed  to  by  IDDB(A3).  A1  now
points to the DDB for the file.
  FSPEC @A1,DAT will take the ascii
data  pointed  to by A2 (our  input
pointer) and place  the  "filespec"
entered in by the user into the DDB
pointed  to  by  A1  at  the proper
offsets (D.FIL, D.EXT, etc.  -  see
last  months  submission).  If  the
user  did not provide an extension,
the extension  default  is .DAT. If
the   user   enters   in  a  faulty
filespec on the input  line,  FSPEC
will  "catch" the error, report  it
to your  screen,  and return you to
the dot.
  INIT  @A1  will  cause  AMOS   to
locate   a  buffer  space  in  user
memory (512  bytes)  for block I/O.
The  pointer  to this block  memory
buffer will be placed in the DDB at
the offset D.BUF.  The  actual size
(512   bytes   in  this  case)   is
calculated  by AMOS  upon  an  INIT
call by consultation  of the device
driver.
  After  the  INIT call, the LOOKUP
@A1 commands AMOS  to  see  if  the
file  located in the DDB pointed to
by A1 exists.  If  it  does exists,
then  the  zero flag of the  status
register will  be set, and the file
information at D.WRK  will be moved
into  the  DDB  pointed to  by  A1.
BNE NOFILE will only be executed if
the file does not exist.
 _CMPW IDDB+D.WRK+6(A3), #-1
 BEQ AOK_
  If the file exists  and there was
no    file    specification   error
produced by the  FSPEC  call,   the
next   step  of  the  program  will
determine  if  the  file entered at
the command line is indeed  random.
It does this by examining  the word
value at offset D.WRK+6. If it is a
-1,  then  the file is random,  and
the program  then  branches  to the
label AOK.
 _TYPE <?>
 PFILE  @A1
 TYPECR < is not a random file.>
 EXIT_
  If the file is not a random file,
then the program continues with the
lines contained above. First, a "?"
is printed  to the screen, then the
PFILE monitor  call  is employed to
type  out  the  filespec   to   the
terminal.  The  PFILE  monitor call
expects  a  pointer  to a file  DDB
following  the  call.   A1  is  the
pointer  in  this  case.  We   then
finish the message to the user with
the  TYPECR  <.  .  .  >,  and then
finally EXIT back to the dot.
 _CRLF

 JNE END_
  This  small  portion  of  code is
self explainatory. These lines just
make  sure that the user knows what
they are  about  to  do.  They must
confirm execution of the program by
entering    in    a    "Y"   before
continuing. Since this program will
wipe out any data contained  in the
blocks  on  the file, CLRAND double
checks the user's intensions.
 _MOVW  IDDB+D.WRK+2(A3),D2_
  Here is where  we  get the number
of blocks of the random file into a
counter register using  D2  as  our
counter.  We  will  consult  D2 and
clear  each block until D2 is equal
to zero.
 _OPENR @A1
 READ @A1
 MOV #128,D3_
  Next,  CLRAND  will open the file
for  random input/output  with  the
OPENR  monitor  call.  The  address
following  the OPENR command should
be a pointer to a random file DDB.
  Once the file  has  been  opened,
the  READ  @A1 will read in a block
from  the file.  The  block  number
actually  read  is contained in the
DDB  at  an  offset of D.REC+2. The
data contained on the disk block is
placed into your user memory at the
address contained in D.BUF.
  After the block has been read in,
we place  another  counter into the
data register D3. This  counter  is
#128. Since CLRAND will be clearing
the  block, and each block contains
128  longwords,   D3   acts   as  a
longword counter.
  _MOV IDDB+D.BUF(A3),A4_
  This instruction  will  move  the
block  pointer  that  the INIT call
created  into the address  register
A4. A4 now points to the first byte
of the block  just read in from the
READ call.
 _CLR (A4)+
 DEC D3
 BNE 10$_
  This is where  the  actual  block
clearing  occurs. For each longword
(totaling 128),  the CLR (A4)+ will
not only clear the longword pointed
to  by A4, but the  "+"  after  the
instruction  will cause A4 to point
to  the  next longword  in  memory.
After 128 passes of this procedure,
D3 will be  zero,  and  the program
falls    through    to   the   next
set instruction below.
 _WRITE @A1
 DECW D2
 BEQ END_
  After the block has  been cleared
in memory, CLRAND then writes  this
block back out to the disk with the
WRITE monitor call. Notice that  A1
is again employed as our pointer to
the   DDB   of   the  file  we  are
manipulating. The block modified in
memory  is written back out to  the
disk in the  exact  location before
the modification.
  DEC  D2  will  cause   our  block
counter  data  register to  be  one
less  than  before,   and   if   D2
contains   a   zero,   the  program
branches to the label END.
 _INCW IDDB+D.REC+2(A3)
 BR READIT_
  If the data register  D2  is  not
zero,   this  means  that  all  the
blocks have  not  been cleared. The
program  must  then  increment  the
block number by one by incrementing
the  word  value (the actual  block
number)  at D.REC+2.  Since  random
files   occupy    contiguous   disk
blocks,  this  has  the  effect  of
pointing to the  next  block of the
random  file.  Once  this has  been
done, the program branches  back to
the   READIT  label,  which  causes
CLRAND to read in the next block of
the file  and proceed to clear this
block.
 _EXIT
 END_
  Once   all   blocks   have   been
cleared,  we  then EXIT back to the
dot.  Upon exit,  notice  that  the
file  is automatically closed.  END
marks the  end  of  the code to the
assembler program.
_A Wrap_
  I  know   this   is   a   lot  of
instructions  and  theory piled  on
you  all  at  once.  We   will   be
continuing our discussion of simple
file   I/O   -   both   random  and
sequential - in the months to come.
Try this program out (it is located
on  the Network in [100,51]).   See
if  you   can  follow  the  theory.
Remember,    however,   that   this
program will  clear  out  a  random
file. 
  Don't  practice  this  program on
any  file  you  need! If you  like,
create a new random  file  with the
_.CREATE_  command.  For example,  to
create a 2-block random file called
TEST.DAT,  the  format  is  _.CREATE_
_TEST.DAT,2_.  _.DUMP_ the  file  after
you have created  it and notice the
data contained in the  file.  There
is a good possibility that there is
some  garbage. Now _.CLRAND TEST.DAT_
from  the  OPR:  account  and  then
_.DUMP_  the  file once again. Notice
that all the blocks of the file now
contain zeros.  Just  what  "Doctor
Dave"   ordered!   Have   fun,   be
careful,  and  I'll  see  you  next
month!