gencat/comp.c |
1 | | /* |
2 | | * comp.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 "comp.h" |
20 | | |
21 | | |
22 | | struct node *tree = NULL; |
23 | | |
24 | | |
25 | | void read_tree(FILE *file) |
26 | | { |
27 | | char buf[1100]; /* more than enough */ |
28 | | struct node *last = NULL, *node; |
29 | | int depth = -1; |
30 | | const char *s, *p, *e; |
31 | | char *name; |
32 | | int n; |
33 | | |
34 | | next: |
35 | | while (fgets(buf, sizeof(buf), file)) { |
36 | | n = 0; |
37 | | s = buf; |
38 | | while (1) { |
39 | | switch (*s++) { |
40 | | case ' ': |
41 | | n++; |
42 | | continue; |
43 | | case '\t': |
44 | | n = (n+8) & ~7; |
45 | | continue; |
46 | | case 0: |
47 | | case '#': |
48 | | goto next; |
49 | | default: |
50 | | break; |
51 | | } |
52 | | break; |
53 | | } |
54 | | for (p = e = --s; *p && *p != '#' && *p != '\n'; p++) |
55 | | if (*p != ' ' && *p != '\t') |
56 | | e = p; |
57 | | if (!last && n) { |
58 | | fprintf(stderr, "first entry must not be intended\n"); |
59 | | exit(1); |
60 | | } |
61 | | name = malloc(e-s+2); |
62 | | if (!name) { |
63 | | perror("malloc"); |
64 | | exit(1); |
65 | | } |
66 | | memcpy(name, s, e-s+1); |
67 | | name[e-s+1] = 0; |
68 | | node = alloc_type(struct node); |
69 | | node->name = name; |
70 | | node->lib = NULL; |
71 | | node->comment = NULL; |
72 | | node->indent = n; |
73 | | node->child = node->next = NULL; |
74 | | if (n > depth) { |
75 | | if (last) |
76 | | last->child = node; |
77 | | else |
78 | | tree = node; |
79 | | node->parent = last; |
80 | | } else { |
81 | | while (last && last->indent != n) |
82 | | last = last->parent; |
83 | | if (!last && n) { |
84 | | fprintf(stderr, "indentation error\n"); |
85 | | exit(1); |
86 | | } |
87 | | last->next = node; |
88 | | node->parent = last->parent; |
89 | | } |
90 | | last = node; |
91 | | depth = n; |
92 | | } |
93 | | } |
94 | | |
95 | | |
96 | | static struct node *find_comp(struct node *node, const char *name) |
97 | | { |
98 | | struct node *found; |
99 | | |
100 | | while (node) { |
101 | | if (!strcasecmp(node->name, name)) |
102 | | return node; |
103 | | found = find_comp(node->child, name); |
104 | | if (found) |
105 | | return found; |
106 | | node = node->next; |
107 | | } |
108 | | return NULL; |
109 | | } |
110 | | |
111 | | |
112 | | static struct line *new_line(char *s) |
113 | | { |
114 | | struct line *line; |
115 | | |
116 | | line = alloc_type(struct line); |
117 | | line->s = stralloc(s); |
118 | | line->next = NULL; |
119 | | return line; |
120 | | } |
121 | | |
122 | | |
123 | | static void append_line(struct line *line, char *s) |
124 | | { |
125 | | int len1, len2; |
126 | | |
127 | | len1 = strlen(line->s); |
128 | | len2 = strlen(s); |
129 | | line->s = realloc(line->s, len1+len2+1+1); /* separating space */ |
130 | | if (!line->s) { |
131 | | perror("realloc"); |
132 | | exit(1); |
133 | | } |
134 | | line->s[len1] = ' '; |
135 | | memcpy(line->s+len1+1, s, len2); |
136 | | line->s[len1+len2+1] = 0; |
137 | | } |
138 | | |
139 | | |
140 | | void read_desc(FILE *file) |
141 | | { |
142 | | struct line **anchor = NULL; |
143 | | char buf[1100]; /* more than enough */ |
144 | | struct node *node; |
145 | | char *p, *end; |
146 | | int skip = 0, lineno = 0; |
147 | | |
148 | | while (fgets(buf, sizeof(buf), file)) { |
149 | | lineno++; |
150 | | p = strchr(buf, '\n'); |
151 | | if (p) |
152 | | *p = 0; |
153 | | p = buf; |
154 | | if (*buf && !isspace(*buf)) { |
155 | | /* tag is ^.*?:\s */ |
156 | | while (1) { |
157 | | p = strchr(p, ':'); |
158 | | if (!p) { |
159 | | fprintf(stderr, "no tag in line %d\n", |
160 | | lineno); |
161 | | exit(1); |
162 | | } |
163 | | if (!p[1] || isspace(p[1])) |
164 | | break; |
165 | | p++; |
166 | | } |
167 | | *p++ = 0; |
168 | | node = find_comp(tree, buf); |
169 | | if (!node) { |
170 | | fprintf(stderr, |
171 | | "component \"%s\" not found in line %d\n", |
172 | | buf, lineno); |
173 | | skip = 1; |
174 | | continue; |
175 | | } |
176 | | for (anchor = &node->comment; *anchor; |
177 | | anchor = &(*anchor)->next); |
178 | | skip = 0; |
179 | | } |
180 | | if (skip) |
181 | | continue; |
182 | | |
183 | | /* remove leading whitespace */ |
184 | | while (*p && isspace(*p)) |
185 | | p++; |
186 | | if (!*p) { |
187 | | if (*anchor) |
188 | | anchor = &(*anchor)->next; |
189 | | continue; |
190 | | } |
191 | | |
192 | | /* remove training whitespace */ |
193 | | end = strrchr(p, 0); |
194 | | while (isspace(end[-1])) |
195 | | end--; |
196 | | *end = 0; |
197 | | |
198 | | if (*anchor) |
199 | | append_line(*anchor, p); |
200 | | else |
201 | | *anchor = new_line(p); |
202 | | } |
203 | | } |
204 | | |
205 | | |
206 | | void set_libs(struct node *node, |
207 | | const char *(*find_lib)(const char *sym, const struct name **names, |
208 | | int *units)) |
209 | | { |
210 | | while (node) { |
211 | | if (!node->child) { |
212 | | node->lib = |
213 | | find_lib(node->name, &node->names, &node->units); |
214 | | if (!node->lib) { |
215 | | fprintf(stderr, "symbol %s not found\n", |
216 | | node->name); |
217 | | exit(1); |
218 | | } |
219 | | } |
220 | | set_libs(node->child, find_lib); |
221 | | node = node->next; |
222 | | } |
223 | | } |
224 | | |
225 | | |
226 | | static void dump_tree_level(const struct node *tree, int level) |
227 | | { |
228 | | const struct node *n; |
229 | | const struct line *line; |
230 | | const struct name *name; |
231 | | |
232 | | for (n = tree; n; n = n->next) { |
233 | | printf("%*s%s", 4*level, "", n->name); |
234 | | if (n->lib) { |
235 | | for (name = n->names; name; name = name->next) |
236 | | printf("%s%s", |
237 | | name == n->names ? " (" : ", ", name->s); |
238 | | printf(")"); |
239 | | } |
240 | | printf("\n"); |
241 | | for (line = n->comment; line; line = line->next) |
242 | | printf("%*s\"%s\"\n", 4*level+2, "", line->s); |
243 | | dump_tree_level(n->child, level+1); |
244 | | } |
245 | | } |
246 | | |
247 | | |
248 | | void dump_tree(void) |
249 | | { |
250 | | dump_tree_level(tree, 0); |
251 | | } |
252 | | |
253 | | |
254 | | static void dump_comp_level(const struct node *tree) |
255 | | { |
256 | | const struct node *n; |
257 | | |
258 | | for (n = tree; n; n = n->next) { |
259 | | if (n->lib) |
260 | | printf("%s\n", n->names->s); |
261 | | dump_comp_level(n->child); |
262 | | } |
263 | | } |
264 | | |
265 | | |
266 | | void dump_comp(void) |
267 | | { |
268 | | dump_comp_level(tree); |
269 | | } |
gencat/comp.h |
1 | | /* |
2 | | * comp.h - 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 | | #ifndef COMP_H |
13 | | #define COMP_H |
14 | | |
15 | | #include "libs.h" |
16 | | |
17 | | |
18 | | struct line { |
19 | | char *s; |
20 | | struct line *next; |
21 | | }; |
22 | | |
23 | | struct node { |
24 | | const char *name; |
25 | | const char *lib; /* NULL if intermediate node */ |
26 | | const struct name *names; |
27 | | /* canonical name and aliases of component */ |
28 | | int units; /* number of units; undefined if intermediate */ |
29 | | struct line *comment; /* NULL if intermediate node */ |
30 | | int indent; /* level of indentation (characters) */ |
31 | | struct node *parent; |
32 | | struct node *child; |
33 | | struct node *next; |
34 | | }; |
35 | | |
36 | | |
37 | | extern struct node *tree; |
38 | | |
39 | | |
40 | | void read_tree(FILE *file); |
41 | | void read_desc(FILE *file); |
42 | | void set_libs(struct node *node, |
43 | | const char *(*find_lib)(const char *sym, const struct name **names, |
44 | | int *units)); |
45 | | void dump_tree(void); |
46 | | void dump_comp(void); |
47 | | |
48 | | #endif /* !COMP_H */ |
gencat/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 "tree.h" |
| 20 | |
| 21 | |
| 22 | struct node *tree = NULL; |
| 23 | |
| 24 | |
| 25 | void read_tree(FILE *file) |
| 26 | { |
| 27 | char buf[1100]; /* more than enough */ |
| 28 | struct node *last = NULL, *node; |
| 29 | int depth = -1; |
| 30 | const char *s, *p, *e; |
| 31 | char *name; |
| 32 | int n; |
| 33 | |
| 34 | next: |
| 35 | while (fgets(buf, sizeof(buf), file)) { |
| 36 | n = 0; |
| 37 | s = buf; |
| 38 | while (1) { |
| 39 | switch (*s++) { |
| 40 | case ' ': |
| 41 | n++; |
| 42 | continue; |
| 43 | case '\t': |
| 44 | n = (n+8) & ~7; |
| 45 | continue; |
| 46 | case 0: |
| 47 | case '#': |
| 48 | goto next; |
| 49 | default: |
| 50 | break; |
| 51 | } |
| 52 | break; |
| 53 | } |
| 54 | for (p = e = --s; *p && *p != '#' && *p != '\n'; p++) |
| 55 | if (*p != ' ' && *p != '\t') |
| 56 | e = p; |
| 57 | if (!last && n) { |
| 58 | fprintf(stderr, "first entry must not be intended\n"); |
| 59 | exit(1); |
| 60 | } |
| 61 | name = malloc(e-s+2); |
| 62 | if (!name) { |
| 63 | perror("malloc"); |
| 64 | exit(1); |
| 65 | } |
| 66 | memcpy(name, s, e-s+1); |
| 67 | name[e-s+1] = 0; |
| 68 | node = alloc_type(struct node); |
| 69 | node->name = name; |
| 70 | node->lib = NULL; |
| 71 | node->comment = NULL; |
| 72 | node->indent = n; |
| 73 | node->child = node->next = NULL; |
| 74 | if (n > depth) { |
| 75 | if (last) |
| 76 | last->child = node; |
| 77 | else |
| 78 | tree = node; |
| 79 | node->parent = last; |
| 80 | } else { |
| 81 | while (last && last->indent != n) |
| 82 | last = last->parent; |
| 83 | if (!last && n) { |
| 84 | fprintf(stderr, "indentation error\n"); |
| 85 | exit(1); |
| 86 | } |
| 87 | last->next = node; |
| 88 | node->parent = last->parent; |
| 89 | } |
| 90 | last = node; |
| 91 | depth = n; |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | |
| 96 | static struct node *find_comp(struct node *node, const char *name) |
| 97 | { |
| 98 | struct node *found; |
| 99 | |
| 100 | while (node) { |
| 101 | if (!strcasecmp(node->name, name)) |
| 102 | return node; |
| 103 | found = find_comp(node->child, name); |
| 104 | if (found) |
| 105 | return found; |
| 106 | node = node->next; |
| 107 | } |
| 108 | return NULL; |
| 109 | } |
| 110 | |
| 111 | |
| 112 | static struct line *new_line(char *s) |
| 113 | { |
| 114 | struct line *line; |
| 115 | |
| 116 | line = alloc_type(struct line); |
| 117 | line->s = stralloc(s); |
| 118 | line->next = NULL; |
| 119 | return line; |
| 120 | } |
| 121 | |
| 122 | |
| 123 | static void append_line(struct line *line, char *s) |
| 124 | { |
| 125 | int len1, len2; |
| 126 | |
| 127 | len1 = strlen(line->s); |
| 128 | len2 = strlen(s); |
| 129 | line->s = realloc(line->s, len1+len2+1+1); /* separating space */ |
| 130 | if (!line->s) { |
| 131 | perror("realloc"); |
| 132 | exit(1); |
| 133 | } |
| 134 | line->s[len1] = ' '; |
| 135 | memcpy(line->s+len1+1, s, len2); |
| 136 | line->s[len1+len2+1] = 0; |
| 137 | } |
| 138 | |
| 139 | |
| 140 | void read_desc(FILE *file) |
| 141 | { |
| 142 | struct line **anchor = NULL; |
| 143 | char buf[1100]; /* more than enough */ |
| 144 | struct node *node; |
| 145 | char *p, *end; |
| 146 | int skip = 0, lineno = 0; |
| 147 | |
| 148 | while (fgets(buf, sizeof(buf), file)) { |
| 149 | lineno++; |
| 150 | p = strchr(buf, '\n'); |
| 151 | if (p) |
| 152 | *p = 0; |
| 153 | p = buf; |
| 154 | if (*buf && !isspace(*buf)) { |
| 155 | /* tag is ^.*?:\s */ |
| 156 | while (1) { |
| 157 | p = strchr(p, ':'); |
| 158 | if (!p) { |
| 159 | fprintf(stderr, "no tag in line %d\n", |
| 160 | lineno); |
| 161 | exit(1); |
| 162 | } |
| 163 | if (!p[1] || isspace(p[1])) |
| 164 | break; |
| 165 | p++; |
| 166 | } |
| 167 | *p++ = 0; |
| 168 | node = find_comp(tree, buf); |
| 169 | if (!node) { |
| 170 | fprintf(stderr, |
| 171 | "component \"%s\" not found in line %d\n", |
| 172 | buf, lineno); |
| 173 | skip = 1; |
| 174 | continue; |
| 175 | } |
| 176 | for (anchor = &node->comment; *anchor; |
| 177 | anchor = &(*anchor)->next); |
| 178 | skip = 0; |
| 179 | } |
| 180 | if (skip) |
| 181 | continue; |
| 182 | |
| 183 | /* remove leading whitespace */ |
| 184 | while (*p && isspace(*p)) |
| 185 | p++; |
| 186 | if (!*p) { |
| 187 | if (*anchor) |
| 188 | anchor = &(*anchor)->next; |
| 189 | continue; |
| 190 | } |
| 191 | |
| 192 | /* remove training whitespace */ |
| 193 | end = strrchr(p, 0); |
| 194 | while (isspace(end[-1])) |
| 195 | end--; |
| 196 | *end = 0; |
| 197 | |
| 198 | if (*anchor) |
| 199 | append_line(*anchor, p); |
| 200 | else |
| 201 | *anchor = new_line(p); |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | |
| 206 | void set_libs(struct node *node, |
| 207 | const char *(*find_lib)(const char *sym, const struct name **names, |
| 208 | int *units)) |
| 209 | { |
| 210 | while (node) { |
| 211 | if (!node->child) { |
| 212 | node->lib = |
| 213 | find_lib(node->name, &node->names, &node->units); |
| 214 | if (!node->lib) { |
| 215 | fprintf(stderr, "symbol %s not found\n", |
| 216 | node->name); |
| 217 | exit(1); |
| 218 | } |
| 219 | } |
| 220 | set_libs(node->child, find_lib); |
| 221 | node = node->next; |
| 222 | } |
| 223 | } |
| 224 | |
| 225 | |
| 226 | static void dump_tree_level(const struct node *tree, int level) |
| 227 | { |
| 228 | const struct node *n; |
| 229 | const struct line *line; |
| 230 | const struct name *name; |
| 231 | |
| 232 | for (n = tree; n; n = n->next) { |
| 233 | printf("%*s%s", 4*level, "", n->name); |
| 234 | if (n->lib) { |
| 235 | for (name = n->names; name; name = name->next) |
| 236 | printf("%s%s", |
| 237 | name == n->names ? " (" : ", ", name->s); |
| 238 | printf(")"); |
| 239 | } |
| 240 | printf("\n"); |
| 241 | for (line = n->comment; line; line = line->next) |
| 242 | printf("%*s\"%s\"\n", 4*level+2, "", line->s); |
| 243 | dump_tree_level(n->child, level+1); |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | |
| 248 | void dump_tree(void) |
| 249 | { |
| 250 | dump_tree_level(tree, 0); |
| 251 | } |
| 252 | |
| 253 | |
| 254 | static void dump_comp_level(const struct node *tree) |
| 255 | { |
| 256 | const struct node *n; |
| 257 | |
| 258 | for (n = tree; n; n = n->next) { |
| 259 | if (n->lib) |
| 260 | printf("%s\n", n->names->s); |
| 261 | dump_comp_level(n->child); |
| 262 | } |
| 263 | } |
| 264 | |
| 265 | |
| 266 | void dump_comp(void) |
| 267 | { |
| 268 | dump_comp_level(tree); |
| 269 | } |
gencat/tree.h |
| 1 | /* |
| 2 | * tree.h - 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 | #ifndef TREE_H |
| 13 | #define TREE_H |
| 14 | |
| 15 | #include "libs.h" |
| 16 | |
| 17 | |
| 18 | struct line { |
| 19 | char *s; |
| 20 | struct line *next; |
| 21 | }; |
| 22 | |
| 23 | struct node { |
| 24 | const char *name; |
| 25 | const char *lib; /* NULL if intermediate node */ |
| 26 | const struct name *names; |
| 27 | /* canonical name and aliases of component */ |
| 28 | int units; /* number of units; undefined if intermediate */ |
| 29 | struct line *comment; /* NULL if intermediate node */ |
| 30 | int indent; /* level of indentation (characters) */ |
| 31 | struct node *parent; |
| 32 | struct node *child; |
| 33 | struct node *next; |
| 34 | }; |
| 35 | |
| 36 | |
| 37 | extern struct node *tree; |
| 38 | |
| 39 | |
| 40 | void read_tree(FILE *file); |
| 41 | void read_desc(FILE *file); |
| 42 | void set_libs(struct node *node, |
| 43 | const char *(*find_lib)(const char *sym, const struct name **names, |
| 44 | int *units)); |
| 45 | void dump_tree(void); |
| 46 | void dump_comp(void); |
| 47 | |
| 48 | #endif /* !TREE_H */ |