Unit ParseParametersUnit

DescriptionusesClasses, Interfaces, Objects and RecordsFunctions and ProceduresTypesConstantsVariables

Description

Parsing command-line arguments.

Terminology:

Parameter

Command-line parameters are given directly by the OS to our program. Implementation of this unit obtains them from Parameters.

Option

Options are encoded by the user as parameters. Examples:

Pewne zalety uzywania w ogole funkcji do parsowania parametrow (w rodzaju getopts czy mojego ParseParameters) ponad robieniem parsowania argumentow za kazdym razem recznie w programie:

Nazewnictwo: wszedzie w tym module, w komentarzach i w identyfikatorach (typow, nazw funkcji, stalych... wszystkiego) staram sie konsekwentnie uzywac okreslenia "parametr" na parametr podany w linii polecen przez usera (a dokladniej rzecz biorac, to sa stringi ktore zostaly nam przekazane przez program ktory nas wywolal) oraz "opcja" na jakas regule wedlug ktorej zamierzamy parsowac (czyli po prostu interpretowac, wszelkie dokladniejsze definicje parsera nie maja tu racji bytu) parametry. Np. wywolanie

  view3dscene --camera-radius 0.5 plik.3ds

ma 4 parametry : parametr numer 0 to "view3dscene" (chociaz niekoniecznie, to zalezy od OSa, np. Windows wymusza postac parametru numer 0), potem "--camera-radius", potem "0.5", potem "plik.3ds". Jezeli teraz zasam regule "jest jedna opcja, --camera-radius, i ma ona jeden argument" to mozemy teraz zinterpretowac parametry i otrzymujemy wynik: napotkana jedna opcja --camera-radius, jej argument to 0.5, a poza tym zostaja dwa parametry ktore nie zostaly wlaczone do zadnej opcji :

  view3dscene plik.3ds

Zadaniem interfejsu tego modulu jest przede wszystkim zdefiniowac scisle "czym jest opcja" oraz "jaki jest zwiazek miedzy parametrami a opcjami". Zadaniem implementacji jest przeprowadzic odpowiednia konwersje : wez parametry, wez opcje, wyrzuc wynik (sparsowane paczki "opcja+zwiazane z nia argumenty") usuwajac zinterpretowane parametry z listy parametrow. Takie nazewnictwo jest konsekwentne z getopts i z Pascalowymi ParamStr/Count.

uses

Overview

Classes, Interfaces, Objects and Records

Name Description
Class EInvalidShortOption Niniejsza funkcja stanowi odpowiednik znanych funkcji z rodziny getopts z libc, modulu GetOpts z FPC i innych.
Class EInvalidLongOption  
Class EWrongOptionArgument  
Class EExcessiveOptionArgument  
Class EMissingOptionArgument  
record TOption  
Class TDynArray_2  
record TParsedOption Jeszcze inna wersja ParseParameters, o nieco innym interfejsie
Class TDynArray_1  

Functions and Procedures

procedure ParseParameters( Options: POption_Array; OptionsCount: Integer; OptionProc: TOptionProc; OptionProcData: Pointer; ParseOnlyKnownLongOptions: boolean =false ); overload;
procedure ParseParameters( const Options: array of TOption; OptionProc: TOptionProc; OptionProcData: Pointer; ParseOnlyKnownLongOptions: boolean =false ); overload;
procedure ParseParameters( Options: TDynOptionArray; OptionProc: TOptionProc; OptionProcData: Pointer; ParseOnlyKnownLongOptions: boolean =false ); overload;
function ParseParameters( const Options: array of TOption; ParseOnlyKnownLongOptions: boolean =false ) : TDynParsedOptionArray; overload;
function ParseParameters( Options: POption_Array; OptionsCount: Integer; ParseOnlyKnownLongOptions: boolean =false ) : TDynParsedOptionArray; overload;
function OptionSeparateArgumentToCount(const v: TOptionSeparateArgument): Integer;
function SeparateArgsToVector3Single(const v: TSeparateArgs): TVector3Single;

Types

TOptionArgument = (...);
TOptionArguments = set of TOptionArgument;
TOptionSeparateArgument = oaRequiredSeparateFirst .. oaRequiredSeparateLast;
TSeparateArgs = array[1..RequiredSeparateLastCount]of string;
TOptionProc = procedure (OptionNum: Integer; HasArgument: boolean; const Argument: string; const SeparateArgs: TSeparateArgs; Data: Pointer);
POption = ˆTOption;
TDynArrayItem_2 = TOption;
PDynArrayItem_2 = POption;
TInfiniteArray_2 = array[0..MaxInt div SizeOf(TDynArrayItem_2)-1]of TDynArrayItem_2;
PInfiniteArray_2 = ˆTInfiniteArray_2;
TDynArrayItemIsSmallerFunc_2 = function (const a, b: TDynArrayItem_2): boolean;
TDynArrayItemIsSmallerFuncByObject_2 = function (const a, b: TDynArrayItem_2): boolean of object;
TDynOptionArray = TDynArray_2;
TOption_Array = TInfiniteArray_2;
POption_Array = PInfiniteArray_2;
PParsedOption = ˆTParsedOption;
TDynArrayItem_1 = TParsedOption;
PDynArrayItem_1 = PParsedOption;
TInfiniteArray_1 = array[0..MaxInt div SizeOf(TDynArrayItem_1)-1]of TDynArrayItem_1;
PInfiniteArray_1 = ˆTInfiniteArray_1;
TDynArrayItemIsSmallerFunc_1 = function (const a, b: TDynArrayItem_1): boolean;
TDynArrayItemIsSmallerFuncByObject_1 = function (const a, b: TDynArrayItem_1): boolean of object;
TDynParsedOptionArray = TDynArray_1;

