1169695Skan/* Dependency generator for Makefile fragments.
2169695Skan   Copyright (C) 2000, 2001, 2003, 2007 Free Software Foundation, Inc.
3169695Skan   Contributed by Zack Weinberg, Mar 2000
4169695Skan
5169695SkanThis program is free software; you can redistribute it and/or modify it
6169695Skanunder the terms of the GNU General Public License as published by the
7169695SkanFree Software Foundation; either version 2, or (at your option) any
8169695Skanlater version.
9169695Skan
10169695SkanThis program is distributed in the hope that it will be useful,
11169695Skanbut WITHOUT ANY WARRANTY; without even the implied warranty of
12169695SkanMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13169695SkanGNU General Public License for more details.
14169695Skan
15169695SkanYou should have received a copy of the GNU General Public License
16169695Skanalong with this program; if not, write to the Free Software
17169695SkanFoundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18169695Skan
19169695Skan In other words, you are welcome to use, share and improve this program.
20169695Skan You are forbidden to forbid anyone else to use, share and improve
21169695Skan what you give them.   Help stamp out software-hoarding!  */
22169695Skan
23169695Skan#include "config.h"
24169695Skan#include "system.h"
25169695Skan#include "mkdeps.h"
26169695Skan
27169695Skan/* Keep this structure local to this file, so clients don't find it
28169695Skan   easy to start making assumptions.  */
29169695Skanstruct deps
30169695Skan{
31169695Skan  const char **targetv;
32169695Skan  unsigned int ntargets;	/* number of slots actually occupied */
33169695Skan  unsigned int targets_size;	/* amt of allocated space - in words */
34169695Skan
35169695Skan  const char **depv;
36169695Skan  unsigned int ndeps;
37169695Skan  unsigned int deps_size;
38169695Skan
39169695Skan  const char **vpathv;
40169695Skan  size_t *vpathlv;
41169695Skan  unsigned int nvpaths;
42169695Skan  unsigned int vpaths_size;
43169695Skan};
44169695Skan
45169695Skanstatic const char *munge (const char *);
46169695Skan
47169695Skan/* Given a filename, quote characters in that filename which are
48169695Skan   significant to Make.  Note that it's not possible to quote all such
49169695Skan   characters - e.g. \n, %, *, ?, [, \ (in some contexts), and ~ are
50169695Skan   not properly handled.  It isn't possible to get this right in any
51169695Skan   current version of Make.  (??? Still true?  Old comment referred to
52169695Skan   3.76.1.)  */
53169695Skan
54169695Skanstatic const char *
55169695Skanmunge (const char *filename)
56169695Skan{
57169695Skan  int len;
58169695Skan  const char *p, *q;
59169695Skan  char *dst, *buffer;
60169695Skan
61169695Skan  for (p = filename, len = 0; *p; p++, len++)
62169695Skan    {
63169695Skan      switch (*p)
64169695Skan	{
65169695Skan	case ' ':
66169695Skan	case '\t':
67169695Skan	  /* GNU make uses a weird quoting scheme for white space.
68169695Skan	     A space or tab preceded by 2N+1 backslashes represents
69169695Skan	     N backslashes followed by space; a space or tab
70169695Skan	     preceded by 2N backslashes represents N backslashes at
71169695Skan	     the end of a file name; and backslashes in other
72169695Skan	     contexts should not be doubled.  */
73169695Skan	  for (q = p - 1; filename <= q && *q == '\\';  q--)
74169695Skan	    len++;
75169695Skan	  len++;
76169695Skan	  break;
77169695Skan
78169695Skan	case '$':
79169695Skan	  /* '$' is quoted by doubling it.  */
80169695Skan	  len++;
81169695Skan	  break;
82169695Skan	}
83169695Skan    }
84169695Skan
85169695Skan  /* Now we know how big to make the buffer.  */
86169695Skan  buffer = XNEWVEC (char, len + 1);
87169695Skan
88169695Skan  for (p = filename, dst = buffer; *p; p++, dst++)
89169695Skan    {
90169695Skan      switch (*p)
91169695Skan	{
92169695Skan	case ' ':
93169695Skan	case '\t':
94169695Skan	  for (q = p - 1; filename <= q && *q == '\\';  q--)
95169695Skan	    *dst++ = '\\';
96169695Skan	  *dst++ = '\\';
97169695Skan	  break;
98169695Skan
99169695Skan	case '$':
100169695Skan	  *dst++ = '$';
101169695Skan	  break;
102169695Skan
103169695Skan	default:
104169695Skan	  /* nothing */;
105169695Skan	}
106169695Skan      *dst = *p;
107169695Skan    }
108169695Skan
109169695Skan  *dst = '\0';
110169695Skan  return buffer;
111169695Skan}
112169695Skan
113169695Skan/* If T begins with any of the partial pathnames listed in d->vpathv,
114169695Skan   then advance T to point beyond that pathname.  */
115169695Skanstatic const char *
116169695Skanapply_vpath (struct deps *d, const char *t)
117169695Skan{
118169695Skan  if (d->vpathv)
119169695Skan    {
120169695Skan      unsigned int i;
121169695Skan      for (i = 0; i < d->nvpaths; i++)
122169695Skan	{
123169695Skan	  if (!strncmp (d->vpathv[i], t, d->vpathlv[i]))
124169695Skan	    {
125169695Skan	      const char *p = t + d->vpathlv[i];
126169695Skan	      if (!IS_DIR_SEPARATOR (*p))
127169695Skan		goto not_this_one;
128169695Skan
129169695Skan	      /* Do not simplify $(vpath)/../whatever.  ??? Might not
130169695Skan		 be necessary. */
131169695Skan	      if (p[1] == '.' && p[2] == '.' && IS_DIR_SEPARATOR (p[3]))
132169695Skan		goto not_this_one;
133169695Skan
134169695Skan	      /* found a match */
135169695Skan	      t = t + d->vpathlv[i] + 1;
136169695Skan	      break;
137169695Skan	    }
138169695Skan	not_this_one:;
139169695Skan	}
140169695Skan    }
141169695Skan
142169695Skan  /* Remove leading ./ in any case.  */
143169695Skan  while (t[0] == '.' && IS_DIR_SEPARATOR (t[1]))
144169695Skan    {
145169695Skan      t += 2;
146169695Skan      /* If we removed a leading ./, then also remove any /s after the
147169695Skan	 first.  */
148169695Skan      while (IS_DIR_SEPARATOR (t[0]))
149169695Skan	++t;
150169695Skan    }
151169695Skan
152169695Skan  return t;
153169695Skan}
154169695Skan
155169695Skan/* Public routines.  */
156169695Skan
157169695Skanstruct deps *
158169695Skandeps_init (void)
159169695Skan{
160169695Skan  return XCNEW (struct deps);
161169695Skan}
162169695Skan
163169695Skanvoid
164169695Skandeps_free (struct deps *d)
165169695Skan{
166169695Skan  unsigned int i;
167169695Skan
168169695Skan  if (d->targetv)
169169695Skan    {
170169695Skan      for (i = 0; i < d->ntargets; i++)
171169695Skan	free ((void *) d->targetv[i]);
172169695Skan      free (d->targetv);
173169695Skan    }
174169695Skan
175169695Skan  if (d->depv)
176169695Skan    {
177169695Skan      for (i = 0; i < d->ndeps; i++)
178169695Skan	free ((void *) d->depv[i]);
179169695Skan      free (d->depv);
180169695Skan    }
181169695Skan
182169695Skan  if (d->vpathv)
183169695Skan    {
184169695Skan      for (i = 0; i < d->nvpaths; i++)
185169695Skan	free ((void *) d->vpathv[i]);
186169695Skan      free (d->vpathv);
187169695Skan      free (d->vpathlv);
188169695Skan    }
189169695Skan
190169695Skan  free (d);
191169695Skan}
192169695Skan
193169695Skan/* Adds a target T.  We make a copy, so it need not be a permanent
194169695Skan   string.  QUOTE is true if the string should be quoted.  */
195169695Skanvoid
196169695Skandeps_add_target (struct deps *d, const char *t, int quote)
197169695Skan{
198169695Skan  if (d->ntargets == d->targets_size)
199169695Skan    {
200169695Skan      d->targets_size = d->targets_size * 2 + 4;
201169695Skan      d->targetv = XRESIZEVEC (const char *, d->targetv, d->targets_size);
202169695Skan    }
203169695Skan
204169695Skan  t = apply_vpath (d, t);
205169695Skan  if (quote)
206169695Skan    t = munge (t);  /* Also makes permanent copy.  */
207169695Skan  else
208169695Skan    t = xstrdup (t);
209169695Skan
210169695Skan  d->targetv[d->ntargets++] = t;
211169695Skan}
212169695Skan
213169695Skan/* Sets the default target if none has been given already.  An empty
214169695Skan   string as the default target in interpreted as stdin.  The string
215169695Skan   is quoted for MAKE.  */
216169695Skanvoid
217169695Skandeps_add_default_target (struct deps *d, const char *tgt)
218169695Skan{
219169695Skan  /* Only if we have no targets.  */
220169695Skan  if (d->ntargets)
221169695Skan    return;
222169695Skan
223169695Skan  if (tgt[0] == '\0')
224169695Skan    deps_add_target (d, "-", 1);
225169695Skan  else
226169695Skan    {
227169695Skan#ifndef TARGET_OBJECT_SUFFIX
228169695Skan# define TARGET_OBJECT_SUFFIX ".o"
229169695Skan#endif
230169695Skan      const char *start = lbasename (tgt);
231169695Skan      char *o = (char *) alloca (strlen (start)
232169695Skan                                 + strlen (TARGET_OBJECT_SUFFIX) + 1);
233169695Skan      char *suffix;
234169695Skan
235169695Skan      strcpy (o, start);
236169695Skan
237169695Skan      suffix = strrchr (o, '.');
238169695Skan      if (!suffix)
239169695Skan        suffix = o + strlen (o);
240169695Skan      strcpy (suffix, TARGET_OBJECT_SUFFIX);
241169695Skan
242169695Skan      deps_add_target (d, o, 1);
243169695Skan    }
244169695Skan}
245169695Skan
246169695Skanvoid
247169695Skandeps_add_dep (struct deps *d, const char *t)
248169695Skan{
249169695Skan  t = munge (apply_vpath (d, t));  /* Also makes permanent copy.  */
250169695Skan
251169695Skan  if (d->ndeps == d->deps_size)
252169695Skan    {
253169695Skan      d->deps_size = d->deps_size * 2 + 8;
254169695Skan      d->depv = XRESIZEVEC (const char *, d->depv, d->deps_size);
255169695Skan    }
256169695Skan  d->depv[d->ndeps++] = t;
257169695Skan}
258169695Skan
259169695Skanvoid
260169695Skandeps_add_vpath (struct deps *d, const char *vpath)
261169695Skan{
262169695Skan  const char *elem, *p;
263169695Skan  char *copy;
264169695Skan  size_t len;
265169695Skan
266169695Skan  for (elem = vpath; *elem; elem = p)
267169695Skan    {
268169695Skan      for (p = elem; *p && *p != ':'; p++);
269169695Skan      len = p - elem;
270169695Skan      copy = XNEWVEC (char, len + 1);
271169695Skan      memcpy (copy, elem, len);
272169695Skan      copy[len] = '\0';
273169695Skan      if (*p == ':')
274169695Skan	p++;
275169695Skan
276169695Skan      if (d->nvpaths == d->vpaths_size)
277169695Skan	{
278169695Skan	  d->vpaths_size = d->vpaths_size * 2 + 8;
279169695Skan	  d->vpathv = XRESIZEVEC (const char *, d->vpathv, d->vpaths_size);
280169695Skan	  d->vpathlv = XRESIZEVEC (size_t, d->vpathlv, d->vpaths_size);
281169695Skan	}
282169695Skan      d->vpathv[d->nvpaths] = copy;
283169695Skan      d->vpathlv[d->nvpaths] = len;
284169695Skan      d->nvpaths++;
285169695Skan    }
286169695Skan}
287169695Skan
288169695Skanvoid
289169695Skandeps_write (const struct deps *d, FILE *fp, unsigned int colmax)
290169695Skan{
291169695Skan  unsigned int size, i, column;
292169695Skan
293169695Skan  column = 0;
294169695Skan  if (colmax && colmax < 34)
295169695Skan    colmax = 34;
296169695Skan
297169695Skan  for (i = 0; i < d->ntargets; i++)
298169695Skan    {
299169695Skan      size = strlen (d->targetv[i]);
300169695Skan      column += size;
301169695Skan      if (colmax && column > colmax)
302169695Skan	{
303169695Skan	  fputs (" \\\n ", fp);
304169695Skan	  column = 1 + size;
305169695Skan	}
306169695Skan      if (i)
307169695Skan	{
308169695Skan	  putc (' ', fp);
309169695Skan	  column++;
310169695Skan	}
311169695Skan      fputs (d->targetv[i], fp);
312169695Skan    }
313169695Skan
314169695Skan  putc (':', fp);
315169695Skan  putc (' ', fp);
316169695Skan  column += 2;
317169695Skan
318169695Skan  for (i = 0; i < d->ndeps; i++)
319169695Skan    {
320169695Skan      size = strlen (d->depv[i]);
321169695Skan      column += size;
322169695Skan      if (colmax && column > colmax)
323169695Skan	{
324169695Skan	  fputs (" \\\n ", fp);
325169695Skan	  column = 1 + size;
326169695Skan	}
327169695Skan      if (i)
328169695Skan	{
329169695Skan	  putc (' ', fp);
330169695Skan	  column++;
331169695Skan	}
332169695Skan      fputs (d->depv[i], fp);
333169695Skan    }
334169695Skan  putc ('\n', fp);
335169695Skan}
336169695Skan
337169695Skanvoid
338169695Skandeps_phony_targets (const struct deps *d, FILE *fp)
339169695Skan{
340169695Skan  unsigned int i;
341169695Skan
342169695Skan  for (i = 1; i < d->ndeps; i++)
343169695Skan    {
344169695Skan      putc ('\n', fp);
345169695Skan      fputs (d->depv[i], fp);
346169695Skan      putc (':', fp);
347169695Skan      putc ('\n', fp);
348169695Skan    }
349169695Skan}
350169695Skan
351169695Skan/* Write out a deps buffer to a file, in a form that can be read back
352169695Skan   with deps_restore.  Returns nonzero on error, in which case the
353169695Skan   error number will be in errno.  */
354169695Skan
355169695Skanint
356169695Skandeps_save (struct deps *deps, FILE *f)
357169695Skan{
358169695Skan  unsigned int i;
359169695Skan
360169695Skan  /* The cppreader structure contains makefile dependences.  Write out this
361169695Skan     structure.  */
362169695Skan
363169695Skan  /* The number of dependences.  */
364169695Skan  if (fwrite (&deps->ndeps, sizeof (deps->ndeps), 1, f) != 1)
365169695Skan      return -1;
366169695Skan  /* The length of each dependence followed by the string.  */
367169695Skan  for (i = 0; i < deps->ndeps; i++)
368169695Skan    {
369169695Skan      size_t num_to_write = strlen (deps->depv[i]);
370169695Skan      if (fwrite (&num_to_write, sizeof (size_t), 1, f) != 1)
371169695Skan          return -1;
372169695Skan      if (fwrite (deps->depv[i], num_to_write, 1, f) != 1)
373169695Skan          return -1;
374169695Skan    }
375169695Skan
376169695Skan  return 0;
377169695Skan}
378169695Skan
379169695Skan/* Read back dependency information written with deps_save into
380169695Skan   the deps buffer.  The third argument may be NULL, in which case
381169695Skan   the dependency information is just skipped, or it may be a filename,
382169695Skan   in which case that filename is skipped.  */
383169695Skan
384169695Skanint
385169695Skandeps_restore (struct deps *deps, FILE *fd, const char *self)
386169695Skan{
387169695Skan  unsigned int i, count;
388169695Skan  size_t num_to_read;
389169695Skan  size_t buf_size = 512;
390169695Skan  char *buf = XNEWVEC (char, buf_size);
391169695Skan
392169695Skan  /* Number of dependences.  */
393169695Skan  if (fread (&count, 1, sizeof (count), fd) != sizeof (count))
394169695Skan    return -1;
395169695Skan
396169695Skan  /* The length of each dependence string, followed by the string.  */
397169695Skan  for (i = 0; i < count; i++)
398169695Skan    {
399169695Skan      /* Read in # bytes in string.  */
400169695Skan      if (fread (&num_to_read, 1, sizeof (size_t), fd) != sizeof (size_t))
401169695Skan	return -1;
402169695Skan      if (buf_size < num_to_read + 1)
403169695Skan	{
404169695Skan	  buf_size = num_to_read + 1 + 127;
405169695Skan	  buf = XRESIZEVEC (char, buf, buf_size);
406169695Skan	}
407169695Skan      if (fread (buf, 1, num_to_read, fd) != num_to_read)
408169695Skan	return -1;
409169695Skan      buf[num_to_read] = '\0';
410169695Skan
411169695Skan      /* Generate makefile dependencies from .pch if -nopch-deps.  */
412169695Skan      if (self != NULL && strcmp (buf, self) != 0)
413169695Skan        deps_add_dep (deps, buf);
414169695Skan    }
415169695Skan
416169695Skan  free (buf);
417169695Skan  return 0;
418169695Skan}
419