Perl常见错误[2]

常见错误之七:
在面向对象的编程中,错误地调用类内部函数。
以代码作为例子:
err.pl文件:

#! /usr/bin/perl -I./ -w
use module;
my $var=module->new();
print “call1:n”;
$var->call();
print “call2:n”;
$var->call2();
print “ncall3:n”;
$var->call3();

下面是module.pm:

package module;

sub new {
my $self={};
bless $self;
return $self;
}
sub call {
my ($self)=@_;
$self->_call(“something as an Argument”);
}
sub call2 {
my ($self)=@_;
_call($self,”something as an Argument”);
}
sub call3 {
my ($self)=@_;
_call(“something as an Argument”);
}
sub _call {
my ($self,$arg) = @_;
if($arg)
{
print “yes ,We got an argument!n”;
}
print “self:”.$self.”n”;
}
1;

现在我们运行err.pl:

renlu@localhost$ chmod +x err.pl
renlu@localhost$ ./err.pl

输出的结果是:

call1:
yes ,We got an argument!
self:module=HASH(0x1f85e88)
call2:
yes ,We got an argument!
self:module=HASH(0x1f85e88)

call3:
self:something as an Argument


第一第二个执行结果一样,第三个不一样?这也很容易让程序出错。我今天下午调了一下午 最后发现是这个原因。特地记录一下。

Perl常见错误

最近在用perl+mdbm+spread做东西。
php是用了很久了,python和ruby与用过,经典脚本语言就perl没摸过,现在在像小学生一样抱着教科书啃。
发现perl果然有难度多了。别的东西没让我这么频繁地犯错误。
1.第一个常见的错误是:向文件输出内容。标准语法是:

print STDERR “this is an apple.”;

我一般都会写成

print STDERR,”this is an apple.”;

总是多打一个逗号。老实说,一般我很少重复地犯错误,但是这个地方我就是记不住。
2.第二个常见错误是:经常漏写Hash引用的箭头。
本来应该写成

print $hash->{$key};

我常常写成

print $hash{$key};

3.第三个常见错误是:字符串比较:
用php时间长了,老是用两个等号来比较字符串。这是错的。正确写法是

if($var eq “hello”) {
print “world”;
}

我经常写成:

if($var==”hello”) {
print “world”;
}

这会导致逻辑错误,很难觉查。
4.第四个常见错误:
if语句不带括号(都是php带坏的)
正确的写法是:

if($var)
{
print “yes”;
}

我经常写成

if($var)
print “yes”;

5.还有一个错误,不是从php中带过来的,一般人估计不会犯:漏写分号。

如此翻译

xj去美国地时候,有汽车展销会,在路边派送礼品。这厮路过一次,人家MM看他色迷迷的,没给他发东西,于是这家伙又折回去,再次路过。这次人家终于给他发了。
礼品是一个汽车模型,里面是一件Tshirt.今天他穿在身上,我们注意到他背后画着一个大插头,下面写着:”Are you plugged in?”
我们都在尝试翻译:
“你插了吗?”
后来觉得应该是被动形式,所以应该是:
“今天你被插了吗?”
再后来觉得其实应该是过去式:
“今天你插过了吗?”
最后我们觉得后面有一个”in”,所以应该是:
“你被插入了吗?”
….
现在自己觉得实在翻译得越来越黄了…

社区全文检索引擎Hyper Estraier 学习笔记[4]

如何搭建一个Web界面的搜索界面
现在我的硬盘上有Linux帮助,php中文文档,mysql文档,C函数手册等文档等,它们一共有500M.
我需要一个索引工具。但是明显在命令行不是太方便。因为这些文档全是HTML格式的,我需要用浏览器来打开它们查看。
我决定在本机架设一个apache,利用hyperestraier来进行索引,提供像Google/baidu那样的web界面。
这是我的操作步骤:
1 准备目录:
我在www目录下新建了两个目录,search/tool和search/search_doc目录,将属主改为apache(这是我的apache运行的用户名).
search/tool/用来放置hyperestraier的程序和索引数据库,search_doc/下放置原始的各种帮助文档。
2.索引帮助文档:
在search/tool/目录下:

