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