spv-legacy-decoder: Always give the pivot table a title.
[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/options.h"
26 #include "output/pivot-table.h"
27 #include "spv.h"
28
29 #include "gl/c-ctype.h"
30 #include "gl/xalloc.h"
31 #include "gl/xmemdup0.h"
32
33 enum css_token_type
34   {
35     T_EOF,
36     T_ID,
37     T_LCURLY,
38     T_RCURLY,
39     T_COLON,
40     T_SEMICOLON,
41     T_ERROR
42   };
43
44 struct css_token
45   {
46     enum css_token_type type;
47     char *s;
48   };
49
50 static char *
51 css_skip_spaces (char *p)
52 {
53   for (;;)
54     {
55       if (c_isspace (*p))
56         p++;
57       else if (!strncmp (p, "<!--", 4))
58         p += 4;
59       else if (!strncmp (p, "-->", 3))
60         p += 3;
61       else
62         return p;
63     }
64 }
65
66 static bool
67 css_is_separator (unsigned char c)
68 {
69   return c_isspace (c) || strchr ("{}:;", c);
70 }
71
72 static void
73 css_token_get (char **p_, struct css_token *token)
74 {
75   char *p = *p_;
76
77   free (token->s);
78   token->s = NULL;
79
80   p = css_skip_spaces (p);
81   if (*p == '\0')
82     token->type = T_EOF;
83   else if (*p == '{')
84     {
85       token->type = T_LCURLY;
86       p++;
87     }
88   else if (*p == '}')
89     {
90       token->type = T_RCURLY;
91       p++;
92     }
93   else if (*p == ':')
94     {
95       token->type = T_COLON;
96       p++;
97     }
98   else if (*p == ';')
99     {
100       token->type = T_SEMICOLON;
101       p++;
102     }
103   else
104     {
105       token->type = T_ID;
106       char *start = p;
107       while (!css_is_separator (*p))
108         p++;
109       token->s = xmemdup0 (start, p - start);
110     }
111   *p_ = p;
112 }
113
114 static void
115 css_decode_key_value (const char *key, const char *value,
116                       struct font_style *font)
117 {
118   if (!strcmp (key, "color"))
119     {
120       struct cell_color color;
121       if (parse_color__ (value, &color))
122         font->fg[0] = font->bg[0] = color;
123     }
124   else if (!strcmp (key, "font-weight"))
125     font->bold = !strcmp (value, "bold");
126   else if (!strcmp (key, "font-style"))
127     font->italic = !strcmp (value, "italic");
128   else if (!strcmp (key, "font-decoration"))
129     font->underline = !strcmp (value, "underline");
130   else if (!strcmp (key, "font-family"))
131     {
132       free (font->typeface);
133       font->typeface = xstrdup (value);
134     }
135   else if (!strcmp (key, "font-size"))
136     font->size = atoi (value) * 3 / 4;
137
138   /* bg_color */
139
140 }
141
142 char *
143 spv_parse_css_style (char *style, struct font_style *font)
144 {
145   *font = (struct font_style) FONT_STYLE_INITIALIZER;
146
147   char *p = style;
148   struct css_token token = { .s = NULL };
149   css_token_get (&p, &token);
150   while (token.type != T_EOF)
151     {
152       if (token.type != T_ID || !strcmp (token.s, "p"))
153         {
154           css_token_get (&p, &token);
155           continue;
156         }
157
158       char *key = token.s;
159       token.s = NULL;
160       css_token_get (&p, &token);
161
162       if (token.type == T_COLON)
163         {
164           struct string value = DS_EMPTY_INITIALIZER;
165           for (;;)
166             {
167               css_token_get (&p, &token);
168               if (token.type != T_ID)
169                 break;
170               if (!ds_is_empty (&value))
171                 ds_put_byte (&value, ' ');
172               ds_put_cstr (&value, token.s);
173             }
174
175           css_decode_key_value (key, ds_cstr (&value), font);
176
177           ds_destroy (&value);
178         }
179       free (key);
180     }
181   return NULL;
182 }