source@mandoc.bsd.lv
 help / color / mirror / Atom feed
* mdocml: `ig' support in all its glory.
@ 2010-05-16 22:28 kristaps
  0 siblings, 0 replies; only message in thread
From: kristaps @ 2010-05-16 22:28 UTC (permalink / raw)
  To: source

Log Message:
-----------
`ig' support in all its glory.  Try

  .ig ig
  asdf
  .ig
  fdsa
  ..

or

  .ig if
  asdf
  .if n \
  foo

for a laugh.  It all works.  Lots of regression tests supporting this
and documentation for the same.

Modified Files:
--------------
    mdocml:
        main.c
        mandoc.h
        roff.7
        roff.c

Added Files:
-----------
    mdocml/regress/roff/if:
        multiline-free0.in
        multiline-free1.in
    mdocml/regress/roff/ig:
        end0.in
        end1.in
        redef0.in
        simple0.in
        simple1.in
        simple2.in

Revision Data
-------------
Index: roff.7
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/roff.7,v
retrieving revision 1.1
retrieving revision 1.2
diff -Lroff.7 -Lroff.7 -u -p -r1.1 -r1.2
--- roff.7
+++ roff.7
@@ -76,6 +76,10 @@ BODY...
 .Ed
 .Bd -literal -offset indent -compact
 \&.if COND \e{ BODY
+BODY... \e}
+.Ed
+.Bd -literal -offset indent -compact
+\&.if COND \e{ BODY
 BODY...
 \&.\e}
 .Ed
@@ -112,15 +116,71 @@ The scope of a conditional is always par
 conditional evaluates to true.
 .Pp
 Note that text subsequent a
+.Sq \&.\e}
+macro is discarded.
+Furthermore, if an explicit closing sequence
 .Sq \e}
-is discarded.
+is specified in a free-form line, the entire line is accepted within the
+scope of the prior macro, not only the text preceding the close.
 .Ss \&ig
-Ignore input until a
-.Sq \.\.
+Ignore input.
+Accepts the following syntax:
+.Pp
+.Bd -literal -offset indent -compact
+\&.ig
+BODY...
+\&..
+.Ed
+.Bd -literal -offset indent -compact
+\&.ig END
+BODY...
+\&.END
+.Ed
+.Pp
+In the first case, input is ignored until a
+.Sq \&..
 macro is encountered on its own line.
-Note that text subsequent the
-.Sq \.\.
+In the second case, input is ignored until a
+.Sq \&.END
+is encountered.
+Text subsequent the
+.Sq \&.END
+or
+.Sq \&..
 is discarded.
+.Pp
+Do not use the escape
+.Sq \e
+anywhere in the definition of END.
+It causes very strange behaviour.
+Furthermore, if you redefine a
+.Nm
+macro, such as
+.Pp
+.D1 \&.ig if
+.Pp
+the subsequent invocation of
+.Sx \&if
+will first signify the end of comment, then be invoked as a macro.
+This behaviour really shouldn't be counted upon.
+.Sh COMPATIBILITY
+This section documents compatibility between mandoc and other other
+troff implementations, at this time limited to GNU troff
+.Pq Qq groff .
+The term
+.Qq historic groff
+refers to groff versions before the
+.Pa doc.tmac
+file re-write
+.Pq somewhere between 1.15 and 1.19 .
+.Pp
+.Bl -dash -compact
+.It
+Historic groff did not accept white-space buffering the custom END tag
+for the
+.Sx \&ig
+macro.
+.El
 .Sh AUTHORS
 The
 .Nm
