aboutsummaryrefslogtreecommitdiffstats
path: root/android/utils
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:04:49 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:04:49 -0800
commitdf7881f07f53b041dc0568be8528e9dbb74994cc (patch)
tree1b3e036f7df4241bf0c2d527b73198c50e1d7891 /android/utils
parent55f4e4a5ec657a017e3bf75299ad71fd1c968dd3 (diff)
downloadexternal_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.h18
-rw-r--r--android/utils/dirscanner.c203
-rw-r--r--android/utils/dirscanner.h25
-rw-r--r--android/utils/ini.c366
-rw-r--r--android/utils/ini.h121
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 */