* source.c: Make global variables current_source_symtab and
[deliverable/binutils-gdb.git] / gdb / cli / cli-cmds.c
index 799e1f464d6e116e55890b064df4b5ca8eac25e4..0b5b857c98fd6c01a8752f09e1c9ba1b5bc17edd 100644 (file)
 #include "gdb_wait.h"          /* For shell escape implementation */
 #include "gdb_regex.h"         /* Used by apropos_command */
 #include "gdb_string.h"
+#include "linespec.h"
+#include "expression.h"
+#include "language.h"
 #include "filenames.h"         /* for DOSish file names */
+#include "objfiles.h"
+#include "source.h"
 
 #include "ui-out.h"
 
@@ -51,7 +56,7 @@ extern void set_history (char *, int);
 
 extern void show_commands (char *, int);
 
-/* Prototypes for local functions */
+/* Prototypes for local command functions */
 
 static void complete_command (char *, int);
 
@@ -79,7 +84,15 @@ static void make_command (char *, int);
 
 static void shell_escape (char *, int);
 
+static void edit_command (char *, int);
+
+static void list_command (char *, int);
+
 void apropos_command (char *, int);
+
+/* Prototypes for local utility functions */
+
+static void ambiguous_line_spec (struct symtabs_and_lines *);
 \f
 /* Limit the call depth of user-defined commands */
 int max_user_call_depth;
@@ -525,6 +538,281 @@ shell_escape (char *arg, int from_tty)
 #endif /* Can fork.  */
 }
 
