分享
 
 
 

如何阅读源代码(2)

王朝other·作者佚名  2008-05-21
窄屏简体版  字體: |||超大  

从注释和程序本身可以看出,这是查找是否存在一个叫做webalizer.conf的配置文件,如果当前目录下有,则用get_config来读入其中内容,如果没有,则查找ETCDIR/webalizer.conf是否存在。如果都没有,则进入下一部分。(注意:ETCDIR = @ETCDIR@在makefile中有定义)/* get command line options */

opterr = 0; /* disable parser errors */

while ((i=getopt(argc,argv,"a:A:c:C:dD:e:E:fF:g:GhHiI:l:Lm:M:n:N:o:pP:qQr:R:s:S:t:Tu:U:vVx:XY"))!=EOF)

{

switch (i)

{

case 'a': add_nlist(optarg,&hidden_agents); break; /* Hide agents */

case 'A': ntop_agents=atoi(optarg); break; /* Top agents */

case 'c': get_config(optarg); break; /* Config file */

case 'C': ntop_ctrys=atoi(optarg); break; /* Top countries */

case 'd': debug_mode=1; break; /* Debug */case 'D': dns_cache=optarg; break; /* DNS Cache filename */

case 'e': ntop_entry=atoi(optarg); break; /* Top entry pages */

case 'E': ntop_exit=atoi(optarg); break; /* Top exit pages */

case 'f': fold_seq_err=1; break; /* Fold sequence errs */

case 'F': log_type=(optarg[0]=='f')?

LOG_FTP:(optarg[0]=='s')?

LOG_SQUID:LOG_CLF; break; /* define log type */case 'g': group_domains=atoi(optarg); break; /* GroupDomains (0=no) */

case 'G': hourly_graph=0; break; /* no hourly graph */

case 'h': print_opts(argv[0]); break; /* help */

case 'H': hourly_stats=0; break; /* no hourly stats */

case 'i': ignore_hist=1; break; /* Ignore history */

case 'I': add_nlist(optarg,&index_alias); break; /* Index alias */

case 'l': graph_lines=atoi(optarg); break; /* Graph Lines */

case 'L': graph_legend=0; break; /* Graph Legends */

case 'm': visit_timeout=atoi(optarg); break; /* Visit Timeout */

case 'M': mangle_agent=atoi(optarg); break; /* mangle user agents */

case 'n': hname=optarg; break; /* Hostname */

case 'N': dns_children=atoi(optarg); break; /* # of DNS children */

case 'o': out_dir=optarg; break; /* Output directory */

case 'p': incremental=1; break; /* Incremental run */

case 'P': add_nlist(optarg,&page_type); break; /* page view types */

case 'q': verbose=1; break; /* Quiet (verbose=1) */

case 'Q': verbose=0; break; /* Really Quiet */

case 'r': add_nlist(optarg,&hidden_refs); break; /* Hide referrer */

case 'R': ntop_refs=atoi(optarg); break; /* Top referrers */

case 's': add_nlist(optarg,&hidden_sites); break; /* Hide site */

case 'S': ntop_sites=atoi(optarg); break; /* Top sites */

case 't': msg_title=optarg; break; /* Report title */

case 'T': time_me=1; break; /* TimeMe */

case 'u': add_nlist(optarg,&hidden_urls); break; /* hide URL

*/

case 'U': ntop_urls=atoi(optarg); break; /* Top urls */

case 'v':

case 'V': print_version(); break; /* Version */

case 'x': html_ext=optarg; break; /* HTML file extension */

case 'X': hide_sites=1; break; /* Hide ind. sites */

case 'Y': ctry_graph=0; break; /* Supress ctry graph */

}

}if (argc - optind != 0) log_fname = argv[optind];

if ( log_fname && (log_fname[0]=='-')) log_fname=NULL; /* force STDIN? *//* check for gzipped file - .gz */

if (log_fname) if (!strcmp((log_fname+strlen(log_fname)-3),".gz")) gz_log=1;

这一段是分析命令行参数及开关。(getopt()的用法我在另外一篇文章中讲过,这里就不再重复了。)可以看到,这个软件虽然功能不太复杂,但是开关选项还是不少。大多数的unix/linux程序的开头部分都是这个套路,初始化配置文件,并且读入分析命令行。在这段程序中,我们需要注意一个函数:add_nlist(). print_opts(), get_config()等等一看就明白,就不用多讲了。这里我们已经是第二次遇到add_nlist这个函数了,就仔细看看吧。$ grep add_nlist *.hlinklist.h:extern int add_nlist(char *, NLISTPTR *); /* add list item */

可以发现它定义在linklist.h中。

在这个h文件中,当然会有一些数据结构的定义,比如:struct nlist { char string[80]; /* list struct for HIDE items */

struct nlist *next; };typedef struct nlist *NLISTPTR;struct glist { char string[80]; /* list struct for GROUP items */

char name[80];

struct glist *next; };typedef struct glist *GLISTPTR;

这是两个链表结构。还有extern GLISTPTR group_sites ; /* "group" lists */extern GLISTPTR group_urls ;extern GLISTPTR group_refs ;

这些都是链表, 太多了,不用一一看得很仔细,因为目前也看不出来什么东西。当然要注意它们是extern的, 也就是说,可以在其他地方(文件)看到它们的数值(类似于C++中的public变量)。这里还定义了4个函数:extern char *isinlist(NLISTPTR, char *); /* scan list for str */extern char *isinglist(GLISTPTR, char *); /* scan glist for str */extern int add_nlist(char *, NLISTPTR *); /* add list item */extern int add_glist(char *, GLISTPTR *); /* add group list item */

