Fix bug #12: Balanced square brackets test should recognize multi-line [Illustration] tags
authorali <ali@juiblex.co.uk>
Mon Sep 23 21:18:27 2013 +0100 (2013-09-23)
changeset 939fb13a5dde3b
parent 92 7a62c77a0dbe
child 94 466f43a12118
Fix bug #12: Balanced square brackets test should recognize multi-line [Illustration] tags
bookloupe/Makefile.am
bookloupe/bookloupe.c
bookloupe/bookloupe.h
bookloupe/counters.c
bookloupe/counters.h
bookloupe/pending.c
bookloupe/pending.h
test/bookloupe/Makefile.am
test/bookloupe/multi-line-illustration.tst
test/compatibility/example.tst
test/harness/testcase.c
     1.1 --- a/bookloupe/Makefile.am	Sat Sep 21 23:40:18 2013 +0100
     1.2 +++ b/bookloupe/Makefile.am	Mon Sep 23 21:18:27 2013 +0100
     1.3 @@ -1,6 +1,7 @@
     1.4  INCLUDES=-I$(top_srcdir)
     1.5  bin_PROGRAMS=bookloupe
     1.6 -bookloupe_SOURCES=bookloupe.c bookloupe.h counters.c counters.h
     1.7 +bookloupe_SOURCES=bookloupe.c bookloupe.h counters.c counters.h \
     1.8 +	pending.c pending.h
     1.9  pkgdata_DATA=bookloupe.typ
    1.10  AM_CFLAGS=$(GLIB_CFLAGS)
    1.11  LIBS=$(GLIB_LIBS)
     2.1 --- a/bookloupe/bookloupe.c	Sat Sep 21 23:40:18 2013 +0100
     2.2 +++ b/bookloupe/bookloupe.c	Mon Sep 23 21:18:27 2013 +0100
     2.3 @@ -29,6 +29,7 @@
     2.4  #include <bl/bl.h>
     2.5  #include "bookloupe.h"
     2.6  #include "counters.h"
     2.7 +#include "pending.h"
     2.8  #include "HTMLentities.h"
     2.9  
    2.10  gchar *prevline;
    2.11 @@ -867,10 +868,26 @@
    2.12  	    isemptyline=FALSE;  /* ignore lines like  *  *  *  as spacers */
    2.13  	if (c==CHAR_UNDERSCORE)
    2.14  	    counters->c_unders++;
    2.15 -	if (c==CHAR_OPEN_CBRACK || c==CHAR_OPEN_RBRACK || c==CHAR_OPEN_SBRACK)
    2.16 +	if (c==CHAR_OPEN_SBRACK)
    2.17 +	{
    2.18 +	    if (!matching_difference(counters,COUNTER_ILLUSTRATION) &&
    2.19 +	      !matching_difference(counters,c) && s==aline &&
    2.20 +	      g_str_has_prefix(s,"[Illustration:"))
    2.21 +		increment_matching(counters,COUNTER_ILLUSTRATION,TRUE);
    2.22 +	    else
    2.23 +		increment_matching(counters,c,TRUE);
    2.24 +	}
    2.25 +	else if (c==CHAR_OPEN_CBRACK || c==CHAR_OPEN_RBRACK)
    2.26  	    increment_matching(counters,c,TRUE);
    2.27 -	if (c==CHAR_CLOSE_CBRACK || c==CHAR_CLOSE_RBRACK ||
    2.28 -	  c==CHAR_CLOSE_SBRACK)
    2.29 +	if (c==CHAR_CLOSE_SBRACK)
    2.30 +	{
    2.31 +	    if (!matching_count(counters,COUNTER_ILLUSTRATION,FALSE) &&
    2.32 +	      !matching_difference(counters,c) && !*snext)
    2.33 +		increment_matching(counters,COUNTER_ILLUSTRATION,FALSE);
    2.34 +	    else
    2.35 +		increment_matching(counters,c,FALSE);
    2.36 +	}
    2.37 +	else if (c==CHAR_CLOSE_CBRACK || c==CHAR_CLOSE_RBRACK)
    2.38  	    increment_matching(counters,c,FALSE);
    2.39  	sprev=s;
    2.40  	s=snext;
    2.41 @@ -2363,168 +2380,6 @@
    2.42  }
    2.43  
    2.44  /*
    2.45 - * print_pending:
    2.46 - *
    2.47 - * If we are in a state of unbalanced quotes, and this line
    2.48 - * doesn't begin with a quote, output the stored error message.
    2.49 - * If the -P switch was used, print the warning even if the
    2.50 - * new para starts with quotes.
    2.51 - */
    2.52 -void print_pending(const char *aline,const char *parastart,
    2.53 -  struct pending *pending)
    2.54 -{
    2.55 -    const char *s;
    2.56 -    gunichar c;
    2.57 -    s=aline;
    2.58 -    while (*s==' ')
    2.59 -	s++;
    2.60 -    c=g_utf8_get_char(s);
    2.61 -    if (pending->dquote)
    2.62 -    {
    2.63 -	if (c!=CHAR_DQUOTE || pswit[QPARA_SWITCH])
    2.64 -	{
    2.65 -	    if (!pswit[OVERVIEW_SWITCH])
    2.66 -	    {
    2.67 -		if (pswit[ECHO_SWITCH])
    2.68 -		    g_print("\n%s\n",parastart);
    2.69 -		g_print("%s\n",pending->dquote);
    2.70 -	    }
    2.71 -	    else
    2.72 -		cnt_dquot++;
    2.73 -	}
    2.74 -	g_free(pending->dquote);
    2.75 -	pending->dquote=NULL;
    2.76 -    }
    2.77 -    if (pending->squote)
    2.78 -    {
    2.79 -	if (!CHAR_IS_SQUOTE(c) || pswit[QPARA_SWITCH] || pending->squot)
    2.80 -	{
    2.81 -	    if (!pswit[OVERVIEW_SWITCH])
    2.82 -	    {
    2.83 -		if (pswit[ECHO_SWITCH])
    2.84 -		    g_print("\n%s\n",parastart);
    2.85 -		g_print("%s\n",pending->squote);
    2.86 -	    }
    2.87 -	    else
    2.88 -		cnt_squot++;
    2.89 -	}
    2.90 -	g_free(pending->squote);
    2.91 -	pending->squote=NULL;
    2.92 -    }
    2.93 -    if (pending->rbrack)
    2.94 -    {
    2.95 -	if (!pswit[OVERVIEW_SWITCH])
    2.96 -	{
    2.97 -	    if (pswit[ECHO_SWITCH])
    2.98 -		g_print("\n%s\n",parastart);
    2.99 -	    g_print("%s\n",pending->rbrack);
   2.100 -	}
   2.101 -	else
   2.102 -	    cnt_brack++;
   2.103 -	g_free(pending->rbrack);
   2.104 -	pending->rbrack=NULL;
   2.105 -    }
   2.106 -    if (pending->sbrack)
   2.107 -    {
   2.108 -	if (!pswit[OVERVIEW_SWITCH])
   2.109 -	{
   2.110 -	    if (pswit[ECHO_SWITCH])
   2.111 -		g_print("\n%s\n",parastart);
   2.112 -	    g_print("%s\n",pending->sbrack);
   2.113 -	}
   2.114 -	else
   2.115 -	    cnt_brack++;
   2.116 -	g_free(pending->sbrack);
   2.117 -	pending->sbrack=NULL;
   2.118 -    }
   2.119 -    if (pending->cbrack)
   2.120 -    {
   2.121 -	if (!pswit[OVERVIEW_SWITCH])
   2.122 -	{
   2.123 -	    if (pswit[ECHO_SWITCH])
   2.124 -		g_print("\n%s\n",parastart);
   2.125 -	    g_print("%s\n",pending->cbrack);
   2.126 -	}
   2.127 -	else
   2.128 -	    cnt_brack++;
   2.129 -	g_free(pending->cbrack);
   2.130 -	pending->cbrack=NULL;
   2.131 -    }
   2.132 -    if (pending->unders)
   2.133 -    {
   2.134 -	if (!pswit[OVERVIEW_SWITCH])
   2.135 -	{
   2.136 -	    if (pswit[ECHO_SWITCH])
   2.137 -		g_print("\n%s\n",parastart);
   2.138 -	    g_print("%s\n",pending->unders);
   2.139 -	}
   2.140 -	else
   2.141 -	    cnt_brack++;
   2.142 -	g_free(pending->unders);
   2.143 -	pending->unders=NULL;
   2.144 -    }
   2.145 -}
   2.146 -
   2.147 -/*
   2.148 - * check_for_mismatched_quotes:
   2.149 - *
   2.150 - * At end of paragraph, check for mismatched quotes.
   2.151 - *
   2.152 - * We don't want to report an error immediately, since it is a
   2.153 - * common convention to omit the quotes at end of paragraph if
   2.154 - * the next paragraph is a continuation of the same speaker.
   2.155 - * Where this is the case, the next para should begin with a
   2.156 - * quote, so we store the warning message and only display it
   2.157 - * at the top of the next iteration if the new para doesn't
   2.158 - * start with a quote.
   2.159 - * The -p switch overrides this default, and warns of unclosed
   2.160 - * quotes on _every_ paragraph, whether the next begins with a
   2.161 - * quote or not.
   2.162 - */
   2.163 -void check_for_mismatched_quotes(const struct counters *counters,
   2.164 -  struct pending *pending)
   2.165 -{
   2.166 -    int squote_straight,squote_curved;
   2.167 -    if (counters->quot%2)
   2.168 -	pending->dquote=
   2.169 -	  g_strdup_printf("    Line %ld - Mismatched quotes",linecnt);
   2.170 -    if (pswit[SQUOTE_SWITCH])
   2.171 -    {
   2.172 -	if (matching_count(counters,CHAR_SQUOTE,TRUE))
   2.173 -	    squote_straight=matching_difference(counters,CHAR_SQUOTE);
   2.174 -	else
   2.175 -	    squote_straight=0;
   2.176 -	if (matching_count(counters,CHAR_LS_QUOTE,TRUE))
   2.177 -	    squote_curved=matching_difference(counters,CHAR_LS_QUOTE);
   2.178 -	else
   2.179 -	    squote_curved=0;
   2.180 -	if (squote_straight || squote_curved)
   2.181 -	    pending->squote=
   2.182 -	      g_strdup_printf("    Line %ld - Mismatched singlequotes?",
   2.183 -	      linecnt);
   2.184 -	if (squote_straight && squote_straight!=1 ||
   2.185 -	  squote_curved && squote_curved!=1)
   2.186 -	    /*
   2.187 -	     * Flag it to be noted regardless of the
   2.188 -	     * first char of the next para.
   2.189 -	     */
   2.190 -	    pending->squot=1;
   2.191 -    }
   2.192 -    if (matching_difference(counters,CHAR_OPEN_RBRACK))
   2.193 -	pending->rbrack=
   2.194 -	  g_strdup_printf("    Line %ld - Mismatched round brackets?",linecnt);
   2.195 -    if (matching_difference(counters,CHAR_OPEN_SBRACK))
   2.196 -	pending->sbrack=
   2.197 -	  g_strdup_printf("    Line %ld - Mismatched square brackets?",linecnt);
   2.198 -    if (matching_difference(counters,CHAR_OPEN_CBRACK))
   2.199 -	pending->cbrack=
   2.200 -	  g_strdup_printf("    Line %ld - Mismatched curly brackets?",linecnt);
   2.201 -    if (counters->c_unders%2)
   2.202 -	pending->unders=
   2.203 -	  g_strdup_printf("    Line %ld - Mismatched underscores?",linecnt);
   2.204 -}
   2.205 -
   2.206 -/*
   2.207   * check_for_omitted_punctuation:
   2.208   *
   2.209   * Check for omitted punctuation at end of paragraph by working back
   2.210 @@ -2693,7 +2548,6 @@
   2.211  	}
   2.212  	checked_linecnt++;
   2.213  	print_pending(aline,parastart,&pending);
   2.214 -	memset(&pending,0,sizeof(pending));
   2.215  	isemptyline=analyse_quotes(aline,&counters);
   2.216  	if (isnewpara && !isemptyline)
   2.217  	{
   2.218 @@ -2774,7 +2628,7 @@
   2.219  	if (isemptyline)
   2.220  	{
   2.221  	    check_for_mismatched_quotes(&counters,&pending);
   2.222 -	    memset(&counters,0,sizeof(counters));
   2.223 +	    counters_reset(&counters);
   2.224  	    /* let the next iteration know that it's starting a new para */
   2.225  	    isnewpara=TRUE;
   2.226  	    if (prevline)
   2.227 @@ -2783,6 +2637,10 @@
   2.228  	g_free(prevline);
   2.229  	prevline=g_strdup(aline);
   2.230      }
   2.231 +    linecnt++;
   2.232 +    check_for_mismatched_quotes(&counters,&pending);
   2.233 +    print_pending(NULL,parastart,&pending);
   2.234 +    reset_pending(&pending);
   2.235      if (prevline)
   2.236      {
   2.237  	g_free(prevline);
     3.1 --- a/bookloupe/bookloupe.h	Sat Sep 21 23:40:18 2013 +0100
     3.2 +++ b/bookloupe/bookloupe.h	Mon Sep 23 21:18:27 2013 +0100
     3.3 @@ -79,9 +79,10 @@
     3.4      int dquote,squote;
     3.5  };
     3.6  
     3.7 -struct pending {
     3.8 -    char *dquote,*squote,*rbrack,*sbrack,*cbrack,*unders;
     3.9 -    long squot;
    3.10 -};
    3.11 +extern gboolean pswit[SWITNO];
    3.12 +
    3.13 +extern long cnt_dquot,cnt_squot,cnt_brack,cnt_bin,cnt_odd,cnt_long,cnt_short;
    3.14 +extern long cnt_punct,cnt_dash,cnt_word,cnt_html,cnt_lineend,cnt_spacend;
    3.15 +extern long linecnt,checked_linecnt;
    3.16  
    3.17  #endif /* BOOKOUPE_H */
     4.1 --- a/bookloupe/counters.c	Sat Sep 21 23:40:18 2013 +0100
     4.2 +++ b/bookloupe/counters.c	Mon Sep 23 21:18:27 2013 +0100
     4.3 @@ -1,4 +1,5 @@
     4.4  #include <stdlib.h>
     4.5 +#include <string.h>
     4.6  #include <glib.h>
     4.7  #include "bookloupe.h"
     4.8  #include "counters.h"
     4.9 @@ -44,9 +45,9 @@
    4.10  	return GINT_TO_POINTER((gint)CHAR_SQUOTE);
    4.11      else if (ch==CHAR_LS_QUOTE || ch==CHAR_RS_QUOTE)
    4.12  	return GINT_TO_POINTER((gint)CHAR_LS_QUOTE);
    4.13 -    else
    4.14 +    else if (ch<0x4000 || ch-0x4000>=NO_SPECIAL_COUNTERS)
    4.15      {
    4.16 -	g_warning("Matching pair not found for U+%04"G_GINT32_FORMAT"X",ch);
    4.17 +	g_warning("Matching pair not found for U+%04" G_GINT32_MODIFIER "X",ch);
    4.18  	return GINT_TO_POINTER((gint)ch);
    4.19      }
    4.20  }
    4.21 @@ -96,6 +97,13 @@
    4.22      return value->open-value->close;
    4.23  }
    4.24  
    4.25 +void counters_reset(struct counters *counters)
    4.26 +{
    4.27 +    if (counters->matching)
    4.28 +	g_tree_destroy(counters->matching);
    4.29 +    memset(counters,0,sizeof(*counters));
    4.30 +}
    4.31 +
    4.32  void counters_destroy(struct counters *counters)
    4.33  {
    4.34      if (counters->matching)
     5.1 --- a/bookloupe/counters.h	Sat Sep 21 23:40:18 2013 +0100
     5.2 +++ b/bookloupe/counters.h	Mon Sep 23 21:18:27 2013 +0100
     5.3 @@ -3,6 +3,12 @@
     5.4  
     5.5  #include <glib.h>
     5.6  
     5.7 +/* Special counters live in the private use area */
     5.8 +enum {
     5.9 +    COUNTER_ILLUSTRATION=0xE000,
    5.10 +    NO_SPECIAL_COUNTERS
    5.11 +};
    5.12 +
    5.13  struct counters {
    5.14      GTree *matching;
    5.15      long quot;
    5.16 @@ -12,6 +18,7 @@
    5.17  void increment_matching(struct counters *counters,gunichar ch,gboolean open);
    5.18  int matching_count(const struct counters *counters,gunichar ch,gboolean open);
    5.19  int matching_difference(const struct counters *counters,gunichar ch);
    5.20 +void counters_reset(struct counters *counters);
    5.21  void counters_destroy(struct counters *counters);
    5.22  
    5.23  #endif /* COUNTERS_H */
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/bookloupe/pending.c	Mon Sep 23 21:18:27 2013 +0100
     6.3 @@ -0,0 +1,239 @@
     6.4 +#include <stdlib.h>
     6.5 +#include <string.h>
     6.6 +#include <glib.h>
     6.7 +#include "bookloupe.h"
     6.8 +#include "pending.h"
     6.9 +
    6.10 +/*
    6.11 + * print_pending:
    6.12 + *
    6.13 + * If we are in a state of unbalanced quotes, and this line
    6.14 + * doesn't begin with a quote, output the stored error message.
    6.15 + * If the -p switch was used, print the warning even if the
    6.16 + * new para starts with quotes.
    6.17 + */
    6.18 +void print_pending(const char *aline,const char *parastart,
    6.19 +  struct pending *pending)
    6.20 +{
    6.21 +    const char *s;
    6.22 +    gunichar c;
    6.23 +    if (aline)
    6.24 +    {
    6.25 +	s=aline;
    6.26 +	while (*s==' ')
    6.27 +	    s++;
    6.28 +	c=g_utf8_get_char(s);
    6.29 +    }
    6.30 +    else
    6.31 +    {
    6.32 +	s=NULL;
    6.33 +	c='\0';
    6.34 +    }
    6.35 +    if (pending->illustration.warning_text)
    6.36 +    {
    6.37 +	if (aline)
    6.38 +	{
    6.39 +	    if (pswit[ECHO_SWITCH] && !pending->illustration.queried_line)
    6.40 +		pending->illustration.queried_line=g_strdup(parastart);
    6.41 +	}
    6.42 +	else
    6.43 +	{
    6.44 +	    if (!pswit[OVERVIEW_SWITCH])
    6.45 +	    {
    6.46 +		if (pending->illustration.queried_line)
    6.47 +		    g_print("\n%s\n",pending->illustration.queried_line);
    6.48 +		g_print("%s\n",pending->illustration.warning_text);
    6.49 +	    }
    6.50 +	    else
    6.51 +		cnt_brack++;
    6.52 +	    g_free(pending->illustration.warning_text);
    6.53 +	    pending->illustration.warning_text=NULL;
    6.54 +	    g_free(pending->illustration.queried_line);
    6.55 +	    pending->illustration.queried_line=NULL;
    6.56 +	}
    6.57 +    }
    6.58 +    if (pending->dquote)
    6.59 +    {
    6.60 +	if (c!=CHAR_DQUOTE || pswit[QPARA_SWITCH])
    6.61 +	{
    6.62 +	    if (!pswit[OVERVIEW_SWITCH])
    6.63 +	    {
    6.64 +		if (pswit[ECHO_SWITCH])
    6.65 +		    g_print("\n%s\n",parastart);
    6.66 +		g_print("%s\n",pending->dquote);
    6.67 +	    }
    6.68 +	    else
    6.69 +		cnt_dquot++;
    6.70 +	}
    6.71 +	g_free(pending->dquote);
    6.72 +	pending->dquote=NULL;
    6.73 +    }
    6.74 +    if (pending->squote)
    6.75 +    {
    6.76 +	if (!CHAR_IS_SQUOTE(c) || pswit[QPARA_SWITCH] || pending->squot)
    6.77 +	{
    6.78 +	    if (!pswit[OVERVIEW_SWITCH])
    6.79 +	    {
    6.80 +		if (pswit[ECHO_SWITCH])
    6.81 +		    g_print("\n%s\n",parastart);
    6.82 +		g_print("%s\n",pending->squote);
    6.83 +	    }
    6.84 +	    else
    6.85 +		cnt_squot++;
    6.86 +	}
    6.87 +	g_free(pending->squote);
    6.88 +	pending->squote=NULL;
    6.89 +    }
    6.90 +    if (pending->rbrack)
    6.91 +    {
    6.92 +	if (!pswit[OVERVIEW_SWITCH])
    6.93 +	{
    6.94 +	    if (pswit[ECHO_SWITCH])
    6.95 +		g_print("\n%s\n",parastart);
    6.96 +	    g_print("%s\n",pending->rbrack);
    6.97 +	}
    6.98 +	else
    6.99 +	    cnt_brack++;
   6.100 +	g_free(pending->rbrack);
   6.101 +	pending->rbrack=NULL;
   6.102 +    }
   6.103 +    if (pending->sbrack)
   6.104 +    {
   6.105 +	if (!pswit[OVERVIEW_SWITCH])
   6.106 +	{
   6.107 +	    if (pswit[ECHO_SWITCH])
   6.108 +		g_print("\n%s\n",parastart);
   6.109 +	    g_print("%s\n",pending->sbrack);
   6.110 +	}
   6.111 +	else
   6.112 +	    cnt_brack++;
   6.113 +	g_free(pending->sbrack);
   6.114 +	pending->sbrack=NULL;
   6.115 +    }
   6.116 +    if (pending->cbrack)
   6.117 +    {
   6.118 +	if (!pswit[OVERVIEW_SWITCH])
   6.119 +	{
   6.120 +	    if (pswit[ECHO_SWITCH])
   6.121 +		g_print("\n%s\n",parastart);
   6.122 +	    g_print("%s\n",pending->cbrack);
   6.123 +	}
   6.124 +	else
   6.125 +	    cnt_brack++;
   6.126 +	g_free(pending->cbrack);
   6.127 +	pending->cbrack=NULL;
   6.128 +    }
   6.129 +    if (pending->unders)
   6.130 +    {
   6.131 +	if (!pswit[OVERVIEW_SWITCH])
   6.132 +	{
   6.133 +	    if (pswit[ECHO_SWITCH])
   6.134 +		g_print("\n%s\n",parastart);
   6.135 +	    g_print("%s\n",pending->unders);
   6.136 +	}
   6.137 +	else
   6.138 +	    cnt_brack++;
   6.139 +	g_free(pending->unders);
   6.140 +	pending->unders=NULL;
   6.141 +    }
   6.142 +}
   6.143 +
   6.144 +void reset_pending(struct pending *pending)
   6.145 +{
   6.146 +    memset(pending,0,sizeof(*pending));
   6.147 +}
   6.148 +
   6.149 +/*
   6.150 + * check_for_mismatched_quotes:
   6.151 + *
   6.152 + * At end of paragraph, check for mismatched quotes.
   6.153 + *
   6.154 + * We don't want to report an error immediately, since it is a
   6.155 + * common convention to omit the quotes at end of paragraph if
   6.156 + * the next paragraph is a continuation of the same speaker.
   6.157 + * Where this is the case, the next para should begin with a
   6.158 + * quote, so we store the warning message and only display it
   6.159 + * at the top of the next iteration if the new para doesn't
   6.160 + * start with a quote.
   6.161 + * The -p switch overrides this default, and warns of unclosed
   6.162 + * quotes on _every_ paragraph, whether the next begins with a
   6.163 + * quote or not.
   6.164 + */
   6.165 +void check_for_mismatched_quotes(const struct counters *counters,
   6.166 +  struct pending *pending)
   6.167 +{
   6.168 +    int squote_straight,squote_curved,difference;
   6.169 +    if (counters->quot%2)
   6.170 +	pending->dquote=
   6.171 +	  g_strdup_printf("    Line %ld - Mismatched quotes",linecnt);
   6.172 +    if (pswit[SQUOTE_SWITCH])
   6.173 +    {
   6.174 +	if (matching_count(counters,CHAR_SQUOTE,TRUE))
   6.175 +	    squote_straight=matching_difference(counters,CHAR_SQUOTE);
   6.176 +	else
   6.177 +	    squote_straight=0;
   6.178 +	if (matching_count(counters,CHAR_LS_QUOTE,TRUE))
   6.179 +	    squote_curved=matching_difference(counters,CHAR_LS_QUOTE);
   6.180 +	else
   6.181 +	    squote_curved=0;
   6.182 +	if (squote_straight || squote_curved)
   6.183 +	    pending->squote=
   6.184 +	      g_strdup_printf("    Line %ld - Mismatched singlequotes?",
   6.185 +	      linecnt);
   6.186 +	if (squote_straight && squote_straight!=1 ||
   6.187 +	  squote_curved && squote_curved!=1)
   6.188 +	    /*
   6.189 +	     * Flag it to be noted regardless of the
   6.190 +	     * first char of the next para.
   6.191 +	     */
   6.192 +	    pending->squot=1;
   6.193 +    }
   6.194 +    difference=matching_difference(counters,COUNTER_ILLUSTRATION);
   6.195 +    if (difference)
   6.196 +    {
   6.197 +	if (difference<0 && pending->illustration.warning_text)
   6.198 +	{
   6.199 +	    difference++;
   6.200 +	    g_free(pending->illustration.queried_line);
   6.201 +	    pending->illustration.queried_line=NULL;
   6.202 +	    g_free(pending->illustration.warning_text);
   6.203 +	    pending->illustration.warning_text=NULL;
   6.204 +	}
   6.205 +	if (difference<0)
   6.206 +	{
   6.207 +	    increment_matching(counters,CHAR_OPEN_SBRACK,FALSE);
   6.208 +	    difference++;
   6.209 +	}
   6.210 +	if (difference)
   6.211 +	{
   6.212 +	    if (pending->illustration.warning_text)
   6.213 +	    {
   6.214 +		if (!pswit[OVERVIEW_SWITCH])
   6.215 +		{
   6.216 +		    if (pending->illustration.queried_line)
   6.217 +			g_print("\n%s\n",pending->illustration.queried_line);
   6.218 +		    g_print("%s\n",pending->illustration.warning_text);
   6.219 +		}
   6.220 +		else
   6.221 +		    cnt_brack++;
   6.222 +		g_free(pending->illustration.warning_text);
   6.223 +	    }
   6.224 +	    pending->illustration.warning_text=g_strdup_printf(
   6.225 +	      "    Line %ld - Mismatched illustration tag?",linecnt);
   6.226 +	    g_free(pending->illustration.queried_line);
   6.227 +	    pending->illustration.queried_line=NULL;
   6.228 +	}
   6.229 +    }
   6.230 +    if (matching_difference(counters,CHAR_OPEN_RBRACK))
   6.231 +	pending->rbrack=
   6.232 +	  g_strdup_printf("    Line %ld - Mismatched round brackets?",linecnt);
   6.233 +    if (matching_difference(counters,CHAR_OPEN_SBRACK))
   6.234 +	pending->sbrack=
   6.235 +	  g_strdup_printf("    Line %ld - Mismatched square brackets?",linecnt);
   6.236 +    if (matching_difference(counters,CHAR_OPEN_CBRACK))
   6.237 +	pending->cbrack=
   6.238 +	  g_strdup_printf("    Line %ld - Mismatched curly brackets?",linecnt);
   6.239 +    if (counters->c_unders%2)
   6.240 +	pending->unders=
   6.241 +	  g_strdup_printf("    Line %ld - Mismatched underscores?",linecnt);
   6.242 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/bookloupe/pending.h	Mon Sep 23 21:18:27 2013 +0100
     7.3 @@ -0,0 +1,23 @@
     7.4 +#ifndef PENDING_H
     7.5 +#define PENDING_H
     7.6 +
     7.7 +#include "counters.h"
     7.8 +
     7.9 +struct pending_warning {
    7.10 +    char *queried_line;
    7.11 +    char *warning_text;
    7.12 +};
    7.13 +
    7.14 +struct pending {
    7.15 +    char *dquote,*squote,*rbrack,*sbrack,*cbrack,*unders;
    7.16 +    long squot;
    7.17 +    struct pending_warning illustration;
    7.18 +};
    7.19 +
    7.20 +void print_pending(const char *aline,const char *parastart,
    7.21 +  struct pending *pending);
    7.22 +void reset_pending(struct pending *pending);
    7.23 +void check_for_mismatched_quotes(const struct counters *counters,
    7.24 +  struct pending *pending);
    7.25 +
    7.26 +#endif /* PENDING_H */
     8.1 --- a/test/bookloupe/Makefile.am	Sat Sep 21 23:40:18 2013 +0100
     8.2 +++ b/test/bookloupe/Makefile.am	Mon Sep 23 21:18:27 2013 +0100
     8.3 @@ -1,5 +1,5 @@
     8.4  TESTS_ENVIRONMENT=BOOKLOUPE=../../bookloupe/bookloupe ../harness/loupe-test
     8.5  TESTS=non-ascii.tst long-line.tst curved-single-quotes.tst \
     8.6 -	curved-genitives.tst
     8.7 +	curved-genitives.tst multi-line-illustration.tst
     8.8  
     8.9  dist_pkgdata_DATA=$(TESTS)
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/test/bookloupe/multi-line-illustration.tst	Mon Sep 23 21:18:27 2013 +0100
     9.3 @@ -0,0 +1,29 @@
     9.4 +**************** INPUT ****************
     9.5 +[Illustration: One or more Caption lines
     9.6 +
     9.7 +One or more Sub-caption lines]
     9.8 +
     9.9 +[Illustration: The first line of a caption.
    9.10 +
    9.11 +A caption that contains balanced [square] brackets in a paragraph.]
    9.12 +
    9.13 +[Square brackets can be used to group several paragraphs.
    9.14 +
    9.15 +This will generate warnings as normal.]
    9.16 +
    9.17 +[Illustration: An ill-formed illustration might confuse.
    9.18 +
    9.19 +It generates warnings.] The opening and closing tags no longer match.
    9.20 +**************** WARNINGS ****************
    9.21 +<expected>
    9.22 +  <error>
    9.23 +    <at line="10"/>
    9.24 +    <at line="12"/>
    9.25 +    <at line="16"/>
    9.26 +    <text>Mismatched square brackets?</text>
    9.27 +  </error>
    9.28 +  <error>
    9.29 +    <at line="14"/>
    9.30 +    <text>Mismatched illustration tag?</text>
    9.31 +  </error>
    9.32 +</expected>
    10.1 --- a/test/compatibility/example.tst	Sat Sep 21 23:40:18 2013 +0100
    10.2 +++ b/test/compatibility/example.tst	Mon Sep 23 21:18:27 2013 +0100
    10.3 @@ -33,6 +33,8 @@
    10.4  travels were profitable to himself. The fact is, that tbere are
    10.5  cousins who come to greatness and rnust be pacified, or they will
    10.6  prove annoying. Heaven forefend a collision between cousins!
    10.7 +
    10.8 +
    10.9  **************** EXPECTED ****************
   10.10  
   10.11  Japan, China, Australia , nay, the continent of Europe, holding an
   10.12 @@ -85,3 +87,6 @@
   10.13  
   10.14  cousins who come to greatness and rnust be pacified, or they will
   10.15      Line 33 column 34 - Query word rnust - not reporting duplicates
   10.16 +
   10.17 +correspond with some of them. On the whole, forgetting two or
   10.18 +    Line 35 - Mismatched quotes
    11.1 --- a/test/harness/testcase.c	Sat Sep 21 23:40:18 2013 +0100
    11.2 +++ b/test/harness/testcase.c	Mon Sep 23 21:18:27 2013 +0100
    11.3 @@ -469,13 +469,7 @@
    11.4  	g_error_free(error);
    11.5  	return FALSE;
    11.6      }
    11.7 -    if (testcase->expected || testcase->warnings)
    11.8 -	r=testcase_spawn_bookloupe(testcase,&output,&error);
    11.9 -    else
   11.10 -    {
   11.11 -	r=testcase_spawn_bookloupe(testcase,NULL,&error);
   11.12 -        output=NULL;
   11.13 -    }
   11.14 +    r=testcase_spawn_bookloupe(testcase,&output,&error);
   11.15      if (!r)
   11.16      {
   11.17  	g_print("%s: FAIL\n",testcase->basename);
   11.18 @@ -492,37 +486,33 @@
   11.19  	g_error_free(error);
   11.20  	return FALSE;
   11.21      }
   11.22 -    if (testcase->expected || testcase->warnings)
   11.23 +    header=g_string_new("\n\nFile: ");
   11.24 +    g_string_append(header,filename);
   11.25 +    g_string_append(header,"\n");
   11.26 +    if (!g_str_has_prefix(output,header->str))
   11.27      {
   11.28 -	header=g_string_new("\n\nFile: ");
   11.29 -	g_string_append(header,filename);
   11.30 -	g_string_append(header,"\n");
   11.31 -	if (!g_str_has_prefix(output,header->str))
   11.32 +	g_print("%s: FAIL\n",testcase->basename);
   11.33 +	g_print("Unexpected header from bookloupe:\n");
   11.34 +	offset=common_prefix_length(output,header->str);
   11.35 +	print_unexpected(output,offset);
   11.36 +	r=FALSE;
   11.37 +    }
   11.38 +    pos=header->len;
   11.39 +    if (r)
   11.40 +    {
   11.41 +	/* Skip the summary */
   11.42 +	s=strstr(output+pos,"\n\n");
   11.43 +	if (s)
   11.44 +	    pos=s-output+2;
   11.45 +	else
   11.46  	{
   11.47  	    g_print("%s: FAIL\n",testcase->basename);
   11.48 -	    g_print("Unexpected header from bookloupe:\n");
   11.49 -	    offset=common_prefix_length(output,header->str);
   11.50 -	    print_unexpected(output,offset);
   11.51 +	    g_print("Unterminated summary from bookloupe:\n%s\n",output+pos);
   11.52  	    r=FALSE;
   11.53  	}
   11.54 -	pos=header->len;
   11.55 -	if (r)
   11.56 -	{
   11.57 -	    /* Skip the summary */
   11.58 -	    s=strstr(output+pos,"\n\n");
   11.59 -	    if (s)
   11.60 -		pos=s-output+2;
   11.61 -	    else
   11.62 -	    {
   11.63 -		g_print("%s: FAIL\n",testcase->basename);
   11.64 -		g_print("Unterminated summary from bookloupe:\n%s\n",
   11.65 -		  output+pos);
   11.66 -		r=FALSE;
   11.67 -	    }
   11.68 -	}
   11.69 -	g_string_free(header,TRUE);
   11.70 -	r=testcase_check_warnings(testcase,output+pos,&xfail);
   11.71      }
   11.72 +    g_string_free(header,TRUE);
   11.73 +    r=testcase_check_warnings(testcase,output+pos,&xfail);
   11.74      g_free(filename);
   11.75      g_free(output);
   11.76      if (r)