remake  4.3+dbg-1.5
write.h
Go to the documentation of this file.
1 /* Write commands associated with a given target. */
2 /*
3 Copyright (C) 2011, 2017, 2020 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 #include "../../dep.h"
22 
23 static debug_return_t
24 dbg_cmd_write(char *psz_args)
25 {
26  file_t *p_target = NULL;
27  const char *psz_target = NULL;
28  int b_stdout = 0;
29 
30  p_target = get_target(&psz_args, &psz_target);
31  if (p_target) {
32  variable_t *p_v = lookup_variable ("SHELL", strlen ("SHELL"));
33  char *psz_filename = NULL;
34  FILE *outfd;
35  char *s;
36 
37  if (! p_target->cmds || ! p_target->cmds->commands) {
38  printf(_("Target \"%s\" doesn't have commands associated with it.\n"),
39  psz_target);
40  return debug_readloop;
41  }
42 
43  s = p_target->cmds->commands;
44 
45  /* FIXME: should get directory from a variable, e.g. TMPDIR */
46 
47  if (psz_args && *psz_args) {
48  if (strcmp (psz_args, "here") == 0)
49  b_stdout = 1;
50  else
51  psz_filename = strdup(psz_args);
52  } else {
53  /* Create target from the basename of the target name. */
54  char *psz_target_basename = strrchr(psz_target, '/');
55  if (!psz_target_basename)
56  psz_target_basename = (char *) psz_target;
57  else
58  psz_target_basename++; /* Skip delimiter */
59  psz_filename = CALLOC(char, strlen(psz_target_basename) + 10);
60  snprintf(psz_filename, MAX_FILE_LENGTH, "/tmp/%s.sh",
61  psz_target_basename);
62  }
63 
64  /* Skip leading space, MAKE's command prefixes:
65  echo suppression @,
66  ignore-error -,
67  and recursion +
68  */
69  while (*s != '\0')
70  {
71  switch (*s) {
72  case '@':
73  case '+':
74  case '-':
75  ++s;
76  break;
77  default:
78  if (!isblank ((unsigned char)*s))
79  goto found_begin;
80  ++s;
81  }
82  }
83 
84  found_begin:
85  if ( '\0' == *s ) {
86  printf(_("Null command string parsed\n"));
87  } else {
88  dep_t *d;
89  dep_t *ood = 0;
90 
91  if (b_stdout)
92  outfd = stdout;
93  else if (!(outfd = fopen (psz_filename, "w"))) {
94  perror ("write target");
95  free(psz_filename);
96  return debug_readloop;
97  }
98 
99  if (p_v) {
100  fprintf(outfd, "#!%s\n", variable_expand(p_v->value));
101  }
102 
103  if (!p_target->floc.filenm && p_target->cmds->fileinfo.filenm) {
104  /* Fake the location based on the commands - it's better than
105  nothing...
106  */
107  fprintf(outfd, "## %s/%s:%lu\n", starting_directory,
108  p_target->cmds->fileinfo.filenm,
109  p_target->cmds->fileinfo.lineno-1);
110  } else {
111  fprintf(outfd, "## %s/%s:%lu\n", starting_directory,
112  p_target->floc.filenm, p_target->floc.lineno);
113  }
114 
115  /* FIXME: this code duplicates some code in file.c:
116  print_target_props. DRY. */
117  fprintf (outfd,
118  "## %s:%s", p_target->name,
119  p_target->double_colon ? ":" : "");
120 
121  /* Print all normal dependencies; note any order-only deps. */
122  for (d = p_target->deps; d != 0; d = d->next)
123  if (! d->ignore_mtime) {
124  fprintf (outfd, " %s", dep_name (d));
125  } else if (! ood)
126  ood = d;
127 
128  /* Print order-only deps, if we have any. */
129  if (ood)
130  {
131  fprintf (outfd, " | %s", dep_name (ood));
132  for (d = ood->next; d != 0; d = d->next)
133  if (d->ignore_mtime)
134  fprintf (outfd, " %s", dep_name (d));
135  }
136 
137  fprintf (outfd, "\n");
138 
139  {
140  char wd[300];
141  if (getcwd (wd, sizeof(wd))) {
142  fprintf(outfd, "\n#cd %s\n", wd);
143  }
144  }
145 
146  initialize_file_variables (p_target, 0);
147  set_file_variables (p_target);
148 
149  {
150 #if 0
151  commands_t cmds;
152  char **lines;
153  unsigned int i;
154  memcpy(&cmds, p_target->cmds, sizeof(cmds));
155  cmds.command_lines = NULL;
156  chop_commands (&cmds);
157  lines = xmalloc (cmds.ncommand_lines * sizeof (char *));
158  expand_command_lines(&cmds, lines, p_target);
159  for (i = 0; i < cmds.ncommand_lines; ++i)
160  {
161  fprintf (outfd, "%s\n", lines[i]);
162  free (lines[i]);
163  }
164  free (lines);
165 #else
166  char *line = allocated_variable_expand_for_file (s, p_target);
167  fprintf (outfd, "%s\n", line);
168  free(line);
169 #endif
170  }
171 
172  if (!b_stdout) {
173  struct stat buf;
174  if (0 == fstat(fileno(outfd), &buf)) {
175  mode_t mode = buf.st_mode;
176  if (buf.st_mode & S_IRUSR) mode |= S_IXUSR;
177  if (buf.st_mode & S_IRGRP) mode |= S_IXGRP;
178  if (buf.st_mode & S_IROTH) mode |= S_IXOTH;
179  if (0 != fchmod(fileno(outfd), mode)) {
180  printf(_("Can't set execute mode on \"%s\".\n"), psz_filename);
181  }
182  }
183  fclose(outfd);
184  printf(_("File \"%s\" written.\n"), psz_filename);
185  free(psz_filename);
186  }
187  }
188  }
189  return debug_readloop;
190 }
191 
192 static void
193 dbg_cmd_write_init(unsigned int c)
194 {
195  short_command[c].func = &dbg_cmd_write;
196  short_command[c].use = _("write [TARGET [FILENAME]]");
197 }
198 
199 
200 /*
201  * Local variables:
202  * eval: (c-set-style "gnu")
203  * indent-tabs-mode: nil
204  * End:
205  */
char * allocated_variable_expand_for_file(const char *psz_line, file_t *p_file)
void * xmalloc(size_t)
const char * name
Definition: filedef.h:36
char * getcwd()
char * value
Definition: variable.h:59
char * starting_directory
#define isblank(c)
Definition: make.h:91
Definition: commands.h:27
#define CALLOC(t, n)
Definition: types.h:83
gmk_floc floc
Definition: filedef.h:39
char * commands
Definition: commands.h:30
unsigned short ncommand_lines
Definition: commands.h:33
struct commands * cmds
Definition: filedef.h:46
struct file * double_colon
Definition: filedef.h:72
struct variable * lookup_variable(const char *name, size_t length)
debug_return_t
Definition: trace.h:32
struct dep * deps
Definition: filedef.h:45
char ** command_lines
Definition: commands.h:31
#define _(msgid)
Definition: make.h:293
Definition: trace.h:40
unsigned long lineno
Definition: gnuremake.h:26
file_t * get_target(char **ppsz_args, const char **ppsz_target)
void initialize_file_variables(struct file *file, int reading)
void chop_commands(struct commands *cmds)
const char * filenm
Definition: gnuremake.h:25
void set_file_variables(struct file *file)
gmk_floc fileinfo
Definition: commands.h:29
#define dep_name(d)
Definition: dep.h:104
char * variable_expand(const char *line)
Definition: variable.h:56
Definition: dep.h:60
Definition: filedef.h:34