# HG changeset patch # User ali # Date 1379967507 -3600 # Node ID 9fb13a5dde3b18e7e14910cf062672cef8995f6d # Parent 7a62c77a0dbe1713a9f01fa7f4222688e0044875 Fix bug #12: Balanced square brackets test should recognize multi-line [Illustration] tags diff -r 7a62c77a0dbe -r 9fb13a5dde3b bookloupe/Makefile.am --- a/bookloupe/Makefile.am Sat Sep 21 23:40:18 2013 +0100 +++ b/bookloupe/Makefile.am Mon Sep 23 21:18:27 2013 +0100 @@ -1,6 +1,7 @@ INCLUDES=-I$(top_srcdir) bin_PROGRAMS=bookloupe -bookloupe_SOURCES=bookloupe.c bookloupe.h counters.c counters.h +bookloupe_SOURCES=bookloupe.c bookloupe.h counters.c counters.h \ + pending.c pending.h pkgdata_DATA=bookloupe.typ AM_CFLAGS=$(GLIB_CFLAGS) LIBS=$(GLIB_LIBS) diff -r 7a62c77a0dbe -r 9fb13a5dde3b bookloupe/bookloupe.c --- a/bookloupe/bookloupe.c Sat Sep 21 23:40:18 2013 +0100 +++ b/bookloupe/bookloupe.c Mon Sep 23 21:18:27 2013 +0100 @@ -29,6 +29,7 @@ #include #include "bookloupe.h" #include "counters.h" +#include "pending.h" #include "HTMLentities.h" gchar *prevline; @@ -867,10 +868,26 @@ isemptyline=FALSE; /* ignore lines like * * * as spacers */ if (c==CHAR_UNDERSCORE) counters->c_unders++; - if (c==CHAR_OPEN_CBRACK || c==CHAR_OPEN_RBRACK || c==CHAR_OPEN_SBRACK) + if (c==CHAR_OPEN_SBRACK) + { + if (!matching_difference(counters,COUNTER_ILLUSTRATION) && + !matching_difference(counters,c) && s==aline && + g_str_has_prefix(s,"[Illustration:")) + increment_matching(counters,COUNTER_ILLUSTRATION,TRUE); + else + increment_matching(counters,c,TRUE); + } + else if (c==CHAR_OPEN_CBRACK || c==CHAR_OPEN_RBRACK) increment_matching(counters,c,TRUE); - if (c==CHAR_CLOSE_CBRACK || c==CHAR_CLOSE_RBRACK || - c==CHAR_CLOSE_SBRACK) + if (c==CHAR_CLOSE_SBRACK) + { + if (!matching_count(counters,COUNTER_ILLUSTRATION,FALSE) && + !matching_difference(counters,c) && !*snext) + increment_matching(counters,COUNTER_ILLUSTRATION,FALSE); + else + increment_matching(counters,c,FALSE); + } + else if (c==CHAR_CLOSE_CBRACK || c==CHAR_CLOSE_RBRACK) increment_matching(counters,c,FALSE); sprev=s; s=snext; @@ -2363,168 +2380,6 @@ } /* - * print_pending: - * - * If we are in a state of unbalanced quotes, and this line - * doesn't begin with a quote, output the stored error message. - * If the -P switch was used, print the warning even if the - * new para starts with quotes. - */ -void print_pending(const char *aline,const char *parastart, - struct pending *pending) -{ - const char *s; - gunichar c; - s=aline; - while (*s==' ') - s++; - c=g_utf8_get_char(s); - if (pending->dquote) - { - if (c!=CHAR_DQUOTE || pswit[QPARA_SWITCH]) - { - if (!pswit[OVERVIEW_SWITCH]) - { - if (pswit[ECHO_SWITCH]) - g_print("\n%s\n",parastart); - g_print("%s\n",pending->dquote); - } - else - cnt_dquot++; - } - g_free(pending->dquote); - pending->dquote=NULL; - } - if (pending->squote) - { - if (!CHAR_IS_SQUOTE(c) || pswit[QPARA_SWITCH] || pending->squot) - { - if (!pswit[OVERVIEW_SWITCH]) - { - if (pswit[ECHO_SWITCH]) - g_print("\n%s\n",parastart); - g_print("%s\n",pending->squote); - } - else - cnt_squot++; - } - g_free(pending->squote); - pending->squote=NULL; - } - if (pending->rbrack) - { - if (!pswit[OVERVIEW_SWITCH]) - { - if (pswit[ECHO_SWITCH]) - g_print("\n%s\n",parastart); - g_print("%s\n",pending->rbrack); - } - else - cnt_brack++; - g_free(pending->rbrack); - pending->rbrack=NULL; - } - if (pending->sbrack) - { - if (!pswit[OVERVIEW_SWITCH]) - { - if (pswit[ECHO_SWITCH]) - g_print("\n%s\n",parastart); - g_print("%s\n",pending->sbrack); - } - else - cnt_brack++; - g_free(pending->sbrack); - pending->sbrack=NULL; - } - if (pending->cbrack) - { - if (!pswit[OVERVIEW_SWITCH]) - { - if (pswit[ECHO_SWITCH]) - g_print("\n%s\n",parastart); - g_print("%s\n",pending->cbrack); - } - else - cnt_brack++; - g_free(pending->cbrack); - pending->cbrack=NULL; - } - if (pending->unders) - { - if (!pswit[OVERVIEW_SWITCH]) - { - if (pswit[ECHO_SWITCH]) - g_print("\n%s\n",parastart); - g_print("%s\n",pending->unders); - } - else - cnt_brack++; - g_free(pending->unders); - pending->unders=NULL; - } -} - -/* - * check_for_mismatched_quotes: - * - * At end of paragraph, check for mismatched quotes. - * - * We don't want to report an error immediately, since it is a - * common convention to omit the quotes at end of paragraph if - * the next paragraph is a continuation of the same speaker. - * Where this is the case, the next para should begin with a - * quote, so we store the warning message and only display it - * at the top of the next iteration if the new para doesn't - * start with a quote. - * The -p switch overrides this default, and warns of unclosed - * quotes on _every_ paragraph, whether the next begins with a - * quote or not. - */ -void check_for_mismatched_quotes(const struct counters *counters, - struct pending *pending) -{ - int squote_straight,squote_curved; - if (counters->quot%2) - pending->dquote= - g_strdup_printf(" Line %ld - Mismatched quotes",linecnt); - if (pswit[SQUOTE_SWITCH]) - { - if (matching_count(counters,CHAR_SQUOTE,TRUE)) - squote_straight=matching_difference(counters,CHAR_SQUOTE); - else - squote_straight=0; - if (matching_count(counters,CHAR_LS_QUOTE,TRUE)) - squote_curved=matching_difference(counters,CHAR_LS_QUOTE); - else - squote_curved=0; - if (squote_straight || squote_curved) - pending->squote= - g_strdup_printf(" Line %ld - Mismatched singlequotes?", - linecnt); - if (squote_straight && squote_straight!=1 || - squote_curved && squote_curved!=1) - /* - * Flag it to be noted regardless of the - * first char of the next para. - */ - pending->squot=1; - } - if (matching_difference(counters,CHAR_OPEN_RBRACK)) - pending->rbrack= - g_strdup_printf(" Line %ld - Mismatched round brackets?",linecnt); - if (matching_difference(counters,CHAR_OPEN_SBRACK)) - pending->sbrack= - g_strdup_printf(" Line %ld - Mismatched square brackets?",linecnt); - if (matching_difference(counters,CHAR_OPEN_CBRACK)) - pending->cbrack= - g_strdup_printf(" Line %ld - Mismatched curly brackets?",linecnt); - if (counters->c_unders%2) - pending->unders= - g_strdup_printf(" Line %ld - Mismatched underscores?",linecnt); -} - -/* * check_for_omitted_punctuation: * * Check for omitted punctuation at end of paragraph by working back @@ -2693,7 +2548,6 @@ } checked_linecnt++; print_pending(aline,parastart,&pending); - memset(&pending,0,sizeof(pending)); isemptyline=analyse_quotes(aline,&counters); if (isnewpara && !isemptyline) { @@ -2774,7 +2628,7 @@ if (isemptyline) { check_for_mismatched_quotes(&counters,&pending); - memset(&counters,0,sizeof(counters)); + counters_reset(&counters); /* let the next iteration know that it's starting a new para */ isnewpara=TRUE; if (prevline) @@ -2783,6 +2637,10 @@ g_free(prevline); prevline=g_strdup(aline); } + linecnt++; + check_for_mismatched_quotes(&counters,&pending); + print_pending(NULL,parastart,&pending); + reset_pending(&pending); if (prevline) { g_free(prevline); diff -r 7a62c77a0dbe -r 9fb13a5dde3b bookloupe/bookloupe.h --- a/bookloupe/bookloupe.h Sat Sep 21 23:40:18 2013 +0100 +++ b/bookloupe/bookloupe.h Mon Sep 23 21:18:27 2013 +0100 @@ -79,9 +79,10 @@ int dquote,squote; }; -struct pending { - char *dquote,*squote,*rbrack,*sbrack,*cbrack,*unders; - long squot; -}; +extern gboolean pswit[SWITNO]; + +extern long cnt_dquot,cnt_squot,cnt_brack,cnt_bin,cnt_odd,cnt_long,cnt_short; +extern long cnt_punct,cnt_dash,cnt_word,cnt_html,cnt_lineend,cnt_spacend; +extern long linecnt,checked_linecnt; #endif /* BOOKOUPE_H */ diff -r 7a62c77a0dbe -r 9fb13a5dde3b bookloupe/counters.c --- a/bookloupe/counters.c Sat Sep 21 23:40:18 2013 +0100 +++ b/bookloupe/counters.c Mon Sep 23 21:18:27 2013 +0100 @@ -1,4 +1,5 @@ #include +#include #include #include "bookloupe.h" #include "counters.h" @@ -44,9 +45,9 @@ return GINT_TO_POINTER((gint)CHAR_SQUOTE); else if (ch==CHAR_LS_QUOTE || ch==CHAR_RS_QUOTE) return GINT_TO_POINTER((gint)CHAR_LS_QUOTE); - else + else if (ch<0x4000 || ch-0x4000>=NO_SPECIAL_COUNTERS) { - g_warning("Matching pair not found for U+%04"G_GINT32_FORMAT"X",ch); + g_warning("Matching pair not found for U+%04" G_GINT32_MODIFIER "X",ch); return GINT_TO_POINTER((gint)ch); } } @@ -96,6 +97,13 @@ return value->open-value->close; } +void counters_reset(struct counters *counters) +{ + if (counters->matching) + g_tree_destroy(counters->matching); + memset(counters,0,sizeof(*counters)); +} + void counters_destroy(struct counters *counters) { if (counters->matching) diff -r 7a62c77a0dbe -r 9fb13a5dde3b bookloupe/counters.h --- a/bookloupe/counters.h Sat Sep 21 23:40:18 2013 +0100 +++ b/bookloupe/counters.h Mon Sep 23 21:18:27 2013 +0100 @@ -3,6 +3,12 @@ #include +/* Special counters live in the private use area */ +enum { + COUNTER_ILLUSTRATION=0xE000, + NO_SPECIAL_COUNTERS +}; + struct counters { GTree *matching; long quot; @@ -12,6 +18,7 @@ void increment_matching(struct counters *counters,gunichar ch,gboolean open); int matching_count(const struct counters *counters,gunichar ch,gboolean open); int matching_difference(const struct counters *counters,gunichar ch); +void counters_reset(struct counters *counters); void counters_destroy(struct counters *counters); #endif /* COUNTERS_H */ diff -r 7a62c77a0dbe -r 9fb13a5dde3b bookloupe/pending.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bookloupe/pending.c Mon Sep 23 21:18:27 2013 +0100 @@ -0,0 +1,239 @@ +#include +#include +#include +#include "bookloupe.h" +#include "pending.h" + +/* + * print_pending: + * + * If we are in a state of unbalanced quotes, and this line + * doesn't begin with a quote, output the stored error message. + * If the -p switch was used, print the warning even if the + * new para starts with quotes. + */ +void print_pending(const char *aline,const char *parastart, + struct pending *pending) +{ + const char *s; + gunichar c; + if (aline) + { + s=aline; + while (*s==' ') + s++; + c=g_utf8_get_char(s); + } + else + { + s=NULL; + c='\0'; + } + if (pending->illustration.warning_text) + { + if (aline) + { + if (pswit[ECHO_SWITCH] && !pending->illustration.queried_line) + pending->illustration.queried_line=g_strdup(parastart); + } + else + { + if (!pswit[OVERVIEW_SWITCH]) + { + if (pending->illustration.queried_line) + g_print("\n%s\n",pending->illustration.queried_line); + g_print("%s\n",pending->illustration.warning_text); + } + else + cnt_brack++; + g_free(pending->illustration.warning_text); + pending->illustration.warning_text=NULL; + g_free(pending->illustration.queried_line); + pending->illustration.queried_line=NULL; + } + } + if (pending->dquote) + { + if (c!=CHAR_DQUOTE || pswit[QPARA_SWITCH]) + { + if (!pswit[OVERVIEW_SWITCH]) + { + if (pswit[ECHO_SWITCH]) + g_print("\n%s\n",parastart); + g_print("%s\n",pending->dquote); + } + else + cnt_dquot++; + } + g_free(pending->dquote); + pending->dquote=NULL; + } + if (pending->squote) + { + if (!CHAR_IS_SQUOTE(c) || pswit[QPARA_SWITCH] || pending->squot) + { + if (!pswit[OVERVIEW_SWITCH]) + { + if (pswit[ECHO_SWITCH]) + g_print("\n%s\n",parastart); + g_print("%s\n",pending->squote); + } + else + cnt_squot++; + } + g_free(pending->squote); + pending->squote=NULL; + } + if (pending->rbrack) + { + if (!pswit[OVERVIEW_SWITCH]) + { + if (pswit[ECHO_SWITCH]) + g_print("\n%s\n",parastart); + g_print("%s\n",pending->rbrack); + } + else + cnt_brack++; + g_free(pending->rbrack); + pending->rbrack=NULL; + } + if (pending->sbrack) + { + if (!pswit[OVERVIEW_SWITCH]) + { + if (pswit[ECHO_SWITCH]) + g_print("\n%s\n",parastart); + g_print("%s\n",pending->sbrack); + } + else + cnt_brack++; + g_free(pending->sbrack); + pending->sbrack=NULL; + } + if (pending->cbrack) + { + if (!pswit[OVERVIEW_SWITCH]) + { + if (pswit[ECHO_SWITCH]) + g_print("\n%s\n",parastart); + g_print("%s\n",pending->cbrack); + } + else + cnt_brack++; + g_free(pending->cbrack); + pending->cbrack=NULL; + } + if (pending->unders) + { + if (!pswit[OVERVIEW_SWITCH]) + { + if (pswit[ECHO_SWITCH]) + g_print("\n%s\n",parastart); + g_print("%s\n",pending->unders); + } + else + cnt_brack++; + g_free(pending->unders); + pending->unders=NULL; + } +} + +void reset_pending(struct pending *pending) +{ + memset(pending,0,sizeof(*pending)); +} + +/* + * check_for_mismatched_quotes: + * + * At end of paragraph, check for mismatched quotes. + * + * We don't want to report an error immediately, since it is a + * common convention to omit the quotes at end of paragraph if + * the next paragraph is a continuation of the same speaker. + * Where this is the case, the next para should begin with a + * quote, so we store the warning message and only display it + * at the top of the next iteration if the new para doesn't + * start with a quote. + * The -p switch overrides this default, and warns of unclosed + * quotes on _every_ paragraph, whether the next begins with a + * quote or not. + */ +void check_for_mismatched_quotes(const struct counters *counters, + struct pending *pending) +{ + int squote_straight,squote_curved,difference; + if (counters->quot%2) + pending->dquote= + g_strdup_printf(" Line %ld - Mismatched quotes",linecnt); + if (pswit[SQUOTE_SWITCH]) + { + if (matching_count(counters,CHAR_SQUOTE,TRUE)) + squote_straight=matching_difference(counters,CHAR_SQUOTE); + else + squote_straight=0; + if (matching_count(counters,CHAR_LS_QUOTE,TRUE)) + squote_curved=matching_difference(counters,CHAR_LS_QUOTE); + else + squote_curved=0; + if (squote_straight || squote_curved) + pending->squote= + g_strdup_printf(" Line %ld - Mismatched singlequotes?", + linecnt); + if (squote_straight && squote_straight!=1 || + squote_curved && squote_curved!=1) + /* + * Flag it to be noted regardless of the + * first char of the next para. + */ + pending->squot=1; + } + difference=matching_difference(counters,COUNTER_ILLUSTRATION); + if (difference) + { + if (difference<0 && pending->illustration.warning_text) + { + difference++; + g_free(pending->illustration.queried_line); + pending->illustration.queried_line=NULL; + g_free(pending->illustration.warning_text); + pending->illustration.warning_text=NULL; + } + if (difference<0) + { + increment_matching(counters,CHAR_OPEN_SBRACK,FALSE); + difference++; + } + if (difference) + { + if (pending->illustration.warning_text) + { + if (!pswit[OVERVIEW_SWITCH]) + { + if (pending->illustration.queried_line) + g_print("\n%s\n",pending->illustration.queried_line); + g_print("%s\n",pending->illustration.warning_text); + } + else + cnt_brack++; + g_free(pending->illustration.warning_text); + } + pending->illustration.warning_text=g_strdup_printf( + " Line %ld - Mismatched illustration tag?",linecnt); + g_free(pending->illustration.queried_line); + pending->illustration.queried_line=NULL; + } + } + if (matching_difference(counters,CHAR_OPEN_RBRACK)) + pending->rbrack= + g_strdup_printf(" Line %ld - Mismatched round brackets?",linecnt); + if (matching_difference(counters,CHAR_OPEN_SBRACK)) + pending->sbrack= + g_strdup_printf(" Line %ld - Mismatched square brackets?",linecnt); + if (matching_difference(counters,CHAR_OPEN_CBRACK)) + pending->cbrack= + g_strdup_printf(" Line %ld - Mismatched curly brackets?",linecnt); + if (counters->c_unders%2) + pending->unders= + g_strdup_printf(" Line %ld - Mismatched underscores?",linecnt); +} diff -r 7a62c77a0dbe -r 9fb13a5dde3b bookloupe/pending.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bookloupe/pending.h Mon Sep 23 21:18:27 2013 +0100 @@ -0,0 +1,23 @@ +#ifndef PENDING_H +#define PENDING_H + +#include "counters.h" + +struct pending_warning { + char *queried_line; + char *warning_text; +}; + +struct pending { + char *dquote,*squote,*rbrack,*sbrack,*cbrack,*unders; + long squot; + struct pending_warning illustration; +}; + +void print_pending(const char *aline,const char *parastart, + struct pending *pending); +void reset_pending(struct pending *pending); +void check_for_mismatched_quotes(const struct counters *counters, + struct pending *pending); + +#endif /* PENDING_H */ diff -r 7a62c77a0dbe -r 9fb13a5dde3b test/bookloupe/Makefile.am --- a/test/bookloupe/Makefile.am Sat Sep 21 23:40:18 2013 +0100 +++ b/test/bookloupe/Makefile.am Mon Sep 23 21:18:27 2013 +0100 @@ -1,5 +1,5 @@ TESTS_ENVIRONMENT=BOOKLOUPE=../../bookloupe/bookloupe ../harness/loupe-test TESTS=non-ascii.tst long-line.tst curved-single-quotes.tst \ - curved-genitives.tst + curved-genitives.tst multi-line-illustration.tst dist_pkgdata_DATA=$(TESTS) diff -r 7a62c77a0dbe -r 9fb13a5dde3b test/bookloupe/multi-line-illustration.tst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/bookloupe/multi-line-illustration.tst Mon Sep 23 21:18:27 2013 +0100 @@ -0,0 +1,29 @@ +**************** INPUT **************** +[Illustration: One or more Caption lines + +One or more Sub-caption lines] + +[Illustration: The first line of a caption. + +A caption that contains balanced [square] brackets in a paragraph.] + +[Square brackets can be used to group several paragraphs. + +This will generate warnings as normal.] + +[Illustration: An ill-formed illustration might confuse. + +It generates warnings.] The opening and closing tags no longer match. +**************** WARNINGS **************** + + + + + + Mismatched square brackets? + + + + Mismatched illustration tag? + + diff -r 7a62c77a0dbe -r 9fb13a5dde3b test/compatibility/example.tst --- a/test/compatibility/example.tst Sat Sep 21 23:40:18 2013 +0100 +++ b/test/compatibility/example.tst Mon Sep 23 21:18:27 2013 +0100 @@ -33,6 +33,8 @@ travels were profitable to himself. The fact is, that tbere are cousins who come to greatness and rnust be pacified, or they will prove annoying. Heaven forefend a collision between cousins! + + **************** EXPECTED **************** Japan, China, Australia , nay, the continent of Europe, holding an @@ -85,3 +87,6 @@ cousins who come to greatness and rnust be pacified, or they will Line 33 column 34 - Query word rnust - not reporting duplicates + +correspond with some of them. On the whole, forgetting two or + Line 35 - Mismatched quotes diff -r 7a62c77a0dbe -r 9fb13a5dde3b test/harness/testcase.c --- a/test/harness/testcase.c Sat Sep 21 23:40:18 2013 +0100 +++ b/test/harness/testcase.c Mon Sep 23 21:18:27 2013 +0100 @@ -469,13 +469,7 @@ g_error_free(error); return FALSE; } - if (testcase->expected || testcase->warnings) - r=testcase_spawn_bookloupe(testcase,&output,&error); - else - { - r=testcase_spawn_bookloupe(testcase,NULL,&error); - output=NULL; - } + r=testcase_spawn_bookloupe(testcase,&output,&error); if (!r) { g_print("%s: FAIL\n",testcase->basename); @@ -492,37 +486,33 @@ g_error_free(error); return FALSE; } - if (testcase->expected || testcase->warnings) + header=g_string_new("\n\nFile: "); + g_string_append(header,filename); + g_string_append(header,"\n"); + if (!g_str_has_prefix(output,header->str)) { - header=g_string_new("\n\nFile: "); - g_string_append(header,filename); - g_string_append(header,"\n"); - if (!g_str_has_prefix(output,header->str)) + g_print("%s: FAIL\n",testcase->basename); + g_print("Unexpected header from bookloupe:\n"); + offset=common_prefix_length(output,header->str); + print_unexpected(output,offset); + r=FALSE; + } + pos=header->len; + if (r) + { + /* Skip the summary */ + s=strstr(output+pos,"\n\n"); + if (s) + pos=s-output+2; + else { g_print("%s: FAIL\n",testcase->basename); - g_print("Unexpected header from bookloupe:\n"); - offset=common_prefix_length(output,header->str); - print_unexpected(output,offset); + g_print("Unterminated summary from bookloupe:\n%s\n",output+pos); r=FALSE; } - pos=header->len; - if (r) - { - /* Skip the summary */ - s=strstr(output+pos,"\n\n"); - if (s) - pos=s-output+2; - else - { - g_print("%s: FAIL\n",testcase->basename); - g_print("Unterminated summary from bookloupe:\n%s\n", - output+pos); - r=FALSE; - } - } - g_string_free(header,TRUE); - r=testcase_check_warnings(testcase,output+pos,&xfail); } + g_string_free(header,TRUE); + r=testcase_check_warnings(testcase,output+pos,&xfail); g_free(filename); g_free(output); if (r)