VirtualBox

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

Last change on this file since 2439 was 2413, checked in by bird, 14 years ago

copyright year update.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.8 KB
Line 
1/* $Id: kDep.c 2413 2010-09-11 17:43:04Z bird $ */
2/** @file
3 * kDep - Common Dependency Managemnt Code.
4 */
5
6/*
7 * Copyright (c) 2004-2010 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#include "k/kTypes.h"
38#if K_OS == K_OS_WINDOWS
39# define USE_WIN_MMAP
40# include <io.h>
41# include <Windows.h>
42 extern void nt_fullpath(const char *pszPath, char *pszFull, size_t cchFull); /* nt_fullpath.c */
43#else
44# include <dirent.h>
45# include <unistd.h>
46# include <stdint.h>
47#endif
48
49#include "kDep.h"
50
51
52/*******************************************************************************
53* Global Variables *
54*******************************************************************************/
55/** List of dependencies. */
56static PDEP g_pDeps = NULL;
57
58
59/**
60 * Corrects all slashes to unix slashes.
61 *
62 * @returns pszFilename.
63 * @param pszFilename The filename to correct.
64 */
65static char *fixslash(char *pszFilename)
66{
67 char *psz = pszFilename;
68 while ((psz = strchr(psz, '\\')) != NULL)
69 *psz++ = '/';
70 return pszFilename;
71}
72
73
74#if K_OS == K_OS_OS2
75
76/**
77 * Corrects the case of a path.
78 *
79 * @param pszPath Pointer to the path, both input and output.
80 * The buffer must be able to hold one more byte than the string length.
81 */
82static void fixcase(char *pszFilename)
83{
84 return;
85}
86
87#elif K_OS != K_OS_WINDOWS
88
89/**
90 * Corrects the case of a path.
91 *
92 * @param pszPath Pointer to the path, both input and output.
93 */
94static void fixcase(char *pszFilename)
95{
96 char *psz;
97
98 /*
99 * Skip the root.
100 */
101 psz = pszFilename;
102 while (*psz == '/')
103 psz++;
104
105 /*
106 * Iterate all the components.
107 */
108 while (*psz)
109 {
110 char chSlash;
111 struct stat s;
112 char *pszStart = psz;
113
114 /*
115 * Find the next slash (or end of string) and terminate the string there.
116 */
117 while (*psz != '/' && *psz)
118 *psz++;
119 chSlash = *psz;
120 *psz = '\0';
121
122 /*
123 * Does this part exist?
124 * If not we'll enumerate the directory and search for an case-insensitive match.
125 */
126 if (stat(pszFilename, &s))
127 {
128 struct dirent *pEntry;
129 DIR *pDir;
130 if (pszStart == pszFilename)
131 pDir = opendir(*pszFilename ? pszFilename : ".");
132 else
133 {
134 pszStart[-1] = '\0';
135 pDir = opendir(pszFilename);
136 pszStart[-1] = '/';
137 }
138 if (!pDir)
139 {
140 *psz = chSlash;
141 break; /* giving up, if we fail to open the directory. */
142 }
143
144 while ((pEntry = readdir(pDir)) != NULL)
145 {
146 if (!strcasecmp(pEntry->d_name, pszStart))
147 {
148 strcpy(pszStart, pEntry->d_name);
149 break;
150 }
151 }
152 closedir(pDir);
153 if (!pEntry)
154 {
155 *psz = chSlash;
156 break; /* giving up if not found. */
157 }
158 }
159
160 /* restore the slash and press on. */
161 *psz = chSlash;
162 while (*psz == '/')
163 psz++;
164 }
165
166 return;
167}
168
169#endif /* !OS/2 && !Windows */
170
171
172/**
173 * 'Optimizes' and corrects the dependencies.
174 */
175void depOptimize(int fFixCase, int fQuiet)
176{
177 /*
178 * Walk the list correct the names and re-insert them.
179 */
180 PDEP pDepOrg = g_pDeps;
181 PDEP pDep = g_pDeps;
182 g_pDeps = NULL;
183 for (; pDep; pDep = pDep->pNext)
184 {
185#ifndef PATH_MAX
186 char szFilename[_MAX_PATH + 1];
187#else
188 char szFilename[PATH_MAX + 1];
189#endif
190 char *pszFilename;
191 struct stat s;
192
193 /*
194 * Skip some fictive names like <built-in> and <command line>.
195 */
196 if ( pDep->szFilename[0] == '<'
197 && pDep->szFilename[pDep->cchFilename - 1] == '>')
198 continue;
199 pszFilename = pDep->szFilename;
200
201#if K_OS != K_OS_OS2 && K_OS != K_OS_WINDOWS
202 /*
203 * Skip any drive letters from compilers running in wine.
204 */
205 if (pszFilename[1] == ':')
206 pszFilename += 2;
207#endif
208
209 /*
210 * The microsoft compilers are notoriously screwing up the casing.
211 * This will screw up kmk (/ GNU Make).
212 */
213 if (fFixCase)
214 {
215#if K_OS == K_OS_WINDOWS
216 nt_fullpath(pszFilename, szFilename, sizeof(szFilename));
217 fixslash(szFilename);
218#else
219 strcpy(szFilename, pszFilename);
220 fixslash(szFilename);
221 fixcase(szFilename);
222#endif
223 pszFilename = szFilename;
224 }
225
226 /*
227 * Check that the file exists before we start depending on it.
228 */
229 if (stat(pszFilename, &s))
230 {
231 if ( !fQuiet
232 || errno != ENOENT
233 || ( pszFilename[0] != '/'
234 && pszFilename[0] != '\\'
235 && ( !isalpha(pszFilename[0])
236 || pszFilename[1] != ':'
237 || ( pszFilename[2] != '/'
238 && pszFilename[2] != '\\')))
239 )
240 fprintf(stderr, "kDep: Skipping '%s' - %s!\n", pszFilename, strerror(errno));
241 continue;
242 }
243
244 /*
245 * Insert the corrected dependency.
246 */
247 depAdd(pszFilename, strlen(pszFilename));
248 }
249
250 /*
251 * Free the old ones.
252 */
253 while (pDepOrg)
254 {
255 pDep = pDepOrg;
256 pDepOrg = pDepOrg->pNext;
257 free(pDep);
258 }
259}
260
261
262/**
263 * Prints the dependency chain.
264 *
265 * @returns Pointer to the allocated dependency.
266 * @param pOutput Output stream.
267 */
268void depPrint(FILE *pOutput)
269{
270 PDEP pDep;
271 for (pDep = g_pDeps; pDep; pDep = pDep->pNext)
272 fprintf(pOutput, " \\\n\t%s", pDep->szFilename);
273 fprintf(pOutput, "\n\n");
274}
275
276
277/**
278 * Prints empty dependency stubs for all dependencies.
279 */
280void depPrintStubs(FILE *pOutput)
281{
282 PDEP pDep;
283 for (pDep = g_pDeps; pDep; pDep = pDep->pNext)
284 fprintf(pOutput, "%s:\n\n", pDep->szFilename);
285}
286
287
288/* sdbm:
289 This algorithm was created for sdbm (a public-domain reimplementation of
290 ndbm) database library. it was found to do well in scrambling bits,
291 causing better distribution of the keys and fewer splits. it also happens
292 to be a good general hashing function with good distribution. the actual
293 function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
294 is the faster version used in gawk. [there is even a faster, duff-device
295 version] the magic constant 65599 was picked out of thin air while
296 experimenting with different constants, and turns out to be a prime.
297 this is one of the algorithms used in berkeley db (see sleepycat) and
298 elsewhere. */
299static unsigned sdbm(const char *str, size_t size)
300{
301 unsigned hash = 0;
302 int c;
303
304 while (size-- > 0 && (c = *(unsigned const char *)str++))
305 hash = c + (hash << 6) + (hash << 16) - hash;
306
307 return hash;
308}
309
310
311/**
312 * Adds a dependency.
313 *
314 * @returns Pointer to the allocated dependency.
315 * @param pszFilename The filename. Does not need to be terminated.
316 * @param cchFilename The length of the filename.
317 */
318PDEP depAdd(const char *pszFilename, size_t cchFilename)
319{
320 unsigned uHash = sdbm(pszFilename, cchFilename);
321 PDEP pDep;
322 PDEP pDepPrev;
323
324 /*
325 * Check if we've already got this one.
326 */
327 pDepPrev = NULL;
328 for (pDep = g_pDeps; pDep; pDepPrev = pDep, pDep = pDep->pNext)
329 if ( pDep->uHash == uHash
330 && pDep->cchFilename == cchFilename
331 && !memcmp(pDep->szFilename, pszFilename, cchFilename))
332 return pDep;
333
334 /*
335 * Add it.
336 */
337 pDep = (PDEP)malloc(sizeof(*pDep) + cchFilename);
338 if (!pDep)
339 {
340 fprintf(stderr, "\nOut of memory! (requested %lx bytes)\n\n",
341 (unsigned long)(sizeof(*pDep) + cchFilename));
342 exit(1);
343 }
344
345 pDep->cchFilename = cchFilename;
346 memcpy(pDep->szFilename, pszFilename, cchFilename);
347 pDep->szFilename[cchFilename] = '\0';
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
379
380/**
381 * Performs a hexdump.
382 */
383void depHexDump(const KU8 *pb, size_t cb, size_t offBase)
384{
385 const unsigned cchWidth = 16;
386 size_t off = 0;
387 while (off < cb)
388 {
389 unsigned i;
390 printf("%s%0*lx %04lx:", off ? "\n" : "", (int)sizeof(pb) * 2,
391 (unsigned long)offBase + (unsigned long)off, (unsigned long)off);
392 for (i = 0; i < cchWidth && off + i < cb ; i++)
393 printf(off + i < cb ? !(i & 7) && i ? "-%02x" : " %02x" : " ", pb[i]);
394
395 while (i++ < cchWidth)
396 printf(" ");
397 printf(" ");
398
399 for (i = 0; i < cchWidth && off + i < cb; i++)
400 {
401 const KU8 u8 = pb[i];
402 printf("%c", u8 < 127 && u8 >= 32 ? u8 : '.');
403 }
404 off += cchWidth;
405 pb += cchWidth;
406 }
407 printf("\n");
408}
409
410
411/**
412 * Reads the file specified by the pInput file stream into memory.
413 *
414 * @returns The address of the memory mapping on success. This must be
415 * freed by calling depFreeFileMemory.
416 *
417 * @param pInput The file stream to load or map into memory.
418 * @param pcbFile Where to return the mapping (file) size.
419 * @param ppvOpaque Opaque data when mapping, otherwise NULL.
420 */
421void *depReadFileIntoMemory(FILE *pInput, size_t *pcbFile, void **ppvOpaque)
422{
423 void *pvFile;
424 long cbFile;
425
426 /*
427 * Figure out file size.
428 */
429#if defined(_MSC_VER)
430 cbFile = _filelength(fileno(pInput));
431 if (cbFile < 0)
432#else
433 if ( fseek(pInput, 0, SEEK_END) < 0
434 || (cbFile = ftell(pInput)) < 0
435 || fseek(pInput, 0, SEEK_SET))
436#endif
437 {
438 fprintf(stderr, "kDep: error: Failed to determin file size.\n");
439 return NULL;
440 }
441 if (pcbFile)
442 *pcbFile = cbFile;
443
444 /*
445 * Try mmap first.
446 */
447#ifdef USE_WIN_MMAP
448 {
449 HANDLE hMapObj = CreateFileMapping((HANDLE)_get_osfhandle(fileno(pInput)),
450 NULL, PAGE_READONLY, 0, cbFile, NULL);
451 if (hMapObj != NULL)
452 {
453 pvFile = MapViewOfFile(hMapObj, FILE_MAP_READ, 0, 0, cbFile);
454 if (pvFile)
455 {
456 *ppvOpaque = hMapObj;
457 return pvFile;
458 }
459 fprintf(stderr, "kDep: warning: MapViewOfFile failed, %d.\n", GetLastError());
460 CloseHandle(hMapObj);
461 }
462 else
463 fprintf(stderr, "kDep: warning: CreateFileMapping failed, %d.\n", GetLastError());
464 }
465
466#endif
467
468 /*
469 * Allocate memory and read the file.
470 */
471 pvFile = malloc(cbFile + 1);
472 if (pvFile)
473 {
474 if (fread(pvFile, cbFile, 1, pInput))
475 {
476 ((KU8 *)pvFile)[cbFile] = '\0';
477 *ppvOpaque = NULL;
478 return pvFile;
479 }
480 fprintf(stderr, "kDep: error: Failed to read %ld bytes.\n", cbFile);
481 free(pvFile);
482 }
483 else
484 fprintf(stderr, "kDep: error: Failed to allocate %ld bytes (file mapping).\n", cbFile);
485 return NULL;
486}
487
488
489/**
490 * Free resources allocated by depReadFileIntoMemory.
491 *
492 * @param pvFile The address of the memory mapping.
493 * @param pvOpaque The opaque value returned together with the mapping.
494 */
495void depFreeFileMemory(void *pvFile, void *pvOpaque)
496{
497#if defined(USE_WIN_MMAP)
498 if (pvOpaque)
499 {
500 UnmapViewOfFile(pvFile);
501 CloseHandle(pvOpaque);
502 return;
503 }
504#endif
505 free(pvFile);
506}
507
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