#!/usr/bin/perl

# Program: unix2macpath
# Author: Patrick Luby
# Usage: exec perl unix2macpath -h for this program's usage

$status = 1; 

# Check if there are any arguments to execute. If not, print a usage statement.
if ($#ARGV < 0 || $ARGV[0] eq "-h") {
  select(STDERR);
  print("\n");
  print("This command takes Unix paths as arguments and prints each\n");
  print("argument's equivalent Mac OS path to stdout.\n");
  print("\n");
  print("This command has the following usage:\n");
  print("     perl $0 [-unquoted] Unix_path_1 ... Unix_path_n\n");
  print("\n");
  print("By default, each converted path is quoted. You can disable quoting\n");
  print("by using the -unquoted option.\n");
  print("\n");
  print("This command will also perform the following error checking:\n");
  print("  - Arguments that are Unix path lists (e.g. path1:path2:path3)\n");
  print("    are convereted to Mac path lists (e.g. path1,path2,path3)\n");
  print("  - Paths that reside in the root filesystem will be\n");
  print("    prepended with root filesystem's Mac OS volume name\n");
  print("  - Paths that contain a Unix softlink will be resolved to their\n");
  print("    underlying absolute path\n");
  print("\n");
  exit($status);
}

# Global variables
$quote = 1;

# Iterate through each argument
for ($i = 0; $i <= $#ARGV; $i++) {

  # Check if quoting is to be disabled
  if ($ARGV[$i] eq "-unquoted") {
    $quote = 0;
    next;
  }

  # Split the path into its components so that we can handle path lists
  @components = split(/:/, $ARGV[$i]);
  $currentcomponent = "";

  # Iterate through each component of the path
  for ($j = 0; $j <= $#components; $j++) {

    # Mac OS 9 cannot resolve Unix directory softlinks. So, we split out the
    # elements in the path and search for directory softlinks. We need to
    # iterate backwards through the path to find the lowest level
    # directory that exists. We then convert that directory to its fully
    # resolved absolute path and add back any remaining portions of the path.
    @elements = split(/\//, $components[$j]);
    $currentargbegin = $components[$j];
    $currentargend = "";
    for ($k = $#elements; $k >= 0; $k--) {
      if (-d $currentargbegin) {
        # Elimate any directory softlinks by finding the fully resolved path
        # for the current path
        $currentargbegin = `cd "$currentargbegin" ; /bin/pwd`;
        chomp($currentargbegin);
        last;
      }
      else {
        # Shift the last element of $currentargbegin to $currentargend before
        # looping
        $currentargbegin = "";
        for ($l = 0; $l < $k; $l++) {
          if ($l == 0) {
            $currentargbegin = "$elements[$l]";
          }
          else {
            $currentargbegin = "$currentargbegin/$elements[$l]";
          }
        }
        $currentargend = "";
        for ($l = $k; $l <= $#elements; $l++) {
          if ($l == $k) {
            $currentargend = "$elements[$l]";
          }
          else {
            $currentargend = "$currentargend/$elements[$l]";
          }
        }
      }
    }
    if ($currentargbegin eq "" || $currentargend eq "") {
      $components[$j] = "$currentargbegin$currentargend";
    }
    else {
      $components[$j] = "$currentargbegin/$currentargend";
    }

    # Resplit out the elements in the path and convert each element
    @elements = split(/\//, $components[$j]);
    $currentpath = "";
    for ($k = 0; $k <= $#elements; $k++) {

      $currentelement = $elements[$k];

      # If the element is a "." (current directory) or "", ignore this element.
      if ($currentelement eq "." || $currentelement eq "") {
        next;
      }

      # If the element is a ".." (parent directory), make this element "".
      if ($currentelement eq "..") {
        $currentelement = "";
      }

      # Append the element to the previously converted elements.
      $currentpath = "$currentpath:$currentelement";

    }

    # If the first element is empty, it is an absolute path. Mac absolute paths
    # are never prefixed with a directory separator (the exact opposite of Unix)
    # so we need to remove the one we added above.
    if ($elements[0] eq "") {
      $currentpath =~ s/^://;
      # If this absolute path is on the "/" mount, we need to do some special
      # logic to figure out its Mac OS 9 volume name.
      $volume = "/" . (split(/:/, $currentpath))[0];
      if (-d $volume) {
        # Quote the path
        $volume =~ s/"/"\\""/g;
        $volume = "\"$volume\"";
        # Use the df command to determine where this volume is mounted
        open(DF, "/bin/df $volume |");
        # Discard header line
        $line = <DF>;
        $line = <DF>;
		@currentmount = split(' ', $line);
        $mount = $currentmount[$#currentmount];
        close(DF);
        if ($mount eq "/") {
          # Get a list of Mac OS 9 volume names
          open(DIR, "ls -A /private/tmp/AppleFinder |");
          while ($line = <DIR>) {
            chomp($line);
            $volumelist[$#volumelist + 1] = $line;
          }
          # Get a list of Unix mount points
          open(DF, "/bin/df |");
          # Discard header line
          $line = <DF>;
          while ($line = <DF>) {
			@currentmount = split(' ', $line);
            # Get top level directory name of mount point
            $mountlist[$#mountlist + 1] =
              (split('\/', $currentmount[$#currentmount]))[1];
          }
          close(DF);
          # Eliminate items in @mountlist from @volumelist. Whatever remains
          # should be the Mac OS 9 volume name for the root filesystem.
          for ($l = 0; $l <= $#mountlist; $l++) {
            for ($m = 0; $m <= $#volumelist; $m++) {
              if("$mountlist[$l]" eq "$volumelist[$m]") {
                # Set matched items to null strings
                $volumelist[$m] = "";
              }
            }
          }
          # Prepend the first non-null volume name to the path
          for ($l = 0; $l <= $#volumelist; $l++) {
            if ("$volumelist[$l]" ne "") {
              $currentpath = "$volumelist[$l]:$currentpath";
              last;
            }
          }
        }
      }
    }

    # If there are no ":" directory separators, we only have an absolute path
    # with only one element. In this case, we can safely assume the path is a
    # Mac volume. Therefore, we need to append a ":" to the end of the path.
    # Also, if the last element was a "..", we need to tack on an extra ":"
    # for the parent directory to get resolved properly.
    if ($currentpath !~ /:/ || $elements[$#elements] eq "..") {
      $currentpath =~ s/$/:/;
    }

    if ($currentcomponent eq "") {
      $currentcomponent = $currentpath;
    }
    else {
      $currentcomponent = "$currentcomponent,$currentpath";
    }

  }

  # Quote the path
  if ($quote) {
    $currentcomponent =~ s/"/"\\""/g;
    $currentcomponent = "\"$currentcomponent\"";
  }

  # Print the converted path
  print "$currentcomponent\n";

}
