VirtualBox

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

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

kmk_cc_exec.c: Make sure the variable doesn't get modified while we're running the expansion program. It'll screw up our string references.

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