/* cfengine for GNU
 
        Copyright (C) 1995
        Free Software Foundation, Inc.
 
   This file is part of GNU cfengine - written and maintained 
   by Mark Burgess, Dept of Computing and Engineering, Oslo College,
   Dept. of Theoretical physics, University of Oslo
 
   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version.
 
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA

*/
 

/*********************************************************************/
/*                                                                   */
/*  TOOLKITS: "sharable" library                                     */
/*                                                                   */
/*********************************************************************/

#include "cf.defs.h"
#include "cf.extern.h"

/*********************************************************************/
/* Level 1                                                           */
/*********************************************************************/

int IsAbsoluteFileName(f)

char *f;

{
if (*f == '/' || *f == '.')
   {
   return true;
   }

return false;
}

/*******************************************************************/

void AddSlash(str)

char *str;

{
if ((strlen(str)== 0) || (str == NULL))
   {
   return;
   }
 
if (str[strlen(str)-1] != '/')
   {
   strcat(str,"/");
   }
}

/*********************************************************************/

void DeleteSlash(str)

char *str;

{
if ((strlen(str)== 0) || (str == NULL))
   {
   return;
   }

 if (str[strlen(str)-1] == '/')
   {
   str[strlen(str)-1] = '\0';
   }
}

/*********************************************************************/

void DeleteNewline(str)

char *str;

{
if ((strlen(str)== 0) || (str == NULL))
   {
   return;
   }

 if (str[strlen(str)-1] == '\n')
   {
   str[strlen(str)-1] = '\0';
   }
}

/*********************************************************************/

int ChopLastNode(str)

  /* Chop off trailing node name (possible blank) starting from
     last character and removing up to the first / encountered 
     e.g. /a/b/c -> /a/b
          /a/b/ -> /a/b                                        */

char *str;

{ char *sp;

if ((sp = strrchr(str, '/')) == NULL)
   {
   return false;
   }
else
   {
   *sp = '\0';
   return true;
   }
}

/*********************************************************************/

char *CanonifyName(str)

char *str;

{ static char buffer[bufsize];
  char *sp;

bzero(buffer,bufsize);
strcpy(buffer,str);

for (sp = buffer; *sp != '\0'; sp++)
    {
    if (!isalnum(*sp) || *sp == '.')
       {
       *sp = '_';
       }
    }

return buffer;
}

/*********************************************************************/

char *Space2Score(str)

char *str;

{ static char buffer[bufsize];
  char *sp;

bzero(buffer,bufsize);
strcpy(buffer,str);

for (sp = buffer; *sp != '\0'; sp++)
    {
    if (*sp == ' ')
       {
       *sp = '_';
       }
    }

return buffer;
}

/*********************************************************************/

char *ASUniqueName(str) /* generates a unique action sequence name */

char *str;

{ static char buffer[bufsize];
  struct Item *ip;
  char *sp;

bzero(buffer,bufsize);
strcpy(buffer,str);

for (ip = VADDCLASSES; ip != NULL; ip=ip->next)
   {
   if (strlen(buffer)+strlen(ip->name)+3 > maxlinksize)
      {
      break;
      }
   
   strcat(buffer,".");
   strcat(buffer,ip->name);
   }

return buffer;
}

/*********************************************************************/

char *ReadLastNode(str)

/* Return the last node of a pathname string  */

char *str;

{ char *sp;
  
if ((sp = strrchr(str, '/')) == NULL)
   {
   return str;
   }
else
   {
   return sp + 1;
   }
}

/*********************************************************************/

int MakeDirectoriesFor(file)  /* Make all directories which underpin file */

char *file;

{ char *sp,*spc;
  char currentpath[bufsize];
  char pathbuf[bufsize];
  struct stat statbuf;
  mode_t mask;
  
if (*file != '/')
   {
   sprintf(OUTPUT,"Will not create directories for a relative filename %s\nHas no invariant meaning\n",file);
   CfLog(cferror,OUTPUT,"");
   return false;
   }

strcpy(pathbuf,file);                                                    /* local copy */

for (sp = pathbuf+strlen(file); (*sp != '/') && (sp >= pathbuf); sp--)   /* skip link name */
   {
   *sp = '\0';
   }

if (lstat(pathbuf,&statbuf) != -1)
   {
   if (S_ISLNK(statbuf.st_mode))
      {
      Verbose("%s: INFO: %s is a symbolic link, not a true directory!\n",VPREFIX,pathbuf);
      }

   if (! S_ISLNK(statbuf.st_mode) && ! S_ISDIR(statbuf.st_mode))
      {
      sprintf(OUTPUT,"Warning. The object %s is not a directory.\n",pathbuf);
      CfLog(cfinform,OUTPUT,"");
      CfLog(cfinform,"Cannot make a new directory without deleting it!\n\n","");
      return(false);
      }
   }

for (sp = file, spc = currentpath; *sp != '\0'; sp++)
   {
   if (*sp != '/' && *sp != '\0')
      {
      *spc = *sp;
      spc++;
      }
   else
      {
      *spc = '\0';

      if (strlen(currentpath) == 0)
         {
         }
      else if (stat(currentpath,&statbuf) == -1)
         {
         Debug2("cfengine: Making directory %s, mode %o\n",currentpath,DEFAULTMODE);

         if (! DONTDO)
            {
	    mask = umask(0);
            if (mkdir(currentpath,DEFAULTMODE) == -1)
               {
               sprintf(OUTPUT,"Unable to make directories to %s\n",file);
               CfLog(cferror,OUTPUT,"mkdir");
	       umask(mask);
               return(false);
               }
	    umask(mask);
            }
         }
      else
         {
         if (! S_ISDIR(statbuf.st_mode))
            {
            sprintf(OUTPUT,"Cannot make %s. %s is not a directory!\n",file,currentpath);
	    CfLog(cferror,OUTPUT,"");
            return(false);
            }
         }

      *spc = '/';
      spc++;
      }
   }

Debug("Directory for %s exists. Okay\n",file);
return(true);
}

/*********************************************************************/

int BufferOverflow(str1,str2)                   /* Should be an inline ! */

char *str1, *str2;

{ int len = strlen(str2);

if ((strlen(str1)+len) > (bufsize - buffer_margin))
   {
   sprintf(OUTPUT,"Buffer overflow constructing string. Increase bufsize macro.\n");
   CfLog(cferror,OUTPUT,"");
   printf("%s: Tried to add %s to %s\n",VPREFIX,str2,str1);
   return true;
   }

return false;
}

/*********************************************************************/

void Chop(str)

char *str;

{
if ((str == NULL) || (strlen(str)==0))
   {
   return;
   }

if (isspace(str[strlen(str)-1]))
   {
   str[strlen(str)-1] = '\0';
   }
}



/*********************************************************************/

int CompressPath(dest,src)

char *dest, *src;

{ char *sp;
  char node[bufsize];

Debug2("CompressPath(%s,%s)\n",dest,src);

bzero(dest,bufsize);

for (sp = src; *sp != '\0'; sp++)
   {
   if (*sp == '/')
      {
      continue;
      }

   bzero(node,maxlinksize);

   sscanf(sp,"%[^/]",node);

   if (strlen(node) > maxlinksize)
      {
      CfLog(cferror,"Link in path suspiciously large","");
      return false;
      }
   
   sp += strlen(node) - 1;

   if (strcmp(node,".") == 0)
      {
      continue;
      }

   if (strcmp(node,"..") == 0)
      {
      if (! ChopLastNode(dest))
	 {
	 Debug("cfengine: used .. beyond top of filesystem!\n");
	 return false;
	 }
      continue;
      }
   else
      {
      strcat(dest,"/");
      }
   
   if (BufferOverflow(dest,node))
      {
      return false;
      }
   
   strcat(dest,node);
   }
return true;
}

/*********************************************************************/
/* TOOLKIT : String                                                  */
/*********************************************************************/

char ToLower (ch)

char ch;

{
if (isdigit(ch) || ispunct(ch))
   {
   return(ch);
   }

if (islower(ch))
   {
   return(ch);
   }
else
   {
   return(ch - 'A' + 'a');
   }
}


/*********************************************************************/

char ToUpper (ch)

char ch;

{
if (isdigit(ch) || ispunct(ch))
   {
   return(ch);
   }

if (isupper(ch))
   {
   return(ch);
   }
else
   {
   return(ch - 'a' + 'A');
   }
}

/*********************************************************************/

char *ToUpperStr (str)

char *str;

{ static char buffer[bufsize];
  int i;

bzero(buffer,bufsize);
  
if (strlen(str) >= bufsize)
   {
   char *tmp;
   tmp = malloc(40+strlen(str));
   sprintf(tmp,"String too long in ToUpperStr: %s",str);
   FatalError(tmp);
   }

for (i = 0; str[i] != '\0'; i++)
   {
   buffer[i] = ToUpper(str[i]);
   }

buffer[i] = '\0';

return buffer;
}


/*********************************************************************/

char *ToLowerStr (str)

char *str;

{ static char buffer[bufsize];
  int i;

bzero(buffer,bufsize);

if (strlen(str) >= bufsize)
   {
   char *tmp;
   tmp = malloc(40+strlen(str));
   sprintf(tmp,"String too long in ToLowerStr: %s",str);
   FatalError(tmp);
   }

for (i = 0; str[i] != '\0'; i++)
   {
   buffer[i] = ToLower(str[i]);
   }

buffer[i] = '\0';

return buffer;
}
