mirror of https://github.com/t1meshift/os_labs.git
92 lines
2.3 KiB
C
92 lines
2.3 KiB
C
|
#include <assert.h>
|
|||
|
#include <errno.h>
|
|||
|
#include <fcntl.h>
|
|||
|
#include <stdint.h>
|
|||
|
#include <stdio.h>
|
|||
|
#include <stdlib.h>
|
|||
|
#include <string.h>
|
|||
|
#include <sys/stat.h>
|
|||
|
#include <sys/time.h>
|
|||
|
#include <sys/wait.h>
|
|||
|
#include <unistd.h>
|
|||
|
#include <stdbool.h>
|
|||
|
|
|||
|
/*
|
|||
|
3. Разработать собственную версию (mytail) команды tail.
|
|||
|
Формат: mytail -n file
|
|||
|
Она читает блок из конца файла, просматривает его с конца до заданного количества строк n и печатает эти строки
|
|||
|
в соответствующем порядке.
|
|||
|
Использовать: stat(), lseek(), open(), read(), close(), ...
|
|||
|
*/
|
|||
|
#define MAX(a,b) ((a)>(b)?(a):(b))
|
|||
|
#define FATAL(fmt, ...) do {\
|
|||
|
fprintf(stderr,fmt,##__VA_ARGS__);\
|
|||
|
exit(1);\
|
|||
|
} while (0)
|
|||
|
|
|||
|
int main(int argc, char *argv[]) {
|
|||
|
const int BUFF_SIZE = 4096;
|
|||
|
long n = 10;
|
|||
|
char *filename = NULL;
|
|||
|
|
|||
|
// Parse arguments (skip 0th arg)
|
|||
|
for (int i = 1; i < argc; ++i) {
|
|||
|
if ((argv[i][0] == '-') && (i < argc - 1)) {
|
|||
|
// -n flag (e.g. -20)
|
|||
|
n = strtol(argv[i], NULL, 10) * -1;
|
|||
|
if (n < 1 || errno == ERANGE) {
|
|||
|
FATAL("Usage: %s [-<number_of_lines>] <file>\n", argv[0]);
|
|||
|
}
|
|||
|
} else {
|
|||
|
filename = argv[i];
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
if (filename == NULL) FATAL("No file name specified.\n");
|
|||
|
|
|||
|
struct stat sb;
|
|||
|
int fd;
|
|||
|
|
|||
|
if (stat(filename, &sb) == -1) {
|
|||
|
perror("stat()");
|
|||
|
FATAL("Couldn't stat %s\n", filename);
|
|||
|
}
|
|||
|
if ((fd = open(filename, O_RDONLY)) == -1) {
|
|||
|
perror("open()");
|
|||
|
FATAL("Couldn't open %s\n", filename);
|
|||
|
}
|
|||
|
|
|||
|
char *buf = calloc(BUFF_SIZE, 1);
|
|||
|
int lf_cnt = 0;
|
|||
|
size_t read_sz = 0;
|
|||
|
off_t file_offset = MAX(sb.st_size - BUFF_SIZE, 0);
|
|||
|
bool seek_stop = false;
|
|||
|
|
|||
|
lseek(fd, -BUFF_SIZE, SEEK_END);
|
|||
|
|
|||
|
do {
|
|||
|
int data_sz = read(fd, buf, BUFF_SIZE);
|
|||
|
for (int i = data_sz - 1; i >= 0; --i) {
|
|||
|
if (buf[i] == '\n') {
|
|||
|
if (++lf_cnt >= n) {
|
|||
|
file_offset += i + 1;
|
|||
|
goto print_lines;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
file_offset -= BUFF_SIZE;
|
|||
|
lseek(fd, -BUFF_SIZE, SEEK_CUR);
|
|||
|
} while ((lf_cnt <= n) && (file_offset > 0));
|
|||
|
|
|||
|
print_lines:
|
|||
|
lseek(fd, file_offset, SEEK_SET);
|
|||
|
do {
|
|||
|
read_sz = read(fd, buf, BUFF_SIZE);
|
|||
|
write(STDOUT_FILENO, buf, read_sz);
|
|||
|
} while (read_sz == BUFF_SIZE);
|
|||
|
|
|||
|
free(buf);
|
|||
|
close(fd);
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|