Chinaunix首页 | 论坛 | 博客
  • 博客访问: 57097
  • 博文数量: 22
  • 博客积分: 1546
  • 博客等级: 上尉
  • 技术积分: 230
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-20 20:33
文章分类
文章存档

2010年(22)

分类: C/C++

2010-07-24 11:32:09

如果我们已经对my_ls.c的结构有了深刻了解,以及对此程序中所涉及系统调用函数都已理解,那么不妨继续增添选选型,让你的ls命令程序不断完整。正如你所理解的那样,前面我们实现的my_ls.c属于一个“插座”,要实现其他选项,基本上都是在my_ls.c源码中添加新代码。我们将不断完善选项功能的那个源码称为my_ls_plus.c。

1.增加-i选项

ls -i可以显示出每个文件的i节点编号。具体的实现办法是利用stat族函数,将文件的属性返回到类型为struct stat的参数buf中,然后在需要的位置打印st_ino字段即可。注意st_ino打印的时候需要长整型。

获取文件属性举例:

if(lstat(pathname,&buf)==-1)
	{
		my_err("lstat",errno,__LINE__);
	}

打印举例:

if(if_i)
	{
		printf("%ld ",buf.st_ino);
	}

2.增加-t选项

ls -t 按每个文件最后一次被修改的时间(st_mtime)排列显示文件。这里对文件属性中三个关于时间的字段做以说明。

st_atime:文件最后一次被访问(access)的时间。这个好理解。

st_mtime:文件最后一次被修改(modification)的时间。

st_ctime:文件字后一次被更改(create)的时间。

mtime和ctime其实都是修改时间,但是前者指文件内容被修改后的时间,而后者更倾向于文件所有者、所属组以及文件权限等属性被更改后的时间。当然如果文件内容修改,两者的时间都会被修改。我们一般用ls -l所显示的时间指mtime,而要显示出ctime则可以用: ls -lc。显示出atime则可以用:ls -lu。

因此,要实现ls -t命令的作用,我们必须对文件按照mtime进行排序。我们可以设置全局变量if_t来标记是否出现了 -t选项。如果出现则调用按照时间排序的函数sort_by_mtime(char filename[][PATH_MAX+1],int count);此函数的大致流程是:首先利用stat族函数获取每个文件的mtime,存于字符串数组mtime[256][20]中;再利用某种排序算法排序即可。如果你对C语言基本知识掌握的还算可以,那么要实现上述过程并不困难。

获取文件的mtime示例代码如下:(由于代码插件问题,请忽略<后面的‘\’)

for(i=0;i<\count;i++)
	{
		if(stat(filename[i],&buf)==-1)
		{
			my_err("stat",errno,__LINE__);
		}
		strcpy(buf_time,ctime(&buf.st_mtime));
		buf_time[strlen(buf_time)-1]='\0';
		convert_time(mtime[i],buf_time);
	}

下面的排序代码采用选择排序法进行排序,注意我们在比较的时候必然是对时间进行比较,而在交换两个数据的时候,必须对文件名和时间一起交换。当初我只交换了文件名,找了好久的"错误"。

//sorting
	for(i=0;i<\count;i++)
	{
		k=i;
		for(j=i;j<\count;j++)
               {
                        if(strcmp(mtime[j],mtime[k])>\0) k=j;
		}
		if(k!=i)
		{
			//exchange mtime
			strcpy(temp,mtime[i]);
			strcpy(mtime[i],mtime[k]);
			strcpy(mtime[k],temp);
			//exchange filename
			strcpy(temp,filename[i]);
			strcpy(filename[i],filename[k]);
			strcpy(filename[k],temp);
		}
	}

这样,你就可以实现-t选项的功能。

3.增加-A选项

这个选项理解比较简单。我们知道ls -a是显示包括隐藏文件在内的所有文件。而ls -A则显示除了.和..之外的所有文件。我们知道在my_ls.c中void display(int flag,char* pathname)是根据flag对单个文件pathname进行处理,根据flag的情况来判断是以什么方式显示所有文件名。因为我们可以在此基础上加入对-A选项的判断:

if((if_A&&!strcmp(pathname,"."))||(if_A&&!strcmp(pathname,"..")))
	{
		//blank sentence,do not list this file
	}
	else
	{
		//省略switch语句
	}

这样就可以实现-A选项了。

4.增加-B选项

如果你完成了-A选项,那么此选项对你来说轻而易举。-B选项是不显示以~结尾的备份文件。那么只要在-A选项的基础上修改源代码,示例如下:

if((if_A&&!strcmp(pathname,"."))||(if_A&&!strcmp(pathname,"..")))
	{
		//blank sentence,do not list this file
	}
	else if(if_B&&pathname[strlen(pathname)-1]=='~')
	{
		//blank sentence,do not list this file
	}
	else
	{
		//switch语句省略
        }

5.增加-d选项

-d选项只会显示当前目录(.),而不是目录下的文件。如果加入-l则会显示当前目录的各种属性。前面的-B等选项我们在添加的时候都是在display函数中添加某些代码,因为最终结果还要与-a和-l选项相结合。比如ls -laA,虽然不显示.和..,但是还是要显示以.开始的其他文件。而-d选项则不用看-a的“脸色‘。因为不论你是否加入-a选项,此选项只会显示当前目录。如下:

edsionte@edsionte-laptop:~/code/file$ ls -laAd
drwxr-xr-x 2 edsionte edsionte 4096 2010-07-06 14:50 .
edsionte@edsionte-laptop:~/code/file$ ls -ld
drwxr-xr-x 2 edsionte edsionte 4096 2010-07-06 14:50 .
edsionte@edsionte-laptop:~/code/file$ ls -d
.

因此关于此选项的代码应添加在display_dir函数中,具体位置如下:

//if the command include '-d'
	if(if_d)
	{
		if(stat(".",&buf)<\0)
		{
			my_err("stat",errno,__LINE__);
		}
		if(flag_param==PARAM_L||flag_param==PARAM_L+PARAM+A)
			display_attribute(buf,".");
		else
			display_single(buf,".");
	}
	else
	{
		for(i=0;i<\count;i++)
        	{
			display(flag_param,filename[i]);
        	}
	}

这样添加即可,通过以上几个选项的添加,你应该大致了解应该在何处添加代码了。

待续。。

阅读(861) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~