66 lines
1.9 KiB
Python
66 lines
1.9 KiB
Python
import argparse
|
|
parser = argparse.ArgumentParser(description="Prints to stdout the patched document")
|
|
parser.add_argument('original', help='original document')
|
|
parser.add_argument('patch', help='patch file')
|
|
args = parser.parse_args()
|
|
|
|
fa = open(args.original,'r')
|
|
la = fa.read().split('\n')
|
|
# a workspace for us to edit, each element being a list that 1) originally contains a corresponding line
|
|
# in a, 2) may be emptied if that line is removed, 3) may be where we insert new content
|
|
ws = [[l] for l in la]
|
|
fp = open(args.patch,'r')
|
|
lp = fp.read().split('\n')
|
|
|
|
def str2intv(s):
|
|
if "," in s:
|
|
x, y = s.split(',')
|
|
else:
|
|
x, y = s, s
|
|
return int(x)-1, int(y)
|
|
|
|
def ws_rm(desc, lp, nb):
|
|
l,r = str2intv(desc)
|
|
for p in range(l,r):
|
|
nb += 1
|
|
assert lp[nb][:2] == "< "
|
|
assert ws[p][0] == lp[nb][2:],\
|
|
f"Patch file wants to delete '{lp[nb][2:]}', but originally line {p} is '{ws[p][0]}'"
|
|
ws[p] = list()
|
|
return nb + 1, l
|
|
|
|
def ws_insert(p, desc, lp, nb):
|
|
l,r = str2intv(desc)
|
|
for _ in range(l,r):
|
|
nb += 1
|
|
assert lp[nb][:2] == "> "
|
|
ws[p].append(lp[nb][2:])
|
|
return nb + 1
|
|
|
|
nb = 0
|
|
while nb < len(lp):
|
|
line = lp[nb]
|
|
if line:
|
|
assert line[0] != '<' and line[0] != '>', f"Expected description at line {nb}, but got {line}"
|
|
else:
|
|
nb += 1
|
|
continue
|
|
idx_d = line.find('d')
|
|
if idx_d != -1:
|
|
nb, _ = ws_rm(line[:idx_d], lp, nb)
|
|
continue
|
|
idx_a = line.find('a')
|
|
if idx_a != -1:
|
|
p = int(line[:idx_a]) - 1
|
|
nb = ws_insert(p, line[idx_a+1:], lp, nb)
|
|
continue
|
|
idx_c = line.find('c')
|
|
if idx_c != -1:
|
|
nb, p = ws_rm(line[:idx_c], lp, nb)
|
|
nb = ws_insert(p, line[idx_c+1:], lp, nb)
|
|
continue
|
|
assert False, f"Unreachable. Cannot parse line {nb}: {line}"
|
|
|
|
flatws = [line for _ in ws for line in _]
|
|
print('\n'.join(flatws), end="") # Don't want to print additional new line
|