estcmd create man_docs_db
find ../search_doc/ -name “*.html” -type f|estcmd gather -cl -fm -cm ./man_docs_db –

然后Hyperestraier就哗啦哗啦地索引这500多M的文要资料。很快就索引完了。
3.进行CGI和estseek.cgi的相关设置。
我们将编译hyperestraier目录下产生的estseek.*复制到search_tool目录下,并修改apache的关于CGI的配置:


Options +ExecCGI
addHandler cgi-script cgi pl


现在search_tool目录下的estseek.cgi能被执行了.当然你得执行chmod a+x estseek.cgi或是chmod 0755 estseek.cgi给这个文件加上执行权屯限。
接着编辑search_tool目录下的estseek.conf文件:

indexname: man_docs_db
tmplfile: estseek.tmpl
topfile: estseek.top
helpfile: estseek.help
lockindex: true
pseudoindex:
replace: ^file:///home/y/www/search_doc/{{!}}/search_doc/
replace: /index.html?${{!}}/
showlreal: false
deftitle: Hyper Estraier: a full-text search system for communities
formtype: normal
perpage: 10 100 10
attrselect: false
#genrecheck: private{{!}}private
#genrecheck: business{{!}}business
#genrecheck: misc{{!}}miscellaneous
attrwidth: 80
showscore: true
extattr: author|Author
extattr: from|From
extattr: to|To
extattr: cc|Cc
extattr: date|Date
snipwwidth: 480
sniphwidth: 96
snipawidth: 96
condgstep: 2
dotfidf: true
scancheck: 3
phraseform: 2
dispproxy:
candetail: true
candir: false
auxmin: 32
smlrvnum: 32
smlrtune: 16 1024 4096
clipview: 2
clipweight: none
relkeynum: 0
spcache:
wildmax: 256
qxpndcmd:
logfile:
logformat: {time}t{REMOTE_ADDR}:{REMOTE_PORT}t{cond}t{hnum}n


这里主要要修改indexname和replace.
说明:
indexname是你前面用estcmd create命令创建的索引数据库的名字.
replace可以多行,能对搜索结果中显示的文件路径做一个正则替换。因为索引入库的URL是file:///home/***类似
的路径,在web中显示出来没法访问。
好的,现在在search_tool/目录创建一个首页index.html,并给一个表单:




现在就可以通过http://localhost/search_tool/来搜索你的帮助文档了。


后记:
但是,很快我发现几个问题:
1:Hyperestraier在处理gb2312的文档时,似乎有时侦测文档的编码类型会失败。搜索的时候对应的结果没有。
2.在显示搜索结果的摘要时,没有过滤HTML标签。这是我问题:我在检索的时候应该用的是:

find ../search_doc/ -name “*.html” -type f|estcmd gather -cl -fm -cm -fh ./man_docs_db –

这才能按照html来解析,否则是按mime来解析的。
3.搜两个词时,我期望的是同时包含其中任何一个词的网页都能出来,但是Hyperestraier就只搜同时包含这两个词的网页,所以搜长点的词经常结果为空。
4.对于有些词,比如中文的”的”,英文的”the”,没有进行忽略。当然这对目前的应用来说不是太大的问题。
但是无论如何,前三个问题,迫切需要解决。下一次就来抓一个出来处理掉。

进步健身的水不换?

前几天去进步游泳,发现水下的视线越来越差。昨天居然发现水中大量漂着渣子,可恶!
我原来还觉得进步这么贵,应该比较卫生。靠。

Linux 声卡设置(喇叭和耳机同时出声的解决)

本本声卡比较新,windows下装上官方驱动才能使,在linux倒是有声,就是音箱和耳机一起响,上班时没法听音乐。后来终于解决了这个问题,记录一下过程:

