2014-05-03 23 views
0

我想将文件数量转换为C中的静态字符串声明。我试图用Python编写一个快速脚本(如下所示),但它看起来并不简单,问题出现了,试图编译输出。将文件转换为静态C字符串声明

import os, sys 
from glob import glob 
from re import sub 

test_dirs = ('basics', 'float', 'import', 'io', 'misc') 
tests = sorted(test_file for test_files in (glob('{}/*.py'.format(dir)) for dir in test_dirs) for test_file in test_files) 

def cfunc_name(t): 
    return sub(r'/|\.|-', '_', t) 

for t in tests: 
    print("void {}(void* data) {{".format(cfunc_name(t))) 
    with open(t) as f: 
    lines = ''.join(f.readlines()) 
    cstr = sub('"', '\\"', lines) 
    cstr = sub('\n', '\"\n\"', cstr) 
    print(" const char * pystr = \"\"\n\"{}\";".format(cstr)) 
    print("end:\n ;\n}") 

print("struct testcase_t core_tests[] = {") 

for t in tests: 
    print(" {{ \"{}\", test_{}_fn, TT_ENABLED_, 0, 0 }},".format(t, cfunc_name(t))) 

print("END_OF_TESTCASES };") 

寻找现有的工具是不完全明显(可能是我的搜索关键词是不完全正确)...有一个简单的UNIX工具,做这样或有没有人遇到类似的东西来吗?

回答

1

这是否适合您? https://code.google.com/p/txt2cs/

我能想到的主要问题是新线条和逃跑,如果你想自己推出。

+2

非打印/控制字符(你所提到的新行)和正确的字符编码也很重要。 – Deduplicator

+0

我设法绕过换行符和内部双引号,但是像_“十六进制转义序列超出范围”这样的编译器错误_有点极端,我真的不想处理(除非必须)。 – errordeveloper

+0

我真的认为你会更好地使用链接的项目(这不是我的项目)。你发布的代码真的很离谱。 'sub('\ n','\'\ n \'',cstr)'应该是'sub(“\ n”,'\\ n',cstr)''''''如果我正在写东西,我会替换这些:http://en.cppreference.com/w/cpp/language/escape加上不在32-127之间的任何字符。请注意,\ xHH语法只能编码一个*字节*,即0-255--所以要小心python的Unicode处理,除非您使用\ u或\ U而不是 – teambob

0

我已经使用txt2cs实现作为参考,最后只用了几行Python来完成所有转义。由于我不想在构建系统中添加额外的东西,因此在Python中完成这项工作会更容易。这将被集成到测试自动化中,这已经是一个复杂的野兽。

主要问题是RE替代必须按照一定的顺序完成,并不是实现此目的的理想工具。

import os, sys 
from glob import glob 
from re import sub 

def escape(s): 
    lookup = { 
    '\0': '\\0', 
    '\t': '\\t', 
    '\n': '\\n\"\n\"', 
    '\r': '\\r', 
    '\\': '\\\\', 
    '\"': '\\\"', 
    } 
    return "\"\"\n\"{}\"".format(''.join([lookup[x] if x in lookup else x for x in s])) 

def chew_filename(t): 
    return { 'func': "test_{}_fn".format(sub(r'/|\.|-', '_', t)), 'desc': t.split('/')[1] } 

def script_to_map(t): 
    r = { 'name': chew_filename(t)['func'] } 
    with open(t) as f: r['script'] = escape(''.join(f.readlines())) 
    return r 

test_function = (
    "void {name}(void* data) {{\n" 
    " const char * pystr = {script};\n" 
    " do_str(pystr);\n" 
    "}}" 
) 

testcase_struct = (
    "struct testcase_t {name}_tests[] = {{\n{body}\n END_OF_TESTCASES\n}};" 
) 
testcase_member = (
    " {{ \"{desc}\", {func}, TT_ENABLED_, 0, 0 }}," 
) 

testgroup_struct = (
    "struct testgroup_t groups[] = {{\n{body}\n END_OF_GROUPS\n}};" 
) 
testgroup_member = (
    " {{ \"{name}/\", {name}_tests }}," 
) 

test_dirs = ('basics', 'float', 'import', 'io', 'misc') 

output = [] 

for group in test_dirs: 
    tests = glob('{}/*.py'.format(group)) 
    output.extend([test_function.format(**script_to_map(test)) for test in tests]) 
    testcase_members = [testcase_member.format(**chew_filename(test)) for test in tests] 
    output.append(testcase_struct.format(name=group, body='\n'.join(testcase_members))) 

testgroup_members = [testgroup_member.format(name=group) for group in test_dirs] 

output.append(testgroup_struct.format(body='\n'.join(testgroup_members))) 

print('\n\n'.join(output)) 

下面是输出看起来像什么,你可以看到初始""\n'\\n\"\n\"'使相当多的可读:

void test_basics_break_py_fn(void* data) { 
    const char * pystr = "" 
"while True:\n" 
" break\n" 
"\n" 
"for i in range(4):\n" 
" print('one', i)\n" 
" if i > 2:\n" 
"  break\n" 
" print('two', i)\n" 
"\n" 
"for i in [1, 2, 3, 4]:\n" 
" if i == 3:\n" 
"  break\n" 
" print(i)\n" 
""; 
    do_str(pystr); 
}