PR gas/14201
[deliverable/binutils-gdb.git] / gdb / utils.c
index cc93915cadbd64d87b5271e040dee1642c276d9f..2d607efd7a66c065cd4b9661ccb38f3648dc0ad8 100644 (file)
@@ -1,8 +1,6 @@
 /* General utility routines for GDB, the GNU debugger.
 
-   Copyright (C) 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
-   1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
-   2009, 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 1986, 1988-2012 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -24,6 +22,7 @@
 #include "gdb_assert.h"
 #include <ctype.h>
 #include "gdb_string.h"
+#include "gdb_wait.h"
 #include "event-top.h"
 #include "exceptions.h"
 #include "gdbthread.h"
@@ -100,8 +99,6 @@ static void vfprintf_maybe_filtered (struct ui_file *, const char *,
 
 static void fputs_maybe_filtered (const char *, struct ui_file *, int);
 
-static void do_my_cleanups (struct cleanup **, struct cleanup *);
-
 static void prompt_for_continue (void);
 
 static void set_screen_size (void);
@@ -111,12 +108,6 @@ static void set_width (void);
 
 static int debug_timestamp = 0;
 
-/* Chain of cleanup actions established with make_cleanup,
-   to be executed if an error happens.  */
-
-static struct cleanup *cleanup_chain;  /* cleaned up after a failed command */
-static struct cleanup *final_cleanup_chain;    /* cleaned up when gdb exits */
-
 /* Nonzero if we have job control.  */
 
 int job_control;
@@ -173,31 +164,11 @@ show_pagination_enabled (struct ui_file *file, int from_tty,
 }
 
 \f
+/* Cleanup utilities.
 
-/* Add a new cleanup to the cleanup_chain,
-   and return the previous chain pointer
-   to be passed later to do_cleanups or discard_cleanups.
-   Args are FUNCTION to clean up with, and ARG to pass to it.  */
-
-struct cleanup *
-make_cleanup (make_cleanup_ftype *function, void *arg)
-{
-  return make_my_cleanup (&cleanup_chain, function, arg);
-}
-
-struct cleanup *
-make_cleanup_dtor (make_cleanup_ftype *function, void *arg,
-                  void (*dtor) (void *))
-{
-  return make_my_cleanup2 (&cleanup_chain,
-                          function, arg, dtor);
-}
-
-struct cleanup *
-make_final_cleanup (make_cleanup_ftype *function, void *arg)
-{
-  return make_my_cleanup (&final_cleanup_chain, function, arg);
-}
+   These are not defined in cleanups.c (nor declared in cleanups.h)
+   because while they use the "cleanup API" they are not part of the
+   "cleanup API".  */
 
 static void
 do_freeargv (void *arg)
@@ -208,7 +179,7 @@ do_freeargv (void *arg)
 struct cleanup *
 make_cleanup_freeargv (char **arg)
 {
-  return make_my_cleanup (&cleanup_chain, do_freeargv, arg);
+  return make_cleanup (do_freeargv, arg);
 }
 
 static void
@@ -220,7 +191,7 @@ do_dyn_string_delete (void *arg)
 struct cleanup *
 make_cleanup_dyn_string_delete (dyn_string_t arg)
 {
-  return make_my_cleanup (&cleanup_chain, do_dyn_string_delete, arg);
+  return make_cleanup (do_dyn_string_delete, arg);
 }
 
 static void
@@ -297,7 +268,7 @@ do_ui_file_delete (void *arg)
 struct cleanup *
 make_cleanup_ui_file_delete (struct ui_file *arg)
 {
-  return make_my_cleanup (&cleanup_chain, do_ui_file_delete, arg);
+  return make_cleanup (do_ui_file_delete, arg);
 }
 
 /* Helper function for make_cleanup_ui_out_redirect_pop.  */
@@ -317,7 +288,7 @@ do_ui_out_redirect_pop (void *arg)
 struct cleanup *
 make_cleanup_ui_out_redirect_pop (struct ui_out *uiout)
 {
-  return make_my_cleanup (&cleanup_chain, do_ui_out_redirect_pop, uiout);
+  return make_cleanup (do_ui_out_redirect_pop, uiout);
 }
 
 static void
