This is a cross-referenced version of fdalloc.plan, to download the unmodified source try fdalloc.plan.
#PROGRAM       /GPFDALLOC(15AM,22AM,DBM,EBM)
#PAGE

#INCLUDE       IOHEAD(/DEFS)
#INCLUDE       STACK(/DEFS)

#PERMANENT     GFMALLOC    [ #XPCK to stupid to include by entrypoint

#PROGRAM

#              Allocate file table entry

#              unit = fdalloc (fd, shift, type, unit, read, write, len)

#              fd:    fd to allocate, or -1
#              shift: zero if GRAP, -ve AMOR
#              type:  Device type, *TR, *TP, *FR, *FW, *FH, *CI
#              unit:  EXEC unit number
#              read:  read PERI mode
#              write: read PERI mode
#              len:    buffer len in chars

#              Return value in X6
#              FDESC returned in X3 if X6 +ve

#              Stack frame

#SET           STFRAME=SXFRAME

#              First the args

#DEFINE        STFD=SXPAR1           [ preferred FD, or -1
#SET           STFRAME=STFRAME+1

#DEFINE        STSHIFT=SXPAR2        [ Current shift
#SET           STFRAME=STFRAME+1

#DEFINE        STTYPE=SXPAR3         [ Device type, eg *TP = 1
#SET           STFRAME=STFRAME+1

#DEFINE        STUNIT=SXPAR4         [ Unit number, eg 2 for *TP2
#SET           STFRAME=STFRAME+1

#DEFINE        STREAD=SXPAR5         [ read Peri mode
#SET           STFRAME=STFRAME+1

#DEFINE        STWRITE=SXPAR6        [ write Peri mode
#SET           STFRAME=STFRAME+1

#DEFINE        STCHARS=SXPAR7        [ buffer length wanted
#SET           STFRAME=STFRAME+1

#              Now the local variables:

#DEFINE        STDESC=STFRAME        [ saved file descriptor pointer
#SET           STFRAME=STFRAME+1

      BEGIN 2  3,1,STFRAME

#              Work out if we  have enough space in the FTABLE.

      LDX   1  PFTABLE
      BNZ   1  PFOK

#              Drat, the table hasn't even been allocated yet.

      LDN   3  SZFTABLE+1            [ get initial size of table
      CALL  1  GXZALLOC              [ zeroing allocator

      BZE   6  NOMEM

      STO   6  PFTABLE
      STO   6  1

      LDN   0  SZFTABLE
      STO   0  0(1)                  [ Save allocated size of table

PFOK  LDX   0  0(1)                  [ Get size of table

      LDXC  3  STFD(2)               [ do we have a preferred FD?
      BCS      FIND                  [ jump if not

      BXGE  3  0,BADF                [ jif outside table

      ADX   1  3
      LDX   3  1(1)                  [ get FD'th entry
      BZE   3  FOUND                 [ jif avail

      BRN      BADF                  [ sorry, in use

FIND  ADN   1  4                     [ skip 1st 4 entries
      SBNC  0  4
      BCS      BADF                  [ shouldn't happen
      
NXT   LDX   3  1(1)                  [ get next table entry
      BZE   3  FOUND                 [ jump if free
      ADN   1  1                     [ point at next table entry
      BCT   0  NXT

#              Can't find a table entry.  Could increase table size
#              or just give up

BADF  NGN   6  EBADF
      BRN      BYE

NOMEM NGN   6  ENOMEM
      BRN      BYE

FOUND STO   1  STDESC(2)             [ save FD pointer

      LDN   3  SZFDESC               [ size of file descriptor

      LDX   4  STCHARS(2)            [ get wanted buffer length
      ADN   4  3
      SRL   4  2                     [ calculate length in words
      ADX   3  4                     [ work out size of descriptor

      CALL  1  GXMALLOC              [ Allocate descriptor
      BZE   6  NOMEM                 [ should be BNG one day

      LDX   1  STDESC(2)
      STO   6  1(1)                  [ save descriptor

      STO   6  3                     [ move descriptor to index reg

      SBX   1  PFTABLE               [ convert table pointer to unit#
      STO   1  6                     [ and move to return

#              Initialise descriptor

      STOZ     FDFLAGS(3)            [ no flags set

#              Calculate PERI commands

      LDX   1  STTYPE(2)
      STO   1  FDTYPE(3)
      LDCT  0  256(1)                [ move type+256 to top 9 bits
      LDN   4  DEVCI                 [ is it a *CI?
      BXE   4  1,*+2                 [ if not we ...
      ADX   0  '#30000'              [   turn on EOF detection

      LDXC  4  STWRITE(2)            [ can we write this FD?
      BCS      RO                    [ jump if read only
      ADX   4  0                     [ compose write PERI
      STO   4  FDWRITE(3)            [ and save
      STO   4  FDPERI(3)             [ save as initial PERI
      LDN   4  FLAGWRITE             [ set write flag
      ORS   4  FDFLAGS(3)
      BRN      *+2 

RO    STOZ     FDWRITE(3)            [ No write access

READ  LDXC  4  STREAD(2)             [ can we read this FD?
      BCS      WO                    [ jump if write only
      ADX   4  0                     [ compose read peri
      STO   4  FDREAD(3)             [ and save
      STO   4  FDPERI(3)             [ save as initial peri
      LDN   4  #7777-FLAGWRITE       [ clear write flag
      ANDS  4  FDFLAGS(3)
      BRN      *+2                   [ and contiue 

WO    STOZ     FDREAD(3)             [ no read access

INIT  LDX   0  STUNIT(2) 
      STO   0  FDUNIT(3)
      LDX   0  STCHARS(2)
      STO   0  FDBUFLEN(3)
      LDX   0  STSHIFT(2)
      STO   0  FDSHIFT(3)
      LDN   7  SMODALPHA             [ shift mod
      SBN   0  #74                   [ start ALPHA?
      BZE   0  SM
      LDN   7  SMODBETA         
      SBN   0  #75-#74               [ or BETA?
      BZE   0  SM
      LDN   7  SMODNONE
SM    STO   7  FDSHIFTMOD(3)`
      STOZ     FDREDTAPE(3)          [ red tape only for *FW
      STOZ     FDCHARS(3)            [ buffer initialy empty
      LDN   1  FDBUF(3)
      STO   1  FDNEXT(3)             [ next char start of buf
      STO   1  FDADDR(3)             [ I/O to buffer
      NGN   1  1                     [ set block mode pointer
      STO   1  FDRECORD(3)           [ to illegal value

BYE   END   2  1,0         

#END
#FINISH