1:
运行lsmod|grep snd,结果是:
snd_hda_intel 457780 4
snd_usb_audio 100608 0
snd_usb_lib 24960 1 snd_usb_audio
snd_rawmidi 30336 1 snd_usb_lib

事先知道声卡就是intel了,那就只记下第一行的snd_hda_intel这个名称。

2.
然后再查看:
cat /proc/asound/card0/codec#1|head
结果是:
Codec: Realtek ALC883
Address: 1
Vendor Id: 0x10ec0883
Subsystem Id: 0x10190000


接着下载alsa源代码中的一个文档,我是下载了alsa-driver的源码代码,然后在
alsa-driver-1.0.16/alsa-kernel/Documentation/中找到了ALSA-Configuration.txt
文件。
然后:
vim ALSA-Configuration.txt ,
搜索alc833,找到:
ALC883/888
3stack-dig 3-jack with SPDIF I/O
6stack-dig 6-jack digital with SPDIF I/O
3stack-6ch 3-jack 6-channel
3stack-6ch-dig 3-jack 6-channel with SPDIF I/O
6stack-dig-demo 6-jack digital for Intel demo board
acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc)
acer-aspire Acer Aspire 9810
medion Medion Laptops
medion-md2 Medion MD2
targa-dig Targa/MSI
targa-2ch-dig Targs/MSI with 2-channel
laptop-eapd 3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE)
lenovo-101e Lenovo 101E
lenovo-nb0763 Lenovo NB0763
lenovo-ms7195-dig Lenovo MS7195
haier-w66 Haier W66

好了,我的本本就是haier的,估计haier的就都是用的同一种芯片。于是我记下,haier-w66。
3:
再打开:vim /etc/modprobe.conf
加入一行:
options snd-hda-intel model=haier-w66
再重启,音箱和耳机可以单独控制音量了。

由于系统的不同,上面的各文件的路径可能略有不同。

Spread学习系列[1]-SP_receive函数说明

