Hi Mathieu,

On Tue, 2011-07-05 at 17:34 +0200, Mathieu Arnold wrote: 
> It's by no way finished, but I'm adding things as they come in my config
> file, and I'm stuck right now, if I remove the "forwarders { ... };" part,
> the test passes, but I can't seem to find a way to get it to work.
> 
> https://gist.github.com/1065061
> 
> Also, it seems that I can't have eol be silently ignored and I have to put
> it in [] which gets me a lot of empty trees in the lense, if someone can
> tell me what I did wrong there, I'd love to hear about it :-)

that was a nice headscratcher; attached is a patch series that solves
the issues you encountered. The commit messages should explain how
things were resolved.

I am looking forward to your submitting the finished named lens (in
which you can just squash my patches into yours)

David

>From 00a7a374f1b017d65ad25d558280f4f5f837d902 Mon Sep 17 00:00:00 2001
From: David Lutterkort <[email protected]>
Date: Tue, 5 Jul 2011 16:16:25 -0700
Subject: [PATCH 1/4] Original lens from https://gist.github.com/1065061

---
 lenses/named.aug            |  190 +++++++++++++++++++++++++++++++++++++++++++
 lenses/tests/test_named.aug |   65 +++++++++++++++
 2 files changed, 255 insertions(+), 0 deletions(-)
 create mode 100644 lenses/named.aug
 create mode 100644 lenses/tests/test_named.aug

diff --git a/lenses/named.aug b/lenses/named.aug
new file mode 100644
index 0000000..0750393
--- /dev/null
+++ b/lenses/named.aug
@@ -0,0 +1,190 @@
+(*
+Module: Named
+  parses /etc/namedb/named.conf
+
+Author: Mathieu Arnold <[email protected]>
+
+About: Reference
+  This lens tries to keep as close as possible to the bind documentation where
+  possible. An online source being :
+  http://www.freebsd.org/cgi/man.cgi?query=syslog.conf&sektion=5
+
+About: Licence
+  This file is licensed under the BSD License.
+
+About: Lens Usage
+   To be documented
+
+About: Configuration files
+  This lens applies to /etc/namedb/named.conf. See <filter>.
+
+ *)
+module Named =
+  autoload xfm
+
+	(************************************************************************
+	 * Group:                 USEFUL PRIMITIVES
+	 *************************************************************************)
+
+	(* Group: Comments and empty lines *)
+
+	(* Variable: empty *)
+        let empty      = Util.empty
+	(* Variable: eol *)
+        let eol        = Util.eol
+	(* Variable: sep_tab *)
+        let sep_tab    = Sep.tab
+	(* Variable: indent *)
+	let indent     = Util.indent
+
+
+	let chr_blank = /[ \t]/
+	let chr_nblank = /[^ \t\n]/
+	let chr_any    = /./
+	let chr_star   = /\*/
+	let chr_nstar  = /[^\* \t\n]/
+	let chr_slash  = /\//
+	let chr_nslash = /[^\/ \t\n]/
+
+	(* Group: single characters macro *)
+
+	(* Variable: semicolon
+	 Deletes a semicolon and default to it
+	 *)
+	let semicolon  = del /[ \t]*;/ ";"
+
+	let sto_to_eol = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/
+
+	let subnet = Rx.ip | Rx.ip . /\/[0-9]+/
+
+	(************************************************************************
+	 * Group:                 LENSE DEFINITION
+	 *************************************************************************)
+
+
+	(************************************************************************
+	 *                              COMMENTS
+	 *************************************************************************)
+
+	let comment_re = chr_nblank
+		       | ( chr_nblank . chr_any*
+			   . ( chr_star  . chr_nslash
+			     | chr_nstar . chr_slash
+			     | chr_nstar . chr_nslash
+			     | chr_blank . chr_nblank ) )
+
+	let comment_first_line
+		       = [ del /([ \t]*\n)?[ \t]*/ ""
+			 . seq "#comment"
+			 . store comment_re
+			  ]
+	let comment_other_line
+		       = [ del /[ \t]*\n[ \t\n]*/ "\n"
+			 . seq "#comment"
+			 . store comment_re
+			  ]
+	let comment_end
+		       = del /[ \t\n]*/ "" . del (chr_star . chr_slash) "*/"
+
+	let comment_extended
+			 = [ indent
+			 . del (chr_slash . chr_star) "/*"
+			 . label "#comment"
+			 . counter "#comment"
+			 . ( (comment_first_line . comment_other_line+)
+			   | comment_first_line?)
+			 . comment_end
+			 . eol ]
+
+	let comment_inline
+			 = [ indent
+			 . del (chr_slash . chr_slash) "//"
+			 . label "#inline"
+			 . indent
+			 . sto_to_eol
+			 . eol ]
+
+	let comment      = comment_extended | comment_inline | Util.comment
+
+	(****
+	 * Generic functions
+	 *)
+
+	let body (attr:lens) = del /{/ "{"
+			     . ( [eol] 
+				 | comment
+				 | (indent . attr . semicolon) )*
+			     . del /[ \t]*}/ "}"
+
+	let group (name:string) (attr:lens) = 
+		  [ indent
+		  . Util.del_str name
+		  . del /[ \t]+/ " "
+		  . label name
+		  . store /[a-z]+/
+		  . del chr_blank* ""
+		  . body attr
+		  . semicolon
+		  ]
+
+	let attr_one (k:regexp) (v:regexp) =
+	  [key k . del chr_blank+  " " . store v]
+
+
+	(* ACL *)
+	(* missing the key possibility *)
+
+	let acl = 
+	  let acl_re = [store subnet] in
+	    group "acl" acl_re
+
+
+	(* Options *)
+
+	let options_attr_boolean =
+		  attr_one ( "acache-enable" | "additional-from-auth" | "additional-from-cache" | "auth-nxdomain" | "check-integrity" | "check-sibling" | "check-wildcard" | "deallocate-on-exit" | "dnssec-accept-expired" | "dnssec-dnskey-kskonly" | "dnssec-enable" | "dnssec-must-be-secure" | "dnssec-secure-to-insecure" | "dnssec-validation" | "empty-zones-enable" | "fake-iquery" | "fetch-glue" | "flush-zones-on-shutdown" | "has-old-clients" | "host-statistics" | "maintain-ixfr-base" | "match-mapped-addresses" | "memstatistics" | "minimal-responses" | "multiple-cnames" | "notify-to-soa" | "provide-ixfr" | "querylog" | "recursion" | "request-ixfr" | "rfc2308-type1" | "treat-cr-as-space" | "try-tcp-refresh" | "update-check-ksk" | "use-alt-transfer-source" | "use-id-pool" | "use-ixfr" | "use-queryport-pool" | "zero-no-soa-ttl" | "zero-no-soa-ttl-cache" | "zone-statistics") ("yes" | "no")
+
+	let options_attr_number =
+		  attr_one ("acache-cleaning-interval" | "cleaning-interval" | "clients-per-query" | "edns-udp-size" | "heartbeat-interval" | "host-statistics-max" | "interface-interval" | "lame-ttl" | "max-cache-ttl" | "max-clients-per-query" | "max-ixfr-log-size" | "max-ncache-ttl" | "max-refresh-time" | "max-retry-time" | "max-transfer-idle-in" | "max-transfer-idle-out" | "max-transfer-time-in" | "max-transfer-time-out" | "max-udp-size" | "min-refresh-time" | "min-retry-time" | "min-roots" | "port" | "queryport-pool-ports" | "queryport-pool-updateinterval" | "recursive-clients" | "reserved-sockets" | "serial-queries" | "serial-query-rate" | "sig-signing-nodes" | "sig-signing-signatures" | "sig-signing-type" | "statistics-interval" | "tcp-clients" | "tcp-listen-queue" | "transfers-in" | "transfers-out" | "transfers-per-ns") (/[0-9]+/)
+
+
+	let options_attr_value =
+		  attr_one ("attach-cache" | "bindkeys-file" | "cache-file" | "check-dup-records" | "check-mx" | "check-mx-cname" | "check-srv-cname" | "dialup" | "directory" | "dump-file" | "forward" | "hostname" | "ixfr-from-differences" | "key-directory" | "memstatistics-file" | "named-xfer" | "notify" | "pid-file" | "random-device" | "recursing-file" | "server-id" | "statistics-file" | "tkey-domain" | "tkey-gssapi-credential" | "transfer-format" | "version") (/"[^"]+"/ | /[^" \t\n;]([^; \t\n]*[^" \t\n;])?/)
+
+	let forwarders_list =
+		    [label "ip" . store Rx.ipv4]
+	  
+	let options_forwarders =
+		  [ key "forwarders"
+		  . del chr_blank+ " "
+		  . body forwarders_list
+		  . semicolon ]
+
+	let options_re = (options_attr_boolean | options_attr_number | options_attr_value | options_forwarders)
+
+	let options =
+		  [ indent
+		  . key "options"
+		  . del /[ \t]+/ " "
+		  . body options_re
+		  . semicolon
+		  ]
+
+	let _ = print_regexp (lens_ctype options)
+	let _ = print_endline ""
+
+	let entries = ( [eol] | comment | acl | options )*
+
+	(* Group: Top of the tree *)
+
+	(* View: lns
+	 generic entries then programs or hostnames matching blocs
+	 *)
+        let lns = entries
+
+	(* Variable: filter
+	 all you need is /etc/namedb/named.conf
+	 *)
+        let filter = incl "/etc/namedb/named.conf"
+
+        let xfm = transform lns filter
diff --git a/lenses/tests/test_named.aug b/lenses/tests/test_named.aug
new file mode 100644
index 0000000..6b6d7f5
--- /dev/null
+++ b/lenses/tests/test_named.aug
@@ -0,0 +1,65 @@
+module Test_Named =
+
+	let comments="
+# foo
+// $FreeBSD: src/etc/namedb/named.conf,v 1.6.2.4 2001/12/05 22:10:12 cjc Exp $
+  /**/
+/* */
+/* bar */
+/*
+ * bar
+ */
+"
+
+	test Named.lns get comments =
+          { }
+	  { "#comment" = "foo" }
+          { "#inline" = "$FreeBSD: src/etc/namedb/named.conf,v 1.6.2.4 2001/12/05 22:10:12 cjc Exp $" }
+	  { "#comment" }
+	  { "#comment" }
+	  { "#comment"
+	    { "1" = "bar" }
+	  }
+	  { "#comment"
+	    { "1" = "* bar" }
+	  }
+
+	let acls = "acl friends {	192.0.2.0/25; # foo
+		127.0.0.1;
+};"
+
+	test Named.lns get acls =
+	  { "acl" = "friends"
+	    {  = "192.0.2.0/25" }
+	    { "#comment" = "foo" }
+	    {  = "127.0.0.1" }
+	    {  }
+	  }
+
+	let options = "options {
+	dnssec-enable yes;
+        request-ixfr yes;
+	tcp-clients 1234;
+	port 53;
+	version \"9.1\";
+	forward first;
+	forwarders {
+	  1.2.3.4;
+	};
+};"
+	test Named.lns get options =
+	  { "options"
+	    {  }
+	    { "dnssec-enable" = "yes" }
+	    {  }
+	    { "request-ixfr" = "yes" }
+	    {  }
+	    { "tcp-clients" = "1234" }
+	    {  }
+	    { "port" = "53" }
+	    {  }
+	    { "version" = "\"9.1\"" }
+	    {  }
+	    { "forward" = "first" }
+	    {  }
+	  }
-- 
1.7.4.4

