cleanup: style
[blender-staging.git] / source / blender / blenlib / intern / path_util.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  *
27  * various string, file, list operations.
28  */
29
30 /** \file blender/blenlib/intern/path_util.c
31  *  \ingroup bli
32  */
33
34 #include <ctype.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <assert.h>
38
39 #include "DNA_listBase.h"
40
41 #include "BLI_utildefines.h"
42 #include "BLI_fileops.h"
43 #include "BLI_path_util.h"
44 #include "BLI_string.h"
45 #include "BLI_string_utf8.h"
46 #include "BLI_fnmatch.h"
47
48 #ifdef WIN32
49 #  include "utf_winfunc.h"
50 #  include "utfconv.h"
51 #  include <io.h>
52 #  ifdef _WIN32_IE
53 #    undef _WIN32_IE
54 #  endif
55 #  define _WIN32_IE 0x0501
56 #  include <windows.h>
57 #  include <shlobj.h>
58 #  include "BLI_winstuff.h"
59 #  include "MEM_guardedalloc.h"
60 #endif /* WIN32 */
61
62 /* local */
63 #define UNIQUE_NAME_MAX 128
64
65 /* implementation */
66
67 /**
68  * Looks for a sequence of decimal digits in string, preceding any filename extension,
69  * returning the integer value if found, or 0 if not.
70  *
71  * \param string  String to scan.
72  * \param head  Optional area to return copy of part of string prior to digits, or before dot if no digits.
73  * \param tail  Optional area to return copy of part of string following digits, or from dot if no digits.
74  * \param numlen  Optional to return number of digits found.
75  */
76 int BLI_stringdec(const char *string, char *head, char *tail, unsigned short *numlen)
77 {
78         unsigned int nums = 0, nume = 0;
79         int i;
80         bool found_digit = false;
81         const char * const lslash = BLI_last_slash(string);
82         const unsigned int string_len = strlen(string);
83         const unsigned int lslash_len = lslash != NULL ? (int)(lslash - string) : 0;
84         unsigned int name_end = string_len;
85
86         while (name_end > lslash_len && string[--name_end] != '.') {} /* name ends at dot if present */
87         if (name_end == lslash_len && string[name_end] != '.') name_end = string_len;
88
89         for (i = name_end - 1; i >= (int)lslash_len; i--) {
90                 if (isdigit(string[i])) {
91                         if (found_digit) {
92                                 nums = i;
93                         }
94                         else {
95                                 nume = i;
96                                 nums = i;
97                                 found_digit = true;
98                         }
99                 }
100                 else {
101                         if (found_digit) break;
102                 }
103         }
104
105         if (found_digit) {
106                 if (tail) strcpy(tail, &string[nume + 1]);
107                 if (head) {
108                         strcpy(head, string);
109                         head[nums] = 0;
110                 }
111                 if (numlen) *numlen = nume - nums + 1;
112                 return ((int)atoi(&(string[nums])));
113         }
114         else {
115                 if (tail) strcpy(tail, string + name_end);
116                 if (head) {
117                         /* name_end points to last character of head,
118                          * make it +1 so null-terminator is nicely placed
119                          */
120                         BLI_strncpy(head, string, name_end + 1);
121                 }
122                 if (numlen) *numlen = 0;
123                 return 0;
124         }
125 }
126
127
128 /**
129  * Returns in area pointed to by string a string of the form "<head><pic><tail>", where pic
130  * is formatted as numlen digits with leading zeroes.
131  */
132 void BLI_stringenc(char *string, const char *head, const char *tail, unsigned short numlen, int pic)
133 {
134         sprintf(string, "%s%.*d%s", head, numlen, MAX2(0, pic), tail);
135 }
136
137 /**
138  * Looks for a numeric suffix preceded by delim character on the end of
139  * name, puts preceding part into *left and value of suffix into *nr.
140  * Returns the length of *left.
141  *
142  * Foo.001 -> "Foo", 1
143  * Returning the length of "Foo"
144  *
145  * \param left  Where to return copy of part preceding delim
146  * \param nr  Where to return value of numeric suffix
147  * \param name  String to split
148  * \param delim  Delimiter character
149  * \return  Length of \a left
150  */
151 int BLI_split_name_num(char *left, int *nr, const char *name, const char delim)
152 {
153         const int name_len = strlen(name);
154
155         *nr = 0;
156         memcpy(left, name, (name_len + 1) * sizeof(char));
157
158         /* name doesn't end with a delimiter "foo." */
159         if ((name_len > 1 && name[name_len - 1] == delim) == 0) {
160                 int a = name_len;
161                 while (a--) {
162                         if (name[a] == delim) {
163                                 left[a] = '\0';  /* truncate left part here */
164                                 *nr = atol(name + a + 1);
165                                 /* casting down to an int, can overflow for large numbers */
166                                 if (*nr < 0)
167                                         *nr = 0;
168                                 return a;
169                         }
170                         else if (isdigit(name[a]) == 0) {
171                                 /* non-numeric suffix - give up */
172                                 break;
173                         }
174                 }
175         }
176
177         return name_len;
178 }
179
180 /**
181  * Looks for a string of digits within name (using BLI_stringdec) and adjusts it by add.
182  */
183 void BLI_newname(char *name, int add)
184 {
185         char head[UNIQUE_NAME_MAX], tail[UNIQUE_NAME_MAX];
186         int pic;
187         unsigned short digits;
188         
189         pic = BLI_stringdec(name, head, tail, &digits);
190         
191         /* are we going from 100 -> 99 or from 10 -> 9 */
192         if (add < 0 && digits < 4 && digits > 0) {
193                 int i, exp;
194                 exp = 1;
195                 for (i = digits; i > 1; i--) exp *= 10;
196                 if (pic >= exp && (pic + add) < exp) digits--;
197         }
198         
199         pic += add;
200         
201         if (digits == 4 && pic < 0) pic = 0;
202         BLI_stringenc(name, head, tail, digits, pic);
203 }
204
205 /**
206  * Ensures name is unique (according to criteria specified by caller in unique_check callback),
207  * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
208  *
209  * \param unique_check  Return true if name is not unique
210  * \param arg  Additional arg to unique_check--meaning is up to caller
211  * \param defname  To initialize name if latter is empty
212  * \param delim  Delimits numeric suffix in name
213  * \param name  Name to be ensured unique
214  * \param name_len  Maximum length of name area
215  * \return true if there if the name was changed
216  */
217 bool BLI_uniquename_cb(bool (*unique_check)(void *arg, const char *name),
218                        void *arg, const char *defname, char delim, char *name, int name_len)
219 {
220         if (name[0] == '\0') {
221                 BLI_strncpy(name, defname, name_len);
222         }
223
224         if (unique_check(arg, name)) {
225                 char numstr[16];
226                 char tempname[UNIQUE_NAME_MAX];
227                 char left[UNIQUE_NAME_MAX];
228                 int number;
229                 int len = BLI_split_name_num(left, &number, name, delim);
230                 do {
231                         /* add 1 to account for \0 */
232                         const int numlen = BLI_snprintf(numstr, sizeof(numstr), "%c%03d", delim, ++number) + 1;
233
234                         /* highly unlikely the string only has enough room for the number
235                          * but support anyway */
236                         if ((len == 0) || (numlen >= name_len)) {
237                                 /* number is know not to be utf-8 */
238                                 BLI_strncpy(tempname, numstr, name_len);
239                         }
240                         else {
241                                 char *tempname_buf;
242                                 tempname_buf = tempname + BLI_strncpy_utf8_rlen(tempname, left, name_len - numlen);
243                                 memcpy(tempname_buf, numstr, numlen);
244                         }
245                 } while (unique_check(arg, tempname));
246
247                 BLI_strncpy(name, tempname, name_len);
248                 
249                 return true;
250         }
251         
252         return false;
253 }
254
255 /* little helper macro for BLI_uniquename */
256 #ifndef GIVE_STRADDR
257 #  define GIVE_STRADDR(data, offset) ( ((char *)data) + offset)
258 #endif
259
260 /* Generic function to set a unique name. It is only designed to be used in situations
261  * where the name is part of the struct, and also that the name is at most UNIQUE_NAME_MAX chars long.
262  * 
263  * For places where this is used, see constraint.c for example...
264  *
265  *  name_offs: should be calculated using offsetof(structname, membername) macro from stddef.h
266  *  len: maximum length of string (to prevent overflows, etc.)
267  *  defname: the name that should be used by default if none is specified already
268  *  delim: the character which acts as a delimiter between parts of the name
269  */
270 static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offs)
271 {
272         Link *link;
273
274         for (link = list->first; link; link = link->next) {
275                 if (link != vlink) {
276                         if (STREQ(GIVE_STRADDR(link, name_offs), name)) {
277                                 return true;
278                         }
279                 }
280         }
281
282         return false;
283 }
284
285 static bool uniquename_unique_check(void *arg, const char *name)
286 {
287         struct {ListBase *lb; void *vlink; int name_offs; } *data = arg;
288         return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offs);
289 }
290
291 /**
292  * Ensures that the specified block has a unique name within the containing list,
293  * incrementing its numeric suffix as necessary.
294  *
295  * \param list  List containing the block
296  * \param vlink  The block to check the name for
297  * \param defname  To initialize block name if latter is empty
298  * \param delim  Delimits numeric suffix in name
299  * \param name_offs  Offset of name within block structure
300  * \param name_len  Maximum length of name area
301  */
302 void BLI_uniquename(ListBase *list, void *vlink, const char *defname, char delim, int name_offs, int name_len)
303 {
304         struct {ListBase *lb; void *vlink; int name_offs; } data;
305         data.lb = list;
306         data.vlink = vlink;
307         data.name_offs = name_offs;
308
309         assert((name_len > 1) && (name_len <= UNIQUE_NAME_MAX));
310
311         /* See if we are given an empty string */
312         if (ELEM(NULL, vlink, defname))
313                 return;
314
315         BLI_uniquename_cb(uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len);
316 }
317
318 static int BLI_path_unc_prefix_len(const char *path); /* defined below in same file */
319
320 /* ******************** string encoding ***************** */
321
322 /* This is quite an ugly function... its purpose is to
323  * take the dir name, make it absolute, and clean it up, replacing
324  * excess file entry stuff (like /tmp/../tmp/../)
325  * note that dir isn't protected for max string names... 
326  * 
327  * If relbase is NULL then its ignored
328  */
329
330 void BLI_cleanup_path(const char *relabase, char *path)
331 {
332         ptrdiff_t a;
333         char *start, *eind;
334         if (relabase) {
335                 BLI_path_abs(path, relabase);
336         }
337         else {
338                 if (path[0] == '/' && path[1] == '/') {
339                         if (path[2] == '\0') {
340                                 return; /* path is "//" - cant clean it */
341                         }
342                         path = path + 2;  /* leave the initial "//" untouched */
343                 }
344         }
345         
346         /* Note
347          *   memmove(start, eind, strlen(eind) + 1);
348          * is the same as
349          *   strcpy(start, eind);
350          * except strcpy should not be used because there is overlap,
351          * so use memmove's slightly more obscure syntax - Campbell
352          */
353         
354 #ifdef WIN32
355         while ( (start = strstr(path, "\\..\\")) ) {
356                 eind = start + strlen("\\..\\") - 1;
357                 a = start - path - 1;
358                 while (a > 0) {
359                         if (path[a] == '\\') break;
360                         a--;
361                 }
362                 if (a < 0) {
363                         break;
364                 }
365                 else {
366                         memmove(path + a, eind, strlen(eind) + 1);
367                 }
368         }
369
370         while ( (start = strstr(path, "\\.\\")) ) {
371                 eind = start + strlen("\\.\\") - 1;
372                 memmove(start, eind, strlen(eind) + 1);
373         }
374
375         /* remove two consecutive backslashes, but skip the UNC prefix,
376          * which needs to be preserved */
377         while ( (start = strstr(path + BLI_path_unc_prefix_len(path), "\\\\")) ) {
378                 eind = start + strlen("\\\\") - 1;
379                 memmove(start, eind, strlen(eind) + 1);
380         }
381 #else
382         while ( (start = strstr(path, "/../")) ) {
383                 a = start - path - 1;
384                 if (a > 0) {
385                         /* <prefix>/<parent>/../<postfix> => <prefix>/<postfix> */
386                         eind = start + (4 - 1) /* strlen("/../") - 1 */; /* strip "/.." and keep last "/" */
387                         while (a > 0 && path[a] != '/') { /* find start of <parent> */
388                                 a--;
389                         }
390                         memmove(path + a, eind, strlen(eind) + 1);
391                 }
392                 else {
393                         /* support for odd paths: eg /../home/me --> /home/me
394                          * this is a valid path in blender but we cant handle this the usual way below
395                          * simply strip this prefix then evaluate the path as usual.
396                          * pythons os.path.normpath() does this */
397
398                         /* Note: previous version of following call used an offset of 3 instead of 4,
399                          * which meant that the "/../home/me" example actually became "home/me".
400                          * Using offset of 3 gives behaviour consistent with the abovementioned
401                          * Python routine. */
402                         memmove(path, path + 3, strlen(path + 3) + 1);
403                 }
404         }
405
406         while ( (start = strstr(path, "/./")) ) {
407                 eind = start + (3 - 1) /* strlen("/./") - 1 */;
408                 memmove(start, eind, strlen(eind) + 1);
409         }
410
411         while ( (start = strstr(path, "//")) ) {
412                 eind = start + (2 - 1) /* strlen("//") - 1 */;
413                 memmove(start, eind, strlen(eind) + 1);
414         }
415 #endif
416 }
417
418 void BLI_cleanup_dir(const char *relabase, char *dir)
419 {
420         BLI_cleanup_path(relabase, dir);
421         BLI_add_slash(dir);
422
423 }
424
425 void BLI_cleanup_file(const char *relabase, char *path)
426 {
427         BLI_cleanup_path(relabase, path);
428         BLI_del_slash(path);
429 }
430
431
432 /**
433  * Make given name safe to be used in paths.
434  *
435  * For now, simply replaces reserved chars (as listed in
436  * http://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words )
437  * by underscores ('_').
438  */
439 void BLI_filename_make_safe(char *fname)
440 {
441         const char *invalid = "/\\?%*:|\"<>. ";
442
443         for (; *fname && (fname = strpbrk(fname, invalid)); fname++) {
444                 *fname = '_';
445         }
446 }
447
448 /**
449  * Does path begin with the special "//" prefix that Blender uses to indicate
450  * a path relative to the .blend file.
451  */
452 bool BLI_path_is_rel(const char *path)
453 {
454         return path[0] == '/' && path[1] == '/';
455 }
456
457 /* return true if the path is a UNC share */
458 bool BLI_path_is_unc(const char *name)
459 {
460         return name[0] == '\\' && name[1] == '\\';
461 }
462
463 /**
464  * Returns the length of the identifying prefix
465  * of a UNC path which can start with '\\' (short version)
466  * or '\\?\' (long version)
467  * If the path is not a UNC path, return 0
468  */
469 static int BLI_path_unc_prefix_len(const char *path)
470 {
471         if (BLI_path_is_unc(path)) {
472                 if ((path[2] == '?') && (path[3] == '\\') ) {
473                         /* we assume long UNC path like \\?\server\share\folder etc... */
474                         return 4;
475                 }
476                 else {
477                         return 2;
478                 }
479         }
480
481         return 0;
482 }
483
484 #if defined(WIN32)
485
486 /* return true if the path is absolute ie starts with a drive specifier (eg A:\) or is a UNC path */
487 static bool BLI_path_is_abs(const char *name)
488 {
489         return (name[1] == ':' && (name[2] == '\\' || name[2] == '/') ) || BLI_path_is_unc(name);
490 }
491
492 static wchar_t *next_slash(wchar_t *path)
493 {
494         wchar_t *slash = path;
495         while (*slash && *slash != L'\\') slash++;
496         return slash;
497 }
498
499 /* adds a slash if the unc path points sto a share */
500 static void BLI_path_add_slash_to_share(wchar_t *uncpath)
501 {
502         wchar_t *slash_after_server = next_slash(uncpath + 2);
503         if (*slash_after_server) {
504                 wchar_t *slash_after_share = next_slash(slash_after_server + 1);
505                 if (!(*slash_after_share)) {
506                         slash_after_share[0] = L'\\';
507                         slash_after_share[1] = L'\0';
508                 }
509         }
510 }
511
512 static void BLI_path_unc_to_short(wchar_t *unc)
513 {
514         wchar_t tmp[PATH_MAX];
515
516         int len = wcslen(unc);
517         int copy_start = 0;
518         /* convert:
519          *    \\?\UNC\server\share\folder\... to \\server\share\folder\...
520          *    \\?\C:\ to C:\ and \\?\C:\folder\... to C:\folder\...
521          */
522         if ((len > 3) &&
523             (unc[0] ==  L'\\') &&
524             (unc[1] ==  L'\\') &&
525             (unc[2] ==  L'?') &&
526             ((unc[3] ==  L'\\') || (unc[3] ==  L'/')))
527         {
528                 if ((len > 5) && (unc[5] ==  L':')) {
529                         wcsncpy(tmp, unc + 4, len - 4);
530                         tmp[len - 4] = L'\0';
531                         wcscpy(unc, tmp);
532                 }
533                 else if ((len > 7) && (wcsncmp(&unc[4], L"UNC", 3) == 0) &&
534                          ((unc[7] ==  L'\\') || (unc[7] ==  L'/')))
535                 {
536                         tmp[0] = L'\\';
537                         tmp[1] = L'\\';
538                         wcsncpy(tmp + 2, unc + 8, len - 8);
539                         tmp[len - 6] = L'\0';
540                         wcscpy(unc, tmp);
541                 }
542         }
543 }
544
545 void BLI_cleanup_unc(char *path, int maxlen)
546 {
547         wchar_t *tmp_16 = alloc_utf16_from_8(path, 1);
548         BLI_cleanup_unc_16(tmp_16);
549         conv_utf_16_to_8(tmp_16, path, maxlen);
550 }
551
552 void BLI_cleanup_unc_16(wchar_t *path_16)
553 {
554         BLI_path_unc_to_short(path_16);
555         BLI_path_add_slash_to_share(path_16);
556 }
557 #endif
558
559 /**
560  * Replaces *file with a relative version (prefixed by "//") such that BLI_path_abs, given
561  * the same *relfile, will convert it back to its original value.
562  */
563 void BLI_path_rel(char *file, const char *relfile)
564 {
565         const char *lslash;
566         char temp[FILE_MAX];
567         char res[FILE_MAX];
568         
569         /* if file is already relative, bail out */
570         if (BLI_path_is_rel(file)) {
571                 return;
572         }
573         
574         /* also bail out if relative path is not set */
575         if (relfile[0] == '\0') {
576                 return;
577         }
578
579 #ifdef WIN32
580         if (BLI_strnlen(relfile, 3) > 2 && !BLI_path_is_abs(relfile)) {
581                 char *ptemp;
582                 /* fix missing volume name in relative base,
583                  * can happen with old recent-files.txt files */
584                 get_default_root(temp);
585                 ptemp = &temp[2];
586                 if (relfile[0] != '\\' && relfile[0] != '/') {
587                         ptemp++;
588                 }
589                 BLI_strncpy(ptemp, relfile, FILE_MAX - 3);
590         }
591         else {
592                 BLI_strncpy(temp, relfile, FILE_MAX);
593         }
594
595         if (BLI_strnlen(file, 3) > 2) {
596                 bool is_unc = BLI_path_is_unc(file);
597
598                 /* Ensure paths are both UNC paths or are both drives */
599                 if (BLI_path_is_unc(temp) != is_unc) {
600                         return;
601                 }
602
603                 /* Ensure both UNC paths are on the same share */
604                 if (is_unc) {
605                         int off;
606                         int slash = 0;
607                         for (off = 0; temp[off] && slash < 4; off++) {
608                                 if (temp[off] != file[off])
609                                         return;
610
611                                 if (temp[off] == '\\')
612                                         slash++;
613                         }
614                 }
615                 else if (temp[1] == ':' && file[1] == ':' && temp[0] != file[0]) {
616                         return;
617                 }
618         }
619 #else
620         BLI_strncpy(temp, relfile, FILE_MAX);
621 #endif
622
623         BLI_char_switch(temp + BLI_path_unc_prefix_len(temp), '\\', '/');
624         BLI_char_switch(file + BLI_path_unc_prefix_len(file), '\\', '/');
625         
626         /* remove /./ which confuse the following slash counting... */
627         BLI_cleanup_path(NULL, file);
628         BLI_cleanup_path(NULL, temp);
629         
630         /* the last slash in the file indicates where the path part ends */
631         lslash = BLI_last_slash(temp);
632
633         if (lslash) {
634                 /* find the prefix of the filename that is equal for both filenames.
635                  * This is replaced by the two slashes at the beginning */
636                 const char *p = temp;
637                 const char *q = file;
638                 char *r = res;
639
640 #ifdef WIN32
641                 while (tolower(*p) == tolower(*q))
642 #else
643                 while (*p == *q)
644 #endif
645                 {
646                         p++;
647                         q++;
648
649                         /* don't search beyond the end of the string
650                          * in the rare case they match */
651                         if ((*p == '\0') || (*q == '\0')) {
652                                 break;
653                         }
654                 }
655
656                 /* we might have passed the slash when the beginning of a dir matches 
657                  * so we rewind. Only check on the actual filename
658                  */
659                 if (*q != '/') {
660                         while ( (q >= file) && (*q != '/') ) { --q; --p; }
661                 }
662                 else if (*p != '/') {
663                         while ( (p >= temp) && (*p != '/') ) { --p; --q; }
664                 }
665                 
666                 r += BLI_strcpy_rlen(r, "//");
667
668                 /* p now points to the slash that is at the beginning of the part
669                  * where the path is different from the relative path. 
670                  * We count the number of directories we need to go up in the
671                  * hierarchy to arrive at the common 'prefix' of the path
672                  */
673                 if (p < temp) p = temp;
674                 while (p && p < lslash) {
675                         if (*p == '/') {
676                                 r += BLI_strcpy_rlen(r, "../");
677                         }
678                         p++;
679                 }
680
681                 /* don't copy the slash at the beginning */
682                 r += BLI_strcpy_rlen(r, q + 1);
683                 
684 #ifdef  WIN32
685                 BLI_char_switch(res + 2, '/', '\\');
686 #endif
687                 strcpy(file, res);
688         }
689 }
690
691 /**
692  * Appends a suffix to the string, fitting it before the extension
693  *
694  * string = Foo.png, suffix = 123, separator = _
695  * Foo.png -> Foo_123.png
696  *
697  * \param string  original (and final) string
698  * \param maxlen  Maximum length of string
699  * \param suffix  String to append to the original string
700  * \param sep Optional separator character
701  * \return  true if succeeded
702  */
703 bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char *sep)
704 {
705         const size_t string_len = strlen(string);
706         const size_t suffix_len = strlen(suffix);
707         const size_t sep_len = strlen(sep);
708         ssize_t a;
709         char extension[FILE_MAX];
710         bool has_extension = false;
711
712         if (string_len + sep_len + suffix_len >= maxlen)
713                 return false;
714
715         for (a = string_len - 1; a >= 0; a--) {
716                 if (string[a] == '.') {
717                         has_extension = true;
718                         break;
719                 }
720                 else if (ELEM(string[a], '/', '\\')) {
721                         break;
722                 }
723         }
724
725         if (!has_extension)
726                 a = string_len;
727
728         BLI_strncpy(extension, string + a, sizeof(extension));
729         sprintf(string + a, "%s%s%s", sep, suffix, extension);
730         return true;
731 }
732
733 /**
734  * Replaces path with the path of its parent directory, returning true if
735  * it was able to find a parent directory within the pathname.
736  */
737 bool BLI_parent_dir(char *path)
738 {
739         const char parent_dir[] = {'.', '.', SEP, '\0'}; /* "../" or "..\\" */
740         char tmp[FILE_MAX + 4];
741
742         BLI_join_dirfile(tmp, sizeof(tmp), path, parent_dir);
743         BLI_cleanup_dir(NULL, tmp); /* does all the work of normalizing the path for us */
744
745         if (!BLI_testextensie(tmp, parent_dir)) {
746                 BLI_strncpy(path, tmp, sizeof(tmp));
747                 return true;
748         }
749         else {
750                 return false;
751         }
752 }
753
754 /**
755  * Looks for a sequence of "#" characters in the last slash-separated component of *path,
756  * returning the indexes of the first and one past the last character in the sequence in
757  * *char_start and *char_end respectively. Returns true if such a sequence was found.
758  */
759 static bool stringframe_chars(const char *path, int *char_start, int *char_end)
760 {
761         unsigned int ch_sta, ch_end, i;
762         /* Insert current frame: file### -> file001 */
763         ch_sta = ch_end = 0;
764         for (i = 0; path[i] != '\0'; i++) {
765                 if (path[i] == '\\' || path[i] == '/') {
766                         ch_end = 0; /* this is a directory name, don't use any hashes we found */
767                 }
768                 else if (path[i] == '#') {
769                         ch_sta = i;
770                         ch_end = ch_sta + 1;
771                         while (path[ch_end] == '#') {
772                                 ch_end++;
773                         }
774                         i = ch_end - 1; /* keep searching */
775                         
776                         /* don't break, there may be a slash after this that invalidates the previous #'s */
777                 }
778         }
779
780         if (ch_end) {
781                 *char_start = ch_sta;
782                 *char_end = ch_end;
783                 return true;
784         }
785         else {
786                 *char_start = -1;
787                 *char_end = -1;
788                 return false;
789         }
790 }
791
792 /**
793  * Ensure *path contains at least one "#" character in its last slash-separated
794  * component, appending one digits long if not.
795  */
796 static void ensure_digits(char *path, int digits)
797 {
798         char *file = (char *)BLI_last_slash(path);
799
800         if (file == NULL)
801                 file = path;
802
803         if (strrchr(file, '#') == NULL) {
804                 int len = strlen(file);
805
806                 while (digits--) {
807                         file[len++] = '#';
808                 }
809                 file[len] = '\0';
810         }
811 }
812
813 /**
814  * Replaces "#" character sequence in last slash-separated component of *path
815  * with frame as decimal integer, with leading zeroes as necessary, to make digits digits.
816  */
817 bool BLI_path_frame(char *path, int frame, int digits)
818 {
819         int ch_sta, ch_end;
820
821         if (digits)
822                 ensure_digits(path, digits);
823
824         if (stringframe_chars(path, &ch_sta, &ch_end)) { /* warning, ch_end is the last # +1 */
825                 char tmp[FILE_MAX];
826                 BLI_snprintf(tmp, sizeof(tmp),
827                              "%.*s%.*d%s",
828                              ch_sta, path, ch_end - ch_sta, frame, path + ch_end);
829                 BLI_strncpy(path, tmp, FILE_MAX);
830                 return true;
831         }
832         return false;
833 }
834
835 /**
836  * Replaces "#" character sequence in last slash-separated component of *path
837  * with sta and end as decimal integers, with leading zeroes as necessary, to make digits
838  * digits each, with a hyphen in-between.
839  */
840 bool BLI_path_frame_range(char *path, int sta, int end, int digits)
841 {
842         int ch_sta, ch_end;
843
844         if (digits)
845                 ensure_digits(path, digits);
846
847         if (stringframe_chars(path, &ch_sta, &ch_end)) { /* warning, ch_end is the last # +1 */
848                 char tmp[FILE_MAX];
849                 BLI_snprintf(tmp, sizeof(tmp),
850                              "%.*s%.*d-%.*d%s",
851                              ch_sta, path, ch_end - ch_sta, sta, ch_end - ch_sta, end, path + ch_end);
852                 BLI_strncpy(path, tmp, FILE_MAX);
853                 return true;
854         }
855         return false;
856 }
857
858 /**
859  * Check if we have '#' chars, usable for #BLI_path_frame, #BLI_path_frame_range
860  */
861 bool BLI_path_frame_check_chars(const char *path)
862 {
863         int ch_sta, ch_end;  /* dummy args */
864         return stringframe_chars(path, &ch_sta, &ch_end);
865 }
866
867 /**
868  * If path begins with "//", strips that and replaces it with basepath directory. Also converts
869  * a drive-letter prefix to something more sensible if this is a non-drive-letter-based system.
870  * Returns true if "//" prefix expansion was done.
871  */
872 bool BLI_path_abs(char *path, const char *basepath)
873 {
874         const bool wasrelative = BLI_path_is_rel(path);
875         char tmp[FILE_MAX];
876         char base[FILE_MAX];
877 #ifdef WIN32
878
879         /* without this: "" --> "C:\" */
880         if (*path == '\0') {
881                 return wasrelative;
882         }
883
884         /* we are checking here if we have an absolute path that is not in the current
885          * blend file as a lib main - we are basically checking for the case that a 
886          * UNIX root '/' is passed.
887          */
888         if (!wasrelative && !BLI_path_is_abs(path)) {
889                 char *p = path;
890                 get_default_root(tmp);
891                 // get rid of the slashes at the beginning of the path
892                 while (*p == '\\' || *p == '/') {
893                         p++;
894                 }
895                 strcat(tmp, p);
896         }
897         else {
898                 BLI_strncpy(tmp, path, FILE_MAX);
899         }
900 #else
901         BLI_strncpy(tmp, path, sizeof(tmp));
902         
903         /* Check for loading a windows path on a posix system
904          * in this case, there is no use in trying C:/ since it 
905          * will never exist on a unix os.
906          * 
907          * Add a / prefix and lowercase the driveletter, remove the :
908          * C:\foo.JPG -> /c/foo.JPG */
909         
910         if (isalpha(tmp[0]) && tmp[1] == ':' && (tmp[2] == '\\' || tmp[2] == '/') ) {
911                 tmp[1] = tolower(tmp[0]); /* replace ':' with driveletter */
912                 tmp[0] = '/'; 
913                 /* '\' the slash will be converted later */
914         }
915         
916 #endif
917
918         /* push slashes into unix mode - strings entering this part are
919          * potentially messed up: having both back- and forward slashes.
920          * Here we push into one conform direction, and at the end we
921          * push them into the system specific dir. This ensures uniformity
922          * of paths and solving some problems (and prevent potential future
923          * ones) -jesterKing.
924          * For UNC paths the first characters containing the UNC prefix
925          * shouldn't be switched as we need to distinguish them from
926          * paths relative to the .blend file -elubie */
927         BLI_char_switch(tmp + BLI_path_unc_prefix_len(tmp), '\\', '/');
928
929         /* Paths starting with // will get the blend file as their base,
930          * this isn't standard in any os but is used in blender all over the place */
931         if (wasrelative) {
932                 const char *lslash;
933                 BLI_strncpy(base, basepath, sizeof(base));
934
935                 /* file component is ignored, so don't bother with the trailing slash */
936                 BLI_cleanup_path(NULL, base);
937                 lslash = BLI_last_slash(base);
938                 BLI_char_switch(base + BLI_path_unc_prefix_len(base), '\\', '/');
939
940                 if (lslash) {
941                         const int baselen = (int) (lslash - base) + 1;  /* length up to and including last "/" */
942                         /* use path for temp storage here, we copy back over it right away */
943                         BLI_strncpy(path, tmp + 2, FILE_MAX);  /* strip "//" */
944                         
945                         memcpy(tmp, base, baselen);  /* prefix with base up to last "/" */
946                         BLI_strncpy(tmp + baselen, path, sizeof(tmp) - baselen);  /* append path after "//" */
947                         BLI_strncpy(path, tmp, FILE_MAX);  /* return as result */
948                 }
949                 else {
950                         /* base doesn't seem to be a directory--ignore it and just strip "//" prefix on path */
951                         BLI_strncpy(path, tmp + 2, FILE_MAX);
952                 }
953         }
954         else {
955                 /* base ignored */
956                 BLI_strncpy(path, tmp, FILE_MAX);
957         }
958
959 #ifdef WIN32
960         /* skip first two chars, which in case of
961          * absolute path will be drive:/blabla and
962          * in case of relpath //blabla/. So relpath
963          * // will be retained, rest will be nice and
964          * shiny win32 backward slashes :) -jesterKing
965          */
966         BLI_char_switch(path + 2, '/', '\\');
967 #endif
968
969         /* ensure this is after correcting for path switch */
970         BLI_cleanup_path(NULL, path);
971
972         return wasrelative;
973 }
974
975
976 /**
977  * Expands path relative to the current working directory, if it was relative.
978  * Returns true if such expansion was done.
979  *
980  * \note Should only be done with command line paths.
981  * this is _not_ something blenders internal paths support like the "//" prefix
982  */
983 bool BLI_path_cwd(char *path)
984 {
985         bool wasrelative = true;
986         const int filelen = strlen(path);
987         
988 #ifdef WIN32
989         if ((filelen >= 3 && BLI_path_is_abs(path)) || BLI_path_is_unc(path))
990                 wasrelative = false;
991 #else
992         if (filelen >= 2 && path[0] == '/')
993                 wasrelative = false;
994 #endif
995         
996         if (wasrelative) {
997                 char cwd[FILE_MAX] = "";
998                 BLI_current_working_dir(cwd, sizeof(cwd)); /* in case the full path to the blend isn't used */
999                 
1000                 if (cwd[0] == '\0') {
1001                         printf("Could not get the current working directory - $PWD for an unknown reason.\n");
1002                 }
1003                 else {
1004                         /* uses the blend path relative to cwd important for loading relative linked files.
1005                          *
1006                          * cwd should contain c:\ etc on win32 so the relbase can be NULL
1007                          * relbase being NULL also prevents // being misunderstood as relative to the current
1008                          * blend file which isn't a feature we want to use in this case since were dealing
1009                          * with a path from the command line, rather than from inside Blender */
1010
1011                         char origpath[FILE_MAX];
1012                         BLI_strncpy(origpath, path, FILE_MAX);
1013                         
1014                         BLI_make_file_string(NULL, path, cwd, origpath); 
1015                 }
1016         }
1017         
1018         return wasrelative;
1019 }
1020
1021 /**
1022  * Copies into *last the part of *dir following the second-last slash.
1023  */
1024 void BLI_getlastdir(const char *dir, char *last, const size_t maxlen)
1025 {
1026         const char *s = dir;
1027         const char *lslash = NULL;
1028         const char *prevslash = NULL;
1029         while (*s) {
1030                 if ((*s == '\\') || (*s == '/')) {
1031                         prevslash = lslash;
1032                         lslash = s;
1033                 }
1034                 s++;
1035         }
1036         if (prevslash) {
1037                 BLI_strncpy(last, prevslash + 1, maxlen);
1038         }
1039         else {
1040                 BLI_strncpy(last, dir, maxlen);
1041         }
1042 }
1043
1044
1045 /**
1046  * Sets the specified environment variable to the specified value,
1047  * and clears it if val == NULL.
1048  */
1049 void BLI_setenv(const char *env, const char *val)
1050 {
1051         /* free windows */
1052 #if (defined(WIN32) || defined(WIN64)) && defined(FREE_WINDOWS)
1053         char *envstr;
1054
1055         if (val)
1056                 envstr = BLI_sprintfN("%s=%s", env, val);
1057         else
1058                 envstr = BLI_sprintfN("%s=", env);
1059
1060         putenv(envstr);
1061         MEM_freeN(envstr);
1062
1063         /* non-free windows */
1064 #elif (defined(WIN32) || defined(WIN64)) /* not free windows */
1065         uputenv(env, val);
1066
1067
1068 #else
1069         /* linux/osx/bsd */
1070         if (val)
1071                 setenv(env, val, 1);
1072         else
1073                 unsetenv(env);
1074 #endif
1075 }
1076
1077
1078 /**
1079  * Only set an env var if already not there.
1080  * Like Unix setenv(env, val, 0);
1081  *
1082  * (not used anywhere).
1083  */
1084 void BLI_setenv_if_new(const char *env, const char *val)
1085 {
1086         if (getenv(env) == NULL)
1087                 BLI_setenv(env, val);
1088 }
1089
1090 /**
1091  * Change every \a from in \a string into \a to. The
1092  * result will be in \a string
1093  *
1094  * \param string The string to work on
1095  * \param from The character to replace
1096  * \param to The character to replace with
1097  */
1098 void BLI_char_switch(char *string, char from, char to) 
1099 {
1100         while (*string != 0) {
1101                 if (*string == from) *string = to;
1102                 string++;
1103         }
1104 }
1105
1106 /**
1107  * Strips off nonexistent (or non-accessible) subdirectories from the end of *dir, leaving the path of
1108  * the lowest-level directory that does exist and we can read.
1109  */
1110 void BLI_make_exist(char *dir)
1111 {
1112         int a;
1113         char par_path[PATH_MAX + 3];
1114
1115         BLI_char_switch(dir, ALTSEP, SEP);
1116
1117         a = strlen(dir);
1118
1119         for (BLI_join_dirfile(par_path, sizeof(par_path), dir, FILENAME_PARENT);
1120              !(BLI_is_dir(dir) && BLI_exists(par_path));
1121              BLI_join_dirfile(par_path, sizeof(par_path), dir, FILENAME_PARENT))
1122         {
1123                 a--;
1124                 while (dir[a] != SEP) {
1125                         a--;
1126                         if (a <= 0) break;
1127                 }
1128                 if (a >= 0) {
1129                         dir[a + 1] = '\0';
1130                 }
1131                 else {
1132 #ifdef WIN32
1133                         get_default_root(dir);
1134 #else
1135                         strcpy(dir, "/");
1136 #endif
1137                         break;
1138                 }
1139         }
1140 }
1141
1142 /**
1143  * Ensures that the parent directory of *name exists.
1144  */
1145 void BLI_make_existing_file(const char *name)
1146 {
1147         char di[FILE_MAX];
1148         BLI_split_dir_part(name, di, sizeof(di));
1149
1150         /* make if the dir doesn't exist */
1151         BLI_dir_create_recursive(di);
1152 }
1153
1154 /**
1155  * Returns in *string the concatenation of *dir and *file (also with *relabase on the
1156  * front if specified and *dir begins with "//"). Normalizes all occurrences of path
1157  * separators, including ensuring there is exactly one between the copies of *dir and *file,
1158  * and between the copies of *relabase and *dir.
1159  *
1160  * \param relabase  Optional prefix to substitute for "//" on front of *dir
1161  * \param string  Area to return result
1162  */
1163 void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file)
1164 {
1165         int sl;
1166
1167         if (string) {
1168                 /* ensure this is always set even if dir/file are NULL */
1169                 string[0] = '\0';
1170
1171                 if (ELEM(NULL, dir, file)) {
1172                         return; /* We don't want any NULLs */
1173                 }
1174         }
1175         else {
1176                 return; /* string is NULL, probably shouldnt happen but return anyway */
1177         }
1178
1179
1180         /* we first push all slashes into unix mode, just to make sure we don't get
1181          * any mess with slashes later on. -jesterKing */
1182         /* constant strings can be passed for those parameters - don't change them - elubie */
1183 #if 0
1184         BLI_char_switch(relabase, '\\', '/');
1185         BLI_char_switch(dir, '\\', '/');
1186         BLI_char_switch(file, '\\', '/');
1187 #endif
1188
1189         /* Resolve relative references */
1190         if (relabase && dir[0] == '/' && dir[1] == '/') {
1191                 char *lslash;
1192                 
1193                 /* Get the file name, chop everything past the last slash (ie. the filename) */
1194                 strcpy(string, relabase);
1195                 
1196                 lslash = (char *)BLI_last_slash(string);
1197                 if (lslash) *(lslash + 1) = 0;
1198
1199                 dir += 2; /* Skip over the relative reference */
1200         }
1201 #ifdef WIN32
1202         else {
1203                 if (BLI_strnlen(dir, 3) >= 2 && dir[1] == ':') {
1204                         BLI_strncpy(string, dir, 3);
1205                         dir += 2;
1206                 }
1207                 else if (BLI_strnlen(dir, 3) >= 2 && BLI_path_is_unc(dir)) {
1208                         string[0] = 0;
1209                 }
1210                 else { /* no drive specified */
1211                            /* first option: get the drive from the relabase if it has one */
1212                         if (relabase && BLI_strnlen(relabase, 3) >= 2 && relabase[1] == ':') {
1213                                 BLI_strncpy(string, relabase, 3);
1214                                 string[2] = '\\';
1215                                 string[3] = '\0';
1216                         }
1217                         else { /* we're out of luck here, guessing the first valid drive, usually c:\ */
1218                                 get_default_root(string);
1219                         }
1220                         
1221                         /* ignore leading slashes */
1222                         while (*dir == '/' || *dir == '\\') dir++;
1223                 }
1224         }
1225 #endif
1226
1227         strcat(string, dir);
1228
1229         /* Make sure string ends in one (and only one) slash */
1230         /* first trim all slashes from the end of the string */
1231         sl = strlen(string);
1232         while (sl > 0 && (string[sl - 1] == '/' || string[sl - 1] == '\\') ) {
1233                 string[sl - 1] = '\0';
1234                 sl--;
1235         }
1236         /* since we've now removed all slashes, put back one slash at the end. */
1237         strcat(string, "/");
1238         
1239         while (*file && (*file == '/' || *file == '\\')) /* Trim slashes from the front of file */
1240                 file++;
1241                 
1242         strcat(string, file);
1243         
1244         /* Push all slashes to the system preferred direction */
1245         BLI_path_native_slash(string);
1246 }
1247
1248 static bool testextensie_ex(const char *str, const size_t str_len,
1249                             const char *ext, const size_t ext_len)
1250 {
1251         BLI_assert(strlen(str) == str_len);
1252         BLI_assert(strlen(ext) == ext_len);
1253
1254         return  (((str_len == 0 || ext_len == 0 || ext_len >= str_len) == 0) &&
1255                  (BLI_strcasecmp(ext, str + str_len - ext_len) == 0));
1256 }
1257
1258 /* does str end with ext. */
1259 bool BLI_testextensie(const char *str, const char *ext)
1260 {
1261         return testextensie_ex(str, strlen(str), ext, strlen(ext));
1262 }
1263
1264 bool BLI_testextensie_n(const char *str, ...)
1265 {
1266         const size_t str_len = strlen(str);
1267
1268         va_list args;
1269         const char *ext;
1270         bool ret = false;
1271
1272         va_start(args, str);
1273
1274         while ((ext = (const char *) va_arg(args, void *))) {
1275                 if (testextensie_ex(str, str_len, ext, strlen(ext))) {
1276                         ret = true;
1277                         break;
1278                 }
1279         }
1280
1281         va_end(args);
1282
1283         return ret;
1284 }
1285
1286 /* does str end with any of the suffixes in *ext_array. */
1287 bool BLI_testextensie_array(const char *str, const char **ext_array)
1288 {
1289         const size_t str_len = strlen(str);
1290         int i = 0;
1291
1292         while (ext_array[i]) {
1293                 if (testextensie_ex(str, str_len, ext_array[i], strlen(ext_array[i]))) {
1294                         return true;
1295                 }
1296
1297                 i++;
1298         }
1299         return false;
1300 }
1301
1302 /**
1303  * Semicolon separated wildcards, eg:
1304  *  '*.zip;*.py;*.exe'
1305  * does str match any of the semicolon-separated glob patterns in fnmatch.
1306  */
1307 bool BLI_testextensie_glob(const char *str, const char *ext_fnmatch)
1308 {
1309         const char *ext_step = ext_fnmatch;
1310         char pattern[16];
1311
1312         while (ext_step[0]) {
1313                 const char *ext_next;
1314                 int len_ext;
1315
1316                 if ((ext_next = strchr(ext_step, ';'))) {
1317                         len_ext = (int)(ext_next - ext_step) + 1;
1318                 }
1319                 else {
1320                         len_ext = sizeof(pattern);
1321                 }
1322
1323                 BLI_strncpy(pattern, ext_step, len_ext);
1324
1325                 if (fnmatch(pattern, str, FNM_CASEFOLD) == 0) {
1326                         return true;
1327                 }
1328                 ext_step += len_ext;
1329         }
1330
1331         return false;
1332 }
1333
1334
1335 /**
1336  * Removes any existing extension on the end of \a path and appends \a ext.
1337  * \return false if there was no room.
1338  */
1339 bool BLI_replace_extension(char *path, size_t maxlen, const char *ext)
1340 {
1341         const size_t path_len = strlen(path);
1342         const size_t ext_len = strlen(ext);
1343         ssize_t a;
1344
1345         for (a = path_len - 1; a >= 0; a--) {
1346                 if (ELEM(path[a], '.', '/', '\\')) {
1347                         break;
1348                 }
1349         }
1350
1351         if ((a < 0) || (path[a] != '.')) {
1352                 a = path_len;
1353         }
1354
1355         if (a + ext_len >= maxlen)
1356                 return false;
1357
1358         memcpy(path + a, ext, ext_len + 1);
1359         return true;
1360 }
1361
1362 /**
1363  * Strip's trailing '.'s and adds the extension only when needed
1364  */
1365 bool BLI_ensure_extension(char *path, size_t maxlen, const char *ext)
1366 {
1367         const size_t path_len = strlen(path);
1368         const size_t ext_len = strlen(ext);
1369         ssize_t a;
1370
1371         /* first check the extension is already there */
1372         if ((ext_len <= path_len) && (STREQ(path + (path_len - ext_len), ext))) {
1373                 return true;
1374         }
1375
1376         for (a = path_len - 1; a >= 0; a--) {
1377                 if (path[a] == '.') {
1378                         path[a] = '\0';
1379                 }
1380                 else {
1381                         break;
1382                 }
1383         }
1384         a++;
1385
1386         if (a + ext_len >= maxlen)
1387                 return false;
1388
1389         memcpy(path + a, ext, ext_len + 1);
1390         return true;
1391 }
1392
1393 bool BLI_ensure_filename(char *filepath, size_t maxlen, const char *filename)
1394 {
1395         char *c = (char *)BLI_last_slash(filepath);
1396         if (!c || ((c - filepath) < maxlen - (strlen(filename) + 1))) {
1397                 strcpy(c ? &c[1] : filepath, filename);
1398                 return true;
1399         }
1400         return false;
1401 }
1402
1403 /* Converts "/foo/bar.txt" to "/foo/" and "bar.txt"
1404  * - wont change 'string'
1405  * - wont create any directories
1406  * - dosnt use CWD, or deal with relative paths.
1407  * - Only fill's in *dir and *file when they are non NULL
1408  * */
1409 void BLI_split_dirfile(const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen)
1410 {
1411         const char *lslash_str = BLI_last_slash(string);
1412         const size_t lslash = lslash_str ? (size_t)(lslash_str - string) + 1 : 0;
1413
1414         if (dir) {
1415                 if (lslash) {
1416                         BLI_strncpy(dir, string, MIN2(dirlen, lslash + 1)); /* +1 to include the slash and the last char */
1417                 }
1418                 else {
1419                         dir[0] = '\0';
1420                 }
1421         }
1422         
1423         if (file) {
1424                 BLI_strncpy(file, string + lslash, filelen);
1425         }
1426 }
1427
1428 /**
1429  * Copies the parent directory part of string into *dir, max length dirlen.
1430  */
1431 void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen)
1432 {
1433         BLI_split_dirfile(string, dir, NULL, dirlen, 0);
1434 }
1435
1436 /**
1437  * Copies the leaf filename part of string into *file, max length filelen.
1438  */
1439 void BLI_split_file_part(const char *string, char *file, const size_t filelen)
1440 {
1441         BLI_split_dirfile(string, NULL, file, 0, filelen);
1442 }
1443
1444 /**
1445  * Append a filename to a dir, ensuring slash separates.
1446  */
1447 void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file)
1448 {
1449         size_t dirlen = BLI_strnlen(dst, maxlen);
1450
1451         /* inline BLI_add_slash */
1452         if ((dirlen > 0) && (dst[dirlen - 1] != SEP)) {
1453                 dst[dirlen++] = SEP;
1454                 dst[dirlen] = '\0';
1455         }
1456
1457         if (dirlen >= maxlen) {
1458                 return; /* fills the path */
1459         }
1460
1461         BLI_strncpy(dst + dirlen, file, maxlen - dirlen);
1462 }
1463
1464 /**
1465  * Simple appending of filename to dir, does not check for valid path!
1466  * Puts result into *dst, which may be same area as *dir.
1467  */
1468 void BLI_join_dirfile(char *__restrict dst, const size_t maxlen, const char *__restrict dir, const char *__restrict file)
1469 {
1470         size_t dirlen = BLI_strnlen(dir, maxlen);
1471
1472         /* args can't match */
1473         BLI_assert(!ELEM(dst, dir, file));
1474
1475         if (dirlen == maxlen) {
1476                 memcpy(dst, dir, dirlen);
1477                 dst[dirlen - 1] = '\0';
1478                 return; /* dir fills the path */
1479         }
1480         else {
1481                 memcpy(dst, dir, dirlen + 1);
1482         }
1483
1484         if (dirlen + 1 >= maxlen) {
1485                 return; /* fills the path */
1486         }
1487
1488         /* inline BLI_add_slash */
1489         if ((dirlen > 0) && (dst[dirlen - 1] != SEP)) {
1490                 dst[dirlen++] = SEP;
1491                 dst[dirlen] = '\0';
1492         }
1493
1494         if (dirlen >= maxlen) {
1495                 return; /* fills the path */
1496         }
1497
1498         BLI_strncpy(dst + dirlen, file, maxlen - dirlen);
1499 }
1500
1501 /**
1502  * like pythons os.path.basename()
1503  *
1504  * \return The pointer into \a path string immediately after last slash,
1505  * or start of \a path if none found.
1506  */
1507 const char *BLI_path_basename(const char *path)
1508 {
1509         const char * const filename = BLI_last_slash(path);
1510         return filename ? filename + 1 : path;
1511 }
1512
1513 /* UNUSED */
1514 #if 0
1515 /**
1516  * Produce image export path.
1517  * 
1518  * Returns:
1519  * 0        if image filename is empty or if destination path
1520  *          matches image path (i.e. both are the same file).
1521  * 2        if source is identical to destination.
1522  * 1        if rebase was successful
1523  * -------------------------------------------------------------
1524  * Hint: Trailing slash in dest_dir is optional.
1525  *
1526  * Logic:
1527  *
1528  * - if an image is "below" current .blend file directory:
1529  *   rebuild the same dir structure in dest_dir
1530  *
1531  *   Example: 
1532  *   src : //textures/foo/bar.png
1533  *   dest: [dest_dir]/textures/foo/bar.png.
1534  *
1535  * - if an image is not "below" current .blend file directory,
1536  *   disregard it's path and copy it into the destination  
1537  *   directory.
1538  *
1539  *   Example:
1540  *   src : //../foo/bar.png becomes
1541  *   dest: [dest_dir]/bar.png.
1542  *
1543  * This logic ensures that all image paths are relative and
1544  * that a user gets his images in one place. It'll also provide
1545  * consistent behavior across exporters.
1546  * IMPORTANT NOTE: If base_dir contains an empty string, then
1547  * this function returns wrong results!
1548  * XXX: test on empty base_dir and return an error ?
1549  */
1550
1551 /**
1552  *
1553  * \param abs  Optional string to return new full path
1554  * \param abs_len  Size of *abs string
1555  * \param rel  Optional area to return new path relative to parent directory of .blend file
1556  *             (only meaningful if item is in a subdirectory thereof)
1557  * \param rel_len  Size of *rel area
1558  * \param base_dir  Path of .blend file
1559  * \param src_dir  Original path of item (any initial "//" will be expanded to
1560  *                 parent directory of .blend file)
1561  * \param dest_dir  New directory into which item will be moved
1562  * \return bli_rebase_state
1563  *
1564  * \note Not actually used anywhere!
1565  */
1566 int BLI_rebase_path(char *abs, size_t abs_len,
1567                     char *rel, size_t rel_len,
1568                     const char *base_dir, const char *src_dir, const char *dest_dir)
1569 {
1570         char path[FILE_MAX];  /* original full path of item */
1571         char dir[FILE_MAX];   /* directory part of src_dir */
1572         char base[FILE_MAX];  /* basename part of src_dir */
1573         char blend_dir[FILE_MAX];   /* directory, where current .blend file resides */
1574         char dest_path[FILE_MAX];
1575         char rel_dir[FILE_MAX];
1576         int len;
1577
1578         if (abs)
1579                 abs[0] = 0;
1580
1581         if (rel)
1582                 rel[0] = 0;
1583
1584         BLI_split_dir_part(base_dir, blend_dir, sizeof(blend_dir));
1585
1586         if (src_dir[0] == '\0')
1587                 return BLI_REBASE_NO_SRCDIR;
1588
1589         BLI_strncpy(path, src_dir, sizeof(path));
1590
1591         /* expand "//" in filename and get absolute path */
1592         BLI_path_abs(path, base_dir);
1593
1594         /* get the directory part */
1595         BLI_split_dirfile(path, dir, base, sizeof(dir), sizeof(base));
1596
1597         len = strlen(blend_dir);
1598
1599         rel_dir[0] = 0;
1600
1601         /* if image is "below" current .blend file directory */
1602         if (!BLI_path_ncmp(path, blend_dir, len)) {
1603
1604                 if (BLI_path_cmp(dir, blend_dir) == 0) {
1605                         /* image is directly in .blend file parent directory => put directly in dest_dir */
1606                         BLI_join_dirfile(dest_path, sizeof(dest_path), dest_dir, base);
1607                 }
1608                 else {
1609                         /* "below" (in subdirectory of .blend file parent directory) => put in same relative directory structure in dest_dir */
1610                         /* rel = image_path_dir - blend_dir */
1611                         BLI_strncpy(rel_dir, dir + len, sizeof(rel_dir));
1612                         /* subdirectories relative to blend_dir */
1613                         BLI_join_dirfile(dest_path, sizeof(dest_path), dest_dir, rel_dir);
1614                         /* same subdirectories relative to dest_dir */
1615                         BLI_path_append(dest_path, sizeof(dest_path), base);
1616                         /* keeping original item basename */
1617                 }
1618
1619         }
1620         /* image is out of current directory -- just put straight in dest_dir */
1621         else {
1622                 BLI_join_dirfile(dest_path, sizeof(dest_path), dest_dir, base);
1623         }
1624
1625         if (abs)
1626                 BLI_strncpy(abs, dest_path, abs_len);
1627
1628         if (rel) {
1629                 strncat(rel, rel_dir, rel_len);
1630                 strncat(rel, base, rel_len); /* FIXME: could overflow rel area! */
1631         }
1632
1633         /* return 2 if (src == dest) */
1634         if (BLI_path_cmp(path, dest_path) == 0) {
1635                 // if (G.debug & G_DEBUG) printf("%s and %s are the same file\n", path, dest_path);
1636                 return BLI_REBASE_IDENTITY;
1637         }
1638
1639         return BLI_REBASE_OK;
1640 }
1641 #endif
1642
1643
1644 /**
1645  * Returns pointer to the leftmost path separator in string. Not actually used anywhere.
1646  */
1647 const char *BLI_first_slash(const char *string)
1648 {
1649         const char * const ffslash = strchr(string, '/');
1650         const char * const fbslash = strchr(string, '\\');
1651         
1652         if (!ffslash) return fbslash;
1653         else if (!fbslash) return ffslash;
1654         
1655         if ((intptr_t)ffslash < (intptr_t)fbslash) return ffslash;
1656         else return fbslash;
1657 }
1658
1659 /**
1660  * Returns pointer to the rightmost path separator in string.
1661  */
1662 const char *BLI_last_slash(const char *string)
1663 {
1664         const char * const lfslash = strrchr(string, '/');
1665         const char * const lbslash = strrchr(string, '\\');
1666
1667         if (!lfslash) return lbslash; 
1668         else if (!lbslash) return lfslash;
1669         
1670         if ((intptr_t)lfslash < (intptr_t)lbslash) return lbslash;
1671         else return lfslash;
1672 }
1673
1674 /**
1675  * Appends a slash to string if there isn't one there already.
1676  * Returns the new length of the string.
1677  */
1678 int BLI_add_slash(char *string)
1679 {
1680         int len = strlen(string);
1681         if (len == 0 || string[len - 1] != SEP) {
1682                 string[len] = SEP;
1683                 string[len + 1] = '\0';
1684                 return len + 1;
1685         }
1686         return len;
1687 }
1688
1689 /**
1690  * Removes the last slash and everything after it to the end of string, if there is one.
1691  */
1692 void BLI_del_slash(char *string)
1693 {
1694         int len = strlen(string);
1695         while (len) {
1696                 if (string[len - 1] == SEP) {
1697                         string[len - 1] = '\0';
1698                         len--;
1699                 }
1700                 else {
1701                         break;
1702                 }
1703         }
1704 }
1705
1706 /**
1707  * Changes to the path separators to the native ones for this OS.
1708  */
1709 void BLI_path_native_slash(char *path)
1710 {
1711 #ifdef WIN32
1712         if (path && BLI_strnlen(path, 3) > 2) {
1713                 BLI_char_switch(path + 2, '/', '\\');
1714         }
1715 #else
1716         BLI_char_switch(path + BLI_path_unc_prefix_len(path), '\\', '/');
1717 #endif
1718 }
1719
1720
1721 #ifdef WITH_ICONV
1722
1723 /**
1724  * Converts a string encoded in the charset named by *code to UTF-8.
1725  * Opens a new iconv context each time it is run, which is probably not the
1726  * most efficient. */
1727 void BLI_string_to_utf8(char *original, char *utf_8, const char *code)
1728 {
1729         size_t inbytesleft = strlen(original);
1730         size_t outbytesleft = 512;
1731         size_t rv = 0;
1732         iconv_t cd;
1733         
1734         if (NULL == code) {
1735                 code = locale_charset();
1736         }
1737         cd = iconv_open("UTF-8", code);
1738
1739         if (cd == (iconv_t)(-1)) {
1740                 printf("iconv_open Error");
1741                 *utf_8 = '\0';
1742                 return;
1743         }
1744         rv = iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft);
1745         if (rv == (size_t) -1) {
1746                 printf("iconv Error\n");
1747                 iconv_close(cd);
1748                 return;
1749         }
1750         *utf_8 = '\0';
1751         iconv_close(cd);
1752 }
1753 #endif // WITH_ICONV