ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rsplit.c
Revision: 1.16
Committed: Fri Jun 7 18:19:22 2024 UTC (10 months, 3 weeks ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.15: +99 -90 lines
Log Message:
feature(rsplit,rlam): Modified to allow any number of files up to system limit

File Contents

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