/*
* pstex:
*
* This is a BiBTeX-like program which
* performs figure inclusions in conjunction
* with a suitable set of macros.
*
* Neil Hunt (Neil%
[email protected]).
*
* Copyright (c) 1989 Teleos Research, Inc 1989.
*
* Anyone can use this software in any manner they choose,
* including modification and redistribution, provided they make
* no charge for it, and these conditions remain unchanged.
*
* This program is distributed as is, with all faults (if any), and
* without any wrranty. No author or distributor accepts responsibility
* to anyone for the consequences of using it, or for whether it serves any
* particular purpose at all, or any other reason.
*
* $Log: pstex.c,v $
* Revision 1.8 89/07/28 10:25:53 neil
* Added copyright and conditions notice.
*
* Revision 1.7 89/07/28 09:51:03 neil
* Cleaned up, and removed some references to spar in pathnames.
*
* Revision 1.6 89/02/10 18:40:48 neil
* Removed dependencies on newlib.
* Now uses ./std.h for standard definitions.
*
* Revision 1.5 89/01/09 13:05:05 hunt
* Updated to use a single .psz file per job rather than a .tps file
* for each included figure.
*
* Revision 1.4 88/12/20 11:52:58 hunt
* General cleanup.
*
* Revision 1.3 88/09/27 07:04:33 hunt
* Added a `%' comment char to end of postscriptbox output lines, to avoid
* additional space which is otherwise left within the psbox area.
*
* Revision 1.2 88/09/20 13:11:26 hunt
* Writes `file' instead of `file.ps' into .psz file.
*
* Revision 1.1 88/08/04 12:34:17 hunt
* Initial revision
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <varargs.h>
#include "std.h"
#include "args.h"
extern FILE * fopenp();
extern double atof();
#ifdef MSDOS
#include <process.h>
#include <stdlib.h>
#else
extern char * getenv();
#endif
#define STRSIZE 256
#ifdef MSDOS
#define DEFPSPATH ".;a:\\tex\\pslib"
#define DEFTEXINPUTS ".;a:\\tex\\inputs"
#else
#define DEFPSPATH ".:/usr/local/lib/tex/font/ps"
#define DEFTEXINPUTS ".:/usr/local/lib/tex/inputs"
#endif
char line[1000];
char * ps_path;
char * texinputs;
bool framemode = FALSE;
bool verbose = FALSE;
FILE * pszfile;
FILE * logfile;
forward bool parse();
forward bool process();
forward char * getarg();
forward bool makepszentry();
forward bool readpsfile();
forward void printerr();
forward void printlog();
int
main(argc, argv)
int argc;
char *argv[];
{
char opt;
int f;
static char auxname[STRSIZE];
static char pszname[STRSIZE];
static char logname[STRSIZE];
/*
* Read paths from environment.
*/
if((ps_path = getenv("DVIPSPATH")) == NULL)
ps_path = DEFPSPATH;
if((texinputs = getenv("TEXINPUTS")) == NULL)
texinputs = DEFTEXINPUTS;
if(getenv("FMHOME"))
framemode = TRUE;
/*
* Parse args.
*/
for(f = 0; (opt = a_next(argc, argv)) != A_END; )
{
switch(opt)
{
default:
fprintf(stderr, "%s: unrecognised option -%c\n",
a_prog_name, opt);
/* FALLTHROUGH */
case 'H':
usage:;
fprintf(stderr, "usage: %s [-z DVIPSPATH] texfile\n",
a_prog_name);
exit(1);
case 'z':
ps_path = a_arg(argc, argv);
break;
case 'f':
case 'F':
framemode = TRUE;
break;
case 'v':
verbose = TRUE;
break;
case A_ARG:
switch(f++)
{
case 0:
strcpy(auxname, a_arg(argc, argv));
strcpy(pszname, auxname);
strcpy(logname, auxname);
strcat(auxname, ".aux");
strcat(pszname, ".psz");
strcat(logname, ".plg");
break;
default:
fprintf(stderr, "%s: too many filenames: %s\n",
a_prog_name, a_arg(argc, argv));
goto usage;
}
break;
}
}
if(f != 1)
goto usage;
if((logfile = fopen(logname, "w")) == NULL)
{
fprintf(stderr, "Cant open log file %s\n", logname);
exit(-1);
}
if((pszfile = fopen(pszname, "w")) == NULL)
{
fprintf(stderr, "Cant open psz file %s\n", pszname);
exit(-1);
}
if(! parse(auxname))
exit(1);
fclose(logfile);
exit(0);
}
/*
* Recurses over \jobname.aux files.
*/
bool
parse(filename)
char *filename;
{
static int level = 0;
FILE *fp;
static char fullname[STRSIZE];
static char args[STRSIZE];
bool status = TRUE;
if((fp = fopenp(texinputs, filename, fullname, "rt")) == NULL)
{
printerr("WARNING: Cant open aux file %s\n", filename);
return FALSE;
}
else
printlog("Level %d aux file: %s\n", level++, filename);
while(fgets(line, 1000, fp))
{
if(sscanf(line, " \\@input { %[^{}] } ", args) == 1)
{
if(! parse(args))
status = FALSE;
continue;
}
if(sscanf(line, " \\psboxaux %[^\n] ", args) == 1)
{
if(! process(args))
status = FALSE;
continue;
}
}
fclose(fp);
--level;
return status;
}
/*
* Processes lines in the .aux files of the form:
* \psboxaux{option-string}{filanem}
* args is the rest of the line when psboxaux is recognised.
*/
bool
process(args)
char *args;
{
char *p, *a;
static char width[STRSIZE];
static char height[STRSIZE];
static char aspect[STRSIZE];
static char scale[STRSIZE];
static char name[STRSIZE];
width[0] = '\0';
height[0] = '\0';
aspect[0] = '\0';
scale[0] = '\0';
name[0] = '\0';
a = args;
if(*a++ != '{')
goto abort;
while(*a == ' ' || *a == '\t')
a++;
while(*a)
{
switch(*a)
{
case 'w':
a = getarg(a, width);
break;
case 'h':
a = getarg(a, height);
break;
case 'a':
a = getarg(a, aspect);
break;
case 's':
a = getarg(a, scale);
break;
case '}':
break;
default:
goto abort;
}
if(a == NULL)
goto abort;
if(*a++ == '}')
break;
}
while(*a == ' ' || *a == '\t')
a++;
if(*a++ != '{')
goto abort;
while(*a == ' ' || *a == '\t')
a++;
p = name;
while(*a && *a != '}')
*p++ = *a++;
*p = '\0';
return makepszentry(name, width, height, aspect, scale);
abort:
printerr("WARNING: Bad arguments: \\psboxaux%s\n", args);
return FALSE;
}
/*
* Returns pointer to char after end of arg.
* Arg ends with ',' ';' unmatched '}' or end of string.
* Arg is terminated with '\0'.
*/
char *
getarg(p, arg)
char *p;
char *arg;
{
int nesting;
/*
* Skip rest of `xxx = '
*/
while((*p >= 'a' && *p <= 'z') ||
(*p >= 'A' && *p <= 'Z'))
p++;
while(*p == ' ' || *p == '\t')
p++;
if(*p++ != '=')
{
printerr("WARNING: Bad psbox format syntax (no '=' found).\n");
return NULL;
}
while(*p == ' ' || *p == '\t')
p++;
/*
* Copy arg.
*/
for(nesting = 0;
*p && (nesting > 0 || (*p != ',' && *p != ';' &&*p != '}')); p++)
{
if(*p == '{')
nesting++;
else if(*p == '}')
--nesting;
*arg++ = *p;
}
*arg = '\0';
/*
* Check.
*/
if(nesting != 0)
{
printerr("WARNING: Unmatched braces in \\psboxaux command\n");
return NULL;
}
return p;
}
/*
* Creates a psz file entry for a ps figure.
* The option string has been parsed into width, height, aspect, and scale.
*/
bool
makepszentry(name, width, height, aspect, scale)
char name[];
char width[];
char height[];
char aspect[];
char scale[];
{
FILE *psfp;
static char psname[STRSIZE];
static char fullname[STRSIZE];
static char wu[STRSIZE], hu[STRSIZE];
double w, h, a, s;
double bbw, bbh;
strcpy(psname, name);
strcat(psname, ".ps");
if((psfp = fopenp(ps_path, psname, fullname, "rt")) == NULL)
{
printerr("WARNING: No file %s\n", psname);
return FALSE;
}
if(*width)
{
if(sscanf(width, "%lg%s", &w, wu) != 2)
{
w = 1.0;
strcpy(wu, width);
}
}
if(*height)
{
if(sscanf(height, "%lg%s", &h, hu) != 2)
{
h = 1.0;
strcpy(hu, height);
}
}
if(*width && *height)
{
if(*scale)
s = atof(scale);
else
s = 1.0;
fprintf(pszfile, "\\pssize{%g%s}{%g%s}{%s}%%\n",
s*w, wu, s*h, hu, name);
printlog(" \\pssize{%.4g%s}{%.4g%s}{%s}\n",
s*w, wu, s*h, hu, name);
if(*aspect)
printlog(" (aspect ignored)\n");
}
else
{
if(! readpsfile(psfp, &bbw, &bbh))
{
printerr(
"WARNING: Postscript file %s contains no %%%%BoundingBox\n",
psname);
goto abort;
}
if(*width)
{
if(*aspect)
a = atof(aspect);
else
a = bbw / bbh;
if(*scale)
s = atof(scale);
else
s = 1.0;
fprintf(pszfile, "\\pssize{%g%s}{%g%s}{%s}%%\n",
s*w, wu, s*w/a, wu, name);
printlog(" \\pssize{%.4g%s}{%.4g%s}{%s}\n",
s*w, wu, s*w/a, wu, name);
}
else if(*height)
{
if(*aspect)
a = atof(aspect);
else
a = bbw / bbh;
if(*scale)
s = atof(scale);
else
s = 1.0;
fprintf(pszfile, "\\pssize{%g%s}{%g%s}{%s}%%\n",
s*h*a, hu, s*h, hu, name);
printlog(" \\pssize{%.4g%s}{%.4g%s}{%s}\n",
s*h*a, hu, s*h, hu, name);
}
else
{
if(*scale)
s = atof(scale);
else
s = 1.0;
fprintf(pszfile, "\\pssize{%gin}{%gin}{%s}%%\n",
s * bbw/72.0, s * bbh/72.0, name);
printlog(" \\pssize{%.4gin}{%.4gin}{%s}\n",
s*bbw/72.0, s*bbh/72.0, name);
if(*aspect)
printlog(" (aspect ignored)\n");
}
}
fclose(psfp);
return TRUE;
abort:
fclose(psfp);
return FALSE;
}
/*
* Reads the .ps file
* to obtain the bounding box data.
*/
bool
readpsfile(psfp, wp, hp)
FILE *psfp;
double *wp;
double *hp;
{
char line[1000];
double x1, y1, x2, y2;
char dummy[100];
while(fgets(line, 1000, psfp))
{
if(sscanf(line, " %%%% BoundingBox : %lf %lf %lf %lf",
&x1, &y1, &x2, &y2) == 4)
{
*wp = Abs(x2 - x1);
*hp = Abs(y2 - y1);
return TRUE;
}
if(framemode && sscanf(line, " %lf %lf %lf %lf %[C] ",
&x1, &y1, &x2, &y2, &dummy[0]) == 5)
{
*wp = Abs(x2 - x1);
*hp = Abs(y2 - y1);
return TRUE;
}
}
return FALSE;
}
void
printerr(fmt, va_alist)
char *fmt;
va_dcl
{
va_list ap;
va_start(ap);
{
vfprintf(logfile, fmt, ap);
vfprintf(stderr, fmt, ap);
}
va_end(ap);
}
void
printlog(fmt, va_alist)
char *fmt;
va_dcl
{
va_list ap;
va_start(ap);
{
vfprintf(logfile, fmt, ap);
if(verbose)
vfprintf(stdout, fmt, ap);
}
va_end(ap);
}