// 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 #include #include #include #include #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; }