* Makefile.tpl: Introduce rules to serialize subconfigure runs.
[deliverable/binutils-gdb.git] / gdb / utils.c
index 4a1b577514303e2f5918bfcffa24a7dd9723752d..58af78ac9a23c44bd514d928973c4128056df6ac 100644 (file)
    Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-/* FIXME: cagney/2002-02-28: The GDB coding standard indicates that
-   "defs.h" should be included first.  Unfortunatly some systems
-   (currently Debian GNU/Linux) include the <stdbool.h> via <curses.h>
-   and they clash with "bfd.h"'s definiton of true/false.  The correct
-   fix is to remove true/false from "bfd.h", however, until that
-   happens, hack around it by including "config.h" and <curses.h>
-   first.  */
-
-#include "config.h"
-
-#ifdef HAVE_CURSES_H
-#include <curses.h>
-#endif
-#ifdef HAVE_TERM_H
-#include <term.h>
-#endif
-
 #include "defs.h"
 #include "gdb_assert.h"
 #include <ctype.h>
 #include "demangle.h"
 #include "expression.h"
 #include "language.h"
+#include "charset.h"
 #include "annotate.h"
+#include "filenames.h"
 
 #include "inferior.h" /* for signed_pointer_to_address */
 
 #include <sys/param.h>         /* For MAXPATHLEN */
 
+#ifdef HAVE_CURSES_H
+#include <curses.h>
+#endif
+#ifdef HAVE_TERM_H
+#include <term.h>
+#endif
+
 #include <readline/readline.h>
 
 #ifdef USE_MMALLOC
@@ -151,13 +143,13 @@ int quit_flag;
 
 int immediate_quit;
 
-/* Nonzero means that encoded C++ names should be printed out in their
-   C++ form rather than raw.  */
+/* Nonzero means that encoded C++/ObjC names should be printed out in their
+   C++/ObjC form rather than raw.  */
 
 int demangle = 1;
 
-/* Nonzero means that encoded C++ names should be printed out in their
-   C++ form even in assembler language displays.  If this is set, but
+/* Nonzero means that encoded C++/ObjC names should be printed out in their
+   C++/ObjC form even in assembler language displays.  If this is set, but
    DEMANGLE is zero, names are printed raw, i.e. DEMANGLE controls.  */
 
 int asm_demangle = 0;
@@ -673,19 +665,34 @@ error_init (void)
   gdb_lasterr = mem_fileopen ();
 }
 
-/* Print a message reporting an internal error. Ask the user if they
-   want to continue, dump core, or just exit. */
+/* Print a message reporting an internal error/warning. Ask the user
+   if they want to continue, dump core, or just exit.  Return
+   something to indicate a quit.  */
 
