13257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel"""Helper class to quickly write a loop over all standard input files.
23257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
33257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielTypical use is:
43257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
53257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    import fileinput
63257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    for line in fileinput.input():
73257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        process(line)
83257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
93257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielThis iterates over the lines of all files listed in sys.argv[1:],
103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldefaulting to sys.stdin if the list is empty.  If a filename is '-' it
113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielis also replaced by sys.stdin.  To specify an alternative list of
123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielfilenames, pass it as the argument to input().  A single file name is
133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielalso allowed.
143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielFunctions filename(), lineno() return the filename and cumulative line
163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielnumber of the line that has just been read; filelineno() returns its
173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielline number in the current file; isfirstline() returns true iff the
183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielline just read is the first line of its file; isstdin() returns true
193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieliff the line was read from sys.stdin.  Function nextfile() closes the
203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielcurrent file so that the next iteration will read the first line from
213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielthe next file (if any); lines not read from the file will not count
223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieltowards the cumulative line count; the filename is not changed until
233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielafter the first line of the next file has been read.  Function close()
243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielcloses the sequence.
253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielBefore any lines have been read, filename() returns None and both line
273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielnumbers are zero; nextfile() has no effect.  After all lines have been
283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielread, filename() and the line number functions return the values
293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielpertaining to the last line read; nextfile() has no effect.
303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielAll files are opened in text mode by default, you can override this by
323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielsetting the mode parameter to input() or FileInput.__init__().
333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielIf an I/O error occurs during opening or reading a file, the IOError
343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielexception is raised.
353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielIf sys.stdin is used more than once, the second and further use will
373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielreturn no lines, except perhaps for interactive use, or if it has been
383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielexplicitly reset (e.g. using sys.stdin.seek(0)).
393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielEmpty files are opened and immediately closed; the only time their
413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielpresence in the list of filenames is noticeable at all is when the
423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniellast file opened is empty.
433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
443257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielIt is possible that the last line of a file doesn't end in a newline
453257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielcharacter; otherwise lines are returned including the trailing
463257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielnewline.
473257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
483257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielClass FileInput is the implementation; its methods filename(),
493257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniellineno(), fileline(), isfirstline(), isstdin(), nextfile() and close()
503257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielcorrespond to the functions in the module.  In addition it has a
513257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielreadline() method which returns the next input line, and a
523257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel__getitem__() method which implements the sequence behavior.  The
533257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielsequence must be accessed in strictly sequential order; sequence
543257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielaccess and readline() cannot be mixed.
553257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
563257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielOptional in-place filtering: if the keyword argument inplace=1 is
573257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielpassed to input() or to the FileInput constructor, the file is moved
583257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielto a backup file and standard output is directed to the input file.
593257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielThis makes it possible to write a filter that rewrites its input file
603257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielin place.  If the keyword argument backup=".<some extension>" is also
613257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielgiven, it specifies the extension for the backup file, and the backup
623257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielfile remains around; by default, the extension is ".bak" and it is
633257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldeleted when the output file is closed.  In-place filtering is
643257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldisabled when standard input is read.  XXX The current implementation
653257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldoes not work for MS-DOS 8+3 filesystems.
663257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
673257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielPerformance: this module is unfortunately one of the slower ways of
683257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielprocessing large numbers of input lines.  Nevertheless, a significant
693257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielspeed-up has been obtained by using readlines(bufsize) instead of
703257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielreadline().  A new keyword argument, bufsize=N, is present on the
713257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielinput() function and the FileInput() class to override the default
723257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielbuffer size.
733257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
743257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielXXX Possible additions:
753257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
763257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel- optional getopt argument processing
773257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel- isatty()
783257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel- read(), read(size), even readlines()
793257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
803257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel"""
813257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
823257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielimport sys, os
833257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
843257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel__all__ = ["input","close","nextfile","filename","lineno","filelineno",
853257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel           "isfirstline","isstdin","FileInput"]
863257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
873257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel_state = None
883257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
893257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielDEFAULT_BUFSIZE = 8*1024
903257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
913257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldef input(files=None, inplace=0, backup="", bufsize=0,
923257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel          mode="r", openhook=None):
933257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    """Return an instance of the FileInput class, which can be iterated.
943257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
953257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    The parameters are passed to the constructor of the FileInput class.
963257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    The returned instance, in addition to being an iterator,
973257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    keeps global state for the functions of this module,.
983257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    """
993257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    global _state
1003257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    if _state and _state._file:
1013257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        raise RuntimeError, "input() already active"
1023257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    _state = FileInput(files, inplace, backup, bufsize, mode, openhook)
1033257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    return _state
1043257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
1053257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldef close():
1063257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    """Close the sequence."""
1073257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    global _state
1083257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    state = _state
1093257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    _state = None
1103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    if state:
1113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        state.close()
1123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
1133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldef nextfile():
1143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    """
1153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    Close the current file so that the next iteration will read the first
1163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    line from the next file (if any); lines not read from the file will
1173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    not count towards the cumulative line count. The filename is not
1183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    changed until after the first line of the next file has been read.
1193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    Before the first line has been read, this function has no effect;
1203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    it cannot be used to skip the first file. After the last line of the
1213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    last file has been read, this function has no effect.
1223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    """
1233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    if not _state:
1243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        raise RuntimeError, "no active input()"
1253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    return _state.nextfile()
1263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
1273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldef filename():
1283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    """
1293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    Return the name of the file currently being read.
1303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    Before the first line has been read, returns None.
1313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    """
1323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    if not _state:
1333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        raise RuntimeError, "no active input()"
1343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    return _state.filename()
1353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
1363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldef lineno():
1373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    """
1383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    Return the cumulative line number of the line that has just been read.
1393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    Before the first line has been read, returns 0. After the last line
1403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    of the last file has been read, returns the line number of that line.
1413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    """
1423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    if not _state:
1433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        raise RuntimeError, "no active input()"
1443257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    return _state.lineno()
1453257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
1463257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldef filelineno():
1473257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    """
1483257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    Return the line number in the current file. Before the first line
1493257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    has been read, returns 0. After the last line of the last file has
1503257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    been read, returns the line number of that line within the file.
1513257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    """
1523257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    if not _state:
1533257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        raise RuntimeError, "no active input()"
1543257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    return _state.filelineno()
1553257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
1563257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldef fileno():
1573257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    """
1583257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    Return the file number of the current file. When no file is currently
1593257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    opened, returns -1.
1603257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    """
1613257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    if not _state:
1623257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        raise RuntimeError, "no active input()"
1633257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    return _state.fileno()
1643257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
1653257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldef isfirstline():
1663257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    """
1673257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    Returns true the line just read is the first line of its file,
1683257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    otherwise returns false.
1693257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    """
1703257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    if not _state:
1713257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        raise RuntimeError, "no active input()"
1723257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    return _state.isfirstline()
1733257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
1743257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldef isstdin():
1753257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    """
1763257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    Returns true if the last line was read from sys.stdin,
1773257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    otherwise returns false.
1783257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    """
1793257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    if not _state:
1803257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        raise RuntimeError, "no active input()"
1813257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    return _state.isstdin()
1823257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
1833257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielclass FileInput:
1843257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    """FileInput([files[, inplace[, backup[, bufsize[, mode[, openhook]]]]]])
1853257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
1863257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    Class FileInput is the implementation of the module; its methods
1873257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    filename(), lineno(), fileline(), isfirstline(), isstdin(), fileno(),
1883257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    nextfile() and close() correspond to the functions of the same name
1893257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    in the module.
1903257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    In addition it has a readline() method which returns the next
1913257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    input line, and a __getitem__() method which implements the
1923257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    sequence behavior. The sequence must be accessed in strictly
1933257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    sequential order; random access and readline() cannot be mixed.
1943257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    """
1953257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
1963257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def __init__(self, files=None, inplace=0, backup="", bufsize=0,
1973257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                 mode="r", openhook=None):
1983257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if isinstance(files, basestring):
1993257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            files = (files,)
2003257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        else:
2013257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if files is None:
2023257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                files = sys.argv[1:]
2033257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if not files:
2043257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                files = ('-',)
2053257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            else:
2063257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                files = tuple(files)
2073257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self._files = files
2083257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self._inplace = inplace
2093257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self._backup = backup
2103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self._bufsize = bufsize or DEFAULT_BUFSIZE
2113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self._savestdout = None
2123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self._output = None
2133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self._filename = None
2143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self._lineno = 0
2153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self._filelineno = 0
2163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self._file = None
2173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self._isstdin = False
2183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self._backupfilename = None
2193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self._buffer = []
2203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self._bufindex = 0
2213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        # restrict mode argument to reading modes
2223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if mode not in ('r', 'rU', 'U', 'rb'):
2233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            raise ValueError("FileInput opening mode must be one of "
2243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                             "'r', 'rU', 'U' and 'rb'")
2253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self._mode = mode
2263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if inplace and openhook:
2273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            raise ValueError("FileInput cannot use an opening hook in inplace mode")
2283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        elif openhook and not hasattr(openhook, '__call__'):
2293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            raise ValueError("FileInput openhook must be callable")
2303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self._openhook = openhook
2313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
2323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def __del__(self):
2333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.close()
2343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
2353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def close(self):
2363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        try:
2373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.nextfile()
2383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        finally:
2393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self._files = ()
2403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
2413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def __iter__(self):
2423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return self
2433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
2443257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def next(self):
2453257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        try:
2463257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            line = self._buffer[self._bufindex]
2473257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        except IndexError:
2483257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            pass
2493257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        else:
2503257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self._bufindex += 1
2513257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self._lineno += 1
2523257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self._filelineno += 1
2533257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            return line
2543257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        line = self.readline()
2553257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if not line:
2563257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            raise StopIteration
2573257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return line
2583257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
2593257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def __getitem__(self, i):
2603257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if i != self._lineno:
2613257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            raise RuntimeError, "accessing lines out of order"
2623257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        try:
2633257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            return self.next()
2643257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        except StopIteration:
2653257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            raise IndexError, "end of input reached"
2663257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
2673257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def nextfile(self):
2683257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        savestdout = self._savestdout
2693257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self._savestdout = 0
2703257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if savestdout:
2713257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            sys.stdout = savestdout
2723257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
2733257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        output = self._output
2743257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self._output = 0
2753257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        try:
2763257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if output:
2773257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                output.close()
2783257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        finally:
2793257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            file = self._file
2803257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self._file = 0
2813257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            try:
2823257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                if file and not self._isstdin:
2833257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    file.close()
2843257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            finally:
2853257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                backupfilename = self._backupfilename
2863257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                self._backupfilename = 0
2873257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                if backupfilename and not self._backup:
2883257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    try: os.unlink(backupfilename)
2893257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    except OSError: pass
2903257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
2913257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                self._isstdin = False
2923257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                self._buffer = []
2933257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                self._bufindex = 0
2943257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
2953257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def readline(self):
2963257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        try:
2973257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            line = self._buffer[self._bufindex]
2983257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        except IndexError:
2993257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            pass
3003257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        else:
3013257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self._bufindex += 1
3023257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self._lineno += 1
3033257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self._filelineno += 1
3043257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            return line
3053257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if not self._file:
3063257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if not self._files:
3073257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                return ""
3083257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self._filename = self._files[0]
3093257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self._files = self._files[1:]
3103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self._filelineno = 0
3113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self._file = None
3123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self._isstdin = False
3133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self._backupfilename = 0
3143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if self._filename == '-':
3153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                self._filename = '<stdin>'
3163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                self._file = sys.stdin
3173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                self._isstdin = True
3183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            else:
3193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                if self._inplace:
3203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    self._backupfilename = (
3213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        self._filename + (self._backup or os.extsep+"bak"))
3223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    try: os.unlink(self._backupfilename)
3233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    except os.error: pass
3243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    # The next few lines may raise IOError
3253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    os.rename(self._filename, self._backupfilename)
3263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    self._file = open(self._backupfilename, self._mode)
3273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    try:
3283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        perm = os.fstat(self._file.fileno()).st_mode
3293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    except OSError:
3303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        self._output = open(self._filename, "w")
3313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    else:
3323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        fd = os.open(self._filename,
3333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                                     os.O_CREAT | os.O_WRONLY | os.O_TRUNC,
3343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                                     perm)
3353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        self._output = os.fdopen(fd, "w")
3363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        try:
3373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                            if hasattr(os, 'chmod'):
3383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                                os.chmod(self._filename, perm)
3393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        except OSError:
3403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                            pass
3413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    self._savestdout = sys.stdout
3423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    sys.stdout = self._output
3433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                else:
3443257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    # This may raise IOError
3453257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    if self._openhook:
3463257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        self._file = self._openhook(self._filename, self._mode)
3473257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    else:
3483257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        self._file = open(self._filename, self._mode)
3493257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self._buffer = self._file.readlines(self._bufsize)
3503257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self._bufindex = 0
3513257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if not self._buffer:
3523257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.nextfile()
3533257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        # Recursive call
3543257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return self.readline()
3553257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
3563257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def filename(self):
3573257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return self._filename
3583257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
3593257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def lineno(self):
3603257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return self._lineno
3613257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
3623257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def filelineno(self):
3633257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return self._filelineno
3643257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
3653257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def fileno(self):
3663257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if self._file:
3673257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            try:
3683257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                return self._file.fileno()
3693257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            except ValueError:
3703257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                return -1
3713257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        else:
3723257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            return -1
3733257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
3743257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def isfirstline(self):
3753257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return self._filelineno == 1
3763257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
3773257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def isstdin(self):
3783257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return self._isstdin
3793257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
3803257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
3813257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldef hook_compressed(filename, mode):
3823257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    ext = os.path.splitext(filename)[1]
3833257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    if ext == '.gz':
3843257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        import gzip
3853257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return gzip.open(filename, mode)
3863257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    elif ext == '.bz2':
3873257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        import bz2
3883257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return bz2.BZ2File(filename, mode)
3893257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    else:
3903257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return open(filename, mode)
3913257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
3923257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
3933257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldef hook_encoded(encoding):
3943257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    import io
3953257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def openhook(filename, mode):
3963257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        mode = mode.replace('U', '').replace('b', '') or 'r'
3973257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return io.open(filename, mode, encoding=encoding, newline='')
3983257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    return openhook
3993257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
4003257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
4013257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldef _test():
4023257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    import getopt
4033257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    inplace = 0
4043257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    backup = 0
4053257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    opts, args = getopt.getopt(sys.argv[1:], "ib:")
4063257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    for o, a in opts:
4073257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if o == '-i': inplace = 1
4083257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if o == '-b': backup = a
4093257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    for line in input(args, inplace=inplace, backup=backup):
4103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if line[-1:] == '\n': line = line[:-1]
4113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if line[-1:] == '\r': line = line[:-1]
4123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        print "%d: %s[%d]%s %s" % (lineno(), filename(), filelineno(),
4133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                                   isfirstline() and "*" or "", line)
4143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    print "%d: %s[%d]" % (lineno(), filename(), filelineno())
4153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
4163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielif __name__ == '__main__':
4173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    _test()
418