This is gsftopk.c in view mode; [Download] [Up]
/*
* Copyright (c) 1994 Paul Vojta. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Patched to work with Kpathsea library by Thomas Esser,
* te@informatik.uni-hannover.de.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1994 Paul Vojta. All rights reserved.\n";
#endif
#include "c-auto.h"
#include "config.h"
#include <errno.h>
#include <ctype.h>
#if !defined (STDC_HEADERS) && defined (HAVE_MEMORY_H)
#include <memory.h>
#endif /* not STDC_HEADERS and HAVE_MEMORY_H */
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <setjmp.h>
#include <kpathsea/c-std.h>
#include <kpathsea/tex-file.h>
#ifdef POSIX_DIRENT
#include <dirent.h>
typedef struct dirent struct_dirent;
#else /* !POSIX */
#include <sys/dir.h>
typedef struct direct struct_dirent;
#endif
#ifndef GS
#define GS "gs"
#endif
#ifndef atof
double atof();
#endif
char *getenv();
#ifdef __GNUC__
#define NORETURN volatile
#else
#define NORETURN /* nothing */
#endif
#ifdef I_STDARG
#define NeedVarargsPrototypes 1
#include <stdarg.h>
#else
#define NeedVarargsPrototypes 0
#include <varargs.h>
#endif
typedef char Boolean;
#define True 1
#define False 0
#ifndef MAXPATHLEN
#define MAXPATHLEN 256
#endif
#define PK_PRE (char) 247
#define PK_ID 89
#define PK_POST (char) 245
#define PK_NOP (char) 246
char ident[] = "gsftopkk version 1.10";
typedef unsigned char byte;
FILE *data_file;
FILE *pk_file;
char *xfilename;
Boolean quiet = False;
int col = 0; /* current column number */
/*
* Information from the .tfm file.
*/
int tfm_lengths[12];
#define lh tfm_lengths[1]
#define bc tfm_lengths[2]
#define ec tfm_lengths[3]
#define nw tfm_lengths[4]
long checksum;
long design;
byte width_index[256];
long tfm_widths[256];
/*
* Information on the bitmap currently being worked on.
*/
byte *bitmap;
int width;
int skip;
int height;
int hoff;
int voff;
int bytes_wide;
unsigned int bm_size;
byte *bitmap_end;
int pk_len;
/*
* Print error message and quit.
*/
#if NeedVarargsPrototypes
NORETURN void
oops(const char *message, ...)
#else
/* VARARGS */
NORETURN void
oops(va_alist)
va_dcl
#endif
{
#if !NeedVarargsPrototypes
const char *message;
#endif
va_list args;
#if NeedVarargsPrototypes
va_start(args, message);
#else
va_start(args);
message = va_arg(args, const char *);
#endif
vfprintf(stderr, message, args);
va_end(args);
putc('\n', stderr);
exit(1);
}
/*
* Either allocate storage or fail with explanation.
*/
char *
xmalloc(size, why)
unsigned size;
const char *why;
{
char *mem = (char *) malloc(size);
if (mem == NULL)
oops("Cannot allocate %u bytes for %s.\n", size, why);
return mem;
}
/*
* Either reallocate storage or fail with explanation.
*/
char *
xrealloc(oldp, size, why)
char *oldp;
unsigned size;
const char *why;
{
char *mem;
mem = oldp == NULL ? (char *) malloc(size)
: (char *) realloc(oldp, size);
if (mem == NULL)
oops("Cannot reallocate %u bytes for %s.\n", size, why);
return mem;
}
/*
* Here's the patch searching stuff. First the typedefs and variables.
*/
static char searchpath[MAXPATHLEN + 1];
#define HUNKSIZE (MAXPATHLEN + 2)
struct spacenode { /* used for storage of directory names */
struct spacenode *next;
char *sp_end; /* end of data for this chunk */
char sp[HUNKSIZE];
}
firstnode;
static jmp_buf found_env;
static FILE *searchfile;
static char *searchname;
static int searchnamelen;
static char *
find_dbl_slash(char *sp_bgn, char *sp_end)
{
char *p;
for (;;) {
p = memchr(sp_bgn, '/', sp_end - sp_bgn);
if (p == NULL) return sp_end;
if (p[1] == '/') return p;
sp_bgn = p + 1;
}
}
static FILE *
search(char *name, kpse_file_format_type path)
{
strcpy(searchpath,kpse_find_file(name, path, true));
searchfile = fopen(searchpath, "r");
return searchfile;
}
/*
* Add to dlstring
*/
char *dlstring = NULL;
unsigned int dls_len = 0;
unsigned int dls_max = 0;
void
addtodls(char *s)
{
int len = strlen(s);
if (dls_len + len >= dls_max) {
unsigned int newsize = dls_max + 80;
if (newsize <= dls_len + len) newsize = dls_len + len + 1;
dlstring = xrealloc(dlstring, dls_max = newsize, "download string");
}
strcpy(dlstring + dls_len, s);
dls_len += len;
}
long
getlong(FILE *f)
{
int value;
value = (int) ((byte) getc(f)) << 24;
value |= (int) ((byte) getc(f)) << 16;
value |= (int) ((byte) getc(f)) << 8;
value |= (int) ((byte) getc(f));
return value;
}
char line[82];
void
expect(char *waitingfor)
{
for (;;) {
if (fgets(line, sizeof(line), data_file) == NULL)
oops("Premature end of file");
if (memcmp(line, waitingfor, strlen(waitingfor)) == 0) return;
fputs("gs: ", stdout);
for (;;) {
fputs(line, stdout);
if (*line == '\0' || line[strlen(line) - 1] == '\n') break;
if (fgets(line, sizeof(line), data_file) == NULL)
oops("Premature end of file");
}
}
}
void
whitespace(void)
{
char c;
for (;;) {
c = getc(data_file);
if (c == '#')
do c = getc(data_file); while (!feof(data_file) && c != '\n');
else if (!isspace(c)) {
ungetc(c, data_file);
break;
}
}
}
int
getint(void)
{
char c;
int i = 0;
do c = getc(data_file); while (isspace(c));
if (c < '0' || c > '9') oops("digit expected");
do {
i = i * 10 + (c - '0');
c = getc(data_file);
} while (c >= '0' && c <= '9');
if (!feof(data_file)) ungetc(c, data_file);
return i;
}
static byte masks[] = {0, 1, 3, 7, 017, 037, 077, 0177, 0377};
byte flag;
int pk_dyn_f;
int pk_dyn_g;
int base; /* cost of this character if pk_dyn_f = 0 */
int deltas[13]; /* cost of increasing pk_dyn_f from i to i+1 */
/*
* Add up statistics for putting out the given shift count
*/
static void
tallyup(int n)
{
int m;
if (n > 208) {
++base;
n -= 192;
for (m = 0x100; m != 0 && m < n; m <<= 4) base += 2;
if (m != 0 && (m = (m - n) / 15) < 13) deltas[m] += 2;
}
else if (n > 13) ++deltas[(208 - n) / 15];
else --deltas[n - 1];
}
/*
* Routines for storing the shift counts
*/
static Boolean odd = False;
static byte part;
static void
pk_put_nyb(int n)
{
if (odd) {
*bitmap_end++ = (part << 4) | n;
odd = False;
}
else {
part = n;
odd = True;
}
}
static void
pk_put_long(int n)
{
if (n >= 16) {
pk_put_nyb(0);
pk_put_long(n / 16);
}
pk_put_nyb(n % 16);
}
static void
pk_put_count(int n)
{
if (n > pk_dyn_f) {
if (n > pk_dyn_g)
pk_put_long(n - pk_dyn_g + 15);
else {
pk_put_nyb(pk_dyn_f + (n - pk_dyn_f + 15) / 16);
pk_put_nyb((n - pk_dyn_f - 1) % 16);
}
}
else pk_put_nyb(n);
}
static void
trim_bitmap(void)
{
byte *p;
byte mask;
/* clear out garbage bits in bitmap */
if (width % 8 != 0) {
mask = ~masks[8 - width % 8];
for (p = bitmap + bytes_wide - 1; p < bitmap_end; p += bytes_wide)
*p &= mask;
}
/*
* Find the bounding box of the bitmap.
*/
/* trim top */
skip = 0;
mask = 0;
for (;;) {
if (bitmap >= bitmap_end) { /* if bitmap is empty */
width = height = hoff = voff = 0;
return;
}
p = bitmap + bytes_wide;
while (p > bitmap) mask |= *--p;
if (mask) break;
++skip;
bitmap += bytes_wide;
}
height -= skip;
voff -= skip;
#ifdef DEBUG
if (skip < 2 || skip > 3)
printf("Character has %d empty rows at top\n", skip);
#endif
/* trim bottom */
skip = 0;
mask = 0;
for (;;) {
p = bitmap_end - bytes_wide;
while (p < bitmap_end) mask |= *p++;
if (mask) break;
++skip;
bitmap_end -= bytes_wide;
}
height -= skip;
#ifdef DEBUG
if (skip < 2 || skip > 3)
printf("Character has %d empty rows at bottom\n", skip);
#endif
/* trim right */
skip = 0;
--width;
for (;;) {
mask = 0;
for (p = bitmap + width / 8; p < bitmap_end; p += bytes_wide)
mask |= *p;
if (mask & (0x80 >> (width % 8))) break;
--width;
++skip;
}
++width;
#ifdef DEBUG
if (skip < 2 || skip > 3)
printf("Character has %d empty columns at right\n", skip);
#endif
/* trim left */
skip = 0;
for (;;) {
mask = 0;
for (p = bitmap + skip / 8; p < bitmap_end; p += bytes_wide)
mask |= *p;
if (mask & (0x80 >> (skip % 8))) break;
++skip;
}
width -= skip;
hoff -= skip;
#ifdef DEBUG
if (skip < 2 || skip > 3)
printf("Character has %d empty columns at left\n", skip);
#endif
bitmap += skip / 8;
skip = skip % 8;
}
/*
* Pack the bitmap using the rll method. (Return false if it's better
* to just pack the bits.)
*/
static Boolean
pk_rll_cvt(void)
{
static int *counts = NULL; /* area for saving bit counts */
static int maxcounts = 0; /* size of this area */
unsigned int ncounts; /* max to allow this time */
int *nextcount; /* next count value */
int *counts_end; /* pointer to end */
byte *rowptr;
byte *p;
byte mask;
byte *rowdup; /* last row checked for dup */
byte paint_switch; /* 0 or 0xff */
int bits_left; /* bits left in row */
int cost;
int i;
/*
* Allocate space for bit counts.
*/
ncounts = (width * height + 3) / 4;
if (ncounts > maxcounts) {
if (counts != NULL) free(counts);
counts = (int *) xmalloc((ncounts + 2) * sizeof(int),
"array for bit counts");
maxcounts = ncounts;
}
counts_end = counts + ncounts;
/*
* Form bit counts and collect statistics
*/
base = 0;
bzero(deltas, sizeof(deltas));
rowdup = NULL; /* last row checked for duplicates */
p = rowptr = bitmap;
mask = 0x80 >> skip;
flag = 0;
paint_switch = 0;
if (*p & mask) {
flag = 8;
paint_switch = 0xff;
}
bits_left = width;
nextcount = counts;
while (rowptr < bitmap_end) { /* loop over shift counts */
int shift_count = bits_left;
for (;;) {
if (bits_left == 0) {
if ((p = rowptr += bytes_wide) >= bitmap_end) break;
mask = 0x80 >> skip;
bits_left = width;
shift_count += width;
}
if (((*p ^ paint_switch) & mask) != 0) break;
--bits_left;
mask >>= 1;
if (mask == 0) {
++p;
while (*p == paint_switch && bits_left >= 8) {
++p;
bits_left -= 8;
}
mask = 0x80;
}
}
if (nextcount >= counts_end) return False;
shift_count -= bits_left;
*nextcount++ = shift_count;
tallyup(shift_count);
/* check for duplicate rows */
if (rowptr != rowdup && bits_left != width) {
byte *p1 = rowptr;
byte *q = rowptr + bytes_wide;
int repeat_count;
while (q < bitmap_end && *p1 == *q) ++p1, ++q;
repeat_count = (p1 - rowptr) / bytes_wide;
if (repeat_count > 0) {
*nextcount++ = -repeat_count;
if (repeat_count == 1) --base;
else {
++base;
tallyup(repeat_count);
}
rowptr += repeat_count * bytes_wide;
}
rowdup = rowptr;
}
paint_switch = ~paint_switch;
}
#ifdef DEBUG
/*
* Dump the bitmap
*/
for (p = bitmap; p < bitmap_end; p += bytes_wide) {
byte *p1 = p;
int j;
mask = 0x80 >> skip;
for (j = 0; j < width; ++j) {
putchar(*p1 & mask ? '@' : '.');
if ((mask >>= 1) == 0) mask = 0x80, ++p1;
}
putchar('\n');
}
putchar('\n');
#endif
/*
* Determine the best pk_dyn_f
*/
pk_dyn_f = 0;
cost = base += 2 * (nextcount - counts);
for (i = 1; i < 14; ++i) {
base += deltas[i - 1];
if (base < cost) {
pk_dyn_f = i;
cost = base;
}
}
/* last chance to bail out */
if (cost * 4 > width * height) return False;
/*
* Pack the bit counts
*/
pk_dyn_g = 208 - 15 * pk_dyn_f;
flag |= pk_dyn_f << 4;
bitmap_end = bitmap;
*nextcount = 0;
nextcount = counts;
while (*nextcount != 0) {
if (*nextcount > 0) pk_put_count(*nextcount);
else
if (*nextcount == -1) pk_put_nyb(15);
else {
pk_put_nyb(14);
pk_put_count(-*nextcount);
}
++nextcount;
}
if (odd) {
pk_put_nyb(0);
++cost;
}
if (cost != 2 * (bitmap_end - bitmap))
printf("Cost miscalculation: expected %d, got %d\n", cost,
2 * (bitmap_end - bitmap));
pk_len = bitmap_end - bitmap;
return True;
}
static void
pk_bm_cvt(void)
{
byte *rowptr;
byte *p;
int blib1; /* bits left in byte */
int bits_left; /* bits left in row */
byte *q;
int blib2;
byte nextbyte;
flag = 14 << 4;
q = bitmap;
blib2 = 8;
nextbyte = 0;
for (rowptr = bitmap; rowptr < bitmap_end; rowptr += bytes_wide) {
p = rowptr;
blib1 = 8 - skip;
bits_left = width;
if (blib2 != 8) {
int n;
if (blib1 < blib2) {
nextbyte |= *p << (blib2 - blib1);
n = blib1;
}
else {
nextbyte |= *p >> (blib1 - blib2);
n = blib2;
}
blib2 -= n;
if ((bits_left -= n) < 0) {
blib2 -= bits_left;
continue;
}
if ((blib1 -= n) == 0) {
blib1 = 8;
++p;
if (blib2 > 0) {
nextbyte |= *p >> (8 - blib2);
blib1 -= blib2;
bits_left -= blib2;
if (bits_left < 0) {
blib2 = -bits_left;
continue;
}
}
}
*q++ = nextbyte;
}
/* fill up whole (destination) bytes */
while (bits_left >= 8) {
nextbyte = *p++ << (8 - blib1);
*q++ = nextbyte | (*p >> blib1);
bits_left -= 8;
}
/* now do the remainder */
nextbyte = *p << (8 - blib1);
if (bits_left > blib1) nextbyte |= p[1] >> blib1;
blib2 = 8 - bits_left;
}
if (blib2 != 8) *q++ = nextbyte;
pk_len = q - bitmap;
}
static void
putshort(short w)
{
putc(w >> 8, pk_file);
putc(w, pk_file);
}
static void
putmed(long w)
{
putc(w >> 16, pk_file);
putc(w >> 8, pk_file);
putc(w, pk_file);
}
static void
putlong(long w)
{
putc(w >> 24, pk_file);
putc(w >> 16, pk_file);
putc(w >> 8, pk_file);
putc(w, pk_file);
}
static void
putglyph(int cc)
{
static Boolean have_first_line = False;
static int llx, lly, urx, ury;
static float char_width;
static byte *area1 = NULL;
static unsigned int size1 = 0;
long dm;
long tfm_wid;
byte *p;
int i;
if (!quiet) {
int wid;
static char *s = "";
wid = (cc >= 100) + (cc >= 10) + 4;
if (col + wid > 80) {
s = "\n";
col = 0;
}
printf("%s[%d", s, cc);
fflush(stdout);
col += wid;
s = " ";
}
if (!have_first_line) {
expect("#^");
if (sscanf(line, "#^ %d %d %d %d %d %f\n", &i,
&llx, &lly, &urx, &ury, &char_width) != 6)
oops("Cannot scanf first line");
}
if (i < cc) oops("Character %d received, %d expected", i, cc);
if (i > cc) {
fprintf(stderr, "Character %d is missing.\n", cc);
have_first_line = True;
return;
}
have_first_line = False;
hoff = -llx + 2;
voff = ury + 2 - 1;
expect("P4\n");
whitespace();
width = getint();
whitespace();
height = getint();
(void) getc(data_file);
if (width != urx - llx + 4 || height != ury - lly + 4)
oops("Dimensions do not match: %d %d %d %d %d %d",
llx, lly, urx, ury, width, height);
bytes_wide = (width + 7) / 8;
bm_size = bytes_wide * height;
if (size1 < bm_size) {
if (area1 != NULL) free(area1);
area1 = (byte *) xmalloc(bm_size, "original bitmap");
size1 = bm_size;
}
for (p = area1 + (height - 1) * bytes_wide; p >= area1; p -= bytes_wide)
if (fread(p, 1, bytes_wide, data_file) != bytes_wide)
oops("Cannot read bitmap of size %u", bm_size);
bitmap = area1;
bitmap_end = bitmap + bm_size;
trim_bitmap();
if (height == 0 || !pk_rll_cvt()) pk_bm_cvt();
tfm_wid = tfm_widths[width_index[cc]];
dm = (long) (char_width + 0.5) - (char_width < -0.5);
if (pk_len + 8 < 4 * 256 && tfm_wid < (1<<24) &&
dm >= 0 && dm < 256 && width < 256 && height < 256 &&
hoff >= -128 && hoff < 128 && voff >= -128 && voff < 128) {
putc(flag | ((pk_len + 8) >> 8), pk_file);
putc(pk_len + 8, pk_file);
putc(cc, pk_file);
putmed(tfm_wid);
putc(dm, pk_file);
putc(width, pk_file);
putc(height, pk_file);
putc(hoff, pk_file);
putc(voff, pk_file);
} else
if (pk_len + 13 < 3 * 65536L && tfm_wid < (1<<24) &&
dm >= 0 && dm < 65536L && width < 65536L && height < 65536L &&
hoff >= -65536L && hoff < 65536L &&
voff >= -65536L && voff < 65536L) {
putc(flag | 4 | ((pk_len + 13) >> 16), pk_file);
putshort(pk_len + 13);
putc(cc, pk_file);
putmed(tfm_wid);
putshort(dm);
putshort(width);
putshort(height);
putshort(hoff);
putshort(voff);
}
else {
putc(flag | 7, pk_file);
putlong(pk_len + 28);
putlong(cc);
putlong(tfm_wid);
putlong((long) (char_width * 65536.0 + 0.5) - (char_width < -0.5));
putlong(0);
putlong(width);
putlong(height);
putlong(hoff);
putlong(voff);
}
fwrite(bitmap, 1, pk_len, pk_file);
if (!quiet) {
putchar(']');
fflush(stdout);
}
}
int
main(int argc, char **argv)
{
FILE *config_file;
FILE *tfm_file;
float dpi;
char *fontname;
int fontlen;
char *configline;
unsigned int cflinelen;
char *p;
char *PSname = NULL;
char *specinfo = "";
char charlist[10*2 + 90*3 + 156*4 + 1];
char designstr[20];
char dpistr[20];
int pid;
int std_in[2];
int std_out[2];
int status;
int cc;
int ppp;
int i;
kpse_set_progname(argv[0]);
kpse_init_prog("GSFTOPK", 300, "cx", false, "cmr10");
xputenv_int ("KPATHSEA_DPI", 300);
if (argc > 1 && strcmp(argv[1], "-q") == 0) {
++argv;
--argc;
quiet = True;
}
if (argc != 3 || (dpi = atof(argv[2])) <= 0.0) {
fputs("Usage: gsftopk [-q] <font> <dpi>\n", stderr);
exit(1);
}
fontname = argv[1];
fontlen = strlen(fontname);
if (!quiet) puts(ident);
config_file = search("psfonts.map",kpse_dvips_config_format);
if (config_file == NULL) oops("Cannot find file psfonts.map.");
configline = (char *) xmalloc(cflinelen = 80, "Config file line");
do {
int len = 0;
if (fgets(configline, cflinelen, config_file) == NULL)
oops("Cannot find font %s in config file.", fontname);
for (;;) {
i = strlen(configline + len);
len += i;
if (len > 0 && configline[len - 1] == '\n') {
configline[--len] = '\0';
break;
}
if (len < cflinelen - 1) break;
configline = xrealloc(configline, cflinelen += 80,
"config file line");
fgets(configline + len, cflinelen - len, config_file);
}
}
while (memcmp(configline, fontname, fontlen) != 0
|| (configline[fontlen] != '\0' && !isspace(configline[fontlen])));
fclose(config_file);
/*
* Parse the line from the config file.
*/
for (p = configline + fontlen; *p != '\0'; ++p) {
if (isspace(*p)) continue;
if (*p == '<') {
char *q = ++p;
char endc;
FILE *f;
addtodls(" (");
while (*p != '\0' && !isspace(*p)) ++p;
endc = *p;
*p = '\0';
f = search(q,kpse_dvips_header_format);
if (f == NULL) oops("Cannot find font file %s", q);
/* search() also sets searchpath */
addtodls(searchpath);
addtodls((char) getc(f) == '\200' ? ") brun" : ") run");
fclose(f);
if (endc == '\0') break;
continue;
}
else if (*p == '"') {
char *q;
specinfo = ++p;
q = strchr(p, '"');
if (q == NULL) break;
p = q;
}
else {
PSname = p;
while (*p != '\0' && !isspace(*p)) ++p;
if (*p == '\0') break;
}
*p = '\0';
}
#ifdef OLD_DVIPS
/* Parse lines like `Symbol-Slanted "/Symbol .167 SlantFont"'. */
if (*(p = specinfo) == '/') {
PSname = ++p;
while (*p && !isspace(*p)) ++p;
if (*p) *p++ = '\0';
specinfo = p;
}
#endif /* OLD_DVIPS */
/*
* Start up GhostScript.
*/
tfm_file = search("render.ps",kpse_dvips_header_format);
if (tfm_file == NULL)
oops("Cannot find PS driver file \"render.ps\".");
fclose(tfm_file);
sprintf(dpistr, "%f", dpi);
if (pipe(std_in) != 0 || pipe(std_out) != 0) {
perror("pipe");
return 1;
}
fflush(stderr); /* to avoid double flushing */
pid = vfork();
if (pid == 0) {
close(std_in[1]);
dup2(std_in[0], 0);
close(std_in[0]);
close(std_out[0]);
dup2(std_out[1], 1);
close(std_out[1]);
execlp(GS, "gs", "-DNODISPLAY", "-dNOGC", "-q", "--",
/* render.ps */ searchpath,
PSname != NULL ? PSname : fontname,
dlstring != NULL ? dlstring : "", specinfo, dpistr, NULL);
perror("gs");
exit(1);
}
if (pid == -1) {
perror("fork");
exit(1);
}
/*
* Open and read the tfm file. If this takes a while, at least
* it can overlap with the startup of GhostScript.
*/
fontlen = strlen(fontname);
xfilename = xmalloc(fontlen + 10, "name of tfm/pk file");
strcpy(xfilename, fontname);
strcpy(xfilename + fontlen, ".tfm");
tfm_file = search(xfilename,kpse_tfm_format);
if (tfm_file == NULL) oops("Cannot find tfm file.");
for (i = 0; i < 12; ++i) {
int j;
j = (int) ((byte) getc(tfm_file)) << 8;
tfm_lengths[i] = j | (int) ((byte) getc(tfm_file));
}
checksum = getlong(tfm_file);
design = getlong(tfm_file);
fseek(tfm_file, 4 * (lh + 6), 0);
p = charlist;
for (cc = bc; cc <= ec; ++cc) {
width_index[cc] = (byte) getc(tfm_file);
if (width_index[cc] != 0) {
sprintf(p, "%d ", cc);
p += strlen(p);
}
(void) getc(tfm_file);
(void) getc(tfm_file);
(void) getc(tfm_file);
}
for (i = 0; i < nw; ++i) tfm_widths[i] = getlong(tfm_file);
fclose(tfm_file);
p[-1] = '\n';
/* write the design size and character list to the file */
sprintf(designstr, "%f\n", (float) design / (1 << 20));
write(std_in[1], designstr, strlen(designstr));
write(std_in[1], charlist, p - charlist);
close(std_in[1]);
/*
* Read the output from GhostScript.
*/
if ((data_file = fdopen(std_out[0], "r")) == NULL) {
perror("GS_out");
exit(1);
}
/*
* Create pk file and write preamble.
*/
fflush(stdout);
sprintf(xfilename + fontlen, ".%dpk", (int) (dpi + 0.5));
if ((pk_file = fopen(xfilename, "w")) == NULL) {
perror(xfilename);
exit(1);
}
putc(PK_PRE, pk_file);
putc(PK_ID, pk_file);
i = strlen(ident);
putc(i, pk_file);
fwrite(ident, 1, i, pk_file);
putlong(design);
putlong(checksum);
ppp = dpi / 72.27 * 65536.0 + 0.5;
putlong(ppp); /* hppp */
putlong(ppp); /* vppp */
/*
* Write the actual characters.
*/
for (cc = bc; cc <= ec; ++cc)
if (width_index[cc] != 0)
putglyph(cc);
fclose(data_file);
if (wait(&status) == -1) {
perror("wait");
exit(1);
}
if (status != 0)
if (status & 0377)
oops("Call to gs stopped by signal %d", status & 0177);
else oops("Call to gs returned nonzero status %d", status >> 8);
putc(PK_POST, pk_file);
while (ftell(pk_file) % 4 != 0) putc(PK_NOP, pk_file);
fclose(pk_file);
if (!quiet) putchar('\n');
return 0;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.