bookloupe/counters.c
author ali <ali@juiblex.co.uk>
Sat Sep 21 23:40:18 2013 +0100 (2013-09-21)
changeset 92 7a62c77a0dbe
child 93 9fb13a5dde3b
permissions -rw-r--r--
Fix bug #6: BL treats a slanted apostrophe ? as a word separator, not as a contraction or possessive
     1 #include <stdlib.h>
     2 #include <glib.h>
     3 #include "bookloupe.h"
     4 #include "counters.h"
     5 
     6 struct matching_counter {
     7     int open,close;
     8 };
     9 
    10 static struct matching_counter *matching_counter_new(void)
    11 {
    12     return g_slice_new0(struct matching_counter);
    13 }
    14 
    15 static void matching_counter_free(struct matching_counter *counter)
    16 {
    17     g_slice_free(struct matching_counter,counter);
    18 }
    19 
    20 static gint compar_unichars(gconstpointer a,gconstpointer b,gpointer unused)
    21 {
    22     /*
    23      * Unicode code points only go up to 0x10FFFF and thus this cannot overflow.
    24      */
    25     return GPOINTER_TO_INT(a)-GPOINTER_TO_INT(b);
    26 }
    27 
    28 /*
    29  * For matching characters, we maintain a count of the opens and closes.
    30  * In the simplest case, we are dealing with a matching pair such as [ and ]
    31  * where there is a 1:1 mapping between an instance of [ with an open and
    32  * between an instance of ] with a close. matching_ket() is
    33  * responsible for selecting an arbitary base character of a matching pair.
    34  */
    35 static gpointer matching_key(gunichar ch)
    36 {
    37     gunichar mirrored;
    38     if (g_unichar_get_mirror_char(ch,&mirrored))
    39 	if (ch<mirrored)
    40 	    return GINT_TO_POINTER((gint)ch);
    41 	else
    42 	    return GINT_TO_POINTER((gint)mirrored);
    43     else if (ch==CHAR_SQUOTE || ch==CHAR_OPEN_SQUOTE)
    44 	return GINT_TO_POINTER((gint)CHAR_SQUOTE);
    45     else if (ch==CHAR_LS_QUOTE || ch==CHAR_RS_QUOTE)
    46 	return GINT_TO_POINTER((gint)CHAR_LS_QUOTE);
    47     else
    48     {
    49 	g_warning("Matching pair not found for U+%04"G_GINT32_FORMAT"X",ch);
    50 	return GINT_TO_POINTER((gint)ch);
    51     }
    52 }
    53 
    54 void increment_matching(struct counters *counters,gunichar ch,gboolean open)
    55 {
    56     gpointer key,orig_key;
    57     struct matching_counter *value;
    58     if (!counters->matching)
    59 	counters->matching=g_tree_new_full(compar_unichars,NULL,NULL,
    60 	  (GDestroyNotify)matching_counter_free);
    61     key=matching_key(ch);
    62     if (!g_tree_lookup_extended(counters->matching,key,&orig_key,
    63       (gpointer *)&value))
    64     {
    65 	value=matching_counter_new();
    66 	g_tree_insert(counters->matching,key,value);
    67     }
    68     if (open)
    69 	value->open++;
    70     else
    71 	value->close++;
    72 }
    73 
    74 int matching_count(const struct counters *counters,gunichar ch,gboolean open)
    75 {
    76     struct matching_counter *value;
    77     if (!counters->matching)
    78 	return 0;
    79     value=g_tree_lookup(counters->matching,matching_key(ch));
    80     if (!value)
    81 	return 0;
    82     return open?value->open:value->close;
    83 }
    84 
    85 /*
    86  * Return open count - closed count
    87  */
    88 int matching_difference(const struct counters *counters,gunichar ch)
    89 {
    90     struct matching_counter *value;
    91     if (!counters->matching)
    92 	return 0;
    93     value=g_tree_lookup(counters->matching,matching_key(ch));
    94     if (!value)
    95 	return 0;
    96     return value->open-value->close;
    97 }
    98 
    99 void counters_destroy(struct counters *counters)
   100 {
   101     if (counters->matching)
   102     {
   103 	g_tree_destroy(counters->matching);
   104 	counters->matching=NULL;
   105     }
   106 }