1 /* $Id: kbuild-object.c 3065 2017-09-30 12:52:35Z 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 "make.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.  */
53 enum kBuildType
54 {
55     kBuildType_Invalid,
56     kBuildType_Target,
57     kBuildType_Template,
58     kBuildType_Tool,
59     kBuildType_Sdk,
60     kBuildType_Unit
61 };
62 
63 enum kBuildSeverity
64 {
65     kBuildSeverity_Warning,
66     kBuildSeverity_Error,
67     kBuildSeverity_Fatal
68 };
69 
70 
71 /**
72  * kBuild object data.
73  */
74 struct 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     struct 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  */
114 struct 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! */
131 static 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. */
135 struct kbuild_eval_data        *g_pTopKbEvalData = NULL;
136 
137 /** Cached variable name '_TEMPLATE'.  */
138 static 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. */
142 int                             g_fKbObjCompMode = 1;
143 
144 
145 /*******************************************************************************
146 *   Internal Functions                                                         *
147 *******************************************************************************/
148 static struct kbuild_object *
149 resolve_kbuild_object_parent(struct kbuild_object *pObj, int fQuiet);
150 static struct kbuild_object *
151 get_kbuild_object_parent(struct kbuild_object *pObj, enum kBuildSeverity enmSeverity);
152 
153 static struct kbuild_object *
154 parse_kbuild_object_variable_accessor(const char *pchExpr, size_t cchExpr,
155                                       enum kBuildSeverity enmSeverity, const struct 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  */
init_kbuild_object(void)164 void 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  */
kbuild_report_problem(enum kBuildSeverity enmSeverity,const struct floc * pFileLoc,const char * pszFormat,...)178 static void kbuild_report_problem(enum kBuildSeverity enmSeverity, const struct 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             message(0, "%s", szBuf);
196             break;
197         case kBuildSeverity_Error:
198             error(pFileLoc, "%s", szBuf);
199             break;
200         default:
201         case kBuildSeverity_Fatal:
202             fatal(pFileLoc, "%s", szBuf);
203             break;
204     }
205 }
206 
207 
208 static const char *
eval_kbuild_type_to_string(enum kBuildType enmType)209 eval_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  */
229 static unsigned
eval_kbuild_type_to_string_length(enum kBuildType enmType)230 eval_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  */
251 static enum kBuildType
eval_kbuild_type_from_string(const char * pchWord,size_t cchWord)252 eval_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  */
288 static const char *
289 kbuild_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 
298 static struct kbuild_object *
lookup_kbuild_object(enum kBuildType enmType,const char * pchName,size_t cchName)299 lookup_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  */
326 static int
is_valid_kbuild_object_variable_name(const char * pchName,size_t cchName)327 is_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 
340 static const char *
kbuild_replace_special_accessors(const char * pchValue,size_t * pcchValue,int * pfDuplicateValue,const struct floc * pFileLoc)341 kbuild_replace_special_accessors(const char *pchValue, size_t *pcchValue, int *pfDuplicateValue,
342                                  const struct 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, _("The '$([%.*s...' accessor can only be used in the context of a kBuild object"),
467                   MAX(cchLeft, 20), pchLeft);
468     }
469 
470     return pchValue;
471 }
472 
473 static struct variable *
define_kbuild_object_variable_cached(struct kbuild_object * pObj,const char * pszName,const char * pchValue,size_t cchValue,int fDuplicateValue,enum variable_origin enmOrigin,int fRecursive,int fNoSpecialAccessors,const struct floc * pFileLoc)474 define_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 struct 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             error(pFileLoc, _("Error defining alias '%s'"), pszPrefixed);
507     }
508 
509     return pVar;
510 }
511 
512 #if 0
513 struct variable *
514 define_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 struct 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  */
547 struct variable *
try_define_kbuild_object_variable_via_accessor(const char * pchName,size_t cchName,const char * pszValue,size_t cchValue,int fDuplicateValue,enum variable_origin enmOrigin,int fRecursive,struct floc const * pFileLoc)548 try_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                                                struct 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, _("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  */
594 struct variable *
define_kbuild_object_variable_in_top_obj(const char * pchName,size_t cchName,const char * pszValue,size_t cchValue,int fDuplicateValue,enum variable_origin enmOrigin,int fRecursive,struct floc const * pFileLoc)595 define_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                                          struct floc const *pFileLoc)
599 {
600     assert(g_pTopKbEvalData != NULL);
601 
602     if (!is_valid_kbuild_object_variable_name(pchName, cchName))
603         fatal(pFileLoc, _("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  */
629 struct variable *
kbuild_object_variable_pre_append(const char * pchName,size_t cchName,const char * pchValue,size_t cchValue,int fSimpleValue,enum variable_origin enmOrigin,int fAppend,const struct floc * pFileLoc)630 kbuild_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 struct 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, _("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 
794 static char *
allocate_expanded_next_token(const char ** ppszCursor,const char * pszEos,size_t * pcchToken,int fStrip)795 allocate_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 
831 static struct kbuild_object *
resolve_kbuild_object_parent(struct kbuild_object * pObj,int fQuiet)832 resolve_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                     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             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  */
871 static struct kbuild_object *
get_kbuild_object_parent(struct kbuild_object * pObj,enum kBuildSeverity enmSeverity)872 get_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 
893 static int
eval_kbuild_define_xxxx(struct kbuild_eval_data ** ppData,const struct floc * pFileLoc,const char * pszLine,const char * pszEos,int fIgnoring,enum kBuildType enmType)894 eval_kbuild_define_xxxx(struct kbuild_eval_data **ppData, const struct 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         fatal(pFileLoc, _("The kBuild define requires a name"));
936 
937     psz = pObj->pszName;
938     while ((ch = *psz++) != '\0')
939         if (!isgraph(ch))
940         {
941             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             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                 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                 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                 fatal(pFileLoc, _("'using <template>' can only be used with 'kBuild-define-target'"));
989             if (pObj->pszTemplate != NULL)
990                 fatal(pFileLoc, _("'using' can only occure once"));
991 
992             pszTemplate = allocate_expanded_next_token(&pszLine, pszEos, &cchTemplate, 1 /*fStrip*/);
993             if (!pszTemplate || !*pszTemplate)
994                 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, _("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 
1028 static int
eval_kbuild_endef_xxxx(struct kbuild_eval_data ** ppData,const struct floc * pFileLoc,const char * pszLine,const char * pszEos,int fIgnoring,enum kBuildType enmType)1029 eval_kbuild_endef_xxxx(struct kbuild_eval_data **ppData, const struct 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         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         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             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 
eval_kbuild_read_hook(struct kbuild_eval_data ** kdata,const struct floc * flocp,const char * pchWord,size_t cchWord,const char * line,const char * eos,int ignoring)1087 int eval_kbuild_read_hook(struct kbuild_eval_data **kdata, const struct 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, _("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  */
is_kbuild_object_variable_accessor(const char * pchName,size_t cchName)1143 int 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  */
1189 static struct kbuild_object *
parse_kbuild_object_variable_accessor(const char * pchExpr,size_t cchExpr,enum kBuildSeverity enmSeverity,const struct floc * pFileLoc,const char ** ppchVarNm,size_t * pcchVarNm,enum kBuildType * penmType)1190 parse_kbuild_object_variable_accessor(const char *pchExpr, size_t cchExpr,
1191                                       enum kBuildSeverity enmSeverity, const struct 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  */
1323 struct variable *
lookup_kbuild_object_variable_accessor(const char * pchName,size_t cchName)1324 lookup_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 
print_kbuild_data_base(void)1381 void 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, "");
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 
print_kbuild_define_stats(void)1405 void print_kbuild_define_stats(void)
1406 {
1407     /* later when hashing stuff */
1408 }
1409 
1410