VirtualBox

source: kBuild/trunk/src/kmk/kdepdb.c@ 2337

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

kdepdb.c: code in progress.

  • Property svn:eol-style set to native
File size: 20.7 KB
Line 
1/* $Id: incdep.c 2283 2009-02-24 04:54:00Z bird $ */
2/** @file
3 * kdepdb - Dependency database.
4 */
5
6/*
7 * Copyright (c) 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 "make.h"
30#include "../lib/k/kDefs.h"
31#include "../lib/k/kTypes.h"
32#include <assert.h>
33#include <glob.h>
34
35#include "dep.h"
36#include "filedef.h"
37#include "job.h"
38#include "commands.h"
39#include "variable.h"
40#include "rule.h"
41#include "debug.h"
42#include "strcache2.h"
43
44#ifdef HAVE_FCNTL_H
45# include <fcntl.h>
46#else
47# include <sys/file.h>
48#endif
49
50#ifdef WINDOWS32
51# include <io.h>
52# include <process.h>
53# include <Windows.h>
54# define PARSE_IN_WORKER
55#endif
56
57/*******************************************************************************
58* Defined Constants And Macros *
59*******************************************************************************/
60/** @def KDEPDB_ASSERT_SIZE
61 * Check the size of an on-disk type.
62 *
63 * @param Type The type which size it being checked.
64 * @param Size The size it should have.
65 */
66#ifdef __GNUC__
67# define KDEPDB_ASSERT_SIZE(Type, Size) \
68 extern int kDepDbAssertSize[1] __attribute__((unused)), \
69 kDepDbAssertSize[sizeof(Type) == (Size)] __attribute__((unused))
70#else
71# define KDEPDB_ASSERT_SIZE(Type, Size) \
72 typedef int kDepDbAssertSize[sizeof(Type) == (Size)]
73#endif
74KDEPDB_ASSERT_SIZE(KU8, 1);
75KDEPDB_ASSERT_SIZE(KU16, 2);
76KDEPDB_ASSERT_SIZE(KU32, 4);
77KDEPDB_ASSERT_SIZE(KU64, 8);
78
79
80/*******************************************************************************
81* Structures and Typedefs *
82*******************************************************************************/
83/**
84 * File header.
85 *
86 * @remarks All on-disk formats are in little-endian format.
87 */
88typedef struct KDEPDBHDR
89{
90 /** The file magic. */
91 KU8 szMagic[8];
92 /** The major file format version. */
93 KU8 uVerMajor;
94 /** The minor file format version. */
95 KU8 uVerMinor;
96 /** Reserved \#2. */
97 KU16 uReserved2;
98 /** Reserved \#1. */
99 KU32 uReserved1;
100 /** The internal name of this file. */
101 KU8 szName[16];
102} KDEPDBHDR;
103KDEPDB_ASSERT_SIZE(KDEPDBHDR, 32);
104
105/** The file header magic value. */
106#define KDEPDBHDR_MAGIC "kDepDb\0"
107/** The current major file format version number. */
108#define KDEPDBHDR_VERSION_MAJOR 0
109/** The current minor file format version number.
110 * Numbers above 240 indicate unsupported development variants. */
111#define KDEPDBHDR_VERSION_MINOR 240
112
113
114/**
115 * Hash table file.
116 *
117 * The hash table is recreated in a new file when we have to grow it.
118 */
119typedef struct KDEPDBHASH
120{
121 /** The file header. */
122 KDEPDBHDR Hdr;
123 /** The number of hash table entries. */
124 KU32 cEntries;
125 /** The number of hash table entries with content. */
126 KU32 cUsedEntries;
127 /** The number of collisions on insert. */
128 KU32 cCollisions;
129 /** Reserved member \#5. */
130 KU32 uReserved5;
131 /** Reserved member \#4. */
132 KU32 uReserved4;
133 /** Reserved member \#3. */
134 KU32 uReserved3;
135 /** Reserved member \#2. */
136 KU32 uReserved2;
137 /** Reserved member \#1. */
138 KU32 uReserved1;
139 /** The hash table. */
140 KU32 auEntries[32];
141} KDEPDBHASH;
142KDEPDB_ASSERT_SIZE(KDEPDBHASH, 32+32+4*32);
143
144/** The item value indicating that it is unused. */
145#define KDEPDBHASH_UNUSED KU32_C(0xffffffff)
146/** The item indicating that it hash been deleted. */
147#define KDEPDBHASH_DELETED KU32_C(0xfffffffe)
148/** The first special item value. */
149#define KDEPDBHASH_END KU32_C(0xfffffff0)
150
151
152/**
153 * A string table string entry.
154 *
155 * This should be a multiple of 32 bytes.
156 */
157typedef struct KDEPDBSTRING
158{
159 /** The hash number for the string. */
160 KU32 uHash;
161 /** The string length, excluding the zero terminator. */
162 KU32 cchString;
163 /** The string. */
164 KU8 szString[24];
165} KDEPDBSTRING;
166KDEPDB_ASSERT_SIZE(KDEPDBSTRING, 32);
167
168
169/**
170 * String table file.
171 *
172 * The file is insertion only and will grow forever.
173 */
174typedef struct KDEPDBSTRTAB
175{
176 /** The file header. */
177 KDEPDBHDR Hdr;
178 /** The end of the valid string table indexes. */
179 KU32 iStringEnd;
180 /** Reserved member \#7. */
181 KU32 uReserved7;
182 /** Reserved member \#6. */
183 KU32 uReserved6;
184 /** Reserved member \#5. */
185 KU32 uReserved5;
186 /** Reserved member \#4. */
187 KU32 uReserved4;
188 /** Reserved member \#3. */
189 KU32 uReserved3;
190 /** Reserved member \#2. */
191 KU32 uReserved2;
192 /** Reserved member \#1. */
193 KU32 uReserved1;
194 /** The string table. */
195 KDEPDBSTRING aStrings[1];
196} KDEPDBSTRTAB;
197KDEPDB_ASSERT_SIZE(KDEPDBSTRTAB, 32+32+32);
198
199/** The end of the valid string table indexes (exclusive). */
200#define KDEPDBG_STRTAB_IDX_END KU32_C(0x80000000)
201/** The string was not found. */
202#define KDEPDBG_STRTAB_IDX_NOT_FOUND KU32_C(0xfffffffd)
203/** Error during string table operation. */
204#define KDEPDBG_STRTAB_IDX_ERROR KU32_C(0xfffffffe)
205/** Generic invalid string table index. */
206#define KDEPDBG_STRTAB_IDX_INVALID KU32_C(0xffffffff)
207
208
209/**
210 * Directory entry.
211 */
212typedef struct KDEPDBDIRENTRY
213{
214 /** The string table index of the entry name.
215 * Unused entries are set to KDEPDBG_STRTAB_IDX_INVALID. */
216 KU32 iName;
217 /** The actual data stream size.
218 * Unused entries are set to KU32_MAX. */
219 KU32 cbData;
220 /** The number of blocks allocated for this stream.
221 * Unused entries are set to KU32_MAX. */
222 KU32 cBlocks;
223 /** The start block number.
224 * The stream is a contiguous sequence of blocks. This optimizes and
225 * simplifies reading the stream at the expense of operations extending it.
226 *
227 * In unused entries, this serves as the free chain pointer with KU32_MAX as
228 * nil value. */
229 KU32 iStartBlock;
230} KDEPDBDIRENTRY;
231KDEPDB_ASSERT_SIZE(KDEPDBDIRENTRY, 16);
232
233/**
234 * Directory file.
235 */
236typedef struct KDEPDBDIR
237{
238 /** The file header. */
239 KDEPDBHDR Hdr;
240 /** The number of entries. */
241 KU32 cEntries;
242 /** The head of the free chain. (Index into aEntries.) */
243 KU32 iFreeHead;
244 /** Reserved member \#6. */
245 KU32 uReserved6;
246 /** Reserved member \#5. */
247 KU32 uReserved5;
248 /** Reserved member \#4. */
249 KU32 uReserved4;
250 /** Reserved member \#3. */
251 KU32 uReserved3;
252 /** Reserved member \#2. */
253 KU32 uReserved2;
254 /** Reserved member \#1. */
255 KU32 uReserved1;
256 /** Directory entries. */
257 KDEPDBDIRENTRY aEntries[2];
258} KDEPDBDIR;
259KDEPDB_ASSERT_SIZE(KDEPDBDIR, 32+32+32);
260
261
262/**
263 * A block allocation bitmap.
264 *
265 * This can track 2^(12+8) = 2^20 = 1M blocks.
266 */
267typedef struct KDEPDBDATABITMAP
268{
269 /** Bitmap where each bit is a block.
270 * 0 indicates unused blocks and 1 indicates used ones. */
271 KU8 bm[4096];
272} KDEPDBDATABITMAP;
273KDEPDB_ASSERT_SIZE(KDEPDBDATABITMAP, 4096);
274
275/**
276 * Data file.
277 *
278 * The block numbering starts with this structure as block 0.
279 */
280typedef struct KDEPDBDATA
281{
282 /** The file header. */
283 KDEPDBHDR Hdr;
284 /** The size of a block. */
285 KU32 cbBlock;
286 /** Reserved member \#7. */
287 KU32 uReserved7;
288 /** Reserved member \#6. */
289 KU32 uReserved6;
290 /** Reserved member \#5. */
291 KU32 uReserved5;
292 /** Reserved member \#4. */
293 KU32 uReserved4;
294 /** Reserved member \#3. */
295 KU32 uReserved3;
296 /** Reserved member \#2. */
297 KU32 uReserved2;
298 /** Reserved member \#1. */
299 KU32 uReserved1;
300
301 /** Block numbers for the allocation bitmaps. */
302 KU32 aiBitmaps[4096];
303} KDEPDBDATA;
304
305/** The end of the valid block indexes (exclusive). */
306#define KDEPDB_BLOCK_IDX_END KU32_C(0xfffffff0)
307/** The index of an unallocated bitmap block. */
308#define KDEPDB_BLOCK_IDX_UNALLOCATED KU32_C(0xffffffff)
309
310
311/**
312 * Stream storing dependencies.
313 *
314 * The stream name gives the output file name, so all that we need is the list
315 * of files it depends on. These are serialized as a list of string table
316 * indexes.
317 */
318typedef struct KDEPDBDEPSTREAM
319{
320 /** String table indexes for the dependencies. */
321 KU32 aiDeps[1];
322} KDEPDBDEPSTREAM;
323
324
325/**
326 * A file handle structure.
327 */
328typedef struct KDEPDBFH
329{
330#if K_OS == K_OS_WINDOWS
331 /** The file handle. */
332 HANDLE hFile;
333 /** The mapping object handle. */
334 HANDLE hMapObj;
335#else
336 /** The file handle. */
337 int fd;
338#endif
339 /** The current file size. */
340 KU32 cb;
341} KDEPDBFH;
342
343
344/**
345 * Internal control structure for a string table.
346 */
347typedef struct KDEPDBINTSTRTAB
348{
349 /** The hash file. */
350 KDEPDBHASH *pHash;
351 /** The handle of the hash file. */
352 KDEPDBFH hHash;
353 /** The string table file. */
354 KDEPDBSTRTAB *pStrTab;
355 /** The end of the allocated string table indexes (i.e. when to grow the
356 * file). */
357 KU32 iStringAlloced;
358 /** The handle of the string table file. */
359 KDEPDBFH hStrTab;
360} KDEPDBINTSTRTAB;
361
362
363/**
364 * Internal control structure for a data set.
365 *
366 * This governs the directory file, the directory hash file and the data file.
367 */
368typedef struct KDEPDBINTDATASET
369{
370 /** The hash file. */
371 KDEPDBHASH pHash;
372 /** The size of the hash file. */
373 KU32 cbHash;
374 /** The size of the directory file. */
375 KU32 cbDir;
376 /** The mapping of the directory file. */
377 KDEPDBHASH pDir;
378 /** The data file. */
379 KDEPDBDATA pData;
380 /** The size of the data file. */
381 KU32 cbData;
382 /** The handle of the hash file. */
383 KDEPDBFH hHash;
384 /** The handle of the directory file. */
385 KDEPDBFH hDir;
386 /** The handle of the data file. */
387 KDEPDBFH hData;
388} KDEPDBINTDATASET;
389
390
391/**
392 * The database instance.
393 *
394 * To simplifiy things the database uses 8 files for storing the different kinds
395 * of data. This greatly reduces the complexity compared to a single file
396 * solution.
397 */
398typedef struct KDEPDB
399{
400 /** The string table. */
401 KDEPDBINTSTRTAB StrTab;
402 /** The variable data set. */
403 KDEPDBINTDATASET DepSet;
404 /** The command data set. */
405 KDEPDBINTDATASET CmdSet;
406} KDEPDB;
407
408
409/*******************************************************************************
410* Internal Functions *
411*******************************************************************************/
412static void *kDepDbAlloc(KSIZE cb);
413static void kDepDbFree(void *pv);
414static int kDepDbFHOpen(KDEPDBFH *pFH, const char *pszFilename);
415static int kDepDbFHClose(KDEPDBFH *pFH);
416static int kDepDbFHWriteAt(KDEPDBFH *pFH, KU32 off, void const *pvBuf, KSIZE cbBuf);
417static int kDepDbFHMap(KDEPDBFH *pFH, void **ppvMap);
418static int kDepDbFHUnmap(KDEPDBFH *pFH, void **ppvMap);
419static int kDepDbFHGrow(KDEPDBFH *pFH, KSIZE cbNew, void **ppvMap);
420static KU32 kDepDbHashString(const char *pszString, size_t cchString);
421
422
423/** xmalloc wrapper. */
424static void *kDepDbAlloc(KSIZE cb)
425{
426 return xmalloc(cb);
427}
428
429
430/** free wrapper. */
431static void kDepDbFree(void *pv)
432{
433 if (pv)
434 free(pv);
435}
436
437
438
439/***
440 * Looks up a string in the string table.
441 *
442 * @returns The string table index.
443 * @retval KDEPDBG_STRTAB_IDX_NOT_FOUND is not found.
444 * @retval KDEPDBG_STRTAB_IDX_ERROR on internal inconsistency.
445 *
446 * @param pStrTab The string table.
447 * @param pszString The string.
448 * @param cchStringIn The string length.
449 * @param uHash The hash of the string.
450 */
451static KU32 kDepDbStrTabLookupHashed(KDEPDBINTSTRTAB const *pStrTab, const char *pszString, size_t cchStringIn, KU32 uHash)
452{
453 KU32 const cchString = (KU32)cchStringIn;
454 KDEPDBHASH const *pHash = pStrTab->pHash;
455 KDEPDBSTRING const *paStrings = &pStrTab->pStrTab->aStrings[0];
456 KU32 const iStringEnd = pStrTab->pStrTab->iStringEnd;
457 KU32 iHash;
458
459 /* sanity */
460 if (cchString != cchStringIn)
461 return KDEPDBG_STRTAB_IDX_NOT_FOUND;
462
463 /*
464 * Hash lookup of the string.
465 */
466 iHash = uHash % pHash->cEntries;
467 for (;;)
468 {
469 KU32 iString = pHash->auEntries[iHash];
470 if (iString < iStringEnd)
471 {
472 KDEPDBSTRING const *pString = &paStrings[iString];
473 if ( pString->uHash == uHash
474 && pString->cchString == cchString
475 && !memcmp(pString->szString, pszString, cchString))
476 return iString;
477 }
478 else if (iString == KDEPDBHASH_UNUSED)
479 return KDEPDBG_STRTAB_IDX_NOT_FOUND;
480 else if (iString != KDEPDBHASH_DELETED)
481 return KDEPDBG_STRTAB_IDX_ERROR;
482
483 /* advance */
484 iHash = (iHash + 1) % pHash->cEntries;
485 }
486}
487
488
489/**
490 * Doubles the hash table size and rehashes it.
491 *
492 * @returns 0 on success, -1 on failure.
493 * @param pStrTab The string table.
494 */
495static int kDepDbStrTabReHash(KDEPDBINTSTRTAB *pStrTab)
496{
497 KDEPDBSTRING const *paStrings = &pStrTab->pStrTab->aStrings[0];
498 KU32 const iStringEnd = pStrTab->pStrTab->iStringEnd;
499 KDEPDBHASH *pHash = pStrTab->pHash;
500 KDEPDBHASH HashHdr = *pHash;
501 KU32 *pauNew;
502 KU32 cEntriesNew;
503 KU32 i;
504
505 /*
506 * Calc the size of the new hash table.
507 */
508 if (pHash->cEntries >= KU32_C(0x80000000))
509 return -1;
510 cEntriesNew = 1024;
511 while (cEntriesNew <= pHash->cEntries)
512 cEntriesNew <<= 1;
513
514 /*
515 * Allocate and initialize an empty hash table in memory.
516 */
517 pauNew = kDepDbAlloc(cEntriesNew * sizeof(KU32));
518 if (!pauNew)
519 return -1;
520 i = cEntriesNew;
521 while (i-- > 0)
522 pauNew[i] = KDEPDBHASH_UNUSED;
523
524 /*
525 * Popuplate the new table.
526 */
527 HashHdr.cEntries = cEntriesNew;
528 HashHdr.cCollisions = 0;
529 HashHdr.cUsedEntries = 0;
530 i = pHash->cEntries;
531 while (i-- > 0)
532 {
533 KU32 iString = pHash->auEntries[i];
534 if (iString < iStringEnd)
535 {
536 KU32 iHash = (paStrings[iString].uHash % cEntriesNew);
537 if (pauNew[iHash] != KDEPDBHASH_UNUSED)
538 {
539 do
540 {
541 iHash = (iHash + 1) % cEntriesNew;
542 HashHdr.cCollisions++;
543 } while (pauNew[iHash] != KDEPDBHASH_UNUSED);
544 }
545 pauNew[iHash] = iString;
546 HashHdr.cEntries++;
547 }
548 else if ( iString != KDEPDBHASH_UNUSED
549 && iString != KDEPDBHASH_DELETED)
550 {
551 /* ignore any invalid entires for now */;
552 }
553 }
554
555 /*
556 * Unmap the hash, write the new hash table and map it again.
557 */
558 if (!kDepDbFHUnmap(&pStrTab->hHash, (void **)&pStrTab->pHash))
559 {
560 if ( !kDepDbFHWriteAt(&pStrTab->hHash, 0, &HashHdr, K_OFFSETOF(KDEPDBHASH, auEntries))
561 && !kDepDbFHWriteAt(&pStrTab->hHash, K_OFFSETOF(KDEPDBHASH, auEntries), pauNew, sizeof(pauNew[0]) * cEntriesNew))
562 {
563 kDepDbFree(pauNew);
564 pauNew = NULL;
565 if (!kDepDbFHMap(&pStrTab->hHash, (void **)&pStrTab->pHash))
566 return 0;
567 }
568 else
569 kDepDbFHWriteAt(&pStrTab->hHash, 0, "\0\0\0\0", 4); /* file is screwed, trash the magic. */
570 }
571
572 kDepDbFree(pauNew);
573 return -1;
574}
575
576
577/**
578 * Add a string to the string table.
579 *
580 * If already in the table, the index of the existing entry is returned.
581 *
582 * @returns String index on success,
583 * @retval KDEPDBG_STRTAB_IDX_ERROR on I/O and inconsistency errors.
584 *
585 * @param pStrTab The string table.
586 * @param pszString The string to add.
587 * @param cchStringIn The length of the string.
588 * @param uHash The hash of the string.
589 */
590static KU32 kDepDbStrTabAddHashed(KDEPDBINTSTRTAB *pStrTab, const char *pszString, size_t cchStringIn, KU32 uHash)
591{
592 KU32 const cchString = (KU32)cchStringIn;
593 KDEPDBHASH *pHash = pStrTab->pHash;
594 KDEPDBSTRING *paStrings = &pStrTab->pStrTab->aStrings[0];
595 KU32 const iStringEnd = pStrTab->pStrTab->iStringEnd;
596 KU32 iInsertAt = KDEPDBHASH_UNUSED;
597 KU32 cCollisions = 0;
598 KU32 iHash;
599 KU32 iString;
600 KU32 cEntries;
601 KDEPDBSTRING *pNewString;
602
603 /* sanity */
604 if (cchString != cchStringIn)
605 return KDEPDBG_STRTAB_IDX_NOT_FOUND;
606
607 /*
608 * Hash lookup of the string.
609 */
610 iHash = uHash % pHash->cEntries;
611 for (;;)
612 {
613 iString = pHash->auEntries[iHash];
614 if (iString < iStringEnd)
615 {
616 KDEPDBSTRING const *pString = &paStrings[iString];
617 if ( pString->uHash == uHash
618 && pString->cchString == cchString
619 && !memcmp(pString->szString, pszString, cchString))
620 return iString;
621 }
622 else
623 {
624 if (iInsertAt == KDEPDBHASH_UNUSED)
625 iInsertAt = iHash;
626 if (iString == KDEPDBHASH_UNUSED)
627 break;
628 if (iString != KDEPDBHASH_DELETED)
629 return KDEPDBG_STRTAB_IDX_ERROR;
630 }
631
632 /* advance */
633 cCollisions++;
634 iHash = (iHash + 1) % pHash->cEntries;
635 }
636
637 /*
638 * Add string to the string table.
639 * The string table file is grown in 256KB increments and ensuring at least 64KB unused new space.
640 */
641 cEntries = cchString + 1 <= sizeof(paStrings[0].szString)
642 ? 1
643 : (cchString + 1 - sizeof(paStrings[0].szString) + sizeof(KDEPDBSTRING) - 1) / sizeof(KDEPDBSTRING);
644 if (iStringEnd + cEntries > pStrTab->iStringAlloced)
645 {
646 KSIZE cbNewSize = K_ALIGN_Z((iStringEnd + cEntries) * sizeof(KDEPDBSTRING) + 64*1024, 256*1024);
647 if (kDepDbFHGrow(&pStrTab->hStrTab, cbNewSize, (void **)&pStrTab->pStrTab) != 0)
648 return KDEPDBG_STRTAB_IDX_ERROR;
649
650 pStrTab->iStringAlloced = (cbNewSize - K_OFFSETOF(KDEPDBSTRTAB, aStrings)) / sizeof(KDEPDBSTRING);
651 paStrings = &pStrTab->pStrTab->aStrings[0];
652 }
653 pNewString = &paStrings[iStringEnd];
654 pNewString->uHash = uHash;
655 pNewString->cchString = cchString;
656 memcpy(&pNewString->szString, pszString, cchString);
657 pNewString->szString[cchString] = '\0';
658
659 pStrTab->pStrTab->iStringEnd = iStringEnd + cEntries;
660
661 /*
662 * Insert hash table entry, rehash it if necessary.
663 */
664 pHash->auEntries[iInsertAt] = iStringEnd;
665 pHash->cUsedEntries++;
666 pHash->cCollisions += cCollisions;
667 if ( pHash->cUsedEntries > pHash->cEntries / 3 * 2
668 && kDepDbStrTabReHash(pStrTab) != 0)
669 return KDEPDBG_STRTAB_IDX_ERROR;
670
671 return iStringEnd;
672}
673
674
675/** Wrapper for kDepDbStrTabLookupHashed. */
676static KU32 kDepDbStrTabLookupN(KDEPDBINTSTRTAB const *pStrTab, const char *pszString, size_t cchString)
677{
678 return kDepDbStrTabLookupHashed(pStrTab, pszString, cchString, kDepDbHashString(pszString, cchString));
679}
680
681
682/** Wrapper for kDepDbStrTabAddHashed. */
683static KU32 kDepDbStrTabAddN(KDEPDBINTSTRTAB *pStrTab, const char *pszString, size_t cchString)
684{
685 return kDepDbStrTabAddHashed(pStrTab, pszString, cchString, kDepDbHashString(pszString, cchString));
686}
687
688
689/** Wrapper for kDepDbStrTabLookupHashed. */
690static KU32 kDepDbStrTabLookup(KDEPDBINTSTRTAB const *pStrTab, const char *pszString)
691{
692 return kDepDbStrTabLookupN(pStrTab, pszString, strlen(pszString));
693}
694
695
696/** Wrapper for kDepDbStrTabAddHashed. */
697static KU32 kDepDbStrTabAdd(KDEPDBINTSTRTAB *pStrTab, const char *pszString)
698{
699 return kDepDbStrTabAddN(pStrTab, pszString, strlen(pszString));
700}
701
702
703
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