VirtualBox

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

Last change on this file since 2278 was 2270, checked in by bird, 16 years ago

kDep.c: Fixed typo breaking with gcc 3.3.5 fprintf optimizations.

  • 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 2270 2009-01-26 00:01:01Z bird $ */
2/** @file
3 * kDep - Common Dependency Managemnt Code.
4 */
5
6/*
7 * Copyright (c) 2004-2009 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*x %04x:", off ? "\n" : "", sizeof(pb) * 2, offBase + off, off);
391 for (i = 0; i < cchWidth && off + i < cb ; i++)
392 printf(off + i < cb ? !(i & 7) && i ? "-%02x" : " %02x" : " ", pb[i]);
393
394 while (i++ < cchWidth)
395 printf(" ");
396 printf(" ");
397
398 for (i = 0; i < cchWidth && off + i < cb; i++)
399 {
400 const KU8 u8 = pb[i];
401 printf("%c", u8 < 127 && u8 >= 32 ? u8 : '.');
402 }
403 off += cchWidth;
404 pb += cchWidth;
405 }
406 printf("\n");
407}
408
409
410/**
411 * Reads the file specified by the pInput file stream into memory.
412 *
413 * @returns The address of the memory mapping on success. This must be
414 * freed by calling depFreeFileMemory.
415 *
416 * @param pInput The file stream to load or map into memory.
417 * @param pcbFile Where to return the mapping (file) size.
418 * @param ppvOpaque Opaque data when mapping, otherwise NULL.
419 */
420void *depReadFileIntoMemory(FILE *pInput, size_t *pcbFile, void **ppvOpaque)
421{
422 void *pvFile;
423 long cbFile;
424
425 /*
426 * Figure out file size.
427 */
428#if defined(_MSC_VER)
429 cbFile = _filelength(fileno(pInput));
430 if (cbFile < 0)
431#else
432 if ( fseek(pInput, 0, SEEK_END) < 0
433 || (cbFile = ftell(pInput)) < 0
434 || fseek(pInput, 0, SEEK_SET))
435#endif
436 {
437 fprintf(stderr, "kDep: error: Failed to determin file size.\n");
438 return NULL;
439 }
440 if (pcbFile)
441 *pcbFile = cbFile;
442
443 /*
444 * Try mmap first.
445 */
446#ifdef USE_WIN_MMAP
447 {
448 HANDLE hMapObj = CreateFileMapping((HANDLE)_get_osfhandle(fileno(pInput)),
449 NULL, PAGE_READONLY, 0, cbFile, NULL);
450 if (hMapObj != NULL)
451 {
452 pvFile = MapViewOfFile(hMapObj, FILE_MAP_READ, 0, 0, cbFile);
453 if (pvFile)
454 {
455 *ppvOpaque = hMapObj;
456 return pvFile;
457 }
458 fprintf(stderr, "kDep: warning: MapViewOfFile failed, %d.\n", GetLastError());
459 CloseHandle(hMapObj);
460 }
461 else
462 fprintf(stderr, "kDep: warning: CreateFileMapping failed, %d.\n", GetLastError());
463 }
464
465#endif
466
467 /*
468 * Allocate memory and read the file.
469 */
470 pvFile = malloc(cbFile + 1);
471 if (pvFile)
472 {
473 if (fread(pvFile, cbFile, 1, pInput))
474 {
475 ((KU8 *)pvFile)[cbFile] = '\0';
476 *ppvOpaque = NULL;
477 return pvFile;
478 }
479 fprintf(stderr, "kDep: error: Failed to read %ld bytes.\n", cbFile);
480 free(pvFile);
481 }
482 else
483 fprintf(stderr, "kDep: error: Failed to allocate %ld bytes (file mapping).\n", cbFile);
484 return NULL;
485}
486
487
488/**
489 * Free resources allocated by depReadFileIntoMemory.
490 *
491 * @param pvFile The address of the memory mapping.
492 * @param pvOpaque The opaque value returned together with the mapping.
493 */
494void depFreeFileMemory(void *pvFile, void *pvOpaque)
495{
496#if defined(USE_WIN_MMAP)
497 if (pvOpaque)
498 {
499 UnmapViewOfFile(pvFile);
500 CloseHandle(pvOpaque);
501 return;
502 }
503#endif
504 free(pvFile);
505}
506
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