Output of file : CMDLINE.SWG contained in archive :
ALLSWAGS.ZIP
SWAGOLX.EXE (c) 1993 GDSOFT ALL RIGHTS RESERVED 00012 COMMAND LINE ROUTINES 1 05-28-9313:34ALL SWAG SUPPORT TEAM Get Command line INFO IMPORT 15 !}¹ {ã> This leads me to a question that I've often wondered about, but neverã> Really bothered to ask anyone: why use a delimiter (commonly '/' or '-')ã> preceeding the parameter option?ããHow would you parse the following command tail:ããCOPY XYZZY.PAS V:\/S/P/Oããif it was entered asããCOPY XYZZY.PAS V:\SPOããThe delimiter is there to - yes - delimit the parameter from the Text precedingãit.ãã(and BTW: All the code examples shown here won't take care of this problem,ãsince they don't allow imbedded parameters. Try this one instead:)ã}ããFunction CAPS(S : String) : String; Assembler;ãAsmã PUSH DSã LDS SI,Sã LES DI,@Resultã CLDã LODSBã STOSBã xor CH,CHã MOV CL,ALã JCXZ @OUTã@LOOP: LODSBã CMP AL,'a'ã JB @NEXTã CMP AL,'z'ã JA @NEXTã SUB AL,20hã@NEXT: STOSBã LOOP @LOOPã@OUT: POP DSãend;ããFunction Switch(C : Char) : Boolean;ãVarã CommandTail : ^String;ã P : Word;ããbeginã CommandTail := PTR(PrefixSeg, $0080);ã P := POS('/' + UpCase(C), CAPS(CommandTail^));ã if P = 0 thenã Switch := Falseã ELSEã beginã Switch := True;ã DELETE(CommandTail^, P, 2)ã endãend;ãã{ãThe CAPS routine only converts the 'a' to 'z' range (I have one in my libraryãthat converts all international Characters, but this was a simple one I couldãType in without looking in my library).ããThe Switch Function also has the added benefit that it strips off the switchãfrom the command line after having tested For it. This way, you should Programãyour Programs in the following way:ãã[...]ã}ãbeginã GetSwitchs;ã CopyFile(ParamStr(1),ParamStr(2))ãend.ãã{ãand the switches can then be at ANY place on the command line, and the Programãwill still Function correctly.ã} 2 05-28-9313:34ALL SWAG SUPPORT TEAM Get Command Line IMPORT 5 !}X {There are basically two ways of retrieving the command line. One way is to useãthe ParamStr Variable: ParamStr(1) contains the first paramter, ParamStr(2)ãcontains the second parameter etc. Another way is to fetch the entire commandãline String from your environment. This can be done as follows:ã}ããProgram GetCommandLine;ããTypeãã PCommandLine = ^TCommandLine;ã TCommandLine = String;ããVarãã CommandLine : PCommandLine;ããbeginã CommandLine := Ptr ( PrefixSeg, $80 );ãend.ã 3 05-28-9313:34ALL SWAG SUPPORT TEAM Get Command Line #2 IMPORT 10 !}² {ã In TP there is, of course, ParamCount and ParamStr.ãã The actual command line can be found in the PSP segment, at offsetã $80 (hexadecimal). The Byte at $80 contains the count of Characters,ã including the leading delimiter Character (usually a space).ãã In TP the PSP segment may be accessed using PrefixSeg. Note that TPã omits the carriage-return that normally appends the input Characterã line. This is a problem For Programs that look For it as the end ofã the String.ãã If you're using a non-TP compiler, you'll need to get the PSP segmentã value via a Dos Function $62 call.ãã Here's a simple TP Program to illustrate. Compile it, then invokeã it With some command-line input...ã}ã(*********************************************************************)ãProgram CommandLine; { CL.PAS }ãVarã CharCount, i : Word;ãbeginã CharCount := Mem[PrefixSeg:$80]; { number of input Characters }ã WriteLn('Input Characters: ', CharCount );ã For i := 1 to CharCount DOã Write( CHR( Mem[PrefixSeg:$80+i] ));ã WriteLn;ãend.ã(*********************************************************************)ã 4 05-28-9313:34ALL SWAG SUPPORT TEAM Get Command Line #3 IMPORT 4 !}ù Program CommandLine; { CL.PAS }ãVarã CharCount,ã i :Word;ãbeginã CharCount := Mem[PrefixSeg:$80]; { number of input Characters}ã WriteLn('Input Characters: ', CharCount );ã For i := 1 to CharCount do Write( CHR( Mem[PrefixSeg:$80+i] ));ã WriteLn;ãend.ããããã 5 05-28-9313:34ALL SWAG SUPPORT TEAM Parse Command Line IMPORT 249 !}fü {*************************************************************************)ã Program name: Command parse sub routinesã Author: Kenneth W. Foxã 1449 Maple Rd.ã KintnersVille Pa. 18930ã USAã Date Started : 5 AUG 1992ã Date finished: 10 jan 1993ã date last Rev: 20 JAn 1993ã*************************************************************************ããCommandline args:ã-----------------ãNONEããDescription of Program:ã-----------------------ãset of Procedures to handle all commandline Parameters With or without regardãto Case -- selected by the Boolean Var Nocase -- if True then everrythingãis converted to uppercase prior to testingããall arguments returned from switches are left in whatever Case they wereãentered on the commandline unless ConvertArgsToUpper is set to True.ããIncludes following Procedures:ããProcedure NAME : PURPOSEã------------------------:-------------------------------------------------ã FnameCheck : to validate Program nameã stops people from renanming the Program if you don'tã want them to -- if you don't care then don't callã this routine.ãã DispCmdline : use to display commandline parameters when debuggingãã ConvertArgtoNumber : converts specified arg from a String to a numericã value.ãã CheckHelp : routine to check to see if the Strings designatedã as commandline help Strings are present or not.ã the use of this routine requires the Fileã Helpuser.pas. Additionally this routine checks toã see if the 'info' switch was present -- conveniaetã way to display registration info in share ware..ããã CmdParse : main routine to parse command line-- this Procedureã is called With Various arguments to alter the contentã of the CmdArray data structure.ããããAdditonal mods to be made:ã---------------------------ã1) add subroutine in cmdline parser to capture delimited Strings (such asãthose between quotes)ãã2) add subroutine to check if any items one the commandline besides the validãswitches and such were present --ããto be used For spotting invalid commandline parameters return value shouldãbe Boolean invalid and the paramString(#)...ããNOTES: may run into trouble writing the routine when the delimited StringsãFunction is added.. possible errors include capturing elements of theãdelimited String as invalid args -- will also check For no closing delimiter..ãã3) develop a version of the cmd line parser which Uses a linked list insteadãof a set of Arrays to save the values in -- will save some memory..ãã4) convert the whole Procedure to an itelligent macro which merely requiresãa list of the command args (doesn't use a fixed Array size -- willãdynamically allocate space based on number of arguments specified in theãarg pickup header File. regrettably , some form of header File will needãto be used in order to specify what will be searched For --ãã5) a possible solution is a way to make a mini compiler macro which willãread in the switches to be processed from a File along With definitionsããeventually convert the whole thing into a Unit // overlay .ãããRev History:ã------------ããnotes on errors -- if the switch Strings are not Varying their lengthã when Const SwitchLength is changed, then the $I CmdParse.H File is notãin the correct pathãã remember that the commandArray initialization Procedure is in theãCmdParse.h File and the appropriate adjustments to the qty and values ofãthe switches need to be made there .. if you are experiencing problemsã With the capture of switches, ensure that you ahe init'd you Array valuesãcorrectlyãã added Boolean present field For argdsw Arrayãã9/5/92 -- moved the call to initCmdArray from the calling routine into theã initialization section of cmdparse.pas -- because i forgot to addã it to chkLabel.pas and was going nuts tring to find the error.ã live and learn.ãã9/5/92 -- added the DispCmdline Procedure as a result of the above sessionã of psychosis..ãã9/6/92 -- re organized cmdparse.pas into more subroutines -- made it easierã to follow what was going on.. also added removeable code toã implement a delimited String parser.. this routine will need toã access the commandline directly instead of using the ParamStr()ã(99 min left), (H)elp, More? Function of turbo.ãã9/6/92 -- added the ConvertArgtoNumber routineã **** NOTE ***** "HelpUser" is a Procedure I add to all Programsã which use command line args or otherwise -- I normally use anã $I IncludeFile to implement it.. the Include Staement MUSTã occur BEFORE the include StaTement For CmdParse.pas File.. orã you can delete the reference to the File from the Programãã9/6/92 -- added the standard help codes to the switches Array in cmdParse.Hã ( /? , /h , /H , help , HELP ).ãã9/6/92 -- added FnameCheck to this File-- FnameCheck requires a Constant orã String called "ProgName" containing the name of the MAIN Programã it checks the ParamStr(0) to verify that the Filename of theã Program has not been renamed -- useful For copyright purposes,ã annoying to users.. use at own perilãã9/6/92 -- updated header File to list Procedures avail in cmdparse.pasãã1/8/93 -- added the info switch to and DisplayInfo routines to showã registration / info request address.ãããend desc.ã}ãã{HEADER File For cmdparse.pas -- include in Calling File }ãã{PROGNAME.pas} {<<<<----- Program using this header File }ã{ 20 Jan 1993} {<<<<----- date this File last changed }ã{ Ken Fox } {<<<<----- Person who last updated this File}ãã(*ãUses Dos,Crt;ããConstã VersionNum = 'V1.0 BETA';ã ProgNameStr = 'NEWPROJ.EXE';ã ProgNameShortStr = 'NP.EXE';ã copyRightStr = ProgNameStr+' ' + VersionNum +ã ', Copyright 1992 - 1993, Ken Fox. All Rights Reserved.';ãã DefaultFileName = 'NEWPROJ.DAT';ãã*)ãã{--------------------------------------------------------------------------}ã{ procs Available in CmdParse.H }ã{ Procedure initCmdArray(Var CmdArray : CommandLineArrayType); }ã{ this proc is included in ths File becuase the args to check For are }ã{ part of the calling routine, not the parser itself. note that the excess }ã{ switches are commented out and will there For not compile but it will }ã{ make it easier to add stuff in the future should you so desire }ã{--------------------------------------------------------------------------}ã{ procs Available in CmdParse.Pas }ã{ additional info on the following procs may be found in the cmdparse.Pas }ã{ File in the ....\tp\include directory.. }ã{ }ã{ Procedure DispCmdline; }ã{ }ã{ Procedure CmdParse(Var CmdArray : CommandLineArrayType; }ã{ NoCase, }ã{ ConvertArgsToUpper : Boolean ); }ã{ }ã{ Procedure ConvertArgtoNumber(ArgNum : Integer; }ã{ Var CmdArray : CommandLineArrayType; }ã{ Var ResultNumber: Word); }ã{ }ã{ Procedure FnameCheck(progname , progname2 :pathStr; }ã{ errorlevel : Byte); }ã{ }ã{ Procedure CheckHelp; }ã{ }ã{--------------------------------------------------------------------------}ããConstãSwitchLength = 4; { maxlegth of a switch to be tested for}ãArgLength = 11; { max length of an argument from the commandline}ãDelimLength = 1; { maxlength of delimiter if used}ãSwitchNum = 6; { the number of switches and hence the size of the Array}ã { of switches without arguments }ãArgdSwitchNum = 2; { the number of switches and hence the size of the Array}ã { of switches With arguments }ãDelimNum = 1; { number of args With delimited Strings }ãããTypeãSwitchType = String[Switchlength];ãArgType = String[ArgLength];ãDelimType = String[DelimLength];ããSwitchesType = Recordã Switch : Array[1..SwitchNum] of SwitchType;ã Present : Array[1..switchNum] of Booleanã end;ããSwitchWithArgType = Recordã Switch : Array[1..ArgdSwitchNum] Of SwitchType;ã Arg : Array[1..ArgdSwitchNum] Of ArgType;ã Present : Array[1..ArgdSwitchNum] of Booleanã end;ããSwitchedArgWithEmbeddedSpacesType = Recordã Switch : Array[1..DelimNum] Of SwitchType;ã StartDelim : Array[1..DelimNum] of DelimType;ã Arg : Array[1..DelimNum] Of ArgType;ã endDelim : Array[1..DelimNum] of DelimType;ã Present : Array[1..DelimNum] of Booleanã end;ãããCommandLineArrayType = Recordã Switches : SwitchesType;ã ArgDSw : SwitchWithArgType;ã { DelimSw : SwitchedArgWithEmbeddedSpacesType; }ã NoParams : Boolean {True if nothing on commandline}ã end;ããVarãNoCase,ãConvertArgsToUpperã : Boolean;ããCmdArray : CommandLineArrayType;ããProcedure initCmdArray(Var CmdArray : CommandLineArrayType);ããbeginã {DEFAULT VALUES SET}ã NoCase := True;ã ConvertArgsToUpper := True;ããwith CmdArray doã beginã Switches.Switch[1] := '/?' ; {default help String}ã Switches.Switch[2] := '/h' ; {default help String}ã Switches.Switch[3] := '/H' ; {default help String}ã Switches.Switch[4] := 'HELP' ; {default help String}ã Switches.Switch[5] := 'help' ; {default help String}ã Switches.Switch[6] := 'INFO' {show author contact Info}ãã{ Switches.Switch[6] := ' ' ;} {NOT USED}ã{ Switches.Switch[7] := ' ' ;} {NOT USED}ã{ Switches.Switch[8] := ' ' ;} {NOT USED}ã{ Switches.Switch[9] := ' ' ;} {NOT USED}ã{ Switches.Switch[10] := ' ' ;} {NOT USED}ã{ Switches.Switch[11] := ' ' ;} {NOT USED}ã{ Switches.Switch[12] := ' ' ;} {NOT USED}ãã{ ArgDSw.Switch[1] := '' ;} {not used}ã{ ArgDSw.Switch[2] := '' ;} {not used}ã{ ArgDSw.Switch[3] := '' ;} {NOT USED}ã{ ArgDSw.Switch[4] := '' ;} {NOT USED}ã{ ArgDSw.Switch[5] := '' ;} {NOT USED}ã{ ArgDSw.Switch[6] := '' ;} {NOT USED}ã{ ArgDSw.Switch[7] := '' ;} {NOT USED}ã{ ArgDSw.Switch[8] := '' ;} {NOT USED}ã{ ArgDSw.Switch[9] := '' ;} {NOT USED}ã{ ArgDSw.Switch[10] := '' ;} {NOT USED}ã{ ArgDSw.Switch[11] := '' ;} {NOT USED}ã{ ArgDSw.Switch[12] := '' ;} {NOT USED}ã{ ArgDSw.Switch[13] := '' ;} {NOT USED}ã(*ãWith DelimSw Doã{ Switch[1] := '' ; } {NOT USED}ã{ StartDelim[1] := '' ; } {NOT USED}ã{ endDelim[1] := '' ; } {NOT USED}ã{ Switch[2] := '' ; } {NOT USED}ã{ StartDelim[2] := '' ; } {NOT USED}ã{ endDelim[2] := '' ; } {NOT USED}ãã{ Switch[3] := '' ; } {NOT USED}ã{ StartDelim[3] := '' ; } {NOT USED}ã{ endDelim[3] := '' ; } {NOT USED}ãã{ Switch[4] := '' ; } {NOT USED}ã{ StartDelim[4] := '' ; } {NOT USED}ã{ endDelim[4] := '' ; } {NOT USED}ãã{ Switch[5] := '' ; } {NOT USED}ã{ StartDelim[5] := '' ; } {NOT USED}ã{ endDelim[5] := '' ; } {NOT USED}ãã{ Switch[6] := '' ; } {NOT USED}ã{ StartDelim[6] := '' ; } {NOT USED}ã{ endDelim[6] := '' ; } {NOT USED}ãã{ Switch[7] := '' ; } {NOT USED}ã{ StartDelim[7] := '' ; } {NOT USED}ã{ endDelim[7] := '' ; } {NOT USED}ãã{ Switch[8] := '' ; } {NOT USED}ã{ StartDelim[8] := '' ; } {NOT USED}ã{ endDelim[8] := '' ; } {NOT USED}ãã{ Switch[9] := '' ; } {NOT USED}ã{ StartDelim[9] := '' ; } {NOT USED}ã{ endDelim[9] := '' ; } {NOT USED}ãã{ Switch[10] := '' ; } {NOT USED}ã{ StartDelim[10] := '' ; } {NOT USED}ã{ endDelim[10] := '' ; } {NOT USED}ãã{ Switch[11] := '' ; } {NOT USED}ã{ StartDelim[11] := '' ; } {NOT USED}ã{ endDelim[11] := '' ; } {NOT USED}ã(99 min left), (H)elp, More? ã{ Switch[12] := '' ; } {NOT USED}ã{ StartDelim[12] := '' ; } {NOT USED}ã{ endDelim[12] := '' ; } {NOT USED}ãã{ Switch[13] := '' ; } {NOT USED}ã{ StartDelim[13] := '' ; } {NOT USED}ã{ endDelim[13] := '' ; } {NOT USED}ãã{ Switch[14] := '' ; } {NOT USED}ã{ StartDelim[14] := '' ; } {NOT USED}ã{ endDelim[14] := '' ; } {NOT USED}ãend {with DelimSw }ã*)ãend; {WITH CmdArray}ããend;ããProcedure CmdParse(Var CmdArray : CommandLineArrayType;ã NoCase,ã ConvertArgsToUpper : Boolean );ãã{ Procedure to handle all commandline Parameters With or without regard }ã{to Case -- selected by the Boolean Var Nocase -- if True then everrything}ã{is converted to uppercase prior to testing}ãã{all arguments returned from switches are left in whatever Case they were }ã{entered on the commandline unless ConvertArgsToUpper is set to True.}ããConstã Blank = ' ';ããVarã counter : Integer;ã Blanks : ArgType;ãã{+++++++++++++++++++++++ Private Procedures to CmdParse Main +++++++++++++}ãProcedure ConvertArgsToUpperCase(Var CmdArray:CommandLineArrayType);ãVarã Counter,ã Counter2 : Integer;ãbegin {--------->>>> ConvertArgsToUpperCase <<<<------------}ãã For Counter := 1 to ArgDSwitchNum Doã For Counter2 := 1 to Length(CmdArray.ArgDSw.Arg[counter]) DOã CmdArray.ArgDSw.Arg[counter,Counter2] :=ã UPCASE(CmdArray.ArgDSw.Arg[counter,Counter2] );ããend; {--------->>>> ConvertArgsToUpperCase <<<<------------}ãã{----------------------------------------------------------------------}ãProcedure ConvertSwitchesToUpperCase(Var CmdArray:CommandLineArrayType);ãVarã Counter,ã Counter2 : Integer;ããbegin {--------->>>> ConvertSwitchesToUpperCase <<<<------------}ã For Counter := 1 to SwitchNum Doã beginã For Counter2 := 1 to Length(CmdArray.Switches.Switch[counter]) DOã CmdArray.Switches.Switch[counter,Counter2] :=ã UPCASE(CmdArray.Switches.Switch[counter,Counter2]);ã end;ã For Counter := 1 to ArgDSwitchNum Doã For Counter2 := 1 to Length(CmdArray.ArgDSw.Switch[counter]) DOã CmdArray.ArgDSw.Switch[counter,Counter2] :=ã UPCASE(CmdArray.ArgDSw.Switch[counter,Counter2] );ããend; {--------->>>> ConvertSwitchesToUpperCase <<<<------------}ãã{----------------------------------------------------------------------}ããProcedure InitializeArrays(Var CmdArray:CommandLineArrayType;ã Var Nocase : Boolean );ãVarã Counterã : Integer;ããbegin {--------->>>> InitializeArrays <<<<------------}ãã cmdArray.NoParams := False;ã For Counter := 1 to SwitchNum Doã CmdArray.Switches.present[counter] := False;ã For Counter := 1 to ArgDSwitchNum Doã beginã CmdArray.ArgDSw.present[counter] := False;ã CmdArray.ArgDSw.Arg[counter] := Blanks;ã end;ã if NoCase then {convert all Switches in CmdArray}ã ConvertSwitchesToUpperCase(CmdArray); {to uppercaseif nocase is set to }ã {True}ãend; {--------->>>> InitializeArrays <<<<------------}ã{----------------------------------------------------------------------}ãProcedure ParseNow(Var CmdArray:CommandLineArrayType;ã Var Nocase : Boolean );ãVarãCounter,Counter2,ãStart,ãSwitLen,CurrentArgLen : Integer;ãBlanks : ArgType;ãTestStr : SwitchType;ãWorkStr : String;ããLabelã Next_Parameter;ããbegin {--------->>>> ParseNow <<<<------------}ã {check For switches without args first}ãã For counter := 1 to ParamCount Doã begin {number of Parameters Loop}ã TestStr:= ParamStr(counter);ãã if Nocase Then { covert paramStr(counter) to upper Case if NoCase}ã begin { is set to True}ã WorkStr := TestStr;ã For Counter2 := 1 to SwitchLength DOã TestStr[counter2] := UPCASE((WorkStr[counter2]));ã end;ãã For Counter2 := 1 to SwitchNum Doã begin { Switches without arguments loop }ã SwitLen := Length(CmdArray.Switches.Switch[Counter2]);ã if CmdArray.Switches.Switch[Counter2] =ã Copy(TestStr,1,SwitLen) thenãã beginã CmdArray.Switches.Present[Counter2] := True;ã Goto Next_Parameter;ã end;ã end; { Switches without arguments loop }ãã For counter2 := 1 to ArgDSwitchNum Doã begin { Switches With arguments test loop }ãã SwitLen := Length(CmdArray.ArgDSw.Switch[Counter2]);ã if CmdArray.ArgDSw.Switch[Counter2] =ã Copy(TestStr,1,SwitLen) thenãã beginã CmdArray.ArgDSw.present[Counter2] := True;ã Start := length(CmdArray.ArgDSw.Switch[Counter2]) + 1;ã CurrentArgLen := length(paramStr(counter)) - (start-1);ã CmdArray.ArgDSw.Arg[Counter2] :=ã Copy(ParamStr(Counter),Start,CurrentArgLen);ãã Goto Next_Parameter; {used inplace of an Exit}ã end;ã end; { Switches With arguments test loop }ãã next_parameter:; {used to speed up execution -- Exit doesn't work here}ãã end; {number of Parameters Loop}ããend; {--------->>>> ParseNow <<<<------------}ããProcedure Parsedelimited(Var CmdArray : CommandLineArrayType;ã NoCase,ã ConvertArgsToUpper : Boolean );ãã{this Procedure will bag any String on the commandline With embedded spaces}ã(* and is delimited by Characters such as "" , {}, [], (), <>, ^^, etc ...*)ãããbegin {--------->>>> Parsedelimited <<<<------------}ãend; {--------->>>> Parsedelimited <<<<------------}ã{----------------------------------------------------------------------}ãã{+++++++++++++++++++ end Private Procedures to CmdParse Main +++++++++++++}ãã{==================================== MAIN Procedure ===================}ãbegin {+++++++++>>>> Procedure CmdParse <<<<++++++++++++}ã {Init Arrays}ã For counter := 1 to ArgLength do { the String Blanks needs to be }ã Blanks[Counter] := Blank; { global because most routines }ã { are useing it }ãã InitCmdArray(CmdArray); { this Procedure located in the cmdparse.h File}ã { assigns values to switches, etc.}ãã InitializeArrays(CmdArray,NoCase);ãããã If ParamCount = 0 then { check command line For null String}ã begin { if nullString then set No Params }ã cmdArray.NoParams := True; { and return to the calling routine }ã Exit;ã end;ããã ParseNow(CmdArray, Nocase); { routine parses the commandline }ã { passing through the switches w/o }ã { arguments first. When Delimited }ã { If Not(NoDelimited) then } { switch parsing is added, it will }ã { Parsedelimited(CmdArray,NoCase);} { occur after all other parsing }ã { as a seperate routine to follow }ã { PARSENOW -- additionally -- add }ã { Boolean Value "NoDelimited" to }ã { calling routine and Cmdparse.h }ã { to bypass checking For delimited }ãã if ConvertArgsToUpper thenã ConvertArgsToUpperCase(CmdArray);ãããend; {+++++++++>>>> Procedure CmdParse <<<<++++++++++++}ãã{====================== end CmdParse MAIN Procedure ===================}ãã{ /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\}ã{ Parser Utility routines }ã{ /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\}ããProcedure ConvertArgtoNumber(ArgNum : Integer;ã Var CmdArray : CommandLineArrayType;ã Var ResultNumber: Word);ãVarã code : Integer;ããbegin {----------->>>> ConvertArgtoNumber <<<<---------------}ãã Val(CmdArray.ArgDsw.Arg[ArgNum],ResultNumber,code);ã if code <> 0 thenã beginã WriteLn('Error commandline argument: ',ã CmdArray.ArgDsw.Switch[ArgNum],' ',ã CmdArray.ArgDsw.Arg[ArgNum]);ã Writeln('press enter to continue');ã readln;ã HelpUser; {see notes}ã end;ããend; {----------->>>> ConvertArgtoNumber <<<<---------------}ãã{/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\}ããProcedure FnameCheck(progname, progname2 :pathStr;ã errorlevel : Byte);ãVarãteststr1,teststr2 :pathStr;ããbegin {----------->>>> FnameCheck <<<<---------------}ããteststr1 := copy(paramstr(0),(length(paramstr(0)) - (Length(progname)-1) ),ã Length(progname));ãteststr2 := copy(paramstr(0),(length(paramstr(0)) - (Length(progname2)-1) ),ã Length(progname2));ããif ((teststr1 <> ProgName) and (teststr2 <> ProgName2))ã thenã beginã WriteLn('Unrecoverable Error in ',progname, ', Check FileNAME');ã halt(Errorlevel);ã end;ããend; {----------->>>> FnameCheck <<<<---------------}ãã{/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\}ããProcedure DispCmdline;ã { use For debugging -- displays the command line parameters}ã { readln at end shows screen Until enter is pressed}ãVAr Count : Integer;ãbeginãClrScr;ããFor Count := 1 to SwitchNum doã if CmdArray.Switches.present[count] thenã WriteLn(CmdArray.Switches.Switch[count],' Present');ããFor Count := 1 to ArgdSwitchNum doã if CmdArray.ArgDsw.present[count] thenã beginã WriteLn(CmdArray.ArgDsw.Switch[count],' Present.');ã WriteLn('Value of: ',CmdArray.ArgDsw.Arg[count]);ã end;ããWriteln;ãWrite('press ENTER to continue');ãReadLn;ãHalt(0);ãend;ããProcedure CheckHelp;ãVarã COUNT : Byte;ãbeginã For count := 1 to 5 doã if cmdArray.Switches.Present[Count] thenã helpUser;ãã if cmdArray.Switches.Present[6] thenã displayinfo;ãend;ãã{---------------------------Helpuser --------------------------}ãProcedure HelpUser;ãbeginã ClrScr;ã Writeln (CopyRightStr);ã WriteLn;ã WriteLn('USAGE: ');ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã Writeln;ã Writeln('Press Enter to continue.');ã ReadLn;ã Writeln;ã WriteLn('EXAMPLE:...............................');ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã WriteLn;ã Writeln (CopyRightStr);ã halt(0);ã end;ã{-------------------------------------------------------------------------}ãProcedure DisplayInfo;ã beginã ClrScr;ã Writeln(copyrightStr);ã Writeln;ã Writeln('Ken Fox');ã WriteLn('1449 Maple Rd.');ã Writeln('Kintnersville Pa. 18930');ã WriteLn('215 672-9713 9 - 5 EST');ã Writeln;ã Writeln('Contact on shareware conference on Internet -- KEN FOX');ã Writeln;ã halt(0);ãã end;ã{--------------------------------------------------------------------------}ããthis info is For all of the PASCAL conference people:ããto use the rotuines in this Program you need to do the followingãã{$I path.......\Progname.h}ã{$I Path.......\Helpuser.PAS}ã{$I path.......\CMDPARSE.PAS}ãã progname.H is a copy of the CMDPARSE.H File which contains the specificã settings For the Program you are writing .ãã HELPUSER.PAS is a Program specific help routine which get called byã the routie CHECKHELP in CMDPARSE.PAS if the CheckHelp Procedure isã used in the main Program. crude but effective.ãã CMDPARSE.PAS -- this File contains all of the parsing routines. I keep thisã File in my .....\TP\INCLUDE directory .ãã I set up a sepearte directory below the tp directory For each Programã and copy the Files Helpuser.Pas and cmdparse.h into it thusly eachã copy of these two Files is customized For the give application Whileã the actual parsing routines are kept in the INCLUDED FileS directory.ã there's no need to modify CMDPARSE.PASãã using the parser..ãã 1) in the CMDPARSE.H File there are templates For all of the Arrayã initializations. the switches to search For are manually inserted in toã each Array item. additionally the Array sizes must be set where indicatedã in the CMDPARSE.H File.ã{-------------------------------------------------------------------------}ã THE FOLLOWING ARE THE SETTINGS For Array SIZESã{-------------------------------------------------------------------------}ããConstãSwitchLength = 4; { maxlegth of a switch to be tested for}ãArgLength = 11; { max length of an argument from the commandline}ãDelimLength = 1; { maxlength of delimiter if used}ãSwitchNum = 6; { the number of switches and hence the size of the Array}ã { of switches without arguments }ãArgdSwitchNum = 2; { the number of switches and hence the size of the Array}ã { of switches With arguments }ãDelimNum = 1; { number of args With delimited Strings }ãã{-------------------------------------------------------------------------}ã THE FOLLOWING SHOW HOW to INIT THE Array SEARCH VarIABLES..ã THESE LINES ARE ALL CONTAINED in ---->>>> CMDPARSE.Hã{-------------------------------------------------------------------------}ãã Switches.Switch[1] := '/?' ; {default help String}ã Switches.Switch[2] := '/h' ; {default help String}ã Switches.Switch[3] := '/H' ; {default help String}ã Switches.Switch[4] := 'HELP' ; {default help String}ã Switches.Switch[5] := 'help' ; {default help String}ã Switches.Switch[6] := 'INFO' {show author contact Info}ãã{ Switches.Switch[6] := ' ' ;} {NOT USED}ãã{---------------------------------}ãTHE FOLLOWING ARE For SWITCHES WHICH WILL CAPTURE A VALUE AS WELL ASãTEST For THE PRESENCE of THE ARGUMENTã{---------------------------------}ã{ ArgDSw.Switch[1] := '' ;} {not used}ã{ ArgDSw.Switch[2] := '' ;} {not used}ã{ ArgDSw.Switch[3] := '' ;} {NOT USED}ã{ ArgDSw.Switch[4] := '' ;} {NOT USED}ã{ ArgDSw.Switch[5] := '' ;} {NOT USED}ã{ ArgDSw.Switch[6] := '' ;} {NOT USED}ã{ ArgDSw.Switch[7] := '' ;} {NOT USED}ãã{-------------------------------------------------------------------------}ãã 2) if you intend to use the routines in HELPUSER.PAS or to performãa Filename validation -- there is a template at the beginning of CMDPARSE.Hãwith Certain Constants which must be set.ããUses Dos,Crt;ããConstã VersionNum = 'V1.0 BETA';ã ProgNameStr = 'NEWPROJ.EXE';ã ProgNameShortStr = 'NP.EXE';ã copyRightStr = ProgNameStr+' ' + VersionNum +ã ', Copyright 1992 - 1993, Ken Fox. All Rights Reserved.';ãã DefaultFileName = 'NEWPROJ.DAT';ãã{-------------------------------------------------------------------------}ãã 3) To call the Various routines in the CMDPARSE.PAS File there areãTemplates which you can cut and paste into you Program from CMDPARSE.Hãã{--------------------------------------------------------------------------}ã{ procs Available in CmdParse.Pas }ã{ additional info on the following procs may be found in the cmdparse.Pas }ã{ File in the ....\tp\include directory.. }ã{ }ã{ Procedure DispCmdline; }ã{ }ã{ Procedure CmdParse(Var CmdArray : CommandLineArrayType; }ã{ NoCase, }ã{ ConvertArgsToUpper : Boolean ); }ã{ }ã{ Procedure ConvertArgtoNumber(ArgNum : Integer; }ã{ Var CmdArray : CommandLineArrayType; }ã{ Var ResultNumber: Word); }ã{ }ã{ Procedure FnameCheck(progname , progname2 :pathStr; }ã{ errorlevel : Byte); }ã{ }ã{ Procedure CheckHelp; }ã{ }ã{--------------------------------------------------------------------------}ãã 4) To test whether an ON/OFF switch is present (such as /?) on theãcommandline use the following:ãã if CmdArray.Switches.Present[number] thenã beginã end;ãã 5) to get the argument from a switch .ãã if CmdArray.ArgDsw.Present[number] thenã WhatEverVariable := CmdArray.ArgDsw.Arg[number];ãã 6) the Procedure ConvertArgtoNumber is avail to convert aãString on the command line to a decimal number.. this is only good forãfor whole numbers w/o nnn.0000111 etc.ãããhope this stuff is useful -- there are other notes and comments sprinkledãthroughout so please check those before calling..ããfinally - in the interest traversing the command tail only once the mostãhenious of Programming Constructs -- the Goto statement -- has been used.ãplease forgive me in advance....ããquestions comments and suggestions are welcome..ããsee the address in the CMDPASE.DOC File..ã 6 05-28-9313:34ALL SWAG SUPPORT TEAM Kill Underscore IMPORT 14 !}ó, {ãThis is another BAsm I've written to optimize my Program. Some of theãcomma-delimited fields have the Underscore Character in the place of Spaces. Itãis desirable For them to be replaced For use in my Program.ããBeFore writing this Procedure I was using:ããProcedure Kill_(Var Strng : String);ãRepeatã Subpos := Pos('_',String);ã if subpos > 0ã then Strng[subpos] := ' ';ãUntil Killpos Subpos = 0;ãend;ããThis was getting called approx 250,000 times in my project, and Turbo ProFilerãpractically waved a red flag at me about it!
ããThis is my new Procedure which screams as Compared to the previous routine.ããI am using TP 6.0 Professional.ãã------------- Code Snippet begins --------------ã}ãProcedure KILL_(Var STRNG); Assembler;ã{ This Procedure KILLS Underscores from a String _and MODifIES THE orIGinAL_ }ãAsmã LES DI, STRNGã xor CX, CXã MOV CL, [ES:DI] { Get String Length}ã MOV AL, '_'ã inC DI { Point to FIRST String Char }ã CLDã@Scan_For_underscore_loop:ã SCASBã JE @FOUND_UNDERSCorEã LOOP @SCAN_For_UNDERSCorE_LOOPã JMP @OUTTATHISã@FOUND_UNDERSCorE:ã DEC DIã MOV Byte PTR [ES:DI], ' 'ã inc diã jmp @scan_For_underscore_loopã(92 min left), (H)elp, More? @OUTTATHIS:ãend;ãã{ãDoes anyone more knowledgable in Assembly than I am have any suggestions Forãthis Procedure? I Realize I am working With the original copy of the Stringãwith this Procedure, and modifying it to boot, but I am saving the time to copyãit to/from the stack when I am making the changes. My Program doES take thisãinto account, and ONLY passes Strings to the procedure.ã}ã 7 05-28-9313:34ALL SWAG SUPPORT TEAM Command Position IMPORT 15 !}?ø {ãI have two BAsm Procedures I have written to speed up a Program which scans aãcomma delimited line. My testing has shown 50,000 iterations of thisãFunction to be approx 3 seconds faster than TP's Var := Pos(',',String);ããI am fairly new to Assembly. This Function doES in fact work, but not as fastãas I feel it should. Can anyone see any places I have gone wrong in speed?ãI've avoided copying the String to the stack, by just declaring a PointerãVariable as the Function's input. I'd like to squeeze a couple more secondsãout of it if I could. The Procedures will deal With about 6 megs of data allãon comma delimited lines.ããI suppose I COULD speed it up, by not declaring ANY Variable, and hard-code itãto specifically use the String Variable I am currently passing to it.ã }ããFunction Commapos(Var STRNG) : Byte; Assembler; Asmã LES DI, STRNG { Point ES:DI to beginning of STRNG }ã xor CH, CH { Just in Case anything is in Register CH }ã MOV CL, [ES:DI] { Load String Length into CL }ã MOV AH, CL { Save len to Compute commapos later }ã inC DI { Point to First Char in String }ã MOV AL, ',' { Looking For Comma }ã CLDã@SCANForCOMMALOOP:ã SCASB { Compare [ES:DI] to contents of AL, inc DI, Dec CL}ã JE @FOUND_COMMA { Found a Comma! }ã LOOP @SCANForCOMMALOOP { No Such Luck! }ã MOV AL, 0 { Loop Fell through, no comma exists, set position to 0 }ã JMP @OUTTAHERE { JumpOut of Loop and Exit } @FOUND_COMMA:ã DEC CL { Reduce by one, since DI was advanced past the comma }ã SUB AH, CL { Subtract CL from AH to give the position }ã MOV AL, AH { Put the result into AL to return to Turbo } @OUTTAHERE:ãend;ã 8 05-28-9313:34ALL SWAG SUPPORT TEAM Command parser IMPORT 7 !}Á { Hey David, try this one out. It Uses a little known fact that TPãwill parse the command line each time you call Paramstr(). So byãstuffing a String into the command-line buffer, we can have TP parse itãFor us.ã}ãProgram Parse;ãTypeã String127 = String[127];ã Cmd = ^String127;ããVarã My_String : Cmd;ã Index : Integer;ããbeginã My_String := Ptr(PrefixSeg, $80); {Point it to command line buffer}ã Write('Enter a line of Text (127 caracters Max) ');ã Readln(My_String^);ã For Index := 1 to Paramcount doã Writeln(Paramstr(Index));ãend.ãã{ You can solve the problem of the 127 caracter limit by reading intoãa standard String and splitting it into <127 caracter substrings.ã} 9 05-28-9313:34ALL SWAG SUPPORT TEAM Handling PARAMSTR IMPORT 15 !}Õ {ã> It Word wrapped one line but you get the idea. Is there an easier orã> faster way to do this?ã}ãVarã Num, Code : Integer;ã Par : String;ããFor F := 2 To ParamCount Doã beginã If Pos('/', ParamStr(F)) = 1 Thenã P := Copy(ParamStr(F), 2, 2);ãã If (Pos('A', P) = 1) Or (Pos('a', P) = 1) Thenã beginã Val(Copy(P, 2, 1), Num, Code);ã If Num In [1..5] Thenã ReadString(Num);ã end;ã If (Pos('O',P) = 1) Or (Pos('o',P) = 1) Then Overide := False;ã If (Pos('S',P) = 1) Or (Pos('s',P) = 1) Then Spin := False;ã If (Pos('F',P) = 1) Or (Pos('f',P) = 1) Then ComLine(1,200);ã If (Pos('C',P) = 1) Or (Pos('c',P) = 1) Then ComLine(2,200);ã If (Pos('R',P) = 1) Or (Pos('r',P) = 1) Thenã beginã Val(Copy(P, 2, 1), Num, Code);ã If Num In [0..10] Thenã Comline(3, Num);ã end;ã If (Pos('L',P) = 1) Or (Pos('l',P) = 1) Then ComLine(4,200);ã If (Pos('M',P) = 1) Or (Pos('m',P) = 1) Then ComLine(Random(4)+1,0);ã If (Pos('B',P) = 1) Or (Pos('b',P) = 1) Then DirectVideo := False;ã If (Pos('P',P) = 1) Or (Pos('p',P) = 1) Thenã beginã Val(Copy(P, 2, 1), Num, Code);ã If Num In [0..3] Thenã Comline(5,200+Num);ã end;ã If (Pos('E',P) = 1) Or (Pos('p',P) = 1) Then ReturnLevel := True;ã If (Pos('?',P) = 1) Then Error;ãend;ãã{ãSome Notes:ã I am not sure if it will return a 0 when the it asks For Val(Copy(P, 2, 1),ãNum, Code) and the P Variable isn't R1, R2, R3, etc (when it is just R from aã/R) so you may have to trap that one differently or change the Program so theyãhave to say /R0 instead of /R. I hope you follow the rest of the code and Iãhope it works. I have no idea what your Program is For so I couldn't test itãeither (too lazy am I? I think not... The above wasn't too easy to do!) So Iãhope it works and good luck...ã}ã 10 11-02-9316:39ALL BRIAN PAPE Parsing a String IMPORT 18 !}ÍW {ãFrom: BRIAN PAPEãSubj: Reading from strings (PARSE)ã---------------------------------------------------------------------------ãCan anyone out there tell me how to read a portion of one stringãvariable into another?ããI grabbed this code from one of my batch file utilities. It isn't realãefficient, as it uses COPY and DELETE, but it doesn't have to be, sinceãit is only called once a program. Where I have cfg:cfgrec, just replaceãcfgrec with your own kind of record. }ããtypeã MyRec = recordã r_var : integer;ã end;ã...ãAnyway, the GET function is what parses the /x:xxxx stuff out of aãregular string. The PARSE procedure gets the actual command tailãfrom the PSP and keeps GETting parameters from it until it is empty.ãBTW, the atoi() function I used is merely val() turned into a function.ã----------------------------------ãprocedure parse(var cfg:cfgrec);ãfunction get(var s:string):string;ãvar i,j : byte;slashflag : boolean;ãbeginã i := 1;ã while (s[i] = ' ') and (i<=length(s)) do inc(i);ã slashflag := s[i] in ['-','/'];ã j := succ(i);ã while ((slashflag and not (s[j] in ['-','/'])) orã (not slashflag and not (s[j] = ' '))) andã (j<=length(s)) do inc(j);ã get := copy(s,i,j-i);ã delete(s,1,j-1);ãend; { get }ããvar s:^string;t:string;ãbeginã s := ptr(prefixseg,$80); { DTA from PSP }ã cfg.working_msg := '';ã cfg.error_msg := '';ã cfg.drive := 0;ã cfg.pause_on_error := false;ã cfg.how_many_retries := 1;ã while s^<>'' doã beginã t := get(s^);ã if t[1] in ['-','/'] thenã beginã if length(t)>=2 thenã case upcase(t[2]) ofã 'C':cfg.how_many_retries :=ã atoi(strip(copy(t,4,length(t)-3),' '));ã 'H','?':begin writehelp; halt(0); end;ã 'W':cfg.working_msg := copy(t,4,length(t)-3);ã 'E':cfg.error_msg := copy(t,4,length(t)-3);ã 'P':cfg.pause_on_error := true;ã end; { case }ã end { if }ã elseã cfg.drive := ord(upcase(t[1]))-65;ã end; { while }ãend; { parse }ãã 11 01-27-9411:55ALL JIM WALSH Command Line Unit IMPORT 67 !} unit CmdLin;ã(*ã This unit will process command line flags, (/N -N)ã a) as present or absent (Is_Param)ã b) with an integer (eg. /N54 /X-76) (Param_Int)ã c) with a real number (eg /J-987.65) (Param_Real)ã d) with strings, including delimited strings with embedded spacesã ( eg. /X"This is the story!" /YFred)ãã Routines are included to count and return the parameters thatã aren't flags (Non_Flag_Count), and to return them withoutã counting the flag parameters (Non_Flag_Param).ãã So ( /X76 Filename.txt /N"My name is Fred." George ) would countã two non-flag params, #1 = filename.txt and #2 = george.ãã This is completely public domain, all I want in return for your useã is appreciation. If you improve this unit, please let me know.ã Some possible improvements would be to allow embedded strings inã non-flag parameters. I haven't done this because I haven't neededã it.ããã Jim Walsh CIS:72571,173ãã*)ããINTERFACEãã function Is_Param(flag:Char) : Boolean;ã { Responds yes if the flag (ie N) is found in the command line (ie /N or -N) }ãã function Param_Int(flag:Char) : LongInt;ã { Returns the integer value after the parameter, ie -M100, or -M-123 }ãã function Param_Real(flag:Char) : Real;ã { Returns the Real value after the parameter, ie -X654.87, or -x-3.14159 }ãã function Param_Text(flag:Char) : String;ã { Returns the string after the parameter, ie -MHello -> 'Hello', }ã { -m"This is it, baby" -> 'This is it, baby', valid string delims='' "" [] }ãã function Non_Flag_Param(index:integer) : string;ã { Returns the indexth parameter, not preceded with a flag delimeter }ã { /X Text.txt /Y876.76 /G"Yes sir!" MeisterBrau /? }ã { For this command line 'Text.txt' is Non Flag Param #1, }ã { and 'MeisterBrau is #2. }ã { NB: Delimeted Non flag parameters (eg "Meister Brau") }ã { not currently supported. }ãã function Non_Flag_Count : integer;ã { Returns the number of non-flag type parameters }ãããIMPLEMENTATIONãconstã flag_delims : Set of Char = ['/','-'];ã no_of_string_delims = 3;ãtypeã string_delim_type = Array[1..3] of recordã start, stop : charã end;ãconstã string_delims : string_delim_type = ((start:#39; stop:#39),ã (start:#34; stop:#34),ã (start:'['; stop:']'));ãããfunction LowerCaseChar(c:char):char;ãbeginã if (c>='A') and (c<='Z') Then LowerCaseChar:=Char(Ord(c)+$20)ã Else LowerCaseChar:=c;ãend;ããã{----------------------------------------------------------------------------}ã function WhereFlagOccurs(flag:Char) : integer;ã { returns the index number of the paramter where the flag occurs }ã { if the flag is never found, it returns 0 }ã varã ti1 : integer;ã finished : boolean;ã paramcnt : integer;ã ts1 : string;ã beginã flag:=LowerCaseChar(flag);ã finished:=false;ã ti1:=1;ã paramcnt:=ParamCount;ã While Not(finished) Do beginã If ti1>paramcnt Then beginã finished:=true;ã ti1:=0;ã end Else beginã ts1:=ParamStr(ti1);ã If (ts1[1] In flag_delims) AND (LowerCaseChar(ts1[2])=flag) Then finished:=true;ã end;ã If Not(finished) Then Inc(ti1);ã end; {While}ã WhereFlagOccurs:=ti1;ã end;ãã{----------------------------------------------------------------------------}ã function Is_Param(flag:Char) : Boolean;ã beginã If WhereFlagOccurs(flag)=0 Then Is_Param:=false Else Is_Param:=true;ã end;ãã{----------------------------------------------------------------------------}ã function Param_Int(flag:Char) : LongInt;ã varã param_loc : integer;ã result : longint;ã ts1 : string;ã ti1 : integer;ã beginã param_loc:=WhereFlagOccurs(flag);ã If param_loc=0 Then result:=0ã Else beginã ts1:=ParamStr(param_loc); { Get the string }ã ts1:=Copy(ts1,3,255); { Get rid of the delim and the flag }ã Val(ts1,result,ti1); { Make the value }ã If ti1<>0 Then result:=0; { Make sure there is no error }ã end; {If/Else}ã Param_Int:=resultã end;ãã{----------------------------------------------------------------------------}ã function Param_Real(flag:Char) : Real;ã varã param_loc : integer;ã result : real;ã ts1 : string;ã ti1 : integer;ã beginã param_loc:=WhereFlagOccurs(flag);ã If param_loc=0 Then result:=0.0ã Else beginã ts1:=ParamStr(param_loc); { Get the string }ã ts1:=Copy(ts1,3,255); { Get rid of the delim and the flag }ã Val(ts1,result,ti1); { Make the value }ã If ti1<>0 Then result:=0.0; { Make sure there is no error }ã end; {If/Else}ã Param_Real:=result;ã end;ãã{----------------------------------------------------------------------}ã function Which_String_Delim(S:string) : byte;ã { Returns the index of the strings first character in the arrayã of string_delims, if the first char of S isn't a delim it returns 0 }ã varã tc1 : char;ã tb1 : byte;ã finished : boolean;ã result : byte;ã beginã tc1:=S[1];ã tb1:=1;ã finished:=false;ã While Not(finished) Do beginã If tb1>no_of_string_delims Then beginã result:=0;ã finished:=true;ã end Else beginã If tc1=string_delims[tb1].start Then beginã result:=tb1;ã finished:=true;ã end;ã end;ã If Not(finished) Then Inc(tb1);ã end; {While}ã Which_String_Delim:=result;ã end; {function Which_String}ãã{-------------------------------------------------------------------------}ã function Param_Text(flag:Char) : String;ã varã param_loc : integer;ã param_cnt : integer;ã result : string;ã ts1 : string;ã ti1 : integer;ã s_delim : byte; { This should be 0(no string), 1', 2", 3[ }ã finished : boolean;ã beginã param_loc:=WhereFlagOccurs(flag);ã If param_loc=0 Then result:=''ã Else beginã ts1:=ParamStr(param_loc); { Get the string }ã ts1:=Copy(ts1,3,255); { Get rid of the delim and the flag }ã { See if the first char of ts1 is one of the string_delims }ã s_delim:=Which_String_Delim(ts1);ã If s_delim=0 Then result:=ts1ã Else beginã result:=Copy(ts1,2,255); { Drop the s_delim }ã finished:=false;ã param_cnt:=ParamCount;ã While Not(finished) Do beginã Inc(param_loc);ã If param_loc>param_cnt Then finished:=trueã Else beginã ts1:=ParamStr(param_loc);ã If ts1[Length(ts1)]=string_delims[s_delim].stop Then finished:=true;ã result:=result+' '+ts1;ã end; { If/Else }ã end; { While }ã result[0]:=Char(Length(result)-1); { Drop the last delimeter }ã end; { If/Else a delimited string }ã end; { If/Else the flag is found }ã Param_Text:=result;ã end;ãã{---------------------------------------------------------------------------}ã function Non_Flag_Param(index:integer) : string;ã varã param_cnt : integer;ã ti1 : integer;ã ts1 : string;ã finished : boolean;ã cur_index : integer;ã beginã param_cnt:=ParamCount;ã cur_index:=0;ã ti1:=0;ã finished:=false;ã While Not(finished) Do beginã Inc(ti1);ã IF cur_index>param_cnt Then beginã ts1:='';ã finished:=true;ã end Else beginã ts1:=ParamStr(ti1);ã If Not(ts1[1] IN flag_delims) Then beginã Inc(cur_index);ã If cur_index=index Then finished:=true;ã end;ã end; {If/Else}ã end; {While}ã Non_Flag_Param:=ts1;ã end;ãã{---------------------------------------------------------------------------}ã function Non_Flag_Count : integer;ã varã param_cnt : integer;ã result : integer;ã ti1 : integer;ã ts1 : string;ã beginã param_cnt:=ParamCount;ã result:=0;ã ti1:=0;ã For ti1:=1 To param_cnt Do beginã ts1:=ParamStr(ti1);ã If Not(ts1[1] IN flag_delims) Then beginã Inc(result);ã end;ã end; {For}ã Non_Flag_Count:=result;ã end;ãããããEND.ã 12 01-27-9411:55ALL LEE CRITES Command Line Unit 2 IMPORT 113 !} {ãThis unit will allow you to access the original command line as it wasãoriginally entered by the user. Here is the source code for the CmdLineãobject. It was developed by Computer Mavericks, using information gleenedãfrom the info-pascal internet forum. In the spirit of the forum, this isãoffered into the public domain. If you use it, think kind thoughs of LeeãCrites and the small staff here at CM.ããThis was written using Borland Pascal 7.0's BPW in Real Mode. (after all,ãyou'll probably not have to many command line parameters to check if youãare working in Windows or OS2, right??? It requires the STRINGS unit thatãcomes with BP7. If you are working in TP6/TP5.5, and don't have access toãthis, we do (should I say ) have a unit for doing null terminatedãstrings for each of those releases that we might be able to send out. AsãI remember, we took the BPW 1.0 Strings unit and played around with itãuntil it compiled in TP6, so I don't know which version that I still haveãaccess to (it's been a while since I looked at our last tp6 archives).ããI threw this together over the weekend, and tested it using the whoamiãprogram and test.bat file. There might still be a problem floating aroundãin there somewhere. This is about the first time that I've really sentãout some source code like this, and really haven't gone through it with aãfine tooth comb. If there are bugs or (more importantly) imporvementsãthat some of you can see, please let me know.ã}ãã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ã{ =-=-=-=-= =-=-=-=-= }ã{ =-= =-= }ã{ CMDLINE.PAS }ã{ This unit contains the following: }ã{ -- CMDLINE, a mute object that will parse the physical command }ã{ line as input by the user, and return the information that was }ã{ requested. }ã{ =-= =-= }ã{ =-=-=-=-= =-=-=-=-= }ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ã{$D-} { debugging information off }ã{$X+} { allow extended syntax }ã{$V+} { require same var type }ã{$R-} { range checking off }ã{$E+} { Add 8087 software emulation code }ã{$N+} { Use the 8087 software emulation code }ã{$I-} { Enable IOResult for I/O checking }ã{$B-} { Short-cut boolean evauation }ã{$O+} { Allow this to be a part of an overlay }ãUnit CmdLine;ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãInterfaceãUses Strings; { Strings is a BP7 unit. I have a TP6 version available }ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãTypeã TCmdLine = Objectã Constructor Init;ã Destructor Done; Virtual;ã { this will return the information requested -- the whole reason }ã { for doing this in the first place. It will return TRUE if the }ã { ParmStrIn was found, otherwise false. This way you can check for }ã { switches entered with no data, since StrBack would otherwise be }ã { null. }ã Function GetParameter(ParmStrIn:String;Var StrBack:String):Boolean;ã Function GetCommandLine:String; { the entire line }ã Function GetActualProgram:String; { the actual name entered }ã Function GetCallingProgram:String; { the fully qulaified name }ã Function GetLaunchingProgram:String; { what environment called me }ã Procedure Trim; { remove leading, trailing, multiple spaces }ã Procedure Capitalize; { just what it sounds like }ã Procedure Restore; { restores the original version }ã Function GetDivideChars:String; { returns the dividing chars }ã Procedure SetDivideChars(NewDivideChars:String); { sets them }ãã Privateã DivideChars:String; { the chars that signal a new parm }ã CommandLine,OriginalCommandLine:String; { just what the name says }ã LaunchingProgram,CallingProgram,ActualProgram:String;ã End; { TCmdLine }ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãVarã CommandLine:TCmdLine;ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ã{PAGE}ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ããã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãImplementationã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ããã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãConstã NONE = '';ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ããã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãProcedure MakeCaps(Var ss:String);ãVar xx,ll:Byte;ãBeginã ll := Length(ss);ã For xx := 1 to ll Do ss[xx] := UpCase(ss[xx]);ãEnd; { MakeCaps }ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ããã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãProcedure TrimString(Var ss:String);ãVar xx:Integer;ãBeginã If (length(ss) < 1) Then exit;ã { remove leading spaces }ã While (ss[1] = chr(32)) Do Begin delete(ss,1,1);ã If (length(ss) < 1) Then exit; End;ã { remove trailing spaces }ã While (ss[length(ss)] = chr(32)) Do Delete(ss,length(ss),1);ã { remove imbedded spaces }ã xx := pos(' ',ss);ã While (xx <> 0) Do Begin Delete(ss,xx,1); xx := Pos(' ',ss); End;ãEnd; { TrimString }ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ããã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãProcedure TCmdLine.Capitalize;ãBeginã MakeCaps(CommandLine);ãEnd; { Capitalize }ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ããã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãDestructor TCmdLine.Done; { I'm not sure what can/should be done here }ãBeginãEnd; { CmdLine }ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ããã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãFunction TCmdLine.GetActualProgram:String;ãBeginã GetActualProgram := ActualProgram;ãEnd; { GetActualProgram }ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ããã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãFunction TCmdLine.GetCallingProgram:String;ãBeginã GetCallingProgram := CallingProgram;ãEnd; { GetCallingProgram }ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ããã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãFunction TCmdLine.GetCommandLine:String;ãBeginã GetCommandLine := CommandLine;ãEnd; { GetCommandLine }ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ããã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãFunction TCmdLine.GetDivideChars:String;ãBeginã GetDivideChars := DivideChars;ãEnd; { GetDivideChars }ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ããã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãFunction TCmdLine.GetLaunchingProgram:String;ãBeginã GetLaunchingProgram := LaunchingProgram;ãEnd; { GetLaunchingProgram }ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ããã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãFunction TCmdLine.GetParameter(ParmStrIn:String;Var StrBack:String):Boolean;ãConst AM:Char = Chr(254);ãVar ss,PrmStr:String; ssLen,ParmLen:Integer;ã { =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ã Procedure SkipQuote(Var xx:Integer;WhichQuote:Char);ã Beginã Inc(xx);ã While (xx <= ssLen) Do Beginã If (ss[xx] = WhichQuote) Then Exit;ã Inc(xx);ã End;ã End; { SkipQuote }ã { =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ã Procedure Setup;ã Var xx,ll:Integer;ã Beginã ss := CommandLine; MakeCaps(ss);ã PrmStr := ParmStrIn; MakeCaps(PrmStr);ã ssLen := Length(ss); ParmLen := Length(PrmStr);ã { change all dividechars into AMs }ã xx := 0;ã While (xx <= ssLen) Do Beginã Inc(xx);ã Case ss[xx] Ofã '''','"','`': SkipQuote(xx,ss[xx]);ã Else If (Pos(ss[xx],DivideChars) > 0) Then ss[xx] := AM;ã End; { case }ã End; { while }ã End; { Setup }ã { =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ã Function IsThisIt(Var Start:Integer):Boolean;ã Var xx:Integer;ã Beginã IsThisIt := False;ã For xx := 1 to ParmLen Do Beginã If (ss[Start+xx] <> PrmStr[xx]) Then Exit;ã End; { yy }ã Start := Start+ParmLen;ã IsThisIt := True;ã End; { IsThisIt }ã { =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ã Function FindIt:Boolean;ã Var xx,yy,l1:Integer;ã Beginã FindIt := False; StrBack := '';ã l1 := ssLen - ParmLen; If (l1 < 1) Then Exit;ã xx := 0;ã While (xx <= l1) Do Beginã Inc(xx);ã If (ss[xx] = AM) Then Beginã If IsThisIt(xx) Then Beginã FindIt := True; yy := 0;ã { find the next AM, and copy the string out }ã While (xx+yy <= ssLen) And (ss[xx+yy] <> AM) Do Inc(yy);ã StrBack := Copy(CommandLine,xx+1,yy-1);ã { delete trailing space(s), if there }ã While (StrBack[Length(StrBack)] = ' ') Doã Delete(StrBack,Length(StrBack),1);ã { we've got the answer, get out }ã Exit;ã End; { this is it }ã End; { found }ã End; { xx }ã End; { FindIt }ã { =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãBeginã { default to not found }ã GetParameter := False; StrBack := '';ã If (Length(CommandLine) < 1) or (CommandLine = NONE) Then Exit;ã If (Length(ParmStrIn) < 1) Then Exit;ãã Setup; GetParameter := FindIt;ãEnd; { GetParameter }ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ããã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãConstructor TCmdLine.Init;ã { =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ã Function LaunchedBy:String;ã Var ParentSeg:^word; p:pchar;ã Beginã ParentSeg := ptr(PrefixSeg,$0016); p := ptr(ParentSeg^-1,8);ã LaunchedBy := StrPas(p);ã End; { LaunchedBy }ã { =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ã Function RealCommandLine:String;ã Var ss:String;ã Beginã ss := StrPas(ptr(PrefixSeg,130));ã If (Ord(ss[0]) > 0) Then ss[0] := Chr(Ord(ss[0])-1);ã RealCommandLine := ss;ã End; { RealCommandLine }ã { =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ã Function ActualProgramName:String;ã Var cc:Char; ss:String; p:PChar; xx,yy:Byte;ã Beginã p := ptr(PrefixSeg,228); ss := ''; xx := 0; yy := 0;ã Repeatã cc := p[xx];ã If (cc <> #0)ã Then Beginã If (Ord(cc) > 47) and (Ord(cc) < 126) Then Beginã ss := ss+' '; ss[Ord(ss[0])] := p[xx]; End;ã Endã Else Begin Inc(yy); If (yy = 1) Then ss := ss+'.'; End;ã Inc(xx);ã Until (xx > 12) or (yy > 1);ã If (ss[Ord(ss[0])] = '.') Then ss[0] := Chr(Ord(ss[0])-1);ã ActualProgramName := ss;ã End; { ActualProgramName }ã { -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãBeginã LaunchingProgram := LaunchedBy; { what environment launched me }ã OriginalCommandLine := RealCommandLine; { the original command line }ã If (Length(OriginalCommandLine) < 1) Then OriginalCommandLine := NONE;ã CommandLine := OriginalCommandLine; { default to exact }ã CallingProgram := ActualProgramName; { just what the user entered }ã ActualProgram := ParamStr(0); { BP returns the fully qualitied name }ãã SetDivideChars('-/'); { set the default DivideChars }ãEnd; { Init }ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ããã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãProcedure TCmdLine.Restore;ãBeginã CommandLine := OriginalCommandLine;ãEnd; { Restore }ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ããã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãProcedure TCmdLine.SetDivideChars(NewDivideChars:String);ãBeginã DivideChars := NewDivideChars;ãEnd; { SetDivideChars }ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ããã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãProcedure TCmdLine.Trim;ãBeginã TrimString(CommandLine);ãEnd; { Trim }ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ããã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãBegin { main block }ã CommandLine.Init;ãEnd. { main block }ã{ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= }ãããã{ This is a test program showing some of the cmdline object functions }ãProgram whoami;ãUses DOS, CRT, CmdLine;ãVar ss:String;ãbeginã { show some general information that it returns }ã WriteLn('I was launched by [',CommandLine.GetLaunchingProgram,']');ã WriteLn('Program executed was [',CommandLine.GetCallingProgram,']');ã WriteLn('BP returnd [',CommandLine.GetActualProgram,']');ã WriteLn('Command line was [',CommandLine.GetCommandLine,']');ãã { these will change the part that you can use }ã CommandLine.Capitalize; CommandLine.Trim;ã WriteLn('Fixed command line [',CommandLine.GetCommandLine,']');ãã { this will return it to it's original value }ã CommandLine.Restore;ã WriteLn('Restored command line [',CommandLine.GetCommandLine,']');ãã { check for the existance of some parameter }ã If CommandLine.GetParameter('s',ss)ã Then WriteLn('Parameter "s" was [',ss,']')ã Else WriteLn('Parameter "s" was not found');ã If CommandLine.GetParameter('ss',ss)ã Then WriteLn('Parameter "ss" was [',ss,']')ã Else WriteLn('Parameter "ss" was not found');ãend.ãã{ã------------------------------ test.bat ------------------------------ã@Echo Offãwhoami /a:france/b 'this-is "the" way' /chest /store /leftãwhoami /aaa-bbb/s"this 'is'-it" /sssãwhoami -ss/shellãã}
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/