ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rsplit.c
Revision: 1.17
Committed: Fri Jun 7 20:26:53 2024 UTC (10 months, 3 weeks ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.16: +2 -4 lines
Log Message:
perf(rsplit): truly minor optimization (possible struct size reduction)

File Contents

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