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@yahoo.fr>
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 gulong himagic
, lomagic
, magic_bits
;
38 const gulong
*long_ptr
;
41 while ((gulong
) str
& (sizeof(gulong
) - 1))
44 return nb_underscores
;
55 long_ptr
= (gulong
*) str
;
60 if (sizeof(gulong
) > 4)
62 mask
= ((mask
<< 16) << 16) | mask
;
64 while (len
>= sizeof(gulong
)) {
67 masked
= *long_ptr
^ mask
;
68 if (HAS_ZERO(masked
)) {
69 /* A '_' has been detected. */
70 gchar
*char_ptr
= (gchar
*) & masked
;
71 nb_underscores
+= (*char_ptr
++ == 0);
72 nb_underscores
+= (*char_ptr
++ == 0);
73 nb_underscores
+= (*char_ptr
++ == 0);
74 nb_underscores
+= (*char_ptr
++ == 0);
75 if (sizeof(gulong
) > 4) {
77 nb_underscores
+= (*char_ptr
++ == 0);
78 nb_underscores
+= (*char_ptr
++ == 0);
79 nb_underscores
+= (*char_ptr
++ == 0);
80 nb_underscores
+= (*char_ptr
++ == 0);
85 len
-= sizeof(gulong
);
88 str
= (const gchar
*) long_ptr
;
90 nb_underscores
+= (*str
== '_');
95 return nb_underscores
;
98 static const gchar
*find_mnemonic_position(const gchar
* str
)
102 for (ptr
= str
; *ptr
!= '\0'; ptr
= g_utf8_next_char(ptr
)) {
103 gunichar ch
= g_unichar_tolower(g_utf8_get_char(ptr
));
104 gpointer ch_key
= GINT_TO_POINTER(ch
);
106 if (g_unichar_isalnum(ch
)) {
107 if (mnemonics
== NULL
) {
108 mnemonics
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
109 g_hash_table_insert(mnemonics
, ch_key
, mnemonics
);
113 if (g_hash_table_lookup(mnemonics
, ch_key
) == NULL
) {
114 g_hash_table_insert(mnemonics
, ch_key
, mnemonics
);
120 /* No position found, add in front. */
125 * Underscores in labels are replaced with mnemonics, so we duplicate them.
126 * The caller has to determine whether the returned string has to be freed.
128 static gchar
*duplicate_underscores(const gchar
* orig
)
130 gint nb_underscores
, len
;
131 const gchar
*ptr_orig
;
132 gchar
*new, *ptr_new
;
134 /* How many underscores? */
136 nb_underscores
= count_underscores(orig
, len
);
137 len
+= nb_underscores
;
139 if (nb_underscores
== 0)
140 return (gchar
*) orig
;
142 ptr_new
= new = g_new(gchar
, len
+ 1);
144 for (ptr_orig
= orig
; *ptr_orig
!= '\0'; ptr_orig
++) {
145 *ptr_new
= *ptr_orig
;
146 if (*ptr_orig
== '_') {
147 /* Duplicate this one. */
160 * The returned string should not be freed. We keep track of already used
161 * mnemonics to avoid giving twice the same letter.
163 const gchar
*add_mnemonic(const gchar
* str
)
165 static gchar
*result
= NULL
;
166 static gint size
= 0;
167 const gchar
*mnemonic_pos
, *end
;
168 gint new_size
, offset
;
171 work
= duplicate_underscores(str
);
172 mnemonic_pos
= find_mnemonic_position(work
);
173 end
= mnemonic_pos
+ strlen(mnemonic_pos
);
175 /* + 2: '_' and '\0'. */
176 new_size
= end
- work
+ 2;
177 if (new_size
> size
) {
181 result
= g_new(gchar
, size
);
184 offset
= mnemonic_pos
- work
;
185 memcpy(result
, work
, offset
);
186 result
[offset
] = '_';
187 memcpy(result
+ offset
+ 1, mnemonic_pos
, end
- mnemonic_pos
+ 1);
195 void reset_mnemonics(void)
197 if (mnemonics
!= NULL
) {
198 g_hash_table_destroy(mnemonics
);
203 void push_mnemonics(void)
205 stack
= g_slist_prepend(stack
, mnemonics
);
209 void pop_mnemonics(void)
212 mnemonics
= g_slist_nth_data(stack
, 0);
213 stack
= g_slist_delete_link(stack
, stack
);