1 /*-
2 ***********************************************************************
3 *
4 * $Id: api.c,v 1.104 2012/11/30 18:50:14 klm Exp $
5 *
6 ***********************************************************************
7 *
8 * Copyright 2011-2012 The KL-EL Project, All Rights Reserved.
9 *
10 ***********************************************************************
11 */
12 #include "all-includes.h"
13
14 static char const *gpcContextAllocationError = "context allocation error";
15 static char const *gpcMemoryAllocationError = "memory allocation error";
16 static char gcKlelQuoteChar = KLEL_DEFAULT_QUOTE_CHAR;
17 static char const *gpcKlelQuotedChars = KLEL_DEFAULT_QUOTED_CHARS;
18
19 /*-
20 ***********************************************************************
21 *
22 * KlelCompile
23 *
24 ***********************************************************************
25 */
26 KLEL_CONTEXT *
KlelCompile(const char * pcInput,unsigned long ulFlags,const KLEL_TYPE_CALLBACK pfGetTypeOfVar,const KLEL_VALUE_CALLBACK pfGetValueOfVar,void * pvData)27 KlelCompile(const char *pcInput, unsigned long ulFlags, const KLEL_TYPE_CALLBACK pfGetTypeOfVar, const KLEL_VALUE_CALLBACK pfGetValueOfVar, void *pvData)
28 {
29 KLEL_CONTEXT *psContext = NULL;
30 KLEL_NODE *psCodeNode = NULL;
31 KLEL_STRING *psString = NULL;
32 KLEL_VALUE *psValue = NULL;
33 char *pcName = NULL;
34 char *pcResult = NULL;
35 size_t szIndex = 0;
36 size_t szLength = 0;
37 uint32_t uiResult = 0;
38
39 /*-
40 *********************************************************************
41 *
42 * Conditionally set implied flags.
43 *
44 *********************************************************************
45 */
46 if (ulFlags & KLEL_MUST_SPECIFY_RETURN_CODES)
47 {
48 ulFlags |= KLEL_MUST_BE_GUARDED_COMMAND;
49 }
50
51 /*-
52 *********************************************************************
53 *
54 * Allocate a new context structure and tag it as not yet valid.
55 *
56 *********************************************************************
57 */
58 psContext = calloc(1, sizeof(KLEL_CONTEXT));
59 if (psContext == NULL)
60 {
61 return NULL;
62 }
63 psContext->bIsValid = 0;
64
65 /*-
66 *********************************************************************
67 *
68 * Initialize context members that were provided by the caller.
69 *
70 *********************************************************************
71 */
72 psContext->pcInput = pcInput;
73 psContext->pfGetTypeOfVar = (pfGetTypeOfVar != NULL) ? pfGetTypeOfVar : (KLEL_TYPE_CALLBACK)KlelGetTypeOfStdVar;
74 psContext->pfGetValueOfVar = (pfGetValueOfVar != NULL) ? pfGetValueOfVar : (KLEL_VALUE_CALLBACK)KlelGetValueOfStdVar;
75 psContext->pvData = pvData;
76
77 /*-
78 *********************************************************************
79 *
80 * Parse the expression and verify that it returns a known type.
81 *
82 *********************************************************************
83 */
84 psContext->psExpression = KlelRoot(psContext);
85 if (psContext->psExpression == NULL)
86 {
87 return psContext;
88 }
89
90 psContext->iExpressionType = KlelTypeCheck(psContext->psExpression, psContext);
91 if (psContext->iExpressionType == KLEL_TYPE_UNKNOWN)
92 {
93 return psContext;
94 }
95
96 /*-
97 *********************************************************************
98 *
99 * Initialize the expression's name. If the caller specified a name,
100 * we simply copy it. Otherwise, we generate a name by calculating a
101 * "standard" BSD checksum over the string representation of the
102 * parsed expression.
103 *
104 *********************************************************************
105 */
106 pcName = calloc(KLEL_MAX_NAME + 1, 1);
107 if (pcName == NULL)
108 {
109 KlelReportMemoryAllocationError(psContext);
110 return psContext;
111 }
112 if (psContext->psExpression->apsChildren[KLEL_LABEL_INDEX] == NULL)
113 {
114 psString = KlelInnerStringOfExpression(psContext->psExpression, KLEL_EXPRESSION_PLUS_EVERYTHING);
115 if (psString == NULL)
116 {
117 KlelReportMemoryAllocationError(psContext);
118 return psContext;
119 }
120 szLength = strlen(psString->pcString);
121 for (szIndex = 0; szIndex < szLength; szIndex++)
122 {
123 uiResult = (uiResult >> 1) + ((uiResult & 1) << 15);
124 uiResult += psString->pcString[szIndex];
125 uiResult &= 0xFFFF;
126 }
127 KlelStringFree(psString, 1);
128 snprintf(pcName, KLEL_MAX_NAME, "expr(%08" PRIx32 ")", uiResult);
129 }
130 else
131 {
132 strncpy(pcName, psContext->psExpression->apsChildren[KLEL_LABEL_INDEX]->acFragment, KLEL_MAX_NAME);
133 }
134 psContext->pcName = pcName;
135
136 /*-
137 *********************************************************************
138 *
139 * Conditionally initialize the interpreter (guarded commands).
140 *
141 *********************************************************************
142 */
143 if (psContext->psExpression->apsChildren[KLEL_EXPRESSION_INDEX]->apsChildren[KLEL_INTERPRETER_INDEX] != NULL)
144 {
145 psValue = KlelInnerExecute(psContext->psExpression->apsChildren[KLEL_EXPRESSION_INDEX]->apsChildren[KLEL_INTERPRETER_INDEX], psContext);
146 if (psValue == NULL)
147 {
148 KlelReportMemoryAllocationError(psContext);
149 return psContext;
150 }
151 pcResult = KlelValueToString(psValue, &szLength);
152 if (pcResult == NULL)
153 {
154 KlelReportMemoryAllocationError(psContext);
155 return psContext;
156 }
157 psContext->pcInterpreter = pcResult;
158 KlelFreeResult(psValue);
159 }
160
161
162 /*-
163 *********************************************************************
164 *
165 * Conditionally initialize the program (guarded commands).
166 *
167 *********************************************************************
168 */
169 if (psContext->psExpression->apsChildren[KLEL_EXPRESSION_INDEX]->apsChildren[KLEL_COMMAND_INDEX] != NULL)
170 {
171 psValue = KlelInnerExecute(psContext->psExpression->apsChildren[KLEL_EXPRESSION_INDEX]->apsChildren[KLEL_COMMAND_INDEX], psContext);
172 if (psValue == NULL)
173 {
174 KlelReportMemoryAllocationError(psContext);
175 return psContext;
176 }
177 pcResult = KlelValueToString(psValue, &szLength);
178 if (pcResult == NULL)
179 {
180 KlelReportMemoryAllocationError(psContext);
181 return psContext;
182 }
183 psContext->pcProgram = pcResult;
184 KlelFreeResult(psValue);
185 }
186
187 /*-
188 *********************************************************************
189 *
190 * The default success exit code is zero (guarded commands). Thus,
191 * all remaining exit codes (i.e., [1-255]) indicate a failure by
192 * default.
193 *
194 *********************************************************************
195 */
196 psContext->aiCodes[0] = 1;
197
198 /*-
199 *********************************************************************
200 *
201 * Conditionally initialize success exit codes (guarded commands).
202 *
203 *********************************************************************
204 */
205 if (psContext->psExpression->apsChildren[KLEL_EXPRESSION_INDEX]->apsChildren[KLEL_PASS_INDEX] != NULL)
206 {
207 memset(psContext->aiCodes, 0, sizeof(psContext->aiCodes));
208 psCodeNode = psContext->psExpression->apsChildren[KLEL_EXPRESSION_INDEX]->apsChildren[KLEL_PASS_INDEX];
209 for (szIndex = 0; szIndex < 256 && psCodeNode != NULL; szIndex++)
210 {
211 KLEL_ASSERT(psCodeNode->iType == KLEL_NODE_INTEGER);
212 if (psCodeNode->llInteger > 255)
213 {
214 KlelReportError(psContext, "return codes must be less than or equal to 255", NULL);
215 return psContext;
216 }
217 psContext->aiCodes[psCodeNode->llInteger] = 1;
218 psCodeNode = psCodeNode->apsChildren[0];
219 }
220 }
221
222 /*-
223 *********************************************************************
224 *
225 * Conditionally initialize failure exit codes (guarded commands).
226 *
227 *********************************************************************
228 */
229 if (psContext->psExpression->apsChildren[KLEL_EXPRESSION_INDEX]->apsChildren[KLEL_FAIL_INDEX] != NULL)
230 {
231 memset(psContext->aiCodes, 1, sizeof(psContext->aiCodes));
232 psCodeNode = psContext->psExpression->apsChildren[KLEL_EXPRESSION_INDEX]->apsChildren[KLEL_FAIL_INDEX];
233 for (szIndex = 0; szIndex < 256 && psCodeNode != NULL; szIndex++)
234 {
235 KLEL_ASSERT(psCodeNode->iType == KLEL_NODE_INTEGER);
236 if (psCodeNode->llInteger > 255)
237 {
238 KlelReportError(psContext, "return codes must be less than or equal to 255", NULL);
239 return psContext;
240 }
241 psContext->aiCodes[psCodeNode->llInteger] = 0;
242 psCodeNode = psCodeNode->apsChildren[0];
243 }
244 }
245
246 /*-
247 *********************************************************************
248 *
249 * Do some sanity checks.
250 *
251 *********************************************************************
252 */
253 if (ulFlags & KLEL_MUST_BE_NAMED && psContext->psExpression->apsChildren[KLEL_LABEL_INDEX] == NULL)
254 {
255 KlelReportError(psContext, "expression must be named when KLEL_MUST_BE_NAMED is set", NULL);
256 return psContext;
257 }
258
259 if ((ulFlags & KLEL_MUST_BE_GUARDED_COMMAND) && psContext->psExpression->iType != KLEL_NODE_GUARDED_COMMAND)
260 {
261 KlelReportError(psContext, "expression must be a guarded command when KLEL_MUST_BE_GUARDED_COMMAND is set", NULL);
262 return psContext;
263 }
264
265 if
266 (
267 (ulFlags & KLEL_MUST_SPECIFY_RETURN_CODES)
268 && psContext->psExpression->apsChildren[KLEL_EXPRESSION_INDEX]->apsChildren[KLEL_PASS_INDEX] == NULL
269 && psContext->psExpression->apsChildren[KLEL_EXPRESSION_INDEX]->apsChildren[KLEL_FAIL_INDEX] == NULL
270 )
271 {
272 KlelReportError(psContext, "expression must specify return codes when KLEL_MUST_SPECIFY_RETURN_CODES is set", NULL);
273 return psContext;
274 }
275
276 /*-
277 *********************************************************************
278 *
279 * Tag the context structure as valid.
280 *
281 *********************************************************************
282 */
283 psContext->bIsValid = 1;
284
285 return psContext;
286 }
287
288
289 /*-
290 ***********************************************************************
291 *
292 * KlelExecute
293 *
294 ***********************************************************************
295 */
296 KLEL_VALUE *
KlelExecute(KLEL_CONTEXT * psContext)297 KlelExecute(KLEL_CONTEXT *psContext)
298 {
299 KLEL_VALUE *psValue = NULL;
300
301 KLEL_ASSERT(psContext != NULL);
302 KLEL_ASSERT(KlelIsValid(psContext));
303
304 if (KlelIsValid(psContext))
305 {
306 KlelClearError(psContext);
307 psValue = KlelInnerExecute(psContext->psExpression, psContext);
308 }
309
310 return psValue;
311 }
312
313
314 /*-
315 ***********************************************************************
316 *
317 * KlelIsValid
318 *
319 ***********************************************************************
320 */
321 int
KlelIsValid(const KLEL_CONTEXT * psContext)322 KlelIsValid(const KLEL_CONTEXT *psContext)
323 {
324 return psContext != NULL && psContext->bIsValid && psContext->psExpression != NULL;
325 }
326
327
328 /*-
329 ***********************************************************************
330 *
331 * KlelGetChecksum
332 *
333 ***********************************************************************
334 */
335 uint32_t
KlelGetChecksum(const KLEL_CONTEXT * psContext,unsigned long ulFlags)336 KlelGetChecksum(const KLEL_CONTEXT *psContext, unsigned long ulFlags)
337 {
338 char *pcExpression = NULL;
339 size_t szLength = 0;
340 size_t szi = 0;
341 uint32_t uiResult = 0;
342
343 KLEL_ASSERT(psContext != NULL);
344 KLEL_ASSERT(KlelIsValid(psContext));
345
346 pcExpression = KlelExpressionToString(psContext, ulFlags);
347 if (pcExpression != NULL)
348 {
349 /*-
350 ***********************************************************************
351 *
352 * This is the "standard" original BSD checksum algorithm.
353 *
354 ***********************************************************************
355 */
356
357 szLength = strlen(pcExpression);
358
359 for (szi = 0; szi < szLength; szi++)
360 {
361 uiResult = (uiResult >> 1) + ((uiResult & 1) << 15);
362 uiResult += pcExpression[szi];
363 uiResult &= 0xFFFF;
364 }
365
366 free(pcExpression);
367 }
368
369 return uiResult;
370 }
371
372
373 /*-
374 ***********************************************************************
375 *
376 * KlelGetName
377 *
378 ***********************************************************************
379 */
380 char *
KlelGetName(const KLEL_CONTEXT * psContext)381 KlelGetName(const KLEL_CONTEXT *psContext)
382 {
383 KLEL_ASSERT(KlelIsValid(psContext));
384
385 return (KlelIsValid(psContext)) ? psContext->pcName : NULL;
386 }
387
388
389 /*-
390 ***********************************************************************
391 *
392 * KlelGetPrivateData
393 *
394 ***********************************************************************
395 */
396 void *
KlelGetPrivateData(const KLEL_CONTEXT * psContext)397 KlelGetPrivateData(const KLEL_CONTEXT *psContext)
398 {
399 void *pvResult = NULL;
400
401 KLEL_ASSERT(psContext != NULL);
402
403 if (psContext != NULL)
404 {
405 pvResult = psContext->pvData;
406 }
407
408 return pvResult;
409 }
410
411
412 /*-
413 ***********************************************************************
414 *
415 * KlelSetPrivateData
416 *
417 ***********************************************************************
418 */
419 void
KlelSetPrivateData(KLEL_CONTEXT * psContext,void * pvData)420 KlelSetPrivateData(KLEL_CONTEXT *psContext, void *pvData)
421 {
422 KLEL_ASSERT(psContext != NULL);
423
424 if (psContext != NULL)
425 {
426 psContext->pvData = pvData;
427 }
428 }
429
430
431 /*-
432 ***********************************************************************
433 *
434 * KlelGetTypeOfExpression
435 *
436 ***********************************************************************
437 */
438 KLEL_EXPR_TYPE
KlelGetTypeOfExpression(const KLEL_CONTEXT * psContext)439 KlelGetTypeOfExpression(const KLEL_CONTEXT *psContext)
440 {
441 KLEL_EXPR_TYPE iType = KLEL_TYPE_UNKNOWN;
442
443 KLEL_ASSERT(KlelIsValid(psContext));
444
445 if (KlelIsValid(psContext))
446 {
447 iType = psContext->iExpressionType;
448 }
449
450 return iType;
451 }
452
453
454 /*-
455 ***********************************************************************
456 *
457 * KlelIsGuardedCommand
458 *
459 ***********************************************************************
460 */
461 int
KlelIsGuardedCommand(const KLEL_CONTEXT * psContext)462 KlelIsGuardedCommand(const KLEL_CONTEXT *psContext)
463 {
464 int bIsGuardedCommand = 0;
465
466 KLEL_ASSERT(KlelIsValid(psContext));
467
468 if (KlelIsValid(psContext))
469 {
470 bIsGuardedCommand = psContext->psExpression->iType == KLEL_NODE_GUARDED_COMMAND;
471 }
472
473 return bIsGuardedCommand;
474 }
475
476
477 /*-
478 ***********************************************************************
479 *
480 * KlelGetCommand
481 *
482 ***********************************************************************
483 */
484 KLEL_COMMAND *
KlelGetCommand(KLEL_CONTEXT * psContext)485 KlelGetCommand(KLEL_CONTEXT *psContext)
486 {
487 KLEL_COMMAND *psCommand = calloc(1, sizeof(KLEL_COMMAND));
488 KLEL_VALUE *psArgument = NULL;
489 char *pcString = NULL;
490 size_t szIndex = 0;
491 size_t szLength = 0;
492
493 KLEL_ASSERT(KlelIsGuardedCommand(psContext));
494
495 if (psCommand != NULL && KlelIsGuardedCommand(psContext))
496 {
497 strncpy(psCommand->acInterpreter, psContext->pcInterpreter, KLEL_MAX_NAME);
498 strncpy(psCommand->acProgram, psContext->pcProgram, KLEL_MAX_NAME);
499 for (szIndex = 0; szIndex < KLEL_MAX_FUNC_ARGS && psContext->psExpression->apsChildren[KLEL_EXPRESSION_INDEX]->apsChildren[szIndex] != NULL; szIndex++)
500 {
501 psArgument = KlelInnerExecute(psContext->psExpression->apsChildren[KLEL_EXPRESSION_INDEX]->apsChildren[szIndex], psContext);
502 if (psArgument == NULL)
503 {
504 free(psCommand);
505 return NULL;
506 }
507 pcString = KlelValueToString(psArgument, &szLength);
508 KlelFreeResult(psArgument);
509 if (pcString == NULL)
510 {
511 free(psCommand);
512 return NULL;
513 }
514 psCommand->szArgumentCount++;
515 psCommand->ppcArgumentVector[szIndex] = pcString;
516 }
517 memcpy(psCommand->aiCodes, psContext->aiCodes, sizeof(psCommand->aiCodes));
518 }
519
520 return psCommand;
521 }
522
523
524 /*-
525 ***********************************************************************
526 *
527 * KlelGetCommandInterpreter
528 *
529 ***********************************************************************
530 */
531 char *
KlelGetCommandInterpreter(KLEL_CONTEXT * psContext)532 KlelGetCommandInterpreter(KLEL_CONTEXT *psContext)
533 {
534 KLEL_ASSERT(KlelIsGuardedCommand(psContext));
535
536 return (KlelIsGuardedCommand(psContext)) ? psContext->pcInterpreter : NULL;
537 }
538
539
540 /*-
541 ***********************************************************************
542 *
543 * KlelGetCommandProgram
544 *
545 ***********************************************************************
546 */
547 char *
KlelGetCommandProgram(KLEL_CONTEXT * psContext)548 KlelGetCommandProgram(KLEL_CONTEXT *psContext)
549 {
550 KLEL_ASSERT(KlelIsGuardedCommand(psContext));
551
552 return (KlelIsGuardedCommand(psContext)) ? psContext->pcProgram : NULL;
553 }
554
555
556 /*-
557 ***********************************************************************
558 *
559 * KlelIsSuccessReturnCode
560 *
561 ***********************************************************************
562 */
563 int
KlelIsSuccessReturnCode(const KLEL_CONTEXT * psContext,unsigned int uiCode)564 KlelIsSuccessReturnCode(const KLEL_CONTEXT *psContext, unsigned int uiCode)
565 {
566 int iResult = 0;
567
568 KLEL_ASSERT(KlelIsGuardedCommand(psContext));
569
570 if (KlelIsGuardedCommand(psContext) && uiCode < 256)
571 {
572 iResult = psContext->aiCodes[uiCode];
573 }
574
575 return iResult;
576 }
577
578
579 /*-
580 ***********************************************************************
581 *
582 * KlelExpressionToString
583 *
584 ***********************************************************************
585 */
586 char *
KlelExpressionToString(const KLEL_CONTEXT * psContext,unsigned long ulFlags)587 KlelExpressionToString(const KLEL_CONTEXT *psContext, unsigned long ulFlags)
588 {
589 char *pcResult = NULL;
590 KLEL_STRING *psString = NULL;
591
592 KLEL_ASSERT(KlelIsValid(psContext));
593
594 if (KlelIsValid(psContext))
595 {
596 psString = KlelInnerStringOfExpression(psContext->psExpression, ulFlags);
597 if (psString != NULL)
598 {
599 pcResult = psString->pcString;
600 KlelStringFree(psString, 0);
601 }
602 }
603
604 return pcResult;
605 }
606
607
608 /*-
609 ***********************************************************************
610 *
611 * KlelFreeContext
612 *
613 ***********************************************************************
614 */
615 void
KlelFreeContext(KLEL_CONTEXT * psContext)616 KlelFreeContext(KLEL_CONTEXT *psContext)
617 {
618 size_t szIndex = 0;
619
620 if (psContext != NULL)
621 {
622 if (psContext->pcName != NULL)
623 {
624 free(psContext->pcName);
625 }
626 if (psContext->pcInterpreter != NULL)
627 {
628 free(psContext->pcInterpreter);
629 }
630 if (psContext->pcProgram != NULL)
631 {
632 free(psContext->pcProgram);
633 }
634 if (psContext->psExpression != NULL)
635 {
636 KlelFreeNode(psContext->psExpression);
637 }
638 if (psContext->psClosures != NULL)
639 {
640 for (szIndex = 0; szIndex < psContext->iClosureCount; szIndex++)
641 {
642 if (psContext->psClosures[szIndex].psValue != NULL)
643 {
644 KlelFreeResult(psContext->psClosures[szIndex].psValue);
645 }
646 }
647 free(psContext->psClosures);
648 }
649 KlelClearError(psContext);
650 free(psContext);
651 }
652 }
653
654
655 /*-
656 ***********************************************************************
657 *
658 * KlelFreeCommand
659 *
660 ***********************************************************************
661 */
662 void
KlelFreeCommand(KLEL_COMMAND * psCommand)663 KlelFreeCommand(KLEL_COMMAND *psCommand)
664 {
665 size_t szi = 0;
666
667 if (psCommand != NULL)
668 {
669 for (szi = 0; szi < KLEL_MAX_FUNC_ARGS; szi++)
670 {
671 if (psCommand->ppcArgumentVector[szi] != NULL)
672 {
673 free(psCommand->ppcArgumentVector[szi]);
674 }
675 }
676
677 free(psCommand);
678 }
679 }
680
681 /*-
682 ***********************************************************************
683 *
684 * KlelClearError
685 *
686 ***********************************************************************
687 */
688 void
KlelClearError(KLEL_CONTEXT * psContext)689 KlelClearError(KLEL_CONTEXT *psContext)
690 {
691 KLEL_ASSERT(KlelIsValid(psContext));
692
693 if (KlelIsValid(psContext))
694 {
695 if
696 (
697 psContext->pcError != NULL
698 && psContext->pcError != gpcContextAllocationError
699 && psContext->pcError != gpcMemoryAllocationError
700 )
701 {
702 free(psContext->pcError);
703 }
704 psContext->pcError = NULL;
705 }
706 }
707
708
709 /*-
710 ***********************************************************************
711 *
712 * KlelCreateValue
713 *
714 ***********************************************************************
715 */
716 KLEL_VALUE *
KlelCreateValue(KLEL_EXPR_TYPE iType,...)717 KlelCreateValue(KLEL_EXPR_TYPE iType, ...)
718 {
719 va_list vlArgs;
720 size_t szLength = 0;
721 KLEL_VALUE *psResult = calloc(1, sizeof(KLEL_VALUE) + KLEL_MAX_NAME + 1);
722 KLEL_VALUE *psTemp = NULL;
723 const char *pcTemp = NULL;
724
725 if (psResult != NULL)
726 {
727 psResult->iType = iType;
728 va_start(vlArgs, iType);
729
730 switch (iType)
731 {
732 case KLEL_TYPE_BOOLEAN:
733 psResult->bBoolean = va_arg(vlArgs, unsigned int);
734 break;
735
736 case KLEL_TYPE_REAL:
737 psResult->dReal = va_arg(vlArgs, double);
738 break;
739
740 case KLEL_EXPR_INTEGER:
741 psResult->llInteger = va_arg(vlArgs, int64_t);
742 break;
743
744 case KLEL_EXPR_STRING:
745 szLength = va_arg(vlArgs, size_t);
746 pcTemp = va_arg(vlArgs, const char *);
747
748 KLEL_ASSERT(pcTemp != NULL || szLength == 0);
749
750 if (pcTemp == NULL && szLength != 0)
751 {
752 KlelFreeResult(psResult);
753 va_end(vlArgs);
754 return NULL;
755 }
756
757 psTemp = realloc(psResult, sizeof(KLEL_VALUE) + szLength + 1);
758 if (psTemp == NULL)
759 {
760 KlelFreeResult(psResult);
761 va_end(vlArgs);
762 return NULL;
763 }
764
765 psResult = psTemp;
766 psResult->iType = KLEL_EXPR_STRING;
767 psResult->szLength = szLength;
768 memcpy(psResult->acString, pcTemp, szLength);
769 psResult->acString[szLength] = 0;
770 break;
771
772 default:
773 pcTemp = va_arg(vlArgs, const char *);
774 psResult->fFunction = va_arg(vlArgs, KLEL_VALUE *(*)(KLEL_VALUE **, void *));
775
776 KLEL_ASSERT(KLEL_IS_FUNCTION(iType));
777 KLEL_ASSERT(pcTemp != NULL);
778 KLEL_ASSERT(psResult->fFunction != NULL);
779 if (pcTemp == NULL || psResult->fFunction == NULL || !KLEL_IS_FUNCTION(iType))
780 {
781 KlelFreeResult(psResult);
782 va_end(vlArgs);
783 return NULL;
784 }
785
786 strncpy(psResult->acString, pcTemp, KLEL_MAX_NAME);
787 break;
788 }
789 }
790
791 va_end(vlArgs);
792 return psResult;
793 }
794
795
796 /*-
797 ***********************************************************************
798 *
799 * KlelSetQuotedChars
800 *
801 ***********************************************************************
802 */
803 void
KlelSetQuotedChars(const char * pcChars)804 KlelSetQuotedChars(const char *pcChars)
805 {
806 KLEL_ASSERT(pcChars != NULL);
807
808 if (pcChars != NULL)
809 {
810 gpcKlelQuotedChars = pcChars;
811 }
812 }
813
814
815 /*-
816 ***********************************************************************
817 *
818 * KlelSetQuoteChar
819 *
820 ***********************************************************************
821 */
822 void
KlelSetQuoteChar(char cChar)823 KlelSetQuoteChar(char cChar)
824 {
825 gcKlelQuoteChar = cChar;
826 }
827
828
829 /*-
830 ***********************************************************************
831 *
832 * KlelValueToQuotedString
833 *
834 ***********************************************************************
835 */
836 char *
KlelValueToQuotedString(const KLEL_VALUE * psValue,size_t * pszLength)837 KlelValueToQuotedString(const KLEL_VALUE *psValue, size_t *pszLength)
838 {
839 size_t szi = 0;
840 size_t szj = 0;
841 size_t szk = 0;
842 size_t szCount = 0;
843 size_t szQuotedChars = 0;
844 char *pcBuffer = NULL;
845 char *pcString = NULL;
846
847 KLEL_ASSERT(psValue != NULL);
848 KLEL_ASSERT(gpcKlelQuotedChars != NULL);
849 KLEL_ASSERT(gcKlelQuoteChar != 0);
850 KLEL_ASSERT(pszLength != NULL);
851
852 if (psValue == NULL || gpcKlelQuotedChars == NULL || gcKlelQuoteChar == 0 || pszLength == NULL)
853 {
854 return NULL;
855 }
856
857 szQuotedChars = strlen(gpcKlelQuotedChars);
858
859 pcString = KlelValueToString(psValue, pszLength);
860 if (pcString != NULL)
861 {
862 /* XXX - This is incredibly inefficient. */
863 for (szi = 0; szi < *pszLength; szi++)
864 {
865 for (szj = 0; szj < szQuotedChars; szj++)
866 {
867 if (pcString[szi] == gpcKlelQuotedChars[szj])
868 {
869 szCount++;
870 }
871 }
872 }
873
874 if (szCount == 0)
875 {
876 return pcString;
877 }
878
879 pcBuffer = calloc(*pszLength + szCount + 1, sizeof(char));
880 if (pcBuffer != NULL)
881 {
882 for (szi = 0; szi < *pszLength; szi++)
883 {
884 for (szj = 0; szj < szQuotedChars; szj++)
885 {
886 if (pcString[szi] == gpcKlelQuotedChars[szj])
887 {
888 pcBuffer[szk] = gcKlelQuoteChar;
889 szk++;
890 }
891 }
892
893 pcBuffer[szk] = pcString[szi];
894 szk++;
895 }
896
897 *pszLength = *pszLength + szCount;
898 }
899
900 free(pcString);
901 }
902
903 return pcBuffer;
904 }
905
906
907 /*-
908 ***********************************************************************
909 *
910 * KlelValueToString
911 *
912 ***********************************************************************
913 */
914 char *
KlelValueToString(const KLEL_VALUE * psValue,size_t * pszLength)915 KlelValueToString(const KLEL_VALUE *psValue, size_t *pszLength)
916 {
917 char *pcBuffer = calloc(1, KLEL_MAX_NAME + 1);
918
919 KLEL_ASSERT(psValue != NULL);
920 KLEL_ASSERT(pszLength != NULL);
921
922 if (psValue != NULL && pcBuffer != NULL)
923 {
924 switch (psValue->iType)
925 {
926 case KLEL_EXPR_BOOLEAN:
927 snprintf(pcBuffer, KLEL_MAX_NAME, "%s", psValue->bBoolean ? "true" : "false");
928 *pszLength = strlen(pcBuffer);
929 break;
930
931 case KLEL_EXPR_REAL:
932 snprintf(pcBuffer, KLEL_MAX_NAME, "%g", psValue->dReal);
933 *pszLength = strlen(pcBuffer);
934 break;
935
936 case KLEL_EXPR_INTEGER:
937 snprintf(pcBuffer, KLEL_MAX_NAME, "%" PRId64, psValue->llInteger);
938 *pszLength = strlen(pcBuffer);
939 break;
940
941 case KLEL_EXPR_STRING:
942 free(pcBuffer);
943 pcBuffer = calloc(1, psValue->szLength + 1);
944 if (pcBuffer != NULL)
945 {
946 memcpy(pcBuffer, psValue->acString, psValue->szLength);
947 *pszLength = psValue->szLength;
948 }
949 break;
950
951 default:
952 if (KLEL_IS_FUNCTION(psValue->iType))
953 {
954 pcBuffer = calloc(KLEL_MAX_NAME + 1, 1);
955 snprintf(pcBuffer, KLEL_MAX_NAME, "\\%s", psValue->acString);
956 }
957 else
958 {
959 KLEL_ASSERT(0); /* Data structure corruption. */
960 return NULL;
961 }
962 }
963 }
964
965 return pcBuffer;
966 }
967
968
969 /*-
970 ***********************************************************************
971 *
972 * KlelFreeNode
973 *
974 ***********************************************************************
975 */
976 void
KlelFreeNode(KLEL_NODE * psResult)977 KlelFreeNode(KLEL_NODE *psResult)
978 {
979 size_t szi = 0;
980
981 if (psResult != NULL)
982 {
983 for (szi = 0; szi < KLEL_MAX_CHILDREN; szi++)
984 {
985 if (psResult->apsChildren[szi] != NULL)
986 {
987 KlelFreeNode(psResult->apsChildren[szi]);
988 }
989 }
990
991 free(psResult);
992 }
993 }
994
995
996 /*-
997 ***********************************************************************
998 *
999 * KlelFreeResult
1000 *
1001 ***********************************************************************
1002 */
1003 void
KlelFreeResult(KLEL_VALUE * psResult)1004 KlelFreeResult(KLEL_VALUE *psResult)
1005 {
1006 if (psResult != NULL)
1007 {
1008 free(psResult);
1009 }
1010 }
1011
1012
1013 /*-
1014 ***********************************************************************
1015 *
1016 * KlelReportError
1017 *
1018 ***********************************************************************
1019 */
1020 void
KlelReportError(KLEL_CONTEXT * psContext,const char * pcFormat,...)1021 KlelReportError(KLEL_CONTEXT *psContext, const char *pcFormat, ...)
1022 {
1023 char *pcError = NULL;
1024 char *pcString = NULL;
1025 int iLength = 0;
1026 va_list pVaList;
1027
1028 KLEL_ASSERT(psContext != NULL);
1029 KLEL_ASSERT(pcFormat != NULL);
1030
1031 if (psContext != NULL)
1032 {
1033 va_start(pVaList, pcFormat);
1034 for (pcString = (char *) pcFormat, iLength = 0; pcString != NULL; pcString = va_arg(pVaList, char *))
1035 {
1036 iLength += strlen(pcString);
1037 }
1038 iLength++; /* Add one for the terminating NULL byte. */
1039 va_end(pVaList);
1040 pcError = (char *) realloc(psContext->pcError, iLength + 1);
1041 if (pcError != NULL)
1042 {
1043 va_start(pVaList, pcFormat);
1044 vsnprintf(pcError, iLength, pcFormat, pVaList);
1045 va_end(pVaList);
1046 psContext->pcError = pcError;
1047 }
1048 }
1049 }
1050
1051
1052 /*-
1053 ***********************************************************************
1054 *
1055 * KlelReportMemoryAllocationError
1056 *
1057 ***********************************************************************
1058 */
1059 void
KlelReportMemoryAllocationError(KLEL_CONTEXT * psContext)1060 KlelReportMemoryAllocationError(KLEL_CONTEXT *psContext)
1061 {
1062 KLEL_ASSERT(psContext != NULL);
1063
1064 if (psContext != NULL)
1065 {
1066 KlelClearError(psContext);
1067 psContext->pcError = gpcMemoryAllocationError;
1068 }
1069 }
1070
1071
1072 /*-
1073 ***********************************************************************
1074 *
1075 * KlelGetError
1076 *
1077 ***********************************************************************
1078 */
1079 const char *
KlelGetError(KLEL_CONTEXT * psContext)1080 KlelGetError(KLEL_CONTEXT *psContext)
1081 {
1082 return (psContext == NULL) ? gpcContextAllocationError : psContext->pcError;
1083 }
1084
1085
1086 /*-
1087 ***********************************************************************
1088 *
1089 * KlelGetFirstError (Note that this is legacy function.)
1090 *
1091 ***********************************************************************
1092 */
1093 const char *
KlelGetFirstError(KLEL_CONTEXT * psContext)1094 KlelGetFirstError(KLEL_CONTEXT *psContext)
1095 {
1096 return KlelGetError(psContext);
1097 }
1098
1099
1100 /*-
1101 ***********************************************************************
1102 *
1103 * KlelGetNextError (Note that this is legacy function.)
1104 *
1105 ***********************************************************************
1106 */
1107 const char *
KlelGetNextError(KLEL_CONTEXT * psContext)1108 KlelGetNextError(KLEL_CONTEXT *psContext)
1109 {
1110 return NULL;
1111 }
1112
1113
1114 /*-
1115 ***********************************************************************
1116 *
1117 * KlelInnerGetTypeOfVar
1118 *
1119 ***********************************************************************
1120 */
1121 KLEL_EXPR_TYPE
KlelInnerGetTypeOfVar(KLEL_CONTEXT * psContext,const char * pcName,void * pvData)1122 KlelInnerGetTypeOfVar(KLEL_CONTEXT *psContext, const char *pcName, void *pvData)
1123 {
1124 KLEL_EXPR_TYPE iResult = KLEL_TYPE_UNKNOWN;
1125
1126 KLEL_ASSERT(psContext != NULL);
1127 KLEL_ASSERT(pcName != NULL);
1128 KLEL_ASSERT(pcName[0] != 0);
1129
1130 if (psContext != NULL && pcName != NULL && pcName[0] != 0)
1131 {
1132 if (psContext->pfGetTypeOfVar != NULL)
1133 {
1134 iResult = psContext->pfGetTypeOfVar(pcName, (void *)psContext);
1135
1136 if (iResult == KLEL_TYPE_UNKNOWN && psContext->pfGetTypeOfVar != (KLEL_TYPE_CALLBACK)KlelGetTypeOfStdVar)
1137 {
1138 iResult = KlelGetTypeOfStdVar(pcName, (void *)psContext);
1139 }
1140 }
1141 else
1142 {
1143 iResult = KlelGetTypeOfStdVar(pcName, (void *)psContext);
1144 }
1145 }
1146
1147 return iResult;
1148 }
1149
1150
1151 /*-
1152 ***********************************************************************
1153 *
1154 * KlelInnerGetValueOfVar
1155 *
1156 ***********************************************************************
1157 */
1158 KLEL_VALUE *
KlelInnerGetValueOfVar(KLEL_CONTEXT * psContext,const char * pcName,void * pvData)1159 KlelInnerGetValueOfVar(KLEL_CONTEXT *psContext, const char *pcName, void *pvData)
1160 {
1161 KLEL_VALUE *psResult = NULL;
1162
1163 KLEL_ASSERT(KlelIsValid(psContext));
1164 KLEL_ASSERT(pcName != NULL);
1165 KLEL_ASSERT(pcName[0] != 0);
1166
1167 if (KlelIsValid(psContext) && pcName != NULL && pcName[0] != 0)
1168 {
1169 if (psContext->pfGetValueOfVar != NULL)
1170 {
1171 psResult = psContext->pfGetValueOfVar(pcName, (void *)psContext);
1172 }
1173
1174 if (psResult == NULL || psResult->iType == KLEL_TYPE_UNKNOWN)
1175 {
1176 KlelFreeResult(psResult);
1177 if (psContext->pfGetTypeOfVar != NULL && psContext->pfGetTypeOfVar != (KLEL_TYPE_CALLBACK)KlelGetTypeOfStdVar)
1178 {
1179 if (psContext->pfGetTypeOfVar(pcName, (void *)psContext) == KLEL_TYPE_UNKNOWN)
1180 {
1181 psResult = KlelGetValueOfStdVar(pcName, (void *)psContext);
1182 }
1183 }
1184 else
1185 {
1186 psResult = KlelGetValueOfStdVar(pcName, (void *)psContext);
1187 }
1188 }
1189 }
1190
1191 return psResult;
1192 }
1193
1194
1195 /*-
1196 ***********************************************************************
1197 *
1198 * KlelIsConstantString
1199 *
1200 ***********************************************************************
1201 */
1202 int
KlelIsConstantString(KLEL_NODE * psNode)1203 KlelIsConstantString(KLEL_NODE *psNode)
1204 {
1205 KLEL_ASSERT(psNode != NULL);
1206
1207 if (psNode != NULL)
1208 {
1209 if (psNode->iType == KLEL_NODE_FRAGMENT)
1210 {
1211 return 1;
1212 }
1213
1214 if (psNode->iType == KLEL_NODE_DOT)
1215 {
1216 return KlelIsConstantString(psNode->apsChildren[KLEL_OPERAND1_INDEX]) && KlelIsConstantString(psNode->apsChildren[KLEL_OPERAND2_INDEX]);
1217 }
1218 }
1219
1220 return 0;
1221 }
1222
1223
1224 /*-
1225 ***********************************************************************
1226 *
1227 * KlelConstantStringLength
1228 *
1229 ***********************************************************************
1230 */
1231 size_t
KlelConstantStringLength(KLEL_NODE * psNode)1232 KlelConstantStringLength(KLEL_NODE *psNode)
1233 {
1234 KLEL_ASSERT(psNode != NULL);
1235 KLEL_ASSERT(KlelIsConstantString(psNode));
1236
1237 if (psNode != NULL)
1238 {
1239 if (psNode->iType == KLEL_NODE_FRAGMENT)
1240 {
1241 return psNode->szLength;
1242 }
1243
1244 if (psNode->iType == KLEL_NODE_DOT)
1245 {
1246 return KlelConstantStringLength(psNode->apsChildren[KLEL_OPERAND1_INDEX]) + KlelConstantStringLength(psNode->apsChildren[KLEL_OPERAND2_INDEX]);
1247 }
1248 }
1249
1250 return 0;
1251 }
1252
1253
1254 /*-
1255 ***********************************************************************
1256 *
1257 * KlelGetReleaseMajor
1258 *
1259 ***********************************************************************
1260 */
1261 int
KlelGetReleaseMajor(void)1262 KlelGetReleaseMajor(void)
1263 {
1264 return KLEL_RELEASE_MAJOR;
1265 }
1266
1267
1268 /*-
1269 ***********************************************************************
1270 *
1271 * KlelGetReleaseMinor
1272 *
1273 ***********************************************************************
1274 */
1275 int
KlelGetReleaseMinor(void)1276 KlelGetReleaseMinor(void)
1277 {
1278 return KLEL_RELEASE_MINOR;
1279 }
1280
1281
1282 /*-
1283 ***********************************************************************
1284 *
1285 * KlelGetReleaseNumber
1286 *
1287 ***********************************************************************
1288 */
1289 uint32_t
KlelGetReleaseNumber(void)1290 KlelGetReleaseNumber(void)
1291 {
1292 return KLEL_RELEASE_NUMBER;
1293 }
1294
1295
1296 /*-
1297 ***********************************************************************
1298 *
1299 * KlelGetReleasePatch
1300 *
1301 ***********************************************************************
1302 */
1303 int
KlelGetReleasePatch(void)1304 KlelGetReleasePatch(void)
1305 {
1306 return KLEL_RELEASE_PATCH;
1307 }
1308
1309
1310 /*-
1311 ***********************************************************************
1312 *
1313 * KlelGetReleaseString
1314 *
1315 ***********************************************************************
1316 */
1317 const char *
KlelGetReleaseString(void)1318 KlelGetReleaseString(void)
1319 {
1320 return PACKAGE_VERSION;
1321 }
1322
1323
1324 /*-
1325 ***********************************************************************
1326 *
1327 * KlelGetVersionCurrent
1328 *
1329 ***********************************************************************
1330 */
1331 int
KlelGetVersionCurrent(void)1332 KlelGetVersionCurrent(void)
1333 {
1334 return KLEL_VERSION_CURRENT;
1335 }
1336
1337
1338 /*-
1339 ***********************************************************************
1340 *
1341 * KlelGetVersionRevision
1342 *
1343 ***********************************************************************
1344 */
1345 int
KlelGetVersionRevision(void)1346 KlelGetVersionRevision(void)
1347 {
1348 return KLEL_VERSION_REVISION;
1349 }
1350
1351
1352 /*-
1353 ***********************************************************************
1354 *
1355 * KlelGetVersionAge
1356 *
1357 ***********************************************************************
1358 */
1359 int
KlelGetVersionAge(void)1360 KlelGetVersionAge(void)
1361 {
1362 return KLEL_VERSION_AGE;
1363 }
1364