Index: source.c =================================================================== RCS file: /cvs/src/src/gdb/source.c,v retrieving revision 1.75 diff -u -p -r1.75 source.c --- source.c 15 May 2006 15:50:13 -0000 1.75 +++ source.c 5 Jul 2006 21:46:11 -0000 @@ -73,6 +73,13 @@ static void show_directories (char *, in char *source_path; +/* Support for source path substitution commands. */ + +static char *substitute_path_from = NULL; +static char *substitute_path_to = NULL; + +static struct cmd_list_element *substitute_path_cmdlist; + /* Symtab of default file for listing lines of. */ static struct symtab *current_source_symtab; @@ -828,6 +835,47 @@ source_full_path_of (char *filename, cha return 1; } +/* If the user specified a source path substitution rule, then + try applying it on PATH, and return the new path. This new + path must be deallocated afterwards. + + Return NULL if no substitution rule was specified by the user, + or of this rule didn't apply to the given PATH. */ + +static char * +xrewrite_source_path (const char *path) +{ + char *from_start; + char *new_path; + + /* If no path substitution rule was specified, then no rewrite + is actually needed. */ + + if (substitute_path_from == NULL) + return NULL; + + /* Search for the first occurence of SUBSTITUTE_PATH_FROM. + No substitution needed of not found. */ + + from_start = strstr (path, substitute_path_from); + + if (from_start == NULL) + return NULL; + + /* Compute the rewritten path and return it. */ + + new_path = (char *) malloc (strlen (path) + 1 + + strlen (substitute_path_to) + - strlen (substitute_path_from)); + strncpy (new_path, path, from_start - path); + strcpy (new_path + (from_start - path), + substitute_path_to); + strcat (new_path, + from_start + strlen (substitute_path_from)); + + return new_path; +} + /* This function is capable of finding the absolute path to a source file, and opening it, provided you give it an OBJFILE and FILENAME. Both the DIRNAME and FULLNAME are only @@ -844,7 +892,7 @@ source_full_path_of (char *filename, cha FULLNAME is set to the absolute path to the file just opened. On Failure - A non valid file descriptor is returned. ( the return value is negitive ) + A non valid file descriptor is returned. ( the return value is negative ) FULLNAME is set to NULL. */ int find_and_open_source (struct objfile *objfile, @@ -857,8 +905,22 @@ find_and_open_source (struct objfile *ob int result; /* Quick way out if we already know its full name */ + if (*fullname) { + { + /* The user may have requested that source paths be rewritten + according to a substitution rule he provided. Check if + this is the case, and do the rewrite if appropriate. */ + char *rewritten_fullname = xrewrite_source_path (*fullname); + + if (rewritten_fullname != NULL) + { + xfree (*fullname); + *fullname = rewritten_fullname; + } + } + result = open (*fullname, OPEN_MODE); if (result >= 0) return result; @@ -869,6 +931,27 @@ find_and_open_source (struct objfile *ob if (dirname != NULL) { + /* If necessary, rewrite the compilation directory name according + to the source path substitution rules specified by the user. + + Normally, we should really try to do the rewrite on the entire + path as opposed to just the directory name, but that's making + things much more complicated since we now have to concat the + dirname and filename, apply the substitution rule, and then do + [...] ??? How do we split the path back into dirname and filename? + In practice, the source path substitution feature should be used + when the entire tree has been moved, in which case only the root + part of the tree path will need to be rewritten. So this should + not be a problem in practice. */ + + char *rewritten_dirname = xrewrite_source_path (dirname); + + if (rewritten_dirname != NULL) + { + make_cleanup (xfree, rewritten_dirname); + dirname = rewritten_dirname; + } + /* Replace a path entry of $cdir with the compilation directory name */ #define cdir_len 5 /* We cast strstr's result in case an ANSIhole has made it const, @@ -1587,6 +1670,129 @@ reverse_search_command (char *regex, int fclose (stream); return; } + +/* Print the current source path substitution rule. */ + +static void +substitute_path_command (char *args, int from_tty) +{ + if (substitute_path_from == NULL) + printf_filtered (_("No source path substitution rule specified.\n")); + else + printf_filtered (_("`%s' in source paths now substituted with `%s'.\n"), + substitute_path_from, substitute_path_to); +} + +/* Extract the first argument (possibly quoted) from ARGS, and return it. + ARGS is updated to point right after that first argument. + The returned value must be deallocated afterwards. + + Return NULL is an argument could not be found. */ + +static char * +xextract_path_argument (char **args) +{ + int is_quoted; + char *p; + int arg_len; + char *path; + + /* First, skip any leading white spaces, and check that we have + at least one character left after the trimming. */ + + while (isspace (**args)) + (*args)++; + + if (**args == '\0') + return NULL; + + /* Find the first character after the first argument. */ + + p = skip_quoted_chars (*args, NULL, " \t"); + arg_len = p - *args; + + /* If the path was quoted, then remove the quotes. */ + + is_quoted = (strchr (get_gdb_completer_quote_characters (), **args) != NULL); + if (is_quoted) + { + if (strchr (get_gdb_completer_quote_characters (), + (*args)[arg_len - 1]) == NULL) + error (_("missing closing quote in argument: %s"), *args); + + arg_len -= 2; + (*args)++; + } + + /* If the argument is empty, then there is no real path, and hence + treat this as if the argumet was missing. */ + + if (arg_len < 1) + return NULL; + + path = (char *) xmalloc ((arg_len + 1) * sizeof (char)); + strncpy (path, *args, arg_len); + path[arg_len] = '\0'; + + *args = p; + + return path; +} + +/* Delete the current source path substitution rule. */ + +static void +substitute_path_remove_command (char *args, int from_tty) +{ + if (substitute_path_from != NULL) + { + xfree (substitute_path_from); + substitute_path_from = NULL; + } + + if (substitute_path_to != NULL) + { + xfree (substitute_path_to); + substitute_path_to = NULL; + } +} + +/* Add a new source path substitution rule. */ + +static void +substitute_path_add_command (char *args, int from_tty) +{ + char *from_path, *to_path; + + /* Extract the arguments from the command line. */ + + if (args == NULL) + error (_("Argument missing in command")); + + from_path = xextract_path_argument (&args); + if (from_path == NULL) + error (_("Argument missing in command")); + + to_path = xextract_path_argument (&args); + if (to_path == NULL) + { + xfree (from_path); + error (_("Argument missing in command")); + } + + /* Remove any previous substitution rule. */ + + substitute_path_remove_command (NULL, from_tty); + + /* Insert the new substitution rule, and print a confirmation message + to the user. */ + + substitute_path_from = from_path; + substitute_path_to = to_path; + + substitute_path_command (NULL, from_tty); +} + void _initialize_source (void) @@ -1666,4 +1872,22 @@ Show number of source lines gdb will lis NULL, show_lines_to_list, &setlist, &showlist); + + add_prefix_cmd ("substitute-path", class_files, substitute_path_command, + _("Show the current source path substitution rule."), + &substitute_path_cmdlist, "substitute-path ", + 0 /* allow-unknown */, &cmdlist); + + add_cmd ("add", class_files, substitute_path_add_command, + _("\ +Add a source path substitution rule. If a substitution rule was previously\n\ +set, it is overridden."), + &substitute_path_cmdlist); + + add_cmd ("remove", class_files, substitute_path_remove_command, + _("\ +Remove the current source path substitution rule. Has no effect\n\ +if no path substitution rule was previously specified."), + &substitute_path_cmdlist); + }