Newer
Older
tdir / tdir
#!/usr/local/bin/python
"""
tdir - Display Formatted Directory Listings
Copyright (c) 2001, TundraWare Inc., All Rights Reserved.
"""

# python Library Imports

import getopt
import os
import sys

# Version info

VERSION = "$Id: tdir,v 1.62 2001/07/17 16:55:04 tundra Exp $"


# Booleans

FALSE = 0 == 1
TRUE = not FALSE

# Output formatting constants.

OWIDTH = 80                 # Output width
COLWIDTH = 19               # Width of each column
TWIDTH = COLWIDTH - 1       # Text width
MAXCOL, INDENT = divmod(OWIDTH, COLWIDTH) # No of output cols & indent
PAD = " "                   # Padding character
SEP = "."                   # Filename "extension" separator
TRUNC = "^"                 # Character indicating name truncation

# Defaults

RECURSE = FALSE             # No recursion
SHOWDIR = TRUE              # Show directories in listing
SHOWFILE = TRUE             # Show files in listing


def OrderByExtension(list):
    ExtList = {}
    ExtList[""] = []             # List of files with no extension
    for x in list:
        y = x.rfind(SEP)
        if y != -1:                    # File has extension
            ext = x[y+1:]
            name =  x[:y]
            if not ExtList.has_key(ext):
                ExtList[ext]= []
            ExtList[ext].append(name)
        else:                    # File has no extension
            ExtList[""].append(x)
    return ExtList


def OutputColumns(list, ISDIRLIST):
    col = 0
    if ISDIRLIST:     # If listing directory, printed length
        BIAS = 2      # is longer by BIAS chars than actual name
    else:
        BIAS = 0
    for x in list:
        if col == MAXCOL:
            sys.stdout.write("\n")
            col = 0
        if len(x) > TWIDTH - BIAS:
            x = x[:TWIDTH - BIAS - 1 ] + TRUNC
        if ISDIRLIST:
            x = "[" + x + "]"
        if col == 0:
                sys.stdout.write(INDENT * PAD)
        sys.stdout.write(x + (COLWIDTH - len(x)) * PAD)
        col += 1
    sys.stdout.write("\n\n")
    

def DisplayOutput(dir, DirList, FileList):
    if (dir[-1] != "/") and (dir[-1] != "\\"):
        DIREND = "/\n"
    else:
        DIREND = "\n"
    sys.stdout.write(dir.replace("\\", "/") + DIREND)
    if SHOWDIR or SHOWFILE :
	sys.stdout.write("\n")
    if len(DirList) > 0:
        DirList.sort()
        OutputColumns(DirList, TRUE)
    if len(FileList) > 0:
        ExtList = OrderByExtension(FileList)
        Ext = ExtList.keys()
        Ext.sort()
        for x in Ext:
            FileList = ExtList[x]
            if len(FileList) > 0:
                FileList.sort()
                if x == "":
                    sep = x
                else:
                    sep = SEP
                sys.stdout.write("{" + sep + x + "}\n")
                OutputColumns(FileList, FALSE)

                                 
def BuildFileList (args, dir, files):
    DirList = []
    FileList = []
    for x in files:
        if (dir[-1] == '/') or (dir[-1] == '\\'):      # This if/else sequence necessary because
            dirstring = dir + x                        # 'tdir /' did not properly report directories
        else:                                          # on WinDoze32 systems which appears to
            dirstring = dir + "/" + x                  # handle '//' or '\/' in files names very well.
        if os.path.isdir(dirstring):
            if SHOWDIR:
                DirList.append(x)
        elif SHOWFILE:
            FileList.append(x)
    DisplayOutput(dir, DirList, FileList)


def Usage():
    UsageInfo = ( 
                 ("tdir " + VERSION.split()[2] +
                  " - Copyright (c) 2001, TundraWare Inc., All Rights Reserved. \n", ""),
                 ("  usage: tdir [-Rdfhtv] [-c #] [-s c] [-w #] [dir...]  where,\n\n", ""),
                 ("-R",      "Recurse down each named directory tree\n"),
                 ("-c #",    "Column width\n"),
                 ("-d",      "Do not display directories in output\n"),
                 ("-f",      "Do not display files in output\n"),
                 ("-h",      "Display this help information\n"),
                 ("-s c",    "Separator character\n"),
                 ("-t",      "Display only the directory tree - same as -Rdf\n"),
                 ("-v",      "Display tdir version information\n"),
                 ("-w #",    "Width of output\n"),
                 ("dir...",  "List of directories to display.  Defaults to ./\n")
                )

    for x, y in UsageInfo:
        if len(x) < 10:        # Only indent for the actual argument info
            sys.stdout.write(10 * PAD)
        sys.stdout.write(x)
        sys.stdout.write((8 - len(x)) * PAD)
        sys.stdout.write(y)

# Program entry and command line processing

try:
    opts, args = getopt.getopt(sys.argv[1:], '-Rc:dfhs:tvw:')
except getopt.GetoptError:
    Usage()
    sys.exit(2)
    
for opt, val in opts:
    if opt == "-R":
        RECURSE = TRUE
    if opt == "-c":
        COLWIDTH = int(val)
    if opt == "-d":
        SHOWDIR = FALSE
    if opt == "-f":
        SHOWFILE = FALSE
    if opt == "-h":
        Usage()
        sys.exit(0)
    if opt == "-s":
         SEP = val[0]
    if opt == "-t":
         RECURSE = TRUE
         SHOWDIR = FALSE
         SHOWFILE = FALSE
    if opt == "-v":
        sys.stdout.write(VERSION + "\n")
        sys.exit(0)
    if opt == "-w":
        OWIDTH = int(val)

if OWIDTH < COLWIDTH:
     sys.stdout.write("Huh? Column width exceeds output width!\n")
     sys.exit(2)
    
TWIDTH = COLWIDTH - 1       # Text width
MAXCOL, INDENT = divmod(OWIDTH, COLWIDTH) # No of output cols & indent

if len(args) == 0:          # Default to local directory if none given
    args = ["./"]

for root in args:
     if not os.path.isdir(root):
          sys.stdout.write(root + " is not a directory!\n")
          sys.exit(2)                           
     if RECURSE:
          os.path.walk(root, BuildFileList, None)
     else:
          BuildFileList(None, root, os.listdir(root))