From: Anthony Liguori <anthony@codemonkey.ws>
To: Paolo Bonzini <bonzini@gnu.org>
Cc: qemu-devel@nongnu.org, Vincent Hanquez <vincent@snarc.org>,
Luiz Capitulino <lcapitulino@redhat.com>
Subject: Re: [Qemu-devel] Re: [PATCH 01/10] Introduce qmisc module
Date: Sun, 18 Oct 2009 11:26:22 -0500 [thread overview]
Message-ID: <4ADB41AE.8080103@codemonkey.ws> (raw)
In-Reply-To: <4ADB2B13.4090207@codemonkey.ws>
[-- Attachment #1: Type: text/plain, Size: 886 bytes --]
Anthony Liguori wrote:
> Paolo Bonzini wrote:
>> On 10/18/2009 04:06 PM, Luiz Capitulino wrote:
>>> Integration with QObjects is a killer feature, I think it's the
>>> stronger argument against grabbing one from the internet.
>>
>> Yeah, I'd say let's go with Anthony's stuff. I'll rebase the encoder
>> on top of it soonish (I still think it's best if JSON encoding lies
>> in QObject like a kind of toString). If we'll need the asynchronous
>> parsing later, we can easily replace it with mine or Vincent's.
>
> One thing I want to add as a feature to the 0.12 release is a nice
> client API. To have this, we'll need message boundary identification
> and a JSON encoder. I'll focus on the message boundary identification
> today.
Here's a first pass. I'll clean up this afternoon and post a proper
patch. It turned out to work pretty well.
Regards,
Anthony Liguori
[-- Attachment #2: json-streamer.c --]
[-- Type: text/x-csrc, Size: 8034 bytes --]
#include <stdint.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#define offset_of(type, member) ((unsigned long)&(((type *)0)->member))
#define container_of(obj, type, member) (type *)((void *)(obj) - offset_of(type, member))
/*
* \"([^\\\"]|(\\\"\\'\\\\\\/\\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,
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_WHITESPACE,
IN_START,
DONE,
SKIP,
};
static const uint8_t json_lexer[][256] = {
[IN_DONE] = {
[1 ... 0x7F] = DONE,
},
/* 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,
},
/* 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,
},
/* Zero */
[IN_ZERO] = {
[1 ... 0x7F] = DONE,
['0' ... '9'] = ERROR,
},
/* Non-zero numbers */
[IN_DIGITS] = {
[1 ... 0x7F] = DONE,
['0' ... '9'] = IN_DIGITS,
},
[IN_DIGIT] = {
['0' ... '9'] = IN_DIGITS,
},
[IN_EXP_E] = {
['-'] = IN_DIGIT,
['+'] = IN_DIGIT,
['0' ... '9'] = IN_DIGITS,
},
[IN_MANTISSA_DIGITS] = {
[1 ... 0x7F] = DONE,
['0' ... '9'] = IN_MANTISSA_DIGITS,
['e'] = IN_EXP_E,
['E'] = IN_EXP_E,
},
[IN_MANTISSA] = {
['0' ... '9'] = IN_MANTISSA_DIGITS,
},
[IN_NONZERO_NUMBER] = {
[1 ... 0x7F] = DONE,
['0' ... '9'] = IN_NONZERO_NUMBER,
['e'] = IN_EXP_E,
['E'] = IN_EXP_E,
['.'] = IN_MANTISSA,
},
[IN_NEG_NONZERO_NUMBER] = {
['1' ... '9'] = IN_NONZERO_NUMBER,
},
/* keywords */
[IN_KEYWORD] = {
[1 ... 0x7F] = DONE,
['a' ... 'z'] = IN_KEYWORD,
},
/* whitespace */
[IN_WHITESPACE] = {
[1 ... 0x7F] = SKIP,
[' '] = IN_WHITESPACE,
['\t'] = IN_WHITESPACE,
['\r'] = IN_WHITESPACE,
['\n'] = IN_WHITESPACE,
},
/* top level rule */
[IN_START] = {
['"'] = IN_DQ_STRING,
['\''] = IN_SQ_STRING,
['0'] = IN_ZERO,
['1' ... '9'] = IN_NONZERO_NUMBER,
['-'] = IN_NEG_NONZERO_NUMBER,
['{'] = IN_DONE,
['}'] = IN_DONE,
['['] = IN_DONE,
[']'] = IN_DONE,
[','] = IN_DONE,
[':'] = IN_DONE,
['a' ... 'z'] = IN_KEYWORD,
[' '] = IN_WHITESPACE,
['\t'] = IN_WHITESPACE,
['\r'] = IN_WHITESPACE,
['\n'] = IN_WHITESPACE,
},
};
typedef struct JSONLexer
{
void (*emit)(struct JSONLexer *lexer, const char *token);
enum json_lexer_state state;
char token[1024];
size_t len;
} JSONLexer;
void json_lexer_init(JSONLexer *lexer,
void (*func)(JSONLexer *, const char *))
{
lexer->emit = func;
lexer->state = IN_START;
lexer->len = 0;
lexer->token[lexer->len] = 0;
}
int json_lexer_feed(JSONLexer *lexer, char ch)
{
lexer->state = json_lexer[lexer->state][(uint8_t)ch];
if (lexer->state == DONE || lexer->state == SKIP) {
if (lexer->state == DONE) {
lexer->emit(lexer, lexer->token);
}
lexer->state = json_lexer[IN_START][(uint8_t)ch];
lexer->len = 0;
}
if (lexer->state == ERROR) {
return -EINVAL;
}
if (lexer->len < (sizeof(lexer->token) - 1)) {
lexer->token[lexer->len++] = ch;
}
lexer->token[lexer->len] = 0;
return 0;
}
typedef struct JSONMessageParser
{
void (*emit)(struct JSONMessageParser *parser, const char *message);
JSONLexer lexer;
int brace_count;
int bracket_count;
char buffer[1024];
size_t len;
} JSONMessageParser;
static void json_message_process_token(JSONLexer *lexer, const char *token)
{
JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer);
if (strcmp(token, "{") == 0) {
parser->brace_count++;
} else if (strcmp(token, "}") == 0) {
parser->brace_count--;
} else if (strcmp(token, "[") == 0) {
parser->bracket_count++;
} else if (strcmp(token, "]") == 0) {
parser->bracket_count--;
}
if (parser->brace_count == 0 &&
parser->bracket_count == 0) {
parser->emit(parser, parser->buffer);
parser->len = 0;
}
}
void json_message_parser_init(JSONMessageParser *parser,
void (*func)(JSONMessageParser *, const char *))
{
parser->emit = func;
parser->brace_count = 0;
parser->bracket_count = 0;
parser->len = 0;
parser->buffer[parser->len] = 0;
json_lexer_init(&parser->lexer, json_message_process_token);
}
int json_message_parser_feed(JSONMessageParser *parser,
const char *buffer, size_t size)
{
size_t i;
for (i = 0; i < size; i++) {
int ret;
parser->buffer[parser->len++] = buffer[i];
parser->buffer[parser->len] = 0; /* FIXME overflow */
ret = json_lexer_feed(&parser->lexer, buffer[i]);
if (ret < 0) {
return ret;
}
}
return 0;
}
static void got_message(JSONMessageParser *parser, const char *message)
{
printf("got message `%s'\n", message);
}
int main(int argc, char **argv)
{
JSONMessageParser parser = {};
char buf[2];
int ch;
json_message_parser_init(&parser, got_message);
while ((ch = getchar()) != EOF) {
buf[0] = ch;
buf[1] = 0;
if (json_message_parser_feed(&parser, buf, 1) < 0) {
fprintf(stderr, "Invalid character `%c'\n", ch);
return 1;
}
}
return 0;
}
next prev parent reply other threads:[~2009-10-18 16:26 UTC|newest]
Thread overview: 62+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-10-08 21:35 [Qemu-devel] [PATCH v0 00/10]: More QObject conversions Luiz Capitulino
2009-10-08 21:35 ` [Qemu-devel] [PATCH 01/10] Introduce qmisc module Luiz Capitulino
2009-10-15 14:02 ` Anthony Liguori
2009-10-15 15:26 ` Luiz Capitulino
2009-10-15 15:35 ` Anthony Liguori
2009-10-15 17:17 ` Luiz Capitulino
2009-10-15 18:33 ` Anthony Liguori
2009-10-15 18:45 ` Anthony Liguori
2009-10-15 16:39 ` Daniel P. Berrange
2009-10-15 16:46 ` Daniel P. Berrange
2009-10-15 17:28 ` Luiz Capitulino
2009-10-15 18:34 ` Anthony Liguori
2009-10-16 13:24 ` [Qemu-devel] " Paolo Bonzini
2009-10-16 13:45 ` Anthony Liguori
2009-10-16 17:35 ` Paolo Bonzini
2009-10-16 17:38 ` Anthony Liguori
2009-10-16 19:36 ` Paolo Bonzini
2009-10-16 21:37 ` Anthony Liguori
2009-10-17 0:32 ` Paolo Bonzini
2009-10-17 0:38 ` malc
2009-10-17 0:46 ` Paolo Bonzini
2009-10-17 1:49 ` Anthony Liguori
2009-10-17 1:50 ` Anthony Liguori
2009-10-17 7:48 ` Paolo Bonzini
2009-10-17 10:01 ` Vincent Hanquez
2009-10-18 14:06 ` Luiz Capitulino
2009-10-18 14:08 ` Paolo Bonzini
2009-10-18 14:49 ` Anthony Liguori
2009-10-18 15:18 ` Luiz Capitulino
2009-10-18 15:25 ` Paolo Bonzini
2009-10-18 16:05 ` Luiz Capitulino
2009-10-18 16:32 ` Anthony Liguori
2009-10-18 18:04 ` Paolo Bonzini
2009-10-18 22:00 ` Luiz Capitulino
2009-10-18 16:26 ` Anthony Liguori [this message]
2009-10-18 17:32 ` Vincent Hanquez
2009-10-18 21:24 ` Anthony Liguori
2009-10-18 15:06 ` Vincent Hanquez
2009-10-18 15:35 ` Luiz Capitulino
2009-10-18 15:39 ` Paolo Bonzini
2009-10-18 16:56 ` Vincent Hanquez
2009-10-18 16:29 ` Anthony Liguori
2009-10-18 16:46 ` Vincent Hanquez
2009-10-18 17:59 ` Paolo Bonzini
2009-10-08 21:35 ` [Qemu-devel] [PATCH 02/10] monitor: Convert do_memory_save() to QObject Luiz Capitulino
2009-10-08 21:35 ` [Qemu-devel] [PATCH 03/10] monitor: Convert do_physical_memory_save() " Luiz Capitulino
2009-10-08 21:35 ` [Qemu-devel] [PATCH 04/10] monitor: Convert do_migrate() " Luiz Capitulino
2009-10-08 21:35 ` [Qemu-devel] [PATCH 05/10] monitor: Convert do_migrate_set_speed() " Luiz Capitulino
2009-10-08 21:35 ` [Qemu-devel] [PATCH 06/10] monitor: Convert do_migrate_cancel() " Luiz Capitulino
2009-10-08 21:35 ` [Qemu-devel] [PATCH 07/10] monitor: Convert do_info_migrate() " Luiz Capitulino
2009-10-10 12:11 ` Markus Armbruster
2009-10-15 14:07 ` Anthony Liguori
2009-10-08 21:35 ` [Qemu-devel] [PATCH 08/10] monitor: Convert bdrv_info() " Luiz Capitulino
2009-10-10 12:18 ` Markus Armbruster
2009-10-14 13:23 ` Luiz Capitulino
2009-10-14 14:11 ` Markus Armbruster
2009-10-15 14:13 ` Anthony Liguori
2009-10-08 21:35 ` [Qemu-devel] [PATCH 09/10] monitor: Convert pci_device_hot_add() " Luiz Capitulino
2009-10-08 21:35 ` [Qemu-devel] [PATCH 10/10] monitor: Convert do_pci_device_hot_remove() " Luiz Capitulino
2009-10-10 12:31 ` [Qemu-devel] [PATCH v0 00/10]: More QObject conversions Markus Armbruster
2009-10-11 14:48 ` Luiz Capitulino
2009-10-12 15:36 ` Markus Armbruster
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4ADB41AE.8080103@codemonkey.ws \
--to=anthony@codemonkey.ws \
--cc=bonzini@gnu.org \
--cc=lcapitulino@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=vincent@snarc.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).