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"不能输入带空格,回车,或跳格的字符串,它们是输入数据的结束标志。