VirtualBox

source: kBuild/trunk/src/kmk/kmk_cc_exec.c@ 2772

Last change on this file since 2772 was 2772, checked in by bird, 10 years ago

Elimiated a few 'return 0' and unnecessary if (rc != 0) following them.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 71.8 KB
Line 
1#ifdef CONFIG_WITH_COMPILER
2/* $Id: kmk_cc_exec.c 2772 2015-02-01 20:53:48Z bird $ */
3/** @file
4 * kmk_cc - Make "Compiler".
5 */
6
7/*
8 * Copyright (c) 2015 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
9 *
10 * This file is part of kBuild.
11 *
12 * kBuild is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * kBuild is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
24 *
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include "make.h"
32
33#include "dep.h"
34#include "variable.h"
35#include "rule.h"
36#include "debug.h"
37#include "hash.h"
38#include <ctype.h>
39#ifdef HAVE_STDINT_H
40# include <stdint.h>
41#endif
42#include <stdarg.h>
43#include <assert.h>
44
45/*******************************************************************************
46* Defined Constants And Macros *
47*******************************************************************************/
48/** @def KMK_CC_WITH_STATS
49 * Enables the collection of extra statistics. */
50#ifndef KMK_CC_WITH_STATS
51# ifdef CONFIG_WITH_MAKE_STATS
52# define KMK_CC_WITH_STATS
53# endif
54#endif
55
56/** @def KMK_CC_STRICT
57 * Indicates whether assertions and other checks are enabled. */
58#ifndef KMK_CC_STRICT
59# ifndef NDEBUG
60# define KMK_CC_STRICT
61# endif
62#endif
63
64#ifdef KMK_CC_STRICT
65# ifdef _MSC_VER
66# define KMK_CC_ASSERT(a_TrueExpr) do { if (!(a_TrueExpr)) __debugbreak(); } while (0)
67# else
68# define KMK_CC_ASSERT(a_TrueExpr) assert(a_TrueExpr)
69# endif
70#else
71# define KMK_CC_ASSERT(a_TrueExpr) do {} while (0)
72#endif
73#define KMK_CC_ASSERT_ALIGNED(a_uValue, a_uAlignment) \
74 KMK_CC_ASSERT( ((a_uValue) & ((a_uAlignment) - 1)) == 0 )
75
76
77/*******************************************************************************
78* Structures and Typedefs *
79*******************************************************************************/
80/**
81 * Block of expand instructions.
82 *
83 * To avoid wasting space on "next" pointers, as well as a lot of time walking
84 * these chains when destroying programs, we work with blocks of instructions.
85 */
86typedef struct kmk_cc_block
87{
88 /** The pointer to the next block (LIFO). */
89 struct kmk_cc_block *pNext;
90 /** The size of this block. */
91 uint32_t cbBlock;
92 /** The offset of the next free byte in the block. When set to cbBlock the
93 * block is 100% full. */
94 uint32_t offNext;
95} KMKCCBLOCK;
96typedef KMKCCBLOCK *PKMKCCBLOCK;
97
98/**
99 * String expansion statistics.
100 */
101typedef struct KMKCCEXPSTATS
102{
103 /** Recent average size. */
104 uint32_t cchAvg;
105} KMKCCEXPSTATS;
106typedef KMKCCEXPSTATS *PKMKCCEXPSTATS;
107
108/**
109 * Expansion instructions.
110 */
111typedef enum KMKCCEXPINSTR
112{
113 /** Copy a plain string. */
114 kKmkCcExpInstr_CopyString = 0,
115 /** Insert an expanded variable value, which name we already know. */
116 kKmkCcExpInstr_PlainVariable,
117 /** Insert an expanded variable value, the name is dynamic (sub prog). */
118 kKmkCcExpInstr_DynamicVariable,
119 /** Insert an expanded variable value, which name we already know, doing
120 * search an replace on a string. */
121 kKmkCcExpInstr_SearchAndReplacePlainVariable,
122 /** Insert the output of function that requires no argument expansion. */
123 kKmkCcExpInstr_PlainFunction,
124 /** Insert the output of function that requires dynamic expansion of one ore
125 * more arguments. (Dynamic is perhaps not such a great name, but whatever.) */
126 kKmkCcExpInstr_DynamicFunction,
127 /** Jump to a new instruction block. */
128 kKmkCcExpInstr_Jump,
129 /** We're done, return. Has no specific structure. */
130 kKmkCcExpInstr_Return,
131 /** The end of valid instructions (exclusive). */
132 kKmkCcExpInstr_End
133} KMKCCEXPANDINSTR;
134
135/** Instruction core. */
136typedef struct kmk_cc_exp_core
137{
138 /** The instruction opcode number (KMKCCEXPANDINSTR). */
139 KMKCCEXPANDINSTR enmOpCode;
140} KMKCCEXPCORE;
141typedef KMKCCEXPCORE *PKMKCCEXPCORE;
142
143/**
144 * String expansion sub program.
145 */
146typedef struct kmk_cc_exp_subprog
147{
148 /** Pointer to the first instruction. */
149 PKMKCCEXPCORE pFirstInstr;
150 /** Statistics. */
151 KMKCCEXPSTATS Stats;
152} KMKCCEXPSUBPROG;
153typedef KMKCCEXPSUBPROG *PKMKCCEXPSUBPROG;
154
155/**
156 * kKmkCcExpInstr_CopyString instruction format.
157 */
158typedef struct kmk_cc_exp_copy_string
159{
160 /** The core instruction. */
161 KMKCCEXPCORE Core;
162 /** The number of bytes to copy. */
163 uint32_t cchCopy;
164 /** Pointer to the source string (not terminated at cchCopy). */
165 const char *pachSrc;
166} KMKCCEXPCOPYSTRING;
167typedef KMKCCEXPCOPYSTRING *PKMKCCEXPCOPYSTRING;
168
169/**
170 * kKmkCcExpInstr_PlainVariable instruction format.
171 */
172typedef struct kmk_cc_exp_plain_variable
173{
174 /** The core instruction. */
175 KMKCCEXPCORE Core;
176 /** The name of the variable (points into variable_strcache). */
177 const char *pszName;
178} KMKCCEXPPLAINVAR;
179typedef KMKCCEXPPLAINVAR *PKMKCCEXPPLAINVAR;
180
181/**
182 * kKmkCcExpInstr_DynamicVariable instruction format.
183 */
184typedef struct kmk_cc_exp_dynamic_variable
185{
186 /** The core instruction. */
187 KMKCCEXPCORE Core;
188 /** Where to continue after this instruction. (This is necessary since the
189 * instructions of the subprogram are emitted after this instruction.) */
190 PKMKCCEXPCORE pNext;
191 /** The subprogram that will give us the variable name. */
192 KMKCCEXPSUBPROG SubProg;
193} KMKCCEXPDYNVAR;
194typedef KMKCCEXPDYNVAR *PKMKCCEXPDYNVAR;
195
196/**
197 * kKmkCcExpInstr_SearchAndReplacePlainVariable instruction format.
198 */
199typedef struct kmk_cc_exp_sr_plain_variable
200{
201 /** The core instruction. */
202 KMKCCEXPCORE Core;
203 /** Where to continue after this instruction. (This is necessary since the
204 * instruction contains string data of variable size.) */
205 PKMKCCEXPCORE pNext;
206 /** The name of the variable (points into variable_strcache). */
207 const char *pszName;
208 /** Search pattern. */
209 const char *pszSearchPattern;
210 /** Replacement pattern. */
211 const char *pszReplacePattern;
212 /** Offset into pszSearchPattern of the significant '%' char. */
213 uint32_t offPctSearchPattern;
214 /** Offset into pszReplacePattern of the significant '%' char. */
215 uint32_t offPctReplacePattern;
216} KMKCCEXPSRPLAINVAR;
217typedef KMKCCEXPSRPLAINVAR *PKMKCCEXPSRPLAINVAR;
218
219/**
220 * Instruction format parts common to both kKmkCcExpInstr_PlainFunction and
221 * kKmkCcExpInstr_DynamicFunction.
222 */
223typedef struct kmk_cc_exp_function_core
224{
225 /** The core instruction. */
226 KMKCCEXPCORE Core;
227 /** Number of arguments. */
228 uint32_t cArgs;
229 /** Set if the function could be modifying the input arguments. */
230 uint8_t fDirty;
231 /** Where to continue after this instruction. (This is necessary since the
232 * instructions are of variable size and may be followed by string data.) */
233 PKMKCCEXPCORE pNext;
234 /**
235 * Pointer to the function table entry.
236 *
237 * @returns New variable buffer position.
238 * @param pchDst Current variable buffer position.
239 * @param papszArgs Pointer to a NULL terminated array of argument strings.
240 * @param pszFuncName The name of the function being called.
241 */
242 char * (*pfnFunction)(char *pchDst, char **papszArgs, const char *pszFuncName);
243 /** Pointer to the function name in the variable string cache. */
244 const char *pszFuncName;
245} KMKCCEXPFUNCCORE;
246typedef KMKCCEXPFUNCCORE *PKMKCCEXPFUNCCORE;
247
248/**
249 * Instruction format for kKmkCcExpInstr_PlainFunction.
250 */
251typedef struct kmk_cc_exp_plain_function
252{
253 /** The bits comment to both plain and dynamic functions. */
254 KMKCCEXPFUNCCORE Core;
255 /** Variable sized argument list (cArgs + 1 in length, last entry is NULL).
256 * The string pointers are to memory following this instruction, to memory in
257 * the next block or to memory in the variable / makefile we're working on
258 * (if zero terminated appropriately). */
259 const char *apszArgs[1];
260} KMKCCEXPPLAINFUNC;
261typedef KMKCCEXPPLAINFUNC *PKMKCCEXPPLAINFUNC;
262/** Calculates the size of an KMKCCEXPPLAINFUNC with a_cArgs. */
263#define KMKCCEXPPLAINFUNC_SIZE(a_cArgs) (sizeof(KMKCCEXPFUNCCORE) + (a_cArgs + 1) * sizeof(const char *))
264
265/**
266 * Instruction format for kKmkCcExpInstr_DynamicFunction.
267 */
268typedef struct kmk_cc_exp_dyn_function
269{
270 /** The bits comment to both plain and dynamic functions. */
271 KMKCCEXPFUNCCORE Core;
272 /** Variable sized argument list (cArgs + 1 in length, last entry is NULL).
273 * The string pointers are to memory following this instruction, to memory in
274 * the next block or to memory in the variable / makefile we're working on
275 * (if zero terminated appropriately). */
276 struct
277 {
278 /** Set if plain string argument, clear if sub program. */
279 uint8_t fPlain;
280 union
281 {
282 /** Sub program for expanding this argument. */
283 KMKCCEXPSUBPROG SubProg;
284 struct
285 {
286 /** Pointer to the plain argument string.
287 * This is allocated in the same manner as the
288 * string pointed to by KMKCCEXPPLAINFUNC::apszArgs. */
289 const char *pszArg;
290 } Plain;
291 } u;
292 } aArgs[1];
293} KMKCCEXPDYNFUNC;
294typedef KMKCCEXPDYNFUNC *PKMKCCEXPDYNFUNC;
295/** Calculates the size of an KMKCCEXPPLAINFUNC with a_cArgs. */
296#define KMKCCEXPDYNFUNC_SIZE(a_cArgs) ( sizeof(KMKCCEXPFUNCCORE) \
297 + (a_cArgs) * sizeof(((PKMKCCEXPDYNFUNC)(uintptr_t)42)->aArgs[0]) )
298
299/**
300 * Instruction format for kKmkCcExpInstr_Jump.
301 */
302typedef struct kmk_cc_exp_jump
303{
304 /** The core instruction. */
305 KMKCCEXPCORE Core;
306 /** Where to jump to (new instruction block, typically). */
307 PKMKCCEXPCORE pNext;
308} KMKCCEXPJUMP;
309typedef KMKCCEXPJUMP *PKMKCCEXPJUMP;
310
311/**
312 * String expansion program.
313 */
314typedef struct kmk_cc_expandprog
315{
316 /** Pointer to the first instruction for this program. */
317 PKMKCCEXPCORE pFirstInstr;
318 /** List of blocks for this program (LIFO). */
319 PKMKCCBLOCK pBlockTail;
320 /** Statistics. */
321 KMKCCEXPSTATS Stats;
322#ifdef KMK_CC_STRICT
323 /** The hash of the input string. Used to check that we get all the change
324 * notifications we require. */
325 uint32_t uInputHash;
326#endif
327} KMKCCEXPPROG;
328/** Pointer to a string expansion program. */
329typedef KMKCCEXPPROG *PKMKCCEXPPROG;
330
331
332/*******************************************************************************
333* Global Variables *
334*******************************************************************************/
335static uint32_t g_cVarForExpandCompilations = 0;
336static uint32_t g_cVarForExpandExecs = 0;
337#ifdef KMK_CC_WITH_STATS
338static uint32_t g_cBlockAllocated = 0;
339static uint32_t g_cbAllocated = 0;
340static uint32_t g_cBlocksAllocatedExpProgs = 0;
341static uint32_t g_cbAllocatedExpProgs = 0;
342static uint32_t g_cSingleBlockExpProgs = 0;
343static uint32_t g_cTwoBlockExpProgs = 0;
344static uint32_t g_cMultiBlockExpProgs = 0;
345static uint32_t g_cbUnusedMemExpProgs = 0;
346#endif
347
348
349/*******************************************************************************
350* Internal Functions *
351*******************************************************************************/
352static int kmk_cc_exp_compile_subprog(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr, PKMKCCEXPSUBPROG pSubProg);
353static char *kmk_exec_expand_subprog_to_tmp(PKMKCCEXPSUBPROG pSubProg, uint32_t *pcch);
354
355
356/**
357 * Initializes global variables for the 'compiler'.
358 */
359void kmk_cc_init(void)
360{
361}
362
363
364/**
365 * Prints stats (for kmk -p).
366 */
367void kmk_cc_print_stats(void)
368{
369 puts(_("\n# The kmk 'compiler' and kmk 'program executor':\n"));
370
371 printf(_("# Variables compiled for string expansion: %6u\n"), g_cVarForExpandCompilations);
372 printf(_("# Variables string expansion runs: %6u\n"), g_cVarForExpandExecs);
373 printf(_("# String expansion runs per compile: %6u\n"), g_cVarForExpandExecs / g_cVarForExpandExecs);
374#ifdef KMK_CC_WITH_STATS
375 printf(_("# Single alloc block exp progs: %6u (%u%%)\n"
376 "# Two alloc block exp progs: %6u (%u%%)\n"
377 "# Three or more alloc block exp progs: %6u (%u%%)\n"
378 ),
379 g_cSingleBlockExpProgs, (uint32_t)((uint64_t)g_cSingleBlockExpProgs * 100 / g_cVarForExpandCompilations),
380 g_cTwoBlockExpProgs, (uint32_t)((uint64_t)g_cTwoBlockExpProgs * 100 / g_cVarForExpandCompilations),
381 g_cMultiBlockExpProgs, (uint32_t)((uint64_t)g_cMultiBlockExpProgs * 100 / g_cVarForExpandCompilations));
382 printf(_("# Total amount of memory for exp progs: %8u bytes\n"
383 "# in: %6u blocks\n"
384 "# avg block size: %6u bytes\n"
385 "# unused memory: %8u bytes (%u%%)\n"
386 "# avg unused memory per block: %6u bytes\n"
387 "\n"),
388 g_cbAllocatedExpProgs, g_cBlocksAllocatedExpProgs, g_cbAllocatedExpProgs / g_cBlocksAllocatedExpProgs,
389 g_cbUnusedMemExpProgs, (uint32_t)((uint64_t)g_cbUnusedMemExpProgs * 100 / g_cbAllocatedExpProgs),
390 g_cbUnusedMemExpProgs / g_cBlocksAllocatedExpProgs);
391
392 printf(_("# Total amount of block mem allocated: %8u bytes\n"), g_cbAllocated);
393 printf(_("# Total number of block allocated: %8u\n"), g_cBlockAllocated);
394 printf(_("# Average block size: %8u byte\n"), g_cbAllocated / g_cBlockAllocated);
395#endif
396
397 puts("");
398}
399
400
401/*
402 *
403 * Various utility functions.
404 * Various utility functions.
405 * Various utility functions.
406 *
407 */
408
409/**
410 * Counts the number of dollar chars in the string.
411 *
412 * @returns Number of dollar chars.
413 * @param pchStr The string to search (does not need to be zero
414 * terminated).
415 * @param cchStr The length of the string.
416 */
417static uint32_t kmk_cc_count_dollars(const char *pchStr, uint32_t cchStr)
418{
419 uint32_t cDollars = 0;
420 const char *pch;
421 while ((pch = memchr(pchStr, '$', cchStr)) != NULL)
422 {
423 cDollars++;
424 cchStr -= pch - pchStr + 1;
425 pchStr = pch + 1;
426 }
427 return cDollars;
428}
429
430#ifdef KMK_CC_STRICT
431/**
432 * Used to check that function arguments are left alone.
433 * @returns Updated hash.
434 * @param uHash The current hash value.
435 * @param psz The string to hash.
436 */
437static uint32_t kmk_cc_debug_string_hash(uint32_t uHash, const char *psz)
438{
439 unsigned char ch;
440 while ((ch = *(unsigned char const *)psz++) != '\0')
441 uHash = (uHash << 6) + (uHash << 16) - uHash + (unsigned char)ch;
442 return uHash;
443}
444
445/**
446 * Used to check that function arguments are left alone.
447 * @returns Updated hash.
448 * @param uHash The current hash value.
449 * @param pch The string to hash, not terminated.
450 * @param cch The number of chars to hash.
451 */
452static uint32_t kmk_cc_debug_string_hash_n(uint32_t uHash, const char *pch, uint32_t cch)
453{
454 while (cch-- > 0)
455 {
456 unsigned char ch = *(unsigned char const *)pch++;
457 uHash = (uHash << 6) + (uHash << 16) - uHash + (unsigned char)ch;
458 }
459 return uHash;
460}
461
462#endif
463
464
465
466/*
467 *
468 * The allocator.
469 * The allocator.
470 * The allocator.
471 *
472 */
473
474
475/**
476 * For the first allocation using the block allocator.
477 *
478 * @returns Pointer to the first allocation (@a cbFirst in size).
479 * @param ppBlockTail Where to return the pointer to the first block.
480 * @param cbFirst The size of the first allocation.
481 * @param cbHint Hint about how much memory we might be needing.
482 */
483static void *kmk_cc_block_alloc_first(PKMKCCBLOCK *ppBlockTail, size_t cbFirst, size_t cbHint)
484{
485 uint32_t cbBlock;
486 PKMKCCBLOCK pNewBlock;
487
488 KMK_CC_ASSERT_ALIGNED(cbFirst, sizeof(void *));
489
490 /*
491 * Turn the hint into a block size.
492 */
493 if (cbHint <= 512)
494 {
495 if (cbHint <= 256)
496 cbBlock = 128;
497 else
498 cbBlock = 256;
499 }
500 else if (cbHint < 2048)
501 cbBlock = 1024;
502 else if (cbHint < 3072)
503 cbBlock = 2048;
504 else
505 cbBlock = 4096;
506
507 /*
508 * Allocate and initialize the first block.
509 */
510 pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock);
511 pNewBlock->cbBlock = cbBlock;
512 pNewBlock->offNext = sizeof(*pNewBlock) + cbFirst;
513 pNewBlock->pNext = NULL;
514 *ppBlockTail = pNewBlock;
515
516#ifdef KMK_CC_WITH_STATS
517 g_cBlockAllocated++;
518 g_cbAllocated += cbBlock;
519#endif
520
521 return pNewBlock + 1;
522}
523
524
525/**
526 * Used for getting the address of the next instruction.
527 *
528 * @returns Pointer to the next allocation.
529 * @param pBlockTail The allocator tail pointer.
530 */
531static void *kmk_cc_block_get_next_ptr(PKMKCCBLOCK pBlockTail)
532{
533 return (char *)pBlockTail + pBlockTail->offNext;
534}
535
536
537/**
538 * Realigns the allocator after doing byte or string allocations.
539 *
540 * @param ppBlockTail Pointer to the allocator tail pointer.
541 */
542static void kmk_cc_block_realign(PKMKCCBLOCK *ppBlockTail)
543{
544 PKMKCCBLOCK pBlockTail = *ppBlockTail;
545 if (pBlockTail->offNext & (sizeof(void *) - 1))
546 {
547 pBlockTail->offNext = (pBlockTail->offNext + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
548 KMK_CC_ASSERT(pBlockTail->cbBlock - pBlockTail->offNext >= sizeof(KMKCCEXPJUMP));
549 }
550}
551
552
553/**
554 * Grows the allocation with another block, byte allocator case.
555 *
556 * @returns Pointer to the byte allocation.
557 * @param ppBlockTail Pointer to the allocator tail pointer.
558 * @param cb The number of bytes to allocate.
559 */
560static void *kmk_cc_block_byte_alloc_grow(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
561{
562 PKMKCCBLOCK pOldBlock = *ppBlockTail;
563 PKMKCCBLOCK pPrevBlock = pOldBlock->pNext;
564 PKMKCCBLOCK pNewBlock;
565 uint32_t cbBlock;
566
567 /*
568 * Check if there accidentally is some space left in the previous block first.
569 */
570 if ( pPrevBlock
571 && pPrevBlock->cbBlock - pPrevBlock->offNext >= cb)
572 {
573 void *pvRet = (char *)pPrevBlock + pPrevBlock->offNext;
574 pPrevBlock->offNext += cb;
575 return pvRet;
576 }
577
578 /*
579 * Allocate a new block.
580 */
581
582 /* Figure the block size. */
583 cbBlock = pOldBlock->cbBlock;
584 while (cbBlock - sizeof(KMKCCEXPJUMP) - sizeof(*pNewBlock) < cb)
585 cbBlock *= 2;
586
587 /* Allocate and initialize the block it with the new instruction already accounted for. */
588 pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock);
589 pNewBlock->cbBlock = cbBlock;
590 pNewBlock->offNext = sizeof(*pNewBlock) + cb;
591 pNewBlock->pNext = pOldBlock;
592 *ppBlockTail = pNewBlock;
593
594#ifdef KMK_CC_WITH_STATS
595 g_cBlockAllocated++;
596 g_cbAllocated += cbBlock;
597#endif
598
599 return pNewBlock + 1;
600}
601
602
603/**
604 * Make a byte allocation.
605 *
606 * Must call kmk_cc_block_realign() when done doing byte and string allocations.
607 *
608 * @returns Pointer to the byte allocation (byte aligned).
609 * @param ppBlockTail Pointer to the allocator tail pointer.
610 * @param cb The number of bytes to allocate.
611 */
612static void *kmk_cc_block_byte_alloc(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
613{
614 PKMKCCBLOCK pBlockTail = *ppBlockTail;
615 uint32_t cbLeft = pBlockTail->cbBlock - pBlockTail->offNext;
616
617 KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEXPJUMP));
618 if (cbLeft >= cb + sizeof(KMKCCEXPJUMP))
619 {
620 void *pvRet = (char *)pBlockTail + pBlockTail->offNext;
621 pBlockTail->offNext += cb;
622 return pvRet;
623 }
624 return kmk_cc_block_byte_alloc_grow(ppBlockTail, cb);
625}
626
627
628/**
629 * Duplicates the given string in a byte allocation.
630 *
631 * Must call kmk_cc_block_realign() when done doing byte and string allocations.
632 *
633 * @returns Pointer to the byte allocation (byte aligned).
634 * @param ppBlockTail Pointer to the allocator tail pointer.
635 * @param cb The number of bytes to allocate.
636 */
637static const char *kmk_cc_block_strdup(PKMKCCBLOCK *ppBlockTail, const char *pachStr, uint32_t cchStr)
638{
639 char *pszCopy;
640 if (cchStr)
641 {
642 pszCopy = kmk_cc_block_byte_alloc(ppBlockTail, cchStr + 1);
643 memcpy(pszCopy, pachStr, cchStr);
644 pszCopy[cchStr] = '\0';
645 return pszCopy;
646 }
647 return "";
648}
649
650
651/**
652 * Grows the allocation with another block, string expansion program case.
653 *
654 * @returns Pointer to a string expansion instruction core.
655 * @param ppBlockTail Pointer to the allocator tail pointer.
656 * @param cb The number of bytes to allocate.
657 */
658static PKMKCCEXPCORE kmk_cc_block_alloc_exp_grow(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
659{
660 PKMKCCBLOCK pOldBlock = *ppBlockTail;
661 PKMKCCBLOCK pNewBlock;
662 PKMKCCEXPCORE pRet;
663 PKMKCCEXPJUMP pJump;
664
665 /* Figure the block size. */
666 uint32_t cbBlock = !pOldBlock->pNext ? 128 : pOldBlock->cbBlock;
667 while (cbBlock - sizeof(KMKCCEXPJUMP) - sizeof(*pNewBlock) < cb)
668 cbBlock *= 2;
669
670 /* Allocate and initialize the block it with the new instruction already accounted for. */
671 pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock);
672 pNewBlock->cbBlock = cbBlock;
673 pNewBlock->offNext = sizeof(*pNewBlock) + cb;
674 pNewBlock->pNext = pOldBlock;
675 *ppBlockTail = pNewBlock;
676
677#ifdef KMK_CC_WITH_STATS
678 g_cBlockAllocated++;
679 g_cbAllocated += cbBlock;
680#endif
681
682 pRet = (PKMKCCEXPCORE)(pNewBlock + 1);
683
684 /* Emit jump. */
685 pJump = (PKMKCCEXPJUMP)((char *)pOldBlock + pOldBlock->offNext);
686 pJump->Core.enmOpCode = kKmkCcExpInstr_Jump;
687 pJump->pNext = pRet;
688 pOldBlock->offNext += sizeof(*pJump);
689 KMK_CC_ASSERT(pOldBlock->offNext <= pOldBlock->cbBlock);
690
691 return pRet;
692}
693
694
695/**
696 * Allocates a string expansion instruction of size @a cb.
697 *
698 * @returns Pointer to a string expansion instruction core.
699 * @param ppBlockTail Pointer to the allocator tail pointer.
700 * @param cb The number of bytes to allocate.
701 */
702static PKMKCCEXPCORE kmk_cc_block_alloc_exp(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
703{
704 PKMKCCBLOCK pBlockTail = *ppBlockTail;
705 uint32_t cbLeft = pBlockTail->cbBlock - pBlockTail->offNext;
706
707 KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEXPJUMP));
708 KMK_CC_ASSERT( (cb & (sizeof(void *) - 1)) == 0 || cb == sizeof(KMKCCEXPCORE) /* final */ );
709
710 if (cbLeft >= cb + sizeof(KMKCCEXPJUMP))
711 {
712 PKMKCCEXPCORE pRet = (PKMKCCEXPCORE)((char *)pBlockTail + pBlockTail->offNext);
713 pBlockTail->offNext += cb;
714 return pRet;
715 }
716 return kmk_cc_block_alloc_exp_grow(ppBlockTail, cb);
717}
718
719
720/**
721 * Frees all memory used by an allocator.
722 *
723 * @param ppBlockTail The allocator tail pointer.
724 */
725static void kmk_cc_block_free_list(PKMKCCBLOCK pBlockTail)
726{
727 while (pBlockTail)
728 {
729 PKMKCCBLOCK pThis = pBlockTail;
730 pBlockTail = pBlockTail->pNext;
731 free(pThis);
732 }
733}
734
735
736/*
737 *
738 * The string expansion compiler.
739 * The string expansion compiler.
740 * The string expansion compiler.
741 *
742 */
743
744
745/**
746 * Emits a kKmkCcExpInstr_Return.
747 *
748 * @param ppBlockTail Pointer to the allocator tail pointer.
749 */
750static void kmk_cc_exp_emit_return(PKMKCCBLOCK *ppBlockTail)
751{
752 PKMKCCEXPCORE pCore = kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pCore));
753 pCore->enmOpCode = kKmkCcExpInstr_Return;
754}
755
756
757/**
758 * Checks if a function is known to mess up the arguments its given.
759 *
760 * When executing calls to "dirty" functions, all arguments must be duplicated
761 * on the heap.
762 *
763 * @returns 1 if dirty, 0 if clean.
764 * @param pszFunction The function name.
765 */
766static uint8_t kmk_cc_is_dirty_function(const char *pszFunction)
767{
768 switch (pszFunction[0])
769 {
770 default:
771 return 0;
772
773 case 'e':
774 if (!strcmp(pszFunction, "eval"))
775 return 1;
776 if (!strcmp(pszFunction, "evalctx"))
777 return 1;
778 return 0;
779
780 case 'f':
781 if (!strcmp(pszFunction, "filter"))
782 return 1;
783 if (!strcmp(pszFunction, "filter-out"))
784 return 1;
785 if (!strcmp(pszFunction, "for"))
786 return 1;
787 return 0;
788
789 case 's':
790 if (!strcmp(pszFunction, "sort"))
791 return 1;
792 return 0;
793 }
794}
795
796
797/**
798 * Emits a function call instruction taking arguments that needs expanding.
799 *
800 * @returns 0 on success, non-zero on failure.
801 * @param ppBlockTail Pointer to the allocator tail pointer.
802 * @param pszFunction The function name (const string from function.c).
803 * @param pchArgs Pointer to the arguments expression string, leading
804 * any blanks has been stripped.
805 * @param cchArgs The length of the arguments expression string.
806 * @param cArgs Number of arguments found.
807 * @param chOpen The char used to open the function call.
808 * @param chClose The char used to close the function call.
809 * @param pfnFunction The function implementation.
810 * @param cMaxArgs Maximum number of arguments the function takes.
811 */
812static int kmk_cc_exp_emit_dyn_function(PKMKCCBLOCK *ppBlockTail, const char *pszFunction,
813 const char *pchArgs, uint32_t cchArgs, uint32_t cArgs, char chOpen, char chClose,
814 make_function_ptr_t pfnFunction, unsigned char cMaxArgs)
815{
816 uint32_t iArg;
817
818 /*
819 * The function instruction has variable size. The maximum argument count
820 * isn't quite like the minium one. Zero means no limit. While a non-zero
821 * value means that any commas beyond the max will be taken to be part of
822 * the final argument.
823 */
824 uint32_t cActualArgs = cArgs <= cMaxArgs || !cMaxArgs ? cArgs : cMaxArgs;
825 PKMKCCEXPDYNFUNC pInstr = (PKMKCCEXPDYNFUNC)kmk_cc_block_alloc_exp(ppBlockTail, KMKCCEXPDYNFUNC_SIZE(cActualArgs));
826 pInstr->Core.Core.enmOpCode = kKmkCcExpInstr_DynamicFunction;
827 pInstr->Core.cArgs = cActualArgs;
828 pInstr->Core.pfnFunction = pfnFunction;
829 pInstr->Core.pszFuncName = pszFunction;
830 pInstr->Core.fDirty = kmk_cc_is_dirty_function(pszFunction);
831
832 /*
833 * Parse the arguments. Plain arguments gets duplicated in the program
834 * memory so that they are terminated and no extra processing is necessary
835 * later on. ASSUMES that the function implementations do NOT change
836 * argument memory. Other arguments the compiled into their own expansion
837 * sub programs.
838 */
839 iArg = 0;
840 for (;;)
841 {
842 /* Find the end of the argument. Check for $. */
843 char ch = '\0';
844 uint8_t fDollar = 0;
845 int32_t cDepth = 0;
846 uint32_t cchThisArg = 0;
847 while (cchThisArg < cchArgs)
848 {
849 ch = pchArgs[cchThisArg];
850 if (ch == chClose)
851 {
852 KMK_CC_ASSERT(cDepth > 0);
853 if (cDepth > 0)
854 cDepth--;
855 }
856 else if (ch == chOpen)
857 cDepth++;
858 else if (ch == ',' && cDepth == 0 && iArg + 1 < cActualArgs)
859 break;
860 else if (ch == '$')
861 fDollar = 1;
862 cchThisArg++;
863 }
864
865 pInstr->aArgs[iArg].fPlain = !fDollar;
866 if (fDollar)
867 {
868 /* Compile it. */
869 int rc;
870 kmk_cc_block_realign(ppBlockTail);
871 rc = kmk_cc_exp_compile_subprog(ppBlockTail, pchArgs, cchThisArg, &pInstr->aArgs[iArg].u.SubProg);
872 if (rc != 0)
873 return rc;
874 }
875 else
876 {
877 /* Duplicate it. */
878 pInstr->aArgs[iArg].u.Plain.pszArg = kmk_cc_block_strdup(ppBlockTail, pchArgs, cchThisArg);
879 }
880 iArg++;
881 if (ch != ',')
882 break;
883 pchArgs += cchThisArg + 1;
884 cchArgs -= cchThisArg + 1;
885 }
886 KMK_CC_ASSERT(iArg == cActualArgs);
887
888 /*
889 * Realign the allocator and take down the address of the next instruction.
890 */
891 kmk_cc_block_realign(ppBlockTail);
892 pInstr->Core.pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
893 return 0;
894}
895
896
897/**
898 * Emits a function call instruction taking plain arguments.
899 *
900 * @returns 0 on success, non-zero on failure.
901 * @param ppBlockTail Pointer to the allocator tail pointer.
902 * @param pszFunction The function name (const string from function.c).
903 * @param pchArgs Pointer to the arguments string, leading any blanks
904 * has been stripped.
905 * @param cchArgs The length of the arguments string.
906 * @param cArgs Number of arguments found.
907 * @param chOpen The char used to open the function call.
908 * @param chClose The char used to close the function call.
909 * @param pfnFunction The function implementation.
910 * @param cMaxArgs Maximum number of arguments the function takes.
911 */
912static void kmk_cc_exp_emit_plain_function(PKMKCCBLOCK *ppBlockTail, const char *pszFunction,
913 const char *pchArgs, uint32_t cchArgs, uint32_t cArgs, char chOpen, char chClose,
914 make_function_ptr_t pfnFunction, unsigned char cMaxArgs)
915{
916 uint32_t iArg;
917
918 /*
919 * The function instruction has variable size. The maximum argument count
920 * isn't quite like the minium one. Zero means no limit. While a non-zero
921 * value means that any commas beyond the max will be taken to be part of
922 * the final argument.
923 */
924 uint32_t cActualArgs = cArgs <= cMaxArgs || !cMaxArgs ? cArgs : cMaxArgs;
925 PKMKCCEXPPLAINFUNC pInstr = (PKMKCCEXPPLAINFUNC)kmk_cc_block_alloc_exp(ppBlockTail, KMKCCEXPPLAINFUNC_SIZE(cActualArgs));
926 pInstr->Core.Core.enmOpCode = kKmkCcExpInstr_PlainFunction;
927 pInstr->Core.cArgs = cActualArgs;
928 pInstr->Core.pfnFunction = pfnFunction;
929 pInstr->Core.pszFuncName = pszFunction;
930 pInstr->Core.fDirty = kmk_cc_is_dirty_function(pszFunction);
931
932 /*
933 * Parse the arguments. Plain arguments gets duplicated in the program
934 * memory so that they are terminated and no extra processing is necessary
935 * later on. ASSUMES that the function implementations do NOT change
936 * argument memory.
937 */
938 iArg = 0;
939 for (;;)
940 {
941 /* Find the end of the argument. */
942 char ch = '\0';
943 int32_t cDepth = 0;
944 uint32_t cchThisArg = 0;
945 while (cchThisArg < cchArgs)
946 {
947 ch = pchArgs[cchThisArg];
948 if (ch == chClose)
949 {
950 KMK_CC_ASSERT(cDepth > 0);
951 if (cDepth > 0)
952 cDepth--;
953 }
954 else if (ch == chOpen)
955 cDepth++;
956 else if (ch == ',' && cDepth == 0 && iArg + 1 < cActualArgs)
957 break;
958 cchThisArg++;
959 }
960
961 /* Duplicate it. */
962 pInstr->apszArgs[iArg++] = kmk_cc_block_strdup(ppBlockTail, pchArgs, cchThisArg);
963 if (ch != ',')
964 break;
965 pchArgs += cchThisArg + 1;
966 cchArgs -= cchThisArg + 1;
967 }
968
969 KMK_CC_ASSERT(iArg == cActualArgs);
970 pInstr->apszArgs[iArg] = NULL;
971
972 /*
973 * Realign the allocator and take down the address of the next instruction.
974 */
975 kmk_cc_block_realign(ppBlockTail);
976 pInstr->Core.pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
977}
978
979
980/**
981 * Emits a kKmkCcExpInstr_DynamicVariable.
982 *
983 * @returns 0 on success, non-zero on failure.
984 * @param ppBlockTail Pointer to the allocator tail pointer.
985 * @param pchNameExpr The name of the variable (ASSUMED presistent
986 * thru-out the program life time).
987 * @param cchNameExpr The length of the variable name. If zero,
988 * nothing will be emitted.
989 */
990static int kmk_cc_exp_emit_dyn_variable(PKMKCCBLOCK *ppBlockTail, const char *pchNameExpr, uint32_t cchNameExpr)
991{
992 PKMKCCEXPDYNVAR pInstr;
993 int rc;
994 KMK_CC_ASSERT(cchNameExpr > 0);
995
996 pInstr = (PKMKCCEXPDYNVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
997 pInstr->Core.enmOpCode = kKmkCcExpInstr_DynamicVariable;
998
999 rc = kmk_cc_exp_compile_subprog(ppBlockTail, pchNameExpr, cchNameExpr, &pInstr->SubProg);
1000
1001 pInstr->pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
1002 return rc;
1003}
1004
1005
1006/**
1007 * Emits either a kKmkCcExpInstr_PlainVariable or
1008 * kKmkCcExpInstr_SearchAndReplacePlainVariable instruction.
1009 *
1010 * @param ppBlockTail Pointer to the allocator tail pointer.
1011 * @param pchName The name of the variable. (Does not need to be
1012 * valid beyond the call.)
1013 * @param cchName The length of the variable name. If zero,
1014 * nothing will be emitted.
1015 */
1016static void kmk_cc_exp_emit_plain_variable_maybe_sr(PKMKCCBLOCK *ppBlockTail, const char *pchName, uint32_t cchName)
1017{
1018 if (cchName > 0)
1019 {
1020 /*
1021 * Hopefully, we're not expected to do any search and replace on the
1022 * expanded variable string later... Requires both ':' and '='.
1023 */
1024 const char *pchEqual;
1025 const char *pchColon = (const char *)memchr(pchName, ':', cchName);
1026 if ( pchColon == NULL
1027 || (pchEqual = (const char *)memchr(pchColon + 1, ':', cchName - (pchColon - pchName - 1))) == NULL
1028 || pchEqual == pchEqual + 1)
1029 {
1030 PKMKCCEXPPLAINVAR pInstr = (PKMKCCEXPPLAINVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
1031 pInstr->Core.enmOpCode = kKmkCcExpInstr_PlainVariable;
1032 pInstr->pszName = strcache2_add(&variable_strcache, pchName, cchName);
1033 }
1034 else if (pchColon != pchName)
1035 {
1036 /*
1037 * Okay, we need to do search and replace the variable value.
1038 * This is performed by patsubst_expand_pat using '%' patterns.
1039 */
1040 uint32_t cchName2 = (uint32_t)(pchColon - pchName);
1041 uint32_t cchSearch = (uint32_t)(pchEqual - pchColon - 1);
1042 uint32_t cchReplace = cchName - cchName2 - cchSearch - 2;
1043 const char *pchPct;
1044 char *psz;
1045 PKMKCCEXPSRPLAINVAR pInstr;
1046
1047 pInstr = (PKMKCCEXPSRPLAINVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
1048 pInstr->Core.enmOpCode = kKmkCcExpInstr_SearchAndReplacePlainVariable;
1049 pInstr->pszName = strcache2_add(&variable_strcache, pchName, cchName2);
1050
1051 /* Figure out the search pattern, unquoting percent chars.. */
1052 psz = (char *)kmk_cc_block_byte_alloc(ppBlockTail, cchSearch + 2);
1053 psz[0] = '%';
1054 memcpy(psz + 1, pchColon + 1, cchSearch);
1055 psz[1 + cchSearch] = '\0';
1056 pchPct = find_percent(psz + 1); /* also performs unquoting */
1057 if (pchPct)
1058 {
1059 pInstr->pszSearchPattern = psz + 1;
1060 pInstr->offPctSearchPattern = (uint32_t)(pchPct - psz - 1);
1061 }
1062 else
1063 {
1064 pInstr->pszSearchPattern = psz;
1065 pInstr->offPctSearchPattern = 0;
1066 }
1067
1068 /* Figure out the replacement pattern, unquoting percent chars.. */
1069 if (cchReplace == 0)
1070 {
1071 pInstr->pszReplacePattern = "%";
1072 pInstr->offPctReplacePattern = 0;
1073 }
1074 else
1075 {
1076 psz = (char *)kmk_cc_block_byte_alloc(ppBlockTail, cchReplace + 2);
1077 psz[0] = '%';
1078 memcpy(psz + 1, pchEqual + 1, cchReplace);
1079 psz[1 + cchReplace] = '\0';
1080 pchPct = find_percent(psz + 1); /* also performs unquoting */
1081 if (pchPct)
1082 {
1083 pInstr->pszReplacePattern = psz + 1;
1084 pInstr->offPctReplacePattern = (uint32_t)(pchPct - psz - 1);
1085 }
1086 else
1087 {
1088 pInstr->pszReplacePattern = psz;
1089 pInstr->offPctReplacePattern = 0;
1090 }
1091 }
1092
1093 /* Note down where the next instruction is after realigning the allocator. */
1094 kmk_cc_block_realign(ppBlockTail);
1095 pInstr->pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
1096 }
1097 }
1098}
1099
1100
1101/**
1102 * Emits a kKmkCcExpInstr_CopyString.
1103 *
1104 * @param ppBlockTail Pointer to the allocator tail pointer.
1105 * @param pchStr The string to emit (ASSUMED presistent thru-out
1106 * the program life time).
1107 * @param cchStr The number of chars to copy. If zero, nothing
1108 * will be emitted.
1109 */
1110static void kmk_cc_exp_emit_copy_string(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr)
1111{
1112 if (cchStr > 0)
1113 {
1114 PKMKCCEXPCOPYSTRING pInstr = (PKMKCCEXPCOPYSTRING)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
1115 pInstr->Core.enmOpCode = kKmkCcExpInstr_CopyString;
1116 pInstr->cchCopy = cchStr;
1117 pInstr->pachSrc = pchStr;
1118 }
1119}
1120
1121
1122/**
1123 * String expansion compilation function common to both normal and sub programs.
1124 *
1125 * @returns 0 on success, non-zero on failure.
1126 * @param ppBlockTail Pointer to the allocator tail pointer.
1127 * @param pchStr The expression to compile.
1128 * @param cchStr The length of the expression to compile.
1129 */
1130static int kmk_cc_exp_compile_common(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr)
1131{
1132 /*
1133 * Process the string.
1134 */
1135 while (cchStr > 0)
1136 {
1137 /* Look for dollar sign, marks variable expansion or dollar-escape. */
1138 int rc;
1139 const char *pchDollar = memchr(pchStr, '$', cchStr);
1140 if (pchDollar)
1141 {
1142 /*
1143 * Check for multiple dollar chars.
1144 */
1145 uint32_t offDollar = (uint32_t)(pchDollar - pchStr);
1146 uint32_t cDollars = 1;
1147 while ( offDollar + cDollars < cchStr
1148 && pchStr[offDollar + cDollars] == '$')
1149 cDollars++;
1150
1151 /*
1152 * Emit a string copy for any preceeding stuff, including half of
1153 * the dollars we found (dollar escape: $$ -> $).
1154 * (kmk_cc_exp_emit_copy_string ignore zero length strings).
1155 */
1156 kmk_cc_exp_emit_copy_string(ppBlockTail, pchStr, offDollar + cDollars / 2);
1157 pchStr += offDollar + cDollars;
1158 cchStr -= offDollar + cDollars;
1159
1160 /*
1161 * Odd number of dollar chars means there is a variable to expand
1162 * or function to call.
1163 */
1164 if (cDollars & 1)
1165 {
1166 if (cchStr > 0)
1167 {
1168 char const chOpen = *pchStr;
1169 if (chOpen == '(' || chOpen == '{')
1170 {
1171 /* There are several alternative ways of finding the ending
1172 parenthesis / braces.
1173
1174 GNU make does one thing for functions and variable containing
1175 any '$' chars before the first closing char. While for
1176 variables where a closing char comes before any '$' char, a
1177 simplified approach is taken. This means that for example:
1178
1179 Given VAR=var, the expressions "$(var())" and
1180 "$($(VAR)())" would be expanded differently.
1181 In the first case the variable "var(" would be
1182 used and in the second "var()".
1183
1184 This code will not duplicate this weird behavior, but work
1185 the same regardless of whether there is a '$' char before
1186 the first closing char. */
1187 make_function_ptr_t pfnFunction;
1188 const char *pszFunction;
1189 unsigned char cMaxArgs;
1190 unsigned char cMinArgs;
1191 char fExpandArgs;
1192 char const chClose = chOpen == '(' ? ')' : '}';
1193 char ch = 0;
1194 uint32_t cchName = 0;
1195 uint32_t cDepth = 1;
1196 uint32_t cMaxDepth = 1;
1197 cDollars = 0;
1198
1199 pchStr++;
1200 cchStr--;
1201
1202 /* First loop: Identify potential function calls and dynamic expansion. */
1203 KMK_CC_ASSERT(!func_char_map[chOpen]);
1204 KMK_CC_ASSERT(!func_char_map[chClose]);
1205 KMK_CC_ASSERT(!func_char_map['$']);
1206 while (cchName < cchStr)
1207 {
1208 ch = pchStr[cchName];
1209 if (!func_char_map[(int)ch])
1210 break;
1211 cchName++;
1212 }
1213
1214 if ( cchName >= MIN_FUNCTION_LENGTH
1215 && cchName <= MAX_FUNCTION_LENGTH
1216 && (isblank(ch) || ch == chClose || cchName == cchStr)
1217 && (pfnFunction = lookup_function_for_compiler(pchStr, cchName, &cMinArgs, &cMaxArgs,
1218 &fExpandArgs, &pszFunction)) != NULL)
1219 {
1220 /*
1221 * It's a function invocation, we should count parameters while
1222 * looking for the end.
1223 * Note! We use cchName for the length of the argument list.
1224 */
1225 uint32_t cArgs = 1;
1226 if (ch != chClose)
1227 {
1228 /* Skip leading spaces before the first arg. */
1229 cchName++;
1230 while (cchName < cchStr && isblank((unsigned char)pchStr[cchName]))
1231 cchName++;
1232
1233 pchStr += cchName;
1234 cchStr -= cchName;
1235 cchName = 0;
1236
1237 while (cchName < cchStr)
1238 {
1239 ch = pchStr[cchName];
1240 if (ch == ',')
1241 {
1242 if (cDepth == 1)
1243 cArgs++;
1244 }
1245 else if (ch == chClose)
1246 {
1247 if (!--cDepth)
1248 break;
1249 }
1250 else if (ch == chOpen)
1251 {
1252 if (++cDepth > cMaxDepth)
1253 cMaxDepth = cDepth;
1254 }
1255 else if (ch == '$')
1256 cDollars++;
1257 cchName++;
1258 }
1259 }
1260 else
1261 {
1262 pchStr += cchName;
1263 cchStr -= cchName;
1264 cchName = 0;
1265 }
1266 if (cArgs < cMinArgs)
1267 {
1268 fatal(NULL, _("Function '%.*s' takes a minimum of %d arguments: %d given"),
1269 pszFunction, (int)cMinArgs, (int)cArgs);
1270 return -1; /* not reached */
1271 }
1272 if (cDepth != 0)
1273 {
1274 fatal(NULL, chOpen == '('
1275 ? _("Missing closing parenthesis calling '%s'") : _("Missing closing braces calling '%s'"),
1276 pszFunction);
1277 return -1; /* not reached */
1278 }
1279 if (cMaxDepth > 16 && fExpandArgs)
1280 {
1281 fatal(NULL, _("Too many levels of nested function arguments expansions: %s"), pszFunction);
1282 return -1; /* not reached */
1283 }
1284 if (!fExpandArgs || cDollars == 0)
1285 kmk_cc_exp_emit_plain_function(ppBlockTail, pszFunction, pchStr, cchName,
1286 cArgs, chOpen, chClose, pfnFunction, cMaxArgs);
1287 else
1288 {
1289 rc = kmk_cc_exp_emit_dyn_function(ppBlockTail, pszFunction, pchStr, cchName,
1290 cArgs, chOpen, chClose, pfnFunction, cMaxArgs);
1291 if (rc != 0)
1292 return rc;
1293 }
1294 }
1295 else
1296 {
1297 /*
1298 * Variable, find the end while checking whether anything needs expanding.
1299 */
1300 if (ch == chClose)
1301 cDepth = 0;
1302 else if (cchName < cchStr)
1303 {
1304 if (ch != '$')
1305 {
1306 /* Second loop: Look for things that needs expanding. */
1307 while (cchName < cchStr)
1308 {
1309 ch = pchStr[cchName];
1310 if (ch == chClose)
1311 {
1312 if (!--cDepth)
1313 break;
1314 }
1315 else if (ch == chOpen)
1316 {
1317 if (++cDepth > cMaxDepth)
1318 cMaxDepth = cDepth;
1319 }
1320 else if (ch == '$')
1321 break;
1322 cchName++;
1323 }
1324 }
1325 if (ch == '$')
1326 {
1327 /* Third loop: Something needs expanding, just find the end. */
1328 cDollars = 1;
1329 cchName++;
1330 while (cchName < cchStr)
1331 {
1332 ch = pchStr[cchName];
1333 if (ch == chClose)
1334 {
1335 if (!--cDepth)
1336 break;
1337 }
1338 else if (ch == chOpen)
1339 {
1340 if (++cDepth > cMaxDepth)
1341 cMaxDepth = cDepth;
1342 }
1343 cchName++;
1344 }
1345 }
1346 }
1347 if (cDepth > 0) /* After warning, we just assume they're all there. */
1348 error(NULL, chOpen == '(' ? _("Missing closing parenthesis ") : _("Missing closing braces"));
1349 if (cMaxDepth >= 16)
1350 {
1351 fatal(NULL, _("Too many levels of nested variable expansions: '%.*s'"), (int)cchName + 2, pchStr - 1);
1352 return -1; /* not reached */
1353 }
1354 if (cDollars == 0)
1355 kmk_cc_exp_emit_plain_variable_maybe_sr(ppBlockTail, pchStr, cchName);
1356 else
1357 {
1358 rc = kmk_cc_exp_emit_dyn_variable(ppBlockTail, pchStr, cchName);
1359 if (rc != 0)
1360 return rc;
1361 }
1362 }
1363 pchStr += cchName + 1;
1364 cchStr -= cchName + (cDepth == 0);
1365 }
1366 else
1367 {
1368 /* Single character variable name. */
1369 kmk_cc_exp_emit_plain_variable_maybe_sr(ppBlockTail, pchStr, 1);
1370 pchStr++;
1371 cchStr--;
1372 }
1373 }
1374 else
1375 {
1376 error(NULL, _("Unexpected end of string after $"));
1377 break;
1378 }
1379 }
1380 }
1381 else
1382 {
1383 /*
1384 * Nothing more to expand, the remainder is a simple string copy.
1385 */
1386 kmk_cc_exp_emit_copy_string(ppBlockTail, pchStr, cchStr);
1387 break;
1388 }
1389 }
1390
1391 /*
1392 * Emit final instruction.
1393 */
1394 kmk_cc_exp_emit_return(ppBlockTail);
1395 return 0;
1396}
1397
1398
1399/**
1400 * Initializes string expansion program statistics.
1401 * @param pStats Pointer to the statistics structure to init.
1402 */
1403static void kmk_cc_exp_stats_init(PKMKCCEXPSTATS pStats)
1404{
1405 pStats->cchAvg = 0;
1406}
1407
1408
1409/**
1410 * Compiles a string expansion sub program.
1411 *
1412 * The caller typically make a call to kmk_cc_block_get_next_ptr after this
1413 * function returns to figure out where to continue executing.
1414 *
1415 * @returns 0 on success, non-zero on failure.
1416 * @param ppBlockTail Pointer to the allocator tail pointer.
1417 * @param pchStr Pointer to the string to compile an expansion
1418 * program for (ASSUMED to be valid for the
1419 * lifetime of the program).
1420 * @param cchStr The length of the string to compile. Expected to
1421 * be at least on char long.
1422 * @param pSubProg The sub program structure to initialize.
1423 */
1424static int kmk_cc_exp_compile_subprog(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr, PKMKCCEXPSUBPROG pSubProg)
1425{
1426 KMK_CC_ASSERT(cchStr > 0);
1427 pSubProg->pFirstInstr = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
1428 kmk_cc_exp_stats_init(&pSubProg->Stats);
1429 return kmk_cc_exp_compile_common(ppBlockTail, pchStr, cchStr);
1430}
1431
1432
1433/**
1434 * Compiles a string expansion program.
1435 *
1436 * @returns Pointer to the program on success, NULL on failure.
1437 * @param pchStr Pointer to the string to compile an expansion
1438 * program for (ASSUMED to be valid for the
1439 * lifetime of the program).
1440 * @param cchStr The length of the string to compile. Expected to
1441 * be at least on char long.
1442 */
1443static PKMKCCEXPPROG kmk_cc_exp_compile(const char *pchStr, uint32_t cchStr)
1444{
1445 /*
1446 * Estimate block size, allocate one and initialize it.
1447 */
1448 PKMKCCEXPPROG pProg;
1449 PKMKCCBLOCK pBlock;
1450 pProg = kmk_cc_block_alloc_first(&pBlock, sizeof(*pProg),
1451 (kmk_cc_count_dollars(pchStr, cchStr) + 4) * 8);
1452 if (pProg)
1453 {
1454 int rc = 0;
1455
1456 pProg->pBlockTail = pBlock;
1457 pProg->pFirstInstr = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(pBlock);
1458 kmk_cc_exp_stats_init(&pProg->Stats);
1459#ifdef KMK_CC_STRICT
1460 pProg->uInputHash = kmk_cc_debug_string_hash_n(0, pchStr, cchStr);
1461#endif
1462
1463 /*
1464 * Join forces with the sub program compilation code.
1465 */
1466 if (kmk_cc_exp_compile_common(&pProg->pBlockTail, pchStr, cchStr) == 0)
1467 {
1468#ifdef KMK_CC_WITH_STATS
1469 pBlock = pProg->pBlockTail;
1470 if (!pBlock->pNext)
1471 g_cSingleBlockExpProgs++;
1472 else if (!pBlock->pNext->pNext)
1473 g_cTwoBlockExpProgs++;
1474 else
1475 g_cMultiBlockExpProgs++;
1476 for (; pBlock; pBlock = pBlock->pNext)
1477 {
1478 g_cBlocksAllocatedExpProgs++;
1479 g_cbAllocatedExpProgs += pBlock->cbBlock;
1480 g_cbUnusedMemExpProgs += pBlock->cbBlock - pBlock->offNext;
1481 }
1482#endif
1483 return pProg;
1484 }
1485 kmk_cc_block_free_list(pProg->pBlockTail);
1486 }
1487 return NULL;
1488}
1489
1490
1491/**
1492 * Compiles a variable direct evaluation as is, setting v->evalprog on success.
1493 *
1494 * @returns Pointer to the program on success, NULL if no program was created.
1495 * @param pVar Pointer to the variable.
1496 */
1497struct kmk_cc_evalprog *kmk_cc_compile_variable_for_eval(struct variable *pVar)
1498{
1499 return NULL;
1500}
1501
1502
1503/**
1504 * Updates the recursive_without_dollar member of a variable structure.
1505 *
1506 * This avoid compiling string expansion programs without only a CopyString
1507 * instruction. By setting recursive_without_dollar to 1, code calling
1508 * kmk_cc_compile_variable_for_expand and kmk_exec_expand_to_var_buf will
1509 * instead treat start treating it as a simple variable, which is faster.
1510 *
1511 * @returns The updated recursive_without_dollar value.
1512 * @param pVar Pointer to the variable.
1513 */
1514static int kmk_cc_update_variable_recursive_without_dollar(struct variable *pVar)
1515{
1516 int fValue;
1517 KMK_CC_ASSERT(pVar->recursive_without_dollar == 0);
1518
1519 if (memchr(pVar->value, '$', pVar->value_length))
1520 fValue = -1;
1521 else
1522 fValue = 1;
1523 pVar->recursive_without_dollar = fValue;
1524
1525 return fValue;
1526}
1527
1528
1529/**
1530 * Compiles a variable for string expansion.
1531 *
1532 * @returns Pointer to the string expansion program on success, NULL if no
1533 * program was created.
1534 * @param pVar Pointer to the variable.
1535 */
1536struct kmk_cc_expandprog *kmk_cc_compile_variable_for_expand(struct variable *pVar)
1537{
1538 KMK_CC_ASSERT(strlen(pVar->value) == pVar->value_length);
1539 KMK_CC_ASSERT(!pVar->expandprog);
1540 KMK_CC_ASSERT(pVar->recursive_without_dollar <= 0);
1541
1542 if ( !pVar->expandprog
1543 && pVar->recursive)
1544 {
1545 if ( pVar->recursive_without_dollar < 0
1546 || ( pVar->recursive_without_dollar == 0
1547 && kmk_cc_update_variable_recursive_without_dollar(pVar) < 0) )
1548 {
1549 pVar->expandprog = kmk_cc_exp_compile(pVar->value, pVar->value_length);
1550 g_cVarForExpandCompilations++;
1551 }
1552 }
1553 return pVar->expandprog;
1554}
1555
1556
1557/**
1558 * String expansion execution worker for outputting a variable.
1559 *
1560 * @returns The new variable buffer position.
1561 * @param pVar The variable to reference.
1562 * @param pchDst The current variable buffer position.
1563 */
1564static char *kmk_exec_expand_worker_reference_variable(struct variable *pVar, char *pchDst)
1565{
1566 if (pVar->value_length > 0)
1567 {
1568 if (!pVar->recursive || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(pVar))
1569 pchDst = variable_buffer_output(pchDst, pVar->value, pVar->value_length);
1570 else
1571 pchDst = reference_recursive_variable(pchDst, pVar);
1572 }
1573 else if (pVar->append)
1574 pchDst = reference_recursive_variable(pchDst, pVar);
1575 return pchDst;
1576}
1577
1578
1579/**
1580 * Executes a stream string expansion instructions, outputting to the current
1581 * varaible buffer.
1582 *
1583 * @returns The new variable buffer position.
1584 * @param pInstrCore The instruction to start executing at.
1585 * @param pchDst The current variable buffer position.
1586 */
1587static char *kmk_exec_expand_instruction_stream_to_var_buf(PKMKCCEXPCORE pInstrCore, char *pchDst)
1588{
1589 for (;;)
1590 {
1591 switch (pInstrCore->enmOpCode)
1592 {
1593 case kKmkCcExpInstr_CopyString:
1594 {
1595 PKMKCCEXPCOPYSTRING pInstr = (PKMKCCEXPCOPYSTRING)pInstrCore;
1596 pchDst = variable_buffer_output(pchDst, pInstr->pachSrc, pInstr->cchCopy);
1597
1598 pInstrCore = &(pInstr + 1)->Core;
1599 break;
1600 }
1601
1602 case kKmkCcExpInstr_PlainVariable:
1603 {
1604 PKMKCCEXPPLAINVAR pInstr = (PKMKCCEXPPLAINVAR)pInstrCore;
1605 struct variable *pVar = lookup_variable_strcached(pInstr->pszName);
1606 if (pVar)
1607 pchDst = kmk_exec_expand_worker_reference_variable(pVar, pchDst);
1608 else
1609 warn_undefined(pInstr->pszName, strcache2_get_len(&variable_strcache, pInstr->pszName));
1610
1611 pInstrCore = &(pInstr + 1)->Core;
1612 break;
1613 }
1614
1615 case kKmkCcExpInstr_DynamicVariable:
1616 {
1617 PKMKCCEXPDYNVAR pInstr = (PKMKCCEXPDYNVAR)pInstrCore;
1618 struct variable *pVar;
1619 uint32_t cchName;
1620 char *pszName = kmk_exec_expand_subprog_to_tmp(&pInstr->SubProg, &cchName);
1621 char *pszColon = (char *)memchr(pszName, ':', cchName);
1622 char *pszEqual;
1623 if ( pszColon == NULL
1624 || (pszEqual = (char *)memchr(pszColon + 1, '=', &pszName[cchName] - pszColon - 1)) == NULL
1625 || pszEqual == pszColon + 1)
1626 {
1627 pVar = lookup_variable(pszName, cchName);
1628 if (pVar)
1629 pchDst = kmk_exec_expand_worker_reference_variable(pVar, pchDst);
1630 else
1631 warn_undefined(pszName, cchName);
1632 }
1633 else if (pszColon != pszName)
1634 {
1635 /*
1636 * Oh, we have to do search and replace. How tedious.
1637 * Since the variable name is a temporary buffer, we can transform
1638 * the strings into proper search and replacement patterns directly.
1639 */
1640 pVar = lookup_variable(pszName, pszColon - pszName);
1641 if (pVar)
1642 {
1643 char const *pszExpandedVarValue = pVar->recursive ? recursively_expand(pVar) : pVar->value;
1644 char *pszSearchPat = pszColon + 1;
1645 char *pszReplacePat = pszEqual + 1;
1646 const char *pchPctSearchPat;
1647 const char *pchPctReplacePat;
1648
1649 *pszEqual = '\0';
1650 pchPctSearchPat = find_percent(pszSearchPat);
1651 pchPctReplacePat = find_percent(pszReplacePat);
1652
1653 if (!pchPctReplacePat)
1654 {
1655 if (pszReplacePat[-2] != '\0') /* On the offchance that a pct was unquoted by find_percent. */
1656 {
1657 memmove(pszName + 1, pszSearchPat, pszReplacePat - pszSearchPat);
1658 if (pchPctSearchPat)
1659 pchPctSearchPat -= pszSearchPat - &pszName[1];
1660 pszSearchPat = &pszName[1];
1661 }
1662 pchPctReplacePat = --pszReplacePat;
1663 *pszReplacePat = '%';
1664 }
1665
1666 if (!pchPctSearchPat)
1667 {
1668 pchPctSearchPat = --pszSearchPat;
1669 *pszSearchPat = '%';
1670 }
1671
1672 pchDst = patsubst_expand_pat(pchDst, pszExpandedVarValue,
1673 pszSearchPat, pszReplacePat,
1674 pchPctSearchPat, pchPctReplacePat);
1675
1676 if (pVar->recursive)
1677 free((void *)pszExpandedVarValue);
1678 }
1679 else
1680 warn_undefined(pszName, pszColon - pszName);
1681 }
1682 free(pszName);
1683
1684 pInstrCore = pInstr->pNext;
1685 break;
1686 }
1687
1688
1689 case kKmkCcExpInstr_SearchAndReplacePlainVariable:
1690 {
1691 PKMKCCEXPSRPLAINVAR pInstr = (PKMKCCEXPSRPLAINVAR)pInstrCore;
1692 struct variable *pVar = lookup_variable_strcached(pInstr->pszName);
1693 if (pVar)
1694 {
1695 char const *pszExpandedVarValue = pVar->recursive ? recursively_expand(pVar) : pVar->value;
1696 pchDst = patsubst_expand_pat(pchDst,
1697 pszExpandedVarValue,
1698 pInstr->pszSearchPattern,
1699 pInstr->pszReplacePattern,
1700 &pInstr->pszSearchPattern[pInstr->offPctSearchPattern],
1701 &pInstr->pszReplacePattern[pInstr->offPctReplacePattern]);
1702 if (pVar->recursive)
1703 free((void *)pszExpandedVarValue);
1704 }
1705 else
1706 warn_undefined(pInstr->pszName, strcache2_get_len(&variable_strcache, pInstr->pszName));
1707
1708 pInstrCore = pInstr->pNext;
1709 break;
1710 }
1711
1712 case kKmkCcExpInstr_PlainFunction:
1713 {
1714 PKMKCCEXPPLAINFUNC pInstr = (PKMKCCEXPPLAINFUNC)pInstrCore;
1715 uint32_t iArg;
1716 if (!pInstr->Core.fDirty)
1717 {
1718#ifdef KMK_CC_STRICT
1719 uint32_t uCrcBefore = 0;
1720 uint32_t uCrcAfter = 0;
1721 iArg = pInstr->Core.cArgs;
1722 while (iArg-- > 0)
1723 uCrcBefore = kmk_cc_debug_string_hash(uCrcBefore, pInstr->apszArgs[iArg]);
1724#endif
1725
1726 pchDst = pInstr->Core.pfnFunction(pchDst, (char **)&pInstr->apszArgs[0], pInstr->Core.pszFuncName);
1727
1728#ifdef KMK_CC_STRICT
1729 iArg = pInstr->Core.cArgs;
1730 while (iArg-- > 0)
1731 uCrcAfter = kmk_cc_debug_string_hash(uCrcAfter, pInstr->apszArgs[iArg]);
1732 KMK_CC_ASSERT(uCrcBefore == uCrcAfter);
1733#endif
1734 }
1735 else
1736 {
1737 char **papszShadowArgs = xmalloc((pInstr->Core.cArgs * 2 + 1) * sizeof(papszShadowArgs[0]));
1738 char **papszArgs = &papszShadowArgs[pInstr->Core.cArgs];
1739
1740 iArg = pInstr->Core.cArgs;
1741 papszArgs[iArg] = NULL;
1742 while (iArg-- > 0)
1743 papszArgs[iArg] = papszShadowArgs[iArg] = xstrdup(pInstr->apszArgs[iArg]);
1744
1745 pchDst = pInstr->Core.pfnFunction(pchDst, (char **)&pInstr->apszArgs[0], pInstr->Core.pszFuncName);
1746
1747 iArg = pInstr->Core.cArgs;
1748 while (iArg-- > 0)
1749 free(papszShadowArgs[iArg]);
1750 free(papszShadowArgs);
1751 }
1752
1753 pInstrCore = pInstr->Core.pNext;
1754 break;
1755 }
1756
1757 case kKmkCcExpInstr_DynamicFunction:
1758 {
1759 PKMKCCEXPDYNFUNC pInstr = (PKMKCCEXPDYNFUNC)pInstrCore;
1760 char **papszArgsShadow = xmalloc( (pInstr->Core.cArgs * 2 + 1) * sizeof(char *));
1761 char **papszArgs = &papszArgsShadow[pInstr->Core.cArgs];
1762 uint32_t iArg;
1763
1764 if (!pInstr->Core.fDirty)
1765 {
1766#ifdef KMK_CC_STRICT
1767 uint32_t uCrcBefore = 0;
1768 uint32_t uCrcAfter = 0;
1769#endif
1770 iArg = pInstr->Core.cArgs;
1771 papszArgs[iArg] = NULL;
1772 while (iArg-- > 0)
1773 {
1774 char *pszArg;
1775 if (!pInstr->aArgs[iArg].fPlain)
1776 pszArg = kmk_exec_expand_subprog_to_tmp(&pInstr->aArgs[iArg].u.SubProg, NULL);
1777 else
1778 pszArg = (char *)pInstr->aArgs[iArg].u.Plain.pszArg;
1779 papszArgsShadow[iArg] = pszArg;
1780 papszArgs[iArg] = pszArg;
1781#ifdef KMK_CC_STRICT
1782 uCrcBefore = kmk_cc_debug_string_hash(uCrcBefore, pszArg);
1783#endif
1784 }
1785 pchDst = pInstr->Core.pfnFunction(pchDst, papszArgs, pInstr->Core.pszFuncName);
1786
1787 iArg = pInstr->Core.cArgs;
1788 while (iArg-- > 0)
1789 {
1790#ifdef KMK_CC_STRICT
1791 KMK_CC_ASSERT(papszArgsShadow[iArg] == papszArgs[iArg]);
1792 uCrcAfter = kmk_cc_debug_string_hash(uCrcAfter, papszArgsShadow[iArg]);
1793#endif
1794 if (!pInstr->aArgs[iArg].fPlain)
1795 free(papszArgsShadow[iArg]);
1796 }
1797 KMK_CC_ASSERT(uCrcBefore == uCrcAfter);
1798 }
1799 else
1800 {
1801 iArg = pInstr->Core.cArgs;
1802 papszArgs[iArg] = NULL;
1803 while (iArg-- > 0)
1804 {
1805 char *pszArg;
1806 if (!pInstr->aArgs[iArg].fPlain)
1807 pszArg = kmk_exec_expand_subprog_to_tmp(&pInstr->aArgs[iArg].u.SubProg, NULL);
1808 else
1809 pszArg = xstrdup(pInstr->aArgs[iArg].u.Plain.pszArg);
1810 papszArgsShadow[iArg] = pszArg;
1811 papszArgs[iArg] = pszArg;
1812 }
1813
1814 pchDst = pInstr->Core.pfnFunction(pchDst, papszArgs, pInstr->Core.pszFuncName);
1815
1816 iArg = pInstr->Core.cArgs;
1817 while (iArg-- > 0)
1818 free(papszArgsShadow[iArg]);
1819 }
1820 free(papszArgsShadow);
1821
1822 pInstrCore = pInstr->Core.pNext;
1823 break;
1824 }
1825
1826 case kKmkCcExpInstr_Jump:
1827 {
1828 PKMKCCEXPJUMP pInstr = (PKMKCCEXPJUMP)pInstrCore;
1829 pInstrCore = pInstr->pNext;
1830 break;
1831 }
1832
1833 case kKmkCcExpInstr_Return:
1834 return pchDst;
1835
1836 default:
1837 fatal(NULL, _("Unknown string expansion opcode: %d (%#x)"),
1838 (int)pInstrCore->enmOpCode, (int)pInstrCore->enmOpCode);
1839 return NULL;
1840 }
1841 }
1842}
1843
1844
1845/**
1846 * Updates the string expansion statistics.
1847 *
1848 * @param pStats The statistics structure to update.
1849 * @param cchResult The result lenght.
1850 */
1851void kmk_cc_exp_stats_update(PKMKCCEXPSTATS pStats, uint32_t cchResult)
1852{
1853 /*
1854 * The average is simplified and not an exact average for every
1855 * expansion that has taken place.
1856 */
1857 pStats->cchAvg = (pStats->cchAvg * 7 + cchResult) / 8;
1858}
1859
1860
1861/**
1862 * Execute a string expansion sub-program, outputting to a new heap buffer.
1863 *
1864 * @returns Pointer to the output buffer (hand to free when done).
1865 * @param pSubProg The sub-program to execute.
1866 * @param pcchResult Where to return the size of the result. Optional.
1867 */
1868static char *kmk_exec_expand_subprog_to_tmp(PKMKCCEXPSUBPROG pSubProg, uint32_t *pcchResult)
1869{
1870 char *pchOldVarBuf;
1871 unsigned int cbOldVarBuf;
1872 char *pchDst;
1873 char *pszResult;
1874 uint32_t cchResult;
1875
1876 /*
1877 * Temporarily replace the variable buffer while executing the instruction
1878 * stream for this sub program.
1879 */
1880 pchDst = install_variable_buffer_with_hint(&pchOldVarBuf, &cbOldVarBuf,
1881 pSubProg->Stats.cchAvg ? pSubProg->Stats.cchAvg + 32 : 256);
1882
1883 pchDst = kmk_exec_expand_instruction_stream_to_var_buf(pSubProg->pFirstInstr, pchDst);
1884
1885 /* Ensure that it's terminated. */
1886 pchDst = variable_buffer_output(pchDst, "\0", 1) - 1;
1887
1888 /* Grab the result buffer before restoring the previous one. */
1889 pszResult = variable_buffer;
1890 cchResult = (uint32_t)(pchDst - pszResult);
1891 if (pcchResult)
1892 *pcchResult = cchResult;
1893 kmk_cc_exp_stats_update(&pSubProg->Stats, cchResult);
1894
1895 variable_buffer = pchOldVarBuf;
1896 variable_buffer_length = cbOldVarBuf;
1897
1898 return pszResult;
1899}
1900
1901
1902/**
1903 * Execute a string expansion program, outputting to the current variable
1904 * buffer.
1905 *
1906 * @returns New variable buffer position.
1907 * @param pProg The program to execute.
1908 * @param pchDst The current varaible buffer position.
1909 */
1910static char *kmk_exec_expand_prog_to_var_buf(PKMKCCEXPPROG pProg, char *pchDst)
1911{
1912 uint32_t cchResult;
1913 uint32_t offStart = (uint32_t)(pchDst - variable_buffer);
1914
1915 if (pProg->Stats.cchAvg >= variable_buffer_length - offStart)
1916 pchDst = ensure_variable_buffer_space(pchDst, offStart + pProg->Stats.cchAvg + 32);
1917
1918 pchDst = kmk_exec_expand_instruction_stream_to_var_buf(pProg->pFirstInstr, pchDst);
1919
1920 cchResult = (uint32_t)(pchDst - variable_buffer);
1921 KMK_CC_ASSERT(cchResult >= offStart);
1922 cchResult -= offStart;
1923 kmk_cc_exp_stats_update(&pProg->Stats, cchResult);
1924 g_cVarForExpandExecs++;
1925
1926 return pchDst;
1927}
1928
1929
1930/**
1931 * Equivalent of eval_buffer, only it's using the evalprog of the variable.
1932 *
1933 * @param pVar Pointer to the variable. Must have a program.
1934 */
1935void kmk_exec_evalval(struct variable *pVar)
1936{
1937 KMK_CC_ASSERT(pVar->evalprog);
1938 assert(0);
1939}
1940
1941
1942/**
1943 * Expands a variable into a variable buffer using its expandprog.
1944 *
1945 * @returns The new variable buffer position.
1946 * @param pVar Pointer to the variable. Must have a program.
1947 * @param pchDst Pointer to the current variable buffer position.
1948 */
1949char *kmk_exec_expand_to_var_buf(struct variable *pVar, char *pchDst)
1950{
1951 KMK_CC_ASSERT(pVar->expandprog);
1952 KMK_CC_ASSERT(pVar->expandprog->uInputHash == kmk_cc_debug_string_hash(0, pVar->value));
1953 return kmk_exec_expand_prog_to_var_buf(pVar->expandprog, pchDst);
1954}
1955
1956
1957/**
1958 * Called when a variable with expandprog or/and evalprog changes.
1959 *
1960 * @param pVar Pointer to the variable.
1961 */
1962void kmk_cc_variable_changed(struct variable *pVar)
1963{
1964 KMK_CC_ASSERT(pVar->evalprog || pVar->expandprog);
1965#if 0
1966 if (pVar->evalprog)
1967 {
1968 kmk_cc_block_free_list(pVar->evalprog->pBlockTail);
1969 pVar->evalprog = NULL;
1970 }
1971#endif
1972 if (pVar->expandprog)
1973 {
1974 kmk_cc_block_free_list(pVar->expandprog->pBlockTail);
1975 pVar->expandprog = NULL;
1976 }
1977}
1978
1979
1980/**
1981 * Called when a variable with expandprog or/and evalprog is deleted.
1982 *
1983 * @param pVar Pointer to the variable.
1984 */
1985void kmk_cc_variable_deleted(struct variable *pVar)
1986{
1987 KMK_CC_ASSERT(pVar->evalprog || pVar->expandprog);
1988#if 0
1989 if (pVar->evalprog)
1990 {
1991 kmk_cc_block_free_list(pVar->evalprog->pBlockTail);
1992 pVar->evalprog = NULL;
1993 }
1994#endif
1995 if (pVar->expandprog)
1996 {
1997 kmk_cc_block_free_list(pVar->expandprog->pBlockTail);
1998 pVar->expandprog = NULL;
1999 }
2000}
2001
2002
2003#endif /* CONFIG_WITH_COMPILER */
2004
Note: See TracBrowser for help on using the repository browser.

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