diff options
author | David 'Digit' Turner <digit@android.com> | 2010-05-10 18:48:35 -0700 |
---|---|---|
committer | David 'Digit' Turner <digit@android.com> | 2010-05-11 17:10:19 -0700 |
commit | 2910f183ddd5286911bc1e3499ea93cb57de8b75 (patch) | |
tree | 43cfd4b9a6697496732722ff7f2fb66d5782597c | |
parent | 0119362f0d74ca74f3ea743f6e0e527a9edcc474 (diff) | |
download | external_qemu-2910f183ddd5286911bc1e3499ea93cb57de8b75.zip external_qemu-2910f183ddd5286911bc1e3499ea93cb57de8b75.tar.gz external_qemu-2910f183ddd5286911bc1e3499ea93cb57de8b75.tar.bz2 |
Upstream: Misc integration - includes qobject.h and related sources
Change-Id: Idfa93ab5c67c95a3bc1869eeaf3a84a75fe24cd6
-rw-r--r-- | Makefile.android | 12 | ||||
-rw-r--r-- | dyngen-exec.h | 7 | ||||
-rw-r--r-- | elf.h | 2 | ||||
-rw-r--r-- | exec-all.h | 20 | ||||
-rwxr-xr-x | feature_to_c.sh | 6 | ||||
-rw-r--r-- | host-utils.c | 3 | ||||
-rw-r--r-- | host-utils.h | 30 | ||||
-rw-r--r-- | hostregs_helper.h | 5 | ||||
-rwxr-xr-x | hxtool | 4 | ||||
-rw-r--r-- | i386-dis.c | 6 | ||||
-rw-r--r-- | i386.ld | 1 | ||||
-rw-r--r-- | ia64.ld | 4 | ||||
-rw-r--r-- | json-lexer.c | 327 | ||||
-rw-r--r-- | json-lexer.h | 50 | ||||
-rw-r--r-- | json-parser.c | 566 | ||||
-rw-r--r-- | json-parser.h | 22 | ||||
-rw-r--r-- | json-streamer.c | 88 | ||||
-rw-r--r-- | json-streamer.h | 39 | ||||
-rw-r--r-- | keymaps.c | 4 | ||||
-rw-r--r-- | m68k.ld | 4 | ||||
-rw-r--r-- | osdep.c | 11 | ||||
-rw-r--r-- | osdep.h | 21 | ||||
-rw-r--r-- | ppc-dis.c | 14 | ||||
-rw-r--r-- | ppc.ld | 1 | ||||
-rw-r--r-- | qbool.c | 76 | ||||
-rw-r--r-- | qbool.h | 29 | ||||
-rw-r--r-- | qdict.c | 356 | ||||
-rw-r--r-- | qdict.h | 49 | ||||
-rw-r--r-- | qemu-aio.h | 5 | ||||
-rw-r--r-- | qemu-lock.h | 3 | ||||
-rw-r--r-- | qemu-malloc.c | 19 | ||||
-rw-r--r-- | qemu-objects.h | 24 | ||||
-rw-r--r-- | qemu-option.c | 542 | ||||
-rw-r--r-- | qemu-option.h | 58 | ||||
-rw-r--r-- | qerror.c | 359 | ||||
-rw-r--r-- | qerror.h | 109 | ||||
-rw-r--r-- | qfloat.c | 76 | ||||
-rw-r--r-- | qfloat.h | 29 | ||||
-rw-r--r-- | qint.c | 66 | ||||
-rw-r--r-- | qint.h | 16 | ||||
-rw-r--r-- | qjson.c | 247 | ||||
-rw-r--r-- | qjson.h | 28 | ||||
-rw-r--r-- | qlist.c | 156 | ||||
-rw-r--r-- | qlist.h | 52 | ||||
-rw-r--r-- | qobject.h | 112 | ||||
-rw-r--r-- | qstring.c | 140 | ||||
-rw-r--r-- | qstring.h | 23 | ||||
-rw-r--r-- | sdl_keysym.h | 2 | ||||
-rw-r--r-- | softmmu_header.h | 149 | ||||
-rw-r--r-- | softmmu_template.h | 9 | ||||
-rw-r--r-- | sparc.ld | 21 | ||||
-rw-r--r-- | thunk.c | 3 | ||||
-rw-r--r-- | thunk.h | 3 | ||||
-rw-r--r-- | translate-all.c | 3 | ||||
-rw-r--r-- | uboot_image.h | 3 | ||||
-rw-r--r-- | vl-android.c | 55 | ||||
-rw-r--r-- | vnc_keysym.h | 2 | ||||
-rw-r--r-- | vnchextile.h | 2 | ||||
-rw-r--r-- | x86_64.ld | 1 |
59 files changed, 3733 insertions, 341 deletions
diff --git a/Makefile.android b/Makefile.android index 62dc2fe..598b430 100644 --- a/Makefile.android +++ b/Makefile.android @@ -49,7 +49,7 @@ ifeq ($(HOST_ARCH),ppc) endif ifeq ($(HOST_OS),darwin) - MY_CFLAGS += -mdynamic-no-pic -fno-exceptions + MY_CFLAGS += -mdynamic-no-pic # When building on Leopard or above, we need to use the 10.4 SDK # or the generated binary will not run on Tiger. @@ -575,6 +575,16 @@ VL_SOURCES := vl-android.c osdep.c cutils.c \ bt-host.c \ bt-vhci.c \ module.c \ + json-lexer.c \ + json-parser.c \ + json-streamer.c \ + qbool.c \ + qdict.c \ + qfloat.c \ + qint.c \ + qjson.c \ + qlist.c \ + qstring.c \ android/boot-properties.c \ android/charmap.c \ android/cmdline-option.c \ diff --git a/dyngen-exec.h b/dyngen-exec.h index b649263..0353f36 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -14,8 +14,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #if !defined(__DYNGEN_EXEC_H__) #define __DYNGEN_EXEC_H__ @@ -48,8 +47,6 @@ typedef struct FILE FILE; extern int fprintf(FILE *, const char *, ...); extern int fputs(const char *, FILE *); extern int printf(const char *, ...); -#undef NULL -#define NULL 0 #if defined(__i386__) #define AREG0 "ebp" @@ -120,7 +117,7 @@ extern int printf(const char *, ...); /* The return address may point to the start of the next instruction. Subtracting one gets us the call instruction itself. */ -#if defined(__s390__) +#if defined(__s390__) && !defined(__s390x__) # define GETPC() ((void*)(((unsigned long)__builtin_return_address(0) & 0x7fffffffUL) - 1)) #elif defined(__arm__) /* Thumb return addresses have the low bit set, so we need to subtract two. @@ -454,7 +454,9 @@ typedef struct { #define R_PPC_SECTOFF_HI 35 #define R_PPC_SECTOFF_HA 36 /* Keep this the last entry. */ +#ifndef R_PPC_NUM #define R_PPC_NUM 37 +#endif /* ARM specific declarations */ @@ -14,8 +14,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #ifndef _EXEC_ALL_H_ @@ -35,17 +34,17 @@ typedef struct TranslationBlock TranslationBlock; /* XXX: make safe guess about sizes */ -#define MAX_OP_PER_INSTR 64 +#define MAX_OP_PER_INSTR 96 /* A Call op needs up to 6 + 2N parameters (N = number of arguments). */ #define MAX_OPC_PARAM 10 #define OPC_BUF_SIZE 2048 #define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR) /* Maximum size a TCG op can expand to. This is complicated because a - single op may require several host instructions and regirster reloads. - For now take a wild guess at 128 bytes, which should allow at least + single op may require several host instructions and register reloads. + For now take a wild guess at 192 bytes, which should allow at least a couple of fixup instructions per argument. */ -#define TCG_MAX_OP_SIZE 128 +#define TCG_MAX_OP_SIZE 192 #define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * MAX_OPC_PARAM) @@ -115,10 +114,7 @@ static inline int tlb_set_page(CPUState *env1, target_ulong vaddr, #define CODE_GEN_AVG_BLOCK_SIZE 64 #endif -#if defined(_ARCH_PPC) || defined(__x86_64__) || defined(__arm__) -#define USE_DIRECT_JUMP -#endif -#if defined(__i386__) && !defined(_WIN32) +#if defined(_ARCH_PPC) || defined(__x86_64__) || defined(__arm__) || defined(__i386__) #define USE_DIRECT_JUMP #endif @@ -283,7 +279,9 @@ static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr #endif /* we could use a ldr pc, [pc, #-4] kind of branch and avoid the flush */ - *(uint32_t *)jmp_addr |= ((addr - (jmp_addr + 8)) >> 2) & 0xffffff; + *(uint32_t *)jmp_addr = + (*(uint32_t *)jmp_addr & ~0xffffff) + | (((addr - (jmp_addr + 8)) >> 2) & 0xffffff); #if QEMU_GNUC_PREREQ(4, 1) __clear_cache((char *) jmp_addr, (char *) jmp_addr + 4); diff --git a/feature_to_c.sh b/feature_to_c.sh index bce77b6..dbf9f19 100755 --- a/feature_to_c.sh +++ b/feature_to_c.sh @@ -17,9 +17,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, -# Boston, MA 02110-1301, USA. +# along with this program; if not, see <http://www.gnu.org/licenses/>. output=$1 shift @@ -74,5 +72,5 @@ for input; do echo " { \"$basename\", $arrayname }," >> $output done -echo " { 0, 0 }" >> $output +echo " { (char *)0, (char *)0 }" >> $output echo "};" >> $output diff --git a/host-utils.c b/host-utils.c index f92c339..dc96123 100644 --- a/host-utils.c +++ b/host-utils.c @@ -23,7 +23,8 @@ * THE SOFTWARE. */ -#include "exec.h" +#include <stdlib.h> +#include <stdint.h> #include "host-utils.h" //#define DEBUG_MULDIV diff --git a/host-utils.h b/host-utils.h index 2128615..5848c64 100644 --- a/host-utils.h +++ b/host-utils.h @@ -27,7 +27,7 @@ #if defined(__x86_64__) #define __HAVE_FAST_MULU64__ -static always_inline void mulu64 (uint64_t *plow, uint64_t *phigh, +static inline void mulu64(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) { __asm__ ("mul %0\n\t" @@ -35,7 +35,7 @@ static always_inline void mulu64 (uint64_t *plow, uint64_t *phigh, : "a" (a), "0" (b)); } #define __HAVE_FAST_MULS64__ -static always_inline void muls64 (uint64_t *plow, uint64_t *phigh, +static inline void muls64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) { __asm__ ("imul %0\n\t" @@ -49,7 +49,7 @@ void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b); /* Binary search for leading zeros. */ -static always_inline int clz32(uint32_t val) +static inline int clz32(uint32_t val) { #if QEMU_GNUC_PREREQ(3, 4) if (val) @@ -86,12 +86,12 @@ static always_inline int clz32(uint32_t val) #endif } -static always_inline int clo32(uint32_t val) +static inline int clo32(uint32_t val) { return clz32(~val); } -static always_inline int clz64(uint64_t val) +static inline int clz64(uint64_t val) { #if QEMU_GNUC_PREREQ(3, 4) if (val) @@ -111,12 +111,12 @@ static always_inline int clz64(uint64_t val) #endif } -static always_inline int clo64(uint64_t val) +static inline int clo64(uint64_t val) { return clz64(~val); } -static always_inline int ctz32(uint32_t val) +static inline int ctz32(uint32_t val) { #if QEMU_GNUC_PREREQ(3, 4) if (val) @@ -155,16 +155,16 @@ static always_inline int ctz32(uint32_t val) #endif } -static always_inline int cto32(uint32_t val) +static inline int cto32(uint32_t val) { return ctz32(~val); } -static always_inline int ctz64(uint64_t val) +static inline int ctz64(uint64_t val) { #if QEMU_GNUC_PREREQ(3, 4) if (val) - return __builtin_ctz(val); + return __builtin_ctzll(val); else return 64; #else @@ -180,12 +180,12 @@ static always_inline int ctz64(uint64_t val) #endif } -static always_inline int cto64(uint64_t val) +static inline int cto64(uint64_t val) { return ctz64(~val); } -static always_inline int ctpop8(uint8_t val) +static inline int ctpop8(uint8_t val) { val = (val & 0x55) + ((val >> 1) & 0x55); val = (val & 0x33) + ((val >> 2) & 0x33); @@ -194,7 +194,7 @@ static always_inline int ctpop8(uint8_t val) return val; } -static always_inline int ctpop16(uint16_t val) +static inline int ctpop16(uint16_t val) { val = (val & 0x5555) + ((val >> 1) & 0x5555); val = (val & 0x3333) + ((val >> 2) & 0x3333); @@ -204,7 +204,7 @@ static always_inline int ctpop16(uint16_t val) return val; } -static always_inline int ctpop32(uint32_t val) +static inline int ctpop32(uint32_t val) { #if QEMU_GNUC_PREREQ(3, 4) return __builtin_popcount(val); @@ -219,7 +219,7 @@ static always_inline int ctpop32(uint32_t val) #endif } -static always_inline int ctpop64(uint64_t val) +static inline int ctpop64(uint64_t val) { #if QEMU_GNUC_PREREQ(3, 4) return __builtin_popcountll(val); diff --git a/hostregs_helper.h b/hostregs_helper.h index c206baf..3a0bece 100644 --- a/hostregs_helper.h +++ b/hostregs_helper.h @@ -1,5 +1,5 @@ /* - * Save/restore host registrs. + * Save/restore host registers. * * Copyright (c) 2007 CodeSourcery * @@ -14,8 +14,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ /* The GCC global register variable extension is used to reserve some @@ -26,10 +26,10 @@ hxtotexi() STEXI*|ETEXI*) flag=$(($flag^1)) ;; DEFHEADING*) - echo $(expr "$str" : "DEFHEADING(\(.*\))") + echo "$(expr "$str" : "DEFHEADING(\(.*\))")" ;; *) - test $flag -eq 1 && echo $str + test $flag -eq 1 && echo "$str" ;; esac done @@ -16,8 +16,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + along with this program; if not, see <http://www.gnu.org/licenses/>. */ /* 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) July 1988 @@ -54,8 +53,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + along with this program; if not, see <http://www.gnu.org/licenses/>. */ /* The SystemV/386 SVR3.2 assembler, and probably all AT&T derived ix86 Unix assemblers, generate floating point instructions with @@ -3,7 +3,6 @@ */ OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) -SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib); ENTRY(_start) SECTIONS { @@ -3,9 +3,7 @@ OUTPUT_FORMAT("elf64-ia64-little", "elf64-ia64-little", "elf64-ia64-little") OUTPUT_ARCH(ia64) ENTRY(_start) -SEARCH_DIR("/usr/ia64-linux/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib"); -/* Do we need any of these for elf? - __DYNAMIC = 0; */ +/* __DYNAMIC = 0; */ SECTIONS { /* Read-only sections, merged into text segment: */ diff --git a/json-lexer.c b/json-lexer.c new file mode 100644 index 0000000..53697c5 --- /dev/null +++ b/json-lexer.c @@ -0,0 +1,327 @@ +/* + * JSON lexer + * + * Copyright IBM, Corp. 2009 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qstring.h" +#include "qlist.h" +#include "qdict.h" +#include "qint.h" +#include "qemu-common.h" +#include "json-lexer.h" + +/* + * \"([^\\\"]|(\\\"\\'\\\\\\/\\b\\f\\n\\r\\t\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))*\" + * '([^\\']|(\\\"\\'\\\\\\/\\b\\f\\n\\r\\t\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))*' + * 0|([1-9][0-9]*(.[0-9]+)?([eE]([-+])?[0-9]+)) + * [{}\[\],:] + * [a-z]+ + * + */ + +enum json_lexer_state { + ERROR = 0, + IN_DONE_STRING, + IN_DQ_UCODE3, + IN_DQ_UCODE2, + IN_DQ_UCODE1, + IN_DQ_UCODE0, + IN_DQ_STRING_ESCAPE, + IN_DQ_STRING, + IN_SQ_UCODE3, + IN_SQ_UCODE2, + IN_SQ_UCODE1, + IN_SQ_UCODE0, + IN_SQ_STRING_ESCAPE, + IN_SQ_STRING, + IN_ZERO, + IN_DIGITS, + IN_DIGIT, + IN_EXP_E, + IN_MANTISSA, + IN_MANTISSA_DIGITS, + IN_NONZERO_NUMBER, + IN_NEG_NONZERO_NUMBER, + IN_KEYWORD, + IN_ESCAPE, + IN_ESCAPE_L, + IN_ESCAPE_LL, + IN_ESCAPE_DONE, + IN_WHITESPACE, + IN_OPERATOR_DONE, + IN_START, +}; + +#define TERMINAL(state) [0 ... 0x7F] = (state) + +static const uint8_t json_lexer[][256] = { + [IN_DONE_STRING] = { + TERMINAL(JSON_STRING), + }, + + /* double quote string */ + [IN_DQ_UCODE3] = { + ['0' ... '9'] = IN_DQ_STRING, + ['a' ... 'f'] = IN_DQ_STRING, + ['A' ... 'F'] = IN_DQ_STRING, + }, + [IN_DQ_UCODE2] = { + ['0' ... '9'] = IN_DQ_UCODE3, + ['a' ... 'f'] = IN_DQ_UCODE3, + ['A' ... 'F'] = IN_DQ_UCODE3, + }, + [IN_DQ_UCODE1] = { + ['0' ... '9'] = IN_DQ_UCODE2, + ['a' ... 'f'] = IN_DQ_UCODE2, + ['A' ... 'F'] = IN_DQ_UCODE2, + }, + [IN_DQ_UCODE0] = { + ['0' ... '9'] = IN_DQ_UCODE1, + ['a' ... 'f'] = IN_DQ_UCODE1, + ['A' ... 'F'] = IN_DQ_UCODE1, + }, + [IN_DQ_STRING_ESCAPE] = { + ['b'] = IN_DQ_STRING, + ['f'] = IN_DQ_STRING, + ['n'] = IN_DQ_STRING, + ['r'] = IN_DQ_STRING, + ['t'] = IN_DQ_STRING, + ['\''] = IN_DQ_STRING, + ['\"'] = IN_DQ_STRING, + ['u'] = IN_DQ_UCODE0, + }, + [IN_DQ_STRING] = { + [1 ... 0xFF] = IN_DQ_STRING, + ['\\'] = IN_DQ_STRING_ESCAPE, + ['"'] = IN_DONE_STRING, + }, + + /* single quote string */ + [IN_SQ_UCODE3] = { + ['0' ... '9'] = IN_SQ_STRING, + ['a' ... 'f'] = IN_SQ_STRING, + ['A' ... 'F'] = IN_SQ_STRING, + }, + [IN_SQ_UCODE2] = { + ['0' ... '9'] = IN_SQ_UCODE3, + ['a' ... 'f'] = IN_SQ_UCODE3, + ['A' ... 'F'] = IN_SQ_UCODE3, + }, + [IN_SQ_UCODE1] = { + ['0' ... '9'] = IN_SQ_UCODE2, + ['a' ... 'f'] = IN_SQ_UCODE2, + ['A' ... 'F'] = IN_SQ_UCODE2, + }, + [IN_SQ_UCODE0] = { + ['0' ... '9'] = IN_SQ_UCODE1, + ['a' ... 'f'] = IN_SQ_UCODE1, + ['A' ... 'F'] = IN_SQ_UCODE1, + }, + [IN_SQ_STRING_ESCAPE] = { + ['b'] = IN_SQ_STRING, + ['f'] = IN_SQ_STRING, + ['n'] = IN_SQ_STRING, + ['r'] = IN_SQ_STRING, + ['t'] = IN_SQ_STRING, + ['\''] = IN_SQ_STRING, + ['\"'] = IN_SQ_STRING, + ['u'] = IN_SQ_UCODE0, + }, + [IN_SQ_STRING] = { + [1 ... 0xFF] = IN_SQ_STRING, + ['\\'] = IN_SQ_STRING_ESCAPE, + ['\''] = IN_DONE_STRING, + }, + + /* Zero */ + [IN_ZERO] = { + TERMINAL(JSON_INTEGER), + ['0' ... '9'] = ERROR, + ['.'] = IN_MANTISSA, + }, + + /* Float */ + [IN_DIGITS] = { + TERMINAL(JSON_FLOAT), + ['0' ... '9'] = IN_DIGITS, + }, + + [IN_DIGIT] = { + ['0' ... '9'] = IN_DIGITS, + }, + + [IN_EXP_E] = { + ['-'] = IN_DIGIT, + ['+'] = IN_DIGIT, + ['0' ... '9'] = IN_DIGITS, + }, + + [IN_MANTISSA_DIGITS] = { + TERMINAL(JSON_FLOAT), + ['0' ... '9'] = IN_MANTISSA_DIGITS, + ['e'] = IN_EXP_E, + ['E'] = IN_EXP_E, + }, + + [IN_MANTISSA] = { + ['0' ... '9'] = IN_MANTISSA_DIGITS, + }, + + /* Number */ + [IN_NONZERO_NUMBER] = { + TERMINAL(JSON_INTEGER), + ['0' ... '9'] = IN_NONZERO_NUMBER, + ['e'] = IN_EXP_E, + ['E'] = IN_EXP_E, + ['.'] = IN_MANTISSA, + }, + + [IN_NEG_NONZERO_NUMBER] = { + ['0'] = IN_ZERO, + ['1' ... '9'] = IN_NONZERO_NUMBER, + }, + + /* keywords */ + [IN_KEYWORD] = { + TERMINAL(JSON_KEYWORD), + ['a' ... 'z'] = IN_KEYWORD, + }, + + /* whitespace */ + [IN_WHITESPACE] = { + TERMINAL(JSON_SKIP), + [' '] = IN_WHITESPACE, + ['\t'] = IN_WHITESPACE, + ['\r'] = IN_WHITESPACE, + ['\n'] = IN_WHITESPACE, + }, + + /* operator */ + [IN_OPERATOR_DONE] = { + TERMINAL(JSON_OPERATOR), + }, + + /* escape */ + [IN_ESCAPE_DONE] = { + TERMINAL(JSON_ESCAPE), + }, + + [IN_ESCAPE_LL] = { + ['d'] = IN_ESCAPE_DONE, + }, + + [IN_ESCAPE_L] = { + ['d'] = IN_ESCAPE_DONE, + ['l'] = IN_ESCAPE_LL, + }, + + [IN_ESCAPE] = { + ['d'] = IN_ESCAPE_DONE, + ['i'] = IN_ESCAPE_DONE, + ['p'] = IN_ESCAPE_DONE, + ['s'] = IN_ESCAPE_DONE, + ['f'] = IN_ESCAPE_DONE, + ['l'] = IN_ESCAPE_L, + }, + + /* top level rule */ + [IN_START] = { + ['"'] = IN_DQ_STRING, + ['\''] = IN_SQ_STRING, + ['0'] = IN_ZERO, + ['1' ... '9'] = IN_NONZERO_NUMBER, + ['-'] = IN_NEG_NONZERO_NUMBER, + ['{'] = IN_OPERATOR_DONE, + ['}'] = IN_OPERATOR_DONE, + ['['] = IN_OPERATOR_DONE, + [']'] = IN_OPERATOR_DONE, + [','] = IN_OPERATOR_DONE, + [':'] = IN_OPERATOR_DONE, + ['a' ... 'z'] = IN_KEYWORD, + ['%'] = IN_ESCAPE, + [' '] = IN_WHITESPACE, + ['\t'] = IN_WHITESPACE, + ['\r'] = IN_WHITESPACE, + ['\n'] = IN_WHITESPACE, + }, +}; + +void json_lexer_init(JSONLexer *lexer, JSONLexerEmitter func) +{ + lexer->emit = func; + lexer->state = IN_START; + lexer->token = qstring_new(); +} + +static int json_lexer_feed_char(JSONLexer *lexer, char ch) +{ + char buf[2]; + + lexer->x++; + if (ch == '\n') { + lexer->x = 0; + lexer->y++; + } + + lexer->state = json_lexer[lexer->state][(uint8_t)ch]; + + switch (lexer->state) { + case JSON_OPERATOR: + case JSON_ESCAPE: + case JSON_INTEGER: + case JSON_FLOAT: + case JSON_KEYWORD: + case JSON_STRING: + lexer->emit(lexer, lexer->token, lexer->state, lexer->x, lexer->y); + case JSON_SKIP: + lexer->state = json_lexer[IN_START][(uint8_t)ch]; + QDECREF(lexer->token); + lexer->token = qstring_new(); + break; + case ERROR: + return -EINVAL; + default: + break; + } + + buf[0] = ch; + buf[1] = 0; + + qstring_append(lexer->token, buf); + + return 0; +} + +int json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size) +{ + size_t i; + + for (i = 0; i < size; i++) { + int err; + + err = json_lexer_feed_char(lexer, buffer[i]); + if (err < 0) { + return err; + } + } + + return 0; +} + +int json_lexer_flush(JSONLexer *lexer) +{ + return json_lexer_feed_char(lexer, 0); +} + +void json_lexer_destroy(JSONLexer *lexer) +{ + QDECREF(lexer->token); +} diff --git a/json-lexer.h b/json-lexer.h new file mode 100644 index 0000000..3b50c46 --- /dev/null +++ b/json-lexer.h @@ -0,0 +1,50 @@ +/* + * JSON lexer + * + * Copyright IBM, Corp. 2009 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#ifndef QEMU_JSON_LEXER_H +#define QEMU_JSON_LEXER_H + +#include "qstring.h" +#include "qlist.h" + +typedef enum json_token_type { + JSON_OPERATOR = 100, + JSON_INTEGER, + JSON_FLOAT, + JSON_KEYWORD, + JSON_STRING, + JSON_ESCAPE, + JSON_SKIP, +} JSONTokenType; + +typedef struct JSONLexer JSONLexer; + +typedef void (JSONLexerEmitter)(JSONLexer *, QString *, JSONTokenType, int x, int y); + +struct JSONLexer +{ + JSONLexerEmitter *emit; + int state; + QString *token; + int x, y; +}; + +void json_lexer_init(JSONLexer *lexer, JSONLexerEmitter func); + +int json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size); + +int json_lexer_flush(JSONLexer *lexer); + +void json_lexer_destroy(JSONLexer *lexer); + +#endif diff --git a/json-parser.c b/json-parser.c new file mode 100644 index 0000000..e04932f --- /dev/null +++ b/json-parser.c @@ -0,0 +1,566 @@ +/* + * JSON Parser + * + * Copyright IBM, Corp. 2009 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include <stdbool.h> + +#include "qemu-common.h" +#include "qstring.h" +#include "qint.h" +#include "qdict.h" +#include "qlist.h" +#include "qfloat.h" +#include "qbool.h" +#include "json-parser.h" +#include "json-lexer.h" + +typedef struct JSONParserContext +{ +} JSONParserContext; + +#define BUG_ON(cond) assert(!(cond)) + +/** + * TODO + * + * 0) make errors meaningful again + * 1) add geometry information to tokens + * 3) should we return a parsed size? + * 4) deal with premature EOI + */ + +static QObject *parse_value(JSONParserContext *ctxt, QList **tokens, va_list *ap); + +/** + * Token manipulators + * + * tokens are dictionaries that contain a type, a string value, and geometry information + * about a token identified by the lexer. These are routines that make working with + * these objects a bit easier. + */ +static const char *token_get_value(QObject *obj) +{ + return qdict_get_str(qobject_to_qdict(obj), "token"); +} + +static JSONTokenType token_get_type(QObject *obj) +{ + return qdict_get_int(qobject_to_qdict(obj), "type"); +} + +static int token_is_operator(QObject *obj, char op) +{ + const char *val; + + if (token_get_type(obj) != JSON_OPERATOR) { + return 0; + } + + val = token_get_value(obj); + + return (val[0] == op) && (val[1] == 0); +} + +static int token_is_keyword(QObject *obj, const char *value) +{ + if (token_get_type(obj) != JSON_KEYWORD) { + return 0; + } + + return strcmp(token_get_value(obj), value) == 0; +} + +static int token_is_escape(QObject *obj, const char *value) +{ + if (token_get_type(obj) != JSON_ESCAPE) { + return 0; + } + + return (strcmp(token_get_value(obj), value) == 0); +} + +/** + * Error handler + */ +static void parse_error(JSONParserContext *ctxt, QObject *token, const char *msg, ...) +{ + fprintf(stderr, "parse error: %s\n", msg); +} + +/** + * String helpers + * + * These helpers are used to unescape strings. + */ +static void wchar_to_utf8(uint16_t wchar, char *buffer, size_t buffer_length) +{ + if (wchar <= 0x007F) { + BUG_ON(buffer_length < 2); + + buffer[0] = wchar & 0x7F; + buffer[1] = 0; + } else if (wchar <= 0x07FF) { + BUG_ON(buffer_length < 3); + + buffer[0] = 0xC0 | ((wchar >> 6) & 0x1F); + buffer[1] = 0x80 | (wchar & 0x3F); + buffer[2] = 0; + } else { + BUG_ON(buffer_length < 4); + + buffer[0] = 0xE0 | ((wchar >> 12) & 0x0F); + buffer[1] = 0x80 | ((wchar >> 6) & 0x3F); + buffer[2] = 0x80 | (wchar & 0x3F); + buffer[3] = 0; + } +} + +static int hex2decimal(char ch) +{ + if (ch >= '0' && ch <= '9') { + return (ch - '0'); + } else if (ch >= 'a' && ch <= 'f') { + return 10 + (ch - 'a'); + } else if (ch >= 'A' && ch <= 'F') { + return 10 + (ch - 'A'); + } + + return -1; +} + +/** + * parse_string(): Parse a json string and return a QObject + * + * string + * "" + * " chars " + * chars + * char + * char chars + * char + * any-Unicode-character- + * except-"-or-\-or- + * control-character + * \" + * \\ + * \/ + * \b + * \f + * \n + * \r + * \t + * \u four-hex-digits + */ +static QString *qstring_from_escaped_str(JSONParserContext *ctxt, QObject *token) +{ + const char *ptr = token_get_value(token); + QString *str; + int double_quote = 1; + + if (*ptr == '"') { + double_quote = 1; + } else { + double_quote = 0; + } + ptr++; + + str = qstring_new(); + while (*ptr && + ((double_quote && *ptr != '"') || (!double_quote && *ptr != '\''))) { + if (*ptr == '\\') { + ptr++; + + switch (*ptr) { + case '"': + qstring_append(str, "\""); + ptr++; + break; + case '\'': + qstring_append(str, "'"); + ptr++; + break; + case '\\': + qstring_append(str, "\\"); + ptr++; + break; + case '/': + qstring_append(str, "/"); + ptr++; + break; + case 'b': + qstring_append(str, "\b"); + ptr++; + break; + case 'n': + qstring_append(str, "\n"); + ptr++; + break; + case 'r': + qstring_append(str, "\r"); + ptr++; + break; + case 't': + qstring_append(str, "\t"); + ptr++; + break; + case 'u': { + uint16_t unicode_char = 0; + char utf8_char[4]; + int i = 0; + + ptr++; + + for (i = 0; i < 4; i++) { + if (qemu_isxdigit(*ptr)) { + unicode_char |= hex2decimal(*ptr) << ((3 - i) * 4); + } else { + parse_error(ctxt, token, + "invalid hex escape sequence in string"); + goto out; + } + ptr++; + } + + wchar_to_utf8(unicode_char, utf8_char, sizeof(utf8_char)); + qstring_append(str, utf8_char); + } break; + default: + parse_error(ctxt, token, "invalid escape sequence in string"); + goto out; + } + } else { + char dummy[2]; + + dummy[0] = *ptr++; + dummy[1] = 0; + + qstring_append(str, dummy); + } + } + + return str; + +out: + QDECREF(str); + return NULL; +} + +/** + * Parsing rules + */ +static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, va_list *ap) +{ + QObject *key, *token = NULL, *value, *peek; + QList *working = qlist_copy(*tokens); + + peek = qlist_peek(working); + key = parse_value(ctxt, &working, ap); + if (qobject_type(key) != QTYPE_QSTRING) { + parse_error(ctxt, peek, "key is not a string in object"); + goto out; + } + + token = qlist_pop(working); + if (!token_is_operator(token, ':')) { + parse_error(ctxt, token, "missing : in object pair"); + goto out; + } + + value = parse_value(ctxt, &working, ap); + if (value == NULL) { + parse_error(ctxt, token, "Missing value in dict"); + goto out; + } + + qdict_put_obj(dict, qstring_get_str(qobject_to_qstring(key)), value); + + qobject_decref(token); + qobject_decref(key); + QDECREF(*tokens); + *tokens = working; + + return 0; + +out: + qobject_decref(token); + qobject_decref(key); + QDECREF(working); + + return -1; +} + +static QObject *parse_object(JSONParserContext *ctxt, QList **tokens, va_list *ap) +{ + QDict *dict = NULL; + QObject *token, *peek; + QList *working = qlist_copy(*tokens); + + token = qlist_pop(working); + if (!token_is_operator(token, '{')) { + goto out; + } + qobject_decref(token); + token = NULL; + + dict = qdict_new(); + + peek = qlist_peek(working); + if (!token_is_operator(peek, '}')) { + if (parse_pair(ctxt, dict, &working, ap) == -1) { + goto out; + } + + token = qlist_pop(working); + while (!token_is_operator(token, '}')) { + if (!token_is_operator(token, ',')) { + parse_error(ctxt, token, "expected separator in dict"); + goto out; + } + qobject_decref(token); + token = NULL; + + if (parse_pair(ctxt, dict, &working, ap) == -1) { + goto out; + } + + token = qlist_pop(working); + } + qobject_decref(token); + token = NULL; + } else { + token = qlist_pop(working); + qobject_decref(token); + token = NULL; + } + + QDECREF(*tokens); + *tokens = working; + + return QOBJECT(dict); + +out: + qobject_decref(token); + QDECREF(working); + QDECREF(dict); + return NULL; +} + +static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap) +{ + QList *list = NULL; + QObject *token, *peek; + QList *working = qlist_copy(*tokens); + + token = qlist_pop(working); + if (!token_is_operator(token, '[')) { + goto out; + } + qobject_decref(token); + token = NULL; + + list = qlist_new(); + + peek = qlist_peek(working); + if (!token_is_operator(peek, ']')) { + QObject *obj; + + obj = parse_value(ctxt, &working, ap); + if (obj == NULL) { + parse_error(ctxt, token, "expecting value"); + goto out; + } + + qlist_append_obj(list, obj); + + token = qlist_pop(working); + while (!token_is_operator(token, ']')) { + if (!token_is_operator(token, ',')) { + parse_error(ctxt, token, "expected separator in list"); + goto out; + } + + qobject_decref(token); + token = NULL; + + obj = parse_value(ctxt, &working, ap); + if (obj == NULL) { + parse_error(ctxt, token, "expecting value"); + goto out; + } + + qlist_append_obj(list, obj); + + token = qlist_pop(working); + } + + qobject_decref(token); + token = NULL; + } else { + token = qlist_pop(working); + qobject_decref(token); + token = NULL; + } + + QDECREF(*tokens); + *tokens = working; + + return QOBJECT(list); + +out: + qobject_decref(token); + QDECREF(working); + QDECREF(list); + return NULL; +} + +static QObject *parse_keyword(JSONParserContext *ctxt, QList **tokens) +{ + QObject *token, *ret; + QList *working = qlist_copy(*tokens); + + token = qlist_pop(working); + + if (token_get_type(token) != JSON_KEYWORD) { + goto out; + } + + if (token_is_keyword(token, "true")) { + ret = QOBJECT(qbool_from_int(true)); + } else if (token_is_keyword(token, "false")) { + ret = QOBJECT(qbool_from_int(false)); + } else { + parse_error(ctxt, token, "invalid keyword `%s'", token_get_value(token)); + goto out; + } + + qobject_decref(token); + QDECREF(*tokens); + *tokens = working; + + return ret; + +out: + qobject_decref(token); + QDECREF(working); + + return NULL; +} + +static QObject *parse_escape(JSONParserContext *ctxt, QList **tokens, va_list *ap) +{ + QObject *token = NULL, *obj; + QList *working = qlist_copy(*tokens); + + if (ap == NULL) { + goto out; + } + + token = qlist_pop(working); + + if (token_is_escape(token, "%p")) { + obj = va_arg(*ap, QObject *); + } else if (token_is_escape(token, "%i")) { + obj = QOBJECT(qbool_from_int(va_arg(*ap, int))); + } else if (token_is_escape(token, "%d")) { + obj = QOBJECT(qint_from_int(va_arg(*ap, int))); + } else if (token_is_escape(token, "%ld")) { + obj = QOBJECT(qint_from_int(va_arg(*ap, long))); + } else if (token_is_escape(token, "%lld")) { + obj = QOBJECT(qint_from_int(va_arg(*ap, long long))); + } else if (token_is_escape(token, "%s")) { + obj = QOBJECT(qstring_from_str(va_arg(*ap, const char *))); + } else if (token_is_escape(token, "%f")) { + obj = QOBJECT(qfloat_from_double(va_arg(*ap, double))); + } else { + goto out; + } + + qobject_decref(token); + QDECREF(*tokens); + *tokens = working; + + return obj; + +out: + qobject_decref(token); + QDECREF(working); + + return NULL; +} + +static QObject *parse_literal(JSONParserContext *ctxt, QList **tokens) +{ + QObject *token, *obj; + QList *working = qlist_copy(*tokens); + + token = qlist_pop(working); + switch (token_get_type(token)) { + case JSON_STRING: + obj = QOBJECT(qstring_from_escaped_str(ctxt, token)); + break; + case JSON_INTEGER: + obj = QOBJECT(qint_from_int(strtoll(token_get_value(token), NULL, 10))); + break; + case JSON_FLOAT: + /* FIXME dependent on locale */ + obj = QOBJECT(qfloat_from_double(strtod(token_get_value(token), NULL))); + break; + default: + goto out; + } + + qobject_decref(token); + QDECREF(*tokens); + *tokens = working; + + return obj; + +out: + qobject_decref(token); + QDECREF(working); + + return NULL; +} + +static QObject *parse_value(JSONParserContext *ctxt, QList **tokens, va_list *ap) +{ + QObject *obj; + + obj = parse_object(ctxt, tokens, ap); + if (obj == NULL) { + obj = parse_array(ctxt, tokens, ap); + } + if (obj == NULL) { + obj = parse_escape(ctxt, tokens, ap); + } + if (obj == NULL) { + obj = parse_keyword(ctxt, tokens); + } + if (obj == NULL) { + obj = parse_literal(ctxt, tokens); + } + + return obj; +} + +QObject *json_parser_parse(QList *tokens, va_list *ap) +{ + JSONParserContext ctxt = {}; + QList *working = qlist_copy(tokens); + QObject *result; + + result = parse_value(&ctxt, &working, ap); + + QDECREF(working); + + return result; +} diff --git a/json-parser.h b/json-parser.h new file mode 100644 index 0000000..97f43f6 --- /dev/null +++ b/json-parser.h @@ -0,0 +1,22 @@ +/* + * JSON Parser + * + * Copyright IBM, Corp. 2009 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#ifndef QEMU_JSON_PARSER_H +#define QEMU_JSON_PARSER_H + +#include "qemu-common.h" +#include "qlist.h" + +QObject *json_parser_parse(QList *tokens, va_list *ap); + +#endif diff --git a/json-streamer.c b/json-streamer.c new file mode 100644 index 0000000..610ffea --- /dev/null +++ b/json-streamer.c @@ -0,0 +1,88 @@ +/* + * JSON streaming support + * + * Copyright IBM, Corp. 2009 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qlist.h" +#include "qint.h" +#include "qdict.h" +#include "qemu-common.h" +#include "json-lexer.h" +#include "json-streamer.h" + +static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTokenType type, int x, int y) +{ + JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer); + QDict *dict; + + if (type == JSON_OPERATOR) { + switch (qstring_get_str(token)[0]) { + case '{': + parser->brace_count++; + break; + case '}': + parser->brace_count--; + break; + case '[': + parser->bracket_count++; + break; + case ']': + parser->bracket_count--; + break; + default: + break; + } + } + + dict = qdict_new(); + qdict_put_obj(dict, "type", QOBJECT(qint_from_int(type))); + QINCREF(token); + qdict_put_obj(dict, "token", QOBJECT(token)); + qdict_put_obj(dict, "x", QOBJECT(qint_from_int(x))); + qdict_put_obj(dict, "y", QOBJECT(qint_from_int(y))); + + qlist_append(parser->tokens, dict); + + if (parser->brace_count == 0 && + parser->bracket_count == 0) { + parser->emit(parser, parser->tokens); + QDECREF(parser->tokens); + parser->tokens = qlist_new(); + } +} + +void json_message_parser_init(JSONMessageParser *parser, + void (*func)(JSONMessageParser *, QList *)) +{ + parser->emit = func; + parser->brace_count = 0; + parser->bracket_count = 0; + parser->tokens = qlist_new(); + + json_lexer_init(&parser->lexer, json_message_process_token); +} + +int json_message_parser_feed(JSONMessageParser *parser, + const char *buffer, size_t size) +{ + return json_lexer_feed(&parser->lexer, buffer, size); +} + +int json_message_parser_flush(JSONMessageParser *parser) +{ + return json_lexer_flush(&parser->lexer); +} + +void json_message_parser_destroy(JSONMessageParser *parser) +{ + json_lexer_destroy(&parser->lexer); + QDECREF(parser->tokens); +} diff --git a/json-streamer.h b/json-streamer.h new file mode 100644 index 0000000..09f3bd7 --- /dev/null +++ b/json-streamer.h @@ -0,0 +1,39 @@ +/* + * JSON streaming support + * + * Copyright IBM, Corp. 2009 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#ifndef QEMU_JSON_STREAMER_H +#define QEMU_JSON_STREAMER_H + +#include "qlist.h" +#include "json-lexer.h" + +typedef struct JSONMessageParser +{ + void (*emit)(struct JSONMessageParser *parser, QList *tokens); + JSONLexer lexer; + int brace_count; + int bracket_count; + QList *tokens; +} JSONMessageParser; + +void json_message_parser_init(JSONMessageParser *parser, + void (*func)(JSONMessageParser *, QList *)); + +int json_message_parser_feed(JSONMessageParser *parser, + const char *buffer, size_t size); + +int json_message_parser_flush(JSONMessageParser *parser); + +void json_message_parser_destroy(JSONMessageParser *parser); + +#endif @@ -75,7 +75,7 @@ static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table, if (!(filename && (f = fopen(filename, "r")))) { fprintf(stderr, "Could not read keymap file: '%s'\n", language); - return 0; + return NULL; } qemu_free(filename); for(;;) { @@ -144,7 +144,7 @@ static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table, void *init_keyboard_layout(const name2keysym_t *table, const char *language) { - return parse_keyboard_layout(table, language, 0); + return parse_keyboard_layout(table, language, NULL); } @@ -3,9 +3,7 @@ OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k") OUTPUT_ARCH(m68k) ENTRY(_start) -SEARCH_DIR("/usr/local/m68k-linux/lib"); -/* Do we need any of these for elf? - __DYNAMIC = 0; */ +/* __DYNAMIC = 0; */ SECTIONS { /* Read-only sections, merged into text segment: */ @@ -33,6 +33,17 @@ #include <sys/statvfs.h> #endif +/* Needed early for CONFIG_BSD etc. */ +#include "config-host.h" + +#ifdef _WIN32 +#include <windows.h> +#elif defined(CONFIG_BSD) +#include <stdlib.h> +#else +#include <malloc.h> +#endif + #include "qemu-common.h" #include "sysemu.h" @@ -2,6 +2,7 @@ #define QEMU_OSDEP_H #include <stdarg.h> +#include <stddef.h> #ifdef __OpenBSD__ #include <sys/types.h> #include <sys/signal.h> @@ -36,6 +37,19 @@ (type *) ((char *) __mptr - offsetof(type, member));}) #endif +/* Convert from a base type to a parent type, with compile time checking. */ +#ifdef __GNUC__ +#define DO_UPCAST(type, field, dev) ( __extension__ ( { \ + char __attribute__((unused)) offset_must_be_zero[ \ + -offsetof(type, field)]; \ + container_of(dev, type, field);})) +#else +#define DO_UPCAST(type, field, dev) container_of(dev, type, field) +#endif + +#define typeof_field(type, field) typeof(((type *)0)->field) +#define type_check(t1,t2) ((t1*)0 - (t2*)0) + #ifndef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif @@ -48,12 +62,9 @@ #endif #ifndef always_inline -#if (__GNUC__ < 3) || defined(__APPLE__) -#define always_inline inline -#else -#define always_inline __attribute__ (( always_inline )) __inline__ +#if !((__GNUC__ < 3) || defined(__APPLE__)) #ifdef __OPTIMIZE__ -#define inline always_inline +#define inline __attribute__ (( always_inline )) __inline__ #endif #endif #else @@ -16,8 +16,8 @@ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with this file; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ +along with this file; see the file COPYING. If not, +see <http://www.gnu.org/licenses/>. */ #include "dis-asm.h" #define BFD_DEFAULT_TARGET_SIZE 64 @@ -39,8 +39,8 @@ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with this file; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ +along with this file; see the file COPYING. If not, +see <http://www.gnu.org/licenses/>. */ /* The opcode table is an array of struct powerpc_opcode. */ @@ -361,9 +361,8 @@ extern const int powerpc_num_macros; the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this file; see the file COPYING. If not, write to the Free - Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA. */ + along with this file; see the file COPYING. + If not, see <http://www.gnu.org/licenses/>. */ /* This file holds the PowerPC opcode table. The opcode table includes almost all of the extended instruction mnemonics. This @@ -573,6 +572,7 @@ const struct powerpc_operand powerpc_operands[] = /* The DS field in a DS form instruction. This is like D, but the lower two bits are forced to zero. */ +#undef DS #define DS DQ + 1 { 0xfffc, 0, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED | PPC_OPERAND_DS }, @@ -3,7 +3,6 @@ */ OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc") OUTPUT_ARCH(powerpc:common) -SEARCH_DIR(/usr/powerpc-linux-gnu/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib) ENTRY(_start) SECTIONS { @@ -0,0 +1,76 @@ +/* + * QBool Module + * + * Copyright (C) 2009 Red Hat Inc. + * + * Authors: + * Luiz Capitulino <lcapitulino@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Copyright IBM, Corp. 2009 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qbool.h" +#include "qobject.h" +#include "qemu-common.h" + +static void qbool_destroy_obj(QObject *obj); + +static const QType qbool_type = { + .code = QTYPE_QBOOL, + .destroy = qbool_destroy_obj, +}; + +/** + * qbool_from_int(): Create a new QBool from an int + * + * Return strong reference. + */ +QBool *qbool_from_int(int value) +{ + QBool *qb; + + qb = qemu_malloc(sizeof(*qb)); + qb->value = value; + QOBJECT_INIT(qb, &qbool_type); + + return qb; +} + +/** + * qbool_get_int(): Get the stored int + */ +int qbool_get_int(const QBool *qb) +{ + return qb->value; +} + +/** + * qobject_to_qbool(): Convert a QObject into a QBool + */ +QBool *qobject_to_qbool(const QObject *obj) +{ + if (qobject_type(obj) != QTYPE_QBOOL) + return NULL; + + return container_of(obj, QBool, base); +} + +/** + * qbool_destroy_obj(): Free all memory allocated by a + * QBool object + */ +static void qbool_destroy_obj(QObject *obj) +{ + assert(obj != NULL); + qemu_free(qobject_to_qbool(obj)); +} @@ -0,0 +1,29 @@ +/* + * QBool Module + * + * Copyright IBM, Corp. 2009 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#ifndef QBOOL_H +#define QBOOL_H + +#include <stdint.h> +#include "qobject.h" + +typedef struct QBool { + QObject_HEAD; + int value; +} QBool; + +QBool *qbool_from_int(int value); +int qbool_get_int(const QBool *qb); +QBool *qobject_to_qbool(const QObject *obj); + +#endif /* QBOOL_H */ @@ -0,0 +1,356 @@ +/* + * QDict data type. + * + * Copyright (C) 2009 Red Hat Inc. + * + * Authors: + * Luiz Capitulino <lcapitulino@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include "qint.h" +#include "qdict.h" +#include "qbool.h" +#include "qstring.h" +#include "qobject.h" +#include "qemu-queue.h" +#include "qemu-common.h" + +static void qdict_destroy_obj(QObject *obj); + +static const QType qdict_type = { + .code = QTYPE_QDICT, + .destroy = qdict_destroy_obj, +}; + +/** + * qdict_new(): Create a new QDict + * + * Return strong reference. + */ +QDict *qdict_new(void) +{ + QDict *qdict; + + qdict = qemu_mallocz(sizeof(*qdict)); + QOBJECT_INIT(qdict, &qdict_type); + + return qdict; +} + +/** + * qobject_to_qdict(): Convert a QObject into a QDict + */ +QDict *qobject_to_qdict(const QObject *obj) +{ + if (qobject_type(obj) != QTYPE_QDICT) + return NULL; + + return container_of(obj, QDict, base); +} + +/** + * tdb_hash(): based on the hash agorithm from gdbm, via tdb + * (from module-init-tools) + */ +static unsigned int tdb_hash(const char *name) +{ + unsigned value; /* Used to compute the hash value. */ + unsigned i; /* Used to cycle through random values. */ + + /* Set the initial value from the key size. */ + for (value = 0x238F13AF * strlen(name), i=0; name[i]; i++) + value = (value + (((const unsigned char *)name)[i] << (i*5 % 24))); + + return (1103515243 * value + 12345); +} + +/** + * alloc_entry(): allocate a new QDictEntry + */ +static QDictEntry *alloc_entry(const char *key, QObject *value) +{ + QDictEntry *entry; + + entry = qemu_mallocz(sizeof(*entry)); + entry->key = qemu_strdup(key); + entry->value = value; + + return entry; +} + +/** + * qdict_find(): List lookup function + */ +static QDictEntry *qdict_find(const QDict *qdict, + const char *key, unsigned int hash) +{ + QDictEntry *entry; + + QLIST_FOREACH(entry, &qdict->table[hash], next) + if (!strcmp(entry->key, key)) + return entry; + + return NULL; +} + +/** + * qdict_put_obj(): Put a new QObject into the dictionary + * + * Insert the pair 'key:value' into 'qdict', if 'key' already exists + * its 'value' will be replaced. + * + * This is done by freeing the reference to the stored QObject and + * storing the new one in the same entry. + * + * NOTE: ownership of 'value' is transferred to the QDict + */ +void qdict_put_obj(QDict *qdict, const char *key, QObject *value) +{ + unsigned int hash; + QDictEntry *entry; + + hash = tdb_hash(key) % QDICT_HASH_SIZE; + entry = qdict_find(qdict, key, hash); + if (entry) { + /* replace key's value */ + qobject_decref(entry->value); + entry->value = value; + } else { + /* allocate a new entry */ + entry = alloc_entry(key, value); + QLIST_INSERT_HEAD(&qdict->table[hash], entry, next); + qdict->size++; + } +} + +/** + * qdict_get(): Lookup for a given 'key' + * + * Return a weak reference to the QObject associated with 'key' if + * 'key' is present in the dictionary, NULL otherwise. + */ +QObject *qdict_get(const QDict *qdict, const char *key) +{ + QDictEntry *entry; + + entry = qdict_find(qdict, key, tdb_hash(key) % QDICT_HASH_SIZE); + return (entry == NULL ? NULL : entry->value); +} + +/** + * qdict_haskey(): Check if 'key' exists + * + * Return 1 if 'key' exists in the dict, 0 otherwise + */ +int qdict_haskey(const QDict *qdict, const char *key) +{ + unsigned int hash = tdb_hash(key) % QDICT_HASH_SIZE; + return (qdict_find(qdict, key, hash) == NULL ? 0 : 1); +} + +/** + * qdict_size(): Return the size of the dictionary + */ +size_t qdict_size(const QDict *qdict) +{ + return qdict->size; +} + +/** + * qdict_get_obj(): Get a QObject of a specific type + */ +static QObject *qdict_get_obj(const QDict *qdict, const char *key, + qtype_code type) +{ + QObject *obj; + + obj = qdict_get(qdict, key); + assert(obj != NULL); + assert(qobject_type(obj) == type); + + return obj; +} + +/** + * qdict_get_int(): Get an integer mapped by 'key' + * + * This function assumes that 'key' exists and it stores a + * QInt object. + * + * Return integer mapped by 'key'. + */ +int64_t qdict_get_int(const QDict *qdict, const char *key) +{ + QObject *obj = qdict_get_obj(qdict, key, QTYPE_QINT); + return qint_get_int(qobject_to_qint(obj)); +} + +/** + * qdict_get_bool(): Get a bool mapped by 'key' + * + * This function assumes that 'key' exists and it stores a + * QBool object. + * + * Return bool mapped by 'key'. + */ +int qdict_get_bool(const QDict *qdict, const char *key) +{ + QObject *obj = qdict_get_obj(qdict, key, QTYPE_QBOOL); + return qbool_get_int(qobject_to_qbool(obj)); +} + +/** + * qdict_get_qlist(): Get the QList mapped by 'key' + * + * This function assumes that 'key' exists and it stores a + * QList object. + * + * Return QList mapped by 'key'. + */ +QList *qdict_get_qlist(const QDict *qdict, const char *key) +{ + return qobject_to_qlist(qdict_get_obj(qdict, key, QTYPE_QLIST)); +} + +/** + * qdict_get_qdict(): Get the QDict mapped by 'key' + * + * This function assumes that 'key' exists and it stores a + * QDict object. + * + * Return QDict mapped by 'key'. + */ +QDict *qdict_get_qdict(const QDict *qdict, const char *key) +{ + return qobject_to_qdict(qdict_get_obj(qdict, key, QTYPE_QDICT)); +} + +/** + * qdict_get_str(): Get a pointer to the stored string mapped + * by 'key' + * + * This function assumes that 'key' exists and it stores a + * QString object. + * + * Return pointer to the string mapped by 'key'. + */ +const char *qdict_get_str(const QDict *qdict, const char *key) +{ + QObject *obj = qdict_get_obj(qdict, key, QTYPE_QSTRING); + return qstring_get_str(qobject_to_qstring(obj)); +} + +/** + * qdict_get_try_int(): Try to get integer mapped by 'key' + * + * Return integer mapped by 'key', if it is not present in + * the dictionary or if the stored object is not of QInt type + * 'err_value' will be returned. + */ +int64_t qdict_get_try_int(const QDict *qdict, const char *key, + int64_t err_value) +{ + QObject *obj; + + obj = qdict_get(qdict, key); + if (!obj || qobject_type(obj) != QTYPE_QINT) + return err_value; + + return qint_get_int(qobject_to_qint(obj)); +} + +/** + * qdict_get_try_str(): Try to get a pointer to the stored string + * mapped by 'key' + * + * Return a pointer to the string mapped by 'key', if it is not present + * in the dictionary or if the stored object is not of QString type + * NULL will be returned. + */ +const char *qdict_get_try_str(const QDict *qdict, const char *key) +{ + QObject *obj; + + obj = qdict_get(qdict, key); + if (!obj || qobject_type(obj) != QTYPE_QSTRING) + return NULL; + + return qstring_get_str(qobject_to_qstring(obj)); +} + +/** + * qdict_iter(): Iterate over all the dictionary's stored values. + * + * This function allows the user to provide an iterator, which will be + * called for each stored value in the dictionary. + */ +void qdict_iter(const QDict *qdict, + void (*iter)(const char *key, QObject *obj, void *opaque), + void *opaque) +{ + int i; + QDictEntry *entry; + + for (i = 0; i < QDICT_HASH_SIZE; i++) { + QLIST_FOREACH(entry, &qdict->table[i], next) + iter(entry->key, entry->value, opaque); + } +} + +/** + * qentry_destroy(): Free all the memory allocated by a QDictEntry + */ +static void qentry_destroy(QDictEntry *e) +{ + assert(e != NULL); + assert(e->key != NULL); + assert(e->value != NULL); + + qobject_decref(e->value); + qemu_free(e->key); + qemu_free(e); +} + +/** + * qdict_del(): Delete a 'key:value' pair from the dictionary + * + * This will destroy all data allocated by this entry. + */ +void qdict_del(QDict *qdict, const char *key) +{ + QDictEntry *entry; + + entry = qdict_find(qdict, key, tdb_hash(key) % QDICT_HASH_SIZE); + if (entry) { + QLIST_REMOVE(entry, next); + qentry_destroy(entry); + qdict->size--; + } +} + +/** + * qdict_destroy_obj(): Free all the memory allocated by a QDict + */ +static void qdict_destroy_obj(QObject *obj) +{ + int i; + QDict *qdict; + + assert(obj != NULL); + qdict = qobject_to_qdict(obj); + + for (i = 0; i < QDICT_HASH_SIZE; i++) { + QDictEntry *entry = QLIST_FIRST(&qdict->table[i]); + while (entry) { + QDictEntry *tmp = QLIST_NEXT(entry, next); + QLIST_REMOVE(entry, next); + qentry_destroy(entry); + entry = tmp; + } + } + + qemu_free(qdict); +} @@ -0,0 +1,49 @@ +#ifndef QDICT_H +#define QDICT_H + +#include "qobject.h" +#include "qlist.h" +#include "qemu-queue.h" +#include <stdint.h> + +#define QDICT_HASH_SIZE 512 + +typedef struct QDictEntry { + char *key; + QObject *value; + QLIST_ENTRY(QDictEntry) next; +} QDictEntry; + +typedef struct QDict { + QObject_HEAD; + size_t size; + QLIST_HEAD(,QDictEntry) table[QDICT_HASH_SIZE]; +} QDict; + +/* Object API */ +QDict *qdict_new(void); +size_t qdict_size(const QDict *qdict); +void qdict_put_obj(QDict *qdict, const char *key, QObject *value); +void qdict_del(QDict *qdict, const char *key); +int qdict_haskey(const QDict *qdict, const char *key); +QObject *qdict_get(const QDict *qdict, const char *key); +QDict *qobject_to_qdict(const QObject *obj); +void qdict_iter(const QDict *qdict, + void (*iter)(const char *key, QObject *obj, void *opaque), + void *opaque); + +/* Helper to qdict_put_obj(), accepts any object */ +#define qdict_put(qdict, key, obj) \ + qdict_put_obj(qdict, key, QOBJECT(obj)) + +/* High level helpers */ +int64_t qdict_get_int(const QDict *qdict, const char *key); +int qdict_get_bool(const QDict *qdict, const char *key); +QList *qdict_get_qlist(const QDict *qdict, const char *key); +QDict *qdict_get_qdict(const QDict *qdict, const char *key); +const char *qdict_get_str(const QDict *qdict, const char *key); +int64_t qdict_get_try_int(const QDict *qdict, const char *key, + int64_t err_value); +const char *qdict_get_try_str(const QDict *qdict, const char *key); + +#endif /* QDICT_H */ @@ -20,6 +20,11 @@ /* Returns 1 if there are still outstanding AIO requests; 0 otherwise */ typedef int (AioFlushHandler)(void *opaque); +/* Runs all currently allowed AIO callbacks of completed requests in the + * respective AIO backend. Returns 0 if no requests was handled, non-zero + * if at least one queued request was handled. */ +typedef int (AioProcessQueue)(void *opaque); + /* Flush any pending AIO operation. This function will block until all * outstanding AIO operations have been completed or cancelled. */ void qemu_aio_flush(void); diff --git a/qemu-lock.h b/qemu-lock.h index 26661ba..49e2203 100644 --- a/qemu-lock.h +++ b/qemu-lock.h @@ -12,8 +12,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + * License along with this library; if not, see <http://www.gnu.org/licenses/> */ /* Locking primitives. Most of this code should be redundant - diff --git a/qemu-malloc.c b/qemu-malloc.c index 295d185..5d9e34d 100644 --- a/qemu-malloc.c +++ b/qemu-malloc.c @@ -42,22 +42,29 @@ void qemu_free(void *ptr) free(ptr); } +static int allow_zero_malloc(void) +{ +#if defined(CONFIG_ZERO_MALLOC) + return 1; +#else + return 0; +#endif +} + void *qemu_malloc(size_t size) { - if (!size) { + if (!size && !allow_zero_malloc()) { abort(); } - return oom_check(malloc(size)); + return oom_check(malloc(size ? size : 1)); } void *qemu_realloc(void *ptr, size_t size) { if (size) { return oom_check(realloc(ptr, size)); - } else { - if (ptr) { - return realloc(ptr, size); - } + } else if (allow_zero_malloc()) { + return oom_check(realloc(ptr, size ? size : 1)); } abort(); } diff --git a/qemu-objects.h b/qemu-objects.h new file mode 100644 index 0000000..e1d1e0c --- /dev/null +++ b/qemu-objects.h @@ -0,0 +1,24 @@ +/* + * Include all QEMU objects. + * + * Copyright (C) 2009 Red Hat Inc. + * + * Authors: + * Luiz Capitulino <lcapitulino@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ +#ifndef QEMU_OBJECTS_H +#define QEMU_OBJECTS_H + +#include "qobject.h" +#include "qint.h" +#include "qfloat.h" +#include "qbool.h" +#include "qstring.h" +#include "qdict.h" +#include "qlist.h" +#include "qjson.h" + +#endif /* QEMU_OBJECTS_H */ diff --git a/qemu-option.c b/qemu-option.c index 646bbad..738e5b6 100644 --- a/qemu-option.c +++ b/qemu-option.c @@ -85,6 +85,70 @@ const char *get_opt_value(char *buf, int buf_size, const char *p) return p; } +int get_next_param_value(char *buf, int buf_size, + const char *tag, const char **pstr) +{ + const char *p; + char option[128]; + + p = *pstr; + for(;;) { + p = get_opt_name(option, sizeof(option), p, '='); + if (*p != '=') + break; + p++; + if (!strcmp(tag, option)) { + *pstr = get_opt_value(buf, buf_size, p); + if (**pstr == ',') { + (*pstr)++; + } + return strlen(buf); + } else { + p = get_opt_value(NULL, 0, p); + } + if (*p != ',') + break; + p++; + } + return 0; +} + +int get_param_value(char *buf, int buf_size, + const char *tag, const char *str) +{ + return get_next_param_value(buf, buf_size, tag, &str); +} + +int check_params(char *buf, int buf_size, + const char * const *params, const char *str) +{ + const char *p; + int i; + + p = str; + while (*p != '\0') { + p = get_opt_name(buf, buf_size, p, '='); + if (*p != '=') { + return -1; + } + p++; + for (i = 0; params[i] != NULL; i++) { + if (!strcmp(params[i], buf)) { + break; + } + } + if (params[i] == NULL) { + return -1; + } + p = get_opt_value(NULL, 0, p); + if (*p != ',') { + break; + } + p++; + } + return 0; +} + /* * Searches an option list for an option with the given name */ @@ -101,6 +165,76 @@ QEMUOptionParameter *get_option_parameter(QEMUOptionParameter *list, return NULL; } +static int parse_option_bool(const char *name, const char *value, int *ret) +{ + if (value != NULL) { + if (!strcmp(value, "on")) { + *ret = 1; + } else if (!strcmp(value, "off")) { + *ret = 0; + } else { + fprintf(stderr, "Option '%s': Use 'on' or 'off'\n", name); + return -1; + } + } else { + *ret = 1; + } + return 0; +} + +static int parse_option_number(const char *name, const char *value, uint64_t *ret) +{ + char *postfix; + uint64_t number; + + if (value != NULL) { + number = strtoull(value, &postfix, 0); + if (*postfix != '\0') { + fprintf(stderr, "Option '%s' needs a number as parameter\n", name); + return -1; + } + *ret = number; + } else { + fprintf(stderr, "Option '%s' needs a parameter\n", name); + return -1; + } + return 0; +} + +static int parse_option_size(const char *name, const char *value, uint64_t *ret) +{ + char *postfix; + double sizef; + + if (value != NULL) { + sizef = strtod(value, &postfix); + switch (*postfix) { + case 'T': + sizef *= 1024; + case 'G': + sizef *= 1024; + case 'M': + sizef *= 1024; + case 'K': + case 'k': + sizef *= 1024; + case 'b': + case '\0': + *ret = (uint64_t) sizef; + break; + default: + fprintf(stderr, "Option '%s' needs size as parameter\n", name); + fprintf(stderr, "You may use k, M, G or T suffixes for " + "kilobytes, megabytes, gigabytes and terabytes.\n"); + return -1; + } + } else { + fprintf(stderr, "Option '%s' needs a parameter\n", name); + return -1; + } + return 0; +} + /* * Sets the value of a parameter in a given option list. The parsing of the * value depends on the type of option: @@ -121,6 +255,8 @@ QEMUOptionParameter *get_option_parameter(QEMUOptionParameter *list, int set_option_parameter(QEMUOptionParameter *list, const char *name, const char *value) { + int flag; + // Find a matching parameter list = get_option_parameter(list, name); if (list == NULL) { @@ -131,23 +267,14 @@ int set_option_parameter(QEMUOptionParameter *list, const char *name, // Process parameter switch (list->type) { case OPT_FLAG: - if (value != NULL) { - if (!strcmp(value, "on")) { - list->value.n = 1; - } else if (!strcmp(value, "off")) { - list->value.n = 0; - } else { - fprintf(stderr, "Option '%s': Use 'on' or 'off'\n", name); - return -1; - } - } else { - list->value.n = 1; - } + if (parse_option_bool(name, value, &flag) == -1) + return -1; + list->value.n = flag; break; case OPT_STRING: if (value != NULL) { - list->value.s = strdup(value); + list->value.s = qemu_strdup(value); } else { fprintf(stderr, "Option '%s' needs a parameter\n", name); return -1; @@ -155,34 +282,10 @@ int set_option_parameter(QEMUOptionParameter *list, const char *name, break; case OPT_SIZE: - if (value != NULL) { - double sizef = strtod(value, (char**) &value); - - switch (*value) { - case 'T': - sizef *= 1024; - case 'G': - sizef *= 1024; - case 'M': - sizef *= 1024; - case 'K': - case 'k': - sizef *= 1024; - case 'b': - case '\0': - list->value.n = (uint64_t) sizef; - break; - default: - fprintf(stderr, "Option '%s' needs size as parameter\n", name); - fprintf(stderr, "You may use k, M, G or T suffixes for " - "kilobytes, megabytes, gigabytes and terabytes.\n"); - return -1; - } - } else { - fprintf(stderr, "Option '%s' needs a parameter\n", name); + if (parse_option_size(name, value, &list->value.n) == -1) return -1; - } break; + default: fprintf(stderr, "Bug: Option '%s' has an unknown type\n", name); return -1; @@ -231,12 +334,12 @@ void free_option_parameters(QEMUOptionParameter *list) while (cur && cur->name) { if (cur->type == OPT_STRING) { - free(cur->value.s); + qemu_free(cur->value.s); } cur++; } - free(list); + qemu_free(list); } /* @@ -360,3 +463,360 @@ void print_option_help(QEMUOptionParameter *list) list++; } } + +/* ------------------------------------------------------------------ */ + +struct QemuOpt { + const char *name; + const char *str; + + QemuOptDesc *desc; + union { + int boolean; + uint64_t uint; + } value; + + QemuOpts *opts; + QTAILQ_ENTRY(QemuOpt) next; +}; + +struct QemuOpts { + char *id; + QemuOptsList *list; + QTAILQ_HEAD(QemuOptHead, QemuOpt) head; + QTAILQ_ENTRY(QemuOpts) next; +}; + +static QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name) +{ + QemuOpt *opt; + + QTAILQ_FOREACH_REVERSE(opt, &opts->head, QemuOptHead, next) { + if (strcmp(opt->name, name) != 0) + continue; + return opt; + } + return NULL; +} + +const char *qemu_opt_get(QemuOpts *opts, const char *name) +{ + QemuOpt *opt = qemu_opt_find(opts, name); + return opt ? opt->str : NULL; +} + +int qemu_opt_get_bool(QemuOpts *opts, const char *name, int defval) +{ + QemuOpt *opt = qemu_opt_find(opts, name); + + if (opt == NULL) + return defval; + assert(opt->desc && opt->desc->type == QEMU_OPT_BOOL); + return opt->value.boolean; +} + +uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval) +{ + QemuOpt *opt = qemu_opt_find(opts, name); + + if (opt == NULL) + return defval; + assert(opt->desc && opt->desc->type == QEMU_OPT_NUMBER); + return opt->value.uint; +} + +uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval) +{ + QemuOpt *opt = qemu_opt_find(opts, name); + + if (opt == NULL) + return defval; + assert(opt->desc && opt->desc->type == QEMU_OPT_SIZE); + return opt->value.uint; +} + +static int qemu_opt_parse(QemuOpt *opt) +{ + if (opt->desc == NULL) + return 0; + switch (opt->desc->type) { + case QEMU_OPT_STRING: + /* nothing */ + return 0; + case QEMU_OPT_BOOL: + return parse_option_bool(opt->name, opt->str, &opt->value.boolean); + case QEMU_OPT_NUMBER: + return parse_option_number(opt->name, opt->str, &opt->value.uint); + case QEMU_OPT_SIZE: + return parse_option_size(opt->name, opt->str, &opt->value.uint); + default: + abort(); + } +} + +static void qemu_opt_del(QemuOpt *opt) +{ + QTAILQ_REMOVE(&opt->opts->head, opt, next); + qemu_free((/* !const */ char*)opt->name); + qemu_free((/* !const */ char*)opt->str); + qemu_free(opt); +} + +int qemu_opt_set(QemuOpts *opts, const char *name, const char *value) +{ + QemuOpt *opt; + QemuOptDesc *desc = opts->list->desc; + int i; + + for (i = 0; desc[i].name != NULL; i++) { + if (strcmp(desc[i].name, name) == 0) { + break; + } + } + if (desc[i].name == NULL) { + if (i == 0) { + /* empty list -> allow any */; + } else { + fprintf(stderr, "option \"%s\" is not valid for %s\n", + name, opts->list->name); + return -1; + } + } + + opt = qemu_mallocz(sizeof(*opt)); + opt->name = qemu_strdup(name); + opt->opts = opts; + QTAILQ_INSERT_TAIL(&opts->head, opt, next); + if (desc[i].name != NULL) { + opt->desc = desc+i; + } + if (value) { + opt->str = qemu_strdup(value); + } + if (qemu_opt_parse(opt) < 0) { + fprintf(stderr, "Failed to parse \"%s\" for \"%s.%s\"\n", opt->str, + opts->list->name, opt->name); + qemu_opt_del(opt); + return -1; + } + return 0; +} + +int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque, + int abort_on_failure) +{ + QemuOpt *opt; + int rc = 0; + + QTAILQ_FOREACH(opt, &opts->head, next) { + rc = func(opt->name, opt->str, opaque); + if (abort_on_failure && rc != 0) + break; + } + return rc; +} + +QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id) +{ + QemuOpts *opts; + + QTAILQ_FOREACH(opts, &list->head, next) { + if (!opts->id) { + continue; + } + if (strcmp(opts->id, id) != 0) { + continue; + } + return opts; + } + return NULL; +} + +QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exists) +{ + QemuOpts *opts = NULL; + + if (id) { + opts = qemu_opts_find(list, id); + if (opts != NULL) { + if (fail_if_exists) { + fprintf(stderr, "tried to create id \"%s\" twice for \"%s\"\n", + id, list->name); + return NULL; + } else { + return opts; + } + } + } + opts = qemu_mallocz(sizeof(*opts)); + if (id) { + opts->id = qemu_strdup(id); + } + opts->list = list; + QTAILQ_INIT(&opts->head); + QTAILQ_INSERT_TAIL(&list->head, opts, next); + return opts; +} + +int qemu_opts_set(QemuOptsList *list, const char *id, + const char *name, const char *value) +{ + QemuOpts *opts; + + opts = qemu_opts_create(list, id, 1); + if (opts == NULL) { + return -1; + } + return qemu_opt_set(opts, name, value); +} + +const char *qemu_opts_id(QemuOpts *opts) +{ + return opts->id; +} + +void qemu_opts_del(QemuOpts *opts) +{ + QemuOpt *opt; + + for (;;) { + opt = QTAILQ_FIRST(&opts->head); + if (opt == NULL) + break; + qemu_opt_del(opt); + } + QTAILQ_REMOVE(&opts->list->head, opts, next); + qemu_free(opts->id); + qemu_free(opts); +} + +int qemu_opts_print(QemuOpts *opts, void *dummy) +{ + QemuOpt *opt; + + fprintf(stderr, "%s: %s:", opts->list->name, + opts->id ? opts->id : "<noid>"); + QTAILQ_FOREACH(opt, &opts->head, next) { + fprintf(stderr, " %s=\"%s\"", opt->name, opt->str); + } + fprintf(stderr, "\n"); + return 0; +} + +int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname) +{ + char option[128], value[1024]; + const char *p,*pe,*pc; + + for (p = params; *p != '\0'; p++) { + pe = strchr(p, '='); + pc = strchr(p, ','); + if (!pe || (pc && pc < pe)) { + /* found "foo,more" */ + if (p == params && firstname) { + /* implicitly named first option */ + pstrcpy(option, sizeof(option), firstname); + p = get_opt_value(value, sizeof(value), p); + } else { + /* option without value, probably a flag */ + p = get_opt_name(option, sizeof(option), p, ','); + if (strncmp(option, "no", 2) == 0) { + memmove(option, option+2, strlen(option+2)+1); + pstrcpy(value, sizeof(value), "off"); + } else { + pstrcpy(value, sizeof(value), "on"); + } + } + } else { + /* found "foo=bar,more" */ + p = get_opt_name(option, sizeof(option), p, '='); + if (*p != '=') { + break; + } + p++; + p = get_opt_value(value, sizeof(value), p); + } + if (strcmp(option, "id") != 0) { + /* store and parse */ + if (qemu_opt_set(opts, option, value) == -1) { + return -1; + } + } + if (*p != ',') { + break; + } + } + return 0; +} + +QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char *firstname) +{ + char value[1024], *id = NULL; + const char *p; + QemuOpts *opts; + + if (strncmp(params, "id=", 3) == 0) { + get_opt_value(value, sizeof(value), params+3); + id = qemu_strdup(value); + } else if ((p = strstr(params, ",id=")) != NULL) { + get_opt_value(value, sizeof(value), p+4); + id = qemu_strdup(value); + } + opts = qemu_opts_create(list, id, 1); + if (opts == NULL) + return NULL; + + if (qemu_opts_do_parse(opts, params, firstname) != 0) { + qemu_opts_del(opts); + return NULL; + } + + return opts; +} + +/* Validate parsed opts against descriptions where no + * descriptions were provided in the QemuOptsList. + */ +int qemu_opts_validate(QemuOpts *opts, QemuOptDesc *desc) +{ + QemuOpt *opt; + + assert(opts->list->desc[0].name == NULL); + + QTAILQ_FOREACH(opt, &opts->head, next) { + int i; + + for (i = 0; desc[i].name != NULL; i++) { + if (strcmp(desc[i].name, opt->name) == 0) { + break; + } + } + if (desc[i].name == NULL) { + fprintf(stderr, "option \"%s\" is not valid for %s\n", + opt->name, opts->list->name); + return -1; + } + + opt->desc = &desc[i]; + + if (qemu_opt_parse(opt) < 0) { + return -1; + } + } + + return 0; +} + +int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func, void *opaque, + int abort_on_failure) +{ + QemuOpts *opts; + int rc = 0; + + QTAILQ_FOREACH(opts, &list->head, next) { + rc = func(opts, opaque); + if (abort_on_failure && rc != 0) + break; + } + return rc; +} diff --git a/qemu-option.h b/qemu-option.h index 059c0a4..666b666 100644 --- a/qemu-option.h +++ b/qemu-option.h @@ -26,6 +26,9 @@ #ifndef QEMU_OPTIONS_H #define QEMU_OPTIONS_H +#include <stdint.h> +#include "qemu-queue.h" + enum QEMUOptionParType { OPT_FLAG, OPT_NUMBER, @@ -46,6 +49,12 @@ typedef struct QEMUOptionParameter { const char *get_opt_name(char *buf, int buf_size, const char *p, char delim); const char *get_opt_value(char *buf, int buf_size, const char *p); +int get_next_param_value(char *buf, int buf_size, + const char *tag, const char **pstr); +int get_param_value(char *buf, int buf_size, + const char *tag, const char *str); +int check_params(char *buf, int buf_size, + const char * const *params, const char *str); /* @@ -66,4 +75,53 @@ void free_option_parameters(QEMUOptionParameter *list); void print_option_parameters(QEMUOptionParameter *list); void print_option_help(QEMUOptionParameter *list); +/* ------------------------------------------------------------------ */ + +typedef struct QemuOpt QemuOpt; +typedef struct QemuOpts QemuOpts; +typedef struct QemuOptsList QemuOptsList; + +enum QemuOptType { + QEMU_OPT_STRING = 0, /* no parsing (use string as-is) */ + QEMU_OPT_BOOL, /* on/off */ + QEMU_OPT_NUMBER, /* simple number */ + QEMU_OPT_SIZE, /* size, accepts (K)ilo, (M)ega, (G)iga, (T)era postfix */ +}; + +typedef struct QemuOptDesc { + const char *name; + enum QemuOptType type; + const char *help; +} QemuOptDesc; + +struct QemuOptsList { + const char *name; + QTAILQ_HEAD(, QemuOpts) head; + QemuOptDesc desc[]; +}; + +const char *qemu_opt_get(QemuOpts *opts, const char *name); +int qemu_opt_get_bool(QemuOpts *opts, const char *name, int defval); +uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval); +uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval); +int qemu_opt_set(QemuOpts *opts, const char *name, const char *value); +typedef int (*qemu_opt_loopfunc)(const char *name, const char *value, void *opaque); +int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque, + int abort_on_failure); + +QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id); +QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exists); +int qemu_opts_set(QemuOptsList *list, const char *id, + const char *name, const char *value); +const char *qemu_opts_id(QemuOpts *opts); +void qemu_opts_del(QemuOpts *opts); +int qemu_opts_validate(QemuOpts *opts, QemuOptDesc *desc); +int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname); +QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char *firstname); + +typedef int (*qemu_opts_loopfunc)(QemuOpts *opts, void *opaque); +int qemu_opts_print(QemuOpts *opts, void *dummy); +int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func, void *opaque, + int abort_on_failure); + #endif diff --git a/qerror.c b/qerror.c new file mode 100644 index 0000000..6c2aba0 --- /dev/null +++ b/qerror.c @@ -0,0 +1,359 @@ +/* + * QError: QEMU Error data-type. + * + * Copyright (C) 2009 Red Hat Inc. + * + * Authors: + * Luiz Capitulino <lcapitulino@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ +#include "qjson.h" +#include "qerror.h" +#include "qstring.h" +#include "sysemu.h" +#include "qemu-common.h" + +static void qerror_destroy_obj(QObject *obj); + +static const QType qerror_type = { + .code = QTYPE_QERROR, + .destroy = qerror_destroy_obj, +}; + +/** + * The 'desc' parameter is a printf-like string, the format of the format + * string is: + * + * %(KEY) + * + * Where KEY is a QDict key, which has to be passed to qerror_from_info(). + * + * Example: + * + * "foo error on device: %(device) slot: %(slot_nr)" + * + * A single percent sign can be printed if followed by a second one, + * for example: + * + * "running out of foo: %(foo)%%" + */ +static const QErrorStringTable qerror_table[] = { + { + .error_fmt = QERR_COMMAND_NOT_FOUND, + .desc = "The command %(name) has not been found", + }, + { + .error_fmt = QERR_DEVICE_ENCRYPTED, + .desc = "The %(device) is encrypted", + }, + { + .error_fmt = QERR_DEVICE_LOCKED, + .desc = "Device %(device) is locked", + }, + { + .error_fmt = QERR_DEVICE_NOT_ACTIVE, + .desc = "The %(device) device has not been activated by the guest", + }, + { + .error_fmt = QERR_DEVICE_NOT_FOUND, + .desc = "The %(device) device has not been found", + }, + { + .error_fmt = QERR_DEVICE_NOT_REMOVABLE, + .desc = "Device %(device) is not removable", + }, + { + .error_fmt = QERR_FD_NOT_FOUND, + .desc = "Failed to find file descriptor named %(name)", + }, + { + .error_fmt = QERR_FD_NOT_SUPPLIED, + .desc = "No file descriptor supplied via SCM_RIGHTS", + }, + { + .error_fmt = QERR_OPEN_FILE_FAILED, + .desc = "Could not open '%(filename)'", + }, + { + .error_fmt = QERR_INVALID_BLOCK_FORMAT, + .desc = "Invalid block format %(name)", + }, + { + .error_fmt = QERR_INVALID_CPU_INDEX, + .desc = "Invalid CPU index", + }, + { + .error_fmt = QERR_INVALID_PARAMETER, + .desc = "Invalid parameter %(name)", + }, + { + .error_fmt = QERR_INVALID_PARAMETER_TYPE, + .desc = "Invalid parameter type, expected: %(expected)", + }, + { + .error_fmt = QERR_INVALID_PASSWORD, + .desc = "The entered password is invalid", + }, + { + .error_fmt = QERR_JSON_PARSING, + .desc = "Invalid JSON syntax", + }, + { + .error_fmt = QERR_KVM_MISSING_CAP, + .desc = "Using KVM without %(capability), %(feature) unavailable", + }, + { + .error_fmt = QERR_MISSING_PARAMETER, + .desc = "Parameter %(name) is missing", + }, + { + .error_fmt = QERR_QMP_BAD_INPUT_OBJECT, + .desc = "Bad QMP input object", + }, + { + .error_fmt = QERR_SET_PASSWD_FAILED, + .desc = "Could not set password", + }, + { + .error_fmt = QERR_TOO_MANY_FILES, + .desc = "Too many open files", + }, + { + .error_fmt = QERR_UNDEFINED_ERROR, + .desc = "An undefined error has ocurred", + }, + { + .error_fmt = QERR_VNC_SERVER_FAILED, + .desc = "Could not start VNC server on %(target)", + }, + {} +}; + +/** + * qerror_new(): Create a new QError + * + * Return strong reference. + */ +QError *qerror_new(void) +{ + QError *qerr; + + qerr = qemu_mallocz(sizeof(*qerr)); + QOBJECT_INIT(qerr, &qerror_type); + + return qerr; +} + +static void qerror_abort(const QError *qerr, const char *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "qerror: bad call in function '%s':\n", qerr->func); + fprintf(stderr, "qerror: -> "); + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + fprintf(stderr, "\nqerror: call at %s:%d\n", qerr->file, qerr->linenr); + abort(); +} + +static void qerror_set_data(QError *qerr, const char *fmt, va_list *va) +{ + QObject *obj; + + obj = qobject_from_jsonv(fmt, va); + if (!obj) { + qerror_abort(qerr, "invalid format '%s'", fmt); + } + if (qobject_type(obj) != QTYPE_QDICT) { + qerror_abort(qerr, "error format is not a QDict '%s'", fmt); + } + + qerr->error = qobject_to_qdict(obj); + + obj = qdict_get(qerr->error, "class"); + if (!obj) { + qerror_abort(qerr, "missing 'class' key in '%s'", fmt); + } + if (qobject_type(obj) != QTYPE_QSTRING) { + qerror_abort(qerr, "'class' key value should be a QString"); + } + + obj = qdict_get(qerr->error, "data"); + if (!obj) { + qerror_abort(qerr, "missing 'data' key in '%s'", fmt); + } + if (qobject_type(obj) != QTYPE_QDICT) { + qerror_abort(qerr, "'data' key value should be a QDICT"); + } +} + +static void qerror_set_desc(QError *qerr, const char *fmt) +{ + int i; + + // FIXME: inefficient loop + + for (i = 0; qerror_table[i].error_fmt; i++) { + if (strcmp(qerror_table[i].error_fmt, fmt) == 0) { + qerr->entry = &qerror_table[i]; + return; + } + } + + qerror_abort(qerr, "error format '%s' not found", fmt); +} + +/** + * qerror_from_info(): Create a new QError from error information + * + * The information consists of: + * + * - file the file name of where the error occurred + * - linenr the line number of where the error occurred + * - func the function name of where the error occurred + * - fmt JSON printf-like dictionary, there must exist keys 'class' and + * 'data' + * - va va_list of all arguments specified by fmt + * + * Return strong reference. + */ +QError *qerror_from_info(const char *file, int linenr, const char *func, + const char *fmt, va_list *va) +{ + QError *qerr; + + qerr = qerror_new(); + qerr->linenr = linenr; + qerr->file = file; + qerr->func = func; + + if (!fmt) { + qerror_abort(qerr, "QDict not specified"); + } + + qerror_set_data(qerr, fmt, va); + qerror_set_desc(qerr, fmt); + + return qerr; +} + +static void parse_error(const QError *qerror, int c) +{ + qerror_abort(qerror, "expected '%c' in '%s'", c, qerror->entry->desc); +} + +static const char *append_field(QString *outstr, const QError *qerror, + const char *start) +{ + QObject *obj; + QDict *qdict; + QString *key_qs; + const char *end, *key; + + if (*start != '%') + parse_error(qerror, '%'); + start++; + if (*start != '(') + parse_error(qerror, '('); + start++; + + end = strchr(start, ')'); + if (!end) + parse_error(qerror, ')'); + + key_qs = qstring_from_substr(start, 0, end - start - 1); + key = qstring_get_str(key_qs); + + qdict = qobject_to_qdict(qdict_get(qerror->error, "data")); + obj = qdict_get(qdict, key); + if (!obj) { + qerror_abort(qerror, "key '%s' not found in QDict", key); + } + + switch (qobject_type(obj)) { + case QTYPE_QSTRING: + qstring_append(outstr, qdict_get_str(qdict, key)); + break; + case QTYPE_QINT: + qstring_append_int(outstr, qdict_get_int(qdict, key)); + break; + default: + qerror_abort(qerror, "invalid type '%c'", qobject_type(obj)); + } + + QDECREF(key_qs); + return ++end; +} + +/** + * qerror_human(): Format QError data into human-readable string. + * + * Formats according to member 'desc' of the specified QError object. + */ +QString *qerror_human(const QError *qerror) +{ + const char *p; + QString *qstring; + + assert(qerror->entry != NULL); + + qstring = qstring_new(); + + for (p = qerror->entry->desc; *p != '\0';) { + if (*p != '%') { + qstring_append_chr(qstring, *p++); + } else if (*(p + 1) == '%') { + qstring_append_chr(qstring, '%'); + p += 2; + } else { + p = append_field(qstring, qerror, p); + } + } + + return qstring; +} + +/** + * qerror_print(): Print QError data + * + * This function will print the member 'desc' of the specified QError object, + * it uses qemu_error() for this, so that the output is routed to the right + * place (ie. stderr or Monitor's device). + */ +void qerror_print(const QError *qerror) +{ + QString *qstring = qerror_human(qerror); + qemu_error("%s\n", qstring_get_str(qstring)); + QDECREF(qstring); +} + +/** + * qobject_to_qerror(): Convert a QObject into a QError + */ +QError *qobject_to_qerror(const QObject *obj) +{ + if (qobject_type(obj) != QTYPE_QERROR) { + return NULL; + } + + return container_of(obj, QError, base); +} + +/** + * qerror_destroy_obj(): Free all memory allocated by a QError + */ +static void qerror_destroy_obj(QObject *obj) +{ + QError *qerr; + + assert(obj != NULL); + qerr = qobject_to_qerror(obj); + + QDECREF(qerr->error); + qemu_free(qerr); +} diff --git a/qerror.h b/qerror.h new file mode 100644 index 0000000..57c5b97 --- /dev/null +++ b/qerror.h @@ -0,0 +1,109 @@ +/* + * QError header file. + * + * Copyright (C) 2009 Red Hat Inc. + * + * Authors: + * Luiz Capitulino <lcapitulino@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ +#ifndef QERROR_H +#define QERROR_H + +#include "qdict.h" +#include "qstring.h" +#include <stdarg.h> + +typedef struct QErrorStringTable { + const char *desc; + const char *error_fmt; +} QErrorStringTable; + +typedef struct QError { + QObject_HEAD; + QDict *error; + int linenr; + const char *file; + const char *func; + const QErrorStringTable *entry; +} QError; + +QError *qerror_new(void); +QError *qerror_from_info(const char *file, int linenr, const char *func, + const char *fmt, va_list *va); +QString *qerror_human(const QError *qerror); +void qerror_print(const QError *qerror); +QError *qobject_to_qerror(const QObject *obj); + +/* + * QError class list + */ +#define QERR_COMMAND_NOT_FOUND \ + "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }" + +#define QERR_DEVICE_ENCRYPTED \ + "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s } }" + +#define QERR_DEVICE_LOCKED \ + "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }" + +#define QERR_DEVICE_NOT_ACTIVE \ + "{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }" + +#define QERR_DEVICE_NOT_FOUND \ + "{ 'class': 'DeviceNotFound', 'data': { 'device': %s } }" + +#define QERR_DEVICE_NOT_REMOVABLE \ + "{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }" + +#define QERR_FD_NOT_FOUND \ + "{ 'class': 'FdNotFound', 'data': { 'name': %s } }" + +#define QERR_FD_NOT_SUPPLIED \ + "{ 'class': 'FdNotSupplied', 'data': {} }" + +#define QERR_OPEN_FILE_FAILED \ + "{ 'class': 'OpenFileFailed', 'data': { 'filename': %s } }" + +#define QERR_INVALID_BLOCK_FORMAT \ + "{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }" + +#define QERR_INVALID_CPU_INDEX \ + "{ 'class': 'InvalidCPUIndex', 'data': {} }" + +#define QERR_INVALID_PARAMETER \ + "{ 'class': 'InvalidParameter', 'data': { 'name': %s } }" + +#define QERR_INVALID_PARAMETER_TYPE \ + "{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }" + +#define QERR_INVALID_PASSWORD \ + "{ 'class': 'InvalidPassword', 'data': {} }" + +#define QERR_JSON_PARSING \ + "{ 'class': 'JSONParsing', 'data': {} }" + +#define QERR_KVM_MISSING_CAP \ + "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }" + +#define QERR_MISSING_PARAMETER \ + "{ 'class': 'MissingParameter', 'data': { 'name': %s } }" + +#define QERR_QMP_BAD_INPUT_OBJECT \ + "{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }" + +#define QERR_SET_PASSWD_FAILED \ + "{ 'class': 'SetPasswdFailed', 'data': {} }" + +#define QERR_UNDEFINED_ERROR \ + "{ 'class': 'UndefinedError', 'data': {} }" + +#define QERR_TOO_MANY_FILES \ + "{ 'class': 'TooManyFiles', 'data': {} }" + +#define QERR_VNC_SERVER_FAILED \ + "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }" + +#endif /* QERROR_H */ diff --git a/qfloat.c b/qfloat.c new file mode 100644 index 0000000..05215f5 --- /dev/null +++ b/qfloat.c @@ -0,0 +1,76 @@ +/* + * QFloat Module + * + * Copyright (C) 2009 Red Hat Inc. + * + * Authors: + * Luiz Capitulino <lcapitulino@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Copyright IBM, Corp. 2009 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qfloat.h" +#include "qobject.h" +#include "qemu-common.h" + +static void qfloat_destroy_obj(QObject *obj); + +static const QType qfloat_type = { + .code = QTYPE_QFLOAT, + .destroy = qfloat_destroy_obj, +}; + +/** + * qfloat_from_int(): Create a new QFloat from a float + * + * Return strong reference. + */ +QFloat *qfloat_from_double(double value) +{ + QFloat *qf; + + qf = qemu_malloc(sizeof(*qf)); + qf->value = value; + QOBJECT_INIT(qf, &qfloat_type); + + return qf; +} + +/** + * qfloat_get_double(): Get the stored float + */ +double qfloat_get_double(const QFloat *qf) +{ + return qf->value; +} + +/** + * qobject_to_qfloat(): Convert a QObject into a QFloat + */ +QFloat *qobject_to_qfloat(const QObject *obj) +{ + if (qobject_type(obj) != QTYPE_QFLOAT) + return NULL; + + return container_of(obj, QFloat, base); +} + +/** + * qfloat_destroy_obj(): Free all memory allocated by a + * QFloat object + */ +static void qfloat_destroy_obj(QObject *obj) +{ + assert(obj != NULL); + qemu_free(qobject_to_qfloat(obj)); +} diff --git a/qfloat.h b/qfloat.h new file mode 100644 index 0000000..9d67876 --- /dev/null +++ b/qfloat.h @@ -0,0 +1,29 @@ +/* + * QFloat Module + * + * Copyright IBM, Corp. 2009 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#ifndef QFLOAT_H +#define QFLOAT_H + +#include <stdint.h> +#include "qobject.h" + +typedef struct QFloat { + QObject_HEAD; + double value; +} QFloat; + +QFloat *qfloat_from_double(double value); +double qfloat_get_double(const QFloat *qi); +QFloat *qobject_to_qfloat(const QObject *obj); + +#endif /* QFLOAT_H */ @@ -0,0 +1,66 @@ +/* + * QInt data type. + * + * Copyright (C) 2009 Red Hat Inc. + * + * Authors: + * Luiz Capitulino <lcapitulino@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ +#include "qint.h" +#include "qobject.h" +#include "qemu-common.h" + +static void qint_destroy_obj(QObject *obj); + +static const QType qint_type = { + .code = QTYPE_QINT, + .destroy = qint_destroy_obj, +}; + +/** + * qint_from_int(): Create a new QInt from an int64_t + * + * Return strong reference. + */ +QInt *qint_from_int(int64_t value) +{ + QInt *qi; + + qi = qemu_malloc(sizeof(*qi)); + qi->value = value; + QOBJECT_INIT(qi, &qint_type); + + return qi; +} + +/** + * qint_get_int(): Get the stored integer + */ +int64_t qint_get_int(const QInt *qi) +{ + return qi->value; +} + +/** + * qobject_to_qint(): Convert a QObject into a QInt + */ +QInt *qobject_to_qint(const QObject *obj) +{ + if (qobject_type(obj) != QTYPE_QINT) + return NULL; + + return container_of(obj, QInt, base); +} + +/** + * qint_destroy_obj(): Free all memory allocated by a + * QInt object + */ +static void qint_destroy_obj(QObject *obj) +{ + assert(obj != NULL); + qemu_free(qobject_to_qint(obj)); +} @@ -0,0 +1,16 @@ +#ifndef QINT_H +#define QINT_H + +#include <stdint.h> +#include "qobject.h" + +typedef struct QInt { + QObject_HEAD; + int64_t value; +} QInt; + +QInt *qint_from_int(int64_t value); +int64_t qint_get_int(const QInt *qi); +QInt *qobject_to_qint(const QObject *obj); + +#endif /* QINT_H */ @@ -0,0 +1,247 @@ +/* + * QObject JSON integration + * + * Copyright IBM, Corp. 2009 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "json-lexer.h" +#include "json-parser.h" +#include "json-streamer.h" +#include "qjson.h" +#include "qint.h" +#include "qlist.h" +#include "qbool.h" +#include "qfloat.h" +#include "qdict.h" + +typedef struct JSONParsingState +{ + JSONMessageParser parser; + va_list *ap; + QObject *result; +} JSONParsingState; + +static void parse_json(JSONMessageParser *parser, QList *tokens) +{ + JSONParsingState *s = container_of(parser, JSONParsingState, parser); + s->result = json_parser_parse(tokens, s->ap); +} + +QObject *qobject_from_jsonv(const char *string, va_list *ap) +{ + JSONParsingState state = {}; + + state.ap = ap; + + json_message_parser_init(&state.parser, parse_json); + json_message_parser_feed(&state.parser, string, strlen(string)); + json_message_parser_flush(&state.parser); + json_message_parser_destroy(&state.parser); + + return state.result; +} + +QObject *qobject_from_json(const char *string) +{ + return qobject_from_jsonv(string, NULL); +} + +QObject *qobject_from_jsonf(const char *string, ...) +{ + QObject *obj; + va_list ap; + + va_start(ap, string); + obj = qobject_from_jsonv(string, &ap); + va_end(ap); + + return obj; +} + +typedef struct ToJsonIterState +{ + int count; + QString *str; +} ToJsonIterState; + +static void to_json(const QObject *obj, QString *str); + +static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) +{ + ToJsonIterState *s = opaque; + QString *qkey; + + if (s->count) { + qstring_append(s->str, ", "); + } + + qkey = qstring_from_str(key); + to_json(QOBJECT(qkey), s->str); + QDECREF(qkey); + + qstring_append(s->str, ": "); + to_json(obj, s->str); + s->count++; +} + +static void to_json_list_iter(QObject *obj, void *opaque) +{ + ToJsonIterState *s = opaque; + + if (s->count) { + qstring_append(s->str, ", "); + } + + to_json(obj, s->str); + s->count++; +} + +static void to_json(const QObject *obj, QString *str) +{ + switch (qobject_type(obj)) { + case QTYPE_QINT: { + QInt *val = qobject_to_qint(obj); + char buffer[1024]; + + snprintf(buffer, sizeof(buffer), "%" PRId64, qint_get_int(val)); + qstring_append(str, buffer); + break; + } + case QTYPE_QSTRING: { + QString *val = qobject_to_qstring(obj); + const char *ptr; + + ptr = qstring_get_str(val); + qstring_append(str, "\""); + while (*ptr) { + if ((ptr[0] & 0xE0) == 0xE0 && + (ptr[1] & 0x80) && (ptr[2] & 0x80)) { + uint16_t wchar; + char escape[7]; + + wchar = (ptr[0] & 0x0F) << 12; + wchar |= (ptr[1] & 0x3F) << 6; + wchar |= (ptr[2] & 0x3F); + ptr += 2; + + snprintf(escape, sizeof(escape), "\\u%04X", wchar); + qstring_append(str, escape); + } else if ((ptr[0] & 0xE0) == 0xC0 && (ptr[1] & 0x80)) { + uint16_t wchar; + char escape[7]; + + wchar = (ptr[0] & 0x1F) << 6; + wchar |= (ptr[1] & 0x3F); + ptr++; + + snprintf(escape, sizeof(escape), "\\u%04X", wchar); + qstring_append(str, escape); + } else switch (ptr[0]) { + case '\"': + qstring_append(str, "\\\""); + break; + case '\\': + qstring_append(str, "\\\\"); + break; + case '\b': + qstring_append(str, "\\b"); + break; + case '\n': + qstring_append(str, "\\n"); + break; + case '\r': + qstring_append(str, "\\r"); + break; + case '\t': + qstring_append(str, "\\t"); + break; + default: { + if (ptr[0] <= 0x1F) { + char escape[7]; + snprintf(escape, sizeof(escape), "\\u%04X", ptr[0]); + qstring_append(str, escape); + } else { + char buf[2] = { ptr[0], 0 }; + qstring_append(str, buf); + } + break; + } + } + ptr++; + } + qstring_append(str, "\""); + break; + } + case QTYPE_QDICT: { + ToJsonIterState s; + QDict *val = qobject_to_qdict(obj); + + s.count = 0; + s.str = str; + qstring_append(str, "{"); + qdict_iter(val, to_json_dict_iter, &s); + qstring_append(str, "}"); + break; + } + case QTYPE_QLIST: { + ToJsonIterState s; + QList *val = qobject_to_qlist(obj); + + s.count = 0; + s.str = str; + qstring_append(str, "["); + qlist_iter(val, (void *)to_json_list_iter, &s); + qstring_append(str, "]"); + break; + } + case QTYPE_QFLOAT: { + QFloat *val = qobject_to_qfloat(obj); + char buffer[1024]; + int len; + + len = snprintf(buffer, sizeof(buffer), "%f", qfloat_get_double(val)); + while (len > 0 && buffer[len - 1] == '0') { + len--; + } + + if (len && buffer[len - 1] == '.') { + buffer[len - 1] = 0; + } else { + buffer[len] = 0; + } + + qstring_append(str, buffer); + break; + } + case QTYPE_QBOOL: { + QBool *val = qobject_to_qbool(obj); + + if (qbool_get_int(val)) { + qstring_append(str, "true"); + } else { + qstring_append(str, "false"); + } + break; + } + case QTYPE_QERROR: + /* XXX: should QError be emitted? */ + case QTYPE_NONE: + break; + } +} + +QString *qobject_to_json(const QObject *obj) +{ + QString *str = qstring_new(); + + to_json(obj, str); + + return str; +} @@ -0,0 +1,28 @@ +/* + * QObject JSON integration + * + * Copyright IBM, Corp. 2009 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#ifndef QJSON_H +#define QJSON_H + +#include <stdarg.h> +#include "qobject.h" +#include "qstring.h" + +QObject *qobject_from_json(const char *string); +QObject *qobject_from_jsonf(const char *string, ...) + __attribute__((__format__ (__printf__, 1, 2))); +QObject *qobject_from_jsonv(const char *string, va_list *ap); + +QString *qobject_to_json(const QObject *obj); + +#endif /* QJSON_H */ @@ -0,0 +1,156 @@ +/* + * QList data type. + * + * Copyright (C) 2009 Red Hat Inc. + * + * Authors: + * Luiz Capitulino <lcapitulino@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ +#include "qlist.h" +#include "qobject.h" +#include "qemu-queue.h" +#include "qemu-common.h" + +static void qlist_destroy_obj(QObject *obj); + +static const QType qlist_type = { + .code = QTYPE_QLIST, + .destroy = qlist_destroy_obj, +}; + +/** + * qlist_new(): Create a new QList + * + * Return strong reference. + */ +QList *qlist_new(void) +{ + QList *qlist; + + qlist = qemu_malloc(sizeof(*qlist)); + QTAILQ_INIT(&qlist->head); + QOBJECT_INIT(qlist, &qlist_type); + + return qlist; +} + +static void qlist_copy_elem(QObject *obj, void *opaque) +{ + QList *dst = opaque; + + qobject_incref(obj); + qlist_append_obj(dst, obj); +} + +QList *qlist_copy(QList *src) +{ + QList *dst = qlist_new(); + + qlist_iter(src, qlist_copy_elem, dst); + + return dst; +} + +/** + * qlist_append_obj(): Append an QObject into QList + * + * NOTE: ownership of 'value' is transferred to the QList + */ +void qlist_append_obj(QList *qlist, QObject *value) +{ + QListEntry *entry; + + entry = qemu_malloc(sizeof(*entry)); + entry->value = value; + + QTAILQ_INSERT_TAIL(&qlist->head, entry, next); +} + +/** + * qlist_iter(): Iterate over all the list's stored values. + * + * This function allows the user to provide an iterator, which will be + * called for each stored value in the list. + */ +void qlist_iter(const QList *qlist, + void (*iter)(QObject *obj, void *opaque), void *opaque) +{ + QListEntry *entry; + + QTAILQ_FOREACH(entry, &qlist->head, next) + iter(entry->value, opaque); +} + +QObject *qlist_pop(QList *qlist) +{ + QListEntry *entry; + QObject *ret; + + if (qlist == NULL || QTAILQ_EMPTY(&qlist->head)) { + return NULL; + } + + entry = QTAILQ_FIRST(&qlist->head); + QTAILQ_REMOVE(&qlist->head, entry, next); + + ret = entry->value; + qemu_free(entry); + + return ret; +} + +QObject *qlist_peek(QList *qlist) +{ + QListEntry *entry; + QObject *ret; + + if (qlist == NULL || QTAILQ_EMPTY(&qlist->head)) { + return NULL; + } + + entry = QTAILQ_FIRST(&qlist->head); + + ret = entry->value; + + return ret; +} + +int qlist_empty(const QList *qlist) +{ + return QTAILQ_EMPTY(&qlist->head); +} + +/** + * qobject_to_qlist(): Convert a QObject into a QList + */ +QList *qobject_to_qlist(const QObject *obj) +{ + if (qobject_type(obj) != QTYPE_QLIST) { + return NULL; + } + + return container_of(obj, QList, base); +} + +/** + * qlist_destroy_obj(): Free all the memory allocated by a QList + */ +static void qlist_destroy_obj(QObject *obj) +{ + QList *qlist; + QListEntry *entry, *next_entry; + + assert(obj != NULL); + qlist = qobject_to_qlist(obj); + + QTAILQ_FOREACH_SAFE(entry, &qlist->head, next, next_entry) { + QTAILQ_REMOVE(&qlist->head, entry, next); + qobject_decref(entry->value); + qemu_free(entry); + } + + qemu_free(qlist); +} @@ -0,0 +1,52 @@ +/* + * QList data type header. + * + * Copyright (C) 2009 Red Hat Inc. + * + * Authors: + * Luiz Capitulino <lcapitulino@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ +#ifndef QLIST_H +#define QLIST_H + +#include "qobject.h" +#include "qemu-queue.h" +#include "qemu-common.h" + +typedef struct QListEntry { + QObject *value; + QTAILQ_ENTRY(QListEntry) next; +} QListEntry; + +typedef struct QList { + QObject_HEAD; + QTAILQ_HEAD(,QListEntry) head; +} QList; + +#define qlist_append(qlist, obj) \ + qlist_append_obj(qlist, QOBJECT(obj)) + +#define QLIST_FOREACH_ENTRY(qlist, var) \ + for ((var) = ((qlist)->head.tqh_first); \ + (var); \ + (var) = ((var)->next.tqe_next)) + +static inline QObject *qlist_entry_obj(const QListEntry *entry) +{ + return entry->value; +} + +QList *qlist_new(void); +QList *qlist_copy(QList *src); +void qlist_append_obj(QList *qlist, QObject *obj); +void qlist_iter(const QList *qlist, + void (*iter)(QObject *obj, void *opaque), void *opaque); +QObject *qlist_pop(QList *qlist); +QObject *qlist_peek(QList *qlist); +int qlist_empty(const QList *qlist); +QList *qobject_to_qlist(const QObject *obj); + +#endif /* QLIST_H */ diff --git a/qobject.h b/qobject.h new file mode 100644 index 0000000..07de211 --- /dev/null +++ b/qobject.h @@ -0,0 +1,112 @@ +/* + * QEMU Object Model. + * + * Based on ideas by Avi Kivity <avi@redhat.com> + * + * Copyright (C) 2009 Red Hat Inc. + * + * Authors: + * Luiz Capitulino <lcapitulino@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * QObject Reference Counts Terminology + * ------------------------------------ + * + * - Returning references: A function that returns an object may + * return it as either a weak or a strong reference. If the reference + * is strong, you are responsible for calling QDECREF() on the reference + * when you are done. + * + * If the reference is weak, the owner of the reference may free it at + * any time in the future. Before storing the reference anywhere, you + * should call QINCREF() to make the reference strong. + * + * - Transferring ownership: when you transfer ownership of a reference + * by calling a function, you are no longer responsible for calling + * QDECREF() when the reference is no longer needed. In other words, + * when the function returns you must behave as if the reference to the + * passed object was weak. + */ +#ifndef QOBJECT_H +#define QOBJECT_H + +#include <stddef.h> +#include <assert.h> + +typedef enum { + QTYPE_NONE, + QTYPE_QINT, + QTYPE_QSTRING, + QTYPE_QDICT, + QTYPE_QLIST, + QTYPE_QFLOAT, + QTYPE_QBOOL, + QTYPE_QERROR, +} qtype_code; + +struct QObject; + +typedef struct QType { + qtype_code code; + void (*destroy)(struct QObject *); +} QType; + +typedef struct QObject { + const QType *type; + size_t refcnt; +} QObject; + +/* Objects definitions must include this */ +#define QObject_HEAD \ + QObject base + +/* Get the 'base' part of an object */ +#define QOBJECT(obj) (&(obj)->base) + +/* High-level interface for qobject_incref() */ +#define QINCREF(obj) \ + qobject_incref(QOBJECT(obj)) + +/* High-level interface for qobject_decref() */ +#define QDECREF(obj) \ + qobject_decref(QOBJECT(obj)) + +/* Initialize an object to default values */ +#define QOBJECT_INIT(obj, qtype_type) \ + obj->base.refcnt = 1; \ + obj->base.type = qtype_type + +/** + * qobject_incref(): Increment QObject's reference count + */ +static inline void qobject_incref(QObject *obj) +{ + if (obj) + obj->refcnt++; +} + +/** + * qobject_decref(): Decrement QObject's reference count, deallocate + * when it reaches zero + */ +static inline void qobject_decref(QObject *obj) +{ + if (obj && --obj->refcnt == 0) { + assert(obj->type != NULL); + assert(obj->type->destroy != NULL); + obj->type->destroy(obj); + } +} + +/** + * qobject_type(): Return the QObject's type + */ +static inline qtype_code qobject_type(const QObject *obj) +{ + assert(obj->type != NULL); + return obj->type->code; +} + +#endif /* QOBJECT_H */ diff --git a/qstring.c b/qstring.c new file mode 100644 index 0000000..740a106 --- /dev/null +++ b/qstring.c @@ -0,0 +1,140 @@ +/* + * QString data type. + * + * Copyright (C) 2009 Red Hat Inc. + * + * Authors: + * Luiz Capitulino <lcapitulino@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ +#include "qobject.h" +#include "qstring.h" +#include "qemu-common.h" + +static void qstring_destroy_obj(QObject *obj); + +static const QType qstring_type = { + .code = QTYPE_QSTRING, + .destroy = qstring_destroy_obj, +}; + +/** + * qstring_new(): Create a new empty QString + * + * Return strong reference. + */ +QString *qstring_new(void) +{ + return qstring_from_str(""); +} + +/** + * qstring_from_substr(): Create a new QString from a C string substring + * + * Return string reference + */ +QString *qstring_from_substr(const char *str, int start, int end) +{ + QString *qstring; + + qstring = qemu_malloc(sizeof(*qstring)); + + qstring->length = end - start + 1; + qstring->capacity = qstring->length; + + qstring->string = qemu_malloc(qstring->capacity + 1); + memcpy(qstring->string, str + start, qstring->length); + qstring->string[qstring->length] = 0; + + QOBJECT_INIT(qstring, &qstring_type); + + return qstring; +} + +/** + * qstring_from_str(): Create a new QString from a regular C string + * + * Return strong reference. + */ +QString *qstring_from_str(const char *str) +{ + return qstring_from_substr(str, 0, strlen(str) - 1); +} + +static void capacity_increase(QString *qstring, size_t len) +{ + if (qstring->capacity < (qstring->length + len)) { + qstring->capacity += len; + qstring->capacity *= 2; /* use exponential growth */ + + qstring->string = qemu_realloc(qstring->string, qstring->capacity + 1); + } +} + +/* qstring_append(): Append a C string to a QString + */ +void qstring_append(QString *qstring, const char *str) +{ + size_t len = strlen(str); + + capacity_increase(qstring, len); + memcpy(qstring->string + qstring->length, str, len); + qstring->length += len; + qstring->string[qstring->length] = 0; +} + +void qstring_append_int(QString *qstring, int64_t value) +{ + char num[32]; + + snprintf(num, sizeof(num), "%" PRId64, value); + qstring_append(qstring, num); +} + +/** + * qstring_append_chr(): Append a C char to a QString + */ +void qstring_append_chr(QString *qstring, int c) +{ + capacity_increase(qstring, 1); + qstring->string[qstring->length++] = c; + qstring->string[qstring->length] = 0; +} + +/** + * qobject_to_qstring(): Convert a QObject to a QString + */ +QString *qobject_to_qstring(const QObject *obj) +{ + if (qobject_type(obj) != QTYPE_QSTRING) + return NULL; + + return container_of(obj, QString, base); +} + +/** + * qstring_get_str(): Return a pointer to the stored string + * + * NOTE: Should be used with caution, if the object is deallocated + * this pointer becomes invalid. + */ +const char *qstring_get_str(const QString *qstring) +{ + return qstring->string; +} + +/** + * qstring_destroy_obj(): Free all memory allocated by a QString + * object + */ +static void qstring_destroy_obj(QObject *obj) +{ + QString *qs; + + assert(obj != NULL); + qs = qobject_to_qstring(obj); + qemu_free(qs->string); + qemu_free(qs); +} diff --git a/qstring.h b/qstring.h new file mode 100644 index 0000000..6aaa7d5 --- /dev/null +++ b/qstring.h @@ -0,0 +1,23 @@ +#ifndef QSTRING_H +#define QSTRING_H + +#include <stdint.h> +#include "qobject.h" + +typedef struct QString { + QObject_HEAD; + char *string; + size_t length; + size_t capacity; +} QString; + +QString *qstring_new(void); +QString *qstring_from_str(const char *str); +QString *qstring_from_substr(const char *str, int start, int end); +const char *qstring_get_str(const QString *qstring); +void qstring_append_int(QString *qstring, int64_t value); +void qstring_append(QString *qstring, const char *str); +void qstring_append_chr(QString *qstring, int c); +QString *qobject_to_qstring(const QObject *obj); + +#endif /* QSTRING_H */ diff --git a/sdl_keysym.h b/sdl_keysym.h index c213ef8..ee90480 100644 --- a/sdl_keysym.h +++ b/sdl_keysym.h @@ -273,5 +273,5 @@ static const name2keysym_t name2keysym[]={ {"Pause", SDLK_PAUSE}, {"Escape", SDLK_ESCAPE}, -{0,0}, +{NULL, 0}, }; diff --git a/softmmu_header.h b/softmmu_header.h index f96b512..356d771 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -14,8 +14,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #if DATA_SIZE == 8 #define SUFFIX q @@ -78,150 +77,6 @@ #define ADDR_READ addr_read #endif -#if (DATA_SIZE <= 4) && (TARGET_LONG_BITS == 32) && defined(__i386__) && \ - (ACCESS_TYPE < NB_MMU_MODES) && defined(ASM_SOFTMMU) - -static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) -{ - int res; - - asm volatile ("movl %1, %%edx\n" - "movl %1, %%eax\n" - "shrl %3, %%edx\n" - "andl %4, %%eax\n" - "andl %2, %%edx\n" - "leal %5(%%edx, %%ebp), %%edx\n" - "cmpl (%%edx), %%eax\n" - "movl %1, %%eax\n" - "je 1f\n" - "movl %6, %%edx\n" - "call %7\n" - "movl %%eax, %0\n" - "jmp 2f\n" - "1:\n" - "addl 12(%%edx), %%eax\n" -#if DATA_SIZE == 1 - "movzbl (%%eax), %0\n" -#elif DATA_SIZE == 2 - "movzwl (%%eax), %0\n" -#elif DATA_SIZE == 4 - "movl (%%eax), %0\n" -#else -#error unsupported size -#endif - "2:\n" - : "=r" (res) - : "r" (ptr), - "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), - "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), - "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), - "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MMU_INDEX][0].addr_read)), - "i" (CPU_MMU_INDEX), - "m" (*(uint8_t *)&glue(glue(__ld, SUFFIX), MMUSUFFIX)) - : "%eax", "%ecx", "%edx", "memory", "cc"); - return res; -} - -#if DATA_SIZE <= 2 -static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr) -{ - int res; - - asm volatile ("movl %1, %%edx\n" - "movl %1, %%eax\n" - "shrl %3, %%edx\n" - "andl %4, %%eax\n" - "andl %2, %%edx\n" - "leal %5(%%edx, %%ebp), %%edx\n" - "cmpl (%%edx), %%eax\n" - "movl %1, %%eax\n" - "je 1f\n" - "movl %6, %%edx\n" - "call %7\n" -#if DATA_SIZE == 1 - "movsbl %%al, %0\n" -#elif DATA_SIZE == 2 - "movswl %%ax, %0\n" -#else -#error unsupported size -#endif - "jmp 2f\n" - "1:\n" - "addl 12(%%edx), %%eax\n" -#if DATA_SIZE == 1 - "movsbl (%%eax), %0\n" -#elif DATA_SIZE == 2 - "movswl (%%eax), %0\n" -#else -#error unsupported size -#endif - "2:\n" - : "=r" (res) - : "r" (ptr), - "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), - "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), - "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), - "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MMU_INDEX][0].addr_read)), - "i" (CPU_MMU_INDEX), - "m" (*(uint8_t *)&glue(glue(__ld, SUFFIX), MMUSUFFIX)) - : "%eax", "%ecx", "%edx", "memory", "cc"); - return res; -} -#endif - -static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE v) -{ - asm volatile ("movl %0, %%edx\n" - "movl %0, %%eax\n" - "shrl %3, %%edx\n" - "andl %4, %%eax\n" - "andl %2, %%edx\n" - "leal %5(%%edx, %%ebp), %%edx\n" - "cmpl (%%edx), %%eax\n" - "movl %0, %%eax\n" - "je 1f\n" -#if DATA_SIZE == 1 - "movzbl %b1, %%edx\n" -#elif DATA_SIZE == 2 - "movzwl %w1, %%edx\n" -#elif DATA_SIZE == 4 - "movl %1, %%edx\n" -#else -#error unsupported size -#endif - "movl %6, %%ecx\n" - "call %7\n" - "jmp 2f\n" - "1:\n" - "addl 8(%%edx), %%eax\n" -#if DATA_SIZE == 1 - "movb %b1, (%%eax)\n" -#elif DATA_SIZE == 2 - "movw %w1, (%%eax)\n" -#elif DATA_SIZE == 4 - "movl %1, (%%eax)\n" -#else -#error unsupported size -#endif - "2:\n" - : - : "r" (ptr), -#if DATA_SIZE == 1 - "q" (v), -#else - "r" (v), -#endif - "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), - "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), - "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), - "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MMU_INDEX][0].addr_write)), - "i" (CPU_MMU_INDEX), - "m" (*(uint8_t *)&glue(glue(__st, SUFFIX), MMUSUFFIX)) - : "%eax", "%ecx", "%edx", "memory", "cc"); -} - -#else - /* generic load/store macros */ static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) @@ -292,8 +147,6 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE #endif /* ACCESS_TYPE != (NB_MMU_MODES + 1) */ -#endif /* !asm */ - #if ACCESS_TYPE != (NB_MMU_MODES + 1) #if DATA_SIZE == 8 diff --git a/softmmu_template.h b/softmmu_template.h index ad00c4d..4cd66f0 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -14,8 +14,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #define DATA_SIZE (1 << SHIFT) @@ -90,9 +89,6 @@ static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr, res |= (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr + 4) << 32; #endif #endif /* SHIFT > 2 */ -#ifdef CONFIG_KQEMU - env->last_io_time = cpu_get_time_fast(); -#endif return res; } @@ -271,9 +267,6 @@ static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr, io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val >> 32); #endif #endif /* SHIFT > 2 */ -#ifdef CONFIG_KQEMU - env->last_io_time = cpu_get_time_fast(); -#endif } void REGPARM glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, @@ -1,7 +1,6 @@ OUTPUT_FORMAT("elf32-sparc", "elf32-sparc", "elf32-sparc") OUTPUT_ARCH(sparc) -SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib); ENTRY(_start) SECTIONS { @@ -66,6 +65,26 @@ SECTIONS .data1 : { *(.data1) } .tdata : { *(.tdata) } .tbss : { *(.tbss) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } .ctors : { *(.ctors) @@ -14,8 +14,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #include <stdlib.h> #include <stdio.h> @@ -14,8 +14,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #ifndef THUNK_H #define THUNK_H diff --git a/translate-all.c b/translate-all.c index 8964758..4d6ea61 100644 --- a/translate-all.c +++ b/translate-all.c @@ -14,8 +14,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #include <stdarg.h> #include <stdlib.h> diff --git a/uboot_image.h b/uboot_image.h index b6d49be..9fc2760 100644 --- a/uboot_image.h +++ b/uboot_image.h @@ -16,8 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc. - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * with this program; if not, see <http://www.gnu.org/licenses/>. * ******************************************************************** * NOTE: This header file defines an interface to U-Boot. Including diff --git a/vl-android.c b/vl-android.c index bb8b759..fc32d77 100644 --- a/vl-android.c +++ b/vl-android.c @@ -1805,61 +1805,6 @@ void sigint_handler(int sig) #endif /* CONFIG_TRACE */ -int get_param_value(char *buf, int buf_size, - const char *tag, const char *str) -{ - const char *p; - char option[128]; - - p = str; - for(;;) { - p = get_opt_name(option, sizeof(option), p, '='); - if (*p != '=') - break; - p++; - if (!strcmp(tag, option)) { - (void)get_opt_value(buf, buf_size, p); - return strlen(buf); - } else { - p = get_opt_value(NULL, 0, p); - } - if (*p != ',') - break; - p++; - } - return 0; -} - -int check_params(char *buf, int buf_size, - const char * const *params, const char *str) -{ - const char *p; - int i; - - p = str; - while (*p != '\0') { - p = get_opt_name(buf, buf_size, p, '='); - if (*p != '=') { - return -1; - } - p++; - for (i = 0; params[i] != NULL; i++) { - if (!strcmp(params[i], buf)) { - break; - } - } - if (params[i] == NULL) { - return -1; - } - p = get_opt_value(NULL, 0, p); - if (*p != ',') { - break; - } - p++; - } - return 0; -} - /***********************************************************/ /* Bluetooth support */ static int nb_hcis; diff --git a/vnc_keysym.h b/vnc_keysym.h index 2d255c9..55cb87e 100644 --- a/vnc_keysym.h +++ b/vnc_keysym.h @@ -320,5 +320,5 @@ static const name2keysym_t name2keysym[]={ {"Katakana_Real", 0xff25}, {"Eisu_toggle", 0xff30}, -{0,0}, +{NULL,0}, }; diff --git a/vnchextile.h b/vnchextile.h index f5b6fcb..6d60b24 100644 --- a/vnchextile.h +++ b/vnchextile.h @@ -72,7 +72,7 @@ static void CONCAT(send_hextile_tile_, NAME)(VncState *vs, *last_bg = bg; } - if (!*has_fg || *last_fg != fg) { + if (n_colors < 3 && (!*has_fg || *last_fg != fg)) { flags |= 0x04; *has_fg = 1; *last_fg = fg; @@ -2,7 +2,6 @@ OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") OUTPUT_ARCH(i386:x86-64) ENTRY(_start) -SEARCH_DIR("/lib64"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/local/lib64"); SECTIONS { /* Read-only sections, merged into text segment: */ |