]>
git.saurik.com Git - apt.git/blob - apt-pkg/contrib/cmndline.cc
   1 // -*- mode: cpp; mode: fold -*- 
   3 // $Id: cmndline.cc,v 1.15 2003/02/10 01:40:58 doogie Exp $ 
   4 /* ###################################################################### 
   6    Command Line Class - Sophisticated command line parser 
   8    This source is placed in the Public Domain, do with it what you will 
   9    It was originally written by Jason Gunthorpe <jgg@debian.org>. 
  11    ##################################################################### */ 
  13 // Include files                                                        /*{{{*/ 
  15 #pragma implementation "apt-pkg/cmndline.h" 
  17 #include <apt-pkg/cmndline.h> 
  18 #include <apt-pkg/error.h> 
  19 #include <apt-pkg/strutl.h> 
  25 // CommandLine::CommandLine - Constructor                               /*{{{*/ 
  26 // --------------------------------------------------------------------- 
  28 CommandLine::CommandLine(Args 
*AList
,Configuration 
*Conf
) : ArgList(AList
),  
  29                                  Conf(Conf
), FileList(0) 
  33 // CommandLine::~CommandLine - Destructor                               /*{{{*/ 
  34 // --------------------------------------------------------------------- 
  36 CommandLine::~CommandLine() 
  41 // CommandLine::Parse - Main action member                              /*{{{*/ 
  42 // --------------------------------------------------------------------- 
  44 bool CommandLine::Parse(int argc
,const char **argv
) 
  47    FileList 
= new const char *[argc
]; 
  48    const char **Files 
= FileList
; 
  50    for (I 
= 1; I 
!= argc
; I
++) 
  52       const char *Opt 
= argv
[I
]; 
  54       // It is not an option 
  63       // Double dash signifies the end of option processing 
  64       if (*Opt 
== '-' && Opt
[1] == 0) 
  70       // Single dash is a short option 
  73          // Iterate over each letter 
  76             // Search for the option 
  78             for (A 
= ArgList
; A
->end() == false && A
->ShortOpt 
!= *Opt
; A
++); 
  80                return _error
->Error(_("Command line option '%c' [from %s] is not known."),*Opt
,argv
[I
]); 
  82             if (HandleOpt(I
,argc
,argv
,Opt
,A
) == false) 
  92       // Match up to a = against the list 
  93       const char *OptEnd 
= Opt
; 
  95       for (; *OptEnd 
!= 0 && *OptEnd 
!= '='; OptEnd
++); 
  96       for (A 
= ArgList
; A
->end() == false &&  
  97            stringcasecmp(Opt
,OptEnd
,A
->LongOpt
) != 0; A
++); 
  99       // Failed, look for a word after the first - (no-foo) 
 100       bool PreceedMatch 
= false; 
 101       if (A
->end() == true) 
 103          for (; Opt 
!= OptEnd 
&& *Opt 
!= '-'; Opt
++); 
 106             return _error
->Error(_("Command line option %s is not understood"),argv
[I
]); 
 109          for (A 
= ArgList
; A
->end() == false && 
 110               stringcasecmp(Opt
,OptEnd
,A
->LongOpt
) != 0; A
++); 
 113          if (A
->end() == true && OptEnd 
- Opt 
!= 1) 
 114             return _error
->Error(_("Command line option %s is not understood"),argv
[I
]); 
 116          // The option could be a single letter option prefixed by a no-.. 
 117          if (A
->end() == true) 
 119             for (A 
= ArgList
; A
->end() == false && A
->ShortOpt 
!= *Opt
; A
++); 
 121             if (A
->end() == true) 
 122                return _error
->Error(_("Command line option %s is not understood"),argv
[I
]); 
 125          // The option is not boolean 
 126          if (A
->IsBoolean() == false) 
 127             return _error
->Error(_("Command line option %s is not boolean"),argv
[I
]); 
 133       if (HandleOpt(I
,argc
,argv
,OptEnd
,A
,PreceedMatch
) == false) 
 137    // Copy any remaining file names over 
 138    for (; I 
!= argc
; I
++) 
 145 // CommandLine::HandleOpt - Handle a single option including all flags  /*{{{*/ 
 146 // --------------------------------------------------------------------- 
 147 /* This is a helper function for parser, it looks at a given argument 
 148    and looks for specific patterns in the string, it gets tokanized 
 149    -ruffly- like -*[yes|true|enable]-(o|longopt)[=][ ][argument] */ 
 150 bool CommandLine::HandleOpt(int &I
,int argc
,const char *argv
[], 
 151                             const char *&Opt
,Args 
*A
,bool PreceedMatch
) 
 153    const char *Argument 
= 0; 
 154    bool CertainArg 
