core/find.c

Go to the documentation of this file.
00001 
00010 #include <ctype.h>
00011 #ifdef WIN32
00012   #include <io.h>
00013 #else
00014   #include <unistd.h>
00015 #endif
00016 #include "globals.h"
00017 #include "output.h"
00018 #include "find.h"
00019 #include "aggregate.h"
00020 #include "module.h"
00021 
00022 static FINDTYPE invar_types[] = {FT_ID, FT_SIZE, FT_CLASS, FT_PARENT, FT_RANK, FT_NAME, FT_LAT, FT_LONG, FT_INSVC, FT_OUTSVC, FT_MODULE, 0};
00023 
00024 static int compare_int(int64 a, FINDOP op, int64 b)
00025 {
00026     switch (op) {
00027     case EQ: return a==b;
00028     case LT: return a<b;
00029     case GT: return a>b;
00030     case LE: return a<=b;
00031     case GE: return a>=b;
00032     case NE: return a!=b;
00033     default:
00034         output_error("compare op %d not supported on integers", op);
00035         return 0;
00036     }
00037 }
00038 
00039 static int compare_int64(int64 a, FINDOP op, int64 b){
00040     return compare_int(a, op, b);
00041 }
00042 
00043 static int compare_int32(int32 a, FINDOP op, int64 b)
00044 {
00045     switch (op) {
00046     case EQ: return a==b;
00047     case LT: return a<b;
00048     case GT: return a>b;
00049     case LE: return a<=b;
00050     case GE: return a>=b;
00051     case NE: return a!=b;
00052     default:
00053         output_error("compare op %d not supported on integers", op);
00054         return 0;
00055     }
00056 }
00057 
00058 static int compare_int16(int16 a, FINDOP op, int64 b)
00059 {
00060     switch (op) {
00061     case EQ: return a==b;
00062     case LT: return a<b;
00063     case GT: return a>b;
00064     case LE: return a<=b;
00065     case GE: return a>=b;
00066     case NE: return a!=b;
00067     default:
00068         output_error("compare op %d not supported on integers", op);
00069         return 0;
00070     }
00071 }
00072 
00073 static int compare_double(double a, FINDOP op, double b)
00074 {
00075     switch (op) {
00076     case EQ: return a==b;
00077     case LT: return a<b;
00078     case GT: return a>b;
00079     case LE: return a<=b;
00080     case GE: return a>=b;
00081     case NE: return a!=b;
00082     default:
00083         output_error("compare op %d not supported on doubles", op);
00084         return 0;
00085     }
00086 }
00087 
00088 static int compare_string(char *a, FINDOP op, char *b)
00089 {
00090     switch (op) {
00091     case SAME: op=EQ; goto CompareInt;
00092     case BEFORE: op=LT; goto CompareInt;
00093     case AFTER: op=GT; goto CompareInt;
00094     case DIFF: op=NE; goto CompareInt;
00095     case LIKE: return match(a, b);
00096     case EQ:
00097     case LT:
00098     case GT:
00099     case LE:
00100     case GE:
00101     case NE:
00102         if (!(isdigit(a[0])||a[0]=='+'||a[0]=='-')&&!(isdigit(b[0])||b[0]=='+'||b[0]=='-'))
00103             output_warning("compare of strings using numeric op usually does not work");
00104         return compare_double(atof(a),op,atof(b));
00105     default:
00106         output_error("compare op %d not supported on strings", op);
00107         return 0;
00108     }
00109 CompareInt:
00110     return compare_int((int64)strcmp(a,b),op,0);
00111 
00112 }
00113 
00114 static int compare_property(OBJECT *obj, char *propname, FINDOP op, void *value)
00115 {
00117     char *propval = object_property_to_string(obj,propname);
00118     if (propval==NULL) return 0;
00119     return compare_string(propval,op,(char*)value);
00120 }
00121 
00125 static int compare_property_alt(OBJECT *obj, char *propname, FINDOP op, void *value){
00126     complex *complex_target = NULL;
00127     char *char_target = NULL;
00128     int16 *int16_target = NULL;
00129     int32 *int32_target = NULL;
00130     int64 *int64_target = NULL;
00131     PROPERTY *prop = object_get_property(obj, propname);
00132     switch(prop->ptype){
00133         case PT_void:
00134             return 0;   /* no comparsion to be made */
00135         case PT_double:
00136             break;
00137         case PT_complex:
00138             complex_target = object_get_complex(obj, prop);
00139             if(complex_target == NULL)
00140                 return 0; /* error value */
00141             break;
00142         case PT_enumeration:
00143         case PT_set:
00144             break;      /* not 100% sure how to make these cooperate yet */
00145         case PT_int16:
00146             int16_target = (int16 *)object_get_int16(obj, prop);
00147             if(int16_target == NULL)
00148                 return 0;
00149             return compare_int16(*int16_target, op, *(int64 *)value);
00150         case PT_int32:
00151             int32_target = (int32 *)object_get_int32(obj, prop);
00152             return compare_int32(*int32_target, op, *(int64 *)value);
00153             break;
00154         case PT_int64:
00155             int64_target = (int64 *)object_get_int64(obj, prop);
00156             return compare_int64(*int64_target, op, *(int64 *)value);
00157             break;
00158         case PT_char8:
00159         case PT_char32:
00160         case PT_char256:
00161         case PT_char1024:
00162             char_target = (char *)object_get_string(obj, prop);
00163             if(char_target == NULL)
00164                 return 0;
00165             return compare_string(char_target, op, value);
00166             break;
00167         case PT_object:
00168 
00169             break;
00170         case PT_bool:
00171             break;
00172         case PT_timestamp:
00173         case PT_double_array:
00174         case PT_complex_array:
00175             break;
00176 #ifdef USE_TRIPLETS
00177         case PT_triple:
00178         case PT_triplex:
00179             break;
00180 #endif
00181         default:
00182             output_error("");
00183             return 0;
00184     }
00185 }
00186 
00187 static int compare(OBJECT *obj, FINDTYPE ftype, FINDOP op, void *value, char *propname)
00188 {
00189     switch (ftype) {
00190     case FT_ID: return compare_int((int64)obj->id,op,(int64)*(OBJECTNUM*)value);
00191     case FT_SIZE: return compare_int((int64)obj->size,op,(int64)*(int*)value);
00192     case FT_CLASS: return compare_string((char*)obj->oclass->name,op,(char*)value);
00193     case FT_MODULE: return compare_string((char*)obj->oclass->module->name,op,(char*)value);
00194     case FT_RANK: return compare_int((int64)obj->rank,op,(int64)*(int*)value);
00195     case FT_CLOCK: return compare_int((int64)obj->clock,op,(int64)*(TIMESTAMP*)value);
00196     case FT_PROPERTY: return compare_property(obj,propname,op,value);
00197     default:
00198         output_error("findtype %s not supported", ftype);
00199         return 0;
00200     }
00201 }
00202 
00203 FINDLIST *new_list(unsigned int n)
00204 {
00205     unsigned int size = (n>>3)+1;
00206     FINDLIST *list = malloc(sizeof(FINDLIST)+size-1);
00207     if (list==NULL)
00208     {
00209         errno=ENOMEM;
00210         return NULL;
00211     }
00212     memset(list->result,0,size);
00213     list->result_size = size;
00214     list->hit_count = 0;
00215     return list;
00216 }
00217 #define SIZE(L) ((L).result_size)
00218 #define COUNT(L) ((L).hit_count)
00219 #define FOUND(L,N) (((L).result[(N)>>3]&(1<<((N)&0x7)))!=0)
00220 #define ADDOBJ(L,N) (!FOUND((L),(N))?((L).result[(N)>>3]|=(1<<((N)&0x7)),++((L).hit_count)):(L).hit_count)
00221 #define DELOBJ(L,N) (FOUND((L),(N))?((L).result[(N)>>3]&=~(1<<((N)&0x7)),--((L).hit_count)):(L).hit_count)
00222 #define ADDALL(L) ((L).hit_count=object_get_count(),memset((L).result,0xff,(L).result_size))
00223 #define DELALL(L) ((L).hit_count=object_get_count(),memset((L).result,0x00,(L).result_size))
00224 
00225 FINDLIST *find_runpgm(FINDLIST *list, FINDPGM *pgm);
00226 FINDPGM *find_mkpgm(char *expression);
00227 
00282 FINDLIST *find_objects(FINDLIST *start, ...)
00283 {
00284     OBJECT *obj;
00285     FINDLIST *result = start;
00286     if (start==FL_NEW || start==FL_GROUP)
00287     {
00288         result=new_list(object_get_count());
00289         ADDALL(*result);
00290     }
00291     /* FL_GROUP is something of an interrupt option that constructs a program by parsing string input. */
00292     if (start==FL_GROUP)
00293     {
00294         FINDPGM *pgm;
00295         va_list(ptr);
00296         va_start(ptr,start);
00297         pgm = find_mkpgm(va_arg(ptr,char*));
00298         if (pgm!=NULL){
00299             return find_runpgm(result,pgm);
00300         } else {
00301             va_end(ptr);
00302             DELALL(*result); /* pgm == NULL */
00303             return result;
00304         }
00305     }
00306     /* if we're not using FL_GROUP, we break apart the va_arg list, taking data inputs in the "correct" type. */
00307     for (obj=object_get_first(); obj!=NULL; obj=obj->next)
00308     {
00309         FINDTYPE ftype;
00310         va_list(ptr);
00311         va_start(ptr,start);
00312         while ((ftype=va_arg(ptr,FINDTYPE)) != FT_END)
00313         {
00314             int invert=0;
00315             int parent=0;
00316             FINDOP conj=AND;
00317             FINDOP op;
00318             char *propname = NULL;
00319             void *value;
00320             OBJECT *target=obj;
00321 
00322             /* conjunction */
00323             if (ftype==AND || ftype==OR)
00324             {   /* expect another op */
00325                 conj=ftype;
00326                 ftype = va_arg(ptr, FINDTYPE);
00327             }
00328 
00329             /* follow to parent */
00330             while (ftype==FT_PARENT)
00331             {
00332                 ftype=va_arg(ptr,FINDTYPE);
00333                 parent++;
00334             }
00335 
00336             /* property option require property name */
00337             if (ftype==FT_PROPERTY)
00338                 propname=va_arg(ptr,char*);
00339 
00340             /* read operation */
00341             op = va_arg(ptr,FINDOP);
00342 
00343             /* negation */
00344             if (op==NOT)
00345             {   /* expect another op */
00346                 invert=1;
00347                 op = va_arg(ptr,FINDOP);
00348             }
00349 
00350             /* read value */
00351             switch (ftype) {
00352                 static int ival;
00353                 static char *sval;
00354                 static OBJECTNUM oval;
00355                 static TIMESTAMP tval;
00356                 static double rval;
00357             case FT_PARENT:
00358             case FT_ID:
00359                 oval = va_arg(ptr,OBJECTNUM);
00360                 value = &oval;
00361                 break;
00362             case FT_SIZE:
00363             case FT_RANK:
00364                 ival = va_arg(ptr,int);
00365                 value = &ival;
00366                 break;
00367             case FT_INSVC:
00368             case FT_OUTSVC:
00369             case FT_CLOCK:
00370                 tval = va_arg(ptr,TIMESTAMP);
00371                 value = &tval;
00372                 break;
00373             case FT_LAT:
00374             case FT_LONG:
00375                 rval = va_arg(ptr, double);
00376                 value = &rval;
00377                 break;
00378             case FT_CLASS:
00379             case FT_NAME:
00380             case FT_PROPERTY:
00381             case FT_MODULE:
00382                 sval = va_arg(ptr,char*);
00383                 value = sval;
00384                 break;
00385             default:
00386                 output_error("invalid findtype means search is specified incorrectly or FT_END is probably missing");
00387                 if (start == FL_NEW) free(result);
00388                 return NULL;
00389             }
00390 
00391             /* follow target to parent */
00392             while (parent-- > 0 && target != NULL)
00393                 target = target->parent;
00394 
00395             /* if target exists */
00396             if (target != NULL)
00397             {
00398                 /* match */
00399                 if (compare(target,ftype,op,value,propname)!=invert)
00400                 {
00401                     if (conj==OR) 
00402                         ADDOBJ(*result,obj->id);
00403                 }
00404                 else
00405                 {
00406                     if (conj==AND) 
00407                         DELOBJ(*result,obj->id);
00408                 }
00409             }
00410         }
00411         va_end(ptr);
00412     }
00413     return result;
00414 }
00415 
00420 int find_makearray(FINDLIST *list, 
00421                    OBJECT ***objs) 
00422 {
00423     OBJECT *obj=find_first(list);
00424     int n = list->hit_count, i;
00425     if (n<=0 || obj==NULL)
00426         return 0;
00427     (*objs) = (OBJECT**)malloc(sizeof(OBJECT*)*(n+1)); /* one extra for handy NULL to terminate list */
00428     for ( i=0 ; i<n && obj!=NULL; obj=find_next(list,obj),i++)
00429         (*objs)[i] = obj;
00430     objs[n]=NULL;/* NULL to terminate list */
00431     return n;
00432 }
00433 
00438 OBJECT *find_first(FINDLIST *list) 
00439 {
00440     return find_next(list,NULL);
00441 }
00442 
00446 OBJECT *find_next(FINDLIST *list, 
00447                   OBJECT *obj) 
00448 {
00449     if (obj==NULL)
00450         obj = object_get_first();
00451     else
00452         obj = obj->next;
00453     while (obj!=NULL && !FOUND(*list,obj->id))
00454         obj=obj->next;
00455 
00456     return obj;
00457 }
00458 
00459 /**************************************************************
00460  * FIND EXPRESSIONS AND FIND MACHINES
00461  **************************************************************/
00462 
00463 #define VALUE(X,T,M) ((X).isconstant?(X).value.constant.M:*((X).value.ref.T))
00464 
00465 int compare_pointer_eq(void *a, FINDVALUE b) { return *(void**)a==b.pointer;}
00466 int compare_pointer_ne(void *a, FINDVALUE b) { return *(void**)a!=b.pointer;}
00467 int compare_pointer_lt(void *a, FINDVALUE b) { return *(void**)a<b.pointer;}
00468 int compare_pointer_gt(void *a, FINDVALUE b) { return *(void**)a>b.pointer;}
00469 int compare_pointer_le(void *a, FINDVALUE b) { return *(void**)a<=b.pointer;}
00470 int compare_pointer_ge(void *a, FINDVALUE b) { return *(void**)a>=b.pointer;}
00471 
00472 int compare_integer16_eq(void *a, FINDVALUE b) { return *(int16*)a==(int16)b.integer;}
00473 int compare_integer16_ne(void *a, FINDVALUE b) { return *(int16*)a!=(int16)b.integer;}
00474 int compare_integer16_lt(void *a, FINDVALUE b) { return *(int16*)a<(int16)b.integer;}
00475 int compare_integer16_gt(void *a, FINDVALUE b) { return *(int16*)a>(int16)b.integer;}
00476 int compare_integer16_le(void *a, FINDVALUE b) { return *(int16*)a<=(int16)b.integer;}
00477 int compare_integer16_ge(void *a, FINDVALUE b) { return *(int16*)a>=(int16)b.integer;}
00478 
00479 int compare_integer32_eq(void *a, FINDVALUE b) { return *(int32*)a==(int32)b.integer;}
00480 int compare_integer32_ne(void *a, FINDVALUE b) { return *(int32*)a!=(int32)b.integer;}
00481 int compare_integer32_lt(void *a, FINDVALUE b) { return *(int32*)a<(int32)b.integer;}
00482 int compare_integer32_gt(void *a, FINDVALUE b) { return *(int32*)a>(int32)b.integer;}
00483 int compare_integer32_le(void *a, FINDVALUE b) { return *(int32*)a<=(int32)b.integer;}
00484 int compare_integer32_ge(void *a, FINDVALUE b) { return *(int32*)a>=(int32)b.integer;}
00485 
00486 int compare_integer64_eq(void *a, FINDVALUE b) { return *(int64*)a==(int64)b.integer;}
00487 int compare_integer64_ne(void *a, FINDVALUE b) { return *(int64*)a!=(int64)b.integer;}
00488 int compare_integer64_lt(void *a, FINDVALUE b) { return *(int64*)a<(int64)b.integer;}
00489 int compare_integer64_gt(void *a, FINDVALUE b) { return *(int64*)a>(int64)b.integer;}
00490 int compare_integer64_le(void *a, FINDVALUE b) { return *(int64*)a<=(int64)b.integer;}
00491 int compare_integer64_ge(void *a, FINDVALUE b) { return *(int64*)a>=(int64)b.integer;}
00492 
00493 int compare_integer_eq(void *a, FINDVALUE b) { return *(long*)a==(long)b.integer;}
00494 int compare_integer_ne(void *a, FINDVALUE b) { return *(long*)a!=(long)b.integer;}
00495 int compare_integer_lt(void *a, FINDVALUE b) { return *(long*)a<(long)b.integer;}
00496 int compare_integer_gt(void *a, FINDVALUE b) { return *(long*)a>(long)b.integer;}
00497 int compare_integer_le(void *a, FINDVALUE b) { return *(long*)a<=(long)b.integer;}
00498 int compare_integer_ge(void *a, FINDVALUE b) { return *(long*)a>=(long)b.integer;}
00499 
00500 int compare_real_eq(void *a, FINDVALUE b) { return *(double*)a==b.real;}
00501 int compare_real_ne(void *a, FINDVALUE b) { return *(double*)a!=b.real;}
00502 int compare_real_lt(void *a, FINDVALUE b) { return *(double*)a<b.real;}
00503 int compare_real_gt(void *a, FINDVALUE b) { return *(double*)a>b.real;}
00504 int compare_real_le(void *a, FINDVALUE b) { return *(double*)a<=b.real;}
00505 int compare_real_ge(void *a, FINDVALUE b) { return *(double*)a>=b.real;}
00506 
00507 /* NOTE: this only works with short-circuiting logic! */
00508 int compare_string_eq(void *a, FINDVALUE b) { return *(char **)a != NULL && strcmp(*(char**)a,b.string)==0;}
00509 int compare_string_ne(void *a, FINDVALUE b) { return *(char **)a != NULL && strcmp(*(char**)a,b.string)!=0;}
00510 int compare_string_lt(void *a, FINDVALUE b) { return *(char **)a != NULL && strcmp(*(char**)a,b.string)<0;}
00511 int compare_string_gt(void *a, FINDVALUE b) { return *(char **)a != NULL && strcmp(*(char**)a,b.string)>0;}
00512 int compare_string_le(void *a, FINDVALUE b) { return *(char **)a != NULL && strcmp(*(char**)a,b.string)<=0;}
00513 int compare_string_ge(void *a, FINDVALUE b) { return *(char **)a != NULL && strcmp(*(char**)a,b.string)>=0;}
00514 
00515 int compare_pointer_li(void *a, FINDVALUE b) {return 0;}
00516 
00517 int compare_integer_li(void *a, FINDVALUE b) {
00518     char temp[256];
00519     if(convert_from_int64(temp, 256, &(b.integer), NULL))
00520         return match(*(char **)a, temp);
00521     return 0;
00522 }
00523 
00524 int compare_real_li(void *a, FINDVALUE b) {
00525     char temp[256];
00526     if(convert_from_double(temp, 256, &(b.real), NULL))
00527         return match(*(char **)a, temp);
00528     return 0;
00529 }
00530 
00531 int compare_string_li(void *a, FINDVALUE b) {return match(*(char **)a, b.string);}
00532 
00533 int compare_integer16_li(void *a, FINDVALUE b) {
00534     char temp[256];
00535     if(convert_from_int16(temp, 256, &(b.integer), NULL))
00536         return match(*(char **)a, temp);
00537     return 0;
00538 }
00539 
00540 int compare_integer32_li(void *a, FINDVALUE b) {
00541     char temp[256];
00542     if(convert_from_int32(temp, 256, &(b.integer), NULL))
00543         return match(*(char **)a, temp);
00544     return 0;
00545 }
00546 
00547 int compare_integer64_li(void *a, FINDVALUE b) {
00548     char temp[256];
00549     if(convert_from_int64(temp, 256, &(b.integer), NULL))
00550         return match(*(char **)a, temp);
00551     return 0;
00552 }
00553 
00554 int compare_pointer_nl(void *a, FINDVALUE b) {return 1;}
00555 
00556 int compare_integer_nl(void *a, FINDVALUE b) {
00557     char temp[256];
00558     if(convert_from_int64(temp, 256, &(b.integer), NULL))
00559         return 1 != match(*(char **)a, temp);
00560     return 0;
00561 }
00562 
00563 int compare_real_nl(void *a, FINDVALUE b) {
00564     char temp[256];
00565     if(convert_from_double(temp, 256, &(b.real), NULL))
00566         return 1 != match(*(char **)a, temp);
00567     return 0;
00568 }
00569 
00570 int compare_string_nl(void *a, FINDVALUE b) {
00571     return 1 != match(*(char **)a, b.string);
00572 }
00573 
00574 int compare_integer16_nl(void *a, FINDVALUE b) {
00575     char temp[256];
00576     if(convert_from_int16(temp, 256, &(b.integer), NULL))
00577         return 1 != match(*(char **)a, temp);
00578     return 0;
00579 }
00580 
00581 int compare_integer32_nl(void *a, FINDVALUE b) {
00582     char temp[256];
00583     if(convert_from_int32(temp, 256, &(b.integer), NULL))
00584         return 1 != match(*(char **)a, temp);
00585     return 0;
00586 }
00587 
00588 int compare_integer64_nl(void *a, FINDVALUE b) {
00589     char temp[256];
00590     if(convert_from_int64(temp, 256, &(b.integer), NULL))
00591         return 1 != match(*(char **)a, temp);
00592     return 0;
00593 }
00594 
00595 static void findlist_add(FINDLIST *list, OBJECT *obj)
00596 {
00597     ADDOBJ(*list,obj->id);
00598 }
00599 static void findlist_del(FINDLIST *list, OBJECT *obj)
00600 {
00601     DELOBJ(*list,obj->id);
00602 }
00603 static void findlist_nop(FINDLIST *list, OBJECT *obj)
00604 {
00605 }
00606 
00607 PGMCONSTFLAGS find_pgmconstants(FINDPGM *pgm)
00608 {
00609     if (pgm==NULL)
00610         return 0;
00611 
00612     /* find the end of the program */
00613     while (pgm->next!=NULL) pgm=pgm->next;
00614     return pgm->constflags;
00615 
00616 }
00617 
00618 static FINDPGM *add_pgm(FINDPGM **pgm, COMPAREFUNC op, unsigned short target, FINDVALUE value, FOUNDACTION pos, FOUNDACTION neg)
00619 {
00620     /* create program entry */
00621     FINDPGM *item = (FINDPGM*)malloc(sizeof(FINDPGM));
00622     if (item!=NULL)
00623     {
00624         item->constflags = CF_CONSTANT; /* initially the result is invariant */
00625         item->op = op;
00626         item->target = target;
00627         item->value = value;
00628         item->pos = pos;
00629         item->neg = neg;
00630         item->next = NULL;
00631 
00632         /* attach to existing program */
00633         if (*pgm!=NULL)
00634         {
00635             FINDPGM *tail = *pgm;
00636 
00637             item->constflags = tail->constflags; /* inherit flags from previous result set */
00638 
00639             /* find tail of existing program */
00640             while (tail->next!=NULL) tail=tail->next;
00641             tail->next = item;
00642         }
00643         else
00644             *pgm = item;
00645     }
00646     else
00647         errno = ENOMEM;
00648 
00649     return item;
00650 }
00651 FINDLIST *find_runpgm(FINDLIST *list, FINDPGM *pgm)
00652 {
00653     if (list==NULL)
00654     {
00655         list=new_list(object_get_count());
00656         ADDALL(*list);
00657     }
00658     if (pgm!=NULL)
00659     {
00660         OBJECT *obj;
00661         for (obj=find_first(list); obj!=NULL; obj=find_next(list,obj))
00662         {
00663             if ((*pgm->op)((void*)(((char*)obj)+pgm->target),pgm->value))
00664             {   if (pgm->pos) (*pgm->pos)(list,obj); }
00665             else
00666             {   if (pgm->neg) (*pgm->neg)(list,obj); }
00667         }
00668         find_runpgm(list,pgm->next);
00669     }
00670     return list;
00671 }
00672 
00673 #define PARSER char *_p
00674 #define START int _m=0, _n=0;
00675 #define ACCEPT { _n+=_m; _p+=_m; _m=0; }
00676 #define HERE (_p+_m)
00677 #define OR {_m=0;}
00678 #define REJECT { return 0; }
00679 #define WHITE (_m+=white(HERE))
00680 #define LITERAL(X) ((_m+=literal(HERE,(X)))>0)
00681 #define TERM(X) ((_m+=(X))>0)
00682 #define COPY(X) {size--; (X)[_n++]=*_p++;}
00683 #define DONE return _n;
00684 
00685 void syntax_error(char *p)
00686 {
00687     char context[16], *nl;
00688     strncpy(context,p,15);
00689     nl = strchr(context,'\n');
00690     if (nl!=NULL) *nl='\0'; else context[15]='\0';
00691     if (strlen(context)>0)
00692         output_message("find expression syntax error at '%s...'", context);
00693     else
00694         output_message("find expression syntax error");
00695 }
00696 
00697 static int white(PARSER)
00698 {
00699     if (*_p=='\0' || !isspace(*_p))
00700         return 0;
00701     /* tail recursion to keep consuming whitespace until none left*/
00702     return white(_p+1)+1;
00703 }
00704 
00705 static int comment(PARSER)
00706 {
00707     int _n = white(_p);
00708     if (_p[_n]=='#')
00709     {
00710         while (_p[_n]!='\n')
00711             _n++;
00712     }
00713     return _n;
00714 }
00715 
00716 static int literal(PARSER, char *text)
00717 {
00718     if (strncmp(_p,text,strlen(text))==0)
00719         return (int)strlen(text);
00720     return 0;
00721 }
00722 
00723 static int name(PARSER, char *result, int size)
00724 {   /* basic name */
00725     START;
00726     while (size>1 && isalpha(*_p) || isdigit(*_p) || *_p=='_') COPY(result);
00727     result[_n]='\0';
00728     DONE;
00729 }
00730 
00731 static int value(PARSER, char *result, int size)
00732 {   /* everything to a semicolon */
00733     START;
00734     while (size>1 && *_p!='\0' && *_p!=';' && *_p!='\n') COPY(result);
00735     result[_n]='\0';
00736     return _n;
00737 }
00738 
00739 static int integer(PARSER, int64 *value)
00740 {
00741     char result[256];
00742     int size=sizeof(result);
00743     START;
00744     while (size>1 && isdigit(*_p)) COPY(result);
00745     result[_n]='\0';
00746     *value=atoi64(result);
00747     return _n;
00748 }
00749 
00750 static int real(PARSER, double *value)
00751 {
00752     char result[256];
00753     int size=sizeof(result);
00754     START;
00755     if (*_p=='+' || *_p=='-') COPY(result);
00756     while (size>1 && isdigit(*_p)) COPY(result);
00757     if (*_p=='.') COPY(result);
00758     while (size>1 && isdigit(*_p)) COPY(result);
00759     if (*_p=='E' || *_p=='e') COPY(result);
00760     if (*_p=='+' || *_p=='-') COPY(result);
00761     while (size>1 && isdigit(*_p)) COPY(result);
00762     result[_n]='\0';
00763     *value=atof(result);
00764     return _n;
00765 }
00766 
00767 static int time_value_seconds(PARSER, TIMESTAMP *t)
00768 {
00769     START;
00770     if WHITE ACCEPT;
00771     if (TERM(integer(HERE,t)) && LITERAL("s")) { *t *= TS_SECOND; ACCEPT; DONE;}
00772     OR
00773     if (TERM(integer(HERE,t)) && LITERAL("S")) { *t *= TS_SECOND; ACCEPT; DONE;}
00774     REJECT;
00775 }
00776 
00777 static int time_value_minutes(PARSER, TIMESTAMP *t)
00778 {
00779     START;
00780     if WHITE ACCEPT;
00781     if (TERM(integer(HERE,t)) && LITERAL("m")) { *t *= 60*TS_SECOND; ACCEPT; DONE;}
00782     OR
00783     if (TERM(integer(HERE,t)) && LITERAL("M")) { *t *= 60*TS_SECOND; ACCEPT; DONE;}
00784     REJECT;
00785 }
00786 
00787 static int time_value_hours(PARSER, TIMESTAMP *t)
00788 {
00789     START;
00790     if WHITE ACCEPT;
00791     if (TERM(integer(HERE,t)) && LITERAL("h")) { *t *= 3600*TS_SECOND; ACCEPT; DONE;}
00792     OR
00793     if (TERM(integer(HERE,t)) && LITERAL("H")) { *t *= 3600*TS_SECOND; ACCEPT; DONE;}
00794     REJECT;
00795 }
00796 
00797 static int time_value_days(PARSER, TIMESTAMP *t)
00798 {
00799     START;
00800     if WHITE ACCEPT;
00801     if (TERM(integer(HERE,t)) && LITERAL("d")) { *t *= 86400*TS_SECOND; ACCEPT; DONE;}
00802     OR
00803     if (TERM(integer(HERE,t)) && LITERAL("D")) { *t *= 86400*TS_SECOND; ACCEPT; DONE;}
00804     REJECT;
00805 }
00806 
00807 static int time_value_datetime(PARSER, TIMESTAMP *t)
00808 {
00809     int64 Y,m,d,H,M,S;
00810     START;
00811     if WHITE ACCEPT;
00812     if (LITERAL("'")
00813         && TERM(integer(HERE,&Y)) && LITERAL("-")
00814         && TERM(integer(HERE,&m)) && LITERAL("-")
00815         && TERM(integer(HERE,&d)) && LITERAL(" ")
00816         && TERM(integer(HERE,&H)) && LITERAL(":")
00817         && TERM(integer(HERE,&M)) && LITERAL(":")
00818         && TERM(integer(HERE,&S)) && LITERAL("'"))
00819     {
00820         struct tm dt = {(int)S,(int)M,(int)H,(int)d,(int)m-1,(int)Y-1900,0,0,0};
00821         int64 tt = mktime(&dt);
00822         if (tt!=-1) {*t=(int64)tt*TS_SECOND; ACCEPT; DONE;}
00823     }
00824     REJECT;
00825 }
00826 
00827 static int time_value(PARSER, TIMESTAMP *t)
00828 {
00829     START;
00830     if WHITE ACCEPT;
00831     if TERM(time_value_seconds(HERE,t)) {ACCEPT; DONE; }
00832     OR
00833     if TERM(time_value_minutes(HERE,t)) {ACCEPT; DONE; }
00834     OR
00835     if TERM(time_value_hours(HERE,t)) {ACCEPT; DONE; }
00836     OR
00837     if TERM(time_value_days(HERE,t)) {ACCEPT; DONE; }
00838     OR
00839     if TERM(time_value_datetime(HERE,t)) {ACCEPT; DONE; }
00840     OR
00841         if TERM(integer(HERE,t)) { ACCEPT; DONE; }
00842     else REJECT;
00843     DONE;
00844 }
00845 
00846 static int compare_op(PARSER, FINDOP *op)
00847 {
00848     /* these first! */
00849     if (strncmp(_p,"!=", 2)==0) {*op=NE; return 2;}
00850     if (strncmp(_p,"<=", 2)==0) {*op=LE; return 2;}
00851     if (strncmp(_p,">=", 2)==0) {*op=GE; return 2;}
00852     if (strncmp(_p,"!~", 2)==0) {*op=UNLIKE; return 2;}
00853 
00854     if (strncmp(_p,"=", 1)==0) {*op=EQ; return 1;}
00855     if (strncmp(_p,"<", 1)==0) {*op=LT; return 1;}
00856     if (strncmp(_p,">", 1)==0) {*op=GT; return 1;}
00857     if (strncmp(_p,"~", 1)==0) {*op=LIKE; return 1;}
00858     return 0;
00859 }
00860 
00861 struct {
00862     COMPAREFUNC pointer, integer, real, string;
00863 } comparemap[] = 
00864 {   {compare_pointer_eq, compare_integer_eq, compare_real_eq, compare_string_eq},
00865     {compare_pointer_lt, compare_integer_lt, compare_real_lt, compare_string_lt},
00866     {compare_pointer_gt, compare_integer_gt, compare_real_gt, compare_string_gt},
00867     {compare_pointer_ne, compare_integer_ne, compare_real_ne, compare_string_ne},
00868     {compare_pointer_le, compare_integer_le, compare_real_le, compare_string_le},
00869     {compare_pointer_ge, compare_integer_ge, compare_real_ge, compare_string_ge},
00870     {compare_pointer_li, compare_integer_li, compare_real_li, compare_string_li},
00871     {compare_pointer_nl, compare_integer_nl, compare_real_nl, compare_string_nl}
00872 };
00873 
00874 struct {
00875     COMPAREFUNC pointer, integer, real, string, int_16, int_32, int_64; /*  int_size to avoid #define int64 (platform.h) */
00876 } comparemap_ext[] =
00877 {   {compare_pointer_eq, compare_integer_eq, compare_real_eq, compare_string_eq, compare_integer16_eq, compare_integer32_eq, compare_integer64_eq},
00878     {compare_pointer_lt, compare_integer_lt, compare_real_lt, compare_string_lt, compare_integer16_lt, compare_integer32_lt, compare_integer64_lt},
00879     {compare_pointer_gt, compare_integer_gt, compare_real_gt, compare_string_gt, compare_integer16_gt, compare_integer32_gt, compare_integer64_gt},
00880     {compare_pointer_ne, compare_integer_ne, compare_real_ne, compare_string_ne, compare_integer16_ne, compare_integer32_ne, compare_integer64_ne},
00881     {compare_pointer_le, compare_integer_le, compare_real_le, compare_string_le, compare_integer16_le, compare_integer32_le, compare_integer64_le},
00882     {compare_pointer_ge, compare_integer_ge, compare_real_ge, compare_string_ge, compare_integer16_ge, compare_integer32_ge, compare_integer64_ge},
00883     {compare_pointer_li, compare_integer_li, compare_real_li, compare_string_li, compare_integer16_li, compare_integer32_li, compare_integer64_li},
00884     {compare_pointer_nl, compare_integer_nl, compare_real_nl, compare_string_nl, compare_integer16_nl, compare_integer32_nl, compare_integer64_nl},
00885 };
00886 
00887 /* int compare_integer32_eq(void *a, FINDVALUE b) { return *(int32*)a==(int32)b.integer;} */
00888 
00889 static int expression(PARSER, FINDPGM **pgm)
00890 {
00891     char32 pname;
00892     char256 pvalue;
00893     FINDOP op = EQ;
00894     START;
00895     if WHITE ACCEPT;
00896     if (TERM(name(HERE,pname,sizeof(pname))) && WHITE,TERM(compare_op(HERE,&op)) && WHITE,TERM(value(HERE,pvalue,sizeof(pvalue))))
00897     {
00898         /* NOTE: this will seg fault if op's value is an invalid index! */
00899         OBJECT _t;
00900 #define OFFSET(X) (unsigned short)((char*)&(_t.X) - (char*)&_t)
00901         if WHITE ACCEPT;
00902         if(op < 0 || op >= FINDOP_END){
00903             output_error("expression(): invalid find op!");
00904             REJECT;
00905         }
00906         if (strcmp(pname,"class")==0)
00907         {
00908             FINDVALUE v;
00909             CLASS *oclass = class_get_class_from_classname(pvalue);
00910             if (oclass==NULL)
00911                 output_error("class '%s' not found", pvalue);
00912             else
00913             {
00914                 v.pointer=(void*)oclass;
00915                 add_pgm(pgm,comparemap[op].pointer,OFFSET(oclass),v,NULL,findlist_del);
00916                 (*pgm)->constflags |= CF_CLASS; /* this will always reduce in a set class of fixed class, leaving it invariant if already so */
00917                 ACCEPT; DONE;
00918             }
00919         }
00920         if (strcmp(pname,"module")==0)
00921         {
00922             FINDVALUE v;
00923             MODULE *mod = module_find(pvalue);
00924             if (mod==NULL)
00925                 output_error("module '%s' not found", pvalue);
00926             else
00927             {
00928                 v.pointer=(void*)mod;
00929                 add_pgm(pgm,comparemap[op].pointer,OFFSET(oclass),v,NULL,findlist_del);
00930                 (*pgm)->constflags |= CF_MODULE; 
00931                 ACCEPT; DONE;
00932             }
00933         }
00934         else if (strcmp(pname,"id")==0)
00935         {
00936             FINDVALUE v;
00937             int idnum = atoi(pvalue);
00938             if(idnum < 0){
00939                 output_error("ID '#%i' not found", idnum);
00940             } else {
00941                 v.integer = idnum;
00942                 add_pgm(pgm,comparemap[op].integer,OFFSET(id),v,NULL,findlist_del);
00943                 (*pgm)->constflags |= CF_ID;
00944                 ACCEPT;
00945                 DONE;
00946             }
00947         }
00948         else if (strcmp(pname, "name") == 0)
00949         {
00950             /* Accept implicitly.  If it's bad, it's bad. -MH */
00951             FINDVALUE v;
00952             strcpy(v.string, pvalue);
00953             printf("find(): v.string=\"%s\", pvalue=\"%s\"\n", v.string, pvalue);
00954             add_pgm(pgm, comparemap[op].string, OFFSET(name), v, NULL, findlist_del);
00955             (*pgm)->constflags |= CF_NAME;
00956             ACCEPT;
00957             DONE;
00958         }
00959         else if (strcmp(pname,"parent")==0)
00960         {
00961             FINDVALUE v;
00962             OBJECT *parent = object_find_name(pvalue);
00963             if (parent==NULL && strcmp(pvalue, "root") != 0 && strcmp(pvalue, "ROOT") != 0)
00964                 output_error("parent '%s' not found", pvalue);
00965             else
00966             {
00967                 v.pointer = (void*)parent;
00968                 add_pgm(pgm,comparemap[op].pointer,OFFSET(parent),v,NULL,findlist_del);
00969                 (*pgm)->constflags |= CF_PARENT;
00970                 ACCEPT; DONE;
00971             }
00972         }
00973         else if (strcmp(pname,"rank")==0)
00974         {
00975             FINDVALUE v;
00976             int rank = atoi(pvalue);
00977             if (rank<0)
00978                 output_error("rank %s is invalid", pvalue);
00979             else
00980             {
00981                 v.integer = rank;
00982                 add_pgm(pgm,comparemap[op].integer,OFFSET(rank),v,NULL,findlist_del);
00983                 (*pgm)->constflags |= CF_RANK;
00984                 ACCEPT; DONE;
00985             }
00986         }
00987         else if (strcmp(pname, "latitude") == 0)
00988         {
00989             /* mostly borrowed from load.c */
00990             FINDVALUE v;
00991             int32 d = 0, m = 0;
00992             double s = 0.0, val = 0.0;
00993             char ns;
00994             if (sscanf(pvalue, "%d%c%d'%lf\"", &d, &ns, &m, &s) > 0) /* 12N34'56" */
00995             {
00996                 val = (double)d+(double)m/60+s/3600;
00997                 if (val >= 0 && val <= 90)
00998                 {
00999                     if (ns=='S')
01000                         val = -val;
01001                     else if (ns=='N')
01002                         ;
01003                     else
01004                         REJECT;
01005                 } else {
01006                     REJECT;
01007                 }
01008                 v.real = val;
01009                 add_pgm(pgm, comparemap[op].real, OFFSET(latitude), v, NULL, findlist_del);
01010                 (*pgm)->constflags |= CF_LAT;
01011                 ACCEPT; DONE;
01012             }
01013         }
01014         else if (strcmp(pname, "longitude") == 0)
01015         {
01016             /* mostly borrowed from load.c */
01017             FINDVALUE v;
01018             int32 d = 0, m = 0;
01019             double s = 0.0, val = 0.0;
01020             char ns;
01021             if (sscanf(pvalue, "%d%c%d'%lf\"", &d, &ns, &m, &s) > 0) /* 12N34'56" */
01022             {
01023                 val = (double)d+(double)m/60+s/3600;
01024                 if (val >= 0 && val <= 180)
01025                 {
01026                     if (ns=='W')
01027                         val = -val;
01028                     else if (ns=='E')
01029                         ;
01030                     else
01031                         REJECT;
01032                 } else {
01033                     REJECT;
01034                 }
01035                 v.real = val;
01036                 add_pgm(pgm, comparemap[op].real, OFFSET(longitude), v, NULL, findlist_del);
01037                 (*pgm)->constflags |= CF_LONG;
01038                 ACCEPT; DONE;
01039             }
01040         }
01041         else if (strcmp(pname, "clock") == 0)
01042         {
01043             FINDVALUE v;
01044             v.integer = convert_to_timestamp(pvalue);
01045             if(v.integer == TS_NEVER)
01046                 REJECT;
01047             add_pgm(pgm, comparemap[op].integer, OFFSET(clock), v, NULL, findlist_del);
01048             (*pgm)->constflags |= CF_CLOCK;
01049             ACCEPT; DONE;
01050         }
01051         else if (strcmp(pname, "insvc") == 0)   /* format? */
01052         {
01053             FINDVALUE v;
01054             v.integer = convert_to_timestamp(pvalue);
01055             printf("find insvc=%i\n", v.integer);
01056             if(v.integer == TS_NEVER)
01057                 REJECT;
01058             add_pgm(pgm, comparemap[op].integer, OFFSET(in_svc), v, NULL, findlist_del);
01059             (*pgm)->constflags |= CF_INSVC;
01060             ACCEPT; DONE;
01061         }
01062         else if (strcmp(pname, "outsvc") == 0)  /* format? */
01063         {
01064             FINDVALUE v;
01065             v.integer = convert_to_timestamp(pvalue);
01066             if(v.integer == TS_NEVER)
01067                 REJECT;
01068             add_pgm(pgm, comparemap[op].integer, OFFSET(out_svc), v, NULL, findlist_del);
01069             (*pgm)->constflags |= CF_OUTSVC;
01070             ACCEPT; DONE;
01071         }
01072         else if (strcmp(pname, "flags") == 0)
01073         {
01075             /* still need to think about how to input flags without hardcoding the flag name. -mh */
01076             output_error("find expression on %s not supported", pname);
01077         }
01078         else
01079             output_error("find expression refers to unknown or unsupported property '%s'", pname);
01080     }
01081     REJECT;
01082 }
01083 
01084 static int expression_list(PARSER, FINDPGM **pgm)
01085 {
01086     START;
01087     if TERM(expression(HERE,pgm)) ACCEPT;
01088     if (WHITE,LITERAL(";") && TERM(expression_list(HERE,pgm))) { ACCEPT; DONE; }
01089     DONE;
01090 }
01091 
01092 FINDPGM *find_mkpgm(char *search)
01093 {
01094     STATUS status=FAILED;
01095     FINDPGM *pgm = NULL;
01096     char *p = search;
01097     while (*p!='\0')
01098     {
01099         int move = expression_list(p,&pgm);
01100         if (move==0)
01101             break;
01102         p+=move;
01103     }
01104     return pgm;
01105 }
01106 
01113 char *find_file(char *name, 
01114                 char *path, 
01115                 int mode) 
01116 {
01117     static char filepath[1024];
01118     static char tempfp[1024];
01119     char *glpath = path?path:getenv("GLPATH");
01120     int found;
01121     char *dir = NULL;
01122 
01123     /*
01124     CAVEAT
01125         Access() is a potential security hole and should never be used.
01126         -HMUG man page
01127      */
01128     if(access(name, mode) == 0){
01129         strncpy(filepath, name, 1024);
01130         return filepath;
01131     }
01132 #ifdef WIN32
01133     if(module_get_exe_path(filepath, 1024)){
01134         sprintf(tempfp, "%s%s", filepath, name);
01135         if(access(tempfp, mode) == 0)
01136             return tempfp;
01137         sprintf(tempfp, "%setc\\%s", filepath, name);
01138         if(access(tempfp, mode) == 0)
01139             return tempfp;
01140         sprintf(tempfp, "%slib\\%s", filepath, name);
01141         if(access(tempfp, mode) == 0)
01142             return tempfp;
01143     }
01144 #else
01145     sprintf(tempfp, "/usr/lib/gridlabd/%s", name);
01146     if(access(tempfp, mode) == 0){
01147         return tempfp;
01148     }
01149     sprintf(tempfp, "/usr/etc/gridlabd/%s", name);
01150     if(access(tempfp, mode) == 0){
01151         return tempfp;
01152     }
01153 #endif
01154     strncpy(filepath,name,sizeof(filepath));
01155 
01156     /* locate unit file on GLPATH if not found locally */
01157     while (!(found=(access(filepath,mode)==0)) && glpath!=NULL)
01158     {
01159         char envbuf[1024];
01160 #ifdef WIN32
01161         char *delim = ";";
01162 #else
01163         char *delim = ":";
01164 #endif
01165         strcpy(envbuf,glpath);
01166         dir = strtok(dir?NULL:envbuf,delim);
01167         if (dir==NULL)
01168             break;
01169         strcpy(filepath,dir);
01170         strcat(filepath,"/");
01171         strcat(filepath,name);
01172     }
01173     return found?filepath:NULL;
01174 }
01175 

GridLAB-DTM Version 1.0
An open-source project initiated by the US Department of Energy