/* * 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 #include #include #include #include "comp.h" #include "pdf.h" static struct format { const char *file_setup; const char *overlay_setup; const char *comp_setup; int left; struct text { const char *font; int size; int y; } name, path, lib, comment; int comment_line_skip; } landscape = { .file_setup = "%%Orientation: Landscape", .overlay_setup = "90 rotate", .comp_setup = "", .left = 20, .name = { "Helvetica-Bold", 24, 57 }, .path = { "Helvetica-Bold", 18, 30 }, .lib = { "Courier", 12, 75 }, .comment = { "Helvetica", 12, 600 }, .comment_line_skip = 14, }, portrait = { .file_setup = "%%Orientation: Portrait", .overlay_setup = "0 790 translate", .comp_setup = "-120 700 translate -90 rotate", .left = 20, .name = { "Helvetica-Bold", 24, 57 }, .path = { "Helvetica-Bold", 18, 30 }, .lib = { "Courier", 12, 75 }, .comment = { "Helvetica", 12, 740 }, .comment_line_skip = 14, }, format; static int children(const struct node *node) { int n = 0; while (node) { n++; node = node->next; } return n; } 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); } 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->names; name; name = name->next) { if (name != node->names) fprintf(file, "(, ) show 0.5 setgray\n"); ps_string(file, name->s); fprintf(file, " show\n"); } fprintf(file, "0 setgray\n"); if (node->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->lib); 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"); } static 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); } static void convert_comp(const struct node *node, FILE *out) { char *tmp; int i, res; for (i = 0; i != node->units; i++) { make_title(out, node, i); if (!i && node->comment) print_comment(out, node->comment); if (asprintf(&tmp, "./sym2xps '%s' '%s' %d '%s' '%s'", node->lib, node->names->s, i+1, "tmp", "tmp.ps") < 0) { perror("asprintf"); exit(1); } res = system(tmp); if (res < 0) { perror("system"); exit(1); } if (res) { fprintf(stderr, "sym2xps returned %d\n", res); exit(1); } fprintf(out, "gsave %s\n", format.comp_setup); cat(out, "tmp.ps"); 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_comp(node, out); node = node->next; } } 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); convert_tree(tree, out); res = pclose(out); if (res < 0) { perror("pclose"); exit(1); } if (res) { fprintf(stderr, "exit status %d\n", res); exit(1); } }