1 /******************************************************************************
2 pamexec
3 *******************************************************************************
4 Split a Netpbm format input file into multiple Netpbm format output streams
5 with one image per output stream and pipe this into the specified command.
6
7 By Bryan Henderson, Olympia WA; June 2000
8 and Michael Pot, New Zealand, August 2011
9
10 Contributed to the public domain by its authors.
11
12 ******************************************************************************/
13
14 #define _DEFAULT_SOURCE 1 /* New name for SVID & BSD source defines */
15 #define _BSD_SOURCE 1 /* Make sure strdup() is in string.h */
16 #define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */
17
18 #include <string.h>
19 #include <stdio.h>
20 #include <errno.h>
21
22 #include "pm_c_util.h"
23 #include "shhopt.h"
24 #include "nstring.h"
25 #include "mallocvar.h"
26 #include "pam.h"
27
28 struct cmdlineInfo {
29 /* All the information the user supplied in the command line,
30 in a form easy for the program to use.
31 */
32 const char * command;
33 const char * inputFileName;
34 unsigned int debug;
35 unsigned int check;
36 };
37
38
39
40
41 static void
parseCommandLine(int argc,const char ** argv,struct cmdlineInfo * const cmdlineP)42 parseCommandLine(int argc, const char ** argv,
43 struct cmdlineInfo * const cmdlineP) {
44 /*----------------------------------------------------------------------------
45 Note that the pointers we place into *cmdlineP are sometimes to storage
46 in the argv array.
47 -----------------------------------------------------------------------------*/
48 optEntry *option_def;
49 /* Instructions to OptParseOptions3 on how to parse our options.
50 */
51 optStruct3 opt;
52
53 unsigned int option_def_index;
54
55 MALLOCARRAY_NOFAIL(option_def, 100);
56
57 option_def_index = 0; /* incremented by OPTENT3 */
58 OPTENT3(0, "debug", OPT_FLAG, NULL, &cmdlineP->debug, 0);
59 OPTENT3(0, "check", OPT_FLAG, NULL, &cmdlineP->check, 0);
60
61 opt.opt_table = option_def;
62 opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */
63 opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */
64
65 pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
66 /* Uses and sets argc, argv, and some of *cmdlineP and others. */
67
68 if (argc-1 < 1)
69 pm_error("You must specify at least one argument: the shell command "
70 "to execute");
71 else {
72 cmdlineP->command = argv[1];
73
74 if (argc-1 < 2)
75 cmdlineP->inputFileName = "-";
76 else {
77 cmdlineP->inputFileName = argv[2];
78
79 if (argc-1 > 2)
80 pm_error("Too many arguments. There are at most two: "
81 "command and input file name");
82 }
83 }
84 }
85
86
87
88 static void
pipeOneImage(FILE * const infileP,FILE * const outfileP)89 pipeOneImage(FILE * const infileP,
90 FILE * const outfileP) {
91
92 struct pam inpam;
93 struct pam outpam;
94 enum pm_check_code checkRetval;
95
96 unsigned int row;
97 tuple * tuplerow;
98
99 pnm_readpaminit(infileP, &inpam, PAM_STRUCT_SIZE(tuple_type));
100
101 pnm_checkpam(&inpam, PM_CHECK_BASIC, &checkRetval);
102
103 outpam = inpam;
104 outpam.file = outfileP;
105
106 pnm_writepaminit(&outpam);
107
108 tuplerow = pnm_allocpamrow(&inpam);
109
110 for (row = 0; row < inpam.height; ++row) {
111 pnm_readpamrow(&inpam, tuplerow);
112 pnm_writepamrow(&outpam, tuplerow);
113 }
114
115 pnm_freepamrow(tuplerow);
116 }
117
118
119
120 static void
doOneImage(FILE * const ifP,const char * const command,bool const check,const char ** const errorP)121 doOneImage(FILE * const ifP,
122 const char * const command,
123 bool const check,
124 const char ** const errorP) {
125 /*----------------------------------------------------------------------------
126 Run command 'command' on the next image in stream *ifP.
127
128 Return as *errorP a text explanation of how we failed, or NULL if we
129 didn't.
130 -----------------------------------------------------------------------------*/
131 FILE * ofP;
132
133 ofP = popen(command, "w");
134
135 if (ofP == NULL)
136 pm_asprintf(errorP,
137 "Failed to start shell to run command '%s'. "
138 "errno = %d (%s)",
139 command, errno, strerror(errno));
140 else {
141 int rc;
142
143 pipeOneImage(ifP, ofP);
144
145 rc = pclose(ofP);
146
147 if (check && rc != 0)
148 pm_asprintf(errorP, "Command '%s' terminated abnormally "
149 "or with nonzero exit status", command);
150 else
151 *errorP = NULL;
152 }
153 }
154
155
156
157 int
main(int argc,const char * argv[])158 main(int argc, const char *argv[]) {
159
160 struct cmdlineInfo cmdline;
161
162 FILE * ifP; /* Input file pointer */
163 int eof; /* No more images in input */
164 unsigned int imageSeq;
165 /* Sequence number of current image in input file. First = 0.
166 (Useful for tracking down problems).
167 */
168
169 pm_proginit(&argc, argv);
170
171 parseCommandLine(argc, argv, &cmdline);
172
173 ifP = pm_openr(cmdline.inputFileName);
174
175 for (eof = FALSE, imageSeq = 0; !eof; ++imageSeq) {
176 const char * error;
177
178 doOneImage(ifP, cmdline.command, cmdline.check, &error);
179
180 if (error) {
181 pm_error("Failed on image %u: %s", imageSeq, error);
182 pm_strfree(error);
183 }
184
185 pnm_nextimage(ifP, &eof);
186 }
187 pm_close(ifP);
188
189 return 0;
190 }
191
192
193
194