home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 15 / CD_ASCQ_15_070894.iso / maj / swag / cmdline.swg < prev    next >
Text File  |  1994-05-27  |  68KB  |  1 lines

  1. 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                      KENNETH W. FOX           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!  <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...π}π                                              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     !}`r 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 <did>) 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 = '<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ππ}