cfengine  3.15.4
About: CFEngine is a configuration management system for configuring and maintaining Unix-like computers (using an own high level policy language). Community version.
  Fossies Dox: cfengine-3.15.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

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