css: add a simple css parser master
authoryu.dongliang <18588496441@163.com>
Tue, 3 Mar 2026 08:48:08 +0000 (16:48 +0800)
committeryu.dongliang <18588496441@163.com>
Tue, 3 Mar 2026 08:48:08 +0000 (16:48 +0800)
16 files changed:
examples/css.html [new file with mode: 0644]
html/Makefile
html/abc_css.c [new file with mode: 0644]
html/abc_html.c
html/abc_html.h
html/abc_io.h [new file with mode: 0644]
html/abc_io_file.c
html/abc_io_http.c
html/abc_io_str.c [new file with mode: 0644]
html/abc_io_util.c [new file with mode: 0644]
html/abc_obj.h
html/main.c
js/abc_libjs.c
js/abc_libjs.so
ui/Makefile
ui/main.c

diff --git a/examples/css.html b/examples/css.html
new file mode 100644 (file)
index 0000000..7e1dda0
--- /dev/null
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+p
+{
+       color:red;
+       text-align:center;
+} 
+</style>
+</head>
+
+<body>
+<p>Hello World!</p>
+<p>这个段落采用CSS样式化。</p>
+</body>
+
+</html>
index b04c19bc3cfa8b5030139aca723599b9a60afb01..e404606a38188bf8efcf18443e1e0d6e2f309e41 100644 (file)
@@ -1,9 +1,11 @@
 CFILES += main.c
 CFILES += abc_obj.c
 CFILES += abc_html.c
-CFILES += abc_html_util.c
+CFILES += abc_css.c
+CFILES += abc_io_util.c
 CFILES += abc_io_file.c
 CFILES += abc_io_http.c
+CFILES += abc_io_str.c
 
 CFILES += ../js/util/scf_string.c
 CFILES += ../js/util/scf_graph.c
diff --git a/html/abc_css.c b/html/abc_css.c
new file mode 100644 (file)
index 0000000..4ddf3b1
--- /dev/null
@@ -0,0 +1,300 @@
+#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;
+}
index a9b0fe0c47719018b3bdecfe04e952c31523d03a..664da6bd46ab777c6f70b5e97b26ab71c785ae55 100644 (file)
@@ -1,33 +1,5 @@
 #include"abc_html.h"
 
-typedef struct {
-       char** names;
-       char*  value;
-       int    type;
-       int    flags;
-} html_attr_t;
-
-typedef struct {
-       char**        names;
-       int           type;
-
-       int           n_attrs;
-       html_attr_t*  attrs;
-
-       uint32_t      flags;
-} html_label_t;
-
-#define abc_number_of(__array)  (sizeof(__array) / sizeof(__array[0]))
-
-extern abc_io_t   abc_io_file;
-extern abc_io_t   abc_io_http;
-
-static abc_io_t*  abc_io_array[ABC_PROTO_NB] =
-{
-       [ABC_PROTO_FILE] = &abc_io_file,
-       [ABC_PROTO_HTTP] = &abc_io_http,
-};
-
 // HTML attrs
 static char* src_keys[]        = {"src",        "源",       NULL};
 static char* href_keys[]       = {"href",       "地址",     NULL};
@@ -37,7 +9,9 @@ static char* height_keys[]     = {"height",     "高度",     NULL};
 
 static char* font_keys[]       = {"font",       "字体",     NULL};
 static char* font_size_keys[]  = {"font-size",  "字号",     NULL};
-static char* font_color_keys[] = {"font-color", "字体颜色", NULL};
+static char* font_color_keys[] = {"font-color", "字体颜色", "color", "颜色", NULL};
+
+static char* text_align_keys[] = {"text-align", "对齐",     NULL};
 
 static char* type_keys[]       = {"type",       "类型",     NULL};
 static char* name_keys[]       = {"name",       "名字",     NULL};
@@ -99,6 +73,7 @@ static char* play_keys[]       = {"play",       "播放",     NULL};
 static char* progress_keys[]   = {"progress",   "进度条",   NULL};
 
 static char* script_keys[]     = {"script",     "脚本",     NULL};
