Mercurial > hg > aim92
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 } |