/*****************************************************************************
*           Change Log
*  Date     | Change
*-----------+-----------------------------------------------------------------
*  4-Dec-85 | [1.106] Created
*  6-Dec-85 | [1.144] Recognize new escapes \W,\G,\S,\R,\Q,\D
*  7-Dec-85 | [1.151] Flush listing file
* 28-Dec-85 | [1.260] Changed to 1401.cfg from 1401.prn so FWF output file
*           | doesn't clobber us.
* 25-Feb-86 | [1.379] include <> => include ""
* 31-Jul-86 | [1.405] Made chars unsigned
*  6-Aug-86 | [1.410] cast malloc args to unsigned
* 17-Nov-91 | [1.428] <jmn> converted for Microsoft C 6.0
* 20-Nov-91 | [1.429] <jmn> configured for new virtual printer code
* 23-Nov-91 | [1.455] <jmn> added .sf for screen font
* 23-Nov-91 | [1.455] <jmn> accept two hex digits following \x
* 23-Nov-91 | [1.455] <jmn> created generic_printer_init
* 25-Nov-91 | [1.182] <jmn> added NOMAP conditional for autocoder inclusion
*  7-Dec-91 | [1.481] <jmn> added CHAR_NE
* 21-Dec-91 | [1.493] <jmn> added CHAR_PERF
* 22-Dec-91 | [1.505] <jmn> use unsigned chars for write_translated
* 23-Dec-91 | [1.527] <jmn> added CHAR_CORNER
* 23-Dec-91 | [1.536] <jmn> init_seq no longer emits the init string; this
*           | is done only when the printer is actually used
* 23-Dec-91 | [1.547] <jmn> save bitstrings in screen_xlat so we can reset
*           | after 132-column mode switch
*  2-Jan-92 | [1.7] <jmn> allow \" as escape
*  2-Jan-92 | [1.9] <jmn> handle multiple .in strings
*  1-Mar-02   	    <jrj> put include of "graph.h" inside conditional
*****************************************************************************/
#include "stdio.h"
#include "stdlib.h"
#include "boolean.h"
#include "string.h"
#include "stdarg.h"
#include "ctype.h"

#ifndef __BORLANDC__
#include "graph.h"
#endif
#include "font.h"
#include "pr.h"
#include "prdev.h"
#include "chars.h"
#include "btypes.h"
#include "diag.h"
#include "rdy.h"
#include "scdspmsg.h"

#ifndef NOMAP
extern struct videoconfig video;
#endif

typedef struct
	{ int len;
	  unsigned char * str;
	} string;

static string * screen_xlat[256];

static string * xlat[256];
static string * final = NULL;
static string * init = NULL;

static string space = {1," "};
extern boolean pr64;

char * cfgname = "1401.cfg";
static int lineno;

#define debug_scan false
#define debug_effects false

/****************************************************************************
*                               printer_upline
* Inputs:
*       printobj * pr: Print object
* Result: void
*       
* Effect: 
*       Increments current_line and does page wrap
****************************************************************************/

void printer_upline(printobj * pr)
    {
     if(pr != NULL)
	pr->current_line = (pr->current_line + 1) % pr->form->pagelength;
    }


/****************************************************************************
*                               set_screen_font
* Inputs:
*       string * source: Source character
*	string * map: Mapped character
*	string * bits: Bitmap for screen
* Result: void
*       
* Effect: 
*       Sets the screen font for the mappable characters.  If bits are
*	supplied for an EGA/VGA, sets the font table for the display
****************************************************************************/

