home *** CD-ROM | disk | FTP | other *** search
/ Boston 2 / boston-2.iso / DOS / PROGRAM / C / GETF / GETF.C < prev    next >
C/C++ Source or Header  |  1993-12-01  |  8KB  |  306 lines

  1. /*
  2.     getf - locate the source file containing a specified function
  3.             and present it in your favorite editor
  4.  
  5.  
  6.     copyright (c) 1988 Marvin Hymowech
  7.  
  8.     Marvin Hymowech, "Find That Function", Dr. Dobb's Journal of Software
  9.     Tools, #142 (August 1988).
  10.  
  11.     transcribed 21 Aug 88 by James R. Van Zandt
  12.     modifications by jrv:
  13.         Calling Unix-style pattern matcher
  14.         Help display
  15.         GETFEDIT variable can ask for line number of function definition
  16.  
  17. */
  18.  
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22.  
  23. #define UNIX_PATTERNS
  24. #define CHAIN
  25.  
  26. #define TRUE 1
  27. #define FALSE 0
  28.  
  29. #define VERSION "2.0"
  30.  
  31. #define LINE_LEN 256
  32. #define MAX_CHOICES 256
  33.  
  34. #define streq(a, b) (strcmp(a, b)==0)
  35.  
  36.     /* function declarations */
  37. int patn_match(char *, char *);
  38. int match(char *, char *);
  39. void edit( char *, char *, int );
  40. void ask_for_file(char **, char **, int *, unsigned int);
  41.  
  42. unsigned int num_ctl_patns;    /* number of %s symbols in GETFEDIT var     */
  43. int line_number_patn;        /* nonzero if %d appears in GETFEDIT var    */
  44. char *file_token, *func_token, *last_token, *line_token;
  45. char arg1[64];                /* argument for editor command line         */
  46. char *arg1_ctl;                /* ctl string for building arg1                */
  47. char *pgm_name;                /* name of editor to invoke                    */
  48.  
  49. main(argc, argv) int argc; char **argv;
  50. {
  51.     char file_line[LINE_LEN], func_line[LINE_LEN];
  52.     char func_name[64], edit_cmd[128];
  53.     char *env_edit_cmd, *ctl_patn;
  54.     unsigned int last_func, len, eof = FALSE;
  55.     static char file_name[] = "funcs.txt";    /* input file name */
  56.     FILE *funcs_file;
  57.     static char delim[] = "\n\t ";            /* white space delimiters        */
  58.     unsigned int num_choices = 0;
  59.     static char *func_choices[ MAX_CHOICES ], *file_choices[ MAX_CHOICES ];
  60.     static int func_line_numbers[MAX_CHOICES];    /* line number from funcs.txt        */
  61.     int line_number;                    /* most recent line number            */
  62.  
  63.     if( argc != 2 )
  64.         {
  65.         fprintf( stderr, "getf: wrong number of arguments\n" );
  66.         help();
  67.         }
  68.     else if(streq(argv[1], "-?")) help();
  69.     
  70.             /* the argument is the function name to find */
  71.     strcpy( func_name, *++argv );
  72.  
  73.     if( (env_edit_cmd = getenv( "GETFEDIT", edit_cmd )) == NULL )
  74.         {
  75.         fprintf( stderr, "getf: missing environment variable GETFEDIT" );
  76.         exit(1);
  77.         }
  78.  
  79.  
  80.             /*
  81.                 Check if GETFEDIT environment variable has a place for
  82.                 function name as well as file name - note function name
  83.                 is assumed to go in the second %s pattern if there are
  84.                 two %s patterns.  
  85.             */
  86.     if( (ctl_patn = strstr( env_edit_cmd, "%s" )) == NULL )
  87.         {
  88.         fprintf( stderr,
  89.             "getf: environment variable GETFEDIT has no %%s pattern" );
  90.         exit(1);
  91.         }
  92.         
  93.     num_ctl_patns = strstr( ++ctl_patn, "%s" ) == NULL ? 1 : 2;
  94.     line_number_patn = strstr( ctl_patn, "%d" );
  95.  
  96. /*    strcpy( edit_cmd, env_edit_cmd );     -- not needed for DeSmet library */
  97.  
  98.     if( (pgm_name = strtok( edit_cmd, " " )) == NULL )
  99.         {
  100.         fprintf( stderr,
  101.             "getf: environment variable GETFEDIT has incorrect format" );
  102.         exit(1);
  103.         }
  104.  
  105.                     /* point to argument following program name */
  106.     arg1_ctl = edit_cmd + strlen(pgm_name) + 1;
  107.  
  108.     if( (funcs_file = fopen( file_name, "r" )) == NULL )
  109.         {
  110.         fprintf( stderr, "getf: can't open %s\n", *argv );
  111.         exit(1);
  112.         }
  113.     while( !eof )        /* loop through file names, which end with colon */
  114.         {
  115.         if( fgets( file_line, LINE_LEN, funcs_file ) == NULL )
  116.             break;
  117.                         /* bypass any line consisting of white space    */
  118.         if( (file_token = strtok( file_line, delim )) == NULL )
  119.             continue;
  120.  
  121.         if( file_token[ len = strlen(file_token) - 1 ] != ':' )
  122.             {
  123.             fprintf(stderr, "getf: incorrect file format in %s", file_name);
  124.             exit(1);
  125.             }
  126.         file_token[ len] = 0;    /* kill trailing colon */
  127.         last_func = FALSE;    /* set up to detect last func this file */
  128.  
  129.         while( !eof && !last_func )    /* loop through func names this file */
  130.                                     /* last such ends with semicolon    */
  131.             {
  132.             if( fgets( func_line, LINE_LEN, funcs_file ) == NULL )
  133.                 {
  134.                 eof = TRUE;
  135.                 break;
  136.                 }
  137.                             /* bypass any line consisting of white space */
  138.             if( (func_token = strtok( func_line, delim )) == NULL )
  139.                 continue;
  140.  
  141.                             /* read line number if present */
  142.             if( (line_token = strtok( NULL, delim )) != NULL )
  143.                 {line_number = atoi(line_token);
  144.                 last_token = line_token;
  145.                 }
  146.             else 
  147.                 {
  148.                 line_number = -1;
  149.                 last_token = func_token;
  150.                 }
  151.  
  152.             if( last_token[ len = strlen(last_token) - 1 ] == ';' )
  153.                 {
  154.                 last_func = TRUE;        /* break loop after this one    */
  155.                 last_token[ len ] = 0;    /* kill trailing semicolon        */
  156.                 }
  157.  
  158. #ifdef UNIX_PATTERNS
  159.             if( match( func_name, func_token ) )  /* use Unix style patterns */
  160. #else
  161.             if( patn_match( func_name, func_token ) )    /* use routine below */
  162. #endif
  163.                 {
  164.                 func_choices[num_choices] = strdup( func_token );
  165.                 file_choices[num_choices] = strdup( file_token );
  166.                 func_line_numbers[num_choices++] = line_number;
  167.                 }
  168.             }
  169.         }
  170.     switch( num_choices )
  171.         {
  172.         case 0:
  173.             fprintf( stderr, "getf: no match for %s in %s",
  174.                                     func_name, file_name );
  175.             exit(1);
  176.         case 1:
  177.             edit( func_choices[0], file_choices[0], func_line_numbers[0] );
  178.         default:
  179.             ask_for_file(func_choices, file_choices, func_line_numbers, 
  180.                                                             num_choices);
  181.         }
  182. }
  183.  
  184.     /*
  185.         Return TRUE if string s matches pattern patn, or FALSE if it
  186.         does not.  Allowable wildcards in patn are: 
  187.             ? for any one character, 
  188.             % for any string of characters up to the next underscore 
  189.               or end of string, and 
  190.             * for any string of characters up to end of string.
  191.     */
  192. int
  193. patn_match( patn, s )
  194. char *patn;        /* pattern */
  195. char *s;        /* string    */
  196. {
  197.     for ( ; *patn; patn++ )
  198.         {
  199.         if( !*s )        /* if out of s chars, no match        */
  200.             return        /* unless patn ends with * or %     */
  201.                 ((*patn == '*' || *patn == '%') && *(patn +1) );
  202.  
  203.         switch( *patn )
  204.             {
  205.             case '%':
  206.                 while( *s != '_' && *s )
  207.                     s++;
  208.                 break;
  209.             case '*':
  210.                 while( *s )
  211.                     s++;
  212.                 break;
  213.             case '?':
  214.                 s++;
  215.                 break;
  216.             default:
  217.                 if( *s != *patn )
  218.                     return FALSE;
  219.                 s++;
  220.             }
  221.         }
  222.     return *s == 0;
  223. }
  224.  
  225. void
  226. ask_for_file( func_choices, file_choices, func_line_numbers, num_choices )
  227. char *func_choices[], *file_choices[];
  228. int func_line_numbers[]; 
  229. unsigned int num_choices;
  230. {
  231.     int i;
  232.     char line[LINE_LEN];
  233.  
  234.     while( TRUE )
  235.         {
  236.         printf( "which one? (CR to exit)\n" );
  237.         for( i = 1; i <= num_choices; i++ )
  238.             printf( "\t%3d: %20s in %-30s\n", i, func_choices[i-1],
  239.                                                 file_choices[i-1] );
  240.         printf( "\nenter number: ");
  241.         fgets( line, LINE_LEN, stdin );
  242.  
  243.         if( line[0] == '\n' )
  244.             break;
  245.         if( (i = atoi(line)) < 1 || i > num_choices )
  246.             printf( "\ninvalid choice\n" );
  247.         else
  248.             edit( func_choices[i-1], 
  249.                 file_choices[i-1], 
  250.                 func_line_numbers[i-1] );
  251.         }
  252. }
  253.  
  254. /*
  255.     chain to the editor with the specified command 
  256. */
  257.     
  258. void
  259. edit( func, file, line )
  260. char *func, *file;
  261. int line;
  262. {
  263.     if( line_number_patn )
  264.         sprintf( arg1, arg1_ctl, file, line );
  265.     else if( num_ctl_patns == 1 )
  266.         sprintf( arg1, arg1_ctl, file );
  267.     else
  268.         sprintf( arg1, arg1_ctl, file, func );
  269.  
  270. #ifdef CHAIN
  271.     chain( pgm_name, arg1 );   
  272. #else
  273.             /* exclp will overlay this program with the editor */
  274.     execlp( pgm_name, pgm_name, arg1, NULL);
  275. #endif
  276.                     /* if we're still here, print error msg    */
  277.     fprintf( stderr, "getf: exec failed" );
  278.     exit(1);
  279. }
  280.         
  281. char *msg[] = 
  282. {"GETF version", VERSION, "\n",
  283. "        locate the source file containing a specified \n",
  284. "        function and present it in your favorite editor\n",
  285. "usage:  getf  function-name\n",
  286. "function-name may include Unix-style regular expressions:\n",
  287. "    *    Matches any string including the null string.\n",
  288. "    ?    Matches any single character.\n",
  289. "    [...]    Matches any one of the characters enclosed.\n",
  290. "    [~...]    Matches any character NOT enclosed.\n",
  291. "    -    May be used inside brackets to specify range\n",
  292. "        (i.e. x[1-58] matches x1, x2, ... x5, x8)\n",
  293. "    \\    Escapes special characters.\n",
  294. "    Other characters match themselves.\n",
  295. "example of environment variable:    GETFEDIT=\\bin\\see.exe %%s -l%%d",
  296. 0
  297. };
  298.  
  299. help()
  300. {    char **sp;
  301.     sp = msg;
  302.     while(*sp) printf(*sp++);
  303.     exit(0);
  304. }
  305.  
  306.