PROC MIKESFILEMANAGER (MFM) IS (
        LITERAL             OBJECT    := "",
        LITERAL             TARGET    := "",
        LITERAL             STARTFROM := "",
        LITERAL             STOPAFTER := "",
        LITERAL             FILEMASK  := "",
        LITERAL             SIZE      := "",
        LITERAL             AGE       := "",
        LITERAL             ACTION    := "SCEF(%S.%F)",
        LITERAL             MARK_FILE := "",
        LITERAL             AUTO_PAGE := "Y",
        RESPONSE (RESPONSE) RESP      := RESULT)
 
BEGIN
 
   STOPT(NAM = NOLCS)
 
   STRING PHASE,
          ONAME,
          PAGE_ACTION,
          FILE_ACTION,
          DO_ACTION,
          IN_BUFF,
          W_BUFF,
          REPLY,
          EXTRA_REPLY,
          MSG_TEXT,
          SFILE,
          MFILE,
          MASK,
          MASK_PART,
          MNAME,
          DETAILS,
          RES_CODE,
          PAGE_HELP,
          FILE_HELP,
          ACTION_HELP,
          FILEMASK_HELP,
          MARK_HELP
 
   STRING STPR   := HEX(11),     @ STart PRotected        @
          STUN   := HEX(3C),     @ Unprotected & Steady   @
          CLS    := HEX(0C),     @ Clear Screen           @
          NL     := HEX(15),     @ New Line               @
          SOM    := HEX(2706),   @ Set SOM to Cursor      @
          VP     := HEX(22),     @ Vertical Position      @
          HP     := HEX(23)      @ Horizontal Position    @
 
   INT    FLAG,
          SFLAG,
          OBJ_CNT,
          OBJECT_LIST,
          WORKING_LIST,
          MARKFL,
          OBJ,
          WORK,
          MRK,
          PTR,
          LAST_OBJ,
          FILE_PTR,
          CURR_POSN,
          LINES,
          LAST_LINE,
          REPLY_LEN,
          EXTRA_REPLY_LEN,
          LAST_REPLY,
          OLDEST,
          YOUNGEST,
          SMALLEST,
          LARGEST,
          FILEAGE,
          FILESIZE
 
   BOOL   MATCH,
          DO_MATCHING,
          SHOW_DEL,
          FILE_MARKED,
          ALL_DELETED,
          AUTO_PG,
          STAY_ON_PAGE
 
   (5000) BOOL DELETED,
               MARKED
 
   SUPERSTRING (20, 45) FNAME
   SUPERSTRING (20, 18) FDETS
 
   SUPERSTRING (20, 1)  MARK
 
   (20)   INT FPTR
 
   PAGE_HELP :=
   CLS + VP + BIN(2) + HP + BIN(4)                 +
   "N - Next page of files"                        + NL + HP + BIN(4) +
   "P - Previous page of files"                    + NL + HP + BIN(4) +
   "F - First page of files"                       + NL + HP + BIN(4) +
   "L - Last page of files"                        + NL + HP + BIN(4) +
   " "                                             + NL + HP + BIN(4) +
   "D - Display files marked for deletion"         + NL + HP + BIN(4) +
   "    These files can then be deselected if"     + NL + HP + BIN(4) +
   "    required (see 'U')"                        + NL + HP + BIN(4) +
   " "                                             + NL + HP + BIN(4) +
   "U - Display files not marked for deletion"     + NL + HP + BIN(4) +
   "    This is used for switching back after"     + NL + HP + BIN(4) +
   "    using 'D' to select deleted files"         + NL + HP + BIN(4) +
   "    Will automatically switch back if all"     + NL + HP + BIN(4) +
   "    files to be deleted are deselected"        + NL + HP + BIN(4) +
   " "                                             + NL + HP + BIN(4) +
   "H - Show this screen"                          + NL + HP + BIN(4) +
   SOM + " "
 
   FILE_HELP :=
   CLS + VP + BIN(2) + HP + BIN(4)                 +
   "Undeleted mode:"                               + NL + HP + BIN(4) +
   " "                                             + NL + HP + BIN(4) +
   "A - Perform action in 'ACTION' parameter"      + NL + HP + BIN(4) +
   "    '?' in ACTION parameter gives details"     + NL + HP + BIN(4) +
   "    Default action is SCEF"                    + NL + HP + BIN(4) +
   "B - Browse file"                               + NL + HP + BIN(4) +
   "C - Copy file (uses COPY_RECORDS)"             + NL + HP + BIN(4) +
   "D - Display file details"                      + NL + HP + BIN(4) +
   "M - Mark file to be put into list of files"    + NL + HP + BIN(4) +
   "Q - Browse file and ask if it is to be deleted"+ NL + HP + BIN(4) +
   "U - Unmark file"                               + NL + HP + BIN(4) +
   "X - Delete file (marks for later deletion)"    + NL + HP + BIN(4) +
   "H - Show this screen"                          + NL + HP + BIN(4) +
   " "                                             + NL + HP + BIN(4) +
   "Deleted mode:"                                 + NL + HP + BIN(4) +
   " "                                             + NL + HP + BIN(4) +
   "B - Browse file"                               + NL + HP + BIN(4) +
   "D - Display file details"                      + NL + HP + BIN(4) +
   "U - Unmark file for deletion"                  + NL + HP + BIN(4) +
   SOM + " "
 
   ACTION_HELP :=
   "Action parameter - allows user specified actions to be" + NL +
   "executed. Parameter substitution will be performed on"  + NL +
   "the line, the following rules being obeyed:"            + NL +
   " "                                                      + NL +
   "%F = filename with FGN"                                 + NL +
   "%G = filename without FGN [1]"                          + NL +
   "%S = object of MFT (source)"                            + NL +
   "%T = target specified to MFT (default = user)"          + NL +
   " "                                                      + NL +
   "[1] Alternative suggestions welcome"                    + NL +
   " "
 
   FILEMASK_HELP :=
   "Filemask parameter - allows a selected subset of files" + NL +
   "to be selected, using wild carding. Not, sadly, as"     + NL +
   "sophisticated as on Unix, but there we go. The"         + NL +
   "character '*' substitutes for any number of characters,"+ NL +
   "so the mask 'ESCAN*B*LL' would match with ESCANDCBILL," + NL +
   "ESCANCSBILLING and ESCANBILL. A trailing '*' is always" + NL +
   "assumed, but a leading one is only assumed when there"  + NL +
   "is no '*' in the string. Hence '*BILL' and 'BILL'"      + NL +
   "would both match 'SCANBILL' and 'BILLCOUNT', but"       + NL +
   "'BILL*' would only match 'BILLCOUNT' of those."         + NL +
   "If the first character is '!' then only those files"    + NL +
   "which do not match the mask will be selected."          + NL +
   " "
 
   MARK_HELP :=
   "MARK_FILE parameter - specifies a file in which a list" + NL +
   "of files marked with the 'M' action will be placed."    + NL +
   " "
 
 
   WHENEVER FLAG NE 0 THEN
      IF FLAG > 0 THEN
         SMSG("ERROR WHEN " + PHASE)
         RESP := FLAG
         RETURN
      ELSE
         SMSG("WARNINGS WHEN " + PHASE)
         SRSMSG(FLAG)
         FLAG := 0
      FI
   FI
 
   IF (((ACTION = "?")
   OR   (FILEMASK = "?"))
   OR   (MARK_FILE = "?")) THEN
      SMSG(CLS + HP + BIN(4))
      IF ACTION = "?" THEN
         SMSG(ACTION_HELP)
      FI
      IF FILEMASK = "?" THEN
         SMSG(FILEMASK_HELP)
      FI
      IF MARK_FILE = "?" THEN
         SMSG(MARK_HELP)
      FI
      RETURN
   FI


   IF SIZE NE "" THEN
      IF DIGITS(SIZE) THEN
         SMALLEST := CHARTOINT(SIZE)
         LARGEST  := CHARTOINT(SIZE)
      ELSF SIZE STARTSWITH "+" THEN
         SMALLEST := CHARTOINT(SIZE AFTER "+")
         LARGEST  := -1
      ELSF SIZE ENDSWITH "+" THEN
         SMALLEST := CHARTOINT(SIZE BEFORE "+")
         LARGEST  := -1
      ELSF SIZE STARTSWITH "-" THEN
         SMALLEST := 0
         LARGEST  := CHARTOINT(SIZE AFTER "-")
      ELSF SIZE ENDSWITH "-" THEN
         SMALLEST := 0
         LARGEST  := CHARTOINT(SIZE BEFORE "-")
      ELSF SIZE INCLUDES "-" THEN
         SMALLEST := CHARTOINT(SIZE BEFORE "-")
         LARGEST  := CHARTOINT(SIZE AFTER "-")
      FI
   ELSE
      SMALLEST := 0
      LARGEST  := -1
   FI
      

   IF AGE NE "" THEN
      IF DIGITS(AGE) THEN
         YOUNGEST := CHARTOINT(AGE)
         OLDEST   := CHARTOINT(AGE)
      ELSF AGE STARTSWITH "+" THEN
         YOUNGEST := CHARTOINT(AGE AFTER "+")
         OLDEST   := -1
      ELSF AGE ENDSWITH "+" THEN
         YOUNGEST := CHARTOINT(AGE BEFORE "+")
         OLDEST   := -1
      ELSF AGE STARTSWITH "-" THEN
         YOUNGEST := 0
         OLDEST   := CHARTOINT(AGE AFTER "-")
      ELSF AGE ENDSWITH "-" THEN
         YOUNGEST := 0
         OLDEST   := CHARTOINT(AGE BEFORE "-")
      ELSF AGE INCLUDES "-" THEN
         YOUNGEST := CHARTOINT(AGE BEFORE "-")
         OLDEST   := CHARTOINT(AGE AFTER "-")
      FI
   ELSE
      YOUNGEST := 0
      OLDEST   := -1
   FI
 
 
   ONAME := OBJECT
 
   PHASE := "CREATING OBJECT_LIST WORKFILE"
 
   CRF(LNA = OBJECT_LIST,
       RES = FLAG)
 
   PHASE := "CREATING WORKING_LIST WORKFILE"
 
   CRF(LNA = WORKING_LIST,
       RES = FLAG)
 
 
   ONAME := OBJECT
 
   PHASE := "CREATING OBJECT_LIST WORKFILE"
 
   CRF(LNA = OBJECT_LIST,
       RES = FLAG)
 
   PHASE := "CREATING WORKING_LIST WORKFILE"
 
   CRF(LNA = WORKING_LIST,
       RES = FLAG)
 
   IF ONAME = "" THEN
      OBJECT_TYPE := "U"
      PHASE := "DISPLAYING USER DETAILS"
      DUD(COM = F,
          LEV = STD,
          STA = VAL STARTFROM,
          STO = VAL STOPAFTER,
          LIS = *OBJECT_LIST,
          RES = FLAG)
 
   ELSF ONAME = "*" THEN
 
      OBJECT_TYPE := "G"
                                                                                
      PHASE := "DISPLAYING GROUP DETAILS OF " + ONAME
 
      DGRD(NAM = *,
           COM = F,
           LEV = STD,
           STA = VAL STARTFROM,
           STO = VAL STOPAFTER,
           LIS = *OBJECT_LIST,
           RES = SFLAG)
 
      IF ((SFLAG = 31501)
      OR  (SFLAG = 39905)) THEN
 
         PHASE := "CREATING OBJECT_LIST WORKFILE"
 
         CRF(LNA = OBJECT_LIST,
             RES = FLAG)
 
         OBJECT_TYPE := "L"
 
         PHASE := "DISPLAYING LIBRARY DETAILS OF " + ONAME
 
         DLBD(NAM = *,
              COM = LBF,
              LEV = STD,
              STA = VAL STARTFROM,
              STO = VAL STOPAFTER,
              LIS = *OBJECT_LIST,
              RES = SFLAG)
 
         IF SFLAG = 31501 THEN
            SMSG(ONAME + " IS NOT A GROUP OR LIBRARY")
            RESP := 1
            RETURN
         FI
 
      FI                                                                        
 
   ELSE                                                                         
 
      OBJECT_TYPE := "L"
 
      PHASE := "DISPLAYING LIBRARY DETAILS OF " + ONAME
 
      DLBD(NAM = VAL ONAME,
           COM = LBF,
           LEV = STD,
           STA = VAL STARTFROM,
           STO = VAL STOPAFTER,
           LIS = *OBJECT_LIST,
           RES = SFLAG)
 
      IF (((SFLAG = 31501)
      OR   (SFLAG = 39905))
      OR   (SFLAG = 37022)) THEN
 
         PHASE := "CREATING OBJECT_LIST WORKFILE"
 
         CRF(LNA = OBJECT_LIST,
             RES = FLAG)
 
         OBJECT_TYPE := "G"
 
         PHASE := "DISPLAYING GROUP DETAILS OF " + ONAME
 
         DGRD(NAM = VAL ONAME,
              COM = F,
              LEV = STD,
              STA = VAL STARTFROM,
              STO = VAL STOPAFTER,
              LIS = *OBJECT_LIST,
              RES = SFLAG)
 
         IF SFLAG = 31501 THEN
            SMSG(ONAME + " IS NOT A GROUP OR LIBRARY")
            RESP := 1
            RETURN
         FI
 
      FI
 
   FI
 
   IF ((TARGET = "")
   OR  (TARGET STARTSWITH ":")) THEN
 
      TARGET_TYPE := "U"
 
   ELSE
 
      TARGET_TYPE := "L"
 
      PHASE := "DISPLAYING LIBRARY DETAILS OF " + TARGET
 
      DLBD(NAM = VAL TARGET,
           COM = BASIC,
           LIS = DUMMY_FILE,
           RES = SFLAG)
 
      IF ((SFLAG = 31501)
      OR  (SFLAG = 39905)) THEN
 
         TARGET_TYPE := "G"
 
         PHASE := "DISPLAYING GROUP DETAILS OF " + TARGET
 
         DGRD(NAM = VAL TARGET,
              COM = BASIC,
              LIS = DUMMY_FILE,
              RES = SFLAG)
 
         IF SFLAG = 31501 THEN
            SMSG(TARGET + " IS NOT A GROUP OR LIBRARY")
            RESP := 1
            RETURN
         FI
 
      FI
 
   FI
 
   PHASE := "OPENING *OBJECT LIST"
 
   OPF(NAM = *OBJECT_LIST,
       CHA = OBJ,
       RES = FLAG)
 
   PHASE := "OPENING *WORKING LIST"
 
   OPF(NAM = *WORKING_LIST,
       CHA = WORK,
       ACC = W,
       RES = FLAG)
 
