- got tired of str[n]casecmp not declared warnings
[blender.git] / source / blender / blenlib / intern / util.c
1 /* util.c
2  *
3  * various string, file, list operations.
4  *
5  *
6  * $Id$
7  *
8  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version. The Blender
14  * Foundation also sells licenses for use in proprietary software under
15  * the Blender License.  See http://www.blender.org/BL/ for information
16  * about this.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  *
27  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
28  * All rights reserved.
29  *
30  * The Original Code is: all of this file.
31  *
32  * Contributor(s): none yet.
33  *
34  * ***** END GPL/BL DUAL LICENSE BLOCK *****
35  * 
36  */
37
38 #include <stdio.h>
39 #include <fcntl.h>
40 #include <ctype.h>
41 #include <string.h>
42 #include <stdlib.h>
43
44 #include "MEM_guardedalloc.h"
45
46 #include "BLI_blenlib.h"
47 #include "DNA_listBase.h"
48 #include "BLI_storage.h"
49 #include "BLI_storage_types.h"
50
51 #include "BLI_util.h"
52
53 #ifdef HAVE_CONFIG_H
54 #include <config.h>
55 #endif
56
57 #ifndef WIN32 
58 #include <unistd.h>
59 #else
60 #include <io.h>
61 #endif
62
63 #ifdef WIN32
64 #include "BLI_winstuff.h"
65 #endif
66
67
68 #ifndef WIN32
69 #include <sys/time.h>
70 #endif
71
72 #ifdef __APPLE__
73 #include <sys/param.h>
74 #include <CoreFoundation/CoreFoundation.h>
75 #endif
76
77 /* local */
78
79 static int add_win32_extension(char *name);
80
81 /* implementation */
82
83 /* Ripped this from blender.c
84  */
85 void addlisttolist(ListBase *list1, ListBase *list2)
86 {
87
88         if(list2->first==0) return;
89
90         if(list1->first==0) {
91                 list1->first= list2->first;
92                 list1->last= list2->last;
93         }
94         else {
95                 ((struct Link *)list1->last)->next= list2->first;
96                 ((struct Link *)list2->first)->prev= list1->last;
97                 list1->last= list2->last;
98         }
99         list2->first= list2->last= 0;
100 }
101
102 int BLI_stringdec(char *string, char *kop, char *staart, unsigned short *numlen)
103 {
104         unsigned short len, len2, nums = 0, nume = 0;
105         short i, found = 0;
106
107         len2 = len =  strlen( string);
108         
109         if (len > 6) {
110                 if (BLI_strncasecmp(string + len - 6, ".blend", 6) == 0) len -= 6;
111                 else if (BLI_strncasecmp(string + len - 6, ".trace", 6) == 0) len -= 6;
112         }
113         
114         if (len == len2) {
115                 if (len > 4) {
116                         /* handle .jf0 en .jf1 for jstreams */
117                         if (BLI_strncasecmp(string + len - 4, ".jf", 3) == 0) len -= 4;
118                         else if (BLI_strncasecmp(string + len - 4, ".tga", 4) == 0) len -= 4;
119                         else if (BLI_strncasecmp(string + len - 4, ".jpg", 4) == 0) len -= 4;
120                         else if (BLI_strncasecmp(string + len - 4, ".png", 4) == 0) len -= 4;
121                         else if (BLI_strncasecmp(string + len - 4, ".txt", 4) == 0) len -= 4;
122                         else if (BLI_strncasecmp(string + len - 4, ".cyc", 4) == 0) len -= 4;
123                         else if (BLI_strncasecmp(string + len - 4, ".enh", 4) == 0) len -= 4;
124                         else if (BLI_strncasecmp(string + len - 4, ".rgb", 4) == 0) len -= 4;
125                         else if (BLI_strncasecmp(string + len - 4, ".psx", 4) == 0) len -= 4;
126                         else if (BLI_strncasecmp(string + len - 4, ".ble", 4) == 0) len -= 4;
127                 }
128         }
129         
130         for (i = len - 1; i >= 0; i--){
131                 if (string[i] == '/') break;
132                 if (isdigit(string[i])) {
133                         if (found){
134                                 nums = i;
135                         }
136                         else{
137                                 nume = i;
138                                 nums = i;
139                                 found = 1;
140                         }
141                 }
142                 else{
143                         if (found) break;
144                 }
145         }
146         if (found){
147                 if (staart) strcpy(staart,&string[nume+1]);
148                 if (kop) {
149                         strcpy(kop,string);
150                         kop[nums]=0;
151                 }
152                 if (numlen) *numlen = nume-nums+1;
153                 return ((int)atoi(&(string[nums])));
154         }
155         if (staart) strcpy(staart, string + len);
156         if (kop) {
157                 strncpy(kop, string, len);
158                 kop[len] = 0;
159         }
160         if (numlen) *numlen=0;
161         return 0;
162 }
163
164
165 void BLI_stringenc(char *string, char *kop, char *staart, unsigned short numlen, int pic)
166 {
167         char numstr[10]="";
168         unsigned short len,i;
169
170         strcpy(string,kop);
171         
172         if (pic>0 || numlen==4) {
173                 len= sprintf(numstr,"%d",pic);
174
175                 for(i=len;i<numlen;i++){
176                         strcat(string,"0");
177                 }
178                 strcat(string,numstr);
179         }
180         strcat(string,staart);
181 }
182
183
184 void BLI_newname(char * name, int add)
185 {
186         char head[128], tail[128];
187         int pic;
188         unsigned short digits;
189         
190         pic = BLI_stringdec(name, head, tail, &digits);
191         
192         /* are we going from 100 -> 99 or from 10 -> 9 */
193         if (add < 0 && digits < 4 && digits > 0) {
194                 int i, exp;
195                 exp = 1;
196                 for (i = digits; i > 1; i--) exp *= 10;
197                 if (pic >= exp && (pic + add) < exp) digits--;
198         }
199         
200         pic += add;
201         
202         if(digits==4 && pic<0) pic= 0;
203         BLI_stringenc(name, head, tail, digits, pic);
204 }
205
206
207 void BLI_addhead(ListBase *listbase, void *vlink)
208 {
209         struct Link *link= vlink;
210
211         if (link == 0) return;
212         if (listbase == 0) return;
213
214         link->next = listbase->first;
215         link->prev = 0;
216
217         if (listbase->first) ((struct Link *)listbase->first)->prev = link;
218         if (listbase->last == 0) listbase->last = link;
219         listbase->first = link;
220 }
221
222
223 void BLI_addtail(ListBase *listbase, void *vlink)
224 {
225         struct Link *link= vlink;
226
227         if (link == 0) return;
228         if (listbase == 0) return;
229
230         link->next = 0;
231         link->prev = listbase->last;
232
233         if (listbase->last) ((struct Link *)listbase->last)->next = link;
234         if (listbase->first == 0) listbase->first = link;
235         listbase->last = link;
236 }
237
238
239 void BLI_remlink(ListBase *listbase, void *vlink)
240 {
241         struct Link *link= vlink;
242
243         if (link == 0) return;
244         if (listbase == 0) return;
245
246         if (link->next) link->next->prev = link->prev;
247         if (link->prev) link->prev->next = link->next;
248
249         if (listbase->last == link) listbase->last = link->prev;
250         if (listbase->first == link) listbase->first = link->next;
251 }
252
253
254 void BLI_freelinkN(ListBase *listbase, void *vlink)
255 {
256         struct Link *link= vlink;
257
258         if (link == 0) return;
259         if (listbase == 0) return;
260
261         BLI_remlink(listbase,link);
262         MEM_freeN(link);
263 }
264
265
266 void BLI_insertlink(ListBase *listbase, void *vprevlink, void *vnewlink)
267 {
268         struct Link *prevlink= vprevlink, *newlink= vnewlink;
269
270         /* newlink comes after prevlink */
271
272         if (newlink == 0) return;
273         if (listbase == 0) return;
274
275         if(listbase->first==0) { /* empty list */
276                 listbase->first= newlink;
277                 listbase->last= newlink;
278                 return;
279         }
280         if (prevlink== 0) {     /* insert before first element */
281                 newlink->next= listbase->first;
282                 newlink->prev= 0;
283                 newlink->next->prev= newlink;
284                 listbase->first= newlink;
285                 return;
286         }
287
288         if (listbase->last== prevlink) /* at end of list */
289                 listbase->last = newlink;
290
291         newlink->next= prevlink->next;
292         prevlink->next= newlink;
293         if(newlink->next) newlink->next->prev= newlink;
294         newlink->prev= prevlink;
295 }
296
297 void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
298 {
299         struct Link *nextlink= vnextlink, *newlink= vnewlink;
300
301         /* newlink before nextlink */
302
303         if (newlink == 0) return;
304         if (listbase == 0) return;
305
306         if(listbase->first==0) { /* empty list */
307                 listbase->first= newlink;
308                 listbase->last= newlink;
309                 return;
310         }
311         if (nextlink== 0) {     /* insert at end of list */
312                 newlink->prev= listbase->last;
313                 newlink->next= 0;
314                 ((struct Link *)listbase->last)->next= newlink;
315                 listbase->last= newlink;
316                 return;
317         }
318
319         if (listbase->first== nextlink) /* at beginning of list */
320                 listbase->first = newlink;
321
322         newlink->next= nextlink;
323         newlink->prev= nextlink->prev;
324         nextlink->prev= newlink;
325         if(newlink->prev) newlink->prev->next= newlink;
326 }
327
328
329 void BLI_freelist(ListBase *listbase)
330 {
331         struct Link *link,*next;
332
333         if (listbase == 0) return;
334         link= listbase->first;
335         while(link) {
336                 next= link->next;
337                 free(link);
338                 link= next;
339         }
340         listbase->first=0;
341         listbase->last=0;
342 }
343
344 void BLI_freelistN(ListBase *listbase)
345 {
346         struct Link *link,*next;
347
348         if (listbase == 0) return;
349         link= listbase->first;
350         while(link) {
351                 next= link->next;
352                 MEM_freeN(link);
353                 link= next;
354         }
355         listbase->first=0;
356         listbase->last=0;
357 }
358
359
360 int BLI_countlist(ListBase *listbase)
361 {
362         Link * link;
363         int count = 0;
364         
365         if (listbase){
366                 link = listbase->first;
367                 while(link) {
368                         count++;
369                         link= link->next;
370                 }
371         }
372         return(count);
373 }
374
375 void * BLI_findlink(ListBase *listbase, int number)
376 {
377         Link * link = NULL;
378
379         if (number >= 0) {
380                 link = listbase->first;
381                 while (link != NULL && number != 0) {
382                         number--;
383                         link = link->next;
384                 }
385         }
386
387         return (link);
388 }
389
390
391 char *BLI_strdupn(char *str, int len) {
392         char *n= MEM_mallocN(len+1, "strdup");
393         memcpy(n, str, len);
394         n[len]= '\0';
395         
396         return n;
397 }
398 char *BLI_strdup(char *str) {
399         return BLI_strdupn(str, strlen(str));
400 }
401
402 char *BLI_strncpy(char *dst, char *src, int maxncpy) {
403         int srclen= strlen(src);
404         int cpylen= (srclen>(maxncpy-1))?(maxncpy-1):srclen;
405         
406         memcpy(dst, src, cpylen);
407         dst[cpylen]= '\0';
408         
409         return dst;
410 }
411
412 int BLI_streq(char *a, char *b) {
413         return (strcmp(a, b)==0);
414 }
415 int BLI_strcaseeq(char *a, char *b) {
416         return (BLI_strcasecmp(a, b)==0);
417 }
418
419 void BLI_makestringcode(char *fromfile, char *str)
420 {
421         char *slash, len, temp[512];
422
423         strcpy(temp, fromfile);
424
425         /* Find the last slash */
426         slash = (strrchr(temp, '/')>strrchr(temp, '\\'))
427             ? strrchr(temp, '/') : strrchr(temp, '\\');
428         if(slash) {
429                 *(slash+1)= 0;
430                 len= strlen(temp);
431                 if(len) {
432                         if(strncmp(str, temp, len)==0) {
433                                 temp[0]= '/';
434                                 temp[1]= '/';
435                                 strcpy(temp+2, str+len);
436                                 strcpy(str, temp);
437                         }
438                 }
439         }
440 }
441
442 int BLI_convertstringcode(char *path, char *basepath, int framenum)
443 {
444         int len, wasrelative= (strncmp(path, "//", 2)==0);
445
446         if (path[0] == '/' && path[1] == '/') {
447                 char *filepart= BLI_strdup(path+2); /* skip code */
448                 char *lslash= BLI_last_slash(basepath);
449
450                 if (lslash) {
451                         int baselen= (int) (lslash-basepath) + 1;
452
453                         memcpy(path, basepath, baselen);
454                         strcpy(path+baselen, filepart);
455                 } else {
456                         strcpy(path, filepart);
457                 }
458                 
459                 MEM_freeN(filepart);
460         }
461
462         len= strlen(path);
463         if(len && path[len-1]=='#') {
464                 sprintf(path+len-1, "%04d", framenum);
465         }
466
467         return wasrelative;
468 }
469
470 void BLI_splitdirstring(char *di,char *fi)
471 {
472         char *lslash= BLI_last_slash(di);
473
474         if (lslash) {
475                 strcpy(fi, lslash+1);
476                 *(lslash+1)=0;
477         } else {
478                 strcpy(fi, di);
479                 di[0]= 0;
480         }
481 }
482
483 char *BLI_gethome(void) {
484         #ifdef __BeOS
485                 return "/boot/home/";           /* BeOS 4.5: doubleclick at icon doesnt give home env */
486
487         #elif !defined(WIN32)
488                 return getenv("HOME");
489
490         #else /* Windows */
491                 char * ret;
492                 static char dir[512];
493
494                 /* Check for %HOME% env var */
495
496                 ret = getenv("HOME");
497                 if(ret) {
498                         sprintf(dir, "%s\\.blender", ret);
499                         if (BLI_exists(dir)) return dir;
500                 }
501
502                 /* else, check install dir (path containing blender.exe) */
503
504                 BLI_getInstallationDir(dir);
505
506                 if (BLI_exists(dir))
507                 {
508                         strcat(dir,"\\.blender");
509                         if (BLI_exists(dir)) return(dir);
510                 }
511
512                                 
513                 /* add user profile support for WIN 2K / NT */
514                 ret = getenv("USERPROFILE");
515                 if (ret) {
516                         if (BLI_exists(ret)) { /* from fop, also below... */
517                                 sprintf(dir, "%s\\Application Data\\Blender Foundation\\Blender", ret);
518                                 BLI_recurdir_fileops(dir);
519                                 if (BLI_exists(dir)) {
520                                         strcat(dir,"\\.blender");
521                                         if(BLI_exists(dir)) return(dir);
522                                 }
523                         }
524                 }
525
526                 /* 
527                    Saving in the Windows dir is less than desirable. 
528                    Use as a last resort ONLY! (aphex)
529                 */
530                 
531                 ret = getenv("WINDOWS");                
532                 if (ret) {
533                         if(BLI_exists(ret)) return ret;
534                 }
535
536                 ret = getenv("WINDIR"); 
537                 if (ret) {
538                         if(BLI_exists(ret)) return ret;
539                 }
540                 
541                 return "C:\\Temp";      /* sheesh! bad, bad, bad! (aphex) */
542         #endif
543 }
544
545 static void char_switch(char *string, char from, char to) 
546 {
547         while (*string != 0) {
548                 if (*string == from) *string = to;
549                 string++;
550         }
551 }
552
553 void BLI_make_exist(char *dir)
554 {
555         int a;
556
557         #ifdef WIN32
558                 char_switch(dir, '/', '\\');
559         #else
560                 char_switch(dir, '\\', '/');
561         #endif  
562         
563         a = strlen(dir);
564         
565 #ifdef WIN32    
566         while(BLI_exists(dir) == 0){
567                 a --;
568                 while(dir[a] != '\\'){
569                         a--;
570                         if (a <= 0) break;
571                 }
572                 if (a >= 0) dir[a+1] = 0;
573                 else {
574                         strcpy(dir,"\\");
575                         break;
576                 }
577         }
578 #else
579         while(BLI_exist(dir) == 0){
580                 a --;
581                 while(dir[a] != '/'){
582                         a--;
583                         if (a <= 0) break;
584                 }
585                 if (a >= 0) dir[a+1] = 0;
586                 else {
587                         strcpy(dir,"/");
588                         break;
589                 }
590         }
591 #endif
592 }
593
594 void BLI_make_file_string(char *relabase, char *string,  char *dir,  char *file)
595 {
596
597         if (!string || !dir || !file) return; /* We don't want any NULLs */
598         
599         string[0]= 0; /* ton */
600
601         /* Resolve relative references */       
602         if (relabase && dir[0] == '/' && dir[1] == '/') {
603                 char *lslash;
604                 
605                 /* Get the file name, chop everything past the last slash (ie. the filename) */
606                 strcpy(string, relabase);
607                 
608                 lslash= (strrchr(string, '/')>strrchr(string, '\\'))?strrchr(string, '/'):strrchr(string, '\\');
609                 
610                 if(lslash) *(lslash+1)= 0;
611
612                 dir+=2; /* Skip over the relative reference */
613         }
614         
615         strcat(string, dir);
616
617         /* Make sure string ends in one (and only one) slash */
618         if (string[strlen(string)-1] != '/' && string[strlen(string)-1] != '\\')
619                 strcat(string, "/");
620         
621         while (*file && (*file == '/' || *file == '\\')) /* Trim slashes from the front of file */
622                 file++;
623                 
624         strcat (string, file);
625         
626         /* Push all slashes to the system preferred direction */
627         #ifdef WIN32
628                 char_switch(string, '/', '\\');
629         #else
630                 char_switch(string, '\\', '/');
631         #endif  
632 }
633
634 int BLI_testextensie(char *str, char *ext)
635 {
636         short a, b;
637         int retval;
638
639         a= strlen(str);
640         b= strlen(ext);
641
642         if(a==0 || b==0 || b>=a) {
643                 retval = 0;
644         } else if (BLI_strcasecmp(ext, str + a - b)) {
645                 retval = 0;     
646         } else {
647                 retval = 1;
648         }
649
650         return (retval);
651 }
652
653 // copies from BKE_utildefines
654 #ifndef FILE_MAXDIR
655 #define FILE_MAXDIR  160
656 #endif
657
658 #ifndef FILE_MAXFILE
659 #define FILE_MAXFILE 80
660 #endif
661
662 void BLI_split_dirfile(char *string, char *dir, char *file)
663 {
664         int a;
665         int len;
666         
667         dir[0]= 0;
668         file[0]= 0;
669
670 #ifdef WIN32
671         char_switch(string, '/', '\\'); /* make sure we have a valid path format */
672
673         if (strlen(string)) {
674                 if (string[0] == '/' || string[0] == '\\') { 
675                         BLI_strncpy(dir, string, FILE_MAXDIR);
676                 } else if (string[1] == ':' && string[2] == '\\') {
677             BLI_strncpy(dir, string, FILE_MAXDIR);
678         } else {
679             BLI_getwdN(dir);
680             strcat(dir,"/");
681             strcat(dir,string);
682             BLI_strncpy(string,dir,FILE_MAXDIR+FILE_MAXFILE);
683         }
684
685         BLI_make_exist(dir);
686
687         // BLI_exist doesn't recognize a slashed dirname as a dir
688         //  check if a trailing slash exists, and remove it. Do not do this
689         //  when we are already at root. -jesterKing
690         a = strlen(dir);
691         if(a>=4 && dir[a-1]=='\\') dir[a-1] = 0;
692
693         if (S_ISDIR(BLI_exist(dir))) {
694
695             /* copy from end of string into file, to ensure filename itself isn't truncated 
696                if string is too long. (aphex) */
697
698             len = FILE_MAXFILE - strlen(string);
699
700             if (len < 0)
701                 BLI_strncpy(file,string + abs(len),FILE_MAXFILE);
702             else
703                 BLI_strncpy(file,string,FILE_MAXFILE);
704             
705             if (strrchr(string,'\\')){
706                 BLI_strncpy(file,strrchr(string,'\\')+1,FILE_MAXFILE);
707             }
708
709             if (a = strlen(dir)) {
710                 if (dir[a-1] != '\\') strcat(dir,"\\");
711             }
712                 }
713                 else {
714                         a = strlen(dir) - 1;
715                         while(a>0 && dir[a] != '\\') a--;
716                         dir[a + 1] = 0;
717                         BLI_strncpy(file, string + strlen(dir),FILE_MAXFILE);
718                 }
719                 
720         }
721         else {
722                 strcpy(dir, "\\");
723                 file[0]=0;
724         }
725 #else
726         if (strlen(string)) {
727                 if (string[0] == '/') { 
728                         strcpy(dir, string);
729                 } else if (string[1] == ':' && string[2] == '\\') {
730                         string+=2;
731                         strcpy(dir, string);
732                 } else {
733                         BLI_getwdN(dir);
734                         strcat(dir,"/");
735                         strcat(dir,string);
736                         strcpy(string,dir);
737                 }
738
739                 BLI_make_exist(dir);
740                         
741                 if (S_ISDIR(BLI_exist(dir))) {
742                         strcpy(file,string + strlen(dir));
743
744                         if (strrchr(file,'/')) strcpy(file,strrchr(file,'/')+1);
745                 
746                         if ( (a = strlen(dir)) ) {
747                                 if (dir[a-1] != '/') strcat(dir,"/");
748                         }
749                 }
750                 else {
751                         a = strlen(dir) - 1;
752                         while(dir[a] != '/') a--;
753                         dir[a + 1] = 0;
754                         strcpy(file, string + strlen(dir));
755                 }
756         }
757         else {
758                 BLI_getwdN(dir);
759                 strcat(dir, "/");
760                 file[0] = 0;
761         }
762 #endif
763 }
764  
765 static int add_win32_extension(char *name)
766 {
767         int retval = 0;
768         int type;
769
770         type = BLI_exist(name);
771         if ((type == 0) || S_ISDIR(type)) {
772 #ifdef _WIN32
773                 char filename[FILE_MAXDIR+FILE_MAXFILE];
774                 char ext[FILE_MAXDIR+FILE_MAXFILE];
775                 char *extensions = getenv("PATHEXT");
776                 if (extensions) {
777                         char *temp;
778                         do {
779                                 strcpy(filename, name);
780                                 temp = strstr(extensions, ";");
781                                 if (temp) {
782                                         strncpy(ext, extensions, temp - extensions);
783                                         ext[temp - extensions] = 0;
784                                         extensions = temp + 1;
785                                         strcat(filename, ext);
786                                 } else {
787                                         strcat(filename, extensions);
788                                 }
789
790                                 type = BLI_exist(filename);
791                                 if (type && (! S_ISDIR(type))) {
792                                         retval = 1;
793                                         strcpy(name, filename);
794                                         break;
795                                 }
796                         } while (temp);
797                 }
798 #endif
799         } else {
800                 retval = 1;
801         }
802
803         return (retval);
804 }
805
806 void BLI_where_am_i(char *fullname, char *name)
807 {
808         char filename[FILE_MAXDIR+FILE_MAXFILE];
809         char *path, *temp;
810         int len;
811 #ifdef _WIN32
812         char *seperator = ";";
813         char *slash = "\\";
814 #else
815         char *seperator = ":";
816         char *slash = "/";
817 #endif
818
819         if (name && fullname && strlen(name)) {
820                 strcpy(fullname, name);
821                 if (name[0] == '.') {
822                         // relative path, prepend cwd
823                         BLI_getwdN(fullname);
824                         len = strlen(fullname);
825                         if (len && fullname[len -1] != slash[0]) {
826                                 strcat(fullname, slash);
827                         }
828                         strcat(fullname, name);
829                         add_win32_extension(fullname);
830                 } else if (BLI_last_slash(name)) {
831                         // full path
832                         strcpy(fullname, name);
833                         add_win32_extension(fullname);
834                 } else {
835                         // search for binary in $PATH
836                         path = getenv("PATH");
837                         if (path) {
838                                 do {
839                                         temp = strstr(path, seperator);
840                                         if (temp) {
841                                                 strncpy(filename, path, temp - path);
842                                                 filename[temp - path] = 0;
843                                                 path = temp + 1;
844                                         } else {
845                                                 strncpy(filename, path, sizeof(filename));
846                                         }
847                                         len = strlen(filename);
848                                         if (len && filename[len - 1] != slash[0]) {
849                                                 strcat(filename, slash);
850                                         }
851                                         strcat(filename, name);
852                                         if (add_win32_extension(filename)) {
853                                                 strcpy(fullname, filename);
854                                                 break;
855                                         }
856                                 } while (temp);
857                         }
858                 }
859 #ifndef NDEBUG
860                 if (strcmp(name, fullname)) {
861                         printf("guessing '%s' == '%s'\n", name, fullname);
862                 }
863 #endif
864
865 #ifdef _WIN32
866                 // in windows change long filename to short filename because
867                 // win2k doesn't know how to parse a commandline with lots of
868                 // spaces and double-quotes. There's another solution to this
869                 // with spawnv(P_WAIT, bprogname, argv) instead of system() but
870                 // that's even uglier
871                 GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
872 #ifndef NDEBUG
873                 printf("Shortname = '%s'\n", fullname);
874 #endif
875 #endif
876         }
877 }
878
879 /* 
880  * returns absolute path to the app bundle
881  * only useful on OS X 
882  */
883 #ifdef __APPLE__
884 char* BLI_getbundle(void) {
885         CFURLRef bundleURL;
886         CFStringRef pathStr;
887         static char path[MAXPATHLEN];
888         CFBundleRef mainBundle = CFBundleGetMainBundle();
889
890         bundleURL = CFBundleCopyBundleURL(mainBundle);
891         pathStr = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
892         CFStringGetCString(pathStr, path, MAXPATHLEN, kCFStringEncodingASCII);
893         return path;
894 }
895 #endif
896
897 int BLI_strcasecmp(const char *s1, const char *s2) {
898         int i;
899
900         for (i=0; ; i++) {
901                 char c1 = tolower(s1[i]);
902                 char c2 = tolower(s2[i]);
903
904                 if (c1<c2) {
905                         return -1;
906                 } else if (c1>c2) {
907                         return 1;
908                 } else if (c1==0) {
909                         break;
910                 }
911         }
912
913         return 0;
914 }
915
916 int BLI_strncasecmp(const char *s1, const char *s2, int n) {
917         int i;
918
919         for (i=0; i<n; i++) {
920                 char c1 = tolower(s1[i]);
921                 char c2 = tolower(s2[i]);
922
923                 if (c1<c2) {
924                         return -1;
925                 } else if (c1>c2) {
926                         return 1;
927                 } else if (c1==0) {
928                         break;
929                 }
930         }
931
932         return 0;
933 }