+static void
+edit_command (char *arg, int from_tty)
+{
+  struct symtabs_and_lines sals;
+  struct symtab_and_line sal;
+  struct symbol *sym;
+  char *arg1;
+  int cmdlen, log10;
+  unsigned m;
+  char *editor;
+  char *p;
+
+  /* Pull in the current default source line if necessary */
+  if (arg == 0)
+    sal = get_current_or_default_source_symtab_and_line ();
+
+  /* bare "edit" edits file with present line.  */
+
+  if (arg == 0)
+    {
+      if (sal.symtab == 0)
+       error ("No default source file yet.");
+      sal.line += get_lines_to_list () / 2;
+    }
+  else
+    {
+
+      /* Now should only be one argument -- decode it in SAL */
+
+      arg1 = arg;
+      sals = decode_line_1 (&arg1, 0, 0, 0, 0);
+
+      if (! sals.nelts) return;  /*  C++  */
+      if (sals.nelts > 1) {
+        ambiguous_line_spec (&sals);
+        xfree (sals.sals);
+        return;
+      }
+
+      sal = sals.sals[0];
+      xfree (sals.sals);
+
+      if (*arg1)
+        error ("Junk at end of line specification.");
+
+      /* if line was specified by address,
+         first print exactly which line, and which file.
+         In this case, sal.symtab == 0 means address is outside
+         of all known source files, not that user failed to give a filename.  */
+      if (*arg == '*')
+        {
+          if (sal.symtab == 0)
+           /* FIXME-32x64--assumes sal.pc fits in long.  */
+           error ("No source file for address %s.",
+                  local_hex_string((unsigned long) sal.pc));
+          sym = find_pc_function (sal.pc);
+          if (sym)
+           {
+             print_address_numeric (sal.pc, 1, gdb_stdout);
+             printf_filtered (" is in ");
+             fputs_filtered (SYMBOL_SOURCE_NAME (sym), gdb_stdout);
+             printf_filtered (" (%s:%d).\n", sal.symtab->filename, sal.line);
+           }
+          else
+           {
+             print_address_numeric (sal.pc, 1, gdb_stdout);
+             printf_filtered (" is at %s:%d.\n",
+                              sal.symtab->filename, sal.line);
+           }
+        }
+
+      /* If what was given does not imply a symtab, it must be an undebuggable
+         symbol which means no source code.  */
+
+      if (sal.symtab == 0)
+        error ("No line number known for %s.", arg);
+    }
+
+  if ((editor = (char *) getenv ("EDITOR")) == NULL)
+      editor = "/bin/ex";
+  
+  /* Approximate base-10 log of line to 1 unit for digit count */
+  for(log10=32, m=0x80000000; !(sal.line & m) && log10>0; log10--, m=m>>1);
+  log10 = 1 + (int)((log10 + (0 == ((m-1) & sal.line)))/3.32192809);
+
+  cmdlen = strlen(editor) + 1
+         + (NULL == sal.symtab->dirname ? 0 : strlen(sal.symtab->dirname) + 1)
+        + (NULL == sal.symtab->filename? 0 : strlen(sal.symtab->filename)+ 1)
+        + log10 + 2;
+  
+  p = xmalloc(cmdlen);
+  sprintf(p,"%s +%d %s%s",editor,sal.line,
+     (NULL == sal.symtab->dirname ? "./" :
+        (NULL != sal.symtab->filename && *(sal.symtab->filename) != '/') ?
+          sal.symtab->dirname : ""),
+     (NULL == sal.symtab->filename ? "unknown" : sal.symtab->filename)
+  );
+  shell_escape(p, from_tty);
+
+  xfree(p);
+}
+
+static void
+list_command (char *arg, int from_tty)
+{
+  struct symtabs_and_lines sals, sals_end;
+  struct symtab_and_line sal, sal_end, cursal;
+  struct symbol *sym;
+  char *arg1;
+  int no_end = 1;
+  int dummy_end = 0;
+  int dummy_beg = 0;
+  int linenum_beg = 0;
+  char *p;
+
+  /* Pull in the current default source line if necessary */
+  if (arg == 0 || arg[0] == '+' || arg[0] == '-')
+    cursal = get_current_or_default_source_symtab_and_line ();
+
+  /* "l" or "l +" lists next ten lines.  */
+
+  if (arg == 0 || STREQ (arg, "+"))
+    {
+      print_source_lines (cursal.symtab, cursal.line,
+                         cursal.line + get_lines_to_list (), 0);
+      return;
+    }
+
+  /* "l -" lists previous ten lines, the ones before the ten just listed.  */
+  if (STREQ (arg, "-"))
+    {
+      print_source_lines (cursal.symtab,
+                         max (get_first_line_listed () - get_lines_to_list (), 1),
+                         get_first_line_listed (), 0);
+      return;
+    }
+
+  /* Now if there is only one argument, decode it in SAL
+     and set NO_END.
+     If there are two arguments, decode them in SAL and SAL_END
+     and clear NO_END; however, if one of the arguments is blank,
+     set DUMMY_BEG or DUMMY_END to record that fact.  */
+
+  if (!have_full_symbols () && !have_partial_symbols ())
+    error ("No symbol table is loaded.  Use the \"file\" command.");
+
+  arg1 = arg;
+  if (*arg1 == ',')
+    dummy_beg = 1;
+  else
+    {
+      sals = decode_line_1 (&arg1, 0, 0, 0, 0);
+
+      if (!sals.nelts)
+       return;                 /*  C++  */
+      if (sals.nelts > 1)
+       {
+         ambiguous_line_spec (&sals);
+         xfree (sals.sals);
+         return;
+       }
+
+      sal = sals.sals[0];
+      xfree (sals.sals);
+    }
+
+  /* Record whether the BEG arg is all digits.  */
+
+  for (p = arg; p != arg1 && *p >= '0' && *p <= '9'; p++);
+  linenum_beg = (p == arg1);
+
+  while (*arg1 == ' ' || *arg1 == '\t')
+    arg1++;
+  if (*arg1 == ',')
+    {
+      no_end = 0;
+      arg1++;
+      while (*arg1 == ' ' || *arg1 == '\t')
+       arg1++;
+      if (*arg1 == 0)
+       dummy_end = 1;
+      else
+       {
+         if (dummy_beg)
+           sals_end = decode_line_1 (&arg1, 0, 0, 0, 0);
+         else
+           sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line, 0);
+         if (sals_end.nelts == 0)
+           return;
+         if (sals_end.nelts > 1)
+           {
+             ambiguous_line_spec (&sals_end);
+             xfree (sals_end.sals);
+             return;
+           }
+         sal_end = sals_end.sals[0];
+         xfree (sals_end.sals);
+       }
+    }
+
+  if (*arg1)
+    error ("Junk at end of line specification.");
+
+  if (!no_end && !dummy_beg && !dummy_end
+      && sal.symtab != sal_end.symtab)
+    error ("Specified start and end are in different files.");
+  if (dummy_beg && dummy_end)
+    error ("Two empty args do not say what lines to list.");
+
+  /* if line was specified by address,
+     first print exactly which line, and which file.
+     In this case, sal.symtab == 0 means address is outside
+     of all known source files, not that user failed to give a filename.  */
+  if (*arg == '*')
+    {
+      if (sal.symtab == 0)
+       /* FIXME-32x64--assumes sal.pc fits in long.  */
+       error ("No source file for address %s.",
+              local_hex_string ((unsigned long) sal.pc));
+      sym = find_pc_function (sal.pc);
+      if (sym)
+       {
+         print_address_numeric (sal.pc, 1, gdb_stdout);
+         printf_filtered (" is in ");
+         fputs_filtered (SYMBOL_SOURCE_NAME (sym), gdb_stdout);
+         printf_filtered (" (%s:%d).\n", sal.symtab->filename, sal.line);
+       }
+      else
+       {
+         print_address_numeric (sal.pc, 1, gdb_stdout);
+         printf_filtered (" is at %s:%d.\n",
+                          sal.symtab->filename, sal.line);
+       }
+    }
+
+  /* If line was not specified by just a line number,
+     and it does not imply a symtab, it must be an undebuggable symbol
+     which means no source code.  */
+
+  if (!linenum_beg && sal.symtab == 0)
+    error ("No line number known for %s.", arg);
+
+  /* If this command is repeated with RET,
+     turn it into the no-arg variant.  */
+
+  if (from_tty)
+    *arg = 0;
+
+  if (dummy_beg && sal_end.symtab == 0)
+    error ("No default source file yet.  Do \"help list\".");
+  if (dummy_beg)
+    print_source_lines (sal_end.symtab,
+                       max (sal_end.line - (get_lines_to_list () - 1), 1),
+                       sal_end.line + 1, 0);
+  else if (sal.symtab == 0)
+    error ("No default source file yet.  Do \"help list\".");
+  else if (no_end)
+    {
+      int first_line = sal.line - get_lines_to_list () / 2;
+
+      if (first_line < 1) first_line = 1;
+
+      print_source_lines (sal.symtab,
+                         first_line,
+                         first_line + get_lines_to_list (),
+                         0);
+    }
+  else
+    print_source_lines (sal.symtab, sal.line,
+                       (dummy_end
+                        ? sal.line + get_lines_to_list ()
+                        : sal_end.line + 1),
+                       0);
+}
+
 static void
 make_command (char *arg, int from_tty)
 {
@@ -594,6 +882,21 @@ apropos_command (char *searchstr, int from_tty)
   xfree (pattern_fastmap);
 }
 \f