@@ -329,7 +300,7 @@ do_free_section_addr_info (void *arg)
 struct cleanup *
 make_cleanup_free_section_addr_info (struct section_addr_info *addrs)
 {
-  return make_my_cleanup (&cleanup_chain, do_free_section_addr_info, addrs);
+  return make_cleanup (do_free_section_addr_info, addrs);
 }
 
 struct restore_integer_closure
@@ -358,8 +329,7 @@ make_cleanup_restore_integer (int *variable)
   c->variable = variable;
   c->value = *variable;
 
-  return make_my_cleanup2 (&cleanup_chain, restore_integer, (void *)c,
-                          xfree);
+  return make_cleanup_dtor (restore_integer, (void *) c, xfree);
 }
 
 /* Remember the current value of *VARIABLE and make it restored when
@@ -386,7 +356,7 @@ do_unpush_target (void *arg)
 struct cleanup *
 make_cleanup_unpush_target (struct target_ops *ops)
 {
-  return make_my_cleanup (&cleanup_chain, do_unpush_target, ops);
+  return make_cleanup (do_unpush_target, ops);
 }
 
 /* Helper for make_cleanup_htab_delete compile time checking the types.  */
@@ -449,7 +419,7 @@ do_value_free_to_mark (void *value)
 struct cleanup *
 make_cleanup_value_free_to_mark (struct value *mark)
 {
-  return make_my_cleanup (&cleanup_chain, do_value_free_to_mark, mark);
+  return make_cleanup (do_value_free_to_mark, mark);
 }
 
 /* Helper for make_cleanup_value_free.  */
@@ -465,7 +435,7 @@ do_value_free (void *value)
 struct cleanup *
 make_cleanup_value_free (struct value *value)
 {
-  return make_my_cleanup (&cleanup_chain, do_value_free, value);
+  return make_cleanup (do_value_free, value);
 }
 
 /* Helper for make_cleanup_free_so.  */
