/* * tree.c - Component hierarchy * * Copyright 2012 by Werner Almesberger * * 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 2 of the License, or * (at your option) any later version. */ #define _GNU_SOURCE /* for strcasecmp */ #include #include #include #include #include "util.h" #include "libs.h" #include "tree.h" struct node *tree = NULL; /* ----- Tree parsing ------------------------------------------------------ */ void read_tree(FILE *file) { char buf[1100]; /* more than enough */ struct node *last = NULL, *node; int depth = -1; const char *s, *p, *e; char *name; int n; next: while (fgets(buf, sizeof(buf), file)) { n = 0; s = buf; while (1) { switch (*s++) { case ' ': n++; continue; case '\t': n = (n+8) & ~7; continue; case 0: case '#': goto next; default: break; } break; } for (p = e = --s; *p && *p != '#' && *p != '\n'; p++) if (*p != ' ' && *p != '\t') e = p; if (!last && n) { fprintf(stderr, "first entry must not be indented\n"); exit(1); } name = malloc(e-s+2); if (!name) { perror("malloc"); exit(1); } memcpy(name, s, e-s+1); name[e-s+1] = 0; node = alloc_type(struct node); node->name = name; node->e = NULL; node->comment = NULL; node->indent = n; node->child = node->next = NULL; if (n > depth) { if (last) last->child = node; else tree = node; node->parent = last; } else { while (last && last->indent != n) last = last->parent; if (!last && n) { fprintf(stderr, "indentation error\n"); exit(1); } last->next = node; node->parent = last->parent; } last = node; depth = n; } } /* ----- Description parsing ----------------------------------------------- */ static struct node *find_comp(struct node *node, const char *name) { struct node *found; while (node) { if (!strcasecmp(node->name, name)) return node; found = find_comp(node->child, name); if (found) return found; node = node->next; } return NULL; } static struct line *new_line(char *s) { const char *uris[] = { "http://", "https://", "ftp://", "file:/", /* one slash, for RFC3986 file:/localpath */ NULL }, **uri = uris; struct line *line; line = alloc_type(struct line); line->s = stralloc(s); /* * Require a slash at all to avoid misdetection. Require only one slash * for compatibility with RFC3986. */ while (*uri && strncmp(s, *uri, strlen(*uri))) uri++; line->url = !!*uri; line->next = NULL; return line; } static void append_line(struct line *line, char *s) { int len1, len2; int spc = !line->url; len1 = strlen(line->s); len2 = strlen(s); line->s = realloc(line->s, len1+len2+spc+1); if (!line->s) { perror("realloc"); exit(1); } if (spc) line->s[len1] = ' '; memcpy(line->s+len1+spc, s, len2); line->s[len1+len2+spc] = 0; } void read_desc(FILE *file) { struct line **anchor = NULL; char buf[1100]; /* more than enough */ struct node *node; char *p, *end; int skip = 0, lineno = 0; while (fgets(buf, sizeof(buf), file)) { lineno++; if (buf[0] == '#') continue; p = strchr(buf, '\n'); if (p) *p = 0; p = buf; if (*buf && !isspace(*buf)) { /* tag is ^.*?:\s */ while (1) { p = strchr(p, ':'); if (!p) { fprintf(stderr, "no tag in line %d\n", lineno); exit(1); } if (!p[1] || isspace(p[1])) break; p++; } *p++ = 0; node = find_comp(tree, buf); if (!node) { fprintf(stderr, "component \"%s\" not found in line %d\n", buf, lineno); skip = 1; continue; } for (anchor = &node->comment; *anchor; anchor = &(*anchor)->next); skip = 0; } if (skip) continue; /* remove leading whitespace */ while (*p && isspace(*p)) p++; if (!*p) { if (*anchor) anchor = &(*anchor)->next; continue; } /* remove training whitespace */ end = strrchr(p, 0); while (isspace(end[-1])) end--; *end = 0; if (*anchor) append_line(*anchor, p); else *anchor = new_line(p); } } /* ----- Associate library entries with tree nodes ------------------------- */ void set_libs(const struct lib *lib, struct node *node) { while (node) { if (!node->child) { node->e = lookup_sym(lib, node->name); if (!node->e) { fprintf(stderr, "symbol %s not found\n", node->name); exit(1); } } set_libs(lib, node->child); node = node->next; } } /* ----- Debug dumps ------------------------------------------------------- */ static void dump_tree_level(const struct node *tree, int level) { const struct node *n; const struct line *line; const struct name *name; for (n = tree; n; n = n->next) { printf("%*s%s", 4*level, "", n->name); if (n->e) { for (name = n->e->names; name; name = name->next) printf("%s%s", name == n->e->names ? " (" : ", ", name->s); printf(")"); } printf("\n"); for (line = n->comment; line; line = line->next) printf("%*s\"%s\"\n", 4*level+2, "", line->s); dump_tree_level(n->child, level+1); } } void dump_tree(void) { dump_tree_level(tree, 0); } static void dump_comp_level(const struct node *tree) { const struct node *n; for (n = tree; n; n = n->next) { if (n->e) printf("%s\n", n->e->names->s); dump_comp_level(n->child); } } void dump_comp(void) { dump_comp_level(tree); }