-NORETURN void
-internal_verror (const char *file, int line,
-                const char *fmt, va_list ap)
+struct internal_problem
 {
-  static char msg[] = "Internal GDB error: recursive internal error.\n";
-  static int dejavu = 0;
+  const char *name;
+  /* FIXME: cagney/2002-08-15: There should be ``maint set/show''
+     commands available for controlling these variables.  */
+  enum auto_boolean should_quit;
+  enum auto_boolean should_dump_core;
+};
+
+/* Report a problem, internal to GDB, to the user.  Once the problem
+   has been reported, and assuming GDB didn't quit, the caller can
+   either allow execution to resume or throw an error.  */
+
+static void
+internal_vproblem (struct internal_problem *problem,
+const char *file, int line,
+                 const char *fmt, va_list ap)
+{
+  static char msg[] = "Recursive internal problem.\n";
+  static int dejavu;
   int quit_p;
   int dump_core_p;
 
-  /* don't allow infinite error recursion. */
+  /* Don't allow infinite error/warning recursion.  */
   switch (dejavu)
     {
     case 0:
@@ -701,23 +708,58 @@ internal_verror (const char *file, int line,
       exit (1);
     }
 
-  /* Try to get the message out */
+  /* Try to get the message out and at the start of a new line.  */
   target_terminal_ours ();
-  fprintf_unfiltered (gdb_stderr, "%s:%d: gdb-internal-error: ", file, line);
+  begin_line ();
+
+  /* The error/warning message.  Format using a style similar to a
+     compiler error message.  */
+  fprintf_unfiltered (gdb_stderr, "%s:%d: %s: ", file, line, problem->name);
   vfprintf_unfiltered (gdb_stderr, fmt, ap);
   fputs_unfiltered ("\n", gdb_stderr);
 
-  /* Default (yes/batch case) is to quit GDB.  When in batch mode this
-     lessens the likelhood of GDB going into an infinate loop. */
-  quit_p = query ("\
-An internal GDB error was detected.  This may make further\n\
-debugging unreliable.  Quit this debugging session? ");
+  /* Provide more details so that the user knows that they are living
+     on the edge.  */
+  fprintf_unfiltered (gdb_stderr, "\
+A problem internal to GDB has been detected.  Further\n\
+debugging may prove unreliable.\n");
+
+  switch (problem->should_quit)
+    {
+    case AUTO_BOOLEAN_AUTO:
+      /* Default (yes/batch case) is to quit GDB.  When in batch mode
+        this lessens the likelhood of GDB going into an infinate
+        loop.  */
+      quit_p = query ("Quit this debugging session? ");
+      break;
+    case AUTO_BOOLEAN_TRUE:
+      quit_p = 1;
+      break;
+    case AUTO_BOOLEAN_FALSE:
+      quit_p = 0;
+      break;
+    default:
+      internal_error (__FILE__, __LINE__, "bad switch");
+    }
 
-  /* Default (yes/batch case) is to dump core.  This leaves a GDB
-     dropping so that it is easier to see that something went wrong to
-     GDB. */
-  dump_core_p = query ("\
-Create a core file containing the current state of GDB? ");
+  switch (problem->should_dump_core)
+    {
+    case AUTO_BOOLEAN_AUTO:
+      /* Default (yes/batch case) is to dump core.  This leaves a GDB
+        `dropping' so that it is easier to see that something went
+        wrong in GDB.  */
+      dump_core_p = query ("Create a core file of GDB? ");
+      break;
+      break;
+    case AUTO_BOOLEAN_TRUE:
+      dump_core_p = 1;
+      break;
+    case AUTO_BOOLEAN_FALSE:
+      dump_core_p = 0;
+      break;
+    default:
+      internal_error (__FILE__, __LINE__, "bad switch");
+    }
 
   if (quit_p)
     {
@@ -736,6 +778,17 @@ Create a core file containing the current state of GDB? ");
     }
 
   dejavu = 0;
+}
+
+static struct internal_problem internal_error_problem = {
+  "internal-error", AUTO_BOOLEAN_AUTO, AUTO_BOOLEAN_AUTO
+};
+
+NORETURN void
+internal_verror (const char *file, int line,
+                const char *fmt, va_list ap)
+{
+  internal_vproblem (&internal_error_problem, file, line, fmt, ap);
   throw_exception (RETURN_ERROR);
 }
 
@@ -744,11 +797,30 @@ internal_error (const char *file, int line, const char *string, ...)
 {
   va_list ap;
   va_start (ap, string);
-
   internal_verror (file, line, string, ap);
   va_end (ap);
 }
 
+static struct internal_problem internal_warning_problem = {
+  "internal-error", AUTO_BOOLEAN_AUTO, AUTO_BOOLEAN_AUTO
+};
+
+void
+internal_vwarning (const char *file, int line,
+                  const char *fmt, va_list ap)
+{
+  internal_vproblem (&internal_warning_problem, file, line, fmt, ap);
+}
+
+void
+internal_warning (const char *file, int line, const char *string, ...)
+{
+  va_list ap;
+  va_start (ap, string);
+  internal_vwarning (file, line, string, ap);
+  va_end (ap);
+}
+
 /* The strerror() function can return NULL for errno values that are
    out of range.  Provide a "safe" version that always returns a
    printable string. */
@@ -1281,6 +1353,23 @@ query (const char *ctlstr,...)
 }
 \f
 
