2016-07-22 06:04:42 +03:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2016-07-23 12:58:21 +03:00
|
|
|
#include <stddef.h>
|
2016-07-22 05:54:32 +03:00
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2016-07-24 07:03:23 +03:00
|
|
|
#include <assert.h>
|
2016-07-22 05:54:32 +03:00
|
|
|
|
2016-07-23 12:58:21 +03:00
|
|
|
#include "util.h"
|
2016-07-23 20:59:37 +03:00
|
|
|
#include "misc.h"
|
2016-07-23 06:48:59 +03:00
|
|
|
#include "style.h"
|
2016-07-22 05:54:32 +03:00
|
|
|
#include "fig.h"
|
|
|
|
#include "lib.h"
|
|
|
|
#include "sch.h"
|
|
|
|
|
|
|
|
|
2016-07-23 21:07:50 +03:00
|
|
|
/* ----- (Global) Labels --------------------------------------------------- */
|
|
|
|
|
|
|
|
|
2016-07-22 05:54:32 +03:00
|
|
|
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;
|
2016-07-24 07:03:23 +03:00
|
|
|
if (!strcmp(s, "BiDi"))
|
|
|
|
return fig_bidir;
|
2016-07-22 05:54:32 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-23 21:07:50 +03:00
|
|
|
/* ----- Text -------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
2016-07-23 06:48:59 +03:00
|
|
|
static void draw_text(int x, int y, const char *s, int dir, int dim,
|
|
|
|
enum fig_shape shape)
|
|
|
|
{
|
|
|
|
fig_text(x, y, s, dim, text_min, 0, COLOR_TEXT, LAYER_TEXT);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-23 21:07:50 +03:00
|
|
|
/* ----- Component fields -------------------------------------------------- */
|
|
|
|
|
|
|
|
|
2016-07-23 20:59:37 +03:00
|
|
|
struct sch_field {
|
|
|
|
struct text txt;
|
|
|
|
struct sch_field *next;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static bool parse_field(struct sch_ctx *ctx, const char *line)
|
|
|
|
{
|
2016-07-24 04:52:15 +03:00
|
|
|
int n;
|
2016-07-23 20:59:37 +03:00
|
|
|
unsigned flags;
|
|
|
|
char hv, hor, vert, italic, bold;
|
|
|
|
struct sch_field *field;
|
|
|
|
struct text *txt;
|
|
|
|
|
|
|
|
field = alloc_type(struct sch_field);
|
|
|
|
txt = &field->txt;
|
|
|
|
|
2016-07-24 04:52:15 +03:00
|
|
|
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) {
|
2016-07-23 20:59:37 +03:00
|
|
|
free(field);
|
|
|
|
return 1;
|
|
|
|
}
|
2016-07-24 04:52:15 +03:00
|
|
|
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)
|
2016-07-23 20:59:37 +03:00
|
|
|
return 0;
|
|
|
|
|
2016-07-24 04:52:15 +03:00
|
|
|
if (flags || !lib_field_visible(ctx->comp, n)) {
|
2016-07-23 20:59:37 +03:00
|
|
|
free(field);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
field->next = ctx->fields;
|
|
|
|
ctx->fields = field;
|
|
|
|
|
|
|
|
switch (hv) {
|
|
|
|
case 'H':
|
|
|
|
txt->rot = 0;
|
|
|
|
break;
|
|
|
|
case 'V':
|
|
|
|
txt->rot = 90;
|
|
|
|
break;
|
|
|
|
default:
|
2016-07-24 07:03:23 +03:00
|
|
|
assert(0);
|
2016-07-23 20:59:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (hor) {
|
|
|
|
case 'L':
|
|
|
|
txt->hor = text_min;
|
|
|
|
break;
|
|
|
|
case 'C':
|
|
|
|
txt->hor = text_mid;
|
|
|
|
break;
|
|
|
|
case 'R':
|
|
|
|
txt->hor = text_max;
|
|
|
|
break;
|
|
|
|
default:
|
2016-07-24 07:03:23 +03:00
|
|
|
assert(0);
|
2016-07-23 20:59:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (vert) {
|
|
|
|
case 'B':
|
|
|
|
txt->vert = text_min;
|
|
|
|
break;
|
|
|
|
case 'C':
|
|
|
|
txt->vert = text_mid;
|
|
|
|
break;
|
|
|
|
case 'T':
|
|
|
|
txt->vert = text_max;
|
|
|
|
break;
|
|
|
|
default:
|
2016-07-24 07:03:23 +03:00
|
|
|
assert(0);
|
2016-07-23 20:59:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// @@@ decode font
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-25 20:43:59 +03:00
|
|
|
static void dump_field(const struct sch_field *field, int m[6])
|
2016-07-23 20:59:37 +03:00
|
|
|
{
|
2016-07-25 20:43:59 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-07-25 20:58:39 +03:00
|
|
|
if (matrix_is_mirrored(m)) {
|
|
|
|
if ((txt.rot % 180) == 0)
|
|
|
|
txt.hor = text_flip(txt.hor);
|
|
|
|
else
|
|
|
|
txt.vert = text_flip(txt.vert);
|
|
|
|
}
|
|
|
|
|
2016-07-25 20:43:59 +03:00
|
|
|
text_fig(&txt, COLOR_FIELD, LAYER_FIELD);
|
|
|
|
}
|
|
|
|
|
2016-07-23 20:59:37 +03:00
|
|
|
|
2016-07-25 20:43:59 +03:00
|
|
|
static void dump_fields(struct sch_field *fields, int m[6])
|
|
|
|
{
|
2016-07-23 20:59:37 +03:00
|
|
|
while (fields) {
|
|
|
|
struct text *txt = &fields->txt;
|
2016-07-25 20:43:59 +03:00
|
|
|
struct sch_field *next = fields->next;
|
2016-07-23 20:59:37 +03:00
|
|
|
|
2016-07-25 20:43:59 +03:00
|
|
|
dump_field(fields, m);
|
2016-07-23 20:59:37 +03:00
|
|
|
text_free(txt);
|
|
|
|
|
|
|
|
free(fields);
|
|
|
|
fields = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-23 21:07:50 +03:00
|
|
|
/* ----- Schematics parser ------------------------------------------------- */
|
|
|
|
|
|
|
|
|
2016-07-22 05:54:32 +03:00
|
|
|
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;
|
2016-07-23 20:59:37 +03:00
|
|
|
ctx->fields = NULL;
|
2016-07-22 05:54:32 +03:00
|
|
|
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;
|
2016-07-23 06:48:59 +03:00
|
|
|
ctx->text = draw_text;
|
2016-07-22 05:54:32 +03:00
|
|
|
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;
|
2016-07-23 12:58:21 +03:00
|
|
|
unsupported("Text HLabel");
|
|
|
|
ctx->text = NULL;
|
2016-07-22 05:54:32 +03:00
|
|
|
return 1;
|
|
|
|
}
|
2016-07-25 06:16:09 +03:00
|
|
|
if (sscanf(line, "Text Label %d %d %d %d",
|
|
|
|
&ctx->x, &ctx->y, &ctx->dir, &ctx->dim) == 4) {
|
2016-07-22 05:54:32 +03:00
|
|
|
ctx->state = sch_text;
|
2016-07-25 06:16:09 +03:00
|
|
|
ctx->text = fig_label;
|
2016-07-22 05:54:32 +03:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Connection */
|
|
|
|
|
|
|
|
if (sscanf(line, "Connection ~ %d %d", &x, &y) == 2) {
|
|
|
|
fig_junction(x, y);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-07-24 07:03:23 +03:00
|
|
|
/* NoConn */
|
|
|
|
|
|
|
|
if (sscanf(line, "NoConn ~ %d %d", &x, &y) == 2) {
|
|
|
|
fig_noconn(x, y);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-07-22 05:54:32 +03:00
|
|
|
/* 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;
|
2016-07-23 12:58:21 +03:00
|
|
|
unsupported("Wire Bus Line");
|
|
|
|
ctx->wire = NULL;
|
2016-07-22 05:54:32 +03:00
|
|
|
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;
|
2016-07-23 12:58:21 +03:00
|
|
|
unsupported("Wire Wire Bus");
|
|
|
|
ctx->wire = NULL;
|
2016-07-22 05:54:32 +03:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (sscanf(line, "Wire Bus Bus%n", &n) == 0 && n) {
|
|
|
|
ctx->state = sch_wire;
|
2016-07-23 12:58:21 +03:00
|
|
|
unsupported("Wire Bus Bus");
|
|
|
|
ctx->wire = NULL;
|
2016-07-22 05:54:32 +03:00
|
|
|
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;
|
|
|
|
}
|
2016-07-24 04:52:15 +03:00
|
|
|
if (sscanf(line, "L %ms", &s) == 1) {
|
|
|
|
ctx->comp = lib_find(s);
|
|
|
|
free(s);
|
2016-07-22 05:54:32 +03:00
|
|
|
return 1;
|
2016-07-24 04:52:15 +03:00
|
|
|
}
|
2016-07-22 05:54:32 +03:00
|
|
|
if (sscanf(line, "U %u", &ctx->unit) == 1)
|
|
|
|
return 1;
|
|
|
|
if (sscanf(line, "P %d %d", &ctx->x, &ctx->y) == 2)
|
|
|
|
return 1;
|
2016-07-23 20:59:37 +03:00
|
|
|
if (parse_field(ctx, line))
|
|
|
|
return 1;
|
2016-07-22 05:54:32 +03:00
|
|
|
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);
|
2016-07-23 20:59:37 +03:00
|
|
|
dump_fields(ctx->fields, m);
|
2016-07-22 05:54:32 +03:00
|
|
|
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;
|
2016-07-23 12:58:21 +03:00
|
|
|
if (ctx->text)
|
|
|
|
ctx->text(ctx->x, ctx->y, line, ctx->dir, ctx->dim,
|
|
|
|
ctx->shape);
|
2016-07-22 05:54:32 +03:00
|
|
|
return 1;
|
|
|
|
case sch_wire:
|
|
|
|
if (sscanf(line, "%d %d %d %d", &x, &y, &ex, &ey) != 4)
|
|
|
|
break;
|
2016-07-23 12:58:21 +03:00
|
|
|
if (ctx->wire)
|
|
|
|
ctx->wire(x, y, ex, ey);
|
2016-07-22 05:54:32 +03:00
|
|
|
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;
|
2016-07-24 07:03:23 +03:00
|
|
|
ctx->lineno = 0;
|
2016-07-22 05:54:32 +03:00
|
|
|
}
|