프로그래밍 초보 탈출

Libraries/Delphi Library

[Parser] Command Line Parser

째즈토끼 2022. 6. 22. 22:00

이건 콘솔용 어플리케이션 등에서 실행시 커맨드라인 파라미터 값을 간단히 처리하기 위한 라이브러리다.

먼저 사용법은

{
	C:\>Project1.exe /a /b Name=Jazz
}

FCML := TCommandLineParser.Create(FALSE, FALSE, '=', TRUE);

Name := FCML.GetValue('NAME');

if FCML.Exists('/A') then ...
unit LibCommandLineParser;

interface

uses
  Windows, SysUtils;
  // 사이즈를 줄이기 위해 Classes를 사용하지 않고 만들었다.

type
  TPairString = packed record
     Name  : String;
     Value : String;
     end;

  TCommandLineParserEnumCallback1 = function (const Name, Value: String; Param: Integer) : BOOL; stdcall;
  TCommandLineParserEnumCallback2 = function (const Name, Value: String; Param: Integer) : BOOL of Object; stdcall;

  TCommandLineParser = class
  private
  protected
    FParam : array of TPairString;
    FCaseSensitiveName : Boolean;

    function Search(Name: String): Integer;
  public
    constructor Create(const CaseSensitiveName : Boolean = FALSE;
		       const UpperCaseValue : Boolean = FALSE;
		       const ParamValueDelimiter : String = ':';
		       const DoTrim : Boolean = TRUE);
    constructor CreateEmpty(const CaseSensitiveName : Boolean = FALSE);	// 커맨드 라인을 추가하지 않는다. PushCommandLine으로 넣어라.
    destructor Destroy; override;

    function Count : Integer;
    function Exists(const Param : String) : Boolean;
    function GetValue(const Param : String) : String;

    procedure PushCommandLine(const CL: String;
		       const UpperCaseValue : Boolean = FALSE;
		       const ParamValueDelimiter : String = ':';
		       const DoTrim : Boolean = TRUE);

    // CallBack에서 FALSE를 리턴하면 ENUM 중지.
    procedure Enum(CallBack: TCommandLineParserEnumCallback1; Param: Integer); overload;
    procedure Enum(CallBack: TCommandLineParserEnumCallback2; Param: Integer); overload;
  end;
{ TCommandLineParser }

constructor TCommandLineParser.CreateEmpty(const CaseSensitiveName : Boolean = FALSE);
begin
  FCaseSensitiveName := CaseSensitiveName;
end;

constructor TCommandLineParser.Create(const CaseSensitiveName : Boolean = FALSE;
				      const UpperCaseValue : Boolean = FALSE;
				      const ParamValueDelimiter : String = ':';
				      const DoTrim : Boolean = TRUE);
var
  BUF, NAME  : String;
  I, N, Ln : Integer;
begin
  FCaseSensitiveName := CaseSensitiveName;
  Ln := Length(ParamValueDelimiter);
  I := 1;
  while TRUE do begin
    BUF := ParamStr(I);
    if BUF = '' then Break;

    if Ln > 0 then begin
       N := Pos(ParamValueDelimiter, BUF);
       if N > 0 then begin
	  NAME := Copy(BUF, 1, N-1);
	  Delete(BUF, 1, N-1+Ln);
	  if not CaseSensitiveName	then NAME := UpperCase(NAME);
	  if UpperCaseValue		then BUF  := UpperCase(BUF);
	  end
       else begin
	  if not CaseSensitiveName then BUF := UpperCase(BUF);
	  NAME := BUF;
	  BUF  := '';
	  end;
       end
    else begin
       if not CaseSensitiveName then BUF := UpperCase(BUF);
       NAME := BUF;
       BUF  := '';
       end;

   if DoTrim then begin
      NAME := Trim(NAME);
      BUF  := Trim(BUF);
      end;

   SetLength(FParam, I);
   FParam[I-1].Name  := NAME;
   FParam[I-1].Value := BUF;
   Inc(I);
   end;
end;

destructor TCommandLineParser.Destroy;
var
  I, Ln : Integer;
begin
  Ln := Length(FParam);
  if Ln > 0 then begin
     for I:=0 to Ln-1 do begin
         FParam[I].Name  := '';
         FParam[I].Value := '';
         end;
     SetLength(FParam, 0);
     end;

  inherited;
end;
function TCommandLineParser.Count: Integer;
begin
  RESULT := Length(FParam);
end;

function TCommandLineParser.Search(Name: String) : Integer;
var
  I, Ln : Integer;
begin
  if not FCaseSensitiveName then Name := UpperCase(Name);
  Ln := Length(FParam);
  if Ln > 0 then for I:=0 to Ln-1 do begin
     if FParam[I].Name = Name then begin
	RESULT := I;
	Exit;
	end;
     end;
  RESULT := -1;