@  Read until either "*** TOTAL" or "---" is at the start of buffer
@  "*** TOTAL" means an empty list
 
   SFLAG := 0
 
   IN_BUFF := FILL(256)
 
   RDR(CHA = OBJ,
       REC = IN_BUFF,
       RES = SFLAG)
 
   IF SFLAG = 0 THEN
      ONAME := ":" + ((IN_BUFF AFTER " :") BEFORE " AT")
   FI
 
   UNTIL (((SFLAG NE 0)
   OR      (IN_BUFF STARTSWITH "*** TOTAL"))
   OR      (IN_BUFF STARTSWITH "---"))
   DO
 
      IN_BUFF := FILL(256)
 
      RDR(CHA = OBJ,
          REC = IN_BUFF,
          RES = SFLAG)
 
   REPEAT
 
   IF ((SFLAG NE 0)
   OR  (IN_BUFF STARTSWITH "***")) THEN
      SMSG("EMPTY OBJECT LIST")
      RESP := 1
      RETURN
   FI
 
   IN_BUFF := FILL(256)
 
   RDR(CHA = OBJ,
       REC = IN_BUFF,
       RES = SFLAG)
 
   PTR := 1
 
@  The list of files to be displayed is now stored in the working
@  list file. Originally, an array was used, but when large numbers
@  of files were selected, heap space ran out.
 
   UNTIL IN_BUFF STARTSWITH "*** TOTAL"
   DO
 
@  Ignore lines starting in "***" (warnings) or space (SECTION lines)
@  or which are < 38 bytes or which are Aliases or Temporary files
@  or Synonyms (note: User/Group display has these in a different
@  column to Library display)
 
@  If MASK doesn't contain a "*" then put one at the front
 
@  If the filename matches, then store filename(fgn) and the file
@  details, separated by a '!' (as the filename is variable length),
@  in the list file
 
      UNLESS ((((((((IN_BUFF STARTSWITH " ")
                 OR (IN_BUFF STARTSWITH "***"))
                 OR (LENGTH IN_BUFF < 38))
                 OR ((LENGTH IN_BUFF > 43)
                      AND (SUBSTR(IN_BUFF,43) = "A")))
                 OR ((LENGTH IN_BUFF > 45)
                      AND (SUBSTR(IN_BUFF,45) = "T")))
                 OR ((LENGTH IN_BUFF > 38)
                      AND (SUBSTR(IN_BUFF,38) = "S")))
                 OR ((LENGTH IN_BUFF > 40)
                      AND (SUBSTR(IN_BUFF,40) = "T")))
                 OR ((LENGTH IN_BUFF > 65)
                     AND (SUBSTR(IN_BUFF,55,4) = "DESC"))) THEN
 
@        Check whether the filename matches the mask, if one is
@        in use

         MATCH := TRUE
         MASK  := FILE_MASK
         MNAME := IN_BUFF BEFORE " "
 
