ftp.nice.ch/pub/next/tools/printer/lj2ps.s.tar.gz#/lj2ps/lj.c

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.