Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: xively-jumpstart-demo
csv_data.c
00001 // Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved. 00002 // This is part of Xively C library, it is under the BSD 3-Clause license. 00003 00004 /** 00005 * \file csv_data.c 00006 * \author Olgierd Humenczuk 00007 * \brief Implements CSV _data layer_ encoders and decoders specific to Xively CSV data format [see csv_data.h] 00008 */ 00009 00010 #include <assert.h> 00011 #include <stdio.h> 00012 #include <time.h> 00013 00014 #include "csv_data.h" 00015 #include "xi_macros.h" 00016 #include "xi_helpers.h" 00017 #include "xi_err.h" 00018 #include "xi_consts.h" 00019 00020 static char XI_CSV_LOCAL_BUFFER[ XI_CSV_BUFFER_SIZE ]; 00021 00022 inline static int csv_encode_value( 00023 char* buffer 00024 , size_t buffer_size 00025 , const xi_datapoint_t* p ) 00026 { 00027 // PRECONDITION 00028 assert( buffer != 0 ); 00029 assert( buffer_size != 0 ); 00030 assert( p != 0 ); 00031 00032 switch( p->value_type ) 00033 { 00034 case XI_VALUE_TYPE_I32: 00035 return snprintf( buffer, buffer_size, "%d", p->value.i32_value ); 00036 case XI_VALUE_TYPE_F32: 00037 return snprintf( buffer, buffer_size, "%f", p->value.f32_value ); 00038 case XI_VALUE_TYPE_STR: 00039 return snprintf( buffer, buffer_size, "%s", p->value.str_value ); 00040 default: 00041 return -1; 00042 } 00043 } 00044 00045 typedef enum 00046 { 00047 XI_CHAR_UNKNOWN = 0, 00048 XI_CHAR_NUMBER, 00049 XI_CHAR_LETTER, 00050 XI_CHAR_DOT, 00051 XI_CHAR_SPACE, 00052 XI_CHAR_NEWLINE, 00053 XI_CHAR_TAB, 00054 XI_CHAR_MINUS 00055 } xi_char_type_t; 00056 00057 inline static xi_char_type_t csv_classify_char( char c ) 00058 { 00059 switch( c ) 00060 { 00061 case 13: 00062 case 11: 00063 return XI_CHAR_NEWLINE; 00064 case 9: 00065 return XI_CHAR_TAB; 00066 case 32: 00067 return XI_CHAR_SPACE; 00068 case 33: case 34: case 35: case 36: case 37: case 38: case 39: 00069 case 40: case 41: case 42: case 43: case 44: 00070 return XI_CHAR_UNKNOWN; 00071 case 45: 00072 return XI_CHAR_MINUS; 00073 case 46: 00074 return XI_CHAR_DOT; 00075 case 47: 00076 return XI_CHAR_UNKNOWN; 00077 case 48: case 49: case 50: case 51: case 52: case 53: case 54: 00078 case 55: case 56: 00079 case 57: 00080 return XI_CHAR_NUMBER; 00081 case 58: case 59: case 60: case 61: case 62: case 63: 00082 case 64: 00083 return XI_CHAR_UNKNOWN; 00084 case 65: case 66: case 67: case 68: case 69: case 70: case 71: 00085 case 72: case 73: case 74: case 75: case 76: case 77: case 78: 00086 case 79: case 80: case 81: case 82: case 83: case 84: case 85: 00087 case 86: case 87: case 88: case 89: 00088 case 90: 00089 return XI_CHAR_LETTER; 00090 case 91: case 92: case 93: case 94: case 95: 00091 case 96: 00092 return XI_CHAR_UNKNOWN; 00093 case 97: case 98: case 99: case 100: case 101: case 102: case 103: 00094 case 104: case 105: case 106: case 107: case 108: case 109: case 110: 00095 case 111: case 112: case 113: case 114: case 115: case 116: case 117: 00096 case 118: case 119: case 120: case 121: 00097 case 122: 00098 return XI_CHAR_LETTER; 00099 case 123: 00100 case 124: 00101 case 125: 00102 return XI_CHAR_UNKNOWN; 00103 default: 00104 return XI_CHAR_UNKNOWN; 00105 } 00106 } 00107 00108 typedef enum 00109 { 00110 XI_STATE_INITIAL = 0, 00111 XI_STATE_MINUS, 00112 XI_STATE_NUMBER, 00113 XI_STATE_FLOAT, 00114 XI_STATE_DOT, 00115 XI_STATE_STRING 00116 } xi_dfa_state_t; 00117 00118 xi_datapoint_t* csv_decode_value( 00119 const char* buffer, xi_datapoint_t* p ) 00120 { 00121 // PRECONDITION 00122 assert( buffer != 0 ); 00123 assert( p != 0 ); 00124 00125 // secure the output buffer 00126 XI_GUARD_EOS( p->value.str_value, XI_VALUE_STRING_MAX_SIZE ); 00127 00128 // clean the counter 00129 size_t counter = 0; 00130 00131 // the transition function 00132 static const short states[][6][2] = 00133 { 00134 // state initial // state minus // state number // state float // state dot // string 00135 { { XI_CHAR_UNKNOWN , XI_STATE_STRING }, { XI_CHAR_UNKNOWN , XI_STATE_STRING }, { XI_CHAR_UNKNOWN , XI_STATE_STRING }, { XI_CHAR_UNKNOWN , XI_STATE_STRING }, { XI_CHAR_UNKNOWN , XI_STATE_STRING }, { XI_CHAR_UNKNOWN , XI_STATE_STRING } }, 00136 { { XI_CHAR_NUMBER , XI_STATE_NUMBER }, { XI_CHAR_NUMBER , XI_STATE_NUMBER }, { XI_CHAR_NUMBER , XI_STATE_NUMBER }, { XI_CHAR_NUMBER , XI_STATE_FLOAT }, { XI_CHAR_NUMBER , XI_STATE_FLOAT }, { XI_CHAR_NUMBER , XI_STATE_STRING } }, 00137 { { XI_CHAR_LETTER , XI_STATE_STRING }, { XI_CHAR_LETTER , XI_STATE_STRING }, { XI_CHAR_LETTER , XI_STATE_STRING }, { XI_CHAR_LETTER , XI_STATE_STRING }, { XI_CHAR_LETTER , XI_STATE_STRING }, { XI_CHAR_LETTER , XI_STATE_STRING } }, 00138 { { XI_CHAR_DOT , XI_STATE_DOT }, { XI_CHAR_DOT , XI_STATE_DOT }, { XI_CHAR_DOT , XI_STATE_DOT }, { XI_CHAR_DOT , XI_STATE_STRING }, { XI_CHAR_DOT , XI_STATE_STRING }, { XI_CHAR_DOT , XI_STATE_STRING } }, 00139 { { XI_CHAR_SPACE , XI_STATE_STRING }, { XI_CHAR_SPACE , XI_STATE_STRING }, { XI_CHAR_SPACE , XI_STATE_STRING }, { XI_CHAR_SPACE , XI_STATE_STRING }, { XI_CHAR_SPACE , XI_STATE_STRING }, { XI_CHAR_SPACE , XI_STATE_STRING } }, 00140 { { XI_CHAR_NEWLINE , XI_STATE_INITIAL }, { XI_CHAR_NEWLINE , XI_STATE_INITIAL }, { XI_CHAR_NEWLINE , XI_STATE_INITIAL }, { XI_CHAR_NEWLINE , XI_STATE_INITIAL }, { XI_CHAR_NEWLINE , XI_STATE_INITIAL }, { XI_CHAR_NEWLINE , XI_STATE_INITIAL } }, 00141 { { XI_CHAR_TAB , XI_STATE_STRING }, { XI_CHAR_TAB , XI_STATE_STRING }, { XI_CHAR_TAB , XI_STATE_STRING }, { XI_CHAR_TAB , XI_STATE_STRING }, { XI_CHAR_TAB , XI_STATE_STRING }, { XI_CHAR_TAB , XI_STATE_STRING } }, 00142 { { XI_CHAR_MINUS , XI_STATE_MINUS }, { XI_CHAR_MINUS , XI_STATE_STRING }, { XI_CHAR_MINUS , XI_STATE_STRING }, { XI_CHAR_MINUS , XI_STATE_STRING }, { XI_CHAR_MINUS , XI_STATE_STRING }, { XI_CHAR_MINUS , XI_STATE_STRING } } 00143 }; 00144 00145 char c = *buffer; 00146 short s = XI_STATE_INITIAL; 00147 00148 while( c != '\n' && c !='\0' && c!='\r' ) 00149 { 00150 if( counter >= XI_VALUE_STRING_MAX_SIZE - 1 ) 00151 { 00152 xi_set_err( XI_DATAPOINT_VALUE_BUFFER_OVERFLOW ); 00153 return 0; 00154 } 00155 00156 xi_char_type_t ct = csv_classify_char( c ); 00157 s = states[ ct ][ s ][ 1 ]; 00158 00159 switch( s ) 00160 { 00161 case XI_STATE_MINUS: 00162 case XI_STATE_NUMBER: 00163 case XI_STATE_FLOAT: 00164 case XI_STATE_DOT: 00165 case XI_STATE_STRING: 00166 p->value.str_value[ counter ] = c; 00167 break; 00168 } 00169 00170 c = *( ++buffer ); 00171 ++counter; 00172 } 00173 00174 // set the guard 00175 p->value.str_value[ counter ] = '\0'; 00176 00177 // update of the state for loose states... 00178 switch( s ) 00179 { 00180 case XI_STATE_MINUS: 00181 case XI_STATE_DOT: 00182 case XI_STATE_INITIAL: 00183 s = XI_STATE_STRING; 00184 break; 00185 } 00186 00187 switch( s ) 00188 { 00189 case XI_STATE_NUMBER: 00190 p->value.i32_value = atoi( p->value.str_value ); 00191 p->value_type = XI_VALUE_TYPE_I32; 00192 break; 00193 case XI_STATE_FLOAT: 00194 p->value.f32_value = atof( p->value.str_value ); 00195 p->value_type = XI_VALUE_TYPE_F32; 00196 break; 00197 case XI_STATE_STRING: 00198 default: 00199 p->value_type = XI_VALUE_TYPE_STR; 00200 } 00201 00202 return p; 00203 } 00204 00205 const char* csv_encode_datapoint( const xi_datapoint_t* data ) 00206 { 00207 00208 // PRECONDITIONS 00209 assert( data != 0 ); 00210 00211 return csv_encode_datapoint_in_place( XI_CSV_LOCAL_BUFFER, sizeof( XI_CSV_LOCAL_BUFFER ), data ) == -1 ? 0 : XI_CSV_LOCAL_BUFFER; 00212 } 00213 00214 int csv_encode_datapoint_in_place( 00215 char* in, size_t in_size 00216 , const xi_datapoint_t* datapoint ) 00217 { 00218 // PRECONDITIONS 00219 assert( in != 0 ); 00220 assert( datapoint != 0 ); 00221 00222 int s = 0; 00223 int size = in_size; 00224 int offset = 0; 00225 00226 if( datapoint->timestamp.timestamp != 0 ) 00227 { 00228 time_t stamp = datapoint->timestamp.timestamp; 00229 struct tm* gmtinfo = xi_gmtime( &stamp ); 00230 00231 s = snprintf( in, size 00232 , "%04d-%02d-%02dT%02d:%02d:%02d.%06dZ," 00233 , gmtinfo->tm_year + 1900 00234 , gmtinfo->tm_mon + 1 00235 , gmtinfo->tm_mday 00236 , gmtinfo->tm_hour 00237 , gmtinfo->tm_min 00238 , gmtinfo->tm_sec 00239 , ( int ) datapoint->timestamp.micro ); 00240 00241 XI_CHECK_S( s, size, offset, XI_CSV_ENCODE_DATAPOINT_BUFFER_OVERRUN ); 00242 } 00243 00244 s = csv_encode_value( in + offset, size - offset, datapoint ); 00245 XI_CHECK_S( s, size, offset, XI_CSV_ENCODE_DATAPOINT_BUFFER_OVERRUN ); 00246 00247 s = snprintf( in + offset, size - offset, "%s", "\n" ); 00248 XI_CHECK_S( s, size, offset, XI_CSV_ENCODE_DATAPOINT_BUFFER_OVERRUN ); 00249 00250 return offset; 00251 00252 err_handling: 00253 return -1; 00254 } 00255 00256 const char* csv_encode_create_datastream( 00257 const char* datastream_id 00258 , const xi_datapoint_t* data ) 00259 { 00260 // PRECONDITIONS 00261 assert( data != 0 ); 00262 00263 int s = snprintf( XI_CSV_LOCAL_BUFFER, sizeof( XI_CSV_LOCAL_BUFFER ) 00264 , "%s,%d\n", datastream_id, data->value.i32_value ); 00265 int size = XI_CSV_BUFFER_SIZE; 00266 00267 XI_CHECK_SIZE( s, size, XI_CSV_ENCODE_DATASTREAM_BUFFER_OVERRUN ); 00268 00269 return XI_CSV_LOCAL_BUFFER; 00270 00271 err_handling: 00272 return 0; 00273 } 00274 00275 xi_feed_t* csv_decode_feed( 00276 const char* buffer 00277 , xi_feed_t* feed ) 00278 { 00279 const char* current = buffer; 00280 int32_t counter = 0; 00281 00282 // find occurence of newline 00283 char* end_of_line = ( char* ) 1; 00284 00285 // while we didn't jump out of the buffer 00286 while( end_of_line ) 00287 { 00288 // get current datapoint 00289 xi_datastream_t* d = &feed->datastreams[ counter ]; 00290 d->datapoint_count = 0; 00291 xi_datapoint_t* p = &d->datapoints[ 0 ]; 00292 memset( p, 0, sizeof( xi_datapoint_t ) ); 00293 00294 end_of_line = strstr( current, "\n" ); 00295 00296 const char* end_of_datastream_id = strstr( current, "," ); 00297 const char* beg_of_datapoint = end_of_datastream_id + 1; 00298 00299 XI_CHECK_ZERO( beg_of_datapoint, XI_CSV_DECODE_FEED_PARSER_ERROR ); 00300 XI_CHECK_ZERO( end_of_datastream_id, XI_CSV_DECODE_FEED_PARSER_ERROR ); 00301 00302 int size = sizeof( d->datastream_id ); 00303 00304 int s = xi_str_copy_untiln( d->datastream_id, size 00305 , current, ',' ); 00306 XI_CHECK_SIZE( s, size, XI_CSV_DECODE_FEED_PARSER_ERROR ); 00307 00308 xi_datapoint_t* ret = csv_decode_datapoint( beg_of_datapoint, p ); 00309 XI_CHECK_ZERO( ret, XI_CSV_DECODE_FEED_PARSER_ERROR ) 00310 00311 d->datapoint_count = 1; 00312 current = end_of_line + 1; 00313 00314 XI_CHECK_CND( ++counter == XI_MAX_DATASTREAMS 00315 , XI_CSV_DECODE_FEED_PARSER_ERROR ); 00316 } 00317 00318 feed->datastream_count = counter; 00319 return feed; 00320 00321 err_handling: 00322 return 0; 00323 } 00324 00325 xi_datapoint_t* csv_decode_datapoint( 00326 const char* buffer 00327 , xi_datapoint_t* datapoint ) 00328 { 00329 // PRECONDITIONS 00330 assert( buffer != 0 ); 00331 assert( datapoint != 0 ); 00332 00333 int ye, mo, da, h, m, s, ms; 00334 00335 const char* beg_of_value = strstr( buffer, "," ); 00336 00337 // check continuation condition 00338 XI_CHECK_ZERO( beg_of_value, XI_CSV_DECODE_DATAPOINT_PARSER_ERROR ); 00339 00340 // move to pointer to the proper position 00341 beg_of_value += 1; 00342 00343 { 00344 int n = sscanf( buffer 00345 , "%04d-%02d-%02dT%02d:%02d:%02d.%06dZ" 00346 , &ye, &mo, &da, &h, &m, &s, &ms ); 00347 00348 // check if the parser worked correctly 00349 XI_CHECK_CND( n != 7, XI_CSV_DECODE_DATAPOINT_PARSER_ERROR ); 00350 00351 // copy parsed data 00352 { 00353 struct tm timeinfo; 00354 00355 timeinfo.tm_year = ye - 1900; 00356 timeinfo.tm_mon = mo - 1; 00357 timeinfo.tm_mday = da; 00358 timeinfo.tm_hour = h; 00359 timeinfo.tm_min = m; 00360 timeinfo.tm_sec = s; 00361 00362 time_t timestamp = xi_mktime( &timeinfo ); 00363 00364 XI_CHECK_CND( ( int )timestamp == -1, XI_CSV_TIME_CONVERTION_ERROR ); 00365 00366 datapoint->timestamp.timestamp = timestamp; 00367 datapoint->timestamp.micro = ms; 00368 } 00369 } 00370 00371 xi_datapoint_t* r = csv_decode_value( beg_of_value 00372 , datapoint ); 00373 00374 00375 XI_CHECK_ZERO( r, XI_CSV_DECODE_DATAPOINT_PARSER_ERROR ); 00376 00377 return datapoint; 00378 00379 err_handling: 00380 return 0; 00381 }
Generated on Wed Jul 13 2022 17:00:32 by
1.7.2