2016-08-02 17:00:08 +03:00
|
|
|
/*
|
2016-08-23 02:47:06 +03:00
|
|
|
* main.c - Visualize and convert Eeschema schematics
|
2016-08-02 17:00:08 +03:00
|
|
|
*
|
|
|
|
* 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 <stdbool.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2016-08-03 13:38:57 +03:00
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
2016-08-18 03:37:15 +03:00
|
|
|
#include "misc/util.h"
|
|
|
|
#include "misc/diag.h"
|
2016-08-18 03:28:42 +03:00
|
|
|
#include "gfx/fig.h"
|
|
|
|
#include "gfx/cro.h"
|
|
|
|
#include "gfx/diff.h"
|
|
|
|
#include "gfx/gfx.h"
|
2016-08-18 03:07:13 +03:00
|
|
|
#include "file/file.h"
|
2016-08-23 02:47:06 +03:00
|
|
|
#include "kicad/ext.h"
|
2016-08-22 07:12:21 +03:00
|
|
|
#include "kicad/sexpr.h"
|
2016-08-22 10:05:41 +03:00
|
|
|
#include "kicad/pl.h"
|
2016-08-18 03:15:44 +03:00
|
|
|
#include "kicad/lib.h"
|
|
|
|
#include "kicad/sch.h"
|
2016-08-18 03:00:02 +03:00
|
|
|
#include "gui/fmt-pango.h"
|
2016-08-18 03:07:13 +03:00
|
|
|
#include "file/git-hist.h"
|
2016-08-18 02:54:25 +03:00
|
|
|
#include "gui/gui.h"
|
2016-08-20 01:53:32 +03:00
|
|
|
#include "version.h"
|
2016-08-02 17:00:08 +03:00
|
|
|
#include "main.h"
|
|
|
|
|
|
|
|
|
|
|
|
static struct gfx_ops const *ops_list[] = {
|
|
|
|
&fig_ops,
|
|
|
|
&cro_png_ops,
|
|
|
|
&cro_pdf_ops,
|
|
|
|
&diff_ops,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-08-22 07:12:21 +03:00
|
|
|
static void sexpr(void)
|
|
|
|
{
|
|
|
|
struct sexpr_ctx *parser = sexpr_new();
|
|
|
|
struct expr *expr;
|
|
|
|
char *buf = NULL;
|
|
|
|
size_t n = 0;
|
|
|
|
|
|
|
|
while (getline(&buf, &n, stdin) > 0)
|
|
|
|
sexpr_parse(parser, buf);
|
|
|
|
if (sexpr_finish(parser, &expr))
|
|
|
|
dump_expr(expr);
|
|
|
|
else
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2016-08-23 02:47:06 +03:00
|
|
|
|
2016-08-02 17:00:08 +03:00
|
|
|
void usage(const char *name)
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
2016-08-23 02:47:06 +03:00
|
|
|
"usage: %s [gtk_flags] [-r] [-N n] kicad_file ...\n"
|
|
|
|
" %s [-r] [-v ...] kicad_file ...\n"
|
2016-08-03 13:38:57 +03:00
|
|
|
" %*s[-- driver_spec]\n"
|
2016-08-02 17:00:08 +03:00
|
|
|
" %s [-v ...] -C [rev:]file\n"
|
2016-08-04 22:12:40 +03:00
|
|
|
" %s [-v ...] -H path_into_repo\n"
|
2016-08-22 07:12:21 +03:00
|
|
|
" %s -S\n"
|
2016-08-20 01:53:32 +03:00
|
|
|
" %s -V\n"
|
2016-08-18 18:06:33 +03:00
|
|
|
" %s gdb ...\n"
|
2016-08-02 17:00:08 +03:00
|
|
|
"\n"
|
2016-08-23 02:47:06 +03:00
|
|
|
" kicad_file [rev:]file.ext\n"
|
|
|
|
" ext .lib, .sch, or .kicad_wks\n"
|
|
|
|
" rev git revision\n"
|
|
|
|
"\n"
|
2016-08-10 15:08:22 +03:00
|
|
|
" -r recurse into sub-sheets\n"
|
|
|
|
" -v increase verbosity of diagnostic output\n"
|
|
|
|
" -C 'cat' the file to standard output\n"
|
|
|
|
" -H show history of repository on standard output\n"
|
2016-08-12 16:42:03 +03:00
|
|
|
" -N n limit history to n revisions (unlimited if omitted or 0)\n"
|
2016-08-22 07:12:21 +03:00
|
|
|
" -S parse S-expressions from stdin and dump to stdout\n"
|
2016-08-20 01:53:32 +03:00
|
|
|
" -V print revision (version) number and exit\n"
|
2016-08-18 18:06:33 +03:00
|
|
|
" gdb run eeshow under gdb\n"
|
2016-08-02 17:00:08 +03:00
|
|
|
"\n"
|
2016-08-06 03:19:56 +03:00
|
|
|
"No driver spec: enter GUI\n"
|
|
|
|
"\n"
|
2016-08-02 17:00:08 +03:00
|
|
|
"FIG driver spec:\n"
|
|
|
|
" fig [-t template.fig] [var=value ...]\n"
|
|
|
|
"\n"
|
|
|
|
" var=value substitute \"<var>\" with \"value\" in template\n"
|
|
|
|
" -t template.fig merge this file with generated output\n"
|
|
|
|
"\n"
|
|
|
|
"Cairo PNG driver spec:\n"
|
|
|
|
" png [-o output.png] [-s scale]\n"
|
|
|
|
"\n"
|
2016-08-02 17:45:44 +03:00
|
|
|
" -o output.png write PNG to specified file (default; standard output)\n"
|
2016-08-02 17:00:08 +03:00
|
|
|
" -s scale scale by indicated factor (default: 1.0)\n"
|
|
|
|
"\n"
|
|
|
|
"Cairo PDF driver spec:\n"
|
2016-08-21 17:37:47 +03:00
|
|
|
" pdf [-o output.pdf] [-s scale] [-T]\n"
|
2016-08-02 17:00:08 +03:00
|
|
|
"\n"
|
2016-08-21 17:37:47 +03:00
|
|
|
" see PNG for -o and -s\n"
|
|
|
|
" -T do not add table of contents\n"
|
2016-08-02 17:00:08 +03:00
|
|
|
"\n"
|
|
|
|
"Diff driver spec:\n"
|
|
|
|
" diff [-o output.pdf] [-s scale] [file.lib ...] file.sch\n"
|
|
|
|
"\n"
|
|
|
|
" see PNG\n"
|
2016-08-22 07:12:21 +03:00
|
|
|
, name, name, (int) strlen(name) + 1, "", name, name, name, name, name);
|
2016-08-02 17:00:08 +03:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-03 13:38:57 +03:00
|
|
|
int main(int argc, char **argv)
|
2016-08-02 17:00:08 +03:00
|
|
|
{
|
|
|
|
struct lib lib;
|
|
|
|
struct sch_ctx sch_ctx;
|
2016-08-02 22:38:21 +03:00
|
|
|
struct file sch_file;
|
2016-08-02 17:00:08 +03:00
|
|
|
bool recurse = 0;
|
|
|
|
const char *cat = NULL;
|
2016-08-04 22:12:40 +03:00
|
|
|
const char *history = NULL;
|
2016-08-07 01:14:31 +03:00
|
|
|
const char *fmt = NULL;
|
2016-08-22 10:05:41 +03:00
|
|
|
struct pl_ctx *pl = NULL;
|
2016-08-10 15:08:22 +03:00
|
|
|
int limit = 0;
|
2016-08-02 17:00:08 +03:00
|
|
|
char c;
|
2016-08-23 02:47:06 +03:00
|
|
|
int dashdash;
|
|
|
|
unsigned i;
|
2016-08-03 13:38:57 +03:00
|
|
|
bool have_dashdash = 0;
|
2016-08-23 02:47:06 +03:00
|
|
|
struct file_names file_names;
|
2016-08-02 17:00:08 +03:00
|
|
|
int gfx_argc;
|
|
|
|
char **gfx_argv;
|
|
|
|
const struct gfx_ops **ops = ops_list;
|
|
|
|
|
2016-08-18 18:06:33 +03:00
|
|
|
if (argc > 1 && !strcmp(argv[1], "gdb")) {
|
|
|
|
char **args;
|
|
|
|
|
|
|
|
args = alloc_type_n(char *, argc + 2);
|
|
|
|
args[0] = "gdb";
|
|
|
|
args[1] = "--args";
|
|
|
|
args[2] = *argv;
|
|
|
|
memcpy(args + 3, argv + 2, sizeof(char *) * (argc - 1));
|
|
|
|
execvp("gdb", args);
|
|
|
|
perror(*argv);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-08-02 17:00:08 +03:00
|
|
|
for (dashdash = 1; dashdash != argc; dashdash++)
|
2016-08-03 13:38:57 +03:00
|
|
|
if (!strcmp(argv[dashdash], "--")) {
|
|
|
|
have_dashdash = 1;
|
2016-08-02 17:00:08 +03:00
|
|
|
break;
|
2016-08-03 13:38:57 +03:00
|
|
|
}
|
2016-08-02 17:00:08 +03:00
|
|
|
|
2016-08-06 03:14:26 +03:00
|
|
|
if (!have_dashdash)
|
|
|
|
gtk_init(&argc, &argv);
|
|
|
|
|
2016-08-23 02:47:06 +03:00
|
|
|
while ((c = getopt(dashdash, argv, "rvC:F:H:N:SV")) != EOF)
|
2016-08-02 17:00:08 +03:00
|
|
|
switch (c) {
|
|
|
|
case 'r':
|
|
|
|
recurse = 1;
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
verbose++;
|
|
|
|
break;
|
|
|
|
case 'C':
|
|
|
|
cat = optarg;
|
|
|
|
break;
|
2016-08-07 01:14:31 +03:00
|
|
|
case 'F':
|
|
|
|
fmt = optarg;
|
|
|
|
break;
|
2016-08-04 22:12:40 +03:00
|
|
|
case 'H':
|
|
|
|
history = optarg;
|
|
|
|
break;
|
2016-08-10 15:08:22 +03:00
|
|
|
case 'N':
|
|
|
|
limit = atoi(optarg);
|
|
|
|
break;
|
2016-08-22 07:12:21 +03:00
|
|
|
case 'S':
|
|
|
|
sexpr();
|
|
|
|
return 0;
|
2016-08-20 01:53:32 +03:00
|
|
|
case 'V':
|
|
|
|
fprintf(stderr, "%s\n", version);
|
|
|
|
return 1;
|
2016-08-02 17:00:08 +03:00
|
|
|
default:
|
|
|
|
usage(*argv);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cat) {
|
2016-08-02 21:36:18 +03:00
|
|
|
struct file file;
|
|
|
|
|
2016-08-02 17:00:08 +03:00
|
|
|
if (argc != optind)
|
|
|
|
usage(*argv);
|
2016-08-06 03:02:57 +03:00
|
|
|
if (!file_open(&file, cat, NULL))
|
|
|
|
return 1;
|
|
|
|
if (!file_read(&file, file_cat, NULL))
|
|
|
|
return 1;
|
2016-08-02 21:36:18 +03:00
|
|
|
file_close(&file);
|
2016-08-02 17:00:08 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-08-04 22:12:40 +03:00
|
|
|
if (history) {
|
|
|
|
struct hist *h;
|
|
|
|
|
|
|
|
h = vcs_git_hist(history);
|
|
|
|
dump_hist(h);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-08-07 01:14:31 +03:00
|
|
|
if (fmt) {
|
|
|
|
char *buf;
|
|
|
|
|
|
|
|
buf = fmt_pango(fmt, argv[optind]);
|
|
|
|
printf("\"%s\"\n", buf);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-08-02 17:00:08 +03:00
|
|
|
if (dashdash - optind < 1)
|
|
|
|
usage(*argv);
|
|
|
|
|
2016-08-23 02:47:06 +03:00
|
|
|
classify_files(&file_names, argv + optind, dashdash - optind);
|
|
|
|
if (!file_names.sch)
|
|
|
|
fatal("top sheet name required");
|
2016-08-05 16:24:39 +03:00
|
|
|
|
2016-08-23 02:47:06 +03:00
|
|
|
if (!have_dashdash) {
|
2016-08-05 16:24:39 +03:00
|
|
|
optind = 0; /* reset getopt */
|
2016-08-23 02:47:06 +03:00
|
|
|
return gui(&file_names, recurse, limit);
|
2016-08-05 16:24:39 +03:00
|
|
|
}
|
|
|
|
|
2016-08-02 22:38:21 +03:00
|
|
|
sch_init(&sch_ctx, recurse);
|
2016-08-23 02:47:06 +03:00
|
|
|
if (!file_open(&sch_file, file_names.sch, NULL))
|
2016-08-06 03:02:57 +03:00
|
|
|
return 1;
|
2016-08-02 22:38:21 +03:00
|
|
|
|
2016-08-02 17:00:08 +03:00
|
|
|
lib_init(&lib);
|
2016-08-23 02:47:06 +03:00
|
|
|
for (i = 0; i != file_names.n_libs; i++)
|
|
|
|
if (!lib_parse(&lib, file_names.libs[i], &sch_file))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (file_names.pl) {
|
|
|
|
struct file file;
|
|
|
|
|
|
|
|
if (!file_open(&file, file_names.pl, &sch_file))
|
|
|
|
return 1;
|
|
|
|
pl = pl_parse(&file);
|
|
|
|
file_close(&file);
|
|
|
|
if (!pl)
|
2016-08-06 03:02:57 +03:00
|
|
|
return 1;
|
2016-08-23 02:47:06 +03:00
|
|
|
}
|
2016-08-02 17:00:08 +03:00
|
|
|
|
|
|
|
if (dashdash == argc) {
|
|
|
|
gfx_argc = 1;
|
2016-08-11 02:28:31 +03:00
|
|
|
gfx_argv = alloc_type_n(char *, 2);
|
2016-08-02 17:00:08 +03:00
|
|
|
gfx_argv[0] = (char *) (*ops)->name;
|
|
|
|
gfx_argv[1] = NULL;
|
|
|
|
} else {
|
|
|
|
gfx_argc = argc - dashdash - 1;
|
|
|
|
if (!gfx_argc)
|
|
|
|
usage(*argv);
|
2016-08-11 02:28:31 +03:00
|
|
|
gfx_argv = alloc_type_n(char *, gfx_argc + 1);
|
2016-08-02 17:00:08 +03:00
|
|
|
memcpy(gfx_argv, argv + dashdash + 1,
|
|
|
|
sizeof(const char *) * (gfx_argc + 1));
|
|
|
|
|
|
|
|
for (ops = ops_list; ops != ARRAY_END(ops_list); ops++)
|
|
|
|
if (!strcmp((*ops)->name, *gfx_argv))
|
|
|
|
goto found;
|
2016-08-11 23:19:32 +03:00
|
|
|
fatal("graphics backend \"%s\" not found\n", *gfx_argv);
|
2016-08-02 17:00:08 +03:00
|
|
|
found:
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
optind = 0; /* reset getopt */
|
|
|
|
|
2016-08-11 00:57:04 +03:00
|
|
|
if (!sch_parse(&sch_ctx, &sch_file, &lib, NULL))
|
2016-08-06 03:02:57 +03:00
|
|
|
return 1;
|
2016-08-02 22:38:21 +03:00
|
|
|
file_close(&sch_file);
|
|
|
|
|
2016-08-02 17:00:08 +03:00
|
|
|
gfx_init(*ops, gfx_argc, gfx_argv);
|
|
|
|
if (recurse) {
|
|
|
|
const struct sheet *sheet;
|
|
|
|
|
2016-08-11 23:19:32 +03:00
|
|
|
if (!gfx_multi_sheet())
|
|
|
|
fatal("graphics backend only supports single sheet\n");
|
2016-08-02 17:00:08 +03:00
|
|
|
for (sheet = sch_ctx.sheets; sheet; sheet = sheet->next) {
|
2016-08-21 17:32:13 +03:00
|
|
|
gfx_sheet_name(sheet->title);
|
2016-08-02 17:00:08 +03:00
|
|
|
sch_render(sheet);
|
2016-08-22 13:18:47 +03:00
|
|
|
if (pl)
|
|
|
|
pl_render(pl, sch_ctx.sheets, sheet);
|
2016-08-02 17:00:08 +03:00
|
|
|
if (sheet->next)
|
|
|
|
gfx_new_sheet();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sch_render(sch_ctx.sheets);
|
2016-08-22 13:18:47 +03:00
|
|
|
if (pl)
|
|
|
|
pl_render(pl, sch_ctx.sheets, sch_ctx.sheets);
|
2016-08-02 17:00:08 +03:00
|
|
|
}
|
|
|
|
gfx_end();
|
|
|
|
|
2016-08-06 02:25:58 +03:00
|
|
|
sch_free(&sch_ctx);
|
2016-08-06 02:34:15 +03:00
|
|
|
lib_free(&lib);
|
2016-08-06 02:25:58 +03:00
|
|
|
|
2016-08-02 17:00:08 +03:00
|
|
|
return 0;
|
|
|
|
}
|