/*
 Copyright (C) 2002 Andreas Thiede ( a.thiede@berlin.de )

 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 of the License, 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
*/

#import <util/file.h>

OSErr GetDirectoryID(short vRefNum, long, StringPtr, long *, Boolean *);
OSErr FSpGetDirectoryID(const FSSpec *, long *, Boolean *);
OSErr FSMakeFSSpecFromPath(ConstStr255Param, FSSpecPtr);


static void CopyNamePart(StringPtr Name, ConstStr255Param fileName, int start )
{
  int end = fileName[0] + 1, nlen, pos;
  for (nlen = 0, pos = start; pos < end && fileName[pos] == ':'; nlen++, pos++)
    Name[nlen + 1] = ':';
  for (; pos < end && fileName[pos] != ':'; nlen++, pos++)
    Name[nlen + 1] = fileName[pos];
  Name[0] = nlen;
}


OSErr FSMakeFSSpecFromPath(ConstStr255Param fileName, FSSpecPtr spec)
{
  Boolean isDir, wasAlias;
  int pos, end;
  OSErr err;
  Str255 Name;
  short vRefNum;
  long dirID;
  
  /* get the initial directory information and set up first path component */
  CopyNamePart(Name, fileName, 1);
  if (Name[0] < fileName[0] && Name[1] != ':') { /* absolute path */
    Name[0]++;
    Name[Name[0]] = ':';
    if ((err = FSMakeFSSpec(0, 0, Name, spec)) != noErr)
      return err;
    if ((err = FSpGetDirectoryID(spec, &dirID, &isDir)) != noErr)
      return err;
    if (! isDir)
      return dirNFErr;
    vRefNum = spec->vRefNum;
    pos = Name[0] + 1;
    CopyNamePart(Name, fileName, pos);
  }
  else {
    dirID = 0;
    vRefNum = 0;
    pos = 1;
    isDir = true;
  }
  
  /* process remaining path parts */
  end = fileName[0] + 1;
  while (true) {
    if ((err = FSMakeFSSpec(vRefNum, dirID, Name[0] == 0 ? NULL : Name,
                            spec)) != noErr ||
        (err = ResolveAliasFile(spec, true, &isDir, &wasAlias)) != noErr)
      return err;
    pos += Name[0];
    if (pos < end) {
      if ((err = FSpGetDirectoryID(spec, &dirID, &isDir)) != noErr)
        return err;
      if (! isDir)
        return dirNFErr;
      vRefNum = spec->vRefNum;
      CopyNamePart(Name, fileName, pos);
    }
    else
      return noErr;
  }
}




/*
 * The following functions are taken from MoreFiles. For now these are all I
 * use; if I end up using lots more I'll include the whole MoreFiles library.
 */

OSErr GetDirectoryID(short vRefNum, long dirID,
                     StringPtr name, long *theDirID, Boolean *isDirectory)
{
  CInfoPBRec pb;
  Str31 tempName;
  OSErr error;

  /* Protection against File Sharing problem */
  if ( (name == NULL) || (name[0] == 0) ) {
    tempName[0] = 0;
    pb.hFileInfo.ioNamePtr = tempName;
    pb.hFileInfo.ioFDirIndex = -1;      /* use ioDirID */
  }
  else {
    pb.hFileInfo.ioNamePtr = name;
    pb.hFileInfo.ioFDirIndex = 0;       /* use ioNamePtr and ioDirID */
  }
  pb.hFileInfo.ioVRefNum = vRefNum;
  pb.hFileInfo.ioDirID = dirID;
  error = PBGetCatInfoSync(&pb);
  *isDirectory = (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0;
  *theDirID = (*isDirectory) ? pb.dirInfo.ioDrDirID : pb.hFileInfo.ioFlParID;
  return error;
}

OSErr FSpGetDirectoryID(const FSSpec *spec, long *theDirID,
                        Boolean *isDirectory)
{
  return GetDirectoryID(spec->vRefNum, spec->parID,
                       (StringPtr)spec->name, theDirID, isDirectory);
}


#include <string.h>

/*
    path      dirname    basename
    "/usr/lib"   "/usr"     "lib"
    "/usr/"    "/"      "usr"
    "usr"     "."      "usr"
    "/"      "/"      "/"
    "."      "."      "."
    ".."      "."      ".."
*/

char *dirname(char *path) 
{
 char *c;
again:
 if (!(c=strrchr(path,'/'))) return ".";
 while (c[1]==0) {   /* remove trailing slashes */
  if (c==path) return c;   /* unless path=='/' */
  *c=0;
  if (*--c!='/') break;
 }
 if (*c=='/') { if (c!=path) *c=0; return path; }
 goto again;
}




/*
    path      dirname    basename
    "/usr/lib"   "/usr"     "lib"
    "/usr/"    "/"      "usr"
    "usr"     "."      "usr"
    "/"      "/"      "/"
    "."      "."      "."
    ".."      "."      ".."
*/

char *basename(char *path) 
{
 char *c;
again:
 if (!(c=strrchr(path,'/'))) return path;
 if (c[1]==0) {
  if (c == path)
   return c;
  else {
   *c=0;
   goto again;
  }
 }
 return c+1;
}


/* Mac file system parameters */
#define MAXPATH 256/* Max path name length+1 */
#define SEP ':'/* Separator in path names */

/* Macro to find out whether we can do HFS-only calls: */
#define FSFCBLen (* (short *) 0x3f6)
#define hfsrunning() (FSFCBLen > 0)

int nfullpath( FSSpec * fsp, char * retbuf)
{
  union {
    HFileInfo f;
    DirInfo d;
    WDPBRec w;
    VolumeParam v;
  } pb;
  char cwd[2*MAXPATH];
  unsigned char namebuf[MAXPATH];
  short err;
  int dir;
  long dirid;
  char *next = cwd + sizeof cwd - 1;
  int len;
  int need_sep = 1;
  
  if (!hfsrunning())
    return -1;
  
  dir = fsp->vRefNum;
  dirid = fsp->parID;
  /* Stuff the filename into the buffer */
  len = fsp->name[0];
  *next = '\0';
  next -= len;
  memcpy(next, fsp->name+1, len);
  
  while (dirid != fsRtParID) {
    pb.d.ioNamePtr = namebuf;
    pb.d.ioVRefNum = dir;
    pb.d.ioFDirIndex = -1;
    pb.d.ioDrDirID = dirid;
    err= PBGetCatInfo((CInfoPBPtr)&pb.d, 0);
    if (err != noErr)
      return err;
    *--next = SEP;
    len = namebuf[0];
    if ( len + strlen(next) >= MAXPATH )
      return -1;
    next -= len;
    memcpy(next, (char *)namebuf+1, len);
    dirid = pb.d.ioDrParID;
    need_sep = 0;
  }
  
  strcpy(retbuf, next);
  if (need_sep) {
    next = strchr(retbuf, '\0');
    *next++ = SEP;
    *next++ = '\0';
  }
  return 0;
}

#if 0
char * getbootvol(void)
{
  short vrefnum;
  static unsigned char name[32];
  
  (void) GetVol(name, &vrefnum);
  p2cstr(name);
  /* Shouldn't fail; return ":" if it does */
  strcat((char *)name, ":");
  return (char *)name;
}
#endif

