分享
 
 
 

如何阅读源代码(3)

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

清空哈西表,为下面即将进行的排序工作做好准备。关于哈西表,这是数据结构中常用的一种用来快速排序的结构,如果不清楚,可以参考相关书籍,比如清华的<<数据结构>>教材或者<<数据结构的C++实现>>等书。

if (verbose>1)

{

uname(&system_info);

printf("Webalizer V%s-%s (%s %s) %s ",

version,editlvl,system_info.sysname,

system_info.release,language);

}

这一段,是打印有关系统的信息和webalizer程序的信息(可以参考uname的函数说明)。#ifndef USE_DNS

if (strstr(argv[0],"webazolver")!=0)

{

printf("DNS support not present, aborting... ");

exit(1);

}#endif /* USE_DNS */

这一段,回忆我们在看README文件的时候,曾经提到过可以在编译的时候设置选项开关来设定DNS支持,在源代码中可以看到多次这样的代码段出现,如果不指定DNS支持,这些代码段则会出现(ifdef)或者不出现(ifndef).下面略过这些代码段,不再重复。/* open log file */

if (gz_log)

{

gzlog_fp = gzopen(log_fname,"rb");

if (gzlog_fp==Z_NULL)

{

/* Error: Can't open log file ... */

fprintf(stderr, "%s %s ",msg_log_err,log_fname);

exit(1);

}

}

else

{

if (log_fname)

{

log_fp = fopen(log_fname,"r");

if (log_fp==NULL)

{

/* Error: Can't open log file ... */

fprintf(stderr, "%s %s ",msg_log_err,log_fname);

exit(1);

}

}

}

这一段,回忆在README文件中曾经读到过,如果log文件是gzip压缩格式,则用gzopen函数打开(可以猜想gz***是一套针对gzip压缩格式的实时解压缩函数),如果不是,则用fopen打开。

/* switch directories if needed */

if (out_dir)

{

if (chdir(out_dir) != 0)

{

/* Error: Can't change directory to ... */

fprintf(stderr, "%s %s ",msg_dir_err,out_dir);

exit(1);

}

}

同样,回忆在README文件中读到过,如果参数行有-o out_dir, 则将输出结果到该目录,否则,则输出到当前目录。在这一段中,如果输出目录不存在(chdir(out_dir) != 0)则出错。#ifdef USE_DNS

if (strstr(argv[0],"webazolver")!=0)

{

if (!dns_children) dns_children=5; /* default dns children if needed */

if (!dns_cache)

{

/* No cache file specified, aborting... */

fprintf(stderr,"%s ",msg_dns_nocf); /* Must have a cache file */

exit(1);

}

}......

在上面曾经提到过,这是DNS解析的代码部分,可以略过不看,不会影响对整个程序的理解。

/* prep hostname */

if (!hname)

{

if (uname(&system_info)) hname="localhost";

else hname=system_info.nodename;

}

这一段继续处理参数做准备工作。如果在命令行中指定了hostname(机器名)则采用指定的名称,否则调用uname查找机器名,如果没有,则用localhost来作为机器名。(同样在README中说得很详细)

/* get past history */

if (ignore_hist) {if (verbose>1) printf("%s ",msg_ign_hist); }

else get_history();