Index: mandoc.h
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/mandoc.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -Lmandoc.h -Lmandoc.h -u -p -r1.3 -r1.4
--- mandoc.h
+++ mandoc.h
@@ -22,10 +22,10 @@ __BEGIN_DECLS
 enum	mandocerr {
 	MANDOCERR_OK,
 	MANDOCERR_SCOPEEXIT, /* scope open on exit */
-	MANDOCERR_NOSCOPE, /* request scope close w/none open */
-	MANDOCERR_NOARGS, /* macro requires argument(s) */
 #define	MANDOCERR_WARNING	MANDOCERR_SCOPEEXIT
 
+	MANDOCERR_NOSCOPE, /* request scope close w/none open */
+	MANDOCERR_NOARGS, /* macro requires argument(s) */
 	MANDOCERR_ARGSLOST, /* line arguments will be lost */
 #define	MANDOCERR_ERROR		MANDOCERR_ARGSLOST
 
Index: roff.c
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/roff.c,v
retrieving revision 1.77
retrieving revision 1.78
diff -Lroff.c -Lroff.c -u -p -r1.77 -r1.78
--- roff.c
+++ roff.c
@@ -81,24 +81,21 @@ typedef	enum rofferr (*roffproc)(ROFF_AR
 struct	roffmac {
 	const char	*name; /* macro name */
 	roffproc	 proc;
+	roffproc	 text;
 };
 
 static	enum rofferr	 roff_if(ROFF_ARGS);
+static	enum rofferr	 roff_if_text(ROFF_ARGS);
 static	enum rofferr	 roff_ig(ROFF_ARGS);
+static	enum rofferr	 roff_ig_text(ROFF_ARGS);
 static	enum rofferr	 roff_cblock(ROFF_ARGS);
 static	enum rofferr	 roff_ccond(ROFF_ARGS);
 
 const	struct roffmac	 roffs[ROFF_MAX] = {
-	{ "if", roff_if },
-	{ "ig", roff_ig },
-	{ ".", roff_cblock },
-	{ "\\}", roff_ccond },
-#if 0
-	{ "am", roff_sub_ig, roff_new_ig },
-	{ "ami", roff_sub_ig, roff_new_ig },
-	{ "de", roff_sub_ig, roff_new_ig },
-	{ "dei", roff_sub_ig, roff_new_ig },
-#endif
+	{ "if", roff_if, roff_if_text },
+	{ "ig", roff_ig, roff_ig_text },
+	{ ".", roff_cblock, NULL },
+	{ "\\}", roff_ccond, NULL },
 };
 
 static	void		 roff_free1(struct roff *);
@@ -218,28 +215,72 @@ roff_parseln(struct roff *r, int ln, 
 		char **bufp, size_t *szp, int pos, int *offs)
 {
 	enum rofft	 t;
-	int		 ppos;
+	int		 ppos, i, j, wtf;
 
 	if (r->last && ! ROFF_CTL((*bufp)[pos])) {
-		if (ROFF_ig == r->last->tok)
-			return(ROFF_IGN);
-		roffnode_cleanscope(r);
-		/* FIXME: this assumes we're discarding! */
-		return(ROFF_IGN);
+		/*
+		 * If a scope is open and we're not a macro, pass it
+		 * through our text detector and continue as quickly as
+		 * possible.
+		 */
+		t = r->last->tok;
+		assert(roffs[t].text);
+		return((*roffs[t].text)
+				(r, t, bufp, szp, ln, pos, pos, offs));
 	} else if ( ! ROFF_CTL((*bufp)[pos]))
+		/*
+		 * Don't do anything if we're free-form text.
+		 */
 		return(ROFF_CONT);
 
-	/* There's nothing on the stack: make us anew. */
+	/* A macro-ish line with a possibly-open macro context. */
+
+	wtf = 0;
+
+	if (r->last && r->last->end) {
+		/*
+		 * We have a scope open that has a custom end-macro
+		 * handler.  Try to match it against the input.
+		 */
+		i = pos + 1;
+		while (' ' == (*bufp)[i] || '\t' == (*bufp)[i])
+			i++;
+
+		for (j = 0; r->last->end[j]; j++, i++)
+			if ((*bufp)[i] != r->last->end[j])
+				break;
+
+		if ('\0' == r->last->end[j] && 
+				('\0' == (*bufp)[i] ||
+				 ' ' == (*bufp)[i] ||
+				 '\t' == (*bufp)[i])) {
+			roffnode_pop(r);
+			roffnode_cleanscope(r);
+			wtf = 1;
+		}
+	}
 
 	ppos = pos;
 	if (ROFF_MAX == (t = roff_parse(*bufp, &pos))) {
-		if (r->last && ROFF_ig == r->last->tok)
+		/* 
+		 * This is some of groff's stranger behaviours.  If we
+		 * encountered a custom end-scope tag and that tag also
+		 * happens to be a "real" macro, then we need to try
+		 * interpreting it again as a real macro.  If it's not,
+		 * then return ignore.  Else continue.
+		 */
+		if (wtf)
 			return(ROFF_IGN);
-		return(ROFF_CONT);
+		else if (NULL == r->last)
+			return(ROFF_CONT);
+
+		/* FIXME: this assumes that we ignore!? */
+		return(ROFF_IGN);
 	}
 
 	assert(roffs[t].proc);
-	return((*roffs[t].proc)(r, t, bufp, szp, ln, ppos, pos, offs));
+	return((*roffs[t].proc)
+			(r, t, bufp, szp, ln, ppos, pos, offs));
 }
 
 
@@ -375,16 +416,78 @@ roff_ccond(ROFF_ARGS)
 static enum rofferr
 roff_ig(ROFF_ARGS)
 {
+	int		sv;
+	size_t		sz;
 
 	if ( ! roffnode_push(r, tok, ln, ppos))
 		return(ROFF_ERR);
 
-	ROFF_MDEBUG(r, "opening ignore block");
+	if ('\0' == (*bufp)[pos]) {
+		ROFF_MDEBUG(r, "opening ignore block");
+		return(ROFF_IGN);
+	}
+
+	sv = pos;
+	while ((*bufp)[pos] && ' ' != (*bufp)[pos] && 
+			'\t' != (*bufp)[pos])
+		pos++;
+
+	/*
+	 * Note: groff does NOT like escape characters in the input.
+	 * Instead of detecting this, we're just going to let it fly and
+	 * to hell with it.
+	 */
+
+	assert(pos > sv);
+	sz = (size_t)(pos - sv);
+
+	r->last->end = malloc(sz + 1);
+
+	if (NULL == r->last->end) {
+		(*r->msg)(MANDOCERR_MEM, r->data, ln, pos, NULL);
+		return(ROFF_ERR);
+	}
+
+	memcpy(r->last->end, *bufp + sv, sz);
+	r->last->end[(int)sz] = '\0';
+
+	ROFF_MDEBUG(r, "opening explicit ignore block");
 
 	if ((*bufp)[pos])
 		if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL))
 			return(ROFF_ERR);
 
+	return(ROFF_IGN);
+}
+
+
+/* ARGSUSED */
+static enum rofferr
+roff_ig_text(ROFF_ARGS)
+{
+
+	return(ROFF_IGN);
+}
+
+
+/* ARGSUSED */
+static enum rofferr
+roff_if_text(ROFF_ARGS)
+{
+	char		*ep, *st;
+
+	st = &(*bufp)[pos];
+	if (NULL == (ep = strstr(st, "\\}"))) {
+		roffnode_cleanscope(r);
+		return(ROFF_IGN);
+	}
+
+	if (ep > st && '\\' != *(ep - 1)) {
+		ROFF_MDEBUG(r, "closing explicit scope (in-line)");
+		roffnode_pop(r);
+	}
+
+	roffnode_cleanscope(r);
 	return(ROFF_IGN);
 }
 
