/* * sch.c - Parse Eeschema .sch file * * Written 2016 by Werner Almesberger * Copyright 2016 by Werner Almesberger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include "util.h" #include "misc.h" #include "style.h" #include "fig.h" #include "lib.h" #include "sch.h" /* ----- (Global) Labels --------------------------------------------------- */ static enum fig_shape do_decode_shape(const char *s) { if (!strcmp(s, "UnSpc")) return fig_unspec; if (!strcmp(s, "Input")) return fig_in; if (!strcmp(s, "Output")) return fig_out; if (!strcmp(s, "3State")) return fig_tri; if (!strcmp(s, "BiDi")) return fig_bidir; fprintf(stderr, "unknown shape: \"%s\"\n", s); exit(1); } static enum fig_shape decode_shape(const char *s) { enum fig_shape res; res = do_decode_shape(s); free((void *) s); return res; } /* ----- Text -------------------------------------------------------------- */ static void draw_text(int x, int y, const char *s, int dir, int dim, enum fig_shape shape) { struct text txt = { .s = s, .size = dim, .x = x, .y = y, .rot = 0, .hor = text_min, .vert = text_min, }; switch (dir) { case 0: /* right */ break; case 1: /* up */ text_rot(&txt, 90); break; case 2: /* left */ txt.hor = text_max; break; case 3: /* down */ text_rot(&txt, 90); txt.hor = text_max; break; default: assert(2 + 2 == 5); } text_fig(&txt, COLOR_TEXT, LAYER_TEXT); } /* ----- Component fields -------------------------------------------------- */ struct sch_field { struct text txt; struct sch_field *next; }; void decode_alignment(struct text *txt, char hor, char vert) { switch (hor) { case 'L': txt->hor = text_min; break; case 'C': txt->hor = text_mid; break; case 'R': txt->hor = text_max; break; default: assert(0); } switch (vert) { case 'B': txt->vert = text_min; break; case 'C': txt->vert = text_mid; break; case 'T': txt->vert = text_max; break; default: assert(0); } } static bool parse_field(struct sch_ctx *ctx, const char *line) { int n; unsigned flags; char hv, hor, vert, italic, bold; struct sch_field *field; struct text *txt; field = alloc_type(struct sch_field); txt = &field->txt; if (sscanf(line, "F %d \"\" %c %d %d %u %u %c %c%c%c", &n, &hv, &txt->x, &txt->y, &txt->size, &flags, &hor, &vert, &italic, &bold) == 10) { free(field); return 1; } if (sscanf(line, "F %d \"%m[^\"]\" %c %d %d %u %u %c %c%c%c", &n, &txt->s, &hv, &txt->x, &txt->y, &txt->size, &flags, &hor, &vert, &italic, &bold) != 11) return 0; if (flags || !lib_field_visible(ctx->comp, n)) { free(field); return 1; } if (n == 0 && ctx->comp->units > 1) { int len = strlen(txt->s); char *s; s = realloc((void *) txt->s, len + 3); if (!s) { perror("realloc"); exit(1); } if (ctx->unit <= 26) sprintf(s + len, "%c", 'A' + ctx->unit - 1); else sprintf(s + len, "%c%c", 'A' + (ctx->unit - 1) / 26 - 1, 'A' + (ctx->unit - 1) % 26); txt->s = s; } field->next = ctx->fields; ctx->fields = field; switch (hv) { case 'H': txt->rot = 0; break; case 'V': txt->rot = 90; break; default: assert(0); } decode_alignment(txt, hor, vert); // @@@ decode font return 1; } static void dump_field(const struct sch_field *field, int m[6]) { struct text txt = field->txt; int dx, dy; dx = txt.x - m[0]; dy = txt.y - m[3]; txt.x = mx(dx, dy, m); txt.y = my(dx, dy, m); text_rot(&txt, matrix_to_angle(m)); switch (txt.rot) { case 180: text_rot(&txt, 180); txt.hor = text_flip(txt.hor); txt.vert = text_flip(txt.vert); break; case 270: text_rot(&txt, 180); txt.vert = text_flip(txt.vert); txt.hor = text_flip(txt.hor); break; default: break; } if (matrix_is_mirrored(m)) { if ((txt.rot % 180) == 0) txt.hor = text_flip(txt.hor); else txt.vert = text_flip(txt.vert); } text_fig(&txt, COLOR_FIELD, LAYER_FIELD); } static void dump_fields(struct sch_field *fields, int m[6]) { while (fields) { struct text *txt = &fields->txt; struct sch_field *next = fields->next; dump_field(fields, m); text_free(txt); free(fields); fields = next; } } /* ----- Schematics parser ------------------------------------------------- */ bool sch_parse(struct sch_ctx *ctx, const char *line) { int n = 0; int x, y, ex, ey; char *s; int m[4]; ctx->lineno++; switch (ctx->state) { case sch_basic: if (sscanf(line, "$Comp%n", &n) == 0 && n) { ctx->state = sch_comp; ctx->fields = NULL; return 1; } if (sscanf(line, "$Sheet%n", &n) == 0 && n) { ctx->state = sch_sheet; return 1; } /* Text */ if (sscanf(line, "Text Notes %d %d %d %d", &ctx->x, &ctx->y, &ctx->dir, &ctx->dim) == 4) { ctx->state = sch_text; ctx->text = draw_text; return 1; } if (sscanf(line, "Text GLabel %d %d %d %d %ms", &ctx->x, &ctx->y, &ctx->dir, &ctx->dim, &s) == 5) { ctx->state = sch_text; ctx->shape = decode_shape(s); ctx->text = fig_glabel; return 1; } if (sscanf(line, "Text HLabel %d %d %d %d %ms", &ctx->x, &ctx->y, &ctx->dir, &ctx->dim, &s) == 5) { ctx->state = sch_text; unsupported("Text HLabel"); ctx->text = NULL; return 1; } if (sscanf(line, "Text Label %d %d %d %d", &ctx->x, &ctx->y, &ctx->dir, &ctx->dim) == 4) { ctx->state = sch_text; ctx->text = fig_label; return 1; } if (sscanf(line, "Entry Wire Line%n", &n) == 0 && n) { ctx->state = sch_text; unsupported("Entry Wire Line"); ctx->text = NULL; return 1; } if (sscanf(line, "Entry Bus Bus%n", &n) == 0 && n) { ctx->state = sch_text; unsupported("Entry Bus Bus"); ctx->text = NULL; return 1; } /* Connection */ if (sscanf(line, "Connection ~ %d %d", &x, &y) == 2) { fig_junction(x, y); return 1; } /* NoConn */ if (sscanf(line, "NoConn ~ %d %d", &x, &y) == 2) { fig_noconn(x, y); return 1; } /* Wire */ if (sscanf(line, "Wire Wire Line%n", &n) == 0 && n) { ctx->state = sch_wire; ctx->wire = fig_wire; return 1; } if (sscanf(line, "Wire Bus Line%n", &n) == 0 && n) { ctx->state = sch_wire; unsupported("Wire Bus Line"); ctx->wire = NULL; return 1; } if (sscanf(line, "Wire Notes Line%n", &n) == 0 && n) { ctx->state = sch_wire; ctx->wire = fig_line; return 1; } if (sscanf(line, "Wire Wire Bus%n", &n) == 0 && n) { ctx->state = sch_wire; unsupported("Wire Wire Bus"); ctx->wire = NULL; return 1; } if (sscanf(line, "Wire Bus Bus%n", &n) == 0 && n) { ctx->state = sch_wire; unsupported("Wire Bus Bus"); ctx->wire = NULL; return 1; } /* EndSCHEMATC */ if (sscanf(line, "$EndSCHEMATC%n", &n) == 0 && n) return 0; break; case sch_descr: if (sscanf(line, "$EndDescr%n", &n) || !n) return 1; ctx->state = sch_basic; return 1; case sch_comp: if (sscanf(line, "$EndComp%n", &n) == 0 && n) { ctx->state = sch_basic; ctx->comp = NULL; return 1; } if (sscanf(line, "L %ms", &s) == 1) { ctx->comp = lib_find(s); free(s); return 1; } if (sscanf(line, "U %u", &ctx->unit) == 1) return 1; if (sscanf(line, "P %d %d", &ctx->x, &ctx->y) == 2) return 1; if (parse_field(ctx, line)) return 1; if (sscanf(line, "AR %n", &n) == 0 && n) return 1; /* @@@ what is "AR" ? */ n = sscanf(line, " %d %d %d %d", m + 1, m + 2, m + 4, m + 5); if (n == 3) return 1; if (n == 4) { m[0] = ctx->x; m[3] = ctx->y; lib_exec(ctx->comp, ctx->unit, m); dump_fields(ctx->fields, m); return 1; } break; case sch_sheet: if (sscanf(line, "$EndSheet%n", &n) || !n) return 1; ctx->state = sch_basic; return 1; case sch_text: ctx->state = sch_basic; if (ctx->text) ctx->text(ctx->x, ctx->y, line, ctx->dir, ctx->dim, ctx->shape); return 1; case sch_wire: if (sscanf(line, "%d %d %d %d", &x, &y, &ex, &ey) != 4) break; if (ctx->wire) ctx->wire(x, y, ex, ey); ctx->state = sch_basic; return 1; default: abort(); } fprintf(stderr, "%u: cannot parse\n\"%s\"\n", ctx->lineno, line); exit(1); } void sch_init(struct sch_ctx *ctx) { ctx->state = sch_descr; ctx->lineno = 0; }