]> Raphaël G. Git Repositories - carabistouilles/commitdiff
Add analyse.c version
authorRaphaël Gertz <git@rapsys.eu>
Tue, 5 Jul 2016 15:40:48 +0000 (17:40 +0200)
committerRaphaël Gertz <git@rapsys.eu>
Tue, 5 Jul 2016 15:40:48 +0000 (17:40 +0200)
analyse.c [new file with mode: 0644]

diff --git a/analyse.c b/analyse.c
new file mode 100644 (file)
index 0000000..1adcdd9
--- /dev/null
+++ b/analyse.c
@@ -0,0 +1,231 @@
+/**
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Raphaël Gertz <rapsys@rapsys.eu>
+ */
+
+/* exit EXIT_FAILURE EXIT_SUCCESS */
+#include <stdlib.h>
+
+/* printf */
+#include <stdio.h>
+
+/* stat S_ISREG */
+#include <sys/stat.h>
+
+/* access R_OK */
+#include <unistd.h>
+
+/* open O_RDONLY */
+#include <fcntl.h>
+
+/* strspn */
+#include <string.h>
+
+/* Zero ascii offset */
+#define ZERO_OFFSET 48
+
+/* Branch cell */
+struct branch {
+       unsigned key;
+       struct branch *next;
+       void *child;
+};
+
+/* Leaf cell */
+struct leaf {
+       unsigned key;
+       struct leaf *next;
+       unsigned count;
+};
+
+/* Lookup leaf prototype */
+struct leaf *lookupLeaf(void **, const char *, unsigned);
+
+/* Main function */
+int main(int argc, char **argv) {
+
+       /* Stat struct */
+       struct stat ss;
+
+       /* File descriptor */
+       int fd;
+
+       /* Return value */
+       int ret;
+
+       /* Line buffer */
+       char line[11] = { 0 };
+
+       /* Current leaf */
+       struct leaf *current;
+
+       /* Tree root */
+       struct branch *tree = NULL;
+
+       /* Unique counter */
+       unsigned unique = 0;
+
+       /* Duplicated counter */
+       unsigned duplicate = 0;
+
+
+       /* Check argument count */
+       if (argc < 2 || argc > 2) {
+               fprintf(stderr, "Usage: %s sirens_fxt.txt\n", argv[0]);
+               exit(EXIT_FAILURE);
+       }
+
+       /* Stat file */
+       if (stat(argv[1], &ss) == -1) {
+               perror("Stat failed");
+               exit(EXIT_FAILURE);
+       }
+
+       /* Check it is a file */
+       if (!S_ISREG(ss.st_mode)) {
+               fprintf(stderr, "%s must be a valid file\n", argv[1]);
+               exit(EXIT_FAILURE);
+       }
+
+       /* Check if readable */
+       if (access(argv[1], R_OK)) {
+               fprintf(stderr, "%s must be readable\n", argv[1]);
+               exit(EXIT_FAILURE);
+       }
+
+       /* Open file */
+       if ((fd = open(argv[1], O_RDONLY)) == -1) {
+               perror("Open failed");
+               exit(EXIT_FAILURE);
+       }
+
+       /* Read file */
+       do {
+               /* Try reading line and check line format */
+               if ((ret = read(fd, &line, 10)) == 10 && strspn(line, "0123456789") == 9 && line[9] == '\n') {
+                       /* Terminate key */
+                       line[9] = '\0';
+                       /* Lookup matching leaf */
+                       current = lookupLeaf((void **)&tree, line, 0);
+                       /* Grow unique */
+                       if (current->count == 0) {
+                               unique++;
+                       } else if (current->count == 1) {
+                               unique--;
+                               duplicate++;
+                       }
+                       current->count++;
+               /* Handle read error */
+               } else if (ret == -1) {
+                       perror("Read failed");
+                       exit(EXIT_FAILURE);
+               /* Handle partial read or invalid line format */
+               } else if (ret > 0) {
+                       line[ret] = '\0';
+                       fprintf(stderr, "%s must be filled with lines matching [0-9]{9}LF format; got \"%s\" instead\n", argv[1], line);
+                       exit(EXIT_FAILURE);
+               }
+       /* Read until end of file */
+       } while (ret != 0);
+
+       /* Close file */
+       if (close(fd) == -1) {
+               perror("Close failed");
+               exit(EXIT_FAILURE);
+       }
+
+       /* Print result */
+       printf("Unique%s: %d, duplicate%s: %d\n", (unique > 1 ? "s" : ""), unique, (duplicate > 1 ? "s" : ""), duplicate);
+
+       /* Successful end */
+       exit(EXIT_SUCCESS);
+}
+
+/* Recursive lookup and populate tree function */
+struct leaf *lookupLeaf(void **base, const char *key, unsigned index) {
+       /* Return leaf */
+       struct leaf *ret;
+
+       /* Insert node on empty level */
+       if (*base == NULL) {
+               /* Branch level */
+               if (index < 8) {
+                       *base = malloc(sizeof(struct branch));
+                       ((struct branch *)*base)->key = key[index] - ZERO_OFFSET;
+                       ((struct branch *)*base)->next = NULL;
+                       ((struct branch *)*base)->child = NULL;
+                       ret = lookupLeaf(&(((struct branch *)*base)->child), key, index + 1);
+               /* Leaf level */
+               } else {
+                       *base = malloc(sizeof(struct leaf));
+                       ((struct leaf *)*base)->key = key[index] - ZERO_OFFSET;
+                       ((struct leaf *)*base)->next = NULL;
+                       ((struct leaf *)*base)->count = 0;
+                       ret = (struct leaf *)*base;
+               }
+       /* Search horizontaly next node */
+       } else {
+               /* Current node for horizontal search */
+               void *current = *base, *prev;
+               /* Branch level */
+               if (index < 8) {
+                       /* Lookup node matching key or allocate it */
+                       while(((struct branch *)current)->key != key[index] - ZERO_OFFSET) {
+                               /* End of horizontal search */
+                               if (((struct branch *)current)->next == NULL) {
+                                       /* Backup current in prev */
+                                       prev = current;
+                                       /* Create new branch with key */
+                                       current = malloc(sizeof(struct branch));
+                                       ((struct branch *)current)->key = key[index] - ZERO_OFFSET;
+                                       ((struct branch *)current)->next = NULL;
+                                       ((struct branch *)current)->child = NULL;
+                                       ((struct branch *)prev)->next = (struct branch *)current;
+                               } else {
+                                       /* Pass to next one */
+                                       current = ((struct branch *)current)->next;
+                               }
+                       }
+
+                       /* Lookup leaf or branch in next level */
+                       ret = lookupLeaf(&(((struct branch *)current)->child), key, index + 1);
+               /* Leaf level */
+               } else {
+                       /* Lookup node matching key or allocate it */
+                       while(((struct leaf *)current)->key != key[index] - ZERO_OFFSET) {
+                               /* End of horizontal search */
+                               if (((struct leaf *)current)->next == NULL) {
+                                       /* Backup current in prev */
+                                       prev = current;
+                                       /* Create new leaf with key */
+                                       current = malloc(sizeof(struct leaf));
+                                       ((struct leaf *)current)->key = key[index] - ZERO_OFFSET;
+                                       ((struct leaf *)current)->next = NULL;
+                                       ((struct leaf *)current)->count = 0;
+                                       ((struct leaf *)prev)->next = (struct leaf *)current;
+                               } else {
+                                       /* Pass to next one */
+                                       current = ((struct leaf *)current)->next;
+                               }
+                       }
+
+                       /* Found leaf, return it */
+                       ret = (struct leaf *)current;
+               }
+       }
+
+       /* Return leaf */
+       return ret;
+}