Index: main.c
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/main.c,v
retrieving revision 1.77
retrieving revision 1.78
diff -Lmain.c -Lmain.c -u -p -r1.77 -r1.78
--- main.c
+++ main.c
@@ -798,8 +798,8 @@ mwarn(void *arg, int line, int col, cons
 static	const char * const	mandocerrs[MANDOCERR_MAX] = {
 	"ok",
 	"multi-line scope open on exit",
-	"request for scope closure when no matching scope is open",
-	"macro requires line argument(s)",
+	"request for scope closure when no matching scope is open: ignored",
+	"macro requires line argument(s): ignored",
 	"line arguments will be lost",
 	"memory exhausted"
 };
--- /dev/null
+++ regress/roff/if/multiline-free1.in
@@ -0,0 +1,11 @@
+.Dd $Mdocdate: May 16 2010 $
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+.if t \{\
+there  \\}   dude
+.\}
+fdsa
--- /dev/null
+++ regress/roff/if/multiline-free0.in
@@ -0,0 +1,10 @@
+.Dd $Mdocdate: May 16 2010 $
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+.if t \{\
+there  \}   dude
+fdsa
--- /dev/null
+++ regress/roff/ig/simple1.in
@@ -0,0 +1,12 @@
+.Dd $Mdocdate: May 16 2010 $
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+123
+.ig
+hello
+..
+12124
--- /dev/null
+++ regress/roff/ig/redef0.in
@@ -0,0 +1,13 @@
+.Dd $Mdocdate: May 16 2010 $
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+a
+.ig if
+asdf
+.if t \
+b
+c
--- /dev/null
+++ regress/roff/ig/simple0.in
@@ -0,0 +1,12 @@
+.Dd $Mdocdate: May 16 2010 $
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+123
+.ig
+hello
+..
+12124
--- /dev/null
+++ regress/roff/ig/simple2.in
@@ -0,0 +1,15 @@
+.Dd $Mdocdate: May 16 2010 $
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+123
+.ig
+hello
+.if t \{\
+hello
+.\}
+..
+12124
--- /dev/null
+++ regress/roff/ig/end1.in
@@ -0,0 +1,12 @@
+.Dd $Mdocdate: May 16 2010 $
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+a
+.ig foo	
+asdf
+.foo
+b
--- /dev/null
+++ regress/roff/ig/end0.in
@@ -0,0 +1,12 @@
+.Dd $Mdocdate: May 16 2010 $
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+a
+.ig foo
+asdf
+.foo
+b
--
 To unsubscribe send an email to source+unsubscribe@mdocml.bsd.lv

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2010-05-16 22:28 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-05-16 22:28 mdocml: `ig' support in all its glory kristaps

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).