>From 3a25ef9e349c6de4da5aca3a716fb277c4166567 Mon Sep 17 00:00:00 2001
From: David Lutterkort <[email protected]>
Date: Tue, 5 Jul 2011 16:42:58 -0700
Subject: [PATCH 2/4] Named: remove trailing whitespace and all tabs

No functional changes
---
 lenses/named.aug            |  312 +++++++++++++++++++++---------------------
 lenses/tests/test_named.aug |   90 ++++++------
 2 files changed, 201 insertions(+), 201 deletions(-)

diff --git a/lenses/named.aug b/lenses/named.aug
index 0750393..fa32186 100644
--- a/lenses/named.aug
+++ b/lenses/named.aug
@@ -22,169 +22,169 @@ About: Configuration files
 module Named =
   autoload xfm
 
-	(************************************************************************
-	 * Group:                 USEFUL PRIMITIVES
-	 *************************************************************************)
+    (************************************************************************
+     * Group:                 USEFUL PRIMITIVES
+     *************************************************************************)
 
-	(* Group: Comments and empty lines *)
+    (* Group: Comments and empty lines *)
 
-	(* Variable: empty *)
+    (* Variable: empty *)
         let empty      = Util.empty
-	(* Variable: eol *)
+    (* Variable: eol *)
         let eol        = Util.eol
-	(* Variable: sep_tab *)
+    (* Variable: sep_tab *)
         let sep_tab    = Sep.tab
