From aff215cc29a295b7bdcc604ae1e71c5514113c29 Mon Sep 17 00:00:00 2001 From: giraffedata Date: Mon, 28 Dec 2020 01:09:14 +0000 Subject: Promote Development to Advanced as Release 10.93.00 git-svn-id: http://svn.code.sf.net/p/netpbm/code/advanced@4017 9d0c8265-081b-0410-96cb-a4ca84ce46f8 --- other/pamarith.c | 457 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 332 insertions(+), 125 deletions(-) (limited to 'other') diff --git a/other/pamarith.c b/other/pamarith.c index 180dbe23..31f52a59 100644 --- a/other/pamarith.c +++ b/other/pamarith.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "pm_c_util.h" #include "mallocvar.h" @@ -8,8 +9,10 @@ #include "shhopt.h" #include "pam.h" -enum function {FN_ADD, FN_SUBTRACT, FN_MULTIPLY, FN_DIVIDE, FN_DIFFERENCE, - FN_MINIMUM, FN_MAXIMUM, FN_MEAN, FN_COMPARE, +static double const EPSILON = 1.0e-5; + +enum Function {FN_ADD, FN_SUBTRACT, FN_MULTIPLY, FN_DIVIDE, FN_DIFFERENCE, + FN_MINIMUM, FN_MAXIMUM, FN_MEAN, FN_EQUAL, FN_COMPARE, FN_AND, FN_OR, FN_NAND, FN_NOR, FN_XOR, FN_SHIFTLEFT, FN_SHIFTRIGHT }; @@ -17,7 +20,7 @@ enum function {FN_ADD, FN_SUBTRACT, FN_MULTIPLY, FN_DIVIDE, FN_DIFFERENCE, static bool -isDyadic(enum function const function) { +isDyadic(enum Function const function) { bool retval; @@ -26,7 +29,6 @@ isDyadic(enum function const function) { case FN_MULTIPLY: case FN_MINIMUM: case FN_MAXIMUM: - case FN_MEAN: case FN_AND: case FN_NAND: case FN_OR: @@ -38,8 +40,10 @@ isDyadic(enum function const function) { case FN_DIFFERENCE: case FN_COMPARE: case FN_DIVIDE: + case FN_MEAN: case FN_SHIFTLEFT: case FN_SHIFTRIGHT: + case FN_EQUAL: retval = TRUE; break; } @@ -52,9 +56,10 @@ struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - enum function function; + enum Function function; unsigned int operandCt; const char ** operandFileNames; + double closeness; }; @@ -75,9 +80,11 @@ parseCommandLine(int argc, const char ** const argv, unsigned int addSpec, subtractSpec, multiplySpec, divideSpec, differenceSpec, - minimumSpec, maximumSpec, meanSpec, compareSpec, + minimumSpec, maximumSpec, meanSpec, equalSpec, compareSpec, andSpec, orSpec, nandSpec, norSpec, xorSpec, - shiftleftSpec, shiftrightSpec; + shiftleftSpec, shiftrightSpec, closenessSpec; + + float closeness; MALLOCARRAY_NOFAIL(option_def, 100); @@ -90,6 +97,7 @@ parseCommandLine(int argc, const char ** const argv, OPTENT3(0, "minimum", OPT_FLAG, NULL, &minimumSpec, 0); OPTENT3(0, "maximum", OPT_FLAG, NULL, &maximumSpec, 0); OPTENT3(0, "mean", OPT_FLAG, NULL, &meanSpec, 0); + OPTENT3(0, "equal", OPT_FLAG, NULL, &equalSpec, 0); OPTENT3(0, "compare", OPT_FLAG, NULL, &compareSpec, 0); OPTENT3(0, "and", OPT_FLAG, NULL, &andSpec, 0); OPTENT3(0, "or", OPT_FLAG, NULL, &orSpec, 0); @@ -98,6 +106,7 @@ parseCommandLine(int argc, const char ** const argv, OPTENT3(0, "xor", OPT_FLAG, NULL, &xorSpec, 0); OPTENT3(0, "shiftleft", OPT_FLAG, NULL, &shiftleftSpec, 0); OPTENT3(0, "shiftright", OPT_FLAG, NULL, &shiftrightSpec, 0); + OPTENT3(0, "closeness", OPT_FLOAT, &closeness, &closenessSpec, 0); opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ @@ -107,7 +116,7 @@ parseCommandLine(int argc, const char ** const argv, /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (addSpec + subtractSpec + multiplySpec + divideSpec + differenceSpec + - minimumSpec + maximumSpec + meanSpec + compareSpec + + minimumSpec + maximumSpec + meanSpec + equalSpec + compareSpec + andSpec + orSpec + nandSpec + norSpec + xorSpec + shiftleftSpec + shiftrightSpec > 1) pm_error("You may specify only one function"); @@ -128,6 +137,8 @@ parseCommandLine(int argc, const char ** const argv, cmdlineP->function = FN_MAXIMUM; else if (meanSpec) cmdlineP->function = FN_MEAN; + else if (equalSpec) + cmdlineP->function = FN_EQUAL; else if (compareSpec) cmdlineP->function = FN_COMPARE; else if (andSpec) @@ -147,15 +158,29 @@ parseCommandLine(int argc, const char ** const argv, else pm_error("You must specify a function (e.g. '-add')"); + if (closenessSpec) { + if (cmdlineP->function != FN_EQUAL) + pm_error("-closeness is valid only with -equal"); + else { + if (closeness < 0 || closeness > 100) + pm_error("-closeness value %f is not a valid percentage", + closeness); + cmdlineP->closeness = (double)closeness/100; + } + } else + cmdlineP->closeness = EPSILON; + if (argc-1 < 2) pm_error("You must specify at least two arguments: the files which " "are the operands of the function. You specified %u", argc-1); else { if (isDyadic(cmdlineP->function) && argc-1 > 2) - pm_error("You specified %u arguments, but a dyadic function. " - "For a dyadic function, you must specify 2 arguments: " - "the operands of the function", argc-1); + pm_error("You specified %u arguments, but a function " + "which is not associative and commutative. " + "Unless a function is associative and commutative " + "(like -add), you must specify exactly two arguments. ", + argc-1); else { cmdlineP->operandCt = argc-1; cmdlineP->operandFileNames = &argv[1]; @@ -180,8 +205,66 @@ enum category { +static void +validateSameWidthHeight(const struct pam * const inpam /* array */, + unsigned int const operandCt) { + unsigned int i; + + for (i = 1; i < operandCt; ++i) { + + if (i > 0) { + if (inpam[i].width != inpam[0].width || + inpam[i].height != inpam[0].height) { + pm_error("The images must be the same width and height. " + "The first is %ux%ux%u, but another is %ux%ux%u", + inpam[0].width, inpam[0].height, inpam[0].depth, + inpam[i].width, inpam[i].height, inpam[i].depth); + } + } + } +} + + + +static void +validateCompatibleDepth(const struct pam * const inpam /* array */, + unsigned int const operandCt) { + + unsigned int i; + bool haveNonUnityDepth; + unsigned int nonUnityDepth; + + for (i = 0, haveNonUnityDepth = false; i < operandCt; ++i) { + if (inpam[i].depth != 1) { + if (haveNonUnityDepth) { + if (inpam[i].depth != nonUnityDepth) + pm_error("The images must have the same depth " + "or depth 1. " + "But one has depth %u and another %u", + nonUnityDepth, inpam[i].depth); + } else { + haveNonUnityDepth = true; + nonUnityDepth = inpam[i].depth; + } + } + } +} + + + +static void +validateConsistentDimensions(const struct pam * const inpam /* array */, + unsigned int const operandCt) { + + validateSameWidthHeight(inpam, operandCt); + + validateCompatibleDepth(inpam, operandCt); +} + + + static enum category -functionCategory(enum function const function) { +functionCategory(enum Function const function) { enum category retval; @@ -192,6 +275,7 @@ functionCategory(enum function const function) { case FN_MINIMUM: case FN_MAXIMUM: case FN_MEAN: + case FN_EQUAL: case FN_COMPARE: case FN_MULTIPLY: case FN_DIVIDE: @@ -238,63 +322,147 @@ outFmtForCompare(int const format1, +static unsigned int +maxDepth(const struct pam * const pam, + unsigned int const pamCt) { + + unsigned int maxDepthSoFar; + unsigned int i; + + assert(pamCt >= 1); + + maxDepthSoFar = pam[0].depth; + for (i = 1; i < pamCt; ++i) { + if (pam[i].depth > maxDepthSoFar) + maxDepthSoFar = pam[i].depth; + } + return maxDepthSoFar; +} + + + +static int +maxFormat(const struct pam * const pam, + unsigned int const pamCt) { + + int maxFormatSoFar; + unsigned int i; + + assert(pamCt >= 1); + + maxFormatSoFar = pam[0].format; + for (i = 1; i < pamCt; ++i) { + if (pam[i].format > maxFormatSoFar) + maxFormatSoFar = pam[i].format; + } + return maxFormatSoFar; +} + + + +static sample +maxMaxval(const struct pam * const pam, + unsigned int const pamCt) { + + sample maxMaxvalSoFar; + unsigned int i; + + assert(pamCt >= 1); + + maxMaxvalSoFar = pam[0].maxval; + for (i = 1; i < pamCt; ++i) { + if (pam[i].maxval > maxMaxvalSoFar) + maxMaxvalSoFar = pam[i].maxval; + } + return maxMaxvalSoFar; +} + + + +static bool +maxvalsAreEqual(const struct pam * const pam, + unsigned int const pamCt) { + + bool equalSoFar; + unsigned int i; + + assert(pamCt >= 1); + + equalSoFar = true; + + for (i = 1; i < pamCt; ++i) { + if (pam[i].maxval != pam[0].maxval) + equalSoFar = false; + } + return equalSoFar; +} + + + static void -computeOutputType(struct pam * const outpamP, - struct pam const inpam1, - struct pam const inpam2, - enum function const function) { +computeOutputType(struct pam * const outpamP, + const struct pam * const inpam, /* array */ + unsigned int const operandCt, + enum Function const function) { + + assert(operandCt >= 1); outpamP->size = sizeof(struct pam); outpamP->len = PAM_STRUCT_SIZE(tuple_type); outpamP->file = stdout; outpamP->plainformat = FALSE; - outpamP->height = inpam1.height; - outpamP->width = inpam1.width; - outpamP->depth = MAX(inpam1.depth, inpam2.depth); + outpamP->height = inpam[0].height; + outpamP->width = inpam[0].width; + outpamP->depth = maxDepth(inpam, operandCt); - if (function == FN_COMPARE) - outpamP->format = outFmtForCompare(inpam1.format, inpam2.format); - else - outpamP->format = MAX(inpam1.format, inpam2.format); + if (function == FN_COMPARE) { + assert(operandCt == 2); + outpamP->format = outFmtForCompare(inpam[0].format, inpam[1].format); + } else + outpamP->format = maxFormat(inpam, operandCt); switch (functionCategory(function)) { case CATEGORY_FRACTIONAL_ARITH: if (function == FN_COMPARE) outpamP->maxval = 2; + else if (function == FN_EQUAL) + outpamP->maxval = 1; else - outpamP->maxval = MAX(inpam1.maxval, inpam2.maxval); + outpamP->maxval = maxMaxval(inpam, operandCt); break; case CATEGORY_BITSTRING: - if (inpam2.maxval != inpam1.maxval) + if (!maxvalsAreEqual(inpam, operandCt)) pm_error("For a bit string operation, the maxvals of the " - "left and right image must be the same. You have " - "left=%u and right=%u", - (unsigned)inpam1.maxval, (unsigned)inpam2.maxval); + "operand images must be the same. Yours differ"); - if (pm_bitstomaxval(pm_maxvaltobits(inpam1.maxval)) != inpam1.maxval) + if (pm_bitstomaxval(pm_maxvaltobits(inpam[0].maxval)) != + inpam[0].maxval) pm_error("For a bit string operation, the maxvals of the inputs " "must be a full binary count, i.e. a power of two " "minus one such as 0xff. You have 0x%x", - (unsigned)inpam1.maxval); + (unsigned)inpam[0].maxval); - outpamP->maxval = inpam1.maxval; + outpamP->maxval = inpam[0].maxval; break; case CATEGORY_SHIFT: - if (pm_bitstomaxval(pm_maxvaltobits(inpam1.maxval)) != inpam1.maxval) + if (pm_bitstomaxval(pm_maxvaltobits(inpam[0].maxval)) != + inpam[0].maxval) pm_error("For a bit shift operation, the maxval of the left " "input image " "must be a full binary count, i.e. a power of two " "minus one such as 0xff. You have 0x%x", - (unsigned)inpam1.maxval); - outpamP->maxval = inpam1.maxval; + (unsigned)inpam[0].maxval); + outpamP->maxval = inpam[0].maxval; } outpamP->bytes_per_sample = (pm_maxvaltobits(outpamP->maxval)+7)/8; - if (outpamP->maxval > 1 && strneq(inpam1.tuple_type, "BLACKANDWHITE", 13)) + if (outpamP->maxval > 1 && + strneq(inpam[0].tuple_type, "BLACKANDWHITE", 13)) { + strcpy(outpamP->tuple_type, ""); - else - strcpy(outpamP->tuple_type, inpam1.tuple_type); + } else + strcpy(outpamP->tuple_type, inpam[0].tuple_type); } @@ -316,6 +484,21 @@ samplenSum(samplen const operands[], +static samplen +samplenProduct(samplen const operands[], + unsigned int const operandCt) { + + unsigned int i; + double product; + + for (i = 1, product = operands[0]; i < operandCt; ++i) + product *= operands[i]; + + return product; +} + + + static samplen samplenMin(samplen const operands[], unsigned int const operandCt) { @@ -364,24 +547,28 @@ samplenMean(samplen const operands[], static samplen -samplenProduct(samplen const operands[], - unsigned int const operandCt) { +samplenEqual(samplen const operands[], + unsigned int const operandCt, + double const closeness) { unsigned int i; - double product; + bool allEqual; - for (i = 1, product = operands[0]; i < operandCt; ++i) - product *= operands[i]; + for (i = 1, allEqual = true; i < operandCt; ++i) { + if (fabs(operands[i]- operands[0]) > closeness) + allEqual = false; + } - return product; + return allEqual ? 1.0 : 0.0; } static samplen -applyNormalizedFunction(enum function const function, +applyNormalizedFunction(enum Function const function, samplen const operands[], - unsigned int const operandCt) { + unsigned int const operandCt, + double const closeness) { samplen result; @@ -412,6 +599,9 @@ applyNormalizedFunction(enum function const function, case FN_MEAN: result = samplenMean(operands, operandCt); break; + case FN_EQUAL: + result = samplenEqual(operands, operandCt, closeness); + break; case FN_COMPARE: result = operands[0] > operands[1] ? @@ -429,16 +619,11 @@ applyNormalizedFunction(enum function const function, static void -doNormalizedArith(struct pam * const inpam1P, - struct pam * const inpam2P, - struct pam * const outpamP, - enum function const function) { - - /* Some of the logic in this subroutine is designed for future - expansion into non-dyadic computations. But for now, all - computations have exactly two operands. - */ - unsigned int const operandCt = 2; +doNormalizedArith(const struct pam * const inpam, /* array */ + unsigned int const operandCt, + const struct pam * const outpamP, + enum Function const function, + double const closeness) { tuplen ** tuplerown; /* tuplerown[0] is the current row in the first operand image */ @@ -454,34 +639,39 @@ doNormalizedArith(struct pam * const inpam1P, the current one-sample computation. plane[1] is the plane number in the second operand image, etc. */ + unsigned int i; MALLOCARRAY_NOFAIL(operands, operandCt); MALLOCARRAY_NOFAIL(plane, operandCt); MALLOCARRAY_NOFAIL(tuplerown, operandCt); - tuplerown[0] = pnm_allocpamrown(inpam1P); - tuplerown[1] = pnm_allocpamrown(inpam2P); + for (i = 0; i < operandCt; ++i) + tuplerown[i] = pnm_allocpamrown(&inpam[i]); tuplerownOut = pnm_allocpamrown(outpamP); for (row = 0; row < outpamP->height; ++row) { + unsigned int i; unsigned int col; - pnm_readpamrown(inpam1P, tuplerown[0]); - pnm_readpamrown(inpam2P, tuplerown[1]); + + for (i = 0; i < operandCt; ++i) + pnm_readpamrown(&inpam[i], tuplerown[i]); for (col = 0; col < outpamP->width; ++col) { unsigned int outplane; for (outplane = 0; outplane < outpamP->depth; ++outplane) { + unsigned int i; unsigned int op; - plane[0] = MIN(outplane, inpam1P->depth-1); - plane[1] = MIN(outplane, inpam2P->depth-1); + for (i = 0; i < operandCt; ++i) + plane[i] = MIN(outplane, inpam[i].depth-1); for (op = 0; op < operandCt; ++op) operands[op] = tuplerown[op][col][plane[op]]; tuplerownOut[col][outplane] = - applyNormalizedFunction(function, operands, operandCt); + applyNormalizedFunction(function, operands, operandCt, + closeness); assert(tuplerownOut[col][outplane] >= 0.); assert(tuplerownOut[col][outplane] <= 1.); } @@ -489,8 +679,8 @@ doNormalizedArith(struct pam * const inpam1P, pnm_writepamrown(outpamP, tuplerownOut); } - pnm_freepamrown(tuplerown[0]); - pnm_freepamrown(tuplerown[1]); + for (i = 0; i < operandCt; ++i) + pnm_freepamrown(tuplerown[i]); free(tuplerown); pnm_freepamrown(tuplerownOut); free(plane); @@ -517,6 +707,22 @@ sampleSum(sample const operands[], +static sample +sampleProduct(sample const operands[], + unsigned int const operandCt, + sample const maxval) { + + unsigned int i; + double product; + + for (i = 0, product = 1.0; i < operandCt; ++i) { + product *= ((double)operands[i]/maxval); + } + return (sample)(product * maxval + 0.5); +} + + + static sample sampleMin(sample const operands[], unsigned int const operandCt) { @@ -567,17 +773,18 @@ sampleMean(sample const operands[], static sample -sampleProduct(sample const operands[], - unsigned int const operandCt, - sample const maxval) { +sampleEqual(sample const operands[], + unsigned int const operandCt, + sample const maxval) { unsigned int i; - double product; + bool allEqual; - for (i = 0, product = 1.0; i < operandCt; ++i) { - product *= ((double)operands[i]/maxval); + for (i = 1, allEqual = true; i < operandCt; ++i) { + if (operands[i] != operands[0]) + allEqual = false; } - return (sample)(product * maxval + 0.5); + return allEqual ? maxval : 0; } @@ -660,7 +867,7 @@ sampleXor(sample const operands[], static sample -applyUnNormalizedFunction(enum function const function, +applyUnNormalizedFunction(enum Function const function, sample const operands[], unsigned int const operandCt, sample const maxval) { @@ -700,6 +907,9 @@ applyUnNormalizedFunction(enum function const function, case FN_MEAN: result = sampleMean(operands, operandCt); break; + case FN_EQUAL: + result = sampleEqual(operands, operandCt, maxval); + break; case FN_COMPARE: result = operands[0] > operands[1] ? 2 : operands[0] < operands[1] ? 0 : 1; @@ -744,21 +954,15 @@ applyUnNormalizedFunction(enum function const function, static void -doUnNormalizedArith(struct pam * const inpam1P, - struct pam * const inpam2P, - struct pam * const outpamP, - enum function const function) { +doUnNormalizedArith(const struct pam * const inpam, /* array */ + unsigned int const operandCt, + const struct pam * const outpamP, + enum Function const function) { /*---------------------------------------------------------------------------- Take advantage of the fact that both inputs and the output use the same maxval to do the computation without time-consuming normalization of sample values. -----------------------------------------------------------------------------*/ - /* Some of the logic in this subroutine is designed for future - expansion into non-dyadic computations. But for now, all - computations have exactly two operands. - */ - unsigned int const operandCt = 2; - sample const maxval = outpamP->maxval; tuple ** tuplerow; @@ -775,33 +979,33 @@ doUnNormalizedArith(struct pam * const inpam1P, the current one-sample computation. plane[1] is the plane number in the second operand image, etc. */ - - /* Input conditions: */ - assert(inpam1P->maxval == maxval); - assert(inpam2P->maxval == maxval); - assert(outpamP->maxval == maxval); + unsigned int i; MALLOCARRAY_NOFAIL(operands, operandCt); MALLOCARRAY_NOFAIL(plane, operandCt); MALLOCARRAY_NOFAIL(tuplerow, operandCt); - tuplerow[0] = pnm_allocpamrow(inpam1P); - tuplerow[1] = pnm_allocpamrow(inpam2P); + for (i = 0; i < operandCt; ++i) + tuplerow[i] = pnm_allocpamrow(&inpam[i]); + tuplerowOut = pnm_allocpamrow(outpamP); for (row = 0; row < outpamP->height; ++row) { + unsigned int i; unsigned int col; - pnm_readpamrow(inpam1P, tuplerow[0]); - pnm_readpamrow(inpam2P, tuplerow[1]); + + for (i = 0; i < operandCt; ++i) + pnm_readpamrow(&inpam[i], tuplerow[i]); for (col = 0; col < outpamP->width; ++col) { unsigned int outplane; for (outplane = 0; outplane < outpamP->depth; ++outplane) { unsigned int op; + unsigned int i; - plane[0] = MIN(outplane, inpam1P->depth-1); - plane[1] = MIN(outplane, inpam2P->depth-1); + for (i = 0; i < operandCt; ++i) + plane[i] = MIN(outplane, inpam[i].depth-1); for (op = 0; op < operandCt; ++op) operands[op] = tuplerow[op][col][plane[op]]; @@ -817,8 +1021,8 @@ doUnNormalizedArith(struct pam * const inpam1P, pnm_writepamrow(outpamP, tuplerowOut); } - pnm_freepamrow(tuplerow[0]); - pnm_freepamrow(tuplerow[1]); + for (i = 0; i < operandCt; ++i) + pnm_freepamrow(tuplerow[i]); free(tuplerow); pnm_freepamrow(tuplerowOut); free(plane); @@ -831,57 +1035,60 @@ int main(int argc, const char *argv[]) { struct CmdlineInfo cmdline; - struct pam inpam1; - struct pam inpam2; - struct pam outpam; - FILE * if1P; - FILE * if2P; + struct pam * inpam; /* malloc'ed array */ + FILE ** ifP; /* malloc'ed array */ + struct pam outpam; pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); - if (cmdline.operandCt != 2) - /* Code for > 2 operands not written yet */ - pm_error("You specified %u operands. We understand only 2.", - cmdline.operandCt); - - if1P = pm_openr(cmdline.operandFileNames[0]); - if2P = pm_openr(cmdline.operandFileNames[1]); + MALLOCARRAY(inpam, cmdline.operandCt); + MALLOCARRAY(ifP, cmdline.operandCt); - pnm_readpaminit(if1P, &inpam1, PAM_STRUCT_SIZE(tuple_type)); - pnm_readpaminit(if2P, &inpam2, PAM_STRUCT_SIZE(tuple_type)); + if (!inpam || !ifP) + pm_error("Failed to allocate arrays for %u operands", + cmdline.operandCt); - if (inpam1.width != inpam2.width || inpam1.height != inpam2.height) - pm_error("The two images must be the same width and height. " - "The first is %ux%ux%u, but the second is %ux%ux%u", - inpam1.width, inpam1.height, inpam1.depth, - inpam2.width, inpam2.height, inpam2.depth); + { + unsigned int i; + for (i = 0; i < cmdline.operandCt; ++i) { + ifP[i] = pm_openr(cmdline.operandFileNames[i]); - if (inpam1.depth != 1 && inpam2.depth != 1 && inpam1.depth != inpam2.depth) - pm_error("The two images must have the same depth or one of them " - "must have depth 1. The first has depth %u and the second " - "has depth %u", inpam1.depth, inpam2.depth); + pnm_readpaminit(ifP[i], &inpam[i], PAM_STRUCT_SIZE(tuple_type)); + } + } + validateConsistentDimensions(inpam, cmdline.operandCt); - computeOutputType(&outpam, inpam1, inpam2, cmdline.function); + computeOutputType(&outpam, inpam, cmdline.operandCt, cmdline.function); pnm_writepaminit(&outpam); switch (functionCategory(cmdline.function)) { case CATEGORY_FRACTIONAL_ARITH: - if (inpam1.maxval == inpam2.maxval && inpam2.maxval == outpam.maxval) - doUnNormalizedArith(&inpam1, &inpam2, &outpam, cmdline.function); + if (maxvalsAreEqual(inpam, cmdline.operandCt) && + inpam[0].maxval == outpam.maxval) + doUnNormalizedArith(inpam, cmdline.operandCt, &outpam, + cmdline.function); else - doNormalizedArith(&inpam1, &inpam2, &outpam, cmdline.function); + doNormalizedArith(inpam, cmdline.operandCt, &outpam, + cmdline.function, cmdline.closeness); break; case CATEGORY_BITSTRING: case CATEGORY_SHIFT: - doUnNormalizedArith(&inpam1, &inpam2, &outpam, cmdline.function); + doUnNormalizedArith(inpam, cmdline.operandCt, &outpam, + cmdline.function); break; } - pm_close(if1P); - pm_close(if2P); + { + unsigned int i; + for (i = 0; i < cmdline.operandCt; ++i) + pm_close(ifP[i]); + } return 0; } + + + -- cgit 1.4.1