Index: /trunk/src/kmk/Makefile.am
===================================================================
--- /trunk/src/kmk/Makefile.am	(revision 2547)
+++ /trunk/src/kmk/Makefile.am	(revision 2548)
@@ -53,4 +53,5 @@
 		alloccache.c \
 		kbuild.c \
+		kbuild-read.c \
 		electric.c \
 		../lib/md5.c \
Index: /trunk/src/kmk/Makefile.kmk
===================================================================
--- /trunk/src/kmk/Makefile.kmk	(revision 2547)
+++ /trunk/src/kmk/Makefile.kmk	(revision 2548)
@@ -205,4 +205,5 @@
 	main.c \
 	kbuild.c \
+	kbuild-read.c \
 	read.c \
 	expreval.c \
Index: /trunk/src/kmk/expand.c
===================================================================
--- /trunk/src/kmk/expand.c	(revision 2547)
+++ /trunk/src/kmk/expand.c	(revision 2548)
@@ -1116,5 +1116,5 @@
 #ifdef CONFIG_WITH_VALUE_LENGTH
 /* Handle the most common case in allocated_variable_expand_for_file
-   specially and provide some additional string lenght features. */
+   specially and provide some additional string length features. */
 
 char *
Index: /trunk/src/kmk/kbuild-read.c
===================================================================
--- /trunk/src/kmk/kbuild-read.c	(revision 2548)
+++ /trunk/src/kmk/kbuild-read.c	(revision 2548)
@@ -0,0 +1,327 @@
+/* $Id$ */
+/** @file
+ * kBuild specific make functionality related to read.c.
+ */
+
+/*
+ * Copyright (c) 2011 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
+ *
+ * This file is part of kBuild.
+ *
+ * kBuild is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * kBuild is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with kBuild.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* No GNU coding style here! */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "make.h"
+#include "filedef.h"
+#include "variable.h"
+#include "dep.h"
+#include "debug.h"
+#include "kbuild.h"
+
+#include <assert.h>
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+#define WORD_IS(a_pszWord, a_cchWord, a_szWord2) \
+        (  (a_cchWord) == sizeof(a_szWord2) - 1 && memcmp((a_pszWord), a_szWord2, sizeof(a_szWord2) - 1) == 0)
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/** Indicate which kind of kBuild define we're working on.  */
+enum kBuildDef
+{
+    kBuildDef_Invalid,
+    kBuildDef_Target,
+    kBuildDef_Template,
+    kBuildDef_Tool,
+    kBuildDef_Sdk,
+    kBuildDef_Unit
+};
+
+enum kBuildExtendBy
+{
+    kBuildExtendBy_NoParent,
+    kBuildExtendBy_Overriding,
+    kBuildExtendBy_Appending,
+    kBuildExtendBy_Prepending
+};
+
+
+/**
+ * The data we stack during eval.
+ */
+struct kbuild_eval_data
+{
+    /** The kind of define. */
+    enum kBuildDef              enmKind;
+    /** Pointer to the element below us on the stack. */
+    struct kbuild_eval_data    *pDown;
+
+    /** The bare name of the define. */
+    char                       *pszName;
+
+    /** The parent name, NULL if none. */
+    char                       *pszParent;
+    /** The inheritance method. */
+    enum kBuildExtendBy         enmExtendBy;
+
+    /** The template, NULL if none. Only applicable to targets. */
+    char                       *pszTemplate;
+
+    /** The variable prefix*/
+    char                       *pszVarPrefix;
+    /** The length of the variable prefix. */
+    size_t                      cchVarPrefix;
+};
+
+
+static const char *
+eval_kbuild_kind_to_string(enum kBuildDef enmKind)
+{
+    switch (enmKind)
+    {
+        case kBuildDef_Target:      return "target";
+        case kBuildDef_Template:    return "template";
+        case kBuildDef_Tool:        return "tool";
+        case kBuildDef_Sdk:         return "sdk";
+        case kBuildDef_Unit:        return "unit";
+        default:
+        case kBuildDef_Invalid:     return "invalid";
+    }
+}
+
+
+static int
+eval_kbuild_define_xxxx(struct kbuild_eval_data **ppData, const struct floc *pFileLoc,
+                        const char *pszLine, const char *pszEos, int fIgnoring, enum kBuildDef enmKind)
+{
+    unsigned int             cch;
+    char                    *psz;
+    struct kbuild_eval_data *pData;
+
+    /*
+     * Create a new kBuild eval data item unless we're in ignore-mode.
+     */
+    if (fIgnoring)
+        return 0;
+
+    pData = xmalloc(sizeof(*pData));
+    pData->enmKind      = enmKind;
+    pData->pszName      = NULL;
+    pData->pszParent    = NULL;
+    pData->enmExtendBy  = kBuildExtendBy_NoParent;
+    pData->pszTemplate  = NULL;
+    pData->pszVarPrefix = NULL;
+    pData->cchVarPrefix = 0;
+    pData->pDown        = *ppData;
+    *ppData             = pData;
+
+    /*
+     * The first word is the name.
+     */
+    pData->pszName = find_next_token_eos(&pszLine, pszEos, &cch);
+    if (!pData->pszName)
+    {
+        error(pFileLoc, _("The kBuild define requires a name"));
+        return 0;
+    }
+    pData->pszName = allocated_variable_expand_2(pData->pszName, cch, &cch);
+
+    /*
+     * Parse subsequent words.
+     */
+    psz = find_next_token_eos(&pszLine, pszEos, &cch);
+    while (psz)
+    {
+        if (WORD_IS(psz, cch, "extending"))
+        {
+            /* Inheritance directive. */
+            if (pData->pszParent != NULL)
+                fatal(pFileLoc, _("'extending' can only occure once"));
+            pData->pszParent = find_next_token_eos(&pszLine, pszEos, &cch);
+            if (pData->pszParent)
+                pData->pszParent = allocated_variable_expand_2(pData->pszParent, cch, &cch);
+            if (!pData->pszParent || !*pData->pszParent)
+                fatal(pFileLoc, _("'extending' requires a parent name"));
+
+            pData->enmExtendBy = kBuildExtendBy_Overriding;
+
+            /* optionally 'by overriding|prepending|appending' */
+            psz = find_next_token_eos(&pszLine, pszEos, &cch);
+            if (psz && WORD_IS(psz, cch, "by"))
+            {
+                cch = 0;
+                psz = find_next_token_eos(&pszLine, pszEos, &cch);
+                if (WORD_IS(psz, cch, "overriding"))
+                    pData->enmExtendBy = kBuildExtendBy_Overriding;
+                else if (WORD_IS(psz, cch, "appending"))
+                    pData->enmExtendBy = kBuildExtendBy_Appending;
+                else if (WORD_IS(psz, cch, "prepending"))
+                    pData->enmExtendBy = kBuildExtendBy_Prepending;
+                else
+                    fatal(pFileLoc, _("Unknown 'extending by' method '%.*s'"), (int)cch, psz);
+
+                /* next token */
+                psz = find_next_token_eos(&pszLine, pszEos, &cch);
+            }
+        }
+        else if (   WORD_IS(psz, cch, "using")
+                 && enmKind == kBuildDef_Tool)
+        {
+            /* Template directive. */
+            if (pData->pszTemplate != NULL )
+                fatal(pFileLoc, _("'using' can only occure once"));
+            pData->pszTemplate = find_next_token_eos(&pszLine, pszEos, &cch);
+            if (pData->pszTemplate)
+                pData->pszTemplate = allocated_variable_expand_2(pData->pszTemplate, cch, &cch);
+            if (!pData->pszTemplate || !*pData->pszTemplate)
+                fatal(pFileLoc, _("'using' requires a template name"));
+
+            /* next token */
+            psz = find_next_token_eos(&pszLine, pszEos, &cch);
+        }
+        else
+            fatal(pFileLoc, _("Don't know what '%.*s' means"), (int)cch, psz);
+    }
+
+    /*
+     * Calc the variable prefix.
+     */
+
+    /** @todo continue here...  */
+
+
+    return 0;
+}
+
+static int
+eval_kbuild_endef_xxxx(struct kbuild_eval_data **ppData, const struct floc *pFileLoc,
+                       const char *pszLine, const char *pszEos, int fIgnoring, enum kBuildDef enmKind)
+{
+    struct kbuild_eval_data *pData;
+    unsigned int             cchName;
+    char                    *pszName;
+
+    if (fIgnoring)
+        return 0;
+
+    /*
+     * Is there something to pop?
+     */
+    pData = *ppData;
+    if (!pData)
+    {
+        error(pFileLoc, _("kBuild-endef-%s is missing kBuild-define-%s"),
+              eval_kbuild_kind_to_string(enmKind), eval_kbuild_kind_to_string(enmKind));
+        return 0;
+    }
+
+    /*
+     * ... and does it have a matching kind?
+     */
+    if (pData->enmKind != enmKind)
+    {
+        error(pFileLoc, _("'kBuild-endef-%s' does not match 'kBuild-define-%s %s'"),
+              eval_kbuild_kind_to_string(enmKind), eval_kbuild_kind_to_string(pData->enmKind), pData->pszName);
+        return 0;
+    }
+
+    /*
+     * The endef-kbuild may optionally be followed by the target name.
+     * It should match the name given to the kBuild-define.
+     */
+    pszName = find_next_token_eos(&pszLine, pszEos, &cchName);
+    if (pszName)
+    {
+        pszName = allocated_variable_expand_2(pszName, cchName, &cchName);
+        if (strcmp(pszName, pData->pszName))
+            error(pFileLoc, _("'kBuild-endef-%s %s' does not match 'kBuild-define-%s %s'"),
+                  eval_kbuild_kind_to_string(enmKind), pszName,
+                  eval_kbuild_kind_to_string(pData->enmKind), pData->pszName);
+        free(pszName);
+    }
+
+    /*
+     * Pop a define off the stack.
+     */
+    *ppData = pData->pDown;
+    free(pData->pszName);
+    free(pData->pszParent);
+    free(pData->pszTemplate);
+    free(pData->pszVarPrefix);
+    free(pData);
+
+    return 0;
+}
+
+int eval_kbuild_define(struct kbuild_eval_data **kdata, const struct floc *flocp,
+                       const char *word, unsigned int wlen, const char *line, const char *eos, int ignoring)
+{
+    assert(memcmp(word, "kBuild-define", sizeof("kBuild-define") - 1) == 0);
+    word += sizeof("kBuild-define") - 1;
+    wlen -= sizeof("kBuild-define") - 1;
+    if (   wlen > 1
+        && word[0] == '-')
+    {
+        if (WORD_IS(word, wlen, "-target"))
+            return eval_kbuild_define_xxxx(kdata, flocp, line, eos,  ignoring, kBuildDef_Target);
+        if (WORD_IS(word, wlen, "-template"))
+            return eval_kbuild_define_xxxx(kdata, flocp, line, eos,  ignoring, kBuildDef_Template);
+        if (WORD_IS(word, wlen, "-tool"))
+            return eval_kbuild_define_xxxx(kdata, flocp, line, eos,  ignoring, kBuildDef_Tool);
+        if (WORD_IS(word, wlen, "-sdk"))
+            return eval_kbuild_define_xxxx(kdata, flocp, line, eos,  ignoring, kBuildDef_Sdk);
+        if (WORD_IS(word, wlen, "-unit"))
+            return eval_kbuild_define_xxxx(kdata, flocp, line, eos,  ignoring, kBuildDef_Unit);
+    }
+
+    error(flocp, _("Unknown syntax 'kBuild-define%.*s'"), (int)wlen, word);
+    return 0;
+}
+
+int eval_kbuild_endef(struct kbuild_eval_data **kdata, const struct floc *flocp,
+                      const char *word, unsigned int wlen, const char *line, const char *eos, int ignoring)
+{
+    assert(memcmp(word, "kBuild-endef", sizeof("kBuild-endef") - 1) == 0);
+    word += sizeof("kBuild-endef") - 1;
+    wlen -= sizeof("kBuild-endef") - 1;
+    if (   wlen > 1
+        && word[0] == '-')
+    {
+        if (WORD_IS(word, wlen, "-target"))
+            return eval_kbuild_endef_xxxx(kdata, flocp, line, eos,  ignoring, kBuildDef_Target);
+        if (WORD_IS(word, wlen, "-template"))
+            return eval_kbuild_endef_xxxx(kdata, flocp, line, eos,  ignoring, kBuildDef_Template);
+        if (WORD_IS(word, wlen, "-tool"))
+            return eval_kbuild_endef_xxxx(kdata, flocp, line, eos,  ignoring, kBuildDef_Tool);
+        if (WORD_IS(word, wlen, "-sdk"))
+            return eval_kbuild_endef_xxxx(kdata, flocp, line, eos,  ignoring, kBuildDef_Sdk);
+        if (WORD_IS(word, wlen, "-unit"))
+            return eval_kbuild_endef_xxxx(kdata, flocp, line, eos,  ignoring, kBuildDef_Unit);
+    }
+
+    error(flocp, _("Unknown syntax 'kBuild-endef%.*s'"), (int)wlen, word);
+    return 0;
+}
+
Index: /trunk/src/kmk/kbuild.h
===================================================================
--- /trunk/src/kmk/kbuild.h	(revision 2547)
+++ /trunk/src/kmk/kbuild.h	(revision 2548)
@@ -39,4 +39,11 @@
 const char *get_default_kbuild_shell(void);
 