-	(* Variable: indent *)
-	let indent     = Util.indent
-
-
-	let chr_blank = /[ \t]/
-	let chr_nblank = /[^ \t\n]/
-	let chr_any    = /./
-	let chr_star   = /\*/
-	let chr_nstar  = /[^\* \t\n]/
-	let chr_slash  = /\//
-	let chr_nslash = /[^\/ \t\n]/
-
-	(* Group: single characters macro *)
-
-	(* Variable: semicolon
-	 Deletes a semicolon and default to it
-	 *)
-	let semicolon  = del /[ \t]*;/ ";"
-
-	let sto_to_eol = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/
-
-	let subnet = Rx.ip | Rx.ip . /\/[0-9]+/
-
-	(************************************************************************
-	 * Group:                 LENSE DEFINITION
-	 *************************************************************************)
-
-
-	(************************************************************************
-	 *                              COMMENTS
-	 *************************************************************************)
-
-	let comment_re = chr_nblank
-		       | ( chr_nblank . chr_any*
-			   . ( chr_star  . chr_nslash
-			     | chr_nstar . chr_slash
-			     | chr_nstar . chr_nslash
-			     | chr_blank . chr_nblank ) )
-
-	let comment_first_line
-		       = [ del /([ \t]*\n)?[ \t]*/ ""
-			 . seq "#comment"
-			 . store comment_re
-			  ]
-	let comment_other_line
-		       = [ del /[ \t]*\n[ \t\n]*/ "\n"
-			 . seq "#comment"
-			 . store comment_re
-			  ]
-	let comment_end
-		       = del /[ \t\n]*/ "" . del (chr_star . chr_slash) "*/"
-
-	let comment_extended
-			 = [ indent
-			 . del (chr_slash . chr_star) "/*"
-			 . label "#comment"
-			 . counter "#comment"
-			 . ( (comment_first_line . comment_other_line+)
-			   | comment_first_line?)
-			 . comment_end
-			 . eol ]
-
-	let comment_inline
-			 = [ indent
-			 . del (chr_slash . chr_slash) "//"
-			 . label "#inline"
-			 . indent
-			 . sto_to_eol
-			 . eol ]
-
-	let comment      = comment_extended | comment_inline | Util.comment
-
-	(****
-	 * Generic functions
-	 *)
-
-	let body (attr:lens) = del /{/ "{"
-			     . ( [eol] 
-				 | comment
-				 | (indent . attr . semicolon) )*
-			     . del /[ \t]*}/ "}"
-
-	let group (name:string) (attr:lens) = 
-		  [ indent
-		  . Util.del_str name
-		  . del /[ \t]+/ " "
-		  . label name
-		  . store /[a-z]+/
-		  . del chr_blank* ""
-		  . body attr
-		  . semicolon
-		  ]
-
-	let attr_one (k:regexp) (v:regexp) =
-	  [key k . del chr_blank+  " " . store v]
-
-
-	(* ACL *)
-	(* missing the key possibility *)
-
-	let acl = 
-	  let acl_re = [store subnet] in
-	    group "acl" acl_re
-
-
-	(* Options *)
-
-	let options_attr_boolean =
-		  attr_one ( "acache-enable" | "additional-from-auth" | "additional-from-cache" | "auth-nxdomain" | "check-integrity" | "check-sibling" | "check-wildcard" | "deallocate-on-exit" | "dnssec-accept-expired" | "dnssec-dnskey-kskonly" | "dnssec-enable" | "dnssec-must-be-secure" | "dnssec-secure-to-insecure" | "dnssec-validation" | "empty-zones-enable" | "fake-iquery" | "fetch-glue" | "flush-zones-on-shutdown" | "has-old-clients" | "host-statistics" | "maintain-ixfr-base" | "match-mapped-addresses" | "memstatistics" | "minimal-responses" | "multiple-cnames" | "notify-to-soa" | "provide-ixfr" | "querylog" | "recursion" | "request-ixfr" | "rfc2308-type1" | "treat-cr-as-space" | "try-tcp-refresh" | "update-check-ksk" | "use-alt-transfer-source" | "use-id-pool" | "use-ixfr" | "use-queryport-pool" | "zero-no-soa-ttl" | "zero-no-soa-ttl-cache" | "zone-statistics") ("yes" | "no")
-
-	let options_attr_number =
-		  attr_one ("acache-cleaning-interval" | "cleaning-interval" | "clients-per-query" | "edns-udp-size" | "heartbeat-interval" | "host-statistics-max" | "interface-interval" | "lame-ttl" | "max-cache-ttl" | "max-clients-per-query" | "max-ixfr-log-size" | "max-ncache-ttl" | "max-refresh-time" | "max-retry-time" | "max-transfer-idle-in" | "max-transfer-idle-out" | "max-transfer-time-in" | "max-transfer-time-out" | "max-udp-size" | "min-refresh-time" | "min-retry-time" | "min-roots" | "port" | "queryport-pool-ports" | "queryport-pool-updateinterval" | "recursive-clients" | "reserved-sockets" | "serial-queries" | "serial-query-rate" | "sig-signing-nodes" | "sig-signing-signatures" | "sig-signing-type" | "statistics-interval" | "tcp-clients" | "tcp-listen-queue" | "transfers-in" | "transfers-out" | "transfers-per-ns") (/[0-9]+/)
-
-
-	let options_attr_value =
-		  attr_one ("attach-cache" | "bindkeys-file" | "cache-file" | "check-dup-records" | "check-mx" | "check-mx-cname" | "check-srv-cname" | "dialup" | "directory" | "dump-file" | "forward" | "hostname" | "ixfr-from-differences" | "key-directory" | "memstatistics-file" | "named-xfer" | "notify" | "pid-file" | "random-device" | "recursing-file" | "server-id" | "statistics-file" | "tkey-domain" | "tkey-gssapi-credential" | "transfer-format" | "version") (/"[^"]+"/ | /[^" \t\n;]([^; \t\n]*[^" \t\n;])?/)
-
-	let forwarders_list =
-		    [label "ip" . store Rx.ipv4]
-	  
-	let options_forwarders =
-		  [ key "forwarders"
-		  . del chr_blank+ " "
-		  . body forwarders_list
-		  . semicolon ]
-
-	let options_re = (options_attr_boolean | options_attr_number | options_attr_value | options_forwarders)
-
-	let options =
-		  [ indent
-		  . key "options"
-		  . del /[ \t]+/ " "
-		  . body options_re
-		  . semicolon
-		  ]
-
-	let _ = print_regexp (lens_ctype options)
-	let _ = print_endline ""
-
-	let entries = ( [eol] | comment | acl | options )*
-
-	(* Group: Top of the tree *)
-
-	(* View: lns
-	 generic entries then programs or hostnames matching blocs
-	 *)
+    (* Variable: indent *)
+    let indent     = Util.indent
+
+
+    let chr_blank = /[ \t]/
+    let chr_nblank = /[^ \t\n]/
+    let chr_any    = /./
+    let chr_star   = /\*/
+    let chr_nstar  = /[^\* \t\n]/
+    let chr_slash  = /\//
+    let chr_nslash = /[^\/ \t\n]/
+
+    (* Group: single characters macro *)
+
+    (* Variable: semicolon
+     Deletes a semicolon and default to it
+     *)
+    let semicolon  = del /[ \t]*;/ ";"
+
+    let sto_to_eol = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/
+
+    let subnet = Rx.ip | Rx.ip . /\/[0-9]+/
+
+    (************************************************************************
+     * Group:                 LENSE DEFINITION
+     *************************************************************************)
+
+
+    (************************************************************************
+     *                              COMMENTS
+     *************************************************************************)
+
+    let comment_re = chr_nblank
+               | ( chr_nblank . chr_any*
+               . ( chr_star  . chr_nslash
+                 | chr_nstar . chr_slash
+                 | chr_nstar . chr_nslash
+                 | chr_blank . chr_nblank ) )
+
+    let comment_first_line
+               = [ del /([ \t]*\n)?[ \t]*/ ""
+             . seq "#comment"
+             . store comment_re
+              ]
+    let comment_other_line
+               = [ del /[ \t]*\n[ \t\n]*/ "\n"
+             . seq "#comment"
+             . store comment_re
+              ]
+    let comment_end
+               = del /[ \t\n]*/ "" . del (chr_star . chr_slash) "*/"
+
+    let comment_extended
+             = [ indent
+             . del (chr_slash . chr_star) "/*"
+             . label "#comment"
+             . counter "#comment"
+             . ( (comment_first_line . comment_other_line+)
+               | comment_first_line?)
+             . comment_end
+             . eol ]
+
+    let comment_inline
+             = [ indent
+             . del (chr_slash . chr_slash) "//"
+             . label "#inline"
+             . indent
+             . sto_to_eol
+             . eol ]
+
+    let comment      = comment_extended | comment_inline | Util.comment
+
+    (****
+     * Generic functions
+     *)
+
+    let body (attr:lens) = del /{/ "{"
+                 . ( [eol]
+                 | comment
+                 | (indent . attr . semicolon) )*
+                 . del /[ \t]*}/ "}"
+
+    let group (name:string) (attr:lens) =
+          [ indent
+          . Util.del_str name
+          . del /[ \t]+/ " "
+          . label name
+          . store /[a-z]+/
+          . del chr_blank* ""
+          . body attr
+          . semicolon
+          ]
+
+    let attr_one (k:regexp) (v:regexp) =
+      [key k . del chr_blank+  " " . store v]
+
+
+    (* ACL *)
+    (* missing the key possibility *)
+
+    let acl =
+      let acl_re = [store subnet] in
+        group "acl" acl_re
+
+
+    (* Options *)
+
+    let options_attr_boolean =
+          attr_one ( "acache-enable" | "additional-from-auth" | "additional-from-cache" | "auth-nxdomain" | "check-integrity" | "check-sibling" | "check-wildcard" | "deallocate-on-exit" | "dnssec-accept-expired" | "dnssec-dnskey-kskonly" | "dnssec-enable" | "dnssec-must-be-secure" | "dnssec-secure-to-insecure" | "dnssec-validation" | "empty-zones-enable" | "fake-iquery" | "fetch-glue" | "flush-zones-on-shutdown" | "has-old-clients" | "host-statistics" | "maintain-ixfr-base" | "match-mapped-addresses" | "memstatistics" | "minimal-responses" | "multiple-cnames" | "notify-to-soa" | "provide-ixfr" | "querylog" | "recursion" | "request-ixfr" | "rfc2308-type1" | "treat-cr-as-space" | "try-tcp-refresh" | "update-check-ksk" | "use-alt-transfer-source" | "use-id-pool" | "use-ixfr" | "use-queryport-pool" | "zero-no-soa-ttl" | "zero-no-soa-ttl-cache" | "zone-statistics") ("yes" | "no")
+
+    let options_attr_number =
+          attr_one ("acache-cleaning-interval" | "cleaning-interval" | "clients-per-query" | "edns-udp-size" | "heartbeat-interval" | "host-statistics-max" | "interface-interval" | "lame-ttl" | "max-cache-ttl" | "max-clients-per-query" | "max-ixfr-log-size" | "max-ncache-ttl" | "max-refresh-time" | "max-retry-time" | "max-transfer-idle-in" | "max-transfer-idle-out" | "max-transfer-time-in" | "max-transfer-time-out" | "max-udp-size" | "min-refresh-time" | "min-retry-time" | "min-roots" | "port" | "queryport-pool-ports" | "queryport-pool-updateinterval" | "recursive-clients" | "reserved-sockets" | "serial-queries" | "serial-query-rate" | "sig-signing-nodes" | "sig-signing-signatures" | "sig-signing-type" | "statistics-interval" | "tcp-clients" | "tcp-listen-queue" | "transfers-in" | "transfers-out" | "transfers-per-ns") (/[0-9]+/)
+
+
+    let options_attr_value =
+          attr_one ("attach-cache" | "bindkeys-file" | "cache-file" | "check-dup-records" | "check-mx" | "check-mx-cname" | "check-srv-cname" | "dialup" | "directory" | "dump-file" | "forward" | "hostname" | "ixfr-from-differences" | "key-directory" | "memstatistics-file" | "named-xfer" | "notify" | "pid-file" | "random-device" | "recursing-file" | "server-id" | "statistics-file" | "tkey-domain" | "tkey-gssapi-credential" | "transfer-format" | "version") (/"[^"]+"/ | /[^" \t\n;]([^; \t\n]*[^" \t\n;])?/)
+
+    let forwarders_list =
+            [label "ip" . store Rx.ipv4]
+
+    let options_forwarders =
+          [ key "forwarders"
+          . del chr_blank+ " "
+          . body forwarders_list
+          . semicolon ]
+
+    let options_re = (options_attr_boolean | options_attr_number | options_attr_value | options_forwarders)
+
+    let options =
+          [ indent
+          . key "options"
+          . del /[ \t]+/ " "
+          . body options_re
+          . semicolon
+          ]
+
+    let _ = print_regexp (lens_ctype options)
+    let _ = print_endline ""
+
+    let entries = ( [eol] | comment | acl | options )*
+
+    (* Group: Top of the tree *)
+
+    (* View: lns
+     generic entries then programs or hostnames matching blocs
+     *)
         let lns = entries
 
-	(* Variable: filter
-	 all you need is /etc/namedb/named.conf
-	 *)
+    (* Variable: filter
+     all you need is /etc/namedb/named.conf
+     *)
         let filter = incl "/etc/namedb/named.conf"
 
         let xfm = transform lns filter
diff --git a/lenses/tests/test_named.aug b/lenses/tests/test_named.aug
index 6b6d7f5..da789c2 100644
--- a/lenses/tests/test_named.aug
+++ b/lenses/tests/test_named.aug
@@ -1,6 +1,6 @@
 module Test_Named =
 
-	let comments="
+    let comments="
 # foo
 // $FreeBSD: src/etc/namedb/named.conf,v 1.6.2.4 2001/12/05 22:10:12 cjc Exp $
   /**/
@@ -11,55 +11,55 @@ module Test_Named =
  */
 "
 
-	test Named.lns get comments =
+    test Named.lns get comments =
           { }
-	  { "#comment" = "foo" }
+      { "#comment" = "foo" }
           { "#inline" = "$FreeBSD: src/etc/namedb/named.conf,v 1.6.2.4 2001/12/05 22:10:12 cjc Exp $" }
-	  { "#comment" }
-	  { "#comment" }
-	  { "#comment"
-	    { "1" = "bar" }
-	  }
-	  { "#comment"
-	    { "1" = "* bar" }
-	  }
+      { "#comment" }
+      { "#comment" }
+      { "#comment"
+        { "1" = "bar" }
+      }
+      { "#comment"
+        { "1" = "* bar" }
+      }
 
-	let acls = "acl friends {	192.0.2.0/25; # foo
-		127.0.0.1;
+    let acls = "acl friends {   192.0.2.0/25; # foo
+        127.0.0.1;
 };"
 
-	test Named.lns get acls =
-	  { "acl" = "friends"
-	    {  = "192.0.2.0/25" }
-	    { "#comment" = "foo" }
-	    {  = "127.0.0.1" }
-	    {  }
-	  }
+    test Named.lns get acls =
+      { "acl" = "friends"
+        {  = "192.0.2.0/25" }
+        { "#comment" = "foo" }
+        {  = "127.0.0.1" }
+        {  }
+      }
 
-	let options = "options {
-	dnssec-enable yes;
+    let options = "options {
+    dnssec-enable yes;
         request-ixfr yes;
-	tcp-clients 1234;
-	port 53;
-	version \"9.1\";
-	forward first;
-	forwarders {
-	  1.2.3.4;
-	};
+    tcp-clients 1234;
+    port 53;
+    version \"9.1\";
+    forward first;
+    forwarders {
+      1.2.3.4;
+    };
 };"
-	test Named.lns get options =
-	  { "options"
-	    {  }
-	    { "dnssec-enable" = "yes" }
-	    {  }
-	    { "request-ixfr" = "yes" }
-	    {  }
-	    { "tcp-clients" = "1234" }
-	    {  }
-	    { "port" = "53" }
-	    {  }
-	    { "version" = "\"9.1\"" }
-	    {  }
-	    { "forward" = "first" }
-	    {  }
-	  }
+    test Named.lns get options =
+      { "options"
+        {  }
+        { "dnssec-enable" = "yes" }
+        {  }
+        { "request-ixfr" = "yes" }
+        {  }
+        { "tcp-clients" = "1234" }
+        {  }
+        { "port" = "53" }
+        {  }
+        { "version" = "\"9.1\"" }
+        {  }
+        { "forward" = "first" }
+        {  }
+      }
-- 
1.7.4.4

>From 627481cd2d9e4a89279fbeddf32107b7b874b970 Mon Sep 17 00:00:00 2001
From: David Lutterkort <[email protected]>
Date: Tue, 5 Jul 2011 16:44:18 -0700
Subject: [PATCH 3/4] Named: fix a couple problems

  * body: '{' and '}' are special in regexps, use '\{' and '\}'
  * options_forwarders: do not consume semicolon after '}'; body does that
---
 lenses/named.aug            |    7 +++----
 lenses/tests/test_named.aug |   24 ++++++++++++++++++++++++
 2 files changed, 27 insertions(+), 4 deletions(-)

diff --git a/lenses/named.aug b/lenses/named.aug
index fa32186..01717c7 100644
--- a/lenses/named.aug
+++ b/lenses/named.aug
@@ -110,11 +110,11 @@ module Named =
      * Generic functions
      *)
 
