From 66ca318dbee60fde5a07a0d457049f059815bbe8 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Sun, 31 Jul 2016 01:48:31 -0300 Subject: [PATCH] sch2fig/sch.c: separate parsing from rendering --- sch2fig/main.c | 24 ++- sch2fig/sch.c | 409 ++++++++++++++++++++++++++++--------------------- sch2fig/sch.h | 86 +++++++---- 3 files changed, 306 insertions(+), 213 deletions(-) diff --git a/sch2fig/main.c b/sch2fig/main.c index 6467ad0..0284dca 100644 --- a/sch2fig/main.c +++ b/sch2fig/main.c @@ -69,6 +69,7 @@ static void usage(const char *name) int main(int argc, char **argv) { + struct sch_ctx sch_ctx; const char *template = NULL; char c; int arg; @@ -94,20 +95,17 @@ int main(int argc, char **argv) if (argc - optind < 1) usage(*argv); - //gfx_init(&fig_ops, template, n_vars, vars); - gfx_init(&cairo_ops, template, n_vars, vars); - for (arg = optind; arg != argc; arg++) { - if (arg == argc - 1) { - struct sch_ctx ctx; + for (arg = optind; arg != argc - 1; arg++) { + struct lib_ctx ctx; - sch_init(&ctx); - read_file(argv[arg], &ctx, do_sch_parse); - } else { - struct lib_ctx ctx; - - lib_init(&ctx); - read_file(argv[arg], &ctx, do_lib_parse); - } + lib_init(&ctx); + read_file(argv[arg], &ctx, do_lib_parse); } + + sch_init(&sch_ctx); + read_file(argv[argc - 1], &sch_ctx, do_sch_parse); + gfx_init(&fig_ops, template, n_vars, vars); + //gfx_init(&cairo_ops, template, n_vars, vars); + sch_render(&sch_ctx); gfx_end(); } diff --git a/sch2fig/sch.c b/sch2fig/sch.c index 50aa533..95c4f97 100644 --- a/sch2fig/sch.c +++ b/sch2fig/sch.c @@ -28,6 +28,157 @@ #include "sch.h" +/* ----- Rendering --------------------------------------------------------- */ + + +static void dump_field(const struct comp_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 do_hsheet_text(const struct sch_obj *obj, + const struct sch_sheet *sheet) +{ + char *s; + + assert(sheet->sheet && sheet->file); + + struct text sheet_txt = { + .size = sheet->sheet_dim, + .x = obj->x, + .y = obj->y, + .rot = 0, + .hor = text_min, + .vert = text_min, + }; + if (asprintf(&s, "Sheet: %s", sheet->sheet)) {} + sheet_txt.s = s; /* work around "const" mismatch */ + + struct text file_txt = { + .size = sheet->file_dim, + .x = obj->x, + .y = obj->y, + .rot = 0, + .hor = text_min, + .vert = text_max, + }; + if (asprintf(&s, "File: %s", sheet->file)) {} + file_txt.s = s; /* work around "const" mismatch */ + + if (sheet->rotated) { + sheet_txt.rot = file_txt.rot = 90; + sheet_txt.x -= HSHEET_FIELD_OFFSET; + sheet_txt.y += sheet->h; + file_txt.x += sheet->w + HSHEET_FIELD_OFFSET; + file_txt.y += sheet->h; + } else { + sheet_txt.y -= HSHEET_FIELD_OFFSET; + file_txt.y += sheet->h + HSHEET_FIELD_OFFSET; + } + + text_fig(&sheet_txt, COLOR_HSHEET_SHEET, LAYER_HSHEET_FIELD); + text_fig(&file_txt, COLOR_HSHEET_FILE, LAYER_HSHEET_FIELD); + +// free((void *) ctx->sheet); +// free((void *) ctx->file); +} + + +static void render_sheet(const struct sch_obj *obj, + const struct sch_sheet *sheet) +{ + const struct sheet_field *field; + + gfx_rect(obj->x, obj->y, obj->x + sheet->w, obj->y + sheet->h, + COLOR_HSHEET_BOX, COLOR_NONE, LAYER_HSHEET_BOX); + do_hsheet_text(obj, sheet); + + for (field = sheet->fields; field; field = field->next) + dwg_hlabel(obj->x, obj->y, field->s, + field->side, field->dim, + field->shape); + // free(field->s) +} + + +void sch_render(const struct sch_ctx *ctx) +{ + const struct sch_obj *obj; + + for (obj = ctx->objs; obj; obj = obj->next) + switch (obj->type) { + case sch_obj_wire: + { + const struct sch_wire *wire = &obj->u.wire; + + wire->fn(obj->x, obj->y, wire->ex, wire->ey); + } + break; + case sch_obj_junction: + dwg_junction(obj->x, obj->y); + break; + case sch_obj_noconn: + dwg_noconn(obj->x, obj->y); + break; + case sch_obj_text: + { + const struct sch_text *text = &obj->u.text; + + text->fn(obj->x, obj->y, text->s, text->dir, + text->dim, text->shape); + } + break; + case sch_obj_comp: + { + const struct sch_comp *comp = &obj->u.comp; + const struct comp_field *field; + + lib_exec(comp->comp, comp->unit, comp->m); + for (field = comp->fields; field; + field = field->next) + dump_field(field, comp->m); + } + break; + case sch_obj_sheet: + render_sheet(obj, &obj->u.sheet); + break; + } +} + + /* ----- (Global) Labels --------------------------------------------------- */ @@ -98,12 +249,6 @@ static void draw_text(int x, int y, const char *s, int dir, int dim, /* ----- Component fields -------------------------------------------------- */ -struct sch_field { - struct text txt; - struct sch_field *next; -}; - - void decode_alignment(struct text *txt, char hor, char vert) { switch (hor) { @@ -138,13 +283,14 @@ void decode_alignment(struct text *txt, char hor, char vert) static bool parse_field(struct sch_ctx *ctx, const char *line) { + struct sch_comp *comp = &ctx->obj.u.comp; int n; unsigned flags; char hv, hor, vert, italic, bold; - struct sch_field *field; + struct comp_field *field; struct text *txt; - field = alloc_type(struct sch_field); + field = alloc_type(struct comp_field); txt = &field->txt; if (sscanf(line, "F %d \"\" %c %d %d %u %u %c %c%c%c", @@ -158,12 +304,12 @@ static bool parse_field(struct sch_ctx *ctx, const char *line) &hor, &vert, &italic, &bold) != 11) return 0; - if (flags || !lib_field_visible(ctx->comp, n)) { + if (flags || !lib_field_visible(comp->comp, n)) { free(field); return 1; } - if (n == 0 && ctx->comp->units > 1) { + if (n == 0 && comp->comp->units > 1) { int len = strlen(txt->s); char *s; @@ -172,17 +318,16 @@ static bool parse_field(struct sch_ctx *ctx, const char *line) perror("realloc"); exit(1); } - if (ctx->unit <= 26) - sprintf(s + len, "%c", 'A' + ctx->unit - 1); + if (comp->unit <= 26) + sprintf(s + len, "%c", 'A' + comp->unit - 1); else sprintf(s + len, "%c%c", - 'A' + (ctx->unit - 1) / 26 - 1, - 'A' + (ctx->unit - 1) % 26); - txt->s = s; + 'A' + (comp->unit - 1) / 26 - 1, + 'A' + (comp->unit - 1) % 26); } - field->next = ctx->fields; - ctx->fields = field; + field->next = comp->fields; + comp->fields = field; switch (hv) { case 'H': @@ -203,59 +348,6 @@ static bool parse_field(struct sch_ctx *ctx, const char *line) } -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; - } -} - - /* ----- Sheet field ------------------------------------------------------- */ @@ -299,29 +391,34 @@ static int decode_side(char side) static bool parse_hsheet_field(struct sch_ctx *ctx, const char *line) { + struct sch_sheet *sheet = &ctx->obj.u.sheet; char *s; - int x, y; char form, side; unsigned n, dim; + struct sheet_field *field; if (sscanf(line, "F%d \"%m[^\"]\" %u", &n, &s, &dim) == 3) { switch (n) { case 0: - ctx->sheet = s; - ctx->sheet_dim = dim; + sheet->sheet = s; + sheet->sheet_dim = dim; return 1; case 1: - ctx->file = s; - ctx->file_dim = dim; + sheet->file = s; + sheet->file_dim = dim; return 1; default: assert(0); } } + field = alloc_type(struct sheet_field); if (sscanf(line, "F%d \"%m[^\"]\" %c %c %d %d %u", - &n, &s, &form, &side, &x, &y, &dim) != 7) + &n, &field->s, &form, &side, &field->x, &field->y, &field->dim) + != 7) { + free(field); return 0; + } assert(n >= 2); if (side == 'B' || side == 'T') { @@ -339,71 +436,38 @@ static bool parse_hsheet_field(struct sch_ctx *ctx, const char *line) * flips rotated sheets where the last imported pin is deleted * back. */ - ctx->rotated = 1; + sheet->rotated = 1; } - dwg_hlabel(x, y, s, decode_side(side), dim, decode_form(form)); - free(s); + field->shape = decode_form(form); + field->side = decode_side(side); + + field->next = sheet->fields; + sheet->fields = field; return 1; } -static void do_hsheet_text(struct sch_ctx *ctx) -{ - char *s; - - assert(ctx->sheet && ctx->file); - - struct text sheet_txt = { - .size = ctx->sheet_dim, - .x = ctx->x, - .y = ctx->y, - .rot = 0, - .hor = text_min, - .vert = text_min, - }; - if (asprintf(&s, "Sheet: %s", ctx->sheet)) {} - sheet_txt.s = s; /* work around "const" mismatch */ - - struct text file_txt = { - .size = ctx->file_dim, - .x = ctx->x, - .y = ctx->y, - .rot = 0, - .hor = text_min, - .vert = text_max, - }; - if (asprintf(&s, "File: %s", ctx->file)) {} - file_txt.s = s; /* work around "const" mismatch */ - - if (ctx->rotated) { - sheet_txt.rot = file_txt.rot = 90; - sheet_txt.x -= HSHEET_FIELD_OFFSET; - sheet_txt.y += ctx->h; - file_txt.x += ctx->w + HSHEET_FIELD_OFFSET; - file_txt.y += ctx->h; - } else { - sheet_txt.y -= HSHEET_FIELD_OFFSET; - file_txt.y += ctx->h + HSHEET_FIELD_OFFSET; - } - - text_fig(&sheet_txt, COLOR_HSHEET_SHEET, LAYER_HSHEET_FIELD); - text_fig(&file_txt, COLOR_HSHEET_FILE, LAYER_HSHEET_FIELD); - - free((void *) ctx->sheet); - free((void *) ctx->file); -} - - /* ----- Schematics parser ------------------------------------------------- */ +static void submit_obj(struct sch_ctx *ctx, enum sch_obj_type type) +{ + struct sch_obj *obj; + + obj = alloc_type(struct sch_obj); + *obj = ctx->obj; + obj->type = type; + obj->next = ctx->objs; + ctx->objs = obj; +} + + bool sch_parse(struct sch_ctx *ctx, const char *line) { + struct sch_obj *obj = &ctx->obj; int n = 0; - int x, y, ex, ey; char *s; - int m[4]; ctx->lineno++; @@ -411,57 +475,60 @@ bool sch_parse(struct sch_ctx *ctx, const char *line) case sch_basic: if (sscanf(line, "$Comp%n", &n) == 0 && n) { ctx->state = sch_comp; - ctx->fields = NULL; + obj->u.comp.fields = NULL; return 1; } if (sscanf(line, "$Sheet%n", &n) == 0 && n) { ctx->state = sch_sheet; - ctx->sheet = NULL; - ctx->file = NULL; - ctx->rotated = 0; + obj->u.sheet.sheet = NULL; + obj->u.sheet.file = NULL; + obj->u.sheet.rotated = 0; + obj->u.sheet.fields = NULL; return 1; } /* Text */ + struct sch_text *text = &obj->u.text; + if (sscanf(line, "Text Notes %d %d %d %d", - &ctx->x, &ctx->y, &ctx->dir, &ctx->dim) == 4) { + &obj->x, &obj->y, &text->dir, &text->dim) == 4) { ctx->state = sch_text; - ctx->text = draw_text; + obj->u.text.fn = draw_text; return 1; } if (sscanf(line, "Text GLabel %d %d %d %d %ms", - &ctx->x, &ctx->y, &ctx->dir, &ctx->dim, &s) == 5) { + &obj->x, &obj->y, &text->dir, &text->dim, &s) == 5) { ctx->state = sch_text; - ctx->shape = decode_shape(s); - ctx->text = dwg_glabel; + obj->u.text.fn = dwg_glabel; + obj->u.text.shape = decode_shape(s); return 1; } if (sscanf(line, "Text HLabel %d %d %d %d %ms", - &ctx->x, &ctx->y, &ctx->dir, &ctx->dim, &s) == 5) { + &obj->x, &obj->y, &text->dir, &text->dim, &s) == 5) { ctx->state = sch_text; - ctx->shape = decode_shape(s); - ctx->text = dwg_hlabel; + obj->u.text.fn = dwg_hlabel; + obj->u.text.shape = decode_shape(s); return 1; } if (sscanf(line, "Text Label %d %d %d %d", - &ctx->x, &ctx->y, &ctx->dir, &ctx->dim) == 4) { + &obj->x, &obj->y, &text->dir, &text->dim) == 4) { ctx->state = sch_text; - ctx->text = dwg_label; + obj->u.text.fn = dwg_label; return 1; } /* Connection */ - if (sscanf(line, "Connection ~ %d %d", &x, &y) == 2) { - dwg_junction(x, y); + if (sscanf(line, "Connection ~ %d %d", &obj->x, &obj->y) == 2) { + submit_obj(ctx, sch_obj_junction); return 1; } /* NoConn */ - if (sscanf(line, "NoConn ~ %d %d", &x, &y) == 2) { - dwg_noconn(x, y); + if (sscanf(line, "NoConn ~ %d %d", &obj->x, &obj->y) == 2) { + submit_obj(ctx, sch_obj_noconn); return 1; } @@ -469,17 +536,17 @@ bool sch_parse(struct sch_ctx *ctx, const char *line) if (sscanf(line, "Wire Wire Line%n", &n) == 0 && n) { ctx->state = sch_wire; - ctx->wire = dwg_wire; + obj->u.wire.fn = dwg_wire; return 1; } if (sscanf(line, "Wire Bus Line%n", &n) == 0 && n) { ctx->state = sch_wire; - ctx->wire = dwg_bus; + obj->u.wire.fn = dwg_bus; return 1; } if (sscanf(line, "Wire Notes Line%n", &n) == 0 && n) { ctx->state = sch_wire; - ctx->wire = dwg_line; + obj->u.wire.fn = dwg_line; return 1; } @@ -497,12 +564,12 @@ bool sch_parse(struct sch_ctx *ctx, const char *line) */ if (sscanf(line, "Entry Wire Line%n", &n) == 0 && n) { ctx->state = sch_wire; - ctx->wire = dwg_wire; + obj->u.wire.fn = dwg_wire; return 1; } if (sscanf(line, "Entry Bus Bus%n", &n) == 0 && n) { ctx->state = sch_wire; - ctx->wire = dwg_bus; + obj->u.wire.fn = dwg_bus; return 1; } @@ -519,46 +586,42 @@ bool sch_parse(struct sch_ctx *ctx, const char *line) case sch_comp: if (sscanf(line, "$EndComp%n", &n) == 0 && n) { ctx->state = sch_basic; - ctx->comp = NULL; + submit_obj(ctx, sch_obj_comp); return 1; } if (sscanf(line, "L %ms", &s) == 1) { - ctx->comp = lib_find(s); + obj->u.comp.comp = lib_find(s); free(s); return 1; } - if (sscanf(line, "U %u", &ctx->unit) == 1) + if (sscanf(line, "U %u", &obj->u.comp.unit) == 1) return 1; - if (sscanf(line, "P %d %d", &ctx->x, &ctx->y) == 2) + if (sscanf(line, "P %d %d", &obj->x, &obj->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); + n = sscanf(line, " %d %d %d %d", + obj->u.comp.m + 1, obj->u.comp.m + 2, + obj->u.comp.m + 4, obj->u.comp.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); + obj->u.comp.m[0] = obj->x; + obj->u.comp.m[3] = obj->y; return 1; } break; case sch_sheet: if (sscanf(line, "$EndSheet%n", &n) == 0 && n) { ctx->state = sch_basic; - do_hsheet_text(ctx); + submit_obj(ctx, sch_obj_sheet); return 1; } if (sscanf(line, "S %d %d %u %u", - &ctx->x, &ctx->y, &ctx->w, &ctx->h) == 4) { - gfx_rect(ctx->x, ctx->y, - ctx->x + ctx->w, ctx->y + ctx->h, - COLOR_HSHEET_BOX, COLOR_NONE, LAYER_HSHEET_BOX); + &obj->x, &obj->y, &obj->u.sheet.w, &obj->u.sheet.h) == 4) return 1; - } if (sscanf(line, "U %*x%n", &n) == 0 && n) return 1; if (parse_hsheet_field(ctx, line)) @@ -566,7 +629,7 @@ bool sch_parse(struct sch_ctx *ctx, const char *line) break; case sch_text: ctx->state = sch_basic; - if (ctx->text) { + { const char *from; char *to; @@ -582,16 +645,15 @@ bool sch_parse(struct sch_ctx *ctx, const char *line) from += 2; } *to = 0; - ctx->text(ctx->x, ctx->y, s, ctx->dir, ctx->dim, - ctx->shape); - free(s); + obj->u.text.s = s; + submit_obj(ctx, sch_obj_text); } return 1; case sch_wire: - if (sscanf(line, "%d %d %d %d", &x, &y, &ex, &ey) != 4) + if (sscanf(line, "%d %d %d %d", &obj->x, &obj->y, + &obj->u.wire.ex, &obj->u.wire.ey) != 4) break; - if (ctx->wire) - ctx->wire(x, y, ex, ey); + submit_obj(ctx, sch_obj_wire); ctx->state = sch_basic; return 1; default: @@ -605,5 +667,6 @@ bool sch_parse(struct sch_ctx *ctx, const char *line) void sch_init(struct sch_ctx *ctx) { ctx->state = sch_descr; + ctx->objs = NULL; ctx->lineno = 0; } diff --git a/sch2fig/sch.h b/sch2fig/sch.h index f0f5604..4a1441e 100644 --- a/sch2fig/sch.h +++ b/sch2fig/sch.h @@ -30,36 +30,67 @@ enum sch_state { sch_wire, /* wire */ }; +struct sch_obj { + enum sch_obj_type { + sch_obj_wire, + sch_obj_junction, + sch_obj_noconn, + sch_obj_text, + sch_obj_comp, + sch_obj_sheet, + } type; + + int x, y; + + union { + struct sch_wire { + void (*fn)(int sx, int sy, int ex, int ey); + int ex, ey; + } wire; + struct sch_text { + void (*fn)(int x, int y, const char *s, + int dir, int dim, enum dwg_shape shape); + const char *s; + int dir; /* orientation */ + int dim; /* dimension */ + enum dwg_shape shape; + } text; + struct sch_comp { + const struct comp *comp; /* current component */ + unsigned unit; /* unit of current component */ + struct comp_field { + struct text txt; + struct comp_field *next; + } *fields; + int m[6]; + } comp; + struct sch_sheet { + unsigned h, w; + const char *sheet; + unsigned sheet_dim; + const char *file; + unsigned file_dim; + bool rotated; + + struct sheet_field { + char *s; + int x, y; + unsigned dim; + enum dwg_shape shape; + unsigned side; + struct sheet_field *next; + } *fields; + } sheet; + } u; + + struct sch_obj *next; +}; + struct sch_ctx { enum sch_state state; - void (*wire)(int sx, int sy, int ex, int ey); - /* text and component */ - - int x, y; /* saved coordinates */ - - /* text */ - - void (*text)(int x, int y, const char *s, int dir, int dim, - enum dwg_shape shape); - int dir; /* orientation */ - int dim; /* dimension */ - enum dwg_shape shape; - - /* component */ - - const struct comp *comp; /* current component */ - unsigned unit; /* unit of current component */ - struct sch_field *fields; - - /* subsheet */ - - unsigned h, w; - const char *sheet; - unsigned sheet_dim; - const char *file; - unsigned file_dim; - bool rotated; + struct sch_obj obj; + struct sch_obj *objs; unsigned lineno; }; @@ -67,6 +98,7 @@ struct sch_ctx { void decode_alignment(struct text *txt, char hor, char vert); +void sch_render(const struct sch_ctx *ctx); bool sch_parse(struct sch_ctx *ctx, const char *line); void sch_init(struct sch_ctx *ctx);