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

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

#PROGRAM

#              read a line from the file.

#              ERR = READLN(FD)

#              CALL  1  READLN
#              LDN   3  FD 

#              return in X6 is +ve, or
#                   0 for EOF
#                   -ve for error

#              When reading from *FR we read block at a time

#SET           ARGS=0

#DEFINE        ARGFD=ARGS
#SET           ARGS=ARGS+1

#SET           STFRAME=SXFRAME

#DEFINE        STFD=SXPAR1
#SET           STFRAME=STFRAME+1


      STACK 2
      OBEY     ARGFD(1)
      LDX   0  0(3)                  [ get FD
      STO   0  STFD(2)

      ADN   1  ARGS

#              Pascal callable entry point

#CUE           GPREADLN

      BEGIN 2  3,1,STFRAME

#              Check if FD is open

      LDX   0  STFD(2)
      STO   0  SXPAR1(3)
      STOZ     SXPAR2(3)            [ read mode
      CALL  1  GPIOCHECK
 
      BNG   6  OUT                  [ fd is not open

      STO   6  3                    [ get fdesc to X3

      LDN   4  #7777-FLAGPART
      ANDS  4  FDFLAGS(3)            [ unset partial record flag

      LDX   7  FDTYPE(3)            [ get device type
      BZE   7  READ                 [ *TR, just do read

      LDX   4  FDPERI(3)
      ANDN  4  #77                  [ get I/O mode
      SBN   4  #22                  [ mode #22 = block read
      
      BNZ   4  READ                 [ jump if not block reads

      LDX   1  FDRECORD(3)          [ get next rec

      BRN      NXREC

READ  LDX   6  FDBUFLEN(3)
      BZE   7  *+2
      SRL   6  2                    [ FH read len is in words
      STO   6  FDCOUNT(3)           [ set read count
      LDX   5  FDUNIT(3)

      PERI  5  FDPERI(3)            [ read a new block/rec

      LDXC  6  FDREPLY(3)
      BCC      *+4
      LDX   1  7                    [ get type to index reg
      SUSBY 5  256(1)
      LDX   6  FDREPLY(3)

      LDX   5  6                    [ get reply
      SLA   5  3                    [ get B3 to overflow

      BVCR     OK                   [ jump if no error

      SLA   5  2                    [ get B5 to overflow
      BVCR     *+3                  [ jump if not eof
      STOZ     6                    [ it's EOF
      BRN      OUT                  [ and go

      NGN   6  EIO                  [ set error
      BRN      OUT                  [ byee

OK    LDX   1  FDADDR(3)            [ get buffer address

      BNZ   7  FH                   [ jif read from *FR/FH

#              From *TR reply is unexpired character count

      ANDN  6  #177                 [ ignore high bits
      LDX   7  FDCOUNT(3)           [ get count
      SBX   7  6                    [ subtract left
      STO   7  6                    [ which we want in X6

      LDX   7  FDPERI(3)            [ what mode PERI did we do?
      STO   7  0
      ANDN  7  #4                   [ read in prev shift
      BZE   7  ALFA                 [ jump if was alfa shift

      ERN   0  #4                   [ turn off "prev shift"
      STO   0  FDPERI(3)
      BRN      DONE                 [ and don't change initial

ALFA  LDN   0  #74                  [ get initial shift
      STO   0  FDSHIFT(3)

      LDN   0  SMODALPHA
      STO   0  FDSHIFTMOD(3)        [ set input shift

      BRN      DONE                 [ all done

#              After read from FR,FH bits 6..23 contain address
#              of word  after last word read

FH    SBX   6  1                    [ subtract buffer address
      ANDN  6  #7777                [ ignore high bits

      BZE   6  OUT                  [ Jump if EOF

      BNZ   4  INREC                [ jump if not block mode

#              Extract info from *FR, *FH buffer

NXREC LDX   6  0(1)                 [ get length
      BZE   6  READ                 [ jump if block finished

      LDX   7  6                    [ get rec len
      ADX   7  1                    [ work out start of next rec
      STO   7  FDRECORD(3)
      SBN   6  1                    [ hide length field
      ADN   1  1

INREC SLL   6  2                    [ Calculate #chars
      LDXC  5  FDSHIFT(3)           [ shift, graphic, amorph?

      BCS      DONE                 [ jump if amorphous

      LDX   0  0(1)                 [ get red tape word

      ADN   1  1                    [ don't count red tape in len
      SBN   6  4

#              If record is exactly 2000 chars long then we need to
#              set partial record flag.

      LDX   4  2000
      BXU   4  6,*+3
      LDN   4  FLAGPART
      ORS   4  FDFLAGS(3)           [ this is partial record

#              Work out initial shift

      BZE   5  GRAP                 [ don't change shift if graphic
      
      LDX   4  0                    [ get red tape to X0
      SRL   4  6                    [ get initial shift
      ANDN  4  1
      ADN   4  #74                  [ deal with broken files
      STO   4  FDSHIFT(3)           [ and save it
      LDN   7  SMODALPHA            [ assume alpha
      SBNC  4  #75
      BCS      *+2                  [ it was
      LDN   7  SMODBETA             [ or not
      STO   7  FDSHIFTMOD(3)

GRAP  SLC   0  2                    [ get chars used in last word
      ANDN  0  3                    [ mask rubbish
      BZE   0  DONE                 [ jif whole word used
      LDN   4  4
      SBX   4  0                    [ chars unused in last word
      SBX   6  4                    [ chars in rec

DONE  STO   1  FDNEXT(3)            [ save pointer to next char
      STO   6  FDCHARS(3)           [ and rec length

      ADN   6  1                    [ pretend 0 len rec = 1 char

OUT   END   2  1,0

#END
#FINISH