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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rsplit.c,v 1.15 2020/04/05 15:07:09 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 int swapped = 0; /* input is byte-swapped */
23
24 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
34 int nfiles = 0; /* output file count */
35
36 RESOLU ourres = {PIXSTANDARD, 0, 0};
37
38 char buf[16384]; /* input buffer used in scanOK() */
39
40
41 /* process header line */
42 int
43 headline(char *s, void *p)
44 {
45 extern const char FMTSTR[];
46 int i;
47
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 if ((i = isbigendian(s)) >= 0) {
57 swapped = (nativebigendian() != i);
58 return(0);
59 }
60 i = nfiles;
61 while (i--) /* else copy line to output streams */
62 if (rofile[i].hdrflags & DOHEADER)
63 fputs(s, rofile[i].output);
64 return(1);
65 }
66
67
68 /* scan field into buffer up to and including terminating byte */
69 int
70 scanOK(int termc)
71 {
72 int skip_white = (termc == ' ');
73 char *cp = buf;
74 int c;
75
76 while ((c = getchar()) != EOF) {
77 if (skip_white && isspace(c))
78 continue;
79 skip_white = 0;
80 if (c == '\n' && isspace(termc))
81 c = termc; /* forgiving assumption */
82 *cp++ = c;
83 if (cp-buf >= sizeof(buf))
84 break;
85 if ((termc == ' ') ? isspace(c) : (c == termc)) {
86 *cp = '\0';
87 return(cp-buf);
88 }
89 }
90 return(0);
91 }
92
93
94 int
95 main(int argc, char *argv[])
96 {
97 int inpflags = 0;
98 int needres = 0;
99 int force = 0;
100 int append = 0;
101 long outcnt = 0;
102 int bininp = 0;
103 int nstdoutcomp = 0;
104 int curterm = '\n';
105 int curncomp = 1;
106 int curbytes = 0;
107 int curflags = 0;
108 const char *curfmt = "ascii";
109 int i;
110
111 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 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 if (!curterm) curterm = '\n';
123 break;
124 case 'i':
125 switch (argv[i][2]) {
126 case 'h':
127 inpflags ^= DOHEADER;
128 break;
129 case 'H':
130 inpflags ^= DORESOLU;
131 break;
132 default:
133 goto badopt;
134 }
135 break;
136 case 'f':
137 force = !force;
138 break;
139 case 'a':
140 append = !append;
141 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 curbytes = 0;
182 break;
183 default:
184 goto badopt;
185 }
186 curncomp = isdigit(argv[i][3]) ?
187 atoi(argv[i]+3) : 1 ;
188 if (curbytes*curncomp > (int)sizeof(buf)) {
189 fputs(argv[0], stderr);
190 fputs(": output size too big\n", stderr);
191 return(1);
192 }
193 bininp += (curbytes > 0);
194 break;
195 case '\0': /* stdout */
196 if (!nstdoutcomp) { /* first use? */
197 needres |= (curflags & DORESOLU);
198 rofile[nfiles].hdrflags = curflags;
199 }
200 rofile[nfiles].output = stdout;
201 if (curbytes > 0)
202 SET_FILE_BINARY(rofile[nfiles].output);
203 rofile[nfiles].termc = curterm;
204 rofile[nfiles].format = curfmt;
205 nstdoutcomp +=
206 rofile[nfiles].ncomp = curncomp;
207 rofile[nfiles].bytsiz = curbytes;
208 rofile[nfiles++].outspec = argv[i];
209 break;
210 badopt:;
211 default:
212 fputs(argv[0], stderr);
213 fputs(": bad option\n", stderr);
214 return(1);
215 }
216 } else if (argv[i][0] == '.' && !argv[i][1]) {
217 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 } else if (argv[i][0] == '!') {
224 needres |= (curflags & DORESOLU);
225 rofile[nfiles].hdrflags = curflags;
226 rofile[nfiles].termc = curterm;
227 if ((rofile[nfiles].output = popen(argv[i]+1, "w")) == NULL) {
228 fputs(argv[i], stderr);
229 fputs(": cannot start command\n", stderr);
230 return(1);
231 }
232 if (curbytes > 0)
233 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 } else {
239 int j = nfiles;
240 while (j--) /* check duplicates */
241 if (!strcmp(argv[i], rofile[j].outspec)) {
242 fputs(argv[0], stderr);
243 fputs(": duplicate output: ", stderr);
244 fputs(argv[i], stderr);
245 fputc('\n', stderr);
246 return(1);
247 }
248 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 rofile[nfiles].hdrflags = curflags;
256 rofile[nfiles].termc = curterm;
257 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 rofile[nfiles].output = fopen(argv[i], append ? "a" : "w");
264 if (!rofile[nfiles].output) {
265 fputs(argv[i], stderr);
266 fputs(": cannot open for output\n", stderr);
267 return(1);
268 }
269 if (curbytes > 0)
270 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 }
276 }
277 if (!nfiles) {
278 fputs(argv[0], stderr);
279 fputs(": no output streams\n", stderr);
280 return(1);
281 } /* 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 }
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 if (rofile[i].output != NULL)
294 ftrylockfile(rofile[i].output);
295 #endif
296 /* load/copy header */
297 if (inpflags & DOHEADER && getheader(stdin, headline, NULL) < 0) {
298 fputs(argv[0], stderr);
299 fputs(": cannot read header from standard input\n",
300 stderr);
301 return(1);
302 }
303 /* handle resolution string */
304 if (inpflags & DORESOLU && !fgetsresolu(&ourres, stdin)) {
305 fputs(argv[0], stderr);
306 fputs(": bad resolution string on standard input\n", stderr);
307 return(1);
308 }
309 if (needres && (ourres.xr <= 0) | (ourres.yr <= 0)) {
310 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 if (rofile[i].hdrflags & DOHEADER) {
325 if (!(inpflags & DOHEADER))
326 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 extern const char BIGEND[];
332 if (rofile[i].bytsiz > 1) {
333 fputs(BIGEND, rofile[i].output);
334 fputs(nativebigendian() ^ swapped ?
335 "1\n" : "0\n", rofile[i].output);
336 }
337 fputformat(rofile[i].format, rofile[i].output);
338 }
339 fputc('\n', rofile[i].output);
340 }
341 if (rofile[i].hdrflags & DORESOLU)
342 fputsresolu(&ourres, rofile[i].output);
343 }
344 do { /* main loop */
345 for (i = 0; i < nfiles; i++) {
346 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 break;
354 } else if (rofile[i].ncomp > 1) { /* N-field output */
355 int n = rofile[i].ncomp;
356 while (n--) {
357 if (!scanOK(rofile[i].termc))
358 break;
359 if (rofile[i].output != NULL &&
360 fputs(buf, rofile[i].output) == EOF)
361 break;
362 }
363 if (n >= 0) /* fell short? */
364 break;
365 if ((rofile[i].output != NULL) & /* add EOL if none */
366 (rofile[i].termc != '\n'))
367 fputc('\n', rofile[i].output);
368 } else { /* 1-field output */
369 if (!scanOK(rofile[i].termc))
370 break;
371 if (rofile[i].output != NULL) {
372 if (fputs(buf, rofile[i].output) == EOF)
373 break;
374 if (rofile[i].termc != '\n') /* add EOL? */
375 fputc('\n', rofile[i].output);
376 }
377 }
378 /* skip input EOL? */
379 if (!bininp && rofile[nfiles-1].termc != '\n') {
380 int c = getchar();
381 if ((c != '\n') & (c != EOF))
382 ungetc(c, stdin);
383 }
384 }
385 if (i < nfiles)
386 break;
387 } while (--outcnt);
388 /* check ending */
389 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 if (outcnt > 0) {
395 fputs(argv[0], stderr);
396 fputs(": warning: premature EOD\n", stderr);
397 }
398 return(0);
399 }