--- ray/src/cal/rsplit.c 2020/03/31 16:39:01 1.12 +++ ray/src/cal/rsplit.c 2024/06/07 18:19:22 1.16 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: rsplit.c,v 1.12 2020/03/31 16:39:01 greg Exp $"; +static const char RCSid[] = "$Id: rsplit.c,v 1.16 2024/06/07 18:19:22 greg Exp $"; #endif /* * rsplit.c - split input into multiple output streams @@ -19,23 +19,27 @@ static const char RCSid[] = "$Id: rsplit.c,v 1.12 2020 #define MAXFILE 512 /* maximum number of files */ -static int swapped = 0; /* input is byte-swapped */ +int swapped = 0; /* input is byte-swapped */ -static FILE *output[MAXFILE]; -static int ncomp[MAXFILE]; -static int bytsiz[MAXFILE]; -static int hdrflags[MAXFILE]; -static const char *format[MAXFILE]; -static int termc[MAXFILE]; -static int nfiles = 0; +struct outstream { /* structure to hold output stream info */ + const char *outspec; /* output specification */ + FILE *output; /* output stream */ + int ncomp; /* component count */ + int bytsiz; /* bytes/component if binary */ + int hdrflags; /* header output flags */ + const char *format; /* data format */ + int termc; /* data separation character */ +} *rofile = NULL; -static RESOLU ourres = {PIXSTANDARD, 0, 0}; +int nfiles = 0; /* output file count */ -static char buf[16384]; /* input buffer used in scanOK() */ +RESOLU ourres = {PIXSTANDARD, 0, 0}; +char buf[16384]; /* input buffer used in scanOK() */ + /* process header line */ -static int +int headline(char *s, void *p) { extern const char FMTSTR[]; @@ -55,14 +59,14 @@ headline(char *s, void *p) } i = nfiles; while (i--) /* else copy line to output streams */ - if (hdrflags[i] & DOHEADER) - fputs(s, output[i]); + if (rofile[i].hdrflags & DOHEADER) + fputs(s, rofile[i].output); return(1); } /* scan field into buffer up to and including terminating byte */ -static int +int scanOK(int termc) { int skip_white = (termc == ' '); @@ -96,13 +100,20 @@ main(int argc, char *argv[]) int append = 0; long outcnt = 0; int bininp = 0; + int nstdoutcomp = 0; int curterm = '\n'; int curncomp = 1; int curbytes = 0; int curflags = 0; const char *curfmt = "ascii"; - int i; + int i; + rofile = (struct outstream *)calloc(argc-1, sizeof(struct outstream)); + if (!rofile) { + fputs(argv[0], stderr); + fputs(": not enough memory\n", stderr); + return(1); + } for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { switch (argv[i][1]) { @@ -181,16 +192,20 @@ main(int argc, char *argv[]) } bininp += (curbytes > 0); break; - case '\0': - needres |= (curflags & DORESOLU); - termc[nfiles] = curterm; - hdrflags[nfiles] = curflags; - output[nfiles] = stdout; + case '\0': /* stdout */ + if (!nstdoutcomp) { /* first use? */ + needres |= (curflags & DORESOLU); + rofile[nfiles].hdrflags = curflags; + } + rofile[nfiles].output = stdout; if (curbytes > 0) - SET_FILE_BINARY(output[nfiles]); - format[nfiles] = curfmt; - ncomp[nfiles] = curncomp; - bytsiz[nfiles++] = curbytes; + SET_FILE_BINARY(rofile[nfiles].output); + rofile[nfiles].termc = curterm; + rofile[nfiles].format = curfmt; + nstdoutcomp += + rofile[nfiles].ncomp = curncomp; + rofile[nfiles].bytsiz = curbytes; + rofile[nfiles++].outspec = argv[i]; break; badopt:; default: @@ -198,21 +213,38 @@ main(int argc, char *argv[]) fputs(": bad option\n", stderr); return(1); } + } else if (argv[i][0] == '.' && !argv[i][1]) { + rofile[nfiles].output = NULL; /* discard data */ + rofile[nfiles].termc = curterm; + rofile[nfiles].format = curfmt; + rofile[nfiles].ncomp = curncomp; + rofile[nfiles].bytsiz = curbytes; + rofile[nfiles++].outspec = argv[i]; } else if (argv[i][0] == '!') { needres |= (curflags & DORESOLU); - termc[nfiles] = curterm; - hdrflags[nfiles] = curflags; - if ((output[nfiles] = popen(argv[i]+1, "w")) == NULL) { + rofile[nfiles].hdrflags = curflags; + rofile[nfiles].termc = curterm; + if ((rofile[nfiles].output = popen(argv[i]+1, "w")) == NULL) { fputs(argv[i], stderr); fputs(": cannot start command\n", stderr); return(1); } if (curbytes > 0) - SET_FILE_BINARY(output[nfiles]); - format[nfiles] = curfmt; - ncomp[nfiles] = curncomp; - bytsiz[nfiles++] = curbytes; + SET_FILE_BINARY(rofile[nfiles].output); + rofile[nfiles].format = curfmt; + rofile[nfiles].ncomp = curncomp; + rofile[nfiles].bytsiz = curbytes; + rofile[nfiles++].outspec = argv[i]; } else { + int j = nfiles; + while (j--) /* check duplicates */ + if (!strcmp(argv[i], rofile[j].outspec)) { + fputs(argv[0], stderr); + fputs(": duplicate output: ", stderr); + fputs(argv[i], stderr); + fputc('\n', stderr); + return(1); + } if (append & (curflags != 0)) { fputs(argv[0], stderr); fputs(": -a option incompatible with -oh and -oH\n", @@ -220,56 +252,58 @@ main(int argc, char *argv[]) return(1); } needres |= (curflags & DORESOLU); - termc[nfiles] = curterm; - hdrflags[nfiles] = curflags; + rofile[nfiles].hdrflags = curflags; + rofile[nfiles].termc = curterm; if (!append & !force && access(argv[i], F_OK) == 0) { fputs(argv[i], stderr); fputs(": file exists -- use -f to overwrite\n", stderr); return(1); } - output[nfiles] = fopen(argv[i], append ? "a" : "w"); - if (output[nfiles] == NULL) { + rofile[nfiles].output = fopen(argv[i], append ? "a" : "w"); + if (!rofile[nfiles].output) { fputs(argv[i], stderr); fputs(": cannot open for output\n", stderr); return(1); } if (curbytes > 0) - SET_FILE_BINARY(output[nfiles]); - format[nfiles] = curfmt; - ncomp[nfiles] = curncomp; - bytsiz[nfiles++] = curbytes; + SET_FILE_BINARY(rofile[nfiles].output); + rofile[nfiles].format = curfmt; + rofile[nfiles].ncomp = curncomp; + rofile[nfiles].bytsiz = curbytes; + rofile[nfiles++].outspec = argv[i]; } - if (nfiles >= MAXFILE) { - fputs(argv[0], stderr); - fputs(": too many output streams\n", stderr); - return(1); - } } if (!nfiles) { fputs(argv[0], stderr); fputs(": no output streams\n", stderr); return(1); + } /* reduce array to size we need */ + rofile = (struct outstream *)realloc(rofile, nfiles*sizeof(struct outstream)); + if (!rofile) { + fputs(argv[0], stderr); + fputs(": realloc() failed!\n", stderr); + return(1); } if (bininp) /* binary input? */ SET_FILE_BINARY(stdin); #ifdef getc_unlocked /* avoid lock/unlock overhead */ flockfile(stdin); for (i = nfiles; i--; ) - flockfile(output[i]); + if (rofile[i].output != NULL) + ftrylockfile(rofile[i].output); #endif /* load/copy header */ if (inpflags & DOHEADER && getheader(stdin, headline, NULL) < 0) { fputs(argv[0], stderr); - fputs(": cannot get header from standard input\n", + fputs(": cannot read header from standard input\n", stderr); return(1); } /* handle resolution string */ if (inpflags & DORESOLU && !fgetsresolu(&ourres, stdin)) { fputs(argv[0], stderr); - fputs(": cannot get resolution string from standard input\n", - stderr); + fputs(": bad resolution string on standard input\n", stderr); return(1); } if (needres && (ourres.xr <= 0) | (ourres.yr <= 0)) { @@ -287,57 +321,62 @@ main(int argc, char *argv[]) } } for (i = 0; i < nfiles; i++) { /* complete headers */ - if (hdrflags[i] & DOHEADER) { + if (rofile[i].hdrflags & DOHEADER) { if (!(inpflags & DOHEADER)) - newheader("RADIANCE", output[i]); - printargs(argc, argv, output[i]); - fprintf(output[i], "NCOMP=%d\n", ncomp[i]); - if (format[i] != NULL) { + newheader("RADIANCE", rofile[i].output); + printargs(argc, argv, rofile[i].output); + fprintf(rofile[i].output, "NCOMP=%d\n", rofile[i].output==stdout ? + nstdoutcomp : rofile[i].ncomp); + if (rofile[i].format != NULL) { extern const char BIGEND[]; - if ((format[i][0] == 'f') | - (format[i][0] == 'd')) { - fputs(BIGEND, output[i]); + if (rofile[i].bytsiz > 1) { + fputs(BIGEND, rofile[i].output); fputs(nativebigendian() ^ swapped ? - "1\n" : "0\n", output[i]); + "1\n" : "0\n", rofile[i].output); } - fputformat(format[i], output[i]); + fputformat(rofile[i].format, rofile[i].output); } - fputc('\n', output[i]); + fputc('\n', rofile[i].output); } - if (hdrflags[i] & DORESOLU) - fputsresolu(&ourres, output[i]); + if (rofile[i].hdrflags & DORESOLU) + fputsresolu(&ourres, rofile[i].output); } do { /* main loop */ for (i = 0; i < nfiles; i++) { - if (bytsiz[i] > 0) { /* binary output */ - if (getbinary(buf, bytsiz[i], ncomp[i], - stdin) < ncomp[i]) + if (rofile[i].bytsiz > 0) { /* binary output */ + if (getbinary(buf, rofile[i].bytsiz, rofile[i].ncomp, + stdin) != rofile[i].ncomp) break; - if (putbinary(buf, bytsiz[i], ncomp[i], - output[i]) < ncomp[i]) + if (rofile[i].output != NULL && + putbinary(buf, rofile[i].bytsiz, rofile[i].ncomp, + rofile[i].output) != rofile[i].ncomp) break; - } else if (ncomp[i] > 1) { /* N-field output */ - int n = ncomp[i]; + } else if (rofile[i].ncomp > 1) { /* N-field output */ + int n = rofile[i].ncomp; while (n--) { - if (!scanOK(termc[i])) + if (!scanOK(rofile[i].termc)) break; - if (fputs(buf, output[i]) == EOF) + if (rofile[i].output != NULL && + fputs(buf, rofile[i].output) == EOF) break; } if (n >= 0) /* fell short? */ break; - if (termc[i] != '\n') /* add EOL if none */ - fputc('\n', output[i]); + if ((rofile[i].output != NULL) & /* add EOL if none */ + (rofile[i].termc != '\n')) + fputc('\n', rofile[i].output); } else { /* 1-field output */ - if (!scanOK(termc[i])) + if (!scanOK(rofile[i].termc)) break; - if (fputs(buf, output[i]) == EOF) - break; - if (termc[i] != '\n') /* add EOL if none */ - fputc('\n', output[i]); + if (rofile[i].output != NULL) { + if (fputs(buf, rofile[i].output) == EOF) + break; + if (rofile[i].termc != '\n') /* add EOL? */ + fputc('\n', rofile[i].output); + } } /* skip input EOL? */ - if (!bininp && termc[nfiles-1] != '\n') { + if (!bininp && rofile[nfiles-1].termc != '\n') { int c = getchar(); if ((c != '\n') & (c != EOF)) ungetc(c, stdin);