void MapFile::PerformSubstitution(ExtArray<MyString> & groups, const MyString pattern, MyString & output) { for (int index = 0; index < pattern.Length(); index++) { if ('\\' == pattern[index]) { index++; if (index < pattern.Length()) { if ('1' <= pattern[index] && '9' >= pattern[index]) { int match = pattern[index] - '0'; if (groups.getlast() >= match) { output += groups[match]; continue; } } output += '\\'; } } output += pattern[index]; } }
/** * Ascending Insertion Sort * This is here so I can sort ExtArray<int>'s * * @param list - the array to sort **/ void CronTab::sort( ExtArray<int> &list ) { int ctr, ctr2, value; for ( ctr = 1; ctr <= list.getlast(); ctr++ ) { value = list[ctr]; ctr2 = ctr; while ( ( ctr2 > 0 ) && ( list[ctr2 - 1] > value ) ) { list[ctr2] = list[ctr2 - 1]; ctr2--; } // WHILE list[ctr2] = value; } // FOR return; }
/** * Just checks to see if a value is in an array * * @param list - the array to search for the value * @param elt - the value to search for in the array * @return true if the element exists in the list **/ bool CronTab::contains( ExtArray<int> &list, const int &elt ) { // // Just run through our array and look for the // the element // bool ret = false; int ctr; for ( ctr = 0; ctr <= list.getlast(); ctr++ ) { // // All we can really do is do a simple comparison // if ( elt == list[ctr] ) { ret = true; break; } } // FOR return ( ret ); }
/** * Important helper function that actually does the grunt work of * find the next runtime. We need to be given an array of the different * time fields so that we can match the current time with different * parameters. The function will recursively call itself until * it can find a match at the MINUTES level. If one recursive call * cannot find a match, it will return false and the previous level * will increment its range index by one and try to find a match. On the * the subsequent call useFirst will be set to true meaning that the level * does not need to look for a value in the range that is greater than or * equal to the current time value. If the failing returns to the MONTHS level, * that means we've exhausted all our possiblities from the current time to the * the end of the year. So we'll increase the year by 1 and try the same logic again * using January 1st as the starting point. * The array match will contain the timestamp information of the job's * next run time * * @param curTime - an array of time attributes for where we start our calculations * @param match - an array of time attributes that is the next run time * @param attribute_idx - the index for the current parameter in CronTab::attributes * @param useFirst - whether we should base ourselves off of Jan 1st * @return true if we able to find a new run time **/ bool CronTab::matchFields( int *curTime, int *match, int attribute_idx, bool useFirst ) { // // Whether we need to tell the next level above that they // should use the first element in their range. If we were told // to then certainly the next level will as well // bool nextUseFirst = useFirst; // // First initialize ourself to know that we don't have a match // match[attribute_idx] = -1; // // Special Day of Week Handling // In order to get the day of week stuff to work, we have // to insert all the days of the month for the matching days of the // week in the range. // ExtArray<int> *curRange = NULL; if ( attribute_idx == CRONTAB_DOM_IDX ) { // // We have to take the current month & year // and convert the days of the week range into // days of the month // //Issue here is that range for dom will be 1-31 //for * and if one doesn't specify day_of_month in a job file if (this->ranges[attribute_idx]->length()==CRONTAB_DAY_OF_MONTH_MAX){ if ((this->ranges[CRONTAB_DOW_IDX]->length()==CRONTAB_DAY_OF_WEEK_MAX)|| (this->ranges[CRONTAB_DOW_IDX]->length()==0)){ //if both wildcards, use month range //if DOW range empty use DOM range curRange = new ExtArray<int>( *this->ranges[attribute_idx] ); } else { //only wildcard in month, so use day of week range //this isn't quite right curRange = new ExtArray<int>( CRONTAB_DAY_OF_MONTH_MAX ); } }else{ // get to here means DOM was specified curRange = new ExtArray<int>( *this->ranges[attribute_idx] ); } int firstDay = dayOfWeek( match[CRONTAB_MONTHS_IDX], 1, match[CRONTAB_YEARS_IDX] ); int ctr, cnt; for ( ctr = 0, cnt = this->ranges[CRONTAB_DOW_IDX]->getlast(); ctr <= cnt; ctr++ ) { // // Now figure out all the days for this specific day of the week // int day = (this->ranges[CRONTAB_DOW_IDX]->getElementAt(ctr) - firstDay) + 1; while ( day <= CRONTAB_DAY_OF_MONTH_MAX ) { if (curRange && day > 0 && !this->contains( *curRange, day ) ) { curRange->add( day ); } day += 7; } // WHILE } // FOR // // We have sort the list since we've added new elements // this->sort( *curRange ); // // Otherwise we'll just use the unmodified range // } else { curRange = this->ranges[attribute_idx]; } // // Find the first match for this field // If our value isn't in the list, then we'll take the next one // bool ret = false; int range_idx, cnt; for ( range_idx = 0, cnt = curRange->getlast(); range_idx <= cnt; range_idx++ ) { // // Two ways to make a match: // // 1) The level below told us that we need to just // the first value in our range if we can. // 2) We need to select the first value in our range // that is greater than or equal to the current // time value for this field. This is usually // what we will do on the very first call to // us. If we fail and return back to the previous // level, when they call us again they'll ask // us to just use the first value that we can // int value = curRange->getElementAt( range_idx ); if ( useFirst || value >= curTime[attribute_idx] ) { // // If this value is greater than the current time value, // ask the next level to useFirst // if ( value > curTime[attribute_idx] ) nextUseFirst = true; // // Day of Month Check! // If this day doesn't exist in this month for // the current year in our search, we have to skip it // if ( attribute_idx == CRONTAB_DOM_IDX ) { int maxDOM = daysInMonth( match[CRONTAB_MONTHS_IDX], match[CRONTAB_YEARS_IDX] ); if ( value > maxDOM ) { continue; } } match[attribute_idx] = value; // // If we're the last field for the crontab (i.e. minutes), // then we should have a valid time now! // if ( attribute_idx == CRONTAB_MINUTES_IDX ) { ret = true; break; // // Now that we have a current value for this field, call to the // next field level and see if they can find a match using our // If we roll back then we'll want the next time around for the // next level to just use the first parameter in their range // if they can // } else { ret = this->matchFields( curTime, match, attribute_idx - 1, nextUseFirst ); nextUseFirst = true; if ( ret ) break; } } } // FOR // // If the next level up failed, we need to have // special handling for months so we can roll over the year // While this may seem trivial it's needed so that we // can change the year in the matching for leap years // We will call ourself to make a nice little loop! // if ( !ret && attribute_idx == CRONTAB_MONTHS_IDX ) { match[CRONTAB_YEARS_IDX]++; ret = this->matchFields( curTime, match, attribute_idx, true ); } // // We only need to delete curRange if we had // instantiated a new object for it // if ( attribute_idx == CRONTAB_DOM_IDX && curRange ) delete curRange; return ( ret ); }