Simple data structures / objects in plain C Snapshot
|
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 \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