core/load.c

Go to the documentation of this file.
00001 
00045 #include <stdlib.h>
00046 #include <stdio.h>
00047 #include <string.h>
00048 #include <ctype.h>
00049 #include <float.h>
00050 #include <sys/types.h>
00051 #include <sys/stat.h>
00052 #include <math.h>
00053 
00054 #ifdef WIN32
00055 typedef struct _stat STAT;
00056 #define FSTAT _fstat
00057 #define tzset _tzset
00058 #define snprintf _snprintf
00059 #else
00060 #include <unistd.h>
00061 typedef struct stat STAT;
00062 #define FSTAT fstat
00063 #endif
00064 
00065 #define QNAN (sqrt(-1)) /* used to force a quiet NAN return value for bad results */
00066 
00067 #include "object.h"
00068 #include "load.h"
00069 #include "output.h"
00070 #include "random.h"
00071 #include "convert.h"
00072 
00073 static unsigned int linenum=0;
00074 static char filename[1024];
00075 
00076 static char *format_object(char *classname, int id)
00077 {
00078     static char256 buffer;
00079     strcpy(buffer,"(unidentified)");
00080     sprintf(buffer,global_object_format,classname,id);
00081     return buffer;
00082 }
00083 
00084 static OBJECT **object_index = NULL;
00085 static unsigned char *object_linked = NULL;
00086 static unsigned int object_index_size = 65536;
00087 /*static*/ STATUS load_set_index(OBJECT *obj, OBJECTNUM id)
00088 {
00089     if (object_index==NULL)
00090     {
00091         object_index = malloc(sizeof(OBJECT*)*object_index_size);
00092         memset(object_index,0,sizeof(OBJECT*)*object_index_size);
00093         object_linked = malloc(sizeof(unsigned char)*object_index_size);
00094         memset(object_linked,0,sizeof(unsigned char)*object_index_size);
00095     }
00096     if (id>=object_index_size) /* index needs to grow */
00097     {   
00098         int new_size = (id/object_index_size+1)*object_index_size;
00099         object_index = realloc(object_index,sizeof(OBJECT*)*new_size);
00100         memset(object_index+object_index_size,0,sizeof(OBJECT*)*object_index_size);
00101         object_linked = realloc(object_linked,sizeof(unsigned char)*new_size);
00102         memset(object_linked+object_index_size,0,sizeof(unsigned char)*object_index_size);
00103         object_index_size = new_size;
00104     }
00105     if (object_index==NULL) { errno = ENOMEM; return FAILED;}
00106     /* collision check here */
00107     object_index[id] = obj;
00108     object_linked[id] = 0;
00109     return SUCCESS;
00110 }
00111 /*static*/ OBJECT *load_get_index(OBJECTNUM id)
00112 {
00113     if (object_index==NULL || id<0 || id>=object_index_size)
00114         return NULL;
00115     object_linked[id]++;
00116     return object_index[id];
00117 }
00118 static OBJECT *get_next_unlinked(CLASS *oclass)
00119 {
00120     unsigned int id;
00121     if (object_index==NULL)
00122         return NULL;
00123     for (id=0; id<object_index_size; id++)
00124     {
00125         if (object_linked[id]==0 && object_index[id]!=NULL && object_index[id]->oclass==oclass)
00126         {
00127             object_linked[id]++;
00128             return object_index[id];
00129         }
00130     }
00131     return NULL;
00132 }
00133 static void free_index(void)
00134 {
00135     if (object_index!=NULL)
00136         free(object_index);
00137     object_index=NULL;
00138     object_index_size = 65536;
00139 }
00140 
00141 static UNRESOLVED *first_unresolved = NULL;
00142 /*static*/ UNRESOLVED *add_unresolved(OBJECT *by, OBJECT **ref, CLASS *oclass, char *id, unsigned int line, int flags)
00143 {
00144     UNRESOLVED *item = malloc(sizeof(UNRESOLVED));
00145     if (item==NULL) { errno = ENOMEM; return NULL; }
00146     item->by = by;
00147     item->ref = ref;
00148     item->oclass = oclass;
00149     strncpy(item->id,id,sizeof(item->id));
00150     item->line = line;
00151     item->next = first_unresolved;
00152     item->flags = flags;
00153     first_unresolved = item;
00154     return item;
00155 }
00156 static int resolve_list(UNRESOLVED *item)
00157 {
00158     OBJECT *obj;
00159     char classname[33];
00160     char propname[33];
00161     OBJECTNUM id = 0;
00162     char op[2];
00163     char star;
00164     UNRESOLVED *next;
00165     while (item!=NULL)
00166     {   
00167         /* insert raw ID number here. -mh */
00168         
00169         if(0 == strcmp(item->id, "root"))
00170             obj = NULL;
00171         else if (sscanf(item->id,"%32[^.].%32[^:]:",classname,propname)==2)
00172         {
00173             char *value = strchr(item->id,':');
00174             FINDLIST *match;
00175             if (value++==NULL)
00176             {
00177                 output_message("%s(%d): %s reference to %s is missing match value", filename, item->line,
00178                     format_object(item->by->oclass->name, item->by->id), item->id);
00179                 return FAILED;
00180             }
00181             match = find_objects(FL_NEW,FT_CLASS,SAME,classname,AND,FT_PROPERTY,propname,SAME,value,FT_END);
00182             if (match==NULL || match->hit_count==0)
00183             {
00184                 output_message("%s(%d): %s reference to %s does not match any existing objects", filename, item->line,
00185                     format_object(item->by->oclass->name, item->by->id), item->id);
00186                 return FAILED;
00187             }
00188             else if (match->hit_count>1)
00189             {
00190                 output_message("%s(%d): %s reference to %s matches more than one object", filename, item->line,
00191                     format_object(item->by->oclass->name, item->by->id), item->id);
00192                 return FAILED;
00193             }
00194             obj=find_first(match);
00195         }
00196         else if (sscanf(item->id,"%[^:]:id%[+-]%d",classname,op,&id)==3)
00197         {
00198             CLASS *oclass = class_get_class_from_classname(classname);
00199             obj = object_find_by_id(item->by->id + (op[0]=='+'?+1:-1)*id);
00200             if (obj==NULL)
00201             {
00202                 output_message("%s(%d): unable resolve reference from %s to %s", filename, item->line,
00203                     format_object(item->by->oclass->name, item->by->id), item->id);
00204                 return FAILED;
00205             }
00206         }
00207         else if (sscanf(item->id,global_object_scan,classname,&id)==2)
00208         {
00209             obj = load_get_index(id);
00210             if (obj==NULL)
00211             {
00212                 output_message("%s(%d): unable resolve reference from %s to %s", filename, item->line,
00213                     format_object(item->by->oclass->name, item->by->id), item->id);
00214                 return FAILED;
00215             }
00216             if ((strcmp(obj->oclass->name,classname)!=0) && (strcmp("id", classname) != 0))
00217             { /* "id:###" is our wildcard.  some converters use it for dangerous simplicity. -mh */
00218                 output_message("%s(%d): class of reference from %s to %s mismatched", filename, item->line,
00219                     format_object(item->by->oclass->name, item->by->id), item->id);
00220                 return FAILED;
00221             }
00222         }
00223         else if (sscanf(item->id,"%[^:]:%c",classname,&star)==2 && star=='*')
00224         {
00225             CLASS *oclass = class_get_class_from_classname(classname);
00226             obj = get_next_unlinked(oclass);
00227             if (obj==NULL)
00228             {
00229                 output_message("%s(%d): unable resolve reference from %s to %s", filename, item->line,
00230                     format_object(item->by->oclass->name, item->by->id), item->id);
00231                 return FAILED;
00232             }
00233         }
00234         else if ((obj=object_find_name(item->id))!=NULL)
00235         {
00236             /* found it already*/
00237         }
00238         else
00239         {
00240             output_message("%s(%d): syntax error in reference from '%s' to '%s'", filename, item->line, object_name(item->by), item->id);
00241             return FAILED;
00242         }
00243         *(item->ref) = obj;
00244         if ((item->flags&UR_RANKS)==UR_RANKS)
00245             object_set_rank(obj,item->by->rank);
00246         next = item->next;
00247         free(item);
00248         item=next;
00249     }
00250     return SUCCESS;
00251 }
00252 /*static*/ int load_resolve_all()
00253 {
00254     return resolve_list(first_unresolved);
00255 }
00256 
00257 #define PARSER char *_p
00258 #define START int _mm=0, _m=0, _n=0, _l=linenum;
00259 #define ACCEPT { _n+=_m; _p+=_m; _m=0; }
00260 #define HERE (_p+_m)
00261 #define OR {_m=0;}
00262 #define REJECT { linenum=_l; return 0; }
00263 #define WHITE (_m+=white(HERE))
00264 #define LITERAL(X) (_mm=literal(HERE,(X)),_m+=_mm,_mm>0)
00265 #define TERM(X) (_mm=(X),_m+=_mm,_mm>0)
00266 #define COPY(X) {size--; (X)[_n++]=*_p++;}
00267 #define DONE return _n;
00268 #define BEGIN_REPEAT {char *__p=_p; int __mm=_mm, __m=_m, __n=_n, __l=_l; int __ln=linenum;
00269 #define REPEAT _p=__p;_m=__m; _mm=__mm; _n=__n; _l=__l; linenum=__ln;
00270 #define END_REPEAT }
00271 
00272 static void syntax_error(char *p)
00273 {
00274     char context[16], *nl;
00275     strncpy(context,p,15);
00276     nl = strchr(context,'\n');
00277     if (nl!=NULL) *nl='\0'; else context[15]='\0';
00278     if (strlen(context)>0)
00279         output_message("%s(%d): syntax error at '%s...'", filename, linenum, context);
00280     else
00281         output_message("%s(%d): syntax error", filename, linenum);
00282 }
00283 
00284 static int white(PARSER)
00285 {
00286     if (*_p=='\0' || !isspace(*_p))
00287         return 0;
00288     if (*_p=='\n') linenum++;
00289     /* tail recursion to keep consuming whitespace until none left*/
00290     return white(_p+1)+1; 
00291 }
00292 
00293 static int comment(PARSER)
00294 {
00295     int _n = white(_p);
00296     if (_p[_n]=='#')
00297     {
00298         while (_p[_n]!='\n') 
00299             _n++;
00300         linenum++;
00301     }
00302     return _n;
00303 }
00304 
00305 static int literal(PARSER, char *text)
00306 {
00307     if (strncmp(_p,text,strlen(text))==0)
00308         return (int)strlen(text);
00309     return 0;
00310 }
00311 
00312 static int name(PARSER, char *result, int size)
00313 {   /* basic name */
00314     START;
00315     while (size>1 && isalpha(*_p) || isdigit(*_p) || *_p=='_') COPY(result);
00316     result[_n]='\0';
00317     DONE;
00318 }
00319 
00320 static int unitspec(PARSER, UNIT **unit)
00321 {
00322     char result[1024];
00323     int size=sizeof(result);
00324     START;
00325     while (size>1 && isalpha(*_p) || isdigit(*_p) || *_p=='*' || *_p=='/' || *_p=='^') COPY(result);
00326     result[_n]='\0';
00327     if ((*unit=unit_find(result))==NULL)
00328         REJECT;
00329     DONE;
00330 }
00331 
00332 static int unitsuffix(PARSER, UNIT **unit)
00333 {
00334     START;
00335     if (LITERAL("["))
00336     {
00337         if (!TERM(unitspec(HERE,unit)))
00338         {
00339             output_message("%s(%d): missing valid unit after [", filename, linenum);
00340             REJECT;
00341         }
00342         if (!LITERAL("]"))
00343         {
00344             output_message("%s(%d): missing ] after unit '%s'", filename, linenum,(*unit)->name);
00345         }
00346         ACCEPT;
00347         DONE;
00348     }
00349     REJECT;
00350     DONE;
00351 }
00352 
00353 static int nameunit(PARSER,char *result,int size,UNIT **unit)
00354 {
00355     START;
00356     if (TERM(name(HERE,result,size)) && unitsuffix(HERE,unit)) ACCEPT; DONE;
00357     REJECT;
00358 }
00359 
00360 static int dotted_name(PARSER, char *result, int size)
00361 {   /* basic name */
00362     START;
00363     while (size>1 && isalpha(*_p) || isdigit(*_p) || *_p=='_' || *_p=='.') COPY(result);
00364     result[_n]='\0';
00365     DONE;
00366 }
00367 
00368 static int value(PARSER, char *result, int size)
00369 {   
00370     /* everything to a semicolon */
00371     char delim=';';
00372     char *start=_p;
00373     START;
00374     if (*_p=='"')
00375     {
00376         delim='"';
00377         *_p++;
00378         size--;
00379     }
00380     while (size>1 && *_p!='\0' && *_p!=delim && *_p!='\n') COPY(result);
00381     result[_n]='\0';
00382     if (delim!=';')
00383         while (*_p!='\0' && *_p!=';' && *_p!='\n') _p++;
00384     return (int)(_p - start);
00385 }
00386 
00387 static int integer(PARSER, int64 *value)
00388 {
00389     char result[256];
00390     int size=sizeof(result);
00391     START;
00392     while (size>1 && isdigit(*_p)) COPY(result);
00393     result[_n]='\0';
00394     *value=atoi64(result);
00395     return _n;
00396 }
00397 
00398 static int integer32(PARSER, int32 *value)
00399 {
00400     char result[256];
00401     int size=sizeof(result);
00402     START;
00403     while (size>1 && isdigit(*_p)) COPY(result);
00404     result[_n]='\0';
00405     *value=atoi(result);
00406     return _n;
00407 }
00408 
00409 static int real(PARSER, double *value)
00410 {
00411     char result[256];
00412     int size=sizeof(result);
00413     START;
00414     if (*_p=='+' || *_p=='-') COPY(result);
00415     while (size>1 && isdigit(*_p)) COPY(result);
00416     if (*_p=='.') COPY(result);
00417     while (size>1 && isdigit(*_p)) COPY(result);
00418     if (*_p=='E' || *_p=='e') COPY(result);
00419     if (*_p=='+' || *_p=='-') COPY(result);
00420     while (size>1 && isdigit(*_p)) COPY(result);
00421     result[_n]='\0';
00422     *value=atof(result);
00423     return _n;
00424 }
00425 
00426 static int functional(PARSER, double *pValue)
00427 {
00428     char32 fname;
00429     double a, b;
00430     START;
00431     if WHITE ACCEPT;
00432     if (LITERAL("random.") && TERM(name(HERE,fname,sizeof(fname))) && LITERAL("(") && TERM(real(HERE,&a)) && LITERAL(",") && TERM(real(HERE,&b)) && LITERAL(")"))
00433     {
00434         RANDOMTYPE rtype = random_type(fname);
00435         if (rtype==RT_INVALID)
00436         {
00437             output_message("%s(%d): %s is not a valid random distribution", filename,linenum,fname);
00438             REJECT;
00439         }
00440         else
00441         {
00442             *pValue = random_value(rtype,a,b);
00443             ACCEPT;
00444         }
00445     } else if TERM(real(HERE,pValue)) ACCEPT
00446     else 
00447     {
00448         output_message("%s(%d): expected property or functional value", filename,linenum);
00449         REJECT;
00450     }
00451     DONE;
00452 }
00453 
00454 static int functional_unit(PARSER,double *pValue,UNIT **unit)
00455 {
00456     START;
00457     if TERM(functional(HERE,pValue))
00458     {
00459         *unit = NULL;
00460         if WHITE ACCEPT;
00461         if TERM(unitspec(HERE,unit)) ACCEPT;
00462         ACCEPT;
00463         DONE;
00464     }
00465     REJECT;
00466 }
00467 
00468 static int time_value_seconds(PARSER, TIMESTAMP *t)
00469 {
00470     START;
00471     if WHITE ACCEPT;
00472     if (TERM(integer(HERE,t)) && LITERAL("s")) { *t *= TS_SECOND; ACCEPT; DONE;}
00473     OR 
00474     if (TERM(integer(HERE,t)) && LITERAL("S")) { *t *= TS_SECOND; ACCEPT; DONE;}
00475     REJECT;
00476 }
00477 
00478 static int time_value_minutes(PARSER, TIMESTAMP *t)
00479 {
00480     START;
00481     if WHITE ACCEPT;
00482     if (TERM(integer(HERE,t)) && LITERAL("m")) { *t *= 60*TS_SECOND; ACCEPT; DONE;}
00483     OR 
00484     if (TERM(integer(HERE,t)) && LITERAL("M")) { *t *= 60*TS_SECOND; ACCEPT; DONE;}
00485     REJECT;
00486 }
00487 
00488 static int time_value_hours(PARSER, TIMESTAMP *t)
00489 {
00490     START;
00491     if WHITE ACCEPT;
00492     if (TERM(integer(HERE,t)) && LITERAL("h")) { *t *= 3600*TS_SECOND; ACCEPT; DONE;}
00493     OR 
00494     if (TERM(integer(HERE,t)) && LITERAL("H")) { *t *= 3600*TS_SECOND; ACCEPT; DONE;}
00495     REJECT;
00496 }
00497 
00498 static int time_value_days(PARSER, TIMESTAMP *t)
00499 {
00500     START;
00501     if WHITE ACCEPT;
00502     if (TERM(integer(HERE,t)) && LITERAL("d")) { *t *= 86400*TS_SECOND; ACCEPT; DONE;}
00503     OR 
00504     if (TERM(integer(HERE,t)) && LITERAL("D")) { *t *= 86400*TS_SECOND; ACCEPT; DONE;}
00505     REJECT;
00506 }
00507 
00508 /*static*/ int time_value_datetime(PARSER, TIMESTAMP *t)
00509 {
00510     int64 Y,m,d,H,M,S;
00511     START;
00512     if WHITE ACCEPT;
00513     if LITERAL("'") ACCEPT;
00514     if (TERM(integer(HERE,&Y)) && LITERAL("-")
00515         && TERM(integer(HERE,&m)) && LITERAL("-")
00516         && TERM(integer(HERE,&d)) && LITERAL(" ")
00517         && TERM(integer(HERE,&H)) && LITERAL(":")
00518         && TERM(integer(HERE,&M)) && LITERAL(":")
00519         && TERM(integer(HERE,&S)))
00520     { 
00521         struct tm dt = {(int)S,(int)M,(int)H,(int)d,(int)m-1,(int)Y-1900,0,0,0};
00522         int64 tt = mktime(&dt);
00523         if (tt!=-1) {*t=(int64)tt*TS_SECOND;
00524         ACCEPT;
00525         if LITERAL("'") ACCEPT;
00526         DONE;}
00527     }
00528     REJECT;
00529 }
00530 
00531 /*static*/ int time_value(PARSER, TIMESTAMP *t)
00532 {
00533     START;
00534     if WHITE ACCEPT;
00535     if (TERM(time_value_seconds(HERE,t)) && WHITE,LITERAL(";")) {ACCEPT; DONE; }
00536     OR
00537     if (TERM(time_value_minutes(HERE,t)) && WHITE,LITERAL(";")) {ACCEPT; DONE; }
00538     OR
00539     if (TERM(time_value_hours(HERE,t)) && WHITE,LITERAL(";")) {ACCEPT; DONE; }
00540     OR
00541     if (TERM(time_value_days(HERE,t)) && WHITE,LITERAL(";")) {ACCEPT; DONE; }
00542     OR
00543     if (TERM(time_value_datetime(HERE,t)) && WHITE,LITERAL(";")) {ACCEPT; DONE; }
00544     OR
00545     if (TERM(integer(HERE,t)) && WHITE,LITERAL(";")) {ACCEPT; DONE; } 
00546     else REJECT;
00547     DONE;
00548 }
00549 
00550 /*static*/ double load_latitude(char *buffer)
00551 {
00552     int32 d, m=0;
00553     double s=0;
00554     char ns;
00555     if((strcmp(buffer, "none") == 0) || (strcmp(buffer, "NONE") == 0)){
00556         return QNAN;
00557     }
00558     if (sscanf(buffer,"%d%c%d'%lf\"",&d,&ns,&m,&s)>1)
00559     {   
00560         double v = (double)d+(double)m/60+s/3600;
00561         if (v>=0 && v<=90)
00562         {
00563             if (ns=='S')
00564                 return -v;
00565             else if (ns=='N')
00566                 return v;
00567         }
00568     }
00569     output_message("%s(%d): '%s' is not a valid latitude", filename,linenum,buffer);
00570     return QNAN;
00571 }
00572 
00573 /*static*/ double load_longitude(char *buffer)
00574 {
00575     int32 d, m=0;
00576     double s=0;
00577     char ns;
00578     if((strcmp(buffer, "none") == 0) || (strcmp(buffer, "NONE") == 0)){
00579         return QNAN;
00580     }
00581     if (sscanf(buffer,"%d%c%d'%lf\"",&d,&ns,&m,&s)>1)
00582     {   
00583         double v = (double)d+(double)m/60+s/3600;
00584         if (v>=0 && v<=180)
00585         {
00586             if (ns=='W')
00587                 return -v;
00588             else if (ns=='E')
00589                 return v;
00590         }
00591     }
00592     output_message("%s(%d): '%s' is not a valid longitude", filename,linenum,buffer);
00593     return QNAN;
00594 }
00595 
00596 static int clock_properties(PARSER)
00597 {
00598     TIMESTAMP tsval;
00599     char32 timezone;
00600     double realval;
00601     START;
00602     if WHITE ACCEPT;
00603     if (LITERAL("tick") && WHITE)
00604     {
00605         if (TERM(real(HERE,&realval)) && WHITE,LITERAL(";"))
00606         {
00607             if (realval!=TS_RESOLUTION)
00608             {
00609                 output_message("%s(%d): timestamp resolution %g does not match system resolution %g, this version does not support variable tick", filename, linenum, realval, TS_RESOLUTION);
00610                 REJECT;
00611             }
00612             ACCEPT;
00613             goto Next;
00614         }
00615         output_message("%s(%d): expected tick value", filename, linenum);
00616         REJECT;
00617     }
00618     OR if (LITERAL("timestamp") && WHITE)
00619     {
00620         if (TERM(time_value(HERE,&tsval)))
00621         {
00622             global_clock = tsval;
00623             ACCEPT;
00624             goto Next;
00625         }
00626         output_message("%s(%d): expected time value", filename, linenum);
00627         REJECT;
00628     }
00629     OR if (LITERAL("timezone") && WHITE)
00630     {
00631         if (TERM(value(HERE,timezone,sizeof(timezone))) && WHITE,LITERAL(";") && strlen(timezone)>0)
00632         {
00633             if (timestamp_set_tz(timezone)==NULL)
00634                 output_warning("%s(%d): timezone %s is not defined",filename,linenum,timezone);
00635             ACCEPT;
00636             goto Next;
00637         }
00638         output_message("%s(%d): expected time zone specification", filename, linenum);
00639         REJECT;
00640     }
00641     OR if (WHITE,LITERAL("}")) {/* don't accept yet */ DONE;}
00642     OR { syntax_error(HERE); REJECT; }
00643     /* may be repeated */
00644 Next:
00645     if TERM(clock_properties(HERE)) ACCEPT;
00646     DONE;
00647 }
00648 
00649 static int clock_block(PARSER)
00650 {
00651     START;
00652     if WHITE ACCEPT;
00653     if LITERAL("clock") ACCEPT else REJECT;
00654     if WHITE ACCEPT;
00655     if LITERAL("{") ACCEPT 
00656     else 
00657     {
00658         output_message("%s(%d): expected clock block opening {",filename,linenum);
00659         REJECT;
00660     }
00661     if WHITE ACCEPT;
00662     if TERM(clock_properties(HERE)) ACCEPT;
00663     if WHITE ACCEPT;
00664     if LITERAL("}") ACCEPT else 
00665     {
00666         output_message("%s(%d): expected clock block closing }",filename,linenum);
00667         REJECT;
00668     }
00669     DONE;
00670 }
00671 
00672 static int module_properties(PARSER, MODULE *mod)
00673 {
00674     int64 val;
00675     CLASSNAME classname;
00676     char256 propname;
00677     char256 propvalue;
00678     START;
00679     if WHITE ACCEPT;
00680     if (LITERAL("major"))
00681     {
00682         if WHITE ACCEPT;
00683         if (TERM(integer(HERE,&val)))
00684         {
00685             if WHITE ACCEPT;
00686             if LITERAL(";")
00687             {
00688                 if (val!=mod->major)
00689                 {
00690                     output_message("%s(%d): %s has an incompatible module major version", filename,linenum,mod->name);
00691                     REJECT; 
00692                 }
00693                 ACCEPT;
00694                 goto Next;
00695             }
00696             else
00697             {
00698                 output_message("%s(%d): expected ; after %s module major number", filename,linenum, mod->name);
00699                 REJECT; 
00700             }
00701         }
00702         else
00703         {
00704             output_message("%s(%d): expected %s module major number", filename,linenum, mod->name);
00705             REJECT; 
00706         }
00707     } 
00708     OR if (LITERAL("minor"))
00709     {
00710         if WHITE ACCEPT;
00711         if (TERM(integer(HERE,&val)))
00712         {
00713             if WHITE ACCEPT;
00714             if LITERAL(";")
00715             {
00716                 if (val!=mod->minor)
00717                 {
00718                     output_message("%s(%d): %s has an incompatible module minor version", filename,linenum,mod->name);
00719                     REJECT; 
00720                 }
00721                 ACCEPT;
00722                 goto Next;
00723             }
00724             else
00725             {
00726                 output_message("%s(%d): expected ; after %s module minor number", filename,linenum, mod->name);
00727                 REJECT; 
00728             }
00729         }
00730         else
00731         {
00732             output_message("%s(%d): expected %s module minor number", filename,linenum, mod->name);
00733             REJECT; 
00734         }
00735     } 
00736     OR if (LITERAL("class"))
00737     {
00738         if WHITE ACCEPT;
00739         if TERM(name(HERE,classname,sizeof(classname)))
00740         {
00741             if WHITE ACCEPT;
00742             if LITERAL(";")
00743             {
00744                 CLASS *oclass = class_get_class_from_classname(classname);
00745                 if (oclass==NULL || oclass->module!=mod) 
00746                 {
00747                     output_message("%s(%d): module '%s' does not implement class '%s'", filename, linenum, mod->name, classname);
00748                     REJECT; 
00749                 }
00750                 ACCEPT;
00751                 goto Next;
00752             }
00753             else
00754             {
00755                 output_message("%s(%d): expected ; after module %s class %s declaration", filename,linenum, mod->name, classname);
00756                 REJECT; 
00757             }
00758         }
00759         else
00760         {
00761             output_message("%s(%d): missing class name in module %s class declaration", filename,linenum, mod->name);
00762             REJECT; 
00763         }
00764     }
00765     OR if (TERM(name(HERE,propname,sizeof(propname))))
00766     {
00767         if WHITE ACCEPT;
00768         if TERM(value(HERE,propvalue,sizeof(propvalue)))
00769         {
00770             if WHITE ACCEPT;
00771             if LITERAL(";")
00772             {
00773                 if (module_setvar(mod,propname,propvalue)>0)
00774                 {
00775                     ACCEPT;
00776                     goto Next;
00777                 }
00778                 else
00779                 {
00780                     output_message("%s(%d): invalid module %s property '%s'", filename, linenum, mod->name, propname);
00781                     REJECT;
00782                 }
00783             }
00784             else
00785             {
00786                 output_message("%s(%d): expected ; after module %s property specification", filename, linenum, mod->name);
00787                 REJECT;
00788             }
00789         }
00790         else
00791         {
00792             output_message("%s(%d): missing module %s property %s value", filename, linenum, mod->name, propname);
00793             REJECT;
00794         }
00795     }
00796     OR if LITERAL("}") {/* don't accept yet */ DONE;}
00797     OR { syntax_error(HERE); REJECT; }
00798     /* may be repeated */
00799 Next:
00800     if TERM(module_properties(HERE,mod)) ACCEPT;
00801     DONE;
00802 }
00803 
00804 static int module_block(PARSER)
00805 {
00806     char module_name[64];
00807     char fmod[8],mod[54];
00808     MODULE *module;
00809     START;
00810     if WHITE ACCEPT;
00811     if LITERAL("module") ACCEPT else REJECT;
00812     if WHITE ACCEPT;
00813     /* load options should go here and get converted to argc/argv */
00814 
00815     /* foreign module */
00816     if (TERM(name(HERE,fmod,sizeof(fmod))) && LITERAL("::") && TERM(name(HERE,mod,sizeof(mod))))
00817     {
00818         sprintf(module_name,"%s::%s",fmod,mod);
00819         if ((module=module_load(module_name,0,NULL))!=NULL)
00820         {
00821             ACCEPT;
00822         }
00823         else
00824         {
00825             output_message("%s(%d): %s module '%s' load failed, %s", filename, linenum, fmod, mod,strerror(errno));
00826             REJECT;
00827         }
00828     }
00829 
00830     OR 
00831     /* native C/C++ module */
00832     if (TERM(name(HERE,module_name,sizeof(module_name))))
00833     {
00834         if ((module=module_load(module_name,0,NULL))!=NULL) 
00835         {   
00836             ACCEPT;
00837         }
00838         else
00839         {
00840             output_message("%s(%d): module '%s' load failed, %s", filename, linenum, module_name,strerror(errno));
00841             REJECT;
00842         }
00843     }
00844     if WHITE ACCEPT;
00845     if LITERAL(";") {ACCEPT;DONE;}
00846     OR
00847     if LITERAL("{") ACCEPT 
00848     else 
00849     {
00850         output_message("%s(%d): expected module %s block opening {", filename, linenum, module_name);
00851         REJECT;
00852     }
00853     if TERM(module_properties(HERE,module)) ACCEPT else REJECT;
00854     if WHITE ACCEPT;
00855     if LITERAL("}") ACCEPT 
00856     else 
00857     {
00858         output_message("%s(%d): expected module %s block closing }", filename, linenum, module_name);
00859         REJECT;
00860     }
00861     DONE;
00862 }
00863 
00864 static int property_type(PARSER, PROPERTYTYPE *ptype)
00865 {
00866     char32 type;
00867     START;
00868     if WHITE ACCEPT;
00869     if TERM(name(HERE,type,sizeof(type)))
00870     {
00871         *ptype = class_get_propertytype_from_typename(type);
00872         if (*ptype==PT_void) 
00873         {   
00874             output_message("%s(%d): property type %s is not recognized", filename, linenum, type);
00875             REJECT;
00876         }
00877         ACCEPT;
00878     }
00879     else REJECT;
00880     DONE;
00881 }
00882 
00883 static int class_properties(PARSER, CLASS *oclass)
00884 {
00885     PROPERTYTYPE type;
00886     PROPERTYNAME propname;
00887     START;
00888     if WHITE ACCEPT;
00889     if (TERM(property_type(HERE,&type)) && WHITE && TERM(name(HERE,propname,sizeof(propname))) && WHITE && LITERAL(";")) 
00890     {
00891         PROPERTY *prop = class_find_property(oclass,propname);
00892         if (prop==NULL)
00893         {
00894             output_message("%s(%d): property %s is not defined in class %s", filename, linenum, propname, oclass->name);
00895             REJECT; 
00896         }
00897         else if (prop->ptype!=type) 
00898         {
00899             output_message("%s(%d): property %s is defined in class %s as type %s", filename, linenum, propname, oclass->name, class_get_property_typename(prop->ptype));
00900             REJECT;
00901         }
00902         ACCEPT;
00903     }
00904     else if LITERAL("}") {/* don't accept yet */ DONE;}
00905     else { syntax_error(HERE); REJECT; }
00906     /* may be repeated */
00907     if TERM(class_properties(HERE,oclass)) ACCEPT;
00908     DONE;
00909 }
00910 
00911 static int class_block(PARSER)
00912 {
00913     CLASSNAME classname;
00914     CLASS *oclass;
00915     START;
00916     if WHITE ACCEPT;
00917     if LITERAL("class") 
00918     {
00919         if WHITE ACCEPT;
00920         if TERM(name(HERE,classname,sizeof(classname)))
00921         {
00922             if WHITE ACCEPT;
00923             if LITERAL("{")
00924             {
00925                 oclass = class_get_class_from_classname(classname);
00926                 if (oclass==NULL) REJECT;
00927                 ACCEPT;
00928             } 
00929             else 
00930             {
00931                 output_message("%s(%d): expected class %s block opening {",filename,linenum,classname);
00932                 REJECT;
00933             }
00934         }
00935         else
00936         {
00937             output_message("%s(%d): expected class name",filename,linenum);
00938             REJECT;
00939         }
00940         if TERM(class_properties(HERE,oclass)) ACCEPT;
00941         if WHITE ACCEPT;
00942         if LITERAL("}") ACCEPT 
00943         else 
00944         {
00945             output_message("%s(%d): expected closing } after class block", filename, linenum);
00946             REJECT;
00947         }
00948     }
00949     else REJECT;
00950     DONE;
00951 }
00952 
00953 int set_flags(OBJECT *obj, char1024 propval)
00954 {
00955     extern KEYWORD oflags[];
00956     if (convert_to_set(propval,&(obj->flags),object_flag_property())<=0)
00957     {
00958         output_message("%s(%d): flags of %s:%d could not be set to %s", filename, linenum, obj->oclass->name, obj->id, propval);
00959         return 0;
00960     };
00961     return 1;
00962 }
00963 
00964 static int object_properties(PARSER, CLASS *oclass, OBJECT *obj)
00965 {
00966     PROPERTYNAME propname;
00967     char1024 propval;
00968     double dval;
00969     UNIT *unit=NULL;
00970     START;
00971     if WHITE ACCEPT;
00972     if TERM(dotted_name(HERE,propname,sizeof(propname)))
00973     {
00974         PROPERTY *prop = class_find_property(oclass,propname);
00975         if WHITE ACCEPT;
00976         if (prop!=NULL && prop->ptype==PT_double && TERM(functional_unit(HERE,&dval,&unit)))
00977         {
00978             if (prop==NULL)
00979             {
00980                 output_message("%s(%d): property '%s' not found", filename, linenum,propname);
00981                 REJECT;
00982             } else if (unit!=NULL && prop->unit!=NULL && strcmp((char *)unit, "") != 0 && unit_convert_ex(unit,prop->unit,&dval)==0)
00983             {
00984                 output_message("%s(%d): units of value are incompatible with units of property, cannot convert from %s to %s", filename, linenum, unit->name,prop->unit->name);
00985                 REJECT;
00986             }
00987             else if (object_set_double_by_name(obj,propname,dval)==0)
00988             {
00989                 output_message("%s(%d): property %s of %s could not be set to '%g'", filename, linenum, propname, format_object(obj->oclass->name, obj->id), dval);
00990                 REJECT;
00991             }
00992             else
00993                 ACCEPT;
00994         }
00995         else if TERM(value(HERE,propval,sizeof(propval)))
00996         {
00997             if (prop==NULL)
00998             {
00999                 /* check for special properties */
01000                 if (strcmp(propname,"root")==0)
01001                     obj->parent = NULL;
01002                 else if (strcmp(propname,"parent")==0)
01003                     add_unresolved(obj,(void*)&obj->parent,oclass,propval,linenum,UR_RANKS);
01004                 else if (strcmp(propname,"rank")==0)
01005                     obj->rank = atoi(propval);
01006                 else if (strcmp(propname,"clock")==0)
01007                     obj->clock = atoi64(propval);
01008                 else if (strcmp(propname,"latitude")==0)
01009                     obj->latitude = load_latitude(propval);
01010                 else if (strcmp(propname,"longitude")==0)
01011                     obj->longitude = load_longitude(propval);
01012                 else if (strcmp(propname,"in")==0)
01013                     obj->in_svc = convert_to_timestamp(propval);
01014                 else if (strcmp(propname,"out")==0)
01015                     obj->out_svc = convert_to_timestamp(propval);
01016                 else if (strcmp(propname,"name")==0)
01017                     object_set_name(obj,propval);
01018                 else if (strcmp(propname,"flags")==0)
01019                 {
01020                     if(set_flags == 0)
01021                         REJECT;
01022                 }
01023                 else if (strcmp(propname,"library")==0)
01024                 {
01025                     output_warning("%s(%d): libraries not yet supported", filename, linenum);
01026                     ACCEPT;
01027                     DONE;
01028                 }
01029                 else
01030                 {
01031                     output_message("%s(%d): property %s is not defined in class %s", filename, linenum, propname, oclass->name);
01032                     REJECT; 
01033                 }
01034             }
01035             else if (prop->ptype==PT_object)
01036             {   void *addr = object_get_addr(obj,propname);
01037                 if (addr==NULL)
01038                 {
01039                     output_message("%s(%d): unable to set parent of %s", filename, linenum, format_object(oclass->name, obj->id));
01040                     REJECT;
01041                 }
01042                 add_unresolved(obj,addr,oclass,propval,linenum,UR_NONE);
01043             }
01044             else if (object_set_value_by_name(obj,propname,propval)==0)
01045             {
01046                 output_message("%s(%d): property %s of %s could not be set to '%s'", filename, linenum, propname, format_object(obj->oclass->name, obj->id), propval);
01047                 REJECT;
01048             }
01049             ACCEPT;
01050         }
01051         if WHITE ACCEPT;
01052         if LITERAL(";") {ACCEPT;}
01053         else
01054         {
01055             output_message("%s(%d): expected ';' at end of property specification", filename,linenum);
01056             REJECT;
01057         }
01058     }
01059     else if LITERAL("}") {/* don't accept yet */ DONE;}
01060     else { syntax_error(HERE); REJECT; }
01061     /* may be repeated */
01062     if TERM(object_properties(HERE,oclass,obj)) ACCEPT;
01063     DONE;
01064 }
01065 
01066 static int object_name_id(PARSER,char *classname, int64 *id)
01067 {
01068     START;
01069     if WHITE ACCEPT;
01070     if TERM(dotted_name(HERE,classname,sizeof(CLASSNAME)))
01071     {
01072         *id = -1; /* anonymous object */
01073         if LITERAL(":")
01074         {
01075             TERM(integer(HERE,id));
01076         }
01077         ACCEPT;
01078         DONE;
01079     }
01080     else if TERM(name(HERE,classname,sizeof(CLASSNAME)))
01081     {
01082         *id = -1; /* anonymous object */
01083         if LITERAL(":")
01084         {
01085             TERM(integer(HERE,id));
01086         }
01087         ACCEPT;
01088         DONE;
01089     }
01090     else
01091         REJECT;
01092 }
01093 
01094 static int object_name_id_range(PARSER,char *classname, int64 *from, int64 *to)
01095 {
01096     START;
01097     if WHITE ACCEPT;
01098     if (TERM(dotted_name(HERE,classname,sizeof(CLASSNAME))) && LITERAL(":") && TERM(integer(HERE,from)) && LITERAL("..")) ACCEPT
01099     else if (TERM(name(HERE,classname,sizeof(CLASSNAME))) && LITERAL(":") && TERM(integer(HERE,from)) && LITERAL("..")) ACCEPT
01100     else REJECT;
01101     if (TERM(integer(HERE,to))) ACCEPT else 
01102     {
01103         output_message("%s(%d): expected id range end value", filename, linenum);
01104         REJECT;
01105     }
01106     DONE;
01107 }
01108 
01109 static int object_name_id_count(PARSER,char *classname, int64 *count)
01110 {
01111     START;
01112     if WHITE ACCEPT;
01113     if (TERM(dotted_name(HERE,classname,sizeof(CLASSNAME))) && LITERAL(":") && LITERAL("..")) ACCEPT
01114     else if (TERM(name(HERE,classname,sizeof(CLASSNAME))) && LITERAL(":") && LITERAL("..")) ACCEPT
01115     else REJECT;
01116     if (TERM(integer(HERE,count))) ACCEPT else 
01117     {
01118         output_message("%s(%d): expected id count", filename, linenum);
01119         REJECT;
01120     }
01121     DONE;
01122 }
01123 
01124 static int object_block(PARSER)
01125 {
01126     static OBJECT nameobj;
01127     CLASSNAME classname;
01128     CLASS *oclass;
01129     OBJECT *obj;
01130     int64 id=-1, id2=-1;
01131     START;
01132     if WHITE ACCEPT;
01133     if LITERAL("object") ACCEPT else REJECT
01134     if WHITE ACCEPT;
01135     if TERM(object_name_id_range(HERE,classname,&id,&id2))
01136     {
01137         oclass = class_get_class_from_classname(classname);
01138         if (oclass==NULL) REJECT;
01139         id2++;
01140         ACCEPT;
01141     }
01142     else if TERM(object_name_id_count(HERE,classname,&id2))
01143     {
01144         id=-1; id2--;  /* count down to zero inclusive */
01145         oclass = class_get_class_from_classname(classname);
01146         if (oclass==NULL) REJECT;
01147         ACCEPT;
01148     }
01149     else if TERM(object_name_id(HERE,classname,&id))
01150     {
01151         oclass = class_get_class_from_classname(classname);
01152         if (oclass==NULL) 
01153         {
01154             output_message("%s(%d): class '%s' is not known", filename, linenum, classname);
01155             REJECT;
01156         }
01157         ACCEPT;
01158     }
01159     else 
01160     {
01161         output_message("%s(%d): expected object id or range", filename, linenum);
01162         REJECT;
01163     }
01164     if WHITE ACCEPT;
01165     if (LITERAL("{")) ACCEPT else 
01166     {
01167         output_message("%s(%d): expected object block starting {", filename, linenum);
01168         REJECT;
01169     }
01170 
01171     /* id(s) is/are valid */
01172     nameobj.name = classname;
01173     if (id2==-1) id2=id+1; /* create singleton */
01174     BEGIN_REPEAT;
01175     while (id<id2)
01176     {
01177         REPEAT;
01178         obj = &nameobj;
01179         if ((*oclass->create)(&obj,NULL)==FAILED) REJECT;
01180         if (obj==NULL || obj==&nameobj) REJECT;
01181         if (id!=-1 && load_set_index(obj,(OBJECTNUM)id)==FAILED)
01182         {
01183             output_message("%s(%d): unable to index object id number for %s", filename, linenum, format_object(classname, (int)id));
01184             REJECT;
01185         }
01186         if TERM(object_properties(HERE,oclass,obj))
01187         {
01188             ACCEPT; 
01189         } else REJECT;
01190         if (id==-1) id2--; else id++;
01191     }
01192     END_REPEAT;
01193     if WHITE ACCEPT;
01194     if LITERAL("}") ACCEPT else 
01195     {
01196         output_message("%s(%d): expected object block closing }", filename, linenum);
01197         REJECT;
01198     }
01199     DONE;
01200 }
01201 
01202 static int import(PARSER)
01203 {
01204     char32 modname;
01205     char1024 fname;
01206     START;
01207     if WHITE ACCEPT;
01208     if LITERAL("import") 
01209     {
01210         if WHITE ACCEPT;
01211         if TERM(name(HERE,modname,sizeof(modname)))
01212         {
01213             if WHITE ACCEPT;
01214             if TERM(value(HERE,fname,sizeof(fname)))
01215             {
01216                 if LITERAL(";")
01217                 {
01218                     int result;
01219                     MODULE *module = module_find(modname);
01220                     if (module==NULL)
01221                     {
01222                         output_message("%s(%d): module %s not loaded", filename, linenum, modname);
01223                         REJECT;
01224                     }
01225                     result = module_import(module,fname);
01226                     if (result < 0)
01227                     {
01228                         output_message("%s(%d): %d errors loading importing %s into %s module", filename, linenum, -result, fname, modname);
01229                         REJECT;
01230                     }
01231                     else if (result==0)
01232                     {
01233                         output_message("%s(%d): module %s load of %s failed; %s", filename, linenum, modname, fname, strerror(errno));
01234                         REJECT;
01235                     }
01236                     else
01237                     {
01238                         output_verbose("%d objects loaded to %s from %s", result, modname, fname);
01239                         ACCEPT;
01240                     }
01241                 }
01242                 else
01243                 {
01244                     output_message("%s(%d): expected ; after module %s import from %s statement", filename, linenum, modname, fname);
01245                     REJECT;
01246                 }
01247             }
01248             else
01249             {
01250                 output_message("%s(%d): expected filename after module %s import statement", filename, linenum, modname);
01251                 REJECT;
01252             }
01253         }
01254         else
01255         {
01256             output_message("%s(%d): expected module name after import statement", filename, linenum);
01257             REJECT;
01258         }
01259     }
01260     DONE
01261 }
01262 
01263 static int library(PARSER)
01264 {
01265     START;
01266     if WHITE ACCEPT;
01267     if LITERAL("library")
01268     {
01269         char libname[1024];
01270         if WHITE ACCEPT;
01271         if ( TERM(dotted_name(HERE,libname,sizeof(libname))) && WHITE,LITERAL(";"))
01272         {
01273             output_warning("%s(%d): libraries not yet supported", filename, linenum);
01274             ACCEPT;
01275             DONE;
01276         }
01277         else
01278         {
01279             output_message("%s(%d): library syntax error", filename, linenum);
01280             REJECT;
01281         }
01282     }
01283     REJECT;
01284 }
01285 
01286 static int gridlabd_file(PARSER)
01287 {
01288     START;
01289     if WHITE ACCEPT;
01290     OR if TERM(object_block(HERE)) {ACCEPT; DONE;}
01291     OR if TERM(class_block(HERE)) {ACCEPT; DONE;}
01292     OR if TERM(module_block(HERE)) {ACCEPT; DONE;}
01293     OR if TERM(clock_block(HERE)) {ACCEPT; DONE;}
01294     OR if TERM(import(HERE)) {ACCEPT; DONE; }
01295     OR if TERM(library(HERE)) {ACCEPT; DONE; }
01296     OR if (*(HERE)=='\0') {ACCEPT; DONE;}
01297     else REJECT;
01298     DONE;
01299 }
01300 
01301 static int suppress = 0;
01302 static int nesting = 0;
01303 static int macro_line[64];
01304 static int process_macro(char *buffer, int size, char *line, char *filename, int linenum);
01305 static int buffer_read(FILE *fp, char *buffer, char *filename, int size)
01306 {
01307     char line[1024];
01308     int n=0;
01309     int linenum=0;
01310     while (fgets(line,sizeof(line),fp)!=NULL)
01311     {
01312         int len;
01313         char *c = strchr(line,'#');
01314         linenum++;
01315         if (c!=NULL) /* truncate at comment */
01316             strcpy(c,"\n");
01317         len = (int)strlen(line);
01318         if (len>=size-1)
01319             return 0;
01320 
01321         /* check for macros that affect reading */
01322         if (line[0]=='%')
01323         {
01324             /* macro disables reading */
01325             if (process_macro(buffer,size,line,filename,linenum)==FALSE)
01326                 return 0;
01327         }
01328 
01329         /* if reading is enabled */
01330         else if (suppress==0)
01331         {
01332             strcpy(buffer,line);
01333             buffer+=len;
01334             size -= len;
01335             n+=len;
01336         }
01337     }
01338     if (nesting>0)
01339     {
01340         output_message("%s(%d): missing %%endif for %%if at %s(%d)", filename,linenum,filename,macro_line[nesting-1]);
01341         return -1;
01342     }
01343     return n;
01344 }
01345 
01346 static int include_file(char *filename, char *buffer, int size, char *offset)
01347 {
01348     STAT stat;
01349     char *ff = find_file(filename,NULL,R_OK);
01350     FILE *fp;
01351     fp = ff?fopen(ff,"r"):NULL;
01352     if (fp==NULL)
01353     {
01354         output_error("include file '%s' open failed: %s", filename, strerror(errno));
01355         errno = 0;
01356         return 0;
01357     }
01358     if (FSTAT(fileno(fp),&stat)==0 && stat.st_size<size)
01359     {
01361         /* buffer = realloc(buffer,size+stat.st_size); */
01362         output_error("unable to grow size of read buffer for include file '%s'", filename);
01363         errno = 0;
01364         return 0;
01365     }
01366     else
01367     {
01368         output_error("unable to get size of included file '%s'", filename);
01369         errno = 0;
01370         return 0;
01371     }
01372     output_verbose("included file '%s' is %d bytes long", filename,stat.st_size);
01373     if (buffer==NULL)
01374     {
01375         output_error("unable to expand buffer size for file '%s': %s", filename, strerror(errno));
01376         errno = 0;
01377         return 0;
01378     }
01379     output_error("%s: include files not supported", filename);
01380     return 0;
01381 }
01382 
01383 static int process_macro(char *buffer, int size, char *line, char *filename, int linenum)
01384 {
01385     if (strncmp(line,"%endif",6)==0)
01386     {
01387         if (nesting>0)
01388         {
01389             nesting--;
01390             suppress &= ~(1<<nesting);
01391             return TRUE;
01392         }
01393         else
01394             output_error("%s(%d): %%endif is mismatched", filename, linenum);
01395         return TRUE;
01396     }
01397     else if (strncmp(line,"%else",5)==0)
01398     {
01399         if ( (suppress&(1<<nesting)) == (1<<nesting) )
01400             suppress &= ~(1<<nesting);
01401         else
01402             suppress |= (1<<nesting);
01403         
01404     }
01405     else if (strncmp(line,"%ifdef",6)==0)
01406     {
01407         char *term = strchr(line+6,' ');
01408         char value[1024];
01409         if (term==NULL)
01410         {
01411             output_message("%s(%d): %%ifdef macro missing term",filename,linenum);
01412             return FALSE;
01413         }
01414         if (sscanf(term+1,"%[^\n]",value)==1 && global_getvar(value, NULL, 0)==NULL)
01415             suppress |= (1<<nesting);
01416         macro_line[nesting] = linenum;
01417         nesting++;
01418         return TRUE;
01419     }
01420     else if (strncmp(line,"%ifndef",7)==0)
01421     {
01422         char *term = strchr(line+7,' ');
01423         char value[1024];
01424         if (term==NULL)
01425         {
01426             output_message("%s(%d): %%ifndef macro missing term",filename,linenum);
01427             return FALSE;
01428         }
01429         if (sscanf(term+1,"%[^\n]",value)==1 && global_getvar(value, NULL, 0)!=NULL)
01430             suppress |= (1<<nesting);
01431         macro_line[nesting] = linenum;
01432         nesting++;
01433         return TRUE;
01434     }
01435     else if (strncmp(line,"%if",3)==0)
01436     {
01437         char var[32], op[4], *value;
01438         double val;
01439         /*output_message("%s(%d): %%if macros not supported yet", filename,linenum);
01440         return FALSE;*/
01441         if (sscanf(line+4,"%s %[!<>=] %lg",var,op,&val)!=3)
01442         {
01443             output_message("%s(%d): %%if macro statement syntax error", filename,linenum);
01444             return FALSE;
01445         }
01446         value = global_getvar(var, NULL, 0);
01447         if (value==NULL)
01448         {
01449             output_message("%s(%d): %s is not defined", filename,linenum,var);
01450             return FALSE;
01451         }
01452         if (strcmp(op,"<")==0) { if (!val<atof(value)) suppress|=(1<<nesting); }
01453         else if (strcmp(op,">")==0) { if (!val>atof(value)) suppress|=(1<<nesting); }
01454         else if (strcmp(op,">=")==0) { if (!val>=atof(value)) suppress|=(1<<nesting); }
01455         else if (strcmp(op,"<=")==0) { if (!val<=atof(value)) suppress|=(1<<nesting); }
01456         else if (strcmp(op,"==")==0) { if (!val==atof(value)) suppress|=(1<<nesting); }
01457         else if (strcmp(op,"!=")==0) { if (!val!=atof(value)) suppress|=(1<<nesting); }
01458         else
01459         {
01460             output_message("%s(%d): operator %s is not recognized", filename,linenum,op);
01461             return FALSE;
01462         }
01463         macro_line[nesting] = linenum;
01464         nesting++;
01465         return TRUE;
01466     }
01467 
01468     /* handles suppressed macros */
01469     if (suppress!=0)
01470         return TRUE;
01471 
01472     /* these macros can be suppressed */
01473     if (strncmp(line,"%include",8)==0)
01474     {
01475         char *term = strchr(line+8,' ');
01476         char value[1024];
01477         if (term==NULL)
01478         {
01479             output_message("%s(%d): %%include macro missing term",filename,linenum);
01480             return FALSE;
01481         }
01482         if (sscanf(term+1,"%[^\n]",value)==1 && include_file(value,buffer,size,line)<=0)
01483         {
01484             output_message("%s(%d): %%include failed",filename,linenum);
01485             return FALSE;
01486         }
01487         return TRUE;
01488     }
01489     else if (strncmp(line,"%define",7)==0)
01490     {
01491         char *term = strchr(line+7,' ');
01492         char value[1024];
01493         if (term==NULL)
01494         {
01495             output_message("%s(%d): %%define macro missing term",filename,linenum);
01496             return FALSE;
01497         }
01498         if (sscanf(term+1,"%[^\n]",value)==1 && global_setvar(value)==SUCCESS)
01499             return TRUE;
01500         else
01501         {
01502             output_message("%s(%d): %%define term not accepted",filename,linenum);
01503             return FALSE;
01504         }
01505     }
01506     else if (strncmp(line,"%print",6)==0)
01507     {
01508         char *term = strchr(line+6,' ');
01509         char value[1024];
01510         char *result;
01511         if (term==NULL)
01512         {
01513             output_message("%s(%d): %%print macro missing term",filename,linenum);
01514             return FALSE;
01515         }
01516         if (sscanf(term+1,"%[^\n]",value)==1 && (result=global_getvar(value, NULL, 0))!=NULL)
01517         {
01518             output_message("%s(%d): %s=%s", filename, linenum, value, result);
01519             return TRUE;
01520         }
01521         else
01522         {
01523             output_message("%s(%d): %%print term not found",filename,linenum);
01524             return FALSE;
01525         }
01526     }
01527     else
01528         return FALSE;
01529 }
01530 
01531 STATUS loadall_glm(char *file) /**< a pointer to the first character in the file name string */
01532 {
01533     OBJECT *obj, *first = object_get_first();
01534     char *buffer = NULL, *p = NULL;
01535     int fsize = 0;
01536     STATUS status=FAILED;
01537     STAT stat;
01538     char *ext = strrchr(file,'.');
01539     FILE *fp;
01540     int move=0;
01541 
01542     fp = fopen(file,"r");
01543     if (fp==NULL) 
01544         goto Failed;
01545     if (FSTAT(fileno(fp),&stat)==0)
01546         buffer = malloc(fsize=stat.st_size+2);
01547     output_verbose("file '%s' is %d bytes long", file,fsize);
01548     if (buffer==NULL)
01549     {
01550         output_error("unable to allocate buffer for file '%s': %s", file, strerror(errno));
01551         errno = ENOMEM;
01552         goto Done;
01553     }
01554     else
01555         p=buffer;
01556     if (buffer_read(fp,buffer,file,fsize)==0)
01557     {
01558         fclose(fp);
01559         goto Failed;
01560     }
01561     fclose(fp);
01562 
01563     /* reset line counter for parser */
01564     linenum = 1;
01565     while (*p!='\0')
01566     {
01567         move = gridlabd_file(p);
01568         if (move==0)
01569             break;
01570         p+=move;
01571     }
01572     status = (*p=='\0') ? SUCCESS : FAILED;
01573     if (status==FAILED)
01574     {
01575         output_message("%s(%d): load failed", file, linenum);
01576         if (p==0)
01577             output_error("%s doesn't appear to be a GLM file", file);
01578         goto Failed;
01579     }
01580     else if ((status=load_resolve_all())==FAILED)
01581         goto Failed;
01582 
01583     /* establish ranks */
01584     for (obj=first?first:object_get_first(); obj!=NULL; obj=obj->next)
01585         object_set_parent(obj,obj->parent);
01586     output_verbose("%d object%s loaded", object_get_count(), object_get_count()>1?"s":"");
01587     goto Done;
01588 Failed:
01589     if (errno!=0){
01590         output_error("unable to load '%s': %s", file, strerror(errno));
01591     }
01592 Done:
01593     free(buffer);
01594     free_index();
01595     linenum=0;
01596     return status;
01597 }
01598 
01604 STATUS loadall(char *file){
01605     char *buffer = NULL, *p = NULL;
01606     char *ext = strrchr(file,'.');
01607     unsigned int old_obj_count = object_get_count();
01608     unsigned int new_obj_count = 0;
01609     unsigned int i;
01610     STATUS load_status = FAILED;
01611 
01612     if(old_obj_count > 1){
01613         output_error("loadall: only one file load is supported at this time.");
01614         return FAILED; /* not what they expected--do not proceed */
01615     }
01616 
01617     /* handle default extension */
01618     strcpy(filename,file);
01619     if (ext==NULL || ext<file+strlen(file)-5)
01620     {
01621         ext = filename+strlen(filename);
01622         strcat(filename,".glm");
01623     }
01624         
01625     if(ext==NULL || strcmp(ext, ".glm")==0)
01626         load_status = loadall_glm(filename);
01627     else if(strcmp(ext, ".xml")==0)
01628         load_status = loadall_xml(filename);
01629     else
01630         output_error("%s: unable to load unknown file type", filename, ext);
01631     
01632     new_obj_count = object_get_count();
01633 
01634     if((load_status == FAILED) && (old_obj_count < new_obj_count)){
01635         for(i = old_obj_count+1; i <= new_obj_count; ++i){
01636             object_remove_by_id(i);
01637         }
01638     }
01639     return load_status;
01640 }
01641 

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