summaryrefslogtreecommitdiff
path: root/util_liveinfo/src/node.c
diff options
context:
space:
mode:
Diffstat (limited to 'util_liveinfo/src/node.c')
-rw-r--r--util_liveinfo/src/node.c389
1 files changed, 389 insertions, 0 deletions
diff --git a/util_liveinfo/src/node.c b/util_liveinfo/src/node.c
new file mode 100644
index 0000000..ae7da68
--- /dev/null
+++ b/util_liveinfo/src/node.c
@@ -0,0 +1,389 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "node.h"
+
+struct node {
+ char *name;
+ enum node_type type;
+
+ void *data;
+
+ struct node *parent;
+ unsigned char mode;
+ int age;
+
+ struct {
+ struct node *next;
+ struct node *prev;
+ } sibling;
+
+ struct node *child;
+};
+
+int errno; /* External symbol */
+
+char *node_to_abspath(const struct node *node)
+{
+ char *path;
+ char *ptr;
+ const struct node *tmp;
+ int len = 0;
+
+ tmp = node;
+ while (tmp && node_name(tmp)) {
+ len += strlen(node_name(tmp)) + 1; /* trail '/' */
+ tmp = node_parent(tmp);
+ }
+
+ path = malloc(len + 3); /* '/' and '\0' */
+ if (!path) {
+ return NULL;
+ }
+
+ if (!len) {
+ path[0] = '/';
+ path[1] = '\0';
+ } else {
+ ptr = path + len + 1;
+ *ptr = '\0';
+ ptr--;
+ *ptr = '/';
+ tmp = node;
+ while (tmp && node_name(tmp)) {
+ ptr -= (strlen(node_name(tmp)) + 1);
+ *ptr = '/';
+ strncpy(ptr + 1, node_name(tmp), strlen(node_name(tmp)));
+ tmp = node_parent(tmp);
+ }
+ }
+
+ return path;
+}
+
+static inline int next_state(int from, char ch)
+{
+ switch (ch)
+ {
+ case '\0':
+ case '/':
+ return 1;
+ case '.':
+ if (from == 1) {
+ return 2;
+ }
+ if (from == 2) {
+ return 3;
+ }
+ }
+
+ return 4;
+}
+
+static inline void abspath(const char* pBuffer, char* pRet)
+{
+ int idx=0;
+ int state = 1;
+ int from;
+ int src_idx = 0;
+ int src_len = strlen(pBuffer);
+ pRet[idx] = '/';
+ idx ++;
+
+ while (src_idx <= src_len) {
+ from = state;
+ state = next_state(from, pBuffer[src_idx]);
+
+ switch (from) {
+ case 1:
+ if (state != 1) {
+ pRet[idx] = pBuffer[src_idx];
+ idx++;
+ }
+ break;
+ case 2:
+ if (state == 1) {
+ if (idx > 1) {
+ idx--;
+ }
+ } else {
+ pRet[idx] = pBuffer[src_idx];
+ idx++;
+ }
+ break;
+ case 3:
+ // Only can go to the 1 or 4
+ if (state == 1) {
+ idx -= 2;
+ if (idx < 1) {
+ idx = 1;
+ }
+
+ while (idx > 1 && pRet[idx] != '/') {
+ idx--; /* Remove .. */
+ }
+ if (idx > 1 && pRet[idx] == '/') {
+ idx--;
+ }
+ while (idx > 1 && pRet[idx] != '/') {
+ idx--; /* Remove parent folder */
+ }
+ }
+ case 4:
+ pRet[idx] = pBuffer[src_idx];
+ idx++;
+ break;
+ }
+
+ pRet[idx] = '\0';
+ src_idx++;
+ }
+}
+
+struct node *node_find(const struct node *node, const char *path)
+{
+ int len = 0;
+ char *ptr;
+ char *buffer;
+
+ if (*path != '/') {
+ while (node->parent && path[0] == '.' && path[1] == '.') {
+ if (path[2] != '/' && path[2] != '\0') {
+ break;
+ }
+
+ path += 2;
+ path += (path[2] == '/');
+ node = node->parent;
+ }
+ }
+
+ buffer = malloc(strlen(path) + 3); /* add 2 more bytes */
+ if (!buffer) {
+ printf("Error: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ abspath(path, buffer);
+
+ ptr = buffer;
+ do {
+ ptr += (*ptr == '/');
+ for (len = 0; ptr[len] && ptr[len] != '/'; len++);
+ if (!len) {
+ break;
+ }
+
+ if (!strncmp("..", ptr, len)) {
+ ptr += len;
+ node = node->parent ? node->parent : node;
+ continue;
+ }
+
+ if (!strncmp(".", ptr, len)) {
+ ptr += len;
+ continue;
+ }
+
+ node = node->child;
+ if (!node) {
+ break;
+ }
+
+ while (node) {
+ if (!strncmp(node->name, ptr, len) && node->name[len] == '\0') {
+ ptr += len;
+ break;
+ }
+
+ node = node->sibling.next;
+ }
+ } while (*ptr && node);
+
+ free(buffer);
+ return (struct node *)node;
+}
+
+struct node *node_create(struct node *parent, const char *name, enum node_type type)
+{
+ struct node *node;
+
+ node = malloc(sizeof(*node));
+ if (!node) {
+ printf("Error: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ node->parent = parent;
+
+ if (name) {
+ node->name = strdup(name);
+ if (!node->name) {
+ printf("Error: %s\n", strerror(errno));
+ free(node);
+ return NULL;
+ }
+ } else {
+ node->name = NULL;
+ }
+
+ node->type = type;
+
+ node->sibling.next = NULL;
+ node->sibling.prev = NULL;
+
+ node->child = NULL;
+ node->data = NULL;
+
+ if (parent) {
+ if (parent->child) {
+ struct node *tmp;
+ tmp = parent->child;
+ while (tmp->sibling.next) {
+ tmp = tmp->sibling.next;
+ }
+
+ tmp->sibling.next = node;
+ node->sibling.prev = tmp;
+ } else {
+ parent->child = node;
+ }
+ }
+ return node;
+}
+
+void *node_destroy(struct node *node)
+{
+ void *data;
+
+ data = node->data;
+ free(node->name);
+ free(node);
+
+ return data;
+}
+
+void node_delete(struct node *node, void (del_cb)(struct node *node))
+{
+ struct node *tmp;
+ struct node *next;
+ struct node *parent;
+
+ if (node->sibling.prev) {
+ node->sibling.prev->sibling.next = node->sibling.next;
+ }
+
+ if (node->sibling.next) {
+ node->sibling.next->sibling.prev = node->sibling.prev;
+ }
+
+ /* Isolate the node */
+ node->sibling.prev = NULL;
+ node->sibling.next = NULL;
+
+ if (node->parent) {
+ if (node->parent->child == node) {
+ node->parent->child = NULL;
+ }
+
+ node->parent = NULL;
+ }
+
+ tmp = node;
+ while (tmp) {
+ /* Reach to the leaf node */
+ while (tmp->child) {
+ tmp = tmp->child;
+ }
+
+ parent = tmp->parent;
+ next = tmp->sibling.next;
+
+ if (parent && parent->child == tmp) {
+ parent->child = NULL;
+ }
+
+ if (del_cb) {
+ del_cb(tmp);
+ }
+
+ node_destroy(tmp);
+
+ if (next) {
+ tmp = next;
+ } else if (parent) {
+ tmp = parent;
+ } else {
+ tmp = NULL;
+ }
+ }
+}
+
+struct node * const node_next_sibling(const struct node *node)
+{
+ return node->sibling.next;
+}
+
+struct node * const node_prev_sibling(const struct node *node)
+{
+ return node->sibling.prev;
+}
+
+void node_set_mode(struct node *node, int mode)
+{
+ node->mode = mode;
+}
+
+void node_set_data(struct node *node, void *data)
+{
+ node->data = data;
+}
+
+void node_set_type(struct node *node, enum node_type type)
+{
+ node->type = type;
+}
+
+struct node * const node_child(const struct node *node)
+{
+ return node->child;
+}
+
+struct node * const node_parent(const struct node *node)
+{
+ return node->parent;
+}
+
+const int const node_mode(const struct node *node)
+{
+ return node->mode;
+}
+
+void * const node_data(const struct node *node)
+{
+ return node->data;
+}
+
+const enum node_type const node_type(const struct node *node)
+{
+ return node->type;
+}
+
+const char * const node_name(const struct node *node)
+{
+ return node->name;
+}
+
+void node_set_age(struct node *node, int age)
+{
+ node->age = age;
+}
+
+int node_age(struct node *node)
+{
+ return node->age;
+}
+
+/* End of a file */