ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/wrapBSDF.c
Revision: 2.2
Committed: Wed Feb 11 19:38:18 2015 UTC (9 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.1: +48 -28 lines
Log Message:
Numerous bug fixes, but still untested

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.2 static const char RCSid[] = "$Id: wrapBSDF.c,v 2.1 2015/02/11 18:08:10 greg Exp $";
3 greg 2.1 #endif
4     /*
5 greg 2.2 * Wrap BSDF data in valid WINDOW XML file
6 greg 2.1 *
7 greg 2.2 * G. Ward February 2015
8 greg 2.1 */
9    
10     #include <ctype.h>
11     #include "rtio.h"
12     #include "rtprocess.h"
13     #include "ezxml.h"
14     #include "bsdf.h"
15     #include "bsdf_m.h"
16     /* XML template file names */
17     const char def_template[] = "minimalBSDFt.xml";
18     const char win6_template[] = "window6BSDFt.xml";
19    
20     const char stdin_name[] = "<stdin>";
21    
22     /* input files (can be stdin_name) */
23     const char *xml_input = NULL;
24     /* unit for materials & geometry */
25 greg 2.2 const char *attr_unit = "meter";
26 greg 2.1 const char legal_units[] = "meter|foot|inch|centimeter|millimeter";
27     /* system materials & geometry */
28     const char *mgf_geometry = NULL;
29    
30     /* angle basis */
31     enum { ABdefault=-1, ABklemsFull=0, ABklemsHalf, ABklemsQuarter,
32     ABtensorTree3, ABtensorTree4, ABend };
33    
34     int angle_basis = ABdefault;
35    
36     /* field IDs and nicknames */
37     struct s_fieldID {
38     char nickName[4];
39     int has_unit;
40     const char *fullName;
41     } XMLfieldID[] = {
42     {"m", 0, "Manufacturer"},
43     {"n", 0, "Name"},
44     {"c", 0, "ThermalConductivity"},
45     {"ef", 0, "EmissivityFront"},
46     {"eb", 0, "EmissivityBack"},
47     {"tir", 0, "TIR"},
48     {"eo", 0, "EffectiveOpennessFraction"},
49     {"t", 1, "Thickness"},
50     {"h", 1, "Height"},
51     {"w", 1, "Width"},
52 greg 2.2 {"\0", 0, NULL} /* terminator */
53 greg 2.1 };
54     /* field assignments */
55     #define MAXASSIGN 12
56     const char *field_assignment[MAXASSIGN];
57     int nfield_assign = 0;
58     #define FASEP ';'
59    
60     /* data file(s) & spectra */
61     enum { DTtransForward, DTtransBackward, DTreflForward, DTreflBackward };
62    
63     enum { DSsolar=-1, DSnir=-2, DSxbar31=-3, DSvisible=-4, DSzbar31=-5 };
64    
65     #define MAXFILES 20
66    
67     struct s_dfile {
68     const char *fname; /* input data file name */
69     short type; /* BSDF data type */
70     short spectrum; /* BSDF sensor spectrum */
71     } data_file[MAXFILES];
72    
73     int ndataf = 0; /* number of data files */
74    
75     const char *spectr_file[MAXFILES]; /* custom spectral curve input */
76    
77     const char top_level_name[] = "WindowElement";
78    
79     static char *basis_definition[] = {
80    
81     "\t\t<IncidentDataStructure>Columns</IncidentDataStructure>\n"
82     "\t\t<AngleBasis>\n"
83     "\t\t\t<AngleBasisName>LBNL/Klems Full</AngleBasisName>\n"
84     "\t\t</AngleBasis>\n",
85    
86     "\t\t<IncidentDataStructure>Columns</IncidentDataStructure>\n"
87     "\t\t<AngleBasis>\n"
88     "\t\t\t<AngleBasisName>LBNL/Klems Half</AngleBasisName>\n"
89     "\t\t</AngleBasis>\n",
90    
91     "\t\t<IncidentDataStructure>Columns</IncidentDataStructure>\n"
92     "\t\t<AngleBasis>\n"
93     "\t\t\t<AngleBasisName>LBNL/Klems Quarter</AngleBasisName>\n"
94     "\t\t</AngleBasis>\n",
95    
96     "\t\t<IncidentDataStructure>TensorTree3</IncidentDataStructure>\n",
97    
98     "\t\t<IncidentDataStructure>TensorTree4</IncidentDataStructure>\n",
99     };
100    
101     /* Copy data from file descriptor to stdout and close */
102     static int
103     copy_and_close(int fd)
104     {
105     int ok = 1;
106     char buf[8192];
107     int n;
108    
109     if (fd < 0)
110     return 0;
111     while ((n = read(fd, buf, sizeof(buf))) > 0)
112     if (write(fileno(stdout), buf, n) != n) {
113     ok = 0;
114     break;
115     }
116     ok &= (n == 0);
117     close(fd);
118     return ok;
119     }
120    
121     /* Allocate and assign string from file or stream */
122     static char *
123     input2str(const char *inpspec)
124     {
125     FILE *fp = NULL;
126     char *str;
127     int len, pos, n;
128    
129     if (inpspec == NULL || !*inpspec)
130     return "";
131     if (inpspec == stdin_name) { /* read from stdin */
132     fp = stdin;
133 greg 2.2 } else if (inpspec[0] == '!') { /* read from command */
134 greg 2.1 fp = popen(inpspec+1, "r");
135     if (fp == NULL) {
136     fprintf(stderr, "Cannot start process '%s'\n",
137 greg 2.2 inpspec);
138 greg 2.1 return "";
139     }
140     } else { /* else load file */
141     int fd = open(inpspec, O_RDONLY);
142     if (fd < 0) {
143     fprintf(stderr, "%s: cannot open\n", inpspec);
144     return "";
145     }
146     len = lseek(fd, 0L, SEEK_END);
147     if (len < 0) {
148     fprintf(stderr, "%s: seek error\n", inpspec);
149     close(fd);
150     return "";
151     }
152     lseek(fd, 0L, SEEK_SET);
153     str = (char *)malloc(len+1);
154     if (str == NULL) {
155     close(fd);
156     goto memerr;
157     }
158     if (read(fd, str, len) != len) {
159     fprintf(stderr, "%s: read error\n", inpspec);
160     free(str);
161     close(fd);
162     return "";
163     }
164     str[len] = '\0';
165     close(fd);
166     return str;
167     }
168     /* reading from stream */
169     str = (char *)malloc((len=8192)+1);
170     if (str == NULL)
171     goto memerr;
172     pos = 0;
173     while ((n = read(fileno(fp), str+pos, len-pos)) > 0)
174     if ((pos += n) >= len) { /* need more space? */
175     str = (char *)realloc(str, (len += len>>2) + 1);
176     if (str == NULL)
177     goto memerr;
178     }
179     if (n < 0) {
180     fprintf(stderr, "%s: read error\n", inpspec);
181     free(str);
182     str = "";
183     } else { /* tidy up result */
184     str[pos] = '\0';
185     str = (char *)realloc(str, (len=pos)+1);
186     if (str == NULL)
187     goto memerr;
188     }
189 greg 2.2 if (inpspec[0] != '!')
190 greg 2.1 fclose(fp);
191     else if (pclose(fp))
192 greg 2.2 fprintf(stderr, "Error running command '%s'\n", inpspec);
193 greg 2.1 return str;
194     memerr:
195     fprintf(stderr, "%s: error allocating memory\n", inpspec);
196     if (fp != NULL)
197 greg 2.2 (inpspec[0] == '!') ? pclose(fp) : fclose(fp);
198 greg 2.1 return "";
199     }
200    
201     /* Make material assignments in field_assignment to XML fields */
202     static int
203     mat_assignments(const char *caller, const char *fn, ezxml_t wtl)
204     {
205     int i;
206    
207     if (!nfield_assign)
208     return 1;
209     wtl = ezxml_child(wtl, "Material");
210     if (wtl == NULL) {
211     fprintf(stderr, "%s: missing <Material> tag\n", fn);
212     return 0;
213     }
214     for (i = 0; i < nfield_assign; i++) {
215     const char *fnext = field_assignment[i];
216     for ( ; ; ) {
217     ezxml_t fld;
218     char sbuf[512];
219     int j;
220    
221     while (isspace(*fnext))
222     ++fnext;
223     if (!*fnext)
224     break;
225     for (j = 0; (*fnext != '=') & !isspace(*fnext); ) {
226     if (!*fnext | (*fnext == FASEP) |
227     (j >= sizeof(sbuf)-1)) {
228     fprintf(stderr,
229     "%s: bad tag name in assignment '%s'\n",
230     caller, field_assignment[i]);
231     return 0;
232     }
233     sbuf[j++] = *fnext++;
234     }
235 greg 2.2 sbuf[j] = '\0'; /* check known field */
236 greg 2.1 for (j = 0; XMLfieldID[j].nickName[0]; j++)
237 greg 2.2 if (!strcasecmp(sbuf, XMLfieldID[j].nickName) ||
238     !strcasecmp(sbuf, XMLfieldID[j].fullName)) {
239 greg 2.1 strcpy(sbuf, XMLfieldID[j].fullName);
240     break;
241     }
242     /* check if tag exists */
243     fld = ezxml_child(wtl, sbuf);
244     if (fld == NULL) { /* otherwise, create one */
245     fprintf(stderr, "%s: warning - adding tag <%s>\n",
246     fn, sbuf);
247     fld = ezxml_add_child_d(wtl, sbuf, strlen(wtl->txt));
248     }
249     if (XMLfieldID[j].has_unit)
250     ezxml_set_attr(fld, "unit", attr_unit);
251     while (isspace(*fnext))
252     ++fnext;
253     if (*fnext++ != '=') {
254     fprintf(stderr,
255     "%s: missing '=' in assignment '%s'\n",
256     caller, field_assignment[i]);
257     return 0;
258     }
259     for (j = 0; *fnext & (*fnext != FASEP); ) {
260     if (j >= sizeof(sbuf)-1) {
261     fprintf(stderr,
262     "%s: field too long in '%s'\n",
263     caller, field_assignment[i]);
264     return 0;
265     }
266     sbuf[j++] = *fnext++;
267     }
268     sbuf[j] = '\0';
269     ezxml_set_txt_d(fld, sbuf);
270     fnext += (*fnext == FASEP);
271     }
272     }
273     return 1; /* no errors */
274     }
275    
276     /* Complete angle basis specification */
277     static int
278     finish_angle_basis(ezxml_t ab)
279     {
280     const char *bn = ezxml_txt(ezxml_child(ab, "AngleBasisName"));
281     int i, n = nabases;
282     char buf[32];
283    
284     if (!*bn) {
285     fputs("Internal error - missing <AngleBasisName>!\n", stderr);
286     return 0;
287     }
288     while (n-- > 0)
289     if (!strcasecmp(bn, abase_list[n].name))
290     break;
291     if (n < 0) {
292     fprintf(stderr, "Internal error - unknown angle basis '%s'", bn);
293     return 0;
294     }
295     for (i = 0; abase_list[n].lat[i].nphis; i++) {
296     ezxml_t tb, abb = ezxml_add_child(ab, "AngleBasisBlock",
297     strlen(ab->txt));
298     sprintf(buf, "%g", i ?
299     .5*(abase_list[n].lat[i].tmin + abase_list[n].lat[i+1].tmin) :
300     .0);
301     ezxml_set_txt_d(ezxml_add_child(abb,"Theta",strlen(abb->txt)), buf);
302     sprintf(buf, "%d", abase_list[n].lat[i].nphis);
303     ezxml_set_txt_d(ezxml_add_child(abb,"nPhis",strlen(abb->txt)), buf);
304     tb = ezxml_add_child(abb, "ThetaBounds", strlen(abb->txt));
305     sprintf(buf, "%g", abase_list[n].lat[i].tmin);
306     ezxml_set_txt(ezxml_add_child(tb,"LowerTheta",strlen(tb->txt)), buf);
307     sprintf(buf, "%g", abase_list[n].lat[i+1].tmin);
308     ezxml_set_txt(ezxml_add_child(tb,"UpperTheta",strlen(tb->txt)), buf);
309     }
310     return 1;
311     }
312    
313     /* Determine our angle basis from current tags */
314     static int
315     determine_angle_basis(const char *fn, ezxml_t wtl)
316     {
317     const char *ids;
318     int i;
319    
320     wtl = ezxml_child(wtl, "DataDefinition");
321     if (wtl == NULL)
322     return -1;
323     ids = ezxml_txt(ezxml_child(wtl, "IncidentDataStructure"));
324     if (ids == NULL)
325     return -1;
326     for (i = 0; i < ABend; i++) {
327     ezxml_t parsed = ezxml_parse_str(basis_definition[i],
328     strlen(basis_definition[i]));
329     int match = 0;
330     if (!strcmp(ids, ezxml_txt(ezxml_child(parsed,
331     "IncidentDataStructure")))) {
332     const char *abn0 = ezxml_txt(
333     ezxml_child(ezxml_child(wtl,
334     "AngleBasis"), "AngleBasisName"));
335     const char *abn1 = ezxml_txt(
336     ezxml_child(ezxml_child(parsed,
337     "AngleBasis"), "AngleBasisName"));
338     match = !strcmp(abn0, abn1);
339     }
340     ezxml_free(parsed);
341     if (match)
342     return i;
343     }
344     return -1;
345     }
346    
347     /* Write out BSDF data block with surrounding tags */
348     static int
349     writeBSDFblock(const char *caller, struct s_dfile *df)
350     {
351     char *cp;
352    
353     puts("\t<WavelengthData>");
354     puts("\t\t<LayerNumber>System</LayerNumber>");
355     switch (df->spectrum) {
356     case DSvisible:
357     puts("\t\t<Wavelength unit=\"Integral\">Visible</Wavelength>");
358     puts("\t\tSourceSpectrum>CIE Illuminant D65 1nm.ssp</SourceSpectrum>");
359     puts("\t\t<DetectorSpectrum>ASTM E308 1931 Y.dsp</DetectorSpectrum>");
360     break;
361     case DSxbar31:
362     puts("\t\t<Wavelength unit=\"Integral\">CIE-X</Wavelength>");
363     puts("\t\tSourceSpectrum>CIE Illuminant D65 1nm.ssp</SourceSpectrum>");
364     puts("\t\t<DetectorSpectrum>ASTM E308 1931 X.dsp</DetectorSpectrum>");
365     break;
366     case DSzbar31:
367     puts("\t\t<Wavelength unit=\"Integral\">CIE-Z</Wavelength>");
368     puts("\t\tSourceSpectrum>CIE Illuminant D65 1nm.ssp</SourceSpectrum>");
369     puts("\t\t<DetectorSpectrum>ASTM E308 1931 Z.dsp</DetectorSpectrum>");
370     break;
371     case DSsolar:
372     puts("\t\t<Wavelength unit=\"Integral\">Solar</Wavelength>");
373     puts("\t\tSourceSpectrum>CIE Illuminant D65 1nm.ssp</SourceSpectrum>");
374     puts("\t\t<DetectorSpectrum>None</DetectorSpectrum>");
375     break;
376     case DSnir:
377     puts("\t\t<Wavelength unit=\"Integral\">NIR</Wavelength>");
378     puts("\t\tSourceSpectrum>PLACE_HOLDER</SourceSpectrum>");
379     puts("\t\t<DetectorSpectrum>PLACE_HOLDER</DetectorSpectrum>");
380     break;
381     default:
382     cp = strrchr(spectr_file[df->spectrum], '.');
383     if (cp != NULL)
384     *cp = '\0';
385     printf("\t\t<Wavelength unit=\"Integral\">%s</Wavelength>\n",
386     spectr_file[df->spectrum]);
387     if (cp != NULL)
388     *cp = '.';
389     puts("\t\tSourceSpectrum>CIE Illuminant D65 1nm.ssp</SourceSpectrum>");
390     printf("\t\t<DetectorSpectrum>%s</DetectorSpectrum>\n",
391     spectr_file[df->spectrum]);
392     break;
393     }
394     puts("\t\t<WavelengthDataBlock>");
395     fputs("\t\t\t<WavelengthDataDirection>", stdout);
396     switch (df->type) {
397     case DTtransForward:
398     fputs("Transmission Front", stdout);
399     break;
400     case DTtransBackward:
401     fputs("Transmission Back", stdout);
402     break;
403     case DTreflForward:
404     fputs("Reflection Front", stdout);
405     break;
406     case DTreflBackward:
407     fputs("Reflection Back", stdout);
408     break;
409     default:
410     fprintf(stderr, "%s: internal - bad BSDF type (%d)\n", caller, df->type);
411     return 0;
412     }
413     puts("</WavelengthDataDirection>");
414     switch (angle_basis) {
415     case ABklemsFull:
416     puts("\t\t\t<ColumnAngleBasis>LBNL/Klems Full</ColumnAngleBasis>");
417     break;
418     case ABklemsHalf:
419     puts("\t\t\t<ColumnAngleBasis>LBNL/Klems Half</ColumnAngleBasis>");
420     break;
421     case ABklemsQuarter:
422     puts("\t\t\t<ColumnAngleBasis>LBNL/Klems Quarter</ColumnAngleBasis>");
423     break;
424     case ABtensorTree3:
425     case ABtensorTree4:
426     puts("\t\t\t<AngleBasis>LBNL/Shirley-Chiu</AngleBasis>");
427     break;
428     default:
429     fprintf(stderr, "%s: bad angle basis (%d)\n", caller, angle_basis);
430     return 0;
431     }
432     puts("\t\t\t<ScatteringDataType>BTDF</ScatteringDataType>");
433     puts("\t\t\t<ScatteringData>");
434     fflush(stdout);
435     if (df->fname == stdin_name) {
436     copy_and_close(fileno(stdin));
437 greg 2.2 } else if (df->fname[0] != '!') {
438 greg 2.1 if (!copy_and_close(open(df->fname, O_RDONLY))) {
439     fprintf(stderr, "%s: error reading from '%s'\n",
440     caller, df->fname);
441     return 0;
442     }
443     } else if (system(df->fname+1)) {
444 greg 2.2 fprintf(stderr, "%s: error running '%s'\n", caller, df->fname);
445 greg 2.1 return 0;
446     }
447     puts("\t\t\t</ScatteringData>");
448     puts("\t\t</WavelengthDataBlock>");
449     puts("\t</WavelengthData>");
450     return 1;
451     }
452    
453     /* Write out XML, interpolating BSDF data block(s) */
454     static int
455     writeBSDF(const char *caller, ezxml_t fl)
456     {
457 greg 2.2 char *xml = ezxml_toxml(fl); /* store XML in string */
458 greg 2.1 int ei, i;
459     /* locate trailer */
460     for (ei = strlen(xml)-strlen("</Layer></Optical></WindowElement>");
461     ei >= 0; ei--)
462     if (!strncmp(xml+ei, "</Layer>", 8))
463     break;
464     if (ei < 0) {
465     fprintf(stderr, "%s: internal - cannot find trailer\n",
466     caller);
467     free(xml);
468     return 0;
469     }
470     fflush(stdout); /* write previous XML info. */
471     if (write(fileno(stdout), xml, ei) != ei) {
472     free(xml);
473     return 0;
474     }
475     for (i = 0; i < ndataf; i++) /* interpolate new data */
476     if (!writeBSDFblock(caller, &data_file[i])) {
477     free(xml);
478     return 0;
479     }
480     fputs(xml+ei, stdout); /* write trailer */
481 greg 2.2 free(xml); /* free string */
482 greg 2.1 return (fflush(stdout) == 0);
483     }
484    
485     /* Insert BSDF data into XML wrapper */
486     static int
487     wrapBSDF(const char *caller)
488     {
489 greg 2.2 const char *xml_path = xml_input;
490 greg 2.1 ezxml_t fl, wtl;
491     /* load previous XML/template */
492 greg 2.2 if (xml_input == stdin_name) {
493     fl = ezxml_parse_fp(stdin);
494     } else if (xml_input[0] == '!') {
495     FILE *pfp = popen(xml_input+1, "r");
496     if (pfp == NULL) {
497     fprintf(stderr, "%s: cannot start process '%s'\n",
498     caller, xml_input);
499     return 0;
500     }
501     fl = ezxml_parse_fp(pfp);
502     if (pclose(pfp)) {
503     fprintf(stderr, "%s: error running '%s'\n",
504     caller, xml_input);
505     return 0;
506     }
507     } else {
508     xml_path = getpath((char *)xml_input, getrlibpath(), R_OK);
509     if (xml_path == NULL) {
510     fprintf(stderr, "%s: cannot find XML file named '%s'\n",
511     caller, xml_input==NULL ? "NULL" : xml_input);
512     return 0;
513     }
514     fl = ezxml_parse_file(xml_path);
515 greg 2.1 }
516     if (fl == NULL) {
517 greg 2.2 fprintf(stderr, "%s: cannot load XML '%s'\n", caller, xml_path);
518 greg 2.1 return 0;
519     }
520     if (ezxml_error(fl)[0]) {
521 greg 2.2 fprintf(stderr, "%s: error in XML '%s': %s\n", caller, xml_path,
522 greg 2.1 ezxml_error(fl));
523     goto failure;
524     }
525     if (strcmp(ezxml_name(fl), top_level_name)) {
526     fprintf(stderr, "%s: top level in XML '%s' not '%s'\n",
527     caller, xml_path, top_level_name);
528     goto failure;
529     }
530     wtl = ezxml_child(fl, "FileType");
531     if (wtl != NULL && strcmp(ezxml_txt(wtl), "BSDF")) {
532     fprintf(stderr, "%s: wrong FileType in XML '%s' (must be 'BSDF')",
533     caller, xml_path);
534     goto failure;
535     }
536     wtl = ezxml_child(ezxml_child(fl, "Optical"), "Layer");
537     if (wtl == NULL) {
538     fprintf(stderr, "%s: no optical layers in XML '%s'",
539     caller, xml_path);
540     goto failure;
541     }
542     /* make material assignments */
543     if (!mat_assignments(caller, xml_path, wtl)) {
544     goto failure;
545     }
546     if (mgf_geometry != NULL) { /* add geometry if specified */
547     ezxml_t geom = ezxml_child(wtl, "Geometry");
548     if (geom == NULL)
549     geom = ezxml_add_child(wtl, "Geometry", 0);
550     ezxml_set_attr(geom, "format", "MGF");
551     geom = ezxml_child(geom, "MGFblock");
552     if (geom == NULL) {
553     geom = ezxml_child(wtl, "Geometry");
554     geom = ezxml_add_child(geom, "MGFblock", strlen(geom->txt));
555     }
556     ezxml_set_attr(geom, "unit", attr_unit);
557     ezxml_set_txt(geom, input2str(mgf_geometry));
558     if (geom->txt[0])
559     ezxml_set_flag(geom, EZXML_TXTM);
560     }
561     /* check basis */
562     if (angle_basis != ABdefault) {
563     ezxml_t ab, dd = ezxml_child(wtl, "DataDefinition");
564     if (dd == NULL) {
565     dd = ezxml_add_child(wtl, "DataDefinition", 0);
566     } else {
567     if (ezxml_child(dd, "DataDefinition") != NULL)
568     fprintf(stderr,
569     "%s: warning - replacing existing <DataDefinition> in '%s'\n",
570     caller, xml_path);
571     while (dd->child != NULL)
572     ezxml_remove(dd->child);
573     }
574     ezxml_insert(ezxml_parse_str(basis_definition[angle_basis],
575     strlen(basis_definition[angle_basis])),
576     dd, 0);
577     if ((ab = ezxml_child(dd, "AngleBasis")) != NULL &&
578     !finish_angle_basis(ab))
579     goto failure;
580     } else if ((angle_basis = determine_angle_basis(xml_path, wtl)) < 0) {
581     fprintf(stderr, "%s: need -a option to set angle basis\n",
582     caller);
583     goto failure;
584     }
585     /* write & add BSDF data blocks */
586     if (!writeBSDF(caller, fl))
587     goto failure;
588     ezxml_free(fl); /* all done */
589     return 1;
590     failure:
591     ezxml_free(fl);
592     return 0;
593     }
594    
595     /* Report usage and exit */
596     static void
597     UsageExit(const char *pname)
598     {
599     fputs("Usage: ", stderr);
600     fputs(pname, stderr);
601 greg 2.2 fputs(" [-W][-a {kf|kh|kq|t3|t4}][-u unit][-g geom][-f 'x=string;y=string']", stderr);
602     fputs(" [-s spectr][-tb inp][-tf inp][-rb inp][-rf inp]", stderr);
603     fputs(" [input.xml]\n", stderr);
604 greg 2.1 exit(1);
605     }
606    
607     /* Load XML file and use to wrap BSDF data (or modify fields) */
608     int
609     main(int argc, char *argv[])
610     {
611     int cur_spectrum = DSvisible;
612     int ncust_spec = 0;
613     int used_stdin = 0;
614     int units_set = 0;
615     int i;
616     /* get/check arguments */
617     for (i = 1; i < argc && argv[i][0] == '-'; i++) {
618     switch (argv[i][1]) {
619     case 'W': /* customize for WINDOW 6 output */
620     xml_input = win6_template;
621     continue;
622     case 'f': /* field assignment(s) */
623     if (++i >= argc)
624     UsageExit(argv[0]);
625     if (nfield_assign >= MAXASSIGN) {
626     fprintf(stderr, "%s: too many -f options",
627     argv[0]);
628     return 1;
629     }
630     field_assignment[nfield_assign++] = argv[i];
631     continue;
632     case 'u': /* unit */
633     if (++i >= argc)
634     UsageExit(argv[0]);
635     if (units_set++) {
636     fprintf(stderr, "%s: only one -u option allowed\n",
637     argv[0]);
638     return 1;
639     }
640 greg 2.2 if (strstr(legal_units, argv[i]) == NULL) {
641     fprintf(stderr, "%s: -u unit must be one of (%s)\n",
642 greg 2.1 argv[0], legal_units);
643     return 1;
644     }
645     attr_unit = argv[i];
646     continue;
647     case 'a': /* angle basis */
648     if (++i >= argc)
649     UsageExit(argv[0]);
650     if (angle_basis != ABdefault) {
651     fprintf(stderr, "%s: only one -a option allowed\n",
652     argv[0]);
653     return 1;
654     }
655     if (!strcasecmp(argv[i], "kf"))
656     angle_basis = ABklemsFull;
657     else if (!strcasecmp(argv[i], "kh"))
658     angle_basis = ABklemsHalf;
659     else if (!strcasecmp(argv[i], "kq"))
660     angle_basis = ABklemsQuarter;
661     else if (!strcasecmp(argv[i], "t3"))
662     angle_basis = ABtensorTree3;
663     else if (!strcasecmp(argv[i], "t4"))
664     angle_basis = ABtensorTree4;
665     else
666     UsageExit(argv[0]);
667     continue;
668     case 't': /* transmission */
669     if (i >= argc-1)
670     UsageExit(argv[0]);
671     if (ndataf >= MAXFILES) {
672     fprintf(stderr, "%s: too many data files\n",
673     argv[0]);
674     return 1;
675     }
676     if (!strcmp(argv[i], "-tf"))
677     data_file[ndataf].type = DTtransForward;
678     else if (!strcmp(argv[i], "-tb"))
679     data_file[ndataf].type = DTtransBackward;
680     else
681     UsageExit(argv[0]);
682     if (!strcmp(argv[++i], "-")) {
683     if (used_stdin++) UsageExit(argv[i]);
684     argv[i] = (char *)stdin_name;
685     }
686     data_file[ndataf].fname = argv[i];
687     data_file[ndataf].spectrum = cur_spectrum;
688     ndataf++;
689     continue;
690     case 'r': /* reflection */
691     if (i >= argc-1)
692     UsageExit(argv[0]);
693     if (ndataf >= MAXFILES) {
694     fprintf(stderr, "%s: too many data files\n",
695     argv[0]);
696     return 1;
697     }
698     if (!strcmp(argv[i], "-rf"))
699     data_file[ndataf].type = DTreflForward;
700     else if (!strcmp(argv[i], "-rb"))
701     data_file[ndataf].type = DTreflBackward;
702     else
703     UsageExit(argv[0]);
704     if (!strcmp(argv[++i], "-")) {
705     if (used_stdin++) UsageExit(argv[i]);
706     argv[i] = (char *)stdin_name;
707     }
708     data_file[ndataf].fname = argv[i];
709     data_file[ndataf++].spectrum = cur_spectrum;
710     continue;
711     case 's': /* spectrum name or input file */
712     if (++i >= argc)
713     UsageExit(argv[0]);
714     if (!strcasecmp(argv[i], "Solar"))
715     cur_spectrum = DSsolar;
716     else if (!strcasecmp(argv[i], "Visible") ||
717     !strcasecmp(argv[i], "CIE-Y"))
718     cur_spectrum = DSvisible;
719     else if (!strcasecmp(argv[i], "CIE-X"))
720     cur_spectrum = DSxbar31;
721     else if (!strcasecmp(argv[i], "CIE-Z"))
722     cur_spectrum = DSzbar31;
723     else if (!strcasecmp(argv[i], "NIR"))
724     cur_spectrum = DSnir;
725     else {
726     if (!strcmp(argv[i], "-")) {
727     fprintf(stderr,
728     "%s: cannot read spectra from stdin",
729     argv[0]);
730     return 1;
731     }
732     cur_spectrum = ncust_spec;
733     spectr_file[ncust_spec++] = argv[i];
734     }
735     continue;
736     case 'g': /* MGF geometry file */
737     if (i >= argc-1)
738     UsageExit(argv[0]);
739     if (mgf_geometry != NULL) {
740     fprintf(stderr, "%s: only one -g option allowed\n",
741     argv[0]);
742     return 1;
743     }
744     if (!strcmp(argv[++i], "-")) {
745     if (used_stdin++) UsageExit(argv[i]);
746     argv[i] = (char *)stdin_name;
747     }
748     mgf_geometry = argv[i];
749     continue;
750     case '\0': /* input XML from stdin */
751     break;
752     default:
753     UsageExit(argv[0]);
754     break;
755     }
756     break;
757     }
758     doneOptions: /* get XML input */
759     if (i >= argc) {
760     if (xml_input == NULL)
761     xml_input = def_template;
762     } else if ((i < argc-1) | (xml_input != NULL)) {
763     fprintf(stderr, "%s: only one XML input allowed\n", argv[0]);
764     UsageExit(argv[0]);
765     } else if (!strcmp(argv[i], "-")) {
766     if (used_stdin++) UsageExit(argv[0]);
767     xml_input = stdin_name;
768     } else {
769     xml_input = argv[i];
770     }
771     if ((xml_input == win6_template) & (angle_basis == ABdefault))
772     angle_basis = ABklemsFull;
773     /* wrap it! */
774     return !wrapBSDF(argv[0]);
775     }