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