Merge pull request #125 from ifupdown-ng/feature/ifparse
YAML output support
This commit is contained in:
commit
9715b41c28
12 changed files with 666 additions and 43 deletions
25
Makefile
25
Makefile
|
@ -39,8 +39,7 @@ LIBIFUPDOWN_SRC = \
|
|||
libifupdown/lifecycle.c \
|
||||
libifupdown/config-parser.c \
|
||||
libifupdown/config-file.c \
|
||||
libifupdown/compat.c \
|
||||
|
||||
libifupdown/compat.c
|
||||
LIBIFUPDOWN_OBJ = ${LIBIFUPDOWN_SRC:.c=.o}
|
||||
LIBIFUPDOWN_LIB = libifupdown.a
|
||||
|
||||
|
@ -48,7 +47,8 @@ MULTICALL_SRC = \
|
|||
cmd/multicall.c \
|
||||
cmd/multicall-options.c \
|
||||
cmd/multicall-exec-options.c \
|
||||
cmd/multicall-match-options.c
|
||||
cmd/multicall-match-options.c \
|
||||
cmd/pretty-print-iface.c
|
||||
MULTICALL_OBJ = ${MULTICALL_SRC:.c=.o}
|
||||
MULTICALL = ifupdown
|
||||
|
||||
|
@ -74,6 +74,22 @@ MULTICALL_${CONFIG_IFCTRSTAT}_OBJ += ${IFCTRSTAT_SRC:.c=.o}
|
|||
CMDS_${CONFIG_IFCTRSTAT} += ifctrstat
|
||||
CPPFLAGS_${CONFIG_IFCTRSTAT} += -DCONFIG_IFCTRSTAT
|
||||
|
||||
# enable ifparse applet (+1 KB)
|
||||
CONFIG_IFPARSE ?= Y
|
||||
IFPARSE_SRC = cmd/ifparse.c
|
||||
MULTICALL_${CONFIG_IFPARSE}_OBJ += ${IFPARSE_SRC:.c=.o}
|
||||
CMDS_${CONFIG_IFPARSE} += ifparse
|
||||
CPPFLAGS_${CONFIG_IFPARSE} += -DCONFIG_IFPARSE
|
||||
|
||||
# enable YAML support (+2 KB)
|
||||
CONFIG_YAML ?= Y
|
||||
YAML_SRC = \
|
||||
libifupdown/yaml-base.c \
|
||||
libifupdown/yaml-writer.c
|
||||
LIBIFUPDOWN_${CONFIG_YAML}_OBJ += ${YAML_SRC:.c=.o}
|
||||
CPPFLAGS_${CONFIG_YAML} += -DCONFIG_YAML
|
||||
|
||||
LIBIFUPDOWN_OBJ += ${LIBIFUPDOWN_Y_OBJ}
|
||||
MULTICALL_OBJ += ${MULTICALL_Y_OBJ}
|
||||
CMDS += ${CMDS_Y}
|
||||
CPPFLAGS += ${CPPFLAGS_Y}
|
||||
|
@ -156,7 +172,8 @@ MANPAGES_8 = \
|
|||
doc/ifquery.8 \
|
||||
doc/ifup.8 \
|
||||
doc/ifdown.8 \
|
||||
doc/ifctrstat.8
|
||||
doc/ifctrstat.8 \
|
||||
doc/ifparse.8
|
||||
|
||||
MANPAGES = ${MANPAGES_5} ${MANPAGES_7} ${MANPAGES_8}
|
||||
|
||||
|
|
224
cmd/ifparse.c
Normal file
224
cmd/ifparse.c
Normal file
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* cmd/ifparse.c
|
||||
* Purpose: Redisplay /e/n/i in alternative formats.
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <fnmatch.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include "libifupdown/libifupdown.h"
|
||||
|
||||
#ifdef CONFIG_YAML
|
||||
# include "libifupdown/yaml-base.h"
|
||||
# include "libifupdown/yaml-writer.h"
|
||||
#endif
|
||||
|
||||
#include "cmd/multicall.h"
|
||||
#include "cmd/pretty-print-iface.h"
|
||||
|
||||
static bool show_all = false;
|
||||
static bool allow_undefined = false;
|
||||
|
||||
static void
|
||||
set_show_all(const char *arg)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
show_all = true;
|
||||
}
|
||||
|
||||
static void
|
||||
set_allow_undefined(const char *arg)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
allow_undefined = true;
|
||||
}
|
||||
|
||||
static const char *output_fmt = "ifupdown";
|
||||
|
||||
static void
|
||||
set_output_fmt(const char *arg)
|
||||
{
|
||||
output_fmt = arg;
|
||||
}
|
||||
|
||||
static struct if_option local_options[] = {
|
||||
{'F', "format", NULL, "output format to use", true, set_output_fmt},
|
||||
{'A', "all", NULL, "show all interfaces", false, set_show_all},
|
||||
{'U', "allow-undefined", NULL, "allow querying undefined (virtual) interfaces", false, set_allow_undefined},
|
||||
};
|
||||
|
||||
static struct if_option_group local_option_group = {
|
||||
.desc = "Program-specific options",
|
||||
.group_size = ARRAY_SIZE(local_options),
|
||||
.group = local_options
|
||||
};
|
||||
|
||||
#ifdef CONFIG_YAML
|
||||
static void
|
||||
prettyprint_interface_yaml(struct lif_interface *iface)
|
||||
{
|
||||
struct lif_yaml_node doc = {};
|
||||
|
||||
lif_yaml_document_init(&doc, "interfaces");
|
||||
|
||||
struct lif_yaml_node *iface_node = lif_yaml_node_new_list(iface->ifname);
|
||||
lif_yaml_node_append_child(&doc, iface_node);
|
||||
|
||||
if (iface->is_auto)
|
||||
{
|
||||
struct lif_yaml_node *iface_entry_node = lif_yaml_node_new_boolean("auto", true);
|
||||
lif_yaml_node_append_child(iface_node, iface_entry_node);
|
||||
}
|
||||
|
||||
struct lif_node *iter;
|
||||
LIF_DICT_FOREACH(iter, &iface->vars)
|
||||
{
|
||||
struct lif_dict_entry *entry = iter->data;
|
||||
const char *value = entry->data;
|
||||
char addr_buf[512];
|
||||
|
||||
if (!strcmp(entry->key, "address"))
|
||||
{
|
||||
struct lif_address *addr = entry->data;
|
||||
|
||||
if (!lif_address_unparse(addr, addr_buf, sizeof addr_buf, true))
|
||||
continue;
|
||||
|
||||
value = addr_buf;
|
||||
}
|
||||
|
||||
struct lif_yaml_node *iface_entry_node = lif_yaml_node_new_string(entry->key, value);
|
||||
lif_yaml_node_append_child(iface_node, iface_entry_node);
|
||||
}
|
||||
|
||||
lif_yaml_write(iface_node, stdout, true);
|
||||
lif_yaml_node_free(&doc);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct prettyprint_impl_map {
|
||||
const char *name;
|
||||
void (*handle)(struct lif_interface *iface);
|
||||
};
|
||||
|
||||
struct prettyprint_impl_map pp_impl_map[] = {
|
||||
{"ifupdown", prettyprint_interface_eni},
|
||||
#ifdef CONFIG_YAML
|
||||
{"yaml-raw", prettyprint_interface_yaml},
|
||||
#endif
|
||||
};
|
||||
|
||||
static int
|
||||
pp_impl_cmp(const void *a, const void *b)
|
||||
{
|
||||
const char *key = a;
|
||||
const struct prettyprint_impl_map *impl = b;
|
||||
|
||||
return strcmp(key, impl->name);
|
||||
}
|
||||
|
||||
int
|
||||
ifparse_main(int argc, char *argv[])
|
||||
{
|
||||
struct lif_dict state = {};
|
||||
struct lif_dict collection = {};
|
||||
struct lif_interface_file_parse_state parse_state = {
|
||||
.collection = &collection,
|
||||
};
|
||||
|
||||
lif_interface_collection_init(&collection);
|
||||
|
||||
if (!lif_state_read_path(&state, exec_opts.state_file))
|
||||
{
|
||||
fprintf(stderr, "%s: could not parse %s\n", argv0, exec_opts.state_file);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!lif_interface_file_parse(&parse_state, exec_opts.interfaces_file))
|
||||
{
|
||||
fprintf(stderr, "%s: could not parse %s\n", argv0, exec_opts.interfaces_file);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (match_opts.property == NULL && lif_lifecycle_count_rdepends(&exec_opts, &collection) == -1)
|
||||
{
|
||||
fprintf(stderr, "%s: could not validate dependency tree\n", argv0);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!lif_compat_apply(&collection))
|
||||
{
|
||||
fprintf(stderr, "%s: failed to apply compatibility glue\n", argv0);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
struct prettyprint_impl_map *m = bsearch(output_fmt, pp_impl_map, ARRAY_SIZE(pp_impl_map), sizeof(*m), pp_impl_cmp);
|
||||
if (m == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: %s: output format not supported\n", argv0, output_fmt);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (show_all)
|
||||
{
|
||||
struct lif_node *n;
|
||||
|
||||
LIF_DICT_FOREACH(n, &collection)
|
||||
{
|
||||
struct lif_dict_entry *entry = n->data;
|
||||
|
||||
m->handle(entry->data);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (optind >= argc)
|
||||
generic_usage(self_applet, EXIT_FAILURE);
|
||||
|
||||
int idx = optind;
|
||||
for (; idx < argc; idx++)
|
||||
{
|
||||
struct lif_dict_entry *entry = lif_dict_find(&collection, argv[idx]);
|
||||
struct lif_interface *iface = NULL;
|
||||
|
||||
if (entry != NULL)
|
||||
iface = entry->data;
|
||||
|
||||
if (entry == NULL && allow_undefined)
|
||||
iface = lif_interface_collection_find(&collection, argv[idx]);
|
||||
|
||||
if (iface == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: unknown interface %s\n", argv0, argv[idx]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
m->handle(iface);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
struct if_applet ifparse_applet = {
|
||||
.name = "ifparse",
|
||||
.desc = "redisplay interface configuration",
|
||||
.main = ifparse_main,
|
||||
.usage = "ifparse [options] <interfaces>\n ifparse [options] --all",
|
||||
.manpage = "8 ifparse",
|
||||
.groups = { &global_option_group, &match_option_group, &exec_option_group, &local_option_group },
|
||||
};
|
|
@ -20,42 +20,7 @@
|
|||
#include <getopt.h>
|
||||
#include "libifupdown/libifupdown.h"
|
||||
#include "cmd/multicall.h"
|
||||
|
||||
void
|
||||
print_interface(struct lif_interface *iface)
|
||||
{
|
||||
if (!lif_lifecycle_query_dependents(&exec_opts, iface, iface->ifname))
|
||||
return;
|
||||
|
||||
if (iface->is_auto)
|
||||
printf("auto %s\n", iface->ifname);
|
||||
|
||||
printf("%s %s\n", iface->is_template ? "template" : "iface", iface->ifname);
|
||||
|
||||
struct lif_node *iter;
|
||||
LIF_DICT_FOREACH(iter, &iface->vars)
|
||||
{
|
||||
struct lif_dict_entry *entry = iter->data;
|
||||
|
||||
if (!strcmp(entry->key, "address"))
|
||||
{
|
||||
struct lif_address *addr = entry->data;
|
||||
char addr_buf[512];
|
||||
|
||||
if (!lif_address_unparse(addr, addr_buf, sizeof addr_buf, true))
|
||||
{
|
||||
printf(" # warning: failed to unparse address\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
printf(" %s %s\n", entry->key, addr_buf);
|
||||
}
|
||||
else
|
||||
printf(" %s %s\n", entry->key, (const char *) entry->data);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
#include "cmd/pretty-print-iface.h"
|
||||
|
||||
void
|
||||
print_interface_dot(struct lif_dict *collection, struct lif_interface *iface, struct lif_interface *parent)
|
||||
|
@ -147,7 +112,7 @@ list_interfaces(struct lif_dict *collection, struct match_options *opts)
|
|||
continue;
|
||||
|
||||
if (opts->pretty_print)
|
||||
print_interface(iface);
|
||||
prettyprint_interface_eni(iface);
|
||||
else if (opts->dot)
|
||||
print_interface_dot(collection, iface, NULL);
|
||||
else
|
||||
|
@ -330,7 +295,7 @@ ifquery_main(int argc, char *argv[])
|
|||
if (match_opts.property != NULL)
|
||||
print_interface_property(iface, match_opts.property);
|
||||
else
|
||||
print_interface(iface);
|
||||
prettyprint_interface_eni(iface);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
@ -36,6 +36,10 @@ extern struct if_applet ifdown_applet;
|
|||
extern struct if_applet ifctrstat_applet;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IFPARSE
|
||||
extern struct if_applet ifparse_applet;
|
||||
#endif
|
||||
|
||||
struct if_applet ifupdown_applet;
|
||||
const struct if_applet *self_applet = NULL;
|
||||
|
||||
|
@ -46,6 +50,9 @@ struct if_applet *applet_table[] = {
|
|||
#ifdef CONFIG_IFUPDOWN
|
||||
&ifdown_applet,
|
||||
#endif
|
||||
#ifdef CONFIG_IFPARSE
|
||||
&ifparse_applet,
|
||||
#endif
|
||||
#ifdef CONFIG_IFQUERY
|
||||
&ifquery_applet,
|
||||
#endif
|
||||
|
|
56
cmd/pretty-print-iface.c
Normal file
56
cmd/pretty-print-iface.c
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* cmd/pretty-print-iface.c
|
||||
* Purpose: interface pretty-printer (/e/n/i style)
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "libifupdown/libifupdown.h"
|
||||
#include "cmd/multicall.h"
|
||||
#include "cmd/pretty-print-iface.h"
|
||||
|
||||
void
|
||||
prettyprint_interface_eni(struct lif_interface *iface)
|
||||
{
|
||||
if (!lif_lifecycle_query_dependents(&exec_opts, iface, iface->ifname))
|
||||
return;
|
||||
|
||||
if (iface->is_auto)
|
||||
printf("auto %s\n", iface->ifname);
|
||||
|
||||
printf("%s %s\n", iface->is_template ? "template" : "iface", iface->ifname);
|
||||
|
||||
struct lif_node *iter;
|
||||
LIF_DICT_FOREACH(iter, &iface->vars)
|
||||
{
|
||||
struct lif_dict_entry *entry = iter->data;
|
||||
|
||||
if (!strcmp(entry->key, "address"))
|
||||
{
|
||||
struct lif_address *addr = entry->data;
|
||||
char addr_buf[512];
|
||||
|
||||
if (!lif_address_unparse(addr, addr_buf, sizeof addr_buf, true))
|
||||
{
|
||||
printf(" # warning: failed to unparse address\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
printf(" %s %s\n", entry->key, addr_buf);
|
||||
}
|
||||
else
|
||||
printf(" %s %s\n", entry->key, (const char *) entry->data);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
23
cmd/pretty-print-iface.h
Normal file
23
cmd/pretty-print-iface.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* cmd/pretty-print-iface.h
|
||||
* Purpose: interface pretty-printer (/e/n/i style)
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#ifndef IFUPDOWN_CMD_PRETTY_PRINT_IFACE_H__GUARD
|
||||
#define IFUPDOWN_CMD_PRETTY_PRINT_IFACE_H__GUARD
|
||||
|
||||
#include "libifupdown/libifupdown.h"
|
||||
|
||||
extern void prettyprint_interface_eni(struct lif_interface *iface);
|
||||
|
||||
#endif
|
62
doc/ifparse.scd
Normal file
62
doc/ifparse.scd
Normal file
|
@ -0,0 +1,62 @@
|
|||
ifparse(8)
|
||||
|
||||
# NAME
|
||||
|
||||
ifparse - redisplay interface configuration in different formats
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
*ifparse* [<_options_>...] <_interfaces_...>
|
||||
|
||||
*ifparse* -A|--all
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
*ifparse* is used to extract information from the interface configuration
|
||||
file. It is intended to be used to translate the interface configuration
|
||||
stanzas between different formats.
|
||||
|
||||
# OPTIONS
|
||||
|
||||
*-a, --auto*
|
||||
Only match interfaces that are marked as _auto_.
|
||||
|
||||
*-h, --help*
|
||||
Display supported options to ifquery.
|
||||
|
||||
*-i, --interfaces* _FILE_
|
||||
Use _FILE_ as the config database.
|
||||
|
||||
*-F, --format* _FORMAT_
|
||||
Use _FORMAT_ to determine what format to use. *ifupdown* and
|
||||
*yaml-raw* formats are available.
|
||||
|
||||
*-I, --include* _PATTERN_
|
||||
Include _PATTERN_ when matching against the config or state
|
||||
database.
|
||||
|
||||
*-U, --allow-undefined*
|
||||
Create virtual interfaces for any interfaces not explicitly
|
||||
defined in the configuration file. This is primarily useful
|
||||
for property queries.
|
||||
|
||||
*-S, --state-file* _FILE_
|
||||
Use _FILE_ as the state database.
|
||||
|
||||
*-V, --version*
|
||||
Print the ifupdown-ng version and exit.
|
||||
|
||||
*-X, --exclude* _PATTERN_
|
||||
Exclude _PATTERN_ when matching against the config or state
|
||||
database.
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
*ifup*(8)++
|
||||
*ifdown*(8)++
|
||||
*ifquery*(8)++
|
||||
*interfaces*(5)
|
||||
|
||||
# AUTHORS
|
||||
|
||||
Ariadne Conill <ariadne@dereferenced.org>
|
|
@ -40,7 +40,7 @@ extern void lif_node_delete(struct lif_node *node, struct lif_list *list);
|
|||
for ((iter) = (head); (iter) != NULL; (iter) = (iter)->next)
|
||||
|
||||
#define LIF_LIST_FOREACH_SAFE(iter, iter_next, head) \
|
||||
for ((iter) = (head), (iter_next) = (iter)->next; (iter) != NULL; (iter) = (iter_next), (iter_next) = (iter) != NULL ? (iter)->next : NULL)
|
||||
for ((iter) = (head), (iter_next) = (iter) != NULL ? (iter)->next : NULL; (iter) != NULL; (iter) = (iter_next), (iter_next) = (iter) != NULL ? (iter)->next : NULL)
|
||||
|
||||
#define LIF_LIST_FOREACH_REVERSE(iter, tail) \
|
||||
for ((iter) = (tail); (iter) != NULL; (iter) = (iter)->prev)
|
||||
|
|
127
libifupdown/yaml-base.c
Normal file
127
libifupdown/yaml-base.c
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* libifupdown/yaml-base.c
|
||||
* Purpose: YAML implementation -- base
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "libifupdown/libifupdown.h"
|
||||
#include "libifupdown/yaml-base.h"
|
||||
|
||||
void
|
||||
lif_yaml_document_init(struct lif_yaml_node *doc, const char *name)
|
||||
{
|
||||
memset(doc, '\0', sizeof *doc);
|
||||
doc->value_type = LIF_YAML_OBJECT;
|
||||
|
||||
if (name != NULL)
|
||||
doc->name = strdup(name);
|
||||
}
|
||||
|
||||
struct lif_yaml_node *
|
||||
lif_yaml_document_new(const char *name)
|
||||
{
|
||||
struct lif_yaml_node *doc = calloc(1, sizeof *doc);
|
||||
|
||||
lif_yaml_document_init(doc, name);
|
||||
doc->malloced = true;
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
struct lif_yaml_node *
|
||||
lif_yaml_node_new_boolean(const char *name, bool value)
|
||||
{
|
||||
struct lif_yaml_node *node = calloc(1, sizeof *node);
|
||||
|
||||
node->malloced = true;
|
||||
node->value_type = LIF_YAML_BOOLEAN;
|
||||
|
||||
if (name != NULL)
|
||||
node->name = strdup(name);
|
||||
|
||||
node->value.bool_value = value;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
struct lif_yaml_node *
|
||||
lif_yaml_node_new_string(const char *name, const char *value)
|
||||
{
|
||||
struct lif_yaml_node *node = calloc(1, sizeof *node);
|
||||
|
||||
node->malloced = true;
|
||||
node->value_type = LIF_YAML_STRING;
|
||||
|
||||
if (name != NULL)
|
||||
node->name = strdup(name);
|
||||
|
||||
if (value != NULL)
|
||||
node->value.str_value = strdup(value);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
struct lif_yaml_node *
|
||||
lif_yaml_node_new_object(const char *name)
|
||||
{
|
||||
struct lif_yaml_node *node = calloc(1, sizeof *node);
|
||||
|
||||
node->malloced = true;
|
||||
node->value_type = LIF_YAML_OBJECT;
|
||||
|
||||
if (name != NULL)
|
||||
node->name = strdup(name);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
struct lif_yaml_node *
|
||||
lif_yaml_node_new_list(const char *name)
|
||||
{
|
||||
struct lif_yaml_node *node = calloc(1, sizeof *node);
|
||||
|
||||
node->malloced = true;
|
||||
node->value_type = LIF_YAML_LIST;
|
||||
|
||||
if (name != NULL)
|
||||
node->name = strdup(name);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void
|
||||
lif_yaml_node_free(struct lif_yaml_node *node)
|
||||
{
|
||||
struct lif_node *iter, *next;
|
||||
|
||||
LIF_LIST_FOREACH_SAFE(iter, next, node->children.head)
|
||||
{
|
||||
struct lif_yaml_node *iter_node = iter->data;
|
||||
|
||||
lif_yaml_node_free(iter_node);
|
||||
}
|
||||
|
||||
free(node->name);
|
||||
|
||||
if (node->value_type == LIF_YAML_STRING)
|
||||
free(node->value.str_value);
|
||||
|
||||
if (node->malloced)
|
||||
free(node);
|
||||
}
|
||||
|
||||
void
|
||||
lif_yaml_node_append_child(struct lif_yaml_node *parent, struct lif_yaml_node *child)
|
||||
{
|
||||
lif_node_insert_tail(&child->node, child, &parent->children);
|
||||
}
|
52
libifupdown/yaml-base.h
Normal file
52
libifupdown/yaml-base.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* libifupdown/yaml-base.h
|
||||
* Purpose: YAML implementation -- base
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#ifndef LIBIFUPDOWN_YAML_BASE_H__GUARD
|
||||
#define LIBIFUPDOWN_YAML_BASE_H__GUARD
|
||||
|
||||
#include "libifupdown/libifupdown.h"
|
||||
|
||||
/* this is a subset of types supported by our implementation */
|
||||
enum lif_yaml_value {
|
||||
LIF_YAML_STRING,
|
||||
LIF_YAML_LIST,
|
||||
LIF_YAML_OBJECT,
|
||||
LIF_YAML_BOOLEAN
|
||||
};
|
||||
|
||||
struct lif_yaml_node {
|
||||
struct lif_node node;
|
||||
|
||||
bool malloced;
|
||||
char *name;
|
||||
enum lif_yaml_value value_type;
|
||||
union {
|
||||
char *str_value; /* for string nodes */
|
||||
bool bool_value; /* for boolean nodes */
|
||||
} value;
|
||||
struct lif_list children; /* for list and object nodes */
|
||||
};
|
||||
|
||||
extern void lif_yaml_document_init(struct lif_yaml_node *doc, const char *name);
|
||||
extern struct lif_yaml_node *lif_yaml_document_new(const char *name);
|
||||
|
||||
extern struct lif_yaml_node *lif_yaml_node_new_boolean(const char *name, bool value);
|
||||
extern struct lif_yaml_node *lif_yaml_node_new_string(const char *name, const char *value);
|
||||
extern struct lif_yaml_node *lif_yaml_node_new_object(const char *name);
|
||||
extern struct lif_yaml_node *lif_yaml_node_new_list(const char *name);
|
||||
extern void lif_yaml_node_free(struct lif_yaml_node *node);
|
||||
extern void lif_yaml_node_append_child(struct lif_yaml_node *parent, struct lif_yaml_node *child);
|
||||
|
||||
#endif
|
66
libifupdown/yaml-writer.c
Normal file
66
libifupdown/yaml-writer.c
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* libifupdown/yaml-writer.c
|
||||
* Purpose: YAML implementation -- writer
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "libifupdown/libifupdown.h"
|
||||
#include "libifupdown/yaml-base.h"
|
||||
#include "libifupdown/yaml-writer.h"
|
||||
|
||||
static const size_t INDENT_WIDTH = 2;
|
||||
|
||||
static void
|
||||
lif_yaml_write_node(const struct lif_yaml_node *node, FILE *f, size_t indent, bool type_annotations)
|
||||
{
|
||||
const struct lif_node *iter;
|
||||
|
||||
if (node->name != NULL)
|
||||
fprintf(f, "%*s%s: ", (int) indent, "", node->name);
|
||||
|
||||
size_t child_indent = indent + INDENT_WIDTH;
|
||||
|
||||
switch (node->value_type)
|
||||
{
|
||||
case LIF_YAML_BOOLEAN:
|
||||
fprintf(f, "%s%s\n", type_annotations ? "!!bool " : "", node->value.bool_value ? "true" : "false");
|
||||
break;
|
||||
case LIF_YAML_STRING:
|
||||
fprintf(f, "%s%s\n", type_annotations ? "!!str " : "", node->value.str_value);
|
||||
break;
|
||||
case LIF_YAML_OBJECT:
|
||||
fprintf(f, "\n");
|
||||
break;
|
||||
case LIF_YAML_LIST:
|
||||
fprintf(f, "\n");
|
||||
child_indent += INDENT_WIDTH;
|
||||
break;
|
||||
}
|
||||
|
||||
LIF_LIST_FOREACH(iter, node->children.head)
|
||||
{
|
||||
const struct lif_yaml_node *iter_node = iter->data;
|
||||
|
||||
if (node->value_type == LIF_YAML_LIST)
|
||||
fprintf(f, "%*s-\n", (int) (child_indent - INDENT_WIDTH), "");
|
||||
|
||||
lif_yaml_write_node(iter_node, f, child_indent, type_annotations);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lif_yaml_write(const struct lif_yaml_node *doc, FILE *f, bool type_annotations)
|
||||
{
|
||||
lif_yaml_write_node(doc, f, 0, type_annotations);
|
||||
}
|
24
libifupdown/yaml-writer.h
Normal file
24
libifupdown/yaml-writer.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* libifupdown/yaml-writer.h
|
||||
* Purpose: YAML implementation -- writer
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#ifndef LIBIFUPDOWN_YAML_WRITER_H__GUARD
|
||||
#define LIBIFUPDOWN_YAML_WRITER_H__GUARD
|
||||
|
||||
#include "libifupdown/libifupdown.h"
|
||||
#include "libifupdown/yaml-base.h"
|
||||
|
||||
extern void lif_yaml_write(const struct lif_yaml_node *doc, FILE *f, bool type_annotations);
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue