*DECK FFSUPFC 
USETEXT TEXTFFS;
      PROC FFSUPFC (SRCBUF, SRCBUF$LEN, CMDNUM);
*CALL COPYRITE
# TITLE FFSUPFC - PARSE FTP COMMAND.                                   #
  
      BEGIN                            # FCSUPFC                       #
  
# 
**    FFSUPFC - PARSE USER COMMAND. 
* 
*     TET TRAN                         88/01/29 
* 
*     THIS PROCEDURE PARSES THE CURRENT USER COMMAND. 
* 
*     PROC FFSUPFC (CMDNUM) 
* 
*     ENTRY   SRCADDR    = AN ITEM CONTAINING THE SOURCE BUFFER ADDR
*             SRCBUF$LEN = NUMBER OF OCTETS IN THE SOURCE BUFFER
* 
*     EXIT    CMDNUM     = A PREDEFINED NUMBER THAT UNIQUELY IDENTIFIES 
*                          THE COMMAND
*             PARA$NUM   = IN COMMON BLOCK /COMMAND/, HAS THE NUMBER OF 
*                          PARAMETER. 
*             PAR        = IN COMMON BLOCK /COMMMAND/, CONTAINS THE 
*                          DETAIL FOR EACH PARAMETER. 
* 
* 
# 
  
# 
****  PROC FFSUPFC - XREF LIST
# 
      XREF
        BEGIN 
        PROC NETUCLR; 
        PROC NETUCAD; 
        FUNC XCOD C(10);
        FUNC XCHD C(10);
        PROC FFSUCDC;                  # COPY A DISPLAY CODE CHAR      #
        END 
  
      ARRAY TRAPMSG[00:00] S(8);
      BEGIN 
      ITEM MSG70 C(00,00,70); 
      ITEM MSG60 C(01,00,60); 
      ITEM MSG50 C(02,00,50); 
      ITEM MSG40 C(03,00,40); 
      ITEM MSG30 C(04,00,30); 
      ITEM MSG20 C(05,00,20); 
      ITEM MSG10 C(06,00,10); 
      ITEM MSGZB U(07,00,60)=[0]; 
      END 
  
# 
****
# 
  
# 
*     LOCAL DEFS
# 
      DEF TOKEN$SIZ          #03#;
      DEF MAXTKN$LEN         #20#;
  
      DEF EOD         #0#;                 # BINARY ZERO - END OF DATA #
      DEF COMMA$0     #O"56000000000000000000"#;    #COMMA, ZERO FILLED#
      DEF SLASH$0     #O"50000000000000000000"#;    #SLASH, ZERO FILLED#
      DEF SPACE$0     #O"55000000000000000000"#;    #SPACE, ZERO FILLED#
      DEF EQUAL$0     #O"54000000000000000000"#;    #EQUAL, ZERO FILLED#
  
      DEF LETTER$A    #O"01000000000000000000"#;    #LETTER A, 0 FILLED#
      DEF LETTER$Z    #O"32000000000000000000"#;    #LETTER Z, 0 FILLED#
      DEF DIGIT$0     #O"33000000000000000000"#;    #DIGIT  0, 0 FILLED#
      DEF DIGIT$9     #O"44000000000000000000"#;    #DIGIT  9, 0 FILLED#
      DEF ASTERISK    #O"47000000000000000000"#;    #ASTERISK, 0 FILLED#
  
      DEF ISCATLIST   #TRUE#; 
      DEF NOTCATLIST  #FALSE#;
  
      ITEM ECLABEL       C(10)="ERRORCODE"; 
      ITEM ERRORCODE     U; 
      ITEM CMDNUM        I;            # COMMAND NUMBER                #
      ITEM INBUF$LEN     I;            # NUMBER OF CHARS IN INBUF      #
      ITEM SRCBUF$LEN    I; 
      ITEM TEMPINDEX     I; 
      ITEM CDT$INDEX     I;            # CURRENT INDEX TO CDT TABLE    #
      ITEM I             I;            # LOOP INDUCTION VARIABLE       #
      ITEM INBUF$INDEX   I;            # CURRENT INDEX TO INPUT BUFFER #
      ITEM PAR$INDEX     I;            # CURRENT INDEX TO PARAM ARRAY  #
      ITEM PPTR          I;            # FIRST PDT ENTRY OF THIS COMMD #
      ITEM PSIZ          I;            # NO OF PARAMETERS COMMAND ALLOW#
      ITEM PNUM          I;            # INDEX FOR SEARCHING PDT TABLE #
      ITEM RIGHT$SEP     U;            # THE EXPECTING SEPARATOR       #
      ITEM J             I;            # LOOP INDUCTION VARIABLE       #
      ITEM SEPARATOR     U;            # THE CURRENT SEPARATOR         #
  
      ARRAY SRCBUF[00:00] S(1); 
        BEGIN 
        ITEM  SRC$WORD  C(00,00,10);
        END 
  
      ARRAY INBUF[00:23] S(1);
        BEGIN 
        ITEM INB$WORD   U(00,00,60);
        END 
  
      ARRAY TOKEN [00:00] S(TOKEN$SIZ);  # CURRENT ASSEMBLED TOKEN     #
        BEGIN 
        ITEM TKN$WORD    U(00,00,60);  # WHOLE WORD REFERENCE          #
        ITEM TKN$10CHAR  C(00,00,10);  # FIRST 10 CHARACTERS           #
        ITEM TKN$20CHAR  C(00,00,20);  # FIRST 20 CHARACTERS           #
        ITEM TKN$LEN     U(02,00,60);  # TOKEN SIZE IN CHARACTERS      #
        END 
  
      ARRAY THISCHAR [00:00] S(1);     # CURRENT CHARACTER             #
        BEGIN 
        ITEM THISCHR        U(00,00,60)=[0];
        END 
  
      CONTROL EJECT;
      FUNC GOODSEP B; 
      BEGIN                            # GOODSEP                       #
# 
*     INTERNAL PROC GOODSEP - GOOD SEPARATOR
* 
*     THIS EMBEDDED FUNCTION RETURNS TRUE IF SEPARATOR IS END OF DATA,
*     A COMMA, A SLASH, OR A BLANK. IT RETURNS FALSE OTHERWISE. 
* 
# 
  
      GOODSEP =  (SEPARATOR EQ EOD)     OR
                 (SEPARATOR EQ COMMA$0) OR
                 (SEPARATOR EQ SLASH$0) ; 
  
      RETURN;                          # RETURN TO CALLER              #
  
      END                              # GOODSEP                       #
  
      CONTROL EJECT;
      PROC FFS2GNC; 
      BEGIN                            # FFS2GNC                       #
# 
*     INTERNAL PROC FFS2GNC - GET NEXT CHARATER 
* 
*     THIS EMBEDDED PROCEDURE GETS THE NEXT CHARACTER IF ONE IS 
*     AVAILABLE. IT RETURNS EOD (END OF DATA CHARATER) IF NO MORE CHAR
*     IS AVAILABLE.  THE RETURNED CHARACTER IS PUT IN ARRAY THECHAR.
* 
# 
  
      IF INBUF$INDEX GQ INBUF$LEN        # IF NO MORE CHARACTER TO GET,#
      THEN
        BEGIN 
        THISCHR = EOD;                   # RETURN END OF DATA CHARATER,#
        RETURN;                          # AND GET OUT.                #
        END 
  
      FFSUCDC (INBUF, INBUF$INDEX, THISCHAR, 0);  # COPY ONE CHARACTER #
      INBUF$INDEX = INBUF$INDEX+1;   #POINT TO NEXT INPUT CHAR IN INBUF#
  
      RETURN;                          # RETURN TO CALLER              #
  
      END                              # FFS2GNC                       #
  
      CONTROL EJECT;
      PROC FFS2GNN; 
      BEGIN                            # FFS2GNN                       #
# 
*     INTERNAL PROC FFS2GNN - GET NEXT NON-BLANK CHARATER 
* 
*     THIS EMBEDDED PROCEDURE SKIPS ALL BLANKS AND GET THE NEXT NON-
*     BLANK CHARACTER INTO ARRAY THISCHAR 
# 
  
      ITEM I       I; 
  
      FFS2GNC;                                    # GET NEXT CHARACTER #
      FOR I=I WHILE (THISCHR EQ SPACE$0)
                AND (INBUF$INDEX LS INBUF$LEN) DO 
        BEGIN 
        FFS2GNC;
        END 
  
      RETURN;                          # RETURN TO CALLER              #
  
      END                              # FFS2GNN                       #
  
  
      CONTROL EJECT;
      PROC FFS2SPV; 
      BEGIN                            # FFS2SPV                       #
