VirtualBox

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

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

Fixed regression.

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