@@ -483,133 +453,7 @@ do_free_so (void *arg)
 struct cleanup *
 make_cleanup_free_so (struct so_list *so)
 {
-  return make_my_cleanup (&cleanup_chain, do_free_so, so);
-}
-
-struct cleanup *
-make_my_cleanup2 (struct cleanup **pmy_chain, make_cleanup_ftype *function,
-                 void *arg,  void (*free_arg) (void *))
-{
-  struct cleanup *new
-    = (struct cleanup *) xmalloc (sizeof (struct cleanup));
-  struct cleanup *old_chain = *pmy_chain;
-
-  new->next = *pmy_chain;
-  new->function = function;
-  new->free_arg = free_arg;
-  new->arg = arg;
-  *pmy_chain = new;
-
-  return old_chain;
-}
-
-struct cleanup *
-make_my_cleanup (struct cleanup **pmy_chain, make_cleanup_ftype *function,
-                void *arg)
-{
-  return make_my_cleanup2 (pmy_chain, function, arg, NULL);
-}
-
-/* Discard cleanups and do the actions they describe
-   until we get back to the point OLD_CHAIN in the cleanup_chain.  */
-
-void
-do_cleanups (struct cleanup *old_chain)
-{
-  do_my_cleanups (&cleanup_chain, old_chain);
-}
-
-void
-do_final_cleanups (struct cleanup *old_chain)
-{
-  do_my_cleanups (&final_cleanup_chain, old_chain);
-}
-
-static void
-do_my_cleanups (struct cleanup **pmy_chain,
-               struct cleanup *old_chain)
-{
-  struct cleanup *ptr;
-
-  while ((ptr = *pmy_chain) != old_chain)
-    {
-      *pmy_chain = ptr->next;  /* Do this first in case of recursion.  */
-      (*ptr->function) (ptr->arg);
-      if (ptr->free_arg)
-       (*ptr->free_arg) (ptr->arg);
-      xfree (ptr);
-    }
-}
-
-/* Discard cleanups, not doing the actions they describe,
-   until we get back to the point OLD_CHAIN in the cleanup_chain.  */
-
-void
-discard_cleanups (struct cleanup *old_chain)
-{
-  discard_my_cleanups (&cleanup_chain, old_chain);
-}
-
-void
-discard_final_cleanups (struct cleanup *old_chain)
-{
-  discard_my_cleanups (&final_cleanup_chain, old_chain);
-}
-
-void
-discard_my_cleanups (struct cleanup **pmy_chain,
-                    struct cleanup *old_chain)
-{
-  struct cleanup *ptr;
-
-  while ((ptr = *pmy_chain) != old_chain)
-    {
-      *pmy_chain = ptr->next;
-      if (ptr->free_arg)
-       (*ptr->free_arg) (ptr->arg);
-      xfree (ptr);
-    }
-}
-
-/* Set the cleanup_chain to 0, and return the old cleanup chain.  */
-struct cleanup *
-save_cleanups (void)
-{
-  return save_my_cleanups (&cleanup_chain);
-}
-
-struct cleanup *
-save_final_cleanups (void)
-{
-  return save_my_cleanups (&final_cleanup_chain);
-}
-
-struct cleanup *
-save_my_cleanups (struct cleanup **pmy_chain)
-{
-  struct cleanup *old_chain = *pmy_chain;
-
-  *pmy_chain = 0;
-  return old_chain;
-}
-
-/* Restore the cleanup chain from a previously saved chain.  */
-void
-restore_cleanups (struct cleanup *chain)
-{
-  restore_my_cleanups (&cleanup_chain, chain);
-}
-
-void
-restore_final_cleanups (struct cleanup *chain)
-{
-  restore_my_cleanups (&final_cleanup_chain, chain);
-}
-
-void
-restore_my_cleanups (struct cleanup **pmy_chain, struct cleanup *chain)
-{
-  *pmy_chain = chain;
+  return make_cleanup (do_free_so, so);
 }
 
 /* This function is useful for cleanups.
@@ -635,18 +479,6 @@ free_current_contents (void *ptr)
     }
 }
 
-/* Provide a known function that does nothing, to use as a base for
-   a possibly long chain of cleanups.  This is useful where we
-   use the cleanup chain for handling normal cleanups as well as dealing
-   with cleanups that need to be done as a result of a call to error().
-   In such cases, we may not be certain where the first cleanup is, unless
-   we have a do-nothing one to always use as the base.  */
-
-void
-null_cleanup (void *arg)
-{
-}
-
 /* If nonzero, display time usage both at startup and for each command.  */
 
 static int display_time;
@@ -887,7 +719,7 @@ can_dump_core (const char *reason)
 const char internal_problem_ask[] = "ask";
 const char internal_problem_yes[] = "yes";
 const char internal_problem_no[] = "no";
