Merge commit 'goog/master' into merge_master
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b25c15b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*~
diff --git a/adb/adb.c b/adb/adb.c
index 0b5ebac..956df54 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -23,6 +23,7 @@
 #include <errno.h>
 #include <string.h>
 #include <time.h>
+#include <sys/time.h>
 
 #include "sysdeps.h"
 #include "adb.h"
@@ -657,10 +658,25 @@
 void start_device_log(void)
 {
     int fd;
-    char    path[100];
+    char    path[PATH_MAX];
+    struct tm now;
+    time_t t;
+    char value[PROPERTY_VALUE_MAX];
 
-    snprintf(path, sizeof path, "/data/adb_%ld.txt", (long)time(NULL));
-    fd = unix_open(path, O_WRONLY | O_CREAT | O_APPEND, 0640);
+    // read the trace mask from persistent property persist.adb.trace_mask
+    // give up if the property is not set or cannot be parsed
+    property_get("persist.adb.trace_mask", value, "");
+    if (sscanf(value, "%x", &adb_trace_mask) != 1)
+        return;
+
+    adb_mkdir("/data/adb", 0775);
+    tzset();
+    time(&t);
+    localtime_r(&t, &now);
+    strftime(path, sizeof(path),
+                "/data/adb/adb-%Y-%m-%d-%H-%M-%S.txt",
+                &now);
+    fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0640);
     if (fd < 0)
         return;
 
@@ -671,11 +687,6 @@
 
     fd = unix_open("/dev/null", O_RDONLY);
     dup2(fd, 0);
-
-    // log everything
-    adb_trace_mask = ~0;
-    // except TRACE_RWX is a bit too verbose
-    adb_trace_mask &= ~TRACE_RWX;
 }
 #endif
 
@@ -875,9 +886,10 @@
         ** AID_INET to diagnose network issues (netcfg, ping)
         ** AID_GRAPHICS to access the frame buffer
         ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
+        ** AID_SDCARD_RW to allow writing to the SD card
         */
         gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS,
-                           AID_NET_BT, AID_NET_BT_ADMIN };
+                           AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_RW };
         setgroups(sizeof(groups)/sizeof(groups[0]), groups);
 
         /* then switch user and group to "shell" */
@@ -919,9 +931,6 @@
     fdevent_loop();
 
     usb_cleanup();
-#if ADB_HOST
-    usb_vendors_cleanup();
-#endif
 
     return 0;
 }
@@ -1081,9 +1090,8 @@
         adb_device_banner = "recovery";
         recovery_mode = 1;
     }
-#if ADB_DEVICE_LOG
+
     start_device_log();
-#endif
     return adb_main(0);
 #endif
 }
diff --git a/adb/adb.h b/adb/adb.h
index 7762e00..b9ed556 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -345,11 +345,6 @@
 #endif
 
 
-/* set this to log to /data/adb/adb_<time>.txt on the device.
- * has no effect if the /data/adb/ directory does not exist.
- */
-#define ADB_DEVICE_LOG 0
-
 #if !TRACE_PACKETS
 #define print_packet(tag,p) do {} while (0)
 #endif
@@ -357,11 +352,10 @@
 #define ADB_PORT 5037
 #define ADB_LOCAL_TRANSPORT_PORT 5555
 
-// Google's USB Vendor ID
-#define VENDOR_ID_GOOGLE        0x18d1
+#define ADB_CLASS              0xff
+#define ADB_SUBCLASS           0x42
+#define ADB_PROTOCOL           0x1
 
-// HTC's USB Vendor ID
-#define VENDOR_ID_HTC           0x0bb4
 
 void local_init();
 int  local_connect(int  port);
diff --git a/adb/adb_client.c b/adb/adb_client.c
index 5868744..243f0fa 100644
--- a/adb/adb_client.c
+++ b/adb/adb_client.c
@@ -213,7 +213,7 @@
             fprintf(stdout,"* daemon started successfully *\n");
         }
         /* give the server some time to start properly and detect devices */
