Root/genkicat/tree.c

1/*
2 * tree.c - Component hierarchy
3 *
4 * Copyright 2012 by Werner Almesberger
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#define _GNU_SOURCE /* for strcasecmp */
13#include <stdlib.h>
14#include <stdio.h>
15#include <string.h>
16#include <ctype.h>
17
18#include "util.h"
19#include "libs.h"
20#include "tree.h"
21
22
23struct node *tree = NULL;
24
25
26/* ----- Tree parsing ------------------------------------------------------ */
27
28
29void read_tree(FILE *file)
30{
31    char buf[1100]; /* more than enough */
32    struct node *last = NULL, *node;
33    int depth = -1;
34    const char *s, *p, *e;
35    char *name;
36    int n;
37
38next:
39    while (fgets(buf, sizeof(buf), file)) {
40        n = 0;
41        s = buf;
42        while (1) {
43            switch (*s++) {
44            case ' ':
45                n++;
46                continue;
47            case '\t':
48                n = (n+8) & ~7;
49                continue;
50            case 0:
51            case '#':
52                goto next;
53            default:
54                break;
55            }
56            break;
57        }
58        for (p = e = --s; *p && *p != '#' && *p != '\n'; p++)
59            if (*p != ' ' && *p != '\t')
60                e = p;
61        if (!last && n) {
62            fprintf(stderr, "first entry must not be indented\n");
63            exit(1);
64        }
65        name = malloc(e-s+2);
66        if (!name) {
67            perror("malloc");
68            exit(1);
69        }
70        memcpy(name, s, e-s+1);
71        name[e-s+1] = 0;
72        node = alloc_type(struct node);
73        node->name = name;
74        node->e = NULL;
75        node->comment = NULL;
76        node->indent = n;
77        node->child = node->next = NULL;
78        if (n > depth) {
79            if (last)
80                last->child = node;
81            else
82                tree = node;
83            node->parent = last;
84        } else {
85            while (last && last->indent != n)
86                last = last->parent;
87            if (!last && n) {
88                fprintf(stderr, "indentation error\n");
89                exit(1);
90            }
91            last->next = node;
92            node->parent = last->parent;
93        }
94        last = node;
95        depth = n;
96    }
97}
98
99
100/* ----- Description parsing ----------------------------------------------- */
101
102
103static struct node *find_comp(struct node *node, const char *name)
104{
105    struct node *found;
106
107    while (node) {
108        if (!strcasecmp(node->name, name))
109            return node;
110        found = find_comp(node->child, name);
111        if (found)
112            return found;
113        node = node->next;
114    }
115    return NULL;
116}
117
118
119static struct line *new_line(char *s)
120{
121    const char *uris[] = {
122        "http://",
123        "https://",
124        "ftp://",
125        "file:/", /* one slash, for RFC3986 file:/localpath */
126        NULL
127    }, **uri = uris;
128    struct line *line;
129
130    line = alloc_type(struct line);
131    line->s = stralloc(s);
132    /*
133     * Require a slash at all to avoid misdetection. Require only one slash
134     * for compatibility with RFC3986.
135     */
136    while (*uri && strncmp(s, *uri, strlen(*uri)))
137        uri++;
138    line->url = !!*uri;
139    line->next = NULL;
140    return line;
141}
142
143
144static void append_line(struct line *line, char *s)
145{
146    int len1, len2;
147    int spc = !line->url;
148
149    len1 = strlen(line->s);
150    len2 = strlen(s);
151    line->s = realloc(line->s, len1+len2+spc+1);
152    if (!line->s) {
153        perror("realloc");
154        exit(1);
155    }
156    if (spc)
157        line->s[len1] = ' ';
158    memcpy(line->s+len1+spc, s, len2);
159    line->s[len1+len2+spc] = 0;
160}
161
162
163void read_desc(FILE *file)
164{
165    struct line **anchor = NULL;
166    char buf[1100]; /* more than enough */
167    struct node *node;
168    char *p, *end;
169    int skip = 0, lineno = 0;
170
171    while (fgets(buf, sizeof(buf), file)) {
172        lineno++;
173        if (buf[0] == '#')
174            continue;
175        p = strchr(buf, '\n');
176        if (p)
177            *p = 0;
178        p = buf;
179        if (*buf && !isspace(*buf)) {
180            /* tag is ^.*?:\s */
181            while (1) {
182                p = strchr(p, ':');
183                if (!p) {
184                    fprintf(stderr, "no tag in line %d\n",
185                        lineno);
186                    exit(1);
187                }
188                if (!p[1] || isspace(p[1]))
189                    break;
190                p++;
191            }
192            *p++ = 0;
193            node = find_comp(tree, buf);
194            if (!node) {
195                fprintf(stderr,
196                    "component \"%s\" not found in line %d\n",
197                    buf, lineno);
198                skip = 1;
199                continue;
200            }
201            for (anchor = &node->comment; *anchor;
202                anchor = &(*anchor)->next);
203            skip = 0;
204        }
205        if (skip)
206            continue;
207
208        /* remove leading whitespace */
209        while (*p && isspace(*p))
210            p++;
211        if (!*p) {
212            if (*anchor)
213                anchor = &(*anchor)->next;
214            continue;
215        }
216
217        /* remove training whitespace */
218        end = strrchr(p, 0);
219        while (isspace(end[-1]))
220            end--;
221        *end = 0;
222
223        if (*anchor)
224            append_line(*anchor, p);
225        else
226            *anchor = new_line(p);
227    }
228}
229
230
231/* ----- Associate library entries with tree nodes ------------------------- */
232
233
234void set_libs(const struct lib *lib, struct node *node)
235{
236    while (node) {
237        if (!node->child) {
238            node->e = lookup_sym(lib, node->name);
239            if (!node->e) {
240                fprintf(stderr, "symbol %s not found\n",
241                    node->name);
242                exit(1);
243            }
244        }
245        set_libs(lib, node->child);
246        node = node->next;
247    }
248}
249
250
251/* ----- Debug dumps ------------------------------------------------------- */
252
253
254static void dump_tree_level(const struct node *tree, int level)
255{
256    const struct node *n;
257    const struct line *line;
258    const struct name *name;
259
260    for (n = tree; n; n = n->next) {
261        printf("%*s%s", 4*level, "", n->name);
262        if (n->e) {
263            for (name = n->e->names; name; name = name->next)
264                printf("%s%s",
265                    name == n->e->names ? " (" : ", ", name->s);
266            printf(")");
267        }
268        printf("\n");
269        for (line = n->comment; line; line = line->next)
270            printf("%*s\"%s\"\n", 4*level+2, "", line->s);
271        dump_tree_level(n->child, level+1);
272    }
273}
274
275
276void dump_tree(void)
277{
278    dump_tree_level(tree, 0);
279}
280
281
282static void dump_comp_level(const struct node *tree)
283{
284    const struct node *n;
285
286    for (n = tree; n; n = n->next) {
287        if (n->e)
288            printf("%s\n", n->e->names->s);
289        dump_comp_level(n->child);
290    }
291}
292
293
294void dump_comp(void)
295{
296    dump_comp_level(tree);
297}
298

Archive Download this file

Branches:
master



interactive