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 (2 days, 22 hours 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

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