Imported Upstream version 1.8.0
[platform/upstream/augeas.git] / src / builtin.c
1 /*
2  * builtin.c: builtin primitives
3  *
4  * Copyright (C) 2007-2016 David Lutterkort
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
19  *
20  * Author: David Lutterkort <dlutter@redhat.com>
21  */
22
23 #include <config.h>
24 #include <stdio.h>
25 #include <stdarg.h>
26 #include <errno.h>
27 #include <stdlib.h>
28
29 #include "syntax.h"
30 #include "memory.h"
31 #include "transform.h"
32 #include "errcode.h"
33
34 #define UNIMPL_BODY(name)                       \
35     {                                           \
36         FIXME(#name " called");                 \
37         abort();                                \
38     }
39
40 /*
41  * Lenses
42  */
43
44 /* V_REGEXP -> V_STRING -> V_LENS */
45 static struct value *lns_del(struct info *info,
46                              struct value *rxp, struct value *dflt) {
47     assert(rxp->tag == V_REGEXP);
48     assert(dflt->tag == V_STRING);
49     return lns_make_prim(L_DEL, ref(info),
50                          ref(rxp->regexp), ref(dflt->string));
51 }
52
53 /* V_REGEXP -> V_LENS */
54 static struct value *lns_store(struct info *info, struct value *rxp) {
55     assert(rxp->tag == V_REGEXP);
56     return lns_make_prim(L_STORE, ref(info), ref(rxp->regexp), NULL);
57 }
58
59 /* V_STRING -> V_LENS */
60 static struct value *lns_value(struct info *info, struct value *str) {
61     assert(str->tag == V_STRING);
62     return lns_make_prim(L_VALUE, ref(info), NULL, ref(str->string));
63 }
64
65 /* V_REGEXP -> V_LENS */
66 static struct value *lns_key(struct info *info, struct value *rxp) {
67     assert(rxp->tag == V_REGEXP);
68     return lns_make_prim(L_KEY, ref(info), ref(rxp->regexp), NULL);
69 }
70
71 /* V_STRING -> V_LENS */
72 static struct value *lns_label(struct info *info, struct value *str) {
73     assert(str->tag == V_STRING);
74     return lns_make_prim(L_LABEL, ref(info), NULL, ref(str->string));
75 }
76
77 /* V_STRING -> V_LENS */
78 static struct value *lns_seq(struct info *info, struct value *str) {
79     assert(str->tag == V_STRING);
80     return lns_make_prim(L_SEQ, ref(info), NULL, ref(str->string));
81 }
82
83 /* V_STRING -> V_LENS */
84 static struct value *lns_counter(struct info *info, struct value *str) {
85     assert(str->tag == V_STRING);
86     return lns_make_prim(L_COUNTER, ref(info), NULL, ref(str->string));
87 }
88
89 /* V_LENS -> V_LENS -> V_LENS -> V_LENS */
90 static struct value *lns_square(struct info *info, struct value *l1,
91                                 struct value *l2, struct value *l3) {
92     assert(l1->tag == V_LENS);
93     assert(l2->tag == V_LENS);
94     assert(l3->tag == V_LENS);
95     int check = info->error->aug->flags & AUG_TYPE_CHECK;
96
97     return lns_make_square(ref(info), ref(l1->lens), ref(l2->lens), ref(l3->lens), check);
98 }
99
100 static void exn_lns_error_detail(struct value *exn, const char *label,
101                                  struct lens *lens) {
102     if (lens == NULL)
103         return;
104
105     char *s = format_info(lens->info);
106     exn_printf_line(exn, "%s: %s", label, s);
107     free(s);
108 }
109
110 static struct value *make_exn_lns_error(struct info *info,
111                                         struct lns_error *err,
112                                         const char *text) {
113     struct value *v;
114
115     if (HAS_ERR(info))
116         return info->error->exn;
117
118     v = make_exn_value(ref(info), "%s", err->message);
119     exn_lns_error_detail(v, "Lens", err->lens);
120     exn_lns_error_detail(v, "  Last match", err->last);
121     exn_lns_error_detail(v, "  Not matching", err->next);
122     if (err->pos >= 0) {
123         char *pos = format_pos(text, err->pos);
124         size_t line, ofs;
125         calc_line_ofs(text, err->pos, &line, &ofs);
126         exn_printf_line(v,
127                      "Error encountered at %d:%d (%d characters into string)",
128                         (int) line, (int) ofs, err->pos);
129         if (pos != NULL)
130             exn_printf_line(v, "%s", pos);
131         free(pos);
132     } else {
133         exn_printf_line(v, "Error encountered at path %s", err->path);
134     }
135
136     return v;
137 }
138
139 static void exn_print_tree(struct value *exn, struct tree *tree) {
140     struct memstream ms;
141
142     init_memstream(&ms);
143     dump_tree(ms.stream, tree);
144     close_memstream(&ms);
145     exn_printf_line(exn, "%s", ms.buf);
146     FREE(ms.buf);
147 }
148
149 static struct value *make_pathx_exn(struct info *info, struct pathx *p) {
150     struct value *v;
151     char *msg;
152     const char *txt, *px_err;
153     int pos;
154
155     px_err = pathx_error(p, &txt, &pos);
156     v = make_exn_value(ref(info), "syntax error in path expression: %s",
157                        px_err);
158
159     if (ALLOC_N(msg, strlen(txt) + 4) >= 0) {
160         strncpy(msg, txt, pos);
161         strcat(msg, "|=|");
162         strcat(msg, txt + pos);
163         exn_add_lines(v, 1, msg);
164     }
165     return v;
166 }
167
168 static struct value *pathx_parse_glue(struct info *info, struct value *tree,
169                                       struct value *path, struct pathx **p) {
170     assert(path->tag == V_STRING);
171     assert(tree->tag == V_TREE);
172
173     if (pathx_parse(tree->origin, info->error, path->string->str, true,
174                     NULL, NULL, p) != PATHX_NOERROR) {
175         return make_pathx_exn(info, *p);
176     } else {
177         return NULL;
178     }
179 }
180
181 /* V_LENS -> V_STRING -> V_TREE */
182 static struct value *lens_get(struct info *info, struct value *l,
183                               struct value *str) {
184     assert(l->tag == V_LENS);
185     assert(str->tag == V_STRING);
186     struct lns_error *err;
187     struct value *v;
188     const char *text = str->string->str;
189
190     struct tree *tree = lns_get(info, l->lens, text, &err);
191     if (err == NULL && ! HAS_ERR(info)) {
192         v = make_value(V_TREE, ref(info));
193         v->origin = make_tree_origin(tree);
194     } else {
195         struct tree *t = make_tree_origin(tree);
196         if (t == NULL)
197             free_tree(tree);
198         tree = t;
199
200         v = make_exn_lns_error(info, err, text);
201         if (tree != NULL) {
202             exn_printf_line(v, "Tree generated so far:");
203             exn_print_tree(v, tree);
204             free_tree(tree);
205         }
206         free_lns_error(err);
207     }
208     return v;
209 }
210
211
212 /* V_LENS -> V_TREE -> V_STRING -> V_STRING */
213 static struct value *lens_put(struct info *info, struct value *l,
214                               struct value *tree, struct value *str) {
215     assert(l->tag == V_LENS);
216     assert(tree->tag == V_TREE);
217     assert(str->tag == V_STRING);
218
219     struct memstream ms;
220     struct value *v;
221     struct lns_error *err;
222
223     init_memstream(&ms);
224     lns_put(ms.stream, l->lens, tree->origin->children,
225             str->string->str, &err);
226     close_memstream(&ms);
227
228     if (err == NULL && ! HAS_ERR(info)) {
229         v = make_value(V_STRING, ref(info));
230         v->string = make_string(ms.buf);
231     } else {
232         v = make_exn_lns_error(info, err, str->string->str);
233         free_lns_error(err);
234         FREE(ms.buf);
235     }
236     return v;
237 }
238
239 /* V_STRING -> V_STRING -> V_TREE -> V_TREE */
240 static struct value *tree_set_glue(struct info *info, struct value *path,
241                                    struct value *val, struct value *tree) {
242     // FIXME: This only works if TREE is not referenced more than once;
243     // otherwise we'll have some pretty weird semantics, and would really
244     // need to copy TREE first
245     assert(path->tag == V_STRING);
246     assert(val->tag == V_STRING);
247     assert(tree->tag == V_TREE);
248
249     struct tree *fake = NULL;
250     struct pathx *p = NULL;
251     struct value *result = NULL;
252
253     if (tree->origin->children == NULL) {
254         tree->origin->children = make_tree(NULL, NULL, tree->origin, NULL);
255         fake = tree->origin->children;
256     }
257
258     result = pathx_parse_glue(info, tree, path, &p);
259     if (result != NULL)
260         goto done;
261
262     if (tree_set(p, val->string->str) == NULL) {
263         result = make_exn_value(ref(info),
264                                 "Tree set of %s to '%s' failed",
265                                 path->string->str, val->string->str);
266         goto done;
267     }
268     if (fake != NULL) {
269         list_remove(fake, tree->origin->children);
270         free_tree(fake);
271     }
272     result = ref(tree);
273
274  done:
275     free_pathx(p);
276     return result;
277 }
278
279 /* V_STRING -> V_TREE -> V_TREE */
280 static struct value *tree_clear_glue(struct info *info, struct value *path,
281                                      struct value *tree) {
282     // FIXME: This only works if TREE is not referenced more than once;
283     // otherwise we'll have some pretty weird semantics, and would really
284     // need to copy TREE first
285     assert(path->tag == V_STRING);
286     assert(tree->tag == V_TREE);
287
288     struct tree *fake = NULL;
289     struct pathx *p = NULL;
290     struct value *result = NULL;
291
292     if (tree->origin->children == NULL) {
293         tree->origin->children = make_tree(NULL, NULL, tree->origin, NULL);
294         fake = tree->origin->children;
295     }
296
297     result = pathx_parse_glue(info, tree, path, &p);
298     if (result != NULL)
299         goto done;
300
301     if (tree_set(p, NULL) == NULL) {
302         result = make_exn_value(ref(info),
303                                 "Tree set of %s to NULL failed",
304                                 path->string->str);
305         goto done;
306     }
307     if (fake != NULL) {
308         list_remove(fake, tree->origin->children);
309         free_tree(fake);
310     }
311     result = ref(tree);
312
313  done:
314     free_pathx(p);
315     return result;
316 }
317
318 static struct value *tree_insert_glue(struct info *info, struct value *label,
319                                       struct value *path, struct value *tree,
320                                       int before) {
321     // FIXME: This only works if TREE is not referenced more than once;
322     // otherwise we'll have some pretty weird semantics, and would really
323     // need to copy TREE first
324     assert(label->tag == V_STRING);
325     assert(path->tag == V_STRING);
326     assert(tree->tag == V_TREE);
327
328     int r;
329     struct pathx *p = NULL;
330     struct value *result = NULL;
331
332     result = pathx_parse_glue(info, tree, path, &p);
333     if (result != NULL)
334         goto done;
335
336     r = tree_insert(p, label->string->str, before);
337     if (r != 0) {
338         result = make_exn_value(ref(info),
339                                 "Tree insert of %s at %s failed",
340                                 label->string->str, path->string->str);
341         goto done;
342     }
343
344     result = ref(tree);
345  done:
346     free_pathx(p);
347     return result;
348 }
349
350 /* Insert after */
351 /* V_STRING -> V_STRING -> V_TREE -> V_TREE */
352 static struct value *tree_insa_glue(struct info *info, struct value *label,
353                                     struct value *path, struct value *tree) {
354     return tree_insert_glue(info, label, path, tree, 0);
355 }
356
357 /* Insert before */
358 /* V_STRING -> V_STRING -> V_TREE -> V_TREE */
359 static struct value *tree_insb_glue(struct info *info, struct value *label,
360                                     struct value *path, struct value *tree) {
361     return tree_insert_glue(info, label, path, tree, 1);
362 }
363
364 /* V_STRING -> V_TREE -> V_TREE */
365 static struct value *tree_rm_glue(struct info *info,
366                                   struct value *path,
367                                   struct value *tree) {
368     // FIXME: This only works if TREE is not referenced more than once;
369     // otherwise we'll have some pretty weird semantics, and would really
370     // need to copy TREE first
371     assert(path->tag == V_STRING);
372     assert(tree->tag == V_TREE);
373
374     struct pathx *p = NULL;
375     struct value *result = NULL;
376
377     result = pathx_parse_glue(info, tree, path, &p);
378     if (result != NULL)
379         goto done;
380
381     if (tree_rm(p) == -1) {
382         result = make_exn_value(ref(info), "Tree rm of %s failed",
383                                 path->string->str);
384         goto done;
385     }
386     result = ref(tree);
387  done:
388     free_pathx(p);
389     return result;
390 }
391
392 /* V_STRING -> V_STRING */
393 static struct value *gensym(struct info *info, struct value *prefix) {
394     assert(prefix->tag == V_STRING);
395     static unsigned int count = 0;
396     struct value *v;
397     char *s;
398     int r;
399
400     r = asprintf(&s, "%s%u", prefix->string->str, count);
401     if (r == -1)
402         return NULL;
403     v = make_value(V_STRING, ref(info));
404     v->string = make_string(s);
405     return v;
406 }
407
408 /* V_STRING -> V_FILTER */
409 static struct value *xform_incl(struct info *info, struct value *s) {
410     assert(s->tag == V_STRING);
411     struct value *v = make_value(V_FILTER, ref(info));
412     v->filter = make_filter(ref(s->string), 1);
413     return v;
414 }
415
416 /* V_STRING -> V_FILTER */
417 static struct value *xform_excl(struct info *info, struct value *s) {
418     assert(s->tag == V_STRING);
419     struct value *v = make_value(V_FILTER, ref(info));
420     v->filter = make_filter(ref(s->string), 0);
421     return v;
422 }
423
424 /* V_LENS -> V_FILTER -> V_TRANSFORM */
425 static struct value *xform_transform(struct info *info, struct value *l,
426                                      struct value *f) {
427     assert(l->tag == V_LENS);
428     assert(f->tag == V_FILTER);
429     if (l->lens->value || l->lens->key) {
430         return make_exn_value(ref(info), "Can not build a transform "
431                               "from a lens that leaves a %s behind",
432                               l->lens->key ? "key" : "value");
433     }
434     struct value *v = make_value(V_TRANSFORM, ref(info));
435     v->transform = make_transform(ref(l->lens), ref(f->filter));
436     return v;
437 }
438
439 static struct value *sys_getenv(struct info *info, struct value *n) {
440     assert(n->tag == V_STRING);
441     struct value *v = make_value(V_STRING, ref(info));
442     v->string = dup_string(getenv(n->string->str));
443     return v;
444 }
445
446 static struct value *sys_read_file(struct info *info, struct value *n) {
447     assert(n->tag == V_STRING);
448     char *str = NULL;
449
450     str = xread_file(n->string->str);
451     if (str == NULL) {
452         char error_buf[1024];
453         const char *errmsg;
454         errmsg = xstrerror(errno, error_buf, sizeof(error_buf));
455         struct value *exn = make_exn_value(ref(info),
456              "reading file %s failed:", n->string->str);
457         exn_printf_line(exn, "%s", errmsg);
458         return exn;
459     }
460     struct value *v = make_value(V_STRING, ref(info));
461     v->string = make_string(str);
462     return v;
463 }
464
465 /* V_LENS -> V_LENS */
466 static struct value *lns_check_rec_glue(struct info *info,
467                                         struct value *l, struct value *r) {
468     assert(l->tag == V_LENS);
469     assert(r->tag == V_LENS);
470     int check = info->error->aug->flags & AUG_TYPE_CHECK;
471
472     return lns_check_rec(info, l->lens, r->lens, check);
473 }
474
475 /*
476  * Print functions
477  */
478
479 /* V_STRING -> V_UNIT */
480 static struct value *pr_string(struct info *info, struct value *s) {
481     printf("%s", s->string->str);
482     return make_unit(ref(info));
483 }
484
485 /* V_REGEXP -> V_UNIT */
486 static struct value *pr_regexp(struct info *info, struct value *r) {
487     print_regexp(stdout, r->regexp);
488     return make_unit(ref(info));
489 }
490
491 /* V_STRING -> V_UNIT */
492 static struct value *pr_endline(struct info *info, struct value *s) {
493     printf("%s\n", s->string->str);
494     return make_unit(ref(info));
495 }
496
497 /* V_TREE -> V_TREE */
498 static struct value *pr_tree(ATTRIBUTE_UNUSED struct info *info,
499                              struct value *t) {
500     print_tree_braces(stdout, 0, t->origin);
501     return ref(t);
502 }
503
504 /*
505  * Lens inspection
506  */
507
508 static struct value *lns_value_of_type(struct info *info, struct regexp *rx) {
509     struct value *result = make_value(V_REGEXP, ref(info));
510     if (rx)
511         result->regexp = ref(rx);
512     else
513         result->regexp = regexp_make_empty(ref(info));
514     return result;
515 }
516
517 /* V_LENS -> V_REGEXP */
518 static struct value *lns_ctype(struct info *info, struct value *l) {
519     return lns_value_of_type(info, l->lens->ctype);
520 }
521
522 /* V_LENS -> V_REGEXP */
523 static struct value *lns_atype(struct info *info, struct value *l) {
524     return lns_value_of_type(info, l->lens->atype);
525 }
526
527 /* V_LENS -> V_REGEXP */
528 static struct value *lns_vtype(struct info *info, struct value *l) {
529     return lns_value_of_type(info, l->lens->vtype);
530 }
531
532 /* V_LENS -> V_REGEXP */
533 static struct value *lns_ktype(struct info *info, struct value *l) {
534     return lns_value_of_type(info, l->lens->ktype);
535 }
536
537 /* V_LENS -> V_STRING */
538 static struct value *lns_fmt_atype(struct info *info, struct value *l) {
539     struct value *result = NULL;
540     char *s = NULL;
541     int r;
542
543     r = lns_format_atype(l->lens, &s);
544     if (r < 0)
545         return info->error->exn;
546     result = make_value(V_STRING, ref(info));
547     result->string = make_string(s);
548     return result;
549 }
550
551 /* V_REGEXP -> V_STRING -> V_STRING */
552 static struct value *rx_match(struct info *info,
553                               struct value *rx, struct value *s) {
554     struct value *result = NULL;
555     const char *str = s->string->str;
556     struct re_registers regs;
557     int r;
558
559     MEMZERO(&regs, 1);
560     r = regexp_match(rx->regexp, str, strlen(str), 0, &regs);
561     if (r < -1) {
562         result =
563             make_exn_value(ref(info), "regexp match failed (internal error)");
564     } else {
565         char *match = NULL;
566         if (r == -1) {
567             /* No match */
568             match = strdup("");
569         } else {
570             match = strndup(str + regs.start[0], regs.end[0] - regs.start[0]);
571         }
572         if (match == NULL) {
573             result = info->error->exn;
574         } else {
575             result = make_value(V_STRING, ref(info));
576             result->string = make_string(match);
577         }
578     }
579     return result;
580 }
581
582 struct module *builtin_init(struct error *error) {
583     struct module *modl = module_create("Builtin");
584     int r;
585
586 #define DEFINE_NATIVE(modl, name, nargs, impl, types ...)               \
587     r = define_native(error, modl, name, nargs, impl, ##types);         \
588     if (r < 0) goto error;
589
590     DEFINE_NATIVE(modl, "gensym", 1, gensym, T_STRING, T_STRING);
591
592     /* Primitive lenses */
593     DEFINE_NATIVE(modl, "del",     2, lns_del, T_REGEXP, T_STRING, T_LENS);
594     DEFINE_NATIVE(modl, "store",   1, lns_store, T_REGEXP, T_LENS);
595     DEFINE_NATIVE(modl, "value",   1, lns_value, T_STRING, T_LENS);
596     DEFINE_NATIVE(modl, "key",     1, lns_key, T_REGEXP, T_LENS);
597     DEFINE_NATIVE(modl, "label",   1, lns_label, T_STRING, T_LENS);
598     DEFINE_NATIVE(modl, "seq",     1, lns_seq, T_STRING, T_LENS);
599     DEFINE_NATIVE(modl, "counter", 1, lns_counter, T_STRING, T_LENS);
600     DEFINE_NATIVE(modl, "square",  3, lns_square, T_LENS, T_LENS, T_LENS, T_LENS);
601     /* Applying lenses (mostly for tests) */
602     DEFINE_NATIVE(modl, "get",     2, lens_get, T_LENS, T_STRING, T_TREE);
603     DEFINE_NATIVE(modl, "put",     3, lens_put, T_LENS, T_TREE, T_STRING,
604                   T_STRING);
605     /* Tree manipulation used by the PUT tests */
606     DEFINE_NATIVE(modl, "set", 3, tree_set_glue, T_STRING, T_STRING, T_TREE,
607                                                  T_TREE);
608     DEFINE_NATIVE(modl, "clear", 2, tree_clear_glue, T_STRING, T_TREE,
609                                                  T_TREE);
610     DEFINE_NATIVE(modl, "rm", 2, tree_rm_glue, T_STRING, T_TREE, T_TREE);
611     DEFINE_NATIVE(modl, "insa", 3, tree_insa_glue, T_STRING, T_STRING, T_TREE,
612                                                    T_TREE);
613     DEFINE_NATIVE(modl, "insb", 3, tree_insb_glue, T_STRING, T_STRING, T_TREE,
614                                                    T_TREE);
615     /* Transforms and filters */
616     DEFINE_NATIVE(modl, "incl", 1, xform_incl, T_STRING, T_FILTER);
617     DEFINE_NATIVE(modl, "excl", 1, xform_excl, T_STRING, T_FILTER);
618     DEFINE_NATIVE(modl, "transform", 2, xform_transform, T_LENS, T_FILTER,
619                                                          T_TRANSFORM);
620     DEFINE_NATIVE(modl, LNS_CHECK_REC_NAME,
621                   2, lns_check_rec_glue, T_LENS, T_LENS, T_LENS);
622     /* Printing */
623     DEFINE_NATIVE(modl, "print_string", 1, pr_string, T_STRING, T_UNIT);
624     DEFINE_NATIVE(modl, "print_regexp", 1, pr_regexp, T_REGEXP, T_UNIT);
625     DEFINE_NATIVE(modl, "print_endline", 1, pr_endline, T_STRING, T_UNIT);
626     DEFINE_NATIVE(modl, "print_tree", 1, pr_tree, T_TREE, T_TREE);
627
628     /* Lens inspection */
629     DEFINE_NATIVE(modl, "lens_ctype", 1, lns_ctype, T_LENS, T_REGEXP);
630     DEFINE_NATIVE(modl, "lens_atype", 1, lns_atype, T_LENS, T_REGEXP);
631     DEFINE_NATIVE(modl, "lens_vtype", 1, lns_vtype, T_LENS, T_REGEXP);
632     DEFINE_NATIVE(modl, "lens_ktype", 1, lns_ktype, T_LENS, T_REGEXP);
633     DEFINE_NATIVE(modl, "lens_format_atype", 1, lns_fmt_atype,
634                   T_LENS, T_STRING);
635
636     /* Regexp matching */
637     DEFINE_NATIVE(modl, "regexp_match", 2, rx_match, T_REGEXP, T_STRING,
638                   T_STRING);
639
640     /* System functions */
641     struct module *sys = module_create("Sys");
642     modl->next = sys;
643     DEFINE_NATIVE(sys, "getenv", 1, sys_getenv, T_STRING, T_STRING);
644     DEFINE_NATIVE(sys, "read_file", 1, sys_read_file, T_STRING, T_STRING);
645     return modl;
646  error:
647     unref(modl, module);
648     return NULL;
649 }
650
651 /*
652  * Local variables:
653  *  indent-tabs-mode: nil
654  *  c-indent-level: 4
655  *  c-basic-offset: 4
656  *  tab-width: 4
657  * End:
658  */