Projects/1BIT/summer-semester/IJC-2/tail.c
2026-04-14 19:28:46 +02:00

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;
}