]>
Commit | Line | Data |
---|---|---|
49e6c08e | 1 | /* Dependency generator for Makefile fragments. |
03b9ab42 | 2 | Copyright (C) 2000, 2001 Free Software Foundation, Inc. |
49e6c08e ZW |
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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 | ||
03b9ab42 NB |
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 | ||
49e6c08e ZW |
40 | static const char *munge PARAMS ((const char *)); |
41 | static const char *base_name PARAMS ((const char *)); | |
42 | ||
49e6c08e ZW |
43 | /* Given a filename, quote characters in that filename which are |
44 | significant to Make. Note that it's not possible to quote all such | |
45 | characters - e.g. \n, %, *, ?, [, \ (in some contexts), and ~ are | |
46 | not properly handled. It isn't possible to get this right in any | |
47 | current version of Make. (??? Still true? Old comment referred to | |
48 | 3.76.1.) */ | |
49 | ||
50 | static const char * | |
51 | munge (filename) | |
52 | const char *filename; | |
53 | { | |
54 | int len; | |
55 | const char *p, *q; | |
56 | char *dst, *buffer; | |
57 | ||
58 | for (p = filename, len = 0; *p; p++, len++) | |
59 | { | |
60 | switch (*p) | |
61 | { | |
62 | case ' ': | |
63 | case '\t': | |
64 | /* GNU make uses a weird quoting scheme for white space. | |
65 | A space or tab preceded by 2N+1 backslashes represents | |
66 | N backslashes followed by space; a space or tab | |
67 | preceded by 2N backslashes represents N backslashes at | |
68 | the end of a file name; and backslashes in other | |
69 | contexts should not be doubled. */ | |
e23c0ba3 | 70 | for (q = p - 1; filename <= q && *q == '\\'; q--) |
49e6c08e ZW |
71 | len++; |
72 | len++; | |
73 | break; | |
74 | ||
75 | case '$': | |
76 | /* '$' is quoted by doubling it. This can mishandle things | |
77 | like "$(" but there's no easy fix. */ | |
78 | len++; | |
79 | break; | |
80 | } | |
81 | } | |
82 | ||
83 | /* Now we know how big to make the buffer. */ | |
dd3b81b4 | 84 | buffer = xmalloc (len + 1); |
49e6c08e ZW |
85 | |
86 | for (p = filename, dst = buffer; *p; p++, dst++) | |
87 | { | |
88 | switch (*p) | |
89 | { | |
90 | case ' ': | |
91 | case '\t': | |
e23c0ba3 | 92 | for (q = p - 1; filename <= q && *q == '\\'; q--) |
49e6c08e ZW |
93 | *dst++ = '\\'; |
94 | *dst++ = '\\'; | |
95 | break; | |
96 | ||
97 | case '$': | |
98 | *dst++ = '$'; | |
99 | break; | |
100 | ||
101 | default: | |
102 | /* nothing */; | |
103 | } | |
104 | *dst = *p; | |
105 | } | |
106 | ||
107 | *dst = '\0'; | |
108 | return buffer; | |
109 | } | |
110 | ||
111 | /* Given a pathname, calculate the non-directory part. This always | |
112 | knows how to handle Unix-style pathnames, and understands VMS and | |
113 | DOS paths on those systems. */ | |
05bccae2 | 114 | |
49e6c08e ZW |
115 | /* Find the base name of a (partial) pathname FNAME. |
116 | Returns a pointer into the string passed in. | |
117 | Accepts Unix (/-separated) paths on all systems, | |
118 | DOS and VMS paths on those systems. */ | |
05bccae2 | 119 | |
49e6c08e ZW |
120 | static const char * |
121 | base_name (fname) | |
122 | const char *fname; | |
123 | { | |
124 | const char *s = fname; | |
125 | const char *p; | |
126 | #if defined (HAVE_DOS_BASED_FILE_SYSTEM) | |
127 | if (ISALPHA (s[0]) && s[1] == ':') s += 2; | |
128 | if ((p = strrchr (s, '\\'))) s = p + 1; | |
129 | #elif defined VMS | |
130 | if ((p = strrchr (s, ':'))) s = p + 1; /* Skip device. */ | |
131 | if ((p = strrchr (s, ']'))) s = p + 1; /* Skip directory. */ | |
132 | if ((p = strrchr (s, '>'))) s = p + 1; /* Skip alternate (int'n'l) dir. */ | |
133 | #endif | |
134 | if ((p = strrchr (s, '/'))) s = p + 1; | |
135 | return s; | |
136 | } | |
137 | ||
138 | /* Public routines. */ | |
139 | ||
140 | struct deps * | |
fd05eb80 | 141 | deps_init () |
49e6c08e ZW |
142 | { |
143 | struct deps *d = (struct deps *) xmalloc (sizeof (struct deps)); | |
144 | ||
145 | /* Allocate space for the vectors now. */ | |
146 | ||
e23c0ba3 ZW |
147 | d->targetv = (const char **) xmalloc (2 * sizeof (const char *)); |
148 | d->depv = (const char **) xmalloc (8 * sizeof (const char *)); | |
49e6c08e ZW |
149 | |
150 | d->ntargets = 0; | |
151 | d->targets_size = 2; | |
152 | d->ndeps = 0; | |
153 | d->deps_size = 8; | |
154 | ||
155 | return d; | |
156 | } | |
157 | ||
158 | void | |
159 | deps_free (d) | |
160 | struct deps *d; | |
161 | { | |
162 | unsigned int i; | |
05bccae2 | 163 | |
49e6c08e ZW |
164 | for (i = 0; i < d->ntargets; i++) |
165 | free ((PTR) d->targetv[i]); | |
05bccae2 | 166 | |
49e6c08e ZW |
167 | for (i = 0; i < d->ndeps; i++) |
168 | free ((PTR) d->depv[i]); | |
169 | ||
170 | free (d->targetv); | |
171 | free (d->depv); | |
172 | free (d); | |
173 | } | |
174 | ||
175 | void | |
176 | deps_add_target (d, t) | |
177 | struct deps *d; | |
178 | const char *t; | |
179 | { | |
180 | t = munge (t); /* Also makes permanent copy. */ | |
181 | ||
182 | if (d->ntargets == d->targets_size) | |
183 | { | |
184 | d->targets_size *= 2; | |
7ceb3598 | 185 | d->targetv = (const char **) xrealloc (d->targetv, |
49e6c08e ZW |
186 | d->targets_size * sizeof (const char *)); |
187 | } | |
05bccae2 | 188 | |
49e6c08e ZW |
189 | d->targetv[d->ntargets++] = t; |
190 | } | |
191 | ||
03b9ab42 NB |
192 | /* Sets the default target if none has been given already. An empty |
193 | string as the default target in interpreted as stdin. */ | |
49e6c08e | 194 | void |
03b9ab42 | 195 | deps_add_default_target (d, tgt) |
49e6c08e | 196 | struct deps *d; |
03b9ab42 | 197 | const char *tgt; |
49e6c08e | 198 | { |
92df03e1 | 199 | char *o, *suffix; |
49e6c08e | 200 | |
03b9ab42 NB |
201 | /* Only if we have no targets. */ |
202 | if (d->ntargets) | |
203 | return; | |
49e6c08e | 204 | |
03b9ab42 NB |
205 | if (tgt[0] == '\0') |
206 | deps_add_target (d, "-"); | |
49e6c08e | 207 | else |
03b9ab42 NB |
208 | { |
209 | tgt = base_name (tgt); | |
210 | o = (char *) alloca (strlen (tgt) + 8); | |
211 | ||
212 | strcpy (o, tgt); | |
213 | suffix = strrchr (o, '.'); | |
49e6c08e | 214 | |
03b9ab42 NB |
215 | #ifndef OBJECT_SUFFIX |
216 | # define OBJECT_SUFFIX ".o" | |
217 | #endif | |
218 | ||
219 | if (suffix) | |
220 | strcpy (suffix, OBJECT_SUFFIX); | |
221 | else | |
222 | strcat (o, OBJECT_SUFFIX); | |
223 | deps_add_target (d, o); | |
224 | } | |
49e6c08e ZW |
225 | } |
226 | ||
227 | void | |
228 | deps_add_dep (d, t) | |
229 | struct deps *d; | |
230 | const char *t; | |
231 | { | |
232 | t = munge (t); /* Also makes permanent copy. */ | |
233 | ||
234 | if (d->ndeps == d->deps_size) | |
235 | { | |
236 | d->deps_size *= 2; | |
7ceb3598 NB |
237 | d->depv = (const char **) |
238 | xrealloc (d->depv, d->deps_size * sizeof (const char *)); | |
49e6c08e ZW |
239 | } |
240 | d->depv[d->ndeps++] = t; | |
241 | } | |
242 | ||
243 | void | |
244 | deps_write (d, fp, colmax) | |
245 | const struct deps *d; | |
246 | FILE *fp; | |
247 | unsigned int colmax; | |
248 | { | |
249 | unsigned int size, i, column; | |
250 | ||
251 | column = 0; | |
252 | if (colmax && colmax < 34) | |
253 | colmax = 34; | |
254 | ||
255 | for (i = 0; i < d->ntargets; i++) | |
256 | { | |
257 | size = strlen (d->targetv[i]); | |
258 | column += size; | |
259 | if (colmax && column > colmax) | |
260 | { | |
261 | fputs (" \\\n ", fp); | |
262 | column = 1 + size; | |
263 | } | |
264 | if (i) | |
265 | { | |
266 | putc (' ', fp); | |
267 | column++; | |
268 | } | |
269 | fputs (d->targetv[i], fp); | |
270 | } | |
271 | ||
272 | putc (':', fp); | |
273 | putc (' ', fp); | |
274 | column += 2; | |
275 | ||
276 | for (i = 0; i < d->ndeps; i++) | |
277 | { | |
278 | size = strlen (d->depv[i]); | |
279 | column += size; | |
280 | if (colmax && column > colmax) | |
281 | { | |
282 | fputs (" \\\n ", fp); | |
283 | column = 1 + size; | |
284 | } | |
285 | if (i) | |
286 | { | |
287 | putc (' ', fp); | |
288 | column++; | |
289 | } | |
290 | fputs (d->depv[i], fp); | |
291 | } | |
292 | putc ('\n', fp); | |
293 | } | |
294 | ||
295 | void | |
296 | deps_dummy_targets (d, fp) | |
297 | const struct deps *d; | |
298 | FILE *fp; | |
299 | { | |
05bccae2 | 300 | unsigned int i; |
49e6c08e ZW |
301 | |
302 | for (i = 1; i < d->ndeps; i++) | |
303 | { | |
304 | fputs (d->depv[i], fp); | |
305 | putc (':', fp); | |
306 | putc ('\n', fp); | |
307 | } | |
308 | } |