19b0b4715fa7c4d538f5f9d82a87bc750a1542cd
[pspp] / src / output / spv / spv-css-parser.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2018 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "spv-css-parser.h"
20
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include "libpspp/str.h"
25 #include "output/pivot-table.h"
26 #include "spv.h"
27
28 #include "gl/c-ctype.h"
29 #include "gl/xalloc.h"
30 #include "gl/xmemdup0.h"
31
32 enum css_token_type
33   {
34     T_EOF,
35     T_ID,
36     T_LCURLY,
37     T_RCURLY,
38     T_COLON,
39     T_SEMICOLON,
40     T_ERROR
41   };
42
43 struct css_token
44   {
45     enum css_token_type type;
46     char *s;
47   };
48
49 static char *
50 css_skip_spaces (char *p)
51 {
52   for (;;)
53     {
54       if (c_isspace (*p))
55         p++;
56       else if (!strncmp (p, "<!--", 4))
57         p += 4;
58       else if (!strncmp (p, "-->", 3))
59         p += 3;
60       else
61         return p;
62     }
63 }
64
65 static bool
66 css_is_separator (unsigned char c)
67 {
68   return c_isspace (c) || strchr ("{}:;", c);
69 }
70
71 static void
72 css_token_get (char **p_, struct css_token *token)
73 {
74   char *p = *p_;
75
76   free (token->s);
77   token->s = NULL;
78
79   p = css_skip_spaces (p);
80   if (*p == '\0')
81     token->type = T_EOF;
82   else if (*p == '{')
83     {
84       token->type = T_LCURLY;
85       p++;
86     }
87   else if (*p == '}')
88     {
89       token->type = T_RCURLY;
90       p++;
91     }
92   else if (*p == ':')
93     {
94       token->type = T_COLON;
95       p++;
96     }
97   else if (*p == ';')
98     {
99       token->type = T_SEMICOLON;
100       p++;
101     }
102   else
103     {
104       token->type = T_ID;
105       char *start = p;
106       while (!css_is_separator (*p))
107         p++;
108       token->s = xmemdup0 (start, p - start);
109     }
110   *p_ = p;
111 }
112
113 static void
114 css_decode_key_value (const char *key, const char *value,
115                       struct font_style *font)
116 {
117   if (!strcmp (key, "font-weight"))
118     font->bold = !strcmp (value, "bold");
119   else if (!strcmp (key, "font-style"))
120     font->italic = !strcmp (value, "italic");
121   else if (!strcmp (key, "font-decoration"))
122     font->underline = !strcmp (value, "underline");
123   else if (!strcmp (key, "font-family"))
124     {
125       free (font->typeface);
126       font->typeface = xstrdup (value);
127     }
128   else if (!strcmp (key, "font-size"))
129     font->size = atoi (value) * 3 / 4;
130
131   /* fg_color, bg_color */
132
133 }
134
135 char *
136 spv_parse_css_style (char *style, struct font_style *font)
137 {
138   *font = (struct font_style) FONT_STYLE_INITIALIZER;
139
140   char *p = style;
141   struct css_token token = { .s = NULL };
142   css_token_get (&p, &token);
143   while (token.type != T_EOF)
144     {
145       if (token.type != T_ID || !strcmp (token.s, "p"))
146         {
147           css_token_get (&p, &token);
148           continue;
149         }
150
151       char *key = token.s;
152       token.s = NULL;
153       css_token_get (&p, &token);
154
155       if (token.type == T_COLON)
156         {
157           struct string value = DS_EMPTY_INITIALIZER;
158           for (;;)
159             {
160               css_token_get (&p, &token);
161               if (token.type != T_ID)
162                 break;
163               if (!ds_is_empty (&value))
164                 ds_put_byte (&value, ' ');
165               ds_put_cstr (&value, token.s);
166             }
167
168           css_decode_key_value (key, ds_cstr (&value), font);
169
170           ds_destroy (&value);
171         }
172       free (key);
173     }
174   return NULL;
175 }