#!/usr/bin/env python

# lsseq - List directory contents while condensing images sequences to
# one entry each.  Filenames that are part of images sequences are
# assumed to be of the form:
#     <descriptiveName>.<frameNum>.<imgExtension>

# Copyright (c) 2008-2012, James Philip Rowell,
# Orange Imagination & Concepts, Inc.
# www.orangeimagination.com
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#   - Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
#
#   - Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in
#     the documentation and/or other materials provided with the
#     distribution.
#
#   - Neither the name of "Orange Imagination & Concepts, Inc."  nor the
#     names of its contributors may be used to endorse or promote
#     products derived from this software without specific prior written
#     permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import argparse
import os
import sys
import subprocess
import seqLister
import textwrap
from operator import itemgetter

MOV_EXT = ["avi", "mov", "mp4", "mpg", "wmv"]
IMAGE_EXT = ["alpha", "als", "anim", "bmp", "btf", "bw", "cin",
    "dib", "dpx", "exr", "gfa", "gif", "giff", "icon", "iff", "img",
    "int", "inta", "jpe", "jpeg", "jpg", "mask", "matte", "pct",
    "pct1", "pct2", "pdb", "pdd", "pic", "pict", "pix", "png",
    "psb", "psd", "raw", "rgb", "rgba", "rle", "rw2", "sgi", "tga",
    "tif", "tiff", "tpic"]
PATH_ABS = 1
PATH_REL = 2
LIST_ALLFILES = 0
LIST_ONLYSEQS = 1 # Images and movies.
LIST_ONLYIMGS = 2 # Strictly images.

# Given that we are not allowing "no separator" between the
# descriptive filename and the frame number, then the only
# other character besides "." (dot) that makes sense to have as a 
# separator is "_" (underscore).
#
# Clearly we should not allow alphanumeric characters as separators,
# NOR unix/linux/windows shell special characters NOR minus ("-")
# NOR space (" ").  That potentially leaves us with only "_", "+",
# "^" and "~".  Tilde has associations with tmp/crufty files or user
# home directories and his unlikely to ever be used as a separator
# character.  "+" and "^" are potentially usable in as separators
# but unlikely to be used so the effort to generalize the mechanism
# to support the "loose" separator to a list is not worth the effort.
# Thus "loose" is only defined as the use of "_" over and above the
# far more desirable strict case of only allowing ".".
#
LOOSE_SEP = "_"

def isFrameNum(f) :
	return f.isdigit() or (f[0] == '-' and f[1:].isdigit())

# Return two components if "filename" is formatted like a file in an
# image sequence otherwise return an empty list.  The two returned
# components are the full filename but missing the frame number,
# and the frame number (with its existing padding if any).
#     Eg.  "a.b.c.001.exr" -> ["a.b.c..exr", "001"]
#          "a.b.c_001.exr" -> ["a.b.c_.exr", "001"]
#
def seqSplit(filename, args) :

    global IMAGE_EXT
    global LOOSE_SEP
    fileComponents = filename.split(".")

    # Test if image.
    #
    if len(fileComponents) > 1 and (fileComponents[-1] in IMAGE_EXT) :

	if not args.strictSeparator :
	    looseFileComponents = fileComponents[-2].split("_")
	    if len(looseFileComponents) > 1 :
		if isFrameNum(looseFileComponents[-1]) :

		    fileFrameNum = looseFileComponents[-1]
		    looseFileComponents.pop(-1)
		    looseFileComponents[-1] = looseFileComponents[-1] + "_"
		    looseFileKey = "_".join(looseFileComponents)
		    fileComponents[-2] = looseFileKey
		    fileKey = ".".join(fileComponents)
		    return [fileKey, fileFrameNum]

	if len(fileComponents) > 2 and isFrameNum(fileComponents[-2]) :

	    fileFrameNum = fileComponents[-2]
	    fileComponents.pop(-2)
	    fileComponents[-2] = fileComponents[-2] + "."
	    fileKey = ".".join(fileComponents)
	    return [fileKey, fileFrameNum]

    return []


# Return true if and only if filename is a movie file.
#
def isMovie(filename) :
    global MOV_EXT
    fileComponents = filename.split(".")

    return len(fileComponents) > 1 \
        and MOV_EXT.count(fileComponents[-1]) >= 1


