VirtualBox

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

Last change on this file since 3107 was 3105, checked in by bird, 8 years ago

hurd workaround

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