diff options
author | Nicolas Dechesne <nicolas.dechesne@linaro.org> | 2018-04-18 13:27:25 +0200 |
---|---|---|
committer | Nicolas Dechesne <nicolas.dechesne@linaro.org> | 2018-04-18 13:27:25 +0200 |
commit | 375b21acdba2d1b9d0b2ba85f9b7df4c57c334e0 (patch) | |
tree | 7001524012dae9c94f0c29007d594929c87830f7 | |
parent | f8343e246b4c40a9cb81b7291f238f343d5a5cc5 (diff) | |
parent | 4ad63502c5ce3f4fbdf223dc7f58d6ba9bbf5eea (diff) |
Merge remote-tracking branch 'upstream/master'
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | accessor.c (renamed from qmi_message.c) | 239 | ||||
-rw-r--r-- | kernel.c | 339 | ||||
-rw-r--r-- | list.h | 95 | ||||
-rw-r--r-- | parser.c | 422 | ||||
-rw-r--r-- | qmi_struct.c | 157 | ||||
-rw-r--r-- | qmic.c | 365 | ||||
-rw-r--r-- | qmic.h | 99 |
8 files changed, 1107 insertions, 617 deletions
@@ -1,10 +1,10 @@ OUT := qmic -CFLAGS := -Wall -g -O2 -LDFLAGS := -prefix := /usr/local +CFLAGS ?= -Wall -g -O2 +LDFLAGS ?= +prefix ?= /usr/local -SRCS := qmic.c qmi_message.c qmi_struct.c +SRCS := accessor.c kernel.c parser.c qmic.c OBJS := $(SRCS:.c=.o) $(OUT): $(OBJS) diff --git a/qmi_message.c b/accessor.c index c1dbfd7..8c1facb 100644 --- a/qmi_message.c +++ b/accessor.c @@ -1,106 +1,102 @@ #include <stdio.h> #include <stdlib.h> -#include <stdbool.h> -#include <string.h> -#include "qmic.h" - -static const char *sz_simple_types[] = { - [TYPE_U8] = "uint8_t", - [TYPE_U16] = "uint16_t", - [TYPE_U32] = "uint32_t", - [TYPE_U64] = "uint64_t", -}; - -struct qmi_message_member { - const char *name; - int type; - struct qmi_struct *qmi_struct; - int id; - bool required; - unsigned array; - - struct qmi_message_member *next; -}; -struct qmi_message { - enum message_type type; - const char *name; - unsigned msg_id; - - struct qmi_message *next; - - LIST_HEAD(qmi_message_member, members); -}; - -LIST_HEAD(qmi_message, qmi_messages); +#include "qmic.h" -void qmi_message_parse(enum message_type message_type) +static void qmi_struct_header(FILE *fp, const char *package) { - struct qmi_message_member *qmm; - struct qmi_message *qm; - struct token msg_id_tok; - struct token type_tok; - struct token num_tok; - struct token id_tok; - unsigned array; - bool required; - - token_expect(TOK_ID, &msg_id_tok); - token_expect('{', NULL); - - qm = malloc(sizeof(struct qmi_message)); - qm->name = msg_id_tok.str; - qm->type = message_type; - - while (!token_accept('}', NULL)) { - array = 0; - - if (token_accept(TOK_REQUIRED, NULL)) - required = true; - else if (token_accept(TOK_OPTIONAL, NULL)) - required = false; - else - yyerror("expected required, optional or '}'"); - - token_expect(TOK_TYPE, &type_tok); - token_expect(TOK_ID, &id_tok); - - if (token_accept('[', NULL)) { - array = 1; - if (token_accept(TOK_NUM, &num_tok)) { - if (num_tok.num & 0xffff0000) - array = 4; - else if (num_tok.num & 0xff00) - array = 2; - } - - token_expect(']', NULL); + struct qmi_struct_member *qsm; + struct qmi_struct *qs; + + list_for_each_entry(qs, &qmi_structs, node) { + fprintf(fp, "struct %s_%s {\n", + package, qs->name); + list_for_each_entry(qsm, &qs->members, node) { + fprintf(fp, "\t%s %s;\n", + sz_simple_types[qsm->type], qsm->name); } + fprintf(fp, "};\n" + "\n"); + } +} - token_expect('=', NULL); - token_expect(TOK_NUM, &num_tok); - token_expect(';', NULL); +static void qmi_struct_emit_prototype(FILE *fp, + const char *package, + const char *message, + const char *member, + unsigned array_size, + struct qmi_struct *qs) +{ + if (array_size) { + fprintf(fp, "int %1$s_%2$s_set_%3$s(struct %1$s_%2$s *%2$s, struct %1$s_%4$s *val, size_t count);\n", + package, message, member, qs->name); - qmm = malloc(sizeof(struct qmi_message_member)); - qmm->name = id_tok.str; - qmm->type = type_tok.num; - qmm->qmi_struct = type_tok.qmi_struct; - qmm->id = num_tok.num; - qmm->required = required; - qmm->array = array; + fprintf(fp, "struct %1$s_%4$s *%1$s_%2$s_get_%3$s(struct %1$s_%2$s *%2$s, size_t *count);\n\n", + package, message, member, qs->name); + } else { + fprintf(fp, "int %1$s_%2$s_set_%3$s(struct %1$s_%2$s *%2$s, struct %1$s_%4$s *val);\n", + package, message, member, qs->name); - LIST_ADD(qm->members, qmm); + fprintf(fp, "struct %1$s_%4$s *%1$s_%2$s_get_%3$s(struct %1$s_%2$s *%2$s);\n\n", + package, message, member, qs->name); } +} - if (token_accept('=', NULL)) { - token_expect(TOK_NUM, &num_tok); - - qm->msg_id = num_tok.num; - } +static void qmi_struct_emit_accessors(FILE *fp, + const char *package, + const char *message, + const char *member, + int member_id, + unsigned array_size, + struct qmi_struct *qs) +{ + if (array_size) { + fprintf(fp, "int %1$s_%2$s_set_%3$s(struct %1$s_%2$s *%2$s, struct %1$s_%4$s *val, size_t count)\n" + "{\n" + " return qmi_tlv_set_array((struct qmi_tlv*)%2$s, %5$d, %6$d, val, count, sizeof(struct %1$s_%4$s));\n" + "}\n\n", + package, message, member, qs->name, member_id, array_size); - token_expect(';', NULL); + fprintf(fp, "struct %1$s_%4$s *%1$s_%2$s_get_%3$s(struct %1$s_%2$s *%2$s, size_t *count)\n" + "{\n" + " size_t size;\n" + " size_t len;\n" + " void *ptr;\n" + "\n" + " ptr = qmi_tlv_get_array((struct qmi_tlv*)%2$s, %5$d, %6$d, &len, &size);\n" + " if (!ptr)\n" + " return NULL;\n" + "\n" + " if (size != sizeof(struct %1$s_%4$s))\n" + " return NULL;\n" + "\n" + " *count = len;\n" + " return ptr;\n" + "}\n\n", + package, message, member, qs->name, member_id, array_size); + } else { + fprintf(fp, "int %1$s_%2$s_set_%3$s(struct %1$s_%2$s *%2$s, struct %1$s_%4$s *val)\n" + "{\n" + " return qmi_tlv_set((struct qmi_tlv*)%2$s, %5$d, val, sizeof(struct %1$s_%4$s));\n" + "}\n\n", + package, message, member, qs->name, member_id); - LIST_ADD(qmi_messages, qm); + fprintf(fp, "struct %1$s_%4$s *%1$s_%2$s_get_%3$s(struct %1$s_%2$s *%2$s)\n" + "{\n" + " size_t len;\n" + " void *ptr;\n" + "\n" + " ptr = qmi_tlv_get((struct qmi_tlv*)%2$s, %5$d, &len);\n" + " if (!ptr)\n" + " return NULL;\n" + "\n" + " if (len != sizeof(struct %1$s_%4$s))\n" + " return NULL;\n" + "\n" + " return ptr;\n" + "}\n\n", + package, message, member, qs->name, member_id); + } } static void qmi_message_emit_message_type(FILE *fp, @@ -166,7 +162,7 @@ static void qmi_message_emit_simple_prototype(FILE *fp, const char *message, struct qmi_message_member *qmm) { - if (qmm->array) { + if (qmm->array_size) { fprintf(fp, "int %1$s_%2$s_set_%3$s(struct %1$s_%2$s *%2$s, %4$s *val, size_t count);\n", package, message, qmm->name, sz_simple_types[qmm->type]); @@ -187,12 +183,12 @@ static void qmi_message_emit_simple_accessors(FILE *fp, const char *message, struct qmi_message_member *qmm) { - if (qmm->array) { + if (qmm->array_size) { fprintf(fp, "int %1$s_%2$s_set_%3$s(struct %1$s_%2$s *%2$s, %4$s *val, size_t count)\n" "{\n" " return qmi_tlv_set_array((struct qmi_tlv*)%2$s, %5$d, %6$d, val, count, sizeof(%4$s));\n" "}\n\n", - package, message, qmm->name, sz_simple_types[qmm->type], qmm->id, qmm->array); + package, message, qmm->name, sz_simple_types[qmm->type], qmm->id, qmm->array_size); fprintf(fp, "%4$s *%1$s_%2$s_get_%3$s(struct %1$s_%2$s *%2$s, size_t *count)\n" "{\n" @@ -210,7 +206,7 @@ static void qmi_message_emit_simple_accessors(FILE *fp, " *count = len;\n" " return ptr;\n" "}\n\n", - package, message, qmm->name, sz_simple_types[qmm->type], qmm->id, qmm->array); + package, message, qmm->name, sz_simple_types[qmm->type], qmm->id, qmm->array_size); } else { fprintf(fp, "int %1$s_%2$s_set_%3$s(struct %1$s_%2$s *%2$s, %4$s val)\n" "{\n" @@ -242,7 +238,7 @@ static void qmi_message_emit_string_prototype(FILE *fp, const char *message, struct qmi_message_member *qmm) { - if (qmm->array) { + if (qmm->array_size) { fprintf(stderr, "Dont' know how to encode string arrays yet"); exit(1); } else { @@ -285,15 +281,15 @@ static void qmi_message_emit_string_accessors(FILE *fp, } -void qmi_message_source(FILE *fp, const char *package) +static void qmi_message_source(FILE *fp, const char *package) { struct qmi_message_member *qmm; struct qmi_message *qm; - for (qm = qmi_messages.head; qm; qm = qm->next) { + list_for_each_entry(qm, &qmi_messages, node) { qmi_message_emit_message(fp, package, qm); - for (qmm = qm->members.head; qmm; qmm = qmm->next) + list_for_each_entry(qmm, &qm->members, node) { switch (qmm->type) { case TYPE_U8: case TYPE_U16: @@ -305,26 +301,27 @@ void qmi_message_source(FILE *fp, const char *package) qmi_message_emit_string_accessors(fp, package, qm->name, qmm); break; case TYPE_STRUCT: - qmi_struct_emit_accessors(fp, package, qm->name, qmm->name, qmm->id, qmm->array, qmm->qmi_struct); + qmi_struct_emit_accessors(fp, package, qm->name, qmm->name, qmm->id, qmm->array_size, qmm->qmi_struct); break; }; + } } } -void qmi_message_header(FILE *fp, const char *package) +static void qmi_message_header(FILE *fp, const char *package) { struct qmi_message_member *qmm; struct qmi_message *qm; - for (qm = qmi_messages.head; qm; qm = qm->next) + list_for_each_entry(qm, &qmi_messages, node) qmi_message_emit_message_type(fp, package, qm->name); fprintf(fp, "\n"); - for (qm = qmi_messages.head; qm; qm = qm->next) { + list_for_each_entry(qm, &qmi_messages, node) { qmi_message_emit_message_prototype(fp, package, qm->name); - for (qmm = qm->members.head; qmm; qmm = qmm->next) { + list_for_each_entry(qmm, &qm->members, node) { switch (qmm->type) { case TYPE_U8: case TYPE_U16: @@ -336,9 +333,43 @@ void qmi_message_header(FILE *fp, const char *package) qmi_message_emit_string_prototype(fp, package, qm->name, qmm); break; case TYPE_STRUCT: - qmi_struct_emit_prototype(fp, package, qm->name, qmm->name, qmm->array, qmm->qmi_struct); + qmi_struct_emit_prototype(fp, package, qm->name, qmm->name, qmm->array_size, qmm->qmi_struct); break; }; } } } + +static void emit_header_file_header(FILE *fp) +{ + fprintf(fp, "#include <stdint.h>\n" + "#include <stdlib.h>\n\n"); + fprintf(fp, "struct qmi_tlv;\n" + "\n" + "struct qmi_tlv *qmi_tlv_init(unsigned txn, unsigned msg_id, unsigned type);\n" + "struct qmi_tlv *qmi_tlv_decode(void *buf, size_t len, unsigned *txn, unsigned type);\n" + "void *qmi_tlv_encode(struct qmi_tlv *tlv, size_t *len);\n" + "void qmi_tlv_free(struct qmi_tlv *tlv);\n" + "\n" + "void *qmi_tlv_get(struct qmi_tlv *tlv, unsigned id, size_t *len);\n" + "void *qmi_tlv_get_array(struct qmi_tlv *tlv, unsigned id, unsigned len_size, size_t *len, size_t *size);\n" + "int qmi_tlv_set(struct qmi_tlv *tlv, unsigned id, void *buf, size_t len);\n" + "int qmi_tlv_set_array(struct qmi_tlv *tlv, unsigned id, unsigned len_size, void *buf, size_t len, size_t size);\n" + "\n"); +} + +void accessor_emit_c(FILE *fp, const char *package) +{ + emit_source_includes(fp, package); + qmi_message_source(fp, package); +} + +void accessor_emit_h(FILE *fp, const char *package) +{ + guard_header(fp, qmi_package); + emit_header_file_header(fp); + qmi_const_header(fp); + qmi_struct_header(fp, qmi_package); + qmi_message_header(fp, qmi_package); + guard_footer(fp); +} diff --git a/kernel.c b/kernel.c new file mode 100644 index 0000000..b6127bd --- /dev/null +++ b/kernel.c @@ -0,0 +1,339 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "qmic.h" + +static const char *sz_native_types[] = { + [TYPE_U8] = "uint8_t", + [TYPE_U16] = "uint16_t", + [TYPE_U32] = "uint32_t", + [TYPE_U64] = "uint64_t", +}; + +static const char *sz_data_types[] = { + [TYPE_U8] = "QMI_UNSIGNED_1_BYTE", + [TYPE_U16] = "QMI_UNSIGNED_2_BYTE", + [TYPE_U32] = "QMI_UNSIGNED_4_BYTE", + [TYPE_U64] = "QMI_UNSIGNED_8_BYTE" +}; + +static void emit_struct_definition(FILE *fp, const char *package, + struct qmi_struct *qs) +{ + struct qmi_struct_member *qsm; + + fprintf(fp, "struct %s_%s {\n", package, qs->name); + + list_for_each_entry(qsm, &qs->members, node) { + switch (qsm->type) { + case TYPE_U8: + case TYPE_U16: + case TYPE_U32: + case TYPE_U64: + fprintf(fp, "\t%s %s;\n", sz_native_types[qsm->type], qsm->name); + break; + } + } + + fprintf(fp, "};\n"); + fprintf(fp, "\n"); +} + +static void emit_struct_native_ei(FILE *fp, const char *package, + struct qmi_struct *qs, + struct qmi_struct_member *qsm) +{ + fprintf(fp, "\t{\n" + "\t\t.data_type = %4$s,\n" + "\t\t.elem_len = 1,\n" + "\t\t.elem_size = sizeof(%5$s),\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s),\n" + "\t},\n", + package, qs->name, qsm->name, + sz_data_types[qsm->type], sz_native_types[qsm->type]); +} + +static void emit_struct_ei(FILE *fp, const char *package, struct qmi_struct *qs) +{ + struct qmi_struct_member *qsm; + + fprintf(fp, "struct qmi_elem_info %s_%s_ei[] = {\n", package, qs->name); + + list_for_each_entry(qsm, &qs->members, node) { + switch (qsm->type) { + case TYPE_U8: + case TYPE_U16: + case TYPE_U32: + case TYPE_U64: + emit_struct_native_ei(fp, package, qs, qsm); + break; + } + } + + fprintf(fp, "\t{}\n"); + fprintf(fp, "};\n"); + fprintf(fp, "\n"); +} + +static void emit_native_type(FILE *fp, const char *package, struct qmi_message *qm, + struct qmi_message_member *qmm) +{ + static const char *sz_types[] = { + [TYPE_U8] = "uint8_t", + [TYPE_U16] = "uint16_t", + [TYPE_U32] = "uint32_t", + [TYPE_U64] = "uint64_t", + }; + + if (!qmm->required) + fprintf(fp, "\tbool %s_valid;\n", qmm->name); + + if (qmm->array_size) { + fprintf(fp, "\tuint32_t %s_len;\n", qmm->name); + fprintf(fp, "\t%s %s[%d];\n", sz_types[qmm->type], + qmm->name, qmm->array_size); + } else { + fprintf(fp, "\t%s %s;\n", sz_types[qmm->type], + qmm->name); + } +} + +static void emit_struct_type(FILE *fp, const char *package, struct qmi_message *qm, + struct qmi_message_member *qmm) +{ + struct qmi_struct *qs = qmm->qmi_struct; + if (!qmm->required) + fprintf(fp, "\tbool %s_valid;\n", qmm->name); + + if (qmm->array_size) { + fprintf(fp, "\tuint32_t %s_len;\n", qmm->name); + fprintf(fp, "\tstruct %s_%s %s[%d];\n", package, qs->name, + qmm->name, qmm->array_size); + } else { + fprintf(fp, "\tstruct %s_%s %s;\n", package, qs->name, qmm->name); + } +} + +static void emit_msg_struct(FILE *fp, const char *package, struct qmi_message *qm) +{ + struct qmi_message_member *qmm; + + fprintf(fp, "struct %1$s_%2$s {\n", package, qm->name); + + list_for_each_entry(qmm, &qm->members, node) { + switch (qmm->type) { + case TYPE_U8: + case TYPE_U16: + case TYPE_U32: + case TYPE_U64: + emit_native_type(fp, package, qm, qmm); + break; + case TYPE_STRING: + fprintf(fp, "\tuint32_t %s_len;\n", qmm->name); + fprintf(fp, "\tchar %s[256];\n", qmm->name); + break; + case TYPE_STRUCT: + emit_struct_type(fp, package, qm, qmm); + break; + } + } + + fprintf(fp, "};\n"); + fprintf(fp, "\n"); +} + +static void emit_native_ei(FILE *fp, const char *package, struct qmi_message *qm, + struct qmi_message_member *qmm) +{ + if (!qmm->required) { + fprintf(fp, "\t{\n" + "\t\t.data_type = QMI_OPT_FLAG,\n" + "\t\t.elem_len = 1,\n" + "\t\t.elem_size = sizeof(bool),\n" + "\t\t.tlv_type = %4$d,\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s_valid),\n" + "\t},\n", + package, qm->name, qmm->name, qmm->id); + } + + if (qmm->array_fixed) { + fprintf(fp, "\t{\n" + "\t\t.data_type = QMI_UNSIGNED_1_BYTE,\n" + "\t\t.elem_len = %5$d,\n" + "\t\t.elem_size = sizeof(%6$s),\n" + "\t\t.array_type = STATIC_ARRAY,\n" + "\t\t.tlv_type = %4$d,\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s),\n" + "\t},\n", + package, qm->name, qmm->name, qmm->id, qmm->array_size, + sz_native_types[qmm->type]); + } else if (qmm->array_size) { + fprintf(fp, "\t{\n" + "\t\t.data_type = QMI_DATA_LEN,\n" + "\t\t.elem_len = 1,\n" + "\t\t.elem_size = sizeof(%5$s),\n" + "\t\t.tlv_type = %4$d,\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s_len),\n" + "\t},\n", + package, qm->name, qmm->name, qmm->id, + qmm->array_size >= 256 ? "uint16_t" : "uint8_t"); + fprintf(fp, "\t{\n" + "\t\t.data_type = QMI_UNSIGNED_1_BYTE,\n" + "\t\t.elem_len = %5$d,\n" + "\t\t.elem_size = sizeof(%6$s),\n" + "\t\t.array_type = VAR_LEN_ARRAY,\n" + "\t\t.tlv_type = %4$d,\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s),\n" + "\t},\n", + package, qm->name, qmm->name, qmm->id, qmm->array_size, + sz_native_types[qmm->type]); + } else { + fprintf(fp, "\t{\n" + "\t\t.data_type = %5$s,\n" + "\t\t.elem_len = 1,\n" + "\t\t.elem_size = sizeof(%6$s),\n" + "\t\t.tlv_type = %4$d,\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s),\n" + "\t},\n", + package, qm->name, qmm->name, qmm->id, + sz_data_types[qmm->type], + sz_native_types[qmm->type]); + } +} + +static void emit_struct_ref_ei(FILE *fp, const char *package, struct qmi_message *qm, + struct qmi_message_member *qmm) +{ + struct qmi_struct *qs = qmm->qmi_struct; + + if (!qmm->required) { + fprintf(fp, "\t{\n" + "\t\t.data_type = QMI_OPT_FLAG,\n" + "\t\t.elem_len = 1,\n" + "\t\t.elem_size = sizeof(bool),\n" + "\t\t.tlv_type = %4$d,\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s_valid),\n" + "\t},\n", + package, qm->name, qmm->name, qmm->id); + } + + if (qmm->array_size) { + fprintf(fp, "\t{\n" + "\t\t.data_type = QMI_DATA_LEN,\n" + "\t\t.elem_len = 1,\n" + "\t\t.elem_size = sizeof(%5$s),\n" + "\t\t.tlv_type = %4$d,\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s_len),\n" + "\t},\n", + package, qm->name, qmm->name, qmm->id, + qmm->array_size >= 256 ? "uint16_t" : "uint8_t"); + + fprintf(fp, "\t{\n" + "\t\t.data_type = QMI_STRUCT,\n" + "\t\t.elem_len = %6$d,\n" + "\t\t.elem_size = sizeof(struct %1$s_%5$s),\n" + "\t\t.array_type = VAR_LEN_ARRAY,\n" + "\t\t.tlv_type = %4$d,\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s),\n" + "\t\t.ei_array = %1$s_%5$s_ei,\n" + "\t},\n", + package, qm->name, qmm->name, qmm->id, qs->name, qmm->array_size); + } else { + fprintf(fp, "\t{\n" + "\t\t.data_type = QMI_STRUCT,\n" + "\t\t.elem_len = 1,\n" + "\t\t.elem_size = sizeof(struct %1$s_%5$s),\n" + "\t\t.tlv_type = %4$d,\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s),\n" + "\t\t.ei_array = %1$s_%5$s_ei,\n" + "\t},\n", + package, qm->name, qmm->name, qmm->id, qs->name); + } +} + +static void emit_elem_info_array_decl(FILE *fp, const char *package, struct qmi_message *qm) +{ + fprintf(fp, "extern struct qmi_elem_info %1$s_%2$s_ei[];\n", + package, qm->name); +} + +static void emit_elem_info_array(FILE *fp, const char *package, struct qmi_message *qm) +{ + struct qmi_message_member *qmm; + + fprintf(fp, "struct qmi_elem_info %1$s_%2$s_ei[] = {\n", + package, qm->name); + + list_for_each_entry(qmm, &qm->members, node) { + switch (qmm->type) { + case TYPE_U8: + case TYPE_U16: + case TYPE_U32: + case TYPE_U64: + emit_native_ei(fp, package, qm, qmm); + break; + case TYPE_STRUCT: + emit_struct_ref_ei(fp, package, qm, qmm); + break; + case TYPE_STRING: + fprintf(fp, "\t{\n" + "\t\t.data_type = QMI_STRING,\n" + "\t\t.elem_len = 256,\n" + "\t\t.elem_size = sizeof(char),\n" + "\t\t.array_type = VAR_LEN_ARRAY,\n" + "\t\t.tlv_type = %4$d,\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s)\n" + "\t},\n", + package, qm->name, qmm->name, qmm->id); + break; + } + } + fprintf(fp, "\t{}\n"); + fprintf(fp, "};\n"); + fprintf(fp, "\n"); +} + +static void emit_h_file_header(FILE *fp) +{ + fprintf(fp, "#include <stdint.h>\n" + "#include <stdbool.h>\n" + "\n" + "#include \"libqrtr.h\"\n" + "\n"); +}; + +void kernel_emit_c(FILE *fp, const char *package) +{ + struct qmi_message *qm; + struct qmi_struct *qs; + + emit_source_includes(fp, package); + + list_for_each_entry(qs, &qmi_structs, node) + emit_struct_ei(fp, package, qs); + + list_for_each_entry(qm, &qmi_messages, node) + emit_elem_info_array(fp, package, qm); +} + +void kernel_emit_h(FILE *fp, const char *package) +{ + struct qmi_message *qm; + struct qmi_struct *qs; + + guard_header(fp, package); + emit_h_file_header(fp); + qmi_const_header(fp); + + list_for_each_entry(qs, &qmi_structs, node) + emit_struct_definition(fp, package, qs); + + list_for_each_entry(qm, &qmi_messages, node) + emit_msg_struct(fp, package, qm); + + list_for_each_entry(qm, &qmi_messages, node) + emit_elem_info_array_decl(fp, package, qm); + fprintf(fp, "\n"); + + guard_footer(fp); +} @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2016, Linaro Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __LIST_H__ +#define __LIST_H__ + +#include <stdbool.h> +#include <stddef.h> + +#define container_of(ptr, type, member) ({ \ + const typeof(((type *)0)->member)*__mptr = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); \ + }) + +struct list_head { + struct list_head *prev; + struct list_head *next; +}; + +#define LIST_INIT(list) { &(list), &(list) } + +static inline void list_init(struct list_head *list) +{ + list->prev = list->next = list; +} + +static inline bool list_empty(struct list_head *list) +{ + return list->next == list; +} + +static inline void list_add(struct list_head *list, struct list_head *item) +{ + struct list_head *prev = list->prev; + + item->next = list; + item->prev = prev; + + prev->next = list->prev = item; +} + +static inline void list_del(struct list_head *item) +{ + item->prev->next = item->next; + item->next->prev = item->prev; +} + +#define list_for_each(item, list) \ + for (item = (list)->next; item != list; item = item->next) + +#define list_for_each_safe(item, next, list) \ + for (item = (list)->next, next = item->next; item != list; item = next, next = item->next) + +#define list_entry(item, type, member) \ + container_of(item, type, member) + +#define list_entry_first(list, type, member) \ + container_of((list)->next, type, member) + +#define list_entry_next(item, member) \ + container_of((item)->member.next, typeof(*(item)), member) + +#define list_for_each_entry(item, list, member) \ + for (item = list_entry_first(list, typeof(*(item)), member); \ + &item->member != list; \ + item = list_entry_next(item, member)) + +#endif diff --git a/parser.c b/parser.c new file mode 100644 index 0000000..4378ced --- /dev/null +++ b/parser.c @@ -0,0 +1,422 @@ +#include <assert.h> +#include <ctype.h> +#include <err.h> +#include <fcntl.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <stdbool.h> +#include <stdlib.h> +#include <unistd.h> + +#include "list.h" +#include "qmic.h" + +const char *qmi_package; + +struct list_head qmi_consts = LIST_INIT(qmi_consts); +struct list_head qmi_messages = LIST_INIT(qmi_messages); +struct list_head qmi_structs = LIST_INIT(qmi_structs); + +enum { + TOK_CONST = 256, + TOK_ID, + TOK_MESSAGE, + TOK_NUM, + TOK_PACKAGE, + TOK_STRUCT, + TOK_TYPE, + TOK_REQUIRED, + TOK_OPTIONAL, +}; + +struct token { + int id; + const char *str; + unsigned num; + struct qmi_struct *qmi_struct; +}; + +static char scratch_buf[128]; +static int scratch_pos; + +static int yyline = 1; + +static int input() +{ + static char input_buf[128]; + static int input_pos; + static int input_len; + int ret; + int ch; + + if (scratch_pos) { + ch = scratch_buf[--scratch_pos]; + goto out; + } + + if (input_pos < input_len) { + ch = input_buf[input_pos++]; + goto out; + } + + ret = read(0, input_buf, sizeof(input_buf)); + if (ret <= 0) + return ret; + + input_pos = 0; + input_len = ret; + + ch = input_buf[input_pos++]; +out: + if (ch == '\n') + yyline++; + return ch; +} + +static void unput(int ch) +{ + assert(scratch_pos < 128); + scratch_buf[scratch_pos++] = ch; + + if (ch == '\n') + yyline--; +} + +struct symbol { + int token; + const char *name; + + int type; + struct qmi_struct *qmi_struct; + + struct list_head node; +}; + +static struct list_head symbols = LIST_INIT(symbols); + +static void symbol_add(const char *name, int token, ...) +{ + struct symbol *sym; + va_list ap; + + va_start(ap, token); + + sym = malloc(sizeof(struct symbol)); + sym->token = token; + sym->name = name; + + switch (token) { + case TOK_MESSAGE: + sym->type = va_arg(ap, int); + break; + case TOK_TYPE: + sym->type = va_arg(ap, int); + if (sym->type == TYPE_STRUCT) + sym->qmi_struct = va_arg(ap, struct qmi_struct *); + break; + } + + list_add(&symbols, &sym->node); + + va_end(ap); +} + +static struct token yylex() +{ + struct symbol *sym; + struct token token = {}; + char buf[128]; + char *p = buf; + int base; + int ch; + + list_for_each_entry(sym, &symbols, node); + + while ((ch = input()) && isspace(ch)) + ; + + if (isalpha(ch)) { + do { + *p++ = ch; + ch = input(); + } while (isalnum(ch) || ch == '_'); + unput(ch); + *p = '\0'; + + token.str = strdup(buf); + list_for_each_entry(sym, &symbols, node) { + if (strcmp(buf, sym->name) == 0) { + token.id = sym->token; + token.num = sym->type; + token.qmi_struct = sym->qmi_struct; + return token; + } + } + + token.id = TOK_ID; + + return token; + } else if (isdigit(ch)) { + do { + *p++ = ch; + ch = input(); + } while (isdigit(ch) || (p - buf == 1 && ch == 'x')); + unput(ch); + *p = '\0'; + + if (buf[0] == '0' && buf[1] == 'x') + base = 16; + else if (buf[0] == '0') + base = 8; + else + base = 10; + + token.id = TOK_NUM; + token.num = strtol(buf, NULL, base); + return token; + } + + token.id = ch; + return token; +} + +static struct token curr_token; + +static void yyerror(const char *fmt, ...) +{ + char buf[128]; + va_list ap; + + va_start(ap, fmt); + + vsprintf(buf, fmt, ap); + printf("parse error on line %d: %s\n", yyline, buf); + + va_end(ap); + exit(1); +} + +static void token_init(void) +{ + curr_token = yylex(); +} + +static int token_accept(int id, struct token *tok) +{ + if (curr_token.id == id) { + if (tok) + *tok = curr_token; + + curr_token = yylex(); + return 1; + } else { + return 0; + } +} + +static void token_expect(int id, struct token *tok) +{ + if (!token_accept(id, tok)) { + switch (id) { + case TOK_CONST: + yyerror("expected const"); + case TOK_ID: + yyerror("expected identifier"); + case TOK_MESSAGE: + yyerror("expected message"); + case TOK_NUM: + yyerror("expected num"); + case TOK_PACKAGE: + yyerror("expected package"); + case TOK_STRUCT: + yyerror("expected struct"); + case TOK_TYPE: + yyerror("expected type"); + case TOK_REQUIRED: + yyerror("expected required"); + case TOK_OPTIONAL: + yyerror("expected optional"); + default: + yyerror("expected '%c'", id); + } + } +} + +static const char *parse_package() +{ + struct token tok; + + if (!token_accept(TOK_ID, &tok)) + yyerror("expected identifier"); + + token_expect(';', NULL); + return tok.str; +} + +static void qmi_const_parse() +{ + struct qmi_const *qc; + struct token num_tok; + struct token id_tok; + + token_expect(TOK_ID, &id_tok); + token_expect('=', NULL); + token_expect(TOK_NUM, &num_tok); + token_expect(';', NULL); + + qc = malloc(sizeof(struct qmi_const)); + qc->name = id_tok.str; + qc->value = num_tok.num; + + list_add(&qmi_consts, &qc->node); +} + +static void qmi_message_parse(enum message_type message_type) +{ + struct qmi_message_member *qmm; + struct qmi_message *qm; + struct token msg_id_tok; + struct token type_tok; + struct token num_tok; + struct token id_tok; + unsigned int array_size; + bool array_fixed = false; + bool required; + + token_expect(TOK_ID, &msg_id_tok); + token_expect('{', NULL); + + qm = calloc(1, sizeof(struct qmi_message)); + qm->name = msg_id_tok.str; + qm->type = message_type; + list_init(&qm->members); + + while (!token_accept('}', NULL)) { + if (token_accept(TOK_REQUIRED, NULL)) + required = true; + else if (token_accept(TOK_OPTIONAL, NULL)) + required = false; + else + yyerror("expected required, optional or '}'"); + + token_expect(TOK_TYPE, &type_tok); + token_expect(TOK_ID, &id_tok); + + if (token_accept('[', NULL)) { + token_expect(TOK_NUM, &num_tok); + array_size = num_tok.num; + token_expect(']', NULL); + + array_fixed = true; + } else if(token_accept('(', NULL)) { + token_expect(TOK_NUM, &num_tok); + array_size = num_tok.num; + token_expect(')', NULL); + } else { + array_size = 0; + } + + token_expect('=', NULL); + token_expect(TOK_NUM, &num_tok); + token_expect(';', NULL); + + qmm = calloc(1, sizeof(struct qmi_message_member)); + qmm->name = id_tok.str; + qmm->type = type_tok.num; + qmm->qmi_struct = type_tok.qmi_struct; + qmm->id = num_tok.num; + qmm->required = required; + qmm->array_size = array_size; + qmm->array_fixed = array_fixed; + + list_add(&qm->members, &qmm->node); + } + + if (token_accept('=', NULL)) { + token_expect(TOK_NUM, &num_tok); + + qm->msg_id = num_tok.num; + } + + token_expect(';', NULL); + + list_add(&qmi_messages, &qm->node); +} + +static void qmi_struct_parse(void) +{ + struct qmi_struct_member *qsm; + struct token struct_id_tok; + struct qmi_struct *qs; + struct token type_tok; + struct token id_tok; + + token_expect(TOK_ID, &struct_id_tok); + token_expect('{', NULL); + + qs = malloc(sizeof(struct qmi_struct)); + qs->name = struct_id_tok.str; + list_init(&qs->members); + + while (token_accept(TOK_TYPE, &type_tok)) { + token_expect(TOK_ID, &id_tok); + token_expect(';', NULL); + + qsm = malloc(sizeof(struct qmi_struct_member)); + qsm->name = id_tok.str; + qsm->type = type_tok.num; + + list_add(&qs->members, &qsm->node); + } + + token_expect('}', NULL); + token_expect(';', NULL); + + list_add(&qmi_structs, &qs->node); + + symbol_add(qs->name, TOK_TYPE, TYPE_STRUCT, qs); +} + +void qmi_parse(void) +{ + struct token tok; + + /* PACKAGE ID<string> ';' */ + /* CONST ID<string> '=' NUM<num> ';' */ + /* STRUCT ID<string> '{' ... '}' ';' */ + /* TYPE<type*> ID<string> ';' */ + /* MESSAGE ID<string> '{' ... '}' ';' */ + /* (REQUIRED | OPTIONAL) TYPE<type*> ID<string> '=' NUM<num> ';' */ + + symbol_add("const", TOK_CONST); + symbol_add("optional", TOK_OPTIONAL); + symbol_add("message", TOK_MESSAGE, MESSAGE_RESPONSE); /* backward compatible with early hacking */ + symbol_add("request", TOK_MESSAGE, MESSAGE_REQUEST); + symbol_add("response", TOK_MESSAGE, MESSAGE_RESPONSE); + symbol_add("indication", TOK_MESSAGE, MESSAGE_INDICATION); + symbol_add("package", TOK_PACKAGE); + symbol_add("required", TOK_REQUIRED); + symbol_add("struct", TOK_STRUCT); + symbol_add("string", TOK_TYPE, TYPE_STRING); + symbol_add("u8", TOK_TYPE, TYPE_U8); + symbol_add("u16", TOK_TYPE, TYPE_U16); + symbol_add("u32", TOK_TYPE, TYPE_U32); + symbol_add("u64", TOK_TYPE, TYPE_U64); + + token_init(); + while (!token_accept(0, NULL)) { + if (token_accept(TOK_PACKAGE, NULL)) { + qmi_package = parse_package(); + } else if (token_accept(TOK_CONST, NULL)) { + qmi_const_parse(); + } else if (token_accept(TOK_STRUCT, NULL)) { + qmi_struct_parse(); + } else if (token_accept(TOK_MESSAGE, &tok)) { + qmi_message_parse(tok.num); + } else { + yyerror("unexpected symbol"); + break; + } + } +} diff --git a/qmi_struct.c b/qmi_struct.c deleted file mode 100644 index ffa9dbf..0000000 --- a/qmi_struct.c +++ /dev/null @@ -1,157 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include "qmic.h" - -static const char *sz_simple_types[] = { - [TYPE_U8] = "uint8_t", - [TYPE_U16] = "uint16_t", - [TYPE_U32] = "uint32_t", - [TYPE_U64] = "uint64_t", - [TYPE_STRING] = "char *", -}; - -struct qmi_struct_member { - const char *name; - int type; - - struct qmi_struct_member *next; -}; - -struct qmi_struct { - const char *name; - - struct qmi_struct *next; - - LIST_HEAD(qmi_struct_member, members); -}; - -LIST_HEAD(qmi_struct, qmi_structs); - -void qmi_struct_parse(void) -{ - struct qmi_struct_member *qsm; - struct token struct_id_tok; - struct qmi_struct *qs; - struct token type_tok; - struct token id_tok; - - token_expect(TOK_ID, &struct_id_tok); - token_expect('{', NULL); - - qs = malloc(sizeof(struct qmi_struct)); - qs->name = struct_id_tok.str; - - while (token_accept(TOK_TYPE, &type_tok)) { - token_expect(TOK_ID, &id_tok); - token_expect(';', NULL); - - qsm = malloc(sizeof(struct qmi_struct_member)); - qsm->name = id_tok.str; - qsm->type = type_tok.num; - - LIST_ADD(qs->members, qsm); - } - - token_expect('}', NULL); - token_expect(';', NULL); - - LIST_ADD(qmi_structs, qs); - - symbol_add(qs->name, TOK_TYPE, TYPE_STRUCT, qs); -} - -void qmi_struct_header(FILE *fp, const char *package) -{ - struct qmi_struct_member *qsm; - struct qmi_struct *qs; - - for (qs = qmi_structs.head; qs; qs = qs->next) { - fprintf(fp, "struct %s_%s {\n", - package, qs->name); - for (qsm = qs->members.head; qsm; qsm = qsm->next) { - fprintf(fp, "\t%s %s;\n", - sz_simple_types[qsm->type], qsm->name); - } - fprintf(fp, "};\n" - "\n"); - } -} - -void qmi_struct_emit_prototype(FILE *fp, - const char *package, - const char *message, - const char *member, - unsigned array_size, - struct qmi_struct *qs) -{ - if (array_size) { - fprintf(fp, "int %1$s_%2$s_set_%3$s(struct %1$s_%2$s *%2$s, struct %1$s_%4$s *val, size_t count);\n", - package, message, member, qs->name); - - fprintf(fp, "struct %1$s_%4$s *%1$s_%2$s_get_%3$s(struct %1$s_%2$s *%2$s, size_t *count);\n\n", - package, message, member, qs->name); - } else { - fprintf(fp, "int %1$s_%2$s_set_%3$s(struct %1$s_%2$s *%2$s, struct %1$s_%4$s *val);\n", - package, message, member, qs->name); - - fprintf(fp, "struct %1$s_%4$s *%1$s_%2$s_get_%3$s(struct %1$s_%2$s *%2$s);\n\n", - package, message, member, qs->name); - } -} - -void qmi_struct_emit_accessors(FILE *fp, - const char *package, - const char *message, - const char *member, - int member_id, - unsigned array_size, - struct qmi_struct *qs) -{ - if (array_size) { - fprintf(fp, "int %1$s_%2$s_set_%3$s(struct %1$s_%2$s *%2$s, struct %1$s_%4$s *val, size_t count)\n" - "{\n" - " return qmi_tlv_set_array((struct qmi_tlv*)%2$s, %5$d, %6$d, val, count, sizeof(struct %1$s_%4$s));\n" - "}\n\n", - package, message, member, qs->name, member_id, array_size); - - fprintf(fp, "struct %1$s_%4$s *%1$s_%2$s_get_%3$s(struct %1$s_%2$s *%2$s, size_t *count)\n" - "{\n" - " size_t size;\n" - " size_t len;\n" - " void *ptr;\n" - "\n" - " ptr = qmi_tlv_get_array((struct qmi_tlv*)%2$s, %5$d, %6$d, &len, &size);\n" - " if (!ptr)\n" - " return NULL;\n" - "\n" - " if (size != sizeof(struct %1$s_%4$s))\n" - " return NULL;\n" - "\n" - " *count = len;\n" - " return ptr;\n" - "}\n\n", - package, message, member, qs->name, member_id, array_size); - } else { - fprintf(fp, "int %1$s_%2$s_set_%3$s(struct %1$s_%2$s *%2$s, struct %1$s_%4$s *val)\n" - "{\n" - " return qmi_tlv_set((struct qmi_tlv*)%2$s, %5$d, val, sizeof(struct %1$s_%4$s));\n" - "}\n\n", - package, message, member, qs->name, member_id); - - fprintf(fp, "struct %1$s_%4$s *%1$s_%2$s_get_%3$s(struct %1$s_%2$s *%2$s)\n" - "{\n" - " size_t len;\n" - " void *ptr;\n" - "\n" - " ptr = qmi_tlv_get((struct qmi_tlv*)%2$s, %5$d, &len);\n" - " if (!ptr)\n" - " return NULL;\n" - "\n" - " if (len != sizeof(struct %1$s_%4$s))\n" - " return NULL;\n" - "\n" - " return ptr;\n" - "}\n\n", - package, message, member, qs->name, member_id); - } -} @@ -9,268 +9,39 @@ #include <stdlib.h> #include <unistd.h> +#include "list.h" #include "qmic.h" -#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) - -static char scratch_buf[128]; -static int scratch_pos; - -static int yyline = 1; - -static int input() -{ - static char input_buf[128]; - static int input_pos; - static int input_len; - int ret; - int ch; - - if (scratch_pos) { - ch = scratch_buf[--scratch_pos]; - goto out; - } - - if (input_pos < input_len) { - ch = input_buf[input_pos++]; - goto out; - } - - ret = read(0, input_buf, sizeof(input_buf)); - if (ret <= 0) - return ret; - - input_pos = 0; - input_len = ret; - - ch = input_buf[input_pos++]; -out: - if (ch == '\n') - yyline++; - return ch; -} - -static void unput(int ch) -{ - assert(scratch_pos < 128); - scratch_buf[scratch_pos++] = ch; - - if (ch == '\n') - yyline--; -} - -struct symbol { - int token; - const char *name; - - int type; - struct qmi_struct *qmi_struct; - - struct symbol *next; +const char *sz_simple_types[] = { + [TYPE_U8] = "uint8_t", + [TYPE_U16] = "uint16_t", + [TYPE_U32] = "uint32_t", + [TYPE_U64] = "uint64_t", + [TYPE_STRING] = "char *", }; -LIST_HEAD(symbol, symbols); - -void symbol_add(const char *name, int token, ...) -{ - struct symbol *sym; - va_list ap; - - va_start(ap, token); - - sym = malloc(sizeof(struct symbol)); - sym->token = token; - sym->name = name; - sym->next = NULL; - - switch (token) { - case TOK_MESSAGE: - sym->type = va_arg(ap, int); - break; - case TOK_TYPE: - sym->type = va_arg(ap, int); - if (sym->type == TYPE_STRUCT) - sym->qmi_struct = va_arg(ap, struct qmi_struct *); - break; - } - - LIST_ADD(symbols, sym); - - va_end(ap); -} - -static struct token yylex() -{ - struct symbol *sym; - struct token token = {}; - char buf[128]; - char *p = buf; - int base; - int ch; - - while ((ch = input()) && isspace(ch)) - ; - - if (isalpha(ch)) { - do { - *p++ = ch; - ch = input(); - } while (isalnum(ch) || ch == '_'); - unput(ch); - *p = '\0'; - - token.str = strdup(buf); - for (sym = symbols.head; sym; sym = sym->next) { - if (strcmp(buf, sym->name) == 0) { - token.id = sym->token; - token.num = sym->type; - token.qmi_struct = sym->qmi_struct; - break; - } - } - - if (!sym) - token.id = TOK_ID; - - return token; - } else if (isdigit(ch)) { - do { - *p++ = ch; - ch = input(); - } while (isdigit(ch) || (p - buf == 1 && ch == 'x')); - unput(ch); - *p = '\0'; - - if (buf[0] == '0' && buf[1] == 'x') - base = 16; - else if (buf[0] == '0') - base = 8; - else - base = 10; - - token.id = TOK_NUM; - token.num = strtol(buf, NULL, base); - return token; - } - - token.id = ch; - return token; -} - -static struct token curr_token; - -void yyerror(const char *fmt, ...) -{ - char buf[128]; - va_list ap; - - va_start(ap, fmt); - - vsprintf(buf, fmt, ap); - printf("parse error on line %d: %s\n", yyline, buf); - - va_end(ap); - exit(1); -} - -static void token_init(void) -{ - curr_token = yylex(); -} - -int token_accept(int id, struct token *tok) -{ - if (curr_token.id == id) { - if (tok) - *tok = curr_token; - - curr_token = yylex(); - return 1; - } else { - return 0; - } -} - -void token_expect(int id, struct token *tok) -{ - if (!token_accept(id, tok)) { - switch (id) { - case TOK_CONST: - yyerror("expected const"); - case TOK_ID: - yyerror("expected identifier"); - case TOK_MESSAGE: - yyerror("expected message"); - case TOK_NUM: - yyerror("expected num"); - case TOK_PACKAGE: - yyerror("expected package"); - case TOK_STRUCT: - yyerror("expected struct"); - case TOK_TYPE: - yyerror("expected type"); - case TOK_REQUIRED: - yyerror("expected required"); - case TOK_OPTIONAL: - yyerror("expected optional"); - default: - yyerror("expected '%c'", id); - } - } -} - -static const char *parse_package() -{ - struct token tok; - - if (!token_accept(TOK_ID, &tok)) - yyerror("expected identifier"); - - token_expect(';', NULL); - return tok.str; -} - - -struct qmi_const { - const char *name; - unsigned value; - - struct qmi_const *next; -}; - -LIST_HEAD(qmi_const, qmi_consts); - -static void qmi_const_parse() -{ - struct qmi_const *qc; - struct token num_tok; - struct token id_tok; - - token_expect(TOK_ID, &id_tok); - token_expect('=', NULL); - token_expect(TOK_NUM, &num_tok); - token_expect(';', NULL); - - qc = malloc(sizeof(struct qmi_const)); - qc->name = id_tok.str; - qc->value = num_tok.num; - LIST_ADD(qmi_consts, qc); -} - -static void qmi_const_header(FILE *fp) +void qmi_const_header(FILE *fp) { struct qmi_const *qc; - if (!qmi_consts.head) + if (list_empty(&qmi_consts)) return; - for (qc = qmi_consts.head; qc; qc = qc->next) + list_for_each_entry(qc, &qmi_consts, node) fprintf(fp, "#define %s %d\n", qc->name, qc->value); fprintf(fp, "\n"); } -static void guard_header(FILE *fp, const char *package) +void emit_source_includes(FILE *fp, const char *package) +{ + fprintf(fp, "#include <errno.h>\n" + "#include <string.h>\n" + "#include \"qmi_%1$s.h\"\n\n", + package); +} + +void guard_header(FILE *fp, const char *package) { char *upper; char *p; @@ -286,92 +57,62 @@ static void guard_header(FILE *fp, const char *package) fprintf(fp, "\n"); } -static void guard_footer(FILE *fp) +void guard_footer(FILE *fp) { fprintf(fp, "#endif\n"); } +static void usage(void) +{ + extern const char *__progname; + + fprintf(stderr, "Usage: %s [-ak]\n", __progname); + exit(1); +} + int main(int argc, char **argv) { - const char *package = NULL; - struct token tok; char fname[256]; FILE *hfp; FILE *sfp; + int method = 0; + int opt; - /* PACKAGE ID<string> ';' */ - /* CONST ID<string> '=' NUM<num> ';' */ - /* STRUCT ID<string> '{' ... '}' ';' */ - /* TYPE<type*> ID<string> ';' */ - /* MESSAGE ID<string> '{' ... '}' ';' */ - /* (REQUIRED | OPTIONAL) TYPE<type*> ID<string> '=' NUM<num> ';' */ - - symbol_add("const", TOK_CONST); - symbol_add("optional", TOK_OPTIONAL); - symbol_add("message", TOK_MESSAGE, MESSAGE_RESPONSE); /* backward compatible with early hacking */ - symbol_add("request", TOK_MESSAGE, MESSAGE_REQUEST); - symbol_add("response", TOK_MESSAGE, MESSAGE_RESPONSE); - symbol_add("indication", TOK_MESSAGE, MESSAGE_INDICATION); - symbol_add("package", TOK_PACKAGE); - symbol_add("required", TOK_REQUIRED); - symbol_add("struct", TOK_STRUCT); - symbol_add("string", TOK_TYPE, TYPE_STRING); - symbol_add("u8", TOK_TYPE, TYPE_U8); - symbol_add("u16", TOK_TYPE, TYPE_U16); - symbol_add("u32", TOK_TYPE, TYPE_U32); - symbol_add("u64", TOK_TYPE, TYPE_U64); - - token_init(); - while (!token_accept(0, NULL)) { - if (token_accept(TOK_PACKAGE, NULL)) { - package = parse_package(); - } else if (token_accept(TOK_CONST, NULL)) { - qmi_const_parse(); - } else if (token_accept(TOK_STRUCT, NULL)) { - qmi_struct_parse(); - } else if (token_accept(TOK_MESSAGE, &tok)) { - qmi_message_parse(tok.num); - } else { - yyerror("unexpected symbol"); + while ((opt = getopt(argc, argv, "ak")) != -1) { + switch (opt) { + case 'a': + method = 0; + break; + case 'k': + method = 1; break; + default: + usage(); } } - snprintf(fname, sizeof(fname), "qmi_%s.c", package); + qmi_parse(); + + snprintf(fname, sizeof(fname), "qmi_%s.c", qmi_package); sfp = fopen(fname, "w"); if (!sfp) err(1, "failed to open %s", fname); - snprintf(fname, sizeof(fname), "qmi_%s.h", package); + snprintf(fname, sizeof(fname), "qmi_%s.h", qmi_package); hfp = fopen(fname, "w"); if (!hfp) err(1, "failed to open %s", fname); - fprintf(sfp, "#include <errno.h>\n" - "#include <string.h>\n" - "#include \"qmi_%1$s.h\"\n\n", - package); - qmi_message_source(sfp, package); - - guard_header(hfp, package); - fprintf(hfp, "#include <stdint.h>\n" - "#include <stdlib.h>\n\n"); - fprintf(hfp, "struct qmi_tlv;\n" - "\n" - "struct qmi_tlv *qmi_tlv_init(unsigned txn, unsigned msg_id, unsigned type);\n" - "struct qmi_tlv *qmi_tlv_decode(void *buf, size_t len, unsigned *txn, unsigned type);\n" - "void *qmi_tlv_encode(struct qmi_tlv *tlv, size_t *len);\n" - "void qmi_tlv_free(struct qmi_tlv *tlv);\n" - "\n" - "void *qmi_tlv_get(struct qmi_tlv *tlv, unsigned id, size_t *len);\n" - "void *qmi_tlv_get_array(struct qmi_tlv *tlv, unsigned id, unsigned len_size, size_t *len, size_t *size);\n" - "int qmi_tlv_set(struct qmi_tlv *tlv, unsigned id, void *buf, size_t len);\n" - "int qmi_tlv_set_array(struct qmi_tlv *tlv, unsigned id, unsigned len_size, void *buf, size_t len, size_t size);\n" - "\n"); - qmi_const_header(hfp); - qmi_struct_header(hfp, package); - qmi_message_header(hfp, package); - guard_footer(hfp); + switch (method) { + case 0: + accessor_emit_c(sfp, qmi_package); + accessor_emit_h(hfp, qmi_package); + break; + case 1: + kernel_emit_c(sfp, qmi_package); + kernel_emit_h(hfp, qmi_package); + break; + } fclose(hfp); fclose(sfp); @@ -3,32 +3,9 @@ #include <stdbool.h> -#define LIST_HEAD(type, name) \ -struct { \ - struct type *head; \ - struct type *tail; \ -} name; - -#define LIST_ADD(list, elem) \ - if (list.tail) { \ - list.tail->next = elem; \ - list.tail = elem; \ - } else { \ - list.tail = elem; \ - list.head = elem; \ - } +#include "list.h" -enum { - TOK_CONST = 256, - TOK_ID, - TOK_MESSAGE, - TOK_NUM, - TOK_PACKAGE, - TOK_STRUCT, - TOK_TYPE, - TOK_REQUIRED, - TOK_OPTIONAL, -}; +#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) enum { TYPE_U8, @@ -45,27 +22,69 @@ enum message_type { MESSAGE_INDICATION = 4, }; -struct token { - int id; - const char *str; - unsigned num; +extern const char *sz_simple_types[]; + +extern const char *qmi_package; + +struct qmi_const { + const char *name; + unsigned value; + + struct list_head node; +}; + +struct qmi_message_member { + const char *name; + int type; struct qmi_struct *qmi_struct; + int id; + bool required; + unsigned array_size; + bool array_fixed; + + struct list_head node; +}; + +struct qmi_message { + enum message_type type; + const char *name; + unsigned msg_id; + + struct list_head node; + + struct list_head members; +}; + +struct qmi_struct_member { + const char *name; + int type; + + struct list_head node; +}; + +struct qmi_struct { + const char *name; + + struct list_head node; + + struct list_head members; }; -void yyerror(const char *fmt, ...); +extern struct list_head qmi_consts; +extern struct list_head qmi_messages; +extern struct list_head qmi_structs; -void symbol_add(const char *name, int token, ...); +void qmi_parse(void); -int token_accept(int id, struct token *tok); -void token_expect(int id, struct token *tok); +void emit_source_includes(FILE *fp, const char *package); +void guard_header(FILE *fp, const char *package); +void guard_footer(FILE *fp); +void qmi_const_header(FILE *fp); -void qmi_message_parse(enum message_type message_type); -void qmi_message_source(FILE *fp, const char *package); -void qmi_message_header(FILE *fp, const char *package); +void accessor_emit_c(FILE *fp, const char *package); +void accessor_emit_h(FILE *fp, const char *package); -void qmi_struct_parse(void); -void qmi_struct_header(FILE *fp, const char *package); -void qmi_struct_emit_prototype(FILE *fp, const char *package, const char *message, const char *member, unsigned array_size, struct qmi_struct *qs); -void qmi_struct_emit_accessors(FILE *fp, const char *package, const char *message, const char *member, int member_id, unsigned array_size, struct qmi_struct *qs); +void kernel_emit_c(FILE *fp, const char *package); +void kernel_emit_h(FILE *fp, const char *package); #endif |