VirtualBox

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

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

Optimizations, tuning and bug fixes for the 'compiled' string expansion code.

  • 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 2771 2015-02-01 20:48:36Z bird $ */
3/** @file
4 * kmk_cc - Make "Compiler".
5 */
6
7/*
8 * Copyright (c) 2015 knut st. osmundsen <[email protected]>
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 * @returns 0 on success, non-zero on failure.
749 * @param ppBlockTail Pointer to the allocator tail pointer.
750 */
751static int kmk_cc_exp_emit_return(PKMKCCBLOCK *ppBlockTail)
752{
753 PKMKCCEXPCORE pCore = kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pCore));
754 pCore->enmOpCode = kKmkCcExpInstr_Return;
755 return 0;
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 int 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 return 0;
980}
981
982
983/**
984 * Emits a kKmkCcExpInstr_DynamicVariable.
985 *
986 * @returns 0 on success, non-zero on failure.
987 * @param ppBlockTail Pointer to the allocator tail pointer.
988 * @param pchNameExpr The name of the variable (ASSUMED presistent
989 * thru-out the program life time).
990 * @param cchNameExpr The length of the variable name. If zero,
991 * nothing will be emitted.
992 */
993static int kmk_cc_exp_emit_dyn_variable(PKMKCCBLOCK *ppBlockTail, const char *pchNameExpr, uint32_t cchNameExpr)
994{
995 PKMKCCEXPDYNVAR pInstr;
996 int rc;
997 KMK_CC_ASSERT(cchNameExpr > 0);
998
999 pInstr = (PKMKCCEXPDYNVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
1000 pInstr->Core.enmOpCode = kKmkCcExpInstr_DynamicVariable;
1001
1002 rc = kmk_cc_exp_compile_subprog(ppBlockTail, pchNameExpr, cchNameExpr, &pInstr->SubProg);
1003
1004 pInstr->pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
1005 return rc;
1006}
1007
1008
1009/**
1010 * Emits either a kKmkCcExpInstr_PlainVariable or
1011 * kKmkCcExpInstr_SearchAndReplacePlainVariable instruction.
1012 *
1013 * @returns 0 on success, non-zero on failure.
1014 * @param ppBlockTail Pointer to the allocator tail pointer.
1015 * @param pchName The name of the variable. (Does not need to be
1016 * valid beyond the call.)
1017 * @param cchName The length of the variable name. If zero,
1018 * nothing will be emitted.
1019 */
1020static int kmk_cc_exp_emit_plain_variable_maybe_sr(PKMKCCBLOCK *ppBlockTail, const char *pchName, uint32_t cchName)
1021{
1022 if (cchName > 0)
1023 {
1024 /*
1025 * Hopefully, we're not expected to do any search and replace on the
1026 * expanded variable string later... Requires both ':' and '='.
1027 */
1028 const char *pchEqual;
1029 const char *pchColon = (const char *)memchr(pchName, ':', cchName);
1030 if ( pchColon == NULL
1031 || (pchEqual = (const char *)memchr(pchColon + 1, ':', cchName - (pchColon - pchName - 1))) == NULL
1032 || pchEqual == pchEqual + 1)
1033 {
1034 PKMKCCEXPPLAINVAR pInstr = (PKMKCCEXPPLAINVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
1035 pInstr->Core.enmOpCode = kKmkCcExpInstr_PlainVariable;
1036 pInstr->pszName = strcache2_add(&variable_strcache, pchName, cchName);
1037 }
1038 else if (pchColon != pchName)
1039 {
1040 /*
1041 * Okay, we need to do search and replace the variable value.
1042 * This is performed by patsubst_expand_pat using '%' patterns.
1043 */
1044 uint32_t cchName2 = (uint32_t)(pchColon - pchName);
1045 uint32_t cchSearch = (uint32_t)(pchEqual - pchColon - 1);
1046 uint32_t cchReplace = cchName - cchName2 - cchSearch - 2;
1047 const char *pchPct;
1048 char *psz;
1049 PKMKCCEXPSRPLAINVAR pInstr;
1050
1051 pInstr = (PKMKCCEXPSRPLAINVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
1052 pInstr->Core.enmOpCode = kKmkCcExpInstr_SearchAndReplacePlainVariable;
1053 pInstr->pszName = strcache2_add(&variable_strcache, pchName, cchName2);
1054
1055 /* Figure out the search pattern, unquoting percent chars.. */
1056 psz = (char *)kmk_cc_block_byte_alloc(ppBlockTail, cchSearch + 2);
1057 psz[0] = '%';
1058 memcpy(psz + 1, pchColon + 1, cchSearch);
1059 psz[1 + cchSearch] = '\0';
1060 pchPct = find_percent(psz + 1); /* also performs unquoting */
1061 if (pchPct)
1062 {
1063 pInstr->pszSearchPattern = psz + 1;
1064 pInstr->offPctSearchPattern = (uint32_t)(pchPct - psz - 1);
1065 }
1066 else
1067 {
1068 pInstr->pszSearchPattern = psz;
1069 pInstr->offPctSearchPattern = 0;
1070 }
1071
1072 /* Figure out the replacement pattern, unquoting percent chars.. */
1073 if (cchReplace == 0)
1074 {
1075 pInstr->pszReplacePattern = "%";
1076 pInstr->offPctReplacePattern = 0;
1077 }
1078 else
1079 {
1080 psz = (char *)kmk_cc_block_byte_alloc(ppBlockTail, cchReplace + 2);
1081 psz[0] = '%';
1082 memcpy(psz + 1, pchEqual + 1, cchReplace);
1083 psz[1 + cchReplace] = '\0';
1084 pchPct = find_percent(psz + 1); /* also performs unquoting */
1085 if (pchPct)
1086 {
1087 pInstr->pszReplacePattern = psz + 1;
1088 pInstr->offPctReplacePattern = (uint32_t)(pchPct - psz - 1);
1089 }
1090 else
1091 {
1092 pInstr->pszReplacePattern = psz;
1093 pInstr->offPctReplacePattern = 0;
1094 }
1095 }
1096
1097 /* Note down where the next instruction is after realigning the allocator. */
1098 kmk_cc_block_realign(ppBlockTail);
1099 pInstr->pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
1100 }
1101 }
1102 return 0;
1103}
1104
1105
1106/**
1107 * Emits a kKmkCcExpInstr_CopyString.
1108 *
1109 * @returns 0 on success, non-zero on failure.
1110 * @param ppBlockTail Pointer to the allocator tail pointer.
1111 * @param pchStr The string to emit (ASSUMED presistent thru-out
1112 * the program life time).
1113 * @param cchStr The number of chars to copy. If zero, nothing
1114 * will be emitted.
1115 */
1116static int kmk_cc_exp_emit_copy_string(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr)
1117{
1118 if (cchStr > 0)
1119 {
1120 PKMKCCEXPCOPYSTRING pInstr = (PKMKCCEXPCOPYSTRING)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
1121 pInstr->Core.enmOpCode = kKmkCcExpInstr_CopyString;
1122 pInstr->cchCopy = cchStr;
1123 pInstr->pachSrc = pchStr;
1124 }
1125 return 0;
1126}
1127
1128
1129/**
1130 * String expansion compilation function common to both normal and sub programs.
1131 *
1132 * @returns 0 on success, non-zero on failure.
1133 * @param ppBlockTail Pointer to the allocator tail pointer.
1134 * @param pchStr The expression to compile.
1135 * @param cchStr The length of the expression to compile.
1136 */
1137static int kmk_cc_exp_compile_common(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr)
1138{
1139 /*
1140 * Process the string.
1141 */
1142 while (cchStr > 0)
1143 {
1144 /* Look for dollar sign, marks variable expansion or dollar-escape. */
1145 int rc;
1146 const char *pchDollar = memchr(pchStr, '$', cchStr);
1147 if (pchDollar)
1148 {
1149 /*
1150 * Check for multiple dollar chars.
1151 */
1152 uint32_t offDollar = (uint32_t)(pchDollar - pchStr);
1153 uint32_t cDollars = 1;
1154 while ( offDollar + cDollars < cchStr
1155 && pchStr[offDollar + cDollars] == '$')
1156 cDollars++;
1157
1158 /*
1159 * Emit a string copy for any preceeding stuff, including half of
1160 * the dollars we found (dollar escape: $$ -> $).
1161 * (kmk_cc_exp_emit_copy_string ignore zero length strings).
1162 */
1163 rc = kmk_cc_exp_emit_copy_string(ppBlockTail, pchStr, offDollar + cDollars / 2);
1164 if (rc != 0)
1165 return rc;
1166 pchStr += offDollar + cDollars;
1167 cchStr -= offDollar + cDollars;
1168
1169 /*
1170 * Odd number of dollar chars means there is a variable to expand
1171 * or function to call.
1172 */
1173 if (cDollars & 1)
1174 {
1175 if (cchStr > 0)
1176 {
1177 char const chOpen = *pchStr;
1178 if (chOpen == '(' || chOpen == '{')
1179 {
1180 /* There are several alternative ways of finding the ending
1181 parenthesis / braces.
1182
1183 GNU make does one thing for functions and variable containing
1184 any '$' chars before the first closing char. While for
1185 variables where a closing char comes before any '$' char, a
1186 simplified approach is taken. This means that for example:
1187
1188 Given VAR=var, the expressions "$(var())" and
1189 "$($(VAR)())" would be expanded differently.
1190 In the first case the variable "var(" would be
1191 used and in the second "var()".
1192
1193 This code will not duplicate this weird behavior, but work
1194 the same regardless of whether there is a '$' char before
1195 the first closing char. */
1196 make_function_ptr_t pfnFunction;
1197 const char *pszFunction;
1198 unsigned char cMaxArgs;
1199 unsigned char cMinArgs;
1200 char fExpandArgs;
1201 char const chClose = chOpen == '(' ? ')' : '}';
1202 char ch = 0;
1203 uint32_t cchName = 0;
1204 uint32_t cDepth = 1;
1205 uint32_t cMaxDepth = 1;
1206 cDollars = 0;
1207
1208 pchStr++;
1209 cchStr--;
1210
1211 /* First loop: Identify potential function calls and dynamic expansion. */
1212 KMK_CC_ASSERT(!func_char_map[chOpen]);
1213 KMK_CC_ASSERT(!func_char_map[chClose]);
1214 KMK_CC_ASSERT(!func_char_map['$']);
1215 while (cchName < cchStr)
1216 {
1217 ch = pchStr[cchName];
1218 if (!func_char_map[(int)ch])
1219 break;
1220 cchName++;
1221 }
1222
1223 if ( cchName >= MIN_FUNCTION_LENGTH
1224 && cchName <= MAX_FUNCTION_LENGTH
1225 && (isblank(ch) || ch == chClose || cchName == cchStr)
1226 && (pfnFunction = lookup_function_for_compiler(pchStr, cchName, &cMinArgs, &cMaxArgs,
1227 &fExpandArgs, &pszFunction)) != NULL)
1228 {
1229 /*
1230 * It's a function invocation, we should count parameters while
1231 * looking for the end.
1232 * Note! We use cchName for the length of the argument list.
1233 */
1234 uint32_t cArgs = 1;
1235 if (ch != chClose)
1236 {
1237 /* Skip leading spaces before the first arg. */
1238 cchName++;
1239 while (cchName < cchStr && isblank((unsigned char)pchStr[cchName]))
1240 cchName++;
1241
1242 pchStr += cchName;
1243 cchStr -= cchName;
1244 cchName = 0;
1245
1246 while (cchName < cchStr)
1247 {
1248 ch = pchStr[cchName];
1249 if (ch == ',')
1250 {
1251 if (cDepth == 1)
1252 cArgs++;
1253 }
1254 else if (ch == chClose)
1255 {
1256 if (!--cDepth)
1257 break;
1258 }
1259 else if (ch == chOpen)
1260 {
1261 if (++cDepth > cMaxDepth)
1262 cMaxDepth = cDepth;
1263 }
1264 else if (ch == '$')
1265 cDollars++;
1266 cchName++;
1267 }
1268 }
1269 else
1270 {
1271 pchStr += cchName;
1272 cchStr -= cchName;
1273 cchName = 0;
1274 }
1275 if (cArgs < cMinArgs)
1276 {
1277 fatal(NULL, _("Function '%.*s' takes a minimum of %d arguments: %d given"),
1278 pszFunction, (int)cMinArgs, (int)cArgs);
1279 return -1; /* not reached */
1280 }
1281 if (cDepth != 0)
1282 {
1283 fatal(NULL, chOpen == '('
1284 ? _("Missing closing parenthesis calling '%s'") : _("Missing closing braces calling '%s'"),
1285 pszFunction);
1286 return -1; /* not reached */
1287 }
1288 if (cMaxDepth > 16 && fExpandArgs)
1289 {
1290 fatal(NULL, _("Too many levels of nested function arguments expansions: %s"), pszFunction);
1291 return -1; /* not reached */
1292 }
1293 if (!fExpandArgs || cDollars == 0)
1294 rc = kmk_cc_exp_emit_plain_function(ppBlockTail, pszFunction, pchStr, cchName,
1295 cArgs, chOpen, chClose, pfnFunction, cMaxArgs);
1296 else
1297 rc = kmk_cc_exp_emit_dyn_function(ppBlockTail, pszFunction, pchStr, cchName,
1298 cArgs, chOpen, chClose, pfnFunction, cMaxArgs);
1299 }
1300 else
1301 {
1302 /*
1303 * Variable, find the end while checking whether anything needs expanding.
1304 */
1305 if (ch == chClose)
1306 cDepth = 0;
1307 else if (cchName < cchStr)
1308 {
1309 if (ch != '$')
1310 {
1311 /* Second loop: Look for things that needs expanding. */
1312 while (cchName < cchStr)
1313 {
1314 ch = pchStr[cchName];
1315 if (ch == chClose)
1316 {
1317 if (!--cDepth)
1318 break;
1319 }
1320 else if (ch == chOpen)
1321 {
1322 if (++cDepth > cMaxDepth)
1323 cMaxDepth = cDepth;
1324 }
1325 else if (ch == '$')
1326 break;
1327 cchName++;
1328 }
1329 }
1330 if (ch == '$')
1331 {
1332 /* Third loop: Something needs expanding, just find the end. */
1333 cDollars = 1;
1334 cchName++;
1335 while (cchName < cchStr)
1336 {
1337 ch = pchStr[cchName];
1338 if (ch == chClose)
1339 {
1340 if (!--cDepth)
1341 break;
1342 }
1343 else if (ch == chOpen)
1344 {
1345 if (++cDepth > cMaxDepth)
1346 cMaxDepth = cDepth;
1347 }
1348 cchName++;
1349 }
1350 }
1351 }
1352 if (cDepth > 0) /* After warning, we just assume they're all there. */
1353 error(NULL, chOpen == '(' ? _("Missing closing parenthesis ") : _("Missing closing braces"));
1354 if (cMaxDepth >= 16)
1355 {
1356 fatal(NULL, _("Too many levels of nested variable expansions: '%.*s'"), (int)cchName + 2, pchStr - 1);
1357 return -1; /* not reached */
1358 }
1359 if (cDollars == 0)
1360 rc = kmk_cc_exp_emit_plain_variable_maybe_sr(ppBlockTail, pchStr, cchName);
1361 else
1362 rc = kmk_cc_exp_emit_dyn_variable(ppBlockTail, pchStr, cchName);
1363 }
1364 pchStr += cchName + 1;
1365 cchStr -= cchName + (cDepth == 0);
1366 }
1367 else
1368 {
1369 /* Single character variable name. */
1370 rc = kmk_cc_exp_emit_plain_variable_maybe_sr(ppBlockTail, pchStr, 1);
1371 pchStr++;
1372 cchStr--;
1373 }
1374 if (rc != 0)
1375 return rc;
1376 }
1377 else
1378 {
1379 error(NULL, _("Unexpected end of string after $"));
1380 break;
1381 }
1382 }
1383 }
1384 else
1385 {
1386 /*
1387 * Nothing more to expand, the remainder is a simple string copy.
1388 */
1389 rc = kmk_cc_exp_emit_copy_string(ppBlockTail, pchStr, cchStr);
1390 if (rc != 0)
1391 return rc;
1392 break;
1393 }
1394 }
1395
1396 /*
1397 * Emit final instruction.
1398 */
1399 return kmk_cc_exp_emit_return(ppBlockTail);
1400}
1401
1402
1403/**
1404 * Initializes string expansion program statistics.
1405 * @param pStats Pointer to the statistics structure to init.
1406 */
1407static void kmk_cc_exp_stats_init(PKMKCCEXPSTATS pStats)
1408{
1409 pStats->cchAvg = 0;
1410}
1411
1412
1413/**
1414 * Compiles a string expansion sub program.
1415 *
1416 * The caller typically make a call to kmk_cc_block_get_next_ptr after this
1417 * function returns to figure out where to continue executing.
1418 *
1419 * @returns 0 on success, non-zero on failure.
1420 * @param ppBlockTail Pointer to the allocator tail pointer.
1421 * @param pchStr Pointer to the string to compile an expansion
1422 * program for (ASSUMED to be valid for the
1423 * lifetime of the program).
1424 * @param cchStr The length of the string to compile. Expected to
1425 * be at least on char long.
1426 * @param pSubProg The sub program structure to initialize.
1427 */
1428static int kmk_cc_exp_compile_subprog(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr, PKMKCCEXPSUBPROG pSubProg)
1429{
1430 KMK_CC_ASSERT(cchStr > 0);
1431 pSubProg->pFirstInstr = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
1432 kmk_cc_exp_stats_init(&pSubProg->Stats);
1433 return kmk_cc_exp_compile_common(ppBlockTail, pchStr, cchStr);
1434}
1435
1436
1437/**
1438 * Compiles a string expansion program.
1439 *
1440 * @returns Pointer to the program on success, NULL on failure.
1441 * @param pchStr Pointer to the string to compile an expansion
1442 * program for (ASSUMED to be valid for the
1443 * lifetime of the program).
1444 * @param cchStr The length of the string to compile. Expected to
1445 * be at least on char long.
1446 */
1447static PKMKCCEXPPROG kmk_cc_exp_compile(const char *pchStr, uint32_t cchStr)
1448{
1449 /*
1450 * Estimate block size, allocate one and initialize it.
1451 */
1452 PKMKCCEXPPROG pProg;
1453 PKMKCCBLOCK pBlock;
1454 pProg = kmk_cc_block_alloc_first(&pBlock, sizeof(*pProg),
1455 (kmk_cc_count_dollars(pchStr, cchStr) + 4) * 8);
1456 if (pProg)
1457 {
1458 int rc = 0;
1459
1460 pProg->pBlockTail = pBlock;
1461 pProg->pFirstInstr = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(pBlock);
1462 kmk_cc_exp_stats_init(&pProg->Stats);
1463#ifdef KMK_CC_STRICT
1464 pProg->uInputHash = kmk_cc_debug_string_hash_n(0, pchStr, cchStr);
1465#endif
1466
1467 /*
1468 * Join forces with the sub program compilation code.
1469 */
1470 if (kmk_cc_exp_compile_common(&pProg->pBlockTail, pchStr, cchStr) == 0)
1471 {
1472#ifdef KMK_CC_WITH_STATS
1473 pBlock = pProg->pBlockTail;
1474 if (!pBlock->pNext)
1475 g_cSingleBlockExpProgs++;
1476 else if (!pBlock->pNext->pNext)
1477 g_cTwoBlockExpProgs++;
1478 else
1479 g_cMultiBlockExpProgs++;
1480 for (; pBlock; pBlock = pBlock->pNext)
1481 {
1482 g_cBlocksAllocatedExpProgs++;
1483 g_cbAllocatedExpProgs += pBlock->cbBlock;
1484 g_cbUnusedMemExpProgs += pBlock->cbBlock - pBlock->offNext;
1485 }
1486#endif
1487 return pProg;
1488 }
1489 kmk_cc_block_free_list(pProg->pBlockTail);
1490 }
1491 return NULL;
1492}
1493
1494
1495/**
1496 * Compiles a variable direct evaluation as is, setting v->evalprog on success.
1497 *
1498 * @returns Pointer to the program on success, NULL if no program was created.
1499 * @param pVar Pointer to the variable.
1500 */
1501struct kmk_cc_evalprog *kmk_cc_compile_variable_for_eval(struct variable *pVar)
1502{
1503 return NULL;
1504}
1505
1506
1507/**
1508 * Updates the recursive_without_dollar member of a variable structure.
1509 *
1510 * This avoid compiling string expansion programs without only a CopyString
1511 * instruction. By setting recursive_without_dollar to 1, code calling
1512 * kmk_cc_compile_variable_for_expand and kmk_exec_expand_to_var_buf will
1513 * instead treat start treating it as a simple variable, which is faster.
1514 *
1515 * @returns The updated recursive_without_dollar value.
1516 * @param pVar Pointer to the variable.
1517 */
1518static int kmk_cc_update_variable_recursive_without_dollar(struct variable *pVar)
1519{
1520 int fValue;
1521 KMK_CC_ASSERT(pVar->recursive_without_dollar == 0);
1522
1523 if (memchr(pVar->value, '$', pVar->value_length))
1524 fValue = -1;
1525 else
1526 fValue = 1;
1527 pVar->recursive_without_dollar = fValue;
1528
1529 return fValue;
1530}
1531
1532
1533/**
1534 * Compiles a variable for string expansion.
1535 *
1536 * @returns Pointer to the string expansion program on success, NULL if no
1537 * program was created.
1538 * @param pVar Pointer to the variable.
1539 */
1540struct kmk_cc_expandprog *kmk_cc_compile_variable_for_expand(struct variable *pVar)
1541{
1542 KMK_CC_ASSERT(strlen(pVar->value) == pVar->value_length);
1543 KMK_CC_ASSERT(!pVar->expandprog);
1544 KMK_CC_ASSERT(pVar->recursive_without_dollar <= 0);
1545
1546 if ( !pVar->expandprog
1547 && pVar->recursive)
1548 {
1549 if ( pVar->recursive_without_dollar < 0
1550 || ( pVar->recursive_without_dollar == 0
1551 && kmk_cc_update_variable_recursive_without_dollar(pVar) < 0) )
1552 {
1553 pVar->expandprog = kmk_cc_exp_compile(pVar->value, pVar->value_length);
1554 g_cVarForExpandCompilations++;
1555 }
1556 }
1557 return pVar->expandprog;
1558}
1559
1560
1561/**
1562 * String expansion execution worker for outputting a variable.
1563 *
1564 * @returns The new variable buffer position.
1565 * @param pVar The variable to reference.
1566 * @param pchDst The current variable buffer position.
1567 */
1568static char *kmk_exec_expand_worker_reference_variable(struct variable *pVar, char *pchDst)
1569{
1570 if (pVar->value_length > 0)
1571 {
1572 if (!pVar->recursive || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(pVar))
1573 pchDst = variable_buffer_output(pchDst, pVar->value, pVar->value_length);
1574 else
1575 pchDst = reference_recursive_variable(pchDst, pVar);
1576 }
1577 else if (pVar->append)
1578 pchDst = reference_recursive_variable(pchDst, pVar);
1579 return pchDst;
1580}
1581
1582
1583/**
1584 * Executes a stream string expansion instructions, outputting to the current
1585 * varaible buffer.
1586 *
1587 * @returns The new variable buffer position.
1588 * @param pInstrCore The instruction to start executing at.
1589 * @param pchDst The current variable buffer position.
1590 */
1591static char *kmk_exec_expand_instruction_stream_to_var_buf(PKMKCCEXPCORE pInstrCore, char *pchDst)
1592{
1593 for (;;)
1594 {
1595 switch (pInstrCore->enmOpCode)
1596 {
1597 case kKmkCcExpInstr_CopyString:
1598 {
1599 PKMKCCEXPCOPYSTRING pInstr = (PKMKCCEXPCOPYSTRING)pInstrCore;
1600 pchDst = variable_buffer_output(pchDst, pInstr->pachSrc, pInstr->cchCopy);
1601
1602 pInstrCore = &(pInstr + 1)->Core;
1603 break;
1604 }
1605
1606 case kKmkCcExpInstr_PlainVariable:
1607 {
1608 PKMKCCEXPPLAINVAR pInstr = (PKMKCCEXPPLAINVAR)pInstrCore;
1609 struct variable *pVar = lookup_variable_strcached(pInstr->pszName);
1610 if (pVar)
1611 pchDst = kmk_exec_expand_worker_reference_variable(pVar, pchDst);
1612 else
1613 warn_undefined(pInstr->pszName, strcache2_get_len(&variable_strcache, pInstr->pszName));
1614
1615 pInstrCore = &(pInstr + 1)->Core;
1616 break;
1617 }
1618
1619 case kKmkCcExpInstr_DynamicVariable:
1620 {
1621 PKMKCCEXPDYNVAR pInstr = (PKMKCCEXPDYNVAR)pInstrCore;
1622 struct variable *pVar;
1623 uint32_t cchName;
1624 char *pszName = kmk_exec_expand_subprog_to_tmp(&pInstr->SubProg, &cchName);
1625 char *pszColon = (char *)memchr(pszName, ':', cchName);
1626 char *pszEqual;
1627 if ( pszColon == NULL
1628 || (pszEqual = (char *)memchr(pszColon + 1, '=', &pszName[cchName] - pszColon - 1)) == NULL
1629 || pszEqual == pszColon + 1)
1630 {
1631 pVar = lookup_variable(pszName, cchName);
1632 if (pVar)
1633 pchDst = kmk_exec_expand_worker_reference_variable(pVar, pchDst);
1634 else
1635 warn_undefined(pszName, cchName);
1636 }
1637 else if (pszColon != pszName)
1638 {
1639 /*
1640 * Oh, we have to do search and replace. How tedious.
1641 * Since the variable name is a temporary buffer, we can transform
1642 * the strings into proper search and replacement patterns directly.
1643 */
1644 pVar = lookup_variable(pszName, pszColon - pszName);
1645 if (pVar)
1646 {
1647 char const *pszExpandedVarValue = pVar->recursive ? recursively_expand(pVar) : pVar->value;
1648 char *pszSearchPat = pszColon + 1;
1649 char *pszReplacePat = pszEqual + 1;
1650 const char *pchPctSearchPat;
1651 const char *pchPctReplacePat;
1652
1653 *pszEqual = '\0';
1654 pchPctSearchPat = find_percent(pszSearchPat);
1655 pchPctReplacePat = find_percent(pszReplacePat);
1656
1657 if (!pchPctReplacePat)
1658 {
1659 if (pszReplacePat[-2] != '\0') /* On the offchance that a pct was unquoted by find_percent. */
1660 {
1661 memmove(pszName + 1, pszSearchPat, pszReplacePat - pszSearchPat);
1662 if (pchPctSearchPat)
1663 pchPctSearchPat -= pszSearchPat - &pszName[1];
1664 pszSearchPat = &pszName[1];
1665 }
1666 pchPctReplacePat = --pszReplacePat;
1667 *pszReplacePat = '%';
1668 }
1669
1670 if (!pchPctSearchPat)
1671 {
1672 pchPctSearchPat = --pszSearchPat;
1673 *pszSearchPat = '%';
1674 }
1675
1676 pchDst = patsubst_expand_pat(pchDst, pszExpandedVarValue,
1677 pszSearchPat, pszReplacePat,
1678 pchPctSearchPat, pchPctReplacePat);
1679
1680 if (pVar->recursive)
1681 free((void *)pszExpandedVarValue);
1682 }
1683 else
1684 warn_undefined(pszName, pszColon - pszName);
1685 }
1686 free(pszName);
1687
1688 pInstrCore = pInstr->pNext;
1689 break;
1690 }
1691
1692
1693 case kKmkCcExpInstr_SearchAndReplacePlainVariable:
1694 {
1695 PKMKCCEXPSRPLAINVAR pInstr = (PKMKCCEXPSRPLAINVAR)pInstrCore;
1696 struct variable *pVar = lookup_variable_strcached(pInstr->pszName);
1697 if (pVar)
1698 {
1699 char const *pszExpandedVarValue = pVar->recursive ? recursively_expand(pVar) : pVar->value;
1700 pchDst = patsubst_expand_pat(pchDst,
1701 pszExpandedVarValue,
1702 pInstr->pszSearchPattern,
1703 pInstr->pszReplacePattern,
1704 &pInstr->pszSearchPattern[pInstr->offPctSearchPattern],
1705 &pInstr->pszReplacePattern[pInstr->offPctReplacePattern]);
1706 if (pVar->recursive)
1707 free((void *)pszExpandedVarValue);
1708 }
1709 else
1710 warn_undefined(pInstr->pszName, strcache2_get_len(&variable_strcache, pInstr->pszName));
1711
1712 pInstrCore = pInstr->pNext;
1713 break;
1714 }
1715
1716 case kKmkCcExpInstr_PlainFunction:
1717 {
1718 PKMKCCEXPPLAINFUNC pInstr = (PKMKCCEXPPLAINFUNC)pInstrCore;
1719 uint32_t iArg;
1720 if (!pInstr->Core.fDirty)
1721 {
1722#ifdef KMK_CC_STRICT
1723 uint32_t uCrcBefore = 0;
1724 uint32_t uCrcAfter = 0;
1725 iArg = pInstr->Core.cArgs;
1726 while (iArg-- > 0)
1727 uCrcBefore = kmk_cc_debug_string_hash(uCrcBefore, pInstr->apszArgs[iArg]);
1728#endif
1729
1730 pchDst = pInstr->Core.pfnFunction(pchDst, (char **)&pInstr->apszArgs[0], pInstr->Core.pszFuncName);
1731
1732#ifdef KMK_CC_STRICT
1733 iArg = pInstr->Core.cArgs;
1734 while (iArg-- > 0)
1735 uCrcAfter = kmk_cc_debug_string_hash(uCrcAfter, pInstr->apszArgs[iArg]);
1736 KMK_CC_ASSERT(uCrcBefore == uCrcAfter);
1737#endif
1738 }
1739 else
1740 {
1741 char **papszShadowArgs = xmalloc((pInstr->Core.cArgs * 2 + 1) * sizeof(papszShadowArgs[0]));
1742 char **papszArgs = &papszShadowArgs[pInstr->Core.cArgs];
1743
1744 iArg = pInstr->Core.cArgs;
1745 papszArgs[iArg] = NULL;
1746 while (iArg-- > 0)
1747 papszArgs[iArg] = papszShadowArgs[iArg] = xstrdup(pInstr->apszArgs[iArg]);
1748
1749 pchDst = pInstr->Core.pfnFunction(pchDst, (char **)&pInstr->apszArgs[0], pInstr->Core.pszFuncName);
1750
1751 iArg = pInstr->Core.cArgs;
1752 while (iArg-- > 0)
1753 free(papszShadowArgs[iArg]);
1754 free(papszShadowArgs);
1755 }
1756
1757 pInstrCore = pInstr->Core.pNext;
1758 break;
1759 }
1760
1761 case kKmkCcExpInstr_DynamicFunction:
1762 {
1763 PKMKCCEXPDYNFUNC pInstr = (PKMKCCEXPDYNFUNC)pInstrCore;
1764 char **papszArgsShadow = xmalloc( (pInstr->Core.cArgs * 2 + 1) * sizeof(char *));
1765 char **papszArgs = &papszArgsShadow[pInstr->Core.cArgs];
1766 uint32_t iArg;
1767
1768 if (!pInstr->Core.fDirty)
1769 {
1770#ifdef KMK_CC_STRICT
1771 uint32_t uCrcBefore = 0;
1772 uint32_t uCrcAfter = 0;
1773#endif
1774 iArg = pInstr->Core.cArgs;
1775 papszArgs[iArg] = NULL;
1776 while (iArg-- > 0)
1777 {
1778 char *pszArg;
1779 if (!pInstr->aArgs[iArg].fPlain)
1780 pszArg = kmk_exec_expand_subprog_to_tmp(&pInstr->aArgs[iArg].u.SubProg, NULL);
1781 else
1782 pszArg = (char *)pInstr->aArgs[iArg].u.Plain.pszArg;
1783 papszArgsShadow[iArg] = pszArg;
1784 papszArgs[iArg] = pszArg;
1785#ifdef KMK_CC_STRICT
1786 uCrcBefore = kmk_cc_debug_string_hash(uCrcBefore, pszArg);
1787#endif
1788 }
1789 pchDst = pInstr->Core.pfnFunction(pchDst, papszArgs, pInstr->Core.pszFuncName);
1790
1791 iArg = pInstr->Core.cArgs;
1792 while (iArg-- > 0)
1793 {
1794#ifdef KMK_CC_STRICT
1795 KMK_CC_ASSERT(papszArgsShadow[iArg] == papszArgs[iArg]);
1796 uCrcAfter = kmk_cc_debug_string_hash(uCrcAfter, papszArgsShadow[iArg]);
1797#endif
1798 if (!pInstr->aArgs[iArg].fPlain)
1799 free(papszArgsShadow[iArg]);
1800 }
1801 KMK_CC_ASSERT(uCrcBefore == uCrcAfter);
1802 }
1803 else
1804 {
1805 iArg = pInstr->Core.cArgs;
1806 papszArgs[iArg] = NULL;
1807 while (iArg-- > 0)
1808 {
1809 char *pszArg;
1810 if (!pInstr->aArgs[iArg].fPlain)
1811 pszArg = kmk_exec_expand_subprog_to_tmp(&pInstr->aArgs[iArg].u.SubProg, NULL);
1812 else
1813 pszArg = xstrdup(pInstr->aArgs[iArg].u.Plain.pszArg);
1814 papszArgsShadow[iArg] = pszArg;
1815 papszArgs[iArg] = pszArg;
1816 }
1817
1818 pchDst = pInstr->Core.pfnFunction(pchDst, papszArgs, pInstr->Core.pszFuncName);
1819
1820 iArg = pInstr->Core.cArgs;
1821 while (iArg-- > 0)
1822 free(papszArgsShadow[iArg]);
1823 }
1824 free(papszArgsShadow);
1825
1826 pInstrCore = pInstr->Core.pNext;
1827 break;
1828 }
1829
1830 case kKmkCcExpInstr_Jump:
1831 {
1832 PKMKCCEXPJUMP pInstr = (PKMKCCEXPJUMP)pInstrCore;
1833 pInstrCore = pInstr->pNext;
1834 break;
1835 }
1836
1837 case kKmkCcExpInstr_Return:
1838 return pchDst;
1839
1840 default:
1841 fatal(NULL, _("Unknown string expansion opcode: %d (%#x)"),
1842 (int)pInstrCore->enmOpCode, (int)pInstrCore->enmOpCode);
1843 return NULL;
1844 }
1845 }
1846}
1847
1848
1849/**
1850 * Updates the string expansion statistics.
1851 *
1852 * @param pStats The statistics structure to update.
1853 * @param cchResult The result lenght.
1854 */
1855void kmk_cc_exp_stats_update(PKMKCCEXPSTATS pStats, uint32_t cchResult)
1856{
1857 /*
1858 * The average is simplified and not an exact average for every
1859 * expansion that has taken place.
1860 */
1861 pStats->cchAvg = (pStats->cchAvg * 7 + cchResult) / 8;
1862}
1863
1864
1865/**
1866 * Execute a string expansion sub-program, outputting to a new heap buffer.
1867 *
1868 * @returns Pointer to the output buffer (hand to free when done).
1869 * @param pSubProg The sub-program to execute.
1870 * @param pcchResult Where to return the size of the result. Optional.
1871 */
1872static char *kmk_exec_expand_subprog_to_tmp(PKMKCCEXPSUBPROG pSubProg, uint32_t *pcchResult)
1873{
1874 char *pchOldVarBuf;
1875 unsigned int cbOldVarBuf;
1876 char *pchDst;
1877 char *pszResult;
1878 uint32_t cchResult;
1879
1880 /*
1881 * Temporarily replace the variable buffer while executing the instruction
1882 * stream for this sub program.
1883 */
1884 pchDst = install_variable_buffer_with_hint(&pchOldVarBuf, &cbOldVarBuf,
1885 pSubProg->Stats.cchAvg ? pSubProg->Stats.cchAvg + 32 : 256);
1886
1887 pchDst = kmk_exec_expand_instruction_stream_to_var_buf(pSubProg->pFirstInstr, pchDst);
1888
1889 /* Ensure that it's terminated. */
1890 pchDst = variable_buffer_output(pchDst, "\0", 1) - 1;
1891
1892 /* Grab the result buffer before restoring the previous one. */
1893 pszResult = variable_buffer;
1894 cchResult = (uint32_t)(pchDst - pszResult);
1895 if (pcchResult)
1896 *pcchResult = cchResult;
1897 kmk_cc_exp_stats_update(&pSubProg->Stats, cchResult);
1898
1899 variable_buffer = pchOldVarBuf;
1900 variable_buffer_length = cbOldVarBuf;
1901
1902 return pszResult;
1903}
1904
1905
1906/**
1907 * Execute a string expansion program, outputting to the current variable
1908 * buffer.
1909 *
1910 * @returns New variable buffer position.
1911 * @param pProg The program to execute.
1912 * @param pchDst The current varaible buffer position.
1913 */
1914static char *kmk_exec_expand_prog_to_var_buf(PKMKCCEXPPROG pProg, char *pchDst)
1915{
1916 uint32_t cchResult;
1917 uint32_t offStart = (uint32_t)(pchDst - variable_buffer);
1918
1919 if (pProg->Stats.cchAvg >= variable_buffer_length - offStart)
1920 pchDst = ensure_variable_buffer_space(pchDst, offStart + pProg->Stats.cchAvg + 32);
1921
1922 pchDst = kmk_exec_expand_instruction_stream_to_var_buf(pProg->pFirstInstr, pchDst);
1923
1924 cchResult = (uint32_t)(pchDst - variable_buffer);
1925 KMK_CC_ASSERT(cchResult >= offStart);
1926 cchResult -= offStart;
1927 kmk_cc_exp_stats_update(&pProg->Stats, cchResult);
1928 g_cVarForExpandExecs++;
1929
1930 return pchDst;
1931}
1932
1933
1934/**
1935 * Equivalent of eval_buffer, only it's using the evalprog of the variable.
1936 *
1937 * @param pVar Pointer to the variable. Must have a program.
1938 */
1939void kmk_exec_evalval(struct variable *pVar)
1940{
1941 KMK_CC_ASSERT(pVar->evalprog);
1942 assert(0);
1943}
1944
1945
1946/**
1947 * Expands a variable into a variable buffer using its expandprog.
1948 *
1949 * @returns The new variable buffer position.
1950 * @param pVar Pointer to the variable. Must have a program.
1951 * @param pchDst Pointer to the current variable buffer position.
1952 */
1953char *kmk_exec_expand_to_var_buf(struct variable *pVar, char *pchDst)
1954{
1955 KMK_CC_ASSERT(pVar->expandprog);
1956 KMK_CC_ASSERT(pVar->expandprog->uInputHash == kmk_cc_debug_string_hash(0, pVar->value));
1957 return kmk_exec_expand_prog_to_var_buf(pVar->expandprog, pchDst);
1958}
1959
1960
1961/**
1962 * Called when a variable with expandprog or/and evalprog changes.
1963 *
1964 * @param pVar Pointer to the variable.
1965 */
1966void kmk_cc_variable_changed(struct variable *pVar)
1967{
1968 KMK_CC_ASSERT(pVar->evalprog || pVar->expandprog);
1969#if 0
1970 if (pVar->evalprog)
1971 {
1972 kmk_cc_block_free_list(pVar->evalprog->pBlockTail);
1973 pVar->evalprog = NULL;
1974 }
1975#endif
1976 if (pVar->expandprog)
1977 {
1978 kmk_cc_block_free_list(pVar->expandprog->pBlockTail);
1979 pVar->expandprog = NULL;
1980 }
1981}
1982
1983
1984/**
1985 * Called when a variable with expandprog or/and evalprog is deleted.
1986 *
1987 * @param pVar Pointer to the variable.
1988 */
1989void kmk_cc_variable_deleted(struct variable *pVar)
1990{
1991 KMK_CC_ASSERT(pVar->evalprog || pVar->expandprog);
1992#if 0
1993 if (pVar->evalprog)
1994 {
1995 kmk_cc_block_free_list(pVar->evalprog->pBlockTail);
1996 pVar->evalprog = NULL;
1997 }
1998#endif
1999 if (pVar->expandprog)
2000 {
2001 kmk_cc_block_free_list(pVar->expandprog->pBlockTail);
2002 pVar->expandprog = NULL;
2003 }
2004}
2005
2006
2007#endif /* CONFIG_WITH_COMPILER */
2008
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