# 
*     INTERNAL PROC FFS2SPV - STORE (CURRENT) PARAMTER VALUE
* 
*     THIS EMBEDDED PROCEDURE COPY THE CONTENT OF TOKEN INTO THE CURRENT
*     ENTRY OF PAR ARRAY
# 
  
      PAR$VAL20[PAR$INDEX] = TKN$20CHAR;
      PAR$LEN  [PAR$INDEX] = TKN$LEN; 
      PAR$INDEX = PAR$INDEX + 1;
  
      RETURN;                          # RETURN TO CALLER              #
  
      END                              # FFS2SPV                       #
  
  
      CONTROL EJECT;
      PROC FFS2ACC; 
      BEGIN                            # FCS2ACC                       #
# 
*     INTERNAL PROC FFS2SCC - APPEND CURRENT CHARACTER TO TOKEN 
* 
*     THIS EMBEDDED PROCEDURE APPENDS THE CURRENT CHARACTER INTO THE
*     THE NEXT AVAILABLE POSITION IN ARRAY TOKEN. 
# 
      FFSUCDC (THISCHAR, 0, TOKEN, TKN$LEN);
      TKN$LEN = TKN$LEN + 1;
  
      RETURN;                          # RETURN TO CALLER              #
  
      END                              # FFS2ACC                       #
  
      CONTROL EJECT;
      PROC FFS2GNT; 
      BEGIN                            # FCS2GNT                       #
# 
*     INTERNAL PROC FFS2GNT - GET NEXT TOKEN
* 
*     THIS EMBEDDED PROCEDURE ASSEMBLIES THE NEXT TOKEN STARTING FROM 
*     INBUF$INDEX.
* 
# 
      ITEM I       I; 
  
      NETUCLR (LOC(TOKEN), TOKEN$SIZ);    # CLEAR THE TOKEN            #
      TKN$LEN = 0;                        # JUST FOR READABILITY       #
      FFS2GNN;                            # GET NEXT NON-BLANK CHAR    #
      FOR I=I WHILE (TKN$LEN LS MAXTKN$LEN) 
                AND (THISCHR NQ SPACE$0)  # IF THISCHR ISNOT A SPACE,  #
                AND (THISCHR NQ COMMA$0)  #    NOT A COMMA,            #
                AND (THISCHR NQ SLASH$0)  #    NOT A SLASH,            #
                AND (THISCHR NQ EQUAL$0)  #    NOT AN EQUAL SIGN,      #
                AND (THISCHR NQ EOD)      #    AND NOT END OF DATA     #
      DO
        BEGIN 
        FFS2ACC;                   # APPEND CURRENT CHARACTER TO TOKEN #
        FFS2GNC;                   # AND GET NEXT CHARACTER.           #
        END 
  
      SEPARATOR = THISCHR;             # REMEMBER WHAT THE SEPARATOR IS#
  
      RETURN;                          # RETURN TO CALLER              #
  
      END                              # FFS2GNT                       #
  
      CONTROL EJECT;
      FUNC FFS2CPR (PARA$TYPE,PARA$SIZE) B; 
      BEGIN                            # FFS2CPR                       #
# 
*     INTERNAL FUNC FFS2CPR - CHECK PARAMETER RANGE 
* 
*     THIS EMBEDDED FUNTION RETURNS TRUE IF THE CURRENT PARAMETER IS
*     WITHIN THE DESIRED RANGE, AND RETURNS FALSE OTHERWISE.
*       . THE PARAMETER IS IN ARRAY *TOKEN* 
*           PARA$TYPE - PARAMETER TYPE CODE, CAN BE 
*                          *ALPHA*
*                          *NUMERIC*
*                          *ALPHANUM* (ALPHANUMERIC)
*                          *ALNUMAS*  (ALPHANUM AND ASTERISK) 
* 
*           PARA$SIZE - MAXIMUM NUMBER OF CHARACTERS THIS TYPE ALLOWS.
# 
      ITEM PARA$TYPE    I;
      ITEM PARA$SIZE    I;
      ITEM VALID        B;
      ITEM I            I;
  
      ARRAY THECHAR [00:00] S(1); 
        BEGIN 
        ITEM THECHR     C(00,54,01);
        END 
  