-    let body (attr:lens) = del /{/ "{"
+    let body (attr:lens) = del /\{/ "{"
                  . ( [eol]
                  | comment
                  | (indent . attr . semicolon) )*
-                 . del /[ \t]*}/ "}"
+                 . del /[ \t]*\}/ "}"
 
     let group (name:string) (attr:lens) =
           [ indent
@@ -157,8 +157,7 @@ module Named =
     let options_forwarders =
           [ key "forwarders"
           . del chr_blank+ " "
-          . body forwarders_list
-          . semicolon ]
+          . body forwarders_list ]
 
     let options_re = (options_attr_boolean | options_attr_number | options_attr_value | options_forwarders)
 
diff --git a/lenses/tests/test_named.aug b/lenses/tests/test_named.aug
index da789c2..76b921b 100644
--- a/lenses/tests/test_named.aug
+++ b/lenses/tests/test_named.aug
@@ -47,6 +47,24 @@ module Test_Named =
       1.2.3.4;
     };
 };"
+    test Named.forwarders_list get "1.2.3.4" = { "ip" = "1.2.3.4" }
+
+    test Named.options_forwarders get "forwarders {\n 1.2.3.4; \n  }" =
+    { "forwarders"
+        {  }
+        { "ip" = "1.2.3.4" }
+        {  } }
+
+
+    test Named.options get "options { \nforwarders {\n 1.2.3.4;\n };\n };" =
+      { "options"
+          {  }
+          { "forwarders"
+              {  }
+              { "ip" = "1.2.3.4" }
+              {  } }
+          {  } }
+
     test Named.lns get options =
       { "options"
         {  }
@@ -62,4 +80,10 @@ module Test_Named =
         {  }
         { "forward" = "first" }
         {  }
+        { "forwarders"
+            {  }
+            { "ip" = "1.2.3.4" }
+            {  }
+        }
+        {  }
       }
