1 /*
2 ********************************************************************************
3 File: cmdarg.c
4 
5 Tab size:           4
6 Max line length:    80
7 Programmer:         Volker Kuhlmann
8 
9 
10 wav2cdr 2.3.4 Copyright (C) 1997, 1998, 1999, 2000, 2006 Volker Kuhlmann
11 This program is free software under the terms of the GNU General Public License
12 version 2 (or later, at your option).
13 See the file COPYING for details about license terms and warranty.
14 <VolkerKuhlmann@gmx.de>
15 
16 
17 DESCRIPTION:
18 
19 Scans and checks the command line arguments.
20 
21 
22 CONDITIONALS:
23 	see wav2cdr.c
24 
25 
26 HISTORY:
27 	see wav2cdr.c, and ChangeLog
28 
29 ********************************************************************************
30 */
31 
32 
33 
34 #include <stddef.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <ctype.h>
39 #include <errno.h>
40 #include <limits.h>
41 #include <assert.h>
42 #include <time.h>
43 #include <math.h>
44 
45 #include "chelp.h"
46 
47 #include "wav2cdr.h"
48 
49 #ifdef HAS_GNUGETOPT
50 #include "getopt.h"
51 #else
52 #include "mygetopt.h"
53 #endif
54 
55 
56 /*
57 	Global + local variables
58 */
59 extern FILE
60 	*msgfile;	/* where to display cmd args and progress */
61 
62 #ifdef DEBUG
63 extern FILE
64 	*dbgfile;	/* where to display debug output */
65 #endif
66 
67 static cmdarg_t
68 	cmdarg = CMDARG_DEFAULT;	/* cmd args, set to default values */
69 
70 /* size of input data in bytes, not counting headers
71 	size not available when == -1 (therefore must be a signed type)
72 	Can not make this int because that may be only 16 bit.
73 	Can not make this size_t because that is usually unsigned int.
74 	Should be the same type as get_file_size().
75 */
76 static signed long input_size;
77 
78 
79 
80 /*
81 	Local function prototypes
82 */
83 static signed long get_num_unit (const string *s);
84 #ifdef GET_UINT16
85 static UINT16 get_uint16_bytes (const char *s);
86 static UINT16 get_uint16_blocks (const char *s);
87 #endif
88 static void check_monotonous_cuts (void);
89 static signed long get_neg_cut (signed long cut);
90 
91 
92 
93 /*
94 	Parse command line and do some checks for consistency.
95 	In: argc, argv
96 	Out: ---
97 	Return: ---
98 */
scan_cmd_args(int argc,char ** argv)99 void scan_cmd_args (int argc, char **argv)
100 {
101 int lidx
102 #ifdef DEBUG
103  		 = -99
104 #endif
105 	;
106 int r = 1;
107 enum {  /* all must be != 0, and != any of the short option letters */
108 	o_in = 1, o_out, o_iscale, o_fscale, o_ssil, o_esil,
109 	o_indflt, o_inwav, o_incdr, o_inraw,
110 	o_todflt, o_toraw, o_tocdr, o_towav,
111 	o_swapwords0, o_swapwords1, o_silthresh, o_sildelay, o_fadein, o_fadeout
112 	};
113 const string shortoptions[] = "hIiOour:Vw:";
114 const struct option longoptions[] = {
115 	{"h",				no_argument, (int *) &cmdarg.usage, 'u'},
116 	{"u",				no_argument, (int *) &cmdarg.usage, 'u'},
117 	{"usage",			no_argument, (int *) &cmdarg.usage, 'u'},
118 	{"help",			no_argument, (int *) &cmdarg.help, 'H'},
119 	{"tocdr",			no_argument, NULL, o_tocdr},
120 	{"towav",			no_argument, NULL, o_towav},
121 	{"toraw",			no_argument, NULL, o_toraw},
122 	{"inraw",			no_argument, NULL, o_inraw},
123 	{"inwav",			no_argument, NULL, o_inwav},
124 	{"incdr",			no_argument, NULL, o_incdr},
125 	#if 0
126 	{"ifmt",			required_argument, NULL, o_iformat},
127 	{"ofmt",			required_argument, NULL, o_oformat},
128 	#endif
129 	{"monostereo",		no_argument, (int *) &cmdarg.monostereo, TRUE},
130 	{"inbig",			no_argument, NULL, 'I'},
131 	{"I",				no_argument, NULL, 'I'},
132 	{"inlittle",		no_argument, NULL, 'i'},
133 	{"i",				no_argument, NULL, 'i'},
134 	{"outbig",			no_argument, NULL, 'O'},
135 	{"O",				no_argument, NULL, 'O'},
136 	{"outlittle",		no_argument, NULL, 'o'},
137 	{"o",				no_argument, NULL, 'o'},
138 	{"swapchannels",	no_argument, NULL, o_swapwords1},
139 	/*{"swch",			no_argument, NULL, o_swapwords1},*/
140 	{"noswapchannels",	no_argument, NULL, o_swapwords0},
141 	/*{"noswch",			no_argument, NULL, o_swapwords0},*/
142 	{"infile",			required_argument, NULL, o_in},
143 	/*{"if",				required_argument, NULL, o_in},*/
144 	{"outfile",			required_argument, NULL, o_out},
145 	/*{"of",				required_argument, NULL, o_out},*/
146 	{"iscale",			required_argument, NULL, o_iscale},
147 	{"fscale",			required_argument, NULL, o_fscale},
148 	{"cut",				no_argument, NULL, 'c'},
149 	{"startsilence",	required_argument, NULL, o_ssil},
150 	{"ss",				required_argument, NULL, o_ssil},
151 	{"endsilence",		required_argument, NULL, o_esil},
152 	{"es",				required_argument, NULL, o_esil},
153 	{"silencecuts", 	no_argument, (int *) &cmdarg.silencecuts, TRUE},
154 	{"silenceinfo",	 	no_argument, (int *) &cmdarg.silenceinfo, TRUE},
155 	{"silencethresh", 	required_argument, NULL, o_silthresh},
156 	{"silencedelay", 	required_argument, NULL, o_sildelay},
157 	{"fadein",		 	required_argument, NULL, o_fadein},
158 	{"fadeout",		 	required_argument, NULL, o_fadeout},
159 	{"quiet", 			no_argument, (int *) &cmdarg.quiet, TRUE},
160 	{"version", 		no_argument, NULL, 'V'},
161 	{"verbose", 		no_argument, (int *) &cmdarg.verbose, TRUE},
162 	{NULL,				no_argument, NULL, 0}
163 	};
164 
165 	/* assignments by getopt will assign a size of int into boolean fields
166 		of cmdarg */
167 	assert (sizeof(BOOL)==sizeof(int));
168 
169 	#ifdef DEBUG
170 	dbgfile = stderr;
171 	DBGPRINTF1 ("long options: %i\n",
172 					sizeof(longoptions) / sizeof(struct option));
173 	#endif
174 	optind = 0;  /* tell getopt to init */
175 	while (r != -1) {
176 		r = getopt_long (argc, argv, shortoptions, longoptions, &lidx);
177 		DBGPRINTF3 ("getopt() ret: x%02x '%c', optind: %i",
178 					r!=-1 ? r : 0xff, ((r>=32) AND (r<127)) ? r : ' ', optind);
179 		DBGPRINTF3 (", optopt '%c' x%02x, lidx: %i",
180 						optopt, optopt, lidx);
181 		DBGPRINTF1 (", optarg: %s\n", optarg != NULL ? optarg : "(NULL)");
182 		switch (r) {
183 		case 'h':
184 		case 'u':
185 			cmdarg.usage = TRUE;
186 			break;
187 		case 'V':
188 			cmdarg.version = TRUE;
189 			break;
190 		case o_swapwords1:
191 			cmdarg.swapwords = TRUE;
192 			break;
193 		case o_swapwords0:
194 			cmdarg.swapwords = FALSE;
195 			break;
196 		case o_inraw:
197 			cmdarg.informat = AF_raw;
198 			cmdarg.little_input = RAW_FORMAT_DEFAULT_IS_LITTLE;
199 			break;
200 		case o_inwav:
201 			cmdarg.informat = AF_wav;
202 			cmdarg.little_input = TRUE;
203 			break;
204 		case o_incdr:
205 			cmdarg.informat = AF_cdr;
206 			cmdarg.little_input = FALSE;
207 			break;
208 		case o_tocdr:
209 			cmdarg.outformat = AF_cdr;
210 			cmdarg.little_output = FALSE;
211 			break;
212 		case o_towav:
213 			cmdarg.outformat = AF_wav;
214 			cmdarg.little_output = TRUE;
215 			break;
216 		case o_toraw:
217 			cmdarg.outformat = AF_raw;
218 			cmdarg.little_output = RAW_FORMAT_DEFAULT_IS_LITTLE;
219 			break;
220 		case 'I':
221 			cmdarg.little_input = FALSE;
222 			if (cmdarg.informat == AF_wav)
223 				exit_error (ERR_CMDARG, "can't read wav in big endian", NULL);
224 			break;
225 		case 'i':
226 			cmdarg.little_input = TRUE;
227 			if (cmdarg.informat == AF_cdr)
228 				exit_error (ERR_CMDARG, "can't read cdr in little endian", NULL);
229 			break;
230 		case 'O':
231 			cmdarg.little_output = FALSE;
232 			if (cmdarg.outformat == AF_wav)
233 				exit_error (ERR_CMDARG, "must write wav in little endian", NULL);
234 			break;
235 		case 'o':
236 			cmdarg.little_output = TRUE;
237 			if (cmdarg.outformat == AF_cdr)
238 				exit_error (ERR_CMDARG, "must write cdr in big endian", NULL);
239 			break;
240 		case o_in:
241 		case 'r':
242 			cmdarg.infilename = optarg;
243 			break;
244 		case o_out:
245 		case 'w':
246 			cmdarg.outfilename = optarg;
247 			break;
248 		case o_iscale:
249 			r = sscanf (optarg, "%li", &cmdarg.iscale);
250 			if (r != 1)
251 				exit_error (ERR_CMDARG,
252 					"with number (syntax): ", optarg);
253 			break;
254 		case o_fscale:
255 			r = sscanf (optarg, "%f", &cmdarg.fscale);
256 			if (r != 1)
257 				exit_error (ERR_CMDARG,
258 					"with floating point number (syntax): ", optarg);
259 			break;
260 		case 'c':
261 			cmdarg.numcuts = 1;  /* set marker that the option was there */
262 			break;
263 		case o_ssil:
264 			cmdarg.startsilence = get_silence_value (optarg);
265 			break;
266 		case o_esil:
267 			cmdarg.endsilence = get_silence_value (optarg);
268 			break;
269 		case o_silthresh:
270 			cmdarg.silence_thresh = get_num_unit (optarg) / CDAUDIOSECTORSIZE;
271 			break;
272 		case o_sildelay:
273 			cmdarg.silence_delay = get_num_unit (optarg) / CDAUDIOSECTORSIZE;
274 			break;
275 		case o_fadein:
276 			cmdarg.fadein = get_num_unit (optarg);
277 			break;
278 		case o_fadeout:
279 			cmdarg.fadeout = get_num_unit (optarg);
280 			break;
281 		case 0:
282 		case -1:
283 			break;
284 		case '?':
285 			/* some error, optopt knows more */
286 			/* this test falls over for long options with option->val == 0 */
287 			if (optopt == 0x00)
288 				exit_error (ERR_CMDARG, "unknown option: ", argv[optind - 1]);
289 			if ((strchr (shortoptions, optopt) != NULL)
290 				OR NOT isprint (optopt))
291 				exit_error (ERR_CMDARG, argv[optind - 1], " requires an argument");
292 			else {
293 				string s[2];
294 				s[0] = isprint (optopt) ? optopt : ' '; s[1] = '\0';
295 				exit_error (ERR_CMDARG, "unknown short option: ", s);
296 			}
297 		default:
298 			/* internal error */
299 			{
300 			string buf[20];
301 			sprintf (buf, "%i", r);
302 			exit_error (ERR_INTERNAL, "can't handle getopt() return val ", buf);
303 			}
304 		}
305 	}
306 	#ifdef DEBUG
307 	DBGPRINTF2 ("End scan. optind: %i   argc = %i\n", optind, argc);
308 	{ int i; for (i = 0; i < argc; i++)
309 		DBGPRINTF2 ("  argv %i %s\n", i, argv[i]);
310 	}
311 	#endif
312 
313 	/* use remaining options to fill up filenames or cut numbers
314 		(but not both) */
315 	while (optind < argc) {
316 		#if 0
317 		/* (if not starting with '-' or exactly "-") */
318 		if ((argv[optind][0] == '-')  AND  (argv[optind][1] != '\0'))
319 			exit_error (ERR_CMDARG, "unknown option ", argv[optind]);
320 		#endif
321 		if (cmdarg.numcuts) {
322 			cmdarg.numcuts = argc - optind;
323 			cmdarg.cutstarts = &argv[optind];
324 			break; /* remaining args are cut numbers */
325 		}
326 		if (cmdarg.infilename == NULL)
327 			cmdarg.infilename = argv[optind];
328 		else {
329 			if (cmdarg.outfilename == NULL)
330 				cmdarg.outfilename = argv[optind];
331 			else
332 				exit_error (ERR_CMDARG, "can not handle ", argv[optind]);
333 		}
334 		optind++;
335 	}
336 
337 	/* treat name "-" the same as stdin/stdout */
338 	/* this must be before main() calls check_cmd_args() */
339 	if ((cmdarg.infilename != NULL)
340 		AND (strcmp (cmdarg.infilename, "-") == 0))
341 		cmdarg.infilename = NULL;
342 	if ((cmdarg.outfilename != NULL)
343 		AND (strcmp (cmdarg.outfilename, "-") == 0))
344 		cmdarg.outfilename = NULL;
345 
346 	/* when finding silence, set output format to raw and byte order to local */
347 	/* this should really go into the big switch() above */
348 	if (cmdarg.silenceinfo)
349 		cmdarg.silencecuts = TRUE;
350 	if (cmdarg.silencecuts) {
351 		cmdarg.outformat = AF_raw;
352 		cmdarg.little_output = is_localhost_little ();
353 	}
354 
355 } /* scan_cmd_args() */
356 
357 
358 
359 /*
360 	Determine how to use stdout and stderr for messages, output, and
361 	debugging output
362 */
set_message_output(void)363 void set_message_output (void)
364 {
365 	/* determine where messages and debugging output go to */
366 	msgfile = stdout;
367 	if (cmdarg.outfilename == NULL)
368 		msgfile = stderr;
369 	#ifdef DEBUG
370 	dbgfile = msgfile;
371 	#endif
372 	if (cmdarg.quiet)
373 		msgfile = open_message_file ();
374 } /* set_message_output() */
375 
376 
377 
378 /*
379 	Check consistency of command line arguments
380 */
check_cmd_args(void)381 void check_cmd_args (void)
382 {
383 int hs;
384 
385 	#if 0
386 	if (cmdarg.fscale < 0.0)
387 		exit_error (ERR_CMDARG, "negative scale factor makes no sense",
388 					 NULL);
389 	if (cmdarg.iscale < 0)
390 		exit_error (ERR_CMDARG, "negative scale factor makes no sense",
391 					 NULL);
392 	#endif
393 	if ((cmdarg.iscale < SCALE_MIN)
394 		OR (cmdarg.iscale > SCALE_MAX)
395 		OR ((signed long) cmdarg.fscale < SCALE_MIN)
396 		OR ((signed long) cmdarg.fscale > SCALE_MAX))
397 		exit_error (ERR_CMDARG, "scale factor out of range", NULL);
398 	if (cmdarg.iscale < 0  OR  cmdarg.fscale < 0.0)
399 		fprintf (msgfile, "Scale factor is negative. "
400 			"Will proceed and assume you know what you are doing.\n");
401 
402 	/* initialise input data size */
403 	input_size = get_file_size (cmdarg.infilename, stdin);
404 	/* Adjust the input data size to the amount of actual data only,
405 		excluding any headers.  FIXME: this is dodgy... */
406 	hs = get_af_header_size (cmdarg.informat);
407 	if (input_size != -1)
408 		input_size -= (input_size >= (signed long) hs) ? hs : input_size;
409 
410 	if (cmdarg.numcuts > 0) {
411 		if ((cmdarg.numcuts > 2) AND (cmdarg.outfilename == NULL))
412 			exit_error (ERR_CMDARG,
413 							"can not cut more than 1 part to stdout", "");
414 		if (cmdarg.numcuts == 1)
415 			exit_error (ERR_CMDARG, "must have >= 2 cut numbers", "");
416 		check_monotonous_cuts ();
417 	}
418 
419 	if (cmdarg.help) {
420 		msgfile = stdout;
421 		help ();
422 	}
423 	if (cmdarg.usage) {
424 		msgfile = stdout;
425 		usage ();
426 	}
427 	if (cmdarg.version) {
428 		msgfile = stdout;
429 		version ();
430 	}
431 
432 	if ((cmdarg.iscale != 100) AND (cmdarg.fscale != 1.0)) {
433 		fprintf (msgfile,
434 			"Both integer and float scale given - float scale ignored.\n");
435 		cmdarg.fscale = 1.0;
436 	}
437 
438 	if (((unsigned long) cmdarg.silence_thresh > USHRT_MAX)
439 		OR ((unsigned long) cmdarg.silence_delay > USHRT_MAX))
440 		exit_error (ERR_CMDARG,
441 					"silence threshold and delay must be positive 16 bit", "");
442 
443 	if (cmdarg.silence_delay == 0)
444 		exit_error (ERR_CMDARG,
445 					"silence delay must be >= 1", "");
446 
447 	if (cmdarg.fadeout > 0 AND cmdarg.numcuts == 0 AND input_size == -1)
448 		exit_error (ERR_CMDARG,
449 					"can't fade out when input size can't be determined", "");
450 
451 } /* check_cmd_args() */
452 
453 
454 
455 /*
456 	Check whether cut numbers are monotonous.
457 */
check_monotonous_cuts(void)458 static void check_monotonous_cuts (void)
459 {
460 int j;
461 unsigned long this, next;
462 string buf[80];
463 
464 	for (j = 0, this = get_cut_value (0); j < (cmdarg.numcuts - 1); j++) {
465 		next = get_cut_value (j + 1);
466 		if (next < this) {
467 			sprintf (buf, "cut number (N+1) not >= (N)  (%li not >= %li)",
468 						next, this);
469 			exit_error (ERR_CMDARG, buf, NULL);
470 		}
471 		this = next;
472 	}
473 } /* check_monotonous_cuts() */
474 
475 
476 
477 /*
478 	Display the current state of internal variables.
479 	Writes to the stream msgfile.
480 	In: ---
481 	Out: ---
482 	Return: ---
483 */
showcmdargs(void)484 void showcmdargs (void)
485 {
486 const string
487 	yes[] = "yes",
488 	no[] = "no",
489 	big[] = "big",
490 	little[] = "little";
491 const string *AF_nameidx[] = AF_NAMEIDX;
492 cdseccount_t firstcut = 0, lastcut = 0;
493 string insize[80], silence[80];
494 string stasil[TIMESTRSIZE], endsil[TIMESTRSIZE];
495 string filength[TIMESTRSIZE], folength[TIMESTRSIZE];
496 string stime[TIMESTRSIZE], sfirstcut[TIMESTRSIZE], slastcut[TIMESTRSIZE];
497 
498 	timeprintf (stasil, cmdarg.startsilence);
499 	timeprintf (endsil, cmdarg.endsilence);
500 	timeprintf (filength, cmdarg.fadein);
501 	timeprintf (folength, cmdarg.fadeout);
502 
503 	if (input_size == -1)
504 		strcpy (insize, "not sizeable/seekable (reading pipe?)");
505 	else {
506 		timeprintf (stime, (unsigned long) input_size);
507 		sprintf (insize, "%li b = %li C = %li s = %s min",
508 				(long) input_size,
509 				(long) input_size / CDAUDIOSECTORSIZE,
510 				/*(float) input_size / CDAUDIOSECTORSIZE / CDSECTORSPERSEC*/
511 				input_size / CDAUDIOSECTORSIZE / CDSECTORSPERSEC,
512 				stime
513 				);
514 	}
515 
516 	if (cmdarg.numcuts > 0) {
517 		firstcut = get_cut_value (0);
518 		lastcut = get_cut_value (cmdarg.numcuts - 1);
519 	}
520 	timeprintf (sfirstcut, firstcut * CDAUDIOSECTORSIZE);
521 	timeprintf (slastcut, lastcut * CDAUDIOSECTORSIZE);
522 	if (cmdarg.silencecuts)
523 		sprintf (silence, "%s   (threshold %li, delay %li C = %.2f s)",
524 					yes, cmdarg.silence_thresh, cmdarg.silence_delay,
525 					(float) cmdarg.silence_delay / CDSECTORSPERSEC);
526 	else
527 		strcpy (silence, no);
528 
529 	fprintf (msgfile,
530 		"Host is:            %s\n"
531 		"Byte order in, out: %s -> %s\n"
532 		"Format in, out:     %s -> %s\n"
533 		"Scale:              %li%%, * %f\n"
534 		"Swap channels:      %s\n"
535 		"Do ->mono->stereo:  %s\n"
536 		"Find silences:      %s  %s\n"
537 		"Add silence:        %li C = %s min, %li C = %s min\n"
538 		"Fade-in / -out:     %li C = %s min, %li C = %s min\n"
539 		"Input data size:    %s\n"
540 		"Number of cuts:     %i\n"
541 		"Skipping before:    %s min = %li C  (excl) (first cut)\n"
542 		"Skipping after:     %s min = %li C  (incl) (last cut)\n"
543 		"Input filename:     %s\n"
544 		"Output filename:    %s%s\n"
545 		"-\n",
546 		is_localhost_little () ? little : big,
547 		cmdarg.little_input ? little : big,
548 			cmdarg.little_output ? little : big,
549 		AF_nameidx[cmdarg.informat],
550 			AF_nameidx[cmdarg.outformat],
551 		cmdarg.iscale,
552 			cmdarg.fscale,
553 		cmdarg.swapwords ? yes : no,
554 		cmdarg.monostereo ? yes : no,
555 		silence,  cmdarg.silenceinfo ? "[INFO]" : "",
556 		cmdarg.startsilence / CDAUDIOSECTORSIZE, stasil,
557 			cmdarg.endsilence / CDAUDIOSECTORSIZE, endsil,
558 		cmdarg.fadein / CDAUDIOSECTORSIZE, filength,
559 			cmdarg.fadeout / CDAUDIOSECTORSIZE, folength,
560 		insize,
561 		cmdarg.numcuts,
562 		sfirstcut, firstcut,
563 		slastcut, lastcut,
564 		STRSTDIN(cmdarg.infilename),
565 		STRSTDOUT(cmdarg.outfilename),
566 			cmdarg.outfilename != NULL ? ".%02d" : ""
567 		);
568 
569 } /* showcmdargs() */
570 
571 
572 
573 /*
574 	Generic: get size number, in bytes
575 	Converts a number (integer) with an optional unit,
576 	units:      type:
577 		b       int   (bytes),
578 		c or C  int   (audio CD sectors, default),
579 		s       float (seconds of CD audio)
580 	In: string representation of the number
581 	Out: ---
582 	Return: number IN BYTES, always a multiple of CDAUDIOSECTORSIZE
583 */
get_num_unit(const string * s)584 static signed long get_num_unit (const string *s)
585 {
586 signed long int i;
587 float sec;
588 char unit[] = "\0";
589 int r;
590 
591 	r = sscanf (s, "%li%1s", &i, unit);
592 	if (r == 1)
593 		unit[0] = 'C';	/* default unit */
594 	if (r < 1  OR  (r == 2  AND  strchr ("bscC.", unit[0]) == NULL))
595 		exit_error (ERR_CMDARG, "number/unit syntax: ", s);
596 	if (r == 2  AND  unit[0] == '.') {
597 		unit[0] = '\0';
598 		r = sscanf (s, "%f%1s", &sec, unit);
599 		if (r == 2  AND  strchr ("bcC", unit[0]) != NULL)
600 			exit_error (ERR_CMDARG,
601 			 "number/unit syntax (fractions not with b, c): ", s);
602 		if (r < 1  OR  unit[0] != 's')
603 			exit_error (ERR_CMDARG, "number/unit syntax: ", s);
604 		unit[0] = 'S';
605 	}
606 	DBGPRINTF3 ("<< get val: %li %2.2f %c", i, sec, unit[0]);
607 
608 	switch (unit[0]) {
609 	case 'c':
610 	case 'C':	/* audio CD sectors */
611 		i *= CDAUDIOSECTORSIZE;
612 		break;
613 	case 'b':	/* bytes */
614 		i = ((i + (CDAUDIOSECTORSIZE / 2)) / CDAUDIOSECTORSIZE)
615 				* CDAUDIOSECTORSIZE;
616 		break;
617 	case 's':	/* seconds of CD audio */
618 		i *= (signed long) CDSECTORSPERSEC * (signed long) CDAUDIOSECTORSIZE;
619 		break;
620 	case 'S':
621 		i = ((signed long) (sec * (float) CDSECTORSPERSEC + 0.5))
622 				* (signed long) CDAUDIOSECTORSIZE;
623 		break;
624 	default:
625 		exit_error (ERR_INTERNAL, "switch", NULL);
626 	}
627 	DBGPRINTF1 ("  new val: %li >>\n", i);
628 
629 	return i;
630 
631 } /* get_num_unit */
632 
633 
634 
635 /*
636 	Get a positive 16 bit value. Uses get_num_unit().
637 	In: string representation of the number
638 	Out: ---
639 	Return: number
640 */
641 #ifdef GET_UINT16
get_uint16_bytes(const char * s)642 static UINT16 get_uint16_bytes (const char *s)
643 {
644 signed long l;
645 
646 	l = get_num_unit (s);
647 	if (l < 0  OR  l > USHRT_MAX)
648 		exit_error (ERR_CMDARG, "number must be positive 16 bit: ", s);
649 	return (UINT16) l;
650 
651 } /* get_uint16_bytes() */
652 #endif
653 
654 
655 
656 /*
657 	Get a positive 16 bit value, in CDAUDIOSECTORSIZE size units.
658 	Uses get_num_unit().
659 	In: string representation of the number
660 	Out: ---
661 	Return: number
662 */
663 #ifdef GET_UINT16
get_uint16_blocks(const char * s)664 static UINT16 get_uint16_blocks (const char *s)
665 {
666 signed long l;
667 
668 	l = get_num_unit (s) / CDAUDIOSECTORSIZE;
669 	if (l < 0  OR  l > USHRT_MAX)
670 		exit_error (ERR_CMDARG, "number must be positive 16 bit: ", s);
671 	return (UINT16) l;
672 
673 } /* get_uint16_blocks() */
674 #endif
675 
676 
677 
678 /*
679 	In: ---
680 	Out: ---
681 	Return: Input size in full CD blocks, or -1 if not available
682 */
get_input_size_in_cd_blocks(void)683 signed long get_input_size_in_cd_blocks (void)
684 {
685 signed long size;
686 
687 	if (input_size == -1)
688 		return -1;
689 
690 	/* this is file format dependent!!, but input_size allows for that */
691 	size = (input_size / CDAUDIOSECTORSIZE);
692 	if ((size * CDAUDIOSECTORSIZE) < input_size)
693 		size++; /* measure from the true end of the cdr file */
694 	return size;
695 
696 } /* get_input_size_in_cd_blocks() */
697 
698 
699 
700 /*
701 	Calculates the cut position from the file size for negative cut numbers.
702 	Expects the input data size to be initialised.
703 */
get_neg_cut(signed long cut)704 static signed long get_neg_cut (signed long cut)
705 {
706 signed long pos, size;
707 
708 	if (input_size == -1)
709 		exit_error (ERR_CMDARG,
710 			"cut numbers must not be negative when input can't be sized",
711 			NULL);
712 
713 	size = get_input_size_in_cd_blocks ();
714 	pos = size - (-cut);
715 	if (pos < 0) {
716 		string buf[100];
717 		sprintf (buf,
718 			"cut %li C before start of input with length %li b = %li C",
719 			(long) cut, (long) input_size, (long) size);
720 		exit_error (ERR_CMDARG, buf, NULL);
721 	}
722 	return pos;
723 } /* get_neg_cut() */
724 
725 
726 
727 /*
728 	Get the Nth cut value.
729 	The value returned is positive and in audio CD sectors!
730 	Expects the input data size to be initialised.
731 */
get_cut_value(int n)732 unsigned long get_cut_value (int n)
733 {
734 signed long cut, l = 0;
735 
736 	cut = get_num_unit (cmdarg.cutstarts[n]) / CDAUDIOSECTORSIZE;
737 	l = cut;
738 	if ((cut == 0L) AND (n == (cmdarg.numcuts - 1))) {
739 		/* a 0 as last cut number means all the rest;
740 		   if input size is not available it's better to use the theoretical
741 		   maximum file size than to fail */
742 		if (input_size != -1)
743 			l = get_neg_cut (cut);
744 		else
745 			l = ULONG_MAX / CDAUDIOSECTORSIZE;
746 	} else if (cut < 0) {
747 		/* negative cut number - calculate from file size */
748 		if (input_size == -1)
749 			exit_error (ERR_CMDARG,
750 				"cut numbers must not be negative when input can't be sized",
751 				NULL);
752 		else
753 			l = get_neg_cut (cut);
754 	}
755 
756 	DBGPRINTF2 ("get_cut_value(%i): %li\n", n, (long) l);
757 	return (unsigned long) l;
758 
759 } /* get_cut_value() */
760 
761 
762 
763 /*
764 	Get a silence value.
765 	The value returned is in bytes.
766 */
get_silence_value(const string * s)767 unsigned long get_silence_value (const string *s)
768 {
769 signed long l;
770 
771 	l = get_num_unit (s);
772 	if (l < 0L)
773 		exit_error (ERR_CMDARG,
774 					"negative silence number does not make sense", NULL);
775 	return (unsigned long) l;
776 
777 } /* get_silence_value() */
778 
779 
780 
781 /*
782 	Return the command arg info
783 	In: buffer
784 	Out: initialised command arg info struct
785 	Return: ---
786 */
get_cmdarg_info(cmdarg_t * pcmdarg)787 void get_cmdarg_info (cmdarg_t *pcmdarg)
788 {
789 	*pcmdarg = cmdarg;
790 }
791 
792 
793 
794 /*
795 	Init a processing info struct, from cmdargs and otherwise
796 	In: buffer
797 	Out: initialised process info struct
798 	Return: ---
799 */
init_process_info(process_t * pinfo)800 void init_process_info (process_t *pinfo)
801 {
802 	pinfo->n_in = pinfo->n_returned = 0;
803 
804 	pinfo->first = TRUE;
805 	pinfo->last = FALSE;
806 
807 	pinfo->little_host = is_localhost_little ();
808 	pinfo->from_little = cmdarg.little_input;
809 	pinfo->to_little = cmdarg.little_output;
810 	pinfo->iscale = cmdarg.iscale;
811 	pinfo->fscale = cmdarg.fscale;
812 	pinfo->swap_channels = cmdarg.swapwords;
813 	pinfo->monostereo = cmdarg.monostereo ? MS_TOMONOSTEREO : MS_NONE;
814 	pinfo->silencecuts = cmdarg.silencecuts;
815 	pinfo->silence_thresh = cmdarg.silence_thresh;
816 	pinfo->silence_delay = cmdarg.silence_delay;
817 	pinfo->silence_val = cmdarg.verbose;
818 	pinfo->fadein = 0;
819 	pinfo->fadeout = 0;
820 
821 } /* init_process_info() */
822 
823 
824 
825 /* EOF cmdarg.c */
826 /******************************************************************************/
827