几年前,我成功地将一个23年历史的老代码库(总代码量为300,000行)转换为驼峰命名法。这只花费了两天时间,但还有一些剩余问题需要几个月才能解决。这种做法是让你的同事程序员非常恼火的好方法。
我认为简单、笨拙、类似 sed 的方法有其优势。在我的认知范围内,基于 IDE 的工具等不能做到以下几点:
- 不能修改没有通过 #ifdef 编译的代码。
- 不能修改注释中的代码。
而且该遗留代码必须在多个编译器/操作系统平台上进行维护(涉及大量 #ifdef 语句)。
不过,这种笨拙的 sed 类方法的主要缺点在于可能会无意中更改字符串(如关键字)。并且我只尝试过用于 C 语言,C++ 可能是另外一回事。
大致分为五个阶段:
1) Generate a list of tokens that you wish to change, and manually edit.
2) For each token in that list, determine the new token.
3) Apply these changes to your code base.
4) Compile.
5) Double-check via a manual diff, and do a final clean-up.
第一步,生成您想更改的令牌列表。命令如下:
cat *.[ch] | sed 's/\([_A-Za-z0-9][_A-Za-z0-9]*\)/\nzzz \1\n/g' | grep -w zzz | sed 's/^zzz //' | grep '_[a-z]' | sort -u > list1
将会在list1中产生:
st_atime
time_t
...
在这个示例中,您真的不想改变这两个令牌,因此请手动编辑列表以将它们删除。但是您可能会错过一些,所以为了本例的缘故,假设您保留这些。
第二步是生成一个脚本来进行更改。例如,使用以下命令:
cat list1 | sed 's/\(.*\)/glob_sub "\\<\1\\>" xxxx_\1/;s/\(xxxx_.*\)_a/\1A/g;s/\(xxxx_.*\)_b/\1B/g;s/\(xxxx_.*\)_a/\1C/g;s/\(xxxx_.*\)_t/\1T/g' | sed 's/zzz //' > list2
将 _a、_b、_c 和 _t 更改为 A、B、C 和 T,从而产生:
glob_sub "\<st_atime\>" xxxx_stAtime
glob_sub "\<time_t\>" xxxx_timeT
您只需要扩展它以涵盖 d、e、f、...、x、y、z,
我假设您已经为您的开发环境编写了类似于“glob_sub”的函数。(如果没有,请放弃。)我的版本(csh,Cygwin)如下:
#!/bin/csh
foreach file (`grep -l "$1" */*.[ch] *.[ch]`)
/bin/mv -f $file $file.bak
/bin/sed "s/$1/$2/g" $file.bak > $file
end
我的一些sed不支持--in-place选项,所以我必须使用mv命令。
第三步是将list2中的脚本应用于您的代码库。例如,在csh中使用source list2
命令。
第四步是编译。编译器(希望如此!)会抱怨xxxx_timeT
。实际上,它可能会对只有timeT
抱怨,但额外的xxx_
可以增加保险。所以对于time_t,您犯了一个错误。可以使用以下命令撤消:
glob_sub "\<xxxx_timeT\>" time_t
第五步也是最后一步是使用您喜欢的差异工具进行手动检查更改,然后通过删除所有不需要的
xxx_
前缀来进行清理。使用grep命令查找
"xxx_
也有助于检查字符串中的标记。 (实际上,添加_xxx后缀可能是个好主意。)