SWAGOLX.EXE (c) 1993 GDSOFT ALL RIGHTS RESERVED 00009 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 {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 {*************************************************************************)π 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! <grin>ππ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...π}π