void set_screen_font(string * source, string * map, string * bits)
    {
     unsigned char * dest;
     unsigned char * maploc;
     unsigned char size;

#ifndef NOMAP
     switch(video.adapter)
        { /* what size */
	 case SC_EGA:
		 size = 14;
		 break;
	 case SC_VGA:
		 size = 16;
		 break;
	} /* what size */

     if(source->len < 1)
        { /* source too short */
	 if(diagnostics_on)
	    tell("set_screen_font: source length < 1");
	 return;
	} /* source too short */

     if(map->len < 1)
        { /* map too short */
	 if(diagnostics_on)
	    tell("set_screen_font: map length < 1");
	 return;
	} /* map too short */

     switch(source->str[0])
        { /* decode special */
	 case CHAR_GM:
		 dest = &char_gm;
		 break;
	 case CHAR_WM:
		 dest = &char_wm;
		 break;
	 case CHAR_RM:
		 dest = &char_rm;
		 break;
	 case CHAR_SM:
		 dest = &char_sm;
		 break;
	 case CHAR_DL:
		 dest = &char_dl;
		 break;
	 case CHAR_SQ:
		 dest = &char_sq;
		 break;
	 case CHAR_MI:
		 dest = &char_mi;
		 break;
	 case CHAR_AMPERSAND:
	 case CHAR_PLUS:
		 dest = &char_plus;
		 break;
	 case CHAR_QUOTE:
	 case CHAR_AT:
		 dest = &char_quote;
		 break;
	 case CHAR_HASH:
	 case CHAR_EQUAL:
		 dest = &char_equal;
		 break;
	 case CHAR_LPAREN:
	 case CHAR_PERCENT:
		 dest = &char_lparen;
		 break;
	 case CHAR_NEX:
		 dest = &char_ne;
		 break;
	 case CHAR_PERF:
		 dest = &char_perf;
		 break;
     /*  case CHAR_LOZENGE: */  /* no such font character... */
	 case CHAR_RPAREN:
		 dest = &char_rparen;
		 break;
	 case CHAR_CORNER1:
		 dest = &char_corner1;
		 break;
	 case CHAR_CORNER2:
		 dest = &char_corner2;
		 break;
	 default: /* unknown char */
		 if(diagnostics_on)
		    {
		     sprintf(diag_buffer,"%s(%d): Error: set_screen_font: Unknown character \"%c\"", 
		     cfgname,
		     lineno,
		     source->str[0]);
		     tell(diag_buffer);
		    }
		 return;
	} /* decode special */

     switch(video.adapter)
        { /* decode adapter */
	 case SC_EGA:
	 case SC_VGA:
		 if(bits->str != NULL)
		    { /* has bits */
		     
		     if(!fontset(map->str[0],
				    bits->str,
				    (unsigned char)(bits->len > size 
						    ? size 
						    : bits->len), 
				    size))
			 { /* fontset failed */
			  tell("font set failed");
			  return;
			 } /* fontset failed */
		    } /* has bits */
		 break;
	} /* decode adapter */
     *dest = map->str[0];
#endif
    }

/****************************************************************************
*                                 freestring
* Inputs:
*       string * s: String object
* Result: void
*       
* Effect: 
*       Frees the string space
****************************************************************************/

void freestring(string * s)
    {
     if(s->str != NULL)
	free(s->str);
     free(s);
    }

/****************************************************************************
*                            physical_printer_open
* Inputs:
*       printobj * pr: Printer object
* Result: boolean
*       true if success
*	false if error
* Effect: 
*       Opens the physical printer
****************************************************************************/

boolean physical_printer_open(printobj * pr)
    {
     pr->prn = fopen(pr->lpt,"wb");
     if(diagnostics_on)
        { /* report */
	 if(pr->prn == NULL)
	    { /* failed */
	     sprintf(diag_buffer,"%s(%d): Error: physical_printer_open: %s open failed",
	     		cfgname,
			lineno,
	     		pr->lpt);
             tell(diag_buffer);
	    } /* failed */
	} /* report */
     return (pr->prn != NULL);
    }

/****************************************************************************
*			    physical_printer_printf
* Inputs:
*       printobj * pr: Printer object for physical printer
*	char * fmt: Format string
*	...	: args
* Result: void
*       
* Effect: 
*       Outputs to real or virtual printer
****************************************************************************/

int physical_printer_printf(printobj * pr, char * fmt, ...)
    {
     int ret;
     va_list marker;
     static char buf[512];

     va_start(marker,fmt);
     ret = vfprintf(pr->prn, fmt, marker);
     va_end(marker);
     return ret;
    }

