#ifndef lint static const char RCSid[] = "$Id: wrapBSDF.c,v 2.24 2019/04/04 00:21:14 greg Exp $"; #endif /* * Wrap BSDF data in valid WINDOW XML file * * G. Ward February 2015 */ #include "platform.h" #include #include "rtio.h" #include "paths.h" #include "ezxml.h" #include "bsdf.h" #include "bsdf_m.h" /* XML template file names */ const char def_template[] = "minimalBSDFt.xml"; const char win6_template[] = "WINDOW6BSDFt.xml"; const char stdin_name[] = ""; /* input files (can be stdin_name) */ const char *xml_input = NULL; /* unit for materials & geometry */ const char *attr_unit = "meter"; const char legal_units[] = "meter|foot|inch|centimeter|millimeter"; /* system materials & geometry */ const char *mgf_geometry = NULL; /* comment list */ #define MAXCOMM 30 const char *commlist[MAXCOMM]; int ncomm = 0; /* angle bases */ enum { ABdefault=-1, ABklemsFull=0, ABklemsHalf, ABklemsQuarter, ABtensorTree3, ABtensorTree4, ABend }; int angle_basis = ABdefault; int correct_solid_angle = 0; const char *klems_basis_name[] = { "LBNL/Klems Full", "LBNL/Klems Half", "LBNL/Klems Quarter", }; /* field IDs and nicknames */ struct s_fieldID { char nickName[4]; short has_unit; short win_need; const char *fullName; } XMLfieldID[] = { {"m", 0, 1, "Manufacturer"}, {"n", 0, 1, "Name"}, {"d", 0, 0, "DeviceType"}, {"c", 0, 0, "ThermalConductivity"}, {"ef", 0, 0, "EmissivityFront"}, {"eb", 0, 0, "EmissivityBack"}, {"tir", 0, 0, "TIR"}, {"eo", 0, 0, "EffectiveOpennessFraction"}, {"t", 1, 1, "Thickness"}, {"h", 1, 0, "Height"}, {"w", 1, 0, "Width"}, {"\0", 0, 0, NULL} /* terminator */ }; /* field assignments */ #define MAXASSIGN 16 const char *field_assignment[MAXASSIGN]; int nfield_assign = 0; #define FASEP ';' /* data file(s) & spectra */ enum { DTransFront, DTransBack, DTreflFront, DTreflBack }; static const char component_name[4][20] = { "Transmission Front", "Transmission Back", "Reflection Front", "Reflection Back" }; enum { DSsolar=-1, DSnir=-2, DSxbar31=-3, DSvisible=-4, DSzbar31=-5, DSuprime=-6, DSvprime=-7 }; #define MAXFILES 20 struct s_dfile { const char *fname; /* input data file name */ short type; /* BSDF data type */ short spectrum; /* BSDF sensor spectrum */ } data_file[MAXFILES]; int ndataf = 0; /* number of data files */ int unlink_datafiles = 0; /* unlink data files when done */ const char *spectr_file[MAXFILES]; /* custom spectral curve input */ const char top_level_name[] = "WindowElement"; static char basis_definition[][256] = { "\t\n" "\t\tColumns\n" "\t\t\n" "\t\t\tLBNL/Klems Full\n" "\t\t\t\n" "\t\n", "\t\n" "\t\tColumns\n" "\t\t\n" "\t\t\tLBNL/Klems Half\n" "\t\t\t\n" "\t\n", "\t\n" "\t\tColumns\n" "\t\t\n" "\t\t\tLBNL/Klems Quarter\n" "\t\t\t\n" "\t\n", "\t\n" "\t\tTensorTree3\n" "\t\n", "\t\n" "\t\tTensorTree4\n" "\t\n", }; /* Check that the last-added data file is unique */ static int check_new_data_file() { int i = ndataf; while (i-- > 0) if ((data_file[i].spectrum == data_file[ndataf].spectrum) & (data_file[i].type == data_file[ndataf].type)) { fprintf(stderr, "%s: warning - ignoring duplicate component %s\n", data_file[ndataf].fname, component_name[data_file[i].type]); return 0; } return 1; } /* Copy data from file descriptor to stdout and close */ static int copy_and_close(int fd) { int ok = 1; char buf[8192]; int n; if (fd < 0) return 0; while ((n = read(fd, buf, sizeof(buf))) > 0) if (write(fileno(stdout), buf, n) != n) { ok = 0; break; } ok &= (n == 0); close(fd); return ok; } /* Allocate and assign string from file or stream */ static char * input2str(const char *inpspec) { FILE *fp = NULL; char *str; int len, pos, n; if (inpspec == NULL || !*inpspec) return ""; if (inpspec == stdin_name) { /* read from stdin */ fp = stdin; } else if (inpspec[0] == '!') { /* read from command */ fp = popen(inpspec+1, "r"); if (fp == NULL) { fprintf(stderr, "Cannot start process '%s'\n", inpspec); return ""; } } else { /* else load file */ int fd = open(inpspec, O_RDONLY); if (fd < 0) { fprintf(stderr, "%s: cannot open\n", inpspec); return ""; } #if !defined(_WIN32) && !defined(_WIN64) /* XXX somehow broken on Windows */ len = lseek(fd, 0L, SEEK_END); if (len > 0) { lseek(fd, 0L, SEEK_SET); str = (char *)malloc(len+1); if (str == NULL) { close(fd); goto memerr; } if (read(fd, str, len) != len) { fprintf(stderr, "%s: read error\n", inpspec); free(str); close(fd); return ""; } str[len] = '\0'; close(fd); return str; } #endif fp = fdopen(fd, "r"); /* not a regular file */ } /* reading from stream */ str = (char *)malloc((len=8192)+1); if (str == NULL) goto memerr; pos = 0; while ((n = read(fileno(fp), str+pos, len-pos)) > 0) if ((pos += n) >= len) { /* need more space? */ str = (char *)realloc(str, (len += len>>2) + 1); if (str == NULL) goto memerr; } if (n < 0) { fprintf(stderr, "%s: read error\n", inpspec); free(str); str = ""; } else { /* tidy up result */ str[pos] = '\0'; str = (char *)realloc(str, (len=pos)+1); if (str == NULL) goto memerr; } if (inpspec[0] != '!') fclose(fp); else if (pclose(fp)) fprintf(stderr, "Error running command '%s'\n", inpspec); return str; memerr: fprintf(stderr, "%s: error allocating memory\n", inpspec); if (fp != NULL) (inpspec[0] == '!') ? pclose(fp) : fclose(fp); return ""; } /* Make material assignments in field_assignment to XML fields */ static int mat_assignments(const char *caller, const char *fn, ezxml_t wtl) { int i; wtl = ezxml_child(wtl, "Material"); if (wtl == NULL) { fprintf(stderr, "%s: missing tag\n", fn); return 0; } for (i = 0; i < nfield_assign; i++) { const char *fnext = field_assignment[i]; for ( ; ; ) { int added = 0; ezxml_t fld; char sbuf[512]; int j; while (isspace(*fnext)) ++fnext; if (!*fnext) break; for (j = 0; *fnext != '=' && !isspace(*fnext); ) { if (!*fnext | (*fnext == FASEP) | (j >= sizeof(sbuf)-1)) { fprintf(stderr, "%s: bad tag name in assignment '%s'\n", caller, field_assignment[i]); return 0; } sbuf[j++] = *fnext++; } sbuf[j] = '\0'; /* check known field */ for (j = 0; XMLfieldID[j].nickName[0]; j++) if (!strcasecmp(sbuf, XMLfieldID[j].nickName) || !strcasecmp(sbuf, XMLfieldID[j].fullName)) { strcpy(sbuf, XMLfieldID[j].fullName); break; } /* check if tag exists */ fld = ezxml_child(wtl, sbuf); if (fld == NULL) { /* otherwise, create one */ if (!XMLfieldID[j].nickName[0]) fprintf(stderr, "%s: warning - adding tag <%s>\n", fn, sbuf); ezxml_add_txt(wtl, "\t"); fld = ezxml_add_child_d(wtl, sbuf, strlen(wtl->txt)); ++added; } if (XMLfieldID[j].has_unit) ezxml_set_attr(fld, "unit", attr_unit); XMLfieldID[j].win_need = 0; while (isspace(*fnext)) ++fnext; if (*fnext++ != '=') { fprintf(stderr, "%s: missing '=' in assignment '%s'\n", caller, field_assignment[i]); return 0; } for (j = 0; *fnext && *fnext != FASEP; ) { if (j >= sizeof(sbuf)-1) { fprintf(stderr, "%s: field too long in '%s'\n", caller, field_assignment[i]); return 0; } sbuf[j++] = *fnext++; } sbuf[j] = '\0'; ezxml_set_txt_d(fld, sbuf); if (added) ezxml_add_txt(wtl, "\n\t"); fnext += (*fnext == FASEP); } } /* check required WINDOW settings */ if (xml_input == win6_template) for (i = 0; XMLfieldID[i].nickName[0]; i++) if (XMLfieldID[i].win_need && !ezxml_txt(ezxml_child(wtl,XMLfieldID[i].fullName))[0]) fprintf(stderr, "%s: warning - missing '%s' assignment for WINDOW <%s>\n", caller, XMLfieldID[i].nickName, XMLfieldID[i].fullName); return 1; } /* Complete angle basis specification */ static int finish_angle_basis(ezxml_t ab) { const char *bn = ezxml_txt(ezxml_child(ab, "AngleBasisName")); int i, n = nabases; char buf[32]; if (!*bn) { fputs("Internal error - missing !\n", stderr); return 0; } while (n-- > 0) if (!strcasecmp(bn, abase_list[n].name)) break; if (n < 0) { fprintf(stderr, "Internal error - unknown angle basis '%s'", bn); return 0; } for (i = 0; abase_list[n].lat[i].nphis; i++) { ezxml_t tb, abb = ezxml_add_child(ab, "AngleBasisBlock", strlen(ab->txt)); sprintf(buf, "%g", i ? .5*(abase_list[n].lat[i].tmin + abase_list[n].lat[i+1].tmin) : .0); ezxml_add_txt(abb, "\n\t\t\t\t"); ezxml_set_txt_d(ezxml_add_child(abb,"Theta",strlen(abb->txt)), buf); sprintf(buf, "%d", abase_list[n].lat[i].nphis); ezxml_add_txt(abb, "\n\t\t\t\t"); ezxml_set_txt_d(ezxml_add_child(abb,"nPhis",strlen(abb->txt)), buf); ezxml_add_txt(abb, "\n\t\t\t\t"); tb = ezxml_add_child(abb, "ThetaBounds", strlen(abb->txt)); ezxml_add_txt(tb, "\n\t\t\t\t\t"); sprintf(buf, "%g", abase_list[n].lat[i].tmin); ezxml_set_txt_d(ezxml_add_child(tb,"LowerTheta",strlen(tb->txt)), buf); ezxml_add_txt(tb, "\n\t\t\t\t\t"); sprintf(buf, "%g", abase_list[n].lat[i+1].tmin); ezxml_set_txt_d(ezxml_add_child(tb,"UpperTheta",strlen(tb->txt)), buf); ezxml_add_txt(tb, "\n\t\t\t\t"); ezxml_add_txt(abb, "\n\t\t\t"); ezxml_add_txt(ab, "\n\t\t\t"); } return 1; } /* Determine our angle basis from current tags */ static int determine_angle_basis(const char *fn, ezxml_t wtl) { const char *ids; int i; wtl = ezxml_child(wtl, "DataDefinition"); if (wtl == NULL) return -1; ids = ezxml_txt(ezxml_child(wtl, "IncidentDataStructure")); if (!ids[0]) return -1; for (i = 0; i < ABend; i++) { ezxml_t parsed = ezxml_parse_str(basis_definition[i], strlen(basis_definition[i])); int match = 0; if (!strcmp(ids, ezxml_txt(ezxml_child(parsed, "IncidentDataStructure")))) { const char *abn0 = ezxml_txt( ezxml_child(ezxml_child(wtl, "AngleBasis"), "AngleBasisName")); const char *abn1 = ezxml_txt( ezxml_child(ezxml_child(parsed, "AngleBasis"), "AngleBasisName")); match = !strcmp(abn0, abn1); } ezxml_free(parsed); if (match) return i; } return -1; } /* Filter Klems angle basis, factoring out incident projected solid angle */ static int filter_klems_matrix(FILE *fp) { const char *bn = klems_basis_name[angle_basis]; int i, j, n = nabases; /* get angle basis */ while (n-- > 0) if (!strcasecmp(bn, abase_list[n].name)) break; if (n < 0) return 0; /* read/correct/write matrix */ for (i = 0; i < abase_list[n].nangles; i++) { const double corr = 1./io_getohm(i, &abase_list[n]); for (j = 0; j < abase_list[n].nangles; j++) { double d; if (fscanf(fp, "%lf", &d) != 1) return 0; if (d < -1e-3) { fputs("Negative BSDF data!\n", stderr); return 0; } printf(" %.3e", d*corr*(d > 0)); } fputc('\n', stdout); } while ((i = getc(fp)) != EOF) if (!isspace(i)) { fputs("Unexpected data past EOF\n", stderr); return 0; } return 1; /* all is good */ } /* Write out BSDF data block with surrounding tags */ static int writeBSDFblock(const char *caller, struct s_dfile *df) { int correct_klems = correct_solid_angle; char *cp; puts("\t"); puts("\t\tSystem"); switch (df->spectrum) { case DSvisible: puts("\t\tVisible"); puts("\t\tCIE Illuminant D65 1nm.ssp"); puts("\t\tASTM E308 1931 Y.dsp"); break; case DSxbar31: puts("\t\tCIE-X"); puts("\t\tCIE Illuminant D65 1nm.ssp"); puts("\t\tASTM E308 1931 X.dsp"); break; case DSzbar31: puts("\t\tCIE-Z"); puts("\t\tCIE Illuminant D65 1nm.ssp"); puts("\t\tASTM E308 1931 Z.dsp"); break; case DSuprime: puts("\t\tCIE-u"); puts("\t\tCIE Illuminant D65 1nm.ssp"); break; case DSvprime: puts("\t\tCIE-v"); puts("\t\tCIE Illuminant D65 1nm.ssp"); break; case DSsolar: puts("\t\tSolar"); puts("\t\tCIE Illuminant D65 1nm.ssp"); puts("\t\tNone"); break; case DSnir: puts("\t\tNIR"); puts("\t\tPLACE_HOLDER"); puts("\t\tPLACE_HOLDER"); break; default: cp = strrchr(spectr_file[df->spectrum], '.'); if (cp != NULL) *cp = '\0'; printf("\t\t%s\n", spectr_file[df->spectrum]); if (cp != NULL) *cp = '.'; puts("\t\tCIE Illuminant D65 1nm.ssp"); printf("\t\t%s\n", spectr_file[df->spectrum]); break; } puts("\t\t"); fputs("\t\t\t", stdout); fputs(component_name[df->type], stdout); puts(""); switch (angle_basis) { case ABklemsFull: case ABklemsHalf: case ABklemsQuarter: fputs("\t\t\t", stdout); fputs(klems_basis_name[angle_basis], stdout); puts(""); fputs("\t\t\t", stdout); fputs(klems_basis_name[angle_basis], stdout); puts(""); break; case ABtensorTree3: case ABtensorTree4: puts("\t\t\tLBNL/Shirley-Chiu"); correct_klems = 0; break; default: fprintf(stderr, "%s: bad angle basis (%d)\n", caller, angle_basis); return 0; } puts("\t\t\tBTDF"); puts("\t\t\t"); fflush(stdout); if (correct_klems) { /* correct Klems matrix data */ FILE *fp = stdin; if (df->fname[0] == '!') fp = popen(df->fname+1, "r"); else if (df->fname != stdin_name) fp = fopen(df->fname, "r"); if (fp == NULL) { fprintf(stderr, "%s: cannot open '%s'\n", caller, df->fname); return 0; } if (!filter_klems_matrix(fp)) { fprintf(stderr, "%s: Klems data error from '%s'\n", caller, df->fname); return 0; } if (df->fname[0] != '!') { fclose(fp); } else if (pclose(fp)) { fprintf(stderr, "%s: error running '%s'\n", caller, df->fname); return 0; } } else if (df->fname == stdin_name) { copy_and_close(fileno(stdin)); } else if (df->fname[0] != '!') { if (!copy_and_close(open(df->fname, O_RDONLY))) { fprintf(stderr, "%s: error reading from '%s'\n", caller, df->fname); return 0; } } else if (system(df->fname+1)) { fprintf(stderr, "%s: error running '%s'\n", caller, df->fname); return 0; } puts("\t\t\t"); puts("\t\t"); puts("\t"); return 1; } /* Write out XML, interpolating BSDF data block(s) */ static int writeBSDF(const char *caller, ezxml_t fl) { char *xml = ezxml_toxml(fl); /* store XML in string */ int ei, i; /* locate trailer */ for (ei = strlen(xml)-strlen(""); ei >= 0; ei--) if (!strncmp(xml+ei, "", 8)) break; if (ei < 0) { fprintf(stderr, "%s: internal - cannot find trailer\n", caller); free(xml); return 0; } puts(""); for (i = 0; i < ncomm; i++) printf("\n", commlist[i]); fflush(stdout); /* write previous XML info. */ if (write(fileno(stdout), xml, ei) != ei) { free(xml); return 0; } for (i = 0; i < ndataf; i++) /* interpolate new data */ if (!writeBSDFblock(caller, &data_file[i])) { free(xml); return 0; } fputs(xml+ei, stdout); /* write trailer */ free(xml); /* free string */ fputc('\n', stdout); if (fflush(stdout) != 0) return 0; /* unlink data files if req. */ for (i = ndataf*(unlink_datafiles != 0); i--; ) if (data_file[i].fname != stdin_name && data_file[i].fname[0] != '!') unlink(data_file[i].fname); if (unlink_datafiles > 1 && mgf_geometry != NULL && mgf_geometry != stdin_name && mgf_geometry[0] != '!') unlink(mgf_geometry); return 1; } /* Insert BSDF data into XML wrapper */ static int wrapBSDF(const char *caller) { const char *xml_path = xml_input; ezxml_t fl, wtl; /* load previous XML/template */ if (xml_input == stdin_name) { fl = ezxml_parse_fp(stdin); } else if (xml_input[0] == '!') { FILE *pfp = popen(xml_input+1, "r"); if (pfp == NULL) { fprintf(stderr, "%s: cannot start process '%s'\n", caller, xml_input); return 0; } fl = ezxml_parse_fp(pfp); if (pclose(pfp)) { fprintf(stderr, "%s: error running '%s'\n", caller, xml_input); return 0; } } else { xml_path = getpath((char *)xml_input, getrlibpath(), R_OK); if (xml_path == NULL) { fprintf(stderr, "%s: cannot find XML file named '%s'\n", caller, xml_input==NULL ? "NULL" : xml_input); return 0; } fl = ezxml_parse_file(xml_path); } if (fl == NULL) { fprintf(stderr, "%s: cannot load XML '%s'\n", caller, xml_path); return 0; } if (ezxml_error(fl)[0]) { fprintf(stderr, "%s: error in XML '%s': %s\n", caller, xml_path, ezxml_error(fl)); goto failure; } if (strcmp(ezxml_name(fl), top_level_name)) { fprintf(stderr, "%s: top level in XML '%s' not '%s'\n", caller, xml_path, top_level_name); goto failure; } wtl = ezxml_child(fl, "FileType"); if (wtl != NULL && strcmp(ezxml_txt(wtl), "BSDF")) { fprintf(stderr, "%s: wrong FileType in XML '%s' (must be 'BSDF')", caller, xml_path); goto failure; } wtl = ezxml_child(ezxml_child(fl, "Optical"), "Layer"); if (wtl == NULL) { fprintf(stderr, "%s: no optical layers in XML '%s'", caller, xml_path); goto failure; } /* make material assignments */ if (!mat_assignments(caller, xml_path, wtl)) goto failure; if (mgf_geometry != NULL) { /* add geometry if specified */ ezxml_t geom = ezxml_child(wtl, "Geometry"); if (geom == NULL) geom = ezxml_add_child(wtl, "Geometry", strlen(wtl->txt)); ezxml_set_attr(geom, "format", "MGF"); geom = ezxml_child(geom, "MGFblock"); if (geom == NULL) { geom = ezxml_child(wtl, "Geometry"); geom = ezxml_add_child(geom, "MGFblock", 0); } ezxml_set_attr(geom, "unit", attr_unit); ezxml_set_txt(geom, input2str(mgf_geometry)); if (geom->txt[0]) ezxml_set_flag(geom, EZXML_TXTM); } /* check basis */ if (angle_basis != ABdefault) { size_t offset = 0; ezxml_t ab, dd = ezxml_child(wtl, "DataDefinition"); if (dd != NULL) { offset = dd->off; if (dd->child != NULL) fprintf(stderr, "%s: warning - replacing existing in '%s'\n", caller, xml_path); ezxml_remove(dd); } else offset = strlen(wtl->txt); dd = ezxml_insert(ezxml_parse_str(basis_definition[angle_basis], strlen(basis_definition[angle_basis])), wtl, offset); if ((ab = ezxml_child(dd, "AngleBasis")) != NULL && !finish_angle_basis(ab)) goto failure; } else if ((angle_basis = determine_angle_basis(xml_path, wtl)) < 0) { fprintf(stderr, "%s: need -a option to set angle basis\n", caller); goto failure; } /* write & add BSDF data blocks */ if (!writeBSDF(caller, fl)) goto failure; ezxml_free(fl); /* all done */ return 1; failure: ezxml_free(fl); return 0; } /* Report usage and exit */ static void UsageExit(const char *pname) { fputs("Usage: ", stderr); fputs(pname, stderr); fputs(" [-W][-c][-a {kf|kh|kq|t3|t4}][-u unit][-g geom][-f 'x=string;y=string']", stderr); fputs(" [-s spectr][-tb inp][-tf inp][-rb inp][-rf inp][-C comm]", stderr); fputs(" [input.xml]\n", stderr); exit(1); } /* Load XML file and use to wrap BSDF data (or modify fields) */ int main(int argc, char *argv[]) { int cur_spectrum = DSvisible; int ncust_spec = 0; int used_stdin = 0; int units_set = 0; int i; /* get/check arguments */ for (i = 1; i < argc && argv[i][0] == '-'; i++) { switch (argv[i][1]) { case 'W': /* customize for WINDOW 6 output */ xml_input = win6_template; continue; case 'f': /* field assignment(s) */ if (++i >= argc) UsageExit(argv[0]); if (nfield_assign >= MAXASSIGN) { fprintf(stderr, "%s: too many -f options", argv[0]); return 1; } field_assignment[nfield_assign++] = argv[i]; continue; case 'u': /* unit */ if (++i >= argc) UsageExit(argv[0]); if (units_set++) { fprintf(stderr, "%s: only one -u option allowed\n", argv[0]); return 1; } if (strstr(legal_units, argv[i]) == NULL) { fprintf(stderr, "%s: -u unit must be one of (%s)\n", argv[0], legal_units); return 1; } attr_unit = argv[i]; continue; case 'U': /* unlink data files when done */ unlink_datafiles = 1 + (argv[i][2] == 'U'); continue; case 'a': /* angle basis */ if (++i >= argc) UsageExit(argv[0]); if (angle_basis != ABdefault) { fprintf(stderr, "%s: only one -a option allowed\n", argv[0]); return 1; } if (!strcasecmp(argv[i], "kf")) angle_basis = ABklemsFull; else if (!strcasecmp(argv[i], "kh")) angle_basis = ABklemsHalf; else if (!strcasecmp(argv[i], "kq")) angle_basis = ABklemsQuarter; else if (!strcasecmp(argv[i], "t3")) angle_basis = ABtensorTree3; else if (!strcasecmp(argv[i], "t4")) angle_basis = ABtensorTree4; else UsageExit(argv[0]); continue; case 'c': /* correct solid angle */ correct_solid_angle = 1; continue; case 'C': /* comment */ if (ncomm >= MAXCOMM) { fprintf(stderr, "%s: too many comments\n", argv[0]); return 1; } if (strchr(argv[++i], '>') != NULL) { fprintf(stderr, "%s: illegal character in comment\n", argv[0]); return 1; } commlist[ncomm++] = argv[i]; continue; case 't': /* transmission */ if (i >= argc-1) UsageExit(argv[0]); if (ndataf >= MAXFILES) { fprintf(stderr, "%s: too many data files\n", argv[0]); return 1; } if (!strcmp(argv[i], "-tf")) data_file[ndataf].type = DTransFront; else if (!strcmp(argv[i], "-tb")) data_file[ndataf].type = DTransBack; else UsageExit(argv[0]); if (!strcmp(argv[++i], "-")) { if (used_stdin++) UsageExit(argv[i]); argv[i] = (char *)stdin_name; } data_file[ndataf].fname = argv[i]; data_file[ndataf].spectrum = cur_spectrum; ndataf += check_new_data_file(); continue; case 'r': /* reflection */ if (i >= argc-1) UsageExit(argv[0]); if (ndataf >= MAXFILES) { fprintf(stderr, "%s: too many data files\n", argv[0]); return 1; } if (!strcmp(argv[i], "-rf")) data_file[ndataf].type = DTreflFront; else if (!strcmp(argv[i], "-rb")) data_file[ndataf].type = DTreflBack; else UsageExit(argv[0]); if (!strcmp(argv[++i], "-")) { if (used_stdin++) UsageExit(argv[i]); argv[i] = (char *)stdin_name; } data_file[ndataf].fname = argv[i]; data_file[ndataf].spectrum = cur_spectrum; ndataf += check_new_data_file(); continue; case 's': /* spectrum name or input file */ if (++i >= argc) UsageExit(argv[0]); if (!strcasecmp(argv[i], "Solar")) cur_spectrum = DSsolar; else if (!strcasecmp(argv[i], "Visible") || !strcasecmp(argv[i], "CIE-Y")) cur_spectrum = DSvisible; else if (!strcasecmp(argv[i], "CIE-X")) cur_spectrum = DSxbar31; else if (!strcasecmp(argv[i], "CIE-Z")) cur_spectrum = DSzbar31; else if (!strcasecmp(argv[i], "CIE-u")) cur_spectrum = DSuprime; else if (!strcasecmp(argv[i], "CIE-v")) cur_spectrum = DSvprime; else if (!strcasecmp(argv[i], "NIR")) cur_spectrum = DSnir; else { if (!strcmp(argv[i], "-")) { fprintf(stderr, "%s: cannot read spectra from stdin", argv[0]); return 1; } cur_spectrum = ncust_spec; spectr_file[ncust_spec++] = argv[i]; } continue; case 'g': /* MGF geometry file */ if (i >= argc-1) UsageExit(argv[0]); if (mgf_geometry != NULL) { fprintf(stderr, "%s: only one -g option allowed\n", argv[0]); return 1; } if (!strcmp(argv[++i], "-")) { if (used_stdin++) UsageExit(argv[i]); argv[i] = (char *)stdin_name; } mgf_geometry = argv[i]; continue; case '\0': /* input XML from stdin */ break; default: UsageExit(argv[0]); break; } break; } doneOptions: /* get XML input */ if (i >= argc) { if (xml_input == NULL) xml_input = def_template; } else if ((i < argc-1) | (xml_input != NULL)) { fprintf(stderr, "%s: only one XML input allowed\n", argv[0]); UsageExit(argv[0]); } else if (!strcmp(argv[i], "-")) { if (used_stdin++) UsageExit(argv[0]); xml_input = stdin_name; } else { xml_input = argv[i]; } /* wrap it! */ return !wrapBSDF(argv[0]); }