groff: update vendor branch to v1.20.1
[dragonfly.git] / contrib / groff / src / utils / pfbtops / pfbtops.c
CommitLineData
4d3e9548
JL
1/* Copyright (C) 1992, 2001, 2003, 2004, 2005, 2009
2 Free Software Foundation, Inc.
92d0a6a6
JR
3 Written by James Clark (jjc@jclark.com)
4
5This file is part of groff.
6
7groff is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
4d3e9548
JL
9Software Foundation, either version 3 of the License, or
10(at your option) any later version.
92d0a6a6
JR
11
12groff is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
4d3e9548
JL
17You should have received a copy of the GNU General Public License
18along with this program. If not, see <http://www.gnu.org/licenses/>. */
92d0a6a6
JR
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
4d3e9548
JL
26#define __GETOPT_PREFIX groff_
27
92d0a6a6
JR
28#include <stdio.h>
29#include <stdlib.h>
92d0a6a6
JR
30#include <limits.h>
31
465b256c
JR
32#include <getopt.h>
33
92d0a6a6
JR
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
41extern const char *Version_string;
42
43static char *program_name;
44
45static void error(const char *s)
46{
47 fprintf(stderr, "%s: %s\n", program_name, s);
48 exit(2);
49}
50
51static void usage(FILE *stream)
52{
53 fprintf(stream, "usage: %s [-v] [pfb_file]\n", program_name);
54}
55
56static 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
147static 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
167int 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}