/****************************************************************************
*                           physical_printer_flush
* Inputs:
*       printobj * pr: Printer object
* Result: int
*       result of fflush
* Effect: 
*       Flushes the output
****************************************************************************/

int physical_printer_flush(printobj * pr)
    {
     if(pr->prn == NULL)
	return -1;	/* error */
     return fflush(pr->prn);
    }

/****************************************************************************
*			   physical_printer_newline
* Inputs:
*	printobj * pr: Printer file descriptor
* Result: void
*       
* Effect: 
*       Advances printer one line
****************************************************************************/

void physical_printer_newline(printobj * pr)
    {
     fprintf(pr->prn,"\r\n");
     printer_upline(pr);
    }

/****************************************************************************
*                                 scan_string
* Inputs:
*       char * * str: Pointer String to be scanned.  May have leading spaces 
*			before the open-quote.
*	
* Result: string *
*       Scanned string with characters converted; explicit length allows
*	NUL characters.  NULL if error.  If there is no string to scan,
*	returns a string * with len==0 and str==NULL.
* Effect: 
*       Allocates heap string for result.  Scan pointer is updated.
* Syntax:
*	\n newline
*	\\ \
*	\e escape
*	\f formfeed
*	\r return
*	\t tab
*	\v vertical tab
*	\G group mark
*	\M mouse icon
*	\W word mark
*	\R record mark
*	\S segment mark
*	\D delta
*	\Q radical
*	\_ perf
*	\c card corner1
*	\C card corner2
****************************************************************************/

