ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rsplit.c
Revision: 1.15
Committed: Sun Apr 5 15:07:09 2020 UTC (4 years ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4, rad5R3, HEAD
Changes since 1.14: +22 -7 lines
Log Message:
Added check for duplicate output file(s)

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rsplit.c,v 1.14 2020/04/05 02:25:22 greg Exp $";
3 #endif
4 /*
5 * rsplit.c - split input into multiple output streams
6 *
7 * 7/4/19 Greg Ward
8 */
9
10 #include <ctype.h>
11
12 #include "rtio.h"
13 #include "platform.h"
14 #include "paths.h"
15 #include "resolu.h"
16
17 #define DOHEADER 1
18 #define DORESOLU 2
19
20 #define MAXFILE 512 /* maximum number of files */
21
22 static int swapped = 0; /* input is byte-swapped */
23
24 static FILE *output[MAXFILE];
25 static int ncomp[MAXFILE];
26 static int bytsiz[MAXFILE];
27 static int hdrflags[MAXFILE];
28 static const char *format[MAXFILE];
29 static int termc[MAXFILE];
30 static int nfiles = 0;
31
32 static RESOLU ourres = {PIXSTANDARD, 0, 0};
33
34 static char buf[16384]; /* input buffer used in scanOK() */
35
36
37 /* process header line */
38 static int
39 headline(char *s, void *p)
40 {
41 extern const char FMTSTR[];
42 int i;
43
44 if (strstr(s, FMTSTR) == s)
45 return(0); /* don't copy format */
46 if (!strncmp(s, "NROWS=", 6))
47 return(0);
48 if (!strncmp(s, "NCOLS=", 6))
49 return(0);
50 if (!strncmp(s, "NCOMP=", 6))
51 return(0);
52 if ((i = isbigendian(s)) >= 0) {
53 swapped = (nativebigendian() != i);
54 return(0);
55 }
56 i = nfiles;
57 while (i--) /* else copy line to output streams */
58 if (hdrflags[i] & DOHEADER)
59 fputs(s, output[i]);
60 return(1);
61 }
62
63
64 /* scan field into buffer up to and including terminating byte */
65 static int
66 scanOK(int termc)
67 {
68 int skip_white = (termc == ' ');
69 char *cp = buf;
70 int c;
71
72 while ((c = getchar()) != EOF) {
73 if (skip_white && isspace(c))
74 continue;
75 skip_white = 0;
76 if (c == '\n' && isspace(termc))
77 c = termc; /* forgiving assumption */
78 *cp++ = c;
79 if (cp-buf >= sizeof(buf))
80 break;
81 if ((termc == ' ') ? isspace(c) : (c == termc)) {
82 *cp = '\0';
83 return(cp-buf);
84 }
85 }
86 return(0);
87 }
88
89
90 int
91 main(int argc, char *argv[])
92 {
93 int inpflags = 0;
94 int needres = 0;
95 int force = 0;
96 int append = 0;
97 long outcnt = 0;
98 int bininp = 0;
99 int nstdoutcomp = 0;
100 int curterm = '\n';
101 int curncomp = 1;
102 int curbytes = 0;
103 int curflags = 0;
104 const char *curfmt = "ascii";
105 short outndx[MAXFILE];
106 int i;
107
108 memset(outndx, 0, sizeof(outndx));
109 for (i = 1; i < argc; i++) {
110 if (argv[i][0] == '-') {
111 switch (argv[i][1]) {
112 case 't':
113 curterm = argv[i][2];
114 if (!curterm) curterm = '\n';
115 break;
116 case 'i':
117 switch (argv[i][2]) {
118 case 'h':
119 inpflags ^= DOHEADER;
120 break;
121 case 'H':
122 inpflags ^= DORESOLU;
123 break;
124 default:
125 goto badopt;
126 }
127 break;
128 case 'f':
129 force = !force;
130 break;
131 case 'a':
132 append = !append;
133 break;
134 case 'x':
135 ourres.xr = atoi(argv[++i]);
136 break;
137 case 'y':
138 ourres.yr = atoi(argv[++i]);
139 break;
140 case 'o':
141 switch (argv[i][2]) {
142 case 'n':
143 outcnt = atol(argv[++i]);
144 continue;
145 case 'h':
146 curflags ^= DOHEADER;
147 continue;
148 case 'H':
149 curflags ^= DORESOLU;
150 continue;
151 case 'f':
152 curfmt = "float";
153 curbytes = sizeof(float);
154 break;
155 case 'd':
156 curfmt = "double";
157 curbytes = sizeof(double);
158 break;
159 case 'i':
160 curfmt = "int";
161 curbytes = sizeof(int);
162 break;
163 case 'w':
164 curfmt = "16-bit";
165 curbytes = 2;
166 break;
167 case 'b':
168 curfmt = "byte";
169 curbytes = 1;
170 break;
171 case 'a':
172 curfmt = "ascii";
173 curbytes = 0;
174 break;
175 default:
176 goto badopt;
177 }
178 curncomp = isdigit(argv[i][3]) ?
179 atoi(argv[i]+3) : 1 ;
180 if (curbytes*curncomp > (int)sizeof(buf)) {
181 fputs(argv[0], stderr);
182 fputs(": output size too big\n", stderr);
183 return(1);
184 }
185 bininp += (curbytes > 0);
186 break;
187 case '\0': /* stdout */
188 if (!nstdoutcomp) { /* first use? */
189 needres |= (curflags & DORESOLU);
190 hdrflags[nfiles] = curflags;
191 }
192 output[nfiles] = stdout;
193 if (curbytes > 0)
194 SET_FILE_BINARY(output[nfiles]);
195 termc[nfiles] = curterm;
196 format[nfiles] = curfmt;
197 nstdoutcomp +=
198 ncomp[nfiles] = curncomp;
199 bytsiz[nfiles] = curbytes;
200 outndx[nfiles++] = i;
201 break;
202 badopt:;
203 default:
204 fputs(argv[0], stderr);
205 fputs(": bad option\n", stderr);
206 return(1);
207 }
208 } else if (argv[i][0] == '.' && !argv[i][1]) {
209 output[nfiles] = NULL; /* discard data */
210 termc[nfiles] = curterm;
211 format[nfiles] = curfmt;
212 ncomp[nfiles] = curncomp;
213 bytsiz[nfiles] = curbytes;
214 outndx[nfiles++] = i;
215 } else if (argv[i][0] == '!') {
216 needres |= (curflags & DORESOLU);
217 hdrflags[nfiles] = curflags;
218 termc[nfiles] = curterm;
219 if ((output[nfiles] = popen(argv[i]+1, "w")) == NULL) {
220 fputs(argv[i], stderr);
221 fputs(": cannot start command\n", stderr);
222 return(1);
223 }
224 if (curbytes > 0)
225 SET_FILE_BINARY(output[nfiles]);
226 format[nfiles] = curfmt;
227 ncomp[nfiles] = curncomp;
228 bytsiz[nfiles] = curbytes;
229 outndx[nfiles++] = i;
230 } else {
231 int j = nfiles;
232 while (j--) /* check duplicates */
233 if (!strcmp(argv[i], argv[outndx[j]])) {
234 fputs(argv[0], stderr);
235 fputs(": duplicate output: ", stderr);
236 fputs(argv[i], stderr);
237 fputc('\n', stderr);
238 return(1);
239 }
240 if (append & (curflags != 0)) {
241 fputs(argv[0], stderr);
242 fputs(": -a option incompatible with -oh and -oH\n",
243 stderr);
244 return(1);
245 }
246 needres |= (curflags & DORESOLU);
247 hdrflags[nfiles] = curflags;
248 termc[nfiles] = curterm;
249 if (!append & !force && access(argv[i], F_OK) == 0) {
250 fputs(argv[i], stderr);
251 fputs(": file exists -- use -f to overwrite\n",
252 stderr);
253 return(1);
254 }
255 output[nfiles] = fopen(argv[i], append ? "a" : "w");
256 if (output[nfiles] == NULL) {
257 fputs(argv[i], stderr);
258 fputs(": cannot open for output\n", stderr);
259 return(1);
260 }
261 if (curbytes > 0)
262 SET_FILE_BINARY(output[nfiles]);
263 format[nfiles] = curfmt;
264 ncomp[nfiles] = curncomp;
265 bytsiz[nfiles] = curbytes;
266 outndx[nfiles++] = i;
267 }
268 if (nfiles >= MAXFILE) {
269 fputs(argv[0], stderr);
270 fputs(": too many output streams\n", stderr);
271 return(1);
272 }
273 }
274 if (!nfiles) {
275 fputs(argv[0], stderr);
276 fputs(": no output streams\n", stderr);
277 return(1);
278 }
279 if (bininp) /* binary input? */
280 SET_FILE_BINARY(stdin);
281 #ifdef getc_unlocked /* avoid lock/unlock overhead */
282 flockfile(stdin);
283 for (i = nfiles; i--; )
284 if (output[i] != NULL)
285 ftrylockfile(output[i]);
286 #endif
287 /* load/copy header */
288 if (inpflags & DOHEADER && getheader(stdin, headline, NULL) < 0) {
289 fputs(argv[0], stderr);
290 fputs(": cannot read header from standard input\n",
291 stderr);
292 return(1);
293 }
294 /* handle resolution string */
295 if (inpflags & DORESOLU && !fgetsresolu(&ourres, stdin)) {
296 fputs(argv[0], stderr);
297 fputs(": bad resolution string on standard input\n", stderr);
298 return(1);
299 }
300 if (needres && (ourres.xr <= 0) | (ourres.yr <= 0)) {
301 fputs(argv[0], stderr);
302 fputs(": -oH option requires -iH or -x and -y options\n", stderr);
303 return(1);
304 }
305 if ((ourres.xr > 0) & (ourres.yr > 0)) {
306 if (outcnt <= 0) {
307 outcnt = ourres.xr * ourres.yr;
308 } else if (outcnt != ourres.xr*ourres.yr) {
309 fputs(argv[0], stderr);
310 fputs(": warning: -on option does not agree with resolution\n",
311 stderr);
312 }
313 }
314 for (i = 0; i < nfiles; i++) { /* complete headers */
315 if (hdrflags[i] & DOHEADER) {
316 if (!(inpflags & DOHEADER))
317 newheader("RADIANCE", output[i]);
318 printargs(argc, argv, output[i]);
319 fprintf(output[i], "NCOMP=%d\n", output[i]==stdout ?
320 nstdoutcomp : ncomp[i]);
321 if (format[i] != NULL) {
322 extern const char BIGEND[];
323 if (bytsiz[i] > 1) {
324 fputs(BIGEND, output[i]);
325 fputs(nativebigendian() ^ swapped ?
326 "1\n" : "0\n", output[i]);
327 }
328 fputformat(format[i], output[i]);
329 }
330 fputc('\n', output[i]);
331 }
332 if (hdrflags[i] & DORESOLU)
333 fputsresolu(&ourres, output[i]);
334 }
335 do { /* main loop */
336 for (i = 0; i < nfiles; i++) {
337 if (bytsiz[i] > 0) { /* binary output */
338 if (getbinary(buf, bytsiz[i], ncomp[i],
339 stdin) < ncomp[i])
340 break;
341 if (output[i] != NULL &&
342 putbinary(buf, bytsiz[i], ncomp[i],
343 output[i]) < ncomp[i])
344 break;
345 } else if (ncomp[i] > 1) { /* N-field output */
346 int n = ncomp[i];
347 while (n--) {
348 if (!scanOK(termc[i]))
349 break;
350 if (output[i] != NULL &&
351 fputs(buf, output[i]) == EOF)
352 break;
353 }
354 if (n >= 0) /* fell short? */
355 break;
356 if ((output[i] != NULL) & /* add EOL if none */
357 (termc[i] != '\n'))
358 fputc('\n', output[i]);
359 } else { /* 1-field output */
360 if (!scanOK(termc[i]))
361 break;
362 if (output[i] != NULL) {
363 if (fputs(buf, output[i]) == EOF)
364 break;
365 if (termc[i] != '\n') /* add EOL? */
366 fputc('\n', output[i]);
367 }
368 }
369 /* skip input EOL? */
370 if (!bininp && termc[nfiles-1] != '\n') {
371 int c = getchar();
372 if ((c != '\n') & (c != EOF))
373 ungetc(c, stdin);
374 }
375 }
376 if (i < nfiles)
377 break;
378 } while (--outcnt);
379 /* check ending */
380 if (fflush(NULL) == EOF) {
381 fputs(argv[0], stderr);
382 fputs(": write error on one or more outputs\n", stderr);
383 return(1);
384 }
385 if (outcnt > 0) {
386 fputs(argv[0], stderr);
387 fputs(": warning: premature EOD\n", stderr);
388 }
389 return(0);
390 }