= false; 
 157    /* Determine the possible location of an option or 0 if their is 
 159    if (Opt
[1] == 0 || (Opt
[1] == '=' && Opt
[2] == 0)) 
 161       if (I 
+ 1 < argc 
&& argv
[I
+1][0] != '-') 
 162          Argument 
= argv
[I
+1]; 
 164       // Equals was specified but we fell off the end! 
 165       if (Opt
[1] == '=' && Argument 
== 0) 
 166          return _error
->Error(_("Option %s requires an argument."),argv
[I
]); 
 183    // Option is an argument set 
 184    if ((A
->Flags 
& HasArg
) == HasArg
) 
 187          return _error
->Error(_("Option %s requires an argument."),argv
[I
]); 
 191       // Parse a configuration file 
 192       if ((A
->Flags 
& ConfigFile
) == ConfigFile
) 
 193          return ReadConfigFile(*Conf
,Argument
); 
 195       // Arbitary item specification 
 196       if ((A
->Flags 
& ArbItem
) == ArbItem
) 
 199          for (J 
= Argument
; *J 
!= 0 && *J 
!= '='; J
++); 
 201             return _error
->Error(_("Option %s: Configuration item specification must have an =<val>."),argv
[I
]); 
 207                return _error
->Error(_("Option %s: Configuration item specification must have an =<val>."),argv
[I
]); 
 208             Conf
->Set(string(Argument
,J
-Argument
),string(argv
[I
++ +1])); 
 211             Conf
->Set(string(Argument
,J
-Argument
),string(J
+1)); 
 216       const char *I 
= A
->ConfName
; 
 217       for (; *I 
!= 0 && *I 
!= ' '; I
++); 
 219          Conf
->Set(string(A
->ConfName
,0,I
-A
->ConfName
),string(I
+1) + Argument
); 
 221          Conf
->Set(A
->ConfName
,string(I
) + Argument
); 
 226    // Option is an integer level 
 227    if ((A
->Flags 
& IntLevel
) == IntLevel
) 
 229       // There might be an argument 
 233          unsigned long Value 
= strtol(Argument
,&EndPtr
,10); 
 235          // Conversion failed and the argument was specified with an =s 
 236          if (EndPtr 
== Argument 
&& CertainArg 
== true) 
 237             return _error
->Error(_("Option %s requires an integer argument, not '%s'"),argv
[I
],Argument
); 
 239          // Conversion was ok, set the value and return 
 240          if (EndPtr 
!= 0 && EndPtr 
!= Argument 
&& *EndPtr 
== 0) 
 242             Conf
->Set(A
->ConfName
,Value
); 
 249       // Increase the level 
 250       Conf
->Set(A
->ConfName
,Conf
->FindI(A
->ConfName
)+1); 
 254    // Option is a boolean 
 255    int Sense 
= -1;  // -1 is unspecified, 0 is yes 1 is no 
 257    // Look for an argument. 
 260       // Look at preceeding text 
 264          if (PreceedMatch 
== false) 
 267          if (strlen(argv
[I
]) >= sizeof(Buffer
)) 
 268             return _error
->Error(_("Option '%s' is too long"),argv
[I
]); 
 270          // Skip the leading dash 
 271          const char *J 
= argv
[I
]; 
 272          for (; *J 
!= 0 && *J 
== '-'; J
++); 
 274          const char *JEnd 
= J
; 
 275          for (; *JEnd 
!= 0 && *JEnd 
!= '-'; JEnd
++); 
 278             strncpy(Buffer
,J
,JEnd 
- J
); 
 279             Buffer
[JEnd 
- J
] = 0; 
 288       Sense 
= StringToBool(Argument
); 
 292          if (Argument 
!= Buffer
) 
 300       if (CertainArg 
== true) 
 301          return _error
->Error(_("Sense %s is not understood, try true or false."),Argument
); 
 306    // Indeterminate sense depends on the flag 
 309       if ((A
->Flags 
& InvBoolean
) == InvBoolean
) 
 315    Conf
->Set(A
->ConfName
,Sense
); 
 319 // CommandLine::FileSize - Count the number of filenames                /*{{{*/ 
 320 // --------------------------------------------------------------------- 
 322 unsigned int CommandLine::FileSize() const 
 324    unsigned int Count 
= 0; 
 325    for (const char **I 
= FileList
; I 
!= 0 && *I 
!= 0; I
++) 
 330 // CommandLine::DispatchArg - Do something with the first arg           /*{{{*/ 
 331 // --------------------------------------------------------------------- 
 333 bool CommandLine::DispatchArg(Dispatch 
*Map
,bool NoMatch
) 
 336    for (I 
= 0; Map
[I
].Match 
!= 0; I
++) 
 338       if (strcmp(FileList
[0],Map
[I
].Match
) == 0) 
 340          bool Res 
= Map
[I
].Handler(*this); 
 341          if (Res 
== false && _error
->PendingError() == false) 
 342             _error
->Error("Handler silently failed"); 
 348    if (Map
[I
].Match 
== 0) 
 351          _error
->Error(_("Invalid operation %s"),FileList
[0]);