+/* Print an error message saying that we couldn't make sense of a
+   \^mumble sequence in a string or character constant.  START and END
+   indicate a substring of some larger string that contains the
+   erroneous backslash sequence, missing the initial backslash.  */
+static NORETURN int
+no_control_char_error (const char *start, const char *end)
+{
+  int len = end - start;
+  char *copy = alloca (end - start + 1);
+
+  memcpy (copy, start, len);
+  copy[len] = '\0';
+
+  error ("There is no control character `\\%s' in the `%s' character set.",
+         copy, target_charset ());
+}
+
 /* Parse a C escape sequence.  STRING_PTR points to a variable
    containing a pointer to the string to parse.  That pointer
    should point to the character after the \.  That pointer
@@ -1299,37 +1388,55 @@ query (const char *ctlstr,...)
 int
 parse_escape (char **string_ptr)
 {
+  int target_char;
   register int c = *(*string_ptr)++;
-  switch (c)
+  if (c_parse_backslash (c, &target_char))
+    return target_char;
+  else switch (c)
     {
-    case 'a':
-      return 007;              /* Bell (alert) char */
-    case 'b':
-      return '\b';
-    case 'e':                  /* Escape character */
-      return 033;
-    case 'f':
-      return '\f';
-    case 'n':
-      return '\n';
-    case 'r':
-      return '\r';
-    case 't':
-      return '\t';
-    case 'v':
-      return '\v';
     case '\n':
       return -2;
     case 0:
       (*string_ptr)--;
       return 0;
     case '^':
-      c = *(*string_ptr)++;
-      if (c == '\\')
-       c = parse_escape (string_ptr);
-      if (c == '?')
-       return 0177;
-      return (c & 0200) | (c & 037);
+      {
+        /* Remember where this escape sequence started, for reporting
+           errors.  */
+        char *sequence_start_pos = *string_ptr - 1;
+
+        c = *(*string_ptr)++;
+
+        if (c == '?')
+          {
+            /* XXXCHARSET: What is `delete' in the host character set?  */
+            c = 0177;
+
+            if (! host_char_to_target (c, &target_char))
+              error ("There is no character corresponding to `Delete' "
+                     "in the target character set `%s'.",
+                     host_charset ());
+
+            return target_char;
+          }
+        else if (c == '\\')
+          target_char = parse_escape (string_ptr);
+        else
+          {
+            if (! host_char_to_target (c, &target_char))
+              no_control_char_error (sequence_start_pos, *string_ptr);
+          }          
+
+        /* Now target_char is something like `c', and we want to find
+           its control-character equivalent.  */
+        if (! target_char_to_control_char (target_char, &target_char))
+          no_control_char_error (sequence_start_pos, *string_ptr);
+
+        return target_char;
+      }
+
+      /* XXXCHARSET: we need to use isdigit and value-of-digit
+         methods of the host character set here.  */
 
     case '0':
     case '1':
@@ -1358,7 +1465,12 @@ parse_escape (char **string_ptr)
        return i;
       }
     default:
-      return c;
+      if (! host_char_to_target (c, &target_char))
+        error ("The escape sequence `\%c' is equivalent to plain `%c', which"
+               " has no equivalent\n"
+               "in the `%s' character set.",
+               c, c, target_charset ());
+      return target_char;
     }
 }
 \f
@@ -1602,7 +1714,7 @@ prompt_for_continue (void)
   /* Call readline, not gdb_readline, because GO32 readline handles control-C
      whereas control-C to gdb_readline will cause the user to get dumped
      out to DOS.  */
-  ignore = readline (cont_prompt);
+  ignore = gdb_readline_wrapper (cont_prompt);
 
   if (annotation_level > 1)
     printf_unfiltered ("\n\032\032post-prompt-for-continue\n");
@@ -1695,6 +1807,51 @@ wrap_here (char *indent)
     }
 }
 
