[Pythonmac-SIG] Re: batch convert line endings

Dean & Yang Draayer draayer@surfglobal.net
Sat, 21 Jul 2001 17:14:26 -0400


> What are people using to batch convert folders full of text files 
> that may have DOS or UNIX line endings to Mac line endings? I was 
> using Cyclone, but it is a pain in the butt as it prompts for each 
> file and also it does a lot more than convert line endings so it 
> is not really optimized just for that. I would love a little 
> droplet like Drop=EFBB or Drop RENAME, etc. that i could put on my 
> desk top and then drag and drop the folder on to it and have all 
> the files changed to Mac line endings. Of course, Mac to UNIX aor 
> DOS line endings would be good too! in case you wanted to send a 
> folder of stuff from your MAC to a Windoze or UNIX user.
> 
> cheers,
> -kp--


I use the following script, saved as an applet.  It only supports 
conversion to Mac-style endings.  It handles drag-and-drop from the 
Finder nicely - any combination of files and folders can be dropped on=
 it. 
 If double-clicked, it prompts for a file to convert.  Folders are 
traversed recursively.  Only files of type 'TEXT' are examined, and=
 only 
those showing non-Mac line endings are actually modified - their=
 pathnames 
are printed so you can see which ones were changed.  Modification=
 dates 
are preserved.  Mixed-style line endings with the same file are=
 handled - 
i.e. the conversion decision is made on a line-by-line basis, rather=
 than 
based on the first line only.  The entire file is read into memory in=
 one 
fell swoop, so large files will be skipped if there's not enough=
 memory.

BEWARE - the original files are overwritten without backing them up!  
(This really needs to be fixed.)  Use at your own risk!

#=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D
# MacLineEndings.py
#   Author: Dean Draayer
#   Date: 16 June 2000
#-------------------------------------------------------
# Converts TEXT files to use mac-style line endings.
# CRLF pairs and lone LFs are changed to CRs.
# Usage: Drop folders and individual files on the applet
#   to convert them.  Folders are walked recursively.
#=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D

import string
from os import path
from sys import argv, exit
from macfs import FSSpec, StandardGetFile

#--- globals ---
numItems =3D 0        # count of number of files actually modified

CR =3D chr(13)
LF =3D chr(10)
CRLF =3D CR + LF


def handleNoArgs():
    (fs, OK) =3D StandardGetFile()
    if OK:                          # user selected something
        return [fs.as_pathname()]   # simulate a one-arg drop
    else:
        exit()                      # user cancelled


def startUp(theArgs):
    print "Running %s..." % path.split(argv[0])[1]


def finishUp(theArgs):
    print "...done. Modified %d files." % numItems


def doArg(anArg):
    if path.isdir(anArg):
        path.walk(anArg, doArg_aux, None)
    else:
        doItem(anArg)

def doArg_aux(arg, parPath, fNames):
    for fName in fNames:
        doItem(path.join(parPath, fName))


def doItem(aPath):
    global numItems

    if path.isdir(aPath):
        return
    fs =3D FSSpec(aPath)
    (fCreat, fType) =3D fs.GetCreatorType()
    if (fType <> 'TEXT'):
        return

    fp =3D open(aPath, 'rb')
    try:
        try:
            data =3D fp.read()
        finally:
            fp.close()
    except MemoryError:
        from MacOS import SysBeep
        SysBeep()
        print "*** FILE TOO BIG! ***  Ignoring", aPath
        return

    if (string.find(data, LF) =3D=3D -1):   # nothing to do if there=
 are no LFs
        return

    print aPath

    # Note: It's important to replace CRLFs before LFs!!!
    data =3D string.replace(data, CRLF, CR)
    data =3D string.replace(data, LF, CR)
    
    savedDates =3D fs.GetDates()          # preserve modification date
    fp =3D open(aPath, 'wb')
    try:
        fp.write(data)
    finally:
        fp.close()
    fs.SetDates(savedDates[0], savedDates[1], savedDates[2])

    numItems =3D numItems + 1


def run(theArgs =3D None):
    global numItems
    numItems =3D 0

    if not theArgs:
        theArgs =3D handleNoArgs()    # handle no-argument situation

    startUp(theArgs)                # perform pre-processing
    map(doArg, theArgs)             # process each argument
    finishUp(theArgs)               # perform post-processing


if __name__ =3D=3D "__main__":
    run(argv[1:])

#=3D=3D=3D end MacLineEndings.py =3D=3D=3D

Sorry about the length of this post!

Dean Draayer
draayer@surfglobal.net