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