VirtualBox

Changeset 2717 in kBuild for trunk/src/kmk


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

kmk: Hacking kBuild-define-*.

Location:
trunk/src/kmk
Files:
7 edited

Legend:

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

    r2549 r2717  
    55
    66/*
    7  * Copyright (c) 2011 knut st. osmundsen <[email protected]>
     7 * Copyright (c) 2011-2013 knut st. osmundsen <[email protected]>
    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. */
  • trunk/src/kmk/kbuild.h

    r2549 r2717  
    3939const char *get_default_kbuild_shell(void);
    4040
     41/** @name kBuild objects
     42 * @{ */
    4143struct kbuild_eval_data;
    42 extern struct kbuild_eval_data *g_pTopKbDef;
    43 struct variable_set *get_top_kbuild_variable_set(void);
    44 char *kbuild_prefix_variable(const char *pszName, unsigned int *pcchName);
     44struct kbuild_object;
    4545
    46 int eval_kbuild_define(struct kbuild_eval_data **kdata, const struct floc *flocp,
    47                        const char *word, unsigned int wlen, const char *line, const char *eos, int ignoring);
    48 int eval_kbuild_endef(struct kbuild_eval_data **kdata, const struct floc *flocp,
    49                       const char *word, unsigned int wlen, const char *line, const char *eos, int ignoring);
     46extern struct kbuild_eval_data *g_pTopKbEvalData;
    5047
    51 void print_kbuild_data_base(void);
    52 void print_kbuild_define_stats(void);
     48
     49/** Special return value indicating variable name isn't an accessor. */
     50#define KOBJ_NOT_KBUILD_ACCESSOR    ( (struct kbuild_object *)~(size_t)0 )
     51
     52/** Special lookup_kbuild_object_variable return value. */
     53#define VAR_NOT_KBUILD_ACCESSOR     ( (struct variable *)~(size_t)0 )
     54
     55struct variable    *lookup_kbuild_object_variable_accessor(const char *pchName, size_t cchName);
     56int                 is_kbuild_object_variable_accessor(const char *pchName, size_t cchName);
     57struct variable    *try_define_kbuild_object_variable_via_accessor(const char *pszName, size_t cchName,
     58                                                                   const char *pszValue, size_t cchValue, int fDuplicateValue,
     59                                                                   enum variable_origin enmOrigin, int fRecursive,
     60                                                                   struct floc const *pFileLoc);
     61struct variable    *define_kbuild_object_variable_in_top_obj(const char *pszName, size_t cchName,
     62                                                             const char *pszValue, size_t cchValue, int fDuplicateValue,
     63                                                             enum variable_origin enmOrigin, int fRecursive,
     64                                                             struct floc const *pFileLoc);
     65struct variable    *kbuild_object_variable_pre_append(const char *pchName, size_t cchName,
     66                                                      const char *pchValue, size_t cchValue, int fSimpleValue,
     67                                                      enum variable_origin enmOrigin, int fAppend,
     68                                                      const struct floc *pFileLoc);
     69int                 eval_kbuild_read_hook(struct kbuild_eval_data **kdata, const struct floc *flocp,
     70                                          const char *word, size_t wlen, const char *line, const char *eos, int ignoring);
     71void                print_kbuild_data_base(void);
     72void                print_kbuild_define_stats(void);
     73void                init_kbuild_object(void);
     74/** @} */
    5375
    5476#endif
  • trunk/src/kmk/main.c

    r2705 r2717  
    15841584#endif
    15851585  initialize_global_hash_tables ();
     1586#ifdef KMK
     1587  init_kbuild_object ();
     1588#endif
    15861589
    15871590  /* Figure out where we are.  */
  • trunk/src/kmk/read.c

    r2591 r2717  
    961961#ifdef KMK
    962962      /* Check for the kBuild language extensions. */
    963       if (   wlen >= sizeof("kBuild-define") - 1
    964           && strneq (p, "kBuild-define", sizeof("kBuild-define") - 1))
    965         krc = eval_kbuild_define (&kdata, fstart, p, wlen, p2, eol, ignoring);
    966       else if (   wlen >= sizeof("kBuild-endef") - 1
    967                && strneq (p, "kBuild-endef", sizeof("kBuild-endef") - 1))
    968         krc = eval_kbuild_endef (&kdata, fstart, p, wlen, p2, eol, ignoring);
    969       else
    970         krc = 42;
    971       if (krc != 42)
     963      if (   wlen > sizeof("kBuild-")
     964          && strneq (p, "kBuild-", sizeof("kBuild-") - 1))
    972965        {
    973           if (krc != 0)
    974             error (fstart, _("krc=%d"), krc);
    975           continue;
     966          krc = eval_kbuild_read_hook (&kdata, fstart, p, wlen, p2, eol, ignoring);
     967          if (krc != 42)
     968            {
     969              if (krc != 0)
     970                error (fstart, _("krc=%d"), krc);
     971              continue;
     972            }
    976973        }
    977 
    978974#endif /* KMK */
    979975
     
    18521848    definition[idx - 1] = '\0';
    18531849
     1850#ifndef CONFIG_WITH_VALUE_LENGTH
    18541851  v = do_variable_definition (&defstart, name, definition, origin, flavor, 0);
     1852#else
     1853  v = do_variable_definition_2 (&defstart, name, definition,
     1854                                idx ? idx - 1 : idx,  flavor == f_simple,
     1855                                0 /* free_value */, origin, flavor,
     1856                                0 /*target_var*/);
     1857#endif
    18551858  free (definition);
    18561859  free (var);
  • trunk/src/kmk/testcase-kBuild-define.kmk

    r2658 r2717  
    55
    66#
    7 # Copyright (c) 2011-2012 knut st. osmundsen <[email protected]>
     7# Copyright (c) 2011-2013 knut st. osmundsen <[email protected]>
    88#
    99# This file is part of kBuild.
     
    2424#
    2525
    26 DEPTH = ../..
     26#DEPTH = ../..
    2727#include $(PATH_KBUILD)/header.kmk
    2828
     29if 0
    2930# object definition syntax:
    30 #      kobject <type> <name> [extends <object>] [object specific args...]
    31 #      endkobj [<type> [name]]
     31#      kobject <type> <name> [extends <object> [by <||>]] [object specific args...]
     32#      kendobj [<type> [name]]
    3233kobject kb-target MyTarget
    3334.TOOL = GCC
    3435.SOURCES = file.c
    35 endobj
     36kendobj
     37else
     38# Target definition.
     39#      kBuild-define-target <name> [extends <target> [by <||>]] [using <template>]
     40#      kBuild-endef-target [name]
     41kBuild-define-target MyTarget
     42_TOOL = GCC
     43_SOURCES = file.c
     44kBuild-endef-target
     45endif
    3646
     47if 0
    3748# accesses an already defined object.
    3849# syntax:
    3950#      kaccess <type> <name>
    40 #      endkacc [<type> [name]]
     51#      kendacc [<type> [name]]
    4152kaccess kb-target MyTarget
    4253.SOURCES += file2.c
    43 endkacc
     54kendacc
     55else
     56#kBuild-access-target MyTarget
     57#_SOURCES += file2.c
     58#kBuild-endacc-target
     59endif
    4460
    4561
    4662# Referencing an object variable, the object must exist.
    4763# syntax: [<type>@<name>].<property>
    48 [kb-target@MyTarget].SOURCES += file3.c
    49 $(info [kb-target@MyTarget].SOURCES is $([kb-target@MyTarget].SOURCES))
     64[target@MyTarget]_SOURCES += file3.c
     65$(info [target@MyTarget]_SOURCES is $([target@MyTarget]_SOURCES))
    5066
    5167
    5268# Test #1
    53 kobject target BaseTarget with DUMMY as template
    54 .SOURCES = BaseTargetSource.c
    55 kendobj
    56 $(if "$([target@BaseTarget].SOURCES)" == "BaseTargetSource.c",,$(error [target@BaseTarget].SOURCES is '$([target@BaseTarget].SOURCES)' not 'BaseTargetSource.c'))
    57 $(if "$(BaseTarget_SOURCES)" == "BaseTargetSource.c",,$(error BaseTarget's _SOURCES wasn't set correctly in the global space))
     69kBuild-define-target BaseTarget using DUMMY
     70_SOURCES = BaseTargetSource.c
     71kBuild-endef-target BaseTarget
     72$(if-expr "$([target@BaseTarget]_SOURCES)" == "BaseTargetSource.c",,$(error [target@BaseTarget]_SOURCES is '$([target@BaseTarget]_SOURCES)' not 'BaseTargetSource.c'))
     73$(if-expr "$(BaseTarget_SOURCES)" == "BaseTargetSource.c",,$(error BaseTarget's _SOURCES wasn't set correctly in the global space))
    5874
    59 $(if "$([target@BaseTarget].TEMPLATE)" == "DUMMY",,$(error [target@BaseTarget].TEMPLATE is '$([target@BaseTarget].TEMPLATE)' not 'DUMMY'))
    60 $(if "$(BaseTarget_TEMPLATE)" == "DUMMY",,$(error BaseTarget's _TEMPLATE wasn't set correctly in the global space))
     75$(if-expr "$([target@BaseTarget]_TEMPLATE)" == "DUMMY",,$(error [target@BaseTarget]_TEMPLATE is '$([target@BaseTarget]_TEMPLATE)' not 'DUMMY'))
     76$(if-expr "$(BaseTarget_TEMPLATE)" == "DUMMY",,$(error BaseTarget's _TEMPLATE wasn't set correctly in the global space))
    6177
    6278# Test #2
    63 kobject target TargetWithLocals
    64 local .LOCAL_PROP = no global alias
    65 kendobj
    66 $(if "$([target@TargetWithLocals].LOCAL_PROP)" == "no global alias",,$(error [target@TargetWithLocals].LOCAL_PROP is '$([target@TargetWithLocals].LOCAL_PROP)' not 'no global alias'))
    67 $(if "$(TargetWithLocals_LOCAL_PROP)" == "",,$(error TargetWithLocals_LOCAL_PROP's local property 'LOCAL_PROP' was exposed globally.))
     79kBuild-define-target TargetWithLocals
     80local _LOCAL_PROP = no global alias
     81kBuild-endef-target
     82$(if-expr "$([target@TargetWithLocals]_LOCAL_PROP)" == "no global alias",,$(error [target@TargetWithLocals]_LOCAL_PROP is '$([target@TargetWithLocals]_LOCAL_PROP)' not 'no global alias'))
     83$(if-expr "$(TargetWithLocals_LOCAL_PROP)" == "",,$(error TargetWithLocals_LOCAL_PROP's local property 'LOCAL_PROP' was exposed globally.))
    6884
     85# Test #3
     86kBuild-define-target OutsideMod
     87_SOURCES = file3.c
     88_OTHER   = inside-value
     89kBuild-endef-target
     90[target@OutsideMod]_SOURCES += file4.c
     91[target@OutsideMod]_SOURCES <= file2.c
     92[target@OutsideMod]_OTHER   = outside-value
     93$(if-expr "$([target@OutsideMod]_SOURCES)" == "file2.c file3.c file4.c",,$(error [target@OutsideMod]_SOURCES is '$([target@OutsideMod]_SOURCES)' not 'file2.c file3.c file4.c'))
     94$(if-expr "OutsideMod_SOURCES"             == "file2.c file3.c file4.c",,$(error OutsideMod_SOURCES is '$(OutsideMod_SOURCES)' not 'file2.c file3.c file4.c'))
     95
     96$(if-expr "$([target@OutsideMod]_OTHER)" == "outside-value",,$(error [target@OutsideMod]_OTHER is '$([target@OutsideMod]_OTHER)' not 'outside-value'))
     97$(if-expr "$(OutsideMod_OTHER)"          == "outside-value",,$(error OutsideMod_OTHER is '$(OutsideMod_OTHER)' not 'outside-value'))
    6998
    7099all_recursive:
    71         #$(ECHO) "kBuild-define-xxxx works fine"
     100        @kmk_echo "kBuild-define-xxxx works fine"
    72101
  • trunk/src/kmk/variable.c

    r2591 r2717  
    202202#endif
    203203
     204
     205#ifdef KMK /* Drop the 'static' */
     206struct variable_set global_variable_set;
     207struct variable_set_list global_setlist
     208#else
    204209static struct variable_set global_variable_set;
    205210static struct variable_set_list global_setlist
     211#endif
    206212  = { 0, &global_variable_set, 0 };
    207213struct variable_set_list *current_variable_set_list = &global_setlist;
     
    249255  struct variable var_key;
    250256
     257  if (env_overrides && origin == o_env)
     258    origin = o_env_override;
     259
    251260#ifndef KMK
    252261  if (set == NULL)
    253262    set = &global_variable_set;
    254 #else
     263#else /* KMK */
     264  /* Intercept kBuild object variable definitions. */
     265  if (name[0] == '[' && length > 3)
     266    {
     267      v = try_define_kbuild_object_variable_via_accessor (name, length,
     268                                                          value, value_len, duplicate_value,
     269                                                          origin, recursive, flocp);
     270      if (v != VAR_NOT_KBUILD_ACCESSOR)
     271        return v;
     272    }
    255273  if (set == NULL)
    256274    {
    257       /* underscore prefixed variables are automatically local in
    258          kBuild-define-* scopes.  They also get a global definition with
    259          the current scope prefix. */
    260       if (g_pTopKbDef && length > 0 && name[0] == '_')
    261         {
    262           char         *prefixed_nm;
    263           unsigned int  prefixed_nm_len;
    264 
    265           set = get_top_kbuild_variable_set();
    266           v = define_variable_in_set(name, length, value, value_len,
    267                                      1 /* duplicate_value */,
    268                                      origin, recursive, set, flocp);
    269 
    270           prefixed_nm_len = length;
    271           prefixed_nm = kbuild_prefix_variable(name, &prefixed_nm_len);
    272           define_variable_in_set(prefixed_nm, prefixed_nm_len,
    273                                  value, value_len, duplicate_value,
    274                                  origin, recursive, &global_variable_set,
    275                                  flocp);
    276           free(prefixed_nm);
    277           return v;
    278         }
     275      if (g_pTopKbEvalData)
     276        return define_kbuild_object_variable_in_top_obj (name, length,
     277                                                         value, value_len, duplicate_value,
     278                                                         origin, recursive, flocp);
    279279      set = &global_variable_set;
    280280    }
    281 #endif
     281#endif /* KMK */
    282282
    283283#ifndef CONFIG_WITH_STRCACHE2
     
    286286  var_slot = (struct variable **) hash_find_slot (&set->table, &var_key);
    287287
    288   if (env_overrides && origin == o_env)
    289     origin = o_env_override;
     288  /* if (env_overrides && origin == o_env)
     289    origin = o_env_override; - bird moved this up */
    290290
    291291  v = *var_slot;
    292292#else  /* CONFIG_WITH_STRCACHE2 */
    293   var_key.name = name = strcache2_add (&variable_strcache, name, length);
    294   var_key.length = length;
     293  name = strcache2_add (&variable_strcache, name, length);
    295294  if (   set != &global_variable_set
    296       || !(v = strcache2_get_user_val (&variable_strcache, var_key.name)))
    297     {
     295      || !(v = strcache2_get_user_val (&variable_strcache, name)))
     296    {
     297      var_key.name = name;
     298      var_key.length = length;
    298299      var_slot = (struct variable **) hash_find_slot_strcached (&set->table, &var_key);
    299300      v = *var_slot;
     
    470471    set = &global_variable_set;
    471472
     473#ifndef CONFIG_WITH_STRCACHE2
    472474  var_key.name = (char *) name;
    473475  var_key.length = length;
    474476  var_slot = (struct variable **) hash_find_slot (&set->table, &var_key);
     477#else
     478  var_key.name = strcache2_lookup(&variable_strcache, name, length);
     479  if (!var_key.name)
     480    return;
     481  var_key.length = length;
     482  var_slot = (struct variable **) hash_find_slot_strcached (&set->table, &var_key);
     483#endif
    475484
    476485  if (env_overrides && origin == o_env)
     
    490499        {
    491500          hash_delete_at (&set->table, var_slot);
     501#ifdef CONFIG_WITH_STRCACHE2
     502          if (set == &global_variable_set)
     503            strcache2_set_user_val (&variable_strcache, v->name, NULL);
     504#endif
    492505          free_variable_name_and_value (v);
    493506        }
     
    735748#ifdef CONFIG_WITH_STRCACHE2
    736749  const char *cached_name;
    737 
     750#endif
     751
     752# ifdef KMK
     753  /* Check for kBuild-define- local variable accesses and handle these first. */
     754  if (length > 3 && name[0] == '[')
     755    {
     756      struct variable *v = lookup_kbuild_object_variable_accessor(name, length);
     757      if (v != VAR_NOT_KBUILD_ACCESSOR)
     758        return v;
     759    }
     760# endif
     761
     762#ifdef CONFIG_WITH_STRCACHE2
    738763  /* lookup the name in the string case, if it's not there it won't
    739764     be in any of the sets either. */
     
    851876#else  /* CONFIG_WITH_STRCACHE2 */
    852877  const char *cached_name;
     878
     879# ifdef KMK
     880  /* Check for kBuild-define- local variable accesses and handle these first. */
     881  if (length > 3 && name[0] == '[' && set == &global_variable_set)
     882    {
     883      struct variable *v = lookup_kbuild_object_variable_accessor(name, length);
     884      if (v != VAR_NOT_KBUILD_ACCESSOR)
     885        return v;
     886    }
     887# endif
    853888
    854889  /* lookup the name in the string case, if it's not there it won't
     
    19141949}
    19151950
    1916 static struct variable *
     1951struct variable *
    19171952do_variable_definition_append (const struct floc *flocp, struct variable *v,
    19181953                               const char *value, unsigned int value_len,
     
    19962031  int conditional = 0;
    19972032  const size_t varname_len = strlen (varname); /* bird */
     2033
    19982034#ifdef CONFIG_WITH_VALUE_LENGTH
    1999   assert (value_len == ~0U || value_len == strlen (value));
     2035  if (value_len == ~0U)
     2036    value_len = strlen (value);
     2037  else
     2038    assert (value_len == strlen (value));
    20002039#endif
    20012040
     
    20662105#endif
    20672106
    2068 #ifdef CONFIG_WITH_LOCAL_VARIABLES
    2069           /* If we have += but we're in a target or local variable context,
    2070              we want to append only with other variables in the context of
    2071              this target.  */
    2072         if (target_var || origin == o_local)
    2073 #else
    20742107        /* If we have += but we're in a target variable context, we want to
    20752108           append only with other variables in the context of this target.  */
    20762109        if (target_var)
    2077 #endif
    20782110          {
    20792111            append = 1;
     
    20862118              append = 0;
    20872119          }
     2120#ifdef KMK
     2121        else if (   g_pTopKbEvalData
     2122                 || (   varname_len > 3
     2123                     && varname[0] == '['
     2124                     && is_kbuild_object_variable_accessor (varname, varname_len)) )
     2125          {
     2126            v = kbuild_object_variable_pre_append (varname, varname_len,
     2127                                                   value, value_len, simple_value,
     2128                                                   origin, org_flavor == f_append, flocp);
     2129            if (free_value)
     2130               free (free_value);
     2131            return v;
     2132          }
     2133#endif
     2134#ifdef CONFIG_WITH_LOCAL_VARIABLES
     2135        /* If 'local', restrict it to the current variable context. */
     2136        else if (origin == o_local)
     2137          v = lookup_variable_in_set (varname, varname_len,
     2138                                      current_variable_set_list->set);
     2139#endif
    20882140        else
    20892141          v = lookup_variable (varname, varname_len);
  • trunk/src/kmk/variable.h

    r2591 r2717  
    143143
    144144#ifdef KMK
     145extern struct variable_set global_variable_set;
     146extern struct variable_set_list global_setlist;
    145147extern unsigned int variable_buffer_length;
    146148# define VARIABLE_BUFFER_ZONE   5
     
    351353void append_string_to_variable (struct variable *v, const char *value,
    352354                                unsigned int value_len, int append);
     355struct variable * do_variable_definition_append (const struct floc *flocp, struct variable *v,
     356                                                 const char *value, unsigned int value_len,
     357                                                 int simple_value, enum variable_origin origin,
     358                                                 int append);
    353359
    354360struct variable *define_variable_in_set (const char *name, unsigned int length,
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette