VirtualBox

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

Last change on this file since 2074 was 2019, checked in by bird, 17 years ago

GPLv2 -> GPLv3. See Ticket #44 for clarifications. Fixes #44.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.9 KB
Line 
1/* $Id: kDep.c 2019 2008-11-02 00:21:05Z 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)
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 fprintf(stderr, "kDep: Skipping '%s' - %s!\n", pszFilename, strerror(errno));
229 continue;
230 }
231
232 /*
233 * Insert the corrected dependency.
234 */
235 depAdd(pszFilename, strlen(pszFilename));
236 }
237
238 /*
239 * Free the old ones.
240 */
241 while (pDepOrg)
242 {
243 pDep = pDepOrg;
244 pDepOrg = pDepOrg->pNext;
245 free(pDep);
246 }
247}
248
249
250/**
251 * Prints the dependency chain.
252 *
253 * @returns Pointer to the allocated dependency.
254 * @param pOutput Output stream.
255 */
256void depPrint(FILE *pOutput)
257{
258 PDEP pDep;
259 for (pDep = g_pDeps; pDep; pDep = pDep->pNext)
260 fprintf(pOutput, " \\\n\t%s", pDep->szFilename);
261 fprintf(pOutput, "\n\n");
262}
263
264
265/**
266 * Prints empty dependency stubs for all dependencies.
267 */
268void depPrintStubs(FILE *pOutput)
269{
270 PDEP pDep;
271 for (pDep = g_pDeps; pDep; pDep = pDep->pNext)
272 fprintf(pOutput, "%s:\n\n", pDep->szFilename);
273}
274
275
276/* sdbm:
277 This algorithm was created for sdbm (a public-domain reimplementation of
278 ndbm) database library. it was found to do well in scrambling bits,
279 causing better distribution of the keys and fewer splits. it also happens
280 to be a good general hashing function with good distribution. the actual
281 function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
282 is the faster version used in gawk. [there is even a faster, duff-device
283 version] the magic constant 65599 was picked out of thin air while
284 experimenting with different constants, and turns out to be a prime.
285 this is one of the algorithms used in berkeley db (see sleepycat) and
286 elsewhere. */
287static unsigned sdbm(const char *str)
288{
289 unsigned hash = 0;
290 int c;
291
292 while ((c = *(unsigned const char *)str++))
293 hash = c + (hash << 6) + (hash << 16) - hash;
294
295 return hash;
296}
297
298
299/**
300 * Adds a dependency.
301 *
302 * @returns Pointer to the allocated dependency.
303 * @param pszFilename The filename.
304 * @param cchFilename The length of the filename.
305 */
306PDEP depAdd(const char *pszFilename, size_t cchFilename)
307{
308 unsigned uHash = sdbm(pszFilename);
309 PDEP pDep;
310 PDEP pDepPrev;
311
312 /*
313 * Check if we've already got this one.
314 */
315 pDepPrev = NULL;
316 for (pDep = g_pDeps; pDep; pDepPrev = pDep, pDep = pDep->pNext)
317 if ( pDep->uHash == uHash
318 && pDep->cchFilename == cchFilename
319 && !memcmp(pDep->szFilename, pszFilename, cchFilename))
320 return pDep;
321
322 /*
323 * Add it.
324 */
325 pDep = (PDEP)malloc(sizeof(*pDep) + cchFilename);
326 if (!pDep)
327 {
328 fprintf(stderr, "\nOut of memory! (requested %lx bytes)\n\n",
329 (unsigned long)(sizeof(*pDep) + cchFilename));
330 exit(1);
331 }
332
333 pDep->cchFilename = cchFilename;
334 memcpy(pDep->szFilename, pszFilename, cchFilename + 1);
335 pDep->uHash = uHash;
336
337 if (pDepPrev)
338 {
339 pDep->pNext = pDepPrev->pNext;
340 pDepPrev->pNext = pDep;
341 }
342 else
343 {
344 pDep->pNext = g_pDeps;
345 g_pDeps = pDep;
346 }
347 return pDep;
348}
349
350
351/**
352 * Frees the current dependency chain.
353 */
354void depCleanup(void)
355{
356 PDEP pDep = g_pDeps;
357 g_pDeps = NULL;
358 while (pDep)
359 {
360 PDEP pFree = pDep;
361 pDep = pDep->pNext;
362 free(pFree);
363 }
364}
365
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