Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members

HeyParser.hh

Go to the documentation of this file.
00001 /*
00002  * HeyParser.hh
00003  *
00004  * Copyright (c) 2003 The University of Utah and the Flux Group.
00005  * All rights reserved.
00006  *
00007  * This file is licensed under the terms of the GNU Public License.  
00008  * See the file "license.terms" for restrictions on redistribution 
00009  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
00010  */
00011 
00012 /**
00013  * @file HeyParser.hh
00014  *
00015  * Header file for the HeyParser, HeyParserException, and HeyPropertyInfo
00016  * classes.
00017  */
00018 
00019 #ifndef _hey_parser_hh
00020 #define _hey_parser_hh
00021 
00022 #include <stack.h>
00023 #include <iostream.h>
00024 
00025 /**
00026  * Base class for exceptions thrown by the parser.
00027  *
00028  * @sa HeyParser
00029  */
00030 class HeyParserException
00031 {
00032     
00033 public:
00034     
00035     /**
00036      * Construct a HeyParserException object with an optional descriptive
00037      * message.
00038      *
00039      * @param msg A short message describing the problem.
00040      * @param value The value that caused the problem.
00041      */
00042     HeyParserException(const char *msg = NULL,
00043                        const char *value = NULL)
00044     {
00045         this->hpe_Message = msg;
00046         this->hpe_Value = value;
00047     };
00048 
00049     /**
00050      * @return The descriptive message passed into the constructor.
00051      */
00052     const char *getMessage(void) const
00053     {
00054         return this->hpe_Message;
00055     };
00056 
00057     /**
00058      * @return The value passed into the constructor.
00059      */
00060     const char *getValue(void) const
00061     {
00062         return this->hpe_Value;
00063     };
00064 
00065     /**
00066      * Output stream operator for HeyParserException objects.  Currently just
00067      * prints out the message passed into the constructor.
00068      *
00069      * @param os The destination output stream.
00070      * @param hpe The object to output.
00071      * @return The value of the 'os' parameter.
00072      */
00073     friend std::ostream &operator<<(std::ostream &os,
00074                                     const HeyParserException &hpe)
00075     {
00076         return os << (hpe.hpe_Message != NULL ? hpe.hpe_Message : "")
00077                   << (hpe.hpe_Value != NULL ? ": " : "")
00078                   << (hpe.hpe_Value != NULL ? hpe.hpe_Value : "");
00079     };
00080 
00081 private:
00082 
00083     /**
00084      * A short message describing the problem.
00085      */
00086     const char *hpe_Message;
00087     
00088     /**
00089      * The value that caused the problem.
00090      */
00091     const char *hpe_Value;
00092     
00093 };
00094 
00095 /**
00096  * A parser for command-line arguments given in the pseudo-English "hey" form.
00097  * The syntax for the arguments looks like this:
00098  *
00099  *   @li hey @<server@> list @<property@>
00100  *   @li hey @<server@> get @<property@> of @<object@>
00101  *   @li hey @<server@> set @<property@> of @<object@> to @<value@>
00102  *   @li hey @<server@> create @<property@> of @<object@> with @<name@> @<value@>
00103  *   @li hey @<server@> delete @<property@> of @<object@>
00104  *   @li hey @<server@> execute @<property@> of @<object@> with @<name@> @<value@>
00105  *   @li hey @<server@> getsuites of @<object@>
00106  *   @li hey @<server@> shutdown
00107  *
00108  * Where:
00109  *
00110  *   @li @<server@> is a reference to a running server program,
00111  *   @li list/get/etc is the verb describing the action to take,
00112  *   @li @<property@> is a object or an attribute of an object, and
00113  *   @li @<name@> @<value@> is a name/value argument pair.
00114  *
00115  * For example, to create a 'string' object named 'bar' with a value of 'Hello,
00116  * World!' in the 'foo' server, you might do:
00117  *
00118  * @code
00119  *   $ hey foo create string with name bar value 'Hello, World!'
00120  * @endcode
00121  *
00122  * Then, you can manipulate the server and object with the following commands:
00123  *
00124  * @code
00125  *   $ hey foo list
00126  *   string
00127  *   strings
00128  *   $ hey foo list strings
00129  *   bar
00130  *   $ hey foo get value of string bar
00131  *   Hello, World!
00132  *   $ hey foo delete string bar
00133  *   ok
00134  *   $ hey foo list strings
00135  *   $
00136  * @endcode
00137  *
00138  * @sa HeyParserException
00139  * @sa HeyPropertyInfo
00140  *
00141  * @see cbhey.cc
00142  * @see hey_bad.cc
00143  * @see hey_good.cc
00144  */
00145 class HeyParser
00146 {
00147 
00148 public:
00149 
00150     /**
00151      * An enumeration of the possible actions to perform on an object.
00152      */
00153     /** @var HeyParser::SHUTDOWN Shutdown the server. */
00154     typedef enum {
00155         SHUTDOWN,
00156         LIST_PROPERTIES,        /**< List the properties of an object. */
00157         GET_PROPERTY,           /**< Get a property from an object. */
00158         SET_PROPERTY,           /**< Set a property in an object. */
00159         CREATE_PROPERTY,        /**< Create a property in an object. */
00160         DELETE_PROPERTY,        /**< Delete a property in an object. */
00161         EXECUTE_PROPERTY,       /**< Execute a property in an object. */
00162         GET_SUITES,             /**< Get the description of a property. */
00163 
00164         WHAT_MAX
00165     } hp_what_t;
00166 
00167     /**
00168      * String versions of the hp_what_t enumeration values.
00169      */
00170     static const char *hp_what_strings[WHAT_MAX];
00171 
00172     /**
00173      * Construct a parser that interprets the given command-line arguments.
00174      * Most of the parsing will be done here so there are fewer surprises along
00175      * the way.  Note that the object expects all of the arguments, including
00176      * the command name.
00177      *
00178      * @callgraph
00179      *
00180      * @param argc The argument count.
00181      * @param argv The argument values.
00182      *
00183      * @throws HeyParserException if there is a problem with the argument list.
00184      */
00185     HeyParser(int argc, const char *argv[])
00186         throw (HeyParserException);
00187 
00188     /**
00189      * Deconstruct a parser object.
00190      */
00191     virtual ~HeyParser(void);
00192 
00193     /**
00194      * @return The argument count.
00195      */
00196     int getArgCount(void) const
00197     {
00198         return( this->hp_ArgCount );
00199     }
00200 
00201     /**
00202      * @return The argument values.
00203      */
00204     const char **getArgValues(void) const
00205     {
00206         return( this->hp_ArgValue );
00207     }
00208 
00209     /**
00210      * @return The argument that specifies which server to talk to.
00211      */
00212     const char *who(void) const
00213     {
00214         return( this->hp_ArgValue[1] );
00215     };
00216 
00217     /**
00218      * @return The action requested by the user (i.e. what to do).
00219      */
00220     hp_what_t what(void) const
00221     {
00222         return( this->hp_What );
00223     };
00224 
00225     /**
00226      * Pop a pair from the property stack.
00227      *
00228      * @param name_out The reference where the property name should be stored.
00229      * @param value_out The reference where the property value should be
00230      * stored.
00231      *
00232      * @throws HeyParserException if there are no more values on the stack.
00233      */
00234     void popProperty(const char *&name_out, const char *&value_out)
00235         throw (HeyParserException);
00236 
00237     /**
00238      * @return The value that a property should be set to.
00239      */
00240     const char *to(void) const
00241     {
00242         return( this->hp_ToValue );
00243     };
00244     
00245     /**
00246      * Get the argument array containing the 'with' name/value pairs.
00247      *
00248      * @param with_out The reference where the 'with' array should be stored.
00249      * The elements of the array are ordered as they were on the command line.
00250      * @param count_out The size of the 'with_out' array.
00251      */
00252     void with(const char **&with_out, size_t &count_out) const;
00253 
00254     /**
00255      * Get the value for a particular 'with' argument.
00256      *
00257      * @param name The name of the 'with' argument to retrieve.
00258      * @param instance The instance of the argument to retrieve.
00259      * @param default_value The default value to return if the 'with' argument
00260      * could not be found.
00261      * @return The value coupled with the given instance of 'name', or
00262      * default_value if the instance could not be found.
00263      *
00264      * @throws HeyParserException if the particular instance of the 'with'
00265      * argument was not found.
00266      */
00267     const char *withValue(const char *name,
00268                           unsigned int instance = 0,
00269                           const char *default_value = NULL) const
00270         throw (HeyParserException);
00271 
00272 private:
00273 
00274     /**
00275      * Helper class that stores name/value pairs.
00276      */
00277     class Pair
00278     {
00279 
00280     public:
00281 
00282         /**
00283          * Construct a Pair object with the given name/value pair.
00284          *
00285          * @param name The name.
00286          * @param value The value.
00287          */
00288         Pair(const char *name = NULL, const char *value = NULL) :
00289             p_Name(name), p_Value(value)
00290         {
00291         };
00292 
00293         /**
00294          * The name of the property.
00295          */
00296         const char *p_Name;
00297 
00298         /**
00299          * The property value.
00300          */
00301         const char *p_Value;
00302     };
00303     
00304     /**
00305      * Consume an argument from the argument list.  This method is for internal
00306      * use when initially processing the argument list.
00307      *
00308      * @sideeffect hp_ArgIndex is incremented by one if there was an argument
00309      * available.
00310      *
00311      * @return The next string in the argument list.
00312      *
00313      * @throws HeyParserException if there are no more arguments to be
00314      * consumed.
00315      */
00316     const char *consumeArg(void)
00317         throw (HeyParserException);
00318 
00319     /**
00320      * Find the next name/value pair in the argument list.  This method differs
00321      * from popProperty() in that it translates from the argument list to
00322      * hp_PropertyStack.  Whereas popProperty() interacts only with
00323      * hp_PropertyStack.
00324      *
00325      * @sideeffect The top element of hp_PropertyStack is popped off.
00326      *
00327      * @param name_out The reference where the property name should be stored.
00328      * @param value_out The reference where the property value should be
00329      * stored.
00330      *
00331      * @throws HeyParserException if there are insufficient arguments.
00332      */
00333     void nextProperty(const char *&name_out, const char *&value_out)
00334         throw (HeyParserException);
00335 
00336     /**
00337      * The arguments count.
00338      */
00339     int hp_ArgCount;
00340 
00341     /**
00342      * The argument values.
00343      */
00344     const char **hp_ArgValue;
00345 
00346     /**
00347      * The "what" value.  This will only be set by the constructor when it is
00348      * initially parsing the arguments.
00349      */
00350     hp_what_t hp_What;
00351 
00352     /**
00353      * The 'to' value for a SET_PROPERTY request.
00354      */
00355     const char *hp_ToValue;
00356 
00357     /**
00358      * The current index in the argument list during processing.
00359      */
00360     int hp_ArgIndex;
00361 
00362     /**
00363      * The stack of property pairs.
00364      */
00365     stack<struct Pair> hp_PropertyStack;
00366     
00367 };
00368 
00369 /**
00370  * Helper class that holds descriptions of properties.
00371  *
00372  * @see HeyParser
00373  */
00374 class HeyPropertyInfo
00375 {
00376 
00377 public:
00378 
00379     /**
00380      * Construct a description of a property.  For example, if a server
00381      * supported the following requests on a 'string' object:
00382      *
00383      * @code
00384      * $ hey server create string with id 2 value Foobar
00385      * ok
00386      * $ hey server get string 2
00387      * Foobar
00388      * $ hey server delete string 2
00389      * ok
00390      * $ hey server get string 2
00391      * Error: No such string: 2
00392      * @endcode
00393      *
00394      * The 'suites' for these requests would be encoded by the following
00395      * array of HeyPropertyInfo's.
00396      *
00397      * @code
00398      * HeyPropertyInfo suites[] = {
00399      *     HeyPropertyInfo("string",
00400      *                     (1L << HeyParser::CREATE_PROPERTY),
00401      *                     "",
00402      *                     "id:int - The string's identifer.\n"
00403      *                     "value:string - The string's value.\n"
00404      *                     "\n"
00405      *                     "Create a string with the given id and value.\n"),
00406      *     HeyPropertyInfo("string",
00407      *                     (1L << HeyParser::GET_PROPERTY) |
00408      *                     (1L << HeyParser::SET_PROPERTY),
00409      *                     "id:int",
00410      *                     "Get or set the value of string 'id'.\n"),
00411      *     HeyPropertyInfo("string",
00412      *                     (1L << HeyParser::DELETE_PROPERTY),
00413      *                     "id:int",
00414      *                     "Delete a string 'id'.\n"),
00415      *     HeyPropertyInfo::HPI_NULL // TERMINATOR
00416      * };
00417      * @endcode
00418      *
00419      * The first object indicates that the 'string' property supports
00420      * CREATE_PROPERTY and takes two arguments, the string identifier and the
00421      * string's value.  The second and third objects also describe the
00422      * 'string' property, but this time, they document what happens when used
00423      * with the get, set, and delete actions.  These objects are then grouped
00424      * in an array so they can be easily sent to an output stream, like so:
00425      *
00426      * @code
00427      *   cout << suites;
00428      * @endcode
00429      *
00430      * The result would then look like the following:
00431      *
00432      * @code
00433      * $ hey server getsuites
00434      * Property:  string
00435      *   Supported verbs: create
00436      * Create a string with the given id and value.
00437      *
00438      * Property:  string
00439      *   Supported verbs: get set
00440      *   Specifiers:  id:int
00441      * Get or set the value of string 'id'.
00442      *
00443      * Property:  string
00444      *   Supported verbs: create
00445      *   Specifiers:  id:int
00446      * Delete a string 'id'.
00447      *
00448      * @endcode
00449      *
00450      * @param name The name of the property.
00451      * @param commands The commands supported by the property.  The commands
00452      * are encoded as a bitmap of the HeyParser::hp_what_t values.
00453      * @param specifiers A description of the specifier argument.
00454      * @param usage A description of the property and how to use it.
00455      */
00456     HeyPropertyInfo(const char *name,
00457                     unsigned int commands,
00458                     const char *specifiers = NULL,
00459                     const char *usage = NULL)
00460         : hpi_Name(name),
00461           hpi_Commands(commands),
00462           hpi_Specifiers(specifiers),
00463           hpi_Usage(usage)
00464     {
00465     };
00466 
00467     /**
00468      * Deconstruct a HeyPropertyInfo.
00469      */
00470     virtual ~HeyPropertyInfo(void)
00471     {
00472     };
00473 
00474     /**
00475      * @return The property's name.
00476      */
00477     const char *getName(void) const
00478     {
00479         return this->hpi_Name;
00480     };
00481 
00482     /**
00483      * @return The bitmap of commands supported by this property.
00484      */
00485     unsigned int getCommands(void) const
00486     {
00487         return this->hpi_Commands;
00488     };
00489 
00490     /**
00491      * @return The string describing the specifier argument, if any.
00492      */
00493     const char *getSpecifiers(void) const
00494     {
00495         return this->hpi_Specifiers;
00496     };
00497 
00498     /**
00499      * @return The string describing how to use this property.
00500      */
00501     const char *getUsage(void) const
00502     {
00503         return this->hpi_Usage;
00504     };
00505 
00506     /**
00507      * Output stream operator for HeyPropertyInfo objects.
00508      *
00509      * @param os The destination output stream.
00510      * @param hpi The object to output.
00511      * @return The value of the 'os' parameter.
00512      */
00513     friend std::ostream &operator<<(std::ostream &os,
00514                                     const HeyPropertyInfo &hpi)
00515     {
00516         unsigned int lpc;
00517 
00518         os << "Property:  " << hpi.hpi_Name << endl
00519            << "  Supported verbs:";
00520         for( lpc = 0; lpc < HeyParser::WHAT_MAX; lpc++ )
00521         {
00522             if( hpi.hpi_Commands & (1L << lpc) )
00523             {
00524                 os << " " << HeyParser::hp_what_strings[lpc];
00525             }
00526         }
00527         os << endl;
00528         if( (hpi.hpi_Specifiers != NULL) &&
00529             (hpi.hpi_Specifiers[0] != '\0') )
00530         {
00531             os << "  Specifiers:  " << hpi.hpi_Specifiers << endl;
00532         }
00533         if( (hpi.hpi_Usage != NULL) && (hpi.hpi_Usage[0] != '\0') )
00534         {
00535             os << hpi.hpi_Usage;
00536         }
00537         return( os );
00538     };
00539 
00540     /**
00541      * Output stream operator for an HPI_NULL terminated array of
00542      * HeyPropertyInfo objects.
00543      *
00544      * @param os The destination output stream.
00545      * @param hpi The array to output.
00546      * @return The value of the 'os' parameter.
00547      */
00548     friend std::ostream &operator<<(std::ostream &os,
00549                                     const HeyPropertyInfo hpi[])
00550     {
00551         unsigned int lpc;
00552 
00553         for( lpc = 0; hpi[lpc].getCommands() != 0; lpc++ )
00554         {
00555             os << hpi[lpc] << endl;
00556         }
00557         return( os );
00558     };
00559 
00560     /**
00561      * Typed NULL for HeyPropertyInfo's.
00562      */
00563     static HeyPropertyInfo HPI_NULL;
00564 
00565 private:
00566 
00567     /**
00568      * The property's name.
00569      */
00570     const char *hpi_Name;
00571     
00572     /**
00573      * The bitmap of commands supported by this property.
00574      */
00575     unsigned int hpi_Commands;
00576     
00577     /**
00578      * The string describing the specifier argument, if any.
00579      */
00580     const char *hpi_Specifiers;
00581     
00582     /**
00583      * The string describing how to use this property.
00584      */
00585     const char *hpi_Usage;
00586     
00587 };
00588 
00589 #endif

Generated on Mon Dec 1 16:29:06 2003 for CPU Broker by doxygen 1.3.4