static string * scan_string(char * * pstr)
    {
     char gstr[81];
     int i;
     char *s;
     char *d;
     string * result;

     s = * pstr;
     d = gstr;

     *d = '\0';

     while(*s != '\0' && *s != '\"')
        { /* scan to open quote */
#if debug_scan
	 printf("pre-scanning string: 0x%x=='%c'\n",s,*s);
#endif
	 s++;
	 *pstr = s;
	} /* scan to open quote */

     if(*s == '\0')
        { /* nothing to scan */
	 result = (string *)malloc(sizeof(string));
	 if(result == NULL)
	    return NULL;
	 result->str = NULL;
	 result->len = 0;
	 return result;
	} /* nothing to scan */

     if(*s=='"')
        {
	 s++;
	 *pstr = s;
	}

     while(*s != '\0' && *s != '\"')
        { /* scan it */

#if debug_scan
	 printf("scanning string: 0x%x=='%c'\n",s,*s);
#endif	 

	 switch(*s)
	    { /* char decode */
	     case '\\':
	     		s++;
#if debug_scan
			 printf("scanning \\: 0x%x=='%c'\n",s,*s);
#endif	 
	     		switch(*s)
			   { /* quote decode */
			    case '"':
				        *d++ = '"';
					break;
			    case 'e':
			    		*d++ = '\33';
					break;
			    case 'n':
			    		*d++ = '\n';
					break;
			    case 'f':
			    		*d++ = '\f';
					break;
			    case 'r':
			    		*d++ = '\r';
					break;
			    case 't':
			    		*d++ = '\t';
					break;
			    case 'v':
			    		*d++ = '\v';
					break;
			    case '\b':
			    		*d++ = '\b';
					break;
			    case 'G':
			    		*d++ = CHAR_GM;
					break;

			    case 'M':
			    		*d++ = CHAR_MI;
					break;
			    case 'N':
				        *d++ = CHAR_NEX;
					break;
			    case 'R':
			    		*d++ = CHAR_RM;
					break;
			    case 'S':
			    		*d++ = CHAR_SM;
					break;
			    case 'D':
			    		*d++ = CHAR_DL;
					break;
			    case 'Q':
			    		*d++ = CHAR_SQ;
					break;
			    case 'W':
			    		*d++ = CHAR_WM;
					break;
			    case '_':
				        *d++ = CHAR_PERF;
					break;
			    case 'C':
				        *d++ = CHAR_CORNER1;
					break;
			    case 'c':
				        *d++ = CHAR_CORNER2;
					break;
			    case '0':
			    case '1':
			    case '2':
			    case '3':
			    case '4':
			    case '5':
			    case '6':
			    case '7':
			    		i = (*s) - '0';
					s++;
					while(*s >= '0' && *s <= '7')
					   { /* accum */
#if debug_scan
	 				     printf("scanning octal: 0x%x=='%c'\n",s,*s);
#endif	 

					    i = i * 8 + (*s) - '0';
					    s++;
					   } /* accum */
#if debug_scan
	 				     printf("done scanning octal: 0x%x=='%c'\n",s,*s);
#endif	 
					s--;  /* back up so next incr leaves us where we were */
#if debug_scan
					printf("stored d (0x%x)= \\%03o\n",d,i);
	 				printf("reset s--: 0x%x=='%c'\n",s,*s);
#endif	 
					*d++ = (unsigned char) i;
					break;
			    case 'x': /* hex */
				    	s++;  /* skip 'x' */
				        if(isalpha(*s))
					   { /* alpha */
					    i = toupper(*s) - 'A' + 10;
					   } /* alpha */
					else
					   { /* numeric */
					    i = (*s) - '0';
					   } /* numeric */
					s++;
					if(isxdigit(*s))
					   { /* second hex digit */
					    i *= 16;
					    if(isalpha(*s))
					       { /* alpha */
						i += toupper(*s) - 'A' + 10;
					       } /* alpha */
					    else
					       { /* numeric */
						i += (*s) - '0';
					       } /* numeric */
					   } /* second hex digit */
					else
					   { /* not hex digit */
					    s--;
					   } /* not hex digit */
					*d++ = (unsigned char) i;
					break;
			    default:
					{
					 sprintf(diag_buffer,
					 		"%s(%d): Error: scan_string: unknown escape \"%c\"",
							cfgname,
							lineno,
							*s);
					 tell(diag_buffer);
					}
#if debug_scan
					printf("stored d (0x%x)= \\%03o\n",d,i);    
#endif
			    		*d++ = *s;
					break;
			   } /* quote decode */
			break;
	     default:
#if debug_scan
			printf("stored d (0x%x)= \\%03o\n",d,i);    
#endif
	     		*d++ = *s;
	     		break;
	    } /* char decode */

#if debug_scan
	 printf("end of scanning \\: 0x%x=='%c'\n",s,*s);
#endif	 
	 s++;
	} /* scan it */


     *pstr = s;

     result = (string *) malloc((unsigned) sizeof(string));

     if(result == NULL)
	return NULL;

     result->len = d - gstr;

#if debug_scan
     printf("result->len = %d (0x%x - 0x%x + 1)\n",result->len,d,gstr);
#endif

     result->str = malloc((unsigned) (result->len + 1));

     for(i=0;i<result->len;i++)	
        { /* copy chars */
	 result->str[i] = gstr[i];
	 result->str[i+1] = '\0';	/* force to be always NUL */
	} /* copy chars */

     if(*s == '"')
        { /* skip terminator */
	 s++;
	 *pstr = s;
	} /* skip terminator */

     return result;
     
    }

/****************************************************************************
*                                check_string
* Inputs:
*       string * s: String to check
* Effect: 
*       Checks the string for the presence of a 'newline' character, and
*	issues a warning message if one is found
****************************************************************************/

void check_string(string * s)
    {
     return;
    }

/****************************************************************************
*                                  outstring
* Inputs:
*       string * s: String, containing embedded NUL characters
*	printobj * pr: Output device
* Effect: 
*       Writes the string to the output device
*	Note that we output it one character at a time because it may
*	have embedded NUL characters
****************************************************************************/

static void outstring(string * s, printobj * pr)
    {
     short i;

     for(i=0;i<s->len;i++)
        { /* print it */
	 (*pr->print)(pr,"%c",s->str[i]);   
	} /* print it */

     (*pr->flush)(pr);
    }

