home *** CD-ROM | disk | FTP | other *** search
/ APDL Public Domain 1 / APDL_PD1A.iso / sound / sox / source / c / sox < prev    next >
Encoding:
Text File  |  1994-06-04  |  17.4 KB  |  769 lines

  1. /*
  2.  * July 5, 1991
  3.  * Copyright 1991 Lance Norskog And Sundry Contributors
  4.  * This source code is freely redistributable and may be used for
  5.  * any purpose.  This copyright notice must be maintained.
  6.  * Lance Norskog And Sundry Contributors are not responsible for
  7.  * the consequences of using this software.
  8.  */
  9.  
  10. #include "st.h"
  11. #if    defined(unix) || defined(AMIGA) || defined(__OS2__) || defined(ARM)
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #endif
  15. #if defined(__STDC__) || defined(ARM)
  16. #include <stdarg.h>
  17. #else
  18. #include <varargs.h>
  19. #endif
  20. #include <ctype.h>
  21. #include <string.h>
  22. #ifdef VMS
  23. #include <errno.h>
  24. #include <perror.h>
  25. #define LASTCHAR        ']'
  26. #else
  27. #include <errno.h>
  28. #define LASTCHAR        '/'
  29. #endif
  30. /* YOU MAY WANT THIS
  31. #include <getopt.h>
  32. */
  33.  
  34. /*
  35.  * SOX main program.
  36.  *
  37.  * Rewrite for new nicer option syntax.  July 13, 1991.
  38.  * Rewrite for separate effects library.  Sep. 15, 1991.
  39.  */
  40.  
  41. #ifdef AMIGA
  42. /* This is the Amiga version string */
  43. char amiversion[AmiVerSize]=AmiVerChars;
  44. #endif /* AMIGA */
  45.  
  46.  
  47. EXPORT float volume = 1.0;    /* expansion coefficient */
  48. int dovolume = 0;
  49. int clipped = 0;    /* Volume change clipping errors */
  50.  
  51. EXPORT float amplitude = 1.0;    /* Largest sample so far */
  52.  
  53. EXPORT int writing = 0;    /* are we writing to a file? */
  54.  
  55. /* export flags */
  56. EXPORT int verbose = 0;    /* be noisy on stderr */
  57. EXPORT int summary = 0;    /* just print summary of information */
  58.  
  59. long ibuf[BUFSIZ];    /* Intermediate processing buffer */
  60. long obuf[BUFSIZ];    /* Intermediate processing buffer */
  61.  
  62.  
  63. long volumechange();
  64.  
  65. #ifdef    DOS
  66. char writebuf[BUFSIZ];    /* output write buffer */
  67. #endif
  68.  
  69. void    gettype(), geteffect(), checkeffect();
  70.  
  71. EXPORT struct soundstream informat, outformat;
  72.  
  73. char *myname;
  74.  
  75. ft_t ft;
  76. struct effect eff;
  77. char *ifile, *ofile, *itype, *otype;
  78. IMPORT char *optarg;
  79. IMPORT int optind;
  80.  
  81. main(n, args)
  82. int n;
  83. char **args;
  84. {
  85.     myname = args[0];
  86.     init();
  87.  
  88.     ifile = ofile = NULL;
  89.  
  90.     /* Get input format options */
  91.     ft = &informat;
  92.     doopts(n, args);
  93.     /* Get input file */
  94.     if (optind >= n)
  95. #ifndef    VMS
  96.         usage("No input file?");
  97. #else
  98.         /* I think this is the VMS patch, but am not certain */
  99.         fail("Input file required");
  100. #endif
  101.     ifile = args[optind];
  102.     if (! strcmp(ifile, "-"))
  103.         ft->fp = stdin;
  104.     else if ((ft->fp = fopen(ifile, READBINARY)) == NULL)
  105.         fail("Can't open input file '%s': %s",
  106.             ifile, strerror(errno));
  107.     ft->filename = ifile;
  108.     optind++;
  109.  
  110.     /* Let -e allow no output file, just do an effect */
  111.     if (optind < n) {
  112.         if (strcmp(args[optind], "-e")) {
  113.         /* Get output format options */
  114.         ft = &outformat;
  115.         doopts(n, args);
  116.         /* Get output file */
  117.         if (optind >= n)
  118.             usage("No output file?");
  119.         ofile = args[optind];
  120.         ft->filename = ofile;
  121.         /*
  122.          * There are two choices here:
  123.          *    1) stomp the old file - normal shell "> file" behavior
  124.          *    2) fail if the old file already exists - csh mode
  125.          */
  126.         if (! strcmp(ofile, "-"))
  127.             ft->fp = stdout;
  128.         else {
  129. #ifdef    unix
  130.              /*
  131.              * Remove old file if it's a text file, but
  132.               * preserve Unix /dev/sound files.  I'm not sure
  133.              * this needs to be here, but it's not hurting
  134.              * anything.
  135.              */
  136.             if ((ft->fp = fopen(ofile, WRITEBINARY)) &&
  137.                    (filetype(fileno(ft->fp)) == S_IFREG)) {
  138.                 fclose(ft->fp);
  139.                 unlink(ofile);
  140.                 creat(ofile, 0666);
  141.                 ft->fp = fopen(ofile, WRITEBINARY);
  142.             }
  143. #else
  144.             ft->fp = fopen(ofile, WRITEBINARY);
  145. #endif
  146.             if (ft->fp == NULL)
  147.                 fail("Can't open output file '%s': %s",
  148.                     ofile, strerror(errno));
  149. #ifdef    DOS
  150.             if (setvbuf (ft->fp,writebuf,_IOFBF,sizeof(writebuf)))
  151.                 fail("Can't set write buffer");
  152. #endif
  153.         }
  154.         writing = 1;
  155.         }
  156.         optind++;
  157.     }
  158.  
  159.     /* ??? */
  160. /*
  161.     if ((optind < n) && !writing && !eff.name)
  162.         fail("Can't do an effect without an output file!");
  163. */
  164.  
  165.     /* Get effect name */
  166.     if (optind < n) {
  167.         eff.name = args[optind];
  168.         optind++;
  169.         geteffect(&eff);
  170.         (* eff.h->getopts)(&eff, n - optind, &args[optind]);
  171.     }
  172.  
  173.     /*
  174.      * If we haven't specifically set an output file
  175.      * don't write a file; we could be doing a summary
  176.      * or a format check.
  177.      */
  178. /*
  179.     if (! ofile)
  180.         usage("Must be given an output file name");
  181. */
  182.     if (! ofile)
  183.         writing = 0;
  184.     /* Check global arguments */
  185.     if (volume <= 0.0)
  186.         fail("Volume must be greater than 0.0");
  187. #if    defined(unix) || defined(AMIGA) || defined(ARM)
  188.     informat.seekable  = (filetype(fileno(informat.fp)) == S_IFREG);
  189.     outformat.seekable = (filetype(fileno(outformat.fp)) == S_IFREG);
  190. #else
  191. #if    defined(DOS) || defined(__OS2__)
  192.     informat.seekable  = 1;
  193.     outformat.seekable = 1;
  194. #else
  195.     informat.seekable  = 0;
  196.     outformat.seekable = 0;
  197. #endif
  198. #endif
  199.  
  200.     /* If file types have not been set with -t, set from file names. */
  201.     if (! informat.filetype) {
  202.         if (informat.filetype = strrchr(ifile, LASTCHAR))
  203.             informat.filetype++;
  204.         else
  205.             informat.filetype = ifile;
  206.         if (informat.filetype = strrchr(informat.filetype, '.'))
  207.             informat.filetype++;
  208.         else /* Default to "auto" */
  209.             informat.filetype = "auto";
  210.     }
  211.     if (writing && ! outformat.filetype) {
  212.         if (outformat.filetype = strrchr(ofile, LASTCHAR))
  213.             outformat.filetype++;
  214.         else
  215.             outformat.filetype = ofile;
  216.         if (outformat.filetype = strrchr(outformat.filetype, '.'))
  217.             outformat.filetype++;
  218.     }
  219.     /* Default the input comment to the filename.
  220.      * The output comment will be assigned when the informat
  221.      * structure is copied to the outformat.
  222.      */
  223.     informat.comment = informat.filename;
  224.  
  225.     process();
  226.     statistics();
  227.     exit(0);
  228. }
  229.  
  230. doopts(n, args)
  231. int n;
  232. char **args;
  233. {
  234.     int c;
  235.     char *str;
  236.  
  237.     while ((c = getopt(n, args, "r:v:t:c:suUAbwlfdDxSV")) != -1) {
  238.         switch(c) {
  239.         case 't':
  240.             if (! ft) usage("-t");
  241.             ft->filetype = optarg;
  242.             if (ft->filetype[0] == '.')
  243.                 ft->filetype++;
  244.             break;
  245.  
  246.         case 'r':
  247.             if (! ft) usage("-r");
  248.             str = optarg;
  249.             if ((! sscanf(str, "%lu", &ft->info.rate)) ||
  250.                     (ft->info.rate <= 0))
  251.                 fail("-r must be given a positive integer");
  252.             break;
  253.         case 'v':
  254.             if (! ft) usage("-v");
  255.             str = optarg;
  256.             if ((! sscanf(str, "%e", &volume)) ||
  257.                     (volume <= 0))
  258.                 fail("Volume value '%s' is not a number",
  259.                     optarg);
  260.             dovolume = 1;
  261.             break;
  262.  
  263.         case 'c':
  264.             if (! ft) usage("-c");
  265.             str = optarg;
  266.             if (! sscanf(str, "%d", &ft->info.channels))
  267.                 fail("-c must be given a number");
  268.             break;
  269.         case 'b':
  270.             if (! ft) usage("-b");
  271.             ft->info.size = BYTE;
  272.             break;
  273.         case 'w':
  274.             if (! ft) usage("-w");
  275.             ft->info.size = WORD;
  276.             break;
  277.         case 'l':
  278.             if (! ft) usage("-l");
  279.             ft->info.size = LONG;
  280.             break;
  281.         case 'f':
  282.             if (! ft) usage("-f");
  283.             ft->info.size = FLOAT;
  284.             break;
  285.         case 'd':
  286.             if (! ft) usage("-d");
  287.             ft->info.size = DOUBLE;
  288.             break;
  289.         case 'D':
  290.             if (! ft) usage("-D");
  291.             ft->info.size = IEEE;
  292.             break;
  293.  
  294.         case 's':
  295.             if (! ft) usage("-s");
  296.             ft->info.style = SIGN2;
  297.             break;
  298.         case 'u':
  299.             if (! ft) usage("-u");
  300.             ft->info.style = UNSIGNED;
  301.             break;
  302.         case 'U':
  303.             if (! ft) usage("-U");
  304.             ft->info.style = ULAW;
  305.             break;
  306.         case 'A':
  307.             if (! ft) usage("-A");
  308.             ft->info.style = ALAW;
  309.             break;
  310.  
  311.         case 'x':
  312.             if (! ft) usage("-x");
  313.             ft->swap = 1;
  314.             break;
  315.  
  316. /*  stat effect does this ?
  317.         case 'S':
  318.             summary = 1;
  319.             break;
  320. */
  321.         case 'V':
  322.             verbose = 1;
  323.             break;
  324.         }
  325.     }
  326. }
  327.  
  328. init() {
  329.  
  330.     /* init files */
  331.     informat.info.rate      = outformat.info.rate  = 0;
  332.     informat.info.size      = outformat.info.size  = -1;
  333.     informat.info.style     = outformat.info.style = -1;
  334.     informat.info.channels  = outformat.info.channels = -1;
  335.     informat.comment   = outformat.comment = NULL;
  336.     informat.swap      = 0;
  337.     informat.filetype  = outformat.filetype  = (char *) 0;
  338.     informat.fp        = stdin;
  339.     outformat.fp       = stdout;
  340.     informat.filename  = "input";
  341.     outformat.filename = "output";
  342. }
  343.  
  344. /*
  345.  * Process input file -> effect -> output file
  346.  *    one buffer at a time
  347.  */
  348.  
  349. process() {
  350.     long isamp, osamp, istart;
  351.     long i, idone, odone;
  352.  
  353.     gettype(&informat);
  354.     if (writing)
  355.         gettype(&outformat);
  356.     /* Read and write starters can change their formats. */
  357.     (* informat.h->startread)(&informat);
  358.     checkformat(&informat);
  359.     report("Input file: using sample rate %lu\n\tsize %s, style %s, %d %s",
  360.         informat.info.rate, sizes[informat.info.size],
  361.         styles[informat.info.style], informat.info.channels,
  362.         (informat.info.channels > 1) ? "channels" : "channel");
  363.     if (informat.comment)
  364.         report("Input file: comment \"%s\"\n",
  365.             informat.comment);
  366.     if (writing) {
  367.         copyformat(&informat, &outformat);
  368.         (* outformat.h->startwrite)(&outformat);
  369.         checkformat(&outformat);
  370.         cmpformats(&informat, &outformat);
  371.     report("Output file: using sample rate %lu\n\tsize %s, style %s, %d %s",
  372.         outformat.info.rate, sizes[outformat.info.size],
  373.         styles[outformat.info.style], outformat.info.channels,
  374.         (outformat.info.channels > 1) ? "channels" : "channel");
  375.         if (outformat.comment)
  376.             report("Output file: comment \"%s\"\n",
  377.                 outformat.comment);
  378.     }
  379.     /* Very Important:
  380.      * Effect fabrication and start is called AFTER files open.
  381.      * Effect may write out data beforehand, and
  382.      * some formats don't know their sample rate until now.
  383.      */
  384.     checkeffect(0);
  385.     /* inform effect about signal information */
  386.     eff.ininfo = informat.info;
  387.     eff.outinfo = outformat.info;
  388.     (* eff.h->start)(&eff);
  389.     istart = 0;
  390.     while((isamp = (*informat.h->read)(&informat,&ibuf[istart],
  391.             (long) BUFSIZ-istart))>0) {
  392.         long *ib = ibuf;
  393.  
  394.         isamp += istart;
  395.         /* Do volume before effect or after?  idunno */
  396.         if (dovolume) for (i = 0; i < isamp; i++)
  397.             ibuf[i] = volumechange(ibuf[i]);
  398.         osamp = sizeof(obuf) / sizeof(long);
  399.         /* Effect (i.e. rate change) may do different sizes I and O */
  400.         while (isamp) {
  401.             idone = isamp;
  402.             odone = osamp;
  403.             (* eff.h->flow)(&eff, ib, obuf, &idone, &odone);
  404.             /*
  405.              * kludge!
  406.              * Effect is stuck.  Start over with new buffer.
  407.              * This can drop samples at end of file.
  408.              * No effects currently do this, but it could happen.
  409.              */
  410.             if (idone == 0) {
  411.                 int i;
  412.                 for(i = isamp - 1; i; i--)
  413.                     ibuf[i] = ib[i];
  414.                 istart = isamp;
  415.                 isamp = 0;
  416.                 break;
  417.             }
  418.             if (writing && (odone > 0))
  419.                 (* outformat.h->write)(&outformat, obuf, (long) odone);
  420.             isamp -= idone;
  421.             ib += idone;
  422.         }
  423.     }
  424.     /* Drain effect out */
  425.     if (writing) {
  426.         odone = sizeof(obuf) / sizeof(long);
  427.         (* eff.h->drain)(&eff, obuf, &odone);
  428.         if (odone > 0)
  429.             (* outformat.h->write)(&outformat, obuf, (long) odone);
  430.         /* keep calling it until it returns a partial buffer */
  431.         while (odone == (sizeof(obuf) / sizeof(long))) {
  432.             (* eff.h->drain)(&eff, obuf, &odone);
  433.             if (odone)
  434.              (* outformat.h->write)(&outformat, obuf, (long) odone);
  435.         }
  436.     }
  437.     /* Very Important:
  438.      * Effect stop is called BEFORE files close.
  439.      * Effect may write out more data after.
  440.      */
  441.     (* eff.h->stop)(&eff);
  442.     (* informat.h->stopread)(&informat);
  443.     fclose(informat.fp);
  444.     if (writing)
  445.         (* outformat.h->stopwrite)(&outformat);
  446.     if (writing)
  447.         fclose(outformat.fp);
  448. }
  449.  
  450. /*
  451.  * Check that we have a known format suffix string.
  452.  */
  453. void
  454. gettype(formp)
  455. ft_t formp;
  456. {
  457.     char **list;
  458.     int i;
  459.  
  460.     if (! formp->filetype)
  461. fail("Must give file type for %s file, either as suffix or with -t option",
  462. formp->filename);
  463.     for(i = 0; formats[i].names; i++) {
  464.         for(list = formats[i].names; *list; list++) {
  465.             char *s1 = *list, *s2 = formp->filetype;
  466.             if (! strcmpcase(s1, s2))
  467.                 break;    /* not a match */
  468.         }
  469.         if (! *list)
  470.             continue;
  471.         /* Found it! */
  472.         formp->h = &formats[i];
  473.         return;
  474.     }
  475.     if (! strcmpcase(formp->filetype, "snd")) {
  476.         verbose = 1;
  477.         report("File type '%s' is used to name several different formats.", formp->filetype);
  478.         report("If the file came from a Macintosh, it is probably");
  479.         report("a .ub file with a sample rate of 11025 (or possibly 5012 or 22050).");
  480.         report("Use the sequence '-t .ub -r 11025 file.snd'");
  481.         report("If it came from a PC, it's probably a Soundtool file.");
  482.         report("Use the sequence '-t .sndt file.snd'");
  483.         report("If it came from a NeXT, it's probably a .au file.");
  484.         fail("Use the sequence '-t .au file.snd'\n");
  485.     }
  486.     fail("File type '%s' of %s file is not known!",
  487.         formp->filetype, formp->filename);
  488. }
  489.  
  490. copyformat(ft, ft2)
  491. ft_t ft, ft2;
  492. {
  493.     int noise = 0;
  494.     if (ft2->info.rate == 0) {
  495.         ft2->info.rate = ft->info.rate;
  496.         noise = 1;
  497.     }
  498.     if (outformat.info.size == -1) {
  499.         ft2->info.size = ft->info.size;
  500.         noise = 1;
  501.     }
  502.     if (outformat.info.style == -1) {
  503.         ft2->info.style = ft->info.style;
  504.         noise = 1;
  505.     }
  506.     if (outformat.info.channels == -1) {
  507.         ft2->info.channels = ft->info.channels;
  508.         noise = 1;
  509.     }
  510.     if (outformat.comment == NULL) {
  511.         ft2->comment = ft->comment;
  512.         noise = 1;
  513.     }
  514.     return noise;
  515. }
  516.  
  517. cmpformats(ft, ft2)
  518. ft_t ft, ft2;
  519. {
  520.     int noise = 0;
  521.     float abs;
  522.  
  523. }
  524.  
  525. /* check that all settings have been given */
  526. checkformat(ft)
  527. ft_t ft;
  528. {
  529.     if (ft->info.rate == 0)
  530.         fail("Sampling rate for %s file was not given\n", ft->filename);
  531.     if ((ft->info.rate < 100) || (ft->info.rate > 50000))
  532.         fail("Sampling rate %lu for %s file is bogus\n",
  533.             ft->info.rate, ft->filename);
  534.     if (ft->info.size == -1)
  535.         fail("Data size was not given for %s file\nUse one of -b/-w/-l/-f/-d/-D", ft->filename);
  536.     if (ft->info.style == -1)
  537.         fail("Data style was not given for %s file\nUse one of -s/-u/-U/-A", ft->filename);
  538.     /* it's so common, might as well default */
  539.     if (ft->info.channels == -1)
  540.         ft->info.channels = 1;
  541.     /*    fail("Number of output channels was not given for %s file",
  542.             ft->filename); */
  543. }
  544.  
  545. /*
  546.  * If no effect given, decide what it should be.
  547.  */
  548. void
  549. checkeffect(effp)
  550. eff_t effp;
  551. {
  552.     int already = (eff.name != (char *) 0);
  553.     char *rate = 0, *chan = 0;
  554.     int i;
  555.  
  556.     for (i = 0; effects[i].name; i++) {
  557.         if (!chan && (effects[i].flags & EFF_CHAN))
  558.             chan = effects[i].name;
  559.         if (! rate && (effects[i].flags & EFF_RATE))
  560.             rate = effects[i].name;
  561.     }
  562.  
  563.     if (eff.name && ! writing)
  564.         return;
  565.  
  566.     /*
  567.      * Require mixdown for channel mismatch.
  568.      * XXX Doesn't handle channel expansion.  Need an effect for this.
  569.      * Require one of the rate-changers on a rate change.
  570.      * Override a rate change by explicitly giving 'copy' command.
  571.      */
  572.     if (informat.info.channels != outformat.info.channels) {
  573.         if (eff.name && !(eff.h->flags & EFF_CHAN))
  574.             fail("Need to do change number of channels first.  Try the '%s' effect.", chan);
  575.         if (! eff.name) {
  576.             eff.name = chan;
  577.             report(
  578. "Changing %d input channels to %d output channels with '%s' effect\n",
  579.             informat.info.channels, outformat.info.channels, chan);
  580.             geteffect(&eff);
  581.         }
  582.     }
  583.     /*
  584.      * Be liberal on rate difference errors.
  585.      * Note that the SPARC 8000-8192 problem
  586.      * comes in just under the wire.  XXX
  587.      *
  588.       * Bogus.  Should just do a percentage.
  589.      */
  590.     if (abs(informat.info.rate - outformat.info.rate) > 200) {
  591.         if (eff.name && !(eff.h->flags & EFF_RATE))
  592.             fail("Need to do rate change first.  Try the '%s' effect.",
  593.             rate);
  594.         if (! eff.name) {
  595.             eff.name = rate;
  596.             report(
  597. "Changing sample rate %lu to rate %lu via noisy 'rate' effect\n",
  598.             informat.info.rate, outformat.info.rate);
  599.             geteffect(&eff);
  600.         }
  601.     }
  602.     /* don't need to change anything */
  603.     if (! eff.name)
  604.         eff.name = "copy";
  605.     if (! already) {
  606.         geteffect(&eff);
  607.         /* give default opts for manufactured effect */
  608.         (* eff.h->getopts)(&eff, 0, (char *) 0);
  609.     }
  610. }
  611.  
  612. /*
  613.  * Check that we have a known effect name.
  614.  */
  615. void
  616. geteffect(effp)
  617. eff_t effp;
  618. {
  619.     int i;
  620.  
  621.     for(i = 0; effects[i].name; i++) {
  622.         char *s1 = effects[i].name, *s2 = effp->name;
  623.         while(*s1 && *s2 && (tolower(*s1) == tolower(*s2)))
  624.             s1++, s2++;
  625.         if (*s1 || *s2)
  626.             continue;    /* not a match */
  627.         /* Found it! */
  628.         effp->h = &effects[i];
  629.         return;
  630.     }
  631.     /* Guido Van Rossum fix */
  632.     fprintf(stderr, "Known effects:");
  633.     for (i = 0; effects[i].name; i++)
  634.         fprintf(stderr, "\t%s\n", effects[i].name);
  635.     fail("\nEffect '%s' is not known!", effp->name);
  636. }
  637.  
  638. /* Guido Van Rossum fix */
  639. statistics() {
  640.     if (dovolume && clipped > 0)
  641.         report("Volume change clipped %d samples", clipped);
  642. }
  643.  
  644. long volumechange(y)
  645. long y;
  646. {
  647.     double y1;
  648.  
  649.     y1 = y * volume;
  650.     if (y1 < -2147483647.0) {
  651.         y1 = -2147483647.0;
  652.         clipped++;
  653.     }
  654.     else if (y1 > 2147483647.0) {
  655.         y1 = 2147483647.0;
  656.         clipped++;
  657.     }
  658.  
  659.     return y1;
  660. }
  661.  
  662. #if    defined(unix) || defined(AMIGA) || defined(ARM)
  663. filetype(fd)
  664. int fd;
  665. {
  666.     struct stat st;
  667.  
  668.     fstat(fd, &st);
  669.  
  670.     return st.st_mode & S_IFMT;
  671. }
  672. #endif
  673.  
  674. char *usagestr =
  675. "[ -V -S ] [ fopts ] ifile [ fopts ] ofile [ effect [ effopts ] ]\nfopts: -r rate -v volume -c channels -s/-u/-U/-A -b/-w/-l/-f/-d/-D -x\neffects and effopts: various";
  676.  
  677. usage(opt)
  678. char *opt;
  679. {
  680. #ifndef    DOS
  681.     /* single-threaded machines don't really need this */
  682.     fprintf(stderr, "%s: ", myname);
  683. #endif
  684.     fprintf(stderr, "Usage: %s", usagestr);
  685.     if (opt)
  686.         fprintf(stderr, "\nFailed at: %s\n", opt);
  687.     exit(1);
  688. }
  689.  
  690. void
  691. #if defined(__STDC__) || defined(ARM)
  692. report(char *fmt, ...)
  693. #else
  694. report(va_alist)
  695. va_dcl
  696. #endif
  697. {
  698.     va_list args;
  699. #if !defined(__STDC__) && !defined(ARM)
  700.     char *fmt;
  701. #endif
  702.  
  703.     if (! verbose)
  704.         return;
  705. #ifndef    DOS
  706.     /* single-threaded machines don't really need this */
  707.     fprintf(stderr, "%s: ", myname);
  708. #endif
  709. #if defined(__STDC__) || defined(ARM)
  710.     va_start(args, fmt);
  711. #else
  712.     va_start(args);
  713. #endif
  714. #ifndef ARM
  715.     fmt = va_arg(args, char *);
  716. #endif
  717.     vfprintf(stderr, fmt, args);
  718.     va_end(args);
  719.     fprintf(stderr, "\n");
  720. }
  721.  
  722. void
  723. #if defined(__STDC__) || defined(ARM)
  724. fail(char *fmt, ...)
  725. #else
  726. fail(va_alist)
  727. va_dcl
  728. #endif
  729. {
  730.     va_list args;
  731. #if !defined(__STDC__) && !defined(ARM)
  732.     char *fmt;
  733. #endif
  734.  
  735. #ifndef    DOS
  736.     /* single-threaded machines don't really need this */
  737.     fprintf(stderr, "%s: ", myname);
  738. #endif
  739. #if defined(__STDC__) || defined(ARM)
  740.     va_start(args, fmt);
  741. #else
  742.     va_start(args);
  743. #endif
  744. #ifndef ARM
  745.     fmt = va_arg(args, char *);
  746. #endif
  747.     vfprintf(stderr, fmt, args);
  748.     va_end(args);
  749.     fprintf(stderr, "\n");
  750.     /* Close the input file and outputfile before exiting*/
  751.     ft = &informat;
  752.     fclose(ft->fp);
  753.     ft = &outformat;
  754.     fclose(ft->fp);
  755.  
  756.     /* remove the output file because we failed */
  757.     REMOVE(ft->filename);
  758.     exit(2);
  759. }
  760.  
  761.  
  762. strcmpcase(s1, s2)
  763. char *s1, *s2;
  764. {
  765.     while(*s1 && *s2 && (tolower(*s1) == tolower(*s2)))
  766.         s1++, s2++;
  767.     return *s1 - *s2;
  768. }
  769.