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 <gfc@altern.org>
21 /*********************************
22 * UTF-8 and filenames handling. *
23 *********************************/
27 #include <string.h> /* memcpy(), strlen(), strstr() */
29 /* The returned string should not be freed. */
30 const gchar
*add_mnemonic(const gchar
* str
)
32 static gchar
*result
= NULL
;
34 const gchar
*ptr
= NULL
, *end
;
37 for (ptr
= str
; *ptr
!= '\0'; ptr
= g_utf8_next_char(ptr
))
38 if (g_unichar_isalnum(g_utf8_get_char(ptr
)))
41 end
= ptr
+ strlen(ptr
);
45 * No g_unichar_isalnum() were found,
46 * we add the underscore in front.
50 /* + 2: '_' and '\0'. */
51 new_size
= end
- str
+ 2;
52 if (new_size
> size
) {
56 result
= g_new(gchar
, size
);
59 memcpy(result
, str
, ptr
- str
);
60 result
[ptr
- str
] = '_';
61 memcpy(result
+ (ptr
- str
) + 1, ptr
, end
- ptr
+ 1);
66 static gboolean
str_is_ascii(const gchar
* str
)
68 while (*str
!= '\0') {
78 /* The returned string should not be freed. */
79 const gchar
*locale_to_utf8(const gchar
* str
)
81 static gchar
*result
= NULL
;
84 if (str_is_ascii(str
))
89 result
= g_locale_to_utf8(str
, -1, NULL
, NULL
, &err
);
91 g_printerr("%s\n", err
->message
);
102 static gboolean
is_clean(const gchar
* filename
)
104 if (filename
[0] != '/' && (filename
[0] != '.' || filename
[1] != '/'))
107 return strstr(filename
, "//") == NULL
&& strstr(filename
, "/./") == NULL
;
110 gchar
*clean_filename(const gchar
* filename
)
112 gchar
*orig_copy
, *copy
, *ptr
, *new, *new_ptr
;
113 gint count
= 0, len
= 0;
116 if (is_clean(filename
))
117 return g_strdup(filename
);
119 /* We work on a copy as we may modify it. */
120 orig_copy
= copy
= g_strdup(filename
);
122 if (copy
[0] == '/') {
123 /* Absolute filename. */
124 while (copy
[1] == '/')
129 /* Relative filename. */
130 gboolean finished
= FALSE
;
132 while (finished
== FALSE
) {
154 * "path1/./path2" is replaced with "path1///path2".
155 * "./" and "//" are counted.
157 for (ptr
= copy
; *ptr
!= '\0'; ptr
++) {
174 /* The filename was clean. */
177 if (orig_copy
!= copy
)
178 /* The filename started with "//". */
179 g_memmove(orig_copy
, copy
, len
+ 1);
184 /* The relative filename just lacked the "./" in the beginning. */
185 new = fast_build_filename(".", copy
);
190 /* We now have to remove the "//". */
193 new = g_new(gchar
, len
- count
+ 1);
196 new = g_new(gchar
, len
- count
+ 3);
202 for (ptr
= copy
; *ptr
!= '\0'; ptr
++)
203 if (ptr
[0] != '/' || ptr
[1] != '/') {
215 gchar
*clean_filename_free(gchar
* filename
)
219 if (filename
[0] == '\0' || is_clean(filename
))
222 clean
= clean_filename(filename
);
229 gchar
*fast_build_filename(const gchar
* dir
, const gchar
* file
)
232 return g_strdup(file
);
235 return g_strdup(dir
);
237 return g_strconcat(dir
, "/", file
, NULL
);
240 gchar
*str_escape(const gchar
* str
)
242 static gboolean
*no_problem
= NULL
;
247 if (no_problem
== NULL
) {
251 no_problem
= g_new0(gboolean
, 256);
253 no_problem
['/'] = TRUE
;
255 for (i
= '0'; i
<= '9'; i
++)
256 no_problem
[i
] = TRUE
;
258 for (i
= 'A'; i
<= 'Z'; i
++)
259 no_problem
[i
] = TRUE
;
261 for (i
= 'a'; i
<= 'z'; i
++)
262 no_problem
[i
] = TRUE
;
265 buffer_length
= strlen(str
) * 2 + 1;
266 buffer
= g_new(gchar
, buffer_length
);
268 escaped_ptr
= buffer
;
270 while (*str
!= '\0') {
271 if (no_problem
[(gint
) (*str
)] == FALSE
)
272 *escaped_ptr
++ = '\\';
274 *escaped_ptr
++ = *str
++;