Ignore:
Timestamp:
Dec 30, 2013, 1:58:43 AM (12 years ago)
Author:
bird
Message:

kmk: Hacking kBuild-define-*.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kmk/kbuild-read.c

    r2549 r2717  
    55
    66/*
    7  * Copyright (c) 2011 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
     7 * Copyright (c) 2011-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
    88 *
    99 * This file is part of kBuild.
     
    3737
    3838#include <assert.h>
     39#include <stdarg.h>
    3940
    4041
     
    4950*   Structures and Typedefs                                                    *
    5051*******************************************************************************/
    51 /** Indicate which kind of kBuild define we're working on.  */
    52 enum kBuildDef
    53 {
    54     kBuildDef_Invalid,
    55     kBuildDef_Target,
    56     kBuildDef_Template,
    57     kBuildDef_Tool,
    58     kBuildDef_Sdk,
    59     kBuildDef_Unit
     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
    6061};
    6162
    62 enum kBuildExtendBy
    63 {
    64     kBuildExtendBy_NoParent,
    65     kBuildExtendBy_Overriding,
    66     kBuildExtendBy_Appending,
    67     kBuildExtendBy_Prepending
     63enum kBuildSeverity
     64{
     65    kBuildSeverity_Warning,
     66    kBuildSeverity_Error,
     67    kBuildSeverity_Fatal
    6868};
    6969
    7070
    7171/**
    72  * The data we stack during eval.
    73  */
    74 struct kbuild_eval_data
    75 {
    76     /** The kind of define. */
    77     enum kBuildDef              enmKind;
     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;
    7880    /** The bare name of the define. */
    7981    char                       *pszName;
     
    8284
    8385    /** Pointer to the next element in the global list. */
    84     struct kbuild_eval_data    *pGlobalNext;
    85     /** Pointer to the element below us on the stack. */
    86     struct kbuild_eval_data    *pStackDown;
     86    struct kbuild_object       *pGlobalNext;
    8787
    8888    /** The variable set associated with this define. */
    8989    struct variable_set_list   *pVariables;
    90     /** The saved current variable set, for restoring in kBuild-endef. */
    91     struct variable_set_list   *pVariablesSaved;
    9290
    9391    /** The parent name, NULL if none. */
    9492    char                       *pszParent;
    95     /** The inheritance method. */
    96     enum kBuildExtendBy         enmExtendBy;
    97     /** Pointer to the parent. Resolved lazily, so it can be NULL even if we have
    98      *  a parent. */
    99     struct kbuild_eval_data    *pParent;
    100 
    101     /** The template, NULL if none. Only applicable to targets. */
    102     char                       *pszTemplate;
    103     /** Pointer to the template. Resolved lazily, so it can be NULL even if we have
    104      *  a parent. */
    105     struct kbuild_eval_data    *pTemplate;
    106 
    107     /** The variable prefix.  */
     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. */
    108105    char                       *pszVarPrefix;
    109106    /** The length of the variable prefix. */
    110107    size_t                      cchVarPrefix;
    111108};
     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
    112124
    113125
     
    117129/** Linked list (LIFO) of kBuild defines.
    118130 * @todo use a hash! */
    119 struct kbuild_eval_data *g_pHeadKbDefs = NULL;
    120 /** Stack of kBuild defines. */
    121 struct kbuild_eval_data *g_pTopKbDef = NULL;
    122 
    123 
    124 struct variable_set *
    125 get_top_kbuild_variable_set(void)
    126 {
    127     struct kbuild_eval_data *pTop = g_pTopKbDef;
    128     assert(pTop != NULL);
    129     return pTop->pVariables->set;
    130 }
    131 
    132 
    133 char *
    134 kbuild_prefix_variable(const char *pszName, unsigned int *pcchName)
    135 {
    136     struct kbuild_eval_data *pTop = g_pTopKbDef;
    137     char        *pszPrefixed;
    138     unsigned int cchPrefixed;
    139 
    140     assert(pTop != NULL);
    141 
    142     cchPrefixed = pTop->cchVarPrefix + *pcchName;
    143     pszPrefixed = xmalloc(cchPrefixed + 1);
    144     memcpy(pszPrefixed, pTop->pszVarPrefix, pTop->cchVarPrefix);
    145     memcpy(&pszPrefixed[pTop->cchVarPrefix], pszName, *pcchName);
    146     pszPrefixed[cchPrefixed] = '\0';
    147     *pcchName = cchPrefixed;
    148     return pszPrefixed;
    149 }
    150 
    151 
     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 *
     149eval_kbuild_resolve_parent(struct kbuild_object *pObj, int fQuiet);
     150
     151static struct kbuild_object *
     152parse_kbuild_object_variable_accessor(const char *pchExpr, size_t cchExpr,
     153                                      enum kBuildSeverity enmSeverity, const struct floc *pFileLoc,
     154                                      const char **ppchVarNm, size_t *pcchVarNm, enum kBuildType *penmType);
     155
     156
     157/**
     158 * Initializes the kBuild object stuff.
     159 *
     160 * Requires the variable_cache to be initialized.
     161 */
     162void init_kbuild_object(void)
     163{
     164    g_pszVarNmTemplate = strcache2_add(&variable_strcache, STRING_SIZE_TUPLE("_TEMPLATE"));
     165}
     166
     167
     168/**
     169 * Reports a problem with dynamic severity level.
     170 *
     171 * @param   enmSeverity         The severity level.
     172 * @param   pFileLoc            The file location.
     173 * @param   pszFormat           The format string.
     174 * @param   ...                 Arguments for the format string.
     175 */
     176static void kbuild_report_problem(enum kBuildSeverity enmSeverity, const struct floc *pFileLoc,
     177                                  const char *pszFormat, ...)
     178{
     179    char    szBuf[8192];
     180    va_list va;
     181
     182    va_start(va, pszFormat);
     183#ifdef _MSC_VER
     184    _vsnprintf(szBuf, sizeof(szBuf), pszFormat, va);
     185#else
     186    vsnprintf(szBuf, sizeof(szBuf), pszFormat, va);
     187#endif
     188    va_end(va);
     189
     190    switch (enmSeverity)
     191    {
     192        case kBuildSeverity_Warning:
     193            message(0, "%s", szBuf);
     194            break;
     195        case kBuildSeverity_Error:
     196            error(pFileLoc, "%s", szBuf);
     197            break;
     198        default:
     199        case kBuildSeverity_Fatal:
     200            fatal(pFileLoc, "%s", szBuf);
     201            break;
     202    }
     203}
     204
     205
     206/**
     207 * Helper function for caching variable name strings.
     208 *
     209 * @returns The string cache variable name.
     210 * @param   pszName             The variable name.
     211 * @param   ppszCache           Cache variable, static or global.  Initialize to
     212 *                              NULL.
     213 */
    152214static const char *
    153 eval_kbuild_kind_to_string(enum kBuildDef enmKind)
    154 {
    155     switch (enmKind)
    156     {
    157         case kBuildDef_Target:      return "target";
    158         case kBuildDef_Template:    return "template";
    159         case kBuildDef_Tool:        return "tool";
    160         case kBuildDef_Sdk:         return "sdk";
    161         case kBuildDef_Unit:        return "unit";
     215kbuild_variable_name(const char *pszName, const char **ppszCache)
     216{
     217    const char *pszRet = *ppszCache;
     218    if (!pszRet)
     219        *ppszCache = pszRet = strcache2_add(&variable_strcache, pszName, strlen(pszName));
     220    return pszRet;
     221}
     222
     223static struct kbuild_object *
     224lookup_kbuild_object(enum kBuildType enmType, const char *pchName, size_t cchName)
     225{
     226    /* Linear lookup for now. */
     227    struct kbuild_object *pCur = g_pHeadKbObjs;
     228    while (pCur)
     229    {
     230        if (   pCur->enmType == enmType
     231            && pCur->cchName == cchName
     232            && !memcmp(pCur->pszName, pchName, cchName))
     233            return pCur;
     234        pCur = pCur->pGlobalNext;
     235    }
     236    return NULL;
     237}
     238
     239
     240/** @name Defining and modifying variables
     241 * @{
     242 */
     243
     244/**
     245 * Checks if the variable name is valid.
     246 *
     247 * @returns 1 if valid, 0 if not.
     248 * @param   pchName             The variable name.
     249 * @param   cchName             The length of the variable name.
     250 */
     251static int
     252is_valid_kbuild_object_variable_name(const char *pchName, size_t cchName)
     253{
     254    if (cchName > 0)
     255    {
     256        if (!memchr(pchName, '[', cchName))
     257        {
     258            /** @todo more? */
     259            return 1;
     260        }
     261    }
     262    return 0;
     263}
     264
     265static struct variable *
     266define_kbuild_object_variable_cached(struct kbuild_object *pObj, const char *pszName,
     267                                     const char *pchValue, size_t cchValue,
     268                                     int fDuplicateValue, enum variable_origin enmOrigin,
     269                                     int fRecursive, const struct floc *pFileLoc)
     270{
     271    struct variable *pVar;
     272    size_t cchName = strcache2_get_len(&variable_strcache, pszName);
     273
     274
     275    pVar = define_variable_in_set(pszName, cchName,
     276                                  pchValue, cchValue, fDuplicateValue,
     277                                  enmOrigin, fRecursive,
     278                                  pObj->pVariables->set,
     279                                  pFileLoc);
     280
     281    /* Single underscore prefixed variables gets a global alias. */
     282    if (   pszName[0] == '_'
     283        && pszName[1] != '_'
     284        && g_fKbObjCompMode)
     285    {
     286        size_t  cchPrefixed = pObj->cchVarPrefix + cchName;
     287        char   *pszPrefixed = xmalloc(cchPrefixed + 1);
     288        memcpy(pszPrefixed, pObj->pszVarPrefix, pObj->cchVarPrefix);
     289        memcpy(&pszPrefixed[pObj->cchVarPrefix], pszName, cchName);
     290        pszPrefixed[cchPrefixed] = '\0';
     291
     292        /** @todo implement variable aliases or something. */
     293        define_variable_in_set(pszPrefixed, cchPrefixed,
     294                               pchValue, cchValue, 1 /*duplicate_value*/,
     295                               enmOrigin, fRecursive,
     296                               &global_variable_set,
     297                               pFileLoc);
     298    }
     299
     300    return pVar;
     301}
     302
     303#if 0
     304struct variable *
     305define_kbuild_object_variable(struct kbuild_object *pObj, const char *pchName, size_t cchName,
     306                              const char *pchValue, size_t cchValue,
     307                              int fDuplicateValue, enum variable_origin enmOrigin,
     308                              int fRecursive, const struct floc *pFileLoc)
     309{
     310    return define_kbuild_object_variable_cached(pObj, strcache2_add(&variable_strcache, pchName, cchName),
     311                                                pchValue, cchValue,
     312                                                fDuplicateValue, enmOrigin,
     313                                                fRecursive, pFileLoc);
     314}
     315#endif
     316
     317/**
     318 * Try define a kBuild object variable via a possible accessor
     319 * ([type@object]var).
     320 *
     321 * @returns Pointer to the defined variable on success.
     322 * @retval  VAR_NOT_KBUILD_ACCESSOR if it isn't an accessor.
     323 *
     324 * @param   pchName         The variable name, not cached.
     325 * @param   cchName         The variable name length.  This will not be ~0U.
     326 * @param   pszValue        The variable value.  If @a fDuplicateValue is clear,
     327 *                          this should be assigned as the actual variable
     328 *                          value, otherwise it will be duplicated.  In the
     329 *                          latter case it might not be properly null
     330 *                          terminated.
     331 * @param   cchValue        The value length.
     332 * @param   fDuplicateValue Whether @a pszValue need to be duplicated on the
     333 *                          heap or is already there.
     334 * @param   enmOrigin       The variable origin.
     335 * @param   fRecursive      Whether it's a recursive variable.
     336 * @param   pFileLoc        The location of the variable definition.
     337 */
     338struct variable *
     339try_define_kbuild_object_variable_via_accessor(const char *pchName, size_t cchName,
     340                                               const char *pszValue, size_t cchValue, int fDuplicateValue,
     341                                               enum variable_origin enmOrigin, int fRecursive,
     342                                               struct floc const *pFileLoc)
     343{
     344    struct kbuild_object   *pObj;
     345    const char             *pchVarNm;
     346    size_t                  cchVarNm;
     347
     348    pObj = parse_kbuild_object_variable_accessor(pchName, cchName, kBuildSeverity_Fatal, pFileLoc,
     349                                                 &pchVarNm, &cchVarNm, NULL);
     350    if (pObj != KOBJ_NOT_KBUILD_ACCESSOR)
     351    {
     352        assert(pObj != NULL);
     353        if (!is_valid_kbuild_object_variable_name(pchVarNm, cchVarNm))
     354            fatal(pFileLoc, _("Invalid kBuild object variable name: '%.*s' ('%s')"),
     355                  (int)cchVarNm, pchVarNm, (int)cchName, pchName);
     356        return define_kbuild_object_variable_cached(pObj, strcache2_add(&variable_strcache, pchVarNm, cchVarNm),
     357                                                    pszValue, cchValue, fDuplicateValue, enmOrigin, fRecursive, pFileLoc);
     358    }
     359
     360    return VAR_NOT_KBUILD_ACCESSOR;
     361}
     362
     363/**
     364 * Define a kBuild object variable in the topmost kBuild object.
     365 *
     366 * This won't be an variable accessor.
     367 *
     368 * @returns Pointer to the defined variable on success.
     369 *
     370 * @param   pchName         The variable name, not cached.
     371 * @param   cchName         The variable name length.  This will not be ~0U.
     372 * @param   pszValue        The variable value.  If @a fDuplicateValue is clear,
     373 *                          this should be assigned as the actual variable
     374 *                          value, otherwise it will be duplicated.  In the
     375 *                          latter case it might not be properly null
     376 *                          terminated.
     377 * @param   cchValue        The value length.
     378 * @param   fDuplicateValue Whether @a pszValue need to be duplicated on the
     379 *                          heap or is already there.
     380 * @param   enmOrigin       The variable origin.
     381 * @param   fRecursive      Whether it's a recursive variable.
     382 * @param   pFileLoc        The location of the variable definition.
     383 */
     384struct variable *
     385define_kbuild_object_variable_in_top_obj(const char *pchName, size_t cchName,
     386                                         const char *pszValue, size_t cchValue, int fDuplicateValue,
     387                                         enum variable_origin enmOrigin, int fRecursive,
     388                                         struct floc const *pFileLoc)
     389{
     390    assert(g_pTopKbEvalData != NULL);
     391
     392    if (!is_valid_kbuild_object_variable_name(pchName, cchName))
     393        fatal(pFileLoc, _("Invalid kBuild object variable name: '%.*s'"), (int)cchName, pchName);
     394
     395    return define_kbuild_object_variable_cached(g_pTopKbEvalData->pObj, strcache2_add(&variable_strcache, pchName, cchName),
     396                                                pszValue, cchValue, fDuplicateValue, enmOrigin, fRecursive, pFileLoc);
     397}
     398
     399/**
     400 * Implements appending and prepending to a kBuild object variable.
     401 *
     402 * The variable is either accessed thru an accessor or by the topmost kBuild
     403 * object.
     404 *
     405 * @returns Pointer to the defined variable on success.
     406 *
     407 * @param   pchName         The variable name, not cached.
     408 * @param   cchName         The variable name length.  This will not be ~0U.
     409 * @param   pszValue        The variable value. Must be duplicated.
     410 * @param   cchValue        The value length.
     411 * @param   fSimpleValue    Whether we've already figured that it's a simple
     412 *                          value.  This is for optimizing appending/prepending
     413 *                          to an existing simple value variable.
     414 * @param   enmOrigin       The variable origin.
     415 * @param   fAppend         Append if set, prepend if clear.
     416 * @param   pFileLoc        The location of the variable definition.
     417 */
     418struct variable *
     419kbuild_object_variable_pre_append(const char *pchName, size_t cchName,
     420                                  const char *pchValue, size_t cchValue, int fSimpleValue,
     421                                  enum variable_origin enmOrigin, int fAppend,
     422                                  const struct floc *pFileLoc)
     423{
     424    struct kbuild_object   *pObj;
     425    struct variable         VarKey;
     426
     427    /*
     428     * Resolve the relevant kBuild object first.
     429     */
     430    if (cchName > 3 && pchName[0] == '[')
     431    {
     432        const char *pchVarNm;
     433        size_t      cchVarNm;
     434        pObj = parse_kbuild_object_variable_accessor(pchName, cchName, kBuildSeverity_Fatal, pFileLoc,
     435                                                     &pchVarNm, &cchVarNm, NULL);
     436        if (pObj != KOBJ_NOT_KBUILD_ACCESSOR)
     437        {
     438            pchName = pchVarNm;
     439            cchName = cchVarNm;
     440        }
     441        else
     442            pObj = g_pTopKbEvalData->pObj;
     443    }
     444    else
     445        pObj = g_pTopKbEvalData->pObj;
     446
     447    /*
     448     * Make sure the variable name is valid.  Raise fatal error if not.
     449     */
     450    if (!is_valid_kbuild_object_variable_name(pchName, cchName))
     451        fatal(pFileLoc, _("Invalid kBuild object variable name: '%.*s'"), (int)cchName, pchName);
     452
     453    /*
     454     * Get the cached name and look it up in the object's variables.
     455     */
     456    VarKey.name = strcache2_lookup(&variable_strcache, pchName, cchName);
     457    if (VarKey.name)
     458    {
     459        struct variable *pVar;
     460
     461        VarKey.length = cchName;
     462        pVar = (struct variable *)hash_find_item_strcached(&pObj->pVariables->set->table, &VarKey);
     463        if (pVar)
     464        {
     465            /* Append/prepend to existing variable. */
     466            return do_variable_definition_append(pFileLoc, pVar, pchValue, cchValue, fSimpleValue, enmOrigin, fAppend);
     467        }
     468
     469        /*
     470         * Not found. Check ancestors if the 'override' directive isn't applied.
     471         */
     472        if (pObj->pszParent && enmOrigin != o_override)
     473        {
     474            struct kbuild_object *pParent = pObj;
     475            for (;;)
     476            {
     477                pParent = eval_kbuild_resolve_parent(pParent, 0 /*fQuiet*/);
     478                if (!pParent)
     479                    break;
     480
     481                pVar = (struct variable *)hash_find_item_strcached(&pParent->pVariables->set->table, &VarKey);
     482                if (pVar)
     483                {
     484                    if (pVar->value_length != ~0U)
     485                        assert(pVar->value_length == strlen(pVar->value));
     486                    else
     487                        pVar->value_length = strlen(pVar->value);
     488
     489                    /*
     490                     * Combine the two values and define the variable in the
     491                     * specified child object.  We must disregard 'origin' a
     492                     * little here, so we must do the gritty stuff our selves.
     493                     */
     494                    if (   pVar->recursive
     495                        || fSimpleValue
     496                        || !cchValue
     497                        || memchr(pchValue, '$', cchValue) == NULL )
     498                    {
     499                        size_t  cchNewValue;
     500                        char   *pszNewValue;
     501                        char   *pszTmp;
     502
     503                        /* Just join up the two values. */
     504                        if (pVar->value_length == 0)
     505                        {
     506                            cchNewValue = cchValue;
     507                            pszNewValue = xstrndup(pchValue, cchValue);
     508                        }
     509                        else if (!cchValue)
     510                        {
     511                            cchNewValue = pVar->value_length;
     512                            pszNewValue = xmalloc(cchNewValue + 1);
     513                            memcpy(pszNewValue, pVar->value, cchNewValue + 1);
     514                        }
     515                        else
     516                        {
     517                            cchNewValue = pVar->value_length + 1 + cchValue;
     518                            pszNewValue = xmalloc(cchNewValue + 1);
     519                            if (fAppend)
     520                            {
     521                                memcpy(pszNewValue, pVar->value, pVar->value_length);
     522                                pszTmp = pszNewValue + pVar->value_length;
     523                                *pszTmp++ = ' ';
     524                                memcpy(pszTmp, pchValue, cchValue);
     525                                pszTmp[cchValue] = '\0';
     526                            }
     527                            else
     528                            {
     529                                memcpy(pszNewValue, pchValue, cchValue);
     530                                pszTmp = pszNewValue + cchValue;
     531                                *pszTmp++ = ' ';
     532                                memcpy(pszNewValue, pVar->value, pVar->value_length);
     533                                pszTmp[pVar->value_length] = '\0';
     534                            }
     535                        }
     536
     537                        /* Define the new variable in the child. */
     538                        return define_kbuild_object_variable_cached(pObj, VarKey.name,
     539                                                                    pszNewValue, cchNewValue, 0 /*fDuplicateValue*/,
     540                                                                    enmOrigin, pVar->recursive, pFileLoc);
     541
     542                    }
     543                    else
     544                    {
     545                        /* Lazy bird: Copy the variable from the ancestor and
     546                                      then do a normal append/prepend on it. */
     547                        pVar = define_kbuild_object_variable_cached(pObj, VarKey.name,
     548                                                                    pVar->value, pVar->value_length, 1 /*fDuplicateValue*/,
     549                                                                    enmOrigin, pVar->recursive, pFileLoc);
     550                        append_expanded_string_to_variable(pVar, pchValue, cchValue, fAppend);
     551                        return pVar;
     552                    }
     553                }
     554            }
     555        }
     556    }
     557    else
     558        VarKey.name = strcache2_add(&variable_strcache, pchName, cchName);
     559
     560    /* Variable not found. */
     561    return define_kbuild_object_variable_cached(pObj, VarKey.name,
     562                                                pchValue, cchValue, 1 /*fDuplicateValue*/, enmOrigin,
     563                                                1 /*fRecursive */, pFileLoc);
     564}
     565
     566/** @} */
     567
     568
     569static const char *
     570eval_kbuild_type_to_string(enum kBuildType enmType)
     571{
     572    switch (enmType)
     573    {
     574        case kBuildType_Target:      return "target";
     575        case kBuildType_Template:    return "template";
     576        case kBuildType_Tool:        return "tool";
     577        case kBuildType_Sdk:         return "sdk";
     578        case kBuildType_Unit:        return "unit";
    162579        default:
    163         case kBuildDef_Invalid:     return "invalid";
    164     }
    165 }
     580        case kBuildType_Invalid:     return "invalid";
     581    }
     582}
     583
     584/**
     585 * Converts a string into an kBuild object type.
     586 *
     587 * @returns The type on success, kBuildType_Invalid on failure.
     588 * @param   pchWord             The pchWord.  Not necessarily zero terminated.
     589 * @param   cchWord             The length of the word.
     590 */
     591static enum kBuildType
     592eval_kbuild_type_from_string(const char *pchWord, size_t cchWord)
     593{
     594    if (cchWord >= 3)
     595    {
     596        if (*pchWord == 't')
     597        {
     598            if (WORD_IS(pchWord, cchWord, "target"))
     599                return kBuildType_Target;
     600            if (WORD_IS(pchWord, cchWord, "template"))
     601                return kBuildType_Template;
     602            if (WORD_IS(pchWord, cchWord, "tool"))
     603                return kBuildType_Tool;
     604        }
     605        else
     606        {
     607            if (WORD_IS(pchWord, cchWord, "sdk"))
     608                return kBuildType_Sdk;
     609            if (WORD_IS(pchWord, cchWord, "unit"))
     610                return kBuildType_Unit;
     611        }
     612    }
     613
     614    return kBuildType_Invalid;
     615}
     616
    166617
    167618static char *
    168 allocate_expanded_next_token(const char **ppszCursor, const char *pszEos, unsigned int *pcchToken, int fStrip)
     619allocate_expanded_next_token(const char **ppszCursor, const char *pszEos, size_t *pcchToken, int fStrip)
    169620{
    170621    unsigned int cchToken;
     
    193644            if (pcchToken)
    194645                *pcchToken = cchToken;
    195         }
    196     }
    197     return pszToken;
    198 }
    199 
    200 static struct kbuild_eval_data *
    201 eval_kbuild_resolve_parent(struct kbuild_eval_data *pData)
    202 {
    203     if (   !pData->pParent
    204         && pData->pszParent)
    205     {
    206         struct kbuild_eval_data *pCur = g_pHeadKbDefs;
     646            return pszToken;
     647        }
     648    }
     649
     650    if (pcchToken)
     651        *pcchToken = 0;
     652    return NULL;
     653}
     654
     655static struct kbuild_object *
     656eval_kbuild_resolve_parent(struct kbuild_object *pObj, int fQuiet)
     657{
     658    if (   !pObj->pParent
     659        && pObj->pszParent)
     660    {
     661        struct kbuild_object *pCur = g_pHeadKbObjs;
    207662        while (pCur)
    208663        {
    209             if (   pCur->enmKind == pData->enmKind
    210                 && !strcmp(pCur->pszName, pData->pszParent))
     664            if (   pCur->enmType == pObj->enmType
     665                && !strcmp(pCur->pszName, pObj->pszParent))
    211666            {
    212667                if (    pCur->pszParent
    213                     &&  (   pCur->pParent == pData
    214                          || !strcmp(pCur->pszParent, pData->pszName)) )
    215                     fatal(&pData->FileLoc, _("'%s' and '%s' are both trying to be each other children..."),
    216                           pData->pszName, pCur->pszName);
    217 
    218                 pData->pParent = pCur;
    219                 pData->pVariables->next = pData->pVariables;
    220                 break;
     668                    &&  (   pCur->pParent == pObj
     669                         || !strcmp(pCur->pszParent, pObj->pszName)) )
     670                    fatal(&pObj->FileLoc, _("'%s' and '%s' are both trying to be each other children..."),
     671                          pObj->pszName, pCur->pszName);
     672
     673                pObj->pParent = pCur;
     674                pObj->pVariables->next = pObj->pVariables;
     675                return pCur;
    221676            }
     677
    222678            pCur = pCur->pGlobalNext;
    223679        }
    224     }
    225     return pData->pParent;
     680
     681        /* Not found. */
     682        if (!fQuiet)
     683            error(&pObj->FileLoc, _("Could not locate parent '%s' of '%s'"), pObj->pszParent, pObj->pszName);
     684    }
     685    return pObj->pParent;
    226686}
    227687
    228688static int
    229689eval_kbuild_define_xxxx(struct kbuild_eval_data **ppData, const struct floc *pFileLoc,
    230                         const char *pszLine, const char *pszEos, int fIgnoring, enum kBuildDef enmKind)
     690                        const char *pszLine, const char *pszEos, int fIgnoring, enum kBuildType enmType)
    231691{
    232692    unsigned int            cch;
    233     unsigned int            cchName;
    234693    char                    ch;
    235694    char                   *psz;
    236695    const char             *pszPrefix;
     696    struct kbuild_object   *pObj;
    237697    struct kbuild_eval_data *pData;
    238698
     
    241701
    242702    /*
    243      * Create a new kBuild eval data item.
    244      */
    245     pData = xmalloc(sizeof(*pData));
    246     pData->enmKind          = enmKind;
    247     pData->pszName          = NULL;
    248     pData->FileLoc          = *pFileLoc;
    249 
    250     pData->pGlobalNext      = g_pHeadKbDefs;
    251     g_pHeadKbDefs           = pData;
    252 
    253     pData->pStackDown       = *ppData;
    254     *ppData = g_pTopKbDef   = pData;
    255     pData->pVariables       = create_new_variable_set();
    256     pData->pVariablesSaved  = NULL;
    257 
    258     pData->pszParent        = NULL;
    259     pData->enmExtendBy      = kBuildExtendBy_NoParent;
    260     pData->pParent          = NULL;
    261 
    262     pData->pszTemplate      = NULL;
    263     pData->pTemplate        = NULL;
    264 
    265     pData->pszVarPrefix     = NULL;
    266     pData->cchVarPrefix     = 0;
     703     * Create a new kBuild object.
     704     */
     705    pObj = xmalloc(sizeof(*pObj));
     706    pObj->enmType           = enmType;
     707    pObj->pszName           = NULL;
     708    pObj->cchName           = 0;
     709    pObj->FileLoc           = *pFileLoc;
     710
     711    pObj->pGlobalNext       = g_pHeadKbObjs;
     712    g_pHeadKbObjs           = pObj;
     713
     714    pObj->pVariables        = create_new_variable_set();
     715
     716    pObj->pszParent         = NULL;
     717    pObj->cchParent         = 0;
     718    pObj->pParent           = NULL;
     719
     720    pObj->pszTemplate       = NULL;
     721
     722    pObj->pszVarPrefix      = NULL;
     723    pObj->cchVarPrefix      = 0;
    267724
    268725    /*
    269726     * The first word is the name.
    270727     */
    271     pData->pszName = allocate_expanded_next_token(&pszLine, pszEos, &cchName, 1 /*strip*/);
    272     if (!pData->pszName || !*pData->pszName)
     728    pObj->pszName = allocate_expanded_next_token(&pszLine, pszEos, &pObj->cchName, 1 /*strip*/);
     729    if (!pObj->pszName || !*pObj->pszName)
    273730        fatal(pFileLoc, _("The kBuild define requires a name"));
    274731
    275     psz = pData->pszName;
     732    psz = pObj->pszName;
    276733    while ((ch = *psz++) != '\0')
    277734        if (!isgraph(ch))
    278735        {
    279736            error(pFileLoc, _("The 'kBuild-define-%s' name '%s' contains one or more invalid characters"),
    280                   eval_kbuild_kind_to_string(enmKind), pData->pszName);
     737                  eval_kbuild_type_to_string(enmType), pObj->pszName);
    281738            break;
    282739        }
     740
     741    /*
     742     * Calc the variable prefix.
     743     */
     744    switch (enmType)
     745    {
     746        case kBuildType_Target:      pszPrefix = ""; break;
     747        case kBuildType_Template:    pszPrefix = "TEMPLATE_"; break;
     748        case kBuildType_Tool:        pszPrefix = "TOOL_"; break;
     749        case kBuildType_Sdk:         pszPrefix = "SDK_"; break;
     750        case kBuildType_Unit:        pszPrefix = "UNIT_"; break;
     751        default:
     752            fatal(pFileLoc, _("enmType=%d"), enmType);
     753            return -1;
     754    }
     755    cch = strlen(pszPrefix);
     756    pObj->cchVarPrefix = cch + pObj->cchName;
     757    pObj->pszVarPrefix = xmalloc(pObj->cchVarPrefix + 1);
     758    memcpy(pObj->pszVarPrefix, pszPrefix, cch);
     759    memcpy(&pObj->pszVarPrefix[cch], pObj->pszName, pObj->cchName);
    283760
    284761    /*
     
    291768        {
    292769            /* Inheritance directive. */
    293             if (pData->pszParent != NULL)
     770            if (pObj->pszParent != NULL)
    294771                fatal(pFileLoc, _("'extending' can only occure once"));
    295             pData->pszParent = allocate_expanded_next_token(&pszLine, pszEos, &cch, 1 /*strip*/);
    296             if (!pData->pszParent || !*pData->pszParent)
     772            pObj->pszParent = allocate_expanded_next_token(&pszLine, pszEos, &pObj->cchParent, 1 /*strip*/);
     773            if (!pObj->pszParent || !*pObj->pszParent)
    297774                fatal(pFileLoc, _("'extending' requires a parent name"));
    298 
    299             pData->enmExtendBy = kBuildExtendBy_Overriding;
    300 
    301             /* optionally 'by overriding|prepending|appending' */
    302             psz = find_next_token_eos(&pszLine, pszEos, &cch);
    303             if (psz && WORD_IS(psz, cch, "by"))
    304             {
    305                 cch = 0;
    306                 psz = find_next_token_eos(&pszLine, pszEos, &cch);
    307                 if (WORD_IS(psz, cch, "overriding"))
    308                     pData->enmExtendBy = kBuildExtendBy_Overriding;
    309                 else if (WORD_IS(psz, cch, "appending"))
    310                     pData->enmExtendBy = kBuildExtendBy_Appending;
    311                 else if (WORD_IS(psz, cch, "prepending"))
    312                     pData->enmExtendBy = kBuildExtendBy_Prepending;
    313                 else
    314                     fatal(pFileLoc, _("Unknown 'extending by' method '%.*s'"), (int)cch, psz);
    315 
    316                 /* next token */
    317                 psz = find_next_token_eos(&pszLine, pszEos, &cch);
    318             }
    319775        }
    320776        else if (WORD_IS(psz, cch, "using"))
    321777        {
     778            char   *pszTemplate;
     779            size_t  cchTemplate;
     780
    322781            /* Template directive. */
    323             if (enmKind != kBuildDef_Tool)
     782            if (enmType != kBuildType_Target)
    324783                fatal(pFileLoc, _("'using <template>' can only be used with 'kBuild-define-target'"));
    325             if (pData->pszTemplate != NULL)
     784            if (pObj->pszTemplate != NULL)
    326785                fatal(pFileLoc, _("'using' can only occure once"));
    327786
    328             pData->pszTemplate = allocate_expanded_next_token(&pszLine, pszEos, &cch, 1 /*fStrip*/);
    329             if (!pData->pszTemplate || !*pData->pszTemplate)
     787            pszTemplate = allocate_expanded_next_token(&pszLine, pszEos, &cchTemplate, 1 /*fStrip*/);
     788            if (!pszTemplate || !*pszTemplate)
    330789                fatal(pFileLoc, _("'using' requires a template name"));
     790
     791            define_kbuild_object_variable_cached(pObj, g_pszVarNmTemplate, pszTemplate, cchTemplate,
     792                                                 0 /*fDuplicateValue*/, o_default, 0 /*fRecursive*/, pFileLoc),
    331793
    332794            /* next token */
     
    338800
    339801    /*
    340      * Calc the variable prefix.
    341      */
    342     switch (enmKind)
    343     {
    344         case kBuildDef_Target:      pszPrefix = ""; break;
    345         case kBuildDef_Template:    pszPrefix = "TEMPLATE_"; break;
    346         case kBuildDef_Tool:        pszPrefix = "TOOL_"; break;
    347         case kBuildDef_Sdk:         pszPrefix = "SDK_"; break;
    348         case kBuildDef_Unit:        pszPrefix = "UNIT_"; break;
    349         default:
    350             fatal(pFileLoc, _("enmKind=%d"), enmKind);
    351             return -1;
    352     }
    353     cch = strlen(pszPrefix);
    354     pData->cchVarPrefix = cch + cchName;
    355     pData->pszVarPrefix = xmalloc(pData->cchVarPrefix + 1);
    356     memcpy(pData->pszVarPrefix, pszPrefix, cch);
    357     memcpy(&pData->pszVarPrefix[cch], pData->pszName, cchName);
    358 
    359     /*
    360      * Try resolve the parent and change the current variable set.
    361      */
    362     eval_kbuild_resolve_parent(pData);
    363     pData->pVariablesSaved = current_variable_set_list;
    364     current_variable_set_list = pData->pVariables;
     802     * Try resolve the parent.
     803     */
     804    eval_kbuild_resolve_parent(pObj, 1 /*fQuiet*/);
     805
     806    /*
     807     * Create an eval stack entry and change the current variable set.
     808     */
     809    pData = xmalloc(sizeof(*pData));
     810    pData->pObj             = pObj;
     811    pData->pVariablesSaved  = current_variable_set_list;
     812    current_variable_set_list = pObj->pVariables;
     813
     814    pData->pStackDown       = *ppData;
     815    *ppData                 = pData;
     816    g_pTopKbEvalData        = pData;
    365817
    366818    return 0;
     
    369821static int
    370822eval_kbuild_endef_xxxx(struct kbuild_eval_data **ppData, const struct floc *pFileLoc,
    371                        const char *pszLine, const char *pszEos, int fIgnoring, enum kBuildDef enmKind)
     823                       const char *pszLine, const char *pszEos, int fIgnoring, enum kBuildType enmType)
    372824{
    373825    struct kbuild_eval_data *pData;
    374     unsigned int             cchName;
     826    struct kbuild_object    *pObj;
     827    size_t                   cchName;
    375828    char                    *pszName;
    376829
     
    385838    {
    386839        error(pFileLoc, _("kBuild-endef-%s is missing kBuild-define-%s"),
    387               eval_kbuild_kind_to_string(enmKind), eval_kbuild_kind_to_string(enmKind));
     840              eval_kbuild_type_to_string(enmType), eval_kbuild_type_to_string(enmType));
    388841        return 0;
    389842    }
     
    392845     * ... and does it have a matching kind?
    393846     */
    394     if (pData->enmKind != enmKind)
     847    pObj = pData->pObj;
     848    if (pObj->enmType != enmType)
    395849        error(pFileLoc, _("'kBuild-endef-%s' does not match 'kBuild-define-%s %s'"),
    396               eval_kbuild_kind_to_string(enmKind), eval_kbuild_kind_to_string(pData->enmKind), pData->pszName);
     850              eval_kbuild_type_to_string(enmType), eval_kbuild_type_to_string(pObj->enmType), pObj->pszName);
    397851
    398852    /*
     
    403857    if (pszName)
    404858    {
    405         if (strcmp(pszName, pData->pszName))
     859        if (   cchName != pObj->cchName
     860            || strcmp(pszName, pObj->pszName))
    406861            error(pFileLoc, _("'kBuild-endef-%s %s' does not match 'kBuild-define-%s %s'"),
    407                   eval_kbuild_kind_to_string(enmKind), pszName,
    408                   eval_kbuild_kind_to_string(pData->enmKind), pData->pszName);
     862                  eval_kbuild_type_to_string(enmType), pszName,
     863                  eval_kbuild_type_to_string(pObj->enmType), pObj->pszName);
    409864        free(pszName);
    410865    }
     
    413868     * Pop a define off the stack.
    414869     */
    415     assert(pData == g_pTopKbDef);
    416     *ppData = g_pTopKbDef = pData->pStackDown;
     870    assert(pData == g_pTopKbEvalData);
     871    *ppData = g_pTopKbEvalData = pData->pStackDown;
    417872    pData->pStackDown      = NULL;
    418873    current_variable_set_list = pData->pVariablesSaved;
    419874    pData->pVariablesSaved = NULL;
     875    free(pData);
    420876
    421877    return 0;
    422878}
    423879
    424 int eval_kbuild_define(struct kbuild_eval_data **kdata, const struct floc *flocp,
    425                        const char *word, unsigned int wlen, const char *line, const char *eos, int ignoring)
    426 {
    427     assert(memcmp(word, "kBuild-define", sizeof("kBuild-define") - 1) == 0);
    428     word += sizeof("kBuild-define") - 1;
    429     wlen -= sizeof("kBuild-define") - 1;
    430     if (   wlen > 1
    431         && word[0] == '-')
    432     {
    433         if (WORD_IS(word, wlen, "-target"))
    434             return eval_kbuild_define_xxxx(kdata, flocp, line, eos,  ignoring, kBuildDef_Target);
    435         if (WORD_IS(word, wlen, "-template"))
    436             return eval_kbuild_define_xxxx(kdata, flocp, line, eos,  ignoring, kBuildDef_Template);
    437         if (WORD_IS(word, wlen, "-tool"))
    438             return eval_kbuild_define_xxxx(kdata, flocp, line, eos,  ignoring, kBuildDef_Tool);
    439         if (WORD_IS(word, wlen, "-sdk"))
    440             return eval_kbuild_define_xxxx(kdata, flocp, line, eos,  ignoring, kBuildDef_Sdk);
    441         if (WORD_IS(word, wlen, "-unit"))
    442             return eval_kbuild_define_xxxx(kdata, flocp, line, eos,  ignoring, kBuildDef_Unit);
    443     }
    444 
    445     error(flocp, _("Unknown syntax 'kBuild-define%.*s'"), (int)wlen, word);
     880int eval_kbuild_read_hook(struct kbuild_eval_data **kdata, const struct floc *flocp,
     881                          const char *pchWord, size_t cchWord, const char *line, const char *eos, int ignoring)
     882{
     883    enum kBuildType enmType;
     884
     885    /*
     886     * Skip the 'kBuild-' prefix that the caller already matched.
     887     */
     888    assert(memcmp(pchWord, "kBuild-", sizeof("kBuild-") - 1) == 0);
     889    pchWord += sizeof("kBuild-") - 1;
     890    cchWord -= sizeof("kBuild-") - 1;
     891
     892    /*
     893     * String switch.
     894     */
     895    if (   cchWord >= sizeof("define-") - 1
     896        && strneq(pchWord, "define-", sizeof("define-") - 1))
     897    {
     898        enmType = eval_kbuild_type_from_string(pchWord + sizeof("define-") - 1, cchWord - sizeof("define-") + 1);
     899        if (enmType != kBuildType_Invalid)
     900            return eval_kbuild_define_xxxx(kdata, flocp, line, eos, ignoring, enmType);
     901    }
     902    else if (   cchWord >= sizeof("endef-") - 1
     903             && strneq(pchWord, "endef-", sizeof("endef-") - 1))
     904    {
     905        enmType = eval_kbuild_type_from_string(pchWord + sizeof("endif-") - 1, cchWord - sizeof("endif-") + 1);
     906        if (enmType != kBuildType_Invalid)
     907            return eval_kbuild_endef_xxxx(kdata, flocp, line, eos, ignoring, enmType);
     908    }
     909    else if (WORD_IS(pchWord, cchWord, "endef"))
     910    {
     911        /* Terminate whatever definition is on top. */
     912
     913    }
     914
     915    /*
     916     * Everything that is prefixed with 'kBuild-' is reserved for language
     917     * extensions, at least until legacy assignments/whatever turns up.
     918     */
     919    error(flocp, _("Unknown syntax 'kBuild-%.*s'"), (int)cchWord, pchWord);
    446920    return 0;
    447921}
    448922
    449 int eval_kbuild_endef(struct kbuild_eval_data **kdata, const struct floc *flocp,
    450                       const char *word, unsigned int wlen, const char *line, const char *eos, int ignoring)
    451 {
    452     assert(memcmp(word, "kBuild-endef", sizeof("kBuild-endef") - 1) == 0);
    453     word += sizeof("kBuild-endef") - 1;
    454     wlen -= sizeof("kBuild-endef") - 1;
    455     if (   wlen > 1
    456         && word[0] == '-')
    457     {
    458         if (WORD_IS(word, wlen, "-target"))
    459             return eval_kbuild_endef_xxxx(kdata, flocp, line, eos,  ignoring, kBuildDef_Target);
    460         if (WORD_IS(word, wlen, "-template"))
    461             return eval_kbuild_endef_xxxx(kdata, flocp, line, eos,  ignoring, kBuildDef_Template);
    462         if (WORD_IS(word, wlen, "-tool"))
    463             return eval_kbuild_endef_xxxx(kdata, flocp, line, eos,  ignoring, kBuildDef_Tool);
    464         if (WORD_IS(word, wlen, "-sdk"))
    465             return eval_kbuild_endef_xxxx(kdata, flocp, line, eos,  ignoring, kBuildDef_Sdk);
    466         if (WORD_IS(word, wlen, "-unit"))
    467             return eval_kbuild_endef_xxxx(kdata, flocp, line, eos,  ignoring, kBuildDef_Unit);
    468     }
    469 
    470     error(flocp, _("Unknown syntax 'kBuild-endef%.*s'"), (int)wlen, word);
     923
     924/** @name kBuild object variable accessor related functions
     925 * @{
     926 */
     927
     928/**
     929 * Checks if the given name is an object variable accessor.
     930 *
     931 * @returns 1 if it is, 0 if it isn't.
     932 * @param   pchName             The potential kBuild variable accessor
     933 *                              expression.
     934 * @param   cchName             Length of the expression.
     935 */
     936int is_kbuild_object_variable_accessor(const char *pchName, size_t cchName)
     937{
     938    char const *pchTmp;
     939
     940    /* See lookup_kbuild_object_variable for the rules. */
     941    if (cchName >= 1+1+1+1 && *pchName == '[')
     942    {
     943        pchName++;
     944        cchName--;
     945
     946        pchTmp = memchr(pchName, '@', cchName);
     947        if (pchTmp)
     948        {
     949            cchName -= pchTmp + 1 - pchName;
     950            pchName  = pchTmp + 1;
     951            pchTmp = memchr(pchName, ']', cchName);
     952            if (pchTmp)
     953            {
     954                cchName -= pchTmp + 1 - pchName;
     955                if (cchName > 0)
     956                    return 1;
     957            }
     958        }
     959    }
    471960    return 0;
    472961}
    473962
     963/**
     964 * Parses a kBuild object variable accessor, resolving the object.
     965 *
     966 * @returns Pointer to the variable if found.
     967 * @retval  NULL if the object (or type) couldn't be resolved.
     968 * @retval  KOBJ_NOT_KBUILD_ACCESSOR if no a kBuild variable accessor.
     969 *
     970 * @param   pchExpr             The kBuild variable accessor expression.
     971 * @param   cchExpr             Length of the expression.
     972 * @param   enmSeverity         The minimum severity level for errors.
     973 * @param   pFileLoc            The file location any errors should be reported
     974 *                              at. Optional.
     975 * @param   ppchVarNm           Where to return the pointer to the start of the
     976 *                              variable name within the string @a pchExpr
     977 *                              points to. Mandatory.
     978 * @param   pcchVarNm           Where to return the length of the variable name.
     979 *                              Mandatory.
     980 * @param   penmType            Where to return the object type. Optional.
     981 */
     982static struct kbuild_object *
     983parse_kbuild_object_variable_accessor(const char *pchExpr, size_t cchExpr,
     984                                      enum kBuildSeverity enmSeverity, const struct floc *pFileLoc,
     985                                      const char **ppchVarNm, size_t *pcchVarNm, enum kBuildType *penmType)
     986{
     987    const char * const pchOrgExpr = pchExpr;
     988    size_t       const cchOrgExpr = cchExpr;
     989    char const        *pchTmp;
     990
     991    /*
     992     * To accept this as an kBuild accessor, we require:
     993     *   1. Open bracket.
     994     *   2. At sign separating the type from the name.
     995     *   3. Closing bracket.
     996     *   4. At least one character following it.
     997     */
     998    if (cchExpr >= 1+1+1+1 && *pchExpr == '[')
     999    {
     1000        pchExpr++;
     1001        cchExpr--;
     1002
     1003        pchTmp = memchr(pchExpr, '@', cchExpr);
     1004        if (pchTmp)
     1005        {
     1006            const char  * const pchType = pchExpr;
     1007            size_t        const cchType = pchTmp - pchExpr;
     1008
     1009            cchExpr -= cchType + 1;
     1010            pchExpr  = pchTmp + 1;
     1011            pchTmp = memchr(pchExpr, ']', cchExpr);
     1012            if (pchTmp)
     1013            {
     1014                const char * const pchObjName = pchExpr;
     1015                size_t       const cchObjName = pchTmp - pchExpr;
     1016
     1017                cchExpr -= cchObjName + 1;
     1018                pchExpr  = pchTmp + 1;
     1019                if (cchExpr > 0)
     1020                {
     1021                    enum kBuildType enmType;
     1022
     1023                    *pcchVarNm = cchExpr;
     1024                    *ppchVarNm = pchExpr;
     1025
     1026                    /*
     1027                     * It's an kBuild define variable accessor, alright.
     1028                     */
     1029                    enmType = eval_kbuild_type_from_string(pchType, cchType);
     1030                    if (penmType)
     1031                        *penmType = enmType;
     1032                    if (enmType != kBuildType_Invalid)
     1033                    {
     1034                        struct kbuild_object *pObj = lookup_kbuild_object(enmType, pchObjName, cchObjName);
     1035                        if (pObj)
     1036                            return pObj;
     1037
     1038                        /* failed. */
     1039                        kbuild_report_problem(enmSeverity, pFileLoc,
     1040                                              _("kBuild object '%s' not found in kBuild variable accessor '%.*s'"),
     1041                                              (int)cchObjName, pchObjName, (int)cchOrgExpr, pchOrgExpr);
     1042                    }
     1043                    else
     1044                        kbuild_report_problem(MAX(enmSeverity, kBuildSeverity_Error), pFileLoc,
     1045                                              _("Invalid type '%.*s' specified in kBuild variable accessor '%.*s'"),
     1046                                              (int)cchType, pchType, (int)cchOrgExpr, pchOrgExpr);
     1047                    return NULL;
     1048                }
     1049            }
     1050        }
     1051    }
     1052
     1053    *ppchVarNm = NULL;
     1054    *pcchVarNm = 0;
     1055    if (penmType)
     1056        *penmType = kBuildType_Invalid;
     1057    return KOBJ_NOT_KBUILD_ACCESSOR;
     1058}
     1059
     1060/**
     1061 * Looks up a variable in a kBuild object.
     1062 *
     1063 * The caller has done minimal matching, i.e. starting square brackets and
     1064 * minimum length.  We do the rest here.
     1065 *
     1066 * @returns Pointer to the variable if found.
     1067 * @retval  NULL if not found.
     1068 * @retval  VAR_NOT_KBUILD_ACCESSOR if no a kBuild variable accessor.
     1069 *
     1070 * @param   pchName             The kBuild variable accessor expression.
     1071 * @param   cchName             Length of the expression.
     1072 */
     1073struct variable *
     1074lookup_kbuild_object_variable_accessor(const char *pchName, size_t cchName)
     1075{
     1076    const char * const     pchOrgName = pchName;
     1077    size_t       const     cchOrgName = cchName;
     1078    const char *           pchVarNm;
     1079    size_t                 cchVarNm;
     1080    struct kbuild_object  *pObj;
     1081
     1082    pObj = parse_kbuild_object_variable_accessor(pchName, cchName, kBuildSeverity_Warning, NULL, &pchVarNm, &cchVarNm, NULL);
     1083    if (pObj != KOBJ_NOT_KBUILD_ACCESSOR)
     1084    {
     1085        if (pObj)
     1086        {
     1087            /*
     1088             * Do the variable lookup.
     1089             */
     1090            const char *pszCachedName = strcache2_lookup(&variable_strcache, pchVarNm, cchVarNm);
     1091            if (pszCachedName)
     1092            {
     1093                struct variable  VarKey;
     1094                struct variable *pVar;
     1095                VarKey.name   = pszCachedName;
     1096                VarKey.length = cchName;
     1097
     1098                pVar = (struct variable *)hash_find_item_strcached(&pObj->pVariables->set->table, &VarKey);
     1099                if (pVar)
     1100                    return pVar;
     1101
     1102                /*
     1103                 * Not found, check ancestors if any.
     1104                 */
     1105                if (pObj->pszParent || pObj->pszTemplate)
     1106                {
     1107                    struct kbuild_object *pParent = pObj;
     1108                    for (;;)
     1109                    {
     1110                        pParent = eval_kbuild_resolve_parent(pParent, 0 /*fQuiet*/);
     1111                        if (!pParent)
     1112                            break;
     1113                        pVar = (struct variable *)hash_find_item_strcached(&pParent->pVariables->set->table, &VarKey);
     1114                        if (pVar)
     1115                            return pVar;
     1116                    }
     1117                }
     1118            }
     1119        }
     1120
     1121        /* Not found one way or the other. */
     1122        return NULL;
     1123    }
     1124
     1125    /* Not a kBuild object variable accessor. */
     1126    return VAR_NOT_KBUILD_ACCESSOR;
     1127}
     1128
     1129/** @} */
     1130
    4741131void print_kbuild_data_base(void)
    4751132{
    476     struct kbuild_eval_data *pCur;
     1133    struct kbuild_object *pCur;
    4771134
    4781135    puts(_("\n# kBuild defines"));
    4791136
    480     for (pCur = g_pHeadKbDefs; pCur; pCur = pCur->pGlobalNext)
     1137    for (pCur = g_pHeadKbObjs; pCur; pCur = pCur->pGlobalNext)
    4811138    {
    4821139        printf("\nkBuild-define-%s %s",
    483                eval_kbuild_kind_to_string(pCur->enmKind), pCur->pszName);
     1140               eval_kbuild_type_to_string(pCur->enmType), pCur->pszName);
    4841141        if (pCur->pszParent)
    485         {
    4861142            printf(" extending %s", pCur->pszParent);
    487             switch (pCur->enmExtendBy)
    488             {
    489                 case kBuildExtendBy_Overriding: break;
    490                 case kBuildExtendBy_Appending:  printf(" by appending"); break;
    491                 case kBuildExtendBy_Prepending: printf(" by prepending"); break;
    492                 default:                        printf(" by ?!?");
    493             }
    494         }
    4951143        if (pCur->pszTemplate)
    4961144            printf(" using %s", pCur->pszTemplate);
     
    5001148
    5011149        printf("kBuild-endef-%s  %s\n",
    502                eval_kbuild_kind_to_string(pCur->enmKind), pCur->pszName);
     1150               eval_kbuild_type_to_string(pCur->enmType), pCur->pszName);
    5031151    }
    5041152    /** @todo hash stats. */
Note: See TracChangeset for help on using the changeset viewer.