IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 7201


Ignore:
Timestamp:
May 24, 2006, 5:51:33 PM (20 years ago)
Author:
Paul Price
Message:

MULTI is now used for multiple items with the same value (-arg 1 -arg 2 -arg 3 ...).
A metadata is used for multiple items specified by a single flag (-arg 1 2 3).
Simplified the code, added more types.
Tested with own test code, and tst_psArguments.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/psLib/src/types/psArguments.c

    r7188 r7201  
    77 *  @author David Robbins, MHPCC
    88 *
    9  *  @version $Revision: 1.5 $ $Name: not supported by cvs2svn $
    10  *  @date $Date: 2006-05-23 23:41:42 $
     9 *  @version $Revision: 1.6 $ $Name: not supported by cvs2svn $
     10 *  @date $Date: 2006-05-25 03:51:33 $
    1111 *
    1212 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
     
    104104
    105105
    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) \
     107case PS_TYPE_##TYPE: \
     108item->data.TYPE = FUNC(argv[argnum]); \
     109return psArgumentRemove(argnum, argc, argv);
     110
     111static 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{
    113117    switch(item->type)
    114118    {
    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);
    124127    case PS_DATA_BOOL:
    125128        // 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);
    136135    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
    150145bool psArgumentParse(psMetadata *arguments,
    151146                     int *argc,
     
    156151    // the default values, which we probably want to output in a "help" message (we don't want to print
    157152    // 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
    161155
    162156    for (int i = 1; i < *argc; i++) {
     
    165159        if (argItem) {
    166160            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
    168208                if (argItem->type != PS_DATA_BOOL && *argc < i + 1) {
    169209                    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;
    173211                }
    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) {
    216217            // Someone's specified a bad option
    217218            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
    293225    return true;
    294 }
    295 
     226
     227failed:
     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) \
     239case PS_TYPE_##TYPE: \
     240return 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);
    296243
    297244static int argLength(psMetadataItem *arg)
     
    299246    switch (arg->type) {
    300247        // 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);
    306254    case PS_DATA_F32:
    307255        return arg->data.F32 >= 0 ? 12 : 13; // -d.dddddde?dd
     
    319267}
    320268
     269
     270#define PRINT_CASE(TYPE,FORMAT) \
     271case PS_TYPE_##TYPE: \
     272printf(FORMAT, item->data.TYPE); \
     273break;
     274
     275// Print the value and comment for an argument item
     276static 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
     328static 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
    321354void psArgumentHelp(psMetadata *arguments)
    322355{
    323356    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
    324364    psMetadataIterator *argIter = psMetadataIteratorAlloc(arguments, PS_LIST_HEAD, NULL);
    325365    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))) {
    344367        // Initial indent
    345368        for (int i = 0; i < NUM_SPACES; i++) {
     
    348371
    349372        // 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
    357375        for (int i = position; i < maxName + NUM_SPACES; i++) {
    358376            printf(" ");
    359377        }
    360378
    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);
    400408    }
    401409
Note: See TracChangeset for help on using the changeset viewer.