《unix/linux编程实践教程》代码集锦

1  chapter 02练习题

linux命令中标准的cp会自动覆盖已经存在的文件,而不给出任何提示,如果已经存在了文件file2,又输入:

$ cp file1 file2

会覆盖file2的内容。标准的cp有一个参数-i可以在覆盖前给出提示,得到确认后才覆盖。编写代码使命令行接受-i参数,并支持以所有情况:

$ cp -i file1 file2
$ cp file1 -i file2
$ cp file1 file2 -i
#include        <stdio.h>
#include        <unistd.h>
#include        <fcntl.h>

#define BUFFERSIZE      4096
#define COPYMODE        0644

void oops(char *, char *);

int main(int ac, char *av[])
{
	int     in_fd, out_fd, n_chars;
 	char    buf[BUFFERSIZE];
	char	*src = NULL, *dest = NULL;
	int	i_option = 0;
						/* check args 	*/
	while( --ac )
	{
		if ( strcmp("-i", *++av) == 0 )
			i_option = 1;
		else if ( !src )
			src = *av;
		else if ( !dest )
			dest = *av;
		else 
			usage();
   }
	if ( !src || !dest )
		usage();
						/* open files	*/

	if ( (in_fd=open(src, O_RDONLY)) == -1 )
                oops("Cannot open ", src );

	if ( !i_option || !exists(dest) || ok_to_replace(dest) )
		if ( (out_fd=creat( dest, COPYMODE)) == -1 )
			oops("Cannot creat", dest);
	
						/* copy files	*/

	while ( (n_chars = read(in_fd , buf, BUFFERSIZE)) > 0 )
 		if ( write( out_fd, buf, n_chars ) != n_chars )
   			oops("Write error to ", dest);
	if ( n_chars == -1 )
			oops("Read error from ", src);

						/* close files	*/

	if ( close(in_fd) == -1 || close(out_fd) == -1 )
 		oops("Error closing files","");
}

void oops(char *s1, char *s2)
{
        fprintf(stderr,"Error: %s ", s1);
        perror(s2);
        exit(1);
}

usage()
{
	fprintf(stderr,"usage: cp [-i] source dest\n");
	exit(1);
}

/*
 * new functions to support the "-i" option
 *
 *   exists(char *filename)  - uses open() to see if file is there
 *                             A better choice is stat() - see Chapter 3
 *   ok_to_replace(char *fn) - ask the user 
 */

int exists(char *filename)
{
	int	fd;

	if ( fd = open(filename, O_RDONLY) )
		close(fd);
	return (fd != -1) ;
}

/*
 * ok_to_replace - prompts to stderr and reads from stdin
 */
int ok_to_replace(char *filename)
{
	char	ans[10];		/* ought to be enough for y/n */
	char	c;
	int	retval = 0;

	fprintf(stderr,"cp: Ok to replace `%s'? ", filename);
	if ( scanf("%9s", ans) == 1 ){
		if ( *ans == 'y' || *ans == 'Y' )
			retval = 1;
	}
	while( ( c = getchar() ) != EOF && c != '\n' )
		;
	return retval;
}

代码分析:

用户命令行输入参数个数可以分为以下3种情况:

1 刚好4个参数

cp -i file1 file2 

2 只有三个参数

cp file1 file2 

3 参数多于四个/三个

cp file1 file2 -i file3
cp file1 file2 file3

4 参数少于三个/四个

cp -i file1
cp file1

前三种的情况代码如下:

	while( --ac )
	{
		if ( strcmp("-i", *++av) == 0 )
			i_option = 1;
		else if ( !src )
			src = *av;
		else if ( !dest )
			dest = *av;
		else 
			usage();
   }

最后一种情况是:

	if ( !src || !dest )
		usage();

用户命令行参数分析分为以下三种情况

1 首先查看是否有-i选项,如果没有则不用考虑覆盖文件问题,代码中用i_option来判断。

2 如果有-i选项,再判断目的文件是否存在,如果没有,则直接复制

3 如果有-i选项,且目的文件已经存在,再判断用户是否需要覆盖掉文件。

代码如下:

	if ( !i_option || !exists(dest) || ok_to_replace(dest) )

||可以表示考察条件的先后顺序

编写函数exists和ok_to_replace

exists

int exists(char *filename)
{
	int	fd;

	if ( fd = open(filename, O_RDONLY) )
		close(fd);
	return (fd != -1) ;
}

ok_to_replace

int ok_to_replace(char *filename)
{
	char	ans[10];		/* ought to be enough for y/n */
	char	c;
	int	retval = 0;

	fprintf(stderr,"cp: Ok to replace `%s'? ", filename);
	if ( scanf("%9s", ans) == 1 ){
		if ( *ans == 'y' || *ans == 'Y' )
			retval = 1;
	}
	while( ( c = getchar() ) != EOF && c != '\n' )
		;
	return retval;
}

while语句是为了清除多于的输入,因为用格式符"%s"不能输入带空格,回车,或跳格的字符串,它们是输入数据的结束标志。

猜你喜欢

转载自blog.csdn.net/qq_40123329/article/details/83663070