1 /*****************************************************************************
2    Major portions of this software are copyrighted by the Medical College
3    of Wisconsin, 1994-2000, and are released under the Gnu General Public
4    License, Version 2.  See the file README.Copyright for details.
5 ******************************************************************************/
6 
7 #include <pwd.h>
8 #include "mrilib.h"
9 #include "thd.h"
10 
11 /*-------------------------------------------------------------*/
12 /*! Return the time at which the file was last modified. */
13 
THD_file_mtime(char * pathname)14 time_t THD_file_mtime( char *pathname )  /* 05 Dec 2001 */
15 {
16    static struct stat buf ; int ii ;
17 
18    if( pathname == NULL || *pathname == '\0' ) return 0 ;
19    ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ;
20    return (time_t)buf.st_mtime ;
21 }
22 
23 /*-----------------------------------------------------------*/
24 /*! Determine if this exists at all (file, directory, ...). */
25 
THD_is_ondisk(char * pathname)26 int THD_is_ondisk( char *pathname )  /* 19 Dec 2002 */
27 {
28    static struct stat buf ; int ii ;
29 
30    if( pathname == NULL || *pathname == '\0' ) return 0 ;
31    ii = stat( pathname , &buf ) ;
32    return (ii == 0) ;
33 }
34 
35 /*-----------------------------------------------------------*/
36 /*! Determine if a prefix is that of a dset on disk. */
37 
THD_is_prefix_ondisk(char * pathname,int stripsels)38 int THD_is_prefix_ondisk( char *pathname, int stripsels)
39 {
40    int ii, open1, open2, open3, open4;
41    char *ppp=pathname;
42 
43    if (!pathname) return(0);
44 
45    if (stripsels) {
46       ppp = strdup(pathname);
47       open1 = open2 = open3 = open4 = 0;
48       for (ii=strlen(ppp)-1; ii>=0; --ii) {
49               if (ppp[ii] == ']' && !open1) open1=1;
50          else if (ppp[ii] == '[' &&  open1) ppp[ii] = '\0';
51          else if (ppp[ii] == '>' && !open2) open2=1;
52          else if (ppp[ii] == '<' &&  open2) ppp[ii] = '\0';
53          else if (ppp[ii] == '}' && !open3) open3=1;
54          else if (ppp[ii] == '{' &&  open3) ppp[ii] = '\0';
55          else if (ppp[ii] == '#' && !open4) open4=1;
56          else if (ppp[ii] == '#' &&  open4) ppp[ii] = '\0';
57       }
58    }
59 
60    if (THD_is_directory(ppp)) { if (ppp!=pathname) free(ppp); return(0); }
61    if (THD_is_ondisk(ppp)) { if (ppp!=pathname) free(ppp); return (1); }
62    ii = THD_is_dataset(THD_filepath(ppp), THD_trailname(ppp,0), -1);
63    if (ii ==-1) { if (ppp!=pathname) free(ppp); return(0); }
64    else { if (ppp!=pathname) free(ppp); return(1); }
65 }
66 
67 /*-----------------------------------------------------------*/
68 /*! Change working directory. */
69 
THD_cwd(char * pathname)70 int THD_cwd( char *pathname )    /* 19 Dec 2002 */
71 {
72    if( pathname == NULL || *pathname == '\0' ) return 0 ;
73    return ( chdir(pathname) == 0 ) ;
74 }
75 
76 /*-----------------------------------------------------------*/
77 /*! Create a directory.  Returns 1 if OK, 0 if not. */
78 
THD_mkdir(char * pathname)79 int THD_mkdir( char *pathname )  /* 19 Dec 2002 */
80 {
81    int lp , ii , jj ;
82    char *pnam ;
83 
84    /* check if input is OK, or if it already exists */
85 
86    if( !THD_filename_ok(pathname) ) return 0 ;
87    if(  THD_is_ondisk  (pathname) ) return THD_is_directory(pathname) ;
88 
89    pnam = strdup(pathname) ;  /* modifiable copy */
90    lp = strlen(pnam) ; ii = 0 ;
91 
92    /* loop over path segments, creating them if needed */
93 
94    while(1){
95 
96      /* advance ii to point to end of next path segment,
97         at the next '/' character, or at the end of pnam */
98 
99      ii += strspn(pnam+ii,"/") ; ii += strcspn(pnam+ii,"/") ;
100 
101      /* insert a NUL to replace the '/', temporarily */
102 
103      if( ii < lp ) pnam[ii] = '\0' ;
104 
105      /* if this segment doesn't already exist, create it */
106 
107      if( !THD_is_directory(pnam) ){
108        jj = mkdir( pnam , 0755 ) ;
109        if( jj != 0 ){ free(pnam); return 0; } /* bad */
110      }
111 
112      /* if reached end of path string, we're done */
113 
114      if( ii == lp ){ free(pnam); return 1; }  /* good */
115 
116      /* reinsert '/' if it was excised */
117 
118      pnam[ii] = '/' ;
119    }
120 
121    return 0 ; /* unreachable */
122 }
123 
124 /*-----------------------------------------------------------*/
125 /*! Determine if this is really a regular file or not. */
126 
THD_is_file(char * pathname)127 int THD_is_file( char *pathname )
128 {
129    static struct stat buf ; int ii ;
130 
131    if( pathname == NULL || *pathname == '\0' ) return 0 ;
132    ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ;
133    ii = (buf.st_mode & S_IFREG) != 0 ; return ii ;
134 }
135 
136 /*-----------------------------------------------------------*/
137 /*! Determine if this is a FIFO or not. [27 Aug 2019] */
138 
THD_is_fifo(char * pathname)139 int THD_is_fifo( char *pathname )
140 {
141    static struct stat buf ; int ii ;
142 
143    if( pathname == NULL || *pathname == '\0' ) return 0 ;
144    ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ;
145    ii = (buf.st_mode & S_IFIFO) != 0 ; return ii ;
146 }
147 
148 /*------------------------------------------------------------*/
149 /*! Determine if this is really a symbolic link or not. */
150 
THD_is_symlink(char * pathname)151 int THD_is_symlink( char *pathname )  /* 03 Mar 1999 */
152 {
153    char buf[32] ; int ii ;
154 
155    if( pathname == NULL || *pathname == '\0' ) return 0 ;
156    ii = readlink( pathname , buf , 32 ) ;
157    return (ii > 0) ;
158 }
159 
160 /*-------------------------------------------------------*/
161 /*! Return the file length (0 if file not found). */
162 
THD_filesize(char * pathname)163 long long THD_filesize( char *pathname )
164 {
165    static struct stat buf ; int ii ;
166 
167    if( pathname == NULL || *pathname == '\0' ) return 0 ;
168    ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ;
169    return (long long)buf.st_size ;
170 }
171 
172 /*-------------------------------------------------------*/
173 /*! Return the file's last modified date in a string     */
174 
THD_filetime(char * pathname)175 char *THD_filetime( char *pathname )
176 {
177    static struct stat buf ; int ii ;
178    static char sout[10][64];
179    static int icall=0;
180    static struct tm *lt=NULL ;
181 
182    ++icall; if (icall > 9) icall=0;
183    sout[icall][0]='\0';
184 
185    if( pathname == NULL || *pathname == '\0' ) return (sout[icall]);
186    ii = stat( pathname , &buf ) ; if( ii != 0 ) return (sout[icall]) ;
187 
188    lt = localtime(&buf.st_mtime);
189    sprintf(sout[icall], "%04d_%02d_%02d-%02d_%02d_%02d",
190             lt->tm_year+1900, lt->tm_mon+1, lt->tm_mday,
191             lt->tm_hour, lt->tm_min, lt->tm_sec);
192 
193    return (sout[icall]) ;
194 }
195 
196 /*-------------------------------------------------------*/
197 /*! Compare file's last modified date to reference
198     -1 file modification predates the specified day
199      0 same as specified day
200      1 newer
201      2 for error in input or file not found              */
202 
THD_filetime_diff(char * pathname,int year,int month,int day)203 int THD_filetime_diff( char *pathname,
204                        int year, int month, int day  )
205 {
206    static struct stat buf ; int ii ;
207    static struct tm *lt=NULL ;
208    int fday, Dday = year*10000+month*100+day;
209 
210    if( pathname == NULL || *pathname == '\0' ) return (2);
211    ii = stat( pathname , &buf ) ; if( ii != 0 ) return (2) ;
212 
213    lt = localtime(&buf.st_mtime);
214    fday = (lt->tm_year+1900)*10000+(lt->tm_mon+1)*100+lt->tm_mday;
215    if (Dday > fday) return(-1);
216    else if (Dday < fday) return(1);
217    else return(0);
218 }
219 
220 
THD_homedir(byte withslash)221 char *THD_homedir(byte withslash)
222 {
223    static char sout[3][520];
224    static int icall=0;
225    char *home=NULL;
226    int nn=0;
227    struct passwd *pw = NULL;
228 
229    ++icall; if (icall>2) icall=0;
230    sout[icall][0]='\0';
231 
232    home = getenv("HOME");
233    if (!home) {
234       pw = getpwuid(getuid());
235       if (pw) home = (char *)pw->pw_dir;
236    }
237    if (home) {
238       if (strlen(home) > 510) {
239          ERROR_message("Not enough space to store home dir of '%s'.\n");
240       } else {
241          sprintf(sout[icall], "%s", home);
242       }
243    }
244 
245    /* remove slash */
246    while ( (nn=strlen(sout[icall])-1) && sout[icall][nn] == '/')
247       sout[icall][nn] = '\0';
248 
249    if (withslash) {
250       nn=strlen(sout[icall]);
251       sout[icall][nn] = '/'; sout[icall][nn+1] = '\0';
252    }
253 
254    return (sout[icall]) ;
255 }
256 
THD_afnirc(void)257 char *THD_afnirc(void)
258 {
259    static char sout[3][520];
260    static int icall=0;
261 
262    ++icall; if (icall>2) icall=0;
263    sout[icall][0]='\0';
264 
265    strcpy(sout[icall],THD_homedir(1));
266    strcat(sout[icall],".afnirc");
267    return(sout[icall]);
268 }
269 
THD_custom_atlas_dir(byte withslash)270 char *THD_custom_atlas_dir(byte withslash)
271 {
272    static char sout[3][520];
273    static int icall=0;
274    char *home=NULL;
275    int nn=0;
276 /*   struct passwd *pw = NULL;*/
277 
278    ++icall; if (icall>2) icall=0;
279    sout[icall][0]='\0';
280 
281    if (!(home = getenv("AFNI_SUPP_ATLAS_DIR"))) {
282       return(sout[icall]);
283    }
284 
285    if (strlen(home) > 510) {
286       ERROR_message("Not enough space to store AFNI_SUPP_ATLAS_DIR dir of '%s'.\n");
287    } else {
288       sprintf(sout[icall], "%s", home);
289    }
290 
291    /* remove slash */
292    while ( (nn=strlen(sout[icall])-1)>=0 && sout[icall][nn] == '/')
293       sout[icall][nn] = '\0';
294 
295    if (withslash) {
296       nn=strlen(sout[icall]);
297       sout[icall][nn] = '/'; sout[icall][nn+1] = '\0';
298    }
299 
300    return (sout[icall]) ;
301 }
302 
303 /* retrieve custom atlas directory and make sure it is present
304    Do not free returned pointer. Failure is a NULL pointer */
THD_get_custom_atlas_dir(byte withslash)305 char *THD_get_custom_atlas_dir(byte withslash)
306 {
307    char *cadir = NULL;
308    cadir = THD_custom_atlas_dir(withslash);
309    if (cadir[0] == '\0') {
310       ERROR_message("Have no custom atlas directory\n");
311       return(NULL);
312    }
313    if (!THD_mkdir(cadir)) {
314       ERROR_message("Cannot create %s directory\n", cadir);
315       return(NULL);
316    }
317    return(cadir);
318 }
319 
THD_custom_atlas_file(char * name)320 char *THD_custom_atlas_file(char *name)
321 {
322    static char sout[3][1024];
323    static int icall=0;
324 /*   struct passwd *pw = NULL;*/
325 
326    ++icall; if (icall>2) icall=0;
327    sout[icall][0]='\0';
328 
329    if (!name) name = getenv("AFNI_SUPP_ATLAS");
330    if (name) {
331       if (THD_is_file(name)) {
332          snprintf(sout[icall], 1020*sizeof(char),"%s",name);
333          return (sout[icall]) ;
334       } else {
335          snprintf(sout[icall], 1020*sizeof(char),
336                         "%s/%s",THD_custom_atlas_dir(0),name);
337          if (!THD_is_file(sout[icall])) {
338             ERROR_message("Supp atlas file %s not found", name);
339          }
340          return (sout[icall]) ;
341       }
342    }
343    /* no name, try default */
344    name = "CustomAtlases.niml";
345    if (THD_is_file(name)) {
346          snprintf(sout[icall], 1020*sizeof(char),"%s",name);
347          return (sout[icall]) ;
348    } else {
349       snprintf(sout[icall], 1020*sizeof(char),
350                      "%s/%s",THD_custom_atlas_dir(0),name);
351       if (THD_is_file(sout[icall])) {
352          return (sout[icall]) ;
353       } else {
354          sout[icall][0]='\0';
355          return (sout[icall]) ;
356       }
357    }
358 
359    return (sout[icall]) ;
360 }
361 
362 /* Return the name of the help directory, no guarantee that it exists
363    Consider THD_get_helpdir()
364    Do not free returned pointer. Failure results in an empty string.
365 */
THD_helpdir(byte withslash)366 char *THD_helpdir(byte withslash)
367 {
368    static char sout[3][610];
369    static int icall=0;
370    char *home=NULL;
371 
372    ++icall; if (icall>2) icall=0;
373 
374    sout[icall][0]='\0';
375 
376    home = THD_homedir(0);
377    if (home[0]=='\0') return(sout[icall]);
378 
379    if (withslash) snprintf(sout[icall],600*sizeof(char),"%s/.afni/help/",home);
380    else snprintf(sout[icall],599*sizeof(char),"%s/.afni/help",home);
381 
382    return (sout[icall]) ;
383 }
384 
385 /* Return the name of the data directory, no guarantee that it exists
386    Consider THD_get_datadir()
387    Do not free returned pointer. Failure results in an empty string.
388 */
THD_datadir(byte withslash)389 char *THD_datadir(byte withslash)
390 {
391    static char sout[3][610];
392    static int icall=0;
393    char *home=NULL;
394 
395    ++icall; if (icall>2) icall=0;
396 
397    sout[icall][0]='\0';
398 
399    home = THD_homedir(0);
400    if (home[0]=='\0') return(sout[icall]);
401 
402    if (withslash) snprintf(sout[icall],600*sizeof(char),"%s/.afni/data/",home);
403    else snprintf(sout[icall],599*sizeof(char),"%s/.afni/data",home);
404 
405    return (sout[icall]) ;
406 }
407 
408 /* retrieve help directory and make sure it is present
409    Do not free returned pointer. Failure is a NULL pointer */
THD_get_helpdir(byte withslash)410 char *THD_get_helpdir(byte withslash)
411 {
412    char *hdir = NULL;
413    hdir = THD_helpdir(withslash);
414    if (hdir[0] == '\0') {
415       ERROR_message("Have no help directory\n");
416       return(NULL);
417    }
418    if (!THD_mkdir(hdir)) {
419       ERROR_message("Cannot create %s directory\n", hdir);
420       return(NULL);
421    }
422    return(hdir);
423 }
424 
425 /* retrieve data directory and make sure it is present
426    Do not free returned pointer. Failure is a NULL pointer */
THD_get_datadir(byte withslash)427 char *THD_get_datadir(byte withslash)
428 {
429    char *hdir = NULL;
430    hdir = THD_datadir(withslash);
431    if (hdir[0] == '\0') {
432       ERROR_message("Have no data directory\n");
433       return(NULL);
434    }
435    if (!THD_mkdir(hdir)) {
436       ERROR_message("Cannot create %s directory\n", hdir);
437       return(NULL);
438    }
439    return(hdir);
440 }
441 
THD_helpsearchlog(int createpath)442 char *THD_helpsearchlog(int createpath)
443 {
444    static int bad = 0;
445    static char shelpname[256]={""};
446 
447    if (!bad && createpath && !THD_mkdir(THD_helpdir(0))) {
448       ERROR_message("Cannot create %s help directory\n", THD_helpdir(0));
449       bad = 1;
450    }
451    snprintf(shelpname,255*sizeof(char),
452                       "%s/aps.log.txt",THD_helpdir(0));
453    return(shelpname);
454 }
455 
456 
457 /*--------------------------------------------------------*/
458 /*! Determine if this is really a directory or not. */
459 
THD_is_directory(char * pathname)460 int THD_is_directory( char *pathname )
461 {
462    static struct stat buf ; int ii ;
463 
464    if( pathname == NULL || *pathname == '\0' ) return 0 ;
465    ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ;
466    ii = (buf.st_mode & S_IFDIR) != 0 ; return ii ;
467 }
468 
469 /*---------------------------------------------------------------*/
470 /*! Determine if this is really an executable file or not. */
471 
THD_is_executable(char * pathname)472 int THD_is_executable( char *pathname )  /* 26 Jun 2001 */
473 {
474    static struct stat buf ; int ii ;
475 
476    if( pathname == NULL || *pathname == '\0' )  return 0  ;
477    ii = stat( pathname , &buf )      ; if( ii ) return 0  ;
478    ii = (buf.st_mode & S_IXOTH) != 0 ; if( ii ) return ii ;
479 
480    /* 15 Jul 2002: also check if file is owned & executable by user */
481 
482    ii = ( getuid() == buf.st_uid       &&
483           (buf.st_mode & S_IXUSR) != 0   ) ;
484    return ii ;
485 }
486 
487 /*--------------------------------------------------------------*/
488 /*! Determine if two filenames are really the same thing. */
489 
THD_equiv_files(char * path1,char * path2)490 int THD_equiv_files( char *path1 , char *path2 )
491 {
492    static struct stat buf1 , buf2 ; int ii ;
493 
494    if( path1 == NULL || path2 == NULL ) return -1 ;
495    ii = stat( path1 , &buf1 ) ; if( ii != 0 ) return -1 ;
496    ii = stat( path2 , &buf2 ) ; if( ii != 0 ) return -1 ;
497 
498    ii = (buf1.st_dev == buf2.st_dev) && (buf1.st_ino == buf2.st_ino) ;
499    return ii ;
500 }
501 
502 /*-----------------------------------------------------------------*/
503 /*! Find a 'trailing name in a pathname.
504 
505    For example, for fname = "/bob/cox/is/the/author/of/AFNI",
506      - the lev=0 trailing name is "AFNI",
507      - the lev=1 trailing name is "of/AFNI",
508      - the lev=2 trailing name is "author/of/AFNI", and so on.
509    That is, "lev" is the number of directory names above the
510    last name to keep.  The pointer returned is to some place
511    in the middle of fname; that is, this is not a malloc()-ed
512    string, so don't try to free() it!.
513 -------------------------------------------------------------------*/
514 
THD_trailname(char * fname,int lev)515 char * THD_trailname( char *fname , int lev )
516 {
517    int fpos , flen , flev ;
518 
519    if( fname == NULL || (flen=strlen(fname)) <= 1 ) return fname ;
520 
521    if( lev < 0 ) lev = 0 ;
522 
523    flev = 0 ;
524    fpos = flen ;
525    if( fname[fpos-1] == '/' ) fpos-- ;  /* skip trailing slash */
526 
527    /* fpos   = index of latest character I've accepted,
528       fpos-1 = index of next character to examine,
529       flev   = number of directory levels found so far */
530 
531    while( fpos > 0 ){
532 
533       if( fname[fpos-1] == '/' ){
534          flev++ ; if( flev >  lev ) break ;  /* reached the lev we like */
535       }
536       fpos-- ;  /* scan backwards */
537    }
538 
539    return (fname+fpos) ;
540 }
541 
542 /*----------------------------------------------------------------------*/
543 /*! Return the path to fname.
544     Do not free returned string.
545 */
THD_filepath(char * fname)546 char * THD_filepath( char *fname )
547 {
548    static int icall=-1;
549    static char pname[10][THD_MAX_NAME];
550    char *ppp = NULL;
551    long lend=0;
552 
553    ++icall; if (icall > 9) icall = 0;
554    pname[icall][0]='.'; pname[icall][1]='/'; pname[icall][2]='\0';
555 
556    if (!fname) return(pname[icall]);
557 
558    lend = strlen(fname);
559    if (fname[lend-1] == '/') {   /* fname is a path*/
560       if (lend >= THD_MAX_NAME-1) {
561          ERROR_message("Path name too long. Returning './' as the file path :(");
562          ERROR_message("  Offending input is:\n   %s",fname) ;
563          ERROR_message("Almost certainly something bad will happen below here!") ;
564       } else {
565          strncpy(pname[icall], fname, lend);
566          pname[icall][lend]='\0';
567       }
568       return(pname[icall]);
569    }
570 
571    if (!(ppp=THD_trailname(fname,0))) return(pname[icall]);
572    if (!(lend = ppp-fname)) return(pname[icall]); /* no path on name */
573 
574    if (lend >= THD_MAX_NAME-1) {
575       ERROR_message("Path name too long. Returning './' as the file path :-(");
576       ERROR_message("  Offending input is:\n   %s",fname) ;
577       ERROR_message("Almost certainly something bad will happen below here!") ;
578       return(pname[icall]);
579    }
580 
581    strncpy(pname[icall], fname, lend);
582    pname[icall][lend]='\0';
583    if( pname[icall][lend-1] != '/' ){
584      pname[icall][lend-1] = '/';
585      pname[icall][lend] = '\0';
586    }
587    return(pname[icall]);
588 }
589 
590 /*----------------------------------------------------------------------*/
591 /* Does filename have a path */
THD_filehaspath(char * fname)592 int THD_filehaspath ( char *fname)
593 {
594    if (!fname) return(0);
595    while (*fname!='\0') { if (*fname=='/') return(1); else ++fname; }
596    return(0);
597 }
598 
599 /*----------------------------------------------------------------------*/
600 
THD_character_ok(char c)601 int THD_character_ok( char c )  /* 04 Feb 2010 */
602 {
603    if( iscntrl(c) || isspace(c) ||
604        c == ';'   ||
605        c == '*'   || c == '?'   ||
606        c == '&'   || c == '|'   ||
607        c == '"'   || c == '>'   ||
608        c == '<'   || c == '\''  ||
609        c == '['   || c == ']'   ||
610        c == '('   || c == ')'   ||
611        c == '{'   || c == '}'   ||
612        c == '!'   || (c & 128) != 0 ) return 0 ;
613    return 1 ;
614 }
615 
616 /*----------------------------------------------------------------------*/
617 
THD_filename_fix(char * name)618 int THD_filename_fix( char *name )  /* 04 Feb 2010 */
619 {
620    int ll , ii , nfix ;
621 
622    if( name == NULL ) return -1 ;
623    ll = strlen( name ) ; if( ll == 0 ) return -1 ;
624    for( nfix=ii=0 ; ii < ll ; ii++ ){
625      if( !THD_character_ok(name[ii]) ){ name[ii] = '_' ; nfix++ ; }
626    }
627    return nfix ;
628 }
629 
630 /*----------------------------------------------------------------------*/
631 /*! Check if a filename is OK - that is, has no crummy characters.
632 
633   The filename can have a '/' in it.  To insist that there be not '/',
634   use THD_filename_pure().
635   The list of crummy characters can be inferred from the source code.
636 */
637 
THD_filename_ok(char * name)638 int THD_filename_ok( char *name )  /* 24 Apr 1997 */
639 {
640    int ll , ii ;
641 
642    if( name == NULL ) return 0 ;
643    ll = strlen( name ) ; if( ll == 0 ) return 0 ;
644    if (ll > 6 && strstr(name, "3dcalc") == name) {
645       return 1; /* have a 3dcalc command, let it be*/
646    }
647    if( AFNI_yesenv("AFNI_ALLOW_ARBITRARY_FILENAMES") ) return 1 ; /* 08 Apr 2009 */
648    for( ii=0 ; ii < ll ; ii++ )
649       if( iscntrl(name[ii]) || isspace(name[ii]) ||
650                                name[ii] == ';'   ||
651           name[ii] == '*'   || name[ii] == '?'   ||
652           name[ii] == '&'   || name[ii] == '|'   ||
653           name[ii] == '"'   || name[ii] == '>'   ||
654           name[ii] == '<'   || name[ii] == '\''  ||
655           name[ii] == '['   || name[ii] == ']'   ||
656           name[ii] == '('   || name[ii] == ')'   ||
657           name[ii] == '{'   || name[ii] == '}'   ||
658           name[ii] == '!'   || (name[ii] & 128) != 0 ) return 0 ;
659 
660    return 1 ;
661 }
662 
663 /*--------------------------------------------------------------------*/
664 /*! Check if a filename is pure - no crummy characters, no '/'. */
665 
THD_filename_pure(char * name)666 int THD_filename_pure( char *name )  /* 28 Feb 2001 */
667 {
668    int ii ;
669 
670    ii = THD_filename_ok( name ) ;
671    if( ii ) ii = (strstr(name,"/") == NULL) ;
672    return ii ;
673 }
674 
675 /*--------------------------------------------------------------*/
676 
677 #undef FNAME
678 #undef FSTYP
679 #undef BSIZE
680 #undef BFREE
681 
682 #if defined(DARWIN) || defined(FreeBSD)  /* Mac or BSD */
683 #  include <sys/param.h>
684 #  include <sys/mount.h>
685 #  define FNAME(a,b) statfs(a,b)
686 #  define FSTYP      statfs
687 #  define BSIZE      f_bsize
688 #  define BFREE      f_bavail
689 #elif defined(LINUX)                     /* Linux */
690 #  include <sys/vfs.h>
691 #  define FNAME(a,b) statfs(a,b)
692 #  define FSTYP      statfs
693 #  define BSIZE      f_bsize
694 #  define BFREE      f_bavail
695 #elif defined(SOLARIS) || defined(SGI)   /* Sun or SGI */
696 #  include <sys/types.h>
697 #  include <sys/statvfs.h>
698 #  define FNAME(a,b) statvfs64(a,b)
699 #  define FSTYP      statvfs64
700 #  define BSIZE      f_bsize
701 #  define BFREE      f_bavail
702 #endif
703 
704 /*--------------------------------------------------------------*/
705 /*! Get free space (in megabytes) on a disk partition.
706     Return value is -1 if can't be determined.
707 ----------------------------------------------------------------*/
708 
THD_freemegabytes(char * pathname)709 int THD_freemegabytes( char *pathname )
710 {
711 #ifdef FNAME
712    int ii ; struct FSTYP buf ;
713    if( pathname == NULL || *pathname == '\0' ) return -1 ;
714    ii = FNAME( pathname , &buf ) ;
715    if( ii ) return -1 ;
716    ii = (int)((double)(buf.BFREE) * (double)(buf.BSIZE) / (1024.0*1024.0)) ;
717    return ii ;
718 #else
719    return -1 ;
720 #endif
721 }
722 
723 /*----------------------------------------------------------------------*/
724 /*! Check a list of dataset names for duplicates. Return value is number
725     of duplicates found.
726      - ns   = number of strings
727      - sar  = string array
728      - flag = 1 to print warnings, 0 to be silent
729 ------------------------------------------------------------------------*/
730 
THD_check_for_duplicates(int ns,char ** sar,int flag)731 int THD_check_for_duplicates( int ns , char **sar , int flag )
732 {
733    int verb = (flag & 1) != 0 ;
734    int ii,jj,li,lj,nw=0 ; char *di, *dj ;
735 
736 ENTRY("THD_check_for_duplicates") ;
737 
738    if( sar == NULL ) RETURN(0) ;
739 
740    for( ii=0 ; ii < ns-1 ; ii++ ){
741 
742      if( sar[ii] == NULL ) continue ;
743      di = strdup(sar[ii]  ) ; li = strlen(di) ;
744           if( strcmp(di+li-5,".HEAD"   ) == 0 ) di[li-5] = '\0' ;
745      else if( strcmp(di+li-5,".BRIK"   ) == 0 ) di[li-5] = '\0' ;
746      else if( strcmp(di+li-8,".BRIK.gz") == 0 ) di[li-8] = '\0' ;
747      else if( strcmp(di+li-7,".nii.gz" ) == 0 ) di[li-3] = '\0' ;
748      else if( strcmp(di+li-1,"."       ) == 0 ) di[li-1] = '\0' ;
749 
750      for( jj=ii+1 ; jj < ns ; jj++ ){
751 
752        if( sar[jj] == NULL ) continue ;
753        dj = strdup(sar[jj]) ; lj = strlen(dj) ;
754             if( strcmp(dj+lj-5,".HEAD"   ) == 0 ) dj[lj-5] = '\0' ;
755        else if( strcmp(dj+lj-5,".BRIK"   ) == 0 ) dj[lj-5] = '\0' ;
756        else if( strcmp(dj+lj-8,".BRIK.gz") == 0 ) dj[lj-8] = '\0' ;
757        else if( strcmp(dj+lj-7,".nii.gz" ) == 0 ) dj[lj-3] = '\0' ;
758        else if( strcmp(dj+lj-1,"."       ) == 0 ) dj[lj-1] = '\0' ;
759 
760        if( strcmp(di,dj) == 0 ){
761          nw++ ;
762          if( verb ) WARNING_message("Datasets '%s' and '%s' are the same?!?",
763                                      sar[ii] , sar[jj] ) ;
764        }
765        free(dj) ;
766      }
767      free(di) ;
768    }
769 
770    RETURN(nw) ;
771 }
772 
773 /*----------------------------------------------------------------------*/
774 /* Check if this directory name is forbidden fruit. */
775 /*----------------------------------------------------------------------*/
776 
THD_forbidden_directory(char * dname)777 int THD_forbidden_directory( char *dname )
778 {
779    if( dname == NULL || *dname == '\0' ) return 1 ;
780 
781 #ifdef DARWIN
782    /* skip system name directories if on MacOS X [18 Sep 2020] */
783    if(
784        strcasestr(dname,"Applications") != NULL ||
785        strcasestr(dname,"Desktop")      != NULL ||
786        strcasestr(dname,"Documents")    != NULL ||
787        strcasestr(dname,"Downloads")    != NULL ||
788        strcasestr(dname,"Library")      != NULL ||
789        strcasestr(dname,"Movies")       != NULL ||
790        strcasestr(dname,"Music")        != NULL ||
791        strcasestr(dname,"Pictures")     != NULL
792     )  return 1 ;
793 #endif
794 
795    /** Other possibilities could go here **/
796 
797    return 0 ;
798 }
799