summaryrefslogtreecommitdiff
path: root/appl/ebook/cssparser.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/ebook/cssparser.b')
-rw-r--r--appl/ebook/cssparser.b143
1 files changed, 143 insertions, 0 deletions
diff --git a/appl/ebook/cssparser.b b/appl/ebook/cssparser.b
new file mode 100644
index 00000000..13c78597
--- /dev/null
+++ b/appl/ebook/cssparser.b
@@ -0,0 +1,143 @@
+implement CSSparser;
+
+include "sys.m";
+ sys: Sys;
+include "string.m";
+ str: String;
+include "css.m";
+ css: CSS;
+ Stylesheet, Statement, Select, Value: import css;
+include "cssparser.m";
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ str = load String String->PATH;
+ css = load CSS CSS->PATH;
+ if (css == nil) {
+ sys->fprint(sys->fildes(2), "cssparser: cannot load %s: %r\n", CSS->PATH);
+ raise "fail:bad module";
+ }
+ css->init(1);
+}
+
+parse(s: string): list of (string, list of Decl)
+{
+ (stylesheet, e) := css->parse(s);
+ if (stylesheet == nil) {
+ warning("error parsing stylesheet: " + e);
+ return nil;
+ }
+ rules, r: list of (string, list of Decl);
+ for (stl := stylesheet.statements; stl != nil; stl = tl stl) {
+ pick st := hd stl {
+ Ruleset =>
+ rules = ruleset2rule(st, rules);
+ }
+ }
+ for (; rules != nil; rules = tl rules)
+ r = hd rules :: r;
+ return r;
+}
+
+ruleset2rule(statement: ref Statement.Ruleset, onto: list of (string, list of Decl)): list of (string, list of Decl)
+{
+ d := makedecls(statement.decls);
+
+ names: list of string;
+ for (sels := statement.selectors; sels != nil; sels = tl sels) {
+ csel := hd sels;
+ if (len csel != 1) {
+ warning("context-specific selectors not allowed");
+ continue;
+ }
+ (nil, l) := hd csel;
+ if ((name := selector2name(l)) != nil)
+ names = name :: names;
+ }
+ for (; names != nil; names = tl names)
+ onto = (hd names, d) :: onto;
+
+ return onto;
+}
+
+makedecls(decls: list of ref CSS->Decl): list of Decl
+{
+ d: list of Decl;
+ for (; decls != nil; decls = tl decls) {
+ nd: Decl;
+ nd.name = (hd decls).property;
+ nd.important = (hd decls).important;
+ s := "";
+ for (vals := (hd decls).values; vals != nil; vals = tl vals) {
+ vs: string;
+ pick v := hd vals {
+ Percentage =>
+ vs = v.value + "%";
+ String or
+ Number or
+ Url or
+ Unicoderange =>
+ vs = v.value;
+ Hexcolour =>
+ vs = rgb2s(v.rgb);
+ RGB =>
+ vs = rgb2s(v.rgb);
+ Ident =>
+ vs = v.name;
+ Unit =>
+ vs = v.value + v.units;
+ }
+ if (s != nil)
+ s[len s] = (hd vals).sep;
+ s += vs;
+ }
+ nd.val = s;
+ d = nd :: d;
+ }
+ return d;
+}
+
+rgb2s(rgb: (int, int, int)): string
+{
+ (r, g, b) := rgb;
+ return sys->sprint("#%.2x%.2x%.2x", r, g, b);
+}
+
+warning(s: string)
+{
+ sys->fprint(sys->fildes(2), "cssparser: %s\n", s);
+}
+
+selector2name(sel: list of ref Select): string
+{
+ tag: string;
+ class: string;
+ pseudo: string;
+
+ for (; sel != nil; sel = tl sel) {
+ pick v := hd sel {
+ Element =>
+ tag = v.name;
+ Class =>
+ class = "." + v.name;
+ Pseudo =>
+ class = ":" + v.name;
+ * =>
+ warning("unknown selector type " + string tagof(hd sel));
+ }
+ }
+ return tag + class + pseudo;
+}
+
+parsedecl(s: string): list of Decl
+{
+ if (s == nil)
+ return nil;
+ (d, e) := css->parsedecl(s);
+ if (d == nil) {
+ warning(e);
+ return nil;
+ }
+ return makedecls(d);
+}