comparison glib/options.c @ 0:5242703e91d3 tip

Initial checkin for AIM92 aimR8.2 (last updated May 1997).
author tomwalters
date Fri, 20 May 2011 15:19:45 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:5242703e91d3
1 /*
2 Copyright (c) Applied Psychology Unit, Medical Research Council. 1988, 1989
3 ===========================================================================
4
5 Permission to use, copy, modify, and distribute this software without fee
6 is hereby granted for research purposes, provided that this copyright
7 notice appears in all copies and in all supporting documentation, and that
8 the software is not redistributed for any fee (except for a nominal shipping
9 charge). Anyone wanting to incorporate all or part of this software in a
10 commercial product must obtain a license from the Medical Research Council.
11
12 The MRC makes no representations about the suitability of this
13 software for any purpose. It is provided "as is" without express or implied
14 warranty.
15
16 THE MRC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
17 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE
18 A.P.U. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
19 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
20 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 */
23
24 /* -------------------------------------------------------------------------------
25
26 The Leanest Resource Manager in the West.
27
28 Options may be supplied as defaults (actually in the code), as command line
29 arguments, and in a option file. The default arguments may be overridden by
30 the option-file contents, which may be overridden from the command line.
31
32 Copyright (c), 1989 The Medical Research Council of the United Kingdom.
33
34 Author : Paul Manson
35 Written : March 1st 1989
36
37 Edited :
38
39 2nd March 1989 (Paul Manson) Added the facility of searching the HOME directory
40 for a option file if one is not found in the
41 working directory.
42
43 8th March 1989 (Paul Manson) Enhanced the above by providing a OPTIONPATH
44 search strategy for Unix. Currently MSDOS only
45 searches for a option file in the directory
46 where the program was found.
47
48 8th March 1989 (Paul Manson) Added the ability to refer to options via
49 abbreviations of their names. At present, an abbrev.
50 will match if it is exactly the same as precisely one
51 option, or if it is the same as the first <n> chars
52 of that option (where <n> is the length of the
53 abbrev) and it matches no other option name.
54
55 9th March 1989 (Paul Manson) Added the readopts and writeopts calls, to implement
56 option headers for files. Also altered the form
57 of command line options accepted: See getopts.h for
58 details.
59
60 10th March 1989 (Paul Manson) Added the "help" facility to provide a simple
61 self-documentation facility. Also altered the
62 Option type to put defaults and comments in
63 the code.
64
65 16th March 1989 (Paul Manson) Altered the final argc/argv shuffling in getopts
66 so that argv simply points at the first argument
67 after the options. Also added fileopts.
68
69 29th March 1989 (Paul Manson) Altered ".res" to ".opt" to coincide with the new
70 naming r'egime. Also added the spitOptionsFile call
71 to automatically produce an options file with
72 comments. To enable this facility, compile getopts
73 with -DSPITHELP; to use it, type <prog> -spit. Do
74 NOT distribute a spitting version of getopts! Altered
75 Options-file scanning to permit trailing comments.
76
77 30th March 1989 (Paul Manson) Completely eradicated the blockWriteToFile used by
78 writenopts. This is now done on a non-aligned basis,
79 as this is likely to be quicker and less complex.
80
81 03rd April 1989 (Paul Manson) Added the calll to outputopt.
82
83 06th April 1989 (Paul Manson) Oh Joy! Oh Bliss! The once-much-maligned SPIT option
84 is recieved into decent society, albeit in the guise
85 of an options "editor" called 'update'.
86
87 10th April 1989 (Paul Manson) The 'update' option no longer exit(1)s, but
88 carries on to execute the program. Also changed
89 OptionFileName so that it correctly gets the
90 cwd on the PC.
91
92 11th April 1989 (Paul Manson) Altered the OptionFileName routines to be EITHER
93 for the PC or for Unix.
94
95 26th April 1989 (Paul Manson) Put in a temporary delta to the PC version so that it
96 only looks for option files (and hence only creates
97 option files) in the current directory. This will be
98 abandoned when we determine a better search strategy.
99
100 15th June 1989 (Paul Manson) Altered SilentOption so that it is alterable, but is
101 NOT visible in any way (ie. not printed by help or
102 spit, and not output to headers).
103
104 11th July 1989 (Paul Manson) Altered so that "help" (and "update") only display
105 (or output) the options which were either read in
106 from the options file, or have been subsequently
107 altered on the command line. The current implementation
108 simply checks to see whether the default and current
109 values for a particular option differ (either in value
110 OR address!).
111
112 27th July 1989 (Paul Manson) Altered so that isON == !isOFF, and not the other way
113 around -- this allows "2", "3", etc to masquerade as
114 "1" while only "0" is "off". Also changed so that no
115 quotes are output to file headers.
116
117
118 July 1994 (MAA) Allowed spaces in strings, by adding double-quotes
119 to the arguments. Bit of a hack, though.
120 ------------------------------------------------------------------------------- */
121
122 #include "options.h"
123 #include <stdio.h>
124 #include <string.h>
125 #if defined( NeXT)
126 #include <stdlib.h>
127 #else
128 #include <malloc.h>
129 #endif
130 #include <ctype.h>
131
132 #if !defined( lint )
133 static char *sccs_id = "@(#)options.c 1.14 Paul Manson (MRC-APU) 5/2/89";
134 #endif
135
136 char defversion[64] = "not set yet" , *versionstr = defversion ;
137
138 #if defined( PC )
139 #include <direct.h>
140 #define DOT '.'
141 #define BACKSLASH_CHAR '\\'
142 #define SLASH_CHARACTER '/'
143 #define OPTION_FILE_PREFIX ""
144 #define OPTION_FILE_SUFFIX ".opt"
145 #else
146 #ifndef THINK_C
147 #include <sys/types.h>
148 #include <sys/stat.h>
149 #endif
150 #define OPTION_FILE_PREFIX "."
151 #define OPTION_FILE_SUFFIX "rc"
152 #define OPTION_PATH "OPTIONSPATH"
153 /* Environment variable for path */
154 #define DEFAULT_OPTION_PATH "."
155 /* Path is first . then ~ (ie home) */
156 #endif
157
158 #define MAX_LINE_LENGTH (256)
159 #define MAX_NAME_LENGTH (128)
160 #define FALSE (0)
161 #define TRUE (1)
162 #define HYPHEN_CHARACTER '-'
163 #define BLANK_CHARACTER ' '
164 #define TAB_CHARACTER '\t'
165 #define NEWLINE_CHARACTER '\n'
166 #define DOUBLE_QUOTE_CHAR '\"'
167 #define ERROR_RESULT (1234)
168 #define EQUALS_CHARACTER '='
169 #define COMMENT_CHARACTER '#'
170 #define NULL_CHARACTER '\000'
171 #define CARRIAGE_RETURN '\r'
172
173 /* Options-specific definitions for "ON", "OFF" and "NULL" */
174
175 #define ON_STRING (ON_OPTION)
176 #define ON_ALIAS "1"
177
178 #define OFF_STRING (OFF_OPTION)
179 #define OFF_ALIAS "0"
180
181 #define NULL_STRING (NULL_OPTION)
182 #define NULL_ALIAS "null"
183
184 #define NOT_USED "Not_used"
185
186 /* For the search_path and Ambiguity procedures */
187
188 #define LINE_CHARS 200
189 #define AMBIGUOUS (-2)
190 #define NO_MATCH (-1)
191 #define DEFAULT_TOGGLE_VALUE (ON_STRING)
192
193 /* For the readopts and writeopts procedures */
194
195 #define OPTION_HEADER_SIZE ( sizeof ( head_string_start ) - 1 + size_digits + 1 )
196 #define OPTION_HEADER_HEADER "header_bytes="
197 #define OPTION_HEADER_DIGITS (7)
198
199 #define min(X,Y) (((X) < (Y)) ? (X) : (Y))
200
201 static char OptionHeaderHeader[] = OPTION_HEADER_HEADER;
202 static char LineFeedArray[] = "\n";
203 static char EqualsArray[] = "="; /* Was " = " */
204 static char QuotesArray[] = "\"";
205
206 /* For the OnLine Help Facility */
207
208 #define HELP_STRING "help"
209 #define UPDATE_STRING "update"
210 #define ALL_STRING "all"
211
212 static int helpOnAllRequired = FALSE;
213 static int helpOnOneRequired = FALSE;
214 static int helpOnOneLocation = 0;
215 static int updateAllRequired = FALSE;
216
217 extern void exit();
218 static int thereWasAnOptionsFile = FALSE;
219 static char *theOptionFileName = NULL;
220
221
222
223
224 #ifndef PC
225 /* -----------------------------------------------------------------------
226
227 search_path( file, path )
228 =========================
229
230 jwh - 4th jan 1987
231
232 searches through string path for file and returns full file name if it
233 finds it. Returns NULL if file is not found. Path is specified in normal
234 path format i.e. "dir1:dir2:dir3...". Works for "~" and "~/dir.." -
235 substitutes HOME for "~". ~ only works for current user!!
236
237 ----------------------------------------------------------------------- */
238
239
240 static char *search_path( file, path )
241 char *file, *path ;
242 {
243 #ifdef THINK_C
244 return ( file ) ;
245 #else
246 char file_name[ LINE_CHARS ] ;
247 int len_next ;
248 struct stat buf ;
249 extern getenv();
250 char *home_directory = (char *)getenv("HOME");
251
252 if( file[ 0 ] == '/' || file[ 0 ] == '.' && file[ 1 ] == '/' )
253 return ( strcpy( malloc((unsigned)(strlen(file) + 1)), file) );
254
255 do
256 {
257 len_next = ( strchr( path, ':' ) == NULL ) ?
258 strlen( path ) : strchr( path, ':' ) - path ;
259
260 if( *path == '~' )
261 {
262 (void) strcpy( file_name, home_directory ) ;
263 (void) strncpy( file_name + strlen( home_directory ), path+1,
264 len_next-1 ) ;
265 (void) sprintf( file_name + strlen( home_directory ) + len_next - 1 ,
266 "/%s", file ) ;
267 }
268 else
269 {
270 (void) strncpy( file_name, path, len_next ) ;
271 (void) sprintf( file_name + len_next , "/%s", file ) ;
272 }
273
274 if( stat( file_name, &buf ) >= 0 && ( buf.st_mode & S_IFDIR ) == 0 )
275 return ( strcpy( malloc((unsigned)(strlen(file_name) + 1)), file_name) );
276
277 path = path + len_next + 1 ;
278 }
279 while( path[ -1 ] != '\0' ) ;
280
281 /* return( NULL ) ; */ return( file ); /* If PATH is NULL, return FILE */
282 #endif
283 }
284
285 /* ---------------------------------------------------------------------------------
286
287 Return the Option File Name, given the Name of the Application (Unix Version)
288
289 Edited:
290
291 --------------------------------------------------------------------------------- */
292 char *UnixOptionFileName(appn)
293 char *appn ;
294 {
295 char *temp;
296
297 temp = malloc((unsigned) (strlen(appn) + strlen(OPTION_FILE_SUFFIX) +
298 strlen(OPTION_FILE_PREFIX) + 1));
299
300 temp = strcpy(temp,OPTION_FILE_PREFIX);
301 temp = strcat(temp,appn);
302 temp = strcat(temp,OPTION_FILE_SUFFIX);
303
304
305 return (temp);
306 }
307 #endif /* Unix Option File Stuff */
308
309 #if defined( PC )
310
311 /* ---------------------------------------------------------------------------------
312
313 Return the Option File Name, given the Name of the Application (PC Version)
314
315 Edited:
316
317 --------------------------------------------------------------------------------- */
318 char *PCOptionFileName(appn, onlyLocal)
319 char *appn ;
320 int onlyLocal;
321 {
322 char *temp;
323 int i ;
324 char *temp2, *lastPart;
325
326
327 temp = malloc((unsigned) (strlen(appn) + strlen(OPTION_FILE_SUFFIX) +
328 strlen(OPTION_FILE_PREFIX) + 1));
329
330 temp = strcpy(temp, appn);
331
332 for (i = 0; temp[i] != NULL_CHARACTER; i++)
333 if (temp[i] == BACKSLASH_CHAR)
334 temp[i] = SLASH_CHARACTER;
335
336 /* Strip Back to the Application Name */
337 if ((lastPart = strrchr(temp, SLASH_CHARACTER)) == NULL)
338 lastPart = temp;
339 else
340 lastPart++; /* Skip over the actual "/" */
341
342 /* lastPart points to the tail name of the path */
343
344 if ((temp2 = strchr(lastPart,DOT)) == NULL)
345 temp = strcat(temp,OPTION_FILE_SUFFIX);
346 else
347 temp2 = strcpy(temp2, OPTION_FILE_SUFFIX);
348
349 if (onlyLocal) /* Remove the full path to give only a local name */
350 return( lastPart);
351 else
352 return (temp);
353 }
354 #endif /* PC Version of OptionFileName */
355
356
357 /* ---------------------------------------------------------------------------------
358
359 Check that there is no ambiguity in the (possibly abbreviated) <name>. If there is
360 no match whatever, return NO_MATCH. If there is a single exact match, or a single
361 abbreviating match, return the index of the matched option; otherwise return
362 AMBIGUOUS.
363
364 --------------------------------------------------------------------------------- */
365 int Ambiguity(options, numOptions, name)
366 Option options[] ;
367 int numOptions;
368 char *name ;
369 {
370 int i, matched, matchedExactly, matchedWhere, moreThanOneInexactMatch;
371
372 matched = FALSE;
373 matchedExactly = FALSE;
374 moreThanOneInexactMatch = FALSE;
375
376 for (i = 0; i < numOptions; i++)
377 if (options[i].classification != OutputOption &&
378 strncmp(name, options[i].name, strlen(name)) == 0) {
379 if (matched) {
380 if (matchedExactly) {
381 if (strcmp(name, options[i].name) == 0) {
382 /* TWO Exact Matches */
383 return AMBIGUOUS;
384 }
385 }
386 else {
387 if (strcmp(name, options[i].name) == 0) {
388 /* THIS is an exact match */
389 matchedExactly = TRUE;
390 matchedWhere = i;
391 }
392 else {
393 /* There are two inexact matches ... if there are no exact ones we
394 have AMBIGUITY */
395 moreThanOneInexactMatch = TRUE;
396 }
397 }
398 }
399 else {
400 if (strcmp(name, options[i].name) == 0) {
401 /* This is an exact match */
402 matchedExactly = TRUE;
403 }
404 matched = TRUE;
405 matchedWhere = i ;
406 }
407 }
408
409 if (moreThanOneInexactMatch)
410 return (AMBIGUOUS);
411 else {
412 if (matched)
413 return (matchedWhere);
414 else
415 return (NO_MATCH);
416 }
417
418 }
419
420
421 /* ---------------------------------------------------------------------------------
422
423 Search for the named option in the list of options. If it is found, return its
424 location (index) in the options array. Otherwise, return NO_MATCH.
425
426 --------------------------------------------------------------------------------- */
427 int LookUp(options, numOptions, name)
428 Option options[] ;
429 int numOptions;
430 char *name ;
431 {
432 int i;
433
434 for (i = 0; i < numOptions; i++)
435 if (options[i].classification != OutputOption && strcmp(name, options[i].name) == 0) {
436 return (i);
437 }
438
439 return (NO_MATCH);
440
441 }
442
443 extern helpRoutine *onLineHelpHandler;
444 extern void updateOptionsFile();
445
446 /* ---------------------------------------------------------------------------------
447
448 Search for the named option in the list of options. If it is found, set its
449 new value as indicated and return TRUE. If not, return either FALSE or AMBIGUOUS.
450
451 Edited:
452
453 8th March 1989 (Paul Manson) Changed the call to LookUp to call Ambiguity instead,
454 thus achieving the matching of abbreviated options.
455
456 15th March 1989 (Paul Manson) Reinstated the call to LookUp in the case that
457 abbreviations (and hence ambiguity) are/is not
458 permitted (ie. in option Header Files).
459
460 --------------------------------------------------------------------------------- */
461 int LookUpAndStore(options, numOptions, name, value, permitAbbrevs, programName)
462 Option options[] ;
463 int numOptions ;
464 char *name, *value;
465 int permitAbbrevs;
466 char *programName ;
467 {
468 int loc ;
469 char *temp;
470
471 /* Account for specific references to the "help" option, with different
472 treatment of the "help=all" command */
473 if (strcmp(name, HELP_STRING) == 0) {
474 /* Check whether it is asking for ALL help */
475 if (strcmp(value, ALL_STRING) == 0) {
476 helpOnAllRequired = TRUE;
477 helpOnOneRequired = FALSE;
478 (*onLineHelpHandler)(options, numOptions, programName);
479 exit(0);
480 }
481 /* Check for other specific kinds of help request */
482 /* else if (strcmp(value, _STRING) == 0) { */
483
484
485 else {
486 /* Expand the (possibly abbreviated) option name */
487 if ((permitAbbrevs && ((loc = Ambiguity(options, numOptions, value)) >= 0)) ||
488 (!permitAbbrevs && ((loc = LookUp(options, numOptions, value)) >= 0))) {
489 helpOnOneRequired = TRUE;
490 helpOnAllRequired = FALSE;
491 helpOnOneLocation = loc ;
492 (*onLineHelpHandler)(options, numOptions, programName);
493 exit(0);
494 }
495 else {
496 if (loc == AMBIGUOUS) {
497 (void) fprintf(stderr, "WARNING: The option name %s is AMBIGUOUS; please be more specific.\n", value);
498 exit(1);
499 }
500 else {
501 (void) fprintf(stderr, "WARNING: The %s program does not have an option named %s.\n",
502 programName, value);
503 exit(1);
504 }
505 }
506 }
507 }
508 else if (strcmp(name, UPDATE_STRING) == 0) {
509 /* Check whether it is asking for ALL updated */
510 if (strcmp(value, ALL_STRING) == 0) {
511 updateAllRequired = TRUE ;
512 updateOptionsFile(options, numOptions, programName, theOptionFileName);
513 updateAllRequired = FALSE;
514 helpOnAllRequired = TRUE ;
515 helpOnOneRequired = FALSE;
516 return (TRUE);
517 }
518 else {
519 /* At present there is no use for a specific update call */
520 (void) fprintf(stderr, "options: The update option may not be altered!\n");
521 exit(1);
522 }
523 }
524 else if ((permitAbbrevs && ((loc = Ambiguity(options, numOptions, name)) >= 0)) ||
525 (!permitAbbrevs && ((loc = LookUp(options, numOptions, name)) >= 0))) {
526 /* It is a conventional "LookUpAndStore" operation */
527 temp = malloc((unsigned)(strlen(value) + 1));
528 temp = strcpy(temp, value);
529 *(options[loc].value) = temp;
530 return (TRUE);
531 }
532 else {
533 if (loc == AMBIGUOUS) {
534 #if defined( PC )
535 (void) fprintf(stderr,
536 "ERROR: The name %s is AMBIGUOUS, and the value %s has not been assigned to any option\n", name, value);
537 exit(1);
538 #else
539 (void) fprintf(stderr,
540 "WARNING: The name %s is AMBIGUOUS, and the value %s has not been assigned to any option\n", name, value);
541 return (AMBIGUOUS);
542 #endif
543 }
544 else
545 return (FALSE);
546 }
547
548
549 }
550
551
552 /* ---------------------------------------------------------------------------------
553
554 Skip Blanks and Tabs. Stop at a printable character or a newline or null.
555
556 --------------------------------------------------------------------------------- */
557 char *skipBlanks (ptr)
558 char *ptr;
559 {
560 while ((*ptr == BLANK_CHARACTER) || (*ptr == TAB_CHARACTER)) ptr++;
561
562 return (ptr);
563 }
564
565
566 /* ---------------------------------------------------------------------------------
567
568 Ensure that the next character is an '='. If it is, return a pointer to the first
569 character after the '='; otherwise, return NULL.
570
571 --------------------------------------------------------------------------------- */
572 char *skipEquals (ptr)
573 char *ptr;
574 {
575 if (ptr[0] == EQUALS_CHARACTER)
576 return (++ptr);
577 else
578 return (NULL);
579 }
580
581
582 /* ---------------------------------------------------------------------------------
583
584 Read a name (ie. a token, a contiguous sequence of nonblank characters, or a
585 quoted string) from the string pointed to by ptr, and copy it the buffer pointed
586 to by <name>. If successful, return a pointer to the character after the token;
587 otherwise, return NULL.
588
589 --------------------------------------------------------------------------------- */
590 char *getName (ptr, name)
591 char *ptr, *name;
592 {
593 char *temp, *i, *namePtr;
594 char stopChar;
595
596 if (ptr[0] == DOUBLE_QUOTE_CHAR) {
597 ptr++;
598 stopChar = DOUBLE_QUOTE_CHAR;
599 }
600 else
601 stopChar = BLANK_CHARACTER;
602
603 temp = ptr;
604
605 while (*temp != NULL_CHARACTER &&
606 *temp != NEWLINE_CHARACTER &&
607 *temp != CARRIAGE_RETURN &&
608 ((stopChar == DOUBLE_QUOTE_CHAR && *temp != stopChar) ||
609 (stopChar == BLANK_CHARACTER &&
610 (*temp != stopChar && *temp != TAB_CHARACTER && *temp != EQUALS_CHARACTER))))
611 temp++;
612
613 if (stopChar == DOUBLE_QUOTE_CHAR && *temp != DOUBLE_QUOTE_CHAR) {
614 (void) fprintf(stderr, "options: Improperly closed quoted string %s\n", --ptr);
615 return (NULL);
616 }
617
618 namePtr = name;
619
620 for (i = ptr; i < temp; )
621 *namePtr++ = *i++;
622
623 *namePtr = NULL_CHARACTER;
624
625 if (stopChar == DOUBLE_QUOTE_CHAR)
626 temp++;
627
628
629 return (temp);
630
631 }
632
633
634 /* ------------------------------------------------------------------------------
635
636 Read lines from the specified file, updating option settings as appropriate.
637
638 Edits: 29th March 1989 (Paul Manson) Altered so that trailing comments allowed.
639
640 ------------------------------------------------------------------------------ */
641 void processOptionFile (options, numOptions, OptionFile, theOptionFileName,
642 limitedChars, checkOptions, programName)
643 Option options[] ;
644 int numOptions ;
645 FILE *OptionFile ;
646 char *theOptionFileName;
647 int limitedChars ;
648 int checkOptions ;
649 char *programName ;
650 {
651 int result ;
652 char name[MAX_NAME_LENGTH] ;
653 char value[MAX_NAME_LENGTH] ;
654 char *line, *linePtr;
655 int maxCharsToRead ;
656 int totalCharsRead ;
657
658 result = EOF;
659 totalCharsRead = 0 ;
660 line = malloc((unsigned) MAX_LINE_LENGTH + 1);
661
662 maxCharsToRead = ((limitedChars) ? (min(MAX_LINE_LENGTH, limitedChars)) :
663 MAX_LINE_LENGTH);
664
665 while (maxCharsToRead > 0 && ((line = fgets(line, maxCharsToRead + 1,
666 OptionFile)) != NULL)) {
667
668 if (line[0] == NULL_CHARACTER)
669 break; /* In the case of a Option Header */
670 else
671 if (limitedChars) {
672 totalCharsRead += strlen(line);
673 maxCharsToRead = min(MAX_LINE_LENGTH, limitedChars - totalCharsRead);
674 }
675
676 linePtr = skipBlanks(line);
677
678 /* Check for Comments and Blank Lines */
679 if ((linePtr[0] == COMMENT_CHARACTER) ||
680 (linePtr[0] == NEWLINE_CHARACTER) ||
681 (linePtr[0] == CARRIAGE_RETURN ) ||
682 (linePtr[0] == NULL_CHARACTER))
683 continue;
684
685 if ((linePtr = getName(linePtr, name)) == NULL) {
686 (void) fprintf(stderr, "options: Missing or Invalid name\n");
687 result = ERROR_RESULT;
688 break;
689 }
690 linePtr = skipBlanks(linePtr);
691 if ((linePtr = skipEquals(linePtr)) == NULL) {
692 (void) fprintf(stderr, "options: Expected an '=' after the name %s\n", name);
693 result = ERROR_RESULT;
694 break;
695 }
696 linePtr = skipBlanks(linePtr);
697 if ((linePtr = getName(linePtr, value)) == NULL) {
698 (void) fprintf(stderr,
699 "options: Missing or Invalid value; name is %s\n", name);
700 result = ERROR_RESULT;
701 break;
702 }
703 linePtr = skipBlanks(linePtr);
704 if ((*linePtr != NEWLINE_CHARACTER) &&
705 (*linePtr != NULL_CHARACTER) &&
706 (*linePtr != COMMENT_CHARACTER) &&
707 (*linePtr != CARRIAGE_RETURN)) {
708 (void) fprintf(stderr,
709 "options: Detected Trailing Garbage in the line %s = %s\n",
710 name, value);
711 result = ERROR_RESULT;
712 break;
713 }
714
715 if (!LookUpAndStore(options, numOptions, name, value, checkOptions, programName) &&
716 checkOptions) {
717 (void) fprintf(stderr, "options: Could not find Option Called %s\n",
718 name);
719 result = ERROR_RESULT;
720 break;
721 }
722
723 }
724
725 if (result != EOF) {
726 (void) fprintf(stderr,"options: Error reading the Option File %s\n",
727 theOptionFileName);
728 (void) fprintf(stderr,"options: Remainder of File is as follows;\n");
729 (void) fputs(line, stderr);
730 while ((line = fgets(line, MAX_LINE_LENGTH, OptionFile)) != NULL)
731 (void) fputs(line, stderr);
732 exit(1);
733 }
734 }
735
736
737 /* ------------------------------------------------------------------------------
738
739 OnLine Help Facility. This is simply the default handler which is to be called
740 if the user specifies no replacement handler.
741
742 ------------------------------------------------------------------------------ */
743 static void defaultHelpHandler(options, numOptions, progName)
744 Option options[] ;
745 int numOptions;
746 char *progName ;
747 {
748 register int help, res;
749
750 if (helpOnOneRequired) {
751 res = helpOnOneLocation;
752 (void) fprintf(stdout, "%-13s %-9s %-9s %s\n", options[res].name,
753 ((*(options[res].value) == NULL) ? ("") : (*(options[res].value))),
754 ((options[res].defaultValue == NULL) ? ("") : (options[res].defaultValue)),
755 ((options[res].comment == NULL) ? ("") : (options[res].comment)));
756 return;
757 }
758
759 help = -1;
760 for (res = 0; res < numOptions; res++)
761 if (strcmp(options[res].name, HELP_STRING) == 0) {
762 help = res;
763 break ;
764 };
765
766
767 /************* Print head of help menu *****************/
768 if (help < 0) {
769 (void) fprintf(stdout, "The Rotter who wrote the `%s' program hasn't provided any \n",
770 progName);
771 (void) fprintf(stdout, "form of on-line 'help' documentation, tsk tsk!\n\n");
772 (void) fprintf(stdout,
773 "We can, however, provide you with the list of available options:\n\n");
774 }
775 else {
776
777 (void)fprintf(stdout,"%s\n", versionstr);
778 (void) fprintf(stdout,
779 "Usage: %s [options] %s\n\n", progName, options[help].comment);
780 }
781
782 (void) fprintf(stdout, "Option Name Current Default Comment\n");
783 (void) fprintf(stdout, "----------- ------- ------- -------\n");
784
785 for (res = numOptions-1 ; res >= 0 ; res-- )
786 if (options[res].classification < OutputOption &&
787 (!thereWasAnOptionsFile || helpOnAllRequired ||
788 strcmp(*(options[res].value), options[res].defaultValue) != 0 ||
789 *(options[res].value) != options[res].defaultValue))
790 (void) fprintf(stdout, "%-13s %-9s %-9s %s\n", options[res].name,
791 ((*(options[res].value) == NULL) ? ("") : (*(options[res].value))),
792 ((options[res].defaultValue == NULL) ? ("") : (options[res].defaultValue)),
793 ((options[res].comment == NULL) ? ("") : (options[res].comment)));
794
795 (void) fprintf(stdout, "\n");
796 return;
797 }
798
799 /* ----- Declare the handlerHolder variable ----- */
800
801 static helpRoutine *onLineHelpHandler = defaultHelpHandler;
802
803
804 /* ------------------------------------------------------------------------------
805
806 Spit out the options to a file (with the appropriate option file name).
807
808 Edits: 29th March 1989 (Paul Manson). For the sake of IBM/PC users, this routine
809 will now spit lines with CR/LF pairs.
810 06th April 1989 (Paul Manson). This routine is no-longer conditionally
811 compiled, but is now more widely accepted.
812
813 ------------------------------------------------------------------------------ */
814
815 void updateOptionsFile(options, numOptions, programName, resFileName)
816 Option options[] ;
817 int numOptions ;
818 char *programName;
819 char *resFileName;
820 {
821 int res ;
822 FILE *fptr;
823
824 if ((fptr = fopen(resFileName, "w")) == NULL) {
825 (void) fprintf(stderr, "Unable to Update Options File called %s.\n", resFileName);
826 exit(1);
827 }
828
829 #if defined( PC ) || defined( THINK_C )
830 (void) fprintf(fptr ,"# %s\n", versionstr);
831 (void) fprintf(fptr, "#\r\n# Options file for the %s program.\r\n#\r\n\r\n", programName);
832 (void) fprintf(fptr, "#Option Name Current Default Comment\r\n");
833 (void) fprintf(fptr, "#----------- ------- ------- -------\r\n\r\n");
834 #else
835 (void) fprintf(fptr ,"# %s\n", versionstr);
836 (void) fprintf(fptr, "#\n# Options file for the %s program.\n#\n\n", programName);
837 (void) fprintf(fptr, "#Option Name Current Default Comment\n");
838 (void) fprintf(fptr, "#----------- ------- ------- -------\n\n");
839 #endif
840
841 for (res = numOptions-1; res >=0 ; res-- )
842 if (options[res].classification < OutputOption && *(options[res].value) != NULL &&
843 (updateAllRequired ||
844 strcmp(*(options[res].value), options[res].defaultValue) != 0 ||
845 *(options[res].value) != options[res].defaultValue)) {
846 #if defined( PC )
847 (void) fprintf(fptr, "%-13s = %-9s # %-9s %s\r\n", options[res].name,
848 ((*(options[res].value) == NULL) ? ("") : (*(options[res].value))),
849 ((options[res].defaultValue == NULL) ? ("") : (options[res].defaultValue)),
850 ((options[res].comment == NULL) ? ("") : (options[res].comment)));
851 #else
852 (void) fprintf(fptr, "%-13s = %-9s # %-9s %s\n", options[res].name,
853 ((*(options[res].value) == NULL) ? ("") : (*(options[res].value))),
854 ((options[res].defaultValue == NULL) ? ("") : (options[res].defaultValue)),
855 ((options[res].comment == NULL) ? ("") : (options[res].comment)));
856 #endif
857 }
858
859 if (fclose(fptr) == EOF) {
860 (void) fprintf(stderr, "options: fclose failed on the options file %s.\n", resFileName);
861 exit(1);
862 }
863
864 thereWasAnOptionsFile = TRUE; /* Cos there is one now! */
865
866 return;
867 }
868
869
870 /* ------------------------------------------------------------------------------
871
872 Process the option file and then the command line options supplied.
873
874 Edited:
875
876 2nd March 1989 (Paul Manson). Changed the calls to OptionFileName (ie.
877 added a <prefix> argument) to facilitate
878 searching of HOME (etc) directories. Note
879 that this is IGNORED for IBM/PCs.
880
881 8th March 1989 (Paul Manson). Ignore the above, as OPTIONSPATH is now
882 used (in conjunction with search_path) to
883 enable proper paths for Unix.
884
885 10th March 1989 (Paul Manson). Added the "help" facility and the default
886 and comment stuff.
887
888 16th March 1989 (Paul Manson). Altered the final argc/argv shuffling so that
889 argv simply points at the first argument after
890 the options.
891
892 July 1994 (MAA). Mended to allow spaces in command-line strings.
893
894 ------------------------------------------------------------------------------ */
895
896
897
898
899 /* Assign the default options */
900
901 void default_nopts( options, numOptions )
902 Option options[] ;
903 int numOptions ;
904 {
905 int i ;
906
907 for (i = 0; i < numOptions; i++)
908 *(options[i].value) = options[i].defaultValue ;
909 }
910
911
912
913 /****************************************************************************
914 * Assign options from the rc file.
915 *
916 * The option file is called ".genxxxrc", where the "xxx" is determined
917 * by the name of the application, (which is in argv[0]).
918 * Here "rc" stands for "resource control".
919 * The file-name is assigned to a string ptr "theOptionFileName".
920 * On Unix, the path for the file-name is determined as follows:
921 * if environment variable OPTION_PATH is set, then use this path.
922 * else the default path is:
923 * `.' (the current directory)
924 * `~' (the users home directory)
925 * The DEFAULT_OPTION_PATH for the option file is defined "." (see above).
926 * This means look first in the current directory, and failing that in the
927 * users home directory.
928 * But these defaults can be overridden by setting an environment variable,
929 * which is defined as OPTIONSPATH (see above). Thus the user could set a
930 * new default path for option files by, eg:
931 * setenv OPTIONSPATH ".:~/rcbin"
932 * This would look first in the current directory, and failing that in a
933 * directory ~/rcbin
934 *****************************************************************************/
935
936 void rcfile_nopts( options, numOptions, file )
937 Option options[] ;
938 int numOptions ;
939 char *file ;
940 {
941 FILE *OptionFile ;
942 char *OptionPathPtr ;
943
944
945 #if defined( PC )
946 if (((OptionFile = fopen(theOptionFileName =
947 PCOptionFileName( file, TRUE ), "r")) != NULL)) {
948 /* -------------------------------------------------------------------------------------
949 Removed temporarily so the PC version ONLY examines and creates option files
950 in the cwd. This will be changed when we determine a better strategy for
951 PC directory PATH searches.
952
953 ((OptionFile = fopen(theOptionFileName =
954 PCOptionFileName( file, FALSE), "r")) != NULL)) {
955 ---------------------------------------------------------------------------------------*/
956 #else
957 if ((OptionPathPtr = (char *)getenv(OPTION_PATH)) == NULL)
958 OptionPathPtr = DEFAULT_OPTION_PATH;
959
960 if ((OptionFile = fopen(theOptionFileName =
961 search_path(UnixOptionFileName( file ),
962 OptionPathPtr), "r")) != NULL) {
963 #endif
964
965 /* Process the Option File */
966
967 (void) processOptionFile(options, numOptions, OptionFile,
968 theOptionFileName, FALSE, TRUE, file ) ;
969 (void) fclose(OptionFile);
970
971 thereWasAnOptionsFile = TRUE;
972
973 }
974 }
975
976
977 /* Assign options from the command line */
978
979 void cmd_line_nopts( options, numOptions, argc, argv )
980 Option options[] ;
981 int numOptions ;
982 int *argc ;
983 char ***argv ;
984 {
985 int i, currentArg ;
986 int finalArg, wasAHyphen ;
987 char name[MAX_NAME_LENGTH] ;
988 char value[MAX_NAME_LENGTH] ;
989 char *line, *linePtr;
990 char *tempstring; /* MAA 23-4-1994 */
991 char *tempstring2; /* MAA 23-4-1994 */
992 int count=0;
993
994
995 /* MAA: next 3 lines */
996 linePtr = (char *) calloc((size_t) MAX_NAME_LENGTH, (size_t) sizeof(char));
997 tempstring = (char *) calloc((size_t) MAX_NAME_LENGTH, (size_t) sizeof(char));
998 tempstring2 = (char *) calloc((size_t) MAX_NAME_LENGTH, (size_t) sizeof(char));
999
1000
1001 finalArg = currentArg = 1; /* Ignore the Program Name */
1002 line = malloc((unsigned) MAX_LINE_LENGTH);
1003
1004 while (currentArg < *argc) {
1005 wasAHyphen = FALSE;
1006 linePtr = strcpy(line, (*argv)[currentArg]);
1007 if (linePtr[0] == HYPHEN_CHARACTER) {
1008 wasAHyphen = TRUE;
1009 linePtr++; /* Skip any leading hyphen */
1010 }
1011
1012 /* MAA: force doublequotes onto beg & end . A rather big hack ...*/
1013 if (strchr(linePtr, BLANK_CHARACTER) != NULL){
1014 strncpy(tempstring, linePtr, (int) strcspn(linePtr, "="));
1015 strcat(tempstring, "=\"");
1016 tempstring2 = (char *) strrchr(linePtr, EQUALS_CHARACTER);
1017 tempstring2++;
1018 strcat(tempstring, tempstring2);
1019 strcat(tempstring, "\"");
1020 linePtr=tempstring;}
1021
1022
1023 if ((linePtr = getName(linePtr, name)) == NULL) {
1024 break;
1025 }
1026
1027 if ((linePtr = skipEquals(linePtr)) == NULL) {
1028 if (!wasAHyphen) {
1029 break; /* Don't interpret <name> <value> as being options */
1030 }
1031 if (strcmp(name, HELP_STRING) == 0) {
1032 #ifdef PC
1033 if (strncmp((*argv)[0]+strlen((*argv)[0])-strlen("gen.exe"), "gen", strlen("gen")) == 0)
1034 #else
1035 if (strcmp((*argv)[0], "gen") == 0)
1036 #endif
1037 /* Special case of gen -help */
1038 usageHelp();
1039 else
1040 /* Case of gen??? -help */
1041 (*onLineHelpHandler)(options, numOptions, (*argv)[0]);
1042 exit(0);
1043 }
1044
1045 if (strcmp(name, UPDATE_STRING) == 0) {
1046 /* Do the Update and Then Goto the Top of the Loop Again */
1047 updateOptionsFile(options, numOptions, (*argv)[0], theOptionFileName);
1048 finalArg = ++currentArg;
1049 continue;
1050 }
1051
1052 (void) strcpy(value, DEFAULT_TOGGLE_VALUE);
1053 }
1054 else {
1055 if ((linePtr = getName(linePtr, value)) == NULL) {
1056 break;
1057 }
1058 }
1059
1060 if(!LookUpAndStore(options, numOptions, name, value, TRUE, (*argv)[0])) {
1061 (void) fprintf(stderr,"options: Could not find an Option called %s\n", name);
1062 exit(1);
1063 }
1064
1065 finalArg = ++currentArg;
1066 }
1067
1068 /* Reset the Command Line argc and argv */
1069 /* The Original Version actually cut the options out of the argv array (by
1070 shifting the remaining arguments left), but the new version simply lets
1071 argv point to the next argument to be processed.
1072
1073 if (finalArg > 1) {
1074 for (i = finalArg; i < *argc; i++)
1075 (*argv)[i - finalArg + 1] = (*argv)[i];
1076 *argc = *argc - finalArg + 1;
1077 }
1078
1079 */
1080
1081 *argv+= finalArg;
1082 *argc = *argc - finalArg;
1083
1084 return;
1085 }
1086
1087
1088
1089 /* Assign options using defaults, then the rc file, then the command line */
1090
1091 void getnopts (options, numOptions, argc, argv)
1092 Option options[] ;
1093 int numOptions ;
1094 int *argc ;
1095 char ***argv ;
1096 {
1097 default_nopts( options, numOptions ) ;
1098 rcfile_nopts( options, numOptions, (*argv)[0] ) ;
1099 cmd_line_nopts( options, numOptions, argc, argv ) ;
1100 }
1101
1102
1103
1104 /* -------------------------------------------------------------------------------
1105
1106 Read an option header from the specified file into the given options array.
1107
1108 ------------------------------------------------------------------------------- */
1109 void readnopts(options, numOptions, filePointer)
1110 Option options[] ;
1111 int numOptions;
1112 FILE *filePointer ;
1113 {
1114 long filePosition ;
1115 char first[200] ;
1116 int headerLength ;
1117
1118 filePosition = ftell(filePointer); /* Save the Original Position */
1119
1120 /* Read the first line of the first block, or as much of it as possible */
1121
1122 if ((!fread(first, 1, strlen(OptionHeaderHeader) + OPTION_HEADER_DIGITS
1123 + strlen(LineFeedArray), filePointer)) ||
1124 (strncmp(first, OptionHeaderHeader, strlen(OptionHeaderHeader)) != 0)) {
1125 /* Assume that this is NOT a option header */
1126 if (fseek(filePointer, filePosition, 0)) {
1127 (void) fprintf(stderr, "options: Error fseeking Option Header File\n");
1128 exit(1);
1129 }
1130 return;
1131 }
1132
1133 /* Extract the Header Length in Bytes */
1134
1135 headerLength = atoi(first + strlen(OptionHeaderHeader));
1136
1137 /* Now, process the stuff. Need to "seek" past the first line before
1138 attempting to read anything, and shorten the headerLength accordingly */
1139
1140 (void) processOptionFile(options, numOptions, filePointer,
1141 "Unknown Option File",
1142 (headerLength - strlen(OptionHeaderHeader) -
1143 OPTION_HEADER_DIGITS - strlen(LineFeedArray)),
1144 FALSE, "???");
1145
1146 /* Make sure that the file pointer is set to the data area */
1147
1148 if (fseek(filePointer, filePosition + headerLength, 0)) {
1149 (void) fprintf(stderr, "options: Error fseeking Option Header File\n");
1150 exit(1);
1151 }
1152
1153 }
1154
1155
1156 /* -------------------------------------------------------------------------------
1157
1158 Count the number of bytes which will be written by writenopts, given the
1159 options array.
1160
1161 ------------------------------------------------------------------------------- */
1162 static int countBytesToWrite( options, numOptions )
1163 Option options[] ;
1164 int numOptions;
1165 {
1166 int sum, i;
1167
1168 sum = 0;
1169
1170 for (i = 0; i < numOptions; i++)
1171 if((options[i].classification == OutputOption ||
1172 options[i].classification == InOutOption) &&
1173 *(options[i].value) != NULL &&
1174 strcmp(*(options[i].value), NULL_STRING) != 0)
1175 sum += strlen(options[i].name) + strlen(EqualsArray) +
1176 strlen(*(options[i].value)) + strlen(LineFeedArray); /* + (2 * strlen(QuotesArray)); */
1177
1178 return (sum);
1179 }
1180
1181 /* -------------------------------------------------------------------------------
1182
1183 The descendent of the lost and lamented blockCopyStrToFile... writes a string
1184 to the indicated file.
1185
1186 ------------------------------------------------------------------------------- */
1187 static void WriteStringToFile(str, filePtr)
1188 char *str;
1189 FILE *filePtr;
1190 {
1191 if (!fwrite(str, 1, strlen(str), filePtr)) {
1192 (void) fprintf(stderr, "WriteStringToFile: Error printing %s to file.\n", str);
1193 exit(1);
1194 }
1195
1196 return;
1197 }
1198
1199
1200 /* -------------------------------------------------------------------------------
1201
1202 Write an option header to the specified file from the information contained
1203 in the given options array. Remove the comments to get debugging info.
1204
1205 ------------------------------------------------------------------------------- */
1206 void writenopts(options, numOptions, filePointer)
1207 Option options[] ;
1208 int numOptions;
1209 FILE *filePointer ;
1210 {
1211 /*int bytesWritten ;*/
1212 int i ;
1213 long filePosition ;
1214 int bytesToWrite ;
1215 int oddHeaderLength ;
1216 char DigitString[OPTION_HEADER_DIGITS + 2];
1217
1218 filePosition = ftell(filePointer);
1219
1220 bytesToWrite = countBytesToWrite(options, numOptions) +
1221 strlen(OptionHeaderHeader) + OPTION_HEADER_DIGITS +
1222 strlen(LineFeedArray) + 1;
1223
1224 if (oddHeaderLength = (bytesToWrite % 2))
1225 bytesToWrite++;
1226
1227 (void) WriteStringToFile(OptionHeaderHeader, filePointer);
1228
1229 (void) sprintf(DigitString, "%0*d", OPTION_HEADER_DIGITS, bytesToWrite);
1230
1231 /*(void) printf("bytesToWrite is %i.\n", bytesToWrite);*/
1232
1233 (void) WriteStringToFile(DigitString, filePointer);
1234
1235 (void) WriteStringToFile(LineFeedArray, filePointer);
1236
1237 /* Copy all of the Options */
1238
1239 for (i = 0; i < numOptions; i++) {
1240
1241 if((options[i].classification == OutputOption ||
1242 options[i].classification == InOutOption) &&
1243 *(options[i].value) != NULL &&
1244 strcmp(*(options[i].value), NULL_STRING) != 0) {
1245
1246 (void) WriteStringToFile(options[i].name, filePointer);
1247
1248 (void) WriteStringToFile(EqualsArray, filePointer);
1249
1250 /* (void) WriteStringToFile(QuotesArray, filePointer); */
1251
1252 (void) WriteStringToFile(*(options[i].value), filePointer);
1253
1254 /* (void) WriteStringToFile(QuotesArray, filePointer); */
1255
1256 (void) WriteStringToFile(LineFeedArray, filePointer);
1257 }
1258 }
1259
1260 if (fputc(NULL_CHARACTER, filePointer) == EOF) {
1261 (void) fprintf(stderr, "writenopts: Error doing fputc of the last NULL character.\n");
1262 exit(1);
1263 }
1264
1265 if (oddHeaderLength && fputc(NULL_CHARACTER, filePointer) == EOF) {
1266 (void) fprintf(stderr, "writenopts: Error doing fputc of the odd-pad NULL character.\n");
1267 exit(1);
1268 }
1269
1270 if (fflush(filePointer)) {
1271 (void) fprintf(stderr, "options: Error while flushing the option header\n");
1272 exit(1);
1273 }
1274
1275 /* seek the fileptr to after the last byte of the header */
1276
1277 if (filePointer != stdout) {
1278 if (fseek(filePointer, filePosition + (long)bytesToWrite, 0)) {
1279 (void) fprintf(stderr, "options: Error fseeking Option Header File\n");
1280 exit(1);
1281 }
1282 }
1283
1284 }
1285
1286
1287 /* ----------------------------------------------------------------------------
1288
1289 A Little Routine to Count the Options in a Options Array .... This MUST
1290 Be NULL-Terminated ...... OR ELSE!
1291
1292 ---------------------------------------------------------------------------- */
1293
1294 static int countOptions(options)
1295 Option options[];
1296 {
1297 int numoptions;
1298
1299 for (numoptions = 0;
1300 options[numoptions].name != NULL; /* DEATH TO ALL WHO TREAD HERE! */
1301 numoptions++);
1302
1303 return (numoptions);
1304
1305 }
1306
1307
1308 /* -------------------------------------------------------------------------------
1309
1310 The Counting version of getnopts -- you MUST null-terminate the options array.
1311
1312 ------------------------------------------------------------------------------- */
1313
1314 void getopts (options, argc, argv)
1315 Option options[] ;
1316 int *argc ;
1317 char ***argv ;
1318 {
1319 (void) getnopts(options, countOptions(options), argc, argv);
1320 }
1321
1322
1323 void cmd_line_opts(options, argc, argv)
1324 Option options[] ;
1325 int *argc ;
1326 char ***argv ;
1327 {
1328 (void) cmd_line_nopts( options, countOptions(options), argc, argv ) ;
1329 }
1330
1331
1332
1333 /* -------------------------------------------------------------------------------
1334
1335 The Counting version of readnopts -- you MUST null-terminate the options array.
1336
1337 ------------------------------------------------------------------------------- */
1338 void readopts(options, filePointer)
1339 Option options[] ;
1340 FILE *filePointer ;
1341 {
1342 (void) readnopts(options, countOptions(options), filePointer);
1343 }
1344
1345 /* -------------------------------------------------------------------------------
1346
1347 The Counting version of writenopts -- you MUST null-terminate the options array.
1348
1349 ------------------------------------------------------------------------------- */
1350 void writeopts(options, filePointer)
1351 Option options[] ;
1352 FILE *filePointer ;
1353 {
1354 (void) writenopts(options, countOptions(options), filePointer);
1355 }
1356
1357
1358 /* -------------------------------------------------------------------------------
1359
1360 Packaging for convenience -- Guaranteed to be Listeria-free!
1361
1362 ------------------------------------------------------------------------------- */
1363
1364 FILE *fileopts( res, argc, argv )
1365 Option *res ;
1366 int *argc ;
1367 char **argv[];
1368 {
1369 FILE *ifp ;
1370 int numOptions;
1371 #if defined( PC )
1372 char *progName ;
1373
1374 progName = (*argv)[0];
1375 #endif
1376
1377 numOptions = countOptions(res);
1378
1379 getnopts( res, numOptions, argc, argv ) ;
1380
1381 if( *argc > 0 ) {
1382 if((ifp = fopen( **argv, "r" )) == NULL) {
1383 (void) fprintf(stderr, "Unable to open the file %s.\n", **argv);
1384 exit(1);
1385 }
1386 }
1387 else
1388 #if defined( PC )
1389 {
1390 /* PCs cannot take binmode files through standard input */
1391 (void) (*onLineHelpHandler)( res, numOptions, progName );
1392 exit(1);
1393 }
1394 #else
1395 ifp = stdin ;
1396 #endif
1397
1398 (*argv)++ ;
1399 (*argc)-- ;
1400
1401 readopts( res, ifp ) ;
1402
1403 return( ifp ) ;
1404
1405 }
1406
1407
1408 /* -------------------------------------------------------------------------------
1409
1410 Packaging for convenience -- Guaranteed to be Listeria-free!
1411
1412 ------------------------------------------------------------------------------- */
1413 FILE *optoutput(str)
1414 char *str;
1415 {
1416 FILE *f;
1417
1418 if (str == NULL)
1419 return (NULL);
1420 else if (str == DEFAULT_TOGGLE_VALUE)
1421 return (stdout);
1422
1423 if ((f = fopen(str, "w")) == NULL) {
1424 (void) fprintf(stderr, "options: Could not open the file %s for output.\n", str);
1425 exit(1);
1426 }
1427 return (f);
1428 }
1429
1430
1431 /* -------------------------------------------------------------------------------
1432
1433 OnLine Help from the user program.
1434
1435 ------------------------------------------------------------------------------- */
1436 void helpnopts(res, numRes, name)
1437 Option res[];
1438 int numRes;
1439 char *name ;
1440 {
1441 (void) (*onLineHelpHandler)(res, numRes, name);
1442 }
1443
1444 /* -------------------------------------------------------------------------------
1445
1446 OnLine Help from the user program. (counting version)
1447
1448 ------------------------------------------------------------------------------- */
1449 void helpopts(res, name)
1450 Option res[];
1451 char *name ;
1452 {
1453 #ifdef PC
1454 if (strncmp(name+strlen(name)-strlen("gen.exe"), "gen", strlen("gen")) == 0)
1455 #else
1456 if (strcmp(name, "gen") == 0)
1457 #endif
1458 /* Special case of gen */
1459 usageHelp();
1460 else
1461 /* Case of gen??? */
1462 (void) (*onLineHelpHandler)(res, countOptions(res), name);
1463 }
1464
1465
1466 /* ---------------------------------------------------------------------------------
1467
1468 Allows an application program to install its very own helpHandler routine to
1469 override the default help-message handler. The behaviour of such a routine is
1470 implicitly trusted by <options>, so you should only install your own handler
1471 when you are quite familiar with the Options structure format. This routine
1472 returns the address of the previously installed handler (which is initially the
1473 default handler) so that this may be reinstated at a later point.
1474
1475 ---------------------------------------------------------------------------------- */
1476
1477 helpRoutine *helpOptsHandler(aHelpRoutine)
1478 helpRoutine *aHelpRoutine;
1479 {
1480 helpRoutine *temp;
1481
1482 temp = onLineHelpHandler;
1483
1484 onLineHelpHandler = aHelpRoutine;
1485
1486 return (temp);
1487 }
1488
1489
1490 /* ---------------------------------------------------------------------------------
1491
1492 A convenience call which returns TRUE (1) if the optionStr is what options thinks
1493 of as "ON", "YES", "TRUE", or "1".... This merely allows us to hide the actual
1494 implementation of "ON" from the application programs.
1495
1496 --------------------------------------------------------------------------------- */
1497
1498 int isOFF(optionStr)
1499 char *optionStr;
1500 {
1501 return (strcmp(OFF_STRING, optionStr) == 0 ||
1502 strcmp(OFF_ALIAS , optionStr) == 0 ||
1503 strcmp(NOT_USED , optionStr) == 0);
1504 }
1505
1506
1507 /* ---------------------------------------------------------------------------------
1508
1509 A convenience call which returns TRUE (1) if the optionStr is what options thinks
1510 of as "NULL", "NONE", nothing, zip, etc... This merely allows us to hide the actual
1511 implementation of "NULL" from the application programs.
1512
1513 --------------------------------------------------------------------------------- */
1514
1515 int isNULL(optionStr)
1516 char *optionStr;
1517 {
1518 return (optionStr == NULL ||
1519 strcmp(NULL_STRING, optionStr) == 0 ||
1520 strcmp(NULL_ALIAS , optionStr) == 0);
1521 }
1522
1523
1524 /* ---------------------------------------------------------------------------------
1525
1526 A routine to reduce the load on the application programmer by providing a simple
1527 boolean check for string equality WITHOUT CASE SIGNIFICANCE. This allows applications
1528 to leave case and typing problems within "options" reliably.
1529
1530 --------------------------------------------------------------------------------- */
1531
1532 static char *stringToLowerCase(str)
1533 char *str;
1534 {
1535 register int i;
1536
1537 if (str == NULL)
1538 return (str);
1539 else {
1540 for (i = 0; str[i] != NULL_CHARACTER; i++)
1541 if (isupper((char) str[i]))
1542 str[i] = (char) tolower((char) str[i]);
1543 return (str);
1544 }
1545 }
1546
1547 extern int OptionStringsEqual(str1, str2)
1548 char *str1, *str2;
1549 {
1550 /* This routine copies the strings into two local buffers, converts them to
1551 lower case, and then compares them for equality. This local copy ensures
1552 that they are automatically deallocated on function return */
1553
1554 #define MAX_COPY_LENGTH (256)
1555
1556 char lc1[MAX_COPY_LENGTH], lc2[MAX_COPY_LENGTH];
1557
1558 if (strlen(str1) < MAX_COPY_LENGTH &&
1559 strlen(str2) < MAX_COPY_LENGTH)
1560 return (strcmp(stringToLowerCase(strcpy(lc1, str1)),
1561 stringToLowerCase(strcpy(lc2, str2))) == 0);
1562 else {
1563 (void) fprintf(stderr, "options: OptionStringsEqual() could not compare the strings %s and %s becaues one was more that %i characters long.\n", str1, str2, MAX_COPY_LENGTH);
1564 exit(1);
1565 }
1566 }
1567
1568
1569
1570 /* Print general usage information in response to: gen -help */
1571 usageHelp()
1572 {
1573 (void)fprintf(stdout,"%s\n\n", versionstr);
1574
1575 (void) fprintf(stdout, "Usage: genXXX [options] [file_name]\n");
1576 (void) fprintf(stdout, " where XXX is one of the following abbreviations:\n\n\
1577 wav waveform \n\
1578 bmm basilar membrane motion \n\
1579 nap neural activity pattern \n\
1580 sai stabilized auditory image \n\
1581 spl spiral version of auditory image \n\
1582 sgm spectrogram \n\
1583 cgm cochleogram " ) ;
1584 (void) fprintf(stdout, "\n\
1585 asa auditory spectral analysis \n\
1586 epn excitation pattern \n\n");
1587
1588 (void) fprintf(stdout, " [file_name] is a headerless wave file (2-byte binary integers).\n");
1589 (void) fprintf(stdout, " [options] are parameters, options and swtiches that control\n");
1590 (void) fprintf(stdout, " the AIM instructions and the AIM tools.\n\n");
1591
1592 (void) fprintf(stdout, " Help with options: genXXX [-help | -help=all | -help=option]\n");
1593 #if !defined( PC )
1594 (void) fprintf(stdout, " Path for options file, (.genXXXrc) = . (or setenv OPTIONSPATH)\n\n");
1595 #endif
1596
1597 (void) fprintf(stdout, "Processes Applied by AIM and Routes Through the Model: \n\n\
1598 Process Auditory Speech Spectra \n\
1599 -------------------------------- -------- ------ ------- \n\
1600 Display input wave genwav genwav genwav \n\
1601 Auditory filtering (gtf/tlf) genbmm \n\
1602 Compression and rectification gensgm genasa " ) ;
1603
1604 (void) fprintf(stdout, "\n\
1605 Neural encoding (2D-AT/haircell) gennap \n\
1606 Temporal integration (LP filter) gencgm genepn \n\
1607 Strobed temporal integration gensai \n\
1608 Spiral mapping of auditory image genspl \n\n");
1609
1610 (void) fprintf(stdout, "Output: genXXX output=on file_name \n");
1611 (void) fprintf(stdout, " output is written to file: file_name.XXX \n");
1612
1613 (void) fprintf(stdout, "\n\
1614 The format for 2-dimensional output format is by columns, with the \n\
1615 lowest channel first in each column (bmm, nap, sgm, cgm, asa, epn).\n\
1616 The format for auditory image output is by rows, for each image frame \n\
1617 in succession, with the row of the lowest channel first (sai, spl).\n\n");
1618
1619 (void) fprintf(stdout, "The Auditory Image Model was developed at the Applied Psychology Unit\n");
1620 (void) fprintf(stdout, "of the Medical Research Council, 15 Chaucer Road, Cambridge, U.K.\n\n");
1621
1622 (void) fprintf(stdout, "Copyright(c) Applied Psychology Unit, Medical Research Council, 1988-1995.\n");
1623
1624 }