-- 
1.7.4.4

>From 2d541a1a383af2e6d963878625571742be1b3337 Mon Sep 17 00:00:00 2001
From: David Lutterkort <[email protected]>
Date: Tue, 5 Jul 2011 17:04:34 -0700
Subject: [PATCH 4/4] Named: do not create empty nodes for eol

If we attach the check for eol to other 'stuff', we do not get an ambiguity
in the tree, and hence don't need to use empty nodes to indicate where the
file has blank lines.

The ambiguity is caused by the fact that eol does not produce any tree
nodes, so a lens like (eol | foo)* is ambiguous in the put direction, since
we can use an arbitrary number of eol before any foo node when going from
tree to file
---
 lenses/named.aug            |   10 +++++-----
 lenses/tests/test_named.aug |   25 +++----------------------
 2 files changed, 8 insertions(+), 27 deletions(-)

diff --git a/lenses/named.aug b/lenses/named.aug
index 01717c7..d189370 100644
--- a/lenses/named.aug
+++ b/lenses/named.aug
@@ -110,11 +110,11 @@ module Named =
      * Generic functions
      *)
 
-    let body (attr:lens) = del /\{/ "{"
-                 . ( [eol]
-                 | comment
-                 | (indent . attr . semicolon) )*
-                 . del /[ \t]*\}/ "}"
+    let body (attr:lens) =
+      let line =
+          comment
+        | indent . attr . semicolon . eol* in
+      del /\{([ \t]*\n)?/ "{" . line* . del /[ \t]*\}/ "}"
 
     let group (name:string) (attr:lens) =
           [ indent
diff --git a/lenses/tests/test_named.aug b/lenses/tests/test_named.aug
index 76b921b..c313a4c 100644
--- a/lenses/tests/test_named.aug
+++ b/lenses/tests/test_named.aug
@@ -33,7 +33,6 @@ module Test_Named =
         {  = "192.0.2.0/25" }
         { "#comment" = "foo" }
         {  = "127.0.0.1" }
-        {  }
       }
 
     let options = "options {
