Mercurial > hg > aim92
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/glib/options.c Fri May 20 15:19:45 2011 +0100 @@ -0,0 +1,1624 @@ +/* + Copyright (c) Applied Psychology Unit, Medical Research Council. 1988, 1989 + =========================================================================== + + Permission to use, copy, modify, and distribute this software without fee + is hereby granted for research purposes, provided that this copyright + notice appears in all copies and in all supporting documentation, and that + the software is not redistributed for any fee (except for a nominal shipping + charge). Anyone wanting to incorporate all or part of this software in a + commercial product must obtain a license from the Medical Research Council. + + The MRC makes no representations about the suitability of this + software for any purpose. It is provided "as is" without express or implied + warranty. + + THE MRC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE + A.P.U. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY + DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/* ------------------------------------------------------------------------------- + + The Leanest Resource Manager in the West. + + Options may be supplied as defaults (actually in the code), as command line + arguments, and in a option file. The default arguments may be overridden by + the option-file contents, which may be overridden from the command line. + + Copyright (c), 1989 The Medical Research Council of the United Kingdom. + + Author : Paul Manson + Written : March 1st 1989 + + Edited : + + 2nd March 1989 (Paul Manson) Added the facility of searching the HOME directory + for a option file if one is not found in the + working directory. + + 8th March 1989 (Paul Manson) Enhanced the above by providing a OPTIONPATH + search strategy for Unix. Currently MSDOS only + searches for a option file in the directory + where the program was found. + + 8th March 1989 (Paul Manson) Added the ability to refer to options via + abbreviations of their names. At present, an abbrev. + will match if it is exactly the same as precisely one + option, or if it is the same as the first <n> chars + of that option (where <n> is the length of the + abbrev) and it matches no other option name. + + 9th March 1989 (Paul Manson) Added the readopts and writeopts calls, to implement + option headers for files. Also altered the form + of command line options accepted: See getopts.h for + details. + + 10th March 1989 (Paul Manson) Added the "help" facility to provide a simple + self-documentation facility. Also altered the + Option type to put defaults and comments in + the code. + + 16th March 1989 (Paul Manson) Altered the final argc/argv shuffling in getopts + so that argv simply points at the first argument + after the options. Also added fileopts. + + 29th March 1989 (Paul Manson) Altered ".res" to ".opt" to coincide with the new + naming r'egime. Also added the spitOptionsFile call + to automatically produce an options file with + comments. To enable this facility, compile getopts + with -DSPITHELP; to use it, type <prog> -spit. Do + NOT distribute a spitting version of getopts! Altered + Options-file scanning to permit trailing comments. + + 30th March 1989 (Paul Manson) Completely eradicated the blockWriteToFile used by + writenopts. This is now done on a non-aligned basis, + as this is likely to be quicker and less complex. + + 03rd April 1989 (Paul Manson) Added the calll to outputopt. + + 06th April 1989 (Paul Manson) Oh Joy! Oh Bliss! The once-much-maligned SPIT option + is recieved into decent society, albeit in the guise + of an options "editor" called 'update'. + + 10th April 1989 (Paul Manson) The 'update' option no longer exit(1)s, but + carries on to execute the program. Also changed + OptionFileName so that it correctly gets the + cwd on the PC. + + 11th April 1989 (Paul Manson) Altered the OptionFileName routines to be EITHER + for the PC or for Unix. + + 26th April 1989 (Paul Manson) Put in a temporary delta to the PC version so that it + only looks for option files (and hence only creates + option files) in the current directory. This will be + abandoned when we determine a better search strategy. + + 15th June 1989 (Paul Manson) Altered SilentOption so that it is alterable, but is + NOT visible in any way (ie. not printed by help or + spit, and not output to headers). + + 11th July 1989 (Paul Manson) Altered so that "help" (and "update") only display + (or output) the options which were either read in + from the options file, or have been subsequently + altered on the command line. The current implementation + simply checks to see whether the default and current + values for a particular option differ (either in value + OR address!). + + 27th July 1989 (Paul Manson) Altered so that isON == !isOFF, and not the other way + around -- this allows "2", "3", etc to masquerade as + "1" while only "0" is "off". Also changed so that no + quotes are output to file headers. + + + July 1994 (MAA) Allowed spaces in strings, by adding double-quotes + to the arguments. Bit of a hack, though. + ------------------------------------------------------------------------------- */ + +#include "options.h" +#include <stdio.h> +#include <string.h> +#if defined( NeXT) +#include <stdlib.h> +#else +#include <malloc.h> +#endif +#include <ctype.h> + +#if !defined( lint ) +static char *sccs_id = "@(#)options.c 1.14 Paul Manson (MRC-APU) 5/2/89"; +#endif + +char defversion[64] = "not set yet" , *versionstr = defversion ; + +#if defined( PC ) +#include <direct.h> +#define DOT '.' +#define BACKSLASH_CHAR '\\' +#define SLASH_CHARACTER '/' +#define OPTION_FILE_PREFIX "" +#define OPTION_FILE_SUFFIX ".opt" +#else +#ifndef THINK_C +#include <sys/types.h> +#include <sys/stat.h> +#endif +#define OPTION_FILE_PREFIX "." +#define OPTION_FILE_SUFFIX "rc" +#define OPTION_PATH "OPTIONSPATH" + /* Environment variable for path */ +#define DEFAULT_OPTION_PATH "." + /* Path is first . then ~ (ie home) */ +#endif + +#define MAX_LINE_LENGTH (256) +#define MAX_NAME_LENGTH (128) +#define FALSE (0) +#define TRUE (1) +#define HYPHEN_CHARACTER '-' +#define BLANK_CHARACTER ' ' +#define TAB_CHARACTER '\t' +#define NEWLINE_CHARACTER '\n' +#define DOUBLE_QUOTE_CHAR '\"' +#define ERROR_RESULT (1234) +#define EQUALS_CHARACTER '=' +#define COMMENT_CHARACTER '#' +#define NULL_CHARACTER '\000' +#define CARRIAGE_RETURN '\r' + +/* Options-specific definitions for "ON", "OFF" and "NULL" */ + +#define ON_STRING (ON_OPTION) +#define ON_ALIAS "1" + +#define OFF_STRING (OFF_OPTION) +#define OFF_ALIAS "0" + +#define NULL_STRING (NULL_OPTION) +#define NULL_ALIAS "null" + +#define NOT_USED "Not_used" + +/* For the search_path and Ambiguity procedures */ + +#define LINE_CHARS 200 +#define AMBIGUOUS (-2) +#define NO_MATCH (-1) +#define DEFAULT_TOGGLE_VALUE (ON_STRING) + +/* For the readopts and writeopts procedures */ + +#define OPTION_HEADER_SIZE ( sizeof ( head_string_start ) - 1 + size_digits + 1 ) +#define OPTION_HEADER_HEADER "header_bytes=" +#define OPTION_HEADER_DIGITS (7) + +#define min(X,Y) (((X) < (Y)) ? (X) : (Y)) + +static char OptionHeaderHeader[] = OPTION_HEADER_HEADER; +static char LineFeedArray[] = "\n"; +static char EqualsArray[] = "="; /* Was " = " */ +static char QuotesArray[] = "\""; + +/* For the OnLine Help Facility */ + +#define HELP_STRING "help" +#define UPDATE_STRING "update" +#define ALL_STRING "all" + +static int helpOnAllRequired = FALSE; +static int helpOnOneRequired = FALSE; +static int helpOnOneLocation = 0; +static int updateAllRequired = FALSE; + +extern void exit(); +static int thereWasAnOptionsFile = FALSE; +static char *theOptionFileName = NULL; + + + + +#ifndef PC +/* ----------------------------------------------------------------------- + + search_path( file, path ) + ========================= + + jwh - 4th jan 1987 + + searches through string path for file and returns full file name if it + finds it. Returns NULL if file is not found. Path is specified in normal + path format i.e. "dir1:dir2:dir3...". Works for "~" and "~/dir.." - + substitutes HOME for "~". ~ only works for current user!! + + ----------------------------------------------------------------------- */ + + +static char *search_path( file, path ) +char *file, *path ; +{ +#ifdef THINK_C + return ( file ) ; +#else + char file_name[ LINE_CHARS ] ; + int len_next ; + struct stat buf ; + extern getenv(); + char *home_directory = (char *)getenv("HOME"); + + if( file[ 0 ] == '/' || file[ 0 ] == '.' && file[ 1 ] == '/' ) + return ( strcpy( malloc((unsigned)(strlen(file) + 1)), file) ); + + do + { + len_next = ( strchr( path, ':' ) == NULL ) ? + strlen( path ) : strchr( path, ':' ) - path ; + + if( *path == '~' ) + { + (void) strcpy( file_name, home_directory ) ; + (void) strncpy( file_name + strlen( home_directory ), path+1, + len_next-1 ) ; + (void) sprintf( file_name + strlen( home_directory ) + len_next - 1 , + "/%s", file ) ; + } + else + { + (void) strncpy( file_name, path, len_next ) ; + (void) sprintf( file_name + len_next , "/%s", file ) ; + } + + if( stat( file_name, &buf ) >= 0 && ( buf.st_mode & S_IFDIR ) == 0 ) + return ( strcpy( malloc((unsigned)(strlen(file_name) + 1)), file_name) ); + + path = path + len_next + 1 ; + } + while( path[ -1 ] != '\0' ) ; + + /* return( NULL ) ; */ return( file ); /* If PATH is NULL, return FILE */ +#endif +} + +/* --------------------------------------------------------------------------------- + + Return the Option File Name, given the Name of the Application (Unix Version) + + Edited: + + --------------------------------------------------------------------------------- */ +char *UnixOptionFileName(appn) + char *appn ; +{ + char *temp; + + temp = malloc((unsigned) (strlen(appn) + strlen(OPTION_FILE_SUFFIX) + + strlen(OPTION_FILE_PREFIX) + 1)); + + temp = strcpy(temp,OPTION_FILE_PREFIX); + temp = strcat(temp,appn); + temp = strcat(temp,OPTION_FILE_SUFFIX); + + + return (temp); +} +#endif /* Unix Option File Stuff */ + +#if defined( PC ) + +/* --------------------------------------------------------------------------------- + + Return the Option File Name, given the Name of the Application (PC Version) + + Edited: + + --------------------------------------------------------------------------------- */ +char *PCOptionFileName(appn, onlyLocal) + char *appn ; + int onlyLocal; +{ + char *temp; + int i ; + char *temp2, *lastPart; + + + temp = malloc((unsigned) (strlen(appn) + strlen(OPTION_FILE_SUFFIX) + + strlen(OPTION_FILE_PREFIX) + 1)); + + temp = strcpy(temp, appn); + + for (i = 0; temp[i] != NULL_CHARACTER; i++) + if (temp[i] == BACKSLASH_CHAR) + temp[i] = SLASH_CHARACTER; + + /* Strip Back to the Application Name */ + if ((lastPart = strrchr(temp, SLASH_CHARACTER)) == NULL) + lastPart = temp; + else + lastPart++; /* Skip over the actual "/" */ + + /* lastPart points to the tail name of the path */ + + if ((temp2 = strchr(lastPart,DOT)) == NULL) + temp = strcat(temp,OPTION_FILE_SUFFIX); + else + temp2 = strcpy(temp2, OPTION_FILE_SUFFIX); + + if (onlyLocal) /* Remove the full path to give only a local name */ + return( lastPart); + else + return (temp); +} +#endif /* PC Version of OptionFileName */ + + +/* --------------------------------------------------------------------------------- + + Check that there is no ambiguity in the (possibly abbreviated) <name>. If there is + no match whatever, return NO_MATCH. If there is a single exact match, or a single + abbreviating match, return the index of the matched option; otherwise return + AMBIGUOUS. + + --------------------------------------------------------------------------------- */ +int Ambiguity(options, numOptions, name) + Option options[] ; + int numOptions; + char *name ; +{ + int i, matched, matchedExactly, matchedWhere, moreThanOneInexactMatch; + + matched = FALSE; + matchedExactly = FALSE; + moreThanOneInexactMatch = FALSE; + + for (i = 0; i < numOptions; i++) + if (options[i].classification != OutputOption && + strncmp(name, options[i].name, strlen(name)) == 0) { + if (matched) { + if (matchedExactly) { + if (strcmp(name, options[i].name) == 0) { + /* TWO Exact Matches */ + return AMBIGUOUS; + } + } + else { + if (strcmp(name, options[i].name) == 0) { + /* THIS is an exact match */ + matchedExactly = TRUE; + matchedWhere = i; + } + else { + /* There are two inexact matches ... if there are no exact ones we + have AMBIGUITY */ + moreThanOneInexactMatch = TRUE; + } + } + } + else { + if (strcmp(name, options[i].name) == 0) { + /* This is an exact match */ + matchedExactly = TRUE; + } + matched = TRUE; + matchedWhere = i ; + } + } + + if (moreThanOneInexactMatch) + return (AMBIGUOUS); + else { + if (matched) + return (matchedWhere); + else + return (NO_MATCH); + } + +} + + +/* --------------------------------------------------------------------------------- + + Search for the named option in the list of options. If it is found, return its + location (index) in the options array. Otherwise, return NO_MATCH. + + --------------------------------------------------------------------------------- */ +int LookUp(options, numOptions, name) + Option options[] ; + int numOptions; + char *name ; +{ + int i; + + for (i = 0; i < numOptions; i++) + if (options[i].classification != OutputOption && strcmp(name, options[i].name) == 0) { + return (i); + } + + return (NO_MATCH); + +} + +extern helpRoutine *onLineHelpHandler; +extern void updateOptionsFile(); + +/* --------------------------------------------------------------------------------- + + Search for the named option in the list of options. If it is found, set its + new value as indicated and return TRUE. If not, return either FALSE or AMBIGUOUS. + + Edited: + + 8th March 1989 (Paul Manson) Changed the call to LookUp to call Ambiguity instead, + thus achieving the matching of abbreviated options. + + 15th March 1989 (Paul Manson) Reinstated the call to LookUp in the case that + abbreviations (and hence ambiguity) are/is not + permitted (ie. in option Header Files). + + --------------------------------------------------------------------------------- */ +int LookUpAndStore(options, numOptions, name, value, permitAbbrevs, programName) + Option options[] ; + int numOptions ; + char *name, *value; + int permitAbbrevs; + char *programName ; +{ + int loc ; + char *temp; + + /* Account for specific references to the "help" option, with different + treatment of the "help=all" command */ + if (strcmp(name, HELP_STRING) == 0) { + /* Check whether it is asking for ALL help */ + if (strcmp(value, ALL_STRING) == 0) { + helpOnAllRequired = TRUE; + helpOnOneRequired = FALSE; + (*onLineHelpHandler)(options, numOptions, programName); + exit(0); + } + /* Check for other specific kinds of help request */ + /* else if (strcmp(value, _STRING) == 0) { */ + + + else { + /* Expand the (possibly abbreviated) option name */ + if ((permitAbbrevs && ((loc = Ambiguity(options, numOptions, value)) >= 0)) || + (!permitAbbrevs && ((loc = LookUp(options, numOptions, value)) >= 0))) { + helpOnOneRequired = TRUE; + helpOnAllRequired = FALSE; + helpOnOneLocation = loc ; + (*onLineHelpHandler)(options, numOptions, programName); + exit(0); + } + else { + if (loc == AMBIGUOUS) { + (void) fprintf(stderr, "WARNING: The option name %s is AMBIGUOUS; please be more specific.\n", value); + exit(1); + } + else { + (void) fprintf(stderr, "WARNING: The %s program does not have an option named %s.\n", + programName, value); + exit(1); + } + } + } + } + else if (strcmp(name, UPDATE_STRING) == 0) { + /* Check whether it is asking for ALL updated */ + if (strcmp(value, ALL_STRING) == 0) { + updateAllRequired = TRUE ; + updateOptionsFile(options, numOptions, programName, theOptionFileName); + updateAllRequired = FALSE; + helpOnAllRequired = TRUE ; + helpOnOneRequired = FALSE; + return (TRUE); + } + else { + /* At present there is no use for a specific update call */ + (void) fprintf(stderr, "options: The update option may not be altered!\n"); + exit(1); + } + } + else if ((permitAbbrevs && ((loc = Ambiguity(options, numOptions, name)) >= 0)) || + (!permitAbbrevs && ((loc = LookUp(options, numOptions, name)) >= 0))) { + /* It is a conventional "LookUpAndStore" operation */ + temp = malloc((unsigned)(strlen(value) + 1)); + temp = strcpy(temp, value); + *(options[loc].value) = temp; + return (TRUE); + } + else { + if (loc == AMBIGUOUS) { +#if defined( PC ) + (void) fprintf(stderr, + "ERROR: The name %s is AMBIGUOUS, and the value %s has not been assigned to any option\n", name, value); + exit(1); +#else + (void) fprintf(stderr, + "WARNING: The name %s is AMBIGUOUS, and the value %s has not been assigned to any option\n", name, value); + return (AMBIGUOUS); +#endif + } + else + return (FALSE); + } + + +} + + +/* --------------------------------------------------------------------------------- + + Skip Blanks and Tabs. Stop at a printable character or a newline or null. + + --------------------------------------------------------------------------------- */ +char *skipBlanks (ptr) + char *ptr; +{ + while ((*ptr == BLANK_CHARACTER) || (*ptr == TAB_CHARACTER)) ptr++; + + return (ptr); +} + + +/* --------------------------------------------------------------------------------- + + Ensure that the next character is an '='. If it is, return a pointer to the first + character after the '='; otherwise, return NULL. + + --------------------------------------------------------------------------------- */ +char *skipEquals (ptr) + char *ptr; +{ + if (ptr[0] == EQUALS_CHARACTER) + return (++ptr); + else + return (NULL); +} + + +/* --------------------------------------------------------------------------------- + + Read a name (ie. a token, a contiguous sequence of nonblank characters, or a + quoted string) from the string pointed to by ptr, and copy it the buffer pointed + to by <name>. If successful, return a pointer to the character after the token; + otherwise, return NULL. + + --------------------------------------------------------------------------------- */ +char *getName (ptr, name) + char *ptr, *name; +{ + char *temp, *i, *namePtr; + char stopChar; + + if (ptr[0] == DOUBLE_QUOTE_CHAR) { + ptr++; + stopChar = DOUBLE_QUOTE_CHAR; + } + else + stopChar = BLANK_CHARACTER; + + temp = ptr; + + while (*temp != NULL_CHARACTER && + *temp != NEWLINE_CHARACTER && + *temp != CARRIAGE_RETURN && + ((stopChar == DOUBLE_QUOTE_CHAR && *temp != stopChar) || + (stopChar == BLANK_CHARACTER && + (*temp != stopChar && *temp != TAB_CHARACTER && *temp != EQUALS_CHARACTER)))) + temp++; + + if (stopChar == DOUBLE_QUOTE_CHAR && *temp != DOUBLE_QUOTE_CHAR) { + (void) fprintf(stderr, "options: Improperly closed quoted string %s\n", --ptr); + return (NULL); + } + + namePtr = name; + + for (i = ptr; i < temp; ) + *namePtr++ = *i++; + + *namePtr = NULL_CHARACTER; + + if (stopChar == DOUBLE_QUOTE_CHAR) + temp++; + + + return (temp); + +} + + +/* ------------------------------------------------------------------------------ + + Read lines from the specified file, updating option settings as appropriate. + + Edits: 29th March 1989 (Paul Manson) Altered so that trailing comments allowed. + + ------------------------------------------------------------------------------ */ +void processOptionFile (options, numOptions, OptionFile, theOptionFileName, + limitedChars, checkOptions, programName) + Option options[] ; + int numOptions ; + FILE *OptionFile ; + char *theOptionFileName; + int limitedChars ; + int checkOptions ; + char *programName ; +{ + int result ; + char name[MAX_NAME_LENGTH] ; + char value[MAX_NAME_LENGTH] ; + char *line, *linePtr; + int maxCharsToRead ; + int totalCharsRead ; + + result = EOF; + totalCharsRead = 0 ; + line = malloc((unsigned) MAX_LINE_LENGTH + 1); + + maxCharsToRead = ((limitedChars) ? (min(MAX_LINE_LENGTH, limitedChars)) : + MAX_LINE_LENGTH); + + while (maxCharsToRead > 0 && ((line = fgets(line, maxCharsToRead + 1, + OptionFile)) != NULL)) { + + if (line[0] == NULL_CHARACTER) + break; /* In the case of a Option Header */ + else + if (limitedChars) { + totalCharsRead += strlen(line); + maxCharsToRead = min(MAX_LINE_LENGTH, limitedChars - totalCharsRead); + } + + linePtr = skipBlanks(line); + + /* Check for Comments and Blank Lines */ + if ((linePtr[0] == COMMENT_CHARACTER) || + (linePtr[0] == NEWLINE_CHARACTER) || + (linePtr[0] == CARRIAGE_RETURN ) || + (linePtr[0] == NULL_CHARACTER)) + continue; + + if ((linePtr = getName(linePtr, name)) == NULL) { + (void) fprintf(stderr, "options: Missing or Invalid name\n"); + result = ERROR_RESULT; + break; + } + linePtr = skipBlanks(linePtr); + if ((linePtr = skipEquals(linePtr)) == NULL) { + (void) fprintf(stderr, "options: Expected an '=' after the name %s\n", name); + result = ERROR_RESULT; + break; + } + linePtr = skipBlanks(linePtr); + if ((linePtr = getName(linePtr, value)) == NULL) { + (void) fprintf(stderr, + "options: Missing or Invalid value; name is %s\n", name); + result = ERROR_RESULT; + break; + } + linePtr = skipBlanks(linePtr); + if ((*linePtr != NEWLINE_CHARACTER) && + (*linePtr != NULL_CHARACTER) && + (*linePtr != COMMENT_CHARACTER) && + (*linePtr != CARRIAGE_RETURN)) { + (void) fprintf(stderr, + "options: Detected Trailing Garbage in the line %s = %s\n", + name, value); + result = ERROR_RESULT; + break; + } + + if (!LookUpAndStore(options, numOptions, name, value, checkOptions, programName) && + checkOptions) { + (void) fprintf(stderr, "options: Could not find Option Called %s\n", + name); + result = ERROR_RESULT; + break; + } + + } + + if (result != EOF) { + (void) fprintf(stderr,"options: Error reading the Option File %s\n", + theOptionFileName); + (void) fprintf(stderr,"options: Remainder of File is as follows;\n"); + (void) fputs(line, stderr); + while ((line = fgets(line, MAX_LINE_LENGTH, OptionFile)) != NULL) + (void) fputs(line, stderr); + exit(1); + } +} + + +/* ------------------------------------------------------------------------------ + + OnLine Help Facility. This is simply the default handler which is to be called + if the user specifies no replacement handler. + + ------------------------------------------------------------------------------ */ +static void defaultHelpHandler(options, numOptions, progName) + Option options[] ; + int numOptions; + char *progName ; +{ + register int help, res; + + if (helpOnOneRequired) { + res = helpOnOneLocation; + (void) fprintf(stdout, "%-13s %-9s %-9s %s\n", options[res].name, + ((*(options[res].value) == NULL) ? ("") : (*(options[res].value))), + ((options[res].defaultValue == NULL) ? ("") : (options[res].defaultValue)), + ((options[res].comment == NULL) ? ("") : (options[res].comment))); + return; + } + + help = -1; + for (res = 0; res < numOptions; res++) + if (strcmp(options[res].name, HELP_STRING) == 0) { + help = res; + break ; + }; + + +/************* Print head of help menu *****************/ + if (help < 0) { + (void) fprintf(stdout, "The Rotter who wrote the `%s' program hasn't provided any \n", + progName); + (void) fprintf(stdout, "form of on-line 'help' documentation, tsk tsk!\n\n"); + (void) fprintf(stdout, + "We can, however, provide you with the list of available options:\n\n"); + } + else { + + (void)fprintf(stdout,"%s\n", versionstr); + (void) fprintf(stdout, + "Usage: %s [options] %s\n\n", progName, options[help].comment); + } + + (void) fprintf(stdout, "Option Name Current Default Comment\n"); + (void) fprintf(stdout, "----------- ------- ------- -------\n"); + + for (res = numOptions-1 ; res >= 0 ; res-- ) + if (options[res].classification < OutputOption && + (!thereWasAnOptionsFile || helpOnAllRequired || + strcmp(*(options[res].value), options[res].defaultValue) != 0 || + *(options[res].value) != options[res].defaultValue)) + (void) fprintf(stdout, "%-13s %-9s %-9s %s\n", options[res].name, + ((*(options[res].value) == NULL) ? ("") : (*(options[res].value))), + ((options[res].defaultValue == NULL) ? ("") : (options[res].defaultValue)), + ((options[res].comment == NULL) ? ("") : (options[res].comment))); + + (void) fprintf(stdout, "\n"); + return; +} + +/* ----- Declare the handlerHolder variable ----- */ + +static helpRoutine *onLineHelpHandler = defaultHelpHandler; + + +/* ------------------------------------------------------------------------------ + + Spit out the options to a file (with the appropriate option file name). + + Edits: 29th March 1989 (Paul Manson). For the sake of IBM/PC users, this routine + will now spit lines with CR/LF pairs. + 06th April 1989 (Paul Manson). This routine is no-longer conditionally + compiled, but is now more widely accepted. + + ------------------------------------------------------------------------------ */ + +void updateOptionsFile(options, numOptions, programName, resFileName) + Option options[] ; + int numOptions ; + char *programName; + char *resFileName; +{ + int res ; + FILE *fptr; + + if ((fptr = fopen(resFileName, "w")) == NULL) { + (void) fprintf(stderr, "Unable to Update Options File called %s.\n", resFileName); + exit(1); + } + +#if defined( PC ) || defined( THINK_C ) + (void) fprintf(fptr ,"# %s\n", versionstr); + (void) fprintf(fptr, "#\r\n# Options file for the %s program.\r\n#\r\n\r\n", programName); + (void) fprintf(fptr, "#Option Name Current Default Comment\r\n"); + (void) fprintf(fptr, "#----------- ------- ------- -------\r\n\r\n"); +#else + (void) fprintf(fptr ,"# %s\n", versionstr); + (void) fprintf(fptr, "#\n# Options file for the %s program.\n#\n\n", programName); + (void) fprintf(fptr, "#Option Name Current Default Comment\n"); + (void) fprintf(fptr, "#----------- ------- ------- -------\n\n"); +#endif + + for (res = numOptions-1; res >=0 ; res-- ) + if (options[res].classification < OutputOption && *(options[res].value) != NULL && + (updateAllRequired || + strcmp(*(options[res].value), options[res].defaultValue) != 0 || + *(options[res].value) != options[res].defaultValue)) { +#if defined( PC ) + (void) fprintf(fptr, "%-13s = %-9s # %-9s %s\r\n", options[res].name, + ((*(options[res].value) == NULL) ? ("") : (*(options[res].value))), + ((options[res].defaultValue == NULL) ? ("") : (options[res].defaultValue)), + ((options[res].comment == NULL) ? ("") : (options[res].comment))); +#else + (void) fprintf(fptr, "%-13s = %-9s # %-9s %s\n", options[res].name, + ((*(options[res].value) == NULL) ? ("") : (*(options[res].value))), + ((options[res].defaultValue == NULL) ? ("") : (options[res].defaultValue)), + ((options[res].comment == NULL) ? ("") : (options[res].comment))); +#endif + } + + if (fclose(fptr) == EOF) { + (void) fprintf(stderr, "options: fclose failed on the options file %s.\n", resFileName); + exit(1); + } + + thereWasAnOptionsFile = TRUE; /* Cos there is one now! */ + + return; +} + + +/* ------------------------------------------------------------------------------ + + Process the option file and then the command line options supplied. + + Edited: + + 2nd March 1989 (Paul Manson). Changed the calls to OptionFileName (ie. + added a <prefix> argument) to facilitate + searching of HOME (etc) directories. Note + that this is IGNORED for IBM/PCs. + + 8th March 1989 (Paul Manson). Ignore the above, as OPTIONSPATH is now + used (in conjunction with search_path) to + enable proper paths for Unix. + + 10th March 1989 (Paul Manson). Added the "help" facility and the default + and comment stuff. + + 16th March 1989 (Paul Manson). Altered the final argc/argv shuffling so that + argv simply points at the first argument after + the options. + + July 1994 (MAA). Mended to allow spaces in command-line strings. + + ------------------------------------------------------------------------------ */ + + + + +/* Assign the default options */ + +void default_nopts( options, numOptions ) +Option options[] ; +int numOptions ; +{ + int i ; + + for (i = 0; i < numOptions; i++) + *(options[i].value) = options[i].defaultValue ; +} + + + +/**************************************************************************** +* Assign options from the rc file. +* +* The option file is called ".genxxxrc", where the "xxx" is determined +* by the name of the application, (which is in argv[0]). +* Here "rc" stands for "resource control". +* The file-name is assigned to a string ptr "theOptionFileName". +* On Unix, the path for the file-name is determined as follows: +* if environment variable OPTION_PATH is set, then use this path. +* else the default path is: +* `.' (the current directory) +* `~' (the users home directory) +* The DEFAULT_OPTION_PATH for the option file is defined "." (see above). +* This means look first in the current directory, and failing that in the +* users home directory. +* But these defaults can be overridden by setting an environment variable, +* which is defined as OPTIONSPATH (see above). Thus the user could set a +* new default path for option files by, eg: +* setenv OPTIONSPATH ".:~/rcbin" +* This would look first in the current directory, and failing that in a +* directory ~/rcbin +*****************************************************************************/ + +void rcfile_nopts( options, numOptions, file ) +Option options[] ; +int numOptions ; +char *file ; +{ + FILE *OptionFile ; + char *OptionPathPtr ; + + +#if defined( PC ) + if (((OptionFile = fopen(theOptionFileName = + PCOptionFileName( file, TRUE ), "r")) != NULL)) { +/* ------------------------------------------------------------------------------------- + Removed temporarily so the PC version ONLY examines and creates option files + in the cwd. This will be changed when we determine a better strategy for + PC directory PATH searches. + + ((OptionFile = fopen(theOptionFileName = + PCOptionFileName( file, FALSE), "r")) != NULL)) { +---------------------------------------------------------------------------------------*/ +#else + if ((OptionPathPtr = (char *)getenv(OPTION_PATH)) == NULL) + OptionPathPtr = DEFAULT_OPTION_PATH; + + if ((OptionFile = fopen(theOptionFileName = + search_path(UnixOptionFileName( file ), + OptionPathPtr), "r")) != NULL) { +#endif + + /* Process the Option File */ + + (void) processOptionFile(options, numOptions, OptionFile, + theOptionFileName, FALSE, TRUE, file ) ; + (void) fclose(OptionFile); + + thereWasAnOptionsFile = TRUE; + + } +} + + +/* Assign options from the command line */ + +void cmd_line_nopts( options, numOptions, argc, argv ) +Option options[] ; +int numOptions ; +int *argc ; +char ***argv ; +{ + int i, currentArg ; + int finalArg, wasAHyphen ; + char name[MAX_NAME_LENGTH] ; + char value[MAX_NAME_LENGTH] ; + char *line, *linePtr; + char *tempstring; /* MAA 23-4-1994 */ + char *tempstring2; /* MAA 23-4-1994 */ + int count=0; + + + /* MAA: next 3 lines */ + linePtr = (char *) calloc((size_t) MAX_NAME_LENGTH, (size_t) sizeof(char)); + tempstring = (char *) calloc((size_t) MAX_NAME_LENGTH, (size_t) sizeof(char)); + tempstring2 = (char *) calloc((size_t) MAX_NAME_LENGTH, (size_t) sizeof(char)); + + + finalArg = currentArg = 1; /* Ignore the Program Name */ + line = malloc((unsigned) MAX_LINE_LENGTH); + + while (currentArg < *argc) { + wasAHyphen = FALSE; + linePtr = strcpy(line, (*argv)[currentArg]); + if (linePtr[0] == HYPHEN_CHARACTER) { + wasAHyphen = TRUE; + linePtr++; /* Skip any leading hyphen */ + } + + /* MAA: force doublequotes onto beg & end . A rather big hack ...*/ + if (strchr(linePtr, BLANK_CHARACTER) != NULL){ + strncpy(tempstring, linePtr, (int) strcspn(linePtr, "=")); + strcat(tempstring, "=\""); + tempstring2 = (char *) strrchr(linePtr, EQUALS_CHARACTER); + tempstring2++; + strcat(tempstring, tempstring2); + strcat(tempstring, "\""); + linePtr=tempstring;} + + + if ((linePtr = getName(linePtr, name)) == NULL) { + break; + } + + if ((linePtr = skipEquals(linePtr)) == NULL) { + if (!wasAHyphen) { + break; /* Don't interpret <name> <value> as being options */ + } + if (strcmp(name, HELP_STRING) == 0) { +#ifdef PC + if (strncmp((*argv)[0]+strlen((*argv)[0])-strlen("gen.exe"), "gen", strlen("gen")) == 0) +#else + if (strcmp((*argv)[0], "gen") == 0) +#endif + /* Special case of gen -help */ + usageHelp(); + else + /* Case of gen??? -help */ + (*onLineHelpHandler)(options, numOptions, (*argv)[0]); + exit(0); + } + + if (strcmp(name, UPDATE_STRING) == 0) { + /* Do the Update and Then Goto the Top of the Loop Again */ + updateOptionsFile(options, numOptions, (*argv)[0], theOptionFileName); + finalArg = ++currentArg; + continue; + } + + (void) strcpy(value, DEFAULT_TOGGLE_VALUE); + } + else { + if ((linePtr = getName(linePtr, value)) == NULL) { + break; + } + } + + if(!LookUpAndStore(options, numOptions, name, value, TRUE, (*argv)[0])) { + (void) fprintf(stderr,"options: Could not find an Option called %s\n", name); + exit(1); + } + + finalArg = ++currentArg; + } + + /* Reset the Command Line argc and argv */ + /* The Original Version actually cut the options out of the argv array (by + shifting the remaining arguments left), but the new version simply lets + argv point to the next argument to be processed. + + if (finalArg > 1) { + for (i = finalArg; i < *argc; i++) + (*argv)[i - finalArg + 1] = (*argv)[i]; + *argc = *argc - finalArg + 1; + } + + */ + + *argv+= finalArg; + *argc = *argc - finalArg; + + return; +} + + + +/* Assign options using defaults, then the rc file, then the command line */ + +void getnopts (options, numOptions, argc, argv) +Option options[] ; +int numOptions ; +int *argc ; +char ***argv ; +{ + default_nopts( options, numOptions ) ; + rcfile_nopts( options, numOptions, (*argv)[0] ) ; + cmd_line_nopts( options, numOptions, argc, argv ) ; +} + + + +/* ------------------------------------------------------------------------------- + + Read an option header from the specified file into the given options array. + + ------------------------------------------------------------------------------- */ +void readnopts(options, numOptions, filePointer) + Option options[] ; + int numOptions; + FILE *filePointer ; +{ + long filePosition ; + char first[200] ; + int headerLength ; + + filePosition = ftell(filePointer); /* Save the Original Position */ + + /* Read the first line of the first block, or as much of it as possible */ + + if ((!fread(first, 1, strlen(OptionHeaderHeader) + OPTION_HEADER_DIGITS + + strlen(LineFeedArray), filePointer)) || + (strncmp(first, OptionHeaderHeader, strlen(OptionHeaderHeader)) != 0)) { + /* Assume that this is NOT a option header */ + if (fseek(filePointer, filePosition, 0)) { + (void) fprintf(stderr, "options: Error fseeking Option Header File\n"); + exit(1); + } + return; + } + + /* Extract the Header Length in Bytes */ + + headerLength = atoi(first + strlen(OptionHeaderHeader)); + + /* Now, process the stuff. Need to "seek" past the first line before + attempting to read anything, and shorten the headerLength accordingly */ + + (void) processOptionFile(options, numOptions, filePointer, + "Unknown Option File", + (headerLength - strlen(OptionHeaderHeader) - + OPTION_HEADER_DIGITS - strlen(LineFeedArray)), + FALSE, "???"); + + /* Make sure that the file pointer is set to the data area */ + + if (fseek(filePointer, filePosition + headerLength, 0)) { + (void) fprintf(stderr, "options: Error fseeking Option Header File\n"); + exit(1); + } + +} + + +/* ------------------------------------------------------------------------------- + + Count the number of bytes which will be written by writenopts, given the + options array. + + ------------------------------------------------------------------------------- */ +static int countBytesToWrite( options, numOptions ) + Option options[] ; + int numOptions; +{ + int sum, i; + + sum = 0; + + for (i = 0; i < numOptions; i++) + if((options[i].classification == OutputOption || + options[i].classification == InOutOption) && + *(options[i].value) != NULL && + strcmp(*(options[i].value), NULL_STRING) != 0) + sum += strlen(options[i].name) + strlen(EqualsArray) + + strlen(*(options[i].value)) + strlen(LineFeedArray); /* + (2 * strlen(QuotesArray)); */ + + return (sum); +} + +/* ------------------------------------------------------------------------------- + + The descendent of the lost and lamented blockCopyStrToFile... writes a string + to the indicated file. + + ------------------------------------------------------------------------------- */ +static void WriteStringToFile(str, filePtr) + char *str; + FILE *filePtr; +{ + if (!fwrite(str, 1, strlen(str), filePtr)) { + (void) fprintf(stderr, "WriteStringToFile: Error printing %s to file.\n", str); + exit(1); + } + + return; +} + + +/* ------------------------------------------------------------------------------- + + Write an option header to the specified file from the information contained + in the given options array. Remove the comments to get debugging info. + + ------------------------------------------------------------------------------- */ +void writenopts(options, numOptions, filePointer) + Option options[] ; + int numOptions; + FILE *filePointer ; +{ +/*int bytesWritten ;*/ + int i ; + long filePosition ; + int bytesToWrite ; + int oddHeaderLength ; + char DigitString[OPTION_HEADER_DIGITS + 2]; + + filePosition = ftell(filePointer); + + bytesToWrite = countBytesToWrite(options, numOptions) + + strlen(OptionHeaderHeader) + OPTION_HEADER_DIGITS + + strlen(LineFeedArray) + 1; + + if (oddHeaderLength = (bytesToWrite % 2)) + bytesToWrite++; + + (void) WriteStringToFile(OptionHeaderHeader, filePointer); + + (void) sprintf(DigitString, "%0*d", OPTION_HEADER_DIGITS, bytesToWrite); + +/*(void) printf("bytesToWrite is %i.\n", bytesToWrite);*/ + + (void) WriteStringToFile(DigitString, filePointer); + + (void) WriteStringToFile(LineFeedArray, filePointer); + + /* Copy all of the Options */ + + for (i = 0; i < numOptions; i++) { + + if((options[i].classification == OutputOption || + options[i].classification == InOutOption) && + *(options[i].value) != NULL && + strcmp(*(options[i].value), NULL_STRING) != 0) { + + (void) WriteStringToFile(options[i].name, filePointer); + + (void) WriteStringToFile(EqualsArray, filePointer); + +/* (void) WriteStringToFile(QuotesArray, filePointer); */ + + (void) WriteStringToFile(*(options[i].value), filePointer); + +/* (void) WriteStringToFile(QuotesArray, filePointer); */ + + (void) WriteStringToFile(LineFeedArray, filePointer); + } + } + + if (fputc(NULL_CHARACTER, filePointer) == EOF) { + (void) fprintf(stderr, "writenopts: Error doing fputc of the last NULL character.\n"); + exit(1); + } + + if (oddHeaderLength && fputc(NULL_CHARACTER, filePointer) == EOF) { + (void) fprintf(stderr, "writenopts: Error doing fputc of the odd-pad NULL character.\n"); + exit(1); + } + + if (fflush(filePointer)) { + (void) fprintf(stderr, "options: Error while flushing the option header\n"); + exit(1); + } + + /* seek the fileptr to after the last byte of the header */ + + if (filePointer != stdout) { + if (fseek(filePointer, filePosition + (long)bytesToWrite, 0)) { + (void) fprintf(stderr, "options: Error fseeking Option Header File\n"); + exit(1); + } + } + +} + + +/* ---------------------------------------------------------------------------- + + A Little Routine to Count the Options in a Options Array .... This MUST + Be NULL-Terminated ...... OR ELSE! + + ---------------------------------------------------------------------------- */ + +static int countOptions(options) + Option options[]; +{ + int numoptions; + + for (numoptions = 0; + options[numoptions].name != NULL; /* DEATH TO ALL WHO TREAD HERE! */ + numoptions++); + + return (numoptions); + +} + + +/* ------------------------------------------------------------------------------- + + The Counting version of getnopts -- you MUST null-terminate the options array. + + ------------------------------------------------------------------------------- */ + +void getopts (options, argc, argv) + Option options[] ; + int *argc ; + char ***argv ; +{ + (void) getnopts(options, countOptions(options), argc, argv); +} + + +void cmd_line_opts(options, argc, argv) +Option options[] ; +int *argc ; +char ***argv ; +{ + (void) cmd_line_nopts( options, countOptions(options), argc, argv ) ; +} + + + +/* ------------------------------------------------------------------------------- + + The Counting version of readnopts -- you MUST null-terminate the options array. + + ------------------------------------------------------------------------------- */ +void readopts(options, filePointer) + Option options[] ; + FILE *filePointer ; +{ + (void) readnopts(options, countOptions(options), filePointer); +} + +/* ------------------------------------------------------------------------------- + + The Counting version of writenopts -- you MUST null-terminate the options array. + + ------------------------------------------------------------------------------- */ +void writeopts(options, filePointer) + Option options[] ; + FILE *filePointer ; +{ + (void) writenopts(options, countOptions(options), filePointer); +} + + +/* ------------------------------------------------------------------------------- + + Packaging for convenience -- Guaranteed to be Listeria-free! + + ------------------------------------------------------------------------------- */ + +FILE *fileopts( res, argc, argv ) +Option *res ; +int *argc ; +char **argv[]; +{ + FILE *ifp ; + int numOptions; +#if defined( PC ) + char *progName ; + + progName = (*argv)[0]; +#endif + + numOptions = countOptions(res); + + getnopts( res, numOptions, argc, argv ) ; + + if( *argc > 0 ) { + if((ifp = fopen( **argv, "r" )) == NULL) { + (void) fprintf(stderr, "Unable to open the file %s.\n", **argv); + exit(1); + } + } + else +#if defined( PC ) + { + /* PCs cannot take binmode files through standard input */ + (void) (*onLineHelpHandler)( res, numOptions, progName ); + exit(1); + } +#else + ifp = stdin ; +#endif + + (*argv)++ ; + (*argc)-- ; + + readopts( res, ifp ) ; + + return( ifp ) ; + +} + + +/* ------------------------------------------------------------------------------- + + Packaging for convenience -- Guaranteed to be Listeria-free! + + ------------------------------------------------------------------------------- */ +FILE *optoutput(str) + char *str; +{ + FILE *f; + + if (str == NULL) + return (NULL); + else if (str == DEFAULT_TOGGLE_VALUE) + return (stdout); + + if ((f = fopen(str, "w")) == NULL) { + (void) fprintf(stderr, "options: Could not open the file %s for output.\n", str); + exit(1); + } + return (f); +} + + +/* ------------------------------------------------------------------------------- + + OnLine Help from the user program. + + ------------------------------------------------------------------------------- */ +void helpnopts(res, numRes, name) + Option res[]; + int numRes; + char *name ; +{ + (void) (*onLineHelpHandler)(res, numRes, name); +} + +/* ------------------------------------------------------------------------------- + + OnLine Help from the user program. (counting version) + + ------------------------------------------------------------------------------- */ +void helpopts(res, name) + Option res[]; + char *name ; +{ +#ifdef PC + if (strncmp(name+strlen(name)-strlen("gen.exe"), "gen", strlen("gen")) == 0) +#else + if (strcmp(name, "gen") == 0) +#endif + /* Special case of gen */ + usageHelp(); + else + /* Case of gen??? */ + (void) (*onLineHelpHandler)(res, countOptions(res), name); +} + + +/* --------------------------------------------------------------------------------- + + Allows an application program to install its very own helpHandler routine to + override the default help-message handler. The behaviour of such a routine is + implicitly trusted by <options>, so you should only install your own handler + when you are quite familiar with the Options structure format. This routine + returns the address of the previously installed handler (which is initially the + default handler) so that this may be reinstated at a later point. + + ---------------------------------------------------------------------------------- */ + +helpRoutine *helpOptsHandler(aHelpRoutine) + helpRoutine *aHelpRoutine; +{ + helpRoutine *temp; + + temp = onLineHelpHandler; + + onLineHelpHandler = aHelpRoutine; + + return (temp); +} + + +/* --------------------------------------------------------------------------------- + + A convenience call which returns TRUE (1) if the optionStr is what options thinks + of as "ON", "YES", "TRUE", or "1".... This merely allows us to hide the actual + implementation of "ON" from the application programs. + + --------------------------------------------------------------------------------- */ + +int isOFF(optionStr) + char *optionStr; +{ + return (strcmp(OFF_STRING, optionStr) == 0 || + strcmp(OFF_ALIAS , optionStr) == 0 || + strcmp(NOT_USED , optionStr) == 0); +} + + +/* --------------------------------------------------------------------------------- + + A convenience call which returns TRUE (1) if the optionStr is what options thinks + of as "NULL", "NONE", nothing, zip, etc... This merely allows us to hide the actual + implementation of "NULL" from the application programs. + + --------------------------------------------------------------------------------- */ + +int isNULL(optionStr) + char *optionStr; +{ + return (optionStr == NULL || + strcmp(NULL_STRING, optionStr) == 0 || + strcmp(NULL_ALIAS , optionStr) == 0); +} + + +/* --------------------------------------------------------------------------------- + + A routine to reduce the load on the application programmer by providing a simple + boolean check for string equality WITHOUT CASE SIGNIFICANCE. This allows applications + to leave case and typing problems within "options" reliably. + + --------------------------------------------------------------------------------- */ + +static char *stringToLowerCase(str) + char *str; +{ + register int i; + + if (str == NULL) + return (str); + else { + for (i = 0; str[i] != NULL_CHARACTER; i++) + if (isupper((char) str[i])) + str[i] = (char) tolower((char) str[i]); + return (str); + } +} + +extern int OptionStringsEqual(str1, str2) + char *str1, *str2; +{ + /* This routine copies the strings into two local buffers, converts them to + lower case, and then compares them for equality. This local copy ensures + that they are automatically deallocated on function return */ + +#define MAX_COPY_LENGTH (256) + + char lc1[MAX_COPY_LENGTH], lc2[MAX_COPY_LENGTH]; + + if (strlen(str1) < MAX_COPY_LENGTH && + strlen(str2) < MAX_COPY_LENGTH) + return (strcmp(stringToLowerCase(strcpy(lc1, str1)), + stringToLowerCase(strcpy(lc2, str2))) == 0); + else { + (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); + exit(1); + } +} + + + +/* Print general usage information in response to: gen -help */ +usageHelp() +{ + (void)fprintf(stdout,"%s\n\n", versionstr); + + (void) fprintf(stdout, "Usage: genXXX [options] [file_name]\n"); + (void) fprintf(stdout, " where XXX is one of the following abbreviations:\n\n\ + wav waveform \n\ + bmm basilar membrane motion \n\ + nap neural activity pattern \n\ + sai stabilized auditory image \n\ + spl spiral version of auditory image \n\ + sgm spectrogram \n\ + cgm cochleogram " ) ; + (void) fprintf(stdout, "\n\ + asa auditory spectral analysis \n\ + epn excitation pattern \n\n"); + + (void) fprintf(stdout, " [file_name] is a headerless wave file (2-byte binary integers).\n"); + (void) fprintf(stdout, " [options] are parameters, options and swtiches that control\n"); + (void) fprintf(stdout, " the AIM instructions and the AIM tools.\n\n"); + + (void) fprintf(stdout, " Help with options: genXXX [-help | -help=all | -help=option]\n"); +#if !defined( PC ) + (void) fprintf(stdout, " Path for options file, (.genXXXrc) = . (or setenv OPTIONSPATH)\n\n"); +#endif + + (void) fprintf(stdout, "Processes Applied by AIM and Routes Through the Model: \n\n\ + Process Auditory Speech Spectra \n\ + -------------------------------- -------- ------ ------- \n\ + Display input wave genwav genwav genwav \n\ + Auditory filtering (gtf/tlf) genbmm \n\ + Compression and rectification gensgm genasa " ) ; + + (void) fprintf(stdout, "\n\ + Neural encoding (2D-AT/haircell) gennap \n\ + Temporal integration (LP filter) gencgm genepn \n\ + Strobed temporal integration gensai \n\ + Spiral mapping of auditory image genspl \n\n"); + + (void) fprintf(stdout, "Output: genXXX output=on file_name \n"); + (void) fprintf(stdout, " output is written to file: file_name.XXX \n"); + + (void) fprintf(stdout, "\n\ + The format for 2-dimensional output format is by columns, with the \n\ + lowest channel first in each column (bmm, nap, sgm, cgm, asa, epn).\n\ + The format for auditory image output is by rows, for each image frame \n\ + in succession, with the row of the lowest channel first (sai, spl).\n\n"); + + (void) fprintf(stdout, "The Auditory Image Model was developed at the Applied Psychology Unit\n"); + (void) fprintf(stdout, "of the Medical Research Council, 15 Chaucer Road, Cambridge, U.K.\n\n"); + + (void) fprintf(stdout, "Copyright(c) Applied Psychology Unit, Medical Research Council, 1988-1995.\n"); + +}