As quickly discussed on IRC, the idea of autogeneration is nice. Please push to a branch so that we can smooth the edges and integration with autotools, and then we can re-post the final patch set. Fabio On 2/5/2013 4:07 PM, Jan Pokorný wrote: > This file is conf/corosync.rnc that models set of valid (in relatively > weak sense) corosync configurations as captured in corosync.conf and > uses RELAX NG Compact Syntax notation for that purpose. > > This was chosen as the most viable option (e.g., when compared > to standard XML encoding of RELAX NG, see below for more reasons) > for modifications and comprehension performed *by humans* and > its brevity is also importand from versioning system perspective. > For automated processing, it can be (and actually is being done > as one of the step towards a final man page/Augeas lens) easily > converted into computer-friendly XML notation, so the advantage > of both approaches can be utilized. Big advantage of RELAX NG > is the simple extendability using various annotations and/or > tags from custom namespace. > > As a side-effect, this schema can be directly used to validate > XML form of corosync.conf (see COROSYNC.XML(5)) if one prefers > it (and beside that, it is to be used in cman->pcmk cluster > conversion utility, which was a prime reason for this changset > originally). > > Apparently, having single authoritative source/model of possible > configurations as a source for producing corosync.conf documentation > and Augeas lens for this file alleviates maintainer's effort and > indirectly leads to more up-to-date/up-to-reality reflection of > possible configuration items. Systematic approach is usually > pretty reasonable... > > The core of this changeset, corosync.rnc, is mostly a result > of copy-paste from original man page, analyzing coroparse.c > and few others for the expected types/sets of values for > particular options and some other annotation work (see > integration task 4/ below). > > Technical details > ----------------- > > - generating corosync.conf documentation: > > rnctree.py > -> [corosync.rnc] ---------> [corosync.full.rng] --------+ > | > xsltproc > simplification-wrapper.xsl > xsltproc | > [corosync.conf.asciidoc] <-------- [corosync.rng] <------+ > + rng2asciidocman.xsl > | xsltproc > asciidoc +-----------> [corosync.conf.5] > | / manpage.xsl > +--> [corosync.conf.xml] --K > \ xsltproc > +-----------> [corosync.conf.5.html] > xhtml.xsl > > - generating corosync.aug Augeas lens: > > rnctree.py > -> [corosync.rnc] ---------> [corosync.full.rng] --------+ > | > xsltproc > rng2lens.xsl > | > [corosync.aug] <------+ > > - apparently, new dependencies in build-time are following > (checks also added into configure.ac): > - xsltproc (or another XSLT 1.0 compliant processor) > - DocBook 5+ stylesheets > - AsciiDoc, and therefore > - Python (version [2.6, 3.0] should be fine) > - optionally trang, but custom rnc2rng (see below) logic is embedded > (this requires Python as well) > > - it might not be difficult to generate C parser code based on the > schema described in corosync.rnc in a similar way in the future, > however this is the next-level challenge > > Licensing concerns and bundling files of other projects > ------------------------------------------------------- > > Not all the added files are authored by me, however they are either > licensed also under revised BSD (lex.py, rnc_tokenize.py, rnctree.py) > or I got approval from the original author as the original licensing > was unclear (simplification.xsl). See LICENSE file modifications. > > The paragraph above enumerated the files that were bundled due to > a lack of respective packages in RHEL or elsewhere and partly because > they are used solely for the purpose or producing a build/release. > > The respective projects are: > - rnc2rng [1] (rnc_tokenize.py, rnctree.py) > - this is a light-weight alternative to trang > - originally public domain, I maintain the extended version licensed > under revised BSD (with an awareness of the original author) > and fined-tuned particularly for this purpose > - PLY [2] (lex.py) > - lexical analyzer used in rnc2rng, which bundles it as well > "since beginning" > - "relax-ng utitilites" [3] (simplification.xsl) > > Integration tasks > ----------------- > > The changeset needs some more love in several aspects: > > 1/ which files are to be part of installation/distribution/tarball > (see ascii-art schemes under Technical details) > - corosync.aug, corosync.conf.5{,.html}? > - corosync.rng? > > 2/ autotools integration > I am not an expert here; the dependencies based on modification > time seem to work only occasinally, "make clear" misses some > by-products, "make dist" and the like may forget some files > (see also 1/) > > 3/ portability > - will AsciiDoc always install XSLT wrappers in > /etc/asciidoc/docbook-xsl? > - and many others, also the variability in locations is connected > to 2/ > > 4/ reflect current state in corosync.rnc > - I tried hard to make sure the schema corresponds to the reality > (using original man page and Augeas lens, and the code itself) > but it should be reviewed carefully by the corosync expert > > [1] http://fedorapeople.org/cgit/jpokorny/public_git/rnc2rng.git/ > (real main project homepage is expected soon) > [2] http://www.dabeaz.com/ply/ > [3] http://downloads.xmlschemata.org/relax-ng/utilities/ > > Signed-off-by: Jan Pokorný <jpokorny@xxxxxxxxxx> > --- > .gitignore | 6 + > LICENSE | 22 +- > conf/Makefile.am | 42 +- > conf/common.xsl | 77 +++ > conf/corosync.rnc | 729 ++++++++++++++++++++++++++ > conf/lenses/corosync.aug | 181 ------- > conf/lex.py | 1069 +++++++++++++++++++++++++++++++++++++++ > conf/rnc_tokenize.py | 275 ++++++++++ > conf/rnctree.py | 609 ++++++++++++++++++++++ > conf/rng2asciidocman.xsl | 490 ++++++++++++++++++ > conf/rng2lens.xsl | 333 ++++++++++++ > conf/simplification-wrapper.xsl | 25 + > conf/simplification.xsl | 1037 +++++++++++++++++++++++++++++++++++++ > conf/xsddatatypes2lens.xsl | 144 ++++++ > configure.ac | 5 + > man/.gitignore | 1 + > man/Makefile.am | 31 +- > man/corosync.conf.5 | 684 ------------------------- > 18 files changed, 4884 insertions(+), 876 deletions(-) > create mode 100644 conf/common.xsl > create mode 100644 conf/corosync.rnc > delete mode 100644 conf/lenses/corosync.aug > create mode 100644 conf/lex.py > create mode 100644 conf/rnc_tokenize.py > create mode 100755 conf/rnctree.py > create mode 100644 conf/rng2asciidocman.xsl > create mode 100644 conf/rng2lens.xsl > create mode 100644 conf/simplification-wrapper.xsl > create mode 100644 conf/simplification.xsl > create mode 100644 conf/xsddatatypes2lens.xsl > delete mode 100644 man/corosync.conf.5 > > diff --git a/.gitignore b/.gitignore > index 1cdac50..5a77dc7 100644 > --- a/.gitignore > +++ b/.gitignore > @@ -3,6 +3,8 @@ > *.so* > *.lo > *.la > +*.pyc > +*.swp > .libs > .deps > .version > @@ -28,3 +30,7 @@ missing > tags > ID > Doxyfile > +/conf/corosync*.rng > +/conf/corosync.conf.asciidoc > +/conf/corosync.conf.xml > +/conf/lenses/corosync.aug > diff --git a/LICENSE b/LICENSE > index 8d32cd1..b3e3d94 100644 > --- a/LICENSE > +++ b/LICENSE > @@ -2,17 +2,27 @@ > The following license applies to every file in this source distribution except > for the files git-version-gen, and gitlog-to-changelog. > > -The git* files, which are available under GPLv3 or later, are only used by > +The git* files, which are available under GPLv3 or later, are only used by > our release process to generate text file content and are not part of any > generated binary. > + > +Some of the files, although licensed like the vast majority of corosync > +codebase under revised BSD license, the actual wording differs as > +the licensors are different. The authoritative license text can be > +found within these files. > + > +Special exception is simplification.xsl transformation obtained verbatim > +from http://downloads.xmlschemata.org/relax-ng/utilities/simplification.xsl, > +author of which, Eric van der Vlist, agreed with effectively inheriting > +corosync's revised BSD license. > ----------------------------------------------------------------------------- > > Copyright (c) 2002-2004 MontaVista Software, Inc. > -Copyright (c) 2005-2010 Red Hat, Inc. > +Copyright (c) 2005-2013 Red Hat, Inc. > > All rights reserved. > > -This software licensed under BSD license, the text of which follows: > +This software licensed under revised BSD license, the text of which follows: > > Redistribution and use in source and binary forms, with or without > modification, are permitted provided that the following conditions are met: > @@ -39,10 +49,10 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF > THE POSSIBILITY OF SUCH DAMAGE. > > ----------------------------------------------------------------------------- > -The corosync project uses software for release processing which generates > +The corosync project uses software for release processing, which generates > changelogs and version information for the software. These programs are not > -used by the generated binaries or libraries These files are git-version-gen > -and gitlog-to-changelog. > +used by the generated binaries or libraries. > +These files are git-version-gen and gitlog-to-changelog. > ----------------------------------------------------------------------------- > The license for these files is as follows: > This program is free software: you can redistribute it and/or modify > diff --git a/conf/Makefile.am b/conf/Makefile.am > index 69f7ff9..d0771c5 100644 > --- a/conf/Makefile.am > +++ b/conf/Makefile.am > @@ -1,4 +1,4 @@ > -# Copyright (c) 2009 Red Hat, Inc. > +# Copyright (c) 2013 Red Hat, Inc. > # > # Authors: Andrew Beekhof > # Steven Dake (sdake@xxxxxxxxxx) > @@ -69,3 +69,43 @@ if INSTALL_DBUSCONF > dbusdir = $(sysconfdir)/dbus-1/system.d > dbus_DATA = corosync-signals.conf > endif > + > +# > +# rnc -> man page DocBook, Augeas lens > +# > + > +CONF_NAME = corosync.conf > +CONF_SCHEMA_ORIG = corosync.rnc > +CONF_XSL_ASCIIDOCMAN = rng2asciidocman.xsl > +CONF_XSL_LENS = rng2lens.xsl > +CONF_XSLS_ASCIIDOCMAN = $(CONF_XSL_ASCIIDOCMAN) common.xsl > +CONF_XSLS_LENS = $(CONF_XSL_LENS) xsddatatypes2lens.xsl common.xsl > +CONF_SCRIPT = rnctree.py > +CONF_SIMPLIFICATOR = simplification-wrapper.xsl > +# derived > +CONF_ASCIIDOC = $(CONF_NAME:=.asciidoc) # fixed name > +CONF_DOCBOOK = $(CONF_NAME:=.xml) # fixed name > + > +CONF_SCHEMA = $(CONF_SCHEMA_ORIG:.rnc=.rng) > +CONF_SCHEMA_ORIG_RNG = $(CONF_SCHEMA_ORIG:.rnc=.orig.rng) > + > +noinst_DATA = $(CONF_SCHEMA_ORIG) $(CONF_SCHEMA_ORIG_RNG) \ > + $(CONF_ASCIIDOC) $(CONF_DOCBOOK) > + > +$(CONF_DOCBOOK): $(CONF_ASCIIDOC) > + $(ASCIIDOC) --doctype=manpage -b docbook -d manpage $< > + > +$(CONF_ASCIIDOC): $(CONF_SCHEMA) $(CONF_XSLS_ASCIIDOCMAN) > + $(XSLTPROC) $(CONF_XSL_ASCIIDOCMAN) $< > $@ > + > +lenses/corosync.aug: $(CONF_SCHEMA_ORIG_RNG) $(CONF_XSLS_LENS) > + $(XSLTPROC) $(CONF_XSL_LENS) $< > $@ > + > +#trang -O rng $(CONF_SCHEMA_ORIG) $@ > +$(CONF_SCHEMA_ORIG_RNG): $(CONF_SCHEMA_ORIG) $(CONF_SCRIPT) > + cat $< | $(PYTHON) $(CONF_SCRIPT) > $@ > + > +$(CONF_SCHEMA): $(CONF_SCHEMA_ORIG_RNG) $(CONF_SIMPLIFICATOR) > + $(XSLTPROC) $(CONF_SIMPLIFICATOR) $< > $@ > + > +all-local: lenses/corosync.aug > diff --git a/conf/common.xsl b/conf/common.xsl > new file mode 100644 > index 0000000..0b75fc3 > --- /dev/null > +++ b/conf/common.xsl > @@ -0,0 +1,77 @@ > +<?xml version="1.0" encoding="utf-8"?> > +<xsl:stylesheet version="1.0" > + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> > + > +<!-- > + Copyright 2013 Red Hat, Inc. > + All rights reserved. > + > + Redistribution and use in source and binary forms, with or without > + modification, are permitted provided that the following conditions are met: > + > + - Redistributions of source code must retain the above copyright notice, > + this list of conditions and the following disclaimer. > + - Redistributions in binary form must reproduce the above copyright notice, > + this list of conditions and the following disclaimer in the documentation > + and/or other materials provided with the distribution. > + - Neither the name of the Red Hat, Inc. nor the names of its > + contributors may be used to endorse or promote products derived from this > + software without specific prior written permission. > + > + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" > + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE > + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF > + THE POSSIBILITY OF SUCH DAMAGE. > +--> > + > +<!-- xsltdoc (http://www.kanzaki.com/parts/xsltdoc.xsl) header --> > +<xsl:template name="_doas_description"> > + <rdf:RDF xmlns="http://purl.org/net/ns/doas#"> > + <rdf:Description rdf:about=""> > + <title>common.xsl XSLT stylesheet</title> > + <description> > + This stylesheet contains shared helper function-like > + templates. > + </description> > + <author rdf:parseType="Resource"> > + <name>Jan Pokorný</name> > + <mbox rdf:resource="jpokorny@xxxxxxxxxx"/> > + </author> > + <created>2013-02-04</created> > + <release rdf:parseType="Resource"> > + <revision>0.1</revision> > + <created>2013-02-04</created> > + </release> > + <rights>Copyright 2013 Red Hat, Inc.</rights> > + <license rdf:resource="http://opensource.org/licenses/BSD-3-Clause"/> > + </rdf:Description> > + </rdf:RDF> > +</xsl:template> > + > +<xsl:template name="text-join"> > + <!--** Simple text join of 'items' using 'sep' (defaults to space). --> > + <!-- TODO: normalize-space? --> > + <xsl:param name="items"/> > + <xsl:param name="sep" select="$SP"/> > + <xsl:param name="markup" value="''"/> > + <xsl:for-each select="$items"> > + <xsl:choose> > + <xsl:when test="position() = 1"> > + <xsl:value-of select="concat($markup, ., $markup)"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:value-of select="concat($sep, $markup, ., $markup)"/> > + </xsl:otherwise> > + </xsl:choose> > + </xsl:for-each> > +</xsl:template> > + > +</xsl:stylesheet> > diff --git a/conf/corosync.rnc b/conf/corosync.rnc > new file mode 100644 > index 0000000..a5c9e52 > --- /dev/null > +++ b/conf/corosync.rnc > @@ -0,0 +1,729 @@ > +# style guide (RELAX NG Compact only): > +# * '##' comments are wrapped at 50/80 (first line/rest), 2-spaced sentence sep, > +# AsciiDoc formatting is used within them > +# * sort everything (except for dependencies/nesting) to ease the lookup > + > +namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0" > +namespace a4doc = "http://people.redhat.com/jpokorny/ns/a4doc" > + > +start = corosync > + > +corosync = > + element corosync { > + (logging? > + & nodelist? > + & resources? > + & quorum? > + & totem > + & uidgid?) > + } > + > +## LOGGING #################################################################### > + > +# only named set of attributes > +common_logging = > + # CFG: corosync.conf, cluster.conf > + ## This specifies whether debug output is > + ## logged for this particular logger. Also can contain value 'trace', > + ## which is highest level of debug informations. > + [ a:defaultValue = "off" ] > + attribute debug {"off"|"on"|"trace"}?, > + > + # CFG: corosync.conf, cluster.conf > + ## If the *to_logfile* option is set to > + ## 'yes', this option specifies the pathname of the log file. > + attribute logfile {text}?, > + > + # CFG: corosync.conf, cluster.conf > + ## This specifies the logfile level for this particular subsystem. Ignored > + ## if *debug* is 'on'. Note: 'debug' is the same as if *debug* is 'on'. > + [ a:defaultValue = "info" ] > + attribute logfile_priority {"alert" > + |"crit" > + |"debug" > + |"emerg" > + |"err" > + |"info" > + |"notice" > + |"warning" > + }?, > + > + # CFG: corosync.conf, cluster.conf > + ## This specifies the syslog facility type > + ## that will be used for any messages sent to syslog. > + [ a:defaultValue = "daemon" ] > + attribute syslog_facility {"daemon" > + |"local0" > + |"local1" > + |"local2" > + |"local3" > + |"local4" > + |"local5" > + |"local6" > + |"local7" > + }?, > + > + # CFG: corosync.conf, cluster.conf > + ## This specifies the syslog level for this > + ## particular subsystem. Ignored if *debug* is 'on'. Note: 'debug' > + ## is the same as *debug* is 'on'. > + [ a:defaultValue = "info" ] > + attribute syslog_priority {"alert" > + |"crit" > + |"debug" > + |"emerg" > + |"err" > + |"info" > + |"notice" > + |"warning" > + }?, > + > + # XXX: undocumented > + attribute tags {text}?, > + > + # CFG: corosync.conf, cluster.conf > + ## This specifies whether to use > + ## the respective destination of logging output. > + ## > + ## Please note, if you are using *to_logfile* and want to rotate the file, > + ## use `logrotate(8)` with the option `copytruncate`, e.g. > + ## > + ## ---- > + ## /var/log/corosync.log { > + ## missingok > + ## compress > + ## notifempty > + ## daily > + ## rotate 7 > + ## copytruncate > + ## } > + ## ---- > + [ a:defaultValue = "no" ] > + attribute to_logfile {"no"|"yes"}?, > + > + # CFG: corosync.conf > + ## This specifies whether to use > + ## the respective destination of logging output. > + [ a:defaultValue = "yes" ] > + attribute to_stderr {"no"|"yes"}?, > + > + # CFG: corosync.conf, cluster.conf > + ## This specifies whether to use > + ## the respective destination of logging output. > + [ a:defaultValue = "yes" ] > + attribute to_syslog {"no"|"yes"}? > + > +logging = > + ## In this configuration section, one can > + ## adjust logging. > + element logging { > + # CFG: corosync.conf > + ## This specifies that file and line should > + ## be printed. > + [ a:defaultValue = "off" ] > + attribute fileline {"off"|"on"}?, > + > + # CFG: corosync.conf > + ## This specifies that the code function name > + ## should be printed. > + [ a:defaultValue = "off" ] > + attribute function_name {"off"|"on"}?, > + > + # CFG: corosync.conf > + ## This specifies that a timestamp is placed > + ## on all log messages. > + [ a:defaultValue = "off" ] > + attribute timestamp {"off"|"on"}?, > + > + common_logging, > + logger_subsys* > + } > + > +logger_subsys = > + element logger_subsys { > + # CFG: corosync.conf, cluster.conf > + ## This specifies the subsystem identity > + ## (name) for which logging is specified. This is the name used by > + ## a service in the `log_init` call, e.g., 'CPG'. > + attribute subsys {text}, > + > + common_logging > + } > + > +## NODELIST ################################################################### > + > +nodelist = > + ## In this configuration section, one can > + ## adjust nodes in the cluster. > + element nodelist { > + node* > + } > + > +node = > + element node { > + # XXX: implied check > + # CFG: corosync.conf, cluster.conf > + ## This configuration option is optional when > + ## using IPv4 and required when using IPv6. This is a 32bit value > + ## specifying the node identifier delivered to the cluster membership > + ## service. If this is not specified with IPv4, *nodeid* will be > + ## determined from the 32bit IP address the system to which the system > + ## is bound with ring identifier of 0. The node identifier value of zero > + ## is reserved and should not be used. > + attribute nodeid {xsd:unsignedInt}?, > + > + # CFG: corosync.conf, cluster.conf > + # NOTE: not a direct mapping in cluster.conf (clusternode/votes) > + attribute quorum_votes {xsd:unsignedInt}?, > + > + # CFG: corosync.conf, cluster.conf > + ## This specifies IP address of one of the nodes for particular ring > + ## as denoted by its number (instead 0, there can be higher numbers). > + attribute ring0_addr {text}, > + attribute ring1_addr {text}?, > + attribute ring2_addr {text}?, > + attribute ring3_addr {text}?, > + attribute ring4_addr {text}?, > + attribute ring5_addr {text}?, > + attribute ring6_addr {text}?, > + attribute ring7_addr {text}?, > + attribute ring8_addr {text}?, > + attribute ring9_addr {text}? > + # NOTE: Augeas lens for corosync.conf counts on X = 0..9 only > + } > + > +## QUORUM ##################################################################### > + > +quorum = > + ## In this configuration section, one can > + ## adjust quorum. > + element quorum { > + # CFG: corosync.conf > + ## This enables Downscale feature > + ## (see `votequorum(5)`). > + [ a:defaultValue = "0" ] > + attribute allow_downscale {"0"|"1"}?, > + > + # CFG: corosync.conf > + ## This enables Auto Tie Breaker feature > + ## (see `votequorum(5)`). > + [ a:defaultValue = "0" ] > + attribute auto_tie_breaker {"0"|"1"}?, > + > + # CFG: corosync.conf, cluster.conf > + ## This specifies the number of expected votes, overriding the number > + ## implied by the number of *node* items within *nodes*. > + attribute expected_votes {xsd:unsignedInt}?, > + > + # CFG: corosync.conf > + ## This enables Last Man Standing feature > + ## (see `votequorum(5)`). > + [ a:defaultValue = "0" ] > + attribute last_man_standing {"0"|"1"}?, > + > + # CFG: corosync.conf > + ## This specifies the tunable for Last Man > + ## Standing feature (see `votequorum(5)`). > + [ a:defaultValue = "0" ] > + attribute last_man_standing_window {xsd:nonNegativeInteger}?, > + > + # CFG: corosync.conf > + ## This specifies the quorum algorithm to use. > + ## As of now, only 'corosync_votequorum' is supported. > + attribute provider {"corosync_votequorum"}?, > + > + # CFG: corosync.conf, cluster.conf > + ## This enables two node cluster operations > + ## (see `votequorum(5)`). > + [ a:defaultValue = "0" ] > + attribute two_node {"0"|"1"}?, > + > + # CFG: corosync.conf > + attribute votes {xsd:unsignedInt}?, > + > + # CFG: corosync.conf > + ## This enables Wait For All feature > + ## (see `votequorum(5)`). > + [ a:defaultValue = "0" ] > + attribute wait_for_all {"0"|"1"}? > + } > + > +## RESOURCES ################################################################## > + > +# only named set of attributes > +common_resource = > + # XXX: undocumented > + attribute max {xsd:decimal}?, > + > + # XXX: undocumented > + attribute poll_period {xsd:unsignedInt}?, > + > + # XXX: undocumented > + attribute recovery {"reboot"|"shutdown"|"watchdog"|"none"}? > + > +load_15min = > + element load_15min { > + common_resource? > + } > + > +memory_used = > + element memory_used { > + common_resource? > + } > + > +system = > + element system { > + (load_15min? > + &memory_used?) > + } > + > +resources = > + element resources { > + system? > + } > + > +## TOTEM ###################################################################### > + > +totem = > + ## In this configuration section, one can > + ## adjust totem protocol. > + element totem { > + # CFG: corosync.conf > + ## This configuration option is only relevant > + ## when no *nodeid* option within *nodelist* section is specified. Some > + ## corosync clients require a signed 32bit nodeid that is greater than > + ## zero however, by default, corosync uses all 32 bits of the IPv4 address > + ## space when generating a nodeid. > + ## Set this option to 'yes' to force the high bit to be zero and therefor > + ## ensure the nodeid is a positive signed 32bit integer. > + [ a:defaultValue = "no" > + a4doc:discretion-hint = > + "The clusters behavior is undefined if this option is enabled" > + ~ " on only a subset of the cluster (for example during a rolling" > + ~ " upgrade)." ] > + attribute clear_node_high_bit {"no"|"yes"}?, > + > + # CFG: corosync.conf, cluster.conf > + # NOTE: not a direct mapping in cluster.conf (top-level tag instead) > + ## This specifies the name of cluster and it's > + ## used for automatic generating of multicast address. > + attribute cluster_name {text}?, > + > + # XXX: implied check > + # CFG: corosync.conf, cluster.conf > + ## This timeout specifies in milliseconds how > + ## long to wait for consensus to be achieved before starting a new round > + ## of membership configuration. The minimum value for *consensus* must be > + ## 1.2 x *token*. > + ## > + ## This value will be automatically calculated at 1.2 x *token* if > + ## the user doesn't specify a *consensus* value. > + ## > + ## For two node clusters, a *consensus* larger than the *join* timeout but > + ## less than *token* is safe. For three-node or larger clusters, > + ## *consensus* should be larger than *token*. There is an increasing risk > + ## of odd membership changes, which still guarantee virtual synchrony, > + ## as node count grows if *consensus* is less than *token*. > + [ a:defaultValue = "1200" ] > + attribute consensus {xsd:unsignedInt}?, > + > + # XXX: missing nss? > + # CFG: corosync.conf > + ## This specifies which cipher should be used > + ## to encrypt all messages. > + [ a:defaultValue = "aes256" ] > + attribute crypto_cipher {"3des"|"aes128"|"aes192"|"aes256"|"none"}?, > + > + # XXX: undocumented > + attribute crypto_compat {"2.0"|"2.2"}?, > + > + # CFG: corosync.conf > + ## This specifies which HMAC authentication > + ## should be used to authenticate all messages. > + [ a:defaultValue = "sha1" ] > + attribute crypto_hash {"none"|"md5"|"sha1"|"sha256"|"sha384"|"sha512"}?, > + > + # XXX: undocumented > + attribute crypto_type {"3des"|"aes128"|"aes192"|"aes256"|"nss"}?, > + > + # CFG: corosync.conf > + ## This timeout specifies in milliseconds how > + ## long to wait before checking that a network interface is back up after > + ## it has been downed. > + [ a:defaultValue = "1000" ] > + attribute downcheck {xsd:unsignedInt}?, > + > + # CFG: corosync.conf, cluster.conf > + ## This constant specifies how many rotations > + ## of the token without receiving any of the messages when messages should > + ## be received may occur before a new configuration is formed. > + [ a:defaultValue = "2500" ] > + attribute fail_recv_const {xsd:unsignedInt}?, > + > + # CFG: corosync.conf > + ## Configures the optional HeartBeating > + ## mechanism for faster failure detection. Keep in mind that engaging this > + ## mechanism in lossy networks could cause faulty loss declaration as > + ## the mechanism relies on the network for heartbeating. > + ## > + ## So as a rule of thumb use this mechanism if you require improved > + ## failure in low to medium utilized networks. > + ## > + ## This constant specifies the number of heartbeat failures the system > + ## should tolerate before declaring heartbeat failure, e.g., 3. > + ## Also if this value is not set or is 0, the heartbeat mechanism is > + ## not engaged in the system and token rotation is the method of failure > + ## detection. Zero disables the mechanism. > + [ a:defaultValue = "0" ] > + attribute heartbeat_failures_allowed {xsd:unsignedInt}?, > + > + # CFG: corosync.conf > + ## This timeout specifies in milliseconds > + ## how long the token should be held by the representative when > + ## the protocol is under low utilization. > + [ a:defaultValue = "180" > + a4doc:danger-hint = > + "It is not recommended to override this value without guidance" > + ~ " from the corosync community." ] > + attribute hold {xsd:unsignedInt}?, > + > + # CFG: corosync.conf, cluster.conf > + ## This timeout specifies in milliseconds how > + ## long to wait for join messages in the membership protocol. > + [ a:defaultValue = "50" ] > + attribute join {xsd:unsignedInt}?, > + > + # CFG: corosync.conf, cluster.conf > + ## This constant specifies the maximum number > + ## of messages that may be sent by one processor on receipt of the token. > + ## The *max_messages* parameter is limited to 256000 / *netmtu* to prevent > + ## overflow of the kernel transmit buffers. > + [ a:defaultValue = "17" ] > + attribute max_messages {xsd:unsignedInt}?, > + > + # CFG: corosync.conf > + ## This constant specifies in milliseconds > + ## the approximate delay that your network takes to transport one packet > + ## from one machine to another. This value is to be set by system engineers > + ## and please don't change it if not sure as this effects the failure > + ## detection mechanism using heartbeat. > + [ a:defaultValue = "50" ] > + attribute max_network_delay {xsd:unsignedInt}?, > + > + # CFG: corosync.conf > + ## This timeout specifies in milliseconds how > + ## long to wait before checking for a partition when no multicast traffic > + ## is being sent. If multicast traffic is being sent, the merge detection > + ## happens automatically as a function of the protocol. > + [ a:defaultValue = "200" ] > + attribute merge {xsd:unsignedInt}?, > + > + # CFG: corosync.conf, cluster.conf > + ## This constant defines the maximum number > + ## of times on receipt of a token a message is checked for retransmission > + ## before a retransmission occurs. This parameter is useful to modify for > + ## switches that delay multicast packets compared to unicast packets. > + ## The default setting works well for nearly all modern switches. > + [ a:defaultValue = "5" ] > + attribute miss_count_const {xsd:unsignedInt}?, > + > + # CFG: corosync.conf, cluster.conf > + ## This specifies the network maximum transmit > + ## unit. To set this value beyond 1500, the regular frame MTU, requires > + ## ethernet devices that support large, or also called jumbo, frames. > + ## If any device in the network doesn't support large frames, the protocol > + ## will not operate properly. The hosts must also have their mtu size set > + ## from 1500 to whatever frame size is specified here. > + ## > + ## Please note that while some NICs or > + ## switches claim large frame support, they support '9000' MTU as > + ## the maximum frame size including the IP header. Setting the *netmtu* > + ## and host MTUs to '9000' will cause totem to use the full 9000 bytes > + ## of the frame. Then Linux will add an 18byte header moving the full > + ## frame size to 9018. As a result some hardware will not operate properly > + ## with this size of data. A *netmtu* of '8982' seems to work for the few > + ## large frame devices that have been tested. Some manufacturers claim > + ## large frame support when in fact they support frame sizes of 4500 bytes. > + ## > + ## When sending multicast traffic, if the network frequently reconfigures, > + ## chances are that some device in the network doesn't support large frames. > + ## > + ## Choose hardware carefully if intending to use large frame support. > + [ a:defaultValue = "1500" ] > + attribute netmtu {xsd:unsignedInt}?, > + > + # XXX: undocumented > + attribute nodeid {xsd:unsignedInt}?, > + > + # CFG: corosync.conf > + ## This specifies the time in milliseconds > + ## to check if the failed ring can be auto-recovered. > + [ a:defaultValue = "1000" ] > + attribute rrp_autorecovery_check_timeout {xsd:unsignedInt}?, > + > + # XXX: implied check: count(interface) <= 4 (2 active + 2 passive) > + # CFG: corosync.conf, cluster.conf > + ## This specifies the mode of redundant ring. > + ## Active replication ('active') offers slightly lower latency from > + ## transmit to delivery in faulty network environments but with less > + ## performance. Passive replication ('passive') may nearly double > + ## the speed of the totem protocol if it doesn't become CPU bound. > + ## The remaining option is 'none', in which case only one network > + ## interface will be used to operate the totem protocol. > + ## > + ## If only one *interface* section is specified, 'none' is automatically > + ## chosen. If multiple *interface* sections are specified, only 'active' > + ## or 'passive' may be chosen. > + ## > + ## The maximum number of *interface* sections that is allowed for either > + ## mode ('active' or 'passive') is 2. > + attribute rrp_mode {"active"|"none"|"passive"}?, > + > + # CFG: corosync.conf > + ## This specifies the number of times > + ## a problem is detected with multicast before setting the link faulty for > + ## 'passive' *rrp_mode*. This variable is unused in 'active' *rrp_mode*. > + ## > + ## The default is 10 x *rrp_problem_count_threshold*. > + attribute rrp_problem_count_mcast_threshold {xsd:unsignedInt}?, > + > + # XXX: implied check > + # CFG: corosync.conf, cluster.conf > + ## This specifies the number of times > + ## a problem is detected with a link before setting the link faulty. > + ## Once a link is set faulty, no more data is transmitted upon it. Also, > + ## the problem counter is no longer decremented when the problem count > + ## timeout expires. > + ## > + ## A problem is detected whenever all tokens from the proceeding > + ## processor have not been received within the *rrp_token_expired_timeout*. > + ## The *rrp_problem_count_threshold* x *rrp_token_expired_timeout* should be > + ## at least 50 milliseconds less than the *token* timeout, or a complete > + ## reconfiguration may occur. > + [ a:defaultValue = "10" ] > + attribute rrp_problem_count_threshold {xsd:unsignedInt}?, > + > + # CFG: corosync.conf > + ## This specifies the time in milliseconds > + ## to wait before decrementing the problem count by 1 for a particular ring > + ## to ensure a link is not marked faulty for transient network failures. > + [ a:defaultValue = "2000" ] > + attribute rrp_problem_count_timeout {xsd:unsignedInt}?, > + > + # CFG: corosync.conf > + ## This specifies the time in milliseconds > + ## to increment the problem counter for the redundant ring protocol after > + ## not having received a token from all rings for a particular processor. > + ## > + ## This value will automatically be calculated from the *token* timeout > + ## and *problem_count_threshold* but may be overridden. > + [ a:defaultValue = "47" > + a4doc:danger-hint = > + "It is not recommended to override this value without guidance" > + ~ " from the corosync community." ] > + attribute rrp_token_expired_timeout {xsd:unsignedInt}?, > + > + # XXX: implied check/migration to current items > + # CFG: corosync.conf, cluster.conf > + ## This specifies that HMAC/SHA1 authentication should be used > + ## to authenticate all messages. It further specifies that all data > + ## should be encrypted with the nss library and aes256 encryption > + ## algorithm to protect data from eavesdropping. > + ## > + ## Enabling this option adds a encryption header to every message sent > + ## by totem which reduces total throughput. Also encryption and > + ## authentication consume extra CPU cycles in corosync. > + [ a:defaultValue = "on" > + a4doc:deprecation-hint = > + "It's recomended to use combination of *crypto_cipher* and *crypto_hash*." > + ] > + attribute secauth {"off"|"on"}?, > + > + # CFG: corosync.conf > + ## This timeout specifies in milliseconds > + ## an upper range between 0 and *send_join* to wait before sending a join > + ## message. For configurations with less than 32 nodes, this parameter > + ## is not necessary. For larger rings, this parameter is necessary > + ## to ensure the NIC is not overflowed with join messages on formation of > + ## a new ring. A reasonable value for large rings (128 nodes) would be > + ## __80__msec. Other timer values must also change if this value > + ## is changed. > + [ a:defaultValue = "0" > + a4doc:danger-hint = > + "Seek advice from the corosync mailing list if trying to run" > + ~ " larger configurations." ] > + attribute send_join {xsd:unsignedInt}?, > + > + # CFG: corosync.conf, cluster.conf > + ## This constant specifies how many rotations > + ## of the token without any multicast traffic should occur before the hold > + ## timer is started. > + [ a:defaultValue = "30" ] > + attribute seqno_unchanged_const {xsd:unsignedInt}?, > + > + # XXX: undocumented > + attribute threads {xsd:unsignedInt}?, > + > + # CFG: corosync.conf, cluster.conf > + ## This timeout specifies a period in > + ## milliseconds until a token loss is declared after not receiving > + ## a token. This is the time spent detecting a failure of a processor > + ## in the current configuration. Reforming a new configuration takes > + ## about 50 milliseconds in addition to this timeout. > + [ a:defaultValue = "1000" ] > + attribute token {xsd:unsignedInt}?, > + > + # CFG: corosync.conf > + ## This timeout specifies a period in > + ## milliseconds without receiving a token after which the token is > + ## retransmitted. This will be automatically calculated if *token* is > + ## modified. > + [ a:defaultValue = "238" > + a4doc:danger-hint = > + "It is not recommended to override this value without guidance" > + ~ " from the corosync community." ] > + attribute token_retransmit {xsd:unsignedInt}?, > + > + # CFG: corosync.conf, cluster.conf > + ## This value identifies how many token > + ## retransmits should be attempted before forming a new configuration. > + ## If this value is set, retransmit and hold will be automatically > + ## calculated from *retransmits_before_loss* and *token*. > + [ a:defaultValue = "4" ] > + attribute token_retransmits_before_loss_const {xsd:unsignedInt}?, > + > + # CFG: corosync.conf > + ## This option controls the transport > + ## mechanism used. If the interface to which corosync is binding is > + ## an RDMA interface such as RoCEE or Infiniband, the 'iba' parameter > + ## may be specified. To avoid the use of multicast entirely, a unicast > + ## transport parameter 'udpu' can be specified. This requires specifying > + ## the list of members that could potentially make up the membership > + ## in *nodelist* section before deployment. > + [ a:defaultValue = "udp" ] > + attribute transport {"iba"|"udp"|"udpu"}?, > + > + # CFG: corosync.conf > + ## This specifies the version of > + ## the configuration file. Currently the only valid value for this > + ## option is '2'. > + attribute version {xsd:unsignedInt}, > + > + # CFG: corosync.conf > + ## This option controls the virtual > + ## synchrony filter type used to identify a primary component. > + ## The preferred choice is YKD dynamic linear voting ('ykd'), however, for > + ## clusters larger than 32 nodes YKD consumes a lot of memory. For large > + ## scale clusters that are created by changing the MAX_PROCESSORS_COUNT > + ## #define in the C code totem.h file, the virtual synchrony filter 'none' > + ## is recommended but then AMF and DLCK services (which are currently > + ## experimental) are not safe for use. > + [ a:defaultValue = "ykd" ] > + attribute vsftype {"none"|"ykd"}?, > + > + # CFG: corosync.conf, cluster.conf > + ## This constant specifies the maximum number > + ## of messages that may be sent on one token rotation. If all processors > + ## perform equally well, this value could be large ('300'), which would > + ## introduce higher latency from origination to delivery for very large > + ## rings. To reduce latency in large rings (16+), the default is a safe > + ## compromise. If 1 or more slow processor(s) are present among fast > + ## processors, *window_size* should be no larger than 256000 / *netmtu* > + ## to avoid overflow of the kernel receive buffers. The user is notified > + ## of this by the display of a retransmit list in the notification logs. > + ## There is no loss of data, but performance is reduced when these errors > + ## occur. > + [ a:defaultValue = "50" ] > + attribute window_size {xsd:unsignedInt}?, > + > + interface* > + } > + > +interface = > + element interface { > + # CFG: corosync.conf, cluster.conf > + ## This specifies the network address > + ## the corosync executive should bind to. > + ## *bindnetaddr* should be an IP address configured on the system, or > + ## a network address. > + ## > + ## For example, if the local interface is `192.168.5.92` with netmask > + ## `255.255.255.0`, you should set *bindnetaddr* to `192.168.5.92` or > + ## `192.168.5.0`. If the local interface is `192.168.5.92` with netmask > + ## `255.255.255.192`, set *bindnetaddr* to `192.168.5.92` or `192.168.5.64`, > + ## and so forth. > + ## > + ## This may also be an IPv6 address, in which case IPv6 networking will be > + ## used. In this case, the exact address must be specified and there is no > + ## automatic selection of the network interface within a specific subnet > + ## as with IPv4. > + ## > + ## If IPv6 networking is used, *nodeid* options within *nodelist* section > + ## must be specified. > + attribute bindnetaddr {text}?, > + > + # CFG: corosync.conf > + ## If this is set to 'yes', the broadcast > + ## address will be used for communication. If this option is set, > + ## *mcastaddr* should not be set. > + [ a:defaultValue = "no" ] > + attribute broadcast {"no"|"yes"}?, > + > + # CFG: corosync.conf, cluster.conf > + ## This is the multicast address used > + ## by corosync executive. The default should work for most networks, but > + ## the network administrator should be queried about a multicast address > + ## to use. Avoid `224.x.x.x` because this is a "config" multicast address. > + ## > + ## This may also be an IPv6 multicast address, in which case IPv6 networking > + ## will be used. If IPv6 networking is used, *nodeid* options within > + ## *nodelist* section must be specified. > + ## > + ## It's not needed to use this option if *cluster_name* option in > + ## *totem* section is used. If both options are used, *mcastaddr* has > + ## higher priority. > + attribute mcastaddr {text}?, > + > + # CFG: corosync.conf, cluster.conf > + ## This specifies the UDP port number. > + ## It is possible to use the same multicast address on a network with > + ## the corosync services configured for different UDP ports. Please note > + ## corosync uses two UDP ports *mcastport* (for mcast receives) and > + ## *mcastport* - 1 (for mcast sends). If you have multiple clusters > + ## on the same network using the same *mcastaddr*, please configure > + ## the **mcastport**s with a gap. > + attribute mcastport {xsd:unsignedShort}?, > + > + # CFG: corosync.conf, cluster.conf > + ## This specifies the ring number for > + ## the interface. When using the redundant ring protocol, each interface > + ## should specify separate ring numbers to uniquely identify to > + ## the membership protocol which interface to use for which redundant ring. > + ## The *ringnumber* must start at '0'. > + attribute ringnumber {xsd:unsignedByte}?, > + > + # CFG: corosync.conf, cluster.conf > + ## This specifies the Time To Live (TTL). > + ## If you run your cluster on a routed network, the default of '1' will > + ## be too small. This option provides a way to increase this up to '255'. > + ## The valid range is '0..255'. Note that this is only valid on multicast > + ## transport types. > + [ a:defaultValue = "1" ] > + attribute ttl {xsd:unsignedByte}? > + } > + > +## UIDGID ##################################################################### > + > +uidgid = > + element uidgid { > + # CFG: corosync.conf, cluster.conf > + # XXX: undocumented > + attribute uid {text}?, > + > + # CFG: corosync.conf, cluster.conf > + # XXX: undocumented > + attribute gid {text}? > + } > + > + > +# vim: et:ts=2:sw=2 > diff --git a/conf/lenses/corosync.aug b/conf/lenses/corosync.aug > deleted file mode 100644 > index 1418c30..0000000 > --- a/conf/lenses/corosync.aug > +++ /dev/null > @@ -1,181 +0,0 @@ > -(* Process /etc/corosync/corosync.conf *) > -(* The lens is based on the corosync.conf(5) man page *) > -module Corosync = > - > -autoload xfm > - > -let comment = Util.comment > -let empty = Util.empty > -let dels = Util.del_str > -let eol = Util.eol > - > -let ws = del /[ \t]+/ " " > -let wsc = del /:[ \t]+/ ": " > -let indent = del /[ \t]*/ "" > -(* We require that braces are always followed by a newline *) > -let obr = del /\{([ \t]*)\n/ "{\n" > -let cbr = del /[ \t]*}[ \t]*\n/ "}\n" > - > -let ikey (k:regexp) = indent . key k > - > -let section (n:regexp) (b:lens) = > - [ ikey n . ws . obr . (b|empty|comment)* . cbr ] > - > -let kv (k:regexp) (v:regexp) = > - [ ikey k . wsc . store v . eol ] > - > -(* FIXME: it would be much more concise to write *) > -(* [ key k . ws . (bare | quoted) ] *) > -(* but the typechecker trips over that *) > -let qstr (k:regexp) = > - let delq = del /['"]/ "\"" in > - let bare = del /["']?/ "" . store /[^"' \t\n]+/ . del /["']?/ "" in > - let quoted = delq . store /.*[ \t].*/ . delq in > - [ ikey k . wsc . bare . eol ] > - |[ ikey k . wsc . quoted . eol ] > - > -(* A integer subsection *) > -let interface = > - let setting = > - kv "ringnumber" Rx.integer > - |kv "mcastport" Rx.integer > - |kv "ttl" Rx.integer > - |qstr /bindnetaddr|mcastaddr/ in > - section "interface" setting > - > -(* The totem section *) > -let totem = > - let setting = > - kv "clear_node_high_bit" /yes|no/ > - |kv "rrp_mode" /none|active|passive/ > - |kv "vsftype" /none|ykd/ > - |kv "secauth" /on|off/ > - |kv "crypto_type" /nss|aes256|aes192|aes128|3des/ > - |kv "crypto_cipher" /none|nss|aes256|aes192|aes128|3des/ > - |kv "crypto_hash" /none|md5|sha1|sha256|sha384|sha512/ > - |kv "transport" /udp|iba/ > - |kv "version" Rx.integer > - |kv "nodeid" Rx.integer > - |kv "threads" Rx.integer > - |kv "netmtu" Rx.integer > - |kv "token" Rx.integer > - |kv "token_retransmit" Rx.integer > - |kv "hold" Rx.integer > - |kv "token_retransmits_before_loss_const" Rx.integer > - |kv "join" Rx.integer > - |kv "send_join" Rx.integer > - |kv "consensus" Rx.integer > - |kv "merge" Rx.integer > - |kv "downcheck" Rx.integer > - |kv "fail_to_recv_const" Rx.integer > - |kv "seqno_unchanged_const" Rx.integer > - |kv "heartbeat_failures_allowed" Rx.integer > - |kv "max_network_delay" Rx.integer > - |kv "max_messages" Rx.integer > - |kv "window_size" Rx.integer > - |kv "rrp_problem_count_timeout" Rx.integer > - |kv "rrp_problem_count_threshold" Rx.integer > - |kv "rrp_token_expired_timeout" Rx.integer > - |interface in > - section "totem" setting > - > -let common_logging = > - kv "to_syslog" /yes|no|on|off/ > - |kv "to_stderr" /yes|no|on|off/ > - |kv "to_logfile" /yes|no|on|off/ > - |kv "debug" /yes|no|on|off|trace/ > - |kv "logfile_priority" /alert|crit|debug|emerg|err|info|notice|warning/ > - |kv "syslog_priority" /alert|crit|debug|emerg|err|info|notice|warning/ > - |kv "syslog_facility" /daemon|local0|local1|local2|local3|local4|local5|local6|local7/ > - |qstr /logfile|tags/ > - > -(* A logger_subsys subsection *) > -let logger_subsys = > - let setting = > - qstr /subsys/ > - |common_logging in > - section "logger_subsys" setting > - > - > -(* The logging section *) > -let logging = > - let setting = > - kv "fileline" /yes|no|on|off/ > - |kv "function_name" /yes|no|on|off/ > - |kv "timestamp" /yes|no|on|off/ > - |common_logging > - |logger_subsys in > - section "logging" setting > - > - > -(* The resource section *) > -let common_resource = > - kv "max" Rx.decimal > - |kv "poll_period" Rx.integer > - |kv "recovery" /reboot|shutdown|watchdog|none/ > - > -let memory_used = > - let setting = > - common_resource in > - section "memory_used" setting > - > - > -let load_15min = > - let setting = > - common_resource in > - section "load_15min" setting > - > -let system = > - let setting = > - load_15min > - |memory_used in > - section "system" setting > - > -(* The resources section *) > -let resources = > - let setting = > - system in > - section "resources" setting > - > -(* The quorum section *) > -let quorum = > - let setting = > - qstr /provider/ > - |kv "expected_votes" Rx.integer > - |kv "votes" Rx.integer > - |kv "wait_for_all" Rx.integer > - |kv "last_man_standing" Rx.integer > - |kv "last_man_standing_window" Rx.integer > - |kv "auto_tie_breaker" Rx.integer > - |kv "two_node" Rx.integer in > - section "quorum" setting > - > -(* The service section *) > -let service = > - let setting = > - qstr /name|ver/ in > - section "service" setting > - > -(* The uidgid section *) > -let uidgid = > - let setting = > - qstr /uid|gid/ in > - section "uidgid" setting > - > -(* The node section *) > -let node = > - let setting = > - qstr /ring[0-9]_addr/ > - |kv "nodeid" Rx.integer > - |kv "quorum_votes" Rx.integer in > - section "node" setting > - > -(* The nodelist section *) > -let nodelist = > - let setting = > - node in > - section "nodelist" setting > - > -let lns = (comment|empty|totem|quorum|logging|resources|service|uidgid|nodelist)* > - > -let xfm = transform lns (incl "/etc/corosync/corosync.conf") > diff --git a/conf/lex.py b/conf/lex.py > new file mode 100644 > index 0000000..137d28f > --- /dev/null > +++ b/conf/lex.py > @@ -0,0 +1,1069 @@ > +# ----------------------------------------------------------------------------- > +# ply: lex.py > +# > +# Copyright (C) 2001-2011, > +# David M. Beazley (Dabeaz LLC) > +# All rights reserved. > +# > +# Redistribution and use in source and binary forms, with or without > +# modification, are permitted provided that the following conditions are > +# met: > +# > +# * Redistributions of source code must retain the above copyright notice, > +# this list of conditions and the following disclaimer. > +# * Redistributions in binary form must reproduce the above copyright notice, > +# this list of conditions and the following disclaimer in the documentation > +# and/or other materials provided with the distribution. > +# * Neither the name of the David Beazley or Dabeaz LLC may be used to > +# endorse or promote products derived from this software without > +# specific prior written permission. > +# > +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR > +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT > +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, > +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY > +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE > +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > +# ----------------------------------------------------------------------------- > + > +__version__ = "3.5" > +__tabversion__ = "3.5" # Version of table file used > + > +import re, sys, types, copy, os > + > +# This tuple contains known string types > +try: > + # Python 2.6 > + StringTypes = (types.StringType, types.UnicodeType) > +except AttributeError: > + # Python 3.0 > + StringTypes = (str, bytes) > + > +# Extract the code attribute of a function. Different implementations > +# are for Python 2/3 compatibility. > + > +if sys.version_info[0] < 3: > + def func_code(f): > + return f.func_code > +else: > + def func_code(f): > + return f.__code__ > + > +# This regular expression is used to match valid token names > +_is_identifier = re.compile(r'^[a-zA-Z0-9_]+$') > + > +# Exception thrown when invalid token encountered and no default error > +# handler is defined. > + > +class LexError(Exception): > + def __init__(self,message,s): > + self.args = (message,) > + self.text = s > + > +# Token class. This class is used to represent the tokens produced. > +class LexToken(object): > + def __str__(self): > + return "LexToken(%s,%r,%d,%d)" % (self.type,self.value,self.lineno,self.lexpos) > + def __repr__(self): > + return str(self) > + > +# This object is a stand-in for a logging object created by the > +# logging module. > + > +class PlyLogger(object): > + def __init__(self,f): > + self.f = f > + def critical(self,msg,*args,**kwargs): > + self.f.write((msg % args) + "\n") > + > + def warning(self,msg,*args,**kwargs): > + self.f.write("WARNING: "+ (msg % args) + "\n") > + > + def error(self,msg,*args,**kwargs): > + self.f.write("ERROR: " + (msg % args) + "\n") > + > + info = critical > + debug = critical > + > +# Null logger is used when no output is generated. Does nothing. > +class NullLogger(object): > + def __getattribute__(self,name): > + return self > + def __call__(self,*args,**kwargs): > + return self > + > +# ----------------------------------------------------------------------------- > +# === Lexing Engine === > +# > +# The following Lexer class implements the lexer runtime. There are only > +# a few public methods and attributes: > +# > +# input() - Store a new string in the lexer > +# token() - Get the next token > +# clone() - Clone the lexer > +# > +# lineno - Current line number > +# lexpos - Current position in the input string > +# ----------------------------------------------------------------------------- > + > +class Lexer: > + def __init__(self): > + self.lexre = None # Master regular expression. This is a list of > + # tuples (re,findex) where re is a compiled > + # regular expression and findex is a list > + # mapping regex group numbers to rules > + self.lexretext = None # Current regular expression strings > + self.lexstatere = {} # Dictionary mapping lexer states to master regexs > + self.lexstateretext = {} # Dictionary mapping lexer states to regex strings > + self.lexstaterenames = {} # Dictionary mapping lexer states to symbol names > + self.lexstate = "INITIAL" # Current lexer state > + self.lexstatestack = [] # Stack of lexer states > + self.lexstateinfo = None # State information > + self.lexstateignore = {} # Dictionary of ignored characters for each state > + self.lexstateerrorf = {} # Dictionary of error functions for each state > + self.lexreflags = 0 # Optional re compile flags > + self.lexdata = None # Actual input data (as a string) > + self.lexpos = 0 # Current position in input text > + self.lexlen = 0 # Length of the input text > + self.lexerrorf = None # Error rule (if any) > + self.lextokens = None # List of valid tokens > + self.lexignore = "" # Ignored characters > + self.lexliterals = "" # Literal characters that can be passed through > + self.lexmodule = None # Module > + self.lineno = 1 # Current line number > + self.lexoptimize = 0 # Optimized mode > + > + def clone(self,object=None): > + c = copy.copy(self) > + > + # If the object parameter has been supplied, it means we are attaching the > + # lexer to a new object. In this case, we have to rebind all methods in > + # the lexstatere and lexstateerrorf tables. > + > + if object: > + newtab = { } > + for key, ritem in self.lexstatere.items(): > + newre = [] > + for cre, findex in ritem: > + newfindex = [] > + for f in findex: > + if not f or not f[0]: > + newfindex.append(f) > + continue > + newfindex.append((getattr(object,f[0].__name__),f[1])) > + newre.append((cre,newfindex)) > + newtab[key] = newre > + c.lexstatere = newtab > + c.lexstateerrorf = { } > + for key, ef in self.lexstateerrorf.items(): > + c.lexstateerrorf[key] = getattr(object,ef.__name__) > + c.lexmodule = object > + return c > + > + # ------------------------------------------------------------ > + # writetab() - Write lexer information to a table file > + # ------------------------------------------------------------ > + def writetab(self,tabfile,outputdir=""): > + if isinstance(tabfile,types.ModuleType): > + return > + basetabfilename = tabfile.split(".")[-1] > + filename = os.path.join(outputdir,basetabfilename)+".py" > + tf = open(filename,"w") > + tf.write("# %s.py. This file automatically created by PLY (version %s). Don't edit!\n" % (tabfile,__version__)) > + tf.write("_tabversion = %s\n" % repr(__tabversion__)) > + tf.write("_lextokens = %s\n" % repr(self.lextokens)) > + tf.write("_lexreflags = %s\n" % repr(self.lexreflags)) > + tf.write("_lexliterals = %s\n" % repr(self.lexliterals)) > + tf.write("_lexstateinfo = %s\n" % repr(self.lexstateinfo)) > + > + tabre = { } > + # Collect all functions in the initial state > + initial = self.lexstatere["INITIAL"] > + initialfuncs = [] > + for part in initial: > + for f in part[1]: > + if f and f[0]: > + initialfuncs.append(f) > + > + for key, lre in self.lexstatere.items(): > + titem = [] > + for i in range(len(lre)): > + titem.append((self.lexstateretext[key][i],_funcs_to_names(lre[i][1],self.lexstaterenames[key][i]))) > + tabre[key] = titem > + > + tf.write("_lexstatere = %s\n" % repr(tabre)) > + tf.write("_lexstateignore = %s\n" % repr(self.lexstateignore)) > + > + taberr = { } > + for key, ef in self.lexstateerrorf.items(): > + if ef: > + taberr[key] = ef.__name__ > + else: > + taberr[key] = None > + tf.write("_lexstateerrorf = %s\n" % repr(taberr)) > + tf.close() > + > + # ------------------------------------------------------------ > + # readtab() - Read lexer information from a tab file > + # ------------------------------------------------------------ > + def readtab(self,tabfile,fdict): > + if isinstance(tabfile,types.ModuleType): > + lextab = tabfile > + else: > + if sys.version_info[0] < 3: > + exec("import %s as lextab" % tabfile) > + else: > + env = { } > + exec("import %s as lextab" % tabfile, env,env) > + lextab = env['lextab'] > + > + if getattr(lextab,"_tabversion","0.0") != __tabversion__: > + raise ImportError("Inconsistent PLY version") > + > + self.lextokens = lextab._lextokens > + self.lexreflags = lextab._lexreflags > + self.lexliterals = lextab._lexliterals > + self.lexstateinfo = lextab._lexstateinfo > + self.lexstateignore = lextab._lexstateignore > + self.lexstatere = { } > + self.lexstateretext = { } > + for key,lre in lextab._lexstatere.items(): > + titem = [] > + txtitem = [] > + for i in range(len(lre)): > + titem.append((re.compile(lre[i][0],lextab._lexreflags | re.VERBOSE),_names_to_funcs(lre[i][1],fdict))) > + txtitem.append(lre[i][0]) > + self.lexstatere[key] = titem > + self.lexstateretext[key] = txtitem > + self.lexstateerrorf = { } > + for key,ef in lextab._lexstateerrorf.items(): > + self.lexstateerrorf[key] = fdict[ef] > + self.begin('INITIAL') > + > + # ------------------------------------------------------------ > + # input() - Push a new string into the lexer > + # ------------------------------------------------------------ > + def input(self,s): > + # Pull off the first character to see if s looks like a string > + c = s[:1] > + if not isinstance(c,StringTypes): > + raise ValueError("Expected a string") > + self.lexdata = s > + self.lexpos = 0 > + self.lexlen = len(s) > + > + # ------------------------------------------------------------ > + # begin() - Changes the lexing state > + # ------------------------------------------------------------ > + def begin(self,state): > + if not state in self.lexstatere: > + raise ValueError("Undefined state") > + self.lexre = self.lexstatere[state] > + self.lexretext = self.lexstateretext[state] > + self.lexignore = self.lexstateignore.get(state,"") > + self.lexerrorf = self.lexstateerrorf.get(state,None) > + self.lexstate = state > + > + # ------------------------------------------------------------ > + # push_state() - Changes the lexing state and saves old on stack > + # ------------------------------------------------------------ > + def push_state(self,state): > + self.lexstatestack.append(self.lexstate) > + self.begin(state) > + > + # ------------------------------------------------------------ > + # pop_state() - Restores the previous state > + # ------------------------------------------------------------ > + def pop_state(self): > + self.begin(self.lexstatestack.pop()) > + > + # ------------------------------------------------------------ > + # current_state() - Returns the current lexing state > + # ------------------------------------------------------------ > + def current_state(self): > + return self.lexstate > + > + # ------------------------------------------------------------ > + # skip() - Skip ahead n characters > + # ------------------------------------------------------------ > + def skip(self,n): > + self.lexpos += n > + > + # ------------------------------------------------------------ > + # opttoken() - Return the next token from the Lexer > + # > + # Note: This function has been carefully implemented to be as fast > + # as possible. Don't make changes unless you really know what > + # you are doing > + # ------------------------------------------------------------ > + def token(self): > + # Make local copies of frequently referenced attributes > + lexpos = self.lexpos > + lexlen = self.lexlen > + lexignore = self.lexignore > + lexdata = self.lexdata > + > + while lexpos < lexlen: > + # This code provides some short-circuit code for whitespace, tabs, and other ignored characters > + if lexdata[lexpos] in lexignore: > + lexpos += 1 > + continue > + > + # Look for a regular expression match > + for lexre,lexindexfunc in self.lexre: > + m = lexre.match(lexdata,lexpos) > + if not m: continue > + > + # Create a token for return > + tok = LexToken() > + tok.value = m.group() > + tok.lineno = self.lineno > + tok.lexpos = lexpos > + > + i = m.lastindex > + func,tok.type = lexindexfunc[i] > + > + if not func: > + # If no token type was set, it's an ignored token > + if tok.type: > + self.lexpos = m.end() > + return tok > + else: > + lexpos = m.end() > + break > + > + lexpos = m.end() > + > + # If token is processed by a function, call it > + > + tok.lexer = self # Set additional attributes useful in token rules > + self.lexmatch = m > + self.lexpos = lexpos > + > + newtok = func(tok) > + > + # Every function must return a token, if nothing, we just move to next token > + if not newtok: > + lexpos = self.lexpos # This is here in case user has updated lexpos. > + lexignore = self.lexignore # This is here in case there was a state change > + break > + > + # Verify type of the token. If not in the token map, raise an error > + if not self.lexoptimize: > + if not newtok.type in self.lextokens: > + raise LexError("%s:%d: Rule '%s' returned an unknown token type '%s'" % ( > + func_code(func).co_filename, func_code(func).co_firstlineno, > + func.__name__, newtok.type),lexdata[lexpos:]) > + > + return newtok > + else: > + # No match, see if in literals > + if lexdata[lexpos] in self.lexliterals: > + tok = LexToken() > + tok.value = lexdata[lexpos] > + tok.lineno = self.lineno > + tok.type = tok.value > + tok.lexpos = lexpos > + self.lexpos = lexpos + 1 > + return tok > + > + # No match. Call t_error() if defined. > + if self.lexerrorf: > + tok = LexToken() > + tok.value = self.lexdata[lexpos:] > + tok.lineno = self.lineno > + tok.type = "error" > + tok.lexer = self > + tok.lexpos = lexpos > + self.lexpos = lexpos > + newtok = self.lexerrorf(tok) > + if lexpos == self.lexpos: > + # Error method didn't change text position at all. This is an error. > + raise LexError("Scanning error. Illegal character '%s'" % (lexdata[lexpos]), lexdata[lexpos:]) > + lexpos = self.lexpos > + if not newtok: continue > + return newtok > + > + self.lexpos = lexpos > + raise LexError("Illegal character '%s' at index %d" % (lexdata[lexpos],lexpos), lexdata[lexpos:]) > + > + self.lexpos = lexpos + 1 > + if self.lexdata is None: > + raise RuntimeError("No input string given with input()") > + return None > + > + # Iterator interface > + def __iter__(self): > + return self > + > + def next(self): > + t = self.token() > + if t is None: > + raise StopIteration > + return t > + > + __next__ = next > + > +# ----------------------------------------------------------------------------- > +# ==== Lex Builder === > +# > +# The functions and classes below are used to collect lexing information > +# and build a Lexer object from it. > +# ----------------------------------------------------------------------------- > + > +# ----------------------------------------------------------------------------- > +# _get_regex(func) > +# > +# Returns the regular expression assigned to a function either as a doc string > +# or as a .regex attribute attached by the @TOKEN decorator. > +# ----------------------------------------------------------------------------- > + > +def _get_regex(func): > + return getattr(func,"regex",func.__doc__) > + > +# ----------------------------------------------------------------------------- > +# get_caller_module_dict() > +# > +# This function returns a dictionary containing all of the symbols defined within > +# a caller further down the call stack. This is used to get the environment > +# associated with the yacc() call if none was provided. > +# ----------------------------------------------------------------------------- > + > +def get_caller_module_dict(levels): > + try: > + raise RuntimeError > + except RuntimeError: > + e,b,t = sys.exc_info() > + f = t.tb_frame > + while levels > 0: > + f = f.f_back > + levels -= 1 > + ldict = f.f_globals.copy() > + if f.f_globals != f.f_locals: > + ldict.update(f.f_locals) > + > + return ldict > + > +# ----------------------------------------------------------------------------- > +# _funcs_to_names() > +# > +# Given a list of regular expression functions, this converts it to a list > +# suitable for output to a table file > +# ----------------------------------------------------------------------------- > + > +def _funcs_to_names(funclist,namelist): > + result = [] > + for f,name in zip(funclist,namelist): > + if f and f[0]: > + result.append((name, f[1])) > + else: > + result.append(f) > + return result > + > +# ----------------------------------------------------------------------------- > +# _names_to_funcs() > +# > +# Given a list of regular expression function names, this converts it back to > +# functions. > +# ----------------------------------------------------------------------------- > + > +def _names_to_funcs(namelist,fdict): > + result = [] > + for n in namelist: > + if n and n[0]: > + result.append((fdict[n[0]],n[1])) > + else: > + result.append(n) > + return result > + > +# ----------------------------------------------------------------------------- > +# _form_master_re() > +# > +# This function takes a list of all of the regex components and attempts to > +# form the master regular expression. Given limitations in the Python re > +# module, it may be necessary to break the master regex into separate expressions. > +# ----------------------------------------------------------------------------- > + > +def _form_master_re(relist,reflags,ldict,toknames): > + if not relist: return [] > + regex = "|".join(relist) > + try: > + lexre = re.compile(regex,re.VERBOSE | reflags) > + > + # Build the index to function map for the matching engine > + lexindexfunc = [ None ] * (max(lexre.groupindex.values())+1) > + lexindexnames = lexindexfunc[:] > + > + for f,i in lexre.groupindex.items(): > + handle = ldict.get(f,None) > + if type(handle) in (types.FunctionType, types.MethodType): > + lexindexfunc[i] = (handle,toknames[f]) > + lexindexnames[i] = f > + elif handle is not None: > + lexindexnames[i] = f > + if f.find("ignore_") > 0: > + lexindexfunc[i] = (None,None) > + else: > + lexindexfunc[i] = (None, toknames[f]) > + > + return [(lexre,lexindexfunc)],[regex],[lexindexnames] > + except Exception: > + m = int(len(relist)/2) > + if m == 0: m = 1 > + llist, lre, lnames = _form_master_re(relist[:m],reflags,ldict,toknames) > + rlist, rre, rnames = _form_master_re(relist[m:],reflags,ldict,toknames) > + return llist+rlist, lre+rre, lnames+rnames > + > +# ----------------------------------------------------------------------------- > +# def _statetoken(s,names) > +# > +# Given a declaration name s of the form "t_" and a dictionary whose keys are > +# state names, this function returns a tuple (states,tokenname) where states > +# is a tuple of state names and tokenname is the name of the token. For example, > +# calling this with s = "t_foo_bar_SPAM" might return (('foo','bar'),'SPAM') > +# ----------------------------------------------------------------------------- > + > +def _statetoken(s,names): > + nonstate = 1 > + parts = s.split("_") > + for i in range(1,len(parts)): > + if not parts[i] in names and parts[i] != 'ANY': break > + if i > 1: > + states = tuple(parts[1:i]) > + else: > + states = ('INITIAL',) > + > + if 'ANY' in states: > + states = tuple(names) > + > + tokenname = "_".join(parts[i:]) > + return (states,tokenname) > + > + > +# ----------------------------------------------------------------------------- > +# LexerReflect() > +# > +# This class represents information needed to build a lexer as extracted from a > +# user's input file. > +# ----------------------------------------------------------------------------- > +class LexerReflect(object): > + def __init__(self,ldict,log=None,reflags=0): > + self.ldict = ldict > + self.error_func = None > + self.tokens = [] > + self.reflags = reflags > + self.stateinfo = { 'INITIAL' : 'inclusive'} > + self.files = {} > + self.error = 0 > + > + if log is None: > + self.log = PlyLogger(sys.stderr) > + else: > + self.log = log > + > + # Get all of the basic information > + def get_all(self): > + self.get_tokens() > + self.get_literals() > + self.get_states() > + self.get_rules() > + > + # Validate all of the information > + def validate_all(self): > + self.validate_tokens() > + self.validate_literals() > + self.validate_rules() > + return self.error > + > + # Get the tokens map > + def get_tokens(self): > + tokens = self.ldict.get("tokens",None) > + if not tokens: > + self.log.error("No token list is defined") > + self.error = 1 > + return > + > + if not isinstance(tokens,(list, tuple)): > + self.log.error("tokens must be a list or tuple") > + self.error = 1 > + return > + > + if not tokens: > + self.log.error("tokens is empty") > + self.error = 1 > + return > + > + self.tokens = tokens > + > + # Validate the tokens > + def validate_tokens(self): > + terminals = {} > + for n in self.tokens: > + if not _is_identifier.match(n): > + self.log.error("Bad token name '%s'",n) > + self.error = 1 > + if n in terminals: > + self.log.warning("Token '%s' multiply defined", n) > + terminals[n] = 1 > + > + # Get the literals specifier > + def get_literals(self): > + self.literals = self.ldict.get("literals","") > + if not self.literals: > + self.literals = "" > + > + # Validate literals > + def validate_literals(self): > + try: > + for c in self.literals: > + if not isinstance(c,StringTypes) or len(c) > 1: > + self.log.error("Invalid literal %s. Must be a single character", repr(c)) > + self.error = 1 > + > + except TypeError: > + self.log.error("Invalid literals specification. literals must be a sequence of characters") > + self.error = 1 > + > + def get_states(self): > + self.states = self.ldict.get("states",None) > + # Build statemap > + if self.states: > + if not isinstance(self.states,(tuple,list)): > + self.log.error("states must be defined as a tuple or list") > + self.error = 1 > + else: > + for s in self.states: > + if not isinstance(s,tuple) or len(s) != 2: > + self.log.error("Invalid state specifier %s. Must be a tuple (statename,'exclusive|inclusive')",repr(s)) > + self.error = 1 > + continue > + name, statetype = s > + if not isinstance(name,StringTypes): > + self.log.error("State name %s must be a string", repr(name)) > + self.error = 1 > + continue > + if not (statetype == 'inclusive' or statetype == 'exclusive'): > + self.log.error("State type for state %s must be 'inclusive' or 'exclusive'",name) > + self.error = 1 > + continue > + if name in self.stateinfo: > + self.log.error("State '%s' already defined",name) > + self.error = 1 > + continue > + self.stateinfo[name] = statetype > + > + # Get all of the symbols with a t_ prefix and sort them into various > + # categories (functions, strings, error functions, and ignore characters) > + > + def get_rules(self): > + tsymbols = [f for f in self.ldict if f[:2] == 't_' ] > + > + # Now build up a list of functions and a list of strings > + > + self.toknames = { } # Mapping of symbols to token names > + self.funcsym = { } # Symbols defined as functions > + self.strsym = { } # Symbols defined as strings > + self.ignore = { } # Ignore strings by state > + self.errorf = { } # Error functions by state > + > + for s in self.stateinfo: > + self.funcsym[s] = [] > + self.strsym[s] = [] > + > + if len(tsymbols) == 0: > + self.log.error("No rules of the form t_rulename are defined") > + self.error = 1 > + return > + > + for f in tsymbols: > + t = self.ldict[f] > + states, tokname = _statetoken(f,self.stateinfo) > + self.toknames[f] = tokname > + > + if hasattr(t,"__call__"): > + if tokname == 'error': > + for s in states: > + self.errorf[s] = t > + elif tokname == 'ignore': > + line = func_code(t).co_firstlineno > + file = func_code(t).co_filename > + self.log.error("%s:%d: Rule '%s' must be defined as a string",file,line,t.__name__) > + self.error = 1 > + else: > + for s in states: > + self.funcsym[s].append((f,t)) > + elif isinstance(t, StringTypes): > + if tokname == 'ignore': > + for s in states: > + self.ignore[s] = t > + if "\\" in t: > + self.log.warning("%s contains a literal backslash '\\'",f) > + > + elif tokname == 'error': > + self.log.error("Rule '%s' must be defined as a function", f) > + self.error = 1 > + else: > + for s in states: > + self.strsym[s].append((f,t)) > + else: > + self.log.error("%s not defined as a function or string", f) > + self.error = 1 > + > + # Sort the functions by line number > + for f in self.funcsym.values(): > + if sys.version_info[0] < 3: > + f.sort(lambda x,y: cmp(func_code(x[1]).co_firstlineno,func_code(y[1]).co_firstlineno)) > + else: > + # Python 3.0 > + f.sort(key=lambda x: func_code(x[1]).co_firstlineno) > + > + # Sort the strings by regular expression length > + for s in self.strsym.values(): > + if sys.version_info[0] < 3: > + s.sort(lambda x,y: (len(x[1]) < len(y[1])) - (len(x[1]) > len(y[1]))) > + else: > + # Python 3.0 > + s.sort(key=lambda x: len(x[1]),reverse=True) > + > + # Validate all of the t_rules collected > + def validate_rules(self): > + for state in self.stateinfo: > + # Validate all rules defined by functions > + > + > + > + for fname, f in self.funcsym[state]: > + line = func_code(f).co_firstlineno > + file = func_code(f).co_filename > + self.files[file] = 1 > + > + tokname = self.toknames[fname] > + if isinstance(f, types.MethodType): > + reqargs = 2 > + else: > + reqargs = 1 > + nargs = func_code(f).co_argcount > + if nargs > reqargs: > + self.log.error("%s:%d: Rule '%s' has too many arguments",file,line,f.__name__) > + self.error = 1 > + continue > + > + if nargs < reqargs: > + self.log.error("%s:%d: Rule '%s' requires an argument", file,line,f.__name__) > + self.error = 1 > + continue > + > + if not _get_regex(f): > + self.log.error("%s:%d: No regular expression defined for rule '%s'",file,line,f.__name__) > + self.error = 1 > + continue > + > + try: > + c = re.compile("(?P<%s>%s)" % (fname, _get_regex(f)), re.VERBOSE | self.reflags) > + if c.match(""): > + self.log.error("%s:%d: Regular expression for rule '%s' matches empty string", file,line,f.__name__) > + self.error = 1 > + except re.error: > + _etype, e, _etrace = sys.exc_info() > + self.log.error("%s:%d: Invalid regular expression for rule '%s'. %s", file,line,f.__name__,e) > + if '#' in _get_regex(f): > + self.log.error("%s:%d. Make sure '#' in rule '%s' is escaped with '\\#'",file,line, f.__name__) > + self.error = 1 > + > + # Validate all rules defined by strings > + for name,r in self.strsym[state]: > + tokname = self.toknames[name] > + if tokname == 'error': > + self.log.error("Rule '%s' must be defined as a function", name) > + self.error = 1 > + continue > + > + if not tokname in self.tokens and tokname.find("ignore_") < 0: > + self.log.error("Rule '%s' defined for an unspecified token %s",name,tokname) > + self.error = 1 > + continue > + > + try: > + c = re.compile("(?P<%s>%s)" % (name,r),re.VERBOSE | self.reflags) > + if (c.match("")): > + self.log.error("Regular expression for rule '%s' matches empty string",name) > + self.error = 1 > + except re.error: > + _etype, e, _etrace = sys.exc_info() > + self.log.error("Invalid regular expression for rule '%s'. %s",name,e) > + if '#' in r: > + self.log.error("Make sure '#' in rule '%s' is escaped with '\\#'",name) > + self.error = 1 > + > + if not self.funcsym[state] and not self.strsym[state]: > + self.log.error("No rules defined for state '%s'",state) > + self.error = 1 > + > + # Validate the error function > + efunc = self.errorf.get(state,None) > + if efunc: > + f = efunc > + line = func_code(f).co_firstlineno > + file = func_code(f).co_filename > + self.files[file] = 1 > + > + if isinstance(f, types.MethodType): > + reqargs = 2 > + else: > + reqargs = 1 > + nargs = func_code(f).co_argcount > + if nargs > reqargs: > + self.log.error("%s:%d: Rule '%s' has too many arguments",file,line,f.__name__) > + self.error = 1 > + > + if nargs < reqargs: > + self.log.error("%s:%d: Rule '%s' requires an argument", file,line,f.__name__) > + self.error = 1 > + > + for f in self.files: > + self.validate_file(f) > + > + > + # ----------------------------------------------------------------------------- > + # validate_file() > + # > + # This checks to see if there are duplicated t_rulename() functions or strings > + # in the parser input file. This is done using a simple regular expression > + # match on each line in the given file. > + # ----------------------------------------------------------------------------- > + > + def validate_file(self,filename): > + import os.path > + base,ext = os.path.splitext(filename) > + if ext != '.py': return # No idea what the file is. Return OK > + > + try: > + f = open(filename) > + lines = f.readlines() > + f.close() > + except IOError: > + return # Couldn't find the file. Don't worry about it > + > + fre = re.compile(r'\s*def\s+(t_[a-zA-Z_0-9]*)\(') > + sre = re.compile(r'\s*(t_[a-zA-Z_0-9]*)\s*=') > + > + counthash = { } > + linen = 1 > + for l in lines: > + m = fre.match(l) > + if not m: > + m = sre.match(l) > + if m: > + name = m.group(1) > + prev = counthash.get(name) > + if not prev: > + counthash[name] = linen > + else: > + self.log.error("%s:%d: Rule %s redefined. Previously defined on line %d",filename,linen,name,prev) > + self.error = 1 > + linen += 1 > + > +# ----------------------------------------------------------------------------- > +# lex(module) > +# > +# Build all of the regular expression rules from definitions in the supplied module > +# ----------------------------------------------------------------------------- > +def lex(module=None,object=None,debug=0,optimize=0,lextab="lextab",reflags=0,nowarn=0,outputdir="", debuglog=None, errorlog=None): > + global lexer > + ldict = None > + stateinfo = { 'INITIAL' : 'inclusive'} > + lexobj = Lexer() > + lexobj.lexoptimize = optimize > + global token,input > + > + if errorlog is None: > + errorlog = PlyLogger(sys.stderr) > + > + if debug: > + if debuglog is None: > + debuglog = PlyLogger(sys.stderr) > + > + # Get the module dictionary used for the lexer > + if object: module = object > + > + if module: > + _items = [(k,getattr(module,k)) for k in dir(module)] > + ldict = dict(_items) > + else: > + ldict = get_caller_module_dict(2) > + > + # Collect parser information from the dictionary > + linfo = LexerReflect(ldict,log=errorlog,reflags=reflags) > + linfo.get_all() > + if not optimize: > + if linfo.validate_all(): > + raise SyntaxError("Can't build lexer") > + > + if optimize and lextab: > + try: > + lexobj.readtab(lextab,ldict) > + token = lexobj.token > + input = lexobj.input > + lexer = lexobj > + return lexobj > + > + except ImportError: > + pass > + > + # Dump some basic debugging information > + if debug: > + debuglog.info("lex: tokens = %r", linfo.tokens) > + debuglog.info("lex: literals = %r", linfo.literals) > + debuglog.info("lex: states = %r", linfo.stateinfo) > + > + # Build a dictionary of valid token names > + lexobj.lextokens = { } > + for n in linfo.tokens: > + lexobj.lextokens[n] = 1 > + > + # Get literals specification > + if isinstance(linfo.literals,(list,tuple)): > + lexobj.lexliterals = type(linfo.literals[0])().join(linfo.literals) > + else: > + lexobj.lexliterals = linfo.literals > + > + # Get the stateinfo dictionary > + stateinfo = linfo.stateinfo > + > + regexs = { } > + # Build the master regular expressions > + for state in stateinfo: > + regex_list = [] > + > + # Add rules defined by functions first > + for fname, f in linfo.funcsym[state]: > + line = func_code(f).co_firstlineno > + file = func_code(f).co_filename > + regex_list.append("(?P<%s>%s)" % (fname,_get_regex(f))) > + if debug: > + debuglog.info("lex: Adding rule %s -> '%s' (state '%s')",fname,_get_regex(f), state) > + > + # Now add all of the simple rules > + for name,r in linfo.strsym[state]: > + regex_list.append("(?P<%s>%s)" % (name,r)) > + if debug: > + debuglog.info("lex: Adding rule %s -> '%s' (state '%s')",name,r, state) > + > + regexs[state] = regex_list > + > + # Build the master regular expressions > + > + if debug: > + debuglog.info("lex: ==== MASTER REGEXS FOLLOW ====") > + > + for state in regexs: > + lexre, re_text, re_names = _form_master_re(regexs[state],reflags,ldict,linfo.toknames) > + lexobj.lexstatere[state] = lexre > + lexobj.lexstateretext[state] = re_text > + lexobj.lexstaterenames[state] = re_names > + if debug: > + for i in range(len(re_text)): > + debuglog.info("lex: state '%s' : regex[%d] = '%s'",state, i, re_text[i]) > + > + # For inclusive states, we need to add the regular expressions from the INITIAL state > + for state,stype in stateinfo.items(): > + if state != "INITIAL" and stype == 'inclusive': > + lexobj.lexstatere[state].extend(lexobj.lexstatere['INITIAL']) > + lexobj.lexstateretext[state].extend(lexobj.lexstateretext['INITIAL']) > + lexobj.lexstaterenames[state].extend(lexobj.lexstaterenames['INITIAL']) > + > + lexobj.lexstateinfo = stateinfo > + lexobj.lexre = lexobj.lexstatere["INITIAL"] > + lexobj.lexretext = lexobj.lexstateretext["INITIAL"] > + lexobj.lexreflags = reflags > + > + # Set up ignore variables > + lexobj.lexstateignore = linfo.ignore > + lexobj.lexignore = lexobj.lexstateignore.get("INITIAL","") > + > + # Set up error functions > + lexobj.lexstateerrorf = linfo.errorf > + lexobj.lexerrorf = linfo.errorf.get("INITIAL",None) > + if not lexobj.lexerrorf: > + errorlog.warning("No t_error rule is defined") > + > + # Check state information for ignore and error rules > + for s,stype in stateinfo.items(): > + if stype == 'exclusive': > + if not s in linfo.errorf: > + errorlog.warning("No error rule is defined for exclusive state '%s'", s) > + if not s in linfo.ignore and lexobj.lexignore: > + errorlog.warning("No ignore rule is defined for exclusive state '%s'", s) > + elif stype == 'inclusive': > + if not s in linfo.errorf: > + linfo.errorf[s] = linfo.errorf.get("INITIAL",None) > + if not s in linfo.ignore: > + linfo.ignore[s] = linfo.ignore.get("INITIAL","") > + > + # Create global versions of the token() and input() functions > + token = lexobj.token > + input = lexobj.input > + lexer = lexobj > + > + # If in optimize mode, we write the lextab > + if lextab and optimize: > + lexobj.writetab(lextab,outputdir) > + > + return lexobj > + > +# ----------------------------------------------------------------------------- > +# runmain() > +# > +# This runs the lexer as a main program > +# ----------------------------------------------------------------------------- > + > +def runmain(lexer=None,data=None): > + if not data: > + try: > + filename = sys.argv[1] > + f = open(filename) > + data = f.read() > + f.close() > + except IndexError: > + sys.stdout.write("Reading from standard input (type EOF to end):\n") > + data = sys.stdin.read() > + > + if lexer: > + _input = lexer.input > + else: > + _input = input > + _input(data) > + if lexer: > + _token = lexer.token > + else: > + _token = token > + > + while 1: > + tok = _token() > + if not tok: break > + sys.stdout.write("(%s,%r,%d,%d)\n" % (tok.type, tok.value, tok.lineno,tok.lexpos)) > + > +# ----------------------------------------------------------------------------- > +# @TOKEN(regex) > +# > +# This decorator function can be used to set the regex expression on a function > +# when its docstring might need to be set in an alternative way > +# ----------------------------------------------------------------------------- > + > +def TOKEN(r): > + def set_regex(f): > + if hasattr(r,"__call__"): > + f.regex = _get_regex(r) > + else: > + f.regex = r > + return f > + return set_regex > + > +# Alternative spelling of the TOKEN decorator > +Token = TOKEN > + > diff --git a/conf/rnc_tokenize.py b/conf/rnc_tokenize.py > new file mode 100644 > index 0000000..3620825 > --- /dev/null > +++ b/conf/rnc_tokenize.py > @@ -0,0 +1,275 @@ > +#!/usr/bin/env python > +# Define the tokenizer for RELAX NG compact syntax > +# This file released to the Public Domain by David Mertz > +# > +# Extended under revised BSD license by Jan Pokorny (jpokorny@xxxxxxxxxx) > +# Copyright 2013 Red Hat, Inc. > +# All rights reserved. > +# > +# Redistribution and use in source and binary forms, with or without > +# modification, are permitted provided that the following conditions are met: > +# > +# - Redistributions of source code must retain the above copyright notice, > +# this list of conditions and the following disclaimer. > +# - Redistributions in binary form must reproduce the above copyright notice, > +# this list of conditions and the following disclaimer in the documentation > +# and/or other materials provided with the distribution. > +# - Neither the name of the Red Hat, Inc. nor the names of its > +# contributors may be used to endorse or promote products derived from this > +# software without specific prior written permission. > +# > +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" > +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE > +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF > +# THE POSSIBILITY OF SUCH DAMAGE. > + > +# TODO: update positions so they can be used for debugging > + > +import re > +try: > + from ply import lex > +except ImportError: > + import lex > + > + > +# > +# tokens declaration > +# > + > +# square (left + right delimiter) together with single-node tree replacement > +pair_rules = tuple(l.replace(' ', '').split(':') for l in ''' > + BEG_BODY : END_BODY : BODY > + BEG_PAREN : END_PAREN : GROUP > + BEG_ANNO : END_ANNO : NS_ANNOTATION > + '''.strip().splitlines()) > +pair_tokens = reduce(lambda a, b: a + tuple(b[:2]), pair_rules, ()) > + > +quant_tokens = tuple(''' > + ANY > + MAYBE > + SOME > + '''.split()) > + > +immediate_tokens = tuple(''' > + ANNOTATION > + CHOICE > + COMMENT > + DATATAG > + DEFINE > + EQUAL > + INTERLEAVE > + LITERAL > + NAME > + PATTERN > + SEQ > + WHITESPACE > + '''.split()) + quant_tokens > + > +# http://relaxng.org/compact-20021121.html#syntax > +keywords = { > + 'attribute': 'ATTR', > + 'default': 'DEFAULT_NS', > + 'datatypes': 'DATATYPES', > + 'div': 'DIV', > + 'element': 'ELEM', > + 'empty': 'EMPTY', > + 'external': 'EXTERNAL', > + 'grammar': 'GRAMMAR', > + 'include': 'INCLUDE', > + 'inherit': 'INHERIT', > + 'list': 'LIST', > + 'mixed': 'MIXED', > + 'namespace': 'NS', > + 'notAllowed': 'NOTALLOWED', > + 'parent': 'PARENT', > + 'start': 'START', > + 'string': 'STRING', > + 'text': 'TEXT', > + 'token': 'TOKEN', > +} > + > +tokens = immediate_tokens + pair_tokens + tuple(keywords.values()) > + > + > +# > +# tokens definition > +# > + > +# RELAX NG/XML datatype NCName is defined in > +# http://books.xmlschemata.org/relaxng/ch19-77215.html > +# http://www.w3.org/TR/REC-xml-names/#NT-NCName > +# which can be resolved as > +# <NCName> ::= <Start> <NonStart>* > +# where > +# <Start> ::= [A-Z] | "_" | [a-z] | [#xC0-#xD6] | ... > +# (see http://www.w3.org/TR/REC-xml/#NT-NameStartChar) > +# <NonStart> ::= <Start> | "-" | "." | [0-9] | #xB7 | .. > +# (see http://www.w3.org/TR/REC-xml/#NT-NameChar) > +# > +# NOTE: skipping [\u10000-\uEFFFF] as it won't get lex'd (???) > +NCName_start = "(?:[A-Z_a-z]" \ > + u"|[\u00C0-\u00D6]" \ > + u"|[\u00D8-\u00F6]" \ > + u"|[\u00F8-\u02FF]" \ > + u"|[\u0370-\u037D]" \ > + u"|[\u037F-\u1FFF]" \ > + u"|[\u200C-\u200D]" \ > + u"|[\u2070-\u218F]" \ > + u"|[\u2C00-\u2FEF]" \ > + u"|[\u3001-\uD7FF]" \ > + u"|[\uF900-\uFDCF]" \ > + u"|[\uFDF0-\uFFFD]" \ > + ")" > +NCName_nonstart = NCName_start + "|(?:[-.0-9]" \ > + u"|\u00B7" \ > + u"|[\u0300-\u036F]" \ > + u"|[\u203F-\u2040]" \ > + ")" > +NCName = NCName_start + "(?:" + NCName_nonstart + ")*" > + > +# lex internals > + > +t_ignore = " \t\n" > + > + > +def t_error(t): > + try: > + t.lexer.skip(1) > + except AttributeError: > + # works in historic version of PLY > + t.skip(1) > + > +# immediate tokens > + > +t_ANY = r'\*' > +t_CHOICE = r'\|' > +t_EQUAL = r'=' > +t_INTERLEAVE = r'&' > +t_MAYBE = r'\?' > +t_SEQ = r',' > +t_SOME = r'\+' > +t_WHITESPACE = r'\s+' > + > + > +def t_ANNOTATION(t): > + r"\#\#[ \t]?.*" > + t.value = t.value.replace('# ', '#', 1).split('##', 1)[1].rstrip() > + return t > + > + > +def t_COMMENT(t): > + r"\#[ \t]?.*" > + t.value = t.value.replace('# ', '#', 1).split('#', 1)[1].rstrip() > + return t > + > + > +def t_DATATYPES(t): > + r"datatypes\s+xsd\s*=\s*.*" > + t.value = t.value.split('=', 1)[1].strip() > + return t > + > + > +def t_DATATAG(t): > + r"xsd:\w+" > + t.value = t.value.split(':', 1)[1] > + return t > + > + > +def t_DEFAULT_NS(t): > + r"default\s+namespace\s*=\s*.*" > + t.value = t.value.split('=', 1)[1].strip() > + return t > + > + > +def t_INCLUDE(t): > + t.value = t.value.split('"', 1)[1][:-1] > + return t > +t_INCLUDE.__doc__ = r'include\s*"' + NCName + '"' > + > + > +def t_LITERAL(t): > + r'".+?"(?:\s*[~]\s*".+?")*' > + t.value = ' '.join(i.strip(' \n"') for i in t.value.split('~')) > + return t > + > + > +def t_NAME(t): > + # "In order to use a keyword as an identifier, it must be quoted with \." > + t.value = t.value[2:] > + return t > +t_NAME.__doc__ = r"\\[.]" + NCName > + > + > +def t_NS(t): > + r"namespace\s+.*" > + t.value = t.value.split(None, 1)[1] > + return t > + > + > +def t_PATTERN(t): > + r'{\s*pattern\s*=\s*".*"\s*}' > + t.value = t.value[:-1].split('=', 1)[1].strip()[1:-1] > + return t > + > + > +# these two last (and in this order) for reason > +def t_DEFINE(t): > + t.value = t.value.split('=', 1)[0].strip() > + return t > +t_DEFINE.__doc__ = NCName + "\s*=" > + > + > +def t_ID(t): > + t.type = keywords.get(t.value, 'NAME') # Check for keywords > + return t > +t_ID.__doc__ = NCName > + > + > +# pair tokens > + > +t_BEG_ANNO = r'\[' > +t_END_ANNO = r'\]' > +t_BEG_BODY = r'{' > +t_END_BODY = r'}' > +t_BEG_PAREN = r'\(' > +t_END_PAREN = r'\)' > + > + > +# > +# processing > +# > + > +def preprocess(rnc): > + # 2.2. BOM stripping > + if len(rnc) >= 2 and ord(rnc[0]) == 0xFE and ord(rnc[1]) == 0xFF: > + rnc = rnc[2:] > + # 2.3 Newline normalization > + rnc = re.sub(r"(?:\n|\r\n?)", "\n", rnc, re.MULTILINE) > + # TODO: 2.4 Escape interpretation > + return rnc > + > + > +def token_list(rnc): > + lex.lex() > + lex.input(preprocess(rnc)) > + ts = [] > + while 1: > + t = lex.token() > + if t is None: > + break > + ts.append(t) > + return ts > + > + > +if __name__ == '__main__': > + import sys > + del t_ignore > + tokens = token_list(sys.stdin.read()) > + print '\n'.join(map(repr, tokens)) > diff --git a/conf/rnctree.py b/conf/rnctree.py > new file mode 100755 > index 0000000..f691a4f > --- /dev/null > +++ b/conf/rnctree.py > @@ -0,0 +1,609 @@ > +#!/usr/bin/env python > +# Convert an RELAX NG compact syntax schema to a Node tree > +# This file released to the Public Domain by David Mertz > +# > +# Extended under revised BSD license by Jan Pokorny (jpokorny@xxxxxxxxxx) > +# Copyright 2013 Red Hat, Inc. > +# All rights reserved. > +# > +# Redistribution and use in source and binary forms, with or without > +# modification, are permitted provided that the following conditions are met: > +# > +# - Redistributions of source code must retain the above copyright notice, > +# this list of conditions and the following disclaimer. > +# - Redistributions in binary form must reproduce the above copyright notice, > +# this list of conditions and the following disclaimer in the documentation > +# and/or other materials provided with the distribution. > +# - Neither the name of the Red Hat, Inc. nor the names of its > +# contributors may be used to endorse or promote products derived from this > +# software without specific prior written permission. > +# > +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" > +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE > +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF > +# THE POSSIBILITY OF SUCH DAMAGE. > + > +# Differences when compared to trang output > +# 1. comments placement > +# 2. sometimes superfluous <group> > +# 3. context-free dichotomy (diff conv08.rng.{expected,trang}) > +# plenty of others (it's not the primary goal to achieve 1:1 trang match) > + > +# XXX: each AST node has its own subclass, knows how to XMLize itself, ...? > + > + > +import sys > +from rnc_tokenize import tokens, pair_rules, keywords, token_list > + > +# ONE ... default cardinality of one > +# DIRECT ... denotes that the usage of NAME is <name>, not <ref name=...> > +quant_tokens_aux = tuple(''' > + DIRECT > + ONE > + '''.split()) > + > +# AST nodes not directly matching the tokens > +parse_constructs = tuple(''' > + ROOT > + '''.split()) + tuple(r[2] for r in pair_rules) > + > +for t in tokens + quant_tokens_aux + parse_constructs: > + globals()[t] = t > + > +keyword_list = keywords.values() > + > +PAIRS = {r[0]: tuple(r[1:]) for r in pair_rules} > + > +TAGS = { > + ONE: 'group', > + SOME: 'oneOrMore', > + MAYBE: 'optional', > + ANY: 'zeroOrMore', > + ELEM: 'element', > + ATTR: 'attribute', > + NAME: 'ref', > +} > + > +URI_DATATYPES = "http://www.w3.org/2001/XMLSchema-datatypes" > +URI_ANNOTATIONS = "http://relaxng.org/ns/compatibility/annotations/1.0" > + > +DEFAULT_NAMESPACE = None > +DATATYPE_LIB = [0, '"' + URI_DATATYPES + '"'] > +OTHER_NAMESPACE = {} > +CONTEXT_FREE = 0 > + > +# debugging > +for i, n in enumerate(""" > + D_NOTHING > + D_TO_NODES > + D_MATCH_PAIR > + D_TYPE_BODIES > + D_NEST_DEFINES > + D_SCAN_NS > +""".split()): > + globals()[n] = i and 2 << (i - 1) or 0 > +dlist = [] > +#dlist.append(D_TO_NODES) > +#dlist.append(D_MATCH_PAIR) > +#dlist.append(D_TYPE_BODIES) > +#dlist.append(D_NEST_DEFINES) > +#dlist.append(D_SCAN_NS) > +debug = reduce(lambda a, b: a | b, dlist, D_NOTHING) > + > + > +def try_debug(what, nodes): > + if debug & globals().get('D_' + what, D_NOTHING): > + print what > + for node in nodes: > + print node.prettyprint() > + > + > +nodetypes = lambda nl: tuple(map(lambda n: n.type, nl)) > +toNodes = lambda toks: map(lambda t: Node(t.type, t.value), toks) > + > + > +class ParseError(SyntaxError): > + pass > + > + > +class Node(object): > + __slots__ = ('type', 'value', 'name', 'quant') > + > + def __iter__(self): > + yield self > + __len__ = lambda self: 1 > + > + def __init__(self, type='', value=None, name=None, quant=ONE): > + self.type = type > + self.value = value if value is not None else [] > + self.name = name > + self.quant = quant > + > + def format(self, indent=0): > + out = [' ' * indent + repr(self)] > + write = out.append > + if isinstance(self.value, str): > + if self.type == COMMENT: > + write(' ' * (1 + indent) + self.value) > + else: > + for node in self.value: > + write(node.format(indent + 1)) > + return '\n'.join(out) > + > + def prettyprint(self): > + print self.format() > + > + def toxml(self): > + if CONTEXT_FREE: > + out = [] > + write = out.append > + write('<?xml version="1.0" encoding="UTF-8"?>') > + write('<grammar>') > + self.type = None > + write(self.xmlnode(1)) > + write('</grammar>') > + return self.add_ns('\n'.join(out)) > + else: > + return self.add_ns(self.xmlnode()) > + > + def collect_annot(self, x): > + ret = {} > + if isinstance(x.value, basestring): > + return ret > + > + name, value = None, None > + for node in x.value: > + if node.type != NS_ANNOTATION: > + break > + for i, inner in enumerate(node.value): > + if i % 3 == 0 and inner.type == NAME: > + name = inner.value > + elif i % 3 == 1 and inner.type == DEFINE: > + name += ':' + inner.value > + elif i % 3 == 2 and inner.type == LITERAL: > + value = inner.value > + if ret.setdefault(name, value) is not value: > + assert 0, "redefinition of %s" % name > + name, value = None, None > + elif i % 3 == 0 and i > 0: > + break > + else: > + assert 0, "NS_ANNOTATION body does not match" > + return [n + '="' + v + '"' for n, v in ret.iteritems()] > + > + def xmlnode(self, indent=0): > + out = [] > + write = out.append > + if self.type == ROOT: > + write('<?xml version="1.0" encoding="UTF-8"?>') > + > + for i, x in enumerate(self.value): > + if not isinstance(x, Node): > + raise TypeError("Unhappy Node.value: " + repr(x)) > + if x.type == START: > + write(' ' * indent + '<start>') > + if (x.name is not None): > + write(' ' * (indent + 1) + '<ref name="%s"/>' % x.name) > + else: > + write(x.xmlnode(indent + 1)) > + write(' ' * indent + '</start>') > + elif x.type == DEFINE: > + write(' ' * indent + '<define name="%s">' % x.name) > + write(x.xmlnode(indent + 1)) > + write(' ' * indent + '</define>') > + elif x.type == COMMENT: > + comments = x.value.split('\n') > + if len(comments) == 1: > + c = ' ' + comments[0] + ' ' > + else: > + c = ('\n' + ' ' * (indent + 1)).join([''] + comments + ['']) > + write(' ' * indent + '<!--%s-->' % c) > + elif x.type == LITERAL: > + write(' ' * indent + '<value>%s</value>' % x.value) > + elif x.type == ANNOTATION: > + write(' ' * indent > + + '<a:documentation>%s</a:documentation>' % x.value) > + elif x.type == INTERLEAVE: > + write(' ' * indent + '<interleave>') > + write(x.xmlnode(indent + 1)) > + write(' ' * indent + '</interleave>') > + elif x.type == CHOICE: > + write(' ' * indent + '<choice>') > + write(x.xmlnode(indent + 1)) > + write(' ' * indent + '</choice>') > + elif x.type in (GROUP, SEQ): > + write(' ' * indent + '<group>') > + write(x.xmlnode(indent + 1)) > + write(' ' * indent + '</group>') > + elif x.type == TEXT: > + write(' ' * indent + '<text/>') > + elif x.type == EMPTY: > + write(' ' * indent + '<empty/>') > + elif x.type == DATATAG: > + DATATYPE_LIB[0] = 1 # Use datatypes > + if x.name is None: # no paramaters > + write(' ' * indent + '<data type="%s"/>' % x.value) > + else: > + write(' ' * indent + '<data type="%s">' % x.name) > + p = '<param name="pattern">%s</param>' % x.value > + write(' ' * (indent + 1) + p) > + write(' ' * indent + '</data>') > + elif x.type == INCLUDE: > + write(' ' * indent + '<include href="%s"/>' % x.value) > + elif x.type == NAME and x.quant == DIRECT: > + assert x.type == NAME > + write(' ' * indent + '<name>%s</name>' % x.value) > + elif x.type in (ATTR, ELEM, NAME): > + a = ('\n' + ' ' * (indent + 3)).join(self.collect_annot(x)) > + name_n_annot = '%s' % (' ' + a).rstrip() > + name = x.value if x.type == NAME else x.name > + if name: > + name_n_annot = ' name="%s"' % name + name_n_annot > + > + indent_inner = indent > + if x.quant != ONE: > + write(' ' * indent_inner + '<%s>' % TAGS[x.quant]) > + indent_inner += 1 > + tag, rest = TAGS[x.type], name_n_annot > + if x.type == NAME or x.type == ATTR and x.value[0].type == TEXT: > + write(' ' * indent_inner + '<%s%s/>' % (tag, rest)) > + else: > + write(' ' * indent_inner + '<%s%s>' % (tag, rest)) > + write(x.xmlnode(indent_inner + 1)) > + write(' ' * indent_inner + '</%s>' % tag) > + if x.quant != ONE: > + indent_inner -= 1 > + write(' ' * indent_inner + '</%s>' % TAGS[x.quant]) > + > + return '\n'.join(out) > + > + def __repr__(self): > + return "Node(%s,%s,%s)[%d]" % (self.type, self.name, > + self.quant, len(self.value)) > + > + def add_ns(self, xml): > + "Add namespace attributes to top level element" > + lines = xml.split('\n') > + self.nest_annotations(lines) # annots not allowed before root elem > + for i, line in enumerate(lines): > + ltpos = line.find('<') > + if ltpos >= 0 and line[ltpos + 1] not in ('!', '?'): > + # We've got an element tag, not PI or comment > + tail = '>' > + new = line[:line.find(tail)] > + if new.endswith('/'): > + new = new[:-1] > + tail = '/' + tail > + new += ' xmlns="http://relaxng.org/ns/structure/1.0"' > + if DEFAULT_NAMESPACE is not None: > + new += '\n ns=%s' % DEFAULT_NAMESPACE > + if DATATYPE_LIB[0]: > + new += '\n datatypeLibrary=%s' % DATATYPE_LIB[1] > + for ns, url in OTHER_NAMESPACE.items(): > + new += '\n xmlns:%s=%s' % (ns, url) > + new += tail > + lines[i] = new > + break > + return '\n'.join(lines) > + > + def nest_annotations(self, lines): > + "Nest any top annotation within first element" > + top_annotations = [] > + for i, line in enumerate(lines[:]): > + if line.find('<a:') >= 0: > + top_annotations.append(line) > + del lines[i] > + else: > + ltpos = line.find('<') > + if ltpos >= 0 and line[ltpos + 1] not in ('!', '?'): > + break > + for line in top_annotations: > + lines.insert(i, ' ' + line) > + > + > +def findmatch(beg, nodes, offset): > + level = 1 > + end = PAIRS[beg][0] > + for i, t in enumerate(nodes[offset:]): > + if t.type == beg: > + level += 1 > + elif t.type == end: > + level -= 1 > + if level == 0: > + return i + offset > + raise EOFError("No closing token encountered for %s @ %d" > + % (beg, offset)) > + > + > +# > +# 1st pass in the pipe > +# > + > +def match_pairs(nodes): > + """<left paren., []> + <tokens> + <right paren., []> --> <ent., <tokens>> > + > + Other effects: > + - merge comments/annotations > + """ > + newnodes = [] > + i = 0 > + while 1: > + if i >= len(nodes): > + break > + node = nodes[i] > + if node.type in PAIRS.keys(): > + # TOKEN, etc. -> NAME where suitable > + # (keyword-like names do not need to be escaped in some cases) > + if node.type == 'BEG_BODY' and newnodes[-1].type in keyword_list: > + if newnodes[-2].type in (ELEM, ATTR): > + newnodes[-1].type = NAME > + # Look for enclosing brackets > + match = findmatch(node.type, nodes, i + 1) > + matchtype = PAIRS[node.type][1] > + node = Node(type=matchtype, value=nodes[i + 1:match]) > + node.value = match_pairs(node.value) > + newnodes.append(node) > + i = match + 1 > + elif (node.type in (COMMENT, ANNOTATION) and i > 0 > + and newnodes[-1].type == node.type): > + # merge comments/annotations > + newnodes[-1].value += "\n" + node.value > + i += 1 > + else: > + newnodes.append(node) > + i += 1 > + if i >= len(nodes): > + break > + if nodes[i].type in (ANY, SOME, MAYBE): > + newnodes[-1].quant = nodes[i].type > + i += 1 > + > + nodes[:] = newnodes > + return nodes > + > + > +# > +# 2nd pass in the pipe > +# > + > +def type_bodies(nodes): > + """Another (main) de-linearization""" > + newnodes = [] > + i = 0 > + while 1: > + if i >= len(nodes): > + break > + if (nodetypes(nodes[i:i + 3]) == (ELEM, NAME, BODY) > + or nodetypes(nodes[i:i + 3]) == (ATTR, NAME, BODY)): > + name, body = nodes[i + 1].value, nodes[i + 2] > + value, quant = type_bodies(body.value), body.quant > + node = Node(nodes[i].type, value, name, quant) > + newnodes.append(node) > + if not name: > + assert False > + i += 3 > + # "element a|b" cases > + elif (nodetypes(nodes[i:i + 3]) == (ELEM, NAME, CHOICE) > + or nodetypes(nodes[i:i + 3]) == (ATTR, NAME, CHOICE)): > + # see nameClass (choice of nameClass+) > + # XXX: very simplified > + if nodes[i].type == ATTR: > + assert False > + node_type = nodes[i].type > + value = [nodes[i + 1]] > + i += 2 > + while nodetypes(nodes[i:i + 2]) == (CHOICE, NAME): > + value.extend(type_bodies(nodes[i:i + 2])) > + i += 2 > + # re-mark quant as we do not want "ref" output here > + for v in value: > + if v.type == NAME: > + v.quant = DIRECT > + assert len(nodes) >= i and nodes[i].type == BODY > + value.extend(type_bodies(nodes[i].value)) > + node = Node(node_type, value, None, nodes[i].quant) > + i += 1 > + newnodes.append(node) > + elif nodetypes(nodes[i:i + 2]) == (DATATAG, PATTERN): > + node = Node(DATATAG, nodes[i + 1].value, nodes[i].value) > + newnodes.append(node) > + i += 2 > + else: > + n = nodes[i] > + if n.type == GROUP: # Recurse into groups > + value = type_bodies(n.value) > + if len(value) > 1 and n.type: > + n = Node(GROUP, value, None, n.quant) > + newnodes.append(n) > + i += 1 > + nodes[:] = newnodes > + return nodes > + > + > +# > +# 3rd pass in the pipe > +# > + > +def _nest_annotations(nodes, mapping, delim=None): > + """Helper to move comments/annotations down into attributes/elements > + > + Uses non-tail recursion to proceed the tree bottom-up as > + otherwise there would be confusion if the annotations are > + newly added (and thus should be kept) or the original ones > + to be moved. > + > + Mapping is partially defined > + token-type |-> accumulator-list for token-type > + for token-types covering annotations (ANNOTATION, NS_ANNOTATION) > + and is used to pass unconsumed annotations down the tree. > + > + Returns triplet: number of consumed nodes, filtered nodes, mapping. > + > + Note that mapping should contain empty lists only when the recursion > + returns back to the initiator (XXX: little bit of sanity checking, > + we cannot speak about proper validation here). > + """ > + # XXX: unclean, yes > + newnodes = [] > + for i, n in enumerate(nodes): > + if delim and n.type == delim: > + break > + > + if not isinstance(n.value, str): # no recurse to terminal str > + if n.type in (ELEM, ATTR): > + mapping_rec = {n: [] for n in > + (ANNOTATION, NS_ANNOTATION, COMMENT)} > + else: > + mapping_rec = mapping > + _nest_annotations(n.value, mapping_rec) > + > + if n.type in (ELEM, ATTR): # annot. consumer (guarded in recursion) > + n.value = (mapping['NS_ANNOTATION'] + mapping['ANNOTATION'] > + + mapping['COMMENT'] + n.value) > + mapping['NS_ANNOTATION'][:], mapping['ANNOTATION'][:] = [], [] > + mapping['COMMENT'][:] = [] > + elif i == len(nodes) - 1 and n.type == COMMENT and not delim: > + # comment at the end of the nodelist, but only if not top-level > + newnodes.append(n) > + continue > + > + mapping.get(n.type, newnodes).append(n) > + > + nodes[:] = newnodes > + return i, nodes, mapping > + > + > +def _intersperse(nodes): > + """Look for interleaved, choice, or sequential nodes in groups/bodies""" > + for node in nodes: > + if node.type in (ELEM, ATTR, GROUP, LITERAL): # XXX: literal? > + val = node.value > + ntypes = [n.type for n in val if not isinstance(val, str)] > + inters = [t for t in ntypes if t in (INTERLEAVE, CHOICE, SEQ)] > + inters = dict(zip(inters, [0] * len(inters))) > + if len(inters) > 1: > + raise ParseError("Ambiguity in sequencing: %s" % node) > + if len(inters) > 0: > + intertype = inters.keys()[0] > + outer_items, last_ntype, internode = [], None, None > + simplify = node.type == GROUP > + for pat in node.value: > + if pat.type == intertype: > + if internode is None: > + internode = Node(intertype, [outer_items.pop()]) > + outer_items.append(internode) > + # otherwise drop it > + elif last_ntype == intertype: > + internode.value.append(pat) > + else: > + outer_items.append(pat) > + if pat.type in (COMMENT, ANNOTATION): > + # these are not interesting wrt. last type > + continue > + elif pat.quant not in (ONE, MAYBE): > + simplify = False > + last_ntype = pat.type > + > + if (simplify and len(outer_items) == 1 > + and outer_items[0] is internode): > + node.type, node.value = internode.type, internode.value > + else: > + node.value = outer_items > + if not isinstance(node.value, str): # No recurse to terminal str > + _intersperse(node.value) > + return nodes > + > + > +def nest_defines(nodes): > + """Attach groups to named patterns > + > + Other effects: > + - annotations are properly nested > + - comments are nested > + """ > + newnodes = [] > + i = 0 > + group, annotations, ns_annotations, comments = [], [], [], [] > + mapping = dict(ANNOTATION=annotations, NS_ANNOTATION=ns_annotations, > + COMMENT=comments) > + while i < len(nodes): > + node = nodes[i] > + newnodes.append(node) > + group[:], annotations[:], ns_annotations[:], comments[:] = [], [], [], [] > + if node.type == DEFINE: > + j, group[:], mapping = _nest_annotations(nodes[i + 1:], mapping, DEFINE) > + i += j > + node.name = node.value > + grp = _intersperse([Node(GROUP, group[:])])[0] > + if len(grp.value) > 1 and grp.type != SEQ: > + node.value = [grp] > + else: > + node.value = grp.value[:] > + # when _nest_annotations returned *not* due to reaching DEFINE, > + # but trailing comments are tolerated > + if i + 1 > len(nodes) or nodes[i + 1].type not in (DEFINE, COMMENT): > + break > + elif node.type == ELEM: > + # top-level element > + _intersperse(Node(GROUP, [node])) > + i += 1 > + nodes[:] = newnodes > + return nodes > + > + > +# > +# 4th pass in the pipe > +# > + > +def scan_NS(nodes): > + """Look for any namespace configuration lines > + > + Other effects: > + - DEFINE(start) --> START > + """ > + global DEFAULT_NAMESPACE, OTHER_NAMESPACE, CONTEXT_FREE > + for node in nodes: > + if node.type == DEFAULT_NS: > + DEFAULT_NAMESPACE = node.value > + elif node.type == NS: > + ns, url = map(str.strip, node.value.split('=', 1)) > + OTHER_NAMESPACE[ns] = url > + elif node.type == ANNOTATION and 'a' not in OTHER_NAMESPACE: > + OTHER_NAMESPACE['a'] = '"' + URI_ANNOTATIONS + '"' > + elif node.type == DATATYPES: > + DATATYPE_LIB[:] = [1, node.value] > + elif not CONTEXT_FREE and node.type == DEFINE and node.name == 'start': > + CONTEXT_FREE = 1 > + node.type = START > + node.name = None > + > + > +def make_nodetree(tokens): > + """Wraps the pipe of conversion passes""" > + nodes = toNodes(tokens) > + try_debug('TO_NODES', nodes) > + > + match_pairs(nodes) > + try_debug('MATCH_PAIR', nodes) > + > + type_bodies(nodes) > + try_debug('TYPE_BODIES', nodes) > + > + nest_defines(nodes) > + try_debug('NEST_DEFINES', nodes) > + > + scan_NS(nodes) > + try_debug('SCAN_NS', nodes) > + > + return Node(ROOT, nodes) > + > + > +if __name__ == '__main__': > + print make_nodetree(token_list(sys.stdin.read())).toxml() > diff --git a/conf/rng2asciidocman.xsl b/conf/rng2asciidocman.xsl > new file mode 100644 > index 0000000..719fe55 > --- /dev/null > +++ b/conf/rng2asciidocman.xsl > @@ -0,0 +1,490 @@ > +<?xml version="1.0" encoding="utf-8"?> > +<xsl:stylesheet version="1.0" > + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > + xmlns:rng="http://relaxng.org/ns/structure/1.0" > + xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" > + xmlns:a4doc="http://people.redhat.com/jpokorny/ns/a4doc" > + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> > + > +<!-- > + Copyright 2013 Red Hat, Inc. > + All rights reserved. > + > + Redistribution and use in source and binary forms, with or without > + modification, are permitted provided that the following conditions are met: > + > + - Redistributions of source code must retain the above copyright notice, > + this list of conditions and the following disclaimer. > + - Redistributions in binary form must reproduce the above copyright notice, > + this list of conditions and the following disclaimer in the documentation > + and/or other materials provided with the distribution. > + - Neither the name of the Red Hat, Inc. nor the names of its > + contributors may be used to endorse or promote products derived from this > + software without specific prior written permission. > + > + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" > + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE > + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF > + THE POSSIBILITY OF SUCH DAMAGE. > + --> > + > +<!-- > + TODO: cross-references > + TODO: support annotations of the sections > + TODO: dependency on simplification can be removed using similar construction > + as used in rng2lens.xsl, IOW. named set of options would be described > + and further referred (wrapped with some wording like "see the named > + set of options XY" ... wait, expanding it fully may be actually better) > + --> > + > +<!-- prologue --> > +<xsl:import href="common.xsl"/> > +<xsl:output method="text"/> > +<xsl:strip-space elements="*"/> > + > +<!-- xsltdoc (http://www.kanzaki.com/parts/xsltdoc.xsl) header --> > +<xsl:template name="_doas_description"> > + <rdf:RDF xmlns="http://purl.org/net/ns/doas#"> > + <rdf:Description rdf:about=""> > + <title>rng2asciidocman.xsl XSLT stylesheet</title> > + <description> > + This stylesheet generates AsciiDoc formatted man page from > + RELAX NG schema modeling corosync configuration (as reified > + in the form of corosync.conf). > + > + INPUT: corosync.rnc converted to non-compact syntax > + + simplified (step7.20) > + OUTPUT: AsciiDoc document suitable for -> DocBook -> man page > + proceeding > + </description> > + <author rdf:parseType="Resource"> > + <name>Jan Pokorný</name> > + <mbox rdf:resource="jpokorny@xxxxxxxxxx"/> > + </author> > + <created>2013-02-01</created> > + <release rdf:parseType="Resource"> > + <revision>0.2</revision> > + <created>2013-02-04</created> > + </release> > + <rights>Copyright 2013 Red Hat, Inc.</rights> > + <license rdf:resource="http://opensource.org/licenses/BSD-3-Clause"/> > + <acknowledgement> > + Based on previous work of Steven Dake et al. > + </acknowledgement> > + </rdf:Description> > + </rdf:RDF> > +</xsl:template> > + > +<!-- > + helpers > + --> > + > +<xsl:variable name="bold" select="'*'"/> > +<xsl:variable name="underline" select='"'"'/> > +<xsl:variable name="SP"><xsl:text> </xsl:text></xsl:variable> > +<xsl:variable name="NL"><xsl:text>
</xsl:text></xsl:variable> > +<xsl:variable name="NLNL"><xsl:text>

