ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/pcomb.c
Revision: 2.59
Committed: Fri Feb 23 03:47:57 2024 UTC (2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.58: +2 -1 lines
Log Message:
perf: Added array index optimization to calcomp routines

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: pcomb.c,v 2.58 2023/12/11 15:13:39 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 doptimize(1); /* optimize definitions */
255 combine(); /* combine pictures */
256 quit(0);
257 usage:
258 eputs("Usage: ");
259 eputs(argv[0]);
260 eputs(
261 " [-w][-h][-ff][-x xr][-y yr][-e expr][-f file] [ [-o][-s f][-c r g b] hdr ..]\n");
262 quit(1);
263 return 1; /* pro forma return */
264 }
265
266
267 static int
268 headline( /* check header line & echo if requested */
269 char *s,
270 void *p
271 )
272 {
273 int orig = *(int *)p;
274 char fmt[MAXFMTLEN];
275 double d;
276 int bigend;
277 COLOR ctmp;
278
279 if (isheadid(s)) /* header id */
280 return(0); /* don't echo */
281 if (formatval(fmt, s)) { /* check format */
282 if (globmatch(ourfmt, fmt)) {
283 wrongformat = 0;
284 strcpy(ourfmt, fmt);
285 } else if (!strcmp("float", fmt))
286 input[nfiles].infloat *= -1;
287 else
288 wrongformat = globmatch(PICFMT, fmt) ? 1 : -1;
289 return(0); /* don't echo */
290 }
291 if ((bigend = isbigendian(s)) >= 0) {
292 if (bigend != nativebigendian()) {
293 eputs(input[nfiles].name);
294 eputs(": unsupported input byte ordering\n");
295 quit(1);
296 }
297 return(0); /* don't echo */
298 }
299 if (!strncmp("NROWS=", s, 6)) { /* X-resolution */
300 input[nfiles].rs.yr = atoi(s+6);
301 return(0); /* don't echo */
302 }
303 if (!strncmp("NCOLS=", s, 6)) { /* Y-resolution */
304 input[nfiles].rs.xr = atoi(s+6);
305 return(0); /* don't echo */
306 }
307 if (isncomp(s)) /* # components */
308 input[nfiles].infloat *= ncompval(s);
309
310 if (orig) { /* undo exposure? */
311 if (isexpos(s)) {
312 d = 1./exposval(s);
313 scalecolor(input[nfiles].coef, d);
314 return(0); /* don't echo */
315 }
316 if (iscolcor(s)) {
317 int i;
318 colcorval(ctmp, s);
319 for (i = 3; i--; )
320 colval(input[nfiles].coef,i) /= colval(ctmp,i);
321 return(0); /* don't echo */
322 }
323 } else if (isexpos(s)) { /* record exposure? */
324 d = exposval(s);
325 scalecolor(input[nfiles].expos, d);
326 } else if (iscolcor(s)) {
327 colcorval(ctmp, s);
328 multcolor(input[nfiles].expos, ctmp);
329 }
330 if (isaspect(s))
331 input[nfiles].pa *= aspectval(s);
332 else if (isview(s) && sscanview(&input[nfiles].vw, s) > 0)
333 gotview++;
334
335 if (echoheader) { /* echo line */
336 putchar('\t');
337 return(fputs(s, stdout));
338 }
339 return(0);
340 }
341
342
343 static void
344 checkfile(int orig) /* ready a file */
345 {
346 int i;
347 /* process header */
348 gotview = 0;
349 input[nfiles].infloat = -1;
350 input[nfiles].rs.rt = PIXSTANDARD;
351 input[nfiles].rs.xr = input[nfiles].rs.yr = 0;
352 if (echoheader) {
353 fputs(input[nfiles].name, stdout);
354 fputs(":\n", stdout);
355 }
356 getheader(input[nfiles].fp, headline, &orig);
357
358 if (input[nfiles].infloat <= 0)
359 input[nfiles].infloat = 0;
360 else if ((input[nfiles].infloat != 3) &
361 (input[nfiles].infloat != 1)) {
362 eputs(input[nfiles].name);
363 eputs(": unsupported number of components\n");
364 quit(1);
365 }
366 if (wrongformat < 0) {
367 eputs(input[nfiles].name);
368 eputs(": not a Radiance picture or float matrix\n");
369 quit(1);
370 }
371 if (wrongformat > 0) {
372 wputs(input[nfiles].name);
373 wputs(": warning -- incompatible picture format\n");
374 }
375 if (!gotview || setview(&input[nfiles].vw) != NULL)
376 input[nfiles].vw.type = 0;
377 else if (commvp == NULL)
378 commvp = &input[nfiles].vw;
379 if ((input[nfiles].rs.xr <= 0) | (input[nfiles].rs.yr <= 0) &&
380 !fgetsresolu(&input[nfiles].rs, input[nfiles].fp)) {
381 eputs(input[nfiles].name);
382 eputs(": bad picture size\n");
383 quit(1);
384 }
385 if (xmax == 0 && ymax == 0) {
386 xmax = scanlen(&input[nfiles].rs);
387 ymax = numscans(&input[nfiles].rs);
388 } else if (scanlen(&input[nfiles].rs) != xmax ||
389 numscans(&input[nfiles].rs) != ymax) {
390 eputs(input[nfiles].name);
391 eputs(": resolution mismatch\n");
392 quit(1);
393 }
394 /* allocate scanlines */
395 for (i = 0; i < WINSIZ; i++)
396 input[nfiles].scan[i] = (COLOR *)emalloc(xmax*sizeof(COLOR));
397 }
398
399
400 static double
401 rgb_bright(
402 COLOR clr
403 )
404 {
405 return(bright(clr));
406 }
407
408
409 static double
410 xyz_bright(
411 COLOR clr
412 )
413 {
414 return(clr[CIEY]);
415 }
416
417
418 double (*ourbright)() = rgb_bright;
419
420
421 static void
422 init(void) /* perform final setup */
423 {
424 int i;
425 /* define constants */
426 varset("PI", ':', PI);
427 varset(vnfiles, ':', (double)nfiles);
428 varset(vxmax, ':', (double)xmax);
429 varset(vymax, ':', (double)ymax);
430 /* set functions */
431 for (i = 0; i < 3; i++) {
432 funset(vcolexp[i], 1, ':', l_expos);
433 funset(vcolin[i], 1, '=', l_colin);
434 }
435 funset(vbrtexp, 1, ':', l_expos);
436 funset(vbrtin, 1, '=', l_colin);
437 funset(vpixaspect, 1, ':', l_pixaspect);
438 for (i = 0; i < 7; i++)
439 funset(vray[i], 1, '=', l_ray);
440 funset(vpsize, 1, '=', l_psize);
441 /* set brightness function */
442 if (!strcmp(ourfmt, CIEFMT)) {
443 varset(vwhteff, ':', 1.0);
444 ourbright = xyz_bright;
445 } else
446 varset(vwhteff, ':', WHTEFFICACY);
447 /* these may be overridden */
448 varset(vxres, ':', (double)xmax);
449 varset(vyres, ':', (double)ymax);
450 }
451
452
453 static void
454 combine(void) /* combine pictures */
455 {
456 EPNODE *coldef[3], *brtdef;
457 int set_x, set_y;
458 COLOR *scanout;
459 double d;
460 int i, j;
461 /* check defined variables */
462 for (j = 0; j < 3; j++) {
463 if (vardefined(vcolout[j]))
464 coldef[j] = eparse(vcolout[j]);
465 else
466 coldef[j] = NULL;
467 }
468 if (vardefined(vbrtout))
469 brtdef = eparse(vbrtout);
470 else
471 brtdef = NULL;
472 /* what to set */
473 set_x = varlookup(vxpos) != NULL && !vardefined(vxpos);
474 set_y = varlookup(vypos) != NULL && !vardefined(vypos);
475 /* allocate scanline */
476 scanout = (COLOR *)emalloc(xres*sizeof(COLOR));
477 /* set input position */
478 yscan = ymax+MIDSCN;
479 /* combine files */
480 for (ypos = yres-1; ypos >= 0; ypos--) {
481 advance();
482 if (set_y) varset(vypos, '=', (double)ypos);
483 for (xpos = 0; xpos < xres; xpos++) {
484 xscan = (xpos+.5)*xmax/xres;
485 if (set_x) varset(vxpos, '=', (double)xpos);
486 eclock++;
487 if (brtdef != NULL) {
488 d = evalue(brtdef);
489 d *= (outfloat > 0) | (d >= 0);
490 setcolor(scanout[xpos], d, d, d);
491 } else {
492 for (j = 0; j < 3; j++) {
493 if (coldef[j] != NULL) {
494 d = evalue(coldef[j]);
495 } else {
496 d = 0.0;
497 for (i = 0; i < nfiles; i++)
498 d += colval(input[i].scan[MIDSCN][xscan],j);
499 }
500 d *= (outfloat > 0) | (d >= 0);
501 colval(scanout[xpos],j) = d;
502 }
503 }
504 }
505 switch (outfloat) {
506 case 3: /* writing out float triplets */
507 if (fwrite(scanout, sizeof(float)*3, xres, stdout) != xres)
508 goto writerr;
509 break;
510 case 1: /* writing out gray float values */
511 for (xpos = 0; xpos < xres; xpos++)
512 if (putbinary(&scanout[xpos][CIEY],
513 sizeof(float), 1, stdout) != 1)
514 goto writerr;
515 break;
516 default: /* writing out Radiance picture */
517 if (fwritescan(scanout, xres, stdout) < 0)
518 goto writerr;
519 break;
520 }
521 }
522 efree((char *)scanout);
523 return;
524 writerr:
525 perror("write error");
526 quit(1);
527 }
528
529
530 static void
531 advance(void) /* read in data for next scanline */
532 {
533 int ytarget;
534 COLOR *st;
535 int i, j;
536
537 for (ytarget = (ypos+.5)*ymax/yres; yscan > ytarget; yscan--)
538 for (i = 0; i < nfiles; i++) {
539 st = input[i].scan[WINSIZ-1];
540 for (j = WINSIZ-1; j > 0; j--) /* rotate window */
541 input[i].scan[j] = input[i].scan[j-1];
542 input[i].scan[0] = st;
543 if (yscan <= MIDSCN) /* hit bottom? */
544 continue;
545 /* read scanline */
546 if (input[i].infloat) {
547 if (fread(st, sizeof(float)*input[i].infloat,
548 xmax, input[i].fp) != xmax)
549 goto readerr;
550 if (input[i].infloat == 1) {
551 const COLORV *f = st[0] + xmax;
552 int x = xmax;
553 while (x-- > 0)
554 st[x][BLU] = st[x][GRN] =
555 st[x][RED] = *--f;
556 }
557 } else if (freadscan(st, xmax, input[i].fp) < 0)
558 goto readerr;
559 for (j = 0; j < xmax; j++) /* adjust color */
560 multcolor(st[j], input[i].coef);
561 }
562 return;
563 readerr:
564 eputs(input[i].name);
565 eputs(": read error\n");
566 quit(1);
567 }
568
569
570 static double
571 l_expos( /* return picture exposure */
572 char *nam
573 )
574 {
575 int fn, n;
576 double d;
577
578 d = argument(1);
579 if (d <= -0.5 || d >= nfiles+0.5) {
580 errno = EDOM;
581 return(0.0);
582 }
583 if (d < 0.5)
584 return((double)nfiles);
585 fn = d - 0.5;
586 if (nam == vbrtexp)
587 return((*ourbright)(input[fn].expos));
588 n = 3;
589 while (n--)
590 if (nam == vcolexp[n])
591 return(colval(input[fn].expos,n));
592 eputs("Bad call to l_expos()!\n");
593 quit(1);
594 return 1; /* pro forma return */
595 }
596
597
598 static double
599 l_pixaspect(char *nm) /* return pixel aspect ratio */
600 {
601 int fn;
602 double d;
603
604 d = argument(1);
605 if (d <= -0.5 || d >= nfiles+0.5) {
606 errno = EDOM;
607 return(0.0);
608 }
609 if (d < 0.5)
610 return((double)nfiles);
611 fn = d - 0.5;
612 return(input[fn].pa);
613 }
614
615
616 static double
617 l_colin( /* return color value for picture */
618 char *nam
619 )
620 {
621 int fn;
622 int n, xoff, yoff;
623 double d;
624
625 d = argument(1);
626 if (d <= -0.5 || d >= nfiles+0.5) {
627 errno = EDOM;
628 return(0.0);
629 }
630 if (d < 0.5)
631 return((double)nfiles);
632 fn = d - 0.5;
633 xoff = yoff = 0;
634 n = nargum();
635 if (n >= 2) {
636 d = argument(2);
637 if (d < 0.0) {
638 xoff = d-.5;
639 if (xscan+xoff < 0)
640 xoff = -xscan;
641 } else {
642 xoff = d+.5;
643 if (xscan+xoff >= xmax)
644 xoff = xmax-1-xscan;
645 }
646 }
647 if (n >= 3) {
648 d = argument(3);
649 if (d < 0.0) {
650 yoff = d-.5;
651 if (yoff+MIDSCN < 0)
652 yoff = -MIDSCN;
653 if (yscan+yoff < 0)
654 yoff = -yscan;
655 } else {
656 yoff = d+.5;
657 if (yoff+MIDSCN >= WINSIZ)
658 yoff = WINSIZ-1-MIDSCN;
659 if (yscan+yoff >= ymax)
660 yoff = ymax-1-yscan;
661 }
662 }
663 if (nam == vbrtin)
664 return((*ourbright)(input[fn].scan[MIDSCN+yoff][xscan+xoff]));
665 n = 3;
666 while (n--)
667 if (nam == vcolin[n])
668 return(colval(input[fn].scan[MIDSCN+yoff][xscan+xoff],n));
669 eputs("Bad call to l_colin()!\n");
670 quit(1);
671 return 1; /* pro forma return */
672 }
673
674
675 static double
676 l_ray( /* return ray origin or direction */
677 char *nam
678 )
679 {
680 static unsigned long ltick[MAXINP];
681 static FVECT lorg[MAXINP], ldir[MAXINP];
682 static double ldist[MAXINP];
683 RREAL loc[2];
684 double d;
685 int fn;
686 int i;
687
688 d = argument(1);
689 if (d <= -0.5 || d >= nfiles+0.5) {
690 errno = EDOM;
691 return(0.0);
692 }
693 if (d < 0.5)
694 return((double)nfiles);
695 fn = d - 0.5;
696 if (ltick[fn] != eclock) { /* need to compute? */
697 if (input[fn].vw.type == 0) {
698 lorg[fn][0] = lorg[fn][1] = lorg[fn][2] = 0.0;
699 ldir[fn][0] = ldir[fn][1] = ldir[fn][2] = 0.0;
700 ldist[fn] = -1.0;
701 errno = EDOM;
702 } else {
703 pix2loc(loc, &input[fn].rs, xscan, ymax-1-yscan);
704 ldist[fn] = viewray(lorg[fn], ldir[fn],
705 &input[fn].vw, loc[0], loc[1]);
706 if (ldist[fn] < -FTINY)
707 errno = EDOM;
708 }
709 ltick[fn] = eclock;
710 }
711 if (nam == vray[i=6])
712 return(ldist[fn]);
713 while (i--)
714 if (nam == vray[i])
715 return(i < 3 ? lorg[fn][i] : ldir[fn][i-3]);
716 eputs("Bad call to l_ray()!\n");
717 quit(1);
718 return 1; /* pro forma return */
719 }
720
721
722 static double
723 l_psize(char *nm) /* compute pixel size in steradians */
724 {
725 static unsigned long ltick[MAXINP];
726 static double psize[MAXINP];
727 FVECT dir0, org, dirx, diry;
728 RREAL locx[2], locy[2];
729 double d;
730 int fn;
731 int i;
732
733 d = argument(1);
734 if (d <= -0.5 || d >= nfiles+0.5) {
735 errno = EDOM;
736 return(0.0);
737 }
738 if (d < 0.5)
739 return((double)nfiles);
740 fn = d - 0.5;
741 if (ltick[fn] != eclock) { /* need to compute? */
742 psize[fn] = 0.0;
743 if (input[fn].vw.type == 0)
744 errno = EDOM;
745 else if (input[fn].vw.type != VT_PAR &&
746 funvalue(vray[6], 1, &d) >= -FTINY) {
747 for (i = 0; i < 3; i++)
748 dir0[i] = funvalue(vray[3+i], 1, &d);
749 pix2loc(locx, &input[fn].rs, xscan+1, ymax-1-yscan);
750 pix2loc(locy, &input[fn].rs, xscan, ymax-yscan);
751 if (viewray(org, dirx, &input[fn].vw,
752 locx[0], locx[1]) >= -FTINY &&
753 viewray(org, diry, &input[fn].vw,
754 locy[0], locy[1]) >= -FTINY) {
755 /* approximate solid angle */
756 for (i = 0; i < 3; i++) {
757 dirx[i] -= dir0[i];
758 diry[i] -= dir0[i];
759 }
760 fcross(dir0, dirx, diry);
761 psize[fn] = VLEN(dir0);
762 }
763 }
764 ltick[fn] = eclock;
765 }
766 return(psize[fn]);
767 }
768
769
770 extern void
771 wputs(const char *msg)
772 {
773 if (!nowarn)
774 eputs(msg);
775 }
776
777
778 extern void
779 eputs(const char *msg)
780 {
781 fputs(msg, stderr);
782 }
783
784
785 extern void
786 quit(int code) /* exit gracefully */
787 {
788 int i;
789 /* close input files */
790 for (i = 0; i < nfiles; i++)
791 if (input[i].name == Command)
792 pclose(input[i].fp);
793 else
794 fclose(input[i].fp);
795 exit(code);
796 }