@        If the mask starts "!", it means "does not match"

         IF MASK STARTSWITH "!" THEN
            MASK := MASK AFTER "!"
            DO_MATCHING := FALSE
         ELSE
            DO_MATCHING := TRUE
         FI
 
         IF ((MASK NE "") AND (NOT (MASK INCLUDES "*"))) THEN
            MASK := "*" + MASK
         FI

@        Go through the mask fragments, finding matches
 
         UNTIL (((MASK = "") OR (MASK = "*")) OR NOT MATCH)
         DO
            IF MASK STARTSWITH "*" THEN
               MASK := MASK AFTER "*"
               IF MASK INCLUDES "*" THEN
                  MASK_PART := MASK BEFORE "*"
               ELSE
                  MASK_PART := MASK
               FI
               MASK := MASK AFTER MASK_PART
               IF MNAME INCLUDES MASK_PART THEN
                  MNAME := MNAME AFTER MASK_PART
               ELSE
                  MATCH := FALSE
               FI
            ELSE
               IF MASK INCLUDES "*" THEN
                  MASK_PART := MASK BEFORE "*"
               ELSE
                  MASK_PART := MASK
               FI
               MASK := MASK AFTER MASK_PART
               IF MNAME STARTSWITH MASK_PART THEN
                  MNAME := MNAME AFTER MASK_PART
               ELSE
                  MATCH := FALSE
               FI
            FI
         REPEAT
 
         IF ((MATCH AND DO_MATCHING)
         OR  (NOT (MATCH OR DO_MATCHING))) THEN
 
@           The filename matches the mask

            W_BUFF := IN_BUFF BEFORE " "
            W_BUFF := W_BUFF + "(" + SUBSTR(IN_BUFF, 32, 5) + ")" + "!"
 
            IF OBJECT_TYPE = "L" THEN
               DETAILS := SUBSTR(IN_BUFF, 41, 18)
            ELSE
               DETAILS := SUBSTR(IN_BUFF, 54, 18)
            FI

            IF SUBSTR(DETAILS, 5, 3) = "NEV" THEN
               FILEAGE := 0
            ELSF SUBSTR(DETAILS, 5, 3) ENDSWITH "K" THEN
               FILEAGE := CHARTOINT(SUBSTR(DETAILS, 5, 2)) * 1000
            ELSE
               FILEAGE := CHARTOINT(SUBSTR(DETAILS, 5, 3))
            FI

            IF SUBSTR(DETAILS, 9, 4) ENDSWITH "M" THEN
               FILESIZE := CHARTOINT(SUBSTR(DETAILS, 9, 3)) * 1000000
            ELSF SUBSTR(DETAILS, 9, 4) ENDSWITH "K" THEN
               FILESIZE := CHARTOINT(SUBSTR(DETAILS, 9, 3)) * 1000
            ELSE
               FILESIZE := CHARTOINT(SUBSTR(DETAILS, 9, 4))
            FI

@           Check for age and size

            IF  ((((FILESIZE >= SMALLEST)
            AND   ((FILESIZE <= LARGEST)
                    OR (LARGEST = -1)))
            AND    (FILEAGE >= YOUNGEST))
            AND   ((FILEAGE <= OLDEST)
                    OR (OLDEST = -1))) THEN

               W_BUFF := W_BUFF + DETAILS
 
               PHASE := "WRITING WORK RECORD"
               WRR(CHA = WORK,
                   REC = W_BUFF,
                   RES = FLAG)
 
              MARKED[PTR]  := FALSE
              DELETED[PTR] := FALSE
 
              PTR := PTR + 1

            FI
 
         FI
 
      FI
 
      IN_BUFF := FILL(256)
 
      RDR(CHA = OBJ,
          REC = IN_BUFF,
          RES = SFLAG)
 
   REPEAT
 
   PHASE := "CLOSING OBJECT_LIST"
 
   CLOF(CHA = OBJ,
        RES = FLAG)
 
   PHASE := "CLOSING WORKING_LIST"
 
   CLOF(CHA = WORK,
        RES = FLAG)
 
   IF PTR = 1 THEN
      SMSG("EMPTY OBJECT LIST")
      RESP := 1
      RETURN
   FI
 
   PHASE := "REOPENING WORKING_LIST"
 
   OPF(NAM = *WORKING_LIST,
       CHA = WORK,
       RES = FLAG)
 
@  Start processing the list file.
 
