diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2016-06-26 18:15:09 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2016-06-26 18:15:09 +0000 |
commit | aab4792db8e0adcaf63cf57a1f5e0b18666dae47 (patch) | |
tree | bbfa9c4e12783d2dfd785c4e10964366550e9a60 /generator | |
parent | fe14f983ade44baa0794e4ce58a1a5334e46cf68 (diff) | |
download | netpbm-mirror-aab4792db8e0adcaf63cf57a1f5e0b18666dae47.tar.gz netpbm-mirror-aab4792db8e0adcaf63cf57a1f5e0b18666dae47.tar.xz netpbm-mirror-aab4792db8e0adcaf63cf57a1f5e0b18666dae47.zip |
Promote Development to Advanced as Release 10.75.00
git-svn-id: http://svn.code.sf.net/p/netpbm/code/advanced@2803 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'generator')
-rw-r--r-- | generator/Makefile | 5 | ||||
-rw-r--r-- | generator/pbmtext.c | 425 | ||||
-rw-r--r-- | generator/pbmtextps.c | 722 | ||||
-rwxr-xr-x | generator/pgmcrater | 20 | ||||
-rwxr-xr-x | generator/ppmrainbow | 41 |
5 files changed, 798 insertions, 415 deletions
diff --git a/generator/Makefile b/generator/Makefile index d0ea6b60..5120008c 100644 --- a/generator/Makefile +++ b/generator/Makefile @@ -16,10 +16,13 @@ include $(BUILDDIR)/config.mk PORTBINARIES = pamcrater pamgauss pamgradient \ pamseq pamshadedrelief pamstereogram \ - pbmpage pbmmake pbmtext pbmtextps pbmupc \ + pbmpage pbmmake pbmtext pbmupc \ pgmkernel pgmmake pgmnoise pgmramp \ ppmcie ppmcolors ppmforge ppmmake ppmpat ppmrough ppmwheel \ +ifneq ($(DONT_HAVE_PROCESS_MGMT),Y) +PORTBINARIES += pbmtextps +endif # We don't include programs that have special library dependencies in the # merge scheme, because we don't want those dependencies to prevent us # from building all the other programs. diff --git a/generator/pbmtext.c b/generator/pbmtext.c index 8ae28616..cfb858a6 100644 --- a/generator/pbmtext.c +++ b/generator/pbmtext.c @@ -20,6 +20,7 @@ #include "pm_c_util.h" #include "mallocvar.h" +#include "nstring.h" #include "shhopt.h" #include "pbm.h" #include "pbmfont.h" @@ -33,13 +34,14 @@ struct CmdlineInfo { const char * text; /* text from command line or NULL if none */ const char * font; /* -font option value or NULL if none */ const char * builtin; /* -builtin option value or NULL if none */ - unsigned int dump; - /* undocumented dump option for installing a new built-in font */ - float space; /* -space option value or default */ - unsigned int width; /* -width option value or zero */ - int lspace; /* lspace option value or default */ - unsigned int nomargins; /* -nomargins */ - unsigned int verbose; + float space; /* -space option value or default */ + int lspace; /* -lspace option value or default */ + unsigned int width; /* -width option value or zero */ + unsigned int nomargins; /* -nomargins option specified */ + unsigned int dryrun; /* -dry-run option specified */ + unsigned int verbose; /* -verbose option specified */ + /* undocumented option */ + unsigned int dumpsheet; /* font data sheet in PBM format for -font */ }; @@ -61,21 +63,22 @@ parseCommandLine(int argc, const char ** argv, MALLOCARRAY_NOFAIL(option_def, 100); option_def_index = 0; /* incremented by OPTENTRY */ - OPTENT3(0, "font", OPT_STRING, &cmdlineP->font, NULL, 0); - OPTENT3(0, "builtin", OPT_STRING, &cmdlineP->builtin, NULL, 0); - OPTENT3(0, "dump", OPT_FLAG, NULL, &cmdlineP->dump, 0); - OPTENT3(0, "space", OPT_FLOAT, &cmdlineP->space, NULL, 0); - OPTENT3(0, "width", OPT_UINT, &cmdlineP->width, NULL, 0); - OPTENT3(0, "lspace", OPT_INT, &cmdlineP->lspace, NULL, 0); - OPTENT3(0, "nomargins", OPT_FLAG, NULL, &cmdlineP->nomargins, 0); - OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); + OPTENT3(0, "font", OPT_STRING, &cmdlineP->font, NULL, 0); + OPTENT3(0, "builtin", OPT_STRING, &cmdlineP->builtin, NULL, 0); + OPTENT3(0, "space", OPT_FLOAT, &cmdlineP->space, NULL, 0); + OPTENT3(0, "lspace", OPT_INT, &cmdlineP->lspace, NULL, 0); + OPTENT3(0, "width", OPT_UINT, &cmdlineP->width, NULL, 0); + OPTENT3(0, "nomargins", OPT_FLAG, NULL, &cmdlineP->nomargins, 0); + OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); + OPTENT3(0, "dry-run", OPT_FLAG, NULL, &cmdlineP->dryrun, 0); + OPTENT3(0, "dump-sheet", OPT_FLAG, NULL, &cmdlineP->dumpsheet, 0); /* Set the defaults */ - cmdlineP->font = NULL; + cmdlineP->font = NULL; cmdlineP->builtin = NULL; - cmdlineP->space = 0.0; - cmdlineP->width = 0; - cmdlineP->lspace = 0; + cmdlineP->space = 0.0; + cmdlineP->width = 0; + cmdlineP->lspace = 0; opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ @@ -128,6 +131,7 @@ parseCommandLine(int argc, const char ** argv, } cmdlineP->text = text; } + free(option_def); } @@ -170,16 +174,12 @@ computeFont(struct CmdlineInfo const cmdline, if (cmdline.verbose) reportFont(fontP); - if (cmdline.dump) { - pbm_dumpfont(fontP); - exit(0); - } *fontPP = fontP; } -struct text { +struct Text { char ** textArray; /* malloc'ed */ unsigned int allocatedLineCount; unsigned int lineCount; @@ -188,7 +188,7 @@ struct text { static void -allocTextArray(struct text * const textP, +allocTextArray(struct Text * const textP, unsigned int const maxLineCount, unsigned int const maxColumnCount) { @@ -198,7 +198,7 @@ allocTextArray(struct text * const textP, MALLOCARRAY_NOFAIL(textP->textArray, maxLineCount); for (line = 0; line < maxLineCount; ++line) { - if(maxColumnCount > 0) + if (maxColumnCount > 0) MALLOCARRAY_NOFAIL(textP->textArray[line], maxColumnCount+1); else textP->textArray[line] = NULL; @@ -209,7 +209,7 @@ allocTextArray(struct text * const textP, static void -freeTextArray(struct text const text) { +freeTextArray(struct Text const text) { unsigned int line; @@ -221,10 +221,16 @@ freeTextArray(struct text const text) { +enum FixMode {SILENT, /* convert silently */ + WARN, /* output message to stderr */ + QUIT /* abort */ }; + + static void fixControlChars(const char * const input, struct font * const fontP, - const char ** const outputP) { + const char ** const outputP, + enum FixMode const fixMode) { /*---------------------------------------------------------------------------- Return a translation of input[] that can be rendered as glyphs in the font 'fontP'. Return it as newly malloced *outputP. @@ -233,9 +239,10 @@ fixControlChars(const char * const input, Remove any trailing newline. (But leave intermediate ones as line delimiters). - - Turn anything that isn't a code point in the font to a single space - (which isn't guaranteed to be in the font either, of course). + + Depending on value of fixMode, turn anything that isn't a code point + in the font to a single space (which isn't guaranteed to be in the + font either, of course). -----------------------------------------------------------------------------*/ /* We don't know in advance how big the output will be because of the tab expansions. So we make sure before processing each input @@ -281,10 +288,17 @@ fixControlChars(const char * const input, output[outCursor++] = ' '; } else if (!fontP->glyph[(unsigned char)input[inCursor]]) { /* Turn this unknown char into a single space. */ - if(fontP->glyph[(unsigned char) ' '] == NULL) + if (fontP->glyph[(unsigned char) ' '] == NULL) pm_error("space character not defined in font"); - else + else if (fixMode == QUIT) + pm_error("character %d not defined in font", + (unsigned int )input[inCursor] ); + else { + if (fixMode == WARN) + pm_message("converting character %d to space", + (unsigned int) input[inCursor] ); output[outCursor++] = ' '; + } } else output[outCursor++] = input[inCursor]; @@ -300,17 +314,16 @@ fixControlChars(const char * const input, static void -fillRect(bit** const bits, - int const height, - int const width, - bit const color) { +clearBackground(bit ** const bits, + int const cols, + int const rows) { unsigned int row; - - for (row = 0; row < height; ++row) { - unsigned int col; - for (col = 0; col < width; ++col) - bits[row][col] = color; + + for (row = 0; row < rows; ++row) { + unsigned int colChar; + for (colChar = 0; colChar < pbm_packed_bytes(cols); ++colChar) + bits[row][colChar] = 0x00; } } @@ -514,7 +527,7 @@ getCharsWithinWidth(char const line[], static void -insertCharacter(const struct glyph * const glyph, +insertCharacter(const struct glyph * const glyphP, int const toprow, int const leftcol, unsigned int const cols, @@ -526,19 +539,20 @@ insertCharacter(const struct glyph * const glyph, -----------------------------------------------------------------------------*/ unsigned int glyph_y; /* Y position within the glyph */ - if (leftcol + glyph->x < 0 || - leftcol + glyph->x + glyph->width > cols || + if (leftcol + glyphP->x < 0 || + leftcol + glyphP->x + glyphP->width > cols || toprow < 0 || - toprow + glyph->height >rows ) + toprow + glyphP->height >rows ) pm_error("internal error. Rendering out of bounds"); - for (glyph_y = 0; glyph_y < glyph->height; ++glyph_y) { + for (glyph_y = 0; glyph_y < glyphP->height; ++glyph_y) { unsigned int glyph_x; /* position within the glyph */ - for (glyph_x = 0; glyph_x < glyph->width; ++glyph_x) { - if (glyph->bmap[glyph_y * glyph->width + glyph_x]) - bits[toprow + glyph_y][leftcol + glyph->x + glyph_x] = - PBM_BLACK; + for (glyph_x = 0; glyph_x < glyphP->width; ++glyph_x) { + if (glyphP->bmap[glyph_y * glyphP->width + glyph_x]) { + unsigned int const col = leftcol + glyphP->x + glyph_x; + bits[toprow+glyph_y][col/8] |= PBM_BLACK << (7-col%8); + } } } } @@ -547,14 +561,15 @@ insertCharacter(const struct glyph * const glyph, static void insertCharacters(bit ** const bits, - struct text const lp, + struct Text const lp, struct font * const fontP, int const topmargin, int const leftmargin, float const intercharacter_space, unsigned int const cols, unsigned int const rows, - int const lspace) { + int const lspace, + bool const fixedAdvance) { /*---------------------------------------------------------------------------- Render the text 'lp' into the image 'bits' using font *fontP and putting 'intercharacter_space' pixels between characters and @@ -581,14 +596,17 @@ insertCharacters(bit ** const bits, char const currentChar = lp.textArray[line][cursor]; unsigned int const glyphIndex = (unsigned char) currentChar; struct glyph * const glyphP = fontP->glyph[glyphIndex]; - int const toprow = row + fontP->maxheight + fontP->y - - glyphP->height - glyphP->y; + int const toprow = + row + fontP->maxheight + fontP->y - glyphP->height - glyphP->y; /* row number in image of top row in glyph */ assert(glyphP != NULL); insertCharacter(glyphP, toprow, leftcol, cols, rows, bits); + if (fixedAdvance) + leftcol += fontP->maxwidth; + else advancePosition(leftcol, currentChar, glyphP, intercharacter_space, accumulatedIcs, &leftcol, &accumulatedIcs); @@ -599,11 +617,11 @@ insertCharacters(bit ** const bits, static void -flowText(struct text const inputText, +flowText(struct Text const inputText, int const targetWidth, struct font * const fontP, float const intercharacterSpace, - struct text * const outputTextP, + struct Text * const outputTextP, unsigned int * const maxleftbP) { unsigned int outputLineNum; @@ -650,7 +668,7 @@ flowText(struct text const inputText, static void -truncateText(struct text const inputText, +truncateText(struct Text const inputText, unsigned int const targetWidth, struct font * const fontP, float const intercharacterSpace, @@ -685,16 +703,17 @@ truncateText(struct text const inputText, static void getText(char const cmdlineText[], struct font * const fontP, - struct text * const inputTextP) { + struct Text * const inputTextP, + enum FixMode const fixMode) { - struct text inputText; + struct Text inputText; if (cmdlineText) { MALLOCARRAY_NOFAIL(inputText.textArray, 1); inputText.allocatedLineCount = 1; inputText.lineCount = 1; fixControlChars(cmdlineText, fontP, - (const char**)&inputText.textArray[0]); + (const char**)&inputText.textArray[0], fixMode); } else { /* Read text from stdin. */ @@ -730,7 +749,8 @@ getText(char const cmdlineText[], if (textArray == NULL) pm_error("out of memory"); } - fixControlChars(buf, fontP, (const char **)&textArray[lineCount]); + fixControlChars(buf, fontP, + (const char **)&textArray[lineCount], fixMode); if (textArray[lineCount] == NULL) pm_error("out of memory"); ++lineCount; @@ -745,7 +765,62 @@ getText(char const cmdlineText[], static void -computeImageHeight(struct text const formattedText, +computeMargins(struct CmdlineInfo const cmdline, + struct Text const inputText, + struct font * const fontP, + unsigned int * const vmarginP, + unsigned int * const hmarginP) { + + if (cmdline.nomargins) { + *vmarginP = 0; + *hmarginP = 0; + } else { + if (inputText.lineCount == 1) { + *vmarginP = fontP->maxheight / 2; + *hmarginP = fontP->maxwidth; + } else { + *vmarginP = fontP->maxheight; + *hmarginP = 2 * fontP->maxwidth; + } + } +} + + + +static void +formatText(struct CmdlineInfo const cmdline, + struct Text const inputText, + struct font * const fontP, + unsigned int const hmargin, + struct Text * const formattedTextP, + unsigned int * const maxleftb0P) { +/*---------------------------------------------------------------------------- + Flow or truncate lines to meet user's width request. +-----------------------------------------------------------------------------*/ + if (cmdline.width > 0) { + unsigned int const fontMargin = fontP->x < 0 ? -fontP->x : 0; + + if (cmdline.width > INT_MAX -10) + pm_error("-width value too large: %u", cmdline.width); + else if (cmdline.width < 2 * hmargin) + pm_error("-width value too small: %u", cmdline.width); + else if (inputText.lineCount == 1) { + flowText(inputText, cmdline.width - fontMargin, + fontP, cmdline.space, formattedTextP, maxleftb0P); + freeTextArray(inputText); + } else { + truncateText(inputText, cmdline.width - fontMargin, + fontP, cmdline.space, maxleftb0P); + *formattedTextP = inputText; + } + } else + *formattedTextP = inputText; +} + + + +static void +computeImageHeight(struct Text const formattedText, const struct font * const fontP, int const interlineSpace, unsigned int const vmargin, @@ -769,7 +844,7 @@ computeImageHeight(struct text const formattedText, static void -computeImageWidth(struct text const formattedText, +computeImageWidth(struct Text const formattedText, const struct font * const fontP, float const intercharacterSpace, unsigned int const hmargin, @@ -817,98 +892,180 @@ computeImageWidth(struct text const formattedText, -int -main(int argc, const char *argv[]) { +static void +renderText(unsigned int const cols, + unsigned int const rows, + struct font * const fontP, + unsigned int const hmargin, + unsigned int const vmargin, + struct Text const formattedText, + unsigned int const maxleftb, + float const space, + int const lspace, + bool const fixedAdvance, + FILE * const ofP) { + + bit ** const bits = pbm_allocarray(pbm_packed_bytes(cols), rows); + + /* Fill background with white */ + clearBackground(bits, cols, rows); + + /* Put the text in */ + insertCharacters(bits, formattedText, fontP, vmargin, hmargin + maxleftb, + space, cols, rows, lspace, fixedAdvance); + + { + unsigned int row; + + pbm_writepbminit(ofP, cols, rows, 0); + + for (row = 0; row < rows; ++row) + pbm_writepbmrow_packed(ofP, bits[row], cols, 0); + } + + pbm_freearray(bits, rows); +} + + + +static char const * sheetTextArray[] = { +"M \",/^_[`jpqy| M", +" ", +"/ !\"#$%&'()*+ /", +"< ,-./01234567 <", +"> 89:;<=>?@ABC >", +"@ DEFGHIJKLMNO @", +"_ PQRSTUVWXYZ[ _", +"{ \\]^_`abcdefg {", +"} hijklmnopqrs }", +"~ tuvwxyz{|}~ ~", +" ", +"M \",/^_[`jpqy| M" }; + + + +static void +validateText(const char ** const textArray, + struct font * const fontP) { +/*---------------------------------------------------------------------------- + Abort the program if there are characters in 'textArray' which cannot be + rendered in font *fontP. +-----------------------------------------------------------------------------*/ + const char * output; + unsigned int textRow; + + for (textRow = 0; textRow < 12; ++textRow) + fixControlChars(textArray[textRow], fontP, &output, QUIT); + + pm_strfree(output); +} + + + +static void +renderSheet(struct font * const fontP, + FILE * const ofP) { + + int const cols = fontP->maxwidth * 16; + int const rows = fontP->maxheight * 12; + struct Text const sheetText = { (char ** const) sheetTextArray, 12, 12}; + + validateText(sheetTextArray, fontP); + + renderText(cols, rows, fontP, 0, 0, sheetText, MAX(-(fontP->x),0), + 0.0, 0, TRUE, ofP); +} + + + +static void +dryrunOutput(unsigned int const cols, + unsigned int const rows, + FILE * const ofP) { + + fprintf(ofP, "%u %u\n", cols, rows); +} + + + +static void +pbmtext(struct CmdlineInfo const cmdline, + struct font * const fontP, + FILE * const ofP) { - struct CmdlineInfo cmdline; - bit ** bits; unsigned int rows, cols; - struct font * fontP; - unsigned int vmargin, hmargin, fontMargin; - struct text inputText; - struct text formattedText; + /* Dimensions in pixels of the output image */ + unsigned int cols0; + unsigned int vmargin, hmargin; + /* Margins in pixels we add to the output image */ + unsigned int hmargin0; + struct Text inputText; + struct Text formattedText; unsigned int maxleftb, maxleftb0; - pm_proginit(&argc, argv); + getText(cmdline.text, fontP, &inputText, + cmdline.verbose ? WARN : SILENT); - parseCommandLine(argc, argv, &cmdline); - - computeFont(cmdline, &fontP); + computeMargins(cmdline, inputText, fontP, &vmargin, &hmargin0); - getText(cmdline.text, fontP, &inputText); - - if (cmdline.nomargins) { - vmargin = 0; - hmargin = 0; - } else { - if (inputText.lineCount == 1) { - vmargin = fontP->maxheight / 2; - hmargin = fontP->maxwidth; - } else { - vmargin = fontP->maxheight; - hmargin = 2 * fontP->maxwidth; - } - } - - if (cmdline.width > 0) { - fontMargin = fontP->x < 0 ? -fontP->x : 0; + formatText(cmdline, inputText, fontP, hmargin0, + &formattedText, &maxleftb0); - if (cmdline.width > INT_MAX -10) - pm_error("-width value too large: %u", cmdline.width); - else if (cmdline.width < 2 * hmargin) - pm_error("-width value too small: %u", cmdline.width); - /* Flow or truncate lines to meet user's width request */ - else if (inputText.lineCount == 1) { - flowText(inputText, cmdline.width - fontMargin, - fontP, cmdline.space, &formattedText, &maxleftb0); - freeTextArray(inputText); - } else { - truncateText(inputText, cmdline.width - fontMargin, - fontP, cmdline.space, &maxleftb0); - formattedText = inputText; - } - } else - formattedText = inputText; - if (formattedText.lineCount == 0) pm_error("No input text"); - computeImageHeight(formattedText, fontP, cmdline.lspace, vmargin, - &rows); + computeImageHeight(formattedText, fontP, cmdline.lspace, vmargin, &rows); computeImageWidth(formattedText, fontP, cmdline.space, - cmdline.width > 0 ? 0 : hmargin, &cols, &maxleftb); + cmdline.width > 0 ? 0 : hmargin0, &cols0, &maxleftb); - if (cols == 0 || rows == 0) + if (cols0 == 0 || rows == 0) pm_error("Input is all whitespace and/or non-renderable characters."); - if (cmdline.width > 0) { - if(cmdline.width < cols) - pm_error("internal error: calculated image width (%u) exceeds " - "specified -width value: %u", - cols, cmdline.width); - else if(maxleftb0 != maxleftb) - pm_error("internal error: contradicting backup values"); - else { - hmargin = MIN(hmargin, (cmdline.width - cols) / 2); - cols = cmdline.width; - } + if (cmdline.width == 0) { + cols = cols0; + hmargin = hmargin0; + } else { + if (cmdline.width < cols0) + pm_error("internal error: calculated image width (%u) exceeds " + "specified -width value: %u", + cols0, cmdline.width); + else if (maxleftb0 != maxleftb) + pm_error("internal error: contradicting backup values"); + else { + hmargin = MIN(hmargin0, (cmdline.width - cols0) / 2); + cols = cmdline.width; + } } - bits = pbm_allocarray(cols, rows); + if (cmdline.dryrun) + dryrunOutput(cols, rows, ofP); + else + renderText(cols, rows, fontP, hmargin, vmargin, formattedText, + maxleftb, cmdline.space, cmdline.lspace, FALSE, ofP); - /* Fill background with white */ - fillRect(bits, rows, cols, PBM_WHITE); + freeTextArray(formattedText); +} - /* Put the text in */ - insertCharacters(bits, formattedText, fontP, vmargin, hmargin + maxleftb, - cmdline.space, cols, rows, cmdline.lspace); - pbm_writepbm(stdout, bits, cols, rows, 0); - pbm_freearray(bits, rows); +int +main(int argc, const char *argv[]) { + + struct CmdlineInfo cmdline; + struct font * fontP; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + computeFont(cmdline, &fontP); + + if (cmdline.dumpsheet) + renderSheet(fontP, stdout); + else + pbmtext(cmdline, fontP, stdout); - freeTextArray(formattedText); pm_close(stdout); return 0; diff --git a/generator/pbmtextps.c b/generator/pbmtextps.c index e6367530..fb55fa0a 100644 --- a/generator/pbmtextps.c +++ b/generator/pbmtextps.c @@ -1,4 +1,4 @@ -/* + /* * pbmtextps.c - render text into a bitmap using a postscript interpreter * * Copyright (C) 2002 by James McCann. @@ -14,7 +14,17 @@ * * Additions by Bryan Henderson contributed to public domain by author. * + * PostScript(R) Language Reference, Third Edition (a.k.a. "Red Book") + * http://www.adobe.com/products/postscript/pdfs/PLRM.pdf + * ISBN 0-201-37922-8 + * + * Postscript Font Naming Issues: + * https://partners.adobe.com/public/developer/en/font/5088.FontNames.pdf + * + * Other resources: + * http://partners.adobe.com/public/developer/ps/index_specs.html */ + #define _XOPEN_SOURCE /* Make sure popen() is in stdio.h */ #define _BSD_SOURCE /* Make sure stdrup() is in string.h */ #include <unistd.h> @@ -22,60 +32,15 @@ #include <stdlib.h> #include <string.h> #include <errno.h> +#include <assert.h> #include "pm_c_util.h" #include "mallocvar.h" #include "nstring.h" #include "shhopt.h" +#include "pm_system.h" #include "pbm.h" - -#define BUFFER_SIZE 2048 - -struct cmdlineInfo { - /* All the information the user supplied in the command line, - in a form easy for the program to use. - */ - unsigned int res; /* resolution, DPI */ - unsigned int fontsize; /* Size of font in points */ - const char * font; /* Name of postscript font */ - float stroke; - /* Width of stroke in points (only for outline font) */ - unsigned int verbose; - const char * text; -}; - - - -static void -writeFileToStdout(const char * const fileName){ - /* simple pbmtopbm */ - - FILE * ifP; - int format; - int cols, rows, row ; - unsigned char * bitrow; - - ifP = pm_openr(fileName); - pbm_readpbminit(ifP, &cols, &rows, &format); - - if (cols==0 || rows==0 || cols>INT_MAX-10 || rows>INT_MAX-10) - pm_error("Abnormal output from gs program. " - "width x height = %u x %u", cols, rows); - - pbm_writepbminit(stdout, cols, rows, 0); - - bitrow = pbm_allocrow_packed(cols); - - for (row = 0; row < rows; ++row) { - pbm_readpbmrow_packed(ifP, bitrow, cols, format); - pbm_writepbmrow_packed(stdout, bitrow, cols, 0); - } - pbm_freerow_packed(bitrow); -} - - - static void validateFontName(const char * const name) { /*----------------------------------------------------------------------------- @@ -132,7 +97,7 @@ asciiHexEncode(char * const inbuff, static void buildTextFromArgs(int const argc, - char ** const argv, + const char ** const argv, const char ** const asciiHexTextP) { /*---------------------------------------------------------------------------- Build the array of text to be included in the Postscript program to @@ -186,9 +151,31 @@ buildTextFromArgs(int const argc, +struct CmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + unsigned int res; + float fontsize; + const char * font; + float stroke; + float ascent; + float descent; + float leftmargin; + float rightmargin; + float topmargin; + float bottommargin; + unsigned int pad; + unsigned int verbose; + unsigned int dump; + const char * text; +}; + + + static void -parseCommandLine(int argc, char ** argv, - struct cmdlineInfo *cmdlineP) { +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo * const cmdlineP) { /*--------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that was passed to us as the argv array. @@ -199,37 +186,104 @@ parseCommandLine(int argc, char ** argv, optStruct3 opt; unsigned int option_def_index; + unsigned int cropSpec, ascentSpec, descentSpec; + unsigned int leftmarginSpec, rightmarginSpec; + unsigned int topmarginSpec, bottommarginSpec; MALLOCARRAY(option_def, 100); option_def_index = 0; /* incremented by OPTENTRY */ - OPTENT3(0, "resolution", OPT_UINT, &cmdlineP->res, NULL, 0); - OPTENT3(0, "font", OPT_STRING, &cmdlineP->font, NULL, 0); - OPTENT3(0, "fontsize", OPT_UINT, &cmdlineP->fontsize, NULL, 0); - OPTENT3(0, "stroke", OPT_FLOAT, &cmdlineP->stroke, NULL, 0); - OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); + OPTENT3(0, "resolution", OPT_UINT, + &cmdlineP->res, NULL, 0); + OPTENT3(0, "font", OPT_STRING, + &cmdlineP->font, NULL, 0); + OPTENT3(0, "fontsize", OPT_FLOAT, + &cmdlineP->fontsize, NULL, 0); + OPTENT3(0, "stroke", OPT_FLOAT, + &cmdlineP->stroke, NULL, 0); + OPTENT3(0, "ascent", OPT_FLOAT, + &cmdlineP->ascent, &ascentSpec, 0); + OPTENT3(0, "descent", OPT_FLOAT, + &cmdlineP->descent, &descentSpec, 0); + OPTENT3(0, "leftmargin", OPT_FLOAT, + &cmdlineP->leftmargin, &leftmarginSpec, 0); + OPTENT3(0, "rightmargin", OPT_FLOAT, + &cmdlineP->rightmargin, &rightmarginSpec, 0); + OPTENT3(0, "topmargin", OPT_FLOAT, + &cmdlineP->topmargin, &topmarginSpec, 0); + OPTENT3(0, "bottommargin", OPT_FLOAT, + &cmdlineP->bottommargin, &bottommarginSpec, 0); + OPTENT3(0, "crop", OPT_FLAG, + NULL, &cropSpec, 0); + OPTENT3(0, "pad", OPT_FLAG, + NULL, &cmdlineP->pad, 0); + OPTENT3(0, "verbose", OPT_FLAG, + NULL, &cmdlineP->verbose, 0); + OPTENT3(0, "dump-ps", OPT_FLAG, + NULL, &cmdlineP->dump, 0); /* Set the defaults */ cmdlineP->res = 150; cmdlineP->fontsize = 24; cmdlineP->font = "Times-Roman"; - cmdlineP->stroke = -1; + cmdlineP->stroke = -1; + cmdlineP->ascent = 0; + cmdlineP->descent = 0; + cmdlineP->rightmargin = 0; + cmdlineP->leftmargin = 0; + cmdlineP->topmargin = 0; + cmdlineP->bottommargin = 0; + cropSpec = FALSE; + cmdlineP->pad = FALSE; opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; - pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); validateFontName(cmdlineP->font); + if (cmdlineP->fontsize <= 0) + pm_error("-fontsize must be positive"); + if (cmdlineP->ascent < 0) + pm_error("-ascent must not be negative"); + if (cmdlineP->descent < 0) + pm_error("-descent must not be negative"); + if (cmdlineP->leftmargin <0) + pm_error("-leftmargin must not be negative"); + if (cmdlineP->rightmargin <0) + pm_error("-rightmargin must not be negative"); + if (cmdlineP->topmargin <0) + pm_error("-topmargin must not be negative"); + if (cmdlineP->bottommargin <0) + pm_error("-bottommargin must not be negative"); + + if (cropSpec == TRUE) { + if (ascentSpec || descentSpec || + leftmarginSpec || rightmarginSpec || + topmarginSpec || bottommarginSpec || + cmdlineP->pad) + pm_error("-crop cannot be specified with -ascent, -descent, " + "-leftmargin, -rightmargin, " + "-topmargin, -bottommargin or -pad"); + } else { + if (!descentSpec && !bottommarginSpec && !cmdlineP->pad) + cmdlineP->descent = cmdlineP->fontsize * 1.5; + + if (!leftmarginSpec) + cmdlineP->leftmargin = cmdlineP->fontsize / 2; + } + buildTextFromArgs(argc, argv, &cmdlineP->text); + + free(option_def); } static void -termCmdline(struct cmdlineInfo const cmdline) { +termCmdline(struct CmdlineInfo const cmdline) { pm_strfree(cmdline.text); } @@ -237,305 +291,431 @@ termCmdline(struct cmdlineInfo const cmdline) { static const char * -construct_postscript(struct cmdlineInfo const cmdline) { +postscriptProgram(struct CmdlineInfo const cmdline) { +/*----------------------------------------------------------------------------- + In Postscript, the bottom of the page is row zero. Postscript allows + negative values but negative regions are clipped from the output image. + We make adjustments to ensure that nothing is lost. + + Postscript also allow fonts to have negative values in the bounding box + coordinates. The bottom edge of "L" is row zero: this row is called the + "baseline". The feet of "g" "p" "y" extend into negative region. In a + similar manner the left edge of the bounding box may be negative. We add + margins on the left and the bottom with "xorigin" and "yorigin" to + provide for such characters. + + The sequence "textstring false charpath flattenpath pathbbox" determines + the bounding box of the entire text when rendered. +-----------------------------------------------------------------------------*/ + + /* C89 limits the size of a string constant, so we have to build the + Postscript command in pieces. + + psVariable, psTemplate: Set variables. + psFixed1: Scale font. Calculate pad metrics. + psFixed2: Determine width, height, xorigin, yorigin. + psFixed3: Render. + psFixed4: Verbose mode: Report font name, metrics. + We could add code to psFixed2 for handling right-to-left writing + (Hebrew, Arabic) and vertical writing (Chinese, Korean, Japanese). + */ + + const char * const psTemplate = + "/FindFont {/%s findfont} def\n" + "/fontsize %f def\n" + "/pensize %f def\n" + "/textstring <%s> def\n" + "/ascent %f def\n" + "/descent %f def\n" + "/leftmargin %f def\n" + "/rightmargin %f def\n" + "/topmargin %f def\n" + "/bottommargin %f def\n" + "/pad %s def\n" + "/verbose %s def\n"; + + const char * const psFixed1 = + "FindFont fontsize scalefont\n" + "pad { dup dup\n" + " /FontMatrix get 3 get /yscale exch def\n" + " /FontBBox get dup\n" + " 1 get yscale mul neg /padbottom exch def\n" + " 3 get yscale mul /padtop exch def}\n" + " {/padbottom 0 def /padtop 0 def}\n" + " ifelse\n" + "setfont\n"; + + const char * const psFixed2 = + "0 0 moveto\n" + "textstring false charpath flattenpath pathbbox\n" + "/BBtop exch def\n" + "/BBright exch def\n" + "/BBbottom exch neg def\n" + "/BBleft exch neg def\n" + "/max { 2 copy lt { exch } if pop } bind def\n" + "/yorigin descent padbottom max BBbottom max bottommargin add def\n" + "/xorigin leftmargin BBleft max def\n" + "/width xorigin BBright add rightmargin add def\n" + "/height ascent BBtop max padtop max topmargin add yorigin add def\n"; + + const char * const psFixed3 = + "<</PageSize [width height]>> setpagedevice\n" + "xorigin yorigin moveto\n" + "pensize 0 lt\n" + " {textstring show}\n" + " {pensize setlinewidth 0 setgray\n" + " textstring true charpath stroke}\n" + " ifelse\n" + "showpage\n"; + + const char * const psFixed4 = + "verbose\n" + " {xorigin yorigin moveto\n" + " [(width height) width height] ==\n" + " [(ascent descent) height yorigin sub yorigin] ==\n" + " [(bounding box) \n" + " textstring false charpath flattenpath pathbbox] ==\n" + " [(Fontname) FindFont dup /FontName\n" + " known\n" + " {/FontName get}\n" + " {pop (anonymous)}\n" + " ifelse] ==}\n" + " if"; + const char * retval; - const char * template; - - if (cmdline.stroke < 0) - template = - "/%s findfont\n" - "%d scalefont\n" - "setfont\n" - "12 36 moveto\n" - "<%s> show\n" - "showpage\n"; - else - template = - "/%s findfont\n" - "%d scalefont\n" - "setfont\n" - "12 36 moveto\n" - "%f setlinewidth\n" - "0 setgray\n" - "<%s> true charpath\n" - "stroke\n" - "showpage\n"; - - if (cmdline.stroke < 0) - pm_asprintf(&retval, template, cmdline.font, cmdline.fontsize, - cmdline.text); - else - pm_asprintf(&retval, template, cmdline.font, cmdline.fontsize, - cmdline.stroke, cmdline.text); + const char * psVariable; + + pm_asprintf(&psVariable, psTemplate, cmdline.font, + cmdline.fontsize, cmdline.stroke, cmdline.text, + cmdline.ascent, cmdline.descent, + cmdline.leftmargin, cmdline.rightmargin, + cmdline.topmargin, cmdline.bottommargin, + cmdline.pad ? "true" : "false", + cmdline.verbose ? "true" : "false" ); + pm_asprintf(&retval, "%s%s%s%s%s", psVariable, + psFixed1, psFixed2, psFixed3, psFixed4); + + pm_strfree(psVariable); + return retval; } -static const char * -gsExecutableName() { +static const char ** +gsArgList(const char * const outputFilename, + struct CmdlineInfo const cmdline) { - const char * const which = "which gs"; + unsigned int const maxArgCt = 50; + + const char ** retval; + unsigned int argCt; /* Number of arguments in 'retval' so far */ - static char buffer[BUFFER_SIZE]; + if (cmdline.res <= 0) + pm_error("Resolution (dpi) must be positive."); + + if (cmdline.fontsize <= 0) + pm_error("Font size must be positive."); + + MALLOCARRAY_NOFAIL(retval, maxArgCt+2); - FILE * f; + argCt = 0; /* initial value */ - memset(buffer, 0, BUFFER_SIZE); + pm_asprintf(&retval[argCt++], "ghostscript"); + pm_asprintf(&retval[argCt++], "-r%d", cmdline.res); + pm_asprintf(&retval[argCt++], "-sDEVICE=pbmraw"); + pm_asprintf(&retval[argCt++], "-sOutputFile=%s", outputFilename); + pm_asprintf(&retval[argCt++], "-q"); + pm_asprintf(&retval[argCt++], "-dBATCH"); + pm_asprintf(&retval[argCt++], "-dSAFER"); + pm_asprintf(&retval[argCt++], "-dNOPAUSE"); + pm_asprintf(&retval[argCt++], "-"); - f = popen(which, "r"); - if (!f) - pm_error("Can't find ghostscript"); + retval[argCt++] = NULL; - fread(buffer, 1, BUFFER_SIZE, f); - if (buffer[strlen(buffer) - 1] == '\n') - buffer[strlen(buffer) - 1] = '\0'; - pclose(f); - - if (buffer[0] != '/' && buffer[0] != '.') - pm_error("Can't find ghostscript"); + assert(argCt < maxArgCt); - return buffer; + return retval; } -static const char * -cropExecutableName(void) { +static void +reportGhostScript(const char * const executableNm, + const char ** const argList) { - const char * const which = "which pnmcrop"; + unsigned int i; - static char buffer[BUFFER_SIZE]; - const char * retval; + pm_message("Running Ghostscript interpreter '%s'", executableNm); - FILE * f; - - memset(buffer, 0, BUFFER_SIZE); - - f = popen(which, "r"); - if (!f) - retval = NULL; - else { - fread(buffer, 1, BUFFER_SIZE, f); - if (buffer[strlen(buffer) - 1] == '\n') - buffer[strlen(buffer) - 1] = 0; - pclose(f); - - if (buffer[0] != '/' && buffer[0] != '.') { - retval = NULL; - pm_message("Can't find pnmcrop"); - } else - retval = buffer; - } - return retval; + pm_message("Program arguments:"); + + for (i = 0; argList[i]; ++i) + pm_message(" '%s'", argList[i]); } -static const char * -gsCommand(const char * const psFname, - const char * const outputFilename, - struct cmdlineInfo const cmdline) { +static void +freeArgList(const char ** const argList) { - const char * retval; - double const x = (double) cmdline.res * 11; - double const y = (double) cmdline.res * - ((double) cmdline.fontsize * 2 + 72) / 72; - - if (cmdline.res <= 0) - pm_error("Resolution (dpi) must be positive."); - - if (cmdline.fontsize <= 0) - pm_error("Font size must be positive."); - - /* The following checks are for guarding against overflows in this - function. Huge x,y values that pass these checks may be - rejected by the 'gs' program. - */ - - if (x > (double) INT_MAX-10) - pm_error("Absurdly fine resolution: %u. Output width too large.", - cmdline.res ); - if (y > (double) INT_MAX-10) - pm_error("Absurdly fine resolution (%u) and/or huge font size (%u). " - "Output height too large.", cmdline.res, cmdline.fontsize); - - pm_asprintf(&retval, "%s -g%dx%d -r%d -sDEVICE=pbm " - "-sOutputFile=%s -q -dBATCH -dNOPAUSE %s " - "</dev/null >/dev/null", - gsExecutableName(), (int) x, (int) y, cmdline.res, - outputFilename, psFname); + unsigned int i; - return retval; + for (i = 0; argList[i]; ++i) + pm_strfree(argList[i]); + + free(argList); } -static const char * -cropCommand(const char * const inputFileName) { +static void +reportFontName(const char * const fontname) { - const char * retval; - const char * plainOpt = pm_plain_output ? "-plain" : "" ; - - if (cropExecutableName()) { - pm_asprintf(&retval, "%s -top -right %s %s", - cropExecutableName(), plainOpt, inputFileName); - if (retval == pm_strsol) - pm_error("Unable to allocate memory"); - } else - retval = NULL; + pm_message("Font: '%s'", fontname); - return retval; } static void -writeProgram(const char * const psFname, - struct cmdlineInfo const cmdline) { +reportMetrics(float const width, + float const height, + float const ascent, + float const descent, + float const BBoxleft, + float const BBoxbottom, + float const BBoxright, + float const BBoxtop) { + + pm_message("-- Metrics in points. Bottom left is (0,0) --"); + pm_message("Width: %f", width); + pm_message("Height: %f", height); + pm_message("Ascent: %f", ascent); + pm_message("Descent: %f", descent); + pm_message("BoundingBox_Left: %f", BBoxleft); + pm_message("BoundingBox_Right: %f", BBoxright); + pm_message("BoundingBox_Top: %f", BBoxtop); + pm_message("BoundingBox_Bottom: %f", BBoxbottom); - const char * ps; - FILE * psfile; +} - psfile = fopen(psFname, "w"); - if (psfile == NULL) - pm_error("Can't open temp file '%s'. Errno=%d (%s)", - psFname, errno, strerror(errno)); - ps = construct_postscript(cmdline); - if (cmdline.verbose) - pm_message("Postscript program = '%s'", ps); - - if (fwrite(ps, 1, strlen(ps), psfile) != strlen(ps)) - pm_error("Can't write postscript to temp file"); +static void +acceptGSoutput(int const pipetosuckFd, + void * const nullParams ) { +/*----------------------------------------------------------------------------- + Accept text written to stdout by the PostScript program. + + There are two kinds of output: + (1) Metrics and fontname reported, when verbose is on. + (2) Error messages from ghostscript. + + We read one line at a time. + + We cannot predict how long one line can be in case (2). In practice + the "execute stack" report gets long. We provide by setting lineBuffSize + to a large number. +-----------------------------------------------------------------------------*/ + unsigned int const lineBuffSize = 1024*32; + FILE * const inFileP = fdopen(pipetosuckFd, "r"); + + float width, height, ascent, descent; + float BBoxleft, BBoxbottom, BBoxright, BBoxtop; + char * lineBuff; /* malloc'd */ + char fontname [2048]; + bool fontnameReported, widthHeightReported; + bool ascentDescentReported, BBoxReported; + + assert(nullParams == NULL); + + fontnameReported = FALSE; /* Initial value */ + widthHeightReported = FALSE; /* Initial value */ + ascentDescentReported = FALSE; /* Initial value */ + BBoxReported = FALSE; /* Initial value */ + + MALLOCARRAY_NOFAIL(lineBuff, lineBuffSize); - fclose(psfile); + while (fgets(lineBuff, lineBuffSize, inFileP) != NULL) { + unsigned int rWidthHeight, rAscentDescent, rBBox, rFontname; - pm_strfree(ps); + rWidthHeight = sscanf(lineBuff, "[(width height) %f %f]", + &width, &height); + + rAscentDescent = sscanf(lineBuff, "[(ascent descent) %f %f]", + &ascent, &descent); + + rBBox = sscanf(lineBuff, "[(bounding box) %f %f %f %f]", + &BBoxleft, &BBoxbottom, &BBoxright, &BBoxtop); + + rFontname = sscanf(lineBuff, "[(Fontname) /%2047s", fontname); + + if (rFontname == 1) + fontnameReported = TRUE; + else if (rWidthHeight == 2) + widthHeightReported = TRUE; + else if (rAscentDescent == 2) + ascentDescentReported = TRUE; + else if (rBBox == 4) + BBoxReported = TRUE; + else + pm_message("[gs] %s", lineBuff); + } + + if (fontnameReported) { + fontname[strlen(fontname)-1] = 0; + reportFontName(fontname); + + if (widthHeightReported && ascentDescentReported && BBoxReported) + reportMetrics(width, height, ascent, descent, + BBoxleft, BBoxbottom, BBoxright, BBoxtop); + } + fclose(inFileP); + pm_strfree(lineBuff); } static void -executeProgram(const char * const psFname, +executeProgram(const char * const psProgram, const char * const outputFname, - struct cmdlineInfo const cmdline) { + struct CmdlineInfo const cmdline) { - const char * com; - int rc; + const char * const executableNm = "gs"; + const char ** const argList = gsArgList(outputFname, cmdline); + + struct bufferDesc feedBuffer; + int termStatus; + unsigned int bytesFed; + + bytesFed = 0; /* Initial value */ + + feedBuffer.buffer = (unsigned char *) psProgram; + feedBuffer.size = strlen(psProgram); + feedBuffer.bytesTransferredP = &bytesFed; - com = gsCommand(psFname, outputFname, cmdline); - if (com == NULL) - pm_error("Can't allocate memory for a 'ghostscript' command"); - if (cmdline.verbose) - pm_message("Running Postscript interpreter '%s'", com); + reportGhostScript(executableNm, argList); - rc = system(com); - if (rc != 0) - pm_error("Failed to run Ghostscript process. rc=%d", rc); + pm_system2_vp(executableNm, + argList, + &pm_feed_from_memory, &feedBuffer, + cmdline.verbose ? &acceptGSoutput : &pm_accept_null, NULL, + &termStatus); - pm_strfree(com); -} + if (termStatus != 0) { + const char * const msg = pm_termStatusDesc(termStatus); + pm_error("Failed to run Ghostscript process. %s", msg); + pm_strfree(msg); + } + freeArgList(argList); +} -static void -cropToStdout(const char * const inputFileName, - bool const verbose) { - const char * com; - com = cropCommand(inputFileName); +static void +writePbm(const char * const fileName, + FILE * const ofP) { +/*---------------------------------------------------------------------------- + Write the PBM image that is in the file named 'fileName" to file *ofP. + I.e. pbmtopbm. - if (com == NULL) { - /* No pnmcrop. So don't crop. */ - pm_message("Can't find pnmcrop command, image will be large"); - writeFileToStdout(inputFileName); - } else { - FILE * pnmcrop; + It's not a byte-for-byte copy because PBM allows the same image to be + represented many ways (all of which we can accept as our input), but we use + libnetpbm to write our output in its specific way. +----------------------------------------------------------------------------*/ + FILE * ifP; + int format; + int cols, rows, row ; + unsigned char * bitrow; + + ifP = pm_openr(fileName); + pbm_readpbminit(ifP, &cols, &rows, &format); - if (verbose) - pm_message("Running crop command '%s'", com); - - pnmcrop = popen(com, "r"); - if (pnmcrop == NULL) - pm_error("Can't run pnmcrop process"); - else { - char buf[2048]; - bool eof; - - eof = FALSE; - - while (!eof) { - int bytesRead; - - bytesRead = fread(buf, 1, sizeof(buf), pnmcrop); - if (bytesRead > 0) { - int rc; - rc = fwrite(buf, 1, bytesRead, stdout); - if (rc != bytesRead) - pm_error("Can't write to stdout"); - } else if (bytesRead == 0) - eof = TRUE; - else - pm_error("Failed to read output of Pnmcrop process. " - "Errno=%d (%s)", errno, strerror(errno)); - } - fclose(pnmcrop); - } - pm_strfree(com); + if (cols == 0 || rows == 0 || cols > INT_MAX - 10 || rows > INT_MAX - 10) + pm_error("Abnormal output from gs program. " + "width x height = %u x %u", cols, rows); + + pbm_writepbminit(ofP, cols, rows, 0); + + bitrow = pbm_allocrow_packed(cols); + + for (row = 0; row < rows; ++row) { + pbm_readpbmrow_packed(ifP, bitrow, cols, format); + pbm_writepbmrow_packed(ofP, bitrow, cols, 0); } + pbm_freerow_packed(bitrow); + pm_close(ifP); } static void -createOutputFile(struct cmdlineInfo const cmdline) { +generatePbm(struct CmdlineInfo const cmdline, + FILE * const ofP) { + + const char * const psProgram = postscriptProgram(cmdline); + + const char * tempPbmFname; + FILE * pbmFileP; + + pm_make_tmpfile(&pbmFileP, &tempPbmFname); + assert(pbmFileP != NULL && tempPbmFname != NULL); + fclose(pbmFileP); + + executeProgram(psProgram, tempPbmFname, cmdline); + + /* Although Ghostscript created a legal PBM file, it uses a different + implementation of the format from libnetpbm's canonical output format, + so instead of copying the content of 'tempPbmFname' to *ofP byte for + byte, we copy it as a PBM image. + */ + writePbm(tempPbmFname, ofP); + + unlink(tempPbmFname); + pm_strfree(tempPbmFname); + pm_strfree(psProgram); +} + - const char * const template = "./pstextpbm.%d.tmp.%s"; - - const char * psFname; - const char * uncroppedPbmFname; - pm_asprintf(&psFname, template, getpid(), "ps"); - if (psFname == NULL) - pm_error("Unable to allocate memory"); - - writeProgram(psFname, cmdline); +static void +dumpPsProgram(struct CmdlineInfo const cmdline) { - pm_asprintf(&uncroppedPbmFname, template, getpid(), "pbm"); - if (uncroppedPbmFname == NULL) - pm_error("Unable to allocate memory"); - - executeProgram(psFname, uncroppedPbmFname, cmdline); + const char * psProgram; - unlink(psFname); - pm_strfree(psFname); + psProgram = postscriptProgram(cmdline); - cropToStdout(uncroppedPbmFname, cmdline.verbose); + puts(psProgram); - unlink(uncroppedPbmFname); - pm_strfree(uncroppedPbmFname); + pm_strfree(psProgram); } int -main(int argc, char *argv[]) { +main(int argc, const char *argv[]) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; - pbm_init(&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); - createOutputFile(cmdline); + if (cmdline.dump) + dumpPsProgram(cmdline); + else + generatePbm(cmdline, stdout); termCmdline(cmdline); return 0; } + + + diff --git a/generator/pgmcrater b/generator/pgmcrater index 1c22ed70..c66f5576 100755 --- a/generator/pgmcrater +++ b/generator/pgmcrater @@ -37,6 +37,26 @@ use strict; use Getopt::Long; +sub doVersionHack($) { + my ($argvR) = @_; + + my $arg1 = $argvR->[0]; + + if (defined($arg1) && (($arg1 eq "--version") || ($arg1 eq "-version"))) { + my $termStatus = system('pamcrater', '--version'); + exit($termStatus == 0 ? 0 : 1); + } +} + + +############################################################################## +# +# MAINLINE +# +############################################################################## + +doVersionHack(\@ARGV); + my @pgmcraterArgv = @ARGV; my $validOptions = GetOptions( diff --git a/generator/ppmrainbow b/generator/ppmrainbow index c0568d9b..a4f90a09 100755 --- a/generator/ppmrainbow +++ b/generator/ppmrainbow @@ -25,11 +25,27 @@ exec perl -w -x -S -- "$0" "$@" #!/usr/bin/perl use strict; use Getopt::Long; +use File::Temp; my ($FALSE, $TRUE) = (0,1); (my $myname = $0) =~ s#\A.*/##; + + +sub doVersionHack($) { + my ($argvR) = @_; + + my $arg1 = $argvR->[0]; + + if (defined($arg1) && (($arg1 eq "--version") || ($arg1 eq "-version"))) { + my $termStatus = system('pgmramp', '--version'); + exit($termStatus == 0 ? 0 : 1); + } +} + + + sub fatal($) { my ($msg) = @_; @@ -37,19 +53,29 @@ sub fatal($) { exit(1); } -my ($Twid, $Thgt, $tmpdir, $norepeat, $verbose); + + +############################################################################## +# +# MAINLINE +# +############################################################################## + +doVersionHack(\@ARGV); + +my ($Twid, $Thgt, $tmpdir, $repeat, $verbose); # set defaults $Twid = 600; $Thgt = 8; $tmpdir = $ENV{"TMPDIR"} || "/tmp"; -$norepeat = $FALSE; +$repeat = $TRUE; $verbose = $FALSE; GetOptions("width=i" => \$Twid, "height=i" => \$Thgt, "tmpdir=s" => \$tmpdir, - "norepeat!" => \$norepeat, + "repeat!" => \$repeat, "verbose!" => \$verbose); if ($Twid < 1 || $Thgt < 1) { @@ -59,7 +85,7 @@ my $verboseCommand = $verbose ? "set -x;" : ""; if (@ARGV < 1) { fatal("You must specify at least one color as an argument"); -} elsif (@ARGV < 2 && $norepeat) { +} elsif (@ARGV < 2 && ! $repeat) { fatal("With the -norepeat option, you must specify at least two colors " . "as arguments."); } @@ -67,14 +93,11 @@ if (@ARGV < 1) { my @colorlist; @colorlist = @ARGV; -if (!$norepeat) { +if ($repeat) { push @colorlist, $ARGV[0]; } -my $ourtmp = "$tmpdir/ppmrainbow$$"; -mkdir($ourtmp, 0777) or - die("Unable to create directory for temporary files '$ourtmp"); - +my $ourtmp = File::Temp::tempdir("$tmpdir/ppmrainbowXXXX", UNLINK=>1); my $widthRemaining; my $n; |