Everhart,Glenn From: mckinneyj@cpgtsa.dcs.saic.com Sent: Wednesday, May 13, 1998 5:04 PM To: Info-VAX@Mvb.Saic.Com Subject: Re: Text to PDF converter for VMS? In article <6jbfe4$pfj$1@nnrp1.dejanews.com>, avajhoej@gtech.com writes: > In article <3558C8F7.DC4BFC0B@remove.bankofny.com>, > Kitty Munson wrote: >> Does anyone have a text to PDF converter that runs under VMS? >> Or have an idea where to find one? > > A simple text2pdf.c exist. I think I saw the reference at the > VMS-Web-Daemon mail-list. Try a search for that file on AltaVista. > > Arne > Though I'm not the author of this one, I do use it and did post it some time ago to VMS-Web-Daemon... here's the C code and man page. --------------------------- TEXT2PDF.MAN ------------------------------ .TH TEXT2PDF 1 "V1.1, 02/97" "Local command" .SH NAME text2pdf \- traduction d'un fichier texte en un fichier Acrobat PDF .SH SYNOPSIS .B text2pdf [-options] [filename] .SH DESCRIPTION .B text2pdf makes a 7-bit clean PDF file (version 1.1) from any input file. It reads from standard input or a named file, and writes the PDF file to standard output. .SH OPTIONS There are various options as follows: .TP 1i .B -h show this message .TP .B -f use PostScript (must be in standard 14, default: Courier) .TP .B -I use ISOLatin1Encoding (default) .TP .B -s use font at given pointsize (default 10) .TP .B -v use given line spacing (default 12 points) .TP .B -l lines per page (default 60, determined automatically if unspecified) .TP .B -c maximum characters per line (default 80) .TP .B -t spaces per tab character (default 8) .TP .B -F ignore formfeed characters (^L) .TP .B -A4 use A4 paper (default) .TP .B -A3 use A3 paper (default A4) .TP .B -x independent paper width in points .TP .B -y independent paper height in points .TP .B -2 format in 2 columns .TP .B -L landscape mode .P Note that where one variable is implied by two options, the second option takes precedence for that variable. (e.g. -A4 -y500). In .B landscape mode, page width and height are simply swapped over before formatting, no matter how or when they were defined. .SH BUGS Backspace character is not processed, so the result of .ce .B "nroff -man man.1 | text2pdf > man.pdf" has not a very nice touch. .SH AUTHOR text2pdf v1.1 (c) Phil Smith, 1996., This software can be find at URL: .ce http://www.ep.cs.nott.ac.uk/~pns/pdfcorner/text2pdf/ .SH NOTE Cette page de man est faite par Bertrand Decouty, fvrier 1997. --------------------------- TEXT2PDF.C ------------------------------ /************************************************************************** This ugly, sparsely-commented program is the source for text2pdf version 1.1. It should be ANSI-conforming and compile on most platforms. You'll need to change LF_EXTRA to 1 for machines which write 2 characters for \n. These include PCs, of course. You may distribute the source or compiled versions free of charge. You may not alter the source in any way other than those mentioned above without the permission of the author, Phil Smith . Please send any comments to the author. Copyright (c) Phil Smith, 1996 REVISION HISTORY Version 1.1 11 Oct 96 Added handling of form-feed characters, removed need for tmp file, put reference to resources in each page (avoid bug in Acrobat), changed date format to PDF-1.1 standard. 12 Jun 96 Added check to avoid blank last page 12 Jun 96 Added LINE_END def to get round platform-specific \r, \n etc. 18 Mar 96 Added ISOLatin1Encoding option **************************************************************************/ #include #include #include #include #ifndef SEEK_SET #define SEEK_SET 0 #endif #define LF_EXTRA 0 /* how many extra characters are written for \n */ /* change to 1 for PCs (where \n => ) */ #define LINE_END '\015' /* CR used in xref table */ #define FF 12 /* formfeed character (^L) */ char *appname = "text2pdf v1.1"; char *progname = "text2pdf"; FILE *infile; int pageNo = 0; int pageObs[50000]; int curObj = 5; /* object number being or last written */ long locations[1000]; char font[256]; char *defaultFont = "Courier"; int ISOEnc = 0; int doFFs = 1; int tab = 8; int pointSize = 10; int vertSpace = 12; int lines = 0; int cols = 80; /* max chars per output line */ int columns = 1; /* number of columns */ /* Default paper is Letter size, as in distiller */ int pageHeight = 792; int pageWidth = 612; #ifndef __VMS unsigned char buf[1024]; #else char buf[1024]; #endif unsigned long fpos = 0; void writestr(char *str) { /* Everything written to the PDF file goes through this function. */ /* This means we can keep track of the file position without using */ /* ftell on a real (tmp) file. However, PCs write out 2 characters */ /* for \n, so we need this ugly loop to keep fpos correct */ fpos += strlen(str); while (*str) { if (*str == '\n') fpos += LF_EXTRA; putchar(*str++); } } void WriteHeader(char *title){ struct tm *ltime; time_t clock; char datestring[30]; time(&clock); ltime = localtime(&clock); strftime(datestring, 30, "D:%Y%m%d%H%M%S", ltime); writestr("%PDF-1.1\n"); locations[1] = fpos; writestr("1 0 obj\n"); writestr("<<\n"); sprintf(buf, "/CreationDate (%s)\n", datestring); writestr(buf); sprintf(buf, "/Producer (%s (\\251 Phil Smith, 1996))\n", appname); writestr(buf); if (title) {sprintf(buf, "/Title (%s)\n", title); writestr(buf);} writestr(">>\n"); writestr("endobj\n"); locations[2] = fpos; writestr("2 0 obj\n"); writestr("<<\n"); writestr("/Type /Catalog\n"); writestr("/Pages 3 0 R\n"); writestr(">>\n"); writestr("endobj\n"); locations[4] = fpos; writestr("4 0 obj\n"); writestr("<<\n"); writestr("/Type /Font\n"); writestr("/Subtype /Type1\n"); writestr("/Name /F1\n"); sprintf(buf, "/BaseFont %s\n", font); writestr(buf); if (ISOEnc) { writestr("/Encoding <<\n"); writestr("/Differences [ 0 /.notdef /.notdef /.notdef /.notdef\n"); writestr("/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"); writestr("/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"); writestr("/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"); writestr("/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"); writestr("/.notdef /.notdef /.notdef /.notdef /space /exclam\n"); writestr("/quotedbl /numbersign /dollar /percent /ampersand\n"); writestr("/quoteright /parenleft /parenright /asterisk /plus /comma\n"); writestr("/hyphen /period /slash /zero /one /two /three /four /five\n"); writestr("/six /seven /eight /nine /colon /semicolon /less /equal\n"); writestr("/greater /question /at /A /B /C /D /E /F /G /H /I /J /K /L\n"); writestr("/M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft\n"); writestr("/backslash /bracketright /asciicircum /underscore\n"); writestr("/quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p\n"); writestr("/q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright\n"); writestr("/asciitilde /.notdef /.notdef /.notdef /.notdef /.notdef\n"); writestr("/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"); writestr("/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"); writestr("/dotlessi /grave /acute /circumflex /tilde /macron /breve\n"); writestr("/dotaccent /dieresis /.notdef /ring /cedilla /.notdef\n"); writestr("/hungarumlaut /ogonek /caron /space /exclamdown /cent\n"); writestr("/sterling /currency /yen /brokenbar /section /dieresis\n"); writestr("/copyright /ordfeminine /guillemotleft /logicalnot /hyphen\n"); writestr("/registered /macron /degree /plusminus /twosuperior\n"); writestr("/threesuperior /acute /mu /paragraph /periodcentered\n"); writestr("/cedilla /onesuperior /ordmasculine /guillemotright\n"); writestr("/onequarter /onehalf /threequarters /questiondown /Agrave\n"); writestr("/Aacute /Acircumflex /Atilde /Adieresis /Aring /AE\n"); writestr("/Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave\n"); writestr("/Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve\n"); writestr("/Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash\n"); writestr("/Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn\n"); writestr("/germandbls /agrave /aacute /acircumflex /atilde /adieresis\n"); writestr("/aring /ae /ccedilla /egrave /eacute /ecircumflex\n"); writestr("/edieresis /igrave /iacute /icircumflex /idieresis /eth\n"); writestr("/ntilde /ograve /oacute /ocircumflex /otilde /odieresis\n"); writestr("/divide /oslash /ugrave /uacute /ucircumflex /udieresis\n"); writestr("/yacute /thorn /ydieresis ]\n"); writestr(">>\n"); } writestr(">>\n"); writestr("endobj\n"); locations[5] = fpos; writestr("5 0 obj\n"); writestr("<<\n"); writestr(" /Font << /F1 4 0 R >>\n"); writestr(" /ProcSet [ /PDF /Text ]\n"); writestr(">>\n"); writestr("endobj\n"); } long StartPage(){ long strmPos; locations[++curObj] = fpos; pageObs[++pageNo] = curObj; sprintf(buf, "%d 0 obj\n", curObj); writestr(buf); writestr("<<\n"); writestr("/Type /Page\n"); writestr("/Parent 3 0 R\n"); writestr("/Resources 5 0 R\n"); sprintf(buf, "/Contents %d 0 R\n", ++curObj); writestr(buf); writestr(">>\n"); writestr("endobj\n"); locations[curObj] = fpos; sprintf(buf, "%d 0 obj\n", curObj); writestr(buf); writestr("<<\n"); sprintf(buf, "/Length %d 0 R\n", curObj + 1); writestr(buf); writestr(">>\n"); writestr("stream\n"); strmPos = fpos; writestr("BT\n"); sprintf(buf, "/F1 %d Tf\n", pointSize); writestr(buf); sprintf(buf, "1 0 0 1 50 %d Tm\n", pageHeight - 40); writestr(buf); sprintf(buf, "%d TL\n", vertSpace); writestr(buf); return strmPos; } void EndPage(long streamStart){ long streamEnd; writestr("ET\n"); streamEnd = fpos; writestr("endstream\n"); writestr("endobj\n"); locations[++curObj] = fpos; sprintf(buf, "%d 0 obj\n", curObj); writestr(buf); sprintf(buf, "%lu\n", streamEnd - streamStart); writestr(buf); writestr("endobj\n"); } void WritePages(){ int atEOF = 0; int atFF; int atBOP; long beginstream; int lineNo, charNo; int ch, column; int padding, i; while (!atEOF) { beginstream = StartPage(); column = 1; while (column++ <= columns) { atFF = 0; atBOP = 0; lineNo = 0; while (lineNo++ < lines && !atEOF && !atFF) { writestr("("); charNo = 0; while (charNo++= 32 && ch <= 127) { if (ch == '(' || ch == ')' || ch == '\\') writestr("\\"); sprintf(buf, "%c", (char)ch); writestr(buf); } else { if (ch == 9) { padding = tab - ((charNo - 1) % tab); for (i = 1; i <= padding; i++) writestr(" "); charNo += (padding - 1); } else { if (ch != FF) { /* write \xxx form for dodgy character */ sprintf(buf, "\\%.3o", ch); writestr(buf); } else { /* don't print anything for a FF */ charNo--; } } } } writestr(")'\n"); /* messy stuff to handle formfeeds. Yuk! */ if (ch == EOF) atEOF = 1; if (ch == FF) atFF = 1; if (lineNo == lines) atBOP = 1; if (atBOP) { ch = getc(infile); if (ch == FF) ch = getc(infile); if (ch == EOF) atEOF = 1; else ungetc(ch, infile); } else if (atFF) { ch = getc(infile); if (ch == EOF) atEOF = 1; else ungetc(ch, infile); } } if (column <= columns) { sprintf(buf, "1 0 0 1 %d %d Tm\n", (pageWidth / 2) + 25, pageHeight - 40); writestr(buf); } } EndPage(beginstream); } } void WriteRest(){ long xref; int i; locations[3] = fpos; writestr("3 0 obj\n"); writestr("<<\n"); writestr("/Type /Pages\n"); sprintf(buf, "/Count %d\n", pageNo); writestr(buf); sprintf(buf, "/MediaBox [ 0 0 %d %d ]\n", pageWidth, pageHeight); writestr(buf); writestr("/Kids [ "); for (i = 1; i <= pageNo; i++) {sprintf(buf, "%d 0 R ", pageObs[i]); writestr(buf);} writestr("]\n"); writestr(">>\n"); writestr("endobj\n"); xref = fpos; writestr("xref\n"); sprintf(buf, "0 %d\n", curObj + 1); writestr(buf); /* note that \n is translated by writestr */ sprintf(buf, "0000000000 65535 f %c", LINE_END); writestr(buf); for (i = 1; i <= curObj; i++) { sprintf(buf, "%.10ld 00000 n %c", locations[i], LINE_END); writestr(buf); } writestr("trailer\n"); writestr("<<\n"); sprintf(buf, "/Size %d\n", curObj + 1); writestr(buf); writestr("/Root 2 0 R\n"); writestr("/Info 1 0 R\n"); writestr(">>\n"); writestr("startxref\n"); sprintf(buf, "%ld\n", xref); writestr(buf); writestr("%%EOF\n"); } void ShowHelp(){ printf("\n%s [options] [filename]\n\n", progname); printf(" %s makes a 7-bit clean PDF file (version 1.1) from any input file.\n", progname); printf(" It reads from standard input or a named file, and writes the PDF file\n"); printf(" to standard output.\n"); printf("\n There are various options as follows:\n\n"); printf(" -h\t\tshow this message\n"); printf(" -f\tuse PostScript (must be in standard 14, default: Courier)\n"); printf(" -I\t\tuse ISOLatin1Encoding\n"); printf(" -s\tuse font at given pointsize (default %d)\n", pointSize); printf(" -v\tuse given line spacing (default %d points)\n", vertSpace); printf(" -l\tlines per page (default 60, determined automatically\n\t\tif unspecified)\n"); printf(" -c\tmaximum characters per line (default 80)\n"); printf(" -t\tspaces per tab character (default 8)\n"); printf(" -F\t\tignore formfeed characters (^L)\n"); printf(" -A4\t\tuse A4 paper (default Letter)\n"); printf(" -A3\t\tuse A3 paper (default Letter)\n"); printf(" -x\tindependent paper width in points\n"); printf(" -y\tindependent paper height in points\n"); printf(" -2\t\tformat in 2 columns\n"); printf(" -L\t\tlandscape mode\n"); printf("\n Note that where one variable is implied by two options, the second option\n takes precedence for that variable. (e.g. -A4 -y500)\n"); printf(" In landscape mode, page width and height are simply swapped over before\n formatting, no matter how or when they were defined.\n"); printf("\n%s (c) Phil Smith, 1996\n", appname); } int main(int argc, char **argv){ int i = 1; int tmp, landscape = 0; char *ifilename = NULL; strcpy(font, "/"); strcat(font, defaultFont); infile = stdin; /* default */ while (i < argc) { if (*argv[i] != '-') { /* input filename */ ifilename = argv[i]; if (!(infile = fopen(ifilename, "r"))) { fprintf(stderr, "%s: couldn't open input file `%s'\n", progname, ifilename); exit(0); } } else { switch (*++argv[i]) { case 'h': ShowHelp(); exit(0); case 'f': strcpy(font, "/"); strcat(font, ++argv[i]); break; case 'I': ISOEnc = 1; break; case 'F': doFFs = 0; break; case 's': pointSize = atoi(++argv[i]); if (pointSize < 1) pointSize = 1; break; case 'v': vertSpace = atoi(++argv[i]); if (vertSpace < 1) vertSpace = 1; break; case 'l': lines = atoi(++argv[i]); if (lines < 1) lines = 1; break; case 'c': cols = atoi(++argv[i]); if (cols < 4) cols = 4; break; case '2': columns = 2; break; case 't': tab = atoi(++argv[i]); if (tab < 1) tab = 1; break; case 'A': switch (*++argv[i]) { case '3': pageWidth = 842; pageHeight = 1190; break; case '4': pageWidth = 595; pageHeight = 842; break; default: fprintf(stderr, "%s: ignoring unknown paper size: A%s\n", progname, argv[i]); } break; case 'x': pageWidth = atoi(++argv[i]); if (pageWidth < 72) pageWidth = 72; break; case 'y': pageHeight = atoi(++argv[i]); if (pageHeight < 72) pageHeight = 72; break; case 'L': landscape = 1; break; default: fprintf(stderr, "%s: ignoring invalid switch: -%s\n", progname, argv[i]); } } i++; } if (landscape) { tmp = pageHeight; pageHeight = pageWidth; pageWidth = tmp; } if (lines == 0) lines = (pageHeight - 72) / vertSpace; if (lines < 1) lines = 1; /* happens to give 60 as default */ WriteHeader(ifilename); WritePages(); WriteRest(); return 0;