1151497Sru/* Copyright (C) 1992, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
279543Sru     Written by James Clark (jjc@jclark.com)
379543Sru
479543SruThis file is part of groff.
579543Sru
679543Srugroff is free software; you can redistribute it and/or modify it under
779543Sruthe terms of the GNU General Public License as published by the Free
879543SruSoftware Foundation; either version 2, or (at your option) any later
979543Sruversion.
1079543Sru
1179543Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY
1279543SruWARRANTY; without even the implied warranty of MERCHANTABILITY or
1379543SruFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1479543Srufor more details.
1579543Sru
1679543SruYou should have received a copy of the GNU General Public License along
1779543Sruwith groff; see the file COPYING.  If not, write to the Free Software
18151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
1979543Sru
2075584Sru/* This translates ps fonts in .pfb format to ASCII ps files. */
2175584Sru
22104862Sru#ifdef HAVE_CONFIG_H
23104862Sru#include <config.h>
24104862Sru#endif
25104862Sru
2675584Sru#include <stdio.h>
27104862Sru#include <stdlib.h>
2875584Sru#include <limits.h>
2975584Sru
30151497Sru#define __GETOPT_PREFIX groff_
31151497Sru#include <getopt.h>
32151497Sru
3375584Sru#include "nonposix.h"
3475584Sru
3575584Sru/* Binary bytes per output line. */
3675584Sru#define BYTES_PER_LINE (64/2)
37114402Sru#define MAX_LINE_LENGTH 78
3875584Sru#define HEX_DIGITS "0123456789abcdef"
3975584Sru
40151497Sruextern const char *Version_string;
41151497Sru
4275584Srustatic char *program_name;
4375584Sru
44151497Srustatic void error(const char *s)
4575584Sru{
4675584Sru  fprintf(stderr, "%s: %s\n", program_name, s);
4775584Sru  exit(2);
4875584Sru}
4975584Sru
5075584Srustatic void usage(FILE *stream)
5175584Sru{
5275584Sru  fprintf(stream, "usage: %s [-v] [pfb_file]\n", program_name);
5375584Sru}
5475584Sru
55114402Srustatic void get_text(int n)
56114402Sru{
57151497Sru  int c = 0, c1;
58114402Sru  int in_string = 0;
59114402Sru  int is_comment = 0;
60114402Sru  int count = 0;
61114402Sru
62114402Sru  while (--n >= 0) {
63114402Sru    c = getchar();
64114402Sru    if (c == '(' && !is_comment)
65114402Sru      in_string++;
66114402Sru    else if (c == ')' && !is_comment)
67114402Sru      in_string--;
68114402Sru    else if (c == '%' && !in_string)
69114402Sru      is_comment = 1;
70114402Sru    else if (c == '\\' && in_string) {
71114402Sru      count++;
72114402Sru      putchar(c);
73151497Sru      if (n-- == 0)
74151497Sru	break;
75114402Sru      c = getchar();
76114402Sru      /* don't split octal character representations */
77114402Sru      if (c >= '0' && c <= '7') {
78114402Sru	count++;
79114402Sru	putchar(c);
80151497Sru	if (n-- == 0)
81151497Sru	  break;
82114402Sru	c = getchar();
83114402Sru	if (c >= '0' && c <= '7') {
84114402Sru	  count++;
85114402Sru	  putchar(c);
86151497Sru	  if (n-- == 0)
87151497Sru	    break;
88114402Sru	  c = getchar();
89114402Sru	  if (c >= '0' && c <= '7') {
90114402Sru	    count++;
91114402Sru	    putchar(c);
92151497Sru	    if (n-- == 0)
93151497Sru	      break;
94114402Sru	    c = getchar();
95114402Sru	  }
96114402Sru	}
97114402Sru      }
98114402Sru    }
99114402Sru    if (c == EOF)
100114402Sru      error("end of file in text packet");
101114402Sru    else if (c == '\r') {
102151497Sru      if (n-- == 0)
103151497Sru	break;
104114402Sru      c1 = getchar();
105151497Sru      if (c1 != '\n') {
106114402Sru	ungetc(c1, stdin);
107151497Sru	n++;
108151497Sru      }
109114402Sru      c = '\n';
110114402Sru    }
111114402Sru    if (c == '\n') {
112114402Sru      count = 0;
113114402Sru      is_comment = 0;
114114402Sru    }
115114402Sru    else if (count >= MAX_LINE_LENGTH) {
116114402Sru      if (in_string > 0) {
117114402Sru	count = 1;
118114402Sru	putchar('\\');
119114402Sru	putchar('\n');
120114402Sru      }
121114402Sru      else if (is_comment) {
122114402Sru	count = 2;
123114402Sru	putchar('\n');
124114402Sru	putchar('%');
125114402Sru      }
126114402Sru      else {
127114402Sru	/* split at the next whitespace character */
128114402Sru	while (c != ' ' && c != '\t' && c != '\f') {
129114402Sru	  putchar(c);
130151497Sru	  if (n-- == 0)
131151497Sru	    break;
132114402Sru	  c = getchar();
133114402Sru	}
134114402Sru	count = 0;
135114402Sru	putchar('\n');
136114402Sru	continue;
137114402Sru      }
138114402Sru    }
139114402Sru    count++;
140114402Sru    putchar(c);
141114402Sru  }
142114402Sru  if (c != '\n')
143114402Sru    putchar('\n');
144114402Sru}
145114402Sru
146114402Srustatic void get_binary(int n)
147114402Sru{
148114402Sru  int c;
149114402Sru  int count = 0;
150114402Sru
151114402Sru  while (--n >= 0) {
152114402Sru    c = getchar();
153114402Sru    if (c == EOF)
154114402Sru      error("end of file in binary packet");
155114402Sru    if (count >= BYTES_PER_LINE) {
156114402Sru      putchar('\n');
157114402Sru      count = 0;
158114402Sru    }
159114402Sru    count++;
160114402Sru    putchar(HEX_DIGITS[(c >> 4) & 0xf]);
161114402Sru    putchar(HEX_DIGITS[c & 0xf]);
162114402Sru  }
163114402Sru  putchar('\n');
164114402Sru}
165114402Sru
166151497Sruint main(int argc, char **argv)
16775584Sru{
16875584Sru  int opt;
16975584Sru  static const struct option long_options[] = {
17075584Sru    { "help", no_argument, 0, CHAR_MAX + 1 },
17175584Sru    { "version", no_argument, 0, 'v' },
17275584Sru    { NULL, 0, 0, 0 }
17375584Sru  };
17475584Sru
17575584Sru  program_name = argv[0];
17675584Sru
17775584Sru  while ((opt = getopt_long(argc, argv, "v", long_options, NULL)) != EOF) {
17875584Sru    switch (opt) {
17975584Sru    case 'v':
180151497Sru      printf("GNU pfbtops (groff) version %s\n", Version_string);
181151497Sru      exit(0);
182151497Sru      break;
18379543Sru    case CHAR_MAX + 1: /* --help */
18475584Sru      usage(stdout);
18575584Sru      exit(0);
18675584Sru      break;
18775584Sru    case '?':
18875584Sru      usage(stderr);
18975584Sru      exit(1);
19075584Sru      break;
19175584Sru    }
19275584Sru  }
19375584Sru
19475584Sru  if (argc - optind > 1) {
19575584Sru    usage(stderr);
19675584Sru    exit(1);
19775584Sru  }
198114402Sru  if (argc > optind && !freopen(argv[optind], "r", stdin)) {
199114402Sru    perror(argv[optind]);
200114402Sru    exit(1);
201114402Sru  }
20275584Sru  SET_BINARY(fileno(stdin));
203114402Sru  for (;;) {
204114402Sru    int type, c, i;
205114402Sru    long n;
20675584Sru
207114402Sru    c = getchar();
208114402Sru    if (c != 0x80)
209114402Sru      error("first byte of packet not 0x80");
210114402Sru    type = getchar();
211114402Sru    if (type == 3)
212114402Sru      break;
213114402Sru    if (type != 1 && type != 2)
214114402Sru      error("bad packet type");
215114402Sru    n = 0;
216114402Sru    for (i = 0; i < 4; i++) {
21775584Sru      c = getchar();
218114402Sru      if (c == EOF)
219114402Sru	error("end of file in packet header");
220114402Sru      n |= (long)c << (i << 3);
22175584Sru    }
222114402Sru    if (n < 0)
223114402Sru      error("negative packet length");
224114402Sru    if (type == 1)
225114402Sru      get_text(n);
226114402Sru    else
227114402Sru      get_binary(n);
228114402Sru  }
22975584Sru  exit(0);
23075584Sru}
231