Fix test_syslog.aug

Fix test_syslog.aug

module Test_syslog =

	let conf="# $FreeBSD: src/etc/syslog.conf,v 1.30.2.1 2009/08/03 08:13:06 kensmith Exp $
#

daemon.info                                     /var/log/cvsupd.log
security.*					-/var/log/security
*.notice;authpriv.none;kern.debug;lpr.info;mail.crit;news.err	/var/log/messages
uucp,news.crit                                          /var/log/spooler
*.emerg						*
daemon.!info					/var/log/foo
daemon.<=info					/var/log/foo
daemon.!<=info					/var/log/foo
*.*						@syslog.far.away
*.*						@syslog.far.away:123
*.*						foo,bar
*.*						|\"/usr/bin/soft arg\"
!startslip
# get that out
*.*						/var/log/slip.log
!pppd,ppp

*.*						/var/log/ppp.log
!+startslip
*.*						/var/log/slip.log
!-startslip
*.*						/var/log/slip.log
#!pppd
*.*						/var/log/ppp.log
+foo.example.com
daemon.info                                     /var/log/cvsupd.log
+foo.example.com,bar.example.com
daemon.info                                     /var/log/cvsupd.log
#+bar.example.com
daemon.info                                     /var/log/cvsupd.log
-foo.example.com
daemon.info                                     /var/log/cvsupd.log
+*
daemon.info                                     /var/log/cvsupd.log
!*
daemon.info                                     /var/log/cvsupd.log
*.=debug;\
        auth,authpriv.none;\
        news.none;mail.none     -/var/log/debug
"

	test Syslog.lns get conf =
          { "#comment" = "$FreeBSD: src/etc/syslog.conf,v 1.30.2.1 2009/08/03 08:13:06 kensmith Exp $" }
	  { }
	  { }
	  { "entry"
	    { "selector" { "facility" = "daemon" } { "level" = "info" } }
	    { "action" { "file" = "/var/log/cvsupd.log" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "security" } { "level" = "*" } }
	    { "action" { "no_sync" } { "file" = "/var/log/security" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "*" } { "level" = "notice" } }
	    { "selector" { "facility" = "authpriv" } { "level" = "none" } }
	    { "selector" { "facility" = "kern" } { "level" = "debug" } }
	    { "selector" { "facility" = "lpr" } { "level" = "info" } }
	    { "selector" { "facility" = "mail" } { "level" = "crit" } }
	    { "selector" { "facility" = "news" } { "level" = "err" } }
	    { "action" { "file" = "/var/log/messages" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "uucp" } { "facility" = "news" } { "level" = "crit" } }
	    { "action" { "file" = "/var/log/spooler" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "*" } { "level" = "emerg" } }
	    { "action" { "user" = "*" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "daemon" } { "comparison" = "!" } { "level" = "info" } }
	    { "action" { "file" = "/var/log/foo" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "daemon" } { "comparison" = "<=" } { "level" = "info" } }
	    { "action" { "file" = "/var/log/foo" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "daemon" } { "comparison" = "!<=" } { "level" = "info" } }
	    { "action" { "file" = "/var/log/foo" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "*" } { "level" = "*" } }
	    { "action" { "hostname" = "syslog.far.away" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "*" } { "level" = "*" } }
	    { "action" { "hostname" = "syslog.far.away" } { "port" = "123" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "*" } { "level" = "*" } }
	    { "action" { "user" = "foo" } { "user" = "bar" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "*" } { "level" = "*" } }
	    { "action" { "program" = "\"/usr/bin/soft arg\"" } }
	  }
	  { "program"
	    { "program" = "startslip" }
	    { "#comment" = "get that out" }
	    { "entry"
	      { "selector" { "facility" = "*" } { "level" = "*" } }
	      { "action" { "file" = "/var/log/slip.log" } }
	    }
	  }
	  { "program"
	    { "program" = "pppd" }
	    { "program" = "ppp" }
	    { }
	    { "entry"
	      { "selector" { "facility" = "*" } { "level" = "*" } }
	      { "action" { "file" = "/var/log/ppp.log" } }
	    }
	  }
	  { "program"
	    { "program" = "startslip" }
	    { "entry"
	      { "selector" { "facility" = "*" } { "level" = "*" } }
	      { "action" { "file" = "/var/log/slip.log" } }
	    }
	  }
	  { "program"
	    { "reverse" }
	    { "program" = "startslip" }
	    { "entry"
	      { "selector" { "facility" = "*" } { "level" = "*" } }
	      { "action" { "file" = "/var/log/slip.log" } }
	    }
	  }
	  { "program"
	    { "program" = "pppd" }
	    { "entry"
	      { "selector" { "facility" = "*" } { "level" = "*" } }
	      { "action" { "file" = "/var/log/ppp.log" } }
	    }
	  }
	  { "hostname"
	    { "hostname" = "foo.example.com" }
	    { "entry"
	      { "selector" { "facility" = "daemon" } { "level" = "info" } }
	      { "action" { "file" = "/var/log/cvsupd.log" } }
	    }
	  }
	  { "hostname"
	    { "hostname" = "foo.example.com" }
	    { "hostname" = "bar.example.com" }
	    { "entry"
	      { "selector" { "facility" = "daemon" } { "level" = "info" } }
	      { "action" { "file" = "/var/log/cvsupd.log" } }
	    }
	  }
	  { "hostname"
	    { "hostname" = "bar.example.com" }
	    { "entry"
	      { "selector" { "facility" = "daemon" } { "level" = "info" } }
	      { "action" { "file" = "/var/log/cvsupd.log" } }
	    }
	  }
	  { "hostname"
	    { "reverse" }
	    { "hostname" = "foo.example.com" }
	    { "entry"
	      { "selector" { "facility" = "daemon" } { "level" = "info" } }
	      { "action" { "file" = "/var/log/cvsupd.log" } }
	    }
	  }
	  { "hostname"
	    { "hostname" = "*" }
	    { "entry"
	      { "selector" { "facility" = "daemon" } { "level" = "info" } }
	      { "action" { "file" = "/var/log/cvsupd.log" } }
	    }
	  }
	  { "program"
	    { "program" = "*" }
	    { "entry"
	      { "selector" { "facility" = "daemon" } { "level" = "info" } }
	      { "action" { "file" = "/var/log/cvsupd.log" } } }
            { "entry"
              { "selector" { "facility" = "*" } { "comparison" = "=" } { "level" = "debug" } }
              { "selector" { "facility" = "auth" } { "facility" = "authpriv" } { "level" = "none" } }
              { "selector" { "facility" = "news" } { "level" = "none" } }
              { "selector" { "facility" = "mail" } { "level" = "none" } }
	      { "action" { "no_sync" } { "file" = "/var/log/debug" } } }
	  }

	(* changing file *)
	test Syslog.lns put "*.* /var\n" after
	  set "/entry[1]/action/file" "/foo"
	  = "*.* /foo\n"

	(* removing entry *)
	test Syslog.lns put "*.* /var\n" after
	  rm "/entry[1]"
	  = ""

	(* changing facility and level *)
	test Syslog.lns put "*.* /var\n" after
	  set "/entry[1]/selector/facility" "daemon" ;
	  set "/entry[1]/selector/level" "info"
	  = "daemon.info /var\n"

	(* insert a facility *)
	test Syslog.lns put "daemon.* /var\n" after
	  insa "facility" "/entry/selector/facility" ;
	  set "/entry/selector/facility[2]" "mail"
	  = "daemon,mail.* /var\n"

	(* creating an entry *)
	test Syslog.lns put "" after
	  set "/entry/selector/facility" "daemon" ;
	  set "/entry/selector/level" "info" ;
	  set "/entry/action/file" "/var"
	  = "daemon.info\t/var\n"

	(* inserting an entry before *)
	test Syslog.lns put "*.* /var\n" after
	  insb "entry" "/entry" ;
	  set "/entry[1]/selector/facility" "daemon" ;
	  set "/entry[1]/selector/level" "info" ;
	  set "/entry[1]/action/file" "/foo"
	  = "daemon.info /foo\n*.*\t/var\n"

	(* inserting an entry after *)
	test Syslog.lns put "*.* /var\n" after
	  insa "entry" "/entry" ;
	  set "/entry[2]/selector/facility" "daemon" ;
	  set "/entry[2]/selector/level" "info" ;
	  set "/entry[2]/action/file" "/foo"
	  = "*.* /var\ndaemon.info\t/foo\n"

	(* insert sync on a file *)
	test Syslog.lns put "*.* /var\n" after
	  insb "no_sync" "/entry/action/file"
	  = "*.* -/var\n"

	(* changing file to remote host *)
	test Syslog.lns put "*.* /var\n" after
	  rm "/entry/action/file" ;
	  set "/entry/action/hostname" "far.far.away"
	  = "*.* @far.far.away\n"

	(* changing file to * *)
	test Syslog.lns put "*.* /var\n" after
	  rm "/entry/action/file" ;
	  set "/entry/action/user" "*"
	  = "*.* *\n"

	(* changing file to users *)
	test Syslog.lns put "*.* /var\n" after
	  rm "/entry/action/file" ;
	  set "/entry/action/user[1]" "john" ;
	  set "/entry/action/user[2]" "paul" ;
	  set "/entry/action/user[3]" "george" ;
	  set "/entry/action/user[4]" "ringo"
	  = "*.* john,paul,george,ringo\n"

	(* changing file to program *)
	test Syslog.lns put "*.* /var\n" after
	  rm "/entry/action/file" ;
	  set "/entry/action/program" "/usr/bin/foo"
	  = "*.* |/usr/bin/foo\n"

	(* inserting a matching program *)
	test Syslog.lns put "" after
	  insa "program" "/" ;
	  set "/program/program" "foo"
	  = "!foo\n"

	(* inserting an entry to a matching program *)
	test Syslog.lns put "!foo\n" after
	  set "/program/entry/selector/facility" "*" ;
	  set "/program/entry/selector/level" "*" ;
	  set "/program/entry/action/file" "/foo"
	  = "!foo\n*.*\t/foo\n"

	(* inserting a matching hostname *)
	test Syslog.lns put "" after
	  insa "hostname" "/" ;
	  set "/hostname/hostname" "foo.foo.away"
	  = "+foo.foo.away\n"

	(* inserting an entry to a matching hostname *)
	test Syslog.lns put "+foo.foo.away\n" after
	  set "/hostname/entry/selector/facility" "*" ;
	  set "/hostname/entry/selector/level" "*" ;
	  set "/hostname/entry/action/file" "/foo"
	  = "+foo.foo.away\n*.*\t/foo\n"

	(* inserting a reverse matching hostname *)
	test Syslog.lns put "" after
	  insa "hostname" "/" ;
	  set "/hostname/reverse" "" ;
	  set "/hostname/hostname" "foo.foo.away"
	  = "-foo.foo.away\n"

        (* tokens can contain capital letters *)
        test Syslog.lns get "LOCAL5.*    -/var/log/foo.log\n" =
          { "entry"
            { "selector"
              { "facility" = "LOCAL5" }
              { "level" = "*" }
            }
            { "action"
              { "no_sync" }
              { "file" = "/var/log/foo.log" }
            }
          }

module Test_syslog =

	let conf="# $FreeBSD: src/etc/syslog.conf,v 1.30.2.1 2009/08/03 08:13:06 kensmith Exp $
#

daemon.info                                     /var/log/cvsupd.log
security.*					-/var/log/security
*.notice;authpriv.none;kern.debug;lpr.info;mail.crit;news.err	/var/log/messages
uucp,news.crit                                          /var/log/spooler
*.emerg						*
daemon.!info					/var/log/foo
daemon.<=info					/var/log/foo
daemon.!<=info					/var/log/foo
*.*						@syslog.far.away
*.*						@syslog.far.away:123
*.*						foo,bar
*.*						|\"/usr/bin/soft arg\"
!startslip
# get that out
*.*						/var/log/slip.log
!pppd,ppp

*.*						/var/log/ppp.log
!+startslip
*.*						/var/log/slip.log
!-startslip
*.*						/var/log/slip.log
#!pppd
*.*						/var/log/ppp.log
+foo.example.com
daemon.info                                     /var/log/cvsupd.log
+foo.example.com,bar.example.com
daemon.info                                     /var/log/cvsupd.log
#+bar.example.com
daemon.info                                     /var/log/cvsupd.log
-foo.example.com
daemon.info                                     /var/log/cvsupd.log
+*
daemon.info                                     /var/log/cvsupd.log
!*
daemon.info                                     /var/log/cvsupd.log
*.=debug;\
        auth,authpriv.none;\
        news.none;mail.none     -/var/log/debug