end;

procedure TCommandLineParser.Enum(CallBack: TCommandLineParserEnumCallback1; Param: Integer);
var
  I, Ln : Integer;
begin
  Ln := Length(FParam);
  if Ln > 0 then for I:=0 to Ln-1 do begin
     if not CallBack(FParam[I].Name, FParam[I].Value, Param) then Break;
     end;
end;

procedure TCommandLineParser.Enum(CallBack: TCommandLineParserEnumCallback2; Param: Integer);
var
  I, Ln : Integer;
begin
  Ln := Length(FParam);
  if Ln > 0 then for I:=0 to Ln-1 do begin
     if not CallBack(FParam[I].Name, FParam[I].Value, Param) then Break;
     end;
end;

function TCommandLineParser.Exists(const Param: String): Boolean;
begin
  RESULT := Search(Param) > -1;
end;

function TCommandLineParser.GetValue(const Param: String): String;
var
  Index : Integer;
begin
  Index := Search(Param);
  if Index > -1
     then RESULT := FParam[Index].Value
     else RESULT := '';
end;
function __GetParamStr(P: PChar; var Param: string): PChar;
var
  i, Len: Integer;
  Start, S, Q: PChar;
begin
  while True do begin
     while (P[0] <> #0) and (P[0] <= ' ') do P := CharNext(P);
     if (P[0] = '"') and (P[1] = '"') then Inc(P, 2) else Break;
     end;
  Len := 0;
  Start := P;
  while P[0] > ' ' do begin
     if P[0] = '"' then begin
        P := CharNext(P);
        while (P[0] <> #0) and (P[0] <> '"') do begin
           Q := CharNext(P);
           Inc(Len, Q - P);
           P := Q;
           end;
        if P[0] <> #0 then P := CharNext(P);
        end
     else begin
        Q := CharNext(P);
        Inc(Len, Q - P);
        P := Q;
        end;
     end;

  SetLength(Param, Len);

  P := Start;
  S := Pointer(Param);
  i := 0;
  while P[0] > ' ' do begin
     if P[0] = '"' then begin
        P := CharNext(P);
        while (P[0] <> #0) and (P[0] <> '"') do begin
           Q := CharNext(P);
           while P < Q do begin
              S[i] := P^;
              Inc(P);
              Inc(i);
              end;
           end;
        if P[0] <> #0 then P := CharNext(P);
        end
    else begin
        Q := CharNext(P);
        while P < Q do begin
           S[i] := P^;
           Inc(P);
           Inc(i);
           end;
        end;
    end;

  RESULT := P;
end;

function __ParamStr(const CommandLine: String; Index: Integer): string;
var
  P: PChar;
begin
  RESULT := '';
  if Index = 0 then  Exit;	// Error

  P := PChar(CommandLine);
  while TRUE do begin
    P := __GetParamStr(P, RESULT);
    if (Index = 1) or (RESULT = '') then Break;
    Dec(Index);
    end;
end;

procedure TCommandLineParser.PushCommandLine(const CL: String;
		       const UpperCaseValue : Boolean = FALSE;
		       const ParamValueDelimiter : String = ':';
		       const DoTrim : Boolean = TRUE);
var
  BUF, NAME  : String;
  I, N, Ln, Count : Integer;
begin
  Ln := Length(ParamValueDelimiter);
  I := 1;
  Count := Length(FParam);

  while TRUE do begin
    BUF := __ParamStr(CL, I);
    if BUF = '' then Break;

    if Ln > 0 then begin
       N := Pos(ParamValueDelimiter, BUF);
       if N > 0 then begin
	  NAME := Copy(BUF, 1, N-1);
	  Delete(BUF, 1, N-1+Ln);
	  if not FCaseSensitiveName	then NAME := UpperCase(NAME);
	  if UpperCaseValue		then BUF  := UpperCase(BUF);
	  end
       else begin
	  if not FCaseSensitiveName then BUF := UpperCase(BUF);
	  NAME := BUF;
	  BUF  := '';
	  end;
       end
    else begin
       if not FCaseSensitiveName then BUF := UpperCase(BUF);
       NAME := BUF;
       BUF  := '';
       end;

   if DoTrim then begin
      NAME := Trim(NAME);
      BUF  := Trim(BUF);
      end;

    SetLength(FParam, Count+1);
    FParam[Count].Name  := NAME;
    FParam[Count].Value := BUF;
    Inc(Count);
    Inc(I);
    end;
end;

end.

'Libraries > Delphi Library' 카테고리의 다른 글

[Math] Complex Library  (0) 2022.06.22
[Graphics] Bitmap Library  (0) 2022.06.22
[TCP/IP] WOL (Wake On Lan)  (0) 2022.06.21
[System] Firewall Library  (0) 2022.06.17
[System] Registry Library  (0) 2022.06.17