-static const char *internal_problem_modes[] =
+static const char *const internal_problem_modes[] =
 {
   internal_problem_ask,
   internal_problem_yes,
@@ -971,7 +803,7 @@ internal_vproblem (struct internal_problem *problem,
       /* Default (yes/batch case) is to quit GDB.  When in batch mode
         this lessens the likelihood of GDB going into an infinite
         loop.  */
-      if (caution == 0)
+      if (!confirm)
         {
           /* Emit the message and quit.  */
           fputs_unfiltered (reason, gdb_stderr);
@@ -1385,7 +1217,7 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args)
 
   /* Automatically answer the default value if the user did not want
      prompts or the command was issued with the server prefix.  */
-  if (! caution || server_command)
+  if (!confirm || server_command)
     return def_value;
 
   /* If input isn't coming from the user directly, just say what
@@ -2590,7 +2422,7 @@ print_spaces_filtered (int n, struct ui_file *stream)
    demangling is off, the name is printed in its "raw" form.  */
 
 void
-fprintf_symbol_filtered (struct ui_file *stream, char *name,
+fprintf_symbol_filtered (struct ui_file *stream, const char *name,
                         enum language lang, int arg_mode)
 {
   char *demangled;
@@ -3340,6 +3172,25 @@ gdb_realpath (const char *filename)
   }
 #endif
 
+  /* The MS Windows method.  If we don't have realpath, we assume we
+     don't have symlinks and just canonicalize to a Windows absolute
+     path.  GetFullPath converts ../ and ./ in relative paths to
+     absolute paths, filling in current drive if one is not given
+     or using the current directory of a specified drive (eg, "E:foo").
+     It also converts all forward slashes to back slashes.  */
+  /* The file system is case-insensitive but case-preserving.
+     So we do not lowercase the path.  Otherwise, we might not
+     be able to display the original casing in a given path.  */
+#if defined (_WIN32)
+  {
+    char buf[MAX_PATH];
+    DWORD len = GetFullPathName (filename, MAX_PATH, buf, NULL);
+
+    if (len > 0 && len < MAX_PATH)
+      return xstrdup (buf);
+  }
+#endif
+
   /* This system is a lost cause, just dup the buffer.  */
   return xstrdup (filename);
 }
@@ -3784,6 +3635,211 @@ producer_is_gcc_ge_4 (const char *producer)
   return minor;
 }
 
+/* Call xfree for each element of CHAR_PTR_VEC and final VEC_free for
+   CHAR_PTR_VEC itself.
+
+   You must not modify CHAR_PTR_VEC after it got registered with this function
+   by make_cleanup as the CHAR_PTR_VEC base address may change on its updates.
+   Contrary to VEC_free this function does not (cannot) clear the pointer.  */
+
+void
+free_char_ptr_vec (VEC (char_ptr) *char_ptr_vec)
+{
+  int ix;
+  char *name;
+
+  for (ix = 0; VEC_iterate (char_ptr, char_ptr_vec, ix, name); ++ix)
+    xfree (name);
+  VEC_free (char_ptr, char_ptr_vec);
+}
+
+/* Helper for make_cleanup_free_char_ptr_vec.  */
+
+static void
+do_free_char_ptr_vec (void *arg)
+{
+  VEC (char_ptr) *char_ptr_vec = arg;
+
+  free_char_ptr_vec (char_ptr_vec);
+}
+
+/* Make cleanup handler calling xfree for each element of CHAR_PTR_VEC and
+   final VEC_free for CHAR_PTR_VEC itself.
+
+   You must not modify CHAR_PTR_VEC after this cleanup registration as the
+   CHAR_PTR_VEC base address may change on its updates.  Contrary to VEC_free
+   this function does not (cannot) clear the pointer.  */
+
+struct cleanup *
+make_cleanup_free_char_ptr_vec (VEC (char_ptr) *char_ptr_vec)
+{
+  return make_cleanup (do_free_char_ptr_vec, char_ptr_vec);
+}
+
+/* Extended version of dirnames_to_char_ptr_vec - additionally if *VECP is
+   non-NULL the new list elements from DIRNAMES are appended to the existing
+   *VECP list of entries.  *VECP address will be updated by this call.  */
+
+void
+dirnames_to_char_ptr_vec_append (VEC (char_ptr) **vecp, const char *dirnames)
+{
+  do
+    {
+      size_t this_len;
+      char *next_dir, *this_dir;
+
+      next_dir = strchr (dirnames, DIRNAME_SEPARATOR);
+      if (next_dir == NULL)
+       this_len = strlen (dirnames);
+      else
+       {
+         this_len = next_dir - dirnames;
+         next_dir++;
+       }
+
+      this_dir = xmalloc (this_len + 1);
+      memcpy (this_dir, dirnames, this_len);
+      this_dir[this_len] = '\0';
+      VEC_safe_push (char_ptr, *vecp, this_dir);
+
+      dirnames = next_dir;
+    }
+  while (dirnames != NULL);
+}
+
+/* Split DIRNAMES by DIRNAME_SEPARATOR delimiter and return a list of all the
+   elements in their original order.  For empty string ("") DIRNAMES return
+   list of one empty string ("") element.
+   
+   You may modify the returned strings.
+   Read free_char_ptr_vec for its cleanup.  */
+
+VEC (char_ptr) *
+dirnames_to_char_ptr_vec (const char *dirnames)
+{
+  VEC (char_ptr) *retval = NULL;
+  
+  dirnames_to_char_ptr_vec_append (&retval, dirnames);
+
+  return retval;
+}
+
+/* Substitute all occurences of string FROM by string TO in *STRINGP.  *STRINGP
+   must come from xrealloc-compatible allocator and it may be updated.  FROM
+   needs to be delimited by IS_DIR_SEPARATOR or DIRNAME_SEPARATOR (or be
+   located at the start or end of *STRINGP.  */
+
+void
+substitute_path_component (char **stringp, const char *from, const char *to)
+{
+  char *string = *stringp, *s;
+  const size_t from_len = strlen (from);
+  const size_t to_len = strlen (to);
+
+  for (s = string;;)
+    {
+      s = strstr (s, from);
+      if (s == NULL)
+       break;
+
+      if ((s == string || IS_DIR_SEPARATOR (s[-1])
+          || s[-1] == DIRNAME_SEPARATOR)
+          && (s[from_len] == '\0' || IS_DIR_SEPARATOR (s[from_len])
+             || s[from_len] == DIRNAME_SEPARATOR))
+       {
+         char *string_new;
+
+         string_new = xrealloc (string, (strlen (string) + to_len + 1));
+
+         /* Relocate the current S pointer.  */
+         s = s - string + string_new;
+         string = string_new;
+
+         /* Replace from by to.  */
+         memmove (&s[to_len], &s[from_len], strlen (&s[from_len]) + 1);
+         memcpy (s, to, to_len);
+
+         s += to_len;
+       }
+      else
+       s++;
+    }
+
+  *stringp = string;
+}
+
+#ifdef HAVE_WAITPID
+
+#ifdef SIGALRM
+
+/* SIGALRM handler for waitpid_with_timeout.  */
+
+static void
+sigalrm_handler (int signo)
+{
+  /* Nothing to do.  */
+}
+
+#endif
+
+/* Wrapper to wait for child PID to die with TIMEOUT.
+   TIMEOUT is the time to stop waiting in seconds.
+   If TIMEOUT is zero, pass WNOHANG to waitpid.
+   Returns PID if it was successfully waited for, otherwise -1.
+
+   Timeouts are currently implemented with alarm and SIGALRM.
+   If the host does not support them, this waits "forever".
+   It would be odd though for a host to have waitpid and not SIGALRM.  */
+
+pid_t
+wait_to_die_with_timeout (pid_t pid, int *status, int timeout)
+{
+  pid_t waitpid_result;
+
+  gdb_assert (pid > 0);
+  gdb_assert (timeout >= 0);
+
+  if (timeout > 0)
+    {
+#ifdef SIGALRM
+#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
+      struct sigaction sa, old_sa;
+
+      sa.sa_handler = sigalrm_handler;
+      sigemptyset (&sa.sa_mask);
+      sa.sa_flags = 0;
+      sigaction (SIGALRM, &sa, &old_sa);
+#else
+      void (*ofunc) ();
+
+      ofunc = (void (*)()) signal (SIGALRM, sigalrm_handler);
+#endif
+
+      alarm (timeout);
+#endif
+
+      waitpid_result = waitpid (pid, status, 0);
+
+#ifdef SIGALRM
+      alarm (0);
+#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
+      sigaction (SIGALRM, &old_sa, NULL);
+#else
+      signal (SIGALRM, ofunc);
+#endif
+#endif
+    }
+  else
+    waitpid_result = waitpid (pid, status, WNOHANG);
+
+  if (waitpid_result == pid)
+    return pid;
+  else
+    return -1;
+}
+
+#endif /* HAVE_WAITPID */
+
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 extern initialize_file_ftype _initialize_utils;
 
This page took 0.031729 seconds and 4 git commands to generate.