Adam's

adam@debian:~$ cat /dev/random

Archive for the ‘Coding’ Category

在IRC中输入彩色文字

with 8 comments

IRC中竟然还可以发送彩色文字, 真好玩儿. 像这样:

各个client有自己的文档, 大致通用, Irssi的在这里.

eexpress写了个脚本生成随机颜色, 但是用起来麻烦. 去Irssi官网上逛了逛, 发现还真有这样的插件, 只是不支持中文. 于是稍微改了下, 添加了UTF-8的支持, 上图就是修改之后的效果.

修改后的脚本已经发到了Irssi scripts维护邮箱, 应该很快就会更新, 等不及的直接去这里下载. 欢迎反馈.

Written by adam8157

September 16th, 2011 at 11:47 pm

Posted in Coding,Linux

Tagged with

用vim处理svn的conflicts

without comments

半年之前就用vimdiff取代了svn的diff(传送门), 但是冲突处理没能用vim实现, 一直耿耿于怀, 这几天终于忍不住收拾了下.

svn处理merge是用的diff3, 顺利合并就返回0, 合并错误就给出选项询问如何解决. 传统的外部工具处理方式也是从这里hook, 比如kdiff3, 先合并, 顺利合并就往下走, 合并错误就出一个用于merging的界面给你编辑, 手动处理后返回0退出.

但是vim并没有实现diff3, 所以hook这里并不合适. 还好, 1.5版的svn引入了交互式的冲突解决方式, 其中有用外部工具处理冲突的”l”. 和你写diff3的wrapper脚本不同的是, 这个只有在diff3不能顺利处理合并的时候才会启动, 容易处理得多, 只需要写个很简单的脚本, 然后将svn配置里的merge-tool-cmd指向它就好.

#!/bin/sh

# Configure your favorite merge program here.
MERGE="vim -d"

if [ -z $2 ]
then
	echo ERROR: This script expects to be called by subversion
	exit 1
fi

# Subversion provides the paths we need as the first, second, third
# and fourth parameters.
BASE=${1}
THEIRS=${2}
MINE=${3}
MERGED=${4}

# Call the merge command (change the following line to make sense for
# your merge program).
$MERGE $MERGED -c ":diffsplit $MINE" -c ":vertical diffsplit $THEIRS" \
	-c ":vertical diffsplit $BASE"

# Return an errorcode of 0 on successful merge, 1 if unresolved conflicts
# remain in the result.  Any other errorcode will be treated as fatal.
exit 0

Enjoy it.

Written by adam8157

January 24th, 2011 at 7:37 pm

Posted in Coding,Tips

Tagged with , ,

有意思的lea指令

with 7 comments

最近恶补汇编时发现lea指令很有意思, 但大部分书都把它一笔带过, 同时网上的资料又很少, 所以记一下.

lea, load effective address, 加载有效地址. 指令形式是从存储器读数据到寄存器, 效果是将存储器的有效地址写入到目的操作数, 简单说, 就是C语言中的”&”.

例如在32位环境下, 有内存位置标签foo, 则下面两行效果相同:

movl $foo, %edi
leal foo, %edi

同时, lea还有个很有用但同时又很难理解的用法, 例如这样:

leal 5(%edx, %edx, 2), %eax

假设%edx的值为x, 上面这行会将%eax的值设置为”3x+5″.

奇怪吧, 一个取址的指令怎么用来做简单算术操作了? 其实理解起来也不难, 5(%edx, %edx, 2)是存储器”3x+5″这个地址中的值, 这个值作为leal的源操作数会被取地址, 地址是什么? 自然就是”3x+5″!

值得注意的是, 不管是AT&T还是Intel语法, lea都是加载有效地址, 所以运算结果需得在地址空间能表示的大小范围内.

PS: 可能有人会问为什么不把源操作数写成5(, %edx, 3), 这个嘛, 因为这种寻址模式的比例因子只能是1, 2, 4或者8.

Written by adam8157

January 5th, 2011 at 10:29 pm

Posted in Coding

Tagged with

