linux tail 命令的简单实现

/**************************************************************
      > File Name: tail.c
      > Author: 逮枫灵
      > mail: Albert@sshenp.com
      > Created Time: 2020年06月13日 星期六 20时55分43秒
 **************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>

#define BUFF_SIZE 1024

int strchrcnt(char *src, char c);
off_t get_start(int n);
void tail_print(int n);

const char *filename;
off_t offset;
int fd;

int main(int argc, char *argv[])
{
	int n = 10;
	if(argc == 4 || argc == 3 && strncmp(argv[1], "-n", 2) == 0)
	{
		char *endptr;
		char *invalid_num;
		if(argc == 4)
		{
			n = strtol(argv[2], &endptr, 10);
			invalid_num = argv[2];
			filename = argv[3];
		}
		else if(argc == 3)
		{
			n = strtol(argv[1] + 2, &endptr, 10);
			invalid_num = argv[1] + 2;
			filename = argv[2];
		}

		if(*endptr != '\0')
		{
			fprintf(stderr, "tail: 无效的号码%%s: \"%s\"\n", invalid_num);
			exit(1);
		}
	}


	tail_print(n);

	return 0;
}

int strchrcnt(char *src, char c)
{
	int count = 0;
	if(src)
	{
		while(*src != '\0')
		{
			if(*src++ == c)
				count++;
		}
	}
	return count;
}

void tail_print(int n)
{
	get_start(n);
	char file_text[BUFF_SIZE + 1];
	memset(file_text, 0, BUFF_SIZE + 1);
	lseek(fd, offset, SEEK_SET);
	int cn = 0;
	while((cn = read(fd, file_text, BUFF_SIZE)) > 0)
	{
		write(STDOUT_FILENO, file_text, cn);
	}
}

off_t get_start(int n)
{
	if((fd = open(filename, O_RDONLY)) == -1)
	{
		perror("open failed");
		exit(1);
	}

	int ln_count = 0;
	int of_count = BUFF_SIZE;
	off_t pre_offset = lseek(fd, 0, SEEK_END);
	char buffer[BUFF_SIZE + 1] = {0};

	while(ln_count <= n)
	{
		offset = lseek(fd, -of_count, SEEK_END);
		if(offset == -1)
		{
			offset = lseek(fd, 0, SEEK_SET);
			read(fd, buffer, pre_offset);
			buffer[pre_offset + 1] = '\0';
			//printf("%s\n", buffer);
			ln_count += strchrcnt(buffer, '\n');
			offset = 0;
			break;
		}

		of_count += read(fd, buffer, BUFF_SIZE);
		ln_count += strchrcnt(buffer, '\n');
		pre_offset = offset;
	}

	int ln_over = ln_count - n + 1;
	char *index = buffer;

	// ln_over could be less than 0
	while(--ln_over > 0)
	{
		index = strchr(index, '\n');		
		index++;
	}
	offset += index - buffer;
	return offset;
}


版权声明:本文为qq_40162781原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。