ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/header.c
Revision: 2.50
Committed: Fri Jun 6 19:11:21 2025 UTC (12 days, 17 hours ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.49: +16 -5 lines
Log Message:
refactor: Making use of printargs() more consistent with fixargv0()

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: header.c,v 2.49 2025/06/04 22:34:27 greg Exp $";
3 #endif
4 /*
5 * header.c - routines for reading and writing information headers.
6 *
7 * Externals declared in rtio.h
8 *
9 * newheader(t,fp) start new information header identified by string t
10 * headidval(r,s) copy header identifier value in s to r
11 * dateval(t,s) get capture date value as UTC
12 * gmtval(t,s) get GMT as UTC
13 * fputdate(t,fp) put out the given UTC
14 * fputnow(fp) put out the current date and time
15 * printargs(ac,av,fp) print an argument list to fp, followed by '\n'
16 * formatval(r,s) copy the format value in s to r
17 * fputformat(s,fp) write "FORMAT=%s" to fp
18 * nativebigendian() are we native on big-endian machine?
19 * isbigendian(s) header line matches "BigEndian=1" (-1 if irrelevant)
20 * fputendian(fp) write native endianness in BigEndian= line
21 * getheader(fp,f,p) read header from fp, calling f(s,p) on each line
22 * globmatch(pat, str) check for glob match of str against pat
23 * checkheader(i,p,o) check header format from i against p and copy to o
24 *
25 * To copy header from input to output, use getheader(fin, fputs, fout)
26 */
27
28 #include "copyright.h"
29
30 #include <ctype.h>
31
32 #include "tiff.h" /* for int32 */
33 #include "paths.h" /* for fixargv0() */
34 #include "rtio.h"
35 #include "color.h"
36 #include "resolu.h"
37
38 #define MAXLINE 2048
39
40 extern time_t timegm(struct tm *tm);
41
42 const char HDRSTR[] = "#?"; /* information header magic number */
43
44 const char FMTSTR[] = "FORMAT="; /* format identifier */
45
46 const char TMSTR[] = "CAPDATE="; /* capture date identifier */
47 const char GMTSTR[] = "GMT="; /* GMT identifier */
48
49 const char BIGEND[] = "BigEndian="; /* big-endian variable */
50
51 static gethfunc mycheck;
52
53
54 void
55 newheader( /* identifying line of information header */
56 const char *s,
57 FILE *fp
58 )
59 {
60 fputs(HDRSTR, fp);
61 fputs(s, fp);
62 fputc('\n', fp);
63 }
64
65
66 int
67 headidval( /* get header id (return true if is id) */
68 char *r,
69 const char *s
70 )
71 {
72 const char *cp = HDRSTR;
73
74 while (*cp) if (*cp++ != *s++) return(0);
75 if (r == NULL) return(1);
76 while (*s && !isspace(*s)) *r++ = *s++;
77 *r = '\0';
78 return(1);
79 }
80
81
82 int
83 dateval( /* convert capture date line to UTC */
84 time_t *tloc,
85 const char *s
86 )
87 {
88 struct tm tms;
89 const char *cp = TMSTR;
90
91 while (*cp) if (*cp++ != *s++) return(0);
92 while (isspace(*s)) s++;
93 if (!*s) return(0);
94 if (sscanf(s, "%d:%d:%d %d:%d:%d",
95 &tms.tm_year, &tms.tm_mon, &tms.tm_mday,
96 &tms.tm_hour, &tms.tm_min, &tms.tm_sec) != 6)
97 return(0);
98 if (tloc == NULL)
99 return(1);
100 tms.tm_mon--;
101 tms.tm_year -= 1900;
102 tms.tm_isdst = -1; /* ask mktime() to figure out DST */
103 *tloc = mktime(&tms);
104 return(1);
105 }
106
107
108 int
109 gmtval( /* convert GMT date line to UTC */
110 time_t *tloc,
111 const char *s
112 )
113 {
114 struct tm tms;
115 const char *cp = GMTSTR;
116
117 while (*cp) if (*cp++ != *s++) return(0);
118 while (isspace(*s)) s++;
119 if (!*s) return(0);
120 if (sscanf(s, "%d:%d:%d %d:%d:%d",
121 &tms.tm_year, &tms.tm_mon, &tms.tm_mday,
122 &tms.tm_hour, &tms.tm_min, &tms.tm_sec) != 6)
123 return(0);
124 if (tloc == NULL)
125 return(1);
126 tms.tm_mon--;
127 tms.tm_year -= 1900;
128 *tloc = timegm(&tms);
129 return(1);
130 }
131
132
133 void
134 fputdate( /* write out the given time value (local & GMT) */
135 time_t tv,
136 FILE *fp
137 )
138 {
139 struct tm *tms;
140
141 tms = localtime(&tv);
142 if (tms != NULL)
143 fprintf(fp, "%s %04d:%02d:%02d %02d:%02d:%02d\n", TMSTR,
144 tms->tm_year+1900, tms->tm_mon+1, tms->tm_mday,
145 tms->tm_hour, tms->tm_min, tms->tm_sec);
146 tms = gmtime(&tv);
147 if (tms != NULL)
148 fprintf(fp, "%s %04d:%02d:%02d %02d:%02d:%02d\n", GMTSTR,
149 tms->tm_year+1900, tms->tm_mon+1, tms->tm_mday,
150 tms->tm_hour, tms->tm_min, tms->tm_sec);
151 }
152
153
154 void
155 fputnow( /* write out the current time */
156 FILE *fp
157 )
158 {
159 time_t tv;
160 time(&tv);
161 fputdate(tv, fp);
162 }
163
164
165 void
166 printargs( /* print command arguments to a file */
167 int ac,
168 char **av,
169 FILE *fp
170 )
171 {
172 if (ac <= 0)
173 return;
174 if (progname == NULL)
175 fixargv0(av[0]); /* sets global progname */
176
177 if (progname >= av[0] && progname - av[0] < strlen(av[0]))
178 fputword(progname, fp);
179 else
180 fputword(av[0], fp);
181 while (--ac > 0) {
182 fputc(' ', fp);
183 fputword(*++av, fp);
184 }
185 fputc('\n', fp);
186 }
187
188
189 int
190 formatval( /* get format value (return true if format) */
191 char fmt[MAXFMTLEN],
192 const char *s
193 )
194 {
195 const char *cp = FMTSTR;
196 char *r = fmt;
197 /* check against format string */
198 while (*cp) if (*cp++ != *s++) return(0);
199 while (isspace(*s)) s++;
200 if (!*s) return(0);
201 if (r == NULL) /* just checking if format? */
202 return(1);
203 do /* copy format ID */
204 *r++ = *s++;
205 while (*s && r-fmt < MAXFMTLEN-1);
206
207 do /* remove trailing white space */
208 *r-- = '\0';
209 while (r > fmt && isspace(*r));
210
211 return(1);
212 }
213
214
215 void
216 fputformat( /* put out a format value */
217 const char *s,
218 FILE *fp
219 )
220 {
221 int align = 0;
222
223 fputs(FMTSTR, fp);
224 fputs(s, fp);
225 /* pad to align binary type for mmap() */
226 if (globmatch(PICFMT, s))
227 align = 0; /* not needed for picture data */
228 else if (!strncmp("float", s, 5))
229 align = sizeof(float);
230 else if (!strncmp("double", s, 6))
231 align = sizeof(double);
232 else if (!strncmp("16-bit", s, 6))
233 align = 2;
234 else if (!strncmp("32-bit", s, 6))
235 align = 4;
236 else if (!strncmp("64-bit", s, 6))
237 align = 8;
238 if (align) {
239 long pos = ftell(fp);
240 if (pos >= 0) {
241 pos = (pos + 2) % align;
242 if (pos) align -= pos;
243 else align = 0;
244 } else
245 align = 0;
246 }
247 while (align-- > 0)
248 putc(' ', fp);
249 fputc('\n', fp);
250 }
251
252
253 int
254 nativebigendian() /* are we native on a big-endian machine? */
255 {
256 union { int32 i; char c[4]; } u;
257
258 u.i = 1;
259
260 return(u.c[0] == 0);
261 }
262
263
264 int
265 isbigendian( /* header line says "BigEndian=1" (-1 if irrelevant) */
266 const char *s
267 )
268 {
269 const char *be = BIGEND;
270
271 while ((*s != '\0') & (*be != '=') && *s++ == *be)
272 ++be;
273 if (*be != '=')
274 return(-1); /* irrelevant */
275 while (isspace(*s))
276 s++;
277 if (*s++ != '=')
278 return(-1);
279 while (isspace(*s))
280 s++;
281 return(*s == '1');
282 }
283
284
285 void
286 fputendian( /* write native endianness in BigEndian= line */
287 FILE *fp
288 )
289 {
290 fputs(BIGEND, fp);
291 if (nativebigendian())
292 fputs("1\n", fp);
293 else
294 fputs("0\n", fp);
295 }
296
297
298 int
299 getheader( /* get header from file */
300 FILE *fp,
301 gethfunc *f,
302 void *p
303 )
304 {
305 int rtotal = 0;
306 char buf[MAXLINE];
307 int firstc = fgetc(fp);
308
309 if (!isprint(firstc))
310 return(-1); /* messed up */
311 ungetc(firstc, fp);
312 for ( ; ; ) {
313 int rval = 0;
314 buf[MAXLINE-2] = '\n';
315 if (fgets(buf, MAXLINE, fp) == NULL)
316 return(-1);
317 if (buf[buf[0]=='\r'] == '\n') /* end of header? */
318 return(rtotal);
319 if (buf[MAXLINE-2] != '\n') {
320 ungetc(buf[MAXLINE-2], fp); /* prevent false end */
321 buf[MAXLINE-2] = '\0';
322 }
323 if (f != NULL && (rval = (*f)(buf, p)) < 0)
324 return(-1);
325 rtotal += rval;
326 }
327 }
328
329
330 struct check {
331 FILE *fp;
332 char fs[MAXFMTLEN];
333 };
334
335
336 static int
337 mycheck( /* check a header line for format info. */
338 char *s,
339 void *cp
340 )
341 {
342 struct check *scp = (struct check *)cp;
343
344 if (!formatval(scp->fs, s) && scp->fp != NULL)
345 return(fputs(s, scp->fp));
346
347 return(0);
348 }
349
350
351 int
352 globmatch( /* check for match of s against pattern p */
353 const char *p,
354 const char *s
355 )
356 {
357 int setmatch;
358
359 do {
360 switch (*p) {
361 case '?': /* match any character */
362 if (!*s++)
363 return(0);
364 break;
365 case '*': /* match any string */
366 while (p[1] == '*') p++;
367 do
368 if ( (p[1]=='?') | (p[1]==*s) &&
369 globmatch(p+1,s) )
370 return(1);
371 while (*s++);
372 return(0);
373 case '[': /* character set */
374 setmatch = (*s == *++p);
375 if (!*p)
376 return(0);
377 while (*++p != ']') {
378 if (!*p)
379 return(0);
380 if (*p == '-') {
381 setmatch += (p[-1] <= *s) & (*s <= p[1]);
382 if (!*++p)
383 break;
384 } else
385 setmatch += (*p == *s);
386 }
387 if (!setmatch)
388 return(0);
389 s++;
390 break;
391 case '\\': /* literal next */
392 if (!*++p)
393 return(0);
394 /* fall through */
395 default: /* normal character */
396 if (*p != *s)
397 return(0);
398 s++;
399 break;
400 }
401 } while (*p++);
402 return(1);
403 }
404
405
406 /*
407 * Checkheader(fin,fmt,fout) returns a value of 1 if the input format
408 * matches the specification in fmt, 0 if no input format was found,
409 * and -1 if the input format does not match or there is an
410 * error reading the header. If fmt is empty, then -1 is returned
411 * if any input format is found (or there is an error), and 0 otherwise.
412 * If fmt contains any '*' or '?' characters, then checkheader
413 * does wildcard expansion and copies a matching result into fmt.
414 * Be sure that fmt is big enough to hold the match in such cases,
415 * and that it is not a static, read-only string!
416 * The input header (minus any format lines) is copied to fout
417 * if fout is not NULL.
418 */
419
420 int
421 checkheader(
422 FILE *fin,
423 char fmt[MAXFMTLEN],
424 FILE *fout
425 )
426 {
427 struct check cdat;
428 char *cp;
429
430 cdat.fp = fout;
431 cdat.fs[0] = '\0';
432 if (getheader(fin, mycheck, &cdat) < 0)
433 return(-1);
434 if (!cdat.fs[0])
435 return(0);
436 for (cp = fmt; *cp; cp++) /* check for globbing */
437 if ((*cp == '?') | (*cp == '*')) {
438 if (globmatch(fmt, cdat.fs)) {
439 strcpy(fmt, cdat.fs);
440 return(1);
441 } else
442 return(-1);
443 }
444 return(strcmp(fmt, cdat.fs) ? -1 : 1); /* literal match */
445 }