第一个patch

with 3 comments

今天很高兴, 我第一次提交patch就被接受了.

事情是这样的: 前几天在挑图片浏览软件, 试用Qiv的过程中, 感觉几个地方不是很如意, 就看了下代码, 顺手打了个patch.

补丁在这里, 很简单, 十几行代码的事情. 未打补丁之前, 开启browser模式时, 参数里的文件会被显示两次; 开启了browser模式又没有指定排序模式的情况下, 参数中文件显示完之后会跳转到文件列表中的第一个而不是参数中文件在列表里的下一个. 打完patch之后应该用起来会比较顺手.

这个修改会体现在Qiv 2.2.4版本中, 希望能给用Qiv的朋友带来方便.

PS: 我后来并没有用Qiv而是选了Mirage, 之前用的是Geeqie.

Written by adam8157

October 30th, 2010 at 9:45 pm

Posted in Coding

Tagged with ,

静态库的链接顺序

with 5 comments

今天工作中遇到了一个很诡异的问题:

项目中, a.c和b.c编译出的obj先打包成静态库c.a, 再和另外一个d.a以及main.c编译出的obj链接成最后的bin文件. a.c中有private_init()和private_read()两个函数, 其中private_init()是个空函数, private_read()则在d.a中被调用.

出现的现象是这样: 如果我main.c中不调用那两个函数, 最后就会链接报错 undefined reference to ‘private_read’, 但如果我在main.c中调用其中一个, 即使只是调用空函数private_init(), 链接也会正常完成. 更诡异得是, Makefile中的链接参数是”-lc -ld”, 但如果改成”-ld -lc”, 现象就消失了.

想了半天没想明白, 最后翻了下Linkers & Loaders by John R. Levine, 终于找到了答案:

Searching libraries

After a library is created, the linker has to be able to search it. Library search generally happens during the first linker pass, after all of the individual input files have been read. If the library or libraries have symbol directories, the linker reads in the directory, and checks each symbol in turn against the linker’s symbol table. If the symbol is used but undefined, the linker includes that symbol’s file from the library. It’s not enough to mark the file for later loading; the linker has to process the symbols in the segments in the library file just like those in an explicitly linked file. The segments go in the segment table, and the symbols, both defined and undefined are entered into the global symbol table. It’s quite common for one library routine to refer to symbols in another library routine, for example, a higher level I/O routine like printf might refer to a lower level putc or write routine.

Library symbol resolution is an interative process. After the linker has made a pass over the symbols in the directory, if it included any files from the library during that pass, it should make another pass to resolve any symbols required by the included files, until it makes a complete pass over the directory and finds nothing else to include. Not all linkers do this; many just make a single sequential pass over the directory and miss any backwards dependencies from a file to another file earlier in the library. Tools like tsort and lorder can minimize the difficulty due to single-pass linkers, but it’s not uncommon for programmers to explcitly list the same library several times on the linker command line to force multiple passes and resolve all the symbols.

Unix linkers and many Windows linkers take an intermixed list of object files and libraries on the command line or in a control file, and process each in order, so that the programmer can control the order in which objects are loaded and libraries are searched. Although in principle this offers a great deal of flexibility and the ability to interpose private versions of library routines by listing the private versions before the library versions, in practice the ordered search provides little extra utility. Programmers invariably list all of their object files, then any application-specific libraries, then system libraries for math functions, network facilities and the like, and finally the standard system libraries.

When programmers use multiple libraries, it’s often necessary to list libraries more than once when there are circular dependencies among libraries. That is, if a routine in library A depends on a routine in library B, but another routine in library B depends on a routine in library A, neither searching A followed by B or B followed by A will find all of the required routines. The problem becomes even worse when the dependencies involve three or more libraries. Telling the linker to search A B A or B A B, or sometimes even A B C D A B C D is inelegant but solves the problem. Since there are rarely any duplicated symbols among the libraries, if the linker simply searched them all as a group as IBM’s mainframe linkers and AIX linker do, programmers would be well served.

