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