1/* MI Command Set - environment commands.
2
3   Copyright (C) 2002, 2003, 2004, 2007, 2008, 2009, 2010, 2011
4   Free Software Foundation, Inc.
5
6   Contributed by Red Hat Inc.
7
8   This file is part of GDB.
9
10   This program is free software; you can redistribute it and/or modify
11   it under the terms of the GNU General Public License as published by
12   the Free Software Foundation; either version 3 of the License, or
13   (at your option) any later version.
14
15   This program is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   GNU General Public License for more details.
19
20   You should have received a copy of the GNU General Public License
21   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
22
23#include "defs.h"
24#include "inferior.h"
25#include "value.h"
26#include "mi-out.h"
27#include "mi-cmds.h"
28#include "mi-getopt.h"
29#include "symtab.h"
30#include "target.h"
31#include "environ.h"
32#include "command.h"
33#include "ui-out.h"
34#include "top.h"
35
36#include "gdb_string.h"
37#include "gdb_stat.h"
38
39static void env_mod_path (char *dirname, char **which_path);
40extern void _initialize_mi_cmd_env (void);
41
42static const char path_var_name[] = "PATH";
43static char *orig_path = NULL;
44
45/* The following is copied from mi-main.c so for m1 and below we can
46   perform old behavior and use cli commands.  If ARGS is non-null,
47   append it to the CMD.  */
48static void
49env_execute_cli_command (const char *cmd, const char *args)
50{
51  if (cmd != 0)
52    {
53      struct cleanup *old_cleanups;
54      char *run;
55
56      if (args != NULL)
57	run = xstrprintf ("%s %s", cmd, args);
58      else
59	run = xstrdup (cmd);
60      old_cleanups = make_cleanup (xfree, run);
61      execute_command ( /*ui */ run, 0 /*from_tty */ );
62      do_cleanups (old_cleanups);
63      return;
64    }
65}
66
67
68/* Print working directory.  */
69void
70mi_cmd_env_pwd (char *command, char **argv, int argc)
71{
72  if (argc > 0)
73    error (_("-environment-pwd: No arguments required"));
74
75  if (mi_version (uiout) < 2)
76    {
77      env_execute_cli_command ("pwd", NULL);
78      return;
79    }
80
81  /* Otherwise the mi level is 2 or higher.  */
82
83  if (! getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)))
84    error (_("-environment-pwd: error finding name of working directory: %s"),
85           safe_strerror (errno));
86
87  ui_out_field_string (uiout, "cwd", gdb_dirbuf);
88}
89
90/* Change working directory.  */
91void
92mi_cmd_env_cd (char *command, char **argv, int argc)
93{
94  if (argc == 0 || argc > 1)
95    error (_("-environment-cd: Usage DIRECTORY"));
96
97  env_execute_cli_command ("cd", argv[0]);
98}
99
100static void
101env_mod_path (char *dirname, char **which_path)
102{
103  if (dirname == 0 || dirname[0] == '\0')
104    return;
105
106  /* Call add_path with last arg 0 to indicate not to parse for
107     separator characters.  */
108  add_path (dirname, which_path, 0);
109}
110
111/* Add one or more directories to start of executable search path.  */
112void
113mi_cmd_env_path (char *command, char **argv, int argc)
114{
115  char *exec_path;
116  char *env;
117  int reset = 0;
118  int optind = 0;
119  int i;
120  char *optarg;
121  enum opt
122    {
123      RESET_OPT
124    };
125  static struct mi_opt opts[] =
126  {
127    {"r", RESET_OPT, 0},
128    { 0, 0, 0 }
129  };
130
131  dont_repeat ();
132
133  if (mi_version (uiout) < 2)
134    {
135      for (i = argc - 1; i >= 0; --i)
136	env_execute_cli_command ("path", argv[i]);
137      return;
138    }
139
140  /* Otherwise the mi level is 2 or higher.  */
141  while (1)
142    {
143      int opt = mi_getopt ("-environment-path", argc, argv, opts,
144                           &optind, &optarg);
145
146      if (opt < 0)
147        break;
148      switch ((enum opt) opt)
149        {
150        case RESET_OPT:
151          reset = 1;
152          break;
153        }
154    }
155  argv += optind;
156  argc -= optind;
157
158
159  if (reset)
160    {
161      /* Reset implies resetting to original path first.  */
162      exec_path = xstrdup (orig_path);
163    }
164  else
165    {
166      /* Otherwise, get current path to modify.  */
167      env = get_in_environ (current_inferior ()->environment, path_var_name);
168
169      /* Can be null if path is not set.  */
170      if (!env)
171        env = "";
172      exec_path = xstrdup (env);
173    }
174
175  for (i = argc - 1; i >= 0; --i)
176    env_mod_path (argv[i], &exec_path);
177
178  set_in_environ (current_inferior ()->environment, path_var_name, exec_path);
179  xfree (exec_path);
180  env = get_in_environ (current_inferior ()->environment, path_var_name);
181  ui_out_field_string (uiout, "path", env);
182}
183
184/* Add zero or more directories to the front of the source path.  */
185void
186mi_cmd_env_dir (char *command, char **argv, int argc)
187{
188  int i;
189  int optind = 0;
190  int reset = 0;
191  char *optarg;
192  enum opt
193    {
194      RESET_OPT
195    };
196  static struct mi_opt opts[] =
197  {
198    {"r", RESET_OPT, 0},
199    { 0, 0, 0 }
200  };
201
202  dont_repeat ();
203
204  if (mi_version (uiout) < 2)
205    {
206      for (i = argc - 1; i >= 0; --i)
207	env_execute_cli_command ("dir", argv[i]);
208      return;
209    }
210
211  /* Otherwise mi level is 2 or higher.  */
212  while (1)
213    {
214      int opt = mi_getopt ("-environment-directory", argc, argv, opts,
215                           &optind, &optarg);
216
217      if (opt < 0)
218        break;
219      switch ((enum opt) opt)
220        {
221        case RESET_OPT:
222          reset = 1;
223          break;
224        }
225    }
226  argv += optind;
227  argc -= optind;
228
229  if (reset)
230    {
231      /* Reset means setting to default path first.  */
232      xfree (source_path);
233      init_source_path ();
234    }
235
236  for (i = argc - 1; i >= 0; --i)
237    env_mod_path (argv[i], &source_path);
238
239  ui_out_field_string (uiout, "source-path", source_path);
240  forget_cached_source_info ();
241}
242
243/* Set the inferior terminal device name.  */
244void
245mi_cmd_inferior_tty_set (char *command, char **argv, int argc)
246{
247  set_inferior_io_terminal (argv[0]);
248}
249
250/* Print the inferior terminal device name  */
251void
252mi_cmd_inferior_tty_show (char *command, char **argv, int argc)
253{
254  const char *inferior_io_terminal = get_inferior_io_terminal ();
255
256  if ( !mi_valid_noargs ("-inferior-tty-show", argc, argv))
257    error (_("-inferior-tty-show: Usage: No args"));
258
259  if (inferior_io_terminal)
260    ui_out_field_string (uiout, "inferior_tty_terminal", inferior_io_terminal);
261}
262
263void
264_initialize_mi_cmd_env (void)
265{
266  struct gdb_environ *environment;
267  char *env;
268
269  /* We want original execution path to reset to, if desired later.
270     At this point, current inferior is not created, so cannot use
271     current_inferior ()->environment.  Also, there's no obvious
272     place where this code can be moved suchs that it surely run
273     before any code possibly mangles original PATH.  */
274  environment = make_environ ();
275  init_environ (environment);
276  env = get_in_environ (environment, path_var_name);
277
278  /* Can be null if path is not set.  */
279  if (!env)
280    env = "";
281  orig_path = xstrdup (env);
282  free_environ (environment);
283}
284