diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:30:32 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:30:32 -0800 |
commit | 8b23a6c7e1aee255004dd19098d4c2462b61b849 (patch) | |
tree | 7a4d682ba51f0ff0364c5ca2509f515bdaf96de9 /android/utils/ini.c | |
parent | f721e3ac031f892af46f255a47d7f54a91317b30 (diff) | |
download | external_qemu-8b23a6c7e1aee255004dd19098d4c2462b61b849.zip external_qemu-8b23a6c7e1aee255004dd19098d4c2462b61b849.tar.gz external_qemu-8b23a6c7e1aee255004dd19098d4c2462b61b849.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'android/utils/ini.c')
-rw-r--r-- | android/utils/ini.c | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/android/utils/ini.c b/android/utils/ini.c new file mode 100644 index 0000000..95bb4e3 --- /dev/null +++ b/android/utils/ini.c @@ -0,0 +1,416 @@ +/* Copyright (C) 2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#include "android/utils/ini.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <errno.h> +#include "android/utils/debug.h" +#include "android/utils/system.h" /* for ASTRDUP */ +#include "android/utils/bufprint.h" +#include "osdep.h" + +/* W() is used to print warnings, D() to print debugging info */ +#define W(...) dwarning(__VA_ARGS__) +#define D(...) VERBOSE_PRINT(avd_config,__VA_ARGS__) + +/* a simple .ini file parser and container for Android + * no sections support. see android/utils/ini.h for + * more details on the supported file format. + */ +typedef struct { + char* key; + char* value; +} IniPair; + +struct IniFile { + int numPairs; + int maxPairs; + IniPair* pairs; +}; + +void +iniFile_free( IniFile* i ) +{ + int nn; + for (nn = 0; nn < i->numPairs; nn++) { + AFREE(i->pairs[nn].key); + i->pairs[nn].key = NULL; + i->pairs[nn].value = NULL; + } + AFREE(i->pairs); + AFREE(i); +} + +static IniFile* +iniFile_alloc( void ) +{ + IniFile* i; + + ANEW0(i); + return i; +} + +static void +iniFile_addPair( IniFile* i, const char* key, int keyLen, + const char* value, int valueLen ) +{ + IniPair* pair; + + if (i->numPairs >= i->maxPairs) { + int oldMax = i->maxPairs; + int newMax = oldMax + (oldMax >> 1) + 4; + + AARRAY_RENEW(i->pairs, newMax); + i->maxPairs = newMax; + } + + pair = i->pairs + i->numPairs; + + AARRAY_NEW(pair->key, keyLen + valueLen + 2); + memcpy(pair->key, key, keyLen); + pair->key[keyLen] = 0; + + pair->value = pair->key + keyLen + 1; + memcpy(pair->value, value, valueLen); + pair->value[valueLen] = 0; + + i->numPairs += 1; +} + +const char* +iniFile_getValue( IniFile* i, const char* key ) +{ + if (i && key) { + int nn; + + for (nn = 0; nn < i->numPairs; nn++) { + if (!strcmp(i->pairs[nn].key,key)) + return i->pairs[nn].value; + } + } + return NULL; +} + +int +iniFile_getPairCount( IniFile* i ) +{ + return i ? i->numPairs : 0; +} + +void +iniFile_getPair( IniFile* i, + int index, + const char* *pKey, + const char* *pValue ) +{ + const char* key = NULL; + const char* value = NULL; + + if (i && index >= 0 && index < i->numPairs) { + key = i->pairs[index].key; + value = i->pairs[index].value; + } + *pKey = key; + *pValue = value; +} + +/* NOTE: we avoid using <ctype.h> functions to avoid locale-specific + * behaviour that can be the source of strange bugs. + */ + +static const char* +skipSpaces( const char* p ) +{ + while (*p == ' ' || *p == '\t') + p ++; + return p; +} + +static const char* +skipToEOL( const char* p ) +{ + while (*p && (*p != '\n' && *p != '\r')) + p ++; + + if (*p) { + p ++; + if (p[-1] == '\r' && p[0] == '\n') + p ++; + } + return p; +} + +static int +isKeyStartChar( int c ) +{ + return ((unsigned)(c-'a') < 26 || + (unsigned)(c-'A') < 26 || + c == '_'); +} + +static int +isKeyChar( int c ) +{ + return isKeyStartChar(c) || ((unsigned)(c-'0') < 10) || (c == '.') || (c == '-'); +} + +IniFile* +iniFile_newFromMemory( const char* text, const char* fileName ) +{ + const char* p = text; + IniFile* ini = iniFile_alloc(); + int lineno = 0; + + if (!fileName) + fileName = "<memoryFile>"; + + D("%s: parsing as .ini file", fileName); + + while (*p) { + const char* key; + int keyLen; + const char* value; + int valueLen; + + lineno += 1; + + /* skip leading whitespace */ + p = skipSpaces(p); + + /* skip comments and empty lines */ + if (*p == 0 || *p == ';' || *p == '#' || *p == '\n' || *p == '\r') { + p = skipToEOL(p); + continue; + } + + /* check the key name */ + key = p++; + if (!isKeyStartChar(*key)) { + p = skipToEOL(p); + W("%4d: key name doesn't start with valid character. line ignored", + lineno); + continue; + } + + while (isKeyChar(*p)) + p++; + + keyLen = p - key; + p = skipSpaces(p); + + /* check the equal */ + if (*p != '=') { + W("%4d: missing expected assignment operator (=). line ignored", + lineno); + p = skipToEOL(p); + continue; + } + p += 1; + + /* skip spaces before the value */ + p = skipSpaces(p); + value = p; + + /* find the value */ + while (*p && (*p != '\n' && *p != '\r')) + p += 1; + + /* remove trailing spaces */ + while (p > value && (p[-1] == ' ' || p[-1] == '\t')) + p --; + + valueLen = p - value; + + iniFile_addPair(ini, key, keyLen, value, valueLen); + D("%4d: KEY='%.*s' VALUE='%.*s'", lineno, + keyLen, key, valueLen, value); + + p = skipToEOL(p); + } + + D("%s: parsing finished", fileName); + + return ini; +} + +IniFile* +iniFile_newFromFile( const char* filepath ) +{ + FILE* fp = fopen(filepath, "rt"); + char* text; + long size; + IniFile* ini = NULL; + + if (fp == NULL) { + D("could not open .ini file: %s: %s", + filepath, strerror(errno)); + return NULL; + } + + fseek(fp, 0, SEEK_END); + size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + /* avoid reading a very large file that was passed by mistake + * this threshold is quite liberal. + */ +#define MAX_INI_FILE_SIZE 655360 + + if (size < 0 || size > MAX_INI_FILE_SIZE) { + W("hardware configuration file '%s' too large (%ld bytes)", + filepath, size); + goto EXIT; + } + + /* read the file, add a sentinel at the end of it */ + AARRAY_NEW(text, size+1); + fread(text, 1, size, fp); + text[size] = 0; + + ini = iniFile_newFromMemory(text, filepath); + AFREE(text); + +EXIT: + fclose(fp); + return ini; +} + +int +iniFile_saveToFile( IniFile* f, const char* filepath ) +{ + FILE* fp = fopen(filepath, "wt"); + IniPair* pair = f->pairs; + IniPair* pairEnd = pair + f->numPairs; + int result = 0; + + if (fp == NULL) { + D("could not create .ini file: %s: %s", + filepath, strerror(errno)); + return -1; + } + + for ( ; pair < pairEnd; pair++ ) { + char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); + p = bufprint(temp, end, "%s = %s\n", pair->key, pair->value); + if (fwrite(temp, p - temp, 1, fp) != 1) { + result = -1; + break; + } + } + + fclose(fp); + return result; +} + +char* +iniFile_getString( IniFile* f, const char* key ) +{ + const char* val = iniFile_getValue(f, key); + + if (!val) + return NULL; + + return ASTRDUP(val); +} + +int +iniFile_getInteger( IniFile* f, const char* key, int defaultValue ) +{ + const char* valueStr = iniFile_getValue(f, key); + int value = defaultValue; + + if (valueStr != NULL) { + char* end; + long l = strtol(valueStr, &end, 10); + if (end != NULL && end[0] == 0 && (int)l == l) + value = l; + } + return value; +} + +double +iniFile_getDouble( IniFile* f, const char* key, double defaultValue ) +{ + const char* valueStr = iniFile_getValue(f, key); + double value = defaultValue; + + if (valueStr != NULL) { + char* end; + double d = strtod(valueStr, &end); + if (end != NULL && end[0] == 0) + value = d; + } + return value; +} + +int +iniFile_getBoolean( IniFile* f, const char* key, const char* defaultValue ) +{ + const char* value = iniFile_getValue(f, key); + + if (!value) + value = defaultValue; + + if (!strcmp(value,"1") || + !strcmp(value,"yes") || + !strcmp(value,"YES") || + !strcmp(value,"true") || + !strcmp(value,"TRUE")) + { + return 1; + } + else + return 0; +} + +int64_t +iniFile_getDiskSize( IniFile* f, const char* key, const char* defaultValue ) +{ + const char* valStr = iniFile_getValue(f, key); + int64_t value = 0; + + if (!valStr) + valStr = defaultValue; + + if (valStr != NULL) { + char* end; + + value = strtoll(valStr, &end, 10); + if (*end == 'k' || *end == 'K') + value *= 1024ULL; + else if (*end == 'm' || *end == 'M') + value *= 1024*1024ULL; + else if (*end == 'g' || *end == 'G') + value *= 1024*1024*1024ULL; + } + return value; +} + +int64_t +iniFile_getInt64( IniFile* f, const char* key, int64_t defaultValue ) +{ + const char* valStr = iniFile_getValue(f, key); + int64_t value = defaultValue; + + if (valStr != NULL) { + char* end; + int64_t d; + + d = strtoll(valStr, &end, 10); + if (end != NULL && end[0] == 0) + value = d; + } + return value; +} + |