blob: d8e011edf43f4250dfa3dd336a44d75c7501bb4c [file] [log] [blame]
sewardj45f4e7c2005-09-27 19:20:21 +00001
2/*--------------------------------------------------------------------*/
3/*--- Command line handling. m_commandline.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
10 Copyright (C) 2000-2005 Julian Seward
11 jseward@acm.org
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
30
31#include "pub_core_basics.h"
32#include "pub_core_libcassert.h"
33#include "pub_core_libcbase.h"
34#include "pub_core_libcfile.h"
35#include "pub_core_libcprint.h"
36#include "pub_core_libcproc.h"
37#include "pub_core_mallocfree.h"
38#include "pub_core_clientstate.h"
39#include "pub_core_commandline.h"
40
41
42/* Add a string to an expandable array of strings. */
43
44static void add_string ( XArrayStrings* xa, HChar* str )
45{
46 Int i;
47 HChar** strs2;
48 vg_assert(xa->used >= 0);
49 vg_assert(xa->size >= 0);
50 vg_assert(xa->used <= xa->size);
51 if (xa->strs == NULL) vg_assert(xa->size == 0);
52
53 if (xa->used == xa->size) {
54 xa->size = xa->size==0 ? 2 : 2*xa->size;
55 strs2 = VG_(malloc)( xa->size * sizeof(HChar*) );
56 for (i = 0; i < xa->used; i++)
57 strs2[i] = xa->strs[i];
58 if (xa->strs)
59 VG_(free)(xa->strs);
60 xa->strs = strs2;
61 }
62 vg_assert(xa->used < xa->size);
63 xa->strs[xa->used++] = str;
64}
65
66
67/* Read the contents of .valgrindrc in 'dir' into malloc'd memory. */
68// Note that we deliberately don't free the malloc'd memory. See
69// comment at call site.
70
71static HChar* read_dot_valgrindrc ( HChar* dir )
72{
73 Int n;
74 SysRes fd;
75 Int size;
76 HChar* f_clo = NULL;
77 HChar filename[VKI_PATH_MAX];
78
79 VG_(snprintf)(filename, VKI_PATH_MAX, "%s/.valgrindrc",
80 ( NULL == dir ? "" : dir ) );
81 fd = VG_(open)(filename, 0, VKI_S_IRUSR);
82 if ( !fd.isError ) {
83 size = VG_(fsize)(fd.val);
84 if (size > 0) {
85 f_clo = VG_(malloc)(size+1);
86 vg_assert(f_clo);
87 n = VG_(read)(fd.val, f_clo, size);
88 if (n == -1) n = 0;
89 vg_assert(n >= 0 && n <= size+1);
90 f_clo[n] = '\0';
91 }
92 VG_(close)(fd.val);
93 }
94 return f_clo;
95}
96
97
98// Add args from a string into VG_(args_for_valgrind), splitting the
99// string at whitespace and adding each component as a separate arg.
100
101static void add_args_from_string ( HChar* s )
102{
103 HChar* tmp;
104 HChar* cp = s;
105 vg_assert(cp);
106 while (True) {
107 // We have alternating sequences: blanks, non-blanks, blanks...
108 // copy the non-blanks sequences, and add terminating '\0'
109 while (VG_(isspace)(*cp)) cp++;
110 if (*cp == 0) break;
111 tmp = cp;
112 while ( !VG_(isspace)(*cp) && *cp != 0 ) cp++;
113 if ( *cp != 0 ) *cp++ = '\0'; // terminate if not the last
114 add_string( &VG_(args_for_valgrind), tmp );
115 }
116}
117
118
119/* Split up the args presented by the launcher to m_main.main(), and
120 park them in VG_(args_for_client) and VG_(args_for_valgrind).
121
122 The resulting arg list is the concatenation of the following:
123 - contents of ~/.valgrindrc
124 - contents of $VALGRIND_OPTS
125 - contents of ./.valgrindrc
126 - args from the command line
127 in the stated order.
128
129 VG_(args_for_valgrind_noexecpass) is set to be the number of items
130 in the first three categories. They are not passed to child invokations
131 at exec, whereas the last group is.
132
133 If the last group contains --command-line-only=yes, then the
134 first three groups are left empty.
135
136 Scheme: first examine the last group (the supplied argc/argv).
137 It should look like this.
138
139 args-for-v exe_name args-for-c
140
141 args-for-v are taken until either they don't start with '-' or
142 a "--" is seen.
143
144 The exe name and args-for-c are recorded without further ado.
145 Note that args-for-c[0] is the first real arg for the client, not
146 its executable name.
147
148 args-for-v are then copied into tmp_xarray.
149
150 if args-for-v does not include --command-line-only=yes:
151 contents of ~/.valgrindrc, $VALGRIND_OPTS and ./.valgrindrc
152 are copied into VG_(args_for_valgrind).
153 else
154 VG_(args_for_valgrind) is made empty.
155
156 Finally, tmp_xarray is copied onto the end of VG_(args_for_valgrind).
157*/
158
159void VG_(split_up_argv)( Int argc, HChar** argv )
160{
161 Int i;
162 Bool augment = True;
163 static Bool already_called = False;
164
165 XArrayStrings tmp_xarray = {0,0,NULL};
166
167 /* This function should be called once, at startup, and then never
168 again. */
169 vg_assert(!already_called);
170 already_called = True;
171
172 /* Collect up the args-for-V. */
173 i = 1; /* skip the exe (stage2) name. */
174 for (; i < argc; i++) {
175 vg_assert(argv[i]);
176 if (0 == VG_(strcmp)(argv[i], "--")) {
177 i++;
178 break;
179 }
180 if (0 == VG_(strcmp)(argv[i], "--command-line-only=yes"))
181 augment = False;
182 if (argv[i][0] != '-')
183 break;
184 add_string( &tmp_xarray, argv[i] );
185 }
186
187 /* Should now be looking at the exe name. */
188 if (i < argc) {
189 vg_assert(argv[i]);
190 VG_(args_the_exename) = argv[i];
191 i++;
192 }
193
194 /* The rest are args for the client. */
195 for (; i < argc; i++) {
196 vg_assert(argv[i]);
197 add_string( &VG_(args_for_client), argv[i] );
198 }
199
200 VG_(args_for_valgrind).size = 0;
201 VG_(args_for_valgrind).used = 0;
202 VG_(args_for_valgrind).strs = NULL;
203
204 /* Get extra args from ~/.valgrindrc, $VALGRIND_OPTS and
205 ./.valgrindrc into VG_(args_for_valgrind). */
206 if (augment) {
207 // read_dot_valgrindrc() allocates the return value with
208 // VG_(malloc)(). We do not free f1_clo and f2_clo as they get
209 // put into VG_(args_for_valgrind) and so must persist.
210 HChar* f1_clo = read_dot_valgrindrc( VG_(getenv)("HOME") );
211 HChar* env_clo = VG_(strdup)( VG_(getenv)(VALGRIND_OPTS) );
212 HChar* f2_clo = read_dot_valgrindrc(".");
213
214 if (f1_clo) add_args_from_string( f1_clo );
215 if (env_clo) add_args_from_string( env_clo );
216 if (f2_clo) add_args_from_string( f2_clo );
217 }
218
219 /* .. and record how many extras we got. */
220 VG_(args_for_valgrind_noexecpass) = VG_(args_for_valgrind).used;
221
222 /* Finally, copy tmp_xarray onto the end. */
223 for (i = 0; i < tmp_xarray.used; i++)
224 add_string( &VG_(args_for_valgrind), tmp_xarray.strs[i] );
225
226 if (tmp_xarray.strs)
227 VG_(free)(tmp_xarray.strs);
228}
229
230/*--------------------------------------------------------------------*/
231/*--- end ---*/
232/*--------------------------------------------------------------------*/