Root/tools/libant/edit.c

Source at commit 0e9b093d2ee3f8195e9848f5a931c2068d37e59f created 11 years 1 day ago.
By Werner Almesberger, tornado/cpu/cpu.brd: improve 3V3 routing
1/*
2 * tools/libant/edit.c - Editing and rendering
3 *
4 * Written 2012 by Werner Almesberger
5 * Copyright 2012 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <stdint.h>
15#include <stdlib.h>
16#include <string.h>
17#include <sys/types.h>
18
19#include "util.h"
20#include "libant.h"
21
22
23#define DEFAULT_FONT "5x7"
24
25
26/* ----- Render a list of editing instructions ----------------------------- */
27
28
29struct font_dir {
30    const char *name;
31    struct font_dir *next;
32} *font_path = NULL, **last_font_dir = &font_path;
33
34
35void add_font_dir(const char *name)
36{
37    struct font_dir *dir;
38
39    dir = alloc_type(struct font_dir);
40    dir->name = strdup(name);
41    if (!dir->name)
42        abort();
43    dir->next = NULL;
44    *last_font_dir = dir;
45    last_font_dir = &dir->next;
46}
47
48
49static struct image *find_font_image(const char *name, const char **error)
50{
51    struct image *img;
52    const char *err;
53    const struct font_dir *dir;
54    FILE *file;
55    char *path;
56
57    img = load_image(name, error);
58    if (img)
59        return img;
60    if (error)
61        err = *error;
62    for (dir = font_path; dir; dir = dir->next) {
63        asprintf(&path, "%s/%s.xbm", dir->name, name);
64        file = fopen(path, "r");
65        if (!file)
66            continue;
67        img = load_image_file(file, error);
68        fclose(file);
69        return img;
70    }
71    if (error)
72        *error = err;
73    return NULL;
74}
75
76
77static struct font *load_font(const char *name, const char **error)
78{
79    struct image *img;
80
81    img = find_font_image(name, error);
82    if (!img)
83        return NULL;
84    return make_font(img, error);
85}
86
87
88static int do_edit(uint8_t *canvas, int width, int height,
89    const struct edit *e, const char **error)
90{
91    struct image *img;
92    struct font *font = NULL;
93    int x = 0, y = 0, max = 0;
94    int spc = 1;
95    const char *s;
96    int xo, yo;
97
98    while (e) {
99        switch (e->type) {
100        case edit_string:
101            if (!font) {
102                font = load_font(DEFAULT_FONT, error);
103                if (!font)
104                    goto fail;
105            }
106            for (s = e->u.s; *s; s++) {
107                xo = draw_char(canvas, width, height,
108                    font, *s, x, y);
109                yo = char_height(font, *s);
110                if (yo > max)
111                    max = yo;
112                x += xo+spc;
113            }
114            break;
115        case edit_font:
116            free_font(font);
117            font = load_font(e->u.s, error);
118            if (!font)
119                goto fail;
120            break;
121        case edit_img:
122            img = load_image(e->u.s, error);
123            if (!img)
124                return 0;
125            xo = draw_image(canvas, width, height, img, x, y);
126            free_image(img);
127            x += xo;
128            break;
129        case edit_spc:
130            spc = e->u.n;
131            break;
132        case edit_xoff:
133            x += e->u.n;
134            break;
135        case edit_xpos:
136            x = e->u.n;
137            break;
138        case edit_yoff:
139            y += e->u.n;
140            break;
141        case edit_ypos:
142            y = e->u.n;
143            break;
144        case edit_nl:
145            x = 0;
146            y += max+1;
147            max = 0;
148            break;
149        default:
150            abort();
151        }
152        e = e->next;
153    }
154    return 1;
155
156fail:
157    free_font(font);
158    return 0;
159}
160
161
162void *apply_edits(int width, int height, const struct edit *e,
163    const char **error)
164{
165    uint8_t *canvas;
166
167    canvas = calloc(1, (width*height+7) >> 3);
168    if (!canvas)
169        abort();
170    if (do_edit(canvas, width, height, e, error))
171        return canvas;
172    free(canvas);
173    return NULL;
174}
175
176
177/* ----- Compile editing instructions -------------------------------------- */
178
179
180static char *alloc_string_n(const char *s, size_t len)
181{
182    char *t;
183
184    t = alloc_size(len+1);
185    memcpy(t, s, len);
186    t[len] = 0;
187    return t;
188}
189
190
191static void add_string(struct edit ***last, const char *start, size_t len)
192{
193    struct edit *e;
194
195    e = alloc_type(struct edit);
196    e->type = edit_string;
197    e->u.s = alloc_string_n(start, len);
198    e->next = NULL;
199    **last = e;
200    *last = &e->next;
201}
202
203
204static const char *parse_coord(struct edit *e, const char *s,
205    enum edit_type off, enum edit_type pos)
206{
207    char *end;
208
209    if (!s[2])
210        return alloc_sprintf("incomplete %c tag", s[1]);
211    e->u.n = strtoul(s+3, &end, 0);
212    if (*end != '>')
213        return alloc_sprintf("invalid number in %c tag", s[1]);
214    switch (s[2]) {
215    case '-':
216        e->u.n = -e->u.n;
217        /* fall through */
218    case '+':
219        e->type = off;
220        break;
221    case '=':
222        e->type = pos;
223        break;
224    default:
225        return
226            alloc_sprintf("unrecognized positioning %c%c", s[1], s[2]);
227    }
228    return NULL;
229}
230
231
232static const char *parse_edit(struct edit **edits, const char *s)
233{
234    struct edit *e;
235    const char *start, *err;
236    int have_text = 0;
237    char *end;
238
239    start = s;
240    for (start = s; *s; s++) {
241        if (*s != '<' && *s != '\n')
242            continue;
243        if (s != start) {
244            add_string(&edits, start, s-start);
245            have_text = 1;
246        }
247        start = s+1;
248
249        if (*s == '\n' && !have_text)
250            continue;
251
252        e = alloc_type(struct edit);
253        e->type = edit_nl; /* pick something without data */
254        e->next = NULL;
255        *edits = e;
256        edits = &e->next;
257
258        if (*s == '\n') {
259            have_text = 0;
260            continue;
261        }
262
263        end = strchr(s, '>');
264        if (!end)
265            return alloc_sprintf("< without >");
266
267        switch (s[1]) {
268        case 'F':
269            if (strncmp(s, "<FONT ", 6))
270                goto fail_tag;
271            e->type = edit_font;
272            e->u.s = alloc_string_n(s+6, end-s-6);
273            break;
274        case 'I':
275            if (strncmp(s, "<IMG ", 5))
276                goto fail_tag;
277            e->type = edit_img;
278            e->u.s = alloc_string_n(s+5, end-s-5);
279            break;
280        case 'S':
281            if (strncmp(s, "<SPC ", 5))
282                goto fail_tag;
283            e->type = edit_spc;
284            e->u.n = strtoul(s+5, &end, 0);
285            if (*end != '>')
286                return
287                    alloc_sprintf("invalid number in SPC tag");
288            break;
289        case 'X':
290            err = parse_coord(e, s, edit_xoff, edit_xpos);
291            if (err)
292                return err;
293            break;
294        case 'Y':
295            err = parse_coord(e, s, edit_yoff, edit_ypos);
296            if (err)
297                return err;
298            break;
299        default:
300            goto fail_tag;
301        }
302        s = end;
303        start = s+1;
304    }
305    if (s != start)
306        add_string(&edits, start, s-start);
307    return NULL;
308
309fail_tag:
310    return alloc_sprintf("unrecognized tag in %.*s", end-s+1, s);
311}
312
313
314struct edit *text2edit(const char *s, const char **error)
315{
316    struct edit *edits = NULL;
317    const char *err;
318
319    err = parse_edit(&edits, s);
320    if (!err)
321        return edits;
322    if (error)
323        *error = err;
324    free_edits(edits);
325    return NULL;
326}
327
328
329/* ----- Free edit list ---------------------------------------------------- */
330
331
332void free_edits(struct edit *e)
333{
334    struct edit *next;
335
336    while (e) {
337        if (e->type == edit_font || e->type == edit_img)
338            free(e->u.s);
339        next = e->next;
340        free(e);
341        e = next;
342    }
343}
344

Archive Download this file

Branches:
master
tornado-v1



interactive