自作のtail(その6)

まだまだ自作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$ 

上手く抽出されました。

つづく

コメント

タイトルとURLをコピーしました