Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include  <ctype.h>
     18 #include "dmStringUtil.h"
     19 #include "dmNewDataTypesValidation.h"
     20 #include "xpl_Logger.h"
     21 
     22 //----------------------------------------------------------------------------------------------
     23 
     24 typedef int                   position_t;
     25 typedef int                   offset_t;
     26 
     27 //----------------------------------------------------------------------------------------------
     28 
     29 class matcher_t
     30 {
     31 public:
     32                               matcher_t( const DMString& str );
     33                               matcher_t( const matcher_t& matcher );
     34   BOOLEAN                     get_char( char& curr_char, offset_t offset ) const;
     35   BOOLEAN                     advance( offset_t offset );
     36   offset_t                    get_offset() const;
     37   position_t                  get_size() const;
     38 
     39 private:
     40   position_t                  _position;
     41   position_t                  _initial_position;
     42   const DMString&             _str;
     43 };
     44 
     45 typedef offset_t (*check_format_fn_t)( matcher_t matcher );
     46 
     47 //----------------------------------------------------------------------------------------------
     48 
     49 matcher_t::matcher_t( const DMString& str )
     50   : _position( 0 ),
     51     _initial_position( 0 ),
     52     _str( str )
     53 {
     54 }
     55 
     56 matcher_t::matcher_t( const matcher_t& matcher )
     57   : _position( matcher._position ),
     58     _initial_position( matcher._position ),
     59     _str( matcher._str )
     60 {
     61 }
     62 
     63 BOOLEAN
     64 matcher_t::advance( offset_t offset )
     65 {
     66   BOOLEAN result = FALSE;
     67 
     68   if( ( offset > 0 ) &&
     69       ( _position + offset <= get_size() ) )
     70   {
     71     _position += offset;
     72     result = TRUE;
     73   }
     74 
     75   return result;
     76 }
     77 
     78 BOOLEAN
     79 matcher_t::get_char( char& curr_char, offset_t offset ) const
     80 {
     81   BOOLEAN result = FALSE;
     82 
     83   if( _position + offset < get_size() )
     84   {
     85     curr_char = _str[ _position + offset ];
     86     result = TRUE;
     87   }
     88 
     89   return result;
     90 }
     91 
     92 offset_t
     93 matcher_t::get_offset() const
     94 {
     95   return _position - _initial_position;
     96 }
     97 
     98 position_t
     99 matcher_t::get_size() const
    100 {
    101   return static_cast<position_t>( _str.length() );
    102 }
    103 
    104 //----------------------------------------------------------------------------------------------
    105 
    106 static
    107 offset_t
    108 is_literal( matcher_t matcher, char literal )
    109 {
    110   char curr_char = '\0';
    111   return ( matcher.get_char( curr_char, 0 ) && ( curr_char == literal ) ) ? 1 : 0;
    112 }
    113 
    114 static
    115 offset_t
    116 is_sign( matcher_t matcher )
    117 {
    118   offset_t offset = is_literal( matcher, '-' );
    119 
    120   if( !offset )
    121   {
    122     offset = is_literal( matcher, '+' );
    123   }
    124 
    125   return offset;
    126 }
    127 
    128 static
    129 offset_t
    130 is_digit( matcher_t matcher )
    131 {
    132   char curr_char = '\0';
    133   return ( matcher.get_char( curr_char, 0 ) && isdigit( curr_char ) ) ? 1 : 0;
    134 }
    135 
    136 static
    137 offset_t
    138 is_number( matcher_t matcher, int min_length, int max_length )
    139 {
    140   for( int i = 0; i < min_length; ++i )
    141   {
    142     if( !matcher.advance( is_digit( matcher ) ) )
    143     {
    144       return 0;
    145     }
    146   }
    147 
    148   for( int i = min_length; i < max_length; ++i )
    149   {
    150     if( !matcher.advance( is_digit( matcher ) ) )
    151     {
    152       return matcher.get_offset();
    153     }
    154   }
    155 
    156   return matcher.get_offset();
    157 }
    158 
    159 static
    160 offset_t
    161 is_integer_part( matcher_t matcher )
    162 {
    163   return is_number( matcher, 1, 10 );
    164 }
    165 
    166 static
    167 offset_t
    168 is_fractional_part( matcher_t matcher )
    169 {
    170   if( !matcher.advance( is_literal( matcher, '.' ) ) ) return 0;
    171   if( !matcher.advance( is_number( matcher, 1, 10 ) ) ) return 0;
    172 
    173   return matcher.get_offset();
    174 }
    175 
    176 static
    177 offset_t
    178 is_Ee( matcher_t matcher )
    179 {
    180   offset_t offset = is_literal( matcher, 'E' );
    181 
    182   if( !offset )
    183   {
    184     offset = is_literal( matcher, 'e' );
    185   }
    186 
    187   return offset;
    188 }
    189 
    190 static
    191 offset_t
    192 is_exponent( matcher_t matcher )
    193 {
    194   if( !matcher.advance( is_Ee( matcher ) ) ) return 0;
    195 
    196   matcher.advance( is_sign( matcher ) );
    197   if( !matcher.advance( is_number( matcher, 1, 10 ) ) ) return 0;
    198 
    199   return matcher.get_offset();
    200 }
    201 
    202 static
    203 offset_t
    204 is_mantissa( matcher_t matcher )
    205 {
    206   matcher.advance( is_sign( matcher ) );
    207 
    208   if( !matcher.advance( is_integer_part( matcher ) ) ) return 0;
    209 
    210   matcher.advance( is_fractional_part( matcher ) );
    211 
    212   return matcher.get_offset();
    213 }
    214 
    215 BOOLEAN
    216 is_float( const DMString& str )
    217 {
    218   XPL_LOG_DM_TMN_Debug(("dmNewDataTypesValidation::is_float str=%s\n", str.c_str()));
    219   matcher_t     matcher( str );
    220 
    221   if( matcher.get_size() == 0 ) return FALSE;
    222   if( !matcher.advance( is_mantissa( matcher ) ) ) return FALSE;
    223   matcher.advance( is_exponent( matcher ) );
    224 
    225   return matcher.get_offset() == str.length();
    226 }
    227 
    228 static
    229 offset_t
    230 is_year( matcher_t matcher )
    231 {
    232   return is_number( matcher, 4, 4 );
    233 }
    234 
    235 static
    236 offset_t
    237 is_number_in_range( matcher_t matcher, int num_digits, int min_value, int max_value )
    238 {
    239   offset_t offset = is_number( matcher, num_digits, num_digits );
    240 
    241   if( offset == 0 ) return 0;
    242 
    243   int       value = 0;
    244 
    245   for( int i = 0; i < num_digits; ++i )
    246   {
    247     char curr_char = '\0';
    248 
    249     if( !matcher.get_char( curr_char, i ) ) return 0;
    250 
    251     value = 10 * value + ( curr_char - '0' );
    252   }
    253 
    254   return ( min_value <= value ) && ( value <= max_value ) ? offset : 0;
    255 }
    256 
    257 static
    258 offset_t
    259 is_month( matcher_t matcher )
    260 {
    261   return is_number_in_range( matcher, 2, 1, 12 );
    262 }
    263 
    264 static
    265 offset_t
    266 is_day_of_month( matcher_t matcher )
    267 {
    268   return is_number_in_range( matcher, 2, 1, 31 );
    269 }
    270 
    271 static
    272 offset_t
    273 is_day_of_year( matcher_t matcher )
    274 {
    275   return is_number_in_range( matcher, 3, 1, 366 );
    276 }
    277 
    278 static
    279 offset_t
    280 is_day_of_week( matcher_t matcher )
    281 {
    282   return is_number_in_range( matcher, 1, 1, 7 );
    283 }
    284 
    285 static
    286 offset_t
    287 is_week_number( matcher_t matcher )
    288 {
    289   return is_number_in_range( matcher, 2, 1, 52 );
    290 }
    291 
    292 static
    293 offset_t
    294 is_YYYY( matcher_t matcher )
    295 {
    296   if( !matcher.advance( is_year( matcher ) ) )          return 0;
    297 
    298   return matcher.get_offset();
    299 }
    300 
    301 static
    302 offset_t
    303 is_YYYY_MM_DD( matcher_t matcher )
    304 {
    305   if( !matcher.advance( is_year( matcher ) ) )          return 0;
    306   if( !matcher.advance( is_literal( matcher, '-' ) ) )  return 0;
    307   if( !matcher.advance( is_month( matcher ) ) )         return 0;
    308   if( !matcher.advance( is_literal( matcher, '-' ) ) )  return 0;
    309   if( !matcher.advance( is_day_of_month( matcher ) ) )  return 0;
    310 
    311   return matcher.get_offset();
    312 }
    313 
    314 static
    315 offset_t
    316 is_YYYY_MM( matcher_t matcher )
    317 {
    318   if( !matcher.advance( is_year( matcher ) ) )          return 0;
    319   if( !matcher.advance( is_literal( matcher, '-' ) ) )  return 0;
    320   if( !matcher.advance( is_month( matcher ) ) )         return 0;
    321 
    322   return matcher.get_offset();
    323 }
    324 
    325 static
    326 offset_t
    327 is_YYYY_DDD( matcher_t matcher )
    328 {
    329   if( !matcher.advance( is_year( matcher ) ) )          return 0;
    330   if( !matcher.advance( is_literal( matcher, '-' ) ) )  return 0;
    331   if( !matcher.advance( is_day_of_year( matcher ) ) )   return 0;
    332 
    333   return matcher.get_offset();
    334 }
    335 
    336 static
    337 offset_t
    338 is_YYYY_Wxx( matcher_t matcher )
    339 {
    340   if( !matcher.advance( is_year( matcher ) ) )          return 0;
    341   if( !matcher.advance( is_literal( matcher, '-' ) ) )  return 0;
    342   if( !matcher.advance( is_literal( matcher, 'W' ) ) )  return 0;
    343   if( !matcher.advance( is_week_number( matcher ) ) )   return 0;
    344 
    345   return matcher.get_offset();
    346 }
    347 
    348 static
    349 offset_t
    350 is_YYYY_Wxx_d( matcher_t matcher )
    351 {
    352   if( !matcher.advance( is_year( matcher ) ) )          return 0;
    353   if( !matcher.advance( is_literal( matcher, '-' ) ) )  return 0;
    354   if( !matcher.advance( is_literal( matcher, 'W' ) ) )  return 0;
    355   if( !matcher.advance( is_week_number( matcher ) ) )   return 0;
    356   if( !matcher.advance( is_literal( matcher, '-' ) ) )  return 0;
    357   if( !matcher.advance( is_day_of_week( matcher ) ) )   return 0;
    358 
    359   return matcher.get_offset();
    360 }
    361 
    362 static
    363 offset_t
    364 is_YYYYMMDD( matcher_t matcher )
    365 {
    366   if( !matcher.advance( is_year( matcher ) ) )          return 0;
    367   if( !matcher.advance( is_month( matcher ) ) )         return 0;
    368   if( !matcher.advance( is_day_of_month( matcher ) ) )  return 0;
    369 
    370   return matcher.get_offset();
    371 }
    372 
    373 static
    374 offset_t
    375 is_YYYYMM( matcher_t matcher )
    376 {
    377   if( !matcher.advance( is_year( matcher ) ) )          return 0;
    378   if( !matcher.advance( is_month( matcher ) ) )         return 0;
    379 
    380   return matcher.get_offset();
    381 }
    382 
    383 static
    384 offset_t
    385 is_YYYYDDD( matcher_t matcher )
    386 {
    387   if( !matcher.advance( is_year( matcher ) ) )          return 0;
    388   if( !matcher.advance( is_day_of_year( matcher ) ) )   return 0;
    389 
    390   return matcher.get_offset();
    391 }
    392 
    393 static
    394 offset_t
    395 is_YYYYWxx( matcher_t matcher )
    396 {
    397   if( !matcher.advance( is_year( matcher ) ) )          return 0;
    398   if( !matcher.advance( is_literal( matcher, 'W' ) ) )  return 0;
    399   if( !matcher.advance( is_week_number( matcher ) ) )   return 0;
    400 
    401   return matcher.get_offset();
    402 }
    403 
    404 static
    405 offset_t
    406 is_YYYYWxxd( matcher_t matcher )
    407 {
    408   if( !matcher.advance( is_year( matcher ) ) )          return 0;
    409   if( !matcher.advance( is_literal( matcher, 'W' ) ) )  return 0;
    410   if( !matcher.advance( is_week_number( matcher ) ) )   return 0;
    411   if( !matcher.advance( is_day_of_week( matcher ) ) )   return 0;
    412 
    413   return matcher.get_offset();
    414 }
    415 
    416 static
    417 BOOLEAN
    418 is_format( matcher_t matcher, check_format_fn_t fn )
    419 {
    420   return (*fn)( matcher ) == matcher.get_size();
    421 }
    422 
    423 BOOLEAN
    424 is_date( const DMString& str )
    425 {
    426   matcher_t     matcher( str );
    427   BOOLEAN          result = TRUE;
    428 
    429   if( matcher.get_size() == 0 ) return FALSE;
    430 
    431   for( ; ; )
    432   {
    433     if( is_format( matcher, is_YYYY ) )       break;
    434     if( is_format( matcher, is_YYYY_MM_DD ) ) break;
    435     if( is_format( matcher, is_YYYY_MM ) )    break;
    436     if( is_format( matcher, is_YYYY_DDD ) )   break;
    437     if( is_format( matcher, is_YYYY_Wxx ) )   break;
    438     if( is_format( matcher, is_YYYY_Wxx_d ) ) break;
    439     if( is_format( matcher, is_YYYYMMDD ) )   break;
    440     if( is_format( matcher, is_YYYYMM ) )     break;
    441     if( is_format( matcher, is_YYYYDDD ) )    break;
    442     if( is_format( matcher, is_YYYYWxx ) )    break;
    443     if( is_format( matcher, is_YYYYWxxd ) )   break;
    444 
    445     result = FALSE;
    446     break;
    447   }
    448 
    449   return result;
    450 }
    451 
    452 static
    453 offset_t
    454 is_hours( matcher_t matcher )
    455 {
    456   return is_number_in_range( matcher, 2, 0, 23 );
    457 }
    458 
    459 static
    460 offset_t
    461 is_minutes( matcher_t matcher )
    462 {
    463   return is_number_in_range( matcher, 2, 0, 59 );
    464 }
    465 
    466 static
    467 offset_t
    468 is_seconds( matcher_t matcher )
    469 {
    470   return is_number_in_range( matcher, 2, 0, 59 );
    471 }
    472 
    473 static
    474 offset_t
    475 is_hh_mm_ss( matcher_t matcher )
    476 {
    477   if( !matcher.advance( is_hours( matcher ) ) )         return 0;
    478   if( !matcher.advance( is_literal( matcher, ':' ) ) )  return 0;
    479   if( !matcher.advance( is_minutes( matcher ) ) )       return 0;
    480   if( !matcher.advance( is_literal( matcher, ':' ) ) )  return 0;
    481   if( !matcher.advance( is_seconds( matcher ) ) )       return 0;
    482 
    483   return matcher.get_offset();
    484 }
    485 
    486 static
    487 offset_t
    488 is_hh_mm( matcher_t matcher )
    489 {
    490   if( !matcher.advance( is_hours( matcher ) ) )         return 0;
    491   if( !matcher.advance( is_literal( matcher, ':' ) ) )  return 0;
    492   if( !matcher.advance( is_minutes( matcher ) ) )       return 0;
    493 
    494   return matcher.get_offset();
    495 }
    496 
    497 static
    498 offset_t
    499 is_hhmmss( matcher_t matcher )
    500 {
    501   if( !matcher.advance( is_hours( matcher ) ) )         return 0;
    502   if( !matcher.advance( is_minutes( matcher ) ) )       return 0;
    503   if( !matcher.advance( is_seconds( matcher ) ) )       return 0;
    504 
    505   return matcher.get_offset();
    506 }
    507 
    508 static
    509 offset_t
    510 is_hhmm( matcher_t matcher )
    511 {
    512   if( !matcher.advance( is_hours( matcher ) ) )         return 0;
    513   if( !matcher.advance( is_minutes( matcher ) ) )       return 0;
    514 
    515   return matcher.get_offset();
    516 }
    517 
    518 static
    519 offset_t
    520 is_hh( matcher_t matcher )
    521 {
    522   if( !matcher.advance( is_hours( matcher ) ) )         return 0;
    523 
    524   return matcher.get_offset();
    525 }
    526 
    527 static
    528 offset_t
    529 is_hh_mm_ssZ( matcher_t matcher )
    530 {
    531   if( !matcher.advance( is_hours( matcher ) ) )         return 0;
    532   if( !matcher.advance( is_literal( matcher, ':' ) ) )  return 0;
    533   if( !matcher.advance( is_minutes( matcher ) ) )       return 0;
    534   if( !matcher.advance( is_literal( matcher, ':' ) ) )  return 0;
    535   if( !matcher.advance( is_seconds( matcher ) ) )       return 0;
    536   if( !matcher.advance( is_literal( matcher, 'Z' ) ) )  return 0;
    537 
    538   return matcher.get_offset();
    539 }
    540 
    541 static
    542 offset_t
    543 is_hh_mm_ss_utc_hh_mm( matcher_t matcher )
    544 {
    545   if( !matcher.advance( is_hours( matcher ) ) )         return 0;
    546   if( !matcher.advance( is_literal( matcher, ':' ) ) )  return 0;
    547   if( !matcher.advance( is_minutes( matcher ) ) )       return 0;
    548   if( !matcher.advance( is_literal( matcher, ':' ) ) )  return 0;
    549   if( !matcher.advance( is_seconds( matcher ) ) )       return 0;
    550   if( !matcher.advance( is_sign( matcher ) ) )          return 0;
    551   if( !matcher.advance( is_hours( matcher ) ) )         return 0;
    552   if( !matcher.advance( is_literal( matcher, ':' ) ) )  return 0;
    553   if( !matcher.advance( is_minutes( matcher ) ) )       return 0;
    554 
    555   return matcher.get_offset();
    556 }
    557 
    558 BOOLEAN
    559 is_time( const DMString& str )
    560 {
    561   matcher_t     matcher( str );
    562   BOOLEAN          result = TRUE;
    563 
    564   if( matcher.get_size() == 0 ) return FALSE;
    565 
    566   for( ; ; )
    567   {
    568     if( is_format( matcher, is_hh_mm_ss ) )           break;
    569     if( is_format( matcher, is_hh_mm ) )              break;
    570     if( is_format( matcher, is_hhmmss ) )             break;
    571     if( is_format( matcher, is_hhmm ) )               break;
    572     if( is_format( matcher, is_hh ) )                 break;
    573     if( is_format( matcher, is_hh_mm_ssZ ) )          break;
    574     if( is_format( matcher, is_hh_mm_ss_utc_hh_mm ) ) break;
    575 
    576     result = FALSE;
    577     break;
    578   }
    579 
    580   return result;
    581 }
    582 
    583 /* DM: Unit tests for is_time, is_data, is_float
    584 
    585 
    586 struct test_t
    587 {
    588   test_t( const char* pattern, BOOLEAN expeted_result )
    589     : _pattern( pattern ),
    590       _expected_result( expeted_result )
    591   {
    592   }
    593 
    594   const char*   _pattern;
    595   BOOLEAN       _expected_result;
    596 };
    597 
    598 void test_float()
    599 {
    600   test_t tests[] =
    601   {
    602     test_t( "1",              TRUE ),
    603     test_t( "123",            TRUE ),
    604     test_t( "+523",           TRUE ),
    605     test_t( "-66544",         TRUE ),
    606     test_t( "6.0",            TRUE ),
    607     test_t( "-64.55",         TRUE ),
    608     test_t( "+66.544",        TRUE ),
    609     test_t( "1e12",           TRUE ),
    610     test_t( "123e12",         TRUE ),
    611     test_t( "+523e-12",       TRUE ),
    612     test_t( "-66544e1",       TRUE ),
    613     test_t( "6.0E+01",        TRUE ),
    614     test_t( "-64.55E12",      TRUE ),
    615     test_t( "+66.544e-44",    TRUE ),
    616 
    617     test_t( "",               FALSE ),
    618     test_t( "+66.544e-",      FALSE ),
    619     test_t( "-66.544e",       FALSE ),
    620     test_t( "+66.",           FALSE ),
    621     test_t( "+x6.5",          FALSE ),
    622     test_t( "++6.0E+01",      FALSE ),
    623     test_t( "--6.0E+01",      FALSE ),
    624     test_t( "--6.0E+-01",     FALSE ),
    625     test_t( "633.45.40E+01",  FALSE ),
    626     test_t( "633.40E+2.1",    FALSE ),
    627   };
    628 
    629   for( int i = 0; i < sizeof( tests ) / sizeof( tests[ 0 ] ); ++i )
    630   {
    631     std::cout <<  ( ( is_float( tests[ i ]._pattern ) == tests[ i ]._expected_result )
    632                        ? "OK    "
    633                        : "Failed" );
    634     std::cout << " - float( " << tests[ i ]._pattern << " )";
    635     std::cout << std::endl;
    636   }
    637 }
    638 
    639 void test_date()
    640 {
    641   test_t tests[] =
    642   {
    643     test_t( "2005-11-23", TRUE ),
    644     test_t( "1243-04",    TRUE ),
    645     test_t( "1990-123",   TRUE ),
    646     test_t( "1322-W12-3", TRUE ),
    647     test_t( "1600-W05",   TRUE ),
    648     test_t( "19121103",   TRUE ),
    649     test_t( "200001",     TRUE ),
    650     test_t( "2001222",    TRUE ),
    651     test_t( "000001",     TRUE ),
    652     test_t( "0000001",    TRUE ),
    653     test_t( "1555",       TRUE ),
    654     test_t( "2210W116",   TRUE ),
    655     test_t( "1203W12",    TRUE ),
    656 
    657     test_t( "20Z5-11-23", FALSE ),
    658     test_t( "205-11-23",  FALSE ),
    659     test_t( "2025-11-2",  FALSE ),
    660     test_t( "2025-11-",   FALSE ),
    661     test_t( "2025-1-12",  FALSE ),
    662     test_t( "2025--12",   FALSE ),
    663     test_t( "2025-00-12", FALSE ),
    664     test_t( "2025-44-12", FALSE ),
    665     test_t( "2025-11-00", FALSE ),
    666     test_t( "2025-11-65", FALSE ),
    667     test_t( "1990-0",     FALSE ),
    668     test_t( "1990-000",   FALSE ),
    669     test_t( "1990-367",   FALSE ),
    670     test_t( "990-367",    FALSE ),
    671     test_t( "123-04",     FALSE ),
    672     test_t( "1322-W12-0", FALSE ),
    673     test_t( "1322-W12-8", FALSE ),
    674     test_t( "1322-W00-3", FALSE ),
    675     test_t( "1322-W0-3",  FALSE ),
    676     test_t( "1322-W-3",   FALSE ),
    677     test_t( "1322-W66-3", FALSE ),
    678     test_t( "155",        FALSE ),
    679     test_t( "1",          FALSE ),
    680     test_t( "",           FALSE ),
    681     test_t( "15522",      FALSE ),
    682     test_t( "1552q",      FALSE ),
    683     test_t( "1552-",      FALSE ),
    684     test_t( "1552-W",     FALSE ),
    685     test_t( "1552W",      FALSE ),
    686     test_t( "2210W1163",  FALSE ),
    687     test_t( "1203w12",    FALSE ),
    688   };
    689 
    690   for( int i = 0; i < sizeof( tests ) / sizeof( tests[ 0 ] ); ++i )
    691   {
    692     std::cout <<  ( ( is_date( tests[ i ]._pattern ) == tests[ i ]._expected_result )
    693                        ? "OK    "
    694                        : "Failed" );
    695     std::cout << " - date( " << tests[ i ]._pattern << " )";
    696     std::cout << std::endl;
    697   }
    698 }
    699 
    700 void test_time()
    701 {
    702   test_t tests[] =
    703   {
    704     test_t( "12:11:23",       TRUE ),
    705     test_t( "12:11",          TRUE ),
    706     test_t( "121123",         TRUE ),
    707     test_t( "1211",           TRUE ),
    708     test_t( "12",             TRUE ),
    709     test_t( "12:11:23Z",      TRUE ),
    710     test_t( "12:11:23+08:00", TRUE ),
    711     test_t( "12:11:23-11:30", TRUE ),
    712 
    713     test_t( "",               FALSE ),
    714     test_t( "1",              FALSE ),
    715     test_t( "Z",              FALSE ),
    716     test_t( "+1",             FALSE ),
    717     test_t( "25:11:23",       FALSE ),
    718     test_t( "15:81:23",       FALSE ),
    719     test_t( "15:11:73",       FALSE ),
    720     test_t( "::",             FALSE ),
    721     test_t( "1:2:3",          FALSE ),
    722     test_t( "12112",          FALSE ),
    723     test_t( "121",            FALSE ),
    724     test_t( "12:11:23+33:00", FALSE ),
    725     test_t( "12:11:23-08:99", FALSE ),
    726     test_t( "12:11:23 08:12", FALSE ),
    727     test_t( "12:11:23 08:12", FALSE ),
    728     test_t( "12:11:23-08:",   FALSE ),
    729     test_t( "12:11:23-08:1",  FALSE ),
    730     test_t( "12:11:23:08:11", FALSE ),
    731   };
    732 
    733   for( int i = 0; i < sizeof( tests ) / sizeof( tests[ 0 ] ); ++i )
    734   {
    735     std::cout <<  ( ( is_time( tests[ i ]._pattern ) == tests[ i ]._expected_result )
    736                        ? "OK    "
    737                        : "Failed" );
    738     std::cout << " - time( " << tests[ i ]._pattern << " )";
    739     std::cout << std::endl;
    740   }
    741 }
    742 
    743 int main(int argc, char* argv[])
    744 {
    745   test_float();
    746   test_date();
    747   test_time();
    748 
    749 	return 0;
    750 }
    751 */
    752