Example #1
0
///////////////////////////////////////////////////////////////////////////////
/// @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;

}
Example #3
0
///////////////////////////////////////////////////////////////////////////////
/// @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()
Example #4
0
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;

}