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