+#include"abc_html.h"
+int __html_add_attr(abc_obj_t* obj, int type, char** names, const char* value, int flags);
+html_label_t* __html_find_label(const char* name);
+
+static int __css_parse_value(abc_obj_t* css, abc_obj_t* attr)
+{
+ scf_string_t* value = scf_string_alloc();
+ if (!value)
+ return -ENOMEM;
+
+ abc_char_t* c = NULL;
+ abc_char_t* c2 = NULL;
+
+ while (1) {
+ c = __io_pop_char(&css->io);
+ if (!c) {
+ scf_loge("\n");
+ scf_string_free(value);
+ return -1;
+ }
+
+ css->text_pos += c->len;
+
+ if (';' == c->c)
+ break;
+ else
+ scf_string_cat_cstr_len(value, c->utf8, c->len);
+
+ free(c);
+ c = NULL;
+ }
+
+ int tmp = c->c;
+
+ free(c);
+ c = NULL;
+
+ if (attr->value)
+ scf_string_free(attr->value);
+
+ attr->value = value;
+ return tmp;
+}
+
+static int __css_parse_attr2(abc_obj_t* css, abc_obj_t* obj, const html_attr_t* attrs, int n_attrs)
+{
+ scf_string_t* key = scf_string_alloc();
+ if (!key)
+ return -ENOMEM;
+
+ abc_char_t* c = NULL;
+
+ while (1) {
+ c = __io_pop_char(&css->io);
+ if (!c) {
+ scf_loge("\n");
+ scf_string_free(key);
+ return -1;
+ }
+
+ css->text_pos += c->len;
+
+ if ('}' == c->c) {
+ free(c);
+ scf_string_free(key);
+ return '}';
+ }
+
+ if (':' == c->c)
+ break;
+
+ if ('_' == c->c
+ || '-' == c->c
+ || ('a' <= c->c && 'z' >= c->c)) {
+ scf_string_cat_cstr_len(key, c->utf8, c->len);
+
+ } else if (' ' == c->c || '\t' == c->c || '\r' == c->c) {
+
+ } else {
+ scf_loge("invalid char '%c:%#x' in CSS attribute, file: %s, line: %d\n",
+ c->c, c->c, css->file->data, css->text_line);
+ assert(0);
+ free(c);
+ scf_string_free(key);
+ return -1;
+ }
+
+ free(c);
+ c = NULL;
+ }
+
+ int tmp = c->c;
+
+ free(c);
+ c = NULL;
+
+ scf_list_t* l;
+ abc_obj_t* attr;
+
+ int i;
+ int j;
+ if (attrs && n_attrs > 0) {
+ for (i = 0; i < n_attrs; i++) {
+
+ for (j = 0; attrs[i].names[j]; j++) {
+ if (!strcmp(attrs[i].names[j], key->data))
+ goto found;
+ }
+ }
+ }
+
+ scf_loge("invalid HTML attribute '%s' in file: %s, line: %d\n", key->data, css->file->data, css->text_pos);
+ scf_string_free(key);
+ return -1;
+
+found:
+ for (l = scf_list_head(&obj->attrs); l != scf_list_sentinel(&obj->attrs); l = scf_list_next(l)) {
+ attr = scf_list_data(l, abc_obj_t, list);
+
+ for (j = 0; attr->keys[j]; j++) {
+ if (!strcmp(attr->keys[j], key->data))
+ break;
+ }
+ }
+
+ if (l == scf_list_sentinel(&obj->attrs)) {
+ int ret = __html_add_attr(obj, attrs[i].type, attrs[i].names, attrs[i].value, attrs[i].flags);
+ if (ret < 0)
+ return ret;
+
+ l = scf_list_tail(&obj->attrs);
+ attr = scf_list_data(l, abc_obj_t, list);
+ }
+
+ scf_string_free(key);
+ key = NULL;
+
+ attr->line = css->text_line;
+ attr->pos = css->text_pos;
+
+ return __css_parse_value(css, attr);
+}
+
+static int __css_parse_attr(abc_obj_t* css, abc_obj_t* obj, const html_attr_t* attrs, int n_attrs)
+{
+ int ret = 0;
+
+ while (1) {
+ ret = __css_parse_attr2(css, obj, attrs, n_attrs);
+ if (ret < 0)
+ return ret;
+
+ if ('}' == ret)
+ break;
+ }
+
+ return ret;
+}
+
+static int __css_parse_obj(abc_obj_t* css, abc_char_t* c)
+{
+ html_label_t* label;
+ abc_obj_t* obj;
+
+ scf_string_t* key = scf_string_cstr_len(c->utf8, c->len);
+
+ css->text_pos += c->len;
+ free(c);
+ c = NULL;
+
+ if (!key)
+ return -ENOMEM;
+
+ while (1) {
+ c = __io_pop_char(&css->io);
+ if (!c) {
+ scf_loge("\n");
+ scf_string_free(key);
+ return -1;
+ }
+
+ css->text_pos += c->len;
+
+ if (' ' == c->c || '{' == c->c)
+ break;
+
+ if ('\n' == c->c) {
+ css->text_line++;
+ css->text_pos = 0;
+ break;
+ }
+
+ scf_string_cat_cstr_len(key, c->utf8, c->len);
+ free(c);
+ c = NULL;
+ }
+
+ int tmp = c->c;
+ int ret;
+
+ free(c);
+ c = NULL;
+
+ label = __html_find_label(key->data);
+ if (!label) {
+ scf_loge("invalid HTML label '%s' in file: %s, line: %d\n",
+ key->data, css->file->data, css->text_line);
+ scf_string_free(key);
+ return -1;
+ }
+
+ scf_string_free(key);
+ key = NULL;
+
+ obj = abc_obj_alloc(css->file, css->text_line, css->text_pos, label->type);
+ if (!obj)
+ return -ENOMEM;
+
+ obj->flags = label->flags;
+ obj->keys = label->names;
+
+ obj->parent = css;
+
+ switch (tmp) {
+ case '{':
+ ret = __css_parse_attr(css, obj, label->attrs, label->n_attrs);
+ if (ret < 0) {
+ abc_obj_free(obj);
+ return ret;
+ }
+ break;
+ default:
+ ret = 0;
+ break;
+ };
+
+ scf_list_add_tail(&css->childs, &obj->list);
+ return 0;
+}
+
+int abc_css_parse(abc_obj_t* css)
+{
+ abc_char_t* c;
+ abc_io_t* io = abc_io_array[ABC_PROTO_STR];
+
+ css->io.proto = io->proto;
+ css->io.priv = NULL;
+ css->io.open = io->open;
+ css->io.close = io->close;
+ css->io.popc = io->popc;
+ css->io.post = io->post;
+
+ css->text_line = 1;
+ css->text_pos = 0;
+
+ int ret = io->open(&css->io, css->text->data);
+ if (ret < 0)
+ return ret;
+
+ while (1) {
+ c = __io_pop_char(&css->io);
+ if (!c)
+ return -1;
+
+ if (EOF == c->c) {
+ free(c);
+ return 0;
+ }
+
+ if ('\n' == c->c || '\r' == c->c) {
+ css->text_line++;
+ css->text_pos = 0;
+
+ free(c);
+ continue;
+ }
+
+ if (' ' == c->c || '\t' == c->c) {
+ css->text_pos++;
+ free(c);
+ continue;
+ }
+
+ if (('a' <= c->c && 'z' >= c->c)
+ || (0x4e00 <= c->c && 0x9fa5 >= c->c)) {
+
+ int ret = __css_parse_obj(css, c);
+ if (ret < 0) {
+ scf_loge("css->text_line: %d, css->text_pos: %d\n", css->text_line, css->text_pos);
+ return ret;
+ }
+ } else {
+ scf_loge("%c:%#x, css->text_line: %d, css->text_pos: %d\n", c->c, c->c, css->text_line, css->text_pos);
+ free(c);
+ return -1;
+ }
+ }
+
+ return -1;
+}