+/* Print input string to gdb_stdout, filtered, with wrap, 
+   arranging strings in columns of n chars. String can be
+   right or left justified in the column.  Never prints 
+   trailing spaces.  String should never be longer than
+   width.  FIXME: this could be useful for the EXAMINE 
+   command, which currently doesn't tabulate very well */
+
+void
+puts_filtered_tabular (char *string, int width, int right)
+{
+  int spaces = 0;
+  int stringlen;
+  char *spacebuf;
+
+  gdb_assert (chars_per_line > 0);
+  if (chars_per_line == UINT_MAX)
+    {
+      fputs_filtered (string, gdb_stdout);
+      fputs_filtered ("\n", gdb_stdout);
+      return;
+    }
+
+  if (((chars_printed - 1) / width + 2) * width >= chars_per_line)
+    fputs_filtered ("\n", gdb_stdout);
+
+  if (width >= chars_per_line)
+    width = chars_per_line - 1;
+
+  stringlen = strlen (string);
+
+  if (chars_printed > 0)
+    spaces = width - (chars_printed - 1) % width - 1;
+  if (right)
+    spaces += width - stringlen;
+
+  spacebuf = alloca (spaces + 1);
+  spacebuf[spaces] = '\0';
+  while (spaces--)
+    spacebuf[spaces] = ' ';
+
+  fputs_filtered (spacebuf, gdb_stdout);
+  fputs_filtered (string, gdb_stdout);
+}
+
+
 /* Ensure that whatever gets printed next, using the filtered output
    commands, starts at the beginning of the line.  I.E. if there is
    any pending output for the current line, flush it and start a new
@@ -2122,7 +2279,7 @@ print_spaces_filtered (int n, struct ui_file *stream)
   fputs_filtered (n_spaces (n), stream);
 }
 \f
-/* C++ demangler stuff.  */
+/* C++/ObjC demangler stuff.  */
 
 /* fprintf_symbol_filtered attempts to demangle NAME, a symbol in language
    LANG, using demangling args ARG_MODE, and print it filtered to STREAM.
@@ -2152,9 +2309,15 @@ fprintf_symbol_filtered (struct ui_file *stream, char *name, enum language lang,
            case language_java:
              demangled = cplus_demangle (name, arg_mode | DMGL_JAVA);
              break;
-           case language_chill:
-             demangled = chill_demangle (name);
-             break;
+           case language_objc:
+             /* Commented out until ObjC handling is enabled.  */
+             /*demangled = objc_demangle (name);*/
+             /*break;*/
+#if 0
+             /* OBSOLETE case language_chill: */
+             /* OBSOLETE   demangled = chill_demangle (name); */
+             /* OBSOLETE   break; */
+#endif
            default:
              demangled = NULL;
              break;
@@ -2269,7 +2432,7 @@ initialize_utils (void)
   add_show_from_set
     (add_set_cmd ("demangle", class_support, var_boolean,
                  (char *) &demangle,
-            "Set demangling of encoded C++ names when displaying symbols.",
+            "Set demangling of encoded C++/ObjC names when displaying symbols.",
                  &setprintlist),
      &showprintlist);
 
@@ -2297,7 +2460,7 @@ initialize_utils (void)
   add_show_from_set
     (add_set_cmd ("asm-demangle", class_support, var_boolean,
                  (char *) &asm_demangle,
-                 "Set demangling of C++ names in disassembly listings.",
+                 "Set demangling of C++/ObjC names in disassembly listings.",
                  &setprintlist),
      &showprintlist);
 }
@@ -2461,9 +2624,7 @@ phex_nz (ULONGEST l, int sizeof_l)
 CORE_ADDR
 host_pointer_to_address (void *ptr)
 {
-  if (sizeof (ptr) != TYPE_LENGTH (builtin_type_void_data_ptr))
-    internal_error (__FILE__, __LINE__,
-                   "core_addr_to_void_ptr: bad cast");
+  gdb_assert (sizeof (ptr) == TYPE_LENGTH (builtin_type_void_data_ptr));
   return POINTER_TO_ADDRESS (builtin_type_void_data_ptr, &ptr);
 }
 
@@ -2471,9 +2632,8 @@ void *
 address_to_host_pointer (CORE_ADDR addr)
 {
   void *ptr;
-  if (sizeof (ptr) != TYPE_LENGTH (builtin_type_void_data_ptr))
-    internal_error (__FILE__, __LINE__,
-                   "core_addr_to_void_ptr: bad cast");
+
+  gdb_assert (sizeof (ptr) == TYPE_LENGTH (builtin_type_void_data_ptr));
   ADDRESS_TO_POINTER (builtin_type_void_data_ptr, &ptr, addr);
   return ptr;
 }
