Changeset 7201
- Timestamp:
- May 24, 2006, 5:51:33 PM (20 years ago)
- File:
-
- 1 edited
-
trunk/psLib/src/types/psArguments.c (modified) (7 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/types/psArguments.c
r7188 r7201 7 7 * @author David Robbins, MHPCC 8 8 * 9 * @version $Revision: 1. 5$ $Name: not supported by cvs2svn $10 * @date $Date: 2006-05-2 3 23:41:42$9 * @version $Revision: 1.6 $ $Name: not supported by cvs2svn $ 10 * @date $Date: 2006-05-25 03:51:33 $ 11 11 * 12 12 * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii … … 104 104 105 105 106 static psMetadataItem *argumentRead(psMetadataItem *item, // Item to read into 107 int argnum, // Argument number 108 int *argc, // Number of arguments in total 109 char **argv) // The arguments 110 111 { 112 psMetadataItem *newItem = NULL; 106 #define ARG_READ_CASE(TYPE,FUNC) \ 107 case PS_TYPE_##TYPE: \ 108 item->data.TYPE = FUNC(argv[argnum]); \ 109 return psArgumentRemove(argnum, argc, argv); 110 111 static bool argumentRead(psMetadataItem *item, // Item to read into 112 int argnum, // Argument number 113 int *argc, // Number of arguments in total 114 char **argv) // The arguments 115 116 { 113 117 switch(item->type) 114 118 { 115 // Only doing a representative set of types 116 case PS_DATA_S32: 117 newItem = psMetadataItemAlloc(item->name, item->type, item->comment, atoi(argv[argnum])); 118 psArgumentRemove(argnum, argc, argv); 119 break; 120 case PS_DATA_F32: 121 newItem = psMetadataItemAlloc(item->name, item->type, item->comment, atof(argv[argnum])); 122 psArgumentRemove(argnum, argc, argv); 123 break; 119 ARG_READ_CASE(U8,atoi); 120 ARG_READ_CASE(U16,atoi); 121 ARG_READ_CASE(U32,atoi); 122 ARG_READ_CASE(S8,atoi); 123 ARG_READ_CASE(S16,atoi); 124 ARG_READ_CASE(S32,atoi); 125 ARG_READ_CASE(F32,atof); 126 ARG_READ_CASE(F64,atof); 124 127 case PS_DATA_BOOL: 125 128 // Turn option on; no optional argument to remove 126 newItem = psMetadataItemAlloc(item->name, item->type, item->comment, true); 127 break; 128 // XXX: Include the other numerical types 129 case PS_DATA_STRING: { 130 //psString string = psStringCopy(argv[argnum]); // Get the argument into PS memory management 131 //psFree(string); 132 newItem = psMetadataItemAlloc(item->name, item->type, item->comment, argv[argnum]); 133 psArgumentRemove(argnum, argc, argv); 134 } 135 break; 129 item->data.B = true; 130 return true; 131 case PS_DATA_STRING: 132 psFree(item->data.V); 133 item->data.V = psStringCopy(argv[argnum]); 134 return psArgumentRemove(argnum, argc, argv); 136 135 default: 137 psError(PS_ERR_IO, true, "Argument type (%x) is not supported --- argument %s ignored\n", 138 item->type, item->name); 139 psFree(newItem); 140 return NULL; 141 } 142 143 return newItem; 144 } 145 146 147 // XXX: There is a memory leak in the MULTI section. I think it might have something to do with reference 148 // counting between lists and MD, in the second section of the code (copy newArgs into arguments), but I'm not 149 // entirely sure. 136 psError(PS_ERR_IO, true, "Argument type (%x) is not supported --- argument %s (%s) ignored\n", 137 item->type, item->name, item->comment); 138 return false; 139 } 140 141 return true; 142 } 143 144 150 145 bool psArgumentParse(psMetadata *arguments, 151 146 int *argc, … … 156 151 // the default values, which we probably want to output in a "help" message (we don't want to print 157 152 // the changed values and have the user think that they are default values). 158 159 psMetadata *newArgs = psMetadataAlloc(); // Place to read arguments into 160 psList *changed = psListAlloc(NULL);// List of keys that have changed 153 psMetadata *oldArgs = psMetadataCopy(NULL, arguments); // Copy of old arguments, in event of an error 154 psMetadata *multiFlag = psMetadataAlloc(); // Flag for which MULTI values have been read 161 155 162 156 for (int i = 1; i < *argc; i++) { … … 165 159 if (argItem) { 166 160 psArgumentRemove(i, argc, argv); // Remove the switch 167 if (argItem->type != PS_DATA_METADATA_MULTI) { 161 162 switch (argItem->type) { 163 case PS_DATA_METADATA: { 164 // -arg 1 2 3 165 psMetadata *params = argItem->data.V; // The list of parameters 166 if (*argc < i + params->list->n) { 167 psError(PS_ERR_IO, true, "Not enough arguments for %s.\n", argItem->name); 168 // Remove the arguments --- they will be ignored 169 for (int j = i; j < *argc; j++) { 170 psArgumentRemove(i, argc, argv); 171 } 172 goto failed; 173 } 174 175 psMetadataIterator *paramsIter = psMetadataIteratorAlloc(params, PS_LIST_HEAD, NULL);// Iter 176 psMetadataItem *param = NULL; // Parameter from iteration 177 while ((param = psMetadataGetAndIncrement(paramsIter))) { 178 argumentRead(param, i, argc, argv); 179 } 180 psFree(paramsIter); 181 break; 182 } 183 case PS_DATA_METADATA_MULTI: { 184 // -arg 1 -arg 2 -arg 3 .... 185 psList *multi = argItem->data.V; // The MULTI list 186 psMetadataItem *template = psListGet(multi, PS_LIST_HEAD) 187 ; // The template item 188 psMetadataItem *newItem = psMetadataItemCopy(template) 189 ; // New item to add 190 argumentRead(newItem, i, argc, argv); 191 psMetadataAddItem(arguments, newItem, PS_LIST_TAIL, PS_META_DUPLICATE_OK); 192 psFree(newItem); // Drop reference 193 194 // Remove the template 195 bool search = false; // Result of search 196 if (!psMetadataLookupBool(&search, multiFlag, argItem->name) || !search) { 197 // Chop the template off 198 psListRemove(multi, PS_LIST_HEAD); // Remove from MULTI (hash side) 199 psListRemoveData(arguments->list, template) 200 ; // Remove from list side 201 psMetadataAddBool(multiFlag, PS_LIST_HEAD, argItem->name, PS_META_REPLACE, 202 NULL, true); 203 } 204 break; 205 } 206 default: 207 // -arg 1 168 208 if (argItem->type != PS_DATA_BOOL && *argc < i + 1) { 169 209 psError(PS_ERR_IO, true, "Required argument for %s is missing.\n", argItem->name); 170 // XXX: Cleanup before returning 171 psFree(newArgs); 172 return false; 210 goto failed; 173 211 } 174 psMetadataItem *newItem = argumentRead(argItem, i, argc, argv); 175 psMetadataAddItem(newArgs, newItem, PS_LIST_TAIL, PS_META_REPLACE); 176 psFree(newItem); 177 } else { 178 // Go through the MULTI 179 psList *multi = argItem->data.V; // The list of MULTI psMetadataItems 180 if (*argc < i + multi->n) { 181 psError(PS_ERR_IO, true, "Not enough arguments for %s.\n", argItem->name); 182 // Remove the arguments --- they will be ignored 183 for (int j = i; j < *argc; j++) { 184 psArgumentRemove(i, argc, argv); 185 } 186 // XXX: Cleanup before returning 187 psFree(newArgs); 188 return false; 189 } 190 191 // Remove any prior existence in the newArgs --- this is important because we specify 192 // adding the new items as DUPLICATE_OK, so if some idiot specifies it twice, we'd end 193 // up with two copies of everything. 194 psMetadataItem *checkItem = psMetadataLookup(newArgs, argItem->name); 195 if (checkItem) { 196 (void)psMetadataRemove(newArgs, 0, argItem->name); 197 (void)psListRemoveData(changed, argItem->name); 198 } 199 200 psListIterator *multiIter = psListIteratorAlloc(multi, PS_LIST_HEAD, true); 201 psMetadataItem *nextItem = NULL; // Item from list 202 while ( (nextItem = psListGetAndIncrement(multiIter)) ) { 203 psMetadataItem *newItem = argumentRead(nextItem, i, argc, argv); 204 psMetadataAddItem(newArgs, newItem, PS_LIST_TAIL, PS_META_DUPLICATE_OK); 205 //psFree(newItem); 206 } 207 psFree(multiIter); 208 } 209 210 // Some book-keeping 211 // psString name = psStringCopy(argItem->name); 212 psListAdd(changed, PS_LIST_TAIL, argItem->name); 213 i--; 214 215 } else if ( (strncmp(argv[i], "-", 1) == 0 ) || (strncmp(argv[i], "+", 1) == 0) ) { 212 argumentRead(argItem, i, argc, argv); 213 break; 214 } 215 i--; // We removed stuff 216 } else if (strncmp(argv[i], "-", 1) == 0 || strncmp(argv[i], "+", 1) == 0) { 216 217 // Someone's specified a bad option 217 218 psError(PS_ERR_IO, true, "Unknown option: %s\n", argv[i]); 218 psFree(newArgs); 219 return false; 220 } 221 } 222 223 // All the arguments are good, so now we can copy the newArgs over 224 psListIterator *changedIter = psListIteratorAlloc(changed, PS_LIST_HEAD, false); // Iterator 225 psString name = NULL; // Item from iteration 226 while ( (name = psListGetAndIncrement(changedIter)) ) { 227 psTrace(__func__, 7, "Updating %s\n", name); 228 psMetadataItem *oldItem = psMetadataLookup(arguments, name); 229 psMetadataItem *newItem = psMetadataLookup(newArgs, name); 230 if ( (oldItem->type != newItem->type) ) { 231 psAbort(__func__, "Shouldn't reach here!\n"); 232 } 233 switch (oldItem->type) { 234 // Only doing a representative set of types 235 case PS_DATA_S32: 236 oldItem->data.S32 = newItem->data.S32; 237 break; 238 case PS_DATA_F32: 239 oldItem->data.F32 = newItem->data.F32; 240 break; 241 case PS_DATA_BOOL: 242 oldItem->data.B = newItem->data.B; 243 break; 244 // XXX: Include the other numerical types 245 case PS_DATA_STRING: 246 psFree(oldItem->data.V); 247 oldItem->data.V = psMemIncrRefCounter(newItem->data.V); 248 break; 249 case PS_DATA_METADATA_MULTI: { 250 psList *newMulti = psMemIncrRefCounter(newItem->data.V); // The new list of MULTI 251 psList *oldMulti = oldItem->data.V; // The old list of MULTI 252 psListIterator *newMultiIter = psListIteratorAlloc(newMulti, PS_LIST_HEAD, false); 253 psListIterator *oldMultiIter = psListIteratorAlloc(oldMulti, PS_LIST_HEAD, true); 254 psMetadataItem *newMultiItem = NULL; // Item from iterator 255 while ( (newMultiItem = psListGetAndIncrement(newMultiIter)) ) { 256 psMetadataItem *oldMultiItem = psListGetAndIncrement(oldMultiIter); 257 if (!oldMultiItem) { 258 psAbort(__func__, 259 "Something went very wrong here! The lists SHOULD be of the same length!\n"); 260 } 261 switch (oldMultiItem->type) { 262 // Only doing a representative set of types 263 case PS_DATA_S32: 264 oldItem->data.S32 = newItem->data.S32; 265 break; 266 case PS_DATA_F32: 267 oldItem->data.F32 = newItem->data.F32; 268 break; 269 // XXX: Include the other numerical types 270 case PS_DATA_STRING: 271 psFree(oldItem->data.V); 272 oldItem->data.V = psMemIncrRefCounter(newItem->data.V); 273 break; 274 default: 275 psAbort(__func__, "Should never ever get here, ever.\n"); 276 } 277 psFree(oldMultiItem); 278 psFree(newMultiItem); 279 } 280 psFree(newMultiIter); 281 psFree(oldMultiIter); 282 } 283 break; 284 default: 285 psAbort(__func__, "Should never ever ever get here.\n"); 286 } 287 } 288 psFree(changedIter); 289 psFree(changed); 290 291 // Now, blow away the newArgs and we're done. 292 psFree(newArgs); 219 goto failed; 220 } 221 } 222 223 psFree(multiFlag); 224 psFree(oldArgs); // Didn't need these 293 225 return true; 294 } 295 226 227 failed: 228 // We need to copy everything back 229 while (psMetadataRemoveIndex(arguments, PS_LIST_TAIL)) 230 ; 231 psMetadataCopy(arguments, oldArgs); 232 psFree(multiFlag); 233 psFree(oldArgs); 234 return false; 235 } 236 237 238 #define LENGTH_CASE(TYPE) \ 239 case PS_TYPE_##TYPE: \ 240 return arg->data.TYPE == 0 ? 1 : \ 241 (arg->data.TYPE > 0 ? (int)log10f((float)arg->data.TYPE) + 1 : \ 242 (int)log10f(-(float)arg->data.TYPE) + 2); 296 243 297 244 static int argLength(psMetadataItem *arg) … … 299 246 switch (arg->type) { 300 247 // Only doing a representative set of types 301 case PS_DATA_S32: 302 return arg->data.S32 == 0 ? 1 : 303 (arg->data.S32 > 0 ? (int)log10f((float)arg->data.S32) + 1 : 304 (int)log10f(-(float)arg->data.S32) + 2); 305 // XXX: Other numerical types 248 LENGTH_CASE(U8); 249 LENGTH_CASE(U16); 250 LENGTH_CASE(U32); 251 LENGTH_CASE(S8); 252 LENGTH_CASE(S16); 253 LENGTH_CASE(S32); 306 254 case PS_DATA_F32: 307 255 return arg->data.F32 >= 0 ? 12 : 13; // -d.dddddde?dd … … 319 267 } 320 268 269 270 #define PRINT_CASE(TYPE,FORMAT) \ 271 case PS_TYPE_##TYPE: \ 272 printf(FORMAT, item->data.TYPE); \ 273 break; 274 275 // Print the value and comment for an argument item 276 static void printValueComment(psMetadataItem *item, // Argument item for which to print 277 const char *comment, // Comment to print 278 unsigned int numSpaces // Number of spaces 279 ) 280 { 281 int valueLength = 0; // Length of the value portion 282 printf("("); 283 if (item) { 284 // Print the value 285 switch (item->type) { 286 PRINT_CASE(U8,"%d"); 287 PRINT_CASE(U16,"%d"); 288 PRINT_CASE(U32,"%d"); 289 PRINT_CASE(S8,"%d"); 290 PRINT_CASE(S16,"%d"); 291 PRINT_CASE(S32,"%d"); 292 PRINT_CASE(F32,"%.6e"); 293 PRINT_CASE(F64,"%.6e"); 294 case PS_DATA_BOOL: 295 if (item->data.B) { 296 printf("TRUE"); 297 } else { 298 printf("FALSE"); 299 } 300 break; 301 case PS_DATA_STRING: 302 if (item->data.V) { 303 printf("""%s""", (char*)(item->data.V)); 304 } 305 break; 306 default: 307 psAbort(__func__, "Argument type (%x) for %s is not supported.\n", item->type, item->name); 308 } 309 valueLength = argLength(item); 310 } 311 printf(")"); 312 313 // Spaces for formatting 314 for (int i = valueLength; i < numSpaces; i++) { 315 printf(" "); 316 } 317 318 // Print the comment 319 if (comment) { 320 printf("%s", comment); 321 } 322 printf("\n"); 323 324 return; 325 } 326 327 // Return the maximum length of the values 328 static void maxLength(int *maxName, // Maximum length of the name 329 int *maxValue, // Maximum length of the value 330 psMetadata *md // Metadata for which to check the length 331 ) 332 { 333 psMetadataIterator *iter = psMetadataIteratorAlloc(md, PS_LIST_HEAD, NULL); // Iterator 334 psMetadataItem *item = NULL; // Item from iteration 335 while ((item = psMetadataGetAndIncrement(iter))) { 336 if (item->type == PS_DATA_METADATA) { 337 maxLength(maxName, maxValue, item->data.V); 338 } else { 339 int nameLength = strlen(item->name); // Length of the name 340 if (nameLength > *maxName) { 341 *maxName = nameLength; 342 } 343 int valueLength = argLength(item); // Length of the value 344 if (valueLength > *maxValue) { 345 *maxValue = valueLength; 346 } 347 } 348 } 349 psFree(iter); 350 return; 351 } 352 353 321 354 void psArgumentHelp(psMetadata *arguments) 322 355 { 323 356 printf("Optional arguments, with default values:\n"); 357 int maxName = 4; // Maximum length of a name 358 int maxValue = 4; // Maximum length of a value 359 360 // First pass to get the sizes 361 maxLength(&maxName, &maxValue, arguments); 362 363 // Second pass to print 324 364 psMetadataIterator *argIter = psMetadataIteratorAlloc(arguments, PS_LIST_HEAD, NULL); 325 365 psMetadataItem *argItem = NULL; // Item from iterator 326 int maxName = 4; // Maximum length of a name 327 int maxValue = 4; // Maximum length of a value 328 329 // First pass to get the sizes 330 while ( (argItem = psMetadataGetAndIncrement(argIter)) ) { 331 if (strlen(argItem->name) > maxName) { 332 maxName = strlen(argItem->name); 333 } 334 int valLength = argLength(argItem); 335 if (valLength > maxValue) { 336 maxValue = valLength; 337 } 338 } 339 340 // Second pass to print 341 psMetadataIteratorSet(argIter, PS_LIST_HEAD); 342 psString lastName = NULL; // Last name we printed 343 while ( (argItem = psMetadataGetAndIncrement(argIter)) ) { 366 while ((argItem = psMetadataGetAndIncrement(argIter))) { 344 367 // Initial indent 345 368 for (int i = 0; i < NUM_SPACES; i++) { … … 348 371 349 372 // Print the name if required 350 int position = 0; // Number of spaces in 351 if (! lastName || strcmp(lastName, argItem->name) != 0) { 352 // A new name 353 printf("%s", argItem->name); 354 position += strlen(argItem->name); 355 lastName = argItem->name; 356 } 373 printf("%s", argItem->name); 374 int position = strlen(argItem->name); // Number of spaces in 357 375 for (int i = position; i < maxName + NUM_SPACES; i++) { 358 376 printf(" "); 359 377 } 360 378 361 // Print the value 362 printf("("); 363 switch (argItem->type) { 364 // Only doing a representative set of types 365 case PS_DATA_S32: 366 printf("%d", argItem->data.S32); 367 break; 368 // XXX: Other numerical types 369 case PS_DATA_F32: 370 printf("%.6e", argItem->data.F32); 371 break; 372 case PS_DATA_F64: 373 printf("%.6e", argItem->data.F64); 374 break; 375 case PS_DATA_BOOL: 376 if (argItem->data.B) { 377 printf("TRUE"); 378 } else { 379 printf("FALSE"); 380 } 381 break; 382 case PS_DATA_STRING: 383 if (argItem->data.V) { 384 printf("""%s""", (char*)(argItem->data.V)); 385 } 386 break; 387 default: 388 psAbort(__func__, "Argument type (%x) is not supported.\n", argItem->type); 389 } 390 printf(")"); 391 for (int i = argLength(argItem); i < maxValue + NUM_SPACES; i++) { 392 printf(" "); 393 } 394 395 // Print the comment 396 if (argItem->comment) { 397 printf("%s", argItem->comment); 398 } 399 printf("\n"); 379 // Check to see if it's a MULTI --- there are no default values for a MULTI 380 // -arg 1 -arg 2 -arg 3 ... 381 psMetadataItem *multiCheck = psMetadataLookup(arguments, argItem->name); // Item to check for MULTI 382 if (multiCheck->type == PS_DATA_METADATA_MULTI) { 383 printValueComment(NULL, argItem->comment, maxValue + NUM_SPACES); 384 continue; 385 } 386 387 // -arg 1 2 3 388 if (argItem->type == PS_DATA_METADATA) { 389 psMetadata *params = argItem->data.V; // The list of parameters 390 psMetadataIterator *paramsIter = psMetadataIteratorAlloc(params, PS_LIST_HEAD, NULL); // Iterator 391 psMetadataItem *paramItem = NULL; // Parameter, from iteration 392 bool first = true; // Is this the first one? 393 while ((paramItem = psMetadataGetAndIncrement(paramsIter))) { 394 if (!first) { 395 for (int i = 0; i < maxName + 2*NUM_SPACES; i++) { 396 printf(" "); 397 } 398 } 399 printValueComment(paramItem, paramItem->comment, maxValue + NUM_SPACES); 400 first = false; 401 } 402 psFree(paramsIter); 403 continue; 404 } 405 406 // -arg 1 407 printValueComment(argItem, argItem->comment, maxValue + NUM_SPACES); 400 408 } 401 409
Note:
See TracChangeset
for help on using the changeset viewer.
