*: Updated copyright to 2009 and normalized name & email.
[kbuild-mirror.git] / src / lib / kDep.c
blob08270236881cf73791081bdc89dab26da283ecba
1 /* $Id$ */
2 /** @file
3 * kDep - Common Dependency Managemnt Code.
4 */
6 /*
7 * Copyright (c) 2004-2009 knut st. osmundsen <bird-kBuild-spamix@anduin.net>
9 * This file is part of kBuild.
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.
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.
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/>
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 #if K_OS == K_OS_WINDOWS
38 # include <windows.h>
39 extern void nt_fullpath(const char *pszPath, char *pszFull, size_t cchFull); /* nt_fullpath.c */
40 #else
41 # include <dirent.h>
42 # include <unistd.h>
43 # include <stdint.h>
44 #endif
46 #include "kDep.h"
49 /*******************************************************************************
50 * Global Variables *
51 *******************************************************************************/
52 /** List of dependencies. */
53 static PDEP g_pDeps = NULL;
56 /**
57 * Corrects all slashes to unix slashes.
59 * @returns pszFilename.
60 * @param pszFilename The filename to correct.
62 static char *fixslash(char *pszFilename)
64 char *psz = pszFilename;
65 while ((psz = strchr(psz, '\\')) != NULL)
66 *psz++ = '/';
67 return pszFilename;
71 #if K_OS == K_OS_OS2
73 /**
74 * Corrects the case of a path.
76 * @param pszPath Pointer to the path, both input and output.
77 * The buffer must be able to hold one more byte than the string length.
79 static void fixcase(char *pszFilename)
81 return;
84 #elif K_OS != K_OS_WINDOWS
86 /**
87 * Corrects the case of a path.
89 * @param pszPath Pointer to the path, both input and output.
91 static void fixcase(char *pszFilename)
93 char *psz;
96 * Skip the root.
98 psz = pszFilename;
99 while (*psz == '/')
100 psz++;
103 * Iterate all the components.
105 while (*psz)
107 char chSlash;
108 struct stat s;
109 char *pszStart = psz;
112 * Find the next slash (or end of string) and terminate the string there.
114 while (*psz != '/' && *psz)
115 *psz++;
116 chSlash = *psz;
117 *psz = '\0';
120 * Does this part exist?
121 * If not we'll enumerate the directory and search for an case-insensitive match.
123 if (stat(pszFilename, &s))
125 struct dirent *pEntry;
126 DIR *pDir;
127 if (pszStart == pszFilename)
128 pDir = opendir(*pszFilename ? pszFilename : ".");
129 else
131 pszStart[-1] = '\0';
132 pDir = opendir(pszFilename);
133 pszStart[-1] = '/';
135 if (!pDir)
137 *psz = chSlash;
138 break; /* giving up, if we fail to open the directory. */
141 while ((pEntry = readdir(pDir)) != NULL)
143 if (!strcasecmp(pEntry->d_name, pszStart))
145 strcpy(pszStart, pEntry->d_name);
146 break;
149 closedir(pDir);
150 if (!pEntry)
152 *psz = chSlash;
153 break; /* giving up if not found. */
157 /* restore the slash and press on. */
158 *psz = chSlash;
159 while (*psz == '/')
160 psz++;
163 return;
166 #endif /* !OS/2 && !Windows */
170 * 'Optimizes' and corrects the dependencies.
172 void depOptimize(int fFixCase, int fQuiet)
175 * Walk the list correct the names and re-insert them.
177 PDEP pDepOrg = g_pDeps;
178 PDEP pDep = g_pDeps;
179 g_pDeps = NULL;
180 for (; pDep; pDep = pDep->pNext)
182 #ifndef PATH_MAX
183 char szFilename[_MAX_PATH + 1];
184 #else
185 char szFilename[PATH_MAX + 1];
186 #endif
187 char *pszFilename;
188 struct stat s;
191 * Skip some fictive names like <built-in> and <command line>.
193 if ( pDep->szFilename[0] == '<'
194 && pDep->szFilename[pDep->cchFilename - 1] == '>')
195 continue;
196 pszFilename = pDep->szFilename;
198 #if K_OS != K_OS_OS2 && K_OS != K_OS_WINDOWS
200 * Skip any drive letters from compilers running in wine.
202 if (pszFilename[1] == ':')
203 pszFilename += 2;
204 #endif
207 * The microsoft compilers are notoriously screwing up the casing.
208 * This will screw up kmk (/ GNU Make).
210 if (fFixCase)
212 #if K_OS == K_OS_WINDOWS
213 nt_fullpath(pszFilename, szFilename, sizeof(szFilename));
214 fixslash(szFilename);
215 #else
216 strcpy(szFilename, pszFilename);
217 fixslash(szFilename);
218 fixcase(szFilename);
219 #endif
220 pszFilename = szFilename;
224 * Check that the file exists before we start depending on it.
226 if (stat(pszFilename, &s))
228 if ( !fQuiet
229 || errno != ENOENT
230 || ( pszFilename[0] != '/'
231 && pszFilename[0] != '\\'
232 && ( !isalpha(pszFilename[0])
233 || pszFilename[1] != ':'
234 || ( pszFilename[2] != '/'
235 && pszFilename[2] != '\\')))
237 fprintf(stderr, "kDep: Skipping '%s' - %s!\n", pszFilename, strerror(errno));
238 continue;
242 * Insert the corrected dependency.
244 depAdd(pszFilename, strlen(pszFilename));
248 * Free the old ones.
250 while (pDepOrg)
252 pDep = pDepOrg;
253 pDepOrg = pDepOrg->pNext;
254 free(pDep);
260 * Prints the dependency chain.
262 * @returns Pointer to the allocated dependency.
263 * @param pOutput Output stream.
265 void depPrint(FILE *pOutput)
267 PDEP pDep;
268 for (pDep = g_pDeps; pDep; pDep = pDep->pNext)
269 fprintf(pOutput, " \\\n\t%s", pDep->szFilename);
270 fprintf(pOutput, "\n\n");
275 * Prints empty dependency stubs for all dependencies.
277 void depPrintStubs(FILE *pOutput)
279 PDEP pDep;
280 for (pDep = g_pDeps; pDep; pDep = pDep->pNext)
281 fprintf(pOutput, "%s:\n\n", pDep->szFilename);
285 /* sdbm:
286 This algorithm was created for sdbm (a public-domain reimplementation of
287 ndbm) database library. it was found to do well in scrambling bits,
288 causing better distribution of the keys and fewer splits. it also happens
289 to be a good general hashing function with good distribution. the actual
290 function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
291 is the faster version used in gawk. [there is even a faster, duff-device
292 version] the magic constant 65599 was picked out of thin air while
293 experimenting with different constants, and turns out to be a prime.
294 this is one of the algorithms used in berkeley db (see sleepycat) and
295 elsewhere. */
296 static unsigned sdbm(const char *str)
298 unsigned hash = 0;
299 int c;
301 while ((c = *(unsigned const char *)str++))
302 hash = c + (hash << 6) + (hash << 16) - hash;
304 return hash;
309 * Adds a dependency.
311 * @returns Pointer to the allocated dependency.
312 * @param pszFilename The filename.
313 * @param cchFilename The length of the filename.
315 PDEP depAdd(const char *pszFilename, size_t cchFilename)
317 unsigned uHash = sdbm(pszFilename);
318 PDEP pDep;
319 PDEP pDepPrev;
322 * Check if we've already got this one.
324 pDepPrev = NULL;
325 for (pDep = g_pDeps; pDep; pDepPrev = pDep, pDep = pDep->pNext)
326 if ( pDep->uHash == uHash
327 && pDep->cchFilename == cchFilename
328 && !memcmp(pDep->szFilename, pszFilename, cchFilename))
329 return pDep;
332 * Add it.
334 pDep = (PDEP)malloc(sizeof(*pDep) + cchFilename);
335 if (!pDep)
337 fprintf(stderr, "\nOut of memory! (requested %lx bytes)\n\n",
338 (unsigned long)(sizeof(*pDep) + cchFilename));
339 exit(1);
342 pDep->cchFilename = cchFilename;
343 memcpy(pDep->szFilename, pszFilename, cchFilename + 1);
344 pDep->uHash = uHash;
346 if (pDepPrev)
348 pDep->pNext = pDepPrev->pNext;
349 pDepPrev->pNext = pDep;
351 else
353 pDep->pNext = g_pDeps;
354 g_pDeps = pDep;
356 return pDep;
361 * Frees the current dependency chain.
363 void depCleanup(void)
365 PDEP pDep = g_pDeps;
366 g_pDeps = NULL;
367 while (pDep)
369 PDEP pFree = pDep;
370 pDep = pDep->pNext;
371 free(pFree);