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