#include "gsint.h"
#define CFG_FATAL(body) \
do { \
fprintf (stderr, "%s:%s:%d: ", program, fname, line); \
fprintf body; \
fprintf (stderr, "\n"); \
fflush (stderr); \
exit (1); \
} while (0)
static struct
{
int code;
char *name;
} enc_7bit_ascii_fise[] =
{
{'{', "adieresis"},
{'|', "odieresis"},
{'}', "aring"},
{'[', "Adieresis"},
{'\\', "Odieresis"},
{']', "Aring"},
{0, NULL},
};
static struct
{
int code;
char *name;
} enc_7bit_ascii_dkno[] =
{
{'{', "ae"},
{'|', "oslash"},
{'}', "aring"},
{'[', "AE"},
{'\\', "Oslash"},
{']', "Aring"},
{0, NULL},
};
#define GET_TOKEN(from) (strtok ((from), " \t\n"))
#define GET_LINE_TOKEN(from) (strtok ((from), "\n"))
#define CHECK_TOKEN() \
if (token2 == NULL) \
CFG_FATAL ((stderr, _("missing argument: %s"), token));
int
read_config (char *path, char *file)
{
FILE *fp;
char fname[512];
char buf[4096];
char *token, *token2;
int line = 0;
sprintf (fname, "%s/%s", path, file);
fp = fopen (fname, "r");
if (fp == NULL)
return 0;
while (fgets (buf, sizeof (buf), fp))
{
line++;
if (buf[0] == '#')
continue;
token = GET_TOKEN (buf);
if (token == NULL)
continue;
if (MATCH (token, "AcceptCompositeCharacters:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
accept_composites = atoi (token2);
}
else if (MATCH (token, "AFMPath:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
strcpy (afm_path_buffer, token2);
afm_path = afm_path_buffer;
}
else if (MATCH (token, "AppendCtrlD:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
append_ctrl_D = atoi (token2);
}
else if (MATCH (token, "Clean7Bit:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
clean_7bit = atoi (token2);
}
else if (MATCH (token, "DefaultEncoding:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
strcpy (encoding_name_buffer, token2);
encoding_name = encoding_name_buffer;
}
else if (MATCH (token, "DefaultFancyHeader:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
strcpy (fancy_header_default, token2);
}
else if (MATCH (token, "DefaultMedia:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
strcpy (media_name_buffer, token2);
media_name = media_name_buffer;
}
else if (MATCH (token, "DefaultOutputMethod:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
if (MATCH (token2, "printer"))
output_file = OUTPUT_FILE_NONE;
else if (MATCH (token2, "stdout"))
output_file = OUTPUT_FILE_STDOUT;
else
CFG_FATAL ((stderr, _("illegal value \"%s\" for option %s"),
token2, token));
}
else if (MATCH (token, "DownloadFont:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
strhash_put (download_fonts, token2, strlen (token2) + 1, NULL,
NULL);
}
else if (MATCH (token, "EscapeChar:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
escape_char = atoi (token2);
if (escape_char < 0 || escape_char > 255)
CFG_FATAL ((stderr, _("invalid value \"%s\" for option %s"),
token2, token));
}
else if (MATCH (token, "FormFeedType:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
if (MATCH (token2, "column"))
formfeed_type = FORMFEED_COLUMN;
else if (MATCH (token2, "page"))
formfeed_type = FORMFEED_PAGE;
else
CFG_FATAL ((stderr, _("illegal value \"%s\" for option %s"),
token2, token));
}
else if (MATCH (token, "GeneratePageSize:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
generate_PageSize = atoi (token2);
}
else if (MATCH (token, "HighlightBarGray:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
highlight_bar_gray = atof (token2);
}
else if (MATCH (token, "HighlightBars:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
highlight_bars = atoi (token2);
}
else if (MATCH (token, "LibraryPath:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
strcpy (libpath, token2);
}
else if (MATCH (token, "MarkWrappedLines:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
strcpy (mark_wrapped_lines_style_name, token2);
}
else if (MATCH (token, "Media:"))
{
char *name;
int w, h, llx, lly, urx, ury;
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
name = token2;
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
w = atoi (token2);
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
h = atoi (token2);
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
llx = atoi (token2);
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
lly = atoi (token2);
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
urx = atoi (token2);
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
ury = atoi (token2);
add_media (name, w, h, llx, lly, urx, ury);
}
else if (MATCH (token, "NoJobHeaderSwitch:"))
{
token2 = GET_LINE_TOKEN (NULL);
CHECK_TOKEN ();
strcpy (no_job_header_switch, token2);
}
else if (MATCH (token, "NonPrintableFormat:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
strcpy (npf_name_buf, token2);
npf_name = npf_name_buf;
}
else if (MATCH (token, "OutputFirstLine:"))
{
token2 = GET_LINE_TOKEN (NULL);
CHECK_TOKEN ();
strcpy (output_first_line, token2);
}
else if (MATCH (token, "PageLabelFormat:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
strcpy (page_label_format_buf, token2);
page_label_format = page_label_format_buf;
}
else if (MATCH (token, "PagePrefeed:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
page_prefeed = atoi (token2);
}
else if (MATCH (token, "PostScriptLevel:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
pslevel = atoi (token2);
}
else if (MATCH (token, "Printer:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
strcpy (printer_buf, token2);
printer = printer_buf;
}
else if (MATCH (token, "QueueParam:"))
{
token2 = GET_LINE_TOKEN (NULL);
CHECK_TOKEN ();
strcpy (queue_param, token2);
}
else if (MATCH (token, "SetPageDevice:"))
{
token2 = GET_LINE_TOKEN (NULL);
CHECK_TOKEN ();
parse_key_value_pair (pagedevice, token2);
}
else if (MATCH (token, "Spooler:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
strcpy (spooler_command, token2);
}
else if (MATCH (token, "StatesColorModel:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
strcpy (states_color_model, token2);
}
else if (MATCH (token, "StatesConfigFile:"))
{
token2 = GET_LINE_TOKEN (NULL);
CHECK_TOKEN ();
strcpy (states_config_file, token2);
}
else if (MATCH (token, "StatesHighlightLevel:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
strcpy (states_highlight_level, token2);
}
else if (MATCH (token, "StatesPath:"))
{
token2 = GET_LINE_TOKEN (NULL);
CHECK_TOKEN ();
strcpy (states_path, token2);
}
else if (MATCH (token, "StatusDict:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
parse_key_value_pair (statusdict, token2);
}
else if (MATCH (token, "TOCFormat:"))
{
token2 = GET_LINE_TOKEN (NULL);
CHECK_TOKEN ();
toc_fmt_string = xstrdup (token2);
}
else if (MATCH (token, "Underlay:"))
{
token2 = GET_LINE_TOKEN (NULL);
CHECK_TOKEN ();
underlay = xmalloc (strlen (token2) + 1);
strcpy (underlay, token2);
}
else if (MATCH (token, "UnderlayAngle:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
ul_angle = atof (token2);
ul_angle_p = 1;
}
else if (MATCH (token, "UnderlayFont:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
if (!parse_font_spec (token2, &ul_font, &ul_ptsize))
CFG_FATAL ((stderr, _("malformed font spec: %s"), token2));
}
else if (MATCH (token, "UnderlayGray:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
ul_gray = atof (token2);
}
else if (MATCH (token, "UnderlayPosition:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
strcpy (ul_position_buf, token2);
ul_position = ul_position_buf;
ul_position_p = 1;
}
else if (MATCH (token, "UnderlayStyle:"))
{
token2 = GET_TOKEN (NULL);
CHECK_TOKEN ();
strcpy (ul_style_str_buf, token2);
ul_style_str = ul_style_str_buf;
}
else
CFG_FATAL ((stderr, _("illegal option: %s"), token));
}
return 1;
}
void
add_media (char *name, int w, int h, int llx, int lly, int urx, int ury)
{
MediaEntry *entry;
MESSAGE (2,
(stderr,
"add_media: name=%s, w=%d, h=%d, llx=%d, lly=%d, urx=%d, ury=%d\n",
name, w, h, llx, lly, urx, ury));
entry = xcalloc (1, sizeof (*entry));
entry->name = xmalloc (strlen (name) + 1);
strcpy (entry->name, name);
entry->w = w;
entry->h = h;
entry->llx = llx;
entry->lly = lly;
entry->urx = urx;
entry->ury = ury;
entry->next = media_names;
media_names = entry;
}
void
do_list_missing_characters (int *array)
{
int i;
int count = 0;
for (i = 0; i < 256; i++)
if (array[i])
{
fprintf (stderr, "%3d ", i);
count++;
if (count % 15 == 0)
fprintf (stderr, "\n");
}
if (count % 15 != 0)
fprintf (stderr, "\n");
}
int
file_existsp (char *name, char *suffix)
{
FileLookupCtx ctx;
strcpy (ctx.name, name);
strcpy (ctx.suffix, suffix ? suffix : "");
return pathwalk (libpath, file_lookup, &ctx);
}
int
paste_file (char *name, char *suffix)
{
char buf[512];
char resources[512];
FILE *fp;
FileLookupCtx ctx;
int pending_comment = 0;
int line = 0;
strcpy (ctx.name, name);
strcpy (ctx.suffix, suffix ? suffix : "");
if (!pathwalk (libpath, file_lookup, &ctx))
return 0;
fp = fopen (ctx.fullname, "r");
if (fp == NULL)
return 0;
#define HDR_TAG "% -- code follows this line --"
while ((fgets (buf, sizeof (buf), fp)))
{
line++;
if (strncmp (buf, HDR_TAG, strlen (HDR_TAG)) == 0)
break;
}
while ((fgets (buf, sizeof (buf), fp)))
{
line++;
#define RESOURCE_DSC "%%DocumentNeededResources:"
#define CONT_DSC "%%+"
if (strncmp (buf, RESOURCE_DSC, strlen (RESOURCE_DSC)) == 0)
{
char *cp, *cp2;
strcpy (resources, buf + strlen (RESOURCE_DSC));
pending_comment = 1;
parse_resources:
cp = GET_TOKEN (resources);
if (cp == NULL)
continue;
if (MATCH (cp, "font"))
{
for (cp = GET_TOKEN (NULL); cp; cp = GET_TOKEN (NULL))
if (!strhash_get (res_fonts, cp, strlen (cp) + 1,
(void **) &cp2))
{
fprintf (ofp, "%%%%IncludeResource: font %s\n", cp);
strhash_put (res_fonts, cp, strlen (cp) + 1, NULL, NULL);
}
continue;
}
else
continue;
}
else if (pending_comment
&& strncmp (buf, CONT_DSC, strlen (CONT_DSC)) == 0)
{
strcpy (resources, buf + strlen (CONT_DSC));
goto parse_resources;
}
else
pending_comment = 0;
#define DIRECTIVE_FORMAT "%Format:"
if (strncmp (buf, DIRECTIVE_FORMAT, strlen (DIRECTIVE_FORMAT)) == 0)
{
int i, j;
char name[256];
char *cp, *cp2;
errno = 0;
for (i = strlen (DIRECTIVE_FORMAT); buf[i] && isspace (buf[i]); i++)
;
if (!buf[i])
FATAL ((stderr, _("%s:%d: %%Format: no name"), ctx.fullname,
line));
for (j = 0;
j < sizeof (name) - 1 && buf[i] && !isspace (buf[i]);
i++)
name[j++] = buf[i];
name[j] = '\0';
if (j >= sizeof (name) - 1)
FATAL ((stderr, _("%s:%d: %%Format: too long name, maxlen=%d"),
ctx.fullname, line, sizeof (name) - 1));
for (; buf[i] && isspace (buf[i]); i++)
;
j = strlen (buf);
for (j--; isspace (buf[j]) && j > i; j--)
;
j++;
MESSAGE (2, (stderr, "%%Format: %s %.*s\n", name, j - i, buf + i));
cp = xmalloc (j - i + 1);
memcpy (cp, buf + i, j - i);
cp[j - i] = '\0';
strhash_put (user_strings, name, strlen (name) + 1, cp,
(void **) &cp2);
if (cp2)
FATAL ((stderr,
_("%s:%d: %%Format: name \"%s\" is already defined"),
ctx.fullname, line, name));
continue;
}
#define DIRECTIVE_HEADERHEIGHT "%HeaderHeight:"
if (strncmp (buf, DIRECTIVE_HEADERHEIGHT,
strlen (DIRECTIVE_HEADERHEIGHT)) == 0)
{
int i;
for (i = strlen (DIRECTIVE_HEADERHEIGHT);
buf[i] && !isspace (buf[i]); i++)
;
if (!buf[i])
FATAL ((stderr, _("%s:%d: %%HeaderHeight: no argument"),
ctx.fullname, line));
d_header_h = atoi (buf + i);
MESSAGE (2, (stderr, "%%HeaderHeight: %d\n", d_header_h));
continue;
}
#define DIRECTIVE_FOOTERHEIGHT "%FooterHeight:"
if (strncmp (buf, DIRECTIVE_FOOTERHEIGHT,
strlen (DIRECTIVE_FOOTERHEIGHT)) == 0)
{
int i;
for (i = strlen (DIRECTIVE_FOOTERHEIGHT);
buf[i] && !isspace (buf[i]); i++)
;
if (!buf[i])
FATAL ((stderr, _("%s:%d: %%FooterHeight: no argument"),
ctx.fullname, line));
d_footer_h = atoi (buf + i);
MESSAGE (2, (stderr, "%%FooterHeight: %d\n", d_footer_h));
continue;
}
fputs (buf, ofp);
}
fclose (fp);
return 1;
}
int
parse_font_spec (char *spec, char **name_return, FontPoint *size_return)
{
int i;
char *cp, *cp2;
cp = strchr (spec, '@');
if (cp)
{
i = cp - spec;
if (cp[1] == '\0')
return 0;
cp++;
cp2 = strchr (cp, '/');
if (cp2)
{
*cp2++ = '\0';
size_return->w = atof (cp);
size_return->h = atof (cp2);
}
else
size_return->w = size_return->h = atof (cp);
}
else
{
i = strlen (spec) - 1;
if (i <= 0 || !ISNUMBERDIGIT (spec[i]))
return 0;
for (i--; i >= 0 && ISNUMBERDIGIT (spec[i]); i--)
;
if (i < 0)
return 0;
if (spec[i] == '/')
{
size_return->h = atof (spec + i + 1);
for (i--; i >= 0 && ISNUMBERDIGIT (spec[i]); i--)
;
if (i < 0)
return 0;
i++;
size_return->w = atof (spec + i);
}
else
{
i++;
size_return->w = size_return->h = atof (spec + i);
}
}
*name_return = (char *) xcalloc (1, i + 1);
strncpy (*name_return, spec, i);
MESSAGE (2, (stderr, "parse_font_spec(): name=%.*s, size=%g/%g\n", i,
*name_return, size_return->w, size_return->h));
if (size_return->w < 0.0 && size_return->h < 0.0)
MESSAGE (0, (stderr, _("%s: warning: font size is negative\n"), program));
else if (size_return->w < 0.0)
MESSAGE (0, (stderr, _("%s: warning: font width is negative\n"), program));
else if (size_return->h < 0.0)
MESSAGE (0, (stderr, _("%s: warning: font height is negative\n"),
program));
return 1;
}
void
read_font_info (void)
{
CachedFontInfo *font_info;
AFMFont font;
int font_info_cached = 1;
int font_cached = 1;
int i;
unsigned int enc_flags = 0;
char fkey[256];
MESSAGE (2, (stderr, _("reading AFM info for font \"%s\"\n"), Fname));
if (accept_composites)
enc_flags = AFM_ENCODE_ACCEPT_COMPOSITES;
sprintf (fkey, "%s@%f", Fname, Fpt.w);
if (!strhash_get (afm_info_cache, fkey, strlen (fkey), (void **) &font_info))
{
AFMError error;
char buf[256];
if (!strhash_get (afm_cache, Fname, strlen (Fname), (void **) &font))
{
error = afm_open_font (afm, AFM_I_COMPOSITES, Fname, &font);
if (error != AFM_SUCCESS)
{
#define COUR "Courier"
if (strncmp (Fname, COUR, strlen (COUR)) != 0)
MESSAGE (0,
(stderr,
_("couldn't open AFM file for font \"%s\", using default\n"),
Fname));
error = afm_open_default_font (afm, &font);
if (error != AFM_SUCCESS)
{
afm_error_to_string (error, buf);
FATAL ((stderr,
_("couldn't open AFM file for the default font: %s"),
buf));
}
}
switch (encoding)
{
case ENC_ISO_8859_1:
(void) afm_font_encoding (font, AFM_ENCODING_ISO_8859_1,
enc_flags);
break;
case ENC_ISO_8859_2:
(void) afm_font_encoding (font, AFM_ENCODING_ISO_8859_2,
enc_flags);
break;
case ENC_ISO_8859_3:
(void) afm_font_encoding (font, AFM_ENCODING_ISO_8859_3,
enc_flags);
break;
case ENC_ISO_8859_4:
(void) afm_font_encoding (font, AFM_ENCODING_ISO_8859_4,
enc_flags);
break;
case ENC_ISO_8859_5:
(void) afm_font_encoding (font, AFM_ENCODING_ISO_8859_5,
enc_flags);
break;
case ENC_ISO_8859_7:
(void) afm_font_encoding (font, AFM_ENCODING_ISO_8859_7,
enc_flags);
break;
case ENC_ASCII:
(void) afm_font_encoding (font, AFM_ENCODING_ASCII, enc_flags);
break;
case ENC_ASCII_FISE:
(void) afm_font_encoding (font, AFM_ENCODING_ASCII, enc_flags);
for (i = 0; enc_7bit_ascii_fise[i].name; i++)
(void) afm_font_encode (font, enc_7bit_ascii_fise[i].code,
enc_7bit_ascii_fise[i].name,
enc_flags);
break;
case ENC_ASCII_DKNO:
(void) afm_font_encoding (font, AFM_ENCODING_ASCII, enc_flags);
for (i = 0; enc_7bit_ascii_dkno[i].name; i++)
(void) afm_font_encode (font, enc_7bit_ascii_dkno[i].code,
enc_7bit_ascii_dkno[i].name,
enc_flags);
break;
case ENC_IBMPC:
(void) afm_font_encoding (font, AFM_ENCODING_IBMPC, enc_flags);
break;
case ENC_MAC:
(void) afm_font_encoding (font, AFM_ENCODING_MAC, enc_flags);
break;
case ENC_VMS:
(void) afm_font_encoding (font, AFM_ENCODING_VMS, enc_flags);
break;
case ENC_HP8:
(void) afm_font_encoding (font, AFM_ENCODING_HP8, enc_flags);
break;
case ENC_KOI8:
(void) afm_font_encoding (font, AFM_ENCODING_KOI8, enc_flags);
break;
case ENC_PS:
break;
}
if (!strhash_put (afm_cache, Fname, strlen (Fname), font, NULL))
font_cached = 0;
}
font_info = (CachedFontInfo *) xcalloc (1, sizeof (*font_info));
for (i = 0; i < 256; i++)
{
AFMNumber w0x, w0y;
(void) afm_font_charwidth (font, Fpt.w, i, &w0x, &w0y);
font_info->font_widths[i] = w0x;
if (font->encoding[i] == AFM_ENC_NONE)
font_info->font_ctype[i] = ' ';
else if (font->encoding[i] == AFM_ENC_NON_EXISTENT)
font_info->font_ctype[i] = '.';
else
font_info->font_ctype[i] = '*';
}
font_info->font_is_fixed
= font->writing_direction_metrics[0].IsFixedPitch;
font_info->font_bbox_lly = font->global_info.FontBBox_lly;
if (!font_cached)
(void) afm_close_font (font);
if (!strhash_put (afm_info_cache, fkey, strlen (fkey), font_info, NULL))
font_info_cached = 0;
}
memcpy (font_widths, font_info->font_widths, 256 * sizeof (double));
memcpy (font_ctype, font_info->font_ctype, 256);
font_is_fixed = font_info->font_is_fixed;
font_bbox_lly = font_info->font_bbox_lly;
if (!font_info_cached)
xfree (font_info);
}
void
download_font (char *name)
{
AFMError error;
const char *prefix;
struct stat stat_st;
char fname[512];
unsigned char buf[4096];
FILE *fp;
int i;
char *cp;
error = afm_font_prefix (afm, name, &prefix);
if (error != AFM_SUCCESS)
return;
sprintf (fname, "%s.pfa", prefix);
if (stat (fname, &stat_st) != 0)
{
sprintf (fname, "%s.pfb", prefix);
if (stat (fname, &stat_st) != 0)
return;
}
MESSAGE (1, (stderr, _("downloading font \"%s\"\n"), name));
fp = fopen (fname, "rb");
if (fp == NULL)
{
MESSAGE (0, (stderr,
_("couldn't open font description file \"%s\": %s\n"),
fname, strerror (errno)));
return;
}
fprintf (ofp, "%%%%BeginResource: font %s\n", name);
i = fgetc (fp);
if (i == EOF)
{
;
}
else if (i == 128)
{
int done = 0;
unsigned int chunk;
unsigned int to_read;
int last_was_cr;
int j;
ungetc (i, fp);
while (!done)
{
i = fread (buf, 1, 6, fp);
if (i != 6)
break;
chunk = buf[2] | (buf[3] << 8) | (buf[4] << 16) | (buf[5] << 24);
switch (buf[1])
{
case 1:
last_was_cr = 0;
while (chunk > 0)
{
to_read = sizeof (buf) < chunk ? sizeof (buf) : chunk;
i = fread (buf, 1, to_read, fp);
if (i == 0)
{
done = 1;
break;
}
for (j = 0; j < i; j++)
{
if (j == 0 && last_was_cr && buf[0] != '\n')
{
fputc ('\n', ofp);
fputc (buf[0], ofp);
}
else if (buf[j] == '\r' && j + 1 < i
&& buf[j + 1] != '\n')
{
fputc ('\n', ofp);
}
else if (buf[j] != '\r')
fputc (buf[j], ofp);
}
chunk -= i;
last_was_cr = (buf[i - 1] == '\r');
}
break;
case 2:
while (chunk > 0)
{
to_read = sizeof (buf) < chunk ? sizeof (buf) : chunk;
i = fread (buf, 1, to_read, fp);
if (i == 0)
{
done = 1;
break;
}
for (j = 0; j < i; j++)
{
fprintf (ofp, "%02X", buf[j]);
if ((j + 1) % 32 == 0)
fprintf (ofp, "\n");
}
chunk -= i;
}
break;
case 3:
done = 1;
break;
}
fprintf (ofp, "\n");
}
}
else
{
ungetc (i, fp);
while ((i = fread (buf, 1, sizeof (buf), fp)) != 0)
fwrite (buf, 1, i, ofp);
}
fprintf (ofp, "%%%%EndResource\n");
(void) strhash_delete (res_fonts, name, strlen (name) + 1, (void **) &cp);
fclose (fp);
}
char *
escape_string (char *string)
{
int i, j;
int len;
char *cp;
for (len = 0, i = 0; string[i]; i++)
switch (string[i])
{
case '(':
case ')':
case '\\':
len += 2;
break;
default:
len++;
}
cp = xmalloc (len + 1);
for (i = 0, j = 0; string[i]; i++)
switch (string[i])
{
case '(':
case ')':
case '\\':
cp[j++] = '\\';
default:
cp[j++] = string[i];
break;
}
cp[j++] = '\0';
return cp;
}
#define NEED_NBYTES(n) \
do { \
if (rbufpos + (n) >= rbuflen) \
{ \
rbuflen += (n) + 1024; \
rbuf = xrealloc (rbuf, rbuflen); \
} \
} while (0)
#define APPEND_CH(ch) \
do { \
int a; \
NEED_NBYTES (width); \
if (width && justification < 0) \
rbuf[rbufpos++] = (ch); \
for (a = 0; a < width - 1; a++) \
rbuf[rbufpos++] = ' '; \
if (!width || justification > 0) \
rbuf[rbufpos++] = (ch); \
} while (0)
#define APPEND_STR(str) \
do { \
int len = strlen ((str)); \
int nspace; \
\
if (len > width) \
nspace = 0; \
else \
nspace = width - len; \
\
NEED_NBYTES (nspace + len); \
if (width && justification > 0) \
for (; nspace; nspace--) \
rbuf[rbufpos++] = ' '; \
\
memcpy (rbuf + rbufpos, str, len); \
rbufpos += len; \
\
if (width && justification < 0) \
for (; nspace; nspace--) \
rbuf[rbufpos++] = ' '; \
} while (0)
char *
format_user_string (char *context_name, char *str)
{
char *cp;
char *rbuf = NULL;
int rbuflen = 0;
int rbufpos = 0;
int i = 0;
int j;
char buf[512];
char buf2[512];
int width = 0;
int justification = 1;
for (i = 0; str[i] != '\0'; i++)
{
int type;
type = str[i];
if (type == '%' || type == '$')
{
i++;
width = 0;
justification = 1;
if (str[i] == '-')
{
i++;
justification = -1;
}
while (isdigit (str[i]))
width = width * 10 + str[i++] - '0';
if (type == '%')
{
switch (str[i])
{
case '%':
APPEND_CH ('%');
break;
case 'c':
getcwd (buf, sizeof (buf));
cp = strrchr (buf, '/');
if (cp)
cp++;
else
cp = buf;
APPEND_STR (cp);
break;
case 'C':
sprintf (buf, "%02d:%02d:%02d", run_tm.tm_hour,
run_tm.tm_min, run_tm.tm_sec);
APPEND_STR (buf);
break;
case 'd':
getcwd (buf, sizeof (buf));
APPEND_STR (buf);
break;
case 'D':
if (str[i + 1] == '{')
{
for (j = 0, i += 2;
j < sizeof (buf2) && str[i] && str[i] != '}';
i++, j++)
buf2[j] = str[i];
if (str[i] != '}')
FATAL ((stderr,
_("%s: too long format for %%D{} escape"),
context_name));
buf2[j] = '\0';
strftime (buf, sizeof (buf), buf2, &run_tm);
}
else
{
sprintf (buf, "%02d-%02d-%02d", run_tm.tm_year % 100,
run_tm.tm_mon + 1, run_tm.tm_mday);
}
APPEND_STR (buf);
break;
case 'E':
sprintf (buf, "%02d/%02d/%02d", run_tm.tm_year % 100,
run_tm.tm_mon + 1, run_tm.tm_mday);
APPEND_STR (buf);
break;
case 'F':
sprintf (buf, "%d.%d.%d",
run_tm.tm_mday,
run_tm.tm_mon + 1,
run_tm.tm_year + 1900);
APPEND_STR (buf);
break;
case 'H':
APPEND_STR (title);
break;
case 'm':
(void) gethostname (buf, sizeof (buf));
cp = strchr (buf, '.');
if (cp)
*cp = '\0';
APPEND_STR (buf);
break;
case 'M':
(void) gethostname (buf, sizeof (buf));
APPEND_STR (buf);
break;
case 'n':
APPEND_STR (passwd->pw_name);
break;
case 'N':
strcpy (buf, passwd->pw_gecos);
cp = strchr (buf, ',');
if (cp)
*cp = '\0';
APPEND_STR (buf);
break;
case 't':
sprintf (buf, "%d:%d%s",
run_tm.tm_hour > 12
? run_tm.tm_hour - 12 : run_tm.tm_hour,
run_tm.tm_min,
run_tm.tm_hour > 12 ? "pm" : "am");
APPEND_STR (buf);
break;
case 'T':
sprintf (buf, "%d:%d", run_tm.tm_hour, run_tm.tm_min);
APPEND_STR (buf);
break;
case '*':
sprintf (buf, "%d:%d:%d", run_tm.tm_hour, run_tm.tm_min,
run_tm.tm_sec);
APPEND_STR (buf);
break;
case 'W':
sprintf (buf, "%02d/%02d/%02d", run_tm.tm_mon + 1,
run_tm.tm_mday, run_tm.tm_year % 100);
APPEND_STR (buf);
break;
default:
FATAL ((stderr, _("%s: unknown `%%' escape `%c' (%d)"),
context_name, str[i], str[i]));
break;
}
}
else
{
switch (str[i])
{
case '$':
APPEND_CH ('$');
break;
case '%':
if (slicing)
sprintf (buf, "%d%c", current_pagenum, slice - 1 + 'A');
else
sprintf (buf, "%d", current_pagenum);
APPEND_STR (buf);
break;
case '=':
APPEND_CH ('\001');
break;
case '(':
for (j = 0, i++;
str[i] && str[i] != ')' && j < sizeof (buf) - 1;
i++)
buf[j++] = str[i];
if (str[i] == '\0')
FATAL ((stderr, _("%s: no closing ')' for $() escape"),
context_name));
if (str[i] != ')')
FATAL ((stderr, _("%s: too long variable name for $() escape"),
context_name));
buf[j] = '\0';
cp = getenv (buf);
if (cp == NULL)
cp = "";
APPEND_STR (cp);
break;
case 'C':
sprintf (buf, "%02d:%02d:%02d", mod_tm.tm_hour,
mod_tm.tm_min, mod_tm.tm_sec);
APPEND_STR (buf);
break;
case 'D':
if (str[i + 1] == '{')
{
for (j = 0, i += 2;
j < sizeof (buf2) && str[i] && str[i] != '}';
i++, j++)
buf2[j] = str[i];
if (str[i] != '}')
FATAL ((stderr,
_("%s: too long format for $D{} escape"),
context_name));
buf2[j] = '\0';
strftime (buf, sizeof (buf), buf2, &mod_tm);
}
else
{
sprintf (buf, "%02d-%02d-%02d", mod_tm.tm_year % 100,
mod_tm.tm_mon + 1, mod_tm.tm_mday);
}
APPEND_STR (buf);
break;
case 'E':
sprintf (buf, "%02d/%02d/%02d", mod_tm.tm_year % 100,
mod_tm.tm_mon + 1, mod_tm.tm_mday);
APPEND_STR (buf);
break;
case 'F':
sprintf (buf, "%d.%d.%d",
mod_tm.tm_mday,
mod_tm.tm_mon + 1,
mod_tm.tm_year + 1900);
APPEND_STR (buf);
break;
case 't':
sprintf (buf, "%d:%d%s",
mod_tm.tm_hour > 12
? mod_tm.tm_hour - 12 : mod_tm.tm_hour,
mod_tm.tm_min,
mod_tm.tm_hour > 12 ? "pm" : "am");
APPEND_STR (buf);
break;
case 'T':
sprintf (buf, "%d:%d", mod_tm.tm_hour, mod_tm.tm_min);
APPEND_STR (buf);
break;
case '*':
sprintf (buf, "%d:%d:%d", mod_tm.tm_hour, mod_tm.tm_min,
mod_tm.tm_sec);
APPEND_STR (buf);
break;
case 'v':
sprintf (buf, "%d", input_filenum);
APPEND_STR (buf);
break;
case 'V':
if (toc)
{
sprintf (buf, "%d-", input_filenum);
APPEND_STR (buf);
}
break;
case 'W':
sprintf (buf, "%02d/%02d/%02d", mod_tm.tm_mon + 1,
mod_tm.tm_mday, mod_tm.tm_year % 100);
APPEND_STR (buf);
break;
case 'N':
APPEND_STR (fname);
break;
case 'n':
cp = strrchr (fname, '/');
if (cp)
cp++;
else
cp = fname;
APPEND_STR (cp);
break;
case 'L':
sprintf (buf, "%d", current_file_linenum - 1);
APPEND_STR (buf);
break;
default:
FATAL ((stderr, _("%s: unknown `$' escape `%c' (%d)"),
context_name, str[i], str[i]));
break;
}
}
width = 0;
justification = 1;
}
else
APPEND_CH (str[i]);
}
APPEND_CH ('\0');
cp = escape_string (rbuf);
xfree (rbuf);
return cp;
}
void
parse_key_value_pair (StringHashPtr set, char *kv)
{
char *cp;
char key[256];
cp = strchr (kv, ':');
if (cp == NULL)
{
if (strhash_delete (set, kv, strlen (kv) + 1, (void **) &cp))
xfree (cp);
}
else
{
sprintf (key, "%.*s", cp - kv, kv);
strhash_put (set, key, strlen (key) + 1, xstrdup (cp + 1),
(void **) &cp);
if (cp)
xfree (cp);
}
}
int
count_key_value_set (StringHashPtr set)
{
int i = 0, got, j;
char *cp;
void *value;
for (got = strhash_get_first (set, &cp, &j, &value); got;
got = strhash_get_next (set, &cp, &j, &value))
i++;
return i;
}
int
pathwalk (char *path, PathWalkProc proc, void *context)
{
char buf[512];
char *cp;
char *cp2;
int len, i;
for (cp = path; cp; cp = strchr (cp, PATH_SEPARATOR))
{
if (cp != path)
cp++;
cp2 = strchr (cp, PATH_SEPARATOR);
if (cp2)
len = cp2 - cp;
else
len = strlen (cp);
memcpy (buf, cp, len);
buf[len] = '\0';
i = (*proc) (buf, context);
if (i != 0)
return i;
}
return 0;
}
int
file_lookup (char *path, void *context)
{
int len;
FileLookupCtx *ctx = context;
struct stat stat_st;
int i;
MESSAGE (2, (stderr, "file_lookup(): %s/%s%s\t", path, ctx->name,
ctx->suffix));
len = strlen (path);
if (len && path[len - 1] == '/')
len--;
sprintf (ctx->fullname, "%.*s/%s%s", len, path, ctx->name, ctx->suffix);
i = stat (ctx->fullname, &stat_st) == 0;
MESSAGE (2, (stderr, "#%c\n", i ? 't' : 'f'));
return i;
}
void
tilde_subst (char *from, char *to)
{
char *cp;
char user[256];
int i, j;
struct passwd *pswd;
if (from[0] != '~')
{
copy_out:
strcpy (to, from);
return;
}
if (from[1] == '/' || from[1] == '\0')
{
cp = getenv ("HOME");
if (cp == NULL)
goto copy_out;
sprintf (to, "%s%s", cp, from + 1);
return;
}
for (i = 1, j = 0; from[i] && from[i] != '/'; i++)
user[j++] = from[i];
user[j++] = '\0';
pswd = getpwnam (user);
if (pswd)
{
sprintf (to, "%s%s", pswd->pw_dir, from + i);
return;
}
goto copy_out;
}
double
parse_float (char *string, int units, int horizontal)
{
double val;
char *end;
val = strtod (string, &end);
if (end == string)
malformed_float:
ERROR ((stderr, _("malformed float dimension: \"%s\""), string));
if (units)
{
switch (*end)
{
case 'c':
val *= 72 / 2.54;
break;
case 'p':
break;
case 'i':
val *= 72;
break;
case '\0':
case 'l':
if (horizontal)
val *= CHAR_WIDTH ('m');
else
val *= LINESKIP;
break;
default:
goto malformed_float;
break;
}
}
else
{
if (*end != '\0')
goto malformed_float;
}
return val;
}
int
is_open (InputStream *is, FILE *fp, char *fname, char *input_filter)
{
is->data_in_buf = 0;
is->bufpos = 0;
is->nreads = 0;
is->unget_ch = NULL;
is->unget_pos = 0;
is->unget_alloc = 0;
if (input_filter)
{
char *cmd = NULL;
int cmdlen;
int i, pos;
is->is_pipe = 1;
if (fname == NULL)
fname = input_filter_stdin;
cmdlen = strlen (input_filter) + 1;
cmd = xmalloc (cmdlen);
pos = 0;
for (i = 0; input_filter[i]; i++)
{
if (input_filter[i] == '%')
{
switch (input_filter[i + 1])
{
case 's':
cmdlen += strlen (fname);
cmd = xrealloc (cmd, cmdlen);
strcpy (cmd + pos, fname);
pos += strlen (fname);
i++;
break;
case '%':
cmd[pos++] = '%';
i++;
break;
default:
cmd[pos++] = input_filter[i];
break;
}
}
else
cmd[pos++] = input_filter[i];
}
cmd[pos++] = '\0';
is->fp = popen (cmd, "r");
xfree (cmd);
if (is->fp == NULL)
{
ERROR ((stderr,
_("couldn't open input filter \"%s\" for file \"%s\": %s"),
input_filter, fname ? fname : "(stdin)",
strerror (errno)));
return 0;
}
}
else
{
is->is_pipe = 0;
if (fp)
is->fp = fp;
else
{
is->fp = fopen (fname, "rb");
if (is->fp == NULL)
{
ERROR ((stderr, _("couldn't open input file \"%s\": %s"), fname,
strerror (errno)));
return 0;
}
}
}
return 1;
}
void
is_close (InputStream *is)
{
if (is->is_pipe)
pclose (is->fp);
else
fclose (is->fp);
if (is->unget_ch)
xfree (is->unget_ch);
}
int
is_getc (InputStream *is)
{
int ch;
if (is->unget_pos > 0)
{
ch = is->unget_ch[--is->unget_pos];
return ch;
}
retry:
if (is->bufpos >= is->data_in_buf)
{
if (is->nreads > 0 && is->data_in_buf < sizeof (is->buf))
return EOF;
is->data_in_buf = fread (is->buf, 1, sizeof (is->buf), is->fp);
is->bufpos = 0;
is->nreads++;
goto retry;
}
return is->buf[is->bufpos++];
}
int
is_ungetc (int ch, InputStream *is)
{
if (is->unget_pos >= is->unget_alloc)
{
is->unget_alloc += 1024;
is->unget_ch = xrealloc (is->unget_ch, is->unget_alloc);
}
is->unget_ch[is->unget_pos++] = ch;
return 1;
}