接在Spread 简介(试译)之后,我跟啃骨头一样一点点儿地把SP_receive的man文档看完了。
这是我做的笔记,基本就是原文翻译,但是我英文太差,翻得太烂了点:(
SP_receive
NAME
SP_receive, SP_scat_receive – Receive message from Spread

SYNOPSIS
#include

int SP_receive( mailbox mbox, service *service_type, char sender[MAX_GROUP_NAME], int max_groups, int *num_groups, char groups[][MAX_GROUP_NAME], int16 *mess_type, int *endian_mismatch, int max_mess_len, char *mess);

int SP_scat_receive( mailbox mbox, service *service_type, char sender[MAX_GROUP_NAME], int max_groups, int *num_groups, char groups[][MAX_GROUP_NAME], int16 *mess_type, int *endian_mismatch, scatter *scat_mess);

DESCRIPTION
SP_receive 函数主要实现接收消息的功能。这个函数不仅接收数据消息,也接收成员关系数据。当前连接所在的所有组的消息都会到达同一个
“收件箱”,因此SP_receive函数一次会从任意一个组中间取回一条消息。当接收完成后,一些成员变量会被设置值,以标记这条消息的各种属性。
因为这个函数是程序从spread 系统中取回消息的唯一渠道,因此在Spread中的应用也是最复杂的。基于这条消息是数据消息,还是成员关系消息,许多
参数的含义都会改变。
没有消息到达的时候,SP_receive函数会阻塞。
mbox参数指定了要在哪个(spread)连接上获取消息。Service_type是指向一个变量的指针,这个变量会
指出当前接收到的消息是”数据消息“,还是成员关系消息。这个变量要么是REG_MESSAGE,要么是
MEMBER_SHIP_MESS,当然会是特定的类型.这个变量也是一个输入参数,在一般的情况下应该被置为0。如果您置为”DROP_RECV”,则表示您愿意接收“不可信消息”,这可能导般如果为消息或组列表分配的缓冲不够的话,消息会被清空。更多关于DROP_RECV的介绍会在后面提到。
后面的参数的含义是依赖于service_type这个变量的取值的.如果service_type的取值是REG_MESSAGE(比如数据消息),那么:
sender参数是一个指向字符的指针,至少需要能容纳MAX_GROUP_NAME个字符。(很拗口吧?其实就是一个长度至为MAX_GROUP_NAME的字符串…)
这个参数将会被设置成为消息发送方的名称(它的组内名称)
max_groups参数是你为groups参数分配的地址所能容纳的最大的组的个数。
Num_groups是一个整型指针,指向在groups参数中返回的组的个数。
groups 参数可以容纳max_groups个组名,每个组名是一个最多有MAX_GROUP_NAME个字符的字符串。所有接收这个消息的组都会被更在这儿,除非数组太小(此时groups尽可能多地接纳至到它满了为止,并且
num_groups会设为负的值).比如,如果你的groups数组能接收5个数组名,而这个消息被7个组接收,前5个组的名字会存在groups这个数组中,num_groups会被设为-7.

真正的消息内容存在命名为mess的缓冲区中,这个缓冲区最少要有max_mess个字节。如果接收的消息的长度要比这个缓冲区大,默认将会返回BUFFER_TOO_SHOFT错误,并在endian_mismatch字域中提供需要的长度。如果DROP_RECV标记被在service_type中传进来,那么mess会尽量多地存储消息内容,多余的内容会被丢弃掉,同时,SP_receive的返回值会指示一个错误。如果使用SP_scat_receive,那么mess和length参数会被一个scat_mess scatter结构体所取代,这个结构会存储它收到的消息和消息的长度。它们会被以接收的次序存储。
如果是MEMB_MESSAGE(比如,成员关系消息),并且特别指出是TRANS_MESS,那么:
sender这个字符数据(字符串)就会设置为成员关系发生变化的组的名字。
max_groups和max_mess_len参数没有用,num_groups会是0,而groups参数因为当前正处于变动之中,暂时没有
了正常的组,由sender参数取代。mess_type参数设为-1,endian_mismatch参数为0(也因为组关系处于变动之中).mess参数只包含
关系变化作用的group的group_id。因此消息体就是:
group_id;

因此本质上你所得到的信息就是通过sender参数和group_id值反映的哪个组产生了变动。

TRANS_MEMB_MESS 的重要性在于,它告诉应用程序,在它之后,在来自同一组的REG_MEMB_MESS之前,接收到的消息都是’clean up’消息,这些消息在真正改变成员关系之前需要保持常态。请阅读其他文档或研究文献以得到更多相关资料。

如果这是一条MEMB_MESSAGE(比如成员关系消息)并且指定了是REG_MEMB_MESS,那么:
sender 字符数组指定了成员关系发生改变的组的名称。
max_groups和max_mess_len参数的含义跟前面一样,mess_type参数设定为当前进程在组成员数组中的索引。endian_mismatch会再次设为0.
groups参数和mess内容用来提供当前组内发生的变化的两种信息。num_groups参数设置为新成员关系中的当前组的成员数(指变动发生后)。相对地,groups 这个数组会被设置为新成员关系中当前组的所有成员的组内名称。这个名称的顺序常常是按接收方的顺序排序的,这样当程序需要一个做代表时就能取一个出来。不同的Spread版本的顺序不同,当前版本的首先按连接到守护进程的顺序,其次是它的私有名称。守护进程的顺序是按照它们在spread.conf文件中列出来的顺序排列的。
第二类信息存储在消息体中,提供了当前进程中所有私有组名称,这些名称从原来的成员关系迁到了新的成员关系中。
所有的内容都一个挨一个地放在message缓冲中。因为这个结构在各个版本中经常变,最好的处理办法就是使用
我们提供的解析函数来将消息体翻译成定义好的描述成员关系的结构体。解析函数有两个变量,一个用来处理字
节流,一个用来处理scatters格式的消息体。
SP_get_memb_info
SP_get_vs_sets_info
SP_get_vs_set_members
SP_scat_get_memb_info
这四个函数填入标准的应用程序用来设置以成员关系的gid和vs信息的结构体。
SP_scat_get_vs_sets_info
SP_scat_get_vs_set_members

这样,如果一个程序需要得到它自己的vs_set(Spread版本4之前提供的信息),他们可以被两个函数调用来文档化。先用SP_get_memb_info然后用SP_get_vs_set_members;

每个vs_set定义成若干成员和一个成员关系字符数组(字符串)。这个数组的类型是char members[][MAX_GROUP_NAME];
每个成员关系型的消息都可能含有一系列的vs_sets,当一个网络合并动作发生时,几个不同的部分可能同时发生合并,每个区块都有它自己的成员集合,这些既有旧成员关系的又有新成员关系的。
如果你想自行解析这个成员关系消息内容,下面的段落指出了当前的数据格式。这个格式肯定会改变(过去已经改变过好几次了),我们不对未来的改变做保证。如果您想自行解析数据,在更新Spread的版本时您需要更新您的代码。
成员关系消息体包含以下几段(它们是有顺序的)。每一段数据都是一个结构体,或者是一个整数(是整数时,一定是一个32位无符号的整数)。vs sets是这样定义的:
group_id gid;
unsigned int num_vs_sets;
unsigned int local_vs_set_offset;
以及一系列vs_sets;
所有的vs_sets都序列地存在成员关系消息体中,读完了一个vs_set,另一个vs_set就在下一个字节开始了。
每一个vs_set都以一下整数num_vs_members开始,因而程序能够得到members数组的长度来进行读取。
unsigned int num_vs_members;
char members[][MAX_GROUP_NAME]

vs_set members数组有num_vs_members个组名,每一个都是一个固定长度的字符串。vs_set members
数组的内容取决于成员关系变更的类型:
CAUSED_BY_JOIN:
vs_set包含有加入进来的进程的私有组名。
CAUSED_BY_LEAVE:
vs_set包含有退出的进程的私有组名。
CAUSED_BY_DISCONNECT:
vs_set 包含有关闭连接的进程的私有组名。
CAUSED_BY_NETWORK:
vs_set包含有形成新成员关系的各个成员组的组名称。每个加入的成员集合都有一个vs_set对应。包含有本地应用程序的私有组名的vs_set会有后来加入的成员。
如果这是一条MEMB_MESSAGE但是既不是REG_MEMB_MESS也不是TRANS_MEMB_MESS,那这就表明这种情形是接收消息的成员离开了组,这是一条通知消息。这种有时被称作”闪人通知”。
这个成员刚刚离开的组的成员们会收到一个正常的TRANS_MEMB_MESS,REG_MEMB_MESS消息对,就跟前面描述的一样。
SP_receive的参数如下:
sender参数就是成员关系发生改变的组的名字。
mess_type and endian_mismatch fields will again be set to 0.
max_groups和max_mess_len参数的含义与原来一样,mess_type和endian_dismatch参数再次置为0.
groups数组和消息体提供发生变动的组的两种信息。num_groups会置为0,groups数组会置为0(既然这个成员不再是组的一个成员了。mess的消息体内容也是空。

返回值:返回返回消息的长度(当成功时)或在失败时返回以下任何一个:
ILLEGAL_SESSION
指定的mbox不正确。
ILLEGAL_MESSAGE
消息包含一个正常的结构,比如一个scatter结构没有正确填充。
CONNECTION_CLOSED
在通信时发生了连接错误,接收无法完成。
GROUPS_TOO_SHORT
如果你的groups数组设定的太小了无法存下返回的数组,会返回一个GROUPS_TOO_SHORT的错误。
这时num_groups会返回负数。
BUFFER_TOO_SHORT
如果消息体缓冲(mess)设置的太短,存不下返回的消息时,会返回这个错误,就会返回这个错误,同时endian_mismatch参数会设置为需要的缓冲的长度。