1. 4FipS.com
  2. Photos
  3. Videos
  4. Code
  5. Forums
  6. pfQuizzz
  7. About
#!/usr/bin/env python
header = """\
| fips_norm - A Simple tab and line ending normalization tool.       .
| (c) 2012-13 +++ Filip Stoklas, aka FipS, http://www.4FipS.com +++  .
| PRODUCT URL: http://code.4fips.com/fips_norm/                      .

import os
import sys
import argparse
from itertools import chain

def prepare_working_set(dirs, exts, rec):
    exts = [e.lower() for e in exts]
    files = chain(*[list_files(d, rec) for d in dirs]) # gather
    files = sorted(set([os.path.abspath(f) for f in files])) # flatten
    files = [f for f in files if f.lower().endswith(tuple(exts))] if "*" not in exts else files # filter
    return files

def list_files(root, rec):
    if rec: return [os.path.join(cur_root, fn) for cur_root, dirs, fnames in os.walk(root) for fn in fnames]
    else: return [os.path.join(root, fn) for fn in os.listdir(root) if os.path.isfile(os.path.join(root, fn))]

def normalize_file(fn, tab, eol_opt):
    status = "[ ]"
        with open(fn, "rb") as f: orig = f.read().decode("utf-8")
        norm = orig.replace('\t', tab)
        if eol_opt:
            tag = "<$$$" + "_EOL_" + "$$$>" 
            norm = norm.replace("\r\n", tag)
            norm = norm.replace('\r', tag)
            norm = norm.replace('\n', tag)
            norm = norm.replace(tag, eol_opt)
        if norm != orig:
            with open(fn, "wb") as f: f.write(norm.encode())
            status = "[o]"
    except IOError:
        status = "[x]"
    print("%s %s" % (status, fn))

def main(dirs, exts, rec, tab, eol_opt):
    fnames = prepare_working_set(dirs, exts, rec)
    for fn in fnames: normalize_file(fn, tab, eol_opt)
    print("[~] DONE")
description = """\
fips_norm is a simple tab and line ending normalization tool.
It allows to recursively scan one or more directories for specific
file types, and process them so that tabs get transformed into
spaces, and mixed line endings get corrected or converted.

It is very easy to use, just type:
fips_norm.py . --extension .cpp .h --tab-space 4 --recursive
fips_norm.py . --extension .cpp .h --line-ending nix --recursive

or simply:
fips_norm.py . -e .cpp .h -t 4 -l nix -r

for more help, type:
fips_norm.py --help

arg_help = {
 "dir" : "specify one or more directories to scan for files to normalize",
 "ext" : "specify one or more file types (extensions) to process, or use * for any file",
 "tab" : "(optional operation)\nspecify the number of space characters to insert for a tab (\\t)",
 "eol" : "(optional operation)\nspecify which line ending style to use:\n"
         "[win] ... DOS / Windows (CR-LF \\r\\n)\n[nix] ... UNIX / Linux / Mac OS X (LF \\n)\n[mac] ... Mac OS 9 Classic (CR \\r)",
 "rec" : "(optional behavior)\nscan files in the directories and sub-directories recursively"

if __name__ == "__main__":
    class Parser(argparse.ArgumentParser):
        def error(self, msg):
            sys.stderr.write("[x] ARGUMENT ERROR: '%s' !!!\n" % msg)
    desc = header + "\n\n" + description + "\n---";
    parser = Parser(description=desc, version=revision, formatter_class=argparse.RawTextHelpFormatter)
    parser.add_argument("directory", nargs='+', help=arg_help["dir"]) # required, 1...n dir(s)
    parser.add_argument("-e", "--extension", nargs='+', required=True, help=arg_help["ext"]) # required, 1...n ext(s)
    parser.add_argument("-t", "--tab-space", type=int, help=arg_help["tab"]) # optional
    parser.add_argument("-l", "--line-ending", choices=["win", "nix", "mac"], help=arg_help["eol"]) # optional
    parser.add_argument("-r", "--recursive", action="store_true", help=arg_help["rec"]) # optional
    cmd_args = parser.parse_args()
    tab = cmd_args.tab_space * ' ' if cmd_args.tab_space else '\t'
    eol_opt = { "win" : "\r\n", "mac" : '\r', "nix" : '\n' }[cmd_args.line_ending] if cmd_args.line_ending else None
    main(cmd_args.directory, cmd_args.extension, cmd_args.recursive, tab, eol_opt)