VirtualBox

source: kBuild/trunk/src/kmk/kbuild-object.c@ 3387

Last change on this file since 3387 was 3141, checked in by bird, 6 years ago

kmk: linux merge fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 50.1 KB
Line 
1/* $Id: kbuild-object.c 3141 2018-03-14 21:58:32Z bird $ */
2/** @file
3 * kBuild objects.
4 */
5
6/*
7 * Copyright (c) 2011-2014 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
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/* No GNU coding style here! */
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include "makeint.h"
32#include "filedef.h"
33#include "variable.h"
34#include "dep.h"
35#include "debug.h"
36#include "kbuild.h"
37
38#include <assert.h>
39#include <stdarg.h>
40
41
42/*******************************************************************************
43* Defined Constants And Macros *
44*******************************************************************************/
45#define WORD_IS(a_pszWord, a_cchWord, a_szWord2) \
46 ( (a_cchWord) == sizeof(a_szWord2) - 1 && memcmp((a_pszWord), a_szWord2, sizeof(a_szWord2) - 1) == 0)
47
48
49/*******************************************************************************
50* Structures and Typedefs *
51*******************************************************************************/
52/** kBuild object type. */
53enum kBuildType
54{
55 kBuildType_Invalid,
56 kBuildType_Target,
57 kBuildType_Template,
58 kBuildType_Tool,
59 kBuildType_Sdk,
60 kBuildType_Unit
61};
62
63enum kBuildSeverity
64{
65 kBuildSeverity_Warning,
66 kBuildSeverity_Error,
67 kBuildSeverity_Fatal
68};
69
70
71/**
72 * kBuild object data.
73 */
74struct kbuild_object
75{
76 /** The object type. */
77 enum kBuildType enmType;
78 /** Object name length. */
79 size_t cchName;
80 /** The bare name of the define. */
81 char *pszName;
82 /** The file location where this define was declared. */
83 floc FileLoc;
84
85 /** Pointer to the next element in the global list. */
86 struct kbuild_object *pGlobalNext;
87
88 /** The variable set associated with this define. */
89 struct variable_set_list *pVariables;
90
91 /** The parent name, NULL if none. */
92 char *pszParent;
93 /** The length of the parent name. */
94 size_t cchParent;
95 /** Pointer to the parent. Resolved lazily, so it can be NULL even if we
96 * have a parent. */
97 struct kbuild_object *pParent;
98
99 /** The template, NULL if none. Only applicable to targets. Only covers the
100 * primary template, not target or type specific templates.
101 * @todo not sure if this is really necessary. */
102 char const *pszTemplate;
103
104 /** The variable prefix. */
105 char *pszVarPrefix;
106 /** The length of the variable prefix. */
107 size_t cchVarPrefix;
108};
109
110
111/**
112 * The data we stack during eval.
113 */
114struct kbuild_eval_data
115{
116 /** Pointer to the element below us on the stack. */
117 struct kbuild_eval_data *pStackDown;
118 /** Pointer to the object. */
119 struct kbuild_object *pObj;
120 /** The saved current variable set, for restoring in kBuild-endef. */
121 struct variable_set_list *pVariablesSaved;
122};
123
124
125
126/*******************************************************************************
127* Global Variables *
128*******************************************************************************/
129/** Linked list (LIFO) of kBuild defines.
130 * @todo use a hash! */
131static struct kbuild_object *g_pHeadKbObjs = NULL;
132/** Stack of kBuild evalutation contexts.
133 * This is for dealing with potential recursive kBuild object definition,
134 * generally believed to only happen via $(eval ) or include similar. */
135struct kbuild_eval_data *g_pTopKbEvalData = NULL;
136
137/** Cached variable name '_TEMPLATE'. */
138static const char *g_pszVarNmTemplate = NULL;
139
140/** Zero if compatibility mode is disabled, non-zero if enabled.
141 * If explicitily enabled, the value will be greater than 1. */
142int g_fKbObjCompMode = 1;
143
144
145/*******************************************************************************
146* Internal Functions *
147*******************************************************************************/
148static struct kbuild_object *
149resolve_kbuild_object_parent(struct kbuild_object *pObj, int fQuiet);
150static struct kbuild_object *
151get_kbuild_object_parent(struct kbuild_object *pObj, enum kBuildSeverity enmSeverity);
152
153static struct kbuild_object *
154parse_kbuild_object_variable_accessor(const char *pchExpr, size_t cchExpr,
155 enum kBuildSeverity enmSeverity, const floc *pFileLoc,
156 const char **ppchVarNm, size_t *pcchVarNm, enum kBuildType *penmType);
157
158
159/**
160 * Initializes the kBuild object stuff.
161 *
162 * Requires the variable_cache to be initialized.
163 */
164void init_kbuild_object(void)
165{
166 g_pszVarNmTemplate = strcache2_add(&variable_strcache, STRING_SIZE_TUPLE("_TEMPLATE"));
167}
168
169
170/**
171 * Reports a problem with dynamic severity level.
172 *
173 * @param enmSeverity The severity level.
174 * @param pFileLoc The file location.
175 * @param pszFormat The format string.
176 * @param ... Arguments for the format string.
177 */
178static void kbuild_report_problem(enum kBuildSeverity enmSeverity, const floc *pFileLoc,
179 const char *pszFormat, ...)
180{
181 char szBuf[8192];
182 va_list va;
183
184 va_start(va, pszFormat);
185#ifdef _MSC_VER
186 _vsnprintf(szBuf, sizeof(szBuf), pszFormat, va);
187#else
188 vsnprintf(szBuf, sizeof(szBuf), pszFormat, va);
189#endif
190 va_end(va);
191
192 switch (enmSeverity)
193 {
194 case kBuildSeverity_Warning:
195 OS(message, 0, "%s", szBuf);
196 break;
197 case kBuildSeverity_Error:
198 OS(error, pFileLoc, "%s", szBuf);
199 break;
200 default:
201 case kBuildSeverity_Fatal:
202 OS(fatal, pFileLoc, "%s", szBuf);
203 break;
204 }
205}
206
207
208static const char *
209eval_kbuild_type_to_string(enum kBuildType enmType)
210{
211 switch (enmType)
212 {
213 case kBuildType_Target: return "target";
214 case kBuildType_Template: return "template";
215 case kBuildType_Tool: return "tool";
216 case kBuildType_Sdk: return "sdk";
217 case kBuildType_Unit: return "unit";
218 default:
219 case kBuildType_Invalid: return "invalid";
220 }
221}
222
223/**
224 * Gets the length of the string representation of the given type.
225 *
226 * @returns The string length.
227 * @param enmType The kBuild object type in question.
228 */
229static unsigned
230eval_kbuild_type_to_string_length(enum kBuildType enmType)
231{
232 switch (enmType)
233 {
234 case kBuildType_Target: return sizeof("target") - 1;
235 case kBuildType_Template: return sizeof("template") - 1;
236 case kBuildType_Tool: return sizeof("tool") - 1;
237 case kBuildType_Sdk: return sizeof("sdk") - 1;
238 case kBuildType_Unit: return sizeof("unit") - 1;
239 default:
240 case kBuildType_Invalid: return sizeof("invalid") - 1;
241 }
242}
243
244/**
245 * Converts a string into an kBuild object type.
246 *
247 * @returns The type on success, kBuildType_Invalid on failure.
248 * @param pchWord The pchWord. Not necessarily zero terminated.
249 * @param cchWord The length of the word.
250 */
251static enum kBuildType
252eval_kbuild_type_from_string(const char *pchWord, size_t cchWord)
253{
254 if (cchWord >= 3)
255 {
256 if (*pchWord == 't')
257 {
258 if (WORD_IS(pchWord, cchWord, "target"))
259 return kBuildType_Target;
260 if (WORD_IS(pchWord, cchWord, "template"))
261 return kBuildType_Template;
262 if (WORD_IS(pchWord, cchWord, "tool"))
263 return kBuildType_Tool;
264 }
265 else
266 {
267 if (WORD_IS(pchWord, cchWord, "sdk"))
268 return kBuildType_Sdk;
269 if (WORD_IS(pchWord, cchWord, "unit"))
270 return kBuildType_Unit;
271 }
272 }
273
274 return kBuildType_Invalid;
275}
276
277
278
279#if 0 /* unused */
280/**
281 * Helper function for caching variable name strings.
282 *
283 * @returns The string cache variable name.
284 * @param pszName The variable name.
285 * @param ppszCache Cache variable, static or global. Initialize to
286 * NULL.
287 */
288static const char *
289kbuild_variable_name(const char *pszName, const char **ppszCache)
290{
291 const char *pszRet = *ppszCache;
292 if (!pszRet)
293 *ppszCache = pszRet = strcache2_add(&variable_strcache, pszName, strlen(pszName));
294 return pszRet;
295}
296#endif
297
298static struct kbuild_object *
299lookup_kbuild_object(enum kBuildType enmType, const char *pchName, size_t cchName)
300{
301 /* Linear lookup for now. */
302 struct kbuild_object *pCur = g_pHeadKbObjs;
303 while (pCur)
304 {
305 if ( pCur->enmType == enmType
306 && pCur->cchName == cchName
307 && !memcmp(pCur->pszName, pchName, cchName))
308 return pCur;
309 pCur = pCur->pGlobalNext;
310 }
311 return NULL;
312}
313
314
315/** @name Defining and modifying variables
316 * @{
317 */
318
319/**
320 * Checks if the variable name is valid.
321 *
322 * @returns 1 if valid, 0 if not.
323 * @param pchName The variable name.
324 * @param cchName The length of the variable name.
325 */
326static int
327is_valid_kbuild_object_variable_name(const char *pchName, size_t cchName)
328{
329 if (cchName > 0)
330 {
331 if (!memchr(pchName, '[', cchName))
332 {
333 /** @todo more? */
334 return 1;
335 }
336 }
337 return 0;
338}
339
340static const char *
341kbuild_replace_special_accessors(const char *pchValue, size_t *pcchValue, int *pfDuplicateValue,
342 const floc *pFileLoc)
343{
344 size_t cchValue = *pcchValue;
345 size_t cbAllocated = *pfDuplicateValue ? 0 : cchValue + 1;
346
347 /*
348 * Loop thru each potential special accessor occurance in the string.
349 *
350 * Unfortunately, we don't have a strnstr function in the C library, so
351 * we'll using memchr and doing a few more rounds in this loop.
352 */
353 size_t cchLeft = cchValue;
354 char *pchLeft = (char *)pchValue;
355 for (;;)
356 {
357 int fSuper;
358 char *pch = (char *)memchr(pchLeft, '$', cchLeft);
359 if (!pch)
360 break;
361
362 pch++;
363 cchLeft -= pch - pchLeft;
364 pchLeft = pch;
365
366 /* [@self] is the shorter, quit if there isn't enough room for even it. */
367 if (cchLeft < sizeof("([@self]") - 1)
368 break;
369
370 /* We don't care how many dollars there are in front of a special accessor. */
371 if (*pchLeft == '$')
372 {
373 do
374 {
375 cchLeft--;
376 pchLeft++;
377 } while (cchLeft >= sizeof("([@self]") - 1 && *pchLeft == '$');
378 if (cchLeft < sizeof("([@self]") - 1)
379 break;
380 }
381
382 /* Is it a special accessor? */
383 if ( pchLeft[2] != '@'
384 || pchLeft[1] != '['
385 || pchLeft[0] != '(')
386 continue;
387 pchLeft += 2;
388 cchLeft -= 2;
389 if (!memcmp(pchLeft, STRING_SIZE_TUPLE("@self]")))
390 fSuper = 0;
391 else if ( cchLeft >= sizeof("@super]")
392 && !memcmp(pchLeft, STRING_SIZE_TUPLE("@super]")))
393 fSuper = 1;
394 else
395 continue;
396
397 /*
398 * We've got something to replace. First figure what with and then
399 * resize the value buffer.
400 */
401 if (g_pTopKbEvalData)
402 {
403 struct kbuild_object *pObj = g_pTopKbEvalData->pObj;
404 size_t const cchSpecial = fSuper ? sizeof("@super") - 1 : sizeof("@self") - 1;
405 size_t cchName;
406 size_t cchType;
407 long cchDelta;
408 const char *pszName;
409
410 if (fSuper)
411 {
412 pObj = get_kbuild_object_parent(pObj, kBuildSeverity_Error);
413 if (!pObj)
414 continue;
415 }
416 pszName = pObj->pszName;
417 cchName = pObj->cchName;
418 cchType = eval_kbuild_type_to_string_length(pObj->enmType);
419 cchDelta = cchType + 1 + cchName - cchSpecial;
420
421 if (cchValue + cchDelta >= cbAllocated)
422 {
423 size_t offLeft = pchLeft - pchValue;
424 char *pszNewValue;
425
426 cbAllocated = cchValue + cchDelta + 1;
427 if (cchValue < 1024)
428 cbAllocated = (cbAllocated + 31) & ~(size_t)31;
429 else
430 cbAllocated = (cbAllocated + 255) & ~(size_t)255;
431 pszNewValue = (char *)xmalloc(cbAllocated);
432
433 memcpy(pszNewValue, pchValue, offLeft);
434 memcpy(pszNewValue + offLeft + cchSpecial + cchDelta,
435 pchLeft + cchSpecial,
436 cchLeft - cchSpecial + 1);
437
438 if (*pfDuplicateValue == 0)
439 free((char *)pchValue);
440 else
441 *pfDuplicateValue = 0;
442
443 pchValue = pszNewValue;
444 pchLeft = pszNewValue + offLeft;
445 }
446 else
447 {
448 assert(*pfDuplicateValue == 0);
449 memmove(pchLeft + cchSpecial + cchDelta,
450 pchLeft + cchSpecial,
451 cchLeft - cchSpecial + 1);
452 }
453
454 cchLeft += cchDelta;
455 cchValue += cchDelta;
456 *pcchValue = cchValue;
457
458 memcpy(pchLeft, eval_kbuild_type_to_string(pObj->enmType), cchType);
459 pchLeft += cchType;
460 *pchLeft++ = '@';
461 memcpy(pchLeft, pszName, cchName);
462 pchLeft += cchName;
463 cchLeft -= cchType + 1 + cchName;
464 }
465 else
466 error(pFileLoc, 20, _("The '$([%.*s...' accessor can only be used in the context of a kBuild object"),
467 (int)MIN(cchLeft, 20), pchLeft);
468 }
469
470 return pchValue;
471}
472
473static struct variable *
474define_kbuild_object_variable_cached(struct kbuild_object *pObj, const char *pszName,
475 const char *pchValue, size_t cchValue,
476 int fDuplicateValue, enum variable_origin enmOrigin,
477 int fRecursive, int fNoSpecialAccessors, const floc *pFileLoc)
478{
479 struct variable *pVar;
480 size_t cchName = strcache2_get_len(&variable_strcache, pszName);
481
482 if (fRecursive && !fNoSpecialAccessors)
483 pchValue = kbuild_replace_special_accessors(pchValue, &cchValue, &fDuplicateValue, pFileLoc);
484
485 pVar = define_variable_in_set(pszName, cchName,
486 pchValue, cchValue, fDuplicateValue,
487 enmOrigin, fRecursive,
488 pObj->pVariables->set,
489 pFileLoc);
490
491 /* Single underscore prefixed variables gets a global alias. */
492 if ( pszName[0] == '_'
493 && pszName[1] != '_'
494 && g_fKbObjCompMode)
495 {
496 struct variable *pAlias;
497 size_t cchPrefixed = pObj->cchVarPrefix + cchName;
498 char *pszPrefixed = xmalloc(cchPrefixed + 1);
499 memcpy(pszPrefixed, pObj->pszVarPrefix, pObj->cchVarPrefix);
500 memcpy(&pszPrefixed[pObj->cchVarPrefix], pszName, cchName);
501 pszPrefixed[cchPrefixed] = '\0';
502
503 pAlias = define_variable_alias_in_set(pszPrefixed, cchPrefixed, pVar, enmOrigin,
504 &global_variable_set, pFileLoc);
505 if (!pAlias->alias)
506 OS(error, pFileLoc, _("Error defining alias '%s'"), pszPrefixed);
507 }
508
509 return pVar;
510}
511
512#if 0
513struct variable *
514define_kbuild_object_variable(struct kbuild_object *pObj, const char *pchName, size_t cchName,
515 const char *pchValue, size_t cchValue,
516 int fDuplicateValue, enum variable_origin enmOrigin,
517 int fRecursive, const floc *pFileLoc)
518{
519 return define_kbuild_object_variable_cached(pObj, strcache2_add(&variable_strcache, pchName, cchName),
520 pchValue, cchValue,
521 fDuplicateValue, enmOrigin,
522 fRecursive, pFileLoc);
523}
524#endif
525
526/**
527 * Try define a kBuild object variable via a possible accessor
528 * ([type@object]var).
529 *
530 * @returns Pointer to the defined variable on success.
531 * @retval VAR_NOT_KBUILD_ACCESSOR if it isn't an accessor.
532 *
533 * @param pchName The variable name, not cached.
534 * @param cchName The variable name length. This will not be ~0U.
535 * @param pszValue The variable value. If @a fDuplicateValue is clear,
536 * this should be assigned as the actual variable
537 * value, otherwise it will be duplicated. In the
538 * latter case it might not be properly null
539 * terminated.
540 * @param cchValue The value length.
541 * @param fDuplicateValue Whether @a pszValue need to be duplicated on the
542 * heap or is already there.
543 * @param enmOrigin The variable origin.
544 * @param fRecursive Whether it's a recursive variable.
545 * @param pFileLoc The location of the variable definition.
546 */
547struct variable *
548try_define_kbuild_object_variable_via_accessor(const char *pchName, size_t cchName,
549 const char *pszValue, size_t cchValue, int fDuplicateValue,
550 enum variable_origin enmOrigin, int fRecursive,
551 floc const *pFileLoc)
552{
553 struct kbuild_object *pObj;
554 const char *pchVarNm;
555 size_t cchVarNm;
556
557 pObj = parse_kbuild_object_variable_accessor(pchName, cchName, kBuildSeverity_Fatal, pFileLoc,
558 &pchVarNm, &cchVarNm, NULL);
559 if (pObj != KOBJ_NOT_KBUILD_ACCESSOR)
560 {
561 assert(pObj != NULL);
562 if (!is_valid_kbuild_object_variable_name(pchVarNm, cchVarNm))
563 fatal(pFileLoc, cchVarNm + cchName, _("Invalid kBuild object variable name: '%.*s' ('%.*s')"),
564 (int)cchVarNm, pchVarNm, (int)cchName, pchName);
565 return define_kbuild_object_variable_cached(pObj, strcache2_add(&variable_strcache, pchVarNm, cchVarNm),
566 pszValue, cchValue, fDuplicateValue, enmOrigin, fRecursive,
567 0 /*fNoSpecialAccessors*/, pFileLoc);
568 }
569
570 return VAR_NOT_KBUILD_ACCESSOR;
571}
572
573/**
574 * Define a kBuild object variable in the topmost kBuild object.
575 *
576 * This won't be an variable accessor.
577 *
578 * @returns Pointer to the defined variable on success.
579 *
580 * @param pchName The variable name, not cached.
581 * @param cchName The variable name length. This will not be ~0U.
582 * @param pszValue The variable value. If @a fDuplicateValue is clear,
583 * this should be assigned as the actual variable
584 * value, otherwise it will be duplicated. In the
585 * latter case it might not be properly null
586 * terminated.
587 * @param cchValue The value length.
588 * @param fDuplicateValue Whether @a pszValue need to be duplicated on the
589 * heap or is already there.
590 * @param enmOrigin The variable origin.
591 * @param fRecursive Whether it's a recursive variable.
592 * @param pFileLoc The location of the variable definition.
593 */
594struct variable *
595define_kbuild_object_variable_in_top_obj(const char *pchName, size_t cchName,
596 const char *pszValue, size_t cchValue, int fDuplicateValue,
597 enum variable_origin enmOrigin, int fRecursive,
598 floc const *pFileLoc)
599{
600 assert(g_pTopKbEvalData != NULL);
601
602 if (!is_valid_kbuild_object_variable_name(pchName, cchName))
603 fatal(pFileLoc, cchName, _("Invalid kBuild object variable name: '%.*s'"), (int)cchName, pchName);
604
605 return define_kbuild_object_variable_cached(g_pTopKbEvalData->pObj, strcache2_add(&variable_strcache, pchName, cchName),
606 pszValue, cchValue, fDuplicateValue, enmOrigin, fRecursive,
607 0 /*fNoSpecialAccessors*/, pFileLoc);
608}
609
610/**
611 * Implements appending and prepending to a kBuild object variable.
612 *
613 * The variable is either accessed thru an accessor or by the topmost kBuild
614 * object.
615 *
616 * @returns Pointer to the defined variable on success.
617 *
618 * @param pchName The variable name, not cached.
619 * @param cchName The variable name length. This will not be ~0U.
620 * @param pszValue The variable value. Must be duplicated.
621 * @param cchValue The value length.
622 * @param fSimpleValue Whether we've already figured that it's a simple
623 * value. This is for optimizing appending/prepending
624 * to an existing simple value variable.
625 * @param enmOrigin The variable origin.
626 * @param fAppend Append if set, prepend if clear.
627 * @param pFileLoc The location of the variable definition.
628 */
629struct variable *
630kbuild_object_variable_pre_append(const char *pchName, size_t cchName,
631 const char *pchValue, size_t cchValue, int fSimpleValue,
632 enum variable_origin enmOrigin, int fAppend,
633 const floc *pFileLoc)
634{
635 struct kbuild_object *pObj;
636 struct variable VarKey;
637
638 /*
639 * Resolve the relevant kBuild object first.
640 */
641 if (cchName > 3 && pchName[0] == '[')
642 {
643 const char *pchVarNm;
644 size_t cchVarNm;
645 pObj = parse_kbuild_object_variable_accessor(pchName, cchName, kBuildSeverity_Fatal, pFileLoc,
646 &pchVarNm, &cchVarNm, NULL);
647 if (pObj != KOBJ_NOT_KBUILD_ACCESSOR)
648 {
649 pchName = pchVarNm;
650 cchName = cchVarNm;
651 }
652 else
653 pObj = g_pTopKbEvalData->pObj;
654 }
655 else
656 pObj = g_pTopKbEvalData->pObj;
657
658 /*
659 * Make sure the variable name is valid. Raise fatal error if not.
660 */
661 if (!is_valid_kbuild_object_variable_name(pchName, cchName))
662 fatal(pFileLoc, cchName, _("Invalid kBuild object variable name: '%.*s'"), (int)cchName, pchName);
663
664 /*
665 * Get the cached name and look it up in the object's variables.
666 */
667 VarKey.name = strcache2_lookup(&variable_strcache, pchName, cchName);
668 if (VarKey.name)
669 {
670 struct variable *pVar;
671
672 VarKey.length = cchName;
673 pVar = (struct variable *)hash_find_item_strcached(&pObj->pVariables->set->table, &VarKey);
674 if (pVar)
675 {
676 /* Append/prepend to existing variable. */
677 int fDuplicateValue = 1;
678 if (pVar->recursive && !fSimpleValue)
679 pchValue = kbuild_replace_special_accessors(pchValue, &cchValue, &fDuplicateValue, pFileLoc);
680
681 pVar = do_variable_definition_append(pFileLoc, pVar, pchValue, cchValue, fSimpleValue, enmOrigin, fAppend);
682
683 if (fDuplicateValue == 0)
684 free((char *)pchValue);
685 return pVar;
686 }
687
688 /*
689 * Not found. Check ancestors if the 'override' directive isn't applied.
690 */
691 if (pObj->pszParent && enmOrigin != o_override)
692 {
693 struct kbuild_object *pParent = pObj;
694 for (;;)
695 {
696 pParent = resolve_kbuild_object_parent(pParent, 0 /*fQuiet*/);
697 if (!pParent)
698 break;
699
700 pVar = (struct variable *)hash_find_item_strcached(&pParent->pVariables->set->table, &VarKey);
701 if (pVar)
702 {
703 if (pVar->value_length != ~0U)
704 assert(pVar->value_length == strlen(pVar->value));
705 else
706 pVar->value_length = strlen(pVar->value);
707
708 /*
709 * Combine the two values and define the variable in the
710 * specified child object. We must disregard 'origin' a
711 * little here, so we must do the gritty stuff our selves.
712 */
713 if ( pVar->recursive
714 || fSimpleValue
715 || !cchValue
716 || memchr(pchValue, '$', cchValue) == NULL )
717 {
718 int fDuplicateValue = 1;
719 size_t cchNewValue;
720 char *pszNewValue;
721 char *pszTmp;
722
723 /* Just join up the two values. */
724 if (pVar->recursive && !fSimpleValue)
725 pchValue = kbuild_replace_special_accessors(pchValue, &cchValue, &fDuplicateValue, pFileLoc);
726 if (pVar->value_length == 0)
727 {
728 cchNewValue = cchValue;
729 pszNewValue = xstrndup(pchValue, cchValue);
730 }
731 else if (!cchValue)
732 {
733 cchNewValue = pVar->value_length;
734 pszNewValue = xmalloc(cchNewValue + 1);
735 memcpy(pszNewValue, pVar->value, cchNewValue + 1);
736 }
737 else
738 {
739 cchNewValue = pVar->value_length + 1 + cchValue;
740 pszNewValue = xmalloc(cchNewValue + 1);
741 if (fAppend)
742 {
743 memcpy(pszNewValue, pVar->value, pVar->value_length);
744 pszTmp = pszNewValue + pVar->value_length;
745 *pszTmp++ = ' ';
746 memcpy(pszTmp, pchValue, cchValue);
747 pszTmp[cchValue] = '\0';
748 }
749 else
750 {
751 memcpy(pszNewValue, pchValue, cchValue);
752 pszTmp = pszNewValue + cchValue;
753 *pszTmp++ = ' ';
754 memcpy(pszNewValue, pVar->value, pVar->value_length);
755 pszTmp[pVar->value_length] = '\0';
756 }
757 }
758
759 /* Define the new variable in the child. */
760 pVar = define_kbuild_object_variable_cached(pObj, VarKey.name,
761 pszNewValue, cchNewValue, 0 /*fDuplicateValue*/,
762 enmOrigin, pVar->recursive, 1 /*fNoSpecialAccessors*/,
763 pFileLoc);
764 if (fDuplicateValue == 0)
765 free((char *)pchValue);
766 }
767 else
768 {
769 /* Lazy bird: Copy the variable from the ancestor and
770 then do a normal append/prepend on it. */
771 pVar = define_kbuild_object_variable_cached(pObj, VarKey.name,
772 pVar->value, pVar->value_length, 1 /*fDuplicateValue*/,
773 enmOrigin, pVar->recursive, 1 /*fNoSpecialAccessors*/,
774 pFileLoc);
775 append_expanded_string_to_variable(pVar, pchValue, cchValue, fAppend);
776 }
777 return pVar;
778 }
779 }
780 }
781 }
782 else
783 VarKey.name = strcache2_add(&variable_strcache, pchName, cchName);
784
785 /* Variable not found. */
786 return define_kbuild_object_variable_cached(pObj, VarKey.name,
787 pchValue, cchValue, 1 /*fDuplicateValue*/, enmOrigin,
788 1 /*fRecursive */, 0 /*fNoSpecialAccessors*/, pFileLoc);
789}
790
791/** @} */
792
793
794static char *
795allocate_expanded_next_token(const char **ppszCursor, const char *pszEos, size_t *pcchToken, int fStrip)
796{
797 unsigned int cchToken;
798 char *pszToken = find_next_token_eos(ppszCursor, pszEos, &cchToken);
799 if (pszToken)
800 {
801 pszToken = allocated_variable_expand_2(pszToken, cchToken, &cchToken);
802 if (pszToken)
803 {
804 if (fStrip)
805 {
806 unsigned int off = 0;
807 while (MY_IS_BLANK(pszToken[off]))
808 off++;
809 if (off)
810 {
811 cchToken -= off;
812 memmove(pszToken, &pszToken[off], cchToken + 1);
813 }
814
815 while (cchToken > 0 && MY_IS_BLANK(pszToken[cchToken - 1]))
816 pszToken[--cchToken] = '\0';
817 }
818
819 assert(cchToken == strlen(pszToken));
820 if (pcchToken)
821 *pcchToken = cchToken;
822 return pszToken;
823 }
824 }
825
826 if (pcchToken)
827 *pcchToken = 0;
828 return NULL;
829}
830
831static struct kbuild_object *
832resolve_kbuild_object_parent(struct kbuild_object *pObj, int fQuiet)
833{
834 if ( !pObj->pParent
835 && pObj->pszParent)
836 {
837 struct kbuild_object *pCur = g_pHeadKbObjs;
838 while (pCur)
839 {
840 if ( pCur->enmType == pObj->enmType
841 && !strcmp(pCur->pszName, pObj->pszParent))
842 {
843 if ( pCur->pszParent
844 && ( pCur->pParent == pObj
845 || !strcmp(pCur->pszParent, pObj->pszName)) )
846 OSS(fatal, &pObj->FileLoc, _("'%s' and '%s' are both trying to be each other children..."),
847 pObj->pszName, pCur->pszName);
848
849 pObj->pParent = pCur;
850 pObj->pVariables->next = pObj->pVariables;
851 return pCur;
852 }
853
854 pCur = pCur->pGlobalNext;
855 }
856
857 /* Not found. */
858 if (!fQuiet)
859 OSS(error, &pObj->FileLoc, _("Could not locate parent '%s' of '%s'"), pObj->pszParent, pObj->pszName);
860 }
861 return pObj->pParent;
862}
863
864/**
865 * Get the parent of the given object, it is expected to have one.
866 *
867 * @returns Pointer to the parent. NULL if we survive failure.
868 * @param pObj The kBuild object.
869 * @param enmSeverity The severity of a missing parent.
870 */
871static struct kbuild_object *
872get_kbuild_object_parent(struct kbuild_object *pObj, enum kBuildSeverity enmSeverity)
873{
874 struct kbuild_object *pParent = pObj->pParent;
875 if (pParent)
876 return pParent;
877
878 pParent = resolve_kbuild_object_parent(pObj, 1 /*fQuiet - complain below */);
879 if (pParent)
880 return pParent;
881
882 if (pObj->pszParent)
883 kbuild_report_problem(enmSeverity, &pObj->FileLoc,
884 _("Could not local parent '%s' for kBuild object '%s'"),
885 pObj->pszParent, pObj->pszName);
886 else
887 kbuild_report_problem(enmSeverity, &pObj->FileLoc,
888 _("kBuild object '%s' has no parent ([@super])"),
889 pObj->pszName);
890 return NULL;
891}
892
893static int
894eval_kbuild_define_xxxx(struct kbuild_eval_data **ppData, const floc *pFileLoc,
895 const char *pszLine, const char *pszEos, int fIgnoring, enum kBuildType enmType)
896{
897 unsigned int cch;
898 char ch;
899 char *psz;
900 const char *pszPrefix;
901 struct kbuild_object *pObj;
902 struct kbuild_eval_data *pData;
903
904 if (fIgnoring)
905 return 0;
906
907 /*
908 * Create a new kBuild object.
909 */
910 pObj = xmalloc(sizeof(*pObj));
911 pObj->enmType = enmType;
912 pObj->pszName = NULL;
913 pObj->cchName = 0;
914 pObj->FileLoc = *pFileLoc;
915
916 pObj->pGlobalNext = g_pHeadKbObjs;
917 g_pHeadKbObjs = pObj;
918
919 pObj->pVariables = create_new_variable_set();
920
921 pObj->pszParent = NULL;
922 pObj->cchParent = 0;
923 pObj->pParent = NULL;
924
925 pObj->pszTemplate = NULL;
926
927 pObj->pszVarPrefix = NULL;
928 pObj->cchVarPrefix = 0;
929
930 /*
931 * The first word is the name.
932 */
933 pObj->pszName = allocate_expanded_next_token(&pszLine, pszEos, &pObj->cchName, 1 /*strip*/);
934 if (!pObj->pszName || !*pObj->pszName)
935 O(fatal, pFileLoc, _("The kBuild define requires a name"));
936
937 psz = pObj->pszName;
938 while ((ch = *psz++) != '\0')
939 if (!isgraph(ch))
940 {
941 OSS(error, pFileLoc, _("The 'kBuild-define-%s' name '%s' contains one or more invalid characters"),
942 eval_kbuild_type_to_string(enmType), pObj->pszName);
943 break;
944 }
945
946 /*
947 * Calc the variable prefix.
948 */
949 switch (enmType)
950 {
951 case kBuildType_Target: pszPrefix = ""; break;
952 case kBuildType_Template: pszPrefix = "TEMPLATE_"; break;
953 case kBuildType_Tool: pszPrefix = "TOOL_"; break;
954 case kBuildType_Sdk: pszPrefix = "SDK_"; break;
955 case kBuildType_Unit: pszPrefix = "UNIT_"; break;
956 default:
957 ON(fatal, pFileLoc, _("enmType=%d"), enmType);
958 return -1;
959 }
960 cch = strlen(pszPrefix);
961 pObj->cchVarPrefix = cch + pObj->cchName;
962 pObj->pszVarPrefix = xmalloc(pObj->cchVarPrefix + 1);
963 memcpy(pObj->pszVarPrefix, pszPrefix, cch);
964 memcpy(&pObj->pszVarPrefix[cch], pObj->pszName, pObj->cchName);
965
966 /*
967 * Parse subsequent words.
968 */
969 psz = find_next_token_eos(&pszLine, pszEos, &cch);
970 while (psz)
971 {
972 if (WORD_IS(psz, cch, "extending"))
973 {
974 /* Inheritance directive. */
975 if (pObj->pszParent != NULL)
976 O(fatal, pFileLoc, _("'extending' can only occure once"));
977 pObj->pszParent = allocate_expanded_next_token(&pszLine, pszEos, &pObj->cchParent, 1 /*strip*/);
978 if (!pObj->pszParent || !*pObj->pszParent)
979 O(fatal, pFileLoc, _("'extending' requires a parent name"));
980 }
981 else if (WORD_IS(psz, cch, "using"))
982 {
983 char *pszTemplate;
984 size_t cchTemplate;
985
986 /* Template directive. */
987 if (enmType != kBuildType_Target)
988 O(fatal, pFileLoc, _("'using <template>' can only be used with 'kBuild-define-target'"));
989 if (pObj->pszTemplate != NULL)
990 O(fatal, pFileLoc, _("'using' can only occure once"));
991
992 pszTemplate = allocate_expanded_next_token(&pszLine, pszEos, &cchTemplate, 1 /*fStrip*/);
993 if (!pszTemplate || !*pszTemplate)
994 O(fatal, pFileLoc, _("'using' requires a template name"));
995
996 define_kbuild_object_variable_cached(pObj, g_pszVarNmTemplate, pszTemplate, cchTemplate,
997 0 /*fDuplicateValue*/, o_default, 0 /*fRecursive*/,
998 1 /*fNoSpecialAccessors*/, pFileLoc);
999
1000 }
1001 else
1002 fatal(pFileLoc, cch, _("Don't know what '%.*s' means"), (int)cch, psz);
1003
1004 /* next token */
1005 psz = find_next_token_eos(&pszLine, pszEos, &cch);
1006 }
1007
1008 /*
1009 * Try resolve the parent.
1010 */
1011 resolve_kbuild_object_parent(pObj, 1 /*fQuiet*/);
1012
1013 /*
1014 * Create an eval stack entry and change the current variable set.
1015 */
1016 pData = xmalloc(sizeof(*pData));
1017 pData->pObj = pObj;
1018 pData->pVariablesSaved = current_variable_set_list;
1019 current_variable_set_list = pObj->pVariables;
1020
1021 pData->pStackDown = *ppData;
1022 *ppData = pData;
1023 g_pTopKbEvalData = pData;
1024
1025 return 0;
1026}
1027
1028static int
1029eval_kbuild_endef_xxxx(struct kbuild_eval_data **ppData, const floc *pFileLoc,
1030 const char *pszLine, const char *pszEos, int fIgnoring, enum kBuildType enmType)
1031{
1032 struct kbuild_eval_data *pData;
1033 struct kbuild_object *pObj;
1034 size_t cchName;
1035 char *pszName;
1036
1037 if (fIgnoring)
1038 return 0;
1039
1040 /*
1041 * Is there something to pop?
1042 */
1043 pData = *ppData;
1044 if (!pData)
1045 {
1046 OSS(error, pFileLoc, _("kBuild-endef-%s is missing kBuild-define-%s"),
1047 eval_kbuild_type_to_string(enmType), eval_kbuild_type_to_string(enmType));
1048 return 0;
1049 }
1050
1051 /*
1052 * ... and does it have a matching kind?
1053 */
1054 pObj = pData->pObj;
1055 if (pObj->enmType != enmType)
1056 OSSS(error, pFileLoc, _("'kBuild-endef-%s' does not match 'kBuild-define-%s %s'"),
1057 eval_kbuild_type_to_string(enmType), eval_kbuild_type_to_string(pObj->enmType), pObj->pszName);
1058
1059 /*
1060 * The endef-kbuild may optionally be followed by the target name.
1061 * It should match the name given to the kBuild-define.
1062 */
1063 pszName = allocate_expanded_next_token(&pszLine, pszEos, &cchName, 1 /*fStrip*/);
1064 if (pszName)
1065 {
1066 if ( cchName != pObj->cchName
1067 || strcmp(pszName, pObj->pszName))
1068 OSSSS(error, pFileLoc, _("'kBuild-endef-%s %s' does not match 'kBuild-define-%s %s'"),
1069 eval_kbuild_type_to_string(enmType), pszName,
1070 eval_kbuild_type_to_string(pObj->enmType), pObj->pszName);
1071 free(pszName);
1072 }
1073
1074 /*
1075 * Pop a define off the stack.
1076 */
1077 assert(pData == g_pTopKbEvalData);
1078 *ppData = g_pTopKbEvalData = pData->pStackDown;
1079 pData->pStackDown = NULL;
1080 current_variable_set_list = pData->pVariablesSaved;
1081 pData->pVariablesSaved = NULL;
1082 free(pData);
1083
1084 return 0;
1085}
1086
1087int eval_kbuild_read_hook(struct kbuild_eval_data **kdata, const floc *flocp,
1088 const char *pchWord, size_t cchWord, const char *line, const char *eos, int ignoring)
1089{
1090 enum kBuildType enmType;
1091
1092 /*
1093 * Skip the 'kBuild-' prefix that the caller already matched.
1094 */
1095 assert(memcmp(pchWord, "kBuild-", sizeof("kBuild-") - 1) == 0);
1096 pchWord += sizeof("kBuild-") - 1;
1097 cchWord -= sizeof("kBuild-") - 1;
1098
1099 /*
1100 * String switch.
1101 */
1102 if ( cchWord >= sizeof("define-") - 1
1103 && strneq(pchWord, "define-", sizeof("define-") - 1))
1104 {
1105 enmType = eval_kbuild_type_from_string(pchWord + sizeof("define-") - 1, cchWord - sizeof("define-") + 1);
1106 if (enmType != kBuildType_Invalid)
1107 return eval_kbuild_define_xxxx(kdata, flocp, line, eos, ignoring, enmType);
1108 }
1109 else if ( cchWord >= sizeof("endef-") - 1
1110 && strneq(pchWord, "endef-", sizeof("endef-") - 1))
1111 {
1112 enmType = eval_kbuild_type_from_string(pchWord + sizeof("endif-") - 1, cchWord - sizeof("endif-") + 1);
1113 if (enmType != kBuildType_Invalid)
1114 return eval_kbuild_endef_xxxx(kdata, flocp, line, eos, ignoring, enmType);
1115 }
1116 else if (WORD_IS(pchWord, cchWord, "endef"))
1117 {
1118 /* Terminate whatever definition is on top. */
1119
1120 }
1121
1122 /*
1123 * Everything that is prefixed with 'kBuild-' is reserved for language
1124 * extensions, at least until legacy assignments/whatever turns up.
1125 */
1126 error(flocp, cchWord, _("Unknown syntax 'kBuild-%.*s'"), (int)cchWord, pchWord);
1127 return 0;
1128}
1129
1130
1131/** @name kBuild object variable accessor related functions
1132 * @{
1133 */
1134
1135/**
1136 * Checks if the given name is an object variable accessor.
1137 *
1138 * @returns 1 if it is, 0 if it isn't.
1139 * @param pchName The potential kBuild variable accessor
1140 * expression.
1141 * @param cchName Length of the expression.
1142 */
1143int is_kbuild_object_variable_accessor(const char *pchName, size_t cchName)
1144{
1145 char const *pchTmp;
1146
1147 /* See lookup_kbuild_object_variable for the rules. */
1148 if (cchName >= 1+1+1+1 && *pchName == '[')
1149 {
1150 pchName++;
1151 cchName--;
1152
1153 pchTmp = memchr(pchName, '@', cchName);
1154 if (pchTmp)
1155 {
1156 cchName -= pchTmp + 1 - pchName;
1157 pchName = pchTmp + 1;
1158 pchTmp = memchr(pchName, ']', cchName);
1159 if (pchTmp)
1160 {
1161 cchName -= pchTmp + 1 - pchName;
1162 if (cchName > 0)
1163 return 1;
1164 }
1165 }
1166 }
1167 return 0;
1168}
1169
1170/**
1171 * Parses a kBuild object variable accessor, resolving the object.
1172 *
1173 * @returns Pointer to the variable if found.
1174 * @retval NULL if the object (or type) couldn't be resolved.
1175 * @retval KOBJ_NOT_KBUILD_ACCESSOR if no a kBuild variable accessor.
1176 *
1177 * @param pchExpr The kBuild variable accessor expression.
1178 * @param cchExpr Length of the expression.
1179 * @param enmSeverity The minimum severity level for errors.
1180 * @param pFileLoc The file location any errors should be reported
1181 * at. Optional.
1182 * @param ppchVarNm Where to return the pointer to the start of the
1183 * variable name within the string @a pchExpr
1184 * points to. Mandatory.
1185 * @param pcchVarNm Where to return the length of the variable name.
1186 * Mandatory.
1187 * @param penmType Where to return the object type. Optional.
1188 */
1189static struct kbuild_object *
1190parse_kbuild_object_variable_accessor(const char *pchExpr, size_t cchExpr,
1191 enum kBuildSeverity enmSeverity, const floc *pFileLoc,
1192 const char **ppchVarNm, size_t *pcchVarNm, enum kBuildType *penmType)
1193{
1194 const char * const pchOrgExpr = pchExpr;
1195 size_t const cchOrgExpr = cchExpr;
1196 char const *pchTmp;
1197
1198 /*
1199 * To accept this as an kBuild accessor, we require:
1200 * 1. Open bracket.
1201 * 2. At sign separating the type from the name.
1202 * 3. Closing bracket.
1203 * 4. At least one character following it.
1204 */
1205 if (cchExpr >= 1+1+1+1 && *pchExpr == '[')
1206 {
1207 pchExpr++;
1208 cchExpr--;
1209
1210 pchTmp = memchr(pchExpr, '@', cchExpr);
1211 if (pchTmp)
1212 {
1213 const char * const pchType = pchExpr;
1214 size_t const cchType = pchTmp - pchExpr;
1215
1216 cchExpr -= cchType + 1;
1217 pchExpr = pchTmp + 1;
1218 pchTmp = memchr(pchExpr, ']', cchExpr);
1219 if (pchTmp)
1220 {
1221 const char * const pchObjName = pchExpr;
1222 size_t const cchObjName = pchTmp - pchExpr;
1223
1224 cchExpr -= cchObjName + 1;
1225 pchExpr = pchTmp + 1;
1226 if (cchExpr > 0)
1227 {
1228
1229 /*
1230 * It's an kBuild define variable accessor, alright.
1231 */
1232 *pcchVarNm = cchExpr;
1233 *ppchVarNm = pchExpr;
1234
1235 /* Deal with known special accessors: [@self]VAR, [@super]VAR. */
1236 if (cchType == 0)
1237 {
1238 int fSuper;
1239
1240 if (WORD_IS(pchObjName, cchObjName, "self"))
1241 fSuper = 0;
1242 else if (WORD_IS(pchObjName, cchObjName, "super"))
1243 fSuper = 1;
1244 else
1245 {
1246 kbuild_report_problem(MAX(enmSeverity, kBuildSeverity_Error), pFileLoc,
1247 _("Invalid special kBuild object accessor: '%.*s'"),
1248 (int)cchOrgExpr, pchOrgExpr);
1249 if (penmType)
1250 *penmType = kBuildType_Invalid;
1251 return NULL;
1252 }
1253 if (g_pTopKbEvalData)
1254 {
1255 struct kbuild_object *pObj = g_pTopKbEvalData->pObj;
1256 struct kbuild_object *pParent;
1257
1258 if (penmType)
1259 *penmType = pObj->enmType;
1260
1261 if (!fSuper)
1262 return pObj;
1263
1264 pParent = get_kbuild_object_parent(pObj, MAX(enmSeverity, kBuildSeverity_Error));
1265 if (pParent)
1266 return pParent;
1267 }
1268 else
1269 kbuild_report_problem(MAX(enmSeverity, kBuildSeverity_Error), pFileLoc,
1270 _("The '%.*s' accessor can only be used in the context of a kBuild object"),
1271 (int)cchOrgExpr, pchOrgExpr);
1272 if (penmType)
1273 *penmType = kBuildType_Invalid;
1274 }
1275 else
1276 {
1277 /* Genric accessor. Check the type and look up the object. */
1278 enum kBuildType enmType = eval_kbuild_type_from_string(pchType, cchType);
1279 if (penmType)
1280 *penmType = enmType;
1281 if (enmType != kBuildType_Invalid)
1282 {
1283 struct kbuild_object *pObj = lookup_kbuild_object(enmType, pchObjName, cchObjName);
1284 if (pObj)
1285 return pObj;
1286
1287 /* failed. */
1288 kbuild_report_problem(enmSeverity, pFileLoc,
1289 _("kBuild object '%s' not found in kBuild variable accessor '%.*s'"),
1290 (int)cchObjName, pchObjName, (int)cchOrgExpr, pchOrgExpr);
1291 }
1292 else
1293 kbuild_report_problem(MAX(enmSeverity, kBuildSeverity_Error), pFileLoc,
1294 _("Invalid type '%.*s' specified in kBuild variable accessor '%.*s'"),
1295 (int)cchType, pchType, (int)cchOrgExpr, pchOrgExpr);
1296 }
1297 return NULL;
1298 }
1299 }
1300 }
1301 }
1302
1303 *ppchVarNm = NULL;
1304 *pcchVarNm = 0;
1305 if (penmType)
1306 *penmType = kBuildType_Invalid;
1307 return KOBJ_NOT_KBUILD_ACCESSOR;
1308}
1309
1310/**
1311 * Looks up a variable in a kBuild object.
1312 *
1313 * The caller has done minimal matching, i.e. starting square brackets and
1314 * minimum length. We do the rest here.
1315 *
1316 * @returns Pointer to the variable if found.
1317 * @retval NULL if not found.
1318 * @retval VAR_NOT_KBUILD_ACCESSOR if no a kBuild variable accessor.
1319 *
1320 * @param pchName The kBuild variable accessor expression.
1321 * @param cchName Length of the expression.
1322 */
1323struct variable *
1324lookup_kbuild_object_variable_accessor(const char *pchName, size_t cchName)
1325{
1326 /*const char * const pchOrgName = pchName;*/
1327 /*size_t const cchOrgName = cchName;*/
1328 const char * pchVarNm;
1329 size_t cchVarNm;
1330 struct kbuild_object *pObj;
1331
1332 pObj = parse_kbuild_object_variable_accessor(pchName, cchName, kBuildSeverity_Warning, NULL, &pchVarNm, &cchVarNm, NULL);
1333 if (pObj != KOBJ_NOT_KBUILD_ACCESSOR)
1334 {
1335 if (pObj)
1336 {
1337 /*
1338 * Do the variable lookup.
1339 */
1340 const char *pszCachedName = strcache2_lookup(&variable_strcache, pchVarNm, cchVarNm);
1341 if (pszCachedName)
1342 {
1343 struct variable VarKey;
1344 struct variable *pVar;
1345 VarKey.name = pszCachedName;
1346 VarKey.length = cchName;
1347
1348 pVar = (struct variable *)hash_find_item_strcached(&pObj->pVariables->set->table, &VarKey);
1349 if (pVar)
1350 return pVar;
1351
1352 /*
1353 * Not found, check ancestors if any.
1354 */
1355 if (pObj->pszParent || pObj->pszTemplate)
1356 {
1357 struct kbuild_object *pParent = pObj;
1358 for (;;)
1359 {
1360 pParent = resolve_kbuild_object_parent(pParent, 0 /*fQuiet*/);
1361 if (!pParent)
1362 break;
1363 pVar = (struct variable *)hash_find_item_strcached(&pParent->pVariables->set->table, &VarKey);
1364 if (pVar)
1365 return pVar;
1366 }
1367 }
1368 }
1369 }
1370
1371 /* Not found one way or the other. */
1372 return NULL;
1373 }
1374
1375 /* Not a kBuild object variable accessor. */
1376 return VAR_NOT_KBUILD_ACCESSOR;
1377}
1378
1379/** @} */
1380
1381void print_kbuild_data_base(void)
1382{
1383 struct kbuild_object *pCur;
1384
1385 puts(_("\n# kBuild defines"));
1386
1387 for (pCur = g_pHeadKbObjs; pCur; pCur = pCur->pGlobalNext)
1388 {
1389 printf("\nkBuild-define-%s %s",
1390 eval_kbuild_type_to_string(pCur->enmType), pCur->pszName);
1391 if (pCur->pszParent)
1392 printf(" extending %s", pCur->pszParent);
1393 if (pCur->pszTemplate)
1394 printf(" using %s", pCur->pszTemplate);
1395 putchar('\n');
1396
1397 print_variable_set(pCur->pVariables->set, "", 0);
1398
1399 printf("kBuild-endef-%s %s\n",
1400 eval_kbuild_type_to_string(pCur->enmType), pCur->pszName);
1401 }
1402 /** @todo hash stats. */
1403}
1404
1405void print_kbuild_define_stats(void)
1406{
1407 /* later when hashing stuff */
1408}
1409
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use