00001
00008 #include "csv_reader.h"
00009
00010 CLASS *csv_reader::oclass = 0;
00011
00012 EXPORT int create_csv_reader(OBJECT **obj, OBJECT *parent){
00013 csv_reader *my = 0;
00014 *obj = gl_create_object(csv_reader::oclass);
00015 if(*obj != NULL){
00016 return 1;
00017 }
00018
00019 return 0;
00020 }
00021
00022 EXPORT int init_csv_reader(OBJECT **obj, OBJECT *parent){
00023 csv_reader *my = OBJECTDATA(obj,csv_reader);
00024 return 1;
00025 }
00026
00028 EXPORT TIMESTAMP sync_csv_reader(OBJECT *obj, TIMESTAMP t0){
00029 return TS_NEVER;
00030 }
00031
00032 csv_reader::csv_reader(){
00033 memset(this, 0, sizeof(csv_reader));
00034 }
00035
00036 csv_reader::csv_reader(MODULE *module){
00037 memset(this, 0, sizeof(csv_reader));
00038 if (oclass==NULL)
00039 {
00040 oclass = gl_register_class(module,"csv_reader",sizeof(csv_reader),NULL);
00041 if (gl_publish_variable(oclass,
00042 PT_int32,"index",PADDR(index),PT_ACCESS,PA_REFERENCE,
00043 PT_char32,"city_name",PADDR(city_name),
00044 PT_char32,"state_name",PADDR(state_name),
00045 PT_double,"lat_deg",PADDR(lat_deg),
00046 PT_double,"lat_min",PADDR(lat_min),
00047 PT_double,"long_deg", PADDR(long_deg),
00048 PT_double,"long_min",PADDR(long_min),
00049 PT_double,"low_temp",PADDR(low_temp),PT_ACCESS,PA_REFERENCE,
00050 PT_double,"high_temp",PADDR(high_temp),PT_ACCESS,PA_REFERENCE,
00051 PT_double,"peak_solar",PADDR(peak_solar),PT_ACCESS,PA_REFERENCE,
00052 PT_int32,"elevation",PADDR(elevation),
00053 PT_enumeration,"status",PADDR(status),PT_ACCESS,PA_REFERENCE,
00054 PT_KEYWORD,"INIT",(enumeration)CR_INIT,
00055 PT_KEYWORD,"OPEN",(enumeration)CR_OPEN,
00056 PT_KEYWORD,"ERROR",(enumeration)CR_ERROR,
00057 PT_char32,"timefmt",PADDR(timefmt),
00058 PT_char32,"timezone",PADDR(timezone),
00059 PT_double,"timezone_offset",PADDR(tz_numval),
00060 PT_char256,"columns",PADDR(columns_str),
00061 PT_char256,"filename",PADDR(filename),
00062 NULL)<1) GL_THROW("unable to publish properties in %s",__FILE__);
00063 memset(this,0,sizeof(csv_reader));
00064 }
00065 }
00066
00070 int csv_reader::open(const char *file){
00071 char line[1024];
00072 char filename[128];
00073 int has_cols = 0;
00074 int linenum = 0;
00075 int i = 0;
00076 OBJECT *obj = OBJECTHDR(this);
00077 weather *wtr = 0;
00078
00079 if(file == 0){
00080 gl_error("csv_reader has no input file name!");
00081
00082
00083
00084
00085 return 0;
00086 }
00087
00088 strncpy(filename, file, 127);
00089 infile = fopen(filename, "r");
00090 if(infile == 0){
00091 gl_error("csv_reader could not open \'%s\' for input!", file);
00092
00093
00094
00095
00096
00097 return 0;
00098 }
00099
00100 if(columns_str[0] != 0){
00101 if(0 == read_header(columns_str)){
00102 gl_error("csv_reader::open ~ column header read failure from explicit headers");
00103 return 0;
00104 } else {
00105 has_cols = 1;
00106 }
00107 }
00108 while(fgets(line, 1024, infile) != NULL){
00109 ++linenum;
00110
00111
00112 size_t _len = strlen(line);
00113 if(line[0] == '#'){
00114 continue;
00115 }
00116 else if(strlen(line) < 1){
00117 continue;
00118 }
00119 else if(line[0] == '$'){
00120 if(0 == read_prop(line+1)){
00121 gl_error("csv_reader::open ~ property read failure on line %i", linenum);
00122 return 0;
00123 } else {
00124 continue;
00125 }
00126 }
00127 else if(has_cols == 0){
00128 if(0 == read_header(line)){
00129 gl_error("csv_reader::open ~ column header read failure on line %i", linenum);
00130 return 0;
00131 } else {
00132 has_cols = 1;
00133 }
00134 } else {
00135 int line_rv = read_line(line, linenum);
00136 if(0 == line_rv){
00137 gl_error("csv_reader::open ~ data line read failure on line %i", linenum);
00138 return 0;
00139 } else if (1 == line_rv){
00140 ++sample_ct;
00141 } else if (2 == line_rv){
00142 ;
00143 }
00144 }
00145 }
00146
00147
00148 samples = (weather**)malloc(sizeof(weather *) * (size_t) sample_ct);
00149 for(i = 0, wtr = weather_root; i < sample_ct && wtr != NULL; ++i, wtr=wtr->next){
00150 samples[i] = wtr;
00151 }
00152 sample_ct = i;
00153
00154
00155
00156
00157
00158 obj->latitude = lat_deg + (lat_deg > 0 ? lat_min : -lat_min) / 60;
00159 obj->longitude = long_deg + (long_deg > 0 ? long_min : -long_min) / 60;
00160
00161 return 1;
00162 }
00163
00164 int csv_reader::read_prop(char *line){
00165 OBJECT *my = OBJECTHDR(this);
00166 char *split = strchr(line, '=');
00167 char propstr[256], valstr[256];
00168 PROPERTY *prop = 0;
00169
00170 if(split == NULL){
00171 gl_error("csv_reader::read_prop ~ missing \'=\' seperator");
00172
00173
00174
00175
00176 return 0;
00177 }
00178
00179 if(2 != sscanf(line, "%[^=]=%[^\n#]", propstr, valstr)){
00180 gl_error("csv_reader::read_prop ~ error reading property & value");
00181
00182
00183
00184
00185 return 0;
00186 }
00187
00188 prop = gl_find_property(oclass, propstr);
00189 if(prop == 0){
00190 gl_error("csv_reader::read_prop ~ unrecognized csv_reader property \'%s\'", propstr);
00191
00192
00193
00194
00195
00196 return 0;
00197 }
00198
00199
00200
00201
00202
00203
00204
00205 void *addr = (void *)((uint64)this + (uint64)prop->addr);
00206 if(prop->ptype == PT_double){
00207 if(1 != sscanf(valstr, "%lg", addr)){
00208 gl_error("csv_reader::read_prop ~ unable to set property \'%s\' to \'%s\'", propstr, valstr);
00209
00210
00211
00212
00213 return 0;
00214 }
00215 } else if(prop->ptype == PT_char32){
00216 strncpy((char *)addr, valstr, 32);
00217
00218
00219 } else {
00220 gl_error("csv_reader::read_prop ~ unable to convert property \'%s\' due to type restrictions", propstr);
00221
00222
00223
00224
00225
00226 return 0;
00227 }
00228 return 1;
00229 }
00230
00231 int csv_reader::read_header(char *line){
00232 struct cmnlist {
00233 char *name;
00234 PROPERTY *column;
00235 struct cmnlist *next;
00236 };
00237 char buffer[1024];
00238 int index = 0, start_idx = 0;
00239 int done = 0;
00240 int i = 0;
00241 PROPERTY *prop = 0;
00242 struct cmnlist *first = 0, *last = 0, *temp = 0;
00243
00244
00245
00246 memset(buffer, 0, 1024);
00247 strncpy(buffer, line, 1023);
00248
00249
00250 while(index < 1024 && 0 == done){
00251 while(buffer[index] != 0 && buffer[index] != ',' && buffer[index] != '\n' && buffer[index] != '\r' && buffer[index] != '#'){
00252 ++index;
00253 }
00254 if(buffer[index] == ','){
00255 buffer[index] = 0;
00256 ++index;
00257 }
00258 if(buffer[index] == '\n' || buffer[index] == '\r' || buffer[index] == '#'){
00259 buffer[index] = 0;
00260 }
00261
00262 temp = (struct cmnlist *)malloc(sizeof(struct cmnlist));
00263 temp->name = buffer+start_idx;
00264 temp->column = prop;
00265 temp->next = 0;
00266
00267 start_idx = index;
00268 ++column_ct;
00269
00270 if(first == 0){
00271 first = last = temp;
00272 } else {
00273 last->next = temp;
00274 last = temp;
00275 }
00276
00277 if(buffer[index] == 0 || buffer[index] == '\n' || buffer[index] == '\r'){
00278 done = 1;
00279 break;
00280 }
00281 }
00282
00283
00284 temp = first;
00285 columns = (PROPERTY **)malloc(sizeof(PROPERTY *) * (size_t)column_ct);
00286 while(temp != 0 && i < column_ct){
00287 temp->column = gl_find_property(weather::oclass, temp->name);
00288 if(temp->column == 0){
00289 gl_error("csv_reader::read_header ~ unable to find column property \'%s\''", temp->name);
00290
00291
00292
00293
00294 return 0;
00295 }
00296 columns[i] = temp->column;
00297 temp = temp->next;
00298 ++i;
00299 }
00300 return 1;
00301 }
00302
00303 int csv_reader::read_line(char *line, int linenum){
00304 int done = 0;
00305 int col = 0;
00306 char buffer[1024];
00307 char *token = 0;
00308 weather *sample = 0;
00309 int64 t1, t2;
00310
00311
00312 strncpy(buffer, line, 1023);
00313 token = strtok(buffer, " ,\t\n\r");
00314
00315 if(token == 0){
00316 return 2;
00317 }
00318
00319 sample = new weather();
00320
00321 if(timefmt[0] == 0){
00322 TIMESTAMP ts = callback->time.convert_to_timestamp(token);
00323 DATETIME dt;
00324 dt.nanosecond = 0;
00325 if ( ts!=TS_INVALID && ts!=TS_NEVER && callback->time.local_datetime(ts,&dt) )
00326 {
00327 sample->month = dt.month;
00328 sample->day = dt.day;
00329 sample->hour = dt.hour;
00330 sample->minute = dt.minute;
00331 sample->second = dt.second;
00332
00333
00334 }
00335 else if(sscanf(token, "%d:%d:%d:%d:%d", &sample->month, &sample->day, &sample->hour, &sample->minute, &sample->second) < 1){
00336 gl_error("csv_reader::read_line ~ unable to read time string \'%s\' with default format", token);
00337
00338
00339
00340
00341 delete sample;
00342 return 0;
00343 }
00344 } else {
00345 if(sscanf(token, timefmt.get_string(), &sample->month, &sample->day, &sample->hour, &sample->minute, &sample->second) < 1){
00346 gl_error("csv_reader::read_line ~ unable to read time string \'%s\' with format \'%s\'", token, timefmt.get_string());
00347
00348
00349
00350
00351 delete sample;
00352 return 0;
00353 }
00354 }
00355
00356 if(weather_last != 0){
00357 t1 = weather_last->month * 31*24*60*60 +
00358 weather_last->day * 24*60*60 +
00359 weather_last->hour * 60*60 +
00360 weather_last->minute * 60 +
00361 weather_last->second;
00362 t2 = sample->month * 31*24*60*60 +
00363 sample->day * 24*60*60 +
00364 sample->hour * 60*60 +
00365 sample->minute * 60 +
00366 sample->second;
00367 if(t1 >= t2){
00368 gl_warning("csv_reader::read_line ~ sample on line %i does not advance in time and has been discarded", linenum);
00369 delete sample;
00370 return 2;
00371 }
00372 }
00373
00374 while((token=strtok(NULL, ",\n\r")) != 0 && col < column_ct){
00375 if(columns[col]->ptype == PT_double){
00376 double *dptr = (double *)((uint64)(columns[col]->addr) + (uint64)(sample));
00377 if(sscanf(token, "%lg", dptr) != 1){
00378 gl_error("csv_reader::read_line ~ unable to set value \'%s\' to double property \'%s\'", token, columns[col]->name);
00379
00380
00381
00382
00383 delete sample;
00384 return 0;
00385 }
00386 }
00387 ++col;
00388 }
00389
00390 if(weather_root == 0){
00391 weather_root = sample;
00392 } else {
00393 weather_last->next = sample;
00394 }
00395 weather_last = sample;
00396
00397 return 1;
00398 }
00399
00400 TIMESTAMP csv_reader::get_data(TIMESTAMP t0, double *temp, double *humid, double *direct, double *diffuse, double *global, double *extra_global, double *wind,double *winddir, double *opaque, double *total, double *rain, double *snow, double *pressure){
00401 DATETIME now, then;
00402
00403 int next_year = 0;
00404 int i = 0;
00405 int idx = index;
00406 int start = index;
00407 now.nanosecond = 0;
00408 then.nanosecond = 0;
00409
00410 int localres;
00411
00412 if(t0 < next_ts){
00413 return -next_ts;
00414 }
00415
00416 localres = gl_localtime(t0, &now);
00417
00418 gl_debug("csv_reader::get_data start");
00419 if(next_ts == 0){
00420
00421 DATETIME guess_dt;
00422 guess_dt.nanosecond = 0;
00423 TIMESTAMP guess_ts;
00424 int i;
00425 #if 0
00426
00427
00428
00429
00430 for(i = 0; i < sample_ct; ++i){
00431 guess_dt.year = now.year;
00432 guess_dt.month = samples[sample_ct-i-1]->month;
00433 guess_dt.day = samples[sample_ct-i-1]->day;
00434 guess_dt.hour = samples[sample_ct-i-1]->hour;
00435 guess_dt.minute = samples[sample_ct-i-1]->minute;
00436 guess_dt.second = samples[sample_ct-i-1]->second;
00437 strcpy(guess_dt.tz, now.tz);
00438
00439 guess_ts = (TIMESTAMP)gl_mktime(&guess_dt);
00440
00441 if(guess_ts <= t0){
00442 break;
00443 }
00444 }
00445 index = sample_ct - i - 1;
00446 #endif
00447 for(i = 0; i < sample_ct; ++i){
00448 guess_dt.year = now.year;
00449 guess_dt.month = samples[i]->month;
00450 guess_dt.day = samples[i]->day;
00451 guess_dt.hour = samples[i]->hour;
00452 guess_dt.minute = samples[i]->minute;
00453 guess_dt.second = samples[i]->second;
00454 strcpy(guess_dt.tz, now.tz);
00455
00456 if(guess_dt.month == 2 && guess_dt.day == 29){
00457 if(!ISLEAPYEAR(now.year))
00458 continue;
00459 }
00460 guess_ts = (TIMESTAMP)gl_mktime(&guess_dt);
00461
00462 if(guess_ts >= t0){
00463 i -= 1;
00464 break;
00465 }
00466 }
00467
00468 index = i;
00469
00470 if(index > -1 && index < sample_ct){
00471 *temp = samples[index]->temperature;
00472 *humid = samples[index]->humidity;
00473 *direct = samples[index]->solar_dir;
00474 *diffuse = samples[index]->solar_diff;
00475 *global = samples[index]->solar_global;
00476 *extra_global = samples[index]->global_horizontal_extra;
00477 *wind = samples[index]->wind_speed;
00478 *winddir = samples[index]->wind_dir;
00479 *opaque = samples[index]-> opq_sky_cov;
00480 *total = samples[index]-> tot_sky_cov;
00481 *rain = samples[index]->rainfall;
00482 *snow = samples[index]->snowdepth;
00483 *pressure = samples[index]->pressure;
00484 } else {
00485 *temp = samples[sample_ct - 1]->temperature;
00486 *humid = samples[sample_ct - 1]->humidity;
00487 *direct = samples[sample_ct - 1]->solar_dir;
00488 *diffuse = samples[sample_ct - 1]->solar_diff;
00489 *global = samples[sample_ct - 1]->solar_global;
00490 *extra_global = samples[sample_ct - 1]->global_horizontal_extra;
00491 *wind = samples[sample_ct - 1]->wind_speed;
00492 *winddir = samples[sample_ct - 1]->wind_dir;
00493 *opaque = samples[sample_ct - 1]-> opq_sky_cov;
00494 *total = samples[sample_ct - 1]-> tot_sky_cov;
00495 *rain = samples[sample_ct - 1]->rainfall;
00496 *snow = samples[sample_ct - 1]->snowdepth;
00497 *pressure = samples[sample_ct - 1]->pressure;
00498 }
00499
00500 then.year = now.year + (index+1 == sample_ct ? 1 : 0);
00501 then.month = samples[(index+1)%sample_ct]->month;
00502 then.day = samples[(index+1)%sample_ct]->day;
00503 then.hour = samples[(index+1)%sample_ct]->hour;
00504 then.minute = samples[(index+1)%sample_ct]->minute;
00505 then.second = samples[(index+1)%sample_ct]->second;
00506 then.nanosecond = 0;
00507 strcpy(then.tz, now.tz);
00508
00509 next_ts = (TIMESTAMP)gl_mktime(&then);
00510
00511
00512 return -next_ts;
00513 }
00514
00515 if(sample_ct == 1){
00516 next_ts += 365 * 24 * 3600;
00517 return -next_ts;
00518 }
00519
00520 do{
00521
00522 if(index+1 >= sample_ct){
00523 index = 0;
00524 } else {
00525 ++index;
00526 }
00527
00528 if(index+1 == sample_ct){
00529 next_year = 1;
00530 } else {
00531 next_year = 0;
00532 }
00533
00534 then.year = now.year + next_year;
00535 then.month = samples[(index+1)%sample_ct]->month;
00536 then.day = samples[(index+1)%sample_ct]->day;
00537 then.hour = samples[(index+1)%sample_ct]->hour;
00538 then.minute = samples[(index+1)%sample_ct]->minute;
00539 then.second = samples[(index+1)%sample_ct]->second;
00540 if(then.month == 2 && then.day == 29){
00541 if(!ISLEAPYEAR(then.year))
00542 continue;
00543 }
00544 strcpy(then.tz, now.tz);
00545
00546
00547 next_ts = (TIMESTAMP)gl_mktime(&then);
00548 } while (next_ts < t0 && index != start);
00549
00550 *temp = samples[index]->temperature;
00551 *humid = samples[index]->humidity;
00552 *direct = samples[index]->solar_dir;
00553 *diffuse = samples[index]->solar_diff;
00554 *global = samples[index]->solar_global;
00555 *extra_global = samples[index]->global_horizontal_extra;
00556 *wind = samples[index]->wind_speed;
00557 *winddir = samples[index]->wind_dir;
00558 *opaque = samples[index]->opq_sky_cov;
00559 *total = samples[index]->tot_sky_cov;
00560 *rain = samples[index]->rainfall;
00561 *snow = samples[index]->snowdepth;
00562 *pressure = samples[index]->pressure;
00563
00564
00565 if(index == start){
00566 GL_THROW("something strange happened with the schedule in csv_reader");
00567
00568
00569
00570
00571
00572 }
00573
00574 gl_debug("csv_reader::get_data end");
00575
00576 return -next_ts;
00577 }
00578
00579