00001
00002
00003
00004
00005
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
00015 {
00016 int used;
00017 int alloced;
00018 struct keyVal *table;
00019 };
00020
00021 struct kvt *newKvt(int size)
00022
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
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
00045 {
00046 kvt->used = 0;
00047 }
00048
00049 struct keyVal *kvtAdd(struct kvt *kvt, char *key, char *val)
00050
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
00063
00064
00065
00066
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
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
00102
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
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);
00127 }
00128
00129
00130
00131 enum keyExpType
00132 {
00133 kxMatch,
00134 kxWildMatch,
00135 kxGT,
00136 kxGE,
00137 kxLT,
00138 kxLE,
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
00154
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
00171 static void dumpExp(struct kvt *kvt, struct exp *exp)
00172
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
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
00323 {
00324 return rkeyEval(kvt, keyExp->rootExp);
00325 }
00326
00327
00328
00329 static struct kxTok *token;
00330
00331 static void advanceToken()
00332
00333 {
00334 token = token->next;
00335 }
00336
00337 static struct exp *nextExp();
00338
00339 static struct exp *parseRelation()
00340
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
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
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
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
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
00502 {
00503 return parseOrExp();
00504 }
00505
00506 static struct exp *parseExp(struct kxTok *tokList)
00507
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
00521
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
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