Line data Source code
1 : // Copyright 2014 Bobby Powers. All rights reserved.
2 : // Use of this source code is governed by a BSD-style
3 : // license that can be found in the LICENSE file.
4 :
5 : #include <libgen.h>
6 : #include <errno.h>
7 : #include <stdbool.h>
8 : #include <stdint.h>
9 : #include <stdlib.h>
10 : #include <string.h>
11 : #include <fcntl.h>
12 : #include <unistd.h>
13 : #include <ctype.h>
14 :
15 : #include "utf.h"
16 : #include "sd.h"
17 : #include "sd_internal.h"
18 :
19 :
20 : #define INITIAL_CAP 8
21 :
22 :
23 : static void file_free(File *f);
24 :
25 :
26 : static const char *SD_ERROR_MSGS[] = {
27 : "no error", // SD_ERR_NO_ERROR
28 : "no memory", // SD_ERR_NOMEM
29 : "bad file", // SD_ERR_BAD_FILE
30 : "unspecified error", // SD_ERR_UNSPECIFIED
31 : "bad XML", // SD_ERR_BAD_XML
32 : "bad equation lex", // SD_ERR_BAD_LEX
33 : "EOF", // SD_ERR_EOF
34 : "circularity error", // SD_ERR_CIRCULAR
35 : };
36 :
37 :
38 : SDProject *
39 20 : sd_project_open(const char *path, int *err)
40 : {
41 20 : FILE *f = NULL;
42 : char *dir, *dir_str;
43 20 : SDProject *p = NULL;
44 : int parse_err;
45 :
46 20 : dir_str = strdup(path);
47 20 : dir = dirname(dir_str);
48 :
49 20 : f = fopen(path, "r");
50 20 : if (!f) {
51 2 : if (err)
52 2 : *err = SD_ERR_BAD_FILE;
53 2 : goto error;
54 : }
55 :
56 18 : p = calloc(1, sizeof(*p));
57 18 : if (!p) {
58 0 : if (err)
59 0 : *err = SD_ERR_NOMEM;
60 0 : goto error;
61 : }
62 18 : sd_project_ref(p);
63 :
64 18 : p->dir_path = strdup(dir);
65 :
66 18 : slice_make(&p->files, 0, INITIAL_CAP);
67 18 : if (!p->files.elems) {
68 0 : if (err)
69 0 : *err = SD_ERR_NOMEM;
70 0 : goto error;
71 : }
72 :
73 18 : parse_err = project_parse_file(p, f);
74 18 : if (parse_err) {
75 1 : if (err)
76 1 : *err = SD_ERR_BAD_XML;
77 1 : goto error;
78 : }
79 :
80 17 : free(dir_str);
81 17 : if (f)
82 17 : fclose(f);
83 17 : return p;
84 :
85 : error:
86 3 : free(dir_str);
87 3 : if (f)
88 1 : fclose(f);
89 3 : sd_project_unref(p);
90 3 : return NULL;
91 : }
92 :
93 : void
94 34 : sd_project_ref(SDProject *p)
95 : {
96 34 : __sync_fetch_and_add(&p->refcount, 1);
97 34 : }
98 :
99 : void
100 37 : sd_project_unref(SDProject *p)
101 : {
102 37 : if (!p)
103 3 : return;
104 34 : if (__sync_sub_and_fetch(&p->refcount, 1) == 0) {
105 18 : free(p->dir_path);
106 35 : for (size_t i = 0; i < p->files.len; ++i)
107 17 : file_free(p->files.elems[i]);
108 18 : free(p->files.elems);
109 18 : free(p);
110 : }
111 : }
112 :
113 : SDModel *
114 27 : sd_project_get_model(SDProject *p, const char *n)
115 : {
116 27 : SDModel *m = NULL;
117 27 : if (!p)
118 1 : goto out;
119 :
120 28 : for (size_t i = 0; i < p->files.len; i++) {
121 26 : File *f = p->files.elems[i];
122 37 : for (size_t j = 0; j < f->models.len; j++) {
123 35 : m = f->models.elems[j];
124 : // match root model
125 35 : if (!m->name && !n)
126 : goto out;
127 : // match named model
128 16 : else if (m->name && n && strcmp(m->name, n) == 0)
129 5 : goto out;
130 11 : m = NULL;
131 : }
132 : }
133 : out:
134 27 : sd_model_ref(m);
135 27 : return m;
136 : }
137 :
138 : int
139 17 : project_add_file(SDProject *p, File *f)
140 : {
141 17 : return slice_append(&p->files, f);
142 : }
143 :
144 : void
145 17 : file_free(File *f)
146 : {
147 17 : free(f->version);
148 17 : free(f->header.smile_version);
149 17 : free(f->header.smile_namespace);
150 17 : free(f->header.name);
151 17 : free(f->header.uuid);
152 17 : free(f->header.vendor);
153 17 : free(f->header.product.name);
154 17 : free(f->header.product.version);
155 17 : free(f->header.product.lang);
156 17 : free(f->sim_specs.method);
157 17 : free(f->sim_specs.time_units);
158 38 : for (size_t i = 0; i < f->models.len; ++i)
159 21 : sd_model_unref(f->models.elems[i]);
160 17 : free(f->models.elems);
161 17 : free(f);
162 17 : }
163 :
164 : const char *
165 2 : sd_error_str(int err)
166 : {
167 2 : if (err < SD_ERR_NO_ERROR && err > SD_ERR_MIN)
168 1 : return SD_ERROR_MSGS[-err];
169 1 : return "unknown error";
170 : }
171 :
172 :
173 : void
174 48 : sd_model_ref(SDModel *m)
175 : {
176 48 : if (!m)
177 3 : return;
178 45 : __sync_fetch_and_add(&m->refcount, 1);
179 : }
180 :
181 : void
182 296 : sd_model_unref(SDModel *m)
183 : {
184 296 : if (!m)
185 251 : return;
186 45 : if (__sync_sub_and_fetch(&m->refcount, 1) == 0) {
187 21 : free(m->name);
188 136 : for (size_t i = 0; i < m->vars.len; ++i)
189 115 : var_free(m->vars.elems[i]);
190 21 : free(m->vars.elems);
191 21 : free(m);
192 : }
193 : }
194 :
195 : void
196 255 : var_free(Var *v)
197 : {
198 255 : if (!v)
199 116 : return;
200 :
201 151 : for (size_t i = 0; i < v->inflows.len; ++i)
202 12 : free(v->inflows.elems[i]);
203 139 : free(v->inflows.elems);
204 155 : for (size_t i = 0; i < v->outflows.len; ++i)
205 16 : free(v->outflows.elems[i]);
206 139 : free(v->outflows.elems);
207 147 : for (size_t i = 0; i < v->conns.len; ++i) {
208 8 : Var *ref = v->conns.elems[i];
209 8 : var_free(ref);
210 : }
211 139 : free(v->conns.elems);
212 139 : free(v->name);
213 139 : free(v->eqn);
214 139 : free(v->src);
215 139 : free(v->gf);
216 139 : sd_model_unref(v->model);
217 139 : free(v);
218 : }
|