/****************************************************************************
*                                  init_seq
* Inputs:
*       char * text: Text line, scanned just past command
*	printobj * pr: Printer device
* Result: boolean
*       true if success
*	false if error
* Effect: 
*       Extracts the initialization string and stores it for
*	later transmission to the printer.  If the string in
*	'init' is not NULL, a new string is created which is
*	the catenation of the existing string and the new
*	string.
****************************************************************************/

static boolean init_seq(char * text, printobj * pr)
    {
     string * s;
     s = scan_string(&text);

#if debug_effects
     printf("init string:");
     dump_string(s);
     printf("\n");
     if(pr64) 
	printf("pr64 true\n");
#endif

     if(init == NULL)
        { /* simple */
	 /* This is the first init string */
	 init = s;
	} /* simple */
     else
        { /* complicated */
	 string n;

	 n.len = init->len + s->len;
	 n.str = malloc(n.len);
	 if(n.str == NULL)
	    return false;
	 memcpy(n.str,init->str,init->len);
	 memcpy(&n.str[init->len],s->str,s->len);
	 free(init->str);
	 *init = n;
	 freestring(s);
	} /* complicated */
     return true;
    }

/****************************************************************************
*                                  fin_seq
* Inputs:
*       char * text: Text line, scanned just past command
* Result: boolean
*       true if success
*	false if error
* Effect: 
*       Extracts the finalization string and stores it
****************************************************************************/

static void fin_seq(char * text)
    {
     final = scan_string(&text);
    }

/****************************************************************************
*                                 dump_string
* Inputs:
*       string * s: String to dump
* Effect: 
*       Dumps the string
****************************************************************************/

void dump_string(string * s)
    {
     short i;
     printf("0x%x: string { len %d, str \"", s,s->len);
     for(i=0;i<s->len;i++)
     	printf("\\%03o",s->str[i]);

     printf("\"}");
    }

/****************************************************************************
*                                 screen_char
* Inputs:
*       char * textline: Input line to be scanned
* Result: boolean
*       true if valid
*	false if error
* Effect: 
*       Sets up the screen bitmaps for the special characters
* Syntax:
*	1401-char font-char [bits...]
* Example:
*	........	0000 0000    00
*	........	0000 0000    00
*	...*....        0001 0000    10
*	...*....        0001 0000    10
*	*******.	1111 1110    FE
*	...*....        0001 0000    10
*	*******.	1111 1110    FE
*	...*....        0001 0000    10
*	*******.	1111 1110    FE
*	...*....        0001 0000    10
*	...*....        0001 0000    10
*	........	0000 0000    00
*	........	0000 0000    00
*	........	0000 0000    00
*
*	.sf "\G" "å" "\x00\x00\x10\x10\xFE\x10\xFE\x10\xFE\x10\x10\x00\x00"
****************************************************************************/

boolean screen_char(char * textline)
    {
     string * source;
     string * map;
     string * bits;

     source = scan_string(&textline);
     map    = scan_string(&textline);
     bits   = scan_string(&textline);
     set_screen_font(source,map,bits);

     /* Save the string for later initialization */
     screen_xlat[map->str[0]] = bits;

     freestring(source);
     freestring(map);
    }

/****************************************************************************
*                                  spec_char
* Inputs:
*       char * textline: Line containing two strings of the form
*			"chr" "conversion"
* Result: boolean
*       true if valid
*	false if error
* Effect: 
*       Stores the conversion string indexed by the character
****************************************************************************/

static boolean spec_char(char * textline)
    {
     string * ch;
     string * conv;
     char * t = textline;
     int c;

     ch = scan_string(&t);

     conv = scan_string(&t);

#if debug_scan | debug_effects
	printf("conversion string: ");
	dump_string(conv);
	printf("\n");
#endif

     if(ch->len != 1)
        { /* wrong length */
	 fprintf(stderr,"%s(%d): Error: .sc sequence not single char\n",
	 			cfgname,lineno);
	 fprintf(stderr,"%s\n",textline);
	 return false;
	} /* wrong length */

     c = (int) ch->str[0];

     if(xlat[c] != NULL && xlat[c] != &space)
        { /* already defined */
	 fprintf(stderr,"%s(%d): Error: .sc already specified for character %d (0%03o, 0x%x)\n",cfgname,lineno,c,c,c);
	 fprintf(stderr,"%s\n",textline);
	} /* already defined */

#if debug_scan
	printf("xlat[%d] (\\%03o, 0x%x) = 0x%x\n",c,c,c,conv);
#endif
     xlat[c] = conv;

     return true;
    }