Constants

oaRequiredSeparateFirst = oaRequired2Separate;
oaRequiredSeparateLast = oaRequired9Separate;
RequiredSeparateFirstCount = 2;
RequiredSeparateLastCount = RequiredSeparateFirstCount + Ord(oaRequiredSeparateLast) - Ord(oaRequiredSeparateFirst);
OptionArgumentsRequiredSeparate: TOptionArguments = [oaRequiredSeparateFirst .. oaRequiredSeparateLast];
EmptySeparateArgs: TSeparateArgs = ('','','', '','','', '','','');
OnlyHelpOptions: array[0..1]of TOption = ( (Short: 'h'; Long: 'help'; Argument: oaNone), (Short: #0; Long: ''; Argument: oaNone) );
HelpOptionHelp = ' -h / --help Print this help message and exit';
VersionOptionHelp = ' -v / --version Print the version number and exit';

Description

Functions and Procedures

procedure ParseParameters( Options: POption_Array; OptionsCount: Integer; OptionProc: TOptionProc; OptionProcData: Pointer; ParseOnlyKnownLongOptions: boolean =false ); overload;
 
procedure ParseParameters( const Options: array of TOption; OptionProc: TOptionProc; OptionProcData: Pointer; ParseOnlyKnownLongOptions: boolean =false ); overload;
 
procedure ParseParameters( Options: TDynOptionArray; OptionProc: TOptionProc; OptionProcData: Pointer; ParseOnlyKnownLongOptions: boolean =false ); overload;
 
function ParseParameters( const Options: array of TOption; ParseOnlyKnownLongOptions: boolean =false ) : TDynParsedOptionArray; overload;
 
function ParseParameters( Options: POption_Array; OptionsCount: Integer; ParseOnlyKnownLongOptions: boolean =false ) : TDynParsedOptionArray; overload;
 
function OptionSeparateArgumentToCount(const v: TOptionSeparateArgument): Integer;

some simple helper utilities ———————————————-

function SeparateArgsToVector3Single(const v: TSeparateArgs): TVector3Single;
 

Types

TOptionArgument = (...);
 
Values
  • oaNone: opcja nie moze miec zadnych argumentow
  • oaOptional: opcja moze ale nie musi pobierac argumentu; jezeli user chce podac jej argument, musi uzyc postaci –opcja=argument (lub -o=argument)
  • oaRequired: opcja musi byc podana z argumentem; user moze ja podac jako –opcja=argument (lub -o=argument) (a wiec tak jak oaOptional) lub jako –opcja argument (lub -o argument) (a wiec tak jak podawalby hipotetyczne oaRequired1Separate)
  • oaRequired2Separate: oaRequired3Separate oznacza ze opcje trzeba podac jako –opcja argument1 argument2 argument3 (lub -o argument1 argument2 argument3).

    Jak widac nie ma oaRequired1Separate - bo to nie byloby uzyteczne, mamy oaRequired ktore jest bardziej elastyczne niz byloby hipotetyczne oaRequired1Separate (bo oaRequired pozwala na zapis –opcja=argument).

    Jak widac tez nie mozemy uzyc dowolnej liczby w miejsce ? - to NIE jest ograniczenie wynikajace z zaprojektowania typu TOptionArgument (bo gdybym chcial moglbym zrobic tutaj po prostu oaRequiredSeparate i dodac pole RequiredSeparateArgs: Integer do rekordu TOption), to jest ograniczenie zwiazane z tym ze TParsedOption zawiera tablice SeparateArgs o stalym rozmiarze. Gdyby mozliwe bylo dowolne ? to tablica SeparateArgs musialaby byc dynamiczna a wiec zarzadzanie typem TParsedOption byloby bardziej skomplikowane (w praktyce, uczynilbym go klasa aby zapewnic mu inicjalizacje/ finalizacje). A wydaje mi sie ze ta dodatkowa komplikacja nie jest warta zachodu - - przeciez raczej nie bedzie ci nigdy zalezalo na podaniu jakiejs duzej wartosci dla ? bo wtedy podawanie takiego parametru byloby dla usera arcy-niewygodne.

    W razie potrzeby mozna rozszerzyc ten typ o dodatkowe oaRequired?Separate, dopisujac kolejne oaRequired?Separate za ostatnim oaRequiredSeparateLast i zmieniajac wartosc stalej oaRequiredSeparateLast.

  • oaRequired3Separate:
  • oaRequired4Separate:
  • oaRequired5Separate:
  • oaRequired6Separate:
  • oaRequired7Separate:
  • oaRequired8Separate:
  • oaRequired9Separate:
TOptionArguments = set of TOptionArgument;
 
TOptionSeparateArgument = oaRequiredSeparateFirst .. oaRequiredSeparateLast;
 
TSeparateArgs = array[1..RequiredSeparateLastCount]of string;
 
TOptionProc = procedure (OptionNum: Integer; HasArgument: boolean; const Argument: string; const SeparateArgs: TSeparateArgs; Data: Pointer);

Gdy ta funkcja bedzie wywolywana z funkcji ParseParameters to znaczenie parametrow bedzie nastepujace :

OptionNum = bedzie numer opcji z tablicy Options (zero-based).

HasArgument = false, jesli Options[ParamNum].Argument in [oaNone, oaRequired?Separate] lub (oaOptional i nie podano argumentu). true wpp. (a wiec gdy Options[ParamNum].Argument = oaRequired lub (oaOptional i podano argument).

Argument = jesli HasArgument to jest to argument podany przy opcji, wpp. '' (notka: zwroc uwage ze nic nie przeszkadza userowi podac argument = ''. Dlatego wlasnie potrzebny jest parametr HasArgument zeby opcje oaOptional mogly rozpoznac czy user nie podal argumentu (HasArgument=false) czy tez podal argument rowny '' (HasArgument = true, Argument = '').

SeparateArgs = jezeli Options[ParamNum].Argument in oaRequired?Separate to odpowiednia ilosc poczatkowych SeparateArgs bedzie usatwiona na poczatkowe argumenty, np. dla oaRequired2Separate powinienes odczytac argumenty z SeparateArgs[1] i SeparateArgs[2]. Wszystkie pozostale SeparateArgs (w powyzszym przykladzie, SeparateArgs[3] .. SeparateArgs[High(SeparateArgs)]) beda rowne ''. Jesli Options[ParamNum].Argument nie byl rowny oaRequired?Separate to wszystkie SeparateArgs[] beda rowne '' (czyli SeparateArgs = EmptySeparateArgs).

Data = OptionProcData podane do ParseParameters

POption = ˆTOption;
 
TDynArrayItem_2 = TOption;
 
PDynArrayItem_2 = POption;
 
TInfiniteArray_2 = array[0..MaxInt div SizeOf(TDynArrayItem_2)-1]of TDynArrayItem_2;
 
PInfiniteArray_2 = ˆTInfiniteArray_2;
 
TDynArrayItemIsSmallerFunc_2 = function (const a, b: TDynArrayItem_2): boolean;
 
TDynArrayItemIsSmallerFuncByObject_2 = function (const a, b: TDynArrayItem_2): boolean of object;
 
TDynOptionArray = TDynArray_2;
 
TOption_Array = TInfiniteArray_2;
 
POption_Array = PInfiniteArray_2;
 
PParsedOption = ˆTParsedOption;
 
TDynArrayItem_1 = TParsedOption;
 
PDynArrayItem_1 = PParsedOption;
 
TInfiniteArray_1 = array[0..MaxInt div SizeOf(TDynArrayItem_1)-1]of TDynArrayItem_1;
 
PInfiniteArray_1 = ˆTInfiniteArray_1;
 
TDynArrayItemIsSmallerFunc_1 = function (const a, b: TDynArrayItem_1): boolean;
 
TDynArrayItemIsSmallerFuncByObject_1 = function (const a, b: TDynArrayItem_1): boolean of object;
 
TDynParsedOptionArray = TDynArray_1;
 

Constants

oaRequiredSeparateFirst = oaRequired2Separate;
 
oaRequiredSeparateLast = oaRequired9Separate;
 
RequiredSeparateFirstCount = 2;
 
RequiredSeparateLastCount = RequiredSeparateFirstCount + Ord(oaRequiredSeparateLast) - Ord(oaRequiredSeparateFirst);
 
OptionArgumentsRequiredSeparate: TOptionArguments = [oaRequiredSeparateFirst .. oaRequiredSeparateLast];
 
EmptySeparateArgs: TSeparateArgs = ('','','', '','','', '','','');
 
OnlyHelpOptions: array[0..1]of TOption = ( (Short: 'h'; Long: 'help'; Argument: oaNone), (Short: #0; Long: ''; Argument: oaNone) );
 
HelpOptionHelp = ' -h / --help Print this help message and exit';

dodajemy tutaj dodatkowo pusta opcje tylko po to zeby obejsc bug FPC 1.0.10 pod Windowsem, patrz InfoWriteBug (w fpc.testy/ lub kambi_fpc_bugs/already_fixed/). To bedzie zdjete gdy przejde na FPC 2.0.

VersionOptionHelp = ' -v / --version Print the version number and exit';
 

Generated by PasDoc 0.10.0 on 2008-02-25 00:00:38