@  If a file is either marked for deletion or marked for inclusion
@  in the file list, the appropriate boolean array entry will be
@  set.
 
   REPLY       := FILL(2000)
   PAGE_ACTION := " "
   LAST_OBJ    := PTR - 1
   FILE_PTR    := 1
   SHOW_DEL    := FALSE
   ALL_DELETED := FALSE
 
   AUTO_PG     := ("Yy" INCLUDES SUBSTR(AUTO_PAGE))
 
   UNTIL (("Qq" INCLUDES PAGE_ACTION) OR ALL_DELETED)
   DO
 
      MSG_TEXT := CLS + STPR + HP + BIN(4) +
                  "Action: " + STUN + " " + STPR +
                  " Next, Prev, First, Last, "
 
      IF SHOW_DEL THEN
         MSG_TEXT := MSG_TEXT + "Undeleted,"
      ELSE
         MSG_TEXT := MSG_TEXT + "Deleted,"
      FI
 
      MSG_TEXT := MSG_TEXT + " Autopage switch, Help, Quit" + NL
 
      IF AUTO_PG THEN
         MSG_TEXT := MSG_TEXT + "AUTOPAGE ON"
      ELSE
         MSG_TEXT := MSG_TEXT + "AUTOPAGE OFF"
      FI
 
      MSG_TEXT := MSG_TEXT + HP + BIN(61) + "Last   Used Alloc" + NL
 
      IF SHOW_DEL THEN
         MSG_TEXT := MSG_TEXT + "Brf, Details, Help, Undelete"
      ELSE
         MSG_TEXT := MSG_TEXT + "Action, Brf, Copy, Details, " +
                     "Help, Mark/Unmark, Query, Xf"
      FI
 
      MSG_TEXT := MSG_TEXT + HP + BIN(60) + "Acc/Wrt  kB    kB" + NL
 
      PTR := 0
 
      CURR_POSN := FILE_PTR
 
      UNTIL ((PTR > 19) OR (FILE_PTR > LAST_OBJ))
      DO
 
         UNLESS (SHOW_DEL NEQ DELETED[FILE_PTR]) THEN
 
            PHASE := "READING RECORD " + NUMERIC(FILE_PTR) + " OF WORK"
 
            RDRN(CHA = WORK,
                 REC = W_BUFF,
                 RNU = FILE_PTR,
                 RES = FLAG)
 
            FNAME[PTR] := W_BUFF BEFORE "!"
            FDETS[PTR] := W_BUFF AFTER "!"
 
            IF MARKED[FILE_PTR] THEN
               MARK[PTR] = "*"
            ELSE
               MARK[PTR] = " "                                                  
            FI
                                                                                
            FPTR[PTR] := FILE_PTR
            PTR := PTR + 1
 
         FI
 
         FILE_PTR = FILE_PTR + 1
 
      REPEAT
 
      LAST_LINE := PTR - 1
 
      FOR PTR FROM 0 TO LAST_LINE
      DO
 
         MSG_TEXT := MSG_TEXT + FILL(1, MARK[PTR])
         MSG_TEXT := MSG_TEXT + STUN + " " + STPR + FNAME[PTR]
         MSG_TEXT := MSG_TEXT + HP + BIN(59)      + FDETS[PTR] + NL
 
      REPEAT
 
      MSG_TEXT := MSG_TEXT + VP + BIN(0) + HP + BIN(13) + SOM
      REPLY    := FILL(2000)
 
      PHASE := "ASKING MESSAGE"
 
      AMSG(PRO = MSG_TEXT,
           MES = REPLY,
           LEN = REPLY_LEN,
           RES = FLAG)
 
      PAGE_ACTION := SUBSTR(REPLY)
 
      IF "Hh" INCLUDES PAGE_ACTION THEN
 
         EXTRA_REPLY := FILL(2000)
 
         PHASE := "SHOWING PAGE HELP"
 
         AMSG(PRO = PAGE_HELP,
              MES = EXTRA_REPLY,
              LEN = EXTRA_REPLY_LEN,
              RES = FLAG)
 
         FILE_PTR := CURR_POSN
 
      ELSF NOT ("Qq" INCLUDES PAGE_ACTION) THEN
 
         IF "Aa" INCLUDES PAGE_ACTION THEN
            IF AUTO_PG THEN
               AUTO_PG := FALSE
            ELSE
               AUTO_PG := TRUE
            FI
            PAGE_ACTION := " "
         FI
 
         REPLY := SUBSTR(REPLY, 1, LENGTH REPLY - 1)
 
         IF ((PAGE_ACTION = " ") AND AUTO_PG) THEN
            PAGE_ACTION := "N"
         FI
 
         STAY_ON_PAGE := FALSE
 
         LAST_REPLY := LENGTH REPLY - 1
 
         IF LAST_REPLY > LAST_LINE THEN
            LAST_REPLY := LAST_LINE
         FI
 
         PTR := 0
 
         UNTIL PTR > LAST_REPLY
         DO
 
            FILE_ACTION := SUBSTR(REPLY, PTR)
 
            SFILE := FNAME[PTR]
 
            SFLAG := 0
 
            IF (("Aa" INCLUDES FILE_ACTION) AND (NOT SHOW_DEL)) THEN
 
               DO_ACTION := ACTION
 
               WHILE DO_ACTION INCLUDES "%F"
               DO
                  DO_ACTION := (DO_ACTION BEFORE "%F") +
                               SFILE +
                               (DO_ACTION AFTER "%F")
               REPEAT
 
               WHILE DO_ACTION INCLUDES "%G"
               DO
                  DO_ACTION := (DO_ACTION BEFORE "%G") +
                               (SFILE BEFORE "(") +
                               (DO_ACTION AFTER "%G")
               REPEAT
 
               WHILE DO_ACTION INCLUDES "%S"
               DO
                  DO_ACTION := (DO_ACTION BEFORE "%S") +
                               ONAME +
                               (DO_ACTION AFTER "%S")
               REPEAT
 
               WHILE DO_ACTION INCLUDES "%T"
               DO
                  DO_ACTION := (DO_ACTION BEFORE "%T") +
                               TARGET +
                               (DO_ACTION AFTER "%T")
               REPEAT
 
               BEGIN
 
                  INT RESULT
 
                  EXSCL(LIN = DO_ACTION,
                        RES = SFLAG)
 
                  IF SFLAG = 0 THEN
                     SFLAG := RESULT
                  FI
 
               END
 
            ELSF "Bb" INCLUDES FILE_ACTION THEN
 
               BRF(FIL = VAL (ONAME + "." + SFILE),
                   RES = SFLAG)
 
            ELSF (("Cc" INCLUDES FILE_ACTION) AND (NOT SHOW_DEL)) THEN
 
               CR(INP = VAL (ONAME + "." + SFILE),
                  NEW = VAL (TARGET + "." + (SFILE BEFORE "(")),
                  RES = SFLAG)
 
            ELSF "Dd" INCLUDES FILE_ACTION THEN
 
               DFD(NAM = VAL (ONAME + "." + SFILE),
                   LEV = STD,
                   RES = SFLAG)
 
               EXTRA_REPLY := FILL(2000)
 
               AMSG(PRO = SOM + " ",
                    MES = EXTRA_REPLY,
                    LEN = EXTRA_REPLY_LEN,
                    RES = FLAG)
 
            ELSF "Hh" INCLUDES FILE_ACTION THEN
 
               EXTRA_REPLY := FILL(2000)
 
               PHASE := "SHOWING FILE HELP"
 
               AMSG(PRO = FILE_HELP,
                    MES = EXTRA_REPLY,
                    LEN = EXTRA_REPLY_LEN,
                    RES = FLAG)
 
            ELSF (("Mm" INCLUDES FILE_ACTION) AND (NOT SHOW_DEL)) THEN
 
               MARKED[FPTR[PTR]] := TRUE
               MARK[PTR]         := "*"
 
            ELSF (("Qq" INCLUDES FILE_ACTION) AND (NOT SHOW_DEL)) THEN
 
               BRF(FIL = VAL (ONAME + "." + SFILE),
                   RES = SFLAG)
 
               EXTRA_REPLY := FILL(2000)
               PHASE := "ASKING DELETE FILE MESSAGE"
 
               SMSG(CLS)
               AMSG(PRO = "Delete this file? ",
                    MES = EXTRA_REPLY,
                    LEN = EXTRA_REPLY_LEN,
                    RES = SFLAG)
 
               IF "Yy" INCLUDES SUBSTR(EXTRA_REPLY) THEN
                  DELETED[FPTR[PTR]] := TRUE
               FI
 
            ELSF "Uu" INCLUDES FILE_ACTION THEN
 
               IF SHOW_DEL THEN
                  DELETED[FPTR[PTR]] := FALSE
               ELSE
                  MARKED[FPTR[PTR]] := FALSE
                  MARK[PTR]         := " "
               FI
                                                                                
            ELSF (("Xx" INCLUDES FILE_ACTION) AND (NOT SHOW_DEL)) THEN
 
               DELETED[FPTR[PTR]] := TRUE
 
            FI
 
            IF SFLAG > 0 THEN
 
               RES_CODE := NUMERIC(SFLAG, 5)
               STAY_ON_PAGE := TRUE
 
               EXTRA_REPLY := FILL(2000)
 
               SMSG("ERROR " + RES_CODE + " ON FILE " + SFILE)
               SRSMSG(SFLAG)
 
               AMSG(PRO = SOM + " ",
                    MES = EXTRA_REPLY,
                    LEN = EXTRA_REPLY_LEN,
                    RES = FLAG)
 
            FI
 
            PTR := PTR + 1
 
         REPEAT
                                                                                 
         IF STAY_ON_PAGE THEN
 
            FILE_PTR := CURR_POSN
 
         ELSF "Dd" INCLUDES PAGE_ACTION THEN
 
            IF SHOW_DEL THEN
               PAGE_ACTION := " "
            ELSE
               SHOW_DEL := TRUE
               FILE_PTR := 1
            FI
                                                                                
         ELSF "Uu" INCLUDES PAGE_ACTION THEN
 
            IF SHOW_DEL THEN
               SHOW_DEL := FALSE
               FILE_PTR := 1
            ELSE
               PAGE_ACTION := " "
            FI
 
         ELSF "Nn" INCLUDES PAGE_ACTION THEN
 
            FOR FILE_PTR FROM FILE_PTR
            UNTIL (((FILE_PTR > LAST_OBJ)
            OR     ((NOT DELETED[FILE_PTR]) AND NOT SHOW_DEL))
            OR     ((DELETED[FILE_PTR]) AND SHOW_DEL))
            DO
            REPEAT
 
            IF FILE_PTR > LAST_OBJ THEN
 
               LINES := 0
 
               FOR FILE_PTR FROM LAST_OBJ BY -1
               UNTIL ((FILE_PTR < 1) OR (LINES > 19))
               DO
                  IF ((NOT DELETED[FILE_PTR] AND (NOT SHOW_DEL))
                  OR  (DELETED[FILE_PTR] AND SHOW_DEL)) THEN
                     LINES = LINES + 1
                  FI
               REPEAT
 
               IF FILE_PTR < 1 THEN
                  IF LINES = 0 THEN
                     IF SHOW_DEL THEN
                        SHOW_DEL := FALSE
                        FILE_PTR := 1
                     ELSE
                        ALL_DELETED := TRUE
                     FI
                  ELSE
                     FILE_PTR := 1
                  FI
               ELSE
                  FILE_PTR := FILE_PTR + 1
               FI
 
            FI                                                                  
 
         ELSF "Pp" INCLUDES PAGE_ACTION THEN
 
            LINES := 0
 
            FOR FILE_PTR FROM (CURR_POSN - 1) BY -1
            UNTIL ((FILE_PTR < 1) OR (LINES > 19))
            DO
               IF ((NOT DELETED[FILE_PTR] AND (NOT SHOW_DEL))
               OR  (DELETED[FILE_PTR] AND SHOW_DEL)) THEN
                  LINES = LINES + 1
               FI
            REPEAT
 
            IF FILE_PTR < 1 THEN
               IF LINES = 0 THEN
                  FOR FILE_PTR FROM 1
                  UNTIL (((FILE_PTR > LAST_OBJ)
                  OR     ((NOT DELETED[FILE_PTR]) AND NOT SHOW_DEL))
                  OR     ((DELETED[FILE_PTR]) AND SHOW_DEL))
                  DO
                  REPEAT
                  IF FILE_PTR > LAST_OBJ THEN
                     IF SHOW_DEL THEN
                        SHOW_DEL := FALSE
                        FILE_PTR := 1
                     ELSE
                        ALL_DELETED := TRUE
                     FI
                  FI
               ELSE
                  FILE_PTR := 1
               FI
            ELSE
               FILE_PTR := FILE_PTR + 1
            FI
 
         ELSF "Ff" INCLUDES PAGE_ACTION THEN
 
            FOR FILE_PTR FROM 1
            UNTIL (((FILE_PTR > LAST_OBJ)
            OR     ((NOT DELETED[FILE_PTR]) AND NOT SHOW_DEL))
            OR     ((DELETED[FILE_PTR]) AND SHOW_DEL))
            DO
            REPEAT
 
            IF FILE_PTR > LAST_OBJ THEN
               IF SHOW_DEL THEN
                  SHOW_DEL := FALSE
                  FILE_PTR := 1
               ELSE
                  ALL_DELETED := TRUE
               FI
            FI
 
         ELSF "Ll" INCLUDES PAGE_ACTION THEN
 
            LINES := 0
 
            FOR FILE_PTR FROM LAST_OBJ BY -1
            UNTIL ((FILE_PTR < 1) OR (LINES > 19))
            DO
               IF ((NOT DELETED[FILE_PTR] AND (NOT SHOW_DEL))
               OR  (DELETED[FILE_PTR] AND SHOW_DEL)) THEN
                  LINES = LINES + 1
               FI
            REPEAT
 
            IF FILE_PTR < 1 THEN
               IF LINES = 0 THEN
                  IF SHOW_DEL THEN
                     SHOW_DEL := FALSE
                     FILE_PTR := 1
                  ELSE
                     ALL_DELETED := TRUE
                  FI
               ELSE
                  FILE_PTR := 1
               FI
            ELSE
               FILE_PTR := FILE_PTR + 1
            FI
 
         ELSE
 
            FOR FILE_PTR FROM CURR_POSN
            UNTIL (((FILE_PTR > LAST_OBJ)
            OR     ((NOT DELETED[FILE_PTR]) AND NOT SHOW_DEL))
            OR     ((DELETED[FILE_PTR]) AND SHOW_DEL))
            DO
            REPEAT
            IF FILE_PTR > LAST_OBJ THEN
               FOR FILE_PTR FROM LAST_OBJ BY -1
               UNTIL (((FILE_PTR < 1)
               OR     ((NOT DELETED[FILE_PTR]) AND NOT SHOW_DEL))
               OR     ((DELETED[FILE_PTR]) AND SHOW_DEL))
               DO
               REPEAT
               IF FILE_PTR < 1 THEN
                  IF SHOW_DEL THEN
                     SHOW_DEL := FALSE
                     FILE_PTR := 1
                  ELSE
                     ALL_DELETED := TRUE
                  FI
               FI
            FI
 
         FI
 
      FI
 
   REPEAT
 
   SMSG(CLS)
 
   FILE_MARKED := FALSE
 
   FOR PTR FROM 1 TO BOUND MARKED
   UNTIL FILE_MARKED
   DO
      IF MARKED[PTR] THEN
         FILE_MARKED := TRUE
      FI
   REPEAT
 
   IF FILE_MARKED THEN
 
      IF MARK_FILE = "" THEN
         REPLY := FILL(2000)
         PHASE := "ASKING MARKFILE MESSAGE"
         AMSG(PRO = "No MARKFILE specified. File name (Q to ignore)? ",
              MES = REPLY,
              LEN = REPLY_LEN,
              RES = SFLAG)
         IF ((REPLY NE "Q") AND (REPLY NE "q")) THEN
            MFILE := SUBSTR(REPLY, 0, REPLY_LEN)
         ELSE
            MFILE := ""
         FI
      ELSE
         MFILE := MARK_FILE
      FI
 
   FI
 
   IF (FILE_MARKED AND (MFILE NE "")) THEN
 
      PHASE := "CREATING MARK_FILE " + MARK_FILE
 
      CRF(NAM = VAL MFILE,
          LNA = MARKFL,
          RES = FLAG)
 
      PHASE := "OPENING MARK_FILE"
 
      OPF(NAM = *MARKFL,
          CHA = MRK,
          ACC = W,
          RES = FLAG)
 
      FOR FILE_PTR FROM 1 TO LAST_OBJ
      DO
         IF MARKED[FILE_PTR] THEN
            PHASE := "READING RECORD NUMBER " + NUMERIC(FILE_PTR)
            RDRN(CHA = WORK,
                 REC = W_BUFF,
                 RNU = FILE_PTR,
                 RES = FLAG)
            PHASE := "WRITING RECORD TO MARK_FILE"
            WRR(CHA = MRK,
                REC = W_BUFF BEFORE "!",
                RES = FLAG)
         FI
      REPEAT
 
      PHASE := "CLOSING MARK_FILE"
 
      CLOF(CHA = MRK,
           RES = FLAG)
 
      PHASE := "SAVING MARK_FILE"
 
      SVF(RES = FLAG)
 
      SMSG("LIST OF MARKED FILES CREATED AS " + MFILE)
 
   FI
 
   FILE_MARKED := FALSE
 
   FOR PTR FROM 1 TO BOUND DELETED
   UNTIL FILE_MARKED
   DO
      IF DELETED[PTR] THEN
         FILE_MARKED := TRUE
      FI
   REPEAT
                                                                                
   IF FILE_MARKED THEN
      REPLY := FILL(2000)
      PHASE := "ASKING DELETE MESSAGE"
      AMSG(PRO = "Action deletes? ",
           MES = REPLY,
           LEN = REPLY_LEN,
           RES = SFLAG)
      IF ((REPLY STARTSWITH "Y") OR (REPLY STARTSWITH "y")) THEN
         FOR PTR FROM 1 TO LAST_OBJ
         DO
            IF DELETED[PTR] THEN
               PHASE := "READING WORK FOR DELETE"
               RDRN(CHA = WORK,
                    REC = W_BUFF,
                    RNU = PTR,
                    RES = FLAG)
               SFILE := ONAME + "." + (W_BUFF BEFORE "!")
               PHASE := "DELETING " + SFILE
               XF(NAM = VAL SFILE,
                  RES = SFLAG)
               IF SFLAG = 33682 THEN
                  REPLY := FILL(2000)
                  PHASE := "ASKING RETENTION DAYS MESSAGE"
                  AMSG(PRO = SFILE + " has retention. Delete anyway? ",
                       MES = REPLY,
                       LEN = REPLY_LEN,
                       RES = SFLAG)
                  IF "Yy" INCLUDES SUBSTR(REPLY) THEN
                     PHASE := "SETTING RETENTION DATE TO +0"
                     CFD(NAM = VAL SFILE,
                         REL = 0DAYS,
                         RES = FLAG)
                     PHASE := "DELETING FILE"
                     XF(NAM = VAL SFILE,
                        RES = SFLAG)
                  ELSE
                     SFLAG := 0
                  FI
               FI
               IF SFLAG NE 0 THEN
                  SMSG("ERROR WHEN " + PHASE)
                  SRSMSG(SFLAG)
                  SFLAG := 0
               FI
            FI
         REPEAT
      FI
   FI
 
   PHASE := "CLOSING *WORKING_LIST"
 
   CLOF(CHA = WORK,
        RES = FLAG)
 
END