VirtualBox

source: kBuild/trunk/src/lib/kDep.c@ 2203

Last change on this file since 2203 was 2104, checked in by bird, 16 years ago
kDepIDB: Added a -qquiet switch for disabling harmless warnings about stale files that cannot be found.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.3 KB
Line 
1/* $Id: kDep.c 2104 2008-11-26 01:52:53Z bird $ */
2/** @file
3 * kDep - Common Dependency Managemnt Code.
4 */
5
6/*
7 * Copyright (c) 2004-2008 knut st. osmundsen <[email protected]>
8 *
9 * This file is part of kBuild.
10 *
11 * kBuild is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * kBuild is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
23 *
24 */
25
26/*******************************************************************************
27* Header Files *
28*******************************************************************************/
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <errno.h>
33#include <ctype.h>
34#include <limits.h>
35#include <sys/stat.h>
36#include "k/kDefs.h"
37#if K_OS == K_OS_WINDOWS
38# include <windows.h>
39 extern void nt_fullpath(const char *pszPath, char *pszFull, size_t cchFull); /* nt_fullpath.c */
40#else
41# include <dirent.h>
42# include <unistd.h>
43# include <stdint.h>
44#endif
45
46#include "kDep.h"
47
48
49/*******************************************************************************
50* Global Variables *
51*******************************************************************************/
52/** List of dependencies. */
53static PDEP g_pDeps = NULL;
54
55
56/**
57 * Corrects all slashes to unix slashes.
58 *
59 * @returns pszFilename.
60 * @param pszFilename The filename to correct.
61 */
62static char *fixslash(char *pszFilename)
63{
64 char *psz = pszFilename;
65 while ((psz = strchr(psz, '\\')) != NULL)
66 *psz++ = '/';
67 return pszFilename;
68}
69
70
71#if K_OS == K_OS_OS2
72
73/**
74 * Corrects the case of a path.
75 *
76 * @param pszPath Pointer to the path, both input and output.
77 * The buffer must be able to hold one more byte than the string length.
78 */
79static void fixcase(char *pszFilename)
80{
81 return;
82}
83
84#elif K_OS != K_OS_WINDOWS
85
86/**
87 * Corrects the case of a path.
88 *
89 * @param pszPath Pointer to the path, both input and output.
90 */
91static void fixcase(char *pszFilename)
92{
93 char *psz;
94
95 /*
96 * Skip the root.
97 */
98 psz = pszFilename;
99 while (*psz == '/')
100 psz++;
101
102 /*
103 * Iterate all the components.
104 */
105 while (*psz)
106 {
107 char chSlash;
108 struct stat s;
109 char *pszStart = psz;
110
111 /*
112 * Find the next slash (or end of string) and terminate the string there.
113 */
114 while (*psz != '/' && *psz)
115 *psz++;
116 chSlash = *psz;
117 *psz = '\0';
118
119 /*
120 * Does this part exist?
121 * If not we'll enumerate the directory and search for an case-insensitive match.
122 */
123 if (stat(pszFilename, &s))
124 {
125 struct dirent *pEntry;
126 DIR *pDir;
127 if (pszStart == pszFilename)
128 pDir = opendir(*pszFilename ? pszFilename : ".");
129 else
130 {
131 pszStart[-1] = '\0';
132 pDir = opendir(pszFilename);
133 pszStart[-1] = '/';
134 }
135 if (!pDir)
136 {
137 *psz = chSlash;
138 break; /* giving up, if we fail to open the directory. */
139 }
140
141 while ((pEntry = readdir(pDir)) != NULL)
142 {
143 if (!strcasecmp(pEntry->d_name, pszStart))
144 {
145 strcpy(pszStart, pEntry->d_name);
146 break;
147 }
148 }
149 closedir(pDir);
150 if (!pEntry)
151 {
152 *psz = chSlash;
153 break; /* giving up if not found. */
154 }
155 }
156
157 /* restore the slash and press on. */
158 *psz = chSlash;
159 while (*psz == '/')
160 psz++;
161 }
162
163 return;
164}
165
166#endif /* !OS/2 && !Windows */
167
168
169/**
170 * 'Optimizes' and corrects the dependencies.
171 */
172void depOptimize(int fFixCase, int fQuiet)
173{
174 /*
175 * Walk the list correct the names and re-insert them.
176 */
177 PDEP pDepOrg = g_pDeps;
178 PDEP pDep = g_pDeps;
179 g_pDeps = NULL;
180 for (; pDep; pDep = pDep->pNext)
181 {
182#ifndef PATH_MAX
183 char szFilename[_MAX_PATH + 1];
184#else
185 char szFilename[PATH_MAX + 1];
186#endif
187 char *pszFilename;
188 struct stat s;
189
190 /*
191 * Skip some fictive names like <built-in> and <command line>.
192 */
193 if ( pDep->szFilename[0] == '<'
194 && pDep->szFilename[pDep->cchFilename - 1] == '>')
195 continue;
196 pszFilename = pDep->szFilename;
197
198#if K_OS != K_OS_OS2 && K_OS != K_OS_WINDOWS
199 /*
200 * Skip any drive letters from compilers running in wine.
201 */
202 if (pszFilename[1] == ':')
203 pszFilename += 2;
204#endif
205
206 /*
207 * The microsoft compilers are notoriously screwing up the casing.
208 * This will screw up kmk (/ GNU Make).
209 */
210 if (fFixCase)
211 {
212#if K_OS == K_OS_WINDOWS
213 nt_fullpath(pszFilename, szFilename, sizeof(szFilename));
214 fixslash(szFilename);
215#else
216 strcpy(szFilename, pszFilename);
217 fixslash(szFilename);
218 fixcase(szFilename);
219#endif
220 pszFilename = szFilename;
221 }
222
223 /*
224 * Check that the file exists before we start depending on it.
225 */
226 if (stat(pszFilename, &s))
227 {
228 if ( !fQuiet
229 || errno != ENOENT
230 || ( pszFilename[0] != '/'
231 && pszFilename[0] != '\\'
232 && ( !isalpha(pszFilename[0])
233 || pszFilename[1] != ':'
234 || ( pszFilename[2] != '/'
235 && pszFilename[2] != '\\')))
236 )
237 fprintf(stderr, "kDep: Skipping '%s' - %s!\n", pszFilename, strerror(errno));
238 continue;
239 }
240
241 /*
242 * Insert the corrected dependency.
243 */
244 depAdd(pszFilename, strlen(pszFilename));
245 }
246
247 /*
248 * Free the old ones.
249 */
250 while (pDepOrg)
251 {
252 pDep = pDepOrg;
253 pDepOrg = pDepOrg->pNext;
254 free(pDep);
255 }
256}
257
258
259/**
260 * Prints the dependency chain.
261 *
262 * @returns Pointer to the allocated dependency.
263 * @param pOutput Output stream.
264 */
265void depPrint(FILE *pOutput)
266{
267 PDEP pDep;
268 for (pDep = g_pDeps; pDep; pDep = pDep->pNext)
269 fprintf(pOutput, " \\\n\t%s", pDep->szFilename);
270 fprintf(pOutput, "\n\n");
271}
272
273
274/**
275 * Prints empty dependency stubs for all dependencies.
276 */
277void depPrintStubs(FILE *pOutput)
278{
279 PDEP pDep;
280 for (pDep = g_pDeps; pDep; pDep = pDep->pNext)
281 fprintf(pOutput, "%s:\n\n", pDep->szFilename);
282}
283
284
285/* sdbm:
286 This algorithm was created for sdbm (a public-domain reimplementation of
287 ndbm) database library. it was found to do well in scrambling bits,
288 causing better distribution of the keys and fewer splits. it also happens
289 to be a good general hashing function with good distribution. the actual
290 function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
291 is the faster version used in gawk. [there is even a faster, duff-device
292 version] the magic constant 65599 was picked out of thin air while
293 experimenting with different constants, and turns out to be a prime.
294 this is one of the algorithms used in berkeley db (see sleepycat) and
295 elsewhere. */
296static unsigned sdbm(const char *str)
297{
298 unsigned hash = 0;
299 int c;
300
301 while ((c = *(unsigned const char *)str++))
302 hash = c + (hash << 6) + (hash << 16) - hash;
303
304 return hash;
305}
306
307
308/**
309 * Adds a dependency.
310 *
311 * @returns Pointer to the allocated dependency.
312 * @param pszFilename The filename.
313 * @param cchFilename The length of the filename.
314 */
315PDEP depAdd(const char *pszFilename, size_t cchFilename)
316{
317 unsigned uHash = sdbm(pszFilename);
318 PDEP pDep;
319 PDEP pDepPrev;
320
321 /*
322 * Check if we've already got this one.
323 */
324 pDepPrev = NULL;
325 for (pDep = g_pDeps; pDep; pDepPrev = pDep, pDep = pDep->pNext)
326 if ( pDep->uHash == uHash
327 && pDep->cchFilename == cchFilename
328 && !memcmp(pDep->szFilename, pszFilename, cchFilename))
329 return pDep;
330
331 /*
332 * Add it.
333 */
334 pDep = (PDEP)malloc(sizeof(*pDep) + cchFilename);
335 if (!pDep)
336 {
337 fprintf(stderr, "\nOut of memory! (requested %lx bytes)\n\n",
338 (unsigned long)(sizeof(*pDep) + cchFilename));
339 exit(1);
340 }
341
342 pDep->cchFilename = cchFilename;
343 memcpy(pDep->szFilename, pszFilename, cchFilename + 1);
344 pDep->uHash = uHash;
345
346 if (pDepPrev)
347 {
348 pDep->pNext = pDepPrev->pNext;
349 pDepPrev->pNext = pDep;
350 }
351 else
352 {
353 pDep->pNext = g_pDeps;
354 g_pDeps = pDep;
355 }
356 return pDep;
357}
358
359
360/**
361 * Frees the current dependency chain.
362 */
363void depCleanup(void)
364{
365 PDEP pDep = g_pDeps;
366 g_pDeps = NULL;
367 while (pDep)
368 {
369 PDEP pFree = pDep;
370 pDep = pDep->pNext;
371 free(pFree);
372 }
373}
374
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette