catalog.h (5857B)
1 #ifndef CATALOG_H 2 #define CATALOG_H 3 4 #include <stdlib.h> 5 #include "symbols.h" 6 7 /* Helper to build more intuitive schema data with fully qualified names. */ 8 9 10 typedef struct entry entry_t; 11 typedef entry_t object_entry_t; 12 typedef entry_t enum_entry_t; 13 typedef entry_t service_entry_t; 14 typedef struct scope_entry scope_entry_t; 15 16 struct entry { 17 fb_compound_type_t *ct; 18 char *name; 19 }; 20 21 struct scope_entry { 22 fb_scope_t *scope; 23 char *name; 24 }; 25 26 typedef struct catalog catalog_t; 27 28 struct catalog { 29 int qualify_names; 30 int nobjects; 31 int nenums; 32 int nservices; 33 size_t name_table_size; 34 object_entry_t *objects; 35 enum_entry_t *enums; 36 service_entry_t *services; 37 char *name_table; 38 object_entry_t *next_object; 39 enum_entry_t *next_enum; 40 service_entry_t *next_service; 41 char *next_name; 42 fb_schema_t *schema; 43 }; 44 45 #include <stdio.h> 46 47 static void count_symbol(void *context, fb_symbol_t *sym) 48 { 49 catalog_t *catalog = context; 50 fb_ref_t *scope_name; 51 size_t n = 0; 52 fb_compound_type_t *ct; 53 54 if (!(ct = get_compound_if_visible(catalog->schema, sym))) { 55 return; 56 } 57 58 /* 59 * Find out how much space the name requires. We must store each 60 * name in full for sorting because comparing a variable number of 61 * parent scope names is otherwise tricky. 62 */ 63 if (catalog->qualify_names) { 64 scope_name = ct->scope->name; 65 while (scope_name) { 66 /* + 1 for '.'. */ 67 n += (size_t)scope_name->ident->len + 1; 68 scope_name = scope_name->link; 69 } 70 } 71 /* + 1 for '\0'. */ 72 n += (size_t)sym->ident->len + 1; 73 catalog->name_table_size += n; 74 75 switch (sym->kind) { 76 case fb_is_struct: 77 case fb_is_table: 78 ++catalog->nobjects; 79 break; 80 case fb_is_union: 81 case fb_is_enum: 82 ++catalog->nenums; 83 break; 84 case fb_is_rpc_service: 85 ++catalog->nservices; 86 break; 87 default: return; 88 } 89 } 90 91 static void install_symbol(void *context, fb_symbol_t *sym) 92 { 93 catalog_t *catalog = context; 94 fb_ref_t *scope_name; 95 int n = 0; 96 char *s, *name; 97 fb_compound_type_t *ct; 98 99 if (!(ct = get_compound_if_visible(catalog->schema, sym))) { 100 return; 101 } 102 103 s = catalog->next_name; 104 name = s; 105 if (catalog->qualify_names) { 106 scope_name = ct->scope->name; 107 while (scope_name) { 108 n = (int)scope_name->ident->len; 109 memcpy(s, scope_name->ident->text, (size_t)n); 110 s += n; 111 *s++ = '.'; 112 scope_name = scope_name->link; 113 } 114 } 115 n = (int)sym->ident->len; 116 memcpy(s, sym->ident->text, (size_t)n); 117 s += n; 118 *s++ = '\0'; 119 catalog->next_name = s; 120 121 switch (sym->kind) { 122 case fb_is_struct: 123 case fb_is_table: 124 catalog->next_object->ct = (fb_compound_type_t *)sym; 125 catalog->next_object->name = name; 126 catalog->next_object++; 127 break; 128 case fb_is_union: 129 case fb_is_enum: 130 catalog->next_enum->ct = (fb_compound_type_t *)sym; 131 catalog->next_enum->name = name; 132 catalog->next_enum++; 133 break; 134 case fb_is_rpc_service: 135 catalog->next_service->ct = (fb_compound_type_t *)sym; 136 catalog->next_service->name = name; 137 catalog->next_service++; 138 break; 139 default: break; 140 } 141 } 142 143 static void count_symbols(void *context, fb_scope_t *scope) 144 { 145 fb_symbol_table_visit(&scope->symbol_index, count_symbol, context); 146 } 147 148 static void install_symbols(void *context, fb_scope_t *scope) 149 { 150 fb_symbol_table_visit(&scope->symbol_index, install_symbol, context); 151 } 152 153 static int compare_entries(const void *x, const void *y) 154 { 155 return strcmp(((const entry_t *)x)->name, ((const entry_t *)y)->name); 156 } 157 158 static void sort_entries(entry_t *entries, int count) 159 { 160 int i; 161 162 qsort(entries, (size_t)count, sizeof(entries[0]), compare_entries); 163 164 for (i = 0; i < count; ++i) { 165 entries[i].ct->export_index = (size_t)i; 166 } 167 } 168 169 static void clear_catalog(catalog_t *catalog) 170 { 171 if (catalog->objects) { 172 free(catalog->objects); 173 } 174 if (catalog->enums) { 175 free(catalog->enums); 176 } 177 if (catalog->services) { 178 free(catalog->services); 179 } 180 if (catalog->name_table) { 181 free(catalog->name_table); 182 } 183 memset(catalog, 0, sizeof(*catalog)); 184 } 185 186 static int build_catalog(catalog_t *catalog, fb_schema_t *schema, int qualify_names, fb_scope_table_t *index) 187 { 188 memset(catalog, 0, sizeof(*catalog)); 189 catalog->qualify_names = qualify_names; 190 catalog->schema = schema; 191 192 /* Build support datastructures before export. */ 193 fb_scope_table_visit(index, count_symbols, catalog); 194 catalog->objects = calloc((size_t)catalog->nobjects, sizeof(catalog->objects[0])); 195 catalog->enums = calloc((size_t)catalog->nenums, sizeof(catalog->enums[0])); 196 catalog->services = calloc((size_t)catalog->nservices, sizeof(catalog->services[0])); 197 catalog->name_table = malloc(catalog->name_table_size); 198 catalog->next_object = catalog->objects; 199 catalog->next_enum = catalog->enums; 200 catalog->next_service = catalog->services; 201 catalog->next_name = catalog->name_table; 202 if ((!catalog->objects && catalog->nobjects > 0) || 203 (!catalog->enums && catalog->nenums > 0) || 204 (!catalog->services && catalog->nservices > 0) || 205 (!catalog->name_table && catalog->name_table_size > 0)) { 206 clear_catalog(catalog); 207 return -1; 208 } 209 fb_scope_table_visit(index, install_symbols, catalog); 210 /* Presort objects and enums because the sorted index is required in Type tables. */ 211 sort_entries(catalog->objects, catalog->nobjects); 212 sort_entries(catalog->enums, catalog->nenums); 213 sort_entries(catalog->services, catalog->nservices); 214 return 0; 215 } 216 217 #endif /* CATALOG_H */