Drizzled Public API Documentation

temporal_format.cc
Go to the documentation of this file.
00001 /* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2008 Sun Microsystems, Inc.
00005  *
00006  *  Authors:
00007  *
00008  *  Jay Pipes <jay.pipes@sun.com>
00009  *
00010  *  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with this program; if not, write to the Free Software
00022  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00023  */
00024 
00031 #include <config.h>
00032 
00033 #include <boost/foreach.hpp>
00034 #include <drizzled/temporal_format.h>
00035 #include <drizzled/temporal.h>
00036 
00037 #include <string.h>
00038 #include PCRE_HEADER
00039 
00040 #include <string>
00041 #include <vector>
00042 
00043 using namespace std;
00044 
00045 namespace drizzled {
00046 
00047 TemporalFormat::TemporalFormat(const char *pattern) :
00048   _pattern(pattern)
00049 , _error_offset(0)
00050 , _error(NULL)
00051 , _year_part_index(0)
00052 , _month_part_index(0)
00053 , _day_part_index(0)
00054 , _hour_part_index(0)
00055 , _minute_part_index(0)
00056 , _second_part_index(0)
00057 , _usecond_part_index(0)
00058 , _nsecond_part_index(0)
00059 {
00060   /* Compile our regular expression */
00061   _re= pcre_compile(pattern
00062                     , 0 /* Default options */
00063                     , &_error
00064                     , &_error_offset
00065                     , NULL /* Use default character table */
00066                     );
00067 }
00068 
00069 TemporalFormat::~TemporalFormat()
00070 {
00071   pcre_free(_re);
00072 }
00073 
00074 bool TemporalFormat::matches(const char *data, size_t data_len, Temporal *to)
00075 {
00076   if (! is_valid()) 
00077     return false;
00078 
00079   int32_t match_vector[OUT_VECTOR_SIZE]; 
00081   /* Make sure we've got no junk in the match_vector. */
00082   memset(match_vector, 0, sizeof(match_vector));
00083 
00084   /* Simply check the subject against the compiled regular expression */
00085   int32_t result= pcre_exec(_re
00086                             , NULL /* No extra data */
00087                             , data
00088                             , data_len
00089                             , 0 /* Start at offset 0 of subject...*/
00090                             , 0 /* Default options */
00091                             , match_vector
00092                             , OUT_VECTOR_SIZE
00093                             );
00094   if (result < 0)
00095   {
00096     switch (result)
00097     {
00098       case PCRE_ERROR_NOMATCH:
00099         return false; /* No match, just return false */
00100       default:
00101         return false;
00102     }
00103     return false;
00104   }
00105 
00106   int32_t expected_match_count= (_year_part_index > 1 ? 1 : 0)
00107                               + (_month_part_index > 1 ? 1 : 0)
00108                               + (_day_part_index > 1 ? 1 : 0)
00109                               + (_hour_part_index > 1 ? 1 : 0)
00110                               + (_minute_part_index > 1 ? 1 : 0)
00111                               + (_second_part_index > 1 ? 1 : 0)
00112                               + (_usecond_part_index > 1 ? 1 : 0)
00113                               + (_nsecond_part_index > 1 ? 1 : 0)
00114                               + 1; /* Add one for the entire match... */
00115   if (result != expected_match_count)
00116     return false;
00117 
00118   /* C++ string class easy to use substr() method is very useful here */
00119   string copy_data(data, data_len);
00120   /* 
00121    * OK, we have the expected substring matches, so grab
00122    * the various temporal parts from the subject string
00123    *
00124    * @note 
00125    *
00126    * TemporalFormatMatch is a friend class to Temporal, so
00127    * we can access the temporal instance's protected data.
00128    */
00129   if (_year_part_index > 1)
00130   {
00131     size_t year_start= match_vector[_year_part_index];
00132     size_t year_len= match_vector[_year_part_index + 1] - match_vector[_year_part_index];
00133     to->_years= atoi(copy_data.substr(year_start, year_len).c_str());
00134     if (year_len == 2)
00135       to->_years+= (to->_years >= DRIZZLE_YY_PART_YEAR ? 1900 : 2000);
00136   }
00137   if (_month_part_index > 1)
00138   {
00139     size_t month_start= match_vector[_month_part_index];
00140     size_t month_len= match_vector[_month_part_index + 1] - match_vector[_month_part_index];
00141     to->_months= atoi(copy_data.substr(month_start, month_len).c_str());
00142   }
00143   if (_day_part_index > 1)
00144   {
00145     size_t day_start= match_vector[_day_part_index];
00146     size_t day_len= match_vector[_day_part_index + 1] - match_vector[_day_part_index];
00147     to->_days= atoi(copy_data.substr(day_start, day_len).c_str());
00148   }
00149   if (_hour_part_index > 1)
00150   {
00151     size_t hour_start= match_vector[_hour_part_index];
00152     size_t hour_len= match_vector[_hour_part_index + 1] - match_vector[_hour_part_index];
00153     to->_hours= atoi(copy_data.substr(hour_start, hour_len).c_str());
00154   }
00155   if (_minute_part_index > 1)
00156   {
00157     size_t minute_start= match_vector[_minute_part_index];
00158     size_t minute_len= match_vector[_minute_part_index + 1] - match_vector[_minute_part_index];
00159     to->_minutes= atoi(copy_data.substr(minute_start, minute_len).c_str());
00160   }
00161   if (_second_part_index > 1)
00162   {
00163     size_t second_start= match_vector[_second_part_index];
00164     size_t second_len= match_vector[_second_part_index + 1] - match_vector[_second_part_index];
00165     to->_seconds= atoi(copy_data.substr(second_start, second_len).c_str());
00166   }
00167   if (_usecond_part_index > 1)
00168   {
00169     size_t usecond_start= match_vector[_usecond_part_index];
00170     size_t usecond_len= match_vector[_usecond_part_index + 1] - match_vector[_usecond_part_index];
00171     /* 
00172      * For microseconds, which are millionth of 1 second, 
00173      * we must ensure that we produce a correct result, 
00174      * even if < 6 places were specified.  For instance, if we get .1, 
00175      * we must produce 100000. .11 should produce 110000, etc.
00176      */
00177     uint32_t multiplier= 1;
00178     int32_t x= usecond_len;
00179     while (x < 6)
00180     {
00181       multiplier*= 10;
00182       ++x;
00183     }
00184     to->_useconds= atoi(copy_data.substr(usecond_start, usecond_len).c_str()) * multiplier;
00185   }
00186   if (_nsecond_part_index > 1)
00187   {
00188     size_t nsecond_start= match_vector[_nsecond_part_index];
00189     size_t nsecond_len= match_vector[_nsecond_part_index + 1] - match_vector[_nsecond_part_index];
00190     /* 
00191      * For nanoseconds, which are 1 billionth of a second, 
00192      * we must ensure that we produce a correct result, 
00193      * even if < 9 places were specified.  For instance, if we get .1, 
00194      * we must produce 100000000. .11 should produce 110000000, etc.
00195      */
00196     uint32_t multiplier= 1;
00197     int32_t x= nsecond_len;
00198     while (x < 9)
00199     {
00200       multiplier*= 10;
00201       ++x;
00202     }
00203     to->_nseconds= atoi(copy_data.substr(nsecond_start, nsecond_len).c_str()) * multiplier;
00204   }
00205   return true;
00206 }
00207 
00208 
00209 #define COUNT_KNOWN_FORMATS 19
00210 
00211 struct temporal_format_args
00212 {
00213   const char *pattern;
00214   int32_t year_part_index;
00215   int32_t month_part_index;
00216   int32_t day_part_index;
00217   int32_t hour_part_index;
00218   int32_t minute_part_index;
00219   int32_t second_part_index;
00220   int32_t usecond_part_index;
00221   int32_t nsecond_part_index;
00222 };
00223 
00236 static struct temporal_format_args __format_args[COUNT_KNOWN_FORMATS]= 
00237 {
00238   {"^(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})\\.(\\d{1,6})$", 1, 2, 3, 4, 5, 6, 7, 0} /* YYYYMMDDHHmmSS.uuuuuu */
00239 , {"^(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})$", 1, 2, 3, 4, 5, 6, 0, 0} /* YYYYMMDDHHmmSS */
00240 , {"^(\\d{4})[-/.](\\d{1,2})[-/.](\\d{1,2})[T|\\s+](\\d{2}):(\\d{2}):(\\d{2})\\.(\\d{1,6})$", 1, 2, 3, 4, 5, 6, 7, 0} /* YYYY[/-.]MM[/-.]DD[T]HH:mm:SS.uuuuuu */
00241 , {"^(\\d{4})[-/.](\\d{1,2})[-/.](\\d{1,2})[T|\\s+](\\d{2}):(\\d{2}):(\\d{2})$", 1, 2, 3, 4, 5, 6, 0, 0} /* YYYY[/-.][M]M[/-.][D]D[T]HH:mm:SS */
00242 , {"^(\\d{2})[-/.](\\d{1,2})[-/.](\\d{1,2})[\\s+](\\d{2}):(\\d{2}):(\\d{2})$", 1, 2, 3, 4, 5, 6, 0, 0} /* YY[/-.][M]M[/-.][D]D HH:mm:SS */
00243 , {"^(\\d{2})[-/.](\\d{1,2})[-/.](\\d{1,2})[\\s+](\\d{2}):(\\d{2})$", 1, 2, 3, 4, 5, 0, 0, 0} /* YY[/-.][M]M[/-.][D]D HH:mm */
00244 , {"^(\\d{4})[-/.](\\d{1,2})[-/.](\\d{1,2})[\\s+](\\d{2}):(\\d{2})$", 1, 2, 3, 4, 5, 0, 0, 0} /* YYYY[/-.][M]M[/-.][D]D HH:mm */
00245 , {"^(\\d{4})[-/.](\\d{1,2})[-/.](\\d{1,2})$", 1, 2, 3, 0, 0, 0, 0, 0} /* YYYY-[M]M-[D]D, YYYY.[M]M.[D]D, YYYY/[M]M/[D]D */ 
00246 , {"^(\\d{4})(\\d{2})(\\d{2})$", 1, 2, 3, 0, 0, 0, 0, 0} /* YYYYMMDD */
00247 , {"^(\\d{2})[-/.]*(\\d{2})[-/.]*(\\d{4})$", 3, 1, 2, 0, 0, 0, 0, 0} /* MM[-/.]DD[-/.]YYYY (US common format)*/
00248 , {"^(\\d{2})[-/.]*(\\d{2})[-/.]*(\\d{2})$", 1, 2, 3, 0, 0, 0, 0, 0} /* YY[-/.]MM[-/.]DD */
00249 , {"^(\\d{2})[-/.]*(\\d{1,2})[-/.]*(\\d{1,2})$", 1, 2, 3, 0, 0, 0, 0, 0} /* YY[-/.][M]M[-/.][D]D */
00250 , {"^(\\d{4})[-/.]*(\\d{1,2})[-/.]*(\\d{1,2})$", 1, 2, 3, 0, 0, 0, 0, 0} /* YYYY[-/.][M]M[-/.][D]D */
00251 , {"^(\\d{2}):*(\\d{2}):*(\\d{2})\\.(\\d{1,6})$", 0, 0, 0, 1, 2, 3, 4, 0} /* HHmmSS.uuuuuu, HH:mm:SS.uuuuuu */
00252 , {"^(\\d{1,2}):*(\\d{2}):*(\\d{2})$", 0, 0, 0, 1, 2, 3, 0, 0} /* [H]HmmSS, [H]H:mm:SS */
00253 , {"^(\\d{1,2}):(\\d{1,2}):(\\d{1,2})$", 0, 0, 0, 1, 2, 3, 0, 0} /* [H]H:[m]m:[S]S */
00254 , {"^(\\d{1,2}):*(\\d{2})$", 0, 0, 0, 0, 1, 2, 0, 0} /* [m]mSS, [m]m:SS */
00255 , {"^(\\d{1,2})$", 0, 0, 0, 0, 0, 1, 0, 0} /* SS, S */
00256 , {"^(\\d{1,2})\\.(\\d{1,6})$", 0, 0, 0, 0, 0, 1, 2, 0} /* [S]S.uuuuuu */
00257 };
00258 
00259 vector<TemporalFormat *> known_datetime_formats;
00260 vector<TemporalFormat *> known_date_formats;
00261 vector<TemporalFormat *> known_time_formats;
00262 vector<TemporalFormat *> all_temporal_formats;
00263 
00269 bool init_temporal_formats()
00270 {
00271   /* Compile all the regular expressions for the datetime formats */
00272   TemporalFormat *tmp;
00273   struct temporal_format_args current_format_args;
00274   
00275   for (int32_t x= 0; x < COUNT_KNOWN_FORMATS; ++x)
00276   {
00277     current_format_args= __format_args[x];
00278     tmp= new TemporalFormat(current_format_args.pattern);
00279     tmp->set_year_part_index(current_format_args.year_part_index);
00280     tmp->set_month_part_index(current_format_args.month_part_index);
00281     tmp->set_day_part_index(current_format_args.day_part_index);
00282     tmp->set_hour_part_index(current_format_args.hour_part_index);
00283     tmp->set_minute_part_index(current_format_args.minute_part_index);
00284     tmp->set_second_part_index(current_format_args.second_part_index);
00285     tmp->set_usecond_part_index(current_format_args.usecond_part_index);
00286     tmp->set_nsecond_part_index(current_format_args.nsecond_part_index);
00287     
00288     /* 
00289      * We store the pointer in all_temporal_formats because we 
00290      * delete pointers from that vector and only that vector
00291      */
00292     all_temporal_formats.push_back(tmp); 
00293 
00294     if (current_format_args.year_part_index > 0) /* A date must have a year */
00295     {
00296       known_datetime_formats.push_back(tmp);
00297       if (current_format_args.second_part_index == 0) /* A time must have seconds. */
00298         known_date_formats.push_back(tmp);
00299     }
00300 
00301     if (current_format_args.second_part_index > 0) /* A time must have seconds, but may not have minutes or hours */
00302       known_time_formats.push_back(tmp);
00303   }
00304   return true;
00305 }
00306 
00308 void deinit_temporal_formats()
00309 {
00310   BOOST_FOREACH(TemporalFormat* it, all_temporal_formats)
00311     delete it;
00312   known_date_formats.clear();
00313   known_datetime_formats.clear();
00314   known_time_formats.clear();
00315   all_temporal_formats.clear();
00316 }
00317 
00318 } /* end namespace drizzled */