1 /*
2   Copyright 2021 Northern.tech AS
3 
4   This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5 
6   This program is free software; you can redistribute it and/or modify it
7   under the terms of the GNU General Public License as published by the
8   Free Software Foundation; version 3.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
18 
19   To the extent this program is licensed as part of the Enterprise
20   versions of CFEngine, the applicable Commercial Open Source License
21   (COSL) may apply to this file if you as a licensee so wish it. See
22   included file COSL.txt.
23 */
24 
25 #include <rlist.h>
26 
27 #include <files_names.h>
28 #include <conversion.h>
29 #include <expand.h>
30 #include <matching.h>
31 #include <scope.h>
32 #include <fncall.h>
33 #include <string_lib.h>                                       /* StringHash */
34 #include <regex.h>          /* StringMatchWithPrecompiledRegex,CompileRegex */
35 #include <misc_lib.h>
36 #include <assoc.h>
37 #include <eval_context.h>
38 #include <json.h>
39 #include <vars.h>                                         /* IsCf3VarString */
40 
41 
42 static Rlist *RlistPrependRval(Rlist **start, Rval rval);
43 
44 static char SECRET_RVAL[] = "************";
45 
DataTypeToRvalType(DataType datatype)46 RvalType DataTypeToRvalType(DataType datatype)
47 {
48     switch (datatype)
49     {
50     case CF_DATA_TYPE_BODY:
51     case CF_DATA_TYPE_BUNDLE:
52     case CF_DATA_TYPE_CONTEXT:
53     case CF_DATA_TYPE_COUNTER:
54     case CF_DATA_TYPE_INT:
55     case CF_DATA_TYPE_INT_RANGE:
56     case CF_DATA_TYPE_OPTION:
57     case CF_DATA_TYPE_REAL:
58     case CF_DATA_TYPE_REAL_RANGE:
59     case CF_DATA_TYPE_STRING:
60         return RVAL_TYPE_SCALAR;
61 
62     case CF_DATA_TYPE_CONTEXT_LIST:
63     case CF_DATA_TYPE_INT_LIST:
64     case CF_DATA_TYPE_OPTION_LIST:
65     case CF_DATA_TYPE_REAL_LIST:
66     case CF_DATA_TYPE_STRING_LIST:
67         return RVAL_TYPE_LIST;
68 
69     case CF_DATA_TYPE_CONTAINER:
70         return RVAL_TYPE_CONTAINER;
71 
72     case CF_DATA_TYPE_NONE:
73         return RVAL_TYPE_NOPROMISEE;
74     }
75 
76     ProgrammingError("DataTypeToRvalType, unhandled");
77 }
78 
RlistValueIsType(const Rlist * rlist,RvalType type)79 bool RlistValueIsType(const Rlist *rlist, RvalType type)
80 {
81     return (rlist != NULL &&
82             rlist->val.type == type);
83 }
84 
RlistScalarValue(const Rlist * rlist)85 char *RlistScalarValue(const Rlist *rlist)
86 {
87     if (rlist->val.type != RVAL_TYPE_SCALAR)
88     {
89         ProgrammingError("Rlist value contains type %c instead of expected scalar", rlist->val.type);
90     }
91 
92     return rlist->val.item;
93 }
94 
RlistScalarValueSafe(const Rlist * rlist)95 char *RlistScalarValueSafe(const Rlist *rlist)
96 {
97     if (rlist->val.type != RVAL_TYPE_SCALAR)
98     {
99         return "[not printable]";
100     }
101 
102     return RlistScalarValue(rlist);
103 }
104 
105 /*******************************************************************/
106 
RlistFnCallValue(const Rlist * rlist)107 FnCall *RlistFnCallValue(const Rlist *rlist)
108 {
109     if (rlist->val.type != RVAL_TYPE_FNCALL)
110     {
111         ProgrammingError("Rlist value contains type %c instead of expected FnCall", rlist->val.type);
112     }
113 
114     return rlist->val.item;
115 }
116 
117 /*******************************************************************/
118 
RlistRlistValue(const Rlist * rlist)119 Rlist *RlistRlistValue(const Rlist *rlist)
120 {
121     if (rlist->val.type != RVAL_TYPE_LIST)
122     {
123         ProgrammingError("Rlist value contains type %c instead of expected List", rlist->val.type);
124     }
125 
126     return rlist->val.item;
127 }
128 
129 /*******************************************************************/
130 
RvalScalarValue(Rval rval)131 char *RvalScalarValue(Rval rval)
132 {
133     if (rval.type != RVAL_TYPE_SCALAR)
134     {
135         ProgrammingError("Internal error: Rval contains type %c instead of expected scalar", rval.type);
136     }
137 
138     return rval.item;
139 }
140 
141 /*******************************************************************/
142 
RvalFnCallValue(Rval rval)143 FnCall *RvalFnCallValue(Rval rval)
144 {
145     if (rval.type != RVAL_TYPE_FNCALL)
146     {
147         ProgrammingError("Rval contains type %c instead of expected FnCall", rval.type);
148     }
149 
150     return rval.item;
151 }
152 
153 /*******************************************************************/
154 
RvalRlistValue(Rval rval)155 Rlist *RvalRlistValue(Rval rval)
156 {
157     if (rval.type != RVAL_TYPE_LIST)
158     {
159         ProgrammingError("Rval contain type %c instead of expected List", rval.type);
160     }
161 
162     return rval.item;
163 }
164 
165 /*******************************************************************/
166 
RvalContainerValue(Rval rval)167 JsonElement *RvalContainerValue(Rval rval)
168 {
169     if (rval.type != RVAL_TYPE_CONTAINER)
170     {
171         ProgrammingError("Rval contain type %c instead of expected container", rval.type);
172     }
173 
174     return rval.item;
175 }
176 
177 
RvalTypeToString(RvalType type)178 const char *RvalTypeToString(RvalType type)
179 {
180     switch (type)
181     {
182     case RVAL_TYPE_CONTAINER:
183         return "data";
184     case RVAL_TYPE_FNCALL:
185         return "call";
186     case RVAL_TYPE_LIST:
187         return "list";
188     case RVAL_TYPE_NOPROMISEE:
189         return "null";
190     case RVAL_TYPE_SCALAR:
191         return "scalar";
192     }
193 
194     assert(false && "never reach");
195     return NULL;
196 }
197 
RlistKeyIn(Rlist * list,const char * key)198 Rlist *RlistKeyIn(Rlist *list, const char *key)
199 {
200     for (Rlist *rp = list; rp != NULL; rp = rp->next)
201     {
202         if (rp->val.type == RVAL_TYPE_SCALAR &&
203             strcmp(RlistScalarValue(rp), key) == 0)
204         {
205             return rp;
206         }
207     }
208 
209     return NULL;
210 }
211 
212 /*******************************************************************/
213 
RlistMatchesRegexRlist(const Rlist * list,const Rlist * search)214 bool RlistMatchesRegexRlist(const Rlist *list, const Rlist *search)
215 /*
216    Returns true if "list" contains all the regular expressions in
217    "search".  Non-scalars in "list" and "search" are skipped.
218 */
219 {
220     for (const Rlist *rp = search; rp != NULL; rp = rp->next)
221     {
222         if (rp->val.type == RVAL_TYPE_SCALAR &&
223             // check for the current element in the search list
224             !RlistMatchesRegex(list, RlistScalarValue(search)))
225         {
226             return false;
227         }
228     }
229 
230     return true;
231 }
232 
RlistMatchesRegex(const Rlist * list,const char * regex)233 bool RlistMatchesRegex(const Rlist *list, const char *regex)
234 /*
235    Returns true if any of the "list" of strings matches "regex".
236    Non-scalars in "list" are skipped.
237 */
238 {
239     if (regex == NULL || list == NULL)
240     {
241         return false;
242     }
243 
244     pcre *rx = CompileRegex(regex);
245     if (!rx)
246     {
247         return false;
248     }
249 
250     for (const Rlist *rp = list; rp != NULL; rp = rp->next)
251     {
252         if (rp->val.type == RVAL_TYPE_SCALAR &&
253             StringMatchFullWithPrecompiledRegex(rx, RlistScalarValue(rp)))
254         {
255             pcre_free(rx);
256             return true;
257         }
258     }
259 
260     pcre_free(rx);
261     return false;
262 }
263 
RlistIsNullList(const Rlist * list)264 bool RlistIsNullList(const Rlist *list)
265 {
266     return (list == NULL);
267 }
268 
RlistIsInListOfRegex(const Rlist * list,const char * str)269 bool RlistIsInListOfRegex(const Rlist *list, const char *str)
270 /*
271    Returns true if any of the "list" of regular expressions matches "str".
272    Non-scalars in "list" are skipped.
273 */
274 {
275     if (str == NULL || list == NULL)
276     {
277         return false;
278     }
279 
280     for (const Rlist *rp = list; rp != NULL; rp = rp->next)
281     {
282         if (rp->val.type == RVAL_TYPE_SCALAR &&
283             StringMatchFull(RlistScalarValue(rp), str))
284         {
285             return true;
286         }
287     }
288 
289     return false;
290 }
291 
RlistContainsString(const Rlist * list,const char * string)292 bool RlistContainsString(const Rlist *list, const char *string)
293 {
294     assert(string != NULL);
295 
296     if (list == NULL)
297     {
298         // Empty Rlist is represented as a NULL pointer
299         return false;
300     }
301 
302     for (const Rlist *rp = list; rp != NULL; rp = rp->next)
303     {
304         if (rp->val.type == RVAL_TYPE_SCALAR &&
305             StringEqual(RlistScalarValue(rp), string))
306         {
307             return true;
308         }
309     }
310     return false;
311 }
312 
313 /*******************************************************************/
314 
RvalCopyScalar(Rval rval)315 static Rval RvalCopyScalar(Rval rval)
316 {
317     assert(rval.type == RVAL_TYPE_SCALAR);
318     const char * src = rval.item ? rval.item : "";
319 
320     return (Rval) {xstrdup(src), RVAL_TYPE_SCALAR};
321 }
322 
RlistAppendRval(Rlist ** start,Rval rval)323 Rlist *RlistAppendRval(Rlist **start, Rval rval)
324 {
325     Rlist *rp = xmalloc(sizeof(Rlist));
326 
327     rp->val  = rval;
328     rp->next = NULL;
329 
330     if (*start == NULL)
331     {
332         *start = rp;
333     }
334     else
335     {
336         Rlist *lp = *start;
337         while (lp->next != NULL)
338         {
339             lp = lp->next;
340         }
341 
342         lp->next = rp;
343     }
344 
345     return rp;
346 }
347 
348 /* Inserts an Rlist node with value #rval, right after the rlist node #node. */
RlistInsertAfter(Rlist * node,Rval rval)349 void RlistInsertAfter(Rlist *node, Rval rval)
350 {
351     assert(node != NULL);
352 
353     Rlist new_node = { .val  = rval,
354                        .next = node->next };
355 
356     node->next = xmemdup(&new_node, sizeof(new_node));
357 }
358 
RvalNewRewriter(const void * item,RvalType type,JsonElement * map)359 Rval RvalNewRewriter(const void *item, RvalType type, JsonElement *map)
360 {
361     switch (type)
362     {
363     case RVAL_TYPE_SCALAR:
364         if (map != NULL && JsonLength(map) > 0 &&       // do we have a rewrite map?
365             (strstr(item, "$(") || strstr(item, "${"))) // are there unresolved variable references?
366         {
367             // TODO: replace with BufferSearchAndReplace when the
368             // string_replace code is merged.
369             // Sorry about the CF_BUFSIZE ugliness.
370             int max_size = 10*CF_BUFSIZE+1;
371             char *buffer_from = xmalloc(max_size);
372             char *buffer_to = xmalloc(max_size);
373 
374             Buffer *format = BufferNew();
375             StringCopy(item, buffer_from, max_size);
376 
377             for (int iteration = 0; iteration < 10; iteration++)
378             {
379                 bool replacement_made = false;
380                 int var_start = -1;
381                 char closing_brace = 0;
382                 for (int c = 0; c < buffer_from[c]; c++)
383                 {
384                     if (buffer_from[c] == '$')
385                     {
386                         if (buffer_from[c+1] == '(')
387                         {
388                             closing_brace = ')';
389                         }
390                         else if (buffer_from[c+1] == '{')
391                         {
392                             closing_brace = '}';
393                         }
394 
395                         if (closing_brace)
396                         {
397                             c++;
398                             var_start = c-1;
399                         }
400                     }
401                     else if (var_start >= 0 && buffer_from[c] == closing_brace)
402                     {
403                         char saved = buffer_from[c];
404                         buffer_from[c] = '\0';
405                         const char *repl = JsonObjectGetAsString(map, buffer_from + var_start + 2);
406                         buffer_from[c] = saved;
407 
408                         if (repl)
409                         {
410                             // Before the replacement.
411                             memcpy(buffer_to, buffer_from, var_start);
412 
413                             // The actual replacement.
414                             int repl_len = strlen(repl);
415                             memcpy(buffer_to + var_start, repl, repl_len);
416 
417                             // The text after.
418                             strlcpy(buffer_to + var_start + repl_len, buffer_from + c + 1, max_size - var_start - repl_len);
419 
420                             // Reset location to immediately after the replacement.
421                             c = var_start + repl_len - 1;
422                             var_start = -1;
423                             StringCopy(buffer_to, buffer_from, max_size);
424                             closing_brace = 0;
425                             replacement_made = true;
426                         }
427                     }
428                 }
429 
430                 if (!replacement_made)
431                 {
432                     break;
433                 }
434             }
435 
436             char *ret = xstrdup(buffer_to);
437 
438             BufferDestroy(format);
439             free(buffer_to);
440             free(buffer_from);
441 
442             return (Rval) { ret, RVAL_TYPE_SCALAR };
443         }
444         else
445         {
446             return (Rval) { xstrdup(item), RVAL_TYPE_SCALAR };
447         }
448 
449     case RVAL_TYPE_FNCALL:
450         return (Rval) { FnCallCopyRewriter(item, map), RVAL_TYPE_FNCALL };
451 
452     case RVAL_TYPE_LIST:
453         return (Rval) { RlistCopyRewriter(item, map), RVAL_TYPE_LIST };
454 
455     case RVAL_TYPE_CONTAINER:
456         return (Rval) { JsonCopy(item), RVAL_TYPE_CONTAINER };
457 
458     case RVAL_TYPE_NOPROMISEE:
459         return ((Rval) {NULL, type});
460     }
461 
462     assert(false);
463     return ((Rval) { NULL, RVAL_TYPE_NOPROMISEE });
464 }
465 
RvalNew(const void * item,RvalType type)466 Rval RvalNew(const void *item, RvalType type)
467 {
468     return RvalNewRewriter(item, type, NULL);
469 }
470 
RvalNewSecret()471 Rval RvalNewSecret()
472 {
473     return ((Rval) {SECRET_RVAL, RVAL_TYPE_SCALAR});
474 }
475 
RvalCopyRewriter(Rval rval,JsonElement * map)476 Rval RvalCopyRewriter(Rval rval, JsonElement *map)
477 {
478     return RvalNewRewriter(rval.item, rval.type, map);
479 }
480 
RvalCopy(Rval rval)481 Rval RvalCopy(Rval rval)
482 {
483     return RvalNew(rval.item, rval.type);
484 }
485 
486 /*******************************************************************/
487 
RlistCopyRewriter(const Rlist * rp,JsonElement * map)488 Rlist *RlistCopyRewriter(const Rlist *rp, JsonElement *map)
489 {
490     Rlist *start = NULL;
491 
492     while (rp != NULL)
493     {
494         RlistAppendRval(&start, RvalCopyRewriter(rp->val, map));
495         rp = rp->next;
496     }
497 
498     return start;
499 }
500 
RlistCopy(const Rlist * rp)501 Rlist *RlistCopy(const Rlist *rp)
502 {
503     return RlistCopyRewriter(rp, NULL);
504 }
505 
506 /*******************************************************************/
507 
RlistDestroy(Rlist * rl)508 void RlistDestroy(Rlist *rl)
509 /* Delete an rlist and all its references */
510 {
511     while (rl != NULL)
512     {
513         Rlist *next = rl->next;
514 
515         if (rl->val.item)
516         {
517             RvalDestroy(rl->val);
518         }
519 
520         free(rl);
521         rl = next;
522     }
523 }
524 
RlistDestroy_untyped(void * rl)525 void RlistDestroy_untyped(void *rl)
526 {
527     RlistDestroy(rl);
528 }
529 
530 /*******************************************************************/
531 
RlistAppendScalarIdemp(Rlist ** start,const char * scalar)532 Rlist *RlistAppendScalarIdemp(Rlist **start, const char *scalar)
533 {
534     if (RlistKeyIn(*start, scalar))
535     {
536         return NULL;
537     }
538 
539     return RlistAppendScalar(start, scalar);
540 }
541 
RlistPrependScalarIdemp(Rlist ** start,const char * scalar)542 Rlist *RlistPrependScalarIdemp(Rlist **start, const char *scalar)
543 {
544     if (RlistKeyIn(*start, scalar))
545     {
546         return NULL;
547     }
548 
549     return RlistPrepend(start, scalar, RVAL_TYPE_SCALAR);
550 }
551 
RlistAppendScalar(Rlist ** start,const char * scalar)552 Rlist *RlistAppendScalar(Rlist **start, const char *scalar)
553 {
554     return RlistAppendRval(start, RvalCopyScalar((Rval) { (char *)scalar, RVAL_TYPE_SCALAR }));
555 }
556 
RlistAppendString(Rlist ** start,const char * string)557 Rlist *RlistAppendString(Rlist **start, const char *string)
558 {
559     Rlist *l = RlistAppendScalar(start, string);
560 
561     assert(RlistContainsString(l, string));
562 
563     return l;
564 }
565 
566 // NOTE: Copies item, does NOT take ownership
RlistAppend(Rlist ** start,const void * item,RvalType type)567 Rlist *RlistAppend(Rlist **start, const void *item, RvalType type)
568 {
569     return RlistAppendAllTypes(start, item, type, false);
570 }
571 
572 // See fncall.c for the usage of allow_all_types.
RlistAppendAllTypes(Rlist ** start,const void * item,RvalType type,bool allow_all_types)573 Rlist *RlistAppendAllTypes(Rlist **start, const void *item, RvalType type, bool allow_all_types)
574 {
575     Rlist *lp = *start;
576 
577     switch (type)
578     {
579     case RVAL_TYPE_SCALAR:
580         return RlistAppendScalar(start, item);
581 
582     case RVAL_TYPE_FNCALL:
583         break;
584 
585     case RVAL_TYPE_LIST:
586         if (allow_all_types)
587         {
588             JsonElement* store = JsonArrayCreate(RlistLen(item));
589             for (const Rlist *rp = item; rp; rp = rp->next)
590             {
591                 JsonArrayAppendElement(store, RvalToJson(rp->val));
592             }
593 
594             return RlistAppendRval(start, (Rval) { store, RVAL_TYPE_CONTAINER });
595         }
596 
597         for (const Rlist *rp = item; rp; rp = rp->next)
598         {
599             lp = RlistAppendRval(start, RvalCopy(rp->val));
600         }
601 
602         return lp;
603 
604     case RVAL_TYPE_CONTAINER:
605         if (allow_all_types)
606         {
607             return RlistAppendRval(start, (Rval) { JsonCopy((JsonElement*) item), RVAL_TYPE_CONTAINER });
608         }
609 
610         // fall through
611 
612     default:
613         Log(LOG_LEVEL_DEBUG, "Cannot append %c to rval-list '%s'", type, (char *) item);
614         return NULL;
615     }
616 
617     Rlist *rp = xmalloc(sizeof(Rlist));
618 
619     rp->val  = RvalNew(item, type);
620     rp->next = NULL;
621 
622     if (*start == NULL)
623     {
624         *start = rp;
625     }
626     else
627     {
628         for (lp = *start; lp->next != NULL; lp = lp->next)
629         {
630         }
631 
632         lp->next = rp;
633     }
634 
635     return rp;
636 }
637 
638 /*******************************************************************/
639 
RlistPrependRval(Rlist ** start,Rval rval)640 static Rlist *RlistPrependRval(Rlist **start, Rval rval)
641 {
642     Rlist *rp = xmalloc(sizeof(Rlist));
643 
644     rp->next = *start;
645     rp->val = rval;
646 
647     *start = rp;
648 
649     return rp;
650 }
651 
RlistPrepend(Rlist ** start,const void * item,RvalType type)652 Rlist *RlistPrepend(Rlist **start, const void *item, RvalType type)
653 {
654     switch (type)
655     {
656     case RVAL_TYPE_LIST:
657         {
658             Rlist *lp = NULL;
659             for (const Rlist *rp = item; rp; rp = rp->next)
660             {
661                 lp = RlistPrependRval(start, RvalCopy(rp->val));
662             }
663             return lp;
664         }
665 
666     case RVAL_TYPE_SCALAR:
667     case RVAL_TYPE_FNCALL:
668     case RVAL_TYPE_CONTAINER:
669     case RVAL_TYPE_NOPROMISEE:
670         return RlistPrependRval(start, RvalNew(item, type));
671     }
672 
673     assert(false);
674     return NULL;
675 }
676 
677 /*******************************************************************/
678 
RlistLen(const Rlist * start)679 int RlistLen(const Rlist *start)
680 {
681     int count = 0;
682 
683     for (const Rlist *rp = start; rp != NULL; rp = rp->next)
684     {
685         count++;
686     }
687 
688     return count;
689 }
690 
691 /*******************************************************************/
692 
RlistParseShown(const char * string)693 Rlist *RlistParseShown(const char *string)
694 {
695     Rlist *newlist = NULL, *splitlist, *rp;
696 
697 /* Parse a string representation generated by ShowList and turn back into Rlist */
698 
699     splitlist = RlistFromSplitString(string, ',');
700 
701     for (rp = splitlist; rp != NULL; rp = rp->next)
702     {
703         char value[CF_MAXVARSIZE] = { 0 };
704         sscanf(RlistScalarValue(rp), "%*[{ '\"]%255[^'\"}]", value);
705         RlistAppendScalar(&newlist, value);
706     }
707 
708     RlistDestroy(splitlist);
709     return newlist;
710 }
711 
712 /*******************************************************************/
713 
714 typedef enum
715 {
716     ST_OPENED,
717     ST_PRECLOSED,
718     ST_CLOSED,
719     ST_IO,
720     ST_ELM1,
721     ST_ELM2,
722     ST_END1,
723     ST_END2,
724     ST_SEP,
725     ST_ERROR
726 } state;
727 
728 #define CLASS_BLANK(x)  (((x)==' ')||((x)=='\t'))
729 #define CLASS_START1(x) (((x)=='\''))
730 #define CLASS_START2(x) (((x)=='"'))
731 #define CLASS_END1(x)   ((CLASS_START1(x)))
732 #define CLASS_END2(x)   ((CLASS_START2(x)))
733 #define CLASS_BRA1(x)   (((x)=='{'))
734 #define CLASS_BRA2(x)   (((x)=='}'))
735 #define CLASS_SEP(x)    (((x)==','))
736 #define CLASS_EOL(x)    (((x)=='\0'))
737 
738 #define CLASS_ANY0(x) ((!CLASS_BLANK(x))&&(!CLASS_BRA1(x)))
739 #define CLASS_ANY1(x) ((!CLASS_BLANK(x))&&(!CLASS_START1(x))&&(!CLASS_START2(x)))
740 #define CLASS_ANY2(x) ((!CLASS_END1(x)))
741 #define CLASS_ANY3(x) ((!CLASS_END2(x)))
742 #define CLASS_ANY4(x) ((!CLASS_BLANK(x))&&(!CLASS_SEP(x))&&(!CLASS_BRA2(x)))
743 #define CLASS_ANY5(x) ((!CLASS_BLANK(x))&&(!CLASS_SEP(x))&&(!CLASS_BRA2(x)))
744 #define CLASS_ANY6(x) ((!CLASS_BLANK(x))&&(!CLASS_START2(x))&&(!CLASS_START2(x)))
745 #define CLASS_ANY7(x) ((!CLASS_BLANK(x))&&(!CLASS_EOL(x)))
746 
747 /**
748  @brief parse elements in a list passed through use_module
749 
750  @param[in] str: is the string to parse
751  @param[out] newlist: rlist of elements found
752 
753  @retval 0: successful > 0: failed
754  */
LaunchParsingMachine(const char * str,Rlist ** newlist)755 static int LaunchParsingMachine(const char *str, Rlist **newlist)
756 {
757     const char *s = str;
758     state current_state = ST_OPENED;
759     int ret;
760 
761     Buffer *buf = BufferNewWithCapacity(CF_MAXVARSIZE);
762 
763     assert(newlist);
764 
765     while (current_state != ST_CLOSED && *s)
766     {
767         switch(current_state)
768         {
769             case ST_ERROR:
770                 Log(LOG_LEVEL_ERR, "Parsing error : Malformed string");
771                 ret = 1;
772                 goto clean;
773             case ST_OPENED:
774                 if (CLASS_BLANK(*s))
775                 {
776                     current_state = ST_OPENED;
777                 }
778                 else if (CLASS_BRA1(*s))
779                 {
780                     current_state = ST_IO;
781                 }
782                 else if (CLASS_ANY0(*s))
783                 {
784                     current_state = ST_ERROR;
785                 }
786                 s++;
787                 break;
788             case ST_IO:
789                 if (CLASS_BLANK(*s))
790                 {
791                     current_state = ST_IO;
792                 }
793                 else if (CLASS_START1(*s))
794                 {
795                     BufferClear(buf);
796                     current_state = ST_ELM1;
797                 }
798                 else if (CLASS_START2(*s))
799                 {
800                     BufferClear(buf);
801                     current_state = ST_ELM2;
802                 }
803                 else if (CLASS_ANY1(*s))
804                 {
805                     current_state = ST_ERROR;
806                 }
807                 s++;
808                 break;
809             case ST_ELM1:
810                 if (CLASS_END1(*s))
811                 {
812                     RlistAppendScalar(newlist, BufferData(buf));
813                     BufferClear(buf);
814                     current_state = ST_END1;
815                 }
816                 else if (CLASS_ANY2(*s))
817                 {
818                     BufferAppendChar(buf, *s);
819                     current_state = ST_ELM1;
820                 }
821                 s++;
822                 break;
823             case ST_ELM2:
824                 if (CLASS_END2(*s))
825                 {
826                     RlistAppendScalar(newlist, BufferData(buf));
827                     BufferClear(buf);
828                     current_state = ST_END2;
829                 }
830                 else if (CLASS_ANY3(*s))
831                 {
832                     BufferAppendChar(buf, *s);
833                     current_state = ST_ELM2;
834                 }
835                 s++;
836                 break;
837             case ST_END1:
838                 if (CLASS_SEP(*s))
839                 {
840                     current_state = ST_SEP;
841                 }
842                 else if (CLASS_BRA2(*s))
843                 {
844                     current_state = ST_PRECLOSED;
845                 }
846                 else if (CLASS_BLANK(*s))
847                 {
848                     current_state = ST_END1;
849                 }
850                 else if (CLASS_ANY4(*s))
851                 {
852                     current_state = ST_ERROR;
853                 }
854                 s++;
855                 break;
856             case ST_END2:
857                 if (CLASS_SEP(*s))
858                 {
859                     current_state = ST_SEP;
860                 }
861                 else if (CLASS_BRA2(*s))
862                 {
863                     current_state = ST_PRECLOSED;
864                 }
865                 else if (CLASS_BLANK(*s))
866                 {
867                     current_state = ST_END2;
868                 }
869                 else if (CLASS_ANY5(*s))
870                 {
871                     current_state = ST_ERROR;
872                 }
873                 s++;
874                 break;
875             case ST_SEP:
876                 if (CLASS_BLANK(*s))
877                 {
878                     current_state = ST_SEP;
879                 }
880                 else if (CLASS_START1(*s))
881                 {
882                     current_state = ST_ELM1;
883                 }
884                 else if (CLASS_START2(*s))
885                 {
886                     current_state = ST_ELM2;
887                 }
888                 else if (CLASS_ANY6(*s))
889                 {
890                     current_state = ST_ERROR;
891                 }
892                 s++;
893                 break;
894             case ST_PRECLOSED:
895                 if (CLASS_BLANK(*s))
896                 {
897                     current_state = ST_PRECLOSED;
898                 }
899                 else if (CLASS_EOL(*s))
900                 {
901                     current_state = ST_CLOSED;
902                 }
903                 else if (CLASS_ANY7(*s))
904                 {
905                     current_state = ST_ERROR;
906                 }
907                 s++;
908                 break;
909             default:
910                 Log(LOG_LEVEL_ERR, "Parsing logic error: unknown state");
911                 ret = 2;
912                 goto clean;
913                 break;
914         }
915     }
916 
917     if (current_state != ST_CLOSED && current_state != ST_PRECLOSED )
918     {
919         Log(LOG_LEVEL_ERR, "Parsing error : Malformed string (unexpected end of input)");
920         ret = 3;
921         goto clean;
922     }
923 
924     BufferDestroy(buf);
925     return 0;
926 
927 clean:
928     BufferDestroy(buf);
929     RlistDestroy(*newlist);
930     assert(ret != 0);
931     return ret;
932 }
933 
RlistParseString(const char * string)934 Rlist *RlistParseString(const char *string)
935 {
936     Rlist *newlist = NULL;
937     if (LaunchParsingMachine(string, &newlist))
938     {
939         return NULL;
940     }
941 
942     return newlist;
943 }
944 
945 /*******************************************************************/
946 
RvalDestroy(Rval rval)947 void RvalDestroy(Rval rval)
948 {
949     if (rval.item == NULL || rval.item == SECRET_RVAL)
950     {
951         return;
952     }
953 
954     switch (rval.type)
955     {
956     case RVAL_TYPE_SCALAR:
957         free(RvalScalarValue(rval));
958         return;
959 
960     case RVAL_TYPE_LIST:
961         RlistDestroy(RvalRlistValue(rval));
962         return;
963 
964     case RVAL_TYPE_FNCALL:
965         FnCallDestroy(RvalFnCallValue(rval));
966         break;
967 
968     case RVAL_TYPE_CONTAINER:
969         JsonDestroy(RvalContainerValue(rval));
970         break;
971 
972     case RVAL_TYPE_NOPROMISEE:
973         return;
974     }
975 }
976 
977 /*********************************************************************/
978 
RlistDestroyEntry(Rlist ** liststart,Rlist * entry)979 void RlistDestroyEntry(Rlist **liststart, Rlist *entry)
980 {
981     if (entry != NULL)
982     {
983         if (entry->val.item)
984         {
985             free(entry->val.item);
986         }
987 
988         Rlist *sp = entry->next;
989 
990         if (entry == *liststart)
991         {
992             *liststart = sp;
993         }
994         else
995         {
996             Rlist *rp = *liststart;
997             while (rp->next != entry)
998             {
999                 rp = rp->next;
1000             }
1001 
1002             assert(rp && rp->next == entry);
1003             rp->next = sp;
1004         }
1005 
1006         free(entry);
1007     }
1008 }
1009 
1010 /*******************************************************************/
1011 
1012 /* Copies a <sep>-delimited unit from <from> into a new entry in <to>.
1013  *
1014  * \<sep> is not counted as the separator, but copied to the new entry
1015  * as <sep>.  No other escape sequences are supported.
1016  *
1017  * Returns the number of bytes read out of <from>; this may be more
1018  * than the length of the new entry in <to>.  The new entry is
1019  * prepended; the caller can reverse <to> once built.
1020  */
SubStrnCopyChr(Rlist ** to,const char * from,char sep,char lstrip)1021 static size_t SubStrnCopyChr(Rlist **to, const char *from, char sep, char lstrip)
1022 {
1023     assert(from && from[0]);
1024     size_t offset = 0;
1025 
1026     while (lstrip != '\0' && from[0] == lstrip && from[0] != '\0')
1027     {
1028         /* Skip over all instances of the 'lstrip' character (e.g. ' ') if
1029          * specified */
1030         from++;
1031         offset++;
1032     }
1033     if (from[0] == '\0')
1034     {
1035         /* Reached the end already so there's nothing to add to the result list,
1036            just tell the caller how far they can move. */
1037         return offset;
1038     }
1039 
1040     const char *end = from;
1041     size_t escapes = 0;
1042     while (end && end[0] && end[0] != sep)
1043     {
1044         end = strchr(end, sep);
1045         assert(end == NULL || end[0] == sep);
1046         if (end && end > from && end[-1] == '\\')
1047         {
1048             escapes++;
1049             end++;
1050         }
1051     }
1052 
1053     size_t consume = (end == NULL) ? strlen(from) : (size_t)(end - from);
1054     assert(consume >= escapes);
1055     char copy[1 + consume - escapes], *dst = copy;
1056 
1057     for (const char *src = from; src[0] != '\0' && src[0] != sep; src++)
1058     {
1059         if (src[0] == '\\' && src[1] == sep)
1060         {
1061             src++; /* Skip over the backslash so we copy the sep */
1062         }
1063         dst++[0] = src[0];
1064     }
1065     assert(dst + 1 == copy + sizeof(copy));
1066     *dst = '\0';
1067 
1068     /* Prepend to the list and reverse when done, costing O(len),
1069      * instead of appending, which costs O(len**2). */
1070     RlistPrependRval(to, RvalCopyScalar((Rval) { copy, RVAL_TYPE_SCALAR }));
1071     return offset + consume;
1072 }
1073 
RlistFromSplitString(const char * string,char sep)1074 Rlist *RlistFromSplitString(const char *string, char sep)
1075 /* Splits a string on a separator - e.g. "," - into a linked list of
1076  * separate items.  Supports escaping separators - e.g. "\," isn't a
1077  * separator, it contributes a simple "," in a list entry. */
1078 {
1079     if (string == NULL || string[0] == '\0')
1080     {
1081         return NULL;
1082     }
1083     Rlist *liststart = NULL;
1084 
1085     for (const char *sp = string; *sp != '\0';)
1086     {
1087         sp += SubStrnCopyChr(&liststart, sp, sep, '\0');
1088         assert((size_t) (sp - string) <= strlen(string));
1089         if (*sp)
1090         {
1091             assert(*sp == sep && (sp == string || sp[-1] != '\\'));
1092             sp++;
1093         }
1094     }
1095 
1096     RlistReverse(&liststart);
1097     return liststart;
1098 }
1099 
1100 /**
1101  * Splits the given string into lines. On Windows, both \n and \r\n newlines are
1102  * detected. Escaped newlines are respected/ignored too.
1103  *
1104  * @param detect_crlf whether to try to detect and respect "\r\n" line endings
1105  * @return: an #Rlist where items are the individual lines **without** the
1106  *          trailing newline character(s)
1107  * @note: Free the result with RlistDestroy()
1108  * @warning: This function doesn't work properly if @string uses "\r\n" newlines
1109  *           and contains '\r' characters that are not part of any "\r\n"
1110  *           sequence because it first splits @string on '\r'.
1111  */
RlistFromStringSplitLines(const char * string,bool detect_crlf)1112 Rlist *RlistFromStringSplitLines(const char *string, bool detect_crlf)
1113 {
1114     if (string == NULL || string[0] == '\0')
1115     {
1116         return NULL;
1117     }
1118 
1119     if (!detect_crlf || (strstr(string, "\r\n") == NULL))
1120     {
1121         return RlistFromSplitString(string, '\n');
1122     }
1123 
1124     /* else we split on '\r' just like RlistFromSplitString() above, but
1125      * strip leading '\n' in every chunk, thus effectively split on \r\n. See
1126      * the warning in the function's documentation.*/
1127     Rlist *liststart = NULL;
1128 
1129     for (const char *sp = string; *sp != '\0';)
1130     {
1131         sp += SubStrnCopyChr(&liststart, sp, '\r', '\n');
1132         assert((size_t) (sp - string) <= strlen(string));
1133         if (*sp)
1134         {
1135             assert(*sp == '\r' && (sp == string || sp[-1] != '\\'));
1136             sp++;
1137         }
1138     }
1139 
1140     RlistReverse(&liststart);
1141     return liststart;
1142 }
1143 
1144 /*******************************************************************/
1145 
RlistFromSplitRegex(const char * string,const char * regex,size_t max_entries,bool allow_blanks)1146 Rlist *RlistFromSplitRegex(const char *string, const char *regex, size_t max_entries, bool allow_blanks)
1147 {
1148     assert(string);
1149     if (!string)
1150     {
1151         return NULL;
1152     }
1153 
1154     const char *sp = string;
1155     size_t entry_count = 0;
1156     size_t start = 0;
1157     size_t end = 0;
1158     Rlist *result = NULL;
1159     Buffer *buffer = BufferNewWithCapacity(CF_MAXVARSIZE);
1160 
1161     pcre *rx = CompileRegex(regex);
1162     if (rx)
1163     {
1164         while ((entry_count < max_entries) &&
1165                StringMatchWithPrecompiledRegex(rx, sp, &start, &end))
1166         {
1167             if (end == 0)
1168             {
1169                 break;
1170             }
1171 
1172             BufferClear(buffer);
1173             BufferAppend(buffer, sp, start);
1174 
1175             if (allow_blanks || BufferSize(buffer) > 0)
1176             {
1177                 RlistAppendScalar(&result, BufferData(buffer));
1178                 entry_count++;
1179             }
1180 
1181             sp += end;
1182         }
1183 
1184         pcre_free(rx);
1185     }
1186 
1187     if (entry_count < max_entries)
1188     {
1189         BufferClear(buffer);
1190         size_t remaining = strlen(sp);
1191         BufferAppend(buffer, sp, remaining);
1192 
1193         if ((allow_blanks && sp != string) || BufferSize(buffer) > 0)
1194         {
1195             RlistAppendScalar(&result, BufferData(buffer));
1196         }
1197     }
1198 
1199     BufferDestroy(buffer);
1200 
1201     return result;
1202 }
1203 
1204 /*******************************************************************/
1205 /*
1206  * Splits string on regex, returns a list of (at most max) fragments.
1207  *
1208  * NOTE: in contrast with RlistFromSplitRegex() this one will produce at most max number of elements;
1209  *       last element will contain everything that lefts from original string (we use everything after
1210  *       the (max-1)-th separator as the final list element, including any separators that may be embedded in it)
1211  */
RlistFromRegexSplitNoOverflow(const char * string,const char * regex,int max)1212 Rlist *RlistFromRegexSplitNoOverflow(const char *string, const char *regex, int max)
1213 {
1214     Rlist *liststart = NULL;
1215     char node[CF_MAXVARSIZE];
1216     size_t start, end;
1217     int count = 0;
1218 
1219     assert(max > 0); // ensured by FnCallStringSplit() before calling us
1220     assert(string != NULL); // ensured by FnCallStringSplit() before calling us
1221 
1222     const char *sp = string;
1223     // We will avoid compiling regex multiple times.
1224     pcre *pattern = CompileRegex(regex);
1225 
1226     if (pattern == NULL)
1227     {
1228         Log(LOG_LEVEL_DEBUG, "Error compiling regex from '%s'", regex);
1229         return NULL;
1230     }
1231 
1232     while (count < max - 1 &&
1233            StringMatchWithPrecompiledRegex(pattern, sp, &start, &end))
1234     {
1235         size_t len = start;
1236         if (len >= CF_MAXVARSIZE)
1237         {
1238             len = CF_MAXVARSIZE - 1;
1239             Log(LOG_LEVEL_WARNING,
1240                 "Segment in string_split() is %zu bytes and will be truncated to %zu bytes",
1241                 start,
1242                 len);
1243         }
1244         memcpy(node, sp, len);
1245         node[len] = '\0';
1246         RlistAppendScalar(&liststart, node);
1247         count++;
1248 
1249         sp += end;
1250     }
1251 
1252     assert(count < max);
1253     RlistAppendScalar(&liststart, sp);
1254 
1255     pcre_free(pattern);
1256 
1257     return liststart;
1258 }
1259 
RlistLast(Rlist * start)1260 Rlist *RlistLast(Rlist *start)
1261 {
1262     if (start == NULL)
1263     {
1264         return NULL;
1265     }
1266     Rlist *rp = start;
1267     while (rp->next != NULL)
1268     {
1269         rp = rp->next;
1270     }
1271     return rp;
1272 }
1273 
RlistFilter(Rlist ** list,bool (* KeepPredicate)(void *,void *),void * predicate_user_data,void (* DestroyItem)(void *))1274 void RlistFilter(Rlist **list,
1275                  bool (*KeepPredicate)(void *, void *), void *predicate_user_data,
1276                  void (*DestroyItem)(void *))
1277 {
1278     assert(KeepPredicate);
1279     Rlist *start = *list, *prev = NULL, *next;
1280 
1281     for (Rlist *rp = start; rp; rp = next)
1282     {
1283         next = rp->next;
1284         if (KeepPredicate(RlistScalarValue(rp), predicate_user_data))
1285         {
1286             prev = rp;
1287         }
1288         else
1289         {
1290             if (prev)
1291             {
1292                 prev->next = next;
1293             }
1294             else
1295             {
1296                 assert(rp == *list);
1297                 *list = next;
1298             }
1299 
1300             if (DestroyItem)
1301             {
1302                 DestroyItem(rp->val.item);
1303                 rp->val.item = NULL;
1304             }
1305 
1306             rp->next = NULL;
1307             RlistDestroy(rp);
1308         }
1309     }
1310 }
1311 
RlistReverse(Rlist ** list)1312 void RlistReverse(Rlist **list)
1313 {
1314     Rlist *prev = NULL;
1315     while (*list)
1316     {
1317         Rlist *tmp = *list;
1318         *list = (*list)->next;
1319         tmp->next = prev;
1320         prev = tmp;
1321     }
1322     *list = prev;
1323 }
1324 
RlistWrite(Writer * writer,const Rlist * list)1325 void RlistWrite(Writer *writer, const Rlist *list)
1326 {
1327     WriterWrite(writer, " {");
1328 
1329     for (const Rlist *rp = list; rp != NULL; rp = rp->next)
1330     {
1331         RvalWriteQuoted(writer, rp->val);
1332 
1333         if (rp->next != NULL)
1334         {
1335             WriterWriteChar(writer, ',');
1336         }
1337     }
1338 
1339     WriterWriteChar(writer, '}');
1340 }
1341 
ScalarWrite(Writer * writer,const char * s,bool quote)1342 void ScalarWrite(Writer *writer, const char *s, bool quote)
1343 {
1344     if (quote)
1345     {
1346         WriterWriteChar(writer, '"');
1347     }
1348     for (; *s; s++)
1349     {
1350         if (*s == '"')
1351         {
1352             WriterWriteChar(writer, '\\');
1353         }
1354         WriterWriteChar(writer, *s);
1355     }
1356     if (quote)
1357     {
1358         WriterWriteChar(writer, '"');
1359     }
1360 }
1361 
RvalWriteParts(Writer * writer,const void * item,RvalType type,bool quote)1362 static void RvalWriteParts(Writer *writer, const void* item, RvalType type, bool quote)
1363 {
1364     if (item == NULL)
1365     {
1366         return;
1367     }
1368 
1369     switch (type)
1370     {
1371     case RVAL_TYPE_SCALAR:
1372         ScalarWrite(writer, item, quote);
1373         break;
1374 
1375     case RVAL_TYPE_LIST:
1376         RlistWrite(writer, item);
1377         break;
1378 
1379     case RVAL_TYPE_FNCALL:
1380         FnCallWrite(writer, item);
1381         break;
1382 
1383     case RVAL_TYPE_NOPROMISEE:
1384         WriterWrite(writer, "(no-one)");
1385         break;
1386 
1387     case RVAL_TYPE_CONTAINER:
1388         JsonWrite(writer, item, 0);
1389         break;
1390     }
1391 }
1392 
RvalWrite(Writer * writer,Rval rval)1393 void RvalWrite(Writer *writer, Rval rval)
1394 {
1395     RvalWriteParts(writer, rval.item, rval.type, false);
1396 }
1397 
RvalWriteQuoted(Writer * writer,Rval rval)1398 void RvalWriteQuoted(Writer *writer, Rval rval)
1399 {
1400     RvalWriteParts(writer, rval.item, rval.type, true);
1401 }
1402 
RvalToString(Rval rval)1403 char *RvalToString(Rval rval)
1404 {
1405     Writer *w = StringWriter();
1406     RvalWrite(w, rval);
1407     return StringWriterClose(w);
1408 }
1409 
RlistToString(const Rlist * rlist)1410 char *RlistToString(const Rlist *rlist)
1411 {
1412     Writer *w = StringWriter();
1413     RlistWrite(w, rlist);
1414     return StringWriterClose(w);
1415 }
1416 
RvalHash(Rval rval,unsigned seed)1417 unsigned RvalHash(Rval rval, unsigned seed)
1418 {
1419     switch (rval.type)
1420     {
1421     case RVAL_TYPE_SCALAR:
1422         return StringHash(RvalScalarValue(rval), seed);
1423     case RVAL_TYPE_FNCALL:
1424         return FnCallHash(RvalFnCallValue(rval), seed);
1425     case RVAL_TYPE_LIST:
1426         return RlistHash(RvalRlistValue(rval), seed);
1427     case RVAL_TYPE_NOPROMISEE:
1428         /* TODO modulus operation is biasing results. */
1429         return (seed + 1);
1430     default:
1431         ProgrammingError("Unhandled case in switch: %d", rval.type);
1432     }
1433 }
1434 
RlistHash(const Rlist * list,unsigned seed)1435 unsigned int RlistHash(const Rlist *list, unsigned seed)
1436 {
1437     unsigned hash = seed;
1438     for (const Rlist *rp = list; rp; rp = rp->next)
1439     {
1440         hash = RvalHash(rp->val, hash);
1441     }
1442     return hash;
1443 }
1444 
RlistHash_untyped(const void * list,unsigned seed)1445 unsigned int RlistHash_untyped(const void *list, unsigned seed)
1446 {
1447     return RlistHash(list, seed);
1448 }
1449 
1450 
FnCallToJson(const FnCall * fp)1451 static JsonElement *FnCallToJson(const FnCall *fp)
1452 {
1453     assert(fp);
1454 
1455     JsonElement *object = JsonObjectCreate(3);
1456 
1457     JsonObjectAppendString(object, "name", fp->name);
1458     JsonObjectAppendString(object, "type", "function-call");
1459 
1460     JsonElement *argsArray = JsonArrayCreate(5);
1461 
1462     for (Rlist *rp = fp->args; rp != NULL; rp = rp->next)
1463     {
1464         switch (rp->val.type)
1465         {
1466         case RVAL_TYPE_SCALAR:
1467             JsonArrayAppendString(argsArray, RlistScalarValue(rp));
1468             break;
1469 
1470         case RVAL_TYPE_FNCALL:
1471             JsonArrayAppendObject(argsArray, FnCallToJson(RlistFnCallValue(rp)));
1472             break;
1473 
1474         default:
1475             assert(false && "Unknown argument type");
1476             break;
1477         }
1478     }
1479     JsonObjectAppendArray(object, "arguments", argsArray);
1480 
1481     return object;
1482 }
1483 
RlistToJson(Rlist * list)1484 static JsonElement *RlistToJson(Rlist *list)
1485 {
1486     JsonElement *array = JsonArrayCreate(RlistLen(list));
1487 
1488     for (Rlist *rp = list; rp; rp = rp->next)
1489     {
1490         switch (rp->val.type)
1491         {
1492         case RVAL_TYPE_SCALAR:
1493             JsonArrayAppendString(array, RlistScalarValue(rp));
1494             break;
1495 
1496         case RVAL_TYPE_LIST:
1497             JsonArrayAppendArray(array, RlistToJson(RlistRlistValue(rp)));
1498             break;
1499 
1500         case RVAL_TYPE_FNCALL:
1501             JsonArrayAppendObject(array, FnCallToJson(RlistFnCallValue(rp)));
1502             break;
1503 
1504         default:
1505             ProgrammingError("Unsupported item type in rlist");
1506             break;
1507         }
1508     }
1509 
1510     return array;
1511 }
1512 
RvalToJson(Rval rval)1513 JsonElement *RvalToJson(Rval rval)
1514 {
1515     /* Only empty Rlist can be NULL. */
1516     assert(rval.item || rval.type == RVAL_TYPE_LIST);
1517 
1518     switch (rval.type)
1519     {
1520     case RVAL_TYPE_SCALAR:
1521         return JsonStringCreate(RvalScalarValue(rval));
1522     case RVAL_TYPE_LIST:
1523         return RlistToJson(RvalRlistValue(rval));
1524     case RVAL_TYPE_FNCALL:
1525         return FnCallToJson(RvalFnCallValue(rval));
1526     case RVAL_TYPE_CONTAINER:
1527         return JsonCopy(RvalContainerValue(rval));
1528     case RVAL_TYPE_NOPROMISEE:
1529         assert(false);
1530         return JsonObjectCreate(1);
1531     }
1532 
1533     assert(false);
1534     return NULL;
1535 }
1536 
1537 /**
1538  * @brief Flattens an Rlist by expanding naked scalar list-variable
1539  *        members. Flattening is only one-level deep.
1540  */
RlistFlatten(EvalContext * ctx,Rlist ** list)1541 void RlistFlatten(EvalContext *ctx, Rlist **list)
1542 {
1543     Rlist *next;
1544     for (Rlist *rp = *list; rp != NULL; rp = next)
1545     {
1546         next = rp->next;
1547 
1548         if (rp->val.type == RVAL_TYPE_SCALAR      &&
1549             IsNakedVar(RlistScalarValue(rp), '@'))
1550         {
1551             char naked[CF_MAXVARSIZE];
1552             GetNaked(naked, RlistScalarValue(rp));
1553 
1554             /* Make sure there are no inner expansions to take place, like if
1555              * rp was "@{blah_$(blue)}".  */
1556             if (!IsExpandable(naked))
1557             {
1558                 Log(LOG_LEVEL_DEBUG,
1559                     "Flattening slist: %s", RlistScalarValue(rp));
1560 
1561                 VarRef *ref = VarRefParse(naked);
1562                 DataType value_type;
1563                 const void *value = EvalContextVariableGet(ctx, ref, &value_type);
1564                 VarRefDestroy(ref);
1565 
1566                 if (value_type == CF_DATA_TYPE_NONE)
1567                 {
1568                     assert(value == NULL);
1569                     continue;                         /* undefined variable */
1570                 }
1571 
1572                 if (DataTypeToRvalType(value_type) != RVAL_TYPE_LIST)
1573                 {
1574                     Log(LOG_LEVEL_WARNING,
1575                         "'%s' failed - variable is not list but %s",
1576                         RlistScalarValue(rp), DataTypeToString(value_type));
1577                     continue;
1578                 }
1579 
1580                 /* NOTE: Remember that value can be NULL as an empty Rlist. */
1581 
1582                 /* at_node: just a mnemonic name for the
1583                             list node with @{blah}. */
1584                 Rlist *at_node      = rp;
1585                 Rlist *insert_after = at_node;
1586                 for (const Rlist *rp2 = value; rp2 != NULL; rp2 = rp2->next)
1587                 {
1588                     assert(insert_after != NULL);
1589 
1590                     RlistInsertAfter(insert_after, RvalCopy(rp2->val));
1591                     insert_after = insert_after->next;
1592                 }
1593 
1594                 /* Make sure we won't miss any element. */
1595                 assert(insert_after->next == next);
1596                 RlistDestroyEntry(list, at_node);   /* Delete @{blah} entry */
1597 
1598                 char *list_s = RlistToString(*list);
1599                 Log(LOG_LEVEL_DEBUG, "Flattened slist: %s", list_s);
1600                 free(list_s);
1601             }
1602         }
1603     }
1604 }
1605 
RlistEqual(const Rlist * list1,const Rlist * list2)1606 bool RlistEqual(const Rlist *list1, const Rlist *list2)
1607 {
1608     const Rlist *rp1, *rp2;
1609 
1610     for (rp1 = list1, rp2 = list2; rp1 != NULL && rp2 != NULL; rp1 = rp1->next, rp2 = rp2->next)
1611     {
1612         if (rp1->val.item != NULL &&
1613             rp2->val.item != NULL)
1614         {
1615             if (rp1->val.type == RVAL_TYPE_FNCALL || rp2->val.type == RVAL_TYPE_FNCALL)
1616             {
1617                 return false;      // inconclusive
1618             }
1619 
1620             const Rlist *rc1 = rp1;
1621             const Rlist *rc2 = rp2;
1622 
1623             // Check for list nesting with { fncall(), "x" ... }
1624 
1625             if (rp1->val.type == RVAL_TYPE_LIST)
1626             {
1627                 rc1 = rp1->val.item;
1628             }
1629 
1630             if (rp2->val.type == RVAL_TYPE_LIST)
1631             {
1632                 rc2 = rp2->val.item;
1633             }
1634 
1635             if (IsCf3VarString(rc1->val.item) || IsCf3VarString(rp2->val.item))
1636             {
1637                 return false;      // inconclusive
1638             }
1639 
1640             if (strcmp(rc1->val.item, rc2->val.item) != 0)
1641             {
1642                 return false;
1643             }
1644         }
1645         else if ((rp1->val.item != NULL && rp2->val.item == NULL) ||
1646                  (rp1->val.item == NULL && rp2->val.item != NULL))
1647         {
1648             return false;
1649         }
1650         else
1651         {
1652             assert(rp1->val.item == NULL && rp2->val.item == NULL);
1653         }
1654     }
1655 
1656     return true;
1657 }
1658 
RlistEqual_untyped(const void * list1,const void * list2)1659 bool RlistEqual_untyped(const void *list1, const void *list2)
1660 {
1661     return RlistEqual(list1, list2);
1662 }
1663 
1664 /*******************************************************************/
1665 
RlistAppendContainerPrimitive(Rlist ** list,const JsonElement * primitive)1666 static void RlistAppendContainerPrimitive(Rlist **list, const JsonElement *primitive)
1667 {
1668     assert(JsonGetElementType(primitive) == JSON_ELEMENT_TYPE_PRIMITIVE);
1669 
1670     switch (JsonGetPrimitiveType(primitive))
1671     {
1672     case JSON_PRIMITIVE_TYPE_BOOL:
1673         RlistAppendScalar(list, JsonPrimitiveGetAsBool(primitive) ? "true" : "false");
1674         break;
1675     case JSON_PRIMITIVE_TYPE_INTEGER:
1676         {
1677             char *str = StringFromLong(JsonPrimitiveGetAsInteger(primitive));
1678             RlistAppendScalar(list, str);
1679             free(str);
1680         }
1681         break;
1682     case JSON_PRIMITIVE_TYPE_REAL:
1683         {
1684             char *str = StringFromDouble(JsonPrimitiveGetAsReal(primitive));
1685             RlistAppendScalar(list, str);
1686             free(str);
1687         }
1688         break;
1689     case JSON_PRIMITIVE_TYPE_STRING:
1690         RlistAppendScalar(list, JsonPrimitiveGetAsString(primitive));
1691         break;
1692 
1693     case JSON_PRIMITIVE_TYPE_NULL:
1694         break;
1695     }
1696 }
1697 
RlistFromContainer(const JsonElement * container)1698 Rlist *RlistFromContainer(const JsonElement *container)
1699 {
1700     Rlist *list = NULL;
1701 
1702     switch (JsonGetElementType(container))
1703     {
1704     case JSON_ELEMENT_TYPE_PRIMITIVE:
1705         RlistAppendContainerPrimitive(&list, container);
1706         break;
1707 
1708     case JSON_ELEMENT_TYPE_CONTAINER:
1709         {
1710             JsonIterator iter = JsonIteratorInit(container);
1711             const JsonElement *child;
1712 
1713             while (NULL != (child = JsonIteratorNextValue(&iter)))
1714             {
1715                 if (JsonGetElementType(child) == JSON_ELEMENT_TYPE_PRIMITIVE)
1716                 {
1717                     RlistAppendContainerPrimitive(&list, child);
1718                 }
1719             }
1720         }
1721         break;
1722     }
1723 
1724     return list;
1725 }
1726