Root/eeshow/kicad/pl-parse.c

1/*
2 * kicad/pl-parse.c - KiCad page layout parser
3 *
4 * Written 2016 by Werner Almesberger
5 * Copyright 2016 by 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 <stdbool.h>
15#include <stdlib.h>
16#include <string.h>
17
18#include "misc/util.h"
19#include "misc/diag.h"
20#include "gfx/text.h"
21#include "file/file.h"
22#include "kicad/sexpr.h"
23#include "kicad/pl-common.h"
24#include "kicad/pl.h"
25
26
27static bool get_coord(const struct expr *e,
28    float *x, float *y, int *dx, int *dy)
29{
30    unsigned n = 0;
31
32    *dx = -1;
33    *dy = -1;
34    for (; e; e = e->next) {
35        if (e->e) {
36            warning("coord: ignoring list");
37            continue;
38        }
39
40        if (!strcmp(e->s, "ltcorner")) {
41            *dx = *dy = 1;
42        } else if (!strcmp(e->s, "lbcorner")) {
43            *dx = 1;
44            *dy = -1;
45        } else if (!strcmp(e->s, "rtcorner")) {
46            *dx = -1;
47            *dy = 1;
48        } else if (!strcmp(e->s, "rbcorner")) {
49            *dx = *dy = -1;
50        } else {
51            char *end;
52            float f = strtof(e->s, &end);
53
54            if (*end) {
55                error("coord: no a number \"%s\"", e->s);
56                return 0;
57            }
58            if (n++)
59                *y = f;
60            else
61                *x = f;
62        }
63    }
64
65    switch (n) {
66    case 0:
67    case 1:
68        error("coord: no enough coordinates");
69        return 0;
70    case 2:
71        return 1;
72    default:
73        error("coord: too many coordinates");
74        return 0;
75    }
76}
77
78
79static bool get_size(const struct expr *e, float *x, float *y)
80{
81    unsigned n = 0;
82
83    for (; e; e = e->next) {
84        char *end;
85        float f;
86
87        if (e->e) {
88            warning("size: ignoring list");
89            continue;
90        }
91
92        f = strtof(e->s, &end);
93        if (*end) {
94            error("size: no a number \"%s\"", e->s);
95            return 0;
96        }
97        if (n++)
98            *y = f;
99        else
100            *x = f;
101    }
102
103    switch (n) {
104    case 0:
105    case 1:
106        error("size: no enough coordinates");
107        return 0;
108    case 2:
109        return 1;
110    default:
111        error("size: too many coordinates");
112        return 0;
113    }
114}
115
116
117static bool get_float(const struct expr *e, float *f)
118{
119    for (; e; e = e->next)
120        if (e->s) {
121            *f = atof(e->s); // @@@ error checking
122            return 1;
123        }
124    error("no number found");
125    return 0;
126}
127
128
129
130static bool get_int(const struct expr *e, int *n)
131{
132    for (; e; e = e->next)
133        if (e->s) {
134            *n = atoi(e->s); // @@@ error checking
135            return 1;
136        }
137    error("no number foundn");
138    return 0;
139}
140
141
142static bool process_setup(struct pl_ctx *pl, const struct expr *e)
143{
144    const char *s;
145    const struct expr *next;
146
147    for (; e; e = e->next) {
148        if (!e->e) {
149            warning("setup: ignoring non-list");
150            continue;
151        }
152
153        s = e->e->s;
154        next = e->e->next;
155
156        if (!strcmp(s, "comment"))
157            continue;
158
159        if (!strcmp(s, "textsize")) {
160            if (!get_size(next, &pl->tx, &pl->ty))
161                return 0;
162        } else if (!strcmp(s, "linewidth")) {
163            // meh
164        } else if (!strcmp(s, "textlinewidth")) {
165            // meh
166        } else if (!strcmp(s, "left_margin")) {
167            if (!get_float(next, &pl->l))
168                return 0;
169        } else if (!strcmp(s, "right_margin")) {
170            if (!get_float(next, &pl->r))
171                return 0;
172        } else if (!strcmp(s, "top_margin")) {
173            if (!get_float(next, &pl->t))
174                return 0;
175        } else if (!strcmp(s, "bottom_margin")) {
176            if (!get_float(next, &pl->b))
177                return 0;
178        } else {
179            warning("setup: ignoring \"%s\"", s);
180        }
181    }
182    return 1;
183}
184
185
186static bool process_font(struct pl_obj *obj, const struct expr *e)
187{
188    const char *s;
189    const struct expr *next;
190
191    for (; e; e = e->next) {
192        if (e->s) {
193            if (!strcmp(e->s, "bold"))
194                obj->font |= font_bold;
195            else if (!strcmp(e->s, "italic"))
196                obj->font |= font_italic;
197            else
198                warning("font: ignoring \"%s\"", e->s);
199            continue;
200        }
201
202        if (!e->e) {
203            warning("font: ignoring empty list");
204            continue;
205        }
206        s = e->e->s;
207        next = e->e->next;
208
209        if (!strcmp(s, "comment"))
210            continue;
211
212        if (!strcmp(s, "size")) {
213            if (!get_size(next, &obj->ex, &obj->ey))
214                return 0;
215        } else {
216            warning("font: ignoring \"%s\"", s);
217        }
218    }
219    return 1;
220}
221
222
223static bool process_justify(struct pl_obj *obj, const struct expr *e)
224{
225    for (; e; e = e->next) {
226        if (e->e) {
227            warning("justify: ignoring list");
228            continue;
229        }
230
231        if (!strcmp(e->s, "center"))
232            obj->hor = obj->vert = text_mid;
233        else if (!strcmp(e->s, "left"))
234            obj->hor = text_min;
235        else if (!strcmp(e->s, "right"))
236            obj->hor = text_max;
237        else if (!strcmp(e->s, "top"))
238            obj->vert = text_max;
239        else if (!strcmp(e->s, "bottom"))
240            obj->vert = text_min;
241        else
242            warning("justify: ignoring \"%s\"", e->s);
243    }
244    return 1;
245}
246
247
248static bool process_obj(struct pl_ctx *pl, const struct expr *e,
249    enum pl_obj_type type)
250{
251    struct pl_obj *obj;
252    const char *s;
253    const struct expr *next;
254
255    obj = alloc_type(struct pl_obj);
256    obj->type = type;
257    obj->s = NULL;
258    obj->repeat = 1;
259    obj->x = obj->y = obj->ex = obj->ey = 0;
260    obj->dx = obj->dy = obj->edx = obj->edy = 0;
261    obj->incrx = 0;
262    obj->incry = 0;
263    obj->incrlabel = 0;
264    obj->font = 0;
265    obj->hor = text_min;
266    obj->vert = text_mid;
267
268    for (; e; e = e->next) {
269        if (e->s) {
270            if (obj->s) {
271                error("pl_obj: multiple strings");
272                return 0;
273            }
274            obj->s = stralloc(e->s);
275            continue;
276        }
277        if (!e->e) {
278            warning("pl_obj: ignoring empty list");
279            continue;
280        }
281
282        s = e->e->s;
283        next = e->e->next;
284
285        if (!strcmp(s, "comment"))
286            continue;
287        if (!strcmp(s, "name"))
288            continue;
289
290        if (!strcmp(s, "linewidth")) {
291            // meh
292        } else if (!strcmp(s, "start") || !strcmp(s, "pos")) {
293            if (!get_coord(next, &obj->x, &obj->y,
294                &obj->dx, &obj->dy))
295                return 0;
296        } else if (!strcmp(s, "end")) {
297            if (!get_coord(next, &obj->ex, &obj->ey,
298                &obj->edx, &obj->edy))
299                return 0;
300        } else if (!strcmp(s, "repeat")) {
301            if (!get_int(next, &obj->repeat))
302                return 0;
303        } else if (!strcmp(s, "incrx")) {
304            if (!get_float(next, &obj->incrx))
305                return 0;
306        } else if (!strcmp(s, "incry")) {
307            if (!get_float(next, &obj->incry))
308                return 0;
309        } else if (!strcmp(s, "incrlabel")) {
310            if (!get_int(next, &obj->incrlabel))
311                return 0;
312        } else if (!strcmp(s, "font")) {
313            if (!process_font(obj, next))
314                return 0;
315        } else if (!strcmp(s, "justify")) {
316            if (!process_justify(obj, next))
317                return 0;
318        } else
319            warning("pl_obj: ignoring \"%s\"", s);
320    }
321
322    obj->next = pl->objs;
323    pl->objs = obj;
324
325    return 1;
326}
327
328
329static bool process_layout(struct pl_ctx *pl, const struct expr *e)
330{
331    const char *s;
332    const struct expr *next;
333
334    for (; e; e = e->next) {
335        if (!e->e) {
336            warning("layout: ignoring non-list");
337            continue;
338        }
339
340        s = e->e->s;
341        next = e->e->next;
342
343        if (!strcmp(s, "comment"))
344            continue;
345        if (!strcmp(s, "setup")) {
346            if (!process_setup(pl, next))
347                return 0;
348        } else if (!strcmp(s, "rect")) {
349            if (!process_obj(pl, next, pl_obj_rect))
350                return 0;
351        } else if (!strcmp(s, "line")) {
352            if (!process_obj(pl, next, pl_obj_line))
353                return 0;
354        } else if (!strcmp(s, "tbtext")) {
355            if (!process_obj(pl, next, pl_obj_text))
356                return 0;
357        } else {
358            warning("layout: ignoring \"%s\"", s);
359        }
360    }
361    return 1;
362}
363
364
365static bool process(struct pl_ctx *p, const struct expr *e)
366{
367    while (e) {
368        if (e->e && e->e->s && !strcmp(e->e->s, "page_layout") &&
369            e->e->next && e->e->next->e)
370            return process_layout(p, e->e->next);
371        e = e->next;
372    }
373    error("no layout information found");
374    return 0;
375}
376
377
378static bool pl_parse_line(const struct file *file,
379    void *user, const char *line)
380{
381    struct pl_ctx *pl = user;
382
383    return sexpr_parse(pl->sexpr_ctx, line);
384}
385
386
387struct pl_ctx *pl_parse(struct file *file)
388{
389    struct pl_ctx *pl;
390    struct expr *e = NULL;
391
392    pl = alloc_type(struct pl_ctx);
393    pl->sexpr_ctx = sexpr_new();
394    pl->l = pl->r = pl->t = pl->b = 0;
395    pl->tx = pl->ty = 0;
396    pl->objs = NULL;
397
398    if (!file_read(file, pl_parse_line, pl)) {
399        sexpr_abort(pl->sexpr_ctx);
400        goto fail;
401    }
402    if (!sexpr_finish(pl->sexpr_ctx, &e))
403        goto fail;
404    if (!process(pl, e))
405        goto fail;
406    free_expr(e);
407    return pl;
408
409fail:
410    free_expr(e);
411    free(pl);
412    return 0;
413}
414
415
416void pl_free(struct pl_ctx *pl)
417{
418    struct pl_obj *next;
419
420    while (pl->objs) {
421        next = pl->objs->next;
422        free((void *) pl->objs->s);
423        free(pl->objs);
424        pl->objs = next;
425    }
426    free(pl);
427}
428

Archive Download this file

Branches:
master



interactive