- changes to the sequencer so new strips use the data name.
[blender.git] / source / blender / blenlib / intern / path_util.c
1 /**
2  *  $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  *
29  * various string, file, list operations.
30  */
31
32 #include <ctype.h>
33 #include <string.h>
34 #include <stdlib.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "DNA_userdef_types.h"
39
40 #include "BLI_fileops.h"
41 #include "BLI_path_util.h"
42 #include "BLI_string.h"
43 #include "BLI_storage.h"
44 #include "BLI_storage_types.h"
45
46 #include "BKE_utildefines.h"
47
48
49
50
51
52 #ifdef WIN32
53 #include <io.h>
54
55 #ifdef _WIN32_IE
56 #undef _WIN32_IE
57 #endif
58 #define _WIN32_IE 0x0501
59 #include <windows.h>
60 #include <shlobj.h>
61
62 #include "BLI_winstuff.h"
63
64 #else /* non windows */
65
66 #ifdef __APPLE__
67 #include <sys/param.h>
68 #include <CoreFoundation/CoreFoundation.h>
69 #endif
70
71 #ifdef __linux__
72 #include "binreloc.h"
73 #endif
74
75 #endif /* WIN32 */
76
77 /* local */
78
79 static int add_win32_extension(char *name);
80
81 /* implementation */
82
83 int BLI_stringdec(const char *string, char *head, char *tail, unsigned short *numlen)
84 {
85         unsigned short len, len2, lenlslash = 0, nums = 0, nume = 0;
86         short i, found = 0;
87         char *lslash = BLI_last_slash(string);
88         len2 = len = strlen(string);
89         if(lslash)
90                 lenlslash= (int)(lslash - string);
91
92         while(len > lenlslash && string[--len] != '.') {};
93         if(len == lenlslash && string[len] != '.') len = len2;
94
95         for (i = len - 1; i >= lenlslash; i--) {
96                 if (isdigit(string[i])) {
97                         if (found){
98                                 nums = i;
99                         }
100                         else{
101                                 nume = i;
102                                 nums = i;
103                                 found = 1;
104                         }
105                 }
106                 else {
107                         if (found) break;
108                 }
109         }
110         if (found) {
111                 if (tail) strcpy(tail, &string[nume+1]);
112                 if (head) BLI_strncpy(head, string, nums);
113                 if (numlen) *numlen = nume-nums+1;
114                 return ((int)atoi(&(string[nums])));
115         }
116         if (tail) strcpy(tail, string + len);
117         if (head) BLI_strncpy(head, string, nums);
118         if (numlen) *numlen=0;
119         return 0;
120 }
121
122
123 void BLI_stringenc(char *string, const char *head, const char *tail, unsigned short numlen, int pic)
124 {
125         char fmtstr[16]="";
126         if(pic < 0) pic= 0;
127         sprintf(fmtstr, "%%s%%.%dd%%s", numlen);
128         sprintf(string, fmtstr, head, pic, tail);
129 }
130
131
132 void BLI_newname(char *name, int add)
133 {
134         char head[128], tail[128];
135         int pic;
136         unsigned short digits;
137         
138         pic = BLI_stringdec(name, head, tail, &digits);
139         
140         /* are we going from 100 -> 99 or from 10 -> 9 */
141         if (add < 0 && digits < 4 && digits > 0) {
142                 int i, exp;
143                 exp = 1;
144                 for (i = digits; i > 1; i--) exp *= 10;
145                 if (pic >= exp && (pic + add) < exp) digits--;
146         }
147         
148         pic += add;
149         
150         if (digits==4 && pic<0) pic= 0;
151         BLI_stringenc(name, head, tail, digits, pic);
152 }
153
154 /* little helper macro for BLI_uniquename */
155 #ifndef GIVE_STRADDR
156         #define GIVE_STRADDR(data, offset) ( ((char *)data) + offset )
157 #endif
158
159 /* Generic function to set a unique name. It is only designed to be used in situations
160  * where the name is part of the struct, and also that the name is at most 128 chars long.
161  * 
162  * For places where this is used, see constraint.c for example...
163  *
164  *      name_offs: should be calculated using offsetof(structname, membername) macro from stddef.h
165  *      len: maximum length of string (to prevent overflows, etc.)
166  *      defname: the name that should be used by default if none is specified already
167  *      delim: the character which acts as a delimeter between parts of the name
168  */
169 void BLI_uniquename(ListBase *list, void *vlink, const char defname[], char delim, short name_offs, short len)
170 {
171         Link *link;
172         char tempname[128];
173         int     number = 1, exists = 0;
174         char *dot;
175         
176         /* Make sure length can be handled */
177         if ((len < 0) || (len > 128))
178                 return;
179         
180         /* See if we are given an empty string */
181         if (ELEM(NULL, vlink, defname))
182                 return;
183         
184         if (GIVE_STRADDR(vlink, name_offs) == '\0') {
185                 /* give it default name first */
186                 BLI_strncpy(GIVE_STRADDR(vlink, name_offs), defname, len);
187         }
188         
189         /* See if we even need to do this */
190         if (list == NULL)
191                 return;
192         
193         for (link = list->first; link; link= link->next) {
194                 if (link != vlink) {
195                         if (!strcmp(GIVE_STRADDR(link, name_offs), GIVE_STRADDR(vlink, name_offs))) {
196                                 exists = 1;
197                                 break;
198                         }
199                 }
200         }
201         if (exists == 0)
202                 return;
203
204         /* Strip off the suffix */
205         dot = strrchr(GIVE_STRADDR(vlink, name_offs), delim);
206         if (dot)
207                 *dot=0;
208         
209         for (number = 1; number <= 999; number++) {
210                 BLI_snprintf(tempname, sizeof(tempname), "%s%c%03d", GIVE_STRADDR(vlink, name_offs), delim, number);
211                 
212                 exists = 0;
213                 for (link= list->first; link; link= link->next) {
214                         if (vlink != link) {
215                                 if (!strcmp(GIVE_STRADDR(link, name_offs), tempname)) {
216                                         exists = 1;
217                                         break;
218                                 }
219                         }
220                 }
221                 if (exists == 0) {
222                         BLI_strncpy(GIVE_STRADDR(vlink, name_offs), tempname, len);
223                         return;
224                 }
225         }
226 }
227
228 /* ******************** string encoding ***************** */
229
230 /* This is quite an ugly function... its purpose is to
231  * take the dir name, make it absolute, and clean it up, replacing
232  * excess file entry stuff (like /tmp/../tmp/../)
233  * note that dir isn't protected for max string names... 
234  * 
235  * If relbase is NULL then its ignored
236  */
237
238 void BLI_cleanup_dir(const char *relabase, char *dir)
239 {
240         BLI_cleanup_file(relabase, dir);
241         BLI_add_slash(dir);
242
243 }
244
245 void BLI_cleanup_file(const char *relabase, char *dir)
246 {
247         short a;
248         char *start, *eind;
249         if (relabase) {
250                 BLI_path_abs(dir, relabase);
251         } else {
252                 if (dir[0]=='/' && dir[1]=='/') {
253                         if (dir[2]== '\0') {
254                                 return; /* path is "//" - cant clean it */
255                         }
256                         dir = dir+2; /* skip the first // */
257                 }
258         }
259         
260         /* Note
261          *   memmove( start, eind, strlen(eind)+1 );
262          * is the same as
263          *   strcpy( start, eind ); 
264          * except strcpy should not be used because there is overlap,
265           * so use memmove's slightly more obscure syntax - Campbell
266          */
267         
268 #ifdef WIN32
269         
270         /* Note, this should really be moved to the file selector,
271          * since this function is used in many areas */
272         if(strcmp(dir, ".")==0) {       /* happens for example in FILE_MAIN */
273            get_default_root(dir);
274            return;
275         }       
276
277         while ( (start = strstr(dir, "\\..\\")) ) {
278                 eind = start + strlen("\\..\\") - 1;
279                 a = start-dir-1;
280                 while (a>0) {
281                         if (dir[a] == '\\') break;
282                         a--;
283                 }
284                 if (a<0) {
285                         break;
286                 } else {
287                         memmove( dir+a, eind, strlen(eind)+1 );
288                 }
289         }
290
291         while ( (start = strstr(dir,"\\.\\")) ){
292                 eind = start + strlen("\\.\\") - 1;
293                 memmove( start, eind, strlen(eind)+1 );
294         }
295
296         while ( (start = strstr(dir,"\\\\" )) ){
297                 eind = start + strlen("\\\\") - 1;
298                 memmove( start, eind, strlen(eind)+1 );
299         }
300
301         if((a = strlen(dir))){                          /* remove the '\\' at the end */
302                 while(a>0 && dir[a-1] == '\\'){
303                         a--;
304                         dir[a] = 0;
305                 }
306         }
307 #else
308         if(dir[0]=='.') {       /* happens, for example in FILE_MAIN */
309            dir[0]= '/';
310            dir[1]= 0;
311            return;
312         }       
313
314         while ( (start = strstr(dir, "/../")) ) {
315                 eind = start + strlen("/../") - 1;
316                 a = start-dir-1;
317                 while (a>0) {
318                         if (dir[a] == '/') break;
319                         a--;
320                 }
321                 if (a<0) {
322                         break;
323                 } else {
324                         memmove( dir+a, eind, strlen(eind)+1 );
325                 }
326         }
327
328         while ( (start = strstr(dir,"/./")) ){
329                 eind = start + strlen("/./") - 1;
330                 memmove( start, eind, strlen(eind)+1 );
331         }
332
333         while ( (start = strstr(dir,"//" )) ){
334                 eind = start + strlen("//") - 1;
335                 memmove( start, eind, strlen(eind)+1 );
336         }
337
338         if( (a = strlen(dir)) ){                                /* remove all '/' at the end */
339                 while(dir[a-1] == '/'){
340                         a--;
341                         dir[a] = 0;
342                         if (a<=0) break;
343                 }
344         }
345 #endif
346 }
347
348
349 void BLI_path_rel(char *file, const char *relfile)
350 {
351         char * lslash;
352         char temp[FILE_MAXDIR+FILE_MAXFILE];
353         char res[FILE_MAXDIR+FILE_MAXFILE];
354         
355         /* if file is already relative, bail out */
356         if(file[0]=='/' && file[1]=='/') return;
357         
358         /* also bail out if relative path is not set */
359         if (relfile[0] == 0) return;
360
361 #ifdef WIN32 
362         if (strlen(relfile) > 2 && relfile[1] != ':') {
363                 char* ptemp;
364                 /* fix missing volume name in relative base,
365                    can happen with old .Blog files */
366                 get_default_root(temp);
367                 ptemp = &temp[2];
368                 if (relfile[0] != '\\' && relfile[0] != '/') {
369                         ptemp++;
370                 }
371                 BLI_strncpy(ptemp, relfile, FILE_MAXDIR + FILE_MAXFILE-3);
372         } else {
373                 BLI_strncpy(temp, relfile, FILE_MAXDIR + FILE_MAXFILE);
374         }
375
376         if (strlen(file) > 2) {
377                 if ( temp[1] == ':' && file[1] == ':' && temp[0] != file[0] )
378                         return;
379         }
380 #else
381         BLI_strncpy(temp, relfile, FILE_MAX);
382 #endif
383
384         BLI_char_switch(temp, '\\', '/');
385         BLI_char_switch(file, '\\', '/');
386         
387         /* remove /./ which confuse the following slash counting... */
388         BLI_cleanup_file(NULL, file);
389         BLI_cleanup_file(NULL, temp);
390         
391         /* the last slash in the file indicates where the path part ends */
392         lslash = BLI_last_slash(temp);
393
394         if (lslash) 
395         {       
396                 /* find the prefix of the filename that is equal for both filenames.
397                    This is replaced by the two slashes at the beginning */
398                 char *p= temp;
399                 char *q= file;
400
401                 while ((*p == *q)) {
402                         ++p; ++q;
403                         /* dont search beyond the end of the string
404                          * in the rare case they match */
405                         if ((*p=='\0') || (*q=='\0')) {
406                                 break;
407                         }
408                 }
409
410                 /* we might have passed the slash when the beginning of a dir matches 
411                    so we rewind. Only check on the actual filename
412                 */
413                 if (*q != '/') {
414                         while ( (q >= file) && (*q != '/') ) { --q; --p; }
415                 } 
416                 else if (*p != '/') {
417                         while ( (p >= temp) && (*p != '/') ) { --p; --q; }
418                 }
419                 
420                 strcpy(res,     "//");
421
422                 /* p now points to the slash that is at the beginning of the part
423                    where the path is different from the relative path. 
424                    We count the number of directories we need to go up in the
425                    hierarchy to arrive at the common 'prefix' of the path
426                 */                      
427                 while (p && p < lslash) {
428                         if (*p == '/') 
429                                 strcat(res,     "../");
430                         ++p;
431                 }
432
433                 strcat(res, q+1); /* don't copy the slash at the beginning */
434                 
435 #ifdef  WIN32
436                 BLI_char_switch(res+2, '/', '\\');
437 #endif
438                 strcpy(file, res);
439         }
440 }
441
442 int BLI_has_parent(char *path)
443 {
444         int len;
445         int slashes = 0;
446         BLI_clean(path);
447         len = BLI_add_slash(path) - 1;
448
449         while (len>=0) {
450                 if ((path[len] == '\\') || (path[len] == '/'))
451                         slashes++;
452                 len--;
453         }
454         return slashes > 1;
455 }
456
457 int BLI_parent_dir(char *path)
458 {
459 #ifdef WIN32
460         static char *parent_dir="..\\";
461 #else
462         static char *parent_dir="../";
463 #endif
464         char tmp[FILE_MAXDIR+FILE_MAXFILE+4];
465         BLI_strncpy(tmp, path, sizeof(tmp));
466         BLI_add_slash(tmp);
467         strcat(tmp, parent_dir);
468         BLI_cleanup_dir(NULL, tmp);
469         
470         if (!BLI_testextensie(tmp, parent_dir)) {
471                 BLI_strncpy(path, tmp, sizeof(tmp));    
472                 return 1;
473         } else {
474                 return 0;
475         }
476 }
477
478 static int stringframe_chars(char *path, int *char_start, int *char_end)
479 {
480         int ch_sta, ch_end, i;
481         /* Insert current frame: file### -> file001 */
482         ch_sta = ch_end = 0;
483         for (i = 0; path[i] != '\0'; i++) {
484                 if (path[i] == '\\' || path[i] == '/') {
485                         ch_end = 0; /* this is a directory name, dont use any hashes we found */
486                 } else if (path[i] == '#') {
487                         ch_sta = i;
488                         ch_end = ch_sta+1;
489                         while (path[ch_end] == '#') {
490                                 ch_end++;
491                         }
492                         i = ch_end-1; /* keep searching */
493                         
494                         /* dont break, there may be a slash after this that invalidates the previous #'s */
495                 }
496         }
497
498         if(ch_end) {
499                 *char_start= ch_sta;
500                 *char_end= ch_end;
501                 return 1;
502         }
503         else {
504                 *char_start= -1;
505                 *char_end= -1;
506                 return 0;
507         }
508 }
509
510 static void ensure_digits(char *path, int digits)
511 {
512         char *file= BLI_last_slash(path);
513
514         if(file==NULL)
515                 file= path;
516
517         if(strrchr(file, '#') == NULL) {
518                 int len= strlen(file);
519
520                 while(digits--) {
521                         file[len++]= '#';
522                 }
523                 file[len]= '\0';
524         }
525 }
526
527 int BLI_path_frame(char *path, int frame, int digits)
528 {
529         int ch_sta, ch_end;
530
531         if(digits)
532                 ensure_digits(path, digits);
533
534         if (stringframe_chars(path, &ch_sta, &ch_end)) { /* warning, ch_end is the last # +1 */
535                 char tmp[FILE_MAX], format[64];
536                 sprintf(format, "%%.%ds%%.%dd%%s", ch_sta, ch_end-ch_sta); /* example result: "%.12s%.5d%s" */
537                 sprintf(tmp, format, path, frame, path+ch_end);
538                 strcpy(path, tmp);
539                 return 1;
540         }
541         return 0;
542 }
543
544 int BLI_path_frame_range(char *path, int sta, int end, int digits)
545 {
546         int ch_sta, ch_end;
547
548         if(digits)
549                 ensure_digits(path, digits);
550
551         if (stringframe_chars(path, &ch_sta, &ch_end)) { /* warning, ch_end is the last # +1 */
552                 char tmp[FILE_MAX], format[64];
553                 sprintf(format, "%%.%ds%%.%dd_%%.%dd%%s", ch_sta, ch_end-ch_sta, ch_end-ch_sta); /* example result: "%.12s%.5d-%.5d%s" */
554                 sprintf(tmp, format, path, sta, end, path+ch_end);
555                 strcpy(path, tmp);
556                 return 1;
557         }
558         return 0;
559 }
560
561 int BLI_path_abs(char *path, const char *basepath)
562 {
563         int wasrelative = (strncmp(path, "//", 2)==0);
564         char tmp[FILE_MAX];
565         char base[FILE_MAX];
566 #ifdef WIN32
567         char vol[3] = {'\0', '\0', '\0'};
568
569         BLI_strncpy(vol, path, 3);
570         /* we are checking here if we have an absolute path that is not in the current
571            blend file as a lib main - we are basically checking for the case that a 
572            UNIX root '/' is passed.
573         */
574         if (!wasrelative && (vol[1] != ':' && (vol[0] == '\0' || vol[0] == '/' || vol[0] == '\\'))) {
575                 char *p = path;
576                 get_default_root(tmp);
577                 // get rid of the slashes at the beginning of the path
578                 while (*p == '\\' || *p == '/') {
579                         p++;
580                 }
581                 strcat(tmp, p);
582         }
583         else {
584                 BLI_strncpy(tmp, path, FILE_MAX);
585         }
586 #else
587         BLI_strncpy(tmp, path, FILE_MAX);
588         
589         /* Check for loading a windows path on a posix system
590          * in this case, there is no use in trying C:/ since it 
591          * will never exist on a unix os.
592          * 
593          * Add a / prefix and lowercase the driveletter, remove the :
594          * C:\foo.JPG -> /c/foo.JPG */
595         
596         if (isalpha(tmp[0]) && tmp[1] == ':' && (tmp[2]=='\\' || tmp[2]=='/') ) {
597                 tmp[1] = tolower(tmp[0]); /* replace ':' with driveletter */
598                 tmp[0] = '/'; 
599                 /* '\' the slash will be converted later */
600         }
601         
602 #endif
603
604         BLI_strncpy(base, basepath, FILE_MAX);
605         
606         BLI_cleanup_file(NULL, base);
607         
608         /* push slashes into unix mode - strings entering this part are
609            potentially messed up: having both back- and forward slashes.
610            Here we push into one conform direction, and at the end we
611            push them into the system specific dir. This ensures uniformity
612            of paths and solving some problems (and prevent potential future
613            ones) -jesterKing. */
614         BLI_char_switch(tmp, '\\', '/');
615         BLI_char_switch(base, '\\', '/');       
616
617         /* Paths starting with // will get the blend file as their base,
618          * this isnt standard in any os but is uesed in blender all over the place */
619         if (wasrelative) {
620                 char *lslash= BLI_last_slash(base);
621                 if (lslash) {
622                         int baselen= (int) (lslash-base) + 1;
623                         /* use path for temp storage here, we copy back over it right away */
624                         BLI_strncpy(path, tmp+2, FILE_MAX);
625                         
626                         memcpy(tmp, base, baselen);
627                         strcpy(tmp+baselen, path);
628                         strcpy(path, tmp);
629                 } else {
630                         strcpy(path, tmp+2);
631                 }
632         } else {
633                 strcpy(path, tmp);
634         }
635         
636         if (path[0]!='\0') {
637                 if ( path[strlen(path)-1]=='/') {
638                         BLI_cleanup_dir(NULL, path);
639                 } else {
640                         BLI_cleanup_file(NULL, path);
641                 }
642         }
643         
644 #ifdef WIN32
645         /* skip first two chars, which in case of
646            absolute path will be drive:/blabla and
647            in case of relpath //blabla/. So relpath
648            // will be retained, rest will be nice and
649            shiny win32 backward slashes :) -jesterKing
650         */
651         BLI_char_switch(path+2, '/', '\\');
652 #endif
653         
654         return wasrelative;
655 }
656
657
658 /*
659  * Should only be done with command line paths.
660  * this is NOT somthing blenders internal paths support like the // prefix
661  */
662 int BLI_path_cwd(char *path)
663 {
664         int wasrelative = 1;
665         int filelen = strlen(path);
666         
667 #ifdef WIN32
668         if (filelen >= 3 && path[1] == ':' && (path[2] == '\\' || path[2] == '/'))
669                 wasrelative = 0;
670 #else
671         if (filelen >= 2 && path[0] == '/')
672                 wasrelative = 0;
673 #endif
674         
675         if (wasrelative==1) {
676                 char cwd[FILE_MAXDIR + FILE_MAXFILE];
677                 BLI_getwdN(cwd); /* incase the full path to the blend isnt used */
678                 
679                 if (cwd[0] == '\0') {
680                         printf( "Could not get the current working directory - $PWD for an unknown reason.");
681                 } else {
682                         /* uses the blend path relative to cwd important for loading relative linked files.
683                         *
684                         * cwd should contain c:\ etc on win32 so the relbase can be NULL
685                         * relbase being NULL also prevents // being misunderstood as relative to the current
686                         * blend file which isnt a feature we want to use in this case since were dealing
687                         * with a path from the command line, rather then from inside Blender */
688                         
689                         char origpath[FILE_MAXDIR + FILE_MAXFILE];
690                         BLI_strncpy(origpath, path, FILE_MAXDIR + FILE_MAXFILE);
691                         
692                         BLI_make_file_string(NULL, path, cwd, origpath); 
693                 }
694         }
695         
696         return wasrelative;
697 }
698
699
700 /* 'di's filename component is moved into 'fi', di is made a dir path */
701 void BLI_splitdirstring(char *di, char *fi)
702 {
703         char *lslash= BLI_last_slash(di);
704
705         if (lslash) {
706                 BLI_strncpy(fi, lslash+1, FILE_MAXFILE);
707                 *(lslash+1)=0;
708         } else {
709                 BLI_strncpy(fi, di, FILE_MAXFILE);
710                 di[0]= 0;
711         }
712 }
713
714 void BLI_getlastdir(const char* dir, char *last, int maxlen)
715 {
716         const char *s = dir;
717         const char *lslash = NULL;
718         const char *prevslash = NULL;
719         while (*s) {
720                 if ((*s == '\\') || (*s == '/')) {
721                         prevslash = lslash;
722                         lslash = s;
723                 }
724                 s++;
725         }
726         if (prevslash) {
727                 BLI_strncpy(last, prevslash+1, maxlen);
728         } else {
729                 BLI_strncpy(last, dir, maxlen);
730         }
731 }
732
733 char *BLI_gethome(void) {
734         #if !defined(WIN32)
735                 return getenv("HOME");
736
737         #else /* Windows */
738                 char * ret;
739                 static char dir[512];
740                 static char appdatapath[MAXPATHLEN];
741                 HRESULT hResult;
742
743                 /* Check for %HOME% env var */
744
745                 ret = getenv("HOME");
746                 if(ret) {
747                         sprintf(dir, "%s\\.blender", ret);
748                         if (BLI_exists(dir)) return dir;
749                 }
750
751                 /* else, check install dir (path containing blender.exe) */
752
753                 BLI_getInstallationDir(dir);
754
755                 if (BLI_exists(dir))
756                 {
757                         strcat(dir,"\\.blender");
758                         if (BLI_exists(dir)) return(dir);
759                 }
760
761                                 
762                 /* add user profile support for WIN 2K / NT */
763                 hResult = SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatapath);
764                 
765                 if (hResult == S_OK)
766                 {
767                         if (BLI_exists(appdatapath)) { /* from fop, also below... */
768                                 sprintf(dir, "%s\\Blender Foundation\\Blender", appdatapath);
769                                 BLI_recurdir_fileops(dir);
770                                 if (BLI_exists(dir)) {
771                                         strcat(dir,"\\.blender");
772                                         if(BLI_exists(dir)) return(dir);
773                                 }
774                         }
775                         hResult = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatapath);
776                         if (hResult == S_OK)
777                         {
778                                 if (BLI_exists(appdatapath)) 
779                                 { /* from fop, also below... */
780                                         sprintf(dir, "%s\\Blender Foundation\\Blender", appdatapath);
781                                         BLI_recurdir_fileops(dir);
782                                         if (BLI_exists(dir)) {
783                                                 strcat(dir,"\\.blender");
784                                                 if(BLI_exists(dir)) return(dir);
785                                         }
786                                 }
787                         }
788                 }
789                 
790                 return "C:\\Temp";      /* sheesh! bad, bad, bad! (aphex) */
791         #endif
792 }
793
794 /* this function returns the path to a blender folder, if it exists
795  * utility functions for BLI_gethome_folder */
796
797 /* #define PATH_DEBUG */ /* for testing paths that are checked */
798
799 static int test_data_path(char *targetpath, char *path_base, char *path_sep, char *folder_name)
800 {
801         char tmppath[FILE_MAXDIR];
802         
803         if(path_sep)    BLI_join_dirfile(tmppath, path_base, path_sep);
804         else                    BLI_strncpy(tmppath, path_base, sizeof(tmppath));
805         
806         BLI_make_file_string("/", targetpath, tmppath, folder_name);
807         
808         if (BLI_exists(targetpath)) {
809 #ifdef PATH_DEBUG
810                 printf("\tpath found: %s\n", targetpath);
811 #endif
812                 return 1;
813         }
814         else {
815 #ifdef PATH_DEBUG
816                 printf("\tpath missing: %s\n", targetpath);
817 #endif
818                 targetpath[0] = '\0';
819                 return 0;
820         }
821 }
822
823 static int gethome_path_local(char *targetpath, char *folder_name)
824 {
825         extern char bprogname[]; /* argv[0] from creator.c */
826         char bprogdir[FILE_MAXDIR];
827         char cwd[FILE_MAXDIR];
828         char *s;
829         int i;
830         
831 #ifdef PATH_DEBUG
832         printf("gethome_path_local...\n");
833 #endif
834         
835         /* try release/folder_name (binary relative) */
836         /* use argv[0] (bprogname) to get the path to the executable */
837         s = BLI_last_slash(bprogname);
838         i = s - bprogname + 1;
839         BLI_strncpy(bprogdir, bprogname, i);
840
841         /* try release/folder_name (BIN relative) */
842         if(test_data_path(targetpath, bprogdir, "release", folder_name))
843                 return 1;
844
845         /* try release/folder_name (CWD relative) */
846         if(test_data_path(targetpath, BLI_getwdN(cwd), "release", folder_name))
847                 return 1;
848
849         /* try ./.blender/folder_name */
850         if(test_data_path(targetpath, bprogdir, ".blender", folder_name))
851                 return 1;
852         
853         return 0;
854 }
855
856 static int gethome_path_user(char *targetpath, char *folder_name)
857 {
858         char *home_path= BLI_gethome();
859
860 #ifdef PATH_DEBUG
861         printf("gethome_path_user...\n");
862 #endif
863         
864         /* try $HOME/folder_name */
865         return test_data_path(targetpath, home_path, ".blender", folder_name);
866 }
867
868 static int gethome_path_system(char *targetpath, char *folder_name)
869 {
870         extern char blender_path[]; /* unix prefix eg. /usr/share/blender/2.5 creator.c */
871         
872         if(!blender_path[0])
873                 return 0;
874         
875 #ifdef PATH_DEBUG
876         printf("gethome_path_system...\n");
877 #endif
878         
879         /* try $BLENDERPATH/folder_name */
880         return test_data_path(targetpath, blender_path, NULL, folder_name);
881 }
882
883 char *BLI_gethome_folder(char *folder_name, int flag)
884 {
885         static char fulldir[FILE_MAXDIR] = "";
886         
887         /* first check if this is a redistributable bundle */
888         if(flag & BLI_GETHOME_LOCAL) {
889                 if (gethome_path_local(fulldir, folder_name))
890                         return fulldir;
891         }
892
893         /* then check if the OS has blender data files installed in a global location */
894         if(flag & BLI_GETHOME_SYSTEM) {
895                 if (gethome_path_system(fulldir, folder_name))
896                         return fulldir;
897         }
898         
899         /* now check the users home dir for data files */
900         if(flag & BLI_GETHOME_USER) {
901                 if (gethome_path_user(fulldir, folder_name))
902                         return fulldir;
903         }
904         
905         return NULL;
906 }
907
908 #ifdef PATH_DEBUG
909 #undef PATH_DEBUG
910 #endif
911
912 void BLI_setenv(const char *env, const char*val)
913 {
914         /* SGI or free windows */
915 #if (defined(__sgi) || ((defined(WIN32) || defined(WIN64)) && defined(FREE_WINDOWS)))
916         char *envstr= MEM_mallocN(sizeof(char) * (strlen(env) + strlen(val) + 2), "envstr"); /* one for = another for \0 */
917
918         sprintf(envstr, "%s=%s", env, val);
919         putenv(envstr);
920         MEM_freeN(envstr);
921
922         /* non-free windows */
923 #elif (defined(WIN32) || defined(WIN64)) /* not free windows */
924         _putenv_s(env, val);
925 #else
926         /* linux/osx/bsd */
927         setenv(env, val, 1);
928 #endif
929 }
930
931
932 /**
933  Only set an env var if already not there.
934  Like Unix setenv(env, val, 0);
935  */
936 void BLI_setenv_if_new(const char *env, const char* val)
937 {
938         if(getenv(env) == NULL)
939                 BLI_setenv(env, val);
940 }
941
942
943 void BLI_clean(char *path)
944 {
945         if(path==0) return;
946 #ifdef WIN32
947         if(path && strlen(path)>2) {
948                 BLI_char_switch(path+2, '/', '\\');
949         }
950 #else
951         BLI_char_switch(path, '\\', '/');
952 #endif
953 }
954
955 void BLI_char_switch(char *string, char from, char to) 
956 {
957         if(string==0) return;
958         while (*string != 0) {
959                 if (*string == from) *string = to;
960                 string++;
961         }
962 }
963
964 void BLI_make_exist(char *dir) {
965         int a;
966
967         #ifdef WIN32
968                 BLI_char_switch(dir, '/', '\\');
969         #else
970                 BLI_char_switch(dir, '\\', '/');
971         #endif  
972         
973         a = strlen(dir);
974         
975 #ifdef WIN32    
976         while(BLI_exists(dir) == 0){
977                 a --;
978                 while(dir[a] != '\\'){
979                         a--;
980                         if (a <= 0) break;
981                 }
982                 if (a >= 0) dir[a+1] = 0;
983                 else {
984                         /* defaulting to drive (usually 'C:') of Windows installation */
985                         get_default_root(dir);
986                         break;
987                 }
988         }
989 #else
990         while(BLI_exist(dir) == 0){
991                 a --;
992                 while(dir[a] != '/'){
993                         a--;
994                         if (a <= 0) break;
995                 }
996                 if (a >= 0) dir[a+1] = 0;
997                 else {
998                         strcpy(dir,"/");
999                         break;
1000                 }
1001         }
1002 #endif
1003 }
1004
1005 void BLI_make_existing_file(char *name)
1006 {
1007         char di[FILE_MAXDIR+FILE_MAXFILE], fi[FILE_MAXFILE];
1008
1009         strcpy(di, name);
1010         BLI_splitdirstring(di, fi);
1011         
1012         /* test exist */
1013         if (BLI_exists(di) == 0) {
1014                 BLI_recurdir_fileops(di);
1015         }
1016 }
1017
1018
1019 void BLI_make_file_string(const char *relabase, char *string,  const char *dir, const char *file)
1020 {
1021         int sl;
1022
1023         if (!string || !dir || !file) return; /* We don't want any NULLs */
1024         
1025         string[0]= 0; /* ton */
1026
1027         /* we first push all slashes into unix mode, just to make sure we don't get
1028            any mess with slashes later on. -jesterKing */
1029         /* constant strings can be passed for those parameters - don't change them - elubie */
1030         /*
1031         BLI_char_switch(relabase, '\\', '/');
1032         BLI_char_switch(dir, '\\', '/');
1033         BLI_char_switch(file, '\\', '/');
1034         */
1035
1036         /* Resolve relative references */       
1037         if (relabase && dir[0] == '/' && dir[1] == '/') {
1038                 char *lslash;
1039                 
1040                 /* Get the file name, chop everything past the last slash (ie. the filename) */
1041                 strcpy(string, relabase);
1042                 
1043                 lslash= (strrchr(string, '/')>strrchr(string, '\\'))?strrchr(string, '/'):strrchr(string, '\\');
1044                 
1045                 if(lslash) *(lslash+1)= 0;
1046
1047                 dir+=2; /* Skip over the relative reference */
1048         }
1049 #ifdef WIN32
1050         else {
1051                 if (strlen(dir) >= 2 && dir[1] == ':' ) {
1052                         BLI_strncpy(string, dir, 3);
1053                         dir += 2;
1054                 }
1055                 else { /* no drive specified */
1056                         /* first option: get the drive from the relabase if it has one */
1057                         if (relabase && strlen(relabase) >= 2 && relabase[1] == ':' ) {
1058                                 BLI_strncpy(string, relabase, 3);       
1059                                 string[2] = '\\';
1060                                 string[3] = '\0';
1061                         }
1062                         else { /* we're out of luck here, guessing the first valid drive, usually c:\ */
1063                                 get_default_root(string);
1064                         }
1065                         
1066                         /* ignore leading slashes */
1067                         while (*dir == '/' || *dir == '\\') dir++;
1068                 }
1069         }
1070 #endif
1071
1072         strcat(string, dir);
1073
1074         /* Make sure string ends in one (and only one) slash */ 
1075         /* first trim all slashes from the end of the string */
1076         sl = strlen(string);
1077         while (sl>0 && ( string[sl-1] == '/' || string[sl-1] == '\\') ) {
1078                 string[sl-1] = '\0';
1079                 sl--;
1080         }
1081         /* since we've now removed all slashes, put back one slash at the end. */
1082         strcat(string, "/");
1083         
1084         while (*file && (*file == '/' || *file == '\\')) /* Trim slashes from the front of file */
1085                 file++;
1086                 
1087         strcat (string, file);
1088         
1089         /* Push all slashes to the system preferred direction */
1090         BLI_clean(string);
1091 }
1092
1093 int BLI_testextensie(const char *str, const char *ext)
1094 {
1095         short a, b;
1096         int retval;
1097
1098         a= strlen(str);
1099         b= strlen(ext);
1100
1101         if(a==0 || b==0 || b>=a) {
1102                 retval = 0;
1103         } else if (BLI_strcasecmp(ext, str + a - b)) {
1104                 retval = 0;     
1105         } else {
1106                 retval = 1;
1107         }
1108
1109         return (retval);
1110 }
1111
1112 int BLI_replace_extension(char *path, int maxlen, const char *ext)
1113 {
1114         int a;
1115
1116         for(a=strlen(path)-1; a>=0; a--)
1117                 if(path[a] == '.' || path[a] == '/' || path[a] == '\\')
1118                         break;
1119         
1120         if(path[a] != '.')
1121                 a= strlen(path);
1122
1123         if(a + strlen(ext) >= maxlen)
1124                 return 0;
1125
1126         strcpy(path+a, ext);
1127         return 1;
1128 }
1129
1130 /* Converts "/foo/bar.txt" to "/foo/" and "bar.txt"
1131  * - wont change 'string'
1132  * - wont create any directories
1133  * - dosnt use CWD, or deal with relative paths.
1134  * - Only fill's in *dir and *file when they are non NULL
1135  * */
1136 void BLI_split_dirfile(const char *string, char *dir, char *file)
1137 {
1138         char *lslash_str = BLI_last_slash(string);
1139         int lslash= lslash_str ? (int)(lslash_str - string) + 1 : 0;
1140
1141         if (dir) {
1142                 if (lslash) {
1143                         BLI_strncpy( dir, string, lslash + 1); /* +1 to include the slash and the last char */
1144                 } else {
1145                         dir[0] = '\0';
1146                 }
1147         }
1148         
1149         if (file) {
1150                 strcpy( file, string+lslash);
1151         }
1152 }
1153
1154 /* simple appending of filename to dir, does not check for valid path! */
1155 void BLI_join_dirfile(char *string, const char *dir, const char *file)
1156 {
1157         int sl_dir;
1158         
1159         if(string != dir) /* compare pointers */
1160                 BLI_strncpy(string, dir, FILE_MAX);
1161         
1162         sl_dir= BLI_add_slash(string);
1163         
1164         if (sl_dir <FILE_MAX) {
1165                 BLI_strncpy(string + sl_dir, file, FILE_MAX-sl_dir);
1166         }
1167 }
1168
1169 /* like pythons os.path.basename( ) */
1170 char *BLI_path_basename(char *path)
1171 {
1172         char *filename= BLI_last_slash(path);
1173         return filename ? filename + 1 : path;
1174 }
1175
1176 /*
1177   Produce image export path.
1178
1179   Fails returning 0 if image filename is empty or if destination path
1180   matches image path (i.e. both are the same file).
1181
1182   Trailing slash in dest_dir is optional.
1183
1184   Logic:
1185
1186   - if an image is "below" current .blend file directory, rebuild the
1187         same dir structure in dest_dir
1188
1189   For example //textures/foo/bar.png becomes
1190   [dest_dir]/textures/foo/bar.png.
1191
1192   - if an image is not "below" current .blend file directory,
1193   disregard it's path and copy it in the same directory where 3D file
1194   goes.
1195
1196   For example //../foo/bar.png becomes [dest_dir]/bar.png.
1197
1198   This logic will help ensure that all image paths are relative and
1199   that a user gets his images in one place. It'll also provide
1200   consistent behaviour across exporters.
1201  */
1202 int BKE_rebase_path(char *abs, int abs_size, char *rel, int rel_size, const char *base_dir, const char *src_dir, const char *dest_dir)
1203 {
1204         char path[FILE_MAX];
1205         char dir[FILE_MAX];
1206         char base[FILE_MAX];
1207         char blend_dir[FILE_MAX];       /* directory, where current .blend file resides */
1208         char dest_path[FILE_MAX];
1209         char rel_dir[FILE_MAX];
1210         int len;
1211
1212         if (abs)
1213                 abs[0]= 0;
1214
1215         if (rel)
1216                 rel[0]= 0;
1217
1218         BLI_split_dirfile(base_dir, blend_dir, NULL);
1219
1220         if (src_dir[0]=='\0')
1221                 return 0;
1222
1223         BLI_strncpy(path, src_dir, sizeof(path));
1224
1225         /* expand "//" in filename and get absolute path */
1226         BLI_path_abs(path, base_dir);
1227
1228         /* get the directory part */
1229         BLI_split_dirfile(path, dir, base);
1230
1231         len= strlen(blend_dir);
1232
1233         rel_dir[0] = 0;
1234
1235         /* if image is "below" current .blend file directory */
1236         if (!strncmp(path, blend_dir, len)) {
1237
1238                 /* if image is _in_ current .blend file directory */
1239                 if (!strcmp(dir, blend_dir)) {
1240                         BLI_join_dirfile(dest_path, dest_dir, base);
1241                 }
1242                 /* "below" */
1243                 else {
1244                         /* rel = image_path_dir - blend_dir */
1245                         BLI_strncpy(rel_dir, dir + len, sizeof(rel_dir));
1246
1247                         BLI_join_dirfile(dest_path, dest_dir, rel_dir);
1248                         BLI_join_dirfile(dest_path, dest_path, base);
1249                 }
1250
1251         }
1252         /* image is out of current directory */
1253         else {
1254                 BLI_join_dirfile(dest_path, dest_dir, base);
1255         }
1256
1257         if (abs)
1258                 BLI_strncpy(abs, dest_path, abs_size);
1259
1260         if (rel) {
1261                 strncat(rel, rel_dir, rel_size);
1262                 strncat(rel, base, rel_size);
1263         }
1264
1265         /* return 2 if src=dest */
1266         if (!strcmp(path, dest_path)) {
1267                 // if (G.f & G_DEBUG) printf("%s and %s are the same file\n", path, dest_path);
1268                 return 2;
1269         }
1270
1271         return 1;
1272 }
1273
1274
1275 static int add_win32_extension(char *name)
1276 {
1277         int retval = 0;
1278         int type;
1279
1280         type = BLI_exist(name);
1281         if ((type == 0) || S_ISDIR(type)) {
1282 #ifdef _WIN32
1283                 char filename[FILE_MAXDIR+FILE_MAXFILE];
1284                 char ext[FILE_MAXDIR+FILE_MAXFILE];
1285                 char *extensions = getenv("PATHEXT");
1286                 if (extensions) {
1287                         char *temp;
1288                         do {
1289                                 strcpy(filename, name);
1290                                 temp = strstr(extensions, ";");
1291                                 if (temp) {
1292                                         strncpy(ext, extensions, temp - extensions);
1293                                         ext[temp - extensions] = 0;
1294                                         extensions = temp + 1;
1295                                         strcat(filename, ext);
1296                                 } else {
1297                                         strcat(filename, extensions);
1298                                 }
1299
1300                                 type = BLI_exist(filename);
1301                                 if (type && (! S_ISDIR(type))) {
1302                                         retval = 1;
1303                                         strcpy(name, filename);
1304                                         break;
1305                                 }
1306                         } while (temp);
1307                 }
1308 #endif
1309         } else {
1310                 retval = 1;
1311         }
1312
1313         return (retval);
1314 }
1315
1316 void BLI_where_am_i(char *fullname, const char *name)
1317 {
1318         char filename[FILE_MAXDIR+FILE_MAXFILE];
1319         char *path = NULL, *temp;
1320         
1321 #ifdef _WIN32
1322         char *separator = ";";
1323         char slash = '\\';
1324 #else
1325         char *separator = ":";
1326         char slash = '/';
1327 #endif
1328
1329         
1330 #ifdef __linux__
1331         /* linux uses binreloc since argv[0] is not relyable, call br_init( NULL ) first */
1332         path = br_find_exe( NULL );
1333         if (path) {
1334                 BLI_strncpy(fullname, path, FILE_MAXDIR+FILE_MAXFILE);
1335                 free(path);
1336                 return;
1337         }
1338 #endif
1339
1340 #ifdef _WIN32
1341         if(GetModuleFileName(0, fullname, FILE_MAXDIR+FILE_MAXFILE)) {
1342                 GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
1343                 return;
1344         }
1345 #endif
1346
1347         /* unix and non linux */
1348         if (name && fullname && strlen(name)) {
1349                 strcpy(fullname, name);
1350                 if (name[0] == '.') {
1351                         // relative path, prepend cwd
1352                         BLI_getwdN(fullname);
1353                         
1354                         // not needed but avoids annoying /./ in name
1355                         if(name && name[0]=='.' && name[1]==slash)
1356                                 BLI_join_dirfile(fullname, fullname, name+2);
1357                         else
1358                                 BLI_join_dirfile(fullname, fullname, name);
1359                         
1360                         add_win32_extension(fullname);
1361                 } else if (BLI_last_slash(name)) {
1362                         // full path
1363                         strcpy(fullname, name);
1364                         add_win32_extension(fullname);
1365                 } else {
1366                         // search for binary in $PATH
1367                         path = getenv("PATH");
1368                         if (path) {
1369                                 do {
1370                                         temp = strstr(path, separator);
1371                                         if (temp) {
1372                                                 strncpy(filename, path, temp - path);
1373                                                 filename[temp - path] = 0;
1374                                                 path = temp + 1;
1375                                         } else {
1376                                                 strncpy(filename, path, sizeof(filename));
1377                                         }
1378                                         BLI_join_dirfile(fullname, fullname, name);
1379                                         if (add_win32_extension(filename)) {
1380                                                 strcpy(fullname, filename);
1381                                                 break;
1382                                         }
1383                                 } while (temp);
1384                         }
1385                 }
1386 #ifndef NDEBUG
1387                 if (strcmp(name, fullname)) {
1388                         printf("guessing '%s' == '%s'\n", name, fullname);
1389                 }
1390 #endif
1391
1392 #ifdef _WIN32
1393                 // in windows change long filename to short filename because
1394                 // win2k doesn't know how to parse a commandline with lots of
1395                 // spaces and double-quotes. There's another solution to this
1396                 // with spawnv(P_WAIT, bprogname, argv) instead of system() but
1397                 // that's even uglier
1398                 GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
1399 #ifndef NDEBUG
1400                 printf("Shortname = '%s'\n", fullname);
1401 #endif
1402 #endif
1403         }
1404 }
1405
1406 void BLI_where_is_temp(char *fullname, int usertemp)
1407 {
1408         fullname[0] = '\0';
1409         
1410         if (usertemp && BLI_exists(U.tempdir)) {
1411                 strcpy(fullname, U.tempdir);
1412         }
1413         
1414         
1415 #ifdef WIN32
1416         if (fullname[0] == '\0') {
1417                 char *tmp = getenv("TEMP"); /* Windows */
1418                 if (tmp && BLI_exists(tmp)) {
1419                         strcpy(fullname, tmp);
1420                 }
1421         }
1422 #else
1423         /* Other OS's - Try TMP and TMPDIR */
1424         if (fullname[0] == '\0') {
1425                 char *tmp = getenv("TMP");
1426                 if (tmp && BLI_exists(tmp)) {
1427                         strcpy(fullname, tmp);
1428                 }
1429         }
1430         
1431         if (fullname[0] == '\0') {
1432                 char *tmp = getenv("TMPDIR");
1433                 if (tmp && BLI_exists(tmp)) {
1434                         strcpy(fullname, tmp);
1435                 }
1436         }
1437 #endif  
1438         
1439         if (fullname[0] == '\0') {
1440                 strcpy(fullname, "/tmp/");
1441         } else {
1442                 /* add a trailing slash if needed */
1443                 BLI_add_slash(fullname);
1444         }
1445 }
1446
1447 char *get_install_dir(void) {
1448         extern char bprogname[];
1449         char *tmpname = BLI_strdup(bprogname);
1450         char *cut;
1451
1452 #ifdef __APPLE__
1453         cut = strstr(tmpname, ".app");
1454         if (cut) cut[0] = 0;
1455 #endif
1456
1457         cut = BLI_last_slash(tmpname);
1458
1459         if (cut) {
1460                 cut[0] = 0;
1461                 return tmpname;
1462         } else {
1463                 MEM_freeN(tmpname);
1464                 return NULL;
1465         }
1466 }
1467
1468 /* 
1469  * returns absolute path to the app bundle
1470  * only useful on OS X 
1471  */
1472 #ifdef __APPLE__
1473 char* BLI_getbundle(void) {
1474         CFURLRef bundleURL;
1475         CFStringRef pathStr;
1476         static char path[MAXPATHLEN];
1477         CFBundleRef mainBundle = CFBundleGetMainBundle();
1478
1479         bundleURL = CFBundleCopyBundleURL(mainBundle);
1480         pathStr = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
1481         CFStringGetCString(pathStr, path, MAXPATHLEN, kCFStringEncodingASCII);
1482         CFRelease(pathStr);
1483         CFRelease(bundleURL);
1484         return path;
1485 }
1486 #endif
1487
1488 #ifdef WITH_ICONV
1489
1490 void BLI_string_to_utf8(char *original, char *utf_8, const char *code)
1491 {
1492         size_t inbytesleft=strlen(original);
1493         size_t outbytesleft=512;
1494         size_t rv=0;
1495         iconv_t cd;
1496         
1497         if (NULL == code) {
1498                 code = locale_charset();
1499         }
1500         cd=iconv_open("UTF-8", code);
1501
1502         if (cd == (iconv_t)(-1)) {
1503                 printf("iconv_open Error");
1504                 *utf_8='\0';
1505                 return ;
1506         }
1507         rv=iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft);
1508         if (rv == (size_t) -1) {
1509                 printf("iconv Error\n");
1510                 return ;
1511         }
1512         *utf_8 = '\0';
1513         iconv_close(cd);
1514 }
1515 #endif // WITH_ICONV
1516
1517