+struct kbuild_eval_data;
+
+int eval_kbuild_define(struct kbuild_eval_data **kdata, const struct floc *flocp,
+                       const char *word, unsigned int wlen, const char *line, const char *eos, int ignoring);
+int eval_kbuild_endef(struct kbuild_eval_data **kdata, const struct floc *flocp,
+                      const char *word, unsigned int wlen, const char *line, const char *eos, int ignoring);
+
 #endif
 
Index: /trunk/src/kmk/make.h
===================================================================
--- /trunk/src/kmk/make.h	(revision 2547)
+++ /trunk/src/kmk/make.h	(revision 2548)
@@ -502,4 +502,7 @@
 char *next_token (const char *);
 char *end_of_token (const char *);
+#ifdef KMK
+char *find_next_token_eos (const char **ptr, const char *eos, unsigned int *lengthptr);
+#endif
 #ifndef CONFIG_WITH_VALUE_LENGTH
 void collapse_continuations (char *);
Index: /trunk/src/kmk/misc.c
===================================================================
--- /trunk/src/kmk/misc.c	(revision 2547)
+++ /trunk/src/kmk/misc.c	(revision 2548)
@@ -727,4 +727,60 @@
 #endif
 }
+#ifdef KMK
+
+/* Same as find_next_token with two exception:
+      - The string ends at EOS or '\0'.
+      - We keep track of $() and ${}, allowing functions to be used. */
+
+char *
+find_next_token_eos (const char **ptr, const char *eos, unsigned int *lengthptr)
+{
+  const char *p = *ptr;
+  const char *e;
+  int level = 0;
+
+  /* skip blanks */
+  for (; p != eos; p++)
+    {
+      unsigned char ch = *p;
+      if (!MY_IS_BLANK(ch))
+        {
+          if (!ch)
+            return NULL;
+          break;
+        }
+    }
+  if (p == eos)
+    return NULL;
+
+  /* skip ahead until EOS or blanks. */
+  for (e = p; e != eos; e++)
+    {
+      unsigned char ch = *e;
+      if (MY_IS_BLANK_OR_EOS(ch))
+        {
+          if (!ch || level == 0)
+            break;
+        }
+      else if (ch == '$')
+        {
+          if (&e[1] != eos && (e[1] == '(' || e[1] == '{'))
+            {
+              level++;
+              e++;
+            }
+        }
+      else if ((ch == ')' || ch == '}') &&  level > 0)
+        level--;
+    }
+
+  *ptr = e;
+  if (lengthptr != 0)
+    *lengthptr = e - p;
+
+  return (char *)p;
+}
+
+#endif /* KMK */
 
 
Index: /trunk/src/kmk/read.c
===================================================================
--- /trunk/src/kmk/read.c	(revision 2547)
+++ /trunk/src/kmk/read.c	(revision 2548)
@@ -593,4 +593,8 @@
   unsigned int tmp_len;
 #endif
