Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals  

dt_stream_text.c

Go to the documentation of this file.
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 /*       reader object implementation                                */
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; /* put char back and go on... */
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); /* skip the key mark */
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; /* put char back and go on... */
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; /* c==eKeyMark --> throw("Unexpected key mark (:)"); */
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       /* skip comment until end of line */
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) ) /* naked/simple identifier */
00172    {
00173       do {
00174          if(! dt_buf_append( buf, c ) )return 0; /* throw out of mem */
00175          c = fgetc(src);
00176       } while ( isIdentifierChar(c) );
00177    }
00178    else
00179    {
00180       if (c!=ePasQuote)
00181          return 0;/*throw("Identifier Expected"); */
00182 
00183       for(;;)
00184       {
00185          c = fgetc(src);
00186          if (c==ePasQuote)
00187          {
00188             c = fgetc(src); /* end reached unless is a double quote */
00189             if (c!=ePasQuote)
00190                break;
00191          }
00192          else if (c==EOF)
00193             return 0;/*throw("End Quote Missing (')"); */
00194 
00195          if(! dt_buf_append( buf, c ) )return 0; /* throw out of mem */
00196       }
00197    }
00198    ungetc( c, src );
00199    return (c==eKeyMark) ? c : 1;    
00200 }
00201 
00202 
00203 /*===================================================================*/
00204 /*       writer object implementation                                */
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 ) /* step is within a record */
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) /* step is within an array */
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 /* putchar( c ); /*TEMP for console debugging */
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 ) /* force explicit CR before LF for line end */
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; /* must quote empty string */
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 

Generated on Sun Jun 1 16:35:38 2003 for datatree by doxygen 1.3.1