Imported Upstream version 1.5.0
[platform/upstream/augeas.git] / src / builtin.c
1 /*
2  * builtin.c: builtin primitives
3  *
4  * Copyright (C) 2007-2015 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;
153     int pos;
154
155     msg = strdup(pathx_error(p, &txt, &pos));
156     if (msg == NULL)
157         return NULL;
158
159     v = make_exn_value(ref(info), "syntax error in path expression: %s", msg);
160     if (ALLOC_N(msg, strlen(txt) + 4) >= 0) {
161         strncpy(msg, txt, pos);
162         strcat(msg, "|=|");
163         strcat(msg, txt + pos);
164         exn_add_lines(v, 1, msg);
165     }
166     return v;
167 }
168
169 static struct value *pathx_parse_glue(struct info *info, struct value *tree,
170                                       struct value *path, struct pathx **p) {
171     assert(path->tag == V_STRING);
172     assert(tree->tag == V_TREE);
173
174     if (pathx_parse(tree->origin, info->error, path->string->str, true,
175                     NULL, NULL, p) != PATHX_NOERROR) {
176         return make_pathx_exn(ref(info), *p);
177     } else {
178         return NULL;
179     }
180 }
181
182 /* V_LENS -> V_STRING -> V_TREE */
183 static struct value *lens_get(struct info *info, struct value *l,
184                               struct value *str) {
185     assert(l->tag == V_LENS);
186     assert(str->tag == V_STRING);
187     struct lns_error *err;
188     struct value *v;
189     const char *text = str->string->str;
190
191     struct tree *tree = lns_get(info, l->lens, text, &err);
192     if (err == NULL && ! HAS_ERR(info)) {
193         v = make_value(V_TREE, ref(info));
194         v->origin = make_tree_origin(tree);
195     } else {
196         struct tree *t = make_tree_origin(tree);
197         if (t == NULL)
198             free_tree(tree);
199         tree = t;
200
201         v = make_exn_lns_error(info, err, text);
202         if (tree != NULL) {
203             exn_printf_line(v, "Tree generated so far:");
204             exn_print_tree(v, tree);
205             free_tree(tree);
206         }
207         free_lns_error(err);
208     }
209     return v;
210 }
211
212
213 /* V_LENS -> V_TREE -> V_STRING -> V_STRING */
214 static struct value *lens_put(struct info *info, struct value *l,
215                               struct value *tree, struct value *str) {
216     assert(l->tag == V_LENS);
217     assert(tree->tag == V_TREE);
218     assert(str->tag == V_STRING);
219
220     struct memstream ms;
221     struct value *v;
222     struct lns_error *err;
223
224     init_memstream(&ms);
225     lns_put(ms.stream, l->lens, tree->origin->children,
226             str->string->str, &err);
227     close_memstream(&ms);
228
229     if (err == NULL && ! HAS_ERR(info)) {
230         v = make_value(V_STRING, ref(info));
231         v->string = make_string(ms.buf);
232     } else {
233         v = make_exn_lns_error(info, err, str->string->str);
234         free_lns_error(err);
235         FREE(ms.buf);
236     }
237     return v;
238 }
239
240 /* V_STRING -> V_STRING -> V_TREE -> V_TREE */
241 static struct value *tree_set_glue(struct info *info, struct value *path,
242                                    struct value *val, struct value *tree) {
243     // FIXME: This only works if TREE is not referenced more than once;
244     // otherwise we'll have some pretty weird semantics, and would really
245     // need to copy TREE first
246     assert(path->tag == V_STRING);
247     assert(val->tag == V_STRING);
248     assert(tree->tag == V_TREE);
249
250     struct tree *fake = NULL;
251     struct pathx *p = NULL;
252     struct value *result = NULL;
253
254     if (tree->origin->children == NULL) {
255         tree->origin->children = make_tree(NULL, NULL, tree->origin, NULL);
256         fake = tree->origin->children;
257     }
258
259     result = pathx_parse_glue(info, tree, path, &p);
260     if (result != NULL)
261         goto done;
262
263     if (tree_set(p, val->string->str) == NULL) {
264         result = make_exn_value(ref(info),
265                                 "Tree set of %s to '%s' failed",
266                                 path->string->str, val->string->str);
267         goto done;
268     }
269     if (fake != NULL) {
270         list_remove(fake, tree->origin->children);
271         free_tree(fake);
272     }
273     result = ref(tree);
274
275  done:
276     free_pathx(p);
277     return result;
278 }
279
280 /* V_STRING -> V_TREE -> V_TREE */
281 static struct value *tree_clear_glue(struct info *info, struct value *path,
282                                      struct value *tree) {
283     // FIXME: This only works if TREE is not referenced more than once;
284     // otherwise we'll have some pretty weird semantics, and would really
285     // need to copy TREE first
286     assert(path->tag == V_STRING);
287     assert(tree->tag == V_TREE);
288
289     struct tree *fake = NULL;
290     struct pathx *p = NULL;
291     struct value *result = NULL;
292
293     if (tree->origin->children == NULL) {
294         tree->origin->children = make_tree(NULL, NULL, tree->origin, NULL);
295         fake = tree->origin->children;
296     }
297
298     result = pathx_parse_glue(info, tree, path, &p);
299     if (result != NULL)
300         goto done;
301
302     if (tree_set(p, NULL) == NULL) {
303         result = make_exn_value(ref(info),
304                                 "Tree set of %s to NULL failed",
305                                 path->string->str);
306         goto done;
307     }
308     if (fake != NULL) {
309         list_remove(fake, tree->origin->children);
310         free_tree(fake);
311     }
312     result = ref(tree);
313
314  done:
315     free_pathx(p);
316     return result;
317 }
318
319 static struct value *tree_insert_glue(struct info *info, struct value *label,
320                                       struct value *path, struct value *tree,
321                                       int before) {
322     // FIXME: This only works if TREE is not referenced more than once;
323     // otherwise we'll have some pretty weird semantics, and would really
324     // need to copy TREE first
325     assert(label->tag == V_STRING);
326     assert(path->tag == V_STRING);
327     assert(tree->tag == V_TREE);
328
329     int r;
330     struct pathx *p = NULL;
331     struct value *result = NULL;
332
333     result = pathx_parse_glue(info, tree, path, &p);
334     if (result != NULL)
335         goto done;
336
337     r = tree_insert(p, label->string->str, before);
338     if (r != 0) {
339         result = make_exn_value(ref(info),
340                                 "Tree insert of %s at %s failed",
341                                 label->string->str, path->string->str);
342         goto done;
343     }
344
345     result = ref(tree);
346  done:
347     free_pathx(p);
348     return result;
349 }
350
351 /* Insert after */
352 /* V_STRING -> V_STRING -> V_TREE -> V_TREE */
353 static struct value *tree_insa_glue(struct info *info, struct value *label,
354                                     struct value *path, struct value *tree) {
355     return tree_insert_glue(info, label, path, tree, 0);
356 }
357
358 /* Insert before */
359 /* V_STRING -> V_STRING -> V_TREE -> V_TREE */
360 static struct value *tree_insb_glue(struct info *info, struct value *label,
361                                     struct value *path, struct value *tree) {
362     return tree_insert_glue(info, label, path, tree, 1);
363 }
364
365 /* V_STRING -> V_TREE -> V_TREE */
366 static struct value *tree_rm_glue(struct info *info,
367                                   struct value *path,
368                                   struct value *tree) {
369     // FIXME: This only works if TREE is not referenced more than once;
370     // otherwise we'll have some pretty weird semantics, and would really
371     // need to copy TREE first
372     assert(path->tag == V_STRING);
373     assert(tree->tag == V_TREE);
374
375     struct pathx *p = NULL;
376     struct value *result = NULL;
377
378     result = pathx_parse_glue(info, tree, path, &p);
379     if (result != NULL)
380         goto done;
381
382     if (tree_rm(p) == -1) {
383         result = make_exn_value(ref(info), "Tree rm of %s failed",
384                                 path->string->str);
385         goto done;
386     }
387     result = ref(tree);
388  done:
389     free_pathx(p);
390     return result;
391 }
392
393 /* V_STRING -> V_STRING */
394 static struct value *gensym(struct info *info, struct value *prefix) {
395     assert(prefix->tag == V_STRING);
396     static unsigned int count = 0;
397     struct value *v;
398     char *s;
399     int r;
400
401     r = asprintf(&s, "%s%u", prefix->string->str, count);
402     if (r == -1)
403         return NULL;
404     v = make_value(V_STRING, ref(info));
405     v->string = make_string(s);
406     return v;
407 }
408
409 /* V_STRING -> V_FILTER */
410 static struct value *xform_incl(struct info *info, struct value *s) {
411     assert(s->tag == V_STRING);
412     struct value *v = make_value(V_FILTER, ref(info));
413     v->filter = make_filter(ref(s->string), 1);
414     return v;
415 }
416
417 /* V_STRING -> V_FILTER */
418 static struct value *xform_excl(struct info *info, struct value *s) {
419     assert(s->tag == V_STRING);
420     struct value *v = make_value(V_FILTER, ref(info));
421     v->filter = make_filter(ref(s->string), 0);
422     return v;
423 }
424
425 /* V_LENS -> V_FILTER -> V_TRANSFORM */
426 static struct value *xform_transform(struct info *info, struct value *l,
427                                      struct value *f) {
428     assert(l->tag == V_LENS);
429     assert(f->tag == V_FILTER);
430     if (l->lens->value || l->lens->key) {
431         return make_exn_value(ref(info), "Can not build a transform "
432                               "from a lens that leaves a %s behind",
433                               l->lens->key ? "key" : "value");
434     }
435     struct value *v = make_value(V_TRANSFORM, ref(info));
436     v->transform = make_transform(ref(l->lens), ref(f->filter));
437     return v;
438 }
439
440 static struct value *sys_getenv(struct info *info, struct value *n) {
441     assert(n->tag == V_STRING);
442     struct value *v = make_value(V_STRING, ref(info));
443     v->string = dup_string(getenv(n->string->str));
444     return v;
445 }
446
447 static struct value *sys_read_file(struct info *info, struct value *n) {
448     assert(n->tag == V_STRING);
449     char *str = NULL;
450
451     str = xread_file(n->string->str);
452     if (str == NULL) {
453         char error_buf[1024];
454         const char *errmsg;
455         errmsg = xstrerror(errno, error_buf, sizeof(error_buf));
456         struct value *exn = make_exn_value(ref(info),
457              "reading file %s failed:", n->string->str);
458         exn_printf_line(exn, "%s", errmsg);
459         return exn;
460     }
461     struct value *v = make_value(V_STRING, ref(info));
462     v->string = make_string(str);
463     return v;
464 }
465
466 /* V_LENS -> V_LENS */
467 static struct value *lns_check_rec_glue(struct info *info,
468                                         struct value *l, struct value *r) {
469     assert(l->tag == V_LENS);
470     assert(r->tag == V_LENS);
471     int check = info->error->aug->flags & AUG_TYPE_CHECK;
472
473     return lns_check_rec(info, l->lens, r->lens, check);
474 }
475
476 /*
477  * Print functions
478  */
479
480 /* V_STRING -> V_UNIT */
481 static struct value *pr_string(struct info *info, struct value *s) {
482     printf("%s", s->string->str);
483     return make_unit(ref(info));
484 }
485
486 /* V_REGEXP -> V_UNIT */
487 static struct value *pr_regexp(struct info *info, struct value *r) {
488     print_regexp(stdout, r->regexp);
489     return make_unit(ref(info));
490 }
491
492 /* V_STRING -> V_UNIT */
493 static struct value *pr_endline(struct info *info, struct value *s) {
494     printf("%s\n", s->string->str);
495     return make_unit(ref(info));
496 }
497
498 /* V_TREE -> V_TREE */
499 static struct value *pr_tree(ATTRIBUTE_UNUSED struct info *info,
500                              struct value *t) {
501     print_tree_braces(stdout, 0, t->origin);
502     return ref(t);
503 }
504
505 /*
506  * Lens inspection
507  */
508
509 static struct value *lns_value_of_type(struct info *info, struct regexp *rx) {
510     struct value *result = make_value(V_REGEXP, ref(info));
511     if (rx)
512         result->regexp = ref(rx);
513     else
514         result->regexp = regexp_make_empty(ref(info));
515     return result;
516 }
517
518 /* V_LENS -> V_REGEXP */
519 static struct value *lns_ctype(struct info *info, struct value *l) {
520     return lns_value_of_type(info, l->lens->ctype);
521 }
522
523 /* V_LENS -> V_REGEXP */
524 static struct value *lns_atype(struct info *info, struct value *l) {
525     return lns_value_of_type(info, l->lens->atype);
526 }
527
528 /* V_LENS -> V_REGEXP */
529 static struct value *lns_vtype(struct info *info, struct value *l) {
530     return lns_value_of_type(info, l->lens->vtype);
531 }
532
533 /* V_LENS -> V_REGEXP */
534 static struct value *lns_ktype(struct info *info, struct value *l) {
535     return lns_value_of_type(info, l->lens->ktype);
536 }
537
538 /* V_LENS -> V_STRING */
539 static struct value *lns_fmt_atype(struct info *info, struct value *l) {
540     struct value *result = NULL;
541     char *s = NULL;
542     int r;
543
544     r = lns_format_atype(l->lens, &s);
545     if (r < 0)
546         return info->error->exn;
547     result = make_value(V_STRING, ref(info));
548     result->string = make_string(s);
549     return result;
550 }
551
552 /* V_REGEXP -> V_STRING -> V_STRING */
553 static struct value *rx_match(struct info *info,
554                               struct value *rx, struct value *s) {
555     struct value *result = NULL;
556     const char *str = s->string->str;
557     struct re_registers regs;
558     int r;
559
560     MEMZERO(&regs, 1);
561     r = regexp_match(rx->regexp, str, strlen(str), 0, &regs);
562     if (r < -1) {
563         result =
564             make_exn_value(ref(info), "regexp match failed (internal error)");
565     } else {
566         char *match = NULL;
567         if (r == -1) {
568             /* No match */
569             match = strdup("");
570         } else {
571             match = strndup(str + regs.start[0], regs.end[0] - regs.start[0]);
572         }
573         if (match == NULL) {
574             result = info->error->exn;
575         } else {
576             result = make_value(V_STRING, ref(info));
577             result->string = make_string(match);
578         }
579     }
580     return result;
581 }
582
583 struct module *builtin_init(struct error *error) {
584     struct module *modl = module_create("Builtin");
585     int r;
586
587 #define DEFINE_NATIVE(modl, name, nargs, impl, types ...)               \
588     r = define_native(error, modl, name, nargs, impl, ##types);         \
589     if (r < 0) goto error;
590
591     DEFINE_NATIVE(modl, "gensym", 1, gensym, T_STRING, T_STRING);
592
593     /* Primitive lenses */
594     DEFINE_NATIVE(modl, "del",     2, lns_del, T_REGEXP, T_STRING, T_LENS);
595     DEFINE_NATIVE(modl, "store",   1, lns_store, T_REGEXP, T_LENS);
596     DEFINE_NATIVE(modl, "value",   1, lns_value, T_STRING, T_LENS);
597     DEFINE_NATIVE(modl, "key",     1, lns_key, T_REGEXP, T_LENS);
598     DEFINE_NATIVE(modl, "label",   1, lns_label, T_STRING, T_LENS);
599     DEFINE_NATIVE(modl, "seq",     1, lns_seq, T_STRING, T_LENS);
600     DEFINE_NATIVE(modl, "counter", 1, lns_counter, T_STRING, T_LENS);
601     DEFINE_NATIVE(modl, "square",  3, lns_square, T_LENS, T_LENS, T_LENS, T_LENS);
602     /* Applying lenses (mostly for tests) */
603     DEFINE_NATIVE(modl, "get",     2, lens_get, T_LENS, T_STRING, T_TREE);
604     DEFINE_NATIVE(modl, "put",     3, lens_put, T_LENS, T_TREE, T_STRING,
605                   T_STRING);
606     /* Tree manipulation used by the PUT tests */
607     DEFINE_NATIVE(modl, "set", 3, tree_set_glue, T_STRING, T_STRING, T_TREE,
608                                                  T_TREE);
609     DEFINE_NATIVE(modl, "clear", 2, tree_clear_glue, T_STRING, T_TREE,
610                                                  T_TREE);
611     DEFINE_NATIVE(modl, "rm", 2, tree_rm_glue, T_STRING, T_TREE, T_TREE);
612     DEFINE_NATIVE(modl, "insa", 3, tree_insa_glue, T_STRING, T_STRING, T_TREE,
613                                                    T_TREE);
614     DEFINE_NATIVE(modl, "insb", 3, tree_insb_glue, T_STRING, T_STRING, T_TREE,
615                                                    T_TREE);
616     /* Transforms and filters */
617     DEFINE_NATIVE(modl, "incl", 1, xform_incl, T_STRING, T_FILTER);
618     DEFINE_NATIVE(modl, "excl", 1, xform_excl, T_STRING, T_FILTER);
619     DEFINE_NATIVE(modl, "transform", 2, xform_transform, T_LENS, T_FILTER,
620                                                          T_TRANSFORM);
621     DEFINE_NATIVE(modl, LNS_CHECK_REC_NAME,
622                   2, lns_check_rec_glue, T_LENS, T_LENS, T_LENS);
623     /* Printing */
624     DEFINE_NATIVE(modl, "print_string", 1, pr_string, T_STRING, T_UNIT);
625     DEFINE_NATIVE(modl, "print_regexp", 1, pr_regexp, T_REGEXP, T_UNIT);
626     DEFINE_NATIVE(modl, "print_endline", 1, pr_endline, T_STRING, T_UNIT);
627     DEFINE_NATIVE(modl, "print_tree", 1, pr_tree, T_TREE, T_TREE);
628
629     /* Lens inspection */
630     DEFINE_NATIVE(modl, "lens_ctype", 1, lns_ctype, T_LENS, T_REGEXP);
631     DEFINE_NATIVE(modl, "lens_atype", 1, lns_atype, T_LENS, T_REGEXP);
632     DEFINE_NATIVE(modl, "lens_vtype", 1, lns_vtype, T_LENS, T_REGEXP);
633     DEFINE_NATIVE(modl, "lens_ktype", 1, lns_ktype, T_LENS, T_REGEXP);
634     DEFINE_NATIVE(modl, "lens_format_atype", 1, lns_fmt_atype,
635                   T_LENS, T_STRING);
636
637     /* Regexp matching */
638     DEFINE_NATIVE(modl, "regexp_match", 2, rx_match, T_REGEXP, T_STRING,
639                   T_STRING);
640
641     /* System functions */
642     struct module *sys = module_create("Sys");
643     modl->next = sys;
644     DEFINE_NATIVE(sys, "getenv", 1, sys_getenv, T_STRING, T_STRING);
645     DEFINE_NATIVE(sys, "read_file", 1, sys_read_file, T_STRING, T_STRING);
646     return modl;
647  error:
648     unref(modl, module);
649     return NULL;
650 }
651
652 /*
653  * Local variables:
654  *  indent-tabs-mode: nil
655  *  c-indent-level: 4
656  *  c-basic-offset: 4
657  *  tab-width: 4
658  * End:
659  */