home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 September
/
Simtel20_Sept92.cdr
/
msdos
/
c
/
getf.arc
/
GETF.C
< prev
next >
Wrap
C/C++ Source or Header
|
1988-11-11
|
8KB
|
306 lines
/*
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);
}