VirtualBox

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

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

String expansion 'compilation' and 'execution' code is mostly done.

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

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