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