@@ -51,39 +50,21 @@ module Test_Named =
 
     test Named.options_forwarders get "forwarders {\n 1.2.3.4; \n  }" =
     { "forwarders"
-        {  }
-        { "ip" = "1.2.3.4" }
-        {  } }
+        { "ip" = "1.2.3.4" } }
 
 
     test Named.options get "options { \nforwarders {\n 1.2.3.4;\n };\n };" =
       { "options"
-          {  }
           { "forwarders"
-              {  }
-              { "ip" = "1.2.3.4" }
-              {  } }
-          {  } }
+              { "ip" = "1.2.3.4" } } }
 
     test Named.lns get options =
       { "options"
-        {  }
         { "dnssec-enable" = "yes" }
-        {  }
         { "request-ixfr" = "yes" }
-        {  }
         { "tcp-clients" = "1234" }
-        {  }
         { "port" = "53" }
-        {  }
         { "version" = "\"9.1\"" }
-        {  }
         { "forward" = "first" }
-        {  }
         { "forwarders"
-            {  }
-            { "ip" = "1.2.3.4" }
-            {  }
-        }
-        {  }
-      }
+            { "ip" = "1.2.3.4" } } }
-- 
1.7.4.4

_______________________________________________
augeas-devel mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/augeas-devel

Reply via email to