xref: /openbsd/gnu/gcc/libcpp/mkdeps.c (revision 404b540a)
1 /* Dependency generator for Makefile fragments.
2    Copyright (C) 2000, 2001, 2003, 2007 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 2, 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; if not, write to the Free Software
17 Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
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     }
84 
85   /* Now we know how big to make the buffer.  */
86   buffer = XNEWVEC (char, len + 1);
87 
88   for (p = filename, dst = buffer; *p; p++, dst++)
89     {
90       switch (*p)
91 	{
92 	case ' ':
93 	case '\t':
94 	  for (q = p - 1; filename <= q && *q == '\\';  q--)
95 	    *dst++ = '\\';
96 	  *dst++ = '\\';
97 	  break;
98 
99 	case '$':
100 	  *dst++ = '$';
101 	  break;
102 
103 	default:
104 	  /* nothing */;
105 	}
106       *dst = *p;
107     }
108 
109   *dst = '\0';
110   return buffer;
111 }
112 
113 /* If T begins with any of the partial pathnames listed in d->vpathv,
114    then advance T to point beyond that pathname.  */
115 static const char *
apply_vpath(struct deps * d,const char * t)116 apply_vpath (struct deps *d, const char *t)
117 {
118   if (d->vpathv)
119     {
120       unsigned int i;
121       for (i = 0; i < d->nvpaths; i++)
122 	{
123 	  if (!strncmp (d->vpathv[i], t, d->vpathlv[i]))
124 	    {
125 	      const char *p = t + d->vpathlv[i];
126 	      if (!IS_DIR_SEPARATOR (*p))
127 		goto not_this_one;
128 
129 	      /* Do not simplify $(vpath)/../whatever.  ??? Might not
130 		 be necessary. */
131 	      if (p[1] == '.' && p[2] == '.' && IS_DIR_SEPARATOR (p[3]))
132 		goto not_this_one;
133 
134 	      /* found a match */
135 	      t = t + d->vpathlv[i] + 1;
136 	      break;
137 	    }
138 	not_this_one:;
139 	}
140     }
141 
142   /* Remove leading ./ in any case.  */
143   while (t[0] == '.' && IS_DIR_SEPARATOR (t[1]))
144     {
145       t += 2;
146       /* If we removed a leading ./, then also remove any /s after the
147 	 first.  */
148       while (IS_DIR_SEPARATOR (t[0]))
149 	++t;
150     }
151 
152   return t;
153 }
154 
155 /* Public routines.  */
156 
157 struct deps *
deps_init(void)158 deps_init (void)
159 {
160   return XCNEW (struct deps);
161 }
162 
163 void
deps_free(struct deps * d)164 deps_free (struct deps *d)
165 {
166   unsigned int i;
167 
168   if (d->targetv)
169     {
170       for (i = 0; i < d->ntargets; i++)
171 	free ((void *) d->targetv[i]);
172       free (d->targetv);
173     }
174 
175   if (d->depv)
176     {
177       for (i = 0; i < d->ndeps; i++)
178 	free ((void *) d->depv[i]);
179       free (d->depv);
180     }
181 
182   if (d->vpathv)
183     {
184       for (i = 0; i < d->nvpaths; i++)
185 	free ((void *) d->vpathv[i]);
186       free (d->vpathv);
187       free (d->vpathlv);
188     }
189 
190   free (d);
191 }
192 
193 /* Adds a target T.  We make a copy, so it need not be a permanent
194    string.  QUOTE is true if the string should be quoted.  */
195 void
deps_add_target(struct deps * d,const char * t,int quote)196 deps_add_target (struct deps *d, const char *t, int quote)
197 {
198   if (d->ntargets == d->targets_size)
199     {
200       d->targets_size = d->targets_size * 2 + 4;
201       d->targetv = XRESIZEVEC (const char *, d->targetv, d->targets_size);
202     }
203 
204   t = apply_vpath (d, t);
205   if (quote)
206     t = munge (t);  /* Also makes permanent copy.  */
207   else
208     t = xstrdup (t);
209 
210   d->targetv[d->ntargets++] = t;
211 }
212 
213 /* Sets the default target if none has been given already.  An empty
214    string as the default target in interpreted as stdin.  The string
215    is quoted for MAKE.  */
216 void
deps_add_default_target(struct deps * d,const char * tgt)217 deps_add_default_target (struct deps *d, const char *tgt)
218 {
219   /* Only if we have no targets.  */
220   if (d->ntargets)
221     return;
222 
223   if (tgt[0] == '\0')
224     deps_add_target (d, "-", 1);
225   else
226     {
227 #ifndef TARGET_OBJECT_SUFFIX
228 # define TARGET_OBJECT_SUFFIX ".o"
229 #endif
230       const char *start = lbasename (tgt);
231       char *o = (char *) alloca (strlen (start)
232                                  + strlen (TARGET_OBJECT_SUFFIX) + 1);
233       char *suffix;
234 
235       strcpy (o, start);
236 
237       suffix = strrchr (o, '.');
238       if (!suffix)
239         suffix = o + strlen (o);
240       strcpy (suffix, TARGET_OBJECT_SUFFIX);
241 
242       deps_add_target (d, o, 1);
243     }
244 }
245 
246 void
deps_add_dep(struct deps * d,const char * t)247 deps_add_dep (struct deps *d, const char *t)
248 {
249   t = munge (apply_vpath (d, t));  /* Also makes permanent copy.  */
250 
251   if (d->ndeps == d->deps_size)
252     {
253       d->deps_size = d->deps_size * 2 + 8;
254       d->depv = XRESIZEVEC (const char *, d->depv, d->deps_size);
255     }
256   d->depv[d->ndeps++] = t;
257 }
258 
259 void
deps_add_vpath(struct deps * d,const char * vpath)260 deps_add_vpath (struct deps *d, const char *vpath)
261 {
262   const char *elem, *p;
263   char *copy;
264   size_t len;
265 
266   for (elem = vpath; *elem; elem = p)
267     {
268       for (p = elem; *p && *p != ':'; p++);
269       len = p - elem;
270       copy = XNEWVEC (char, len + 1);
271       memcpy (copy, elem, len);
272       copy[len] = '\0';
273       if (*p == ':')
274 	p++;
275 
276       if (d->nvpaths == d->vpaths_size)
277 	{
278 	  d->vpaths_size = d->vpaths_size * 2 + 8;
279 	  d->vpathv = XRESIZEVEC (const char *, d->vpathv, d->vpaths_size);
280 	  d->vpathlv = XRESIZEVEC (size_t, d->vpathlv, d->vpaths_size);
281 	}
282       d->vpathv[d->nvpaths] = copy;
283       d->vpathlv[d->nvpaths] = len;
284       d->nvpaths++;
285     }
286 }
287 
288 void
deps_write(const struct deps * d,FILE * fp,unsigned int colmax)289 deps_write (const struct deps *d, FILE *fp, unsigned int colmax)
290 {
291   unsigned int size, i, column;
292 
293   column = 0;
294   if (colmax && colmax < 34)
295     colmax = 34;
296 
297   for (i = 0; i < d->ntargets; i++)
298     {
299       size = strlen (d->targetv[i]);
300       column += size;
301       if (colmax && column > colmax)
302 	{
303 	  fputs (" \\\n ", fp);
304 	  column = 1 + size;
305 	}
306       if (i)
307 	{
308 	  putc (' ', fp);
309 	  column++;
310 	}
311       fputs (d->targetv[i], fp);
312     }
313 
314   putc (':', fp);
315   putc (' ', fp);
316   column += 2;
317 
318   for (i = 0; i < d->ndeps; i++)
319     {
320       size = strlen (d->depv[i]);
321       column += size;
322       if (colmax && column > colmax)
323 	{
324 	  fputs (" \\\n ", fp);
325 	  column = 1 + size;
326 	}
327       if (i)
328 	{
329 	  putc (' ', fp);
330 	  column++;
331 	}
332       fputs (d->depv[i], fp);
333     }
334   putc ('\n', fp);
335 }
336 
337 void
deps_phony_targets(const struct deps * d,FILE * fp)338 deps_phony_targets (const struct deps *d, FILE *fp)
339 {
340   unsigned int i;
341 
342   for (i = 1; i < d->ndeps; i++)
343     {
344       putc ('\n', fp);
345       fputs (d->depv[i], fp);
346       putc (':', fp);
347       putc ('\n', fp);
348     }
349 }
350 
351 /* Write out a deps buffer to a file, in a form that can be read back
352    with deps_restore.  Returns nonzero on error, in which case the
353    error number will be in errno.  */
354 
355 int
deps_save(struct deps * deps,FILE * f)356 deps_save (struct deps *deps, FILE *f)
357 {
358   unsigned int i;
359 
360   /* The cppreader structure contains makefile dependences.  Write out this
361      structure.  */
362 
363   /* The number of dependences.  */
364   if (fwrite (&deps->ndeps, sizeof (deps->ndeps), 1, f) != 1)
365       return -1;
366   /* The length of each dependence followed by the string.  */
367   for (i = 0; i < deps->ndeps; i++)
368     {
369       size_t num_to_write = strlen (deps->depv[i]);
370       if (fwrite (&num_to_write, sizeof (size_t), 1, f) != 1)
371           return -1;
372       if (fwrite (deps->depv[i], num_to_write, 1, f) != 1)
373           return -1;
374     }
375 
376   return 0;
377 }
378 
379 /* Read back dependency information written with deps_save into
380    the deps buffer.  The third argument may be NULL, in which case
381    the dependency information is just skipped, or it may be a filename,
382    in which case that filename is skipped.  */
383 
384 int
deps_restore(struct deps * deps,FILE * fd,const char * self)385 deps_restore (struct deps *deps, FILE *fd, const char *self)
386 {
387   unsigned int i, count;
388   size_t num_to_read;
389   size_t buf_size = 512;
390   char *buf = XNEWVEC (char, buf_size);
391 
392   /* Number of dependences.  */
393   if (fread (&count, 1, sizeof (count), fd) != sizeof (count))
394     return -1;
395 
396   /* The length of each dependence string, followed by the string.  */
397   for (i = 0; i < count; i++)
398     {
399       /* Read in # bytes in string.  */
400       if (fread (&num_to_read, 1, sizeof (size_t), fd) != sizeof (size_t))
401 	return -1;
402       if (buf_size < num_to_read + 1)
403 	{
404 	  buf_size = num_to_read + 1 + 127;
405 	  buf = XRESIZEVEC (char, buf, buf_size);
406 	}
407       if (fread (buf, 1, num_to_read, fd) != num_to_read)
408 	return -1;
409       buf[num_to_read] = '\0';
410 
411       /* Generate makefile dependencies from .pch if -nopch-deps.  */
412       if (self != NULL && strcmp (buf, self) != 0)
413         deps_add_dep (deps, buf);
414     }
415 
416   free (buf);
417   return 0;
418 }
419