/****************************************************************************
*                                  test_seq
* Inputs:
*       char * s: String which is argument
*	printobj * pr: Output file
* Effect: 
*       Writes the string, then its decoded value, to prn
****************************************************************************/

void test_seq(char * s, printobj * pr)
    {
     string * str;

     fprintf(pr->prn,".ts %s",s);

     str = scan_string(&s);

#if debug_effects
	printf("test string: ");
	dump_string(str);
	printf("\n");
#endif

     fprintf(pr->prn," => \"");
     (*pr->write_translated)(str->str,pr);
     fprintf(pr->prn,"\"\n");
    }

/****************************************************************************
*                              screen_font_reset
* Result: void
*       
* Effect: 
*       For all entries defined in screen_xlat, set the screen font
****************************************************************************/

void screen_font_reset()
    {
#ifndef NOMAP
     int i;
     unsigned char size;

     switch(video.adapter)
        { /* what size */
	 case SC_EGA:
		 size = 14;
		 break;
	 case SC_VGA:
		 size = 16;
		 break;
	} /* what size */

     for(i=0; i<256; i++)
        { /* scan entries */
	 if(screen_xlat[i] != NULL)
	    { /* has map */
	     fontset(i, screen_xlat[i]->str,
	     	     (unsigned char)(screen_xlat[i]->len > size 
		     				? size 
						: screen_xlat[i]->len),
		     size);
	    } /* has map */
	} /* scan entries */
#endif
    }

/****************************************************************************
*                            generic_printer_init
* Inputs:
*       printobj * pr: Print object
*	boolean test: true if .ts should be executed
* Result: boolean
*       true if success
*	false if error
* Effect: 
*       Performs generic printer and screen init
****************************************************************************/

boolean generic_printer_init(printobj * pr, boolean test)
    {
     FILE * init;
     int i;
     char initline[81];

     if(pr->prn == NULL) 
	return false;

     for(i=0;i<256;i++) 
	screen_xlat[i] = xlat[i] = NULL;

	for(i=177;i<0400;i++)
	   { /* space out */
	    xlat[i] = &space;
	   } /* space out */

	 init = fopen(cfgname,"r");
	 if(init==NULL) 
	    { /* no init */
	 	return true;	/* no init file, assume ok */
	    } /* no init */

	 lineno = 0;

	 while(true)
	    { /* init printer */
	     fgets(initline,81,init);
	     if(feof(init)) 
		break;
	     /* Process the init line */
	     lineno++;

	     if(diagnostics_on)
		tell(initline);
	     if(initline[0] == '.')
	        { /* directive */
		 if(strncmp(initline,".in",3) == 0)
		    { /* init seq */
		     init_seq(&initline[3],pr);
		     continue;
		    } /* init seq */
		 if(strncmp(initline,".ts",3) == 0)
		    { /* test seq */
		     if(test)
		     	test_seq(&initline[3],pr);
		     continue;
		    } /* test seq */
		 if(strncmp(initline,".fi",3) == 0)
		    { /* fin seq */
		     fin_seq(&initline[3]);
		     continue;
		    } /* fin seq */
		 if(strncmp(initline,".sc",3) == 0)
		    { /* spec */
		     spec_char(&initline[3]);
		     continue;
		    } /* spec */
		 if(strncmp(initline,".sf",3) == 0)
		    { /* screen font */
		     screen_char(&initline[3]);
		     continue;
		    } /* screen font */
		 fprintf(stderr,"%s(%d): Error: Unknown initialization command `%-3.3s'\n",
		 		cfgname,
				lineno,
		 		initline);
		     
		} /* directive */
	    } /* init printer */

	 fclose(init);
	 
	 (*pr->flush)(pr);
	 return true;
     
    }

