00001 #include "dt_stream_text.h"
00002 #include "dt_stream_base.h"
00003 #include "dt_buf.h"
00004
00005 #include <malloc.h>
00006 #include <ctype.h>
00007 #include <assert.h>
00008
00009
00011 enum {
00012 eCommentMark = '#',
00013 ePasQuote = '\'',
00014 eArrayOpen = '(',
00015 eArrayClose = ')',
00016 eRecordOpen = '{',
00017 eRecordClose = '}',
00018 eKeyMark = ':',
00019 };
00020
00022 static dt_bool isIdentifierChar(int c)
00023 {
00024 if( isalnum(c) )
00025 return 1;
00026
00027 switch(c)
00028 {
00029 case '+': case '-': case '.': case '_':
00030 return 1;
00031 default:
00032 return 0;
00033 }
00034 }
00035
00036
00037
00038
00039
00040
00042 typedef struct
00043 {
00044 dt_reader base;
00045 FILE* src;
00046 dt_buf key, val;
00047 } dt_reader_text;
00048
00050 static void dt_reader_text_free( dt_reader* obj );
00051
00053 static dt_bool dt_reader_text_read( dt_reader* obj, dt_stream_step* step );
00054
00055 dt_reader*
00056 dt_create_text_reader( FILE* src, dt_text_mode_flags flags )
00057 {
00058 dt_reader_text* ans = (dt_reader_text*)malloc(sizeof(dt_reader_text));
00059 if( ans )
00060 {
00061 dt_init_reader_base( & ans->base, & dt_reader_text_free, & dt_reader_text_read );
00062 ans->src = src;
00063 if( dt_buf_init( & ans->key ) )
00064 {
00065 if( dt_buf_init( & ans->val ) )
00066 return & ans->base;
00067 dt_buf_free( & ans->key );
00068 }
00069 free(ans);
00070 }
00071 return 00;
00072 }
00073
00074 static void dt_reader_text_free( dt_reader* obj )
00075 {
00076 dt_reader_text* o = (dt_reader_text*)obj;
00077 dt_buf_free( & o->key );
00078 dt_buf_free( & o->val );
00079 free( o );
00080 }
00081
00082 static int skipBlanks( FILE* const src );
00083 static int readIdentifier( FILE* const src, dt_buf* buf );
00084
00085 static dt_bool dt_reader_text_read( dt_reader* obj, dt_stream_step* step )
00086 {
00087 dt_reader_text* const o = (dt_reader_text*)obj;
00088 FILE* const src = o->src;
00089
00090 int c = skipBlanks( src );
00091
00092 step->key = 00;
00093 step->key_len = 0;
00094 step->val = 00;
00095 step->val_len = 0;
00096
00097 switch( c ) {
00098 case eArrayOpen: step->kind = dt_arr_in; return 1;
00099 case eArrayClose: step->kind = dt_arr_out; return 1;
00100 case eRecordOpen: step->kind = dt_rec_in; return 1;
00101 case eRecordClose: step->kind = dt_rec_out; return 1;
00102 case EOF: step->kind = dt_end; return 1;
00103 default: ungetc(c,src); break;
00104 }
00105
00106 c = readIdentifier( src, & o->key );
00107 if (c != eKeyMark) {
00108 step->kind = dt_leaf;
00109 step->val = o->key.begin;
00110 step->val_len = o->key.strEnd - step->val;
00111 return 1;
00112 }
00113 fgetc(src);
00114 step->key = o->key.begin;
00115 step->key_len = o->key.strEnd-step->key;
00116 c = skipBlanks(src);
00117
00118 switch (c) {
00119 case eArrayOpen: step->kind = dt_arr_in; return 1;
00120 case eRecordOpen: step->kind = dt_rec_in; return 1;
00121 default: ungetc(c,src); break;
00122 }
00123
00124 c = readIdentifier( src, & o->val );
00125 if ( c==0 || c==eKeyMark ) {
00126 step->key = 00;
00127 step->key_len = 0;
00128 return 0;
00129 }
00130
00131 step->kind = dt_leaf;
00132 step->val = o->val.begin;
00133 step->val_len = o->val.strEnd-step->val;
00134 return 1;
00135 }
00136
00137
00141 static int skipBlanks(FILE* const src)
00142 {
00143 int c = fgetc(src);
00144 for(;;)
00145 {
00146 while( isspace(c) || (c==',') )
00147 c = fgetc(src);
00148
00149 if ( c != eCommentMark )
00150 break;
00151
00152 do { c = fgetc(src); } while ( c!='\n' && c!='\r' && c!=EOF );
00153 }
00154 return c;
00155 }
00156
00165 static int readIdentifier(FILE* const src, dt_buf* buf)
00166 {
00167 int c = fgetc(src);
00168
00169 dt_buf_clear( buf );
00170
00171 if( isIdentifierChar(c) )
00172 {
00173 do {
00174 if(! dt_buf_append( buf, c ) )return 0;
00175 c = fgetc(src);
00176 } while ( isIdentifierChar(c) );
00177 }
00178 else
00179 {
00180 if (c!=ePasQuote)
00181 return 0;
00182
00183 for(;;)
00184 {
00185 c = fgetc(src);
00186 if (c==ePasQuote)
00187 {
00188 c = fgetc(src);
00189 if (c!=ePasQuote)
00190 break;
00191 }
00192 else if (c==EOF)
00193 return 0;
00194
00195 if(! dt_buf_append( buf, c ) )return 0;
00196 }
00197 }
00198 ungetc( c, src );
00199 return (c==eKeyMark) ? c : 1;
00200 }
00201
00202
00203
00204
00205
00206
00208 typedef struct
00209 {
00210 dt_writer base;
00211 FILE* dst;
00212 dt_text_mode_flags mode;
00213 int depth;
00214 dt_step_kind lastKind;
00215 } dt_writer_text;
00216
00217
00218 static void dt_writer_text_free( dt_writer* obj );
00219 static dt_bool dt_writer_text_write( dt_writer* obj, dt_stream_step const* step );
00220
00221
00222 dt_writer*
00223 dt_create_text_writer( FILE* dst, dt_text_mode_flags mode )
00224 {
00225 dt_writer_text* ans = (dt_writer_text*)malloc(sizeof(dt_writer_text));
00226 if( ans )
00227 {
00228 dt_init_writer_base( & ans->base, & dt_writer_text_free, & dt_writer_text_write );
00229 ans->dst = dst;
00230 ans->mode = mode;
00231 ans->depth = 0;
00232 ans->lastKind = dt_end;
00233 return & ans->base;
00234 }
00235 return 00;
00236 }
00237
00238
00240 static void dt_writer_text_free(dt_writer* obj)
00241 {
00242 dt_writer_text* o = (dt_writer_text*)obj;
00243 free( o );
00244 }
00245
00246
00247 static dt_bool sendChar(dt_writer_text* o, int c);
00248 static dt_bool startNewLine(dt_writer_text* o);
00249 static dt_bool writeIdentifier(dt_writer_text* o
00250 , dt_byte const* base, dt_byte const* end);
00251
00253 static dt_bool dt_writer_text_write(dt_writer* obj, dt_stream_step const* step)
00254 {
00255 dt_bool ok;
00256 dt_writer_text* o = (dt_writer_text*)obj;
00257 dt_step_kind lastKind = o->lastKind;
00258 o->lastKind = step->kind;
00259
00260 switch (step->kind)
00261 {
00262 case dt_end:
00263 o->depth = 0;
00264 return startNewLine(o) && 0==fflush( o->dst );
00265 case dt_arr_out:
00266 -- o->depth;
00267 if( ! (o->mode & dt_text_packed) )
00268 if ( 0 == o->depth )
00269 ok = startNewLine(o);
00270 else
00271 ok = sendChar(o,' ');
00272 else
00273 ok = 1;
00274 return ok && sendChar(o,eArrayClose);
00275 case dt_rec_out:
00276 -- o->depth;
00277 return startNewLine(o) && sendChar(o,eRecordClose);
00278 }
00279
00280 if( step->key )
00281 {
00282 int const packed = (o->mode & dt_text_packed);
00283 if( ! packed )
00284 {
00285 if( ! startNewLine(o) ) return 0;
00286 }
00287 else {
00288 if( lastKind == dt_leaf )
00289 if( ! sendChar( o, ' ' ) ) return 0;
00290 }
00291 if(!( writeIdentifier( o, step->key, step->key + step->key_len )
00292 && sendChar( o, eKeyMark )
00293 && ( packed || sendChar( o, '\t' ) )
00294 )) return 0;
00295 }
00296 else if (o->depth > 0)
00297 {
00298 ok = (lastKind == dt_arr_in) || sendChar( o, ',' );
00299 if( ! (o->mode & dt_text_packed) )
00300 if( 1 == o->depth )
00301 ok = ok && startNewLine(o);
00302 else {
00303 if ( lastKind==dt_rec_out && step->kind==dt_rec_in )
00304 ok = ok && startNewLine(o);
00305 ok = ok && sendChar( o, ' ' );
00306 }
00307 if( ! ok ) return 0;
00308 }
00309
00310 switch (step->kind)
00311 {
00312 case dt_arr_in:
00313 ++ o->depth;
00314 return sendChar( o, eArrayOpen );
00315 case dt_rec_in:
00316 ++ o->depth;
00317 return sendChar( o, eRecordOpen );
00318 case dt_leaf:
00319 return writeIdentifier( o, step->val, step->val + step->val_len );
00320 }
00321 return 1;
00322 }
00323
00324
00326 static dt_bool sendChar( dt_writer_text* o, int c)
00327 {
00328 assert( !! o );
00329
00330 return fputc( c, o->dst ) != EOF;
00331 }
00332
00334 static dt_bool startNewLine( dt_writer_text* o )
00335 {
00336 int i;
00337
00338 assert( !! o );
00339
00340 if( o->mode & dt_text_packed )
00341 return 1;
00342
00343 if( o->mode & dt_text_crlf )
00344 if(! sendChar(o,'\r') ) return 0;
00345
00346 if(! sendChar(o,'\n') ) return 0;
00347
00348 for( i = o->depth ; i>0 ; --i )
00349 if(! sendChar(o,'\t') ) return 0;
00350 return 1;
00351 }
00352
00353
00355 static dt_bool writeIdentifier( dt_writer_text* o
00356 , dt_byte const* base, dt_byte const* end)
00357 {
00358 dt_bool needQuote = 0;
00359 dt_byte const* scan;
00360
00361 assert( !! o );
00362
00363 if( base == end )
00364 needQuote = 1;
00365 else
00366 for( scan = base ; scan != end ; ++scan )
00367 if( ! isIdentifierChar(*scan) )
00368 {
00369 needQuote = 1;
00370 break;
00371 }
00372
00373 if( needQuote )
00374 {
00375 if(! sendChar(o,ePasQuote) ) return 0;
00376 for ( scan = base ; scan != end ; ++scan )
00377 {
00378 if (*scan!=ePasQuote) {
00379 if(! sendChar(o,*scan) ) return 0;
00380 }
00381 else {
00382 if(! sendChar(o,ePasQuote) ) return 0;
00383 if(! sendChar(o,ePasQuote) ) return 0;
00384 }
00385 }
00386 if(! sendChar(o,ePasQuote) ) return 0;
00387 }
00388 else
00389 {
00390 for ( scan = base ; scan != end ; ++scan )
00391 if(! sendChar(o,*scan) ) return 0;
00392 }
00393 return 1;
00394 }
00395
00396