blob: 43553fc57a138041c49ab465eb590ffc512e6daa [file] [log] [blame]
#! /usr/bin/python3 -B
# Copyright 2018 Gavin D. Howard
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
#
# Release script for bc (to put into toybox).
# ***WARNING***: This script is only intended to be used by the project
# maintainer to cut releases.
import sys
import os
import subprocess
import regex as re
cwd = os.path.realpath(os.getcwd())
script = os.path.realpath(sys.argv[0])
testdir = os.path.dirname(script)
if len(sys.argv) < 2:
print("usage: {} toybox_dir".format(script))
sys.exit(1)
toybox = sys.argv[1].rstrip(os.sep)
toybox_bc = toybox + "/toys/pending/bc.c"
os.chdir(testdir)
os.chdir("../..")
res = subprocess.run(["make", "gen/lib.c"])
if res.returncode != 0:
sys.exit(res.returncode)
content = ""
with open(testdir + "/files.txt") as f:
files = f.read().splitlines()
for name in files:
if name == "gen/lib.c":
header_end = 2
else:
header_end = 22
with open(name) as f:
lines = f.readlines()
# Skip the header lines.
for i in range(header_end, len(lines)):
content += lines[i]
vm_c = "src/vm.c"
vm_c_stuff = ""
with open(vm_c) as f:
vm_c_lines = f.readlines()
for i in range(22, len(vm_c_lines)):
vm_c_stuff += vm_c_lines[i]
vm_c_replacements = [
[ '\t', ' ' ],
[ '\n [ ]*assert\(.*?\);$', '' ],
[ '^BcStatus bc_vm_exec\(unsigned int flags, BcVec \*exprs, BcVec \*files,' +
'\n[ ]*BcParseInit parse_init, BcParseExpr parse_expr\)\n\{',
'void bc_main(void) {\n' ],
[ '^ bcg.posix = flags & BC_FLAG_S;$', '' ],
[ '^ bcg.warn = flags & BC_FLAG_W;$', '' ],
[ '([^_])flags ', r'\1toys.optflags ' ],
[ 'files->len', 'toys.optc' ],
[ '\*\(\(char\*\*\) bc_vec_item\(files, i\)\)', 'toys.optargs[i]' ],
[ '^ bc_parse_free\(&vm\.parse\);', ' if (CFG_TOYBOX_FREE) bc_parse_free(&vm.parse);' ],
[ '^ bc_program_free\(&vm\.prog\);', ' if (CFG_TOYBOX_FREE) bc_program_free(&vm.prog);' ],
[ 'if \(\(s = bc_program_init\(&vm\.prog, len, parse_init, parse_expr\)\)\) return s;',
'if ((toys.exitval = bc_program_init(&vm.prog, len))) return;' ],
[ 'return s == BC_STATUS_QUIT \? BC_STATUS_SUCCESS : s;',
'toys.exitval = s == BC_STATUS_QUIT ? BC_STATUS_SUCCESS : s;' ],
[ 'vm->parse\.parse\(&vm', 'bc_parse_parse(&vm' ],
[ 'vm\.parse\.parse\(&vm', 'bc_parse_parse(&vm' ],
[ '^ return BC_STATUS_EXEC_SIGACTION_FAIL;$',
' toys.exitval = BC_STATUS_EXEC_SIGACTION_FAIL;\n return;' ],
[ '\(\(s = parse_init\(&vm\.parse, &vm\.prog\)\)\)', '((s = bc_parse_init(&vm.parse, &vm.prog)))' ],
[ '^[ ]*if \(exprs->len > 1 && \(s = bc_vm_process\(&vm, exprs->vec\)\)\) goto err;$', '' ],
[ 'if \(exprs->len <= 1\) s = bc_vm_stdin\(&vm\);$', 's = bc_vm_stdin(&vm);' ],
]
for rep in vm_c_replacements:
r = re.compile(rep[0], re.M | re.DOTALL)
vm_c_stuff = r.sub(rep[1], vm_c_stuff)
content += vm_c_stuff
regexes = [
'^#include .*$',
'^#ifndef BC.*_H$',
'^#define BC.*_H$',
'^#endif \/\/ BC.*_H$',
'^extern.*$',
'^static ',
'^#define BC_FLAG_X \(1<<0\)$',
'^#define BC_FLAG_W \(1<<1\)$',
'^#define BC_FLAG_S \(1<<2\)$',
'^#define BC_FLAG_Q \(1<<3\)$',
'^#define BC_FLAG_L \(1<<4\)$',
'^#define BC_FLAG_I \(1<<5\)$',
'^#define BC_FLAG_C \(1<<6\)$',
'^#define BC_INVALID_IDX \(\(size_t\) -1\)$',
'^#define BC_MAX\(a, b\) \(\(a\) > \(b\) \? \(a\) : \(b\)\)$',
'^#define BC_MIN\(a, b\) \(\(a\) < \(b\) \? \(a\) : \(b\)\)$',
'\n\n// This one is needed for dc too.$'
]
regexes_all = [
'\n#ifdef DC_CONFIG // Exclude.*?#endif // DC_CONFIG Exclude$',
'\n#ifdef DC_CONFIG.*?#else // DC_CONFIG$',
'\n#ifdef DC_CONFIG.*?#endif // DC_CONFIG$',
'\n#endif // DC_CONFIG$',
'\n#ifdef BC_CONFIG$',
'\n#else // BC_CONFIG.*?#endif // BC_CONFIG$',
'\n#endif // BC_CONFIG$',
'^#ifndef NDEBUG.*?^#endif \/\/ NDEBUG$',
'\n\t[\t]*assert\(.*?\);$',
'\#if !defined\(BC_CONFIG\).*?\#endif',
'\n[\t]*// \*\* Exclude start\. \*\*.*?^[\t]*// \*\* Exclude end\. \*\*$',
'^\tBC_STATUS_INVALID_OPTION,$',
'^\tl->next = next;$',
'^BcStatus bc_parse_init\(BcParse \*p, BcProgram \*prog\) \{.*?\}',
'^[\t]*p->parse = parse;$',
'^[\t]*p->parse_init = parse_init;$',
'^[\t]*p->parse_exp = parse_expr;$',
'!strcmp\(bcg\.name, bc_name\) && '
]
replacements = [
[ '\t', ' ' ],
[ 'bcg.posix', '(toys.optflags & FLAG_s)' ],
[ 'bcg.warn', '(toys.optflags & FLAG_w)' ],
[ 'bcg.', 'TT.' ],
[ 'BC_FLAG_Q', 'FLAG_q' ],
[ 'BC_FLAG_L', 'FLAG_l' ],
[ 'BC_FLAG_I', 'FLAG_i' ],
[ 'BC_FLAG_C', 'FLAG_c' ],
[ 'BC_MAX\(', 'maxof(' ],
[ 'BC_MIN\(', 'minof(' ],
[ 'BC_INVALID_IDX', '((size_t) -1)' ],
[ ' bool', ' int' ],
[ '^bool ', 'int ' ],
[ ' true', ' 1' ],
[ ' false', ' 0' ],
[ 'true', '1' ],
[ 'BcStatus bc_lex_init\(BcLex \*l, BcLexNext next\)', 'BcStatus bc_lex_init(BcLex *l)' ],
[ 'l->next\(l\)', 'bc_lex_token(l)' ],
[ '^BcStatus bc_parse_create\(BcParse \*p, BcProgram \*prog,\n[ ]*BcParseParse parse, BcLexNext next\)\n\{',
'BcStatus bc_parse_init(BcParse *p, BcProgram *prog) {' ],
[ 'BcStatus bc_program_init\(BcProgram \*p, size_t line_len,\n' +
'[ ]*BcParseInit parse_init, BcParseExpr parse_expr\)\n\{',
'BcStatus bc_program_init(BcProgram *p, size_t line_len) {\n' ],
[ 'if \(\(s = bc_lex_init\(&p->lex, next\)\)\) return s;', 'if ((s = bc_lex_init(&p->lex))) return s;' ],
[ 'p->parse_init\(', 'bc_parse_init(' ],
[ 'p->parse_exp\(', 'bc_parse_expr(' ],
[ '^BcStatus bc_program_pushVar\(BcProgram \*p, char \*code, size_t \*bgn, bool pop\)',
'BcStatus bc_program_pushVar(BcProgram *p, char *code, size_t *bgn)' ],
]
for reg in regexes:
r = re.compile(reg, re.M)
content = r.sub('', content)
for reg in regexes_all:
r = re.compile(reg, re.M | re.DOTALL)
content = r.sub('', content)
for rep in replacements:
r = re.compile(rep[0], re.M)
content = r.sub(rep[1], content)
with open(testdir + "/header.c") as f:
content = f.read() + content
content = re.sub('\n\n\n+', '\n\n', content)
os.chdir(cwd)
with open(toybox_bc, 'w') as f:
f.write(content)