ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/rmtxop.c
Revision: 2.38
Committed: Fri Apr 4 18:06:48 2025 UTC (3 weeks, 6 days ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.37: +1 -5 lines
Log Message:
perf(rmtxop,rcomb): Switched default internal data type from double to float

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rmtxop.c,v 2.37 2025/04/04 01:48:25 greg Exp $";
3 #endif
4 /*
5 * General component matrix operations.
6 */
7
8 #include <errno.h>
9 #include "rtio.h"
10 #include "rmatrix.h"
11 #include "platform.h"
12
13 /* Unary matrix operation(s) */
14 typedef struct {
15 double cmat[MAXCOMP*MAXCOMP]; /* component transformation */
16 double sca[MAXCOMP]; /* scalar coefficients */
17 const char *csym; /* symbolic coefs or file */
18 short clen; /* number of coefficients */
19 short nsf; /* number of scalars */
20 short transpose; /* do transpose? */
21 } RUNARYOP;
22
23 /* Matrix input source and requested operation(s) */
24 typedef struct {
25 const char *inspec; /* input specification */
26 RMPref rmp; /* matrix preference */
27 RUNARYOP preop; /* unary operation(s) */
28 RMATRIX *mtx; /* original matrix if loaded */
29 int binop; /* binary op with next (or 0) */
30 } ROPMAT;
31
32 int verbose = 0; /* verbose reporting? */
33
34 /* Load matrix */
35 int
36 loadmatrix(ROPMAT *rop)
37 {
38 if (rop->mtx != NULL) /* already loaded? */
39 return(0);
40
41 rop->mtx = rmx_load(rop->inspec, rop->rmp);
42
43 return(!rop->mtx ? -1 : 1);
44 }
45
46 extern int checksymbolic(ROPMAT *rop);
47
48 /* Check/set transform based on a reference input file */
49 int
50 checkreffile(ROPMAT *rop)
51 {
52 static const char *curRF = NULL;
53 static RMATRIX refm;
54 const int nc = rop->mtx->ncomp;
55 int i;
56
57 if (!curRF || strcmp(rop->preop.csym, curRF)) {
58 FILE *fp = fopen(rop->preop.csym, "rb");
59 if (!rmx_load_header(&refm, fp)) {
60 fprintf(stderr, "%s: cannot read info header\n",
61 rop->preop.csym);
62 curRF = NULL;
63 if (fp) fclose(fp);
64 return(-1);
65 }
66 fclose(fp);
67 curRF = rop->preop.csym;
68 }
69 if (refm.ncomp == 3) {
70 rop->preop.csym = (refm.dtype == DTxyze) ? "XYZ" : "RGB";
71 return(checksymbolic(rop));
72 }
73 if (refm.ncomp == 2) {
74 fprintf(stderr, "%s: cannot convert to 2 components\n",
75 curRF);
76 return(-1);
77 }
78 if (refm.ncomp == 1) {
79 rop->preop.csym = "Y"; /* XXX big assumption */
80 return(checksymbolic(rop));
81 }
82 if (refm.ncomp == nc &&
83 !memcmp(refm.wlpart, rop->mtx->wlpart, sizeof(refm.wlpart)))
84 return(0); /* nothing to do */
85
86 if ((nc <= 3) | (nc > MAXCSAMP) | (refm.ncomp > MAXCSAMP)) {
87 fprintf(stderr, "%s: cannot resample from %d to %d components\n",
88 curRF, nc, refm.ncomp);
89 return(-1);
90 }
91 rop->preop.clen = refm.ncomp * nc; /* compute spec to ref */
92
93 for (i = 0; i < nc; i++) {
94 SCOLOR scstim, scresp;
95 int j;
96 memset(scstim, 0, sizeof(COLORV)*nc);
97 scstim[i] = 1.f;
98 convertscolor(scresp, refm.ncomp, refm.wlpart[0], refm.wlpart[3],
99 scstim, nc, rop->mtx->wlpart[0], rop->mtx->wlpart[3]);
100 for (j = refm.ncomp; j-- > 0; )
101 rop->preop.cmat[j*nc + i] = scresp[j];
102 }
103 memcpy(rop->mtx->wlpart, refm.wlpart, sizeof(rop->mtx->wlpart));
104 return(0);
105 }
106
107 /* Compute conversion row from spectrum to one channel of RGB */
108 void
109 rgbrow(ROPMAT *rop, int r, int p)
110 {
111 const int nc = rop->mtx->ncomp;
112 const float * wlp = rop->mtx->wlpart;
113 int i;
114
115 for (i = nc; i--; ) {
116 int nmEnd = wlp[0] + (wlp[3] - wlp[0])*i/nc;
117 int nmStart = wlp[0] + (wlp[3] - wlp[0])*(i+1)/nc;
118 COLOR crgb;
119 spec_rgb(crgb, nmStart, nmEnd);
120 rop->preop.cmat[r*nc+i] = crgb[p];
121 }
122 }
123
124 /* Compute conversion row from spectrum to one channel of XYZ */
125 void
126 xyzrow(ROPMAT *rop, int r, int p)
127 {
128 const int nc = rop->mtx->ncomp;
129 const float * wlp = rop->mtx->wlpart;
130 int i;
131
132 for (i = nc; i--; ) {
133 int nmEnd = wlp[0] + (wlp[3] - wlp[0])*i/nc;
134 int nmStart = wlp[0] + (wlp[3] - wlp[0])*(i+1)/nc;
135 COLOR cxyz;
136 spec_cie(cxyz, nmStart, nmEnd);
137 rop->preop.cmat[r*nc+i] = cxyz[p];
138 }
139 }
140
141 /* Use the spectral sensitivity function to compute matrix coefficients */
142 void
143 sensrow(ROPMAT *rop, int r, double (*sf)(const SCOLOR sc, int ncs, const float wlpt[4]))
144 {
145 const int nc = rop->mtx->ncomp;
146 int i;
147
148 for (i = nc; i--; ) {
149 SCOLOR sclr;
150 memset(sclr, 0, sizeof(COLORV)*nc);
151 sclr[i] = 1.f;
152 rop->preop.cmat[r*nc+i] = (*sf)(sclr, nc, rop->mtx->wlpart);
153 }
154 }
155
156 /* Check/set symbolic transform */
157 int
158 checksymbolic(ROPMAT *rop)
159 {
160 const int nc = rop->mtx->ncomp;
161 const int dt = rop->mtx->dtype;
162 double cf = 1;
163 int i, j;
164 /* check suffix => reference file */
165 if (strchr(rop->preop.csym, '.') > rop->preop.csym)
166 return(checkreffile(rop));
167
168 if (nc < 3) {
169 fprintf(stderr, "%s: -c '%s' requires at least 3 components\n",
170 rop->inspec, rop->preop.csym);
171 return(-1);
172 }
173 rop->preop.clen = strlen(rop->preop.csym) * nc;
174 if (rop->preop.clen > MAXCOMP*MAXCOMP) {
175 fprintf(stderr, "%s: -c '%s' results in too many components\n",
176 rop->inspec, rop->preop.csym);
177 return(-1);
178 }
179 for (j = 0; rop->preop.csym[j]; j++) {
180 int comp = 0;
181 switch (rop->preop.csym[j]) {
182 case 'B':
183 case 'b':
184 ++comp;
185 /* fall through */
186 case 'G':
187 case 'g':
188 ++comp;
189 /* fall through */
190 case 'R':
191 case 'r':
192 if (rop->preop.csym[j] <= 'Z')
193 cf = 1./WHTEFFICACY;
194 if (dt == DTxyze) {
195 for (i = 3; i--; )
196 rop->preop.cmat[j*nc+i] = cf*xyz2rgbmat[comp][i];
197 } else if (nc == 3)
198 rop->preop.cmat[j*nc+comp] = 1.;
199 else
200 rgbrow(rop, j, comp);
201 break;
202 case 'Z':
203 case 'z':
204 ++comp;
205 /* fall through */
206 case 'Y':
207 case 'y':
208 ++comp;
209 /* fall through */
210 case 'X':
211 case 'x':
212 if ((rop->preop.csym[j] <= 'Z') & (dt != DTxyze))
213 cf = WHTEFFICACY;
214 if (dt == DTxyze) {
215 rop->preop.cmat[j*nc+comp] = 1.;
216 } else if (nc == 3) {
217 for (i = 3; i--; )
218 rop->preop.cmat[j*nc+i] =
219 rgb2xyzmat[comp][i];
220 } else if (comp == CIEY)
221 sensrow(rop, j, scolor2photopic);
222 else
223 xyzrow(rop, j, comp);
224
225 for (i = nc*(cf != 1); i--; )
226 rop->preop.cmat[j*nc+i] *= cf;
227 break;
228 case 'S': /* scotopic (il)luminance */
229 cf = WHTSCOTOPIC;
230 /* fall through */
231 case 's':
232 sensrow(rop, j, scolor2scotopic);
233 for (i = nc*(cf != 1); i--; )
234 rop->preop.cmat[j*nc+i] *= cf;
235 break;
236 case 'M': /* melanopic (il)luminance */
237 cf = WHTMELANOPIC;
238 /* fall through */
239 case 'm':
240 sensrow(rop, j, scolor2melanopic);
241 for (i = nc*(cf != 1); i--; )
242 rop->preop.cmat[j*nc+i] *= cf;
243 break;
244 case 'A': /* average component */
245 case 'a':
246 for (i = nc; i--; )
247 rop->preop.cmat[j*nc+i] = 1./(double)nc;
248 break;
249 default:
250 fprintf(stderr, "%s: -c '%c' unsupported\n",
251 rop->inspec, rop->preop.csym[j]);
252 return(-1);
253 }
254 }
255 /* return recommended output type */
256 if (!strcasecmp(rop->preop.csym, "XYZ")) {
257 if (dt <= DTspec)
258 return(DTxyze);
259 } else if (!strcasecmp(rop->preop.csym, "RGB")) {
260 if (dt <= DTspec)
261 return(DTrgbe);
262 } else if (dt == DTspec)
263 return(DTfloat); /* probably not actual spectrum */
264 return(0);
265 }
266
267 /* Get matrix and perform unary operations */
268 RMATRIX *
269 loadop(ROPMAT *rop)
270 {
271 int outtype = 0;
272 RMATRIX *mres;
273 int i, j;
274
275 if (loadmatrix(rop) < 0) /* make sure we're loaded */
276 return(NULL);
277
278 if (rop->preop.csym && /* symbolic transform? */
279 (outtype = checksymbolic(rop)) < 0)
280 goto failure;
281 if (rop->preop.clen > 0) { /* apply component transform? */
282 if (rop->preop.clen % rop->mtx->ncomp) {
283 fprintf(stderr, "%s: -c must have N x %d coefficients\n",
284 rop->inspec, rop->mtx->ncomp);
285 goto failure;
286 }
287 if (rop->preop.nsf > 0) { /* scale transform, first */
288 if (rop->preop.nsf == 1) {
289 for (i = rop->preop.clen; i--; )
290 rop->preop.cmat[i] *= rop->preop.sca[0];
291 } else if (rop->preop.nsf*rop->mtx->ncomp != rop->preop.clen) {
292 fprintf(stderr, "%s: -s must have one or %d factors\n",
293 rop->inspec,
294 rop->preop.clen/rop->mtx->ncomp);
295 goto failure;
296 } else {
297 for (i = rop->preop.nsf; i--; )
298 for (j = rop->mtx->ncomp; j--; )
299 rop->preop.cmat[i*rop->mtx->ncomp+j]
300 *= rop->preop.sca[i];
301 }
302 }
303 mres = rmx_transform(rop->mtx, rop->preop.clen/rop->mtx->ncomp,
304 rop->preop.cmat);
305 if (mres == NULL) {
306 fprintf(stderr, "%s: matrix transform failed\n",
307 rop->inspec);
308 goto failure;
309 }
310 if (verbose)
311 fprintf(stderr, "%s: applied %d x %d transform%s\n",
312 rop->inspec, mres->ncomp,
313 rop->mtx->ncomp,
314 rop->preop.nsf ? " (* scalar)" : "");
315 rop->preop.nsf = 0; /* now folded in */
316 if ((mres->ncomp > 3) & (mres->dtype <= DTspec))
317 outtype = DTfloat; /* probably not actual spectrum */
318 rmx_free(rop->mtx);
319 rop->mtx = mres;
320 }
321 if (rop->preop.nsf > 0) { /* apply scalar(s)? */
322 if (rop->preop.nsf == 1) {
323 for (i = rop->mtx->ncomp; --i; )
324 rop->preop.sca[i] = rop->preop.sca[0];
325 } else if (rop->preop.nsf != rop->mtx->ncomp) {
326 fprintf(stderr, "%s: -s must have one or %d factors\n",
327 rop->inspec, rop->mtx->ncomp);
328 goto failure;
329 }
330 if (!rmx_scale(rop->mtx, rop->preop.sca)) {
331 fputs(rop->inspec, stderr);
332 fputs(": scalar operation failed\n", stderr);
333 goto failure;
334 }
335 if (verbose) {
336 fputs(rop->inspec, stderr);
337 fputs(": applied scalar (", stderr);
338 for (i = 0; i < rop->preop.nsf; i++)
339 fprintf(stderr, " %f", rop->preop.sca[i]);
340 fputs(" )\n", stderr);
341 }
342 }
343 if (rop->preop.transpose) { /* transpose matrix? */
344 if (!rmx_transpose(rop->mtx)) {
345 fputs(rop->inspec, stderr);
346 fputs(": transpose failed\n", stderr);
347 goto failure;
348 }
349 if (verbose) {
350 fputs(rop->inspec, stderr);
351 fputs(": transposed rows and columns\n", stderr);
352 }
353 }
354 mres = rop->mtx;
355 rop->mtx = NULL;
356 if (outtype)
357 mres->dtype = outtype;
358 return(mres);
359 failure:
360 rmx_free(rop->mtx);
361 return(rop->mtx = NULL);
362 }
363
364 /* Execute binary operation, free matrix arguments and return new result */
365 RMATRIX *
366 binaryop(const char *inspec, RMATRIX *mleft, int op, RMATRIX *mright)
367 {
368 RMATRIX *mres = NULL;
369 int i;
370
371 if ((mleft == NULL) | (mright == NULL))
372 return(NULL);
373 switch (op) {
374 case '.': /* concatenate */
375 if (mleft->ncomp != mright->ncomp) {
376 fputs(inspec, stderr);
377 fputs(": # components do not match\n", stderr);
378 } else if (mleft->ncols != mright->nrows) {
379 fputs(inspec, stderr);
380 fputs(": mismatched dimensions\n",
381 stderr);
382 } else
383 mres = rmx_multiply(mleft, mright);
384 rmx_free(mleft);
385 rmx_free(mright);
386 if (mres == NULL) {
387 fputs(inspec, stderr);
388 fputs(": concatenation failed\n", stderr);
389 return(NULL);
390 }
391 if (verbose) {
392 fputs(inspec, stderr);
393 fputs(": concatenated matrix\n", stderr);
394 }
395 break;
396 case '+':
397 if (!rmx_sum(mleft, mright, NULL)) {
398 fputs(inspec, stderr);
399 fputs(": matrix sum failed\n", stderr);
400 rmx_free(mleft);
401 rmx_free(mright);
402 return(NULL);
403 }
404 if (verbose) {
405 fputs(inspec, stderr);
406 fputs(": added in matrix\n", stderr);
407 }
408 rmx_free(mright);
409 mres = mleft;
410 break;
411 case '*':
412 case '/': {
413 const char * tnam = (op == '/') ?
414 "division" : "multiplication";
415 errno = 0;
416 if (!rmx_elemult(mleft, mright, (op == '/'))) {
417 fprintf(stderr, "%s: element-wise %s failed\n",
418 inspec, tnam);
419 rmx_free(mleft);
420 rmx_free(mright);
421 return(NULL);
422 }
423 if (errno)
424 fprintf(stderr,
425 "%s: warning - error during element-wise %s\n",
426 inspec, tnam);
427 else if (verbose)
428 fprintf(stderr, "%s: element-wise %s\n", inspec, tnam);
429 rmx_free(mright);
430 mres = mleft;
431 } break;
432 default:
433 fprintf(stderr, "%s: unknown operation '%c'\n", inspec, op);
434 rmx_free(mleft);
435 rmx_free(mright);
436 return(NULL);
437 }
438 return(mres);
439 }
440
441 /* Perform matrix operations from left to right */
442 RMATRIX *
443 op_left2right(ROPMAT *mop)
444 {
445 RMATRIX *mleft = loadop(mop);
446
447 while (mop->binop) {
448 if (mleft == NULL)
449 break;
450 mleft = binaryop(mop[1].inspec,
451 mleft, mop->binop, loadop(mop+1));
452 mop++;
453 }
454 return(mleft);
455 }
456
457 /* Perform matrix operations from right to left */
458 RMATRIX *
459 op_right2left(ROPMAT *mop)
460 {
461 RMATRIX *mright;
462 int rpos = 0;
463 /* find end of list */
464 while (mop[rpos].binop)
465 if (mop[rpos++].binop != '.') {
466 fputs(
467 "Right-to-left evaluation only for matrix multiplication!\n",
468 stderr);
469 return(NULL);
470 }
471 mright = loadop(mop+rpos);
472 while (rpos-- > 0) {
473 if (mright == NULL)
474 break;
475 mright = binaryop(mop[rpos+1].inspec,
476 loadop(mop+rpos), mop[rpos].binop, mright);
477 }
478 return(mright);
479 }
480
481 #define t_nrows(mop) ((mop)->preop.transpose ? (mop)->mtx->ncols \
482 : (mop)->mtx->nrows)
483 #define t_ncols(mop) ((mop)->preop.transpose ? (mop)->mtx->nrows \
484 : (mop)->mtx->ncols)
485
486 /* Should we prefer concatenating from rightmost matrix towards left? */
487 int
488 prefer_right2left(ROPMAT *mop)
489 {
490 int mri = 0;
491
492 while (mop[mri].binop) /* find rightmost matrix */
493 if (mop[mri++].binop != '.')
494 return(0); /* pre-empt reversal for other ops */
495
496 if (mri <= 1)
497 return(0); /* won't matter */
498
499 if (loadmatrix(mop+mri) < 0) /* load rightmost cat */
500 return(1); /* fail will bail in a moment */
501
502 if (t_ncols(mop+mri) == 1)
503 return(1); /* definitely better R->L */
504
505 if (t_ncols(mop+mri) >= t_nrows(mop+mri))
506 return(0); /* ...probably worse */
507
508 if (loadmatrix(mop) < 0) /* load leftmost */
509 return(0); /* fail will bail in a moment */
510
511 return(t_ncols(mop+mri) < t_nrows(mop));
512 }
513
514 int
515 get_factors(double da[], int n, char *av[])
516 {
517 int ac;
518
519 for (ac = 0; ac < n && isflt(av[ac]); ac++)
520 da[ac] = atof(av[ac]);
521 return(ac);
522 }
523
524 ROPMAT *
525 resize_moparr(ROPMAT *mop, int n2alloc)
526 {
527 int nmats = 0;
528 int i;
529
530 while (mop[nmats++].binop)
531 ;
532 for (i = nmats; i >= n2alloc; i--)
533 rmx_free(mop[i].mtx);
534 mop = (ROPMAT *)realloc(mop, n2alloc*sizeof(ROPMAT));
535 if (mop == NULL) {
536 fputs("Out of memory in resize_moparr()\n", stderr);
537 exit(1);
538 }
539 if (n2alloc > nmats)
540 memset(mop+nmats, 0, (n2alloc-nmats)*sizeof(ROPMAT));
541 return(mop);
542 }
543
544 /* Load one or more matrices and operate on them, sending results to stdout */
545 int
546 main(int argc, char *argv[])
547 {
548 int outfmt = DTfromHeader;
549 const char *defCsym = NULL;
550 int nall = 2;
551 ROPMAT *mop = (ROPMAT *)calloc(nall, sizeof(ROPMAT));
552 int nmats = 0;
553 RMATRIX *mres = NULL;
554 int stdin_used = 0;
555 int i;
556 /* get options and arguments */
557 for (i = 1; i < argc; i++) {
558 if (argv[i][0] && !argv[i][1] &&
559 strchr(".+*/", argv[i][0]) != NULL) {
560 if (!nmats || mop[nmats-1].binop) {
561 fprintf(stderr,
562 "%s: missing matrix argument before '%c' operation\n",
563 argv[0], argv[i][0]);
564 return(1);
565 }
566 mop[nmats-1].binop = argv[i][0];
567 } else if (argv[i][0] != '-' || !argv[i][1]) {
568 if (argv[i][0] == '-') {
569 if (stdin_used++) {
570 fprintf(stderr,
571 "%s: standard input used for more than one matrix\n",
572 argv[0]);
573 return(1);
574 }
575 mop[nmats].inspec = stdin_name;
576 } else
577 mop[nmats].inspec = argv[i];
578 if (!mop[nmats].preop.csym)
579 mop[nmats].preop.csym = defCsym;
580 if (nmats > 0 && !mop[nmats-1].binop)
581 mop[nmats-1].binop = '.';
582 nmats++;
583 } else {
584 int n = argc-1 - i;
585 switch (argv[i][1]) { /* get option */
586 case 'v':
587 verbose++;
588 break;
589 case 'f':
590 switch (argv[i][2]) {
591 case 'd':
592 outfmt = DTdouble;
593 break;
594 case 'f':
595 outfmt = DTfloat;
596 break;
597 case 'a':
598 outfmt = DTascii;
599 break;
600 case 'c':
601 outfmt = DTrgbe;
602 break;
603 default:
604 goto userr;
605 }
606 break;
607 case 't':
608 mop[nmats].preop.transpose = 1;
609 break;
610 case 's':
611 if (n > MAXCOMP) n = MAXCOMP;
612 i += mop[nmats].preop.nsf =
613 get_factors(mop[nmats].preop.sca,
614 n, argv+i+1);
615 if (mop[nmats].preop.nsf <= 0) {
616 fprintf(stderr, "%s: -s missing arguments\n",
617 argv[0]);
618 goto userr;
619 }
620 break;
621 case 'C':
622 if (!n || isflt(argv[i+1]))
623 goto userr;
624 defCsym = mop[nmats].preop.csym = argv[++i];
625 mop[nmats].preop.clen = 0;
626 break;
627 case 'c':
628 if (n && !isflt(argv[i+1])) {
629 mop[nmats].preop.csym = argv[++i];
630 mop[nmats].preop.clen = 0;
631 break;
632 }
633 if (n > MAXCOMP*MAXCOMP) n = MAXCOMP*MAXCOMP;
634 i += mop[nmats].preop.clen =
635 get_factors(mop[nmats].preop.cmat,
636 n, argv+i+1);
637 if (mop[nmats].preop.clen <= 0) {
638 fprintf(stderr, "%s: -c missing arguments\n",
639 argv[0]);
640 goto userr;
641 }
642 mop[nmats].preop.csym = NULL;
643 break;
644 case 'r':
645 if (argv[i][2] == 'f')
646 mop[nmats].rmp = RMPreflF;
647 else if (argv[i][2] == 'b')
648 mop[nmats].rmp = RMPreflB;
649 else
650 goto userr;
651 break;
652 default:
653 fprintf(stderr, "%s: unknown operation '%s'\n",
654 argv[0], argv[i]);
655 goto userr;
656 }
657 }
658 if (nmats >= nall)
659 mop = resize_moparr(mop, nall += 2);
660 }
661 if (mop[0].inspec == NULL) /* nothing to do? */
662 goto userr;
663 if (mop[nmats-1].binop) {
664 fprintf(stderr,
665 "%s: missing matrix argument after '%c' operation\n",
666 argv[0], mop[nmats-1].binop);
667 return(1);
668 }
669 /* favor quicker concatenation */
670 mop[nmats].mtx = prefer_right2left(mop) ? op_right2left(mop)
671 : op_left2right(mop);
672 if (mop[nmats].mtx == NULL)
673 return(1);
674 /* apply trailing unary operations */
675 mop[nmats].inspec = "trailing_ops";
676 mres = loadop(mop+nmats);
677 if (mres == NULL)
678 return(1);
679 if (outfmt == DTfromHeader) /* check data type */
680 outfmt = mres->dtype;
681 if (outfmt == DTrgbe) {
682 if (mres->ncomp > 3)
683 outfmt = DTspec;
684 else if (mres->dtype == DTxyze)
685 outfmt = DTxyze;
686 }
687 newheader("RADIANCE", stdout); /* write result to stdout */
688 printargs(argc, argv, stdout);
689 return(rmx_write(mres, outfmt, stdout) ? 0 : 1);
690 userr:
691 fprintf(stderr,
692 "Usage: %s [-v][-f{adfc}][-t][-s sf .. | -c ce ..][-rf|-rb] m1 [.+*/] .. > mres\n",
693 argv[0]);
694 return(1);
695 }