/************************************************************************** * * (c) Copyright Hewlett-Packard Company, 1998. All rights are * reserved. Copying or other reproduction of this program except * for archival purposes is prohibited without the prior written * consent of Hewlett-Packard Company. * * RESTRICTED RIGHTS LEGEND * * Use, duplication, or disclosure by the Government is subject to * restrictions as set forth in paragraph (b) (3) (B) of the Rights * in Technical Data and Computer Software clause in DAR 7-104.9(a). * * HEWLETT-PACKARD COMPANY * Boise, Idaho, USA ***************************************************************************/ /******************************* NOTICE *************************************** HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE SOFTWARE OR TECHNICAL INFORMATION. HEWLETT-PACKARD COMPANY DOES NOT WARRANT, GUARANTEE OR MAKE ANY REPRESENTATIONS REGARDING THE USE OR THE RESULTS OF THE USE OF THE SOFTWARE OR TECHNICAL INFORMATION IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY, CURRENTNESS, OR OTHERWISE. THE ENTIRE RISK AS TO THE RESULTS AND PERFORMANCE OF THE SOFTWARE OR TECHNICAL INFORMATION IS ASSUMED BY YOU. The exclusion of implied warranties is not permitted by some jurisdictions. The above exclusion may not apply to you. IN NO EVENT WILL HEWLETT-PACKARD COMPANY BE LIABLE TO YOU FOR ANY CONSEQUENTIAL, INCIDENTAL OR INDIRECT DAMAGES (INCLUDING DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION AND THE LIKE) ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE OR TECHNICAL INFORMATION EVEN IF HEWLETT-PACKARD HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. Because some jurisdictions do not allow the exclusion or limitation of liability for consequential or incidental damages, the above limitations may not apply to you. Hewlett-Packard liability to you for actual damages from any cause whatsoever, and regardless of the form of the action (whether in contract, tort including negligence, product liability or otherwise), will be limited to US $50. Copyright (c) 1998, 1999 Hewlett-Packard Company. All rights reserved. Author: Jim D. (Andy) Anderson ******************************************************************************/ #include #include #include #include #include #include #include #include "jetlib.h" #define TRUE 1 #define FALSE 0 #define boolean unsigned char #define MAX_OUT_BUFFER_SIZE 2048 #define BOTTOMSPACE 2 #define STAPLESPACE 5 #define PUNCHEDSPACE 5 #define RIGHTMARGIN 96 #define BOTTOMMARGIN 74 static char* Text2XL_version = "PCL XL Text->XL Filter. Revision: 1.3 "; static char* Text2XL_copyright = "Copyright Hewlett-Packard Company, 1998, 1999. All rights are reserved."; /* Function prototypes to keep somne compilers happy */ static void HP_LogError(HP_pUByte); static void HP_FlushOutBuffer(HP_StreamHandleType, unsigned long, HP_pUByte, HP_SInt32); static void text2xl(HP_StreamHandleType); static FILE *inputFile = NULL; static FILE *outputFile = NULL; static FILE *errOutputFile = NULL; static boolean errorLogged = FALSE; /****************************************************************** * * For XL, the default values to print a text page. * These variables may be replaced later, when we allow configuring * the filter for various text sizes, fonts, paper sizes, etc. * ******************************************************************/ HP_UByte *ListFontName = "Courier "; HP_UByte *MediaType = "Prepunched"; HP_UByte pageSide[2] = {HP_eFrontMediaSide, HP_eBackMediaSide}; HP_UInt16 XRes = 600; HP_UInt16 YRes = 600; HP_SInt32 CopyCount = 1; HP_BOOL Collate = FALSE; HP_BOOL Repeat = FALSE; HP_BOOL Duplex = FALSE; HP_Real32 PageXScale = 1.0; HP_Real32 PageYScale = 1.0; HP_UInt16 SymbolSet = 590; HP_UByte ListOrientation = HP_ePortraitOrientation; HP_UByte PaperSize = HP_eLetterPaper; HP_Real32 CharSize = 83.33; boolean AutoCR = TRUE; boolean pageNumbering = FALSE; boolean stapling = FALSE; boolean threeHole = FALSE; HP_SInt16 XSpacing[256] = { 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, }; /****************************************************************** * * For internal use, These values must be calculated from the above * values. For instance, the character size would be used to determine * the MacColumns setting for fixed pitch fonts. I've made no provisions * for variable width fonts. * * I use 4 column tabs. I _like_ 4 column tabs. * ******************************************************************/ HP_UInt16 MaxColumns = RIGHTMARGIN; HP_UInt16 MaxRows = BOTTOMMARGIN; HP_UInt16 YSpacing = 85; HP_UInt16 TabWidth = 4; /* Action codes. Each character read from the file deternines an action code */ /* Normally, printable characters just have an action code of NORMAL */ typedef enum {NORMAL, FLUSH, CR, LF, TAB, BS, CRLF, FF, ENDSESSION} ControlCodes ; /********************************************************************* * * Logs an error string to an output device and sets an error flag * ********************************************************************/ static void HP_LogError(HP_pUByte outBuff) { fputs(outBuff, errOutputFile); errorLogged = TRUE; } /********************************************************************* * * Flushes the output buffer to the output device. This is required * by jetlib.c to allow it to handle the user's data buffer. * ********************************************************************/ static void HP_FlushOutBuffer(HP_StreamHandleType pStream, unsigned long cookie, HP_pUByte pOutBuffer, HP_SInt32 libBuffLen) { fwrite((const void *)pOutBuffer, (size_t)1, (size_t)libBuffLen, outputFile); if (ferror(outputFile)) { HP_LogError("Buffer Flush to output failed\n"); } pStream->HP_CurrentBufferLen = 0; /* set outbuffer to empty */ } /********************************************************************* * * Draws a line and prints the current page number at the bottom * of each page when the -p option is selected * ********************************************************************/ static void printPageNumber(HP_StreamHandleType pStream, HP_UInt32 pageNumber) { HP_UByte buff[80]; HP_SInt16 space[80]; HP_UInt16 x, y = 0, z; if (pageNumbering) { HP_SetPenSource_Gray1(pStream, 0); HP_SetPenWidth_1(pStream, 2); HP_SetCursor_1(pStream, 0, y = ((MaxRows + (BOTTOMSPACE-1)) * YSpacing)); /* Set the cursor to the start of the line */ HP_LinePath_2(pStream, MaxColumns * XSpacing[32], y); /* now move the cursor to the end of the line */ HP_PaintPath_1(pStream); /* Paint the resulting path */ z = sprintf(buff, "Page: %ld", pageNumber); y = 0; for ( x = 0 ; x < z ; x++ ) y += (space[x] = XSpacing[buff[x]]); y = ((MaxColumns * XSpacing[32]) / 2) - (y/2); /* Center the page number */ HP_SetCursor_1(pStream, y, (MaxRows + BOTTOMSPACE) * YSpacing); HP_Text_1(pStream, buff, z, space, z); HP_NewPath_1(pStream); } } /******************************************************************* * * The actual text handler. Two stage. * Stage 1, get the character and classify it. Set an action code * for followup if need be. * * Stage 2, execute the action code, do this in a loop as one action might * provoke another. * ******************************************************************/ static void text2xl(HP_StreamHandleType pStream) { boolean inSession = TRUE; /* True while printing file */ HP_SInt32 curX; /* cursor X coordinate */ HP_SInt32 curY; /* Cursor Y coordinate */ HP_SInt32 buffX; /* Actual X cursor position to print buffer at */ HP_SInt32 buffY; /* Actual Y cursor position to print buffer at */ HP_UInt16 tOffset = 0; /* for caclulating TAB spacing */ HP_SInt16 curColumn = 0; /* Column counter */ HP_UInt16 curRow = 0; /* Row (line) Counter */ HP_SInt16 curChar = 0; /* Character read from file/pipe */ HP_UInt32 index = 0; /* Index into the local character array */ HP_UInt32 pageNumber = 0; /* Current page number */ HP_UByte lineBuff[256] = { 0 }; /* array of characters to print */ HP_SInt16 space[256] = { 0 }; /* Array of X displacements for characters */ ControlCodes actionCode = NORMAL; /* Action code */ if (pageNumbering) MaxRows -= BOTTOMSPACE; /* Saves room for page number */ fprintf(outputFile, "\x1B%%-12345X");/* UEL */ if (Collate && !Repeat) fprintf(outputFile, "@PJL SET QTY=%d\n", CopyCount); /* The printer has a disk or enough memory to collate for us */ fprintf(outputFile, "@PJL ENTER LANGUAGE = PCLXL\n"); /* Enter XL */ fprintf(outputFile, ") HP-PCL XL;2;0;Comment: %s (%s)\n", Text2XL_version, __DATE__); /* Stream Header */ HP_BeginSession_1(pStream, XRes, YRes, HP_eInch); do { if (threeHole) { /* * An example of how you can add an attribute * to a any JetLIB operator call when you need * extra and don't want to rewrite JetLIB. * In this case, if threeHole is TRUE, a MediaType * attribute will be added via low level code to * the basic BeginPage operator. */ HP_AttrUByteArray(pStream, MediaType, (HP_UInt32)strlen(MediaType)); HP_AttrId(pStream, HP_MediaType); } if (Duplex) { /* Add duplex info to BeginPage if needed */ HP_AttrUByte(pStream, HP_eDuplexVerticalBinding); HP_AttrId(pStream, HP_DuplexPageMode); /* * Insure we get the first page as front in case * of multiple copies when duplexing */ HP_AttrUByte(pStream, HP_eFrontMediaSide); HP_AttrId(pStream, HP_DuplexPageSide); } HP_BeginPage_1(pStream, ListOrientation, PaperSize); /* */ HP_SetPageOrigin_1(pStream, 100, 100); HP_SetPageScale_1(pStream, PageXScale, PageYScale); HP_SetColorSpace_1(pStream, HP_eGray); HP_SetClipMode_1(pStream, HP_eEvenOdd); HP_NewPath_1(pStream); HP_SetBrushSource_Gray1(pStream, 0); HP_SetFont_1(pStream, ListFontName, strlen(ListFontName), CharSize, SymbolSet); /* */ memset(lineBuff, 0, sizeof(lineBuff)); MaxColumns = RIGHTMARGIN; index = curColumn = curRow = 0; /* defaultValues */ if (stapling) curRow = STAPLESPACE; if (threeHole) curColumn = PUNCHEDSPACE; curY = buffY = (1+curRow) * YSpacing; /* 1+curRow because character prints UP from Y position */ curX = buffX = curColumn * XSpacing[32]; pageNumber = 0; actionCode = NORMAL; while (inSession) { curChar = fgetc(inputFile); switch(curChar) { case EOF: actionCode = ENDSESSION; break; default: /* Put character into line buffer */ lineBuff[index] = (HP_UByte)curChar; curX += space[index++] = XSpacing[(HP_UByte)curChar]; curColumn++; if (curColumn>= MaxColumns) actionCode = CRLF; /* We do automatic CRLF around here */ if (index > 255) /* If true, the lineBuff ran out of space */ actionCode = FLUSH; break; case 0x0A: /* Line Feed */ if (AutoCR) /* Are we adding the CR to LF? */ actionCode = CRLF; else actionCode = LF; break; case 0x0D: /* Carriage Return */ actionCode = CR; break; case 0x09: /* Tab */ actionCode = TAB; break; case 0x0C: /* Form Feed */ actionCode = FF; break; case 0x7F: /* Back Space */ actionCode = BS; break; } while (actionCode != NORMAL) /* Stay in this loop till actionCode=NORMAL */ { /* * Because things are not NORMAL, we should go ahead and flush * any text out to the binary file. First we send the * cursor postion which we've been updating and then the text */ if (index) { HP_SetCursor_1(pStream, buffX, buffY); HP_Text_1(pStream, lineBuff, index, space, index); HP_NewPath_1(pStream); memset(lineBuff, index = 0, sizeof(lineBuff)); } switch(actionCode) { default: /* * If we get this "default", something serious is * broken and we should exit. Print an error message * then fall through ending the session. */ HP_LogError("Unknown Action Code Encountered - Aborting.\n"); case ENDSESSION: /* * End of file, End of Job. We need to set a flag and * exit back to main(). Set inSession FALSE and fall * through. */ inSession = FALSE; case NORMAL: /* * Some compilers complain if not * all enumerations are handled by * a switch() statement. */ case FLUSH: /* * We already flushed the line buffer to the page. * * FLUSH is an emergency action that prevents overwriting * the stack in case of MaxColumns > 256. */ actionCode = NORMAL; break; case FF: /* Form Feed */ /* * Send out an EndPage to close the page and * use BeginPage and all the required settings * to start a new page. Reset the cursor to the * upper left corner, reset row/column counters * and get back to printing. */ pageNumber++; printPageNumber(pStream, pageNumber); if (!Collate && !Repeat) HP_EndPage_2(pStream, CopyCount); else HP_EndPage_1(pStream); /* * We don't need to resend duplex or media type info. * It stays set throughout the session. */ HP_BeginPage_1(pStream, ListOrientation, PaperSize); HP_SetPageOrigin_1(pStream, 100, 100); HP_SetPageScale_1(pStream, PageXScale, PageYScale); HP_SetColorSpace_1(pStream, HP_eGray); HP_SetClipMode_1(pStream, HP_eEvenOdd); HP_NewPath_1(pStream); HP_SetBrushSource_Gray1(pStream, 0); HP_SetFont_1(pStream, ListFontName, strlen(ListFontName), CharSize, SymbolSet); actionCode = NORMAL; curRow = curColumn = 0; MaxColumns = RIGHTMARGIN; if (stapling) curRow = STAPLESPACE; if (threeHole) { if (Duplex && (pageSide[pageNumber & 1] == HP_eBackMediaSide)) /* Backside, decrease maximum line length */ MaxColumns = RIGHTMARGIN-PUNCHEDSPACE; else /* Frontside or !Duplex, start off inset */ curColumn = PUNCHEDSPACE; } curY = (1+curRow) * YSpacing; curX = curColumn * XSpacing[32]; break; case CRLF: /*Carriage Return/LineFeed */ /* * Move the cursor down one line and back to the * left edge of the page. Reset the column count, and * clear the buffer. If the maximum number of lines has * been printed, set the action code to FF (FormFeed), * otherwise, set to NORMAL. */ curRow++; if (curRow >= MaxRows) actionCode = FF; else { actionCode = NORMAL; curX = 0; curY+= YSpacing; curColumn = 0; if (threeHole) { if (Duplex && (pageSide[pageNumber & 1] == HP_eBackMediaSide)) MaxColumns = RIGHTMARGIN-PUNCHEDSPACE; else curColumn = PUNCHEDSPACE; } curX = curColumn * XSpacing[32]; } break; case LF: /* Line Feed */ /* * Move the cursor one line down and if the maximum * number of lines has been printed, set the action * code to FF, otherwise, set to NORMAL and keep * going. */ curRow++; if (curRow >= MaxRows) actionCode = FF; else { actionCode = NORMAL; curY+= YSpacing; } break; case CR: /* Carriage Return */ /* * Move the cursor to the left margin of the page and * clear the buffer. set the actionCode to NORMAL * and keep going. */ if (threeHole) { if (Duplex && (pageSide[pageNumber & 1] == HP_eBackMediaSide)) MaxColumns = RIGHTMARGIN-PUNCHEDSPACE; else curColumn = PUNCHEDSPACE; } curX = curColumn * XSpacing[32]; actionCode = NORMAL; break; case BS: /* Back Space */ /* * Move the cursor left one space character width. CLear * the buffer and decrement the column count. set the * actionCode to NORMAL and keep going. */ curX -= XSpacing[32]; if (curX < 0) curX = 0; curColumn--; if (curColumn < 0) curColumn = 0; actionCode = NORMAL; break; case TAB: /* Tab Character */ /* * Move the cursor right to the next logical tab column * by calculating the distance in characters, then * adding that many space character displacements to * the cursor's X position. Add the distance to the * column count. set the actionCode to NORMAL and * keep going. */ tOffset = curColumn % TabWidth; if (tOffset) { curX += tOffset * XSpacing[32]; curColumn = tOffset; } else { curX += TabWidth * XSpacing[32]; curColumn += TabWidth; } if (curColumn > MaxColumns) actionCode = CRLF; else { actionCode = NORMAL; } curColumn = 0; break; } HP_FlushStreamBuffer(pStream); buffX = curX; buffY = curY; } } pageNumber++; printPageNumber(pStream, pageNumber); if (!Collate && !Repeat) HP_EndPage_2(pStream, CopyCount); else HP_EndPage_1(pStream); } while (Repeat && --CopyCount); HP_EndSession_1(pStream); fprintf(outputFile, "\x1B%%-12345X");/* UEL */ HP_FlushStreamBuffer(pStream); } /**************************************************************** * * Regular command line parser. Used for standard UNIX and DOS * ****************************************************************/ main (int argc, HP_UByte *argv[]) { int argIndex; HP_UByte *inFileName = NULL; HP_UByte *outFileName = NULL; HP_UByte *errFileName = NULL; HP_StreamHandleType pStream = NULL; boolean doParse = TRUE; boolean printUsage = FALSE; boolean gotInFile = FALSE; if (argc > 1) { for (argIndex = 1; doParse && (argIndex < argc); ) { switch (argv[argIndex][0]) { default: if (!gotInFile) { gotInFile = TRUE; inFileName = argv[argIndex]; } argIndex++; break; case '-': switch (argv[argIndex][1]) { case 'h': /* both H and h to be case insensative */ case 'H': case '?': doParse = FALSE; printUsage = TRUE; argIndex++; break; case 'o': case 'O': outFileName = argv[argIndex + 1]; argIndex = argIndex + 2; break; case 'e': case 'E': errFileName = argv[argIndex + 1]; argIndex = argIndex + 2; break; case 'p': case 'P': pageNumbering = TRUE; argIndex++; break; case 'D': case 'd': Duplex = TRUE; argIndex++; break; case '3': threeHole = TRUE; argIndex++; break; case 'S': case 's': stapling = TRUE; argIndex++; break; case 'T': case 't': sscanf(argv[argIndex + 1], "%d", &TabWidth); argIndex = argIndex + 2; break; case 'C': case 'c': switch (argv[argIndex][2]) { default: Collate = FALSE; Repeat = FALSE; break; case 'P': case 'p': Collate = TRUE; Repeat = FALSE; break; case 'C': case 'c': Collate = FALSE; Repeat = TRUE; break; } sscanf(argv[argIndex + 1], "%d", &CopyCount); if (CopyCount < 0) CopyCount *= -1; argIndex = argIndex + 2; break; default: argIndex++; break; } break; } } /* end of for loop */ } /* Open error output file for -e parameter */ if (!errFileName) errOutputFile = stderr; else { errOutputFile = fopen(errFileName, "w+"); if (!errOutputFile) { errOutputFile = stderr; fprintf(errOutputFile, "Could Not Open Error Output File: %s\n", errFileName); } } fprintf(errOutputFile, "%s (%s)\n", Text2XL_version, __DATE__); fprintf(errOutputFile, "%s\n", Text2XL_copyright); if (printUsage) { fprintf(errOutputFile, "\nusage as a filter:\n"); fprintf(errOutputFile, " tail textfile | text2xl [ options ] > [output]\n"); fprintf(errOutputFile, "\nusage as a file converter:\n"); fprintf(errOutputFile, " text2xl [ options ] [inFile] [-o ]\n"); fprintf(errOutputFile, "\nCommand Line Options:\n"); fprintf(errOutputFile, " -? | -h This help output\n"); fprintf(errOutputFile, " -o = path of the output file (default: stdout)\n"); fprintf(errOutputFile, " -e = path for error & status output (default: stderr)\n"); fprintf(errOutputFile, " -p = Print Page Number at the bottom of each page\n"); fprintf(errOutputFile, " -s = Adjusts top margin down for a staple in upper left corner\n"); fprintf(errOutputFile, " -3 = Selects 3 hole (prepunched) media type & adjust margins to fit\n"); fprintf(errOutputFile, " -d = Selects duplex output\n"); fprintf(errOutputFile, " -t n = Set tab stops at n space characters along the line\n"); fprintf(errOutputFile, " -c n = Copy Count, n = copies to print\n"); fprintf(errOutputFile, " -cc n = Host Collated Copies\n"); fprintf(errOutputFile, " -cp n = Printer Collated Copies\n"); doParse = FALSE; } if (Duplex && (CopyCount > 1) && !(Collate | Repeat)) { fprintf(errOutputFile, "Error: Multiple duplexed copies are only available with the -cp or -cc options\No Conversion\n"); doParse = FALSE; } if (doParse) { if (!outFileName) outputFile = stdout; else outputFile = fopen(outFileName, "wb"); if (!inFileName) inputFile = stdin; else inputFile = fopen(inFileName, "rb"); pStream = HP_NewStream(MAX_OUT_BUFFER_SIZE, HP_FlushOutBuffer, 0/*cookie*/); if (pStream && outputFile && inputFile) { /* Start the conversion, make a the call from here */ text2xl(pStream); fprintf(errOutputFile, "Conversion Complete.\n"); } else { if (!pStream) fprintf(errOutputFile, "Could Not Allocate Stream Memory: %d Bytes Requested\n", MAX_OUT_BUFFER_SIZE); if (!outputFile) fprintf(errOutputFile, "Could Not Open Output File: %s\n", outFileName); if (!inputFile) fprintf(errOutputFile, "Could Not Open Input File: %s\n", inFileName); fprintf(errOutputFile, "Conversion Aborted.\n"); errorLogged = TRUE; } if (pStream) HP_FinishStream(pStream); if (outputFile && (outputFile != stdout)) fclose(outputFile); if (inputFile && (inputFile != stdin)) fclose(inputFile); } if (errOutputFile != stderr) fclose(errOutputFile); return(errorLogged); }