00001
00011 #include <stdlib.h>
00012 #include <stdio.h>
00013 #include <errno.h>
00014 #include <math.h>
00015 #include <cctype>
00016
00017 #include "../tape/schedule.h"
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 range_list *cron_part(char *part, int first=0){
00028 int off = 0, lo = 0, hi = 0, flip = 0, has_num = 0;
00029 range_list *list = 0;
00030 size_t i = 0, len = strlen(part);
00031 char num[2] = "";
00032
00033
00034 if(part[0] == '*' && first == 0){
00035 return new range_list(-1, -1);
00036 }
00037
00038 for(i = 0; i < len && part[i] != 0; ++i){
00039 if(isdigit(part[i])){
00040 if(flip == 0){
00041 ++has_num;
00042 lo = (lo * 10) + (part[i] - '0');
00043 } else {
00044 ++has_num;
00045 hi = (hi * 10) + (part[i] - '0');
00046 }
00047 } else if(part[i] == '-'){
00048 if(flip == 0){
00049 flip = 1;
00050 has_num = 0;
00051 } else {
00052 gl_error("invalid cron part: cannot use multiple dashes!");
00053 return 0;
00054 }
00055 } else if(part[i] == '*'){
00056 gl_error("invalid cron part: star only valid atomically");
00057 return 0;
00058 } else if(part[i] == ','){
00059
00060 if(has_num == 0){
00061 gl_error("invalid cron part: comma without prior value, or comma interrupting a dash operator");
00062 return 0;
00063 }
00064 list = cron_part(part+i+1, 1);
00065 if(list == 0){
00066 return 0;
00067 }
00068 break;
00069 }
00070 }
00071
00072 if(hi < lo){
00073 if(flip == 0){
00074 hi = lo;
00075 } else {
00076 gl_error("invalid cron part: cannot use a descending range");
00077 return 0;
00078 }
00079 }
00080 return new range_list(lo, hi, list);
00081 }
00082
00083
00084
00085
00086
00087
00088
00089 schedule_list *parse_cron(char *cron_str){
00090 double value = 0.0;
00091 char *mohs, *hods, *doms, *moys, *dows, *vals;
00092 char cron_cpy[128];
00093 range_list *mohr = 0, *hodr = 0, *domr = 0, *moyr = 0, *dowr = 0;
00094 range_list *mohptr = 0, *hodptr = 0, *domptr = 0, *moyptr = 0, *dowptr = 0;
00095 range_list **moh = 0, **hod = 0, **dom = 0, **moy = 0, **dow = 0;
00096 schedule_list **sheap = 0, **sheap2 = 0;
00097 int oobct = 0, listct = 0, i = 0, j = 0, k = 0, l = 0, m = 0, idx = 0;
00098
00099 strcpy(cron_cpy, cron_str);
00100
00101 mohs = strtok(cron_cpy, " \t\n\r");
00102 hods = strtok(NULL, " \t\n\r");
00103 doms = strtok(NULL, " \t\n\r");
00104 moys = strtok(NULL, " \t\n\r");
00105 dows = strtok(NULL, " \t\n\r");
00106 vals = strtok(NULL, " \t\n\r");
00107
00108 if((mohs && hods && doms && moys && dows) == 0){
00109 gl_error("Insufficient arguements in cron line \"%s\"", cron_str);
00110 return 0;
00111 }
00112
00113 mohr = cron_part(mohs);
00114 hodr = cron_part(hods);
00115 domr = cron_part(doms);
00116 moyr = cron_part(moys);
00117 dowr = cron_part(dows);
00118
00119 if((mohr && hodr && domr && moyr && dowr) == 0){
00120 gl_error("Unable to parse arguements in cron line \"%s\"", cron_str);
00121 return 0;
00122 }
00123
00124
00125 if(mohr->check(-1, -1) == 0 && mohr->check(0,60) == 0){
00126 gl_error("minute_of_hour out of bounds: %s", cron_str);
00127 ++oobct;
00128 }
00129 if(hodr->check(-1, -1) == 0 && hodr->check(0,24) == 0){
00130 gl_error("hour_of_day out of bounds: %s", cron_str);
00131 ++oobct;
00132 }
00133 if(domr->check(-1, -1) == 0 && domr->check(0,31) == 0){
00134 gl_error("day_of_month out of bounds: %s", cron_str);
00135 ++oobct;
00136 }
00137 if(moyr->check(-1, -1) == 0 && moyr->check(0,12) == 0){
00138 gl_error("month_of_year out of bounds: %s", cron_str);
00139 ++oobct;
00140 }
00141 if(dowr->check(-1, -1) == 0 && dowr->check(0,7) == 0){
00142 gl_error("day_of_week out of bounds: %s", cron_str);
00143 ++oobct;
00144 }
00145
00146 if(oobct > 0){
00147 gl_error("out-of-bound cron time ranges can cause incorrect schedule calculations");
00148 if(mohr != 0) delete mohr;
00149 if(hodr != 0) delete hodr;
00150 if(domr != 0) delete domr;
00151 if(moyr != 0) delete moyr;
00152 if(dowr != 0) delete dowr;
00153 return 0;
00154 }
00155
00156 if(vals == NULL){
00157 value = 1.0;
00158 } else {
00159 value = atof(vals);
00160 }
00161
00162 listct = mohr->get_count() * hodr->get_count() * domr->get_count() * moyr->get_count() * dowr->get_count();
00163 if(listct < 1){
00164 gl_error("non-postive product of the range list counts, something strange happened");
00165 return 0;
00166 }
00167
00168 sheap = (schedule_list **)malloc(sizeof(schedule_list *) * listct);
00169 sheap2 = (schedule_list **)malloc(sizeof(schedule_list *) * listct);
00170
00171 moh = (range_list **)malloc(sizeof(range_list *) * mohr->get_count());
00172 hod = (range_list **)malloc(sizeof(range_list *) * hodr->get_count());
00173 dom = (range_list **)malloc(sizeof(range_list *) * domr->get_count());
00174 moy = (range_list **)malloc(sizeof(range_list *) * moyr->get_count());
00175 dow = (range_list **)malloc(sizeof(range_list *) * dowr->get_count());
00176
00177 dowptr = dowr;
00178 for(i = 0; i < dowr->get_count() && dowptr != NULL; ++i){
00179 dow[i] = dowptr;
00180 dowptr = dowptr->next;
00181 }
00182 moyptr = moyr;
00183 for(j = 0; j < moyr->get_count() && moyptr != NULL; ++j){
00184 moy[j] = moyptr;
00185 moyptr = moyptr->next;
00186 }
00187 domptr = domr;
00188 for(k = 0; k < domr->get_count() && domptr != NULL; ++k){
00189 dom[k] = domptr;
00190 domptr = domptr->next;
00191 }
00192 hodptr = hodr;
00193 for(l = 0; l < hodr->get_count() && hodptr != NULL; ++l){
00194 hod[l] = hodptr;
00195 hodptr = hodptr->next;
00196 }
00197 mohptr = mohr;
00198 for(m = 0; m <mohr->get_count() && mohptr != NULL; ++m){
00199 moh[m] = mohptr;
00200 mohptr = mohptr->next;
00201 }
00202
00203 for(i = 0; i < dowr->get_count(); ++i){
00204 for(j = 0; j < moyr->get_count(); ++j){
00205 for(k = 0; k < domr->get_count(); ++k){
00206 for(l = 0; l < hodr->get_count(); ++l){
00207 for(m = 0; m <mohr->get_count(); ++m){
00208 sheap[idx] = new schedule_list(moh[m], hod[l], dom[k], moy[j], dow[i], value);
00209 ++idx;
00210 }
00211 }
00212 }
00213 }
00214 }
00215
00216
00217 for(i = 0; i < listct-1; ++i){
00218 sheap[i]->group_right = sheap[i+1];
00219 }
00220 sheap[i]->group_right = 0;
00221
00222 return sheap[0];
00223 }
00224
00225 schedule_list::schedule_list(range_list *moh, range_list *hod, range_list *dom, range_list *moy, range_list *dow, double val){
00226 moh_start = moh->min;
00227 moh_end = moh->max;
00228 hod_start = hod->min;
00229 hod_end = hod->max;
00230 dom_start = dom->min;
00231 dom_end = dom->max;
00232 dow_start = dow->min;
00233 dow_end = dow->max;
00234 moy_start = moy->min;
00235 moy_end = moy->max;
00236 scale = val;
00237 next = 0;
00238 group_left = 0;
00239 group_right = 0;
00240
00241 if(dow_start == -1 && dow_end == -1 && dom_start == -1 && dom_end == -1){
00242 dow_or_dom = schedule_list::wor_skip;
00243 } else if(dow_start == -1 && dow_end == -1 && dom_start != -1 && dom_end != -1){
00244 dow_or_dom = schedule_list::wor_month;
00245 } else if(dow_start != -1 && dow_end != -1 && dom_start == -1 && dom_end == -1){
00246 dow_or_dom = schedule_list::wor_week;
00247 } else {
00248 dow_or_dom = wor_skip;
00249 }
00250 }
00251
00253
00255 CLASS* schedule::oclass = NULL;
00256 schedule *schedule::defaults = NULL;
00257
00258 schedule::schedule(MODULE *module)
00259 {
00260
00261
00262 if (oclass==NULL)
00263 {
00264
00265 oclass = gl_register_class(module,"schedule",sizeof(schedule),PC_PRETOPDOWN);
00266 if (oclass==NULL)
00267 GL_THROW("unable to register object class implemented by %s",__FILE__);
00268
00269
00270 if (gl_publish_variable(oclass,
00271 PT_double, "value", PADDR(currval), PT_ACCESS, PA_REFERENCE,
00272 PT_double, "default_value", PADDR(default_value),
00273 PT_timestamp, "next_ts", PADDR(next_ts), PT_ACCESS, PA_REFERENCE,
00274 PT_enumeration, "state", PADDR(state), PT_ACCESS, PA_REFERENCE,
00275 PT_KEYWORD, "INIT", TS_INIT,
00276 PT_KEYWORD, "OPEN", TS_OPEN,
00277 PT_KEYWORD, "DONE", TS_DONE,
00278 PT_KEYWORD, "ERROR", TS_ERROR,
00279 PT_char256, "error_msg", PADDR(errmsg), PT_ACCESS, PA_REFERENCE,
00280 PT_char256, "filename", PADDR(filename),
00281 PT_char1024, "schedule", PADDR(sched),
00282 NULL)<1)
00283 GL_THROW("unable to publish properties in %s",__FILE__);
00284
00285
00286 defaults = this;
00287 memset(this, 0, sizeof(schedule));
00288 default_value = 1.0;
00289 next_ts = TS_INIT;
00290 }
00291 }
00292
00293 int schedule::create()
00294 {
00295
00296 memcpy(this,defaults,sizeof(schedule));
00297 return 1;
00298 }
00299
00300 int schedule::init(OBJECT *parent)
00301 {
00302 OBJECT *hdr = OBJECTHDR(this);
00303 int rv = 1;
00304
00305 currval = default_value;
00306 if(filename[0] == 0){
00307 rv = parse_schedule();
00308 } else {
00309 rv = open_sched_file();
00310 }
00311
00312 if(rv == 0){
00313 state = TS_ERROR;
00314 strcpy(errmsg, "Error reading & parsing schedule input source");
00315 }
00316
00317
00318
00319
00320 if(state == TS_INIT){
00321 state = TS_OPEN;
00322 } else if(state == TS_ERROR){
00323 gl_error("unable to open schedule");
00324 state = TS_DONE;
00325 }
00326
00327 return 1;
00328 }
00329
00330
00331 int test_sched_dt(int lo, int hi, int dt){
00332 if(lo != -1 && hi != -1){
00333 if(lo <= dt){
00334 if(hi == lo){
00335 if(dt == lo){
00336 return 1;
00337 }
00338 } else if(dt <= hi){
00339 return 1;
00340 }
00341 }
00342 } else if(lo == -1 && hi == -1){
00343 return 1;
00344 }
00345 return 0;
00346 }
00347 double get_sched_list_value(schedule_list *sched_list, TIMESTAMP t1){
00348 double res = 0.0;
00349 return res;
00350 }
00351
00352 TIMESTAMP schedule::presync(TIMESTAMP t0, TIMESTAMP t1){
00353
00354 DATETIME dt;
00355 TIMESTAMP min = TS_NEVER;
00356 TIMESTAMP max = TS_NEVER;
00357 int res = 0;
00358
00359 schedule_list *lptr = 0, *child = 0;
00360
00361
00362
00363 gl_localtime(t1, &dt);
00364
00365 currval = default_value;
00366
00367 for(lptr = sched_list; lptr != NULL; lptr = lptr->next){
00368
00369
00370
00371
00372
00373 for(child = lptr; child != NULL; child = child->group_right){
00374 res = test_sched_dt(child->moy_start, child->moy_end, dt.month);
00375 if(res == 0){
00376 continue;
00377 }
00378 if(child->dow_or_dom == schedule_list::wor_skip){
00379 res = 1;
00380 } else if(child->dow_or_dom == schedule_list::wor_month){
00381 res = test_sched_dt(child->dom_start, child->dom_end, dt.day);
00382 } else if(child->dow_or_dom == schedule_list::wor_week){
00383 res = test_sched_dt(child->dow_start, child->dow_end, dt.weekday);
00384 } else if(child->dow_or_dom == schedule_list::wor_both){
00385 res = test_sched_dt(child->dom_start, child->dom_end, dt.day) + test_sched_dt(child->dow_start, child->dow_end, dt.weekday);
00386 } else {
00387 gl_verbose("invalid day of week/day of month flag");
00388 continue;
00389 }
00390 if(res == 0){
00391 continue;
00392 }
00393 res = test_sched_dt(child->hod_start, child->hod_end, dt.hour);
00394 res += test_sched_dt(child->moh_start, child->moh_end, dt.minute > 59 ? 59 : dt.minute);
00395 if(res == 2){
00396 currval = child->scale;
00397 break;
00398 }
00399 }
00400 }
00401
00402 return TS_NEVER;
00403 }
00404
00405 TIMESTAMP schedule::sync(TIMESTAMP t0, TIMESTAMP t1){
00406 return TS_NEVER;
00407 }
00408
00414 int schedule::parse_schedule(){
00415 char sched_buf[1025];
00416 char *sched_ptr[128], *temp = 0;
00417 size_t i = 0, token_ct = 1;
00418 schedule_list *first = 0, *push = 0, *next = 0;
00419
00420 strcpy(sched_buf, this->sched);
00421
00422
00423
00424 temp = strtok(sched_buf, ";");
00425 for(i = 0; i < 128 && temp != NULL; ++i){
00426 sched_ptr[i] = temp;
00427 temp = strtok(NULL, ";");
00428 }
00429
00430 token_ct = i;
00431
00432
00433 for(i = 0; i < token_ct; ++i){
00434 push = next;
00435 next = parse_cron(sched_ptr[i]);
00436 if(next == 0){
00437 gl_error("Error parsing schedule string");
00438 return 0;
00439 }
00440 if(first == 0){
00441 first = next;
00442 } else {
00443 push->next = next;
00444 }
00445 }
00446
00447 sched_list = first;
00448 return 1;
00449 }
00450
00455 int schedule::open_sched_file(){
00456 gl_error("schedule file input not yet supported");
00457 return 0;
00458 }
00459
00461
00463
00464 void new_schedule(MODULE *mod){
00465 new schedule(mod);
00466 }
00467
00468 EXPORT int create_schedule(OBJECT **obj, OBJECT *parent)
00469 {
00470 *obj = gl_create_object(schedule::oclass);
00471 if (*obj!=NULL)
00472 {
00473 schedule *my = OBJECTDATA(*obj,schedule);
00474 gl_set_parent(*obj,parent);
00475 my->create();
00476 return 1;
00477 }
00478 return 0;
00479 }
00480
00481 EXPORT int init_schedule(OBJECT *obj)
00482 {
00483 schedule *my = OBJECTDATA(obj,schedule);
00484 return my->init(obj->parent);
00485 }
00486
00487 EXPORT TIMESTAMP commit_schedule(OBJECT *obj, TIMESTAMP t1, TIMESTAMP t2){
00488
00489 return TS_NEVER;
00490 }
00491
00492 EXPORT TIMESTAMP sync_schedule(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
00493 {
00494 schedule *my = OBJECTDATA(obj, schedule);
00495 TIMESTAMP t1 = my->sync(obj->clock, t0);
00496
00497 try {
00498 switch (pass)
00499 {
00500 case PC_PRETOPDOWN:
00501 t1 = my->presync(obj->clock, t0);
00502 break;
00503
00504 case PC_BOTTOMUP:
00505 t1 = my->sync(obj->clock, t0);
00506 obj->clock = t0;
00507 break;
00508
00509 default:
00510 gl_error("schedule::sync- invalid pass configuration");
00511 t1 = TS_INVALID;
00512 }
00513 }
00514 catch (char *msg)
00515 {
00516 gl_error("schedule::sync exception caught: %s", msg);
00517 t1 = TS_INVALID;
00518 }
00519 catch (...)
00520 {
00521 gl_error("schedule::sync exception caught: no info");
00522 t1 = TS_INVALID;
00523 }
00524
00525 obj->clock = t0;
00526 return t1;
00527 }
00528