# 
*     MAKE SURE THE NUMBER OF CHARS DOES NOT EXCEED THE LIMIT THIS
*     TYPE ALLOWS.
# 
      IF TKN$LEN GR PARA$SIZE          # IF TOO MANY CHARACTERS IN PARA#
      THEN
        BEGIN 
        FFS2CPR = FALSE;               # SET RESULT TO BAD VALIDATION  #
        RETURN;                        # AND EXIT THIS ROUTINE         #
        END 
  
# 
*     STEP THROUGH EACH CHARACTER IN THE TOKEN, MAKING SURE THEY ARE
*     ALL WITHIN RANGE. 
# 
      VALID = TRUE; 
      FOR I=0 STEP 1 WHILE (I LS TKN$LEN) AND VALID DO
        BEGIN 
        FFSUCDC (TOKEN, I, THECHAR, 9);     # GET A CHARACTER          #
        IF (PARA$TYPE EQ NUMERIC) 
        THEN
          BEGIN 
          VALID = (THECHR GQ "0") AND (THECHR LQ "9");
          END 
        ELSE IF (PARA$TYPE EQ ALPHA)
        THEN
          BEGIN 
          VALID = (THECHR GQ "A") AND (THECHR LQ "Z");
          END 
        ELSE IF (PARA$TYPE EQ ALPHANUM) 
        THEN
          BEGIN 
          VALID = (THECHR GQ "A") AND (THECHR LQ "9");
          END 
        ELSE IF PARA$TYPE EQ ALNUMAS   # ALPHANUM, ASTERISK ALLOWED    #
        THEN
          BEGIN 
          VALID = ( THECHR EQ "*" ) OR
                  ((THECHR GQ "A") AND (THECHR LQ "9"));
          END 
        END 
  
      FFS2CPR = VALID;                 # RETURN THE VALIDATING RESULT  #
  
      RETURN;                          # RETURN TO CALLER              #
      END                              # FFS2CPR                       #
  
      CONTROL EJECT;
      FUNC FFS2VPT (PDT$INDEX) B; 
      BEGIN                            # FFS2VPT                       #
# 
*     INTERNAL FUNC FFS2VPT - VALIDATE PARAMETER TYPE 
* 
*     THIS EMBEDDED FUNTION RETURNS TRUE IF THE CURRENT PARAMETER PASSES
*     THE TYPE CHECK, AND RETURNS FALSE OTHERWISE.
*       . THE PARAMETER IS IN ARRAY *TOKEN* 
*       . THE DESCRIPTION FOR THE PARAMETER IS IN *PDT* TABLE, INDEXED
*         BY *PDT$INDEX*
*           PDT$TPCODE[PDT$INDEX] - PARAMETER TYPE CODE, CAN BE 
*                                     *ALPHA* 
*                                     *NUMERIC* 
*                                     *ALPHANUM* (ALPHANUMERIC) 
*                                     *ALNUMAS*  (ALPHANUM AND ASTERISK)
*                                     *LISTTYPE* (LIST OF KNOW VALUES)
* 
*           PDT$TPLEN [PDT$INDEX] - MAXIMUM NUMBER OF CHARACTERS THIS 
*                                   TYPE ALLOWS.
* 
# 
      ITEM PARA$TYPE    I;
      ITEM PARA$SIZE    I;
      ITEM VALID        B;
      ITEM PDT$INDEX    I;
      ITEM LPTR         I;
      ITEM LSIZ         I;
      ITEM I            I;
  
      PARA$TYPE = PDT$TPCODE[PDT$INDEX];
      PARA$SIZE = PDT$TPLEN [PDT$INDEX];
  
