reconcile korg/master into goog/master
diff --git a/Android.mk b/Android.mk
index 0367fef..deec80a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,15 +1,14 @@
+ifneq ($(TARGET_SIMULATOR),true)
+ifeq ($(TARGET_ARCH),arm)
+
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
 commands_recovery_local_path := $(LOCAL_PATH)
 
-ifneq ($(TARGET_SIMULATOR),true)
-ifeq ($(TARGET_ARCH),arm)
-
 LOCAL_SRC_FILES := \
 	recovery.c \
 	bootloader.c \
-	commands.c \
 	firmware.c \
 	install.c \
 	roots.c \
@@ -32,14 +31,19 @@
 
 LOCAL_MODULE_TAGS := eng
 
-LOCAL_STATIC_LIBRARIES := libminzip libunz libamend libmtdutils libmincrypt
+LOCAL_STATIC_LIBRARIES :=
+ifeq ($(TARGET_RECOVERY_UI_LIB),)
+  LOCAL_SRC_FILES += default_recovery_ui.c
+else
+  LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UI_LIB)
+endif
+LOCAL_STATIC_LIBRARIES += libminzip libunz libmtdutils libmincrypt
 LOCAL_STATIC_LIBRARIES += libminui libpixelflinger_static libpng libcutils
 LOCAL_STATIC_LIBRARIES += libstdc++ libc
 
 include $(BUILD_EXECUTABLE)
 
 include $(commands_recovery_local_path)/minui/Android.mk
-include $(commands_recovery_local_path)/amend/Android.mk
 include $(commands_recovery_local_path)/minzip/Android.mk
 include $(commands_recovery_local_path)/mtdutils/Android.mk
 include $(commands_recovery_local_path)/tools/Android.mk
diff --git a/amend/Android.mk b/amend/Android.mk
deleted file mode 100644
index c3b7c32..0000000
--- a/amend/Android.mk
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright 2007 The Android Open Source Project
-#
-
-LOCAL_PATH := $(call my-dir)
-
-amend_src_files := \
-	amend.c \
-	lexer.l \
-	parser_y.y \
-	ast.c \
-	symtab.c \
-	commands.c \
-	execute.c
-
-amend_test_files := \
-	test_symtab.c \
-	test_commands.c
-
-# "-x c" forces the lex/yacc files to be compiled as c;
-# the build system otherwise forces them to be c++.
-amend_cflags := -Wall -x c
-
-#
-# Build the host-side command line tool
-#
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-		$(amend_src_files) \
-		$(amend_test_files) \
-		register.c \
-		main.c
-
-LOCAL_CFLAGS := $(amend_cflags) -g -O0
-LOCAL_MODULE := amend
-LOCAL_YACCFLAGS := -v
-
-include $(BUILD_HOST_EXECUTABLE)
-
-#
-# Build the device-side library
-#
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(amend_src_files)
-LOCAL_SRC_FILES += $(amend_test_files)
-
-LOCAL_CFLAGS := $(amend_cflags)
-LOCAL_MODULE := libamend
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/amend/amend.c b/amend/amend.c
deleted file mode 100644
index 6f706d0..0000000
--- a/amend/amend.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#include <stdlib.h>
-#include "amend.h"
-#include "lexer.h"
-#include "parser.h"
-
-extern const AmCommandList *gCommands;
-
-const AmCommandList *
-parseAmendScript(const char *buf, size_t bufLen)
-{
-    setLexerInputBuffer(buf, bufLen);
-    int ret = yyparse();
-    if (ret != 0) {
-        return NULL;
-    }
-    return gCommands;
-}
diff --git a/amend/amend.h b/amend/amend.h
deleted file mode 100644
index 416f974..0000000
--- a/amend/amend.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2007 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 AMEND_H_
-#define AMEND_H_
-
-#include "ast.h"
-#include "execute.h"
-
-const AmCommandList *parseAmendScript(const char *buf, size_t bufLen);
-
-#endif  // AMEND_H_
diff --git a/amend/ast.c b/amend/ast.c
deleted file mode 100644
index f53efdc..0000000
--- a/amend/ast.c
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#include <stdio.h>
-#include "ast.h"
-
-static const char gSpaces[] =
-    "                                                                "
-    "                                                                "
-    "                                                                "
-    "                                                                "
-    "                                                                "
-    "                                                                "
-    "                                                                ";
-const int gSpacesMax = sizeof(gSpaces) - 1;
-
-static const char *
-pad(int level)
-{
-    level *= 4;
-    if (level > gSpacesMax) {
-        level = gSpacesMax;
-    }
-    return gSpaces + gSpacesMax - level;
-}
-
-void dumpBooleanValue(int level, const AmBooleanValue *booleanValue);
-void dumpStringValue(int level, const AmStringValue *stringValue);
-
-void
-dumpBooleanExpression(int level, const AmBooleanExpression *booleanExpression)
-{
-    const char *op;
-    bool unary = false;
-
-    switch (booleanExpression->op) {
-    case AM_BOP_NOT:
-        op = "NOT";
-        unary = true;
-        break;
-    case AM_BOP_EQ:
-        op = "EQ";
-        break;
-    case AM_BOP_NE:
-        op = "NE";
-        break;
-    case AM_BOP_AND:
-        op = "AND";
-        break;
-    case AM_BOP_OR:
-        op = "OR";
-        break;
-    default:
-        op = "??";
-        break;
-    }
-
-    printf("%sBOOLEAN %s {\n", pad(level), op);
-    dumpBooleanValue(level + 1, booleanExpression->arg1);
-    if (!unary) {
-        dumpBooleanValue(level + 1, booleanExpression->arg2);
-    }
-    printf("%s}\n", pad(level));
-}
-
-void
-dumpFunctionArguments(int level, const AmFunctionArguments *functionArguments)
-{
-    int i;
-    for (i = 0; i < functionArguments->argc; i++) {
-        dumpStringValue(level, &functionArguments->argv[i]);
-    }
-}
-
-void
-dumpFunctionCall(int level, const AmFunctionCall *functionCall)
-{
-    printf("%sFUNCTION %s (\n", pad(level), functionCall->name);
-    dumpFunctionArguments(level + 1, functionCall->args);
-    printf("%s)\n", pad(level));
-}
-
-void
-dumpStringValue(int level, const AmStringValue *stringValue)
-{
-    switch (stringValue->type) {
-    case AM_SVAL_LITERAL:
-        printf("%s\"%s\"\n", pad(level), stringValue->u.literal);
-        break;
-    case AM_SVAL_FUNCTION:
-        dumpFunctionCall(level, stringValue->u.function);
-        break;
-    default:
-        printf("%s<UNKNOWN SVAL TYPE %d>\n", pad(level), stringValue->type);
-        break;
-    }
-}
-
-void
-dumpStringComparisonExpression(int level,
-        const AmStringComparisonExpression *stringComparisonExpression)
-{
-    const char *op;
-
-    switch (stringComparisonExpression->op) {
-    case AM_SOP_LT:
-        op = "LT";
-        break;
-    case AM_SOP_LE:
-        op = "LE";
-        break;
-    case AM_SOP_GT:
-        op = "GT";
-        break;
-    case AM_SOP_GE:
-        op = "GE";
-        break;
-    case AM_SOP_EQ:
-        op = "EQ";
-        break;
-    case AM_SOP_NE:
-        op = "NE";
-        break;
-    default:
-        op = "??";
-        break;
-    }
-    printf("%sSTRING %s {\n", pad(level), op);
-    dumpStringValue(level + 1, stringComparisonExpression->arg1);
-    dumpStringValue(level + 1, stringComparisonExpression->arg2);
-    printf("%s}\n", pad(level));
-}
-
-void
-dumpBooleanValue(int level, const AmBooleanValue *booleanValue)
-{
-    switch (booleanValue->type) {
-    case AM_BVAL_EXPRESSION:
-        dumpBooleanExpression(level, &booleanValue->u.expression);
-        break;
-    case AM_BVAL_STRING_COMPARISON:
-        dumpStringComparisonExpression(level,
-                &booleanValue->u.stringComparison);
-        break;
-    default:
-        printf("%s<UNKNOWN BVAL TYPE %d>\n", pad(1), booleanValue->type);
-        break;
-    }
-}
-
-void
-dumpWordList(const AmWordList *wordList)
-{
-    int i;
-    for (i = 0; i < wordList->argc; i++) {
-        printf("%s\"%s\"\n", pad(1), wordList->argv[i]);
-    }
-}
-
-void
-dumpCommandArguments(const AmCommandArguments *commandArguments)
-{
-    if (commandArguments->booleanArgs) {
-        dumpBooleanValue(1, commandArguments->u.b);
-    } else {
-        dumpWordList(commandArguments->u.w);
-    }
-}
-
-void
-dumpCommand(const AmCommand *command)
-{
-    printf("command \"%s\" {\n", command->name);
-    dumpCommandArguments(command->args);
-    printf("}\n");
-}
-
-void
-dumpCommandList(const AmCommandList *commandList)
-{
-    int i;
-    for (i = 0; i < commandList->commandCount; i++) {
-        dumpCommand(commandList->commands[i]);
-    }
-}
diff --git a/amend/ast.h b/amend/ast.h
deleted file mode 100644
index 7834a2b..0000000
--- a/amend/ast.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2007 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 AMEND_AST_H_
-#define AMEND_AST_H_
-
-#include "commands.h"
-
-typedef struct AmStringValue AmStringValue;
-
-typedef struct {
-    int argc;
-    AmStringValue *argv;
-} AmFunctionArguments;
-
-/* An internal structure used only by the parser;
- * will not appear in the output AST.
-xxx try to move this into parser.h
- */
-typedef struct AmFunctionArgumentBuilder AmFunctionArgumentBuilder;
-struct AmFunctionArgumentBuilder {
-    AmFunctionArgumentBuilder *next;
-    AmStringValue *arg;
-    int argCount;
-};
-
-typedef struct AmWordListBuilder AmWordListBuilder;
-struct AmWordListBuilder {
-    AmWordListBuilder *next;
-    const char *word;
-    int wordCount;
-};
-
-typedef struct {
-    const char *name;
-    Function *fn;
-    AmFunctionArguments *args;
-} AmFunctionCall;
-
-
-/* <string-value> ::=
- *      <literal-string> |
- *      <function-call>
- */
-struct AmStringValue {
-    unsigned int line;
-
-    enum {
-        AM_SVAL_LITERAL,
-        AM_SVAL_FUNCTION,
-    } type;
-    union {
-        const char *literal;
-//xxx inline instead of using pointers
-        AmFunctionCall *function;
-    } u;
-};
-
-
-/* <string-comparison-expression> ::=
- *      <string-value> <string-comparison-operator> <string-value>
- */
-typedef struct {
-    unsigned int line;
-
-    enum {
-        AM_SOP_LT,
-        AM_SOP_LE,
-        AM_SOP_GT,
-        AM_SOP_GE,
-        AM_SOP_EQ,
-        AM_SOP_NE,
-    } op;
-    AmStringValue *arg1;
-    AmStringValue *arg2;
-} AmStringComparisonExpression;
-
-
-/* <boolean-expression> ::=
- *      ! <boolean-value> |
- *      <boolean-value> <binary-boolean-operator> <boolean-value>
- */
-typedef struct AmBooleanValue AmBooleanValue;
-typedef struct {
-    unsigned int line;
-
-    enum {
-        AM_BOP_NOT,
-
-        AM_BOP_EQ,
-        AM_BOP_NE,
-
-        AM_BOP_AND,
-
-        AM_BOP_OR,
-    } op;
-    AmBooleanValue *arg1;
-    AmBooleanValue *arg2;
-} AmBooleanExpression;
-
-
-/* <boolean-value> ::=
- *      <boolean-expression> |
- *      <string-comparison-expression>
- */
-struct AmBooleanValue {
-    unsigned int line;
-
-    enum {
-        AM_BVAL_EXPRESSION,
-        AM_BVAL_STRING_COMPARISON,
-    } type;
-    union {
-        AmBooleanExpression expression;
-        AmStringComparisonExpression stringComparison;
-    } u;
-};
-
-
-typedef struct {
-    unsigned int line;
-
-    int argc;
-    const char **argv;
-} AmWordList;
-
-
-typedef struct {
-    bool booleanArgs;
-    union {
-        AmWordList *w;
-        AmBooleanValue *b;
-    } u;
-} AmCommandArguments;
-
-typedef struct {
-    unsigned int line;
-
-    const char *name;
-    Command *cmd;
-    AmCommandArguments *args;
-} AmCommand;
-
-typedef struct {
-    AmCommand **commands;
-    int commandCount;
-    int arraySize;
-} AmCommandList;
-
-void dumpCommandList(const AmCommandList *commandList);
-
-#endif  // AMEND_AST_H_
diff --git a/amend/commands.c b/amend/commands.c
deleted file mode 100644
index 78121ad..0000000
--- a/amend/commands.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include "symtab.h"
-#include "commands.h"
-
-#if 1
-#define TRACE(...)  printf(__VA_ARGS__)
-#else
-#define TRACE(...)  /**/
-#endif
-
-typedef enum {
-    CMD_TYPE_UNKNOWN = -1,
-    CMD_TYPE_COMMAND = 0,
-    CMD_TYPE_FUNCTION
-} CommandType;
-
-typedef struct {
-    const char *name;
-    void *cookie;
-    CommandType type;
-    CommandArgumentType argType;
-    CommandHook hook;
-} CommandEntry;
-
-static struct {
-    SymbolTable *symbolTable;
-    bool commandStateInitialized;
-} gCommandState;
-
-int
-commandInit()
-{
-    if (gCommandState.commandStateInitialized) {
-        return -1;
-    }
-    gCommandState.symbolTable = createSymbolTable();
-    if (gCommandState.symbolTable == NULL) {
-        return -1;
-    }
-    gCommandState.commandStateInitialized = true;
-    return 0;
-}
-
-void
-commandCleanup()
-{
-    if (gCommandState.commandStateInitialized) {
-        gCommandState.commandStateInitialized = false;
-        deleteSymbolTable(gCommandState.symbolTable);
-        gCommandState.symbolTable = NULL;
-//xxx need to free the entries and names in the symbol table
-    }
-}
-
-static int
-registerCommandInternal(const char *name, CommandType type,
-        CommandArgumentType argType, CommandHook hook, void *cookie)
-{
-    CommandEntry *entry;
-
-    if (!gCommandState.commandStateInitialized) {
-        return -1;
-    }
-    if (name == NULL || hook == NULL) {
-        return -1;
-    }
-    if (type != CMD_TYPE_COMMAND && type != CMD_TYPE_FUNCTION) {
-        return -1;
-    }
-    if (argType != CMD_ARGS_BOOLEAN && argType != CMD_ARGS_WORDS) {
-        return -1;
-    }
-
-    entry = (CommandEntry *)malloc(sizeof(CommandEntry));
-    if (entry != NULL) {
-        entry->name = strdup(name);
-        if (entry->name != NULL) {
-            int ret;
-
-            entry->cookie = cookie;
-            entry->type = type;
-            entry->argType = argType;
-            entry->hook = hook;
-            ret = addToSymbolTable(gCommandState.symbolTable,
-                        entry->name, entry->type, entry);
-            if (ret == 0) {
-                return 0;
-            }
-        }
-        free(entry);
-    }
-
-    return -1;
-}
-
-int
-registerCommand(const char *name,
-        CommandArgumentType argType, CommandHook hook, void *cookie)
-{
-    return registerCommandInternal(name,
-            CMD_TYPE_COMMAND, argType, hook, cookie);
-}
-
-int
-registerFunction(const char *name, FunctionHook hook, void *cookie)
-{
-    return registerCommandInternal(name,
-            CMD_TYPE_FUNCTION, CMD_ARGS_WORDS, (CommandHook)hook, cookie);
-}
-
-Command *
-findCommand(const char *name)
-{
-    return (Command *)findInSymbolTable(gCommandState.symbolTable,
-            name, CMD_TYPE_COMMAND);
-}
-
-Function *
-findFunction(const char *name)
-{
-    return (Function *)findInSymbolTable(gCommandState.symbolTable,
-            name, CMD_TYPE_FUNCTION);
-}
-
-CommandArgumentType
-getCommandArgumentType(Command *cmd)
-{
-    CommandEntry *entry = (CommandEntry *)cmd;
-
-    if (entry != NULL) {
-        return entry->argType;
-    }
-    return CMD_ARGS_UNKNOWN;
-}
-
-static int
-callCommandInternal(CommandEntry *entry, int argc, const char *argv[])
-{
-    if (entry != NULL && entry->argType == CMD_ARGS_WORDS &&
-            (argc == 0 || (argc > 0 && argv != NULL)))
-    {
-        int i;
-        for (i = 0; i < argc; i++) {
-            if (argv[i] == NULL) {
-                goto bail;
-            }
-        }
-        TRACE("calling command %s\n", entry->name);
-        return entry->hook(entry->name, entry->cookie, argc, argv);
-    }
-bail:
-    return -1;
-}
-
-static int
-callBooleanCommandInternal(CommandEntry *entry, bool arg)
-{
-    if (entry != NULL && entry->argType == CMD_ARGS_BOOLEAN) {
-        TRACE("calling boolean command %s\n", entry->name);
-        return entry->hook(entry->name, entry->cookie, arg ? 1 : 0, NULL);
-    }
-    return -1;
-}
-
-int
-callCommand(Command *cmd, int argc, const char *argv[])
-{
-    return callCommandInternal((CommandEntry *)cmd, argc, argv);
-}
-
-int
-callBooleanCommand(Command *cmd, bool arg)
-{
-    return callBooleanCommandInternal((CommandEntry *)cmd, arg);
-}
-
-int
-callFunctionInternal(CommandEntry *entry, int argc, const char *argv[],
-        char **result, size_t *resultLen)
-{
-    if (entry != NULL && entry->argType == CMD_ARGS_WORDS &&
-            (argc == 0 || (argc > 0 && argv != NULL)))
-    {
-        if (result != NULL)
-        {
-            /* This is the actual invocation of the function,
-             * which means that none of the arguments are allowed
-             * to be NULL.
-             */
-            int i;
-            for (i = 0; i < argc; i++) {
-                if (argv[i] == NULL) {
-                    goto bail;
-                }
-            }
-            TRACE("calling function %s\n", entry->name);
-            return ((FunctionHook)entry->hook)(entry->name, entry->cookie,
-                    argc, argv, result, resultLen);
-        }
-    }
-bail:
-    return -1;
-}
-
-int
-callFunction(Function *fn, int argc, const char *argv[],
-        char **result, size_t *resultLen)
-{
-    return callFunctionInternal((CommandEntry *)fn, argc, argv,
-            result, resultLen);
-}
diff --git a/amend/commands.h b/amend/commands.h
deleted file mode 100644
index 6c97e55..0000000
--- a/amend/commands.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#include <stdbool.h>
-
-#ifndef AMEND_COMMANDS_H_
-#define AMEND_COMMANDS_H_
-
-/* Invoke a command.
- *
- * When a boolean command is called, "argc" is the boolean value and
- * "argv" is NULL.
- */
-typedef int (*CommandHook)(const char *name, void *cookie,
-                           int argc, const char *argv[]);
-
-int commandInit(void);
-void commandCleanup(void);
-
-/*
- * Command management
- */
-
-struct Command;
-typedef struct Command Command;
-
-typedef enum {
-    CMD_ARGS_UNKNOWN = -1,
-    CMD_ARGS_BOOLEAN = 0,
-    CMD_ARGS_WORDS
-} CommandArgumentType;
-
-int registerCommand(const char *name,
-        CommandArgumentType argType, CommandHook hook, void *cookie);
-
-Command *findCommand(const char *name);
-
-CommandArgumentType getCommandArgumentType(Command *cmd);
-
-int callCommand(Command *cmd, int argc, const char *argv[]);
-int callBooleanCommand(Command *cmd, bool arg);
-
-/*
- * Function management
- */
-
-typedef int (*FunctionHook)(const char *name, void *cookie,
-                                int argc, const char *argv[],
-                                char **result, size_t *resultLen);
-
-struct Function;
-typedef struct Function Function;
-
-int registerFunction(const char *name, FunctionHook hook, void *cookie);
-
-Function *findFunction(const char *name);
-
-int callFunction(Function *fn, int argc, const char *argv[],
-        char **result, size_t *resultLen);
-
-#endif  // AMEND_COMMANDS_H_
diff --git a/amend/execute.c b/amend/execute.c
deleted file mode 100644
index 9162ad6..0000000
--- a/amend/execute.c
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#undef NDEBUG
-#include <assert.h>
-#include "ast.h"
-#include "execute.h"
-
-typedef struct {
-    int c;
-    const char **v;
-} StringList;
-
-static int execBooleanValue(ExecContext *ctx,
-        const AmBooleanValue *booleanValue, bool *result);
-static int execStringValue(ExecContext *ctx, const AmStringValue *stringValue,
-        const char **result);
-
-static int
-execBooleanExpression(ExecContext *ctx,
-        const AmBooleanExpression *booleanExpression, bool *result)
-{
-    int ret;
-    bool arg1, arg2;
-    bool unary;
-
-    assert(ctx != NULL);
-    assert(booleanExpression != NULL);
-    assert(result != NULL);
-    if (ctx == NULL || booleanExpression == NULL || result == NULL) {
-        return -__LINE__;
-    }
-
-    if (booleanExpression->op == AM_BOP_NOT) {
-        unary = true;
-    } else {
-        unary = false;
-    }
-
-    ret = execBooleanValue(ctx, booleanExpression->arg1, &arg1);
-    if (ret != 0) return ret;
-
-    if (!unary) {
-        ret = execBooleanValue(ctx, booleanExpression->arg2, &arg2);
-        if (ret != 0) return ret;
-    } else {
-        arg2 = false;
-    }
-
-    switch (booleanExpression->op) {
-    case AM_BOP_NOT:
-        *result = !arg1;
-        break;
-    case AM_BOP_EQ:
-        *result = (arg1 == arg2);
-        break;
-    case AM_BOP_NE:
-        *result = (arg1 != arg2);
-        break;
-    case AM_BOP_AND:
-        *result = (arg1 && arg2);
-        break;
-    case AM_BOP_OR:
-        *result = (arg1 || arg2);
-        break;
-    default:
-        return -__LINE__;
-    }
-
-    return 0;
-}
-
-static int
-execFunctionArguments(ExecContext *ctx,
-        const AmFunctionArguments *functionArguments, StringList *result)
-{
-    int ret;
-
-    assert(ctx != NULL);
-    assert(functionArguments != NULL);
-    assert(result != NULL);
-    if (ctx == NULL || functionArguments == NULL || result == NULL) {
-        return -__LINE__;
-    }
-
-    result->c = functionArguments->argc;
-    result->v = (const char **)malloc(result->c * sizeof(const char *));
-    if (result->v == NULL) {
-        result->c = 0;
-        return -__LINE__;
-    }
-
-    int i;
-    for (i = 0; i < functionArguments->argc; i++) {
-        ret = execStringValue(ctx, &functionArguments->argv[i], &result->v[i]);
-        if (ret != 0) {
-            result->c = 0;
-            free(result->v);
-            //TODO: free the individual args, if we're responsible for them.
-            result->v = NULL;
-            return ret;
-        }
-    }
-
-    return 0;
-}
-
-static int
-execFunctionCall(ExecContext *ctx, const AmFunctionCall *functionCall,
-        const char **result)
-{
-    int ret;
-
-    assert(ctx != NULL);
-    assert(functionCall != NULL);
-    assert(result != NULL);
-    if (ctx == NULL || functionCall == NULL || result == NULL) {
-        return -__LINE__;
-    }
-
-    StringList args;
-    ret = execFunctionArguments(ctx, functionCall->args, &args);
-    if (ret != 0) {
-        return ret;
-    }
-
-    ret = callFunction(functionCall->fn, args.c, args.v, (char **)result, NULL);
-    if (ret != 0) {
-        return ret;
-    }
-
-    //TODO: clean up args
-
-    return 0;
-}
-
-static int
-execStringValue(ExecContext *ctx, const AmStringValue *stringValue,
-        const char **result)
-{
-    int ret;
-
-    assert(ctx != NULL);
-    assert(stringValue != NULL);
-    assert(result != NULL);
-    if (ctx == NULL || stringValue == NULL || result == NULL) {
-        return -__LINE__;
-    }
-
-    switch (stringValue->type) {
-    case AM_SVAL_LITERAL:
-        *result = strdup(stringValue->u.literal);
-        break;
-    case AM_SVAL_FUNCTION:
-        ret = execFunctionCall(ctx, stringValue->u.function, result);
-        if (ret != 0) {
-            return ret;
-        }
-        break;
-    default:
-        return -__LINE__;
-    }
-
-    return 0;
-}
-
-static int
-execStringComparisonExpression(ExecContext *ctx,
-        const AmStringComparisonExpression *stringComparisonExpression,
-        bool *result)
-{
-    int ret;
-
-    assert(ctx != NULL);
-    assert(stringComparisonExpression != NULL);
-    assert(result != NULL);
-    if (ctx == NULL || stringComparisonExpression == NULL || result == NULL) {
-        return -__LINE__;
-    }
-
-    const char *arg1, *arg2;
-    ret = execStringValue(ctx, stringComparisonExpression->arg1, &arg1);
-    if (ret != 0) {
-        return ret;
-    }
-    ret = execStringValue(ctx, stringComparisonExpression->arg2, &arg2);
-    if (ret != 0) {
-        return ret;
-    }
-
-    int cmp = strcmp(arg1, arg2);
-
-    switch (stringComparisonExpression->op) {
-    case AM_SOP_LT:
-        *result = (cmp < 0);
-        break;
-    case AM_SOP_LE:
-        *result = (cmp <= 0);
-        break;
-    case AM_SOP_GT:
-        *result = (cmp > 0);
-        break;
-    case AM_SOP_GE:
-        *result = (cmp >= 0);
-        break;
-    case AM_SOP_EQ:
-        *result = (cmp == 0);
-        break;
-    case AM_SOP_NE:
-        *result = (cmp != 0);
-        break;
-    default:
-        return -__LINE__;
-        break;
-    }
-
-    return 0;
-}
-
-static int
-execBooleanValue(ExecContext *ctx, const AmBooleanValue *booleanValue,
-        bool *result)
-{
-    int ret;
-
-    assert(ctx != NULL);
-    assert(booleanValue != NULL);
-    assert(result != NULL);
-    if (ctx == NULL || booleanValue == NULL || result == NULL) {
-        return -__LINE__;
-    }
-
-    switch (booleanValue->type) {
-    case AM_BVAL_EXPRESSION:
-        ret = execBooleanExpression(ctx, &booleanValue->u.expression, result);
-        break;
-    case AM_BVAL_STRING_COMPARISON:
-        ret = execStringComparisonExpression(ctx,
-                &booleanValue->u.stringComparison, result);
-        break;
-    default:
-        ret = -__LINE__;
-        break;
-    }
-
-    return ret;
-}
-
-static int
-execCommand(ExecContext *ctx, const AmCommand *command)
-{
-    int ret;
-
-    assert(ctx != NULL);
-    assert(command != NULL);
-    if (ctx == NULL || command == NULL) {
-        return -__LINE__;
-    }
-
-    CommandArgumentType argType;
-    argType = getCommandArgumentType(command->cmd);
-    switch (argType) {
-    case CMD_ARGS_BOOLEAN:
-        {
-            bool bVal;
-            ret = execBooleanValue(ctx, command->args->u.b, &bVal);
-            if (ret == 0) {
-                ret = callBooleanCommand(command->cmd, bVal);
-            }
-        }
-        break;
-    case CMD_ARGS_WORDS:
-        {
-            AmWordList *words = command->args->u.w;
-            ret = callCommand(command->cmd, words->argc, words->argv);
-        }
-        break;
-    default:
-        ret = -__LINE__;
-        break;
-    }
-
-    return ret;
-}
-
-int
-execCommandList(ExecContext *ctx, const AmCommandList *commandList)
-{
-    int i;
-    for (i = 0; i < commandList->commandCount; i++) {
-        int ret = execCommand(ctx, commandList->commands[i]);
-        if (ret != 0) {
-            int line = commandList->commands[i]->line;
-            return line > 0 ? line : ret;
-        }
-    }
-
-    return 0;
-}
diff --git a/amend/execute.h b/amend/execute.h
deleted file mode 100644
index 3becb48..0000000
--- a/amend/execute.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2007 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 AMEND_EXECUTE_H_
-#define AMEND_EXECUTE_H_
-
-typedef struct ExecContext ExecContext;
-
-/* Returns 0 on success, otherwise the line number that failed. */
-int execCommandList(ExecContext *ctx, const AmCommandList *commandList);
-
-#endif  // AMEND_EXECUTE_H_
diff --git a/amend/lexer.h b/amend/lexer.h
deleted file mode 100644
index fc716fd..0000000
--- a/amend/lexer.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2007 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 AMEND_LEXER_H_
-#define AMEND_LEXER_H_
-
-#define AMEND_LEXER_BUFFER_INPUT 1
-
-void yyerror(const char *msg);
-int yylex(void);
-
-#if AMEND_LEXER_BUFFER_INPUT
-void setLexerInputBuffer(const char *buf, size_t buflen);
-#else
-#include <stdio.h>
-void yyset_in(FILE *in_str);
-#endif
-
-const char *tokenToString(int token);
-
-typedef enum {
-    AM_UNKNOWN_ARGS,
-    AM_WORD_ARGS,
-    AM_BOOLEAN_ARGS,
-} AmArgumentType;
-
-void setLexerArgumentType(AmArgumentType type);
-int getLexerLineNumber(void);
-
-#endif  // AMEND_LEXER_H_
diff --git a/amend/lexer.l b/amend/lexer.l
deleted file mode 100644
index 80896d1..0000000
--- a/amend/lexer.l
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-%{
-    #include <stdio.h>
-    #include <stdlib.h>
-    #include "ast.h"
-    #include "lexer.h"
-    #include "parser.h"
-
-    const char *tokenToString(int token)
-    {
-        static char scratch[128];
-
-        switch (token) {
-        case TOK_AND:
-            return "&&";
-        case TOK_OR:
-            return "||";
-        case TOK_EQ:
-            return "==";
-        case TOK_NE:
-            return "!=";
-        case TOK_GE:
-            return ">=";
-        case TOK_LE:
-            return "<=";
-        case TOK_EOF:
-            return "EOF";
-        case TOK_EOL:
-            return "EOL\n";
-        case TOK_STRING:
-            snprintf(scratch, sizeof(scratch),
-                    "STRING<%s>", yylval.literalString);
-            return scratch;
-        case TOK_IDENTIFIER:
-            snprintf(scratch, sizeof(scratch), "IDENTIFIER<%s>",
-                    yylval.literalString);
-            return scratch;
-        case TOK_WORD:
-            snprintf(scratch, sizeof(scratch), "WORD<%s>",
-                    yylval.literalString);
-            return scratch;
-        default:
-            if (token > ' ' && token <= '~') {
-                scratch[0] = (char)token;
-                scratch[1] = '\0';
-            } else {
-                snprintf(scratch, sizeof(scratch), "??? <%d>", token);
-            }
-            return scratch;
-        }
-    }
-
-    typedef struct {
-        char *value;
-        char *nextc;
-        unsigned int alloc_size;
-    } AmString;
-
-    static int addCharToString(AmString *str, char c)
-    {
-        if ((unsigned int)(str->nextc - str->value) >= str->alloc_size) {
-            char *new_value;
-            unsigned int new_size;
-
-            new_size = (str->alloc_size + 1) * 2;
-            if (new_size < 64) {
-                new_size = 64;
-            }
-
-            new_value = (char *)realloc(str->value, new_size);
-            if (new_value == NULL) {
-                yyerror("out of memory");
-                return -1;
-            }
-            str->nextc = str->nextc - str->value + new_value;
-            str->value = new_value;
-            str->alloc_size = new_size;
-        }
-        *str->nextc++ = c;
-        return 0;
-    }
-
-    static int setString(AmString *str, const char *p)
-    {
-        str->nextc = str->value;
-        while (*p != '\0') {
-//TODO: add the whole string at once
-            addCharToString(str, *p++);
-        }
-        return addCharToString(str, '\0');
-    }
-
-    static AmString gStr = { NULL, NULL, 0 };
-    static int gLineNumber = 1;
-    static AmArgumentType gArgumentType = AM_UNKNOWN_ARGS;
-    static const char *gErrorMessage = NULL;
-
-#if AMEND_LEXER_BUFFER_INPUT
-    static const char *gInputBuffer;
-    static const char *gInputBufferNext;
-    static const char *gInputBufferEnd;
-
-# define YY_INPUT(buf, result, max_size) \
-    do { \
-        int nbytes = gInputBufferEnd - gInputBufferNext; \
-        if (nbytes > 0) { \
-            if (nbytes > max_size) { \
-                nbytes = max_size; \
-            } \
-            memcpy(buf, gInputBufferNext, nbytes); \
-            gInputBufferNext += nbytes; \
-            result = nbytes; \
-        } else { \
-            result = YY_NULL; \
-        } \
-    } while (false)
-#endif  // AMEND_LEXER_BUFFER_INPUT
-
-%}
-
-%option noyywrap
-
-%x QUOTED_STRING BOOLEAN WORDS
-
-ident [a-zA-Z_][a-zA-Z_0-9]*
-word [^ \t\r\n"]+
-
-%%
-    /* This happens at the beginning of each call to yylex().
-     */
-    if (gArgumentType == AM_WORD_ARGS) {
-        BEGIN(WORDS);
-    } else if (gArgumentType == AM_BOOLEAN_ARGS) {
-        BEGIN(BOOLEAN);
-    }
-
-        /*xxx require everything to be 7-bit-clean, printable characters */
-<INITIAL>{
-        {ident}/[ \t\r\n] {
-                /* The only token we recognize in the initial
-                 * state is an identifier followed by whitespace.
-                 */
-                setString(&gStr, yytext);
-                yylval.literalString = gStr.value;
-                return TOK_IDENTIFIER;
-            }
-    }
-
-<BOOLEAN>{
-        {ident} {
-                /* Non-quoted identifier-style string */
-                setString(&gStr, yytext);
-                yylval.literalString = gStr.value;
-                return TOK_IDENTIFIER;
-            }
-        "&&"    return TOK_AND;
-        "||"    return TOK_OR;
-        "=="    return TOK_EQ;
-        "!="    return TOK_NE;
-        ">="    return TOK_GE;
-        "<="    return TOK_LE;
-        [<>()!,] return yytext[0];
-    }
-
-    /* Double-quoted string handling */
-
-<WORDS,BOOLEAN>\"  {
-        /* Initial quote */
-        gStr.nextc = gStr.value;
-        BEGIN(QUOTED_STRING);
-    }
-
-<QUOTED_STRING>{
-        \"  {
-                /* Closing quote */
-                BEGIN(INITIAL);
-                addCharToString(&gStr, '\0');
-                yylval.literalString = gStr.value;
-                if (gArgumentType == AM_WORD_ARGS) {
-                    return TOK_WORD;
-                } else {
-                    return TOK_STRING;
-                }
-            }
-
-        <<EOF>> |
-        \n  {
-                /* Unterminated string */
-                yyerror("unterminated string");
-                return TOK_ERROR;
-            }
-
-        \\\" {
-                /* Escaped quote */
-                addCharToString(&gStr, '"');
-            }
-
-        \\\\ {
-                /* Escaped backslash */
-                addCharToString(&gStr, '\\');
-            }
-
-        \\. {
-                /* No other escapes allowed. */
-                gErrorMessage = "illegal escape";
-                return TOK_ERROR;
-            }
-
-        [^\\\n\"]+ {
-                /* String contents */
-                char *p = yytext;
-                while (*p != '\0') {
-        /* TODO: add the whole string at once */
-                    addCharToString(&gStr, *p++);
-                }
-            }
-    }
-
-<WORDS>{
-        /*xxx look out for backslashes; escape backslashes and quotes */
-        /*xxx if a quote is right against a char, we should append */
-        {word} {
-                /* Whitespace-separated word */
-                setString(&gStr, yytext);
-                yylval.literalString = gStr.value;
-                return TOK_WORD;
-            }
-    }
-
-<INITIAL,WORDS,BOOLEAN>{
-        \n  {
-                /* Count lines */
-                gLineNumber++;
-                gArgumentType = AM_UNKNOWN_ARGS;
-                BEGIN(INITIAL);
-                return TOK_EOL;
-            }
-
-        /*xxx backslashes to extend lines? */
-            /* Skip whitespace and comments.
-             */
-        [ \t\r]+ ;
-        #.*      ;
-
-        .   {
-                /* Fail on anything we didn't expect. */
-                gErrorMessage = "unexpected character";
-                return TOK_ERROR;
-            }
-    }
-%%
-
-void
-yyerror(const char *msg)
-{
-    if (!strcmp(msg, "syntax error") && gErrorMessage != NULL) {
-        msg = gErrorMessage;
-        gErrorMessage = NULL;
-    }
-    fprintf(stderr, "line %d: %s at '%s'\n", gLineNumber, msg, yytext);
-}
-
-#if AMEND_LEXER_BUFFER_INPUT
-void
-setLexerInputBuffer(const char *buf, size_t buflen)
-{
-    gLineNumber = 1;
-    gInputBuffer = buf;
-    gInputBufferNext = gInputBuffer;
-    gInputBufferEnd = gInputBuffer + buflen;
-}
-#endif  // AMEND_LEXER_BUFFER_INPUT
-
-void
-setLexerArgumentType(AmArgumentType type)
-{
-    gArgumentType = type;
-}
-
-int
-getLexerLineNumber(void)
-{
-    return gLineNumber;
-}
diff --git a/amend/main.c b/amend/main.c
deleted file mode 100644
index bc9e587..0000000
--- a/amend/main.c
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "ast.h"
-#include "lexer.h"
-#include "parser.h"
-#include "register.h"
-#include "execute.h"
-
-void
-lexTest()
-{
-    int token;
-    do {
-        token = yylex();
-        if (token == 0) {
-            printf(" EOF");
-            fflush(stdout);
-            break;
-        } else {
-            printf(" %s", tokenToString(token));
-            fflush(stdout);
-            if (token == TOK_IDENTIFIER) {
-                if (strcmp(yylval.literalString, "assert") == 0) {
-                    setLexerArgumentType(AM_BOOLEAN_ARGS);
-                } else {
-                    setLexerArgumentType(AM_WORD_ARGS);
-                }
-                do {
-                    token = yylex();
-                    printf(" %s", tokenToString(token));
-                    fflush(stdout);
-                } while (token != TOK_EOL && token != TOK_EOF && token != 0);
-            } else if (token != TOK_EOL) {
-                fprintf(stderr, "syntax error: expected identifier\n");
-                break;
-            }
-        }
-    } while (token != 0);
-    printf("\n");
-}
-
-void
-usage()
-{
-    printf("usage: amend [--debug-lex|--debug-ast] [<filename>]\n");
-    exit(1);
-}
-
-extern const AmCommandList *gCommands;
-int
-main(int argc, char *argv[])
-{
-    FILE *inputFile = NULL;
-    bool debugLex = false;
-    bool debugAst = false;
-    const char *fileName = NULL;
-    int err;
-
-#if 1
-    extern int test_symtab(void);
-    int ret = test_symtab();
-    if (ret != 0) {
-        fprintf(stderr, "test_symtab() failed: %d\n", ret);
-        exit(ret);
-    }
-    extern int test_cmd_fn(void);
-    ret = test_cmd_fn();
-    if (ret != 0) {
-        fprintf(stderr, "test_cmd_fn() failed: %d\n", ret);
-        exit(ret);
-    }
-#endif
-
-    argc--;
-    argv++;
-    while (argc > 0) {
-        if (strcmp("--debug-lex", argv[0]) == 0) {
-            debugLex = true;
-        } else if (strcmp("--debug-ast", argv[0]) == 0) {
-            debugAst = true;
-        } else if (argv[0][0] == '-') {
-            fprintf(stderr, "amend: Unknown option \"%s\"\n", argv[0]);
-            usage();
-        } else {
-            fileName = argv[0];
-        }
-        argc--;
-        argv++;
-    }
-
-    if (fileName != NULL) {
-        inputFile = fopen(fileName, "r");
-        if (inputFile == NULL) {
-            fprintf(stderr, "amend: Can't open input file '%s'\n", fileName);
-            usage();
-        }
-    }
-
-    commandInit();
-//xxx clean up
-
-    err = registerUpdateCommands();
-    if (err < 0) {
-        fprintf(stderr, "amend: Error registering commands: %d\n", err);
-        exit(-err);
-    }
-    err = registerUpdateFunctions();
-    if (err < 0) {
-        fprintf(stderr, "amend: Error registering functions: %d\n", err);
-        exit(-err);
-    }
-
-#if AMEND_LEXER_BUFFER_INPUT
-    if (inputFile == NULL) {
-        fprintf(stderr, "amend: No input file\n");
-        usage();
-    }
-    char *fileData;
-    int fileDataLen;
-    fseek(inputFile, 0, SEEK_END);
-    fileDataLen = ftell(inputFile);
-    rewind(inputFile);
-    if (fileDataLen < 0) {
-        fprintf(stderr, "amend: Can't get file length\n");
-        exit(2);
-    } else if (fileDataLen == 0) {
-        printf("amend: Empty input file\n");
-        exit(0);
-    }
-    fileData = (char *)malloc(fileDataLen + 1);
-    if (fileData == NULL) {
-        fprintf(stderr, "amend: Can't allocate %d bytes\n", fileDataLen + 1);
-        exit(2);
-    }
-    size_t nread = fread(fileData, 1, fileDataLen, inputFile);
-    if (nread != (size_t)fileDataLen) {
-        fprintf(stderr, "amend: Didn't read %d bytes, only %zd\n", fileDataLen,
-                nread);
-        exit(2);
-    }
-    fileData[fileDataLen] = '\0';
-    setLexerInputBuffer(fileData, fileDataLen);
-#else
-    if (inputFile == NULL) {
-        inputFile = stdin;
-    }
-    yyset_in(inputFile);
-#endif
-
-    if (debugLex) {
-        lexTest();
-    } else {
-        int ret = yyparse();
-        if (ret != 0) {
-            fprintf(stderr, "amend: Parse failed (%d)\n", ret);
-            exit(2);
-        } else {
-            if (debugAst) {
-                dumpCommandList(gCommands);
-            }
-printf("amend: Parse successful.\n");
-            ret = execCommandList((ExecContext *)1, gCommands);
-            if (ret != 0) {
-                fprintf(stderr, "amend: Execution failed (%d)\n", ret);
-                exit(3);
-            }
-printf("amend: Execution successful.\n");
-        }
-    }
-
-    return 0;
-}
diff --git a/amend/parser.h b/amend/parser.h
deleted file mode 100644
index aeb8657..0000000
--- a/amend/parser.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2007 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 AMEND_PARSER_H_
-#define AMEND_PARSER_H_
-
-#include "parser_y.h"
-
-int yyparse(void);
-
-#endif  // AMEND_PARSER_H_
diff --git a/amend/parser_y.y b/amend/parser_y.y
deleted file mode 100644
index b634016..0000000
--- a/amend/parser_y.y
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-%{
-#undef NDEBUG
-    #include <stdlib.h>
-    #include <string.h>
-    #include <assert.h>
-    #include <stdio.h>
-    #include "ast.h"
-    #include "lexer.h"
-    #include "commands.h"
-
-    void yyerror(const char *msg);
-    int yylex(void);
-
-#define STRING_COMPARISON(out, a1, sop, a2) \
-    do { \
-        out = (AmBooleanValue *)malloc(sizeof(AmBooleanValue)); \
-        if (out == NULL) { \
-            YYABORT; \
-        } \
-        out->type = AM_BVAL_STRING_COMPARISON; \
-        out->u.stringComparison.op = sop; \
-        out->u.stringComparison.arg1 = a1; \
-        out->u.stringComparison.arg2 = a2; \
-    } while (false)
-
-#define BOOLEAN_EXPRESSION(out, a1, bop, a2) \
-    do { \
-        out = (AmBooleanValue *)malloc(sizeof(AmBooleanValue)); \
-        if (out == NULL) { \
-            YYABORT; \
-        } \
-        out->type = AM_BVAL_EXPRESSION; \
-        out->u.expression.op = bop; \
-        out->u.expression.arg1 = a1; \
-        out->u.expression.arg2 = a2; \
-    } while (false)
-
-AmCommandList *gCommands = NULL;
-%}
-
-%start  lines
-
-%union  {
-        char *literalString;
-        AmFunctionArgumentBuilder *functionArgumentBuilder;
-        AmFunctionArguments *functionArguments;
-        AmFunctionCall *functionCall;
-        AmStringValue *stringValue;
-        AmBooleanValue *booleanValue;
-        AmWordListBuilder *wordListBuilder;
-        AmCommandArguments *commandArguments;
-        AmCommand *command;
-        AmCommandList *commandList;
-    }
-
-%token  TOK_AND TOK_OR TOK_EQ TOK_NE TOK_GE TOK_LE TOK_EOF TOK_EOL TOK_ERROR
-%token  <literalString> TOK_STRING TOK_IDENTIFIER TOK_WORD
-
-%type   <commandList> lines
-%type   <command> command line
-%type   <functionArgumentBuilder> function_arguments
-%type   <functionArguments> function_arguments_or_empty
-%type   <functionCall> function_call
-%type   <literalString> function_name
-%type   <stringValue> string_value
-%type   <booleanValue> boolean_expression
-%type   <wordListBuilder> word_list
-%type   <commandArguments> arguments
-
-/* Operator precedence, weakest to strongest.
- * Same as C/Java precedence.
- */
-
-%left   TOK_OR
-%left   TOK_AND
-%left   TOK_EQ TOK_NE
-%left   '<' '>' TOK_LE TOK_GE
-%right   '!'
-
-%%
-
-lines :     /* empty */
-                {
-                    $$ = (AmCommandList *)malloc(sizeof(AmCommandList));
-                    if ($$ == NULL) {
-                        YYABORT;
-                    }
-gCommands = $$;
-                    $$->arraySize = 64;
-                    $$->commandCount = 0;
-                    $$->commands = (AmCommand **)malloc(
-                            sizeof(AmCommand *) * $$->arraySize);
-                    if ($$->commands == NULL) {
-                        YYABORT;
-                    }
-                }
-        |   lines line
-                {
-                    if ($2 != NULL) {
-                        if ($1->commandCount >= $1->arraySize) {
-                            AmCommand **newArray;
-                            newArray = (AmCommand **)realloc($$->commands,
-                                sizeof(AmCommand *) * $$->arraySize * 2);
-                            if (newArray == NULL) {
-                                YYABORT;
-                            }
-                            $$->commands = newArray;
-                            $$->arraySize *= 2;
-                        }
-                        $1->commands[$1->commandCount++] = $2;
-                    }
-                }
-        ;
-
-line :      line_ending
-                {
-                    $$ = NULL;  /* ignore blank lines */
-                }
-        |   command arguments line_ending
-                {
-                    $$ = $1;
-                    $$->args = $2;
-                    setLexerArgumentType(AM_UNKNOWN_ARGS);
-                }
-        ;
-
-command :   TOK_IDENTIFIER
-                {
-                    Command *cmd = findCommand($1);
-                    if (cmd == NULL) {
-                        fprintf(stderr, "Unknown command \"%s\"\n", $1);
-                        YYABORT;
-                    }
-                    $$ = (AmCommand *)malloc(sizeof(AmCommand));
-                    if ($$ == NULL) {
-                        YYABORT;
-                    }
-                    $$->line = getLexerLineNumber();
-                    $$->name = strdup($1);
-                    if ($$->name == NULL) {
-                        YYABORT;
-                    }
-                    $$->args = NULL;
-                    CommandArgumentType argType = getCommandArgumentType(cmd);
-                    if (argType == CMD_ARGS_BOOLEAN) {
-                        setLexerArgumentType(AM_BOOLEAN_ARGS);
-                    } else {
-                        setLexerArgumentType(AM_WORD_ARGS);
-                    }
-                    $$->cmd = cmd;
-                }
-        ;
-
-line_ending :
-            TOK_EOL
-        |   TOK_EOF
-        ;
-
-arguments : boolean_expression
-                {
-                    $$ = (AmCommandArguments *)malloc(
-                            sizeof(AmCommandArguments));
-                    if ($$ == NULL) {
-                        YYABORT;
-                    }
-                    $$->booleanArgs = true;
-                    $$->u.b = $1;
-                }
-        |   word_list
-                {
-                    /* Convert the builder list into an array.
-                     * Do it in reverse order; the words were pushed
-                     * onto the list in LIFO order.
-                     */
-                    AmWordList *w = (AmWordList *)malloc(sizeof(AmWordList));
-                    if (w == NULL) {
-                        YYABORT;
-                    }
-                    if ($1 != NULL) {
-                        AmWordListBuilder *words = $1;
-
-                        w->argc = words->wordCount;
-                        w->argv = (const char **)malloc(w->argc *
-                                        sizeof(char *));
-                        if (w->argv == NULL) {
-                            YYABORT;
-                        }
-                        int i;
-                        for (i = w->argc; words != NULL && i > 0; --i) {
-                            AmWordListBuilder *f = words;
-                            w->argv[i-1] = words->word;
-                            words = words->next;
-                            free(f);
-                        }
-                        assert(i == 0);
-                        assert(words == NULL);
-                    } else {
-                        w->argc = 0;
-                        w->argv = NULL;
-                    }
-                    $$ = (AmCommandArguments *)malloc(
-                            sizeof(AmCommandArguments));
-                    if ($$ == NULL) {
-                        YYABORT;
-                    }
-                    $$->booleanArgs = false;
-                    $$->u.w = w;
-                }
-        ;
-
-word_list : /* empty */
-                { $$ = NULL; }
-        |   word_list TOK_WORD
-                {
-                    if ($1 == NULL) {
-                        $$ = (AmWordListBuilder *)malloc(
-                                sizeof(AmWordListBuilder));
-                        if ($$ == NULL) {
-                            YYABORT;
-                        }
-                        $$->next = NULL;
-                        $$->wordCount = 1;
-                    } else {
-                        $$ = (AmWordListBuilder *)malloc(
-                                sizeof(AmWordListBuilder));
-                        if ($$ == NULL) {
-                            YYABORT;
-                        }
-                        $$->next = $1;
-                        $$->wordCount = $$->next->wordCount + 1;
-                    }
-                    $$->word = strdup($2);
-                    if ($$->word == NULL) {
-                        YYABORT;
-                    }
-                }
-        ;
-
-boolean_expression :
-            '!' boolean_expression
-                {
-                    $$ = (AmBooleanValue *)malloc(sizeof(AmBooleanValue));
-                    if ($$ == NULL) {
-                        YYABORT;
-                    }
-                    $$->type = AM_BVAL_EXPRESSION;
-                    $$->u.expression.op = AM_BOP_NOT;
-                    $$->u.expression.arg1 = $2;
-                    $$->u.expression.arg2 = NULL;
-                }
-    /* TODO: if both expressions are literals, evaluate now */
-        |   boolean_expression TOK_AND boolean_expression
-                { BOOLEAN_EXPRESSION($$, $1, AM_BOP_AND, $3); }
-        |   boolean_expression TOK_OR boolean_expression
-                { BOOLEAN_EXPRESSION($$, $1, AM_BOP_OR, $3); }
-        |   boolean_expression TOK_EQ boolean_expression
-                { BOOLEAN_EXPRESSION($$, $1, AM_BOP_EQ, $3); }
-        |   boolean_expression TOK_NE boolean_expression
-                { BOOLEAN_EXPRESSION($$, $1, AM_BOP_NE, $3); }
-        |   '(' boolean_expression ')'
-                { $$ = $2; }
-    /* TODO: if both strings are literals, evaluate now */
-        |   string_value '<' string_value
-                { STRING_COMPARISON($$, $1, AM_SOP_LT, $3); }
-        |   string_value '>' string_value
-                { STRING_COMPARISON($$, $1, AM_SOP_GT, $3); }
-        |   string_value TOK_EQ string_value
-                { STRING_COMPARISON($$, $1, AM_SOP_EQ, $3); }
-        |   string_value TOK_NE string_value
-                { STRING_COMPARISON($$, $1, AM_SOP_NE, $3); }
-        |   string_value TOK_LE string_value
-                { STRING_COMPARISON($$, $1, AM_SOP_LE, $3); }
-        |   string_value TOK_GE string_value
-                { STRING_COMPARISON($$, $1, AM_SOP_GE, $3); }
-        ;
-
-string_value :
-            TOK_IDENTIFIER
-                {
-                    $$ = (AmStringValue *)malloc(sizeof(AmStringValue));
-                    if ($$ == NULL) {
-                        YYABORT;
-                    }
-                    $$->type = AM_SVAL_LITERAL;
-                    $$->u.literal = strdup($1);
-                    if ($$->u.literal == NULL) {
-                        YYABORT;
-                    }
-                }
-        |   TOK_STRING
-                {
-                    $$ = (AmStringValue *)malloc(sizeof(AmStringValue));
-                    if ($$ == NULL) {
-                        YYABORT;
-                    }
-                    $$->type = AM_SVAL_LITERAL;
-                    $$->u.literal = strdup($1);
-                    if ($$->u.literal == NULL) {
-                        YYABORT;
-                    }
-                }
-        |   function_call
-                {
-                    $$ = (AmStringValue *)malloc(sizeof(AmStringValue));
-                    if ($$ == NULL) {
-                        YYABORT;
-                    }
-                    $$->type = AM_SVAL_FUNCTION;
-                    $$->u.function = $1;
-                }
-        ;
-
-        /* We can't just say
-         *  TOK_IDENTIFIER '(' function_arguments_or_empty ')'
-         * because parsing function_arguments_or_empty will clobber
-         * the underlying string that yylval.literalString points to.
-         */
-function_call :
-            function_name '(' function_arguments_or_empty ')'
-                {
-                    Function *fn = findFunction($1);
-                    if (fn == NULL) {
-                        fprintf(stderr, "Unknown function \"%s\"\n", $1);
-                        YYABORT;
-                    }
-                    $$ = (AmFunctionCall *)malloc(sizeof(AmFunctionCall));
-                    if ($$ == NULL) {
-                        YYABORT;
-                    }
-                    $$->name = $1;
-                    if ($$->name == NULL) {
-                        YYABORT;
-                    }
-                    $$->fn = fn;
-                    $$->args = $3;
-                }
-        ;
-
-function_name :
-            TOK_IDENTIFIER
-                {
-                    $$ = strdup($1);
-                }
-        ;
-
-function_arguments_or_empty :
-            /* empty */
-                {
-                    $$ = (AmFunctionArguments *)malloc(
-                            sizeof(AmFunctionArguments));
-                    if ($$ == NULL) {
-                        YYABORT;
-                    }
-                    $$->argc = 0;
-                    $$->argv = NULL;
-                }
-        |   function_arguments
-                {
-                    AmFunctionArgumentBuilder *args = $1;
-                    assert(args != NULL);
-
-                    /* Convert the builder list into an array.
-                     * Do it in reverse order; the args were pushed
-                     * onto the list in LIFO order.
-                     */
-                    $$ = (AmFunctionArguments *)malloc(
-                            sizeof(AmFunctionArguments));
-                    if ($$ == NULL) {
-                        YYABORT;
-                    }
-                    $$->argc = args->argCount;
-                    $$->argv = (AmStringValue *)malloc(
-                            $$->argc * sizeof(AmStringValue));
-                    if ($$->argv == NULL) {
-                        YYABORT;
-                    }
-                    int i;
-                    for (i = $$->argc; args != NULL && i > 0; --i) {
-                        AmFunctionArgumentBuilder *f = args;
-                        $$->argv[i-1] = *args->arg;
-                        args = args->next;
-                        free(f->arg);
-                        free(f);
-                    }
-                    assert(i == 0);
-                    assert(args == NULL);
-                }
-        ;
-
-function_arguments :
-            string_value
-                {
-                    $$ = (AmFunctionArgumentBuilder *)malloc(
-                            sizeof(AmFunctionArgumentBuilder));
-                    if ($$ == NULL) {
-                        YYABORT;
-                    }
-                    $$->next = NULL;
-                    $$->argCount = 1;
-                    $$->arg = $1;
-                }
-        |   function_arguments ',' string_value
-                {
-                    $$ = (AmFunctionArgumentBuilder *)malloc(
-                            sizeof(AmFunctionArgumentBuilder));
-                    if ($$ == NULL) {
-                        YYABORT;
-                    }
-                    $$->next = $1;
-                    $$->argCount = $$->next->argCount + 1;
-                    $$->arg = $3;
-                }
-        ;
-    /* xxx this whole tool needs to be hardened */
diff --git a/amend/register.c b/amend/register.c
deleted file mode 100644
index 0f44b74..0000000
--- a/amend/register.c
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#undef NDEBUG
-#include <assert.h>
-#include "commands.h"
-
-#include "register.h"
-
-#define UNUSED(p)   ((void)(p))
-
-#define CHECK_BOOL() \
-    do { \
-        assert(argv == NULL); \
-        if (argv != NULL) return -1; \
-        assert(argc == true || argc == false); \
-        if (argc != true && argc != false) return -1; \
-    } while (false)
-
-#define CHECK_WORDS() \
-    do { \
-        assert(argc >= 0); \
-        if (argc < 0) return -1; \
-        assert(argc == 0 || argv != NULL); \
-        if (argc != 0 && argv == NULL) return -1; \
-    } while (false)
-
-#define CHECK_FN() \
-    do { \
-        CHECK_WORDS(); \
-        assert(result != NULL);            \
-        if (result == NULL) return -1;     \
-    } while (false)
-
-
-/*
- * Command definitions
- */
-
-/* assert <boolexpr>
- */
-static int
-cmd_assert(const char *name, void *cookie, int argc, const char *argv[])
-{
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_BOOL();
-
-    /* If our argument is false, return non-zero (failure)
-     * If our argument is true, return zero (success)
-     */
-    if (argc) {
-        return 0;
-    } else {
-        return 1;
-    }
-}
-
-/* format <root>
- */
-static int
-cmd_format(const char *name, void *cookie, int argc, const char *argv[])
-{
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_WORDS();
-//xxx
-    return -1;
-}
-
-/* copy_dir <srcdir> <dstdir>
- */
-static int
-cmd_copy_dir(const char *name, void *cookie, int argc, const char *argv[])
-{
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_WORDS();
-//xxx
-    return -1;
-}
-
-/* mark <resource> dirty|clean
- */
-static int
-cmd_mark(const char *name, void *cookie, int argc, const char *argv[])
-{
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_WORDS();
-//xxx when marking, save the top-level hash at the mark point
-//    so we can retry on failure.  Otherwise the hashes won't match,
-//    or someone could intentionally dirty the FS to force a downgrade
-//xxx
-    return -1;
-}
-
-/* done
- */
-static int
-cmd_done(const char *name, void *cookie, int argc, const char *argv[])
-{
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_WORDS();
-//xxx
-    return -1;
-}
-
-int
-registerUpdateCommands()
-{
-    int ret;
-
-    ret = registerCommand("assert", CMD_ARGS_BOOLEAN, cmd_assert, NULL);
-    if (ret < 0) return ret;
-
-    ret = registerCommand("copy_dir", CMD_ARGS_WORDS, cmd_copy_dir, NULL);
-    if (ret < 0) return ret;
-
-    ret = registerCommand("format", CMD_ARGS_WORDS, cmd_format, NULL);
-    if (ret < 0) return ret;
-
-    ret = registerCommand("mark", CMD_ARGS_WORDS, cmd_mark, NULL);
-    if (ret < 0) return ret;
-
-    ret = registerCommand("done", CMD_ARGS_WORDS, cmd_done, NULL);
-    if (ret < 0) return ret;
-
-    return 0;
-}
-
-
-/*
- * Function definitions
- */
-
-/* update_forced()
- *
- * Returns "true" if some system setting has determined that
- * the update should happen no matter what.
- */
-static int
-fn_update_forced(const char *name, void *cookie, int argc, const char *argv[],
-        char **result, size_t *resultLen)
-{
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_FN();
-
-    if (argc != 0) {
-        fprintf(stderr, "%s: wrong number of arguments (%d)\n",
-                name, argc);
-        return 1;
-    }
-
-    //xxx check some global or property
-    bool force = true;
-    if (force) {
-        *result = strdup("true");
-    } else {
-        *result = strdup("");
-    }
-    if (resultLen != NULL) {
-        *resultLen = strlen(*result);
-    }
-
-    return 0;
-}
-
-/* get_mark(<resource>)
- *
- * Returns the current mark associated with the provided resource.
- */
-static int
-fn_get_mark(const char *name, void *cookie, int argc, const char *argv[],
-        char **result, size_t *resultLen)
-{
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_FN();
-
-    if (argc != 1) {
-        fprintf(stderr, "%s: wrong number of arguments (%d)\n",
-                name, argc);
-        return 1;
-    }
-
-    //xxx look up the value
-    *result = strdup("");
-    if (resultLen != NULL) {
-        *resultLen = strlen(*result);
-    }
-
-    return 0;
-}
-
-/* hash_dir(<path-to-directory>)
- */
-static int
-fn_hash_dir(const char *name, void *cookie, int argc, const char *argv[],
-        char **result, size_t *resultLen)
-{
-    int ret = -1;
-
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_FN();
-
-    const char *dir;
-    if (argc != 1) {
-        fprintf(stderr, "%s: wrong number of arguments (%d)\n",
-                name, argc);
-        return 1;
-    } else {
-        dir = argv[0];
-    }
-
-//xxx build and return the string
-    *result = strdup("hashvalue");
-    if (resultLen != NULL) {
-      *resultLen = strlen(*result);
-    }
-    ret = 0;
-
-    return ret;
-}
-
-/* matches(<str>, <str1> [, <strN>...])
- * If <str> matches (strcmp) any of <str1>...<strN>, returns <str>,
- * otherwise returns "".
- *
- * E.g., assert matches(hash_dir("/path"), "hash1", "hash2")
- */
-static int
-fn_matches(const char *name, void *cookie, int argc, const char *argv[],
-        char **result, size_t *resultLen)
-{
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_FN();
-
-    if (argc < 2) {
-        fprintf(stderr, "%s: not enough arguments (%d < 2)\n",
-                name, argc);
-        return 1;
-    }
-
-    int i;
-    for (i = 1; i < argc; i++) {
-        if (strcmp(argv[0], argv[i]) == 0) {
-            *result = strdup(argv[0]);
-            if (resultLen != NULL) {
-                *resultLen = strlen(*result);
-            }
-            return 0;
-        }
-    }
-
-    *result = strdup("");
-    if (resultLen != NULL) {
-        *resultLen = 1;
-    }
-    return 0;
-}
-
-/* concat(<str>, <str1> [, <strN>...])
- * Returns the concatenation of all strings.
- */
-static int
-fn_concat(const char *name, void *cookie, int argc, const char *argv[],
-        char **result, size_t *resultLen)
-{
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_FN();
-
-    size_t totalLen = 0;
-    int i;
-    for (i = 0; i < argc; i++) {
-        totalLen += strlen(argv[i]);
-    }
-
-    char *s = (char *)malloc(totalLen + 1);
-    if (s == NULL) {
-        return -1;
-    }
-    s[totalLen] = '\0';
-    for (i = 0; i < argc; i++) {
-        //TODO: keep track of the end to avoid walking the string each time
-        strcat(s, argv[i]);
-    }
-    *result = s;
-    if (resultLen != NULL) {
-        *resultLen = strlen(s);
-    }
-
-    return 0;
-}
-
-int
-registerUpdateFunctions()
-{
-    int ret;
-
-    ret = registerFunction("update_forced", fn_update_forced, NULL);
-    if (ret < 0) return ret;
-
-    ret = registerFunction("get_mark", fn_get_mark, NULL);
-    if (ret < 0) return ret;
-
-    ret = registerFunction("hash_dir", fn_hash_dir, NULL);
-    if (ret < 0) return ret;
-
-    ret = registerFunction("matches", fn_matches, NULL);
-    if (ret < 0) return ret;
-
-    ret = registerFunction("concat", fn_concat, NULL);
-    if (ret < 0) return ret;
-
-    return 0;
-}
diff --git a/amend/register.h b/amend/register.h
deleted file mode 100644
index 1d9eacb..0000000
--- a/amend/register.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2007 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 AMEND_REGISTER_H_
-#define AMEND_REGISTER_H_
-
-int registerUpdateCommands(void);
-int registerUpdateFunctions(void);
-
-#endif  // AMEND_REGISTER_H_
diff --git a/amend/symtab.c b/amend/symtab.c
deleted file mode 100644
index 835d2fc..0000000
--- a/amend/symtab.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include "symtab.h"
-
-#define DEFAULT_TABLE_SIZE 16
-
-typedef struct {
-    char *symbol;
-    const void *cookie;
-    unsigned int flags;
-} SymbolTableEntry;
-
-struct SymbolTable {
-    SymbolTableEntry *table;
-    int numEntries;
-    int maxSize;
-};
-
-SymbolTable *
-createSymbolTable()
-{
-    SymbolTable *tab;
-
-    tab = (SymbolTable *)malloc(sizeof(SymbolTable));
-    if (tab != NULL) {
-        tab->numEntries = 0;
-        tab->maxSize = DEFAULT_TABLE_SIZE;
-        tab->table = (SymbolTableEntry *)malloc(
-                            tab->maxSize * sizeof(SymbolTableEntry));
-        if (tab->table == NULL) {
-            free(tab);
-            tab = NULL;
-        }
-    }
-    return tab;
-}
-
-void
-deleteSymbolTable(SymbolTable *tab)
-{
-    if (tab != NULL) {
-        while (tab->numEntries > 0) {
-            free(tab->table[--tab->numEntries].symbol);
-        }
-        free(tab->table);
-    }
-}
-
-void *
-findInSymbolTable(SymbolTable *tab, const char *symbol, unsigned int flags)
-{
-    int i;
-
-    if (tab == NULL || symbol == NULL) {
-        return NULL;
-    }
-
-    // TODO: Sort the table and binary search
-    for (i = 0; i < tab->numEntries; i++) {
-        if (strcmp(tab->table[i].symbol, symbol) == 0 &&
-                tab->table[i].flags == flags)
-        {
-            return (void *)tab->table[i].cookie;
-        }
-    }
-
-    return NULL;
-}
-
-int
-addToSymbolTable(SymbolTable *tab, const char *symbol, unsigned int flags,
-        const void *cookie)
-{
-    if (tab == NULL || symbol == NULL || cookie == NULL) {
-        return -1;
-    }
-
-    /* Make sure that this symbol isn't already in the table.
-     */
-    if (findInSymbolTable(tab, symbol, flags) != NULL) {
-        return -2;
-    }
-
-    /* Make sure there's enough space for the new entry.
-     */
-    if (tab->numEntries == tab->maxSize) {
-        SymbolTableEntry *newTable;
-        int newSize;
-
-        newSize = tab->numEntries * 2;
-        if (newSize < DEFAULT_TABLE_SIZE) {
-            newSize = DEFAULT_TABLE_SIZE;
-        }
-        newTable = (SymbolTableEntry *)realloc(tab->table,
-                            newSize * sizeof(SymbolTableEntry));
-        if (newTable == NULL) {
-            return -1;
-        }
-        tab->maxSize = newSize;
-        tab->table = newTable;
-    }
-
-    /* Insert the new entry.
-     */
-    symbol = strdup(symbol);
-    if (symbol == NULL) {
-        return -1;
-    }
-    // TODO: Sort the table
-    tab->table[tab->numEntries].symbol = (char *)symbol;
-    tab->table[tab->numEntries].cookie = cookie;
-    tab->table[tab->numEntries].flags = flags;
-    tab->numEntries++;
-
-    return 0;
-}
diff --git a/amend/symtab.h b/amend/symtab.h
deleted file mode 100644
index f83c65b..0000000
--- a/amend/symtab.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2007 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 AMEND_SYMTAB_H_
-#define AMEND_SYMTAB_H_
-
-typedef struct SymbolTable SymbolTable;
-
-SymbolTable *createSymbolTable(void);
-
-void deleteSymbolTable(SymbolTable *tab);
-
-/* symbol and cookie must be non-NULL.
- */
-int addToSymbolTable(SymbolTable *tab, const char *symbol, unsigned int flags,
-        const void *cookie);
-
-void *findInSymbolTable(SymbolTable *tab, const char *symbol,
-        unsigned int flags);
-
-#endif  // AMEND_SYMTAB_H_
diff --git a/amend/test_commands.c b/amend/test_commands.c
deleted file mode 100644
index 452f808..0000000
--- a/amend/test_commands.c
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#undef NDEBUG
-#include <assert.h>
-#include "commands.h"
-
-static struct {
-    bool called;
-    const char *name;
-    void *cookie;
-    int argc;
-    const char **argv;
-    int returnValue;
-    char *functionResult;
-} gTestCommandState;
-
-static int
-testCommand(const char *name, void *cookie, int argc, const char *argv[])
-{
-    gTestCommandState.called = true;
-    gTestCommandState.name = name;
-    gTestCommandState.cookie = cookie;
-    gTestCommandState.argc = argc;
-    gTestCommandState.argv = argv;
-    return gTestCommandState.returnValue;
-}
-
-static int
-testFunction(const char *name, void *cookie, int argc, const char *argv[],
-        char **result, size_t *resultLen)
-{
-    gTestCommandState.called = true;
-    gTestCommandState.name = name;
-    gTestCommandState.cookie = cookie;
-    gTestCommandState.argc = argc;
-    gTestCommandState.argv = argv;
-    if (result != NULL) {
-        *result = gTestCommandState.functionResult;
-        if (resultLen != NULL) {
-            *resultLen = strlen(*result);
-        }
-    }
-    return gTestCommandState.returnValue;
-}
-
-static int
-test_commands()
-{
-    Command *cmd;
-    int ret;
-    CommandArgumentType argType;
-
-    ret = commandInit();
-    assert(ret == 0);
-
-    /* Make sure we can't initialize twice.
-     */
-    ret = commandInit();
-    assert(ret < 0);
-
-    /* Try calling with some bad values.
-     */
-    ret = registerCommand(NULL, CMD_ARGS_UNKNOWN, NULL, NULL);
-    assert(ret < 0);
-
-    ret = registerCommand("hello", CMD_ARGS_UNKNOWN, NULL, NULL);
-    assert(ret < 0);
-
-    ret = registerCommand("hello", CMD_ARGS_WORDS, NULL, NULL);
-    assert(ret < 0);
-
-    cmd = findCommand(NULL);
-    assert(cmd == NULL);
-
-    argType = getCommandArgumentType(NULL);
-    assert((int)argType < 0);
-
-    ret = callCommand(NULL, -1, NULL);
-    assert(ret < 0);
-
-    ret = callBooleanCommand(NULL, false);
-    assert(ret < 0);
-
-    /* Register some commands.
-     */
-    ret = registerCommand("one", CMD_ARGS_WORDS, testCommand,
-            &gTestCommandState);
-    assert(ret == 0);
-
-    ret = registerCommand("two", CMD_ARGS_WORDS, testCommand,
-            &gTestCommandState);
-    assert(ret == 0);
-
-    ret = registerCommand("bool", CMD_ARGS_BOOLEAN, testCommand,
-            &gTestCommandState);
-    assert(ret == 0);
-
-    /* Make sure that all of those commands exist and that their
-     * argument types are correct.
-     */
-    cmd = findCommand("one");
-    assert(cmd != NULL);
-    argType = getCommandArgumentType(cmd);
-    assert(argType == CMD_ARGS_WORDS);
-
-    cmd = findCommand("two");
-    assert(cmd != NULL);
-    argType = getCommandArgumentType(cmd);
-    assert(argType == CMD_ARGS_WORDS);
-
-    cmd = findCommand("bool");
-    assert(cmd != NULL);
-    argType = getCommandArgumentType(cmd);
-    assert(argType == CMD_ARGS_BOOLEAN);
-
-    /* Make sure that no similar commands exist.
-     */
-    cmd = findCommand("on");
-    assert(cmd == NULL);
-
-    cmd = findCommand("onee");
-    assert(cmd == NULL);
-
-    /* Make sure that a double insertion fails.
-     */
-    ret = registerCommand("one", CMD_ARGS_WORDS, testCommand,
-            &gTestCommandState);
-    assert(ret < 0);
-
-    /* Make sure that bad args fail.
-     */
-    cmd = findCommand("one");
-    assert(cmd != NULL);
-
-    ret = callCommand(cmd, -1, NULL);   // argc must be non-negative
-    assert(ret < 0);
-
-    ret = callCommand(cmd, 1, NULL);    // argv can't be NULL if argc > 0
-    assert(ret < 0);
-
-    /* Make sure that you can't make a boolean call on a regular command.
-     */
-    cmd = findCommand("one");
-    assert(cmd != NULL);
-
-    ret = callBooleanCommand(cmd, false);
-    assert(ret < 0);
-
-    /* Make sure that you can't make a regular call on a boolean command.
-     */
-    cmd = findCommand("bool");
-    assert(cmd != NULL);
-
-    ret = callCommand(cmd, 0, NULL);
-    assert(ret < 0);
-
-    /* Set up some arguments.
-     */
-    int argc = 4;
-    const char *argv[4] = { "ONE", "TWO", "THREE", "FOUR" };
-
-    /* Make a call and make sure that it occurred.
-     */
-    cmd = findCommand("one");
-    assert(cmd != NULL);
-    memset(&gTestCommandState, 0, sizeof(gTestCommandState));
-    gTestCommandState.called = false;
-    gTestCommandState.returnValue = 25;
-    ret = callCommand(cmd, argc, argv);
-//xxx also try calling with a null argv element (should fail)
-    assert(ret == 25);
-    assert(gTestCommandState.called);
-    assert(strcmp(gTestCommandState.name, "one") == 0);
-    assert(gTestCommandState.cookie == &gTestCommandState);
-    assert(gTestCommandState.argc == argc);
-    assert(gTestCommandState.argv == argv);
-
-    /* Make a boolean call and make sure that it occurred.
-     */
-    cmd = findCommand("bool");
-    assert(cmd != NULL);
-
-    memset(&gTestCommandState, 0, sizeof(gTestCommandState));
-    gTestCommandState.called = false;
-    gTestCommandState.returnValue = 12;
-    ret = callBooleanCommand(cmd, false);
-    assert(ret == 12);
-    assert(gTestCommandState.called);
-    assert(strcmp(gTestCommandState.name, "bool") == 0);
-    assert(gTestCommandState.cookie == &gTestCommandState);
-    assert(gTestCommandState.argc == 0);
-    assert(gTestCommandState.argv == NULL);
-
-    memset(&gTestCommandState, 0, sizeof(gTestCommandState));
-    gTestCommandState.called = false;
-    gTestCommandState.returnValue = 13;
-    ret = callBooleanCommand(cmd, true);
-    assert(ret == 13);
-    assert(gTestCommandState.called);
-    assert(strcmp(gTestCommandState.name, "bool") == 0);
-    assert(gTestCommandState.cookie == &gTestCommandState);
-    assert(gTestCommandState.argc == 1);
-    assert(gTestCommandState.argv == NULL);
-
-    /* Smoke test commandCleanup().
-     */
-    commandCleanup();
-
-    return 0;
-}
-
-static int
-test_functions()
-{
-    Function *fn;
-    int ret;
-
-    ret = commandInit();
-    assert(ret == 0);
-
-    /* Try calling with some bad values.
-     */
-    ret = registerFunction(NULL, NULL, NULL);
-    assert(ret < 0);
-
-    ret = registerFunction("hello", NULL, NULL);
-    assert(ret < 0);
-
-    fn = findFunction(NULL);
-    assert(fn == NULL);
-
-    ret = callFunction(NULL, -1, NULL, NULL, NULL);
-    assert(ret < 0);
-
-    /* Register some functions.
-     */
-    ret = registerFunction("one", testFunction, &gTestCommandState);
-    assert(ret == 0);
-
-    ret = registerFunction("two", testFunction, &gTestCommandState);
-    assert(ret == 0);
-
-    ret = registerFunction("three", testFunction, &gTestCommandState);
-    assert(ret == 0);
-
-    /* Make sure that all of those functions exist.
-     * argument types are correct.
-     */
-    fn = findFunction("one");
-    assert(fn != NULL);
-
-    fn = findFunction("two");
-    assert(fn != NULL);
-
-    fn = findFunction("three");
-    assert(fn != NULL);
-
-    /* Make sure that no similar functions exist.
-     */
-    fn = findFunction("on");
-    assert(fn == NULL);
-
-    fn = findFunction("onee");
-    assert(fn == NULL);
-
-    /* Make sure that a double insertion fails.
-     */
-    ret = registerFunction("one", testFunction, &gTestCommandState);
-    assert(ret < 0);
-
-    /* Make sure that bad args fail.
-     */
-    fn = findFunction("one");
-    assert(fn != NULL);
-
-    // argc must be non-negative
-    ret = callFunction(fn, -1, NULL, (char **)1, NULL);
-    assert(ret < 0);
-
-    // argv can't be NULL if argc > 0
-    ret = callFunction(fn, 1, NULL, (char **)1, NULL);
-    assert(ret < 0);
-
-    // result can't be NULL
-    ret = callFunction(fn, 0, NULL, NULL, NULL);
-    assert(ret < 0);
-
-    /* Set up some arguments.
-     */
-    int argc = 4;
-    const char *argv[4] = { "ONE", "TWO", "THREE", "FOUR" };
-
-    /* Make a call and make sure that it occurred.
-     */
-    char *functionResult;
-    size_t functionResultLen;
-    fn = findFunction("one");
-    assert(fn != NULL);
-    memset(&gTestCommandState, 0, sizeof(gTestCommandState));
-    gTestCommandState.called = false;
-    gTestCommandState.returnValue = 25;
-    gTestCommandState.functionResult = "1234";
-    functionResult = NULL;
-    functionResultLen = 55;
-    ret = callFunction(fn, argc, argv,
-            &functionResult, &functionResultLen);
-//xxx also try calling with a null resultLen arg (should succeed)
-//xxx also try calling with a null argv element (should fail)
-    assert(ret == 25);
-    assert(gTestCommandState.called);
-    assert(strcmp(gTestCommandState.name, "one") == 0);
-    assert(gTestCommandState.cookie == &gTestCommandState);
-    assert(gTestCommandState.argc == argc);
-    assert(gTestCommandState.argv == argv);
-    assert(strcmp(functionResult, "1234") == 0);
-    assert(functionResultLen == strlen(functionResult));
-
-    /* Smoke test commandCleanup().
-     */
-    commandCleanup();
-
-    return 0;
-}
-
-static int
-test_interaction()
-{
-    Command *cmd;
-    Function *fn;
-    int ret;
-
-    ret = commandInit();
-    assert(ret == 0);
-
-    /* Register some commands.
-     */
-    ret = registerCommand("one", CMD_ARGS_WORDS, testCommand, (void *)0xc1);
-    assert(ret == 0);
-
-    ret = registerCommand("two", CMD_ARGS_WORDS, testCommand, (void *)0xc2);
-    assert(ret == 0);
-
-    /* Register some functions, one of which shares a name with a command.
-     */
-    ret = registerFunction("one", testFunction, (void *)0xf1);
-    assert(ret == 0);
-
-    ret = registerFunction("three", testFunction, (void *)0xf3);
-    assert(ret == 0);
-
-    /* Look up each of the commands, and make sure no command exists
-     * with the name used only by our function.
-     */
-    cmd = findCommand("one");
-    assert(cmd != NULL);
-
-    cmd = findCommand("two");
-    assert(cmd != NULL);
-
-    cmd = findCommand("three");
-    assert(cmd == NULL);
-
-    /* Look up each of the functions, and make sure no function exists
-     * with the name used only by our command.
-     */
-    fn = findFunction("one");
-    assert(fn != NULL);
-
-    fn = findFunction("two");
-    assert(fn == NULL);
-
-    fn = findFunction("three");
-    assert(fn != NULL);
-
-    /* Set up some arguments.
-     */
-    int argc = 4;
-    const char *argv[4] = { "ONE", "TWO", "THREE", "FOUR" };
-
-    /* Call the overlapping command and make sure that the cookie is correct.
-     */
-    cmd = findCommand("one");
-    assert(cmd != NULL);
-    memset(&gTestCommandState, 0, sizeof(gTestCommandState));
-    gTestCommandState.called = false;
-    gTestCommandState.returnValue = 123;
-    ret = callCommand(cmd, argc, argv);
-    assert(ret == 123);
-    assert(gTestCommandState.called);
-    assert(strcmp(gTestCommandState.name, "one") == 0);
-    assert((int)gTestCommandState.cookie == 0xc1);
-    assert(gTestCommandState.argc == argc);
-    assert(gTestCommandState.argv == argv);
-
-    /* Call the overlapping function and make sure that the cookie is correct.
-     */
-    char *functionResult;
-    size_t functionResultLen;
-    fn = findFunction("one");
-    assert(fn != NULL);
-    memset(&gTestCommandState, 0, sizeof(gTestCommandState));
-    gTestCommandState.called = false;
-    gTestCommandState.returnValue = 125;
-    gTestCommandState.functionResult = "5678";
-    functionResult = NULL;
-    functionResultLen = 66;
-    ret = callFunction(fn, argc, argv, &functionResult, &functionResultLen);
-    assert(ret == 125);
-    assert(gTestCommandState.called);
-    assert(strcmp(gTestCommandState.name, "one") == 0);
-    assert((int)gTestCommandState.cookie == 0xf1);
-    assert(gTestCommandState.argc == argc);
-    assert(gTestCommandState.argv == argv);
-    assert(strcmp(functionResult, "5678") == 0);
-    assert(functionResultLen == strlen(functionResult));
-
-    /* Clean up.
-     */
-    commandCleanup();
-
-    return 0;
-}
-
-int
-test_cmd_fn()
-{
-    int ret;
-
-    ret = test_commands();
-    if (ret != 0) {
-        fprintf(stderr, "test_commands() failed: %d\n", ret);
-        return ret;
-    }
-
-    ret = test_functions();
-    if (ret != 0) {
-        fprintf(stderr, "test_functions() failed: %d\n", ret);
-        return ret;
-    }
-
-    ret = test_interaction();
-    if (ret != 0) {
-        fprintf(stderr, "test_interaction() failed: %d\n", ret);
-        return ret;
-    }
-
-    return 0;
-}
diff --git a/amend/test_symtab.c b/amend/test_symtab.c
deleted file mode 100644
index 017d18c..0000000
--- a/amend/test_symtab.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#include <stdlib.h>
-#undef NDEBUG
-#include <assert.h>
-#include "symtab.h"
-
-int
-test_symtab()
-{
-    SymbolTable *tab;
-    void *cookie;
-    int ret;
-
-    /* Test creation */
-    tab = createSymbolTable();
-    assert(tab != NULL);
-
-    /* Smoke-test deletion */
-    deleteSymbolTable(tab);
-
-
-    tab = createSymbolTable();
-    assert(tab != NULL);
-
-
-    /* table parameter must be non-NULL. */
-    ret = addToSymbolTable(NULL, NULL, 0, NULL);
-    assert(ret < 0);
-
-    /* symbol parameter must be non-NULL. */
-    ret = addToSymbolTable(tab, NULL, 0, NULL);
-    assert(ret < 0);
-    
-    /* cookie parameter must be non-NULL. */
-    ret = addToSymbolTable(tab, "null", 0, NULL);
-    assert(ret < 0);
-
-
-    /* table parameter must be non-NULL. */
-    cookie = findInSymbolTable(NULL, NULL, 0);
-    assert(cookie == NULL);
-
-    /* symbol parameter must be non-NULL. */
-    cookie = findInSymbolTable(tab, NULL, 0);
-    assert(cookie == NULL);
-
-
-    /* Try some actual inserts.
-     */
-    ret = addToSymbolTable(tab, "one", 0, (void *)1);
-    assert(ret == 0);
-
-    ret = addToSymbolTable(tab, "two", 0, (void *)2);
-    assert(ret == 0);
-
-    ret = addToSymbolTable(tab, "three", 0, (void *)3);
-    assert(ret == 0);
-
-    /* Try some lookups.
-     */
-    cookie = findInSymbolTable(tab, "one", 0);
-    assert((int)cookie == 1);
-
-    cookie = findInSymbolTable(tab, "two", 0);
-    assert((int)cookie == 2);
-
-    cookie = findInSymbolTable(tab, "three", 0);
-    assert((int)cookie == 3);
-
-    /* Try to insert something that's already there.
-     */
-    ret = addToSymbolTable(tab, "one", 0, (void *)1111);
-    assert(ret < 0);
-
-    /* Make sure that the failed duplicate insert didn't
-     * clobber the original cookie value.
-     */
-    cookie = findInSymbolTable(tab, "one", 0);
-    assert((int)cookie == 1);
-
-    /* Try looking up something that isn't there.
-     */
-    cookie = findInSymbolTable(tab, "FOUR", 0);
-    assert(cookie == NULL);
-
-    /* Try looking up something that's similar to an existing entry.
-     */
-    cookie = findInSymbolTable(tab, "on", 0);
-    assert(cookie == NULL);
-
-    cookie = findInSymbolTable(tab, "onee", 0);
-    assert(cookie == NULL);
-
-    /* Test flags.
-     * Try inserting something with a different flag.
-     */
-    ret = addToSymbolTable(tab, "ten", 333, (void *)10);
-    assert(ret == 0);
-
-    /* Make sure it's there.
-     */
-    cookie = findInSymbolTable(tab, "ten", 333);
-    assert((int)cookie == 10);
-
-    /* Make sure it's not there when looked up with a different flag.
-     */
-    cookie = findInSymbolTable(tab, "ten", 0);
-    assert(cookie == NULL);
-
-    /* Try inserting something that has the same name as something
-     * with a different flag.
-     */
-    ret = addToSymbolTable(tab, "one", 333, (void *)11);
-    assert(ret == 0);
-
-    /* Make sure the new entry exists.
-     */
-    cookie = findInSymbolTable(tab, "one", 333);
-    assert((int)cookie == 11);
-
-    /* Make sure the old entry still has the right value.
-     */
-    cookie = findInSymbolTable(tab, "one", 0);
-    assert((int)cookie == 1);
-
-    /* Try deleting again, now that there's stuff in the table.
-     */
-    deleteSymbolTable(tab);
-
-    return 0;
-}
diff --git a/amend/tests/001-nop/expected.txt b/amend/tests/001-nop/expected.txt
deleted file mode 100644
index d4a85ce..0000000
--- a/amend/tests/001-nop/expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-I am a jelly donut.
diff --git a/amend/tests/001-nop/info.txt b/amend/tests/001-nop/info.txt
deleted file mode 100644
index 9942f10..0000000
--- a/amend/tests/001-nop/info.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-This is a sample no-op test, which does at least serve to verify that the
-test harness is working.
diff --git a/amend/tests/001-nop/run b/amend/tests/001-nop/run
deleted file mode 100644
index 51637c1..0000000
--- a/amend/tests/001-nop/run
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2007 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.
-
-echo 'I am a jelly donut.'
diff --git a/amend/tests/002-lex-empty/SKIP b/amend/tests/002-lex-empty/SKIP
deleted file mode 100644
index e69de29..0000000
--- a/amend/tests/002-lex-empty/SKIP
+++ /dev/null
diff --git a/amend/tests/002-lex-empty/expected.txt b/amend/tests/002-lex-empty/expected.txt
deleted file mode 100644
index 822a54c..0000000
--- a/amend/tests/002-lex-empty/expected.txt
+++ /dev/null
@@ -1 +0,0 @@
- EOF
diff --git a/amend/tests/002-lex-empty/info.txt b/amend/tests/002-lex-empty/info.txt
deleted file mode 100644
index 090083f..0000000
--- a/amend/tests/002-lex-empty/info.txt
+++ /dev/null
@@ -1 +0,0 @@
-Test to make sure that an empty file is accepted properly.
diff --git a/amend/tests/002-lex-empty/input b/amend/tests/002-lex-empty/input
deleted file mode 100644
index e69de29..0000000
--- a/amend/tests/002-lex-empty/input
+++ /dev/null
diff --git a/amend/tests/002-lex-empty/run b/amend/tests/002-lex-empty/run
deleted file mode 100644
index 35c4a4f..0000000
--- a/amend/tests/002-lex-empty/run
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2007 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.
-
-amend --debug-lex input
diff --git a/amend/tests/003-lex-command/expected.txt b/amend/tests/003-lex-command/expected.txt
deleted file mode 100644
index e40db0c..0000000
--- a/amend/tests/003-lex-command/expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
- IDENTIFIER<this_identifier_is_not_assert> EOL
- IDENTIFIER<NEITHER_IS_THIS_123> EOL
- IDENTIFIER<but_the_next_one_is> EOL
- IDENTIFIER<assert> EOL
- IDENTIFIER<next_one_is_not_an_identifier> EOL
-line 6: unexpected character at '1'
- EOF
-line 1: unexpected character at '"'
- EOF
-line 1: unexpected character at '='
- EOF
-line 1: unexpected character at '9'
- EOF
diff --git a/amend/tests/003-lex-command/info.txt b/amend/tests/003-lex-command/info.txt
deleted file mode 100644
index 9296648..0000000
--- a/amend/tests/003-lex-command/info.txt
+++ /dev/null
@@ -1 +0,0 @@
-Test to make sure that simple command names are tokenized properly.
diff --git a/amend/tests/003-lex-command/input b/amend/tests/003-lex-command/input
deleted file mode 100644
index b9ef231..0000000
--- a/amend/tests/003-lex-command/input
+++ /dev/null
@@ -1,6 +0,0 @@
-this_identifier_is_not_assert
-NEITHER_IS_THIS_123
-but_the_next_one_is
-assert
-next_one_is_not_an_identifier
-12not_an_identifier
diff --git a/amend/tests/003-lex-command/input2 b/amend/tests/003-lex-command/input2
deleted file mode 100644
index eb5daf7..0000000
--- a/amend/tests/003-lex-command/input2
+++ /dev/null
@@ -1 +0,0 @@
-"quoted"
diff --git a/amend/tests/003-lex-command/input3 b/amend/tests/003-lex-command/input3
deleted file mode 100644
index f1c8738..0000000
--- a/amend/tests/003-lex-command/input3
+++ /dev/null
@@ -1 +0,0 @@
-==
diff --git a/amend/tests/003-lex-command/input4 b/amend/tests/003-lex-command/input4
deleted file mode 100644
index 3ad5abd..0000000
--- a/amend/tests/003-lex-command/input4
+++ /dev/null
@@ -1 +0,0 @@
-99
diff --git a/amend/tests/003-lex-command/run b/amend/tests/003-lex-command/run
deleted file mode 100644
index 2e21fab..0000000
--- a/amend/tests/003-lex-command/run
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2007 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.
-
-amend --debug-lex input
-amend --debug-lex input2
-amend --debug-lex input3
-amend --debug-lex input4
diff --git a/amend/tests/004-lex-comment/expected.txt b/amend/tests/004-lex-comment/expected.txt
deleted file mode 100644
index a728a5e..0000000
--- a/amend/tests/004-lex-comment/expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
- IDENTIFIER<comment_on_this_line> EOL
- IDENTIFIER<none_on_this_one> EOL
- EOL
- EOL
- EOF
diff --git a/amend/tests/004-lex-comment/info.txt b/amend/tests/004-lex-comment/info.txt
deleted file mode 100644
index 0691248..0000000
--- a/amend/tests/004-lex-comment/info.txt
+++ /dev/null
@@ -1 +0,0 @@
-Test to make sure that comments are stripped out.
diff --git a/amend/tests/004-lex-comment/input b/amend/tests/004-lex-comment/input
deleted file mode 100644
index 6736c95..0000000
--- a/amend/tests/004-lex-comment/input
+++ /dev/null
@@ -1,4 +0,0 @@
-comment_on_this_line # this is a "comment" (with / a bunch) # \\ of stuff \
-none_on_this_one
-# beginning of line
-                         # preceded by whitespace
diff --git a/amend/tests/004-lex-comment/run b/amend/tests/004-lex-comment/run
deleted file mode 100644
index 35c4a4f..0000000
--- a/amend/tests/004-lex-comment/run
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2007 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.
-
-amend --debug-lex input
diff --git a/amend/tests/005-lex-quoted-string/expected.txt b/amend/tests/005-lex-quoted-string/expected.txt
deleted file mode 100644
index 9bb5ac4..0000000
--- a/amend/tests/005-lex-quoted-string/expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
- IDENTIFIER<test> WORD<string> EOL
- IDENTIFIER<test> WORD<string with spaces> EOL
- IDENTIFIER<test> WORD<string with "escaped" quotes> EOL
- IDENTIFIER<test> WORD<string with \escaped\ backslashes> EOL
- IDENTIFIER<test> WORD<string with # a comment character> EOL
- EOF
- EOL
- IDENTIFIER<test1>line 2: unterminated string at '
-'
- ??? <0>
- EOL
- IDENTIFIER<test1>line 2: illegal escape at '\n'
- ??? <0>
diff --git a/amend/tests/005-lex-quoted-string/info.txt b/amend/tests/005-lex-quoted-string/info.txt
deleted file mode 100644
index be458bd..0000000
--- a/amend/tests/005-lex-quoted-string/info.txt
+++ /dev/null
@@ -1 +0,0 @@
-Test to make sure that quoted strings are tokenized properly.
diff --git a/amend/tests/005-lex-quoted-string/input b/amend/tests/005-lex-quoted-string/input
deleted file mode 100644
index 2b34bbc..0000000
--- a/amend/tests/005-lex-quoted-string/input
+++ /dev/null
@@ -1,5 +0,0 @@
-test "string"
-test "string with spaces"
-test "string with \"escaped\" quotes"
-test "string with \\escaped\\ backslashes"
-test "string with # a comment character"
diff --git a/amend/tests/005-lex-quoted-string/input2 b/amend/tests/005-lex-quoted-string/input2
deleted file mode 100644
index 09e6689..0000000
--- a/amend/tests/005-lex-quoted-string/input2
+++ /dev/null
@@ -1,2 +0,0 @@
-# This should fail
-test1 "unterminated string
diff --git a/amend/tests/005-lex-quoted-string/input3 b/amend/tests/005-lex-quoted-string/input3
deleted file mode 100644
index 02f3f85..0000000
--- a/amend/tests/005-lex-quoted-string/input3
+++ /dev/null
@@ -1,2 +0,0 @@
-# This should fail
-test1 "string with illegal escape \n in the middle"
diff --git a/amend/tests/005-lex-quoted-string/run b/amend/tests/005-lex-quoted-string/run
deleted file mode 100644
index 7b1292a..0000000
--- a/amend/tests/005-lex-quoted-string/run
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2007 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.
-
-amend --debug-lex input
-amend --debug-lex input2
-amend --debug-lex input3
diff --git a/amend/tests/006-lex-words/SKIP b/amend/tests/006-lex-words/SKIP
deleted file mode 100644
index e69de29..0000000
--- a/amend/tests/006-lex-words/SKIP
+++ /dev/null
diff --git a/amend/tests/006-lex-words/expected.txt b/amend/tests/006-lex-words/expected.txt
deleted file mode 100644
index a78a0b1..0000000
--- a/amend/tests/006-lex-words/expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
- IDENTIFIER<test> WORD<this> WORD<has> WORD<a> WORD<bunch> WORD<of> WORD<BARE> WORD<ALPHA> WORD<WORDS> EOL
- IDENTIFIER<test> WORD<12> WORD<this> WORD<has(some> WORD<)> WORD<ALPHANUMER1C> WORD<and> WORD<\\> WORD<whatever> WORD<characters> EOL
- IDENTIFIER<test> WORD<this> WORD<has> WORD<mixed> WORD<bare> WORD<and quoted> WORD<words> EOL
- IDENTIFIER<test> WORD<what> WORD<about> WORD<quotesin the middle?> EOL
- IDENTIFIER<test> WORD<"""shouldn't> WORD<be> WORD<a> WORD<quoted> WORD<string> EOL
- EOF
diff --git a/amend/tests/006-lex-words/info.txt b/amend/tests/006-lex-words/info.txt
deleted file mode 100644
index dd37016..0000000
--- a/amend/tests/006-lex-words/info.txt
+++ /dev/null
@@ -1 +0,0 @@
-Test to make sure that argument words are tokenized properly.
diff --git a/amend/tests/006-lex-words/input b/amend/tests/006-lex-words/input
deleted file mode 100644
index a4de638..0000000
--- a/amend/tests/006-lex-words/input
+++ /dev/null
@@ -1,5 +0,0 @@
-test this has a bunch of BARE ALPHA WORDS
-test 12 this has(some ) ALPHANUMER1C and \\ whatever characters
-test this has mixed bare "and quoted" words
-test what about quotes"in the middle?"
-test \"\"\"shouldn't be a quoted string
diff --git a/amend/tests/006-lex-words/input2 b/amend/tests/006-lex-words/input2
deleted file mode 100644
index 09e6689..0000000
--- a/amend/tests/006-lex-words/input2
+++ /dev/null
@@ -1,2 +0,0 @@
-# This should fail
-test1 "unterminated string
diff --git a/amend/tests/006-lex-words/input3 b/amend/tests/006-lex-words/input3
deleted file mode 100644
index 02f3f85..0000000
--- a/amend/tests/006-lex-words/input3
+++ /dev/null
@@ -1,2 +0,0 @@
-# This should fail
-test1 "string with illegal escape \n in the middle"
diff --git a/amend/tests/006-lex-words/run b/amend/tests/006-lex-words/run
deleted file mode 100644
index 35c4a4f..0000000
--- a/amend/tests/006-lex-words/run
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2007 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.
-
-amend --debug-lex input
diff --git a/amend/tests/007-lex-real-script/expected.txt b/amend/tests/007-lex-real-script/expected.txt
deleted file mode 100644
index 012f62c..0000000
--- a/amend/tests/007-lex-real-script/expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
- IDENTIFIER<assert> IDENTIFIER<hash_dir> ( STRING<SYS:> ) == STRING<112345oldhashvalue1234123> EOL
- IDENTIFIER<mark> WORD<SYS:> WORD<dirty> EOL
- IDENTIFIER<copy_dir> WORD<PKG:android-files> WORD<SYS:> EOL
- IDENTIFIER<assert> IDENTIFIER<hash_dir> ( STRING<SYS:> ) == STRING<667890newhashvalue6678909> EOL
- IDENTIFIER<mark> WORD<SYS:> WORD<clean> EOL
- IDENTIFIER<done> EOL
- IDENTIFIER<assert> IDENTIFIER<hash_dir> ( STRING<SYS:> , STRING<blah> ) == STRING<112345oldhashvalue1234123> EOL
- IDENTIFIER<assert> STRING<true> == STRING<false> EOL
- IDENTIFIER<assert> IDENTIFIER<one> ( STRING<abc> , IDENTIFIER<two> ( STRING<def> ) ) == STRING<five> EOL
- IDENTIFIER<assert> IDENTIFIER<hash_dir> ( STRING<SYS:> ) == STRING<667890newhashvalue6678909> || IDENTIFIER<hash_dir> ( STRING<SYS:> ) == STRING<667890newhashvalue6678909> EOL
- EOF
diff --git a/amend/tests/007-lex-real-script/info.txt b/amend/tests/007-lex-real-script/info.txt
deleted file mode 100644
index 5e321f5..0000000
--- a/amend/tests/007-lex-real-script/info.txt
+++ /dev/null
@@ -1 +0,0 @@
-An input script similar to one that will actually be used in practice.
diff --git a/amend/tests/007-lex-real-script/input b/amend/tests/007-lex-real-script/input
deleted file mode 100644
index f3f1fd9..0000000
--- a/amend/tests/007-lex-real-script/input
+++ /dev/null
@@ -1,10 +0,0 @@
-assert hash_dir("SYS:") == "112345oldhashvalue1234123"
-mark SYS: dirty
-copy_dir "PKG:android-files" SYS:
-assert hash_dir("SYS:") == "667890newhashvalue6678909"
-mark SYS: clean
-done
-assert hash_dir("SYS:", "blah") == "112345oldhashvalue1234123"
-assert "true" == "false"
-assert one("abc", two("def")) == "five"
-assert hash_dir("SYS:") == "667890newhashvalue6678909" || hash_dir("SYS:") == "667890newhashvalue6678909"
diff --git a/amend/tests/007-lex-real-script/run b/amend/tests/007-lex-real-script/run
deleted file mode 100644
index 35c4a4f..0000000
--- a/amend/tests/007-lex-real-script/run
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2007 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.
-
-amend --debug-lex input
diff --git a/amend/tests/008-parse-real-script/expected.txt b/amend/tests/008-parse-real-script/expected.txt
deleted file mode 100644
index dabf6d4..0000000
--- a/amend/tests/008-parse-real-script/expected.txt
+++ /dev/null
@@ -1,74 +0,0 @@
-command "assert" {
-    STRING EQ {
-        FUNCTION hash_dir (
-            "SYS:"
-        )
-        "112345oldhashvalue1234123"
-    }
-}
-command "mark" {
-    "SYS:"
-    "dirty"
-}
-command "copy_dir" {
-    "PKG:android-files"
-    "SYS:"
-}
-command "assert" {
-    STRING EQ {
-        FUNCTION hash_dir (
-            "SYS:"
-        )
-        "667890newhashvalue6678909"
-    }
-}
-command "mark" {
-    "SYS:"
-    "clean"
-}
-command "done" {
-}
-command "assert" {
-    STRING EQ {
-        FUNCTION hash_dir (
-            "SYS:"
-            "blah"
-        )
-        "112345oldhashvalue1234123"
-    }
-}
-command "assert" {
-    STRING EQ {
-        "true"
-        "false"
-    }
-}
-command "assert" {
-    STRING NE {
-        FUNCTION matches (
-            FUNCTION hash_dir (
-                "SYS:"
-            )
-            "667890newhashvalue6678909"
-            "999999newhashvalue6678909"
-        )
-        ""
-    }
-}
-command "assert" {
-    BOOLEAN OR {
-        STRING EQ {
-            FUNCTION hash_dir (
-                "SYS:"
-            )
-            "667890newhashvalue6678909"
-        }
-        STRING EQ {
-            FUNCTION hash_dir (
-                "SYS:"
-            )
-            "999999newhashvalue6678909"
-        }
-    }
-}
-amend: Parse successful.
diff --git a/amend/tests/008-parse-real-script/info.txt b/amend/tests/008-parse-real-script/info.txt
deleted file mode 100644
index 5e321f5..0000000
--- a/amend/tests/008-parse-real-script/info.txt
+++ /dev/null
@@ -1 +0,0 @@
-An input script similar to one that will actually be used in practice.
diff --git a/amend/tests/008-parse-real-script/input b/amend/tests/008-parse-real-script/input
deleted file mode 100644
index b073306..0000000
--- a/amend/tests/008-parse-real-script/input
+++ /dev/null
@@ -1,10 +0,0 @@
-assert hash_dir("SYS:") == "112345oldhashvalue1234123"
-mark SYS: dirty
-copy_dir "PKG:android-files" SYS:
-assert hash_dir("SYS:") == "667890newhashvalue6678909"
-mark SYS: clean
-done
-assert hash_dir("SYS:", "blah") == "112345oldhashvalue1234123"
-assert "true" == "false"
-assert matches(hash_dir("SYS:"), "667890newhashvalue6678909", "999999newhashvalue6678909") != ""
-assert hash_dir("SYS:") == "667890newhashvalue6678909" || hash_dir("SYS:") == "999999newhashvalue6678909"
diff --git a/amend/tests/008-parse-real-script/run b/amend/tests/008-parse-real-script/run
deleted file mode 100644
index 9544e1b..0000000
--- a/amend/tests/008-parse-real-script/run
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2007 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.
-
-amend --debug-ast input
diff --git a/amend/tests/XXX-long-token/SKIP b/amend/tests/XXX-long-token/SKIP
deleted file mode 100644
index e69de29..0000000
--- a/amend/tests/XXX-long-token/SKIP
+++ /dev/null
diff --git a/amend/tests/XXX-stack-overflow/SKIP b/amend/tests/XXX-stack-overflow/SKIP
deleted file mode 100644
index e69de29..0000000
--- a/amend/tests/XXX-stack-overflow/SKIP
+++ /dev/null
diff --git a/amend/tests/one-test b/amend/tests/one-test
deleted file mode 100755
index 9cebd3f..0000000
--- a/amend/tests/one-test
+++ /dev/null
@@ -1,150 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2007 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.
-
-# Set up prog to be the path of this script, including following symlinks,
-# and set up progdir to be the fully-qualified pathname of its directory.
-prog="$0"
-while [ -h "${prog}" ]; do
-    newProg=`/bin/ls -ld "${prog}"`
-    newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
-    if expr "x${newProg}" : 'x/' >/dev/null; then
-        prog="${newProg}"
-    else
-        progdir=`dirname "${prog}"`
-        prog="${progdir}/${newProg}"
-    fi
-done
-oldwd=`pwd`
-progdir=`dirname "${prog}"`
-cd "${progdir}"
-progdir=`pwd`
-prog="${progdir}"/`basename "${prog}"`
-
-info="info.txt"
-run="run"
-expected="expected.txt"
-output="out.txt"
-skip="SKIP"
-
-dev_mode="no"
-if [ "x$1" = "x--dev" ]; then
-    dev_mode="yes"
-    shift
-fi
-
-update_mode="no"
-if [ "x$1" = "x--update" ]; then
-    update_mode="yes"
-    shift
-fi
-
-usage="no"
-if [ "x$1" = "x--help" ]; then
-    usage="yes"
-else
-    if [ "x$1" = "x" ]; then
-        testdir=`basename "$oldwd"`
-    else
-        testdir="$1"
-    fi
-
-    if [ '!' -d "$testdir" ]; then
-        td2=`echo ${testdir}-*`
-        if [ '!' -d "$td2" ]; then
-            echo "${testdir}: no such test directory" 1>&2
-            usage="yes"
-        fi
-        testdir="$td2"
-    fi
-fi
-
-if [ "$usage" = "yes" ]; then
-    prog=`basename $prog`
-    (
-        echo "usage:"
-        echo "  $prog --help             Print this message."
-        echo "  $prog testname           Run test normally."
-        echo "  $prog --dev testname     Development mode (dump to stdout)."
-        echo "  $prog --update testname  Update mode (replace expected.txt)."
-        echo "  Omitting the test name uses the current directory as the test."
-    ) 1>&2
-    exit 1
-fi
-
-td_info="$testdir"/"$info"
-td_run="$testdir"/"$run"
-td_expected="$testdir"/"$expected"
-td_skip="$testdir"/"$skip"
-
-if [ -r "$td_skip" ]; then
-    exit 2
-fi
-
-tmpdir=/tmp/test-$$
-
-if [ '!' '(' -r "$td_info" -a -r "$td_run" -a -r "$td_expected" ')' ]; then
-    echo "${testdir}: missing files" 1>&2
-    exit 1
-fi
-
-# copy the test to a temp dir and run it
-
-echo "${testdir}: running..." 1>&2
-
-rm -rf "$tmpdir"
-cp -Rp "$testdir" "$tmpdir"
-cd "$tmpdir"
-chmod 755 "$run"
-
-#PATH="${progdir}/../build/bin:${PATH}"
-
-good="no"
-if [ "$dev_mode" = "yes" ]; then
-    "./$run" 2>&1
-    echo "exit status: $?" 1>&2
-    good="yes"
-elif [ "$update_mode" = "yes" ]; then
-    "./$run" >"${progdir}/$td_expected" 2>&1
-    good="yes"
-else
-    "./$run" >"$output" 2>&1
-    cmp -s "$expected" "$output"
-    if [ "$?" = "0" ]; then
-        # output == expected
-        good="yes"
-        echo "$testdir"': succeeded!' 1>&2
-    fi
-fi
-
-if [ "$good" = "yes" ]; then
-    cd "$oldwd"
-    rm -rf "$tmpdir"
-    exit 0
-fi
-
-(
-    echo "${testdir}: FAILED!"
-    echo ' '
-    echo '#################### info'
-    cat "$info" | sed 's/^/# /g'
-    echo '#################### diffs'
-    diff -u "$expected" "$output"
-    echo '####################'
-    echo ' '
-    echo "files left in $tmpdir"
-) 1>&2
-
-exit 1
diff --git a/amend/tests/run-all-tests b/amend/tests/run-all-tests
deleted file mode 100755
index c696bbd..0000000
--- a/amend/tests/run-all-tests
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2007 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.
-
-# Set up prog to be the path of this script, including following symlinks,
-# and set up progdir to be the fully-qualified pathname of its directory.
-prog="$0"
-while [ -h "${prog}" ]; do
-    newProg=`/bin/ls -ld "${prog}"`
-    newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
-    if expr "x${newProg}" : 'x/' >/dev/null; then
-        prog="${newProg}"
-    else
-        progdir=`dirname "${prog}"`
-        prog="${progdir}/${newProg}"
-    fi
-done
-oldwd=`pwd`
-progdir=`dirname "${prog}"`
-cd "${progdir}"
-progdir=`pwd`
-prog="${progdir}"/`basename "${prog}"`
-
-passed=0
-skipped=0
-skipNames=""
-failed=0
-failNames=""
-
-for i in *; do
-    if [ -d "$i" -a -r "$i" ]; then
-        ./one-test "$i"
-        status=$?
-        if [ "$status" = "0" ]; then
-            ((passed += 1))
-        elif [ "$status" = "2" ]; then
-            ((skipped += 1))
-            skipNames="$skipNames $i"
-        else
-            ((failed += 1))
-            failNames="$failNames $i"
-        fi
-    fi
-done
-
-echo "passed:  $passed test(s)"
-echo "skipped: $skipped test(s)"
-
-for i in $skipNames; do
-    echo "skipped: $i"
-done
-
-echo "failed:  $failed test(s)"
-    
-for i in $failNames; do
-    echo "failed: $i"
-done
diff --git a/commands.c b/commands.c
deleted file mode 100644
index b4678ba..0000000
--- a/commands.c
+++ /dev/null
@@ -1,1075 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#undef NDEBUG
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <unistd.h>
-
-#include "amend/commands.h"
-#include "commands.h"
-#include "common.h"
-#include "cutils/misc.h"
-#include "cutils/properties.h"
-#include "firmware.h"
-#include "minzip/DirUtil.h"
-#include "minzip/Zip.h"
-#include "roots.h"
-
-static int gDidShowProgress = 0;
-
-#define UNUSED(p)   ((void)(p))
-
-#define CHECK_BOOL() \
-    do { \
-        assert(argv == NULL); \
-        if (argv != NULL) return -1; \
-        assert(argc == true || argc == false); \
-        if (argc != true && argc != false) return -1; \
-    } while (false)
-
-#define CHECK_WORDS() \
-    do { \
-        assert(argc >= 0); \
-        if (argc < 0) return -1; \
-        assert(argc == 0 || argv != NULL); \
-        if (argc != 0 && argv == NULL) return -1; \
-    } while (false)
-
-#define CHECK_FN() \
-    do { \
-        CHECK_WORDS(); \
-        assert(result != NULL); \
-        if (result == NULL) return -1; \
-    } while (false)
-
-/*
- * Command definitions
- */
-
-/* assert <boolexpr>
- */
-static int
-cmd_assert(const char *name, void *cookie, int argc, const char *argv[])
-{
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_BOOL();
-
-    /* If our argument is false, return non-zero (failure)
-     * If our argument is true, return zero (success)
-     */
-    if (argc) {
-        return 0;
-    } else {
-        return 1;
-    }
-}
-
-/* format <root>
- */
-static int
-cmd_format(const char *name, void *cookie, int argc, const char *argv[])
-{
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_WORDS();
-
-    if (argc != 1) {
-        LOGE("Command %s requires exactly one argument\n", name);
-        return 1;
-    }
-    const char *root = argv[0];
-    ui_print("Formatting %s...\n", root);
-
-    int ret = format_root_device(root);
-    if (ret != 0) {
-        LOGE("Can't format %s\n", root);
-        return 1;
-    }
-
-    return 0;
-}
-
-/* delete <file1> [<fileN> ...]
- * delete_recursive <file-or-dir1> [<file-or-dirN> ...]
- *
- * Like "rm -f", will try to delete every named file/dir, even if
- * earlier ones fail.  Recursive deletes that fail halfway through
- * give up early.
- */
-static int
-cmd_delete(const char *name, void *cookie, int argc, const char *argv[])
-{
-    UNUSED(cookie);
-    CHECK_WORDS();
-    int nerr = 0;
-    bool recurse;
-
-    if (argc < 1) {
-        LOGE("Command %s requires at least one argument\n", name);
-        return 1;
-    }
-
-    recurse = (strcmp(name, "delete_recursive") == 0);
-    ui_print("Deleting files...\n");
-
-    int i;
-    for (i = 0; i < argc; i++) {
-        const char *root_path = argv[i];
-        char pathbuf[PATH_MAX];
-        const char *path;
-
-        /* This guarantees that all paths use "SYSTEM:"-style roots;
-         * plain paths won't make it through translate_root_path().
-         */
-        path = translate_root_path(root_path, pathbuf, sizeof(pathbuf));
-        if (path != NULL) {
-            int ret = ensure_root_path_mounted(root_path);
-            if (ret < 0) {
-                LOGW("Can't mount volume to delete \"%s\"\n", root_path);
-                nerr++;
-                continue;
-            }
-            if (recurse) {
-                ret = dirUnlinkHierarchy(path);
-            } else {
-                ret = unlink(path);
-            }
-            if (ret != 0 && errno != ENOENT) {
-                LOGW("Can't delete %s\n(%s)\n", path, strerror(errno));
-                nerr++;
-            }
-        } else {
-            nerr++;
-        }
-    }
-//TODO: add a way to fail if a delete didn't work
-
-    return 0;
-}
-
-typedef struct {
-    int num_done;
-    int num_total;
-} ExtractContext;
-
-static void extract_count_cb(const char *fn, void *cookie)
-{
-   ++((ExtractContext*) cookie)->num_total;
-}
-
-static void extract_cb(const char *fn, void *cookie)
-{
-    // minzip writes the filename to the log, so we don't need to
-    ExtractContext *ctx = (ExtractContext*) cookie;
-    ui_set_progress((float) ++ctx->num_done / ctx->num_total);
-}
-
-/* copy_dir <src-dir> <dst-dir> [<timestamp>]
- *
- * The contents of <src-dir> will become the contents of <dst-dir>.
- * The original contents of <dst-dir> are preserved unless something
- * in <src-dir> overwrote them.
- *
- * e.g., for "copy_dir PKG:system SYSTEM:", the file "PKG:system/a"
- * would be copied to "SYSTEM:a".
- *
- * The specified timestamp (in decimal seconds since 1970) will be used,
- * or a fixed default timestamp will be supplied otherwise.
- */
-static int
-cmd_copy_dir(const char *name, void *cookie, int argc, const char *argv[])
-{
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_WORDS();
-
-    // To create a consistent system image, never use the clock for timestamps.
-    struct utimbuf timestamp = { 1217592000, 1217592000 };  // 8/1/2008 default
-    if (argc == 3) {
-        char *end;
-        time_t value = strtoul(argv[2], &end, 0);
-        if (value == 0 || end[0] != '\0') {
-            LOGE("Command %s: invalid timestamp \"%s\"\n", name, argv[2]);
-            return 1;
-        } else if (value < timestamp.modtime) {
-            LOGE("Command %s: timestamp \"%s\" too early\n", name, argv[2]);
-            return 1;
-        }
-        timestamp.modtime = timestamp.actime = value;
-    } else if (argc != 2) {
-        LOGE("Command %s requires exactly two arguments\n", name);
-        return 1;
-    }
-
-    // Use 40% of the progress bar (80% post-verification) by default
-    ui_print("Copying files...\n");
-    if (!gDidShowProgress) ui_show_progress(DEFAULT_FILES_PROGRESS_FRACTION, 0);
-
-    /* Mount the destination volume if it isn't already.
-     */
-    const char *dst_root_path = argv[1];
-    int ret = ensure_root_path_mounted(dst_root_path);
-    if (ret < 0) {
-        LOGE("Can't mount %s\n", dst_root_path);
-        return 1;
-    }
-
-    /* Get the real target path.
-     */
-    char dstpathbuf[PATH_MAX];
-    const char *dst_path;
-    dst_path = translate_root_path(dst_root_path,
-            dstpathbuf, sizeof(dstpathbuf));
-    if (dst_path == NULL) {
-        LOGE("Command %s: bad destination path \"%s\"\n", name, dst_root_path);
-        return 1;
-    }
-
-    /* Try to copy the directory.  The source may be inside a package.
-     */
-    const char *src_root_path = argv[0];
-    char srcpathbuf[PATH_MAX];
-    const char *src_path;
-    if (is_package_root_path(src_root_path)) {
-        const ZipArchive *package;
-        src_path = translate_package_root_path(src_root_path,
-                srcpathbuf, sizeof(srcpathbuf), &package);
-        if (src_path == NULL) {
-            LOGE("Command %s: bad source path \"%s\"\n", name, src_root_path);
-            return 1;
-        }
-
-        /* Extract the files.  Set MZ_EXTRACT_FILES_ONLY, because only files
-         * are validated by the signature.  Do a dry run first to count how
-         * many there are (and find some errors early).
-         */
-        ExtractContext ctx;
-        ctx.num_done = 0;
-        ctx.num_total = 0;
-
-        if (!mzExtractRecursive(package, src_path, dst_path,
-                    MZ_EXTRACT_FILES_ONLY | MZ_EXTRACT_DRY_RUN,
-                    &timestamp, extract_count_cb, (void *) &ctx) ||
-            !mzExtractRecursive(package, src_path, dst_path,
-                    MZ_EXTRACT_FILES_ONLY,
-                    &timestamp, extract_cb, (void *) &ctx)) {
-            LOGW("Command %s: couldn't extract \"%s\" to \"%s\"\n",
-                    name, src_root_path, dst_root_path);
-            return 1;
-        }
-    } else {
-        LOGE("Command %s: non-package source path \"%s\" not yet supported\n",
-                name, src_root_path);
-//xxx mount the src volume
-//xxx
-        return 255;
-    }
-
-    return 0;
-}
-
-/* run_program <program-file> [<args> ...]
- *
- * Run an external program included in the update package.
- */
-static int
-cmd_run_program(const char *name, void *cookie, int argc, const char *argv[])
-{
-    UNUSED(cookie);
-    CHECK_WORDS();
-
-    if (argc < 1) {
-        LOGE("Command %s requires at least one argument\n", name);
-        return 1;
-    }
-
-    // Copy the program file to temporary storage.
-    if (!is_package_root_path(argv[0])) {
-        LOGE("Command %s: non-package program file \"%s\" not supported\n",
-                name, argv[0]);
-        return 1;
-    }
-
-    char path[PATH_MAX];
-    const ZipArchive *package;
-    if (!translate_package_root_path(argv[0], path, sizeof(path), &package)) {
-        LOGE("Command %s: bad source path \"%s\"\n", name, argv[0]);
-        return 1;
-    }
-
-    const ZipEntry *entry = mzFindZipEntry(package, path);
-    if (entry == NULL) {
-        LOGE("Can't find %s\n", path);
-        return 1;
-    }
-
-    static const char *binary = "/tmp/run_program_binary";
-    unlink(binary);  // just to be sure
-    int fd = creat(binary, 0755);
-    if (fd < 0) {
-        LOGE("Can't make %s\n", binary);
-        return 1;
-    }
-    bool ok = mzExtractZipEntryToFile(package, entry, fd);
-    close(fd);
-
-    if (!ok) {
-        LOGE("Can't copy %s\n", path);
-        return 1;
-    }
-
-    // Create a copy of argv to NULL-terminate it, as execv requires
-    char **args = (char **) malloc(sizeof(char*) * (argc + 1));
-    memcpy(args, argv, sizeof(char*) * argc);
-    args[argc] = NULL;
-
-    pid_t pid = fork();
-    if (pid == 0) {
-        execv(binary, args);
-        fprintf(stderr, "E:Can't run %s\n(%s)\n", binary, strerror(errno));
-        _exit(-1);
-    }
-
-    int status;
-    waitpid(pid, &status, 0);
-    if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
-        return 0;
-    } else {
-        LOGE("Error in %s\n(Status %d)\n", path, status);
-        return 1;
-    }
-}
-
-/* set_perm <uid> <gid> <mode> <path> [... <pathN>]
- * set_perm_recursive <uid> <gid> <dir-mode> <file-mode> <path> [... <pathN>]
- *
- * Like "chmod", "chown" and "chgrp" all in one, set ownership and permissions
- * of single files or entire directory trees.  Any error causes failure.
- * User, group, and modes must all be integer values (hex or octal OK).
- */
-static int
-cmd_set_perm(const char *name, void *cookie, int argc, const char *argv[])
-{
-    UNUSED(cookie);
-    CHECK_WORDS();
-    bool recurse = !strcmp(name, "set_perm_recursive");
-
-    int min_args = 4 + (recurse ? 1 : 0);
-    if (argc < min_args) {
-        LOGE("Command %s requires at least %d args\n", name, min_args);
-        return 1;
-    }
-
-    // All the arguments except the path(s) are numeric.
-    int i, n[min_args - 1];
-    for (i = 0; i < min_args - 1; ++i) {
-        char *end;
-        n[i] = strtoul(argv[i], &end, 0);
-        if (end[0] != '\0' || argv[i][0] == '\0') {
-            LOGE("Command %s: invalid argument \"%s\"\n", name, argv[i]);
-            return 1;
-        }
-    }
-
-    for (i = min_args - 1; i < min_args; ++i) {
-        char path[PATH_MAX];
-        if (translate_root_path(argv[i], path, sizeof(path)) == NULL) {
-            LOGE("Command %s: bad path \"%s\"\n", name, argv[i]);
-            return 1;
-        }
-
-        if (ensure_root_path_mounted(argv[i])) {
-            LOGE("Can't mount %s\n", argv[i]);
-            return 1;
-        }
-
-        if (recurse
-                ? dirSetHierarchyPermissions(path, n[0], n[1], n[2], n[3])
-                : (chown(path, n[0], n[1]) || chmod(path, n[2]))) {
-           LOGE("Can't chown/mod %s\n(%s)\n", path, strerror(errno));
-           return 1;
-        }
-    }
-
-    return 0;
-}
-
-/* show_progress <fraction> <duration>
- *
- * Use <fraction> of the on-screen progress meter for the next operation,
- * automatically advancing the meter over <duration> seconds (or more rapidly
- * if the actual rate of progress can be determined).
- */
-static int
-cmd_show_progress(const char *name, void *cookie, int argc, const char *argv[])
-{
-    UNUSED(cookie);
-    CHECK_WORDS();
-
-    if (argc != 2) {
-        LOGE("Command %s requires exactly two arguments\n", name);
-        return 1;
-    }
-
-    char *end;
-    double fraction = strtod(argv[0], &end);
-    if (end[0] != '\0' || argv[0][0] == '\0' || fraction < 0 || fraction > 1) {
-        LOGE("Command %s: invalid fraction \"%s\"\n", name, argv[0]);
-        return 1;
-    }
-
-    int duration = strtoul(argv[1], &end, 0);
-    if (end[0] != '\0' || argv[0][0] == '\0') {
-        LOGE("Command %s: invalid duration \"%s\"\n", name, argv[1]);
-        return 1;
-    }
-
-    // Half of the progress bar is taken by verification,
-    // so everything that happens during installation is scaled.
-    ui_show_progress(fraction * (1 - VERIFICATION_PROGRESS_FRACTION), duration);
-    gDidShowProgress = 1;
-    return 0;
-}
-
-/* symlink <link-target> <link-path>
- *
- * Create a symlink, like "ln -s".  The link path must not exist already.
- * Note that <link-path> is in root:path format, but <link-target> is
- * for the target filesystem (and may be relative).
- */
-static int
-cmd_symlink(const char *name, void *cookie, int argc, const char *argv[])
-{
-    UNUSED(cookie);
-    CHECK_WORDS();
-
-    if (argc != 2) {
-        LOGE("Command %s requires exactly two arguments\n", name);
-        return 1;
-    }
-
-    char path[PATH_MAX];
-    if (translate_root_path(argv[1], path, sizeof(path)) == NULL) {
-        LOGE("Command %s: bad path \"%s\"\n", name, argv[1]);
-        return 1;
-    }
-
-    if (ensure_root_path_mounted(argv[1])) {
-        LOGE("Can't mount %s\n", argv[1]);
-        return 1;
-    }
-
-    if (symlink(argv[0], path)) {
-        LOGE("Can't symlink %s\n", path);
-        return 1;
-    }
-
-    return 0;
-}
-
-struct FirmwareContext {
-    size_t total_bytes, done_bytes;
-    char *data;
-};
-
-static bool firmware_fn(const unsigned char *data, int data_len, void *cookie)
-{
-    struct FirmwareContext *context = (struct FirmwareContext*) cookie;
-    if (context->done_bytes + data_len > context->total_bytes) {
-        LOGE("Data overrun in firmware\n");
-        return false;  // Should not happen, but let's be safe.
-    }
-
-    memcpy(context->data + context->done_bytes, data, data_len);
-    context->done_bytes += data_len;
-    ui_set_progress(context->done_bytes * 1.0 / context->total_bytes);
-    return true;
-}
-
-/* write_radio_image <src-image>
- * write_hboot_image <src-image>
- * Doesn't actually take effect until the rest of installation finishes.
- */
-static int
-cmd_write_firmware_image(const char *name, void *cookie,
-        int argc, const char *argv[])
-{
-    UNUSED(cookie);
-    CHECK_WORDS();
-
-    if (argc != 1) {
-        LOGE("Command %s requires exactly one argument\n", name);
-        return 1;
-    }
-
-    const char *type;
-    if (!strcmp(name, "write_radio_image")) {
-        type = "radio";
-    } else if (!strcmp(name, "write_hboot_image")) {
-        type = "hboot";
-    } else {
-        LOGE("Unknown firmware update command %s\n", name);
-        return 1;
-    }
-
-    if (!is_package_root_path(argv[0])) {
-        LOGE("Command %s: non-package image file \"%s\" not supported\n",
-                name, argv[0]);
-        return 1;
-    }
-
-    ui_print("Extracting %s image...\n", type);
-    char path[PATH_MAX];
-    const ZipArchive *package;
-    if (!translate_package_root_path(argv[0], path, sizeof(path), &package)) {
-        LOGE("Command %s: bad source path \"%s\"\n", name, argv[0]);
-        return 1;
-    }
-
-    const ZipEntry *entry = mzFindZipEntry(package, path);
-    if (entry == NULL) {
-        LOGE("Can't find %s\n", path);
-        return 1;
-    }
-
-    // Load the update image into RAM.
-    struct FirmwareContext context;
-    context.total_bytes = mzGetZipEntryUncompLen(entry);
-    context.done_bytes = 0;
-    context.data = malloc(context.total_bytes);
-    if (context.data == NULL) {
-        LOGE("Can't allocate %d bytes for %s\n", context.total_bytes, argv[0]);
-        return 1;
-    }
-
-    if (!mzProcessZipEntryContents(package, entry, firmware_fn, &context) ||
-        context.done_bytes != context.total_bytes) {
-        LOGE("Can't read %s\n", argv[0]);
-        free(context.data);
-        return 1;
-    }
-
-    if (remember_firmware_update(type, context.data, context.total_bytes)) {
-        LOGE("Can't store %s image\n", type);
-        free(context.data);
-        return 1;
-    }
-
-    return 0;
-}
-
-static bool write_raw_image_process_fn(
-        const unsigned char *data,
-        int data_len, void *ctx)
-{
-    int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len);
-    if (r == data_len) return true;
-    LOGE("%s\n", strerror(errno));
-    return false;
-}
-
-/* write_raw_image <src-image> <dest-root>
- */
-static int
-cmd_write_raw_image(const char *name, void *cookie,
-        int argc, const char *argv[])
-{
-    UNUSED(cookie);
-    CHECK_WORDS();
-
-    if (argc != 2) {
-        LOGE("Command %s requires exactly two arguments\n", name);
-        return 1;
-    }
-
-    // Use 10% of the progress bar (20% post-verification) by default
-    const char *src_root_path = argv[0];
-    const char *dst_root_path = argv[1];
-    ui_print("Writing %s...\n", dst_root_path);
-    if (!gDidShowProgress) ui_show_progress(DEFAULT_IMAGE_PROGRESS_FRACTION, 0);
-
-    /* Find the source image, which is probably in a package.
-     */
-    if (!is_package_root_path(src_root_path)) {
-        LOGE("Command %s: non-package source path \"%s\" not yet supported\n",
-                name, src_root_path);
-        return 255;
-    }
-
-    /* Get the package.
-     */
-    char srcpathbuf[PATH_MAX];
-    const char *src_path;
-    const ZipArchive *package;
-    src_path = translate_package_root_path(src_root_path,
-            srcpathbuf, sizeof(srcpathbuf), &package);
-    if (src_path == NULL) {
-        LOGE("Command %s: bad source path \"%s\"\n", name, src_root_path);
-        return 1;
-    }
-
-    /* Get the entry.
-     */
-    const ZipEntry *entry = mzFindZipEntry(package, src_path);
-    if (entry == NULL) {
-        LOGE("Missing file %s\n", src_path);
-        return 1;
-    }
-
-    /* Unmount the destination root if it isn't already.
-     */
-    int ret = ensure_root_path_unmounted(dst_root_path);
-    if (ret < 0) {
-        LOGE("Can't unmount %s\n", dst_root_path);
-        return 1;
-    }
-
-    /* Open the partition for writing.
-     */
-    const MtdPartition *partition = get_root_mtd_partition(dst_root_path);
-    if (partition == NULL) {
-        LOGE("Can't find %s\n", dst_root_path);
-        return 1;
-    }
-    MtdWriteContext *context = mtd_write_partition(partition);
-    if (context == NULL) {
-        LOGE("Can't open %s\n", dst_root_path);
-        return 1;
-    }
-
-    /* Extract and write the image.
-     */
-    bool ok = mzProcessZipEntryContents(package, entry,
-            write_raw_image_process_fn, context);
-    if (!ok) {
-        LOGE("Error writing %s\n", dst_root_path);
-        mtd_write_close(context);
-        return 1;
-    }
-
-    if (mtd_erase_blocks(context, -1) == (off_t) -1) {
-        LOGE("Error finishing %s\n", dst_root_path);
-        mtd_write_close(context);
-        return -1;
-    }
-
-    if (mtd_write_close(context)) {
-        LOGE("Error closing %s\n", dst_root_path);
-        return -1;
-    }
-    return 0;
-}
-
-/* mark <resource> dirty|clean
- */
-static int
-cmd_mark(const char *name, void *cookie, int argc, const char *argv[])
-{
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_WORDS();
-//xxx when marking, save the top-level hash at the mark point
-//    so we can retry on failure.  Otherwise the hashes won't match,
-//    or someone could intentionally dirty the FS to force a downgrade
-//xxx
-    return -1;
-}
-
-/* done
- */
-static int
-cmd_done(const char *name, void *cookie, int argc, const char *argv[])
-{
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_WORDS();
-//xxx
-    return -1;
-}
-
-
-/*
- * Function definitions
- */
-
-/* compatible_with(<version>)
- *
- * Returns "true" if this version of the script parser and command
- * set supports the named version.
- */
-static int
-fn_compatible_with(const char *name, void *cookie, int argc, const char *argv[],
-        char **result, size_t *resultLen)
-{
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_FN();
-
-    if (argc != 1) {
-        fprintf(stderr, "%s: wrong number of arguments (%d)\n",
-                name, argc);
-        return 1;
-    }
-
-    if (!strcmp(argv[0], "0.1") || !strcmp(argv[0], "0.2")) {
-        *result = strdup("true");
-    } else {
-        *result = strdup("");
-    }
-    if (resultLen != NULL) {
-        *resultLen = strlen(*result);
-    }
-    return 0;
-}
-
-/* update_forced()
- *
- * Returns "true" if some system setting has determined that
- * the update should happen no matter what.
- */
-static int
-fn_update_forced(const char *name, void *cookie, int argc, const char *argv[],
-        char **result, size_t *resultLen)
-{
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_FN();
-
-    if (argc != 0) {
-        fprintf(stderr, "%s: wrong number of arguments (%d)\n",
-                name, argc);
-        return 1;
-    }
-
-    //xxx check some global or property
-    bool force = true;
-    if (force) {
-        *result = strdup("true");
-    } else {
-        *result = strdup("");
-    }
-    if (resultLen != NULL) {
-        *resultLen = strlen(*result);
-    }
-
-    return 0;
-}
-
-/* get_mark(<resource>)
- *
- * Returns the current mark associated with the provided resource.
- */
-static int
-fn_get_mark(const char *name, void *cookie, int argc, const char *argv[],
-        char **result, size_t *resultLen)
-{
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_FN();
-
-    if (argc != 1) {
-        fprintf(stderr, "%s: wrong number of arguments (%d)\n",
-                name, argc);
-        return 1;
-    }
-
-    //xxx look up the value
-    *result = strdup("");
-    if (resultLen != NULL) {
-        *resultLen = strlen(*result);
-    }
-
-    return 0;
-}
-
-/* hash_dir(<path-to-directory>)
- */
-static int
-fn_hash_dir(const char *name, void *cookie, int argc, const char *argv[],
-        char **result, size_t *resultLen)
-{
-    int ret = -1;
-
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_FN();
-
-    const char *dir;
-    if (argc != 1) {
-        fprintf(stderr, "%s: wrong number of arguments (%d)\n",
-                name, argc);
-        return 1;
-    } else {
-        dir = argv[0];
-    }
-
-    return ret;
-}
-
-/* matches(<str>, <str1> [, <strN>...])
- * If <str> matches (strcmp) any of <str1>...<strN>, returns <str>,
- * otherwise returns "".
- *
- * E.g., assert matches(hash_dir("/path"), "hash1", "hash2")
- */
-static int
-fn_matches(const char *name, void *cookie, int argc, const char *argv[],
-        char **result, size_t *resultLen)
-{
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_FN();
-
-    if (argc < 2) {
-        fprintf(stderr, "%s: not enough arguments (%d < 2)\n",
-                name, argc);
-        return 1;
-    }
-
-    int i;
-    for (i = 1; i < argc; i++) {
-        if (strcmp(argv[0], argv[i]) == 0) {
-            *result = strdup(argv[0]);
-            if (resultLen != NULL) {
-                *resultLen = strlen(*result);
-            }
-            return 0;
-        }
-    }
-
-    *result = strdup("");
-    if (resultLen != NULL) {
-        *resultLen = 1;
-    }
-    return 0;
-}
-
-/* concat(<str>, <str1> [, <strN>...])
- * Returns the concatenation of all strings.
- */
-static int
-fn_concat(const char *name, void *cookie, int argc, const char *argv[],
-        char **result, size_t *resultLen)
-{
-    UNUSED(name);
-    UNUSED(cookie);
-    CHECK_FN();
-
-    size_t totalLen = 0;
-    int i;
-    for (i = 0; i < argc; i++) {
-        totalLen += strlen(argv[i]);
-    }
-
-    char *s = (char *)malloc(totalLen + 1);
-    if (s == NULL) {
-        return -1;
-    }
-    s[totalLen] = '\0';
-    for (i = 0; i < argc; i++) {
-        //TODO: keep track of the end to avoid walking the string each time
-        strcat(s, argv[i]);
-    }
-    *result = s;
-    if (resultLen != NULL) {
-        *resultLen = strlen(s);
-    }
-
-    return 0;
-}
-
-/* getprop(<property>)
- * Returns the named Android system property value, or "" if not set.
- */
-static int
-fn_getprop(const char *name, void *cookie, int argc, const char *argv[],
-        char **result, size_t *resultLen)
-{
-    UNUSED(cookie);
-    CHECK_FN();
-
-    if (argc != 1) {
-        LOGE("Command %s requires exactly one argument\n", name);
-        return 1;
-    }
-
-    char value[PROPERTY_VALUE_MAX];
-    property_get(argv[0], value, "");
-
-    *result = strdup(value);
-    if (resultLen != NULL) {
-        *resultLen = strlen(*result);
-    }
-
-    return 0;
-}
-
-/* file_contains(<filename>, <substring>)
- * Returns "true" if the file exists and contains the specified substring.
- */
-static int
-fn_file_contains(const char *name, void *cookie, int argc, const char *argv[],
-        char **result, size_t *resultLen)
-{
-    UNUSED(cookie);
-    CHECK_FN();
-
-    if (argc != 2) {
-        LOGE("Command %s requires exactly two arguments\n", name);
-        return 1;
-    }
-
-    char pathbuf[PATH_MAX];
-    const char *root_path = argv[0];
-    const char *path = translate_root_path(root_path, pathbuf, sizeof(pathbuf));
-    if (path == NULL) {
-        LOGE("Command %s: bad path \"%s\"\n", name, root_path);
-        return 1;
-    }
-
-    if (ensure_root_path_mounted(root_path)) {
-        LOGE("Can't mount %s\n", root_path);
-        return 1;
-    }
-
-    const char *needle = argv[1];
-    char *haystack = (char*) load_file(path, NULL);
-    if (haystack == NULL) {
-        LOGI("%s: Can't read \"%s\" (%s)\n", name, path, strerror(errno));
-        *result = "";  /* File not found is not an error. */
-    } else if (strstr(haystack, needle) == NULL) {
-        LOGI("%s: Can't find \"%s\" in \"%s\"\n", name, needle, path);
-        *result = strdup("");
-        free(haystack);
-    } else {
-        *result = strdup("true");
-        free(haystack);
-    }
-
-    if (resultLen != NULL) {
-        *resultLen = strlen(*result);
-    }
-    return 0;
-}
-
-int
-register_update_commands(RecoveryCommandContext *ctx)
-{
-    int ret;
-
-    ret = commandInit();
-    if (ret < 0) return ret;
-
-    /*
-     * Commands
-     */
-
-    ret = registerCommand("assert", CMD_ARGS_BOOLEAN, cmd_assert, (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerCommand("delete", CMD_ARGS_WORDS, cmd_delete, (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerCommand("delete_recursive", CMD_ARGS_WORDS, cmd_delete,
-            (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerCommand("copy_dir", CMD_ARGS_WORDS,
-            cmd_copy_dir, (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerCommand("run_program", CMD_ARGS_WORDS,
-            cmd_run_program, (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerCommand("set_perm", CMD_ARGS_WORDS,
-            cmd_set_perm, (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerCommand("set_perm_recursive", CMD_ARGS_WORDS,
-            cmd_set_perm, (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerCommand("show_progress", CMD_ARGS_WORDS,
-            cmd_show_progress, (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerCommand("symlink", CMD_ARGS_WORDS, cmd_symlink, (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerCommand("format", CMD_ARGS_WORDS, cmd_format, (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerCommand("write_radio_image", CMD_ARGS_WORDS,
-            cmd_write_firmware_image, (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerCommand("write_hboot_image", CMD_ARGS_WORDS,
-            cmd_write_firmware_image, (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerCommand("write_raw_image", CMD_ARGS_WORDS,
-            cmd_write_raw_image, (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerCommand("mark", CMD_ARGS_WORDS, cmd_mark, (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerCommand("done", CMD_ARGS_WORDS, cmd_done, (void *)ctx);
-    if (ret < 0) return ret;
-
-    /*
-     * Functions
-     */
-
-    ret = registerFunction("compatible_with", fn_compatible_with, (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerFunction("update_forced", fn_update_forced, (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerFunction("get_mark", fn_get_mark, (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerFunction("hash_dir", fn_hash_dir, (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerFunction("matches", fn_matches, (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerFunction("concat", fn_concat, (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerFunction("getprop", fn_getprop, (void *)ctx);
-    if (ret < 0) return ret;
-
-    ret = registerFunction("file_contains", fn_file_contains, (void *)ctx);
-    if (ret < 0) return ret;
-
-    return 0;
-}
diff --git a/commands.h b/commands.h
deleted file mode 100644
index e9acea2..0000000
--- a/commands.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2007 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 RECOVERY_COMMANDS_H_
-#define RECOVERY_COMMANDS_H_
-
-#include "minzip/Zip.h"
-
-typedef struct {
-    ZipArchive *package;
-} RecoveryCommandContext;
-
-int register_update_commands(RecoveryCommandContext *ctx);
-
-#endif  // RECOVERY_COMMANDS_H_
diff --git a/default_recovery_ui.c b/default_recovery_ui.c
new file mode 100644
index 0000000..d4e6204
--- /dev/null
+++ b/default_recovery_ui.c
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#include <linux/input.h>
+
+#include "recovery_ui.h"
+#include "common.h"
+
+char* MENU_HEADERS[] = { "Android system recovery utility",
+                         "",
+                         NULL };
+
+char* MENU_ITEMS[] = { "reboot system now",
+                       "apply sdcard:update.zip",
+                       "wipe data/factory reset",
+                       "wipe cache partition",
+                       NULL };
+
+int device_toggle_display(volatile char* key_pressed, int key_code) {
+    return key_code == KEY_HOME;
+}
+
+int device_reboot_now(volatile char* key_pressed, int key_code) {
+    return 0;
+}
+
+int device_handle_key(int key_code, int visible) {
+    if (visible) {
+        switch (key_code) {
+            case KEY_DOWN:
+            case KEY_VOLUMEDOWN:
+                return HIGHLIGHT_DOWN;
+
+            case KEY_UP:
+            case KEY_VOLUMEUP:
+                return HIGHLIGHT_UP;
+
+            case KEY_ENTER:
+                return SELECT_ITEM;
+        }
+    }
+
+    return NO_ACTION;
+}
+
+int device_perform_action(int which) {
+    return which;
+}
+
+int device_wipe_data() {
+    return 0;
+}
diff --git a/install.c b/install.c
index ab19478..2c557ea 100644
--- a/install.c
+++ b/install.c
@@ -22,7 +22,6 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
-#include "amend/amend.h"
 #include "common.h"
 #include "install.h"
 #include "mincrypt/rsa.h"
@@ -35,85 +34,9 @@
 #include "verifier.h"
 #include "firmware.h"
 
-#define ASSUMED_UPDATE_SCRIPT_NAME  "META-INF/com/google/android/update-script"
 #define ASSUMED_UPDATE_BINARY_NAME  "META-INF/com/google/android/update-binary"
 #define PUBLIC_KEYS_FILE "/res/keys"
 
-static const ZipEntry *
-find_update_script(ZipArchive *zip)
-{
-//TODO: Get the location of this script from the MANIFEST.MF file
-    return mzFindZipEntry(zip, ASSUMED_UPDATE_SCRIPT_NAME);
-}
-
-static int read_data(ZipArchive *zip, const ZipEntry *entry,
-        char** ppData, int* pLength) {
-    int len = (int)mzGetZipEntryUncompLen(entry);
-    if (len <= 0) {
-        LOGE("Bad data length %d\n", len);
-        return -1;
-    }
-    char *data = malloc(len + 1);
-    if (data == NULL) {
-        LOGE("Can't allocate %d bytes for data\n", len + 1);
-        return -2;
-    }
-    bool ok = mzReadZipEntry(zip, entry, data, len);
-    if (!ok) {
-        LOGE("Error while reading data\n");
-        free(data);
-        return -3;
-    }
-    data[len] = '\0';     // not necessary, but just to be safe
-    *ppData = data;
-    if (pLength) {
-        *pLength = len;
-    }
-    return 0;
-}
-
-static int
-handle_update_script(ZipArchive *zip, const ZipEntry *update_script_entry)
-{
-    /* Read the entire script into a buffer.
-     */
-    int script_len;
-    char* script_data;
-    if (read_data(zip, update_script_entry, &script_data, &script_len) < 0) {
-        LOGE("Can't read update script\n");
-        return INSTALL_ERROR;
-    }
-
-    /* Parse the script.  Note that the script and parse tree are never freed.
-     */
-    const AmCommandList *commands = parseAmendScript(script_data, script_len);
-    if (commands == NULL) {
-        LOGE("Syntax error in update script\n");
-        return INSTALL_ERROR;
-    } else {
-        UnterminatedString name = mzGetZipEntryFileName(update_script_entry);
-        LOGI("Parsed %.*s\n", name.len, name.str);
-    }
-
-    /* Execute the script.
-     */
-    int ret = execCommandList((ExecContext *)1, commands);
-    if (ret != 0) {
-        int num = ret;
-        char *line = NULL, *next = script_data;
-        while (next != NULL && ret-- > 0) {
-            line = next;
-            next = memchr(line, '\n', script_data + script_len - line);
-            if (next != NULL) *next++ = '\0';
-        }
-        LOGE("Failure at line %d:\n%s\n", num, next ? line : "(not found)");
-        return INSTALL_ERROR;
-    }
-
-    LOGI("Installation complete.\n");
-    return INSTALL_SUCCESS;
-}
-
 // The update binary ask us to install a firmware file on reboot.  Set
 // that up.  Takes ownership of type and filename.
 static int
@@ -252,11 +175,9 @@
     char* firmware_type = NULL;
     char* firmware_filename = NULL;
 
-    char buffer[81];
+    char buffer[1024];
     FILE* from_child = fdopen(pipefd[0], "r");
     while (fgets(buffer, sizeof(buffer), from_child) != NULL) {
-        LOGI("read: %s", buffer);
-
         char* command = strtok(buffer, " \n");
         if (command == NULL) {
             continue;
@@ -331,30 +252,8 @@
     ui_print("Installing update...\n");
 
     int result = try_update_binary(path, zip);
-    if (result == INSTALL_SUCCESS || result == INSTALL_ERROR) {
-        register_package_root(NULL, NULL);  // Unregister package root
-        return result;
-    }
-
-    // if INSTALL_CORRUPT is returned, this package doesn't have an
-    // update binary.  Fall back to the older mechanism of looking for
-    // an update script.
-
-    const ZipEntry *script_entry;
-    script_entry = find_update_script(zip);
-    if (script_entry == NULL) {
-        LOGE("Can't find update script\n");
-        return INSTALL_CORRUPT;
-    }
-
-    if (register_package_root(zip, path) < 0) {
-        LOGE("Can't register package root\n");
-        return INSTALL_ERROR;
-    }
-
-    int ret = handle_update_script(zip, script_entry);
     register_package_root(NULL, NULL);  // Unregister package root
-    return ret;
+    return result;
 }
 
 // Reads a file containing one or more public keys as produced by
diff --git a/minui/graphics.c b/minui/graphics.c
index 06c5fdf..adbfc09 100644
--- a/minui/graphics.c
+++ b/minui/graphics.c
@@ -115,6 +115,7 @@
     if (n > 1) return;
     vi.yres_virtual = vi.yres * 2;
     vi.yoffset = n * vi.yres;
+    vi.bits_per_pixel = 16;
     if (ioctl(gr_fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
         perror("active fb swap failed");
     }
diff --git a/minui/minui.h b/minui/minui.h
index 80b47a4..567d421 100644
--- a/minui/minui.h
+++ b/minui/minui.h
@@ -41,22 +41,6 @@
 // see http://www.mjmwired.net/kernel/Documentation/input/ for info.
 struct input_event;
 
-// Dream-specific key codes
-#define KEY_DREAM_HOME        102  // = KEY_HOME
-#define KEY_DREAM_RED         107  // = KEY_END
-#define KEY_DREAM_VOLUMEDOWN  114  // = KEY_VOLUMEDOWN
-#define KEY_DREAM_VOLUMEUP    115  // = KEY_VOLUMEUP
-#define KEY_DREAM_SYM         127  // = KEY_COMPOSE
-#define KEY_DREAM_MENU        139  // = KEY_MENU
-#define KEY_DREAM_BACK        158  // = KEY_BACK
-#define KEY_DREAM_FOCUS       211  // = KEY_HP (light touch on camera)
-#define KEY_DREAM_CAMERA      212  // = KEY_CAMERA
-#define KEY_DREAM_AT          215  // = KEY_EMAIL
-#define KEY_DREAM_GREEN       231
-#define KEY_DREAM_FATTOUCH    258  // = BTN_2 ???
-#define KEY_DREAM_BALL        272  // = BTN_MOUSE
-#define KEY_DREAM_TOUCH       330  // = BTN_TOUCH
-
 int ev_init(void);
 void ev_exit(void);
 int ev_get(struct input_event *ev, unsigned dont_wait);
diff --git a/recovery.c b/recovery.c
index 5ccd38f..ed6a9c8 100644
--- a/recovery.c
+++ b/recovery.c
@@ -29,7 +29,6 @@
 #include <unistd.h>
 
 #include "bootloader.h"
-#include "commands.h"
 #include "common.h"
 #include "cutils/properties.h"
 #include "firmware.h"
@@ -37,6 +36,7 @@
 #include "minui/minui.h"
 #include "minzip/DirUtil.h"
 #include "roots.h"
+#include "recovery_ui.h"
 
 static const struct option OPTIONS[] = {
   { "send_intent", required_argument, NULL, 's' },
@@ -258,23 +258,6 @@
     sync();  // For good measure.
 }
 
-#define TEST_AMEND 0
-#if TEST_AMEND
-static void
-test_amend()
-{
-    extern int test_symtab(void);
-    extern int test_cmd_fn(void);
-    int ret;
-    LOGD("Testing symtab...\n");
-    ret = test_symtab();
-    LOGD("  returned %d\n", ret);
-    LOGD("Testing cmd_fn...\n");
-    ret = test_cmd_fn();
-    LOGD("  returned %d\n", ret);
-}
-#endif  // TEST_AMEND
-
 static int
 erase_root(const char *root)
 {
@@ -287,26 +270,25 @@
 static void
 prompt_and_wait()
 {
-    char* headers[] = { "Android system recovery <"
-                          EXPAND(RECOVERY_API_VERSION) ">",
-                        "",
-                        "Use trackball to highlight;",
-                        "click to select.",
-                        "",
-                        NULL };
-
-    // these constants correspond to elements of the items[] list.
-#define ITEM_REBOOT        0
-#define ITEM_APPLY_SDCARD  1
-#define ITEM_WIPE_DATA     2
-#define ITEM_WIPE_CACHE    3
-    char* items[] = { "reboot system now [Home+Back]",
-                      "apply sdcard:update.zip [Alt+S]",
-                      "wipe data/factory reset [Alt+W]",
-                      "wipe cache partition",
+    char* title[] = { "Android system recovery <"
+                          EXPAND(RECOVERY_API_VERSION) "e>",
+                      "",
                       NULL };
 
-    ui_start_menu(headers, items);
+    // count the number of lines in our title, plus the
+    // product-provided headers.
+    int count = 0;
+    char** p;
+    for (p = title; *p; ++p, ++count);
+    for (p = MENU_HEADERS; *p; ++p, ++count);
+
+    char** headers = malloc((count+1) * sizeof(char*));
+    char** h = headers;
+    for (p = title; *p; ++p, ++h) *h = *p;
+    for (p = MENU_HEADERS; *p; ++p, ++h) *h = *p;
+    *h = NULL;
+
+    ui_start_menu(headers, MENU_ITEMS);
     int selected = 0;
     int chosen_item = -1;
 
@@ -314,29 +296,28 @@
     ui_reset_progress();
     for (;;) {
         int key = ui_wait_key();
-        int alt = ui_key_pressed(KEY_LEFTALT) || ui_key_pressed(KEY_RIGHTALT);
         int visible = ui_text_visible();
 
-        if (key == KEY_DREAM_BACK && ui_key_pressed(KEY_DREAM_HOME)) {
-            // Wait for the keys to be released, to avoid triggering
-            // special boot modes (like coming back into recovery!).
-            while (ui_key_pressed(KEY_DREAM_BACK) ||
-                   ui_key_pressed(KEY_DREAM_HOME)) {
-                usleep(1000);
+        int action = device_handle_key(key, visible);
+
+        if (action < 0) {
+            switch (action) {
+                case HIGHLIGHT_UP:
+                    --selected;
+                    selected = ui_menu_select(selected);
+                    break;
+                case HIGHLIGHT_DOWN:
+                    ++selected;
+                    selected = ui_menu_select(selected);
+                    break;
+                case SELECT_ITEM:
+                    chosen_item = selected;
+                    break;
+                case NO_ACTION:
+                    break;
             }
-            chosen_item = ITEM_REBOOT;
-        } else if (alt && key == KEY_W) {
-            chosen_item = ITEM_WIPE_DATA;
-        } else if (alt && key == KEY_S) {
-            chosen_item = ITEM_APPLY_SDCARD;
-        } else if ((key == KEY_DOWN || key == KEY_VOLUMEDOWN) && visible) {
-            ++selected;
-            selected = ui_menu_select(selected);
-        } else if ((key == KEY_UP || key == KEY_VOLUMEUP) && visible) {
-            --selected;
-            selected = ui_menu_select(selected);
-        } else if (key == BTN_MOUSE && visible) {
-            chosen_item = selected;
+        } else {
+            chosen_item = action;
         }
 
         if (chosen_item >= 0) {
@@ -344,12 +325,18 @@
             // on the screen.
             ui_end_menu();
 
+            // device-specific code may take some action here.  It may
+            // return one of the core actions handled in the switch
+            // statement below.
+            chosen_item = device_perform_action(chosen_item);
+
             switch (chosen_item) {
                 case ITEM_REBOOT:
                     return;
 
                 case ITEM_WIPE_DATA:
                     ui_print("\n-- Wiping data...\n");
+                    device_wipe_data();
                     erase_root("DATA:");
                     erase_root("CACHE:");
                     ui_print("Data wipe complete.\n");
@@ -373,8 +360,8 @@
                         return;  // reboot if logs aren't visible
                     } else {
                       if (firmware_update_pending()) {
-                        ui_print("\nReboot via home+back or menu\n"
-                                 "to complete installation.\n");
+                        ui_print("\nReboot via menu to complete\n"
+                                 "installation.\n");
                       } else {
                         ui_print("\nInstall from sdcard complete.\n");
                       }
@@ -384,7 +371,7 @@
 
             // if we didn't return from this function to reboot, show
             // the menu again.
-            ui_start_menu(headers, items);
+            ui_start_menu(headers, MENU_ITEMS);
             selected = 0;
             chosen_item = -1;
 
@@ -445,24 +432,19 @@
     property_list(print_property, NULL);
     fprintf(stderr, "\n");
 
-#if TEST_AMEND
-    test_amend();
-#endif
-
-    RecoveryCommandContext ctx = { NULL };
-    if (register_update_commands(&ctx)) {
-        LOGE("Can't install update commands\n");
-    }
-
     int status = INSTALL_SUCCESS;
 
     if (update_package != NULL) {
         status = install_package(update_package);
         if (status != INSTALL_SUCCESS) ui_print("Installation aborted.\n");
-    } else if (wipe_data || wipe_cache) {
-        if (wipe_data && erase_root("DATA:")) status = INSTALL_ERROR;
+    } else if (wipe_data) {
+        if (device_wipe_data()) status = INSTALL_ERROR;
+        if (erase_root("DATA:")) status = INSTALL_ERROR;
         if (wipe_cache && erase_root("CACHE:")) status = INSTALL_ERROR;
         if (status != INSTALL_SUCCESS) ui_print("Data wipe failed.\n");
+    } else if (wipe_cache) {
+        if (wipe_cache && erase_root("CACHE:")) status = INSTALL_ERROR;
+        if (status != INSTALL_SUCCESS) ui_print("Cache wipe failed.\n");
     } else {
         status = INSTALL_ERROR;  // No command specified
     }
diff --git a/recovery_ui.h b/recovery_ui.h
new file mode 100644
index 0000000..8818ef3
--- /dev/null
+++ b/recovery_ui.h
@@ -0,0 +1,76 @@
+/*
+ * 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 _RECOVERY_UI_H
+#define _RECOVERY_UI_H
+
+// Called in the input thread when a new key (key_code) is pressed.
+// *key_pressed is an array of KEY_MAX+1 bytes indicating which other
+// keys are already pressed.  Return true if the text display should
+// be toggled.
+extern int device_toggle_display(volatile char* key_pressed, int key_code);
+
+// Called in the input thread when a new key (key_code) is pressed.
+// *key_pressed is an array of KEY_MAX+1 bytes indicating which other
+// keys are already pressed.  Return true if the device should reboot
+// immediately.
+extern int device_reboot_now(volatile char* key_pressed, int key_code);
+
+// Called from the main thread when recovery is waiting for input and
+// a key is pressed.  key is the code of the key pressed; visible is
+// true if the recovery menu is being shown.  Implementations can call
+// ui_key_pressed() to discover if other keys are being held down.
+// Return one of the defined constants below in order to:
+//
+//   - move the menu highlight (HIGHLIGHT_*)
+//   - invoke the highlighted item (SELECT_ITEM)
+//   - do nothing (NO_ACTION)
+//   - invoke a specific action (a menu position: any non-negative number)
+extern int device_handle_key(int key, int visible);
+
+// Perform a recovery action selected from the menu.  'which' will be
+// the item number of the selected menu item, or a non-negative number
+// returned from device_handle_key().  The menu will be hidden when
+// this is called; implementations can call ui_print() to print
+// information to the screen.
+extern int device_perform_action(int which);
+
+// Called when we do a wipe data/factory reset operation (either via a
+// reboot from the main system with the --wipe_data flag, or when the
+// user boots into recovery manually and selects the option from the
+// menu.)  Can perform whatever device-specific wiping actions are
+// needed.  Return 0 on success.  The userdata and cache partitions
+// are erased after this returns (whether it returns success or not).
+int device_wipe_data();
+
+#define NO_ACTION           -1
+
+#define HIGHLIGHT_UP        -2
+#define HIGHLIGHT_DOWN      -3
+#define SELECT_ITEM         -4
+
+#define ITEM_REBOOT          0
+#define ITEM_APPLY_SDCARD    1
+#define ITEM_WIPE_DATA       2
+#define ITEM_WIPE_CACHE      3
+
+// Header text to display above the main menu.
+extern char* MENU_HEADERS[];
+
+// Text of menu items.
+extern char* MENU_ITEMS[];
+
+#endif
diff --git a/res/images/icon_error.png b/res/images/icon_error.png
index 7064c2e..6cb71c0 100644
--- a/res/images/icon_error.png
+++ b/res/images/icon_error.png
Binary files differ
diff --git a/res/images/icon_firmware_install.png b/res/images/icon_firmware_install.png
index ee2afac..8bfe775 100644
--- a/res/images/icon_firmware_install.png
+++ b/res/images/icon_firmware_install.png
Binary files differ
diff --git a/res/images/icon_installing.png b/res/images/icon_installing.png
index f24f2e3..1aeb9d9 100644
--- a/res/images/icon_installing.png
+++ b/res/images/icon_installing.png
Binary files differ
diff --git a/roots.c b/roots.c
index 6a6cf8a..8f8dace 100644
--- a/roots.c
+++ b/roots.c
@@ -52,6 +52,7 @@
     { "RECOVERY:", g_mtd_device, NULL, "recovery", "/", g_raw },
     { "SDCARD:", "/dev/block/mmcblk0p1", "/dev/block/mmcblk0", NULL, "/sdcard", "vfat" },
     { "SYSTEM:", g_mtd_device, NULL, "system", "/system", "yaffs2" },
+    { "MBM:", g_mtd_device, NULL, "mbm", NULL, g_raw },
     { "TMP:", NULL, NULL, NULL, "/tmp", NULL },
 };
 #define NUM_ROOTS (sizeof(g_roots) / sizeof(g_roots[0]))
diff --git a/tools/ota/Android.mk b/tools/ota/Android.mk
index b7a57d6..0bde7ee 100644
--- a/tools/ota/Android.mk
+++ b/tools/ota/Android.mk
@@ -14,11 +14,6 @@
 
 LOCAL_PATH := $(call my-dir)
 
-include $(CLEAR_VARS)
-LOCAL_MODULE := make-update-script
-LOCAL_SRC_FILES := make-update-script.c
-include $(BUILD_HOST_EXECUTABLE)
-
 ifneq ($(TARGET_SIMULATOR),true)
 
 include $(CLEAR_VARS)
diff --git a/tools/ota/make-update-script.c b/tools/ota/make-update-script.c
deleted file mode 100644
index 1e1148b..0000000
--- a/tools/ota/make-update-script.c
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * 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.
- */
-
-#include "private/android_filesystem_config.h"
-
-#include <dirent.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-/*
- * Recursively walk the directory tree at <sysdir>/<subdir>, writing
- * script commands to set permissions and create symlinks.
- * Assume the contents already have the specified default permissions,
- * so only output commands if they need to be changed from the defaults.
- *
- * Note that permissions are set by fs_config(), which uses a lookup table of
- * Android permissions.  They are not drawn from the build host filesystem.
- */
-static void walk_files(
-        const char *sysdir, const char *subdir,
-        unsigned default_uid, unsigned default_gid,
-        unsigned default_dir_mode, unsigned default_file_mode) {
-    const char *sep = strcmp(subdir, "") ? "/" : "";
-
-    char fn[PATH_MAX];
-    unsigned dir_uid = 0, dir_gid = 0, dir_mode = 0;
-    snprintf(fn, PATH_MAX, "system%s%s", sep, subdir);
-    fs_config(fn, 1, &dir_uid, &dir_gid, &dir_mode);
-
-    snprintf(fn, PATH_MAX, "%s%s%s", sysdir, sep, subdir);
-    DIR *dir = opendir(fn);
-    if (dir == NULL) {
-        perror(fn);
-        exit(1);
-    }
-
-    /*
-     * We can use "set_perm" and "set_perm_recursive" to set file permissions
-     * (owner, group, and file mode) for individual files and entire subtrees.
-     * We want to use set_perm_recursive efficiently to avoid setting the
-     * permissions of every single file in the system image individually.
-     *
-     * What we do is recursively set our entire subtree to the permissions
-     * used by the first file we encounter, and then use "set_perm" to adjust
-     * the permissions of subsequent files which don't match the first one.
-     * This is bad if the first file is an outlier, but it generally works.
-     * Subdirectories can do the same thing recursively if they're different.
-     */
-
-    int is_first = 1;
-    const struct dirent *e;
-    while ((e = readdir(dir))) {
-        // Skip over "." and ".." entries
-        if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, "..")) continue;
-
-        if (e->d_type == DT_LNK) {  // Symlink
-
-            // Symlinks don't really have permissions, so this is orthogonal.
-            snprintf(fn, PATH_MAX, "%s/%s%s%s", sysdir, subdir, sep, e->d_name);
-            int len = readlink(fn, fn, PATH_MAX - 1);
-            if (len <= 0) {
-                perror(fn);
-                exit(1);
-            }
-            fn[len] = '\0';
-            printf("symlink %s SYSTEM:%s%s%s\n", fn, subdir, sep, e->d_name);
-
-        } else if (e->d_type == DT_DIR) {  // Subdirectory
-
-            // Use the parent directory as the model for default permissions.
-            // We haven't seen a file, so just make up some file defaults.
-            if (is_first && (
-                    dir_mode != default_dir_mode ||
-                    dir_uid != default_uid || dir_gid != default_gid)) {
-                default_uid = dir_uid;
-                default_gid = dir_gid;
-                default_dir_mode = dir_mode;
-                default_file_mode = dir_mode & default_file_mode & 0666;
-                printf("set_perm_recursive %d %d 0%o 0%o SYSTEM:%s\n",
-                         default_uid, default_gid,
-                         default_dir_mode, default_file_mode,
-                         subdir);
-            }
-
-            is_first = 0;
-
-            // Recursively handle the subdirectory.
-            // Note, the recursive call handles the directory's own permissions.
-            snprintf(fn, PATH_MAX, "%s%s%s", subdir, sep, e->d_name);
-            walk_files(sysdir, fn,
-                    default_uid, default_gid,
-                    default_dir_mode, default_file_mode);
-
-        } else {  // Ordinary file
-
-            // Get the file's desired permissions.
-            unsigned file_uid = 0, file_gid = 0, file_mode = 0;
-            snprintf(fn, PATH_MAX, "system/%s%s%s", subdir, sep, e->d_name);
-            fs_config(fn, 0, &file_uid, &file_gid, &file_mode);
-
-            // If this is the first file, its mode gets to become the default.
-            if (is_first && (
-                    dir_mode != default_dir_mode ||
-                    file_mode != default_file_mode ||
-                    dir_uid != default_uid || file_uid != default_uid ||
-                    dir_gid != default_gid || file_gid != default_gid)) {
-                default_uid = dir_uid;
-                default_gid = dir_gid;
-                default_dir_mode = dir_mode;
-                default_file_mode = file_mode;
-                printf("set_perm_recursive %d %d 0%o 0%o SYSTEM:%s\n",
-                         default_uid, default_gid,
-                         default_dir_mode, default_file_mode,
-                         subdir);
-            }
-
-            is_first = 0;
-
-            // Otherwise, override this file if it doesn't match the defaults.
-            if (file_mode != default_file_mode ||
-                file_uid != default_uid || file_gid != default_gid) {
-                printf("set_perm %d %d 0%o SYSTEM:%s%s%s\n",
-                         file_uid, file_gid, file_mode,
-                         subdir, sep, e->d_name);
-            }
-
-        }
-    }
-
-    // Set the directory's permissions directly, if they never got set.
-    if (dir_mode != default_dir_mode ||
-        dir_uid != default_uid || dir_gid != default_gid) {
-        printf("set_perm %d %d 0%o SYSTEM:%s\n",
-                dir_uid, dir_gid, dir_mode, subdir);
-    }
-
-    closedir(dir);
-}
-
-/*
- * Generate the update script (in "Amend", see commands/recovery/commands.c)
- * for the complete-reinstall OTA update packages the build system makes.
- *
- * The generated script makes a variety of sanity checks about the device,
- * erases and reinstalls system files, and sets file permissions appropriately.
- */
-int main(int argc, char *argv[]) {
-    if (argc != 3) {
-        fprintf(stderr, "usage: %s systemdir android-info.txt >update-script\n",
-                argv[0]);
-        return 2;
-    }
-
-    // ensure basic recovery script language compatibility
-    printf("assert compatible_with(\"0.2\") == \"true\"\n");
-
-    // if known, make sure the device name is correct
-    const char *device = getenv("TARGET_DEVICE");
-    if (device != NULL) {
-        printf("assert getprop(\"ro.product.device\") == \"%s\" || "
-                "getprop(\"ro.build.product\") == \"%s\"\n", device, device);
-    }
-
-    // scan android-info.txt to enforce compatibility with the target system
-    FILE *fp = fopen(argv[2], "r");
-    if (fp == NULL) {
-        perror(argv[2]);
-        return 1;
-    }
-
-    // The lines we're looking for look like:
-    //     version-bootloader=x.yy.zzzz|x.yy.zzzz|...
-    // or:
-    //     require version-bootloader=x.yy.zzzz|x.yy.zzzz|...
-    char line[256];
-    while (fgets(line, sizeof(line), fp)) {
-        const char *name = strtok(line, "="), *value = strtok(NULL, "|\n");
-        if (value != NULL &&
-            (!strcmp(name, "version-bootloader") ||
-             !strcmp(name, "require version-bootloader"))) {
-            printf("assert getprop(\"ro.bootloader\") == \"%s\"", value);
-
-            while ((value = strtok(NULL, "|\n")) != NULL) {
-              printf(" || getprop(\"ro.bootloader\") == \"%s\"", value);
-            }
-            printf("\n");
-        }
-        // We also used to check version-baseband, but we update radio.img
-        // ourselves, so there's no need.
-    }
-
-    // erase the boot sector first, so if the update gets interrupted,
-    // the system will reboot into the recovery partition and start over.
-    printf("format BOOT:\n");
-
-    // write the radio image (actually just loads it into RAM for now)
-    printf("show_progress 0.1 0\n");
-    printf("write_radio_image PACKAGE:radio.img\n");
-
-    // erase and reinstall the system image
-    printf("show_progress 0.5 0\n");
-    printf("format SYSTEM:\n");
-    printf("copy_dir PACKAGE:system SYSTEM:\n");
-
-    // walk the files in the system image, set their permissions, etc.
-    // use -1 for default values to force permissions to be set explicitly.
-    walk_files(argv[1], "", -1, -1, -1, -1);
-
-    // as the last step, write the boot sector.
-    printf("show_progress 0.2 0\n");
-    printf("write_raw_image PACKAGE:boot.img BOOT:\n");
-
-    // after the end of the script, the radio will be written to cache
-    // leave some space in the progress bar for this operation
-    printf("show_progress 0.2 10\n");
-    return 0;
-}
diff --git a/ui.c b/ui.c
index b84f172..0a8b985 100644
--- a/ui.c
+++ b/ui.c
@@ -27,6 +27,7 @@
 
 #include "common.h"
 #include "minui/minui.h"
+#include "recovery_ui.h"
 
 #define MAX_COLS 64
 #define MAX_ROWS 32
@@ -307,20 +308,14 @@
         }
         pthread_mutex_unlock(&key_queue_mutex);
 
-        // Alt+L or Home+End: toggle log display
-        int alt = key_pressed[KEY_LEFTALT] || key_pressed[KEY_RIGHTALT];
-        if ((alt && ev.code == KEY_L && ev.value > 0) ||
-            (key_pressed[KEY_HOME] && ev.code == KEY_END && ev.value > 0)) {
+        if (ev.value > 0 && device_toggle_display(key_pressed, ev.code)) {
             pthread_mutex_lock(&gUpdateMutex);
             show_text = !show_text;
             update_screen_locked();
             pthread_mutex_unlock(&gUpdateMutex);
         }
 
-        // Green+Menu+Red: reboot immediately
-        if (ev.code == KEY_DREAM_RED &&
-            key_pressed[KEY_DREAM_MENU] &&
-            key_pressed[KEY_DREAM_GREEN]) {
+        if (ev.value > 0 && device_reboot_now(key_pressed, ev.code)) {
             reboot(RB_AUTOBOOT);
         }
     }
diff --git a/updater/Android.mk b/updater/Android.mk
index 897b9d7..d4a4e33 100644
--- a/updater/Android.mk
+++ b/updater/Android.mk
@@ -18,11 +18,47 @@
 
 LOCAL_SRC_FILES := $(updater_src_files)
 
-LOCAL_STATIC_LIBRARIES := libapplypatch libedify libmtdutils libminzip libz
+LOCAL_STATIC_LIBRARIES := $(TARGET_RECOVERY_UPDATER_LIBS) $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS)
+LOCAL_STATIC_LIBRARIES += libapplypatch libedify libmtdutils libminzip libz
 LOCAL_STATIC_LIBRARIES += libmincrypt libbz
 LOCAL_STATIC_LIBRARIES += libcutils libstdc++ libc
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
 
+# Each library in TARGET_RECOVERY_UPDATER_LIBS should have a function
+# named "Register_<libname>()".  Here we emit a little C function that
+# gets #included by updater.c.  It calls all those registration
+# functions.
+
+# Devices can also add libraries to TARGET_RECOVERY_UPDATER_EXTRA_LIBS.
+# These libs are also linked in with updater, but we don't try to call
+# any sort of registration function for these.  Use this variable for
+# any subsidiary static libraries required for your registered
+# extension libs.
+
+inc := $(call intermediates-dir-for,PACKAGING,updater_extensions)/register.inc
+
+# During the first pass of reading the makefiles, we dump the list of
+# extension libs to a temp file, then copy that to the ".list" file if
+# it is different than the existing .list (if any).  The register.inc
+# file then uses the .list as a prerequisite, so it is only rebuilt
+# (and updater.o recompiled) when the list of extension libs changes.
+
+junk := $(shell mkdir -p $(dir $(inc));\
+	        echo $(TARGET_RECOVERY_UPDATER_LIBS) > $(inc).temp;\
+	        diff -q $(inc).temp $(inc).list || cp -f $(inc).temp $(inc).list)
+
+$(inc) : libs := $(TARGET_RECOVERY_UPDATER_LIBS)
+$(inc) : $(inc).list
+	$(hide) mkdir -p $(dir $@)
+	$(hide) echo "" > $@
+	$(hide) $(foreach lib,$(libs),echo "extern void Register_$(lib)(void);" >> $@)
+	$(hide) echo "void RegisterDeviceExtensions() {" >> $@
+	$(hide) $(foreach lib,$(libs),echo "  Register_$(lib)();" >> $@)
+	$(hide) echo "}" >> $@
+
+$(call intermediates-dir-for,EXECUTABLES,updater)/updater.o : $(inc)
+LOCAL_C_INCLUDES += $(dir $(inc))
+
 LOCAL_MODULE := updater
 
 LOCAL_FORCE_STATIC_EXECUTABLE := true
diff --git a/updater/updater.c b/updater/updater.c
index 31d93ae..1aa277c 100644
--- a/updater/updater.c
+++ b/updater/updater.c
@@ -23,6 +23,11 @@
 #include "install.h"
 #include "minzip/Zip.h"
 
+// Generated by the makefile, this function defines the
+// RegisterDeviceExtensions() function, which calls all the
+// registration functions for device-specific extensions.
+#include "register.inc"
+
 // Where in the package we expect to find the edify script to execute.
 // (Note it's "updateR-script", not the older "update-script".)
 #define SCRIPT_NAME "META-INF/com/google/android/updater-script"
@@ -76,6 +81,7 @@
 
     RegisterBuiltins();
     RegisterInstallFunctions();
+    RegisterDeviceExtensions();
     FinishRegistration();
 
     // Parse the script.