Update to groff 1.19.2.
[dragonfly.git] / contrib / groff-1.19 / src / utils / pfbtops / pfbtops.c
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
44 static void error(const char *s)
45 {
46   fprintf(stderr, "%s: %s\n", program_name, s);
47   exit(2);
48 }
49
50 static void usage(FILE *stream)
51 {
52   fprintf(stream, "usage: %s [-v] [pfb_file]\n", program_name);
53 }
54
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
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
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 }