remove amend
Yank all the code to install OTA packages out of the recovery binary itself. Now packages are installed by a binary included in the package (run as a child of recovery), so we can make improvements in the installation process without waiting for a new release to use them.
This commit is contained in:
+1
-3
@@ -9,7 +9,6 @@ ifeq ($(TARGET_ARCH),arm)
|
|||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
recovery.c \
|
recovery.c \
|
||||||
bootloader.c \
|
bootloader.c \
|
||||||
commands.c \
|
|
||||||
firmware.c \
|
firmware.c \
|
||||||
install.c \
|
install.c \
|
||||||
roots.c \
|
roots.c \
|
||||||
@@ -32,14 +31,13 @@ LOCAL_CFLAGS += -DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION)
|
|||||||
|
|
||||||
LOCAL_MODULE_TAGS := eng
|
LOCAL_MODULE_TAGS := eng
|
||||||
|
|
||||||
LOCAL_STATIC_LIBRARIES := libminzip libunz libamend libmtdutils libmincrypt
|
LOCAL_STATIC_LIBRARIES := libminzip libunz libmtdutils libmincrypt
|
||||||
LOCAL_STATIC_LIBRARIES += libminui libpixelflinger_static libpng libcutils
|
LOCAL_STATIC_LIBRARIES += libminui libpixelflinger_static libpng libcutils
|
||||||
LOCAL_STATIC_LIBRARIES += libstdc++ libc
|
LOCAL_STATIC_LIBRARIES += libstdc++ libc
|
||||||
|
|
||||||
include $(BUILD_EXECUTABLE)
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|
||||||
include $(commands_recovery_local_path)/minui/Android.mk
|
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)/minzip/Android.mk
|
||||||
include $(commands_recovery_local_path)/mtdutils/Android.mk
|
include $(commands_recovery_local_path)/mtdutils/Android.mk
|
||||||
include $(commands_recovery_local_path)/tools/Android.mk
|
include $(commands_recovery_local_path)/tools/Android.mk
|
||||||
|
|||||||
@@ -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)
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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_
|
|
||||||
-198
@@ -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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-165
@@ -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_
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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_
|
|
||||||
-315
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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_
|
|
||||||
@@ -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_
|
|
||||||
-299
@@ -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;
|
|
||||||
}
|
|
||||||
-189
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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_
|
|
||||||
@@ -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 */
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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_
|
|
||||||
-132
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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_
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
I am a jelly donut.
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
This is a sample no-op test, which does at least serve to verify that the
|
|
||||||
test harness is working.
|
|
||||||
@@ -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.'
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
EOF
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Test to make sure that an empty file is accepted properly.
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Test to make sure that simple command names are tokenized properly.
|
|
||||||
@@ -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
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
"quoted"
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
==
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
99
|
|
||||||
@@ -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
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
IDENTIFIER<comment_on_this_line> EOL
|
|
||||||
IDENTIFIER<none_on_this_one> EOL
|
|
||||||
EOL
|
|
||||||
EOL
|
|
||||||
EOF
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Test to make sure that comments are stripped out.
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Test to make sure that quoted strings are tokenized properly.
|
|
||||||
@@ -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"
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# This should fail
|
|
||||||
test1 "unterminated string
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# This should fail
|
|
||||||
test1 "string with illegal escape \n in the middle"
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Test to make sure that argument words are tokenized properly.
|
|
||||||
@@ -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
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# This should fail
|
|
||||||
test1 "unterminated string
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# This should fail
|
|
||||||
test1 "string with illegal escape \n in the middle"
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
An input script similar to one that will actually be used in practice.
|
|
||||||
@@ -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"
|
|
||||||
@@ -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
|
|
||||||
@@ -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.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
An input script similar to one that will actually be used in practice.
|
|
||||||
@@ -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"
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
-1075
File diff suppressed because it is too large
Load Diff
-28
@@ -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_
|
|
||||||
@@ -22,7 +22,6 @@
|
|||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "amend/amend.h"
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "install.h"
|
#include "install.h"
|
||||||
#include "mincrypt/rsa.h"
|
#include "mincrypt/rsa.h"
|
||||||
@@ -35,85 +34,9 @@
|
|||||||
#include "verifier.h"
|
#include "verifier.h"
|
||||||
#include "firmware.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 ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary"
|
||||||
#define PUBLIC_KEYS_FILE "/res/keys"
|
#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
|
// The update binary ask us to install a firmware file on reboot. Set
|
||||||
// that up. Takes ownership of type and filename.
|
// that up. Takes ownership of type and filename.
|
||||||
static int
|
static int
|
||||||
@@ -252,11 +175,9 @@ try_update_binary(const char *path, ZipArchive *zip) {
|
|||||||
char* firmware_type = NULL;
|
char* firmware_type = NULL;
|
||||||
char* firmware_filename = NULL;
|
char* firmware_filename = NULL;
|
||||||
|
|
||||||
char buffer[81];
|
char buffer[1024];
|
||||||
FILE* from_child = fdopen(pipefd[0], "r");
|
FILE* from_child = fdopen(pipefd[0], "r");
|
||||||
while (fgets(buffer, sizeof(buffer), from_child) != NULL) {
|
while (fgets(buffer, sizeof(buffer), from_child) != NULL) {
|
||||||
LOGI("read: %s", buffer);
|
|
||||||
|
|
||||||
char* command = strtok(buffer, " \n");
|
char* command = strtok(buffer, " \n");
|
||||||
if (command == NULL) {
|
if (command == NULL) {
|
||||||
continue;
|
continue;
|
||||||
@@ -331,30 +252,8 @@ handle_update_package(const char *path, ZipArchive *zip,
|
|||||||
ui_print("Installing update...\n");
|
ui_print("Installing update...\n");
|
||||||
|
|
||||||
int result = try_update_binary(path, zip);
|
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
|
register_package_root(NULL, NULL); // Unregister package root
|
||||||
return ret;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads a file containing one or more public keys as produced by
|
// Reads a file containing one or more public keys as produced by
|
||||||
|
|||||||
+1
-28
@@ -29,7 +29,6 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "bootloader.h"
|
#include "bootloader.h"
|
||||||
#include "commands.h"
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "cutils/properties.h"
|
#include "cutils/properties.h"
|
||||||
#include "firmware.h"
|
#include "firmware.h"
|
||||||
@@ -258,23 +257,6 @@ finish_recovery(const char *send_intent)
|
|||||||
sync(); // For good measure.
|
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
|
static int
|
||||||
erase_root(const char *root)
|
erase_root(const char *root)
|
||||||
{
|
{
|
||||||
@@ -288,7 +270,7 @@ static void
|
|||||||
prompt_and_wait()
|
prompt_and_wait()
|
||||||
{
|
{
|
||||||
char* headers[] = { "Android system recovery <"
|
char* headers[] = { "Android system recovery <"
|
||||||
EXPAND(RECOVERY_API_VERSION) ">",
|
EXPAND(RECOVERY_API_VERSION) "e>",
|
||||||
"",
|
"",
|
||||||
"Use trackball to highlight;",
|
"Use trackball to highlight;",
|
||||||
"click to select.",
|
"click to select.",
|
||||||
@@ -445,15 +427,6 @@ main(int argc, char **argv)
|
|||||||
property_list(print_property, NULL);
|
property_list(print_property, NULL);
|
||||||
fprintf(stderr, "\n");
|
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;
|
int status = INSTALL_SUCCESS;
|
||||||
|
|
||||||
if (update_package != NULL) {
|
if (update_package != NULL) {
|
||||||
|
|||||||
@@ -14,11 +14,6 @@
|
|||||||
|
|
||||||
LOCAL_PATH := $(call my-dir)
|
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)
|
ifneq ($(TARGET_SIMULATOR),true)
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user