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