aboutsummaryrefslogtreecommitdiff
path: root/challenge-012/paulo-custodio/c/ch-2.c
blob: d4d7aa84e20128fb71cc1c92d92877f9032c9f9d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/*
Challenge 012

Challenge #2
Write a script that finds the common directory path, given a collection of
paths and directory separator. For example, if the following paths are
supplied.
/a/b/c/d
/a/b/cd
/a/b/cc
/a/b/c/d/e
and the path separator is /. Your script should return /a/b as common
directory path.
*/

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

void* check_mem(void* p) {
    if (!p) {
        fputs("Out of memory", stderr);
        exit(EXIT_FAILURE);
    }
    return p;
}

char* common_path(char sep, char* paths[], int num_paths) {
    const char* p0 = paths[0];
    const char* end_common = paths[0];
    while (true) {
        const char* p1 = strchr(p0, sep);
        if (p1 == NULL)
            p1 = p0 + strlen(p0);
        for (int i = 1; i < num_paths; i++) {
            const char* q0 = paths[i] + (p0 - paths[0]);
            const char* q1 = strchr(q0, sep);
            if (q1 == NULL)
                q1 = q0 + strlen(q0);
            if (q1 - q0 != p1 - p0 ||
                strncmp(paths[0], paths[i], p1 - paths[0]) != 0)
                goto failed;
        }
        end_common = p1;
        p0 = p1 + 1;
    }
failed:
    {
        char* ret = check_mem(strdup(paths[0]));
        ret[end_common - paths[0]] = '\0';          // truncate
        return ret;
    }
}

int main(int argc, char* argv[]) {
    if (argc != 1) {
        fputs("usage: ch-2", stderr);
        return EXIT_FAILURE;
    }

    char line[BUFSIZ];
    if (!gets(line)) {
        fputs("expected separator from input", stderr);
        return EXIT_FAILURE;
    }
    char sep = line[0];

    char** paths = NULL;
    int num_paths = 0;
    while (gets(line)) {
        num_paths++;
        paths = check_mem(realloc(paths, num_paths * sizeof(char**)));
        paths[num_paths - 1] = check_mem(strdup(line));
    }
    if (num_paths == 0) {
        fputs("expected paths from input", stderr);
        return EXIT_FAILURE;
    }

    char* common = common_path(sep, paths, num_paths);
    printf("%s\n", common);

    free(common);
    for (int i = 0; i < num_paths; i++)
        free(paths[i]);
    free(paths);
}