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