summaryrefslogtreecommitdiff
path: root/src/config_tree.ml
diff options
context:
space:
mode:
authorDaniil Baturin <daniil@baturin.org>2017-09-12 21:10:21 +0700
committerDaniil Baturin <daniil@baturin.org>2017-09-12 21:10:21 +0700
commitdd67f0333363d3afb0f8d42aaed94f52712dd759 (patch)
tree3467040ab5d3e4080e5b74edf6601fb82e98db0b /src/config_tree.ml
parentbc2c1a032a4aad1d5c3f5047d51f86bf8370b163 (diff)
parent5761be1601db95ceeec49104c502902939e194d6 (diff)
downloadvyconf-dd67f0333363d3afb0f8d42aaed94f52712dd759.tar.gz
vyconf-dd67f0333363d3afb0f8d42aaed94f52712dd759.zip
Merge branch 'master' of github.com:vyos/vyconf
Diffstat (limited to 'src/config_tree.ml')
-rw-r--r--src/config_tree.ml145
1 files changed, 144 insertions, 1 deletions
diff --git a/src/config_tree.ml b/src/config_tree.ml
index 538b258..9fed465 100644
--- a/src/config_tree.ml
+++ b/src/config_tree.ml
@@ -105,4 +105,147 @@ let is_ephemeral node path =
let data = Vytree.get_data node path in
data.ephemeral
-
+module Renderer =
+struct
+ (* TODO Replace use of Printf with Format *)
+
+ module L = List
+ module S = String
+ module PF = Printf
+ module VT = Vytree
+ module RT = Reference_tree
+
+ (* Nodes are ordered based on a comarison of their names *)
+ let compare cmp node1 node2 =
+ let name1 = VT.name_of_node node1 in
+ let name2 = VT.name_of_node node2 in
+ cmp name1 name2
+
+ let indentation indent level = S.make (level * indent) ' '
+
+ let render_inactive data = if data.inactive then "#INACTIVE " else ""
+ let render_ephemeral data = if data.ephemeral then "#EPHEMERAL " else ""
+
+ let render_comment data indents =
+ match data.comment with
+ | None -> ""
+ (* Trailing indentation for the rest of the material on the next line *)
+ | Some c -> PF.sprintf "/*%s*/\n%s" c indents
+
+ let render_tag = function
+ | None -> ""
+ | Some tag -> PF.sprintf "%s " tag
+
+ let render_outer indents data name tag =
+ [render_comment data indents ;
+ render_inactive data;
+ render_ephemeral data;
+ render_tag tag;
+ name]
+ |> S.concat ""
+
+ let render_values = function
+ | [v] -> PF.sprintf "\"%s\";" v
+ | vs -> S.concat "; " vs |> PF.sprintf "[%s];"
+
+ let render_inner_and_outer indents inner outer =
+ if inner = ""
+ (* Hidden or empty descendents yield empty nodes *)
+ then PF.sprintf "%s%s { }" indents outer
+ else PF.sprintf "%s%s %s" indents outer inner
+
+ let render
+ ?(indent=4)
+ ?(reftree)
+ ?(cmp=BatString.numeric_compare)
+ ?(showephemeral=false)
+ ?(showinactive=false)
+ (config_tree:t)
+ =
+ let is_hidden data =
+ (not showephemeral && data.ephemeral) ||
+ (not showinactive && data.inactive)
+ in
+ let rec render_node level ?tag node =
+ let data = VT.data_of_node node in
+ let name = VT.name_of_node node in
+ (* Hide inactive and ephemeral when necessary *)
+ if is_hidden data then ""
+ else
+ let indents = indentation indent level in
+ let outer = render_outer indents data name tag in
+ let inner = (* Children are ignored if the node has values *)
+ match data.values with
+ | [] -> VT.children_of_node node |> render_children level
+ | values -> render_values values
+ in
+ PF.sprintf "%s%s %s" indents outer inner
+ and render_children level = function
+ | [] -> "{ }"
+ | children ->
+ let indents = indentation indent level in
+ let render_child node = render_node (level + 1) node in
+ let rendered_children = L.map render_child children |> S.concat "\n"
+ in
+ if rendered_children = "" then "{ }"
+ else PF.sprintf "{\n%s\n%s}" rendered_children indents
+ in
+ (* Walks the reftree and config_tree side-by-side *)
+ let rec render_node_rt level tag rt node =
+ let data = VT.data_of_node node in
+ let name = VT.name_of_node node in
+ let rt_data = VT.data_of_node rt in
+ let rt_name = VT.name_of_node rt in
+ (* Hide inactive and ephemeral when necessary *)
+ if is_hidden data then ""
+ else
+ (* TODO refactor this ugly approach*)
+ let (outer_name, level', inner) =
+ let open RT in
+ let children = VT.children_of_node node in
+ let ordered = rt_data.keep_order in
+ match rt_data.node_type with
+ | Tag ->
+ ("", 0, render_children_rt level (Some name) ordered rt children)
+ | Other ->
+ (name, level, render_children_rt level None ordered rt children)
+ | Leaf ->
+ (name, level, render_values data.values)
+ in
+ let indents = indentation indent level' in
+ let outer = render_outer indents data outer_name tag in
+ PF.sprintf "%s%s %s" indents outer inner
+ and render_children_rt level tag ordered rt = function
+ | [] -> "{ }"
+ | children ->
+ let is_tagged = BatOption.is_some tag in
+ let indents = indentation indent level in
+ let reorder nodes =
+ if ordered then nodes
+ else L.sort (compare cmp) nodes
+ in
+ let render_child node =
+ let level' = if is_tagged then level else level + 1 in
+ let node_reftree = VT.find rt (VT.name_of_node node) in
+ (* If there is no reftree for a node, default to stand-alone *)
+ match node_reftree with
+ | Some rt' -> render_node_rt level' tag rt' node
+ | None -> render_node level' ?tag node
+ in
+ let rendered_children = children
+ |> reorder
+ |> L.map render_child
+ |> S.concat "\n"
+ in
+ if rendered_children = "" then "{ }"
+ else if is_tagged
+ then rendered_children
+ else PF.sprintf "{\n%s\n%s}" rendered_children indents
+ in
+ match reftree with
+ | None -> render_node 0 config_tree
+ | Some rt -> render_node_rt 0 None rt config_tree
+
+end (* Renderer *)
+
+let render = Renderer.render