@@ -2534,25 +2694,118 @@ string_to_core_addr (const char *my_string)
 char *
 gdb_realpath (const char *filename)
 {
+  /* Method 1: The system has a compile time upper bound on a filename
+     path.  Use that and realpath() to canonicalize the name.  This is
+     the most common case.  Note that, if there isn't a compile time
+     upper bound, you want to avoid realpath() at all costs.  */
 #if defined(HAVE_REALPATH)
+  {
 # if defined (PATH_MAX)
-  char buf[PATH_MAX];
+    char buf[PATH_MAX];
 #  define USE_REALPATH
 # elif defined (MAXPATHLEN)
-  char buf[MAXPATHLEN];
-#  define USE_REALPATH
-# elif defined (HAVE_UNISTD_H) && defined(HAVE_ALLOCA)
-  char *buf = alloca ((size_t)pathconf ("/", _PC_PATH_MAX));
+    char buf[MAXPATHLEN];
 #  define USE_REALPATH
 # endif
+# if defined (USE_REALPATH)
+    const char *rp = realpath (filename, buf);
+    if (rp == NULL)
+      rp = filename;
+    return xstrdup (rp);
+  }
+# endif
 #endif /* HAVE_REALPATH */
 
-#if defined(USE_REALPATH)
-  char *rp = realpath (filename, buf);
-  return xstrdup (rp ? rp : filename);
-#elif defined(HAVE_CANONICALIZE_FILE_NAME)
-  return canonicalize_file_name (filename);
-#else
+  /* Method 2: The host system (i.e., GNU) has the function
+     canonicalize_file_name() which malloc's a chunk of memory and
+     returns that, use that.  */
+#if defined(HAVE_CANONICALIZE_FILE_NAME)
+  {
+    char *rp = canonicalize_file_name (filename);
+    if (rp == NULL)
+      return xstrdup (filename);
+    else
+      return rp;
+  }
+#endif
+
+  /* FIXME: cagney/2002-11-13:
+
+     Method 2a: Use realpath() with a NULL buffer.  Some systems, due
+     to the problems described in in method 3, have modified their
+     realpath() implementation so that it will allocate a buffer when
+     NULL is passed in.  Before this can be used, though, some sort of
+     configure time test would need to be added.  Otherwize the code
+     will likely core dump.  */
+
+  /* Method 3: Now we're getting desperate!  The system doesn't have a
+     compile time buffer size and no alternative function.  Query the
+     OS, using pathconf(), for the buffer limit.  Care is needed
+     though, some systems do not limit PATH_MAX (return -1 for
+     pathconf()) making it impossible to pass a correctly sized buffer
+     to realpath() (it could always overflow).  On those systems, we
+     skip this.  */
+#if defined (HAVE_REALPATH) && defined (HAVE_UNISTD_H) && defined(HAVE_ALLOCA)
+  {
+    /* Find out the max path size.  */
+    long path_max = pathconf ("/", _PC_PATH_MAX);
+    if (path_max > 0)
+      {
+       /* PATH_MAX is bounded.  */
+       char *buf = alloca (path_max);
+       char *rp = realpath (filename, buf);
+       return xstrdup (rp ? rp : filename);
+      }
+  }
+#endif
+
+  /* This system is a lost cause, just dup the buffer.  */
   return xstrdup (filename);
+}
+
+/* Return a copy of FILENAME, with its directory prefix canonicalized
+   by gdb_realpath.  */
+
+char *
+xfullpath (const char *filename)
+{
+  const char *base_name = lbasename (filename);
+  char *dir_name;
+  char *real_path;
+  char *result;
+
+  /* Extract the basename of filename, and return immediately 
+     a copy of filename if it does not contain any directory prefix. */
+  if (base_name == filename)
+    return xstrdup (filename);
+
+  dir_name = alloca ((size_t) (base_name - filename + 2));
+  /* Allocate enough space to store the dir_name + plus one extra
+     character sometimes needed under Windows (see below), and
+     then the closing \000 character */
+  strncpy (dir_name, filename, base_name - filename);
+  dir_name[base_name - filename] = '\000';
+
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+  /* We need to be careful when filename is of the form 'd:foo', which
+     is equivalent of d:./foo, which is totally different from d:/foo.  */
+  if (strlen (dir_name) == 2 &&
+      isalpha (dir_name[0]) && dir_name[1] == ':')
+    {
+      dir_name[2] = '.';
+      dir_name[3] = '\000';
+    }
 #endif
+
+  /* Canonicalize the directory prefix, and build the resulting
+     filename. If the dirname realpath already contains an ending
+     directory separator, avoid doubling it.  */
+  real_path = gdb_realpath (dir_name);
+  if (IS_DIR_SEPARATOR (real_path[strlen (real_path) - 1]))
+    result = concat (real_path, base_name, NULL);
+  else
+    result = concat (real_path, SLASH_STRING, base_name, NULL);
+
+  xfree (real_path);
+  return result;
 }
This page took 0.030829 seconds and 4 git commands to generate.