VirtualBox

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

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

Use double quotes.

  • 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 1284 2007-11-30 02:56:22Z bird $ */
2/** @file
3 *
4 * kDep - Common Dependency Managemnt Code.
5 *
6 * Copyright (c) 2004-2007 knut st. osmundsen <[email protected]>
7 *
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 2 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, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <errno.h>
35#include <ctype.h>
36#include <limits.h>
37#include <sys/stat.h>
38#include "k/kDefs.h"
39#if K_OS == K_OS_WINDOWS
40# include <windows.h>
41 extern void nt_fullpath(const char *pszPath, char *pszFull, size_t cchFull); /* nt_fullpath.c */
42#else
43# include <dirent.h>
44# include <unistd.h>
45# include <stdint.h>
46#endif
47
48#include "kDep.h"
49
50
51/*******************************************************************************
52* Global Variables *
53*******************************************************************************/
54/** List of dependencies. */
55static PDEP g_pDeps = NULL;
56
57
58/**
59 * Corrects all slashes to unix slashes.
60 *
61 * @returns pszFilename.
62 * @param pszFilename The filename to correct.
63 */
64static char *fixslash(char *pszFilename)
65{
66 char *psz = pszFilename;
67 while ((psz = strchr(psz, '\\')) != NULL)
68 *psz++ = '/';
69 return pszFilename;
70}
71
72
73#if K_OS == K_OS_OS2
74
75/**
76 * Corrects the case of a path.
77 *
78 * @param pszPath Pointer to the path, both input and output.
79 * The buffer must be able to hold one more byte than the string length.
80 */
81static void fixcase(char *pszFilename)
82{
83 return;
84}
85
86#elif K_OS != K_OS_WINDOWS
87
88/**
89 * Corrects the case of a path.
90 *
91 * @param pszPath Pointer to the path, both input and output.
92 */
93static void fixcase(char *pszFilename)
94{
95 char *psz;
96
97 /*
98 * Skip the root.
99 */
100 psz = pszFilename;
101 while (*psz == '/')
102 psz++;
103
104 /*
105 * Iterate all the components.
106 */
107 while (*psz)
108 {
109 char chSlash;
110 struct stat s;
111 char *pszStart = psz;
112
113 /*
114 * Find the next slash (or end of string) and terminate the string there.
115 */
116 while (*psz != '/' && *psz)
117 *psz++;
118 chSlash = *psz;
119 *psz = '\0';
120
121 /*
122 * Does this part exist?
123 * If not we'll enumerate the directory and search for an case-insensitive match.
124 */
125 if (stat(pszFilename, &s))
126 {
127 struct dirent *pEntry;
128 DIR *pDir;
129 if (pszStart == pszFilename)
130 pDir = opendir(*pszFilename ? pszFilename : ".");
131 else
132 {
133 pszStart[-1] = '\0';
134 pDir = opendir(pszFilename);
135 pszStart[-1] = '/';
136 }
137 if (!pDir)
138 {
139 *psz = chSlash;
140 break; /* giving up, if we fail to open the directory. */
141 }
142
143 while ((pEntry = readdir(pDir)) != NULL)
144 {
145 if (!strcasecmp(pEntry->d_name, pszStart))
146 {
147 strcpy(pszStart, pEntry->d_name);
148 break;
149 }
150 }
151 closedir(pDir);
152 if (!pEntry)
153 {
154 *psz = chSlash;
155 break; /* giving up if not found. */
156 }
157 }
158
159 /* restore the slash and press on. */
160 *psz = chSlash;
161 while (*psz == '/')
162 psz++;
163 }
164
165 return;
166}
167
168#endif /* !OS/2 && !Windows */
169
170
171/**
172 * 'Optimizes' and corrects the dependencies.
173 */
174void depOptimize(int fFixCase)
175{
176 /*
177 * Walk the list correct the names and re-insert them.
178 */
179 PDEP pDepOrg = g_pDeps;
180 PDEP pDep = g_pDeps;
181 g_pDeps = NULL;
182 for (; pDep; pDep = pDep->pNext)
183 {
184#ifndef PATH_MAX
185 char szFilename[_MAX_PATH + 1];
186#else
187 char szFilename[PATH_MAX + 1];
188#endif
189 char *pszFilename;
190 struct stat s;
191
192 /*
193 * Skip some fictive names like <built-in> and <command line>.
194 */
195 if ( pDep->szFilename[0] == '<'
196 && pDep->szFilename[pDep->cchFilename - 1] == '>')
197 continue;
198 pszFilename = pDep->szFilename;
199
200#if K_OS != K_OS_OS2 && K_OS != K_OS_WINDOWS
201 /*
202 * Skip any drive letters from compilers running in wine.
203 */
204 if (pszFilename[1] == ':')
205 pszFilename += 2;
206#endif
207
208 /*
209 * The microsoft compilers are notoriously screwing up the casing.
210 * This will screw up kmk (/ GNU Make).
211 */
212 if (fFixCase)
213 {
214#if K_OS == K_OS_WINDOWS
215 nt_fullpath(pszFilename, szFilename, sizeof(szFilename));
216#else
217 strcpy(szFilename, pszFilename);
218 fixslash(szFilename);
219 fixcase(szFilename);
220#endif
221 pszFilename = szFilename;
222 }
223
224 /*
225 * Check that the file exists before we start depending on it.
226 */
227 if (stat(pszFilename, &s))
228 {
229 fprintf(stderr, "kDep: Skipping '%s' - %s!\n", pszFilename, strerror(errno));
230 continue;
231 }
232
233 /*
234 * Insert the corrected dependency.
235 */
236 depAdd(pszFilename, strlen(pszFilename));
237 }
238
239 /*
240 * Free the old ones.
241 */
242 while (pDepOrg)
243 {
244 pDep = pDepOrg;
245 pDepOrg = pDepOrg->pNext;
246 free(pDep);
247 }
248}
249
250
251/**
252 * Prints the dependency chain.
253 *
254 * @returns Pointer to the allocated dependency.
255 * @param pOutput Output stream.
256 */
257void depPrint(FILE *pOutput)
258{
259 PDEP pDep;
260 for (pDep = g_pDeps; pDep; pDep = pDep->pNext)
261 fprintf(pOutput, " \\\n\t%s", pDep->szFilename);
262 fprintf(pOutput, "\n\n");
263}
264
265
266/**
267 * Prints empty dependency stubs for all dependencies.
268 */
269void depPrintStubs(FILE *pOutput)
270{
271 PDEP pDep;
272 for (pDep = g_pDeps; pDep; pDep = pDep->pNext)
273 fprintf(pOutput, "%s:\n\n", pDep->szFilename);
274}
275
276
277/* sdbm:
278 This algorithm was created for sdbm (a public-domain reimplementation of
279 ndbm) database library. it was found to do well in scrambling bits,
280 causing better distribution of the keys and fewer splits. it also happens
281 to be a good general hashing function with good distribution. the actual
282 function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
283 is the faster version used in gawk. [there is even a faster, duff-device
284 version] the magic constant 65599 was picked out of thin air while
285 experimenting with different constants, and turns out to be a prime.
286 this is one of the algorithms used in berkeley db (see sleepycat) and
287 elsewhere. */
288static unsigned sdbm(const char *str)
289{
290 unsigned hash = 0;
291 int c;
292
293 while ((c = *(unsigned const char *)str++))
294 hash = c + (hash << 6) + (hash << 16) - hash;
295
296 return hash;
297}
298
299
300/**
301 * Adds a dependency.
302 *
303 * @returns Pointer to the allocated dependency.
304 * @param pszFilename The filename.
305 * @param cchFilename The length of the filename.
306 */
307PDEP depAdd(const char *pszFilename, size_t cchFilename)
308{
309 unsigned uHash = sdbm(pszFilename);
310 PDEP pDep;
311 PDEP pDepPrev;
312
313 /*
314 * Check if we've already got this one.
315 */
316 pDepPrev = NULL;
317 for (pDep = g_pDeps; pDep; pDepPrev = pDep, pDep = pDep->pNext)
318 if ( pDep->uHash == uHash
319 && pDep->cchFilename == cchFilename
320 && !memcmp(pDep->szFilename, pszFilename, cchFilename))
321 return pDep;
322
323 /*
324 * Add it.
325 */
326 pDep = (PDEP)malloc(sizeof(*pDep) + cchFilename);
327 if (!pDep)
328 {
329 fprintf(stderr, "\nOut of memory! (requested %#x bytes)\n\n", 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.

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