lib/keys.c

Go to the documentation of this file.
00001 /* keys.c - Stuff to manage a little key/value pair table and
00002  * evaluate expressions on it. 
00003  *
00004  * This file is copyright 2002 Jim Kent, but license is hereby
00005  * granted for all use - public, private or commercial. */
00006 
00007 #include "common.h"
00008 #include "keys.h"
00009 #include "kxTok.h"
00010 
00011 static char const rcsid[] = "$Id: keys.c,v 1.10 2005/04/10 14:41:23 markd Exp $";
00012 
00013 struct kvt
00014 /* Key/value table. */
00015     {
00016     int used;             /* Number of keys used in table. */
00017     int alloced;          /* Number allocated in table. */
00018     struct keyVal *table; /* The table itself. */
00019     };
00020 
00021 struct kvt *newKvt(int size)
00022 /* Get a new key value table. */
00023 {
00024 struct kvt *kvt;
00025 AllocVar(kvt);
00026 kvt->alloced = size;
00027 kvt->table = needMem(size * sizeof(kvt->table[0]));
00028 return kvt;
00029 }
00030 
00031 
00032 void freeKvt(struct kvt **pKvt)
00033 /* Free up key value table. */
00034 {
00035 struct kvt *kvt;
00036 if ((kvt = *pKvt) != NULL)
00037     {
00038     freeMem(kvt->table);
00039     freez(pKvt);
00040     }
00041 }
00042 
00043 void kvtClear(struct kvt *kvt)
00044 /* Clear the keys table. */
00045 {
00046 kvt->used = 0;
00047 }
00048 
00049 struct keyVal *kvtAdd(struct kvt *kvt, char *key, char *val)
00050 /* Add in new key. */
00051 {
00052 struct keyVal *kv;
00053 if (kvt->used == kvt->alloced)
00054     errAbort("Too many keys in keyVal(%s %s)", key, val);
00055 kv = &kvt->table[kvt->used++];
00056 kv->key = key;
00057 kv->val = val;
00058 return kv;
00059 }
00060 
00061 void kvtParseAdd(struct kvt *kvt, char *text)
00062 /* Add in keys from text.  Text is in format:
00063  *     key val
00064  * for each line of text. Text gets many of it's
00065  * space characters and newlines replaced by 0's
00066  * and should persist until call to keysClear(). */
00067 {
00068 char *lines[256];
00069 int lineCount;
00070 int i;
00071 char *k, *v;
00072 
00073 lineCount = chopString(text, "\n\r", lines, ArraySize(lines));
00074 for (i=0; i<lineCount; ++i)
00075     {
00076     k = lines[i];
00077     if ((v = strchr(k, ' ')) != NULL)
00078         {
00079         *v++ = 0;
00080         kvtAdd(kvt, k, v);
00081         }
00082     }
00083 }
00084 
00085 struct keyVal* kvtGet(struct kvt *kvt, char *key)
00086 /* get the keyVal for the specified key, of NULL if not found. */
00087 {
00088 int i;
00089 struct keyVal *keyTable = kvt->table;
00090 int keysUsed = kvt->used;
00091 
00092 for (i=0; i<keysUsed; ++i)
00093     {
00094     if (sameString(key, keyTable[i].key))
00095         return &keyTable[i];
00096     }
00097 return NULL;
00098 }
00099 
00100 char *kvtLookup(struct kvt *kvt, char *key)
00101 /* Search table for key.  Return key value, or NULL if
00102  * key not found. */
00103 {
00104 struct keyVal *keyVal = kvtGet(kvt, key);
00105 if (keyVal == NULL)
00106     return NULL;
00107 else
00108     return keyVal->val;
00109 }
00110 
00111 void kvtWriteAll(struct kvt *kvt, FILE *f, struct slName *hideList)
00112 /* Write all keys to file except the ones in hideList */
00113 {
00114 int i;
00115 static char lf = '\n';
00116 struct keyVal *kv = kvt->table;
00117 int keyCount = kvt->used;
00118 
00119 for (i=0; i<keyCount; ++i)
00120     {
00121     char *key = kv->key;
00122     if (kv->val != NULL && !slNameInList(hideList, key))
00123         fprintf(f, "%s %s\n", key, kv->val);
00124     ++kv;
00125     }
00126 mustWrite(f, &lf, 1);   /* Instead of fputc for error checking. */
00127 }
00128 
00129 
00130 /* Expression evaluator - evaluates a parsed tree. */
00131 enum keyExpType
00132     {
00133     kxMatch,
00134     kxWildMatch,
00135     kxGT,      /* Greater Than */
00136     kxGE,      /* Greater Than or Equal */
00137     kxLT,      /* Less Than */
00138     kxLE,      /* Less Than or Equal */
00139     kxAnd,
00140     kxOr,
00141     kxNot,
00142     kxXor,
00143     };
00144 
00145 struct exp
00146     {
00147     void *left;
00148     void *right;
00149     enum keyExpType type;
00150     };
00151 
00152 static void getIntVals(struct kvt *kvt, struct exp *exp, int *retLeft, int *retRight)
00153 /* Look up value for key on left hand side of expression and
00154  * literal string from right hand side.  Convert both to ints. */
00155 {
00156 char *rightString = exp->right;
00157 char *leftKey = exp->left;
00158 char *leftString = kvtLookup(kvt, leftKey);
00159 
00160 if (leftString == NULL)
00161     *retLeft = 0;
00162 else
00163     *retLeft = atoi(leftString);
00164 if (rightString == NULL)
00165     *retRight = 0;
00166 else
00167     *retRight = atoi(rightString);
00168 }
00169 
00170 #if 0 /* unused */
00171 static void dumpExp(struct kvt *kvt, struct exp *exp)
00172 /* Print out expression. */
00173 {
00174 switch (exp->type)
00175     {
00176     case kxMatch:
00177         {
00178         char *key = exp->left;
00179         char *matcher = exp->right;
00180         char *val = kvtLookup(kvt, key);
00181         printf("%s(%s) match %s\n", key, val, matcher);
00182         break;
00183         }
00184     case kxWildMatch:
00185         {
00186         char *key = exp->left;
00187         char *matcher = exp->right;
00188         char *val = kvtLookup(kvt, key);
00189         printf("%s(%s) wildMatch %s\n", key, val, matcher);
00190         break;
00191         }
00192     case kxGT:
00193         {
00194         int left, right;
00195         getIntVals(kvt, exp, &left, &right);
00196         printf("%d > %d\n", left, right);
00197         break;
00198         }
00199     case kxGE:
00200         {
00201         int left, right;
00202         getIntVals(kvt, exp, &left, &right);
00203         printf("%d >= %d\n", left, right);
00204         break;
00205         }
00206     case kxLT:
00207         {
00208         int left, right;
00209         getIntVals(kvt, exp, &left, &right);
00210         printf("%d < %d\n", left, right);
00211         break;
00212         }
00213     case kxLE:
00214         {
00215         int left, right;
00216         getIntVals(kvt, exp, &left, &right);
00217         printf("%d <= %d\n", left, right);
00218         break;
00219         }
00220     
00221     case kxNot:
00222         {
00223         printf("!\n");
00224         break;
00225         }
00226     case kxAnd:
00227         {
00228         printf("&\n");
00229         break;
00230         }
00231     case kxOr:
00232         {
00233         printf("|\n");
00234         break;
00235         }
00236     case kxXor:
00237         {
00238         printf("^\n");
00239         break;
00240         }
00241     }
00242 }
00243 #endif
00244 
00245 static boolean rkeyEval(struct kvt *kvt, struct exp *exp)
00246 /* Recursively evaluate expression. */
00247 {
00248 if (exp == NULL)
00249     return TRUE;
00250 switch (exp->type)
00251     {
00252     case kxMatch:
00253         {
00254         char *key = exp->left;
00255         char *matcher = exp->right;
00256         char *val = kvtLookup(kvt, key);
00257         if (val == NULL)
00258             return sameWord(matcher, "null");
00259         else
00260             return sameWord(matcher, val);
00261         }
00262     case kxWildMatch:
00263         {
00264         char *key = exp->left;
00265         char *matcher = exp->right;
00266         char *val = kvtLookup(kvt, key);
00267         if (val == NULL)
00268             return sameString(matcher, "*");
00269         else
00270             return wildMatch(matcher, val);
00271         }
00272     case kxGT:
00273         {
00274         int left, right;
00275         getIntVals(kvt, exp, &left, &right);
00276         return left > right;
00277         }
00278     case kxGE:
00279         {
00280         int left, right;
00281         getIntVals(kvt, exp, &left, &right);
00282         return left >= right;
00283         }
00284     case kxLT:
00285         {
00286         int left, right;
00287         getIntVals(kvt, exp, &left, &right);
00288         return left < right;
00289         }
00290     case kxLE:
00291         {
00292         int left, right;
00293         getIntVals(kvt, exp, &left, &right);
00294         return left <= right;
00295         }
00296     
00297     case kxNot:
00298         {
00299         return !rkeyEval(kvt, exp->right);
00300         }
00301     case kxAnd:
00302         {
00303         return rkeyEval(kvt, exp->left) && rkeyEval(kvt, exp->right);
00304         }
00305     case kxOr:
00306         {
00307         return rkeyEval(kvt, exp->left) || rkeyEval(kvt, exp->right);
00308         }
00309     case kxXor:
00310         {
00311         return rkeyEval(kvt, exp->left) ^ rkeyEval(kvt, exp->right);
00312         }
00313     default:
00314         {
00315         errAbort("unknown expression type %d", exp->type);
00316         return 0;
00317         }
00318     }
00319 }
00320 
00321 boolean keyExpEval(struct keyExp *keyExp, struct kvt *kvt)
00322 /* Evaluate key expression. */
00323 {
00324 return rkeyEval(kvt, keyExp->rootExp);
00325 }
00326 
00327 /***** A little recursive descent parser. *****/
00328 
00329 static struct kxTok *token;      /* Next token for parser. */
00330 
00331 static void advanceToken()
00332 /* Move to next token. */
00333 {
00334 token = token->next;
00335 }
00336 
00337 static struct exp *nextExp();       /* Get next expression. */
00338 
00339 static struct exp *parseRelation()
00340 /* Parse key=wildcard. */
00341 {
00342 struct kxTok *key, *match;
00343 
00344 if (token == NULL)
00345     return NULL;
00346 if (token->type != kxtString)
00347     errAbort("Expecting key got %s", token->string);
00348 key = token;
00349 advanceToken();
00350 if (token->type == kxtEquals)
00351     {
00352     advanceToken();
00353     if (token->type == kxtString || token->type == kxtWildString)
00354         {
00355         struct exp *exp;
00356         match = token;
00357         advanceToken();
00358         AllocVar(exp);
00359         exp->left = key->string;
00360         exp->right = match->string;
00361         exp->type = (match->type == kxtString ? kxMatch : kxWildMatch);
00362         return exp;
00363         }
00364     else
00365         {
00366         errAbort("Expecting string to match in key=match expression,\ngot %s", token->string);
00367         }
00368     }
00369 else if (token->type == kxtGT || token->type == kxtGE || token->type == kxtLT || token->type == kxtLE)
00370     {
00371     enum kxTokType relation = token->type;
00372     advanceToken();
00373     if (isdigit(token->string[0]))
00374         {
00375         struct exp *exp;
00376         match = token;
00377         advanceToken();
00378         AllocVar(exp);
00379         exp->left = key->string;
00380         exp->right = match->string;
00381         if (relation == kxtGT) exp->type = kxGT;
00382         else if (relation == kxtGE) exp->type = kxGE;
00383         else if (relation == kxtLT) exp->type = kxLT;
00384         else if (relation == kxtLE) exp->type = kxLE;
00385         return exp;
00386         }
00387     else
00388         {
00389         errAbort("Expecting number got %s", token->string);
00390         }
00391     }
00392 else
00393     errAbort("Expecting = got %s", token->string);
00394 return NULL;
00395 }
00396 
00397 static struct exp *parseParenthesized()
00398 /* Parse parenthesized expressions. */
00399 {
00400 struct exp *exp;
00401 if (token == NULL)
00402     return NULL;
00403 if (token->type == kxtOpenParen)
00404     {
00405     advanceToken();
00406     exp = nextExp();
00407     if (token->type != kxtCloseParen)
00408         errAbort("Unmatched parenthesis");
00409     advanceToken();
00410     return exp;
00411     }
00412 else
00413     {
00414     return parseRelation();
00415     }            
00416 }
00417 
00418 static struct exp *parseNot()
00419 /* Parse not */
00420 {
00421 struct exp *exp;
00422 struct exp *right;
00423 
00424 if (token == NULL)
00425     return NULL;
00426 if (token->type == kxtNot)
00427     {
00428     advanceToken();
00429     right = nextExp();
00430     AllocVar(exp);
00431     exp->right = right;
00432     exp->type = kxNot;
00433     return exp;
00434     }
00435 else
00436     return parseParenthesized();
00437 }
00438 
00439 static struct exp *parseAndExp()
00440 /* Parse and level expressions. */
00441 {
00442 struct exp *left;
00443 struct exp *right, *exp;
00444 struct kxTok *tok;
00445 enum kxTokType type;
00446 
00447 if ((left = parseNot()) == NULL)
00448     return NULL;
00449 if ((tok = token) == NULL)
00450     return left;
00451 type = token->type;
00452 if (type == kxtAnd)
00453     {
00454     advanceToken();
00455     right = nextExp();
00456     if (right == NULL)
00457         errAbort("Expecting expression on the other side of %s", tok->string);
00458     AllocVar(exp);
00459     exp->left = left;
00460     exp->right = right;
00461     exp->type = kxAnd;
00462     return exp;
00463     }
00464 else
00465     return left;    
00466 }
00467 
00468 static struct exp *parseOrExp()
00469 /* Parse lowest level of precedent expressions - or and xor. */
00470 {
00471 struct exp *left;
00472 struct exp *right, *exp;
00473 struct kxTok *tok;
00474 enum kxTokType type;
00475 
00476 if ((left = parseAndExp()) == NULL)
00477     return NULL;
00478 if ((tok = token) == NULL)
00479     return left;
00480 type = token->type;
00481 if (type == kxtOr || type == kxtXor)
00482     {
00483     advanceToken();
00484     right = nextExp();
00485     if (right == NULL)
00486         errAbort("Expecting expression on the other side of %s", tok->string);
00487     AllocVar(exp);
00488     exp->left = left;
00489     exp->right = right;
00490     if (type == kxtOr)
00491         exp->type = kxOr;
00492     else
00493         exp->type = kxXor;
00494     return exp;
00495     }
00496 else
00497     return left;    
00498 }
00499 
00500 static struct exp *nextExp()
00501 /* Get another expression. */
00502 {
00503 return parseOrExp();
00504 }
00505 
00506 static struct exp *parseExp(struct kxTok *tokList)
00507 /* Convert key expression from token stream to parse tree. */
00508 {
00509 struct exp *exp;
00510 token = tokList;
00511 exp =  nextExp();
00512 if (token->type != kxtEnd)
00513     {
00514     errAbort("Extra tokens past end of expression.  Missing &?");
00515     }
00516 return exp;
00517 }
00518 
00519 struct keyExp *keyExpParse(char *text)
00520 /* Parse text into key expression.  Squawk and die if it
00521  * fails. */
00522 {
00523 struct keyExp *ke;
00524 struct kxTok *tok;
00525 AllocVar(ke);
00526 ke->tokenList = tok = kxTokenize(text, TRUE);
00527 ke->rootExp = parseExp(tok);
00528 
00529 return ke;
00530 }
00531 
00532 
00533 
00534 boolean keyTextScan(char *text, char *key, char *valBuf, int valBufSize)
00535 /* Get value of key. Return FALSE if key doesn't exist. */
00536 {
00537 int keySize = strlen(key);
00538 char *s, *nl;
00539 boolean ok = FALSE;
00540 
00541 for (s = text; !isspace(s[0]); s = nl+1)
00542     {
00543     nl = strchr(s, '\n');
00544     assert(nl != NULL);
00545     if (s[keySize] == ' ' && memcmp(s, key, keySize) == 0)
00546         {
00547         char *val = s + keySize + 1;
00548         int valSize = nl - val;
00549         if (valSize >= valBufSize)
00550             valSize = valBufSize-1;
00551         memcpy(valBuf, val, valSize);
00552         valBuf[valSize] = 0;
00553         ok = TRUE;
00554         break;
00555         }
00556     }
00557 return ok;
00558 }
00559 

Generated on Tue Dec 25 18:39:31 2007 for blat by  doxygen 1.5.2