home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 8 / CDASC08.ISO / NEWS / 4415 / CMDLINE.SWG < prev    next >
Text File  |  1993-10-07  |  43KB  |  1 lines

  1. 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...π}π