Simple data structures / objects in plain C Snapshot
properties.c
Go to the documentation of this file.
00001 #include "properties.h"
00002 #include <string.h>
00003 #include <stdio.h>
00004 #include <stdlib.h>
00005 #include <limits.h>
00006 #include <ctype.h>
00007 #include <errno.h>
00008 #include <cutils/dbuf.h>
00009 
00010 /* I took the liberty to adapt the property file parsing stuff from java.lang.Properties class */
00011 
00012 #define IN_BUF_SIZE 8192
00013 #define TRUE 1
00014 #define FALSE 0
00015 
00016 static int load_properties(PROPERTIES *props, const char *file_name);
00017 static int readLine(FILE *fp, DBUF *lineBuff, char *inBuf, int *inOff, int *inLimit);
00018 static int loadConvert ( DBUF *ret, const char * in, int off, int len);
00019 
00020 static int props_compare_key(HASH_Entry *entry, void * key, ssize_t key_length)
00021 {
00022   NAMEVALUE_HASH_ENTRY *pe = (NAMEVALUE_HASH_ENTRY *) entry;
00023 
00024   M_UNUSED( key_length );
00025   return strcmp( pe->name, key );
00026 }
00027 
00028 
00029 int PROPERTIES_init( PROPERTIES *props, int num_buckets )
00030 {
00031   return HASH_init( &props->props, num_buckets, 0, props_compare_key, 0 );
00032 }
00033 
00034 void PROPERTIES_free( PROPERTIES *props )
00035 {
00036    HASH_Entry *cur;
00037    NAMEVALUE_HASH_ENTRY *entry;
00038 
00039    HASH_DELETEALL(cur, &props->props);
00040      entry = (NAMEVALUE_HASH_ENTRY *) cur;
00041      free(entry->name);
00042      free(entry->value);
00043      free(entry);
00044    HASH_DELETEALL_END
00045 }
00046 
00047 
00048 int PROPERTIES_put( PROPERTIES *props, const char *name , const char *value )
00049 {
00050   NAMEVALUE_HASH_ENTRY *val;
00051 
00052   val = (NAMEVALUE_HASH_ENTRY *) malloc( sizeof(  NAMEVALUE_HASH_ENTRY ) ); 
00053   if (!val) {
00054     return -1;
00055   }
00056   val->value = val->name = 0;
00057 
00058   val->name = strdup( name );
00059   if (!val->name) {
00060     goto err;
00061   }
00062   val->value = strdup( value );
00063   if (!val->value) {
00064     goto err;
00065   }
00066   if (HASH_insert( &props->props, &val->entry, (void *)  name, -1 )) {
00067     goto err;
00068   }
00069   return 0;
00070 err:
00071   if (val->value) {
00072     free( val->value );
00073   }
00074   if (val->name) {
00075     free( val->name );
00076   }
00077   free( val );
00078   return 0;
00079 
00080 }
00081 
00082 const char * PROPERTIES_get( PROPERTIES *props, const char *name )
00083 {
00084   NAMEVALUE_HASH_ENTRY *value;
00085 
00086   value = (NAMEVALUE_HASH_ENTRY *) HASH_find( &props->props, (void *) name, -1 );
00087   if (!value) {
00088     return 0;
00089   }
00090   return value->value;
00091 }
00092 
00093 
00094 
00095 
00096 int PROPERTIES_load(PROPERTIES *props, const char *file_name)
00097 {
00098    if (PROPERTIES_init( props, 30 )) {
00099      return -1;
00100    }
00101    return load_properties( props, file_name );
00102 }
00103 
00104 
00105 static int load_properties(PROPERTIES *props, const char *file_name)
00106 {
00107   FILE * fp; 
00108   DBUF line,name,value;
00109   int limit;
00110   int keyLen;
00111   int valueStart;
00112   char c;
00113   int hasSep;
00114   int precedingBackslash;
00115   char *inBuf;
00116   int inOff = 0, inLimit = 0;
00117         
00118   fp = fopen( file_name , "r");
00119   if (!fp) {
00120     return -1;
00121    }
00122 
00123   inBuf = malloc( IN_BUF_SIZE );
00124   if (!inBuf) {
00125     fclose(fp);
00126     return -1;
00127   }
00128 
00129   DBUF_init( &line, 0 );
00130 
00131   while( (limit = readLine(fp, &line, inBuf, &inOff, &inLimit )) >=0 ) {
00132         c = 0;
00133         DBUF_add( &line, &c, sizeof(c) );
00134         
00135 
00136         keyLen = 0;
00137         valueStart = limit;
00138         hasSep = FALSE;
00139 
00140         //System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
00141         precedingBackslash = FALSE;
00142         while (keyLen < limit) {
00143             c = line.buf[keyLen];
00144             //need check if escaped.
00145             if ((c == '=' ||  c == ':') && !precedingBackslash) {
00146                 valueStart = keyLen + 1;
00147                 hasSep = TRUE;
00148                 break;
00149             } else if ((c == ' ' || c == '\t' ||  c == '\f') && !precedingBackslash) {
00150                 valueStart = keyLen + 1;
00151                 break;
00152             } 
00153             if (c == '\\') {
00154                 precedingBackslash = !precedingBackslash;
00155             } else {
00156                 precedingBackslash = FALSE;
00157             }
00158             keyLen++;
00159         }
00160         while (valueStart < limit) {
00161             c = line.buf[valueStart];
00162             if (c != ' ' && c != '\t' &&  c != '\f') {
00163                 if (!hasSep && (c == '=' ||  c == ':')) {
00164                     hasSep = TRUE;
00165                 } else {
00166                     break;
00167                 }
00168             }
00169             valueStart++;
00170         }
00171 
00172         DBUF_init( &name, 0 );
00173         DBUF_init( &value, 0 );
00174 
00175         if (loadConvert(&name, (char *) line.buf, 0, keyLen)) {
00176                         return -1;
00177         }
00178         if (loadConvert(&value, (char *) line.buf, valueStart, limit - valueStart)) {
00179                         return -1;
00180         }
00181 
00182         PROPERTIES_put( props, (char *) name.buf, (char *) value.buf );
00183   }
00184   fclose(fp);
00185   free(inBuf);
00186   return 0;
00187 }
00188 
00189 
00190 static int readLine(FILE *fp, DBUF *lineBuf, char *inBuf, int *inOff, int *inLimit) 
00191 {
00192   int len = 0;
00193   char c = 0;
00194  
00195   DBUF_reset( lineBuf );
00196 
00197   int skipWhiteSpace = TRUE;
00198   int isCommentLine = FALSE;
00199   int isNewLine = TRUE;
00200   int appendedLineBegin = FALSE;
00201   int precedingBackslash = FALSE;
00202   int skipLF = FALSE;
00203 
00204   while (TRUE) {
00205                 if ( *inOff >= *inLimit ) {
00206                         //inLimit = inStream.read(inBuf);
00207                         *inLimit = fread(inBuf,1,IN_BUF_SIZE,fp);
00208                         *inOff = 0;
00209                         
00210                         if (*inLimit <= 0) {
00211                                 if (len == 0 || isCommentLine) { 
00212                                         return -1; 
00213                                 }
00214                                 return len;
00215                         }
00216                 }     
00217                 
00218                 //The line below is equivalent to calling a 
00219                 //ISO8859-1 decoder.
00220                 c = (char) (0xff & inBuf[ (*inOff)++ ]);
00221                 if (skipLF) {
00222                         skipLF = FALSE;
00223                         if (c == '\n') {
00224                                 continue;
00225                         }
00226                 }
00227                 if (skipWhiteSpace) {
00228                         if (c == ' ' || c == '\t' || c == '\f') {
00229                                 continue;
00230                         }
00231                         if (!appendedLineBegin && (c == '\r' || c == '\n')) {
00232                                 continue;
00233                         }
00234                         skipWhiteSpace = FALSE;
00235                         appendedLineBegin = FALSE;
00236                 }
00237                 
00238                 if (isNewLine) {
00239                         isNewLine = FALSE;
00240                         if (c == '#' || c == '!') {
00241                                 isCommentLine = TRUE;
00242                                 continue;
00243                         }
00244                 }
00245                 
00246                 if (c != '\n' && c != '\r') {
00247                         //lineBuf[len++] = c;
00248                         //lineBuf += c;
00249                         DBUF_add( lineBuf, &c, sizeof(c) );
00250                         len ++;
00251                         
00252                         //flip the preceding backslash flag
00253                         if (c == '\\') {
00254                                 precedingBackslash = !precedingBackslash;
00255                         } else {
00256                                 precedingBackslash = FALSE;
00257                         }
00258                 }
00259                 else {
00260                         // reached EOL
00261                         if (isCommentLine || len == 0) {
00262                                 isCommentLine = FALSE;
00263                                 isNewLine = TRUE;
00264                                 skipWhiteSpace = TRUE;
00265                                 len = 0;
00266                                 DBUF_reset( lineBuf );
00267                                 continue;
00268                         }
00269                         if ( *inOff >= *inLimit ) {
00270                                 //inLimit = inStream.read(inBuf);
00271                                 *inLimit = fread(inBuf,1,IN_BUF_SIZE,fp);
00272                                 *inOff = 0;
00273                                 if ( *inLimit <= 0 ) {
00274                                         return len;
00275                                 }
00276                         }
00277                         if (precedingBackslash) {
00278                                 len -= 1;
00279                                 //skip the leading whitespace characters in following line
00280                                 skipWhiteSpace = TRUE;
00281                                 appendedLineBegin = TRUE;
00282                                 precedingBackslash = FALSE;
00283                                 if (c == '\r') {
00284                                         skipLF = TRUE;
00285                                 }
00286                         } else {
00287                                 return len;
00288                         }
00289                 }
00290   }
00291 }
00292 
00293 /*
00294  * Converts encoded &#92;uxxxx to unicode chars
00295  * and changes special saved chars to their original forms
00296  */
00297 static int loadConvert ( DBUF *ret, const char * in, int off, int len) {
00298   char aChar;
00299   int end = off + len;
00300   unsigned int value=0; 
00301   int i;
00302   
00303   while (off < end) {
00304         aChar = in[off++];
00305         if (aChar == '\\') {
00306             aChar = in[off++];   
00307             if(aChar == 'u') {
00308                 // Read the xxxx
00309                
00310                                 for (i=0; i<4; i++) {
00311                                         aChar = in[off++];  
00312                                         switch (aChar) {
00313                                           case '0': case '1': case '2': case '3': case '4':
00314                                           case '5': case '6': case '7': case '8': case '9':
00315                                                          value = (value << 4) + aChar - '0';
00316                                                  break;
00317                                           case 'a': case 'b': case 'c':
00318                                                                   case 'd': case 'e': case 'f':
00319                                                  value = (value << 4) + 10 + aChar - 'a';
00320                                                  break;
00321                                           case 'A': case 'B': case 'C':
00322                                                                   case 'D': case 'E': case 'F':
00323                                                  value = (value << 4) + 10 + aChar - 'A';
00324                                                  break;
00325                                           default:
00326 #if 0
00327                                                   if (Log::is_error()) {
00328                                                           Log::log( LOG_ERROR, "Malformed \\uxxxx encoding.");
00329                                                                           return -1;
00330                                                   }
00331 #endif
00332                                           return -1;
00333                                         }
00334                                 }
00335                                 DBUF_add( ret, &value, sizeof( value ) );
00336                         } else {
00337                 if (aChar == 't') aChar = '\t'; 
00338                 else if (aChar == 'r') aChar = '\r';
00339                 else if (aChar == 'n') aChar = '\n';
00340                 else if (aChar == 'f') aChar = '\f'; 
00341                 
00342                 DBUF_add( ret, &aChar, sizeof( aChar ) );
00343             }
00344         } else {
00345             DBUF_add( ret, &aChar, sizeof( aChar ) );
00346         }
00347   }
00348 
00349   aChar = 0;
00350   DBUF_add( ret, &aChar, sizeof( aChar ) );
00351   return 0;
00352 }
00353 
00354