00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00038 #include "fastlib/fx/datanode.h"
00039
00040
00041 #ifndef LINE_MAX
00042 #define LINE_MAX 2048
00043 #endif
00044
00045 static void datanode__reset(struct datanode *node)
00046 {
00047 node->mod_type = 0;
00048 node->val_type = 0;
00049 node->meta = NULL;
00050
00051 node->key = NULL;
00052 node->val = NULL;
00053
00054 node->first_child = NULL;
00055 node->last_child = NULL;
00056 node->next = NULL;
00057 node->parent = NULL;
00058 }
00059
00060 void datanode_init(struct datanode *node, const char *key)
00061 {
00062 datanode__reset(node);
00063 node->key = strdup(key);
00064 }
00065
00066 void datanode_destroy(struct datanode *node)
00067 {
00068 struct datanode *child = node->first_child;
00069
00070 while (child) {
00071 struct datanode *next = child->next;
00072
00073 datanode_destroy(child);
00074 free(child);
00075
00076 child = next;
00077 }
00078
00079 free(node->key);
00080 free(node->val);
00081
00082 datanode__reset(node);
00083 }
00084
00085
00086
00087 struct datanode *datanode_lookup_expert(struct datanode *node, char *path,
00088 int create)
00089 {
00090 char *end = path + strlen(path);
00091 *end = '/';
00092
00093 while (path < end) {
00094 char *slash = strchr(path, '/');
00095 *slash = '\0';
00096
00097
00098 if (unlikely(*path == '\0' || strcmp(path, ".") == 0)) {
00099 path = slash + 1;
00100 continue;
00101 } else if (unlikely(strcmp(path, "..") == 0)) {
00102 if (node->parent) {
00103 node = node->parent;
00104 }
00105 path = slash + 1;
00106 continue;
00107 }
00108
00109
00110
00111
00112
00113 if (!node->last_child
00114 || likely(strcmp(path, node->last_child->key) != 0)) {
00115 struct datanode *child;
00116 struct datanode **prev;
00117
00118
00119
00120
00121 for (prev = &node->first_child, child = node->first_child; child;
00122 prev = &child->next, child = child->next) {
00123 if (unlikely(strcmp(path, child->key) == 0)) {
00124 *prev = child->next;
00125 child->next = NULL;
00126 node->last_child->next = child;
00127 node->last_child = child;
00128 break;
00129 }
00130 }
00131
00132
00133 if (unlikely(!child)) {
00134 if (!create) {
00135 return NULL;
00136 }
00137
00138 child = malloc(sizeof(struct datanode));
00139 datanode__reset(child);
00140
00141 child->key = malloc((slash - path + 1) * sizeof(char));
00142 strcpy(child->key, path);
00143 child->parent = node;
00144 *prev = child;
00145 node->last_child = child;
00146 }
00147 }
00148
00149 node = node->last_child;
00150 path = slash + 1;
00151 }
00152
00153 return node;
00154 }
00155
00156 struct datanode *datanode_lookup(struct datanode *node, const char *path,
00157 int create)
00158 {
00159 struct datanode *retval;
00160 char *buf = strdup(path);
00161
00162 retval = datanode_lookup_expert(node, buf, create);
00163
00164 free(buf);
00165 return retval;
00166 }
00167
00168 static int datanode__exists_impl(struct datanode *node)
00169 {
00170 struct datanode *child;
00171
00172 if (node->val) {
00173 return 1;
00174 }
00175
00176 for (child = node->first_child; child; child = child->next) {
00177 if (datanode__exists_impl(child)) {
00178 return 1;
00179 }
00180 }
00181
00182 return 0;
00183 }
00184
00185 int datanode_exists(struct datanode *node, const char *path)
00186 {
00187 node = datanode_lookup(node, path, 0);
00188
00189 return node && datanode__exists_impl(node);
00190 }
00191
00192 void datanode_copy(struct datanode *dest, struct datanode *src,
00193 int overwrite)
00194 {
00195 struct datanode *child;
00196
00197 if (!dest->val || overwrite) {
00198 dest->mod_type = src->mod_type;
00199 dest->val_type = src->val_type;
00200 dest->meta = src->meta;
00201
00202
00203 if (src->val && src->val_type >= 0) {
00204 free(dest->val);
00205 dest->val = strdup(src->val);
00206 }
00207 }
00208
00209 for (child = src->first_child; child; child = child->next) {
00210 datanode_copy(datanode_lookup_expert(dest, child->key, 1), child,
00211 overwrite);
00212 }
00213 }
00214
00215
00216
00217 static void datanode__write_path(struct datanode *node, FILE *stream)
00218 {
00219 if (node->parent) {
00220 datanode__write_path(node->parent, stream);
00221 putc('/', stream);
00222 }
00223 hex_to_stream(stream, node->key, "_.-+");
00224 }
00225
00226 void datanode_write(struct datanode *node, FILE *stream,
00227 const char *type_char)
00228 {
00229 struct datanode *child;
00230
00231 if (node->val && node->val_type >= 0) {
00232 datanode__write_path(node, stream);
00233 if (type_char) {
00234 fprintf(stream, ":%c", type_char[node->mod_type]);
00235 }
00236 putc(' ', stream);
00237 hex_to_stream(stream, node->val, "_.-+");
00238 putc('\n', stream);
00239 }
00240
00241 for (child = node->first_child; child; child = child->next) {
00242 datanode_write(child, stream, type_char);
00243 }
00244 }
00245
00246 void datanode_read(struct datanode *node, FILE *stream,
00247 const char *type_char, int overwrite)
00248 {
00249 char buf[LINE_MAX];
00250
00251 while (fgets(buf, sizeof(buf), stream) != NULL) {
00252 struct datanode *entry;
00253 char *key;
00254 char *val;
00255 int type;
00256 int len;
00257
00258
00259 for (key = buf; isspace(*key); ++key) {}
00260 if (*key == '\0' || *key == '#') {
00261 continue;
00262 }
00263 for (len = strlen(key); isspace(key[len-1]); --len) {}
00264 key[len] = '\n';
00265
00266
00267 for (val = key; !isspace(*val); ++val) {}
00268 key[len] = '\0';
00269 if (val - key == len) {
00270 val = "";
00271 } else {
00272 len = val - key;
00273 *val = '\0';
00274 while (isspace(*++val)) {}
00275 }
00276
00277
00278 type = 0;
00279 if (len > 2 && key[len-2] == ':') {
00280 if (type_char) {
00281 type = strchr(type_char, key[len-1]) - type_char;
00282 }
00283 key[len-2] = '\0';
00284 } else if (key[len-1] == ':') {
00285 key[len-1] = '\0';
00286 }
00287
00288 unhex_in_place(key);
00289 unhex_in_place(val);
00290
00291 entry = datanode_lookup_expert(node, key, 1);
00292 if (!entry->val || overwrite) {
00293 if (type_char) {
00294 entry->mod_type = type;
00295 }
00296 free(entry->val);
00297 entry->val = strdup(val);
00298 }
00299 }
00300 }