VirtualBox

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

Last change on this file since 2879 was 2851, checked in by bird, 9 years ago

updates

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