</xsl:text></xsl:variable> > +<xsl:variable name="NLNLNL"><xsl:text>


</xsl:text></xsl:variable> > + > +<xsl:template name="string-replace-all"> > + <!--** Replaces each occurrence of 'replace' in 'string' with 'by'. --> > + <xsl:param name="string"/> > + <xsl:param name="replace"/> > + <xsl:param name="by"/> > + <xsl:choose> > + <xsl:when test="contains($string, $replace)"> > + <xsl:value-of select="substring-before($string, $replace)"/> > + <xsl:value-of select="$by"/> > + <!--@Recursion.--> > + <xsl:call-template name="string-replace-all"> > + <xsl:with-param name="string" > + select="substring-after($string, $replace)"/> > + <xsl:with-param name="replace" select="$replace"/> > + <xsl:with-param name="by" select="$by"/> > + </xsl:call-template> > + </xsl:when> > + <xsl:otherwise> > + <xsl:value-of select="$string"/> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template name="serialize-per-name"> > + <!--** Generates "A, B and C" with optional markup of items. --> > + <xsl:param name="items"/> > + <xsl:param name="markup" value="''"/> > + <xsl:for-each select="$items"> > + <xsl:choose> > + <xsl:when test="position() = 1"> > + <xsl:value-of select="concat($markup, @name, $markup)"/> > + </xsl:when> > + <xsl:when test="position() = last()"> > + <xsl:value-of select="concat(' and ', $markup, @name, $markup)"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:value-of select="concat(', ', $markup, @name, $markup)"/> > + </xsl:otherwise> > + </xsl:choose> > + </xsl:for-each> > +</xsl:template> > + > +<xsl:template name="context-description"> > + <!--** Generates context description. --> > + <xsl:param name="items"/> > + <xsl:choose> > + <xsl:when test='@name != $start-name'> > + <xsl:choose> > + <xsl:when test="count($items) <= 1"> > + <xsl:text>subsection of </xsl:text> > + </xsl:when> > + <xsl:otherwise> > + <xsl:text>subsections of </xsl:text> > + </xsl:otherwise> > + </xsl:choose> > + <xsl:value-of select="concat($bold, @name, $bold)"/> > + <xsl:text> section</xsl:text> > + <xsl:choose> > + <xsl:when test="count($items) = 0"/> > + <xsl:when test="count($items) = 1"> > + <xsl:text> is</xsl:text> > + </xsl:when> > + <xsl:otherwise> > + <xsl:text> are</xsl:text> > + </xsl:otherwise> > + </xsl:choose> > + </xsl:when> > + <xsl:otherwise> > + <xsl:choose> > + <xsl:when test="count($items) = 0"> > + <xsl:text>top-level section</xsl:text> > + </xsl:when> > + <xsl:when test="count($items) = 1"> > + <xsl:text>top-level section is</xsl:text> > + </xsl:when> > + <xsl:otherwise> > + <xsl:text>top-level sections are</xsl:text> > + </xsl:otherwise> > + </xsl:choose> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<!-- > + configuration > + --> > + > +<xsl:variable name="head">// generated, no point in editing this > +COROSYNC_CONF(5) > +================ > +:doctype: manpage > +:man source: corosync Man Page > +//:man version: > +:man manual: Corosync Cluster Engine Programmer's Manual > +// workaround AsciiDoc not supporting glosslist as it's in DocBook5+ > +:listtags-glossary.list: <glosslist{id? id="{id}"}{role? role="{role}"}{reftext? xreflabel="{reftext}"}>{title?<title>{title}</title>}|</glosslist> > + > + > +NAME > +---- > +corosync.conf - corosync executive configuration file > + > + > +SYNOPSIS > +-------- > +`/etc/corosync/corosync.conf` > + > + > +DESCRIPTION > +----------- > +The *`corosync.conf`* instructs the corosync executive about various parameters > +needed to control the corosync executive. > + > +The configuration file consists top level directives that mostly denote > +bracketed configuration sections (i.e., wrapped by a pair of '{', '}' > +characters and identified by the preceeding directive). The content of > +a section consists of new-line separated configuration items, option-value > +pairs delimited by ':', interleaved with likewise formatted subsections. > +Empty lines and lines starting with '#' character are ignored. > + > + > +CONFIGURATION SECTIONS AND OPTIONS > +---------------------------------- > +</xsl:variable> > + > +<xsl:variable name="tail"> > + > +FILES > +----- > +[glossary] > +*`/etc/corosync/corosync.conf`*:: > + The corosync executive configuration file. > + > + > +SEE ALSO > +-------- > +*corosync_overview*(8), *votequorum*(5), *logrotate*(8) > +</xsl:variable> > + > +<!-- > + declarative attitude > + --> > + > +<xsl:variable name="start-name" select="/rng:grammar/rng:start/rng:ref/@name"/> > +<xsl:variable name="start" > + select="/rng:grammar/rng:define[@name = $start-name]/rng:element"/> > + > +<xsl:template match="/"> > + <!--** Triggers template, wrapping processed top element with head/tail. --> > + <xsl:value-of select="$head"/> > + <xsl:apply-templates select="$start"/> > + <xsl:value-of select="$tail"/> > +</xsl:template> > + > +<xsl:template match="rng:element"> > + <!--** Section handling. --> > + <xsl:variable name="secs-required" > + select="/rng:grammar/rng:define[ > + @name = > + (current() > + |current()/rng:group > + |current()/rng:interleave > + |current()/rng:group/rng:interleave > + )/rng:ref/@name > + ]/rng:element[ > + a:documentation or current() != $start > + ]"/> > + <xsl:variable name="secs-optional" > + select="/rng:grammar/rng:define[ > + @name = > + (current()/rng:zeroOrMore > + |current()/rng:group/rng:zeroOrMore > + |current()/rng:interleave/rng:optional > + |current()/rng:group/rng:interleave/rng:optional > + |current()/rng:optional > + |current()/rng:group/rng:optional > + )/rng:ref/@name > + ]/rng:element[ > + a:documentation or current() != $start > + ]"/> > + > + <xsl:if test="a:documentation"> > + <xsl:call-template name="string-replace-all"> > + <xsl:with-param name="string" select="a:documentation"/> > + <xsl:with-param name="replace" select="$NLNL"/> > + <xsl:with-param name="by" select="concat($NL, '+', $NL)"/> > + </xsl:call-template> > + <xsl:value-of select="$NL"/> > + </xsl:if> > + > + <xsl:choose> > + <xsl:when test="$secs-required or $secs-optional"> > + <xsl:if test="$secs-required"> > + <xsl:variable name="context-description"> > + <xsl:call-template name="context-description"> > + <xsl:with-param name="items" select="$secs-required"/> > + </xsl:call-template> > + </xsl:variable> > + <xsl:variable name="secs-required-line"> > + <xsl:call-template name="serialize-per-name"> > + <xsl:with-param name="items" select="$secs-required"/> > + <xsl:with-param name="markup" select="$bold"/> > + </xsl:call-template> > + </xsl:variable> > + <xsl:text>Required </xsl:text> > + <xsl:value-of select="concat($context-description, $SP, > + $secs-required-line)"/> > + <xsl:choose> > + <xsl:when test="$secs-optional"> > + <xsl:text>,</xsl:text> > + </xsl:when> > + <xsl:otherwise> > + <xsl:text>.</xsl:text> > + </xsl:otherwise> > + </xsl:choose> > + <xsl:value-of select="$NL"/> > + </xsl:if> > + <!-- sep --> > + <xsl:if test="$secs-optional"> > + <xsl:variable name="context-description"> > + <xsl:call-template name="context-description"> > + <xsl:with-param name="items" select="$secs-optional"/> > + </xsl:call-template> > + </xsl:variable> > + <xsl:variable name="secs-optional-line"> > + <xsl:call-template name="serialize-per-name"> > + <xsl:with-param name="items" select="$secs-optional"/> > + <xsl:with-param name="markup" select="$bold"/> > + </xsl:call-template> > + </xsl:variable> > + <xsl:choose> > + <xsl:when test="$secs-required"> > + <xsl:text>optional </xsl:text> > + </xsl:when> > + <xsl:otherwise> > + <xsl:text>Optional </xsl:text> > + </xsl:otherwise> > + </xsl:choose> > + <xsl:value-of select="concat($context-description, $SP, > + $secs-optional-line, '.', $NL)"/> > + </xsl:if> > + </xsl:when> > + <xsl:otherwise> > + <xsl:variable name="context-description"> > + <xsl:call-template name="context-description"> > + <xsl:with-param name="items" select="$secs-required"/> > + </xsl:call-template> > + </xsl:variable> > + <xsl:text>There is no </xsl:text> > + <xsl:value-of select="$context-description"/> > + <xsl:text>.</xsl:text> > + <xsl:value-of select="$NL"/> > + </xsl:otherwise> > + </xsl:choose> > + <xsl:value-of select="$NL"/> > + > + <xsl:call-template name="proceed-options"> > + <xsl:with-param name="opts-required" > + select="(. > + |rng:group > + )/rng:attribute[a:documentation]"/> > + <xsl:with-param name="opts-optional" > + select="(. > + |rng:group > + )/rng:optional/rng:attribute[a:documentation]"/> > + </xsl:call-template> > + > + <xsl:call-template name="proceed-sections"> > + <xsl:with-param name="secs-required" > + select="$secs-required"/> > + <xsl:with-param name="secs-optional" > + select="$secs-optional"/> > + </xsl:call-template> > +</xsl:template> > + > +<xsl:template match="rng:attribute"> > + <!--** Option handling. --> > + <xsl:variable name="content"> > + <xsl:call-template name="string-replace-all"> > + <xsl:with-param name="string" select="a:documentation"/> > + <xsl:with-param name="replace" select="$NLNL"/> > + <xsl:with-param name="by" select="concat($NL, '+', $NL)"/> > + </xsl:call-template> > + </xsl:variable> > + <xsl:value-of select="$NL"/> > + <xsl:value-of select="concat($bold, @name, $bold)"/> > + <xsl:if test="@a:defaultValue"> > + <xsl:value-of select="concat(' (default: ', $underline, @a:defaultValue, $underline,')')"/> > + </xsl:if> > + <xsl:text>::</xsl:text> > + <xsl:value-of select="concat($NLNL, $content)"/> > + <xsl:if test="rng:choice"> > + <!--@Show enumerated values.--> > + <xsl:value-of select="$NL"/> > + <xsl:text>Possible values: </xsl:text> > + <xsl:call-template name="text-join"> > + <xsl:with-param name="items" select="rng:choice/rng:value"/> > + <xsl:with-param name="sep" select="', '"/> > + <xsl:with-param name="markup" select="$underline"/> > + </xsl:call-template> > + <xsl:text>.</xsl:text> > + </xsl:if> > + <xsl:for-each select="@a4doc:*[contains(local-name(), '-hint')]"> > + <!--@Extra handling of per-option a4doc annotations.--> > + <xsl:value-of select="$NLNL"/> > + <xsl:choose> > + <xsl:when test="local-name() = 'danger-hint'"> > + <xsl:text>CAUTION: </xsl:text> > + </xsl:when> > + <xsl:when test="local-name() = 'discretion-hint'"> > + <xsl:text>IMPORTANT: </xsl:text> > + </xsl:when> > + <xsl:when test="local-name() = 'deprecation-hint'"> > + <xsl:text>WARNING: This has been deprecated. </xsl:text> > + </xsl:when> > + <xsl:otherwise> > + <xsl:text>WARNING: </xsl:text> > + </xsl:otherwise> > + </xsl:choose> > + <xsl:value-of select="normalize-space(.)"/> > + <xsl:value-of select="$NL"/> > + </xsl:for-each> > + <xsl:value-of select="$NLNL"/> > +</xsl:template> > + > +<!-- > + procedural attitude > + --> > + > +<xsl:template name="proceed-sections"> > + <!--** Required/optional sections handling. --> > + <xsl:param name="secs-required" value="false()"/> > + <xsl:param name="secs-optional" value="false()"/> > + > + <!-- cannot use $secs-required|$secs-optional (we need explicit order) --> > + <xsl:for-each select="$secs-required"> > + <xsl:value-of select="concat($NL, '=== ', @name, $NLNLNL)"/> > + <xsl:apply-templates select="."/> > + </xsl:for-each> > + > + <xsl:for-each select="$secs-optional"> > + <xsl:value-of select="concat($NL, '=== ', @name, $NLNLNL)"/> > + <xsl:apply-templates select="."/> > + </xsl:for-each> > +</xsl:template> > + > +<xsl:template name="proceed-options"> > + <!--** Required/optional options handling. --> > + <xsl:param name="opts-required" value="false()"/> > + <xsl:param name="opts-optional" value="false()"/> > + > + <xsl:variable name="opts-required-line"> > + <xsl:call-template name="serialize-per-name"> > + <xsl:with-param name="items" select="$opts-required"/> > + <xsl:with-param name="markup" select="$underline"/> > + </xsl:call-template> > + </xsl:variable> > + <xsl:variable name="opts-optional-line"> > + <xsl:call-template name="serialize-per-name"> > + <xsl:with-param name="items" select="$opts-optional"/> > + <xsl:with-param name="markup" select="$underline"/> > + </xsl:call-template> > + </xsl:variable> > + > + <xsl:if test="$opts-required"> > + <xsl:value-of select="$NL"/> > + <xsl:choose> > + <xsl:when test="count($opts-required) = 1"> > + <xsl:text>==== Required option</xsl:text> > + </xsl:when> > + <xsl:otherwise> > + <xsl:text>==== Required options</xsl:text> > + </xsl:otherwise> > + </xsl:choose> > + <xsl:value-of select="$NL"/> > + <xsl:apply-templates select="$opts-required"/> > + </xsl:if> > + > + <xsl:if test="$opts-optional"> > + <xsl:value-of select="$NL"/> > + <xsl:choose> > + <xsl:when test="count($opts-optional) = 1"> > + <xsl:text>==== Optional or conditionally required option</xsl:text> > + </xsl:when> > + <xsl:otherwise> > + <xsl:text>==== Optional or conditionally required options</xsl:text> > + </xsl:otherwise> > + </xsl:choose> > + <xsl:value-of select="$NL"/> > + <xsl:apply-templates select="$opts-optional"/> > + </xsl:if> > +</xsl:template> > + > +</xsl:stylesheet> > +<!-- vim: set et ts=4 sw=4: --> > diff --git a/conf/rng2lens.xsl b/conf/rng2lens.xsl > new file mode 100644 > index 0000000..c205a6f > --- /dev/null > +++ b/conf/rng2lens.xsl > @@ -0,0 +1,333 @@ > +<?xml version="1.0" encoding="utf-8"?> > +<xsl:stylesheet version="1.0" > + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > + xmlns:rng="http://relaxng.org/ns/structure/1.0" > + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> > + > +<!-- > + Copyright 2013 Red Hat, Inc. > + All rights reserved. > + > + Redistribution and use in source and binary forms, with or without > + modification, are permitted provided that the following conditions are met: > + > + - Redistributions of source code must retain the above copyright notice, > + this list of conditions and the following disclaimer. > + - Redistributions in binary form must reproduce the above copyright notice, > + this list of conditions and the following disclaimer in the documentation > + and/or other materials provided with the distribution. > + - Neither the name of the Red Hat, Inc. nor the names of its > + contributors may be used to endorse or promote products derived from this > + software without specific prior written permission. > + > + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" > + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE > + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF > + THE POSSIBILITY OF SUCH DAMAGE. > +--> > + > +<!-- > + TODO: migrate to using Build Augeas "library" > + --> > + > +<!-- prologue --> > +<xsl:import href="common.xsl"/> > +<xsl:import href="xsddatatypes2lens.xsl"/> > +<xsl:output method="text"/> > +<xsl:strip-space elements="*"/> > + > +<!-- xsltdoc (http://www.kanzaki.com/parts/xsltdoc.xsl) header --> > +<xsl:template name="_doas_description"> > + <rdf:RDF xmlns="http://purl.org/net/ns/doas#"> > + <rdf:Description rdf:about=""> > + <title>rng2lens.xsl XSLT stylesheet</title> > + <description> > + This stylesheet generates Augeas lens from RELAX NG schema > + modeling corosync configuration (as reified in the form > + of corosync.conf). > + > + INPUT: corosync.rnc converted 1:1 to non-compact syntax > + (no simplification) > + OUTPUT: Augeas lens for corosync.conf > + </description> > + <author rdf:parseType="Resource"> > + <name>Jan Pokorný</name> > + <mbox rdf:resource="jpokorny@xxxxxxxxxx"/> > + </author> > + <created>2013-02-01</created> > + <release rdf:parseType="Resource"> > + <revision>0.2</revision> > + <created>2013-02-04</created> > + </release> > + <rights>Copyright 2013 Red Hat, Inc.</rights> > + <license rdf:resource="http://opensource.org/licenses/BSD-3-Clause"/> > + <acknowledgement> > + Based on previous work of Angus Salkeld et al. > + </acknowledgement> > + </rdf:Description> > + </rdf:RDF> > +</xsl:template> > + > +<!-- > + helpers > + --> > + > +<xsl:variable name="SP"><xsl:text> </xsl:text></xsl:variable> > +<xsl:variable name="NL"><xsl:text>
</xsl:text></xsl:variable> > +<xsl:variable name="NLNL"><xsl:text>