# 
*     IF THIS PARAMETER, FOR INSTANCE "XT", IS OF TYPE NUMAS, THE VALUE 
*     CAN BE A SINGLE ASTERISK, OR ALL DIGITS.
# 
      IF (PARA$TYPE EQ NUMAS) 
      THEN
        BEGIN 
        IF TKN$10CHAR EQ ASTERISK      # SEE IF THE VALUE IS AN ASTERK# 
        THEN
          BEGIN 
          FFS2VPT = TRUE;              # IF IT IS, THE PARA IS GOOD.  # 
          RETURN;                      #                   SO, RETURN # 
          END 
        ELSE                           # OTHERWISE,                   # 
          BEGIN 
          PARA$TYPE = NUMERIC;         # PROCEED, TREAT IT AS NUMERIC.# 
          END 
        END 
  
      IF   (PARA$TYPE EQ ALPHA)        # IF IT IS ALPHA TYPE           #
        OR (PARA$TYPE EQ NUMERIC)      # OR IF IT IS NUMERIC TYPE      #
        OR (PARA$TYPE EQ ALPHANUM)     # OR IT IS ALPHA NUMERIC        #
        OR (PARA$TYPE EQ ALNUMAS)      # OR ALPHANUMERIC AND ASTERISK  #
      THEN
        BEGIN 
        FFS2VPT = FFS2CPR (PARA$TYPE, PARA$SIZE);  # CALL CHECK RANGE  #
        END 
      ELSE                             # LIST TYPE                     #
        BEGIN 
        LPTR = PDT$LPTR[PDT$INDEX];    # POINT TO THE FIRST LIST ELEMNT#
        LSIZ = PDT$LSIZ[PDT$INDEX];    # NO. OF ELEMENTS FOR THIS CMD  #
        VALID = FALSE;                 # INITIALIZE TO NOT VALID       #
        FOR I=LPTR STEP 1 WHILE (I LS LPTR+LSIZ) AND (NOT VALID) DO 
          BEGIN 
          VALID = LET$VALUEN[I] EQ TKN$10CHAR;
          END 
        FFS2VPT = VALID;               # RESULT THE VALIDATION RESULT  #
        END 
  
      RETURN;                          # RETURN TO CALLER              #
  
      END                              # FFS2VPT                       #
  
      CONTROL EJECT;
      PROC FFS2CPF (ISCATLIST); 
      BEGIN                            # FFS2CPF                       #
# 
*     INTERNAL PROC FFS2CPF - CRACK (NOS) PF PARAMETERS 
* 
*     THIS EMBEDDED PROCEDURE PARSES THE NOS PERMANENT FILE PARAMETERS. 
*     A PF PARAMETER HAS THE FORM,
*              FNAME/KEYWORD=VALUE (OR JUST KEYWORD), ... 
*       . ALL PARAMETERS (EXCEPT THE FIRST - FNAME) HAVE THE FORM 
*         KEYWORD=VALUE, OR JUST KEYWORD. NO POSITION PARAMETERS
*         ALLOWED.
*       . ALL SEPARATORS (EXCEPT THE FIRST ONE - SLASH) HAVE TO 
*         BE A COMMA. 
* 
*     NOTE
*       IF THIS IS THE PARAMETER LIST FOR THE CATLIST COMMAND (ISCATLIST
*     FLAG = TRUE), THE PORTION FNAME DOES NOT EXIST. 
* 
# 
  
     ITEM ISCATLIST     B;        # TRUE IF THIS IS THE CATLIST PAR LST#
     ITEM PDT$INDEX     I;        # CURRENT INDEX TO PDT TABLE         #
     ITEM PNUM          I;
  
# 
*    RESET THE SEEN FLAG FOR EACH POSSIBLE PARAMETER. 
# 
      FOR PDT$INDEX = PPTR STEP 1 WHILE PDT$INDEX LS (PPTR+PSIZ)
      DO
        BEGIN 
        PDT$SEEN[PDT$INDEX] = FALSE;
        END 
  
      PDT$INDEX = PPTR;           # POINT TO BEGINING OF PARAMETER LIST#
  
  
# 
*     IF THIS IS THE CATLIST PARAMETER LIST, SKIP PARSING THE POSI- 
*     TIONAL FILE NAME SECTION. 
# 
      IF ISCATLIST
      THEN
        BEGIN 
        PAR$INDEX = PAR$INDEX + 1;
        GOTO CAT$ENTRYPT;              # GOTO CATLIST ENTRY POINT      #
        END 
  
# 
*     CHECK FILE NAME 
# 
      FFS2GNT;                         # GET FIRST TOKEN - FILE NAME   #
      IF   ( TKN$LEN EQ 0 )            # NO FILE NAME SPECIFIED,       #
        OR ( NOT FFS2VPT(PDT$INDEX))   #  OR NOT A VALID NOS FILE NAME,#
        OR ( NOT GOODSEP )             #  OR THE SEPARATOR IS NOT GOOD #
      THEN
        BEGIN 
        CMDNUM = ERR$501;              # RETURN ERROR CODE,            #
        ERRORCODE = 1;
        RETURN;                        # AND GET OUT OF THIS ROUTINE   #
        END 