"

	test Syslog.lns get conf =
          { "#comment" = "$FreeBSD: src/etc/syslog.conf,v 1.30.2.1 2009/08/03 08:13:06 kensmith Exp $" }
	  { }
	  { }
	  { "entry"
	    { "selector" { "facility" = "daemon" } { "level" = "info" } }
	    { "action" { "file" = "/var/log/cvsupd.log" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "security" } { "level" = "*" } }
	    { "action" { "no_sync" } { "file" = "/var/log/security" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "*" } { "level" = "notice" } }
	    { "selector" { "facility" = "authpriv" } { "level" = "none" } }
	    { "selector" { "facility" = "kern" } { "level" = "debug" } }
	    { "selector" { "facility" = "lpr" } { "level" = "info" } }
	    { "selector" { "facility" = "mail" } { "level" = "crit" } }
	    { "selector" { "facility" = "news" } { "level" = "err" } }
	    { "action" { "file" = "/var/log/messages" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "uucp" } { "facility" = "news" } { "level" = "crit" } }
	    { "action" { "file" = "/var/log/spooler" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "*" } { "level" = "emerg" } }
	    { "action" { "user" = "*" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "daemon" } { "comparison" = "!" } { "level" = "info" } }
	    { "action" { "file" = "/var/log/foo" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "daemon" } { "comparison" = "<=" } { "level" = "info" } }
	    { "action" { "file" = "/var/log/foo" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "daemon" } { "comparison" = "!<=" } { "level" = "info" } }
	    { "action" { "file" = "/var/log/foo" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "*" } { "level" = "*" } }
	    { "action" { "hostname" = "syslog.far.away" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "*" } { "level" = "*" } }
	    { "action" { "hostname" = "syslog.far.away" } { "port" = "123" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "*" } { "level" = "*" } }
	    { "action" { "user" = "foo" } { "user" = "bar" } }
	  }
	  { "entry"
	    { "selector" { "facility" = "*" } { "level" = "*" } }
	    { "action" { "program" = "\"/usr/bin/soft arg\"" } }
	  }
	  { "program"
	    { "program" = "startslip" }
	    { "#comment" = "get that out" }
	    { "entry"
	      { "selector" { "facility" = "*" } { "level" = "*" } }
	      { "action" { "file" = "/var/log/slip.log" } }
	    }
	  }
	  { "program"
	    { "program" = "pppd" }
	    { "program" = "ppp" }
	    { }
	    { "entry"
	      { "selector" { "facility" = "*" } { "level" = "*" } }
	      { "action" { "file" = "/var/log/ppp.log" } }
	    }
	  }
	  { "program"
	    { "program" = "startslip" }
	    { "entry"
	      { "selector" { "facility" = "*" } { "level" = "*" } }
	      { "action" { "file" = "/var/log/slip.log" } }
	    }
	  }
	  { "program"
	    { "reverse" }
	    { "program" = "startslip" }
	    { "entry"
	      { "selector" { "facility" = "*" } { "level" = "*" } }
	      { "action" { "file" = "/var/log/slip.log" } }
	    }
	  }
	  { "program"
	    { "program" = "pppd" }
	    { "entry"
	      { "selector" { "facility" = "*" } { "level" = "*" } }
	      { "action" { "file" = "/var/log/ppp.log" } }
	    }
	  }
	  { "hostname"
	    { "hostname" = "foo.example.com" }
	    { "entry"
	      { "selector" { "facility" = "daemon" } { "level" = "info" } }
	      { "action" { "file" = "/var/log/cvsupd.log" } }
	    }
	  }
	  { "hostname"
	    { "hostname" = "foo.example.com" }
	    { "hostname" = "bar.example.com" }
	    { "entry"
	      { "selector" { "facility" = "daemon" } { "level" = "info" } }
	      { "action" { "file" = "/var/log/cvsupd.log" } }
	    }
	  }
	  { "hostname"
	    { "hostname" = "bar.example.com" }
	    { "entry"
	      { "selector" { "facility" = "daemon" } { "level" = "info" } }
	      { "action" { "file" = "/var/log/cvsupd.log" } }
	    }
	  }
	  { "hostname"
	    { "reverse" }
	    { "hostname" = "foo.example.com" }
	    { "entry"
	      { "selector" { "facility" = "daemon" } { "level" = "info" } }
	      { "action" { "file" = "/var/log/cvsupd.log" } }
	    }
	  }
	  { "hostname"
	    { "hostname" = "*" }
	    { "entry"
	      { "selector" { "facility" = "daemon" } { "level" = "info" } }
	      { "action" { "file" = "/var/log/cvsupd.log" } }
	    }
	  }
	  { "program"
	    { "program" = "*" }
	    { "entry"
	      { "selector" { "facility" = "daemon" } { "level" = "info" } }
	      { "action" { "file" = "/var/log/cvsupd.log" } } }
            { "entry"
              { "selector" { "facility" = "*" } { "comparison" = "=" } { "level" = "debug" } }
              { "selector" { "facility" = "auth" } { "facility" = "authpriv" } { "level" = "none" } }
              { "selector" { "facility" = "news" } { "level" = "none" } }
              { "selector" { "facility" = "mail" } { "level" = "none" } }
	      { "action" { "no_sync" } { "file" = "/var/log/debug" } } }
	  }

	(* changing file *)
	test Syslog.lns put "*.* /var\n" after
	  set "/entry[1]/action/file" "/foo"
	  = "*.* /foo\n"

	(* removing entry *)
	test Syslog.lns put "*.* /var\n" after
	  rm "/entry[1]"
	  = ""

	(* changing facility and level *)
	test Syslog.lns put "*.* /var\n" after
	  set "/entry[1]/selector/facility" "daemon" ;
	  set "/entry[1]/selector/level" "info"
	  = "daemon.info /var\n"

	(* insert a facility *)
	test Syslog.lns put "daemon.* /var\n" after
	  insa "facility" "/entry/selector/facility" ;
	  set "/entry/selector/facility[2]" "mail"
	  = "daemon,mail.* /var\n"

	(* creating an entry *)
	test Syslog.lns put "" after
	  set "/entry/selector/facility" "daemon" ;
	  set "/entry/selector/level" "info" ;
	  set "/entry/action/file" "/var"
	  = "daemon.info\t/var\n"

	(* inserting an entry before *)
	test Syslog.lns put "*.* /var\n" after
	  insb "entry" "/entry" ;
	  set "/entry[1]/selector/facility" "daemon" ;
	  set "/entry[1]/selector/level" "info" ;
	  set "/entry[1]/action/file" "/foo"
	  = "daemon.info /foo\n*.*\t/var\n"

	(* inserting an entry after *)
	test Syslog.lns put "*.* /var\n" after
	  insa "entry" "/entry" ;
	  set "/entry[2]/selector/facility" "daemon" ;
	  set "/entry[2]/selector/level" "info" ;
	  set "/entry[2]/action/file" "/foo"
	  = "*.* /var\ndaemon.info\t/foo\n"

	(* insert sync on a file *)
	test Syslog.lns put "*.* /var\n" after
	  insb "no_sync" "/entry/action/file"
	  = "*.* -/var\n"

	(* changing file to remote host *)
	test Syslog.lns put "*.* /var\n" after
	  rm "/entry/action/file" ;
	  set "/entry/action/hostname" "far.far.away"
	  = "*.* @far.far.away\n"

	(* changing file to * *)
	test Syslog.lns put "*.* /var\n" after
	  rm "/entry/action/file" ;
	  set "/entry/action/user" "*"
	  = "*.* *\n"

	(* changing file to users *)
	test Syslog.lns put "*.* /var\n" after
	  rm "/entry/action/file" ;
	  set "/entry/action/user[1]" "john" ;
	  set "/entry/action/user[2]" "paul" ;
	  set "/entry/action/user[3]" "george" ;
	  set "/entry/action/user[4]" "ringo"
	  = "*.* john,paul,george,ringo\n"

	(* changing file to program *)
	test Syslog.lns put "*.* /var\n" after
	  rm "/entry/action/file" ;
	  set "/entry/action/program" "/usr/bin/foo"
	  = "*.* |/usr/bin/foo\n"

	(* inserting a matching program *)
	test Syslog.lns put "" after
	  insa "program" "/" ;
	  set "/program/program" "foo"
	  = "!foo\n"

	(* inserting an entry to a matching program *)
	test Syslog.lns put "!foo\n" after
	  set "/program/entry/selector/facility" "*" ;
	  set "/program/entry/selector/level" "*" ;
	  set "/program/entry/action/file" "/foo"
	  = "!foo\n*.*\t/foo\n"

	(* inserting a matching hostname *)
	test Syslog.lns put "" after
	  insa "hostname" "/" ;
	  set "/hostname/hostname" "foo.foo.away"
	  = "+foo.foo.away\n"

	(* inserting an entry to a matching hostname *)
	test Syslog.lns put "+foo.foo.away\n" after
	  set "/hostname/entry/selector/facility" "*" ;
	  set "/hostname/entry/selector/level" "*" ;
	  set "/hostname/entry/action/file" "/foo"
	  = "+foo.foo.away\n*.*\t/foo\n"

	(* inserting a reverse matching hostname *)
	test Syslog.lns put "" after
	  insa "hostname" "/" ;
	  set "/hostname/reverse" "" ;
	  set "/hostname/hostname" "foo.foo.away"
	  = "-foo.foo.away\n"

        (* tokens can contain capital letters *)
        test Syslog.lns get "LOCAL5.*    -/var/log/foo.log\n" = ?
          { "entry"
            { "selector"
              { "facility" = "LOCAL5" }
              { "level" = "*" }
            }
            { "action"
              { "no_sync" }
              { "file" = "/var/log/foo.log" }
            }
          }


Modified yum spec that seems to work

Modified yum spec that seems to work

# Parsing inistyle files

map
  grammar yum
  include '/etc/yum.conf' '/system/config/yum'
end

