mirror of
git://projects.qi-hardware.com/eda-tools.git
synced 2025-04-21 12:27:27 +03:00
gencat clashes with an existing tool. rename to genkicat (1/2)
The "gencat" with older rights to the name is from libc, no less. I wonder how I missed that :-(
This commit is contained in:
8
genkicat/DESC
Normal file
8
genkicat/DESC
Normal file
@@ -0,0 +1,8 @@
|
||||
wm9707scft/v: This is a comment.
|
||||
Continuation of the same line.
|
||||
|
||||
Here we have a line break,
|
||||
and so on
|
||||
wm9707scft/v: Another comment
|
||||
for the same component.
|
||||
WM9707SCFT/V: Component names in comments are case-insensitive.
|
||||
77
genkicat/Makefile
Normal file
77
genkicat/Makefile
Normal file
@@ -0,0 +1,77 @@
|
||||
#
|
||||
# Makefile - Expanded component view generator
|
||||
#
|
||||
# Copyright 2012 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.
|
||||
#
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
|
||||
OBJS = gencat.o tree.o libs.o run.o comp.o fped.o pdf.o
|
||||
|
||||
SHELL = /bin/bash
|
||||
CFLAGS = -Wall -g
|
||||
|
||||
CC_normal := $(CC)
|
||||
DEPEND_normal := $(CPP) $(CFLAGS) -MM -MG
|
||||
|
||||
CC_quiet = @echo " CC " $@ && $(CC_normal)
|
||||
GEN_quiet = @echo " GENERATE " $@ &&
|
||||
DEPEND_quiet = @$(DEPEND_normal)
|
||||
|
||||
ifeq ($(V),1)
|
||||
CC = $(CC_normal)
|
||||
GEN =
|
||||
DEPEND = $(DEPEND_normal)
|
||||
else
|
||||
CC = $(CC_quiet)
|
||||
GEN = $(GEN_quiet)
|
||||
DEPEND = $(DEPEND_quiet)
|
||||
endif
|
||||
|
||||
.PHONY: all clean spotless install uninstall
|
||||
|
||||
all: gencat-bin
|
||||
|
||||
gencat-bin: $(OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LDLIBS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) $*.c -o $*.o
|
||||
$(DEPEND) $*.c | \
|
||||
sed -e \
|
||||
'/^\(.*:\)\? */{p;s///;s/ *\\\?$$/ /;s/ */:\n/g;H;}' \
|
||||
-e '$${g;p;}' -e d >$*.d; \
|
||||
[ "$${PIPESTATUS[*]}" = "0 0" ] || { rm -f $*.d; exit 1; }
|
||||
|
||||
-include $(OBJS:.o=.d)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) $(OBJS:.o=.d)
|
||||
|
||||
spotless: clean
|
||||
rm -f gencat-bin
|
||||
|
||||
#
|
||||
# Note: we use .../lib/gencat/ instead of .../libexec/gencat/ because FHS-3.0
|
||||
# does not define libexec under the /usr/local/ hierarchy. (And older versions
|
||||
# of FHS don't define libexec at all.)
|
||||
#
|
||||
|
||||
install: all
|
||||
mkdir -p $(DESTDIR)/$(PREFIX)/bin
|
||||
mkdir -p $(DESTDIR)/$(PREFIX)/lib/gencat
|
||||
./mkgencat-wrapper -m 755 -p $(DESTDIR)/$(PREFIX)/lib/gencat/ \
|
||||
$(DESTDIR)/$(PREFIX)/bin/gencat
|
||||
install -m 755 gencat-bin $(DESTDIR)/$(PREFIX)/lib/gencat/
|
||||
install -m 755 sym2xps $(DESTDIR)/$(PREFIX)/lib/gencat/
|
||||
install -m 755 expand-pintype $(DESTDIR)/$(PREFIX)/lib/gencat/
|
||||
|
||||
uninstall:
|
||||
rm -f $(DESTDIR)/$(PREFIX)/bin/gencat
|
||||
rm -rf $(DESTDIR)/$(PREFIX)/lib/gencat
|
||||
|
||||
95
genkicat/comp.c
Normal file
95
genkicat/comp.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* comp.c - Component libraries
|
||||
*
|
||||
* Copyright 2012 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "run.h"
|
||||
#include "libs.h"
|
||||
|
||||
|
||||
static const char *field(const char *s, int n)
|
||||
{
|
||||
while (n-- && *s) {
|
||||
while (*s && !isspace(*s))
|
||||
s++;
|
||||
while (*s && isspace(*s))
|
||||
s++;
|
||||
}
|
||||
return *s ? s : NULL;
|
||||
}
|
||||
|
||||
|
||||
static void comp_add_lib(struct lib *lib, const char *path)
|
||||
{
|
||||
FILE *file;
|
||||
struct entry *e = NULL;
|
||||
char buf[1024]; /* @@@ */
|
||||
char *name, *spc;
|
||||
const char *s;
|
||||
|
||||
file = fopen(path, "r");
|
||||
if (!file) {
|
||||
perror(path);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while (fgets(buf, sizeof(buf), file)) {
|
||||
if (!strncmp(buf, "ALIAS ", 6) && e)
|
||||
add_name(e, buf+6);
|
||||
if (strncmp(buf, "DEF ", 4))
|
||||
continue;
|
||||
s = field(buf, 7);
|
||||
if (!s) {
|
||||
fprintf(stderr, "DEF record lacks units field in %s\n",
|
||||
path);
|
||||
exit(1);
|
||||
}
|
||||
name = buf+4;
|
||||
if (*name == '~')
|
||||
name++;
|
||||
spc = strchr(name, ' ');
|
||||
if (!spc) {
|
||||
fprintf(stderr, "invalid DEF line in %s\n", path);
|
||||
exit(1);
|
||||
}
|
||||
*spc = 0;
|
||||
e = new_entry(lib, atoi(s));
|
||||
if (!e->units) {
|
||||
fprintf(stderr, "invalid number of units in %s\n",
|
||||
path);
|
||||
exit(1);
|
||||
}
|
||||
add_name(e, name);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
|
||||
static void comp_ps_entry(FILE *file, const struct lib *lib,
|
||||
const struct entry *e, int unit, int landscape)
|
||||
{
|
||||
if (!landscape)
|
||||
fprintf(file, "-120 700 translate -90 rotate\n");
|
||||
run_cmd("sym2xps '%s' '%s' %d '%s' '%s'",
|
||||
e->file->path, e->names->s, unit+1, "tmp", "tmp.ps");
|
||||
cat(file, "tmp.ps");
|
||||
}
|
||||
|
||||
|
||||
struct lib comp_lib = {
|
||||
.ext = ".lib",
|
||||
.add_lib = comp_add_lib,
|
||||
.ps_entry = comp_ps_entry,
|
||||
};
|
||||
86
genkicat/expand-pintype
Executable file
86
genkicat/expand-pintype
Executable file
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# expand-pintype - Expand pin types of symbols in a Kicad library
|
||||
#
|
||||
# Copyright 2010, 2012 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.
|
||||
#
|
||||
|
||||
#
|
||||
# usage:
|
||||
#
|
||||
# expand-pintype input.lib
|
||||
# expand-pintype input.lib output.lib
|
||||
#
|
||||
|
||||
|
||||
$GAP = 50; # gap between pin and type, in mil
|
||||
$CHAR_WIDTH = 60; # default character width, in mil
|
||||
$NAME_WIDTH = 15; # name field width in ASCII mode, in characters
|
||||
|
||||
|
||||
%map = (
|
||||
"I" => "Input",
|
||||
"O" => "Output",
|
||||
"B" => "BiDi",
|
||||
"T" => "3-state",
|
||||
"P" => "Passive",
|
||||
"U" => "Unspec",
|
||||
"W" => "Pwr In",
|
||||
"w" => "Pwr Out",
|
||||
"C" => "OC",
|
||||
"E" => "OE",
|
||||
"N" => "NC",
|
||||
);
|
||||
|
||||
if (@ARGV < 2) {
|
||||
$out = 0;
|
||||
} elsif (@ARGV == 2) {
|
||||
$file = pop @ARGV;
|
||||
$out = 1;
|
||||
open(FILE, ">$file") || die "$file: $!";
|
||||
} else {
|
||||
print STDERR "usage: expand-pintype input.lib [output.lib]\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while (<>) {
|
||||
if ($out) {
|
||||
# make name differ so that KiCad's cache doesn't get confused
|
||||
s/^DEF\s+~?/$&X/;
|
||||
s/^F1\s+"+/$&X/;
|
||||
print FILE || die;
|
||||
}
|
||||
next unless /^X/;
|
||||
@a = split(/\s+/);
|
||||
($name, $pin, $x, $y, $dir, $unit, $pt) = @a[1, 2, 3, 4, 6, 9, 11];
|
||||
$type = $map{$pt};
|
||||
$type = "???" unless defined $type;
|
||||
if ($out) {
|
||||
$off = $GAP+(length $type)*$CHAR_WIDTH/2;
|
||||
if ($dir eq "U") {
|
||||
($a, $y) = (90, $y-$off);
|
||||
} elsif ($dir eq "D") {
|
||||
($a, $y) = (90, $y+$off);
|
||||
} elsif ($dir eq "R") {
|
||||
($a, $x) = (0, $x-$off);
|
||||
} else {
|
||||
($a, $x) = (0, $x+$off);
|
||||
}
|
||||
$type =~ y/ /~/;
|
||||
print FILE sprintf("T %d %d %d 60 0 %d 0 %s Normal 0\n",
|
||||
$a*10, $x, $y, $unit, $type);
|
||||
} else {
|
||||
$s = "$name ($pin)";
|
||||
$f = $NAME_WIDTH-length $s;
|
||||
$f = "-" x ($f > 0 ? $f : 0);
|
||||
print "$s $f $type\n";
|
||||
}
|
||||
}
|
||||
if ($out) {
|
||||
close FILE || die;
|
||||
}
|
||||
62
genkicat/fped.c
Normal file
62
genkicat/fped.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* comp.c - Component libraries
|
||||
*
|
||||
* Copyright 2012 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.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* for asprintf */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "run.h"
|
||||
#include "libs.h"
|
||||
|
||||
|
||||
static void fped_add_lib(struct lib *lib, const char *path)
|
||||
{
|
||||
FILE *file;
|
||||
char buf[1024]; /* @@@ */
|
||||
char *tmp, *nl;
|
||||
|
||||
asprintf(&tmp, "fped -k '%s' -", path);
|
||||
file = popen(tmp, "r");
|
||||
if (!file) {
|
||||
perror(path);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while (fgets(buf, sizeof(buf), file)) {
|
||||
if (strncmp(buf, "$MODULE ", 8))
|
||||
continue;
|
||||
nl = strchr(buf, '\n');
|
||||
if (nl)
|
||||
*nl = 0;
|
||||
add_name(new_entry(lib, 1), buf+8);
|
||||
}
|
||||
|
||||
pclose(file);
|
||||
}
|
||||
|
||||
|
||||
static void fped_ps_entry(FILE *file, const struct lib *lib,
|
||||
const struct entry *e, int unit, int landscape)
|
||||
{
|
||||
fprintf(file, "0 -25 translate\n");
|
||||
run_cmd("fped -P -s x200 '%s' -1 '%s' '%s'",
|
||||
e->file->path, e->names->s, "tmp.ps");
|
||||
run_cmd("sed -i -e '/OUT pdfmark/d' tmp.ps");
|
||||
cat(file, "tmp.ps");
|
||||
}
|
||||
|
||||
|
||||
struct lib fped_lib = {
|
||||
.ext = ".fpd",
|
||||
.add_lib = fped_add_lib,
|
||||
.ps_entry = fped_ps_entry,
|
||||
};
|
||||
3
genkicat/gencat
Executable file
3
genkicat/gencat
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
PATH=$PATH:.
|
||||
exec gencat-bin "$@"
|
||||
119
genkicat/genkicat.c
Normal file
119
genkicat/genkicat.c
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* gencat.c - Generate expanded component view
|
||||
*
|
||||
* Copyright 2012 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tree.h"
|
||||
#include "libs.h"
|
||||
#include "pdf.h"
|
||||
#include "gencat.h"
|
||||
|
||||
|
||||
int quiet = 0;
|
||||
|
||||
|
||||
static void usage(const char *name)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: %s [-F] [-d|-D] [-p] [-P] [-q] [-L libdir ...] [-l lib ...]\n"
|
||||
" %*s hierarchy [descriptions ...]\n\n"
|
||||
" -d dump the tree instead of generating a PDF\n"
|
||||
" -D dump all the canonical component names (without aliases)\n"
|
||||
" -F use fped footprints instead of KiCad components\n"
|
||||
" -L libdir search all libraries in the specified directory\n"
|
||||
" -l lib search the specified library\n"
|
||||
" -p use portrait orientation; default: landscape\n"
|
||||
" -P generate Postscript instead of PDF (mainly for debugging)\n"
|
||||
" -q don't show progress\n"
|
||||
, name, (int) strlen(name), "");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct lib *lib = &comp_lib;
|
||||
FILE *file;
|
||||
int c;
|
||||
int opt_dump_tree = 0, opt_dump_comp = 0, postscript = 0, portrait = 0;
|
||||
char **arg;
|
||||
|
||||
while ((c = getopt(argc, argv, "dDFL:l:Ppq")) != EOF)
|
||||
switch (c) {
|
||||
case 'd':
|
||||
opt_dump_tree = 1;
|
||||
break;
|
||||
case 'D':
|
||||
opt_dump_comp = 1;
|
||||
break;
|
||||
case 'F':
|
||||
lib = &fped_lib;
|
||||
break;
|
||||
case 'L':
|
||||
add_libdir(lib, optarg);
|
||||
break;
|
||||
case 'l':
|
||||
add_lib(lib, optarg);
|
||||
break;
|
||||
case 'P':
|
||||
postscript = 1;
|
||||
break;
|
||||
case 'p':
|
||||
portrait = 1;
|
||||
break;
|
||||
case 'q':
|
||||
quiet = 1;
|
||||
break;
|
||||
default:
|
||||
usage(*argv);
|
||||
}
|
||||
|
||||
if (opt_dump_tree && opt_dump_comp)
|
||||
usage(*argv);
|
||||
|
||||
switch (argc-optind) {
|
||||
case 1:
|
||||
case 2:
|
||||
break;
|
||||
default:
|
||||
usage(*argv);
|
||||
}
|
||||
|
||||
file = fopen(argv[optind], "r");
|
||||
if (!file) {
|
||||
perror(argv[optind]);
|
||||
exit(1);
|
||||
}
|
||||
read_tree(file);
|
||||
fclose(file);
|
||||
set_libs(lib, tree);
|
||||
|
||||
for (arg = argv+optind+1; *arg; arg++) {
|
||||
file = fopen(*arg, "r");
|
||||
if (!file) {
|
||||
perror(*arg);
|
||||
exit(1);
|
||||
}
|
||||
read_desc(file);
|
||||
fclose(file);
|
||||
}
|
||||
if (opt_dump_tree)
|
||||
dump_tree();
|
||||
else if (opt_dump_comp)
|
||||
dump_comp();
|
||||
else
|
||||
make_pdf(!postscript, portrait);
|
||||
return 0;
|
||||
}
|
||||
17
genkicat/genkicat.h
Normal file
17
genkicat/genkicat.h
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* gencat.h - Generate expanded component view
|
||||
*
|
||||
* Copyright 2012 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.
|
||||
*/
|
||||
|
||||
#ifndef GENCAT_H
|
||||
#define GENCAT_H
|
||||
|
||||
extern int quiet;
|
||||
|
||||
#endif /* !GENCAT_H */
|
||||
112
genkicat/libs.c
Normal file
112
genkicat/libs.c
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* libc.h - Component or module libraries
|
||||
*
|
||||
* Copyright 2012 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.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* for strcasecmp */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "libs.h"
|
||||
|
||||
|
||||
const struct entry *lookup_sym(const struct lib *lib, const char *name)
|
||||
{
|
||||
const struct file *file;
|
||||
const struct entry *e;
|
||||
|
||||
for (file = lib->files; file; file = file->next)
|
||||
for (e = file->entries; e; e = e->next)
|
||||
if (!strcasecmp(e->names->s, name))
|
||||
return e;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void add_name(struct entry *e, char *s)
|
||||
{
|
||||
char *nl;
|
||||
struct name **p;
|
||||
|
||||
nl = strchr(s, '\n');
|
||||
if (nl)
|
||||
*nl = 0;
|
||||
for (p = &e->names; *p; p = &(*p)->next);
|
||||
*p = alloc_type(struct name);
|
||||
(*p)->s = stralloc(s);
|
||||
(*p)->next = NULL;
|
||||
}
|
||||
|
||||
|
||||
struct entry *new_entry(struct lib *lib, int units)
|
||||
{
|
||||
struct entry *e;
|
||||
|
||||
e = alloc_type(struct entry);
|
||||
e->names = NULL;
|
||||
e->units = units;
|
||||
e->file = lib->files;
|
||||
e->next = lib->files->entries;
|
||||
lib->files->entries = e;
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
void add_lib(struct lib *lib, const char *path)
|
||||
{
|
||||
struct file *file;
|
||||
|
||||
file = alloc_type(struct file);
|
||||
file->path = stralloc(path);
|
||||
file->entries = NULL;
|
||||
file->lib = lib;
|
||||
file->next = lib->files;
|
||||
lib->files = file;
|
||||
|
||||
lib->add_lib(lib, path);
|
||||
}
|
||||
|
||||
|
||||
void add_libdir(struct lib *lib, const char *path)
|
||||
{
|
||||
DIR *dir;
|
||||
const struct dirent *de;
|
||||
size_t len;
|
||||
char *tmp;
|
||||
|
||||
assert(strlen(lib->ext) == 4);
|
||||
dir = opendir(path);
|
||||
if (!dir) {
|
||||
perror(path);
|
||||
exit(1);
|
||||
}
|
||||
while (1) {
|
||||
de = readdir(dir);
|
||||
if (!de)
|
||||
break;
|
||||
if (strchr(de->d_name, '~'))
|
||||
continue;
|
||||
len = strlen(de->d_name);
|
||||
if (len < 4)
|
||||
continue;
|
||||
if (strcmp(de->d_name+len-4, lib->ext))
|
||||
continue;
|
||||
if (asprintf(&tmp, "%s/%s", path, de->d_name) < 0) {
|
||||
perror("asprintf");
|
||||
exit(1);
|
||||
}
|
||||
add_lib(lib, tmp);
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
53
genkicat/libs.h
Normal file
53
genkicat/libs.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* libs.h - Component or module libraries
|
||||
*
|
||||
* Copyright 2012 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.
|
||||
*/
|
||||
|
||||
#ifndef LIBS_H
|
||||
#define LIBS_H
|
||||
|
||||
struct name {
|
||||
const char *s;
|
||||
struct name *next;
|
||||
};
|
||||
|
||||
struct entry {
|
||||
struct name *names;
|
||||
int units;
|
||||
const struct file *file;
|
||||
struct entry *next;
|
||||
};
|
||||
|
||||
struct file {
|
||||
const char *path;
|
||||
struct entry *entries;
|
||||
const struct lib *lib;
|
||||
struct file *next;
|
||||
};
|
||||
|
||||
struct lib {
|
||||
const char *ext; /* file extension, ".lib" or ".fpd" */
|
||||
void (*add_lib)(struct lib *lib, const char *path);
|
||||
void (*ps_entry)(FILE *file, const struct lib *lib,
|
||||
const struct entry *e, int unit, int landscape);
|
||||
struct file *files;
|
||||
};
|
||||
|
||||
|
||||
extern struct lib comp_lib;
|
||||
extern struct lib fped_lib;
|
||||
|
||||
|
||||
const struct entry *lookup_sym(const struct lib *lib, const char *name);
|
||||
void add_name(struct entry *e, char *s);
|
||||
struct entry *new_entry(struct lib *lib, int units);
|
||||
void add_lib(struct lib *lib, const char *path);
|
||||
void add_libdir(struct lib *lib, const char *path);
|
||||
|
||||
#endif /* !LIBS_H */
|
||||
49
genkicat/mkgenkicat-wrapper
Executable file
49
genkicat/mkgenkicat-wrapper
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/bin/sh -e
|
||||
#
|
||||
# mkgencat-wrapper - Generate wrapper script for gencat
|
||||
#
|
||||
# Copyright 2012 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.
|
||||
#
|
||||
|
||||
|
||||
MODE=555
|
||||
DIR=
|
||||
|
||||
usage()
|
||||
{
|
||||
echo "usage: $0 [-m mode] [-p directory] wrapper-path" 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
while [ "$1" ]; do
|
||||
case "$1" in
|
||||
-m) shift
|
||||
MODE=$1;;
|
||||
-p) shift
|
||||
DIR=$1;;
|
||||
-*) usage;;
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
: ${DIR:=`dirname $1`}
|
||||
|
||||
[ -d "$DIR" ] && [ "$1" ] && [ -z "$2" ] || usage
|
||||
|
||||
trap "rm -f _wrapper" 0
|
||||
|
||||
cat <<EOF >_wrapper
|
||||
#!/bin/sh
|
||||
PATH=\$PATH:$DIR
|
||||
exec gencat-bin "\$@"
|
||||
EOF
|
||||
chmod $MODE _wrapper
|
||||
|
||||
mv _wrapper "$1"
|
||||
356
genkicat/pdf.c
Normal file
356
genkicat/pdf.c
Normal file
@@ -0,0 +1,356 @@
|
||||
/*
|
||||
* pdf.c - Generate PDF
|
||||
*
|
||||
* Copyright 2012 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.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* for strcasecmp */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "gencat.h"
|
||||
#include "tree.h"
|
||||
#include "libs.h"
|
||||
#include "pdf.h"
|
||||
|
||||
|
||||
static struct format {
|
||||
const char *file_setup;
|
||||
const char *overlay_setup;
|
||||
int left;
|
||||
struct text {
|
||||
const char *font;
|
||||
int size;
|
||||
int y;
|
||||
} name, path, lib, comment, index;
|
||||
int comment_line_skip;
|
||||
int index_line_skip;
|
||||
int index_column_skip;
|
||||
int index_lines;
|
||||
int index_columns;
|
||||
} landscape = {
|
||||
.file_setup = "%%Orientation: Landscape",
|
||||
.overlay_setup = "90 rotate",
|
||||
.left = 20,
|
||||
.name = { "Helvetica-Bold", 24, 57 },
|
||||
.path = { "Helvetica-Bold", 18, 30 },
|
||||
.lib = { "Courier", 12, 75 },
|
||||
.comment = { "Helvetica", 12, 600 },
|
||||
.index = { "Helvetica", 10, 32 },
|
||||
.comment_line_skip = 14,
|
||||
.index_line_skip = 12,
|
||||
.index_column_skip = 195, /* make a little wider than in portrait */
|
||||
.index_lines = 45,
|
||||
.index_columns = 4,
|
||||
}, portrait = {
|
||||
.file_setup = "%%Orientation: Portrait",
|
||||
.overlay_setup = "0 790 translate",
|
||||
.left = 20,
|
||||
.name = { "Helvetica-Bold", 24, 57 },
|
||||
.path = { "Helvetica-Bold", 18, 30 },
|
||||
.lib = { "Courier", 12, 75 },
|
||||
.comment = { "Helvetica", 12, 740 },
|
||||
.index = { "Helvetica", 10, 0 },
|
||||
.comment_line_skip = 14,
|
||||
.index_line_skip = 12,
|
||||
.index_column_skip = 185,
|
||||
.index_lines = 63,
|
||||
.index_columns = 3,
|
||||
};
|
||||
|
||||
static const struct format *format;
|
||||
|
||||
static int total, done = 0;
|
||||
|
||||
|
||||
/* ----- Utility functions ------------------------------------------------- */
|
||||
|
||||
|
||||
static void ps_string(FILE *file, const char *s)
|
||||
{
|
||||
fputc('(', file);
|
||||
while (*s) {
|
||||
if (*s == '(' || *s == ')' || *s == '\\')
|
||||
fputc('\\', file);
|
||||
fputc(*s, file);
|
||||
s++;
|
||||
}
|
||||
fputc(')', file);
|
||||
}
|
||||
|
||||
|
||||
/* ----- Alphabetic index -------------------------------------------------- */
|
||||
|
||||
|
||||
struct index {
|
||||
const char *s;
|
||||
const struct node *node;
|
||||
};
|
||||
|
||||
|
||||
static void collect_names(const struct node *node, struct index **idx, int *n)
|
||||
{
|
||||
const struct name *name;
|
||||
|
||||
while (node) {
|
||||
if (node->child)
|
||||
collect_names(node->child, idx, n);
|
||||
else {
|
||||
for (name = node->e->names; name; name = name->next) {
|
||||
(*n)++;
|
||||
*idx = realloc(*idx, *n*sizeof(struct entry));
|
||||
if (!*idx)
|
||||
abort();
|
||||
(*idx)[*n-1].s = name->s;
|
||||
(*idx)[*n-1].node = node;
|
||||
}
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int comp(const void *a, const void *b)
|
||||
{
|
||||
const struct index *ai = a;
|
||||
const struct index *bi = b;
|
||||
|
||||
return strcasecmp(ai->s, bi->s);
|
||||
}
|
||||
|
||||
|
||||
static void make_index(FILE *file, const struct node *node)
|
||||
{
|
||||
struct index *idx = NULL;
|
||||
const struct index *p;
|
||||
int n = 0;
|
||||
int line = 0, col = 0;
|
||||
|
||||
collect_names(node, &idx, &n);
|
||||
qsort(idx, n, sizeof(struct index), comp);
|
||||
|
||||
fprintf(file, "[ /Title (Index) /Count 0 /OUT pdfmark\n");
|
||||
|
||||
fprintf(file, "/%s findfont %d scalefont setfont\n",
|
||||
format->index.font, format->index.size);
|
||||
fprintf(file, "gsave %s 0 setgray\n", format->overlay_setup);
|
||||
|
||||
for (p = idx; p != idx+n; p++) {
|
||||
if (line == format->index_lines) {
|
||||
line = 0;
|
||||
col++;
|
||||
}
|
||||
if (col == format->index_columns) {
|
||||
fprintf(file, "grestore showpage\n");
|
||||
fprintf(file, "gsave %s 0 setgray\n",
|
||||
format->overlay_setup);
|
||||
col = 0;
|
||||
}
|
||||
fprintf(file, "newpath %d -%d moveto currentpoint\n",
|
||||
format->left+col*format->index_column_skip,
|
||||
format->index.y+line*format->index_line_skip);
|
||||
|
||||
fprintf(file, "[ /Rect [ ");
|
||||
ps_string(file, p->s);
|
||||
fprintf(file, " false charpath flattenpath pathbbox ]\n");
|
||||
fprintf(file, " /Subtype /Link\n");
|
||||
fprintf(file, " /Border [ 0 0 0 ]\n");
|
||||
fprintf(file, " /Action << /Subtype /GoTo /Dest /%p%p >>\n",
|
||||
p->node, p->s);
|
||||
fprintf(file, " /ANN pdfmark\n");
|
||||
|
||||
fprintf(file, "moveto ");
|
||||
ps_string(file, p->s);
|
||||
fprintf(file, " show\n");
|
||||
line++;
|
||||
}
|
||||
fprintf(file, "grestore showpage\n");
|
||||
|
||||
free(idx);
|
||||
}
|
||||
|
||||
|
||||
/* ----- Overlay and table of contents ------------------------------------- */
|
||||
|
||||
|
||||
static int children(const struct node *node)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
while (node) {
|
||||
n++;
|
||||
node = node->next;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
static void print_path(FILE *file, const struct node *node)
|
||||
{
|
||||
if (node->parent) {
|
||||
print_path(file, node->parent);
|
||||
fprintf(file, "( > ) show\n");
|
||||
}
|
||||
ps_string(file, node->name);
|
||||
fprintf(file, " 0.5 setgray show 0 setgray\n");
|
||||
}
|
||||
|
||||
|
||||
static void make_title(FILE *file, const struct node *node, int unit)
|
||||
{
|
||||
const struct name *name;
|
||||
|
||||
fprintf(file, "gsave %s 0 setgray\n", format->overlay_setup);
|
||||
|
||||
fprintf(file, "/%s findfont %d scalefont setfont\n",
|
||||
format->name.font, format->name.size);
|
||||
fprintf(file, "%d %d moveto\n", format->left, -format->name.y);
|
||||
for (name = node->e->names; name; name = name->next) {
|
||||
if (name != node->e->names)
|
||||
fprintf(file, "(, ) show 0.5 setgray\n");
|
||||
ps_string(file, name->s);
|
||||
fprintf(file, " show\n");
|
||||
if (!unit)
|
||||
fprintf(file, "[ /Dest /%p%p /DEST pdfmark\n",
|
||||
node, name->s);
|
||||
}
|
||||
fprintf(file, "0 setgray\n");
|
||||
if (node->e->units > 1)
|
||||
fprintf(file, " ( \\(%c\\)) show\n", 'A'+unit);
|
||||
|
||||
fprintf(file, "/%s findfont %d scalefont setfont\n",
|
||||
format->path.font, format->path.size);
|
||||
fprintf(file, "%d %d moveto\n", format->left, -format->path.y);
|
||||
print_path(file, node);
|
||||
|
||||
fprintf(file, "/%s findfont %d scalefont setfont\n",
|
||||
format->lib.font, format->lib.size);
|
||||
fprintf(file, "%d %d moveto\n", format->left, -format->lib.y);
|
||||
ps_string(file, node->e->file->path);
|
||||
fprintf(file, " show\n");
|
||||
|
||||
fprintf(file, "grestore\n");
|
||||
}
|
||||
|
||||
|
||||
static void print_comment(FILE *file, const struct line *comment)
|
||||
{
|
||||
const struct line *line;
|
||||
int lines = 0;
|
||||
int n;
|
||||
|
||||
fprintf(file, "gsave %s 0 setgray\n", format->overlay_setup);
|
||||
fprintf(file, "/%s findfont %d scalefont setfont\n",
|
||||
format->comment.font, format->comment.size);
|
||||
for (line = comment; line; line = line->next)
|
||||
lines++;
|
||||
n = 0;
|
||||
for (line = comment; line; line = line->next) {
|
||||
n++;
|
||||
fprintf(file, "%d -%d moveto\n", format->left,
|
||||
format->comment.y+(n-lines)*format->comment_line_skip);
|
||||
ps_string(file, line->s);
|
||||
fprintf(file, " show\n");
|
||||
}
|
||||
fprintf(file, "grestore\n");
|
||||
}
|
||||
|
||||
|
||||
/* ----- Component conversion ---------------------------------------------- */
|
||||
|
||||
|
||||
static void convert_entry(const struct node *node, FILE *out)
|
||||
{
|
||||
const struct lib *lib = node->e->file->lib;
|
||||
int i;
|
||||
|
||||
for (i = 0; i != node->e->units; i++) {
|
||||
if (!quiet) {
|
||||
fprintf(stderr, "\r%u/%u", ++done, total);
|
||||
fflush(stderr);
|
||||
}
|
||||
make_title(out, node, i);
|
||||
if (!i && node->comment)
|
||||
print_comment(out, node->comment);
|
||||
fprintf(out, "gsave\n");
|
||||
node->e->file->lib->ps_entry(out, lib, node->e, i,
|
||||
format == &landscape);
|
||||
fprintf(out, "\ngrestore\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void convert_tree(const struct node *node, FILE *out)
|
||||
{
|
||||
while (node) {
|
||||
fprintf(out, "[ /Title (%s) /Count %d /OUT pdfmark\n",
|
||||
node->name, -children(node->child));
|
||||
if (node->child)
|
||||
convert_tree(node->child, out);
|
||||
else
|
||||
convert_entry(node, out);
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ----- Setup and PDF generation ------------------------------------------ */
|
||||
|
||||
|
||||
static int count_tree(const struct node *node)
|
||||
{
|
||||
int sum = 0;
|
||||
|
||||
while (node) {
|
||||
if (node->child)
|
||||
sum += count_tree(node->child);
|
||||
else
|
||||
sum += node->e->units;
|
||||
node = node->next;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
void make_pdf(int pdf, int use_portrait)
|
||||
{
|
||||
FILE *out;
|
||||
int res;
|
||||
|
||||
if (use_portrait)
|
||||
format = &portrait;
|
||||
else
|
||||
format = &landscape;
|
||||
if (pdf)
|
||||
out = popen(
|
||||
"gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=- "
|
||||
"-f -", "w");
|
||||
else
|
||||
out = popen("cat", "w");
|
||||
if (!out) {
|
||||
perror("gs");
|
||||
exit(1);
|
||||
}
|
||||
fprintf(out, "%%!PS\n%s\n", format->file_setup);
|
||||
make_index(out, tree);
|
||||
total = count_tree(tree);
|
||||
convert_tree(tree, out);
|
||||
if (!quiet)
|
||||
fprintf(stderr, "\rFinishing\n");
|
||||
res = pclose(out);
|
||||
if (res < 0) {
|
||||
perror("pclose");
|
||||
exit(1);
|
||||
}
|
||||
if (res) {
|
||||
fprintf(stderr, "exit status %d\n", res);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
17
genkicat/pdf.h
Normal file
17
genkicat/pdf.h
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* pdf.h - Generate PDF
|
||||
*
|
||||
* Copyright 2012 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.
|
||||
*/
|
||||
|
||||
#ifndef PDF_H
|
||||
#define PDF_H
|
||||
|
||||
void make_pdf(int pdf, int use_portrait);
|
||||
|
||||
#endif /* !PDF_H */
|
||||
6
genkicat/run
Executable file
6
genkicat/run
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
# Hack: ps2pdf is happy with the PS generate, but if we invoke gs diretctly,
|
||||
# isn't. Some voodoo is still missing ...
|
||||
./gencat -p \
|
||||
-L /home/qi/kicad-libs/components \
|
||||
/home/qi/kicad-libs/components/EXPAND DESC >out.pdf
|
||||
70
genkicat/run.c
Normal file
70
genkicat/run.c
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* run.c - Run helper scripts
|
||||
*
|
||||
* Copyright 2012 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.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* for vasprintf */
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "run.h"
|
||||
|
||||
|
||||
void run_cmd(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *tmp;
|
||||
int res;
|
||||
|
||||
va_start(ap, fmt);
|
||||
if (vasprintf(&tmp, fmt, ap) < 0) {
|
||||
perror("vasprintf");
|
||||
exit(1);
|
||||
}
|
||||
res = system(tmp);
|
||||
if (res < 0) {
|
||||
perror("system");
|
||||
exit(1);
|
||||
}
|
||||
if (res) {
|
||||
fprintf(stderr, "\"%s\" returned %d\n", tmp, res);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void cat(FILE *out, const char *name)
|
||||
{
|
||||
FILE *in;
|
||||
char buf[10000]; /* pick any good size */
|
||||
size_t got, wrote;
|
||||
|
||||
in = fopen(name, "r");
|
||||
if (!in) {
|
||||
perror(name);
|
||||
exit(1);
|
||||
}
|
||||
while (1) {
|
||||
got = fread(buf, 1, sizeof(buf), in);
|
||||
if (!got)
|
||||
break;
|
||||
wrote = fwrite(buf, 1, got, out);
|
||||
if (wrote != got) {
|
||||
perror("fwrite");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (ferror(in)) {
|
||||
perror(name);
|
||||
exit(1);
|
||||
}
|
||||
fclose(in);
|
||||
}
|
||||
18
genkicat/run.h
Normal file
18
genkicat/run.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* run.h - Run helper scripts
|
||||
*
|
||||
* Copyright 2012 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.
|
||||
*/
|
||||
|
||||
#ifndef RUN_H
|
||||
#define RUN_H
|
||||
|
||||
void run_cmd(const char *fmt, ...);
|
||||
void cat(FILE *out, const char *name);
|
||||
|
||||
#endif /* !RUN_H */
|
||||
84
genkicat/sym2xps
Executable file
84
genkicat/sym2xps
Executable file
@@ -0,0 +1,84 @@
|
||||
#!/bin/sh -e
|
||||
#
|
||||
# sym2xps - Convert a symbol from a Kicad library to Postscript with expanded
|
||||
# pin types
|
||||
#
|
||||
# Copyright 2012 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.
|
||||
#
|
||||
|
||||
|
||||
usage()
|
||||
{
|
||||
echo "usage: $0 library symbol unit tmpdir outfile" 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
lib=$1
|
||||
sym=$2
|
||||
unit=$3
|
||||
tmp=$4
|
||||
out=$5
|
||||
|
||||
[ "$lib" ] && [ "$sym" ] && [ "$unit" ] && [ "$tmp" ] && [ "$out" ] || usage
|
||||
|
||||
[ -r "$lib" ] || {
|
||||
echo "$lib: not found" 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
grep "^DEF $sym " "$lib" >/dev/null || grep "^DEF ~$sym " "$lib" >/dev/null || {
|
||||
echo "\"$sym\" not found in $lib" 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
[ "${tmp#/}" = "$tmp" ] && tmp=`pwd`/$tmp
|
||||
[ "${out#/}" = "$out" ] && out=`pwd`/$out
|
||||
|
||||
mkdir "$tmp"
|
||||
|
||||
trap "rm -rf '$tmp'" 0
|
||||
|
||||
expand-pintype "$lib" "$tmp"/tmp.lib
|
||||
|
||||
cat <<EOF >"$tmp"/tmp.pro
|
||||
[eeschema]
|
||||
version=1
|
||||
[eeschema/libraries]
|
||||
LibName1=./tmp
|
||||
EOF
|
||||
|
||||
X=6000
|
||||
Y=4000
|
||||
|
||||
sed "\@^DEF $sym @,/^ENDDEF/p;d" "$lib" |
|
||||
awk '/^F. / { if ($1 == "F0") sub(/"$/, "?\"", $2);
|
||||
print substr($1, 1, 1), substr($1, 2, 1), $2,
|
||||
$6, '$X'+$3, '$Y'+$4, $5, " 0000", $8, $9 }' >"$tmp"/fx.tmp
|
||||
#F field_number "text" orientation posX posY size Flags (see below)
|
||||
#F0 reference posx posy text_size text_orient visibile htext_justify vtext_justify
|
||||
|
||||
cat <<EOF >"$tmp"/tmp.sch
|
||||
EESchema Schematic File Version 2 date Mon Mar 26 09:29:33 2012
|
||||
LIBS:dummy
|
||||
EELAYER 43 0
|
||||
EELAYER END
|
||||
\$Comp
|
||||
L X$sym ??
|
||||
U $unit 1 00000000
|
||||
P $X $Y
|
||||
`cat "$tmp"/fx.tmp`
|
||||
$unit $X $Y
|
||||
1 0 0 -1
|
||||
\$EndComp
|
||||
\$EndSCHEMATC
|
||||
EOF
|
||||
|
||||
cd "$tmp"
|
||||
eeschema --plot=ps "$tmp/tmp.sch"
|
||||
mv tmp.ps "$out"
|
||||
269
genkicat/tree.c
Normal file
269
genkicat/tree.c
Normal file
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* tree.c - Component hierarchy
|
||||
*
|
||||
* Copyright 2012 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.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* for strcasecmp */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "libs.h"
|
||||
#include "tree.h"
|
||||
|
||||
|
||||
struct node *tree = NULL;
|
||||
|
||||
|
||||
void read_tree(FILE *file)
|
||||
{
|
||||
char buf[1100]; /* more than enough */
|
||||
struct node *last = NULL, *node;
|
||||
int depth = -1;
|
||||
const char *s, *p, *e;
|
||||
char *name;
|
||||
int n;
|
||||
|
||||
next:
|
||||
while (fgets(buf, sizeof(buf), file)) {
|
||||
n = 0;
|
||||
s = buf;
|
||||
while (1) {
|
||||
switch (*s++) {
|
||||
case ' ':
|
||||
n++;
|
||||
continue;
|
||||
case '\t':
|
||||
n = (n+8) & ~7;
|
||||
continue;
|
||||
case 0:
|
||||
case '#':
|
||||
goto next;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (p = e = --s; *p && *p != '#' && *p != '\n'; p++)
|
||||
if (*p != ' ' && *p != '\t')
|
||||
e = p;
|
||||
if (!last && n) {
|
||||
fprintf(stderr, "first entry must not be intended\n");
|
||||
exit(1);
|
||||
}
|
||||
name = malloc(e-s+2);
|
||||
if (!name) {
|
||||
perror("malloc");
|
||||
exit(1);
|
||||
}
|
||||
memcpy(name, s, e-s+1);
|
||||
name[e-s+1] = 0;
|
||||
node = alloc_type(struct node);
|
||||
node->name = name;
|
||||
node->e = NULL;
|
||||
node->comment = NULL;
|
||||
node->indent = n;
|
||||
node->child = node->next = NULL;
|
||||
if (n > depth) {
|
||||
if (last)
|
||||
last->child = node;
|
||||
else
|
||||
tree = node;
|
||||
node->parent = last;
|
||||
} else {
|
||||
while (last && last->indent != n)
|
||||
last = last->parent;
|
||||
if (!last && n) {
|
||||
fprintf(stderr, "indentation error\n");
|
||||
exit(1);
|
||||
}
|
||||
last->next = node;
|
||||
node->parent = last->parent;
|
||||
}
|
||||
last = node;
|
||||
depth = n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct node *find_comp(struct node *node, const char *name)
|
||||
{
|
||||
struct node *found;
|
||||
|
||||
while (node) {
|
||||
if (!strcasecmp(node->name, name))
|
||||
return node;
|
||||
found = find_comp(node->child, name);
|
||||
if (found)
|
||||
return found;
|
||||
node = node->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static struct line *new_line(char *s)
|
||||
{
|
||||
struct line *line;
|
||||
|
||||
line = alloc_type(struct line);
|
||||
line->s = stralloc(s);
|
||||
line->next = NULL;
|
||||
return line;
|
||||
}
|
||||
|
||||
|
||||
static void append_line(struct line *line, char *s)
|
||||
{
|
||||
int len1, len2;
|
||||
|
||||
len1 = strlen(line->s);
|
||||
len2 = strlen(s);
|
||||
line->s = realloc(line->s, len1+len2+1+1); /* separating space */
|
||||
if (!line->s) {
|
||||
perror("realloc");
|
||||
exit(1);
|
||||
}
|
||||
line->s[len1] = ' ';
|
||||
memcpy(line->s+len1+1, s, len2);
|
||||
line->s[len1+len2+1] = 0;
|
||||
}
|
||||
|
||||
|
||||
void read_desc(FILE *file)
|
||||
{
|
||||
struct line **anchor = NULL;
|
||||
char buf[1100]; /* more than enough */
|
||||
struct node *node;
|
||||
char *p, *end;
|
||||
int skip = 0, lineno = 0;
|
||||
|
||||
while (fgets(buf, sizeof(buf), file)) {
|
||||
lineno++;
|
||||
if (buf[0] == '#')
|
||||
continue;
|
||||
p = strchr(buf, '\n');
|
||||
if (p)
|
||||
*p = 0;
|
||||
p = buf;
|
||||
if (*buf && !isspace(*buf)) {
|
||||
/* tag is ^.*?:\s */
|
||||
while (1) {
|
||||
p = strchr(p, ':');
|
||||
if (!p) {
|
||||
fprintf(stderr, "no tag in line %d\n",
|
||||
lineno);
|
||||
exit(1);
|
||||
}
|
||||
if (!p[1] || isspace(p[1]))
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
*p++ = 0;
|
||||
node = find_comp(tree, buf);
|
||||
if (!node) {
|
||||
fprintf(stderr,
|
||||
"component \"%s\" not found in line %d\n",
|
||||
buf, lineno);
|
||||
skip = 1;
|
||||
continue;
|
||||
}
|
||||
for (anchor = &node->comment; *anchor;
|
||||
anchor = &(*anchor)->next);
|
||||
skip = 0;
|
||||
}
|
||||
if (skip)
|
||||
continue;
|
||||
|
||||
/* remove leading whitespace */
|
||||
while (*p && isspace(*p))
|
||||
p++;
|
||||
if (!*p) {
|
||||
if (*anchor)
|
||||
anchor = &(*anchor)->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* remove training whitespace */
|
||||
end = strrchr(p, 0);
|
||||
while (isspace(end[-1]))
|
||||
end--;
|
||||
*end = 0;
|
||||
|
||||
if (*anchor)
|
||||
append_line(*anchor, p);
|
||||
else
|
||||
*anchor = new_line(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void set_libs(const struct lib *lib, struct node *node)
|
||||
{
|
||||
while (node) {
|
||||
if (!node->child) {
|
||||
node->e = lookup_sym(lib, node->name);
|
||||
if (!node->e) {
|
||||
fprintf(stderr, "symbol %s not found\n",
|
||||
node->name);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
set_libs(lib, node->child);
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void dump_tree_level(const struct node *tree, int level)
|
||||
{
|
||||
const struct node *n;
|
||||
const struct line *line;
|
||||
const struct name *name;
|
||||
|
||||
for (n = tree; n; n = n->next) {
|
||||
printf("%*s%s", 4*level, "", n->name);
|
||||
if (n->e) {
|
||||
for (name = n->e->names; name; name = name->next)
|
||||
printf("%s%s",
|
||||
name == n->e->names ? " (" : ", ", name->s);
|
||||
printf(")");
|
||||
}
|
||||
printf("\n");
|
||||
for (line = n->comment; line; line = line->next)
|
||||
printf("%*s\"%s\"\n", 4*level+2, "", line->s);
|
||||
dump_tree_level(n->child, level+1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dump_tree(void)
|
||||
{
|
||||
dump_tree_level(tree, 0);
|
||||
}
|
||||
|
||||
|
||||
static void dump_comp_level(const struct node *tree)
|
||||
{
|
||||
const struct node *n;
|
||||
|
||||
for (n = tree; n; n = n->next) {
|
||||
if (n->e)
|
||||
printf("%s\n", n->e->names->s);
|
||||
dump_comp_level(n->child);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dump_comp(void)
|
||||
{
|
||||
dump_comp_level(tree);
|
||||
}
|
||||
43
genkicat/tree.h
Normal file
43
genkicat/tree.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* tree.h - Component hierarchy
|
||||
*
|
||||
* Copyright 2012 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.
|
||||
*/
|
||||
|
||||
#ifndef TREE_H
|
||||
#define TREE_H
|
||||
|
||||
#include "libs.h"
|
||||
|
||||
|
||||
struct line {
|
||||
char *s;
|
||||
struct line *next;
|
||||
};
|
||||
|
||||
struct node {
|
||||
const char *name;
|
||||
const struct entry *e; /* NULL if intermediate node */
|
||||
struct line *comment; /* NULL if intermediate node */
|
||||
int indent; /* level of indentation (characters) */
|
||||
struct node *parent;
|
||||
struct node *child;
|
||||
struct node *next;
|
||||
};
|
||||
|
||||
|
||||
extern struct node *tree;
|
||||
|
||||
|
||||
void read_tree(FILE *file);
|
||||
void read_desc(FILE *file);
|
||||
void set_libs(const struct lib *lib, struct node *node);
|
||||
void dump_tree(void);
|
||||
void dump_comp(void);
|
||||
|
||||
#endif /* !TREE_H */
|
||||
39
genkicat/util.h
Normal file
39
genkicat/util.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* util.h - Utility functions
|
||||
*
|
||||
* Copyright 2012 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.
|
||||
*/
|
||||
|
||||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define alloc_size(s) \
|
||||
({ void *alloc_size_tmp = malloc(s); \
|
||||
if (!alloc_size_tmp) \
|
||||
abort(); \
|
||||
alloc_size_tmp; })
|
||||
|
||||
#define alloc_type(t) ((t *) alloc_size(sizeof(t)))
|
||||
|
||||
|
||||
static inline char *stralloc(const char *s)
|
||||
{
|
||||
char *t;
|
||||
|
||||
t = strdup(s);
|
||||
if (t)
|
||||
return t;
|
||||
perror("strdup");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#endif /* !UTIL_H */
|
||||
Reference in New Issue
Block a user