简单说就是: 传统的Unix编译环境下, 静态库的加载是顺序搜索一遍, 遇到没链接的函数就记下, 如果这个函数在后面的库或obj中出现了, 链接器就会把这个函数所在的obj链接过去, 不包含未链接函数的obj就会被忽略过去(静态库也只是obj的简单打包而已).

于是, “-lc”的时候, 因为那两个函数在main.c中都没有被调用, 链接器就把a.o略过去了, “-ld”的时候虽然有了a.o中函数的调用, 但链接器已经把它给略过去, 找不到了.

所以如果库A依赖库B, 链接的顺序就应该写为A B, 如果相互依赖就应该为A B A或者B A B的顺序.

PS: 我查了一下, 大多现代的编译链都不会有这个问题, 但是传统, 标准以及我手里的这个编译链却都是这样的, 为了通用, 以后还是注意点吧.

Written by adam8157

September 8th, 2010 at 8:04 pm

Posted in Coding

Tagged with ,

shell脚本中的空格

with 8 comments

一直不太理解shell脚本中为什么那么多空格不可省略(比如[]), 又有那么多空格不可以有(比如=), shell脚本为什么对格式要求这么高?

查了好多, 基本上都在总结哪里必须空格, 哪里必须不带空格. 明显, 这不是问题的本质所在. 虽然我脚本写的不多, 但是我总感觉shell脚本很优雅. 一门优雅的语言, 如shell和c, 应该是原理决定规则, 而不是像c++一样, 规则去决定实现. 不要激动, c++之父Bjarne Stroustrup就说过, 他实际上是创造了一堆他心目中的强大的面向对象语言的理论规则, 并且他不认为有人能够完全的理解c++.

扯远了, 那么关于shell的空格要求是个什么原理呢? 其实, 和你表观看到的不一样, 有些shell表达式其实是命令风格的函数, 例如”[", 实际上, 它是个和test差不多的函数, 它后面跟的, 包括"]“, 都只是它的参数, shell中输入命令的时候要靠空格来区分各个参数, 这里也是一样. “=”两边不能有空格同样也是因为它的命令风格要对这些进行区分的要求. 虽然很诡异, 但是也可以理解, 毕竟shell脚本就是逐行运行的命令.

有些知识的积累就该是这样, 去理解而不是去总结. 就像c的数组下标为什么从0开始, 只要明白了a[i]同等于*(a+i), 一切都是那么自然.

最后, 字不够, 贴图凑.

Written by adam8157

May 12th, 2010 at 7:11 pm

Posted in Coding,Linux

Tagged with

关于SVN的外部diff工具

without comments

公司的项目用的SVN, 也还好, 虽然慢点. 但是它的diff和merge实在是human-unreadable.

还好, SVN可以使用外部的diff工具, 例如vimdiff, 只要写个下面那样的脚本, 然后将svn的config中diff-cmd指向它就好.

另外关于diff3, 我的理解刚开始和svn的merge不同, svn实际上是将两个版本的差异变化实施到当前版本. 我想用vimdiff来实现, 最后cat合并后的本地版本以满足svn的要求, 但是一直有问题, 还差点在生产中出状况, 而且这个用的也不多, 所以暂时放下. 有那位大侠实现了vimdiff作为svn的diff3-cmd, 请一定告诉我, 联系方式见About.

#!/bin/sh

# Configure your favorite diff program here.
DIFF="vimdiff"

if [ -z $2 ]
then
    echo ERROR: This script expects to be called by subversion
    exit 1
fi

# Subversion provides the paths we need as the sixth and seventh
# parameters.
LEFT=${6}
RIGHT=${7}

# Call the diff command (change the following line to make sense for
# your merge program).
#$DIFF --left $LEFT --right $RIGHT
$DIFF $LEFT $RIGHT

# Return an errorcode of 0 if no differences were detected, 1 if some were.
# Any other errorcode will be treated as fatal.
exit 0

Written by adam8157

May 3rd, 2010 at 12:40 pm

Posted in Coding,Tips

Tagged with , ,