[Pythonmac-SIG] cheol (Content entry, sort of)
Gordon Worley
redbird@rbisland.cx
Wed, 18 Jul 2001 21:18:44 -0400
Okay, I promised, and thus I deliver. :-)
Below is my command line tool for changing the line ending characters
in text files. It supports regular expression pattern matching since
I'm not sure how well regular shell pattern expansion would work when
converted to work on Classic as well as OS X. As you might have
guessed, this is a command line tool (since I don't use MacPython
anymore, just Python on OS X), so if you want an interface someone
else is going to have to do it. Also, I decided not to include
en/detabbing, since this is a line ending changer and it wouldn't be
very Unixy if I started adding all sorts of features willy nilly (in
fact, I think I'm going to take out the pattern matching when I
officially release a version of this on my Web site since it's just
there to make it easy to add a Mac interface to). Oh, also, someone
might want to improve the converting to dos line endings, since it
will screw up the file if you type 'cheol -d dos_file.txt' (but I
rarely need to convert to dos line endings so I just don't worry
about it).
Finally, some of the variable names suck, and I know it, but that's
just me being a BOFH so that I will be assured to win all future
contests that want to use this code. ;-P
Oh, and as far as help, man page forthcoming. ;^)
cheol.py:
#!/usr/bin/python
"""
cheol: change end of line character
Copyright (C) 2000-2001 Gordon Worley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or any
later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
For a copy of the GNU General Public License, visit
<http://www.gnu.org/> or write to the Free Software Foundation, Inc.,
59 Temple Place--Suite 330, Boston, MA 02111-1307, USA.
To contact me, please visit my Web site at <http://homepage.mac.com/
redbird/> or e-mail me at <redbird@rbisland.cx>.
#history
#0.3 added help and ability to convert to mac and dos. Name changed
to cheol.py from unixify.pl.
#0.1 added recursion, uses Jurgen Hermann's FileMorpher
#0.0 just converts the given files
"""
__version__ = "cheol 0.3, Copyright Gordon Worley via the GNU
GPL.\nType -h for help"
#fn = filename
#this first part is not by me, but put right in this code
#so that everything can stay in one file :-)
#by Jurgen Hermann, from ASPN
import os, string
def replaceFile(oldname, newname):
""" Rename file 'oldname' to 'newname'.
"""
if os.name == 'nt' and os.path.exists(oldname):
# POSIX rename does an atomic replace, WIN32 rename
does not. :-(
try:
os.remove(newname)
except OSError, exc:
import errno
if exc.errno != errno.ENOENT: raise exc
# rename it
os.rename(oldname, newname)
class FileMorpher:
""" A class that enables a client to securely update an existing file,
including the ability to make an automated backup version.
"""
def __init__(self, filename, **kw):
""" The constructor takes the filename and some options.
backup -- boolean indicating whether you want
a backup file
(default is yes)
"""
self.filename = filename
self.do_backup = kw.get('backup', 0)
self.stream = None
self.basename, ext = os.path.splitext(self.filename)
def __del__(self):
if self.stream:
# Remove open temp file
self.__close()
os.remove(self.__tempfile())
def __tempfile(self):
return self.basename + ".tmp"
def __close(self):
""" Close temp stream, if open.
"""
if self.stream:
self.stream.close()
self.stream = None
def load(self):
""" Load the content of the original file into a string and
return it. All I/O exceptions are passed through.
"""
file = open(self.filename, "rt")
try:
content = file.read()
finally:
file.close()
return content
def save(self, content):
""" Save new content, using a temporary file.
"""
file = self.opentemp()
file.write(content)
self.commit()
def opentemp(self):
""" Open a temporary file for writing and return an
open stream.
"""
assert not self.stream, "Write stream already open"
self.stream = open(self.__tempfile(), "wt")
return self.stream
def commit(self):
""" Close the open temp stream and replace the original file,
optionally making a backup copy.
"""
assert self.stream, "Write stream not open"
# close temp file
self.__close()
# do optional backup and rename temp file to the correct name
if self.do_backup:
replaceFile(self.filename, self.basename + ".bak")
replaceFile(self.__tempfile(), self.filename)
#end part not by me
#begin part by me
import re
def convert(fn, pattern, mode, is_recv):
if is_recv:
if os.path.isdir(fn) and not os.path.islink(fn):
fns = os.listdir(fn)
for afn in fns:
convert(os.path.join(fn, afn),
pattern, mode, is_recv)
if re.match(pattern, fn) and not os.path.isdir(fn):
f = FileMorpher(fn)
temp = f.load()
if mode == 1:
temp = string.replace(temp, '\n\r', '\n')
temp = string.replace(temp, '\r', '\n')
elif mode == 0:
temp = string.replace(temp, '\n\r', '\r')
temp = string.replace(temp, '\n', '\r')
elif mode == 2:
#this code could be dangerous, but I don't do these
#conversions often enough to care :-P
temp = string.replace(temp, '\r', '\n')
temp = string.replace(temp, '\n', '\n\r')
stream = f.opentemp()
stream.write(temp)
f.commit()
help = """\
cheol: Converts EOL characters
%s [options] <path ...>
options
-r : recursive
-m : macify line endings
-u : unixify line endings
-d : dosify line endings
-p <pattern> : apply only to filenames matching <pattern>
-h : print help
path is a file or directory
"""
if __name__ == '__main__':
import sys, getopt
opts, args = getopt.getopt(sys.argv[1:], "hmudrp:")
mode = 1 #default is unix, 0 is mac, 2 is dos
is_recv = 0 #is recursive
pattern = ""
for opt in opts:
if opt[0] == "-r":
is_recv = 1
elif opt[0] == "-p":
pattern = opt[1]
elif opt[0] == "-m":
mode = 0;
elif opt[0] == "-u":
mode = 1;
elif opt[0] == "-d":
mode = 2;
elif opt[0] == "-h":
print help % sys.argv[0]
sys.exit(0)
if not args:
print __version__
for arg in args:
convert(arg, pattern, mode, is_recv);
--
Gordon Worley `When I use a word,' Humpty Dumpty
http://homepage.mac.com/redbird/ said, `it means just what I choose
redbird@rbisland.cx it to mean--neither more nor less.'
PGP: 0xBBD3B003 --Lewis Carroll