Mercurial > geeqie
annotate src/ui_fileops.c @ 40:dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
* pan-view.c: Add option to ignore symbolic links to folders when
creating file list (no gui control yet), and do not allow listing
the root folder as this introduces too many issues (for instance
how do we ignore special filesystems such as /proc using only stat
attributes?). Add fix to not show empty folders in the flower view.
* thumb_standard.c (thumb_loader_std_finish): Fix logic that caused
thumbnails to be saved for images with a size between normal and large
when using large thumbnails.
* ui_fileops.[ch]: Add utilities lstat_utf8 and islink.
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
##### an offical release when making enhancements and translation updates. #####
author | gqview |
---|---|
date | Sat, 16 Apr 2005 16:26:49 +0000 |
parents | d907d608745f |
children | 31759d770628 |
rev | line source |
---|---|
9 | 1 /* |
2 * (SLIK) SimpLIstic sKin functions | |
3 * (C) 2004 John Ellis | |
4 * | |
5 * Author: John Ellis | |
6 * | |
7 * This software is released under the GNU General Public License (GNU GPL). | |
8 * Please read the included file COPYING for more information. | |
9 * This software comes with no warranty of any kind, use at your own risk! | |
10 */ | |
11 | |
12 #ifdef HAVE_CONFIG_H | |
13 # include "config.h" | |
14 #endif | |
15 | |
16 #include <pwd.h> | |
17 #include <stdio.h> | |
18 #include <stdlib.h> | |
19 #include <string.h> | |
20 #include <unistd.h> | |
21 #include <sys/param.h> | |
22 #include <dirent.h> | |
23 #include <utime.h> | |
24 | |
25 #include <glib.h> | |
26 #include <gtk/gtk.h> /* for locale warning dialog */ | |
27 | |
28 #include "ui_fileops.h" | |
29 | |
30 #include "ui_utildlg.h" /* for locale warning dialog */ | |
31 | |
32 /* | |
33 *----------------------------------------------------------------------------- | |
34 * generic file information and manipulation routines (public) | |
35 *----------------------------------------------------------------------------- | |
36 */ | |
37 | |
38 /* file sorting method (case) */ | |
39 gint file_sort_case_sensitive = FALSE; | |
40 | |
41 | |
42 void print_term(const gchar *text_utf8) | |
43 { | |
44 gchar *text_l; | |
45 | |
46 text_l = g_locale_from_utf8(text_utf8, -1, NULL, NULL, NULL); | |
47 printf((text_l) ? text_l : text_utf8); | |
48 g_free(text_l); | |
49 } | |
50 | |
51 static void encoding_dialog(const gchar *path); | |
52 | |
53 static gint encoding_dialog_idle(gpointer data) | |
54 { | |
55 gchar *path = data; | |
56 | |
57 encoding_dialog(path); | |
58 g_free(path); | |
59 | |
60 return FALSE; | |
61 } | |
62 | |
63 static gint encoding_dialog_delay(gpointer data) | |
64 { | |
65 g_idle_add(encoding_dialog_idle, data); | |
66 | |
67 return 0; | |
68 } | |
69 | |
70 static void encoding_dialog(const gchar *path) | |
71 { | |
72 static gint warned_user = FALSE; | |
73 GenericDialog *gd; | |
74 GString *string; | |
75 const gchar *lc; | |
76 const gchar *bf; | |
77 | |
78 /* check that gtk is initialized (loop is level > 0) */ | |
79 if (gtk_main_level() == 0) | |
80 { | |
81 /* gtk not initialized */ | |
82 gtk_init_add(encoding_dialog_delay, g_strdup(path)); | |
83 return; | |
84 } | |
85 | |
86 if (warned_user) return; | |
87 warned_user = TRUE; | |
88 | |
89 lc = getenv("LANG"); | |
90 bf = getenv("G_BROKEN_FILENAMES"); | |
91 warned_user = TRUE; | |
92 | |
93 string = g_string_new(""); | |
94 g_string_append(string, "One or more filenames are not encoded with the preferred locale character set.\n"); | |
95 g_string_append_printf(string, "Operations on, and display of these files with %s may not succeed.\n\n", PACKAGE); | |
96 g_string_append(string, "If your filenames are not encoded in utf-8, try setting\n"); | |
97 g_string_append(string, "the environment variable G_BROKEN_FILENAMES=1\n"); | |
98 g_string_append_printf(string, "It appears G_BROKEN_FILENAMES is %s%s\n\n", | |
99 (bf) ? "set to " : "not set.", (bf) ? bf : ""); | |
100 g_string_append_printf(string, "The locale appears to be set to \"%s\"\n(set by the LANG environment variable)\n", (lc) ? lc : "undefined"); | |
101 if (lc && (strstr(lc, "UTF-8") || strstr(lc, "utf-8"))) | |
102 { | |
103 gchar *name; | |
104 name = g_convert(path, -1, "UTF-8", "ISO-8859-1", NULL, NULL, NULL); | |
105 string = g_string_append(string, "\nPreferred encoding appears to be UTF-8, however the file:\n"); | |
106 g_string_append_printf(string, "\"%s\"\n%s encoded in valid UTF-8.\n", | |
107 (name) ? name : "[name not displayable]", | |
108 (g_utf8_validate(path, -1, NULL)) ? "is": "is NOT"); | |
109 g_free(name); | |
110 } | |
111 | |
112 gd = generic_dialog_new("Filename encoding locale mismatch", | |
113 PACKAGE, "locale warning", NULL, TRUE, NULL, NULL); | |
114 generic_dialog_add_button(gd, GTK_STOCK_CLOSE, NULL, NULL, TRUE); | |
115 | |
116 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_WARNING, | |
117 "Filename encoding locale mismatch", string->str); | |
118 | |
119 gtk_widget_show(gd->dialog); | |
120 | |
121 g_string_free(string, TRUE); | |
122 } | |
123 | |
124 gchar *path_to_utf8(const gchar *path) | |
125 { | |
126 gchar *utf8; | |
127 GError *error = NULL; | |
128 | |
129 if (!path) return NULL; | |
130 | |
131 utf8 = g_filename_to_utf8(path, -1, NULL, NULL, &error); | |
132 if (error) | |
133 { | |
134 printf("Unable to convert filename to UTF-8:\n%s\n%s\n", path, error->message); | |
135 g_error_free(error); | |
136 encoding_dialog(path); | |
137 } | |
138 if (!utf8) | |
139 { | |
140 /* just let it through, but bad things may happen */ | |
141 utf8 = g_strdup(path); | |
142 } | |
143 | |
144 return utf8; | |
145 } | |
146 | |
147 gchar *path_from_utf8(const gchar *utf8) | |
148 { | |
149 gchar *path; | |
150 GError *error = NULL; | |
151 | |
152 if (!utf8) return NULL; | |
153 | |
154 path = g_filename_from_utf8(utf8, -1, NULL, NULL, &error); | |
155 if (error) | |
156 { | |
157 printf("Unable to convert filename to locale from UTF-8:\n%s\n%s\n", utf8, error->message); | |
158 g_error_free(error); | |
159 } | |
160 if (!path) | |
161 { | |
162 /* if invalid UTF-8, text probaby still in original form, so just copy it */ | |
163 path = g_strdup(utf8); | |
164 } | |
165 | |
166 return path; | |
167 } | |
168 | |
169 /* first we try the HOME environment var, if that doesn't work, we try getpwuid(). */ | |
170 const gchar *homedir(void) | |
171 { | |
172 static gchar *home = NULL; | |
173 | |
174 if (!home) | |
175 { | |
176 home = path_to_utf8(getenv("HOME")); | |
177 } | |
178 if (!home) | |
179 { | |
180 struct passwd *pw = getpwuid(getuid()); | |
181 if (pw) home = path_to_utf8(pw->pw_dir); | |
182 } | |
183 | |
184 return home; | |
185 } | |
186 | |
187 gint stat_utf8(const gchar *s, struct stat *st) | |
188 { | |
189 gchar *sl; | |
190 gint ret; | |
191 | |
192 if (!s) return FALSE; | |
193 sl = path_from_utf8(s); | |
194 ret = (stat(sl, st) == 0); | |
195 g_free(sl); | |
196 | |
197 return ret; | |
198 } | |
199 | |
40
dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
200 gint lstat_utf8(const gchar *s, struct stat *st) |
dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
201 { |
dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
202 gchar *sl; |
dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
203 gint ret; |
dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
204 |
dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
205 if (!s) return FALSE; |
dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
206 sl = path_from_utf8(s); |
dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
207 ret = (lstat(sl, st) == 0); |
dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
208 g_free(sl); |
dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
209 |
dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
210 return ret; |
dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
211 } |
dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
212 |
9 | 213 gint isname(const gchar *s) |
214 { | |
215 struct stat st; | |
216 | |
217 return stat_utf8(s, &st); | |
218 } | |
219 | |
220 gint isfile(const gchar *s) | |
221 { | |
222 struct stat st; | |
223 | |
224 return (stat_utf8(s, &st) && S_ISREG(st.st_mode)); | |
225 } | |
226 | |
227 gint isdir(const gchar *s) | |
228 { | |
229 struct stat st; | |
230 | |
231 return (stat_utf8(s ,&st) && S_ISDIR(st.st_mode)); | |
232 } | |
233 | |
40
dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
234 gint islink(const gchar *s) |
dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
235 { |
dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
236 struct stat st; |
dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
237 |
dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
238 return (lstat_utf8(s ,&st) && S_ISLNK(st.st_mode)); |
dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
239 } |
dcc04a6a58bf
Sat Apr 16 12:29:42 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
240 |
9 | 241 gint64 filesize(const gchar *s) |
242 { | |
243 struct stat st; | |
244 | |
245 if (!stat_utf8(s, &st)) return 0; | |
246 return (gint)st.st_size; | |
247 } | |
248 | |
249 time_t filetime(const gchar *s) | |
250 { | |
251 struct stat st; | |
252 | |
253 if (!stat_utf8(s, &st)) return 0; | |
254 return st.st_mtime; | |
255 } | |
256 | |
257 gint filetime_set(const gchar *s, time_t tval) | |
258 { | |
259 gint ret = FALSE; | |
260 | |
261 if (tval > 0) | |
262 { | |
263 struct utimbuf ut; | |
264 gchar *sl; | |
265 | |
266 ut.actime = ut.modtime = tval; | |
267 | |
268 sl = path_from_utf8(s); | |
269 ret = (utime(sl, &ut) == 0); | |
270 g_free(sl); | |
271 } | |
272 | |
273 return ret; | |
274 } | |
275 | |
276 gint access_file(const gchar *s, int mode) | |
277 { | |
278 gchar *sl; | |
279 gint ret; | |
280 | |
281 if (!s) return FALSE; | |
282 | |
283 sl = path_from_utf8(s); | |
284 ret = (access(sl, mode) == 0); | |
285 g_free(sl); | |
286 | |
287 return ret; | |
288 } | |
289 | |
290 gint unlink_file(const gchar *s) | |
291 { | |
292 gchar *sl; | |
293 gint ret; | |
294 | |
295 if (!s) return FALSE; | |
296 | |
297 sl = path_from_utf8(s); | |
298 ret = (unlink(sl) == 0); | |
299 g_free(sl); | |
300 | |
301 return ret; | |
302 } | |
303 | |
304 gint symlink_utf8(const gchar *source, const gchar *target) | |
305 { | |
306 gchar *sl; | |
307 gchar *tl; | |
308 gint ret; | |
309 | |
310 if (!source || !target) return FALSE; | |
311 | |
312 sl = path_from_utf8(source); | |
313 tl = path_from_utf8(target); | |
314 | |
315 ret = (symlink(sl, tl) == 0); | |
316 | |
317 g_free(sl); | |
318 g_free(tl); | |
319 | |
320 return ret; | |
321 } | |
322 | |
323 gint mkdir_utf8(const gchar *s, int mode) | |
324 { | |
325 gchar *sl; | |
326 gint ret; | |
327 | |
328 if (!s) return FALSE; | |
329 | |
330 sl = path_from_utf8(s); | |
331 ret = (mkdir(sl, mode) == 0); | |
332 g_free(sl); | |
333 return ret; | |
334 } | |
335 | |
336 gint rmdir_utf8(const gchar *s) | |
337 { | |
338 gchar *sl; | |
339 gint ret; | |
340 | |
341 if (!s) return FALSE; | |
342 | |
343 sl = path_from_utf8(s); | |
344 ret = (rmdir(sl) == 0); | |
345 g_free(sl); | |
346 | |
347 return ret; | |
348 } | |
349 | |
350 gint copy_file_attributes(const gchar *s, const gchar *t, gint perms, gint mtime) | |
351 { | |
352 struct stat st; | |
353 gchar *sl, *tl; | |
354 gint ret = FALSE; | |
355 | |
356 if (!s || !t) return FALSE; | |
357 | |
358 sl = path_from_utf8(s); | |
359 tl = path_from_utf8(t); | |
360 | |
361 if (stat(sl, &st) == 0) | |
362 { | |
363 struct utimbuf tb; | |
364 | |
365 ret = TRUE; | |
366 | |
367 /* set the dest file attributes to that of source (ignoring errors) */ | |
368 | |
369 if (perms && chown(tl, st.st_uid, st.st_gid) < 0) ret = FALSE; | |
370 if (perms && chmod(tl, st.st_mode) < 0) ret = FALSE; | |
371 | |
372 tb.actime = st.st_atime; | |
373 tb.modtime = st.st_mtime; | |
374 if (mtime && utime(tl, &tb) < 0) ret = FALSE; | |
375 } | |
376 | |
377 g_free(sl); | |
378 g_free(tl); | |
379 | |
380 return ret; | |
381 } | |
382 | |
383 /* paths are in filesystem encoding */ | |
384 static gint hard_linked(const gchar *a, const gchar *b) | |
385 { | |
386 struct stat sta; | |
387 struct stat stb; | |
388 | |
389 if (stat(a, &sta) != 0 || stat(b, &stb) != 0) return FALSE; | |
390 | |
391 return (sta.st_dev == stb.st_dev && | |
392 sta.st_ino == stb.st_ino); | |
393 } | |
394 | |
395 gint copy_file(const gchar *s, const gchar *t) | |
396 { | |
397 FILE *fi = NULL; | |
398 FILE *fo = NULL; | |
399 gchar *sl, *tl; | |
400 gchar buf[4096]; | |
401 gint b; | |
402 | |
403 sl = path_from_utf8(s); | |
404 tl = path_from_utf8(t); | |
405 | |
406 if (hard_linked(sl, tl)) | |
407 { | |
408 g_free(sl); | |
409 g_free(tl); | |
410 return TRUE; | |
411 } | |
412 | |
413 fi = fopen(sl, "rb"); | |
414 if (fi) | |
415 { | |
416 fo = fopen(tl, "wb"); | |
417 if (!fo) | |
418 { | |
419 fclose(fi); | |
420 fi = NULL; | |
421 } | |
422 } | |
423 | |
424 g_free(sl); | |
425 g_free(tl); | |
426 | |
427 if (!fi || !fo) return FALSE; | |
428 | |
429 while((b = fread(buf, sizeof(char), 4096, fi)) && b != 0) | |
430 { | |
431 if (fwrite(buf, sizeof(char), b, fo) != b) | |
432 { | |
433 fclose(fi); | |
434 fclose(fo); | |
435 return FALSE; | |
436 } | |
437 } | |
438 | |
439 fclose(fi); | |
440 fclose(fo); | |
441 | |
442 copy_file_attributes(s, t, TRUE, TRUE); | |
443 | |
444 return TRUE; | |
445 } | |
446 | |
447 gint move_file(const gchar *s, const gchar *t) | |
448 { | |
449 gchar *sl, *tl; | |
450 gint ret = TRUE; | |
451 | |
452 if (!s || !t) return FALSE; | |
453 | |
454 sl = path_from_utf8(s); | |
455 tl = path_from_utf8(t); | |
456 if (rename(sl, tl) < 0) | |
457 { | |
458 /* this may have failed because moving a file across filesystems | |
459 was attempted, so try copy and delete instead */ | |
460 if (copy_file(s, t)) | |
461 { | |
462 if (unlink(sl) < 0) | |
463 { | |
464 /* err, now we can't delete the source file so return FALSE */ | |
465 ret = FALSE; | |
466 } | |
467 } | |
468 else | |
469 { | |
470 ret = FALSE; | |
471 } | |
472 } | |
473 g_free(sl); | |
474 g_free(tl); | |
475 | |
476 return ret; | |
477 } | |
478 | |
479 gint rename_file(const gchar *s, const gchar *t) | |
480 { | |
481 gchar *sl, *tl; | |
482 gint ret; | |
483 | |
484 if (!s || !t) return FALSE; | |
485 | |
486 sl = path_from_utf8(s); | |
487 tl = path_from_utf8(t); | |
488 ret = (rename(sl, tl) == 0); | |
489 g_free(sl); | |
490 g_free(tl); | |
491 | |
492 return ret; | |
493 } | |
494 | |
495 gchar *get_current_dir(void) | |
496 { | |
497 gchar *pathl; | |
498 gchar *path8; | |
499 | |
500 pathl = g_get_current_dir(); | |
501 path8 = path_to_utf8(pathl); | |
502 g_free(pathl); | |
503 | |
504 return path8; | |
505 } | |
506 | |
507 gint path_list(const gchar *path, GList **files, GList **dirs) | |
508 { | |
509 DIR *dp; | |
510 struct dirent *dir; | |
511 struct stat ent_sbuf; | |
512 GList *f_list = NULL; | |
513 GList *d_list = NULL; | |
514 gchar *pathl; | |
515 | |
516 if (!path) return FALSE; | |
517 | |
518 pathl = path_from_utf8(path); | |
519 dp = opendir(pathl); | |
520 if (!dp) | |
521 { | |
522 /* dir not found */ | |
523 g_free(pathl); | |
524 return FALSE; | |
525 } | |
526 | |
527 /* root dir fix */ | |
528 if (pathl[0] == '/' && pathl[1] == '\0') | |
529 { | |
530 g_free(pathl); | |
531 pathl = g_strdup(""); | |
532 } | |
533 | |
534 while ((dir = readdir(dp)) != NULL) | |
535 { | |
536 /* skip removed files */ | |
537 if (dir->d_ino > 0) | |
538 { | |
539 gchar *name = dir->d_name; | |
540 gchar *filepath = g_strconcat(pathl, "/", name, NULL); | |
541 if (stat(filepath, &ent_sbuf) >= 0) | |
542 { | |
543 gchar *path8; | |
544 gchar *name8; | |
545 | |
546 name8 = path_to_utf8(name); | |
547 path8 = g_strconcat(path, "/", name8, NULL); | |
548 g_free(name8); | |
549 | |
550 if (dirs && S_ISDIR(ent_sbuf.st_mode) && | |
551 !(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) ) | |
552 { | |
553 d_list = g_list_prepend(d_list, path8); | |
554 path8 = NULL; | |
555 } | |
556 else if (files && S_ISREG(ent_sbuf.st_mode)) | |
557 { | |
558 f_list = g_list_prepend(f_list, path8); | |
559 path8 = NULL; | |
560 } | |
561 g_free(path8); | |
562 } | |
563 g_free(filepath); | |
564 } | |
565 } | |
566 closedir(dp); | |
567 | |
568 g_free(pathl); | |
569 | |
570 if (dirs) *dirs = g_list_reverse(d_list); | |
571 if (files) *files = g_list_reverse(f_list); | |
572 | |
573 return TRUE; | |
574 } | |
575 | |
576 void path_list_free(GList *list) | |
577 { | |
578 g_list_foreach(list, (GFunc)g_free, NULL); | |
579 g_list_free(list); | |
580 } | |
581 | |
582 GList *path_list_copy(GList *list) | |
583 { | |
584 GList *new_list = NULL; | |
585 GList *work; | |
586 | |
587 work = list; | |
588 while (work) | |
589 { | |
590 gchar *path; | |
591 | |
592 path = work->data; | |
593 work = work->next; | |
594 | |
595 new_list = g_list_prepend(new_list, g_strdup(path)); | |
596 } | |
597 | |
598 return g_list_reverse(new_list); | |
599 } | |
600 | |
601 long checksum_simple(const gchar *path) | |
602 { | |
603 gchar *path8; | |
604 FILE *f; | |
605 long sum = 0; | |
606 gint c; | |
607 | |
608 path8 = path_from_utf8(path); | |
609 f = fopen(path8, "r"); | |
610 g_free(path8); | |
611 if (!f) return -1; | |
612 | |
613 while((c = fgetc(f)) != EOF) | |
614 { | |
615 sum += c; | |
616 } | |
617 | |
618 fclose(f); | |
619 | |
620 return sum; | |
621 } | |
622 | |
623 gchar *unique_filename(const gchar *path, const gchar *ext, const gchar *divider, gint pad) | |
624 { | |
625 gchar *unique; | |
626 gint n = 1; | |
627 | |
628 if (!ext) ext = ""; | |
629 if (!divider) divider = ""; | |
630 | |
631 unique = g_strconcat(path, ext, NULL); | |
632 while (isname(unique)) | |
633 { | |
634 g_free(unique); | |
635 if (pad) | |
636 { | |
637 unique = g_strdup_printf("%s%s%03d%s", path, divider, n, ext); | |
638 } | |
639 else | |
640 { | |
641 unique = g_strdup_printf("%s%s%d%s", path, divider, n, ext); | |
642 } | |
643 n++; | |
644 if (n > 999) | |
645 { | |
646 /* well, we tried */ | |
647 g_free(unique); | |
648 return NULL; | |
649 } | |
650 } | |
651 | |
652 return unique; | |
653 } | |
654 | |
655 gchar *unique_filename_simple(const gchar *path) | |
656 { | |
657 gchar *unique; | |
658 const gchar *name; | |
659 const gchar *ext; | |
660 | |
661 if (!path) return NULL; | |
662 | |
663 name = filename_from_path(path); | |
664 if (!name) return NULL; | |
665 | |
666 ext = extension_from_path(name); | |
667 | |
668 if (!ext) | |
669 { | |
670 unique = unique_filename(path, NULL, "_", TRUE); | |
671 } | |
672 else | |
673 { | |
674 gchar *base; | |
675 | |
676 base = remove_extension_from_path(path); | |
677 unique = unique_filename(base, ext, "_", TRUE); | |
678 g_free(base); | |
679 } | |
680 | |
681 return unique; | |
682 } | |
683 | |
684 const gchar *filename_from_path(const gchar *path) | |
685 { | |
686 const gchar *base; | |
687 | |
688 if (!path) return NULL; | |
689 | |
690 base = strrchr(path, '/'); | |
691 if (base) return base + 1; | |
692 | |
693 return path; | |
694 } | |
695 | |
696 gchar *remove_level_from_path(const gchar *path) | |
697 { | |
698 gchar *new_path; | |
699 const gchar *ptr = path; | |
700 gint p; | |
701 | |
702 if (!path) return NULL; | |
703 | |
704 p = strlen(path) - 1; | |
705 if (p < 0) return NULL; | |
706 while(ptr[p] != '/' && p > 0) p--; | |
707 if (p == 0 && ptr[p] == '/') p++; | |
708 new_path = g_strndup(path, (guint)p); | |
709 return new_path; | |
710 } | |
711 | |
712 gchar *concat_dir_and_file(const gchar *base, const gchar *name) | |
713 { | |
714 if (!base || !name) return NULL; | |
715 | |
716 if (strcmp(base, "/") == 0) return g_strconcat(base, name, NULL); | |
717 | |
718 return g_strconcat(base, "/", name, NULL); | |
719 } | |
720 | |
721 const gchar *extension_from_path(const gchar *path) | |
722 { | |
723 if (!path) return NULL; | |
724 return strrchr(path, '.'); | |
725 } | |
726 | |
727 gint file_extension_match(const gchar *path, const gchar *ext) | |
728 { | |
729 gint p; | |
730 gint e; | |
731 | |
732 if (!path) return FALSE; | |
733 if (!ext) return TRUE; | |
734 | |
735 p = strlen(path); | |
736 e = strlen(ext); | |
737 | |
738 return (p > e && strncasecmp(path + p - e, ext, e) == 0); | |
739 } | |
740 | |
741 gchar *remove_extension_from_path(const gchar *path) | |
742 { | |
743 gchar *new_path; | |
744 const gchar *ptr = path; | |
745 gint p; | |
746 | |
747 if (!path) return NULL; | |
748 if (strlen(path) < 2) return g_strdup(path); | |
749 | |
750 p = strlen(path) - 1; | |
751 while(ptr[p] != '.' && p > 0) p--; | |
752 if (p == 0) p = strlen(path) - 1; | |
753 new_path = g_strndup(path, (guint)p); | |
754 return new_path; | |
755 } | |
756 | |
757 void parse_out_relatives(gchar *path) | |
758 { | |
759 gint s, t; | |
760 | |
761 if (!path) return; | |
762 | |
763 s = t = 0; | |
764 | |
765 while (path[s] != '\0') | |
766 { | |
767 if (path[s] == '/' && path[s+1] == '.' && (path[s+2] == '/' || path[s+2] == '\0') ) | |
768 { | |
769 s += 2; | |
770 } | |
771 else if (path[s] == '/' && path[s+1] == '.' && path[s+2] == '.' && (path[s+3] == '/' || path[s+3] == '\0') ) | |
772 { | |
773 s += 3; | |
774 if (t > 0) t--; | |
775 while (path[t] != '/' && t > 0) t--; | |
776 } | |
777 else | |
778 { | |
779 if (s != t) path[t] = path[s]; | |
780 t++; | |
781 s++; | |
782 } | |
783 } | |
784 if (t == 0 && path[t] == '/') t++; | |
785 if (t > 1 && path[t-1] == '/') t--; | |
786 path[t] = '\0'; | |
787 } | |
788 | |
789 gint file_in_path(const gchar *name) | |
790 { | |
791 gchar *path; | |
792 gchar *namel; | |
793 gint p, l; | |
794 gint ret = FALSE; | |
795 | |
796 if (!name) return FALSE; | |
797 path = g_strdup(getenv("PATH")); | |
798 if (!path) return FALSE; | |
799 namel = path_from_utf8(name); | |
800 | |
801 p = 0; | |
802 l = strlen(path); | |
803 while (p < l && !ret) | |
804 { | |
805 gchar *f; | |
806 gint e = p; | |
807 while (path[e] != ':' && path[e] != '\0') e++; | |
808 path[e] = '\0'; | |
809 e++; | |
810 f = g_strconcat(path + p, "/", namel, NULL); | |
811 if (isfile(f)) ret = TRUE; | |
812 g_free(f); | |
813 p = e; | |
814 } | |
815 g_free(namel); | |
816 g_free(path); | |
817 | |
818 return ret; | |
819 } | |
820 |