#!/usr/bin/env python

# Copyright 2001 Dan York

# 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 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.
# http://www.gnu.org/copyleft/gpl.html


# import various modules that we need

from os import *
from os.path import *
import getopt
from sys import argv,stderr,exit

# define two constants purely to make code more readable
TRUE = 1
FALSE = 0

def FormatFile (file):
    """adds the size to the filename if -s is set"""
    if Size:
       try:
          if islink(file):
	      s = lstat(file)[6]
	  else:
              s =  getsize(file)
             # format size to look prettier
          fs = ("[%9s]  " + file) % (str(s))
          return (fs)
        # if we get 'permission denied' print a bogus size field 
       except OSError:
          return ('[   denied]' + file)
    else:
       return (file)

def PrintLink(istring,file):
    """prints out a link"""
    if exists(file):
        print istring +  FormatFile(file) + " --> " + readlink(file)
    else:
        print istring + FormatFile(file) + " --> (" + readlink(file)+")"

def PrintTree(level, dir, files, prefix):
    """Prints the tree of files"""
       # alpha sort the file
    files.sort()
       # test if we are running in the cwd. If not cd to wherever we are to run
    if split(getcwd())[-1] != dir:
        chdir(dir)

       # strain out all unnecessary files - this is necessary so that we can
       # correctly determine the end of the listing for directories and therefore
       # round out the line (when a -d is used). While we are at it, let's get
       # rid of all 'hidden' files that begin with a dot.
    RevisedFileList = []
    if DirsOnly:
        for i in files:
           if i[0] != '.' and isdir(i):
              RevisedFileList.append(i)
    else:
        for i in files:
           if i[0] != '.':
              RevisedFileList.append(i)

       # loop through all the files that are left
    for f in RevisedFileList:
             # create the string to put in front of the filename
             # check if it is the last one if so, round the corner by using a quote
             # Also, set up the prefix for the next recursion (if there is one)
           if f == RevisedFileList[-1]:
               istring = prefix + "`-- "
               NextPrefix = prefix + '    '
           else:
               istring = prefix + "|-- "
               NextPrefix = prefix + '|   '
  
           try:
                   # if it is a directory, print it and recurse into that dir
               if isdir(f):
	           if islink(f):
		       PrintLink(istring,f)
		   else:
                       print istring + FormatFile(f)

		   if not islink(f):
                     PrintTree(level + 1, f, listdir(f),NextPrefix)
                   # if -d is set (dirs only) then do nothing else. otherwise proceed
               elif not DirsOnly:
                       # if it is a link, test to see if it exists
                    if islink(f):
		       PrintLink(istring,f)
                       # otherwise it must be a file
                    else:
                        print istring + FormatFile(f)
              # this is here in case a file generates "permission denied"
              # for instance if perms are wrong or the file does not exist
              # Note that directories are already printed above regardless
              # of their status
           except OSError:
               if not DirsOnly and not isdir(f):
                   print istring +  FormatFile(f)
      # change back to the directory we originally came from (only really
      # applies to recursive calls to PrintTree
    chdir('..')

# Set initial indentation level to zero, and set DirsOnly and Size to FALSE
level = 0
DirsOnly = FALSE
Size = FALSE

# Get the options and arguments and trap for errors
# Note that getopt allows for '-d -s', '-s -d', '-ds', '-sd'
# 'opts' will contain command line options, if any
# 'args' will contain other arguments, if any

try:
    opts, args = getopt.getopt(argv[1:],"ds")
except getopt.error, msg:
    # If the user gave something other than -d or -s, quit with an error
    stderr.write("\ntree: commandline error: "+msg+"\n\n")
    exit(1)

# Scan option flags and set appropriate variables
for i in opts:
    if i[0] == '-d':
        DirsOnly = TRUE
    elif i[0] == '-s':
        Size = TRUE

# if no argument, assume the current dir and print '.', else print cwd
if not args:
    cwd = getcwd()
    print "."
else:
    # check to be sure that the argument *is* a directory and if so, print it
    if isdir(args[0]):
        cwd = args[0]
        print cwd
    else:
        # if arg is NOT a directory, print error message and quit
        stderr.write("\ntree: commandline error: "+args[0]+\
	    " is not a directory\n\n")
        exit(1)

PrintTree(level,cwd,listdir(cwd),'')