注意,这些都是extern的,也就是说,可以在其他地方见到它们的调用(有点相当于C++中的public函数)。再来看看linklist.c,NLISTPTR new_nlist(char *); /* new list node */void del_nlist(NLISTPTR *); /* del list */GLISTPTR new_glist(char *, char *); /* new group list node */void del_glist(GLISTPTR *); /* del group list */int isinstr(char *, char *);

这5个函数是内部使用的(相当于C++中的private), 也就是说,这些函数只被isinlist(NLISTPTR, char *), isinglist(GLISTPTR, char *), add_nlist(char *, NLISTPTR *), add_glist(char *, GLISTPTR *)调用,而不会出现在其他地方。所以,我们先来看这几个内部函数。举例来说,add_nlist(char *)NLISTPTR new_nlist(char *str){

NLISTPTR newptr;if (sizeof(newptr->string) < strlen(str))

{

if (verbose)

fprintf(stderr,"[new_nlist] %s ",msg_big_one);

}

if (( newptr = malloc(sizeof(struct nlist))) != NULL)

{strncpy(newptr->string, str, sizeof(newptr->string));newptr->next=NULL;}

return newptr;}

这个函数分配了一个struct nlist, 并且把其中的string赋值为str, next赋值为NULL.这实际上是创建了链表中的一个节点。verbose是一个全局变量,定义了输出信息的类型,如果verbose为1,则输出很详细的信息,否则输出简略信息。这是为了调试或者使用者详细了解程序情况来用的。不是重要内容,虽然我们常常可以在这个源程序的其他地方看到它。另外一个函数:void del_nlist(NLISTPTR *list){

NLISTPTR cptr,nptr;cptr=*list;

while (cptr!=NULL)

{

nptr=cptr->next;

free(cptr);

cptr=nptr;

}}

这个函数删除了一个nlist(也可能是list所指向的那一个部分开始知道链表结尾),比较简单。看完了这两个内部函数,可以来看/*********************************************//* ADD_NLIST - add item to FIFO linked list *//*********************************************/int add_nlist(char *str, NLISTPTR *list){

NLISTPTR newptr,cptr,pptr;if ( (newptr = new_nlist(str)) != NULL)

{

if (*list==NULL) *list=newptr;

else

{

cptr=pptr=*list;

while(cptr!=NULL) { pptr=cptr; cptr=cptr->next; };

pptr->next = newptr;

}

}

return newptr==NULL;}

这个函数是建立了一个新的节点,把参数str赋值给新节点的string, 并把它连接到list所指向链表的结尾。另外的三个函数:new_glist(), del_glist(), add_glist()完成的功能和上述三个差不多,所不同的只是它们所处理的数据结构不同。看完了这几个函数,我们回到main程序。接下来是,/* setup our internal variables */

init_counters(); /* initalize main counters */

我们所阅读的这个软件是用来分析日志并且做出统计的,那么这个函数的名字已经告诉了我们,这是一个初始化计数器的函数。简略的看看吧!$ grep init_counters *.hwebalizer.h:extern void init_counters();

在webalizer.c中找到:void init_counters(){

int i;

for (i=0;i_RC;i++) response[i].count = 0;

for (i=0;i<31;i++) /* monthly totals */

{

tm_xfer[i]=0.0;

tm_hit[i]=tm_file[i]=tm_site[i]=tm_page[i]=tm_visit[i]=0;

}

for (i=0;i<24;i++) /* hourly totals */

{

th_hit[i]=th_file[i]=th_page[i]=0;

th_xfer[i]=0.0;

}......}

略过去一大串代码,不用看了,肯定是计数器清0。在主程序中,接下来是:if (page_type==NULL) /* check if page types present */

{

if ((log_type == LOG_CLF) || (log_type == LOG_SQUID))

{

add_nlist("htm*" ,&page_type); /* if no page types specified, we */

add_nlist("cgi" ,&page_type); /* use the default ones here... */

if (!isinlist(page_type,html_ext)) add_nlist(html_ext,&page_type);

}

else add_nlist("txt" ,&page_type); /* FTP logs default to .txt */

}

page_type这个变量在前面见过,case 'P': add_nlist(optarg,&page_type); break; /* page view types

根据在最开始读过的README文件,这个page_type是用来定义处理的页面的类型的。在README文件中,-P name Page type. This is the extension of files you consider to

be pages for Pages calculations (sometimes called 'pageviews').

The default is 'htm*' and 'cgi' (plus whatever HTMLExtension

you specified if it is different). Don't use a period!

我们在程序中也可以看到,如果没有在命令行中或者config文件中指定,则根据处理的日志文件的类型来添加缺省的文件类型。比如对于CLF文件(WWW日志),处理html, htm, cgi文件if (log_type == LOG_FTP)

{

/* disable stuff for ftp logs */

ntop_entry=ntop_exit=0;

ntop_search=0;

}

else

.....

这一段是对于FTP的日志格式,设置搜索列表。

for (i=0;i

{

sm_htab[i]=sd_htab[i]=NULL; /* initalize hash tables */

um_htab[i]=NULL;

rm_htab[i]=NULL;

am_htab[i]=NULL;

sr_htab[i]=NULL;

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有