/* append_type.c
 * Given the name of a file, use information stored by the file system to
 * attempt to determine the type of the data in the file.  Use the Unix
 * conventions for indicating file types:
 *  
 *  Character        File type
 *     *             executable
 *     /             directory
 *     @             symbolic link
 *
 * Append this character to the name, and return the result in buf.
 *
 * Peter Webb, Summer 1990
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

/* Package include files */

#include "reformat.h"
#include "types.h"
#include "error.h"
#include "extern.h"

/* Return the type of the file */

FileType WhatFileType(name)
  char *name;
{
  struct stat blk;

/* Make a call to stat to find out about the file */
  
  if (FullInputPath(name, ScratchBuf) != AllOk) return(unknown);
  if (stat(ScratchBuf, &blk) != 0)
    {
      err_msg(WhatType, FileSystemError);
      return(unknown);
    }

/* Check the st_mode field */

#ifdef UNICOS 

/* Symbolic links don't exist in UNICOS */

  if ((blk.st_mode & S_IFMT) == S_IFDIR)  /* Directory */
    return(dir);
  else if (blk.st_mode & S_IEXEC)              /* Executable */
    return(exec);
  else return(plain);

#else

/* Enlightened UNIX systems have symbolic links */

  if ((blk.st_mode & S_IFMT) == S_IFLNK)       /* It's a symbolic link */
    return(link);
  else if ((blk.st_mode & S_IFMT) == S_IFDIR)  /* Directory */
    return(dir);
  else if (blk.st_mode & S_IEXEC)              /* Executable */
    return(exec);
  else return(plain);              /* Plain file - data type unknown */

#endif

}

/* Return the last element in a path name.  Remove any special characters at
 * the end of the file name.  This code is very ugly, and makes me unhappy.
 * But it works.
 */

ErrorCode LastPathElement(name, buf)
  char *name, *buf;
{
  char *ptr, *ptr1;
  FileType ftype;

/* Find the rightmost '/' */
  
  ptr = strrchr(name, '/');
	

/* If the '/' is at the end of the name, then this might be a directory file */

  if (ptr != NULL && *(ptr+1) == '\0')
    {
      *ptr = '\0';
      ptr1 = strrchr(name, '/');
      if (ptr1 == NULL) strcpy(buf, name);
      else if (strlen(ptr1) != 0 && (ftype = WhatFileType(ptr1)) == dir)
	strcpy(buf, (ptr1+1));
      else
	{
	  *buf = '\0';
	  if (ftype == unknown) return(err_msg(LastPathElt, UnknownFileType));
	}
      *ptr = '/';
      return(AllOk);
    }
  
/* Check for '@' and '*' */

  if ((ptr = strrchr(name, '@')) != NULL)
    {
      *ptr = '\0';
      ptr1 = strrchr(name, '/');
      if ((ftype = WhatFileType( (ptr1 == NULL ? name : ptr1) )) == link)
	strcpy(buf, (ptr1 == NULL ? name : ptr1));
      else if (ftype == unknown) return(err_msg(LastPathElt, UnknownFileType));
      else strcpy(buf, name);
      *ptr = '@';
      return(AllOk);
    }

  if ((ptr = strrchr(name, '*')) != NULL)
    {
      *ptr = '\0';
      ptr1 = strrchr(name, '/');
      if ( (ftype = WhatFileType( (ptr1 == NULL ? name : ptr1) )) == link)
	strcpy(buf, (ptr1 == NULL ? name : ptr1));
      else if (ftype == unknown) return(err_msg(LastPathElt, UnknownFileType));
      else strcpy(buf, name);
      *ptr = '*';
      return(AllOk);
    }
  strcpy(buf, name);
  return(AllOk);
}

ErrorCode AppendType(file, buf)
  char *file, *buf;
{
  FileType kind;

/* Check parameters */

  if (file == NULL || buf == NULL)
    return(err_msg(AppendFileType, NullPtr));
  if (*file == NULL) return(err_msg(AppendFileType, BadInput));

/* Get the file type */

  kind = WhatFileType(file);

/* Concatenate the type and filename */

  switch (kind)
    {
    case link:    sprintf(buf, "%s@", file);  break;
    case dir:     sprintf(buf, "%s/", file);  break;
    case exec:    sprintf(buf, "%s*", file);  break;
    case plain:   strcpy(buf, file);          break;
    case unknown:
      return(err_msg(AppendFileType, UnknownFileType));
    default:
      return(err_msg(AppendFileType, InternalError));
    }

  return(AllOk);

}

