diff options
| author | Neil <nyamatongwe@gmail.com> | 2013-07-01 16:27:22 +1000 | 
|---|---|---|
| committer | Neil <nyamatongwe@gmail.com> | 2013-07-01 16:27:22 +1000 | 
| commit | c47b81b98f01cf84f5559adae256bff58b54005f (patch) | |
| tree | 811de80df7364b1ee026097542eb554b66876014 | |
| parent | 2af1cdfe0d46bfabfc0ec29f6a0b549ab255bea8 (diff) | |
| download | scintilla-mirror-c47b81b98f01cf84f5559adae256bff58b54005f.tar.gz | |
Refactoring Python scripts into scripts directory.
| -rw-r--r-- | scripts/FileGenerator.py | 150 | 
1 files changed, 150 insertions, 0 deletions
| diff --git a/scripts/FileGenerator.py b/scripts/FileGenerator.py new file mode 100644 index 000000000..601030cbb --- /dev/null +++ b/scripts/FileGenerator.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python +# FileGenerator.py - implemented 2013 by Neil Hodgson neilh@scintilla.org +# Released to the public domain. + +# Generate or regenerate source files based on comments in those files. +# May be modified in-place or a template may be generated into a complete file. +# Requires Python 2.4 or later +# The files are copied to a string apart from sections between a +# ++Autogenerated comment and a --Autogenerated comment which is +# generated by the CopyWithInsertion function. After the whole string is  +# instantiated, it is compared with the target file and if different the file  +# is rewritten. + +import codecs, os, string, sys + +lineEnd = "\r\n" if sys.platform == "win32" else "\n" + +def UpdateFile(filename, updated): +    """ If the file contents are different to updated then copy updated into the +    file else leave alone so Mercurial and make don't treat it as modified. """ +    newOrChanged = "Changed" +    try: +        with codecs.open(filename, "r", "utf-8") as infile: +            original = infile.read() +        if updated == original: +            # Same as before so don't write +            return +        os.unlink(filename) +    except IOError:	# File is not there yet +        newOrChanged = "New" +    with codecs.open(filename, "w", "utf-8") as outfile: +        outfile.write(updated) +    print("%s %s" % (newOrChanged, filename)) + +# Automatically generated sections contain start and end comments, +# a definition line and the results. +# The results are replaced by regenerating based on the definition line. +# The definition line is a comment prefix followed by "**". +# If there is a digit after the ** then this indicates which list to use +# and the digit and next character are not part of the definition +# Backslash is used as an escape within the definition line. +# The part between \( and \) is repeated for each item in the list. +# \* is replaced by each list item. \t, and \n are tab and newline. +# If there is no definition line than the first list is copied verbatim. +# If retainDefs then the comments controlling generation are copied. +def CopyWithInsertion(input, commentPrefix, retainDefs, lists): +    copying = 1 +    generated = False +    listid = 0 +    output = [] +    for line in input.splitlines(0): +        isStartGenerated = line.lstrip().startswith(commentPrefix + "++Autogenerated") +        if copying and not isStartGenerated: +            output.append(line) +        if isStartGenerated: +            if retainDefs: +                output.append(line) +            copying = 0 +            generated = False +        elif not copying and not generated: +            # Generating +            if line.startswith(commentPrefix + "**"): +                # Pattern to transform input data +                if retainDefs: +                    output.append(line) +                definition = line[len(commentPrefix + "**"):] +                if (commentPrefix == "<!--") and (" -->" in definition): +                    definition = definition.replace(" -->", "") +                listid = 0 +                if definition[0] in string.digits: +                    listid = int(definition[:1]) +                    definition = definition[2:] +                # Hide double slashes as a control character +                definition = definition.replace("\\\\", "\001") +                # Do some normal C style transforms +                definition = definition.replace("\\n", "\n") +                definition = definition.replace("\\t", "\t") +                # Get the doubled backslashes back as single backslashes +                definition = definition.replace("\001", "\\") +                startRepeat = definition.find("\\(") +                endRepeat = definition.find("\\)") +                intro = definition[:startRepeat] +                out = "" +                if intro.endswith("\n"): +                    pos = 0 +                else: +                    pos = len(intro) +                out += intro +                middle = definition[startRepeat+2:endRepeat] +                for i in lists[listid]: +                    item = middle.replace("\\*", i) +                    if pos and (pos + len(item) >= 80): +                        out += "\\\n" +                        pos = 0 +                    out += item +                    pos += len(item) +                    if item.endswith("\n"): +                        pos = 0 +                outro = definition[endRepeat+2:] +                out += outro +                out = out.replace("\n", lineEnd) # correct EOLs in generated content +                output.append(out) +            else: +                # Simple form with no rule to transform input +                output.extend(lists[0]) +            generated = True +        if line.lstrip().startswith(commentPrefix + "--Autogenerated") or \ +            line.lstrip().startswith(commentPrefix + "~~Autogenerated"): +            copying = 1 +            if retainDefs: +                output.append(line) +    output = [line.rstrip(" \t") for line in output] # trim trailing whitespace +    return lineEnd.join(output) + lineEnd + +def GenerateFile(inpath, outpath, commentPrefix, retainDefs, *lists): +    """Generate 'outpath' from 'inpath'. +    """ + +    try: +        with codecs.open(inpath, "r", "UTF-8") as infile: +            original = infile.read() +        updated = CopyWithInsertion(original, commentPrefix, +            retainDefs, lists) +        UpdateFile(outpath, updated) +    except IOError: +        print("Can not open %s" % inpath) + +def Generate(inpath, outpath, commentPrefix, *lists): +    """Generate 'outpath' from 'inpath'. +    """ +    GenerateFile(inpath, outpath, commentPrefix, inpath == outpath, *lists) + +def Regenerate(filename, commentPrefix, *lists): +    """Regenerate the given file. +    """ +    Generate(filename, filename, commentPrefix, *lists) + +def UpdateLineInFile(path, linePrefix, lineReplace): +    lines = [] +    updated = False +    with codecs.open(path, "r", "utf-8") as f: +        for l in f.readlines(): +            l = l.rstrip() +            if not updated and l.startswith(linePrefix): +                lines.append(lineReplace) +                updated = True +            else: +                lines.append(l) +    contents = lineEnd.join(lines) + lineEnd +    UpdateFile(path, contents) | 
