/* Copyright (C) 1992-2020 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
groff is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or
(at your option) any later version.
groff is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
/* This translates ps fonts in .pfb format to ASCII ps files. */
#ifdef HAVE_CONFIG_H
#include
#endif
#define __GETOPT_PREFIX groff_
#include // errno
#include
#include // exit(), EXIT_FAILURE, EXIT_SUCCESS
#include // strerror()
#include
#include
#include "nonposix.h"
/* Binary bytes per output line. */
#define BYTES_PER_LINE (64/2)
#define MAX_LINE_LENGTH 78
#define HEX_DIGITS "0123456789abcdef"
extern const char *Version_string;
static char *program_name;
static void error(const char *s)
{
fprintf(stderr, "%s: error: %s\n", program_name, s);
exit(EXIT_FAILURE);
}
static void usage(FILE *stream)
{
fprintf(stream, "usage: %s [pfb-file]\n"
"usage: %s {-v | --version}\n"
"usage: %s --help\n",
program_name, program_name, program_name);
}
static void get_text(int n)
{
int c = 0, c1;
int in_string = 0;
int is_comment = 0;
int count = 0;
while (--n >= 0) {
c = getchar();
if (c == '(' && !is_comment)
in_string++;
else if (c == ')' && !is_comment)
in_string--;
else if (c == '%' && !in_string)
is_comment = 1;
else if (c == '\\' && in_string) {
count++;
putchar(c);
if (n-- == 0)
break;
c = getchar();
/* don't split octal character representations */
if (c >= '0' && c <= '7') {
count++;
putchar(c);
if (n-- == 0)
break;
c = getchar();
if (c >= '0' && c <= '7') {
count++;
putchar(c);
if (n-- == 0)
break;
c = getchar();
if (c >= '0' && c <= '7') {
count++;
putchar(c);
if (n-- == 0)
break;
c = getchar();
}
}
}
}
if (c == EOF)
error("end of file in text packet");
else if (c == '\r') {
if (n-- == 0)
break;
c1 = getchar();
if (c1 != '\n') {
ungetc(c1, stdin);
n++;
}
c = '\n';
}
if (c == '\n') {
count = 0;
is_comment = 0;
}
else if (count >= MAX_LINE_LENGTH) {
if (in_string > 0) {
count = 1;
putchar('\\');
putchar('\n');
}
else if (is_comment) {
count = 2;
putchar('\n');
putchar('%');
}
else {
/* split at the next whitespace character */
while (c != ' ' && c != '\t' && c != '\f') {
putchar(c);
if (n-- == 0)
break;
c = getchar();
}
count = 0;
putchar('\n');
continue;
}
}
count++;
putchar(c);
}
if (c != '\n')
putchar('\n');
}
static void get_binary(int n)
{
int c;
int count = 0;
while (--n >= 0) {
c = getchar();
if (c == EOF)
error("end of file in binary packet");
if (count >= BYTES_PER_LINE) {
putchar('\n');
count = 0;
}
count++;
putchar(HEX_DIGITS[(c >> 4) & 0xf]);
putchar(HEX_DIGITS[c & 0xf]);
}
putchar('\n');
}
int main(int argc, char **argv)
{
int opt;
static const struct option long_options[] = {
{ "help", no_argument, 0, CHAR_MAX + 1 },
{ "version", no_argument, 0, 'v' },
{ NULL, 0, 0, 0 }
};
program_name = argv[0];
while ((opt = getopt_long(argc, argv, "v", long_options, NULL)) != EOF) {
switch (opt) {
case 'v':
printf("GNU pfbtops (groff) version %s\n", Version_string);
exit(EXIT_SUCCESS);
break;
case CHAR_MAX + 1: /* --help */
usage(stdout);
exit(EXIT_SUCCESS);
break;
case '?':
usage(stderr);
exit(2);
break;
}
}
if (argc - optind > 1) {
usage(stderr);
exit(2);
}
const char *file = argv[optind];
if (argc > optind && !freopen(file, "r", stdin)) {
fprintf(stderr, "%s: error: unable to open file '%s': %s\n",
program_name, file, strerror(errno));
exit(EXIT_FAILURE);
}
SET_BINARY(fileno(stdin));
for (;;) {
int type, c, i;
long n;
c = getchar();
if (c != 0x80)
error("first byte of packet not 0x80");
type = getchar();
if (type == 3)
break;
if (type != 1 && type != 2)
error("bad packet type");
n = 0;
for (i = 0; i < 4; i++) {
c = getchar();
if (c == EOF)
error("end of file in packet header");
n |= (long)c << (i << 3);
}
if (n < 0)
error("negative packet length");
if (type == 1)
get_text(n);
else
get_binary(n);
}
exit(EXIT_SUCCESS);
}
// Local Variables:
// fill-column: 72
// mode: C
// End:
// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: