IMPLEMENTATION MODULE CmdArgs ;


FROM ASCII IMPORT cr, nul ;

FROM StrLib IMPORT StrLen ;


CONST
   esc    = '\' ;
   space  = ' ' ;
   squote = "'" ;
   dquote = '"' ;
   tab    = ' ' ;

(* %%%FORWARD%%%
PROCEDURE GetArg (CmdLine: ARRAY OF CHAR ;
                  n: CARDINAL; VAR Argi: ARRAY OF CHAR) : BOOLEAN ; FORWARD ;
PROCEDURE GetNextArg (CmdLine: ARRAY OF CHAR; VAR CmdIndex: CARDINAL;
                      VAR Arg: ARRAY OF CHAR) : BOOLEAN ; FORWARD ;
PROCEDURE CopyUntilSpace (From: ARRAY OF CHAR;
                          VAR FromIndex: CARDINAL; FromHigh: CARDINAL;
                          VAR To: ARRAY OF CHAR;
                          VAR ToIndex: CARDINAL; ToHigh: CARDINAL) ; FORWARD ;
PROCEDURE CopyUntil (From: ARRAY OF CHAR;
                     VAR FromIndex: CARDINAL; FromHigh: CARDINAL;
                     VAR To: ARRAY OF CHAR;
                     VAR ToIndex: CARDINAL; ToHigh: CARDINAL;
                     UntilChar: CHAR) ; FORWARD ;
PROCEDURE CopyChar (From: ARRAY OF CHAR;
                    VAR FromIndex: CARDINAL; FromHigh: CARDINAL;
                    VAR To: ARRAY OF CHAR;
                    VAR ToIndex: CARDINAL; ToHigh: CARDINAL) ; FORWARD ;
PROCEDURE Narg (CmdLine: ARRAY OF CHAR) : CARDINAL ; FORWARD ;
PROCEDURE Escape (ch: CHAR) : BOOLEAN ; FORWARD ;
PROCEDURE Space (ch: CHAR) : BOOLEAN ; FORWARD ;
PROCEDURE DoubleQuote (ch: CHAR) : BOOLEAN ; FORWARD ;
PROCEDURE SingleQuote (ch: CHAR) : BOOLEAN ; FORWARD ;
   %%%FORWARD%%% *)


(*
   GetArg - takes a command line and attempts to extract argument, n,
            from CmdLine. The resulting argument is placed into, a.
            The result of the operation is returned.
*)

PROCEDURE GetArg (CmdLine: ARRAY OF CHAR ;
                  n: CARDINAL; VAR Argi: ARRAY OF CHAR) : BOOLEAN ;
VAR
   Index,
   i     : CARDINAL ;
   Another: BOOLEAN ;
BEGIN
   Index := 0 ;
   (* Continually retrieve an argument until we get the n th argument. *)
   i := 0 ;
   REPEAT
      Another := GetNextArg(CmdLine, Index, Argi) ;
      INC(i) ;
   UNTIL (i>n) OR (NOT Another) ;
   RETURN( i>n )
END GetArg ;


(*
   GetNextArg - Returns true if another argument may be found.
                The argument is taken from CmdLine at position Index,
                Arg is filled with the found argument.
*)

PROCEDURE GetNextArg (CmdLine: ARRAY OF CHAR; VAR CmdIndex: CARDINAL;
                      VAR Arg: ARRAY OF CHAR) : BOOLEAN ;
VAR
   ArgIndex: CARDINAL ;  (* Index into Arg *)
   HighA,
   HighC: CARDINAL ;
