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