# Split the filename key into (<imagename>, "", <ext>)
# (empty placeholder for framenum)
#
def splitImageName(filename) :
    numSep = "."
    fileComponents = filename.split(".")
    if fileComponents[-2] == '' :
	fileComponents.pop(-2)
    else :
	numSep = fileComponents[-2][-1] # i.e.; "_"
	fileComponents[-2] = fileComponents[-2][:-1]

    fileExt = fileComponents.pop(-1)
    fileRoot = ".".join(fileComponents) + numSep
    return [fileRoot, "", fileExt]

# Reconstruct the imagename with the frame number.
#
def actualImageName(filename, padding, frame) :
    fileParts = splitImageName(filename)
    formatStr = "{0:0=-" + str(padding) + "d}"
    return fileParts[0] + formatStr.format(frame) + "." + fileParts[2]


def printSeq(filename, frameList, args, traversedPath) :

    fileComponents = splitImageName(filename)

    missingFrames = []
    zeroFrames = []
    minFrame = frameList[1][0][0]
    maxFrame = frameList[1][-1][0]
    padding = frameList[0]
    i = minFrame
    while i <= maxFrame:
        iMissing = False
        currFrameData = frameList[1][0]
        if i != currFrameData[0] : # frame number
            iMissing = True
            if args.showMissing :
                missingFrames.append(i)
        else :
            frameList[1].pop(0)
        if (not iMissing and args.showZero) :
            # if this file is a broken soft link '-1' was stashed as mtime
            if currFrameData[2] == -1 : # mtime
                zeroFrames.append(i)
                actualFilename = actualImageName(filename, padding, i)
                print >> sys.stderr, os.path.basename(sys.argv[0]) + \
                    ": warning: " + actualFilename + " is a broken soft link."
            elif currFrameData[1] == 0 : # file size
                zeroFrames.append(i)
        i = i + 1

    formatStr = "%0" + str(padding) + "d"
    if minFrame != maxFrame :
        if args.seqFormat == 'rv' :
            padStr = '@' * padding
            if padding == 4 :
                padStr = '#'
            frameRange = str(minFrame) + "-" + str(maxFrame) + padStr
        else :
            frameRange = "[" \
                + (formatStr % minFrame) \
                + "-" \
                + (formatStr % maxFrame) \
                + "]"
    else :
        if args.seqFormat == 'rv' :
            frameRange = (formatStr % minFrame)
        else :
            frameRange = "[" \
                + (formatStr % minFrame) \
                + "]"
    fileComponents[1] = frameRange

    if args.seqFormat == 'nuke' :
	if minFrame == maxFrame :
	    fileComponents[1] = (formatStr % minFrame)
	else :
	    fileComponents[1] = "%0" + str(padding) + "d"
        if args.prependPath > 0 :
            sys.stdout.write(traversedPath)
        print fileComponents[0] + fileComponents[1] + "." + fileComponents[2],
	if minFrame == maxFrame :
	    print ""
	else :
	    print str(minFrame) + "-" + str(maxFrame)

    elif args.seqFormat == 'shake' :
	if minFrame == maxFrame :
	    fileComponents[1] = (formatStr % minFrame)
	    print "shake ",
	else :
	    if padding == 4 :
		fileComponents[1] = "#"
	    else :
		fileComponents[1] = "@"*padding
	    print "shake -t", str(minFrame) + "-" + str(maxFrame) + " ",
        if args.prependPath > 0 :
            sys.stdout.write(traversedPath)
	else :
            sys.stdout.write("")
        print fileComponents[0] + fileComponents[1] + "." + fileComponents[2]

    elif args.seqFormat == 'glob' :
	if minFrame < 0 :
	    fileComponents[1] = "[\-0-9]"
	else :
	    fileComponents[1] = "[0-9]"
	if (padding > 1) :
	    fileComponents[1] = fileComponents[1] + "[0-9]"*(padding-1)

        if args.prependPath > 0 :
            sys.stdout.write(traversedPath)
        print fileComponents[0] + fileComponents[1] + "." + fileComponents[2]

    else : # native and rv
        if args.prependPath > 0 :
            sys.stdout.write(traversedPath)
        if args.extremes :
            fileComponents[1] = formatStr % minFrame

        print fileComponents[0] + fileComponents[1] + "." + fileComponents[2],
        if minFrame != maxFrame and args.extremes :
            print ""
            sys.stdout.write(traversedPath)
            fileComponents[1] = formatStr % maxFrame
	    print fileComponents[0] + fileComponents[1] + "." + fileComponents[2],

        if args.combineErrorFrames :
            errFrames = missingFrames + zeroFrames
            frameSeq = seqLister.condenseSeq(errFrames)
            if (len(frameSeq) > 0) :
                sys.stdout.write(" [")
                doPrintComma = False
                for f in frameSeq :
                    if doPrintComma :
                        sys.stdout.write(",")
                    sys.stdout.write(f)
                    doPrintComma = True
                sys.stdout.write("]")
            print ""
        else :
            missingFrameSeq = seqLister.condenseSeq(missingFrames)
            if (len(missingFrameSeq) > 0) :
                sys.stdout.write(" m:[")
                doPrintComma = False
                for f in missingFrameSeq :
                    if doPrintComma :
                        sys.stdout.write(",")
                    sys.stdout.write(f)
                    doPrintComma = True
                sys.stdout.write("]")
            zeroFrameSeq = seqLister.condenseSeq(zeroFrames)
            if (len(zeroFrameSeq) > 0) :
                if (len(missingFrameSeq) > 0) :
                    sys.stdout.write(",")
                sys.stdout.write(" z:[")
                doPrintComma = False
                for f in zeroFrameSeq :
                    if doPrintComma :
                        sys.stdout.write(",")
                    sys.stdout.write(f)
                    doPrintComma = True
                sys.stdout.write("]")
            print ""


