This is lj.c in view mode; [Download] [Up]
/* Project: lj2ps
** File: lj.c
**
** Author: Christopher Lishka
** Organization: Wisconsin State Laboratory of Hygiene
** Data Processing Dept.
**
** Copyright (C) 1990 by Christopher Lishka.
**
** This program 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 1, or (at your option)
** any later version.
**
** This program 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, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
static char * ModuleID = "Module lj: v1.0, production";
/* Include files
*/
#include <stdio.h>
#if defined (NeXT)
#include <stdlib.h>
#endif
#include "lj.h"
#include "ljcmds.h"
#include "ljfonts.h"
#include "scan.h"
#include "lj2ps.h"
/* External definitions
*/
/* Global variables
*/
/* Front panel variables */
int panel_copies; /* Front panel: Copies */
int panel_manual_feed; /* Front panel: Manual Feed */
int panel_font_source; /* Front panel: Font Source */
int panel_font_number; /* Front panel: Font Number */
int panel_orientation; /* Front panel: Font Source, Font Number */
int panel_form; /* Front panel: Form (i.e. lines/page) */
/* Postscript specific variables */
double ps_scale_x; /* PS: scale in x direction */
double ps_scale_y; /* PS: scale in y direction */
double ps_offset_x; /* PS: offset in x direction */
double ps_offset_y; /* PS: offset in y direction */
/* Job control */
int copies; /* Number of copies */
#if defined (NeXT)
int allow_page_reversing = 1;
#endif
/* Page control */
int paper_source; /* Where the paper is coming from */
int orientation; /* Portrait/landscape (code) */
psize page_size; /* Type of paper being used (structure) */
double page_height; /* Height of physical page (inches) */
double page_width; /* Width of physical page (inches) */
double char_height; /* Char height (~= VMI) (inches) */
double char_width; /* Char width (~= HMI) (inches) */
double margin_top; /* Top margin (inches) */
int text_length; /* Text length (lines) */
double text_height; /* Text height (inches) */
double margin_left; /* Left margin (inches) */
double text_width; /* Text width (inches) */
int perf_skip; /* 1 if perforation skip is on */
int line_term; /* Current line termination mode */
/* Fonts */
ljfont font_p; /* Primary font */
ljfont font_s; /* Secondary font */
int underline; /* Underline mode */
/* Font management */
int font_ID; /* Current font ID */
int char_code; /* Current character code */
/* Raster graphics */
int resolution; /* Current graphics resolution */
int margin_graphics; /* Graphics left margin, in dots? */
/* Rectangular area fill */
int rect_size_h; /* Horizontal rectangle size */
int rect_size_v; /* Vertical rectangle size */
int fill_ID; /* Current area fill ID */
/* Macro */
int macro_ID; /* Current macro ID */
/* Troubleshooting commands */
int eol_wrap; /* End-of-line wrap on/off */
int display_funcs; /* Display functions on/off */
/* Implementation variables */
double current_x; /* Current X position (inches) */
double current_y; /* Current Y position (inches) */
int current_line; /* Current line being printed (lines) */
int current_font; /* Primary or secondary (code) */
int empty_line; /* Ture if line is empty (boolean) */
int empty_text; /* True if text is empty (boolean) */
int empty_page; /* True if page is empty (boolean) */
double compress_width; /* Compression in x axis (%) */
double compress_height; /* Compression in y axis (%) */
double offset_width; /* Offset of x axis (inches) */
double offset_height; /* Offset of y axis (inches) */
/* Global function list
*/
extern void lj_factory_setup(); /* Reset to factory defaults */
extern void lj_startup(); /* Do before the virtual LJ is ready... */
extern void lj_shutdown(); /* Do after the virtual LJ is shutdown... */
extern void lj_page_begin(); /* Start a new page */
extern void lj_page_end(); /* End the current page */
/* macro lj_text_begin();*/ /* Start text */
/* macro lj_text_add(); */ /* Add text to buffer */
/* macro lj_text_end(); */ /* End text (i.e. flush the buffer) */
/* macro lj_cursor_move();*//* Move cursor to a new location */
/* macro lj_set_font(); */ /* Use a new font to print the text */
/* macro lj_undl_begin();*/ /* Start underlining */
/* macro lj_undl_flush();*/ /* Flush the current underline request */
/* macro lj_undl_end(); */ /* End underlining */
extern void lj_nl(); /* Print a newline */
extern void lj_reset(); /* Reset the printer to default state */
extern int lj_paper_size(); /* Get the dimensions of paper and envelopes */
/* Local constants
*/
/* Local structures and types
*/
/* Local variables
*/
/* Implementation variables */
static int new_page; /* Is the next page a new one? */
static int page_number; /* Which page we are currently printing */
/* Tables */
psize paper_size[] = { /* Sizes (in inches) for paper and envelopes */
{ LJ_PS_EXECUTIVE, 7.2500, 10.5000, 57, /* Paper sizes */
0.2000, 0.2000, 0.1667, 0.3333 },
{ LJ_PS_LETTER, 8.5000, 11.0000, 60,
0.2000, 0.2000, 0.1667, 0.3333 },
{ LJ_PS_LEGAL, 8.5000, 14.0000, 78,
0.2000, 0.2000, 0.1667, 0.3333 },
{ LJ_PS_A4, 8.2677, 11.6929, 64,
0.2000, 0.1933, 0.1667, 0.3067 },
{ LJ_PS_MONARCH, 3.8750, 7.5000, 39, /* Envelope sizes */
0.2000, 0.2000, 0.1667, 0.3333 },
{ LJ_PS_COMMERCIAL10, 4.1250, 9.5000, 51,
0.2000, 0.2000, 0.1667, 0.3333 },
{ LJ_PS_INTERNATIONALDL, 4.3307, 8.6614, 46,
0.2000, 0.1933, 0.1667, 0.3067 },
{ LJ_PS_INTERNATIONALC5, 6.3780, 9.0157, 48,
0.2000, 0.1933, 0.1667, 0.3067 },
{ 0, 0.0000, 0.0000 } /* The end must be all 0's */
};
/* Local macro definitions
*/
/* Local function list
*/
/* Function bodies
*/
void
lj_factory_setup()
{
panel_copies = 1;
panel_manual_feed = LJ_PS_TRAY_1;
panel_form = 60;
panel_orientation = LJ_OR_PORTRAIT;
panel_font_source = LJ_FS_INTERNAL;
panel_font_number = 0;
ps_scale_x = 1.0;
ps_scale_y = 1.0;
ps_offset_x = 0.0;
ps_offset_y = 0.0;
} /* lj_factory_setup() */
void
lj_startup(ofile)
FILE *ofile;
{
/* Set the default laserjet variables by executing a reset (ljcmd_E) */
lj_reset(ofile);
/*
** The postscript prologue
**
** Postscript naming conventions used here:
**
** Note: X = uppercase letter; x = lowercase letter.
**
** X, XX, XXX: Functions
**
** x, xx, xxx: Global variables
**
** Xx, Xxx: Temporary variables
*/
/* First write out the comments */
fprintf(ofile, "%%!PS-Adobe-1.0\n"); /* The standard header */
fprintf(ofile, "%%%%Creator: %s %s (%s)\n",
PROGRAM, VERSION, STATUS); /* Identify oneself! */
fprintf(ofile, "%%%%Pages: (atend)\n");
fprintf(ofile, "%%%%EndComments\n");
fprintf(ofile, "\n");
/* Next, write the prologue code */
/* Set the number of copies */
fprintf(ofile, "/#copies %d def\n", copies);
/* Use letter size paper (8.5"x11") */
/* fputs("letter\n", ofile);*/ /* XXX */
#if !defined (NeXT)
/* Set manual or automatic feed */
if( (paper_source == LJ_PS_MANUAL)
|| (paper_source == LJ_PS_MANUAL_ENVELOPE) ){
fprintf(ofile, "statusdict begin /manualfeed true def end\n");
}
else{
fprintf(ofile, "statusdict begin /manualfeed false def end\n");
}
#endif
/* Define variables for the current font, font size, and font width */
fputs("\n", ofile);
fprintf(ofile, "/cf /%s def\n", font_p.ps_name);
fprintf(ofile, "/cs %.4f def\n", pt2in(font_p.point_size));
fprintf(ofile, "/cw %.4f def\n", font_p.width);
/* Left margin */
fputs("\n", ofile);
fprintf(ofile, "/ml %.4f def\n", margin_left);
/* Variables for underlining */
fputs("\n", ofile);
fputs("/ux 0.0 def\n", ofile); /* X coord of underline beginning */
fputs("/uy 0.0 def\n", ofile); /* Y coord of underline beginning */
/* <String> S -> % Show the string */
fputs("\n/S /show load def\n", ofile);
/* <X> <Y> -> % Move to (<X>,<Y>) */
fputs("\n/M /moveto load def\n", ofile);
/* <DeltaX> HRM -> % Move <DeltaX> horizontally (i.e. relative) */
fputs("\n\
/HRM {\n\
0 rmoveto\n\
} bind def\n\
", ofile);
/* <Y> VM -> % Move to <Y> (i.e. vertical absolute) */
fputs("\n\
/VM {\n\
currentpoint pop exch moveto\n\
} bind def\n\
", ofile);
/* Set Right Margin -- uses clippath
** Note: 25 is used as an arbitrary size. The only requirement of this
** number is that it must be outside the page boundaries
*/
fputs("\n\
/RM {\n\
/Tr exch def\n\
currentpoint initclip\n\
newpath\n\
0 0 moveto Tr 0 lineto Tr 25 lineto 0 25 lineto\n\
closepath clip\n\
moveto\n\
} bind def\n\
", ofile);
/* <typeface> <point-size> F ->
** Set the font, given typeface and point size.
** Note that the character-width is derived by having PostScript
** provide the width of the *space* character (which is likely
** the best character to use for a proportional font).
*/
fputs("\n\
/F {\n\
/Tp exch def /Tf exch def\n\
Tf findfont Tp scalefont setfont\n\
/cf Tf def /cs Tp def /cw ( ) stringwidth pop def\n\
} bind def\n\
", ofile);
/* <typeface> <width> <height> FS ->
** Set the font, given typeface, X scale factor, Y scale factor.
** Note that the character-width is derived by having PostScript
** provide the width of the *space* character (which is likely
** the best character to use for a proportional font).
*/
fputs("\n\
/FS {\n\
/Ty exch def /Tx exch def /Tf exch def\n\
Tf findfont [Tx 0 0 Ty 0 0] makefont setfont\n\
/cf Tf def /cs Ty def /cw ( ) stringwidth pop def\n\
} bind def\n\
", ofile);
/* US -> Start a new underline */
fputs("\n\
/US {\n\
currentpoint /uy exch def /ux exch def\n\
} bind def\n\
", ofile);
/* UE -> Finish (i.e. draw!) the current underline
**
** Note that this underlining does not yet work across separate lines,
** so US and UE must be called on the same line. Also, underlining does
** not work backwards, so only use it if going forwards with the
** underlines (yes, I know this is very limited, but tracking page motion
** is a bit hard with underlining).
*/
fputs("\n\
/UE {\n\
/Tcx currentpoint pop def\n\
gsave\n\
newpath\n\
cf findfont cs scalefont dup\n\
/FontMatrix get 0 get /Ts exch def /FontInfo get dup\n\
/UnderlinePosition get Ts mul /To exch def\n\
/UnderlineThickness get Ts mul /Tt exch def\n\
ux uy To add moveto Tcx uy To add lineto\n\
Tt setlinewidth stroke\n\
grestore\n\
} bind def\n\
", ofile);
/* TAB -> Tab over to the next tab stop
** For efficiency, this function gets the currentpoint, exch's to
** get the current-x to the top-of-stack, works magic on the
** current-x to figure out the position of the tab stop, exch's
** again to get the arguments in the right sequence for the moveto
** operator, and moves to the tab position.
**
** Note that (1.0 + LJ_ERROR) is added to the calculation. The 1.0
** represents the movement to the next tab-stop. LJ_ERROR is needed
** insure that the value is within a certain error-margin in its proximity
** to the tab-stop when the "cvi" (i.e. drop the decimal portion) is
** performed.
*/
fprintf(ofile, "\n\
/TAB {\n\
currentpoint exch\n\
ml sub cw div %d div %f add cvi %d mul cw mul ml add\n\
exch moveto\n\
} bind def\n\
",
LJ_TAB_WIDTH,
(1.0 + LJ_ERROR),
LJ_TAB_WIDTH);
/* Initialization of the position stack would go here, if it was
** implemented! */
/* Mark the end of the prolog */
fprintf(ofile, "\n%%%%EndProlog\n");
#if defined (NeXT)
fprintf (ofile, "%%%%BeginSetup\n");
if (!allow_page_reversing)
fprintf (ofile, "%%%%Feature: *PageOrder Special\n");
/* Set manual feed, if desired. */
if( (paper_source == LJ_PS_MANUAL)
|| (paper_source == LJ_PS_MANUAL_ENVELOPE) )
fprintf(ofile, "%%%%Feature: *ManualFeed True\n");
else
fprintf (ofile, "%%%%Feature: *ManualFeed False\n");
fprintf (ofile, "%%%%EndSetup\n");
#endif
/* Start the first page */
new_page = 1;
page_number = 0;
} /* lj_startup() */
void
lj_shutdown(ofile)
FILE *ofile;
{
#if !defined (NeXT)
fprintf(ofile, "\nstatusdict begin /manualfeed false def end\n");
#endif
fprintf(ofile, "%%%%Trailer\n");
fprintf(ofile, "%%%%Pages: %d\n", page_number);
} /* lj_shutdown() */
void
lj_page_begin(ofile)
FILE *ofile;
{
/* Set starting position */
current_x = margin_left;
current_y = page_height - margin_top - char_height;
current_line = 1;
/* Print the PostScript page header */
if( new_page ){
page_number++;
#if defined (NeXT)
/*
** To prevent page reversing, we don't output %%Page comments, at
** least until NeXT pays attention to %%PageOrder commands.
*/
if (allow_page_reversing)
#endif
fprintf(ofile, "\n%%%%Page: ? %d\n", page_number);
}
/* Save the current graphics state */
fputs("save\n", ofile);
/* Note: the next three pieces of code must be in the following
** order to insure that everything works correctly:
**
** (1) Make inches the default measure
** (2) Rotate the the page to landscape, if necessary
** (3) Perform default offsets and page scaling
*/
/* Make inches the default measure. Note that this must be at the
** beginning of every *page* (rather than in the prologue) because
** the PostScript showpage function resets the graphics state.
*/
fprintf(ofile, "72 72 scale\n");
/* Rotate the page to the proper orientation */
if( orientation == LJ_OR_LANDSCAPE ){
fprintf(ofile,
"90 rotate 0 %.4f translate\n",
-page_size.width);
}
/* Make sure everything fits in the printable region */
fprintf(ofile, "%.4f %.4f translate %.4f %.4f scale\n",
offset_width, offset_height,
compress_width, compress_height);
/* Make sure that a current point exists */
fputs("0 0 moveto\n", ofile);
/* Set the initial font */
if( current_font == LJ_FT_PRIMARY )
lj_set_font(ofile, font_p);
else
lj_set_font(ofile, font_s);
/* Set the left margin */
fprintf(ofile, "/ml %.4f def ", margin_left);
/* Set the right margin */
fprintf(ofile, " %.4f RM ",
margin_left + text_width);
/* Default position */
fprintf(ofile,
"%.4f %.4f M\n", current_x, current_y);
empty_page = 1;
lj_undl_mark(ofile);
lj_text_begin();
} /* lj_page_begin() */
void
lj_page_end(ofile)
FILE *ofile;
{
lj_text_end(ofile);
lj_undl_flush(ofile);
fputs("\nrestore ", ofile);
if( empty_page ){
/* Clear the page without using erasepage! */
fputs("gsave newpath clippath 1 setgray fill grestore\n", ofile);
new_page = 0; /* Still the same physical page */
}
else{
fputs("showpage\n", ofile); /* Print the page */
new_page = 1; /* A new physical page is started */
}
} /* lj_page_end() */
void
lj_nl(ofile)
FILE *ofile;
{
lj_text_end(ofile);
lj_undl_flush(ofile);
current_x = margin_left;
current_y -= char_height;
fprintf(ofile, "%% NL\n%.4f %.4f M ", current_x, current_y);
empty_line = 1;
lj_undl_mark(ofile);
lj_text_begin();
} /* lj_nl() */
void
lj_reset(ofile)
FILE *ofile;
{
/* ***** JOB CONTROL **************************************************
*/
copies = panel_copies; /* Number of copies, from the "front panel" */
/* ***** FONTS ********************************************************
**
** Note: fonts must come before page control because the HMI (i.e.
** char_width) is determined from the font.
*/
/* Reset the primary font */
if( lj_find_font(panel_font_source, panel_font_number, &font_p) == 1 ){
fatal_error("could not find specified font", "");
}
/* Reset the secondary font */
if( lj_find_font(panel_font_source, panel_font_number, &font_p) == 1 ){
fatal_error("could not find specified font", "");
}
/* Underline, should be off */
underline = LJ_UL_OFF;
/* ***** PAGE CONTROL ************************************************
*/
/* Paper source, from the "front panel" */
paper_source = panel_manual_feed;
/* Page orientation, from the "front panel" */
orientation = panel_orientation;
/* Determine the physical page size */
page_size.code = LJ_PS_LETTER; /* Letter size, by default */
if( lj_paper_size(&page_size) ){
internal_error("illegal page size", "");
}
/* Page width and height */
if( orientation == LJ_OR_PORTRAIT ){
page_width = page_size.width;
page_height = page_size.height;
}
else{
page_width = page_size.height;
page_height = page_size.width;
}
/* Top margin, text height (inches), and text length (lines).
** Char width and height are set here as well due to the
** inter-dependencies.
*/
margin_top = 0.5; /* Top and bottom margins are 1/2" */
text_height = page_height - margin_top - 0.5; /* 0.5 is for bottom margin */
char_height = text_height / panel_form;
char_width = font_p.width; /* inches per character */
text_length = text_height / char_height;
/* Left margin + text_width (= page width - right margin) */
margin_left = 0.0;
/* Initially, the right margin is not set. To simulate this, the
** text_width is set to be wider than any reasonable page width.
*/
text_width = 99.00;
/* Perforation skip */
perf_skip = 1;
/* Line termination: start with normal */
line_term = LJ_LT_NORM;
/* ***** FONT MANAGEMENT **********************************************
*/
/* Current font ID, for soft fonts */
font_ID = 0;
/* Current character code, for soft fonts */
char_code = 0;
/* ***** RASTER GRAPHICS **********************************************
*/
/* Graphics resolution, start at 300 dpi */
resolution = 75;
/* Graphics margin, start at 0 */
margin_graphics = 0;
/* ***** RECTANGULAR AREA FILL ****************************************
*/
/* ID for filling areas (one ID used for both patterns and gray scales) */
fill_ID = LJ_FI_RULE; /* *Black* greyscale! */
/* Horizontal and vertical graphics area sizes */
rect_size_h = 0;
rect_size_v = 0;
/* ***** MACRO ********************************************************
*/
/* Current macro ID */
macro_ID = 0;
/* ***** TROUBLESHOOTING COMMANDS *************************************
*/
/* End-of-line wrap: should be off */
eol_wrap = 0;
/* Display functions should be off */
display_funcs = 0;
/* ***** IMPLEMENTATION VARIABLES *************************************
*/
current_x = margin_left;
current_y = page_height - margin_top - char_height;
current_line = 1;
current_font = LJ_FT_PRIMARY;
empty_line = 1;
empty_text = 1;
empty_page = 1;
compress_width = ps_scale_x * LJ_DEFAULT_SCALE_X;
compress_height = ps_scale_y * LJ_DEFAULT_SCALE_Y;
offset_width = ps_offset_x + LJ_DEFAULT_OFFSET_X;
offset_height = ps_offset_y + LJ_DEFAULT_OFFSET_Y;
} /* lj_reset() */
/* lj_paper_size() looks up the dimensions of the paper or envelope
** passed in the code field of the argument. If the code is legal, then
** the width and height fields are filled and a 0 is returned. If the
** code does not exist, then the width and height fields are undefined and
** a 1 is returned.
*/
int
lj_paper_size(page_size)
psize *page_size;
{
int found;
int counter;
found = 0;
for( counter = 0; !found && !(paper_size[counter].code == 0); counter++ ){
if( page_size->code == paper_size[counter].code ){
found = 1;
page_size->width = paper_size[counter].width;
page_size->height = paper_size[counter].height;
} /* if(...) */
} /* for(...) */
return( !found );
} /* lj_paper_size() */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.