summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Dechesne <nicolas.dechesne@linaro.org>2018-04-18 13:27:25 +0200
committerNicolas Dechesne <nicolas.dechesne@linaro.org>2018-04-18 13:27:25 +0200
commit375b21acdba2d1b9d0b2ba85f9b7df4c57c334e0 (patch)
tree7001524012dae9c94f0c29007d594929c87830f7
parentf8343e246b4c40a9cb81b7291f238f343d5a5cc5 (diff)
parent4ad63502c5ce3f4fbdf223dc7f58d6ba9bbf5eea (diff)
Merge remote-tracking branch 'upstream/master'
-rw-r--r--Makefile8
-rw-r--r--accessor.c (renamed from qmi_message.c)239
-rw-r--r--kernel.c339
-rw-r--r--list.h95
-rw-r--r--parser.c422
-rw-r--r--qmi_struct.c157
-rw-r--r--qmic.c365
-rw-r--r--qmic.h99
8 files changed, 1107 insertions, 617 deletions
diff --git a/Makefile b/Makefile
index 0783e49..a3a81d7 100644
--- a/Makefile
+++ b/Makefile
@@ -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);
+}
diff --git a/list.h b/list.h
new file mode 100644
index 0000000..1ef5083
--- /dev/null
+++ b/list.h
@@ -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);
- }
-}
diff --git a/qmic.c b/qmic.c
index 857c4e1..f542f82 100644
--- a/qmic.c
+++ b/qmic.c
@@ -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);
diff --git a/qmic.h b/qmic.h
index da95bd2..482be4c 100644
--- a/qmic.h
+++ b/qmic.h
@@ -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