Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

kvplib/keyValuePair.c

Go to the documentation of this file.
00001 /* keyValuePair.c - parse string of key/value pairs for config information */
00002 
00003 /* G.J.Crone, University College London */
00004 
00005 /*
00006  * Current CVS Tag:
00007  * $Header: /cvs/minoscvs/rep1/minossoft/OnlineUtil/kvplib/keyValuePair.c,v 1.3 2004/05/13 18:57:07 rhatcher Exp $
00008  */
00009  
00010 /* 
00011  * Modification History : DO NOT EDIT - MAINTAINED BY CVS 
00012  * $Log: keyValuePair.c,v $
00013  * Revision 1.3  2004/05/13 18:57:07  rhatcher
00014  * synch with online CVS repository as of 2004-04-30
00015  *
00016  * Revision 1.18  2004/04/30 16:27:41  gjc
00017  * Aha, found the bug.  Add 1 to reclen to allow for the terminating 0!
00018  *
00019  * Revision 1.17  2004/04/30 15:33:42  gjc
00020  * Simplification to stripSpaces so that it no longer relies on
00021  * strlen().  Reduces number of errors in valgrind.
00022  *
00023  * Revision 1.16  2004/03/04 16:15:55  gjc
00024  * Grow internal buffer (by allocating larger buffer and copying data) as
00025  * necessary.
00026  *
00027  * Revision 1.15  2004/03/04 11:50:19  gjc
00028  * Added new function kvpQueryLength to return the number of elements in
00029  * an array.
00030  *
00031  * Revision 1.14  2003/09/04 21:06:15  gjc
00032  * Use malloc instead of static array.  Move BUFFER_SIZE in keyValuePair.c to KVP_BUFFER_SIZE in keyValuePair.h
00033  *
00034  * Revision 1.13  2003/07/31 16:53:01  gjc
00035  * Invalidate old key and skip it from kvpFormat when overwriting in kvpParse
00036  *
00037  * Revision 1.12  2003/02/27 12:34:36  gjc
00038  * Robert Hatcher's mods to avoid warnings with gcc 3.2
00039  *
00040  * Revision 1.1  2003/02/25 21:18:41  rhatcher
00041  * key-value pair string en/decoding that the DAQ group uses.  Comes through
00042  * in the RawRunConfigBlock (which holds the "run prepare" string).
00043  * small modifications to "official" version to eliminate warning messages.
00044  *
00045  * Revision 1.11  2003/02/13 15:41:18  gjc
00046  * Increased MAXKEYS and check for exceding it in kvpParse
00047  *
00048  * Revision 1.10  2002/07/30 10:46:57  gjc
00049  * Use isspace() at the beginning of strings in stripSpaces as well as
00050  * the end.
00051  *
00052  * Revision 1.9  2002/06/14 08:30:45  gjc
00053  * Fixed bug with multiple floating point numbers with exponent field.
00054  * Also, allow for multiple definitions of a key with last value
00055  * overriding earlier settings.
00056  *
00057  * Revision 1.8  2001/07/24 17:19:55  gjc
00058  * Added new function kvpGetStringArray
00059  *
00060  * Revision 1.7  2001/06/26 12:05:40  gjc
00061  * 2 bugfixes.  Check that we've matched the whole key and not just an
00062  * initial substring.  Add 1 to length of record written by kvpWrite to
00063  * take account of the null terminator.
00064  *
00065  * Revision 1.6  2001/05/30 07:16:53  tcn
00066  * One ifdef moved to exclude all kvpSet... functions making use of kvpSet() -
00067  * fixes compile problems for VxWorks
00068  *
00069  * Revision 1.5  2001/05/23 10:35:53  gjc
00070  * Conditional compilation for VxWorks - skip functions using snprintf
00071  * for now,
00072  * Make kvpParse ignore from "//" to end of line to allow comments in
00073  * string being parsed.
00074  *
00075  * Revision 1.4  2001/05/16 11:52:09  gjc
00076  * Added new function kvpUpdateInt needed for run number kludge.
00077  * Removed reference to syslog and added new error code KVP_E_TERMINATOR
00078  * for missing semi-colon.
00079  *
00080  * Revision 1.3  2001/04/11 16:27:04  gjc
00081  * Stricter checking of numeric values in kvpParse.  Fixes bug with
00082  * inconsistent element count for hex values.
00083  * No longer start again at beginnning of internal buffers every time
00084  * kvpParse is a called.  Must call kvpReset before kvpParse if that's
00085  * what you want.
00086  *
00087  * Revision 1.2  2001/04/03 14:30:08  gjc
00088  * Return an error from kvpParse if the length field does not match the
00089  * length of the supplied values.
00090  * Ignore whitespace arounf key in kvpFindKey.
00091  *
00092  * Revision 1.1  2001/03/26 18:09:20  gjc
00093  * initial check in
00094  *
00095  *
00096  */ 
00097 
00098 /*
00099 DESCRIPTION
00100 <Insert a description of the file/module here>
00101 INCLUDE FILES: <place list of any relevant header files here>
00102 */
00103 
00104 /* includes */
00105 #include <string.h>
00106 #include <stdlib.h>
00107 #include <stdio.h>
00108 #include <unistd.h>
00109 #include <ctype.h>
00110 
00111 #include "keyValuePair.h"
00112 
00113 /* defines */
00114 
00115 /* typedefs */
00116 
00117 /* globals */   
00118 
00119 /* locals */
00120 static char* keyPtrs[MAXKEYS] ;
00121 static char* valPtrs[MAXKEYS] ;
00122 static KeyType valTypes[MAXKEYS] ;
00123 static int nelements[MAXKEYS] ;
00124 static int nkeys = 0 ;
00125 static char* kvpBuffer = NULL ;
00126 static int kvpBufferSize ;
00127 static char* spare = NULL ;
00128 static int spaceLeft = 0 ;
00129 static KvpErrorCode lastError = KVP_E_OK ;
00130 
00131 /* forward declarations */
00132 
00133 static void kvpRealloc (
00134                         int minExtension
00135                         )
00136 {
00137    char* newBuffer ;
00138    int newSize;
00139    int item ;
00140    int length ;
00141    int extension ;
00142 
00143    /* Allocate new buffer */
00144    if (minExtension < KVP_MIN_BUFFER_SIZE) {
00145       extension = KVP_MIN_BUFFER_SIZE ;
00146    }
00147    else {
00148       extension = minExtension ;
00149    }
00150 
00151    newSize = kvpBufferSize + extension ;
00152    newBuffer = malloc (newSize) ;
00153    spare = newBuffer ;
00154    spaceLeft = newSize ;
00155 
00156    /* Copy from old buffer, updating pointers as we go */
00157    for (item = 0; item < nkeys; item++) {
00158       keyPtrs[item] = strcpy (spare, keyPtrs[item]) ;
00159       length = strlen (keyPtrs[item]) + 1 ;
00160       spare += length ;
00161       spaceLeft -= length ;
00162 
00163       valPtrs[item] = strcpy (spare, valPtrs[item]) ;
00164       length = strlen (valPtrs[item]) + 1 ;
00165       spare += length ;
00166       spaceLeft -= length ;
00167    }
00168 
00169    /* Drop old buffer */
00170    free (kvpBuffer) ;
00171    kvpBuffer = newBuffer ;
00172    kvpBufferSize = newSize ;
00173 }
00174 
00175 void kvpDumpInternals (void)
00176 {
00177    printf ("kvpBuffer=%p spare=%p kvpBufferSize=%d spaceLeft=%d nkeys=%d\n",
00178            kvpBuffer,
00179            spare,
00180            kvpBufferSize,
00181            spaceLeft,
00182            nkeys) ;
00183 }
00184 
00185 /********************************************************************
00186 *
00187 * stripSpaces - Strip whitespace from beginning and end of string
00188 *
00189 * NB: This function modifies the input string in place!
00190 *
00191 * RETURNS: the stripped string
00192 *
00193 */
00194 static char* stripSpaces (char* string)
00195 {
00196    char* endPtr ;
00197    char* tPtr;
00198 
00199    while (isspace(*string)) {
00200       string++ ;
00201    }
00202 
00203    tPtr = string ;
00204    endPtr = string ;
00205    while (*tPtr != 0) {
00206       if (!isspace (*tPtr)) {
00207          endPtr = tPtr ;
00208       }
00209       tPtr++ ;
00210    }
00211    *(endPtr + 1) = 0 ;
00212 
00213    return (string) ;
00214 }
00215 
00216 static int validateValue (
00217                           char* value,
00218                           KeyType valType
00219                           )
00220 {
00221    int inNumber ;
00222    int hexCandidate ;
00223    int octalCandidate ;
00224    int decimalPoint ;
00225    int digit ;
00226    int count ;
00227    int exponent ;
00228 
00229    count = 0 ;
00230    inNumber = 0 ;
00231    hexCandidate = 0 ;
00232    octalCandidate = 0 ;
00233    decimalPoint = 0 ;
00234    exponent = 0 ;
00235    while (*value != 0) {
00236       if (valType == KT_STRING) {
00237          count++ ;
00238       }
00239       else {
00240          if (hexCandidate == 2) {
00241             digit = isxdigit (*value) ;
00242          }
00243          else {
00244             digit = isdigit (*value) ;
00245             if ((octalCandidate == 1) && (*value > '7')) {
00246                lastError = KVP_E_ILLNUMBER ;
00247                return (-1) ;
00248             }
00249          }
00250          if (digit) { 
00251             if (!inNumber) {
00252                count++ ;
00253                inNumber = 1 ;
00254                if ((*value == '0') && valType == KT_INT) {
00255                   /* It could be part of an 0x prefix */
00256                   hexCandidate = 1;
00257                }
00258                else {
00259                   hexCandidate = 0;
00260                }
00261             }
00262             else if (hexCandidate == 1) {
00263                /* Actually, surprisingly in this day and age,
00264                   it's an octal prefix */
00265                hexCandidate = 0 ;
00266                octalCandidate = 1 ;
00267                /* Better check that it's a valid octal digit */
00268                if (*value > '7') {
00269                   lastError = KVP_E_ILLNUMBER ;
00270                   return (-1) ;
00271                }
00272             }
00273          }
00274          else { /* not a digit */
00275             if ((hexCandidate == 1) && tolower (*value) == 'x') {
00276                hexCandidate = 2 ;
00277             }
00278             else if  ((*value == '+') || (*value == '-')) {
00279                if (inNumber) {
00280                   if (exponent != 1) {
00281                      /* sign in middle of number */
00282                      lastError = KVP_E_ILLNUMBER ;
00283                      return (-1) ;
00284                   }
00285                }
00286                else {
00287                   inNumber = 1 ;
00288                   count++ ;
00289                }
00290             }
00291             else if ((valType == KT_FLOAT) &&  (*value == '.')) {
00292                if (decimalPoint == 0) {
00293                   decimalPoint = 1 ;
00294                }
00295                else {
00296                   lastError = KVP_E_ILLNUMBER ;
00297                   return (-1) ;
00298                }
00299             }
00300             else if ((valType == KT_FLOAT) &&  tolower(*value) == 'e') {
00301                if (exponent == 0) {
00302                   exponent = 1 ;
00303                }
00304                else {
00305                   lastError = KVP_E_ILLNUMBER ;
00306                   return (-1) ;
00307                }
00308             }
00309             else { /* not part of '0x' and no decimal point */
00310                if ((*value == ' ') || (*value == '\t') ||
00311                    (*value == ',')) {
00312                   inNumber = 0 ;
00313                   hexCandidate = 0 ;
00314                   octalCandidate = 0 ;
00315                   decimalPoint = 0 ;
00316                   exponent = 0 ;
00317                }
00318                else {
00319                   lastError = KVP_E_ILLNUMBER ;
00320                   return (-1) ;
00321                }
00322             }
00323          }
00324       }
00325       value++ ;
00326    }
00327    return (count) ;
00328 }
00329 
00330 /********************************************************************
00331 *
00332 * kvpFindKey - Find key and return index into array
00333 *
00334 * <Insert longer description here>
00335 *
00336 * RETURNS: index of key or -1 if not found
00337 *
00338 */
00339 int kvpFindKey (
00340                 const char* key
00341                 )
00342 {
00343    int keynum ;
00344    int candidate ;
00345    const char* kStart ;
00346    int kLength ;
00347 
00348    candidate = -1 ;
00349    kStart = key ;
00350    while (isspace(*kStart)) {
00351      kStart++ ;
00352    }
00353    kLength = strlen (kStart) ;
00354    while ((kLength > 0) && isspace (kStart[kLength-1])) {
00355      kLength-- ;
00356    }
00357 
00358    for (keynum = 0 ; keynum < nkeys ; keynum++) {
00359       if ((strncmp (kStart, keyPtrs[keynum], kLength) == 0) &&
00360           (strlen (keyPtrs[keynum]) == (size_t)kLength)) {
00361          candidate = keynum ;
00362       }
00363    }
00364    return (candidate) ;
00365 }
00366 
00367 
00368 /********************************************************************
00369 *
00370 * kvpGetBase - Get an integer in the specified base.
00371 *
00372 * <Insert longer description here>
00373 *
00374 * RETURNS: <insert return values here>
00375 *
00376 */
00377 static int kvpGetBase (
00378                        const char* key,
00379                        int defaultValue,
00380                        int radix
00381                        )
00382 {
00383    int value ;
00384    int kValue ;
00385    char* valString ;
00386    char* endPtr ;
00387 
00388    value = defaultValue ;
00389 
00390    valString = kvpGetString (key) ;
00391    if (valString != NULL) {
00392       kValue = strtol (valString, &endPtr, radix) ;
00393       if (valString != endPtr) {
00394          value = kValue ;
00395          lastError = KVP_E_OK ;
00396       }
00397       else {
00398          lastError = KVP_E_BADVALUE ;
00399       }
00400    }
00401    else {
00402       lastError = KVP_E_NOTFOUND ;
00403    }
00404    return (value) ;
00405 }
00406 
00407 #ifndef VxWorks
00408 /********************************************************************
00409 *
00410 * kvpSet - Store a key/value pair
00411 *
00412 * <Insert longer description here>
00413 *
00414 * RETURNS: KVP_E_OK for success or error code
00415 *
00416 */
00417 static KvpErrorCode kvpSet (
00418                             const char *key,
00419                             const void *value,
00420                             KeyType type,
00421                             int count
00422                             )
00423 {
00424    int nchars ;
00425    int element ;
00426    int* iPtr ;
00427    float* fPtr ;
00428    int entry ;
00429    int valueSpace ;
00430    int keyLength ;
00431    int requiredSpace ;
00432 
00433    /* Make sure things have been initialised properly */
00434    if (spare == NULL) {
00435       kvpInit (0) ;
00436    }
00437 
00438    /* Check that this key does not already exist */
00439    entry = kvpFindKey (key) ;
00440    if (entry >= 0) {
00441       lastError = KVP_E_DUPLICATE ;
00442       return (lastError) ;
00443    }
00444 
00445    /* Check that we have space in the keys array */
00446    if (nkeys >= MAXKEYS) {
00447       lastError = KVP_E_TOOMANY ;
00448       return (lastError) ;
00449    }
00450 
00451    keyLength = strlen (key) + 1 ;
00452    requiredSpace = keyLength ;
00453    switch (type) {
00454    case KT_INT:
00455       requiredSpace += count * MAX_INT_LENGTH;
00456       break;
00457    case KT_FLOAT:
00458       requiredSpace += count * MAX_FLOAT_LENGTH;
00459       break;
00460    case KT_STRING:
00461       requiredSpace += strlen (value) ;
00462       break;
00463    default:
00464       lastError = KVP_E_BADTYPE ;
00465       return (lastError) ;
00466    }
00467 
00468 
00469    if (spaceLeft < requiredSpace) {
00470       kvpRealloc (requiredSpace) ;
00471    }
00472 
00473    /* Store the key in the next spare space in our buffer */
00474    keyPtrs[nkeys] = spare ;
00475    nchars = snprintf (spare, spaceLeft, "%s", key) ;
00476    if (nchars < 0) {
00477       lastError = KVP_E_SYSTEM ;
00478       return (lastError) ;
00479    }
00480 
00481    /* Check for illegal characters in key */
00482    if (strcspn (key, "=;,#") != (size_t)nchars) {
00483       lastError = KVP_E_BADKEY ;
00484       return (lastError) ;
00485    }
00486 
00487    /* Only update buffer pointers now we know key is OK */
00488    nchars++ ;
00489    valueSpace = spaceLeft - nchars ;
00490 
00491    valPtrs[nkeys] = spare + nchars ;
00492 
00493    switch (type) {
00494    case KT_INT:
00495       iPtr = (int*) value ;
00496       for (element = 0 ; element < count ; element++) {
00497          if (element > 0) {
00498             spare[nchars++] = ',' ;
00499          }
00500          nchars += snprintf (spare+nchars, valueSpace,
00501                              "%i", iPtr[element]) ;
00502          valueSpace = spaceLeft - nchars ;
00503          if (valueSpace < 1) {
00504             /* This should NEVER happen now */
00505             lastError = KVP_E_TOOLONG ;
00506             return (lastError) ;
00507          }
00508       }
00509       break ;
00510    case KT_FLOAT:
00511       fPtr = (float*) value ;
00512       for (element = 0 ; element < count ; element++) {
00513          if (element > 0) {
00514             spare[nchars++] = ',' ;
00515          }
00516          nchars += snprintf (spare+nchars, valueSpace,
00517                              "%g", fPtr[element]) ;
00518          valueSpace = spaceLeft - nchars ;
00519          if (valueSpace < 1) {
00520             /* This should NEVER happen now */
00521             lastError = KVP_E_TOOLONG ;
00522             return (lastError) ;
00523          }
00524       }
00525       break ;
00526    case KT_STRING:
00527       count = snprintf (spare+nchars, valueSpace,
00528                          "%s", (char *) value) ;
00529       if (count > valueSpace) {
00530          /* This should NEVER happen now */
00531          lastError = KVP_E_TOOLONG ;
00532          return (lastError) ;
00533       }
00534       nchars += count ;
00535       break ;
00536    default:
00537       lastError = KVP_E_BADTYPE ;
00538       return (lastError) ;
00539       break ;
00540    }
00541    if (nchars < 0) {
00542       lastError = KVP_E_SYSTEM ;
00543       return (lastError) ;
00544    }
00545 
00546    valTypes[nkeys] = type ;
00547    nelements[nkeys] = count ;
00548    nkeys++ ;
00549 
00550    nchars++ ;
00551    spare += nchars ;
00552    spaceLeft -= nchars ;
00553 
00554    lastError = KVP_E_OK ;
00555    return (lastError) ;
00556 }
00557 
00558 
00559 
00560 /********************************************************************
00561 *
00562 * kvpUpdate - Update value associated with known key
00563 *
00564 * <Insert longer description here>
00565 *
00566 * RETURNS: KVP_E_OK for success or error code
00567 *
00568 */
00569 static KvpErrorCode kvpUpdate (
00570                                const char *key,
00571                                const void *value,
00572                                KeyType type,
00573                                int count
00574                                )
00575 {
00576    int nchars ;
00577    int element ;
00578    int* iPtr ;
00579    float* fPtr ;
00580    int entry ;
00581    int requiredSpace ;
00582 
00583    /* Find the key */
00584    entry = kvpFindKey (key) ;
00585    if (entry < 0) {
00586       lastError = KVP_E_NOTFOUND ;
00587       return (lastError) ;
00588    }
00589 
00590    if (valTypes[entry] != type) {
00591       lastError = KVP_E_BADVALUE ;
00592       return (lastError) ;
00593    }
00594 
00595    switch (type) {
00596    case KT_INT:
00597       requiredSpace = count * MAX_INT_LENGTH;
00598       break;
00599    case KT_FLOAT:
00600       requiredSpace = count * MAX_FLOAT_LENGTH;
00601       break;
00602    case KT_STRING:
00603       requiredSpace = strlen (value) ;
00604       break;
00605    default:
00606       lastError = KVP_E_BADTYPE ;
00607       return (lastError) ;
00608       break ;
00609    }
00610 
00611    if (spaceLeft < requiredSpace) {
00612       kvpRealloc (requiredSpace) ;
00613    }
00614 
00615    /* Write the new value at the first spare point in our buffer.
00616       Note that we don't free up the space used by the previous value */
00617    nchars = 0 ;
00618    valPtrs[entry] = spare ;
00619    switch (type) {
00620    case KT_INT:
00621       iPtr = (int*) value ;
00622       for (element = 0 ; element < count ; element++) {
00623          if (element > 0) {
00624             spare[nchars++] = ',' ;
00625          }
00626          nchars += snprintf (spare+nchars, spaceLeft-nchars,
00627                              "%i", iPtr[element]) ;
00628       }
00629       break ;
00630    case KT_FLOAT:
00631       fPtr = (float*) value ;
00632       for (element = 0 ; element < count ; element++) {
00633          if (element > 0) {
00634             spare[nchars++] = ',' ;
00635          }
00636          nchars += snprintf (spare+nchars, spaceLeft-nchars,
00637                              "%g", fPtr[element]) ;
00638       }
00639       break ;
00640    case KT_STRING:
00641       count = snprintf (spare+nchars, spaceLeft-nchars,
00642                          "%s", (char *) value) ;
00643       nchars += count ;
00644       break ;
00645    default:
00646       lastError = KVP_E_BADTYPE ;
00647       return (lastError) ;
00648    }
00649    if (nchars < 0) {
00650       lastError = KVP_E_SYSTEM ;
00651       return (lastError) ;
00652    }
00653 
00654    nelements[entry] = count ;
00655 
00656    nchars++ ;
00657    spare += nchars ;
00658    spaceLeft -= nchars ;
00659 
00660    lastError = KVP_E_OK ;
00661    return (lastError) ;
00662 }
00663 #endif  /* VxWorks */
00664 
00665 /********************************************************************
00666 *
00667 * kvpParse - Find the start of each key/value pair in given buffer
00668 *
00669 * <Insert longer description here>
00670 *
00671 * RETURNS: number of keys/values found
00672 *
00673 */
00674 int kvpParse (
00675               const char* record
00676               )
00677 {
00678    char* myPtr ;
00679    char* key ;
00680    char* value ;
00681    char typeChar ;
00682    int count ;
00683    int reclen ;
00684    int oldKeyNumber ;
00685 
00686    /* Make sure things have been initialised properly */
00687    reclen = strlen (record) + 1 ;
00688 
00689    if (spare == NULL) {
00690       kvpInit (reclen) ;
00691    }
00692 
00693    if (reclen > spaceLeft) {
00694       kvpRealloc (reclen) ;
00695    }
00696    
00697    /* Take a local copy of the input record */
00698    strncpy (spare, record, reclen) ;
00699 
00700    myPtr = spare;
00701    while (isspace(*myPtr)) {
00702       myPtr++ ;
00703    }
00704 
00705    /* Find the Key Value pairs in our copy and remember where they are */
00706    do {
00707       key = myPtr ;
00708       myPtr = strchr (myPtr, '#') ;
00709       /* Simplistic test if there isn't a hash sign there isn't
00710          another key/value pair. */
00711       if (myPtr != NULL) {
00712          if (nkeys >= MAXKEYS) {
00713             lastError = KVP_E_TOOMANY ;
00714             return (-1) ;
00715          }
00716          /* terminate key string excluding # */
00717          *myPtr++ = 0 ;
00718          /* Save key without surrounding whitespace */
00719          key = stripSpaces (key) ;
00720          /* Ignore comments introduced by // */
00721          if ((key[0] == '/') && (key[1] == '/')) {
00722             myPtr = NULL ;
00723             break ;
00724          }
00725          keyPtrs[nkeys] = key ;
00726 
00727          /* Invalidate old entry for this key if we have one */
00728          oldKeyNumber = kvpFindKey (key) ;
00729          if (oldKeyNumber >= 0) {
00730             valTypes[oldKeyNumber] = KT_INVALID ;
00731          }
00732 
00733          /* extract type info */
00734          typeChar = *myPtr++ ;
00735          switch (typeChar) {
00736          case 'I':
00737             valTypes[nkeys] = KT_INT ;
00738             break ;
00739          case 'F':
00740             valTypes[nkeys] = KT_FLOAT ;
00741             break ;
00742          case 'S':
00743             valTypes[nkeys] = KT_STRING ;
00744             break ;
00745          }
00746 
00747          /* Check for specification of number of elements */
00748          if (*myPtr == '=') {
00749             nelements[nkeys] = 0 ;
00750          }
00751          else {
00752             /* Read array length from folowing chars */
00753             nelements[nkeys] = strtol (myPtr, &myPtr, 10) ;
00754          }
00755 
00756          /* Save the value */
00757          if (*myPtr == '=') {
00758             myPtr++ ;
00759             value = myPtr ;
00760             /* The value ends at the next semicolon */
00761             myPtr = strchr (myPtr, ';') ;
00762             if (myPtr == NULL) {
00763                lastError = KVP_E_TERMINATOR ;
00764                reclen++ ;
00765             }
00766             else {
00767                /* strip the semicolon */
00768                *myPtr++ = 0 ;
00769             }
00770             valPtrs[nkeys] = value ;
00771 
00772             /* Count the number of elements in the value and check
00773                validity of numbers */
00774             count = validateValue (value, valTypes[nkeys]) ;
00775             if (count < 0) {
00776                return (count) ;
00777             }
00778             if (nelements[nkeys] == 0) {
00779                nelements[nkeys] = count ;
00780             }
00781             else if (nelements[nkeys] != count) {
00782                lastError = KVP_E_WRONGCOUNT ;
00783                return (-1) ;
00784             }
00785             nkeys++ ;
00786          }
00787          else {
00788             lastError = KVP_E_BADINPUT ;
00789             return (-1) ;
00790          }
00791       }
00792    } while (myPtr != NULL) ;
00793 
00794    spare += reclen ;
00795    spaceLeft -= reclen ;
00796 
00797    lastError = KVP_E_OK ;
00798    return (nkeys) ;
00799 }
00800 
00801 /********************************************************************
00802 *
00803 * kvpReset - Reset buffers and counters
00804 *
00805 * <Insert longer description here>
00806 *
00807 * RETURNS: N/A
00808 *
00809 */
00810 void kvpReset (void)
00811 {
00812    if (kvpBuffer != NULL) {
00813       free (kvpBuffer) ;
00814    }
00815    spare = kvpBuffer = NULL ;
00816    spaceLeft = 0 ;
00817    nkeys = 0 ;
00818 }
00819 
00820 void kvpInit (
00821               int bufferSize
00822               )
00823 {
00824    if (bufferSize > KVP_MIN_BUFFER_SIZE) {
00825       kvpBufferSize = bufferSize ;
00826    }
00827    else {
00828       kvpBufferSize = KVP_MIN_BUFFER_SIZE ;
00829    }
00830 
00831    kvpBuffer = malloc(kvpBufferSize) ;
00832    spare = kvpBuffer ;
00833    spaceLeft = kvpBufferSize ;
00834 }
00835 
00836 int kvpQueryLength (const char* key) {
00837    int keynum ;
00838 
00839    keynum = kvpFindKey (key) ;
00840    if (keynum >= 0) {
00841      lastError = KVP_E_OK ;
00842      return (nelements[keynum]) ;
00843    }
00844    else {
00845      lastError = KVP_E_NOTFOUND ;
00846      return (0) ;
00847    }
00848 }
00849 
00850 /********************************************************************
00851 *
00852 * kvpGetEntry - Get entry by index
00853 *
00854 * <Insert longer description here>
00855 *
00856 * RETURNS: KVP_E_OK ==> success,  KVP_E_NOTFOUND if entry outside
00857 *         valid range
00858 *
00859 */
00860 KvpErrorCode kvpGetEntry (
00861                           int entry,
00862                           char** key,
00863                           KeyType* type,
00864                           int* size,
00865                           char** value
00866                           )
00867 {
00868    if (entry < nkeys) {
00869      *key = keyPtrs[entry] ;
00870      *type = valTypes[entry] ;
00871      *value = valPtrs[entry] ;
00872      *size = nelements[entry] ;
00873      return (KVP_E_OK) ;
00874    }
00875    else {
00876      return (KVP_E_NOTFOUND) ;
00877    }
00878 }
00879 
00880 /********************************************************************
00881 *
00882 * kvpGetString - Get value associated with key as a string
00883 *
00884 * <Insert longer description here>
00885 *
00886 * RETURNS: string associated with given key or NULL if error
00887 *
00888 */
00889 char* kvpGetString (
00890                     const char* key
00891                     )
00892 {
00893    int keynum ;
00894 
00895    keynum = kvpFindKey (key) ;
00896    if (keynum >= 0) {
00897      lastError = KVP_E_OK ;
00898      return (valPtrs[keynum]) ;
00899    }
00900    else {
00901      lastError = KVP_E_NOTFOUND ;
00902      return (NULL) ;
00903    }
00904 }
00905 
00906 /********************************************************************
00907 *
00908 * kvpGetStringArray - Get value associated with key as array of strings
00909 *
00910 * <Insert longer description here>
00911 *
00912 * RETURNS:  
00913 *
00914 */
00915 KvpErrorCode kvpGetStringArray (
00916                                 const char* key,
00917                                 char* values,
00918                                 int  maxlen,
00919                                 int* entries
00920                                 )
00921 {
00922    char* valString ;
00923    int index ;
00924    int element ;
00925    int length ;
00926    int end ;
00927 
00928    lastError = KVP_E_OK ;
00929    index = kvpFindKey (key) ;
00930    if (index >= 0) {
00931       if (valTypes[index] == KT_STRING) {
00932          valString = valPtrs[index] ;
00933       }
00934       element = 0 ;
00935       length = 0 ;
00936       lastError = KVP_E_OK ;
00937       end = 0 ;
00938 
00939       do {
00940          if (*valString == 0) {
00941             end = 1 ;
00942          }
00943 
00944          if (*valString == ',') {
00945             values[element*maxlen+length] = 0 ;
00946             element++ ;
00947             length = 0 ;
00948             if (element == *entries) {
00949                lastError = KVP_E_TRUNCATE ;
00950             }
00951          }
00952          else {
00953             values[element*maxlen+length] = *valString ;
00954             length++ ;
00955             if (length == maxlen) {
00956                lastError = KVP_E_TRUNCATE ;
00957             }
00958          }
00959          valString++ ;
00960       } while (!end  && (lastError == KVP_E_OK)) ;
00961 
00962 
00963       *entries = element + 1 ;
00964    }
00965    else {
00966       lastError = KVP_E_NOTFOUND ;
00967    }
00968    return (lastError) ;
00969 }
00970 
00971 /********************************************************************
00972 *
00973 * kvpGetHex - Get value associated with key as a hex integer
00974 *
00975 * <Insert longer description here>
00976 *
00977 * RETURNS: see kvpGetBase
00978 *
00979 */
00980 int kvpGetHex (
00981                const char* key,
00982                int defaultValue
00983                )
00984 {
00985    return (kvpGetBase (key, defaultValue, 16)) ;
00986 }
00987 
00988 /********************************************************************
00989 *
00990 * kvpGetDec - Get value associated with key as a decimal integer
00991 *
00992 * <Insert longer description here>
00993 *
00994 * RETURNS:  see kvpGetBase
00995 *
00996 */
00997 int kvpGetDec (
00998                const char* key,
00999                int defaultValue
01000                )
01001 {
01002    return (kvpGetBase (key, defaultValue, 10)) ;
01003 }
01004 
01005 
01006 
01007 /********************************************************************
01008 *
01009 * kvpGetDec - Get value associated with key as an integer
01010 *
01011 * <Insert longer description here>
01012 *
01013 * RETURNS:  see kvpGetBase
01014 *
01015 */
01016 int kvpGetInt (
01017                const char* key,
01018                int defaultValue
01019                )
01020 {
01021    return (kvpGetBase (key, defaultValue, 0)) ;
01022 }
01023 
01024 
01025 /********************************************************************
01026 *
01027 * kvpGetIntArray - Get value associated with key as array of integers
01028 *
01029 * <Insert longer description here>
01030 *
01031 * RETURNS:  
01032 *
01033 */
01034 KvpErrorCode kvpGetIntArray (
01035                              const char* key,
01036                              int* values,
01037                              int* entries
01038                              )
01039 {
01040    char* valString ;
01041    char* endPtr ;
01042    int index ;
01043    int element ;
01044 
01045    lastError = KVP_E_OK ;
01046    index = kvpFindKey (key) ;
01047    if (index >= 0) {
01048       if (valTypes[index] == KT_INT) {
01049          valString = valPtrs[index] ;
01050 
01051          if (nelements[index] <= *entries) {
01052             *entries = nelements[index] ;
01053          }
01054          else {
01055             lastError = KVP_E_TRUNCATE ;
01056          }
01057          for (element = 0 ; element < *entries ; element++) {
01058             values[element] = strtol (valString, &endPtr, 0) ;
01059             if (valString == endPtr) {
01060                lastError = KVP_E_BADVALUE ;
01061                lastError = KVP_E_BADVALUE ;
01062                break ;
01063             }
01064             valString = endPtr + 1 ;
01065          }
01066       }
01067       else {
01068          lastError = KVP_E_BADVALUE ;
01069       }
01070    }
01071    else {
01072       lastError = KVP_E_NOTFOUND ;
01073    }
01074    return (lastError) ;
01075 }
01076 
01077 
01078 /********************************************************************
01079 *
01080 * kvpGetFloatArray - Get value associated with key as an array of integers
01081 *
01082 * <Insert longer description here>
01083 *
01084 * RETURNS:  
01085 *
01086 */
01087 KvpErrorCode kvpGetFloatArray (
01088                              const char* key,
01089                              float* values,
01090                              int* entries
01091                              )
01092 {
01093    char* valString ;
01094    char* endPtr ;
01095    int index ;
01096    int element ;
01097 
01098    lastError = KVP_E_OK ;
01099    index = kvpFindKey (key) ;
01100    if (index >= 0) {
01101       if (valTypes[index] == KT_FLOAT) {
01102          valString = valPtrs[index] ;
01103 
01104          if (nelements[index] <= *entries) {
01105             *entries = nelements[index] ;
01106          }
01107          else {
01108             lastError = KVP_E_TRUNCATE ;
01109          }
01110          for (element = 0 ; element < *entries ; element++) {
01111             values[element] = strtod (valString, &endPtr) ;
01112             if (valString == endPtr) {
01113                lastError = KVP_E_BADVALUE ;
01114                lastError = KVP_E_BADVALUE ;
01115                break ;
01116             }
01117             valString = endPtr + 1 ;
01118          }
01119       }
01120       else {
01121          lastError = KVP_E_BADVALUE ;
01122       }
01123    }
01124    else {
01125       lastError = KVP_E_NOTFOUND ;
01126    }
01127    return (lastError) ;
01128 }
01129 
01130 /********************************************************************
01131 *
01132 * kvpGetDouble - Get value associated with key as a double
01133 *
01134 * <Insert longer description here>
01135 *
01136 * RETURNS: value if found else the defauly value given.
01137 *
01138 */
01139 double kvpGetDouble (
01140                      const char* key,
01141                      double defaultValue
01142                      )
01143 {
01144    double value ;
01145    double kValue ;
01146    char* valString ;
01147    char* endPtr ;
01148 
01149    value = defaultValue ;
01150 
01151    valString = kvpGetString (key) ;
01152    if (valString != NULL) {
01153       kValue = strtod (valString, &endPtr) ;
01154       if (valString != endPtr) {
01155          value = kValue ;
01156          lastError = KVP_E_OK ;
01157       }
01158       else {
01159          lastError = KVP_E_BADVALUE ;
01160       }
01161    }
01162    else {
01163       lastError = KVP_E_NOTFOUND ;
01164    }
01165    return (value) ;
01166 }
01167 
01168 
01169 /********************************************************************
01170 *
01171 * kvpGetFloat - Get value associated with key as a float
01172 *
01173 * <Insert longer description here>
01174 *
01175 * RETURNS: See kvpGetDouble
01176 *
01177 */
01178 float kvpGetFloat (
01179                    const char* key,
01180                    float defaultValue
01181                    )
01182 {
01183    return ((float) kvpGetDouble (key, (double) defaultValue)) ;
01184 }
01185 
01186 
01187 #ifndef VxWorks
01188 /********************************************************************
01189 *
01190 * kvpSetString - Store a key value pair with a string value
01191 *
01192 * <Insert longer description here>
01193 *
01194 * RETURNS: <insert return values here>
01195 *
01196 */
01197 KvpErrorCode kvpSetString (
01198                            const char* key,
01199                            const char* value
01200                            )
01201 {
01202    return (kvpSet (key, value, KT_STRING, 1)) ;
01203 }
01204 
01205 /********************************************************************
01206 *
01207 * kvpSetIntArray - Store a key value pair with an int value
01208 *
01209 * <Insert longer description here>
01210 *
01211 * RETURNS: <insert return values here>
01212 *
01213 */
01214 KvpErrorCode kvpSetIntArray (
01215                              const char* key,
01216                              const int* values,
01217                              int count
01218                              )
01219 {
01220    return (kvpSet (key, values, KT_INT, count)) ;
01221 }
01222 /********************************************************************
01223 *
01224 * kvpSetFloatArray - Store a key value pair with an int value
01225 *
01226 * <Insert longer description here>
01227 *
01228 * RETURNS: <insert return values here>
01229 *
01230 */
01231 KvpErrorCode kvpSetFloatArray (
01232                                const char* key,
01233                                const float* values,
01234                                int count
01235                                )
01236 {
01237    return (kvpSet (key, values, KT_FLOAT, count)) ;
01238 }
01239 
01240 /********************************************************************
01241 *
01242 * kvpSetInt - Store a key value pair with an int value
01243 *
01244 * <Insert longer description here>
01245 *
01246 * RETURNS: <insert return values here>
01247 *
01248 */
01249 KvpErrorCode kvpSetInt (
01250                         const char* key,
01251                         int value
01252                         )
01253 {
01254    return (kvpSet (key, &value, KT_INT, 1)) ;
01255 }
01256 
01257 /********************************************************************
01258 *
01259 * kvpUpdateInt - Update a key value pair with an int value
01260 *
01261 * <Insert longer description here>
01262 *
01263 * RETURNS: <insert return values here>
01264 *
01265 */
01266 KvpErrorCode kvpUpdateInt (
01267                            const char* key,
01268                            int value
01269                         )
01270 {
01271    return (kvpUpdate (key, &value, KT_INT, 1)) ;
01272 }
01273 
01274 
01275 /********************************************************************
01276 *
01277 * kvpSetFloat - Store a key value pair with a float value
01278 *
01279 * <Insert longer description here>
01280 *
01281 * RETURNS: <insert return values here>
01282 *
01283 */
01284 KvpErrorCode kvpSetFloat (
01285                           const char* key,
01286                           float value
01287                           )
01288 {
01289    return (kvpSet (key, &value, KT_FLOAT, 1)) ;
01290 }
01291 
01292 /********************************************************************
01293 *
01294 * kvpWrite - Write out all key value pairs to given stream
01295 *
01296 * <Insert longer description here>
01297 *
01298 * RETURNS: Number of characters written or -1 for error
01299 *
01300 */
01301 int kvpWrite (
01302               int stream
01303               )
01304 {
01305    char* buffer ;
01306    int reclen ;
01307    int lengthWritten ;
01308 
01309    buffer = malloc (kvpBufferSize) ;
01310    reclen = kvpFormat (buffer, kvpBufferSize) + 1 ;
01311    lengthWritten = write (stream, buffer, reclen)  ;
01312    free (buffer) ;
01313    return (lengthWritten) ;
01314 }
01315 
01316 
01317 /********************************************************************
01318 *
01319 * kvpFormat - Write all key value pairs to given buffer
01320 *
01321 * <Insert longer description here>
01322 *
01323 * RETURNS: Number of characters written (not including the terminating
01324 * 0) or -1 for error
01325 *
01326 */
01327 int kvpFormat (
01328                char* buffer,
01329                int bufferSize
01330                )
01331 {
01332    int entry ;
01333    int offset ;
01334    int nchars ;
01335    const char* type ;
01336 
01337    offset = 0 ;
01338    for (entry = 0 ; entry < nkeys ; entry++) {
01339       switch (valTypes[entry]) {
01340       case KT_INVALID:
01341          /* skip it */
01342          continue;
01343       case KT_INT:
01344          type = "I" ;
01345          break ;
01346       case KT_FLOAT:
01347          type = "F" ;
01348          break ;
01349       case KT_STRING:
01350       default:
01351          type = "S" ;
01352       }
01353 
01354       nchars = snprintf (&buffer[offset], bufferSize-offset,
01355                          "%s#%s%d=%s;",
01356                          keyPtrs[entry], type, nelements[entry],
01357                          valPtrs[entry]) ;
01358 
01359       if ((nchars > bufferSize-offset) || (nchars == -1)) {
01360          return (-1) ;
01361       }
01362       offset += nchars ;
01363    }
01364    return (offset) ;
01365 }
01366 #endif /* VxWorks */
01367 
01368 /********************************************************************
01369 *
01370 * kvpPrintError - Print the error message corresponding to code
01371 *
01372 * <Insert longer description here>
01373 *
01374 * RETURNS: N/A
01375 *
01376 */
01377 void kvpPrintError (
01378                     KvpErrorCode code
01379                     )
01380 {
01381    fprintf (stderr, "kvp error -- %s\n", kvpErrorString (code)) ;
01382 }
01383 
01384 
01385 /********************************************************************
01386 *
01387 * kvpErrorString - Find the error message corresponding to code
01388 *
01389 * <Insert longer description here>
01390 *
01391 * RETURNS: Error as character string
01392 *
01393 */
01394 const 
01395 char* kvpErrorString (
01396                       KvpErrorCode code
01397                       )
01398 {
01399    const char* result ;
01400 
01401    switch (code) {
01402    case KVP_E_OK:
01403       result = "Success" ;
01404       break ;
01405    case KVP_E_DUPLICATE:
01406       result = "Duplicate key" ;
01407       break ;
01408    case KVP_E_NOTFOUND:
01409       result = "Key not found" ;
01410       break ;
01411    case KVP_E_SYSTEM:
01412       result = "error from system function:" ;
01413       break ;
01414    case KVP_E_BADTYPE:
01415       result = "Type not supported" ;
01416       break ;
01417    case KVP_E_BADKEY:
01418       result = "Illegal characters in key" ;
01419       break ;
01420    case KVP_E_BADVALUE:
01421       result = "value not valid in requested type" ;
01422       break ;
01423    case KVP_E_TOOMANY:
01424       result = "Maximum number of keys exceeded" ;
01425       break ;
01426    case KVP_E_TOOLONG:
01427       result = "record too long to parse" ;
01428       break ;
01429    case KVP_E_BADINPUT:
01430       result = "Syntax error in input" ;
01431       break ;
01432    case KVP_E_TRUNCATE:
01433       result = "Array truncated" ;
01434       break ;
01435    case KVP_E_WRONGCOUNT:
01436       result = "inconsistent element count" ;
01437       break ;
01438    case KVP_E_ILLNUMBER:
01439       result = "illegal character in number" ;
01440       break ;
01441    case KVP_E_TERMINATOR:
01442       result = "missing terminator on input string" ;
01443       break ;
01444    default:
01445       result = "unknown error" ;
01446    }
01447    return (result) ;
01448 }
01449 
01450 
01451 /********************************************************************
01452 *
01453 * kvpError - Return the id of the last error that occured
01454 *
01455 * <Insert longer description here>
01456 *
01457 * RETURNS: error code
01458 *
01459 */
01460 KvpErrorCode kvpError (void)
01461 {
01462    return (lastError) ;
01463 }

Generated on Mon Feb 15 11:06:50 2010 for loon by  doxygen 1.3.9.1