まだまだ自作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$
上手く抽出されました。
つづく
コメント