From 3a2be6f9d910b862d4e5ea237d734315627dd661 Mon Sep 17 00:00:00 2001 From: giraffedata Date: Thu, 21 Sep 2006 18:00:16 +0000 Subject: Release 10.36.0 git-svn-id: http://svn.code.sf.net/p/netpbm/code/advanced@65 9d0c8265-081b-0410-96cb-a4ca84ce46f8 --- GNUmakefile | 3 +- Makefile.common | 24 +- Makefile.version | 5 +- converter/other/Makefile | 15 +- converter/other/cameratopam/Makefile | 3 +- converter/other/fiasco/Makefile | 2 +- converter/other/fiasco/codec/Makefile | 2 +- converter/other/fiasco/input/Makefile | 4 +- converter/other/fiasco/lib/Makefile | 2 +- converter/other/fiasco/output/Makefile | 7 +- converter/other/jbig/Makefile | 4 +- converter/other/jpeg2000/Makefile | 4 +- converter/other/jpeg2000/libjasper/Makefile.common | 4 +- converter/other/pamtosvg/pamtosvg.test | 6 +- converter/other/pnmtopalm/Makefile | 4 +- converter/other/pnmtopalm/gen_palm_colormap.c | 33 +- converter/pbm/pbmtonokia.c | 669 +++++++++++++++------ converter/ppm/ppmtobmp.c | 2 +- converter/ppm/ppmtompeg/Makefile | 5 +- converter/ppm/xvminitoppm.c | 4 +- doc/HISTORY | 44 +- doc/INSTALL | 3 + editor/pamperspective.c | 10 +- editor/pamthreshold.c | 21 +- editor/pbmpscale.c | 230 +++---- editor/pnmcrop.c | 18 +- editor/pnmrotate.c | 4 +- generator/pamstereogram.test | 8 +- lib/Makefile | 6 +- lib/libpammap.c | 20 +- lib/libpamn.c | 284 +++++++-- lib/libpamread.c | 104 +++- lib/libpamwrite.c | 29 +- lib/libpbm3.c | 113 ++-- lib/libpgm1.c | 186 ++++-- lib/libpm.c | 292 ++++++--- lib/libpnm1.c | 125 +++- lib/libpnm2.c | 102 +++- lib/libppm1.c | 290 ++++++--- lib/libppmcmap.c | 313 +++++++--- lib/libppmcolor.c | 257 +++++--- lib/libppmfuzzy.c | 89 +-- lib/pm.h | 18 +- lib/ppm.h | 17 +- lib/util/Makefile | 6 +- lib/util/nstring.c | 26 +- lib/util/nstring.h | 9 + other/Makefile | 3 +- other/pamx/Makefile | 3 +- urt/scanargs.c | 2 +- 50 files changed, 2384 insertions(+), 1050 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 56c6126c..420d558c 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -117,7 +117,8 @@ $(BUILDDIR)/inttypes_netpbm.h: $(TYPEGEN) # cross compiling. $(BUILDDIR)/pm_config.h: \ - $(SRCDIR)/pm_config.in.h Makefile.config inttypes_netpbm.h $(ENDIANGEN) + $(SRCDIR)/pm_config.in.h Makefile.config inttypes_netpbm.h \ + $(ENDIANGEN) echo '/* pm_config.h GENERATED BY A MAKE RULE */' >$@ || $(DELETEIT) echo '#ifndef PM_CONFIG_H' >>$@ || $(DELETEIT) echo '#define PM_CONFIG_H' >>$@ || $(DELETEIT) diff --git a/Makefile.common b/Makefile.common index cc1f20e0..c31013c6 100644 --- a/Makefile.common +++ b/Makefile.common @@ -52,10 +52,14 @@ # front end, so takes linker options in a different format # LDFLAGS: linker options # LIBS or LOADLIBES: names of libraries to be added to all links -# INCLUDES: Compiler option string to establish the search path for include -# files when compiling things or computing dependencies (make dep). -# current directory, corresponding source tree directory, and ./importinc -# are implied, so should not be in here. +# COMP_INCLUDES: Compiler option string to establish the search path for +# component-specific include files when compiling things or computing +# dependencies (make dep). Header files from this part of the search +# path take precedence over general Netpbm header files and external +# library header files. +# EXTERN_INCLUDES: Like COMP_INCLUDES, but for external libraries, e.g. +# libjpeg. All header files from the Netpbm source tree take precedence +# over these. # In addition, there is CADD, which is extra C compilation flags and # is intended to be set on a make command line (e.g. 'make CADD=-g') @@ -68,7 +72,10 @@ include $(SRCDIR)/Makefile.version -INCLUDES2 := $(INCLUDES) -I$(SRCDIR)/$(SUBDIR) -I. -I importinc +NETPBM_INCLUDES := -I importinc -I$(SRCDIR)/$(SUBDIR) + +# -I. is needed when builddir != srcdir +INCLUDES = -I. $(COMP_INCLUDES) $(NETPBM_INCLUDES) $(EXTERN_INCLUDES) ifeq ($(NETPBMLIBTYPE),unixstatic) NETPBMLIBFNAME = libnetpbm.$(STATICLIBSUFFIX) @@ -194,7 +201,6 @@ config: $(OBJECTS): %.o: %.c importinc ############################################################################# # Note that the user may have configured -I options into CFLAGS or CPPFLAGS. -# -I. is needed when builddir != srcdir # Note about -o: There used to be systems that couldn't handle a space # between flag and value. But we found a Solaris gcc on 2003.09.02 that # actually fails _without_ the space (it invokes Solaris 'as' with the @@ -210,7 +216,7 @@ $(OBJECTS): %.o: %.c importinc # assertion and crash the program if it isn't really true. You can add # -UNDEBUG (in any of various ways) to override this. # - $(CC) -c $(INCLUDES2) -DNDEBUG \ + $(CC) -c $(INCLUDES) -DNDEBUG \ $(CPPFLAGS) $(CFLAGS) $(CFLAGS_PERSONAL) $(CADD) -o $@ $< # libopt is a utility program used in the make file below. @@ -314,7 +320,7 @@ $(PORTBINARIES) $(MATHBINARIES): %: %.o $(NETPBMLIB) $(LIBOPT) %.o2: %.c importinc # Note that the user may have configured -I options into CFLAGS. - $(CC) -c $(INCLUDES2) -DNDEBUG $(CFLAGS) \ + $(CC) -c $(INCLUDES) -DNDEBUG $(CFLAGS) \ "-Dmain=main_$*" \ $(CFLAGS_MERGE) $(CFLAGS_PERSONAL) $(CADD) -o $@ $< @@ -469,7 +475,7 @@ dep: $(SUBDIRS:%=%/dep) importinc # before the first make after a clean. ifneq ($(DEP_SOURCES)x,x) - $(CC) -MM -MG $(INCLUDES2) $(DEP_SOURCES) >Makefile.depend + $(CC) -MM -MG $(INCLUDES) $(DEP_SOURCES) >Makefile.depend endif # Note: if I stack all these subdirectory targets into one rule, I get diff --git a/Makefile.version b/Makefile.version index 4683751d..a524892c 100644 --- a/Makefile.version +++ b/Makefile.version @@ -1,3 +1,4 @@ NETPBM_MAJOR_RELEASE = 10 -NETPBM_MINOR_RELEASE = 35 -NETPBM_POINT_RELEASE = 05 +NETPBM_MINOR_RELEASE = 36 +NETPBM_POINT_RELEASE = 0 + diff --git a/converter/other/Makefile b/converter/other/Makefile index 4585c45d..6cde424d 100644 --- a/converter/other/Makefile +++ b/converter/other/Makefile @@ -20,10 +20,9 @@ ifneq ($(BUILD_FIASCO), N) SUBDIRS += fiasco endif -INCLUDES = -I$(SRCDIR)/util ifneq ($(TIFFLIB),NONE) ifneq ($(TIFFHDR_DIR)x,x) - INCLUDES += -I$(TIFFHDR_DIR) + EXTERN_INCLUDES += -I$(TIFFHDR_DIR) endif endif @@ -31,30 +30,30 @@ ifeq ($(shell libpng-config --version),) ifneq ($(PNGLIB),NONE) HAVE_PNGLIB = Y ifneq ($(PNGHDR_DIR)x,x) - INCLUDES += -I$(PNGHDR_DIR) + EXTERN_INCLUDES += -I$(PNGHDR_DIR) endif ifneq ($(ZHDR_DIR)x,x) - INCLUDES += -I$(ZHDR_DIR) + EXTERN_INCLUDES += -I$(ZHDR_DIR) endif endif else HAVE_PNGLIB = Y - INCLUDES += $(shell libpng-config --cflags) + EXTERN_INCLUDES += $(shell libpng-config --cflags) endif ifneq ($(JPEGLIB),NONE) ifneq ($(JPEGHDR_DIR)x,x) - INCLUDES += -I$(JPEGHDR_DIR) + EXTERN_INCLUDES += -I$(JPEGHDR_DIR) endif endif ifneq ($(URTLIB),NONE) ifneq ($(URTHDR_DIR)x,x) - INCLUDES += -I$(URTHDR_DIR) + EXTERN_INCLUDES += -I$(URTHDR_DIR) endif endif ifneq ($(XML2_LIBS),NONE) ifneq ($(XML2_CFLAGS),NONE) - INCLUDES += $(XML2_CFLAGS) + EXTERN_INCLUDES += $(XML2_CFLAGS) endif endif diff --git a/converter/other/cameratopam/Makefile b/converter/other/cameratopam/Makefile index c50c9176..178b4fff 100644 --- a/converter/other/cameratopam/Makefile +++ b/converter/other/cameratopam/Makefile @@ -5,9 +5,10 @@ endif SUBDIR = converter/other/cameratopam VPATH=.:$(SRCDIR)/$(SUBDIR) +EXTERN_INCLUDES = ifneq ($(JPEGLIB),NONE) ifneq ($(JPEGHDR_DIR)x,x) - INCLUDES += -I$(JPEGHDR_DIR) + EXTERN_INCLUDES += -I$(JPEGHDR_DIR) CFLAGS += -DHAVE_JPEG endif endif diff --git a/converter/other/fiasco/Makefile b/converter/other/fiasco/Makefile index 0dd945ed..0330802c 100644 --- a/converter/other/fiasco/Makefile +++ b/converter/other/fiasco/Makefile @@ -7,7 +7,7 @@ VPATH=.:$(SRCDIR)/$(SUBDIR) include $(BUILDDIR)/Makefile.config -INCLUDES = \ +COMP_INCLUDES = \ -I$(SRCDIR)/$(SUBDIR)/codec -I$(SRCDIR)/$(SUBDIR)/input \ -I$(SRCDIR)/$(SUBDIR)/output -I$(SRCDIR)/$(SUBDIR)/lib \ diff --git a/converter/other/fiasco/codec/Makefile b/converter/other/fiasco/codec/Makefile index 9a9d502a..c5f94c28 100644 --- a/converter/other/fiasco/codec/Makefile +++ b/converter/other/fiasco/codec/Makefile @@ -8,7 +8,7 @@ VPATH=.:$(SRCDIR)/$(SUBDIR) include $(BUILDDIR)/Makefile.config -INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR) -I$(SRCDIR)/$(FIASCOSUBDIR)/lib \ +COMP_INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR) -I$(SRCDIR)/$(FIASCOSUBDIR)/lib \ -I$(SRCDIR)/$(FIASCOSUBDIR)/input -I$(SRCDIR)/$(FIASCOSUBDIR)/output OBJECTS = approx.o bintree.o coder.o coeff.o \ diff --git a/converter/other/fiasco/input/Makefile b/converter/other/fiasco/input/Makefile index c01af772..6cd8e34b 100644 --- a/converter/other/fiasco/input/Makefile +++ b/converter/other/fiasco/input/Makefile @@ -13,8 +13,8 @@ OBJECTS = basis.o matrices.o mc.o nd.o read.o tree.o weights.o MERGE_OBJECTS = $(OBJECTS) -INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR) -I$(SRCDIR)/$(FIASCOSUBDIR)/lib \ - -I$(SRCDIR)/$(FIASCOSUBDIR)/codec +COMP_INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR) -I$(SRCDIR)/$(FIASCOSUBDIR)/lib \ + -I$(SRCDIR)/$(FIASCOSUBDIR)/codec all: libfiasco_input.a diff --git a/converter/other/fiasco/lib/Makefile b/converter/other/fiasco/lib/Makefile index 99d7c1d7..bd129016 100644 --- a/converter/other/fiasco/lib/Makefile +++ b/converter/other/fiasco/lib/Makefile @@ -21,7 +21,7 @@ OBJECTS = \ MERGE_OBJECTS = $(OBJECTS) -INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR) +COMP_INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR) all: libfiasco_lib.a diff --git a/converter/other/fiasco/output/Makefile b/converter/other/fiasco/output/Makefile index 3bdc4635..fc1d4155 100644 --- a/converter/other/fiasco/output/Makefile +++ b/converter/other/fiasco/output/Makefile @@ -12,9 +12,10 @@ OBJECTS = matrices.o mc.o nd.o tree.o weights.o write.o MERGE_OBJECTS = $(OBJECTS) -INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR) \ - -I$(SRCDIR)/$(FIASCOSUBDIR)/lib \ - -I$(SRCDIR)/$(FIASCOSUBDIR)/codec +COMP_INCLUDES = \ + -I$(SRCDIR)/$(FIASCOSUBDIR) \ + -I$(SRCDIR)/$(FIASCOSUBDIR)/lib \ + -I$(SRCDIR)/$(FIASCOSUBDIR)/codec all: libfiasco_output.a diff --git a/converter/other/jbig/Makefile b/converter/other/jbig/Makefile index ca98ef29..4be21582 100644 --- a/converter/other/jbig/Makefile +++ b/converter/other/jbig/Makefile @@ -9,9 +9,9 @@ include $(BUILDDIR)/Makefile.config LIBJBIG_OBJECTS = jbig.o jbig_tab.o -INCLUDES = +EXTERN_INCLUDES = ifneq ($(JBIGHDR_DIR),NONE) - INCLUDES += -I$(JBIGHDR_DIR) + EXTERN_INCLUDES += -I$(JBIGHDR_DIR) endif ifneq ($(JBIGHDR_DIR),NONE) diff --git a/converter/other/jpeg2000/Makefile b/converter/other/jpeg2000/Makefile index 70cfafb7..c5e74361 100644 --- a/converter/other/jpeg2000/Makefile +++ b/converter/other/jpeg2000/Makefile @@ -9,9 +9,9 @@ SUBDIRS = libjasper include $(BUILDDIR)/Makefile.config -INCLUDES = +EXTERN_INCLUDES = ifneq ($(JASPERHDR_DIR),NONE) - INCLUDES += -I$(JASPERHDR_DIR) + EXTERN_INCLUDES += -I$(JASPERHDR_DIR) endif diff --git a/converter/other/jpeg2000/libjasper/Makefile.common b/converter/other/jpeg2000/libjasper/Makefile.common index 71a11832..84781769 100644 --- a/converter/other/jpeg2000/libjasper/Makefile.common +++ b/converter/other/jpeg2000/libjasper/Makefile.common @@ -17,10 +17,10 @@ $(SUBDIRS:%=%/partlist): %/partlist: $(CURDIR)/% $(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \ SRCDIR=$(SRCDIR) BUILDDIR=$(BUILDDIR) $(notdir $@) -INCLUDES = -I$(JASPERSRCDIR)/include -I$(JASPERSRCDIR)/importinc - include $(SRCDIR)/Makefile.common +INCLUDES = -I$(JASPERSRCDIR)/include -I$(JASPERSRCDIR)/importinc + DEFS = -DHAVE_LIBM=1 -DSTDC_HEADERS=1 -DHAVE_FCNTL_H=1 -DHAVE_LIMITS_H=1 -DHAVE_UNISTD_H=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STDDEF_H=1 -DEXCLUDE_BMP_SUPPORT -DEXCLUDE_RAS_SUPPORT -DEXCLUDE_MIF_SUPPORT -DEXCLUDE_JPG_SUPPORT -DEXCLUDE_PGX_SUPPORT -DEXCLUDE_PNM_SUPPORT $(LIB_OBJECTS):%.o:%.c diff --git a/converter/other/pamtosvg/pamtosvg.test b/converter/other/pamtosvg/pamtosvg.test index df3a07d3..3217287e 100644 --- a/converter/other/pamtosvg/pamtosvg.test +++ b/converter/other/pamtosvg/pamtosvg.test @@ -1,6 +1,8 @@ +echo "Test 1. Should print nothing" # This will print nothing if successful (diff will find no difference) -ppmmake black 20 20 | ppmdraw -script="line 5 2 15 17" | pamtosvg | \ +ppmmake black 20 20 | ppmdraw -script="line 5 2 15 17" | ./pamtosvg | \ diff testline.svg - +echo "Test 2. Should print nothing" # This will print nothing if successful (diff will find no difference) -pamtosvg ../../../../testgrid.pbm | diff testgrid.svg - +./pamtosvg ../../../testgrid.pbm | diff testgrid.svg - diff --git a/converter/other/pnmtopalm/Makefile b/converter/other/pnmtopalm/Makefile index 2a76297e..d7bf2829 100644 --- a/converter/other/pnmtopalm/Makefile +++ b/converter/other/pnmtopalm/Makefile @@ -24,8 +24,8 @@ $(BINARIES): %: %.o palmcolormap.o $(NETPBMLIB) $(LIBOPT) $(LD) $(LDFLAGS) -o $@ $< palmcolormap.o $(LIBOPTS) \ $(MATHLIB) $(LDLIBS) $(RPATH) $(LADD) -gen_palm_colormap : $(SUBDIR)/gen_palm_colormap.c palmcolormap.o - $(CC) $(INCLUDES) $(CFLAGS) $(LDFLAGS) -o $@ $< palmcolormap.o \ +gen_palm_colormap : % : %.c palmcolormap.o + $(CC) -I importinc $(CFLAGS) $(LDFLAGS) -o $@ $< palmcolormap.o \ $(LIBOPTS) $(MATHLIB) $(LDLIBS) $(LADD) diff --git a/converter/other/pnmtopalm/gen_palm_colormap.c b/converter/other/pnmtopalm/gen_palm_colormap.c index 4b65e631..b71854b2 100644 --- a/converter/other/pnmtopalm/gen_palm_colormap.c +++ b/converter/other/pnmtopalm/gen_palm_colormap.c @@ -7,18 +7,25 @@ #include "palm.h" -int main( int argc, char **argv ) { - - int i; - Color_s current; - Colormap default_map = palmcolor_build_default_8bit_colormap (); - - printf("P3\n%d 1\n255\n", default_map->ncolors); - for (i = 0; i < default_map->ncolors; i++) { - current = default_map->color_entries[i]; - printf ("%d %d %d\n", (current & 0xFF0000) >> 16, (current & 0xFF00) >> 8, (current & 0xFF)); - /* printf ("%x: %d %d %d\n", (current & 0xFF000000) >> 24, (current & 0xFF0000) >> 16, (current & 0xFF00) >> 8, (current & 0xFF)); */ - }; - return 0; +int +main(int argc, + char ** argv) { + + Colormap const defaultMap = palmcolor_build_default_8bit_colormap(); + + unsigned int i; + + printf("P3\n%d 1\n255\n", defaultMap->ncolors); + + for (i = 0; i < defaultMap->ncolors; ++i) { + Color_s const current = defaultMap->color_entries[i]; + + printf("%u %u %u\n", + (unsigned char)(current >> 16), + (unsigned char)(current >> 8), + (unsigned char)(current >> 0)); + } + + return 0; } diff --git a/converter/pbm/pbmtonokia.c b/converter/pbm/pbmtonokia.c index 214958c5..3c47eac3 100644 --- a/converter/pbm/pbmtonokia.c +++ b/converter/pbm/pbmtonokia.c @@ -1,231 +1,510 @@ -/* pbmtonokia.c - convert a portable bitmap to Nokia Smart Messaging +/* pbmtonokia.c - convert a PBM image to Nokia Smart Messaging Formats (NOL, NGG, HEX) -** Copyright (C)2001 OMS Open Media System GmbH, Tim Rühsen -** . -** -** Permission to use, copy, modify, and distribute this software and its -** documentation for any purpose and without fee is hereby granted, provided -** that the above copyright notice appear in all copies and that both that -** copyright notice and this permission notice appear in supporting -** documentation. This software is provided "as is" without express or -** implied warranty. + Copyright information is at end of file. +*/ -History - 07.06.2001 Created - 20.11.2001 Handle Picture Messages - new option -txt to embed text into Picture Messages - new option -net to specify operator network code for - Nokia Operator Logos +#define _BSD_SOURCE /* Make sure strcasecmp() is in string.h */ +#include +#include -Notes: - - limited to rows <= 255 and columns <= 255 - - limited to b/w graphics, not animated +#include "pm_c_util.h" +#include "nstring.h" +#include "mallocvar.h" +#include "shhopt.h" +#include "pbm.h" -Testing: - Testing was done with SwissCom SMSC (Switzerland) and IC3S SMSC (Germany). - The data was send with EMI/UCP protocol over TCP/IP. +enum outputFormat { + FMT_HEX_NOL, + FMT_HEX_NGG, + FMT_HEX_NPM, + FMT_NOL, + FMT_NGG, + FMT_NPM +}; - - 7.6.2001: tested with Nokia 3210: 72x14 Operator Logo - - 7.6.2001: tested with Nokia 6210: 72x14 Operator Logo and - 72x14 Group Graphic -Todo: - - more testing - - sendsms compatibility ? - - are -fmt NOL and -fmt NGG working ok? */ +struct cmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; /* Filename of input files */ + int outputFormat; + const char * networkCode; + const char * txt; /* NULL means unspecified */ +}; -#define _BSD_SOURCE /* Make sure strcasecmp() is in string.h */ -#include -#include "nstring.h" -#include "pbm.h" -#define FMT_HEX_NOL 1 -#define FMT_HEX_NGG 2 -#define FMT_HEX_NPM 3 -#define FMT_NOL 4 -#define FMT_NGG 5 - -static void -usage(char *myname) -{ - pm_message("Copyright (C)2001 OMS GmbH"); - pm_message("Contact: Tim Ruehsen \n"); - pm_usage("[options] [pbmfile]\n" - " Options:\n" - " -fmt " - "Output format (default=HEX_NOL)\n" - " -net " - "Network code for NOL operator logos\n" - " -txt " - "Text for NPM picture messages\n"); - - exit(1); +static const char * +uppercase(const char * const subject) { + + char * buffer; + + buffer = malloc(strlen(subject) + 1); + + if (buffer == NULL) + pm_error("Out of memory allocating buffer for uppercasing a " + "%u-character string", strlen(subject)); + else { + unsigned int i; + + i = 0; + while (subject[i]) { + buffer[i] = TOUPPER(subject[i]); + ++i; + } + buffer[i] = '\0'; + } + return buffer; } -int -main(int argc, char *argv[]) -{ - FILE *fp; - bit **image; - unsigned int c; - int argpos, output=FMT_HEX_NOL, rows, cols, row, col, p, it, len; - char header[32], *myname; - char network_code[6+1]; - char *text=NULL; - - if ((myname=strrchr(argv[0],'/'))!=NULL) myname++; else myname=argv[0]; - pbm_init(&argc, argv); - strcpy(network_code, "62F210"); /* default is German D1 net */ - - for(argpos=1;argposargpos+1 && ISDIGIT(argv[argpos+1][0])) - {argpos++;break;} - } else if (STREQ(argv[argpos],"-fmt") && argc>argpos+1) { - ++argpos; - if (!strcasecmp(argv[argpos],"HEX_NOL")) output=FMT_HEX_NOL; - else if (!strcasecmp(argv[argpos],"HEX_NGG")) - output=FMT_HEX_NGG; - else if (!strcasecmp(argv[argpos],"HEX_NPM")) - output=FMT_HEX_NPM; - else if (!strcasecmp(argv[argpos],"NOL")) output=FMT_NOL; - else if (!strcasecmp(argv[argpos],"NGG")) output=FMT_NGG; - else usage(myname); - } else if (STREQ(argv[argpos],"-net") && argc>argpos+1) { - char * const network_code_arg=argv[++argpos]; - unsigned int it; - len=strlen(network_code_arg); - if (len!=6) - pm_error("Network code must be 6 hex-digits long"); - for (it=0;itargpos+1) { - text=argv[++argpos]; +static void +parseCommandLine(int argc, 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. +-----------------------------------------------------------------------------*/ + optEntry * option_def; + /* Instructions to optParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + unsigned int fmtSpec, netSpec, txtSpec; + const char * fmtOpt; + const char * netOpt; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "fmt", OPT_STRING, &fmtOpt, + &fmtSpec, 0); + OPTENT3(0, "net", OPT_STRING, &netOpt, + &netSpec, 0); + OPTENT3(0, "txt", OPT_STRING, &cmdlineP->txt, + &txtSpec, 0); + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ + + optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (fmtSpec) { + if (STRCASEEQ(fmtOpt, "HEX_NOL")) + cmdlineP->outputFormat = FMT_HEX_NOL; + else if (STRCASEEQ(fmtOpt, "HEX_NGG")) + cmdlineP->outputFormat = FMT_HEX_NGG; + else if (STRCASEEQ(fmtOpt, "HEX_NPM")) + cmdlineP->outputFormat = FMT_HEX_NPM; + else if (STRCASEEQ(fmtOpt, "NOL")) + cmdlineP->outputFormat = FMT_NOL; + else if (STRCASEEQ(fmtOpt, "NGG")) + cmdlineP->outputFormat = FMT_NGG; + else if (STRCASEEQ(fmtOpt, "NPM")) + cmdlineP->outputFormat = FMT_NPM; + else + pm_error("-fmt option must be HEX_NGG, HEX_NOL, HEX_NPM, " + "NGG, NOL or NPM. You specified '%s'", fmtOpt); + } else + cmdlineP->outputFormat = FMT_HEX_NOL; + + if (netSpec) { + if (strlen(netOpt) != 6) + pm_error("-net option must be 6 hex digits long. " + "You specified %u characters", strlen(netOpt)); + else if (!strishex(netOpt)) + pm_error("-net option must be hexadecimal. You specified '%s'", + netOpt); + else + cmdlineP->networkCode = uppercase(netOpt); + } else + cmdlineP->networkCode = strdup("62F210"); /* German D1 net */ + + if (!txtSpec) + cmdlineP->txt = NULL; + else if (strlen(cmdlineP->txt) > 120) + pm_error("Text message is longer (%u characters) than " + "the 120 characters allowed by the format.", + strlen(cmdlineP->txt)); + + if (argc-1 == 0) + cmdlineP->inputFileName = "-"; + else if (argc-1 != 1) + pm_error("Program takes zero or one argument (filename). You " + "specified %u", argc-1); + else + cmdlineP->inputFileName = argv[1]; +} + + + +static void +freeCmdline(struct cmdlineInfo const cmdline) { + + strfree(cmdline.networkCode); +} + + + +static void +convertToHexNol(bit ** const image, + unsigned int const cols, + unsigned int const rows, + const char * const networkCode, + FILE * const ofP) { + + unsigned int row; + + /* header */ + fprintf(ofP, "06050415820000%s00%02X%02X01", networkCode, cols, rows); + + /* image */ + for (row = 0; row < rows; ++row) { + unsigned int col; + unsigned int p; + unsigned int c; + + c = 0; + + for (p = 0, col = 0; col < cols; ++col) { + if (image[row][col] == PBM_BLACK) + c |= 0x80 >> p; + if (++p == 8) { + fprintf(ofP, "%02X",c); + p = c = 0; } - else usage(myname); - } else break; + } + if (p > 0) + fprintf(ofP, "%02X", c); } +} - if (argpos==argc) { - image = pbm_readpbm(stdin, &cols, &rows); - } else { - fp=pm_openr(argv[argpos]); - image = pbm_readpbm(fp, &cols, &rows); - pm_close(fp); - } - memset(header,0,sizeof(header)); - switch (output) { - case FMT_HEX_NOL: - /* header */ - printf("06050415820000%s00%02X%02X01",network_code,cols,rows); - - /* image */ - for (row=0;row>p; - if (++p==8) { - printf("%02X",c); - p=c=0; - } +static void +convertToHexNgg(bit ** const image, + unsigned int const cols, + unsigned int const rows, + FILE * const ofP) { + + unsigned int row; + + /* header */ + fprintf(ofP, "0605041583000000%02X%02X01", cols, rows); + + /* image */ + for (row = 0; row < rows; ++row) { + unsigned int col; + unsigned int p; + unsigned int c; + + for (p = 0, c = 0, col = 0; col < cols; ++col) { + if (image[row][col] == PBM_BLACK) + c |= 0x80 >> p; + if (++p == 8) { + fprintf(ofP, "%02X", c); + p = c = 0; } - if (p) printf("%02X",c); } - break; - case FMT_HEX_NGG: - /* header */ - printf("0605041583000000%02X%02X01",cols,rows); - - /* image */ - for (row=0;row>p; - if (++p==8) { - printf("%02X",c); - p=c=0; - } + if (p > 0) + fprintf(ofP, "%02X", c); + } +} + + + + +static void +convertToHexNpm(bit ** const image, + unsigned int const cols, + unsigned int const rows, + const char * const text, + FILE * const ofP) { + + unsigned int row; + + /* header */ + fprintf(ofP, "060504158A0000"); + + /* text */ + if (text) { + size_t const len = strlen(text); + + unsigned int it; + + fprintf(ofP, "00%04X", len); + + for (it = 0; it < len; ++it) + fprintf(ofP, "%02X", text[it]); + } + + /* image */ + fprintf(ofP, "02%04X00%02X%02X01", (cols * rows) / 8 + 4, cols, rows); + + for (row = 0; row < rows; ++row) { + unsigned int col; + unsigned int p; + unsigned int c; + + for (p = 0, c = 0, col = 0; col < cols; ++col) { + if (image[row][col] == PBM_BLACK) + c |= 0x80 >> p; + if (++p == 8) { + fprintf(ofP, "%02X", c); + p = c = 0; } - if (p) printf("%02X",c); } - break; - case FMT_HEX_NPM: - /* header */ - printf("060504158A0000"); + if (p > 0) + fprintf(ofP, "%02X", c); + } +} + - /* text */ - if (text!=NULL) { - printf("00%04X",(len=strlen(text))); - for (it=0;it>p; - if (++p==8) { - printf("%02X",c); - p=c=0; - } - } - if (p) printf("%02X",c); + /* padding (to keep gnokii happy) */ + for (it = 0; it < 8 - cols * rows % 8; ++it) + putc('0', ofP); +} + + + + +static void +convertToNgg(bit ** const image, + unsigned int const cols, + unsigned int const rows, + FILE * const ofP) { + + unsigned int row; + char header[32]; + unsigned int it; + + /* header - this is a hack */ + + header[ 0] = 'N'; + header[ 1] = 'G'; + header[ 2] = 'G'; + header[ 3] = 0; + header[ 4] = 1; + header[ 5] = 0; + header[ 6] = cols; + header[ 7] = 0; + header[ 8] = rows; + header[ 9] = 0; + header[10] = 1; + header[11] = 0; + header[12] = 1; + header[13] = 0; + header[14] = 0x4a; + header[15] = 0; + + fwrite(header, 16, 1, ofP); + + /* image */ + + for (row = 0; row < rows; ++row) { + unsigned int col; + unsigned int p; + unsigned int c; + + for (p = 0, c = 0, col = 0; col < cols; ++col) { + char const output = image[row][col] == PBM_BLACK ? '1' : '0'; + + putc(output, ofP); } - break; - case FMT_NOL: - /* header - this is a hack */ - header[0]='N'; - header[1]='O'; - header[2]='L'; - header[4]=header[7]=header[8]=header[14]=header[16]=1; - header[6]=4; - header[10]=cols; - header[12]=rows; - header[18]=0x53; - fwrite(header,20,1,stdout); - - /* image */ - for (row=0;row\n", - output); - return 1; } + +freeCmdline(cmdline); + return 0; } + + +/* Copyright (C)2001 OMS Open Media System GmbH, Tim Rühsen +** . +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. + + Created 2001.06.07 + +Notes: + - limited to rows <= 255 and columns <= 255 + - limited to b/w graphics, not animated + +Testing: + Testing was done with SwissCom SMSC (Switzerland) and IC3S SMSC (Germany). + The data was send with EMI/UCP protocol over TCP/IP. + + - 7.6.2001: tested with Nokia 3210: 72x14 Operator Logo + - 7.6.2001: tested with Nokia 6210: 72x14 Operator Logo and + 72x14 Group Graphic +*/ diff --git a/converter/ppm/ppmtobmp.c b/converter/ppm/ppmtobmp.c index 071f3b12..b9ac063e 100644 --- a/converter/ppm/ppmtobmp.c +++ b/converter/ppm/ppmtobmp.c @@ -647,7 +647,7 @@ choose_colortype_bpp(struct cmdline_info const cmdline, pm_error("There are too many colors in the image to " "represent in the\n" "number of bits per pixel you requested: %d.\n" - "You may use Ppmquant to reduce the number of " + "You may use Pnmquant to reduce the number of " "colors in the image.", cmdline.bpp); else diff --git a/converter/ppm/ppmtompeg/Makefile b/converter/ppm/ppmtompeg/Makefile index 5e923fee..6db72ea9 100644 --- a/converter/ppm/ppmtompeg/Makefile +++ b/converter/ppm/ppmtompeg/Makefile @@ -18,11 +18,12 @@ else JPEGLIBX = $(JPEGLIB) endif -INCLUDES = -I$(SRCDIR)/$(SUBDIR)/headers +COMP_INCLUDES = -I$(SRCDIR)/$(SUBDIR)/headers +EXTERN_INCLUDES = ifneq ($(JPEGHDR_DIR),NONE) ifneq ($(JPEGHDR_DIR)x,x) - INCLUDES += -I$(JPEGHDR_DIR) + EXTERN_INCLUDES += -I$(JPEGHDR_DIR) endif endif diff --git a/converter/ppm/xvminitoppm.c b/converter/ppm/xvminitoppm.c index dfc76fcf..8cea1f9d 100644 --- a/converter/ppm/xvminitoppm.c +++ b/converter/ppm/xvminitoppm.c @@ -12,6 +12,7 @@ #include #include +#include #include "pm_c_util.h" #include "nstring.h" @@ -61,7 +62,8 @@ getline(FILE * const ifP, rc = fgets(buf, size, ifP); if (rc == NULL) { if (ferror(ifP)) - pm_perror("read error"); + pm_error("read error. fgets() failed, errno=%d (%s)", + errno, strerror(errno)); else pm_error("unexpected EOF"); } diff --git a/doc/HISTORY b/doc/HISTORY index 9e057e6d..64c0e95b 100644 --- a/doc/HISTORY +++ b/doc/HISTORY @@ -1,41 +1,55 @@ See http://netpbm.sourceforge.net/history.html for a general history of Netpbm. - CHANGE HISTORY -------------- -06.09.11 BJH Release 10.35.05 - - Remove some generated files from release so build works. +06.09.21 BJH Release 10.36.0 - Properly clean thinkjettopbm.c with 'make distclean'. + pbmtonokia: Add plain NPM output capability. Thanks Paul Bolle + . -06.09.10 BJH Release 10.35.04 + pbmtonokia: Pad to 8 bytes. Thanks Paul Bolle + . - Fix version number control. + pbmtonokia: Limit text to 120 bytes. Thanks Paul Bolle + . -06.09.09 BJH Release 10.35.03 + pamthreshold: don't gather global information, and reread + file, for local thresholding (to save time, resources). + Thanks Erik Auerswald . - Remove general history from change file + libnetpbm: BK color matching adjustments, change of + enum bk_color. Thanks "Kenan Kalajdzic" + . -06.09.03 BJH Release 10.35.02 + Fix version number control. pbmtonokia: fix headers of NGG and NOL to include 3 character magic. + Release allocated memory before longjmping from libnetpbm. + + Eliminate pm_perror() in favor of informative error messages. + + libnetpbm: fix rgb:r/g/b color name parsing for invalid + syntax. + + Add pm_errormsg(), pm_setusererrormsg(), pm_setusermessage(). + pm_accept_to_pamtuples: fix bug: fill in pam structure. Thanks "Christian Schlotter" . -06.08.26 BJH Release 10.35.01 - Fix selection of MMX_SEE fastpath based on GNU compiler version number. - libnetpbm: fix rgb:r/g/b color name parsing for invalid - syntax. + Properly clean thinkjettopbm.c with 'make distclean'. + + Remove some generated files from release so build works. + + Remove general history from change file -06.08.19 BJH Release 10.35.00 +06.08.19 BJH Release 10.35.0 Add pgmdeshadow. diff --git a/doc/INSTALL b/doc/INSTALL index 78cf1ebf..c83b725d 100644 --- a/doc/INSTALL +++ b/doc/INSTALL @@ -173,6 +173,9 @@ shared libraries (which is kept in /var/ld/ld.config). Make sure that path includes the directory in which you installed the Netpbm shared library. You can also use the LD_LIBRARY_PATH environment variable. +On AIX, the environment variable LIBPATH affects the share library search +path. On AIX 5.3 and newer, you can use LD_LIBRARY_PATH as well. + Besides the Netpbm shared library, libnetpbm, several of the converter programs, e.g. Jpegtopnm, use separately distributed libraries that understand the graphics format involved. You need to make sure your diff --git a/editor/pamperspective.c b/editor/pamperspective.c index fdf446c7..08011cc3 100644 --- a/editor/pamperspective.c +++ b/editor/pamperspective.c @@ -161,9 +161,9 @@ typedef struct { xw_ll, yw_ll, zw_ll, xw_lr, yw_lr, zw_lr; /* Originally I planned to include the possibility to move the - centre of projection, that is the pixel the camera "looks at". It + center of projection, that is the pixel the camera "looks at". It turned out, maybe surprisingly, that this does not have any - effect. So now this centre is moved to (0,0). + effect. So now this center is moved to (0,0). Another original plan was to correct the output parameters depending on the lengths of the paralellograms sides or its @@ -714,7 +714,7 @@ static void determine_world_parallelogram (world_data *const world, point of an image determines a line in the world. 3 equations state that the 4 points form a parallelogram. The 4th - equation is for normalization and states, that the centre of the + equation is for normalization and states, that the center of the parallelogram has a z-coordinate of 1. -----------------------------------------------------------------------------*/ { @@ -1021,8 +1021,8 @@ static void determine_coefficients_pixel (world_data *const world, Constructs ax,...,cz from xw_ul,...,zw_lr The calculations assume pixel coordinates, that is the point ul - corresponds to the centre of the pixel (0,0) and the point lr - corresponds to the centre of the pixel (width-1,height-1) + corresponds to the center of the pixel (0,0) and the point lr + corresponds to the center of the pixel (width-1,height-1) -----------------------------------------------------------------------------*/ { number width,height; diff --git a/editor/pamthreshold.c b/editor/pamthreshold.c index 40260e79..4caaed9b 100644 --- a/editor/pamthreshold.c +++ b/editor/pamthreshold.c @@ -508,9 +508,16 @@ thresholdLocal(struct pam * const inpamP, windowHeight = MIN(oddLocalHeight, inpamP->height); - analyzeDistribution(inpamP, &histogram, &globalRange); - - computeGlobalThreshold(inpamP, histogram, globalRange, &globalThreshold); + /* global information is needed for dual thresholding */ + if (cmdline.dual) { + analyzeDistribution(inpamP, &histogram, &globalRange); + computeGlobalThreshold(inpamP, histogram, globalRange, + &globalThreshold); + } else { + histogram = NULL; + initRange(&globalRange); + globalThreshold = 1.0; + } outrow = pnm_allocpamrow(outpamP); @@ -580,17 +587,17 @@ main(int argc, char **argv) { parseCommandLine(argc, argv, &cmdline); - if (cmdline.simple) + if (cmdline.simple || cmdline.local) ifP = pm_openr(cmdline.inputFileName); else ifP = pm_openr_seekable(cmdline.inputFileName); - /* threshold each image in the PAM file */ + /* Threshold each image in the PAM file */ eof = FALSE; while (!eof) { pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); - /* set output image parameters for a bilevel image */ + /* Set output image parameters for a bilevel image */ outpam.size = sizeof(outpam); outpam.len = PAM_STRUCT_SIZE(tuple_type); outpam.file = stdout; @@ -605,7 +612,7 @@ main(int argc, char **argv) { pnm_writepaminit(&outpam); - /* do the thresholding */ + /* Do the thresholding */ if (cmdline.simple) thresholdSimple(&inpam, &outpam, cmdline.threshold); diff --git a/editor/pbmpscale.c b/editor/pbmpscale.c index 63f203ed..2e24f3cd 100644 --- a/editor/pbmpscale.c +++ b/editor/pbmpscale.c @@ -81,119 +81,125 @@ void nextrow_pscale(ifd, row) } + + int -main(argc, argv) - int argc; - char *argv[]; -{ - FILE *ifd; - register bit *outrow; - register int row, col, i, k; - int scale, cutoff, ucutoff ; - unsigned char *flags; - - pbm_init( &argc, argv ); - - if (argc < 2) - pm_usage("scale [pbmfile]"); - - scale = atoi(argv[1]); - if (scale < 1) - pm_perror("bad scale (< 1)"); - - if (argc == 3) - ifd = pm_openr(argv[2]); - else - ifd = stdin ; - - inrow[0] = inrow[1] = inrow[2] = NULL; - pbm_readpbminit(ifd, &columns, &rows, &format) ; - - outrow = pbm_allocrow(columns*scale) ; - MALLOCARRAY(flags, columns); - if (flags == NULL) - pm_error("out of memory") ; - - pbm_writepbminit(stdout, columns*scale, rows*scale, 0) ; - - cutoff = scale / 2; - ucutoff = scale - 1 - cutoff; - nextrow_pscale(ifd, 0); - for (row = 0; row < rows; row++) { - nextrow_pscale(ifd, row+1); - for (col = 0; col < columns; col++) { - flags[col] = 0 ; - for (i = 0; i != 8; i += 2) { - int vec = inrow[thisrow][col] != PBM_WHITE; - for (k = 0; k < 7; k++) { - int x = col + xd_pscale[(k+i)&7] ; - int y = thisrow + yd_pscale[(k+i)&7] ; - vec <<= 1; - if (x >=0 && x < columns && inrow[y]) - vec |= (inrow[y][x] != PBM_WHITE) ; +main(int argc, char ** argv) { + + FILE * ifP; + bit * outrow; + unsigned int row; + int scale, cutoff, ucutoff ; + unsigned char *flags; + + pbm_init( &argc, argv ); + + if (argc < 2) + pm_usage("scale [pbmfile]"); + + scale = atoi(argv[1]); + if (scale < 1) + pm_error("Scale argument must be at least one. You specified '%s'", + argv[1]); + + if (argc == 3) + ifP = pm_openr(argv[2]); + else + ifP = stdin ; + + inrow[0] = inrow[1] = inrow[2] = NULL; + pbm_readpbminit(ifP, &columns, &rows, &format) ; + + outrow = pbm_allocrow(columns*scale) ; + MALLOCARRAY(flags, columns); + if (flags == NULL) + pm_error("out of memory") ; + + pbm_writepbminit(stdout, columns*scale, rows*scale, 0) ; + + cutoff = scale / 2; + ucutoff = scale - 1 - cutoff; + nextrow_pscale(ifP, 0); + for (row = 0; row < rows; ++row) { + unsigned int col; + unsigned int i; + nextrow_pscale(ifP, row+1); + for (col = 0; col < columns; ++col) { + unsigned int i; + flags[col] = 0 ; + for (i = 0; i != 8; i += 2) { + int vec = inrow[thisrow][col] != PBM_WHITE; + unsigned int k; + for (k = 0; k < 7; ++k) { + int x = col + xd_pscale[(k+i)&7] ; + int y = thisrow + yd_pscale[(k+i)&7] ; + vec <<= 1; + if (x >=0 && x < columns && inrow[y]) + vec |= (inrow[y][x] != PBM_WHITE) ; + } + flags[col] |= corner(vec)< ucutoff) - (i < cutoff) ; - int cut = (zone < 0) ? (cutoff - i) : - (zone > 0) ? (i - ucutoff) : 0 ; - - for (col = 0; col < columns; col++) { - int pix = inrow[thisrow][col] ; - int flag = flags[col] ; - int cutl, cutr ; - - switch (zone) { - case -1: - switch (NW(flag)) { - case 0: cutl = 0; break; - case 1: cutl = cut; break; - case 2: cutl = cut ? cut-1 : 0; break; - case 3: cutl = (cut && cutoff > 1) ? cut-1 : cut; break; - default: cutl = 0; /* Should never reach here */ - } - switch (NE(flag)) { - case 0: cutr = 0; break; - case 1: cutr = cut; break; - case 2: cutr = cut ? cut-1 : 0; break; - case 3: cutr = (cut && cutoff > 1) ? cut-1 : cut; break; - default: cutr = 0; /* Should never reach here */ - } - break; - case 0: - cutl = cutr = 0; - break ; - case 1: - switch (SW(flag)) { - case 0: cutl = 0; break; - case 1: cutl = cut; break; - case 2: cutl = cut ? cut-1 : 0; break; - case 3: cutl = (cut && cutoff > 1) ? cut-1 : cut; break; - default: cutl = 0; /* should never reach here */ - } - switch (SE(flag)) { - case 0: cutr = 0; break; - case 1: cutr = cut; break; - case 2: cutr = cut ? cut-1 : 0; break; - case 3: cutr = (cut && cutoff > 1) ? cut-1 : cut; break; - default: cutr = 0; /* should never reach here */ - } - break; - default: cutl = 0; cutr = 0; /* Should never reach here */ + } + for (i = 0; i < scale; i++) { + bit *ptr = outrow ; + int zone = (i > ucutoff) - (i < cutoff) ; + int cut = (zone < 0) ? (cutoff - i) : + (zone > 0) ? (i - ucutoff) : 0 ; + + for (col = 0; col < columns; ++col) { + int pix = inrow[thisrow][col] ; + int flag = flags[col] ; + int cutl, cutr; + unsigned int k; + + switch (zone) { + case -1: + switch (NW(flag)) { + case 0: cutl = 0; break; + case 1: cutl = cut; break; + case 2: cutl = cut ? cut-1 : 0; break; + case 3: cutl = (cut && cutoff > 1) ? cut-1 : cut; break; + default: cutl = 0; /* Should never reach here */ + } + switch (NE(flag)) { + case 0: cutr = 0; break; + case 1: cutr = cut; break; + case 2: cutr = cut ? cut-1 : 0; break; + case 3: cutr = (cut && cutoff > 1) ? cut-1 : cut; break; + default: cutr = 0; /* Should never reach here */ + } + break; + case 0: + cutl = cutr = 0; + break ; + case 1: + switch (SW(flag)) { + case 0: cutl = 0; break; + case 1: cutl = cut; break; + case 2: cutl = cut ? cut-1 : 0; break; + case 3: cutl = (cut && cutoff > 1) ? cut-1 : cut; break; + default: cutl = 0; /* should never reach here */ + } + switch (SE(flag)) { + case 0: cutr = 0; break; + case 1: cutr = cut; break; + case 2: cutr = cut ? cut-1 : 0; break; + case 3: cutr = (cut && cutoff > 1) ? cut-1 : cut; break; + default: cutr = 0; /* should never reach here */ + } + break; + default: cutl = 0; cutr = 0; /* Should never reach here */ + } + for (k = 0; k < cutl; ++k) /* left part */ + *ptr++ = !pix ; + for (k = 0; k < scale-cutl-cutr; ++k) /* center part */ + *ptr++ = pix ; + for (k = 0; k < cutr; ++k) /* right part */ + *ptr++ = !pix ; } - for (k = 0; k < cutl; k++) /* left part */ - *ptr++ = !pix ; - for (k = 0; k < scale-cutl-cutr; k++) /* centre part */ - *ptr++ = pix ; - for (k = 0; k < cutr; k++) /* right part */ - *ptr++ = !pix ; - } - pbm_writepbmrow(stdout, outrow, scale*columns, 0) ; - } - } - pm_close(ifd); - exit(0); + pbm_writepbmrow(stdout, outrow, scale*columns, 0) ; + } + } + pm_close(ifP); + return 0; } diff --git a/editor/pnmcrop.c b/editor/pnmcrop.c index 5fafbaac..4ef778c3 100644 --- a/editor/pnmcrop.c +++ b/editor/pnmcrop.c @@ -338,13 +338,19 @@ findBordersInFile(const char * const borderFileName, +static const char * +ending(unsigned int const n) { + + return n > 1 ? "s" : ""; +} + + + static void reportOneEdge(unsigned int const oldBorderSize, unsigned int const newBorderSize, const char * const place) { -#define ending(n) (((n) > 1) ? "s" : "") - if (newBorderSize > oldBorderSize) pm_message("Adding %u pixel%s to the %u-pixel %s border", newBorderSize - oldBorderSize, @@ -376,10 +382,10 @@ reportCroppingParameters(unsigned int const oldLeftBorderSize, oldTopBorderSize == 0 && oldBottomBorderSize == 0) pm_message("No Border found."); - reportOneEdge(oldLeftBorderSize, newLeftBorderSize, "left" ); - reportOneEdge(oldRightBorderSize, newRightBorderSize, "right" ); - reportOneEdge(oldTopBorderSize, newTopBorderSize, "top" ); - reportOneEdge(oldBottomBorderSize, newBottomBorderSize, "bottom" ); + reportOneEdge(oldLeftBorderSize, newLeftBorderSize, "left" ); + reportOneEdge(oldRightBorderSize, newRightBorderSize, "right" ); + reportOneEdge(oldTopBorderSize, newTopBorderSize, "top" ); + reportOneEdge(oldBottomBorderSize, newBottomBorderSize, "bottom"); } diff --git a/editor/pnmrotate.c b/editor/pnmrotate.c index 64c69e2a..fafb2f3a 100644 --- a/editor/pnmrotate.c +++ b/editor/pnmrotate.c @@ -705,7 +705,7 @@ shearXToOutputFile(FILE * const ofP, unsigned int row; xel * xelrow; - pnm_writepnminit(stdout, newcols, rows, maxval, format, 0); + pnm_writepnminit(ofP, newcols, rows, maxval, format, 0); xelrow = pnm_allocrow(newcols); @@ -722,7 +722,7 @@ shearXToOutputFile(FILE * const ofP, shearFinal(xels[row], xelrow, cols, newcols, format, bgColor, antialias, shiftAmount, x2shearjunk); - pnm_writepnmrow(stdout, xelrow, newcols, maxval, format, 0); + pnm_writepnmrow(ofP, xelrow, newcols, maxval, format, 0); } pnm_freerow(xelrow); } diff --git a/generator/pamstereogram.test b/generator/pamstereogram.test index 7eb01fff..80f70ee0 100644 --- a/generator/pamstereogram.test +++ b/generator/pamstereogram.test @@ -20,7 +20,7 @@ echo Test 10. Should print 1266273778 293: ./pamstereogram -randomseed=1 -makemask ../testgrid.pbm | cksum echo Test 11. Should print 3034751595 1070: -./pamgauss 100 10 -maxval=10000 -sigma 20 | pamfunc -multiplier=500 | \ +pamgauss 100 10 -maxval=10000 -sigma 20 | pamfunc -multiplier=500 | \ ./pamstereogram -randomseed=1 -dpi=10 -makemask | cksum # Grayscale @@ -28,11 +28,11 @@ echo Test 11. Should print 3034751595 1070: echo Test 20. Should print 2468969328 289: ./pamstereogram -randomseed=1 -grayscale ../testgrid.pbm | cksum echo Test 21. Should print 1946982115 4068: -./pamseq 1 100 | pnmtile 200 20 | \ +pamseq 1 100 | pnmtile 200 20 | \ ./pamstereogram -randomseed=1 -dpi=10 -grayscale | \ cksum echo Test 22. Should print 2078013430 4068: -./pamseq 1 100 | pnmtile 200 20 | \ +pamseq 1 100 | pnmtile 200 20 | \ ./pamstereogram -randomseed=1 -dpi=10 -grayscale -maxval 255 | \ cksum @@ -41,7 +41,7 @@ echo Test 22. Should print 2078013430 4068: echo Test 30. Should print 1319392622 731: ./pamstereogram -randomseed=1 -color ../testgrid.pbm | cksum echo Test 31. Should print 389886159 12062: -./pamseq 1 100 | pnmtile 200 20 | \ +pamseq 1 100 | pnmtile 200 20 | \ ./pamstereogram -randomseed=1 -dpi=10 -color | \ cksum diff --git a/lib/Makefile b/lib/Makefile index bd8eccae..704b838a 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -40,7 +40,7 @@ ifneq (${VMS}x,x) LIBOBJECTS += libpbmvms.o endif # Library objects to be linked but not built by Makefile.common: -LIBOBJECTS_X = util/shhopt.o util/nstring.o util/filename.o +LIBOBJECTS_X = util/shhopt.o util/nstring.o util/vasprintf.o util/filename.o MANUALS3 = libnetpbm MANUALS5 = pbm pgm ppm pnm pam @@ -55,8 +55,6 @@ DATAFILES = rgb.txt .PHONY: all all: libnetpbm extra_staticlib -INCLUDES = -I$(SRCDIR)/$(SUBDIR) -I. -Iimportinc - SUBDIRS = util SCRIPTS = BINARIES = @@ -64,6 +62,8 @@ BINARIES = OMIT_LIBRARY_RULE = 1 include $(SRCDIR)/Makefile.common +INCLUDES = -I$(SRCDIR)/$(SUBDIR) -I. -Iimportinc + # The following must go after Makefile.common because $(LIBNETPBM) may # contain a reference to $(NETPBM_MAJOR_RELEASE). .PHONY: libnetpbm diff --git a/lib/libpammap.c b/lib/libpammap.c index 9e90ade0..98c7f798 100644 --- a/lib/libpammap.c +++ b/lib/libpammap.c @@ -24,12 +24,13 @@ #define HASH_SIZE 20023 unsigned int -pnm_hashtuple(struct pam * const pamP, tuple const tuple) { +pnm_hashtuple(struct pam * const pamP, + tuple const tuple) { /*---------------------------------------------------------------------------- Return the hash value of the tuple 'tuple' -- i.e. an index into a hash table. -----------------------------------------------------------------------------*/ - int i; + unsigned int i; unsigned int hash; const unsigned int hash_factor[] = {33023, 30013, 27011}; @@ -281,7 +282,7 @@ computehashrecoverable(struct pam * const pamP, tuple values. */ for (row = 0; row < pamP->height && !full; ++row) { - int col; + unsigned int col; const tuple * tuplerow; /* The row of tuples we are processing */ if (tupleArray) @@ -354,19 +355,20 @@ computetuplefreqhash(struct pam * const pamP, rowbuffer = NULL; color = NULL; - if (setjmp(jmpbuf) == 0) { - pm_setjmpbufsave(&jmpbuf, &origJmpbufP); - computehashrecoverable(pamP, tupleArray, maxsize, newMaxval, sizeP, - &tuplefreqhash, &rowbuffer, &color); - pm_setjmpbuf(origJmpbufP); - } else { + if (setjmp(jmpbuf) != 0) { if (color) pnm_freepamtuple(color); if (rowbuffer) pnm_freepamrow(rowbuffer); if (tuplefreqhash) pnm_destroytuplehash(tuplefreqhash); + pm_setjmpbuf(origJmpbufP); pm_longjmp(); + } else { + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + computehashrecoverable(pamP, tupleArray, maxsize, newMaxval, sizeP, + &tuplefreqhash, &rowbuffer, &color); + pm_setjmpbuf(origJmpbufP); } return tuplefreqhash; } diff --git a/lib/libpamn.c b/lib/libpamn.c index c7610100..2ec50e7e 100644 --- a/lib/libpamn.c +++ b/lib/libpamn.c @@ -10,6 +10,7 @@ #include "pm_c_util.h" #include "mallocvar.h" +#include "nstring.h" #include "pam.h" #include "fileio.h" #include "pm_gamma.h" @@ -18,15 +19,19 @@ -tuplen * -pnm_allocpamrown(const struct pam * const pamP) { +static void +allocpamrown(const struct pam * const pamP, + tuplen ** const tuplerownP, + const char ** const errorP) { /*---------------------------------------------------------------------------- We assume that the dimensions of the image are such that arithmetic overflow will not occur in our calculations. NOTE: pnm_readpaminit() ensures this assumption is valid. -----------------------------------------------------------------------------*/ - const int bytes_per_tuple = pamP->depth * sizeof(samplen); + int const bytes_per_tuple = pamP->depth * sizeof(samplen); + tuplen * tuplerown; + const char * error; /* The tuple row data structure starts with 'width' pointers to the tuples, immediately followed by the 'width' tuples @@ -35,64 +40,106 @@ pnm_allocpamrown(const struct pam * const pamP) { tuplerown = malloc(pamP->width * (sizeof(tuplen *) + bytes_per_tuple)); if (tuplerown == NULL) - pm_error("Out of memory allocating space for a tuple row of\n" - "%d tuples by %d samples per tuple by %d bytes per sample.", - pamP->width, pamP->depth, sizeof(samplen)); - - { + asprintfN(&error, "Out of memory allocating space for a tuple row of" + "%u tuples by %u samples per tuple by %u bytes per sample.", + pamP->width, pamP->depth, sizeof(samplen)); + else { /* Now we initialize the pointers to the individual tuples to make this a regulation C two dimensional array. */ - char *p; - int i; + unsigned char * p; + unsigned int i; - p = (char*) (tuplerown + pamP->width); /* location of Tuple 0 */ - for (i = 0; i < pamP->width; i++) { + p = (unsigned char*) (tuplerown + pamP->width); + /* location of Tuple 0 */ + for (i = 0; i < pamP->width; ++i) { tuplerown[i] = (tuplen) p; p += bytes_per_tuple; } + *errorP = NULL; + *tuplerownP = tuplerown; } - return(tuplerown); } -void -pnm_readpamrown(const struct pam * const pamP, - tuplen * const tuplenrow) { +tuplen * +pnm_allocpamrown(const struct pam * const pamP) { +/*---------------------------------------------------------------------------- + We assume that the dimensions of the image are such that arithmetic + overflow will not occur in our calculations. NOTE: pnm_readpaminit() + ensures this assumption is valid. +-----------------------------------------------------------------------------*/ + const char * error; + tuplen * tuplerown; - /* For speed, we don't check any of the inputs for consistency - here (unless it's necessary to avoid crashing). Any consistency - checking should have been done by a prior call to - pnm_writepaminit(). - */ - assert(pamP->maxval != 0); + allocpamrown(pamP, &tuplerown, &error); - /* Need a special case for raw PBM because it has multiple tuples (8) - packed into one byte. - */ - if (PAM_FORMAT_TYPE(pamP->format) == PBM_TYPE) { - int col; - bit *bitrow; - if (pamP->depth != 1) - pm_error("Invalid pam structure passed to pnm_readpamrow(). " - "It says PBM format, but 'depth' member is not 1."); - bitrow = pbm_allocrow(pamP->width); - pbm_readpbmrow(pamP->file, bitrow, pamP->width, pamP->format); - for (col = 0; col < pamP->width; col++) - tuplenrow[col][0] = - bitrow[col] == PBM_BLACK ? 0.0 : 1.0; + if (error) { + pm_errormsg("pnm_allocpamrown() failed. %s", error); + strfree(error); + pm_longjmp(); + } + + return tuplerown; +} + + + +static void +readpbmrow(const struct pam * const pamP, + tuplen * const tuplenrow) { + + bit * bitrow; + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + + bitrow = pbm_allocrow(pamP->width); + + if (setjmp(jmpbuf) != 0) { pbm_freerow(bitrow); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + unsigned int col; + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + + pbm_readpbmrow(pamP->file, bitrow, pamP->width, pamP->format); + + for (col = 0; col < pamP->width; ++col) + tuplenrow[col][0] = bitrow[col] == PBM_BLACK ? 0.0 : 1.0; + + pm_setjmpbuf(origJmpbufP); + } + pbm_freerow(bitrow); +} + + + +static void +readpamrow(const struct pam * const pamP, + tuplen * const tuplenrow) { + + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + tuple * tuplerow; + + tuplerow = pnm_allocpamrow(pamP); + + if (setjmp(jmpbuf) != 0) { + pnm_freepamrow(tuplerow); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); } else { float const scaler = 1.0 / pamP->maxval; /* Note: multiplication is faster than division, so we divide once here so we can multiply many times later. */ - int col; - tuple * tuplerow; - tuplerow = pnm_allocpamrow(pamP); + unsigned int col; + + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); pnm_readpamrow(pamP, tuplerow); for (col = 0; col < pamP->width; ++col) { @@ -100,15 +147,16 @@ pnm_readpamrown(const struct pam * const pamP, for (plane = 0; plane < pamP->depth; ++plane) tuplenrow[col][plane] = tuplerow[col][plane] * scaler; } - pnm_freepamrow(tuplerow); + pm_setjmpbuf(origJmpbufP); } + pnm_freepamrow(tuplerow); } void -pnm_writepamrown(const struct pam * const pamP, - const tuplen * const tuplenrow) { +pnm_readpamrown(const struct pam * const pamP, + tuplen * const tuplenrow) { /* For speed, we don't check any of the inputs for consistency here (unless it's necessary to avoid crashing). Any consistency @@ -121,20 +169,66 @@ pnm_writepamrown(const struct pam * const pamP, packed into one byte. */ if (PAM_FORMAT_TYPE(pamP->format) == PBM_TYPE) { - int col; - bit *bitrow; - bitrow = pbm_allocrow(pamP->width); - for (col = 0; col < pamP->width; col++) - bitrow[col] = - tuplenrow[col][0] < 0.5 ? PBM_BLACK : PBM_WHITE; + if (pamP->depth != 1) + pm_error("Invalid pam structure passed to pnm_readpamrow(). " + "It says PBM format, but 'depth' member is not 1."); + + readpbmrow(pamP, tuplenrow); + } else + readpamrow(pamP, tuplenrow); +} + + + +static void +writepbmrow(const struct pam * const pamP, + const tuplen * const tuplenrow) { + + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + bit * bitrow; + + bitrow = pbm_allocrow(pamP->width); + + if (setjmp(jmpbuf) != 0) { + pbm_freerow(bitrow); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + unsigned int col; + + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + + for (col = 0; col < pamP->width; ++col) + bitrow[col] = tuplenrow[col][0] < 0.5 ? PBM_BLACK : PBM_WHITE; pbm_writepbmrow(pamP->file, bitrow, pamP->width, pamP->format == PBM_FORMAT); - pbm_freerow(bitrow); + + pm_setjmpbuf(origJmpbufP); + } + pbm_freerow(bitrow); +} + + + +static void +writepamrow(const struct pam * const pamP, + const tuplen * const tuplenrow) { + + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + tuple * tuplerow; + + tuplerow = pnm_allocpamrow(pamP); + + if (setjmp(jmpbuf) != 0) { + pnm_freepamrow(tuplerow); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); } else { - tuple * tuplerow; - int col; + unsigned int col; - tuplerow = pnm_allocpamrow(pamP); + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); for (col = 0; col < pamP->width; ++col) { unsigned int plane; @@ -143,8 +237,32 @@ pnm_writepamrown(const struct pam * const pamP, (tuplenrow[col][plane] * pamP->maxval + 0.5); } pnm_writepamrow(pamP, tuplerow); - pnm_freepamrow(tuplerow); + + pm_setjmpbuf(origJmpbufP); } + pnm_freepamrow(tuplerow); +} + + + +void +pnm_writepamrown(const struct pam * const pamP, + const tuplen * const tuplenrow) { + + /* For speed, we don't check any of the inputs for consistency + here (unless it's necessary to avoid crashing). Any consistency + checking should have been done by a prior call to + pnm_writepaminit(). + */ + assert(pamP->maxval != 0); + + /* Need a special case for raw PBM because it has multiple tuples (8) + packed into one byte. + */ + if (PAM_FORMAT_TYPE(pamP->format) == PBM_TYPE) + writepbmrow(pamP, tuplenrow); + else + writepamrow(pamP, tuplenrow); } @@ -152,8 +270,8 @@ pnm_writepamrown(const struct pam * const pamP, tuplen ** pnm_allocpamarrayn(const struct pam * const pamP) { - tuplen **tuplenarray; - int row; + tuplen ** tuplenarray; + const char * error; /* If the speed of this is ever an issue, it might be sped up a little by allocating one large chunk. @@ -161,12 +279,32 @@ pnm_allocpamarrayn(const struct pam * const pamP) { MALLOCARRAY(tuplenarray, pamP->height); if (tuplenarray == NULL) - pm_error("Out of memory allocating the row pointer section of " - "a %u row array", pamP->height); - - for (row = 0; row < pamP->height; row++) { - tuplenarray[row] = pnm_allocpamrown(pamP); + asprintfN(&error, + "Out of memory allocating the row pointer section of " + "a %u row array", pamP->height); + else { + unsigned int rowsDone; + + rowsDone = 0; + + while (rowsDone < pamP->height && !error) { + allocpamrown(pamP, &tuplenarray[rowsDone], &error); + if (!error) + ++rowsDone; + } + if (error) { + unsigned int row; + for (row = 0; row < rowsDone; ++row) + pnm_freepamrown(tuplenarray[rowsDone]); + free(tuplenarray); + } + } + if (error) { + pm_errormsg("pnm_allocpamarrayn() failed. %s", error); + strfree(error); + pm_longjmp(); } + return(tuplenarray); } @@ -191,16 +329,28 @@ pnm_readpamn(FILE * const file, int const size) { tuplen **tuplenarray; - int row; + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; pnm_readpaminit(file, pamP, size); tuplenarray = pnm_allocpamarrayn(pamP); - for (row = 0; row < pamP->height; row++) - pnm_readpamrown(pamP, tuplenarray[row]); + if (setjmp(jmpbuf) != 0) { + pnm_freepamarrayn(tuplenarray, pamP); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + unsigned int row; - return(tuplenarray); + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + + for (row = 0; row < pamP->height; ++row) + pnm_readpamrown(pamP, tuplenarray[row]); + + pm_setjmpbuf(origJmpbufP); + } + return tuplenarray; } @@ -209,11 +359,11 @@ void pnm_writepamn(struct pam * const pamP, tuplen ** const tuplenarray) { - int row; + unsigned int row; pnm_writepaminit(pamP); - for (row = 0; row < pamP->height; row++) + for (row = 0; row < pamP->height; ++row) pnm_writepamrown(pamP, tuplenarray[row]); } @@ -473,6 +623,8 @@ createUngammaMapOffset(const struct pam * const pamP, can be used in a reverse lookup to convert normalized ungamma'ed samplen values to integer sample values. The 0.5 effectively does the rounding. + + This never throws an error. Return value NULL means failed. -----------------------------------------------------------------------------*/ pnm_transformMap * retval; pnm_transformMap ungammaTransformMap; diff --git a/lib/libpamread.c b/lib/libpamread.c index 1b65745a..85701a90 100644 --- a/lib/libpamread.c +++ b/lib/libpamread.c @@ -18,30 +18,46 @@ #include "pam.h" #include "fileio.h" +#include "nstring.h" static void readPbmRow(const struct pam * const pamP, tuple * const tuplerow) { - unsigned char *bitrow; if (pamP->depth != 1) pm_error("Invalid pam structure passed to pnm_readpamrow(). " "It says PBM format, but 'depth' member is not 1."); + else { + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + unsigned char * bitrow; + + bitrow = (unsigned char *) pbm_allocrow(pbm_packed_bytes(pamP->width)); + + if (setjmp(jmpbuf) != 0) { + pbm_freerow(bitrow); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + + pbm_readpbmrow_packed(pamP->file, bitrow, pamP->width, + pamP->format); - bitrow = (unsigned char *) pbm_allocrow(pbm_packed_bytes(pamP->width)); - pbm_readpbmrow_packed(pamP->file, bitrow, pamP->width, pamP->format); - - if (tuplerow) { - int col; - for (col = 0; col < pamP->width; ++col) { - tuplerow[col][0] = - ( ((bitrow[col/8] >> (7-col%8)) & 1 ) == PBM_BLACK) - ? PAM_PBM_BLACK : PAM_PBM_WHITE - ; + if (tuplerow) { + unsigned int col; + for (col = 0; col < pamP->width; ++col) { + tuplerow[col][0] = + ( ((bitrow[col/8] >> (7-col%8)) & 1 ) == PBM_BLACK) + ? PAM_PBM_BLACK : PAM_PBM_WHITE + ; + } + } + pm_setjmpbuf(origJmpbufP); } - } - pbm_freerow(bitrow); + pbm_freerow(bitrow); + } } @@ -185,6 +201,7 @@ readRawNonPbmRow(const struct pam * const pamP, unsigned char * inbuf; size_t bytesRead; + const char * error; inbuf = pnm_allocrowimage(pamP); @@ -192,25 +209,34 @@ readRawNonPbmRow(const struct pam * const pamP, if (bytesRead != rowImageSize) { if (feof(pamP->file)) - pm_error("End of file encountered when trying to read a row from " - "input file."); + asprintfN(&error, + "End of file encountered when trying to read a row from " + "input file."); else - pm_error("Error reading a row from input file. " - "fread() fails with errno=%d (%s)", - errno, strerror(errno)); - } - if (tuplerow) { - switch (pamP->bytes_per_sample) { - case 1: parse1BpsRow(pamP, tuplerow, inbuf); break; - case 2: parse2BpsRow(pamP, tuplerow, inbuf); break; - case 3: parse3BpsRow(pamP, tuplerow, inbuf); break; - case 4: parse4BpsRow(pamP, tuplerow, inbuf); break; - default: - pm_error("invalid bytes per sample passed to " - "pnm_formatpamrow(): %u", pamP->bytes_per_sample); + asprintfN(&error, "Error reading a row from input file. " + "fread() fails with errno=%d (%s)", + errno, strerror(errno)); + } else { + error = NULL; /* initial assumption */ + if (tuplerow) { + switch (pamP->bytes_per_sample) { + case 1: parse1BpsRow(pamP, tuplerow, inbuf); break; + case 2: parse2BpsRow(pamP, tuplerow, inbuf); break; + case 3: parse3BpsRow(pamP, tuplerow, inbuf); break; + case 4: parse4BpsRow(pamP, tuplerow, inbuf); break; + default: + asprintfN(&error, "invalid bytes per sample passed to " + "pnm_formatpamrow(): %u", pamP->bytes_per_sample); + } } } pnm_freerowimage(inbuf); + + if (error) { + pm_errormsg("%s", error); + strfree(error); + pm_longjmp(); + } } @@ -263,15 +289,27 @@ pnm_readpam(FILE * const fileP, struct pam * const pamP, int const size) { - tuple **tuplearray; - int row; + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + tuple ** tuplearray; pnm_readpaminit(fileP, pamP, size); tuplearray = pnm_allocpamarray(pamP); - for (row = 0; row < pamP->height; row++) - pnm_readpamrow(pamP, tuplearray[row]); - + if (setjmp(jmpbuf) != 0) { + pnm_freepamarray(tuplearray, pamP); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + unsigned int row; + + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + + for (row = 0; row < pamP->height; ++row) + pnm_readpamrow(pamP, tuplearray[row]); + + pm_setjmpbuf(origJmpbufP); + } return tuplearray; } diff --git a/lib/libpamwrite.c b/lib/libpamwrite.c index 9184a4b5..83f0f41b 100644 --- a/lib/libpamwrite.c +++ b/lib/libpamwrite.c @@ -308,22 +308,33 @@ writePamRawRow(const struct pam * const pamP, Write mutiple ('count') copies of the same row ('tuplerow') to the file, in raw (not plain) format. -----------------------------------------------------------------------------*/ + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; unsigned int rowImageSize; - unsigned char * outbuf; /* malloc'ed */ - unsigned int i; outbuf = pnm_allocrowimage(pamP); pnm_formatpamrow(pamP, tuplerow, outbuf, &rowImageSize); - for (i = 0; i < count; ++i) { - size_t bytesWritten; - - bytesWritten = fwrite(outbuf, 1, rowImageSize, pamP->file); - if (bytesWritten != rowImageSize) - pm_error("fwrite() failed to write an image row to the file. " - "errno=%d (%s)", errno, strerror(errno)); + if (setjmp(jmpbuf) != 0) { + pnm_freerowimage(outbuf); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + unsigned int i; + + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + + for (i = 0; i < count; ++i) { + size_t bytesWritten; + + bytesWritten = fwrite(outbuf, 1, rowImageSize, pamP->file); + if (bytesWritten != rowImageSize) + pm_error("fwrite() failed to write an image row to the file. " + "errno=%d (%s)", errno, strerror(errno)); + } + pm_setjmpbuf(origJmpbufP); } pnm_freerowimage(outbuf); } diff --git a/lib/libpbm3.c b/lib/libpbm3.c index 2e7b922c..a5d5ea62 100644 --- a/lib/libpbm3.c +++ b/lib/libpbm3.c @@ -58,8 +58,8 @@ static void packBitsWithMmxSse(FILE * const fileP, const bit * const bitrow, unsigned char * const packedBits, - int const cols, - int * const nextColP) { + unsigned int const cols, + unsigned int * const nextColP) { /*---------------------------------------------------------------------------- Pack the bits of bitrow[] into bytes at 'packedBits'. Going left to right, stop when there aren't enough bits left to fill a whole byte. Return @@ -136,8 +136,8 @@ static void packBitsGeneric(FILE * const fileP, const bit * const bitrow, unsigned char * const packedBits, - int const cols, - int * const nextColP) { + unsigned int const cols, + unsigned int * const nextColP) { /*---------------------------------------------------------------------------- Pack the bits of bitrow[] into byts at 'packedBits'. Going left to right, stop when there aren't enough bits left to fill a whole byte. Return @@ -166,42 +166,64 @@ packBitsGeneric(FILE * const fileP, +static void +packPartialBytes(const bit * const bitrow, + unsigned int const cols, + unsigned int const nextCol, + unsigned char * const packedBits) { + + /* routine for partial byte at the end of packedBits[] + Prior to addition of the above enhancement, + this method was used for the entire process + */ + + unsigned int col; + int bitshift; + unsigned char item; + + bitshift = 7; /* initial value */ + item = 0; /* initial value */ + for (col = nextCol; col < cols; ++col, --bitshift) + if (bitrow[col] != 0) + item |= 1 << bitshift; + + packedBits[col/8] = item; +} + + + static void writePbmRowRaw(FILE * const fileP, const bit * const bitrow, int const cols) { - int nextCol; + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + unsigned char * packedBits; - unsigned char * const packedBits = pbm_allocrow_packed(cols); + packedBits = pbm_allocrow_packed(cols); - if (HAVE_MMX_SSE) - packBitsWithMmxSse(fileP, bitrow, packedBits, cols, &nextCol); - else - packBitsGeneric(fileP, bitrow, packedBits, cols, &nextCol); + if (setjmp(jmpbuf) != 0) { + pbm_freerow_packed(packedBits); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + unsigned int nextCol; - /* routine for partial byte at the end of packed_bits[] - Prior to addition of the above enhancement, - this method was used for the entire process - */ - - if (cols % 8 > 0) { - int col; - int bitshift; - unsigned char item; - - bitshift = 7; /* initial value */ - item = 0; /* initial value */ - for (col = nextCol; col < cols; ++col, --bitshift ) - if (bitrow[col] !=0) - item |= 1 << bitshift - ; + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + + if (HAVE_MMX_SSE) + packBitsWithMmxSse(fileP, bitrow, packedBits, cols, &nextCol); + else + packBitsGeneric(fileP, bitrow, packedBits, cols, &nextCol); + + if (cols % 8 > 0) + packPartialBytes(bitrow, cols, nextCol, packedBits); - packedBits[col/8] = item; + writePackedRawRow(fileP, packedBits, cols); + + pm_setjmpbuf(origJmpbufP); } - - writePackedRawRow(fileP, packedBits, cols); - pbm_freerow_packed(packedBits); } @@ -244,22 +266,37 @@ pbm_writepbmrow(FILE * const fileP, void pbm_writepbmrow_packed(FILE * const fileP, - const unsigned char * const packed_bits, + const unsigned char * const packedBits, int const cols, int const forceplain) { if (!forceplain && !pm_plain_output) - writePackedRawRow(fileP, packed_bits, cols); + writePackedRawRow(fileP, packedBits, cols); else { - bit *bitrow; - int col; + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + bit * bitrow; bitrow = pbm_allocrow(cols); - for (col = 0; col < cols; ++col) - bitrow[col] = - packed_bits[col/8] & (0x80 >> (col%8)) ? PBM_BLACK : PBM_WHITE; - writePbmRowPlain(fileP, bitrow, cols); + if (setjmp(jmpbuf) != 0) { + pbm_freerow(bitrow); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + unsigned int col; + + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + + for (col = 0; col < cols; ++col) + bitrow[col] = + packedBits[col/8] & (0x80 >> (col%8)) ? + PBM_BLACK : PBM_WHITE; + + writePbmRowPlain(fileP, bitrow, cols); + + pm_setjmpbuf(origJmpbufP); + } pbm_freerow(bitrow); } } diff --git a/lib/libpgm1.c b/lib/libpgm1.c index 75fa365b..5b17910a 100644 --- a/lib/libpgm1.c +++ b/lib/libpgm1.c @@ -28,6 +28,7 @@ #include "libpam.h" #include "fileio.h" #include "mallocvar.h" +#include "nstring.h" gray * @@ -190,105 +191,166 @@ pgm_getrawsample(FILE * const file, -void -pgm_readpgmrow(FILE * const file, +static void +readRpgmRow(FILE * const fileP, gray * const grayrow, int const cols, gray const maxval, int const format) { - switch (format) { - case PGM_FORMAT: { - unsigned int col; - for (col = 0; col < cols; ++col) { - grayrow[col] = pm_getuint(file); - if (grayrow[col] > maxval) - pm_error("value out of bounds (%u > %u)", - grayrow[col], maxval); + unsigned int const bytesPerSample = maxval < 256 ? 1 : 2; + int const bytesPerRow = cols * bytesPerSample; + + unsigned char * rowBuffer; + const char * error; + + MALLOCARRAY(rowBuffer, bytesPerRow); + if (rowBuffer == NULL) + asprintfN(&error, "Unable to allocate memory for row buffer " + "for %u columns", cols); + else { + ssize_t rc; + rc = fread(rowBuffer, 1, bytesPerRow, fileP); + if (rc == 0) + asprintfN(&error, "Error reading row. fread() errno=%d (%s)", + errno, strerror(errno)); + else if (rc != bytesPerRow) + asprintfN(&error, "Error reading row. Short read of %u bytes " + "instead of %u", rc, bytesPerRow); + else { + error = NULL; + if (maxval < 256) { + unsigned int col; + for (col = 0; col < cols; ++col) + grayrow[col] = (gray)rowBuffer[col]; + } else { + unsigned int bufferCursor; + unsigned int col; + + bufferCursor = 0; /* Start at beginning of rowBuffer[] */ + + for (col = 0; col < cols; ++col) { + gray g; + + g = rowBuffer[bufferCursor++] << 8; + g |= rowBuffer[bufferCursor++]; + + grayrow[col] = g; + } + } } + free(rowBuffer); } - break; - - case RPGM_FORMAT: { - unsigned int const bytesPerSample = maxval < 256 ? 1 : 2; - int const bytesPerRow = cols * bytesPerSample; + if (error) { + pm_errormsg("%s", error); + strfree(error); + pm_longjmp(); + } +} - unsigned char * rowBuffer; - ssize_t rc; - MALLOCARRAY(rowBuffer, bytesPerRow); - if (rowBuffer == NULL) - pm_error("Unable to allocate memory for row buffer " - "for %u columns", cols); - rc = fread(rowBuffer, 1, bytesPerRow, file); - if (rc == 0) - pm_error("Error reading row. fread() errno=%d (%s)", - errno, strerror(errno)); - else if (rc != bytesPerRow) - pm_error("Error reading row. Short read of %u bytes " - "instead of %u", rc, bytesPerRow); +static void +readPbmRow(FILE * const fileP, + gray * const grayrow, + int const cols, + gray const maxval, + int const format) { + + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + bit * bitrow; + + bitrow = pbm_allocrow(cols); + if (setjmp(jmpbuf) != 0) { + pbm_freerow(bitrow); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + unsigned int col; + + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + + pbm_readpbmrow(fileP, bitrow, cols, format); + for (col = 0; col < cols; ++col) + grayrow[col] = (bitrow[col] == PBM_WHITE ) ? maxval : 0; - if (maxval < 256) { - unsigned int col; - for (col = 0; col < cols; ++col) - grayrow[col] = (gray)rowBuffer[col]; - } else { - unsigned int bufferCursor; - unsigned int col; + pm_setjmpbuf(origJmpbufP); + } + pbm_freerow(bitrow); +} - bufferCursor = 0; /* Start at beginning of rowBuffer[] */ - for (col = 0; col < cols; ++col) { - gray g; - g = rowBuffer[bufferCursor++] << 8; - g |= rowBuffer[bufferCursor++]; +void +pgm_readpgmrow(FILE * const fileP, + gray * const grayrow, + int const cols, + gray const maxval, + int const format) { - grayrow[col] = g; - } + switch (format) { + case PGM_FORMAT: { + unsigned int col; + for (col = 0; col < cols; ++col) { + grayrow[col] = pm_getuint(fileP); + if (grayrow[col] > maxval) + pm_error("value out of bounds (%u > %u)", + grayrow[col], maxval); } - free(rowBuffer); } + break; + + case RPGM_FORMAT: + readRpgmRow(fileP, grayrow, cols, maxval, format); break; case PBM_FORMAT: - case RPBM_FORMAT: { - bit * bitrow; - int col; - - bitrow = pbm_allocrow(cols); - pbm_readpbmrow( file, bitrow, cols, format ); - for (col = 0; col < cols; ++col) - grayrow[col] = (bitrow[col] == PBM_WHITE ) ? maxval : 0; - pbm_freerow(bitrow); - } + case RPBM_FORMAT: + readPbmRow(fileP, grayrow, cols, maxval, format); break; default: - pm_error( "can't happen" ); + pm_error("can't happen"); } } gray ** -pgm_readpgm(FILE * const file, +pgm_readpgm(FILE * const fileP, int * const colsP, int * const rowsP, gray * const maxvalP) { - gray** grays; - int row; + gray ** grays; + int rows, cols; + gray maxval; int format; + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; - pgm_readpgminit( file, colsP, rowsP, maxvalP, &format ); + pgm_readpgminit(fileP, &cols, &rows, &maxval, &format); - grays = pgm_allocarray( *colsP, *rowsP ); - - for ( row = 0; row < *rowsP; ++row ) - pgm_readpgmrow( file, grays[row], *colsP, *maxvalP, format ); + grays = pgm_allocarray(cols, rows); + + if (setjmp(jmpbuf) != 0) { + pgm_freearray(grays, rows); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + unsigned int row; + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + + for (row = 0; row < rows; ++row) + pgm_readpgmrow(fileP, grays[row], cols, maxval, format); + + pm_setjmpbuf(origJmpbufP); + } + *colsP = cols; + *rowsP = rows; + *maxvalP = maxval; return grays; } diff --git a/lib/libpm.c b/lib/libpm.c index 2e563a09..df59e6c4 100644 --- a/lib/libpm.c +++ b/lib/libpm.c @@ -55,7 +55,7 @@ /* The following are set by pm_init(), then used by subsequent calls to other pm_xxx() functions. */ -static const char* pm_progname; +static const char * pm_progname; static bool pm_showmessages; /* Programs should display informational messages (because the user didn't specify the --quiet option). @@ -76,6 +76,17 @@ static jmp_buf * pm_jmpbufP = NULL; NULL, which is the default value, means when a libnetpbm function encounters an error, it causes the process to exit. */ +static pm_usererrormsgfn * userErrorMsgFn = NULL; + /* A function to call to issue an error message. + + NULL means use the library default: print to Standard Error + */ + +static pm_usermessagefn * userMessageFn = NULL; + /* A function to call to issue an error message. + + NULL means use the library default: print to Standard Error + */ @@ -108,20 +119,24 @@ pm_longjmp(void) { void -pm_usage(const char usage[]) { - pm_error("usage: %s %s", pm_progname, usage); +pm_setusererrormsgfn(pm_usererrormsgfn * fn) { + + userErrorMsgFn = fn; } void -pm_perror(const char reason[] ) { +pm_setusermessagefn(pm_usermessagefn * fn) { - if (reason != NULL && strlen(reason) != 0) - pm_error("%s - errno=%d (%s)", reason, errno, strerror(errno)); - else - pm_error("Something failed with errno=%d (%s)", - errno, strerror(errno)); + userMessageFn = fn; +} + + + +void +pm_usage(const char usage[]) { + pm_error("usage: %s %s", pm_progname, usage); } @@ -134,24 +149,64 @@ pm_message(const char format[], ...) { va_start(args, format); if (pm_showmessages) { - fprintf(stderr, "%s: ", pm_progname); - vfprintf(stderr, format, args); - fputc('\n', stderr); + const char * msg; + vasprintfN(&msg, format, args); + + if (userMessageFn) + userMessageFn(msg); + else + fprintf(stderr, "%s: %s\n", pm_progname, msg); + + strfree(msg); } va_end(args); } +static void +errormsg(const char * const msg) { + + if (userErrorMsgFn) + userErrorMsgFn(msg); + else + fprintf(stderr, "%s: %s\n", pm_progname, msg); +} + + + +void PM_GNU_PRINTF_ATTR(1,2) +pm_errormsg(const char format[], ...) { + + va_list args; + const char * msg; + + va_start(args, format); + + vasprintfN(&msg, format, args); + + errormsg(msg); + + strfree(msg); + + va_end(args); +} + + + void PM_GNU_PRINTF_ATTR(1,2) pm_error(const char format[], ...) { va_list args; + const char * msg; va_start(args, format); - fprintf(stderr, "%s: ", pm_progname); - vfprintf(stderr, format, args); - fputc('\n', stderr); + vasprintfN(&msg, format, args); + + errormsg(msg); + + strfree(msg); + va_end(args); pm_longjmp(); @@ -186,8 +241,64 @@ pm_freerow(char * const itrow) { -char** -pm_allocarray(int const cols, int const rows, int const size ) { +static void +allocarrayNoHeap(unsigned char ** const rowIndex, + unsigned int const cols, + unsigned int const rows, + unsigned int const size, + const char ** const errorP) { + + if (UINT_MAX / cols < size) + asprintfN(errorP, + "Arithmetic overflow multiplying %u by %u to get the " + "size of a row to allocate.", cols, size); + else { + unsigned int rowsDone; + + rowsDone = 0; + *errorP = NULL; + + while (rowsDone < rows && !*errorP) { + unsigned char * const rowSpace = malloc(cols * size); + if (rowSpace == NULL) + asprintfN(errorP, + "Unable to allocate a %u-column by %u byte row", + cols, size); + else + rowIndex[rowsDone++] = rowSpace; + } + if (*errorP) { + unsigned int row; + for (row = 0; row < rowsDone; ++row) + free(rowIndex[row]); + } + } +} + + + +static unsigned char * +allocRowHeap(unsigned int const cols, + unsigned int const rows, + unsigned int const size) { + + unsigned char * retval; + + if (UINT_MAX / cols / rows < size) + /* Too big even to request the memory ! */ + retval = NULL; + else + retval = malloc(rows * cols * size); + + return retval; +} + + + +char ** +pm_allocarray(int const cols, + int const rows, + int const size ) { /*---------------------------------------------------------------------------- Allocate an array of 'rows' rows of 'cols' columns each, with each element 'size' bytes. @@ -206,38 +317,46 @@ pm_allocarray(int const cols, int const rows, int const size ) { We use unfragmented format if possible, but if the allocation of the row heap fails, we fall back to fragmented. -----------------------------------------------------------------------------*/ - char** rowIndex; - char * rowheap; + unsigned char ** rowIndex; + const char * error; MALLOCARRAY(rowIndex, rows + 1); if (rowIndex == NULL) - pm_error("out of memory allocating row index (%u rows) for an array", - rows); - rowheap = malloc(rows * cols * size); - if (rowheap == NULL) { - /* We couldn't get the whole heap in one block, so try fragmented - format. - */ - unsigned int row; - - rowIndex[rows] = NULL; /* Declare it fragmented format */ - - for (row = 0; row < rows; ++row) { - rowIndex[row] = pm_allocrow(cols, size); - if (rowIndex[row] == NULL) - pm_error("out of memory allocating Row %u " - "(%u columns, %u bytes per tuple) " - "of an array", row, cols, size); - } - } else { - /* It's unfragmented format */ - unsigned int row; - rowIndex[rows] = rowheap; /* Declare it unfragmented format */ + asprintfN(&error, + "out of memory allocating row index (%u rows) for an array", + rows); + else { + unsigned char * rowheap; - for (row = 0; row < rows; ++row) - rowIndex[row] = &(rowheap[row * cols * size]); + rowheap = allocRowHeap(cols, rows, size); + + if (rowheap) { + /* It's unfragmented format */ + + rowIndex[rows] = rowheap; /* Declare it unfragmented format */ + + if (rowheap) { + unsigned int row; + + for (row = 0; row < rows; ++row) + rowIndex[row] = &(rowheap[row * cols * size]); + } + error = NULL; + } else { + /* We couldn't get the whole heap in one block, so try fragmented + format. + */ + rowIndex[rows] = NULL; /* Declare it fragmented format */ + + allocarrayNoHeap(rowIndex, cols, rows, size, &error); + } } - return rowIndex; + if (error) { + pm_errormsg("Couldn't allocate %u-row array. %s", rows, error); + strfree(error); + pm_longjmp(); + } + return (char **)rowIndex; } @@ -807,17 +926,65 @@ mkstemp2(char * const filenameBuffer) { +static void +makeTmpfileWithTemplate(const char * const filenameTemplate, + FILE ** const filePP, + const char ** const filenameP, + const char ** const errorP) { + + char * filenameBuffer; /* malloc'ed */ + + filenameBuffer = strdup(filenameTemplate); + + if (filenameBuffer == NULL) + asprintfN(errorP, "Unable to allocate storage for temporary " + "file name"); + else { + int rc; + + rc = mkstemp2(filenameBuffer); + + if (rc < 0) + asprintfN(errorP, + "Unable to create temporary file according to name " + "pattern '%s'. mkstemp() failed with errno %d (%s)", + filenameTemplate, errno, strerror(errno)); + else { + int const fd = rc; + + FILE * fileP; + fileP = fdopen(fd, "w+b"); + + if (fileP == NULL) + asprintfN(errorP, "Unable to create temporary file. " + "fdopen() failed with errno %d (%s)", + errno, strerror(errno)); + else { + *errorP = NULL; + *filePP = fileP; + *filenameP = filenameBuffer; + } + if (*errorP) { + unlink(filenameBuffer); + close(fd); + } + } + if (*errorP) + strfree(filenameBuffer); + } +} + + + void pm_make_tmpfile(FILE ** const filePP, const char ** const filenameP) { - int fd; - FILE * fileP; const char * filenameTemplate; - char * filenameBuffer; /* malloc'ed */ unsigned int fnamelen; const char * tmpdir; const char * dirseparator; + const char * error; fnamelen = strlen (pm_progname) + 10; /* "/" + "_XXXXXX\0" */ @@ -832,27 +999,18 @@ pm_make_tmpfile(FILE ** const filePP, tmpdir, dirseparator, pm_progname, "_XXXXXX"); if (filenameTemplate == NULL) - pm_error("Unable to allocate storage for temporary file name"); - - filenameBuffer = strdup(filenameTemplate); - - fd = mkstemp2(filenameBuffer); - - if (fd < 0) - pm_error("Unable to create temporary file according to name " - "pattern '%s'. mkstemp() failed with " - "errno %d (%s)", filenameTemplate, errno, strerror(errno)); + asprintfN(&error, + "Unable to allocate storage for temporary file name"); else { - fileP = fdopen(fd, "w+b"); + makeTmpfileWithTemplate(filenameTemplate, filePP, filenameP, &error); - if (fileP == NULL) - pm_error("Unable to create temporary file. fdopen() failed " - "with errno %d (%s)", errno, strerror(errno)); + strfree(filenameTemplate); + } + if (error) { + pm_errormsg("%s", error); + strfree(error); + pm_longjmp(); } - strfree(filenameTemplate); - - *filenameP = filenameBuffer; - *filePP = fileP; } @@ -1212,9 +1370,9 @@ pm_readmagicnumber(FILE * const ifP) { Oliver Trepte, oliver@fysik4.kth.se, 930613 */ #define PM_BUF_SIZE 16384 /* First try this size of the buffer, then - double this until we reach PM_MAX_BUF_INC */ + double this until we reach PM_MAX_BUF_INC */ #define PM_MAX_BUF_INC 65536 /* Don't allocate more memory in larger blocks - than this. */ + than this. */ char * pm_read_unknown_size(FILE * const file, diff --git a/lib/libpnm1.c b/lib/libpnm1.c index 82f99b93..536e5dc4 100644 --- a/lib/libpnm1.c +++ b/lib/libpnm1.c @@ -133,6 +133,74 @@ pnm_readpnminit(FILE * const fileP, +static void +readpgmrow(FILE * const fileP, + xel * const xelrow, + int const cols, + xelval const maxval, + int const format) { + + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + gray * grayrow; + + grayrow = pgm_allocrow(cols); + + if (setjmp(jmpbuf) != 0) { + pgm_freerow(grayrow); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + unsigned int col; + + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + + pgm_readpgmrow(fileP, grayrow, cols, (gray) maxval, format); + + for (col = 0; col < cols; ++col) + PNM_ASSIGN1(xelrow[col], grayrow[col]); + + pm_setjmpbuf(origJmpbufP); + } + pgm_freerow(grayrow); +} + + + +static void +readpbmrow(FILE * const fileP, + xel * const xelrow, + int const cols, + xelval const maxval, + int const format) { + + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + bit * bitrow; + + bitrow = pbm_allocrow(cols); + + if (setjmp(jmpbuf) != 0) { + pbm_freerow(bitrow); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + unsigned int col; + + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + + pbm_readpbmrow(fileP, bitrow, cols, format); + + for (col = 0; col < cols; ++col) + PNM_ASSIGN1(xelrow[col], bitrow[col] == PBM_BLACK ? 0 : maxval); + + pm_setjmpbuf(origJmpbufP); + } + pbm_freerow(bitrow); +} + + + void pnm_readpnmrow(FILE * const fileP, xel * const xelrow, @@ -145,28 +213,13 @@ pnm_readpnmrow(FILE * const fileP, ppm_readppmrow(fileP, (pixel*) xelrow, cols, (pixval) maxval, format); break; - case PGM_TYPE: { - gray * grayrow; - unsigned int col; - - grayrow = pgm_allocrow(cols); - pgm_readpgmrow(fileP, grayrow, cols, (gray) maxval, format); - for (col = 0; col < cols; ++col) - PNM_ASSIGN1(xelrow[col], grayrow[col]); - pgm_freerow(grayrow); - } - break; + case PGM_TYPE: + readpgmrow(fileP, xelrow, cols, maxval, format); + break; - case PBM_TYPE: { - bit * bitrow; - unsigned int col; - bitrow = pbm_allocrow(cols); - pbm_readpbmrow(fileP, bitrow, cols, format); - for (col = 0; col < cols; ++col) - PNM_ASSIGN1(xelrow[col], bitrow[col] == PBM_BLACK ? 0: maxval); - pbm_freerow(bitrow); - } - break; + case PBM_TYPE: + readpbmrow(fileP, xelrow, cols, maxval, format); + break; default: pm_error("INTERNAL ERROR. Impossible format."); @@ -182,15 +235,35 @@ pnm_readpnm(FILE * const fileP, xelval * const maxvalP, int * const formatP) { + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + int cols, rows; + xelval maxval; + int format; xel ** xels; - int row; - pnm_readpnminit(fileP, colsP, rowsP, maxvalP, formatP); + pnm_readpnminit(fileP, &cols, &rows, &maxval, &format); + + xels = pnm_allocarray(cols, rows); - xels = pnm_allocarray(*colsP, *rowsP); + if (setjmp(jmpbuf) != 0) { + pnm_freearray(xels, rows); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + unsigned int row; - for (row = 0; row < *rowsP; ++row) - pnm_readpnmrow(fileP, xels[row], *colsP, *maxvalP, *formatP); + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + + for (row = 0; row < rows; ++row) + pnm_readpnmrow(fileP, xels[row], cols, maxval, format); + + pm_setjmpbuf(origJmpbufP); + } + *colsP = cols; + *rowsP = rows; + *maxvalP = maxval; + *formatP = format; return xels; } diff --git a/lib/libpnm2.c b/lib/libpnm2.c index aae78d52..7e4f7e2a 100644 --- a/lib/libpnm2.c +++ b/lib/libpnm2.c @@ -55,6 +55,74 @@ pnm_writepnminit(FILE * const fileP, +static void +writepgmrow(FILE * const fileP, + xel * const xelrow, + unsigned int const cols, + xelval const maxval, + int const format, + bool const plainFormat) { + + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + gray * grayrow; + + grayrow = pgm_allocrow(cols); + + if (setjmp(jmpbuf) != 0) { + pgm_freerow(grayrow); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + unsigned int col; + + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + + for (col = 0; col < cols; ++col) + grayrow[col] = PNM_GET1(xelrow[col]); + + pgm_writepgmrow(fileP, grayrow, cols, (gray) maxval, plainFormat); + + pm_setjmpbuf(origJmpbufP); + } + pgm_freerow(grayrow); +} + + + +static void +writepbmrow(FILE * const fileP, + xel * const xelrow, + unsigned int const cols, + bool const plainFormat) { + + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + bit * bitrow; + + bitrow = pbm_allocrow(cols); + + if (setjmp(jmpbuf) != 0) { + pbm_freerow(bitrow); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + unsigned int col; + + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + + for (col = 0; col < cols; ++col) + bitrow[col] = PNM_GET1(xelrow[col]) == 0 ? PBM_BLACK : PBM_WHITE; + + pbm_writepbmrow(fileP, bitrow, cols, plainFormat); + + pm_setjmpbuf(origJmpbufP); + } + pbm_freerow(bitrow); +} + + + void pnm_writepnmrow(FILE * const fileP, xel * const xelrow, @@ -71,35 +139,13 @@ pnm_writepnmrow(FILE * const fileP, plainFormat); break; - case PGM_TYPE: { - gray* grayrow; - unsigned int col; - - grayrow = pgm_allocrow(cols); - - for (col = 0; col < cols; ++col) - grayrow[col] = PNM_GET1(xelrow[col]); - - pgm_writepgmrow(fileP, grayrow, cols, (gray) maxval, plainFormat); - - pgm_freerow( grayrow ); - } - break; - - case PBM_TYPE: { - bit* bitrow; - unsigned int col; - - bitrow = pbm_allocrow(cols); - - for (col = 0; col < cols; ++col) - bitrow[col] = PNM_GET1(xelrow[col]) == 0 ? PBM_BLACK : PBM_WHITE; - - pbm_writepbmrow(fileP, bitrow, cols, plainFormat); + case PGM_TYPE: + writepgmrow(fileP, xelrow, cols, maxval, format, plainFormat); + break; - pbm_freerow(bitrow); - } - break; + case PBM_TYPE: + writepbmrow(fileP, xelrow, cols, plainFormat); + break; default: pm_error("invalid format argument received by pnm_writepnmrow(): %d" diff --git a/lib/libppm1.c b/lib/libppm1.c index 57a1db7d..a7ea78cf 100644 --- a/lib/libppm1.c +++ b/lib/libppm1.c @@ -19,6 +19,7 @@ #include #include #include + #include "ppm.h" #include "libppm.h" #include "pgm.h" @@ -29,6 +30,7 @@ #include "libpam.h" #include "fileio.h" #include "mallocvar.h" +#include "nstring.h" pixel * @@ -150,124 +152,211 @@ ppm_readppminit(FILE * const fileP, -void -ppm_readppmrow(FILE* const fileP, - pixel* const pixelrow, - int const cols, - pixval const maxval, - int const format) { - - switch (format) { - case PPM_FORMAT: { - unsigned int col; - for (col = 0; col < cols; ++col) { - pixval const r = pm_getuint(fileP); - pixval const g = pm_getuint(fileP); - pixval const b = pm_getuint(fileP); - - if (r > maxval) - pm_error("Red sample value %u is greater than maxval (%u)", - r, maxval); - if (g > maxval) - pm_error("Green sample value %u is greater than maxval (%u)", - g, maxval); - if (b > maxval) - pm_error("Blue sample value %u is greater than maxval (%u)", - b, maxval); - - PPM_ASSIGN(pixelrow[col], r, g, b); - } +static void +readppm(FILE * const fileP, + pixel * const pixelrow, + unsigned int const cols, + pixval const maxval, + int const format) { + + unsigned int col; + + for (col = 0; col < cols; ++col) { + pixval const r = pm_getuint(fileP); + pixval const g = pm_getuint(fileP); + pixval const b = pm_getuint(fileP); + + if (r > maxval) + pm_error("Red sample value %u is greater than maxval (%u)", + r, maxval); + if (g > maxval) + pm_error("Green sample value %u is greater than maxval (%u)", + g, maxval); + if (b > maxval) + pm_error("Blue sample value %u is greater than maxval (%u)", + b, maxval); + + PPM_ASSIGN(pixelrow[col], r, g, b); } - break; +} - /* For PAM, we require a depth of 3, which means the raster format - is identical to Raw PPM! How convenient. - */ - case PAM_FORMAT: - case RPPM_FORMAT: { - unsigned int const bytesPerSample = maxval < 256 ? 1 : 2; - unsigned int const bytesPerRow = cols * 3 * bytesPerSample; - - unsigned int bufferCursor; - unsigned char * rowBuffer; - ssize_t rc; - MALLOCARRAY(rowBuffer, bytesPerRow); + +static void +readrppm(FILE * const fileP, + pixel * const pixelrow, + unsigned int const cols, + pixval const maxval, + int const format) { + + unsigned int const bytesPerSample = maxval < 256 ? 1 : 2; + unsigned int const bytesPerRow = cols * 3 * bytesPerSample; - if (rowBuffer == NULL) - pm_error("Unable to allocate memory for row buffer " - "for %u columns", cols); + unsigned char * rowBuffer; + const char * error; + + MALLOCARRAY(rowBuffer, bytesPerRow); + + if (rowBuffer == NULL) + asprintfN(&error, "Unable to allocate memory for row buffer " + "for %u columns", cols); + else { + ssize_t rc; rc = fread(rowBuffer, 1, bytesPerRow, fileP); if (feof(fileP)) - pm_error("Unexpected EOF reading row of PPM image."); + asprintfN(&error, "Unexpected EOF reading row of PPM image."); else if (ferror(fileP)) - pm_error("Error reading row. fread() errno=%d (%s)", - errno, strerror(errno)); + asprintfN(&error, "Error reading row. fread() errno=%d (%s)", + errno, strerror(errno)); else if (rc != bytesPerRow) - pm_error("Error reading row. Short read of %u bytes " - "instead of %u", rc, bytesPerRow); - - bufferCursor = 0; /* start at beginning of rowBuffer[] */ + asprintfN(&error, "Error reading row. Short read of %u bytes " + "instead of %u", rc, bytesPerRow); + else { + unsigned int bufferCursor; + + error = NULL; + + bufferCursor = 0; /* start at beginning of rowBuffer[] */ - if (bytesPerSample == 1) { - unsigned int col; - for (col = 0; col < cols; ++col) { - pixval const r = rowBuffer[bufferCursor++]; - pixval const g = rowBuffer[bufferCursor++]; - pixval const b = rowBuffer[bufferCursor++]; - PPM_ASSIGN(pixelrow[col], r, g, b); - } - } else { - /* two byte samples */ - unsigned int col; - for (col = 0; col < cols; ++col) { - pixval r, g, b; - - r = rowBuffer[bufferCursor++] << 8; - r |= rowBuffer[bufferCursor++]; - - g = rowBuffer[bufferCursor++] << 8; - g |= rowBuffer[bufferCursor++]; - - b = rowBuffer[bufferCursor++] << 8; - b |= rowBuffer[bufferCursor++]; - - PPM_ASSIGN(pixelrow[col], r, g, b); + if (bytesPerSample == 1) { + unsigned int col; + for (col = 0; col < cols; ++col) { + pixval const r = rowBuffer[bufferCursor++]; + pixval const g = rowBuffer[bufferCursor++]; + pixval const b = rowBuffer[bufferCursor++]; + PPM_ASSIGN(pixelrow[col], r, g, b); + } + } else { + /* two byte samples */ + unsigned int col; + for (col = 0; col < cols; ++col) { + pixval r, g, b; + + r = rowBuffer[bufferCursor++] << 8; + r |= rowBuffer[bufferCursor++]; + + g = rowBuffer[bufferCursor++] << 8; + g |= rowBuffer[bufferCursor++]; + + b = rowBuffer[bufferCursor++] << 8; + b |= rowBuffer[bufferCursor++]; + + PPM_ASSIGN(pixelrow[col], r, g, b); + } } } free(rowBuffer); } - break; + if (error) { + pm_errormsg("%s", error); + strfree(error); + pm_longjmp(); + } +} - case PGM_FORMAT: - case RPGM_FORMAT: { - gray * const grayrow = pgm_allocrow(cols); + + +static void +readpgm(FILE * const fileP, + pixel * const pixelrow, + unsigned int const cols, + pixval const maxval, + int const format) { + + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + gray * grayrow; + + grayrow = pgm_allocrow(cols); + + if (setjmp(jmpbuf) != 0) { + pgm_freerow(grayrow); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { unsigned int col; + + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); pgm_readpgmrow(fileP, grayrow, cols, maxval, format); + for (col = 0; col < cols; ++col) { pixval const g = grayrow[col]; PPM_ASSIGN(pixelrow[col], g, g, g); } - pgm_freerow(grayrow); + pm_setjmpbuf(origJmpbufP); } - break; + pgm_freerow(grayrow); +} - case PBM_FORMAT: - case RPBM_FORMAT: { - bit * const bitrow = pbm_allocrow(cols); + + +static void +readpbm(FILE * const fileP, + pixel * const pixelrow, + unsigned int const cols, + pixval const maxval, + int const format) { + + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + bit * bitrow; + + bitrow = pbm_allocrow(cols); + + if (setjmp(jmpbuf) != 0) { + pbm_freerow(bitrow); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { unsigned int col; + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + pbm_readpbmrow(fileP, bitrow, cols, format); + for (col = 0; col < cols; ++col) { pixval const g = (bitrow[col] == PBM_WHITE) ? maxval : 0; PPM_ASSIGN(pixelrow[col], g, g, g); } - pbm_freerow(bitrow); + pm_setjmpbuf(origJmpbufP); } - break; + pbm_freerow(bitrow); +} + + + +void +ppm_readppmrow(FILE * const fileP, + pixel * const pixelrow, + int const cols, + pixval const maxval, + int const format) { + + switch (format) { + case PPM_FORMAT: + readppm(fileP, pixelrow, cols, maxval, format); + break; + + /* For PAM, we require a depth of 3, which means the raster format + is identical to Raw PPM! How convenient. + */ + case PAM_FORMAT: + case RPPM_FORMAT: + readrppm(fileP, pixelrow, cols, maxval, format); + break; + + case PGM_FORMAT: + case RPGM_FORMAT: + readpgm(fileP, pixelrow, cols, maxval, format); + break; + + case PBM_FORMAT: + case RPBM_FORMAT: + readpbm(fileP, pixelrow, cols, maxval, format); + break; default: pm_error("Invalid format code"); @@ -281,17 +370,36 @@ ppm_readppm(FILE * const fileP, int * const colsP, int * const rowsP, pixval * const maxvalP) { - pixel** pixels; - int row; + + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + pixel ** pixels; + int cols, rows; + pixval maxval; int format; - ppm_readppminit(fileP, colsP, rowsP, maxvalP, &format); + ppm_readppminit(fileP, &cols, &rows, &maxval, &format); - pixels = ppm_allocarray(*colsP, *rowsP); + pixels = ppm_allocarray(cols, rows); - for (row = 0; row < *rowsP; ++row) - ppm_readppmrow(fileP, pixels[row], *colsP, *maxvalP, format); + if (setjmp(jmpbuf) != 0) { + ppm_freearray(pixels, rows); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + unsigned int row; + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + + for (row = 0; row < rows; ++row) + ppm_readppmrow(fileP, pixels[row], cols, maxval, format); + + *colsP = cols; + *rowsP = rows; + *maxvalP = maxval; + + pm_setjmpbuf(origJmpbufP); + } return pixels; } diff --git a/lib/libppmcmap.c b/lib/libppmcmap.c index a9efccbc..c1243cb6 100644 --- a/lib/libppmcmap.c +++ b/lib/libppmcmap.c @@ -12,9 +12,11 @@ ** implied warranty. */ -#include "ppm.h" -#include "libppm.h" +#include "pm_c_util.h" +#include "nstring.h" #include "mallocvar.h" +#include "libppm.h" +#include "ppm.h" #include "ppmcmap.h" #define HASH_SIZE 20023 @@ -110,94 +112,124 @@ ppm_addtocolorhist( colorhist_vector chv, -colorhash_table -ppm_alloccolorhash(void) { +static colorhash_table +alloccolorhash(void) { colorhash_table cht; int i; MALLOCARRAY(cht, HASH_SIZE); + if (cht) { + for (i = 0; i < HASH_SIZE; ++i) + cht[i] = NULL; + } + return cht; +} + + + +colorhash_table +ppm_alloccolorhash(void) { + colorhash_table cht; + + cht = alloccolorhash(); + if (cht == NULL) pm_error( "out of memory allocating hash table" ); - for (i = 0; i < HASH_SIZE; ++i) - cht[i] = NULL; - return cht; } -static colorhash_table -computecolorhash(pixel ** const pixels, - const int cols, const int rows, - const int maxcolors, int * const colorsP, - FILE * const ifp, pixval const maxval, int const format) { -/*---------------------------------------------------------------------------- - Compute a color histogram from an image. The input is one of two types: +static void +readppmrow(FILE * const fileP, + pixel * const pixelrow, + int const cols, + pixval const maxval, + int const format, + const char ** const errorP) { - 1) a two-dimensional array of pixels 'pixels'; In this case, 'pixels' - is non-NULL and 'ifp' is NULL. + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + + if (setjmp(jmpbuf) != 0) { + pm_setjmpbuf(origJmpbufP); + asprintfN(errorP, "Failed to read row of image."); + } else { + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); - 2) an open file, positioned to the image data. In this case, - 'pixels' is NULL and 'ifp' is non-NULL. ifp is the stream - descriptor for the input file, and 'maxval' and 'format' are - parameters of the image data in it. - - We return with the file still open and its position undefined. + ppm_readppmrow(fileP, pixelrow, cols, maxval, format); - In either case, the image is 'cols' by 'rows'. + *errorP = NULL; /* Would have longjmped if anything went wrong */ + + pm_setjmpbuf(origJmpbufP); + } +} - Return the number of colors found as *colorsP. - However, if 'maxcolors' is nonzero and the number of colors is - greater than 'maxcolors', return a null return value and *colorsP - undefined. + +static void +buildHashTable(FILE * const ifP, + pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + pixval const maxval, + int const format, + unsigned int const maxcolors, + colorhash_table const cht, + pixel * const rowbuffer, + int * const nColorsP, + bool * const tooManyColorsP, + const char ** const errorP) { +/*---------------------------------------------------------------------------- + Look at all the colors in the file *ifP or array pixels[][] and add + them to the hash table 'cht'. + + Even if we fail, we may add some colors to 'cht'. + + As soon as we've seen more that 'maxcolors' colors, we quit. In that + case, only, we return *tooManyColorsP == true. That is not a failure. + 'maxcolors' == 0 means infinity. -----------------------------------------------------------------------------*/ - colorhash_table cht; - int row; - pixel * rowbuffer; /* malloc'ed */ - /* Buffer for a row read from the input file; undefined (but still - allocated) if input is not from a file. - */ - - cht = ppm_alloccolorhash( ); - *colorsP = 0; /* initial value */ + unsigned int row; + unsigned int nColors; - rowbuffer = ppm_allocrow(cols); + nColors = 0; /* initial value */ + *tooManyColorsP = FALSE; /* initial value */ + *errorP = NULL; /* initial value */ /* Go through the entire image, building a hash table of colors. */ - for (row = 0; row < rows; ++row) { - int col; + for (row = 0; row < rows && !*tooManyColorsP && !*errorP; ++row) { + unsigned int col; pixel * pixelrow; /* The row of pixels we are processing */ - if (ifp) { - ppm_readppmrow(ifp, rowbuffer, cols, maxval, format); + if (ifP) { + readppmrow(ifP, rowbuffer, cols, maxval, format, errorP); pixelrow = rowbuffer; } else pixelrow = pixels[row]; - for (col = 0; col < cols; ++col) { + for (col = 0; col < cols && !*tooManyColorsP && !*errorP; ++col) { const pixel apixel = pixelrow[col]; const int hash = ppm_hashpixel(apixel); colorhist_list chl; for (chl = cht[hash]; - chl != (colorhist_list) 0 && - !PPM_EQUAL(chl->ch.color, apixel); + chl && !PPM_EQUAL(chl->ch.color, apixel); chl = chl->next); if (chl) - chl->ch.value++; + ++chl->ch.value; else { /* It's not in the hash yet, so add it (if allowed) */ - ++(*colorsP); - if (maxcolors > 0 && *colorsP > maxcolors) { - ppm_freecolorhash(cht); - return NULL; - } else { + ++nColors; + if (maxcolors > 0 && nColors > maxcolors) + *tooManyColorsP = TRUE; + else { MALLOCVAR(chl); if (chl == NULL) - pm_error("out of memory computing hash table"); + asprintfN(errorP, + "out of memory computing hash table"); chl->ch.color = apixel; chl->ch.value = 1; chl->next = cht[hash]; @@ -206,31 +238,124 @@ computecolorhash(pixel ** const pixels, } } } - ppm_freerow(rowbuffer); - return cht; + *nColorsP = nColors; +} + + + +static void +computecolorhash(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + unsigned int const maxcolors, + int * const nColorsP, + FILE * const ifP, + pixval const maxval, + int const format, + colorhash_table * const chtP, + const char ** const errorP) { +/*---------------------------------------------------------------------------- + Compute a color histogram from an image. The input is one of two types: + + 1) a two-dimensional array of pixels 'pixels'; In this case, 'pixels' + is non-NULL and 'ifP' is NULL. + + 2) an open file, positioned to the image data. In this case, + 'pixels' is NULL and 'ifP' is non-NULL. ifP is the stream + descriptor for the input file, and 'maxval' and 'format' are + parameters of the image data in it. + + We return with the file still open and its position undefined. + + In either case, the image is 'cols' by 'rows'. + + Return the number of colors found as *colorsP. + + However, if 'maxcolors' is nonzero and the number of colors is + greater than 'maxcolors', return a null return value and *colorsP + undefined. +-----------------------------------------------------------------------------*/ + pixel * rowbuffer; /* malloc'ed */ + /* Buffer for a row read from the input file; undefined (but still + allocated) if input is not from a file. + */ + + MALLOCARRAY(rowbuffer, cols); + + if (rowbuffer == NULL) + asprintfN(errorP, "Unable to allocate %u-column row buffer.", cols); + else { + colorhash_table cht; + bool tooManyColors; + + cht = alloccolorhash(); + + if (cht == NULL) + asprintfN(errorP, "Unable to allocate color hash."); + else { + buildHashTable(ifP, pixels, cols, rows, maxval, format, maxcolors, + cht, rowbuffer, + nColorsP, &tooManyColors, errorP); + + if (tooManyColors) { + ppm_freecolorhash(cht); + *chtP = NULL; + } else + *chtP = cht; + + if (*errorP) + ppm_freecolorhash(cht); + } + free(rowbuffer); + } } colorhash_table ppm_computecolorhash(pixel ** const pixels, - const int cols, const int rows, - const int maxcolors, int * const colorsP) { + int const cols, + int const rows, + int const maxcolors, + int * const colorsP) { + + colorhash_table cht; + const char * error; + + computecolorhash(pixels, cols, rows, maxcolors, colorsP, + NULL, 0, 0, &cht, &error); - return computecolorhash(pixels, cols, rows, maxcolors, colorsP, - NULL, 0, 0); + if (error) { + pm_errormsg("%s", error); + strfree(error); + pm_longjmp(); + } + return cht; } colorhash_table -ppm_computecolorhash2(FILE * const ifp, - const int cols, const int rows, - const pixval maxval, const int format, - const int maxcolors, int * const colorsP ) { +ppm_computecolorhash2(FILE * const ifP, + int const cols, + int const rows, + pixval const maxval, + int const format, + int const maxcolors, + int * const colorsP ) { + + colorhash_table cht; + const char * error; - return computecolorhash(NULL, cols, rows, maxcolors, colorsP, - ifp, maxval, format); + computecolorhash(NULL, cols, rows, maxcolors, colorsP, + ifP, maxval, format, &cht, &error); + + if (error) { + pm_errormsg("%s", error); + strfree(error); + pm_longjmp(); + } + return cht; } @@ -353,30 +478,50 @@ ppm_colorhashtocolorhist(colorhash_table const cht, int const maxcolors) { colorhash_table ppm_colorhisttocolorhash(colorhist_vector const chv, int const colors) { + + colorhash_table retval; colorhash_table cht; - int i, hash; - pixel color; - colorhist_list chl; + const char * error; - cht = ppm_alloccolorhash( ); /* Initializes to NULLs */ - - for (i = 0; i < colors; ++i) { - color = chv[i].color; - hash = ppm_hashpixel(color); - for (chl = cht[hash]; chl != (colorhist_list) 0; chl = chl->next) - if (PPM_EQUAL(chl->ch.color, color)) - pm_error( - "same color found twice - %d %d %d", PPM_GETR(color), - PPM_GETG(color), PPM_GETB(color) ); - MALLOCVAR(chl); - if (chl == NULL) - pm_error("out of memory"); - chl->ch.color = color; - chl->ch.value = i; - chl->next = cht[hash]; - cht[hash] = chl; + cht = alloccolorhash( ); /* Initializes to NULLs */ + if (cht == NULL) + asprintfN(&error, "Unable to allocate color hash"); + else { + unsigned int i; + + for (i = 0, error = NULL; i < colors && !error; ++i) { + pixel const color = chv[i].color; + int const hash = ppm_hashpixel(color); + + colorhist_list chl; + + for (chl = cht[hash]; chl && !error; chl = chl->next) + if (PPM_EQUAL(chl->ch.color, color)) + asprintfN(&error, "same color found twice: (%u %u %u)", + PPM_GETR(color), + PPM_GETG(color), + PPM_GETB(color)); + MALLOCVAR(chl); + if (chl == NULL) + asprintfN(&error, "out of memory"); + else { + chl->ch.color = color; + chl->ch.value = i; + chl->next = cht[hash]; + cht[hash] = chl; + } + } + if (error) + ppm_freecolorhash(cht); } - return cht; + if (error) { + pm_errormsg("%s", error); + strfree(error); + pm_longjmp(); + } else + retval = cht; + + return retval; } diff --git a/lib/libppmcolor.c b/lib/libppmcolor.c index 7cfacd29..a200ab2b 100644 --- a/lib/libppmcolor.c +++ b/lib/libppmcolor.c @@ -19,6 +19,7 @@ #include "pm_c_util.h" #include "mallocvar.h" +#include "nstring.h" #include "ppm.h" #include "colorname.h" @@ -247,22 +248,6 @@ parseNewDecX11(char const colorname[], -static bool -isHexString(char const string[], - int const hexit[]) { - - bool retval; - const char * p; - - for (p = &string[0], retval = true; *p && retval == true; ++p) { - if (hexit[(unsigned int)*p] == -1) - retval = false; - } - return retval; -} - - - static void parseOldX11(char const colorname[], pixval const maxval, @@ -278,7 +263,7 @@ parseOldX11(char const colorname[], computeHexTable(hexit); - if (!isHexString(&colorname[1], hexit)) + if (!strishex(&colorname[1])) pm_error("Non-hexadecimal characters in #-type color specification"); switch (strlen(colorname) - 1 /* (Number of hex digits) */) { @@ -471,11 +456,12 @@ processColorfileEntry(struct colorfile_entry const ce, colorhash_table const cht, const char ** const colornames, pixel * const colors, - unsigned int * const colornameIndexP) { + unsigned int * const colornameIndexP, + const char ** const errorP) { if (*colornameIndexP >= MAXCOLORNAMES) - pm_error("Too many colors in colorname dictionary. " - "Max allowed is %u", MAXCOLORNAMES); + asprintfN(errorP, "Too many colors in colorname dictionary. " + "Max allowed is %u", MAXCOLORNAMES); else { pixel color; @@ -487,13 +473,17 @@ processColorfileEntry(struct colorfile_entry const ce, file gives for each color, so we just ignore the current entry. */ + *errorP = NULL; } else { ppm_addtocolorhash(cht, &color, *colornameIndexP); colornames[*colornameIndexP] = strdup(ce.colorname); colors[*colornameIndexP] = color; if (colornames[*colornameIndexP] == NULL) - pm_error("Unable to allocate space for color name"); - ++(*colornameIndexP); + asprintfN(errorP, "Unable to allocate space for color name"); + else { + *errorP = NULL; + ++(*colornameIndexP); + } } } } @@ -501,39 +491,173 @@ processColorfileEntry(struct colorfile_entry const ce, static void -readcolordict(const char * const fileName, +openColornameFile(const char * const fileName, + bool const mustOpen, + FILE ** const filePP, + const char ** const errorP) { + + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + + if (setjmp(jmpbuf) != 0) { + asprintfN(errorP, "Failed to open color name file"); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + *filePP = pm_openColornameFile(fileName, mustOpen); + + *errorP = NULL; /* Would have longjmped if there were a problem */ + + pm_setjmpbuf(origJmpbufP); + } +} + + + +static void +readOpenColorFile(FILE * const colorFileP, + unsigned int * const nColorsP, + const char ** const colornames, + pixel * const colors, + colorhash_table const cht, + const char ** const errorP) { +/*---------------------------------------------------------------------------- + Read the color dictionary file *colorFileP and add the colors in it + to colornames[], colors[], and 'cht'. + + We may add colors to 'cht' even if we fail. +-----------------------------------------------------------------------------*/ + unsigned int nColorsDone; + bool done; + + nColorsDone = 0; + done = FALSE; + *errorP = NULL; + + while (!done && !*errorP) { + struct colorfile_entry const ce = pm_colorget(colorFileP); + + if (!ce.colorname) + done = TRUE; + else + processColorfileEntry(ce, cht, colornames, colors, + &nColorsDone, errorP); + } + if (!*errorP) { + *nColorsP = nColorsDone; + + while (nColorsDone < MAXCOLORNAMES) + colornames[nColorsDone++] = NULL; + } + + if (*errorP) { + unsigned int colorIndex; + + for (colorIndex = 0; colorIndex < nColorsDone; ++colorIndex) + strfree(colornames[colorIndex]); + } +} + + + +static colorhash_table +allocColorHash(void) { + + colorhash_table cht; + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + + if (setjmp(jmpbuf) != 0) + cht = NULL; + else { + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + cht = ppm_alloccolorhash(); + } + pm_setjmpbuf(origJmpbufP); + + return cht; +} + + + +static void +readColorFile(const char * const fileName, bool const mustOpen, unsigned int * const nColorsP, const char ** const colornames, - pixel * const colors, - colorhash_table const cht) { + pixel * const colors, + colorhash_table const cht, + const char ** const errorP) { - FILE * colorFile; + FILE * colorFileP; - colorFile = pm_openColornameFile(fileName, mustOpen); + openColornameFile(fileName, mustOpen, &colorFileP, errorP); + if (!*errorP) { + if (colorFileP == NULL) { + /* Couldn't open it, but Caller says treat same as + empty file + */ + *nColorsP = 0; + *errorP = NULL; + } else { + readOpenColorFile(colorFileP, nColorsP, colornames, colors, cht, + errorP); + + fclose(colorFileP); + } + } +} - if (colorFile != NULL) { - unsigned int colornameIndex; - bool done; + - colornameIndex = 0; /* initial value */ - done = FALSE; - while (!done) { - struct colorfile_entry const ce = pm_colorget(colorFile); +static void +readcolordict(const char * const fileName, + bool const mustOpen, + unsigned int * const nColorsP, + const char *** const colornamesP, + pixel ** const colorsP, + colorhash_table * const chtP, + const char ** const errorP) { - if (!ce.colorname) - done = TRUE; - else - processColorfileEntry(ce, cht, colornames, colors, - &colornameIndex); - } + const char ** colornames; - *nColorsP = colornameIndex; + MALLOCARRAY(colornames, MAXCOLORNAMES); - while (colornameIndex < MAXCOLORNAMES) - colornames[colornameIndex++] = NULL; + if (colornames == NULL) + asprintfN(errorP, "Unable to allocate space for colorname table."); + else { + pixel * colors; - fclose(colorFile); + MALLOCARRAY(colors, MAXCOLORNAMES); + + if (colors == NULL) + asprintfN(errorP, "Unable to allocate space for color table."); + else { + colorhash_table cht; + + cht = allocColorHash(); + + if (cht == NULL) + asprintfN(errorP, "Unable to allocate space for color hash"); + else { + readColorFile(fileName, mustOpen, + nColorsP, colornames, colors, cht, + errorP); + + if (*errorP) + ppm_freecolorhash(cht); + else + *chtP = cht; + } + if (*errorP) + free(colors); + else + *colorsP = colors; + } + if (*errorP) + free(colornames); + else + *colornamesP = colornames; } } @@ -551,32 +675,31 @@ ppm_readcolordict(const char * const fileName, const char ** colornames; pixel * colors; unsigned int nColors; + const char * error; - cht = ppm_alloccolorhash(); - - MALLOCARRAY(colornames, MAXCOLORNAMES); - - colors = ppm_allocrow(MAXCOLORNAMES); + readcolordict(fileName, mustOpen, &nColors, &colornames, &colors, &cht, + &error); - if (colornames == NULL) - pm_error("Unable to allocate space for colorname table."); - - readcolordict(fileName, mustOpen, &nColors, colornames, colors, cht); - - if (chtP) - *chtP = cht; - else + if (error) { + pm_errormsg("%s", error); + strfree(error); ppm_freecolorhash(cht); - if (colornamesP) - *colornamesP = colornames; - else - ppm_freecolornames(colornames); - if (colorsP) - *colorsP = colors; - else - ppm_freerow(colors); - if (nColorsP) - *nColorsP = nColors; + } else { + if (chtP) + *chtP = cht; + else + ppm_freecolorhash(cht); + if (colornamesP) + *colornamesP = colornames; + else + ppm_freecolornames(colornames); + if (colorsP) + *colorsP = colors; + else + ppm_freerow(colors); + if (nColorsP) + *nColorsP = nColors; + } } diff --git a/lib/libppmfuzzy.c b/lib/libppmfuzzy.c index 6127d5d5..e149b42a 100644 --- a/lib/libppmfuzzy.c +++ b/lib/libppmfuzzy.c @@ -84,7 +84,7 @@ memberTrapez(fzLog const x1, static fzLog hueIsAround000(double const hue) { - return memberZ(10, 30, hue); + return memberZ(10, 20, hue); } @@ -92,7 +92,7 @@ hueIsAround000(double const hue) { static fzLog hueIsAround015(double const hue) { - return memberZ(30, 40, hue); + return memberZ(20, 40, hue); } @@ -100,7 +100,7 @@ hueIsAround015(double const hue) { static fzLog hueIsAround030(double const hue) { - return memberTrapez(10, 30, 40, 60, hue); + return memberTrapez(10, 20, 40, 60, hue); } @@ -108,7 +108,7 @@ hueIsAround030(double const hue) { static fzLog hueIsAround060(double const hue) { - return memberTrapez(40, 60, 60, 80, hue); + return memberTrapez(40, 50, 60, 70, hue); } @@ -116,7 +116,7 @@ hueIsAround060(double const hue) { static fzLog hueIsAround120(double const hue) { - return memberTrapez(60, 80, 150, 180, hue); + return memberTrapez(60, 70, 150, 180, hue); } @@ -160,14 +160,14 @@ hueIsAround360(double const hue) { static fzLog satIsVeryLow(double const sat) { - return memberZ(0.02, 0.1, sat); + return memberZ(0.03, 0.08, sat); } static fzLog satIsLow(double const sat) { - return memberTrapez(0.02, 0.1, 0.2, 0.3, sat); + return memberTrapez(0.03, 0.08, 0.17, 0.2, sat); } @@ -175,7 +175,7 @@ satIsLow(double const sat) { static fzLog satIsMedium(double const sat) { - return memberTrapez(0.2, 0.3, 0.6, 0.7, sat); + return memberTrapez(0.17, 0.2, 0.6, 0.8, sat); } @@ -183,7 +183,7 @@ satIsMedium(double const sat) { static fzLog satIsHigh(double const sat) { - return memberS(0.6, 0.7, sat); + return memberS(0.6, 0.8, sat); } @@ -195,7 +195,7 @@ satIsHigh(double const sat) { static fzLog valIsVeryLow(double const val) { - return memberZ(0.1, 0.2, val); + return memberZ(0.05, 0.2, val); } @@ -203,7 +203,7 @@ valIsVeryLow(double const val) { static fzLog valIsLow(double const val) { - return memberTrapez(0.1, 0.2, 0.3, 0.6, val); + return memberTrapez(0.05, 0.2, 0.25, 0.3, val); } @@ -211,7 +211,7 @@ valIsLow(double const val) { static fzLog valIsMedium(double const val) { - return memberTrapez(0.3, 0.6, 0.7, 0.8, val); + return memberTrapez(0.25, 0.3, 0.6, 0.7, val); } @@ -219,7 +219,15 @@ valIsMedium(double const val) { static fzLog valIsHigh(double const val) { - return memberS(0.7, 0.8, val); + return memberTrapez(0.6, 0.7, 0.95, 0.97, val); +} + + + +static fzLog +valIsVeryHigh(double const val) { + + return memberS(0.95, 0.97, val); } @@ -269,10 +277,11 @@ matchBk(pixel const color, fzLog const satMedium = satIsMedium(hsv.s); fzLog const satHigh = satIsHigh(hsv.s); - fzLog const valVeryLow = valIsVeryLow(hsv.v); - fzLog const valLow = valIsLow(hsv.v); - fzLog const valMedium = valIsMedium(hsv.v); - fzLog const valHigh = valIsHigh(hsv.v); + fzLog const valVeryLow = valIsVeryLow(hsv.v); + fzLog const valLow = valIsLow(hsv.v); + fzLog const valMedium = valIsMedium(hsv.v); + fzLog const valHigh = valIsHigh(hsv.v); + fzLog const valVeryHigh = valIsVeryHigh(hsv.v); fzLog const hueAround000 = hueIsAround000(hsv.h); fzLog const hueAround015 = hueIsAround015(hsv.h); @@ -285,13 +294,13 @@ matchBk(pixel const color, fzLog const hueAround360 = hueIsAround360(hsv.h); (*bkMatchP)[BKCOLOR_BLACK] = - fzAnd(fzOr(satVeryLow, satLow), valVeryLow); + fzAnd(fzOr(satVeryLow, satLow), fzOr(valVeryLow, valLow)); (*bkMatchP)[BKCOLOR_GRAY] = - fzAnd(fzOr(satVeryLow, satLow), fzOr(valLow, valMedium)); + fzAnd(satVeryLow, fzAnd(fzNot(valVeryLow), fzNot(valVeryHigh))); (*bkMatchP)[BKCOLOR_WHITE] = - fzAnd(fzOr(satVeryLow, satLow), valHigh); + fzAnd(satVeryLow, valVeryHigh); (*bkMatchP)[BKCOLOR_RED] = fzAnd(fzAnd(fzOr(hueAround000, hueAround360), fzNot(satVeryLow)), @@ -300,38 +309,40 @@ matchBk(pixel const color, (*bkMatchP)[BKCOLOR_ORANGE] = fzAnd(fzAnd(hueAround030, fzOr(satMedium, satHigh)), - fzOr(valMedium, valHigh) + fzOr(fzOr(valMedium, valHigh), valVeryHigh) ); (*bkMatchP)[BKCOLOR_YELLOW] = fzAnd(fzAnd(hueAround060, fzOr(satMedium, satHigh)), - fzOr(valMedium, valHigh) + fzOr(valHigh, valVeryHigh) ); (*bkMatchP)[BKCOLOR_GREEN] = - fzAnd(fzAnd(hueAround120, fzNot(satVeryLow)), - fzOr(valMedium, valHigh) + fzAnd(fzAnd(hueAround120, fzOr(satMedium, satHigh)), + fzAnd(fzNot(valVeryLow), fzNot(valLow)) ); (*bkMatchP)[BKCOLOR_BLUE] = - fzAnd(fzAnd(hueAround180, fzAnd(fzNot(satVeryLow), fzNot(satLow))), - fzOr(valMedium, valHigh) + fzAnd(fzAnd(hueAround180, fzNot(satVeryLow)), + fzNot(valVeryLow) ); (*bkMatchP)[BKCOLOR_VIOLET] = - fzAnd(fzAnd(hueAround270, fzNot(satVeryLow)), + fzAnd(fzAnd(hueAround270, fzOr(satMedium, satHigh)), fzOr(valMedium, valHigh) ); (*bkMatchP)[BKCOLOR_PURPLE] = - fzAnd(fzAnd(hueAround320, fzNot(satVeryLow)), + fzAnd(fzAnd(hueAround320, fzOr(satMedium, satHigh)), fzOr(valMedium, valHigh) ); (*bkMatchP)[BKCOLOR_BROWN] = - fzAnd(fzOr(hueAround015, hueAround360), - fzAnd(fzNot(satVeryLow), fzNot(valHigh)) - ); + fzOr( + fzAnd(fzOr(hueAround015, hueAround360), + fzAnd(fzNot(satVeryLow), fzOr(valLow, valMedium))), + fzAnd(hueAround015, satLow) + ); } @@ -359,17 +370,17 @@ ppm_bk_color_from_color(pixel const color, static pixel const bkColorMap[BKCOLOR_COUNT] = { - { 0, 0, 0}, /* BKCOLOR_BLACK */ {174, 174, 174}, /* BKCOLOR_GRAY */ - {255, 255, 255}, /* BKCOLOR_WHITE */ - {255, 0, 0}, /* BKCOLOR_RED */ + {128, 42, 42}, /* BKCOLOR_BROWN */ {255, 128, 0}, /* BKCOLOR_ORANGE */ + {255, 0, 0}, /* BKCOLOR_RED */ {255, 255, 0}, /* BKCOLOR_YELLOW */ { 0, 255, 0}, /* BKCOLOR_GREEN */ { 0, 0, 255}, /* BKCOLOR_BLUE */ {143, 94, 153}, /* BKCOLOR_VIOLET */ {160, 32, 240}, /* BKCOLOR_PURPLE */ - {128, 42, 42} /* BKCOLOR_BROWN */ + {255, 255, 255}, /* BKCOLOR_WHITE */ + { 0, 0, 0} /* BKCOLOR_BLACK */ }; @@ -393,17 +404,17 @@ ppm_color_from_bk_color(bk_color const bkColor, static const char * const bkColorNameMap[BKCOLOR_COUNT] = { - "black", "gray", - "white", - "red", + "brown", "orange", + "red", "yellow", "green", "blue", "violet", "purple", - "brown" + "white", + "black" }; diff --git a/lib/pm.h b/lib/pm.h index 040a6a4b..696d763c 100644 --- a/lib/pm.h +++ b/lib/pm.h @@ -154,15 +154,25 @@ pm_setjmpbufsave(jmp_buf * const jmpbufP, void pm_longjmp(void); + +typedef void pm_usermessagefn(const char * msg); + +void +pm_setusermessagefn(pm_usermessagefn * fn); + +typedef void pm_usererrormsgfn(const char * msg); + +void +pm_setusererrormsgfn(pm_usererrormsgfn * fn); + void PM_GNU_PRINTF_ATTR(1,2) pm_message (const char format[], ...); void PM_GNU_PRINTF_ATTR(1,2) -pm_error (const char reason[], ...); +pm_errormsg(const char format[], ...); -/* Obsolete - use helpful error message instead */ -void -pm_perror (const char reason[]); +void PM_GNU_PRINTF_ATTR(1,2) +pm_error (const char reason[], ...); /* Obsolete - use shhopt and user's manual instead */ void diff --git a/lib/ppm.h b/lib/ppm.h index 033330b9..622d3e09 100644 --- a/lib/ppm.h +++ b/lib/ppm.h @@ -259,22 +259,25 @@ ppm_saturation(pixel const p, typedef enum { /* A color from the set of universally understood colors developed - by Brent Berlin and Paul Kay + by Brent Berlin and Paul Kay. + + Algorithms in libnetpbm depend on the numerical representations + of these values being as follows. */ - BKCOLOR_BLACK = 0, - BKCOLOR_GRAY, - BKCOLOR_WHITE, - BKCOLOR_RED, + BKCOLOR_GRAY = 0, + BKCOLOR_BROWN, BKCOLOR_ORANGE, + BKCOLOR_RED, BKCOLOR_YELLOW, BKCOLOR_GREEN, BKCOLOR_BLUE, BKCOLOR_VIOLET, BKCOLOR_PURPLE, - BKCOLOR_BROWN + BKCOLOR_WHITE, + BKCOLOR_BLACK } bk_color; -#define BKCOLOR_COUNT (BKCOLOR_BROWN+1) +#define BKCOLOR_COUNT (BKCOLOR_BLACK+1) bk_color ppm_bk_color_from_color(pixel const color, diff --git a/lib/util/Makefile b/lib/util/Makefile index 8f461f28..ffa1db5b 100644 --- a/lib/util/Makefile +++ b/lib/util/Makefile @@ -7,11 +7,9 @@ VPATH=.:$(SRCDIR)/$(SUBDIR) include $(BUILDDIR)/Makefile.config -INCLUDES = -I $(BUILDDIR) -I $(SRCDIR)/$(SUBDIR)/.. - # nstring is required for asprintf(), etc. Also some systems don't have # snprintf(), e.g. Solaris 2.5.1. 2002.03.29. -UTILOBJECTS = shhopt.o nstring.o filename.o +UTILOBJECTS = shhopt.o nstring.o vasprintf.o filename.o MERGE_OBJECTS = @@ -19,6 +17,8 @@ all: $(UTILOBJECTS) include $(SRCDIR)/Makefile.common +INCLUDES = -I $(BUILDDIR) -I $(SRCDIR)/$(SUBDIR)/.. + $(UTILOBJECTS):%.o:%.c importinc $(CC) -c $(INCLUDES) -DNDEBUG $(CFLAGS) $(CFLAGS_SHLIB) \ $(CFLAGS_PERSONAL) $(CADD) -o $@ $< diff --git a/lib/util/nstring.c b/lib/util/nstring.c index 702a3c44..58500547 100644 --- a/lib/util/nstring.c +++ b/lib/util/nstring.c @@ -740,15 +740,6 @@ const char * const strsol = "NO MEMORY TO CREATE STRING!"; -/* We would like to have vasprintfN(), but it is difficult because you - can't run through a va_list twice, which we would want to do: once - to measure the length; once actually to build the string. On some - machines, you can simply make two copies of the va_list variable in - normal C fashion, but on others you need va_copy, which is a - relatively recent invention. In particular, the simple va_list copy - failed on an AMD64 Gcc Linux system in March 2006. -*/ - void PM_GNU_PRINTF_ATTR(2,3) asprintfN(const char ** const resultP, const char * const fmt, @@ -904,3 +895,20 @@ memmemN(const char * const haystack, return NULL; } + + + +bool +strishex(const char * const subject) { + + bool retval; + unsigned int i; + + retval = TRUE; /* initial assumption */ + + for (i = 0; i < strlen(subject); ++i) + if (!ISXDIGIT(subject[i])) + retval = FALSE; + + return retval; +} diff --git a/lib/util/nstring.h b/lib/util/nstring.h index 9ed20051..70a53f45 100644 --- a/lib/util/nstring.h +++ b/lib/util/nstring.h @@ -5,6 +5,7 @@ #include #include +#include "pm_c_util.h" #include "pm.h" /* For PM_GNU_PRINTF_ATTR, __inline__ */ #ifdef __cplusplus @@ -134,6 +135,11 @@ asprintfN(const char ** const resultP, const char * const fmt, ...) PM_GNU_PRINTF_ATTR(2,3); +void +vasprintfN(const char ** const resultP, + const char * const format, + va_list args); + void strfree(const char * const string); @@ -150,6 +156,9 @@ memmemN(const char * const haystack, const char * const needle, size_t const needlelen); +bool +strishex(const char * const subject); + #ifdef __cplusplus } #endif diff --git a/other/Makefile b/other/Makefile index 87f92f96..139527e3 100644 --- a/other/Makefile +++ b/other/Makefile @@ -9,9 +9,10 @@ include $(BUILDDIR)/Makefile.config SUBDIRS = pamx +EXTERN_INCLUDES = ifneq ($(LINUXSVGALIB),NONE) ifneq ($(LINUXSVGAHDR_DIR),) - INCLUDES += -I$(LINUXSVGAHDR_DIR) + EXTERN_INCLUDES += -I$(LINUXSVGAHDR_DIR) endif endif diff --git a/other/pamx/Makefile b/other/pamx/Makefile index a86a3331..8aab2608 100644 --- a/other/pamx/Makefile +++ b/other/pamx/Makefile @@ -7,9 +7,10 @@ VPATH=.:$(SRCDIR)/$(SUBDIR) include $(BUILDDIR)/Makefile.config +EXTERN_INCLUDE = ifneq ($(X11LIB),NONE) ifneq ($(X11HDR_DIR),) - INCLUDES += -I$(X11HDR_DIR) + EXTERN_INCLUDES += -I$(X11HDR_DIR) endif endif diff --git a/urt/scanargs.c b/urt/scanargs.c index 416f2380..b91f3e37 100644 --- a/urt/scanargs.c +++ b/urt/scanargs.c @@ -49,9 +49,9 @@ #include #endif +#include "pm_c_util.h" #include "nstring.h" -typedef char bool; /* * An explicit assumption is made in this code that all pointers look * alike, except possible char * pointers. -- cgit 1.4.1