3 * various string, file, list operations.
8 * ***** BEGIN GPL/BL DUAL 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. 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
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.
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.
27 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
28 * All rights reserved.
30 * The Original Code is: all of this file.
32 * Contributor(s): none yet.
34 * ***** END GPL/BL DUAL LICENSE BLOCK *****
44 #include "MEM_guardedalloc.h"
46 #include "BLI_blenlib.h"
47 #include "DNA_listBase.h"
48 #include "BLI_storage.h"
49 #include "BLI_storage_types.h"
64 #include "BLI_winstuff.h"
73 #include <sys/param.h>
74 #include <CoreFoundation/CoreFoundation.h>
79 static int add_win32_extension(char *name);
83 /* Ripped this from blender.c
85 void addlisttolist(ListBase *list1, ListBase *list2)
88 if(list2->first==0) return;
91 list1->first= list2->first;
92 list1->last= list2->last;
95 ((struct Link *)list1->last)->next= list2->first;
96 ((struct Link *)list2->first)->prev= list1->last;
97 list1->last= list2->last;
99 list2->first= list2->last= 0;
102 int BLI_stringdec(char *string, char *kop, char *staart, unsigned short *numlen)
104 unsigned short len, len2, nums = 0, nume = 0;
107 len2 = len = strlen( string);
110 if (strncasecmp(string + len - 6, ".blend", 6) == 0) len -= 6;
111 else if (strncasecmp(string + len - 6, ".trace", 6) == 0) len -= 6;
116 /* handle .jf0 en .jf1 for jstreams */
117 if (strncasecmp(string + len - 4, ".jf", 3) == 0) len -= 4;
118 else if (strncasecmp(string + len - 4, ".tga", 4) == 0) len -= 4;
119 else if (strncasecmp(string + len - 4, ".jpg", 4) == 0) len -= 4;
120 else if (strncasecmp(string + len - 4, ".png", 4) == 0) len -= 4;
121 else if (strncasecmp(string + len - 4, ".txt", 4) == 0) len -= 4;
122 else if (strncasecmp(string + len - 4, ".cyc", 4) == 0) len -= 4;
123 else if (strncasecmp(string + len - 4, ".enh", 4) == 0) len -= 4;
124 else if (strncasecmp(string + len - 4, ".rgb", 4) == 0) len -= 4;
125 else if (strncasecmp(string + len - 4, ".psx", 4) == 0) len -= 4;
126 else if (strncasecmp(string + len - 4, ".ble", 4) == 0) len -= 4;
130 for (i = len - 1; i >= 0; i--){
131 if (string[i] == '/') break;
132 if (isdigit(string[i])) {
147 if (staart) strcpy(staart,&string[nume+1]);
152 if (numlen) *numlen = nume-nums+1;
153 return ((int)atoi(&(string[nums])));
155 if (staart) strcpy(staart, string + len);
157 strncpy(kop, string, len);
160 if (numlen) *numlen=0;
165 void BLI_stringenc(char *string, char *kop, char *staart, unsigned short numlen, int pic)
168 unsigned short len,i;
172 if (pic>0 || numlen==4) {
173 len= sprintf(numstr,"%d",pic);
175 for(i=len;i<numlen;i++){
178 strcat(string,numstr);
180 strcat(string,staart);
184 void BLI_newname(char * name, int add)
186 char head[128], tail[128];
188 unsigned short digits;
190 pic = BLI_stringdec(name, head, tail, &digits);
192 /* are we going from 100 -> 99 or from 10 -> 9 */
193 if (add < 0 && digits < 4 && digits > 0) {
196 for (i = digits; i > 1; i--) exp *= 10;
197 if (pic >= exp && (pic + add) < exp) digits--;
202 if(digits==4 && pic<0) pic= 0;
203 BLI_stringenc(name, head, tail, digits, pic);
207 void BLI_addhead(ListBase *listbase, void *vlink)
209 struct Link *link= vlink;
211 if (link == 0) return;
212 if (listbase == 0) return;
214 link->next = listbase->first;
217 if (listbase->first) ((struct Link *)listbase->first)->prev = link;
218 if (listbase->last == 0) listbase->last = link;
219 listbase->first = link;
223 void BLI_addtail(ListBase *listbase, void *vlink)
225 struct Link *link= vlink;
227 if (link == 0) return;
228 if (listbase == 0) return;
231 link->prev = listbase->last;
233 if (listbase->last) ((struct Link *)listbase->last)->next = link;
234 if (listbase->first == 0) listbase->first = link;
235 listbase->last = link;
239 void BLI_remlink(ListBase *listbase, void *vlink)
241 struct Link *link= vlink;
243 if (link == 0) return;
244 if (listbase == 0) return;
246 if (link->next) link->next->prev = link->prev;
247 if (link->prev) link->prev->next = link->next;
249 if (listbase->last == link) listbase->last = link->prev;
250 if (listbase->first == link) listbase->first = link->next;
254 void BLI_freelinkN(ListBase *listbase, void *vlink)
256 struct Link *link= vlink;
258 if (link == 0) return;
259 if (listbase == 0) return;
261 BLI_remlink(listbase,link);
266 void BLI_insertlink(ListBase *listbase, void *vprevlink, void *vnewlink)
268 struct Link *prevlink= vprevlink, *newlink= vnewlink;
270 /* newlink comes after prevlink */
272 if (newlink == 0) return;
273 if (listbase == 0) return;
275 if(listbase->first==0) { /* empty list */
276 listbase->first= newlink;
277 listbase->last= newlink;
280 if (prevlink== 0) { /* insert before first element */
281 newlink->next= listbase->first;
283 newlink->next->prev= newlink;
284 listbase->first= newlink;
288 if (listbase->last== prevlink) /* at end of list */
289 listbase->last = newlink;
291 newlink->next= prevlink->next;
292 prevlink->next= newlink;
293 if(newlink->next) newlink->next->prev= newlink;
294 newlink->prev= prevlink;
297 void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
299 struct Link *nextlink= vnextlink, *newlink= vnewlink;
301 /* newlink before nextlink */
303 if (newlink == 0) return;
304 if (listbase == 0) return;
306 if(listbase->first==0) { /* empty list */
307 listbase->first= newlink;
308 listbase->last= newlink;
311 if (nextlink== 0) { /* insert at end of list */
312 newlink->prev= listbase->last;
314 ((struct Link *)listbase->last)->next= newlink;
315 listbase->last= newlink;
319 if (listbase->first== nextlink) /* at beginning of list */
320 listbase->first = newlink;
322 newlink->next= nextlink;
323 newlink->prev= nextlink->prev;
324 nextlink->prev= newlink;
325 if(newlink->prev) newlink->prev->next= newlink;
329 void BLI_freelist(ListBase *listbase)
331 struct Link *link,*next;
333 if (listbase == 0) return;
334 link= listbase->first;
344 void BLI_freelistN(ListBase *listbase)
346 struct Link *link,*next;
348 if (listbase == 0) return;
349 link= listbase->first;
360 int BLI_countlist(ListBase *listbase)
366 link = listbase->first;
375 void * BLI_findlink(ListBase *listbase, int number)
380 link = listbase->first;
381 while (link != NULL && number != 0) {
391 char *BLI_strdupn(char *str, int len) {
392 char *n= MEM_mallocN(len+1, "strdup");
398 char *BLI_strdup(char *str) {
399 return BLI_strdupn(str, strlen(str));
402 char *BLI_strncpy(char *dst, char *src, int maxncpy) {
403 int srclen= strlen(src);
404 int cpylen= (srclen>(maxncpy-1))?(maxncpy-1):srclen;
406 memcpy(dst, src, cpylen);
412 int BLI_streq(char *a, char *b) {
413 return (strcmp(a, b)==0);
415 int BLI_strcaseeq(char *a, char *b) {
416 return (strcasecmp(a, b)==0);
419 void BLI_makestringcode(char *fromfile, char *str)
421 char *slash, len, temp[512];
423 strcpy(temp, fromfile);
425 /* Find the last slash */
426 slash = (strrchr(temp, '/')>strrchr(temp, '\\'))
427 ? strrchr(temp, '/') : strrchr(temp, '\\');
432 if(strncmp(str, temp, len)==0) {
435 strcpy(temp+2, str+len);
442 int BLI_convertstringcode(char *path, char *basepath, int framenum)
444 int len, wasrelative= (strncmp(path, "//", 2)==0);
446 if (path[0] == '/' && path[1] == '/') {
447 char *filepart= BLI_strdup(path+2); /* skip code */
448 char *lslash= BLI_last_slash(basepath);
451 int baselen= (int) (lslash-basepath) + 1;
453 memcpy(path, basepath, baselen);
454 strcpy(path+baselen, filepart);
456 strcpy(path, filepart);
463 if(len && path[len-1]=='#') {
464 sprintf(path+len-1, "%04d", framenum);
470 void BLI_splitdirstring(char *di,char *fi)
472 char *lslash= BLI_last_slash(di);
475 strcpy(fi, lslash+1);
483 char *BLI_gethome(void) {
486 return "/boot/home/"; /* BeOS 4.5: doubleclick at icon doesnt give home env */
488 #elif !defined(WIN32)
489 return getenv("HOME");
493 static char dir[512];
496 ret = getenv("HOME");
498 if (BLI_exists(ret)) return ret;
502 "change-over" period - blender still checks in
503 old locations, but Ctrl+U now saves in ~/.blender
506 BLI_getInstallationDir(dir);
510 strcat(dir,"/.blender");
511 if (BLI_exists(dir)) return(dir);
515 everything below this point to be removed -
516 blender should use the same %HOME% across
517 all versions of Windows... (aphex)
520 /* add user profile support for WIN 2K / NT */
521 ret = getenv("USERPROFILE");
523 if (BLI_exists(ret)) { /* from fop, also below... */
524 sprintf(dir, "%s/Application Data/Not a Number/Blender", ret);
525 BLI_recurdir_fileops(dir);
526 if (BLI_exists(dir)) {
535 Saving in the Windows dir is less than desirable.
536 Use as a last resort ONLY! (aphex)
539 ret = getenv("WINDOWS");
541 if(BLI_exists(ret)) return ret;
544 ret = getenv("WINDIR");
546 if(BLI_exists(ret)) return ret;
549 return "C:\\Temp"; /* sheesh! bad, bad, bad! (aphex) */
553 static void char_switch(char *string, char from, char to)
555 while (*string != 0) {
556 if (*string == from) *string = to;
561 void BLI_make_exist(char *dir)
566 char_switch(dir, '/', '\\');
568 char_switch(dir, '\\', '/');
574 while(BLI_exists(dir) == 0){
576 while(dir[a] != '\\'){
580 if (a >= 0) dir[a+1] = 0;
587 while(BLI_exist(dir) == 0){
589 while(dir[a] != '/'){
593 if (a >= 0) dir[a+1] = 0;
602 void BLI_make_file_string(char *relabase, char *string, char *dir, char *file)
605 if (!string || !dir || !file) return; /* We don't want any NULLs */
607 string[0]= 0; /* ton */
609 /* Resolve relative references */
610 if (relabase && dir[0] == '/' && dir[1] == '/') {
613 /* Get the file name, chop everything past the last slash (ie. the filename) */
614 strcpy(string, relabase);
616 lslash= (strrchr(string, '/')>strrchr(string, '\\'))?strrchr(string, '/'):strrchr(string, '\\');
618 if(lslash) *(lslash+1)= 0;
620 dir+=2; /* Skip over the relative reference */
625 /* Make sure string ends in one (and only one) slash */
626 if (string[strlen(string)-1] != '/' && string[strlen(string)-1] != '\\')
629 while (*file && (*file == '/' || *file == '\\')) /* Trim slashes from the front of file */
632 strcat (string, file);
634 /* Push all slashes to the system preferred direction */
636 char_switch(string, '/', '\\');
638 char_switch(string, '\\', '/');
642 int BLI_testextensie(char *str, char *ext)
650 if(a==0 || b==0 || b>=a) {
652 } else if (strcasecmp(ext, str + a - b)) {
661 void BLI_split_dirfile(char *string, char *dir, char *file)
669 if (strlen(string)) {
670 if (string[0] == '/' || string[0] == '\\') {
672 } else if (string[1] == ':' && string[2] == '\\') {
683 // BLI_exist doesn't recognize a slashed dirname as a dir
684 // check if a trailing slash exists, and remove it. Do not do this
685 // when we are already at root. -jesterKing
687 if(a>=4 && dir[a-1]=='\\') dir[a-1] = 0;
689 if (S_ISDIR(BLI_exist(dir))) {
690 strcpy(file,string + strlen(dir));
692 if (strrchr(file,'\\')) strcpy(file,strrchr(file,'\\')+1);
694 if (a = strlen(dir)) {
695 if (dir[a-1] != '\\') strcat(dir,"\\");
700 while(a>0 && dir[a] != '\\') a--;
702 strcpy(file, string + strlen(dir));
711 if (strlen(string)) {
712 if (string[0] == '/') {
714 } else if (string[1] == ':' && string[2] == '\\') {
726 if (S_ISDIR(BLI_exist(dir))) {
727 strcpy(file,string + strlen(dir));
729 if (strrchr(file,'/')) strcpy(file,strrchr(file,'/')+1);
731 if ( (a = strlen(dir)) ) {
732 if (dir[a-1] != '/') strcat(dir,"/");
737 while(dir[a] != '/') a--;
739 strcpy(file, string + strlen(dir));
750 // copies from BKE_utildefines
752 #define FILE_MAXDIR 160
756 #define FILE_MAXFILE 80
759 static int add_win32_extension(char *name)
764 type = BLI_exist(name);
765 if ((type == 0) || S_ISDIR(type)) {
767 char filename[FILE_MAXDIR+FILE_MAXFILE];
768 char ext[FILE_MAXDIR+FILE_MAXFILE];
769 char *extensions = getenv("PATHEXT");
773 strcpy(filename, name);
774 temp = strstr(extensions, ";");
776 strncpy(ext, extensions, temp - extensions);
777 ext[temp - extensions] = 0;
778 extensions = temp + 1;
779 strcat(filename, ext);
781 strcat(filename, extensions);
784 type = BLI_exist(filename);
785 if (type && (! S_ISDIR(type))) {
787 strcpy(name, filename);
800 void BLI_where_am_i(char *fullname, char *name)
802 char filename[FILE_MAXDIR+FILE_MAXFILE];
806 char *seperator = ";";
809 char *seperator = ":";
813 if (name && fullname && strlen(name)) {
814 strcpy(fullname, name);
815 if (name[0] == '.') {
816 // relative path, prepend cwd
817 BLI_getwdN(fullname);
818 len = strlen(fullname);
819 if (len && fullname[len -1] != slash[0]) {
820 strcat(fullname, slash);
822 strcat(fullname, name);
823 add_win32_extension(fullname);
824 } else if (BLI_last_slash(name)) {
826 strcpy(fullname, name);
827 add_win32_extension(fullname);
829 // search for binary in $PATH
830 path = getenv("PATH");
833 temp = strstr(path, seperator);
835 strncpy(filename, path, temp - path);
836 filename[temp - path] = 0;
839 strncpy(filename, path, sizeof(filename));
841 len = strlen(filename);
842 if (len && filename[len - 1] != slash[0]) {
843 strcat(filename, slash);
845 strcat(filename, name);
846 if (add_win32_extension(filename)) {
847 strcpy(fullname, filename);
854 if (strcmp(name, fullname)) {
855 printf("guessing '%s' == '%s'\n", name, fullname);
860 // in windows change long filename to short filename because
861 // win2k doesn't know how to parse a commandline with lots of
862 // spaces and double-quotes. There's another solution to this
863 // with spawnv(P_WAIT, bprogname, argv) instead of system() but
864 // that's even uglier
865 GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
867 printf("Shortname = '%s'\n", fullname);
874 * returns absolute path to the app bundle
875 * only useful on OS X
878 char* BLI_getbundle(void) {
881 char path[MAXPATHLEN];
882 CFBundleRef mainBundle = CFBundleGetMainBundle();
884 bundleURL = CFBundleCopyBundleURL(mainBundle);
885 pathStr = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
886 CFStringGetCString(pathStr, path, MAXPATHLEN, kCFStringEncodingASCII);