+static char* style_keys[]      = {"style",      "样式",     NULL};
 
 static html_attr_t  html_attrs[] =
 {
@@ -158,8 +133,10 @@ static html_attr_t  h6_attrs[] =
 
 static html_attr_t  p_attrs[] =
 {
-       {font_keys,        "SimSong",    ABC_HTML_ATTR_FONT,      0},
-       {font_size_keys,   "16",         ABC_HTML_ATTR_FONT_SIZE, 0},
+       {font_keys,        "SimSong",    ABC_HTML_ATTR_FONT,       0},
+       {font_size_keys,   "16",         ABC_HTML_ATTR_FONT_SIZE,  0},
+       {font_color_keys,  "black",      ABC_HTML_ATTR_FONT_COLOR, ABC_HTML_FLAG_SHOW},
+       {text_align_keys,  "left",       ABC_HTML_ATTR_TEXT_ALIGN, ABC_HTML_FLAG_SHOW},
 };
 
 static html_attr_t  a_attrs[] =
@@ -273,12 +250,13 @@ static html_label_t  html_labels[] =
        {progress_keys, ABC_HTML_PROGRESS, 0,                           NULL,         ABC_HTML_FLAG_OPEN},
 
        {script_keys,   ABC_HTML_SCRIPT,   abc_number_of(script_attrs), script_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW},
+
+       {style_keys,    ABC_HTML_STYLE,    0,                           NULL,         ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW},
 };
 
 static int __html_parse_obj(abc_html_t* html, abc_char_t* c);
 
-
-static html_label_t* __html_find_label(const char* name)
+html_label_t* __html_find_label(const char* name)
 {
        html_label_t* label;
 
@@ -298,7 +276,7 @@ static html_label_t* __html_find_label(const char* name)
        return NULL;
 }
 
