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, 1 month 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

# User Rev Content
1 greg 1.1 #ifndef lint
2 greg 1.15 static const char RCSid[] = "$Id: rsplit.c,v 1.14 2020/04/05 02:25:22 greg Exp $";
3 greg 1.1 #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 greg 1.6 #include "rtio.h"
13 greg 1.1 #include "platform.h"
14 greg 1.9 #include "paths.h"
15 greg 1.1 #include "resolu.h"
16    
17     #define DOHEADER 1
18     #define DORESOLU 2
19    
20     #define MAXFILE 512 /* maximum number of files */
21    
22 greg 1.10 static int swapped = 0; /* input is byte-swapped */
23    
24 greg 1.7 static FILE *output[MAXFILE];
25 greg 1.12 static int ncomp[MAXFILE];
26 greg 1.7 static int bytsiz[MAXFILE];
27 greg 1.12 static int hdrflags[MAXFILE];
28 greg 1.7 static const char *format[MAXFILE];
29     static int termc[MAXFILE];
30     static int nfiles = 0;
31 greg 1.1
32 greg 1.7 static RESOLU ourres = {PIXSTANDARD, 0, 0};
33 greg 1.1
34 greg 1.7 static char buf[16384]; /* input buffer used in scanOK() */
35 greg 1.1
36    
37     /* process header line */
38     static int
39     headline(char *s, void *p)
40     {
41     extern const char FMTSTR[];
42 greg 1.10 int i;
43 greg 1.1
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 greg 1.10 if ((i = isbigendian(s)) >= 0) {
53     swapped = (nativebigendian() != i);
54     return(0);
55     }
56     i = nfiles;
57 greg 1.1 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 greg 1.11 int skip_white = (termc == ' ');
69 greg 1.1 char *cp = buf;
70     int c;
71    
72     while ((c = getchar()) != EOF) {
73 greg 1.11 if (skip_white && isspace(c))
74     continue;
75     skip_white = 0;
76     if (c == '\n' && isspace(termc))
77     c = termc; /* forgiving assumption */
78 greg 1.1 *cp++ = c;
79     if (cp-buf >= sizeof(buf))
80     break;
81 greg 1.11 if ((termc == ' ') ? isspace(c) : (c == termc)) {
82 greg 1.1 *cp = '\0';
83     return(cp-buf);
84     }
85     }
86     return(0);
87     }
88    
89    
90     int
91     main(int argc, char *argv[])
92     {
93 greg 1.8 int inpflags = 0;
94     int needres = 0;
95 greg 1.1 int force = 0;
96     int append = 0;
97     long outcnt = 0;
98     int bininp = 0;
99 greg 1.14 int nstdoutcomp = 0;
100 greg 1.1 int curterm = '\n';
101 greg 1.12 int curncomp = 1;
102 greg 1.1 int curbytes = 0;
103     int curflags = 0;
104     const char *curfmt = "ascii";
105 greg 1.15 short outndx[MAXFILE];
106     int i;
107 greg 1.1
108 greg 1.15 memset(outndx, 0, sizeof(outndx));
109 greg 1.1 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 greg 1.5 if (!curterm) curterm = '\n';
115 greg 1.1 break;
116     case 'i':
117     switch (argv[i][2]) {
118     case 'h':
119 greg 1.8 inpflags ^= DOHEADER;
120 greg 1.1 break;
121     case 'H':
122 greg 1.8 inpflags ^= DORESOLU;
123 greg 1.1 break;
124     default:
125     goto badopt;
126     }
127     break;
128     case 'f':
129 greg 1.8 force = !force;
130 greg 1.1 break;
131     case 'a':
132 greg 1.8 append = !append;
133 greg 1.1 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 greg 1.12 curbytes = 0;
174 greg 1.1 break;
175     default:
176     goto badopt;
177     }
178 greg 1.12 curncomp = isdigit(argv[i][3]) ?
179     atoi(argv[i]+3) : 1 ;
180     if (curbytes*curncomp > (int)sizeof(buf)) {
181 greg 1.1 fputs(argv[0], stderr);
182     fputs(": output size too big\n", stderr);
183     return(1);
184     }
185 greg 1.7 bininp += (curbytes > 0);
186 greg 1.1 break;
187 greg 1.14 case '\0': /* stdout */
188     if (!nstdoutcomp) { /* first use? */
189     needres |= (curflags & DORESOLU);
190     hdrflags[nfiles] = curflags;
191     }
192 greg 1.1 output[nfiles] = stdout;
193     if (curbytes > 0)
194     SET_FILE_BINARY(output[nfiles]);
195 greg 1.14 termc[nfiles] = curterm;
196 greg 1.1 format[nfiles] = curfmt;
197 greg 1.14 nstdoutcomp +=
198     ncomp[nfiles] = curncomp;
199 greg 1.15 bytsiz[nfiles] = curbytes;
200     outndx[nfiles++] = i;
201 greg 1.1 break;
202     badopt:;
203     default:
204     fputs(argv[0], stderr);
205     fputs(": bad option\n", stderr);
206     return(1);
207     }
208 greg 1.13 } 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 greg 1.15 bytsiz[nfiles] = curbytes;
214     outndx[nfiles++] = i;
215 greg 1.1 } else if (argv[i][0] == '!') {
216 greg 1.8 needres |= (curflags & DORESOLU);
217 greg 1.14 hdrflags[nfiles] = curflags;
218 greg 1.1 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 greg 1.12 ncomp[nfiles] = curncomp;
228 greg 1.15 bytsiz[nfiles] = curbytes;
229     outndx[nfiles++] = i;
230 greg 1.1 } else {
231 greg 1.15 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 greg 1.8 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 greg 1.14 hdrflags[nfiles] = curflags;
248 greg 1.1 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 greg 1.12 ncomp[nfiles] = curncomp;
265 greg 1.15 bytsiz[nfiles] = curbytes;
266     outndx[nfiles++] = i;
267 greg 1.1 }
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 greg 1.13 if (output[i] != NULL)
285 greg 1.14 ftrylockfile(output[i]);
286 greg 1.1 #endif
287     /* load/copy header */
288 greg 1.8 if (inpflags & DOHEADER && getheader(stdin, headline, NULL) < 0) {
289 greg 1.1 fputs(argv[0], stderr);
290 greg 1.14 fputs(": cannot read header from standard input\n",
291 greg 1.1 stderr);
292     return(1);
293     }
294     /* handle resolution string */
295 greg 1.8 if (inpflags & DORESOLU && !fgetsresolu(&ourres, stdin)) {
296 greg 1.1 fputs(argv[0], stderr);
297 greg 1.14 fputs(": bad resolution string on standard input\n", stderr);
298 greg 1.1 return(1);
299     }
300 greg 1.8 if (needres && (ourres.xr <= 0) | (ourres.yr <= 0)) {
301 greg 1.1 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 greg 1.8 if (!(inpflags & DOHEADER))
317 greg 1.1 newheader("RADIANCE", output[i]);
318     printargs(argc, argv, output[i]);
319 greg 1.14 fprintf(output[i], "NCOMP=%d\n", output[i]==stdout ?
320     nstdoutcomp : ncomp[i]);
321 greg 1.10 if (format[i] != NULL) {
322     extern const char BIGEND[];
323 greg 1.15 if (bytsiz[i] > 1) {
324 greg 1.10 fputs(BIGEND, output[i]);
325     fputs(nativebigendian() ^ swapped ?
326     "1\n" : "0\n", output[i]);
327     }
328 greg 1.1 fputformat(format[i], output[i]);
329 greg 1.10 }
330 greg 1.1 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 greg 1.12 if (getbinary(buf, bytsiz[i], ncomp[i],
339     stdin) < ncomp[i])
340 greg 1.1 break;
341 greg 1.13 if (output[i] != NULL &&
342     putbinary(buf, bytsiz[i], ncomp[i],
343 greg 1.12 output[i]) < ncomp[i])
344 greg 1.4 break;
345 greg 1.12 } else if (ncomp[i] > 1) { /* N-field output */
346     int n = ncomp[i];
347 greg 1.1 while (n--) {
348     if (!scanOK(termc[i]))
349     break;
350 greg 1.13 if (output[i] != NULL &&
351     fputs(buf, output[i]) == EOF)
352 greg 1.4 break;
353 greg 1.1 }
354     if (n >= 0) /* fell short? */
355     break;
356 greg 1.13 if ((output[i] != NULL) & /* add EOL if none */
357     (termc[i] != '\n'))
358 greg 1.4 fputc('\n', output[i]);
359 greg 1.1 } else { /* 1-field output */
360     if (!scanOK(termc[i]))
361     break;
362 greg 1.13 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 greg 1.1 }
369 greg 1.7 /* 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 greg 1.1 }
376     if (i < nfiles)
377     break;
378     } while (--outcnt);
379 greg 1.2 /* check ending */
380 greg 1.3 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 greg 1.4 if (outcnt > 0) {
386     fputs(argv[0], stderr);
387     fputs(": warning: premature EOD\n", stderr);
388     }
389 greg 1.1 return(0);
390     }