#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ARR_LEN(arr) (sizeof(arr) / sizeof(*arr))
#define FILE_END "END" 

typedef struct {
    char first_name[64];
    char last_name[64];
    unsigned int age;
} Person;

char *fgets_strip(char *s, int size, FILE *stream) {
    char *ret = fgets(s, size, stream);
    s[strcspn(s, "\n")] = 0;
    return ret;
}

int person_parse(char *s, Person *person) {
    char format[4 + 1 + 4 + 1 + 2 + 1];
    assert((size_t)snprintf(
        format,
        ARR_LEN(format),
        "%%%zus %%%zus %%u",
        ARR_LEN(person->first_name),
        ARR_LEN(person->last_name)
    ) < ARR_LEN(format));

    return sscanf(
        s,
        format,
        person->first_name,
        person->last_name,
        &person->age
    ) < 3 ? -1 : 0;
}

int person_read(FILE *f, Person *person) {
    char buf[256];
    fgets_strip(buf, ARR_LEN(buf), f);

    if (strncmp(buf, FILE_END, ARR_LEN(FILE_END)) == 0) {
        return 0;
    }
    return person_parse(buf, person) < 0 ? 0 : 1;
}

void person_print(Person *person) {
    printf(
        "nome: %s, cognome: %s, eta': %u\n",
        person->first_name,
        person->last_name,
        person->age
    );
}

int person_is_relative(Person *p1, Person *p2) {
    return strcmp(p1->last_name, p2->last_name) == 0;
}

typedef Person Data;

typedef struct ListHead {
    struct ListHead *next;
    Data data;
} ListHead;

typedef ListHead *Link;

Link list_new_raw(void) {
    return malloc(sizeof(ListHead));
}

Link list_new(Data data) {
    Link ret = list_new_raw();
    ret->data = data;
    ret->next = NULL;
    return ret;
}

Link list_input(FILE *f, int (*input) (FILE *, Data *)) {
    ListHead *head = NULL;
    ListHead **next = &head;

    Data data;
    while (input(f, &data)) {
        *next = list_new(data);
        next = &(*next)->next;
    }
    return head;
}

Link list_find(Link head, Data *key, int (*compare) (Data *, Data *)) {
    while (head && !compare(key, &head->data)) {
        head = head->next;
    }
    return head;
}

Link list_find_nth(Link head, Data *key, size_t n, int (*compare) (Data *, Data *)) {
    size_t count = 0;
    Link found;
    while (count < n && (found = list_find(head, key, compare))) {
        ++count;
        head = found->next;
    }
    return found;
}

int main(void) {
    FILE *f = fopen("input.txt", "r");
    Link list = list_input(f, person_read);
    fclose(f);

    Person key;
    puts("inserire cognome");
    fgets_strip(key.last_name, ARR_LEN(key.last_name), stdin);

    puts("inserire n");
    size_t n;
    scanf("%zu", &n);

    Link found = list_find_nth(list, &key, n, person_is_relative);
    if (found) {
        person_print(&found->data);
    } else {
        puts("il parente ricercato non esiste");
    }
}