|
|
BSD 4.3
/*
* maharani - a czarina-like program that generates interpress files
*
* Written for Xerox Corporation by William LeFebvre
*
* Copyright (c) 1984, 1985 Xerox Corporation
*
* HISTORY
* 13-Jan-86 lee at Xerox, WRC
* Changed a call to strcpyn to strncpy.
*
* 8-apr-85 ed flint conditional compilation for vax11-c (vms)
* 26-mar-85 ed @ Xerox, WRC
* add fclose after do_file to prevent running out of open file descriptors
*/
#ifdef vax11c
# include stdio
# include ssdef
# include ctype
# include descrip
#else
# include <stdio.h>
# include <pwd.h>
# include <strings.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/time.h>
#endif
# include "iptokens.h"
# include "literal.h"
# include "operator.h"
# define QIP "qip"
# define Break_size 1024
# define Default_universal_prefix "Xerox/XC1-1-1/"
# define Line_size 128
/* All page boundaries are computed in the 1/10 point co-ordinate system */
/*
* Orig_y is an offset from the top of the page. It must be converted
* to a measurement from the bottom of the page (a calculation that is
* rotation-dependent).
*/
# define INCH 720
# define Half_INCH 360
# define Sixth_INCH 120 /* one line at 6 lpi */
# define Page_width (8 * INCH + Half_INCH)
# define Page_length (11 * INCH)
# define Orig_x (9 * INCH / 10)
# define Orig_y (Sixth_INCH * 5)
# define Header_to_orig_x 0
# define Header_to_orig_y (2 * Sixth_INCH)
/* Frame variable defines */
# define F_transform 0
# define F_headfont 1
# define F_bodyfont 2
# define F_italicfont 3
# define No 0
# define Yes 1
extern int errno;
/* enum, perhaps? */
typedef char boolean;
/* routines that return something other than int */
char *strecpy();
char *allocate();
char *next_arg();
char *sbrk();
char *getenv();
char *itoa();
char *rindex();
/* option flags */
boolean lflg = No; /* line printer mode */
boolean rflg = No; /* rotation - landscape mode */
boolean tflg = No; /* omit title */
/* valued options */
int columns = 1;
char *bodyfont_name = "Vintage-Printwheel/10";
char *headfont_name = "Modern-Bold/12";
char *italicfont_name = "Modern-Bold-Italic/12";
char *banner = NULL;
char *copies = "1";
char *header = "%f %t Page %p, line %l";
char *name = NULL;
char *output = NULL;
char *pages = NULL;
#ifdef vax11c
char *template = "IPPXXXXXX";
#endif
/*
* page characteristics: these variables define the extremes for the
* current page or column. 'column_separation' is the distance between
* the left sides of each column on the page.
*/
int left_margin = Orig_x;
int right_margin;
int top_margin;
int bottom_margin;
int column_separation;
/* sundries */
boolean send_to_printer = Yes;
char real_header[256]; /* header built here */
char *myname; /* name invoked with */
char *filename;
int *page_select = NULL; /* array of page selections */
int *curr_page_select;
int page_low;
int page_high;
int ipress_file; /* interpress file descriptor */
int null_file; /* fd for /dev/null */
int line_number;
int page_number;
int pages_printed = 0; /* total pages for this interpress file */
int special_font = 0; /* fonts that require special handling */
int line_spacing;
int tab_amount = 8;
#ifndef vax11c
struct passwd *pwd; /* passwd entry for this user */
struct stat file_stat; /* stat of current file */
#endif
# define Font_Terminal 1
/* current arguments */
int argc;
char **argv;
/* font structure definition */
struct font
{
char *ft_universal_name;
char *ft_leaf_name;
int ft_size;
};
/* fonts used */
struct font headfont;
struct font bodyfont;
struct font italicfont;
main(_argc, _argv)
int _argc;
char **_argv;
{
char *ptr; /* temporary pointers used for loops and such */
char *src;
char *dest;
int length;
int i;
FILE *file; /* file currently processing */
#ifdef vax11c
int error;
int retlen;
char command[256];
$DESCRIPTOR(mahadesc,"MAHAENV");
$DESCRIPTOR(cmddesc,command);
#endif
/* get our name */
if (_argc < 1)
{
exit(1);
}
#ifdef vax11c
myname= _argv[0];
#else
if ((myname = rindex(_argv[0], '/')) == NULL)
{
myname = _argv[0];
}
else
{
myname++;
}
#endif
/* get the options specified in the environment (defaults) */
#ifdef vax11c
if ( (error= lib$get_symbol(&mahadesc,&cmddesc,&retlen)) == SS$_NORMAL )
{
if ( retlen != 0 )
{
command[retlen & 0xff]= '\0'; /* null terminate string */
src= command;
/* break the string up into null terminated arguments */
/* half the length is a good upper bound on number of arguments */
argv = (char **)allocate(strlen(src) / 2);
for (argc = 1, ptr = src; *ptr != '\0'; argc++)
{
while (*ptr == ' ')
ptr++;
argv[argc] = ptr;
while (*ptr != ' ' && *ptr != '\0')
{
if (*ptr == '"')
{
while (*++ptr != '"' && *ptr != '\0');
}
else if (*ptr == '\'')
{
while (*++ptr != '\'' && *ptr != '\0');
}
ptr++;
}
*ptr++ = '\0';
}
/* terminate the argument list */
argv[argc] = NULL;
/* process the options found in the environment */
get_options();
}
}
#else
if ((src = getenv("MAHA")) != NULL)
{
/* break the string up into null terminated arguments */
/* half the length is a good upper bound on number of arguments */
argv = (char **)allocate(strlen(src) / 2);
for (argc = 1, ptr = src; *ptr != '\0'; argc++)
{
while (*ptr == ' ')
ptr++;
argv[argc] = ptr;
while (*ptr != ' ' && *ptr != '\0')
{
if (*ptr == '"')
{
while (*++ptr != '"' && *ptr != '\0');
}
else if (*ptr == '\'')
{
while (*++ptr != '\'' && *ptr != '\0');
}
ptr++;
}
*ptr++ = '\0';
}
/* terminate the argument list */
argv[argc] = NULL;
/* process the options found in the environment */
get_options();
}
#endif
/* use the real arguments */
argc = _argc;
argv = _argv;
/* process (real) arguments */
get_options();
/* establish and verify the requested fonts */
establish_font(headfont_name, &headfont);
establish_font(bodyfont_name, &bodyfont);
establish_font(italicfont_name, &italicfont);
#ifndef vax11c
/* get passwd entry for future reference */
pwd = getpwuid(geteuid());
#endif
/* setup output file */
if (output == NULL)
{
/* build a temporary file name */
#ifdef vax11c
output= mktemp(template);
#else
output = allocate(1 + 5 + 1 + 2 + 1);
(void) sprintf(output, "/tmp/@%d.ip", getpid());
#endif
}
#ifdef vax11c
if ((ipress_file = creat(output, 0, "rfm=udf")) == -1)
#else
if ((ipress_file = creat(output, 0666)) == -1)
#endif
{
system_error(output);
exit(1);
}
ip_select(ipress_file);
#ifndef vax11c
/* open the null device for throwing away output */
null_file = open("/dev/null", 1);
/* set null strings to default values */
if (name == NULL)
{
/* banner name defaults to full name from gecos field */
name = pwd->pw_gecos;
/* perform expansion and stripping */
if ((ptr = index(name, ',')) != NULL)
{
*ptr = '\0'; /* this affects pwd->pw_gecos, too! */
}
if (index(name, '&') != NULL)
{
name = allocate(strlen(name) + strlen(pwd->pw_name) + 1);
for (src = pwd->pw_gecos, dest = name; *src != '\0'; src++, dest++)
{
if (*src == '&')
{
for (ptr = pwd->pw_name; *ptr != '\0'; ptr++)
{
*dest++ = *ptr;
}
}
else
{
*dest = *src;
}
}
}
}
#endif
if (banner == NULL)
{
/* banner defaults to file name(s) */
if (argc == 0)
{
banner = "out of the blue";
}
else
{
for (length = 0, i = 0; i < argc; i++)
{
length += strlen(argv[i]) + 2;
}
banner = allocate(length + 1);
for (ptr = banner, i = 0; i < argc; i++)
{
ptr = strecpy(ptr, argv[i]);
ptr = strecpy(ptr, ", ");
}
ptr -= 2;
*ptr = '\0';
}
}
/* unravel the page specifiation */
/* we will never need more than strlen(pages) ints to hold the info */
if (pages != NULL)
{
page_select = (int *)allocate(strlen(pages) * sizeof(int));
unravel_pages(pages, page_select);
}
/* write the preamble for the interpress file */
Op(beginBlock);
Op(beginBody); /* preamble start */
/* setup font definitions in frame */
SetupFont(headfont.ft_universal_name,
headfont.ft_size * 10.,
F_headfont);
SetupFont(bodyfont.ft_universal_name,
bodyfont.ft_size * 10.,
F_bodyfont);
SetupFont(italicfont.ft_universal_name,
headfont.ft_size * 10., /* use headfont's size */
F_italicfont);
/* remember special fonts */
if (strcmp(bodyfont.ft_leaf_name, "Terminal") == 0)
{
special_font = Font_Terminal;
}
/* save scaling transform that uses 1/10 point co-ordinate system */
top_margin = (rflg ? Page_width : Page_length) - Orig_y;
bottom_margin = 2 * Sixth_INCH;
right_margin = (rflg ? Page_length : Page_width) - Orig_x;
column_separation = (right_margin - Orig_x) / columns;
line_spacing = (bodyfont.ft_size + 2) * 10;
if (rflg)
{
/* we need a rotation transform, too */
Rotate(90.);
Translate((double)Page_width, (double)0);
}
AppendRational(353L,10000000L);
Op(scale);
if (rflg)
{
Op(concat);
Op(concat);
}
AppendInteger((long) F_transform);
Op(fset);
Op(endBody); /* end preamble */
if (argc == 0)
{
/* no filenames -- do standard input */
filename = NULL;
do_file(stdin);
}
for (; argc > 0; argc--, argv++)
{
filename = argv[0];
if (strcmp(filename, "-") == 0)
{
/* this is really standard input */
filename = NULL;
do_file(stdin);
}
else
{
/* open the file */
if ((file = fopen(filename, "r")) == NULL)
{
system_error(filename);
}
else
{
do_file(file);
(void) fclose(file);
}
}
}
/* wrap up the output */
ip_select(ipress_file);
Op(endBlock);
ip_close();
/* send to the printer */
if (send_to_printer)
{
if (pages_printed == 0)
{
/* don't print anything but remove temporary */
#ifdef vax11c
delete(output);
#else
(void) unlink(output);
#endif
}
else
{
#ifdef vax11c
char buff[256];
int wait= 0;
$DESCRIPTOR(buffdesc,buff);
(void) strcpy(buff,"xpress/noformat ");
(void) strcat(buff,output);
buffdesc.dsc$w_length= strlen(buff);
if ( (error= lib$spawn(&buffdesc,0,0,&wait)) != SS$_NORMAL )
{
fprintf(stderr,"\nFile %s contains interpress master\n",output);
exit(error);
}
delete(output);
#else
char *buff;
/* exec a "qip" to queue the file */
buff = allocate(strlen(name) + 1 + 1);
(void) strcpy(buff, "F");
(void) strcat(buff, name);
execl(QIP, "qip", "-c", copies, "-nc", "-nk",
"-t", banner, "-x", buff, output, 0);
perror(QIP);
fprintf(stderr, "File %s contains interpress master.\n", output);
#endif
}
}
}
get_options()
{
while (--argc > 0)
{
argv++;
if (!process_arg())
{
break;
}
}
}
/*
* unravel_pages(str, spec) - unravel the page range specification in "str"
* into integer pairs in "spec". The first two
* ints in "spec" bound the first range of pages,
* the next two bound the second range, and so on.
* The array is terminated with the pair 0, 0.
*/
unravel_pages(str, spec)
char *str;
int *spec;
{
int last_num = 0;
int this_num = 0;
register char ch;
boolean is_range = No;
boolean bad_spec = No;
boolean done = No;
# define Start_new_num (last_num = this_num, this_num = 0)
while (!done)
{
if ((ch = *str++) == '\0')
{
/* set "done" flag and pretend it's the end of a number */
done = Yes;
ch = ',';
}
if (ch >= '0' && ch <= '9')
{
this_num *= 10;
this_num += ch - '0';
}
else if (ch == '-')
{
if (this_num < last_num && *str != '\0')
{
bad_spec = Yes;
}
*spec++ = this_num;
Start_new_num;
is_range = Yes;
}
else if (ch == ',')
{
if (this_num < last_num)
{
bad_spec = Yes;
}
*spec++ = this_num;
if (is_range)
{
is_range = No;
}
else
{
*spec++ = this_num;
}
Start_new_num;
}
else
{
fprintf(stderr, "%s: bad character in page specification\n",
myname);
exit(1);
}
}
if (*--spec == 0)
{
*spec = 1 << 15; /* infinity */
}
if (bad_spec)
{
fprintf(stderr,
"%s: pages should be given in non-descending order.\n",
myname);
}
}
process_arg()
{
register char ch;
register int temp;
register char *p1;
register char *p2;
if (argv[0][0] == '-')
{
if ((ch = argv[0][1]) > '0' && ch <= '9')
{
/* this is a column count specifier */
columns = ch - '0';
}
else switch(ch)
{
case '\0': /* not an option */
return(No);
case 'b':
banner = next_arg();
break;
case 'c':
temp = atoi(copies = next_arg());
if (temp < 1)
{
fprintf(stderr,
"%s: bogus number of copies; you only get one!\n",
myname);
copies = "1";
}
break;
case 'f':
bodyfont_name = next_arg();
break;
case 'F':
headfont_name = next_arg();
break;
case 'H': /* replace header */
header = next_arg();
break;
case 'h': /* append to header */
p1 = next_arg();
p2 = allocate(strlen(header) + strlen(p1) + 1);
(void) strcpy(p2, header);
(void) strcat(p2, " ");
(void) strcat(p2, p1);
header = p2;
break;
case 'l':
tflg = lflg = Yes;
break;
case 'n':
name = next_arg();
break;
case 'o':
output = next_arg();
send_to_printer = No;
break;
case 'r':
rflg = Yes;
break;
case 'R':
rflg = No;
break;
case 's':
pages = next_arg();
break;
case 't':
tflg = Yes;
break;
default:
fprintf(stderr, "%s: unknown option '%c'\n", myname, ch);
}
return(Yes);
}
else
{
return(No);
}
}
char *next_arg()
{
if (argv[0][2] == '\0')
{
if (--argc > 0)
{
return((++argv)[0]);
}
else
{
argv++;
return(NULL);
}
}
else
{
return(&(argv[0][2]));
}
}
/*
* establish_font(name, font) - break apart the parts of the string "name"
* and fill in the structure pointed to by
* "font". Also, verify that the font requested
* actually exists. This routine also
* understands universal font names.
*/
establish_font(name, font)
char *name;
struct font *font;
{
register char *unamep;
register char *ptr;
char *slashp;
register int size;
if (name[0] != '/')
{
/* not a universal name -- put the default on the front */
font->ft_universal_name = unamep =
allocate(strlen(Default_universal_prefix) +
strlen(name) + 1);
(void) strcpy(unamep, Default_universal_prefix);
(void) strcat(unamep, name);
}
else
{
/* already is a universal name -- just allocate space for it */
font->ft_universal_name = unamep = allocate(strlen(name));
/* copy in the whole name, without the leading slash */
(void) strcpy(unamep, name + 1);
}
/* strip size off the end, if it is there */
if ((slashp = ptr = rindex(unamep, '/')) != NULL)
{
register char ch;
size = 0;
while ((ch = *++ptr) != '\0')
{
if (ch < '0' || ch > '9')
{
/* last element is not a number -- no point size */
size = 0;
break;
}
/* shift this digit in */
size *= 10;
size += (ch - '0');
}
/* if no point size, use default */
if (size == 0)
{
font->ft_size = 10;
}
else
{
font->ft_size = size;
*slashp = '\0';
}
}
/* set pointer to last element */
if ((ptr = rindex(unamep, '/')) != NULL)
{
font->ft_leaf_name = ptr + 1;
}
else
{
font->ft_leaf_name = font->ft_universal_name;
}
}
do_file(file)
FILE *file;
{
char *src;
char *dest;
char input_line[Line_size];
char line_buffer[Line_size];
char ch;
int current_line;
int lines_on_page;
int length;
int column;
#ifndef vax11c
/* fstat it to get information displayed in the header */
if (fstat(fileno(file), &file_stat) == -1)
{
system_error("fstat botched");
return;
}
#endif
/* reset essentials */
page_number = 0;
line_number = 1;
lines_on_page = 0;
curr_page_select = page_select;
if (pages != NULL)
{
page_low = page_select[0];
page_high = page_select[1];
}
current_line = top_margin;
/*
* Strangeness: page_number is incremented by page_start and
* line_number is incremented in the "while(fgets..." loop.
*/
/* start the first page */
page_start();
/*
* More strangeness: we had to set line_number to 1 to trick
* page_start into reporting the right line count in the header. Now
* we reset it to 0 before entering the read/print loop.
*/
line_number = 0;
while (fgets(input_line, Line_size, file) != NULL)
{
/* new line */
line_number++;
/* remember the length */
length = strlen(input_line);
/* nuke any trailing newline */
if (input_line[length - 1] == '\n')
{
input_line[--length] = '\0';
}
if (lflg ? lines_on_page >= 66 : current_line < bottom_margin)
{
/* start a new page */
page_end(No);
page_start();
lines_on_page = 0;
/* remember, y goes backwards */
current_line = top_margin;
}
/* make sure that the line actually contains something */
if (input_line[0] != '\0')
{
/* set x and y for the beginning of the line */
Setxy((double)left_margin, (double)current_line);
/* copy from input_line to line_buffer making any necessary
changes along the way */
column = 0;
src = input_line;
dest = line_buffer;
while ((ch = *src) != '\0')
{
switch(ch)
{
case '\f': /* new page after this line */
current_line = bottom_margin;
lines_on_page = 66;
break;
case '\t': /* tab expansion */
do
{
*dest++ = ' ';
column++;
} while (column % tab_amount != 0);
break;
case '$':
*dest++ = '\244';
column++;
break;
case '-':
if (special_font == Font_Terminal)
{
/* heavy hackery here */
*dest = '\0';
ShowString(line_buffer);
Setyrel(-20.);
ShowString("\305");
Setyrel(20.);
dest = line_buffer;
column++;
break;
}
/* else fall thru ... */
default:
*dest++ = ch;
column++;
}
src++;
}
*dest = '\0';
if (line_buffer[0] != '\0')
{
ShowString(line_buffer);
}
}
/* advance the line counters */
current_line -= line_spacing;
lines_on_page++;
}
/* wrap up the file */
page_end(Yes);
}
/*
* page handling: a distinction is made between virtual pages and actual
* pages. A virtual page is one series of lines from the file that appears
* vertically on the printed page. The actual page is the page as the
* printer prints it (a printed page, if you will). There may be several
* virtual pages on one actual page. The page_start and page_end routines
* that follow start and terminate virtual pages. The mapping between
* virtual and actual pages is a function of the options specified by the
* user. If the user requests two column output then there will be two
* virtual pages for every actual page. These pages will sit side-by-side on
* the actual page. The mapping is accomplished by changing the variables
* left_margin and right_margin. "page_start" also handles printing of the
* page header, since there is only one of these on every actual page.
*/
static int current_column;
page_start()
{
boolean in_set;
#ifdef vax11c
long bintim;
#endif
/* reset the column count if starting a new file */
if (line_number == 1)
{
current_column = 0;
}
/* either move the left margin or put out a new page */
if (current_column != 0)
{
left_margin += column_separation;
}
else
{
/* increment page count and reset margin */
page_number++;
left_margin = Orig_x;
/* is it in the page specification set? */
if (page_select == NULL)
{
/* every page is in the set if there is no specification */
in_set = Yes;
}
else
{
if (page_low <= page_number && page_number <= page_high)
{
in_set = Yes;
ip_select(ipress_file);
if (page_number == page_high)
{
/* at the top of the current range -- time to move up */
curr_page_select += 2;
page_low = curr_page_select[0];
page_high = curr_page_select[1];
}
}
else
{
/* not in set -- redirect output to null device */
in_set = No;
ip_select(null_file);
}
}
if (in_set)
{
register char *src;
register char *dst;
register char ch;
/* increment total page count */
pages_printed++;
/* output stuff for new ip page */
Op(beginBody);
/* set the transformation */
Fget(F_transform);
Op(concatt);
/* build the header if we need to print it */
if (!tflg)
{
/* move characters from header to real_header */
/* and expand format items along the way. */
src = header;
dst = real_header;
while ((ch = *src) != '\0')
{
if (ch == '%')
{
switch(ch = *++src)
{
case 'f': /* file name */
dst = strecpy(dst,
filename == NULL ?
"Standard input" :
filename);
break;
case 't': /* mtime */
#ifdef vax11c
time(&bintim);
strncpy(dst,ctime(&bintim), 24);
dst += 24;
#else
/*
* ctime returns a 26 character string that
* has a newline and null at the end.
* 26 - 2 == 24.
*/
if (file_stat.st_mtime != 0)
{
(void) strncpy(dst,ctime(&file_stat.st_mtime),24);
dst += 24;
}
#endif
break;
case 'p': /* page number */
dst = itoa(dst, page_number);
break;
case 'l': /* line number */
dst = itoa(dst, line_number);
break;
case '\0': /* end of the string */
src--; /* maintain loop invariant */
break;
default: /* copy the character */
*dst++ = ch;
/* break; */
}
}
else
{
*dst++ = ch;
}
src++;
}
/* terminate the real header */
*dst = '\0';
/* display the header */
Setxy((double)(left_margin - Header_to_orig_x),
(double)(top_margin + Header_to_orig_y));
Setfont(F_headfont);
ShowString(real_header);
}
}
}
/* select the body font */
Setfont(F_bodyfont);
}
page_end(eof)
int eof;
{
if ((current_column = ++current_column % columns) == 0 || eof)
{
Op(endBody);
}
}
char *strecpy(dest, src)
register char *src;
register char *dest;
{
while (*dest++ = *src++)
;
return(--dest);
}
char *itoa(buff, val)
char *buff;
int val;
{
char tbuff[12]; /* will build number here -- max of 10 digits */
register char *ptr = tbuff + 11;
*ptr-- = '\0';
while (val != 0)
{
*ptr-- = (val % 10) + '0';
val /= 10;
}
return(strecpy(buff, ++ptr));
}
/*
* allocate(space) - allocate "space" bytes with sbrk. This routine uses a
* fairly naive algorithm. It sbrk-s space in Break_size
* chunks and allocates space from a chunk until a request
* for more space than is left in the chunk is made. Then,
* it allocates a new chunk. The unused space at the end
* of the old chunk remains unused. This does NOT depend
* on sbrk returning contiguous chunks of memory during the
* life of the program.
*/
char *allocate(space)
int space;
{
static char *hi_water = NULL;
static char *max_alloc = NULL;
register char *ptr;
/* this works with max_alloc = hi_water = NULL, although we probably
shouldn't depend on that! */
if (max_alloc + space > hi_water)
{
hi_water = sbrk(Break_size);
if ((int)hi_water == -1)
{
system_error("out of space");
exit(1);
}
max_alloc = hi_water + Break_size - 1;
}
ptr = hi_water;
hi_water += space;
return(ptr);
}
system_error(message)
char *message;
{
int saved_errno;
/* value of errno not preserved by fprintf */
saved_errno = errno;
fprintf(stderr, "%s: ", myname);
errno = saved_errno;
perror(message);
}
#ifdef vax11c
char *rindex(string, c)
char *string, c;
{
register char *pos;
pos = 0;
do {
if (*string == c)
pos = string;
} while (*string++);
return(pos);
}
#endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.