2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 * See the COPYING file for license information.
18 * Guillaume Chazarain <guichaz@gmail.com>
21 /*****************************************
22 * Try to add unique mnemonics to labels *
23 *****************************************/
25 #include <string.h> /* strlen(), memcpy() */
28 #include "mnemonics.h"
29 #include "str_utils.h"
31 static GSList
*stack
= NULL
;
32 static GHashTable
*mnemonics
= NULL
;
34 static gint
count_underscores(const gchar
* str
, gint len
)
36 gint nb_underscores
= 0;
37 const gulong
*long_ptr
;
39 while ((gulong
) str
& (sizeof(gulong
) - 1))
42 return nb_underscores
;
53 long_ptr
= (gulong
*) str
;
55 while (len
>= sizeof(gulong
)) {
56 gulong masked
= *long_ptr
^ LONG_MASK(0x5F5F5F5FL
, 0x5F5F5F5F5F5F5F5FL
);
58 if (HAS_ZERO(masked
)) {
59 /* A '_' has been detected. */
60 gchar
*char_ptr
= (gchar
*) & masked
;
62 for (i
= 0; i
< sizeof(gulong
); i
++)
63 nb_underscores
+= (*char_ptr
++ == 0);
67 len
-= sizeof(gulong
);
70 str
= (const gchar
*) long_ptr
;
72 nb_underscores
+= (*str
== '_');
77 return nb_underscores
;
80 static const gchar
*find_mnemonic_position(const gchar
* str
)
84 for (ptr
= str
; *ptr
!= '\0'; ptr
= g_utf8_next_char(ptr
)) {
85 gunichar ch
= g_unichar_tolower(g_utf8_get_char(ptr
));
86 gpointer ch_key
= GINT_TO_POINTER(ch
);
88 if (g_unichar_isalnum(ch
)) {
89 if (mnemonics
== NULL
) {
90 mnemonics
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
91 g_hash_table_insert(mnemonics
, ch_key
, mnemonics
);
95 if (g_hash_table_lookup(mnemonics
, ch_key
) == NULL
) {
96 g_hash_table_insert(mnemonics
, ch_key
, mnemonics
);
102 /* No position found, add in front. */
107 * Underscores in labels are replaced with mnemonics, so we duplicate them.
108 * The caller has to determine whether the returned string has to be freed.
110 static gchar
*duplicate_underscores(const gchar
* orig
)
112 gint nb_underscores
, len
;
113 const gchar
*ptr_orig
;
114 gchar
*new, *ptr_new
;
116 /* How many underscores? */
118 nb_underscores
= count_underscores(orig
, len
);
119 len
+= nb_underscores
;
121 if (nb_underscores
== 0)
122 return (gchar
*) orig
;
124 ptr_new
= new = g_new(gchar
, len
+ 1);
126 for (ptr_orig
= orig
; *ptr_orig
!= '\0'; ptr_orig
++) {
127 *ptr_new
= *ptr_orig
;
128 if (*ptr_orig
== '_') {
129 /* Duplicate this one. */
142 * The returned string should not be freed. We keep track of already used
143 * mnemonics to avoid giving twice the same letter.
145 const gchar
*add_mnemonic(const gchar
* str
)
147 static gchar
*result
= NULL
;
148 static gint size
= 0;
149 const gchar
*mnemonic_pos
, *end
;
150 gint new_size
, offset
;
153 work
= duplicate_underscores(str
);
154 mnemonic_pos
= find_mnemonic_position(work
);
155 end
= mnemonic_pos
+ strlen(mnemonic_pos
);
157 /* + 2: '_' and '\0'. */
158 new_size
= end
- work
+ 2;
159 if (new_size
> size
) {
163 result
= g_new(gchar
, size
);
166 offset
= mnemonic_pos
- work
;
167 memcpy(result
, work
, offset
);
168 result
[offset
] = '_';
169 memcpy(result
+ offset
+ 1, mnemonic_pos
, end
- mnemonic_pos
+ 1);
177 void reset_mnemonics(void)
179 if (mnemonics
!= NULL
) {
180 g_hash_table_destroy(mnemonics
);
185 void push_mnemonics(void)
187 stack
= g_slist_prepend(stack
, mnemonics
);
191 void pop_mnemonics(void)
194 mnemonics
= g_slist_nth_data(stack
, 0);
195 stack
= g_slist_delete_link(stack
, stack
);