#include #include #include #include "pm_c_util.h" #include "shhopt.h" #include "mallocvar.h" typedef struct { unsigned int * target; unsigned int targetDepth; unsigned int machine; const char * color; /* NULL means not specified */ const char * inputFileName; } CmdLineInfo; static CmdLineInfo parsedCommandLine(int argc, const char ** const argv) { optEntry * option_def; /* Instructions to OptParseOptions4 on how to parse our options. */ optStruct3 opt; unsigned int option_def_index; CmdLineInfo cmdLine; unsigned int targetSpec, colorSpec; const char ** target; MALLOCARRAY_NOFAIL(option_def, 100); option_def_index = 0; /* incremented by OPTENT3 */ OPTENT3(0, "target", OPT_STRINGLIST, &target, &targetSpec, 0); OPTENT3(0, "color", OPT_STRING, &cmdLine.color, &colorSpec, 0); OPTENT3(0, "machine", OPT_FLAG, NULL, &cmdLine.machine, 0); OPTENT3(0, 0, OPT_END, NULL, NULL, 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 */ pm_optParseOptions4(&argc, argv, opt, sizeof(opt), 0); if (targetSpec + colorSpec > 1) pm_error("You cannot specify both -target and -color"); else if (targetSpec + colorSpec == 0) pm_error("You must specify either -target or -color"); else if (targetSpec) { unsigned int i; cmdLine.color = NULL; cmdLine.target = NULL; /* initial value */ for (i = 0, cmdLine.targetDepth = 0; target[i]; ++i) { unsigned int sampleVal; const char * error; pm_string_to_uint(target[i], &sampleVal, &error); if (error) { pm_error("Invalid sample value in -target option: '%s'. " "%s", target[i], error); } REALLOCARRAY(cmdLine.target, i+1); cmdLine.target[cmdLine.targetDepth++] = sampleVal; } free(target); } else assert (colorSpec == 1); if (argc-1 < 1) cmdLine.inputFileName = "-"; else { cmdLine.inputFileName = argv[1]; if (argc-1 > 1) pm_error("Too many arguments: %u. " "The only possible argument is the input file name", argc-1); } free(option_def); return cmdLine; } static void freeCmdLine(CmdLineInfo const cmdLine) { if (!cmdLine.color) pnm_freepamtuple(cmdLine.target); } static tuple targetValue(CmdLineInfo const cmdLine, struct pam * const inpamP) { /*---------------------------------------------------------------------------- The tuple value user wants us to find in the image, per 'cmdLine'. The return value is to be interpreted per *inpamP. -----------------------------------------------------------------------------*/ tuple retval; if (cmdLine.color) { if (inpamP->depth != 3) pm_error("You specified -color, but the input image has " "depth %u, not 3", inpamP->depth); else retval = pnm_parsecolor(cmdLine.color, inpamP->maxval); } else { if (cmdLine.targetDepth != inpamP->depth) pm_error("You specified a %u-tuple for -target, " "but the input image is of depth %u", cmdLine.targetDepth, inpamP->depth); else { unsigned int i; retval = pnm_allocpamtuple(inpamP); for (i = 0; i < inpamP->depth; ++i) retval[i] = cmdLine.target[i]; } } return retval; } static void printHeader(FILE * const ofP, struct pam * const inpamP, tuple const target) { unsigned int plane; fprintf(ofP, "Locations containing tuple "); fprintf(ofP, "("); for (plane = 0; plane < inpamP->depth; ++plane) { fprintf(ofP, "%u", (unsigned)target[plane]); if (plane + 1 < inpamP->depth) fprintf(ofP, "/"); } fprintf(ofP, ")"); fprintf(ofP, "/%u", (unsigned)inpamP->maxval); fprintf(ofP, ":\n"); } static unsigned int decimalDigitCt(unsigned int const n) { /*---------------------------------------------------------------------------- Minimum number of digits needed to display 'n' in decimal. -----------------------------------------------------------------------------*/ unsigned int digitCt; if (n == 0) digitCt = 1; else { unsigned int x; for (digitCt = 0, x = n; x > 0;) { ++digitCt; x /= 10; } assert(digitCt > 0); } return digitCt; } static void pamfind(FILE * const ifP, struct pam * const inpamP, CmdLineInfo const cmdLine, FILE * const ofP) { pnm_readpaminit(ifP, inpamP, PAM_STRUCT_SIZE(tuple_type)); { tuple * const inputRow = pnm_allocpamrow(inpamP); tuple const target = targetValue(cmdLine, inpamP); unsigned int row; const char * fmt; if (cmdLine.machine) { pm_asprintf(&fmt, "%%0%uu %%0%uu\n", decimalDigitCt(inpamP->height-1), decimalDigitCt(inpamP->width-1)); } else { printHeader(ofP, inpamP, target); fmt = pm_strdup("(%u, %u)\n"); } for (row = 0; row < inpamP->height; ++row) { unsigned int col; pnm_readpamrow(inpamP, inputRow); for (col = 0; col < inpamP->width; ++col) { if (pnm_tupleequal(inpamP, target, inputRow[col])) { fprintf(ofP, fmt, row, col); } } } pm_strfree(fmt); pnm_freepamtuple(target); pnm_freepamrow(inputRow); } } int main(int argc, const char *argv[]) { FILE * ifP; CmdLineInfo cmdLine; struct pam inpam; pm_proginit(&argc, argv); cmdLine = parsedCommandLine(argc, argv); ifP = pm_openr(cmdLine.inputFileName); pamfind(ifP, &inpam, cmdLine, stdout); freeCmdLine(cmdLine); pm_close(inpam.file); return 0; }