+/* Print a list of files and line numbers which a user may choose from
+   in order to list a function which was specified ambiguously (as with
+   `list classname::overloadedfuncname', for example).  The vector in
+   SALS provides the filenames and line numbers.  */
+
+static void
+ambiguous_line_spec (struct symtabs_and_lines *sals)
+{
+  int i;
+
+  for (i = 0; i < sals->nelts; ++i)
+    printf_filtered ("file: \"%s\", line number: %d\n",
+                    sals->sals[i].symtab->filename, sals->sals[i].line);
+}
+
 static void
 set_debug (char *arg, int from_tty)
 {
@@ -812,6 +1115,43 @@ from the target.", &setlist),
 With no arguments, run an inferior shell.");
   set_cmd_completer (c, filename_completer);
 
+  c = add_com ("edit", class_files, edit_command,
+           concat ("Edit specified file or function.\n\
+With no argument, edits file containing most recent line listed.\n\
+", "\
+Editing targets can be specified in these ways:\n\
+  FILE:LINENUM, to edit at that line in that file,\n\
+  FUNCTION, to edit at the beginning of that function,\n\
+  FILE:FUNCTION, to distinguish among like-named static functions.\n\
+  *ADDRESS, to edit at the line containing that address.\n\
+Uses EDITOR environment variable contents as editor (or ex as default).",NULL));
+
+  c->completer = location_completer;
+
+  add_com ("list", class_files, list_command,
+          concat ("List specified function or line.\n\
+With no argument, lists ten more lines after or around previous listing.\n\
+\"list -\" lists the ten lines before a previous ten-line listing.\n\
+One argument specifies a line, and ten lines are listed around that line.\n\
+Two arguments with comma between specify starting and ending lines to list.\n\
+", "\
+Lines can be specified in these ways:\n\
+  LINENUM, to list around that line in current file,\n\
+  FILE:LINENUM, to list around that line in that file,\n\
+  FUNCTION, to list around beginning of that function,\n\
+  FILE:FUNCTION, to distinguish among like-named static functions.\n\
+  *ADDRESS, to list around the line containing that address.\n\
+With two args if one is empty it stands for ten lines away from the other arg.", NULL));
+
+  if (!xdb_commands)
+    add_com_alias ("l", "list", class_files, 1);
+  else
+    add_com_alias ("v", "list", class_files, 1);
+
+  if (dbx_commands)
+    add_com_alias ("file", "list", class_files, 1);
+
+
   /* NOTE: cagney/2000-03-20: Being able to enter ``(gdb) !ls'' would
      be a really useful feature.  Unfortunately, the below wont do
      this.  Instead it adds support for the form ``(gdb) ! ls''
This page took 0.027386 seconds and 4 git commands to generate.