-        adb_sleep_ms(2000);
+        adb_sleep_ms(3000);
         // fall through to _adb_connect
     } else {
         // if server was running, check its version to make sure it is not out of date
diff --git a/adb/transport_usb.c b/adb/transport_usb.c
index 50ebff7..3737c5c 100644
--- a/adb/transport_usb.c
+++ b/adb/transport_usb.c
@@ -135,11 +135,9 @@
     unsigned i;
     for (i = 0; i < vendorIdCount; i++) {
         if (vid == vendorIds[i]) {
-            /* class:vendor (0xff) subclass:android (0x42) proto:adb (0x01) */
-            if(usb_class == 0xff) {
-                if((usb_subclass == 0x42) && (usb_protocol == 0x01)) {
-                    return 1;
-                }
+            if (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS &&
+                    usb_protocol == ADB_PROTOCOL) {
+                return 1;
             }
 
             return 0;
diff --git a/adb/usb_osx.c b/adb/usb_osx.c
index 171a9fc..4892c38 100644
--- a/adb/usb_osx.c
+++ b/adb/usb_osx.c
@@ -32,9 +32,6 @@
 
 #define  DBG   D
 
-#define ADB_SUBCLASS           0x42
-#define ADB_PROTOCOL           0x1
-
 static IONotificationPortRef    notificationPort = 0;
 static io_iterator_t*           notificationIterators;
 
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index f949249..9a15146 100644
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -16,25 +16,119 @@
 
 #include "usb_vendors.h"
 
-#include "sysdeps.h"
 #include <stdio.h>
+
+#ifdef _WIN32
+#  define WIN32_LEAN_AND_MEAN
+#  include "windows.h"
+#  include "shlobj.h"
+#else
+#  include <unistd.h>
+#  include <sys/stat.h>
+#endif
+
+#include "sysdeps.h"
 #include "adb.h"
 
-int* vendorIds = NULL;
+#define ANDROID_PATH            ".android"
+#define ANDROID_ADB_INI         "adb_usb.ini"
+
+#define TRACE_TAG               TRACE_USB
+
+// Google's USB Vendor ID
+#define VENDOR_ID_GOOGLE        0x18d1
+// HTC's USB Vendor ID
+#define VENDOR_ID_HTC           0x0bb4
+
+/** built-in vendor list */
+int builtInVendorIds[] = {
+    VENDOR_ID_GOOGLE,
+    VENDOR_ID_HTC,
+};
+
+#define BUILT_IN_VENDOR_COUNT    (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
+
+/* max number of supported vendor ids (built-in + 3rd party). increase as needed */
+#define VENDOR_COUNT_MAX         128
+
+int vendorIds[VENDOR_COUNT_MAX];
 unsigned vendorIdCount = 0;
 
-void usb_vendors_init(void) {
-    /* for now, only put the built-in VENDOR_ID_* */
-    vendorIdCount = 2;
-    vendorIds = (int*)malloc(vendorIdCount * sizeof(int));
-    vendorIds[0] = VENDOR_ID_GOOGLE;
-    vendorIds[1] = VENDOR_ID_HTC;
+int get_adb_usb_ini(char* buff, size_t len);
+
+void usb_vendors_init(void)
+{
+    if (VENDOR_COUNT_MAX < BUILT_IN_VENDOR_COUNT) {
+        fprintf(stderr, "VENDOR_COUNT_MAX not big enough for built-in vendor list.\n");
+        exit(2);
+    }
+
+    /* add the built-in vendors at the beginning of the array */
+    memcpy(vendorIds, builtInVendorIds, sizeof(builtInVendorIds));
+
+    /* default array size is the number of built-in vendors */
+    vendorIdCount = BUILT_IN_VENDOR_COUNT;
+
+    if (VENDOR_COUNT_MAX == BUILT_IN_VENDOR_COUNT)
+        return;
+
+    char temp[PATH_MAX];
+    if (get_adb_usb_ini(temp, sizeof(temp)) == 0) {
+        FILE * f = fopen(temp, "rt");
+
+        if (f != NULL) {
+            /* The vendor id file is pretty basic. 1 vendor id per line.
+               Lines starting with # are comments */
+            while (fgets(temp, sizeof(temp), f) != NULL) {
+                if (temp[0] == '#')
+                    continue;
+
+                long value = strtol(temp, NULL, 0);
+                if (errno == EINVAL || errno == ERANGE || value > INT_MAX || value < 0) {
+                    fprintf(stderr, "Invalid content in %s. Quitting.\n", ANDROID_ADB_INI);
+                    exit(2);
+                }
+
+                vendorIds[vendorIdCount++] = (int)value;
+
+                /* make sure we don't go beyond the array */
+                if (vendorIdCount == VENDOR_COUNT_MAX) {
+                    break;
+                }
+            }
+        }
+    }
 }
 
-void usb_vendors_cleanup(void) {
-    if (vendorIds != NULL) {
-        free(vendorIds);
-        vendorIds = NULL;
-        vendorIdCount = 0;
+/* Utils methods */
+
+/* builds the path to the adb vendor id file. returns 0 if success */
+int build_path(char* buff, size_t len, const char* format, const char* home)
+{
+    if (snprintf(buff, len, format, home, ANDROID_PATH, ANDROID_ADB_INI) >= len) {
+        return 1;
     }
+
+    return 0;
+}
+
+/* fills buff with the path to the adb vendor id file. returns 0 if success */
+int get_adb_usb_ini(char* buff, size_t len)
+{
+#ifdef _WIN32
+    const char* home = getenv("ANDROID_SDK_HOME");
+    if (home != NULL) {
+        return build_path(buff, len, "%s\\%s\\%s", home);
+    } else {
+        char path[MAX_PATH];
+        SHGetFolderPath( NULL, CSIDL_PROFILE, NULL, 0, path);
+        return build_path(buff, len, "%s\\%s\\%s", path);
+    }
+#else
+    const char* home = getenv("HOME");
+    if (home == NULL)
+        home = "/tmp";
+
+    return build_path(buff, len, "%s/%s/%s", home);
+#endif
 }
diff --git a/adb/usb_vendors.h b/adb/usb_vendors.h
index 43e5f99..43790b9 100644
--- a/adb/usb_vendors.h
+++ b/adb/usb_vendors.h
@@ -17,10 +17,9 @@
 #ifndef __USB_VENDORS_H
 #define __USB_VENDORS_H
 
-extern int* vendorIds;
+extern int vendorIds[];
 extern unsigned  vendorIdCount;
 
 void usb_vendors_init(void);
-void usb_vendors_cleanup(void);
 
 #endif
\ No newline at end of file
diff --git a/include/acc/acc.h b/include/acc/acc.h
new file mode 100644
index 0000000..054d6a0
--- /dev/null
+++ b/include/acc/acc.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_ACC_ACC_H
+#define ANDROID_ACC_ACC_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+typedef char                        ACCchar;
+typedef int32_t                     ACCint;
+typedef uint32_t                    ACCuint;
+typedef ssize_t                     ACCsizei;
+typedef unsigned int                ACCenum;
+typedef void                        ACCvoid;
+typedef struct ACCscript            ACCscript;
+
+#define ACC_NO_ERROR                0x0000
+#define ACC_INVALID_ENUM            0x0500
+#define ACC_INVALID_OPERATION       0x0502
+#define ACC_INVALID_VALUE           0x0501
+#define ACC_OUT_OF_MEMORY           0x0505
+
+#define ACC_COMPILE_STATUS          0x8B81
+#define ACC_INFO_LOG_LENGTH         0x8B84
+
+
+// ----------------------------------------------------------------------------
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ACCscript* accCreateScript();
+
+void accDeleteScript(ACCscript* script);
+
+ACCenum accGetError( ACCscript* script );
+
+void accScriptSource(ACCscript* script,
+    ACCsizei count,
+    const ACCchar** string,
+    const ACCint* length);
+
+void accCompileScript(ACCscript* script);
+
+void accGetScriptiv(ACCscript* script,
+    ACCenum pname,
+    ACCint* params);
+
+void accGetScriptInfoLog(ACCscript* script,
+    ACCsizei maxLength,
+    ACCsizei* length,
+    ACCchar* infoLog);
+
+void accGetScriptLabel(ACCscript* script, const ACCchar * name,
+                       ACCvoid** address);
+
+#ifdef __cplusplus
+};
+#endif
+
+// ----------------------------------------------------------------------------
+
+#endif
diff --git a/init/devices.c b/init/devices.c
index 300faab..04ada63 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -115,6 +115,7 @@
     { "/dev/oncrpc/",       0660,   AID_ROOT,       AID_SYSTEM,     1 },
     { "/dev/adsp/",         0660,   AID_SYSTEM,     AID_AUDIO,      1 },
     { "/dev/mt9t013",       0660,   AID_SYSTEM,     AID_SYSTEM,     0 },
+    { "/dev/msm_camera/",   0660,   AID_SYSTEM,     AID_SYSTEM,     1 },
     { "/dev/akm8976_daemon",0640,   AID_COMPASS,    AID_SYSTEM,     0 },
     { "/dev/akm8976_aot",   0640,   AID_COMPASS,    AID_SYSTEM,     0 },
     { "/dev/akm8976_pffd",  0640,   AID_COMPASS,    AID_SYSTEM,     0 },
@@ -384,7 +385,10 @@
         } else if (!strncmp(uevent->subsystem, "adsp", 4)) {
             base = "/dev/adsp/";
             mkdir(base, 0755);
-      } else if(!strncmp(uevent->subsystem, "input", 5)) {
+        } else if (!strncmp(uevent->subsystem, "msm_camera", 10)) {
+            base = "/dev/msm_camera/";
+            mkdir(base, 0755);
+        } else if(!strncmp(uevent->subsystem, "input", 5)) {
             base = "/dev/input/";
             mkdir(base, 0755);
         } else if(!strncmp(uevent->subsystem, "mtd", 3)) {
diff --git a/libacc/Android.mk b/libacc/Android.mk
index c3207cc..77c71c6 100644
--- a/libacc/Android.mk
+++ b/libacc/Android.mk
@@ -5,8 +5,15 @@
 # Shared library
 #
 
-LOCAL_MODULE:= acc
-LOCAL_SRC_FILES := acc.cpp disassem.cpp
-LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE:= libacc
+LOCAL_SRC_FILES := acc.cpp
 
-include $(BUILD_EXECUTABLE)
+ifeq ($(TARGET_ARCH),arm)
+LOCAL_SRC_FILES += disassem.cpp
+endif
+
+LOCAL_SHARED_LIBRARIES := libdl
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/libacc/LICENSE b/libacc/LICENSE
new file mode 100644
index 0000000..aea41e0
--- /dev/null
+++ b/libacc/LICENSE
@@ -0,0 +1,21 @@
+ Obfuscated Tiny C Compiler
+
+ Copyright (C) 2001-2003 Fabrice Bellard
+
+ This software is provided 'as-is', without any express or implied
+ warranty.  In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product and its documentation
+ *is* required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+
diff --git a/libacc/acc.cpp b/libacc/acc.cpp
index 04d45d5..b7e4594 100644
--- a/libacc/acc.cpp
+++ b/libacc/acc.cpp
@@ -4,33 +4,10 @@
  * in scripting environments where speed and memory footprint are important.
  *
  * This code is based upon the "unobfuscated" version of the
- * Obfuscated Tiny C compiler, and retains the
- * original copyright notice and license from that compiler, see below.
+ * Obfuscated Tiny C compiler, see the file LICENSE for details.
  *
  */
 
-/*
- Obfuscated Tiny C Compiler
-
- Copyright (C) 2001-2003 Fabrice Bellard
-
- This software is provided 'as-is', without any express or implied
- warranty.  In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product and its documentation
- *is* required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
- */
-
 #include <ctype.h>
 #include <dlfcn.h>
 #include <stdarg.h>
@@ -59,6 +36,13 @@
 #include "disassem.h"
 #endif
 
+#include <acc/acc.h>
+
+#define LOG_API(...) do {} while(0)
+// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
+
+// #define ENABLE_ARM_DISASSEMBLY
+
 namespace acc {
 
 class Compiler {
@@ -116,6 +100,27 @@
         }
     };
 
+    /**
+     * A code generator creates an in-memory program, generating the code on
+     * the fly. There is one code generator implementation for each supported
+     * architecture.
+     *
+     * The code generator implements the following abstract machine:
+     * R0 - the main accumulator.
+     * R1 - the secondary accumulator.
+     * FP - a frame pointer for accessing function arguments and local
+     *      variables.
+     * SP - a stack pointer for storing intermediate results while evaluating
+     *      expressions. The stack pointer grows downwards.
+     *
+     * The function calling convention is that all arguments are placed on the
+     * stack such that the first argument has the lowest address.
+     * After the call, the result is in R0. The caller is responsible for
+     * removing the arguments from the stack.
+     * The R0 and R1 registers are not saved across function calls. The
+     * FP and SP registers are saved.
+     */
+
     class CodeGenerator {
     public:
         CodeGenerator() {}
@@ -125,70 +130,170 @@
             this->pCodeBuf = pCodeBuf;
         }
 
-        /* returns address to patch with local variable size
+        /* Emit a function prolog.
+         * argCount is the number of arguments.
+         * Save the old value of the FP.
+         * Set the new value of the FP.
+         * Convert from the native platform calling convention to
+         * our stack-based calling convention. This may require
+         * pushing arguments from registers to the stack.
+         * Allocate "N" bytes of stack space. N isn't known yet, so
+         * just emit the instructions for adjusting the stack, and return
+         * the address to patch up. The patching will be done in
+         * functionExit().
+         * returns address to patch with local variable size.
         */
         virtual int functionEntry(int argCount) = 0;
 
-        virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) = 0;
+        /* Emit a function epilog.
+         * Restore the old SP and FP register values.
+         * Return to the calling function.
+         * argCount - the number of arguments to the function.
+         * localVariableAddress - returned from functionEntry()
+         * localVariableSize - the size in bytes of the local variables.
+         */
+        virtual void functionExit(int argCount, int localVariableAddress,
+                                  int localVariableSize) = 0;
 
-        /* load immediate value */
+        /* load immediate value to R0 */
         virtual void li(int t) = 0;
 
+        /* Jump to a target, and return the address of the word that
+         * holds the target data, in case it needs to be fixed up later.
+         */
         virtual int gjmp(int t) = 0;
 
-        /* l = 0: je, l == 1: jne */
+        /* Test R0 and jump to a target if the test succeeds.
+         * l = 0: je, l == 1: jne
+         * Return the address of the word that holds the targed data, in
+         * case it needs to be fixed up later.
+         */
         virtual int gtst(bool l, int t) = 0;
 
+        /* Compare R1 against R0, and store the boolean result in R0.
+         * op specifies the comparison.
+         */
         virtual void gcmp(int op) = 0;
 
+        /* Perform the arithmetic op specified by op. R1 is the
+         * left argument, R0 is the right argument.
+         */
         virtual void genOp(int op) = 0;
 
-        virtual void clearECX() = 0;
+        /* Set R1 to 0.
+         */
+        virtual void clearR1() = 0;
 
-        virtual void pushEAX() = 0;
+        /* Push R0 onto the stack.
+         */
+        virtual void pushR0() = 0;
 
-        virtual void popECX() = 0;
+        /* Pop R1 off of the stack.
+         */
+        virtual void popR1() = 0;
 
-        virtual void storeEAXToAddressECX(bool isInt) = 0;
+        /* Store R0 to the address stored in R1.
+         * isInt is true if a whole 4-byte integer value
+         * should be stored, otherwise a 1-byte character
+         * value should be stored.
+         */
+        virtual void storeR0ToR1(bool isInt) = 0;
 
-        virtual void loadEAXIndirect(bool isInt) = 0;
+        /* Load R0 from the address stored in R0.
+         * isInt is true if a whole 4-byte integer value
+         * should be loaded, otherwise a 1-byte character
+         * value should be loaded.
+         */
+        virtual void loadR0FromR0(bool isInt) = 0;
 
-        virtual void leaEAX(int ea) = 0;
+        /* Load the absolute address of a variable to R0.
+         * If ea <= LOCAL, then this is a local variable, or an
+         * argument, addressed relative to FP.
+         * else it is an absolute global address.
+         */
+        virtual void leaR0(int ea) = 0;
 
-        virtual void storeEAX(int ea) = 0;
+        /* Store R0 to a variable.
+         * If ea <= LOCAL, then this is a local variable, or an
+         * argument, addressed relative to FP.
+         * else it is an absolute global address.
+         */
+        virtual void storeR0(int ea) = 0;
 
-        virtual void loadEAX(int ea, bool isIncDec, int op) = 0;
+        /* load R0 from a variable.
+         * If ea <= LOCAL, then this is a local variable, or an
+         * argument, addressed relative to FP.
+         * else it is an absolute global address.
+         * If isIncDec is true, then the stored variable's value
+         * should be post-incremented or post-decremented, based
+         * on the value of op.
+         */
+        virtual void loadR0(int ea, bool isIncDec, int op) = 0;
 
+        /* Emit code to adjust the stack for a function call. Return the
+         * label for the address of the instruction that adjusts the
+         * stack size. This will be passed as argument "a" to
+         * endFunctionCallArguments.
+         */
         virtual int beginFunctionCallArguments() = 0;
 
-        virtual void storeEAToArg(int l) = 0;
+        /* Emit code to store R0 to the stack at byte offset l.
+         */
+        virtual void storeR0ToArg(int l) = 0;
 
+        /* Patch the function call preamble.
+         * a is the address returned from beginFunctionCallArguments
+         * l is the number of bytes the arguments took on the stack.
+         * Typically you would also emit code to convert the argument
+         * list into whatever the native function calling convention is.
+         * On ARM for example you would pop the first 5 arguments into
+         * R0..R4
+         */
         virtual void endFunctionCallArguments(int a, int l) = 0;
 
-
+        /* Emit a call to an unknown function. The argument "symbol" needs to
+         * be stored in the location where the address should go. It forms
+         * a chain. The address will be patched later.
+         * Return the address of the word that has to be patched.
+         */
         virtual int callForward(int symbol) = 0;
 
+        /* Call a function using PC-relative addressing. t is the PC-relative
+         * address of the function. It has already been adjusted for the
+         * architectural jump offset, so just store it as-is.
+         */
         virtual void callRelative(int t) = 0;
 
+        /* Call a function pointer. L is the number of bytes the arguments
+         * take on the stack. The address of the function is stored at
+         * location SP + l.
+         */
         virtual void callIndirect(int l) = 0;
 
+        /* Adjust SP after returning from a function call. l is the
+         * number of bytes of arguments stored on the stack. isIndirect
+         * is true if this was an indirect call. (In which case the
+         * address of the function is stored at location SP + l.)
+         */
         virtual void adjustStackAfterCall(int l, bool isIndirect) = 0;
 
+        /* Print a disassembly of the assembled code to out. Return
+         * non-zero if there is an error.
+         */
         virtual int disassemble(FILE* out) = 0;
 
-        /* output a symbol and patch all calls to it */
+        /* Generate a symbol at the current PC. t is the head of a
+         * linked list of addresses to patch.
+         */
         virtual void gsym(int t) = 0;
 
-        virtual int finishCompile() {
-#if defined(__arm__)
-            const long base = long(pCodeBuf->getBase());
-            const long curr = base + long(pCodeBuf->getSize());
-            int err = cacheflush(base, curr, 0);
-            return err;
-#else
-            return 0;
-#endif
-        }
+        /*
+         * Do any cleanup work required at the end of a compile.
+         * For example, an instruction cache might need to be
+         * invalidated.
+         * Return non-zero if there is an error.
+         */
+        virtual int finishCompile() = 0;
 
         /**
          * Adjust relative branches by this amount.
@@ -214,6 +319,10 @@
         intptr_t getPC() {
             return pCodeBuf->getPC();
         }
+
+        intptr_t getSize() {
+            return pCodeBuf->getSize();
+        }
     private:
         CodeBuf* pCodeBuf;
     };
@@ -228,7 +337,7 @@
         /* returns address to patch with local variable size
         */
         virtual int functionEntry(int argCount) {
-            fprintf(stderr, "functionEntry(%d);\n", argCount);
+            LOG_API(stderr, "functionEntry(%d);\n", argCount);
             // sp -> arg4 arg5 ...
             // Push our register-based arguments back on the stack
             if (argCount > 0) {
@@ -243,7 +352,7 @@
         }
 
         virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
-            fprintf(stderr, "functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
+            LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
             // Patch local variable allocation code:
             if (localVariableSize < 0 || localVariableSize > 255) {
                 error("localVariables out of range: %d", localVariableSize);
@@ -270,7 +379,7 @@
 
         /* load immediate value */
         virtual void li(int t) {
-            fprintf(stderr, "li(%d);\n", t);
+            LOG_API("li(%d);\n", t);
             if (t >= 0 && t < 255) {
                  o4(0xE3A00000 + t); // mov    r0, #0
             } else if (t >= -256 && t < 0) {
@@ -285,20 +394,20 @@
         }
 
         virtual int gjmp(int t) {
-            fprintf(stderr, "gjmp(%d);\n", t);
+            LOG_API("gjmp(%d);\n", t);
             return o4(0xEA000000 | encodeAddress(t)); // b .L33
         }
 
         /* l = 0: je, l == 1: jne */
         virtual int gtst(bool l, int t) {
-            fprintf(stderr, "gtst(%d, %d);\n", l, t);
+            LOG_API("gtst(%d, %d);\n", l, t);
             o4(0xE3500000); // cmp r0,#0
             int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
             return o4(branch | encodeAddress(t));
         }
 
         virtual void gcmp(int op) {
-            fprintf(stderr, "gcmp(%d);\n", op);
+            LOG_API("gcmp(%d);\n", op);
             o4(0xE1510000); // cmp r1, r1
             switch(op) {
             case OP_EQUALS:
@@ -332,7 +441,7 @@
         }
 
         virtual void genOp(int op) {
-            fprintf(stderr, "genOp(%d);\n", op);
+            LOG_API("genOp(%d);\n", op);
             switch(op) {
             case OP_MUL:
                 o4(0x0E0000091); // mul     r0,r1,r0
@@ -378,23 +487,23 @@
 #endif
         }
 
-        virtual void clearECX() {
-            fprintf(stderr, "clearECX();\n");
+        virtual void clearR1() {
+            LOG_API("clearR1();\n");
             o4(0xE3A01000);  // mov    r1, #0
         }
 
-        virtual void pushEAX() {
-            fprintf(stderr, "pushEAX();\n");
+        virtual void pushR0() {
+            LOG_API("pushR0();\n");
             o4(0xE92D0001);  // stmfd   sp!,{r0}
         }
 
-        virtual void popECX() {
-            fprintf(stderr, "popECX();\n");
+        virtual void popR1() {
+            LOG_API("popR1();\n");
             o4(0xE8BD0002);  // ldmfd   sp!,{r1}
         }
 
-        virtual void storeEAXToAddressECX(bool isInt) {
-            fprintf(stderr, "storeEAXToAddressECX(%d);\n", isInt);
+        virtual void storeR0ToR1(bool isInt) {
+            LOG_API("storeR0ToR1(%d);\n", isInt);
             if (isInt) {
                 o4(0xE5810000); // str r0, [r1]
             } else {
@@ -402,16 +511,16 @@
             }
         }
 
-        virtual void loadEAXIndirect(bool isInt) {
-            fprintf(stderr, "loadEAXIndirect(%d);\n", isInt);
+        virtual void loadR0FromR0(bool isInt) {
+            LOG_API("loadR0FromR0(%d);\n", isInt);
             if (isInt)
                 o4(0xE5900000); // ldr r0, [r0]
             else
                 o4(0xE5D00000); // ldrb r0, [r0]
         }
 
-        virtual void leaEAX(int ea) {
-            fprintf(stderr, "leaEAX(%d);\n", ea);
+        virtual void leaR0(int ea) {
+            LOG_API("leaR0(%d);\n", ea);
             if (ea < LOCAL) {
                 // Local, fp relative
                 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
@@ -431,8 +540,8 @@
             }
         }
 
-        virtual void storeEAX(int ea) {
-            fprintf(stderr, "storeEAX(%d);\n", ea);
+        virtual void storeR0(int ea) {
+            LOG_API("storeR0(%d);\n", ea);
             if (ea < LOCAL) {
                 // Local, fp relative
                 if (ea < -4095 || ea > 4095) {
@@ -452,8 +561,8 @@
             }
         }
 
-        virtual void loadEAX(int ea, bool isIncDec, int op) {
-            fprintf(stderr, "loadEAX(%d, %d, %d);\n", ea, isIncDec, op);
+        virtual void loadR0(int ea, bool isIncDec, int op) {
+            LOG_API("loadR0(%d, %d, %d);\n", ea, isIncDec, op);
             if (ea < LOCAL) {
                 // Local, fp relative
                 if (ea < -4095 || ea > 4095) {
@@ -500,12 +609,12 @@
         }
 
         virtual int beginFunctionCallArguments() {
-            fprintf(stderr, "beginFunctionCallArguments();\n");
+            LOG_API("beginFunctionCallArguments();\n");
             return o4(0xE24DDF00); // Placeholder
         }
 
-        virtual void storeEAToArg(int l) {
-            fprintf(stderr, "storeEAToArg(%d);\n", l);
+        virtual void storeR0ToArg(int l) {
+            LOG_API("storeR0ToArg(%d);\n", l);
             if (l < 0 || l > 4096-4) {
                 error("l out of range for stack offset: 0x%08x", l);
             }
@@ -513,7 +622,7 @@
         }
 
         virtual void endFunctionCallArguments(int a, int l) {
-            fprintf(stderr, "endFunctionCallArguments(0x%08x, %d);\n", a, l);
+            LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
             if (l < 0 || l > 0x3FC) {
                 error("L out of range for stack adjustment: 0x%08x", l);
             }
@@ -526,13 +635,13 @@
         }
 
         virtual int callForward(int symbol) {
-            fprintf(stderr, "callForward(%d);\n", symbol);
+            LOG_API("callForward(%d);\n", symbol);
             // Forward calls are always short (local)
             return o4(0xEB000000 | encodeAddress(symbol));
         }
 
         virtual void callRelative(int t) {
-            fprintf(stderr, "callRelative(%d);\n", t);
+            LOG_API("callRelative(%d);\n", t);
             int abs = t + getPC() + jumpOffset();
             fprintf(stderr, "abs=%d (0x%08x)\n", abs, abs);
             if (t >= - (1 << 25) && t < (1 << 25)) {
@@ -548,7 +657,7 @@
         }
 
         virtual void callIndirect(int l) {
-            fprintf(stderr, "callIndirect(%d);\n", l);
+            LOG_API("callIndirect(%d);\n", l);
             int argCount = l >> 2;
             int poppedArgs = argCount > 4 ? 4 : argCount;
             int adjustedL = l - (poppedArgs << 2);
@@ -560,7 +669,7 @@
         }
 
         virtual void adjustStackAfterCall(int l, bool isIndirect) {
-            fprintf(stderr, "adjustStackAfterCall(%d, %d);\n", l, isIndirect);
+            LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
             int argCount = l >> 2;
             int stackArgs = argCount > 4 ? argCount - 4 : 0;
             int stackUse = stackArgs + (isIndirect ? 1 : 0);
@@ -578,11 +687,11 @@
 
         /* output a symbol and patch all calls to it */
         virtual void gsym(int t) {
-            fprintf(stderr, "gsym(0x%x)\n", t);
+            LOG_API("gsym(0x%x)\n", t);
             int n;
             int base = getBase();
             int pc = getPC();
-            fprintf(stderr, "pc = 0x%x\n", pc);
+            LOG_API("pc = 0x%x\n", pc);
             while (t) {
                 int data = * (int*) t;
                 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
@@ -597,8 +706,20 @@
             }
         }
 
+        virtual int finishCompile() {
+#if defined(__arm__)
+            const long base = long(getBase());
+            const long curr = long(getPC());
+            int err = cacheflush(base, curr, 0);
+            return err;
+#else
+            return 0;
+#endif
+        }
+
         virtual int disassemble(FILE* out) {
-               disasmOut = out;
+#ifdef ENABLE_ARM_DISASSEMBLY
+            disasmOut = out;
             disasm_interface_t  di;
             di.di_readword = disassemble_readword;
             di.di_printaddr = disassemble_printaddr;
@@ -610,6 +731,7 @@
                 fprintf(out, "%08x: %08x  ", i, *(int*) i);
                 ::disasm(&di, i, 0);
             }
+#endif
             return 0;
         }
 
@@ -679,7 +801,7 @@
         }
     };
 
-#endif // PROVIDE_X86_CODEGEN
+#endif // PROVIDE_ARM_CODEGEN
 
 #ifdef PROVIDE_X86_CODEGEN
 
@@ -730,23 +852,23 @@
                 o(0x92); /* xchg %edx, %eax */
         }
 
-        virtual void clearECX() {
+        virtual void clearR1() {
             oad(0xb9, 0); /* movl $0, %ecx */
         }
 
-        virtual void pushEAX() {
+        virtual void pushR0() {
             o(0x50); /* push %eax */
         }
 
-        virtual void popECX() {
+        virtual void popR1() {
             o(0x59); /* pop %ecx */
         }
 
-        virtual void storeEAXToAddressECX(bool isInt) {
+        virtual void storeR0ToR1(bool isInt) {
             o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */
         }
 
-        virtual void loadEAXIndirect(bool isInt) {
+        virtual void loadR0FromR0(bool isInt) {
             if (isInt)
                 o(0x8b); /* mov (%eax), %eax */
             else
@@ -754,15 +876,15 @@
             ob(0); /* add zero in code */
         }
 
-        virtual void leaEAX(int ea) {
+        virtual void leaR0(int ea) {
             gmov(10, ea); /* leal EA, %eax */
         }
 
-        virtual void storeEAX(int ea) {
+        virtual void storeR0(int ea) {
             gmov(6, ea); /* mov %eax, EA */
         }
 
-        virtual void loadEAX(int ea, bool isIncDec, int op) {
+        virtual void loadR0(int ea, bool isIncDec, int op) {
             gmov(8, ea); /* mov EA, %eax */
             if (isIncDec) {
                 /* Implement post-increment or post decrement.
@@ -776,7 +898,7 @@
             return oad(0xec81, 0); /* sub $xxx, %esp */
         }
 
-        virtual void storeEAToArg(int l) {
+        virtual void storeR0ToArg(int l) {
             oad(0x248489, l); /* movl %eax, xxx(%esp) */
         }
 
@@ -808,7 +930,7 @@
         }
 
         virtual int disassemble(FILE* out) {
-            return 1;
+            return 0;
         }
 
         /* output a symbol and patch all calls to it */
@@ -822,6 +944,10 @@
             }
         }
 
+        virtual int finishCompile() {
+            return 0;
+        }
+
     private:
 
         /** Output 1 to 4 bytes.
@@ -868,6 +994,39 @@
 
 #endif // PROVIDE_X86_CODEGEN
 
+    class InputStream {
+    public:
+        virtual int get() = 0;
+        virtual long tell() = 0;
+    };
+
+    class FileInputStream : public InputStream {
+    public:
+        FileInputStream(FILE* in) : f(in) {}
+        virtual int get() { return fgetc(f); }
+        virtual long tell() { return ftell(f); }
+    private:
+        FILE* f;
+    };
+
+    class TextInputStream : public InputStream {
+    public:
+        TextInputStream(const char* text, size_t textLength)
+            : pText(text), mTextLength(textLength), mPosition(0) {
+        }
+        virtual int get() {
+            return mPosition < mTextLength ? pText[mPosition++] : EOF;
+        }
+        virtual long tell() {
+            return mPosition;
+        }
+
+    private:
+        const char* pText;
+        size_t mTextLength;
+        size_t mPosition;
+    };
+
     /* vars: value of variables
      loc : local variable index
      glo : global variable index
@@ -882,7 +1041,8 @@
     void* pSymbolBase;
     void* pGlobalBase;
     void* pVarsBase;
-    FILE* file;
+
+    InputStream* file;
 
     CodeBuf codeBuf;
     CodeGenerator* pGen;
@@ -957,7 +1117,7 @@
                 ch = dch;
             }
         } else
-            ch = fgetc(file);
+            ch = file->get();
         /*    printf("ch=%c 0x%x\n", ch, ch); */
     }
 
@@ -1108,7 +1268,7 @@
         va_list ap;
 
         va_start(ap, fmt);
-        fprintf(stderr, "%ld: ", ftell((FILE *) file));
+        fprintf(stderr, "%ld: ", file->tell());
         vfprintf(stderr, fmt, ap);
         fprintf(stderr, "\n");
         va_end(ap);
@@ -1149,7 +1309,7 @@
             } else if (c == 2) {
                 /* -, +, !, ~ */
                 unary(0);
-                pGen->clearECX();
+                pGen->clearR1();
                 if (t == '!')
                     pGen->gcmp(a);
                 else
@@ -1175,15 +1335,15 @@
                 unary(0);
                 if (tok == '=') {
                     next();
-                    pGen->pushEAX();
+                    pGen->pushR0();
                     expr();
-                    pGen->popECX();
-                    pGen->storeEAXToAddressECX(t == TOK_INT);
+                    pGen->popR1();
+                    pGen->storeR0ToR1(t == TOK_INT);
                 } else if (t) {
-                    pGen->loadEAXIndirect(t == TOK_INT);
+                    pGen->loadR0FromR0(t == TOK_INT);
                 }
             } else if (t == '&') {
-                pGen->leaEAX(*(int *) tok);
+                pGen->leaR0(*(int *) tok);
                 next();
             } else {
                 n = *(int *) t;
@@ -1195,10 +1355,10 @@
                     /* assignment */
                     next();
                     expr();
-                    pGen->storeEAX(n);
+                    pGen->storeR0(n);
                 } else if (tok != '(') {
                     /* variable */
-                    pGen->loadEAX(n, tokl == 11, tokc);
+                    pGen->loadR0(n, tokl == 11, tokc);
                     if (tokl == 11) {
                         next();
                     }
@@ -1209,7 +1369,7 @@
         /* function call */
         if (tok == '(') {
             if (n == 1)
-                pGen->pushEAX();
+                pGen->pushR0();
 
             /* push args and invert order */
             a = pGen->beginFunctionCallArguments();
@@ -1217,7 +1377,7 @@
             l = 0;
             while (tok != ')') {
                 expr();
-                pGen->storeEAToArg(l);
+                pGen->storeR0ToArg(l);
                 if (tok == ',')
                     next();
                 l = l + 4;
@@ -1255,9 +1415,9 @@
                     a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
                     sum(l);
                 } else {
-                    pGen->pushEAX();
+                    pGen->pushR0();
                     sum(l);
-                    pGen->popECX();
+                    pGen->popR1();
 
                     if ((l == 4) | (l == 5)) {
                         pGen->gcmp(t);
@@ -1420,6 +1580,10 @@
             delete pGen;
             pGen = 0;
         }
+        if (file) {
+            delete file;
+            file = 0;
+        }
     }
 
     void clear() {
@@ -1470,7 +1634,7 @@
 #endif
         }
         if (pGen == NULL) {
-            fprintf(stderr, "No code generator defined.");
+            fprintf(stderr, "No code generator defined.\n");
         }
     }
 
@@ -1490,16 +1654,16 @@
         cleanup();
     }
 
-    int compile(FILE* in, args& args) {
+    int compile(const char* text, size_t textLength) {
         cleanup();
         clear();
         codeBuf.init(ALLOC_SIZE);
-        setArchitecture(args.architecture);
+        setArchitecture(NULL);
         if (!pGen) {
             return -1;
         }
         pGen->init(&codeBuf);
-        file = in;
+        file = new TextInputStream(text, textLength);
         sym_stk = (intptr_t) calloc(1, ALLOC_SIZE);
         dstk = (intptr_t) strcpy((char*) sym_stk,
                 " int if else while break return for define main ")
@@ -1534,6 +1698,38 @@
         return pGen->disassemble(out);
     }
 
+    /* Look through the symbol table to find a symbol.
+     * If found, return its value.
+     */
+    void* lookup(const char* name) {
+        if (!sym_stk) {
+            return NULL;
+        }
+        size_t nameLen = strlen(name);
+        char* pSym = (char*) sym_stk;
+        char c;
+        for(;;) {
+            c = *pSym++;
+            if (c == 0) {
+                break;
+            }
+            if (c == TAG_TOK) {
+                if (memcmp(pSym, name, nameLen) == 0
+                        && pSym[nameLen] == TAG_TOK) {
+                    int tok = pSym - 1 - (char*) sym_stk;
+                    tok = tok * 8 + TOK_IDENT;
+                    if (tok <= TOK_DEFINE) {
+                        return 0;
+                    } else {
+                        tok = vars + tok;
+                        return * (void**) tok;
+                    }
+                }
+            }
+        }
+        return NULL;
+    }
+
 };
 
 const char* Compiler::operatorChars =
@@ -1578,96 +1774,130 @@
 };
 #endif
 
-} // namespace acc
+struct ACCscript {
+    ACCscript() {
+        text = 0;
+        textLength = 0;
+        accError = ACC_NO_ERROR;
+    }
 
-// This is a separate function so it can easily be set by breakpoint in gdb.
-int run(acc::Compiler& c, int argc, char** argv) {
-    return c.run(argc, argv);
-}
+    ~ACCscript() {
+        delete text;
+    }
 
-int main(int argc, char** argv) {
-    bool doDump = false;
-    bool doDisassemble = false;
-    const char* inFile = NULL;
-    const char* outFile = NULL;
-    const char* architecture = NULL;
-    int i;
-    for (i = 1; i < argc; i++) {
-        char* arg = argv[i];
-        if (arg[0] == '-') {
-            switch (arg[1]) {
-            case 'a':
-                if (i + 1 >= argc) {
-                    fprintf(stderr, "Expected architecture after -a\n");
-                    return 2;
-                }
-                architecture = argv[i+1];
-                i += 1;
-                break;
-            case 'd':
-                if (i + 1 >= argc) {
-                    fprintf(stderr, "Expected filename after -d\n");
-                    return 2;
-                }
-                doDump = true;
-                outFile = argv[i + 1];
-                i += 1;
-                break;
-            case 'S':
-                doDisassemble = true;
-                break;
-            default:
-                fprintf(stderr, "Unrecognized flag %s\n", arg);
-                return 3;
-            }
-        } else if (inFile == NULL) {
-            inFile = arg;
-        } else {
-            break;
+    void setError(ACCenum error) {
+        if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
+            accError = error;
         }
     }
 
-    FILE* in = stdin;
-    if (inFile) {
-        in = fopen(inFile, "r");
-        if (!in) {
-            fprintf(stderr, "Could not open input file %s\n", inFile);
-            return 1;
-        }
-    }
-    acc::Compiler compiler;
-    acc::Compiler::args args;
-    if (architecture != NULL) {
-        args.architecture = architecture;
-    }
-    int compileResult = compiler.compile(in, args);
-    if (in != stdin) {
-        fclose(in);
-    }
-    if (compileResult) {
-        fprintf(stderr, "Compile failed: %d\n", compileResult);
-        return 6;
-    }
-    if (doDisassemble) {
-        compiler.disassemble(stderr);
-    }
-    if (doDump) {
-        FILE* save = fopen(outFile, "w");
-        if (!save) {
-            fprintf(stderr, "Could not open output file %s\n", outFile);
-            return 5;
-        }
-        compiler.dump(save);
-        fclose(save);
-    } else {
-        fprintf(stderr, "Executing compiled code:\n");
-        int codeArgc = argc - i + 1;
-        char** codeArgv = argv + i - 1;
-        codeArgv[0] = (char*) (inFile ? inFile : "stdin");
-        int result = run(compiler, codeArgc, codeArgv);
-        fprintf(stderr, "result: %d\n", result);
+    ACCenum getError() {
+        ACCenum result = accError;
+        accError = ACC_NO_ERROR;
         return result;
     }
 
-    return 0;
+    Compiler compiler;
+    char* text;
+    int textLength;
+    ACCenum accError;
+};
+
+
+extern "C"
+ACCscript* accCreateScript() {
+    return new ACCscript();
 }
+
+extern "C"
+ACCenum accGetError( ACCscript* script ) {
+    return script->getError();
+}
+
+extern "C"
+void accDeleteScript(ACCscript* script) {
+    delete script;
+}
+
+extern "C"
+void accScriptSource(ACCscript* script,
+    ACCsizei count,
+    const ACCchar ** string,
+    const ACCint * length) {
+    int totalLength = 0;
+    for(int i = 0; i < count; i++) {
+        int len = -1;
+        const ACCchar* s = string[i];
+        if (length) {
+            len = length[i];
+        }
+        if (len < 0) {
+            len = strlen(s);
+        }
+        totalLength += len;
+    }
+    delete script->text;
+    char* text = new char[totalLength + 1];
+    script->text = text;
+    script->textLength = totalLength;
+    char* dest = text;
+    for(int i = 0; i < count; i++) {
+        int len = -1;
+        const ACCchar* s = string[i];
+        if (length) {
+            len = length[i];
+        }
+        if (len < 0) {
+            len = strlen(s);
+        }
+        memcpy(dest, s, len);
+        dest += len;
+    }
+    text[totalLength] = '\0';
+}
+
+extern "C"
+void accCompileScript(ACCscript* script) {
+    int result = script->compiler.compile(script->text, script->textLength);
+    if (result) {
+        script->setError(ACC_INVALID_OPERATION);
+    }
+}
+
+extern "C"
+void accGetScriptiv(ACCscript* script,
+    ACCenum pname,
+    ACCint * params) {
+    switch (pname) {
+        case ACC_INFO_LOG_LENGTH:
+            *params = 0;
+            break;
+    }
+}
+
+extern "C"
+void accGetScriptInfoLog(ACCscript* script,
+    ACCsizei maxLength,
+    ACCsizei * length,
+    ACCchar * infoLog) {
+    if (length) {
+        *length = 0;
+    }
+    if (maxLength > 0 && infoLog) {
+        *infoLog = 0;
+    }
+}
+
+extern "C"
+void accGetScriptLabel(ACCscript* script, const ACCchar * name,
+                       ACCvoid ** address) {
+    void* value = script->compiler.lookup(name);
+    if (value) {
+        *address = value;
+    } else {
+        script->setError(ACC_INVALID_VALUE);
+    }
+}
+
+} // namespace acc
+
diff --git a/libacc/test b/libacc/test
deleted file mode 100755
index 28b7655..0000000
--- a/libacc/test
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/sh
-rm -f tests/acc
-g++ acc.cpp disassem.cpp -g -ldl -o tests/acc && tests/acc tests/otcc.c -a x86 -d tests/otcc.out && diff tests/otcc.out tests/otcc.out-orig
-if [ -x "tests/acc" ]; then
-  tests/acc -S tests/returnval.c
-
-  if [ "$(uname)" = "Linux" ]; then
-    if [ "$(uname -m)" = "i686" ]; then
-      echo "Linux i686. Testing otcc.c"
-      tests/acc tests/otcc.c tests/otcc.c tests/returnval.c
-    fi
-  fi
-fi
diff --git a/libacc/testarm b/libacc/testarm
deleted file mode 100755
index d1a442e..0000000
--- a/libacc/testarm
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-adb remount
-adb push tests/returnval.c /system/bin/returnval.c
-mm -j8 && adb sync && adb shell /system/bin/acc -S /system/bin/returnval.c
diff --git a/libacc/tests/.gitignore b/libacc/tests/.gitignore
index 9974532..a26b298 100644
--- a/libacc/tests/.gitignore
+++ b/libacc/tests/.gitignore
@@ -1,2 +1,2 @@
-acc
+test-acc
 *.out
diff --git a/libacc/tests/Android.mk b/libacc/tests/Android.mk
new file mode 100644
index 0000000..2cff9d3
--- /dev/null
+++ b/libacc/tests/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	main.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libacc
+
+LOCAL_MODULE:= acc
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/libacc/tests/bellard.otccex.c b/libacc/tests/data/bellard.otccex.c
similarity index 100%
rename from libacc/tests/bellard.otccex.c
rename to libacc/tests/data/bellard.otccex.c
diff --git a/libacc/tests/expr.c b/libacc/tests/data/expr.c
similarity index 100%
rename from libacc/tests/expr.c
rename to libacc/tests/data/expr.c
diff --git a/libacc/tests/hello.c b/libacc/tests/data/hello.c
similarity index 100%
rename from libacc/tests/hello.c
rename to libacc/tests/data/hello.c
diff --git a/libacc/tests/missing-main.c b/libacc/tests/data/missing-main.c
similarity index 100%
rename from libacc/tests/missing-main.c
rename to libacc/tests/data/missing-main.c
diff --git a/libacc/tests/otcc.c b/libacc/tests/data/otcc.c
similarity index 100%
rename from libacc/tests/otcc.c
rename to libacc/tests/data/otcc.c
diff --git a/libacc/tests/returnval.c b/libacc/tests/data/returnval.c
similarity index 100%
rename from libacc/tests/returnval.c
rename to libacc/tests/data/returnval.c
diff --git a/libacc/tests/simplest.c b/libacc/tests/data/simplest.c
similarity index 100%
rename from libacc/tests/simplest.c
rename to libacc/tests/data/simplest.c
diff --git a/libacc/tests/hello.out-orig b/libacc/tests/hello.out-orig
deleted file mode 100644
index 1fb7bf5..0000000
--- a/libacc/tests/hello.out-orig
+++ /dev/null
Binary files differ
diff --git a/libacc/tests/main.cpp b/libacc/tests/main.cpp
new file mode 100644
index 0000000..8cfc196
--- /dev/null
+++ b/libacc/tests/main.cpp
@@ -0,0 +1,102 @@
+/*
+ * Android "Almost" C Compiler.
+ * This is a compiler for a small subset of the C language, intended for use
+ * in scripting environments where speed and memory footprint are important.
+ *
+ * This code is based upon the "unobfuscated" version of the
+ * Obfuscated Tiny C compiler, see the file LICENSE for details.
+ *
+ */
+
+#include <ctype.h>
+#include <dlfcn.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(__arm__)
+#include <unistd.h>
+#endif
+
+#include <acc/acc.h>
+
+
+typedef int (*MainPtr)(int, char**);
+// This is a separate function so it can easily be set by breakpoint in gdb.
+int run(MainPtr mainFunc, int argc, char** argv) {
+    return mainFunc(argc, argv);
+}
+
+int main(int argc, char** argv) {
+    const char* inFile = NULL;
+    bool printListing;
+    FILE* in = stdin;
+    int i;
+    for (i = 1; i < argc; i++) {
+        char* arg = argv[i];
+        if (arg[0] == '-') {
+            switch (arg[1]) {
+                case 'S':
+                    printListing = true;
+                    break;
+            default:
+                fprintf(stderr, "Unrecognized flag %s\n", arg);
+                return 3;
+            }
+        } else if (inFile == NULL) {
+            inFile = arg;
+        } else {
+            break;
+        }
+    }
+
+    if (! inFile) {
+        fprintf(stderr, "input file required\n");
+        return 2;
+    }
+
+    if (inFile) {
+        in = fopen(inFile, "r");
+        if (!in) {
+            fprintf(stderr, "Could not open input file %s\n", inFile);
+            return 1;
+        }
+    }
+
+    fseek(in, 0, SEEK_END);
+    size_t fileSize = (size_t) ftell(in);
+    rewind(in);
+    ACCchar* text = new ACCchar[fileSize];
+    size_t bytesRead = fread(text, 1, fileSize, in);
+    if (bytesRead != fileSize) {
+        fprintf(stderr, "Could not read all of file %s\n", inFile);
+    }
+
+    ACCscript* script = accCreateScript();
+
+    const ACCchar* scriptSource[] = {text};
+    accScriptSource(script, 1, scriptSource, NULL);
+    delete[] text;
+
+    accCompileScript(script);
+
+    MainPtr mainPointer = 0;
+
+    accGetScriptLabel(script, "main", (ACCvoid**) & mainPointer);
+
+    int result = accGetError(script);
+    if (result == ACC_NO_ERROR) {
+        fprintf(stderr, "Executing compiled code:\n");
+        int codeArgc = argc - i + 1;
+        char** codeArgv = argv + i - 1;
+        codeArgv[0] = (char*) (inFile ? inFile : "stdin");
+        result = run(mainPointer, codeArgc, codeArgv);
+        fprintf(stderr, "result: %d\n", result);
+    }
+
+    accDeleteScript(script);
+
+    return result;
+}
diff --git a/libacc/tests/otcc.out-orig b/libacc/tests/otcc.out-orig
deleted file mode 100644
index fa14c72..0000000
--- a/libacc/tests/otcc.out-orig
+++ /dev/null
Binary files differ
diff --git a/libacc/tests/testarm b/libacc/tests/testarm
new file mode 100755
index 0000000..db7ebe5
--- /dev/null
+++ b/libacc/tests/testarm
@@ -0,0 +1,9 @@
+#!/bin/sh
+adb remount
+adb shell rm /system/bin/acc
+adb push data/returnval.c /system/bin/returnval.c
+cd ..
+mm -j8
+cd tests
+adb sync
+adb shell /system/bin/acc -S /system/bin/returnval.c
diff --git a/libacc/tests/testlocal b/libacc/tests/testlocal
new file mode 100755
index 0000000..a76322b
--- /dev/null
+++ b/libacc/tests/testlocal
@@ -0,0 +1,15 @@
+#!/bin/sh
+rm -f test-acc
+cd ..
+g++ -I../include acc.cpp disassem.cpp tests/main.cpp -g -ldl -o tests/test-acc
+cd tests
+if [ -x "test-acc" ]; then
+  ./test-acc -S data/returnval.c
+
+  if [ "$(uname)" = "Linux" ]; then
+    if [ "$(uname -m)" = "i686" ]; then
+      echo "Linux i686. Testing otcc.c"
+      ./test-acc data/otcc.c data/otcc.c data/returnval.c
+    fi
+  fi
+fi
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index aaee8bf..087d652 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -17,7 +17,6 @@
 include $(CLEAR_VARS)
 
 commonSources := \
-	abort_socket.c \
 	array.c \
 	hashmap.c \
 	atomic.c \
@@ -45,22 +44,23 @@
 # some files must not be compiled when building against Mingw
 # they correspond to features not used by our host development tools
 # which are also hard or even impossible to port to native Win32
-WITH_MINGW :=
+WINDOWS_HOST_ONLY :=
 ifeq ($(HOST_OS),windows)
     ifeq ($(strip $(USE_CYGWIN)),)
-        WITH_MINGW := 1
+        WINDOWS_HOST_ONLY := 1
     endif
 endif
 # USE_MINGW is defined when we build against Mingw on Linux
 ifneq ($(strip $(USE_MINGW)),)
-    WITH_MINGW := 1
+    WINDOWS_HOST_ONLY := 1
 endif
 
-ifeq ($(WITH_MINGW),1)
+ifeq ($(WINDOWS_HOST_ONLY),1)
     commonSources += \
         uio.c
 else
     commonSources += \
+        abort_socket.c \
         mspace.c \
         selector.c \
         tztime.c \
diff --git a/libcutils/abort_socket.c b/libcutils/abort_socket.c
index d732142..6a5e5e4 100644
--- a/libcutils/abort_socket.c
+++ b/libcutils/abort_socket.c
@@ -239,7 +239,7 @@
     }
 
     if (pfd[0].revents) {
-        if (pfd[0].revents & POLLIN) {
+        if (pfd[0].revents & POLLOUT) {
             /* ready to write() without blocking */
             do {
                 ret = write(s->fd, buf, count);
diff --git a/nexus/CommandListener.cpp b/nexus/CommandListener.cpp
index fdf3fed..5b03357 100644
--- a/nexus/CommandListener.cpp
+++ b/nexus/CommandListener.cpp
@@ -33,54 +33,19 @@
 
 CommandListener::CommandListener() :
                  FrameworkListener("nexus") {
-    registerCmd(new WifiEnableCmd());
-    registerCmd(new WifiDisableCmd());
-    registerCmd(new WifiScanCmd());
     registerCmd(new WifiScanResultsCmd());
     registerCmd(new WifiListNetworksCmd());
     registerCmd(new WifiAddNetworkCmd());
     registerCmd(new WifiRemoveNetworkCmd());
-    registerCmd(new WifiSetVarCmd());
-    registerCmd(new WifiGetVarCmd());
 
-    registerCmd(new VpnEnableCmd());
-    registerCmd(new VpnSetVarCmd());
-    registerCmd(new VpnGetVarCmd());
-    registerCmd(new VpnDisableCmd());
+    registerCmd(new GetCmd());
+    registerCmd(new SetCmd());
 }
  
 /* -------------
  * Wifi Commands
  * ------------ */
 
-CommandListener::WifiEnableCmd::WifiEnableCmd() :
-                 NexusCommand("wifi_enable") {
-} 
-               
-int CommandListener::WifiEnableCmd::runCommand(SocketClient *cli, char *data) {
-    Controller *c = NetworkManager::Instance()->findController("WIFI");
-
-    if (c->enable())
-        cli->sendMsg(ErrorCode::OperationFailed, "Failed to enable wifi", true);
-    else
-        cli->sendMsg(ErrorCode::CommandOkay, "Wifi Enabled", false);
-    return 0;
-}
-
-CommandListener::WifiDisableCmd::WifiDisableCmd() :
-                 NexusCommand("wifi_disable") {
-} 
-               
-int CommandListener::WifiDisableCmd::runCommand(SocketClient *cli, char *data) {
-    Controller *c = NetworkManager::Instance()->findController("WIFI");
-
-    if (c->disable())
-        cli->sendMsg(ErrorCode::OperationFailed, "Failed to disable wifi", true);
-    else
-        cli->sendMsg(ErrorCode::CommandOkay, "Wifi Disabled", false);
-    return 0;
-}
-
 CommandListener::WifiAddNetworkCmd::WifiAddNetworkCmd() :
                  NexusCommand("wifi_add_network") {
 } 
@@ -116,21 +81,6 @@
     return 0;
 }
 
-CommandListener::WifiScanCmd::WifiScanCmd() :
-                 NexusCommand("wifi_scan") {
-} 
-
-int CommandListener::WifiScanCmd::runCommand(SocketClient *cli, char *data) {
-    WifiController *wc = (WifiController *) NetworkManager::Instance()->findController("WIFI");
-
-    if (wc->setScanMode(atoi(data)))
-        cli->sendMsg(ErrorCode::OperationFailed, "Failed to set scan mode", true);
-    else
-        cli->sendMsg(ErrorCode::CommandOkay, "Scan mode set", false);
-
-    return 0;
-}
-
 CommandListener::WifiScanResultsCmd::WifiScanResultsCmd() :
                  NexusCommand("wifi_scan_results") {
 } 
@@ -181,158 +131,39 @@
     return 0;
 }
 
-CommandListener::WifiSetVarCmd::WifiSetVarCmd() :
-                 NexusCommand("wifi_setvar") {
-} 
-
-int CommandListener::WifiSetVarCmd::runCommand(SocketClient *cli, char *data) {
-    WifiController *wc = (WifiController *) NetworkManager::Instance()->findController("WIFI");
-
-    char *bword;
-    char *last;
-    char varname[32];
-    char val[250];
-    int networkId;
-
-    if (!(bword = strtok_r(data, ":", &last)))
-        goto out_inval;
-
-    networkId = atoi(bword);
-   
-    if (!(bword = strtok_r(NULL, ":", &last)))
-        goto out_inval;
-
-    strncpy(varname, bword, sizeof(varname));
-
-    if (!(bword = strtok_r(NULL, ":", &last)))
-        goto out_inval;
-
-    strncpy(val, bword, sizeof(val));
-
-    LOGD("Network id %d, varname '%s', value '%s'", networkId, varname, val);
-
-    return 0;
-
-out_inval:
-    errno = EINVAL;
-    cli->sendMsg(ErrorCode::CommandParameterError, "Failed to set variable.", true);
-    return 0;
-}
-
-CommandListener::WifiGetVarCmd::WifiGetVarCmd() :
-                 NexusCommand("wifi_getvar") {
-} 
-
-int CommandListener::WifiGetVarCmd::runCommand(SocketClient *cli, char *data) {
-    WifiController *wc = (WifiController *) NetworkManager::Instance()->findController("WIFI");
-
-    char *bword;
-    char *last;
-    char varname[32];
-    int networkId;
-
-    if (!(bword = strtok_r(data, ":", &last)))
-        goto out_inval;
-   
-    networkId = atoi(bword);
-
-    if (!(bword = strtok_r(NULL, ":", &last)))
-        goto out_inval;
-
-    strncpy(varname, bword, sizeof(varname));
-
-    LOGD("networkId = %d, varname '%s'", networkId, varname);
-
-    return 0;
-out_inval:
-    errno = EINVAL;
-    cli->sendMsg(ErrorCode::CommandParameterError, "Failed to get variable.", true);
-    return 0;
-}
-
 /* ------------
  * Vpn Commands
  * ------------ */
-CommandListener::VpnEnableCmd::VpnEnableCmd() :
-                 NexusCommand("vpn_enable") {
-} 
-               
-int CommandListener::VpnEnableCmd::runCommand(SocketClient *cli, char *data) {
-    Controller *c = NetworkManager::Instance()->findController("VPN");
 
-    if (c->enable())
-        cli->sendMsg(ErrorCode::OperationFailed, "Failed to enable VPN", true);
-    else
-        cli->sendMsg(ErrorCode::CommandOkay, "VPN enabled", false);
-    return 0;
-}
-
-CommandListener::VpnSetVarCmd::VpnSetVarCmd() :
-                 NexusCommand("vpn_setvar") {
+/* ----------------
+ * Generic Commands
+ * ---------------- */
+CommandListener::GetCmd::GetCmd() :
+                 NexusCommand("get") {
 } 
 
-int CommandListener::VpnSetVarCmd::runCommand(SocketClient *cli, char *data) {
-    VpnController *vc = (VpnController *) NetworkManager::Instance()->findController("VPN");
-
+int CommandListener::GetCmd::runCommand(SocketClient *cli, char *data) {
     char *bword;
     char *last;
-    char varname[32];
-    char val[250];
-
-    if (!(bword = strtok_r(data, ":", &last)))
-        goto out_inval;
-
-    strncpy(varname, bword, sizeof(varname));
-
-    if (!(bword = strtok_r(NULL, ":", &last)))
-        goto out_inval;
-
-    strncpy(val, bword, sizeof(val));
-
-    if (!strcasecmp(varname, "vpn_gateway")) {
-        if (vc->setVpnGateway(val))
-            goto out_inval;
-    } else {
-        cli->sendMsg(ErrorCode::CommandParameterError, "Variable not found.", true);
-        return 0;
-    }
-
-    cli->sendMsg(ErrorCode::CommandOkay, "Variable written.", false);
-    return 0;
-
-out_inval:
-    errno = EINVAL;
-    cli->sendMsg(ErrorCode::CommandParameterError, "Failed to set variable.", true);
-    return 0;
-}
-
-CommandListener::VpnGetVarCmd::VpnGetVarCmd() :
-                 NexusCommand("vpn_getvar") {
-} 
-
-int CommandListener::VpnGetVarCmd::runCommand(SocketClient *cli, char *data) {
-    VpnController *vc = (VpnController *) NetworkManager::Instance()->findController("VPN");
-
-    char *bword;
-    char *last;
-    char varname[32];
+    char propname[32];
 
     if (!(bword = strtok_r(data, ":", &last)))
         goto out_inval;
    
-    strncpy(varname, bword, sizeof(varname));
+    strncpy(propname, bword, sizeof(propname));
 
-    if (!strcasecmp(varname, "vpn_gateway")) {
-        char buffer[255];
+    char pb[255];
+    snprintf(pb, sizeof(pb), "%s:", propname);
 
-        sprintf(buffer, "%s:%s", varname, inet_ntoa(vc->getVpnGateway()));
-        cli->sendMsg(ErrorCode::VariableRead, buffer, false);
-    } else {
-        cli->sendMsg(ErrorCode::CommandParameterError, "Variable not found.", true);
-        return 0;
+    if (!NetworkManager::Instance()->getProperty(propname,
+                                                 &pb[strlen(pb)],
+                                                 sizeof(pb) - strlen(pb))) {
+        goto out_inval;
     }
 
-    cli->sendMsg(ErrorCode::CommandOkay, "Variable read.", false);
+    cli->sendMsg(ErrorCode::VariableRead, pb, false);
+
+    cli->sendMsg(ErrorCode::CommandOkay, "Property read.", false);
     return 0;
 out_inval:
     errno = EINVAL;
@@ -340,16 +171,34 @@
     return 0;
 }
 
-CommandListener::VpnDisableCmd::VpnDisableCmd() :
-                 NexusCommand("vpn_disable") {
-} 
-               
-int CommandListener::VpnDisableCmd::runCommand(SocketClient *cli, char *data) {
-    Controller *c = NetworkManager::Instance()->findController("VPN");
+CommandListener::SetCmd::SetCmd() :
+                 NexusCommand("set") {
+}
 
-    if (c->disable())
-        cli->sendMsg(ErrorCode::OperationFailed, "Failed to disable VPN", true);
-    else
-        cli->sendMsg(ErrorCode::CommandOkay, "VPN disabled", false);
+int CommandListener::SetCmd::runCommand(SocketClient *cli, char *data) {
+    char *bword;
+    char *last;
+    char propname[32];
+    char propval[250];
+
+    if (!(bword = strtok_r(data, ":", &last)))
+        goto out_inval;
+
+    strncpy(propname, bword, sizeof(propname));
+
+    if (!(bword = strtok_r(NULL, ":", &last)))
+        goto out_inval;
+
+    strncpy(propval, bword, sizeof(propval));
+
+    if (NetworkManager::Instance()->setProperty(propname, propval))
+        goto out_inval;
+
+    cli->sendMsg(ErrorCode::CommandOkay, "Property set.", false);
+    return 0;
+
+out_inval:
+    errno = EINVAL;
+    cli->sendMsg(ErrorCode::CommandParameterError, "Failed to set property.", true);
     return 0;
 }
diff --git a/nexus/CommandListener.h b/nexus/CommandListener.h
index a44aa29..6973aaa 100644
--- a/nexus/CommandListener.h
+++ b/nexus/CommandListener.h
@@ -25,19 +25,6 @@
     virtual ~CommandListener() {}
 
 private:
-    class WifiEnableCmd : public NexusCommand {
-    public:
-        WifiEnableCmd();
-        virtual ~WifiEnableCmd() {}
-        int runCommand(SocketClient *c, char *data);
-    };
-
-    class WifiDisableCmd : public NexusCommand {
-    public:
-        WifiDisableCmd();
-        virtual ~WifiDisableCmd() {}
-        int runCommand(SocketClient *c, char *data);
-    };
 
     class WifiScanCmd : public NexusCommand {
     public:
@@ -74,48 +61,19 @@
         int runCommand(SocketClient *c, char *data);
     };
 
-    class WifiSetVarCmd : public NexusCommand {
+    class SetCmd : public NexusCommand {
     public:
-        WifiSetVarCmd();
-        virtual ~WifiSetVarCmd() {}
+        SetCmd();
+        virtual ~SetCmd() {}
         int runCommand(SocketClient *c, char *data);
     };
 
-    class WifiGetVarCmd : public NexusCommand {
+    class GetCmd : public NexusCommand {
     public:
-        WifiGetVarCmd();
-        virtual ~WifiGetVarCmd() {}
+        GetCmd();
+        virtual ~GetCmd() {}
         int runCommand(SocketClient *c, char *data);
     };
-
-    class VpnEnableCmd : public NexusCommand {
-    public:
-        VpnEnableCmd();
-        virtual ~VpnEnableCmd() {}
-        int runCommand(SocketClient *c, char *data);
-    };
-
-    class VpnSetVarCmd : public NexusCommand {
-    public:
-        VpnSetVarCmd();
-        virtual ~VpnSetVarCmd() {}
-        int runCommand(SocketClient *c, char *data);
-    };
-
-    class VpnGetVarCmd : public NexusCommand {
-    public:
-        VpnGetVarCmd();
-        virtual ~VpnGetVarCmd() {}
-        int runCommand(SocketClient *c, char *data);
-    };
-
-    class VpnDisableCmd : public NexusCommand {
-    public:
-        VpnDisableCmd();
-        virtual ~VpnDisableCmd() {}
-        int runCommand(SocketClient *c, char *data);
-    };
-
 };
 
 #endif
diff --git a/nexus/Controller.cpp b/nexus/Controller.cpp
index cc1a187..133e796 100644
--- a/nexus/Controller.cpp
+++ b/nexus/Controller.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <fcntl.h>
 #include <unistd.h>
@@ -32,8 +33,13 @@
 extern "C" int init_module(void *, unsigned int, const char *);
 extern "C" int delete_module(const char *, unsigned int);
 
-Controller::Controller(const char *name) {
+Controller::Controller(const char *name, const char *prefix) {
     mName = name;
+    mPropertyPrefix = prefix;
+    mProperties = new PropertyCollection();
+
+    mEnabled = false;
+    registerProperty("enable");
 }
 
 int Controller::start() {
@@ -44,12 +50,69 @@
     return 0;
 }
 
+const PropertyCollection & Controller::getProperties() {
+    return *mProperties;
+}
+
+int Controller::setProperty(const char *name, char *value) {
+    if (!strcmp(name, "enable")) {
+        int en = atoi(value);
+        int rc;
+
+        rc = (en ? enable() : disable());
+
+        if (!rc)
+            mEnabled = en;
+
+        return rc;
+    }
+
+    errno = ENOENT;
+    return -1;
+}
+
+const char *Controller::getProperty(const char *name, char *buffer, size_t maxsize) {
+    if (!strcmp(name, "enable")) {
+        snprintf(buffer, maxsize, "%d", mEnabled);
+        return buffer;
+    }
+
+    errno = ENOENT;
+    return NULL;
+}
+
+int Controller::registerProperty(const char *name) {
+    PropertyCollection::iterator it;
+
+    for (it = mProperties->begin(); it != mProperties->end(); ++it) {
+        if (!strcmp(name, (*it))) {
+            errno = EADDRINUSE;
+            LOGE("Failed to register property (%s)", strerror(errno));
+            return -1;
+        }
+    }
+
+    mProperties->push_back(name);
+    return 0;
+}
+
+int Controller::unregisterProperty(const char *name) {
+    PropertyCollection::iterator it;
+
+    for (it = mProperties->begin(); it != mProperties->end(); ++it) {
+        if (!strcmp(name, (*it))) {
+            mProperties->erase(it);
+            return 0;
+        }
+    }
+    errno = ENOENT;
+    return -1;
+}
+
 int Controller::loadKernelModule(char *modpath, const char *args) {
     void *module;
     unsigned int size;
 
-    LOGD("loadKernelModule(%s, %s)", modpath, args);
-
     module = loadFile(modpath, &size);
     if (!module) {
         errno = -EIO;
@@ -65,7 +128,6 @@
     int rc = -1;
     int retries = 10;
 
-    LOGD("unloadKernelModule(%s)", modtag);
     while (retries--) {
         rc = delete_module(modtag, O_NONBLOCK | O_EXCL);
         if (rc < 0 && errno == EAGAIN)
@@ -107,7 +169,6 @@
     return false;
 }
 
-
 void *Controller::loadFile(char *filename, unsigned int *_size)
 {
 	int ret, fd;
diff --git a/nexus/Controller.h b/nexus/Controller.h
index 8e69978..ae37426 100644
--- a/nexus/Controller.h
+++ b/nexus/Controller.h
@@ -16,31 +16,48 @@
 #ifndef _CONTROLLER_H
 #define _CONTROLLER_H
 
+#include <unistd.h>
+#include <sys/types.h>
+
 #include "../../../frameworks/base/include/utils/List.h"
 
+#include "PropertyCollection.h"
+
 class Controller {
 private:
     const char *mName;
+    const char *mPropertyPrefix;
+    PropertyCollection *mProperties;
+    bool mEnabled;
     
 public:
-    Controller(const char *name);
+    Controller(const char *name, const char *prefix);
     virtual ~Controller() {}
 
     virtual int start();
     virtual int stop();
 
-    virtual int enable() = 0;
-    virtual int disable() = 0;
+    virtual const PropertyCollection &getProperties();
+    virtual int setProperty(const char *name, char *value);
+    virtual const char *getProperty(const char *name, char *buffer, size_t maxsize);
 
-    virtual const char *getName() { return mName; }
+    const char *getName() { return mName; }
+    const char *getPropertyPrefix() { return mPropertyPrefix; }
 
 protected:
     int loadKernelModule(char *modpath, const char *args);
     bool isKernelModuleLoaded(const char *modtag);
     int unloadKernelModule(const char *modtag);
 
+    int registerProperty(const char *name);
+    int unregisterProperty(const char *name);
+
 private:
     void *loadFile(char *filename, unsigned int *_size);
+
+    virtual int enable() = 0;
+    virtual int disable() = 0;
+
 };
 
 typedef android::List<Controller *> ControllerCollection;
diff --git a/nexus/LoopController.cpp b/nexus/LoopController.cpp
index 38037ac..400d279 100644
--- a/nexus/LoopController.cpp
+++ b/nexus/LoopController.cpp
@@ -18,7 +18,7 @@
 #include "LoopController.h"
 
 LoopController::LoopController() :
-                Controller("LOOP") {
+                Controller("LOOP", "loop") {
 }
 
 int LoopController::enable() {
diff --git a/nexus/LoopController.h b/nexus/LoopController.h
index 8b89977..d047f87 100644
--- a/nexus/LoopController.h
+++ b/nexus/LoopController.h
@@ -23,6 +23,7 @@
     LoopController();
     virtual ~LoopController() {}
 
+private:
     int enable();
     int disable();
 };
diff --git a/nexus/NetworkManager.cpp b/nexus/NetworkManager.cpp
index 3b823d1..022d7f8 100644
--- a/nexus/NetworkManager.cpp
+++ b/nexus/NetworkManager.cpp
@@ -83,6 +83,73 @@
     return NULL;
 }
 
+int NetworkManager::setProperty(const char *name, char *value) {
+    char *tmp = strdup(name);
+    char *next = tmp;
+    char *prefix;
+    char *rest;
+    ControllerCollection::iterator it;
+
+    if (!(prefix = strsep(&next, ".")))
+        goto out_inval;
+
+    rest = next;
+
+    if (!strncasecmp(prefix, "netman", 6)) {
+        errno = ENOSYS;
+        return -1;
+    }
+
+    for (it = mControllers->begin(); it != mControllers->end(); ++it) {
+        if (!strcasecmp(prefix, (*it)->getPropertyPrefix())) {
+            return (*it)->setProperty(rest, value);
+        }
+    }
+
+    errno = ENOENT;
+    return -1;
+
+out_inval:
+    errno = EINVAL;
+    return -1;
+}
+
+const char *NetworkManager::getProperty(const char *name, char *buffer,
+                                                          size_t maxsize) {
+    char *tmp = strdup(name);
+    char *next = tmp;
+    char *prefix;
+    char *rest;
+    ControllerCollection::iterator it;
+
+    if (!(prefix = strsep(&next, ".")))
+        goto out_inval;
+
+    rest = next;
+
+    if (!strncasecmp(prefix, "netman", 6)) {
+        errno = ENOSYS;
+        return NULL;
+    }
+
+    for (it = mControllers->begin(); it != mControllers->end(); ++it) {
+        if (!strcasecmp(prefix, (*it)->getPropertyPrefix())) {
+            return (*it)->getProperty(rest, buffer, maxsize);
+        }
+    }
+
+    errno = ENOENT;
+    return NULL;
+
+out_inval:
+    errno = EINVAL;
+    return NULL;
+}
+
+const PropertyCollection &NetworkManager::getProperties() {
+    return *mProperties;
+}
+
 int NetworkManager::onInterfaceCreated(Controller *c, char *name) {
     LOGD("Interface %s created by controller %s", name, c->getName());
     return 0;
diff --git a/nexus/NetworkManager.h b/nexus/NetworkManager.h
index 0ac4a4d..bd00849 100644
--- a/nexus/NetworkManager.h
+++ b/nexus/NetworkManager.h
@@ -19,6 +19,7 @@
 #include <sysutils/SocketListener.h>
 
 #include "Controller.h"
+#include "PropertyCollection.h"
 
 class NetworkManager {
 private:
@@ -27,6 +28,7 @@
 private:
     ControllerCollection *mControllers;
     SocketListener       *mBroadcaster;
+    PropertyCollection   *mProperties;
 
 public:
     virtual ~NetworkManager() {}
@@ -37,6 +39,10 @@
 
     Controller *findController(const char *name);
 
+    const PropertyCollection &getProperties();
+    int setProperty(const char *name, char *value);
+    const char *getProperty(const char *name, char *buffer, size_t maxsize);
+
     void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }
     SocketListener *getBroadcaster() { return mBroadcaster; }
 
@@ -45,6 +51,9 @@
 private:
     int startControllers();
     int stopControllers();
+    int registerProperty(const char *name);
+    int unregisterProperty(const char *name);
+
     NetworkManager();
 
 public:
diff --git a/nexus/OpenVpnController.cpp b/nexus/OpenVpnController.cpp
index 411a0c7..1934024 100644
--- a/nexus/OpenVpnController.cpp
+++ b/nexus/OpenVpnController.cpp
@@ -63,7 +63,6 @@
 }
 
 int OpenVpnController::disable() {
-
     if (mServiceManager->stop("openvpn"))
         return -1;
     return 0;
diff --git a/nexus/OpenVpnController.h b/nexus/OpenVpnController.h
index b321029..439e18a 100644
--- a/nexus/OpenVpnController.h
+++ b/nexus/OpenVpnController.h
@@ -31,6 +31,8 @@
 
     int start();
     int stop();
+
+private:
     int enable();
     int disable();
 };
diff --git a/nexus/PropertyCollection.h b/nexus/PropertyCollection.h
new file mode 100644
index 0000000..4be1cf0
--- /dev/null
+++ b/nexus/PropertyCollection.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _PROPERTY_COLLECTION_H
+#define _PROPERTY_COLLECTION_H
+
+#include "../../../frameworks/base/include/utils/List.h"
+
+typedef android::List<const char *> PropertyCollection;
+
+#endif
+
diff --git a/nexus/VpnController.cpp b/nexus/VpnController.cpp
index cd24c19..d3bc216 100644
--- a/nexus/VpnController.cpp
+++ b/nexus/VpnController.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <stdio.h>
 #include <string.h>
 #include <errno.h>
 #include <sys/socket.h>
@@ -23,7 +24,8 @@
 #include "VpnController.h"
 
 VpnController::VpnController() :
-               Controller("VPN") {
+               Controller("VPN", "vpn") {
+    registerProperty("gateway");
 }
 
 int VpnController::start() {
@@ -46,15 +48,23 @@
     return -1;
 }
 
-int VpnController::setVpnGateway(const char *vpnGw) {
-    if (!inet_aton(vpnGw, &mVpnGateway)) {
-        errno = EINVAL;
-        return -1;
-    }
-    return 0;
+int VpnController::setProperty(const char *name, char *value) {
+    if (!strcmp(name, "gateway")) {
+        if (!inet_aton(value, &mVpnGateway)) {
+            errno = EINVAL;
+            return -1;
+        }
+        return 0;
+    } 
+
+    return Controller::setProperty(name, value);
 }
 
-int VpnController::setVpnGateway(struct in_addr *vpnGw) {
-    memcpy(&mVpnGateway, vpnGw, sizeof(struct in_addr));
-    return 0;
+const char *VpnController::getProperty(const char *name, char *buffer, size_t maxsize) {
+    if (!strcmp(name, "gateway")) {
+        snprintf(buffer, maxsize, "%s", inet_ntoa(mVpnGateway));
+        return buffer;
+    }
+
+    return Controller::getProperty(name, buffer, maxsize);
 }
diff --git a/nexus/VpnController.h b/nexus/VpnController.h
index 4088e6a..0a93990 100644
--- a/nexus/VpnController.h
+++ b/nexus/VpnController.h
@@ -33,14 +33,14 @@
     virtual int start();
     virtual int stop();
 
+    virtual int setProperty(const char *name, char *value);
+    virtual const char *getProperty(const char *name, char *buffer,
+                                    size_t maxlen);
+
+private:
     virtual int enable();
     virtual int disable();
 
-    struct in_addr &getVpnGateway() { return mVpnGateway; }
-    int setVpnGateway(const char *vpnGw);
-    int setVpnGateway(struct in_addr *vpnGw);
-
-protected:
 };
 
 #endif
diff --git a/nexus/WifiController.cpp b/nexus/WifiController.cpp
index 126db69..72207ce 100644
--- a/nexus/WifiController.cpp
+++ b/nexus/WifiController.cpp
@@ -13,6 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+#include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 
@@ -26,7 +28,7 @@
 #include "ErrorCode.h"
 
 WifiController::WifiController(char *modpath, char *modname, char *modargs) :
-                Controller("WIFI") {
+                Controller("WIFI", "wifi") {
     strncpy(mModulePath, modpath, sizeof(mModulePath));
     strncpy(mModuleName, modname, sizeof(mModuleName));
     strncpy(mModuleArgs, modargs, sizeof(mModuleArgs));
@@ -34,6 +36,8 @@
     mSupplicant = new Supplicant();
     mScanner = new WifiScanner(mSupplicant, 10);
     mCurrentScanMode = 0;
+
+    registerProperty("scanmode");
 }
 
 int WifiController::start() {
@@ -94,7 +98,7 @@
     return -1;
 }
 
-void WifiController::sendStatusBroadcast(char *msg) {
+void WifiController::sendStatusBroadcast(const char *msg) {
     NetworkManager::Instance()->
                     getBroadcaster()->
                     sendBroadcast(ErrorCode::UnsolicitedInformational, msg, false);
@@ -167,3 +171,20 @@
 WifiNetworkCollection *WifiController::createNetworkList() {
     return mSupplicant->createNetworkList();
 }
+
+int WifiController::setProperty(const char *name, char *value) {
+    if (!strcmp(name, "scanmode")) 
+        return setScanMode((uint32_t) strtoul(value, NULL, 0));
+
+    return Controller::setProperty(name, value);
+}
+
+const char *WifiController::getProperty(const char *name, char *buffer, size_t maxsize) {
+    if (!strcmp(name, "scanmode")) {
+        snprintf(buffer, maxsize, "0x%.8x", mCurrentScanMode);
+        return buffer;
+    } 
+
+    return Controller::getProperty(name, buffer, maxsize);
+}
+
diff --git a/nexus/WifiController.h b/nexus/WifiController.h
index b9c981c..a70fb5b 100644
--- a/nexus/WifiController.h
+++ b/nexus/WifiController.h
@@ -54,15 +54,14 @@
     int start();
     int stop();
 
-    int enable();
-    int disable();
-
     int addNetwork();
     int removeNetwork(int networkId);
     WifiNetworkCollection *createNetworkList();
 
-    int getScanMode() { return mCurrentScanMode; }
-    int setScanMode(uint32_t mode);
+    virtual int setProperty(const char *name, char *value);
+    virtual const char *getProperty(const char *name, char *buffer,
+                                    size_t maxlen);
+
     ScanResultCollection *createScanResults();
 
     char *getModulePath() { return mModulePath; }
@@ -79,7 +78,13 @@
     virtual bool isFirmwareLoaded() = 0;
     virtual bool isPoweredUp() = 0;
 
-    void sendStatusBroadcast(char *msg);
+    void sendStatusBroadcast(const char *msg);
+
+private:
+    int setScanMode(uint32_t mode);
+    int enable();
+    int disable();
+
 };
 
 #endif
diff --git a/nexus/WifiScanner.cpp b/nexus/WifiScanner.cpp
index 1bc9722..048e784 100644
--- a/nexus/WifiScanner.cpp
+++ b/nexus/WifiScanner.cpp
@@ -65,7 +65,7 @@
         struct timeval to;
         int rc = 0;
 
-        to.tv_sec = 0;
+        to.tv_usec = 0;
         to.tv_sec = mPeriod;
 
         FD_ZERO(&read_fds);
@@ -83,4 +83,5 @@
         } else if (FD_ISSET(mCtrlPipe[0], &read_fds))
             break;
     } // while
+    LOGD("Stopping wifi scanner");
 }
diff --git a/rootdir/etc/init.goldfish.sh b/rootdir/etc/init.goldfish.sh
index 0eb0154..f1b801d 100755
--- a/rootdir/etc/init.goldfish.sh
+++ b/rootdir/etc/init.goldfish.sh
@@ -34,6 +34,10 @@
     ;;
 esac
 
+# call 'qemu-props' to set system properties from the emulator.
+#
+/system/bin/qemu-props
+
 # this line doesn't really do anything useful. however without it the
 # previous setprop doesn't seem to apply for some really odd reason
 setprop ro.qemu.init.completed 1