1 /* Copyright (C) 1992, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
2 Written by James Clark (jjc@jclark.com)
3
4 This file is part of groff.
5
6 groff is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
9 version.
10
11 groff is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with groff; see the file COPYING. If not, write to the Free Software
18 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
19
20 /* This translates ps fonts in .pfb format to ASCII ps files. */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <limits.h>
29
30 #define __GETOPT_PREFIX groff_
31 #include <getopt.h>
32
33 #include "nonposix.h"
34
35 /* Binary bytes per output line. */
36 #define BYTES_PER_LINE (64/2)
37 #define MAX_LINE_LENGTH 78
38 #define HEX_DIGITS "0123456789abcdef"
39
40 extern const char *Version_string;
41
42 static char *program_name;
43
error(const char * s)44 static void error(const char *s)
45 {
46 fprintf(stderr, "%s: %s\n", program_name, s);
47 exit(2);
48 }
49
usage(FILE * stream)50 static void usage(FILE *stream)
51 {
52 fprintf(stream, "usage: %s [-v] [pfb_file]\n", program_name);
53 }
54
get_text(int n)55 static void get_text(int n)
56 {
57 int c = 0, c1;
58 int in_string = 0;
59 int is_comment = 0;
60 int count = 0;
61
62 while (--n >= 0) {
63 c = getchar();
64 if (c == '(' && !is_comment)
65 in_string++;
66 else if (c == ')' && !is_comment)
67 in_string--;
68 else if (c == '%' && !in_string)
69 is_comment = 1;
70 else if (c == '\\' && in_string) {
71 count++;
72 putchar(c);
73 if (n-- == 0)
74 break;
75 c = getchar();
76 /* don't split octal character representations */
77 if (c >= '0' && c <= '7') {
78 count++;
79 putchar(c);
80 if (n-- == 0)
81 break;
82 c = getchar();
83 if (c >= '0' && c <= '7') {
84 count++;
85 putchar(c);
86 if (n-- == 0)
87 break;
88 c = getchar();
89 if (c >= '0' && c <= '7') {
90 count++;
91 putchar(c);
92 if (n-- == 0)
93 break;
94 c = getchar();
95 }
96 }
97 }
98 }
99 if (c == EOF)
100 error("end of file in text packet");
101 else if (c == '\r') {
102 if (n-- == 0)
103 break;
104 c1 = getchar();
105 if (c1 != '\n') {
106 ungetc(c1, stdin);
107 n++;
108 }
109 c = '\n';
110 }
111 if (c == '\n') {
112 count = 0;
113 is_comment = 0;
114 }
115 else if (count >= MAX_LINE_LENGTH) {
116 if (in_string > 0) {
117 count = 1;
118 putchar('\\');
119 putchar('\n');
120 }
121 else if (is_comment) {
122 count = 2;
123 putchar('\n');
124 putchar('%');
125 }
126 else {
127 /* split at the next whitespace character */
128 while (c != ' ' && c != '\t' && c != '\f') {
129 putchar(c);
130 if (n-- == 0)
131 break;
132 c = getchar();
133 }
134 count = 0;
135 putchar('\n');
136 continue;
137 }
138 }
139 count++;
140 putchar(c);
141 }
142 if (c != '\n')
143 putchar('\n');
144 }
145
get_binary(int n)146 static void get_binary(int n)
147 {
148 int c;
149 int count = 0;
150
151 while (--n >= 0) {
152 c = getchar();
153 if (c == EOF)
154 error("end of file in binary packet");
155 if (count >= BYTES_PER_LINE) {
156 putchar('\n');
157 count = 0;
158 }
159 count++;
160 putchar(HEX_DIGITS[(c >> 4) & 0xf]);
161 putchar(HEX_DIGITS[c & 0xf]);
162 }
163 putchar('\n');
164 }
165
main(int argc,char ** argv)166 int main(int argc, char **argv)
167 {
168 int opt;
169 static const struct option long_options[] = {
170 { "help", no_argument, 0, CHAR_MAX + 1 },
171 { "version", no_argument, 0, 'v' },
172 { NULL, 0, 0, 0 }
173 };
174
175 program_name = argv[0];
176
177 while ((opt = getopt_long(argc, argv, "v", long_options, NULL)) != EOF) {
178 switch (opt) {
179 case 'v':
180 printf("GNU pfbtops (groff) version %s\n", Version_string);
181 exit(0);
182 break;
183 case CHAR_MAX + 1: /* --help */
184 usage(stdout);
185 exit(0);
186 break;
187 case '?':
188 usage(stderr);
189 exit(1);
190 break;
191 }
192 }
193
194 if (argc - optind > 1) {
195 usage(stderr);
196 exit(1);
197 }
198 if (argc > optind && !freopen(argv[optind], "r", stdin)) {
199 perror(argv[optind]);
200 exit(1);
201 }
202 SET_BINARY(fileno(stdin));
203 for (;;) {
204 int type, c, i;
205 long n;
206
207 c = getchar();
208 if (c != 0x80)
209 error("first byte of packet not 0x80");
210 type = getchar();
211 if (type == 3)
212 break;
213 if (type != 1 && type != 2)
214 error("bad packet type");
215 n = 0;
216 for (i = 0; i < 4; i++) {
217 c = getchar();
218 if (c == EOF)
219 error("end of file in packet header");
220 n |= (long)c << (i << 3);
221 }
222 if (n < 0)
223 error("negative packet length");
224 if (type == 1)
225 get_text(n);
226 else
227 get_binary(n);
228 }
229 exit(0);
230 }
231