Fix compile errors caused by r4500 / r4501.
[asterisk/asterisk.git] / utils / frame.c
1 /****************************************************************************
2  *
3  * Programs for processing sound files in raw- or WAV-format.
4  * -- Useful functions for parsing command line options and
5  *    issuing errors, warnings, and chit chat.
6  *
7  * Name:    frame.c
8  * Version: see static char *standardversion, below.
9  * Author:  Mark Roberts <mark@manumark.de>
10  *          Michael Labuschke <michael@labuschke.de> sys_errlist fixes 
11  *              
12  ****************************************************************************/
13 /****************************************************************************
14  *  These are useful functions that all DSP programs might find handy
15  ****************************************************************************/
16
17 #include <stdio.h>
18 #include <math.h>
19 #include <stdlib.h> /* for exit and malloc */
20 #include <string.h>
21 #include <time.h>
22 #include <stdarg.h>
23 #include <errno.h>
24 #include <assert.h>
25 #include "frame.h"
26
27 time_t stopwatch;       /* will hold time at start of calculation */
28 int samplefrequency;
29 unsigned short samplewidth;
30 unsigned short channels;
31 int wavout;            /* TRUE iff out file should be a .WAV file */
32 int iswav;             /* TRUE iff in file was found to be a .WAV file */
33 FILE *in, *out;
34 char *infilename, *outfilename;
35 int verboselevel;
36 char *version = "";
37 char *usage = "";
38 static int test_usage;
39
40 static char *standardversion = "frame version 1.3, June 13th 2001";
41 static char *standardusage =
42 "\nOptions common to all mark-dsp programs:\n"
43
44 "-h \t\t create a WAV-header on output files.\n"
45 "-c#\t\t set number of channels to # (1 or 2). Default: like input.\n"
46 "-w#\t\t set number of bits per sample (width) to # (only 16)\n"
47 "-f#\t\t set sample frequency to #. Default: like input.\n"
48 "-V \t\t verbose: talk a lot.\n"
49 "-Q \t\t quiet: talk as little as possible.\n\n"
50 "In most cases, a filename of '-' means stdin or stdout.\n\n"
51 "Bug-reports: mark@manumark.de\n"
52 ;
53
54 /* -----------------------------------------------------------------------
55    Writes the number of samples to result that are yet to be read from anyin.
56    Return values are TRUE on success, FALSE on failure.
57    -----------------------------------------------------------------------*/
58 int getremainingfilelength( FILE *anyin, long *result)
59 {
60     long i;
61
62     i = ftell(anyin);
63     if (i == -1) return FALSE;
64     if (fseek(anyin, 0, SEEK_END) == -1) return FALSE;
65     *result = ftell(anyin);
66     if (*result == -1) return FALSE;
67     (*result) -= i;
68     (*result) /= samplewidth;
69     if (fseek(anyin, i, SEEK_SET) == -1) return FALSE;
70     return TRUE;
71 }
72
73 /* -----------------------------------------------------------------------
74    Read a .pk-header from 'anyin'.
75    -----------------------------------------------------------------------*/
76 void readpkheader( FILE *anyin)
77 {
78    unsigned short tempushort;
79    int tempint, i, x;
80    unsigned char blood[8];
81
82    for (i = 0; i < 11; i++)
83    {
84            if (!fread( &tempint, 4, 1, anyin)) {
85                    return;
86            }
87            printf( "%d: %d, ", i, tempint);
88    }
89    printf( "\n");
90    if (!fread( blood, 1, 8, anyin)) {
91            return;
92    }
93    for (i = 0; i < 8; i++)
94            printf( "%d ", blood[i]);
95    printf( "\n");
96    for (i = 0; i < 8; i++)
97    {
98            for (x = 128; x > 0; x /= 2)
99                    printf((blood[i] & x) == 0? "0 ":"1 ");
100            printf(i%4==3? "\n":"| ");
101    }
102    printf( "\n");
103    for (i = 0; i < 2; i++)
104    {
105            if (!fread( &tempint, 4, 1, anyin)) {
106                    return;
107            }
108            printf( "%d: %d, ", i, tempint);
109    }
110    printf( "\n");
111    for (i = 0; i < 2; i++)
112    {
113            if (!fread( &tempushort, 2, 1, anyin)) {
114                    return;
115            }
116            printf( "%d: %d, ", i, tempushort);
117    }
118    printf( "\n");
119 }
120
121
122
123 /* -----------------------------------------------------------------------
124    Read a .WAV header from 'anyin'. See header for details.
125    -----------------------------------------------------------------------*/
126 void readwavheader( FILE *anyin)
127 {
128    unsigned int tempuint, sf;
129    unsigned short tempushort, cn;
130    char str[9];
131    int nowav = FALSE;
132
133    iswav = FALSE;
134
135    if (ftell(anyin) == -1) /* If we cannot seek this file */
136    {
137            nowav = TRUE;   /* -> Pretend this is no wav-file */
138            chat("File not seekable: not checking for WAV-header.\n");
139    }
140    else
141    {
142            /* Expect four bytes "RIFF" and four bytes filelength */
143            if (!fread(str, 1, 8, anyin)) {           /* 0 */
144                    return;
145            }
146            str[4] = '\0';
147            if (strcmp(str, "RIFF") != 0) nowav = TRUE;
148            /* Expect eight bytes "WAVEfmt " */
149            if (!fread(str, 1, 8, anyin)) {           /* 8 */
150                    return;
151            }
152            str[8] = '\0';
153            if (strcmp(str, "WAVEfmt ") != 0) nowav = TRUE;
154            /* Expect length of fmt data, which should be 16 */
155            if (!fread(&tempuint, 4, 1, anyin)) {        /* 16 */
156                    return;
157            }
158            if (tempuint != 16) nowav = TRUE;
159            /* Expect format tag, which should be 1 for pcm */
160            if (!fread(&tempushort, 2, 1, anyin)) { /* 20 */
161                    return;
162            }
163            if (tempushort != 1)
164                    nowav = TRUE;
165            /* Expect number of channels */
166            if (!fread(&cn, 2, 1, anyin)) { /* 20 */
167                    return;
168            }
169            if (cn != 1 && cn != 2) nowav = TRUE;
170            /* Read samplefrequency */
171            if (!fread(&sf, 4, 1, anyin)) {  /* 24 */
172                    return;
173            }
174            /* Read bytes per second: Should be samplefreq * channels * 2 */
175            if (!fread(&tempuint, 4, 1, anyin)) {         /* 28 */
176                    return;
177            }
178            if (tempuint != sf * cn * 2) nowav = TRUE;
179            /* read bytes per frame: Should be channels * 2 */
180            if (!fread(&tempushort, 2, 1, anyin)) {       /* 32 */
181                    return;
182            }
183            if (tempushort != cn * 2) nowav = TRUE;
184            /* Read bits per sample: Should be 16 */
185            if (!fread(&tempushort, 2, 1, anyin)) {       /* 34 */
186                    return;
187            }
188            if (tempushort != 16) nowav = TRUE;
189            if (!fread(str, 4, 1, anyin)) {            /* 36 */
190                    return;
191            }
192            str[4] = '\0';
193            if (strcmp(str, "data") != 0) nowav = TRUE;
194            if (!fread(&tempuint, 4, 1, anyin)) {   /* 40 */
195                    return;
196            }
197            if (nowav)
198            {
199                    fseek(anyin, 0, SEEK_SET);   /* Back to beginning of file */
200                    chat("File has no WAV header.\n");
201            }
202            else
203            {
204                    samplefrequency = sf;
205                    channels = cn;
206                    chat("Read WAV header: %d channels, samplefrequency %d.\n",
207                          channels, samplefrequency);
208                    iswav = TRUE;
209            }
210    }
211    return;
212 }
213
214
215
216 /* -----------------------------------------------------------------------
217    Write a .WAV header to 'out'. See header for details.
218    -----------------------------------------------------------------------*/
219 void makewavheader( void)
220 {
221    unsigned int tempuint, filelength;
222    unsigned short tempushort;
223
224    /* If fseek fails, don't create the header. */
225    if (fseek(out, 0, SEEK_END) != -1)
226    {
227            filelength = ftell(out);
228            chat("filelength %d, ", filelength);
229            fseek(out, 0, SEEK_SET);
230            if (!fwrite("RIFF", 1, 4, out)) { /* 0 */
231                    return;
232            }
233            tempuint = filelength - 8;
234            if (!fwrite(&tempuint, 4, 1, out)) {    /* 4 */
235                    return;
236            }
237            if (!fwrite("WAVEfmt ", 1, 8, out)) {   /* 8 */
238                    return;
239            }
240            /* length of fmt data 16 bytes */
241            tempuint = 16;
242            if (!fwrite(&tempuint, 4, 1, out)) {   /* 16 */
243                    return;
244            }
245            /* Format tag: 1 for pcm */
246            tempushort = 1;
247            if (!fwrite(&tempushort, 2, 1, out)) { /* 20 */
248                    return;
249            }
250            chat("%d channels\n", channels);
251            if (!fwrite(&channels, 2, 1, out)) {
252                    return;
253            }
254            chat("samplefrequency %d\n", samplefrequency);
255            if (!fwrite(&samplefrequency, 4, 1, out)) {   /* 24 */
256                    return;
257            }
258            /* Bytes per second */
259            tempuint = channels * samplefrequency * 2;
260            if (!fwrite(&tempuint, 4, 1, out)) {         /* 28 */
261                    return;
262            }
263            /* Block align */
264            tempushort = 2 * channels;
265            if (!fwrite(&tempushort, 2, 1, out)) {       /* 32 */
266                    return;
267            }
268            /* Bits per sample */
269            tempushort = 16;
270            if (!fwrite(&tempushort, 2, 1, out)) {       /* 34 */
271                    return;
272            }
273            if (!fwrite("data", 4, 1, out)) {            /* 36 */
274                    return;
275            }
276            tempuint = filelength - 44;
277            if (!fwrite(&tempuint, 4, 1, out)) {   /* 40 */
278                    return;
279            }
280    }
281    return;
282 }
283
284 /* -----------------------------------------------------------------------
285    After all is read and done, inform the inclined user of the elapsed time
286    -----------------------------------------------------------------------*/
287 static void statistics( void)
288 {
289    int temp;
290
291    temp = time(NULL) - stopwatch;
292    if (temp != 1)
293    {
294       inform ("\nTime: %d seconds\n", temp);
295    }
296    else
297    {
298       inform ("\nTime: 1 second\n");
299    }
300    return;
301 }
302
303
304 /* -----------------------------------------------------------------------
305    Start the stopwatch and make sure the user is informed at end of program.
306    -----------------------------------------------------------------------*/
307 void startstopwatch(void)
308 {
309    stopwatch = time(NULL);       /* Remember time 'now' */
310    atexit(statistics);           /* Call function statistics() at exit. */
311
312    return;
313 }
314
315 /* --------------------------------------------------------------------
316    Tests the character 'coal' for being a command line option character,
317    momentarrily '-'.
318    -------------------------------------------------------------------- */
319 int isoptionchar (char coal)
320 {
321    return (coal =='-');
322 }
323
324 /* -----------------------------------------------------------------------
325    Reads through the arguments on the lookout for an option starting
326    with 'string'. The rest of the option is read as a time and passed
327    to *result, where the result is meant to mean 'number of samples' in
328    that time.
329    On failure, *result is unchanged.
330    return value is TRUE on success, FALSE otherwise.
331    -----------------------------------------------------------------------*/
332 int parsetimearg( int argcount, char *args[], char *string, int *result)
333 {
334     int i;
335
336     if ((i = findoption( argcount, args, string)) > 0)
337     {
338         if (parsetime(args[i] + 1 + strlen( string), result))
339             return TRUE;
340         argerrornum(args[i]+1, ME_NOTIME);
341     }
342     return FALSE;
343 }
344
345 /* -----------------------------------------------------------------------
346    The string argument is read as a time and passed
347    to *result, where the result is meant to mean 'number of samples' in
348    that time.
349    On failure, *result is unchanged.
350    return value is TRUE on success, FALSE otherwise.
351    -----------------------------------------------------------------------*/
352 int parsetime(char *string, int *result)
353 {
354     int k;
355     double temp;
356     char m, s, end;
357
358     k = sscanf(string, "%30lf%1c%1c%1c", &temp, &m, &s, &end);
359     switch (k)
360       {
361       case 0: case EOF: case 4:
362         return FALSE;
363       case 1:
364         *result = temp;
365         break;
366       case 2:
367         if (m == 's')
368           *result = temp * samplefrequency;
369         else
370           return FALSE;
371         break;
372       case 3:
373         if (m == 'm' && s == 's')
374           *result = temp * samplefrequency / 1000;
375         else if (m == 'H' && s == 'z')
376           *result = samplefrequency / temp;
377         else
378           return FALSE;
379         break;
380       default:
381         argerrornum(NULL, ME_THISCANTHAPPEN);
382       }
383     return TRUE;
384 }
385
386 /* -----------------------------------------------------------------------
387    The string argument is read as a frequency and passed
388    to *result, where the result is meant to mean 'number of samples' in
389    one cycle of that frequency.
390    On failure, *result is unchanged.
391    return value is TRUE on success, FALSE otherwise.
392    -----------------------------------------------------------------------*/
393 int parsefreq(char *string, double *result)
394 {
395     int k;
396     double temp;
397     char m, s, end;
398
399     k = sscanf(string, "%30lf%1c%1c%1c", &temp, &m, &s, &end);
400     switch (k)
401       {
402       case 0: case EOF: case 2: case 4:
403         return FALSE;
404       case 1:
405         *result = temp;
406         break;
407       case 3:
408         if (m == 'H' && s == 'z')
409           *result = samplefrequency / temp;
410         else
411           return FALSE;
412         break;
413       default:
414         argerrornum(NULL, ME_THISCANTHAPPEN);
415       }
416     return TRUE;
417 }
418
419 char *parsefilearg( int argcount, char *args[])
420 {
421   int i;
422   char *result = NULL;
423
424    for (i = 1; i < argcount; i++)
425    {
426       if (args[i][0] != '\0' &&
427           (!isoptionchar (args[i][0]) || args[i][1] == '\0' ))
428       {
429         /*---------------------------------------------*
430          * The argument is a filename:                 *
431          * it is either no dash followed by something, *
432          * or it is a dash following by nothing.       *
433          *---------------------------------------------*/
434         result = malloc( strlen( args[i]) + 1);
435         if (result == NULL)
436             fatalperror( "Couldn't allocate memory for filename\n");
437         strcpy( result, args[i]);
438         args[i][0] = '\0';                    /* Mark as used up */
439         break;
440       }
441    }
442    return result;
443 }
444
445 int parseswitch( char *found, char *wanted)
446 {
447   if (strncmp( found, wanted, strlen( wanted)) == 0)
448     {
449       if (found[strlen( wanted)] == '\0')
450         return TRUE;
451       else
452         argerrornum( found, ME_NOSWITCH);
453     }
454   return FALSE;
455 }
456
457 int parseswitcharg( int argcount, char *args[], char *string)
458 {
459   int i;
460
461   if ((i = findoption( argcount, args, string)) > 0)
462     {
463       if (args[i][strlen( string) + 1] == '\0')
464         return TRUE;
465       else
466         argerrornum( args[i] + 1, ME_NOSWITCH);
467     }
468   return FALSE;
469 }
470
471 int parseintarg( int argcount, char *args[], char *string, int *result)
472 {
473   int i, temp;
474   char c;
475
476   if ((i = findoption( argcount, args, string)) > 0)
477    {
478       switch (sscanf(args[i] + 1 + strlen( string),
479                      "%30d%1c", &temp, &c))
480       {
481         case 0: case EOF: case 2:
482             argerrornum(args[i]+1, ME_NOINT);
483             return FALSE;
484          case 1:
485            *result = temp;
486             break;
487          default:
488             say("frame.c: This can't happen\n");
489       }
490       return TRUE;
491    }
492   else
493     {
494       return FALSE;
495     }
496 }
497
498 /* --------------------------------------------------------------------
499    Reads through the arguments on the lookout for an option starting
500    with 'string'. The rest of the option is read as a double and
501    passed to *result.
502    On failure, *result is unchanged.
503    return value is TRUE on success, FALSE otherwise.
504    -------------------------------------------------------------------- */
505 int parsedoublearg( int argcount, char *args[], char *string, double *result)
506 {
507   int i;
508   double temp;
509   char end;
510
511   if ((i = findoption( argcount, args, string)) > 0)
512     {
513       switch (sscanf(args[i] + 1 + strlen( string), "%30lf%1c", &temp, &end))
514         {
515         case 0: case EOF: case 2:
516           argerrornum(args[i]+1, ME_NODOUBLE);
517           return FALSE;
518         case 1:
519           *result = temp;
520           break;
521         default:
522           say("frame.c: This can't happen\n");
523         }
524       return TRUE;
525     }
526   else
527     {
528       return FALSE;
529     }
530 }
531
532 /* --------------------------------------------------------------------
533    Reads through the arguments on the lookout for an option starting
534    with 'string'. The rest of the option is read as a volume, i.e.
535    absolute, percent or db. The result is passed to *result.
536    On failure, *result is unchanged.
537    return value is TRUE on success, FALSE otherwise.
538    -------------------------------------------------------------------- */
539 int parsevolarg( int argcount, char *args[], char *string, double *result)
540 {
541   double vol = 1.0;
542   char sbd, sbb, end;
543   int i, weird = FALSE;
544
545   if ((i = findoption( argcount, args, string)) > 0)
546     {
547       switch (sscanf(args[i] + 1 + strlen( string),
548                      "%30lf%1c%1c%1c", &vol, &sbd, &sbb, &end))
549         {
550           case 0: case EOF: case 4:
551           weird = TRUE;
552           break;    /* No number: error */
553         case 1:
554           *result = vol;
555           break;
556         case 2:
557           if (sbd == '%')
558             *result = vol / 100;
559           else
560             weird = TRUE;    /* One char but no percent: error */
561           break;
562         case 3:
563           if (sbd =='d' && sbb == 'b')
564             *result = pow(2, vol / 6.02);
565           else
566             weird = TRUE;    /* Two chars but not db: error */
567           break;
568         default:
569           say("frame.c: This can't happen.\n");
570         }
571       if (weird)
572         argerrornum( args[i] + 1, ME_NOVOL);
573           /* ("Weird option: couldn't parse volume '%s'\n", args[i]+2); */
574       return !weird;
575     }
576   else
577     {
578       return FALSE;
579     }
580 }
581
582
583 /* --------------------------------------------------------------------
584    Reads the specified string 's' and interprets it as a volume. The string
585    would be of the form 1.8 or 180% or 5db.
586    On success, the return value TRUE and *result is given result
587    (i.e. the relative volume, i.e. 1.8). On failure, FALSE is returned and
588    result is given value 1.0.
589    -------------------------------------------------------------------- */
590 int parsevolume(char *s, double *result)
591 {
592     int k;
593     char sbd, sbb, end;
594
595     *result = 1.0;
596     k = sscanf(s, "%30lf%1c%1c%1c", result, &sbd, &sbb, &end);
597     switch (k)
598     {
599       case 0:
600       case EOF:
601       case 4:
602        return FALSE;
603       case 1:
604        break;
605       case 2:
606        if (sbd != '%')
607            return FALSE;
608        (*result) /=100;
609        break;
610       case 3:
611        if (sbd !='d' || sbb != 'b')
612            return FALSE;
613        (*result) = pow(2, (*result) / 6.02);
614        break;
615       default:
616        say("parsevolume: This can't happen (%d).\n", k);
617     }
618     return TRUE;
619 }
620
621 /* --------------------------------------------------------------------
622    Reports an error due to parsing the string 's' encountered on the
623    command line.
624    -------------------------------------------------------------------- */
625 void argerror(char *s)
626 {
627   error ("Error parsing command line. Unrecognized option:\n\t-%s\n", s);
628   fatalerror("\nTry --help for help.\n");
629 }
630
631 /* --------------------------------------------------------------------
632    Reports an error due to parsing the string 's' encountered on the
633    command line. 'code' indicates the type of error.
634    -------------------------------------------------------------------- */
635 void argerrornum(char *s, Errornum code)
636 {
637   char *message;
638
639   if (code == ME_TOOMANYFILES)
640     {
641       error("Too many files on command line: '%s'.\n", s);
642     }
643   else
644     {
645       if (s != NULL)
646         error ("Error parsing option -%s:\n\t", s);
647       switch( code)
648         {
649         case ME_NOINT:
650           message = "Integer expected";
651           break;
652         case ME_NODOUBLE:
653           message = "Floating point number expected";
654           break;
655         case ME_NOTIME:
656           message = "Time argument expected";
657           break;
658         case ME_NOVOL:
659           message = "Volume argument expected";
660           break;
661         case ME_NOSWITCH:
662           message = "Garbage after switch-type option";
663           break;
664         case ME_HEADERONTEXTFILE:
665           message = "Option -h is not useful for text-output";
666           break;
667         case ME_NOINFILE:
668           message = "No input file specified";
669           break;
670         case ME_NOOUTFILE:
671           message = "No output file specified";
672           break;
673         case ME_NOIOFILE:
674           message = "No input/output file specified";
675           break;
676         case ME_NOSTDIN:
677           message = "Standard in not supported here";
678           break;
679         case ME_NOSTDOUT:
680           message = "Standard out not supported here";
681           break;
682         case ME_NOSTDIO:
683           message = "Standard in/out not supported here";
684           break;
685         case ME_NOTENOUGHFILES:
686           message = "Not enough files specified";
687           break;
688         case ME_THISCANTHAPPEN:
689           fatalerror("\nThis can't happen. Report this as a bug\n");
690           /* fatalerror does not return */
691         default:
692           error("Error code %d not implemented. Fix me!\n", code);
693           message = "Error message not implemented. Fix me!";
694         }
695       error("%s\n", message);
696     }
697   fatalerror("\nTry --help for help.\n");
698 }
699
700 /* --------------------------------------------------------------------
701    Reports an error due to parsing the string 's' encountered on the
702    command line. 'message' explains the type of error.
703    -------------------------------------------------------------------- */
704 void argerrortxt(char *s, char *message)
705 {
706   if (s != NULL)
707     error ("Error parsing option -%s:\n\t", s);
708   else
709     error ("Error parsing command line:\n\t");
710   error ("%s\n", message);
711   fatalerror("\nTry --help for help.\n");
712 }
713
714 /* --------------------------------------------------------------------
715    Check for any remaining arguments and complain about their existence
716    -------------------------------------------------------------------- */
717 void checknoargs( int argcount, char *args[])
718 {
719   int i, errorcount = 0;
720
721   for (i = 1; i < argcount; i++)
722     {
723       if (args[i][0] != '\0')   /* An unused argument! */
724         {
725           errorcount++;
726           if (errorcount == 1)
727             error("The following arguments were not recognized:\n");
728           error("\t%s\n", args[i]);
729         }
730     }
731   if (errorcount > 0)           /* Errors are fatal */
732     fatalerror("\nTry --help for help.\n");
733
734   return;                       /* No errors? Return. */
735 }
736
737 /* --------------------------------------------------------------------
738    Parses the command line arguments as represented by the function
739    arguments. Sets the global variables 'in', 'out', 'samplefrequency'
740    and 'samplewidth' accordingly. Also verboselevel.
741    The files 'in' and 'out' are even opened according to 'fileswitch'.
742    See headerfile for details
743    -------------------------------------------------------------------- */
744 void parseargs( int argcount, char *args[], int fileswitch)
745 {
746    char *filename;
747    int tempint = 0;
748
749    if ((fileswitch & 1) != 0)     /* If getting infile  */
750      in = NULL;
751    if ((fileswitch & 4) != 0)     /* If getting outfile */
752      out = NULL;
753    wavout = FALSE;
754    verboselevel = 5;
755    samplefrequency = DEFAULTFREQ;
756    samplewidth = 2;
757    channels = 1;
758
759    /*-----------------------------------------------*
760     * First first check testcase, usage and version *
761     *-----------------------------------------------*/
762    test_usage = parseswitcharg( argcount, args, "-test-usage");
763    if (parseswitcharg( argcount, args, "-help"))
764        {
765          printf("%s%s", usage, standardusage);
766          exit(0);
767        }
768    if (parseswitcharg( argcount, args, "-version"))
769        {
770          printf("%s\n(%s)\n", version, standardversion);
771          exit(0);
772        }
773    /*--------------------------------------*
774     * Set verboselevel                     *
775     *--------------------------------------*/
776    while (parseswitcharg( argcount, args, "V"))
777                verboselevel = 10;
778    while (parseswitcharg( argcount, args, "Q"))
779                verboselevel = 1;
780    /*-------------------------------------------------*
781     * Get filenames and open files *
782     *-------------------------------------------------*/
783    if ((fileswitch & 1) != 0)        /* Infile wanted */
784      {
785        infilename = parsefilearg( argcount, args);
786        if (infilename == NULL)
787          argerrornum( NULL, ME_NOINFILE);
788        if (strcmp( infilename, "-") == 0)
789          {
790            infilename = "<stdin>";
791            in = stdin;
792            if ((fileswitch & 2) != 0)   /* Binfile wanted */
793              readwavheader( in);
794          }
795        else
796          {
797            if ((fileswitch & 2) == 0)   /* Textfile wanted */
798              in = fopen(infilename, "rt");
799            else                         /* Binfile wanted */
800              if ((in = fopen(infilename, "rb")) != NULL)
801                readwavheader( in);
802          }
803        if (in == NULL)
804          fatalerror("Error opening input file '%s': %s\n", infilename,strerror(errno));
805        else
806          inform("Using file '%s' as input\n", infilename);
807      }
808    if ((fileswitch & 4) != 0)        /* Outfile wanted */
809      {
810        outfilename = parsefilearg( argcount, args);
811        if (outfilename == NULL)
812          argerrornum( NULL, ME_NOOUTFILE);
813        if (strcmp( outfilename, "-") == 0)
814          {
815            outfilename = "<stdout>";
816            out = stdout;
817          }
818        else
819          {
820
821            if ((fileswitch & 8) == 0)   /* Textfile wanted */
822              out = fopen(outfilename, "wt");
823            else                         /* Binfile wanted */
824              out = fopen(outfilename, "wb");
825          }
826        if (out == NULL)
827          fatalerror("Error opening output file '%s': %s\n", outfilename,strerror(errno));
828        else
829          inform("Using file '%s' as output\n", outfilename);
830      }
831    if ((fileswitch & 32) != 0)      /* In-/Outfile wanted */
832      {
833        assert (in == NULL && out == NULL);
834        infilename = outfilename = parsefilearg( argcount, args);
835        if (outfilename == NULL)
836          argerrornum( NULL, ME_NOIOFILE);
837        if (strcmp( infilename, "-") == 0)
838          argerrornum( infilename, ME_NOSTDIN);
839        inform("Using file '%s' as input/output\n", outfilename);
840        in = out = fopen(outfilename, "r+");
841        if (out == NULL)
842          fatalerror("Error opening input/output file '%s': %s\n", outfilename,strerror(errno));
843
844        readwavheader( in);
845      }
846    if ((fileswitch & 16) == 0)  /* No additional files wanted */
847      {
848        if ((filename = parsefilearg( argcount, args)) != NULL)
849          argerrornum( filename, ME_TOOMANYFILES);
850      }
851
852    /*-------------------------------------------------*
853     * Set samplefrequency, width, wavout, 
854     *-------------------------------------------------*/
855    parseintarg( argcount, args, "f", &samplefrequency);
856    wavout = parseswitcharg( argcount, args, "h");
857    if (parseintarg( argcount, args, "w", &tempint))
858      {
859        if (tempint != 16)
860          argerrortxt(NULL, "Option -w is only valid "
861                      "with value 16. Sorry.");
862        else
863          samplewidth = tempint;
864      }
865    if (parseintarg( argcount, args, "c", &tempint))
866      {
867        if (tempint != 1 && tempint != 2)
868          argerrortxt(NULL, "Option -c is only valid "
869                      "with values 1 or 2. Sorry.");
870        else
871          channels = tempint;
872      }
873    /*-------------------------------------------------*
874     * Create WAV-header on output if wanted.          *
875     *-------------------------------------------------*/
876    if (wavout)
877      switch (fileswitch & (12))
878        {
879        case 4:   /* User wants header on textfile */
880          argerrornum( NULL, ME_HEADERONTEXTFILE);
881        case 12:  /* User wants header on binfile  */
882          makewavheader();
883          break;
884        case 0:   /* User wants header, but there is no outfile */
885          /* Problem: what about i/o-file, 32? You might want a header
886             on that? Better ignore this case. */
887          break;
888        case 8:    /* An application musn't ask for this */
889        default:   /* This can't happen */
890          assert( FALSE);
891        }
892    return;
893 }
894
895 /* --------------------------------------------------------------------
896    Returns the index 'i' of the first argument that IS an option, and
897    which begins with the label 's'. If there is none, -1.
898    We also mark that option as done with, i.e. we cross it out.
899    -------------------------------------------------------------------- */
900 int findoption( int argcount, char *args[], char *s)
901 {
902    int i;
903
904    if (test_usage)
905      printf("Checking for option -%s\n", s);
906
907    for (i=1; i<argcount; i++)
908    {
909      if (isoptionchar (args[i][0]) &&
910          strncmp( args[i] + 1, s, strlen( s)) == 0)
911        {
912          args[i][0] = '\0';
913          return i;
914        }
915    }
916    return -1;
917 }
918
919 /* --------------------------------------------------------------------
920    Finishes off the .WAV header (if any) and exits correctly and formerly.
921    -------------------------------------------------------------------- */
922 int myexit (int value)
923 {
924   switch (value)
925     {
926     case 0:
927       if (wavout)
928         makewavheader();  /* Writes a fully informed .WAV header */
929       chat("Success!\n");
930       break;
931     default:
932       chat("Failure.\n");
933       break;
934     }
935   exit (value);
936 }
937
938 /* --------------------------------------------------------------------
939    Reads the stated input file bufferwise, calls the function 'work'
940    with the proper values, and writes the result to the stated output file.
941    Return value: TRUE on success, FALSE otherwise.
942    -------------------------------------------------------------------- */
943 int workloop( FILE *theinfile, FILE *theoutfile,
944               int (*work)( short *buffer, int length) )
945 {
946   short *buffer;
947   int length, nowlength;
948
949   length = BUFFSIZE;
950   if ((buffer = malloc( sizeof(short) * length)) == NULL)
951     fatalperror ("");
952   while (TRUE)
953     {
954       nowlength = fread(buffer, sizeof(short), length, theinfile);
955       if (ferror( theinfile) != 0)
956         fatalperror("Error reading input file");
957       if (nowlength == 0)   /* Reached end of input file */
958         break;
959       /* Call the routine that does the work */
960       if (!work (buffer, nowlength))         /* On error, stop. */
961         return FALSE;
962       if (!fwrite(buffer, sizeof(short), nowlength, theoutfile)) {
963               return FALSE;
964       }
965       if (ferror( theoutfile) != 0)
966         fatalperror("Error writing to output file");
967     }
968   return TRUE;      /* Input file done with, no errors. */
969 }
970
971 int __attribute__((format(printf,1,2))) chat( const char *format, ...)
972 {
973     va_list ap;
974     int result = 0;
975
976     if (verboselevel > 5)
977     {
978         va_start( ap, format);
979         result = vfprintf( stderr, format, ap);
980         va_end( ap);
981     }
982     return result;
983 }
984
985 int __attribute__((format(printf,1,2))) inform( const char *format, ...)
986 {
987     va_list ap;
988     int result = 0;
989
990     if (verboselevel > 1)
991     {
992         va_start( ap, format);
993         result = vfprintf( stderr, format, ap);
994         va_end( ap);
995     }
996     return result;
997 }
998
999 int __attribute__((format(printf,1,2))) error( const char *format, ...)
1000 {
1001     va_list ap;
1002     int result;
1003
1004     va_start( ap, format);
1005     result = vfprintf( stderr, format, ap);
1006     va_end( ap);
1007     return result;
1008 }
1009
1010 void __attribute__((format(printf,1,2))) fatalerror( const char *format, ...)
1011 {
1012     va_list ap;
1013
1014     va_start( ap, format);
1015     vfprintf( stderr, format, ap);
1016     va_end( ap);
1017     myexit(1);
1018 }
1019
1020 void fatalperror( const char *string)
1021 {
1022   perror( string);
1023   myexit( 1);
1024 }
1025
1026 int __attribute__((format(printf,1,2))) say( const char *format, ...)
1027 {
1028     va_list ap;
1029     int result;
1030
1031     va_start( ap, format);
1032     result = vfprintf( stdout, format, ap);
1033     va_end( ap);
1034     return result;
1035 }
1036
1037
1038 char *malloccopy( char *string)
1039 {
1040     char *result;
1041
1042     result = malloc( strlen( string) + 1);
1043     if (result != NULL)
1044         strcpy( result, string);
1045     return result;
1046 }
1047
1048
1049 char *mallocconcat( char *one, char *two)
1050 {
1051     char *result;
1052
1053     result = malloc( strlen( one) + strlen( two) + 1);
1054     if (result != NULL)
1055       {
1056         strcpy( result, one);
1057         strcat( result, two);
1058       }
1059     return result;
1060 }
1061
1062 double double2db( double value)
1063 {
1064   if (value < 0)
1065     value = -value;
1066   return 6.0 * log( value / 32767) / log( 2);
1067 }
1068
1069 void readawaysamples( FILE *input, size_t size)
1070 {
1071   short *buffer;
1072   int samplesread, count;
1073
1074   buffer = malloc( sizeof( *buffer) * BUFFSIZE);
1075   if (buffer == NULL) fatalperror("Couldn't allocate buffer");
1076
1077   while (size > 0)
1078     {
1079       if (size > BUFFSIZE)
1080         count = BUFFSIZE;
1081       else
1082         count = size;
1083
1084       samplesread = fread( buffer, sizeof(*buffer), count, input);
1085       if (ferror( input) != 0)
1086         fatalperror("Error reading input file");
1087       size -= samplesread;
1088     }
1089   free( buffer);
1090 }
1091