</xsl:text></xsl:variable> > +<xsl:variable name="QUOT"><xsl:text>"</xsl:text></xsl:variable> > + > +<xsl:template name="string-replace-all"> > + <!--** Replaces each occurrence of 'replace' in 'string' with 'by'. --> > + <xsl:param name="string"/> > + <xsl:param name="replace"/> > + <xsl:param name="by"/> > + <xsl:choose> > + <xsl:when test="contains($string, $replace)"> > + <xsl:value-of select="substring-before($string, $replace)"/> > + <xsl:value-of select="$by"/> > + <!-- recursion --> > + <xsl:call-template name="string-replace-all"> > + <xsl:with-param name="string" > + select="substring-after($string, $replace)"/> > + <xsl:with-param name="replace" select="$replace"/> > + <xsl:with-param name="by" select="$by"/> > + </xsl:call-template> > + </xsl:when> > + <xsl:otherwise> > + <xsl:value-of select="$string"/> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template name="serialize-per-name-plus"> > + <!--** Generates "A|B|C" with extra decorations via modes. --> > + <xsl:param name="items"/> > + <xsl:for-each select="$items"> > + <xsl:variable name="prefix"> > + <xsl:choose> > + <xsl:when test="name() = 'attribute'"> > + <xsl:apply-templates select="." mode="plus-prefix-option"/> > + </xsl:when> > + </xsl:choose> > + </xsl:variable> > + <xsl:variable name="suffix"> > + <xsl:choose> > + <xsl:when test="name() = 'attribute'"> > + <xsl:apply-templates select="." mode="plus-suffix-option"/> > + </xsl:when> > + </xsl:choose> > + </xsl:variable> > + <!--@Serialization itself, using obtained prefix/suffix.--> > + <xsl:choose> > + <xsl:when test="position() = 1"> > + <xsl:value-of select="concat($NL, ' ', $prefix, @name, $suffix)"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:value-of select="concat($NL, ' |', $prefix, @name, $suffix)"/> > + </xsl:otherwise> > + </xsl:choose> > + </xsl:for-each> > +</xsl:template> > + > +<!-- > + configuration > + --> > + > +<xsl:variable name="toplevel-name">lns</xsl:variable> > + > +<!-- XXX: this can be overriden from autotools --> > +<xsl:param name="config-file" > + select="concat($QUOT, '/etc/corosync/corosync.conf', $QUOT)"/> > + > +<xsl:variable name="head">(* generated, no point in editing this *) > +(* Process /etc/corosync/corosync.conf *) > +(* The lens is based on the corosync RELAX NG schema defining *) > +(* corosync configuration (same base for corosync.conf man page) *) > +module Corosync = > + > +autoload xfm > + > +let comment = Util.comment > +let empty = Util.empty > +let dels = Util.del_str > +let eol = Util.eol > + > +let ws = del /[ \t]+/ " " > +let wsc = del /:[ \t]+/ ": " > +let indent = del /[ \t]*/ "" > +(* We require that braces are always followed by a newline *) > +let obr = del /\{([ \t]*)\n/ "{\n" > +let cbr = del /[ \t]*}[ \t]*\n/ "}\n" > + > +let ikey (k:regexp) = indent . key k > + > +let section (n:regexp) (b:lens) = > + [ ikey n . ws . obr . (b|empty|comment)* . cbr ] > + > +let kv (k:regexp) (v:regexp) = > + [ ikey k . wsc . store v . eol ] > + > +(* FIXME: it would be much more concise to write *) > +(* [ key k . ws . (bare | quoted) ] *) > +(* but the typechecker trips over that *) > +let qstr (k:regexp) = > + let delq = del /['"]/ "\"" in > + let bare = del /["']?/ "" . store /[^"' \t\n]+/ . del /["']?/ "" in > + let quoted = delq . store /.*[ \t].*/ . delq in > + [ ikey k . wsc . bare . eol ] > + |[ ikey k . wsc . quoted . eol ] > + > +</xsl:variable> > + > +<!-- > + declarative attitude > + --> > + > +<xsl:variable name="start-name" select="/rng:grammar/rng:start/rng:ref/@name"/> > +<xsl:variable name="start" > + select="/rng:grammar/rng:define[@name = $start-name]"/> > + > +<xsl:key name="definekey" match="/rng:grammar/rng:define" use="@name"/> > +<xsl:key name="refkey" match="rng:ref" use="@name"/> > + > +<xsl:template match="/"> > + <!--** Triggers template, wrapping processed top element with head/tail. --> > + <xsl:value-of select="$head"/> > + <xsl:apply-templates select="$start"/> > + <xsl:value-of select="concat('let xfm = transform ', $toplevel-name)"/> > + <xsl:value-of select="concat(' (incl ', QUOT, $config-file, QUOT, ')')"/> > +</xsl:template> > + > +<xsl:template match="rng:define | rng:element"> > + <!--** Sections handling. --> > + <xsl:choose> > + <xsl:when test="name() = 'define' and rng:element[@name = current()/@name]"> > + <!--@Delegate to nested element with the same @name if suitable.--> > + <xsl:apply-templates select="rng:element[@name = current()/@name]"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:variable name="secs-required" > + select="(current() > + |current()/rng:group > + |current()/rng:interleave > + |current()/rng:group/rng:interleave > + )/rng:ref"/> > + <xsl:variable name="secs-optional" > + select="(current()/rng:zeroOrMore > + |current()/rng:group/rng:zeroOrMore > + |current()/rng:interleave/rng:optional > + |current()/rng:group/rng:interleave/rng:optional > + |current()/rng:optional > + |current()/rng:group/rng:optional > + )/rng:ref"/> > + <xsl:variable name="opts-required" > + select="(. > + |rng:group > + )/rng:attribute"/> > + <xsl:variable name="opts-optional" > + select="(. > + |rng:group > + )/rng:optional/rng:attribute"/> > + > + <xsl:if test="name() = 'element' and $start//rng:ref[@name = current()/@name]"> > + <xsl:value-of select="concat('(* The ', @name, > + ' section *)', $NL)"/> > + </xsl:if> > + > + <!--@Emit non-duplicated definitions we depend on (-> postorder).--> > + <xsl:for-each select="$secs-required|$secs-optional"> > + <xsl:if test="generate-id() = generate-id(key('refkey', @name)[1])"> > + <xsl:apply-templates select="key('definekey', @name)"/> > + </xsl:if> > + </xsl:for-each> > + > + <!--@Determine initial part.--> > + <xsl:choose> > + <xsl:when test="@name = $start-name"> > + <xsl:value-of select="concat('let ', $toplevel-name, > + ' = (comment|empty|')"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:value-of select="concat('let ', @name, ' =')"/> > + <xsl:if test="name() = 'element'"> > + <xsl:value-of select="concat($NL, ' let setting =')"/> > + </xsl:if> > + </xsl:otherwise> > + </xsl:choose> > + > + <!--@Determine body.--> > + <xsl:call-template name="serialize-per-name-plus"> > + <xsl:with-param name="items" > + select="$secs-required > + |$secs-optional > + |$opts-required > + |$opts-optional"/> > + </xsl:call-template> > + > + <!--@Determine final part.--> > + <xsl:choose> > + <xsl:when test="@name = $start-name"> > + <xsl:text>)*</xsl:text> > + </xsl:when> > + <xsl:when test="name() = 'element'"> > + <xsl:value-of select="concat(' in', $NL, ' section ', > + $QUOT, @name, $QUOT, > + ' setting')"/> > + </xsl:when> > + </xsl:choose> > + <xsl:value-of select="$NLNL"/> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="*" mode="plus-prefix-option"> > + <!--** Option has extra line prefix: 'kv' or 'qstr'. --> > + <xsl:choose> > + <xsl:when test="rng:choice or rng:data[@type != '']"> > + <!--@Start kv (finalized in 'plus-suffix-option' mode).--> > + <xsl:value-of select="concat('kv', $SP, $QUOT)"/> > + </xsl:when> > + <xsl:otherwise> > + <!--@Start qstr (finalized in 'plus-suffix-option' mode).--> > + <xsl:value-of select="concat('qstr', $SP, '/')"/> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="*" mode="plus-suffix-option"> > + <!--** Option has extra line suffix: (type/enumerated values). --> > + <xsl:choose> > + <xsl:when test="rng:choice"> > + <!--@Finalize kv with enumerated values forming target regexp.--> > + <xsl:value-of select="concat($QUOT, $SP)"/> > + <xsl:text>/</xsl:text> > + <xsl:call-template name="text-join"> > + <xsl:with-param name="items" select="rng:choice/rng:value"/> > + <xsl:with-param name="sep" select="'|'"/> > + </xsl:call-template> > + <xsl:text>/</xsl:text> > + </xsl:when> > + <xsl:when test="rng:data[@type != '']"> > + <!--@Finalize kv with explicit type (see xsddatatypes2lens.xsl).--> > + <xsl:value-of select="concat($QUOT, $SP)"/> > + <xsl:call-template name="xsddatatype2lens"> > + <xsl:with-param name="type" select="rng:data/@type"/> > + </xsl:call-template> > + </xsl:when> > + <xsl:otherwise> > + <!--@Finalize qstr.--> > + <xsl:value-of select="'/'"/> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +</xsl:stylesheet> > +<!-- vim: set et ts=4 sw=4: --> > diff --git a/conf/simplification-wrapper.xsl b/conf/simplification-wrapper.xsl > new file mode 100644 > index 0000000..c2b820a > --- /dev/null > +++ b/conf/simplification-wrapper.xsl > @@ -0,0 +1,25 @@ > +<?xml version="1.0" encoding="utf-8"?> > +<xsl:stylesheet version="1.0" > + xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> > +<xsl:import href="simplification.xsl"/> > + > +<xsl:param name="step" select="'20'"/> > +<xsl:variable name="step_concat" select="concat('step7.', $step)"/> > + > +<xsl:template match="/"> > + <xsl:choose> > + <xsl:when test="$step = '20'"> > + <xsl:apply-templates mode="step7.20"> > + <xsl:with-param name="out" select="0"/> > + <xsl:with-param name="stop-after" select="$step_concat"/> > + </xsl:apply-templates> > + </xsl:when> > + <xsl:otherwise> > + <xsl:message terminate="yes"> > + <xsl:value-of select="concat('Not implemented: ', $step_concat)"/> > + </xsl:message> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +</xsl:stylesheet> > diff --git a/conf/simplification.xsl b/conf/simplification.xsl > new file mode 100644 > index 0000000..1dd0447 > --- /dev/null > +++ b/conf/simplification.xsl > @@ -0,0 +1,1037 @@ > +<?xml version="1.0" encoding="utf-8"?> > +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://relaxng.org/ns/structure/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl" > +exclude-result-prefixes = "exsl rng"> > + > +<xsl:output method="xml"/> > + > +<xsl:param name="out-name">simplified-</xsl:param> > + > +<!-- 7.2 --> > + > +<xsl:template match="/"> > + <xsl:param name="out" select="1"/> > + <xsl:param name="stop-after" select="''"/> > + <xsl:comment>7.2</xsl:comment> > + <xsl:variable name="step"> > + <xsl:apply-templates mode="step7.2"/> > + </xsl:variable> > + <xsl:if test="$out=1"> > + <exsl:document href="{$out-name}7-2.rng" method="xml" indent="no"> > + <xsl:copy-of select="$step"/> > + </exsl:document> > + </xsl:if> > + <xsl:choose> > + <xsl:when test="$stop-after = 'step7.2'"> > + <xsl:copy-of select="$step"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:apply-templates select="exsl:node-set($step)" mode="step7.3"> > + <xsl:with-param name="out" select="$out"/> > + <xsl:with-param name="stop-after" select="$stop-after"/> > + </xsl:apply-templates> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="rng:*|text()|@*[namespace-uri()='']" mode="step7.2"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.2"/> > + <xsl:apply-templates mode="step7.2"/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="*|@*" mode="step7.2"/> > + > +<!-- 7.3 --> > + > +<xsl:template match="/" mode="step7.3"> > + <xsl:param name="out" select="1"/> > + <xsl:param name="stop-after" select="''"/> > + <xsl:comment>7.3</xsl:comment> > + <xsl:variable name="step"> > + <xsl:apply-templates mode="step7.3"/> > + </xsl:variable> > + <xsl:if test="$out=1"> > + <exsl:document href="{$out-name}7-3.rng" method="xml" indent="yes"> > + <xsl:copy-of select="$step"/> > + </exsl:document> > + </xsl:if> > + <xsl:choose> > + <xsl:when test="$stop-after = 'step7.3'"> > + <xsl:copy-of select="$step"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:apply-templates select="exsl:node-set($step)" mode="step7.4"> > + <xsl:with-param name="out" select="$out"/> > + <xsl:with-param name="stop-after" select="$stop-after"/> > + </xsl:apply-templates> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="*|text()|@*" mode="step7.3"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.3"/> > + <xsl:apply-templates mode="step7.3"/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="text()[normalize-space(.)='' and not(parent::rng:param or parent::rng:value)]" mode="step7.3"/> > + > +<xsl:template match="@name|@type|@combine" mode="step7.3"> > + <xsl:attribute name="{name()}"> > + <xsl:value-of select="normalize-space(.)"/> > + </xsl:attribute> > +</xsl:template> > + > +<xsl:template match="rng:name/text()" mode="step7.3"> > + <xsl:value-of select="normalize-space(.)"/> > +</xsl:template> > + > +<!-- 7.4 --> > + > +<xsl:template match="/" mode="step7.4"> > + <xsl:param name="out" select="1"/> > + <xsl:param name="stop-after" select="''"/> > + <xsl:comment>7.4</xsl:comment> > + <xsl:variable name="step"> > + <xsl:apply-templates mode="step7.4"/> > + </xsl:variable> > + <xsl:if test="$out=1"> > + <exsl:document href="{$out-name}7-4.rng" method="xml" indent="yes"> > + <xsl:copy-of select="$step"/> > + </exsl:document> > + </xsl:if> > + <xsl:choose> > + <xsl:when test="$stop-after = 'step7.4'"> > + <xsl:copy-of select="$step"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:apply-templates select="exsl:node-set($step)" mode="step7.5"> > + <xsl:with-param name="out" select="$out"/> > + <xsl:with-param name="stop-after" select="$stop-after"/> > + </xsl:apply-templates> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="*|text()|@*" mode="step7.4"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.4"/> > + <xsl:apply-templates mode="step7.4"/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="@datatypeLibrary" mode="step7.4"/> > + > +<xsl:template match="rng:data|rng:value" mode="step7.4"> > + <xsl:copy> > + <xsl:attribute name="datatypeLibrary"> > + <xsl:value-of select="ancestor-or-self::*[@datatypeLibrary][1]/@datatypeLibrary"/> > + </xsl:attribute> > + <xsl:apply-templates select="@*" mode="step7.4"/> > + <xsl:apply-templates mode="step7.4"/> > + </xsl:copy> > +</xsl:template> > + > +<!-- 7.5 --> > + > +<xsl:template match="/" mode="step7.5"> > + <xsl:param name="out" select="1"/> > + <xsl:param name="stop-after" select="''"/> > + <xsl:comment>7.5</xsl:comment> > + <xsl:variable name="step"> > + <xsl:apply-templates mode="step7.5"/> > + </xsl:variable> > + <xsl:if test="$out=1"> > + <exsl:document href="{$out-name}7-5.rng" method="xml" indent="yes"> > + <xsl:copy-of select="$step"/> > + </exsl:document> > + </xsl:if> > + <xsl:choose> > + <xsl:when test="$stop-after = 'step7.5'"> > + <xsl:copy-of select="$step"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:apply-templates select="exsl:node-set($step)" mode="step7.7"> > + <xsl:with-param name="out" select="$out"/> > + <xsl:with-param name="stop-after" select="$stop-after"/> > + </xsl:apply-templates> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="*|text()|@*" mode="step7.5"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.5"/> > + <xsl:apply-templates mode="step7.5"/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="rng:value[not(@type)]/@datatypeLibrary" mode="step7.5"/> > + > +<xsl:template match="rng:value[not(@type)]" mode="step7.5"> > + <value type="token" datatypeLibrary=""> > + <xsl:apply-templates select="@*" mode="step7.5"/> > + <xsl:apply-templates mode="step7.5"/> > + </value> > +</xsl:template> > + > +<!-- 7.7 --> > + > +<xsl:template match="/" mode="step7.7"> > + <xsl:param name="out" select="1"/> > + <xsl:param name="stop-after" select="''"/> > + <xsl:comment>7.7</xsl:comment> > + <xsl:variable name="step"> > + <xsl:apply-templates mode="step7.7"/> > + </xsl:variable> > + <xsl:if test="$out=1"> > + <exsl:document href="{$out-name}7-7.rng" method="xml" indent="yes"> > + <xsl:copy-of select="$step"/> > + </exsl:document> > + </xsl:if> > + <xsl:choose> > + <xsl:when test="$stop-after = 'step7.7'"> > + <xsl:copy-of select="$step"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:apply-templates select="exsl:node-set($step)" mode="step7.8"> > + <xsl:with-param name="out" select="$out"/> > + <xsl:with-param name="stop-after" select="$stop-after"/> > + </xsl:apply-templates> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="*|text()|@*" mode="step7.7"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.7"/> > + <xsl:apply-templates mode="step7.7"/> > + </xsl:copy> > +</xsl:template> > + > + > +<xsl:template match="rng:externalRef" mode="step7.7"> > + <xsl:variable name="ref-rtf"> > + <xsl:apply-templates select="document(@href)"> > + <xsl:with-param name="out" select="0"/> > + <xsl:with-param name="stop-after" select="'step7.7'"/> > + </xsl:apply-templates> > + </xsl:variable> > + <xsl:variable name="ref" select="exsl:node-set($ref-rtf)"/> > + <xsl:element name="{local-name($ref/*)}" namespace="http://relaxng.org/ns/structure/1.0"> > + <xsl:if test="not($ref/*/@ns) and @ns"> > + <xsl:attribute name="ns"> > + <xsl:value-of select="@ns"/> > + </xsl:attribute> > + </xsl:if> > + <xsl:copy-of select="$ref/*/@*"/> > + <xsl:copy-of select="$ref/*/*|$ref/*/text()"/> > + </xsl:element> > +</xsl:template> > + > +<!-- 7.8 --> > + > +<xsl:template match="/" mode="step7.8"> > + <xsl:param name="out" select="1"/> > + <xsl:param name="stop-after" select="''"/> > + <xsl:comment>7.8</xsl:comment> > + <xsl:variable name="step"> > + <xsl:apply-templates mode="step7.8"/> > + </xsl:variable> > + <xsl:if test="$out=1"> > + <exsl:document href="{$out-name}7-8.rng" method="xml" indent="yes"> > + <xsl:copy-of select="$step"/> > + </exsl:document> > + </xsl:if> > + <xsl:choose> > + <xsl:when test="$stop-after = 'step7.8'"> > + <xsl:copy-of select="$step"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:apply-templates select="exsl:node-set($step)" mode="step7.9"> > + <xsl:with-param name="out" select="$out"/> > + <xsl:with-param name="stop-after" select="$stop-after"/> > + </xsl:apply-templates> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="*|text()|@*" mode="step7.8"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.8"/> > + <xsl:apply-templates mode="step7.8"/> > + </xsl:copy> > +</xsl:template> > + > + > +<xsl:template match="rng:include" mode="step7.8"> > + <xsl:variable name="ref-rtf"> > + <xsl:apply-templates select="document(@href)"> > + <xsl:with-param name="out" select="0"/> > + <xsl:with-param name="stop-after" select="'step7.8'"/> > + </xsl:apply-templates> > + </xsl:variable> > + <xsl:variable name="ref" select="exsl:node-set($ref-rtf)"/> > + <div> > + <xsl:copy-of select="@*[name() != 'href']"/> > + <xsl:copy-of select="*"/> > + <xsl:copy-of select="$ref/rng:grammar/rng:start[not(current()/rng:start)]"/> > + <xsl:copy-of select="$ref/rng:grammar/rng:define[not(@name = current()/rng:define/@name)]"/> > + </div> > +</xsl:template> > + > +<!-- 7.9 --> > + > +<xsl:template match="/" mode="step7.9"> > + <xsl:param name="out" select="1"/> > + <xsl:param name="stop-after" select="''"/> > + <xsl:comment>7.9</xsl:comment> > + <xsl:variable name="step"> > + <xsl:apply-templates mode="step7.9"/> > + </xsl:variable> > + <xsl:if test="$out=1"> > + <exsl:document href="{$out-name}7-9.rng" method="xml" indent="yes"> > + <xsl:copy-of select="$step"/> > + </exsl:document> > + </xsl:if> > + <xsl:choose> > + <xsl:when test="$stop-after = 'step7.9'"> > + <xsl:copy-of select="$step"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:apply-templates select="exsl:node-set($step)" mode="step7.10"> > + <xsl:with-param name="out" select="$out"/> > + <xsl:with-param name="stop-after" select="$stop-after"/> > + </xsl:apply-templates> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="*|text()|@*" mode="step7.9"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.9"/> > + <xsl:apply-templates mode="step7.9"/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="@name[parent::rng:element|parent::rng:attribute]" mode="step7.9"/> > + > +<xsl:template match="rng:element[@name]|rng:attribute[@name]" mode="step7.9"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.9"/> > + <xsl:if test="self::rng:attribute and not(@ns)"> > + <xsl:attribute name="ns"/> > + </xsl:if> > + <name> > + <xsl:value-of select="@name"/> > + </name> > + <xsl:apply-templates mode="step7.9"/> > + </xsl:copy> > +</xsl:template> > + > +<!-- 7.10 --> > + > +<xsl:template match="/" mode="step7.10"> > + <xsl:param name="out" select="1"/> > + <xsl:param name="stop-after" select="''"/> > + <xsl:comment>7.10</xsl:comment> > + <xsl:variable name="step"> > + <xsl:apply-templates mode="step7.10"/> > + </xsl:variable> > + <xsl:if test="$out=1"> > + <exsl:document href="{$out-name}7-10.rng" method="xml" indent="yes"> > + <xsl:copy-of select="$step"/> > + </exsl:document> > + </xsl:if> > + <xsl:choose> > + <xsl:when test="$stop-after = 'step7.10'"> > + <xsl:copy-of select="$step"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:apply-templates select="exsl:node-set($step)" mode="step7.11"> > + <xsl:with-param name="out" select="$out"/> > + <xsl:with-param name="stop-after" select="$stop-after"/> > + </xsl:apply-templates> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="*|text()|@*" mode="step7.10"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.10"/> > + <xsl:apply-templates mode="step7.10"/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="@ns" mode="step7.10"/> > + > +<xsl:template match="rng:name|rng:nsName|rng:value" mode="step7.10"> > + <xsl:copy> > + <xsl:attribute name="ns"> > + <xsl:value-of select="ancestor-or-self::*[@ns][1]/@ns"/> > + </xsl:attribute> > + <xsl:apply-templates select="@*" mode="step7.10"/> > + <xsl:apply-templates mode="step7.10"/> > + </xsl:copy> > +</xsl:template> > + > +<!-- 7.11 --> > + > +<xsl:template match="/" mode="step7.11"> > + <xsl:param name="out" select="1"/> > + <xsl:param name="stop-after" select="''"/> > + <xsl:comment>7.11</xsl:comment> > + <xsl:variable name="step"> > + <xsl:apply-templates mode="step7.11"/> > + </xsl:variable> > + <xsl:if test="$out=1"> > + <exsl:document href="{$out-name}7-11.rng" method="xml" indent="yes"> > + <xsl:copy-of select="$step"/> > + </exsl:document> > + </xsl:if> > + <xsl:choose> > + <xsl:when test="$stop-after = 'step7.11'"> > + <xsl:copy-of select="$step"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:apply-templates select="exsl:node-set($step)" mode="step7.12"> > + <xsl:with-param name="out" select="$out"/> > + <xsl:with-param name="stop-after" select="$stop-after"/> > + </xsl:apply-templates> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="*|text()|@*" mode="step7.11"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.11"/> > + <xsl:apply-templates mode="step7.11"/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="rng:name[contains(., ':')]" mode="step7.11"> > + <xsl:variable name="prefix" select="substring-before(., ':')"/> > + <name> > + <xsl:attribute name="ns"> > + <xsl:for-each select="namespace::*"> > + <xsl:if test="name()=$prefix"> > + <xsl:value-of select="."/> > + </xsl:if> > + </xsl:for-each> > + </xsl:attribute> > + <xsl:value-of select="substring-after(., ':')"/> > + </name> > +</xsl:template> > + > +<!-- 7.12 --> > + > +<xsl:template match="/" mode="step7.12"> > + <xsl:param name="out" select="1"/> > + <xsl:param name="stop-after" select="''"/> > + <xsl:comment>7.12</xsl:comment> > + <xsl:variable name="step"> > + <xsl:apply-templates mode="step7.12"/> > + </xsl:variable> > + <xsl:if test="$out=1"> > + <exsl:document href="{$out-name}7-12.rng" method="xml" indent="yes"> > + <xsl:copy-of select="$step"/> > + </exsl:document> > + </xsl:if> > + <xsl:choose> > + <xsl:when test="$stop-after = 'step7.12'"> > + <xsl:copy-of select="$step"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:apply-templates select="exsl:node-set($step)" mode="step7.13"> > + <xsl:with-param name="out" select="$out"/> > + <xsl:with-param name="stop-after" select="$stop-after"/> > + </xsl:apply-templates> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="*|text()|@*" mode="step7.12"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.12"/> > + <xsl:apply-templates mode="step7.12"/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="rng:div" mode="step7.12"> > + <xsl:apply-templates mode="step7.12"/> > +</xsl:template> > + > +<!-- 7.13 --> > + > +<xsl:template match="/" mode="step7.13"> > + <xsl:param name="out" select="1"/> > + <xsl:param name="stop-after" select="''"/> > + <xsl:comment>7.13</xsl:comment> > + <xsl:variable name="step"> > + <xsl:apply-templates mode="step7.13"/> > + </xsl:variable> > + <xsl:if test="$out=1"> > + <exsl:document href="{$out-name}7-13.rng" method="xml" indent="yes"> > + <xsl:copy-of select="$step"/> > + </exsl:document> > + </xsl:if> > + <xsl:choose> > + <xsl:when test="$stop-after = 'step7.13'"> > + <xsl:copy-of select="$step"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:apply-templates select="exsl:node-set($step)" mode="step7.14"> > + <xsl:with-param name="out" select="$out"/> > + <xsl:with-param name="stop-after" select="$stop-after"/> > + </xsl:apply-templates> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="*|text()|@*" mode="step7.13"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.13"/> > + <xsl:apply-templates mode="step7.13"/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="rng:define[count(*)>1]|rng:oneOrMore[count(*)>1]|rng:zeroOrMore[count(*)>1]|rng:optional[count(*)>1]|rng:list[count(*)>1]|rng:mixed[count(*)>1]" mode="step7.13"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.13"/> > + <xsl:call-template name="reduce7.13"> > + <xsl:with-param name="node-name" select="'group'"/> > + </xsl:call-template> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="rng:except[count(*)>1]" mode="step7.13"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.13"/> > + <xsl:call-template name="reduce7.13"> > + <xsl:with-param name="node-name" select="'choice'"/> > + </xsl:call-template> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="rng:attribute[count(*) =1]" mode="step7.13"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.13"/> > + <xsl:apply-templates select="*" mode="step7.13"/> > + <text/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="rng:element[count(*)>2]" mode="step7.13"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.13"/> > + <xsl:apply-templates select="*[1]" mode="step7.13"/> > + <xsl:call-template name="reduce7.13"> > + <xsl:with-param name="left" select="*[4]"/> > + <xsl:with-param name="node-name" select="'group'"/> > + <xsl:with-param name="out"> > + <group> > + <xsl:apply-templates select="*[2]" mode="step7.13"/> > + <xsl:apply-templates select="*[3]" mode="step7.13"/> > + </group> > + </xsl:with-param> > + </xsl:call-template> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="rng:group[count(*)=1]|rng:choice[count(*)=1]|rng:interleave[count(*)=1]" mode="step7.13"> > + <xsl:apply-templates select="*" mode="step7.13"/> > +</xsl:template> > + > +<xsl:template match="rng:group[count(*)>2]|rng:choice[count(*)>2]|rng:interleave[count(*)>2]" mode="step7.13" name="reduce7.13"> > + <xsl:param name="left" select="*[3]"/> > + <xsl:param name="node-name" select="name()"/> > + <xsl:param name="out"> > + <xsl:element name="{$node-name}"> > + <xsl:apply-templates select="*[1]" mode="step7.13"/> > + <xsl:apply-templates select="*[2]" mode="step7.13"/> > + </xsl:element> > + </xsl:param> > + <xsl:choose> > + <xsl:when test="$left"> > + <xsl:variable name="newOut"> > + <xsl:element name="{$node-name}"> > + <xsl:copy-of select="$out"/> > + <xsl:apply-templates select="$left" mode="step7.13"/> > + </xsl:element> > + </xsl:variable> > + <xsl:call-template name="reduce7.13"> > + <xsl:with-param name="left" select="$left/following-sibling::*[1]"/> > + <xsl:with-param name="out" select="$newOut"/> > + <xsl:with-param name="node-name" select="$node-name"/> > + </xsl:call-template> > + </xsl:when> > + <xsl:otherwise> > + <xsl:copy-of select="$out"/> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<!-- 7.14 --> > + > +<xsl:template match="/" mode="step7.14"> > + <xsl:param name="out" select="1"/> > + <xsl:param name="stop-after" select="''"/> > + <xsl:comment>7.14</xsl:comment> > + <xsl:variable name="step"> > + <xsl:apply-templates mode="step7.14"/> > + </xsl:variable> > + <xsl:if test="$out=1"> > + <exsl:document href="{$out-name}7-14.rng" method="xml" indent="yes"> > + <xsl:copy-of select="$step"/> > + </exsl:document> > + </xsl:if> > + <xsl:choose> > + <xsl:when test="$stop-after = 'step7.14'"> > + <xsl:copy-of select="$step"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:apply-templates select="exsl:node-set($step)" mode="step7.15"> > + <xsl:with-param name="out" select="$out"/> > + <xsl:with-param name="stop-after" select="$stop-after"/> > + </xsl:apply-templates> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="*|text()|@*" mode="step7.14"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.14"/> > + <xsl:apply-templates mode="step7.14"/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="rng:mixed" mode="step7.14"> > + <interleave> > + <xsl:apply-templates mode="step7.14"/> > + <text/> > + </interleave> > +</xsl:template> > + > +<!-- 7.15 --> > + > +<xsl:template match="/" mode="step7.15"> > + <xsl:param name="out" select="1"/> > + <xsl:param name="stop-after" select="''"/> > + <xsl:comment>7.15</xsl:comment> > + <xsl:variable name="step"> > + <xsl:apply-templates mode="step7.15"/> > + </xsl:variable> > + <xsl:if test="$out=1"> > + <exsl:document href="{$out-name}7-15.rng" method="xml" indent="yes"> > + <xsl:copy-of select="$step"/> > + </exsl:document> > + </xsl:if> > + <xsl:choose> > + <xsl:when test="$stop-after = 'step7.15'"> > + <xsl:copy-of select="$step"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:apply-templates select="exsl:node-set($step)" mode="step7.16"> > + <xsl:with-param name="out" select="$out"/> > + <xsl:with-param name="stop-after" select="$stop-after"/> > + </xsl:apply-templates> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="*|text()|@*" mode="step7.15"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.15"/> > + <xsl:apply-templates mode="step7.15"/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="rng:optional" mode="step7.15"> > + <choice> > + <xsl:apply-templates mode="step7.15"/> > + <empty/> > + </choice> > +</xsl:template> > + > +<!-- 7.16 --> > + > +<xsl:template match="/" mode="step7.16"> > + <xsl:param name="out" select="1"/> > + <xsl:param name="stop-after" select="''"/> > + <xsl:comment>7.16</xsl:comment> > + <xsl:variable name="step"> > + <xsl:apply-templates mode="step7.16"/> > + </xsl:variable> > + <xsl:if test="$out=1"> > + <exsl:document href="{$out-name}7-16.rng" method="xml" indent="yes"> > + <xsl:copy-of select="$step"/> > + </exsl:document> > + </xsl:if> > + <xsl:choose> > + <xsl:when test="$stop-after = 'step7.16'"> > + <xsl:copy-of select="$step"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:apply-templates select="exsl:node-set($step)" mode="step7.18"> > + <xsl:with-param name="out" select="$out"/> > + <xsl:with-param name="stop-after" select="$stop-after"/> > + </xsl:apply-templates> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="*|text()|@*" mode="step7.16"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.16"/> > + <xsl:apply-templates mode="step7.16"/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="rng:zeroOrMore" mode="step7.16"> > + <choice> > + <oneOrMore> > + <xsl:apply-templates mode="step7.16"/> > + </oneOrMore> > + <empty/> > + </choice> > +</xsl:template> > + > +<!-- 7.18 --> > + > +<xsl:template match="/" mode="step7.18"> > + <xsl:param name="out" select="1"/> > + <xsl:param name="stop-after" select="''"/> > + <xsl:comment>7.18</xsl:comment> > + <xsl:variable name="step"> > + <xsl:apply-templates mode="step7.18"/> > + </xsl:variable> > + <xsl:if test="$out=1"> > + <exsl:document href="{$out-name}7-18.rng" method="xml" indent="yes"> > + <xsl:copy-of select="$step"/> > + </exsl:document> > + </xsl:if> > + <xsl:choose> > + <xsl:when test="$stop-after = 'step7.18'"> > + <xsl:copy-of select="$step"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:apply-templates select="exsl:node-set($step)" mode="step7.19"> > + <xsl:with-param name="out" select="$out"/> > + <xsl:with-param name="stop-after" select="$stop-after"/> > + </xsl:apply-templates> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="*|text()|@*" mode="step7.18"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.18"/> > + <xsl:apply-templates mode="step7.18"/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="@combine" mode="step7.18"/> > +<xsl:template match="rng:start[preceding-sibling::rng:start]|rng:define[@name=preceding-sibling::rng:define/@name]" mode="step7.18"/> > + > +<xsl:template match="rng:start[not(preceding-sibling::rng:start) and following-sibling::rng:start]" mode="step7.18"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.18"/> > + <xsl:element name="{parent::*/rng:start/@combine}"> > + <xsl:call-template name="start7.18"/> > + </xsl:element> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template name="start7.18"> > + <xsl:param name="left" select="following-sibling::rng:start[2]"/> > + <xsl:param name="node-name" select="parent::*/rng:start/@combine"/> > + <xsl:param name="out"> > + <xsl:element name="{$node-name}"> > + <xsl:apply-templates select="*" mode="step7.18"/> > + <xsl:apply-templates select="following-sibling::rng:start[1]/*" mode="step7.18"/> > + </xsl:element> > + </xsl:param> > + <xsl:choose> > + <xsl:when test="$left/*"> > + <xsl:variable name="newOut"> > + <xsl:element name="{$node-name}"> > + <xsl:copy-of select="$out"/> > + <xsl:apply-templates select="$left/*" mode="step7.18"/> > + </xsl:element> > + </xsl:variable> > + <xsl:call-template name="start7.18"> > + <xsl:with-param name="left" select="$left/following-sibling::rng:start[1]"/> > + <xsl:with-param name="node-name" select="$node-name"/> > + <xsl:with-param name="out" select="$newOut"/> > + </xsl:call-template> > + </xsl:when> > + <xsl:otherwise> > + <xsl:copy-of select="$out"/> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="rng:define[not(@name=preceding-sibling::rng:define/@name) and @name=following-sibling::rng:define/@name]" mode="step7.18"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.18"/> > + <xsl:call-template name="define7.18"/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template name="define7.18"> > + <xsl:param name="left" select="following-sibling::rng:define[@name=current()/@name][2]"/> > + <xsl:param name="node-name" select="parent::*/rng:define[@name=current()/@name]/@combine"/> > + <xsl:param name="out"> > + <xsl:element name="{$node-name}"> > + <xsl:apply-templates select="*" mode="step7.18"/> > + <xsl:apply-templates select="following-sibling::rng:define[@name=current()/@name][1]/*" mode="step7.18"/> > + </xsl:element> > + </xsl:param> > + <xsl:choose> > + <xsl:when test="$left/*"> > + <xsl:variable name="newOut"> > + <xsl:element name="{$node-name}"> > + <xsl:copy-of select="$out"/> > + <xsl:apply-templates select="$left/*" mode="step7.18"/> > + </xsl:element> > + </xsl:variable> > + <xsl:call-template name="define7.18"> > + <xsl:with-param name="left" select="$left/following-sibling::rng:define[@name=current()/@name][1]"/> > + <xsl:with-param name="node-name" select="$node-name"/> > + <xsl:with-param name="out" select="$newOut"/> > + </xsl:call-template> > + </xsl:when> > + <xsl:otherwise> > + <xsl:copy-of select="$out"/> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<!-- 7.19 --> > + > +<xsl:template match="/" mode="step7.19"> > + <xsl:param name="out" select="1"/> > + <xsl:param name="stop-after" select="''"/> > + <xsl:comment>7.19</xsl:comment> > + <xsl:variable name="step"> > + <xsl:apply-templates mode="step7.19"/> > + </xsl:variable> > + <xsl:if test="$out=1"> > + <exsl:document href="{$out-name}7-19.rng" method="xml" indent="yes"> > + <xsl:copy-of select="$step"/> > + </exsl:document> > + </xsl:if> > + <xsl:choose> > + <xsl:when test="$stop-after = 'step7.19'"> > + <xsl:copy-of select="$step"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:apply-templates select="exsl:node-set($step)" mode="step7.20"> > + <xsl:with-param name="out" select="$out"/> > + <xsl:with-param name="stop-after" select="$stop-after"/> > + </xsl:apply-templates> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="*|text()|@*" mode="step7.19"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.19"/> > + <xsl:apply-templates mode="step7.19"/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="/rng:grammar" mode="step7.19"> > + <grammar> > + <xsl:apply-templates mode="step7.19"/> > + <xsl:apply-templates select="//rng:define" mode="step7.19-define"/> > + </grammar> > +</xsl:template> > + > +<xsl:template match="/*" mode="step7.19"> > + <grammar> > + <start> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.19"/> > + <xsl:apply-templates mode="step7.19"/> > + </xsl:copy> > + </start> > + </grammar> > +</xsl:template> > + > +<xsl:template match="rng:define|rng:define/@name|rng:ref/@name" mode="step7.19"/> > + > +<xsl:template match="rng:define" mode="step7.19-define"> > + <xsl:copy> > + <xsl:attribute name="name"> > + <xsl:value-of select="concat(@name, '-', generate-id())"/> > + </xsl:attribute> > + <xsl:apply-templates select="@*" mode="step7.19"/> > + <xsl:apply-templates mode="step7.19"/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="rng:grammar" mode="step7.19"> > + <xsl:apply-templates select="rng:start/*" mode="step7.19"/> > +</xsl:template> > + > +<xsl:template match="rng:ref" mode="step7.19"> > + <xsl:copy> > + <xsl:attribute name="name"> > + <xsl:value-of select="concat(@name, '-', generate-id(ancestor::rng:grammar[1]/rng:define[@name=current()/@name]))"/> > + </xsl:attribute> > + <xsl:apply-templates select="@*" mode="step7.19"/> > + <xsl:apply-templates mode="step7.19"/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="rng:parentRef" mode="step7.19"> > + <ref> > + <xsl:attribute name="name"> > + <xsl:value-of select="concat(@name, '-', generate-id(ancestor::rng:grammar[2]/rng:define[@name=current()/@name]))"/> > + </xsl:attribute> > + <xsl:apply-templates select="@*" mode="step7.19"/> > + <xsl:apply-templates mode="step7.19"/> > + </ref> > +</xsl:template> > + > +<!-- 7.20 --> > + > +<xsl:template match="/" mode="step7.20"> > + <xsl:param name="out" select="1"/> > + <xsl:param name="stop-after" select="''"/> > + <xsl:comment>7.20</xsl:comment> > + <xsl:variable name="step"> > + <xsl:apply-templates mode="step7.20"/> > + </xsl:variable> > + <xsl:if test="$out=1"> > + <exsl:document href="{$out-name}7-20.rng" method="xml" indent="yes"> > + <xsl:copy-of select="$step"/> > + </exsl:document> > + </xsl:if> > + <xsl:choose> > + <xsl:when test="$stop-after = 'step7.20'"> > + <xsl:copy-of select="$step"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:apply-templates select="exsl:node-set($step)" mode="step7.22"> > + <xsl:with-param name="out" select="$out"/> > + <xsl:with-param name="stop-after" select="$stop-after"/> > + </xsl:apply-templates> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="*|text()|@*" mode="step7.20"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.20"/> > + <xsl:apply-templates mode="step7.20"/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="/rng:grammar" mode="step7.20"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.20"/> > + <xsl:apply-templates mode="step7.20"/> > + <xsl:apply-templates select="//rng:element[not(parent::rng:define)]" mode="step7.20-define"/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="rng:element" mode="step7.20-define"> > + <define name="__{rng:name}-elt-{generate-id()}"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.20"/> > + <xsl:apply-templates mode="step7.20"/> > + </xsl:copy> > + </define> > +</xsl:template> > + > +<xsl:template match="rng:element[not(parent::rng:define)]" mode="step7.20"> > + <ref name="__{rng:name}-elt-{generate-id()}"/> > +</xsl:template> > + > +<xsl:template match="rng:define[not(rng:element)]" mode="step7.20"/> > + > +<xsl:template match="rng:ref[@name=/*/rng:define[not(rng:element)]/@name]" mode="step7.20"> > + <xsl:apply-templates select="/*/rng:define[@name=current()/@name]/*" mode="step7.20"/> > +</xsl:template> > + > +<!-- 7.22 --> > + > +<xsl:template match="/" mode="step7.22"> > + <xsl:param name="out" select="1"/> > + <xsl:param name="stop-after" select="''"/> > + <xsl:comment>7.22</xsl:comment> > + <xsl:variable name="step"> > + <xsl:apply-templates mode="step7.22"/> > + </xsl:variable> > + <xsl:if test="$out=1"> > + <exsl:document href="{$out-name}7-22.rng" method="xml" indent="yes"> > + <xsl:copy-of select="$step"/> > + </exsl:document> > + </xsl:if> > + <xsl:choose> > + <xsl:when test="$stop-after = 'step7.22'"> > + <xsl:copy-of select="$step"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:apply-templates select="exsl:node-set($step)" mode="step7.23"> > + <xsl:with-param name="out" select="$out"/> > + <xsl:with-param name="stop-after" select="$stop-after"/> > + </xsl:apply-templates> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="*|text()|@*" mode="step7.22"> > + <xsl:param name="updated" select="0"/> > + <xsl:copy> > + <xsl:if test="$updated != 0"> > + <xsl:attribute name="updated"><xsl:value-of select="$updated"/></xsl:attribute> > + </xsl:if> > + <xsl:apply-templates select="@*" mode="step7.22"/> > + <xsl:apply-templates mode="step7.22"/> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="@updated" mode="step7.22"/> > + > +<xsl:template match="/rng:grammar" mode="step7.22"> > + <xsl:variable name="thisIteration-rtf"> > + <xsl:copy> > + <xsl:apply-templates select="@*" mode="step7.22"/> > + <xsl:apply-templates mode="step7.22"/> > + </xsl:copy> > + </xsl:variable> > + <xsl:variable name="thisIteration" select="exsl:node-set($thisIteration-rtf)"/> > + <xsl:choose> > + <xsl:when test="$thisIteration//@updated"> > + <xsl:apply-templates select="$thisIteration/rng:grammar" mode="step7.22"/> > + </xsl:when> > + <xsl:otherwise> > + <xsl:copy-of select="$thisIteration-rtf"/> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +<xsl:template match="rng:choice[*[1][not(self::rng:empty)] and *[2][self::rng:empty]]" mode="step7.22"> > + <xsl:copy> > + <xsl:attribute name="updated">1</xsl:attribute> > + <xsl:apply-templates select="*[2]" mode="step7.22" /> > + <xsl:apply-templates select="*[1]" mode="step7.22" /> > + </xsl:copy> > +</xsl:template> > + > +<xsl:template match="rng:group[count(rng:empty)=1]|rng:interleave[count(rng:empty)=1]" mode="step7.22"> > + <xsl:apply-templates select="*[not(self::rng:empty)]" mode="step7.22"> > + <xsl:with-param name="updated" select="1"/> > + </xsl:apply-templates> > +</xsl:template> > + > +<xsl:template match="rng:group[count(rng:empty)=2]|rng:interleave[count(rng:empty)=2]|rng:choice[count(rng:empty)=2]|rng:oneOrMore[rng:empty]" mode="step7.22"> > + <rng:empty updated="1"/> > +</xsl:template> > + > +</xsl:stylesheet> > diff --git a/conf/xsddatatypes2lens.xsl b/conf/xsddatatypes2lens.xsl > new file mode 100644 > index 0000000..88ae304 > --- /dev/null > +++ b/conf/xsddatatypes2lens.xsl > @@ -0,0 +1,144 @@ > +<?xml version="1.0" encoding="utf-8"?> > +<xsl:stylesheet version="1.0" > + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> > + > +<!-- > + Copyright 2013 Red Hat, Inc. > + All rights reserved. > + > + Redistribution and use in source and binary forms, with or without > + modification, are permitted provided that the following conditions are met: > + > + - Redistributions of source code must retain the above copyright notice, > + this list of conditions and the following disclaimer. > + - Redistributions in binary form must reproduce the above copyright notice, > + this list of conditions and the following disclaimer in the documentation > + and/or other materials provided with the distribution. > + - Neither the name of the Red Hat, Inc. nor the names of its > + contributors may be used to endorse or promote products derived from this > + software without specific prior written permission. > + > + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" > + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE > + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF > + THE POSSIBILITY OF SUCH DAMAGE. > +--> > + > +<!-- xsltdoc (http://www.kanzaki.com/parts/xsltdoc.xsl) header --> > +<xsl:template name="_doas_description"> > + <rdf:RDF xmlns="http://purl.org/net/ns/doas#"> > + <rdf:Description rdf:about=""> > + <title>xsddatatypes2lens.xsl XSLT stylesheet</title> > + <description> > + This stylesheet contains a helper function-like template > + xsddatatype2lens. > + </description> > + <author rdf:parseType="Resource"> > + <name>Jan Pokorný</name> > + <mbox rdf:resource="jpokorny@xxxxxxxxxx"/> > + </author> > + <created>2013-02-01</created> > + <release rdf:parseType="Resource"> > + <revision>0.2</revision> > + <created>2013-02-04</created> > + </release> > + <rights>Copyright 2013 Red Hat, Inc.</rights> > + <license rdf:resource="http://opensource.org/licenses/BSD-3-Clause"/> > + <!-- acknowledgement> > + XY added mapping for A and B. > + </acknowledgement --> > + </rdf:Description> > + </rdf:RDF> > +</xsl:template> > + > +<xsl:template name="xsddatatype2lens"> > + <!--** Maps some XSD datatypes to respective primitives in Augeas lenses. > + > + Note that there is a simple support for backward compatibility > + through the compat-date parameter that, when explicitly set > + as suitable (YYYYMMDD format), will (usually) bring more > + fine-grained view for some datatypes. > + --> > + <xsl:param name="type"/> > + <xsl:param name="compat-date" select="0"/> > + <xsl:choose> > + <!-- > + 3.3 Primitive Datatypes > + --> > + <!-- TODO: string --> > + <!-- TODO: boolean --> > + <xsl:when test="$type = 'decimal'">Rx.reldecimal</xsl:when> > + <xsl:when test="$type = 'float'">Rx.reldecimal</xsl:when> > + <xsl:when test="$type = 'double'">Rx.reldecimal</xsl:when> > + <!-- TODO: duration --> > + <!-- TODO: dateTime --> > + <!-- TODO: time --> > + <!-- TODO: date --> > + <!-- TODO: gYearMonth --> > + <!-- TODO: gYear --> > + <!-- TODO: gMonthDay --> > + <!-- TODO: gDay --> > + <!-- TODO: gMonth --> > + <xsl:when test="$type = 'hexBinary'">Rx.hex</xsl:when> > + <!-- TODO: base64Binary --> > + <!-- TODO: anyURI --> > + <!-- TODO: QName --> > + <!-- TODO: NOTATION --> > + <!-- > + 3.4 Other Built-in Datatypes > + --> > + <!-- TODO: normalizedString --> > + <!-- TODO: token --> > + <!-- TODO: language --> > + <xsl:when test="$type = 'NMTOKEN'">Xml.nmtoken</xsl:when> > + <!-- TODO: NMTOKENS --> > + <!-- TODO: Name --> > + <!-- TODO: NCName --> > + <!-- TODO: ID --> > + <!-- TODO: IDREF --> > + <!-- TODO: IDREFS --> > + <!-- TODO: ENTITY --> > + <!-- TODO: ENTITIES --> > + <xsl:when test="$type = 'integer'">Rx.relinteger</xsl:when> > + <xsl:when test="$type = 'nonPositiveInteger'">Rx.relinteger</xsl:when> > + <xsl:when test="$type = 'negativeInteger'">Rx.relinteger</xsl:when> > + <xsl:when test="$type = 'long'">Rx.relinteger</xsl:when> > + <xsl:when test="$type = 'int'">Rx.relinteger</xsl:when> > + <xsl:when test="$type = 'short'">Rx.relinteger</xsl:when> > + <xsl:when test="$type = 'byte'">Rx.relinteger</xsl:when> > + <xsl:when test="$type = 'nonNegativeInteger'">Rx.integer</xsl:when> > + <xsl:when test="$type = 'unsignedLong'">Rx.integer</xsl:when> > + <xsl:when test="$type = 'unsignedInt'">Rx.integer</xsl:when> > + <xsl:when test="$type = 'unsignedShort'">Rx.integer</xsl:when> > + <xsl:when test="$type = 'unsignedByte'"> > + <xsl:choose> > + <xsl:when test="$compat-date >= 20130103"> > + <xsl:text>Rx.byte</xsl:text> > + </xsl:when> > + <xsl:otherwise> > + <xsl:text>Rx.integer</xsl:text> > + </xsl:otherwise> > + </xsl:choose> > + </xsl:when> > + <xsl:when test="$type = 'positiveInteger'">Rx.integer</xsl:when> > + <!-- TODO: yearMonthDuration --> > + <!-- TODO: dayTimeDuration --> > + <!-- TODO: dateTimeStamp --> > + <xsl:otherwise> > + <xsl:message> > + <xsl:value-of select="concat('Unhandled XML datatype: ', $type)"/> > + </xsl:message> > + </xsl:otherwise> > + </xsl:choose> > +</xsl:template> > + > +</xsl:stylesheet> > +<!-- vim: set et ts=4 sw=4: --> > diff --git a/configure.ac b/configure.ac > index 5346279..bb79a76 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -95,6 +95,11 @@ AC_CHECK_PROGS([DOT], [dot]) > AC_CHECK_PROGS([DOXYGEN], [doxygen]) > AC_CHECK_PROGS([AWK], [awk]) > AC_CHECK_PROGS([SED], [sed]) > +# these are for generated corosync.conf.5 and corosync.aug > +AC_CHECK_PROGS([XSLTPROC], [xsltproc]) > +AC_CHECK_PROGS([ASCIIDOC], [asciidoc]) > +AC_CHECK_PROGS([PYTHON], [python]) > + > AC_PATH_PROG([BASHPATH], [bash]) > > # Checks for compiler characteristics. > diff --git a/man/.gitignore b/man/.gitignore > index 0315fcd..531c10e 100644 > --- a/man/.gitignore > +++ b/man/.gitignore > @@ -1,2 +1,3 @@ > *.html > *.3 > +/corosync.conf.5 > diff --git a/man/Makefile.am b/man/Makefile.am > index 9824524..c179859 100644 > --- a/man/Makefile.am > +++ b/man/Makefile.am > @@ -1,5 +1,5 @@ > # Copyright (c) 2004 MontaVista Software, Inc. > -# Copyright (c) 2009, 2012 Red Hat, Inc. > +# Copyright (c) 2013 Red Hat, Inc. > # > # Authors: Steven Dake (sdake@xxxxxxxxxx) > # Fabio M. Di Nitto (fdinitto@xxxxxxxxxx) > @@ -39,7 +39,8 @@ xml_man = corosync-xmlproc.8 \ > > INDEX_HTML = index.html > > -autogen_man = cpg_context_get.3 \ > +autogen_man = corosync.conf.5 \ > + cpg_context_get.3 \ > cpg_context_set.3 \ > cpg_dispatch.3 \ > cpg_fd_get.3 \ > @@ -115,8 +116,7 @@ EXTRA_DIST = $(INDEX_HTML) \ > > man_MANS = $(autogen_man) > > -dist_man_MANS = corosync.conf.5 \ > - votequorum.5 \ > +dist_man_MANS = votequorum.5 \ > corosync.8 \ > corosync-cmapctl.8 \ > corosync-blackbox.8 \ > @@ -139,6 +139,18 @@ endif > > HTML_DOCS = $(dist_man_MANS:%=%.html) $(man_MANS:%=%.html) > > +DOCBOOK_XSL_MAN = /etc/asciidoc/docbook-xsl/manpage.xsl > +DOCBOOK_XSL_XHTML = /etc/asciidoc/docbook-xsl/xhtml.xsl > +# verbatim from a2x > +DOCBOOK_XSLT_OPTS = --stringparam callout.graphics 0 \ > + --stringparam navig.graphics 0 \ > + --stringparam admon.textlabel 1 \ > + --stringparam admon.graphics 0 \ > + --nonet > +# we need more space for topcenter text > +DOCBOOK_XSLT_OPTS += --param man.th.extra3.max.length 52 > + > + > # developer man page generation > %.3: %.3.in $(autogen_common) > @echo Generating $@ man page && \ > @@ -154,6 +166,17 @@ HTML_DOCS = $(dist_man_MANS:%=%.html) $(man_MANS:%=%.html) > rm -f $@-t-t && \ > mv $@-t $@ > > +# corosync.conf.5{,.html} > +corosync.conf.5: > + @echo Generating $@ man page && \ > + $(MAKE) $(AM_MAKEFLAGS) -C ../conf $(@:.5=.xml) && \ > + $(XSLTPROC) $(DOCBOOK_XSLT_OPTS) $(DOCBOOK_XSL_MAN) ../conf/$(@:.5=.xml) > + > +corosync.conf.5.html: > + @echo Generating $@ HTMLized man page && \ > + $(MAKE) $(AM_MAKEFLAGS) -C ../conf $(@:.5.html=.xml) && \ > + $(XSLTPROC) $(DOCBOOK_XSLT_OPTS) $(DOCBOOK_XSL_XHTML) ../conf/$(@:.5.html=.xml) > $@ > + > clean-local: > rm -rf $(HTML_DOCS) $(autogen_man) > > diff --git a/man/corosync.conf.5 b/man/corosync.conf.5 > deleted file mode 100644 > index 9da9dbb..0000000 > --- a/man/corosync.conf.5 > +++ /dev/null > @@ -1,684 +0,0 @@ > -.\"/* > -.\" * Copyright (c) 2005 MontaVista Software, Inc. > -.\" * Copyright (c) 2006-2012 Red Hat, Inc. > -.\" * > -.\" * All rights reserved. > -.\" * > -.\" * Author: Steven Dake (sdake@xxxxxxxxxx) > -.\" * > -.\" * This software licensed under BSD license, the text of which follows: > -.\" * > -.\" * Redistribution and use in source and binary forms, with or without > -.\" * modification, are permitted provided that the following conditions are met: > -.\" * > -.\" * - Redistributions of source code must retain the above copyright notice, > -.\" * this list of conditions and the following disclaimer. > -.\" * - Redistributions in binary form must reproduce the above copyright notice, > -.\" * this list of conditions and the following disclaimer in the documentation > -.\" * and/or other materials provided with the distribution. > -.\" * - Neither the name of the MontaVista Software, Inc. nor the names of its > -.\" * contributors may be used to endorse or promote products derived from this > -.\" * software without specific prior written permission. > -.\" * > -.\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" > -.\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > -.\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > -.\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE > -.\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > -.\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > -.\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > -.\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > -.\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > -.\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF > -.\" * THE POSSIBILITY OF SUCH DAMAGE. > -.\" */ > -.TH COROSYNC_CONF 5 2012-10-10 "corosync Man Page" "Corosync Cluster Engine Programmer's Manual" > -.SH NAME > -corosync.conf - corosync executive configuration file > - > -.SH SYNOPSIS > -/etc/corosync/corosync.conf > - > -.SH DESCRIPTION > -The corosync.conf instructs the corosync executive about various parameters > -needed to control the corosync executive. Empty lines and lines starting with > -# character are ignored. The configuration file consists of bracketed top level > -directives. The possible directive choices are: > - > -.TP > -totem { } > -This top level directive contains configuration options for the totem protocol. > -.TP > -logging { } > -This top level directive contains configuration options for logging. > -.TP > -quorum { } > -This top level directive contains configuration options for quorum. > -.TP > -nodelist { } > -This top level directive contains configuration options for nodes in cluster. > -.TP > -qb { } > -This top level directive contains configuration options related to libqb. > - > -.PP > -.PP > -Within the > -.B totem > -directive, an interface directive is required. There is also one configuration > -option which is required: > -.PP > -.PP > -Within the > -.B interface > -sub-directive of totem there are four parameters which are required. There is > -one parameter which is optional. > - > -.TP > -ringnumber > -This specifies the ring number for the interface. When using the redundant > -ring protocol, each interface should specify separate ring numbers to uniquely > -identify to the membership protocol which interface to use for which redundant > -ring. The ringnumber must start at 0. > - > -.TP > -bindnetaddr > -This specifies the network address the corosync executive should bind > -to. > - > -bindnetaddr should be an IP address configured on the system, or a network > -address. > - > -For example, if the local interface is 192.168.5.92 with netmask > -255.255.255.0, you should set bindnetaddr to 192.168.5.92 or 192.168.5.0. > -If the local interface is 192.168.5.92 with netmask 255.255.255.192, > -set bindnetaddr to 192.168.5.92 or 192.168.5.64, and so forth. > - > -This may also be an IPV6 address, in which case IPV6 networking will be used. > -In this case, the exact address must be specified and there is no automatic > -selection of the network interface within a specific subnet as with IPv4. > - > -If IPv6 networking is used, the nodeid field in nodelist must be specified. > - > -.TP > -broadcast > -This is optional and can be set to yes. If it is set to yes, the broadcast > -address will be used for communication. If this option is set, mcastaddr > -should not be set. > - > -.TP > -mcastaddr > -This is the multicast address used by corosync executive. The default > -should work for most networks, but the network administrator should be queried > -about a multicast address to use. Avoid 224.x.x.x because this is a "config" > -multicast address. > - > -This may also be an IPV6 multicast address, in which case IPV6 networking > -will be used. If IPv6 networking is used, the nodeid field in nodelist must > -be specified. > - > -It's not needed to use this option if cluster_name option is used. If both options > -are used, mcastaddr has higher priority. > - > -.TP > -mcastport > -This specifies the UDP port number. It is possible to use the same multicast > -address on a network with the corosync services configured for different > -UDP ports. > -Please note corosync uses two UDP ports mcastport (for mcast receives) and > -mcastport - 1 (for mcast sends). > -If you have multiple clusters on the same network using the same mcastaddr > -please configure the mcastports with a gap. > - > -.TP > -ttl > -This specifies the Time To Live (TTL). If you run your cluster on a routed > -network then the default of "1" will be too small. This option provides > -a way to increase this up to 255. The valid range is 0..255. > -Note that this is only valid on multicast transport types. > - > -.PP > -.PP > -Within the > -.B totem > -directive, there are seven configuration options of which one is required, > -five are optional, and one is required when IPV6 is configured in the interface > -subdirective. The required directive controls the version of the totem > -configuration. The optional option unless using IPV6 directive controls > -identification of the processor. The optional options control secrecy and > -authentication, the redundant ring mode of operation and maximum network MTU > -field. > - > -.TP > -version > -This specifies the version of the configuration file. Currently the only > -valid version for this directive is 2. > - > -.PP > -clear_node_high_bit > -This configuration option is optional and is only relevant when no nodeid is > -specified. Some corosync clients require a signed 32 bit nodeid that is greater > -than zero however by default corosync uses all 32 bits of the IPv4 address space > -when generating a nodeid. Set this option to yes to force the high bit to be > -zero and therefor ensure the nodeid is a positive signed 32 bit integer. > - > -WARNING: The clusters behavior is undefined if this option is enabled on only > -a subset of the cluster (for example during a rolling upgrade). > - > -.TP > -crypto_hash > -This specifies which HMAC authentication should be used to authenticate all > -messages. Valid values are none (no authentication), md5, sha1, sha256, > -sha384 and sha512. > - > -The default is sha1. > - > -.TP > -crypto_cipher > -This specifies which cipher should be used to encrypt all messages. > -Valid values are none (no encryption), aes256, aes192, aes128 and 3des. > -Enabling crypto_cipher, requires also enabling of crypto_hash. > - > -The default is aes256. > - > -.TP > -secauth > -This specifies that HMAC/SHA1 authentication should be used to authenticate > -all messages. It further specifies that all data should be encrypted with the > -nss library and aes256 encryption algorithm to protect data from eavesdropping. > - > -Enabling this option adds a encryption header to every message sent by totem which > -reduces total throughput. Also encryption and authentication consume extra CPU > -cycles in corosync. > - > -The default is on. > - > -WARNING: This parameter is deprecated. It's recomended to use combination of > -crypto_cipher and crypto_hash. > - > -.TP > -rrp_mode > -This specifies the mode of redundant ring, which may be none, active, or > -passive. Active replication offers slightly lower latency from transmit > -to delivery in faulty network environments but with less performance. > -Passive replication may nearly double the speed of the totem protocol > -if the protocol doesn't become cpu bound. The final option is none, in > -which case only one network interface will be used to operate the totem > -protocol. > - > -If only one interface directive is specified, none is automatically chosen. > -If multiple interface directives are specified, only active or passive may > -be chosen. > - > -The maximum number of interface directives that is allowed for either > -modes (active or passive) is 2. > - > -.TP > -netmtu > -This specifies the network maximum transmit unit. To set this value beyond > -1500, the regular frame MTU, requires ethernet devices that support large, or > -also called jumbo, frames. If any device in the network doesn't support large > -frames, the protocol will not operate properly. The hosts must also have their > -mtu size set from 1500 to whatever frame size is specified here. > - > -Please note while some NICs or switches claim large frame support, they support > -9000 MTU as the maximum frame size including the IP header. Setting the netmtu > -and host MTUs to 9000 will cause totem to use the full 9000 bytes of the frame. > -Then Linux will add a 18 byte header moving the full frame size to 9018. As a > -result some hardware will not operate properly with this size of data. A netmtu > -of 8982 seems to work for the few large frame devices that have been tested. > -Some manufacturers claim large frame support when in fact they support frame > -sizes of 4500 bytes. > - > -When sending multicast traffic, if the network frequently reconfigures, chances are > -that some device in the network doesn't support large frames. > - > -Choose hardware carefully if intending to use large frame support. > - > -The default is 1500. > - > -.TP > -vsftype > -This directive controls the virtual synchrony filter type used to identify > -a primary component. The preferred choice is YKD dynamic linear voting, > -however, for clusters larger then 32 nodes YKD consumes alot of memory. For > -large scale clusters that are created by changing the MAX_PROCESSORS_COUNT > -#define in the C code totem.h file, the virtual synchrony filter "none" is > -recommended but then AMF and DLCK services (which are currently experimental) > -are not safe for use. > - > -The default is ykd. The vsftype can also be set to none. > - > -.TP > -transport > -This directive controls the transport mechanism used. If the interface to > -which corosync is binding is an RDMA interface such as RoCEE or Infiniband, the > -"iba" parameter may be specified. To avoid the use of multicast entirely, a > -unicast transport parameter "udpu" can be specified. This requires specifying > -the list of members in nodelist directive, that could potentially make up > -the membership before deployment. > - > -The default is udp. The transport type can also be set to udpu or iba. > - > -.TP > -cluster_name > -This specifies the name of cluster and it's used for automatic generating > -of multicast address. > - > -.TP > -config_version > -This specifies version of config file. This is converted to unsigned 64-bit int. > -By default it's 0. Option is used to prevent joining old nodes with not > -up-to-date configuration. If value is not 0, and node is going for first time > -(only for first time, join after split doesn't follow this rules) > -from single-node membership to multiple nodes membership, other nodes > -config_versions are collected. If current node config_version is not > -equal to highest of collected versions, corosync is terminated. > - > -.TP > -ip_version > -Specifies version of IP to use for communication. Value can be one of > -ipv4 or ipv6. Default (if unspecified) is ipv4. > - > - > -Within the > -.B totem > -directive, there are several configuration options which are used to control > -the operation of the protocol. It is generally not recommended to change any > -of these values without proper guidance and sufficient testing. Some networks > -may require larger values if suffering from frequent reconfigurations. Some > -applications may require faster failure detection times which can be achieved > -by reducing the token timeout. > - > -.TP > -token > -This timeout specifies in milliseconds until a token loss is declared after not > -receiving a token. This is the time spent detecting a failure of a processor > -in the current configuration. Reforming a new configuration takes about 50 > -milliseconds in addition to this timeout. > - > -The default is 1000 milliseconds. > - > -.TP > -token_retransmit > -This timeout specifies in milliseconds after how long before receiving a token > -the token is retransmitted. This will be automatically calculated if token > -is modified. It is not recommended to alter this value without guidance from > -the corosync community. > - > -The default is 238 milliseconds. > - > -.TP > -hold > -This timeout specifies in milliseconds how long the token should be held by > -the representative when the protocol is under low utilization. It is not > -recommended to alter this value without guidance from the corosync community. > - > -The default is 180 milliseconds. > - > -.TP > -token_retransmits_before_loss_const > -This value identifies how many token retransmits should be attempted before > -forming a new configuration. If this value is set, retransmit and hold will > -be automatically calculated from retransmits_before_loss and token. > - > -The default is 4 retransmissions. > - > -.TP > -join > -This timeout specifies in milliseconds how long to wait for join messages in > -the membership protocol. > - > -The default is 50 milliseconds. > - > -.TP > -send_join > -This timeout specifies in milliseconds an upper range between 0 and send_join > -to wait before sending a join message. For configurations with less then > -32 nodes, this parameter is not necessary. For larger rings, this parameter > -is necessary to ensure the NIC is not overflowed with join messages on > -formation of a new ring. A reasonable value for large rings (128 nodes) would > -be 80msec. Other timer values must also change if this value is changed. Seek > -advice from the corosync mailing list if trying to run larger configurations. > - > -The default is 0 milliseconds. > - > -.TP > -consensus > -This timeout specifies in milliseconds how long to wait for consensus to be > -achieved before starting a new round of membership configuration. The minimum > -value for consensus must be 1.2 * token. This value will be automatically > -calculated at 1.2 * token if the user doesn't specify a consensus value. > - > -For two node clusters, a consensus larger then the join timeout but less then > -token is safe. For three node or larger clusters, consensus should be larger > -then token. There is an increasing risk of odd membership changes, which stil > -guarantee virtual synchrony, as node count grows if consensus is less than > -token. > - > -The default is 1200 milliseconds. > - > -.TP > -merge > -This timeout specifies in milliseconds how long to wait before checking for > -a partition when no multicast traffic is being sent. If multicast traffic > -is being sent, the merge detection happens automatically as a function of > -the protocol. > - > -The default is 200 milliseconds. > - > -.TP > -downcheck > -This timeout specifies in milliseconds how long to wait before checking > -that a network interface is back up after it has been downed. > - > -The default is 1000 millseconds. > - > -.TP > -fail_recv_const > -This constant specifies how many rotations of the token without receiving any > -of the messages when messages should be received may occur before a new > -configuration is formed. > - > -The default is 2500 failures to receive a message. > - > -.TP > -seqno_unchanged_const > -This constant specifies how many rotations of the token without any multicast > -traffic should occur before the hold timer is started. > - > -The default is 30 rotations. > - > -.TP > -heartbeat_failures_allowed > -[HeartBeating mechanism] > -Configures the optional HeartBeating mechanism for faster failure detection. Keep in > -mind that engaging this mechanism in lossy networks could cause faulty loss declaration > -as the mechanism relies on the network for heartbeating. > - > -So as a rule of thumb use this mechanism if you require improved failure in low to > -medium utilized networks. > - > -This constant specifies the number of heartbeat failures the system should tolerate > -before declaring heartbeat failure e.g 3. Also if this value is not set or is 0 then the > -heartbeat mechanism is not engaged in the system and token rotation is the method > -of failure detection > - > -The default is 0 (disabled). > - > -.TP > -max_network_delay > -[HeartBeating mechanism] > -This constant specifies in milliseconds the approximate delay that your network takes > -to transport one packet from one machine to another. This value is to be set by system > -engineers and please dont change if not sure as this effects the failure detection > -mechanism using heartbeat. > - > -The default is 50 milliseconds. > - > -.TP > -window_size > -This constant specifies the maximum number of messages that may be sent on one > -token rotation. If all processors perform equally well, this value could be > -large (300), which would introduce higher latency from origination to delivery > -for very large rings. To reduce latency in large rings(16+), the defaults are > -a safe compromise. If 1 or more slow processor(s) are present among fast > -processors, window_size should be no larger then 256000 / netmtu to avoid > -overflow of the kernel receive buffers. The user is notified of this by > -the display of a retransmit list in the notification logs. There is no loss > -of data, but performance is reduced when these errors occur. > - > -The default is 50 messages. > - > -.TP > -max_messages > -This constant specifies the maximum number of messages that may be sent by one > -processor on receipt of the token. The max_messages parameter is limited to > -256000 / netmtu to prevent overflow of the kernel transmit buffers. > - > -The default is 17 messages. > - > -.TP > -miss_count_const > -This constant defines the maximum number of times on receipt of a token > -a message is checked for retransmission before a retransmission occurs. This > -parameter is useful to modify for switches that delay multicast packets > -compared to unicast packets. The default setting works well for nearly all > -modern switches. > - > -The default is 5 messages. > - > -.TP > -rrp_problem_count_timeout > -This specifies the time in milliseconds to wait before decrementing the > -problem count by 1 for a particular ring to ensure a link is not marked > -faulty for transient network failures. > - > -The default is 2000 milliseconds. > - > -.TP > -rrp_problem_count_threshold > -This specifies the number of times a problem is detected with a link before > -setting the link faulty. Once a link is set faulty, no more data is > -transmitted upon it. Also, the problem counter is no longer decremented when > -the problem count timeout expires. > - > -A problem is detected whenever all tokens from the proceeding processor have > -not been received within the rrp_token_expired_timeout. The > -rrp_problem_count_threshold * rrp_token_expired_timeout should be atleast 50 > -milliseconds less then the token timeout, or a complete reconfiguration > -may occur. > - > -The default is 10 problem counts. > - > -.TP > -rrp_problem_count_mcast_threshold > -This specifies the number of times a problem is detected with multicast before > -setting the link faulty for passive rrp mode. This variable is unused in active > -rrp mode. > - > -The default is 10 times rrp_problem_count_threshold. > - > -.TP > -rrp_token_expired_timeout > -This specifies the time in milliseconds to increment the problem counter for > -the redundant ring protocol after not having received a token from all rings > -for a particular processor. > - > -This value will automatically be calculated from the token timeout and > -problem_count_threshold but may be overridden. It is not recommended to > -override this value without guidance from the corosync community. > - > -The default is 47 milliseconds. > - > -.TP > -rrp_autorecovery_check_timeout > -This specifies the time in milliseconds to check if the failed ring can be > -auto-recovered. > - > -The default is 1000 milliseconds. > - > -.PP > -Within the > -.B logging > -directive, there are several configuration options which are all optional. > - > -.PP > -The following 3 options are valid only for the top level logging directive: > - > -.TP > -timestamp > -This specifies that a timestamp is placed on all log messages. > - > -The default is off. > - > -.TP > -fileline > -This specifies that file and line should be printed. > - > -The default is off. > - > -.TP > -function_name > -This specifies that the code function name should be printed. > - > -The default is off. > - > -.PP > -The following options are valid both for top level logging directive > -and they can be overriden in logger_subsys entries. > - > -.TP > -to_stderr > -.TP > -to_logfile > -.TP > -to_syslog > -These specify the destination of logging output. Any combination of > -these options may be specified. Valid options are > -.B yes > -and > -.B no. > - > -The default is syslog and stderr. > - > -Please note, if you are using to_logfile and want to rotate the file, use logrotate(8) > -with the option > -.B > -copytruncate. > -eg. > -.IP > -.RS > -.ne 18 > -.nf > -.ta 4n 30n 33n > -/var/log/corosync.log { > - missingok > - compress > - notifempty > - daily > - rotate 7 > - copytruncate > -} > -.ta > -.fi > -.RE > -.IP > -.PP > - > - > -.TP > -logfile > -If the > -.B to_logfile > -directive is set to > -.B yes > -, this option specifies the pathname of the log file. > - > -No default. > - > -.TP > -logfile_priority > -This specifies the logfile priority for this particular subsystem. Ignored if debug is on. > -Possible values are: alert, crit, debug (same as debug = on), emerg, err, info, notice, warning. > - > -The default is: info. > - > -.TP > -syslog_facility > -This specifies the syslog facility type that will be used for any messages > -sent to syslog. options are daemon, local0, local1, local2, local3, local4, > -local5, local6 & local7. > - > -The default is daemon. > - > -.TP > -syslog_priority > -This specifies the syslog level for this particular subsystem. Ignored if debug is on. > -Possible values are: alert, crit, debug (same as debug = on), emerg, err, info, notice, warning. > - > -The default is: info. > - > -.TP > -debug > -This specifies whether debug output is logged for this particular logger. Also can contain > -value trace, what is highest level of debug informations. > - > -The default is off. > - > -.PP > -Within the > -.B logging > -directive, logger_subsys directives are optional. > - > -.PP > -Within the > -.B logger_subsys > -sub-directive, all of the above logging configuration options are valid and > -can be used to override the default settings. > -The subsys entry, described below, is mandatory to identify the subsystem. > - > -.TP > -subsys > -This specifies the subsystem identity (name) for which logging is specified. This is the > -name used by a service in the log_init () call. E.g. 'CPG'. This directive is > -required. > - > -.PP > -Within the > -.B quorum > -directive it is possible to specify the quorum algorithm to use with the > - > -.TP > -provider > -directive. At the time of writing only corosync_votequorum is supported. > -See votequorum(5) for configuration options. > - > -.PP > -Within the > -.B nodelist > -directive it is possible to specify specific informations about nodes in cluster. Directive > -can contain only > -.B node > -sub-directive, which specifies every node that should be a member of the membership, and where > -non-default options are needed. Every node must have at least ring0_addr field filled. > - > -For UDPU, every node that should be a member of the membership must be specified. > - > -Possible options are: > -.TP > -ringX_addr > -This specifies ip address of one of the nodes. X is ring number. > - > -.TP > -nodeid > -This configuration option is optional when using IPv4 and required when using > -IPv6. This is a 32 bit value specifying the node identifier delivered to the > -cluster membership service. If this is not specified with IPv4, the node id > -will be determined from the 32 bit IP address the system to which the system > -is bound with ring identifier of 0. The node identifier value of zero is > -reserved and should not be used. > - > -.PP > -Within the > -.B qb > -directive it is possible to specify options for libqb. > - > -Possible option is: > -.TP > -ipc_type > -This specifies type of IPC to use. Can be one of native (default), shm and socket. > -Native means one of shm or socket, depending on what is supported by OS. On systems > -with support for both, SHM is selected. SHM is generally faster, but need to allocate > -ring buffer file in /dev/shm. > - > -.SH "FILES" > -.TP > -/etc/corosync/corosync.conf > -The corosync executive configuration file. > - > -.SH "SEE ALSO" > -.BR corosync_overview (8), > -.BR votequorum (5), > -.BR logrotate (8) > -.PP > _______________________________________________ discuss mailing list discuss@xxxxxxxxxxxx http://lists.corosync.org/mailman/listinfo/discuss