/****************************************************************************
*			     physical_printer_init
* Inputs:
*	printobj * pr: print file descriptor
*	boolean test: True if .ts directives are to have action
*			false if they are not to have action
* Result: boolean
*	true if successful
*	false if error
* Effect: 
*       Initializes the 'prn' device with whatever string is required
*	Establishes the print conversion strings for the device
* Handles the print directives
*	.in "str"	Printer initialization string
*	.fi "str"	Printer finalization string
*	.sc "chr" "as"	Prints chr as indicated value
*			chr is ascii char, or \nnn
****************************************************************************/

boolean physical_printer_init(printobj * pr, boolean test)
    {
     if(diagnostics_on)
	tell(">physical_printer_init");
	 
     if(!generic_printer_init(pr,test))
        { /* failed */
	 if(diagnostics_on)
	    tell("<physical_printer_init (false)");
	return false;
	} /* failed */

     if(pr64)
        { /* try to write it */
	 if((pr->ready)(pr))
	    { /* go for it */
	     if(diagnostics_on)
		tell("physical_printer_init: writing init string");
	     outstring(init,pr);
	     init = NULL;
	    } /* go for it */
	 else
	    if(diagnostics_on)
	       tell("physical_printer_init: device offline, init deferred");
	} /* try to write it */

     if(diagnostics_on)
	tell("<physical_printer_init (true)");

     return true;
    }

/****************************************************************************
*			    physical_printer_final
* Inputs:
*	printobj * pr: Listing file, open in binary mode
* Effect: 
*       Writes finalization string to listing file
****************************************************************************/

void physical_printer_final(printobj * pr)
    {
     if(!pr64) 
	return;

     if(final == NULL) 
	return;

     if(pr->prn == NULL) 
	return;

     outstring(final,pr);

    }

/****************************************************************************
*			   physical_write_translated
* Inputs:
*       unsigned char * str: String to write
*	printobj * pr: Open device designator
* Effect: 
*       Writes the string to the output device
* Notes:
*	It is assumed the device is ready; this is tested at a higher
*	level.  By the time we get here, it is supposed to be ready
****************************************************************************/

void physical_write_translated(unsigned char * str,printobj * pr)
    {
     short i;

     if(init != NULL)
        { /* perform init */
	 outstring(init,pr);
	 init = NULL;
	} /* perform init */

     for(i=0;i<strlen(str);i++)
        { /* write it */
	 if(xlat[str[i]] == NULL)
	    { /* verbatim */
	     fputc(str[i],pr->prn);
	    } /* verbatim */
	 else
	    { /* translate */
	     outstring(xlat[str[i]],pr);
	    } /* translate */
	} /* write it */
    }

/****************************************************************************
*                           physical_printer_close
* Inputs:
*       printobj * pr:
* Result: void
*       
* Effect: 
*       Closes the printer
****************************************************************************/

void physical_printer_close(printobj * pr)
    {
     if(pr->prn == NULL)
	return;
     fclose(pr->prn);
     pr->prn = NULL;
    }

/****************************************************************************
*                           physical_printer_eject
* Inputs:
*       printobj * pr: Printer object
* Result: void
*       
* Effect: 
*       Ejects the paper
****************************************************************************/

void physical_printer_eject(printobj * pr)
    {
     (*pr->print)(pr,"\f");
    }

/****************************************************************************
*                                physical_test
* Result: boolean
*       false, always
****************************************************************************/

boolean physical_test()
    {
     return false;
    }

/****************************************************************************
*			    physical_printer_clear
* Inputs:
*       printobj * pr: Printer object
* Result: void
*       
* Effect: 
*       Does nothing for physical printer
****************************************************************************/

void physical_printer_clear(printobj * pr)
    {
     /* does nothing */
    }

/****************************************************************************
*                           physical_printer_ready
* Inputs:
*       printobj * pr: Printer object
* Result: boolean
*       true if printer is ready
*	false if printer is not ready
****************************************************************************/

boolean physical_printer_ready(printobj * pr)
    {
     return printer_ready(pr->nlpt);
    }
