/////////////////////////////////////////////////////////////////////////////// /// @fn validateDate( string date ) /// @brief Checks the passed date for validity in format and numbering /// @param string date is the date to be checked /// @return true if the date is valid (in "MM/DD" format with possible real days) /// @return false if the date is invalid /////////////////////////////////////////////////////////////////////////////// bool validate::validateDate( string date ) { int month = 0; //Number of the month we were sent to check int day = 0; //Number of the day we were sent to check int monthsInAYear = 12; //Number of months in a year //This is an array of the number of days in each month, that is: //31 days in January, 28 (or 29) in February, 31 in March, etc. int daysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; //Makes sure the date is only 5 characters long, that is, "MM/DD" if ( date.length() != 5 ) { return false; } //Grabs the 2 left characters of the date and converts to an integer month = str_to_int( str_left( date, 2 ) ); //Grabs the 2 right characters of the date and converts to an integer day = str_to_int( str_right( date, 2 ) ); //Checks to make sure the month number is a valid number if ( month > monthsInAYear || month <= 0 ) { return false; //checks to make sure the day number is valid } else if ( day > daysInMonth[month - 1] || day <= 0 ) { return false; } return true; }
////////////////////////////////////////////////////////////////////// /// @fn vector<string> str_split(string str, string delimiters, bool keep_delim) /// @brief -- Returns a vector of strings from str by breaking /// lines at any of delimiters, /// @param string str -- The string to search /// @param string delimiters -- A string of delimiting characters. /// @param bool keep_delim -- Maintains the delimiters in the lines /// if true, or discards if false. ////////////////////////////////////////////////////////////////////// vector<string> str_split(string str, string delimiters, bool keep_delim) { vector<string> lines; while (str != "") { unsigned int delimiter_pos = str.find_first_of(delimiters); // If we DID find a delimiter... if (delimiter_pos != string::npos) { // Shift the position forward by either one or zero, // depending on keep_delim. // This prevents delimiter_pos from becoming zero if // we don't find a delimiter (npos = -1) and keep_delim // is true, thus calling str_left with a length of zero. delimiter_pos += keep_delim; // By keeping the length to delimiter_pos, we can exclude the // delimiters unless keep_delim is true, in which case it // will include the delimiters lines.push_back(str_left(str, delimiter_pos)); // Remove the part of the string we just captured. // Adjust by keep_delim here instead of in str_left // so we avoid the situation described above. str = str_right(str, str.length() - delimiter_pos + keep_delim - 1); } else { // If we didn't find a delimiter... // Push EVERYTHING onto the vector. lines.push_back(str); // And empty the string. str = ""; } }; return lines; }
/////////////////////////////////////////////////////////////////////////////// /// @fn vector<string> getDates( string startDate, string endDate ) /// @brief Returns a vector of strings that contain all the dates between /// startDate and endDate, inclusively /// @param string startDate is the start date for the requested vacation /// @param string endDate is the end date for the requested vacation /// @pre the dates being passed in have already been validated /// using the validateDate function /// @ret vector of strings that contain all dates between startDate and endDate /// inclusive /// @note the parameters startDate and endDate must be in "MM/DD" where MM is /// the month number and DD is the day number /// @note all of the strings (dates) in the vector returned will be in the /// format of "MM/DD" /////////////////////////////////////////////////////////////////////////////// vector<string> validate::getDates( string startDate, string endDate ) { //if ( validateDate( startDate ) == false || validateDate( endDate ) == false ) { //OUTPUT.insert_line(OUTPUT.num_lines(), "The dates sent into getDates fail. This is why we're infinite looping probably k.\n"; //} //Grabs the 2 left characters of the dates and converts to integers int startMonth = str_to_int( str_left( startDate, 2 ) ); int endMonth = str_to_int( str_left( endDate, 2 ) ); //Grabs the 2 right characters of the dates and converts to integers int startDay = str_to_int( str_right( startDate, 2 ) ); int endDay = str_to_int( str_right( endDate, 2 ) ); //This will be our day to begin each iteration's pushing of dates into the //dates vector int startIterationDay = 0; //An array of 12 items (0 to 11) telling us how many days are in each month int daysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; //This will be used so we can deal with request rollovers from month to month //And from december into january int currentIterationMonth = startMonth; //This will be our flag for telling us we're done loading all of the dates //between start and end into the vector. 1=done, 0=not done yet bool Done = false; //This will be our flag for telling us when we're rolling over from one month //to another, default to false so we can start from the middle of a random //month bool fromAnotherMonth = false; //This will be used for pushing onto the dates vector string currentIterationDate = ""; //This will store all of the dates between startDate and endDate, inclusively vector<string> dates; //While we're not done while ( !Done ) { //This should start us on the correct day, be it at the beginning of the //month due to rollover or in the middle of some random month because that //is the day that was requested if ( fromAnotherMonth ) { startIterationDay = 1; } else { startIterationDay = startDay; } //This should run from either the start day or the beginning of a //the month to the number of days in the month or the endDate //Whichever happens to come first for ( int x = startIterationDay; x <= daysInMonth[currentIterationMonth - 1]; x++ ) { //We want to generate dates like: "0M/0D" or "0M/DD" if ( currentIterationMonth < 10 ) { //We want to generate dates like: "0M/0D" if ( x < 10 ) { currentIterationDate = "0" + int_to_str( currentIterationMonth ) + "/0" + int_to_str( x ); //We want to generate dates like "0M/DD" } else { currentIterationDate = "0" + int_to_str( currentIterationMonth ) + "/" + int_to_str( x ); } //We want to generate dates like: "MM/0D" or "MM/DD" } else { //We want to generate dates like: "MM/0D" if ( x < 10 ) { currentIterationDate = int_to_str( currentIterationMonth ) + "/0" + int_to_str( x ); } //We want to generate dates like "MM/DD" else { currentIterationDate = int_to_str( currentIterationMonth ) + "/" + int_to_str( x ); } } //End date generation //end else //Push proper date in form of MM/DD into the dates vector! Yaaay! dates.push_back( currentIterationDate ); //If we've arrived at the endDate, we need to stop pushing more //dates into the vector, we we change our Done flag to 1 to //stop us once we go back to the top of the while loop /* //The stuff in this comment block is the original stuff, the rest below the loop OUTPUT.insert_line(OUTPUT.num_lines(), "currentiterationdate: " << currentIterationDate << "endDate: " << endDate << "\n"; if ( currentIterationDate == endDate ) { Done = true; break; } //However, if we still haven't hit the endDate and we're at the //end of the month, we need to set up to rollover to the next month else if ( x == daysInMonth[currentIterationMonth - 1] ) { fromAnotherMonth = true; //We are coming from another month currentIterationMonth+=1; //We need to start in the next month } //And for added rollover ability, if we get to the end of December //and we need to roll into January, we set the month iteration back //to 1, for the first month if ( currentIterationMonth == 13 ) { currentIterationMonth = 1; break; }*/ } //End for loop //However, if we still haven't hit the endDate and we're at the //end of the month, we need to set up to rollover to the next month //else if ( x == daysInMonth[currentIterationMonth - 1] ) { fromAnotherMonth = true; //We are coming from another month currentIterationMonth+=1; //We need to start in the next month //} if ( currentIterationDate == endDate ) { Done = true; break; } //And for added rollover ability, if we get to the end of December //and we need to roll into January, we set the month iteration back //to 1, for the first month if ( currentIterationMonth == 13 ) { currentIterationMonth = 1; } } //end while loop return dates; //Sends back the vector of dates we workd so hard to get } //end getDates()
int vsf_filename_passes_filter(const struct mystr* p_filename_str, const struct mystr* p_filter_str, unsigned int* iters) { /* A simple routine to match a filename against a pattern. * This routine is used instead of e.g. fnmatch(3), because we should be * reluctant to trust the latter. fnmatch(3) involves _lots_ of string * parsing and handling. There is broad potential for any given fnmatch(3) * implementation to be buggy. * * Currently supported pattern(s): * - any number of wildcards, "*" or "?" * - {,} syntax (not nested) * * Note that pattern matching is only supported within the last path * component. For example, searching for /a/b/? will work, but searching * for /a/?/c will not. */ struct mystr filter_remain_str = INIT_MYSTR; struct mystr name_remain_str = INIT_MYSTR; struct mystr temp_str = INIT_MYSTR; struct mystr brace_list_str = INIT_MYSTR; struct mystr new_filter_str = INIT_MYSTR; int ret = 0; char last_token = 0; int must_match_at_current_pos = 1; str_copy(&filter_remain_str, p_filter_str); str_copy(&name_remain_str, p_filename_str); while (!str_isempty(&filter_remain_str) && *iters < VSFTP_MATCHITERS_MAX) { static struct mystr s_match_needed_str; /* Locate next special token */ struct str_locate_result locate_result = str_locate_chars(&filter_remain_str, "*?{"); (*iters)++; /* Isolate text leading up to token (if any) - needs to be matched */ if (locate_result.found) { unsigned int indexx = locate_result.index; str_left(&filter_remain_str, &s_match_needed_str, indexx); str_mid_to_end(&filter_remain_str, &temp_str, indexx + 1); str_copy(&filter_remain_str, &temp_str); last_token = locate_result.char_found; } else { /* No more tokens. Must match remaining filter string exactly. */ str_copy(&s_match_needed_str, &filter_remain_str); str_empty(&filter_remain_str); last_token = 0; } if (!str_isempty(&s_match_needed_str)) { /* Need to match something.. could be a match which has to start at * current position, or we could allow it to start anywhere */ unsigned int indexx; locate_result = str_locate_str(&name_remain_str, &s_match_needed_str); if (!locate_result.found) { /* Fail */ goto out; } indexx = locate_result.index; if (must_match_at_current_pos && indexx > 0) { goto out; } /* Chop matched string out of remainder */ str_mid_to_end(&name_remain_str, &temp_str, indexx + str_getlen(&s_match_needed_str)); str_copy(&name_remain_str, &temp_str); } if (last_token == '?') { if (str_isempty(&name_remain_str)) { goto out; } str_right(&name_remain_str, &temp_str, str_getlen(&name_remain_str) - 1); str_copy(&name_remain_str, &temp_str); must_match_at_current_pos = 1; } else if (last_token == '{') { struct str_locate_result end_brace = str_locate_char(&filter_remain_str, '}'); must_match_at_current_pos = 1; if (end_brace.found) { str_split_char(&filter_remain_str, &temp_str, '}'); str_copy(&brace_list_str, &filter_remain_str); str_copy(&filter_remain_str, &temp_str); str_split_char(&brace_list_str, &temp_str, ','); while (!str_isempty(&brace_list_str)) { str_copy(&new_filter_str, &brace_list_str); str_append_str(&new_filter_str, &filter_remain_str); if (vsf_filename_passes_filter(&name_remain_str, &new_filter_str, iters)) { ret = 1; goto out; } str_copy(&brace_list_str, &temp_str); str_split_char(&brace_list_str, &temp_str, ','); } goto out; } else if (str_isempty(&name_remain_str) || str_get_char_at(&name_remain_str, 0) != '{') { goto out; } else { str_right(&name_remain_str, &temp_str, str_getlen(&name_remain_str) - 1); str_copy(&name_remain_str, &temp_str); } } else { must_match_at_current_pos = 0; } } /* Any incoming string left means no match unless we ended on the correct * type of wildcard. */ if (str_getlen(&name_remain_str) > 0 && last_token != '*') { goto out; } /* OK, a match */ ret = 1; if (*iters == VSFTP_MATCHITERS_MAX) { ret = 0; } out: str_free(&filter_remain_str); str_free(&name_remain_str); str_free(&temp_str); str_free(&brace_list_str); str_free(&new_filter_str); return ret; }
////////////////////////////////////////////////////////////////////// /// @fn string str_find_range(string str, string start, string end, bool nested, bool inclusive) /// @brief -- Returns the string contained between "start" and "end" /// @param string str -- The string to examine /// @param string start -- The string defining the start of the range /// @param string end -- The string defining the end of the range /// @param bool nested -- Take into account layers of start/end ranges /// For example, nested parentheses "(hello (he said))" /// would return "(hello (he said)" when nested = false /// and "(hello (he said))" when nested = true /// @param bool inclusive -- If true, return the string including the /// start/end values. For example, "(hello)" /// would return "hello" when inclusive = false /// and "(hello)" when inclusive = true /// @param bool ignore_quotes -- If true, this will ignore start/end values /// found between sets of quotes. For example, /// with parentheses again, " ("Hey, :)") " would /// return " ("Hey, :) " with ignore = false and /// " ("Hey, :)") " with ignore = true. /// @param char ignore_following -- If *either* start, *or* end are found /// directly after this character, they will /// be ignored in the search. /// * If ignore_following == 0, no ignoring will /// be performed at all. /// @return -- Returns the string if found, or a blank string if /// the string wasn't found. ////////////////////////////////////////////////////////////////////// string str_find_range(string str, string start, string end, bool nested, bool inclusive, bool ignore_quotes, char ignore_following) { // For the purposes of this routine, we will assume // inclusive = true and take that into account // at the end when we return the string. unsigned int start_pos = 0; unsigned int end_pos = 1; vector<string> removed_quotes; vector<unsigned int> removed_pos; bool quotes_removed = false; // Make something almost impossible for someone to be searching // for, therefore unlikely to interfere in the search process. // ----- THIS NEEDS TO BE REPLACED WITH SOMETHING 100% RELIABLE ----- char ignore_ch[10] = {21, 22, 24, 26, 17, 18, 19, 20, 21, 22}; string ignore(ignore_ch); if (ignore_quotes) { // While there are still quote-ranges within the string while (!quotes_removed) { // Find them, not-nested, but inclusive. Obviously, we don't // need to infinitely loop this, so we set ignore_quotes // to false in this instance. string temp_quote = str_find_range(str, "\"", "\"", false, true, false); // If it returns "", we didn't find any more quotes, so // we're done. if (temp_quote == "") { quotes_removed = true; } else { unsigned int pos = str.find(temp_quote); // Make sure we didn't break anything... if (pos != string::npos) { // Otherwise, add the quote to the removed_quotes vector. removed_quotes.push_back(temp_quote); // And store WHERE we put the removal. removed_pos.push_back(pos); str.replace(pos, temp_quote.length(), ignore); } else { throw Exception(15, "We somehow broke our own function... Apparently, searching doesn't work. (strmanip.cpp, str_find_range())"); } /* if (pos != string::npos) */ } /* if (temp_quote == "") */ }; /* while (!quotes_removed) */ } /* if (ignore_quotes) */ // Store the original (quote-removed, but not stripped) // string for use later. :) string original = str; bool ignore_char_found = true; while (ignore_char_found) { // Find the first instance of start start_pos = str.find(start, start_pos); if (end_pos <= start_pos) { end_pos = start_pos + 1; } // It has to be after the start pos, you know. end_pos = str.find(end, end_pos); // See that there IS a previous char and test to see if it // matches the ignore char. if (start_pos == string::npos || end_pos == string::npos) { ignore_char_found = false; } else if (ignore_following != 0 && // If ignore_following is zero, don't ignore at all. start_pos > 0 && str[start_pos - 1] == ignore_following) { start_pos++; } else if (ignore_following != 0 && end_pos > 0 && str[end_pos - 1] == ignore_following) { end_pos++; } else if (start_pos > end_pos) { unsigned int temp = start_pos; start_pos = end_pos; end_pos = temp; } else { ignore_char_found = false; } }; // Make sure we actually HAVE an instance of each start and end. if (start_pos == string::npos || end_pos == string::npos || start_pos == end_pos) { return ""; } if (nested) { // Nested is more complicated. // We have to keep track of how many starts // and ends we come across. // We initialize start_count to one, because we // have to count them as we come across them in the string. // If we find another start before an end, we have to then // find TWO ends in order to really be done. unsigned int start_count = 1; unsigned int end_count = 0; // While we're checking, we check for both starts and ends // and if we run out of starts or ends, unsigned int check_pos = start_pos + 1; // While we have more starts than ends... // and we haven't run past the end of the string. while (start_count > end_count && check_pos < str.length()) { unsigned int temp_start = str.find(start, check_pos);; unsigned int temp_end = str.find(end, check_pos);; // If we're all out of both starts AND ends... if (temp_start == string::npos && temp_end == string::npos) { // Since we're all the way here, and we didn't break out // for start_count == end_count... check_pos = str.length(); // AND we store the break condition, because it's broken. end_pos = string::npos; } else if (temp_start < temp_end) { // Only increment if the character previous isn't our // ignore condition. if (temp_start > 0 && str[temp_start - 1] != ignore_following) { // If the start came first... increment it. start_count++; } // And set the next check to just after // the place we just found. check_pos = temp_start + 1; /* else if (temp_start < temp_end) */ } else { // Same as above. if (temp_end > 0 && str[temp_end - 1] != ignore_following) { // Otherwise, if the end came first, increment its count. end_count++; } // Set the next check pos to where IT was. check_pos = temp_end + 1; // And, since we're interested in the ending position... // store that. end_pos = temp_end; } /* temp_start vs temp_end */ }; /* while (start_count > end_count && check_pos < str.length()) */ } /* if (nested) */ // Make sure we actually HAVE an instance of each start and end. if (start_pos == string::npos || end_pos == string::npos) { return ""; } else { // If we HAVE something to work with, strip the // outsides of the string. str = str_mid(str, start_pos, end_pos - start_pos + end.length()); } // If we chose to ignore quotes, AND we // have some to replace... if (ignore_quotes && !removed_quotes.empty()) { bool quotes_replaced = false; while (!quotes_replaced) { // Find the first instance of an "ignore" in the stripped string. unsigned int stripped_pos = str.find(ignore); // If there was one... if (stripped_pos != string::npos) { // Find its match in the original, unstripped string // by finding everything from the beginning of the stripped string // to the end of the first ignore. We include the ignore string // to guarantee what we're searching for is actually something // that we ignored. string left = str_left(str, stripped_pos + ignore.length()); unsigned int original_pos = original.find(left); if (original_pos == string::npos) { throw Exception(10, "We somehow broke our own function... Apparently, searching identical strings doesn't work. (strmanip.cpp, str_find_range())"); } // In order to get the position of the IGNORE character, we have to // shift forward by the length of the string we compared with, // minus the length of the ignore string. original_pos = original_pos + left.length() - ignore.length(); // Find the index in the positions vector that matches // the position we just found. // NOTE: We can't just take the first ignore string, because // it's possible that in the stripping, we got rid of some of // the ignored data, and we want to make sure we put everything // back in the right place. unsigned int quote_index = search(removed_pos, original_pos); if (quote_index == UINT_MAX) { throw Exception(stripped_pos, "We somehow broke our own function... Apparently, searching identical strings doesn't work. (strmanip.cpp, str_find_range())"); } // Replace the ignore string with the removed string. str.replace(stripped_pos, ignore.length(), removed_quotes[quote_index]); } else { quotes_replaced = true; } /* if (stripped_pos != string::npos) */ }; /* while (!quotes_replaced) */ } /* if (ignore_quotes && !removed_quotes.empty()) */ if (!inclusive) { // If we're not including the start/end, then we // use the mid function and get everything between the // start/end caps. str = str_mid(str, start.length(), str.length() - start.length() - end.length()); } // If we make it this far... return str; }
////////////////////////////////////////////////////////////////////// /// @fn string str_strip(string str, string to_strip, bool leading, bool inner, bool trailing) /// @brief -- Returns the string with all instances of to_strip /// removed, according to the parameters. /// @param string str -- The string to examine /// @param string to_strip -- The string to find and remove /// @param bool leading -- Whether to remove instances of to_strip found /// at the beginning of the string, before other /// characters. /// @param bool inner -- Whether to remove instances of to_strip found /// between other characters. /// @param bool trailing -- Whether to remove instances of to_strip found /// at the end of the string. ////////////////////////////////////////////////////////////////////// string str_strip(string str, string to_strip, bool leading, bool inner, bool trailing) { // For sanity's sake... if (str.find(to_strip) == string::npos || (!leading && !inner && !trailing)) { // Don't bother if it's not there. :) return str; } // Now... Check leading/trailing if (leading) { // While the first characters in the string match // what we're stripping... while (str_left(str, to_strip.length()) == to_strip) { // Throw them away. str = str_right(str, str.length() - to_strip.length()); }; } /* if (leading) */ if (trailing) { // While the last characters in the string match // what we're stripping... while (str_right(str, to_strip.length()) == to_strip) { // Throw them away. str = str_left(str, str.length() - to_strip.length()); }; } /* if (trailing) */ // Work from the inside. if (inner) { // Get the edges. unsigned int left = 0; unsigned int right = str.length(); // Loop through the string and find the first bit that // doesn't match what we're stripping. while (str_mid(str, left, to_strip.length()) == to_strip) { left += to_strip.length(); }; // Loop through and find the last that doesn't match. while (str_mid(str, right - to_strip.length(), to_strip.length()) == to_strip) { right -= to_strip.length(); }; bool done = false; while (!done) { unsigned int pos = str.find(to_strip, left); if (pos == string::npos || pos > right) { done = true; } else { str.erase(pos, to_strip.length()); // Since we just removed a chunk of the string, // we have to adjust the right bound. right -= to_strip.length(); } /* if (pos == string::npos) */ }; /* while (!done) */ } /* if (inner) */ return str; }