Fix bug #36: Document workaround to prevent Guiguts conversion of utf-8 files passed to Bookloupe
7 struct matching_counter {
11 GQuark counters_error_quark(void)
15 quark=g_quark_from_static_string("counters_error");
19 static struct matching_counter *matching_counter_new(void)
21 return g_slice_new0(struct matching_counter);
24 static void matching_counter_free(struct matching_counter *counter)
26 g_slice_free(struct matching_counter,counter);
29 static gint compar_unichars(gconstpointer a,gconstpointer b,gpointer unused)
32 * Unicode code points only go up to 0x10FFFF and thus this cannot overflow.
34 return GPOINTER_TO_INT(a)-GPOINTER_TO_INT(b);
38 * For matching characters, we maintain a count of the opens and closes.
39 * In the simplest case, we are dealing with a matching pair such as [ and ]
40 * where there is a 1:1 mapping between an instance of [ with an open and
41 * between an instance of ] with a close. matching_ket() is
42 * responsible for selecting an arbitary base character of a matching pair.
44 static gpointer matching_key(gunichar ch)
47 if (g_unichar_get_mirror_char(ch,&mirrored))
49 return GINT_TO_POINTER((gint)ch);
51 return GINT_TO_POINTER((gint)mirrored);
52 else if (ch==CHAR_SQUOTE || ch==CHAR_OPEN_SQUOTE)
53 return GINT_TO_POINTER((gint)CHAR_SQUOTE);
54 else if (ch==CHAR_LS_QUOTE || ch==CHAR_RS_QUOTE)
55 return GINT_TO_POINTER((gint)CHAR_LS_QUOTE);
56 else if (ch==CHAR_LD_QUOTE || ch==CHAR_RD_QUOTE)
57 return GINT_TO_POINTER((gint)CHAR_LD_QUOTE);
58 else if (ch==CHAR_DQUOTE)
59 return GINT_TO_POINTER((gint)ch);
60 else if (ch<0x4000 || ch-0x4000>=NO_SPECIAL_COUNTERS)
61 g_warning("Matching pair not found for U+%04" G_GINT32_MODIFIER "X",ch);
62 return GINT_TO_POINTER((gint)ch);
65 gboolean innermost_quote_matches(struct counters *counters,gunichar ch)
68 if (counters->open_quotes)
69 head=counters->open_quotes->data;
72 return head==matching_key(ch);
75 gboolean count_quote(struct counters *counters,gunichar ch,QuoteClass klass,
80 if (counters->open_quotes)
81 head=counters->open_quotes->data;
87 if (head!=matching_key(ch))
89 /* else fall through */
91 if (head!=matching_key(ch))
93 g_set_error(err,COUNTERS_ERROR,COUNTERS_ERROR_FAILED,
94 "Closing quotation mark with no matching open?");
98 counters->open_quotes=g_slist_delete_link(counters->open_quotes,
99 counters->open_quotes);
102 if (head==matching_key(ch))
104 g_set_error(err,COUNTERS_ERROR,COUNTERS_ERROR_FAILED,
105 "Directly nested quotation marks of same type?");
109 head=matching_key(ch);
110 counters->open_quotes=g_slist_prepend(counters->open_quotes,head);
116 void increment_matching(struct counters *counters,gunichar ch,gboolean open)
118 gpointer key,orig_key;
119 struct matching_counter *value;
120 if (!counters->matching)
121 counters->matching=g_tree_new_full(compar_unichars,NULL,NULL,
122 (GDestroyNotify)matching_counter_free);
123 key=matching_key(ch);
124 if (!g_tree_lookup_extended(counters->matching,key,&orig_key,
127 value=matching_counter_new();
128 g_tree_insert(counters->matching,key,value);
136 int matching_count(const struct counters *counters,gunichar ch,gboolean open)
138 struct matching_counter *value;
139 if (!counters->matching)
141 value=g_tree_lookup(counters->matching,matching_key(ch));
144 return open?value->open:value->close;
148 * Return open count - closed count
150 int matching_difference(const struct counters *counters,gunichar ch)
152 struct matching_counter *value;
153 if (!counters->matching)
155 value=g_tree_lookup(counters->matching,matching_key(ch));
158 return value->open-value->close;
161 void counters_reset(struct counters *counters)
163 if (counters->matching)
164 g_tree_destroy(counters->matching);
165 memset(counters,0,sizeof(*counters));
168 void counters_destroy(struct counters *counters)
170 if (counters->matching)
172 g_tree_destroy(counters->matching);
173 counters->matching=NULL;