home *** CD-ROM | disk | FTP | other *** search
- /*
- getf - locate the source file containing a specified function
- and present it in your favorite editor
-
-
- copyright (c) 1988 Marvin Hymowech
-
- Marvin Hymowech, "Find That Function", Dr. Dobb's Journal of Software
- Tools, #142 (August 1988).
-
- transcribed 21 Aug 88 by James R. Van Zandt
- modifications by jrv:
- Calling Unix-style pattern matcher
- Help display
- GETFEDIT variable can ask for line number of function definition
-
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #define UNIX_PATTERNS
- #define CHAIN
-
- #define TRUE 1
- #define FALSE 0
-
- #define VERSION "2.0"
-
- #define LINE_LEN 256
- #define MAX_CHOICES 256
-
- #define streq(a, b) (strcmp(a, b)==0)
-
- /* function declarations */
- int patn_match(char *, char *);
- int match(char *, char *);
- void edit( char *, char *, int );
- void ask_for_file(char **, char **, int *, unsigned int);
-
- unsigned int num_ctl_patns; /* number of %s symbols in GETFEDIT var */
- int line_number_patn; /* nonzero if %d appears in GETFEDIT var */
- char *file_token, *func_token, *last_token, *line_token;
- char arg1[64]; /* argument for editor command line */
- char *arg1_ctl; /* ctl string for building arg1 */
- char *pgm_name; /* name of editor to invoke */
-
- main(argc, argv) int argc; char **argv;
- {
- char file_line[LINE_LEN], func_line[LINE_LEN];
- char func_name[64], edit_cmd[128];
- char *env_edit_cmd, *ctl_patn;
- unsigned int last_func, len, eof = FALSE;
- static char file_name[] = "funcs.txt"; /* input file name */
- FILE *funcs_file;
- static char delim[] = "\n\t "; /* white space delimiters */
- unsigned int num_choices = 0;
- static char *func_choices[ MAX_CHOICES ], *file_choices[ MAX_CHOICES ];
- static int func_line_numbers[MAX_CHOICES]; /* line number from funcs.txt */
- int line_number; /* most recent line number */
-
- if( argc != 2 )
- {
- fprintf( stderr, "getf: wrong number of arguments\n" );
- help();
- }
- else if(streq(argv[1], "-?")) help();
-
- /* the argument is the function name to find */
- strcpy( func_name, *++argv );
-
- if( (env_edit_cmd = getenv( "GETFEDIT", edit_cmd )) == NULL )
- {
- fprintf( stderr, "getf: missing environment variable GETFEDIT" );
- exit(1);
- }
-
-
- /*
- Check if GETFEDIT environment variable has a place for
- function name as well as file name - note function name
- is assumed to go in the second %s pattern if there are
- two %s patterns.
- */
- if( (ctl_patn = strstr( env_edit_cmd, "%s" )) == NULL )
- {
- fprintf( stderr,
- "getf: environment variable GETFEDIT has no %%s pattern" );
- exit(1);
- }
-
- num_ctl_patns = strstr( ++ctl_patn, "%s" ) == NULL ? 1 : 2;
- line_number_patn = strstr( ctl_patn, "%d" );
-
- /* strcpy( edit_cmd, env_edit_cmd ); -- not needed for DeSmet library */
-
- if( (pgm_name = strtok( edit_cmd, " " )) == NULL )
- {
- fprintf( stderr,
- "getf: environment variable GETFEDIT has incorrect format" );
- exit(1);
- }
-
- /* point to argument following program name */
- arg1_ctl = edit_cmd + strlen(pgm_name) + 1;
-
- if( (funcs_file = fopen( file_name, "r" )) == NULL )
- {
- fprintf( stderr, "getf: can't open %s\n", *argv );
- exit(1);
- }
- while( !eof ) /* loop through file names, which end with colon */
- {
- if( fgets( file_line, LINE_LEN, funcs_file ) == NULL )
- break;
- /* bypass any line consisting of white space */
- if( (file_token = strtok( file_line, delim )) == NULL )
- continue;
-
- if( file_token[ len = strlen(file_token) - 1 ] != ':' )
- {
- fprintf(stderr, "getf: incorrect file format in %s", file_name);
- exit(1);
- }
- file_token[ len] = 0; /* kill trailing colon */
- last_func = FALSE; /* set up to detect last func this file */
-
- while( !eof && !last_func ) /* loop through func names this file */
- /* last such ends with semicolon */
- {
- if( fgets( func_line, LINE_LEN, funcs_file ) == NULL )
- {
- eof = TRUE;
- break;
- }
- /* bypass any line consisting of white space */
- if( (func_token = strtok( func_line, delim )) == NULL )
- continue;
-
- /* read line number if present */
- if( (line_token = strtok( NULL, delim )) != NULL )
- {line_number = atoi(line_token);
- last_token = line_token;
- }
- else
- {
- line_number = -1;
- last_token = func_token;
- }
-
- if( last_token[ len = strlen(last_token) - 1 ] == ';' )
- {
- last_func = TRUE; /* break loop after this one */
- last_token[ len ] = 0; /* kill trailing semicolon */
- }
-
- #ifdef UNIX_PATTERNS
- if( match( func_name, func_token ) ) /* use Unix style patterns */
- #else
- if( patn_match( func_name, func_token ) ) /* use routine below */
- #endif
- {
- func_choices[num_choices] = strdup( func_token );
- file_choices[num_choices] = strdup( file_token );
- func_line_numbers[num_choices++] = line_number;
- }
- }
- }
- switch( num_choices )
- {
- case 0:
- fprintf( stderr, "getf: no match for %s in %s",
- func_name, file_name );
- exit(1);
- case 1:
- edit( func_choices[0], file_choices[0], func_line_numbers[0] );
- default:
- ask_for_file(func_choices, file_choices, func_line_numbers,
- num_choices);
- }
- }
-
- /*
- Return TRUE if string s matches pattern patn, or FALSE if it
- does not. Allowable wildcards in patn are:
- ? for any one character,
- % for any string of characters up to the next underscore
- or end of string, and
- * for any string of characters up to end of string.
- */
- int
- patn_match( patn, s )
- char *patn; /* pattern */
- char *s; /* string */
- {
- for ( ; *patn; patn++ )
- {
- if( !*s ) /* if out of s chars, no match */
- return /* unless patn ends with * or % */
- ((*patn == '*' || *patn == '%') && *(patn +1) );
-
- switch( *patn )
- {
- case '%':
- while( *s != '_' && *s )
- s++;
- break;
- case '*':
- while( *s )
- s++;
- break;
- case '?':
- s++;
- break;
- default:
- if( *s != *patn )
- return FALSE;
- s++;
- }
- }
- return *s == 0;
- }
-
- void
- ask_for_file( func_choices, file_choices, func_line_numbers, num_choices )
- char *func_choices[], *file_choices[];
- int func_line_numbers[];
- unsigned int num_choices;
- {
- int i;
- char line[LINE_LEN];
-
- while( TRUE )
- {
- printf( "which one? (CR to exit)\n" );
- for( i = 1; i <= num_choices; i++ )
- printf( "\t%3d: %20s in %-30s\n", i, func_choices[i-1],
- file_choices[i-1] );
- printf( "\nenter number: ");
- fgets( line, LINE_LEN, stdin );
-
- if( line[0] == '\n' )
- break;
- if( (i = atoi(line)) < 1 || i > num_choices )
- printf( "\ninvalid choice\n" );
- else
- edit( func_choices[i-1],
- file_choices[i-1],
- func_line_numbers[i-1] );
- }
- }
-
- /*
- chain to the editor with the specified command
- */
-
- void
- edit( func, file, line )
- char *func, *file;
- int line;
- {
- if( line_number_patn )
- sprintf( arg1, arg1_ctl, file, line );
- else if( num_ctl_patns == 1 )
- sprintf( arg1, arg1_ctl, file );
- else
- sprintf( arg1, arg1_ctl, file, func );
-
- #ifdef CHAIN
- chain( pgm_name, arg1 );
- #else
- /* exclp will overlay this program with the editor */
- execlp( pgm_name, pgm_name, arg1, NULL);
- #endif
- /* if we're still here, print error msg */
- fprintf( stderr, "getf: exec failed" );
- exit(1);
- }
-
- char *msg[] =
- {"GETF version", VERSION, "\n",
- " locate the source file containing a specified \n",
- " function and present it in your favorite editor\n",
- "usage: getf function-name\n",
- "function-name may include Unix-style regular expressions:\n",
- " * Matches any string including the null string.\n",
- " ? Matches any single character.\n",
- " [...] Matches any one of the characters enclosed.\n",
- " [~...] Matches any character NOT enclosed.\n",
- " - May be used inside brackets to specify range\n",
- " (i.e. x[1-58] matches x1, x2, ... x5, x8)\n",
- " \\ Escapes special characters.\n",
- " Other characters match themselves.\n",
- "example of environment variable: GETFEDIT=\\bin\\see.exe %%s -l%%d",
- 0
- };
-
- help()
- { char **sp;
- sp = msg;
- while(*sp) printf(*sp++);
- exit(0);
- }
-
-