# 
*     FILE NAME IS GOOD, STORE IT.
# 
      FFS2SPV;                     # STORE THE FILE NAME INTO PAR ARRAY#
      PDT$SEEN[PDT$INDEX] = TRUE;      #REMEMBER, THIS PARA IS NOW SEEN#
  
  
CAT$ENTRYPT:                           # CATLIST ENTRY POINT           #
  
# 
*     UP TO THIS POINT, THE FNAME IS EITHER NOT NEEDED, OR HAS BEEN 
*     SUCCESSFULLY PARSED, THE FOLLOWING CODE PARSE THE REST OF THE 
*     PARAMETER LIST  KEYWORD[=VALUE] , KEYWORD[=VALUE] , ... 
# 
  
      FFS2GNT;                         # GET NEXT TOKEN                #
  
      FOR I=I                          # LOOP WHILE THERE IS MORE TO DO#
        WHILE (TKN$LEN NQ 0) OR (SEPARATOR NQ EOD)
      DO
        BEGIN 
        PNUM =0;                       # INITILAIZE TO NOT FOUND       #
        FOR PDT$INDEX=PPTR STEP 1      # SEARCH PDT FOR MATCHING PARA  #
          WHILE ((PDT$INDEX LS PPTR+PSIZ) AND (PNUM EQ 0))
        DO
          BEGIN 
          IF TKN$10CHAR EQ PDT$NAME[PDT$INDEX]
          THEN
            BEGIN 
            PNUM = PDT$INDEX; 
            END 
          END 
  
        IF PNUM EQ 0                   # PARAMETER NOT FOUND IN PDT    #
        THEN
          BEGIN 
          ERRORCODE = 2;
          CMDNUM = ERR$501;            # RETURN ERROR CODE,            #
          RETURN;                      # AND GET OUT OF THIS ROUTINE   #
          END 
  
# 
*       PARAMETER WAS FOUND IN PDT TABLE, VALIDATE IT 
# 
        IF SEPARATOR EQ EQUAL$0        # CASE OF KEYWORD = VALUE       #
        THEN
          BEGIN 
          FFS2GNT;                     # GET PARAMETER VALUE.          #
  
          IF    ( NOT GOODSEP )        # IF IT IS NOT A GOOD SEPARATOR,#
             OR ( PDT$SEEN[PNUM]    )  # PARAM HAS BEEN SEEN BEFORE, OR#
             OR ( NOT FFS2VPT(PNUM) )  # PARAM DID NOT PASS VALIDATION #
          THEN
            BEGIN 
            ERRORCODE = 3;
            CMDNUM = ERR$501;          # RETURN ERROR CODE,            #
            RETURN;                    # AND GET OUT OF THIS ROUTINE   #
            END 
  
          PAR$NAME[PAR$INDEX]= PDT$NAME[PNUM];  # STORE PARAMETER NAME #
          FFS2SPV;                     # STORE THE PARAMETER VALUE     #
          END 
  
        ELSE                           # CASE OF KEYWORD ONLY          #
          BEGIN 
          IF   (PDT$TYPE[PNUM] NQ KEYWORD) # IF IT IS NOT KEYWORD TYPE,#
            OR ( PDT$SEEN[PNUM]  )     # OR PARAM HAS BEEN SEEN BEFORE #
            OR ( NOT GOODSEP     )     # OR THE SEPARATOR IS BAD       #
          THEN
            BEGIN 
            ERRORCODE = 4;
            CMDNUM = ERR$501;          # RETURN ERROR CODE,            #
            RETURN;                    # AND GET OUT OF THIS ROUTINE   #
            END 
  
          PAR$NAME[PAR$INDEX]= PDT$NAME[PNUM];  # STORE PARAMETER NAME #
          PAR$INDEX = PAR$INDEX + 1;   # ADJUST PAR$INDEX TO NEXT ENTRY#
          END 
  
        PDT$SEEN[PNUM] = TRUE;         # REMEMBER THIS PARA IS NOW SEEN#
  
        FFS2GNT;         # GET NEXT TOKEN. GET READY FOR NEXT ITERATION#
  
        END 
  
      RETURN;                          # RETURN TO CALLER              #
  
      END                              # FFS2CPF                       #
  
      CONTROL EJECT;
      PROC FFS2CFP; 
      BEGIN                            # FFS2CFP                       #
