まだまだ自作tail続きます。
前回ファイルを読み込みながら表示してた処理を、今回は、ファイル読み込みと、抽出結果を表示する処理に分離します。
ついでにファイル読み込みは、fopen~fgetc~fcloseを、open~read~closeに置き換えます。
20 case 'c':
21 len = atoi(optarg);
22 break;
~省略~
39 fp=fopen(fname,"r");
40 if(fseek(fp,-len,SEEK_END) != 0){
41 perror("ERROR");
42 }
43 while((c=fgetc(fp)) != -1){
44 putchar(c);
45 }
46 fclose(fp);
上は、前回のソースです。
何も考えずにlenという変数名にしたのですが、短すぎて、何の長さなのか早速分からなくなったので、req_lenという変数名に改名。
まあこれでも、分かりにくいです。いつも長さ関係の名前を付けるとき、~lenって名前にするべきか、~sizeって名前にするべきか、悩みます。いつも結論が出ないので、とりあえずの名前で寝かせている始末。
上の39行目fopenは、下の47行目openに変更、エラー処理も追加。fseekは、lseekに変更。きっと処理が早くなります。
下のソースになりました。
15 int req_len = 10;
~省略~
25 case 'c':
26 req_len = atoi(optarg);
27 break;
~省略~
47 if((fd=open(fname, O_RDONLY)) == -1){
48 perror("ERROR");
49 return 1;
50 }
51
52 if(lseek(fd, -req_len, SEEK_END) < 0){
53 perror("ERROR");
54 return 1;
55 }
さらにバッファ変数bufを用意して、readに対応。
readの戻り値は、要求したリードサイズを読み込みできるとは限らないので、this_lenっていう新設の変数に格納して、この値で、バッファポインタbufpを進めます。
このようなソースになりました。
19 char buf[0x1000];
20 char *bufp;
21 ssize_t this_len;
57 bufp = buf;
58 while(1){
59 this_len = read(fd, bufp, req_len - (bufp-buf));
60 if(this_len == 0)break;
61 bufp += this_len;
62 }
最後は、抽出結果を表示する部分、見出し表示(<== ファイル名 ==>)は、結果表示としてまとまっていた方がよいので、qflagの判定とprintfの2行を、66行目に移動してきました。
68行目から71行目は、前回ファイル読み込みしながら表示してた処理を、分離して、バッファの内容を表示するだけの処理として新設。
66 if(!qflag)
67 printf("<== %s ==>\n",fname);
68 bufp = buf;
69 while(req_len--){
70 putchar((int)*bufp++);
71 }
ソース全体です。
takk@deb9:~/tmp$ cat -n t.c
1 #include <stdio.h>
2 #include <sys/types.h> //stat
3 #include <sys/stat.h> //stat
4 #include <unistd.h> //stat
5 #include <getopt.h> //getopt
6 #include <stdlib.h> //atoi
7 #include <fcntl.h> //open
8
9 int main(int argc, char* argv[])
10 {
11 int c;
12 int fd;
13 char *fname;
14 struct stat fs;
15 int req_len = 10;
16 int optch;
17 int qflag = 0;
18
19 char buf[0x1000];
20 char *bufp;
21 ssize_t this_len;
22
23 while ((optch = getopt(argc, argv, "c:q")) != -1){
24 switch (optch) {
25 case 'c':
26 req_len = atoi(optarg);
27 break;
28 case 'q':
29 qflag = 1;
30 break;
31 default:
32 printf("parameter error\n");
33 return 1;
34 }
35 }
36
37 argv += optind;
38 argc -= optind;
39
40 while(argc--){
41 fname = *argv++;
42
43 stat(fname, &fs);
44
45 req_len = fs.st_size < req_len ? fs.st_size : req_len;
46
47 if((fd=open(fname, O_RDONLY)) == -1){
48 perror("ERROR");
49 return 1;
50 }
51
52 if(lseek(fd, -req_len, SEEK_END) < 0){
53 perror("ERROR");
54 return 1;
55 }
56
57 bufp = buf;
58 while(1){
59 this_len = read(fd, bufp, req_len - (bufp-buf));
60 if(this_len == 0)break;
61 bufp += this_len;
62 }
63
64 close(fd);
65
66 if(!qflag)
67 printf("<== %s ==>\n",fname);
68 bufp = buf;
69 while(req_len--){
70 putchar((int)*bufp++);
71 }
72 }
73
74 return 0;
75 }
takk@deb9:~/tmp$
では、1000 Byte程度のファイルを作成し、確認してみます。
takk@deb9:~/tmp$ truncate -s 1000 c.bin takk@deb9:~/tmp$ echo -ne "\x3\x2\x1" >> c.bin
これで、1000 Byteまでオール0、その後3 2 1と格納された1003 Byteのデータができました。
末尾5 Byte抽出。
takk@deb9:~/tmp$ ./a.out -qc5 c.bin | od -tx1 0000000 00 00 03 02 01 0000005 takk@deb9:~/tmp$
末尾1000 Byte抽出。
takk@deb9:~/tmp$ ./a.out -qc1000 c.bin | od -tx1 -Ad -w10 0000000 00 00 00 00 00 00 00 00 00 00 * 0000990 00 00 00 00 00 00 00 03 02 01 0001000 takk@deb9:~/tmp$
上手く抽出されました。
つづく


コメント