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