Get rid of spctx completely
[colloquium.git] / libstorycode / storycode.c
1 /*
2  * storycode.c
3  *
4  * Copyright © 2019 Thomas White <taw@bitwiz.org.uk>
5  *
6  * This file is part of Colloquium.
7  *
8  * Colloquium is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <gio/gio.h>
31
32 #include "narrative.h"
33 #include "slide.h"
34 #include "stylesheet.h"
35 #include "narrative_priv.h"
36 #include "slide_priv.h"
37
38 #include "storycode_parse.h"
39 #include "storycode_lex.h"
40
41
42 extern int scdebug;
43
44
45 Narrative *storycode_parse_presentation(const char *sc)
46 {
47         YY_BUFFER_STATE b;
48         Narrative *n;
49
50         b = sc_scan_string(sc);
51         //scdebug = 1;
52         n = narrative_new();
53         scparse(n);
54         sc_delete_buffer(b);
55         //narrative_debug(n);
56
57         return n;
58 }
59
60
61 static int write_string(GOutputStream *fh, char *str)
62 {
63         gssize r;
64         GError *error = NULL;
65         r = g_output_stream_write(fh, str, strlen(str), NULL, &error);
66         if ( r == -1 ) {
67                 fprintf(stderr, "Write failed: %s\n", error->message);
68                 return 1;
69         }
70         return 0;
71 }
72
73
74 char unitc(enum length_unit unit)
75 {
76         if ( unit == LENGTH_FRAC ) return 'f';
77         if ( unit == LENGTH_UNIT ) return 'u';
78         return '?';
79 }
80
81
82 const char *bgcolc(enum gradient bggrad)
83 {
84         if ( bggrad == GRAD_NONE ) return "";
85         if ( bggrad == GRAD_HORIZ ) return "HORIZONTAL ";
86         if ( bggrad == GRAD_VERT ) return "VERTICAL ";
87         return "?";
88 }
89
90
91 const char *alignc(enum alignment ali)
92 {
93         if ( ali == ALIGN_LEFT ) return "left";
94         if ( ali == ALIGN_CENTER ) return "center";
95         if ( ali == ALIGN_RIGHT ) return "right";
96         return "?";
97 }
98
99
100 static const char *maybe_alignment(enum alignment ali)
101 {
102         if ( ali == ALIGN_INHERIT ) return "";
103         if ( ali == ALIGN_LEFT ) return "[left]";
104         if ( ali == ALIGN_CENTER ) return "[center]";
105         if ( ali == ALIGN_RIGHT ) return "[right]";
106         return "[?]";
107 }
108
109
110 static void write_run_border(GOutputStream *fh, enum text_run_type t)
111 {
112         if ( t == TEXT_RUN_BOLD ) write_string(fh, "*");
113         if ( t == TEXT_RUN_ITALIC ) write_string(fh, "/");
114         if ( t == TEXT_RUN_UNDERLINE ) write_string(fh, "_");
115 }
116
117
118 static char *escape_text(const char *in)
119 {
120         int i, j;
121         size_t len;
122         size_t nl = 0;
123         size_t np = 0;
124         const char *esc = "*/_";
125         size_t n_esc = 3;
126         char *out;
127
128         len = strlen(in);
129         for ( i=0; i<len; i++ ) {
130                 for ( j=0; j<n_esc; j++ ) {
131                         if ( in[i] == esc[j] ) {
132                                 nl++;
133                                 break;
134                         }
135                 }
136         }
137
138         out = malloc(len + nl + 1);
139         if ( out == NULL ) return NULL;
140
141         np = 0;
142         for ( i=0; i<=len; i++ ) {
143                 for ( j=0; j<n_esc; j++ ) {
144                         if ( in[i] == esc[j] ) {
145                                 out[np++] = '\\';
146                                 break;
147                         }
148                 }
149                 out[np++] = in[i];
150         }
151
152         return out;
153 }
154
155
156 static void write_para(GOutputStream *fh, struct text_run *runs, int n_runs)
157 {
158         int i;
159         for ( i=0; i<n_runs; i++ ) {
160                 char *escaped_str;
161                 write_run_border(fh, runs[i].type);
162                 escaped_str = escape_text(runs[i].text);
163                 write_string(fh, escaped_str);
164                 free(escaped_str);
165                 write_run_border(fh, runs[i].type);
166         }
167 }
168
169
170 static void write_text(GOutputStream *fh, SlideItem *item, int geom,
171                        const char *t)
172 {
173         char tmp[256];
174         size_t indent;
175         int i;
176
177         if ( geom ) {
178                 snprintf(tmp, 255, "  %s[%.4g%cx%.4g%c+%.4g%c+%.4g%c]%s", t,
179                          item->geom.w.len, unitc(item->geom.w.unit),
180                          item->geom.h.len, unitc(item->geom.h.unit),
181                          item->geom.x.len, unitc(item->geom.x.unit),
182                          item->geom.y.len, unitc(item->geom.y.unit),
183                          maybe_alignment(item->align));
184         } else {
185                 snprintf(tmp, 255, "  %s%s",
186                          t, maybe_alignment(item->align));
187         }
188
189         indent = strlen(tmp);
190         write_string(fh, tmp);
191         write_string(fh, ": ");
192         write_para(fh, item->paras[0].runs, item->paras[0].n_runs);
193         write_string(fh, "\n");
194         for ( i=0; i<indent; i++ ) tmp[i] = ' ';
195         for ( i=1; i<item->n_paras; i++ ) {
196                 write_string(fh, tmp);
197                 write_string(fh, ": ");
198                 write_para(fh, item->paras[i].runs, item->paras[i].n_runs);
199                 write_string(fh, "\n");
200         }
201 }
202
203
204 static void write_image(GOutputStream *fh, SlideItem *item)
205 {
206         char tmp[256];
207
208         snprintf(tmp, 255, "  IMAGE[%.4g%cx%.4g%c+%.4g%c+%.4g%c]",
209                  item->geom.w.len, unitc(item->geom.w.unit),
210                  item->geom.h.len, unitc(item->geom.h.unit),
211                  item->geom.x.len, unitc(item->geom.x.unit),
212                  item->geom.y.len, unitc(item->geom.y.unit));
213
214         write_string(fh, tmp);
215         write_string(fh, ": ");
216         write_string(fh, item->filename);
217         write_string(fh, "\n");
218 }
219
220
221 static int write_slide(GOutputStream *fh, Slide *s)
222 {
223         int i;
224
225         for ( i=0; i<s->n_items; i++ ) {
226                 switch ( s->items[i].type ) {
227
228                         case SLIDE_ITEM_TEXT:
229                         write_text(fh, &s->items[i], 1, "TEXT");
230                         break;
231
232                         case SLIDE_ITEM_PRESTITLE:
233                         write_text(fh, &s->items[i], 0, "PRESTITLE");
234                         break;
235
236                         case SLIDE_ITEM_SLIDETITLE:
237                         write_text(fh, &s->items[i], 0, "SLIDETITLE");
238                         break;
239
240                         case SLIDE_ITEM_FOOTER:
241                         write_string(fh, "  FOOTER\n");
242                         break;
243
244                         case SLIDE_ITEM_IMAGE:
245                         write_image(fh, &s->items[i]);
246                         break;
247
248                 }
249         }
250
251         return 0;
252 }
253
254
255 static int write_item(GOutputStream *fh, struct narrative_item *item)
256 {
257         switch ( item->type ) {
258
259                 case NARRATIVE_ITEM_TEXT:
260                 /* FIXME: separate alignment */
261                 if ( write_string(fh, ": ") ) return 1;
262                 write_para(fh, item->runs, item->n_runs);
263                 if ( write_string(fh, "\n") ) return 1;
264                 break;
265
266                 case NARRATIVE_ITEM_PRESTITLE:
267                 /* FIXME: separate alignment */
268                 if ( write_string(fh, "PRESTITLE: ") ) return 1;
269                 write_para(fh, item->runs, item->n_runs);
270                 if ( write_string(fh, "\n") ) return 1;
271                 break;
272
273                 case NARRATIVE_ITEM_BP:
274                 /* FIXME: separate alignment */
275                 if ( write_string(fh, "BP: ") ) return 1;
276                 write_para(fh, item->runs, item->n_runs);
277                 if ( write_string(fh, "\n") ) return 1;
278                 break;
279
280                 case NARRATIVE_ITEM_SLIDE:
281                 /* FIXME: separate slide size */
282                 if ( write_string(fh, "SLIDE {\n") ) return 1;
283                 if ( write_slide(fh, item->slide) ) return 1;
284                 if ( write_string(fh, "}\n") ) return 1;
285                 break;
286
287                 case NARRATIVE_ITEM_EOP:
288                 if ( write_string(fh, "ENDOFPRESENTATION\n") ) return 1;
289                 break;
290
291         }
292         return 0;
293 }
294
295
296 int storycode_write_presentation(Narrative *n, GOutputStream *fh)
297 {
298         int i;
299         char *ss_text;
300
301         /* Stylesheet */
302         ss_text = stylesheet_serialise(n->stylesheet);
303         if ( ss_text == NULL ) return 1;
304         if ( write_string(fh, ss_text) ) return 1;
305
306         if ( write_string(fh, "\n") ) return 1;
307
308         for ( i=0; i<n->n_items; i++ ) {
309                 if ( write_item(fh, &n->items[i]) ) return 1;
310         }
311
312         return 0;
313 }