1 /*
2 Copyright (C) 2004, 2005, 2007, 2008, 2010, 2011
3 R. Bernstein <rocky@gnu.org>
4 This file is part of GNU Make (remake variant).
5 
6 GNU Make is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Make is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Make; see the file COPYING.  If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20 
21 /* Helper routines for debugger command interface. */
22 
23 #include "../rule.h"
24 #include "../trace.h"
25 #include "../commands.h"
26 #include "../expand.h"
27 #include "fns.h"
28 #include "stack.h"
29 #include "debug.h"
30 #include "print.h"
31 #include "msg.h"
32 
33 #ifdef HAVE_STRING_H
34 #include <string.h>
35 #endif
36 
37 #ifdef HAVE_SYS_WAIT_H
38 #include <sys/wait.h>
39 #endif
40 
41 #ifdef HAVE_LIBREADLINE
42 
43 # ifdef bcmp
44 #   undef bcmp
45 # endif
46 
47 
48 # ifdef bzero
49 #   undef bzero
50 # endif
51 
52 
53 # ifdef bcopy
54 #   undef bcopy
55 # endif
56 
57 
58 #include <readline/readline.h>
59 #endif
60 
61 gmk_floc *p_target_loc = NULL;
62 char   *psz_target_name = NULL;
63 
64 /*! We use the if when we fake a line number because
65    a real one hasn't been recorded on the stack. */
66 gmk_floc  fake_floc;
67 
68 /* From readline. ?? Should this be in configure?  */
69 #ifndef whitespace
70 #define whitespace(c) (((c) == ' ') || ((c) == '\t'))
71 #endif
72 
73 brkpt_mask_t
get_brkpt_option(const char * psz_break_type)74 get_brkpt_option(const char *psz_break_type)
75 {
76   if (is_abbrev_of (psz_break_type, "all", 1)) {
77     return BRK_ALL;
78   } else if (is_abbrev_of (psz_break_type, "prerequisite", 3)) {
79     return BRK_BEFORE_PREREQ;
80   } else if (is_abbrev_of (psz_break_type, "run", 1)) {
81     return BRK_AFTER_PREREQ;
82   } else if (is_abbrev_of (psz_break_type, "end", 1)) {
83     return BRK_AFTER_CMD;
84   } else if (is_abbrev_of (psz_break_type, "temp", 1)) {
85     return BRK_TEMP;
86   } else {
87     dbg_errmsg("Unknown breakpoint modifier %s", psz_break_type);
88     return BRK_NONE;
89   }
90 }
91 
92 /*! Parse psz_arg for a signed integer. The value is returned in
93     *pi_result. If warn is true, then we'll give a warning if no
94     integer found. The return value is true if parsing succeeded in
95     any event..
96  */
97 bool
get_int(const char * psz_arg,int * pi_result,bool b_warn)98 get_int(const char *psz_arg, int *pi_result, bool b_warn)
99 {
100   int i;
101   char *endptr;
102 
103   if (!psz_arg || 0==strlen(psz_arg)) return 0;
104 
105   i = strtol(psz_arg, &endptr, 10);
106   if (*endptr != '\0') {
107     if (b_warn)
108       dbg_errmsg("expecting %s to be an integer", psz_arg);
109     return false;
110   }
111   *pi_result = i;
112   return true;
113 }
114 
115 bool
get_uint(const char * psz_arg,unsigned int * result,bool b_warn)116 get_uint(const char *psz_arg, unsigned int *result, bool b_warn)
117 {
118   unsigned int i;
119   char *endptr;
120 
121   if (!psz_arg || 0==strlen(psz_arg)) return 0;
122 
123   i = strtol(psz_arg, &endptr, 10);
124   if (*endptr != '\0') {
125     if (b_warn)
126       dbg_errmsg("expecting %s to be an integer", psz_arg);
127     return false;
128   }
129   *result = i;
130   return true;
131 }
132 
133 /* Find the next "word" - skip leading blanks and the "word" is the
134    largest non-blank characters after that. ppsz_str is modified to
135    point after the portion returned and also the region initially
136    pointed to by ppsz_str is modified so that word is zero-byte
137    termintated.
138  */
139 char *
get_word(char ** ppsz_str)140 get_word(char **ppsz_str)
141 {
142   char *psz_word;
143 
144   /* Skip leading blanks. */
145   while (**ppsz_str && whitespace (**ppsz_str))
146     **ppsz_str += 1;
147 
148   /* Word starts here at first non blank character. */
149   psz_word = *ppsz_str;
150 
151   /* Find end of word - next whitespace. */
152   while (**ppsz_str && !whitespace (**ppsz_str))
153     (*ppsz_str)++;
154 
155   if (**ppsz_str) *((*ppsz_str)++) = '\0';
156 
157   return psz_word;
158 }
159 
160 /*!
161   Return the current target from the stack or NULL
162   if none set.
163  */
164 const file_t *
get_current_target(void)165 get_current_target(void)
166 {
167   if (p_stack && p_stack->p_target)
168     return p_stack->p_target;
169   else
170     return NULL;
171 }
172 
173 
174 /*!
175   Return the current target from the stack or NULL
176   if none set.
177  */
178 const gmk_floc *
get_current_floc(void)179 get_current_floc(void)
180 {
181   file_t *p_target = (file_t *) get_current_target();
182   gmk_floc *p_floc;
183 
184   p_floc = &p_target->floc;
185 
186   if (p_floc->filenm && p_floc->lineno != 0)
187     return p_floc;
188   else
189     return NULL;
190 }
191 
192 
193 /*! Find the target in first word of psz_args or use $@ (the current
194     stack) if none.  We also allow $@ or @ explicitly as a target name
195     to mean the current target on the stack. NULL is returned if a lookup
196     of the target name was not found. ppsz_target is to the name
197     looked up.
198  */
199 file_t *
get_target(char ** ppsz_args,const char ** ppsz_target)200 get_target(char **ppsz_args, /*out*/ const char **ppsz_target)
201 {
202   if (!*ppsz_args || !**ppsz_args) {
203     file_t *p_target = (file_t *) get_current_target();
204     /* Use current target */
205     if (p_target && p_target->name) {
206       *ppsz_args = (char *) p_target->name;
207     } else {
208       printf(_("Default target not found here. You must supply one\n"));
209       return NULL;
210     }
211   }
212 
213   *ppsz_target = get_word(ppsz_args);
214 
215   /* As a special case, we'll allow $@ or @ for the current target. */
216   if ( 0 == strcmp("$@", *ppsz_target) || 0 == strcmp("@", *ppsz_target) ) {
217     if (p_stack && p_stack->p_target && p_stack->p_target->name)
218       *ppsz_target = p_stack->p_target->name;
219     else {
220       printf(_("No current target found for $@ - supply a target name.\n"));
221       return NULL;
222     }
223   }
224 
225   {
226     file_t *p_target = lookup_file (*ppsz_target);
227 
228     if (!p_target)
229       printf(_("Target \"%s\" doesn't appear to be a target name.\n"),
230 	     *ppsz_target);
231     return p_target;
232   }
233 }
234 
235 /*! Return true if psz_substr is an initial prefix (abbreviation) of
236     psz_word. The empty string is not a valid abbreviation. */
237 bool
is_abbrev_of(const char * psz_substr,const char * psz_word,unsigned int i_min)238 is_abbrev_of(const char* psz_substr, const char* psz_word,
239 	     unsigned int i_min)
240 {
241   if (strlen(psz_substr) < i_min)
242     return false;
243   else {
244     const char *psz = strstr(psz_word, psz_substr);
245     return (psz && psz == psz_word);
246   }
247 }
248 
249 /*! toggle var on or on or off depending on psz_onoff */
250 void
on_off_toggle(const char * psz_onoff,int * var)251 on_off_toggle(const char *psz_onoff, int *var)
252 {
253   if (strcmp (psz_onoff, "on") == 0)
254     *var = 1;
255   else if (strcmp (psz_onoff, "off") == 0)
256     *var = 0;
257   else if (strcmp (psz_onoff, "toggle") == 0)
258     *var = !*var;
259   else
260     printf(_("expecting \"on\", \"off\", or \"toggle\"; got \"%s\" \n"),
261 	   psz_onoff);
262 }
263 
264 /*! Print an interpretation of the debug level mask. */
265 void
print_db_level(debug_level_mask_t e_debug_level)266 print_db_level(debug_level_mask_t e_debug_level)
267 {
268   if (e_debug_level & DB_BASIC)
269     printf("Basic tracing (0x%x)\n", (unsigned int) DB_BASIC);
270   if (e_debug_level & DB_TRACE)
271     printf("Tracing (0x%x)\n", (unsigned int) DB_TRACE);
272   if (e_debug_level & DB_VERBOSE)
273     printf("Verbose Tracing (0x%x)\n", (unsigned int) DB_VERBOSE);
274   if (e_debug_level & DB_SHELL)
275     printf("Tracing shell commands 0x%x\n", (unsigned int) DB_SHELL);
276   if (e_debug_level & DB_MAKEFILES)
277     printf("Tracing Rebuilding Makefiles 0x%x\n", (unsigned int) DB_MAKEFILES);
278   if (e_debug_level & DB_UPDATE_GOAL)
279     printf("Tracing Goal target updates 0x%x\n", (unsigned int) DB_MAKEFILES);
280   if (e_debug_level & DB_UPDATE_GOAL)
281     printf("Tracing reading Makefiles 0x%x\n", (unsigned int) DB_READ_MAKEFILES);
282   if (e_debug_level & DB_CALL)
283     printf("Tracing function call and returns 0x%x\n", (unsigned int) DB_CALL);
284 }
285 
286 static const char *reason2str[] = {
287     "->",
288     "..",
289     "<-",
290     "||",
291     "rd",
292     "!!",
293     "--",
294     "++",
295     ":o"
296 };
297 
298 
299 
300 /** Print where we are in the Makefile. */
301 void
print_debugger_location(const file_t * p_target,debug_enter_reason_t reason,const floc_stack_node_t * p_stack_floc)302 print_debugger_location(const file_t *p_target, debug_enter_reason_t reason,
303 			const floc_stack_node_t *p_stack_floc)
304 {
305   if (p_target_loc) {
306     if (reason != DEBUG_NOT_GIVEN && reason != DEBUG_STACK_CHANGING)
307       printf("%s ", reason2str[reason]);
308     printf("(");
309     if ( !p_target_loc->filenm && p_target_loc->lineno != 0
310 	 && p_target && p_target->name ) {
311       /* We don't have file location info in the target floc, but we
312 	 do have it as part of the name, so use that. This happens for
313 	 example with we've stopped before reading a Makefile.
314       */
315       if (p_target->cmds) {
316 	gmk_floc floc;
317 	memcpy(&floc, &(p_target->cmds->fileinfo.filenm), sizeof(gmk_floc));
318 	/* HACK: is it okay to assume that the target is on the line
319 	   before the first command? Or should we list the line
320 	   that the command starts on - so we know we've faked the location?
321 	*/
322 	floc.lineno--;
323 	p_target_loc->filenm = floc.filenm;
324 	p_target_loc->lineno = floc.lineno;
325 	print_floc_prefix(&floc);
326 	printf (")\n");
327       } else if (p_target->phony)
328 	printf("%s: .PHONY target)\n", p_target->name);
329       else
330 	printf("%s:0)\n", p_target->name);
331     } else {
332       print_floc_prefix(p_target_loc);
333       printf (")\n");
334     }
335   } else if (p_stack_floc && p_stack_floc->p_floc) {
336       printf("\n(");
337       print_floc_prefix(p_stack_floc->p_floc);
338       printf (")\n");
339   } else if (p_stack_floc_top && p_stack_floc_top->p_floc) {
340       printf("\n(");
341       print_floc_prefix(p_stack_floc_top->p_floc);
342       printf (")\n");
343   }
344 
345   /* Could/should generalize the below into a prompt string. */
346   switch (reason)
347     {
348     case DEBUG_BRKPT_BEFORE_PREREQ:
349     case DEBUG_STEP_HIT:
350       dbg_cmd_show_exp((char *) "$@: $+", true);
351       break;
352     case DEBUG_STACK_CHANGING:
353       break;
354     default:
355       dbg_cmd_show_exp((char *) "$@", true);
356       break;
357     }
358 }
359 
360 /** Strip whitespace from the start and end of STRING.  Return a pointer
361    into STRING. */
362 char *
stripwhite(char * string)363 stripwhite (char *string)
364 {
365   char *s, *t;
366 
367   for (s = string; whitespace (*s); s++)
368     ;
369 
370   if (*s == 0)
371     return (s);
372 
373   t = s + strlen (s) - 1;
374   while (t > s && whitespace (*t))
375     t--;
376   *++t = '\0';
377 
378   return s;
379 }
380 
381 /* Show if i_bool is "on" or "off" */
382 const char *
var_to_on_off(int i_bool)383 var_to_on_off(int i_bool)
384 {
385   return i_bool ? "on" : "off";
386 }
387 
388 /*! See if psz_varname is $varname or $(varname) */
389 variable_t *
try_without_dollar(const char * psz_varname)390 try_without_dollar(const char *psz_varname)
391 {
392   printf("Can't find variable `%s'.\n", psz_varname);
393   if (psz_varname && psz_varname[0] == '$') {
394     const char *psz_nodollar = &(psz_varname[1]);
395     char *psz_try = calloc(1, strlen(psz_varname));
396     if (psz_nodollar && 1 == sscanf(psz_nodollar, "(%s)", psz_try)) {
397       /* Remove trailing ')' */
398       if ( ')' == psz_try[strlen(psz_try)-1] )
399 	psz_try[strlen(psz_try)-1]='\0';
400       printf(_("Did you mean `%s'?\n"), psz_try);
401     } else
402       printf(_("Did you mean `%s'?\n"), psz_nodollar);
403     free(psz_try);
404   } else {
405     printf("Adding variable `%s'.\n", psz_varname);
406     return define_variable (psz_varname, strlen(psz_varname), "", o_debugger, 0);
407   }
408   return NULL;
409 
410 }
411 
412 /*! Show a expression. Set "expand" to 1 if you want variable
413    definitions inside the displayed value expanded.
414 */
415 bool
dbg_cmd_show_exp(char * psz_varname,bool expand)416 dbg_cmd_show_exp (char *psz_varname, bool expand)
417 {
418   if (!psz_varname || 0==strlen(psz_varname)) {
419     printf(_("You need to supply a variable name.\n"));
420     return false;
421   } else {
422     variable_t *p_v;
423     variable_set_t *p_set = NULL;
424     variable_set_list_t *p_file_vars = NULL;
425     if (p_stack && p_stack->p_target && p_stack->p_target->name) {
426       const char *psz_target = p_stack->p_target->name;
427       file_t *p_target = lookup_file (psz_target);
428       if (p_target) {
429 	initialize_file_variables (p_target, 0);
430 	set_file_variables (p_target);
431 	p_file_vars = p_target->variables;
432 	p_set = p_file_vars->set;
433       }
434     }
435     if (p_set) {
436       p_v = lookup_variable_in_set(psz_varname, strlen(psz_varname), p_set);
437       if (!p_v)
438 	/* May be a global variable. */
439 	p_v = lookup_variable (psz_varname, strlen (psz_varname));
440     } else {
441       p_v = lookup_variable (psz_varname, strlen (psz_varname));
442     }
443     if (p_v) {
444       if (expand) {
445 	print_variable_expand(p_v);
446       } else
447 	print_variable(p_v);
448     } else {
449       if (expand)
450 	printf("%s\n", variable_expand_set(psz_varname, p_file_vars));
451       else {
452 	try_without_dollar(psz_varname);
453 	return false;
454       }
455     }
456   }
457   return true;
458 }
459 
dbg_print_invocation(void)460 void dbg_print_invocation(void)
461 {
462   unsigned int i;
463   printf("%s ", global_argv[0]);
464   for (i = 1; global_argv[i]; i++) {
465     printf(" %s", global_argv[i]);
466   }
467   printf("\n");
468 }
469 
find_rule(const char * psz_name)470 rule_t *find_rule (const char *psz_name)
471 {
472   rule_t *r;
473 
474   for (r = pattern_rules; r != 0; r = r->next)
475     {
476       unsigned int i;
477       for (i = 0; r->targets[i] != 0; ++i)
478 	if (0 == strcmp(r->targets[i], psz_name)) return r;
479     }
480   return NULL;
481 }
482 
chomp(char * line)483 void chomp(char * line)
484 {
485   unsigned int len = strlen(line);
486   if (line[len-1] == '\n') line[len-1] = '\0';
487 }
488 
489 
shell_rc_status(int rc)490 void shell_rc_status(int rc)
491 {
492   if (rc == -1)
493     printf(_("Error: %s\n"), strerror(errno));
494   else if (WEXITSTATUS(rc) != 0)
495     printf(_("Warning: return code was %d\n"), WEXITSTATUS(rc));
496 }
497 
498 /*
499  * Local variables:
500  * eval: (c-set-style "gnu")
501  * indent-tabs-mode: nil
502  * End:
503  */
504