衷心感谢 北京GNOME用户组 - 張韡武 老师给我这次参与开源项目的机会,我会珍惜这次机会,用心去实现项目需求,这个项目是一个很好的加入开源社区的入口项目,通过这个项目能更好的了解、使用、参与、服务开源。顺便仰慕下像张老师这样思想与脚步一直在路上的大神。
下面是结合开题报告和与张老师的邮件交流后对项目的整体理解与设计。
项目提案参见http://code.csdn.net/os_camp/16/proposals/65
项目详细需求参见http://www.realss.com/foldcolumn_requirements.html
foldcolumn工具的应用价值已经在项目提案中提到,针对上面的提案和详细需求,我认为本项目的总体目标是构建一个方便用在管道上的命令行工具和一个便于其它命令行软件链接使用的库,这个命令行工具和库的目的是将输入数据按照表格形式输出,用户可以指定表格宽度、列宽、表格样式等。
在设计实现的时候恰好反过来,即:
(1)构建表格化数据输出库libfoldcolumn,这个库可供其他程序链接调用实现表格数据的输出;
(2)使用libfoldcolumn库构建命令行工具foldcolumn,这也相当于是对libfoldcolumn库的测试。
有下面三种方法可供用户选择,具体参见下面命令行参数解析:
(1)均分表格宽度;
(2)用户指定每列宽度,或者指定部分列宽度,其他列均分剩余宽度;
这两种方法容易实现,而且不仅适用与从文件读入数据,同样适用于通过管道读入数据;
(3)项目详细需求中提到的高增琦列宽选择算法,但是这种方法需要预先扫描一遍文件确定列宽,再重新读入文件内容进行表格输出,因此这种方法只适用与从文件输入数据。
这里需要注意:每列的最小宽度:2个半角英文字符宽度,各列宽度之和不能超过表格宽度;
foldcolumn以第一行(实际表格形式的第一行)列数为准,需要用户自己确保文件中每行的列数相同,如果每行的列数不相同,那么:如果后面表格行列数超过第一行列数,那么超出的列会被略去;如果后面行中列数少于第一行列数,那么后面缺少的列按空列处理。
超过列宽换行时,不能分割英文单词、不能分割中文字的多个字节,还有就是行首不能是标点符号等,这里借助吴咏伟liblinebreak开源库实现。
(1)字符编码和兼容性参照heirloom(http://heirloom.sourceforge.net/),heirloom是unix工具集,所以foldcolumn最终也是具有posix特性的unix工具,暂不兼容windows;
(2)命令行参数与相似项目(如groff)保持一致,这样方便用户熟悉使用。
/*table style*/ typedef enum foco_table_t{ foco_TABLE_T,/*use Tab (actually two blanks) to separate columns*/ foco_TABLE_H,/*use horizontal line to separate lines , Tab (actually two blanks) to separate columns*/ foco_TABLE_V,/*use '|' to separate columns, empty line to separate rowss*/ foco_TABLE_B/*use box-drawing character (Unix,CP/M,BBS) to draw table*/ }foco_table_t; /*column alignment*/ typedef enum foco_align_t{ foco_ALIGN_LEFT, foco_ALIGN_RIGHT }foco_align_t; typedef struct foco_t{ foco_table_t table;/*table style, refer to struct foco_table_t*/ int width; /*table width*/ char delimiter; /*delimiter between columns*/ int columnSize; /*table's column number, user can not specify it. It equals with the column number in the first line*/ int *widths; /*column width has been specified by user,widths[i] specifies column i width*/ int widthSize; /*number of widths' element,-1 for specifying column width by reading file one time *after specifying all column width ,it equals with table's column number */ int precision; /*precision for float/double*/ foco_align_t*alignment;/*alignment[i] specifies column i alignment,i starts with 0*/ char *lines; /*line starting with lines will not be broken into columns*/ bool *columns; /*if columns[i] is true , it shows that this column need not to line break, i starts with 0*/ FILE *out; /*print table into out (stdout default)*/ bool wide; /*if the out stream has not been specified oriention, *true for using wide-character oriented I/O functions such as fputwc; *false for using narrow-character oriented I/O functions such as fputc; */ bool *numeric;/*if numeric[i] is true , it shows that this column of the intput line may need to process precision, i starts with 0*/ bool *isNumeric;/*if isNumeric[i] is true, it shows that this column of the intput line really need to process precision, i starts with 0*/ /*user can not specify isNumeric*/ bool blank; /*when blank is true, will print empty lines*/ char *lang; char *locale; }foco_t;
/** * Init foco_t's attributes with default values * @param[in] pFoco its attributes contain all information to draw table. */ void foco_init(foco_t*pFoco); /** * Free foco_t's attributes, but not free the foco_t pointer * @param[in] pFoco its attributes contain all information to draw table. */ void foco_destroy(foco_t*pFoco); /** * Read each line in the input files to draw table according to pFoco attributes * @param[in] pFoco its attributes contain all information to draw table * @param[in] inputs input files * @param[in] type shows inputs is FILE** or file name of c string value pointer * foco_ARGV_FP for FILE* * * foco_ARGV_FN for char* * * @param[in] num input files' number * @return line number in all the input files */ int foco_foldcolumn(foco_t*pFoco,void*inputs,foco_argv_t type,int num);
foldcolumn命令行工具通过链接调用libfoldcolumn库函数实现,所以主要是考虑命令行参数设计与解析,然后通过命令行参数值来对foco_t结构体变量赋值,然后循环读入数据行,并调用相应的libfoldcolumn库函数实现。
这里的命令行参数有些与项目需求中不一致,参数遵循System V风格(即带横线)如下:
foldcolumn [OPTION]... [FILE]...
从FILE文件中读入数据,如果不给出文件名,默认情况是从标准输入读入数据,然后对数据进行表格化,输出到标准输出。
-d, --delimiter=DELIMITER
表格列分隔符,默认是'\t',仅限与ascii码内的可打印字符和'\t',不能是数字和字母;
-w, --width=WIDTH
表格的总宽度,默认值终端宽度/80;
-W, --widths=LIST
每列宽度,参数值是一个逗号分隔的数字串,参数值可选,表示各列宽度,如-W100 -w "20,10,15",表示前3列分别占20,10,15,后面几列均分55,当然不给出参数值就是所有列均分表格宽度;如果不指定-w,使用“高增琦--张韡武”算法来确定每列的宽度,但是这时需要先读一遍文件,所以不适合命令行管道模式;
-p, --precision=PRECISION
数字处理,浮点数精度,默认是3位;
-a, --align=ALIGN
ALIGN是一个逗号分隔的数字串,这些数字代表采用右对齐的列号,从1开始,未列出的列使用左对齐。如果不指定a,各列默认是左对齐;
-i, --ignore=LINE
对以LINE开头的行,不进行分列,原样输出,但是超过表格宽度还是要换行的;
-c, --column=LIST
对列号为NO(默认逗号分隔)的列不进行换行,用最宽数据作为该列的宽度,参数只对从文件读入数据的情况有效;
-t, --table=0/1/2/3
表格样式,参见解决方案二
-o, --out=output filename
输出文件名,缺省是标准输出;
-A,--append
以追加方式输出,默认是覆盖,文件不存在自动创建;
-l,--lang=LANG
-L,--locale=LOCALE
-h, --help
显示帮助信息;
-v, --version
显示foldcolumn版本;
研究室里面使用的是svn,git很少使用,所以先熟悉了下git的使用基本操作,然后在csdn的code创建了项目进行了练习。
foldcolumn要使用liblinebreak库进行换行处理,所以需要学习liblinebreak,现在只是大致看了下liblinebreak,并且通过breaktext了解了liblinebreak的基本用法,接下来需要深入学习下。
liblinebreakhttps://github.com/adah1972/libunibreak/wiki
heirloom项目http://heirloom.sourceforge.net/
foldcolumn代码托管https://code.csdn.net/xhu_eternalcc/foldcolumn