VirtualBox

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

Last change on this file since 1165 was 1165, checked in by bird, 18 years ago

Optimized kDebIDB a bit for Windows; use nt_fullpath and map the IDB file into memory.

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