Created
October 9, 2018 12:11
-
-
Save jcommelin/ab7b99ee1dcd9084e2f73a940e91bb40 to your computer and use it in GitHub Desktop.
Apply replacement script on file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/python3 | |
### Read a replacement script from stdin | |
### Read a filename from commandline args | |
### Output to stdout | |
### Replacement script has the following form | |
# ----eofmarker | |
# line:col:line:col | |
# multiline replacement | |
# text foobar quux | |
# eofmarker | |
# ----anothereof | |
# line:col:line:col | |
# etc etc etc | |
# anothereof | |
### The eofmarker can by any string (without newlines) | |
### The final newline of the replacement text is stripped. | |
### line:col:line:col are the coordinates | |
### of the begin and end of replacement | |
import sys | |
import functools | |
def eprint(msg): | |
print(msg, file=sys.stderr) | |
sys.exit(1) | |
scripts = [] | |
cur = {} | |
cur['lines'] = [] | |
status = 0 | |
for nr,line in enumerate(sys.stdin.readlines(),start=1): | |
line = line.rstrip() | |
if (status == 0): # at beginning of new chunk | |
if (line[0:4] == "----"): | |
cur['eof'] = line[4:] | |
status = 1 | |
else: | |
eprint("Illegal start of chunk in replacement script at line: " + str(nr)) | |
elif (status == 1): # parsing line and column numbers | |
try: | |
[sl1,sc1,sl2,sc2] = line.split(':') | |
(l1,c1,l2,c2) = (int(sl1),int(sc1),int(sl2),int(sc2)) | |
assert [sl1,sc1,sl2,sc2] == [str(l1),str(c1),str(l2),str(c2)] | |
assert l1 < l2 or (l1 == l2 and c1 <= c2) | |
cur['coords'] = (l1,c1,l2,c2) | |
except: | |
eprint("Illegal location line in replacement script at line: " + str(nr)) | |
status = 2 | |
elif (status == 2): | |
if (line == cur['eof']): | |
if len(cur['lines']) > 0: # drop newline of final replacement string | |
cur['lines'][-1] = cur['lines'][-1][:-1] | |
scripts += [cur] | |
cur = {} | |
cur['lines'] = [] | |
status = 0 | |
else: | |
cur['lines'] += line + '\n' | |
else: # shouldn't happen | |
eprint("Unreachable code was reached") | |
def subst(text,script): | |
(l1,c1,l2,c2) = script['coords'] | |
lines = script['lines'] | |
for nr,line in enumerate(text,start=1): | |
if nr < l1: | |
yield line | |
elif nr == l1: | |
if c1 > len(line): | |
eprint("Line is too short. Line number: " + str(nr)) | |
if len(lines) > 0: | |
lines[0] = line[0:c1] + lines[0] | |
else: | |
lines = [line[0:c1]] | |
if nr == l2: | |
if c2 > len(line): | |
eprint("Line is too short. Line number: " + str(nr)) | |
lines[-1] += line[c2:] | |
for l in lines: | |
yield l | |
elif nr > l2: | |
yield line | |
if nr < l1: | |
eprint("Replacement failed. File is too short.") | |
with open(sys.argv[1],"r+") as f: | |
for line in functools.reduce(subst,reversed(scripts),f.readlines()): | |
print(line,end='') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment