1 /*
2  *      Command line parsing related functions
3  *
4  *      Copyright (c) 1999 Mark Taylor
5  *                    2000-2017 Robert Hegemann
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22 
23 /* $Id: parse.c,v 1.307 2017/09/26 12:25:07 robert Exp $ */
24 
25 #ifdef HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28 
29 #include <assert.h>
30 #include <ctype.h>
31 #include <math.h>
32 
33 #ifdef STDC_HEADERS
34 # include <stdio.h>
35 # include <stdlib.h>
36 # include <string.h>
37 #else
38 # ifndef HAVE_STRCHR
39 #  define strchr index
40 #  define strrchr rindex
41 # endif
42 char   *strchr(), *strrchr();
43 # ifndef HAVE_MEMCPY
44 #  define memcpy(d, s, n) bcopy ((s), (d), (n))
45 #  define memmove(d, s, n) bcopy ((s), (d), (n))
46 # endif
47 #endif
48 
49 
50 #ifdef HAVE_LIMITS_H
51 # include <limits.h>
52 #endif
53 
54 #include "lame.h"
55 
56 #include "parse.h"
57 #include "main.h"
58 #include "get_audio.h"
59 #include "version.h"
60 #include "console.h"
61 
62 #undef dimension_of
63 #define dimension_of(array) (sizeof(array)/sizeof(array[0]))
64 
65 #ifdef WITH_DMALLOC
66 #include <dmalloc.h>
67 #endif
68 
69 
70 #ifdef HAVE_ICONV
71 #include <iconv.h>
72 #include <errno.h>
73 #include <locale.h>
74 #include <langinfo.h>
75 #endif
76 
77 #if defined _ALLOW_INTERNAL_OPTIONS
78 #define INTERNAL_OPTS 1
79 #else
80 #define INTERNAL_OPTS 0
81 #endif
82 
83 #if (INTERNAL_OPTS!=0)
84 #include "set_get.h"
85 #define DEV_HELP(a) a
86 #else
87 #define DEV_HELP(a)
88 #define lame_set_tune(a,b) (void)0
89 #define lame_set_short_threshold(a,b,c) (void)0
90 #define lame_set_maskingadjust(a,b) (void)0
91 #define lame_set_maskingadjust_short(a,b) (void)0
92 #define lame_set_ATHcurve(a,b) (void)0
93 #define lame_set_preset_notune(a,b) (void)0
94 #define lame_set_substep(a,b) (void)0
95 #define lame_set_subblock_gain(a,b) (void)0
96 #define lame_set_sfscale(a,b) (void)0
97 #endif
98 
99 static int const lame_alpha_version_enabled = LAME_ALPHA_VERSION;
100 static int const internal_opts_enabled = INTERNAL_OPTS;
101 
102 /* GLOBAL VARIABLES.  set by parse_args() */
103 /* we need to clean this up */
104 
105 ReaderConfig global_reader = { sf_unknown, 0, 0, 0, 0 };
106 WriterConfig global_writer = { 0 };
107 
108 UiConfig global_ui_config = {0,0,0,0};
109 
110 DecoderConfig global_decoder;
111 
112 RawPCMConfig global_raw_pcm =
113 { /* in_bitwidth */ 16
114 , /* in_signed   */ -1
115 , /* in_endian   */ ByteOrderLittleEndian
116 };
117 
118 
119 
120 /* possible text encodings */
121 typedef enum TextEncoding
122 { TENC_RAW     /* bytes will be stored as-is into ID3 tags, which are Latin1 per definition */
123 , TENC_LATIN1  /* text will be converted from local encoding to Latin1, as ID3 needs it */
124 , TENC_UTF16   /* text will be converted from local encoding to Unicode, as ID3v2 wants it */
125 } TextEncoding;
126 
127 #ifdef HAVE_ICONV
128 #define ID3TAGS_EXTENDED
129 /* search for Zero termination in multi-byte strings */
130 static size_t
strlenMultiByte(char const * str,size_t w)131 strlenMultiByte(char const* str, size_t w)
132 {
133     size_t n = 0;
134     if (str != 0) {
135         size_t i, x = 0;
136         for (n = 0; ; ++n) {
137             x = 0;
138             for (i = 0; i < w; ++i) {
139                 x += *str++ == 0 ? 1 : 0;
140             }
141             if (x == w) {
142                 break;
143             }
144         }
145     }
146     return n;
147 }
148 
149 
150 static size_t
currCharCodeSize(void)151 currCharCodeSize(void)
152 {
153     size_t n = 1;
154     char dst[32];
155     char* src = "A";
156     char* cur_code = nl_langinfo(CODESET);
157     iconv_t xiconv = iconv_open(cur_code, "ISO_8859-1");
158     if (xiconv != (iconv_t)-1) {
159         for (n = 0; n < 32; ++n) {
160             char* i_ptr = src;
161             char* o_ptr = dst;
162             size_t srcln = 1;
163             size_t avail = n;
164             size_t rc = iconv(xiconv, &i_ptr, &srcln, &o_ptr, &avail);
165             if (rc != (size_t)-1) {
166                 break;
167             }
168         }
169         iconv_close(xiconv);
170     }
171     return n;
172 }
173 
174 #if 0
175 static
176 char* fromLatin1( char* src )
177 {
178     char* dst = 0;
179     if (src != 0) {
180         size_t const l = strlen(src);
181         size_t const n = l*4;
182         dst = calloc(n+4, 4);
183         if (dst != 0) {
184             char* cur_code = nl_langinfo(CODESET);
185             iconv_t xiconv = iconv_open(cur_code, "ISO_8859-1");
186             if (xiconv != (iconv_t)-1) {
187                 char* i_ptr = src;
188                 char* o_ptr = dst;
189                 size_t srcln = l;
190                 size_t avail = n;
191                 iconv(xiconv, &i_ptr, &srcln, &o_ptr, &avail);
192                 iconv_close(xiconv);
193             }
194         }
195     }
196     return dst;
197 }
198 
199 static
200 char* fromUtf16( char* src )
201 {
202     char* dst = 0;
203     if (src != 0) {
204         size_t const l = strlenMultiByte(src, 2);
205         size_t const n = l*4;
206         dst = calloc(n+4, 4);
207         if (dst != 0) {
208             char* cur_code = nl_langinfo(CODESET);
209             iconv_t xiconv = iconv_open(cur_code, "UTF-16LE");
210             if (xiconv != (iconv_t)-1) {
211                 char* i_ptr = (char*)src;
212                 char* o_ptr = dst;
213                 size_t srcln = l*2;
214                 size_t avail = n;
215                 iconv(xiconv, &i_ptr, &srcln, &o_ptr, &avail);
216                 iconv_close(xiconv);
217             }
218         }
219     }
220     return dst;
221 }
222 #endif
223 
224 static
toLatin1(char * src)225 char* toLatin1( char* src )
226 {
227     size_t w = currCharCodeSize();
228     char* dst = 0;
229     if (src != 0) {
230         size_t const l = strlenMultiByte(src, w);
231         size_t const n = l*4;
232         dst = calloc(n+4, 4);
233         if (dst != 0) {
234             char* cur_code = nl_langinfo(CODESET);
235             iconv_t xiconv = iconv_open("ISO_8859-1//TRANSLIT", cur_code);
236             if (xiconv != (iconv_t)-1) {
237                 char* i_ptr = (char*)src;
238                 char* o_ptr = dst;
239                 size_t srcln = l*w;
240                 size_t avail = n;
241                 iconv(xiconv, &i_ptr, &srcln, &o_ptr, &avail);
242                 iconv_close(xiconv);
243             }
244         }
245     }
246     return dst;
247 }
248 
249 
250 static
toUtf16(char * src)251 char* toUtf16( char* src )
252 {
253     size_t w = currCharCodeSize();
254     char* dst = 0;
255     if (src != 0) {
256         size_t const l = strlenMultiByte(src, w);
257         size_t const n = (l+1)*4;
258         dst = calloc(n+4, 4);
259         if (dst != 0) {
260             char* cur_code = nl_langinfo(CODESET);
261             iconv_t xiconv = iconv_open("UTF-16LE//TRANSLIT", cur_code);
262             dst[0] = 0xff;
263             dst[1] = 0xfe;
264             if (xiconv != (iconv_t)-1) {
265                 char* i_ptr = (char*)src;
266                 char* o_ptr = &dst[2];
267                 size_t srcln = l*w;
268                 size_t avail = n;
269                 iconv(xiconv, &i_ptr, &srcln, &o_ptr, &avail);
270                 iconv_close(xiconv);
271             }
272         }
273     }
274     return dst;
275 }
276 #endif
277 
278 #if defined( _WIN32 ) && !defined(__MINGW32__)
279 #define ID3TAGS_EXTENDED
280 
toLatin1(char const * s)281 char* toLatin1(char const* s)
282 {
283     return utf8ToLatin1(s);
284 }
285 
toUtf16(char const * s)286 unsigned short* toUtf16(char const* s)
287 {
288     return utf8ToUtf16(s);
289 }
290 #endif
291 
evaluateArgument(char const * token,char const * arg,char * _EndPtr)292 static int evaluateArgument(char const* token, char const* arg, char* _EndPtr)
293 {
294     if (arg != 0 && arg != _EndPtr)
295         return 1;
296     error_printf("WARNING: argument missing for '%s'\n", token);
297     return 0;
298 }
299 
getDoubleValue(char const * token,char const * arg,double * ptr)300 static int getDoubleValue(char const* token, char const* arg, double* ptr)
301 {
302     char *_EndPtr=0;
303     double d = strtod(arg, &_EndPtr);
304     if (ptr != 0) {
305         *ptr = d;
306     }
307     return evaluateArgument(token, arg, _EndPtr);
308 }
309 
getIntValue(char const * token,char const * arg,int * ptr)310 static int getIntValue(char const* token, char const* arg, int* ptr)
311 {
312     char *_EndPtr=0;
313     long d = strtol(arg, &_EndPtr, 10);
314     if (ptr != 0) {
315         *ptr = d;
316     }
317     return evaluateArgument(token, arg, _EndPtr);
318 }
319 
320 #ifdef ID3TAGS_EXTENDED
321 static int
set_id3v2tag(lame_global_flags * gfp,int type,unsigned short const * str)322 set_id3v2tag(lame_global_flags* gfp, int type, unsigned short const* str)
323 {
324     switch (type)
325     {
326         case 'a': return id3tag_set_textinfo_utf16(gfp, "TPE1", str);
327         case 't': return id3tag_set_textinfo_utf16(gfp, "TIT2", str);
328         case 'l': return id3tag_set_textinfo_utf16(gfp, "TALB", str);
329         case 'g': return id3tag_set_textinfo_utf16(gfp, "TCON", str);
330         case 'c': return id3tag_set_comment_utf16(gfp, 0, 0, str);
331         case 'n': return id3tag_set_textinfo_utf16(gfp, "TRCK", str);
332         case 'y': return id3tag_set_textinfo_utf16(gfp, "TYER", str);
333         case 'v': return id3tag_set_fieldvalue_utf16(gfp, str);
334     }
335     return 0;
336 }
337 #endif
338 
339 static int
set_id3tag(lame_global_flags * gfp,int type,char const * str)340 set_id3tag(lame_global_flags* gfp, int type, char const* str)
341 {
342     switch (type)
343     {
344         case 'a': return id3tag_set_artist(gfp, str), 0;
345         case 't': return id3tag_set_title(gfp, str), 0;
346         case 'l': return id3tag_set_album(gfp, str), 0;
347         case 'g': return id3tag_set_genre(gfp, str);
348         case 'c': return id3tag_set_comment(gfp, str), 0;
349         case 'n': return id3tag_set_track(gfp, str);
350         case 'y': return id3tag_set_year(gfp, str), 0;
351         case 'v': return id3tag_set_fieldvalue(gfp, str);
352     }
353     return 0;
354 }
355 
356 static int
id3_tag(lame_global_flags * gfp,int type,TextEncoding enc,char * str)357 id3_tag(lame_global_flags* gfp, int type, TextEncoding enc, char* str)
358 {
359     void* x = 0;
360     int result;
361     if (enc == TENC_UTF16 && type != 'v' ) {
362         id3_tag(gfp, type, TENC_LATIN1, str); /* for id3v1 */
363     }
364     switch (enc)
365     {
366         default:
367 #ifdef ID3TAGS_EXTENDED
368         case TENC_LATIN1: x = toLatin1(str); break;
369         case TENC_UTF16:  x = toUtf16(str);   break;
370 #else
371         case TENC_RAW:    x = strdup(str);   break;
372 #endif
373     }
374     switch (enc)
375     {
376         default:
377 #ifdef ID3TAGS_EXTENDED
378         case TENC_LATIN1: result = set_id3tag(gfp, type, x);   break;
379         case TENC_UTF16:  result = set_id3v2tag(gfp, type, x); break;
380 #else
381         case TENC_RAW:    result = set_id3tag(gfp, type, x);   break;
382 #endif
383     }
384     free(x);
385     return result;
386 }
387 
388 
389 
390 
391 /************************************************************************
392 *
393 * license
394 *
395 * PURPOSE:  Writes version and license to the file specified by fp
396 *
397 ************************************************************************/
398 
399 static int
lame_version_print(FILE * const fp)400 lame_version_print(FILE * const fp)
401 {
402     const char *b = get_lame_os_bitness();
403     const char *v = get_lame_version();
404     const char *u = get_lame_url();
405     const size_t lenb = strlen(b);
406     const size_t lenv = strlen(v);
407     const size_t lenu = strlen(u);
408     const size_t lw = 80;       /* line width of terminal in characters */
409     const size_t sw = 16;       /* static width of text */
410 
411     if (lw >= lenb + lenv + lenu + sw || lw < lenu + 2)
412         /* text fits in 80 chars per line, or line even too small for url */
413         if (lenb > 0)
414             fprintf(fp, "LAME %s version %s (%s)\n\n", b, v, u);
415         else
416             fprintf(fp, "LAME version %s (%s)\n\n", v, u);
417     else {
418         int const n_white_spaces = (int)((lenu+2) > lw ? 0 : lw-2-lenu);
419         /* text too long, wrap url into next line, right aligned */
420         if (lenb > 0)
421             fprintf(fp, "LAME %s version %s\n%*s(%s)\n\n", b, v, n_white_spaces, "", u);
422         else
423             fprintf(fp, "LAME version %s\n%*s(%s)\n\n", v, n_white_spaces, "", u);
424     }
425     if (lame_alpha_version_enabled)
426         fprintf(fp, "warning: alpha versions should be used for testing only\n\n");
427 
428 
429     return 0;
430 }
431 
432 static int
print_license(FILE * const fp)433 print_license(FILE * const fp)
434 {                       /* print version & license */
435     lame_version_print(fp);
436     fprintf(fp,
437             "Copyright (c) 1999-2011 by The LAME Project\n"
438             "Copyright (c) 1999,2000,2001 by Mark Taylor\n"
439             "Copyright (c) 1998 by Michael Cheng\n"
440             "Copyright (c) 1995,1996,1997 by Michael Hipp: mpglib\n" "\n");
441     fprintf(fp,
442             "This library is free software; you can redistribute it and/or\n"
443             "modify it under the terms of the GNU Library General Public\n"
444             "License as published by the Free Software Foundation; either\n"
445             "version 2 of the License, or (at your option) any later version.\n"
446             "\n");
447     fprintf(fp,
448             "This library is distributed in the hope that it will be useful,\n"
449             "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
450             "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
451             "Library General Public License for more details.\n"
452             "\n");
453     fprintf(fp,
454             "You should have received a copy of the GNU Library General Public\n"
455             "License along with this program. If not, see\n"
456             "<http://www.gnu.org/licenses/>.\n");
457     return 0;
458 }
459 
460 
461 /************************************************************************
462 *
463 * usage
464 *
465 * PURPOSE:  Writes command line syntax to the file specified by fp
466 *
467 ************************************************************************/
468 
469 int
usage(FILE * const fp,const char * ProgramName)470 usage(FILE * const fp, const char *ProgramName)
471 {                       /* print general syntax */
472     lame_version_print(fp);
473     fprintf(fp,
474             "usage: %s [options] <infile> [outfile]\n"
475             "\n"
476             "    <infile> and/or <outfile> can be \"-\", which means stdin/stdout.\n"
477             "\n"
478             "Try:\n"
479             "     \"%s --help\"           for general usage information\n"
480             " or:\n"
481             "     \"%s --preset help\"    for information on suggested predefined settings\n"
482             " or:\n"
483             "     \"%s --longhelp\"\n"
484             "  or \"%s -?\"              for a complete options list\n\n",
485             ProgramName, ProgramName, ProgramName, ProgramName, ProgramName);
486     return 0;
487 }
488 
489 
490 /************************************************************************
491 *
492 * usage
493 *
494 * PURPOSE:  Writes command line syntax to the file specified by fp
495 *           but only the most important ones, to fit on a vt100 terminal
496 *
497 ************************************************************************/
498 
499 int
short_help(const lame_global_flags * gfp,FILE * const fp,const char * ProgramName)500 short_help(const lame_global_flags * gfp, FILE * const fp, const char *ProgramName)
501 {                       /* print short syntax help */
502     lame_version_print(fp);
503     fprintf(fp,
504             "usage: %s [options] <infile> [outfile]\n"
505             "\n"
506             "    <infile> and/or <outfile> can be \"-\", which means stdin/stdout.\n"
507             "\n" "RECOMMENDED:\n" "    lame -V2 input.wav output.mp3\n" "\n", ProgramName);
508     fprintf(fp,
509             "OPTIONS:\n"
510             "    -b bitrate      set the bitrate, default 128 kbps\n"
511             "    -h              higher quality, but a little slower.\n"
512             "    -f              fast mode (lower quality)\n"
513             "    -V n            quality setting for VBR.  default n=%i\n"
514             "                    0=high quality,bigger files. 9.999=smaller files\n",
515             lame_get_VBR_q(gfp));
516     fprintf(fp,
517             "    --preset type   type must be \"medium\", \"standard\", \"extreme\", \"insane\",\n"
518             "                    or a value for an average desired bitrate and depending\n"
519             "                    on the value specified, appropriate quality settings will\n"
520             "                    be used.\n"
521             "                    \"--preset help\" gives more info on these\n" "\n");
522     fprintf(fp,
523 #if defined(WIN32)
524             "    --priority type  sets the process priority\n"
525             "                     0,1 = Low priority\n"
526             "                     2   = normal priority\n"
527             "                     3,4 = High priority\n" "\n"
528 #endif
529 #if defined(__OS2__)
530             "    --priority type  sets the process priority\n"
531             "                     0 = Low priority\n"
532             "                     1 = Medium priority\n"
533             "                     2 = Regular priority\n"
534             "                     3 = High priority\n"
535             "                     4 = Maximum priority\n" "\n"
536 #endif
537             "    --help id3      ID3 tagging related options\n" "\n"
538             DEV_HELP(
539             "    --help dev      developer options\n" "\n"
540             )
541             "    --longhelp      full list of options\n" "\n"
542             "    --license       print License information\n\n"
543             );
544 
545     return 0;
546 }
547 
548 /************************************************************************
549 *
550 * usage
551 *
552 * PURPOSE:  Writes command line syntax to the file specified by fp
553 *
554 ************************************************************************/
555 
556 static void
wait_for(FILE * const fp,int lessmode)557 wait_for(FILE * const fp, int lessmode)
558 {
559     if (lessmode) {
560         fflush(fp);
561         getchar();
562     }
563     else {
564         fprintf(fp, "\n");
565     }
566     fprintf(fp, "\n");
567 }
568 
569 static void
help_id3tag(FILE * const fp)570 help_id3tag(FILE * const fp)
571 {
572     fprintf(fp,
573             "  ID3 tag options:\n"
574             "    --tt <title>    audio/song title (max 30 chars for version 1 tag)\n"
575             "    --ta <artist>   audio/song artist (max 30 chars for version 1 tag)\n"
576             "    --tl <album>    audio/song album (max 30 chars for version 1 tag)\n"
577             "    --ty <year>     audio/song year of issue (1 to 9999)\n"
578             "    --tc <comment>  user-defined text (max 30 chars for v1 tag, 28 for v1.1)\n");
579     fprintf(fp,
580             "    --tn <track[/total]>   audio/song track number and (optionally) the total\n"
581             "                           number of tracks on the original recording. (track\n"
582             "                           and total each 1 to 255. just the track number\n"
583             "                           creates v1.1 tag, providing a total forces v2.0).\n");
584     fprintf(fp,
585             "    --tg <genre>    audio/song genre (name or number in list)\n"
586             "    --ti <file>     audio/song albumArt (jpeg/png/gif file, v2.3 tag)\n"
587             "    --tv <id=value> user-defined frame specified by id and value (v2.3 tag)\n"
588             "                    syntax: --tv \"TXXX=description=content\"\n"
589             );
590     fprintf(fp,
591             "    --add-id3v2     force addition of version 2 tag\n"
592             "    --id3v1-only    add only a version 1 tag\n"
593             "    --id3v2-only    add only a version 2 tag\n"
594 #ifdef ID3TAGS_EXTENDED
595             "    --id3v2-utf16   add following options in unicode text encoding\n"
596             "    --id3v2-latin1  add following options in latin-1 text encoding\n"
597 #endif
598             "    --space-id3v1   pad version 1 tag with spaces instead of nulls\n"
599             "    --pad-id3v2     same as '--pad-id3v2-size 128'\n"
600             "    --pad-id3v2-size <value> adds version 2 tag, pad with extra <value> bytes\n"
601             "    --genre-list    print alphabetically sorted ID3 genre list and exit\n"
602             "    --ignore-tag-errors  ignore errors in values passed for tags\n" "\n"
603             );
604     fprintf(fp,
605             "    Note: A version 2 tag will NOT be added unless one of the input fields\n"
606             "    won't fit in a version 1 tag (e.g. the title string is longer than 30\n"
607             "    characters), or the '--add-id3v2' or '--id3v2-only' options are used,\n"
608             "    or output is redirected to stdout.\n"
609             );
610 }
611 
612 static void
help_developer_switches(FILE * const fp)613 help_developer_switches(FILE * const fp)
614 {
615     if ( !internal_opts_enabled ) {
616     fprintf(fp,
617             "    Note: Almost all of the following switches aren't available in this build!\n\n"
618             );
619     }
620     fprintf(fp,
621             "  ATH related:\n"
622             "    --noath         turns ATH down to a flat noise floor\n"
623             "    --athshort      ignore GPSYCHO for short blocks, use ATH only\n"
624             "    --athonly       ignore GPSYCHO completely, use ATH only\n"
625             "    --athtype n     selects between different ATH types [0-4]\n"
626             "    --athlower x    lowers ATH by x dB\n"
627             );
628     fprintf(fp,
629             "    --athaa-type n  ATH auto adjust: 0 'no' else 'loudness based'\n"
630 /** OBSOLETE "    --athaa-loudapprox n   n=1 total energy or n=2 equal loudness curve\n"*/
631             "    --athaa-sensitivity x  activation offset in -/+ dB for ATH auto-adjustment\n"
632             "\n");
633     fprintf(fp,
634             "  PSY related:\n"
635             "    --short         use short blocks when appropriate\n"
636             "    --noshort       do not use short blocks\n"
637             "    --allshort      use only short blocks\n"
638             );
639     fprintf(fp,
640             "(1) --temporal-masking x   x=0 disables, x=1 enables temporal masking effect\n"
641             "    --nssafejoint   M/S switching criterion\n"
642             "    --nsmsfix <arg> M/S switching tuning [effective 0-3.5]\n"
643             "(2) --interch x     adjust inter-channel masking ratio\n"
644             "    --ns-bass x     adjust masking for sfbs  0 -  6 (long)  0 -  5 (short)\n"
645             "    --ns-alto x     adjust masking for sfbs  7 - 13 (long)  6 - 10 (short)\n"
646             "    --ns-treble x   adjust masking for sfbs 14 - 21 (long) 11 - 12 (short)\n"
647             );
648     fprintf(fp,
649             "    --ns-sfb21 x    change ns-treble by x dB for sfb21\n"
650             "    --shortthreshold x,y  short block switching threshold,\n"
651             "                          x for L/R/M channel, y for S channel\n"
652             "    -Z [n]          always do calculate short block maskings\n");
653     fprintf(fp,
654             "  Noise Shaping related:\n"
655             "(1) --substep n     use pseudo substep noise shaping method types 0-2\n"
656             "(1) -X n[,m]        selects between different noise measurements\n"
657             "                    n for long block, m for short. if m is omitted, m = n\n"
658             " 1: CBR, ABR and VBR-old encoding modes only\n"
659             " 2: ignored\n"
660            );
661 }
662 
663 int
long_help(const lame_global_flags * gfp,FILE * const fp,const char * ProgramName,int lessmode)664 long_help(const lame_global_flags * gfp, FILE * const fp, const char *ProgramName, int lessmode)
665 {                       /* print long syntax help */
666     lame_version_print(fp);
667     fprintf(fp,
668             "usage: %s [options] <infile> [outfile]\n"
669             "\n"
670             "    <infile> and/or <outfile> can be \"-\", which means stdin/stdout.\n"
671             "\n" "RECOMMENDED:\n" "    lame -V2 input.wav output.mp3\n" "\n", ProgramName);
672     fprintf(fp,
673             "OPTIONS:\n"
674             "  Input options:\n"
675             "    --scale <arg>   scale input (multiply PCM data) by <arg>\n"
676             "    --scale-l <arg> scale channel 0 (left) input (multiply PCM data) by <arg>\n"
677             "    --scale-r <arg> scale channel 1 (right) input (multiply PCM data) by <arg>\n"
678             "    --swap-channel  swap L/R channels\n"
679             "    --ignorelength  ignore file length in WAV header\n"
680             "    --gain <arg>    apply Gain adjustment in decibels, range -20.0 to +12.0\n"
681            );
682 #if (defined HAVE_MPGLIB || defined AMIGA_MPEGA)
683     fprintf(fp,
684             "    --mp1input      input file is a MPEG Layer I   file\n"
685             "    --mp2input      input file is a MPEG Layer II  file\n"
686             "    --mp3input      input file is a MPEG Layer III file\n"
687            );
688 #endif
689     fprintf(fp,
690             "    --nogap <file1> <file2> <...>\n"
691             "                    gapless encoding for a set of contiguous files\n"
692             "    --nogapout <dir>\n"
693             "                    output dir for gapless encoding (must precede --nogap)\n"
694             "    --nogaptags     allow the use of VBR tags in gapless encoding\n"
695             "    --out-dir <dir> output dir, must exist\n"
696            );
697     fprintf(fp,
698             "\n"
699             "  Input options for RAW PCM:\n"
700             "    -r              input is raw pcm\n"
701             "    -s sfreq        sampling frequency of input file (kHz) - default 44.1 kHz\n"
702             "    --signed        input is signed (default)\n"
703             "    --unsigned      input is unsigned\n"
704             "    --bitwidth w    input bit width is w (default 16)\n"
705             "    -x              force byte-swapping of input\n"
706             "    --little-endian input is little-endian (default)\n"
707             "    --big-endian    input is big-endian\n"
708             "    -a              downmix from stereo to mono file for mono encoding\n"
709            );
710 
711     wait_for(fp, lessmode);
712     fprintf(fp,
713             "  Operational options:\n"
714             "    -m <mode>       (j)oint, (s)imple, (f)orce, (d)ual-mono, (m)ono (l)eft (r)ight\n"
715             "                    default is (j)\n"
716             "                    joint  = Uses the best possible of MS and LR stereo\n"
717             "                    simple = force LR stereo on all frames\n"
718             "                    force  = force MS stereo on all frames.\n"
719 	   );
720     fprintf(fp,
721             "    --preset type   type must be \"medium\", \"standard\", \"extreme\", \"insane\",\n"
722             "                    or a value for an average desired bitrate and depending\n"
723             "                    on the value specified, appropriate quality settings will\n"
724             "                    be used.\n"
725             "                    \"--preset help\" gives more info on these\n"
726             "    --comp  <arg>   choose bitrate to achieve a compression ratio of <arg>\n");
727     fprintf(fp, "    --replaygain-fast   compute RG fast but slightly inaccurately (default)\n"
728 #ifdef DECODE_ON_THE_FLY
729             "    --replaygain-accurate   compute RG more accurately and find the peak sample\n"
730 #endif
731             "    --noreplaygain  disable ReplayGain analysis\n"
732 #ifdef DECODE_ON_THE_FLY
733             "    --clipdetect    enable --replaygain-accurate and print a message whether\n"
734             "                    clipping occurs and how far the waveform is from full scale\n"
735 #endif
736         );
737     fprintf(fp,
738             "    --flush         flush output stream as soon as possible\n"
739             "    --freeformat    produce a free format bitstream\n"
740             "    --decode        input=mp3 file, output=wav\n"
741             "    -t              disable writing wav header when using --decode\n");
742 
743     wait_for(fp, lessmode);
744     fprintf(fp,
745             "  Verbosity:\n"
746             "    --disptime <arg>print progress report every arg seconds\n"
747             "    -S              don't print progress report, VBR histograms\n"
748             "    --nohist        disable VBR histogram display\n"
749             "    --quiet         don't print anything on screen\n"
750             "    --silent        don't print anything on screen, but fatal errors\n"
751             "    --brief         print more useful information\n"
752             "    --verbose       print a lot of useful information\n" "\n");
753     fprintf(fp,
754             "  Noise shaping & psycho acoustic algorithms:\n"
755             "    -q <arg>        <arg> = 0...9.  Default  -q 3 \n"
756             "                    -q 0:  Highest quality, very slow \n"
757             "                    -q 9:  Poor quality, but fast \n"
758             "    -h              Same as -q 2.   \n"
759             "    -f              Same as -q 7.   Fast, ok quality\n");
760 
761     wait_for(fp, lessmode);
762     fprintf(fp,
763             "  CBR (constant bitrate, the default) options:\n"
764             "    -b <bitrate>    set the bitrate in kbps, default 128 kbps\n"
765             "    --cbr           enforce use of constant bitrate\n"
766             "\n"
767             "  ABR options:\n"
768             "    --abr <bitrate> specify average bitrate desired (instead of quality)\n" "\n");
769     fprintf(fp,
770             "  VBR options:\n"
771             "    -V n            quality setting for VBR.  default n=%i\n"
772             "                    0=high quality,bigger files. 9=smaller files\n"
773             "    -v              the same as -V 4\n"
774             "    --vbr-old       use old variable bitrate (VBR) routine\n"
775             "    --vbr-new       use new variable bitrate (VBR) routine (default)\n"
776             "    -Y              lets LAME ignore noise in sfb21, like in CBR\n"
777 			"                    (Default for V3 to V9.999)\n"
778             ,
779             lame_get_VBR_q(gfp));
780     fprintf(fp,
781             "    -b <bitrate>    specify minimum allowed bitrate, default  32 kbps\n"
782             "    -B <bitrate>    specify maximum allowed bitrate, default 320 kbps\n"
783             "    -F              strictly enforce the -b option, for use with players that\n"
784             "                    do not support low bitrate mp3\n"
785             "    -t              disable writing LAME Tag\n"
786             "    -T              enable and force writing LAME Tag\n");
787 
788     wait_for(fp, lessmode);
789     DEV_HELP(
790         help_developer_switches(fp);
791         wait_for(fp, lessmode);
792             )
793 
794     fprintf(fp,
795             "  MP3 header/stream options:\n"
796             "    -e <emp>        de-emphasis n/5/c  (obsolete)\n"
797             "    -c              mark as copyright\n"
798             "    -o              mark as non-original\n"
799             "    -p              error protection.  adds 16 bit checksum to every frame\n"
800             "                    (the checksum is computed correctly)\n"
801             "    --nores         disable the bit reservoir\n"
802             "    --strictly-enforce-ISO   comply as much as possible to ISO MPEG spec\n");
803     fprintf(fp,
804             "    --buffer-constraint <constraint> available values for constraint:\n"
805             "                                     default, strict, maximum\n"
806             "\n"
807             );
808     fprintf(fp,
809             "  Filter options:\n"
810             "  --lowpass <freq>        frequency(kHz), lowpass filter cutoff above freq\n"
811             "  --lowpass-width <freq>  frequency(kHz) - default 15%% of lowpass freq\n"
812             "  --highpass <freq>       frequency(kHz), highpass filter cutoff below freq\n"
813             "  --highpass-width <freq> frequency(kHz) - default 15%% of highpass freq\n");
814     fprintf(fp,
815             "  --resample <sfreq>  sampling frequency of output file(kHz)- default=automatic\n");
816 
817     wait_for(fp, lessmode);
818     help_id3tag(fp);
819     fprintf(fp,
820 #if defined(WIN32)
821             "\n\nMS-Windows-specific options:\n"
822             "    --priority <type>  sets the process priority:\n"
823             "                         0,1 = Low priority (IDLE_PRIORITY_CLASS)\n"
824             "                         2 = normal priority (NORMAL_PRIORITY_CLASS, default)\n"
825             "                         3,4 = High priority (HIGH_PRIORITY_CLASS))\n"
826             "    Note: Calling '--priority' without a parameter will select priority 0.\n"
827 #endif
828 #if defined(__OS2__)
829             "\n\nOS/2-specific options:\n"
830             "    --priority <type>  sets the process priority:\n"
831             "                         0 = Low priority (IDLE, delta = 0)\n"
832             "                         1 = Medium priority (IDLE, delta = +31)\n"
833             "                         2 = Regular priority (REGULAR, delta = -31)\n"
834             "                         3 = High priority (REGULAR, delta = 0)\n"
835             "                         4 = Maximum priority (REGULAR, delta = +31)\n"
836             "    Note: Calling '--priority' without a parameter will select priority 0.\n"
837 #endif
838             "\nMisc:\n    --license       print License information\n\n"
839         );
840 
841 #if defined(HAVE_NASM)
842     wait_for(fp, lessmode);
843     fprintf(fp,
844             "  Platform specific:\n"
845             "    --noasm <instructions> disable assembly optimizations for mmx/3dnow/sse\n");
846     wait_for(fp, lessmode);
847 #endif
848 
849     display_bitrates(fp);
850 
851     return 0;
852 }
853 
854 static void
display_bitrate(FILE * const fp,const char * const version,const int d,const int indx)855 display_bitrate(FILE * const fp, const char *const version, const int d, const int indx)
856 {
857     int     i;
858     int nBitrates = 14;
859     if (d == 4)
860         nBitrates = 8;
861 
862 
863     fprintf(fp,
864             "\nMPEG-%-3s layer III sample frequencies (kHz):  %2d  %2d  %g\n"
865             "bitrates (kbps):", version, 32 / d, 48 / d, 44.1 / d);
866     for (i = 1; i <= nBitrates; i++)
867         fprintf(fp, " %2i", lame_get_bitrate(indx, i));
868     fprintf(fp, "\n");
869 }
870 
871 int
display_bitrates(FILE * const fp)872 display_bitrates(FILE * const fp)
873 {
874     display_bitrate(fp, "1", 1, 1);
875     display_bitrate(fp, "2", 2, 0);
876     display_bitrate(fp, "2.5", 4, 0);
877     fprintf(fp, "\n");
878     fflush(fp);
879     return 0;
880 }
881 
882 
883 /*  note: for presets it would be better to externalize them in a file.
884     suggestion:  lame --preset <file-name> ...
885             or:  lame --preset my-setting  ... and my-setting is defined in lame.ini
886  */
887 
888 /*
889 Note from GB on 08/25/2002:
890 I am merging --presets and --alt-presets. Old presets are now aliases for
891 corresponding abr values from old alt-presets. This way we now have a
892 unified preset system, and I hope than more people will use the new tuned
893 presets instead of the old unmaintained ones.
894 */
895 
896 
897 
898 /************************************************************************
899 *
900 * usage
901 *
902 * PURPOSE:  Writes presetting info to #stdout#
903 *
904 ************************************************************************/
905 
906 
907 static void
presets_longinfo_dm(FILE * msgfp)908 presets_longinfo_dm(FILE * msgfp)
909 {
910     fprintf(msgfp,
911             "\n"
912             "The --preset switches are aliases over LAME settings.\n"
913             "\n" "\n");
914     fprintf(msgfp,
915             "To activate these presets:\n"
916             "\n" "   For VBR modes (generally highest quality):\n" "\n");
917     fprintf(msgfp,
918             "     --preset medium      This preset should provide near transparency to most\n"
919             "                          people on most music.\n"
920             "\n"
921             "     --preset standard    This preset should generally be transparent to most\n"
922             "                          people on most music and is already quite high\n"
923             "                          in quality.\n" "\n");
924     fprintf(msgfp,
925             "     --preset extreme     If you have extremely good hearing and similar\n"
926             "                          equipment, this preset will generally provide\n"
927             "                          slightly higher quality than the \"standard\" mode.\n" "\n");
928     fprintf(msgfp,
929             "   For CBR 320kbps (highest quality possible from the --preset switches):\n"
930             "\n"
931             "     --preset insane      This preset will usually be overkill for most people\n"
932             "                          and most situations, but if you must have the\n"
933             "                          absolute highest quality with no regard to filesize,\n"
934             "                          this is the way to go.\n" "\n");
935     fprintf(msgfp,
936             "   For ABR modes (high quality per given bitrate but not as high as VBR):\n"
937             "\n"
938             "     --preset <kbps>      Using this preset will usually give you good quality\n"
939             "                          at a specified bitrate. Depending on the bitrate\n"
940             "                          entered, this preset will determine the optimal\n"
941             "                          settings for that particular situation. For example:\n"
942             "                          \"--preset 185\" activates this preset and uses 185\n"
943             "                          as an average kbps.\n" "\n");
944     fprintf(msgfp,
945             "   \"cbr\"  - If you use the ABR mode (read above) with a significant\n"
946             "            bitrate such as 80, 96, 112, 128, 160, 192, 224, 256, 320,\n"
947             "            you can use the \"cbr\" option to force CBR mode encoding\n"
948             "            instead of the standard abr mode. ABR does provide higher\n"
949             "            quality but CBR may be useful in situations such as when\n"
950             "            streaming an mp3 over the internet may be important.\n" "\n");
951     fprintf(msgfp,
952             "    For example:\n"
953             "\n"
954             "    --preset standard <input file> <output file>\n"
955             " or --preset cbr 192 <input file> <output file>\n"
956             " or --preset 172 <input file> <output file>\n"
957             " or --preset extreme <input file> <output file>\n" "\n" "\n");
958     fprintf(msgfp,
959             "A few aliases are also available for ABR mode:\n"
960             "phone => 16kbps/mono        phon+/lw/mw-eu/sw => 24kbps/mono\n"
961             "mw-us => 40kbps/mono        voice => 56kbps/mono\n"
962             "fm/radio/tape => 112kbps    hifi => 160kbps\n"
963             "cd => 192kbps               studio => 256kbps\n");
964 }
965 
966 
967 static int
presets_set(lame_t gfp,int fast,int cbr,const char * preset_name,const char * ProgramName)968 presets_set(lame_t gfp, int fast, int cbr, const char *preset_name, const char *ProgramName)
969 {
970     int     mono = 0;
971 
972     if ((strcmp(preset_name, "help") == 0) && (fast < 1)
973         && (cbr < 1)) {
974         lame_version_print(stdout);
975         presets_longinfo_dm(stdout);
976         return -1;
977     }
978 
979     /*aliases for compatibility with old presets */
980 
981     if (strcmp(preset_name, "phone") == 0) {
982         preset_name = "16";
983         mono = 1;
984     }
985     if ((strcmp(preset_name, "phon+") == 0) ||
986         (strcmp(preset_name, "lw") == 0) ||
987         (strcmp(preset_name, "mw-eu") == 0) || (strcmp(preset_name, "sw") == 0)) {
988         preset_name = "24";
989         mono = 1;
990     }
991     if (strcmp(preset_name, "mw-us") == 0) {
992         preset_name = "40";
993         mono = 1;
994     }
995     if (strcmp(preset_name, "voice") == 0) {
996         preset_name = "56";
997         mono = 1;
998     }
999     if (strcmp(preset_name, "fm") == 0) {
1000         preset_name = "112";
1001     }
1002     if ((strcmp(preset_name, "radio") == 0) || (strcmp(preset_name, "tape") == 0)) {
1003         preset_name = "112";
1004     }
1005     if (strcmp(preset_name, "hifi") == 0) {
1006         preset_name = "160";
1007     }
1008     if (strcmp(preset_name, "cd") == 0) {
1009         preset_name = "192";
1010     }
1011     if (strcmp(preset_name, "studio") == 0) {
1012         preset_name = "256";
1013     }
1014 
1015     if (strcmp(preset_name, "medium") == 0) {
1016         lame_set_VBR_q(gfp, 4);
1017         lame_set_VBR(gfp, vbr_default);
1018         return 0;
1019     }
1020 
1021     if (strcmp(preset_name, "standard") == 0) {
1022         lame_set_VBR_q(gfp, 2);
1023         lame_set_VBR(gfp, vbr_default);
1024         return 0;
1025     }
1026 
1027     else if (strcmp(preset_name, "extreme") == 0) {
1028         lame_set_VBR_q(gfp, 0);
1029         lame_set_VBR(gfp, vbr_default);
1030         return 0;
1031     }
1032 
1033     else if ((strcmp(preset_name, "insane") == 0) && (fast < 1)) {
1034 
1035         lame_set_preset(gfp, INSANE);
1036 
1037         return 0;
1038     }
1039 
1040     /* Generic ABR Preset */
1041     if (((atoi(preset_name)) > 0) && (fast < 1)) {
1042         if ((atoi(preset_name)) >= 8 && (atoi(preset_name)) <= 320) {
1043             lame_set_preset(gfp, atoi(preset_name));
1044 
1045             if (cbr == 1)
1046                 lame_set_VBR(gfp, vbr_off);
1047 
1048             if (mono == 1) {
1049                 lame_set_mode(gfp, MONO);
1050             }
1051 
1052             return 0;
1053 
1054         }
1055         else {
1056             lame_version_print(Console_IO.Error_fp);
1057             error_printf("Error: The bitrate specified is out of the valid range for this preset\n"
1058                          "\n"
1059                          "When using this mode you must enter a value between \"32\" and \"320\"\n"
1060                          "\n" "For further information try: \"%s --preset help\"\n", ProgramName);
1061             return -1;
1062         }
1063     }
1064 
1065     lame_version_print(Console_IO.Error_fp);
1066     error_printf("Error: You did not enter a valid profile and/or options with --preset\n"
1067                  "\n"
1068                  "Available profiles are:\n"
1069                  "\n"
1070                  "                 medium\n"
1071                  "                 standard\n"
1072                  "                 extreme\n"
1073                  "                 insane\n"
1074                  "          <cbr> (ABR Mode) - The ABR Mode is implied. To use it,\n"
1075                  "                             simply specify a bitrate. For example:\n"
1076                  "                             \"--preset 185\" activates this\n"
1077                  "                             preset and uses 185 as an average kbps.\n" "\n");
1078     error_printf("    Some examples:\n"
1079                  "\n"
1080                  " or \"%s --preset standard <input file> <output file>\"\n"
1081                  " or \"%s --preset cbr 192 <input file> <output file>\"\n"
1082                  " or \"%s --preset 172 <input file> <output file>\"\n"
1083                  " or \"%s --preset extreme <input file> <output file>\"\n"
1084                  "\n"
1085                  "For further information try: \"%s --preset help\"\n", ProgramName, ProgramName,
1086                  ProgramName, ProgramName, ProgramName);
1087     return -1;
1088 }
1089 
1090 static void
genre_list_handler(int num,const char * name,void * cookie)1091 genre_list_handler(int num, const char *name, void *cookie)
1092 {
1093     (void) cookie;
1094     console_printf("%3d %s\n", num, name);
1095 }
1096 
1097 
1098 /************************************************************************
1099 *
1100 * parse_args
1101 *
1102 * PURPOSE:  Sets encoding parameters to the specifications of the
1103 * command line.  Default settings are used for parameters
1104 * not specified in the command line.
1105 *
1106 * If the input file is in WAVE or AIFF format, the sampling frequency is read
1107 * from the AIFF header.
1108 *
1109 * The input and output filenames are read into #inpath# and #outpath#.
1110 *
1111 ************************************************************************/
1112 
1113 /* would use real "strcasecmp" but it isn't portable */
1114 static int
local_strcasecmp(const char * s1,const char * s2)1115 local_strcasecmp(const char *s1, const char *s2)
1116 {
1117     unsigned char c1;
1118     unsigned char c2;
1119 
1120     do {
1121         c1 = (unsigned char) tolower(*s1);
1122         c2 = (unsigned char) tolower(*s2);
1123         if (!c1) {
1124             break;
1125         }
1126         ++s1;
1127         ++s2;
1128     } while (c1 == c2);
1129     return c1 - c2;
1130 }
1131 
1132 static int
local_strncasecmp(const char * s1,const char * s2,int n)1133 local_strncasecmp(const char *s1, const char *s2, int n)
1134 {
1135     unsigned char c1 = 0;
1136     unsigned char c2 = 0;
1137     int     cnt = 0;
1138 
1139     do {
1140         if (cnt == n) {
1141             break;
1142         }
1143         c1 = (unsigned char) tolower(*s1);
1144         c2 = (unsigned char) tolower(*s2);
1145         if (!c1) {
1146             break;
1147         }
1148         ++s1;
1149         ++s2;
1150         ++cnt;
1151     } while (c1 == c2);
1152     return c1 - c2;
1153 }
1154 
1155 
1156 
1157 /* LAME is a simple frontend which just uses the file extension */
1158 /* to determine the file type.  Trying to analyze the file */
1159 /* contents is well beyond the scope of LAME and should not be added. */
1160 static int
filename_to_type(const char * FileName)1161 filename_to_type(const char *FileName)
1162 {
1163     size_t  len = strlen(FileName);
1164 
1165     if (len < 4)
1166         return sf_unknown;
1167 
1168     FileName += len - 4;
1169     if (0 == local_strcasecmp(FileName, ".mpg"))
1170         return sf_mp123;
1171     if (0 == local_strcasecmp(FileName, ".mp1"))
1172         return sf_mp123;
1173     if (0 == local_strcasecmp(FileName, ".mp2"))
1174         return sf_mp123;
1175     if (0 == local_strcasecmp(FileName, ".mp3"))
1176         return sf_mp123;
1177     if (0 == local_strcasecmp(FileName, ".wav"))
1178         return sf_wave;
1179     if (0 == local_strcasecmp(FileName, ".aif"))
1180         return sf_aiff;
1181     if (0 == local_strcasecmp(FileName, ".raw"))
1182         return sf_raw;
1183     if (0 == local_strcasecmp(FileName, ".ogg"))
1184         return sf_ogg;
1185     return sf_unknown;
1186 }
1187 
1188 static int
resample_rate(double freq)1189 resample_rate(double freq)
1190 {
1191     if (freq >= 1.e3)
1192         freq *= 1.e-3;
1193 
1194     switch ((int) freq) {
1195     case 8:
1196         return 8000;
1197     case 11:
1198         return 11025;
1199     case 12:
1200         return 12000;
1201     case 16:
1202         return 16000;
1203     case 22:
1204         return 22050;
1205     case 24:
1206         return 24000;
1207     case 32:
1208         return 32000;
1209     case 44:
1210         return 44100;
1211     case 48:
1212         return 48000;
1213     default:
1214         error_printf("Illegal resample frequency: %.3f kHz\n", freq);
1215         return 0;
1216     }
1217 }
1218 
1219 #ifdef _WIN32
1220 #define SLASH '\\'
1221 #define COLON ':'
1222 #elif __OS2__
1223 #define SLASH '\\'
1224 #else
1225 #define SLASH '/'
1226 #endif
1227 
1228 static
scanPath(char const * s,char const ** a,char const ** b)1229 size_t scanPath(char const* s, char const** a, char const** b)
1230 {
1231     char const* s1 = s;
1232     char const* s2 = s;
1233     if (s != 0) {
1234         for (; *s; ++s) {
1235             switch (*s) {
1236             case SLASH:
1237 #ifdef _WIN32
1238             case COLON:
1239 #endif
1240                 s2 = s;
1241                 break;
1242             }
1243         }
1244 #ifdef _WIN32
1245         if (*s2 == COLON) {
1246             ++s2;
1247         }
1248 #endif
1249     }
1250     if (a) {
1251         *a = s1;
1252     }
1253     if (b) {
1254         *b = s2;
1255     }
1256     return s2-s1;
1257 }
1258 
1259 static
scanBasename(char const * s,char const ** a,char const ** b)1260 size_t scanBasename(char const* s, char const** a, char const** b)
1261 {
1262     char const* s1 = s;
1263     char const* s2 = s;
1264     if (s != 0) {
1265         for (; *s; ++s) {
1266             switch (*s) {
1267             case SLASH:
1268 #ifdef _WIN32
1269             case COLON:
1270 #endif
1271                 s1 = s2 = s;
1272                 break;
1273             case '.':
1274                 s2 = s;
1275                 break;
1276             }
1277         }
1278         if (s2 == s1) {
1279             s2 = s;
1280         }
1281         if (*s1 == SLASH
1282 #ifdef _WIN32
1283           || *s1 == COLON
1284 #endif
1285            ) {
1286             ++s1;
1287         }
1288     }
1289     if (a != 0) {
1290         *a = s1;
1291     }
1292     if (b != 0) {
1293         *b = s2;
1294     }
1295     return s2-s1;
1296 }
1297 
1298 static
isCommonSuffix(char const * s_ext)1299 int isCommonSuffix(char const* s_ext)
1300 {
1301     char const* suffixes[] =
1302     { ".WAV", ".RAW", ".MP1", ".MP2"
1303     , ".MP3", ".MPG", ".MPA", ".CDA"
1304     , ".OGG", ".AIF", ".AIFF", ".AU"
1305     , ".SND", ".FLAC", ".WV", ".OFR"
1306     , ".TAK", ".MP4", ".M4A", ".PCM"
1307     , ".W64"
1308     };
1309     size_t i;
1310     for (i = 0; i < dimension_of(suffixes); ++i) {
1311         if (local_strcasecmp(s_ext, suffixes[i]) == 0) {
1312             return 1;
1313         }
1314     }
1315     return 0;
1316 }
1317 
1318 
generateOutPath(char const * inPath,char const * outDir,char const * s_ext,char * outPath)1319 int generateOutPath(char const* inPath, char const* outDir, char const* s_ext, char* outPath)
1320 {
1321     size_t const max_path = PATH_MAX;
1322 #if 1
1323     size_t i = 0;
1324     int out_dir_used = 0;
1325 
1326     if (outDir != 0 && outDir[0] != 0) {
1327         out_dir_used = 1;
1328         while (*outDir) {
1329             outPath[i++] = *outDir++;
1330             if (i >= max_path) {
1331                 goto err_generateOutPath;
1332             }
1333         }
1334         if (i > 0 && outPath[i-1] != SLASH) {
1335             outPath[i++] = SLASH;
1336             if (i >= max_path) {
1337                 goto err_generateOutPath;
1338             }
1339         }
1340         outPath[i] = 0;
1341     }
1342     else {
1343         char const* pa;
1344         char const* pb;
1345         size_t j, n = scanPath(inPath, &pa, &pb);
1346         if (i+n >= max_path) {
1347             goto err_generateOutPath;
1348         }
1349         for (j = 0; j < n; ++j) {
1350             outPath[i++] = pa[j];
1351         }
1352         if (n > 0) {
1353             outPath[i++] = SLASH;
1354             if (i >= max_path) {
1355                 goto err_generateOutPath;
1356             }
1357         }
1358         outPath[i] = 0;
1359     }
1360     {
1361         int replace_suffix = 0;
1362         char const* na;
1363         char const* nb;
1364         size_t j, n = scanBasename(inPath, &na, &nb);
1365         if (i+n >= max_path) {
1366             goto err_generateOutPath;
1367         }
1368         for (j = 0; j < n; ++j) {
1369             outPath[i++] = na[j];
1370         }
1371         outPath[i] = 0;
1372         if (isCommonSuffix(nb) == 1) {
1373             replace_suffix = 1;
1374             if (out_dir_used == 0) {
1375                 if (local_strcasecmp(nb, s_ext) == 0) {
1376                     replace_suffix = 0;
1377                 }
1378             }
1379         }
1380         if (replace_suffix == 0) {
1381             while (*nb) {
1382                 outPath[i++] = *nb++;
1383                 if (i >= max_path) {
1384                     goto err_generateOutPath;
1385                 }
1386             }
1387             outPath[i] = 0;
1388         }
1389     }
1390     if (i+5 >= max_path) {
1391         goto err_generateOutPath;
1392     }
1393     while (*s_ext) {
1394         outPath[i++] = *s_ext++;
1395     }
1396     outPath[i] = 0;
1397     return 0;
1398 err_generateOutPath:
1399     error_printf( "error: output file name too long\n" );
1400     return 1;
1401 #else
1402     strncpy(outPath, inPath, PATH_MAX + 1 - 4);
1403     strncat(outPath, s_ext, 4);
1404     return 0;
1405 #endif
1406 }
1407 
1408 
1409 static int
set_id3_albumart(lame_t gfp,char const * file_name)1410 set_id3_albumart(lame_t gfp, char const* file_name)
1411 {
1412     int ret = -1;
1413     FILE *fpi = 0;
1414     char *albumart = 0;
1415 
1416     if (file_name == 0) {
1417         return 0;
1418     }
1419     fpi = lame_fopen(file_name, "rb");
1420     if (!fpi) {
1421         ret = 1;
1422     }
1423     else {
1424         size_t size;
1425 
1426         fseek(fpi, 0, SEEK_END);
1427         size = ftell(fpi);
1428         fseek(fpi, 0, SEEK_SET);
1429         albumart = (char *)malloc(size);
1430         if (!albumart) {
1431             ret = 2;
1432         }
1433         else {
1434             if (fread(albumart, 1, size, fpi) != size) {
1435                 ret = 3;
1436             }
1437             else {
1438                 ret = id3tag_set_albumart(gfp, albumart, size) ? 4 : 0;
1439             }
1440             free(albumart);
1441         }
1442         fclose(fpi);
1443     }
1444     switch (ret) {
1445     case 1: error_printf("Could not find: '%s'.\n", file_name); break;
1446     case 2: error_printf("Insufficient memory for reading the albumart.\n"); break;
1447     case 3: error_printf("Read error: '%s'.\n", file_name); break;
1448     case 4: error_printf("Unsupported image: '%s'.\nSpecify JPEG/PNG/GIF image\n", file_name); break;
1449     default: break;
1450     }
1451     return ret;
1452 }
1453 
1454 
1455 enum ID3TAG_MODE
1456 { ID3TAG_MODE_DEFAULT
1457 , ID3TAG_MODE_V1_ONLY
1458 , ID3TAG_MODE_V2_ONLY
1459 };
1460 
dev_only_with_arg(char const * str,char const * token,char const * nextArg,int * argIgnored,int * argUsed)1461 static int dev_only_with_arg(char const* str, char const* token, char const* nextArg, int* argIgnored, int* argUsed)
1462 {
1463     if (0 != local_strcasecmp(token,str)) return 0;
1464     *argUsed = 1;
1465     if (internal_opts_enabled) return 1;
1466     *argIgnored = 1;
1467     error_printf("WARNING: ignoring developer-only switch --%s %s\n", token, nextArg);
1468     return 0;
1469 }
1470 
dev_only_without_arg(char const * str,char const * token,int * argIgnored)1471 static int dev_only_without_arg(char const* str, char const* token, int* argIgnored)
1472 {
1473     if (0 != local_strcasecmp(token,str)) return 0;
1474     if (internal_opts_enabled) return 1;
1475     *argIgnored = 1;
1476     error_printf("WARNING: ignoring developer-only switch --%s\n", token);
1477     return 0;
1478 }
1479 
1480 /* Ugly, NOT final version */
1481 
1482 #define T_IF(str)          if ( 0 == local_strcasecmp (token,str) ) {
1483 #define T_ELIF(str)        } else if ( 0 == local_strcasecmp (token,str) ) {
1484 #define T_ELIF2(str1,str2) } else if ( 0 == local_strcasecmp (token,str1)  ||  0 == local_strcasecmp (token,str2) ) {
1485 #define T_ELSE             } else {
1486 #define T_END              }
1487 
1488 #define T_ELIF_INTERNAL(str) \
1489                            } else if (dev_only_without_arg(str,token,&argIgnored)) {
1490 
1491 #define T_ELIF_INTERNAL_WITH_ARG(str) \
1492                            } else if (dev_only_with_arg(str,token,nextArg,&argIgnored,&argUsed)) {
1493 
1494 
1495 static int
parse_args_(lame_global_flags * gfp,int argc,char ** argv,char * const inPath,char * const outPath,char ** nogap_inPath,int * num_nogap)1496 parse_args_(lame_global_flags * gfp, int argc, char **argv,
1497            char *const inPath, char *const outPath, char **nogap_inPath, int *num_nogap)
1498 {
1499     char    outDir[PATH_MAX+1] = "";
1500     int     input_file = 0;  /* set to 1 if we parse an input file name  */
1501     int     i;
1502     int     autoconvert = 0;
1503     int     nogap = 0;
1504     int     nogap_tags = 0;  /* set to 1 to use VBR tags in NOGAP mode */
1505     const char *ProgramName = argv[0];
1506     int     count_nogap = 0;
1507     int     noreplaygain = 0; /* is RG explicitly disabled by the user */
1508     int     id3tag_mode = ID3TAG_MODE_DEFAULT;
1509     int     ignore_tag_errors = 0;  /* Ignore errors in values passed for tags */
1510 #ifdef ID3TAGS_EXTENDED
1511     enum TextEncoding id3_tenc = TENC_UTF16;
1512 #else
1513     enum TextEncoding id3_tenc = TENC_LATIN1;
1514 #endif
1515 
1516 #ifdef HAVE_ICONV
1517     setlocale(LC_CTYPE, "");
1518 #endif
1519     inPath[0] = '\0';
1520     outPath[0] = '\0';
1521     /* turn on display options. user settings may turn them off below */
1522     global_ui_config.silent = 0; /* default */
1523     global_ui_config.brhist = 1;
1524     global_decoder.mp3_delay = 0;
1525     global_decoder.mp3_delay_set = 0;
1526     global_decoder.disable_wav_header = 0;
1527     global_ui_config.print_clipping_info = 0;
1528     id3tag_init(gfp);
1529 
1530     /* process args */
1531     for (i = 0; ++i < argc;) {
1532         char    c;
1533         char   *token;
1534         char   *arg;
1535         char   *nextArg;
1536         int     argUsed;
1537         int     argIgnored=0;
1538 
1539         token = argv[i];
1540         if (*token++ == '-') {
1541             argUsed = 0;
1542             nextArg = i + 1 < argc ? argv[i + 1] : "";
1543 
1544             if (!*token) { /* The user wants to use stdin and/or stdout. */
1545                 input_file = 1;
1546                 if (inPath[0] == '\0')
1547                     strncpy(inPath, argv[i], PATH_MAX + 1);
1548                 else if (outPath[0] == '\0')
1549                     strncpy(outPath, argv[i], PATH_MAX + 1);
1550             }
1551             if (*token == '-') { /* GNU style */
1552                 double  double_value = 0;
1553                 int     int_value = 0;
1554                 token++;
1555 
1556                 T_IF("resample")
1557                     argUsed = getDoubleValue(token, nextArg, &double_value);
1558                     if (argUsed)
1559                         (void) lame_set_out_samplerate(gfp, resample_rate(double_value));
1560 
1561                 T_ELIF("vbr-old")
1562                     lame_set_VBR(gfp, vbr_rh);
1563 
1564                 T_ELIF("vbr-new")
1565                     lame_set_VBR(gfp, vbr_mt);
1566 
1567                 T_ELIF("vbr-mtrh")
1568                     lame_set_VBR(gfp, vbr_mtrh);
1569 
1570                 T_ELIF("cbr")
1571                     lame_set_VBR(gfp, vbr_off);
1572 
1573                 T_ELIF("abr")
1574                     /* values larger than 8000 are bps (like Fraunhofer), so it's strange to get 320000 bps MP3 when specifying 8000 bps MP3 */
1575                     argUsed = getIntValue(token, nextArg, &int_value);
1576                     if (argUsed) {
1577                         if (int_value >= 8000) {
1578                             int_value = (int_value + 500) / 1000;
1579                         }
1580                         if (int_value > 320) {
1581                             int_value = 320;
1582                         }
1583                         if (int_value < 8) {
1584                             int_value = 8;
1585                         }
1586                         lame_set_VBR(gfp, vbr_abr);
1587                         lame_set_VBR_mean_bitrate_kbps(gfp, int_value);
1588                     }
1589 
1590                 T_ELIF("r3mix")
1591                     lame_set_preset(gfp, R3MIX);
1592 
1593                 T_ELIF("bitwidth")
1594                     argUsed = getIntValue(token, nextArg, &int_value);
1595                     if (argUsed)
1596                         global_raw_pcm.in_bitwidth = int_value;
1597 
1598                 T_ELIF("signed")
1599                     global_raw_pcm.in_signed = 1;
1600 
1601                 T_ELIF("unsigned")
1602                     global_raw_pcm.in_signed = 0;
1603 
1604                 T_ELIF("little-endian")
1605                     global_raw_pcm.in_endian = ByteOrderLittleEndian;
1606 
1607                 T_ELIF("big-endian")
1608                     global_raw_pcm.in_endian = ByteOrderBigEndian;
1609 
1610                 T_ELIF("mp1input")
1611                     global_reader.input_format = sf_mp1;
1612 
1613                 T_ELIF("mp2input")
1614                     global_reader.input_format = sf_mp2;
1615 
1616                 T_ELIF("mp3input")
1617                     global_reader.input_format = sf_mp3;
1618 
1619                 T_ELIF("ogginput")
1620                     error_printf("sorry, vorbis support in LAME is deprecated.\n");
1621                 return -1;
1622 
1623                 T_ELIF("decode")
1624                     (void) lame_set_decode_only(gfp, 1);
1625 
1626                 T_ELIF("flush")
1627                     global_writer.flush_write = 1;
1628 
1629                 T_ELIF("decode-mp3delay")
1630                     argUsed = getIntValue(token, nextArg, &int_value);
1631                     if (argUsed) {
1632                         global_decoder.mp3_delay = int_value;
1633                         global_decoder.mp3_delay_set = 1;
1634                     }
1635 
1636                 T_ELIF("nores")
1637                     lame_set_disable_reservoir(gfp, 1);
1638 
1639                 T_ELIF("strictly-enforce-ISO")
1640                     lame_set_strict_ISO(gfp, MDB_STRICT_ISO);
1641 
1642                 T_ELIF("buffer-constraint")
1643                   argUsed = 1;
1644                 if (strcmp(nextArg, "default") == 0)
1645                   (void) lame_set_strict_ISO(gfp, MDB_DEFAULT);
1646                 else if (strcmp(nextArg, "strict") == 0)
1647                   (void) lame_set_strict_ISO(gfp, MDB_STRICT_ISO);
1648                 else if (strcmp(nextArg, "maximum") == 0)
1649                   (void) lame_set_strict_ISO(gfp, MDB_MAXIMUM);
1650                 else {
1651                     error_printf("unknown buffer constraint '%s'\n", nextArg);
1652                     return -1;
1653                 }
1654 
1655                 T_ELIF("scale")
1656                     argUsed = getDoubleValue(token, nextArg, &double_value);
1657                     if (argUsed)
1658                         (void) lame_set_scale(gfp, (float) double_value);
1659 
1660                 T_ELIF("scale-l")
1661                     argUsed = getDoubleValue(token, nextArg, &double_value);
1662                     if (argUsed)
1663                         (void) lame_set_scale_left(gfp, (float) double_value);
1664 
1665                 T_ELIF("scale-r")
1666                     argUsed = getDoubleValue(token, nextArg, &double_value);
1667                     if (argUsed)
1668                         (void) lame_set_scale_right(gfp, (float) double_value);
1669 
1670                 T_ELIF("gain")
1671                     argUsed = getDoubleValue(token, nextArg, &double_value);
1672                     if (argUsed) {
1673                         double gain = double_value;
1674                         gain = gain > -20.f ? gain : -20.f;
1675                         gain = gain < 12.f ? gain : 12.f;
1676                         gain = pow(10.f, gain*0.05);
1677                         (void) lame_set_scale(gfp, (float) gain);
1678                     }
1679 
1680                 T_ELIF("noasm")
1681                     argUsed = 1;
1682                 if (!strcmp(nextArg, "mmx"))
1683                     (void) lame_set_asm_optimizations(gfp, MMX, 0);
1684                 if (!strcmp(nextArg, "3dnow"))
1685                     (void) lame_set_asm_optimizations(gfp, AMD_3DNOW, 0);
1686                 if (!strcmp(nextArg, "sse"))
1687                     (void) lame_set_asm_optimizations(gfp, SSE, 0);
1688 
1689                 T_ELIF("freeformat")
1690                     lame_set_free_format(gfp, 1);
1691 
1692                 T_ELIF("replaygain-fast")
1693                     lame_set_findReplayGain(gfp, 1);
1694 
1695 #ifdef DECODE_ON_THE_FLY
1696                 T_ELIF("replaygain-accurate")
1697                     lame_set_decode_on_the_fly(gfp, 1);
1698                 lame_set_findReplayGain(gfp, 1);
1699 #endif
1700 
1701                 T_ELIF("noreplaygain")
1702                     noreplaygain = 1;
1703                 lame_set_findReplayGain(gfp, 0);
1704 
1705 
1706 #ifdef DECODE_ON_THE_FLY
1707                 T_ELIF("clipdetect")
1708                     global_ui_config.print_clipping_info = 1;
1709                     lame_set_decode_on_the_fly(gfp, 1);
1710 #endif
1711 
1712                 T_ELIF("nohist")
1713                     global_ui_config.brhist = 0;
1714 
1715 #if defined(__OS2__) || defined(WIN32)
1716                 T_ELIF("priority")
1717                     argUsed = getIntValue(token, nextArg, &int_value);
1718                     if (argUsed)
1719                         setProcessPriority(int_value);
1720 #endif
1721 
1722                 /* options for ID3 tag */
1723 #ifdef ID3TAGS_EXTENDED
1724                 T_ELIF2("id3v2-utf16","id3v2-ucs2") /* id3v2-ucs2 for compatibility only */
1725                     id3_tenc = TENC_UTF16;
1726                     id3tag_add_v2(gfp);
1727 
1728                 T_ELIF("id3v2-latin1")
1729                     id3_tenc = TENC_LATIN1;
1730                     id3tag_add_v2(gfp);
1731 #endif
1732 
1733                 T_ELIF("tt")
1734                     argUsed = 1;
1735                     id3_tag(gfp, 't', id3_tenc, nextArg);
1736 
1737                 T_ELIF("ta")
1738                     argUsed = 1;
1739                     id3_tag(gfp, 'a', id3_tenc, nextArg);
1740 
1741                 T_ELIF("tl")
1742                     argUsed = 1;
1743                     id3_tag(gfp, 'l', id3_tenc, nextArg);
1744 
1745                 T_ELIF("ty")
1746                     argUsed = 1;
1747                     id3_tag(gfp, 'y', id3_tenc, nextArg);
1748 
1749                 T_ELIF("tc")
1750                     argUsed = 1;
1751                     id3_tag(gfp, 'c', id3_tenc, nextArg);
1752 
1753                 T_ELIF("tn")
1754                     int ret = id3_tag(gfp, 'n', id3_tenc, nextArg);
1755                     argUsed = 1;
1756                     if (ret != 0) {
1757                         if (0 == ignore_tag_errors) {
1758                             if (id3tag_mode == ID3TAG_MODE_V1_ONLY) {
1759                                 if (global_ui_config.silent < 9) {
1760                                     error_printf("The track number has to be between 1 and 255 for ID3v1.\n");
1761                                 }
1762                                 return -1;
1763                             }
1764                             else if (id3tag_mode == ID3TAG_MODE_V2_ONLY) {
1765                                 /* track will be stored as-is in ID3v2 case, so no problem here */
1766                             }
1767                             else {
1768                                 if (global_ui_config.silent < 9) {
1769                                     error_printf("The track number has to be between 1 and 255 for ID3v1, ignored for ID3v1.\n");
1770                                 }
1771                             }
1772                         }
1773                     }
1774 
1775                 T_ELIF("tg")
1776                     int ret = 0;
1777                     argUsed = 1;
1778                     if (nextArg != 0 && strlen(nextArg) > 0) {
1779                         ret = id3_tag(gfp, 'g', id3_tenc, nextArg);
1780                     }
1781                     if (ret != 0) {
1782                         if (0 == ignore_tag_errors) {
1783                             if (ret == -1) {
1784                                 error_printf("Unknown ID3v1 genre number: '%s'.\n", nextArg);
1785                                 return -1;
1786                             }
1787                             else if (ret == -2) {
1788                                 if (id3tag_mode == ID3TAG_MODE_V1_ONLY) {
1789                                     error_printf("Unknown ID3v1 genre: '%s'.\n", nextArg);
1790                                     return -1;
1791                                 }
1792                                 else if (id3tag_mode == ID3TAG_MODE_V2_ONLY) {
1793                                     /* genre will be stored as-is in ID3v2 case, so no problem here */
1794                                 }
1795                                 else {
1796                                     if (global_ui_config.silent < 9) {
1797                                         error_printf("Unknown ID3v1 genre: '%s'.  Setting ID3v1 genre to 'Other'\n", nextArg);
1798                                     }
1799                                 }
1800                             }
1801                             else {
1802                                 if (global_ui_config.silent < 10)
1803                                     error_printf("Internal error.\n");
1804                                 return -1;
1805                             }
1806                         }
1807                     }
1808 
1809                 T_ELIF("tv")
1810                     argUsed = 1;
1811                     if (id3_tag(gfp, 'v', id3_tenc, nextArg)) {
1812                         if (global_ui_config.silent < 9) {
1813                             error_printf("Invalid field value: '%s'. Ignored\n", nextArg);
1814                         }
1815                     }
1816 
1817                 T_ELIF("ti")
1818                     argUsed = 1;
1819                     if (set_id3_albumart(gfp, nextArg) != 0) {
1820                         if (! ignore_tag_errors) {
1821                             return -1;
1822                         }
1823                     }
1824 
1825                 T_ELIF("ignore-tag-errors")
1826                     ignore_tag_errors = 1;
1827 
1828                 T_ELIF("add-id3v2")
1829                     id3tag_add_v2(gfp);
1830 
1831                 T_ELIF("id3v1-only")
1832                     id3tag_v1_only(gfp);
1833                     id3tag_mode = ID3TAG_MODE_V1_ONLY;
1834 
1835                 T_ELIF("id3v2-only")
1836                     id3tag_v2_only(gfp);
1837                     id3tag_mode = ID3TAG_MODE_V2_ONLY;
1838 
1839                 T_ELIF("space-id3v1")
1840                     id3tag_space_v1(gfp);
1841 
1842                 T_ELIF("pad-id3v2")
1843                     id3tag_pad_v2(gfp);
1844 
1845                 T_ELIF("pad-id3v2-size")
1846                     argUsed = getIntValue(token, nextArg, &int_value);
1847                     if (argUsed) {
1848                         int_value = int_value <= 128000 ? int_value : 128000;
1849                         int_value = int_value >= 0      ? int_value : 0;
1850                         id3tag_set_pad(gfp, int_value);
1851                     }
1852 
1853                 T_ELIF("genre-list")
1854                     id3tag_genre_list(genre_list_handler, NULL);
1855                     return -2;
1856 
1857 
1858                 T_ELIF("lowpass")
1859                     argUsed = getDoubleValue(token, nextArg, &double_value);
1860                     if (argUsed) {
1861                         if (double_value < 0) {
1862                             lame_set_lowpassfreq(gfp, -1);
1863                         }
1864                         else {
1865                             /* useful are 0.001 kHz...50 kHz, 50 Hz...50000 Hz */
1866                             if (double_value < 0.001 || double_value > 50000.) {
1867                                 error_printf("Must specify lowpass with --lowpass freq, freq >= 0.001 kHz\n");
1868                                 return -1;
1869                             }
1870                             lame_set_lowpassfreq(gfp, (int) (double_value * (double_value < 50. ? 1.e3 : 1.e0) + 0.5));
1871                         }
1872                     }
1873 
1874                 T_ELIF("lowpass-width")
1875                     argUsed = getDoubleValue(token, nextArg, &double_value);
1876                     if (argUsed) {
1877                         /* useful are 0.001 kHz...16 kHz, 16 Hz...50000 Hz */
1878                         if (double_value < 0.001 || double_value > 50000.) {
1879                             error_printf
1880                                 ("Must specify lowpass width with --lowpass-width freq, freq >= 0.001 kHz\n");
1881                             return -1;
1882                         }
1883                         lame_set_lowpasswidth(gfp, (int) (double_value * (double_value < 16. ? 1.e3 : 1.e0) + 0.5));
1884                     }
1885 
1886                 T_ELIF("highpass")
1887                     argUsed = getDoubleValue(token, nextArg, &double_value);
1888                     if (argUsed) {
1889                         if (double_value < 0.0) {
1890                             lame_set_highpassfreq(gfp, -1);
1891                         }
1892                         else {
1893                             /* useful are 0.001 kHz...16 kHz, 16 Hz...50000 Hz */
1894                             if (double_value < 0.001 || double_value > 50000.) {
1895                                 error_printf("Must specify highpass with --highpass freq, freq >= 0.001 kHz\n");
1896                                 return -1;
1897                             }
1898                             lame_set_highpassfreq(gfp, (int) (double_value * (double_value < 16. ? 1.e3 : 1.e0) + 0.5));
1899                         }
1900                     }
1901 
1902                 T_ELIF("highpass-width")
1903                     argUsed = getDoubleValue(token, nextArg, &double_value);
1904                     if (argUsed) {
1905                         /* useful are 0.001 kHz...16 kHz, 16 Hz...50000 Hz */
1906                         if (double_value < 0.001 || double_value > 50000.) {
1907                             error_printf
1908                                 ("Must specify highpass width with --highpass-width freq, freq >= 0.001 kHz\n");
1909                             return -1;
1910                         }
1911                         lame_set_highpasswidth(gfp, (int) double_value);
1912                     }
1913 
1914                 T_ELIF("comp")
1915                     argUsed = getDoubleValue(token, nextArg, &double_value);
1916                     if (argUsed) {
1917                         if (double_value < 1.0) {
1918                             error_printf("Must specify compression ratio >= 1.0\n");
1919                             return -1;
1920                         }
1921                         else {
1922                             lame_set_compression_ratio(gfp, (float) double_value);
1923                         }
1924                     }
1925 
1926                 /* some more GNU-ish options could be added
1927                  * brief         => few messages on screen (name, status report)
1928                  * o/output file => specifies output filename
1929                  * O             => stdout
1930                  * i/input file  => specifies input filename
1931                  * I             => stdin
1932                  */
1933                 T_ELIF("quiet")
1934                     global_ui_config.silent = 10; /* on a scale from 1 to 10 be very silent */
1935 
1936                 T_ELIF("silent")
1937                     global_ui_config.silent = 9;
1938 
1939                 T_ELIF("brief")
1940                     global_ui_config.silent = -5; /* print few info on screen */
1941 
1942                 T_ELIF("verbose")
1943                     global_ui_config.silent = -10; /* print a lot on screen */
1944 
1945                 T_ELIF2("version", "license")
1946                     print_license(stdout);
1947                 return -2;
1948 
1949                 T_ELIF2("help", "usage")
1950                     if (0 == local_strncasecmp(nextArg, "id3", 3)) {
1951                         help_id3tag(stdout);
1952                     }
1953                     else if (0 == local_strncasecmp(nextArg, "dev", 3)) {
1954                         help_developer_switches(stdout);
1955                     }
1956                     else {
1957                         short_help(gfp, stdout, ProgramName);
1958                     }
1959                 return -2;
1960 
1961                 T_ELIF("longhelp")
1962                     long_help(gfp, stdout, ProgramName, 0 /* lessmode=NO */ );
1963                 return -2;
1964 
1965                 T_ELIF("?")
1966 #ifdef __unix__
1967                     FILE   *fp = popen("less -Mqc", "w");
1968                     long_help(gfp, fp, ProgramName, 0 /* lessmode=NO */ );
1969                     pclose(fp);
1970 #else
1971                     long_help(gfp, stdout, ProgramName, 1 /* lessmode=YES */ );
1972 #endif
1973                 return -2;
1974 
1975                 T_ELIF2("preset", "alt-preset")
1976                     argUsed = 1;
1977                 {
1978                     int     fast = 0, cbr = 0;
1979 
1980                     while ((strcmp(nextArg, "fast") == 0) || (strcmp(nextArg, "cbr") == 0)) {
1981 
1982                         if ((strcmp(nextArg, "fast") == 0) && (fast < 1))
1983                             fast = 1;
1984                         if ((strcmp(nextArg, "cbr") == 0) && (cbr < 1))
1985                             cbr = 1;
1986 
1987                         argUsed++;
1988                         nextArg = i + argUsed < argc ? argv[i + argUsed] : "";
1989                     }
1990 
1991                     if (presets_set(gfp, fast, cbr, nextArg, ProgramName) < 0)
1992                         return -1;
1993                 }
1994 
1995                 T_ELIF("disptime")
1996                     argUsed = getDoubleValue(token, nextArg, &double_value);
1997                     if (argUsed)
1998                         global_ui_config.update_interval = (float) double_value;
1999 
2000                 T_ELIF("nogaptags")
2001                     nogap_tags = 1;
2002 
2003                 T_ELIF("nogapout")
2004                     int const arg_n = strnlen(nextArg, PATH_MAX);
2005                     if (arg_n >= PATH_MAX) {
2006                         error_printf("%s: %s argument length (%d) exceeds limit (%d)\n", ProgramName, token, arg_n, PATH_MAX);
2007                         return -1;
2008                     }
2009                     strncpy(outPath, nextArg, PATH_MAX);
2010                     outPath[PATH_MAX] = '\0';
2011                     argUsed = 1;
2012 
2013                 T_ELIF("out-dir")
2014                     int const arg_n = strnlen(nextArg, PATH_MAX);
2015                     if (arg_n >= PATH_MAX) {
2016                         error_printf("%s: %s argument length (%d) exceeds limit (%d)\n", ProgramName, token, arg_n, PATH_MAX);
2017                         return -1;
2018                     }
2019                     strncpy(outDir, nextArg, PATH_MAX);
2020                     outDir[PATH_MAX] = '\0';
2021                     argUsed = 1;
2022 
2023                 T_ELIF("nogap")
2024                     nogap = 1;
2025 
2026                 T_ELIF("swap-channel")
2027                     global_reader.swap_channel = 1;
2028 
2029                 T_ELIF("ignorelength")
2030                     global_reader.ignorewavlength = 1;
2031 
2032                 T_ELIF ("athaa-sensitivity")
2033                     argUsed = getDoubleValue(token, nextArg, &double_value);
2034                     if (argUsed)
2035                         lame_set_athaa_sensitivity(gfp, (float) double_value);
2036 
2037                 /* ---------------- lots of dead switches ---------------- */
2038 
2039                 T_ELIF_INTERNAL("noshort")
2040                     (void) lame_set_no_short_blocks(gfp, 1);
2041 
2042                 T_ELIF_INTERNAL("short")
2043                     (void) lame_set_no_short_blocks(gfp, 0);
2044 
2045                 T_ELIF_INTERNAL("allshort")
2046                     (void) lame_set_force_short_blocks(gfp, 1);
2047 
2048                 T_ELIF_INTERNAL("notemp")
2049                     (void) lame_set_useTemporal(gfp, 0);
2050 
2051                 T_ELIF_INTERNAL_WITH_ARG("interch")
2052                     argUsed = getDoubleValue(token, nextArg, &double_value);
2053                     if (argUsed)
2054                         (void) lame_set_interChRatio(gfp, (float) double_value);
2055 
2056                 T_ELIF_INTERNAL_WITH_ARG("temporal-masking")
2057                     argUsed = getIntValue(token, nextArg, &int_value);
2058                     if (argUsed)
2059                         (void) lame_set_useTemporal(gfp, int_value ? 1 : 0);
2060 
2061                 T_ELIF_INTERNAL("nspsytune")
2062                     ;
2063 
2064                 T_ELIF_INTERNAL("nssafejoint")
2065                     lame_set_exp_nspsytune(gfp, lame_get_exp_nspsytune(gfp) | 2);
2066 
2067                 T_ELIF_INTERNAL_WITH_ARG("nsmsfix")
2068                     argUsed = getDoubleValue(token, nextArg, &double_value);
2069                     if (argUsed)
2070                         (void) lame_set_msfix(gfp, double_value);
2071 
2072                 T_ELIF_INTERNAL_WITH_ARG("ns-bass")
2073                     argUsed = getDoubleValue(token, nextArg, &double_value);
2074                     if (argUsed) {
2075                         int     k = (int) (double_value * 4);
2076                         if (k < -32)
2077                             k = -32;
2078                         if (k > 31)
2079                             k = 31;
2080                         if (k < 0)
2081                             k += 64;
2082                         lame_set_exp_nspsytune(gfp, lame_get_exp_nspsytune(gfp) | (k << 2));
2083                     }
2084 
2085                 T_ELIF_INTERNAL_WITH_ARG("ns-alto")
2086                     argUsed = getDoubleValue(token, nextArg, &double_value);
2087                     if (argUsed) {
2088                         int     k = (int) (double_value * 4);
2089                         if (k < -32)
2090                             k = -32;
2091                         if (k > 31)
2092                             k = 31;
2093                         if (k < 0)
2094                             k += 64;
2095                         lame_set_exp_nspsytune(gfp, lame_get_exp_nspsytune(gfp) | (k << 8));
2096                     }
2097 
2098                 T_ELIF_INTERNAL_WITH_ARG("ns-treble")
2099                     argUsed = getDoubleValue(token, nextArg, &double_value);
2100                     if (argUsed) {
2101                         int     k = (int) (double_value * 4);
2102                         if (k < -32)
2103                             k = -32;
2104                         if (k > 31)
2105                             k = 31;
2106                         if (k < 0)
2107                             k += 64;
2108                         lame_set_exp_nspsytune(gfp, lame_get_exp_nspsytune(gfp) | (k << 14));
2109                     }
2110 
2111                 T_ELIF_INTERNAL_WITH_ARG("ns-sfb21")
2112                     /*  to be compatible with Naoki's original code,
2113                      *  ns-sfb21 specifies how to change ns-treble for sfb21 */
2114                     argUsed = getDoubleValue(token, nextArg, &double_value);
2115                     if (argUsed) {
2116                         int     k = (int) (double_value * 4);
2117                         if (k < -32)
2118                             k = -32;
2119                         if (k > 31)
2120                             k = 31;
2121                         if (k < 0)
2122                             k += 64;
2123                         lame_set_exp_nspsytune(gfp, lame_get_exp_nspsytune(gfp) | (k << 20));
2124                     }
2125 
2126                 T_ELIF_INTERNAL_WITH_ARG("tune") /*without helptext */
2127                     argUsed = getDoubleValue(token, nextArg, &double_value);
2128                     if (argUsed)
2129                         lame_set_tune(gfp, (float) double_value);
2130 
2131                 T_ELIF_INTERNAL_WITH_ARG("shortthreshold")
2132                 {
2133                     float   x, y;
2134                     int     n = sscanf(nextArg, "%f,%f", &x, &y);
2135                     if (n == 1) {
2136                         y = x;
2137                     }
2138                     (void) lame_set_short_threshold(gfp, x, y);
2139                 }
2140                 T_ELIF_INTERNAL_WITH_ARG("maskingadjust") /*without helptext */
2141                     argUsed = getDoubleValue(token, nextArg, &double_value);
2142                     if (argUsed)
2143                         (void) lame_set_maskingadjust(gfp, (float) double_value);
2144 
2145                 T_ELIF_INTERNAL_WITH_ARG("maskingadjustshort") /*without helptext */
2146                     argUsed = getDoubleValue(token, nextArg, &double_value);
2147                     if (argUsed)
2148                         (void) lame_set_maskingadjust_short(gfp, (float) double_value);
2149 
2150                 T_ELIF_INTERNAL_WITH_ARG("athcurve") /*without helptext */
2151                     argUsed = getDoubleValue(token, nextArg, &double_value);
2152                     if (argUsed)
2153                         (void) lame_set_ATHcurve(gfp, (float) double_value);
2154 
2155                 T_ELIF_INTERNAL("no-preset-tune") /*without helptext */
2156                     (void) lame_set_preset_notune(gfp, 0);
2157 
2158                 T_ELIF_INTERNAL_WITH_ARG("substep")
2159                     argUsed = getIntValue(token, nextArg, &int_value);
2160                     if (argUsed)
2161                         (void) lame_set_substep(gfp, int_value);
2162 
2163                 T_ELIF_INTERNAL_WITH_ARG("sbgain") /*without helptext */
2164                     argUsed = getIntValue(token, nextArg, &int_value);
2165                     if (argUsed)
2166                         (void) lame_set_subblock_gain(gfp, int_value);
2167 
2168                 T_ELIF_INTERNAL("sfscale") /*without helptext */
2169                     (void) lame_set_sfscale(gfp, 1);
2170 
2171                 T_ELIF_INTERNAL("noath")
2172                     (void) lame_set_noATH(gfp, 1);
2173 
2174                 T_ELIF_INTERNAL("athonly")
2175                     (void) lame_set_ATHonly(gfp, 1);
2176 
2177                 T_ELIF_INTERNAL("athshort")
2178                     (void) lame_set_ATHshort(gfp, 1);
2179 
2180                 T_ELIF_INTERNAL_WITH_ARG("athlower")
2181                     argUsed = getDoubleValue(token, nextArg, &double_value);
2182                     if (argUsed)
2183                         (void) lame_set_ATHlower(gfp, (float) double_value);
2184 
2185                 T_ELIF_INTERNAL_WITH_ARG("athtype")
2186                     argUsed = getIntValue(token, nextArg, &int_value);
2187                     if (argUsed)
2188                         (void) lame_set_ATHtype(gfp, int_value);
2189 
2190                 T_ELIF_INTERNAL_WITH_ARG("athaa-type") /*  switch for developing, no DOCU */
2191                     /* once was 1:Gaby, 2:Robert, 3:Jon, else:off */
2192                     argUsed = getIntValue(token, nextArg, &int_value);
2193                     if (argUsed)
2194                         (void) lame_set_athaa_type(gfp, int_value); /* now: 0:off else:Jon */
2195 
2196                 T_ELIF_INTERNAL_WITH_ARG("debug-file") /* switch for developing, no DOCU */
2197                     /* file name to print debug info into */
2198                     set_debug_file(nextArg);
2199 
2200                 T_ELSE {
2201                     if (!argIgnored) {
2202                         error_printf("%s: unrecognized option --%s\n", ProgramName, token);
2203                         return -1;
2204                     }
2205                     argIgnored = 0;
2206                 }
2207                 T_END   i += argUsed;
2208 
2209             }
2210             else {
2211                 while ((c = *token++) != '\0') {
2212                     double double_value = 0;
2213                     int int_value = 0;
2214                     arg = *token ? token : nextArg;
2215                     switch (c) {
2216                     case 'm':
2217                         argUsed = 1;
2218 
2219                         switch (*arg) {
2220                         case 's':
2221                             (void) lame_set_mode(gfp, STEREO);
2222                             break;
2223                         case 'd':
2224                             (void) lame_set_mode(gfp, DUAL_CHANNEL);
2225                             break;
2226                         case 'f':
2227                             lame_set_force_ms(gfp, 1);
2228                             (void) lame_set_mode(gfp, JOINT_STEREO);
2229                             break;
2230                         case 'j':
2231                             lame_set_force_ms(gfp, 0);
2232                             (void) lame_set_mode(gfp, JOINT_STEREO);
2233                             break;
2234                         case 'm':
2235                             (void) lame_set_mode(gfp, MONO);
2236                             break;
2237                         case 'l':
2238                             (void) lame_set_mode(gfp, MONO);
2239                             (void) lame_set_scale_left(gfp, 2);
2240                             (void) lame_set_scale_right(gfp, 0);
2241                             break;
2242                         case 'r':
2243                             (void) lame_set_mode(gfp, MONO);
2244                             (void) lame_set_scale_left(gfp, 0);
2245                             (void) lame_set_scale_right(gfp, 2);
2246                             break;
2247                         case 'a': /* same as 'j' ??? */
2248                             lame_set_force_ms(gfp, 0);
2249                             (void) lame_set_mode(gfp, JOINT_STEREO);
2250                             break;
2251                         default:
2252                             error_printf("%s: -m mode must be s/d/f/j/m/l/r not %s\n", ProgramName,
2253                                          arg);
2254                             return -1;
2255                         }
2256                         break;
2257 
2258                     case 'V':
2259                         argUsed = getDoubleValue("V", arg, &double_value);
2260                         if (argUsed) {
2261                             /* to change VBR default look in lame.h */
2262                             if (lame_get_VBR(gfp) == vbr_off)
2263                                 lame_set_VBR(gfp, vbr_default);
2264                             lame_set_VBR_quality(gfp, (float) double_value);
2265                         }
2266                         break;
2267                     case 'v':
2268                         /* to change VBR default look in lame.h */
2269                         if (lame_get_VBR(gfp) == vbr_off)
2270                             lame_set_VBR(gfp, vbr_default);
2271                         break;
2272 
2273                     case 'q':
2274                         argUsed = getIntValue("q", arg, &int_value);
2275                         if (argUsed)
2276                             (void) lame_set_quality(gfp, int_value);
2277                         break;
2278                     case 'f':
2279                         (void) lame_set_quality(gfp, 7);
2280                         break;
2281                     case 'h':
2282                         (void) lame_set_quality(gfp, 2);
2283                         break;
2284 
2285                     case 's':
2286                         argUsed = getDoubleValue("s", arg, &double_value);
2287                         if (argUsed) {
2288                             double_value = (int) (double_value * (double_value <= 192 ? 1.e3 : 1.e0) + 0.5);
2289                             global_reader.input_samplerate = (int)double_value;
2290                             (void) lame_set_in_samplerate(gfp, (int)double_value);
2291                         }
2292                         break;
2293                     case 'b':
2294                         argUsed = getIntValue("b", arg, &int_value);
2295                         if (argUsed) {
2296                             lame_set_brate(gfp, int_value);
2297                             lame_set_VBR_min_bitrate_kbps(gfp, lame_get_brate(gfp));
2298                         }
2299                         break;
2300                     case 'B':
2301                         argUsed = getIntValue("B", arg, &int_value);
2302                         if (argUsed) {
2303                             lame_set_VBR_max_bitrate_kbps(gfp, int_value);
2304                         }
2305                         break;
2306                     case 'F':
2307                         lame_set_VBR_hard_min(gfp, 1);
2308                         break;
2309                     case 't': /* dont write VBR tag */
2310                         (void) lame_set_bWriteVbrTag(gfp, 0);
2311                         global_decoder.disable_wav_header = 1;
2312                         break;
2313                     case 'T': /* do write VBR tag */
2314                         (void) lame_set_bWriteVbrTag(gfp, 1);
2315                         nogap_tags = 1;
2316                         global_decoder.disable_wav_header = 0;
2317                         break;
2318                     case 'r': /* force raw pcm input file */
2319 #if defined(LIBSNDFILE)
2320                         error_printf
2321                             ("WARNING: libsndfile may ignore -r and perform fseek's on the input.\n"
2322                              "Compile without libsndfile if this is a problem.\n");
2323 #endif
2324                         global_reader.input_format = sf_raw;
2325                         break;
2326                     case 'x': /* force byte swapping */
2327                         global_reader.swapbytes = 1;
2328                         break;
2329                     case 'p': /* (jo) error_protection: add crc16 information to stream */
2330                         lame_set_error_protection(gfp, 1);
2331                         break;
2332                     case 'a': /* autoconvert input file from stereo to mono - for mono mp3 encoding */
2333                         autoconvert = 1;
2334                         (void) lame_set_mode(gfp, MONO);
2335                         break;
2336                     case 'd':   /*(void) lame_set_allow_diff_short( gfp, 1 ); */
2337                     case 'k':   /*lame_set_lowpassfreq(gfp, -1);
2338                                   lame_set_highpassfreq(gfp, -1); */
2339                         error_printf("WARNING: -%c is obsolete.\n", c);
2340                         break;
2341                     case 'S':
2342                         global_ui_config.silent = 5;
2343                         break;
2344                     case 'X':
2345                         /*  experimental switch -X:
2346                             the differnt types of quant compare are tough
2347                             to communicate to endusers, so they shouldn't
2348                             bother to toy around with them
2349                          */
2350                         {
2351                             int     x, y;
2352                             int     n = sscanf(arg, "%d,%d", &x, &y);
2353                             if (n == 1) {
2354                                 y = x;
2355                             }
2356                             argUsed = 1;
2357                             if (internal_opts_enabled) {
2358                                 lame_set_quant_comp(gfp, x);
2359                                 lame_set_quant_comp_short(gfp, y);
2360                             }
2361                         }
2362                         break;
2363                     case 'Y':
2364                         lame_set_experimentalY(gfp, 1);
2365                         break;
2366                     case 'Z':
2367                         /*  experimental switch -Z:
2368                          */
2369                         {
2370                             int     n = 1;
2371                             argUsed = sscanf(arg, "%d", &n);
2372                             /*if (internal_opts_enabled)*/
2373                             {
2374                                 lame_set_experimentalZ(gfp, n);
2375                             }
2376                         }
2377                         break;
2378                     case 'e':
2379                         argUsed = 1;
2380 
2381                         switch (*arg) {
2382                         case 'n':
2383                             lame_set_emphasis(gfp, 0);
2384                             break;
2385                         case '5':
2386                             lame_set_emphasis(gfp, 1);
2387                             break;
2388                         case 'c':
2389                             lame_set_emphasis(gfp, 3);
2390                             break;
2391                         default:
2392                             error_printf("%s: -e emp must be n/5/c not %s\n", ProgramName, arg);
2393                             return -1;
2394                         }
2395                         break;
2396                     case 'c':
2397                         lame_set_copyright(gfp, 1);
2398                         break;
2399                     case 'o':
2400                         lame_set_original(gfp, 0);
2401                         break;
2402 
2403                     case '?':
2404                         long_help(gfp, stdout, ProgramName, 0 /* LESSMODE=NO */ );
2405                         return -1;
2406 
2407                     default:
2408                         error_printf("%s: unrecognized option -%c\n", ProgramName, c);
2409                         return -1;
2410                     }
2411                     if (argUsed) {
2412                         if (arg == token)
2413                             token = ""; /* no more from token */
2414                         else
2415                             ++i; /* skip arg we used */
2416                         arg = "";
2417                         argUsed = 0;
2418                     }
2419                 }
2420             }
2421         }
2422         else {
2423             if (nogap) {
2424                 if ((num_nogap != NULL) && (count_nogap < *num_nogap)) {
2425                     strncpy(nogap_inPath[count_nogap++], argv[i], PATH_MAX + 1);
2426                     input_file = 1;
2427                 }
2428                 else {
2429                     /* sorry, calling program did not allocate enough space */
2430                     error_printf
2431                         ("Error: 'nogap option'.  Calling program does not allow nogap option, or\n"
2432                          "you have exceeded maximum number of input files for the nogap option\n");
2433                     *num_nogap = -1;
2434                     return -1;
2435                 }
2436             }
2437             else {
2438                 /* normal options:   inputfile  [outputfile], and
2439                    either one can be a '-' for stdin/stdout */
2440                 if (inPath[0] == '\0') {
2441                     strncpy(inPath, argv[i], PATH_MAX + 1);
2442                     input_file = 1;
2443                 }
2444                 else {
2445                     if (outPath[0] == '\0')
2446                         strncpy(outPath, argv[i], PATH_MAX + 1);
2447                     else {
2448                         error_printf("%s: excess arg %s\n", ProgramName, argv[i]);
2449                         return -1;
2450                     }
2451                 }
2452             }
2453         }
2454     }                   /* loop over args */
2455 
2456     if (!input_file) {
2457         usage(Console_IO.Console_fp, ProgramName);
2458         return -1;
2459     }
2460 
2461     if (lame_get_decode_only(gfp) && count_nogap > 0) {
2462         error_printf("combination of nogap and decode not supported!\n");
2463         return -1;
2464     }
2465 
2466     if (inPath[0] == '-') {
2467         if (global_ui_config.silent == 0) { /* user didn't overrule default behaviour */
2468             global_ui_config.silent = 1;
2469         }
2470     }
2471 #ifdef WIN32
2472     else
2473         dosToLongFileName(inPath);
2474 #endif
2475 
2476     if (outPath[0] == '\0') { /* no explicit output dir or file */
2477         if (count_nogap > 0) { /* in case of nogap encode */
2478             strncpy(outPath, outDir, PATH_MAX);
2479             outPath[PATH_MAX] = '\0'; /* whatever someone set via --out-dir <path> argument */
2480         }
2481         else if (inPath[0] == '-') {
2482             /* if input is stdin, default output is stdout */
2483             strcpy(outPath, "-");
2484         }
2485         else {
2486             char const* s_ext = lame_get_decode_only(gfp) ? ".wav" : ".mp3";
2487             if (generateOutPath(inPath, outDir, s_ext, outPath) != 0) {
2488                 return -1;
2489             }
2490         }
2491     }
2492 
2493     /* RG is enabled by default */
2494     if (!noreplaygain)
2495         lame_set_findReplayGain(gfp, 1);
2496 
2497     /* disable VBR tags with nogap unless the VBR tags are forced */
2498     if (nogap && lame_get_bWriteVbrTag(gfp) && nogap_tags == 0) {
2499         console_printf("Note: Disabling VBR Xing/Info tag since it interferes with --nogap\n");
2500         lame_set_bWriteVbrTag(gfp, 0);
2501     }
2502 
2503     /* some file options not allowed with stdout */
2504     if (outPath[0] == '-') {
2505         (void) lame_set_bWriteVbrTag(gfp, 0); /* turn off VBR tag */
2506     }
2507 
2508     /* if user did not explicitly specify input is mp3, check file name */
2509     if (global_reader.input_format == sf_unknown)
2510         global_reader.input_format = filename_to_type(inPath);
2511 
2512 #if !(defined HAVE_MPGLIB || defined AMIGA_MPEGA)
2513     if (is_mpeg_file_format(global_reader.input_format)) {
2514         error_printf("Error: libmp3lame not compiled with mpg123 *decoding* support \n");
2515         return -1;
2516     }
2517 #endif
2518 
2519     /* default guess for number of channels */
2520     if (autoconvert)
2521         (void) lame_set_num_channels(gfp, 2);
2522     else if (MONO == lame_get_mode(gfp))
2523         (void) lame_set_num_channels(gfp, 1);
2524     else
2525         (void) lame_set_num_channels(gfp, 2);
2526 
2527     if (lame_get_free_format(gfp)) {
2528         if (lame_get_brate(gfp) < 8 || lame_get_brate(gfp) > 640) {
2529             error_printf("For free format, specify a bitrate between 8 and 640 kbps\n");
2530             error_printf("with the -b <bitrate> option\n");
2531             return -1;
2532         }
2533     }
2534     if (num_nogap != NULL)
2535         *num_nogap = count_nogap;
2536     return 0;
2537 }
2538 
2539 static int
string_to_argv(char * str,char ** argv,int N)2540 string_to_argv(char* str, char** argv, int N)
2541 {
2542     int     argc = 0;
2543     if (str == 0) return argc;
2544     argv[argc++] = "lhama";
2545     for (;;) {
2546         int     quoted = 0;
2547         while (isspace(*str)) { /* skip blanks */
2548             ++str;
2549         }
2550         if (*str == '\"') { /* is quoted argument ? */
2551             quoted = 1;
2552             ++str;
2553         }
2554         if (*str == '\0') { /* end of string reached */
2555             break;
2556         }
2557         /* found beginning of some argument */
2558         if (argc < N) {
2559             argv[argc++] = str;
2560         }
2561         /* look out for end of argument, either end of string, blank or quote */
2562         for(; *str != '\0'; ++str) {
2563             if (quoted) {
2564                 if (*str == '\"') { /* end of quotation reached */
2565                     *str++ = '\0';
2566                     break;
2567                 }
2568             }
2569             else {
2570                 if (isspace(*str)) { /* parameter separator reached */
2571                     *str++ = '\0';
2572                     break;
2573                 }
2574             }
2575         }
2576     }
2577     return argc;
2578 }
2579 
2580 static int
merge_argv(int argc,char ** argv,int str_argc,char ** str_argv,int N)2581 merge_argv(int argc, char** argv, int str_argc, char** str_argv, int N)
2582 {
2583     int     i;
2584     if (argc > 0) {
2585         str_argv[0] = argv[0];
2586         if (str_argc < 1) str_argc = 1;
2587     }
2588     for (i = 1; i < argc; ++i) {
2589         int     j = str_argc + i - 1;
2590         if (j < N) {
2591             str_argv[j] = argv[i];
2592         }
2593     }
2594     return argc + str_argc - 1;
2595 }
2596 
2597 #ifdef DEBUG
2598 static void
dump_argv(int argc,char ** argv)2599 dump_argv(int argc, char** argv)
2600 {
2601     int     i;
2602     for (i = 0; i < argc; ++i) {
2603         printf("%d: \"%s\"\n",i,argv[i]);
2604     }
2605 }
2606 #endif
2607 
2608 
parse_args(lame_t gfp,int argc,char ** argv,char * const inPath,char * const outPath,char ** nogap_inPath,int * num_nogap)2609 int parse_args(lame_t gfp, int argc, char **argv, char *const inPath, char *const outPath, char **nogap_inPath, int *num_nogap)
2610 {
2611     char   *str_argv[512], *str;
2612     int     str_argc, ret;
2613     str = lame_getenv("LAMEOPT");
2614     str_argc = string_to_argv(str, str_argv, dimension_of(str_argv));
2615     str_argc = merge_argv(argc, argv, str_argc, str_argv, dimension_of(str_argv));
2616 #ifdef DEBUG
2617     dump_argv(str_argc, str_argv);
2618 #endif
2619     ret = parse_args_(gfp, str_argc, str_argv, inPath, outPath, nogap_inPath, num_nogap);
2620     free(str);
2621     return ret;
2622 }
2623 
2624 /* end of parse.c */
2625