+#ifdef KMK
+  struct kbuild_eval_data *kdata = 0;
+  int krc;
+#endif
 
 #define record_waiting_files()						      \
@@ -896,4 +900,22 @@
 	continue;
 
+#ifdef KMK
+      /* Check for the kBuild language extensions. */
+      if (   wlen >= sizeof("kBuild-define") - 1
+          && strneq (p, "kBuild-define", sizeof("kBuild-define") - 1))
+        krc = eval_kbuild_define (&kdata, fstart, p, wlen, p2, eol, ignoring);
+      else if (   wlen >= sizeof("kBuild-endef") - 1
+               && strneq (p, "kBuild-endef", sizeof("kBuild-endef") - 1))
+        krc = eval_kbuild_endef (&kdata, fstart, p, wlen, p2, eol, ignoring);
+      else
+        krc = 42;
+      if (krc != 42)
+        {
+          if (krc != 0)
+            error (fstart, _("krc=%d"), krc);
+          continue;
+        }
+
+#endif /* KMK */
       if (word1eq ("export"))
 	{
@@ -1646,4 +1668,9 @@
   if (conditionals->if_cmds)
     fatal (fstart, _("missing `endif'"));
+#ifdef KMK
+
+  if (kdata != NULL)
+    fatal (fstart, _("missing `kBuild-endef-*'"));
+#endif
 
   /* At eof, record the last rule.  */
Index: /trunk/src/kmk/testcase-kBuild-define.kmk
===================================================================
--- /trunk/src/kmk/testcase-kBuild-define.kmk	(revision 2548)
+++ /trunk/src/kmk/testcase-kBuild-define.kmk	(revision 2548)
@@ -0,0 +1,53 @@
+# $Id$
+## @file
+# kBuild - testcase for the kBuild-define-* directives.
+#
+
+#
+# Copyright (c) 2011 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
+#
+# This file is part of kBuild.
+#
+# kBuild is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# kBuild is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with kBuild.  If not, see <http://www.gnu.org/licenses/>
+#
+#
+
+DEPTH = ../..
+#include $(PATH_KBUILD)/header.kmk
+
+kBuild-define-target MyTarget
+
+TEMPLATE = MyTemplate
+SOURCES = MySourceFile.c
+
+kBuild-endef-target  MyTarget
+
+
+INDIRECT_NAME = MyTarget$(strip $1)
+kBuild-define-target $(call INDIRECT_NAME, 2)
+
+TEMPLATE = MyTemplate2
+SOURCES = MySourceFile2.c
+
+kBuild-endef-target  $(call INDIRECT_NAME, 2)
+
+
+
+
+all_recursive:
+	$(ECHO) "kBuild-define-xxxx works fine"
+
+
+
+
Index: /trunk/src/kmk/variable.c
===================================================================
--- /trunk/src/kmk/variable.c	(revision 2547)
+++ /trunk/src/kmk/variable.c	(revision 2548)
@@ -1279,5 +1279,6 @@
   && defined (CONFIG_WITH_TOUPPER_TOLOWER) \
   && defined (CONFIG_WITH_DEFINED) \
-  && defined (CONFIG_WITH_VALUE_LENGTH) && defined (CONFIG_WITH_COMPARE) \
+  && defined (CONFIG_WITH_VALUE_LENGTH) \
+  && defined (CONFIG_WITH_COMPARE) \
   && defined (CONFIG_WITH_STACK) \
   && defined (CONFIG_WITH_MATH) \
@@ -1302,4 +1303,5 @@
   (void) define_variable ("KMK_FEATURES", 12,
                           "append-dash-n abspath includedep-queue install-hard-linking"
+                          " kBuild-define"
                           " rsort"
                           " abspathex"
@@ -1331,5 +1333,6 @@
 # else /* MSC can't deal with strings mixed with #if/#endif, thus the slow way. */
 #  error "All features should be enabled by default!"
-  strcpy (buf, "append-dash-n abspath includedep-queue install-hard-linking");
+  strcpy (buf, "append-dash-n abspath includedep-queue install-hard-linking"
+               " kBuild-define");
 #  if defined (CONFIG_WITH_RSORT)
   strcat (buf, " rsort");