BEGIN
   HighA := HIGH(Arg) ;
   HighC := StrLen(CmdLine) ;
   ArgIndex := 0 ;
   (* Skip spaces *)
   WHILE (CmdIndex<HighC) AND Space(CmdLine[CmdIndex]) DO
      INC(CmdIndex)
   END ;
   IF CmdIndex<HighC
   THEN
      IF SingleQuote(CmdLine[CmdIndex])
      THEN
         (* Skip over the single quote *)
         INC(CmdIndex) ;
         CopyUntil(CmdLine, CmdIndex, HighC, Arg, ArgIndex, HighA, squote) ;
         INC(CmdIndex)
      ELSIF DoubleQuote(CmdLine[CmdIndex])
      THEN
         (* Skip over the double quote *)
         INC(CmdIndex) ;
         CopyUntil(CmdLine, CmdIndex, HighC, Arg, ArgIndex, HighA, dquote) ;
         INC(CmdIndex)
      ELSE
         CopyUntilSpace(CmdLine, CmdIndex, HighC, Arg, ArgIndex, HighA)
      END
   END ;
   (* Skip spaces *)
   WHILE (CmdIndex<HighC) AND Space(CmdLine[CmdIndex]) DO
      INC(CmdIndex)
   END ;
   IF ArgIndex<HighA
   THEN
      Arg[ArgIndex] := nul
   END ;
   RETURN( (CmdIndex<HighC) )
END GetNextArg ;


(*
   CopyUntilSpace - copies characters until a Space character is found.
*)

PROCEDURE CopyUntilSpace (From: ARRAY OF CHAR;
                          VAR FromIndex: CARDINAL; FromHigh: CARDINAL;
                          VAR To: ARRAY OF CHAR;
                          VAR ToIndex: CARDINAL; ToHigh: CARDINAL) ;
BEGIN
   WHILE (FromIndex<FromHigh) AND (ToIndex<ToHigh) AND
         (NOT Space(From[FromIndex])) DO
      CopyChar(From, FromIndex, FromHigh, To, ToIndex, ToHigh)
   END
END CopyUntilSpace ;


(*
   CopyUntil - copies characters until the UntilChar is found.
*)

PROCEDURE CopyUntil (From: ARRAY OF CHAR;
                     VAR FromIndex: CARDINAL; FromHigh: CARDINAL;
                     VAR To: ARRAY OF CHAR;
                     VAR ToIndex: CARDINAL; ToHigh: CARDINAL;
                     UntilChar: CHAR) ;
BEGIN
   WHILE (FromIndex<FromHigh) AND (ToIndex<ToHigh) AND
         (From[FromIndex]#UntilChar) DO
      CopyChar(From, FromIndex, FromHigh, To, ToIndex, ToHigh)
   END
END CopyUntil ;


(*
   CopyChar - copies a character from string From to string To and
              takes into consideration escape characters. ie \x
              Where x is any character.
*)

PROCEDURE CopyChar (From: ARRAY OF CHAR;
                    VAR FromIndex: CARDINAL; FromHigh: CARDINAL;
                    VAR To: ARRAY OF CHAR;
                    VAR ToIndex: CARDINAL; ToHigh: CARDINAL) ;
BEGIN
   IF (FromIndex<FromHigh) AND (ToIndex<ToHigh)
   THEN
      IF Escape(From[FromIndex])
      THEN
         (* Skip over Escape Character *)
         INC(FromIndex)
      END ;
      IF FromIndex<FromHigh
      THEN
         (* Copy Normal Character *)
         To[ToIndex] := From[FromIndex] ;
         INC(ToIndex) ;
         INC(FromIndex)
      END
   END
END CopyChar ;


(*
   Narg - returns the number of arguments available from
          command line, CmdLine.
*)

PROCEDURE Narg (CmdLine: ARRAY OF CHAR) : CARDINAL ;
VAR
   a    : ARRAY [0..1000] OF CHAR ;
   ArgNo: CARDINAL ;
BEGIN
   ArgNo := 0 ;
   WHILE GetArg(CmdLine, ArgNo, a) DO
      INC( ArgNo )
   END ;
(*
   IF ArgNo>0
   THEN
      DEC(ArgNo)
   END ;
*)
   RETURN( ArgNo )
END Narg ;


PROCEDURE Escape (ch: CHAR) : BOOLEAN ;
BEGIN
   RETURN( ch=esc )
END Escape ;


PROCEDURE Space (ch: CHAR) : BOOLEAN ;
BEGIN
   RETURN( (ch=space) OR (ch=tab) )
END Space ;


PROCEDURE DoubleQuote (ch: CHAR) : BOOLEAN ;
BEGIN
   RETURN( ch=dquote )
END DoubleQuote ;


PROCEDURE SingleQuote (ch: CHAR) : BOOLEAN ;
BEGIN
   RETURN( ch=squote )
END SingleQuote ;


END CmdArgs.