# 
*     INTERNAL PROC FFS2CFP - CRACK FTP PARAMETERS
* 
*     THIS EMBEDDED PROCEDURE CRACKS THE FTP PARAMETER LIST. ALL THE FTP
*     PARAMETERS ARE POSITIONAL. HOWEVER, THE SEPARATOR, DEPEDING ON THE
*     COMMAND, CAN BE EITHER A BLANK, OR A COMMA.  THE CORRECT SEPARATOR
*     IS SET IN THE VARIABLE *RIGHT$SEP* PRIOR TO CALLS TO THIS ROUTINE.
# 
      ITEM I       I; 
      ITEM PNUM    I; 
# 
*     RESET THE SEEN FLAG FOR EACH POSSIBLE PARAMETER.
# 
      FOR PNUM = PPTR STEP 1 WHILE PNUM LS (PPTR+PSIZ)
      DO
        BEGIN 
        PDT$SEEN[PNUM] = FALSE; 
        END 
  
      FFS2GNT;                         # GET FIRST TOKEN ON THE LIST   #
      FOR PNUM=PPTR STEP 1             # LOOP WHILE THERE IS MORE TO DO#
          WHILE ((TKN$LEN NQ 0) OR (SEPARATOR NQ EOD))
      DO
        BEGIN 
        IF   ( (SEPARATOR NQ EOD) AND     # IF IT IS NOT END OF DATA,  #
               (SEPARATOR NQ RIGHT$SEP))  #     AND WRONG SEPARATOR,   #
          OR (PNUM GQ PPTR+PSIZ)       # OR TOO MANY PARAMETERS SEEN   #
          OR (NOT FFS2VPT(PNUM))       # OR PARA TYPE FAILS VALIDATION #
        THEN
          BEGIN 
          ERRORCODE = 5;
          CMDNUM = ERR$501;            # RETURN ERROR CODE             #
          RETURN;                      # AND EXIT THIS ROUTINE         #
          END 
# 
*       EVERYTHING LOOKS GOOD, STORE THE PARAMETER. 
# 
        PDT$SEEN[PNUM] = TRUE;         # REMEMBER THIS PARA IS NOW SEEN#        # 
        FFS2SPV;                       # STORE PARAM INTO PAR ARRAY    #
        FFS2GNT;                       # GET ANOTHER TOKEN             #
        END 
  
      RETURN;                          # RETURN TO CALLER              #
  
      END                              # FFS2CFP                       #
  
  
      CONTROL EJECT;
# 
*     START MAIN PROCEDURE
# 
      ERRORCODE = 0;
# 
*     CONVERT TO DISPLAY CODE.
# 
  
      TEMPINDEX  = 0; 
      INBUF$LEN = SRCBUF$LEN - 2; 
      NETUCAD (SRCBUF, 0, INBUF$LEN, INBUF, TEMPINDEX); 
  
# 
*     PARSE COMMAND 
# 
      PARA$NUM = 0;                    # INIT NUMBER OF PARAMS TO ZERO #
      INBUF$INDEX = 0;                 # POINT TO BEGINING OF INPUT BUF#
  
      FFS2GNT;                         # GET FIRST TOKEN - COMMAND NAME#
      IF (TKN$LEN EQ 0) OR             # NOTHING THERE, OR             #
        NOT((SEPARATOR EQ SPACE$0)OR(SEPARATOR EQ EOD)) # BAD SEPARATOR#
      THEN
        BEGIN 
        CMDNUM = ERR$500;              # RETURN ERROR CODE             #
        GOTO FFSUPFC$EXIT;             # AND GET OUT                   #
        END 
  
  
