Mostly complete implementation of the 'c' (character available)
authorschwarze <schwarze@openbsd.org>
Sun, 19 Aug 2018 17:43:39 +0000 (17:43 +0000)
committerschwarze <schwarze@openbsd.org>
Sun, 19 Aug 2018 17:43:39 +0000 (17:43 +0000)
roff conditional, except that the .char request still isn't supported
and that behaviour differs from groff in many edge cases.
But at least valid character names and numbers are now distinguished
from invalid ones.
This also fixes the bug that parsing of the 'c' conditional was
incomplete, which resulted in leaking the tested character to the
input parser at the beginning of the body when the condition was
inverted.

share/man/man7/roff.7
usr.bin/mandoc/roff.c

index b2edb41..2196575 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: roff.7,v 1.80 2018/08/18 21:36:53 schwarze Exp $
+.\"    $OpenBSD: roff.7,v 1.81 2018/08/19 17:43:39 schwarze Exp $
 .\"
 .\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
 .\" Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,7 +15,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: August 18 2018 $
+.Dd $Mdocdate: August 19 2018 $
 .Dt ROFF 7
 .Os
 .Sh NAME
@@ -1003,13 +1003,13 @@ is
 or
 .Sq o
 .Pq odd page ,
-it evaluates to true.
+it evaluates to true, and the
+.Ar body
+starts with the next character.
 .It
 If the first character of
 .Ar condition
 is
-.Sq c
-.Pq character available ,
 .Sq e
 .Pq even page ,
 .Sq t
@@ -1017,7 +1017,20 @@ is
 or
 .Sq v
 .Pq vroff mode ,
-it evaluates to false.
+it evaluates to false, and the
+.Ar body
+starts with the next character.
+.It
+If the first character of
+.Ar condition
+is
+.Sq c
+.Pq character available ,
+it evaluates to true if the following character is an ASCII character
+or a valid character escape sequence, or to false otherwise.
+The
+.Ar body
+starts with the character following that next character.
 .It
 If the first character of
 .Ar condition
index b889e9f..c085475 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: roff.c,v 1.207 2018/08/18 22:04:32 schwarze Exp $ */
+/*     $OpenBSD: roff.c,v 1.208 2018/08/19 17:43:39 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
@@ -2166,9 +2166,10 @@ out:
 static int
 roff_evalcond(struct roff *r, int ln, char *v, int *pos)
 {
-       char    *cp, *name;
-       size_t   sz;
-       int      deftype, number, savepos, istrue, wanttrue;
+       const char      *start, *end;
+       char            *cp, *name;
+       size_t           sz;
+       int              deftype, len, number, savepos, istrue, wanttrue;
 
        if ('!' == v[*pos]) {
                wanttrue = 0;
@@ -2183,12 +2184,50 @@ roff_evalcond(struct roff *r, int ln, char *v, int *pos)
        case 'o':
                (*pos)++;
                return wanttrue;
-       case 'c':
        case 'e':
        case 't':
        case 'v':
                (*pos)++;
                return !wanttrue;
+       case 'c':
+               do {
+                       (*pos)++;
+               } while (v[*pos] == ' ');
+
+               /*
+                * Quirk for groff compatibility:
+                * The horizontal tab is neither available nor unavailable.
+                */
+
+               if (v[*pos] == '\t') {
+                       (*pos)++;
+                       return 0;
+               }
+
+               /* Printable ASCII characters are available. */
+
+               if (v[*pos] != '\\') {
+                       (*pos)++;
+                       return wanttrue;
+               }
+
+               end = v + ++*pos;
+               switch (mandoc_escape(&end, &start, &len)) {
+               case ESCAPE_SPECIAL:
+                       istrue = mchars_spec2cp(start, len) != -1;
+                       break;
+               case ESCAPE_UNICODE:
+                       istrue = 1;
+                       break;
+               case ESCAPE_NUMBERED:
+                       istrue = mchars_num2char(start, len) != -1;
+                       break;
+               default:
+                       istrue = !wanttrue;
+                       break;
+               }
+               *pos = end - v;
+               return istrue == wanttrue;
        case 'd':
        case 'r':
                cp = v + *pos + 1;