grammar yum

  token EOL /\n/ = '\n'
  token INDENT /[ \t]+/ = '\t'
  token EQ /\s*=\s*/ =  '='
  token COMMENT /[ \t]*(#|REM|rem).*\n/ = '# \n'

  file: ( comment | section ) *

  comment: [ COMMENT ]

  section: [
             '[' . key ... . ']' . EOL .
             ( comment | kv ) *
           ]

  kv: [ key ... . EQ . store ... . EOL ]

end

# Parsing inistyle files

#map
#  grammar yum
#  include '/etc/yum.conf' '/system/config/yum'
#end

grammar yum
  token EOL /\n/ = '\n'

  token INDENT /[ \t]+/ = '\t'

  token EQ /\s*=\s*/ =  '='

  token OPT_WS /[ \t]*/ = ''

  file: ( comment | section ) *

  comment: OPT_WS . ( /#.*/ | 'REM' | 'rem' )? . EOL

  section: [
             '[' . key ... . ']' . EOL .
             ( comment | kv ) *
           ]

  kv: [ key ... . EQ . store ... . EOL ]

end


Fix example in lens

Fix example in lens

(*
Module: Cron
 Parses /etc/cron.d/*, /etc/crontab

Author: Raphael Pinson <raphink@gmail.com>

About: Reference
 This lens tries to keep as close as possible to `man 5 crontab` where
 possible.

About: License
  This file is licensed under the GPL.

About: Lens Usage
  Sample usage of this lens in augtool

    * Get the entry that launches '/usr/bin/ls'
      >  match '/files/etc/crontab/entry[. = "/usr/bin/ls"]'

About: Configuration files
  This lens applies to /etc/cron.d/* and /etc/crontab. See <filter>.
*)

module Cron =
  autoload xfm

(************************************************************************
 * Group:                 USEFUL PRIMITIVES
 *************************************************************************)

(* Group: Generic primitives *)

(* Variable: eol *)
let eol     = Util.eol

(* Variable: indent *)
let indent  = Util.indent

(* Variable: comment *)
let comment = Util.comment

(* Variable: empty *)
let empty   = Util.empty

(* Variable: num *)
let num        = /[0-9\*][0-9\/,-\*]*/

(* Variable: alpha *)
let alpha      = /[A-Za-z]{3}/

(* Variable: alphanum *)
let alphanum   = num | alpha

(* Group: Separators *)

(* Variable: sep_spc *)
let sep_spc = Util.del_ws_spc

(* Variable: sep_eq *)
let sep_eq  = Util.del_str "="

(************************************************************************
 * Group:                       ENTRIES
 *************************************************************************)

(************************************************************************
 * View: shellvar
 *   A shell variable in crontab
 *************************************************************************)

let shellvar =
  let key_re = Shellvars.key_re - "entry" in
  [ key key_re . sep_eq . Shellvars.simple_value . eol ]

(* View: minute *)
let minute     = [ label "minute"       . store num ]

(* View: hour *)
let hour       = [ label "hour"         . store num ]

(* View: dayofmonth *)
let dayofmonth = [ label "dayofmonth" . store num ]

(* View: month *)
let month      = [ label "month"        . store alphanum ]

(* View: dayofweek *)
let dayofweek  = [ label "dayofweek"  . store alphanum ]

(* View: user *)
let user       = [ label "user"         . store Rx.word ]

(************************************************************************
 * View: time
 *   Time in the format "minute hour dayofmonth month dayofweek"
 *************************************************************************)
let time        = [ label "time" .
                  minute . sep_spc . hour  . sep_spc . dayofmonth
                         . sep_spc . month . sep_spc . dayofweek ]

(* Variable: the valid values for schedules *)
let schedule_re = "reboot" | "yearly" | "annually" | "monthly"
                | "weekly" | "daily"  | "midnight" | "hourly"

(************************************************************************
 * View: schedule
 *   Time in the format "@keyword"
 *************************************************************************)
let schedule    = [ label "schedule" . Util.del_str "@"
                   . store schedule_re ]

(************************************************************************
 * View: entry
 *   A crontab entry
 *************************************************************************)

let entry       = [ label "entry" . indent
                   . ( time | schedule )
                   . sep_spc . user
                   . sep_spc . store Rx.space_in . eol ]

(*
 * View: lns
 *   The cron lens
 *)
let lns = ( empty | comment | shellvar | entry )*

(* Variable: filter *)
let filter =
  incl "/etc/cron.d/*" .
  incl "/etc/crontab" .
  Util.stdexcl

let xfm = transform lns filter

(*
Module: Cron
 Parses /etc/cron.d/*, /etc/crontab

Author: Raphael Pinson <raphink@gmail.com>

About: Reference
 This lens tries to keep as close as possible to `man 5 crontab` where
 possible.

About: License
  This file is licensed under the GPL.

About: Lens Usage
  Sample usage of this lens in augtool

    * Get the identifier of the devices with a "Clone" option:
      > match "/files/etc/X11/xorg.conf/Device[Option = 'Clone']/Identifier"

About: Configuration files
  This lens applies to /etc/cron.d/* and /etc/crontab. See <filter>.
*)

module Cron =
  autoload xfm

(************************************************************************
 * Group:                 USEFUL PRIMITIVES
 *************************************************************************)

(* Group: Generic primitives *)

(* Variable: eol *)
let eol     = Util.eol

(* Variable: indent *)
let indent  = Util.indent

(* Variable: comment *)
let comment = Util.comment

(* Variable: empty *)
let empty   = Util.empty

(* Variable: num *)
let num        = /[0-9\*][0-9\/,-\*]*/

(* Variable: alpha *)
let alpha      = /[A-Za-z]{3}/

(* Variable: alphanum *)
let alphanum   = num | alpha

(* Group: Separators *)

(* Variable: sep_spc *)
let sep_spc = Util.del_ws_spc

(* Variable: sep_eq *)
let sep_eq  = Util.del_str "="

(************************************************************************
 * Group:                       ENTRIES
 *************************************************************************)

(************************************************************************
 * View: shellvar
 *   A shell variable in crontab
 *************************************************************************)

let shellvar =
  let key_re = Shellvars.key_re - "entry" in
  [ key key_re . sep_eq . Shellvars.simple_value . eol ]

(* View: minute *)
let minute     = [ label "minute"       . store num ]

(* View: hour *)
let hour       = [ label "hour"         . store num ]

(* View: dayofmonth *)
let dayofmonth = [ label "dayofmonth" . store num ]

(* View: month *)
let month      = [ label "month"        . store alphanum ]

(* View: dayofweek *)
let dayofweek  = [ label "dayofweek"  . store alphanum ]

(* View: user *)
let user       = [ label "user"         . store Rx.word ]

(************************************************************************
 * View: time
 *   Time in the format "minute hour dayofmonth month dayofweek"
 *************************************************************************)
let time        = [ label "time" .
                  minute . sep_spc . hour  . sep_spc . dayofmonth
                         . sep_spc . month . sep_spc . dayofweek ]

(* Variable: the valid values for schedules *)
let schedule_re = "reboot" | "yearly" | "annually" | "monthly"
                | "weekly" | "daily"  | "midnight" | "hourly"

(************************************************************************
 * View: schedule
 *   Time in the format "@keyword"
 *************************************************************************)
let schedule    = [ label "schedule" . Util.del_str "@"
                   . store schedule_re ]

(************************************************************************
 * View: entry
 *   A crontab entry
 *************************************************************************)

let entry       = [ label "entry" . indent
                   . ( time | schedule )
                   . sep_spc . user
                   . sep_spc . store Rx.space_in . eol ]

(*
 * View: lns
 *   The cron lens
 *)
let lns = ( empty | comment | shellvar | entry )*

(* Variable: filter *)
let filter =
  incl "/etc/cron.d/*" .
  incl "/etc/crontab" .
  Util.stdexcl

let xfm = transform lns filter


Add ocsinventory-agent.cfg to SimpleVars (#637)

(*
Module: Simplevars
  Parses simple key = value conffiles

Author: Raphael Pinson <raphink@gmail.com>

About: License
   This file is licenced under the LGPL v2+, like the rest of Augeas.

About: Lens Usage
   To be documented

About: Examples
   The <Test_Simplevars> file contains various examples and tests.
*)

module Simplevars =

autoload xfm

(* Variable: to_comment_re
   The regexp to match the value *)
let to_comment_re =
     let to_comment_squote = /'[^\n']*'/
  in let to_comment_dquote = /"[^\n"]*"/
  in let to_comment_noquote = /[^\n \t'"#][^\n#]*[^\n \t#]|[^\n \t'"#]/
  in to_comment_squote | to_comment_dquote | to_comment_noquote

(* View: entry *)
let entry =
     let some_value = Sep.space_equal . store to_comment_re
     (* Avoid ambiguity in tree by making a subtree here *)
  in let empty_value = [del /[ \t]*=/ "="] . store ""
  in [ Util.indent . key Rx.word
            . (some_value? | empty_value)
            . (Util.eol | Util.comment_eol) ]

(* View: lns *)
let lns = (Util.empty | Util.comment | entry)*

(* Variable: filter *)
let filter = incl "/etc/kernel-img.conf"
           . incl "/etc/kerneloops.conf"
           . incl "/etc/wgetrc"
           . incl "/etc/zabbix/*.conf"
           . incl "/etc/audit/auditd.conf"
           . incl "/etc/mixerctl.conf"
           . incl "/etc/wsconsctlctl.conf"
           . incl "/etc/ocsinventory/ocsinventory-agent.cfg"

let xfm = transform lns filter

(*
Module: Simplevars
  Parses simple key = value conffiles

Author: Raphael Pinson <raphink@gmail.com>

About: License
   This file is licenced under the LGPL v2+, like the rest of Augeas.

About: Lens Usage
   To be documented

About: Examples
   The <Test_Simplevars> file contains various examples and tests.
*)

module Simplevars =

autoload xfm

(* Variable: to_comment_re
   The regexp to match the value *)
let to_comment_re =
     let to_comment_squote = /'[^\n']*'/
  in let to_comment_dquote = /"[^\n"]*"/
  in let to_comment_noquote = /[^\n \t'"#][^\n#]*[^\n \t#]|[^\n \t'"#]/
  in to_comment_squote | to_comment_dquote | to_comment_noquote

(* View: entry *)
let entry =
     let some_value = Sep.space_equal . store to_comment_re
     (* Avoid ambiguity in tree by making a subtree here *)
  in let empty_value = [del /[ \t]*=/ "="] . store ""
  in [ Util.indent . key Rx.word
            . (some_value? | empty_value)
            . (Util.eol | Util.comment_eol) ]

(* View: lns *)
let lns = (Util.empty | Util.comment | entry)*

(* Variable: filter *)
let filter = incl "/etc/kernel-img.conf"
           . incl "/etc/kerneloops.conf"
           . incl "/etc/wgetrc"
           . incl "/etc/zabbix/*.conf"
           . incl "/etc/audit/auditd.conf"
           . incl "/etc/mixerctl.conf"
           . incl "/etc/wsconsctlctl.conf"

let xfm = transform lns filter


Add Util.doseol

Add Util.doseol

(*
Module: Util
  Generic module providing useful primitives

Author: David Lutterkort

About: License
  This file is licensed under the LGPLv2+, like the rest of Augeas.
*)

module Util =

(*
Variable: del_str
  Delete a string and default to it

  Parameters:
     s:string - the string to delete and default to
*)
  let del_str (s:string) = del s s

(*
Variable: del_ws
  Delete mandatory whitespace
*)
  let del_ws = del /[ \t]+/

(*
Variable: del_ws_spc
  Delete mandatory whitespace, default to single space
*)
  let del_ws_spc = del_ws " "

(*
Variable: del_ws_tab
  Delete mandatory whitespace, default to single tab
*)
  let del_ws_tab = del_ws "\t"

(*
Variable: del_opt_ws
  Delete optional whitespace
*)
  let del_opt_ws = del /[ \t]*/

(*
Variable: eol
  Delete end of line, including optional trailing whitespace
*)
  let eol = del /[ \t]*\n/ "\n"

(*
Variable: doseol
  Delete end of line with optional carriage return,
  including optional trailing whitespace
*)
  let doseol = del /[ \t]*\r?\n/ "\n"

(*
Variable: indent
  Delete indentation, including leading whitespace
*)
  let indent = del /[ \t]*/ ""

(* Group: Comment
     This is a general definition of comment
     It allows indentation for comments, removes the leading and trailing spaces
     of comments and stores them in nodes, except for empty comments which are
     ignored together with empty lines

View: comment_generic
  Map comments and set default comment sign
*)

  let comment_generic (r:regexp) (d:string) =
    [ label "#comment" . del r d
        . store /([^ \t\r\n].*[^ \t\r\n]|[^ \t\r\n])/ . eol ]

(* View: comment
  Map comments into "#comment" nodes
*)
  let comment = comment_generic /[ \t]*#[ \t]*/ "# "

(* View: comment_noindent
  Map comments into "#comment" nodes, without indentation
*)
  let comment_noindent = comment_generic /#[ \t]*/ "# "

(* View: comment_eol
  Map eol comments into "#comment" nodes
  Add a space before # for end of line comments
*)
  let comment_eol = comment_generic /[ \t]*#[ \t]*/ " # "

(* View: comment_or_eol
    A <comment_eol> or <eol>, with an optional empty comment *)
 let comment_or_eol = comment_eol | (del /[ \t]*(#[ \t]*)?\r?\n/ "\n")

(* View: comment_multiline
    A C-style multiline comment *)
  let comment_multiline =
     let mline_re = (/[^ \t\r\n].*[^ \t\r\n]|[^ \t\r\n]/ - /.*\*\/.*/) in
     let mline = [ seq "mline"
                 . del /[ \t\r\n]*/ "\n"
                 . store mline_re ] in
     [ label "#mcomment" . del /[ \t]*\/\*/ "/*"
       . counter "mline"
       . mline . (eol . mline)*
       . del /[ \t\r\n]*\*\/[ \t]*\r?\n/ "\n*/\n" ]

(* View: comment_c_style
    A comment line, C-style *)
  let comment_c_style =
    comment_generic /[ \t]*\/\/[ \t]*/ "// "

(* View: empty_generic
  A generic definition of <empty>
  Map empty lines, including empty comments *)
  let empty_generic (r:regexp) =
    [ del r "" . del_str "\n" ]

(* View: empty
  Map empty lines, including empty comments *)
  let empty = empty_generic /[ \t]*#?[ \t]*/

(* View: empty_c_style
  Map empty lines, including C-style empty comment *)
  let empty_c_style =
    empty_generic /[ \t]*((\/\/)|(\/\*[ \t]*\*\/))?[ \t]*/

(* View: Split *)
(* Split (SEP . ELT)* into an array-like tree where each match for ELT *)
(* appears in a separate subtree. The labels for the subtrees are      *)
(* consecutive numbers, starting at 0                                  *)
  let split (elt:lens) (sep:lens) =
    let sym = gensym "split" in
    counter sym . ( [ seq sym . sep . elt ] ) *

(* View: delim *)
  let delim (op:string) = del (/[ \t]*/ . op . /[ \t]*/)
                              (" " . op . " ")

(* Group: Exclusions

Variable: stdexcl
  Exclusion for files that are commonly not wanted/needed
*)
  let stdexcl = (excl "*~") .
    (excl "*.rpmnew") .
    (excl "*.rpmsave") .
    (excl "*.dpkg-old") .
    (excl "*.dpkg-new") .
    (excl "*.dpkg-bak") .
    (excl "*.dpkg-dist") .
    (excl "*.augsave") .
    (excl "*.augnew")

(*
Module: Util
  Generic module providing useful primitives

Author: David Lutterkort

About: License
  This file is licensed under the LGPLv2+, like the rest of Augeas.
*)

module Util =

(*
Variable: del_str
  Delete a string and default to it

  Parameters:
     s:string - the string to delete and default to
*)
  let del_str (s:string) = del s s

(*
Variable: del_ws
  Delete mandatory whitespace
*)
  let del_ws = del /[ \t]+/

(*
Variable: del_ws_spc
  Delete mandatory whitespace, default to single space
*)
  let del_ws_spc = del_ws " "

(*
Variable: del_ws_tab
  Delete mandatory whitespace, default to single tab
*)
  let del_ws_tab = del_ws "\t"

(*
Variable: del_opt_ws
  Delete optional whitespace
*)
  let del_opt_ws = del /[ \t]*/

(*
Variable: eol
  Delete end of line, including optional trailing whitespace
*)
  let eol = del /[ \t]*\n/ "\n"

(*
Variable: indent
  Delete indentation, including leading whitespace
*)
  let indent = del /[ \t]*/ ""

(* Group: Comment
     This is a general definition of comment
     It allows indentation for comments, removes the leading and trailing spaces
     of comments and stores them in nodes, except for empty comments which are
     ignored together with empty lines

View: comment_generic
  Map comments and set default comment sign
*)

  let comment_generic (r:regexp) (d:string) =
    [ label "#comment" . del r d
        . store /([^ \t\n].*[^ \t\n]|[^ \t\n])/ . eol ]

(* View: comment
  Map comments into "#comment" nodes
*)
  let comment = comment_generic /[ \t]*#[ \t]*/ "# "

(* View: comment_noindent
  Map comments into "#comment" nodes, without indentation
*)
  let comment_noindent = comment_generic /#[ \t]*/ "# "

(* View: comment_eol
  Map eol comments into "#comment" nodes
  Add a space before # for end of line comments
*)
  let comment_eol = comment_generic /[ \t]*#[ \t]*/ " # "

(* View: comment_or_eol
    A <comment_eol> or <eol>, with an optional empty comment *)
 let comment_or_eol = comment_eol | (del /[ \t]*(#[ \t]*)?\n/ "\n")

(* View: comment_multiline
    A C-style multiline comment *)
  let comment_multiline =
     let mline_re = (/[^ \t\n].*[^ \t\n]|[^ \t\n]/ - /.*\*\/.*/) in
     let mline = [ seq "mline"
                 . del /[ \t\n]*/ "\n"
                 . store mline_re ] in
     [ label "#mcomment" . del /[ \t]*\/\*/ "/*"
       . counter "mline"
       . mline . (eol . mline)*
       . del /[ \t\n]*\*\/[ \t]*\n/ "\n*/\n" ]

(* View: comment_c_style
    A comment line, C-style *)
  let comment_c_style =
    comment_generic /[ \t]*\/\/[ \t]*/ "// "

(* View: empty_generic
  A generic definition of <empty>
  Map empty lines, including empty comments *)
  let empty_generic (r:regexp) =
    [ del r "" . del_str "\n" ]

(* View: empty
  Map empty lines, including empty comments *)
  let empty = empty_generic /[ \t]*#?[ \t]*/

(* View: empty_c_style
  Map empty lines, including C-style empty comment *)
  let empty_c_style =
    empty_generic /[ \t]*((\/\/)|(\/\*[ \t]*\*\/))?[ \t]*/

(* View: Split *)
(* Split (SEP . ELT)* into an array-like tree where each match for ELT *)
(* appears in a separate subtree. The labels for the subtrees are      *)
(* consecutive numbers, starting at 0                                  *)
  let split (elt:lens) (sep:lens) =
    let sym = gensym "split" in
    counter sym . ( [ seq sym . sep . elt ] ) *

(* View: delim *)
  let delim (op:string) = del (/[ \t]*/ . op . /[ \t]*/)
                              (" " . op . " ")

(* Group: Exclusions

Variable: stdexcl
  Exclusion for files that are commonly not wanted/needed
*)
  let stdexcl = (excl "*~") .
    (excl "*.rpmnew") .
    (excl "*.rpmsave") .
    (excl "*.dpkg-old") .
    (excl "*.dpkg-new") .
    (excl "*.dpkg-bak") .
    (excl "*.dpkg-dist") .
    (excl "*.augsave") .
    (excl "*.augnew")


PHPFPM Support

PHPFPM Support

(* PHP module for Augeas                      *)
(* Author: Raphael Pinson <raphink@gmail.com> *)
(*                                            *)

module PHP =
  autoload xfm

(************************************************************************
 * INI File settings
 *************************************************************************)

let comment  = IniFile.comment IniFile.comment_re IniFile.comment_default
let sep      = IniFile.sep IniFile.sep_re IniFile.sep_default
let empty    = IniFile.empty

(************************************************************************
 *                        ENTRY
 *
 * We have to remove the keyword "section" from possible entry keywords
 * otherwise it would lead to an ambiguity with the "section" label
 * since PHP allows entries outside of sections.
 *************************************************************************)
let entry    = IniFile.indented_entry IniFile.entry_re sep comment

(************************************************************************
 *                         TITLE
 *
 * We use IniFile.title_label because there can be entries
 * outside of sections whose labels would conflict with section names
 *************************************************************************)
let title       = IniFile.title ( IniFile.record_re - ".anon" )
let record      = IniFile.record title entry

let record_anon = [ label ".anon" . ( entry | empty )+ ]

(************************************************************************
 *                         LENS & FILTER
 * There can be entries before any section
 * IniFile.entry includes comment management, so we just pass entry to lns
 *************************************************************************)
let lns    = record_anon? . record*

let filter = (incl "/etc/php*/*/*.ini")
             . (incl "/etc/php.ini")
             . (incl "/etc/php.d/*.ini")
             (* PHPFPM Support *)
             . (incl "/etc/php*/fpm/pool.d/*.conf")
             (* Zend Community edition *)
             . (incl "/usr/local/zend/etc/php.ini")
             . (incl "/usr/local/zend/etc/conf.d/*.ini")
             . Util.stdexcl

let xfm = transform lns filter

(* PHP module for Augeas                      *)
(* Author: Raphael Pinson <raphink@gmail.com> *)
(*                                            *)

module PHP =
  autoload xfm

(************************************************************************
 * INI File settings
 *************************************************************************)

let comment  = IniFile.comment IniFile.comment_re IniFile.comment_default
let sep      = IniFile.sep IniFile.sep_re IniFile.sep_default
let empty    = IniFile.empty

(************************************************************************
 *                        ENTRY
 *
 * We have to remove the keyword "section" from possible entry keywords
 * otherwise it would lead to an ambiguity with the "section" label
 * since PHP allows entries outside of sections.
 *************************************************************************)
let entry    = IniFile.indented_entry IniFile.entry_re sep comment

(************************************************************************
 *                         TITLE
 *
 * We use IniFile.title_label because there can be entries
 * outside of sections whose labels would conflict with section names
 *************************************************************************)
let title       = IniFile.title ( IniFile.record_re - ".anon" )
let record      = IniFile.record title entry

let record_anon = [ label ".anon" . ( entry | empty )+ ]

(************************************************************************
 *                         LENS & FILTER
 * There can be entries before any section
 * IniFile.entry includes comment management, so we just pass entry to lns
 *************************************************************************)
let lns    = record_anon? . record*

let filter = (incl "/etc/php*/*/*.ini")
             . (incl "/etc/php.ini")
             . (incl "/etc/php.d/*.ini")
             (* Zend Community edition *)
             . (incl "/usr/local/zend/etc/php.ini")
             . (incl "/usr/local/zend/etc/conf.d/*.ini")
             . Util.stdexcl

let xfm = transform lns filter


augeas: remove support for #comments

augeas: remove support for #comments

we don't use them in the scenarios anyway

module Deckard =
  autoload xfm

let del_str = Util.del_str

let space = del /[ \t]+/ " "
let tab = del /[ \t]+/ "\t"
let ws = del /[\t ]*/ ""
let word = /[^\t\n\/; ]+/

let comment = del /[;]/ ";" . [label "comment" . store /[^\n]+/]

let eol = del /([ \t]*([;][^\n]*)?\n)+/ "\n" . Util.indent
let comment_or_eol =  ws . comment? . del_str "\n" . del /([ \t]*([;][^\n]*)?\n)*/ "\n" . Util.indent

(*let comment_or_eol = [ label "#comment" . counter "comment" . (ws . [del /[;#]/ ";" . label "" . store /[^\n]*/ ]? . del_str "\n")]+ . Util.indent
*)

let domain_re = (/[^.\t\n\/; ]+(\.[^.\t\n\/; ]+)*\.?/ | ".") - "SECTION" (*quick n dirty, sorry to whoever will ever own SECTION TLD*)
let class_re = /CLASS[0-9]+/ | "IN" | "CH" | "HS" | "NONE" | "ANY"
let domain = [ label "domain" . store domain_re ]
let ttl = [label "ttl" . store /[0-9]+/]
let class = [label "class" . store class_re ]
let type = [label "type" . store ((/[^0-9;\n \t][^\t\n\/; ]*/) - class_re) ]
(* RFC 3597 section 5 rdata syntax is "\# 1 ab"*)
let data_re = /((\\#[ \t])?[^ \t\n;][^\n;]*[^ \t\n;])|[^ \t\n;]/ (*Can not start nor end with whitespace but can have whitespace in the middle. Disjunction is there so we match strings of length one.*)
let data = [label "data" . store data_re ]

let ip_re = /[0-9a-f.:]+/
let hex_re = /[0-9a-fA-F]+/

let match_option =  "opcode" | "qtype" | "qcase" | "qname" | "subdomain" | "flags" | "rcode" | "question" | "answer" | "authority" | "additional" | "all" | "TCP" | "ttl"
let adjust_option = "copy_id" | "copy_query"
let reply_option = "QR" | "TC" | "AA" | "AD" | "RD" | "RA" | "CD" | "DO" | "NOERROR" | "FORMERR" | "SERVFAIL" | "NXDOMAIN" | "NOTIMP" | "REFUSED" | "YXDOMAIN" | "YXRRSET" | "NXRRSET" | "NOTAUTH" | "NOTZONE" | "BADVERS" | "BADSIG" | "BADKEY" | "BADTIME" | "BADMODE" | "BADNAME" | "BADALG" | "BADTRUNC" | "BADCOOKIE"
let step_option = "REPLY" | "QUERY" | "CHECK_ANSWER" | "CHECK_OUT_QUERY" | /TIME_PASSES[ \t]+ELAPSE/

let mandatory = [del_str "MANDATORY" . label "mandatory" . value "true" . comment_or_eol]
let tsig = [del_str "TSIG" . label "tsig" . space . [label "keyname" . store word] . space . [label "secret" . store word] . comment_or_eol]

let match = (mandatory | tsig)* . del_str "MATCH" . [space . label "match" . store match_option ]+ . comment_or_eol
let adjust =  (mandatory | tsig)* . del_str "ADJUST" . [space . label "adjust" . store adjust_option ]+ . comment_or_eol
let reply =  (mandatory | tsig)* . del ("REPLY" | "FLAGS") "REPLY" .  [space . label "reply" . store reply_option ]+ . comment_or_eol

let question = [label "record" . domain . tab . (class . tab)? . type . comment_or_eol ]
let record = [label "record" . domain . tab . (ttl . tab)? . (class . tab)? . type . tab . data . comment_or_eol]

let section_question = [ label "question" . del_str "SECTION QUESTION" .
                       comment_or_eol . question? ]
let section_answer = [ label "answer" . del_str "SECTION ANSWER" .
                       comment_or_eol . record* ]
let section_authority = [ label "authority" . del_str "SECTION AUTHORITY" .
                          comment_or_eol . record* ]
let section_additional = [ label "additional" . del_str "SECTION ADDITIONAL" .
                           comment_or_eol . record* ]
let sections = [label "section" . section_question? . section_answer? . section_authority? . section_additional?]

let raw = [del_str "RAW" . comment_or_eol . label "raw" . store hex_re  ] . comment_or_eol

(* This is quite dirty hack to match every combination of options given to entry since 'let normal = ((match | adjust | reply | mandatory | tsig)* . sections)' just is not possible *)

let normal = (match . (adjust . reply? | reply . adjust?)? | adjust . (match . reply? | reply . match?)? | reply . (match . adjust? | adjust . match?)?)? . (mandatory | tsig)* . sections

let entry = [label "entry" . del_str "ENTRY_BEGIN" . comment_or_eol . ( normal | raw ) . del_str "ENTRY_END" . eol]

let single_address = [ label "address" . space . store ip_re ]

let addresses = [label "address" . counter "address" . [seq "address" . del_str "ADDRESS" . space . store ip_re . comment_or_eol]+]

let range = [label "range" . del_str "RANGE_BEGIN" . space . [ label "from" . store /[0-9]+/] . space .
            [ label "to" . store /[0-9]+/] . single_address? . comment_or_eol . addresses? . entry* . del_str "RANGE_END" . eol]

let step = [label "step" . del_str "STEP" . space . store /[0-9]+/ . space . [label "type" . store step_option] . [space . label "timestamp" . store /[0-9]+/]? . comment_or_eol .
           entry? ]

let config_record = /[^\n]*/ - ("CONFIG_END" | /STEP.*/ | /SCENARIO.*/ | /RANGE.*/ | /ENTRY.*/)

let config = [ label "config" . counter "config" . [seq "config" . store config_record . del_str "\n"]* . del_str "CONFIG_END" . comment_or_eol ]

let guts = (step | range )*

let scenario = [label "scenario" . del_str "SCENARIO_BEGIN" . space . store data_re . comment_or_eol . guts . del_str "SCENARIO_END" . eol]

let lns = config? . scenario

(* TODO: REPLAY step *)
(* TODO: store all comments into the tree instead of ignoring them *)

(*let filter = incl "/home/test/*.rpl"*)
let filter = incl "/home/sbalazik/nic/deckard/git/sets/resolver/*.rpl"

let xfm = transform lns filter

module Deckard =
  autoload xfm

let del_str = Util.del_str

let space = del /[ \t]+/ " "
let tab = del /[ \t]+/ "\t"
let ws = del /[\t ]*/ ""
let word = /[^\t\n\/#; ]+/

let comment = del /[;#]/ ";" . [label "comment" . store /[^\n]+/]

let eol = del /([ \t]*([;#][^\n]*)?\n)+/ "\n" . Util.indent
let comment_or_eol =  ws . comment? . del_str "\n" . del /([ \t]*([;#][^\n]*)?\n)*/ "\n" . Util.indent

(*let comment_or_eol = [ label "#comment" . counter "comment" . (ws . [del /[;#]/ ";" . label "" . store /[^\n]*/ ]? . del_str "\n")]+ . Util.indent
*)

let domain_re = (/[^.\t\n\/#; ]+(\.[^.\t\n\/#; ]+)*\.?/ | ".") - "SECTION" (*quick n dirty, sorry to whoever will ever own SECTION TLD*)
let class_re = /CLASS[0-9]+/ | "IN" | "CH" | "HS" | "NONE" | "ANY"
let domain = [ label "domain" . store domain_re ]
let ttl = [label "ttl" . store /[0-9]+/]
let class = [label "class" . store class_re ]
let type = [label "type" . store ((/[^0-9#;\n \t][^\t\n\/#; ]*/) - class_re) ]
(* RFC 3597 section 5 rdata syntax is "\# 1 ab"*)
let data_re = /((\\\#[ \t])?[^ \t\n#;][^\n#;]*[^ \t\n#;])|[^ \t\n#;]/ (*Can not start nor end with whitespace but can have whitespace in the middle. Disjunction is there so we match strings of length one.*)
let data = [label "data" . store data_re ]

let ip_re = /[0-9a-f.:]+/
let hex_re = /[0-9a-fA-F]+/

let match_option =  "opcode" | "qtype" | "qcase" | "qname" | "subdomain" | "flags" | "rcode" | "question" | "answer" | "authority" | "additional" | "all" | "TCP" | "ttl"
let adjust_option = "copy_id" | "copy_query"
let reply_option = "QR" | "TC" | "AA" | "AD" | "RD" | "RA" | "CD" | "DO" | "NOERROR" | "FORMERR" | "SERVFAIL" | "NXDOMAIN" | "NOTIMP" | "REFUSED" | "YXDOMAIN" | "YXRRSET" | "NXRRSET" | "NOTAUTH" | "NOTZONE" | "BADVERS" | "BADSIG" | "BADKEY" | "BADTIME" | "BADMODE" | "BADNAME" | "BADALG" | "BADTRUNC" | "BADCOOKIE"
let step_option = "REPLY" | "QUERY" | "CHECK_ANSWER" | "CHECK_OUT_QUERY" | /TIME_PASSES[ \t]+ELAPSE/

let mandatory = [del_str "MANDATORY" . label "mandatory" . value "true" . comment_or_eol]
let tsig = [del_str "TSIG" . label "tsig" . space . [label "keyname" . store word] . space . [label "secret" . store word] . comment_or_eol]

let match = (mandatory | tsig)* . del_str "MATCH" . [space . label "match" . store match_option ]+ . comment_or_eol
let adjust =  (mandatory | tsig)* . del_str "ADJUST" . [space . label "adjust" . store adjust_option ]+ . comment_or_eol
let reply =  (mandatory | tsig)* . del ("REPLY" | "FLAGS") "REPLY" .  [space . label "reply" . store reply_option ]+ . comment_or_eol

let question = [label "record" . domain . tab . (class . tab)? . type . comment_or_eol ]
let record = [label "record" . domain . tab . (ttl . tab)? . (class . tab)? . type . tab . data . comment_or_eol]

let section_question = [ label "question" . del_str "SECTION QUESTION" .
                       comment_or_eol . question? ]
let section_answer = [ label "answer" . del_str "SECTION ANSWER" .
                       comment_or_eol . record* ]
let section_authority = [ label "authority" . del_str "SECTION AUTHORITY" .
                          comment_or_eol . record* ]
let section_additional = [ label "additional" . del_str "SECTION ADDITIONAL" .
                           comment_or_eol . record* ]
let sections = [label "section" . section_question? . section_answer? . section_authority? . section_additional?]

let raw = [del_str "RAW" . comment_or_eol . label "raw" . store hex_re  ] . comment_or_eol

(* This is quite dirty hack to match every combination of options given to entry since 'let normal = ((match | adjust | reply | mandatory | tsig)* . sections)' just is not possible *)

let normal = (match . (adjust . reply? | reply . adjust?)? | adjust . (match . reply? | reply . match?)? | reply . (match . adjust? | adjust . match?)?)? . (mandatory | tsig)* . sections

let entry = [label "entry" . del_str "ENTRY_BEGIN" . comment_or_eol . ( normal | raw ) . del_str "ENTRY_END" . eol]

let single_address = [ label "address" . space . store ip_re ]

let addresses = [label "address" . counter "address" . [seq "address" . del_str "ADDRESS" . space . store ip_re . comment_or_eol]+]

let range = [label "range" . del_str "RANGE_BEGIN" . space . [ label "from" . store /[0-9]+/] . space .
            [ label "to" . store /[0-9]+/] . single_address? . comment_or_eol . addresses? . entry* . del_str "RANGE_END" . eol]

let step = [label "step" . del_str "STEP" . space . store /[0-9]+/ . space . [label "type" . store step_option] . [space . label "timestamp" . store /[0-9]+/]? . comment_or_eol .
           entry? ]

let config_record = /[^\n]*/ - ("CONFIG_END" | /STEP.*/ | /SCENARIO.*/ | /RANGE.*/ | /ENTRY.*/)

let config = [ label "config" . counter "config" . [seq "config" . store config_record . del_str "\n"]* . del_str "CONFIG_END" . comment_or_eol ]

let guts = (step | range )*

let scenario = [label "scenario" . del_str "SCENARIO_BEGIN" . space . store data_re . comment_or_eol . guts . del_str "SCENARIO_END" . eol]

let lns = config? . scenario

(* TODO: REPLAY step *)
(* TODO: store all comments into the tree instead of ignoring them *)

(*let filter = incl "/home/test/*.rpl"*)
let filter = incl "/media/test/27159fa1-67d4-4162-8707-cd67900f3b36/stepan/nic/deckard_stable/deckard/sets/resolver/*.rpl"

let xfm = transform lns filter


Fstab: map comments and support empty lines

(* Parsing /etc/fstab *)

module Fstab =
  autoload xfm

  let sep_tab = Util.del_ws_tab
  let sep_spc = Util.del_ws_spc
  let comma = Util.del_str ","
  let eol = del /[ \t]*\n/ "\n"

  let comment = Util.comment
  let empty   = Util.empty

  let word = /[^,# \n\t]+/
  let comma_sep_list (l:string) =
    [ label l . store word ] . ([comma . label l . store word])*
  let record = [ seq "mntent" .
                   [ label "spec" . store  word ] . sep_tab .
                   [ label "file" . store word ] . sep_tab .
                   comma_sep_list "vfstype" . sep_tab .
                   comma_sep_list "opt" .
                   (sep_tab . [ label "dump" . store /[0-9]+/ ] .
                    ( sep_spc . [ label "passno" . store /[0-9]+/ ])? )?
                 . eol ]

  let lns = ( empty | comment | record ) *

  let xfm = transform lns (incl "/etc/fstab")

(* Local Variables: *)
(* mode: caml *)
(* End: *)

(* Parsing /etc/fstab *)

module Fstab =
  autoload xfm

  let sep_tab = Util.del_ws_tab
  let sep_spc = Util.del_ws_spc
  let comma = Util.del_str ","
  let eol = del /[ \t]*\n/ "\n"

  let comment = [ del /#.*\n/ "# " ]
  let word = /[^,# \n\t]+/
  let comma_sep_list (l:string) =
    [ label l . store word ] . ([comma . label l . store word])*
  let record = [ seq "mntent" .
                   [ label "spec" . store  word ] . sep_tab .
                   [ label "file" . store word ] . sep_tab .
                   comma_sep_list "vfstype" . sep_tab .
                   comma_sep_list "opt" .
                   (sep_tab . [ label "dump" . store /[0-9]+/ ] .
                    ( sep_spc . [ label "passno" . store /[0-9]+/ ])? )?
                 . eol ]

  let lns = ( comment | record ) *

  let xfm = transform lns (incl "/etc/fstab")

(* Local Variables: *)
(* mode: caml *)
(* End: *)


Json: fix handling of whitespace

Json: fix handling of whitespace

We just gobble up whitespace after various expressions as part of the lens
processing that expression.

module Json =

(* A generic lens for Json files                                           *)
(* Based on the following grammar from http://www.json.org/                *)
(* Object ::= '{'Members ? '}'                                             *)
(* Members ::= Pair+                                                       *)
(* Pair ::= String ':' Value                                               *)
(* Array ::= '[' Elements ']'                                              *)
(* Elements ::= Value ( "," Value )*                                       *)
(* Value ::= String | Number | Object | Array | "true" | "false" | "null"  *)
(* String ::= "\"" Char* "\""                                              *)
(* Number ::= /-?[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?/                      *)

let spc = /[ \t\n]*/

let ws = del spc ""
let eol = del spc "\n"
let delim (c:string) (d:string) = del (c . spc) d
let dels (s:string) = del s s

let comma = delim "," ","
let colon = delim ":" ":"
let lbrace = delim "{" "{"
let rbrace = delim "}" "}"
let lbrack = delim "[" "["
let rbrack = delim "]" "]"

let str_store =
  let q =  del "\"" "\"" in
  q . store /[^"]*/ . q . ws             (* " Emacs, relax *)

let number = [ label "number" . store /-?[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?/ ]
let str = [ label "string" . str_store ]

let const (r:regexp) = [ label "const" . store r . ws ]

let value0 = str | number | const /true|false|null/

let fix_value (value:lens) =
  let array = [ label "array" . lbrack . Build.opt_list value comma . rbrack ] in
  let pair = [ label "entry" . str_store . colon . value ] in
  let obj = [ label "dict" . lbrace . Build.opt_list pair comma . rbrace ] in
  (str | number | obj | array | const /true|false|null/)

(* Typecheck finitely deep nesting *)
let value1 = fix_value value0
let value2 = fix_value value1

(* Process arbitrarily deeply nested JSON objects *)
let rec rlns = fix_value rlns

let lns = ws . rlns

module Json =

(* A generic lens for Json files                                           *)
(* Based on the following grammar from http://www.json.org/                *)
(* Object ::= '{'Members ? '}'                                             *)
(* Members ::= Pair+                                                       *)
(* Pair ::= String ':' Value                                               *)
(* Array ::= '[' Elements ']'                                              *)
(* Elements ::= Value ( "," Value )*                                       *)
(* Value ::= String | Number | Object | Array | "true" | "false" | "null"  *)
(* String ::= "\"" Char* "\""                                              *)
(* Number ::= /-?[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?/                      *)

let spc = /[ \t\n]*/

let ws = del spc ""
let eol = del spc "\n"
let delim (c:string) (d:string) = del (spc . c . spc) d
let dels (s:string) = del s s

let comma = delim "," ", "
let colon = delim ":" ": "
let lbrace = delim "{" "{ "
let rbrace = delim "}" "} "
let lbrack = delim "[" "[ "
let rbrack = delim "]" " ]"

let str_store =
  let q =  del "\"" "\"" in
  q . store /[^"]*/ . q             (* " Emacs, relax *)

let number = [ label "number" . store /-?[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?/ ]
let str = [ label "string" . str_store ]

let const (r:regexp) = [ label "const" . store r ]

let value0 = str | number | const /true|false|null/

let fix_value (value:lens) =
  let array = [ label "array" . lbrack . Build.opt_list value comma . rbrack ] in
  let pair = [ label "entry" . str_store . colon . value ] in
  let obj = [ label "dict" . lbrace . Build.opt_list pair comma . rbrace ] in
  str | number | obj | array | const /true|false|null/

(* Do shallow typechecks *)
let value1 = fix_value value0
(* FIXME: We are very sloppy with whitespace
let value2 = fix_value value1
*)

(* Construct the real lens *)
let rec lns = fix_value lns


Shellvars: add locale.conf, vconsole.conf systemd configs

Fixes BZ#881841

(*
Module: Shellvars
 Generic lens for shell-script config files like the ones found
 in /etc/sysconfig

About: License
   This file is licenced under the LGPL v2+, like the rest of Augeas.

About: Lens Usage
   To be documented
*)

module Shellvars =
  autoload xfm

  let empty   = Util.empty
  let empty_part_re = Util.empty_generic_re . /\n+/
  let eol = del (/[ \t]+|[ \t]*[;\n]/ . empty_part_re*) "\n"
  let semicol_eol = del (/[ \t]*[;\n]/ . empty_part_re*) "\n"

  let key_re = /[A-Za-z0-9_]+(\[[0-9]+\])?/ - "unset" - "export"
  let matching_re = "${!" . key_re . /[\*@]\}/
  let eq = Util.del_str "="

  let eol_for_comment = del /([ \t]*\n)([ \t]*(#[ \t]*)?\n)*/ "\n"
  let comment = Util.comment_generic_seteol /[ \t]*#[ \t]*/ " # " eol_for_comment
  (* comment_eol in shell MUST begin with a space *)
  let comment_eol = Util.comment_generic_seteol /[ \t]+#[ \t]*/ " # " eol_for_comment
  let comment_or_eol = comment_eol | semicol_eol

  let xchgs   = Build.xchgs
  let semicol = del /;?/ ""

  let char  = /[^`;() '"\t\n]|\\\\"/
  let dquot = /"([^"\\]|\\\\.)*"/                    (* " Emacs, relax *)
  let squot = /'[^']*'/
  let bquot = /`[^`\n]*`/
  (* dbquot don't take spaces or semi-colons *)
  let dbquot = /``[^` \t\n;]+``/
  let dollar_assign = /\$\([^\)#\n]*\)/

  let sto_to_semicol = store /[^#; \t\n][^#;\n]+[^#; \t\n]|[^#; \t\n]+/

  (* Array values of the form '(val1 val2 val3)'. We do not handle empty *)
  (* arrays here because of typechecking headaches. Instead, they are    *)
  (* treated as a simple value                                           *)
  let array =
    let array_value = store (char+ | dquot) in
    del /\([ \t]*/ "(" . counter "values" .
      [ seq "values" . array_value ] .
      [ del /[ \t\n]+/ " " . seq "values" . array_value ] *
      . del /[ \t]*\)/ ")"

  (* Treat an empty list () as a value '()'; that's not quite correct *)
  (* but fairly close.                                                *)
  let simple_value =
    let empty_array = /\([ \t]*\)/ in
      store (char* | (dquot | squot)+
            | bquot | dbquot | dollar_assign | empty_array)

  let export = [ key "export" . Util.del_ws_spc ]
  let kv = [ Util.indent . export? . key key_re
           . eq . (simple_value | array) . comment_or_eol ]

  let var_action (name:string) =
    [ Util.indent . xchgs name ("@" . name) . Util.del_ws_spc
    . store (key_re | matching_re) . comment_or_eol ]

  let unset = var_action "unset"
  let bare_export = var_action "export"

  let source =
    [ Util.indent
      . del /\.|source/ "." . label ".source"
      . Util.del_ws_spc . store /[^;=# \t\n]+/ . comment_or_eol ]

  let shell_builtin_cmds = "ulimit" | "shift" | "exit"

  let builtin =
    [ Util.indent . label "@builtin"
      . store shell_builtin_cmds
      . (Util.del_ws_spc
      . [ label "args" . sto_to_semicol ])?
      . comment_or_eol ]

  let keyword (kw:string) = Util.indent . Util.del_str kw
  let keyword_label (kw:string) (lbl:string) = keyword kw . label lbl

  let return =
    [ Util.indent . label "@return"
      . Util.del_str "return"
      . ( Util.del_ws_spc . store Rx.integer )?
      . comment_or_eol ]

(************************************************************************
 * Group:                 CONDITIONALS AND LOOPS
 *************************************************************************)

  let generic_cond_start (start_kw:string) (lbl:string)
                         (then_kw:string) (contents:lens) =
      keyword_label start_kw lbl . Sep.space
      . sto_to_semicol . semicol_eol
      . keyword then_kw . eol
      . contents

  let generic_cond (start_kw:string) (lbl:string)
                       (then_kw:string) (contents:lens) (end_kw:string) =
      [ generic_cond_start start_kw lbl then_kw contents
        . keyword end_kw . comment_or_eol ]

  let cond_if (entry:lens) =
    let elif = [ generic_cond_start "elif" "@elif" "then" entry+ ] in
    let else = [ keyword_label "else" "@else" . eol . entry+ ] in
    generic_cond "if" "@if" "then" (entry+ . elif* . else?) "fi"

  let loop_for (entry:lens) =
    generic_cond "for" "@for" "do" entry+ "done"

  let loop_while (entry:lens) =
    generic_cond "while" "@while" "do" entry+ "done"

  let loop_until (entry:lens) =
    generic_cond "until" "@until" "do" entry+ "done"

  let loop_select (entry:lens) =
    generic_cond "select" "@select" "do" entry+ "done"

  let case (entry:lens) =
    let case_entry = [ label "@case_entry"
                       . Util.indent . store /[^ \t\n\)]+/
                       . Util.del_str ")" . eol
                       . entry*
                       . Util.indent . Util.del_str ";;" . eol ] in
      [ keyword_label "case" "@case" . Sep.space
        . store (char+ | ("\"" . char+ . "\""))
        . del /[ \t\n]+/ " " . Util.del_str "in" . eol
        . (empty* . comment* . case_entry)*
        . empty* . comment*
        . keyword "esac" . comment_or_eol ]

  let function (entry:lens) =
    [ Util.indent . label "@function"
      . del /(function[ \t]+)?/ ""
      . store Rx.word . del /[ \t]*\(\)/ "()"
      . eol . Util.del_str "{" . eol
      . entry+
      . Util.indent . Util.del_str "}" . eol ]

  let rec rec_entry =
    let entry = comment | source | kv
              | unset | bare_export | builtin | return | rec_entry in
        cond_if entry
      | loop_for entry
      | loop_select entry
      | loop_while entry
      | loop_until entry
      | case entry
      | function entry

  let lns_norec = empty* . (comment | source | kv | unset | bare_export | builtin | return) *

  let lns = empty* . (comment | source | kv | unset | bare_export | builtin | return | rec_entry) *

  let sc_incl (n:string) = (incl ("/etc/sysconfig/" . n))
  let sc_excl (n:string) = (excl ("/etc/sysconfig/" . n))

  let filter_sysconfig =
      sc_incl "*" .
      sc_excl "bootloader" .
      sc_excl "hw-uuid" .
      sc_excl "hwconf" .
      sc_excl "ip*tables" .
      sc_excl "kernel" .
      sc_excl "*.pub" .
      sc_excl "sysstat.ioconf" .
      sc_excl "system-config-firewall" .
      sc_excl "system-config-securitylevel" .
      sc_excl "network" .
      sc_incl "network/config" .
      sc_incl "network/dhcp" .
      sc_incl "network/dhcp6r" .
      sc_incl "network/dhcp6s" .
      sc_incl "network/ifcfg-*" .
      sc_incl "network/if-down.d/*" .
      sc_incl "network/ifroute-*" .
      sc_incl "network/if-up.d/*" .
      sc_incl "network/providers/*" .
      sc_excl "network-scripts" .
      sc_incl "network-scripts/ifcfg-*" .
      sc_excl "rhn" .
      sc_incl "rhn/allowed-actions/*" .
      sc_excl "rhn/allowed-actions/script" .
      sc_incl "rhn/allowed-actions/script/*" .
      sc_incl "rhn/rhnsd" .
      sc_excl "SuSEfirewall2.d" .
      sc_incl "SuSEfirewall2.d/cobbler" .
      sc_incl "SuSEfirewall2.d/services/*" .
      sc_excl "SuSEfirewall2.d/services/TEMPLATE"

  let filter_default = incl "/etc/default/*"
                     . excl "/etc/default/grub_installdevice*"
                     . excl "/etc/default/whoopsie"
  let filter_misc    = incl "/etc/arno-iptables-firewall/debconf.cfg"
                     . incl "/etc/cron-apt/config"
                     . incl "/etc/environment"
                     . incl "/etc/blkid.conf"
                     . incl "/etc/adduser.conf"
                     . incl "/etc/cowpoke.conf"
                     . incl "/etc/cvs-cron.conf"
                     . incl "/etc/cvs-pserver.conf"
                     . incl "/etc/devscripts.conf"
                     . incl "/etc/lintianrc"
                     . incl "/etc/lsb-release"
                     . incl "/etc/os-release"
                     . incl "/etc/popularity-contest.conf"
                     . incl "/etc/rc.conf"
                     . incl "/etc/selinux/config"
                     . incl "/etc/ucf.conf"
                     . incl "/etc/locale.conf"
                     . incl "/etc/vconsole.conf"

  let filter = filter_sysconfig
             . filter_default
             . filter_misc
             . Util.stdexcl

  let xfm = transform lns filter

(* Local Variables: *)
(* mode: caml       *)
(* End:             *)

(*
Module: Shellvars
 Generic lens for shell-script config files like the ones found
 in /etc/sysconfig

About: License
   This file is licenced under the LGPL v2+, like the rest of Augeas.

About: Lens Usage
   To be documented
*)

module Shellvars =
  autoload xfm

  let empty   = Util.empty
  let empty_part_re = Util.empty_generic_re . /\n+/
  let eol = del (/[ \t]+|[ \t]*[;\n]/ . empty_part_re*) "\n"
  let semicol_eol = del (/[ \t]*[;\n]/ . empty_part_re*) "\n"

  let key_re = /[A-Za-z0-9_]+(\[[0-9]+\])?/ - "unset" - "export"
  let matching_re = "${!" . key_re . /[\*@]\}/
  let eq = Util.del_str "="

  let eol_for_comment = del /([ \t]*\n)([ \t]*(#[ \t]*)?\n)*/ "\n"
  let comment = Util.comment_generic_seteol /[ \t]*#[ \t]*/ " # " eol_for_comment
  (* comment_eol in shell MUST begin with a space *)
  let comment_eol = Util.comment_generic_seteol /[ \t]+#[ \t]*/ " # " eol_for_comment
  let comment_or_eol = comment_eol | semicol_eol

  let xchgs   = Build.xchgs
  let semicol = del /;?/ ""

  let char  = /[^`;() '"\t\n]|\\\\"/
  let dquot = /"([^"\\]|\\\\.)*"/                    (* " Emacs, relax *)
  let squot = /'[^']*'/
  let bquot = /`[^`\n]*`/
  (* dbquot don't take spaces or semi-colons *)
  let dbquot = /``[^` \t\n;]+``/
  let dollar_assign = /\$\([^\)#\n]*\)/

  let sto_to_semicol = store /[^#; \t\n][^#;\n]+[^#; \t\n]|[^#; \t\n]+/

  (* Array values of the form '(val1 val2 val3)'. We do not handle empty *)
  (* arrays here because of typechecking headaches. Instead, they are    *)
  (* treated as a simple value                                           *)
  let array =
    let array_value = store (char+ | dquot) in
    del /\([ \t]*/ "(" . counter "values" .
      [ seq "values" . array_value ] .
      [ del /[ \t\n]+/ " " . seq "values" . array_value ] *
      . del /[ \t]*\)/ ")"

  (* Treat an empty list () as a value '()'; that's not quite correct *)
  (* but fairly close.                                                *)
  let simple_value =
    let empty_array = /\([ \t]*\)/ in
      store (char* | (dquot | squot)+
            | bquot | dbquot | dollar_assign | empty_array)

  let export = [ key "export" . Util.del_ws_spc ]
  let kv = [ Util.indent . export? . key key_re
           . eq . (simple_value | array) . comment_or_eol ]

  let var_action (name:string) =
    [ Util.indent . xchgs name ("@" . name) . Util.del_ws_spc
    . store (key_re | matching_re) . comment_or_eol ]

  let unset = var_action "unset"
  let bare_export = var_action "export"

  let source =
    [ Util.indent
      . del /\.|source/ "." . label ".source"
      . Util.del_ws_spc . store /[^;=# \t\n]+/ . comment_or_eol ]

  let shell_builtin_cmds = "ulimit" | "shift" | "exit"

  let builtin =
    [ Util.indent . label "@builtin"
      . store shell_builtin_cmds
      . (Util.del_ws_spc
      . [ label "args" . sto_to_semicol ])?
      . comment_or_eol ]

  let keyword (kw:string) = Util.indent . Util.del_str kw
  let keyword_label (kw:string) (lbl:string) = keyword kw . label lbl

  let return =
    [ Util.indent . label "@return"
      . Util.del_str "return"
      . ( Util.del_ws_spc . store Rx.integer )?
      . comment_or_eol ]

(************************************************************************
 * Group:                 CONDITIONALS AND LOOPS
 *************************************************************************)

  let generic_cond_start (start_kw:string) (lbl:string)
                         (then_kw:string) (contents:lens) =
      keyword_label start_kw lbl . Sep.space
      . sto_to_semicol . semicol_eol
      . keyword then_kw . eol
      . contents

  let generic_cond (start_kw:string) (lbl:string)
                       (then_kw:string) (contents:lens) (end_kw:string) =
      [ generic_cond_start start_kw lbl then_kw contents
        . keyword end_kw . comment_or_eol ]

  let cond_if (entry:lens) =
    let elif = [ generic_cond_start "elif" "@elif" "then" entry+ ] in
    let else = [ keyword_label "else" "@else" . eol . entry+ ] in
    generic_cond "if" "@if" "then" (entry+ . elif* . else?) "fi"

  let loop_for (entry:lens) =
    generic_cond "for" "@for" "do" entry+ "done"

  let loop_while (entry:lens) =
    generic_cond "while" "@while" "do" entry+ "done"

  let loop_until (entry:lens) =
    generic_cond "until" "@until" "do" entry+ "done"

  let loop_select (entry:lens) =
    generic_cond "select" "@select" "do" entry+ "done"

  let case (entry:lens) =
    let case_entry = [ label "@case_entry"
                       . Util.indent . store /[^ \t\n\)]+/
                       . Util.del_str ")" . eol
                       . entry*
                       . Util.indent . Util.del_str ";;" . eol ] in
      [ keyword_label "case" "@case" . Sep.space
        . store (char+ | ("\"" . char+ . "\""))
        . del /[ \t\n]+/ " " . Util.del_str "in" . eol
        . (empty* . comment* . case_entry)*
        . empty* . comment*
        . keyword "esac" . comment_or_eol ]

  let function (entry:lens) =
    [ Util.indent . label "@function"
      . del /(function[ \t]+)?/ ""
      . store Rx.word . del /[ \t]*\(\)/ "()"
      . eol . Util.del_str "{" . eol
      . entry+
      . Util.indent . Util.del_str "}" . eol ]

  let rec rec_entry =
    let entry = comment | source | kv
              | unset | bare_export | builtin | return | rec_entry in
        cond_if entry
      | loop_for entry
      | loop_select entry
      | loop_while entry
      | loop_until entry
      | case entry
      | function entry

  let lns_norec = empty* . (comment | source | kv | unset | bare_export | builtin | return) *

  let lns = empty* . (comment | source | kv | unset | bare_export | builtin | return | rec_entry) *

  let sc_incl (n:string) = (incl ("/etc/sysconfig/" . n))
  let sc_excl (n:string) = (excl ("/etc/sysconfig/" . n))

  let filter_sysconfig =
      sc_incl "*" .
      sc_excl "bootloader" .
      sc_excl "hw-uuid" .
      sc_excl "hwconf" .
      sc_excl "ip*tables" .
      sc_excl "kernel" .
      sc_excl "*.pub" .
      sc_excl "sysstat.ioconf" .
      sc_excl "system-config-firewall" .
      sc_excl "system-config-securitylevel" .
      sc_excl "network" .
      sc_incl "network/config" .
      sc_incl "network/dhcp" .
      sc_incl "network/dhcp6r" .
      sc_incl "network/dhcp6s" .
      sc_incl "network/ifcfg-*" .
      sc_incl "network/if-down.d/*" .
      sc_incl "network/ifroute-*" .
      sc_incl "network/if-up.d/*" .
      sc_incl "network/providers/*" .
      sc_excl "network-scripts" .
      sc_incl "network-scripts/ifcfg-*" .
      sc_excl "rhn" .
      sc_incl "rhn/allowed-actions/*" .
      sc_excl "rhn/allowed-actions/script" .
      sc_incl "rhn/allowed-actions/script/*" .
      sc_incl "rhn/rhnsd" .
      sc_excl "SuSEfirewall2.d" .
      sc_incl "SuSEfirewall2.d/cobbler" .
      sc_incl "SuSEfirewall2.d/services/*" .
      sc_excl "SuSEfirewall2.d/services/TEMPLATE"

  let filter_default = incl "/etc/default/*"
                     . excl "/etc/default/grub_installdevice*"
                     . excl "/etc/default/whoopsie"
  let filter_misc    = incl "/etc/arno-iptables-firewall/debconf.cfg"
                     . incl "/etc/cron-apt/config"
                     . incl "/etc/environment"
                     . incl "/etc/blkid.conf"
                     . incl "/etc/adduser.conf"
                     . incl "/etc/cowpoke.conf"
                     . incl "/etc/cvs-cron.conf"
                     . incl "/etc/cvs-pserver.conf"
                     . incl "/etc/devscripts.conf"
                     . incl "/etc/lintianrc"
                     . incl "/etc/lsb-release"
                     . incl "/etc/os-release"
                     . incl "/etc/popularity-contest.conf"
                     . incl "/etc/rc.conf"
                     . incl "/etc/selinux/config"
                     . incl "/etc/ucf.conf"

  let filter = filter_sysconfig
             . filter_default
             . filter_misc
             . Util.stdexcl

  let xfm = transform lns filter

(* Local Variables: *)
(* mode: caml       *)
(* End:             *)


Removed trailing space in token in slapd.lens

(* Slapd module for Augeas
   Author: Free Ekanayaka <free@64studio.com>

   Reference: man slapd.conf(5), man slapd.access (5)

*)

module Slapd =
  autoload xfm

(************************************************************************
 *                           USEFUL PRIMITIVES
 *************************************************************************)

let eol         = Util.eol
let spc         = Util.del_ws_spc
let sep         = del /[ \t\n]+/ " "

let sto_to_eol  = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/
let sto_to_spc  = store /[^\\# \t\n]+/

let comment     = Util.comment
let empty       = Util.empty

(************************************************************************
 *                           ACCESS TO
 *************************************************************************)

let access_re   = "access to"
let control_re  = "stop" | "continue" | "break"
let what        = [ spc . label "access"
                  . store (/[^\\# \t\n]+/ - ("by" | control_re)) ]

(* TODO: parse the control field, see man slapd.access (5) *)
let control     = [ spc . label "control" . store control_re ]
let by          = [ sep . key "by" . spc . sto_to_spc
                  . what? . control? ]

let access      = [ key access_re . spc. sto_to_spc . by+ . eol ]

(************************************************************************
 *                             GLOBAL
 *************************************************************************)

(* TODO: parse special field separately, see man slapd.conf (5) *)
let global_re   = "allow"
                | "argsfile"
                | "attributeoptions"
                | "attributetype"
                | "authz-policy"
                | "ldap"
                | "dn"
                | "concurrency"
                | "cron_max_pending"
                | "conn_max_pending_auth"
                | "defaultsearchbase"
                | "disallow"
                | "ditcontentrule"
                | "gentlehup"
                | "idletimeout"
                | "include"
                | "index_substr_if_minlen"
                | "index_substr_if_maxlen"
                | "index_substr_any_len"
                | "index_substr_any_step"
                | "localSSF"
                | "loglevel"
                | "moduleload"
                | "modulepath"
                | "objectclass"
                | "objectidentifier"
                | "password-hash"
                | "password-crypt-salt-format"
                | "pidfile"
                | "referral"
                | "replica-argsfile"
                | "replica-pidfile"
                | "replicationinterval"
                | "require"
                | "reverse-lookup"
                | "rootDSE"
                | "sasl-host"
                | "sasl-realm"
                | "sasl-secprops"
                | "schemadn"
                | "security"
                | "sizelimit"
                | "sockbuf_max_incoming "
                | "sockbuf_max_incoming_auth"
                | "threads"
                | "timelimit time"
                | "tool-threads"
                | "TLSCipherSuite"
                | "TLSCACertificateFile"
                | "TLSCACertificatePath"
                | "TLSCertificateFile"
                | "TLSCertificateKeyFile"
                | "TLSDHParamFile"
                | "TLSRandFile"
                | "TLSVerifyClient"
                | "TLSCRLCheck"
                | "backend"

let global     = Build.key_ws_value global_re

(************************************************************************
 *                             DATABASE
 *************************************************************************)

(* TODO: support all types of database backend *)
let database_hdb = "cachesize"
                | "cachefree"
                | "checkpoint"
                | "dbconfig"
                | "dbnosync"
                | "directory"
                | "dirtyread"
                | "idlcachesize"
                | "index"
                | "linearindex"
                | "lockdetect"
                | "mode"
                | "searchstack"
                | "shm_key"

let database_re = "suffix"
                | "lastmod"
                | "limits"
                | "maxderefdepth"
                | "overlay"
                | "readonly"
                | "replica uri"
                | "replogfile"
                | "restrict"
                | "rootdn"
                | "rootpw"
                | "subordinate"
                | "syncrepl rid"
                | "updatedn"
                | "updateref"
                | database_hdb

let database_entry =
     let val = Quote.double_opt
  in Build.key_value_line database_re Sep.space val

let database    = [ key "database"
                  . spc
                  . sto_to_eol
                  . eol
                  . (comment|empty|database_entry|access)* ]

(************************************************************************
 *                              LENS
 *************************************************************************)

let lns         = (comment|empty|global|access)* . (database)*

let filter      = incl "/etc/ldap/slapd.conf"
                . incl "/etc/openldap/slapd.conf"

let xfm         = transform lns filter

(* Slapd module for Augeas
   Author: Free Ekanayaka <free@64studio.com>

   Reference: man slapd.conf(5), man slapd.access (5)

*)

module Slapd =
  autoload xfm

(************************************************************************
 *                           USEFUL PRIMITIVES
 *************************************************************************)

let eol         = Util.eol
let spc         = Util.del_ws_spc
let sep         = del /[ \t\n]+/ " "

let sto_to_eol  = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/
let sto_to_spc  = store /[^\\# \t\n]+/

let comment     = Util.comment
let empty       = Util.empty

(************************************************************************
 *                           ACCESS TO
 *************************************************************************)

let access_re   = "access to"
let control_re  = "stop" | "continue" | "break"
let what        = [ spc . label "access"
                  . store (/[^\\# \t\n]+/ - ("by" | control_re)) ]

(* TODO: parse the control field, see man slapd.access (5) *)
let control     = [ spc . label "control" . store control_re ]
let by          = [ sep . key "by" . spc . sto_to_spc
                  . what? . control? ]

let access      = [ key access_re . spc. sto_to_spc . by+ . eol ]

(************************************************************************
 *                             GLOBAL
 *************************************************************************)

(* TODO: parse special field separately, see man slapd.conf (5) *)
let global_re   = "allow"
                | "argsfile"
                | "attributeoptions"
                | "attributetype"
                | "authz-policy"
                | "ldap"
                | "dn"
                | "concurrency"
                | "cron_max_pending"
                | "conn_max_pending_auth"
                | "defaultsearchbase"
                | "disallow"
                | "ditcontentrule"
                | "gentlehup"
                | "idletimeout"
                | "include"
                | "index_substr_if_minlen"
                | "index_substr_if_maxlen"
                | "index_substr_any_len"
                | "index_substr_any_step"
                | "localSSF"
                | "loglevel"
                | "moduleload"
                | "modulepath"
                | "objectclass"
                | "objectidentifier"
                | "password-hash"
                | "password-crypt-salt-format"
                | "pidfile"
                | "referral"
                | "replica-argsfile"
                | "replica-pidfile"
                | "replicationinterval"
                | "require"
                | "reverse-lookup"
                | "rootDSE"
                | "sasl-host "
                | "sasl-realm"
                | "sasl-secprops"
                | "schemadn"
                | "security"
                | "sizelimit"
                | "sockbuf_max_incoming "
                | "sockbuf_max_incoming_auth"
                | "threads"
                | "timelimit time"
                | "tool-threads"
                | "TLSCipherSuite"
                | "TLSCACertificateFile"
                | "TLSCACertificatePath"
                | "TLSCertificateFile"
                | "TLSCertificateKeyFile"
                | "TLSDHParamFile"
                | "TLSRandFile"
                | "TLSVerifyClient"
                | "TLSCRLCheck"
                | "backend"

let global     = Build.key_ws_value global_re

(************************************************************************
 *                             DATABASE
 *************************************************************************)

(* TODO: support all types of database backend *)
let database_hdb = "cachesize"
                | "cachefree"
                | "checkpoint"
                | "dbconfig"
                | "dbnosync"
                | "directory"
                | "dirtyread"
                | "idlcachesize"
                | "index"
                | "linearindex"
                | "lockdetect"
                | "mode"
                | "searchstack"
                | "shm_key"

let database_re = "suffix"
                | "lastmod"
                | "limits"
                | "maxderefdepth"
                | "overlay"
                | "readonly"
                | "replica uri"
                | "replogfile"
                | "restrict"
                | "rootdn"
                | "rootpw"
                | "subordinate"
                | "syncrepl rid"
                | "updatedn"
                | "updateref"
                | database_hdb

let database_entry =
     let val = Quote.double_opt
  in Build.key_value_line database_re Sep.space val

let database    = [ key "database"
                  . spc
                  . sto_to_eol
                  . eol
                  . (comment|empty|database_entry|access)* ]

(************************************************************************
 *                              LENS
 *************************************************************************)

let lns         = (comment|empty|global|access)* . (database)*

let filter      = incl "/etc/ldap/slapd.conf"
                . incl "/etc/openldap/slapd.conf"

let xfm         = transform lns filter


Upstream augeas fix for backslashes at the start of directive args

From: https://github.com/hercules-team/augeas/pull/325
Fixes: #1531

(* Apache HTTPD lens for Augeas

Authors:
  David Lutterkort <lutter@redhat.com>
  Francis Giraldeau <francis.giraldeau@usherbrooke.ca>
  Raphael Pinson <raphink@gmail.com>

About: Reference
  Online Apache configuration manual: http://httpd.apache.org/docs/trunk/

About: License
    This file is licensed under the LGPL v2+.

About: Lens Usage
  Sample usage of this lens in augtool

  Apache configuration is represented by two main structures, nested sections
  and directives. Sections are used as labels, while directives are kept as a
  value. Sections and directives can have positional arguments inside values
  of "arg" nodes. Arguments of sections must be the firsts child of the
  section node.

  This lens doesn't support automatic string quoting. Hence, the string must
  be quoted when containing a space.

  Create a new VirtualHost section with one directive:
  > clear /files/etc/apache2/sites-available/foo/VirtualHost
  > set /files/etc/apache2/sites-available/foo/VirtualHost/arg "172.16.0.1:80"
  > set /files/etc/apache2/sites-available/foo/VirtualHost/directive "ServerAdmin"
  > set /files/etc/apache2/sites-available/foo/VirtualHost/*[self::directive="ServerAdmin"]/arg "admin@example.com"

About: Configuration files
  This lens applies to files in /etc/httpd and /etc/apache2. See <filter>.

*)

module Httpd =

autoload xfm

(******************************************************************
 *                           Utilities lens
 *****************************************************************)
let dels (s:string)     = del s s

(* deal with continuation lines *)
let sep_spc    =  del /([ \t]+|[ \t]*\\\\\r?\n[ \t]*)/ " "

let sep_osp             = Sep.opt_space
let sep_eq              = del /[ \t]*=[ \t]*/ "="

let nmtoken             = /[a-zA-Z:_][a-zA-Z0-9:_.-]*/
let word                = /[a-zA-Z][a-zA-Z0-9._-]*/

let comment             = Util.comment
let eol                 = Util.doseol
let empty               = Util.empty_dos
let indent              = Util.indent

(* borrowed from shellvars.aug *)
let char_arg_dir  = /([^\\ '"\t\r\n]|[^ '"\t\r\n]+[^\\ '"\t\r\n])|\\\\"|\\\\'/
let char_arg_sec  = /[^ '"\t\r\n>]|\\\\"|\\\\'/
let cdot = /\\\\./
let cl = /\\\\\n/
let dquot =
     let no_dquot = /[^"\\\r\n]/
  in /"/ . (no_dquot|cdot|cl)* . /"/
let squot =
     let no_squot = /[^'\\\r\n]/
  in /'/ . (no_squot|cdot|cl)* . /'/
let comp = /[<>=]?=/

(******************************************************************
 *                            Attributes
 *****************************************************************)

let arg_dir = [ label "arg" . store (char_arg_dir+|dquot|squot) ]
let arg_sec = [ label "arg" . store (char_arg_sec+|comp|dquot|squot) ]

let argv (l:lens) = l . (sep_spc . l)*

let directive = [ indent . label "directive" . store word .
                  (sep_spc . argv arg_dir)? . eol ]

let section (body:lens) =
    (* opt_eol includes empty lines *)
    let opt_eol = del /([ \t]*#?\r?\n)*/ "\n" in
    let inner = (sep_spc . argv arg_sec)? . sep_osp .
             dels ">" . opt_eol . ((body|comment) . (body|empty|comment)*)? .
             indent . dels "</" in
    let kword = key word in
    let dword = del word "a" in
        [ indent . dels "<" . square kword inner dword . del ">" ">" . eol ]

let rec content = section (content|directive)

let lns = (content|directive|comment|empty)*

let filter = (incl "/etc/apache2/apache2.conf") .
             (incl "/etc/apache2/httpd.conf") .
             (incl "/etc/apache2/ports.conf") .
             (incl "/etc/apache2/conf.d/*") .
             (incl "/etc/apache2/conf-available/*.conf") .
             (incl "/etc/apache2/mods-available/*") .
             (incl "/etc/apache2/sites-available/*") .
             (incl "/etc/httpd/conf.d/*.conf") .
             (incl "/etc/httpd/httpd.conf") .
             (incl "/etc/httpd/conf/httpd.conf") .
             Util.stdexcl

let xfm = transform lns filter

(* Apache HTTPD lens for Augeas

Authors:
  David Lutterkort <lutter@redhat.com>
  Francis Giraldeau <francis.giraldeau@usherbrooke.ca>
  Raphael Pinson <raphink@gmail.com>

About: Reference
  Online Apache configuration manual: http://httpd.apache.org/docs/trunk/

About: License
    This file is licensed under the LGPL v2+.

About: Lens Usage
  Sample usage of this lens in augtool

  Apache configuration is represented by two main structures, nested sections
  and directives. Sections are used as labels, while directives are kept as a
  value. Sections and directives can have positional arguments inside values
  of "arg" nodes. Arguments of sections must be the firsts child of the
  section node.

  This lens doesn't support automatic string quoting. Hence, the string must
  be quoted when containing a space.

  Create a new VirtualHost section with one directive:
  > clear /files/etc/apache2/sites-available/foo/VirtualHost
  > set /files/etc/apache2/sites-available/foo/VirtualHost/arg "172.16.0.1:80"
  > set /files/etc/apache2/sites-available/foo/VirtualHost/directive "ServerAdmin"
  > set /files/etc/apache2/sites-available/foo/VirtualHost/*[self::directive="ServerAdmin"]/arg "admin@example.com"

About: Configuration files
  This lens applies to files in /etc/httpd and /etc/apache2. See <filter>.

*)

module Httpd =

autoload xfm

(******************************************************************
 *                           Utilities lens
 *****************************************************************)
let dels (s:string)     = del s s

(* deal with continuation lines *)
let sep_spc    =  del /([ \t]+|[ \t]*\\\\\r?\n[ \t]*)/ " "

let sep_osp             = Sep.opt_space
let sep_eq              = del /[ \t]*=[ \t]*/ "="

let nmtoken             = /[a-zA-Z:_][a-zA-Z0-9:_.-]*/
let word                = /[a-zA-Z][a-zA-Z0-9._-]*/

let comment             = Util.comment
let eol                 = Util.doseol
let empty               = Util.empty_dos
let indent              = Util.indent

(* borrowed from shellvars.aug *)
let char_arg_dir  = /([^\\ '"\t\r\n]|[^\\ '"\t\r\n][^ '"\t\r\n]*[^\\ '"\t\r\n])|\\\\"|\\\\'/
let char_arg_sec  = /[^ '"\t\r\n>]|\\\\"|\\\\'/
let cdot = /\\\\./
let cl = /\\\\\n/
let dquot =
     let no_dquot = /[^"\\\r\n]/
  in /"/ . (no_dquot|cdot|cl)* . /"/
let squot =
     let no_squot = /[^'\\\r\n]/
  in /'/ . (no_squot|cdot|cl)* . /'/
let comp = /[<>=]?=/

(******************************************************************
 *                            Attributes
 *****************************************************************)

let arg_dir = [ label "arg" . store (char_arg_dir+|dquot|squot) ]
let arg_sec = [ label "arg" . store (char_arg_sec+|comp|dquot|squot) ]

let argv (l:lens) = l . (sep_spc . l)*

let directive = [ indent . label "directive" . store word .
                  (sep_spc . argv arg_dir)? . eol ]

let section (body:lens) =
    (* opt_eol includes empty lines *)
    let opt_eol = del /([ \t]*#?\r?\n)*/ "\n" in
    let inner = (sep_spc . argv arg_sec)? . sep_osp .
             dels ">" . opt_eol . ((body|comment) . (body|empty|comment)*)? .
             indent . dels "</" in
    let kword = key word in
    let dword = del word "a" in
        [ indent . dels "<" . square kword inner dword . del ">" ">" . eol ]

let rec content = section (content|directive)

let lns = (content|directive|comment|empty)*

let filter = (incl "/etc/apache2/apache2.conf") .
             (incl "/etc/apache2/httpd.conf") .
             (incl "/etc/apache2/ports.conf") .
             (incl "/etc/apache2/conf.d/*") .
             (incl "/etc/apache2/conf-available/*.conf") .
             (incl "/etc/apache2/mods-available/*") .
             (incl "/etc/apache2/sites-available/*") .
             (incl "/etc/httpd/conf.d/*.conf") .
             (incl "/etc/httpd/httpd.conf") .
             (incl "/etc/httpd/conf/httpd.conf") .
             Util.stdexcl

let xfm = transform lns filter


Make sure the usage shows up properly formated.

(*
Module: Ssh
  Parses ssh client configuration

Author: Jiri Suchomel <jsuchome@suse.cz>

About: Reference
    ssh_config man page

About: License
    This file is licensed under the GPL.

About: Lens Usage
  Sample usage of this lens in augtool

(start code)
augtool> set /files/etc/ssh/ssh_config/Host example.com
augtool> set /files/etc/ssh/ssh_config/Host[.='example.com']/RemoteForward/machine1:1234 machine2:5678
augtool> set /files/etc/ssh/ssh_config/Host[.='example.com']/Ciphers/1 aes128-ctr
augtool> set /files/etc/ssh/ssh_config/Host[.='example.com']/Ciphers/2 aes192-ctr
(end code)

*)

module Ssh =
    autoload xfm

    let eol = del /[ \t]*\n/ "\n"
    let spc = Util.del_ws_spc

    let key_re = /[A-Za-z0-9]+/
               - /SendEnv|Host|ProxyCommand|RemoteForward|LocalForward|MACs|Ciphers/

    let comment = Util.comment
    let empty = Util.empty
    let comma = Util.del_str ","
    let indent = Util.indent
    let value_to_eol = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/
    let value_to_spc = store /[^ \t\n]+/
    let value_to_comma = store /[^, \t\n]+/

    let array_entry (k:string) =
        [ indent . key k . counter k . [ spc . seq k . value_to_spc]* . eol ]

    let commas_entry (k:string) =
	[ key k . counter k . spc .
	    [ seq k . value_to_comma] . ([ seq k . comma . value_to_comma])* . eol ]

    let send_env = array_entry "SendEnv"

    let proxy_command = [ indent . key "ProxyCommand" . spc . value_to_eol . eol ]

    let fw_entry (k:string) = [ indent . key k . spc .
	[ key /[^ \t\n\/]+/ . spc . value_to_eol . eol ]]

    let remote_fw = fw_entry "RemoteForward"
    let local_fw = fw_entry "LocalForward"

    let ciphers = commas_entry "Ciphers"
    let macs	= commas_entry "MACs"

    let other_entry =
	[ indent . key key_re . spc . value_to_spc . eol ]

    let entry = (comment | empty
	| send_env
	| proxy_command
	| remote_fw
	| local_fw
	| macs
	| ciphers
	| other_entry)

    let host = [ key "Host" . spc . value_to_eol . eol . entry* ]

    let lns = entry* . host*

    let xfm = transform lns (incl "/etc/ssh/ssh_config" .
                             incl (Sys.getenv("HOME") . "/.ssh/config"))

(*
Module: Ssh
  Parses ssh client configuration

Author: Jiri Suchomel <jsuchome@suse.cz>

About: Reference
    ssh_config man page

About: License
    This file is licensed under the GPL.

About: Lens Usage
  Sample usage of this lens in augtool

augtool> set /files/etc/ssh/ssh_config/Host example.com
augtool> set /files/etc/ssh/ssh_config/Host[.='example.com']/RemoteForward/machine1:1234 machine2:5678
augtool> set /files/etc/ssh/ssh_config/Host[.='example.com']/Ciphers/1 aes128-ctr
augtool> set /files/etc/ssh/ssh_config/Host[.='example.com']/Ciphers/2 aes192-ctr

*)

module Ssh =
    autoload xfm

    let eol = del /[ \t]*\n/ "\n"
    let spc = Util.del_ws_spc

    let key_re = /[A-Za-z0-9]+/
               - /SendEnv|Host|ProxyCommand|RemoteForward|LocalForward|MACs|Ciphers/

    let comment = Util.comment
    let empty = Util.empty
    let comma = Util.del_str ","
    let indent = Util.indent
    let value_to_eol = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/
    let value_to_spc = store /[^ \t\n]+/
    let value_to_comma = store /[^, \t\n]+/

    let array_entry (k:string) =
        [ indent . key k . counter k . [ spc . seq k . value_to_spc]* . eol ]

    let commas_entry (k:string) =
	[ key k . counter k . spc .
	    [ seq k . value_to_comma] . ([ seq k . comma . value_to_comma])* . eol ]

    let send_env = array_entry "SendEnv"

    let proxy_command = [ indent . key "ProxyCommand" . spc . value_to_eol . eol ]

    let fw_entry (k:string) = [ indent . key k . spc .
	[ key /[^ \t\n\/]+/ . spc . value_to_eol . eol ]]

    let remote_fw = fw_entry "RemoteForward"
    let local_fw = fw_entry "LocalForward"

    let ciphers = commas_entry "Ciphers"
    let macs	= commas_entry "MACs"

    let other_entry =
	[ indent . key key_re . spc . value_to_spc . eol ]

    let entry = (comment | empty
	| send_env
	| proxy_command
	| remote_fw
	| local_fw
	| macs
	| ciphers
	| other_entry)

    let host = [ key "Host" . spc . value_to_eol . eol . entry* ]

    let lns = entry* . host*

    let xfm = transform lns (incl "/etc/ssh/ssh_config" .
                             incl (Sys.getenv("HOME") . "/.ssh/config"))


Dnsmasq: process files in /etc/dnsmasq.d/*

Fixes bug #65 reported by abnormaliti