diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:04:49 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:04:49 -0800 |
commit | df7881f07f53b041dc0568be8528e9dbb74994cc (patch) | |
tree | 1b3e036f7df4241bf0c2d527b73198c50e1d7891 /android/utils | |
parent | 55f4e4a5ec657a017e3bf75299ad71fd1c968dd3 (diff) | |
download | external_qemu-df7881f07f53b041dc0568be8528e9dbb74994cc.zip external_qemu-df7881f07f53b041dc0568be8528e9dbb74994cc.tar.gz external_qemu-df7881f07f53b041dc0568be8528e9dbb74994cc.tar.bz2 |
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'android/utils')
-rw-r--r-- | android/utils/debug.h | 18 | ||||
-rw-r--r-- | android/utils/dirscanner.c | 203 | ||||
-rw-r--r-- | android/utils/dirscanner.h | 25 | ||||
-rw-r--r-- | android/utils/ini.c | 366 | ||||
-rw-r--r-- | android/utils/ini.h | 121 |
5 files changed, 733 insertions, 0 deletions
diff --git a/android/utils/debug.h b/android/utils/debug.h new file mode 100644 index 0000000..28b93ee --- /dev/null +++ b/android/utils/debug.h @@ -0,0 +1,18 @@ +/* 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. +*/ +#ifndef _ANDROID_UTILS_DEBUG_H +#define _ANDROID_UTILS_DEBUG_H + +/* we'll move android_debug.h here later */ +#include "android_debug.h" + +#endif /* _ANDROID_UTILS_DEBUG_H */ diff --git a/android/utils/dirscanner.c b/android/utils/dirscanner.c new file mode 100644 index 0000000..9f44d2d --- /dev/null +++ b/android/utils/dirscanner.c @@ -0,0 +1,203 @@ +/* Copyright (C) 2007-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/dirscanner.h" +#include "android_utils.h" +#include "vl.h" +#include <stddef.h> + +#define DIRSCANNER_BASE \ + char root[PATH_MAX]; \ + int rootLen; \ + char full[PATH_MAX]; \ + + +#if _WIN32 + +#include <io.h> + +struct DirScanner { + DIRSCANNER_BASE + intptr_t findIndex1; + struct _finddata_t findData; +}; + +/* note: findIndex1 contains the find index + 1 + * so a value of 0 means 'invalid' + */ + +static int +_dirScannerInit( DirScanner* s ) +{ + char* p = s->root + s->rootLen; + char* end = s->root + sizeof s->root; + int ret; + + /* create file spec by appending \* to root */ + p = bufprint(p, end, "\\*"); + if (p >= end) + return -1; + + ret = _findfirst(s->root, &s->findData) + 1; + + s->findIndex1 = ret+1; + return ret; +} + +static void +_dirScanner_done( DirScanner* s ) +{ + if (s->findIndex1 > 0) { + _findclose(s->findIndex1-1); + s->findIndex1 = 0; + } +} + +const char* +dirScanner_next( DirScanner* s ) +{ + char* ret = NULL; + + if (!s || s->findIndex1 <= 0) + return NULL; + + while (ret == NULL) { + ret = s->findData.name; + + /* ignore special directories */ + if (!strcmp(ret, ".") || !strcmp(ret, "..")) { + ret = NULL; + } + /* find next one */ + if (_findnext(s->findIndex1-1, &s->findData) < 0) { + _dirScanner_done(s); + break; + } + } + return ret; +} + +#else /* !_WIN32 */ + +#include <dirent.h> +struct DirScanner { + DIRSCANNER_BASE + DIR* dir; + struct dirent* entry; +}; + +static int +_dirScannerInit( DirScanner* s ) +{ + s->dir = opendir(s->root); + + if (s->dir == NULL) + return -1; + + s->entry = NULL; + return 0; +} + +static void +_dirScanner_done( DirScanner* s ) +{ + if (s->dir) { + closedir(s->dir); + s->dir = NULL; + } +} + +const char* +dirScanner_next( DirScanner* s ) +{ + char* ret = NULL; + + if (!s || s->dir == NULL) + return NULL; + + for (;;) + { + /* read new entry if needed */ + s->entry = readdir(s->dir); + if (s->entry == NULL) { + _dirScanner_done(s); + break; + } + + /* ignore special directories */ + ret = s->entry->d_name; + + if (!strcmp(ret,".") || !strcmp(ret,"..")) { + ret = NULL; + continue; + } + break; + } + return ret; +} + +#endif /* !_WIN32 */ + +DirScanner* +dirScanner_new ( const char* rootPath ) +{ + DirScanner* s = qemu_mallocz(sizeof *s); + char* p = s->root; + char* end = p + sizeof s->root; + + p = bufprint(p, end, "%s", rootPath); + if (p >= end) + goto FAIL; + + s->rootLen = (p - s->root); + + if (_dirScannerInit(s) < 0) + goto FAIL; + + return s; + +FAIL: + dirScanner_free(s); + return NULL; +} + + +void +dirScanner_free( DirScanner* s ) +{ + if (!s) + return; + + _dirScanner_done(s); + qemu_free(s); +} + + +const char* +dirScanner_nextFull( DirScanner* s ) +{ + const char* name = dirScanner_next(s); + char* p; + char* end; + + if (name == NULL) + return NULL; + + p = s->full; + end = p + sizeof s->full; + + p = bufprint(p, end, "%.*s/%s", s->rootLen, s->root, name); + if (p >= end) { + /* ignore if the full name is too long */ + return dirScanner_nextFull(s); + } + return s->full; +} diff --git a/android/utils/dirscanner.h b/android/utils/dirscanner.h new file mode 100644 index 0000000..9486cfc --- /dev/null +++ b/android/utils/dirscanner.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2007-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. +*/ +#ifndef _ANDROID_UTILS_DIR_H +#define _ANDROID_UTILS_DIR_H + +/* simple utility to parse directories for files */ +/* needed because Unix and Windows don't use the same stuff */ + +typedef struct DirScanner DirScanner; + +DirScanner* dirScanner_new ( const char* rootPath ); +void dirScanner_free( DirScanner* s ); +const char* dirScanner_next( DirScanner* s ); +const char* dirScanner_nextFull( DirScanner* s ); + +#endif /* _ANDROID_UTILS_DIR_H */ diff --git a/android/utils/ini.c b/android/utils/ini.c new file mode 100644 index 0000000..d99ecdd --- /dev/null +++ b/android/utils/ini.c @@ -0,0 +1,366 @@ +/* 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_debug.h" +#include "osdep.h" + +/* W() is used to print warnings, D() to print debugging info */ +#define W(...) dwarning(__VA_ARGS__) +#define D(...) VERBOSE_PRINT(vm_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++) { + free(i->pairs[nn].key); + i->pairs[nn].key = NULL; + i->pairs[nn].value = NULL; + } + free(i->pairs); + free(i); +} + +static IniFile* +iniFile_alloc( void ) +{ + IniFile* i = calloc(1, sizeof(*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; + IniPair* newPairs = realloc(i->pairs, newMax*sizeof(newPairs[0])); + + i->pairs = newPairs; + i->maxPairs = newMax; + } + + pair = i->pairs + i->numPairs; + + pair->key = malloc(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 == '.'); +} + +IniFile* +iniFile_newFromMemory( const char* text, const char* fileName ) +{ + const char* p = text; + IniFile* ini = iniFile_alloc(); + int lineno = 0; + + if (!fileName) + fileName = "<unknownFile>"; + + 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("%s:%d: key name doesn't start with valid character. line ignored", + fileName, lineno); + continue; + } + + while (isKeyChar(*p)) + p++; + + keyLen = p - key; + p = skipSpaces(p); + + /* check the equal */ + if (*p != '=') { + W("%s:%d: missing expected assignment operator (=). line ignored", + fileName, 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("%s:%d: KEY='%.*s' VALUE='%.*s'", fileName, lineno, + keyLen, key, valueLen, value); + + p = skipToEOL(p); + } + + return ini; +} + +IniFile* +iniFile_newFromFile( const char* filepath ) +{ + FILE* fp = fopen(filepath, "rt"); + char* text; + long size; + IniFile* ini = NULL; + + if (fp == NULL) { + W("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 */ + text = malloc(size+1); + fread(text, 1, size, fp); + text[size] = 0; + + ini = iniFile_newFromMemory(text, filepath); + free(text); + +EXIT: + fclose(fp); + return ini; +} + +char* +iniFile_getString( IniFile* f, const char* key ) +{ + const char* val = iniFile_getValue(f, key); + + if (!val) + return NULL; + + return qemu_strdup(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; +} diff --git a/android/utils/ini.h b/android/utils/ini.h new file mode 100644 index 0000000..41b369b --- /dev/null +++ b/android/utils/ini.h @@ -0,0 +1,121 @@ +/* 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. +*/ +#ifndef _ANDROID_UTILS_INI_H +#define _ANDROID_UTILS_INI_H + +#include <stdint.h> + +/* the emulator supports a simple .ini file format for its configuration + * files. Here's the BNF for it: + * + * file := <line>* + * line := <comment> | <LF> | <assignment> + * comment := (';'|'#') <noLF>* <LF> + * assignment := <space>* <keyName> <space>* '=' <space>* <valueString> <space>* <LF> + * keyName := <keyNameStartChar> <keyNameChar>* + * keyNameStartChar := [A-Za-z_] + * keyNameChar := [A-Za-z0-9_.] + * valueString := <noLF>* + * space := ' ' | '\t' + * LF := '\r\n' | '\n' | '\r' + * noLF := [^<LF>] + * + * Or, in English: + * + * - no support for sections + * - empty lines are ignored, as well as lines beginning with ';' or '#' + * - lines must be of the form: "<keyName> = <value>" + * - key names must start with a letter or an underscore + * - other key name characters can be letters, digits, underscores or dots + * + * - leading and trailing space are allowed and ignored before/after the key name + * and before/after the value + * + * - there is no restriction on the value, except that it can't contain + * leading/trailing space/tab characters or newline/charfeed characters + * + * - empty values are possible, and will be stored as an empty string. + * - any badly formatted line is discarded (and will print a warning) + * + */ + +/* an opaque structure used to model an .ini configuration file */ +typedef struct IniFile IniFile; + +/* creates a new IniFile object from a config file loaded in memory. + * 'fileName' is only used when writing a warning to stderr in case + * of badly formed output + */ +IniFile* iniFile_newFromMemory( const char* text, const char* fileName ); + +/* creates a new IniFile object from a file path, + * returns NULL if the file cannot be opened. + */ +IniFile* iniFile_newFromFile( const char* filePath); + +/* free an IniFile object */ +void iniFile_free( IniFile* f ); + +/* returns the number of (key.value) pairs in an IniFile */ +int iniFile_getPairCount( IniFile* f ); + +/* return a specific (key,value) pair from an IniFile. + * if the index is not correct, both '*pKey' and '*pValue' will be + * set to NULL. + * + * you should probably use iniFile_getValue() and its variants instead + */ +void iniFile_getPair( IniFile* f, + int index, + const char* *pKey, + const char* *pValue ); + +/* returns the value of a given key from an IniFile. + * NULL if the key is not assigned in the corresponding configuration file + */ +const char* iniFile_getValue( IniFile* f, const char* key ); + +/* returns a copy of the value of a given key, or NULL + */ +char* iniFile_getString( IniFile* f, const char* key ); + +/* returns an integer value, or a default in case the value string is + * missing or badly formatted + */ +int iniFile_getInteger( IniFile* f, const char* key, int defaultValue ); + +/* returns a double value, or a default in case the value string is + * missing or badly formatted + */ +double iniFile_getDouble( IniFile* f, const char* key, double defaultValue ); + +/* returns a copy of a given key's value, if any, or NULL if it is missing + * caller must call free() to release it */ +char* iniFile_getString( IniFile* f, const char* key ); + +/* parses a key value as a boolean. Accepted values are "1", "0", "yes", "YES", + * "no" and "NO". Returns either 1 or 0. + * note that the default value must be provided as a string too + */ +int iniFile_getBoolean( IniFile* f, const char* key, const char* defaultValue ); + +/* parses a key value as a disk size. this means it can be an integer followed + * by a suffix that can be one of "mMkKgG" which correspond to KiB, MiB and GiB + * multipliers. + * + * NOTE: we consider that 1K = 1024, not 1000. + */ +int64_t iniFile_getDiskSize( IniFile* f, const char* key, const char* defaultValue ); + +/* */ + +#endif /* _ANDROID_UTILS_INI_H */ |