ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.9
Committed: Wed Nov 5 19:03:03 2003 UTC (20 years, 4 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.8: +12 -2 lines
Log Message:
Added check for too many input columns for binary buffer

File Contents

# User Rev Content
1 greg 1.1 #ifndef lint
2 greg 1.9 static const char RCSid[] = "$Id: rcalc.c,v 1.8 2003/08/01 14:14:23 schorsch Exp $";
3 greg 1.1 #endif
4     /*
5     * rcalc.c - record calculator program.
6     *
7     * 9/11/87
8     */
9    
10 schorsch 1.5 #include <stdlib.h>
11 greg 1.1 #include <stdio.h>
12 schorsch 1.5 #include <string.h>
13 greg 1.1 #include <math.h>
14     #include <ctype.h>
15    
16 schorsch 1.5 #include "platform.h"
17 greg 1.1 #include "calcomp.h"
18 schorsch 1.7 #include "rterror.h"
19 greg 1.1
20     #define isnum(c) (isdigit(c) || (c)=='-' || (c)=='.' \
21     || (c)=='+' || (c)=='e' || (c)=='E')
22    
23     #define isblnk(c) (igneol ? isspace(c) : (c)==' '||(c)=='\t')
24    
25     #define INBSIZ 4096 /* longest record */
26     #define MAXCOL 32 /* number of columns recorded */
27    
28     /* field type specifications */
29     #define F_NUL 0 /* empty */
30     #define F_TYP 0x7000 /* mask for type */
31     #define F_WID 0x0fff /* mask for width */
32     #define T_LIT 0x1000 /* string literal */
33     #define T_STR 0x2000 /* string variable */
34     #define T_NUM 0x3000 /* numeric value */
35    
36     struct strvar { /* string variable */
37     char *name;
38     char *val;
39     char *preset;
40     struct strvar *next;
41     };
42    
43     struct field { /* record format structure */
44     int type; /* type of field (& width) */
45     union {
46     char *sl; /* string literal */
47     struct strvar *sv; /* string variable */
48     char *nv; /* numeric variable */
49     EPNODE *ne; /* numeric expression */
50     } f; /* field contents */
51     struct field *next; /* next field in record */
52     };
53    
54     #define savqstr(s) strcpy(emalloc(strlen(s)+1),s)
55     #define freqstr(s) efree(s)
56    
57 schorsch 1.5 static void scaninp(void), advinp(void), resetinp(void);
58     static void putrec(void), putout(void), nbsynch(void);
59     static int getrec(void);
60     static void execute(char *file);
61     static void initinp(FILE *fp);
62     static void svpreset(char *eqn);
63     static void readfmt(char *spec, int output);
64     static int readfield(char **pp);
65     static int getfield(struct field *f);
66     static void chanset(int n, double v);
67     static void bchanset(int n, double v);
68     static struct strvar* getsvar(char *svname);
69 greg 1.1
70     struct field *inpfmt = NULL; /* input record format */
71     struct field *outfmt = NULL; /* output record structure */
72     struct strvar *svhead = NULL; /* string variables */
73    
74     int blnkeq = 1; /* blanks compare equal? */
75     int igneol = 0; /* ignore end of line? */
76     char sepchar = '\t'; /* input/output separator */
77     int noinput = 0; /* no input records? */
78 greg 1.3 int nbicols = 0; /* number of binary input columns */
79     int bocols = 0; /* produce binary output columns */
80 greg 1.1 char inpbuf[INBSIZ]; /* input buffer */
81     double colval[MAXCOL]; /* input column values */
82     unsigned long colflg = 0; /* column retrieved flags */
83     int colpos; /* output column position */
84    
85     int nowarn = 0; /* non-fatal diagnostic output */
86     int unbuff = 0; /* unbuffered output (flush each record) */
87    
88     struct {
89     FILE *fin; /* input file */
90     int chr; /* next character */
91     char *beg; /* home position */
92     char *pos; /* scan position */
93     char *end; /* read position */
94     } ipb; /* circular lookahead buffer */
95    
96    
97 schorsch 1.5 int
98     main(
99     int argc,
100     char *argv[]
101     )
102 greg 1.1 {
103     int i;
104    
105 greg 1.2 esupport |= E_VARIABLE|E_FUNCTION|E_INCHAN|E_OUTCHAN|E_RCONST;
106     esupport &= ~(E_REDEFW);
107 greg 1.1
108     #ifdef BIGGERLIB
109     biggerlib();
110     #endif
111     varset("PI", ':', 3.14159265358979323846);
112    
113     for (i = 1; i < argc && argv[i][0] == '-'; i++)
114     switch (argv[i][1]) {
115     case 'b':
116     blnkeq = !blnkeq;
117     break;
118     case 'l':
119     igneol = !igneol;
120     break;
121     case 't':
122     sepchar = argv[i][2];
123     break;
124     case 's':
125     svpreset(argv[++i]);
126     break;
127     case 'f':
128     fcompile(argv[++i]);
129     break;
130     case 'e':
131     scompile(argv[++i], NULL, 0);
132     break;
133     case 'n':
134     noinput = 1;
135     break;
136     case 'i':
137 greg 1.3 switch (argv[i][2]) {
138     case '\0':
139     nbicols = 0;
140     readfmt(argv[++i], 0);
141     break;
142     case 'a':
143     nbicols = 0;
144     break;
145     case 'd':
146     if (isdigit(argv[i][3]))
147     nbicols = atoi(argv[i]+3);
148     else
149     nbicols = 1;
150 greg 1.9 if (nbicols*sizeof(double) > INBSIZ) {
151     eputs(argv[0]);
152     eputs(": too many input columns\n");
153     quit(1);
154     }
155 greg 1.3 break;
156     case 'f':
157     if (isdigit(argv[i][3]))
158     nbicols = -atoi(argv[i]+3);
159     else
160     nbicols = -1;
161 greg 1.9 if (-nbicols*sizeof(float) > INBSIZ) {
162     eputs(argv[0]);
163     eputs(": too many input columns\n");
164     quit(1);
165     }
166 greg 1.3 break;
167     default:
168     goto userr;
169     }
170 greg 1.1 break;
171     case 'o':
172 greg 1.3 switch (argv[i][2]) {
173     case '\0':
174     bocols = 0;
175     readfmt(argv[++i], 1);
176     break;
177     case 'a':
178     bocols = 0;
179     break;
180     case 'd':
181     bocols = 1;
182     break;
183     case 'f':
184     bocols = -1;
185     break;
186     }
187 greg 1.1 break;
188     case 'w':
189     nowarn = !nowarn;
190     break;
191     case 'u':
192     unbuff = !unbuff;
193     break;
194 greg 1.3 default:;
195     userr:
196 greg 1.1 eputs("Usage: ");
197     eputs(argv[0]);
198     eputs(" [-b][-l][-n][-w][-u][-tS][-s svar=sval][-e expr][-f source][-i infmt][-o outfmt] [file]\n");
199     quit(1);
200     }
201    
202     if (noinput) { /* produce a single output record */
203     eclock++;
204     putout();
205     quit(0);
206     }
207    
208     if (blnkeq) /* for efficiency */
209     nbsynch();
210    
211     if (i == argc) /* from stdin */
212     execute(NULL);
213     else /* from one or more files */
214     for ( ; i < argc; i++)
215     execute(argv[i]);
216    
217     quit(0);
218     }
219    
220    
221 schorsch 1.5 static void
222     nbsynch(void) /* non-blank starting synch character */
223 greg 1.1 {
224     if (inpfmt == NULL || (inpfmt->type & F_TYP) != T_LIT)
225     return;
226     while (isblnk(*inpfmt->f.sl))
227     inpfmt->f.sl++;
228     if (!*inpfmt->f.sl)
229     inpfmt = inpfmt->next;
230     }
231    
232    
233 greg 1.3 int
234 schorsch 1.5 getinputrec( /* get next input record */
235     FILE *fp
236     )
237 greg 1.3 {
238     if (inpfmt != NULL)
239     return(getrec());
240     if (nbicols > 0)
241     return(fread(inpbuf, sizeof(double),
242     nbicols, fp) == nbicols);
243     if (nbicols < 0)
244     return(fread(inpbuf, sizeof(float),
245     -nbicols, fp) == -nbicols);
246     return(fgets(inpbuf, INBSIZ, fp) != NULL);
247     }
248    
249    
250 schorsch 1.5 static void
251     execute( /* process a file */
252     char *file
253     )
254 greg 1.1 {
255     int conditional = vardefined("cond");
256     long nrecs = 0;
257     long nout = 0;
258     FILE *fp;
259    
260     if (file == NULL)
261     fp = stdin;
262     else if ((fp = fopen(file, "r")) == NULL) {
263     eputs(file);
264     eputs(": cannot open\n");
265     quit(1);
266     }
267     if (inpfmt != NULL)
268     initinp(fp);
269 greg 1.3
270     while (getinputrec(fp)) {
271 greg 1.1 varset("recno", '=', (double)++nrecs);
272     colflg = 0;
273     eclock++;
274     if (!conditional || varvalue("cond") > 0.0) {
275     varset("outno", '=', (double)++nout);
276     putout();
277     }
278     }
279     fclose(fp);
280     }
281    
282    
283 schorsch 1.5 static void
284     putout(void) /* produce an output record */
285 greg 1.1 {
286    
287     colpos = 0;
288     if (outfmt != NULL)
289     putrec();
290 greg 1.3 else if (bocols)
291     chanout(bchanset);
292 greg 1.1 else
293     chanout(chanset);
294 greg 1.4 if (colpos && !bocols)
295 greg 1.1 putchar('\n');
296     if (unbuff)
297     fflush(stdout);
298     }
299    
300    
301     double
302 schorsch 1.5 chanvalue( /* return value for column n */
303     int n
304     )
305 greg 1.1 {
306     int i;
307     register char *cp;
308    
309     if (noinput || inpfmt != NULL) {
310     eputs("no column input\n");
311     quit(1);
312     }
313     if (n < 1) {
314     eputs("illegal channel number\n");
315     quit(1);
316     }
317 greg 1.3 if (nbicols > 0) {
318     if (n > nbicols)
319     return(0.0);
320     cp = inpbuf + (n-1)*sizeof(double);
321     return(*(double *)cp);
322     }
323     if (nbicols < 0) {
324     if (n > -nbicols)
325     return(0.0);
326     cp = inpbuf + (n-1)*sizeof(float);
327     return(*(float *)cp);
328     }
329 greg 1.1 if (n <= MAXCOL && colflg & 1L<<(n-1))
330     return(colval[n-1]);
331    
332     cp = inpbuf;
333     for (i = 1; i < n; i++)
334     if (blnkeq && isspace(sepchar)) {
335     while (isspace(*cp))
336     cp++;
337     while (*cp && !isspace(*cp))
338     cp++;
339     } else
340     while (*cp && *cp++ != sepchar)
341     ;
342    
343     while (isspace(*cp)) /* some atof()'s don't like tabs */
344     cp++;
345    
346     if (n <= MAXCOL) {
347     colflg |= 1L<<(n-1);
348     return(colval[n-1] = atof(cp));
349     } else
350     return(atof(cp));
351     }
352    
353    
354 greg 1.3 void
355 schorsch 1.5 chanset( /* output column n */
356     int n,
357     double v
358     )
359 greg 1.1 {
360     if (colpos == 0) /* no leading separator */
361     colpos = 1;
362     while (colpos < n) {
363     putchar(sepchar);
364     colpos++;
365     }
366     printf("%.9g", v);
367 greg 1.3 }
368    
369    
370     void
371 schorsch 1.5 bchanset( /* output binary channel n */
372     int n,
373     double v
374     )
375 greg 1.3 {
376     static char zerobuf[sizeof(double)];
377    
378     while (++colpos < n)
379     fwrite(zerobuf,
380     bocols>0 ? sizeof(double) : sizeof(float),
381     1, stdout);
382     if (bocols > 0)
383     fwrite(&v, sizeof(double), 1, stdout);
384     else {
385     float fval = v;
386     fwrite(&fval, sizeof(float), 1, stdout);
387     }
388 greg 1.1 }
389    
390    
391 schorsch 1.5 static void
392     readfmt( /* read record format */
393     char *spec,
394     int output
395     )
396 greg 1.1 {
397     int fd;
398     char *inptr;
399     struct field fmt;
400     int res;
401     register struct field *f;
402     /* check for inline format */
403     for (inptr = spec; *inptr; inptr++)
404     if (*inptr == '$')
405     break;
406     if (*inptr) /* inline */
407     inptr = spec;
408     else { /* from file */
409     if ((fd = open(spec, 0)) == -1) {
410     eputs(spec);
411     eputs(": cannot open\n");
412     quit(1);
413     }
414     res = read(fd, inpbuf+1, INBSIZ-1);
415     if (res <= 0 || res >= INBSIZ-1) {
416     eputs(spec);
417     if (res < 0)
418     eputs(": read error\n");
419     else if (res == 0)
420     eputs(": empty file\n");
421     else if (res >= INBSIZ-1)
422     eputs(": format too long\n");
423     quit(1);
424     }
425     close(fd);
426     (inptr=inpbuf+1)[res] = '\0';
427     }
428     f = &fmt; /* get fields */
429     while ((res = readfield(&inptr)) != F_NUL) {
430     f->next = (struct field *)emalloc(sizeof(struct field));
431     f = f->next;
432     f->type = res;
433     switch (res & F_TYP) {
434     case T_LIT:
435     f->f.sl = savqstr(inpbuf);
436     break;
437     case T_STR:
438     f->f.sv = getsvar(inpbuf);
439     break;
440     case T_NUM:
441     if (output)
442     f->f.ne = eparse(inpbuf);
443     else
444     f->f.nv = savestr(inpbuf);
445     break;
446     }
447     /* add final newline if necessary */
448     if (!igneol && *inptr == '\0' && inptr[-1] != '\n')
449     inptr = "\n";
450     }
451     f->next = NULL;
452     if (output)
453     outfmt = fmt.next;
454     else
455     inpfmt = fmt.next;
456     }
457    
458    
459 schorsch 1.5 static int
460     readfield( /* get next field in format */
461     register char **pp
462     )
463 greg 1.1 {
464     int type = F_NUL;
465     int width = 0;
466     register char *cp;
467    
468     cp = inpbuf;
469     while (cp < &inpbuf[INBSIZ-1] && **pp != '\0') {
470     width++;
471     switch (type) {
472     case F_NUL:
473     if (**pp == '$') {
474     (*pp)++;
475     width++;
476     if (**pp == '{') {
477     type = T_NUM;
478     (*pp)++;
479     continue;
480     } else if (**pp == '(') {
481     type = T_STR;
482     (*pp)++;
483     continue;
484     } else if (**pp != '$') {
485     eputs("format error\n");
486     quit(1);
487     }
488     width--;
489     }
490     type = T_LIT;
491     *cp++ = *(*pp)++;
492     continue;
493     case T_LIT:
494     if (**pp == '$') {
495     width--;
496     break;
497     }
498     *cp++ = *(*pp)++;
499     continue;
500     case T_NUM:
501     if (**pp == '}') {
502     (*pp)++;
503     break;
504     }
505     if (!isspace(**pp))
506     *cp++ = **pp;
507     (*pp)++;
508     continue;
509     case T_STR:
510     if (**pp == ')') {
511     (*pp)++;
512     break;
513     }
514     if (!isspace(**pp))
515     *cp++ = **pp;
516     (*pp)++;
517     continue;
518     }
519     break;
520     }
521     *cp = '\0';
522     return(type | width);
523     }
524    
525    
526     struct strvar *
527 schorsch 1.5 getsvar( /* get string variable */
528     char *svname
529     )
530 greg 1.1 {
531     register struct strvar *sv;
532    
533     for (sv = svhead; sv != NULL; sv = sv->next)
534     if (!strcmp(sv->name, svname))
535     return(sv);
536     sv = (struct strvar *)emalloc(sizeof(struct strvar));
537     sv->name = savqstr(svname);
538     sv->val = sv->preset = NULL;
539     sv->next = svhead;
540     svhead = sv;
541     return(sv);
542     }
543    
544    
545 schorsch 1.5 static void
546     svpreset( /* preset a string variable */
547     char *eqn
548     )
549 greg 1.1 {
550     register struct strvar *sv;
551     register char *val;
552    
553     for (val = eqn; *val != '='; val++)
554     if (!*val)
555     return;
556     *val++ = '\0';
557     sv = getsvar(eqn);
558     if (sv->preset != NULL)
559     freqstr(sv->preset);
560     if (sv->val != NULL)
561     freqstr(sv->val);
562     sv->val = sv->preset = savqstr(val);
563     *--val = '=';
564     }
565    
566    
567 schorsch 1.5 static void
568     clearrec(void) /* clear input record variables */
569 greg 1.1 {
570     register struct field *f;
571    
572     for (f = inpfmt; f != NULL; f = f->next)
573     switch (f->type & F_TYP) {
574     case T_NUM:
575     dremove(f->f.nv);
576     break;
577     case T_STR:
578     if (f->f.sv->val != f->f.sv->preset) {
579     freqstr(f->f.sv->val);
580     f->f.sv->val = f->f.sv->preset;
581     }
582     break;
583     }
584     }
585    
586    
587 schorsch 1.5 static int
588     getrec(void) /* get next record from file */
589 greg 1.1 {
590     int eatline;
591     register struct field *f;
592    
593     while (ipb.chr != EOF) {
594     eatline = !igneol && ipb.chr != '\n';
595     if (blnkeq) /* beware of nbsynch() */
596     while (isblnk(ipb.chr))
597     scaninp();
598     clearrec(); /* start with fresh record */
599     for (f = inpfmt; f != NULL; f = f->next)
600     if (getfield(f) == -1)
601     break;
602     if (f == NULL) {
603     advinp();
604     return(1);
605     }
606     resetinp();
607     if (eatline) { /* eat rest of line */
608     while (ipb.chr != '\n') {
609     if (ipb.chr == EOF)
610     return(0);
611     scaninp();
612     }
613     scaninp();
614     advinp();
615     }
616     }
617     return(0);
618     }
619    
620    
621 schorsch 1.5 static int
622     getfield( /* get next field */
623     register struct field *f
624     )
625 greg 1.1 {
626 schorsch 1.6 static char buf[RMAXWORD+1]; /* no recursion! */
627 greg 1.1 int delim, inword;
628     double d;
629     char *np;
630     register char *cp;
631    
632     switch (f->type & F_TYP) {
633     case T_LIT:
634     cp = f->f.sl;
635     do {
636     if (blnkeq && isblnk(*cp)) {
637     if (!isblnk(ipb.chr))
638     return(-1);
639     do
640     cp++;
641     while (isblnk(*cp));
642     do
643     scaninp();
644     while (isblnk(ipb.chr));
645     } else if (*cp == ipb.chr) {
646     cp++;
647     scaninp();
648     } else
649     return(-1);
650     } while (*cp);
651     return(0);
652     case T_STR:
653     if (f->next == NULL || (f->next->type & F_TYP) != T_LIT)
654     delim = EOF;
655     else
656     delim = f->next->f.sl[0];
657     cp = buf;
658     do {
659 greg 1.9 if (ipb.chr == EOF || ipb.chr == '\n')
660 greg 1.1 inword = 0;
661     else if (blnkeq && delim != EOF)
662     inword = isblnk(delim) ?
663     !isblnk(ipb.chr)
664     : ipb.chr != delim;
665     else
666     inword = cp-buf < (f->type & F_WID);
667     if (inword) {
668     *cp++ = ipb.chr;
669     scaninp();
670     }
671 schorsch 1.6 } while (inword && cp < &buf[RMAXWORD]);
672 greg 1.1 *cp = '\0';
673     if (f->f.sv->val == NULL)
674     f->f.sv->val = savqstr(buf); /* first setting */
675     else if (strcmp(f->f.sv->val, buf))
676     return(-1); /* doesn't match! */
677     return(0);
678     case T_NUM:
679     if (f->next == NULL || (f->next->type & F_TYP) != T_LIT)
680     delim = EOF;
681     else
682     delim = f->next->f.sl[0];
683     np = NULL;
684     cp = buf;
685     do {
686     if (!((np==NULL&&isblnk(ipb.chr)) || isnum(ipb.chr)))
687     inword = 0;
688     else if (blnkeq && delim != EOF)
689     inword = isblnk(delim) ?
690     !isblnk(ipb.chr)
691     : ipb.chr != delim;
692     else
693     inword = cp-buf < (f->type & F_WID);
694     if (inword) {
695     if (np==NULL && !isblnk(ipb.chr))
696     np = cp;
697     *cp++ = ipb.chr;
698     scaninp();
699     }
700 schorsch 1.6 } while (inword && cp < &buf[RMAXWORD]);
701 greg 1.1 *cp = '\0';
702     d = np==NULL ? 0. : atof(np);
703     if (!vardefined(f->f.nv))
704     varset(f->f.nv, '=', d); /* first setting */
705     else if ((d = (varvalue(f->f.nv)-d)/(d==0.?1.:d)) > .001
706     || d < -.001)
707     return(-1); /* doesn't match! */
708     return(0);
709     }
710 schorsch 1.5 return -1; /* pro forma return */
711 greg 1.1 }
712    
713    
714 schorsch 1.5 static void
715     putrec(void) /* output a record */
716 greg 1.1 {
717     char fmt[32];
718     register int n;
719     register struct field *f;
720     int adlast, adnext;
721    
722     adlast = 0;
723     for (f = outfmt; f != NULL; f = f->next) {
724     adnext = blnkeq &&
725     f->next != NULL &&
726     !( (f->next->type&F_TYP) == T_LIT &&
727     f->next->f.sl[0] == ' ' );
728     switch (f->type & F_TYP) {
729     case T_LIT:
730     fputs(f->f.sl, stdout);
731     adlast = f->f.sl[(f->type&F_WID)-1] != ' ';
732     break;
733     case T_STR:
734     if (f->f.sv->val == NULL) {
735     eputs(f->f.sv->name);
736     eputs(": undefined string\n");
737     quit(1);
738     }
739     n = (int)(f->type & F_WID) - strlen(f->f.sv->val);
740     if (adlast)
741     fputs(f->f.sv->val, stdout);
742     if (!(adlast && adnext))
743     while (n-- > 0)
744     putchar(' ');
745     if (!adlast)
746     fputs(f->f.sv->val, stdout);
747     adlast = 1;
748     break;
749     case T_NUM:
750     n = f->type & F_WID;
751     if (adlast && adnext)
752     strcpy(fmt, "%g");
753     else if (adlast)
754     sprintf(fmt, "%%-%dg", n);
755     else
756     sprintf(fmt, "%%%dg", n);
757     printf(fmt, evalue(f->f.ne));
758     adlast = 1;
759     break;
760     }
761     }
762     }
763    
764    
765 schorsch 1.5 static void
766     initinp(FILE *fp) /* prepare lookahead buffer */
767    
768 greg 1.1 {
769     ipb.fin = fp;
770     ipb.beg = ipb.end = inpbuf;
771     ipb.pos = inpbuf-1; /* position before beginning */
772     ipb.chr = '\0';
773     scaninp();
774     }
775    
776    
777 schorsch 1.5 static void
778     scaninp(void) /* scan next character */
779 greg 1.1 {
780     if (ipb.chr == EOF)
781     return;
782     if (++ipb.pos >= &inpbuf[INBSIZ])
783     ipb.pos = inpbuf;
784     if (ipb.pos == ipb.end) { /* new character */
785     if ((ipb.chr = getc(ipb.fin)) != EOF) {
786     *ipb.end = ipb.chr;
787     if (++ipb.end >= &inpbuf[INBSIZ])
788     ipb.end = inpbuf;
789     if (ipb.end == ipb.beg)
790     ipb.beg = NULL;
791     }
792     } else
793     ipb.chr = *ipb.pos;
794     }
795    
796    
797 schorsch 1.5 static void
798     advinp(void) /* move home to current position */
799 greg 1.1 {
800     ipb.beg = ipb.pos;
801     }
802    
803    
804 schorsch 1.5 static void
805     resetinp(void) /* rewind position and advance 1 */
806 greg 1.1 {
807     if (ipb.beg == NULL) /* full */
808     ipb.beg = ipb.end;
809     ipb.pos = ipb.beg;
810     ipb.chr = *ipb.pos;
811     if (++ipb.beg >= &inpbuf[INBSIZ])
812     ipb.beg = inpbuf;
813     scaninp();
814     }
815    
816    
817     void
818 schorsch 1.5 eputs(char *msg)
819 greg 1.1 {
820     fputs(msg, stderr);
821     }
822    
823    
824     void
825 schorsch 1.5 wputs(char *msg)
826 greg 1.1 {
827     if (!nowarn)
828     eputs(msg);
829     }
830    
831    
832     void
833 schorsch 1.5 quit(int code)
834 greg 1.1 {
835     exit(code);
836     }