diff options
Diffstat (limited to 'apt-pkg/contrib')
-rw-r--r-- | apt-pkg/contrib/cmndline.cc | 280 | ||||
-rw-r--r-- | apt-pkg/contrib/cmndline.h | 91 | ||||
-rw-r--r-- | apt-pkg/contrib/configuration.cc | 231 | ||||
-rw-r--r-- | apt-pkg/contrib/configuration.h | 13 | ||||
-rw-r--r-- | apt-pkg/contrib/strutl.cc | 45 | ||||
-rw-r--r-- | apt-pkg/contrib/strutl.h | 3 |
6 files changed, 656 insertions, 7 deletions
diff --git a/apt-pkg/contrib/cmndline.cc b/apt-pkg/contrib/cmndline.cc new file mode 100644 index 00000000..6b36325c --- /dev/null +++ b/apt-pkg/contrib/cmndline.cc @@ -0,0 +1,280 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: cmndline.cc,v 1.1 1998/09/22 05:30:26 jgg Exp $ +/* ###################################################################### + + Command Line Class - Sophisticated command line parser + + ##################################################################### */ + /*}}}*/ +// Include files /*{{{*/ +#ifdef __GNUG__ +#pragma implementation "apt-pkg/cmndline.h" +#endif +#include <apt-pkg/cmndline.h> +#include <apt-pkg/error.h> +#include <strutl.h> + /*}}}*/ + +// CommandLine::CommandLine - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +CommandLine::CommandLine(Args *AList,Configuration *Conf) : ArgList(AList), + Conf(Conf), FileList(0) +{ +} + /*}}}*/ +// CommandLine::Parse - Main action member /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool CommandLine::Parse(int argc,const char **argv) +{ + FileList = new const char *[argc]; + const char **Files = FileList; + int I; + for (I = 1; I != argc; I++) + { + const char *Opt = argv[I]; + + // It is not an option + if (*Opt != '-') + { + *Files++ = Opt; + continue; + } + + Opt++; + + // Double dash signifies the end of option processing + if (*Opt == '-' && Opt[1] == 0) + break; + + // Single dash is a short option + if (*Opt != '-') + { + // Iterate over each letter + while (*Opt != 0) + { + // Search for the option + Args *A; + for (A = ArgList; A->end() == false && A->ShortOpt != *Opt; A++); + if (A->end() == true) + return _error->Error("Command line option '%c' [from %s] is not known.",*Opt,argv[I]); + + if (HandleOpt(I,argc,argv,Opt,A) == false) + return false; + if (*Opt != 0) + Opt++; + } + continue; + } + + Opt++; + + // Match up to a = against the list + const char *OptEnd = Opt; + Args *A; + for (; *OptEnd != 0 && *OptEnd != '='; OptEnd++); + for (A = ArgList; A->end() == false && + stringcasecmp(Opt,OptEnd,A->LongOpt) != 0; A++); + + // Failed, look for a word after the first - (no-foo) + if (A->end() == true) + { + for (; Opt != OptEnd && *Opt != '-'; Opt++); + + if (Opt == OptEnd) + return _error->Error("Command line option %s is not understood",argv[I]); + Opt++; + + for (A = ArgList; A->end() == false && + stringcasecmp(Opt,OptEnd,A->LongOpt) != 0; A++); + + // Failed again.. + if (A->end() == true && OptEnd - Opt != 1) + return _error->Error("Command line option %s is not understood",argv[I]); + + // The option could be a single letter option prefixed by a no-.. + for (A = ArgList; A->end() == false && A->ShortOpt != *Opt; A++); + + if (A->end() == true) + return _error->Error("Command line option %s is not understood",argv[I]); + } + + // Deal with it. + OptEnd--; + if (HandleOpt(I,argc,argv,OptEnd,A) == false) + return false; + } + + // Copy any remaining file names over + for (; I != argc; I++) + *Files++ = argv[I]; + *Files = 0; + + return true; +} + /*}}}*/ +// CommandLine::HandleOpt - Handle a single option including all flags /*{{{*/ +// --------------------------------------------------------------------- +/* This is a helper function for parser, it looks at a given argument + and looks for specific patterns in the string, it gets tokanized + -ruffly- like -*[yes|true|enable]-(o|longopt)[=][ ][argument] */ +bool CommandLine::HandleOpt(int &I,int argc,const char *argv[], + const char *&Opt,Args *A) +{ + const char *Argument = 0; + bool CertainArg = false; + int IncI = 0; + + /* Determine the possible location of an option or 0 if their is + no option */ + if (Opt[1] == 0 || (Opt[1] == '=' && Opt[2] == 0)) + { + if (I + 1 < argc && argv[I+1][0] != '-') + Argument = argv[I+1]; + + // Equals was specified but we fell off the end! + if (Opt[1] == '=' && Argument == 0) + return _error->Error("Option %s requires an argument.",argv[I]); + if (Opt[1] == '=') + CertainArg = true; + + IncI = 1; + } + else + { + if (Opt[1] == '=') + { + CertainArg = true; + Argument = Opt + 2; + } + else + Argument = Opt + 1; + } + + // Option is an argument set + if ((A->Flags & HasArg) == HasArg) + { + if (Argument == 0) + return _error->Error("Option %s requires an argument.",argv[I]); + Opt += strlen(Opt); + I += IncI; + + // Parse a configuration file + if ((A->Flags & ConfigFile) == ConfigFile) + return ReadConfigFile(*Conf,Argument); + + Conf->Set(A->ConfName,Argument); + return true; + } + + // Option is an integer level + if ((A->Flags & IntLevel) == IntLevel) + { + // There might be an argument + if (Argument != 0) + { + char *EndPtr; + unsigned long Value = strtol(Argument,&EndPtr,10); + + // Conversion failed and the argument was specified with an =s + if (EndPtr == Argument && CertainArg == true) + return _error->Error("Option %s requires an integer argument, not '%s'",argv[I],Argument); + + // Conversion was ok, set the value and return + if (EndPtr != Argument) + { + Conf->Set(A->ConfName,Value); + Opt += strlen(Opt); + I += IncI; + return true; + } + } + + // Increase the level + Conf->Set(A->ConfName,Conf->FindI(A->ConfName)+1); + return true; + } + + // Option is a boolean + int Sense = -1; // -1 is unspecified, 0 is yes 1 is no + + // Look for an argument. + while (1) + { + // Look at preceeding text + char Buffer[300]; + if (Argument == 0) + { + if (strlen(argv[I]) >= sizeof(Buffer)) + return _error->Error("Option '%s' is too long",argv[I]); + + const char *J = argv[I]; + for (; *J != 0 && *J == '-'; J++); + const char *JEnd = J; + for (; *JEnd != 0 && *JEnd != '-'; JEnd++); + if (*JEnd != 0) + { + strncpy(Buffer,J,JEnd - J); + Buffer[JEnd - J] = 0; + Argument = Buffer; + CertainArg = true; + } + else + break; + } + + // Check for positives + if (strcasecmp(Argument,"yes") == 0 || + strcasecmp(Argument,"true") == 0 || + strcasecmp(Argument,"with") == 0 || + strcasecmp(Argument,"enable") == 0) + { + Sense = 1; + + // Eat the argument + if (Argument != Buffer) + { + Opt += strlen(Opt); + I += IncI; + } + break; + } + + // Check for negatives + if (strcasecmp(Argument,"no") == 0 || + strcasecmp(Argument,"false") == 0 || + strcasecmp(Argument,"without") == 0 || + strcasecmp(Argument,"disable") == 0) + { + Sense = 0; + + // Eat the argument + if (Argument != Buffer) + { + Opt += strlen(Opt); + I += IncI; + } + break; + } + + if (CertainArg == true) + return _error->Error("Sense %s is not understood, try true or false.",Argument); + + Argument = 0; + } + + // Indeterminate sense depends on the flag + if (Sense == -1) + { + if ((A->Flags & InvBoolean) == InvBoolean) + Sense = 0; + else + Sense = 1; + } + + Conf->Set(A->ConfName,Sense); + return true; +} + /*}}}*/ diff --git a/apt-pkg/contrib/cmndline.h b/apt-pkg/contrib/cmndline.h new file mode 100644 index 00000000..038f421e --- /dev/null +++ b/apt-pkg/contrib/cmndline.h @@ -0,0 +1,91 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: cmndline.h,v 1.1 1998/09/22 05:30:26 jgg Exp $ +/* ###################################################################### + + Command Line Class - Sophisticated command line parser + + This class provides a unified command line parser/option handliner/ + configuration mechanism. It allows the caller to specify the option + set and map the option set into the configuration class or other + special functioning. + + Filenames are stripped from the option stream and put into their + own array. + + The argument descriptor array can be initialized as: + + CommandLine::Args Args[] = + {{'q',"quiet","apt::get::quiet",CommandLine::IntLevel}, + {0,0,0,0,0}}; + + The flags mean, + HasArg - Means the argument has a value + IntLevel - Means the argument is an integer level indication, the + following -qqqq (+3) -q5 (=5) -q=5 (=5) are valid + Boolean - Means it is true/false or yes/no. + -d (true) --no-d (false) --yes-d (true) + --long (true) --no-long (false) --yes-long (true) + -d=yes (true) -d=no (false) Words like enable, disable, + true false, yes no and on off are recognized in logical + places. + InvBoolean - Same as boolean but the case with no specified sense + (first case) is set to false. + ConfigFile - Means this flag should be interprited as the name of + a config file to read in at this point in option processing. + Implies HasArg. + The default, if the flags are 0 is to use Boolean + + ##################################################################### */ + /*}}}*/ +// Header section: pkglib +#ifndef PKGLIB_CMNDLINE_H +#define PKGLIB_CMNDLINE_H + +#ifdef __GNUG__ +#pragma interface "apt-pkg/cmndline.h" +#endif + +#include <apt-pkg/configuration.h> + +class CommandLine +{ + public: + struct Args; + + protected: + + Args *ArgList; + Configuration *Conf; + bool HandleOpt(int &I,int argc,const char *argv[],const char *&Opt,Args *A); + + public: + + enum AFlags + { + HasArg = (1 << 0), + IntLevel = (1 << 1), + Boolean = (1 << 2), + InvBoolean = (1 << 3), + ConfigFile = (1 << 4) | HasArg + }; + + const char **FileList; + + bool Parse(int argc,const char **argv); + void ShowHelp(); + + CommandLine(Args *AList,Configuration *Conf); +}; + +struct CommandLine::Args +{ + char ShortOpt; + const char *LongOpt; + const char *ConfName; + unsigned long Flags; + + inline bool end() {return ShortOpt == 0 && LongOpt == 0;}; +}; + +#endif diff --git a/apt-pkg/contrib/configuration.cc b/apt-pkg/contrib/configuration.cc index 72b654b0..bff2dc6e 100644 --- a/apt-pkg/contrib/configuration.cc +++ b/apt-pkg/contrib/configuration.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: configuration.cc,v 1.3 1998/07/12 23:58:44 jgg Exp $ +// $Id: configuration.cc,v 1.4 1998/09/22 05:30:26 jgg Exp $ /* ###################################################################### Configuration Class @@ -16,9 +16,11 @@ #pragma implementation "apt-pkg/configuration.h" #endif #include <apt-pkg/configuration.h> +#include <apt-pkg/error.h> #include <strutl.h> #include <stdio.h> +#include <fstream.h> /*}}}*/ Configuration *_config = new Configuration; @@ -140,6 +142,39 @@ int Configuration::FindI(const char *Name,int Default) return Res; } /*}}}*/ +// Configuration::FindB - Find a boolean type /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool Configuration::FindB(const char *Name,bool Default) +{ + Item *Itm = Lookup(Name,false); + if (Itm == 0 || Itm->Value.empty() == true) + return Default; + + char *End; + int Res = strtol(Itm->Value.c_str(),&End,0); + if (End == Itm->Value.c_str() || Res < 0 || Res > 1) + { + // Check for positives + if (strcasecmp(Itm->Value,"no") == 0 || + strcasecmp(Itm->Value,"false") == 0 || + strcasecmp(Itm->Value,"without") == 0 || + strcasecmp(Itm->Value,"disable") == 0) + return false; + + // Check for negatives + if (strcasecmp(Itm->Value,"no") == 0 || + strcasecmp(Itm->Value,"false") == 0 || + strcasecmp(Itm->Value,"without") == 0 || + strcasecmp(Itm->Value,"disable") == 0) + return false; + + return Default; + } + + return Res; +} + /*}}}*/ // Configuration::Set - Set a value /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -164,3 +199,197 @@ void Configuration::Set(const char *Name,int Value) Itm->Value = S; } /*}}}*/ +// Configuration::Exists - Returns true if the Name exists /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool Configuration::Exists(const char *Name) +{ + Item *Itm = Lookup(Name,false); + if (Itm == 0) + return false; + return true; +} + /*}}}*/ + +// ReadConfigFile - Read a configuration file /*{{{*/ +// --------------------------------------------------------------------- +/* The configuration format is very much like the named.conf format + used in bind8, in fact this routine can parse most named.conf files. */ +bool ReadConfigFile(Configuration &Conf,string FName) +{ + // Open the stream for reading + ifstream F(FName.c_str(),ios::in | ios::nocreate); + if (!F != 0) + return _error->Errno("ifstream::ifstream","Opening configuration file %s",FName.c_str()); + + char Buffer[300]; + string LineBuffer; + + // Parser state + string ParentTag; + + int CurLine = 0; + bool InComment = false; + while (F.eof() == false) + { + F.getline(Buffer,sizeof(Buffer)); + CurLine++; + _strtabexpand(Buffer,sizeof(Buffer)); + _strstrip(Buffer); + + // Multi line comment + if (InComment == true) + { + for (const char *I = Buffer; *I != 0; I++) + { + if (*I == '*' && I[1] == '/') + { + memmove(Buffer,I+2,strlen(I+2) + 1); + InComment = false; + break; + } + } + if (InComment == true) + continue; + } + + // Discard single line comments + for (char *I = Buffer; *I != 0; I++) + { + if (*I == '/' && I[1] == '/') + { + *I = 0; + break; + } + } + + // Look for multi line comments + for (char *I = Buffer; *I != 0; I++) + { + if (*I == '/' && I[1] == '*') + { + InComment = true; + for (char *J = Buffer; *J != 0; J++) + { + if (*J == '*' && J[1] == '/') + { + memmove(I,J+2,strlen(J+2) + 1); + InComment = false; + break; + } + } + + if (InComment == true) + { + *I = 0; + break; + } + } + } + + // Blank + if (Buffer[0] == 0) + continue; + + // We now have a valid line fragment + for (char *I = Buffer; *I != 0;) + { + if (*I == '{' || *I == ';' || *I == '}') + { + // Put the last fragement into the buffer + char *Start = Buffer; + char *Stop = I; + for (; Start != I && isspace(*Start) != 0; Start++); + for (; Stop != Start && isspace(Stop[-1]) != 0; Stop--); + if (LineBuffer.empty() == false && Stop - Start != 0) + LineBuffer += ' '; + LineBuffer += string(Start,Stop - Start); + + // Remove the fragment + char TermChar = *I; + memmove(Buffer,I + 1,strlen(I + 1) + 1); + I = Buffer; + + // Move up a tag + if (TermChar == '}') + { + string::size_type Pos = ParentTag.rfind("::"); + if (Pos == string::npos) + ParentTag = string(); + else + ParentTag = string(ParentTag,0,Pos); + } + + // Syntax Error + if (TermChar == '{' && LineBuffer.empty() == true) + return _error->Error("Syntax error %s:%u: Block starts with no name.",FName.c_str(),CurLine); + + if (LineBuffer.empty() == true) + continue; + + // Parse off the tag + string::size_type Pos = LineBuffer.find(' '); + if (Pos == string::npos) + { + if (TermChar == '{') + Pos = LineBuffer.length(); + else + return _error->Error("Syntax error %s:%u: Tag with no value",FName.c_str(),CurLine); + } + + string Tag = string(LineBuffer,0,Pos); + + // Go down a level + if (TermChar == '{') + { + if (ParentTag.empty() == true) + ParentTag = Tag; + else + ParentTag += string("::") + Tag; + Tag = string(); + } + + // We dont have a value to set + if (Pos == LineBuffer.length()) + { + LineBuffer = string(); + continue; + } + + // Parse off the word + string Word; + if (ParseCWord(LineBuffer.c_str()+Pos,Word) == false) + return _error->Error("Syntax error %s:%u: Malformed value",FName.c_str(),CurLine); + + // Generate the item name + string Item; + if (ParentTag.empty() == true) + Item = Tag; + else + { + if (Tag.empty() == true) + Item = ParentTag; + else + Item = ParentTag + "::" + Tag; + } + + // Set the item in the configuration class + Conf.Set(Item,Word); + + // Empty the buffer + LineBuffer = string(); + } + else + I++; + } + + // Store the fragment + const char *Stripd = _strstrip(Buffer); + if (*Stripd != 0 && LineBuffer.empty() == false) + LineBuffer += " "; + LineBuffer += Stripd; + } + + return true; +} + /*}}}*/ diff --git a/apt-pkg/contrib/configuration.h b/apt-pkg/contrib/configuration.h index 9229a0f6..1cdf6786 100644 --- a/apt-pkg/contrib/configuration.h +++ b/apt-pkg/contrib/configuration.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: configuration.h,v 1.3 1998/07/12 23:58:45 jgg Exp $ +// $Id: configuration.h,v 1.4 1998/09/22 05:30:27 jgg Exp $ /* ###################################################################### Configuration Class @@ -51,13 +51,20 @@ class Configuration string Find(const char *Name,const char *Default = 0); string FindDir(const char *Name,const char *Default = 0); int FindI(const char *Name,int Default = 0); - + bool FindB(const char *Name,bool Default = false); + + inline void Set(string Name,string Value) {Set(Name.c_str(),Value);}; void Set(const char *Name,string Value); - void Set(const char *Name,int Value); + void Set(const char *Name,int Value); + inline bool Exists(string Name) {return Exists(Name.c_str());}; + bool Exists(const char *Name); + Configuration(); }; extern Configuration *_config; +bool ReadConfigFile(Configuration &Conf,string File); + #endif diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index f30d9ffe..5a61f269 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: strutl.cc,v 1.3 1998/07/19 04:22:08 jgg Exp $ +// $Id: strutl.cc,v 1.4 1998/09/22 05:30:28 jgg Exp $ /* ###################################################################### String Util - Some usefull string functions. @@ -77,7 +77,7 @@ char *_strtabexpand(char *String,size_t Len) // --------------------------------------------------------------------- /* This grabs a single word, converts any % escaped characters to their proper values and advances the pointer. Double quotes are understood - and striped out as well. */ + and striped out as well. This is for URI/URL parsing. */ bool ParseQuoteWord(const char *&String,string &Res) { // Skip leading whitespace @@ -128,6 +128,47 @@ bool ParseQuoteWord(const char *&String,string &Res) return true; } /*}}}*/ +// ParseCWord - Parses a string like a C "" expression /*{{{*/ +// --------------------------------------------------------------------- +/* This expects a series of space seperated strings enclosed in ""'s. + It concatenates the ""'s into a single string. */ +bool ParseCWord(const char *String,string &Res) +{ + // Skip leading whitespace + const char *C = String; + for (;*C != 0 && *C == ' '; C++); + if (*C == 0) + return false; + + char Buffer[1024]; + char *Buf = Buffer; + if (strlen(String) >= sizeof(Buffer)) + return false; + + for (; *C != 0; C++) + { + if (*C == '"') + { + for (C++; *C != 0 && *C != '"'; C++) + *Buf++ = *C; + + if (*C == 0) + return false; + + continue; + } + + if (C != String && isspace(*C) != 0 && isspace(C[-1]) != 0) + continue; + if (isspace(*C) == 0) + return false; + *Buf++ = ' '; + } + *Buf = 0; + Res = Buffer; + return true; +} + /*}}}*/ // QuoteString - Convert a string into quoted from /*{{{*/ // --------------------------------------------------------------------- /* */ diff --git a/apt-pkg/contrib/strutl.h b/apt-pkg/contrib/strutl.h index b49b1a52..7af21558 100644 --- a/apt-pkg/contrib/strutl.h +++ b/apt-pkg/contrib/strutl.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: strutl.h,v 1.3 1998/07/19 04:22:09 jgg Exp $ +// $Id: strutl.h,v 1.4 1998/09/22 05:30:29 jgg Exp $ /* ###################################################################### String Util - These are some usefull string functions @@ -24,6 +24,7 @@ char *_strstrip(char *String); char *_strtabexpand(char *String,size_t Len); bool ParseQuoteWord(const char *&String,string &Res); +bool ParseCWord(const char *String,string &Res); string QuoteString(string Str,const char *Bad); string SizeToStr(double Bytes); string TimeToStr(unsigned long Sec); |