3 * various string, file, list operations.
8 * ***** BEGIN GPL LICENSE BLOCK *****
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.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
25 * All rights reserved.
27 * The Original Code is: all of this file.
29 * Contributor(s): none yet.
31 * ***** END GPL LICENSE BLOCK *****
41 #include <math.h> /* for log10 */
43 #include "MEM_guardedalloc.h"
45 #include "DNA_listBase.h"
46 #include "DNA_userdef_types.h"
48 #include "BLI_blenlib.h"
49 #include "BLI_storage.h"
50 #include "BLI_storage_types.h"
51 #include "BLI_dynamiclist.h"
54 #include "BKE_utildefines.h"
72 #define _WIN32_IE 0x0501
76 #include "BLI_winstuff.h"
78 /* for duplicate_defgroup */
79 #if !(defined vsnprintf)
80 #define vsnprintf _vsnprintf
91 #include <sys/param.h>
92 #include <CoreFoundation/CoreFoundation.h>
101 static int add_win32_extension(char *name);
105 /* Ripped this from blender.c */
106 void addlisttolist(ListBase *list1, ListBase *list2)
108 if (list2->first==0) return;
110 if (list1->first==0) {
111 list1->first= list2->first;
112 list1->last= list2->last;
115 ((Link *)list1->last)->next= list2->first;
116 ((Link *)list2->first)->prev= list1->last;
117 list1->last= list2->last;
119 list2->first= list2->last= 0;
122 int BLI_stringdec(char *string, char *kop, char *start, unsigned short *numlen)
124 unsigned short len, len2, nums = 0, nume = 0;
127 len2 = len = strlen(string);
130 if (BLI_strncasecmp(string + len - 6, ".blend", 6) == 0) len -= 6;
131 else if (BLI_strncasecmp(string + len - 6, ".trace", 6) == 0) len -= 6;
135 if (BLI_strncasecmp(string + len - 9, ".blend.gz", 9) == 0) len -= 9;
140 /* handle .jf0 en .jf1 for jstreams */
141 if (BLI_strncasecmp(string + len - 4, ".jf", 3) == 0) len -= 4;
142 else if (BLI_strncasecmp(string + len - 4, ".tga", 4) == 0) len -= 4;
143 else if (BLI_strncasecmp(string + len - 4, ".jpg", 4) == 0) len -= 4;
144 else if (BLI_strncasecmp(string + len - 4, ".png", 4) == 0) len -= 4;
145 else if (BLI_strncasecmp(string + len - 4, ".txt", 4) == 0) len -= 4;
146 else if (BLI_strncasecmp(string + len - 4, ".cyc", 4) == 0) len -= 4;
147 else if (BLI_strncasecmp(string + len - 4, ".enh", 4) == 0) len -= 4;
148 else if (BLI_strncasecmp(string + len - 4, ".rgb", 4) == 0) len -= 4;
149 else if (BLI_strncasecmp(string + len - 4, ".psx", 4) == 0) len -= 4;
150 else if (BLI_strncasecmp(string + len - 4, ".ble", 4) == 0) len -= 4;
151 else if (BLI_strncasecmp(string + len - 4, ".exr", 4) == 0) len -= 4;
155 for (i = len - 1; i >= 0; i--) {
156 if (string[i] == '/') break;
157 if (isdigit(string[i])) {
172 if (start) strcpy(start,&string[nume+1]);
177 if (numlen) *numlen = nume-nums+1;
178 return ((int)atoi(&(string[nums])));
180 if (start) strcpy(start, string + len);
182 strncpy(kop, string, len);
185 if (numlen) *numlen=0;
190 void BLI_stringenc(char *string, char *kop, char *start, unsigned short numlen, int pic)
193 unsigned short len,i;
197 if (pic>0 || numlen==4) {
198 len= sprintf(numstr,"%d",pic);
200 for(i=len;i<numlen;i++){
203 strcat(string,numstr);
205 strcat(string, start);
209 void BLI_newname(char *name, int add)
211 char head[128], tail[128];
213 unsigned short digits;
215 pic = BLI_stringdec(name, head, tail, &digits);
217 /* are we going from 100 -> 99 or from 10 -> 9 */
218 if (add < 0 && digits < 4 && digits > 0) {
221 for (i = digits; i > 1; i--) exp *= 10;
222 if (pic >= exp && (pic + add) < exp) digits--;
227 if (digits==4 && pic<0) pic= 0;
228 BLI_stringenc(name, head, tail, digits, pic);
231 /* little helper macro for BLI_uniquename */
233 #define GIVE_STRADDR(data, offset) ( ((char *)data) + offset )
236 /* Generic function to set a unique name. It is only designed to be used in situations
237 * where the name is part of the struct, and also that the name is at most 128 chars long.
239 * For places where this is used, see constraint.c for example...
241 * name_offs: should be calculated using offsetof(structname, membername) macro from stddef.h
242 * len: maximum length of string (to prevent overflows, etc.)
243 * defname: the name that should be used by default if none is specified already
245 void BLI_uniquename(ListBase *list, void *vlink, char defname[], short name_offs, short len)
249 int number = 1, exists = 0;
252 /* Make sure length can be handled */
253 if ((len < 0) || (len > 128))
256 /* See if we are given an empty string */
257 if (ELEM(NULL, vlink, defname))
260 if (GIVE_STRADDR(vlink, name_offs) == '\0') {
261 /* give it default name first */
262 BLI_strncpy(GIVE_STRADDR(vlink, name_offs), defname, len);
265 /* See if we even need to do this */
269 for (link = list->first; link; link= link->next) {
271 if (!strcmp(GIVE_STRADDR(link, name_offs), GIVE_STRADDR(vlink, name_offs))) {
280 /* Strip off the suffix */
281 dot = strchr(GIVE_STRADDR(vlink, name_offs), '.');
285 for (number = 1; number <= 999; number++) {
286 BLI_snprintf(tempname, 128, "%s.%03d", GIVE_STRADDR(vlink, name_offs), number);
289 for (link= list->first; link; link= link->next) {
291 if (!strcmp(GIVE_STRADDR(link, name_offs), tempname)) {
298 BLI_strncpy(GIVE_STRADDR(vlink, name_offs), tempname, len);
305 void BLI_addhead(ListBase *listbase, void *vlink)
309 if (link == NULL) return;
310 if (listbase == NULL) return;
312 link->next = listbase->first;
315 if (listbase->first) ((Link *)listbase->first)->prev = link;
316 if (listbase->last == NULL) listbase->last = link;
317 listbase->first = link;
321 void BLI_addtail(ListBase *listbase, void *vlink)
325 if (link == NULL) return;
326 if (listbase == NULL) return;
329 link->prev = listbase->last;
331 if (listbase->last) ((Link *)listbase->last)->next = link;
332 if (listbase->first == 0) listbase->first = link;
333 listbase->last = link;
337 void BLI_remlink(ListBase *listbase, void *vlink)
341 if (link == NULL) return;
342 if (listbase == NULL) return;
344 if (link->next) link->next->prev = link->prev;
345 if (link->prev) link->prev->next = link->next;
347 if (listbase->last == link) listbase->last = link->prev;
348 if (listbase->first == link) listbase->first = link->next;
352 void BLI_freelinkN(ListBase *listbase, void *vlink)
356 if (link == NULL) return;
357 if (listbase == NULL) return;
359 BLI_remlink(listbase,link);
364 void BLI_insertlink(ListBase *listbase, void *vprevlink, void *vnewlink)
366 Link *prevlink= vprevlink;
367 Link *newlink= vnewlink;
369 /* newlink comes after prevlink */
370 if (newlink == NULL) return;
371 if (listbase == NULL) return;
374 if (listbase->first == NULL) {
376 listbase->first= newlink;
377 listbase->last= newlink;
381 /* insert before first element */
382 if (prevlink == NULL) {
383 newlink->next= listbase->first;
385 newlink->next->prev= newlink;
386 listbase->first= newlink;
391 if (listbase->last== prevlink)
392 listbase->last = newlink;
394 newlink->next= prevlink->next;
395 prevlink->next= newlink;
396 if (newlink->next) newlink->next->prev= newlink;
397 newlink->prev= prevlink;
400 /* This uses insertion sort, so NOT ok for large list */
401 void BLI_sortlist(ListBase *listbase, int (*cmp)(void *, void *))
403 Link *current = NULL;
404 Link *previous = NULL;
407 if (cmp == NULL) return;
408 if (listbase == NULL) return;
410 if (listbase->first != listbase->last)
412 for( previous = listbase->first, current = previous->next; current; current = next )
414 next = current->next;
415 previous = current->prev;
417 BLI_remlink(listbase, current);
419 while(previous && cmp(previous, current) == 1)
421 previous = previous->prev;
424 BLI_insertlinkafter(listbase, previous, current);
429 void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink)
431 Link *prevlink= vprevlink;
432 Link *newlink= vnewlink;
434 /* newlink before nextlink */
435 if (newlink == NULL) return;
436 if (listbase == NULL) return;
439 if (listbase->first == NULL) {
440 listbase->first= newlink;
441 listbase->last= newlink;
445 /* insert at head of list */
446 if (prevlink == NULL) {
447 newlink->prev = NULL;
448 newlink->next = listbase->first;
449 ((Link *)listbase->first)->prev = newlink;
450 listbase->first = newlink;
455 if (listbase->last == prevlink)
456 listbase->last = newlink;
458 newlink->next = prevlink->next;
459 newlink->prev = prevlink;
460 prevlink->next = newlink;
461 if (newlink->next) newlink->next->prev = newlink;
464 void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
466 Link *nextlink= vnextlink;
467 Link *newlink= vnewlink;
469 /* newlink before nextlink */
470 if (newlink == NULL) return;
471 if (listbase == NULL) return;
474 if (listbase->first == NULL) {
475 listbase->first= newlink;
476 listbase->last= newlink;
480 /* insert at end of list */
481 if (nextlink == NULL) {
482 newlink->prev= listbase->last;
484 ((Link *)listbase->last)->next= newlink;
485 listbase->last= newlink;
489 /* at beginning of list */
490 if (listbase->first== nextlink)
491 listbase->first = newlink;
493 newlink->next= nextlink;
494 newlink->prev= nextlink->prev;
495 nextlink->prev= newlink;
496 if (newlink->prev) newlink->prev->next= newlink;
500 void BLI_freelist(ListBase *listbase)
504 if (listbase == NULL)
507 link= listbase->first;
514 listbase->first= NULL;
515 listbase->last= NULL;
518 void BLI_freelistN(ListBase *listbase)
522 if (listbase == NULL) return;
524 link= listbase->first;
531 listbase->first= NULL;
532 listbase->last= NULL;
536 int BLI_countlist(ListBase *listbase)
542 link = listbase->first;
551 void *BLI_findlink(ListBase *listbase, int number)
556 link = listbase->first;
557 while (link != NULL && number != 0) {
566 int BLI_findindex(ListBase *listbase, void *vlink)
571 if (listbase == NULL) return -1;
572 if (vlink == NULL) return -1;
574 link= listbase->first;
586 /*=====================================================================================*/
587 /* Methods for access array (realloc) */
588 /*=====================================================================================*/
590 /* remove item with index */
591 static void rem_array_item(struct DynamicArray *da, unsigned int index)
593 da->items[index]=NULL;
595 if(index==da->last_item_index){
596 while((!da->items[da->last_item_index]) && (da->last_item_index>0)){
597 da->last_item_index--;
602 /* add array (if needed, then realloc) */
603 static void add_array_item(struct DynamicArray *da, void *item, unsigned int index)
605 /* realloc of access array */
606 if(da->max_item_index < index){
607 unsigned int i, max = da->max_item_index;
611 da->max_item_index += PAGE_SIZE; /* OS can allocate only PAGE_SIZE Bytes */
612 } while(da->max_item_index<=index);
614 nitems = (void**)MEM_mallocN(sizeof(void*)*(da->max_item_index+1), "dlist access array");
616 nitems[i] = da->items[i];
618 /* set rest pointers to the NULL */
619 for(i=max+1; i<=da->max_item_index; i++)
622 MEM_freeN(da->items); /* free old access array */
626 da->items[index] = item;
628 if(index > da->last_item_index) da->last_item_index = index;
631 /* free access array */
632 static void destroy_array(DynamicArray *da)
635 da->last_item_index=0;
636 da->max_item_index=0;
637 MEM_freeN(da->items);
641 /* initialize dynamic array */
642 static void init_array(DynamicArray *da)
647 da->last_item_index=0;
648 da->max_item_index = PAGE_SIZE-1;
649 da->items = (void*)MEM_mallocN(sizeof(void*)*(da->max_item_index+1), "dlist access array");
650 for(i=0; i<=da->max_item_index; i++) da->items[i]=NULL;
653 /* reinitialize dynamic array */
654 static void reinit_array(DynamicArray *da)
660 /*=====================================================================================*/
661 /* Methods for two way dynamic list with access array */
662 /*=====================================================================================*/
664 /* create new two way dynamic list with access array from two way dynamic list
665 * it doesn't copy any items to new array or something like this It is strongly
666 * recomended to use BLI_dlist_ methods for adding/removing items from dynamic list
667 * unless you can end with inconsistence system !!! */
668 DynamicList *BLI_dlist_from_listbase(ListBase *lb)
676 count = BLI_countlist(lb);
678 dlist = MEM_mallocN(sizeof(DynamicList), "temp dynamic list");
680 dlist->lb.first = lb->first;
681 dlist->lb.last = lb->last;
682 /* access array stuff */
683 dlist->da.count=count;
684 dlist->da.max_item_index = count-1;
685 dlist->da.last_item_index = count -1;
686 dlist->da.items = (void*)MEM_mallocN(sizeof(void*)*count, "temp dlist access array");
688 item = (Link*)lb->first;
690 dlist->da.items[i] = (void*)item;
695 /* to prevent you of using original ListBase :-) */
696 lb->first = lb->last = NULL;
701 /* take out ListBase from DynamicList and destroy all temporary structures of DynamicList */
702 ListBase *BLI_listbase_from_dlist(DynamicList *dlist, ListBase *lb)
704 if(!dlist) return NULL;
706 if(!lb) lb = (ListBase*)MEM_mallocN(sizeof(ListBase), "ListBase");
708 lb->first = dlist->lb.first;
709 lb->last = dlist->lb.last;
711 /* free all items of access array */
712 MEM_freeN(dlist->da.items);
713 /* free DynamicList*/
719 /* return pointer at item from th dynamic list with access array */
720 void *BLI_dlist_find_link(DynamicList *dlist, unsigned int index)
722 if(!dlist || !dlist->da.items) return NULL;
724 if((index <= dlist->da.last_item_index) && (index >= 0) && (dlist->da.count>0)){
725 return dlist->da.items[index];
732 /* return count of items in the dynamic list with access array */
733 unsigned int BLI_count_items(DynamicList *dlist)
737 return dlist->da.count;
740 /* free item from the dynamic list with access array */
741 void BLI_dlist_free_item(DynamicList *dlist, unsigned int index)
743 if(!dlist || !dlist->da.items) return;
745 if((index <= dlist->da.last_item_index) && (dlist->da.items[index])){
746 BLI_freelinkN(&(dlist->lb), dlist->da.items[index]);
747 rem_array_item(&(dlist->da), index);
751 /* remove item from the dynamic list with access array */
752 void BLI_dlist_rem_item(DynamicList *dlist, unsigned int index)
754 if(!dlist || !dlist->da.items) return;
756 if((index <= dlist->da.last_item_index) && (dlist->da.items[index])){
757 BLI_remlink(&(dlist->lb), dlist->da.items[index]);
758 rem_array_item(&(dlist->da), index);
762 /* add item to the dynamic list with access array (index) */
763 void* BLI_dlist_add_item_index(DynamicList *dlist, void *item, unsigned int index)
765 if(!dlist || !dlist->da.items) return NULL;
767 if((index <= dlist->da.max_item_index) && (dlist->da.items[index])) {
768 /* you can't place item at used index */
772 add_array_item(&(dlist->da), item, index);
773 BLI_addtail(&(dlist->lb), item);
778 /* destroy dynamic list with access array */
779 void BLI_dlist_destroy(DynamicList *dlist)
783 BLI_freelistN(&(dlist->lb));
784 destroy_array(&(dlist->da));
787 /* initialize dynamic list with access array */
788 void BLI_dlist_init(DynamicList *dlist)
792 dlist->lb.first = NULL;
793 dlist->lb.last = NULL;
795 init_array(&(dlist->da));
798 /* reinitialize dynamic list with acces array */
799 void BLI_dlist_reinit(DynamicList *dlist)
803 BLI_freelistN(&(dlist->lb));
804 reinit_array(&(dlist->da));
807 /*=====================================================================================*/
809 char *BLI_strdupn(const char *str, int len) {
810 char *n= MEM_mallocN(len+1, "strdup");
816 char *BLI_strdup(const char *str) {
817 return BLI_strdupn(str, strlen(str));
820 char *BLI_strncpy(char *dst, const char *src, int maxncpy) {
821 int srclen= strlen(src);
822 int cpylen= (srclen>(maxncpy-1))?(maxncpy-1):srclen;
824 memcpy(dst, src, cpylen);
830 int BLI_snprintf(char *buffer, size_t count, const char *format, ...)
835 va_start(arg, format);
836 n = vsnprintf(buffer, count, format, arg);
838 if (n != -1 && n < count) {
841 buffer[count-1] = '\0';
848 int BLI_streq(char *a, char *b) {
849 return (strcmp(a, b)==0);
851 int BLI_strcaseeq(char *a, char *b) {
852 return (BLI_strcasecmp(a, b)==0);
855 /* ******************** string encoding ***************** */
857 /* This is quite an ugly function... its purpose is to
858 * take the dir name, make it absolute, and clean it up, replacing
859 * excess file entry stuff (like /tmp/../tmp/../)
860 * note that dir isn't protected for max string names...
863 void BLI_cleanup_dir(const char *relabase, char *dir)
865 BLI_cleanup_file(relabase, dir);
873 void BLI_cleanup_file(const char *relabase, char *dir)
878 BLI_convertstringcode(dir, relabase, 0);
881 if(dir[0]=='.') { /* happens for example in FILE_MAIN */
882 get_default_root(dir);
886 while ( (start = strstr(dir, "\\..\\")) ) {
887 eind = start + strlen("\\..\\") - 1;
890 if (dir[a] == '\\') break;
896 while ( (start = strstr(dir,"\\.\\")) ){
897 eind = start + strlen("\\.\\") - 1;
901 while ( (start = strstr(dir,"\\\\" )) ){
902 eind = start + strlen("\\\\") - 1;
906 if((a = strlen(dir))){ /* remove the '\\' at the end */
907 while(a>0 && dir[a-1] == '\\'){
913 if(dir[0]=='.') { /* happens, for example in FILE_MAIN */
919 while ( (start = strstr(dir, "/../")) ) {
920 eind = start + strlen("/../") - 1;
923 if (dir[a] == '/') break;
929 while ( (start = strstr(dir,"/./")) ){
930 eind = start + strlen("/./") - 1;
934 while ( (start = strstr(dir,"//" )) ){
935 eind = start + strlen("//") - 1;
939 if( (a = strlen(dir)) ){ /* remove all '/' at the end */
940 while(dir[a-1] == '/'){
950 void BLI_makestringcode(const char *relfile, char *file)
955 char temp[FILE_MAXDIR+FILE_MAXFILE];
956 char res[FILE_MAXDIR+FILE_MAXFILE];
958 /* if file is already relative, bail out */
959 if(file[0]=='/' && file[1]=='/') return;
961 /* also bail out if relative path is not set */
962 if (relfile[0] == 0) return;
965 if (strlen(relfile) > 2 && relfile[1] != ':') {
967 /* fix missing volume name in relative base,
968 can happen with old .Blog files */
969 get_default_root(temp);
971 if (relfile[0] != '\\' && relfile[0] != '/') {
974 BLI_strncpy(ptemp, relfile, FILE_MAXDIR + FILE_MAXFILE-3);
976 BLI_strncpy(temp, relfile, FILE_MAXDIR + FILE_MAXFILE);
979 if (strlen(file) > 2) {
980 if ( temp[1] == ':' && file[1] == ':' && temp[0] != file[0] )
984 BLI_strncpy(temp, relfile, FILE_MAX);
987 BLI_char_switch(temp, '\\', '/');
988 BLI_char_switch(file, '\\', '/');
990 /* the last slash in the file indicates where the path part ends */
991 lslash = BLI_last_slash(temp);
995 /* find the prefix of the filename that is equal for both filenames.
996 This is replaced by the two slashes at the beginning */
1002 /* we might have passed the slash when the beginning of a dir matches
1003 so we rewind. Only check on the actual filename
1006 while ( (q >= file) && (*q != '/') ) { --q; --p; }
1008 else if (*p != '/') {
1009 while ( (p >= temp) && (*p != '/') ) { --p; --q; }
1014 /* p now points to the slash that is at the beginning of the part
1015 where the path is different from the relative path.
1016 We count the number of directories we need to go up in the
1017 hierarchy to arrive at the common 'prefix' of the path
1019 while (p && p < lslash) {
1025 strcat(res, q+1); /* don't copy the slash at the beginning */
1028 BLI_char_switch(res+2, '/', '\\');
1034 int BLI_convertstringcode(char *path, const char *basepath, int framenum)
1039 char base[FILE_MAX];
1040 char vol[3] = {'\0', '\0', '\0'};
1042 BLI_strncpy(vol, path, 3);
1043 wasrelative= (strncmp(vol, "//", 2)==0);
1046 /* we are checking here if we have an absolute path that is not in the current
1047 blend file as a lib main - we are basically checking for the case that a
1048 UNIX root '/' is passed.
1050 if (!wasrelative && (vol[1] != ':' && (vol[0] == '\0' || vol[0] == '/' || vol[0] == '\\'))) {
1052 get_default_root(tmp);
1053 // get rid of the slashes at the beginning of the path
1054 while (*p == '\\' || *p == '/') {
1060 BLI_strncpy(tmp, path, FILE_MAX);
1063 BLI_strncpy(tmp, path, FILE_MAX);
1066 BLI_strncpy(base, basepath, FILE_MAX);
1068 /* push slashes into unix mode - strings entering this part are
1069 potentially messed up: having both back- and forward slashes.
1070 Here we push into one conform direction, and at the end we
1071 push them into the system specific dir. This ensures uniformity
1072 of paths and solving some problems (and prevent potential future
1073 ones) -jesterKing. */
1074 BLI_char_switch(tmp, '\\', '/');
1075 BLI_char_switch(base, '\\', '/');
1077 if (tmp[0] == '/' && tmp[1] == '/') {
1078 char *filepart= BLI_strdup(tmp+2); /* skip code */
1079 char *lslash= BLI_last_slash(base);
1082 int baselen= (int) (lslash-base) + 1;
1084 memcpy(tmp, base, baselen);
1085 strcpy(tmp+baselen, filepart);
1087 strcpy(tmp, filepart);
1090 MEM_freeN(filepart);
1094 /* Insert current frame: file### -> file001 */
1096 for (ch_sta = 0; tmp[ch_sta] != '\0'; ch_sta++) {
1097 if (tmp[ch_sta] == '#') {
1099 while (tmp[ch_end] == '#') {
1105 if (ch_end) { /* warning, ch_end is the last # +1 */
1106 /* Add the frame number? */
1107 short numlen, hashlen;
1108 char format[16]; /* 6 is realistically the maxframe (300000), so 8 should be enough, but 16 to be safe. */
1110 numlen = 1 + (int)log10((double)framenum); /* this is the number of chars in the number */
1111 hashlen = ch_end - ch_sta;
1113 sprintf(format, "%d", framenum);
1115 if (numlen==hashlen) { /* simple case */
1116 memcpy(tmp+ch_sta, format, numlen);
1117 } else if (numlen < hashlen) {
1118 memcpy(tmp+ch_sta + (hashlen-numlen), format, numlen); /*dont copy the string terminator */
1119 memset(tmp+ch_sta, '0', hashlen-numlen);
1121 /* number is longer then number of #'s */
1122 if (tmp[ch_end] == '\0') { /* hashes are last, no need to move any string*/
1123 /* bad juju - not testing string length here :/ */
1124 memcpy(tmp+ch_sta, format, numlen+1); /* add 1 to get the string terminator \0 */
1126 /* we need to move the end characters */
1127 int i = strlen(tmp); /* +1 to copy the string terminator */
1128 int j = i + (numlen-hashlen); /* from/to */
1129 while (i >= ch_end) {
1134 memcpy(tmp + ch_sta, format, numlen);
1138 /* done with file### stuff */
1142 /* skip first two chars, which in case of
1143 absolute path will be drive:/blabla and
1144 in case of relpath //blabla/. So relpath
1145 // will be retained, rest will be nice and
1146 shiny win32 backward slashes :) -jesterKing
1148 BLI_char_switch(path+2, '/', '\\');
1154 /* copy di to fi, filename only */
1155 void BLI_splitdirstring(char *di, char *fi)
1157 char *lslash= BLI_last_slash(di);
1160 BLI_strncpy(fi, lslash+1, FILE_MAXFILE);
1163 BLI_strncpy(fi, di, FILE_MAXFILE);
1168 char *BLI_gethome(void) {
1170 return "/boot/home/"; /* BeOS 4.5: doubleclick at icon doesnt give home env */
1172 #elif !defined(WIN32)
1173 return getenv("HOME");
1177 static char dir[512];
1178 static char appdatapath[MAXPATHLEN];
1181 /* Check for %HOME% env var */
1183 ret = getenv("HOME");
1185 sprintf(dir, "%s\\.blender", ret);
1186 if (BLI_exists(dir)) return dir;
1189 /* else, check install dir (path containing blender.exe) */
1191 BLI_getInstallationDir(dir);
1193 if (BLI_exists(dir))
1195 strcat(dir,"\\.blender");
1196 if (BLI_exists(dir)) return(dir);
1200 /* add user profile support for WIN 2K / NT */
1201 hResult = SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatapath);
1203 if (hResult == S_OK)
1205 if (BLI_exists(appdatapath)) { /* from fop, also below... */
1206 sprintf(dir, "%s\\Blender Foundation\\Blender", appdatapath);
1207 BLI_recurdir_fileops(dir);
1208 if (BLI_exists(dir)) {
1209 strcat(dir,"\\.blender");
1210 if(BLI_exists(dir)) return(dir);
1213 hResult = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatapath);
1214 if (hResult == S_OK)
1216 if (BLI_exists(appdatapath))
1217 { /* from fop, also below... */
1218 sprintf(dir, "%s\\Blender Foundation\\Blender", appdatapath);
1219 BLI_recurdir_fileops(dir);
1220 if (BLI_exists(dir)) {
1221 strcat(dir,"\\.blender");
1222 if(BLI_exists(dir)) return(dir);
1228 ret = getenv("USERPROFILE");
1230 if (BLI_exists(ret)) { /* from fop, also below... */
1231 sprintf(dir, "%s\\Application Data\\Blender Foundation\\Blender", ret);
1232 BLI_recurdir_fileops(dir);
1233 if (BLI_exists(dir)) {
1234 strcat(dir,"\\.blender");
1235 if(BLI_exists(dir)) return(dir);
1242 Saving in the Windows dir is less than desirable.
1243 Use as a last resort ONLY! (aphex)
1246 ret = getenv("WINDOWS");
1248 if(BLI_exists(ret)) return ret;
1251 ret = getenv("WINDIR");
1253 if(BLI_exists(ret)) return ret;
1256 return "C:\\Temp"; /* sheesh! bad, bad, bad! (aphex) */
1260 void BLI_clean(char *path)
1264 if(path && strlen(path)>2) {
1265 BLI_char_switch(path+2, '/', '\\');
1268 BLI_char_switch(path, '\\', '/');
1272 void BLI_char_switch(char *string, char from, char to)
1274 if(string==0) return;
1275 while (*string != 0) {
1276 if (*string == from) *string = to;
1281 void BLI_make_exist(char *dir) {
1285 BLI_char_switch(dir, '/', '\\');
1287 BLI_char_switch(dir, '\\', '/');
1293 while(BLI_exists(dir) == 0){
1295 while(dir[a] != '\\'){
1299 if (a >= 0) dir[a+1] = 0;
1301 /* defaulting to drive (usually 'C:') of Windows installation */
1302 get_default_root(dir);
1307 while(BLI_exist(dir) == 0){
1309 while(dir[a] != '/'){
1313 if (a >= 0) dir[a+1] = 0;
1322 void BLI_make_existing_file(char *name)
1324 char di[FILE_MAXDIR], fi[FILE_MAXFILE];
1327 BLI_splitdirstring(di, fi);
1330 if (BLI_exists(di) == 0) {
1331 BLI_recurdir_fileops(di);
1336 void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file)
1340 if (!string || !dir || !file) return; /* We don't want any NULLs */
1342 string[0]= 0; /* ton */
1344 /* we first push all slashes into unix mode, just to make sure we don't get
1345 any mess with slashes later on. -jesterKing */
1346 /* constant strings can be passed for those parameters - don't change them - elubie */
1348 BLI_char_switch(relabase, '\\', '/');
1349 BLI_char_switch(dir, '\\', '/');
1350 BLI_char_switch(file, '\\', '/');
1353 /* Resolve relative references */
1354 if (relabase && dir[0] == '/' && dir[1] == '/') {
1357 /* Get the file name, chop everything past the last slash (ie. the filename) */
1358 strcpy(string, relabase);
1360 lslash= (strrchr(string, '/')>strrchr(string, '\\'))?strrchr(string, '/'):strrchr(string, '\\');
1362 if(lslash) *(lslash+1)= 0;
1364 dir+=2; /* Skip over the relative reference */
1368 if (strlen(dir) >= 2 && dir[1] == ':' ) {
1369 BLI_strncpy(string, dir, 3);
1372 else { /* no drive specified */
1373 /* first option: get the drive from the relabase if it has one */
1374 if (relabase && strlen(relabase) >= 2 && relabase[1] == ':' ) {
1375 BLI_strncpy(string, relabase, 3);
1379 else { /* we're out of luck here, guessing the first valid drive, usually c:\ */
1380 get_default_root(string);
1383 /* ignore leading slashes */
1384 while (*dir == '/' || *dir == '\\') dir++;
1389 strcat(string, dir);
1391 /* Make sure string ends in one (and only one) slash */
1392 /* first trim all slashes from the end of the string */
1393 sl = strlen(string);
1394 while (sl>0 && ( string[sl-1] == '/' || string[sl-1] == '\\') ) {
1395 string[sl-1] = '\0';
1398 /* since we've now removed all slashes, put back one slash at the end. */
1399 strcat(string, "/");
1401 while (*file && (*file == '/' || *file == '\\')) /* Trim slashes from the front of file */
1404 strcat (string, file);
1406 /* Push all slashes to the system preferred direction */
1410 int BLI_testextensie(const char *str, const char *ext)
1418 if(a==0 || b==0 || b>=a) {
1420 } else if (BLI_strcasecmp(ext, str + a - b)) {
1430 * This is a simple version of BLI_split_dirfile that has the following advantages...
1432 * Converts "/foo/bar.txt" to "/foo/" and "bar.txt"
1433 * - wont change 'string'
1434 * - wont create any directories
1435 * - dosnt use CWD, or deal with relative paths.
1436 * - Only fill's in *dir and *file when they are non NULL
1438 void BLI_split_dirfile_basic(const char *string, char *dir, char *file)
1440 int lslash=0, i = 0;
1441 for (i=0; string[i]!='\0'; i++) {
1442 if (string[i]=='\\' || string[i]=='/')
1447 BLI_strncpy( dir, string, lslash+1); /* +1 to include the slash and the last char */
1454 strcpy( file, string+lslash);
1460 * - May modify 'string' variable
1461 * - May create the directory if it dosnt exist
1462 * if this is not needed use BLI_split_dirfile_basic(...)
1464 void BLI_split_dirfile(char *string, char *dir, char *file)
1469 short is_relative = 0;
1470 char path[FILE_MAX];
1477 BLI_strncpy(path, string, FILE_MAX);
1478 BLI_char_switch(path, '/', '\\'); /* make sure we have a valid path format */
1482 if (path[0] == '/' || path[0] == '\\') {
1483 BLI_strncpy(dir, path, FILE_MAXDIR);
1484 if (sl > 1 && path[0] == '\\' && path[1] == '\\') is_relative = 1;
1485 } else if (sl > 2 && path[1] == ':' && path[2] == '\\') {
1486 BLI_strncpy(dir, path, FILE_MAXDIR);
1491 BLI_strncpy(path,dir,FILE_MAXDIR+FILE_MAXFILE);
1494 // BLI_exist doesn't recognize a slashed dirname as a dir
1495 // check if a trailing slash exists, and remove it. Do not do this
1496 // when we are already at root. -jesterKing
1498 if(a>=4 && dir[a-1]=='\\') dir[a-1] = 0;
1501 printf("WARNING: BLI_split_dirfile needs absolute dir\n");
1504 BLI_make_exist(dir);
1507 if (S_ISDIR(BLI_exist(dir))) {
1509 /* copy from end of string into file, to ensure filename itself isn't truncated
1510 if string is too long. (aphex) */
1512 len = FILE_MAXFILE - strlen(path);
1515 BLI_strncpy(file,path + abs(len),FILE_MAXFILE);
1517 BLI_strncpy(file,path,FILE_MAXFILE);
1519 if (strrchr(path,'\\')) {
1520 BLI_strncpy(file,strrchr(path,'\\')+1,FILE_MAXFILE);
1523 if ( (a = strlen(dir)) ) {
1524 if (dir[a-1] != '\\') strcat(dir,"\\");
1528 a = strlen(dir) - 1;
1529 while(a>0 && dir[a] != '\\') a--;
1531 BLI_strncpy(file, path + strlen(dir),FILE_MAXFILE);
1536 /* defaulting to first valid drive hoping it's not empty CD and DVD drives */
1537 get_default_root(dir);
1541 if (strlen(string)) {
1542 if (string[0] == '/') {
1543 strcpy(dir, string);
1544 } else if (string[1] == ':' && string[2] == '\\') {
1546 strcpy(dir, string);
1551 strcpy((char *)string,dir);
1554 BLI_make_exist(dir);
1556 if (S_ISDIR(BLI_exist(dir))) {
1557 strcpy(file,string + strlen(dir));
1559 if (strrchr(file,'/')) strcpy(file,strrchr(file,'/')+1);
1561 if ( (a = strlen(dir)) ) {
1562 if (dir[a-1] != '/') strcat(dir,"/");
1566 a = strlen(dir) - 1;
1567 while(dir[a] != '/') a--;
1569 strcpy(file, string + strlen(dir));
1580 /* simple appending of filename to dir, does not check for valid path! */
1581 void BLI_join_dirfile(char *string, const char *dir, const char *file)
1583 int sl_dir = strlen(dir);
1584 BLI_strncpy(string, dir, FILE_MAX);
1585 if (sl_dir > FILE_MAX-1) sl_dir = FILE_MAX-1;
1587 /* only add seperator if needed */
1589 if (string[sl_dir-1] != '\\') {
1590 string[sl_dir] = '\\';
1594 if (string[sl_dir-1] != '/') {
1595 string[sl_dir] = '/';
1600 if (sl_dir <FILE_MAX) {
1601 BLI_strncpy(string + sl_dir, file, FILE_MAX-sl_dir);
1605 static int add_win32_extension(char *name)
1610 type = BLI_exist(name);
1611 if ((type == 0) || S_ISDIR(type)) {
1613 char filename[FILE_MAXDIR+FILE_MAXFILE];
1614 char ext[FILE_MAXDIR+FILE_MAXFILE];
1615 char *extensions = getenv("PATHEXT");
1619 strcpy(filename, name);
1620 temp = strstr(extensions, ";");
1622 strncpy(ext, extensions, temp - extensions);
1623 ext[temp - extensions] = 0;
1624 extensions = temp + 1;
1625 strcat(filename, ext);
1627 strcat(filename, extensions);
1630 type = BLI_exist(filename);
1631 if (type && (! S_ISDIR(type))) {
1633 strcpy(name, filename);
1646 void BLI_where_am_i(char *fullname, const char *name)
1648 char filename[FILE_MAXDIR+FILE_MAXFILE];
1649 char *path = NULL, *temp;
1652 char *seperator = ";";
1655 char *seperator = ":";
1661 /* linux uses binreloc since argv[0] is not relyable, call br_init( NULL ) first */
1662 path = br_find_exe( NULL );
1664 strcpy(fullname, path);
1669 /* unix and non linux */
1670 if (name && fullname && strlen(name)) {
1671 strcpy(fullname, name);
1672 if (name[0] == '.') {
1673 // relative path, prepend cwd
1674 BLI_getwdN(fullname);
1675 len = strlen(fullname);
1676 if (len && fullname[len -1] != slash[0]) {
1677 strcat(fullname, slash);
1679 strcat(fullname, name);
1680 add_win32_extension(fullname);
1681 } else if (BLI_last_slash(name)) {
1683 strcpy(fullname, name);
1684 add_win32_extension(fullname);
1686 // search for binary in $PATH
1687 path = getenv("PATH");
1690 temp = strstr(path, seperator);
1692 strncpy(filename, path, temp - path);
1693 filename[temp - path] = 0;
1696 strncpy(filename, path, sizeof(filename));
1698 len = strlen(filename);
1699 if (len && filename[len - 1] != slash[0]) {
1700 strcat(filename, slash);
1702 strcat(filename, name);
1703 if (add_win32_extension(filename)) {
1704 strcpy(fullname, filename);
1711 if (strcmp(name, fullname)) {
1712 printf("guessing '%s' == '%s'\n", name, fullname);
1717 // in windows change long filename to short filename because
1718 // win2k doesn't know how to parse a commandline with lots of
1719 // spaces and double-quotes. There's another solution to this
1720 // with spawnv(P_WAIT, bprogname, argv) instead of system() but
1721 // that's even uglier
1722 GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
1724 printf("Shortname = '%s'\n", fullname);
1730 void BLI_where_is_temp(char *fullname, int usertemp)
1734 if (usertemp && BLI_exists(U.tempdir)) {
1735 strcpy(fullname, U.tempdir);
1740 if (fullname[0] == '\0') {
1741 char *tmp = getenv("TEMP"); /* Windows */
1742 if (tmp && BLI_exists(tmp)) {
1743 strcpy(fullname, tmp);
1747 /* Other OS's - Try TMP and TMPDIR */
1748 if (fullname[0] == '\0') {
1749 char *tmp = getenv("TMP");
1750 if (tmp && BLI_exists(tmp)) {
1751 strcpy(fullname, tmp);
1755 if (fullname[0] == '\0') {
1756 char *tmp = getenv("TMPDIR");
1757 if (tmp && BLI_exists(tmp)) {
1758 strcpy(fullname, tmp);
1763 if (fullname[0] == '\0') {
1764 strcpy(fullname, "/tmp/");
1766 /* add a trailing slash if needed */
1767 BLI_add_slash(fullname);
1772 * returns absolute path to the app bundle
1773 * only useful on OS X
1776 char* BLI_getbundle(void) {
1778 CFStringRef pathStr;
1779 static char path[MAXPATHLEN];
1780 CFBundleRef mainBundle = CFBundleGetMainBundle();
1782 bundleURL = CFBundleCopyBundleURL(mainBundle);
1783 pathStr = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
1784 CFStringGetCString(pathStr, path, MAXPATHLEN, kCFStringEncodingASCII);
1789 /* strcasestr not available in MSVC */
1790 char *BLI_strcasestr(const char *s, const char *find)
1792 register char c, sc;
1793 register size_t len;
1795 if ((c = *find++) != 0) {
1800 if ((sc = *s++) == 0)
1804 } while (BLI_strncasecmp(s, find, len) != 0);
1807 return ((char *) s);
1811 int BLI_strcasecmp(const char *s1, const char *s2) {
1815 char c1 = tolower(s1[i]);
1816 char c2 = tolower(s2[i]);
1830 int BLI_strncasecmp(const char *s1, const char *s2, int n) {
1833 for (i=0; i<n; i++) {
1834 char c1 = tolower(s1[i]);
1835 char c2 = tolower(s2[i]);
1852 #include "localcharset.h"
1854 void BLI_string_to_utf8(char *original, char *utf_8, char *code)
1856 size_t inbytesleft=strlen(original);
1857 size_t outbytesleft=512;
1862 code = locale_charset();
1864 cd=iconv_open("UTF-8", code);
1866 if (cd == (iconv_t)(-1)) {
1867 printf("iconv_open Error");
1871 rv=iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft);
1872 if (rv == (size_t) -1) {
1873 printf("iconv Error\n");
1879 #endif // WITH_ICONV
1881 void BLI_timestr(double _time, char *str)
1883 /* format 00:00:00.00 (hr:min:sec) string has to be 12 long */
1884 int hr= ( (int) _time) / (60*60);
1885 int min= (((int) _time) / 60 ) % 60;
1886 int sec= ( (int) (_time)) % 60;
1887 int hun= ( (int) (_time * 100.0)) % 100;
1890 sprintf(str, "%.2d:%.2d:%.2d.%.2d",hr,min,sec,hun);
1892 sprintf(str, "%.2d:%.2d.%.2d",min,sec,hun);
1898 /* ************** 64 bits magic, trick to support up to 32 gig of address space *************** */
1899 /* only works for malloced pointers (8 aligned) */
1903 #if defined(WIN32) && !defined(FREE_WINDOWS)
1904 #define PMASK 0x07FFFFFFFFi64
1906 #define PMASK 0x07FFFFFFFFll
1910 int BLI_int_from_pointer(void *poin)
1912 long lval= (long)poin;
1914 return (int)(lval>>3);
1917 void *BLI_pointer_from_int(int val)
1919 static int firsttime= 1;
1920 static long basevalue= 0;
1923 void *poin= malloc(10000);
1924 basevalue= (long)poin;
1925 basevalue &= ~PMASK;
1926 printf("base: %d pointer %p\n", basevalue, poin); /* debug */
1930 return (void *)(basevalue | (((long)val)<<3));
1935 int BLI_int_from_pointer(void *poin)
1939 void *BLI_pointer_from_int(int val)