home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Otherware
/
Otherware_1_SB_Development.iso
/
amiga
/
print
/
pf_deskj.lzh
/
PF
/
Source
/
print.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-27
|
18KB
|
690 lines
/*---------------------------------------------------------*
| Author: Maurizio Loreti, aka MLO or I3NOO. |
| Address: University of Padova - Department of Physics |
| Via F. Marzolo, 8 - 35131 PADOVA - Italy |
| Phone: (39)(49) 844-313 FAX: (39)(49) 844-245 |
| E-Mail: LORETI at IPDINFN (BITNET); or VAXFPD::LORETI |
| (DECnet) - VAXFPD is node 38.257 i.e. 39169; or |
| LORETI@PADOVA.INFN.IT (INTERNET). |
| Home: Via G. Donizetti 6 - 35010 CADONEGHE (PD) - Italy |
*---------------------------------------------------------*/
#include <stdio.h> /* Standard library */
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <ctype.h>
#include <exec/types.h> /* Amiga specific */
#include <intuition/intuition.h>
#include <graphics/gfxbase.h>
#include <libraries/dos.h>
#include <libraries/reqbase.h>
#include <devices/printer.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include "mlo.h" /* Program specific */
#include "pf2.h"
#include "ext.h"
static Boolean CheckBreak(void); /* Local functions */
static void CheckDefaults(void);
static void ClearPageBuffer(void);
static void ClearThisPage(void);
static void Detab(char *buffer, int length);
static void DoubleLine(char *left, char *right);
static void EjectPage(void);
static void Header(int type);
static void InterLine(void);
static void OutLine(void);
static void ResetPrinter(void);
static void SendBuffer(char *buffer);
static void SendToPrinter(char *fmt, ...);
static void Syntax(void);
/*-----------------------------------------*
| Routines (sorted in alphabetical order) |
*-----------------------------------------*/
static Boolean CheckBreak(void)
{
/**
| Check for CTRL-C
**/
if (SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
return True;
}
return False;
}
static void CheckDefaults(void)
{
/**
| As the name says, this procedure checks for incompatible options
| selected: e.g. the only Landscape fonts are Courier, so to give
| the command PF2 -TL ... is an error. I suppose that the internal
| fonts only are present; otherwise this procedure should be modified.
| Checks:
| -> Letter-Gothic: 12 or 24 cpi; portrait only.
| -> Times: proportional; portrait only.
| -> Courier: 10 or 20 cpi; plus 16.67 cpi for Courier Roman (not
| allowed for Courier Italic).
| -> Landscape/Italic not allowed.
| -> The number of extra spaces inserted before every line must be
| not negative.
**/
switch (Font) {
case GOTHIC:
Orientation = PORTRAIT;
if (Pitch == P10CPI) {
Pitch = P12CPI;
} else {
Pitch = P24CPI;
}
break;
case TIMES:
Orientation = PORTRAIT;
Pitch = PROPORTIONAL;
break;
case COURIER:
if (Pitch == P16_67CPI && Style == ITALIC) {
Pitch = P20CPI;
}
break;
}
if (Orientation == LANDSCAPE) {
Style = ROMAN;
}
if (nBlanks < 0) {
nBlanks = 0;
} else {
if (nBlanks) {
Buffer = inBuffer + nBlanks;
memset(inBuffer, BLANK, nBlanks);
}
}
}
void Cleanup(
int code
){
/**
| Releases all system resources (closes opened files
| and frees heap memory - if any). "code" is the
| status to be returned to the operating system.
**/
windowOff();
if (fp != NULL) fclose(fp);
if (pPB != NULL) {
if (pPB->line[0] != NULL) free(pPB->line[0]);
free(pPB);
}
if (PrinterOpened) CloseDevice((struct IORequest *) IOrequest);
if (IOrequest != NULL) DeleteExtIO((struct IORequest *) IOrequest);
if (printPort != NULL) DeletePort((struct MsgPort *) printPort);
if (!FromCLI) {
int i;
fprintf(stdout, "\nStrike <CR> to continue ... ");
while ( (i = getchar()) != '\n' && i != EOF) { }
}
if (ReqBase != NULL) {
PurgeFiles(&fr);
CloseLibrary((struct Library *) ReqBase);
}
if (GfxBase != NULL) CloseLibrary((struct Library *) GfxBase);
if (IntuitionBase != NULL) CloseLibrary((struct Library *) IntuitionBase);
exit(code);
}
static void ClearPageBuffer(void)
{
/**
| This routine resets the content of the page buffer
| used in the 2-pages-on-a-sheet mode to all-blank
| lines, and the pointer to the next line to be filled
| to the first line in the buffer.
**/
memset(pPB->line[0], BLANK, BUFFER_SIZE);
ThisLine = 0;
}
static void ClearThisPage(void)
{
/**
| Called every end of file: in the normal mode, ejects a page;
| in the 2-pages mode, switches from the left to the right page
| (if there is at least a line on this page), and leaving the
| remainder of the lines on the current page all blank.
**/
switch (PageMode) {
case SINGLE_PAGE:
EjectPage();
break;
case LEFT_PAGE:
if (ThisLine) {
Header(UP);
PageMode = RIGHT_PAGE;
ThisLine = 0;
}
break;
case RIGHT_PAGE:
if (ThisLine) {
FlushBuffers();
PageMode = LEFT_PAGE;
ClearPageBuffer();
}
break;
}
}
static void Detab(
char *buffer,
int length
){
/**
| Translates TAB stops to blanks: TAB stops are assumed at columns
| (1 + N * nTabs), with N = 1, 2, ... ; the default value of nTabs
| is 8, and can be changed using the command switches. In the same
| time non-printable characters are deleted from the input string:
| for non-printable I mean characters from 00 to 037 and 0177, assuming
| that characters over 0177 have special meaning different for every
| computer and that nothing can be said about them.
| The buffer can hold "length" characters only.
**/
char temp[LINE_LENGTH]; /* Internal buffer */
char *pC1, *pC2; /* Temporary pointers */
char *pEnd; /* Pointer to the buffer end */
strcpy(temp, buffer);
pEnd = (buffer + length - 1);
for (pC1 = temp, pC2 = buffer; *pC1 && pC2 < pEnd; pC1++) {
if (*pC1 == TAB) {
do {
*pC2++ = BLANK;
} while (((pC2 - buffer) % nTabs) && (pC2 < pEnd));
} else {
if (isspace(*pC1) || !iscntrl(*pC1)) {
*pC2++ = *pC1;
}
}
}
*pC2 = NIHIL;
}
void DoOutput(
char *FileName
){
/**
| Sends to the printer the given file.
**/
if ((fp = fopen(FileName, "r")) == NULL) {
printf("Can't open input file %s ...", FileName);
return;
}
printf("Printing file %s ... ", FileName);
while (fgets(Buffer, bufferLength, fp) != NULL) {
if (CheckBreak()) {
printf("*** PF2: BREAK ***\n");
EjectPage();
ExitProgram();
}
Detab(Buffer, bufferLength);
OutLine();
}
printf("done.\n");
fclose(fp);
fp = NULL;
ClearThisPage();
}
static void DoubleLine(
char *left,
char *right
){
/**
| Prints a line in the 2-pages mode, the two parameters being
| pointers to the left-page line and the right-page line; a
| blank line is printed if the corresponding pointer is NULL.
**/
if (left == NULL) {
SendToPrinter("%c%*c%c%*c",
V_LINE, TOTAL_LENGTH, BLANK, V_LINE, SEP_LENGTH, BLANK);
} else {
SendToPrinter("%c%*c%.*s%*c%c%*c",
V_LINE, SIDE_LENGTH, BLANK, OUTPUT_LENGTH, left,
SIDE_LENGTH, BLANK, V_LINE, SEP_LENGTH, BLANK);
}
if (right == NULL) {
SendToPrinter("%c%*c%c\r",
V_LINE, TOTAL_LENGTH, BLANK, V_LINE);
} else {
SendToPrinter("%c%*c%.*s%*c%c\r",
V_LINE, SIDE_LENGTH, BLANK, OUTPUT_LENGTH, right,
SIDE_LENGTH, BLANK, V_LINE);
}
}
static void EjectPage(void)
{
SendToPrinter("%c", FORM_FEED);
}
void ExitProgram(void)
{
ResetPrinter();
printf("Good Bye!\n");
Cleanup(SYS_NORMAL_CODE);
}
void FlushBuffers(void)
{
/**
| In the 2-pages mode, prints the current page as
| it is (non filled lines will be left blank).
**/
int i;
switch (PageMode) {
case LEFT_PAGE:
if (!ThisLine) return;
for (i=0; i<ThisLine; i++) {
DoubleLine(pPB->line[i], NULL);
InterLine();
}
for (i=ThisLine; i<PAGE_LENGTH; i++) {
DoubleLine(NULL, NULL);
InterLine();
}
Header(DOWN);
break;
case RIGHT_PAGE:
for (i=ThisLine; i<PAGE_LENGTH; i++) {
DoubleLine(pPB->line[i], NULL);
InterLine();
}
Header(DOWN);
break;
}
}
static void Header(
int type
){
/**
| Prints the top or the down header in the 2-pages mode:
| a solid line separated from the text by a blank line.
**/
memset(Buffer, H_LINE, TOTAL_LENGTH);
if (type == UP) {
SendToPrinter("%c%.*s%c%*c%c%.*s%c\r",
NW, TOTAL_LENGTH, Buffer, NE, SEP_LENGTH,
BLANK, NW, TOTAL_LENGTH, Buffer, NE);
InterLine();
}
DoubleLine(NULL, NULL);
InterLine();
if (type == DOWN) {
SendToPrinter("%c%.*s%c%*c%c%.*s%c\r",
SW, TOTAL_LENGTH, Buffer, SE, SEP_LENGTH,
BLANK, SW, TOTAL_LENGTH, Buffer, SE);
EjectPage();
}
}
void InitPrinter(void)
{
char *PitchID[] = {"10", "12", "16.67", "20", "24"};
UBYTE status[2] = {0, 0};
int dummy;
/**
| Connect properly to printer device
**/
printPort = (PrintIO *) CreatePort(PORT_NAME, 0);
IOrequest = (PrintIO *) CreateExtIO((struct MsgPort *) printPort,
sizeof(PrintIO));
if (!(PrinterOpened = (OpenDevice("printer.device", 0,
(struct IORequest *) IOrequest, 0) == 0))) {
Cleanup(SYS_ABORT_CODE);
}
/**
| Check if the printer is there... Actually, if the printer is connected
| to the serial port, I don't know what to do: in this case I continue,
| knowing that a System requester will come after a while. If the printer
| is connected to the parallel port, printer selected (bit 0), paper out
| (bit 1) and printer offline (bit 2) are checked.
**/
FOREVER {
IOrequest->ios.io_Command = PRD_QUERY;
IOrequest->ios.io_Data = (APTR) status;
IOrequest->ios.io_Flags = 0;
if (DoIO((struct IORequest *) IOrequest)) {
Cleanup(SYS_ABORT_CODE);
}
if (IOrequest->ios.io_Actual == 2) break;
if ((status[0] & 0x7) == 0x4) break;
puts("Please, check if your printer is ready!");
printf("When done, enter <CR> ... ");
while (((dummy = getc(stdin)) != NEWLINE) && (dummy != EOF) ) {}
puts("");
}
/**
| Printer initialisation: see the HP DeskJet 500
| user's manual for explanation...
**/
SendToPrinter("%c&l%do%dD%c(10U%c(s0u", ESC, Orientation, Lpi, ESC, ESC);
if (Pitch == PROPORTIONAL) {
SendToPrinter("1p");
} else {
SendToPrinter("0p%sh", PitchID[Pitch]);
}
SendToPrinter("%dv%ds0b%dt%dQ", Height, Style, Font, Quality);
}
static void InterLine(void)
{
/**
| Writing at 8 lines per inch and 6 points high characters,
| the double page border is not continuous. This procedure
| skips half line, draws the border, then skips another half
| line down to the correct placement for next printing.
**/
SendToPrinter("%c=", ESC);
DoubleLine(NULL, NULL);
SendToPrinter("%c=", ESC);
}
static void OutLine(void)
{
/**
| Outputs a line to the printer.
| In the normal mode, the line is sent to the port after storing a
| carriage return and a line feed after the text, and leaving to the
| printer to deal with form feeds and long lines.
| In the 2-pages mode, the line is truncated to a fixed length: if
| we are in the left page, the line is stored in the internal buffer;
| otherwise, it is printed together with the corresponding left line.
**/
int length, n;
static char *EndOfLine = "\r\n";
length = strlen(inBuffer) - 1;
switch (PageMode) {
case SINGLE_PAGE:
memcpy(inBuffer+length, EndOfLine, 3);
SendBuffer(inBuffer);
break;
case LEFT_PAGE:
if (length > OUTPUT_LENGTH) {
length = OUTPUT_LENGTH;
}
memcpy(pPB->line[ThisLine], Buffer, length);
if (++ThisLine >= PAGE_LENGTH) {
Header(UP);
PageMode = RIGHT_PAGE;
ThisLine = 0;
}
break;
case RIGHT_PAGE:
if ((n = OUTPUT_LENGTH - length) > 0) {
memset(Buffer+length, BLANK, n);
}
DoubleLine(pPB->line[ThisLine], Buffer);
InterLine();
if (++ThisLine >= PAGE_LENGTH) {
Header(DOWN);
PageMode = LEFT_PAGE;
ClearPageBuffer();
}
break;
}
}
static void ResetPrinter(void)
{
/**
| Resets the printer to the default.
**/
SendToPrinter("%cE", ESC);
}
static void SendBuffer(
char *buffer
){
IOrequest->ios.io_Command = PRD_RAWWRITE;
IOrequest->ios.io_Data = (APTR) buffer;
IOrequest->ios.io_Length = strlen(buffer);
IOrequest->ios.io_Flags = 0;
if (DoIO((struct IORequest *) IOrequest)) {
Cleanup(SYS_ABORT_CODE);
}
}
static void SendToPrinter(
char *fmt,
...
){
static char slate[LINE_LENGTH];
va_list vl;
va_start(vl, fmt);
vsprintf(slate, fmt, vl);
va_end(vl);
SendBuffer(slate);
}
void SetSpecialMode(void)
{
/**
| Sets the internal constants for the "two pages on a sheet"
| special mode.
**/
int i;
if ((pPB = malloc(sizeof(PageBuffer))) == NULL) {
fprintf(stderr, "Can't allocate the Page Buffer ...");
Cleanup(SYS_ABORT_CODE);
}
if ((pPB->line[0] = malloc(BUFFER_SIZE)) == NULL) {
fprintf(stderr, "Can't allocate the Line Buffer ...");
Cleanup(SYS_ABORT_CODE);
}
for (i=1; i<PAGE_LENGTH; i++) {
pPB->line[i] = pPB->line[0] + (i * OUTPUT_LENGTH);
}
Orientation = LANDSCAPE;
Font = COURIER;
Style = ROMAN;
Pitch = P16_67CPI;
Height = 6;
Lpi = 8;
nBlanks = 0;
ClearPageBuffer();
}
char **Setup(
int *pArgc,
char **argv
){
/**
| We look into the command line for switches; the function value is
| argv when pointing to the first non-switch argument (i.e. the first
| file name) - if any. If the 2-page mode was requested, the procedure
| allocates from the heap memory the internal buffer for the left-page
| lines, and a service buffer filled with the pointers to the first
| character of every line in the left page; this calling malloc(),
| to make this program more portable.
**/
int i;
char c;
/**
| Error if called from the Workbench, or if called
| from the CLI but without any argument.
**/
if (*pArgc < 2) Syntax();
while (--(*pArgc)) {
if ((*++argv)[0] == '-') {
/**
| A switch ...
**/
for (i=1; (c = (*argv)[i]); i++) {
switch (c) {
case 'l': case 'L':
Orientation = LANDSCAPE;
break;
case 'i': case 'I':
Style = ITALIC;
break;
case 'b': case 'B':
nBlanks = atoi(*argv + ++i);
goto NextSwitch;
case 'a': case 'A':
nTabs = atoi(*argv + ++i);
goto NextSwitch;
case 'g': case 'G':
Font = GOTHIC;
break;
case 't': case 'T':
Font = TIMES;
break;
case 's': case 'S':
Pitch = P16_67CPI;
break;
case 'x': case 'X':
Pitch = P20CPI;
break;
case '6':
Height = 6;
break;
case '8':
Lpi = 8;
break;
case 'd': case 'D':
Quality = DRAFT_Q;
break;
case '2':
PageMode = LEFT_PAGE;
break;
default:
Syntax();
}
}
} else {
/**
| The first file name; perform some
| intialisations, then return to the caller.
**/
if (PageMode != SINGLE_PAGE) {
SetSpecialMode();
} else {
CheckDefaults();
}
return argv;
}
NextSwitch: ;
}
/**
| Here if no file name given; initialise
| the printer, then exit without reset.
**/
CheckDefaults();
InitPrinter();
puts("Printer initialised ... Good bye!");
Cleanup(SYS_NORMAL_CODE);
}
static void Syntax(void)
{
/**
| A syntax error has been detected in the command
| line; a short help is output to the screen.
**/
puts("Usage: PF2 [switches] [file [file [file ... ] ] ]");
puts("Switches: -l : Landscape (default is Portrait);");
puts(" -i : Italic (default is Roman);");
puts(" -bN : insert N Blanks before every output line;");
puts(" -aN : tAb stops every N characters (default: 8);");
puts(" -g : Letter-Gothic font (default is Courier);");
puts(" -t : Times font (default is Courier);");
puts(" -s : Small pitch (Courier: 16.67 cpi; "
"Letter-Gothic: 24 cpi);");
puts(" -x : eXtra-small pitch (20 cpi - for Courier only);");
puts(" -8 : 8 lines per inch (default: 6 lpi);");
puts(" -6 : 6 points high font (default: 12 points);");
puts(" -d : Draft quality (default is Letter quality);");
puts(" -2 : special mode (2 pages on every sheet of paper).\n");
puts("The s/x/l switches are ignored when incompatible with selected font.");
puts("The default pitch is 10 cpi for Courier and 12 cpi for Letter-Gothic");
puts("(Times is a proportional font); all switches different from -d and");
puts("-a will be ignored, if -2 is selected. The switches on the command");
puts("line can be grouped: e.g. -c -8 -s is the same as -c8s; only -bN and");
puts("-aN, if present, must be specified alone or the last in a group. The");
puts("printer is reset to its default, at the completion - UNLESS if no");
puts("file names are given. This program can be interrupted with CTRL-C.\n");
Cleanup(SYS_NORMAL_CODE);
}