1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #include <ctype.h>
6 #include <Eina.h>
7 #include "eo_parser.h"
8 #include "eolian_database.h"
9 #include "eolian_priv.h"
10
11 void
database_object_add(Eolian_Unit * unit,const Eolian_Object * obj)12 database_object_add(Eolian_Unit *unit, const Eolian_Object *obj)
13 {
14 /* object storage */
15 eina_hash_add(unit->objects, obj->name, obj);
16 eina_hash_add(unit->state->staging.unit.objects, obj->name, obj);
17 eina_hash_set(unit->state->staging.objects_f, obj->file, eina_list_append
18 ((Eina_List *)eina_hash_find(unit->state->staging.objects_f, obj->file), obj));
19 }
20
21 EAPI Eolian_Object_Type
eolian_object_type_get(const Eolian_Object * obj)22 eolian_object_type_get(const Eolian_Object *obj)
23 {
24 if (!obj) return EOLIAN_OBJECT_UNKNOWN;
25 return obj->type;
26 }
27
28 EAPI const Eolian_Unit *
eolian_object_unit_get(const Eolian_Object * obj)29 eolian_object_unit_get(const Eolian_Object *obj)
30 {
31 if (!obj) return NULL;
32 return obj->unit;
33 }
34
35 EAPI const char *
eolian_object_file_get(const Eolian_Object * obj)36 eolian_object_file_get(const Eolian_Object *obj)
37 {
38 if (!obj) return NULL;
39 return obj->file;
40 }
41
42 EAPI int
eolian_object_line_get(const Eolian_Object * obj)43 eolian_object_line_get(const Eolian_Object *obj)
44 {
45 if (!obj) return 0;
46 return obj->line;
47 }
48
49 EAPI int
eolian_object_column_get(const Eolian_Object * obj)50 eolian_object_column_get(const Eolian_Object *obj)
51 {
52 if (!obj) return 0;
53 return obj->column;
54 }
55
56 EAPI const char *
eolian_object_name_get(const Eolian_Object * obj)57 eolian_object_name_get(const Eolian_Object *obj)
58 {
59 if (!obj) return NULL;
60 return obj->name;
61 }
62
63 EAPI const char *
eolian_object_c_name_get(const Eolian_Object * obj)64 eolian_object_c_name_get(const Eolian_Object *obj)
65 {
66 if (!obj) return NULL;
67 return obj->c_name;
68 }
69
70 typedef struct _Eolian_Namespace_List
71 {
72 Eina_Iterator itr;
73 char *curp;
74 } Eolian_Namespace_List;
75
76 static Eina_Bool
_nmsp_iterator_next(Eolian_Namespace_List * it,void ** data)77 _nmsp_iterator_next(Eolian_Namespace_List *it, void **data)
78 {
79 if (!it || !it->curp)
80 return EINA_FALSE;
81
82 char *ndot = strchr(it->curp, '.');
83 if (!ndot)
84 return EINA_FALSE;
85
86 *ndot = '\0';
87 if (data) *data = it->curp;
88 it->curp = ndot + 1;
89 return EINA_TRUE;
90 }
91
92 static void *
_nmsp_container_get(Eina_Iterator * it EINA_UNUSED)93 _nmsp_container_get(Eina_Iterator *it EINA_UNUSED)
94 {
95 return NULL;
96 }
97
98 EAPI const char *
eolian_object_short_name_get(const Eolian_Object * obj)99 eolian_object_short_name_get(const Eolian_Object *obj)
100 {
101 if (!obj || !obj->name) return NULL;
102 const char *ldot = strrchr(obj->name, '.');
103 if (ldot)
104 return ldot + 1;
105 return obj->name;
106 }
107
108 EAPI Eina_Iterator *
eolian_object_namespaces_get(const Eolian_Object * obj)109 eolian_object_namespaces_get(const Eolian_Object *obj)
110 {
111 if (!obj || !obj->name || !strchr(obj->name, '.')) return NULL;
112
113 size_t nstrl = strlen(obj->name) + 1;
114 size_t anstrl = nstrl - 1 - (nstrl - 1) % sizeof(void *) + sizeof(void *);
115
116 Eolian_Namespace_List *it = malloc(sizeof(Eolian_Namespace_List) + anstrl);
117 memset(&it->itr, 0, sizeof(Eina_Iterator));
118 it->curp = (char *)(it + 1);
119 memcpy(it->curp, obj->name, nstrl);
120
121 EINA_MAGIC_SET(&it->itr, EINA_MAGIC_ITERATOR);
122 it->itr.version = EINA_ITERATOR_VERSION;
123 it->itr.next = FUNC_ITERATOR_NEXT(_nmsp_iterator_next);
124 it->itr.get_container = _nmsp_container_get;
125 it->itr.free = FUNC_ITERATOR_FREE(free);
126 return &it->itr;
127 }
128
129 EAPI Eina_Bool
eolian_object_is_beta(const Eolian_Object * obj)130 eolian_object_is_beta(const Eolian_Object *obj)
131 {
132 if (!obj) return EINA_FALSE;
133 return obj->is_beta;
134 }
135
database_doc_del(Eolian_Documentation * doc)136 void database_doc_del(Eolian_Documentation *doc)
137 {
138 if (!doc) return;
139 eina_stringshare_del(doc->summary);
140 eina_stringshare_del(doc->description);
141 eina_stringshare_del(doc->since);
142 eina_list_free(doc->ref_dbg);
143 free(doc);
144 }
145
146 EAPI const char *
eolian_documentation_summary_get(const Eolian_Documentation * doc)147 eolian_documentation_summary_get(const Eolian_Documentation *doc)
148 {
149 EINA_SAFETY_ON_NULL_RETURN_VAL(doc, NULL);
150 return doc->summary;
151 }
152
153 EAPI const char *
eolian_documentation_description_get(const Eolian_Documentation * doc)154 eolian_documentation_description_get(const Eolian_Documentation *doc)
155 {
156 EINA_SAFETY_ON_NULL_RETURN_VAL(doc, NULL);
157 return doc->description;
158 }
159
160 EAPI const char *
eolian_documentation_since_get(const Eolian_Documentation * doc)161 eolian_documentation_since_get(const Eolian_Documentation *doc)
162 {
163 EINA_SAFETY_ON_NULL_RETURN_VAL(doc, NULL);
164 return doc->since;
165 }
166
167 EAPI Eina_List *
eolian_documentation_string_split(const char * doc)168 eolian_documentation_string_split(const char *doc)
169 {
170 EINA_SAFETY_ON_NULL_RETURN_VAL(doc, NULL);
171 if (!doc[0])
172 return NULL;
173 const char *sep = strstr(doc, "\n\n");
174 Eina_List *ret = NULL;
175 for (;;)
176 {
177 Eina_Strbuf *buf = eina_strbuf_new();
178 if (sep)
179 eina_strbuf_append_length(buf, doc, sep - doc);
180 else
181 eina_strbuf_append(buf, doc);
182 eina_strbuf_trim(buf);
183 if (eina_strbuf_length_get(buf))
184 ret = eina_list_append(ret, eina_strbuf_string_steal(buf));
185 eina_strbuf_free(buf);
186 if (!sep)
187 break;
188 doc = sep + 2;
189 sep = strstr(doc, "\n\n");
190 }
191 return ret;
192 }
193
194 static Eina_Bool
_skip_ref_word(const char ** doc)195 _skip_ref_word(const char **doc)
196 {
197 if (((*doc)[0] != '_') && !isalpha((*doc)[0]))
198 return EINA_FALSE;
199
200 while (((*doc)[0] == '_') || isalnum((*doc)[0]))
201 ++*doc;
202
203 return EINA_TRUE;
204 }
205
206 /* this make sure the format is correct at least, it cannot verify the
207 * correctness of the reference itself (but Eolian will do it in its
208 * lexer, so there is nothing to worry about; all references are guaranteed
209 * to be right
210 */
211 static Eolian_Doc_Token_Type
_get_ref_token(const char * doc,const char ** doc_end)212 _get_ref_token(const char *doc, const char **doc_end)
213 {
214 /* not a ref at all, for convenience */
215 if (doc[0] != '@')
216 return EOLIAN_DOC_TOKEN_UNKNOWN;
217
218 ++doc;
219
220 Eina_Bool is_event = (doc[0] == '[');
221 if (is_event)
222 ++doc;
223
224 if (_skip_ref_word(&doc))
225 {
226 while (doc[0] == '.')
227 {
228 ++doc;
229 if (!_skip_ref_word(&doc))
230 {
231 --doc;
232 break;
233 }
234 }
235 if (is_event) while (doc[0] == ',')
236 {
237 ++doc;
238 if (!_skip_ref_word(&doc))
239 {
240 --doc;
241 break;
242 }
243 }
244 }
245 else
246 return EOLIAN_DOC_TOKEN_UNKNOWN;
247
248 if (is_event)
249 {
250 if (doc[0] != ']')
251 return EOLIAN_DOC_TOKEN_UNKNOWN;
252 ++doc;
253 }
254
255 if (doc_end)
256 *doc_end = doc;
257
258 /* got a reference */
259 return EOLIAN_DOC_TOKEN_REF;
260 }
261
262 EAPI const char *
eolian_documentation_tokenize(const char * doc,Eolian_Doc_Token * ret)263 eolian_documentation_tokenize(const char *doc, Eolian_Doc_Token *ret)
264 {
265 /* token is used for statekeeping, so force it */
266 EINA_SAFETY_ON_NULL_RETURN_VAL(ret, NULL);
267
268 /* we've reached the end or invalid input */
269 if (!doc || !doc[0])
270 {
271 ret->text = ret->text_end = NULL;
272 ret->type = EOLIAN_DOC_TOKEN_UNKNOWN;
273 return NULL;
274 }
275
276 Eina_Bool cont = (ret->type != EOLIAN_DOC_TOKEN_UNKNOWN);
277
278 /* we can only check notes etc at beginning of parsing */
279 if (cont)
280 goto mloop;
281
282 #define CMP_MARK_NOTE(doc, note) !strncmp(doc, note ": ", sizeof(note) + 1)
283
284 /* different types of notes */
285 if (CMP_MARK_NOTE(doc, "Note"))
286 {
287 ret->text = doc;
288 ret->text_end = doc + sizeof("Note:");
289 ret->type = EOLIAN_DOC_TOKEN_MARK_NOTE;
290 return ret->text_end;
291 }
292 else if (CMP_MARK_NOTE(doc, "Warning"))
293 {
294 ret->text = doc;
295 ret->text_end = doc + sizeof("Warning:");
296 ret->type = EOLIAN_DOC_TOKEN_MARK_WARNING;
297 return ret->text_end;
298 }
299 else if (CMP_MARK_NOTE(doc, "Remark"))
300 {
301 ret->text = doc;
302 ret->text_end = doc + sizeof("Remark:");
303 ret->type = EOLIAN_DOC_TOKEN_MARK_REMARK;
304 return ret->text_end;
305 }
306 else if (CMP_MARK_NOTE(doc, "TODO"))
307 {
308 ret->text = doc;
309 ret->text_end = doc + sizeof("TODO:");
310 ret->type = EOLIAN_DOC_TOKEN_MARK_TODO;
311 return ret->text_end;
312 }
313
314 #undef CMP_MARK_NOTE
315
316 mloop:
317 /* monospace markup ($foo) */
318 if ((doc[0] == '$') && ((doc[1] == '_') || isalpha(doc[1])))
319 {
320 ret->text = ++doc;
321 ret->text_end = ret->text;
322 while ((ret->text_end[0] == '_') || isalnum(ret->text_end[0]))
323 ++ret->text_end;
324 ret->type = EOLIAN_DOC_TOKEN_MARKUP_MONOSPACE;
325 return ret->text_end;
326 }
327
328 /* complex monospace markup ($[...]) */
329 if ((doc[0] == '$') && (doc[1] == '['))
330 {
331 doc += 2;
332 ret->text = doc;
333 ret->text_end = ret->text;
334 while ((ret->text_end[0] != '\0') && (ret->text_end[0] != ']') &&
335 (ret->text_end[0] != '\n'))
336 {
337 /* escape: skip backslash */
338 if ((ret->text_end[0] == '\\') && (ret->text_end[1] != '\0') &&
339 (ret->text_end[1] != '\n'))
340 ++ret->text_end;
341 ++ret->text_end;
342 }
343 ret->type = EOLIAN_DOC_TOKEN_MARKUP_MONOSPACE;
344 /* return past the ending bracket as that's markup syntax */
345 if (ret->text_end[0] == ']')
346 return ret->text_end + 1;
347 return ret->text_end;
348 }
349
350 /* references */
351 Eolian_Doc_Token_Type rtp = _get_ref_token(doc, &ret->text_end);
352 if (rtp != EOLIAN_DOC_TOKEN_UNKNOWN)
353 {
354 ret->text = doc + 1;
355 ret->type = rtp;
356 return ret->text_end;
357 }
358
359 const char *schr = doc, *pschr = NULL;
360 /* keep finding potential tokens until a suitable one is found
361 * terminate text token there (it also means next token can directly
362 * be tested for event/monospace)
363 */
364 while ((schr = strpbrk(schr, "@$")))
365 {
366 /* escape sequences */
367 if ((schr != doc) && (schr[-1] == '\\'))
368 {
369 schr += 1;
370 continue;
371 }
372 /* monospace markup */
373 if ((schr[0] == '$') && (
374 (schr[1] == '_') || (schr[1] == '[') || isalpha(schr[1])))
375 {
376 pschr = schr;
377 break;
378 }
379 /* references */
380 if (_get_ref_token(schr, NULL) != EOLIAN_DOC_TOKEN_UNKNOWN)
381 {
382 pschr = schr;
383 break;
384 }
385 /* nothing, keep matching text from next char on */
386 schr += 1;
387 }
388
389 /* figure out where we actually end */
390 ret->text = doc;
391 ret->text_end = pschr ? pschr : (doc + strlen(doc));
392 ret->type = EOLIAN_DOC_TOKEN_TEXT;
393 return ret->text_end;
394 }
395
396 EAPI void
eolian_doc_token_init(Eolian_Doc_Token * tok)397 eolian_doc_token_init(Eolian_Doc_Token *tok)
398 {
399 if (!tok)
400 return;
401 tok->type = EOLIAN_DOC_TOKEN_UNKNOWN;
402 tok->text = tok->text_end = NULL;
403 }
404
405 EAPI Eolian_Doc_Token_Type
eolian_doc_token_type_get(const Eolian_Doc_Token * tok)406 eolian_doc_token_type_get(const Eolian_Doc_Token *tok)
407 {
408 EINA_SAFETY_ON_NULL_RETURN_VAL(tok, EOLIAN_DOC_TOKEN_UNKNOWN);
409 return tok->type;
410 }
411
412 EAPI char *
eolian_doc_token_text_get(const Eolian_Doc_Token * tok)413 eolian_doc_token_text_get(const Eolian_Doc_Token *tok)
414 {
415 EINA_SAFETY_ON_NULL_RETURN_VAL(tok, NULL);
416 if (tok->type == EOLIAN_DOC_TOKEN_UNKNOWN)
417 return NULL;
418 Eina_Strbuf *buf = eina_strbuf_new();
419 for (const char *p = tok->text; p != tok->text_end; ++p)
420 {
421 if (*p == '\\') ++p;
422 if (p != tok->text_end)
423 eina_strbuf_append_char(buf, *p);
424 }
425 char *ptr = eina_strbuf_string_steal(buf);
426 eina_strbuf_free(buf);
427 return ptr;
428 }
429
430 static Eolian_Object_Type
_resolve_event(char * name,const Eolian_Unit * unit1,const Eolian_Unit * unit2,const Eolian_Object ** data1,const Eolian_Object ** data2)431 _resolve_event(char *name, const Eolian_Unit *unit1, const Eolian_Unit *unit2,
432 const Eolian_Object **data1, const Eolian_Object **data2)
433 {
434 /* never trust the user */
435 if (name[0] == ',')
436 return EOLIAN_OBJECT_UNKNOWN;
437
438 char *evname = strrchr(name, '.');
439 if (!evname)
440 return EOLIAN_OBJECT_UNKNOWN;
441
442 *evname++ = '\0';
443 const Eolian_Class *cl = eolian_unit_class_by_name_get(unit1, name);
444 if (!cl && unit2)
445 cl = eolian_unit_class_by_name_get(unit2, name);
446 if (!cl)
447 return EOLIAN_OBJECT_UNKNOWN;
448
449 const Eolian_Event *ev = eolian_class_event_by_name_get(cl, evname);
450 if (!ev)
451 return EOLIAN_OBJECT_UNKNOWN;
452
453 if (data1) *data1 = &cl->base;
454 if (data2) *data2 = &ev->base;
455 return EOLIAN_OBJECT_EVENT;
456 }
457
458 Eolian_Object_Type
database_doc_token_ref_resolve(const Eolian_Doc_Token * tok,const Eolian_Unit * unit1,const Eolian_Unit * unit2,const Eolian_Object ** data1,const Eolian_Object ** data2)459 database_doc_token_ref_resolve(const Eolian_Doc_Token *tok,
460 const Eolian_Unit *unit1, const Eolian_Unit *unit2,
461 const Eolian_Object **data1, const Eolian_Object **data2)
462 {
463 if (tok->type != EOLIAN_DOC_TOKEN_REF)
464 return EOLIAN_OBJECT_UNKNOWN;
465
466 size_t nlen = tok->text_end - tok->text;
467
468 /* events are handled separately */
469 if (tok->text[0] == '[')
470 {
471 /* strip brackets */
472 size_t elen = nlen - 2;
473 char *ename = alloca(elen + 1);
474 memcpy(ename, tok->text + 1, elen);
475 ename[elen] = '\0';
476 return _resolve_event(ename, unit1, unit2, data1, data2);
477 }
478
479 char *name = alloca(nlen + 1);
480 memcpy(name, tok->text, nlen);
481 name[nlen] = '\0';
482
483 const Eolian_Object *decl = eolian_unit_object_by_name_get(unit1, name);
484 if (!decl && unit2)
485 decl = eolian_unit_object_by_name_get(unit2, name);
486 if (decl)
487 {
488 if (data1) *data1 = decl;
489 Eolian_Object_Type tp = eolian_object_type_get(decl);
490 switch (tp)
491 {
492 case EOLIAN_OBJECT_CLASS:
493 case EOLIAN_OBJECT_TYPEDECL:
494 case EOLIAN_OBJECT_CONSTANT:
495 case EOLIAN_OBJECT_ERROR:
496 /* we only allow certain types to be referenced */
497 return tp;
498 default:
499 return EOLIAN_OBJECT_UNKNOWN;
500 }
501 }
502
503 /* from here it can only be a function, a struct field or an enum field */
504
505 char *suffix = strrchr(name, '.');
506 /* no suffix, therefore invalid */
507 if (!suffix)
508 return EOLIAN_OBJECT_UNKNOWN;
509
510 /* name will terminate before suffix, suffix will be standalone */
511 *suffix++ = '\0';
512
513 /* try a struct field */
514 const Eolian_Typedecl *tpd = eolian_unit_struct_by_name_get(unit1, name);
515 if (!tpd && unit2)
516 tpd = eolian_unit_struct_by_name_get(unit2, name);
517 if (tpd)
518 {
519 const Eolian_Struct_Type_Field *fld = eolian_typedecl_struct_field_get(tpd, suffix);
520 /* field itself is invalid */
521 if (!fld)
522 return EOLIAN_OBJECT_UNKNOWN;
523 if (data1) *data1 = &tpd->base;
524 if (data2) *data2 = &fld->base;
525 return EOLIAN_OBJECT_STRUCT_FIELD;
526 }
527
528 /* try an enum field */
529 tpd = eolian_unit_enum_by_name_get(unit1, name);
530 if (!tpd && unit2)
531 tpd = eolian_unit_enum_by_name_get(unit2, name);
532 if (tpd)
533 {
534 const Eolian_Enum_Type_Field *fld = eolian_typedecl_enum_field_get(tpd, suffix);
535 /* field itself is invalid */
536 if (!fld)
537 return EOLIAN_OBJECT_UNKNOWN;
538 if (data1) *data1 = &tpd->base;
539 if (data2) *data2 = &fld->base;
540 return EOLIAN_OBJECT_ENUM_FIELD;
541 }
542
543 /* now it can only be a function or invalid */
544
545 Eolian_Function_Type ftype = EOLIAN_UNRESOLVED;
546 if (!strcmp(suffix, "get"))
547 ftype = EOLIAN_PROP_GET;
548 else if (!strcmp(suffix, "set"))
549 ftype = EOLIAN_PROP_SET;
550
551 if (ftype != EOLIAN_UNRESOLVED)
552 {
553 suffix = strrchr(name, '.');
554 /* wrong suffix, therefore invalid */
555 if (!suffix)
556 return EOLIAN_OBJECT_UNKNOWN;
557 /* re-terminate */
558 *suffix++ = '\0';
559 }
560
561 const Eolian_Class *cl = eolian_unit_class_by_name_get(unit1, name);
562 if (!cl && unit2)
563 cl = eolian_unit_class_by_name_get(unit2, name);
564 if (!cl)
565 return EOLIAN_OBJECT_UNKNOWN;
566
567 const Eolian_Function *fid = eolian_class_function_by_name_get(cl, suffix, ftype);
568 if (!fid)
569 return EOLIAN_OBJECT_UNKNOWN;
570
571 /* got a func */
572 if (data1) *data1 = &cl->base;
573 if (data2) *data2 = &fid->base;
574 return EOLIAN_OBJECT_FUNCTION;
575 }
576
577 EAPI Eolian_Object_Type
eolian_doc_token_ref_resolve(const Eolian_Doc_Token * tok,const Eolian_State * state,const Eolian_Object ** data,const Eolian_Object ** data2)578 eolian_doc_token_ref_resolve(const Eolian_Doc_Token *tok, const Eolian_State *state,
579 const Eolian_Object **data, const Eolian_Object **data2)
580 {
581 return database_doc_token_ref_resolve(tok, (const Eolian_Unit *)state, NULL, data, data2);
582 }
583
584 void
database_unit_init(Eolian_State * state,Eolian_Unit * unit,const char * file)585 database_unit_init(Eolian_State *state, Eolian_Unit *unit, const char *file)
586 {
587 unit->file = eina_stringshare_ref(file);
588 unit->state = state;
589
590 unit->children = eina_hash_stringshared_new(NULL);
591 unit->classes = eina_hash_stringshared_new(EINA_FREE_CB(database_class_del));
592 unit->constants = eina_hash_stringshared_new(EINA_FREE_CB(database_constant_del));
593 unit->errors = eina_hash_stringshared_new(EINA_FREE_CB(database_error_del));
594 unit->aliases = eina_hash_stringshared_new(EINA_FREE_CB(database_typedecl_del));
595 unit->structs = eina_hash_stringshared_new(EINA_FREE_CB(database_typedecl_del));
596 unit->enums = eina_hash_stringshared_new(EINA_FREE_CB(database_typedecl_del));
597 unit->objects = eina_hash_stringshared_new(NULL);
598
599 /* baseline version; support for higher featurelevel must be specified explicitly */
600 unit->version = 1;
601 }
602
603 static void
_unit_contents_del(Eolian_Unit * unit)604 _unit_contents_del(Eolian_Unit *unit)
605 {
606 eina_stringshare_del(unit->file);
607 eina_hash_free(unit->children);
608 eina_hash_free(unit->classes);
609 eina_hash_free(unit->constants);
610 eina_hash_free(unit->errors);
611 eina_hash_free(unit->aliases);
612 eina_hash_free(unit->structs);
613 eina_hash_free(unit->enums);
614 eina_hash_free(unit->objects);
615 }
616
617 void
database_unit_del(Eolian_Unit * unit)618 database_unit_del(Eolian_Unit *unit)
619 {
620 if (!unit)
621 return;
622
623 _unit_contents_del(unit);
624 free(unit);
625 }
626
627 static Eina_Bool
_hashlist_free_cb(const Eina_Hash * hash EINA_UNUSED,const void * key EINA_UNUSED,void * data,void * fdata EINA_UNUSED)628 _hashlist_free_cb(const Eina_Hash *hash EINA_UNUSED,
629 const void *key EINA_UNUSED,
630 void *data, void *fdata EINA_UNUSED)
631 {
632 eina_list_free((Eina_List *)data);
633 return EINA_TRUE;
634 }
635
636 static void
_hashlist_free(Eina_Hash * h)637 _hashlist_free(Eina_Hash *h)
638 {
639 eina_hash_foreach(h, _hashlist_free_cb, NULL);
640 eina_hash_free(h);
641 }
642
643 static void
_hashlist_free_buckets(Eina_Hash * h)644 _hashlist_free_buckets(Eina_Hash *h)
645 {
646 eina_hash_foreach(h, _hashlist_free_cb, NULL);
647 eina_hash_free_buckets(h);
648 }
649
650 static void
_state_area_init(Eolian_State * state,Eolian_State_Area * a)651 _state_area_init(Eolian_State *state, Eolian_State_Area *a)
652 {
653 database_unit_init(state, &a->unit, NULL);
654
655 a->units = eina_hash_stringshared_new(NULL);
656
657 a->classes_f = eina_hash_stringshared_new(NULL);
658 a->aliases_f = eina_hash_stringshared_new(NULL);
659 a->structs_f = eina_hash_stringshared_new(NULL);
660 a->enums_f = eina_hash_stringshared_new(NULL);
661 a->constants_f = eina_hash_stringshared_new(NULL);
662 a->errors_f = eina_hash_stringshared_new(NULL);
663 a->objects_f = eina_hash_stringshared_new(NULL);
664 }
665
666 static Eina_Bool
_ulist_free_cb(const Eina_Hash * hash EINA_UNUSED,const void * key EINA_UNUSED,void * data,void * fdata EINA_UNUSED)667 _ulist_free_cb(const Eina_Hash *hash EINA_UNUSED,
668 const void *key EINA_UNUSED,
669 void *data, void *fdata EINA_UNUSED)
670 {
671 database_unit_del((Eolian_Unit *)data);
672 return EINA_TRUE;
673 }
674
675 static void
_state_area_contents_del(Eolian_State_Area * a)676 _state_area_contents_del(Eolian_State_Area *a)
677 {
678 _unit_contents_del(&a->unit);
679
680 eina_hash_foreach(a->units, _ulist_free_cb, NULL);
681 eina_hash_free(a->units);
682
683 eina_hash_free(a->classes_f);
684 _hashlist_free(a->aliases_f);
685 _hashlist_free(a->structs_f);
686 _hashlist_free(a->enums_f);
687 _hashlist_free(a->constants_f);
688 _hashlist_free(a->errors_f);
689 _hashlist_free(a->objects_f);
690 }
691
692 static void
_default_panic_cb(const Eolian_State * state EINA_UNUSED,const char * msg)693 _default_panic_cb(const Eolian_State *state EINA_UNUSED, const char *msg)
694 {
695 _eolian_log(msg);
696 }
697
698 static void
_default_error_cb(const Eolian_Object * obj,const char * msg,void * data EINA_UNUSED)699 _default_error_cb(const Eolian_Object *obj, const char *msg, void *data EINA_UNUSED)
700 {
701 if (obj)
702 _eolian_log_line(obj->file, obj->line, obj->column, msg);
703 else
704 _eolian_log(msg);
705 }
706
707 EAPI Eolian_State *
eolian_state_new(void)708 eolian_state_new(void)
709 {
710 Eolian_State *state = calloc(1, sizeof(Eolian_State));
711 if (!state)
712 return NULL;
713
714 state->panic = _default_panic_cb;
715
716 if (setjmp(state->jmp_env))
717 {
718 state->panic(state, state->panic_msg);
719 eina_stringshare_del(state->panic_msg);
720 exit(EXIT_FAILURE);
721 }
722
723 state->error = _default_error_cb;
724
725 _state_area_init(state, &state->main);
726 _state_area_init(state, &state->staging);
727
728 state->filenames_eo = eina_hash_string_small_new(free);
729 state->filenames_eot = eina_hash_string_small_new(free);
730
731 state->defer = eina_hash_string_small_new(NULL);
732
733 return state;
734 }
735
736 EAPI void
eolian_state_free(Eolian_State * state)737 eolian_state_free(Eolian_State *state)
738 {
739 if (!state)
740 return;
741
742 _state_area_contents_del(&state->main);
743 _state_area_contents_del(&state->staging);
744
745 eina_hash_free(state->filenames_eo);
746 eina_hash_free(state->filenames_eot);
747
748 eina_hash_free(state->defer);
749
750 free(state);
751 }
752
753 EAPI Eolian_Panic_Cb
eolian_state_panic_cb_set(Eolian_State * state,Eolian_Panic_Cb cb)754 eolian_state_panic_cb_set(Eolian_State *state, Eolian_Panic_Cb cb)
755 {
756 Eolian_Panic_Cb old_cb = state->panic;
757 state->panic = cb ? cb : _default_panic_cb;
758 return old_cb;
759 }
760
761 EAPI Eolian_Error_Cb
eolian_state_error_cb_set(Eolian_State * state,Eolian_Error_Cb cb)762 eolian_state_error_cb_set(Eolian_State *state, Eolian_Error_Cb cb)
763 {
764 Eolian_Error_Cb old_cb = state->error;
765 state->error = cb ? cb : _default_error_cb;
766 return old_cb;
767 }
768
769 EAPI void *
eolian_state_error_data_set(Eolian_State * state,void * data)770 eolian_state_error_data_set(Eolian_State *state, void *data)
771 {
772 void *old_data = state->error_data;
773 state->error_data = data;
774 return old_data;
775 }
776
777 #define EO_SUFFIX ".eo"
778 #define EOT_SUFFIX ".eot"
779
780 static char *
join_path(const char * path,const char * file)781 join_path(const char *path, const char *file)
782 {
783 Eina_Strbuf *buf = eina_strbuf_new();
784 char *ret;
785
786 eina_strbuf_append(buf, path);
787 eina_strbuf_append_char(buf, '/');
788 eina_strbuf_append(buf, file);
789
790 ret = eina_file_path_sanitize(eina_strbuf_string_get(buf));
791 eina_strbuf_free(buf);
792 return ret;
793 }
794
795 typedef struct _Scan_State
796 {
797 Eolian_State *eos;
798 Eina_Bool succ;
799 } Scan_State;
800
801 static void
_scan_cb(const char * name,const char * path,void * data)802 _scan_cb(const char *name, const char *path, void *data)
803 {
804 Scan_State *sst = data;
805 Eina_Bool is_eo = eina_str_has_suffix(name, EO_SUFFIX);
806 if (!is_eo && !eina_str_has_suffix(name, EOT_SUFFIX)) return;
807 Eina_Hash *fh = is_eo ? sst->eos->filenames_eo : sst->eos->filenames_eot;
808 const char *origpath = eina_hash_find(fh, name);
809 char *newpath = join_path(path, name);
810 if (origpath)
811 {
812 if (strcmp(origpath, newpath))
813 {
814 eolian_state_log(sst->eos,
815 "conflicting paths for '%s': '%s' -> '%s'",
816 name, origpath, newpath);
817 sst->succ = EINA_FALSE;
818 }
819 free(newpath);
820 }
821 else
822 eina_hash_add(fh, name, newpath);
823 }
824
825 EAPI Eina_Bool
eolian_state_directory_add(Eolian_State * state,const char * dir)826 eolian_state_directory_add(Eolian_State *state, const char *dir)
827 {
828 if (!dir || !state) return EINA_FALSE;
829 Scan_State sst = { state, EINA_TRUE };
830 return eina_file_dir_list(dir, EINA_TRUE, _scan_cb, &sst) && sst.succ;
831 }
832
833 EAPI Eina_Bool
eolian_state_system_directory_add(Eolian_State * state)834 eolian_state_system_directory_add(Eolian_State *state)
835 {
836 Eina_Bool ret;
837 Eina_Strbuf *buf = eina_strbuf_new();
838 eina_strbuf_append(buf, eina_prefix_data_get(_eolian_prefix));
839 eina_strbuf_append(buf, "/include");
840 ret = eolian_state_directory_add(state, eina_strbuf_string_get(buf));
841 eina_strbuf_free(buf);
842 return ret;
843 }
844
845 EAPI Eina_Iterator *
eolian_state_eot_files_get(const Eolian_State * state)846 eolian_state_eot_files_get(const Eolian_State *state)
847 {
848 if (!state) return NULL;
849 return eina_hash_iterator_key_new(state->filenames_eot);
850 }
851
852 EAPI Eina_Iterator *
eolian_state_eo_files_get(const Eolian_State * state)853 eolian_state_eo_files_get(const Eolian_State *state)
854 {
855 if (!state) return NULL;
856 return eina_hash_iterator_key_new(state->filenames_eo);
857 }
858
859 EAPI Eina_Iterator *
eolian_state_eot_file_paths_get(const Eolian_State * state)860 eolian_state_eot_file_paths_get(const Eolian_State *state)
861 {
862 if (!state) return NULL;
863 return eina_hash_iterator_data_new(state->filenames_eot);
864 }
865
866 EAPI Eina_Iterator *
eolian_state_eo_file_paths_get(const Eolian_State * state)867 eolian_state_eo_file_paths_get(const Eolian_State *state)
868 {
869 if (!state) return NULL;
870 return eina_hash_iterator_data_new(state->filenames_eo);
871 }
872
873 static Eolian_Unit *
_eolian_file_parse_nodep(Eolian_Unit * parent,const char * filename)874 _eolian_file_parse_nodep(Eolian_Unit *parent, const char *filename)
875 {
876 Eina_Bool is_eo;
877 is_eo = eina_str_has_suffix(filename, EO_SUFFIX);
878 if (!is_eo && !eina_str_has_suffix(filename, EOT_SUFFIX))
879 {
880 eolian_state_log(parent->state,
881 "file '%s' doesn't have a correct extension",
882 filename);
883 return NULL;
884 }
885 const char *eopath = eina_hash_find(is_eo ? parent->state->filenames_eo : parent->state->filenames_eot, filename);
886 if (!eopath)
887 {
888 eolian_state_log(parent->state,
889 "file '%s' is not registered in the database",
890 filename);
891 return NULL;
892 }
893 return eo_parser_database_fill(parent, eopath, !is_eo);
894 }
895
896 static void
_state_clean(Eolian_State * state)897 _state_clean(Eolian_State *state)
898 {
899 eina_hash_free_buckets(state->defer);
900
901 Eolian_State_Area *st = &state->staging;
902
903 Eolian_Unit *stu = &st->unit;
904 eina_hash_free_buckets(stu->classes);
905 eina_hash_free_buckets(stu->constants);
906 eina_hash_free_buckets(stu->aliases);
907 eina_hash_free_buckets(stu->structs);
908 eina_hash_free_buckets(stu->enums);
909 eina_hash_free_buckets(stu->objects);
910
911 eina_hash_foreach(st->units, _ulist_free_cb, NULL);
912 eina_hash_free_buckets(st->units);
913
914 eina_hash_free_buckets(st->classes_f);
915
916 _hashlist_free_buckets(st->aliases_f);
917 _hashlist_free_buckets(st->structs_f);
918 _hashlist_free_buckets(st->enums_f);
919 _hashlist_free_buckets(st->constants_f);
920 _hashlist_free_buckets(st->objects_f);
921 }
922
923 void
database_defer(Eolian_State * state,const char * fname,Eina_Bool isdep)924 database_defer(Eolian_State *state, const char *fname, Eina_Bool isdep)
925 {
926 void *nval = (void *)((size_t)isdep + 1);
927 size_t found = (size_t)eina_hash_find(state->defer, fname);
928 /* add if not found or upgrade to dep if requested */
929 if (!found)
930 eina_hash_add(state->defer, fname, nval);
931 else if ((found <= 1) && isdep)
932 eina_hash_set(state->defer, fname, nval);
933 }
934
935 static Eina_Bool _parse_deferred(Eolian_Unit *parent);
936 static void _merge_units(Eolian_Unit *unit);
937
938 typedef struct _Defer_Data
939 {
940 Eolian_Unit *parent;
941 Eina_Bool succ;
942 } Defer_Data;
943
944 static Eina_Bool
_defer_hash_cb(const Eina_Hash * hash EINA_UNUSED,const void * key,void * data,void * fdata)945 _defer_hash_cb(const Eina_Hash *hash EINA_UNUSED, const void *key,
946 void *data, void *fdata)
947 {
948 Defer_Data *d = fdata;
949 Eina_Bool alone = ((size_t)data <= 1);
950 Eolian_Unit *parent = d->parent;
951 /* not a dependency; parse standalone */
952 if (alone)
953 parent = &parent->state->staging.unit;
954 Eolian_Unit *pdep = _eolian_file_parse_nodep(parent, key);
955 d->succ = (pdep && _parse_deferred(pdep));
956 /* standalone-parsed stuff forms its own dependency trees,
957 * so we have to merge the units manually and separately
958 */
959 if (d->succ && alone)
960 _merge_units(pdep);
961 return d->succ;
962 }
963
964 static Eina_Bool
_parse_deferred(Eolian_Unit * parent)965 _parse_deferred(Eolian_Unit *parent)
966 {
967 Eina_Hash *defer = parent->state->defer;
968 if (!eina_hash_population(defer))
969 return EINA_TRUE;
970 /* clean room for more deps for later parsing */
971 parent->state->defer = eina_hash_string_small_new(NULL);
972 Defer_Data d = { parent, EINA_FALSE };
973 eina_hash_foreach(defer, _defer_hash_cb, &d);
974 if (!d.succ)
975 eina_hash_free_buckets(parent->state->defer);
976 eina_hash_free(defer);
977 return d.succ;
978 }
979
980 static Eina_Bool
_merge_unit_cb(const Eina_Hash * hash EINA_UNUSED,const void * key,void * data,void * fdata)981 _merge_unit_cb(const Eina_Hash *hash EINA_UNUSED,
982 const void *key, void *data, void *fdata)
983 {
984 Eina_Hash *dest = fdata;
985 if (!eina_hash_find(dest, key))
986 {
987 eina_hash_add(dest, key, data);
988 eolian_object_ref((Eolian_Object *)data);
989 }
990 return EINA_TRUE;
991 }
992
993 static Eina_Bool
_merge_unit_cb_noref(const Eina_Hash * hash EINA_UNUSED,const void * key,void * data,void * fdata)994 _merge_unit_cb_noref(const Eina_Hash *hash EINA_UNUSED,
995 const void *key, void *data, void *fdata)
996 {
997 Eina_Hash *dest = fdata;
998 if (!eina_hash_find(dest, key))
999 eina_hash_add(dest, key, data);
1000 return EINA_TRUE;
1001 }
1002
1003 static void
_merge_unit(Eolian_Unit * dest,Eolian_Unit * src)1004 _merge_unit(Eolian_Unit *dest, Eolian_Unit *src)
1005 {
1006 eina_hash_foreach(src->classes, _merge_unit_cb, dest->classes);
1007 eina_hash_foreach(src->constants, _merge_unit_cb, dest->constants);
1008 eina_hash_foreach(src->aliases, _merge_unit_cb, dest->aliases);
1009 eina_hash_foreach(src->structs, _merge_unit_cb, dest->structs);
1010 eina_hash_foreach(src->enums, _merge_unit_cb, dest->enums);
1011 eina_hash_foreach(src->objects, _merge_unit_cb_noref, dest->objects);
1012 }
1013
1014 typedef struct _Merge_Data
1015 {
1016 Eina_Hash *cycles;
1017 Eolian_Unit *unit;
1018 } Merge_Data;
1019
1020 static Eina_Bool
_merge_units_cb(const Eina_Hash * hash EINA_UNUSED,const void * key EINA_UNUSED,void * data,void * fdata)1021 _merge_units_cb(const Eina_Hash *hash EINA_UNUSED,
1022 const void *key EINA_UNUSED, void *data, void *fdata)
1023 {
1024 Merge_Data *mdata = fdata;
1025 Merge_Data imdata = { mdata->cycles, data };
1026 if (!eina_hash_find(imdata.cycles, &imdata.unit))
1027 {
1028 eina_hash_add(imdata.cycles, &imdata.unit, imdata.unit);
1029 eina_hash_foreach(imdata.unit->children, _merge_units_cb, &imdata);
1030 }
1031 _merge_unit(mdata->unit, imdata.unit);
1032 return EINA_TRUE;
1033 }
1034
1035
1036 static void
_merge_units(Eolian_Unit * unit)1037 _merge_units(Eolian_Unit *unit)
1038 {
1039 Merge_Data mdata = { eina_hash_pointer_new(NULL), unit };
1040 eina_hash_foreach(unit->children, _merge_units_cb, &mdata);
1041 eina_hash_free(mdata.cycles);
1042 }
1043
1044 static Eina_Bool
_merge_staging_cb(const Eina_Hash * hash EINA_UNUSED,const void * key,void * data,void * fdata)1045 _merge_staging_cb(const Eina_Hash *hash EINA_UNUSED,
1046 const void *key, void *data, void *fdata)
1047 {
1048 eina_hash_add((Eina_Hash *)fdata, key, data);
1049 return EINA_TRUE;
1050 }
1051
1052 static void
_merge_staging(Eolian_State * state)1053 _merge_staging(Eolian_State *state)
1054 {
1055 Eolian_State_Area *amain = &state->main, *staging = &state->staging;
1056 _merge_unit(&amain->unit, &staging->unit);
1057
1058 eina_hash_foreach(staging->units, _merge_staging_cb, amain->units);
1059 eina_hash_free_buckets(staging->units);
1060
1061 #define EOLIAN_STAGING_MERGE_LIST(name) \
1062 eina_hash_foreach(staging->name##_f, _merge_staging_cb, amain->name##_f); \
1063 eina_hash_free_buckets(staging->name##_f);
1064
1065 EOLIAN_STAGING_MERGE_LIST(classes);
1066 EOLIAN_STAGING_MERGE_LIST(aliases);
1067 EOLIAN_STAGING_MERGE_LIST(structs);
1068 EOLIAN_STAGING_MERGE_LIST(enums);
1069 EOLIAN_STAGING_MERGE_LIST(constants);
1070 EOLIAN_STAGING_MERGE_LIST(objects);
1071
1072 #undef EOLIAN_STAGING_MERGE_LIST
1073
1074 _state_clean(state);
1075 }
1076
1077 EAPI const Eolian_Unit *
eolian_state_file_parse(Eolian_State * state,const char * filename)1078 eolian_state_file_parse(Eolian_State *state, const char *filename)
1079 {
1080 if (!state)
1081 return NULL;
1082
1083 _state_clean(state);
1084 Eolian_Unit *ret = _eolian_file_parse_nodep(&state->staging.unit, filename);
1085 if (!ret)
1086 return NULL;
1087 if (!_parse_deferred(ret))
1088 return NULL;
1089 _merge_units(ret);
1090 if (!database_validate(&state->staging.unit))
1091 return NULL;
1092 _merge_staging(state);
1093 return ret;
1094 }
1095
1096 EAPI const Eolian_Unit *
eolian_state_file_path_parse(Eolian_State * state,const char * filepath)1097 eolian_state_file_path_parse(Eolian_State *state, const char *filepath)
1098 {
1099 const Eolian_Unit *unit;
1100 if (!state)
1101 return NULL;
1102
1103 char *mpath = strdup(filepath);
1104 if (!mpath)
1105 return NULL;
1106
1107 char *fname = strrchr(mpath, '/');
1108 if (fname && strrchr(fname, '\\'))
1109 fname = strrchr(fname, '\\');
1110
1111 const char *toscan = mpath;
1112 if (!fname)
1113 {
1114 toscan = ".";
1115 fname = mpath;
1116 }
1117 else
1118 *fname++ = '\0';
1119
1120 if (!eolian_state_directory_add(state, toscan))
1121 {
1122 eolian_state_log(state, "could not scan directory '%s'", toscan);
1123 free(mpath);
1124 return NULL;
1125 }
1126 unit = eolian_state_file_parse(state, fname);
1127 free(mpath);
1128 return unit;
1129 }
1130
1131 typedef struct _Parse_Data
1132 {
1133 Eolian_State *state;
1134 Eina_Bool ret;
1135 } Parse_Data;
1136
_tfile_parse(const Eina_Hash * hash EINA_UNUSED,const void * key EINA_UNUSED,void * data,void * fdata)1137 static Eina_Bool _tfile_parse(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata)
1138 {
1139 Parse_Data *pd = fdata;
1140 Eolian_Unit *unit = NULL;
1141 if (pd->ret)
1142 unit = eo_parser_database_fill(&pd->state->staging.unit, data, EINA_TRUE);
1143 pd->ret = !!unit;
1144 if (pd->ret) pd->ret = _parse_deferred(unit);
1145 if (pd->ret) _merge_units(unit);
1146 return pd->ret;
1147 }
1148
1149 EAPI Eina_Bool
eolian_state_all_eot_files_parse(Eolian_State * state)1150 eolian_state_all_eot_files_parse(Eolian_State *state)
1151 {
1152 Parse_Data pd = { state, EINA_TRUE };
1153
1154 if (!state)
1155 return EINA_FALSE;
1156
1157 _state_clean(state);
1158 eina_hash_foreach(state->filenames_eot, _tfile_parse, &pd);
1159
1160 if (pd.ret && !database_validate(&state->staging.unit))
1161 return EINA_FALSE;
1162
1163 _merge_staging(state);
1164
1165 return pd.ret;
1166 }
1167
_file_parse(const Eina_Hash * hash EINA_UNUSED,const void * key EINA_UNUSED,void * data,void * fdata)1168 static Eina_Bool _file_parse(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata)
1169 {
1170 Parse_Data *pd = fdata;
1171 Eolian_Unit *unit = NULL;
1172 if (pd->ret)
1173 unit = eo_parser_database_fill(&pd->state->staging.unit, data, EINA_FALSE);
1174 pd->ret = !!unit;
1175 if (pd->ret) pd->ret = _parse_deferred(unit);
1176 if (pd->ret) _merge_units(unit);
1177 return pd->ret;
1178 }
1179
1180 EAPI Eina_Bool
eolian_state_all_eo_files_parse(Eolian_State * state)1181 eolian_state_all_eo_files_parse(Eolian_State *state)
1182 {
1183 Parse_Data pd = { state, EINA_TRUE };
1184
1185 if (!state)
1186 return EINA_FALSE;
1187
1188 _state_clean(state);
1189 eina_hash_foreach(state->filenames_eo, _file_parse, &pd);
1190
1191 if (pd.ret && !database_validate(&state->staging.unit))
1192 return EINA_FALSE;
1193
1194 _merge_staging(state);
1195
1196 return pd.ret;
1197 }
1198
1199 EAPI Eina_Bool
eolian_state_check(const Eolian_State * state)1200 eolian_state_check(const Eolian_State *state)
1201 {
1202 return database_check(state);
1203 }
1204
1205 EAPI const Eolian_Unit *
eolian_state_unit_by_file_get(const Eolian_State * state,const char * file_name)1206 eolian_state_unit_by_file_get(const Eolian_State *state, const char *file_name)
1207 {
1208 if (!state) return NULL;
1209 Eina_Stringshare *shr = eina_stringshare_add(file_name);
1210 Eolian_Unit *unit = eina_hash_find(state->main.units, shr);
1211 eina_stringshare_del(shr);
1212 return unit;
1213 }
1214
1215 EAPI Eina_Iterator *
eolian_state_units_get(const Eolian_State * state)1216 eolian_state_units_get(const Eolian_State *state)
1217 {
1218 if (!state) return NULL;
1219 return eina_hash_iterator_data_new(state->main.units);
1220 }
1221
1222 EAPI Eina_Iterator *
eolian_state_objects_by_file_get(const Eolian_State * state,const char * file_name)1223 eolian_state_objects_by_file_get(const Eolian_State *state, const char *file_name)
1224 {
1225 if (!state) return NULL;
1226 Eina_Stringshare *shr = eina_stringshare_add(file_name);
1227 Eina_List *l = eina_hash_find(state->main.objects_f, shr);
1228 eina_stringshare_del(shr);
1229 if (!l) return NULL;
1230 return eina_list_iterator_new(l);
1231 }
1232
1233 EAPI const Eolian_Class *
eolian_state_class_by_file_get(const Eolian_State * state,const char * file_name)1234 eolian_state_class_by_file_get(const Eolian_State *state, const char *file_name)
1235 {
1236 if (!state) return NULL;
1237 Eina_Stringshare *shr = eina_stringshare_add(file_name);
1238 Eolian_Class *cl = eina_hash_find(state->main.classes_f, shr);
1239 eina_stringshare_del(shr);
1240 return cl;
1241 }
1242
1243 EAPI Eina_Iterator *
eolian_state_constants_by_file_get(const Eolian_State * state,const char * file_name)1244 eolian_state_constants_by_file_get(const Eolian_State *state, const char *file_name)
1245 {
1246 if (!state) return NULL;
1247 Eina_Stringshare *shr = eina_stringshare_add(file_name);
1248 Eina_List *l = eina_hash_find(state->main.constants_f, shr);
1249 eina_stringshare_del(shr);
1250 if (!l) return NULL;
1251 return eina_list_iterator_new(l);
1252 }
1253
1254 EAPI Eina_Iterator *
eolian_state_errors_by_file_get(const Eolian_State * state,const char * file_name)1255 eolian_state_errors_by_file_get(const Eolian_State *state, const char *file_name)
1256 {
1257 if (!state) return NULL;
1258 Eina_Stringshare *shr = eina_stringshare_add(file_name);
1259 Eina_List *l = eina_hash_find(state->main.errors_f, shr);
1260 eina_stringshare_del(shr);
1261 if (!l) return NULL;
1262 return eina_list_iterator_new(l);
1263 }
1264
1265 EAPI Eina_Iterator *
eolian_state_aliases_by_file_get(const Eolian_State * state,const char * file_name)1266 eolian_state_aliases_by_file_get(const Eolian_State *state, const char *file_name)
1267 {
1268 if (!state) return NULL;
1269 Eina_Stringshare *shr = eina_stringshare_add(file_name);
1270 Eina_List *l = eina_hash_find(state->main.aliases_f, shr);
1271 eina_stringshare_del(shr);
1272 if (!l) return NULL;
1273 return eina_list_iterator_new(l);
1274 }
1275
1276 EAPI Eina_Iterator *
eolian_state_structs_by_file_get(const Eolian_State * state,const char * file_name)1277 eolian_state_structs_by_file_get(const Eolian_State *state, const char *file_name)
1278 {
1279 if (!state) return NULL;
1280 Eina_Stringshare *shr = eina_stringshare_add(file_name);
1281 Eina_List *l = eina_hash_find(state->main.structs_f, shr);
1282 eina_stringshare_del(shr);
1283 if (!l) return NULL;
1284 return eina_list_iterator_new(l);
1285 }
1286
1287 EAPI Eina_Iterator *
eolian_state_enums_by_file_get(const Eolian_State * state,const char * file_name)1288 eolian_state_enums_by_file_get(const Eolian_State *state, const char *file_name)
1289 {
1290 if (!state) return NULL;
1291 Eina_Stringshare *shr = eina_stringshare_add(file_name);
1292 Eina_List *l = eina_hash_find(state->main.enums_f, shr);
1293 eina_stringshare_del(shr);
1294 if (!l) return NULL;
1295 return eina_list_iterator_new(l);
1296 }
1297
1298 EAPI const Eolian_State *
eolian_unit_state_get(const Eolian_Unit * unit)1299 eolian_unit_state_get(const Eolian_Unit *unit)
1300 {
1301 if (!unit) return NULL;
1302 return unit->state;
1303 }
1304
1305 EAPI Eina_Iterator *
eolian_unit_children_get(const Eolian_Unit * unit)1306 eolian_unit_children_get(const Eolian_Unit *unit)
1307 {
1308 if (!unit) return NULL;
1309 return eina_hash_iterator_data_new(unit->children);
1310 }
1311
1312 EAPI const char *
eolian_unit_file_get(const Eolian_Unit * unit)1313 eolian_unit_file_get(const Eolian_Unit *unit)
1314 {
1315 if (!unit) return NULL;
1316 return unit->file;
1317 }
1318
1319 EAPI const char *
eolian_unit_file_path_get(const Eolian_Unit * unit)1320 eolian_unit_file_path_get(const Eolian_Unit *unit)
1321 {
1322 if (!unit || !unit->file) return NULL;
1323 Eina_Bool is_eo = eina_str_has_suffix(unit->file, EO_SUFFIX);
1324 return eina_hash_find(is_eo
1325 ? unit->state->filenames_eo
1326 : unit->state->filenames_eot, unit->file);
1327 }
1328
1329 EAPI unsigned short
eolian_unit_version_get(const Eolian_Unit * unit)1330 eolian_unit_version_get(const Eolian_Unit *unit)
1331 {
1332 if (!unit) return 0;
1333 return unit->version;
1334 }
1335
1336 EAPI const Eolian_Object *
eolian_unit_object_by_name_get(const Eolian_Unit * unit,const char * name)1337 eolian_unit_object_by_name_get(const Eolian_Unit *unit, const char *name)
1338 {
1339 if (!unit) return NULL;
1340 Eina_Stringshare *shr = eina_stringshare_add(name);
1341 Eolian_Object *o = eina_hash_find(unit->objects, shr);
1342 eina_stringshare_del(shr);
1343 return o;
1344 }
1345
eolian_unit_objects_get(const Eolian_Unit * unit)1346 EAPI Eina_Iterator *eolian_unit_objects_get(const Eolian_Unit *unit)
1347 {
1348 return (unit ? eina_hash_iterator_data_new(unit->objects) : NULL);
1349 }
1350
1351 EAPI const Eolian_Class *
eolian_unit_class_by_name_get(const Eolian_Unit * unit,const char * class_name)1352 eolian_unit_class_by_name_get(const Eolian_Unit *unit, const char *class_name)
1353 {
1354 if (!unit) return NULL;
1355 Eina_Stringshare *shr = eina_stringshare_add(class_name);
1356 Eolian_Class *cl = eina_hash_find(unit->classes, shr);
1357 eina_stringshare_del(shr);
1358 return cl;
1359 }
1360
1361 EAPI Eina_Iterator *
eolian_unit_classes_get(const Eolian_Unit * unit)1362 eolian_unit_classes_get(const Eolian_Unit *unit)
1363 {
1364 return (unit ? eina_hash_iterator_data_new(unit->classes) : NULL);
1365 }
1366
1367 EAPI const Eolian_Constant *
eolian_unit_constant_by_name_get(const Eolian_Unit * unit,const char * name)1368 eolian_unit_constant_by_name_get(const Eolian_Unit *unit, const char *name)
1369 {
1370 if (!unit) return NULL;
1371 Eina_Stringshare *shr = eina_stringshare_add(name);
1372 Eolian_Constant *v = eina_hash_find(unit->constants, shr);
1373 eina_stringshare_del(shr);
1374 return v;
1375 }
1376
1377 EAPI const Eolian_Error *
eolian_unit_error_by_name_get(const Eolian_Unit * unit,const char * name)1378 eolian_unit_error_by_name_get(const Eolian_Unit *unit, const char *name)
1379 {
1380 if (!unit) return NULL;
1381 Eina_Stringshare *shr = eina_stringshare_add(name);
1382 Eolian_Error *v = eina_hash_find(unit->errors, shr);
1383 eina_stringshare_del(shr);
1384 return v;
1385 }
1386
1387 EAPI Eina_Iterator *
eolian_unit_constants_get(const Eolian_Unit * unit)1388 eolian_unit_constants_get(const Eolian_Unit *unit)
1389 {
1390 return (unit ? eina_hash_iterator_data_new(unit->constants) : NULL);
1391 }
1392
1393 EAPI Eina_Iterator *
eolian_unit_errors_get(const Eolian_Unit * unit)1394 eolian_unit_errors_get(const Eolian_Unit *unit)
1395 {
1396 return (unit ? eina_hash_iterator_data_new(unit->errors) : NULL);
1397 }
1398
1399 EAPI const Eolian_Typedecl *
eolian_unit_alias_by_name_get(const Eolian_Unit * unit,const char * name)1400 eolian_unit_alias_by_name_get(const Eolian_Unit *unit, const char *name)
1401 {
1402 if (!unit) return NULL;
1403 Eina_Stringshare *shr = eina_stringshare_add(name);
1404 Eolian_Typedecl *tp = eina_hash_find(unit->aliases, shr);
1405 eina_stringshare_del(shr);
1406 if (!tp) return NULL;
1407 return tp;
1408 }
1409
1410 EAPI const Eolian_Typedecl *
eolian_unit_struct_by_name_get(const Eolian_Unit * unit,const char * name)1411 eolian_unit_struct_by_name_get(const Eolian_Unit *unit, const char *name)
1412 {
1413 if (!unit) return NULL;
1414 Eina_Stringshare *shr = eina_stringshare_add(name);
1415 Eolian_Typedecl *tp = eina_hash_find(unit->structs, shr);
1416 eina_stringshare_del(shr);
1417 if (!tp) return NULL;
1418 return tp;
1419 }
1420
1421 EAPI const Eolian_Typedecl *
eolian_unit_enum_by_name_get(const Eolian_Unit * unit,const char * name)1422 eolian_unit_enum_by_name_get(const Eolian_Unit *unit, const char *name)
1423 {
1424 if (!unit) return NULL;
1425 Eina_Stringshare *shr = eina_stringshare_add(name);
1426 Eolian_Typedecl *tp = eina_hash_find(unit->enums, shr);
1427 eina_stringshare_del(shr);
1428 if (!tp) return NULL;
1429 return tp;
1430 }
1431
1432 EAPI Eina_Iterator *
eolian_unit_aliases_get(const Eolian_Unit * unit)1433 eolian_unit_aliases_get(const Eolian_Unit *unit)
1434 {
1435 return (unit ? eina_hash_iterator_data_new(unit->aliases) : NULL);
1436 }
1437
1438 EAPI Eina_Iterator *
eolian_unit_structs_get(const Eolian_Unit * unit)1439 eolian_unit_structs_get(const Eolian_Unit *unit)
1440 {
1441 return (unit ? eina_hash_iterator_data_new(unit->structs) : NULL);
1442 }
1443
1444 EAPI Eina_Iterator *
eolian_unit_enums_get(const Eolian_Unit * unit)1445 eolian_unit_enums_get(const Eolian_Unit *unit)
1446 {
1447 return (unit ? eina_hash_iterator_data_new(unit->enums) : NULL);
1448 }
1449
1450 EAPI const char *
eolian_error_message_get(const Eolian_Error * err)1451 eolian_error_message_get(const Eolian_Error *err)
1452 {
1453 if (!err) return NULL;
1454 return err->msg;
1455 }
1456
1457 EAPI Eina_Bool
eolian_error_is_extern(const Eolian_Error * err)1458 eolian_error_is_extern(const Eolian_Error *err)
1459 {
1460 if (!err) return EINA_FALSE;
1461 return err->is_extern;
1462 }
1463
1464 EAPI const Eolian_Documentation *
eolian_error_documentation_get(const Eolian_Error * err)1465 eolian_error_documentation_get(const Eolian_Error *err)
1466 {
1467 EINA_SAFETY_ON_NULL_RETURN_VAL(err, NULL);
1468 return err->doc;
1469 }
1470
1471 void
database_error_del(Eolian_Error * err)1472 database_error_del(Eolian_Error *err)
1473 {
1474 if (!err || eolian_object_unref(&err->base)) return;
1475 eina_stringshare_del(err->msg);
1476 database_doc_del(err->doc);
1477 free(err);
1478 }
1479
1480 void
database_error_add(Eolian_Unit * unit,Eolian_Error * err)1481 database_error_add(Eolian_Unit *unit, Eolian_Error *err)
1482 {
1483 EOLIAN_OBJECT_ADD(unit, err->base.name, err, errors);
1484 eina_hash_set(unit->state->staging.errors_f, err->base.file, eina_list_append
1485 ((Eina_List*)eina_hash_find(unit->state->staging.errors_f, err->base.file),
1486 err));
1487 database_object_add(unit, &err->base);
1488 }
1489
1490 char *
database_class_to_filename(const char * cname)1491 database_class_to_filename(const char *cname)
1492 {
1493 char *ret;
1494 Eina_Strbuf *strbuf = eina_strbuf_new();
1495 eina_strbuf_append(strbuf, cname);
1496 eina_strbuf_replace_all(strbuf, ".", "_");
1497 eina_strbuf_append(strbuf, ".eo");
1498
1499 ret = eina_strbuf_string_steal(strbuf);
1500 eina_strbuf_free(strbuf);
1501
1502 eina_str_tolower(&ret);
1503
1504 return ret;
1505 }
1506