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

HeyParser.hh

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

Generated on Fri Oct 22 07:50:24 2004 for CPU Broker by  doxygen 1.3.9.1