fixup
[lcr.git] / libgsmfr / src / toast.c
1 /*
2  * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
3  * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
4  * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
5  */
6
7 /* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/toast.c,v 1.8 1996/07/02 10:41:04 jutta Exp $ */
8
9 #include        "toast.h"
10
11 /*  toast -- lossy sound compression using the gsm library.
12  */
13
14 char   * progname;
15
16 int     f_decode   = 0;         /* decode rather than encode     (-d) */
17 int     f_cat      = 0;         /* write to stdout; implies -p   (-c) */
18 int     f_force    = 0;         /* don't ask about replacements  (-f) */
19 int     f_precious = 0;         /* avoid deletion of original    (-p) */
20 int     f_fast     = 0;         /* use faster fpt algorithm      (-F) */
21 int     f_verbose  = 0;         /* debugging                     (-V) */
22 int     f_ltp_cut  = 0;         /* LTP cut-off margin            (-C) */
23
24 struct stat instat;             /* stat (inname)                 */
25
26 FILE    *in,     *out;
27 char    *inname, *outname;
28
29 /*
30  *  The function (*output)() writes a frame of 160 samples given as
31  *  160 signed 16 bit values (gsm_signals) to <out>.
32  *  The function (*input)() reads one such frame from <in>.
33  *  The function (*init_output)() begins output (e.g. writes a header).,
34  *  The function (*init_input)() begins input (e.g. skips a header).
35  *
36  *  There are different versions of input, output, init_input and init_output
37  *  for different formats understood by toast; which ones are used 
38  *  depends on the command line arguments and, in their absence, the
39  *  filename; the fallback is #defined in toast.h
40  *
41  *  The specific implementations of input, output, init_input and init_output
42  *  for a format `foo' live in toast_foo.c.
43  */
44
45 int     (*output   ) P((gsm_signal *)),
46         (*input    ) P((gsm_signal *));
47 int     (*init_input)  P((void)),
48         (*init_output) P((void));
49
50 static int      generic_init P0() { return 0; } /* NOP */
51
52 struct fmtdesc {
53
54         char * name, * longname, * suffix;
55
56         int  (* init_input )  P((void)),
57              (* init_output)  P((void));
58
59         int  (* input ) P((gsm_signal * )),
60              (* output) P((gsm_signal * ));
61
62 } f_audio = {
63                 "audio",
64                 "8 kHz, 8 bit u-law encoding with Sun audio header", ".au",
65                 audio_init_input,
66                 audio_init_output,
67                 ulaw_input,
68                 ulaw_output
69 }, f_ulaw = {
70                 "u-law", "plain 8 kHz, 8 bit u-law encoding", ".u",
71                 generic_init,
72                 generic_init,
73                 ulaw_input,
74                 ulaw_output 
75
76 }, f_alaw = {
77                 "A-law", "8 kHz, 8 bit A-law encoding", ".A",
78                 generic_init,
79                 generic_init,
80                 alaw_input,
81                 alaw_output
82
83 }, f_linear = {
84                 "linear",
85                 "16 bit (13 significant) signed 8 kHz signal", ".l",
86                 generic_init,
87                 generic_init,
88                 linear_input,
89                 linear_output
90 };
91
92 struct fmtdesc * alldescs[] = {
93         &f_audio,
94         &f_alaw,
95         &f_ulaw,
96         &f_linear,
97         (struct fmtdesc *)NULL
98 };
99
100 #define DEFAULT_FORMAT  f_ulaw          /* default audio format, others */
101                                         /* are: f_alaw,f_audio,f_linear */
102 struct fmtdesc * f_format  = 0;
103
104 /*
105  *  basename + suffix of a pathname
106  */
107 static char * endname P1((name), char * name)
108 {
109         if (name) {
110                 char * s = strrchr(name, '/');
111                 if (s && s[1]) name = s + 1;
112         }
113         return name;
114
115 }
116
117 /*
118  *  Try to figure out what we're supposed to do from the argv[0], if
119  *  any, and set the parameters accordingly.
120  */
121 static void parse_argv0 P1((av0), char * av0 )
122 {
123         int     l;
124
125         progname = av0 = endname(av0 ? av0 : "toast");
126
127         /*  If the name starts with `un', we want to decode, not code.
128          *  If the name ends in `cat', we want to write to stdout,
129          *  and decode as well.
130          */
131
132         if (!strncmp(av0, "un", 2)) f_decode = 1;
133         if (  (l = strlen(av0)) >= 3 /* strlen("cat") */
134            && !strcmp( av0 + l - 3, "cat" )) f_cat = f_decode = 1;
135 }
136
137
138 /*
139  *  Check whether the name (possibly generated by appending
140  *  .gsm to something else) is short enough for this system.
141  */
142 static int length_okay P1((name), char * name)
143 {
144         long    max_filename_length = 0;
145         char    * end;
146
147         /* If our _pathname_ is too long, we'll usually not be
148          * able to open the file at all -- don't worry about that.
149          * 
150          * But if the _filename_ is too long, there is danger of
151          * silent truncation on some systems, which results
152          * in the target replacing the source!
153          */
154
155         if (!name) return 0;
156         end = endname(name);
157
158 #ifdef  NAME_MAX
159         max_filename_length  = NAME_MAX;
160 #else
161 #ifdef  _PC_NAME_MAX
162 #ifdef USE_PATHCONF
163         {       char * s, tmp; 
164                 
165                 /*  s = dirname(name)
166                  */
167                 if ((s = end) > name) {
168                         if (s > name + 1) s--;
169                         tmp = s;
170                         *s  = 0;
171                 }
172
173                 errno = 0;
174                 max_filename_length = pathconf(s > name ? name : ".",
175                         _PC_NAME_MAX);
176                 if (max_filename_length == -1 && errno) {
177                         perror( s > name ? name : "." );
178                         fprintf(stderr,
179                 "%s: cannot get dynamic filename length limit for %s.\n",
180                                 progname, s > name ? name : ".");
181                         return 0;
182                 }
183                 if (s > name) *s = tmp;
184         }
185 #endif /* USE_PATHCONF  */
186 #endif /* _PC_NAME_MAX  */
187 #endif /* !NAME_MAX     */
188
189         if (max_filename_length > 0 && strlen(end) > max_filename_length) {
190                 fprintf(stderr,
191                         "%s: filename \"%s\" is too long (maximum is %ld)\n",
192                         progname, endname(name), max_filename_length );
193                 return 0;
194         }
195
196         return 1;
197 }
198
199 /*
200  *  Return a pointer the suffix of a string, if any.
201  *  A suffix alone has no suffix, an empty suffix can not be had.
202  */
203 static char * suffix P2((name, suf), char *name, char * suf) 
204 {
205         size_t nlen = strlen(name);
206         size_t slen = strlen(suf);
207
208         if (!slen || nlen <= slen) return (char *)0;
209         name += nlen - slen;
210         return memcmp(name, suf, slen) ? (char *)0 : name;
211 }
212
213
214 static void catch_signals P1((fun), SIGHANDLER_T (*fun) ()) 
215 {
216 #ifdef  SIGHUP
217         signal( SIGHUP,   fun );
218 #endif
219 #ifdef  SIGINT
220         signal( SIGINT,   fun );
221 #endif
222 #ifdef  SIGPIPE
223         signal( SIGPIPE,  fun );
224 #endif
225 #ifdef  SIGTERM
226         signal( SIGTERM,  fun );
227 #endif
228 #ifdef  SIGXFSZ
229         signal( SIGXFSZ,  fun );
230 #endif
231 }
232
233 static SIGHANDLER_T onintr P0()
234 {
235         char * tmp = outname;
236
237 #ifdef  HAS_SYSV_SIGNALS
238         catch_signals( SIG_IGN );
239 #endif
240
241         outname = (char *)0;
242         if (tmp) (void)unlink(tmp);
243
244         exit(1);
245 }
246
247 /*
248  *  Allocate some memory and complain if it fails.
249  */
250 static char * emalloc P1((len), size_t len)
251 {
252         char * s;
253         if (!(s = malloc(len))) {
254                 fprintf(stderr, "%s: failed to malloc %d bytes -- abort\n",
255                         progname, len);
256                 onintr();
257                 exit(1);
258         }
259         return s;
260 }
261
262 static char* normalname P3((name, want, cut), char *name, char *want,char *cut)
263 {
264         size_t  maxlen;
265         char    * s, * p;
266
267         p = (char *)0;
268         if (!name) return p;
269
270         maxlen = strlen(name) + 1 + strlen(want) + strlen(cut);
271         p = strcpy(emalloc(maxlen), name);
272
273         if (s = suffix(p, cut)) strcpy(s, want);
274         else if (*want && !suffix(p, want)) strcat(p, want);
275
276         return p;
277 }
278
279 /*
280  *  Generate a `plain' (non-encoded) name from a given name.
281  */
282 static char * plainname P1((name), char *name)
283 {
284         return normalname(name, "", SUFFIX_TOASTED );
285 }
286
287 /*
288  *  Generate a `code' name from a given name.
289  */
290 static char * codename P1((name), char *name)
291 {
292         return normalname( name, SUFFIX_TOASTED, "" );
293 }
294
295 /*
296  *  If we're supposed to ask (fileno (stderr) is a tty, and f_force not
297  *  set), ask the user whether to overwrite a file or not.
298  */
299 static int ok_to_replace P1(( name ), char * name)
300 {
301         int reply, c;
302
303         if (f_force) return 1;                  /* YES, do replace   */
304         if (!isatty(fileno(stderr))) return 0;  /* NO, don't replace */
305
306         fprintf(stderr,
307                 "%s already exists; do you wish to overwrite %s (y or n)? ",
308                 name, name);
309         fflush(stderr);
310
311         for (c = reply = getchar(); c != '\n' && c != EOF; c = getchar()) ;
312         if (reply == 'y') return 1;
313
314         fprintf(stderr, "\tnot overwritten\n");
315         return 0;
316 }
317
318 static void update_mode P0()
319 {
320         if (!instat.st_nlink) return;           /* couldn't stat in */
321
322 #ifdef HAS_FCHMOD
323         if (fchmod(fileno(out), instat.st_mode & 07777)) {
324                 perror(outname);
325                 fprintf(stderr, "%s: could not change file mode of \"%s\"\n",
326                         progname, outname);
327         }
328 #else 
329 #ifdef HAS_CHMOD
330         if (outname && chmod(outname, instat.st_mode & 07777)) {
331                 perror(outname);
332                 fprintf(stderr, "%s: could not change file mode of \"%s\"\n",
333                         progname, outname);
334         }
335 #endif /* HAS_CHMOD  */
336 #endif /* HAS_FCHMOD */
337 }
338
339 static void update_own P0()
340 {
341         if (!instat.st_nlink) return; /* couldn't stat in */
342 #ifdef HAS_FCHOWN
343         (void)fchown(fileno(out), instat.st_uid, instat.st_gid);
344 #else 
345 #ifdef HAS_CHOWN
346         (void)chown(outname, instat.st_uid, instat.st_gid);
347 #endif /* HAS_CHOWN  */
348 #endif /* HAS_FCHOWN */
349 }
350
351 static void update_times P0()
352 {
353         if (!instat.st_nlink) return;   /* couldn't stat in */
354
355 #ifdef HAS_UTIMES
356         if (outname) {
357                 struct timeval tv[2];
358
359                 tv[0].tv_sec  = instat.st_atime;
360                 tv[1].tv_sec  = instat.st_mtime;
361                 tv[0].tv_usec = tv[1].tv_usec = 0;
362                 (void) utimes(outname, tv);
363         }
364 #else
365 #ifdef HAS_UTIME
366
367         if (outname) {
368
369 #ifdef  HAS_UTIMBUF
370                 struct utimbuf ut;
371
372                 ut.actime     = instat.st_atime;
373                 ut.modtime    = instat.st_mtime;
374
375 #       ifdef   HAS_UTIMEUSEC
376                 ut.acusec     = instat.st_ausec;
377                 ut.modusec    = instat.st_musec;
378 #       endif   /* HAS_UTIMEUSEC */
379
380                 (void) utime(outname, &ut);
381
382 #else /* UTIMBUF */
383
384                 time_t ut[2];
385
386                 ut[0] = instat.st_atime;
387                 ut[1] = instat.st_mtime;
388
389                 (void) utime(outname, ut);
390
391 #endif  /* UTIMBUF */
392         }
393 #endif /* HAS_UTIME */
394 #endif /* HAS_UTIMES */
395 }
396
397
398 static int okay_as_input P3((name,f,st), char* name, FILE* f, struct stat * st)
399 {
400 # ifdef HAS_FSTAT
401         if (fstat(fileno(f), st) < 0)
402 # else
403         if (stat(name, st) < 0)
404 # endif
405         {
406                 perror(name);
407                 fprintf(stderr, "%s: cannot stat \"%s\"\n", progname, name);
408                 return 0;
409         }
410
411         if (!S_ISREG(st->st_mode)) {
412                 fprintf(stderr,
413                         "%s: \"%s\" is not a regular file -- unchanged.\n",
414                         progname, name);
415                 return 0;
416         }
417         if (st->st_nlink > 1 && !f_cat && !f_precious) {
418                 fprintf(stderr, 
419                       "%s: \"%s\" has %s other link%s -- unchanged.\n",
420                         progname,name,st->st_nlink - 1,"s" + (st->st_nlink<=2));
421                 return 0;
422         }
423         return 1;
424 }
425
426 static void prepare_io P1(( desc), struct fmtdesc * desc)
427 {
428         output      = desc->output;
429         input       = desc->input;
430
431         init_input  = desc->init_input;
432         init_output = desc->init_output;
433 }
434
435 static struct fmtdesc * grok_format P1((name), char * name)
436 {
437         char * c;
438         struct fmtdesc ** f;
439
440         if (name) {
441                 c = plainname(name);
442
443                 for (f = alldescs; *f; f++) {
444                         if (  (*f)->suffix
445                            && *(*f)->suffix
446                            && suffix(c, (*f)->suffix)) {
447
448                                 free(c);
449                                 return *f;
450                         }
451                 }
452
453                 free(c);
454         }
455         return (struct fmtdesc *)0;
456 }
457
458 static int open_input P2((name, st), char * name, struct stat * st)
459 {
460         struct fmtdesc * f = f_format;
461
462         st->st_nlink = 0;       /* indicates `undefined' value */
463         if (!name) {
464                 inname = (char *)NULL;
465                 in     = stdin;
466 #ifdef  HAS__FSETMODE
467                 _fsetmode(in, "b");
468 #endif
469         }
470         else {
471                 if (f_decode) inname = codename(name);
472                 else {
473                         if (!f_cat && suffix(name, SUFFIX_TOASTED)) {
474                                 fprintf(stderr,
475                         "%s: %s already has \"%s\" suffix -- unchanged.\n",
476                                         progname, name, SUFFIX_TOASTED );
477                                 return 0;
478                         }
479                         inname = strcpy(emalloc(strlen(name)+1), name);
480                 }
481                 if (!(in = fopen(inname, READ))) {
482                         perror(inname); /* not guaranteed to be valid here */
483                         fprintf(stderr, "%s: cannot open \"%s\" for reading\n",
484                                 progname, inname);
485                         return 0;
486                 }
487                 if (!okay_as_input(inname, in, st)) return 0;
488                 if (!f) f = grok_format(inname);
489         }
490         prepare_io( f ? f : & DEFAULT_FORMAT );
491         return 1;
492 }
493
494 static int open_output P1((name), char *name)
495 {
496         if (!name || f_cat) {
497                 out     = stdout;
498                 outname = (char *)NULL;
499 #ifdef  HAS__FSETMODE
500                 _fsetmode(out, "b"); 
501 #endif
502         }
503         else {
504                 int outfd = -1;
505                 char * o;
506
507                 o = (*(f_decode ? plainname : codename))(name);
508                 if (!length_okay(o)) return 0;
509                 if ((outfd = open(o, O_WRITE_EXCL, 0666)) >= 0)
510                         out = fdopen(outfd, WRITE);
511                 else if (errno != EEXIST) out = (FILE *)NULL;
512                 else if (ok_to_replace(o)) out = fopen(o, WRITE);
513                 else return 0;
514
515                 if (!out) {
516                         perror(o);
517                         fprintf(stderr,
518                                 "%s: can't open \"%s\" for writing\n",
519                                 progname, o);
520                         if (outfd >= 0) (void)close(outfd);
521                         return 0;
522                 }
523
524                 outname = o;
525         }
526         return 1;
527 }
528
529 static int process_encode P0()
530 {
531         gsm             r;
532         gsm_signal      s[ 160 ];
533         gsm_frame       d;
534  
535         int             cc;
536
537         if (!(r = gsm_create())) {
538                 perror(progname);
539                 return -1;
540         }
541         (void)gsm_option(r, GSM_OPT_FAST,       &f_fast);
542         (void)gsm_option(r, GSM_OPT_VERBOSE,    &f_verbose);
543         (void)gsm_option(r, GSM_OPT_LTP_CUT,    &f_ltp_cut);
544
545         while ((cc = (*input)(s)) > 0) {
546                 if (cc < sizeof(s) / sizeof(*s))
547                         memset((char *)(s+cc), 0, sizeof(s)-(cc * sizeof(*s)));
548                 gsm_encode(r, s, d);
549                 if (fwrite((char *)d, sizeof(d), 1, out) != 1) {
550                         perror(outname ? outname : "stdout");
551                         fprintf(stderr, "%s: error writing to %s\n",
552                                 progname, outname ? outname : "stdout");
553                         gsm_destroy(r);
554                         return -1;
555                 }
556         }
557         if (cc < 0) {
558                 perror(inname ? inname : "stdin");
559                 fprintf(stderr, "%s: error reading from %s\n",
560                         progname, inname ? inname : "stdin");
561                 gsm_destroy(r);
562                 return -1;
563         }
564         gsm_destroy(r);
565
566         return 0;
567 }
568
569 static int process_decode P0()
570 {
571         gsm             r;
572         gsm_frame       s;
573         gsm_signal      d[ 160 ];
574  
575         int             cc;
576
577         if (!(r = gsm_create())) {      /* malloc failed */
578                 perror(progname);
579                 return -1;
580         }
581         (void)gsm_option(r, GSM_OPT_FAST,    &f_fast);
582         (void)gsm_option(r, GSM_OPT_VERBOSE, &f_verbose);
583
584         while ((cc = fread(s, 1, sizeof(s), in)) > 0) {
585
586                 if (cc != sizeof(s)) {
587                         if (cc >= 0) fprintf(stderr,
588                         "%s: incomplete frame (%d byte%s missing) from %s\n",
589                                         progname, sizeof(s) - cc,
590                                         "s" + (sizeof(s) - cc == 1),
591                                         inname ? inname : "stdin" );
592                         gsm_destroy(r);
593                         errno = 0;
594                         return -1;
595                 }
596                 if (gsm_decode(r, s, d)) {
597                         fprintf(stderr, "%s: bad frame in %s\n", 
598                                 progname, inname ? inname : "stdin");
599                         gsm_destroy(r);
600                         errno = 0;
601                         return -1;
602                 }
603
604                 if ((*output)(d) < 0) {
605                         perror(outname);
606                         fprintf(stderr, "%s: error writing to %s\n",
607                                         progname, outname);
608                         gsm_destroy(r);
609                         return -1;
610                 }
611         }
612
613         if (cc < 0) {
614                 perror(inname ? inname : "stdin" );
615                 fprintf(stderr, "%s: error reading from %s\n", progname,
616                         inname ? inname : "stdin");
617                 gsm_destroy(r);
618                 return -1;
619         }
620
621         gsm_destroy(r);
622         return 0;
623 }
624
625 static int process P1((name), char * name)
626 {
627         int step = 0;
628
629         out     = (FILE *)0;
630         in      = (FILE *)0;
631
632         outname = (char *)0;
633         inname  = (char *)0;
634
635         if (!open_input(name, &instat) || !open_output(name))
636                 goto err;
637
638         if ((*(f_decode ? init_output    : init_input))()) {
639                 fprintf(stderr, "%s: error %s %s\n",
640                         progname,
641                         f_decode ? "writing header to" : "reading header from",
642                         f_decode ? (outname ? outname : "stdout")
643                                  : (inname ? inname : "stdin"));
644                 goto err;
645         }
646
647         if ((*(f_decode ? process_decode : process_encode))())
648                 goto err;
649
650         if (fflush(out) < 0 || ferror(out)) {
651                 perror(outname ? outname : "stdout");
652                 fprintf(stderr, "%s: error writing \"%s\"\n", progname,
653                                 outname ? outname:"stdout");
654                 goto err;
655         }
656
657         if (out != stdout) {
658
659                 update_times();
660                 update_mode ();
661                 update_own  ();
662
663                 if (fclose(out) < 0) {
664                         perror(outname);
665                         fprintf(stderr, "%s: error writing \"%s\"\n",
666                                 progname, outname);
667                         goto err;
668                 }
669                 if (outname != name) free(outname);
670                 outname = (char *)0;
671         }
672         out = (FILE *)0;
673         if (in  != stdin) {
674                 (void)fclose(in), in = (FILE *)0;
675                 if (!f_cat && !f_precious) {
676                         if (unlink(inname) < 0) {
677                                 perror(inname);
678                                 fprintf(stderr,
679                                         "%s: source \"%s\" not deleted.\n",
680                                         progname, inname);
681                         }
682                         goto err;
683                 }
684                 if (inname != name) free(inname);
685                 inname = (char *)0;
686         }
687         return 0;
688
689         /*
690          *  Error handling and cleanup.
691          */
692 err:
693         if (out && out != stdout) {
694                 (void)fclose(out), out = (FILE *)0;
695                 if (unlink(outname) < 0 && errno != ENOENT && errno != EINTR) {
696                         perror(outname);
697                         fprintf(stderr, "%s: could not unlink \"%s\"\n",
698                                 progname, outname);
699                 }
700         }
701         if (in && in != stdin) (void)fclose(in), in = (FILE *)0;
702
703         if (inname  && inname  != name) free(inname);
704         if (outname && outname != name) free(outname);
705
706         return -1;
707 }
708
709 static void version P0()
710 {
711         printf( "%s 1.0, version %s\n",
712                 progname,
713                 "$Id: toast.c,v 1.8 1996/07/02 10:41:04 jutta Exp $" );
714 }
715
716 static void help P0()
717 {
718         printf("Usage: %s [-fcpdhvaulsFC] [files...]\n", progname);
719         printf("\n");
720
721         printf(" -f  force     Replace existing files without asking\n");
722         printf(" -c  cat       Write to stdout, do not remove source files\n");
723         printf(" -d  decode    Decode data (default is encode)\n");
724         printf(" -p  precious  Do not delete the source\n");
725         printf("\n");
726
727         printf(" -u  u-law     Force 8 kHz/8 bit u-law in/output format\n");
728         printf(" -s  sun .au   Force Sun .au u-law in/output format\n");
729         printf(" -a  A-law     Force 8 kHz/8 bit A-law in/output format\n");
730         printf(" -l  linear    Force 16 bit linear in/output format\n");
731         printf("\n");
732
733         printf(" -F  fast      Sacrifice conformance to performance\n");
734         printf(" -C  cutoff    Ignore most samples during LTP\n");
735         printf(" -v  version   Show version information\n");
736         printf(" -h  help      Print this text\n");
737         printf("\n");
738 }
739
740
741 static void set_format P1((f), struct fmtdesc * f)
742 {
743         if (f_format && f_format != f) {
744                 fprintf( stderr,
745         "%s: only one of -[uals] is possible (%s -h for help)\n",
746                         progname, progname);
747                 exit(1);
748         }
749
750         f_format = f;
751 }
752
753 int main P2((ac, av), int ac, char **av)
754 {
755         int             opt;
756         extern int      optind;
757         extern char     * optarg;
758
759         parse_argv0(*av);
760
761         while ((opt = getopt(ac, av, "fcdpvhuaslVFC:")) != EOF) switch (opt) {
762
763         case 'd': f_decode   = 1; break;
764         case 'f': f_force    = 1; break;
765         case 'c': f_cat      = 1; break;
766         case 'p': f_precious = 1; break;
767         case 'F': f_fast     = 1; break;
768         case 'C': f_ltp_cut  = 100; break;
769 #ifndef NDEBUG
770         case 'V': f_verbose  = 1; break;        /* undocumented */
771 #endif
772
773         case 'u': set_format( &f_ulaw   ); break;
774         case 'l': set_format( &f_linear ); break;
775         case 'a': set_format( &f_alaw   ); break;
776         case 's': set_format( &f_audio  ); break;
777
778         case 'v': version(); exit(0);
779         case 'h': help();    exit(0);
780
781         default: 
782         usage:
783                 fprintf(stderr,
784         "Usage: %s [-fcpdhvuaslFC] [files...] (-h for help)\n",
785                         progname);
786                 exit(1);
787         }
788
789         f_precious |= f_cat;
790
791         av += optind;
792         ac -= optind;
793
794         catch_signals(onintr);
795
796         if (ac <= 0) process( (char *)0 );
797         else while (ac--) process( *av++ );
798
799         exit(0);
800 }