/*****************************************************************************
   Major portions of this software are copyrighted by the Medical College
   of Wisconsin, 1994-2000, and are released under the Gnu General Public
   License, Version 2.  See the file README.Copyright for details.
******************************************************************************/

#include "mrilib.h"
#include "thd.h"

/*-------------------------------------------------------------*/
/*! Return the time at which the file was last modified. */

time_t THD_file_mtime( char *pathname )  /* 05 Dec 2001 */
{
   static struct stat buf ; int ii ;

   if( pathname == NULL || *pathname == '\0' ) return 0 ;
   ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ;
   return (time_t)buf.st_mtime ;
}

/*-----------------------------------------------------------*/
/*! Determine if this exists at all (file, directory, ...). */

int THD_is_ondisk( char *pathname )  /* 19 Dec 2002 */
{
   static struct stat buf ; int ii ;

   if( pathname == NULL || *pathname == '\0' ) return 0 ;
   ii = stat( pathname , &buf ) ;
   return (ii == 0) ;
}

/*-----------------------------------------------------------*/
/*! Change working directory. */

int THD_cwd( char *pathname )    /* 19 Dec 2002 */
{
   if( pathname == NULL || *pathname == '\0' ) return 0 ;
   return ( chdir(pathname) == 0 ) ;
}

/*-----------------------------------------------------------*/
/*! Create a directory.  Returns 1 if OK, 0 if not. */

int THD_mkdir( char *pathname )  /* 19 Dec 2002 */
{
   int lp , ii , jj ;
   char *pnam ;

   /* check if input is OK, or if it already exists */

   if( !THD_filename_ok(pathname) ) return 0 ;
   if(  THD_is_ondisk  (pathname) ) return THD_is_directory(pathname) ;

   pnam = strdup(pathname) ;  /* modifiable copy */
   lp = strlen(pnam) ; ii = 0 ;

   /* loop over path segments, creating them if needed */

   while(1){

     /* advance ii to point to end of next path segment,
        at the next '/' character, or at the end of pnam */

     ii += strspn(pnam+ii,"/") ; ii += strcspn(pnam+ii,"/") ;

     /* insert a NUL to replace the '/', temporarily */

     if( ii < lp ) pnam[ii] = '\0' ;

     /* if this segment doesn't already exist, create it */

     if( !THD_is_directory(pnam) ){
       jj = mkdir( pnam , 0755 ) ;
       if( jj != 0 ){ free(pnam); return 0; } /* bad */
     }

     /* if reached end of path string, we're done */

     if( ii == lp ){ free(pnam); return 1; }  /* good */

     /* reinsert '/' if it was excised */

     pnam[ii] = '/' ;
   }

   return 0 ; /* unreachable */
}

/*-----------------------------------------------------------*/
/*! Determine if this is really a regular file or not. */

int THD_is_file( char *pathname )
{
   static struct stat buf ; int ii ;

   if( pathname == NULL || *pathname == '\0' ) return 0 ;
   ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ;
   ii = (buf.st_mode & S_IFREG) != 0 ; return ii ;
}

/*------------------------------------------------------------*/
/*! Determine if this is really a symbolic link or not. */

int THD_is_symlink( char *pathname )  /* 03 Mar 1999 */
{
   char buf[32] ; int ii ;

   if( pathname == NULL || *pathname == '\0' ) return 0 ;
   ii = readlink( pathname , buf , 32 ) ;
   return (ii > 0) ;
}

/*-------------------------------------------------------*/
/*! Return the file length (0 if file not found). */

long long THD_filesize( char *pathname )
{
   static struct stat buf ; int ii ;

   if( pathname == NULL || *pathname == '\0' ) return 0 ;
   ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ;
   return (long long)buf.st_size ;
}

/*--------------------------------------------------------*/
/*! Determine if this is really a directory or not. */

int THD_is_directory( char *pathname )
{
   static struct stat buf ; int ii ;

   if( pathname == NULL || *pathname == '\0' ) return 0 ;
   ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ;
   ii = (buf.st_mode & S_IFDIR) != 0 ; return ii ;
}

/*---------------------------------------------------------------*/
/*! Determine if this is really an executable file or not. */

