#include "macutils.h"

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;
}

/* This function is an adaptation of the function FSpLocationFromPath in
   tclMacUtils.c in the Tcl 8.0 distribution */
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);
}


syntax highlighted by Code2HTML, v. 0.9.1