def stripDotFiles(dirContents, stripIt) :
    if not stripIt:
        return dirContents
    else :
        strippedDirContents = []
        for f in dirContents :
            if f[0] != "." :
                strippedDirContents.append(f)
        return strippedDirContents


def listSeqDir(dirContents, path, listSubDirs, args, traversedPath) :

    tmpCWD = ""
    # Stash the current working dir, to come back to and the end
    # of this function.
    if (len(path) > 0) :
        tmpCWD = os.path.abspath(".")
        os.chdir(path)

    # The 'imageDictionary' has <imageName>..<ext> (or <imageName>_.<ext>)
    # (i.e.; name without the frame number) as the key for each entry.
    # Each entry is a two item list containing a number and a list
    # of three-tuples, namely:
    #     [ <framePadding>, [ (frameNum, fileSize, mtime), ... ] ]
    #
    imageDictionary = {}
    moviesDictionary = {}
    otherFiles = []
    dirList = []

    # Go through the directory contents sifting out the various file types,
    # collect the names into various lists for printing after this is done.
    #
    for filename in dirContents:
        fileParts = seqSplit(filename, args)
        if len(fileParts) == 2 : # Means file is an image.
            newFrameNum = int(fileParts[1])
            newPaddingSize = len(fileParts[1])

            # Check to see if file exists - might be broken soft link.
            if not os.path.exists(filename) :
                newFrameSize = 0
                newFrameMTime = -1
            else :
                realFilename = os.path.realpath(filename)
                newFrameSize = os.path.getsize(realFilename)
                newFrameMTime = os.path.getmtime(realFilename)

            if newFrameNum < 0 and newFrameNum > -10 and newPaddingSize == 2:
                newPaddingSize = 1

            if imageDictionary.has_key(fileParts[0]) :
                # tack on new frame number.
                imageDictionary[fileParts[0]][1].append( \
                    (newFrameNum, newFrameSize, newFrameMTime))
                # smallest length frame number determines padding.
                if (newPaddingSize < imageDictionary[fileParts[0]][0]) :
                    imageDictionary[fileParts[0]][0] = newPaddingSize
            else :
                # initialiaze dictionary entry.
                imageDictionary[fileParts[0]] \
                    = [newPaddingSize, [(newFrameNum, newFrameSize, newFrameMTime)]]

        elif isMovie(filename) :
            # Check to see if file exists - might be broken soft link.
            if not os.path.exists(filename) :
                moviesDictionary[filename] = -1
            else :
                realFilename = os.path.realpath(filename)
                moviesDictionary[filename] = os.path.getmtime(realFilename)

        else :
            isFileDir = os.path.isdir(filename)
            if ((not isFileDir
                    or not listSubDirs
                    or not args.listDirContents)
                    and args.listWhichFiles == LIST_ALLFILES):
                otherFiles.append(filename)
            if isFileDir :
                dirList.append(filename)

    # Use actual "ls" to print non-image files nicely.
    #
    otherFiles.sort()
    if len(otherFiles) > 0 :
        extra_ls_options = []
        if args.classify :
            extra_ls_options.append("-F")
        if args.singleColumn :
            extra_ls_options.append("-1")
        if args.sortByMTime :
            extra_ls_options.append("-t")
        if args.reverseListing :
            extra_ls_options.append("-r")
        lsCmd = ["ls", "-d"] + extra_ls_options + otherFiles
        sys.stdout.flush()
        subprocess.call(lsCmd)
        sys.stdout.flush()

    # Now actually print the sequences in this directory.
    #
    imKeys = imageDictionary.keys()
    movKeys = moviesDictionary.keys()
    if args.listWhichFiles != LIST_ONLYIMGS :
        for m in movKeys :
            imKeys.append(m)
    if args.sortByMTime :
        timeList = []
        for k in imKeys :
            if isMovie(k) :
                timeList.append((k, moviesDictionary[k]))
            else :
                validTimes = []
                for im in imageDictionary[k][1] :
                    if im[2] != -1 :
                        validTimes.append(im[2])
                validTimes.sort()
                if args.timeCompare == 'oldest' :
                    time = validTimes[0]
                elif args.timeCompare == 'median' :
                    time = validTimes[len(validTimes)/2]
                else : # newest
                    time = validTimes[-1]
                timeList.append((k, time))

        timeList.sort(key=itemgetter(1))
        # Note: ls -t prints newest first; ls -tr is newest last.
        if not args.reverseListing :
            timeList.reverse()
        for k in timeList :
            if isMovie(k[0]) :
                if args.prependPath > 0 :
                    sys.stdout.write(traversedPath)
                print k[0]
            else :
                imageDictionary[k[0]][1].sort(key=itemgetter(0))
                printSeq(k[0], imageDictionary[k[0]], args, traversedPath)
    else :
        imKeys.sort()
        if args.reverseListing :
            imKeys.reverse()
        for k in imKeys :
            if isMovie(k) :
                if args.prependPath > 0 :
                    sys.stdout.write(traversedPath)
                print k
            else :
                imageDictionary[k][1].sort(key=itemgetter(0))
                printSeq(k, imageDictionary[k], args, traversedPath)

    # lsseq - the contents of any subdirectories if need be.
    #
    if ((listSubDirs or args.isRecursive) and args.listDirContents) :
        dirList.sort()
        for d in dirList :
            if d[-1] == "/" :
                d = d[:-1]
            if args.prependPath == 0 :
                print ""
                if args.isRecursive :
                    print traversedPath + d + ":"
                else :
                    print d + ":"
            listSeqDir(stripDotFiles(os.listdir(d), args.ignoreDotFiles),
                d, False, args, traversedPath + d + "/")

    if (len(path) > 0) :
        os.chdir(tmpCWD)


