[PATCH v2] C++ify gdb/common/environ.c

Simon Marchi simon.marchi@polymtl.ca
Sat Apr 15 21:22:00 GMT 2017


On 2017-04-15 14:50, Sergio Durigan Junior wrote:
> diff --git a/gdb/charset.c b/gdb/charset.c
> index f55e482..a5ab383 100644
> --- a/gdb/charset.c
> +++ b/gdb/charset.c
> @@ -794,16 +794,14 @@ find_charset_names (void)
>    int err, status;
>    int fail = 1;
>    int flags;
> -  struct gdb_environ *iconv_env;
> +  std::unique_ptr<gdb_environ> iconv_env (new gdb_environ);

Can it be allocated on the stack?

>  void
> -set_in_environ (struct gdb_environ *e, const char *var, const char 
> *value)
> +gdb_environ::set_in_environ (const char *var, const char *value)
>  {
> -  int i;
> -  int len = strlen (var);
> -  char **vector = e->vector;
> -  char *s;
> +  std::unordered_map<std::string, std::string>::iterator el;
> +  bool needs_update = true;
> 
> -  for (i = 0; (s = vector[i]) != NULL; i++)
> -    if (strncmp (s, var, len) == 0 && s[len] == '=')
> -      break;
> +  el = this->env.find (var);
> 
> -  if (s == 0)
> +  if (el != this->env.end ())
>      {
> -      if (i == e->allocated)
> +      if (el->second.compare (value) == 0)

I think operator== will do what you want.

If you did a return here, you wouldn't need the needs_update variable.  
I don't mind though, some people prefer a single return point.

> diff --git a/gdb/common/environ.h b/gdb/common/environ.h
> index 3ace69e..c630425 100644
> --- a/gdb/common/environ.h
> +++ b/gdb/common/environ.h
> @@ -17,33 +17,55 @@
>  #if !defined (ENVIRON_H)
>  #define ENVIRON_H 1
> 
> -/* We manipulate environments represented as these structures.  */
> +#include <unordered_map>
> +#include <vector>

In the interface of gdb_environ, I think you could get rid of the 
"environ" in method names.  You can also remove the (void) for methods 
without parameters.

> 
> -struct gdb_environ
> -  {
> -    /* Number of usable slots allocated in VECTOR.
> -       VECTOR always has one slot not counted here,
> -       to hold the terminating zero.  */
> -    int allocated;
> -    /* A vector of slots, ALLOCATED + 1 of them.
> -       The first few slots contain strings "VAR=VALUE"
> -       and the next one contains zero.
> -       Then come some unused slots.  */
> -    char **vector;
> -  };
> +/* Class that represents the environment variables as seeing by the

s/as seeing/as seen/

> +   inferior.  */
> 
> -extern struct gdb_environ *make_environ (void);
> +class gdb_environ
> +{
> +public:
> +  /* Regular constructor and destructor.  */
> +  gdb_environ ();
> +  ~gdb_environ ();
> 
> -extern void free_environ (struct gdb_environ *);
> +  /* Reinitialize the environment stored.  This is used when the user
> +     wants to delete all environment variables added by him/her.  */
> +  void reinit_environ (void);
> 
> -extern void init_environ (struct gdb_environ *);
> +  /* Return the value in the environment for the variable VAR.  */
> +  char *get_in_environ (const char *var) const;

Looking at the users, I think that this could return const char *.  It 
would also be good to mention that the pointer is valid as long as the 
corresponding variable environment is not removed/replaced.

It could also return something based on std::string, but I don't know 
how good it would be:

1. returning const std::string &: can't return "NULL".
2. returning gdb::optional<std::string>: it works but makes a copy of 
the string, maybe it's ok since there isn't a ton of that.  It would 
however make the return value usable even after the corresponding 
variable is removed from the env.
3. returning gdb::optional<const std::string &>: I don't think it can be 
done.
4. returning gdb::optional<std::reference_wrapper<const std::string>>: 
it works, but it gets a bit ugly.

One thing is sure, since you are constructing some std::string inside 
the methods, you could change the parameters in the interface from const 
char * to const std::string &.  With the implicit string constructor 
from const char *, the users won't have to be changed, but it will be 
possible to pass an std::string directly.

> 
> -extern char *get_in_environ (const struct gdb_environ *, const char 
> *);
> +  /* Store VAR=VALUE in the environment.  */
> +  void set_in_environ (const char *var, const char *value);
> 
> -extern void set_in_environ (struct gdb_environ *, const char *, const 
> char *);
> +  /* Unset VAR in environment.  */
> +  void unset_in_environ (const char *var);
> 
> -extern void unset_in_environ (struct gdb_environ *, const char *);
> +  /* Return the environment vector represented as a 'char **'.  */
> +  char **get_environ_char_vector (void) const;
> 
> -extern char **environ_vector (struct gdb_environ *);
> +  /* Return the environment vector.  */
> +  std::vector<char *> get_environ_vector (void) const;

Return a const reference, and change the (sole) user of this method to 
get a reference too?

> @@ -2159,11 +2160,12 @@ environment_info (char *var, int from_tty)
>      }
>    else
>      {
> -      char **vector = environ_vector (current_inferior 
> ()->environment);
> +      std::vector<char *> vector =
> +	current_inferior ()->environment->get_environ_vector ();
> 
> -      while (*vector)
> +      for (char *&elem : vector)

Is there advantage of doing

   for (char *&elem : vector)

vs

   for (char *elem : vector)

?

> diff --git a/gdb/inferior.h b/gdb/inferior.h
> index b5eb3d1..e48d5cb 100644
> --- a/gdb/inferior.h
> +++ b/gdb/inferior.h
> @@ -42,6 +42,9 @@ struct continuation;
>  /* For struct frame_id.  */
>  #include "frame.h"
> 
> +/* For gdb_environ.  */
> +#include "environ.h"
> +

You can remove the "struct gdb_environ;" above this.

>  #include "progspace.h"
>  #include "registry.h"
> 
> @@ -362,7 +365,7 @@ public:
> 
>    /* Environment to use for running inferior,
>       in format described in environ.h.  */
> -  gdb_environ *environment = NULL;
> +  std::unique_ptr<gdb_environ> environment;

Can this be simply

   gdb_environ environment;

?

> @@ -270,7 +270,7 @@ mi_cmd_inferior_tty_show (const char *command,
> char **argv, int argc)
>  void
>  _initialize_mi_cmd_env (void)
>  {
> -  struct gdb_environ *environment;
> +  std::unique_ptr<gdb_environ> environment (new gdb_environ);

Again, can it be allocated on the stack?

Thanks,

Simon



More information about the Gdb-patches mailing list