ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/pcomb.c
Revision: 2.62
Committed: Sat Jun 7 05:09:46 2025 UTC (12 days, 3 hours ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.61: +1 -2 lines
Log Message:
refactor: Put some declarations into "paths.h" and included in "platform.h"

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: pcomb.c,v 2.61 2025/06/03 21:31: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 "color.h"
13 #include "calcomp.h"
14 #include "view.h"
15
16 #define MAXINP 1024 /* maximum number of input files */
17 #define WINSIZ 127 /* scanline window size */
18 #define MIDSCN ((WINSIZ-1)/2+1)
19
20 struct {
21 char *name; /* file or command name */
22 FILE *fp; /* stream pointer */
23 VIEW vw; /* view for picture */
24 RESOLU rs; /* image resolution and orientation */
25 int infloat; /* input is floating point (#comp)? */
26 float pa; /* pixel aspect ratio */
27 COLOR *scan[WINSIZ]; /* input scanline window */
28 COLOR coef; /* coefficient */
29 COLOR expos; /* recorded exposure */
30 } input[MAXINP]; /* input pictures */
31
32 int nfiles; /* number of input files */
33
34 VIEW *commvp = NULL; /* common view parameters */
35
36 char ourfmt[MAXFMTLEN] = PICFMT; /* input picture format */
37 int outfloat = 0; /* #component float output? */
38
39 char StandardInput[] = "<stdin>";
40 char Command[] = "<Command>";
41 char vcolin[3][4] = {"ri", "gi", "bi"};
42 char vcolout[3][4] = {"ro", "go", "bo"};
43 char vbrtin[] = "li";
44 char vbrtout[] = "lo";
45 char vcolexp[3][4] = {"re", "ge", "be"};
46 char vbrtexp[] = "le";
47 char vpixaspect[] = "pa";
48
49 char vray[7][4] = {"Ox", "Oy", "Oz", "Dx", "Dy", "Dz", "T"};
50
51 char vpsize[] = "S";
52
53 char vnfiles[] = "nfiles";
54 char vwhteff[] = "WE";
55 char vxmax[] = "xmax";
56 char vymax[] = "ymax";
57 char vxres[] = "xres";
58 char vyres[] = "yres";
59 char vxpos[] = "x";
60 char vypos[] = "y";
61
62 int nowarn = 0; /* no warning messages? */
63
64 int xmax = 0, ymax = 0; /* input resolution */
65
66 int xscan, yscan; /* input position */
67
68 int xres, yres; /* output resolution */
69
70 int xpos, ypos; /* output position */
71
72 int echoheader = 1;
73 int wrongformat = 0;
74 int gotview;
75
76
77 static gethfunc headline;
78 static void checkfile(int orig);
79 static double rgb_bright(COLOR clr);
80 static double xyz_bright(COLOR clr);
81 static void init(void);
82 static void combine(void);
83 static void advance(void);
84 static double l_expos(char *nam);
85 static double l_pixaspect(char *nm);
86 static double l_colin(char *nam);
87 static double l_ray(char *nam);
88 static double l_psize(char *nm);
89
90
91 int
92 main(
93 int argc,
94 char *argv[]
95 )
96 {
97 int original;
98 double f;
99 int a;
100
101 SET_DEFAULT_BINARY();
102 SET_FILE_BINARY(stdin);
103 SET_FILE_BINARY(stdout);
104 fixargv0(argv[0]); /* sets global progname */
105 esupport |= E_VARIABLE|E_FUNCTION|E_RCONST;
106 esupport &= ~(E_OUTCHAN|E_INCHAN);
107 /* scan options */
108 for (a = 1; a < argc; a++) {
109 if (argv[a][0] == '-')
110 switch (argv[a][1]) {
111 case 'x':
112 case 'y':
113 a++;
114 continue;
115 case 'w':
116 nowarn = !nowarn;
117 continue;
118 case 'h':
119 echoheader = !echoheader;
120 continue;
121 case 'f':
122 if (argv[a][2]) {
123 outfloat = (argv[a][2] == 'f');
124 continue;
125 }
126 /* fall through */
127 case 'e':
128 a++;
129 continue;
130 }
131 break;
132 }
133 newheader("RADIANCE", stdout); /* start header */
134 fputnow(stdout);
135 /* process files */
136 for (nfiles = 0; nfiles < MAXINP; nfiles++) {
137 setcolor(input[nfiles].coef, 1.0, 1.0, 1.0);
138 setcolor(input[nfiles].expos, 1.0, 1.0, 1.0);
139 input[nfiles].vw = stdview;
140 input[nfiles].pa = 1.0;
141 }
142 nfiles = 0;
143 original = 0;
144 for ( ; a < argc; a++) {
145 if (nfiles >= MAXINP) {
146 eputs(argv[0]);
147 eputs(": too many picture files\n");
148 quit(1);
149 }
150 if (argv[a][0] == '-')
151 switch (argv[a][1]) {
152 case '\0':
153 input[nfiles].name = StandardInput;
154 input[nfiles].fp = stdin;
155 break;
156 case 'o':
157 original++;
158 continue;
159 case 's':
160 f = atof(argv[++a]);
161 scalecolor(input[nfiles].coef, f);
162 continue;
163 case 'c':
164 colval(input[nfiles].coef,RED)*=atof(argv[++a]);
165 colval(input[nfiles].coef,GRN)*=atof(argv[++a]);
166 colval(input[nfiles].coef,BLU)*=atof(argv[++a]);
167 continue;
168 default:
169 goto usage;
170 }
171 else {
172 if (argv[a][0] == '!') {
173 input[nfiles].name = Command;
174 input[nfiles].fp = popen(argv[a]+1, "r");
175 } else {
176 input[nfiles].name = argv[a];
177 input[nfiles].fp = fopen(argv[a], "r");
178 }
179 if (input[nfiles].fp == NULL) {
180 perror(argv[a]);
181 quit(1);
182 }
183 }
184 checkfile(original);
185 nfiles++;
186 original = 0;
187 }
188 init(); /* set constants */
189 /* go back and get expressions */
190 for (a = 1; a < argc; a++) {
191 char *fpath;
192 if (argv[a][0] == '-')
193 switch (argv[a][1]) {
194 case 'x':
195 varset(vxres, ':', eval(argv[++a]));
196 continue;
197 case 'y':
198 varset(vyres, ':', eval(argv[++a]));
199 continue;
200 case 'w':
201 continue;
202 case 'h':
203 continue;
204 case 'f':
205 if (argv[a][2])
206 continue;
207 fpath = getpath(argv[++a], getrlibpath(), 0);
208 if (fpath == NULL) {
209 eputs(argv[0]);
210 eputs(": cannot find file '");
211 eputs(argv[a]);
212 eputs("'\n");
213 quit(1);
214 }
215 fcompile(fpath);
216 continue;
217 case 'e':
218 scompile(argv[++a], NULL, 0);
219 continue;
220 }
221 break;
222 }
223 /* get output resolution */
224 xres = varvalue(vxres) + .5;
225 yres = varvalue(vyres) + .5;
226 if (xres <= 0 || yres <= 0) {
227 eputs(argv[0]);
228 eputs(": illegal output resolution\n");
229 quit(1);
230 }
231 if (!vardefined(vbrtout)) /* single or 3-channel? */
232 outfloat *= 3;
233
234 printargs(argc, argv, stdout); /* complete header */
235 if (commvp != NULL) {
236 fputs(VIEWSTR, stdout);
237 fprintview(commvp, stdout);
238 fputc('\n', stdout);
239 }
240 if (outfloat) { /* print output format */
241 printf("NROWS=%d\nNCOLS=%d\n", yres, xres);
242 fputncomp(outfloat, stdout);
243 fputendian(stdout);
244 fputformat("float", stdout);
245 } else if (strcmp(ourfmt, PICFMT))
246 fputformat(ourfmt, stdout);
247 else
248 fputformat(COLRFMT, stdout);
249 fputc('\n', stdout); /* end header */
250 if (!outfloat)
251 fprtresolu(xres, yres, stdout);
252
253 doptimize(1); /* optimize definitions */
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 }