ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/rcomb.c
(Generate patch)

Comparing ray/src/util/rcomb.c (file contents):
Revision 2.2 by greg, Mon Dec 18 23:04:05 2023 UTC vs.
Revision 2.28 by greg, Fri Mar 28 00:06:36 2025 UTC

# Line 3 | Line 3 | static const char RCSid[] = "$Id$";
3   #endif
4   /*
5   * General component matrix combiner, operating on a row at a time.
6 + *
7 + * Multi-processing mode under Unix creates children that each work
8 + * on one input row at a time, fed by the original process.  Final conversion
9 + * and output to stdout is sorted by last child while its siblings send it
10 + * their record calculations.
11   */
12  
8 #include <errno.h>
13   #include <math.h>
14   #include "platform.h"
15 + #include "rtprocess.h"
16   #include "rtio.h"
12 #include "resolu.h"
17   #include "rmatrix.h"
18   #include "calcomp.h"
15 #include "paths.h"
19  
20   #ifndef M_PI
21   #define M_PI    3.14159265358979323846
22   #endif
23  
24 + #ifndef MAXCOMP
25   #define MAXCOMP         MAXCSAMP        /* #components we support */
26 + #endif
27  
28   /* Unary matrix operation(s) */
29   typedef struct {
# Line 55 | Line 60 | int            cur_row;                        /* current input/output row */
60   int             cur_col;                        /* current input/output column */
61   int             cur_chan;                       /* if we're looping channels */
62  
63 < static int      checksymbolic(ROPMAT *rop);
63 > SUBPROC         *cproc = NULL;                  /* child process array */
64 > int             nchildren = 0;                  /* # of child processes */
65 > int             inchild = -1;                   /* our child ID (-1: parent) */
66  
67 < static int
67 > extern int      checksymbolic(ROPMAT *rop);
68 >
69 > int
70   split_input(ROPMAT *rop)
71   {
72          if (rop->rmp == &rop->imx && !(rop->rmp = rmx_copy(&rop->imx))) {
# Line 69 | Line 78 | split_input(ROPMAT *rop)
78   }
79  
80   /* Check/set transform based on a reference input file */
81 < static int
81 > int
82   checkreffile(ROPMAT *rop)
83   {
84          static const char       *curRF = NULL;
# Line 132 | Line 141 | checkreffile(ROPMAT *rop)
141   }
142  
143   /* Compute conversion row from spectrum to one channel of RGB */
144 < static void
144 > void
145   rgbrow(ROPMAT *rop, int r, int p)
146   {
147          const int       nc = rop->imx.ncomp;
# Line 149 | Line 158 | rgbrow(ROPMAT *rop, int r, int p)
158   }
159  
160   /* Compute conversion row from spectrum to one channel of XYZ */
161 < static void
161 > void
162   xyzrow(ROPMAT *rop, int r, int p)
163   {
164          const int       nc = rop->imx.ncomp;
# Line 166 | Line 175 | xyzrow(ROPMAT *rop, int r, int p)
175   }
176  
177   /* Use the spectral sensitivity function to compute matrix coefficients */
178 < static void
179 < sensrow(ROPMAT *rop, int r, double (*sf)(SCOLOR sc, int ncs, const float wlpt[4]))
178 > void
179 > sensrow(ROPMAT *rop, int r, double (*sf)(const SCOLOR sc, int ncs, const float wlpt[4]))
180   {
181          const int       nc = rop->imx.ncomp;
182          int             i;
# Line 181 | Line 190 | sensrow(ROPMAT *rop, int r, double (*sf)(SCOLOR sc, in
190   }
191  
192   /* Check/set symbolic transform */
193 < static int
193 > int
194   checksymbolic(ROPMAT *rop)
195   {
196          const int       nc = rop->imx.ncomp;
197          const int       dt = rop->imx.dtype;
198 +        double          cf = 1;
199          int             i, j;
200                                          /* check suffix => reference file */
201          if (strchr(rop->preop.csym, '.') > rop->preop.csym)
# Line 206 | Line 216 | checksymbolic(ROPMAT *rop)
216                  int     comp = 0;
217                  switch (rop->preop.csym[j]) {
218                  case 'B':
219 +                case 'b':
220                          ++comp;
221                          /* fall through */
222                  case 'G':
223 +                case 'g':
224                          ++comp;
225                          /* fall through */
226                  case 'R':
227 +                case 'r':
228 +                        if (rop->preop.csym[j] <= 'Z')
229 +                                cf = 1./WHTEFFICACY;
230                          if (dt == DTxyze) {
231                                  for (i = 3; i--; )
232 <                                        rop->preop.cmat[j*nc+i] = 1./WHTEFFICACY *
218 <                                                        xyz2rgbmat[comp][i];
232 >                                        rop->preop.cmat[j*nc+i] = cf*xyz2rgbmat[comp][i];
233                          } else if (nc == 3)
234                                  rop->preop.cmat[j*nc+comp] = 1.;
235                          else
236                                  rgbrow(rop, j, comp);
237                          break;
238                  case 'Z':
239 +                case 'z':
240                          ++comp;
241                          /* fall through */
242                  case 'Y':
243 +                case 'y':
244                          ++comp;
245                          /* fall through */
246                  case 'X':
247 +                case 'x':
248 +                        if ((rop->preop.csym[j] <= 'Z') & (dt != DTxyze))
249 +                                cf = WHTEFFICACY;
250                          if (dt == DTxyze) {
251                                  rop->preop.cmat[j*nc+comp] = 1.;
252                          } else if (nc == 3) {
# Line 239 | Line 258 | checksymbolic(ROPMAT *rop)
258                          else
259                                  xyzrow(rop, j, comp);
260  
261 <                        for (i = nc*(dt != DTxyze); i--; )
262 <                                rop->preop.cmat[j*nc+i] *= WHTEFFICACY;
261 >                        for (i = nc*(cf != 1); i--; )
262 >                                rop->preop.cmat[j*nc+i] *= cf;
263                          break;
264                  case 'S':               /* scotopic (il)luminance */
265 +                        cf = WHTSCOTOPIC;
266 +                        /* fall through */
267 +                case 's':
268                          sensrow(rop, j, scolor2scotopic);
269 <                        for (i = nc; i--; )
270 <                                rop->preop.cmat[j*nc+i] *= WHTSCOTOPIC;
269 >                        for (i = nc*(cf != 1); i--; )
270 >                                rop->preop.cmat[j*nc+i] *= cf;
271                          break;
272                  case 'M':               /* melanopic (il)luminance */
273 +                        cf = WHTMELANOPIC;
274 +                        /* fall through */
275 +                case 'm':
276                          sensrow(rop, j, scolor2melanopic);
277 <                        for (i = nc; i--; )
278 <                                rop->preop.cmat[j*nc+i] *= WHTMELANOPIC;
277 >                        for (i = nc*(cf != 1); i--; )
278 >                                rop->preop.cmat[j*nc+i] *= cf;
279                          break;
280                  case 'A':               /* average component */
281 +                case 'a':
282                          for (i = nc; i--; )
283                                  rop->preop.cmat[j*nc+i] = 1./(double)nc;
284                          break;
# Line 267 | Line 293 | checksymbolic(ROPMAT *rop)
293          memcpy(rop->rmp->wlpart, WLPART, sizeof(rop->rmp->wlpart));
294          rop->rmp->ncomp = rop->preop.clen / nc;
295                                          /* decide on output type */
296 <        if (!strcmp(rop->preop.csym, "XYZ")) {
296 >        if (!strcasecmp(rop->preop.csym, "XYZ")) {
297                  if (dt <= DTspec)
298                          rop->rmp->dtype = DTxyze;
299 <        } else if (!strcmp(rop->preop.csym, "RGB")) {
299 >        } else if (!strcasecmp(rop->preop.csym, "RGB")) {
300                  if (dt <= DTspec)
301                          rop->rmp->dtype = DTrgbe;
302          } else if (rop->rmp->dtype == DTspec)
# Line 278 | Line 304 | checksymbolic(ROPMAT *rop)
304          return(1);
305   }
306  
307 < static int
307 > int
308   get_component_xfm(ROPMAT *rop)
309   {
310          int     i, j;
# Line 361 | Line 387 | get_component_xfm(ROPMAT *rop)
387          return(1);
388   }
389  
390 < static int
390 > int
391   apply_op(RMATRIX *dst, const RMATRIX *src, const RUNARYOP *ro)
392   {
393          if (ro->clen > 0) {
# Line 374 | Line 400 | apply_op(RMATRIX *dst, const RMATRIX *src, const RUNAR
400                          return(0);
401                  rmx_free(res);
402          } else if (dst != src)
403 <                memcpy(dst->mtx, src->mtx,
378 <                                sizeof(double)*dst->ncomp*dst->ncols*dst->nrows);
403 >                memcpy(dst->mtx, src->mtx, rmx_array_size(dst));
404          if (ro->nsf == dst->ncomp)
405                  rmx_scale(dst, ro->sca);
406          return(1);
407   }
408  
409 < static int
409 > int
410   open_input(ROPMAT *rop)
411   {
412          int     outtype;
# Line 403 | Line 428 | open_input(ROPMAT *rop)
428   }
429  
430   /* Return nominal wavelength associated with input component (return nm) */
431 < static double
431 > double
432   l_wavelength(char *nam)
433   {
434          double  comp = argument(1);
# Line 427 | Line 452 | l_wavelength(char *nam)
452   }
453  
454   /* Return ith input with optional channel selector */
455 < static double
455 > double
456   l_chanin(char *nam)
457   {
458          double  inp = argument(1);
# Line 452 | Line 477 | l_chanin(char *nam)
477          return(mop[mi].rmp->mtx[cur_col*in_ncomp + chan]);
478   }
479  
480 < static int
480 > int
481   initialize(RMATRIX *imp)
482   {
483          int     i;
# Line 465 | Line 490 | initialize(RMATRIX *imp)
490                  restype = mop[i].rmp->dtype;
491                  if (!imp->dtype || (restype = rmx_newtype(restype, imp->dtype)) > 0)
492                          imp->dtype = restype;
493 <                else
493 >                else if (!nowarn)
494                          fprintf(stderr, "%s: warning - data type mismatch\n",
495                                          mop[i].inspec);
496                  if (!i) {
# Line 499 | Line 524 | initialize(RMATRIX *imp)
524          return(1);
525   }
526  
527 < static void
527 > void
528   output_headinfo(FILE *fp)
529   {
530          int     i;
# Line 522 | Line 547 | output_headinfo(FILE *fp)
547          }
548   }
549  
550 < static int
551 < combine_input(ROPMAT *res, FILE *fout)
550 > int
551 > spawned_children(int np)
552   {
553 <        int     set_r, set_c;
554 <        RMATRIX *tmp = NULL;
555 <        int     co_set;
556 <        int     i;
557 <                                        /* allocate input row buffers */
553 >        int     i, rv;
554 >
555 > #if defined(_WIN32) || defined(_WIN64)
556 >        if (np > 1) {
557 >                if (!nowarn)
558 >                        fputs("Warning: only one process under Windows\n", stderr);
559 >                np = 1;
560 >        } else
561 > #endif
562 >        if ((in_nrows > 0) & (np*4 > in_nrows))
563 >                np = in_nrows/4;
564 >                                /* we'll be doing a row at a time */
565          for (i = 0; i < nmats; i++) {
566 <                mop[i].imx.nrows = 1;   /* we'll be doing a row at a time */
566 >                mop[i].imx.nrows = 1;
567                  if (!rmx_prepare(&mop[i].imx))
568                          goto memerror;
569                  if (mop[i].rmp != &mop[i].imx) {
# Line 540 | Line 572 | combine_input(ROPMAT *res, FILE *fout)
572                                  goto memerror;
573                  }
574          }
575 <                                        /* prep output row buffers */
576 <        if (mcat || res->preop.clen > 0) {
577 <                if (!split_input(res))  /* need separate buffer */
546 <                        return(0);
547 <                if (res->preop.clen > 0)
548 <                        res->rmp->ncomp = res->preop.clen / res->imx.ncomp;
549 <                res->rmp->nrows = 1;
550 <                if (!mcat | !mcat_last && !rmx_prepare(res->rmp))
575 >                                /* prep output row buffer(s) */
576 >        if (mop[nmats].preop.clen > 0) {
577 >                if (!split_input(&mop[nmats]))  /* need separate buffer */
578                          goto memerror;
579 +                mop[nmats].rmp->ncomp = mop[nmats].preop.clen /
580 +                                        mop[nmats].imx.ncomp;
581          }
582 <        if (mcat && mcat_last &&
583 <                        !(tmp = rmx_alloc(1, res->imx.ncols, res->rmp->ncomp)))
582 >        mop[nmats].imx.nrows = 1;
583 >        if (!rmx_prepare(&mop[nmats].imx))
584                  goto memerror;
585 <        res->imx.nrows = 1;
586 <        if (!rmx_prepare(&res->imx))
585 >        if (mop[nmats].rmp != &mop[nmats].imx) {
586 >                mop[nmats].rmp->nrows = 1;
587 >                if (!rmx_prepare(mop[nmats].rmp))
588 >                        goto memerror;
589 >        }
590 >        if (np <= 1) {          /* single process return */
591 > #ifdef getc_unlocked
592 >                for (i = 0; i < nmats; i++)
593 >                        flockfile(mop[i].infp);
594 >                flockfile(stdout);
595 > #endif
596 >                return(0);
597 >        }
598 >        fflush(stdout);         /* flush header & spawn children */
599 >        nchildren = np + 1;     /* extra child to sequence output */
600 >        cproc = (SUBPROC *)malloc(sizeof(SUBPROC)*nchildren);
601 >        if (!cproc)
602                  goto memerror;
603 +        for (i = nchildren; i--; ) cproc[i] = sp_inactive;
604 +        cproc[nchildren-1].flags |= PF_FILT_OUT;
605 +                                /* start each child from parent */
606 +        for (i = 0; i < nchildren; i++)
607 +                if ((rv = open_process(&cproc[i], NULL)) <= 0)
608 +                        break;  /* child breaks here */
609 +        if (rv < 0) {
610 +                perror("fork"); /* WTH? */
611 +                close_processes(cproc, i);
612 +                exit(1);
613 +        }
614 +        if (i != nchildren-1) { /* last child is sole reader */
615 +                int     j = i;
616 +                while (j-- > 0) {
617 +                        close(cproc[j].r);
618 +                        cproc[j].r = -1;
619 +                }
620 +        }
621 +        if (rv > 0)
622 +                return(1);      /* parent return value */
623 +
624 +        inchild = i;            /* else set our child index */
625 +        while (i-- > 0)         /* only parent writes siblings */
626 +                close(cproc[i].w);
627 +
628 +        i = nmats;              /* close matrix streams (carefully) */
629 +        while (i-- > 0) {
630 +                if (mop[i].infp != stdin) {
631 +                        close(fileno(mop[i].infp));     /* avoid lseek() */
632 +                        fclose(mop[i].infp);            /* ! pclose() */
633 +                }
634 +                mop[i].infp = NULL;
635 +        }
636 +        fpurge(stdin);          /* discard previously buffered input */
637 +
638 +        if (inchild == nchildren-1)
639 +                return(-1);     /* output process return value */
640 +
641 +        i = nmats;              /* get matrix rows from parent */
642 +        while (i-- > 0) {
643 +                mop[i].infp = stdin;
644 +                mop[i].imx.dtype = DTrmx_native;
645 +                mop[i].imx.pflags &= ~RMF_SWAPIN;
646 +        }
647 + #ifdef getc_unlocked
648 +        flockfile(stdin);
649 + #endif
650 +        mop[nmats].rmp->dtype = DTrmx_native;
651 +        return(0);              /* worker child return value */
652 + memerror:
653 +        fputs("Out of memory in spawned_children()\n", stderr);
654 +        exit(1);
655 + }
656 +
657 + int
658 + parent_loop(void)
659 + {
660 +        int     i;
661 +
662 +        rmx_reset(&mop[nmats].imx);             /* not touching output side */
663 +        if (mop[nmats].rmp != &mop[nmats].imx) {
664 +                rmx_free(mop[nmats].rmp);
665 +                mop[nmats].rmp = &mop[nmats].imx;
666 +        }
667 + #ifdef getc_unlocked
668 +        for (i = 0; i < nmats; i++)             /* we handle matrix inputs */
669 +                flockfile(mop[i].infp);
670 + #endif
671 +                                                /* load & send rows to kids */
672 +        for (cur_row = 0; (in_nrows <= 0) | (cur_row < in_nrows); cur_row++) {
673 +            int         wfd = cproc[cur_row % (nchildren-1)].w;
674 +            for (i = 0; i < nmats; i++)
675 +                if (!rmx_load_row(mop[i].imx.mtx, &mop[i].imx, mop[i].infp)) {
676 +                        if (cur_row > in_nrows) /* unknown #input rows? */
677 +                                break;
678 +                        fprintf(stderr, "%s: load error at row %d\n",
679 +                                        mop[i].inspec, cur_row);
680 +                        return(0);
681 +                }
682 +            if (i < nmats)
683 +                break;
684 +            for (i = 0; i < nmats; i++)
685 +                if (writebuf(wfd, mop[i].imx.mtx, rmx_array_size(&mop[i].imx))
686 +                                        != rmx_array_size(&mop[i].imx)) {
687 +                        fprintf(stderr, "%s: write error at row %d\n",
688 +                                        mop[i].inspec, cur_row);
689 +                        return(0);
690 +                }
691 +        }
692 +        i = close_processes(cproc, nchildren);  /* collect family */
693 +        free(cproc); cproc = NULL; nchildren = 0;
694 +        if (i < 0) {
695 +                if (!nowarn)
696 +                        fputs("Warning: lost child process\n", stderr);
697 +                return(1);
698 +        }
699 +        if (i > 0) {
700 +                fprintf(stderr, "Child exited with status %d\n", i);
701 +                return(0);
702 +        }
703 +        return(1);                              /* return success! */
704 + }
705 +
706 + int
707 + combine_input(void)
708 + {
709 +        const int       row0 = (inchild >= 0)*inchild;
710 +        const int       rstep = nchildren ? nchildren-1 : 1;
711 +        ROPMAT          *res = &mop[nmats];
712 +        int             set_r, set_c;
713 +        RMATRIX         *tmp = NULL;
714 +        int             co_set;
715 +        int             i;
716 +
717 +        if (mcat_last && !(tmp = rmx_alloc(1, res->imx.ncols, res->rmp->ncomp))) {
718 +                fputs("Out of buffer space in combine_input()\n", stderr);
719 +                return(0);
720 +        }
721                                          /* figure out what the user set */
722          co_set = fundefined("co");
723          if (!co_set)
# Line 571 | Line 733 | combine_input(ROPMAT *res, FILE *fout)
733          } else                          /* save a little time */
734                  set_r = set_c = 0;
735                                          /* read/process row-by-row */
736 <        for (cur_row = 0; (in_nrows <= 0) | (cur_row < in_nrows); cur_row++) {
736 >        for (cur_row = row0; (in_nrows <= 0) | (cur_row < in_nrows); cur_row += rstep) {
737              RMATRIX     *mres = NULL;
738 <            for (i = 0; i < nmats; i++) {
738 >            for (i = 0; i < nmats; i++)
739                  if (!rmx_load_row(mop[i].imx.mtx, &mop[i].imx, mop[i].infp)) {
740 <                        if (in_nrows <= 0)      /* normal end? */
741 <                                goto loop_exit;
742 <                        fprintf(stderr, "%s: read error at row %d\n",
740 >                        if (cur_row > in_nrows) /* unknown #input rows? */
741 >                                break;
742 >                        fprintf(stderr, "%s: load error at row %d\n",
743                                          mop[i].inspec, cur_row);
744                          return(0);
745                  }
746 +            if (i < nmats)
747 +                break;
748 +            for (i = 0; i < nmats; i++)
749                  if (!apply_op(mop[i].rmp, &mop[i].imx, &mop[i].preop))
750                          return(0);
586            }
751              if (set_r) varset("r", '=', cur_row);
752              for (cur_col = 0; cur_col < in_ncols; cur_col++) {
753                  if (set_c) varset("c", '=', cur_col);
# Line 621 | Line 785 | combine_input(ROPMAT *res, FILE *fout)
785              }
786              rmx_free(mres); mres = NULL;
787              if (!rmx_write_data(res->rmp->mtx, res->rmp->ncomp,
788 <                                res->rmp->ncols, res->rmp->dtype, fout))
788 >                                res->rmp->ncols, res->rmp->dtype, stdout) ||
789 >                                 (inchild >= 0 && fflush(stdout) == EOF)) {
790 >                fprintf(stderr, "Conversion/write error at row %d\n",
791 >                                cur_row);
792                  return(0);
793 +            }
794          }
795 < loop_exit:
796 < #if 0           /* we're about to exit, so who cares? */
797 <        rmx_free(tmp);                  /* clean up */
798 <        rmx_reset(res->rmp);
799 <        rmx_reset(&res->imx);
800 <        for (i = 0; i < nmats; i++) {
801 <                rmx_reset(mop[i].rmp);
795 >        return(inchild >= 0 || fflush(stdout) != EOF);
796 > multerror:
797 >        fputs("Unexpected matrix multiply error\n", stderr);
798 >        return(0);
799 > }
800 >
801 > int
802 > output_loop(void)
803 > {
804 >        const size_t    row_size = rmx_array_size(mop[nmats].rmp);
805 >        int             cur_child = 0;
806 >        int             i = nmats;
807 >
808 >        while (i-- > 0) {                               /* free input buffers */
809                  rmx_reset(&mop[i].imx);
810 <                if (mop[i].inspec[0] == '!')
811 <                        pclose(mop[i].infp);
812 <                else if (mop[i].inspec != stdin_name)
813 <                        fclose(mop[i].infp);
639 <                mop[i].infp = NULL;
810 >                if (mop[i].rmp != &mop[i].imx) {
811 >                        rmx_free(mop[i].rmp);
812 >                        mop[i].rmp = &mop[i].imx;
813 >                }
814          }
815 +        if (mop[nmats].rmp != &mop[nmats].imx)          /* output is split? */
816 +                rmx_reset(&mop[nmats].imx);
817 + #ifdef getc_unlocked
818 +        flockfile(stdout);                              /* we own this, now */
819   #endif
820 <        return(fflush(fout) != EOF);
821 < memerror:
822 <        fputs("Out of buffer space in combine_input()\n", stderr);
823 <        return(0);
824 < multerror:
825 <        fputs("Unexpected matrix multiply error in combine_input()\n", stderr);
826 <        return(0);
820 >        for ( ; ; ) {                                   /* loop until no more */
821 >                ssize_t         rv;
822 >                rv = readbuf(cproc[cur_child].r, mop[nmats].rmp->mtx, row_size);
823 >                if (!rv)                                /* out of rows? */
824 >                        break;
825 >                if (rv != row_size) {
826 >                        fputs("Read error\n", stderr);
827 >                        return(0);
828 >                }                                       /* do final conversion */
829 >                if (!rmx_write_data(mop[nmats].rmp->mtx, mop[nmats].rmp->ncomp,
830 >                                mop[nmats].rmp->ncols, mop[nmats].rmp->dtype, stdout)) {
831 >                        fputs("Conversion/write error\n", stderr);
832 >                        return(0);
833 >                }
834 >                cur_child++;
835 >                cur_child *= (cur_child < inchild);     /* loop over workers */
836 >        }
837 >        return(fflush(stdout) != EOF);
838   }
839  
840 < static int
840 > int
841   get_factors(double da[], int n, char *av[])
842   {
843          int     ac;
# Line 658 | Line 847 | get_factors(double da[], int n, char *av[])
847          return(ac);
848   }
849  
850 < static void
850 > void
851   resize_inparr(int n2alloc)
852   {
853          int     i;
854  
855 <        for (i = nmats; i > n2alloc; i--) {
855 >        if (n2alloc == nall)
856 >                return;
857 >        for (i = nall; i-- > n2alloc; ) {
858                  rmx_reset(&mop[i].imx);
859                  if (mop[i].rmp != &mop[i].imx)
860                          rmx_free(mop[i].rmp);
# Line 673 | Line 864 | resize_inparr(int n2alloc)
864                  fputs("Out of memory in resize_inparr()\n", stderr);
865                  exit(1);
866          }
867 <        if (n2alloc > nmats)
868 <                memset(mop+nmats, 0, (n2alloc-nmats)*sizeof(ROPMAT));
867 >        if (n2alloc > nall)
868 >                memset(mop+nall, 0, (n2alloc-nall)*sizeof(ROPMAT));
869          nall = n2alloc;
870   }
871  
# Line 687 | Line 878 | main(int argc, char *argv[])
878          const char      *defCsym = NULL;
879          int             echoheader = 1;
880          int             stdin_used = 0;
881 +        int             nproc = 1;
882          const char      *mcat_spec = NULL;
883          int             n2comp = 0;
884          uby8            comp_ndx[128];
# Line 714 | Line 906 | main(int argc, char *argv[])
906                          case 'h':
907                                  echoheader = !echoheader;
908                                  break;
909 +                        case 'n':
910 +                                nproc = atoi(argv[++i]);
911 +                                if (nproc <= 0)
912 +                                        goto userr;
913 +                                break;
914                          case 'e':
915                                  if (!n) goto userr;
916                                  comp_ndx[n2comp++] = i++;
# Line 752 | Line 949 | main(int argc, char *argv[])
949                                  }
950                                  break;
951                          case 'C':
952 +                                mcat_last = 0;
953                                  if (!n || isflt(argv[i+1]))
954                                          goto userr;
955                                  defCsym = mop[nmats].preop.csym = argv[++i];
956                                  mop[nmats].preop.clen = 0;
759                                mcat_last = 0;
957                                  break;
958                          case 'c':
959 +                                mcat_last = 0;
960                                  if (n && !isflt(argv[i+1])) {
961                                          mop[nmats].preop.csym = argv[++i];
962                                          mop[nmats].preop.clen = 0;
# Line 774 | Line 972 | main(int argc, char *argv[])
972                                          goto userr;
973                                  }
974                                  mop[nmats].preop.csym = NULL;
777                                mcat_last = 0;
975                                  break;
976                          case 'm':
977 +                                mcat_last = 1;
978                                  if (!n) goto userr;
979                                  if (argv[++i][0] == '-' && !argv[i][1]) {
980                                          if (stdin_used++) goto stdin_error;
981                                          mcat_spec = stdin_name;
982                                  } else
983                                          mcat_spec = argv[i];
786                                mcat_last = 1;
984                                  break;
985                          default:
986                                  fprintf(stderr, "%s: unknown option '%s'\n",
# Line 851 | Line 1048 | main(int argc, char *argv[])
1048                  fprintf(stderr, "%s: unsupported output format\n", argv[0]);
1049                  return(1);
1050          }
1051 <                                        /* process & write rows */
1052 <        return(combine_input(&mop[nmats], stdout) ? 0 : 1);
1051 >        doptimize(1);                   /* optimize definitions */
1052 >        i = spawned_children(nproc);    /* create multiple processes if requested */
1053 >        if (i > 0)                      /* running in parent process? */
1054 >                return(parent_loop() ? 0 : 1);
1055 >        if (i < 0)                      /* running in output process? */
1056 >                return(output_loop() ? 0 : 1);
1057 >                                        /* else we are a worker process */
1058 >        return(combine_input() ? 0 : 1);
1059   stdin_error:
1060          fprintf(stderr, "%s: %s used for more than one input\n",
1061                          argv[0], stdin_name);
1062          return(1);
1063   userr:
1064          fprintf(stderr,
1065 <        "Usage: %s [-h][-f{adfc}][-e expr][-f file][-s sf .. | -c ce ..] m1 .. -m mcat > mres\n",
1065 >        "Usage: %s [-h][-f{adfc}][-n nproc][-e expr][-f file][-s sf .. | -c ce ..] m1 .. -m mcat > mres\n",
1066                          argv[0]);
1067          return(1);
1068   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines