gencat/Makefile |
| 1 | # |
| 2 | # Makefile - Expanded component view generator |
| 3 | # |
| 4 | # Copyright 2012 by Werner Almesberger |
| 5 | # |
| 6 | # This program is free software; you can redistribute it and/or modify |
| 7 | # it under the terms of the GNU General Public License as published by |
| 8 | # the Free Software Foundation; either version 2 of the License, or |
| 9 | # (at your option) any later version. |
| 10 | # |
| 11 | |
| 12 | PREFIX ?= /usr/local |
| 13 | |
| 14 | OBJS = gencat.o comp.o libs.o pdf.o |
| 15 | |
| 16 | SHELL = /bin/bash |
| 17 | CFLAGS = -Wall -g |
| 18 | |
| 19 | CC_normal := $(CC) |
| 20 | DEPEND_normal := $(CPP) $(CFLAGS) -MM -MG |
| 21 | |
| 22 | CC_quiet = @echo " CC " $@ && $(CC_normal) |
| 23 | GEN_quiet = @echo " GENERATE " $@ && |
| 24 | DEPEND_quiet = @$(DEPEND_normal) |
| 25 | |
| 26 | ifeq ($(V),1) |
| 27 | CC = $(CC_normal) |
| 28 | GEN = |
| 29 | DEPEND = $(DEPEND_normal) |
| 30 | else |
| 31 | CC = $(CC_quiet) |
| 32 | GEN = $(GEN_quiet) |
| 33 | DEPEND = $(DEPEND_quiet) |
| 34 | endif |
| 35 | |
| 36 | .PHONY: all clean spotless install uninstall |
| 37 | |
| 38 | all: gencat-bin |
| 39 | |
| 40 | gencat-bin: $(OBJS) |
| 41 | $(CC) $(CFLAGS) -o $@ $(OBJS) $(LDLIBS) |
| 42 | |
| 43 | %.o: %.c |
| 44 | $(CC) -c $(CFLAGS) $*.c -o $*.o |
| 45 | $(DEPEND) $*.c | \ |
| 46 | sed -e \ |
| 47 | '/^\(.*:\)\? */{p;s///;s/ *\\\?$$/ /;s/ */:\n/g;H;}' \ |
| 48 | -e '$${g;p;}' -e d >$*.d; \ |
| 49 | [ "$${PIPESTATUS[*]}" = "0 0" ] || { rm -f $*.d; exit 1; } |
| 50 | |
| 51 | -include $(OBJS:.o=.d) |
| 52 | |
| 53 | clean: |
| 54 | rm -f $(OBJS) $(OBJS:.o=.d) |
| 55 | |
| 56 | spotless: clean |
| 57 | rm -f gencat-bin |
| 58 | |
| 59 | # |
| 60 | # Note: we use .../lib/gencat/ instead of .../libexec/gencat/ because FHS-3.0 |
| 61 | # does not define libexec under the /usr/local/ hierarchy. (And older versions |
| 62 | # of FHS don't define libexec at all.) |
| 63 | # |
| 64 | |
| 65 | install: all |
| 66 | mkdir -p $(DESTDIR)/$(PREFIX)/bin |
| 67 | mkdir -p $(DESTDIR)/$(PREFIX)/lib/gencat |
| 68 | ./mkgencat-wrapper -m 755 -p $(DESTDIR)/$(PREFIX)/lib/gencat/ \ |
| 69 | $(DESTDIR)/$(PREFIX)/bin/gencat |
| 70 | install -m 755 gencat-bin $(DESTDIR)/$(PREFIX)/lib/gencat/ |
| 71 | install -m 755 sym2xps $(DESTDIR)/$(PREFIX)/lib/gencat/ |
| 72 | install -m 755 expand-pintype $(DESTDIR)/$(PREFIX)/lib/gencat/ |
| 73 | |
| 74 | uninstall: |
| 75 | rm -f $(DESTDIR)/$(PREFIX)/bin/gencat |
| 76 | rm -rf $(DESTDIR)/$(PREFIX)/lib/gencat |
| 77 | |
gencat/comp.c |
| 1 | /* |
| 2 | * comp.c - Component hierarchy |
| 3 | * |
| 4 | * Copyright 2012 by Werner Almesberger |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; either version 2 of the License, or |
| 9 | * (at your option) any later version. |
| 10 | */ |
| 11 | |
| 12 | #define _GNU_SOURCE /* for strcasecmp */ |
| 13 | #include <stdlib.h> |
| 14 | #include <stdio.h> |
| 15 | #include <string.h> |
| 16 | #include <ctype.h> |
| 17 | |
| 18 | #include "util.h" |
| 19 | #include "comp.h" |
| 20 | |
| 21 | |
| 22 | struct node *tree = NULL; |
| 23 | |
| 24 | |
| 25 | void read_tree(FILE *file) |
| 26 | { |
| 27 | char buf[1100]; /* more than enough */ |
| 28 | struct node *last = NULL, *node; |
| 29 | int depth = -1; |
| 30 | const char *s, *p, *e; |
| 31 | char *name; |
| 32 | int n; |
| 33 | |
| 34 | next: |
| 35 | while (fgets(buf, sizeof(buf), file)) { |
| 36 | n = 0; |
| 37 | s = buf; |
| 38 | while (1) { |
| 39 | switch (*s++) { |
| 40 | case ' ': |
| 41 | n++; |
| 42 | continue; |
| 43 | case '\t': |
| 44 | n = (n+8) & ~7; |
| 45 | continue; |
| 46 | case 0: |
| 47 | case '#': |
| 48 | goto next; |
| 49 | default: |
| 50 | break; |
| 51 | } |
| 52 | break; |
| 53 | } |
| 54 | for (p = e = --s; *p && *p != '#' && *p != '\n'; p++) |
| 55 | if (*p != ' ' && *p != '\t') |
| 56 | e = p; |
| 57 | if (!last && n) { |
| 58 | fprintf(stderr, "first entry must not be intended\n"); |
| 59 | exit(1); |
| 60 | } |
| 61 | name = malloc(e-s+2); |
| 62 | if (!name) { |
| 63 | perror("malloc"); |
| 64 | exit(1); |
| 65 | } |
| 66 | memcpy(name, s, e-s+1); |
| 67 | name[e-s+1] = 0; |
| 68 | node = alloc_type(struct node); |
| 69 | node->name = name; |
| 70 | node->lib = NULL; |
| 71 | node->comment = NULL; |
| 72 | node->indent = n; |
| 73 | node->child = node->next = NULL; |
| 74 | if (n > depth) { |
| 75 | if (last) |
| 76 | last->child = node; |
| 77 | else |
| 78 | tree = node; |
| 79 | node->parent = last; |
| 80 | } else { |
| 81 | while (last && last->indent != n) |
| 82 | last = last->parent; |
| 83 | if (!last && n) { |
| 84 | fprintf(stderr, "indentation error\n"); |
| 85 | exit(1); |
| 86 | } |
| 87 | last->next = node; |
| 88 | node->parent = last->parent; |
| 89 | } |
| 90 | last = node; |
| 91 | depth = n; |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | |
| 96 | static struct node *find_comp(struct node *node, const char *name) |
| 97 | { |
| 98 | struct node *found; |
| 99 | |
| 100 | while (node) { |
| 101 | if (!strcasecmp(node->name, name)) |
| 102 | return node; |
| 103 | found = find_comp(node->child, name); |
| 104 | if (found) |
| 105 | return found; |
| 106 | node = node->next; |
| 107 | } |
| 108 | return NULL; |
| 109 | } |
| 110 | |
| 111 | |
| 112 | static struct line *new_line(char *s) |
| 113 | { |
| 114 | struct line *line; |
| 115 | |
| 116 | line = alloc_type(struct line); |
| 117 | line->s = stralloc(s); |
| 118 | line->next = NULL; |
| 119 | return line; |
| 120 | } |
| 121 | |
| 122 | |
| 123 | static void append_line(struct line *line, char *s) |
| 124 | { |
| 125 | int len1, len2; |
| 126 | |
| 127 | len1 = strlen(line->s); |
| 128 | len2 = strlen(s); |
| 129 | line->s = realloc(line->s, len1+len2+1+1); /* separating space */ |
| 130 | if (!line->s) { |
| 131 | perror("realloc"); |
| 132 | exit(1); |
| 133 | } |
| 134 | line->s[len1] = ' '; |
| 135 | memcpy(line->s+len1+1, s, len2); |
| 136 | line->s[len1+len2+1] = 0; |
| 137 | } |
| 138 | |
| 139 | |
| 140 | void read_desc(FILE *file) |
| 141 | { |
| 142 | struct line **anchor = NULL; |
| 143 | char buf[1100]; /* more than enough */ |
| 144 | struct node *node; |
| 145 | char *p, *end; |
| 146 | int skip = 0, lineno = 0; |
| 147 | |
| 148 | while (fgets(buf, sizeof(buf), file)) { |
| 149 | lineno++; |
| 150 | p = strchr(buf, '\n'); |
| 151 | if (p) |
| 152 | *p = 0; |
| 153 | p = buf; |
| 154 | if (*buf && !isspace(*buf)) { |
| 155 | /* tag is ^.*?:\s */ |
| 156 | while (1) { |
| 157 | p = strchr(p, ':'); |
| 158 | if (!p) { |
| 159 | fprintf(stderr, "no tag in line %d\n", |
| 160 | lineno); |
| 161 | exit(1); |
| 162 | } |
| 163 | if (!p[1] || isspace(p[1])) |
| 164 | break; |
| 165 | p++; |
| 166 | } |
| 167 | *p++ = 0; |
| 168 | node = find_comp(tree, buf); |
| 169 | if (!node) { |
| 170 | fprintf(stderr, |
| 171 | "component \"%s\" not found in line %d\n", |
| 172 | buf, lineno); |
| 173 | skip = 1; |
| 174 | continue; |
| 175 | } |
| 176 | for (anchor = &node->comment; *anchor; |
| 177 | anchor = &(*anchor)->next); |
| 178 | skip = 0; |
| 179 | } |
| 180 | if (skip) |
| 181 | continue; |
| 182 | |
| 183 | /* remove leading whitespace */ |
| 184 | while (*p && isspace(*p)) |
| 185 | p++; |
| 186 | if (!*p) { |
| 187 | if (*anchor) |
| 188 | anchor = &(*anchor)->next; |
| 189 | continue; |
| 190 | } |
| 191 | |
| 192 | /* remove training whitespace */ |
| 193 | end = strrchr(p, 0); |
| 194 | while (isspace(end[-1])) |
| 195 | end--; |
| 196 | *end = 0; |
| 197 | |
| 198 | if (*anchor) |
| 199 | append_line(*anchor, p); |
| 200 | else |
| 201 | *anchor = new_line(p); |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | |
| 206 | void set_libs(struct node *node, |
| 207 | const char *(*find_lib)(const char *sym, const struct name **names, |
| 208 | int *units)) |
| 209 | { |
| 210 | while (node) { |
| 211 | if (!node->child) { |
| 212 | node->lib = |
| 213 | find_lib(node->name, &node->names, &node->units); |
| 214 | if (!node->lib) { |
| 215 | fprintf(stderr, "symbol %s not found\n", |
| 216 | node->name); |
| 217 | exit(1); |
| 218 | } |
| 219 | } |
| 220 | set_libs(node->child, find_lib); |
| 221 | node = node->next; |
| 222 | } |
| 223 | } |
| 224 | |
| 225 | |
| 226 | static void dump_tree_level(const struct node *tree, int level) |
| 227 | { |
| 228 | const struct node *n; |
| 229 | const struct line *line; |
| 230 | const struct name *name; |
| 231 | |
| 232 | for (n = tree; n; n = n->next) { |
| 233 | printf("%*s%s", 4*level, "", n->name); |
| 234 | if (n->lib) { |
| 235 | for (name = n->names; name; name = name->next) |
| 236 | printf("%s%s", |
| 237 | name == n->names ? " (" : ", ", name->s); |
| 238 | printf(")"); |
| 239 | } |
| 240 | printf("\n"); |
| 241 | for (line = n->comment; line; line = line->next) |
| 242 | printf("%*s\"%s\"\n", 4*level+2, "", line->s); |
| 243 | dump_tree_level(n->child, level+1); |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | |
| 248 | void dump_tree(void) |
| 249 | { |
| 250 | dump_tree_level(tree, 0); |
| 251 | } |
| 252 | |
| 253 | |
| 254 | static void dump_comp_level(const struct node *tree) |
| 255 | { |
| 256 | const struct node *n; |
| 257 | |
| 258 | for (n = tree; n; n = n->next) { |
| 259 | if (n->lib) |
| 260 | printf("%s\n", n->names->s); |
| 261 | dump_comp_level(n->child); |
| 262 | } |
| 263 | } |
| 264 | |
| 265 | |
| 266 | void dump_comp(void) |
| 267 | { |
| 268 | dump_comp_level(tree); |
| 269 | } |
gencat/expand-pintype |
| 1 | #!/usr/bin/perl |
| 2 | # |
| 3 | # expand-pintype - Expand pin types of symbols in a Kicad library |
| 4 | # |
| 5 | # Copyright 2010, 2012 by Werner Almesberger |
| 6 | # |
| 7 | # This program is free software; you can redistribute it and/or modify |
| 8 | # it under the terms of the GNU General Public License as published by |
| 9 | # the Free Software Foundation; either version 2 of the License, or |
| 10 | # (at your option) any later version. |
| 11 | # |
| 12 | |
| 13 | # |
| 14 | # usage: |
| 15 | # |
| 16 | # expand-pintype input.lib |
| 17 | # expand-pintype input.lib output.lib |
| 18 | # |
| 19 | |
| 20 | |
| 21 | $GAP = 50; # gap between pin and type, in mil |
| 22 | $CHAR_WIDTH = 60; # default character width, in mil |
| 23 | $NAME_WIDTH = 15; # name field width in ASCII mode, in characters |
| 24 | |
| 25 | |
| 26 | %map = ( |
| 27 | "I" => "Input", |
| 28 | "O" => "Output", |
| 29 | "B" => "BiDi", |
| 30 | "T" => "3-state", |
| 31 | "P" => "Passive", |
| 32 | "U" => "Unspec", |
| 33 | "W" => "Pwr In", |
| 34 | "w" => "Pwr Out", |
| 35 | "C" => "OC", |
| 36 | "E" => "OE", |
| 37 | "N" => "NC", |
| 38 | ); |
| 39 | |
| 40 | if (@ARGV < 2) { |
| 41 | $out = 0; |
| 42 | } elsif (@ARGV == 2) { |
| 43 | $file = pop @ARGV; |
| 44 | $out = 1; |
| 45 | open(FILE, ">$file") || die "$file: $!"; |
| 46 | } else { |
| 47 | print STDERR "usage: expand-pintype input.lib [output.lib]\n"; |
| 48 | exit(1); |
| 49 | } |
| 50 | |
| 51 | while (<>) { |
| 52 | if ($out) { |
| 53 | # make name differ so that KiCad's cache doesn't get confused |
| 54 | s/^DEF\s+~?/$&X/; |
| 55 | s/^F1\s+"+/$&X/; |
| 56 | print FILE || die; |
| 57 | } |
| 58 | next unless /^X/; |
| 59 | @a = split(/\s+/); |
| 60 | ($name, $pin, $x, $y, $dir, $unit, $pt) = @a[1, 2, 3, 4, 6, 9, 11]; |
| 61 | $type = $map{$pt}; |
| 62 | $type = "???" unless defined $type; |
| 63 | if ($out) { |
| 64 | $off = $GAP+(length $type)*$CHAR_WIDTH/2; |
| 65 | if ($dir eq "U") { |
| 66 | ($a, $y) = (90, $y-$off); |
| 67 | } elsif ($dir eq "D") { |
| 68 | ($a, $y) = (90, $y+$off); |
| 69 | } elsif ($dir eq "R") { |
| 70 | ($a, $x) = (0, $x-$off); |
| 71 | } else { |
| 72 | ($a, $x) = (0, $x+$off); |
| 73 | } |
| 74 | $type =~ y/ /~/; |
| 75 | print FILE sprintf("T %d %d %d 60 0 %d 0 %s Normal 0\n", |
| 76 | $a*10, $x, $y, $unit, $type); |
| 77 | } else { |
| 78 | $s = "$name ($pin)"; |
| 79 | $f = $NAME_WIDTH-length $s; |
| 80 | $f = "-" x ($f > 0 ? $f : 0); |
| 81 | print "$s $f $type\n"; |
| 82 | } |
| 83 | } |
| 84 | if ($out) { |
| 85 | close FILE || die; |
| 86 | } |
gencat/gencat.c |
| 1 | /* |
| 2 | * gencat.c - Generate expanded component view |
| 3 | * |
| 4 | * Copyright 2012 by Werner Almesberger |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; either version 2 of the License, or |
| 9 | * (at your option) any later version. |
| 10 | */ |
| 11 | |
| 12 | |
| 13 | #include <stdlib.h> |
| 14 | #include <stdio.h> |
| 15 | #include <unistd.h> |
| 16 | #include <string.h> |
| 17 | |
| 18 | #include "comp.h" |
| 19 | #include "libs.h" |
| 20 | #include "pdf.h" |
| 21 | #include "gencat.h" |
| 22 | |
| 23 | |
| 24 | int quiet = 0; |
| 25 | |
| 26 | |
| 27 | static void usage(const char *name) |
| 28 | { |
| 29 | fprintf(stderr, |
| 30 | "usage: %s [-d|-D] [-p] [-P] [-q] [-L libdir ...] [-l lib ...] hierarchy\n" |
| 31 | " %*s [descriptions ...]\n\n" |
| 32 | " -d dump the tree instead of generating a PDF\n" |
| 33 | " -D dump all the canonical component names (without aliases)\n" |
| 34 | " -L libdir search all libraries in the specified directory\n" |
| 35 | " -l lib search the specified component library\n" |
| 36 | " -p use portrait orientation; default: landscape\n" |
| 37 | " -P generate Postscript instead of PDF (mainly for debugging)\n" |
| 38 | " -q don't show progress\n" |
| 39 | , name, (int) strlen(name), ""); |
| 40 | exit(1); |
| 41 | } |
| 42 | |
| 43 | |
| 44 | int main(int argc, char **argv) |
| 45 | { |
| 46 | FILE *file; |
| 47 | int c; |
| 48 | int opt_dump_tree = 0, opt_dump_comp = 0, postscript = 0, portrait = 0; |
| 49 | char **arg; |
| 50 | |
| 51 | while ((c = getopt(argc, argv, "dDL:l:Ppq")) != EOF) |
| 52 | switch (c) { |
| 53 | case 'd': |
| 54 | opt_dump_tree = 1; |
| 55 | break; |
| 56 | case 'D': |
| 57 | opt_dump_comp = 1; |
| 58 | break; |
| 59 | case 'L': |
| 60 | add_libdir(optarg); |
| 61 | break; |
| 62 | case 'l': |
| 63 | add_lib(optarg); |
| 64 | break; |
| 65 | case 'P': |
| 66 | postscript = 1; |
| 67 | break; |
| 68 | case 'p': |
| 69 | portrait = 1; |
| 70 | break; |
| 71 | case 'q': |
| 72 | quiet = 1; |
| 73 | break; |
| 74 | default: |
| 75 | usage(*argv); |
| 76 | } |
| 77 | |
| 78 | if (opt_dump_tree && opt_dump_comp) |
| 79 | usage(*argv); |
| 80 | |
| 81 | switch (argc-optind) { |
| 82 | case 1: |
| 83 | case 2: |
| 84 | break; |
| 85 | default: |
| 86 | usage(*argv); |
| 87 | } |
| 88 | |
| 89 | file = fopen(argv[optind], "r"); |
| 90 | if (!file) { |
| 91 | perror(argv[optind]); |
| 92 | exit(1); |
| 93 | } |
| 94 | read_tree(file); |
| 95 | fclose(file); |
| 96 | set_libs(tree, lookup_sym); |
| 97 | |
| 98 | for (arg = argv+optind+1; *arg; arg++) { |
| 99 | file = fopen(*arg, "r"); |
| 100 | if (!file) { |
| 101 | perror(*arg); |
| 102 | exit(1); |
| 103 | } |
| 104 | read_desc(file); |
| 105 | fclose(file); |
| 106 | } |
| 107 | if (opt_dump_tree) |
| 108 | dump_tree(); |
| 109 | else if (opt_dump_comp) |
| 110 | dump_comp(); |
| 111 | else |
| 112 | make_pdf(!postscript, portrait); |
| 113 | return 0; |
| 114 | } |
gencat/libs.c |
| 1 | /* |
| 2 | * libs.c - Component libraries |
| 3 | * |
| 4 | * Copyright 2012 by Werner Almesberger |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; either version 2 of the License, or |
| 9 | * (at your option) any later version. |
| 10 | */ |
| 11 | |
| 12 | #define _GNU_SOURCE /* for strcasecmp */ |
| 13 | #include <stdlib.h> |
| 14 | #include <stdio.h> |
| 15 | #include <ctype.h> |
| 16 | #include <string.h> |
| 17 | #include <sys/types.h> |
| 18 | #include <dirent.h> |
| 19 | |
| 20 | #include "util.h" |
| 21 | #include "libs.h" |
| 22 | |
| 23 | |
| 24 | struct entry { |
| 25 | struct name *names; |
| 26 | int units; |
| 27 | struct entry *next; |
| 28 | }; |
| 29 | |
| 30 | static struct lib { |
| 31 | const char *path; |
| 32 | struct entry *comps; |
| 33 | struct lib *next; |
| 34 | } *libs = NULL; |
| 35 | |
| 36 | |
| 37 | const char *lookup_sym(const char *name, const struct name **names, int *units) |
| 38 | { |
| 39 | const struct lib *lib; |
| 40 | const struct entry *e; |
| 41 | |
| 42 | for (lib = libs; lib; lib = lib->next) |
| 43 | for (e = lib->comps; e; e = e->next) |
| 44 | if (!strcasecmp(e->names->s, name)) { |
| 45 | if (names) |
| 46 | *names = e->names; |
| 47 | if (units) |
| 48 | *units = e->units; |
| 49 | return lib->path; |
| 50 | } |
| 51 | return NULL; |
| 52 | } |
| 53 | |
| 54 | |
| 55 | static const char *field(const char *s, int n) |
| 56 | { |
| 57 | while (n-- && *s) { |
| 58 | while (*s && !isspace(*s)) |
| 59 | s++; |
| 60 | while (*s && isspace(*s)) |
| 61 | s++; |
| 62 | } |
| 63 | return *s ? s : NULL; |
| 64 | } |
| 65 | |
| 66 | |
| 67 | static void add_name(struct entry *e, char *s) |
| 68 | { |
| 69 | char *nl; |
| 70 | struct name **p; |
| 71 | |
| 72 | nl = strchr(s, '\n'); |
| 73 | if (nl) |
| 74 | *nl = 0; |
| 75 | for (p = &e->names; *p; p = &(*p)->next); |
| 76 | *p = alloc_type(struct name); |
| 77 | (*p)->s = stralloc(s); |
| 78 | (*p)->next = NULL; |
| 79 | } |
| 80 | |
| 81 | |
| 82 | void add_lib(const char *path) |
| 83 | { |
| 84 | FILE *file; |
| 85 | struct lib *lib; |
| 86 | struct entry *e = NULL; |
| 87 | char buf[1024]; /* @@@ */ |
| 88 | char *name, *spc; |
| 89 | const char *s; |
| 90 | |
| 91 | file = fopen(path, "r"); |
| 92 | if (!file) { |
| 93 | perror(path); |
| 94 | exit(1); |
| 95 | } |
| 96 | |
| 97 | lib = alloc_type(struct lib); |
| 98 | lib->path = stralloc(path); |
| 99 | lib->comps = NULL; |
| 100 | lib->next = libs; |
| 101 | libs = lib; |
| 102 | |
| 103 | while (fgets(buf, sizeof(buf), file)) { |
| 104 | if (!strncmp(buf, "ALIAS ", 6) && e) |
| 105 | add_name(e, buf+6); |
| 106 | if (strncmp(buf, "DEF ", 4)) |
| 107 | continue; |
| 108 | s = field(buf, 7); |
| 109 | if (!s) { |
| 110 | fprintf(stderr, "DEF record lacks units field in %s\n", |
| 111 | path); |
| 112 | exit(1); |
| 113 | } |
| 114 | name = buf+4; |
| 115 | if (*name == '~') |
| 116 | name++; |
| 117 | spc = strchr(name, ' '); |
| 118 | if (!spc) { |
| 119 | fprintf(stderr, "invalid DEF line in %s\n", path); |
| 120 | exit(1); |
| 121 | } |
| 122 | *spc = 0; |
| 123 | e = alloc_type(struct entry); |
| 124 | e->names = NULL; |
| 125 | add_name(e, name); |
| 126 | e->units = atoi(s); |
| 127 | if (!e->units) { |
| 128 | fprintf(stderr, "invalid number of units in %s\n", |
| 129 | path); |
| 130 | exit(1); |
| 131 | } |
| 132 | e->next = lib->comps; |
| 133 | lib->comps = e; |
| 134 | } |
| 135 | |
| 136 | fclose(file); |
| 137 | } |
| 138 | |
| 139 | |
| 140 | void add_libdir(const char *path) |
| 141 | { |
| 142 | DIR *dir; |
| 143 | const struct dirent *de; |
| 144 | size_t len; |
| 145 | char *tmp; |
| 146 | |
| 147 | dir = opendir(path); |
| 148 | if (!dir) { |
| 149 | perror(path); |
| 150 | exit(1); |
| 151 | } |
| 152 | while (1) { |
| 153 | de = readdir(dir); |
| 154 | if (!de) |
| 155 | break; |
| 156 | len = strlen(de->d_name); |
| 157 | if (len < 4) |
| 158 | continue; |
| 159 | if (strcmp(de->d_name+len-4, ".lib")) |
| 160 | continue; |
| 161 | if (asprintf(&tmp, "%s/%s", path, de->d_name) < 0) { |
| 162 | perror("asprintf"); |
| 163 | exit(1); |
| 164 | } |
| 165 | add_lib(tmp); |
| 166 | } |
| 167 | closedir(dir); |
| 168 | } |
gencat/pdf.c |
| 1 | /* |
| 2 | * pdf.c - Generate PDF |
| 3 | * |
| 4 | * Copyright 2012 by Werner Almesberger |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; either version 2 of the License, or |
| 9 | * (at your option) any later version. |
| 10 | */ |
| 11 | |
| 12 | #define _GNU_SOURCE |
| 13 | #include <stdlib.h> |
| 14 | #include <stdio.h> |
| 15 | #include <sys/types.h> |
| 16 | |
| 17 | #include "gencat.h" |
| 18 | #include "comp.h" |
| 19 | #include "pdf.h" |
| 20 | |
| 21 | |
| 22 | static struct format { |
| 23 | const char *file_setup; |
| 24 | const char *overlay_setup; |
| 25 | const char *comp_setup; |
| 26 | int left; |
| 27 | struct text { |
| 28 | const char *font; |
| 29 | int size; |
| 30 | int y; |
| 31 | } name, path, lib, comment; |
| 32 | int comment_line_skip; |
| 33 | } landscape = { |
| 34 | .file_setup = "%%Orientation: Landscape", |
| 35 | .overlay_setup = "90 rotate", |
| 36 | .comp_setup = "", |
| 37 | .left = 20, |
| 38 | .name = { "Helvetica-Bold", 24, 57 }, |
| 39 | .path = { "Helvetica-Bold", 18, 30 }, |
| 40 | .lib = { "Courier", 12, 75 }, |
| 41 | .comment = { "Helvetica", 12, 600 }, |
| 42 | .comment_line_skip = 14, |
| 43 | }, portrait = { |
| 44 | .file_setup = "%%Orientation: Portrait", |
| 45 | .overlay_setup = "0 790 translate", |
| 46 | .comp_setup = "-120 700 translate -90 rotate", |
| 47 | .left = 20, |
| 48 | .name = { "Helvetica-Bold", 24, 57 }, |
| 49 | .path = { "Helvetica-Bold", 18, 30 }, |
| 50 | .lib = { "Courier", 12, 75 }, |
| 51 | .comment = { "Helvetica", 12, 740 }, |
| 52 | .comment_line_skip = 14, |
| 53 | }, format; |
| 54 | |
| 55 | static int total, done = 0; |
| 56 | |
| 57 | |
| 58 | static int children(const struct node *node) |
| 59 | { |
| 60 | int n = 0; |
| 61 | |
| 62 | while (node) { |
| 63 | n++; |
| 64 | node = node->next; |
| 65 | } |
| 66 | return n; |
| 67 | } |
| 68 | |
| 69 | |
| 70 | static void ps_string(FILE *file, const char *s) |
| 71 | { |
| 72 | fputc('(', file); |
| 73 | while (*s) { |
| 74 | if (*s == '(' || *s == ')' || *s == '\\') |
| 75 | fputc('\\', file); |
| 76 | fputc(*s, file); |
| 77 | s++; |
| 78 | } |
| 79 | fputc(')', file); |
| 80 | } |
| 81 | |
| 82 | |
| 83 | static void print_path(FILE *file, const struct node *node) |
| 84 | { |
| 85 | if (node->parent) { |
| 86 | print_path(file, node->parent); |
| 87 | fprintf(file, "( > ) show\n"); |
| 88 | } |
| 89 | ps_string(file, node->name); |
| 90 | fprintf(file, " 0.5 setgray show 0 setgray\n"); |
| 91 | } |
| 92 | |
| 93 | |
| 94 | static void make_title(FILE *file, const struct node *node, int unit) |
| 95 | { |
| 96 | const struct name *name; |
| 97 | |
| 98 | fprintf(file, "gsave %s 0 setgray\n", format.overlay_setup); |
| 99 | |
| 100 | fprintf(file, "/%s findfont %d scalefont setfont\n", |
| 101 | format.name.font, format.name.size); |
| 102 | fprintf(file, "%d %d moveto\n", format.left, -format.name.y); |
| 103 | for (name = node->names; name; name = name->next) { |
| 104 | if (name != node->names) |
| 105 | fprintf(file, "(, ) show 0.5 setgray\n"); |
| 106 | ps_string(file, name->s); |
| 107 | fprintf(file, " show\n"); |
| 108 | } |
| 109 | fprintf(file, "0 setgray\n"); |
| 110 | if (node->units > 1) |
| 111 | fprintf(file, " ( \\(%c\\)) show\n", 'A'+unit); |
| 112 | |
| 113 | fprintf(file, "/%s findfont %d scalefont setfont\n", |
| 114 | format.path.font, format.path.size); |
| 115 | fprintf(file, "%d %d moveto\n", format.left, -format.path.y); |
| 116 | print_path(file, node); |
| 117 | |
| 118 | fprintf(file, "/%s findfont %d scalefont setfont\n", |
| 119 | format.lib.font, format.lib.size); |
| 120 | fprintf(file, "%d %d moveto\n", format.left, -format.lib.y); |
| 121 | ps_string(file, node->lib); |
| 122 | fprintf(file, " show\n"); |
| 123 | |
| 124 | fprintf(file, "grestore\n"); |
| 125 | } |
| 126 | |
| 127 | |
| 128 | static void print_comment(FILE *file, const struct line *comment) |
| 129 | { |
| 130 | const struct line *line; |
| 131 | int lines = 0; |
| 132 | int n; |
| 133 | |
| 134 | fprintf(file, "gsave %s 0 setgray\n", format.overlay_setup); |
| 135 | fprintf(file, "/%s findfont %d scalefont setfont\n", |
| 136 | format.comment.font, format.comment.size); |
| 137 | for (line = comment; line; line = line->next) |
| 138 | lines++; |
| 139 | n = 0; |
| 140 | for (line = comment; line; line = line->next) { |
| 141 | n++; |
| 142 | fprintf(file, "%d -%d moveto\n", format.left, |
| 143 | format.comment.y+(n-lines)*format.comment_line_skip); |
| 144 | ps_string(file, line->s); |
| 145 | fprintf(file, " show\n"); |
| 146 | } |
| 147 | fprintf(file, "grestore\n"); |
| 148 | } |
| 149 | |
| 150 | |
| 151 | static void cat(FILE *out, const char *name) |
| 152 | { |
| 153 | FILE *in; |
| 154 | char buf[10000]; /* pick any good size */ |
| 155 | size_t got, wrote; |
| 156 | |
| 157 | in = fopen(name, "r"); |
| 158 | if (!in) { |
| 159 | perror(name); |
| 160 | exit(1); |
| 161 | } |
| 162 | while (1) { |
| 163 | got = fread(buf, 1, sizeof(buf), in); |
| 164 | if (!got) |
| 165 | break; |
| 166 | wrote = fwrite(buf, 1, got, out); |
| 167 | if (wrote != got) { |
| 168 | perror("fwrite"); |
| 169 | exit(1); |
| 170 | } |
| 171 | } |
| 172 | if (ferror(in)) { |
| 173 | perror(name); |
| 174 | exit(1); |
| 175 | } |
| 176 | fclose(in); |
| 177 | } |
| 178 | |
| 179 | |
| 180 | static void convert_comp(const struct node *node, FILE *out) |
| 181 | { |
| 182 | char *tmp; |
| 183 | int i, res; |
| 184 | |
| 185 | for (i = 0; i != node->units; i++) { |
| 186 | if (!quiet) { |
| 187 | fprintf(stderr, "\r%u/%u", ++done, total); |
| 188 | fflush(stderr); |
| 189 | } |
| 190 | make_title(out, node, i); |
| 191 | if (!i && node->comment) |
| 192 | print_comment(out, node->comment); |
| 193 | if (asprintf(&tmp, "sym2xps '%s' '%s' %d '%s' '%s'", |
| 194 | node->lib, node->names->s, i+1, "tmp", "tmp.ps") < 0) { |
| 195 | perror("asprintf"); |
| 196 | exit(1); |
| 197 | } |
| 198 | res = system(tmp); |
| 199 | if (res < 0) { |
| 200 | perror("system"); |
| 201 | exit(1); |
| 202 | } |
| 203 | if (res) { |
| 204 | fprintf(stderr, "sym2xps returned %d\n", res); |
| 205 | exit(1); |
| 206 | } |
| 207 | fprintf(out, "gsave %s\n", format.comp_setup); |
| 208 | cat(out, "tmp.ps"); |
| 209 | fprintf(out, "\ngrestore\n"); |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | |
| 214 | static void convert_tree(const struct node *node, FILE *out) |
| 215 | { |
| 216 | while (node) { |
| 217 | fprintf(out, "[ /Title (%s) /Count %d /OUT pdfmark\n", |
| 218 | node->name, -children(node->child)); |
| 219 | if (node->child) |
| 220 | convert_tree(node->child, out); |
| 221 | else |
| 222 | convert_comp(node, out); |
| 223 | node = node->next; |
| 224 | } |
| 225 | } |
| 226 | |
| 227 | |
| 228 | static int count_tree(const struct node *node) |
| 229 | { |
| 230 | int sum = 0; |
| 231 | |
| 232 | while (node) { |
| 233 | if (node->child) |
| 234 | sum += count_tree(node->child); |
| 235 | else |
| 236 | sum += node->units; |
| 237 | node = node->next; |
| 238 | } |
| 239 | return sum; |
| 240 | } |
| 241 | |
| 242 | |
| 243 | void make_pdf(int pdf, int use_portrait) |
| 244 | { |
| 245 | FILE *out; |
| 246 | int res; |
| 247 | |
| 248 | if (use_portrait) |
| 249 | format = portrait; |
| 250 | else |
| 251 | format = landscape; |
| 252 | if (pdf) |
| 253 | out = popen( |
| 254 | "gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=- " |
| 255 | "-f -", "w"); |
| 256 | else |
| 257 | out = popen("cat", "w"); |
| 258 | if (!out) { |
| 259 | perror("gs"); |
| 260 | exit(1); |
| 261 | } |
| 262 | fprintf(out, "%%!PS\n%s\n", format.file_setup); |
| 263 | total = count_tree(tree); |
| 264 | convert_tree(tree, out); |
| 265 | if (!quiet) |
| 266 | fprintf(stderr, "\rFinishing\n"); |
| 267 | res = pclose(out); |
| 268 | if (res < 0) { |
| 269 | perror("pclose"); |
| 270 | exit(1); |
| 271 | } |
| 272 | if (res) { |
| 273 | fprintf(stderr, "exit status %d\n", res); |
| 274 | exit(1); |
| 275 | } |
| 276 | } |
gencat/sym2xps |
| 1 | #!/bin/sh -e |
| 2 | # |
| 3 | # sym2xps - Convert a symbol from a Kicad library to Postscript with expanded |
| 4 | # pin types |
| 5 | # |
| 6 | # Copyright 2012 by Werner Almesberger |
| 7 | # |
| 8 | # This program is free software; you can redistribute it and/or modify |
| 9 | # it under the terms of the GNU General Public License as published by |
| 10 | # the Free Software Foundation; either version 2 of the License, or |
| 11 | # (at your option) any later version. |
| 12 | # |
| 13 | |
| 14 | |
| 15 | usage() |
| 16 | { |
| 17 | echo "usage: $0 library symbol unit tmpdir outfile" 1>&2 |
| 18 | exit 1 |
| 19 | } |
| 20 | |
| 21 | |
| 22 | lib=$1 |
| 23 | sym=$2 |
| 24 | unit=$3 |
| 25 | tmp=$4 |
| 26 | out=$5 |
| 27 | |
| 28 | [ "$lib" ] && [ "$sym" ] && [ "$unit" ] && [ "$tmp" ] && [ "$out" ] || usage |
| 29 | |
| 30 | [ -r "$lib" ] || { |
| 31 | echo "$lib: not found" 1>&2 |
| 32 | exit 1 |
| 33 | } |
| 34 | |
| 35 | grep "^DEF $sym " "$lib" >/dev/null || grep "^DEF ~$sym " "$lib" >/dev/null || { |
| 36 | echo "\"$sym\" not found in $lib" 1>&2 |
| 37 | exit 1 |
| 38 | } |
| 39 | |
| 40 | [ "${tmp#/}" = "$tmp" ] && tmp=`pwd`/$tmp |
| 41 | [ "${out#/}" = "$out" ] && out=`pwd`/$out |
| 42 | |
| 43 | mkdir "$tmp" |
| 44 | |
| 45 | trap "rm -rf '$tmp'" 0 |
| 46 | |
| 47 | expand-pintype "$lib" "$tmp"/tmp.lib |
| 48 | |
| 49 | cat <<EOF >"$tmp"/tmp.pro |
| 50 | [eeschema] |
| 51 | version=1 |
| 52 | [eeschema/libraries] |
| 53 | LibName1=./tmp |
| 54 | EOF |
| 55 | |
| 56 | X=6000 |
| 57 | Y=4000 |
| 58 | |
| 59 | sed "\@^DEF $sym @,/^ENDDEF/p;d" "$lib" | |
| 60 | awk '/^F. / { if ($1 == "F0") sub(/"$/, "?\"", $2); |
| 61 | print substr($1, 1, 1), substr($1, 2, 1), $2, |
| 62 | $6, '$X'+$3, '$Y'+$4, $5, " 0000", $8, $9 }' >"$tmp"/fx.tmp |
| 63 | #F field_number "text" orientation posX posY size Flags (see below) |
| 64 | #F0 reference posx posy text_size text_orient visibile htext_justify vtext_justify |
| 65 | |
| 66 | cat <<EOF >"$tmp"/tmp.sch |
| 67 | EESchema Schematic File Version 2 date Mon Mar 26 09:29:33 2012 |
| 68 | LIBS:dummy |
| 69 | EELAYER 43 0 |
| 70 | EELAYER END |
| 71 | \$Comp |
| 72 | L X$sym ?? |
| 73 | U $unit 1 00000000 |
| 74 | P $X $Y |
| 75 | `cat "$tmp"/fx.tmp` |
| 76 | $unit $X $Y |
| 77 | 1 0 0 -1 |
| 78 | \$EndComp |
| 79 | \$EndSCHEMATC |
| 80 | EOF |
| 81 | |
| 82 | cd "$tmp" |
| 83 | eeschema --plot=ps "$tmp/tmp.sch" |
| 84 | mv tmp.ps "$out" |
genex/Makefile |
1 | | # |
2 | | # Makefile - Expanded component view generator |
3 | | # |
4 | | # Copyright 2012 by Werner Almesberger |
5 | | # |
6 | | # This program is free software; you can redistribute it and/or modify |
7 | | # it under the terms of the GNU General Public License as published by |
8 | | # the Free Software Foundation; either version 2 of the License, or |
9 | | # (at your option) any later version. |
10 | | # |
11 | | |
12 | | PREFIX ?= /usr/local |
13 | | |
14 | | OBJS = genex.o comp.o libs.o pdf.o |
15 | | |
16 | | SHELL = /bin/bash |
17 | | CFLAGS = -Wall -g |
18 | | |
19 | | CC_normal := $(CC) |
20 | | DEPEND_normal := $(CPP) $(CFLAGS) -MM -MG |
21 | | |
22 | | CC_quiet = @echo " CC " $@ && $(CC_normal) |
23 | | GEN_quiet = @echo " GENERATE " $@ && |
24 | | DEPEND_quiet = @$(DEPEND_normal) |
25 | | |
26 | | ifeq ($(V),1) |
27 | | CC = $(CC_normal) |
28 | | GEN = |
29 | | DEPEND = $(DEPEND_normal) |
30 | | else |
31 | | CC = $(CC_quiet) |
32 | | GEN = $(GEN_quiet) |
33 | | DEPEND = $(DEPEND_quiet) |
34 | | endif |
35 | | |
36 | | .PHONY: all clean spotless install uninstall |
37 | | |
38 | | all: genex-bin |
39 | | |
40 | | genex-bin: $(OBJS) |
41 | | $(CC) $(CFLAGS) -o $@ $(OBJS) $(LDLIBS) |
42 | | |
43 | | %.o: %.c |
44 | | $(CC) -c $(CFLAGS) $*.c -o $*.o |
45 | | $(DEPEND) $*.c | \ |
46 | | sed -e \ |
47 | | '/^\(.*:\)\? */{p;s///;s/ *\\\?$$/ /;s/ */:\n/g;H;}' \ |
48 | | -e '$${g;p;}' -e d >$*.d; \ |
49 | | [ "$${PIPESTATUS[*]}" = "0 0" ] || { rm -f $*.d; exit 1; } |
50 | | |
51 | | -include $(OBJS:.o=.d) |
52 | | |
53 | | clean: |
54 | | rm -f $(OBJS) $(OBJS:.o=.d) |
55 | | |
56 | | spotless: clean |
57 | | rm -f genex-bin |
58 | | |
59 | | # |
60 | | # Note: we use .../lib/genex/ instead of .../libexec/genex/ because FHS-3.0 |
61 | | # does not define libexec under the /usr/local/ hierarchy. (And older versions |
62 | | # of FHS don't define libexec at all.) |
63 | | # |
64 | | |
65 | | install: all |
66 | | mkdir -p $(DESTDIR)/$(PREFIX)/bin |
67 | | mkdir -p $(DESTDIR)/$(PREFIX)/lib/genex |
68 | | ./mkgenex-wrapper -m 755 -p $(DESTDIR)/$(PREFIX)/lib/genex/ \ |
69 | | $(DESTDIR)/$(PREFIX)/bin/genex |
70 | | install -m 755 genex-bin $(DESTDIR)/$(PREFIX)/lib/genex/ |
71 | | install -m 755 sym2xps $(DESTDIR)/$(PREFIX)/lib/genex/ |
72 | | install -m 755 expand-pintype $(DESTDIR)/$(PREFIX)/lib/genex/ |
73 | | |
74 | | uninstall: |
75 | | rm -f $(DESTDIR)/$(PREFIX)/bin/genex |
76 | | rm -rf $(DESTDIR)/$(PREFIX)/lib/genex |
77 | | |
genex/comp.c |
1 | | /* |
2 | | * comp.c - Component hierarchy |
3 | | * |
4 | | * Copyright 2012 by Werner Almesberger |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 2 of the License, or |
9 | | * (at your option) any later version. |
10 | | */ |
11 | | |
12 | | #define _GNU_SOURCE /* for strcasecmp */ |
13 | | #include <stdlib.h> |
14 | | #include <stdio.h> |
15 | | #include <string.h> |
16 | | #include <ctype.h> |
17 | | |
18 | | #include "util.h" |
19 | | #include "comp.h" |
20 | | |
21 | | |
22 | | struct node *tree = NULL; |
23 | | |
24 | | |
25 | | void read_tree(FILE *file) |
26 | | { |
27 | | char buf[1100]; /* more than enough */ |
28 | | struct node *last = NULL, *node; |
29 | | int depth = -1; |
30 | | const char *s, *p, *e; |
31 | | char *name; |
32 | | int n; |
33 | | |
34 | | next: |
35 | | while (fgets(buf, sizeof(buf), file)) { |
36 | | n = 0; |
37 | | s = buf; |
38 | | while (1) { |
39 | | switch (*s++) { |
40 | | case ' ': |
41 | | n++; |
42 | | continue; |
43 | | case '\t': |
44 | | n = (n+8) & ~7; |
45 | | continue; |
46 | | case 0: |
47 | | case '#': |
48 | | goto next; |
49 | | default: |
50 | | break; |
51 | | } |
52 | | break; |
53 | | } |
54 | | for (p = e = --s; *p && *p != '#' && *p != '\n'; p++) |
55 | | if (*p != ' ' && *p != '\t') |
56 | | e = p; |
57 | | if (!last && n) { |
58 | | fprintf(stderr, "first entry must not be intended\n"); |
59 | | exit(1); |
60 | | } |
61 | | name = malloc(e-s+2); |
62 | | if (!name) { |
63 | | perror("malloc"); |
64 | | exit(1); |
65 | | } |
66 | | memcpy(name, s, e-s+1); |
67 | | name[e-s+1] = 0; |
68 | | node = alloc_type(struct node); |
69 | | node->name = name; |
70 | | node->lib = NULL; |
71 | | node->comment = NULL; |
72 | | node->indent = n; |
73 | | node->child = node->next = NULL; |
74 | | if (n > depth) { |
75 | | if (last) |
76 | | last->child = node; |
77 | | else |
78 | | tree = node; |
79 | | node->parent = last; |
80 | | } else { |
81 | | while (last && last->indent != n) |
82 | | last = last->parent; |
83 | | if (!last && n) { |
84 | | fprintf(stderr, "indentation error\n"); |
85 | | exit(1); |
86 | | } |
87 | | last->next = node; |
88 | | node->parent = last->parent; |
89 | | } |
90 | | last = node; |
91 | | depth = n; |
92 | | } |
93 | | } |
94 | | |
95 | | |
96 | | static struct node *find_comp(struct node *node, const char *name) |
97 | | { |
98 | | struct node *found; |
99 | | |
100 | | while (node) { |
101 | | if (!strcasecmp(node->name, name)) |
102 | | return node; |
103 | | found = find_comp(node->child, name); |
104 | | if (found) |
105 | | return found; |
106 | | node = node->next; |
107 | | } |
108 | | return NULL; |
109 | | } |
110 | | |
111 | | |
112 | | static struct line *new_line(char *s) |
113 | | { |
114 | | struct line *line; |
115 | | |
116 | | line = alloc_type(struct line); |
117 | | line->s = stralloc(s); |
118 | | line->next = NULL; |
119 | | return line; |
120 | | } |
121 | | |
122 | | |
123 | | static void append_line(struct line *line, char *s) |
124 | | { |
125 | | int len1, len2; |
126 | | |
127 | | len1 = strlen(line->s); |
128 | | len2 = strlen(s); |
129 | | line->s = realloc(line->s, len1+len2+1+1); /* separating space */ |
130 | | if (!line->s) { |
131 | | perror("realloc"); |
132 | | exit(1); |
133 | | } |
134 | | line->s[len1] = ' '; |
135 | | memcpy(line->s+len1+1, s, len2); |
136 | | line->s[len1+len2+1] = 0; |
137 | | } |
138 | | |
139 | | |
140 | | void read_desc(FILE *file) |
141 | | { |
142 | | struct line **anchor = NULL; |
143 | | char buf[1100]; /* more than enough */ |
144 | | struct node *node; |
145 | | char *p, *end; |
146 | | int skip = 0, lineno = 0; |
147 | | |
148 | | while (fgets(buf, sizeof(buf), file)) { |
149 | | lineno++; |
150 | | p = strchr(buf, '\n'); |
151 | | if (p) |
152 | | *p = 0; |
153 | | p = buf; |
154 | | if (*buf && !isspace(*buf)) { |
155 | | /* tag is ^.*?:\s */ |
156 | | while (1) { |
157 | | p = strchr(p, ':'); |
158 | | if (!p) { |
159 | | fprintf(stderr, "no tag in line %d\n", |
160 | | lineno); |
161 | | exit(1); |
162 | | } |
163 | | if (!p[1] || isspace(p[1])) |
164 | | break; |
165 | | p++; |
166 | | } |
167 | | *p++ = 0; |
168 | | node = find_comp(tree, buf); |
169 | | if (!node) { |
170 | | fprintf(stderr, |
171 | | "component \"%s\" not found in line %d\n", |
172 | | buf, lineno); |
173 | | skip = 1; |
174 | | continue; |
175 | | } |
176 | | for (anchor = &node->comment; *anchor; |
177 | | anchor = &(*anchor)->next); |
178 | | skip = 0; |
179 | | } |
180 | | if (skip) |
181 | | continue; |
182 | | |
183 | | /* remove leading whitespace */ |
184 | | while (*p && isspace(*p)) |
185 | | p++; |
186 | | if (!*p) { |
187 | | if (*anchor) |
188 | | anchor = &(*anchor)->next; |
189 | | continue; |
190 | | } |
191 | | |
192 | | /* remove training whitespace */ |
193 | | end = strrchr(p, 0); |
194 | | while (isspace(end[-1])) |
195 | | end--; |
196 | | *end = 0; |
197 | | |
198 | | if (*anchor) |
199 | | append_line(*anchor, p); |
200 | | else |
201 | | *anchor = new_line(p); |
202 | | } |
203 | | } |
204 | | |
205 | | |
206 | | void set_libs(struct node *node, |
207 | | const char *(*find_lib)(const char *sym, const struct name **names, |
208 | | int *units)) |
209 | | { |
210 | | while (node) { |
211 | | if (!node->child) { |
212 | | node->lib = |
213 | | find_lib(node->name, &node->names, &node->units); |
214 | | if (!node->lib) { |
215 | | fprintf(stderr, "symbol %s not found\n", |
216 | | node->name); |
217 | | exit(1); |
218 | | } |
219 | | } |
220 | | set_libs(node->child, find_lib); |
221 | | node = node->next; |
222 | | } |
223 | | } |
224 | | |
225 | | |
226 | | static void dump_tree_level(const struct node *tree, int level) |
227 | | { |
228 | | const struct node *n; |
229 | | const struct line *line; |
230 | | const struct name *name; |
231 | | |
232 | | for (n = tree; n; n = n->next) { |
233 | | printf("%*s%s", 4*level, "", n->name); |
234 | | if (n->lib) { |
235 | | for (name = n->names; name; name = name->next) |
236 | | printf("%s%s", |
237 | | name == n->names ? " (" : ", ", name->s); |
238 | | printf(")"); |
239 | | } |
240 | | printf("\n"); |
241 | | for (line = n->comment; line; line = line->next) |
242 | | printf("%*s\"%s\"\n", 4*level+2, "", line->s); |
243 | | dump_tree_level(n->child, level+1); |
244 | | } |
245 | | } |
246 | | |
247 | | |
248 | | void dump_tree(void) |
249 | | { |
250 | | dump_tree_level(tree, 0); |
251 | | } |
252 | | |
253 | | |
254 | | static void dump_comp_level(const struct node *tree) |
255 | | { |
256 | | const struct node *n; |
257 | | |
258 | | for (n = tree; n; n = n->next) { |
259 | | if (n->lib) |
260 | | printf("%s\n", n->names->s); |
261 | | dump_comp_level(n->child); |
262 | | } |
263 | | } |
264 | | |
265 | | |
266 | | void dump_comp(void) |
267 | | { |
268 | | dump_comp_level(tree); |
269 | | } |
genex/expand-pintype |
1 | | #!/usr/bin/perl |
2 | | # |
3 | | # expand-pintype - Expand pin types of symbols in a Kicad library |
4 | | # |
5 | | # Copyright 2010, 2012 by Werner Almesberger |
6 | | # |
7 | | # This program is free software; you can redistribute it and/or modify |
8 | | # it under the terms of the GNU General Public License as published by |
9 | | # the Free Software Foundation; either version 2 of the License, or |
10 | | # (at your option) any later version. |
11 | | # |
12 | | |
13 | | # |
14 | | # usage: |
15 | | # |
16 | | # expand-pintype input.lib |
17 | | # expand-pintype input.lib output.lib |
18 | | # |
19 | | |
20 | | |
21 | | $GAP = 50; # gap between pin and type, in mil |
22 | | $CHAR_WIDTH = 60; # default character width, in mil |
23 | | $NAME_WIDTH = 15; # name field width in ASCII mode, in characters |
24 | | |
25 | | |
26 | | %map = ( |
27 | | "I" => "Input", |
28 | | "O" => "Output", |
29 | | "B" => "BiDi", |
30 | | "T" => "3-state", |
31 | | "P" => "Passive", |
32 | | "U" => "Unspec", |
33 | | "W" => "Pwr In", |
34 | | "w" => "Pwr Out", |
35 | | "C" => "OC", |
36 | | "E" => "OE", |
37 | | "N" => "NC", |
38 | | ); |
39 | | |
40 | | if (@ARGV < 2) { |
41 | | $out = 0; |
42 | | } elsif (@ARGV == 2) { |
43 | | $file = pop @ARGV; |
44 | | $out = 1; |
45 | | open(FILE, ">$file") || die "$file: $!"; |
46 | | } else { |
47 | | print STDERR "usage: expand-pintype input.lib [output.lib]\n"; |
48 | | exit(1); |
49 | | } |
50 | | |
51 | | while (<>) { |
52 | | if ($out) { |
53 | | # make name differ so that KiCad's cache doesn't get confused |
54 | | s/^DEF\s+~?/$&X/; |
55 | | s/^F1\s+"+/$&X/; |
56 | | print FILE || die; |
57 | | } |
58 | | next unless /^X/; |
59 | | @a = split(/\s+/); |
60 | | ($name, $pin, $x, $y, $dir, $unit, $pt) = @a[1, 2, 3, 4, 6, 9, 11]; |
61 | | $type = $map{$pt}; |
62 | | $type = "???" unless defined $type; |
63 | | if ($out) { |
64 | | $off = $GAP+(length $type)*$CHAR_WIDTH/2; |
65 | | if ($dir eq "U") { |
66 | | ($a, $y) = (90, $y-$off); |
67 | | } elsif ($dir eq "D") { |
68 | | ($a, $y) = (90, $y+$off); |
69 | | } elsif ($dir eq "R") { |
70 | | ($a, $x) = (0, $x-$off); |
71 | | } else { |
72 | | ($a, $x) = (0, $x+$off); |
73 | | } |
74 | | $type =~ y/ /~/; |
75 | | print FILE sprintf("T %d %d %d 60 0 %d 0 %s Normal 0\n", |
76 | | $a*10, $x, $y, $unit, $type); |
77 | | } else { |
78 | | $s = "$name ($pin)"; |
79 | | $f = $NAME_WIDTH-length $s; |
80 | | $f = "-" x ($f > 0 ? $f : 0); |
81 | | print "$s $f $type\n"; |
82 | | } |
83 | | } |
84 | | if ($out) { |
85 | | close FILE || die; |
86 | | } |
genex/genex.c |
1 | | /* |
2 | | * genex.c - Generate expanded component view |
3 | | * |
4 | | * Copyright 2012 by Werner Almesberger |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 2 of the License, or |
9 | | * (at your option) any later version. |
10 | | */ |
11 | | |
12 | | |
13 | | #include <stdlib.h> |
14 | | #include <stdio.h> |
15 | | #include <unistd.h> |
16 | | #include <string.h> |
17 | | |
18 | | #include "comp.h" |
19 | | #include "libs.h" |
20 | | #include "pdf.h" |
21 | | #include "genex.h" |
22 | | |
23 | | |
24 | | int quiet = 0; |
25 | | |
26 | | |
27 | | static void usage(const char *name) |
28 | | { |
29 | | fprintf(stderr, |
30 | | "usage: %s [-d|-D] [-p] [-P] [-q] [-L libdir ...] [-l lib ...] hierarchy\n" |
31 | | " %*s [descriptions ...]\n\n" |
32 | | " -d dump the tree instead of generating a PDF\n" |
33 | | " -D dump all the canonical component names (without aliases)\n" |
34 | | " -L libdir search all libraries in the specified directory\n" |
35 | | " -l lib search the specified component library\n" |
36 | | " -p use portrait orientation; default: landscape\n" |
37 | | " -P generate Postscript instead of PDF (mainly for debugging)\n" |
38 | | " -q don't show progress\n" |
39 | | , name, (int) strlen(name), ""); |
40 | | exit(1); |
41 | | } |
42 | | |
43 | | |
44 | | int main(int argc, char **argv) |
45 | | { |
46 | | FILE *file; |
47 | | int c; |
48 | | int opt_dump_tree = 0, opt_dump_comp = 0, postscript = 0, portrait = 0; |
49 | | char **arg; |
50 | | |
51 | | while ((c = getopt(argc, argv, "dDL:l:Ppq")) != EOF) |
52 | | switch (c) { |
53 | | case 'd': |
54 | | opt_dump_tree = 1; |
55 | | break; |
56 | | case 'D': |
57 | | opt_dump_comp = 1; |
58 | | break; |
59 | | case 'L': |
60 | | add_libdir(optarg); |
61 | | break; |
62 | | case 'l': |
63 | | add_lib(optarg); |
64 | | break; |
65 | | case 'P': |
66 | | postscript = 1; |
67 | | break; |
68 | | case 'p': |
69 | | portrait = 1; |
70 | | break; |
71 | | case 'q': |
72 | | quiet = 1; |
73 | | break; |
74 | | default: |
75 | | usage(*argv); |
76 | | } |
77 | | |
78 | | if (opt_dump_tree && opt_dump_comp) |
79 | | usage(*argv); |
80 | | |
81 | | switch (argc-optind) { |
82 | | case 1: |
83 | | case 2: |
84 | | break; |
85 | | default: |
86 | | usage(*argv); |
87 | | } |
88 | | |
89 | | file = fopen(argv[optind], "r"); |
90 | | if (!file) { |
91 | | perror(argv[optind]); |
92 | | exit(1); |
93 | | } |
94 | | read_tree(file); |
95 | | fclose(file); |
96 | | set_libs(tree, lookup_sym); |
97 | | |
98 | | for (arg = argv+optind+1; *arg; arg++) { |
99 | | file = fopen(*arg, "r"); |
100 | | if (!file) { |
101 | | perror(*arg); |
102 | | exit(1); |
103 | | } |
104 | | read_desc(file); |
105 | | fclose(file); |
106 | | } |
107 | | if (opt_dump_tree) |
108 | | dump_tree(); |
109 | | else if (opt_dump_comp) |
110 | | dump_comp(); |
111 | | else |
112 | | make_pdf(!postscript, portrait); |
113 | | return 0; |
114 | | } |
genex/libs.c |
1 | | /* |
2 | | * libs.c - Component libraries |
3 | | * |
4 | | * Copyright 2012 by Werner Almesberger |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 2 of the License, or |
9 | | * (at your option) any later version. |
10 | | */ |
11 | | |
12 | | #define _GNU_SOURCE /* for strcasecmp */ |
13 | | #include <stdlib.h> |
14 | | #include <stdio.h> |
15 | | #include <ctype.h> |
16 | | #include <string.h> |
17 | | #include <sys/types.h> |
18 | | #include <dirent.h> |
19 | | |
20 | | #include "util.h" |
21 | | #include "libs.h" |
22 | | |
23 | | |
24 | | struct entry { |
25 | | struct name *names; |
26 | | int units; |
27 | | struct entry *next; |
28 | | }; |
29 | | |
30 | | static struct lib { |
31 | | const char *path; |
32 | | struct entry *comps; |
33 | | struct lib *next; |
34 | | } *libs = NULL; |
35 | | |
36 | | |
37 | | const char *lookup_sym(const char *name, const struct name **names, int *units) |
38 | | { |
39 | | const struct lib *lib; |
40 | | const struct entry *e; |
41 | | |
42 | | for (lib = libs; lib; lib = lib->next) |
43 | | for (e = lib->comps; e; e = e->next) |
44 | | if (!strcasecmp(e->names->s, name)) { |
45 | | if (names) |
46 | | *names = e->names; |
47 | | if (units) |
48 | | *units = e->units; |
49 | | return lib->path; |
50 | | } |
51 | | return NULL; |
52 | | } |
53 | | |
54 | | |
55 | | static const char *field(const char *s, int n) |
56 | | { |
57 | | while (n-- && *s) { |
58 | | while (*s && !isspace(*s)) |
59 | | s++; |
60 | | while (*s && isspace(*s)) |
61 | | s++; |
62 | | } |
63 | | return *s ? s : NULL; |
64 | | } |
65 | | |
66 | | |
67 | | static void add_name(struct entry *e, char *s) |
68 | | { |
69 | | char *nl; |
70 | | struct name **p; |
71 | | |
72 | | nl = strchr(s, '\n'); |
73 | | if (nl) |
74 | | *nl = 0; |
75 | | for (p = &e->names; *p; p = &(*p)->next); |
76 | | *p = alloc_type(struct name); |
77 | | (*p)->s = stralloc(s); |
78 | | (*p)->next = NULL; |
79 | | } |
80 | | |
81 | | |
82 | | void add_lib(const char *path) |
83 | | { |
84 | | FILE *file; |
85 | | struct lib *lib; |
86 | | struct entry *e = NULL; |
87 | | char buf[1024]; /* @@@ */ |
88 | | char *name, *spc; |
89 | | const char *s; |
90 | | |
91 | | file = fopen(path, "r"); |
92 | | if (!file) { |
93 | | perror(path); |
94 | | exit(1); |
95 | | } |
96 | | |
97 | | lib = alloc_type(struct lib); |
98 | | lib->path = stralloc(path); |
99 | | lib->comps = NULL; |
100 | | lib->next = libs; |
101 | | libs = lib; |
102 | | |
103 | | while (fgets(buf, sizeof(buf), file)) { |
104 | | if (!strncmp(buf, "ALIAS ", 6) && e) |
105 | | add_name(e, buf+6); |
106 | | if (strncmp(buf, "DEF ", 4)) |
107 | | continue; |
108 | | s = field(buf, 7); |
109 | | if (!s) { |
110 | | fprintf(stderr, "DEF record lacks units field in %s\n", |
111 | | path); |
112 | | exit(1); |
113 | | } |
114 | | name = buf+4; |
115 | | if (*name == '~') |
116 | | name++; |
117 | | spc = strchr(name, ' '); |
118 | | if (!spc) { |
119 | | fprintf(stderr, "invalid DEF line in %s\n", path); |
120 | | exit(1); |
121 | | } |
122 | | *spc = 0; |
123 | | e = alloc_type(struct entry); |
124 | | e->names = NULL; |
125 | | add_name(e, name); |
126 | | e->units = atoi(s); |
127 | | if (!e->units) { |
128 | | fprintf(stderr, "invalid number of units in %s\n", |
129 | | path); |
130 | | exit(1); |
131 | | } |
132 | | e->next = lib->comps; |
133 | | lib->comps = e; |
134 | | } |
135 | | |
136 | | fclose(file); |
137 | | } |
138 | | |
139 | | |
140 | | void add_libdir(const char *path) |
141 | | { |
142 | | DIR *dir; |
143 | | const struct dirent *de; |
144 | | size_t len; |
145 | | char *tmp; |
146 | | |
147 | | dir = opendir(path); |
148 | | if (!dir) { |
149 | | perror(path); |
150 | | exit(1); |
151 | | } |
152 | | while (1) { |
153 | | de = readdir(dir); |
154 | | if (!de) |
155 | | break; |
156 | | len = strlen(de->d_name); |
157 | | if (len < 4) |
158 | | continue; |
159 | | if (strcmp(de->d_name+len-4, ".lib")) |
160 | | continue; |
161 | | if (asprintf(&tmp, "%s/%s", path, de->d_name) < 0) { |
162 | | perror("asprintf"); |
163 | | exit(1); |
164 | | } |
165 | | add_lib(tmp); |
166 | | } |
167 | | closedir(dir); |
168 | | } |
genex/pdf.c |
1 | | /* |
2 | | * pdf.c - Generate PDF |
3 | | * |
4 | | * Copyright 2012 by Werner Almesberger |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 2 of the License, or |
9 | | * (at your option) any later version. |
10 | | */ |
11 | | |
12 | | #define _GNU_SOURCE |
13 | | #include <stdlib.h> |
14 | | #include <stdio.h> |
15 | | #include <sys/types.h> |
16 | | |
17 | | #include "genex.h" |
18 | | #include "comp.h" |
19 | | #include "pdf.h" |
20 | | |
21 | | |
22 | | static struct format { |
23 | | const char *file_setup; |
24 | | const char *overlay_setup; |
25 | | const char *comp_setup; |
26 | | int left; |
27 | | struct text { |
28 | | const char *font; |
29 | | int size; |
30 | | int y; |
31 | | } name, path, lib, comment; |
32 | | int comment_line_skip; |
33 | | } landscape = { |
34 | | .file_setup = "%%Orientation: Landscape", |
35 | | .overlay_setup = "90 rotate", |
36 | | .comp_setup = "", |
37 | | .left = 20, |
38 | | .name = { "Helvetica-Bold", 24, 57 }, |
39 | | .path = { "Helvetica-Bold", 18, 30 }, |
40 | | .lib = { "Courier", 12, 75 }, |
41 | | .comment = { "Helvetica", 12, 600 }, |
42 | | .comment_line_skip = 14, |
43 | | }, portrait = { |
44 | | .file_setup = "%%Orientation: Portrait", |
45 | | .overlay_setup = "0 790 translate", |
46 | | .comp_setup = "-120 700 translate -90 rotate", |
47 | | .left = 20, |
48 | | .name = { "Helvetica-Bold", 24, 57 }, |
49 | | .path = { "Helvetica-Bold", 18, 30 }, |
50 | | .lib = { "Courier", 12, 75 }, |
51 | | .comment = { "Helvetica", 12, 740 }, |
52 | | .comment_line_skip = 14, |
53 | | }, format; |
54 | | |
55 | | static int total, done = 0; |
56 | | |
57 | | |
58 | | static int children(const struct node *node) |
59 | | { |
60 | | int n = 0; |
61 | | |
62 | | while (node) { |
63 | | n++; |
64 | | node = node->next; |
65 | | } |
66 | | return n; |
67 | | } |
68 | | |
69 | | |
70 | | static void ps_string(FILE *file, const char *s) |
71 | | { |
72 | | fputc('(', file); |
73 | | while (*s) { |
74 | | if (*s == '(' || *s == ')' || *s == '\\') |
75 | | fputc('\\', file); |
76 | | fputc(*s, file); |
77 | | s++; |
78 | | } |
79 | | fputc(')', file); |
80 | | } |
81 | | |
82 | | |
83 | | static void print_path(FILE *file, const struct node *node) |
84 | | { |
85 | | if (node->parent) { |
86 | | print_path(file, node->parent); |
87 | | fprintf(file, "( > ) show\n"); |
88 | | } |
89 | | ps_string(file, node->name); |
90 | | fprintf(file, " 0.5 setgray show 0 setgray\n"); |
91 | | } |
92 | | |
93 | | |
94 | | static void make_title(FILE *file, const struct node *node, int unit) |
95 | | { |
96 | | const struct name *name; |
97 | | |
98 | | fprintf(file, "gsave %s 0 setgray\n", format.overlay_setup); |
99 | | |
100 | | fprintf(file, "/%s findfont %d scalefont setfont\n", |
101 | | format.name.font, format.name.size); |
102 | | fprintf(file, "%d %d moveto\n", format.left, -format.name.y); |
103 | | for (name = node->names; name; name = name->next) { |
104 | | if (name != node->names) |
105 | | fprintf(file, "(, ) show 0.5 setgray\n"); |
106 | | ps_string(file, name->s); |
107 | | fprintf(file, " show\n"); |
108 | | } |
109 | | fprintf(file, "0 setgray\n"); |
110 | | if (node->units > 1) |
111 | | fprintf(file, " ( \\(%c\\)) show\n", 'A'+unit); |
112 | | |
113 | | fprintf(file, "/%s findfont %d scalefont setfont\n", |
114 | | format.path.font, format.path.size); |
115 | | fprintf(file, "%d %d moveto\n", format.left, -format.path.y); |
116 | | print_path(file, node); |
117 | | |
118 | | fprintf(file, "/%s findfont %d scalefont setfont\n", |
119 | | format.lib.font, format.lib.size); |
120 | | fprintf(file, "%d %d moveto\n", format.left, -format.lib.y); |
121 | | ps_string(file, node->lib); |
122 | | fprintf(file, " show\n"); |
123 | | |
124 | | fprintf(file, "grestore\n"); |
125 | | } |
126 | | |
127 | | |
128 | | static void print_comment(FILE *file, const struct line *comment) |
129 | | { |
130 | | const struct line *line; |
131 | | int lines = 0; |
132 | | int n; |
133 | | |
134 | | fprintf(file, "gsave %s 0 setgray\n", format.overlay_setup); |
135 | | fprintf(file, "/%s findfont %d scalefont setfont\n", |
136 | | format.comment.font, format.comment.size); |
137 | | for (line = comment; line; line = line->next) |
138 | | lines++; |
139 | | n = 0; |
140 | | for (line = comment; line; line = line->next) { |
141 | | n++; |
142 | | fprintf(file, "%d -%d moveto\n", format.left, |
143 | | format.comment.y+(n-lines)*format.comment_line_skip); |
144 | | ps_string(file, line->s); |
145 | | fprintf(file, " show\n"); |
146 | | } |
147 | | fprintf(file, "grestore\n"); |
148 | | } |
149 | | |
150 | | |
151 | | static void cat(FILE *out, const char *name) |
152 | | { |
153 | | FILE *in; |
154 | | char buf[10000]; /* pick any good size */ |
155 | | size_t got, wrote; |
156 | | |
157 | | in = fopen(name, "r"); |
158 | | if (!in) { |
159 | | perror(name); |
160 | | exit(1); |
161 | | } |
162 | | while (1) { |
163 | | got = fread(buf, 1, sizeof(buf), in); |
164 | | if (!got) |
165 | | break; |
166 | | wrote = fwrite(buf, 1, got, out); |
167 | | if (wrote != got) { |
168 | | perror("fwrite"); |
169 | | exit(1); |
170 | | } |
171 | | } |
172 | | if (ferror(in)) { |
173 | | perror(name); |
174 | | exit(1); |
175 | | } |
176 | | fclose(in); |
177 | | } |
178 | | |
179 | | |
180 | | static void convert_comp(const struct node *node, FILE *out) |
181 | | { |
182 | | char *tmp; |
183 | | int i, res; |
184 | | |
185 | | for (i = 0; i != node->units; i++) { |
186 | | if (!quiet) { |
187 | | fprintf(stderr, "\r%u/%u", ++done, total); |
188 | | fflush(stderr); |
189 | | } |
190 | | make_title(out, node, i); |
191 | | if (!i && node->comment) |
192 | | print_comment(out, node->comment); |
193 | | if (asprintf(&tmp, "sym2xps '%s' '%s' %d '%s' '%s'", |
194 | | node->lib, node->names->s, i+1, "tmp", "tmp.ps") < 0) { |
195 | | perror("asprintf"); |
196 | | exit(1); |
197 | | } |
198 | | res = system(tmp); |
199 | | if (res < 0) { |
200 | | perror("system"); |
201 | | exit(1); |
202 | | } |
203 | | if (res) { |
204 | | fprintf(stderr, "sym2xps returned %d\n", res); |
205 | | exit(1); |
206 | | } |
207 | | fprintf(out, "gsave %s\n", format.comp_setup); |
208 | | cat(out, "tmp.ps"); |
209 | | fprintf(out, "\ngrestore\n"); |
210 | | } |
211 | | } |
212 | | |
213 | | |
214 | | static void convert_tree(const struct node *node, FILE *out) |
215 | | { |
216 | | while (node) { |
217 | | fprintf(out, "[ /Title (%s) /Count %d /OUT pdfmark\n", |
218 | | node->name, -children(node->child)); |
219 | | if (node->child) |
220 | | convert_tree(node->child, out); |
221 | | else |
222 | | convert_comp(node, out); |
223 | | node = node->next; |
224 | | } |
225 | | } |
226 | | |
227 | | |
228 | | static int count_tree(const struct node *node) |
229 | | { |
230 | | int sum = 0; |
231 | | |
232 | | while (node) { |
233 | | if (node->child) |
234 | | sum += count_tree(node->child); |
235 | | else |
236 | | sum += node->units; |
237 | | node = node->next; |
238 | | } |
239 | | return sum; |
240 | | } |
241 | | |
242 | | |
243 | | void make_pdf(int pdf, int use_portrait) |
244 | | { |
245 | | FILE *out; |
246 | | int res; |
247 | | |
248 | | if (use_portrait) |
249 | | format = portrait; |
250 | | else |
251 | | format = landscape; |
252 | | if (pdf) |
253 | | out = popen( |
254 | | "gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=- " |
255 | | "-f -", "w"); |
256 | | else |
257 | | out = popen("cat", "w"); |
258 | | if (!out) { |
259 | | perror("gs"); |
260 | | exit(1); |
261 | | } |
262 | | fprintf(out, "%%!PS\n%s\n", format.file_setup); |
263 | | total = count_tree(tree); |
264 | | convert_tree(tree, out); |
265 | | if (!quiet) |
266 | | fprintf(stderr, "\rFinishing\n"); |
267 | | res = pclose(out); |
268 | | if (res < 0) { |
269 | | perror("pclose"); |
270 | | exit(1); |
271 | | } |
272 | | if (res) { |
273 | | fprintf(stderr, "exit status %d\n", res); |
274 | | exit(1); |
275 | | } |
276 | | } |
genex/sym2xps |
1 | | #!/bin/sh -e |
2 | | # |
3 | | # sym2xps - Convert a symbol from a Kicad library to Postscript with expanded |
4 | | # pin types |
5 | | # |
6 | | # Copyright 2012 by Werner Almesberger |
7 | | # |
8 | | # This program is free software; you can redistribute it and/or modify |
9 | | # it under the terms of the GNU General Public License as published by |
10 | | # the Free Software Foundation; either version 2 of the License, or |
11 | | # (at your option) any later version. |
12 | | # |
13 | | |
14 | | |
15 | | usage() |
16 | | { |
17 | | echo "usage: $0 library symbol unit tmpdir outfile" 1>&2 |
18 | | exit 1 |
19 | | } |
20 | | |
21 | | |
22 | | lib=$1 |
23 | | sym=$2 |
24 | | unit=$3 |
25 | | tmp=$4 |
26 | | out=$5 |
27 | | |
28 | | [ "$lib" ] && [ "$sym" ] && [ "$unit" ] && [ "$tmp" ] && [ "$out" ] || usage |
29 | | |
30 | | [ -r "$lib" ] || { |
31 | | echo "$lib: not found" 1>&2 |
32 | | exit 1 |
33 | | } |
34 | | |
35 | | grep "^DEF $sym " "$lib" >/dev/null || grep "^DEF ~$sym " "$lib" >/dev/null || { |
36 | | echo "\"$sym\" not found in $lib" 1>&2 |
37 | | exit 1 |
38 | | } |
39 | | |
40 | | [ "${tmp#/}" = "$tmp" ] && tmp=`pwd`/$tmp |
41 | | [ "${out#/}" = "$out" ] && out=`pwd`/$out |
42 | | |
43 | | mkdir "$tmp" |
44 | | |
45 | | trap "rm -rf '$tmp'" 0 |
46 | | |
47 | | expand-pintype "$lib" "$tmp"/tmp.lib |
48 | | |
49 | | cat <<EOF >"$tmp"/tmp.pro |
50 | | [eeschema] |
51 | | version=1 |
52 | | [eeschema/libraries] |
53 | | LibName1=./tmp |
54 | | EOF |
55 | | |
56 | | X=6000 |
57 | | Y=4000 |
58 | | |
59 | | sed "\@^DEF $sym @,/^ENDDEF/p;d" "$lib" | |
60 | | awk '/^F. / { if ($1 == "F0") sub(/"$/, "?\"", $2); |
61 | | print substr($1, 1, 1), substr($1, 2, 1), $2, |
62 | | $6, '$X'+$3, '$Y'+$4, $5, " 0000", $8, $9 }' >"$tmp"/fx.tmp |
63 | | #F field_number "text" orientation posX posY size Flags (see below) |
64 | | #F0 reference posx posy text_size text_orient visibile htext_justify vtext_justify |
65 | | |
66 | | cat <<EOF >"$tmp"/tmp.sch |
67 | | EESchema Schematic File Version 2 date Mon Mar 26 09:29:33 2012 |
68 | | LIBS:dummy |
69 | | EELAYER 43 0 |
70 | | EELAYER END |
71 | | \$Comp |
72 | | L X$sym ?? |
73 | | U $unit 1 00000000 |
74 | | P $X $Y |
75 | | `cat "$tmp"/fx.tmp` |
76 | | $unit $X $Y |
77 | | 1 0 0 -1 |
78 | | \$EndComp |
79 | | \$EndSCHEMATC |
80 | | EOF |
81 | | |
82 | | cd "$tmp" |
83 | | eeschema --plot=ps "$tmp/tmp.sch" |
84 | | mv tmp.ps "$out" |