聪明的软件工程师会利用软件来简化自己的工作,本人显然过于迟钝,直到最近才开窍,懂得去利用软件来简化写软件的工作量。
以前,一直在维护一套dvd解码的软件,这套软件规模,说大不大,说小也不小,大概100多万行,可是总是有做不完的客户定制工作需要经常打开或者关闭某些功能定义。按照传统的方法就是直接去修改h文件,然后保存,然后make all。
多年前,第一次编译Linux内核,在make之前要先make menuconfig,看了那个config的方式,印象很深刻,想说如果把这套方式用在手头的软件上是不是也可以呢?不过后来还是没有花太多时间去了解Linux的定制界面是如何实现,据说是用来一种比较高级的脚本语言来做。
有时候,灵感来临就是一瞬间,这一次我把它捕捉下来,因为我觉得这个做法比较简单,而且有一定的好玩性。说真的,我对Java script的认知真的很基础,之前没有做过任何项目,不过在过去的一个星期,加上五一假期闲中偷忙地囫囵吞枣式地恶补之后,基本上已经把功能完成了。下面发出来给大家观赏一下。
整个项目的构想是这样的:
1. 用java script写一个网页程序,可以在本地运行和显示用户的选项,比如默认的osd语言,是否支持循环播放,默认的dvd区码等等。
2. 用户在网页界面上选择完成之后,按保存按键,就会在本地生成一个h文件,这个h文件就是包含了相关的#define XXXX的头文件
3. 然后把这个h文件#include到源程序里面,就可以实现程序的定制。
下面是这个软件的界面,我直接把HTML代码嵌入进来了:
然后就是JS部分的设计:
在实现的过程中,有几个难题:
1. 确定用那几种控件来表达config文件里面的不同形式,这需要一些抽象思维和概括能力,唉,事实上我纠结了很久。不过总算把它work it out了。
我把所有定义归类为3种,第一种是最简单的,也就是支持还是不支持,只有2选一,然后表现出来的定义方式就是类似于
#define STH
或者
//#define STH
对于这一类定义,我提供一个单选框,也就是checkbox
对于第二种,就是多选一,如上面的55键还是44键,这种使用radio button来做
第三种类型,是给某个常量赋值,比如默认的osd语言,我采用select来做
2. 第2个难题其实也是从第一个里面来,就是如何从控件里面获取我需要的信息,也许我是对这些控件不熟,我一开始是看了好多例子,然后我发现与其看例子不如查手册。我最后的做法是把checkbox的value直接写成define里面的常量名,这样我在编码的时候就可以用来构造输出的文本。
3. 第三个难题是如何让html文件变成可扩展,也就是以后往里面增加选项的时候,不用同时更新业务部分的代码。这个其实也是结合上面2点,上面2点做好了,这个问题就不存在了。我的做法是:
var my_string;
var fso, file;
var ipt = document.getElementsByTagName("input");
var len = ipt.length;
var ipt_str = new Array(len - 2);
var sel = document.getElementsByTagName("select");
var sel_len = sel.length;
var sel_str = new Array(sel_len);
len -= 2;
//最后2个是按钮
for (var i = 0; i < len; i++) {
//alert("this is "+i);
//alert(i+ " type is "+ ipt[i].type);
if (ipt[i].type == "checkbox") {
if (ipt[i].checked) {
ipt_str[i] = "#define " + ipt[i].value;
} else {
ipt_str[i] = "//#define " + ipt[i].value;
}
} else if (ipt[i].type == "radio") {
if (ipt[i].checked) {
ipt_str[i] = "#define " + ipt[i].value;
} else {
ipt_str[i] = "//#define " + ipt[i].value;
}
}
}
for (var j = 0; j < sel_len; j++) {
sel_str[j] = "#define " + sel[j].name + " " + sel[j].options[sel[j].selectedIndex].text;
}
我在上面的代码里面定义了一个ipt_str[]数组,这个数组就是保存各个定义。
然后用for循环遍历各个控件的属性,然后把value取出来构造成我们最终想要的形式输出。
4. 最后一个难题,就是对于文件输出的支持,目前只有ie上面能正常,firefox是不支持的,还好我没有在这个问题上面纠结很久。反正我只需要这个功能能在本地使用就行,所以浏览器的兼容性不是我要考虑的问题。
下面把文件输出的代码贴上来:
fso = new ActiveXObject("Scripting.FileSystemObject");
if(fso.FolderExists("d:\\javascript") == false)
{
fso.CreateFolder("d:\\javascript");
}
file = fso.CreateTextFile("d:\\javascript\\cfg_js.h", true);
for ( i = 0; i < len; i++) {
file.WriteLine(ipt_str[i]);
}
for ( j = 0; j < sel_len; j++) {
file.WriteLine(sel_str[j]);
}
file.Close();
最后输出的文件是这样子的:
//#define SUPPORT_TV
//#define SUPPORT_ET_GAME64
//#define SUPPORT_ET_DVB
//#define INIT_REPEAT_ALL
#define USE_JDF_TFT
//#define USE_LONGTEN_TFT
//#define SUPPORT_FALSE_DPF
//#define GENERAL_PORTABLE_8202KA_64_DVD
#define GENERAL_PORTABLE_8202KD_64_DVD
#define USE_55KEYS_IR
//#define USE_44KEYS_IR
#define DEFAULT_OSD_ENGLISH
//#define DEFAULT_OSD_SPANISH
//#define DEFAULT_OSD_TURKISH
//#define DEFAULT_OSD_ITALIAN
//#define DEFAULT_OSD_ARABIC
//#define DEFAULT_OSD_ARABIC
//#define DEFAULT_OSD_RUSSIAN
//#define DEFAULT_OSD_KOREAN
//#define DEFAULT_OSD_PORTUGUESE
//#define DEFAULT_OSD_THAI
//#define DEFAULT_OSD_CHINESE
#define CUSTOM_LOGO logo_worldtech
#define VOL_VALUE 15
这样,这个小小的项目就介绍完了。