int THD_is_executable( char *pathname )  /* 26 Jun 2001 */
{
   static struct stat buf ; int ii ;

   if( pathname == NULL || *pathname == '\0' )  return 0  ;
   ii = stat( pathname , &buf )      ; if( ii ) return 0  ;
   ii = (buf.st_mode & S_IXOTH) != 0 ; if( ii ) return ii ;

   /* 15 Jul 2002: also check if file is owned & executable by user */

   ii = ( getuid() == buf.st_uid       &&
          (buf.st_mode & S_IXUSR) != 0   ) ;
   return ii ;
}

/*--------------------------------------------------------------*/
/*! Determine if two filenames are really the same thing. */

int THD_equiv_files( char *path1 , char *path2 )
{
   static struct stat buf1 , buf2 ; int ii ;

   if( path1 == NULL || path2 == NULL ) return -1 ;
   ii = stat( path1 , &buf1 ) ; if( ii != 0 ) return -1 ;
   ii = stat( path2 , &buf2 ) ; if( ii != 0 ) return -1 ;

   ii = (buf1.st_dev == buf2.st_dev) && (buf1.st_ino == buf2.st_ino) ;
   return ii ;
}

/*-----------------------------------------------------------------*/
/*! Find a 'trailing name in a pathname.

   For example, for fname = "/bob/cox/is/the/author/of/AFNI",
     - the lev=0 trailing name is "AFNI",
     - the lev=1 trailing name is "of/AFNI",
     - the lev=2 trailing name is "author/of/AFNI", and so on.
   That is, "lev" is the number of directory names above the
   last name to keep.  The pointer returned is to some place
   in the middle of fname; that is, this is not a malloc()-ed
   string, so don't try to free() it!.
-------------------------------------------------------------------*/

char * THD_trailname( char *fname , int lev )
{
   int fpos , flen , flev ;

   if( fname == NULL || (flen=strlen(fname)) <= 1 ) return fname ;

   if( lev < 0 ) lev = 0 ;

   flev = 0 ;
   fpos = flen ;
   if( fname[fpos-1] == '/' ) fpos-- ;  /* skip trailing slash */

   /* fpos   = index of latest character I've accepted,
      fpos-1 = index of next character to examine,
      flev   = number of directory levels found so far */

   while( fpos > 0 ){

      if( fname[fpos-1] == '/' ){
         flev++ ; if( flev >  lev ) break ;  /* reached the lev we like */
      }
      fpos-- ;  /* scan backwards */
   }

   return (fname+fpos) ;
}

/*----------------------------------------------------------------------*/
/*! Check if a filename is OK - that is, has no crummy characters.

  The filename can have a '/' in it.  To insist that there be not '/',
  use THD_filename_pure().
  The list of crummy characters can be inferred from the source code.
*/

int THD_filename_ok( char *name )  /* 24 Apr 1997 */
{
   int ll , ii ;

   if( name == NULL ) return 0 ;
   ll = strlen( name ) ; if( ll == 0 ) return 0 ;

   for( ii=0 ; ii < ll ; ii++ )
      if( iscntrl(name[ii]) || isspace(name[ii]) ||
                               name[ii] == ';'   ||
          name[ii] == '*'   || name[ii] == '?'   ||
          name[ii] == '&'   || name[ii] == '|'   ||
          name[ii] == '"'   || name[ii] == '>'   ||
          name[ii] == '<'   || name[ii] == '\''  ||
          name[ii] == '['   || name[ii] == ']'   ||
          name[ii] == '('   || name[ii] == ')'   ||
          name[ii] == '{'   || name[ii] == '}'   ||
          name[ii] == '!'   || (name[ii] & 128) != 0 ) return 0 ;

   return 1 ;
}

/*--------------------------------------------------------------------*/
/*! Check if a filename is pure - no crummy characters, no '/'. */

int THD_filename_pure( char *name )  /* 28 Feb 2001 */
{
   int ii ;

   ii = THD_filename_ok( name ) ;
   if( ii ) ii = (strstr(name,"/") == NULL) ;
   return ii ;
}

/*--------------------------------------------------------------*/

#undef FNAME
#undef FSTYP
#undef BSIZE
#undef BFREE

#if defined(DARWIN) || defined(FreeBSD)  /* Mac or BSD */
#  include <sys/param.h>
#  include <sys/mount.h>
#  define FNAME(a,b) statfs(a,b)
#  define FSTYP      statfs
#  define BSIZE      f_bsize
#  define BFREE      f_bavail
#elif defined(LINUX)                     /* Linux */
#  include <sys/vfs.h>
#  define FNAME(a,b) statfs(a,b)
#  define FSTYP      statfs
#  define BSIZE      f_bsize
#  define BFREE      f_bavail
#elif defined(SOLARIS) || defined(SGI)   /* Sun or SGI */
#  include <sys/types.h>
#  include <sys/statvfs.h>
#  define FNAME(a,b) statvfs64(a,b)
#  define FSTYP      statvfs64
#  define BSIZE      f_bsize
#  define BFREE      f_bavail
#endif

/*--------------------------------------------------------------*/
/*! Get free space (in megabytes) on a disk partition.
    Return value is -1 if can't be determined.
----------------------------------------------------------------*/

int THD_freemegabytes( char *pathname )
{
#ifdef FNAME
   int ii ; struct FSTYP buf ;
   if( pathname == NULL || *pathname == '\0' ) return -1 ;
   ii = FNAME( pathname , &buf ) ;
   if( ii ) return -1 ;
   ii = (int)((double)(buf.BFREE) * (double)(buf.BSIZE) / (1024.0*1024.0)) ;
   return ii ;
#else
   return -1 ;
#endif
}

/*----------------------------------------------------------------------*/
/*! Check a list of dataset names for duplicates. Return value is number
    of duplicates found.
     - ns   = number of strings
     - sar  = string array
     - flag = 1 to print warnings, 0 to be silent
------------------------------------------------------------------------*/

int THD_check_for_duplicates( int ns , char **sar , int flag )
{
   int verb = (flag & 1) != 0 ;
   int ii,jj,li,lj,nw=0 ; char *di, *dj ;

ENTRY("THD_check_for_duplicates") ;

   if( sar == NULL ) RETURN(0) ;

   for( ii=0 ; ii < ns-1 ; ii++ ){

     if( sar[ii] == NULL ) continue ;
     di = strdup(sar[ii]  ) ; li = strlen(di) ;
          if( strcmp(di+li-5,".HEAD"   ) == 0 ) di[li-5] = '\0' ;
     else if( strcmp(di+li-5,".BRIK"   ) == 0 ) di[li-5] = '\0' ;
     else if( strcmp(di+li-8,".BRIK.gz") == 0 ) di[li-8] = '\0' ;
     else if( strcmp(di+li-7,".nii.gz" ) == 0 ) di[li-3] = '\0' ;
     else if( strcmp(di+li-1,"."       ) == 0 ) di[li-1] = '\0' ;

     for( jj=ii+1 ; jj < ns ; jj++ ){

       if( sar[jj] == NULL ) continue ;
       dj = strdup(sar[jj]) ; lj = strlen(dj) ;
            if( strcmp(dj+lj-5,".HEAD"   ) == 0 ) dj[lj-5] = '\0' ;
       else if( strcmp(dj+lj-5,".BRIK"   ) == 0 ) dj[lj-5] = '\0' ;
       else if( strcmp(dj+lj-8,".BRIK.gz") == 0 ) dj[lj-8] = '\0' ;
       else if( strcmp(dj+lj-7,".nii.gz" ) == 0 ) dj[lj-3] = '\0' ;
       else if( strcmp(dj+lj-1,"."       ) == 0 ) dj[lj-1] = '\0' ;

       if( strcmp(di,dj) == 0 ){
         nw++ ;
         if( verb ) WARNING_message("Datasets '%s' and '%s' are the same?!?",
                                     sar[ii] , sar[jj] ) ;
       }
       free(dj) ;
     }
     free(di) ;
   }

   RETURN(nw) ;
}


syntax highlighted by Code2HTML, v. 0.9.1