#!/usr/bin/env python """ tdir - Display Formatted Directory Listings Copyright (c) 2001-2018 TundraWare Inc., All Rights Reserved. """ # python Library Imports import getopt import os import sys # Version info VERSION = "$Id: tdir,v 1.73 2018/06/17 00:00:00 tundra Exp $" # Supporting Functions # Found at: http://stackoverflow.com/questions/566746/how-to-get-console-window-width-in-python def GetTerminalSize(): env = os.environ def ioctl_GWINSZ(fd): try: import fcntl, termios, struct, os cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234')) except: return return cr cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2) if not cr: try: fd = os.open(os.ctermid(), os.O_RDONLY) cr = ioctl_GWINSZ(fd) os.close(fd) except: pass if not cr: cr = (env.get('LINES', 25), env.get('COLUMNS', 80)) ### Use get(key[, default]) instead of a try/catch #try: # cr = (env['LINES'], env['COLUMNS']) #except: # cr = (25, 80) return int(cr[1]), int(cr[0]) # End of 'GetTerminalSize()' # Output formatting constants. OWIDTH = 80 # Default output width fixed for non-*NIX systems if os.name == 'posix': # On *NIX get the current window parameter instead OWIDTH = GetTerminalSize()[0] - 1 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 DOTFILE = '.' # Dotfiles start with this # Defaults RECURSE = False # No recursion SHOWDIR = True # Show directories in listing SHOWDOT = True # Show dotfiles in listing SHOWFILE = True # Show files in listing SORTBYEXT = True # Sort file names by extension def OrderByExtension(list): ExtList = {} ExtList[""] = [] # List of files with no extension for x in list: y = x.rfind(SEP) if not y: # Handle special case of 'dot file' type files ext = "" name = x elif y != -1: # File has extension ext = x[y:] name = x[:y] if ext not in ExtList: ExtList[ext]= [] else: # File has no extension ext = "" name = x ExtList[ext].append(name) 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: if SORTBYEXT: ExtList = OrderByExtension(FileList) Ext = list(ExtList.keys()) Ext.sort() for x in Ext: FileList = ExtList[x] if len(FileList) > 0: FileList.sort() sys.stdout.write("(" + x + ")\n") OutputColumns(FileList, False) else: FileList.sort() OutputColumns(FileList, False) def BuildFileList (args, dir, files): DirList = [] FileList = [] for x in files: df = x.startswith(DOTFILE) # Track whether name is a 'dotfile/dir' 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 and (not df or SHOWDOT): DirList.append(x) elif SHOWFILE and (not df or SHOWDOT): FileList.append(x) DisplayOutput(dir, DirList, FileList) def Usage(): UsageInfo = ( ("tdir " + VERSION.split()[2] + " - Copyright (c) 2001-2018 TundraWare Inc., All Rights Reserved. \n", ""), (" usage: tdir [-DRdefhtv] [-c #] [-s c] [-w #] [dir...] where,\n\n", ""), ("-D", "Do not display dot files\n"), ("-R", "Recurse down each named directory tree\n"), ("-c #", "Column width\n"), ("-d", "Do not display directories in output\n"), ("-e", "Do not sort files by extension\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:], '-DRc:edfhs:tvw:') except getopt.GetoptError: Usage() sys.exit(2) for opt, val in opts: if opt == "-D": SHOWDOT = False if opt == "-R": RECURSE = True if opt == "-c": COLWIDTH = int(val) if opt == "-d": SHOWDIR = False if opt == "-e": SORTBYEXT = 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: for root, dir, files in os.walk(root): if root[-1] != os.sep: root += os.sep print(root) else: BuildFileList(None, root, os.listdir(root))