196 lines
5.6 KiB
C
196 lines
5.6 KiB
C
// tail.c
|
|
// Řešení IJC-DU2, příklad a), 15.4.2024
|
|
// Autor: Roman Nečas, FIT
|
|
// Přeloženo: gcc 11.4.0
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <stdbool.h>
|
|
|
|
#define MAX_LINE_LENGTH 2048 // Maximalna dlzka riadku je 2047 + '\n'
|
|
|
|
typedef struct {
|
|
char **buffer; // pole ukazatelov na riadky
|
|
int size; // velkost bufferu
|
|
int start; // Index prveho riadku
|
|
int count; // pocet riadkov v bufferi
|
|
} CircularBuffer;
|
|
|
|
// vytvori kruhovy buffer s kapacitou n
|
|
CircularBuffer *cbuf_create(int n) {
|
|
CircularBuffer *cb = (CircularBuffer *)malloc(sizeof(CircularBuffer));
|
|
if (cb == NULL) {
|
|
fprintf(stderr, "Error: Failed to allocate memory for circular buffer.\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
cb->buffer = (char **)malloc(n * sizeof(char *));
|
|
if (cb->buffer == NULL) {
|
|
fprintf(stderr, "Error: Failed to allocate memory for line buffer.\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
for (int i = 0; i < n; i++) {
|
|
cb->buffer[i] = (char *)malloc((MAX_LINE_LENGTH+1) * sizeof(char));
|
|
if (cb->buffer[i] == NULL) {
|
|
fprintf(stderr, "Error: Failed to allocate memory for line.\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
cb->size = n;
|
|
cb->start = 0;
|
|
cb->count = 0;
|
|
return cb;
|
|
}
|
|
|
|
// vloz riadok do bufferu
|
|
void cbuf_put(CircularBuffer *cb, char *line) {
|
|
line[MAX_LINE_LENGTH] = '\0';
|
|
line[MAX_LINE_LENGTH-1] = '\n';
|
|
strncpy(cb->buffer[(cb->start + cb->count) % cb->size], line, MAX_LINE_LENGTH);
|
|
cb->buffer[(cb->start + cb->count) % cb->size][MAX_LINE_LENGTH] = '\0';
|
|
if (cb->count < cb->size) {
|
|
cb->count++;
|
|
} else {
|
|
cb->start = (cb->start + 1) % cb->size;
|
|
}
|
|
}
|
|
|
|
// nacitaj riadok z bufferu
|
|
char *cbuf_get(CircularBuffer *cb, int index) {
|
|
if (index < 0 || index >= cb->count) {
|
|
fprintf(stderr, "Error: Line index out of buffer range.\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
return cb->buffer[(cb->start + index) % cb->size];
|
|
}
|
|
|
|
// vyscisti pamat
|
|
void cbuf_free(CircularBuffer *cb) {
|
|
for (int i = 0; i < cb->size; i++) {
|
|
free(cb->buffer[i]);
|
|
}
|
|
free(cb->buffer);
|
|
free(cb);
|
|
}
|
|
|
|
bool isNumber(char *str) {
|
|
for(int i = 0; str[i] != '\0'; i++) {
|
|
if(!isdigit(str[i])) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
int main(int argc, char *argv[]) {
|
|
int n = 10; // defaultny pocet riadkov
|
|
FILE *file = stdin;
|
|
|
|
// Parsing argumentov
|
|
if (argc == 3 && strcmp(argv[1], "-n") == 0) { // 3 argumenty nacitja z stdin
|
|
if(isNumber(argv[2]) == false)
|
|
{
|
|
fprintf(stderr, "Error: Invalid number of lines.\n");
|
|
return 1;
|
|
}
|
|
n = atoi(argv[2]);
|
|
if (n < 0) {
|
|
fprintf(stderr, "Error: Invalid number of lines.\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
else if (n == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else if(argc == 4 && strcmp(argv[1], "-n") == 0) { // 4 argumenty, subor je posledny
|
|
if(isNumber(argv[2]) == false)
|
|
{
|
|
fprintf(stderr, "Error: Invalid number of lines.\n");
|
|
return 1;
|
|
}
|
|
n = atoi(argv[2]);
|
|
if (n < 0) {
|
|
fprintf(stderr, "Error: Invalid number of lines.\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
else if (n == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
file = fopen(argv[3], "r");
|
|
if (file == NULL) {
|
|
fprintf(stderr, "Error: Unable to open file '%s'.\n", argv[3]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
else if(argc == 4 && strcmp(argv[2], "-n") == 0) { // 4 argumenty, subor je 2
|
|
if(isNumber(argv[3]) == false)
|
|
{
|
|
fprintf(stderr, "Error: Invalid number of lines.\n");
|
|
return 1;
|
|
}
|
|
|
|
n = atoi(argv[3]);
|
|
if (n < 0) {
|
|
fprintf(stderr, "Error: Invalid number of lines.\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
else if (n == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
file = fopen(argv[1], "r");
|
|
if (file == NULL) {
|
|
fprintf(stderr, "Error: Unable to open file '%s'.\n", argv[1]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
else if (argc == 2) { // 2 argument, subor je druhy
|
|
file = fopen(argv[1], "r");
|
|
if (file == NULL) {
|
|
fprintf(stderr, "Error: Unable to open file '%s'.\n", argv[1]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
} else if(argc != 1) {
|
|
fprintf(stderr, "Usage: %s [-n number] [file]\n", argv[0]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
// Inicializacia kruhoveho bufferu
|
|
CircularBuffer *cb = cbuf_create(n);
|
|
|
|
// nacitame riadky
|
|
char line[MAX_LINE_LENGTH];
|
|
int islonger = 0;
|
|
while (fgets(line, sizeof(line), file) != NULL) {
|
|
int len = strlen(line);
|
|
if (len == (MAX_LINE_LENGTH-1) && line[MAX_LINE_LENGTH -1] != '\n') {
|
|
islonger = 1;
|
|
// zahodime zvysok riadku
|
|
int c;
|
|
while ((c = fgetc(file)) != '\n'&& c!= EOF);
|
|
}
|
|
cbuf_put(cb, line);
|
|
}
|
|
if (islonger == 1)
|
|
{
|
|
fprintf(stderr, "Too long line, above limit will be truncated\n");
|
|
}
|
|
|
|
// vypiseme poslledne riadky
|
|
int start_index = cb->count >= n ? cb->count - n : 0;
|
|
for (int i = start_index; i < cb->count; i++) {
|
|
printf("%s", cbuf_get(cb, i));
|
|
}
|
|
|
|
// vycisti pamet
|
|
cbuf_free(cb);
|
|
if (file != stdin) {
|
|
fclose(file);
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|