d1b2efa28c72bf2954fff85dc038e72d08672b0f
[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 #include <stdarg.h>
44
45 #include "MEM_guardedalloc.h"
46
47 #include "BLI_blenlib.h"
48 #include "DNA_listBase.h"
49 #include "BLI_storage.h"
50 #include "BLI_storage_types.h"
51 #include "BLI_dynamiclist.h"
52
53 #include "BLI_util.h"
54 #include "BKE_utildefines.h"
55
56
57 #ifdef HAVE_CONFIG_H
58 #include <config.h>
59 #endif
60
61 #ifndef WIN32 
62 #include <unistd.h>
63 #else
64 #include <io.h>
65 #endif
66
67 #ifdef WIN32
68 #include "BLI_winstuff.h"
69
70 /* for duplicate_defgroup */
71 #if !(defined vsnprintf)
72 #define vsnprintf _vsnprintf
73 #endif
74
75 #endif
76
77
78 #ifndef WIN32
79 #include <sys/time.h>
80 #endif
81
82 #ifdef __APPLE__
83 #include <sys/param.h>
84 #include <CoreFoundation/CoreFoundation.h>
85 #endif
86
87 /* local */
88
89 static int add_win32_extension(char *name);
90
91 /* implementation */
92
93 /* Ripped this from blender.c */
94 void addlisttolist(ListBase *list1, ListBase *list2)
95 {
96         if (list2->first==0) return;
97
98         if (list1->first==0) {
99                 list1->first= list2->first;
100                 list1->last= list2->last;
101         }
102         else {
103                 ((Link *)list1->last)->next= list2->first;
104                 ((Link *)list2->first)->prev= list1->last;
105                 list1->last= list2->last;
106         }
107         list2->first= list2->last= 0;
108 }
109
110 int BLI_stringdec(char *string, char *kop, char *start, unsigned short *numlen)
111 {
112         unsigned short len, len2, nums = 0, nume = 0;
113         short i, found = 0;
114
115         len2 = len = strlen(string);
116         
117         if (len > 6) {
118                 if (BLI_strncasecmp(string + len - 6, ".blend", 6) == 0) len -= 6;
119                 else if (BLI_strncasecmp(string + len - 6, ".trace", 6) == 0) len -= 6;
120         }
121         
122         if (len > 9) {
123                 if (BLI_strncasecmp(string + len - 9, ".blend.gz", 9) == 0) len -= 9;
124         }
125                 
126         if (len == len2) {
127                 if (len > 4) {
128                         /* handle .jf0 en .jf1 for jstreams */
129                         if (BLI_strncasecmp(string + len - 4, ".jf", 3) == 0) len -= 4;
130                         else if (BLI_strncasecmp(string + len - 4, ".tga", 4) == 0) len -= 4;
131                         else if (BLI_strncasecmp(string + len - 4, ".jpg", 4) == 0) len -= 4;
132                         else if (BLI_strncasecmp(string + len - 4, ".png", 4) == 0) len -= 4;
133                         else if (BLI_strncasecmp(string + len - 4, ".txt", 4) == 0) len -= 4;
134                         else if (BLI_strncasecmp(string + len - 4, ".cyc", 4) == 0) len -= 4;
135                         else if (BLI_strncasecmp(string + len - 4, ".enh", 4) == 0) len -= 4;
136                         else if (BLI_strncasecmp(string + len - 4, ".rgb", 4) == 0) len -= 4;
137                         else if (BLI_strncasecmp(string + len - 4, ".psx", 4) == 0) len -= 4;
138                         else if (BLI_strncasecmp(string + len - 4, ".ble", 4) == 0) len -= 4;
139                         else if (BLI_strncasecmp(string + len - 4, ".exr", 4) == 0) len -= 4;
140                 }
141         }
142         
143         for (i = len - 1; i >= 0; i--) {
144                 if (string[i] == '/') break;
145                 if (isdigit(string[i])) {
146                         if (found){
147                                 nums = i;
148                         }
149                         else{
150                                 nume = i;
151                                 nums = i;
152                                 found = 1;
153                         }
154                 }
155                 else {
156                         if (found) break;
157                 }
158         }
159         if (found){
160                 if (start) strcpy(start,&string[nume+1]);
161                 if (kop) {
162                         strcpy(kop,string);
163                         kop[nums]=0;
164                 }
165                 if (numlen) *numlen = nume-nums+1;
166                 return ((int)atoi(&(string[nums])));
167         }
168         if (start) strcpy(start, string + len);
169         if (kop) {
170                 strncpy(kop, string, len);
171                 kop[len] = 0;
172         }
173         if (numlen) *numlen=0;
174         return 0;
175 }
176
177
178 void BLI_stringenc(char *string, char *kop, char *start, unsigned short numlen, int pic)
179 {
180         char numstr[10]="";
181         unsigned short len,i;
182
183         strcpy(string,kop);
184         
185         if (pic>0 || numlen==4) {
186                 len= sprintf(numstr,"%d",pic);
187                 
188                 for(i=len;i<numlen;i++){
189                         strcat(string,"0");
190                 }
191                 strcat(string,numstr);
192         }
193         strcat(string, start);
194 }
195
196
197 void BLI_newname(char *name, int add)
198 {
199         char head[128], tail[128];
200         int pic;
201         unsigned short digits;
202         
203         pic = BLI_stringdec(name, head, tail, &digits);
204         
205         /* are we going from 100 -> 99 or from 10 -> 9 */
206         if (add < 0 && digits < 4 && digits > 0) {
207                 int i, exp;
208                 exp = 1;
209                 for (i = digits; i > 1; i--) exp *= 10;
210                 if (pic >= exp && (pic + add) < exp) digits--;
211         }
212         
213         pic += add;
214         
215         if (digits==4 && pic<0) pic= 0;
216         BLI_stringenc(name, head, tail, digits, pic);
217 }
218
219
220 void BLI_addhead(ListBase *listbase, void *vlink)
221 {
222         Link *link= vlink;
223
224         if (link == NULL) return;
225         if (listbase == NULL) return;
226
227         link->next = listbase->first;
228         link->prev = NULL;
229
230         if (listbase->first) ((Link *)listbase->first)->prev = link;
231         if (listbase->last == NULL) listbase->last = link;
232         listbase->first = link;
233 }
234
235
236 void BLI_addtail(ListBase *listbase, void *vlink)
237 {
238         Link *link= vlink;
239
240         if (link == NULL) return;
241         if (listbase == NULL) return;
242
243         link->next = NULL;
244         link->prev = listbase->last;
245
246         if (listbase->last) ((Link *)listbase->last)->next = link;
247         if (listbase->first == 0) listbase->first = link;
248         listbase->last = link;
249 }
250
251
252 void BLI_remlink(ListBase *listbase, void *vlink)
253 {
254         Link *link= vlink;
255
256         if (link == NULL) return;
257         if (listbase == NULL) return;
258
259         if (link->next) link->next->prev = link->prev;
260         if (link->prev) link->prev->next = link->next;
261
262         if (listbase->last == link) listbase->last = link->prev;
263         if (listbase->first == link) listbase->first = link->next;
264 }
265
266
267 void BLI_freelinkN(ListBase *listbase, void *vlink)
268 {
269         Link *link= vlink;
270
271         if (link == NULL) return;
272         if (listbase == NULL) return;
273
274         BLI_remlink(listbase,link);
275         MEM_freeN(link);
276 }
277
278
279 void BLI_insertlink(ListBase *listbase, void *vprevlink, void *vnewlink)
280 {
281         Link *prevlink= vprevlink;
282         Link *newlink= vnewlink;
283
284         /* newlink comes after prevlink */
285         if (newlink == NULL) return;
286         if (listbase == NULL) return;
287         
288         /* empty list */
289         if (listbase->first == NULL) { 
290                 
291                 listbase->first= newlink;
292                 listbase->last= newlink;
293                 return;
294         }
295         
296         /* insert before first element */
297         if (prevlink == NULL) { 
298                 newlink->next= listbase->first;
299                 newlink->prev= 0;
300                 newlink->next->prev= newlink;
301                 listbase->first= newlink;
302                 return;
303         }
304
305         /* at end of list */
306         if (listbase->last== prevlink) 
307                 listbase->last = newlink;
308
309         newlink->next= prevlink->next;
310         prevlink->next= newlink;
311         if (newlink->next) newlink->next->prev= newlink;
312         newlink->prev= prevlink;
313 }
314
315 /* This uses insertion sort, so NOT ok for large list */
316 void BLI_sortlist(ListBase *listbase, int (*cmp)(void *, void *))
317 {
318         Link *current = NULL;
319         Link *previous = NULL;
320         Link *next = NULL;
321         
322         if (cmp == NULL) return;
323         if (listbase == NULL) return;
324
325         if (listbase->first != listbase->last)
326         {
327                 for( previous = listbase->first, current = previous->next; current; current = next )
328                 {
329                         next = current->next;
330                         previous = current->prev;
331                         
332                         BLI_remlink(listbase, current);
333                         
334                         while(previous && cmp(previous, current) == 1)
335                         {
336                                 previous = previous->prev;
337                         }
338                         
339                         BLI_insertlinkafter(listbase, previous, current);
340                 }
341         }
342 }
343
344 void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink)
345 {
346         Link *prevlink= vprevlink;
347         Link *newlink= vnewlink;
348
349         /* newlink before nextlink */
350         if (newlink == NULL) return;
351         if (listbase == NULL) return;
352
353         /* empty list */
354         if (listbase->first == NULL) { 
355                 listbase->first= newlink;
356                 listbase->last= newlink;
357                 return;
358         }
359         
360         /* insert at head of list */
361         if (prevlink == NULL) { 
362                 newlink->prev = NULL;
363                 newlink->next = listbase->first;
364                 ((Link *)listbase->first)->prev = newlink;
365                 listbase->first = newlink;
366                 return;
367         }
368
369         /* at end of list */
370         if (listbase->last == prevlink) 
371                 listbase->last = newlink;
372
373         newlink->next = prevlink->next;
374         newlink->prev = prevlink;
375         prevlink->next = newlink;
376         if (newlink->next) newlink->next->prev = newlink;
377 }
378
379 void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
380 {
381         Link *nextlink= vnextlink;
382         Link *newlink= vnewlink;
383
384         /* newlink before nextlink */
385         if (newlink == NULL) return;
386         if (listbase == NULL) return;
387
388         /* empty list */
389         if (listbase->first == NULL) { 
390                 listbase->first= newlink;
391                 listbase->last= newlink;
392                 return;
393         }
394         
395         /* insert at end of list */
396         if (nextlink == NULL) { 
397                 newlink->prev= listbase->last;
398                 newlink->next= 0;
399                 ((Link *)listbase->last)->next= newlink;
400                 listbase->last= newlink;
401                 return;
402         }
403
404         /* at beginning of list */
405         if (listbase->first== nextlink) 
406                 listbase->first = newlink;
407
408         newlink->next= nextlink;
409         newlink->prev= nextlink->prev;
410         nextlink->prev= newlink;
411         if (newlink->prev) newlink->prev->next= newlink;
412 }
413
414
415 void BLI_freelist(ListBase *listbase)
416 {
417         Link *link, *next;
418
419         if (listbase == NULL) 
420                 return;
421         
422         link= listbase->first;
423         while (link) {
424                 next= link->next;
425                 free(link);
426                 link= next;
427         }
428         
429         listbase->first= NULL;
430         listbase->last= NULL;
431 }
432
433 void BLI_freelistN(ListBase *listbase)
434 {
435         Link *link, *next;
436
437         if (listbase == NULL) return;
438         
439         link= listbase->first;
440         while (link) {
441                 next= link->next;
442                 MEM_freeN(link);
443                 link= next;
444         }
445         
446         listbase->first= NULL;
447         listbase->last= NULL;
448 }
449
450
451 int BLI_countlist(ListBase *listbase)
452 {
453         Link *link;
454         int count = 0;
455         
456         if (listbase) {
457                 link = listbase->first;
458                 while (link) {
459                         count++;
460                         link= link->next;
461                 }
462         }
463         return count;
464 }
465
466 void *BLI_findlink(ListBase *listbase, int number)
467 {
468         Link *link = NULL;
469
470         if (number >= 0) {
471                 link = listbase->first;
472                 while (link != NULL && number != 0) {
473                         number--;
474                         link = link->next;
475                 }
476         }
477
478         return link;
479 }
480
481 int BLI_findindex(ListBase *listbase, void *vlink)
482 {
483         Link *link= NULL;
484         int number= 0;
485         
486         if (listbase == NULL) return -1;
487         if (vlink == NULL) return -1;
488         
489         link= listbase->first;
490         while (link) {
491                 if (link == vlink)
492                         return number;
493                 
494                 number++;
495                 link= link->next;
496         }
497         
498         return -1;
499 }
500
501 /*=====================================================================================*/
502 /* Methods for access array (realloc) */
503 /*=====================================================================================*/
504
505 /* remove item with index */
506 static void rem_array_item(struct DynamicArray *da, unsigned int index)
507 {
508         da->items[index]=NULL;
509         da->count--;
510         if(index==da->last_item_index){
511                 while((!da->items[da->last_item_index]) && (da->last_item_index>0)){
512                         da->last_item_index--;
513                 }
514         }
515 }
516
517 /* add array (if needed, then realloc) */
518 static void add_array_item(struct DynamicArray *da, void *item, unsigned int index)
519 {
520         /* realloc of access array */
521         if(da->max_item_index < index){
522                 unsigned int i, max = da->max_item_index;
523                 void **nitems;
524
525                 do {
526                         da->max_item_index += PAGE_SIZE;        /* OS can allocate only PAGE_SIZE Bytes */
527                 } while(da->max_item_index<=index);
528
529                 nitems = (void**)MEM_mallocN(sizeof(void*)*(da->max_item_index+1), "dlist access array");
530                 for(i=0;i<=max;i++)
531                         nitems[i] = da->items[i];
532
533                 /* set rest pointers to the NULL */
534                 for(i=max+1; i<=da->max_item_index; i++)
535                         nitems[i]=NULL;
536
537                 MEM_freeN(da->items);           /* free old access array */
538                 da->items = nitems;
539         }
540
541         da->items[index] = item;
542         da->count++;
543         if(index > da->last_item_index) da->last_item_index = index;
544 }
545
546 /* free access array */
547 static void destroy_array(DynamicArray *da)
548 {
549         da->count=0;
550         da->last_item_index=0;
551         da->max_item_index=0;
552         MEM_freeN(da->items);
553         da->items = NULL;
554 }
555
556 /* initialize dynamic array */
557 static void init_array(DynamicArray *da)
558 {
559         unsigned int i;
560
561         da->count=0;
562         da->last_item_index=0;
563         da->max_item_index = PAGE_SIZE-1;
564         da->items = (void*)MEM_mallocN(sizeof(void*)*(da->max_item_index+1), "dlist access array");
565         for(i=0; i<=da->max_item_index; i++) da->items[i]=NULL;
566 }
567
568 /* reinitialize dynamic array */
569 static void reinit_array(DynamicArray *da)
570 {
571         destroy_array(da);
572         init_array(da);
573 }
574
575 /*=====================================================================================*/
576 /* Methods for two way dynamic list with access array */
577 /*=====================================================================================*/
578
579 /* create new two way dynamic list with access array from two way dynamic list
580  * it doesn't copy any items to new array or something like this It is strongly
581  * recomended to use BLI_dlist_ methods for adding/removing items from dynamic list
582  * unless you can end with inconsistence system !!! */
583 DynamicList *BLI_dlist_from_listbase(ListBase *lb)
584 {
585         DynamicList *dlist;
586         Link *item;
587         int i=0, count;
588         
589         if(!lb) return NULL;
590         
591         count = BLI_countlist(lb);
592
593         dlist = MEM_mallocN(sizeof(DynamicList), "temp dynamic list");
594         /* ListBase stuff */
595         dlist->lb.first = lb->first;
596         dlist->lb.last = lb->last;
597         /* access array stuff */
598         dlist->da.count=count;
599         dlist->da.max_item_index = count-1;
600         dlist->da.last_item_index = count -1;
601         dlist->da.items = (void*)MEM_mallocN(sizeof(void*)*count, "temp dlist access array");
602
603         item = (Link*)lb->first;
604         while(item){
605                 dlist->da.items[i] = (void*)item;
606                 item = item->next;
607                 i++;
608         }
609
610         /* to prevent you of using original ListBase :-) */
611         lb->first = lb->last = NULL;
612
613         return dlist;
614 }
615
616 /* take out ListBase from DynamicList and destroy all temporary structures of DynamicList */
617 ListBase *BLI_listbase_from_dlist(DynamicList *dlist, ListBase *lb)
618 {
619         if(!dlist) return NULL;
620
621         if(!lb) lb = (ListBase*)MEM_mallocN(sizeof(ListBase), "ListBase");
622         
623         lb->first = dlist->lb.first;
624         lb->last = dlist->lb.last;
625
626         /* free all items of access array */
627         MEM_freeN(dlist->da.items);
628         /* free DynamicList*/
629         MEM_freeN(dlist);
630
631         return lb;
632 }
633
634 /* return pointer at item from th dynamic list with access array */
635 void *BLI_dlist_find_link(DynamicList *dlist, unsigned int index)
636 {
637         if(!dlist || !dlist->da.items) return NULL;
638
639         if((index <= dlist->da.last_item_index) && (index >= 0) && (dlist->da.count>0)){
640                 return dlist->da.items[index];
641         }
642         else {
643                 return NULL;
644         }
645 }
646
647 /* return count of items in the dynamic list with access array */
648 unsigned int BLI_count_items(DynamicList *dlist)
649 {
650         if(!dlist) return 0;
651
652         return dlist->da.count;
653 }
654
655 /* free item from the dynamic list with access array */
656 void BLI_dlist_free_item(DynamicList *dlist, unsigned int index)
657 {
658         if(!dlist || !dlist->da.items) return;
659         
660         if((index <= dlist->da.last_item_index) && (dlist->da.items[index])){
661                 BLI_freelinkN(&(dlist->lb), dlist->da.items[index]);
662                 rem_array_item(&(dlist->da), index);
663         }
664 }
665
666 /* remove item from the dynamic list with access array */
667 void BLI_dlist_rem_item(DynamicList *dlist, unsigned int index)
668 {
669         if(!dlist || !dlist->da.items) return;
670         
671         if((index <= dlist->da.last_item_index) && (dlist->da.items[index])){
672                 BLI_remlink(&(dlist->lb), dlist->da.items[index]);
673                 rem_array_item(&(dlist->da), index);
674         }
675 }
676
677 /* add item to the dynamic list with access array (index) */
678 void* BLI_dlist_add_item_index(DynamicList *dlist, void *item, unsigned int index)
679 {
680         if(!dlist || !dlist->da.items) return NULL;
681
682         if((index <= dlist->da.max_item_index) && (dlist->da.items[index])) {
683                 /* you can't place item at used index */
684                 return NULL;
685         }
686         else {
687                 add_array_item(&(dlist->da), item, index);
688                 BLI_addtail(&(dlist->lb), item);
689                 return item;
690         }
691 }
692
693 /* destroy dynamic list with access array */
694 void BLI_dlist_destroy(DynamicList *dlist)
695 {
696         if(!dlist) return;
697
698         BLI_freelistN(&(dlist->lb));
699         destroy_array(&(dlist->da));
700 }
701
702 /* initialize dynamic list with access array */
703 void BLI_dlist_init(DynamicList *dlist)
704 {
705         if(!dlist) return;
706
707         dlist->lb.first = NULL;
708         dlist->lb.last = NULL;
709
710         init_array(&(dlist->da));
711 }
712
713 /* reinitialize dynamic list with acces array */
714 void BLI_dlist_reinit(DynamicList *dlist)
715 {
716         if(!dlist) return;
717         
718         BLI_freelistN(&(dlist->lb));
719         reinit_array(&(dlist->da));
720 }
721
722 /*=====================================================================================*/
723
724 char *BLI_strdupn(const char *str, int len) {
725         char *n= MEM_mallocN(len+1, "strdup");
726         memcpy(n, str, len);
727         n[len]= '\0';
728         
729         return n;
730 }
731 char *BLI_strdup(const char *str) {
732         return BLI_strdupn(str, strlen(str));
733 }
734
735 char *BLI_strncpy(char *dst, const char *src, int maxncpy) {
736         int srclen= strlen(src);
737         int cpylen= (srclen>(maxncpy-1))?(maxncpy-1):srclen;
738         
739         memcpy(dst, src, cpylen);
740         dst[cpylen]= '\0';
741         
742         return dst;
743 }
744
745 int BLI_snprintf(char *buffer, size_t count, const char *format, ...)
746 {
747         int n;
748         va_list arg;
749
750         va_start(arg, format);
751         n = vsnprintf(buffer, count, format, arg);
752         
753         if (n != -1 && n < count) {
754                 buffer[n] = '\0';
755         } else {
756                 buffer[count-1] = '\0';
757         }
758         
759         va_end(arg);
760         return n;
761 }
762
763 int BLI_streq(char *a, char *b) {
764         return (strcmp(a, b)==0);
765 }
766 int BLI_strcaseeq(char *a, char *b) {
767         return (BLI_strcasecmp(a, b)==0);
768 }
769
770 /* ******************** string encoding ***************** */
771
772 /* This is quite an ugly function... its purpose is to
773  * take the dir name, make it absolute, and clean it up, replacing
774  * excess file entry stuff (like /tmp/../tmp/../)
775  * note that dir isn't protected for max string names... 
776  */
777
778 void BLI_cleanup_dir(const char *relabase, char *dir)
779 {
780         BLI_cleanup_file(relabase, dir);
781 #ifdef WIN32
782         strcat(dir, "\\");
783 #else
784         strcat(dir, "/");
785 #endif
786 }
787
788 void BLI_cleanup_file(const char *relabase, char *dir)
789 {
790         short a;
791         char *start, *eind;
792         
793         BLI_convertstringcode(dir, relabase, 0);
794         
795 #ifdef WIN32
796         if(dir[0]=='.') {       /* happens for example in FILE_MAIN */
797            get_default_root(dir);
798            return;
799         }       
800
801         while ( (start = strstr(dir, "\\..\\")) ) {
802                 eind = start + strlen("\\..\\") - 1;
803                 a = start-dir-1;
804                 while (a>0) {
805                         if (dir[a] == '\\') break;
806                         a--;
807                 }
808                 strcpy(dir+a,eind);
809         }
810
811         while ( (start = strstr(dir,"\\.\\")) ){
812                 eind = start + strlen("\\.\\") - 1;
813                 strcpy(start,eind);
814         }
815
816         while ( (start = strstr(dir,"\\\\" )) ){
817                 eind = start + strlen("\\\\") - 1;
818                 strcpy(start,eind);
819         }
820
821         if((a = strlen(dir))){                          /* remove the '\\' at the end */
822                 while(a>0 && dir[a-1] == '\\'){
823                         a--;
824                         dir[a] = 0;
825                 }
826         }
827 #else
828         if(dir[0]=='.') {       /* happens, for example in FILE_MAIN */
829            dir[0]= '/';
830            dir[1]= 0;
831            return;
832         }       
833
834         while ( (start = strstr(dir, "/../")) ) {
835                 eind = start + strlen("/../") - 1;
836                 a = start-dir-1;
837                 while (a>0) {
838                         if (dir[a] == '/') break;
839                         a--;
840                 }
841                 strcpy(dir+a,eind);
842         }
843
844         while ( (start = strstr(dir,"/./")) ){
845                 eind = start + strlen("/./") - 1;
846                 strcpy(start,eind);
847         }
848
849         while ( (start = strstr(dir,"//" )) ){
850                 eind = start + strlen("//") - 1;
851                 strcpy(start,eind);
852         }
853
854         if( (a = strlen(dir)) ){                                /* remove all '/' at the end */
855                 while(dir[a-1] == '/'){
856                         a--;
857                         dir[a] = 0;
858                         if (a<=0) break;
859                 }
860         }
861 #endif
862 }
863
864
865 void BLI_makestringcode(const char *relfile, char *file)
866 {
867         char * p;
868         char * q;
869         char * lslash;
870         char temp[FILE_MAXDIR+FILE_MAXFILE];
871         char res[FILE_MAXDIR+FILE_MAXFILE];
872
873         /* if file is already relative, bail out */
874         if(file[0]=='/' && file[1]=='/') return;
875         
876         /* also bail out if relative path is not set */
877         if (relfile[0] == 0) return;
878
879 #ifdef WIN32 
880         if (strlen(relfile) > 2 && relfile[1] != ':') {
881                 char* ptemp;
882                 /* fix missing volume name in relative base,
883                    can happen with old .Blog files */
884                 get_default_root(temp);
885                 ptemp = &temp[2];
886                 if (relfile[0] != '\\' && relfile[0] != '/') {
887                         ptemp++;
888                 }
889                 BLI_strncpy(ptemp, relfile, FILE_MAXDIR + FILE_MAXFILE-3);
890         } else {
891                 BLI_strncpy(temp, relfile, FILE_MAXDIR + FILE_MAXFILE);
892         }
893
894         if (strlen(file) > 2) {
895                 if ( temp[1] == ':' && file[1] == ':' && temp[0] != file[0] )
896                         return;
897         }
898 #else
899         BLI_strncpy(temp, relfile, FILE_MAX);
900 #endif
901
902         BLI_char_switch(temp, '\\', '/');
903         BLI_char_switch(file, '\\', '/');
904
905         /* the last slash in the file indicates where the path part ends */
906         lslash = BLI_last_slash(temp);
907
908         if (lslash) 
909         {       
910                 /* find the prefix of the filename that is equal for both filenames.
911                    This is replaced by the two slashes at the beginning */
912                 p = temp;
913                 q = file;
914                 while (*p == *q) {
915                         ++p; ++q;
916                 }
917                 /* we might have passed the slash when the beginning of a dir matches 
918                    so we rewind. Only check on the actual filename
919                 */
920                 if (*q != '/') {
921                         while ( (q >= file) && (*q != '/') ) { --q; --p; }
922                 } 
923                 else if (*p != '/') {
924                         while ( (p >= temp) && (*p != '/') ) { --p; --q; }
925                 }
926                 
927                 strcpy(res,     "//");
928
929                 /* p now points to the slash that is at the beginning of the part
930                    where the path is different from the relative path. 
931                    We count the number of directories we need to go up in the
932                    hierarchy to arrive at the common 'prefix' of the path
933                 */                      
934                 while (p && p < lslash) {
935                         if (*p == '/') 
936                                 strcat(res,     "../");
937                         ++p;
938                 }
939
940                 strcat(res, q+1); /* don't copy the slash at the beginning */
941                 
942 #ifdef  WIN32
943                 BLI_char_switch(res+2, '/', '\\');
944 #endif
945                 strcpy(file, res);
946         }
947 }
948
949 int BLI_convertstringcode(char *path, const char *basepath, int framenum)
950 {
951         int len, wasrelative;
952         char tmp[FILE_MAXDIR+FILE_MAXFILE];
953         char base[FILE_MAXDIR];
954         char vol[3] = {'\0', '\0', '\0'};
955
956         BLI_strncpy(vol, path, 3);
957         wasrelative= (strncmp(vol, "//", 2)==0);
958
959 #ifdef WIN32
960         /* we are checking here if we have an absolute path that is not in the current
961            blend file as a lib main - we are basically checking for the case that a 
962            UNIX root '/' is passed.
963         */
964         if (!wasrelative && (vol[1] != ':' && (vol[0] == '\0' || vol[0] == '/' || vol[0] == '\\'))) {
965                 char *p = path;
966                 get_default_root(tmp);
967                 // get rid of the slashes at the beginning of the path
968                 while (*p == '\\' || *p == '/') {
969                         p++;
970                 }
971                 strcat(tmp, p);
972         }
973         else {
974                 strcpy(tmp, path);
975         }
976 #else
977         strcpy(tmp, path);
978 #endif
979
980         strcpy(base, basepath);
981         
982         /* push slashes into unix mode - strings entering this part are
983            potentially messed up: having both back- and forward slashes.
984            Here we push into one conform direction, and at the end we
985            push them into the system specific dir. This ensures uniformity
986            of paths and solving some problems (and prevent potential future
987            ones) -jesterKing. */
988         BLI_char_switch(tmp, '\\', '/');
989         BLI_char_switch(base, '\\', '/');       
990
991         if (tmp[0] == '/' && tmp[1] == '/') {
992                 char *filepart= BLI_strdup(tmp+2); /* skip code */
993                 char *lslash= BLI_last_slash(base);
994
995                 if (lslash) {
996                         int baselen= (int) (lslash-base) + 1;
997
998                         memcpy(tmp, base, baselen);
999                         strcpy(tmp+baselen, filepart);
1000                 } else {
1001                         strcpy(tmp, filepart);
1002                 }
1003                 
1004                 MEM_freeN(filepart);
1005         }
1006
1007         len= strlen(tmp);
1008         if(len && tmp[len-1]=='#') {
1009                 sprintf(tmp+len-1, "%04d", framenum);
1010         }
1011
1012         strcpy(path, tmp);
1013 #ifdef WIN32
1014         /* skip first two chars, which in case of
1015            absolute path will be drive:/blabla and
1016            in case of relpath //blabla/. So relpath
1017            // will be retained, rest will be nice and
1018            shiny win32 backward slashes :) -jesterKing
1019         */
1020         BLI_char_switch(path+2, '/', '\\');
1021 #endif
1022
1023         return wasrelative;
1024 }
1025
1026 /* copy di to fi without directory only */
1027 void BLI_splitdirstring(char *di, char *fi)
1028 {
1029         char *lslash= BLI_last_slash(di);
1030
1031         if (lslash) {
1032                 BLI_strncpy(fi, lslash+1, FILE_MAXFILE);
1033                 *(lslash+1)=0;
1034         } else {
1035                 BLI_strncpy(fi, di, FILE_MAXFILE);
1036                 di[0]= 0;
1037         }
1038 }
1039
1040 char *BLI_gethome(void) {
1041         #ifdef __BeOS
1042                 return "/boot/home/";           /* BeOS 4.5: doubleclick at icon doesnt give home env */
1043
1044         #elif !defined(WIN32)
1045                 return getenv("HOME");
1046
1047         #else /* Windows */
1048                 char * ret;
1049                 static char dir[512];
1050
1051                 /* Check for %HOME% env var */
1052
1053                 ret = getenv("HOME");
1054                 if(ret) {
1055                         sprintf(dir, "%s\\.blender", ret);
1056                         if (BLI_exists(dir)) return dir;
1057                 }
1058
1059                 /* else, check install dir (path containing blender.exe) */
1060
1061                 BLI_getInstallationDir(dir);
1062
1063                 if (BLI_exists(dir))
1064                 {
1065                         strcat(dir,"\\.blender");
1066                         if (BLI_exists(dir)) return(dir);
1067                 }
1068
1069                                 
1070                 /* add user profile support for WIN 2K / NT */
1071                 ret = getenv("USERPROFILE");
1072                 if (ret) {
1073                         if (BLI_exists(ret)) { /* from fop, also below... */
1074                                 sprintf(dir, "%s\\Application Data\\Blender Foundation\\Blender", ret);
1075                                 BLI_recurdir_fileops(dir);
1076                                 if (BLI_exists(dir)) {
1077                                         strcat(dir,"\\.blender");
1078                                         if(BLI_exists(dir)) return(dir);
1079                                 }
1080                         }
1081                 }
1082
1083                 /* 
1084                    Saving in the Windows dir is less than desirable. 
1085                    Use as a last resort ONLY! (aphex)
1086                 */
1087                 
1088                 ret = getenv("WINDOWS");                
1089                 if (ret) {
1090                         if(BLI_exists(ret)) return ret;
1091                 }
1092
1093                 ret = getenv("WINDIR"); 
1094                 if (ret) {
1095                         if(BLI_exists(ret)) return ret;
1096                 }
1097                 
1098                 return "C:\\Temp";      /* sheesh! bad, bad, bad! (aphex) */
1099         #endif
1100 }
1101
1102 void BLI_clean(char *path)
1103 {
1104         if(path==0) return;
1105 #ifdef WIN32
1106         if(path && strlen(path)>2) {
1107                 BLI_char_switch(path+2, '/', '\\');
1108         }
1109 #else
1110         BLI_char_switch(path, '\\', '/');
1111 #endif
1112 }
1113
1114 void BLI_char_switch(char *string, char from, char to) 
1115 {
1116         if(string==0) return;
1117         while (*string != 0) {
1118                 if (*string == from) *string = to;
1119                 string++;
1120         }
1121 }
1122
1123 void BLI_make_exist(char *dir) {
1124         int a;
1125
1126         #ifdef WIN32
1127                 BLI_char_switch(dir, '/', '\\');
1128         #else
1129                 BLI_char_switch(dir, '\\', '/');
1130         #endif  
1131         
1132         a = strlen(dir);
1133         
1134 #ifdef WIN32    
1135         while(BLI_exists(dir) == 0){
1136                 a --;
1137                 while(dir[a] != '\\'){
1138                         a--;
1139                         if (a <= 0) break;
1140                 }
1141                 if (a >= 0) dir[a+1] = 0;
1142                 else {
1143                         /* defaulting to drive (usually 'C:') of Windows installation */
1144                         get_default_root(dir);
1145                         break;
1146                 }
1147         }
1148 #else
1149         while(BLI_exist(dir) == 0){
1150                 a --;
1151                 while(dir[a] != '/'){
1152                         a--;
1153                         if (a <= 0) break;
1154                 }
1155                 if (a >= 0) dir[a+1] = 0;
1156                 else {
1157                         strcpy(dir,"/");
1158                         break;
1159                 }
1160         }
1161 #endif
1162 }
1163
1164 void BLI_make_existing_file(char *name)
1165 {
1166         char di[FILE_MAXDIR], fi[FILE_MAXFILE];
1167         
1168         strcpy(di, name);
1169         BLI_splitdirstring(di, fi);
1170         
1171         /* test exist */
1172         if (BLI_exists(di) == 0) {
1173                 BLI_recurdir_fileops(di);
1174         }
1175 }
1176
1177
1178 void BLI_make_file_string(const char *relabase, char *string,  const char *dir, const char *file)
1179 {
1180         int sl;
1181
1182         if (!string || !dir || !file) return; /* We don't want any NULLs */
1183         
1184         string[0]= 0; /* ton */
1185
1186         /* we first push all slashes into unix mode, just to make sure we don't get
1187            any mess with slashes later on. -jesterKing */
1188         /* constant strings can be passed for those parameters - don't change them - elubie */
1189         /*
1190         BLI_char_switch(relabase, '\\', '/');
1191         BLI_char_switch(dir, '\\', '/');
1192         BLI_char_switch(file, '\\', '/');
1193         */
1194
1195         /* Resolve relative references */       
1196         if (relabase && dir[0] == '/' && dir[1] == '/') {
1197                 char *lslash;
1198                 
1199                 /* Get the file name, chop everything past the last slash (ie. the filename) */
1200                 strcpy(string, relabase);
1201                 
1202                 lslash= (strrchr(string, '/')>strrchr(string, '\\'))?strrchr(string, '/'):strrchr(string, '\\');
1203                 
1204                 if(lslash) *(lslash+1)= 0;
1205
1206                 dir+=2; /* Skip over the relative reference */
1207         }
1208 #ifdef WIN32
1209         else {
1210                 if (strlen(dir) >= 2 && dir[1] == ':' ) {
1211                         BLI_strncpy(string, dir, 3);
1212                         dir += 2;
1213                 }
1214                 else { /* no drive specified */
1215                         /* first option: get the drive from the relabase if it has one */
1216                         if (relabase && strlen(relabase) >= 2 && relabase[1] == ':' ) {
1217                                 BLI_strncpy(string, relabase, 3);       
1218                                 string[2] = '\\';
1219                                 string[3] = '\0';
1220                         }
1221                         else { /* we're out of luck here, guessing the first valid drive, usually c:\ */
1222                                 get_default_root(string);
1223                         }
1224                         
1225                         /* ignore leading slashes */
1226                         while (*dir == '/' || *dir == '\\') dir++;
1227                 }
1228         }
1229 #endif
1230
1231         strcat(string, dir);
1232
1233         /* Make sure string ends in one (and only one) slash */ 
1234         /* first trim all slashes from the end of the string */
1235         sl = strlen(string);
1236         while (sl>0 && ( string[sl-1] == '/' || string[sl-1] == '\\') ) {
1237                 string[sl-1] = '\0';
1238                 sl--;
1239         }
1240         /* since we've now removed all slashes, put back one slash at the end. */
1241         strcat(string, "/");
1242         
1243         while (*file && (*file == '/' || *file == '\\')) /* Trim slashes from the front of file */
1244                 file++;
1245                 
1246         strcat (string, file);
1247         
1248         /* Push all slashes to the system preferred direction */
1249         BLI_clean(string);
1250 }
1251
1252 int BLI_testextensie(const char *str, const char *ext)
1253 {
1254         short a, b;
1255         int retval;
1256
1257         a= strlen(str);
1258         b= strlen(ext);
1259
1260         if(a==0 || b==0 || b>=a) {
1261                 retval = 0;
1262         } else if (BLI_strcasecmp(ext, str + a - b)) {
1263                 retval = 0;     
1264         } else {
1265                 retval = 1;
1266         }
1267
1268         return (retval);
1269 }
1270
1271
1272
1273 void BLI_split_dirfile(const char *string, char *dir, char *file)
1274 {
1275         int a;
1276 #ifdef WIN32
1277         int sl;
1278         short is_relative = 0;
1279         char path[FILE_MAX];
1280 #endif
1281
1282         dir[0]= 0;
1283         file[0]= 0;
1284
1285 #ifdef WIN32
1286         BLI_strncpy(path, string, FILE_MAX);
1287         BLI_char_switch(path, '/', '\\'); /* make sure we have a valid path format */
1288         sl = strlen(path);
1289         if (sl) {
1290                 int len;
1291                 if (path[0] == '/' || path[0] == '\\') { 
1292                         BLI_strncpy(dir, path, FILE_MAXDIR);
1293                         if (sl > 1 && path[0] == '\\' && path[1] == '\\') is_relative = 1;
1294                 } else if (sl > 2 && path[1] == ':' && path[2] == '\\') {
1295                         BLI_strncpy(dir, path, FILE_MAXDIR);
1296                 } else {
1297                         BLI_getwdN(dir);
1298                         strcat(dir,"\\");
1299                         strcat(dir,path);
1300                         BLI_strncpy(path,dir,FILE_MAXDIR+FILE_MAXFILE);
1301                 }
1302                 
1303                 // BLI_exist doesn't recognize a slashed dirname as a dir
1304                 //  check if a trailing slash exists, and remove it. Do not do this
1305                 //  when we are already at root. -jesterKing
1306                 a = strlen(dir);
1307                 if(a>=4 && dir[a-1]=='\\') dir[a-1] = 0;
1308
1309                 if (is_relative) {
1310                         printf("WARNING: BLI_split_dirfile needs absolute dir\n");
1311                 }
1312                 else {
1313                         BLI_make_exist(dir);
1314                 }
1315
1316                 if (S_ISDIR(BLI_exist(dir))) {
1317
1318                         /* copy from end of string into file, to ensure filename itself isn't truncated 
1319                         if string is too long. (aphex) */
1320
1321                         len = FILE_MAXFILE - strlen(path);
1322
1323                         if (len < 0)
1324                                 BLI_strncpy(file,path + abs(len),FILE_MAXFILE);
1325                         else
1326                                 BLI_strncpy(file,path,FILE_MAXFILE);
1327                     
1328                         if (strrchr(path,'\\')) {
1329                                 BLI_strncpy(file,strrchr(path,'\\')+1,FILE_MAXFILE);
1330                         }
1331                         
1332                         if ( (a = strlen(dir)) ) {
1333                                 if (dir[a-1] != '\\') strcat(dir,"\\");
1334                         }
1335                 }
1336                 else {
1337                         a = strlen(dir) - 1;
1338                         while(a>0 && dir[a] != '\\') a--;
1339                         dir[a + 1] = 0;
1340                         BLI_strncpy(file, path + strlen(dir),FILE_MAXFILE);
1341                 }
1342
1343         }
1344         else {
1345                 /* defaulting to first valid drive hoping it's not empty CD and DVD drives */
1346                 get_default_root(dir);
1347                 file[0]=0;
1348         }
1349 #else
1350         if (strlen(string)) {
1351                 if (string[0] == '/') { 
1352                         strcpy(dir, string);
1353                 } else if (string[1] == ':' && string[2] == '\\') {
1354                         string+=2;
1355                         strcpy(dir, string);
1356                 } else {
1357                         BLI_getwdN(dir);
1358                         strcat(dir,"/");
1359                         strcat(dir,string);
1360                         strcpy((char *)string,dir);
1361                 }
1362
1363                 BLI_make_exist(dir);
1364                         
1365                 if (S_ISDIR(BLI_exist(dir))) {
1366                         strcpy(file,string + strlen(dir));
1367
1368                         if (strrchr(file,'/')) strcpy(file,strrchr(file,'/')+1);
1369                 
1370                         if ( (a = strlen(dir)) ) {
1371                                 if (dir[a-1] != '/') strcat(dir,"/");
1372                         }
1373                 }
1374                 else {
1375                         a = strlen(dir) - 1;
1376                         while(dir[a] != '/') a--;
1377                         dir[a + 1] = 0;
1378                         strcpy(file, string + strlen(dir));
1379                 }
1380         }
1381         else {
1382                 BLI_getwdN(dir);
1383                 strcat(dir, "/");
1384                 file[0] = 0;
1385         }
1386 #endif
1387 }
1388
1389 /* simple appending of filename to dir, does not check for valid path! */
1390 void BLI_join_dirfile(char *string, const char *dir, const char *file)
1391 {
1392         int sl_dir = strlen(dir);
1393         BLI_strncpy(string, dir, FILE_MAX);
1394         if (sl_dir > FILE_MAX-1) sl_dir = FILE_MAX-1;
1395 #ifdef WIN32
1396         string[sl_dir] = '\\';
1397 #else
1398         string[sl_dir] = '/';
1399 #endif
1400         sl_dir++;
1401         if (sl_dir <FILE_MAX) {
1402                 BLI_strncpy(string + sl_dir, file, FILE_MAX-sl_dir);
1403         }
1404 }
1405
1406 static int add_win32_extension(char *name)
1407 {
1408         int retval = 0;
1409         int type;
1410
1411         type = BLI_exist(name);
1412         if ((type == 0) || S_ISDIR(type)) {
1413 #ifdef _WIN32
1414                 char filename[FILE_MAXDIR+FILE_MAXFILE];
1415                 char ext[FILE_MAXDIR+FILE_MAXFILE];
1416                 char *extensions = getenv("PATHEXT");
1417                 if (extensions) {
1418                         char *temp;
1419                         do {
1420                                 strcpy(filename, name);
1421                                 temp = strstr(extensions, ";");
1422                                 if (temp) {
1423                                         strncpy(ext, extensions, temp - extensions);
1424                                         ext[temp - extensions] = 0;
1425                                         extensions = temp + 1;
1426                                         strcat(filename, ext);
1427                                 } else {
1428                                         strcat(filename, extensions);
1429                                 }
1430
1431                                 type = BLI_exist(filename);
1432                                 if (type && (! S_ISDIR(type))) {
1433                                         retval = 1;
1434                                         strcpy(name, filename);
1435                                         break;
1436                                 }
1437                         } while (temp);
1438                 }
1439 #endif
1440         } else {
1441                 retval = 1;
1442         }
1443
1444         return (retval);
1445 }
1446
1447 void BLI_where_am_i(char *fullname, char *name)
1448 {
1449         char filename[FILE_MAXDIR+FILE_MAXFILE];
1450         char *path, *temp;
1451         int len;
1452 #ifdef _WIN32
1453         char *seperator = ";";
1454         char *slash = "\\";
1455 #else
1456         char *seperator = ":";
1457         char *slash = "/";
1458 #endif
1459
1460         if (name && fullname && strlen(name)) {
1461                 strcpy(fullname, name);
1462                 if (name[0] == '.') {
1463                         // relative path, prepend cwd
1464                         BLI_getwdN(fullname);
1465                         len = strlen(fullname);
1466                         if (len && fullname[len -1] != slash[0]) {
1467                                 strcat(fullname, slash);
1468                         }
1469                         strcat(fullname, name);
1470                         add_win32_extension(fullname);
1471                 } else if (BLI_last_slash(name)) {
1472                         // full path
1473                         strcpy(fullname, name);
1474                         add_win32_extension(fullname);
1475                 } else {
1476                         // search for binary in $PATH
1477                         path = getenv("PATH");
1478                         if (path) {
1479                                 do {
1480                                         temp = strstr(path, seperator);
1481                                         if (temp) {
1482                                                 strncpy(filename, path, temp - path);
1483                                                 filename[temp - path] = 0;
1484                                                 path = temp + 1;
1485                                         } else {
1486                                                 strncpy(filename, path, sizeof(filename));
1487                                         }
1488                                         len = strlen(filename);
1489                                         if (len && filename[len - 1] != slash[0]) {
1490                                                 strcat(filename, slash);
1491                                         }
1492                                         strcat(filename, name);
1493                                         if (add_win32_extension(filename)) {
1494                                                 strcpy(fullname, filename);
1495                                                 break;
1496                                         }
1497                                 } while (temp);
1498                         }
1499                 }
1500 #ifndef NDEBUG
1501                 if (strcmp(name, fullname)) {
1502                         printf("guessing '%s' == '%s'\n", name, fullname);
1503                 }
1504 #endif
1505
1506 #ifdef _WIN32
1507                 // in windows change long filename to short filename because
1508                 // win2k doesn't know how to parse a commandline with lots of
1509                 // spaces and double-quotes. There's another solution to this
1510                 // with spawnv(P_WAIT, bprogname, argv) instead of system() but
1511                 // that's even uglier
1512                 GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
1513 #ifndef NDEBUG
1514                 printf("Shortname = '%s'\n", fullname);
1515 #endif
1516 #endif
1517         }
1518 }
1519
1520 /* 
1521  * returns absolute path to the app bundle
1522  * only useful on OS X 
1523  */
1524 #ifdef __APPLE__
1525 char* BLI_getbundle(void) {
1526         CFURLRef bundleURL;
1527         CFStringRef pathStr;
1528         static char path[MAXPATHLEN];
1529         CFBundleRef mainBundle = CFBundleGetMainBundle();
1530
1531         bundleURL = CFBundleCopyBundleURL(mainBundle);
1532         pathStr = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
1533         CFStringGetCString(pathStr, path, MAXPATHLEN, kCFStringEncodingASCII);
1534         return path;
1535 }
1536 #endif
1537
1538 /* strcasestr not available in MSVC */
1539 char *BLI_strcasestr(const char *s, const char *find)
1540 {
1541     register char c, sc;
1542     register size_t len;
1543         
1544     if ((c = *find++) != 0) {
1545                 c= tolower(c);
1546                 len = strlen(find);
1547                 do {
1548                         do {
1549                                 if ((sc = *s++) == 0)
1550                                         return (NULL);
1551                                 sc= tolower(sc);
1552                         } while (sc != c);
1553                 } while (BLI_strncasecmp(s, find, len) != 0);
1554                 s--;
1555     }
1556     return ((char *) s);
1557 }
1558
1559
1560 int BLI_strcasecmp(const char *s1, const char *s2) {
1561         int i;
1562
1563         for (i=0; ; i++) {
1564                 char c1 = tolower(s1[i]);
1565                 char c2 = tolower(s2[i]);
1566
1567                 if (c1<c2) {
1568                         return -1;
1569                 } else if (c1>c2) {
1570                         return 1;
1571                 } else if (c1==0) {
1572                         break;
1573                 }
1574         }
1575
1576         return 0;
1577 }
1578
1579 int BLI_strncasecmp(const char *s1, const char *s2, int n) {
1580         int i;
1581
1582         for (i=0; i<n; i++) {
1583                 char c1 = tolower(s1[i]);
1584                 char c2 = tolower(s2[i]);
1585
1586                 if (c1<c2) {
1587                         return -1;
1588                 } else if (c1>c2) {
1589                         return 1;
1590                 } else if (c1==0) {
1591                         break;
1592                 }
1593         }
1594
1595         return 0;
1596 }
1597
1598
1599 #ifdef WITH_ICONV
1600 #include "iconv.h"
1601 #include "localcharset.h"
1602
1603 void BLI_string_to_utf8(char *original, char *utf_8, char *code)
1604 {
1605         size_t inbytesleft=strlen(original);
1606         size_t outbytesleft=512;
1607         size_t rv=0;
1608         iconv_t cd;
1609         
1610         if (NULL == code) {
1611                 code = locale_charset();
1612         }
1613         cd=iconv_open("UTF-8", code);
1614
1615         if (cd == (iconv_t)(-1)) {
1616                 printf("iconv_open Error");
1617                 *utf_8='\0';
1618                 return ;
1619         }
1620         rv=iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft);
1621         if (rv == (size_t) -1) {
1622                 printf("iconv Error\n");
1623                 return ;
1624         }
1625         *utf_8 = '\0';
1626         iconv_close(cd);
1627 }
1628 #endif // WITH_ICONV
1629
1630 void BLI_timestr(double _time, char *str)
1631 {
1632         /* format 00:00:00.00 (hr:min:sec) string has to be 12 long */
1633         int  hr= ( (int)  _time) / (60*60);
1634         int min= (((int)  _time) / 60 ) % 60;
1635         int sec= ( (int) (_time)) % 60;
1636         int hun= ( (int) (_time   * 100.0)) % 100;
1637         
1638         if (hr) {
1639                 sprintf(str, "%.2d:%.2d:%.2d.%.2d",hr,min,sec,hun);
1640         } else {
1641                 sprintf(str, "%.2d:%.2d.%.2d",min,sec,hun);
1642         }
1643         
1644         str[11]=0;
1645 }
1646
1647 /* ************** 64 bits magic, trick to support up to 32 gig of address space *************** */
1648 /*                only works for malloced pointers (8 aligned)                   */
1649
1650 #ifdef __LP64__ 
1651
1652 #if defined(WIN32) && !defined(FREE_WINDOWS)
1653 #define PMASK           0x07FFFFFFFFi64
1654 #else
1655 #define PMASK           0x07FFFFFFFFll
1656 #endif
1657
1658
1659 int BLI_int_from_pointer(void *poin)
1660 {
1661         long lval= (long)poin;
1662         
1663         return (int)(lval>>3);
1664 }
1665
1666 void *BLI_pointer_from_int(int val)
1667 {
1668         static int firsttime= 1;
1669         static long basevalue= 0;
1670         
1671         if(firsttime) {
1672                 void *poin= malloc(10000);
1673                 basevalue= (long)poin;
1674                 basevalue &= ~PMASK;
1675                 printf("base: %d pointer %p\n", basevalue, poin); /* debug */
1676                 firsttime= 0;
1677                 free(poin);
1678         }
1679         return (void *)(basevalue | (((long)val)<<3));
1680 }
1681
1682 #else
1683
1684 int BLI_int_from_pointer(void *poin)
1685 {
1686         return (int)poin;
1687 }
1688 void *BLI_pointer_from_int(int val)
1689 {
1690         return (void *)val;
1691 }
1692
1693 #endif
1694