-static int __html_add_attr(abc_obj_t* obj, int type, char** names, const char* value, int flags)
+int __html_add_attr(abc_obj_t* obj, int type, char** names, const char* value, int flags)
 {
        abc_obj_t* attr = abc_obj_alloc(NULL, 0, 0, type);
        if (!attr)
@@ -443,7 +421,7 @@ int abc_html_post(abc_html_t** pp, abc_html_t* form, abc_obj_t* submit)
        html->io.popc  = io->popc;
        html->io.post  = io->post;
 
-       ret = io->post(html, url->data + n, content);
+       ret = io->post(&html->io, url->data + n, content);
        if (ret < 0) {
                scf_string_free(url);
                scf_string_free(content);
@@ -495,7 +473,7 @@ int abc_html_open(abc_html_t** pp, const char* path)
        html->io.popc  = io->popc;
        html->io.post  = io->post;
 
-       int ret = io->open(html, path + n);
+       int ret = io->open(&html->io, path + n);
        if (ret < 0) {
                free(html);
                return ret;
@@ -518,10 +496,10 @@ void abc_html_close(abc_html_t* html)
        abc_char_t* c;
 
        if (html) {
-               while ( html->tmp_list) {
-                       c = html->tmp_list;
+               while ( html->io.tmp_list) {
+                       c = html->io.tmp_list;
 
-                       html->tmp_list = c->next;
+                       html->io.tmp_list = c->next;
                        free(c);
                }
 
@@ -529,7 +507,7 @@ void abc_html_close(abc_html_t* html)
                        abc_obj_free(html->root);
 
                if (html->io.close)
-                       html->io.close(html);
+                       html->io.close(&html->io);
 
                if (html->file)
                        scf_string_free(html->file);
@@ -550,7 +528,7 @@ static int __html_parse_end(abc_html_t* html, abc_obj_t* obj)
        abc_char_t* c = NULL;
 
        while (1) {
-               c = __html_pop_char(html);
+               c = __io_pop_char(&html->io);
                if (!c) {
                        scf_loge("\n");
                        scf_string_free(end);
@@ -595,7 +573,7 @@ static int __html_parse_text(abc_html_t* html, abc_obj_t* obj)
 
        int flag = 0;
        while (1) {
-               c = __html_pop_char(html);
+               c = __io_pop_char(&html->io);
                if (!c) {
                        scf_loge("\n");
                        scf_string_free(text);
@@ -610,14 +588,14 @@ static int __html_parse_text(abc_html_t* html, abc_obj_t* obj)
                                if (ABC_HTML_SCRIPT != obj->type)
                                        break;
 
-                               abc_char_t* c2 = __html_pop_char(html);
+                               abc_char_t* c2 = __io_pop_char(&html->io);
                                if (!c2) {
                                        scf_loge("\n");
                                        scf_string_free(text);
                                        return -1;
                                }
 
-                               __html_push_char(html, c2);
+                               __io_push_char(&html->io, c2);
 
                                if ('/' == c2->c)
                                        break;
@@ -643,7 +621,7 @@ static int __html_parse_text(abc_html_t* html, abc_obj_t* obj)
        text = NULL;
 
        if (ABC_HTML_FLAG_OPEN == (obj->flags & 0x1)) { // single labels
-               __html_push_char(html, c);
+               __io_push_char(&html->io, c);
                c = NULL;
                return 0;
        };
@@ -652,7 +630,7 @@ static int __html_parse_text(abc_html_t* html, abc_obj_t* obj)
        free(c);
        c = NULL;
 
-       c = __html_pop_char(html);
+       c = __io_pop_char(&html->io);
        if (!c) {
                scf_loge("\n");
                free(c);
@@ -735,7 +713,7 @@ static int __html_parse_value(abc_html_t* html, abc_obj_t* attr)
        int flag = 0;
 
        while (1) {
-               c = __html_pop_char(html);
+               c = __io_pop_char(&html->io);
                if (!c) {
                        scf_loge("\n");
                        scf_string_free(value);
@@ -749,9 +727,9 @@ static int __html_parse_value(abc_html_t* html, abc_obj_t* attr)
                                break;
 
                        if ('/' == c->c) {
-                               c2 = __html_pop_char(html);
+                               c2 = __io_pop_char(&html->io);
 
-                               __html_push_char(html, c2);
+                               __io_push_char(&html->io, c2);
                                if ('>' == c2->c)
                                        break;
                        }
@@ -791,7 +769,7 @@ static int __html_parse_attr2(abc_html_t* html, abc_obj_t* obj, const html_attr_
        abc_char_t* c = NULL;
 
        while (1) {
-               c = __html_pop_char(html);
+               c = __io_pop_char(&html->io);
                if (!c) {
                        scf_loge("\n");
                        scf_string_free(key);
@@ -1015,7 +993,7 @@ static int __html_run_js(abc_html_t* html, abc_obj_t* obj)
                        return ret;
                }
 #if 1
-               assert(!html->tmp_list_js);
+               assert(!html->io.tmp_list_js);
 
                void* so = dlopen(obj->js_so->data, RTLD_LAZY);
                void (*f)() = dlsym(so, "__js_main");
@@ -1025,13 +1003,13 @@ static int __html_run_js(abc_html_t* html, abc_obj_t* obj)
                so = NULL;
 #endif
                abc_char_t* c;
-               while ( html->tmp_list_js) {
-                       c = html->tmp_list_js;
+               while ( html->io.tmp_list_js) {
+                       c = html->io.tmp_list_js;
 
-                       html->tmp_list_js = c->next;
+                       html->io.tmp_list_js = c->next;
 
-                       c->next = html->tmp_list;
-                       html->tmp_list = c;
+                       c->next = html->io.tmp_list;
+                       html->io.tmp_list = c;
                }
        }
 
@@ -1053,7 +1031,7 @@ static int __html_parse_obj(abc_html_t* html, abc_char_t* c)
                return -ENOMEM;
 
        while (1) {
-               c = __html_pop_char(html);
+               c = __io_pop_char(&html->io);
                if (!c) {
                        scf_loge("\n");
                        scf_string_free(key);
@@ -1135,7 +1113,7 @@ static int __html_parse_obj(abc_html_t* html, abc_char_t* c)
        }
 
        if ('/' == ret) {
-               c = __html_pop_char(html);
+               c = __io_pop_char(&html->io);
                if (!c) {
                        scf_loge("\n");
                        return -1;
@@ -1160,6 +1138,15 @@ static int __html_parse_obj(abc_html_t* html, abc_char_t* c)
                                return -1;
                        break;
 
+               case ABC_HTML_STYLE:
+                       if (obj->text) {
+                               scf_logi("\033[33mcss: %s\033[0m\n", obj->text->data);
+
+                               if (abc_css_parse(obj) < 0)
+                                       return -1;
+                       }
+                       break;
+
                case ABC_HTML_VIDEO:
                        html->has_video = 1;
 
@@ -1180,7 +1167,7 @@ int abc_html_parse(abc_html_t* html)
        abc_char_t* c;
 
        while (1) {
-               c = __html_pop_char(html);
+               c = __io_pop_char(&html->io);
                if (!c)
                        return -1;
 
@@ -1204,12 +1191,12 @@ int abc_html_parse(abc_html_t* html)
 
                free(c);
 
-               c = __html_pop_char(html);
+               c = __io_pop_char(&html->io);
                if ('!' == c->c) { // <! note >
                        free(c);
 
                        while (1) {
-                               c = __html_pop_char(html);
+                               c = __io_pop_char(&html->io);
 
                                int tmp = c->c;
                                free(c);
index 66e9a55771ae8f0f9ca4b97862c4147b76d7ccfc..81f78913b48a11e27363e39e4d670997791154fe 100644 (file)
@@ -1,50 +1,35 @@
 #ifndef ABC_HTML_H
 #define ABC_HTML_H
 
+#include"abc_io.h"
 #include"abc_obj.h"
 #include"scf_parse.h"
 
-typedef struct abc_char_s  abc_char_t;
 typedef struct abc_html_s  abc_html_t;
-typedef struct abc_io_s    abc_io_t;
 
-enum abc_protos
-{
-       ABC_PROTO_FILE,
-       ABC_PROTO_HTTP,
-
-       ABC_PROTO_NB
-};
-
-#define ABC_UTF8_MAX 6
-struct abc_char_s
-{
-       abc_char_t*     next;
-       int             c;
+typedef struct {
+       char** names;
+       char*  value;
+       int    type;
+       int    flags;
+} html_attr_t;
 
-       int             len;
-       uint8_t         utf8[ABC_UTF8_MAX];
-};
+typedef struct {
+       char**        names;
+       int           type;
 
-struct abc_io_s
-{
-       char*           proto;
-       void*           priv;
+       int           n_attrs;
+       html_attr_t*  attrs;
 
-       int           (*open )(abc_html_t* html, const char* path);
-       void          (*close)(abc_html_t* html);
+       uint32_t      flags;
+} html_label_t;
 
-       int           (*popc )(abc_html_t* html);
-       int           (*post )(abc_html_t* html, const char* path, scf_string_t* content);
-};
+#define abc_number_of(__array)  (sizeof(__array) / sizeof(__array[0]))
 
 struct abc_html_s
 {
        scf_list_t      list;
 
-       abc_char_t*     tmp_list;
-       abc_char_t*     tmp_list_js;
-
        abc_obj_t*      root;
        abc_obj_t*      current;
 
@@ -56,7 +41,6 @@ struct abc_html_s
 
        scf_parse_t*    js;
 
-       uint8_t         download :1;
        uint8_t         has_video:1;
 };
 
@@ -65,8 +49,6 @@ int    abc_html_post (abc_html_t** pp, abc_html_t* form, abc_obj_t* submit);
 void abc_html_close(abc_html_t*  html);
 
 int  abc_html_parse(abc_html_t* html);
-
-abc_char_t*  __html_pop_char (abc_html_t* html);
-void         __html_push_char(abc_html_t* html, abc_char_t* c);
+int  abc_css_parse (abc_obj_t*  css);
 
 #endif
diff --git a/html/abc_io.h b/html/abc_io.h
new file mode 100644 (file)
index 0000000..c5ca2db
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef ABC_IO_H
+#define ABC_IO_H
+
+#include"scf_string.h"
+#include"scf_list.h"
+
+typedef struct abc_char_s  abc_char_t;
+typedef struct abc_io_s    abc_io_t;
+
+enum abc_protos
+{
+       ABC_PROTO_FILE,
+       ABC_PROTO_HTTP,
+       ABC_PROTO_STR,
+
+       ABC_PROTO_NB
+};
+
+extern abc_io_t*  abc_io_array[ABC_PROTO_NB];
+
+#define ABC_UTF8_MAX 6
+struct abc_char_s
+{
+       abc_char_t*     next;
+       int             c;
+
+       int             len;
+       uint8_t         utf8[ABC_UTF8_MAX];
+};
+
+struct abc_io_s
+{
+       char*           proto;
+
+       void*           priv;
+       uint8_t         download:1;
+
+       abc_char_t*     tmp_list;
+       abc_char_t*     tmp_list_js;
+
+       int           (*open )(abc_io_t* io, const char* path);
+       void          (*close)(abc_io_t* io);
+
+       int           (*popc )(abc_io_t* io);
+       int           (*post )(abc_io_t* io, const char* path, scf_string_t* content);
+};
+
+abc_char_t*  __io_pop_char (abc_io_t* io);
+void         __io_push_char(abc_io_t* io, abc_char_t* c);
+
+#endif
index 16afbbd12dbd2760adbc4ca365d0450e9c399c53..8bf2fed34d8f70cbb62dbe168b8830f29dd55b73 100644 (file)
@@ -1,12 +1,12 @@
-#include"abc_html.h"
+#include"abc_io.h"
 
-static int __file_open(abc_html_t* html, const char* path)
+static int __file_open(abc_io_t* io, const char* path)
 {
-       if (!html || !path)
+       if (!io || !path)
                return -EINVAL;
 
-       html->io.priv = fopen(path, "r");
-       if (!html->io.priv) {
+       io->priv = fopen(path, "r");
+       if (!io->priv) {
                char cwd[4096];
                getcwd(cwd, 4095);
 
@@ -14,25 +14,20 @@ static int __file_open(abc_html_t* html, const char* path)
                return -1;
        }
 
-       html->download = 1;
+       io->download = 1;
        return 0;
 }
 
-static void __file_close(abc_html_t* html)
+static void __file_close(abc_io_t* io)
 {
-       if (html && html->io.priv) {
-
-               fclose(html->io.priv);
-       }
+       if (io && io->priv)
+               fclose(io->priv);
 }
 
-static int __file_popc(abc_html_t* html)
+static int __file_popc(abc_io_t* io)
 {
-       if (html && html->io.priv) {
-
-               return fgetc(html->io.priv);
-       }
-
+       if (io && io->priv)
+               return fgetc(io->priv);
        return EOF;
 }
 
index 1d6b246eba82dea2faf0742404733cb6a3a415d1..559fea123eb3338f67adc7b4de56a181873d0066 100644 (file)
@@ -1,4 +1,4 @@
-#include"abc_html.h"
+#include"abc_io.h"
 
 typedef struct {
        scf_string_t*    host;
@@ -89,11 +89,11 @@ static void http_chunk_size(abc_http_t* http)
        }
 }
 
-static int http_filter_chunk(abc_html_t* html)
+static int http_filter_chunk(abc_io_t* io)
 {
-       abc_http_t* http = html->io.priv;
+       abc_http_t* http = io->priv;
 
-       if (html->download)
+       if (io->download)
                return 0;
 
        while (http->cpos < http->rbuf->len) {
@@ -108,7 +108,7 @@ static int http_filter_chunk(abc_html_t* html)
                http->cpos += 2;
 
                if (0 == http->content_length) {
-                       html->download = 1;
+                       io->download = 1;
                        return 0;
                }
 
@@ -134,8 +134,8 @@ static int http_filter_chunk(abc_html_t* html)
 
 static void* http_thread(void* arg)
 {
-       abc_html_t* html = arg;
-       abc_http_t* http = html->io.priv;
+       abc_io_t*   io   = arg;
+       abc_http_t* http = io->priv;
 
        while (!http->exit) {
                struct epoll_event ev;
@@ -193,14 +193,14 @@ static void* http_thread(void* arg)
                                if (http->rpos > 0) {
                                        if (!http->chunk_flag) {
                                                if (http->content_length == http->rbuf->len - http->rpos) {
-                                                       html->download = 1;
+                                                       io->download = 1;
 
                                                        scf_logi("http response: %s\n", http->rbuf->data);
                                                }
                                        } else {
-                                               http_filter_chunk(html);
+                                               http_filter_chunk(io);
 
-                                               if (html->download)
+                                               if (io->download)
                                                        scf_logi("http response: %s\n", http->rbuf->data);
                                        }
                                }
@@ -212,7 +212,7 @@ static void* http_thread(void* arg)
                if (ev.events & EPOLLOUT) {
                        pthread_mutex_lock(&http->mutex);
                        if (0 == http->wpos) {
-                               html->download  = 0;
+                               io->download  = 0;
                                http->rbuf->len = 0;
                                http->rpos      = 0;
                        }
@@ -379,9 +379,9 @@ static int __http_open2(abc_http_t** pp, const char* path)
        return 0;
 }
 
-static int __http_open(abc_html_t* html, const char* path)
+static int __http_open(abc_io_t* io, const char* path)
 {
-       if (!html || !path)
+       if (!io || !path)
                return -EINVAL;
 
        abc_http_t* http = NULL;
@@ -413,11 +413,11 @@ static int __http_open(abc_html_t* html, const char* path)
        ABC_HTTP_FILL("Accept: */*\r\n");
        ABC_HTTP_FILL("\r\n");
 
-       html->io.priv = http;
+       io->priv = http;
 
-       if (pthread_create(&http->tid, NULL, http_thread, html)) {
+       if (pthread_create(&http->tid, NULL, http_thread, io)) {
                abc_http_close(http);
-               html->io.priv = NULL;
+               io->priv = NULL;
                return -1;
        }
 
@@ -425,9 +425,9 @@ static int __http_open(abc_html_t* html, const char* path)
        return 0;
 }
 
-static int __http_post(abc_html_t* html, const char* path, scf_string_t* content)
+static int __http_post(abc_io_t* io, const char* path, scf_string_t* content)
 {
-       if (!html || !path || !content)
+       if (!io || !path || !content)
                return -EINVAL;
 
        abc_http_t* http = NULL;
@@ -459,11 +459,11 @@ static int __http_post(abc_html_t* html, const char* path, scf_string_t* content
 
        ABC_HTTP_FILL(content->data);
 
-       html->io.priv = http;
+       io->priv = http;
 
-       if (pthread_create(&http->tid, NULL, http_thread, html)) {
+       if (pthread_create(&http->tid, NULL, http_thread, io)) {
                abc_http_close(http);
-               html->io.priv = NULL;
+               io->priv = NULL;
                return -1;
        }
 
@@ -471,18 +471,18 @@ static int __http_post(abc_html_t* html, const char* path, scf_string_t* content
        return 0;
 }
 
-static void __http_close(abc_html_t* html)
+static void __http_close(abc_io_t* io)
 {
-       if (html)
-               abc_http_close(html->io.priv);
+       if (io)
+               abc_http_close(io->priv);
 }
 
-static int __http_popc(abc_html_t* html)
+static int __http_popc(abc_io_t* io)
 {
        abc_http_t* http;
 
-       if (html) {
-               http = html->io.priv;
+       if (io) {
+               http = io->priv;
 
                if (http) {
                        int c;
diff --git a/html/abc_io_str.c b/html/abc_io_str.c
new file mode 100644 (file)
index 0000000..ba31fcf
--- /dev/null
@@ -0,0 +1,65 @@
+#include"abc_io.h"
+
+typedef struct {
+       scf_string_t*  text;
+       int            text_i;
+} abc_str_t;
+
+static int __str_open(abc_io_t* io, const char* path)
+{
+       if (!io || !path)
+               return -EINVAL;
+
+       abc_str_t* s = calloc(1, sizeof(abc_str_t));
+       if (!s)
+               return -ENOMEM;
+
+       s->text = scf_string_cstr(path);
+       if (!s->text) {
+               free(s);
+               return -ENOMEM;
+       }
+
+       io->priv = s;
+       io->download = 1;
+       return 0;
+}
+
+static void __str_close(abc_io_t* io)
+{
+       abc_str_t* s;
+
+       if (io && io->priv) {
+               s = io->priv;
+
+               if (s->text)
+                       scf_string_free(s->text);
+
+               free(s);
+               io->priv = NULL;
+       }
+}
+
+static int __str_popc(abc_io_t* io)
+{
+       abc_str_t* s;
+
+       if (io && io->priv) {
+               s = io->priv;
+
+               if (s->text_i < s->text->len)
+                       return s->text->data[s->text_i++];
+       }
+
+       return EOF;
+}
+
+abc_io_t  abc_io_str =
+{
+       .proto = "str://",
+
+       .open  = __str_open,
+       .close = __str_close,
+
+       .popc  = __str_popc,
+};
diff --git a/html/abc_io_util.c b/html/abc_io_util.c
new file mode 100644 (file)
index 0000000..dd1fa0b
--- /dev/null
@@ -0,0 +1,97 @@
+#include"abc_io.h"
+
+extern abc_io_t   abc_io_file;
+extern abc_io_t   abc_io_http;
+extern abc_io_t   abc_io_str;
+
+abc_io_t*  abc_io_array[ABC_PROTO_NB] =
+{
+       [ABC_PROTO_FILE] = &abc_io_file,
+       [ABC_PROTO_HTTP] = &abc_io_http,
+       [ABC_PROTO_STR]  = &abc_io_str,
+};
+
+abc_char_t* __io_pop_char(abc_io_t* io)
+{
+       assert(io);
+
+       abc_char_t* c;
+
+       if (io->tmp_list) {
+               c            = io->tmp_list;
+               io->tmp_list = c->next;
+               return c;
+       }
+
+       c = malloc(sizeof(abc_char_t));
+       if (!c)
+               return NULL;
+
+       int ret = io->popc(io);
+       if (EOF == ret) {
+               c->c = ret;
+               return c;
+       }
+
+       if (ret < 0x80) {
+               c->c   = ret;
+               c->len = 1;
+               c->utf8[0] = ret;
+               return c;
+       }
+
+       if (0x6 == (ret >> 5)) {
+               c->c   = ret & 0x1f;
+               c->len = 2;
+
+       } else if (0xe == (ret >> 4)) {
+               c->c   = ret & 0xf;
+               c->len = 3;
+
+       } else if (0x1e == (ret >> 3)) {
+               c->c   = ret & 0x7;
+               c->len = 4;
+
+       } else if (0x3e == (ret >> 2)) {
+               c->c   = ret & 0x3;
+               c->len = 5;
+
+       } else if (0x7e == (ret >> 1)) {
+               c->c   = ret & 0x1;
+               c->len = 6;
+       } else {
+               scf_loge("utf8 first byte wrong %#x\n", ret);
+               free(c);
+               return NULL;
+       }
+
+       c->utf8[0] = ret;
+
+       int i;
+       for (i = 1; i < c->len; i++) {
+
+               ret = io->popc(io);
+
+               if (0x2  == (ret >> 6)) {
+                       c->c <<= 6;
+                       c->c  |= ret & 0x3f;
+
+                       c->utf8[i] = ret;
+               } else {
+                       scf_loge("utf8 byte[%d] wrong %#x\n", i + 1, ret);
+                       free(c);
+                       return NULL;
+               }
+       }
+
+       return c;
+}
+
+void __io_push_char(abc_io_t* io, abc_char_t* c)
+{
+       assert(io);
+       assert(c);
+
+       c->next        = io->tmp_list;
+       io->tmp_list = c;
+}
index f87c59a784ffb895108af16d7c729581bb279da2..c1a74f31a06ad0f2460118b65bdf7628f88e2866 100644 (file)
@@ -4,6 +4,7 @@
 #include"scf_string.h"
 #include"scf_list.h"
 #include"abc_ffmpeg.h"
+#include"abc_io.h"
 
 typedef struct abc_obj_s   abc_obj_t;
 
@@ -56,6 +57,8 @@ enum abc_objs
 
        ABC_HTML_SCRIPT,
 
+       ABC_HTML_STYLE,
+
        ABC_HTML_NB, // total HTML objects
 
        ABC_HTML_ATTR_ID,
@@ -75,6 +78,8 @@ enum abc_objs
        ABC_HTML_ATTR_FONT_SIZE,
        ABC_HTML_ATTR_FONT_COLOR,
 
+       ABC_HTML_ATTR_TEXT_ALIGN,
+
        ABC_HTML_ATTR_WIDTH,
        ABC_HTML_ATTR_HEIGHT,
 
@@ -124,6 +129,10 @@ struct abc_obj_s
        scf_string_t*   value;
        scf_string_t*   text;
 
+       int             text_line;
+       int             text_pos;
+       abc_io_t        io;
+
        scf_string_t*   file; // file name
        int             line; // line
        int             pos;  // position
index ff8a43890abf8264b29a11620f6a3cce58730b5c..4a8eb4b0fbb61e210f645ea7cfcd1f1795723514 100644 (file)
@@ -14,7 +14,7 @@ int main(int argc, char* argv[])
                return -1;
        }
 
-       while (!html->download)
+       while (!html->io.download)
                usleep(50 * 1000);
 
        if (abc_html_parse(html) < 0) {
index 553244150c1828c24256dedcda0a43e07374dde5..f8a1312c68c78780a1089d659c84343bf958aa60 100644 (file)
@@ -126,9 +126,9 @@ int abc_html_write(abc_html_t* html, const char* s)
        while (*pp)
                pp = &(*pp)->next;
 
-       *pp = html->tmp_list_js;
+       *pp = html->io.tmp_list_js;
 
-       html->tmp_list_js = h;
+       html->io.tmp_list_js = h;
        return 0;
 
 error:
index 376eaa007efa1e1da105f67eaf01a94be84e17be..b5d7e51efae8bd855a2bd95d04bf4c0060ff4aea 100755 (executable)
Binary files a/js/abc_libjs.so and b/js/abc_libjs.so differ
index f9c56cce9bb46404960f261c070efb2cf901dac2..86240945ce686874496eac20181ac9188ace26fd 100644 (file)
@@ -43,10 +43,11 @@ CFILES += abc_render_video.c
 CFILES += abc_render_audio.c
 
 CFILES += ../html/abc_html.c
-CFILES += ../html/abc_html_util.c
 CFILES += ../html/abc_obj.c
+CFILES += ../html/abc_io_util.c
 CFILES += ../html/abc_io_file.c
 CFILES += ../html/abc_io_http.c
+CFILES += ../html/abc_io_str.c
 
 CFILES += ../ffmpeg/abc_ffmpeg_img.c
 CFILES += ../ffmpeg/abc_ffmpeg_input.c
index 6556e516746338eeea00f791a7f0cbd757dba9a5..41801d7215d2bed2125804e6bac784fc4cff8a78 100644 (file)
--- a/ui/main.c
+++ b/ui/main.c
@@ -58,7 +58,7 @@ static int __do_button_move(abc_ctx_t* ctx, int x, int y)
        GdkWindow*  window;
        GdkCursor*  cursor;
 
-       if (!ctx->current->download)
+       if (!ctx->current->io.download)
                return 0;
 
        if (!ctx->current->root)
@@ -375,7 +375,7 @@ static gboolean timer_handler(gpointer user_data)
        abc_obj_t* obj;
 
        if (ctx->current) {
-               if (!ctx->current->download)
+               if (!ctx->current->io.download)
                        return TRUE;
 
                if (!ctx->current->root) {
@@ -494,7 +494,7 @@ int main(int argc, char *argv[])
                return ret;
        }
 
-       while (!html->download)
+       while (!html->io.download)
                usleep(50 * 1000);
 
        ret = abc_html_parse(html);