# 
*     SEARCH COMMAND DISCRIPTOR TABLE FOR COMMAND NAME MATCHING TOKEN 
# 
  
      CDT$NAME[CDT$LAST] = TKN$10CHAR;  # ASSURE SEARCHING WILL HIT    #
  
      FOR CDT$INDEX=CDT$FIRST STEP 1
                     WHILE CDT$NAME[CDT$INDEX] NQ TKN$10CHAR
      DO
        BEGIN 
        END 
  
      IF CDT$INDEX LS CDT$LAST         # COMMAND FOUND IN CDT TABLE    #
      THEN
        BEGIN 
        CMDNUM = CDT$CNUM[CDT$INDEX];  # RETURN COMMAND NUMBER         #
        END 
      ELSE                             # NOT FOUND - UNKNOWN COMMAND   #
        BEGIN 
        CMDNUM = ERR$500;              # RETURN ERROR CODE             #
        GOTO FFSUPFC$EXIT;             # AND EXIT THIS ROUTINE         #
        END 
  
  
# 
*     IF THIS FTP COMMAND IS NOT SUPPORTED, STOP THE PARSING , RETURN 
# 
  
      IF NOT CDT$SPPT[CDT$INDEX] THEN GOTO FFSUPFC$EXIT;
  
  
# 
*     START PARSING PARAMETERS
# 
  
      PAR$INDEX = 1;                   # INITILAIZE PARAM ARAY INDEX   #
      NETUCLR (LOC(PAR), (PAR$LAST-PAR$FIRST+1)*PAR$ESIZ);
      PPTR = CDT$PPTR[CDT$INDEX];      # FIRST PDT ENTRY FOR THIS COMMD#
      PSIZ = CDT$PSIZ[CDT$INDEX];      # NO OF PARA THIS COMMD ALLOWS  #
  
  
# 
*     THE PARAMETER LIST CAN BE ONE OF THE FOLLOWING FORMATS
* 
*       SAMPLE COMMAND  SAMPLE PARAMETER LIST    POINTS OF INTEREST 
* 
*     1.    TYPE        A N                      SEPARATOR = BLANK
*     2.    PORT        H1,H2,H3,H4,H5,H6        SEPARATOR = COMMA
*     3.    STOR        FNAME,KEYWORD=VALUE,...  1ST PARA IS POSITIONAL 
*     4.    NLST        KEYWORD=VALUE,... 
# 
  
      IF CDT$NOSPF[CDT$INDEX]       # IF NOS PF INVOLVED, CASE 3 OR 4  #
      THEN
        BEGIN 
        IF CMDNUM EQ LIST$CMD OR
           CMDNUM EQ NLST$CMD OR
           CMDNUM EQ SITE$CMD 
        THEN
          BEGIN 
          FFS2CPF (ISCATLIST);         # CRACK NOS PF PARAS  - CATLIST #
          END 
        ELSE
          BEGIN 
          FFS2CPF (NOTCATLIST);        #CRACK NOS PF PARAS - NONCATLIST#
          END 
        END 
      ELSE                          # NOS PF NOT INVOLVED, 1 OR 2 ABOVE#
        BEGIN 
        IF CMDNUM EQ TYPE$CMD          # IN CASE OF THE TYPE COMMAND,  #
        THEN
          RIGHT$SEP = SPACE$0;         # THE SEPARATOR SHOULD BE BLANK.#
        ELSE
          RIGHT$SEP = COMMA$0;         # OTHERWISE, IT SHOULD BE COMMA.#
  
        FFS2CFP;                       # CRACK FTP PARAMETER LIST      #
        END 
  
      IF CMDNUM LS 0                   # ERROR OCCURED,                #
        THEN GOTO FFSUPFC$EXIT;        #            EXIT THIS ROUTINE  #
  
  
# 
*     COMMAND, PARAMETER NAMES AND PARAMETER VALUES PARSED SUCCESSFULLY.
*     CHECK THAT ALL REQUIRED PARAMETERS HAVE BEEN SPECIFIED. 
# 
      FOR PNUM=PPTR STEP 1 WHILE PNUM LS PPTR+PSIZ DO 
        BEGIN 
        IF PDT$REQD[PNUM] AND NOT PDT$SEEN[PNUM]
        THEN
          BEGIN 
          CMDNUM = ERR$500;            # RETURN ERROR CODE             #
          GOTO FFSUPFC$EXIT;           # AND EXIT THIS ROUTINE         #
          END 
        END 
  
      PARA$NUM = PAR$INDEX - 1;        # RETURN NUMBER OF PARAMS SEEN  #
  
FFSUPFC$EXIT: 
  
      RETURN;                          # RETURN TO CALLER              #
  
      END                              # FFSUPFC                       #
  
      TERM