def main():

    # Redefine the exception handling routine so that it does NOT
    # do a trace dump if the user types ^C while lsseq is running.
    #
    old_excepthook = sys.excepthook
    def new_hook(exceptionType, value, traceback):
        if exceptionType != KeyboardInterrupt and exceptionType != IOError:
            old_excepthook(exceptionType, value, traceback)
        else:
            pass
    sys.excepthook = new_hook

    global IMAGE_EXT
    global MOV_EXT
    global PATH_ABS
    global PATH_REL
    global LIST_ALLFILES
    global LIST_ONLYSEQS
    global LIST_ONLYIMGS

    p = argparse.ArgumentParser(
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description=textwrap.dedent('''\
            List directory contents (akin to /bin/ls) while condensing image
            sequences to one entry each. Filenames that are part of image
            sequences are assumed to be of the form:

                <descriptiveName>.<frameNum>.<imgExtension>

            where <imgExtension> is drawn from a default list of image extensions
            (see option -i) or they can be set with the environment variable
            OIC_IMAGE_EXTENSION=exr:jpg:tif (for example).  Similarly there is an
            OIC_MOV_EXTENSION environment variable for movie file extensions.

            %(prog)s will first list all non-image-sequence files followed by the
            list of image sequences as such:

                $ %(prog)s
                [output of /bin/ls minus image sequences]
                [list of images sequences]
            '''),
        usage="%(prog)s [OPTION]... [FILE]...")

    p.add_argument("--version", action="version", version="1.800")

    p.add_argument("--single", "-1", action="store_true",
        dest="singleColumn", default=False,
        help="list one non-image file per line (ls)")
    p.add_argument("--all", "-a", action="store_false",
        dest="ignoreDotFiles", default=True,
        help="do not ignore entries starting with '.' (ls)")
    p.add_argument("--combineLists", "-c", action="store_true",
        dest="combineErrorFrames", default=False,
        help="Combine the lists of zero, missing and bad frames into one list.")
    p.add_argument("--directory", "-d", action="store_false",
        dest="listDirContents", default=True,
        help="list directory entries instead of contents, \
        and do not dereference symbolic links (ls)")
    p.add_argument("--extremes", "-e", action="store_true",
        dest="extremes", default=False,
        help="only list the first and last image on a separate line each. \
        This option implies --prependPathAbs (unless --prependPathRel is \
        explicitly specified) and --strictlyOnlyImages.")
    p.add_argument("--format", "-f", action="store", type=str,
        choices=("native", "nuke", "rv", "shake", "glob"),
        dest="seqFormat",
        metavar="FORMAT",
        default="native",
        help="list image sequences in various formats.\
        The choices are 'native' (default), 'nuke', 'rv', 'shake' and 'glob'.\
	Note that glob prints correct results if and only if \
	the frame numbers are padded.")
    p.add_argument("--classify", "-F", action="store_true",
        dest="classify", default=False,
        help="append indicator (one of */=>@|) to entries (ls)")
    p.add_argument("--imgExt", "-i", action="store_true",
        dest="printImgExtensions", default=False,
        help="print list of raster and movie file extensions and exit")

    p.add_argument("--looseNumSeparator", "-l", action="store_false",
        dest="strictSeparator",
        help="Allow the use of '_' (underscore), in addition to '.' (dot)\
	    as a separator between the descriptiveName and frameNumber when\
	    looking to interpret filenames as\
	    image sequences. i.e.; <descriptiveName>_<frameNum>.<imgExtension>\
	    (also see --strictNumSeparator)")

    p.add_argument("--showMissing", "-m", action="store_true",
        dest="showMissing", default=True,
        help="show list of missing frames [default]" )
    p.add_argument("--skipMissing", "-M", action="store_false",
        dest="showMissing",
        help="do not show list of missing frames" )

    p.add_argument("--onlyImages", "-o", action="store_const",
        dest="listWhichFiles", default=LIST_ALLFILES, const=LIST_ONLYSEQS,
        help="only list image sequences or movies")
    p.add_argument("--strictlyOnlyImages", "-O", action="store_const",
        dest="listWhichFiles", const=LIST_ONLYIMGS,
        help="strictly only list image sequences (i.e.; no movies)")

    p.add_argument("--prependPathAbs", "-p", action="store_const",
        dest="prependPath", default=0, const=PATH_ABS,
        help="prepend the absolute path name to the image name. \
        This option implies the option --onlyImages and will also \
        suppress printing directory name headers when listing \
        directory contents.")
    p.add_argument("--prependPathRel", "-P", action="store_const",
        dest="prependPath", const=PATH_REL,
        help="prepend the relative path name to the image name. \
        This option implies the option --onlyImages and will also \
        suppress printing directory name headers when listing \
        directory contents.")

    p.add_argument("--reverse", "-r", action="store_true",
        dest="reverseListing", default=False,
        help="reverse order while sorting")
    p.add_argument("--recursive", "-R", action="store_true",
        dest="isRecursive", default=False,
        help="list subdirectories recursively")

    p.add_argument("--strictNumSeparator", "-s", action="store_true",
        dest="strictSeparator", default=True,
        help="Strictly enforce the use of '.' (dot) as a separator between the\
	    descriptiveName and frameNumber when looking to interpret filenames as\
	    image sequences. i.e.; <descriptiveName>.<frameNum>.<imgExtension>\
	    (this is the default; also see --looseNumSeparator)")

    p.add_argument("--time", action="store", type=str,
        dest="timeCompare",
        help="which frame in the sequence to use to compare times \
        between sequences when sorting by time.  The possible values \
        for 'FRAME_AGE' are 'oldest', 'median' and 'newest' \
        (default).", metavar="FRAME_AGE", default="newest",
        choices=("oldest", "median", "newest"))
    p.add_argument("-t", action="store_true",
        dest="sortByMTime", default=False,
        help="sort by modification time, the default comparison \
        time is between the most recently modified (newest) frames \
        in each sequence. (see --time). (ls)")
    p.add_argument("--showZero", "-z", action="store_true",
        dest="showZero", default=True,
        help="show list of zero length images [default]" )
    p.add_argument("--skipZero", "-Z", action="store_false",
        dest="showZero",
        help="do not show list of zero length images" )

    p.add_argument("files", metavar="FILE", nargs="*",
        help="file names")

    args = p.parse_args()

    tmpExt = os.getenv("OIC_IMAGE_EXTENSION")
    if tmpExt != None and tmpExt != "" :
        IMAGE_EXT = tmpExt.split(":")

    tmpExt = os.getenv("OIC_MOV_EXTENSION")
    if tmpExt != None and tmpExt != "" :
        MOV_EXT = tmpExt.split(":")

    if args.printImgExtensions :
        print "Image extensions:", IMAGE_EXT
        print "Movie extensions:", MOV_EXT
        sys.exit(0)

    if args.prependPath == PATH_REL :
        if args.listWhichFiles == LIST_ALLFILES :
            args.listWhichFiles = LIST_ONLYSEQS

    if args.prependPath == PATH_ABS :
        if args.listWhichFiles == LIST_ALLFILES :
            args.listWhichFiles = LIST_ONLYSEQS

    if args.extremes :
        if args.prependPath == 0 :
            args.prependPath = PATH_ABS
        args.showMissing = False
        args.showZero = False
        args.seqFormat = 'native'
        if args.listWhichFiles == LIST_ALLFILES :
            args.listWhichFiles = LIST_ONLYIMGS # Strictly only images.

    # The following logic attempts to mimic the behavior
    # of /bin/ls as well as possible.

    # No args means list the current directory.
    #
    if len(args.files) == 0:
        if (not args.listDirContents) :
            if args.listWhichFiles == LIST_ALLFILES :
                print "."
        else :
            if args.isRecursive :
                if args.prependPath == 0 :
                    print ".:"
                passedPath = "./"
            else :
                passedPath = ""
            if args.prependPath == PATH_ABS :
                passedPath = os.getcwd() + "/"

            listSeqDir(stripDotFiles(os.listdir("."), args.ignoreDotFiles), "", False, args, passedPath)

    # We are being asked to list a specific directory, so we don't need
    # to print the directory name before listing the contents (unless
    # it is a recursive listing).  (/bin/ls behavior.)
    #
    elif len(args.files) == 1 and os.path.isdir(args.files[0]) :
        arg0 = args.files[0]
        # Strip out trailing "/" that may have been tacked on by
        # file completion.  (/bin/ls does not do this - but it's
        # cleaner looking.)
        if args.files[0][-1] == "/" :
            arg0 = args.files[0][:-1]
        if (not args.listDirContents) :
            print arg0
        else :
            if args.isRecursive:
                if args.prependPath == 0 :
                    print arg0 + ":"
                passedPath = arg0 + "/"
            else :
                passedPath = ""
            if args.prependPath == PATH_REL :
                passedPath = arg0 + "/"
            if args.prependPath == PATH_ABS :
                passedPath = os.getcwd() + "/"

            listSeqDir(stripDotFiles(os.listdir(arg0), args.ignoreDotFiles), arg0, False, args, passedPath)

    # List all the arguments on the command line and unless prevented by
    # the "-d" option, it will also list the contents of all the directories
    # entered on the command line as well.
    #
    else:
        passedPath = ""
        if args.prependPath == PATH_ABS :
            passedPath = os.getcwd() + "/"
        listSeqDir(args.files, "", True, args, passedPath)

if __name__ == '__main__':
    main()
