ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/pcomb.c
Revision: 2.58
Committed: Mon Dec 11 15:13:39 2023 UTC (5 months, 1 week ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.57: +7 -3 lines
Log Message:
perf(rmtxcomb,pcomb): Avoid calling varset() if unnecessary

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: pcomb.c,v 2.57 2023/12/09 23:46:51 greg Exp $";
3 #endif
4 /*
5 * Combine picture files according to calcomp functions.
6 *
7 * 1/4/89
8 */
9
10 #include "platform.h"
11 #include "standard.h"
12 #include "paths.h"
13 #include "color.h"
14 #include "calcomp.h"
15 #include "view.h"
16
17 #define MAXINP 1024 /* maximum number of input files */
18 #define WINSIZ 127 /* scanline window size */
19 #define MIDSCN ((WINSIZ-1)/2+1)
20
21 struct {
22 char *name; /* file or command name */
23 FILE *fp; /* stream pointer */
24 VIEW vw; /* view for picture */
25 RESOLU rs; /* image resolution and orientation */
26 int infloat; /* input is floating point (#comp)? */
27 float pa; /* pixel aspect ratio */
28 COLOR *scan[WINSIZ]; /* input scanline window */
29 COLOR coef; /* coefficient */
30 COLOR expos; /* recorded exposure */
31 } input[MAXINP]; /* input pictures */
32
33 int nfiles; /* number of input files */
34
35 VIEW *commvp = NULL; /* common view parameters */
36
37 char ourfmt[MAXFMTLEN] = PICFMT; /* input picture format */
38 int outfloat = 0; /* #component float output? */
39
40 char StandardInput[] = "<stdin>";
41 char Command[] = "<Command>";
42 char vcolin[3][4] = {"ri", "gi", "bi"};
43 char vcolout[3][4] = {"ro", "go", "bo"};
44 char vbrtin[] = "li";
45 char vbrtout[] = "lo";
46 char vcolexp[3][4] = {"re", "ge", "be"};
47 char vbrtexp[] = "le";
48 char vpixaspect[] = "pa";
49
50 char vray[7][4] = {"Ox", "Oy", "Oz", "Dx", "Dy", "Dz", "T"};
51
52 char vpsize[] = "S";
53
54 char vnfiles[] = "nfiles";
55 char vwhteff[] = "WE";
56 char vxmax[] = "xmax";
57 char vymax[] = "ymax";
58 char vxres[] = "xres";
59 char vyres[] = "yres";
60 char vxpos[] = "x";
61 char vypos[] = "y";
62
63 int nowarn = 0; /* no warning messages? */
64
65 int xmax = 0, ymax = 0; /* input resolution */
66
67 int xscan, yscan; /* input position */
68
69 int xres, yres; /* output resolution */
70
71 int xpos, ypos; /* output position */
72
73 char *progname; /* global argv[0] */
74
75 int echoheader = 1;
76 int wrongformat = 0;
77 int gotview;
78
79
80 static gethfunc headline;
81 static void checkfile(int orig);
82 static double rgb_bright(COLOR clr);
83 static double xyz_bright(COLOR clr);
84 static void init(void);
85 static void combine(void);
86 static void advance(void);
87 static double l_expos(char *nam);
88 static double l_pixaspect(char *nm);
89 static double l_colin(char *nam);
90 static double l_ray(char *nam);
91 static double l_psize(char *nm);
92
93
94 int
95 main(
96 int argc,
97 char *argv[]
98 )
99 {
100 int original;
101 double f;
102 int a;
103
104 SET_DEFAULT_BINARY();
105 SET_FILE_BINARY(stdin);
106 SET_FILE_BINARY(stdout);
107 progname = argv[0];
108 esupport |= E_VARIABLE|E_FUNCTION|E_RCONST;
109 esupport &= ~(E_OUTCHAN|E_INCHAN);
110 /* scan options */
111 for (a = 1; a < argc; a++) {
112 if (argv[a][0] == '-')
113 switch (argv[a][1]) {
114 case 'x':
115 case 'y':
116 a++;
117 continue;
118 case 'w':
119 nowarn = !nowarn;
120 continue;
121 case 'h':
122 echoheader = !echoheader;
123 continue;
124 case 'f':
125 if (argv[a][2]) {
126 outfloat = (argv[a][2] == 'f');
127 continue;
128 }
129 /* fall through */
130 case 'e':
131 a++;
132 continue;
133 }
134 break;
135 }
136 newheader("RADIANCE", stdout); /* start header */
137 fputnow(stdout);
138 /* process files */
139 for (nfiles = 0; nfiles < MAXINP; nfiles++) {
140 setcolor(input[nfiles].coef, 1.0, 1.0, 1.0);
141 setcolor(input[nfiles].expos, 1.0, 1.0, 1.0);
142 input[nfiles].vw = stdview;
143 input[nfiles].pa = 1.0;
144 }
145 nfiles = 0;
146 original = 0;
147 for ( ; a < argc; a++) {
148 if (nfiles >= MAXINP) {
149 eputs(argv[0]);
150 eputs(": too many picture files\n");
151 quit(1);
152 }
153 if (argv[a][0] == '-')
154 switch (argv[a][1]) {
155 case '\0':
156 input[nfiles].name = StandardInput;
157 input[nfiles].fp = stdin;
158 break;
159 case 'o':
160 original++;
161 continue;
162 case 's':
163 f = atof(argv[++a]);
164 scalecolor(input[nfiles].coef, f);
165 continue;
166 case 'c':
167 colval(input[nfiles].coef,RED)*=atof(argv[++a]);
168 colval(input[nfiles].coef,GRN)*=atof(argv[++a]);
169 colval(input[nfiles].coef,BLU)*=atof(argv[++a]);
170 continue;
171 default:
172 goto usage;
173 }
174 else {
175 if (argv[a][0] == '!') {
176 input[nfiles].name = Command;
177 input[nfiles].fp = popen(argv[a]+1, "r");
178 } else {
179 input[nfiles].name = argv[a];
180 input[nfiles].fp = fopen(argv[a], "r");
181 }
182 if (input[nfiles].fp == NULL) {
183 perror(argv[a]);
184 quit(1);
185 }
186 }
187 checkfile(original);
188 nfiles++;
189 original = 0;
190 }
191 init(); /* set constants */
192 /* go back and get expressions */
193 for (a = 1; a < argc; a++) {
194 char *fpath;
195 if (argv[a][0] == '-')
196 switch (argv[a][1]) {
197 case 'x':
198 varset(vxres, ':', eval(argv[++a]));
199 continue;
200 case 'y':
201 varset(vyres, ':', eval(argv[++a]));
202 continue;
203 case 'w':
204 continue;
205 case 'h':
206 continue;
207 case 'f':
208 if (argv[a][2])
209 continue;
210 fpath = getpath(argv[++a], getrlibpath(), 0);
211 if (fpath == NULL) {
212 eputs(argv[0]);
213 eputs(": cannot find file '");
214 eputs(argv[a]);
215 eputs("'\n");
216 quit(1);
217 }
218 fcompile(fpath);
219 continue;
220 case 'e':
221 scompile(argv[++a], NULL, 0);
222 continue;
223 }
224 break;
225 }
226 /* get output resolution */
227 xres = varvalue(vxres) + .5;
228 yres = varvalue(vyres) + .5;
229 if (xres <= 0 || yres <= 0) {
230 eputs(argv[0]);
231 eputs(": illegal output resolution\n");
232 quit(1);
233 }
234 if (!vardefined(vbrtout)) /* single or 3-channel? */
235 outfloat *= 3;
236
237 printargs(argc, argv, stdout); /* complete header */
238 if (commvp != NULL) {
239 fputs(VIEWSTR, stdout);
240 fprintview(commvp, stdout);
241 fputc('\n', stdout);
242 }
243 if (outfloat) { /* print format if known */
244 printf("NROWS=%d\nNCOLS=%d\n", yres, xres);
245 fputncomp(outfloat, stdout);
246 fputendian(stdout);
247 fputformat("float", stdout);
248 } else if (strcmp(ourfmt, PICFMT))
249 fputformat(ourfmt, stdout);
250 fputc('\n', stdout); /* end header */
251 if (!outfloat)
252 fprtresolu(xres, yres, stdout);
253
254 combine(); /* combine pictures */
255 quit(0);
256 usage:
257 eputs("Usage: ");
258 eputs(argv[0]);
259 eputs(
260 " [-w][-h][-ff][-x xr][-y yr][-e expr][-f file] [ [-o][-s f][-c r g b] hdr ..]\n");
261 quit(1);
262 return 1; /* pro forma return */
263 }
264
265
266 static int
267 headline( /* check header line & echo if requested */
268 char *s,
269 void *p
270 )
271 {
272 int orig = *(int *)p;
273 char fmt[MAXFMTLEN];
274 double d;
275 int bigend;
276 COLOR ctmp;
277
278 if (isheadid(s)) /* header id */
279 return(0); /* don't echo */
280 if (formatval(fmt, s)) { /* check format */
281 if (globmatch(ourfmt, fmt)) {
282 wrongformat = 0;
283 strcpy(ourfmt, fmt);
284 } else if (!strcmp("float", fmt))
285 input[nfiles].infloat *= -1;
286 else
287 wrongformat = globmatch(PICFMT, fmt) ? 1 : -1;
288 return(0); /* don't echo */
289 }
290 if ((bigend = isbigendian(s)) >= 0) {
291 if (bigend != nativebigendian()) {
292 eputs(input[nfiles].name);
293 eputs(": unsupported input byte ordering\n");
294 quit(1);
295 }
296 return(0); /* don't echo */
297 }
298 if (!strncmp("NROWS=", s, 6)) { /* X-resolution */
299 input[nfiles].rs.yr = atoi(s+6);
300 return(0); /* don't echo */
301 }
302 if (!strncmp("NCOLS=", s, 6)) { /* Y-resolution */
303 input[nfiles].rs.xr = atoi(s+6);
304 return(0); /* don't echo */
305 }
306 if (isncomp(s)) /* # components */
307 input[nfiles].infloat *= ncompval(s);
308
309 if (orig) { /* undo exposure? */
310 if (isexpos(s)) {
311 d = 1./exposval(s);
312 scalecolor(input[nfiles].coef, d);
313 return(0); /* don't echo */
314 }
315 if (iscolcor(s)) {
316 int i;
317 colcorval(ctmp, s);
318 for (i = 3; i--; )
319 colval(input[nfiles].coef,i) /= colval(ctmp,i);
320 return(0); /* don't echo */
321 }
322 } else if (isexpos(s)) { /* record exposure? */
323 d = exposval(s);
324 scalecolor(input[nfiles].expos, d);
325 } else if (iscolcor(s)) {
326 colcorval(ctmp, s);
327 multcolor(input[nfiles].expos, ctmp);
328 }
329 if (isaspect(s))
330 input[nfiles].pa *= aspectval(s);
331 else if (isview(s) && sscanview(&input[nfiles].vw, s) > 0)
332 gotview++;
333
334 if (echoheader) { /* echo line */
335 putchar('\t');
336 return(fputs(s, stdout));
337 }
338 return(0);
339 }
340
341
342 static void
343 checkfile(int orig) /* ready a file */
344 {
345 int i;
346 /* process header */
347 gotview = 0;
348 input[nfiles].infloat = -1;
349 input[nfiles].rs.rt = PIXSTANDARD;
350 input[nfiles].rs.xr = input[nfiles].rs.yr = 0;
351 if (echoheader) {
352 fputs(input[nfiles].name, stdout);
353 fputs(":\n", stdout);
354 }
355 getheader(input[nfiles].fp, headline, &orig);
356
357 if (input[nfiles].infloat <= 0)
358 input[nfiles].infloat = 0;
359 else if ((input[nfiles].infloat != 3) &
360 (input[nfiles].infloat != 1)) {
361 eputs(input[nfiles].name);
362 eputs(": unsupported number of components\n");
363 quit(1);
364 }
365 if (wrongformat < 0) {
366 eputs(input[nfiles].name);
367 eputs(": not a Radiance picture or float matrix\n");
368 quit(1);
369 }
370 if (wrongformat > 0) {
371 wputs(input[nfiles].name);
372 wputs(": warning -- incompatible picture format\n");
373 }
374 if (!gotview || setview(&input[nfiles].vw) != NULL)
375 input[nfiles].vw.type = 0;
376 else if (commvp == NULL)
377 commvp = &input[nfiles].vw;
378 if ((input[nfiles].rs.xr <= 0) | (input[nfiles].rs.yr <= 0) &&
379 !fgetsresolu(&input[nfiles].rs, input[nfiles].fp)) {
380 eputs(input[nfiles].name);
381 eputs(": bad picture size\n");
382 quit(1);
383 }
384 if (xmax == 0 && ymax == 0) {
385 xmax = scanlen(&input[nfiles].rs);
386 ymax = numscans(&input[nfiles].rs);
387 } else if (scanlen(&input[nfiles].rs) != xmax ||
388 numscans(&input[nfiles].rs) != ymax) {
389 eputs(input[nfiles].name);
390 eputs(": resolution mismatch\n");
391 quit(1);
392 }
393 /* allocate scanlines */
394 for (i = 0; i < WINSIZ; i++)
395 input[nfiles].scan[i] = (COLOR *)emalloc(xmax*sizeof(COLOR));
396 }
397
398
399 static double
400 rgb_bright(
401 COLOR clr
402 )
403 {
404 return(bright(clr));
405 }
406
407
408 static double
409 xyz_bright(
410 COLOR clr
411 )
412 {
413 return(clr[CIEY]);
414 }
415
416
417 double (*ourbright)() = rgb_bright;
418
419
420 static void
421 init(void) /* perform final setup */
422 {
423 int i;
424 /* define constants */
425 varset("PI", ':', PI);
426 varset(vnfiles, ':', (double)nfiles);
427 varset(vxmax, ':', (double)xmax);
428 varset(vymax, ':', (double)ymax);
429 /* set functions */
430 for (i = 0; i < 3; i++) {
431 funset(vcolexp[i], 1, ':', l_expos);
432 funset(vcolin[i], 1, '=', l_colin);
433 }
434 funset(vbrtexp, 1, ':', l_expos);
435 funset(vbrtin, 1, '=', l_colin);
436 funset(vpixaspect, 1, ':', l_pixaspect);
437 for (i = 0; i < 7; i++)
438 funset(vray[i], 1, '=', l_ray);
439 funset(vpsize, 1, '=', l_psize);
440 /* set brightness function */
441 if (!strcmp(ourfmt, CIEFMT)) {
442 varset(vwhteff, ':', 1.0);
443 ourbright = xyz_bright;
444 } else
445 varset(vwhteff, ':', WHTEFFICACY);
446 /* these may be overridden */
447 varset(vxres, ':', (double)xmax);
448 varset(vyres, ':', (double)ymax);
449 }
450
451
452 static void
453 combine(void) /* combine pictures */
454 {
455 EPNODE *coldef[3], *brtdef;
456 int set_x, set_y;
457 COLOR *scanout;
458 double d;
459 int i, j;
460 /* check defined variables */
461 for (j = 0; j < 3; j++) {
462 if (vardefined(vcolout[j]))
463 coldef[j] = eparse(vcolout[j]);
464 else
465 coldef[j] = NULL;
466 }
467 if (vardefined(vbrtout))
468 brtdef = eparse(vbrtout);
469 else
470 brtdef = NULL;
471 /* what to set */
472 set_x = varlookup(vxpos) != NULL && !vardefined(vxpos);
473 set_y = varlookup(vypos) != NULL && !vardefined(vypos);
474 /* allocate scanline */
475 scanout = (COLOR *)emalloc(xres*sizeof(COLOR));
476 /* set input position */
477 yscan = ymax+MIDSCN;
478 /* combine files */
479 for (ypos = yres-1; ypos >= 0; ypos--) {
480 advance();
481 if (set_y) varset(vypos, '=', (double)ypos);
482 for (xpos = 0; xpos < xres; xpos++) {
483 xscan = (xpos+.5)*xmax/xres;
484 if (set_x) varset(vxpos, '=', (double)xpos);
485 eclock++;
486 if (brtdef != NULL) {
487 d = evalue(brtdef);
488 d *= (outfloat > 0) | (d >= 0);
489 setcolor(scanout[xpos], d, d, d);
490 } else {
491 for (j = 0; j < 3; j++) {
492 if (coldef[j] != NULL) {
493 d = evalue(coldef[j]);
494 } else {
495 d = 0.0;
496 for (i = 0; i < nfiles; i++)
497 d += colval(input[i].scan[MIDSCN][xscan],j);
498 }
499 d *= (outfloat > 0) | (d >= 0);
500 colval(scanout[xpos],j) = d;
501 }
502 }
503 }
504 switch (outfloat) {
505 case 3: /* writing out float triplets */
506 if (fwrite(scanout, sizeof(float)*3, xres, stdout) != xres)
507 goto writerr;
508 break;
509 case 1: /* writing out gray float values */
510 for (xpos = 0; xpos < xres; xpos++)
511 if (putbinary(&scanout[xpos][CIEY],
512 sizeof(float), 1, stdout) != 1)
513 goto writerr;
514 break;
515 default: /* writing out Radiance picture */
516 if (fwritescan(scanout, xres, stdout) < 0)
517 goto writerr;
518 break;
519 }
520 }
521 efree((char *)scanout);
522 return;
523 writerr:
524 perror("write error");
525 quit(1);
526 }
527
528
529 static void
530 advance(void) /* read in data for next scanline */
531 {
532 int ytarget;
533 COLOR *st;
534 int i, j;
535
536 for (ytarget = (ypos+.5)*ymax/yres; yscan > ytarget; yscan--)
537 for (i = 0; i < nfiles; i++) {
538 st = input[i].scan[WINSIZ-1];
539 for (j = WINSIZ-1; j > 0; j--) /* rotate window */
540 input[i].scan[j] = input[i].scan[j-1];
541 input[i].scan[0] = st;
542 if (yscan <= MIDSCN) /* hit bottom? */
543 continue;
544 /* read scanline */
545 if (input[i].infloat) {
546 if (fread(st, sizeof(float)*input[i].infloat,
547 xmax, input[i].fp) != xmax)
548 goto readerr;
549 if (input[i].infloat == 1) {
550 const COLORV *f = st[0] + xmax;
551 int x = xmax;
552 while (x-- > 0)
553 st[x][BLU] = st[x][GRN] =
554 st[x][RED] = *--f;
555 }
556 } else if (freadscan(st, xmax, input[i].fp) < 0)
557 goto readerr;
558 for (j = 0; j < xmax; j++) /* adjust color */
559 multcolor(st[j], input[i].coef);
560 }
561 return;
562 readerr:
563 eputs(input[i].name);
564 eputs(": read error\n");
565 quit(1);
566 }
567
568
569 static double
570 l_expos( /* return picture exposure */
571 char *nam
572 )
573 {
574 int fn, n;
575 double d;
576
577 d = argument(1);
578 if (d <= -0.5 || d >= nfiles+0.5) {
579 errno = EDOM;
580 return(0.0);
581 }
582 if (d < 0.5)
583 return((double)nfiles);
584 fn = d - 0.5;
585 if (nam == vbrtexp)
586 return((*ourbright)(input[fn].expos));
587 n = 3;
588 while (n--)
589 if (nam == vcolexp[n])
590 return(colval(input[fn].expos,n));
591 eputs("Bad call to l_expos()!\n");
592 quit(1);
593 return 1; /* pro forma return */
594 }
595
596
597 static double
598 l_pixaspect(char *nm) /* return pixel aspect ratio */
599 {
600 int fn;
601 double d;
602
603 d = argument(1);
604 if (d <= -0.5 || d >= nfiles+0.5) {
605 errno = EDOM;
606 return(0.0);
607 }
608 if (d < 0.5)
609 return((double)nfiles);
610 fn = d - 0.5;
611 return(input[fn].pa);
612 }
613
614
615 static double
616 l_colin( /* return color value for picture */
617 char *nam
618 )
619 {
620 int fn;
621 int n, xoff, yoff;
622 double d;
623
624 d = argument(1);
625 if (d <= -0.5 || d >= nfiles+0.5) {
626 errno = EDOM;
627 return(0.0);
628 }
629 if (d < 0.5)
630 return((double)nfiles);
631 fn = d - 0.5;
632 xoff = yoff = 0;
633 n = nargum();
634 if (n >= 2) {
635 d = argument(2);
636 if (d < 0.0) {
637 xoff = d-.5;
638 if (xscan+xoff < 0)
639 xoff = -xscan;
640 } else {
641 xoff = d+.5;
642 if (xscan+xoff >= xmax)
643 xoff = xmax-1-xscan;
644 }
645 }
646 if (n >= 3) {
647 d = argument(3);
648 if (d < 0.0) {
649 yoff = d-.5;
650 if (yoff+MIDSCN < 0)
651 yoff = -MIDSCN;
652 if (yscan+yoff < 0)
653 yoff = -yscan;
654 } else {
655 yoff = d+.5;
656 if (yoff+MIDSCN >= WINSIZ)
657 yoff = WINSIZ-1-MIDSCN;
658 if (yscan+yoff >= ymax)
659 yoff = ymax-1-yscan;
660 }
661 }
662 if (nam == vbrtin)
663 return((*ourbright)(input[fn].scan[MIDSCN+yoff][xscan+xoff]));
664 n = 3;
665 while (n--)
666 if (nam == vcolin[n])
667 return(colval(input[fn].scan[MIDSCN+yoff][xscan+xoff],n));
668 eputs("Bad call to l_colin()!\n");
669 quit(1);
670 return 1; /* pro forma return */
671 }
672
673
674 static double
675 l_ray( /* return ray origin or direction */
676 char *nam
677 )
678 {
679 static unsigned long ltick[MAXINP];
680 static FVECT lorg[MAXINP], ldir[MAXINP];
681 static double ldist[MAXINP];
682 RREAL loc[2];
683 double d;
684 int fn;
685 int i;
686
687 d = argument(1);
688 if (d <= -0.5 || d >= nfiles+0.5) {
689 errno = EDOM;
690 return(0.0);
691 }
692 if (d < 0.5)
693 return((double)nfiles);
694 fn = d - 0.5;
695 if (ltick[fn] != eclock) { /* need to compute? */
696 if (input[fn].vw.type == 0) {
697 lorg[fn][0] = lorg[fn][1] = lorg[fn][2] = 0.0;
698 ldir[fn][0] = ldir[fn][1] = ldir[fn][2] = 0.0;
699 ldist[fn] = -1.0;
700 errno = EDOM;
701 } else {
702 pix2loc(loc, &input[fn].rs, xscan, ymax-1-yscan);
703 ldist[fn] = viewray(lorg[fn], ldir[fn],
704 &input[fn].vw, loc[0], loc[1]);
705 if (ldist[fn] < -FTINY)
706 errno = EDOM;
707 }
708 ltick[fn] = eclock;
709 }
710 if (nam == vray[i=6])
711 return(ldist[fn]);
712 while (i--)
713 if (nam == vray[i])
714 return(i < 3 ? lorg[fn][i] : ldir[fn][i-3]);
715 eputs("Bad call to l_ray()!\n");
716 quit(1);
717 return 1; /* pro forma return */
718 }
719
720
721 static double
722 l_psize(char *nm) /* compute pixel size in steradians */
723 {
724 static unsigned long ltick[MAXINP];
725 static double psize[MAXINP];
726 FVECT dir0, org, dirx, diry;
727 RREAL locx[2], locy[2];
728 double d;
729 int fn;
730 int i;
731
732 d = argument(1);
733 if (d <= -0.5 || d >= nfiles+0.5) {
734 errno = EDOM;
735 return(0.0);
736 }
737 if (d < 0.5)
738 return((double)nfiles);
739 fn = d - 0.5;
740 if (ltick[fn] != eclock) { /* need to compute? */
741 psize[fn] = 0.0;
742 if (input[fn].vw.type == 0)
743 errno = EDOM;
744 else if (input[fn].vw.type != VT_PAR &&
745 funvalue(vray[6], 1, &d) >= -FTINY) {
746 for (i = 0; i < 3; i++)
747 dir0[i] = funvalue(vray[3+i], 1, &d);
748 pix2loc(locx, &input[fn].rs, xscan+1, ymax-1-yscan);
749 pix2loc(locy, &input[fn].rs, xscan, ymax-yscan);
750 if (viewray(org, dirx, &input[fn].vw,
751 locx[0], locx[1]) >= -FTINY &&
752 viewray(org, diry, &input[fn].vw,
753 locy[0], locy[1]) >= -FTINY) {
754 /* approximate solid angle */
755 for (i = 0; i < 3; i++) {
756 dirx[i] -= dir0[i];
757 diry[i] -= dir0[i];
758 }
759 fcross(dir0, dirx, diry);
760 psize[fn] = VLEN(dir0);
761 }
762 }
763 ltick[fn] = eclock;
764 }
765 return(psize[fn]);
766 }
767
768
769 extern void
770 wputs(const char *msg)
771 {
772 if (!nowarn)
773 eputs(msg);
774 }
775
776
777 extern void
778 eputs(const char *msg)
779 {
780 fputs(msg, stderr);
781 }
782
783
784 extern void
785 quit(int code) /* exit gracefully */
786 {
787 int i;
788 /* close input files */
789 for (i = 0; i < nfiles; i++)
790 if (input[i].name == Command)
791 pclose(input[i].fp);
792 else
793 fclose(input[i].fp);
794 exit(code);
795 }