1 /* Dependency generator for Makefile fragments.
2    Copyright (C) 2000-2014 Free Software Foundation, Inc.
3    Contributed by Zack Weinberg, Mar 2000
4 
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 3, or (at your option) any
8 later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING3.  If not see
17 <http://www.gnu.org/licenses/>.
18 
19  In other words, you are welcome to use, share and improve this program.
20  You are forbidden to forbid anyone else to use, share and improve
21  what you give them.   Help stamp out software-hoarding!  */
22 
23 #include "config.h"
24 #include "system.h"
25 #include "mkdeps.h"
26 
27 /* Keep this structure local to this file, so clients don't find it
28    easy to start making assumptions.  */
29 struct deps
30 {
31   const char **targetv;
32   unsigned int ntargets;	/* number of slots actually occupied */
33   unsigned int targets_size;	/* amt of allocated space - in words */
34 
35   const char **depv;
36   unsigned int ndeps;
37   unsigned int deps_size;
38 
39   const char **vpathv;
40   size_t *vpathlv;
41   unsigned int nvpaths;
42   unsigned int vpaths_size;
43 };
44 
45 static const char *munge (const char *);
46 
47 /* Given a filename, quote characters in that filename which are
48    significant to Make.  Note that it's not possible to quote all such
49    characters - e.g. \n, %, *, ?, [, \ (in some contexts), and ~ are
50    not properly handled.  It isn't possible to get this right in any
51    current version of Make.  (??? Still true?  Old comment referred to
52    3.76.1.)  */
53 
54 static const char *
munge(const char * filename)55 munge (const char *filename)
56 {
57   int len;
58   const char *p, *q;
59   char *dst, *buffer;
60 
61   for (p = filename, len = 0; *p; p++, len++)
62     {
63       switch (*p)
64 	{
65 	case ' ':
66 	case '\t':
67 	  /* GNU make uses a weird quoting scheme for white space.
68 	     A space or tab preceded by 2N+1 backslashes represents
69 	     N backslashes followed by space; a space or tab
70 	     preceded by 2N backslashes represents N backslashes at
71 	     the end of a file name; and backslashes in other
72 	     contexts should not be doubled.  */
73 	  for (q = p - 1; filename <= q && *q == '\\';  q--)
74 	    len++;
75 	  len++;
76 	  break;
77 
78 	case '$':
79 	  /* '$' is quoted by doubling it.  */
80 	  len++;
81 	  break;
82 
83 	case '#':
84 	  /* '#' is quoted with a backslash.  */
85 	  len++;
86 	  break;
87 	}
88     }
89 
90   /* Now we know how big to make the buffer.  */
91   buffer = XNEWVEC (char, len + 1);
92 
93   for (p = filename, dst = buffer; *p; p++, dst++)
94     {
95       switch (*p)
96 	{
97 	case ' ':
98 	case '\t':
99 	  for (q = p - 1; filename <= q && *q == '\\';  q--)
100 	    *dst++ = '\\';
101 	  *dst++ = '\\';
102 	  break;
103 
104 	case '$':
105 	  *dst++ = '$';
106 	  break;
107 
108 	case '#':
109 	  *dst++ = '\\';
110 	  break;
111 
112 	default:
113 	  /* nothing */;
114 	}
115       *dst = *p;
116     }
117 
118   *dst = '\0';
119   return buffer;
120 }
121 
122 /* If T begins with any of the partial pathnames listed in d->vpathv,
123    then advance T to point beyond that pathname.  */
124 static const char *
apply_vpath(struct deps * d,const char * t)125 apply_vpath (struct deps *d, const char *t)
126 {
127   if (d->vpathv)
128     {
129       unsigned int i;
130       for (i = 0; i < d->nvpaths; i++)
131 	{
132 	  if (!filename_ncmp (d->vpathv[i], t, d->vpathlv[i]))
133 	    {
134 	      const char *p = t + d->vpathlv[i];
135 	      if (!IS_DIR_SEPARATOR (*p))
136 		goto not_this_one;
137 
138 	      /* Do not simplify $(vpath)/../whatever.  ??? Might not
139 		 be necessary. */
140 	      if (p[1] == '.' && p[2] == '.' && IS_DIR_SEPARATOR (p[3]))
141 		goto not_this_one;
142 
143 	      /* found a match */
144 	      t = t + d->vpathlv[i] + 1;
145 	      break;
146 	    }
147 	not_this_one:;
148 	}
149     }
150 
151   /* Remove leading ./ in any case.  */
152   while (t[0] == '.' && IS_DIR_SEPARATOR (t[1]))
153     {
154       t += 2;
155       /* If we removed a leading ./, then also remove any /s after the
156 	 first.  */
157       while (IS_DIR_SEPARATOR (t[0]))
158 	++t;
159     }
160 
161   return t;
162 }
163 
164 /* Public routines.  */
165 
166 struct deps *
deps_init(void)167 deps_init (void)
168 {
169   return XCNEW (struct deps);
170 }
171 
172 void
deps_free(struct deps * d)173 deps_free (struct deps *d)
174 {
175   unsigned int i;
176 
177   if (d->targetv)
178     {
179       for (i = 0; i < d->ntargets; i++)
180 	free ((void *) d->targetv[i]);
181       free (d->targetv);
182     }
183 
184   if (d->depv)
185     {
186       for (i = 0; i < d->ndeps; i++)
187 	free ((void *) d->depv[i]);
188       free (d->depv);
189     }
190 
191   if (d->vpathv)
192     {
193       for (i = 0; i < d->nvpaths; i++)
194 	free ((void *) d->vpathv[i]);
195       free (d->vpathv);
196       free (d->vpathlv);
197     }
198 
199   free (d);
200 }
201 
202 /* Adds a target T.  We make a copy, so it need not be a permanent
203    string.  QUOTE is true if the string should be quoted.  */
204 void
deps_add_target(struct deps * d,const char * t,int quote)205 deps_add_target (struct deps *d, const char *t, int quote)
206 {
207   if (d->ntargets == d->targets_size)
208     {
209       d->targets_size = d->targets_size * 2 + 4;
210       d->targetv = XRESIZEVEC (const char *, d->targetv, d->targets_size);
211     }
212 
213   t = apply_vpath (d, t);
214   if (quote)
215     t = munge (t);  /* Also makes permanent copy.  */
216   else
217     t = xstrdup (t);
218 
219   d->targetv[d->ntargets++] = t;
220 }
221 
222 /* Sets the default target if none has been given already.  An empty
223    string as the default target in interpreted as stdin.  The string
224    is quoted for MAKE.  */
225 void
deps_add_default_target(struct deps * d,const char * tgt)226 deps_add_default_target (struct deps *d, const char *tgt)
227 {
228   /* Only if we have no targets.  */
229   if (d->ntargets)
230     return;
231 
232   if (tgt[0] == '\0')
233     deps_add_target (d, "-", 1);
234   else
235     {
236 #ifndef TARGET_OBJECT_SUFFIX
237 # define TARGET_OBJECT_SUFFIX ".o"
238 #endif
239       const char *start = lbasename (tgt);
240       char *o = (char *) alloca (strlen (start)
241                                  + strlen (TARGET_OBJECT_SUFFIX) + 1);
242       char *suffix;
243 
244       strcpy (o, start);
245 
246       suffix = strrchr (o, '.');
247       if (!suffix)
248         suffix = o + strlen (o);
249       strcpy (suffix, TARGET_OBJECT_SUFFIX);
250 
251       deps_add_target (d, o, 1);
252     }
253 }
254 
255 void
deps_add_dep(struct deps * d,const char * t)256 deps_add_dep (struct deps *d, const char *t)
257 {
258   t = munge (apply_vpath (d, t));  /* Also makes permanent copy.  */
259 
260   if (d->ndeps == d->deps_size)
261     {
262       d->deps_size = d->deps_size * 2 + 8;
263       d->depv = XRESIZEVEC (const char *, d->depv, d->deps_size);
264     }
265   d->depv[d->ndeps++] = t;
266 }
267 
268 void
deps_add_vpath(struct deps * d,const char * vpath)269 deps_add_vpath (struct deps *d, const char *vpath)
270 {
271   const char *elem, *p;
272   char *copy;
273   size_t len;
274 
275   for (elem = vpath; *elem; elem = p)
276     {
277       for (p = elem; *p && *p != ':'; p++);
278       len = p - elem;
279       copy = XNEWVEC (char, len + 1);
280       memcpy (copy, elem, len);
281       copy[len] = '\0';
282       if (*p == ':')
283 	p++;
284 
285       if (d->nvpaths == d->vpaths_size)
286 	{
287 	  d->vpaths_size = d->vpaths_size * 2 + 8;
288 	  d->vpathv = XRESIZEVEC (const char *, d->vpathv, d->vpaths_size);
289 	  d->vpathlv = XRESIZEVEC (size_t, d->vpathlv, d->vpaths_size);
290 	}
291       d->vpathv[d->nvpaths] = copy;
292       d->vpathlv[d->nvpaths] = len;
293       d->nvpaths++;
294     }
295 }
296 
297 void
deps_write(const struct deps * d,FILE * fp,unsigned int colmax)298 deps_write (const struct deps *d, FILE *fp, unsigned int colmax)
299 {
300   unsigned int size, i, column;
301 
302   column = 0;
303   if (colmax && colmax < 34)
304     colmax = 34;
305 
306   for (i = 0; i < d->ntargets; i++)
307     {
308       size = strlen (d->targetv[i]);
309       column += size;
310       if (i)
311 	{
312 	  if (colmax && column > colmax)
313 	    {
314 	      fputs (" \\\n ", fp);
315 	      column = 1 + size;
316 	    }
317 	  else
318 	    {
319 	      putc (' ', fp);
320 	      column++;
321 	    }
322 	}
323       fputs (d->targetv[i], fp);
324     }
325 
326   putc (':', fp);
327   column++;
328 
329   for (i = 0; i < d->ndeps; i++)
330     {
331       size = strlen (d->depv[i]);
332       column += size;
333       if (colmax && column > colmax)
334 	{
335 	  fputs (" \\\n ", fp);
336 	  column = 1 + size;
337 	}
338       else
339 	{
340 	  putc (' ', fp);
341 	  column++;
342 	}
343       fputs (d->depv[i], fp);
344     }
345   putc ('\n', fp);
346 }
347 
348 void
deps_phony_targets(const struct deps * d,FILE * fp)349 deps_phony_targets (const struct deps *d, FILE *fp)
350 {
351   unsigned int i;
352 
353   for (i = 1; i < d->ndeps; i++)
354     {
355       putc ('\n', fp);
356       fputs (d->depv[i], fp);
357       putc (':', fp);
358       putc ('\n', fp);
359     }
360 }
361 
362 /* Write out a deps buffer to a file, in a form that can be read back
363    with deps_restore.  Returns nonzero on error, in which case the
364    error number will be in errno.  */
365 
366 int
deps_save(struct deps * deps,FILE * f)367 deps_save (struct deps *deps, FILE *f)
368 {
369   unsigned int i;
370 
371   /* The cppreader structure contains makefile dependences.  Write out this
372      structure.  */
373 
374   /* The number of dependences.  */
375   if (fwrite (&deps->ndeps, sizeof (deps->ndeps), 1, f) != 1)
376       return -1;
377   /* The length of each dependence followed by the string.  */
378   for (i = 0; i < deps->ndeps; i++)
379     {
380       size_t num_to_write = strlen (deps->depv[i]);
381       if (fwrite (&num_to_write, sizeof (size_t), 1, f) != 1)
382           return -1;
383       if (fwrite (deps->depv[i], num_to_write, 1, f) != 1)
384           return -1;
385     }
386 
387   return 0;
388 }
389 
390 /* Read back dependency information written with deps_save into
391    the deps buffer.  The third argument may be NULL, in which case
392    the dependency information is just skipped, or it may be a filename,
393    in which case that filename is skipped.  */
394 
395 int
deps_restore(struct deps * deps,FILE * fd,const char * self)396 deps_restore (struct deps *deps, FILE *fd, const char *self)
397 {
398   unsigned int i, count;
399   size_t num_to_read;
400   size_t buf_size = 512;
401   char *buf;
402 
403   /* Number of dependences.  */
404   if (fread (&count, 1, sizeof (count), fd) != sizeof (count))
405     return -1;
406 
407   buf = XNEWVEC (char, buf_size);
408 
409   /* The length of each dependence string, followed by the string.  */
410   for (i = 0; i < count; i++)
411     {
412       /* Read in # bytes in string.  */
413       if (fread (&num_to_read, 1, sizeof (size_t), fd) != sizeof (size_t))
414 	{
415 	  free (buf);
416 	  return -1;
417 	}
418       if (buf_size < num_to_read + 1)
419 	{
420 	  buf_size = num_to_read + 1 + 127;
421 	  buf = XRESIZEVEC (char, buf, buf_size);
422 	}
423       if (fread (buf, 1, num_to_read, fd) != num_to_read)
424 	{
425 	  free (buf);
426 	  return -1;
427 	}
428       buf[num_to_read] = '\0';
429 
430       /* Generate makefile dependencies from .pch if -nopch-deps.  */
431       if (self != NULL && filename_cmp (buf, self) != 0)
432         deps_add_dep (deps, buf);
433     }
434 
435   free (buf);
436   return 0;
437 }
438