VirtualBox

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

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

string expansion debugged and enabled. fixed access-after-alloc bug in func_sort and could lead to heap corruption.

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