如果在命令行中指定了忽略历史文件,则不读取历史文件,否则调用get_history()来读取历史数据。在这里,我们可以回想在README文件中同样说过这一细节,在命令行或者配置文件中都能指定这一开关。需要说明的是,我们在这里并不一定需要去看get_history这一函数,因为从函数的名称,README文件和程序注释都能很清楚的得知这一函数的功能,不一定要去看代码。而如果要猜想的话,也可以想到,history是webalizer在上次运行的时候记录下来的一个文件,而这个文件则是去读取它,并将它的数据包括到这次的分析中去。不信,我们可以来看看。void get_history(){

int i,numfields;

FILE *hist_fp;

char buffer[BUFSIZE];/* first initalize internal array */

for (i=0;i<12;i++)

{

hist_month[i]=hist_year[i]=hist_fday[i]=hist_lday[i]=0;

hist_hit[i]=hist_files[i]=hist_site[i]=hist_page[i]=hist_visit[i]=0;

hist_xfer[i]=0.0;

}hist_fp=fopen(hist_fname,"r");if (hist_fp)

{

if (verbose>1) printf("%s %s ",msg_get_hist,hist_fname);

while ((fgets(buffer,BUFSIZE,hist_fp)) != NULL)

{

i = atoi(buffer) -1;

if (i>11)

{

if (verbose)

fprintf(stderr,"%s (mth=%d) ",msg_bad_hist,i+1);

continue;

}/* month# year# requests files sites xfer firstday lastday */

numfields = sscanf(buffer,"%d %d %lu %lu %lu %lf %d %d %lu %lu",

&hist_month[i],

&hist_year[i],

&hist_hit[i],

&hist_files[i],

&hist_site[i],

&hist_xfer[i],

&hist_fday[i],

&hist_lday[i],

&hist_page[i],

&hist_visit[i]);if (numfields==8) /* kludge for reading 1.20.xx history files */

{

hist_page[i] = 0;

hist_visit[i] = 0;

}

}

fclose(hist_fp);

}

else if (verbose>1) printf("%s ",msg_no_hist);}/*********************************************//* PUT_HISTORY - write out history file *//*********************************************/void put_history(){

int i;

FILE *hist_fp;hist_fp = fopen(hist_fname,"w");if (hist_fp)

{

if (verbose>1) printf("%s ",msg_put_hist);

for (i=0;i<12;i++)

{

if ((hist_month[i] != 0) && (hist_hit[i] != 0))

{

fprintf(hist_fp,"%d %d %lu %lu %lu %.0f %d %d %lu %lu ",

hist_month[i],

hist_year[i],

hist_hit[i],

hist_files[i],

hist_site[i],

hist_xfer[i],

hist_fday[i],

hist_lday[i],

hist_page[i],

hist_visit[i]);

}

}

fclose(hist_fp);

}

else

if (verbose)

fprintf(stderr,"%s %s ",msg_hist_err,hist_fname);}

在preserve.c中,这两个函数是成对出现的。get_history()读取文件中的数据,并将其记录到hist_开头的一些数组中去。而put_history()则是将一些数据记录到同样的数组中去。我们可以推测得知,hist_数组是全局变量(在函数中没有定义),也可以查找源代码验证。同样,我们可以找一找put_history()出现的地方,来验证刚才的推测是否正确。在webalizer.c的1311行,出现:month_update_exit(rec_tstamp); /* calculate exit pages */

write_month_html(); /* write monthly HTML file */

write_main_index(); /* write main HTML file */

put_history(); /* write history */

可以知道,推测是正确的。再往下读代码,if (incremental) /* incremental processing? */

{

if ((i=restore_state())) /* restore internal data structs */

{

/* Error: Unable to restore run data (error num) */

/* if (verbose) fprintf(stderr,"%s (%d) ",msg_bad_data,i); */

fprintf(stderr,"%s (%d) ",msg_bad_data,i);

exit(1);

}

......

}

同样,这也是处理命令行和做数据准备,而且和get_history(), put_history()有些类似,读者可以自己练习一下。下面,终于进入了程序的主体部分, 在做完了命令行分析,数据准备之后,开始从日志文件中读取数据并做分析了。/*********************************************/

/* MAIN PROCESS LOOP - read through log file */

/*********************************************/while ( (gz_log)?(our_gzgets(gzlog_fp,buffer,BUFSIZE) != Z_NULL):

(fgets(buffer,BUFSIZE,log_fname?log_fp:stdin) != NULL))

我看到这里的时候,颇有一些不同意作者的这种写法。这一段while中的部分写的比较复杂而且效率不高。因为从程序推断和从他的代码看来,作者是想根据日志文件的类型不同来采用不同的方法读取文件,如果是gzip格式,则用our_gzgets来读取其中一行,如果是普通的文本文件格式,则用fgets()来读取。但是,这段代码是写在while循环中的,每次读取一行就要重复判断一次,明显是多余的而且降低了程序的性能。可以在while循环之前做一次这样的判断,然后就不用重复了。total_rec++;

if (strlen(buffer) == (BUFSIZE-1))

{

if (verbose)

{

fprintf(stderr,"%s",msg_big_rec);

if (debug_mode) fprintf(stderr,": %s",buffer);

else fprintf(stderr," ");

}total_bad++; /* bump bad record counter *//* get the rest of the record */

while ( (gz_log)?(our_gzgets(gzlog_fp,buffer,BUFSIZE)!=Z_NULL):

(fgets(buffer,BUFSIZE,log_fname?log_fp:stdin)!=NULL))

{

if (strlen(buffer) < BUFSIZE-1)

{

if (debug_mode && verbose) fprintf(stderr,"%s ",buffer);

break;

}

if (debug_mode && verbose) fprintf(stderr,"%s",buffer);

}

continue; /* go get next record if any */

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
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- 王朝網路 版權所有