1 /* rec_engine.c -- generic stroke recognition engine interface
2
3 Copyright (C) 2000 Carl Worth
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <dlfcn.h>
20 #include <errno.h>
21
22 #include "rec.h"
23 #include "rec_engine.h"
24 #include "anchor_engine.h"
25 #include "dir_engine.h"
26 #include "grid_engine.h"
27 #include "raw_engine.h"
28 #include "sprintf_alloc.h"
29
30 #ifdef DMALLOC
31 #include "dmalloc.h"
32 #endif
33
34 struct engine_func_map
35 {
36 char *name;
37 rec_engine_funcs_t funcs;
38 };
39 typedef struct engine_func_map engine_func_map_t;
40
41 static engine_func_map_t static_engines[] = {
42 { "anchor",
43 {
44 anchor_priv_alloc,
45 anchor_priv_free,
46 anchor_feature_data_alloc,
47 anchor_feature_data_free,
48 anchor_classify_stroke,
49 anchor_classification_str_alloc,
50 anchor_free_classification,
51 anchor_recognize_stroke,
52 anchor_set_option
53 }
54 },
55 { "dir",
56 {
57 dir_priv_alloc,
58 dir_priv_free,
59 dir_feature_data_alloc,
60 dir_feature_data_free,
61 dir_classify_stroke,
62 dir_classification_str_alloc,
63 dir_free_classification,
64 dir_recognize_stroke,
65 dir_set_option
66 }
67 },
68 { "dir_length",
69 {
70 dir_priv_alloc,
71 dir_priv_free,
72 dir_feature_data_alloc,
73 dir_feature_data_free,
74 dir_length_classify_stroke,
75 dir_classification_str_alloc,
76 dir_free_classification,
77 dir_recognize_stroke,
78 dir_set_option
79 }
80 },
81 { "grid",
82 {
83 grid_priv_alloc,
84 grid_priv_free,
85 grid_feature_data_alloc,
86 grid_feature_data_free,
87 grid_classify_stroke,
88 grid_classification_str_alloc,
89 grid_free_classification,
90 grid_recognize_stroke,
91 grid_set_option
92 }
93 },
94 { "raw",
95 {
96 raw_priv_alloc,
97 raw_priv_free,
98 raw_feature_data_alloc,
99 raw_feature_data_free,
100 raw_classify_stroke,
101 raw_classification_str_alloc,
102 raw_free_classification,
103 raw_recognize_stroke,
104 raw_set_option
105 }
106 }
107 };
108 static int num_static_engines = sizeof(static_engines) / sizeof(engine_func_map_t);
109
rec_engine_init(rec_engine_t * engine,rec_t * rec,char * engine_name)110 int rec_engine_init(rec_engine_t *engine, rec_t *rec, char *engine_name)
111 {
112 int i;
113 int err;
114 void *dlh;
115 char *error;
116 char *libname;
117 int chars_matched;
118 int ret_val = 0;
119
120 engine->rec = rec;
121 engine->name = strdup(engine_name);
122 engine->num = 0;
123 engine->priv = NULL;
124
125 engine->funcs = NULL;
126 chars_matched = 0;
127 for (i=0; i < num_static_engines; i++) {
128 char *name_i = static_engines[i].name;
129 int name_i_len = strlen(name_i);
130 if (strncmp(engine_name, name_i, name_i_len) == 0) {
131 if (name_i_len > chars_matched) {
132 chars_matched = name_i_len;
133 engine->funcs = &static_engines[i].funcs;
134 }
135 }
136 }
137
138 if (engine->funcs == NULL) {
139 sprintf_alloc(&libname, "%s%s", REC_LIB_PREFIX, engine_name);
140 dlh = dlopen(libname, RTLD_LAZY);
141 if (dlh == NULL) {
142 fprintf(stderr, "%s: failed to open library %s: %s",
143 __FUNCTION__, libname, dlerror());
144 ret_val = EINVAL;
145 goto CLEANUP;
146 }
147
148 engine->funcs = dlsym(dlh, REC_ENGINE_FUNCS_SYMBOL);
149 if ((error = dlerror()) != NULL) {
150 fprintf(stderr, "%s: Failed to find symbol %s in %s: %s\n",
151 __FUNCTION__, REC_ENGINE_FUNCS_SYMBOL, libname, error);
152 ret_val = EINVAL;
153 goto CLEANUP;
154 }
155
156 CLEANUP:
157 if (dlh) {
158 dlclose(dlh);
159 }
160 free(libname);
161 }
162
163 if (engine->funcs->priv_alloc) {
164 err = (engine->funcs->priv_alloc)(engine);
165 if (err) {
166 fprintf(stderr, "%s: An error occurred during %s:priv_alloc: %s\n",
167 __FUNCTION__, engine->name, strerror(err));
168 ret_val = err;
169 }
170 }
171
172 return ret_val;
173 }
174
rec_engine_deinit(rec_engine_t * engine)175 void rec_engine_deinit(rec_engine_t *engine)
176 {
177 if (engine->funcs->priv_free) {
178 (engine->funcs->priv_free)(engine);
179 }
180 engine->funcs = NULL;
181 engine->num = 0;
182 free(engine->name);
183 }
184
rec_engine_feature_data_alloc(rec_engine_t * engine,char * feature_data_str)185 void *rec_engine_feature_data_alloc(rec_engine_t *engine, char *feature_data_str)
186 {
187 if (engine->funcs->feature_data_alloc == NULL) {
188 return NULL;
189 }
190
191 return (engine->funcs->feature_data_alloc)(engine, feature_data_str);
192 }
193
rec_engine_feature_data_free(rec_engine_t * engine,void * feature_data)194 void rec_engine_feature_data_free(rec_engine_t *engine, void *feature_data)
195 {
196 if (engine->funcs->feature_data_free) {
197 (engine->funcs->feature_data_free)(engine, feature_data);
198 }
199 }
200
rec_engine_classify_stroke(rec_engine_t * engine,stroke_t * stroke)201 void rec_engine_classify_stroke(rec_engine_t *engine, stroke_t *stroke)
202 {
203 if (engine->funcs->classify_stroke) {
204 (engine->funcs->classify_stroke)(engine, stroke);
205 }
206 }
207
rec_engine_classification_str_alloc(rec_engine_t * engine,stroke_t * stroke)208 char *rec_engine_classification_str_alloc(rec_engine_t *engine, stroke_t *stroke)
209 {
210 if (engine->funcs->classification_str_alloc == NULL) {
211 return strdup("");
212 }
213
214 return (engine->funcs->classification_str_alloc)(engine, stroke);
215 }
216
rec_engine_free_classification(rec_engine_t * engine,stroke_t * stroke)217 void rec_engine_free_classification(rec_engine_t *engine, stroke_t *stroke)
218 {
219 if (engine->funcs->free_classification) {
220 (engine->funcs->free_classification)(engine, stroke);
221 }
222 }
223
rec_engine_recognize_stroke(rec_engine_t * engine,stroke_t * stroke,void * feature_data)224 double rec_engine_recognize_stroke(rec_engine_t *engine, stroke_t *stroke,
225 void *feature_data)
226 {
227 if (engine->funcs->recognize_stroke == NULL) {
228 return 1.0;
229 }
230
231 return (engine->funcs->recognize_stroke)(engine, stroke, feature_data);
232 }
233
rec_engine_set_option(rec_engine_t * engine,char * name,char * value)234 int rec_engine_set_option(rec_engine_t *engine, char *name, char *value)
235 {
236 if (engine->funcs->set_option == NULL) {
237 return 0;
238 }
239
240 return (engine->funcs->set_option)(engine, name, value);
241 }
242
rec_engine_list_init(rec_engine_list_t * list)243 int rec_engine_list_init(rec_engine_list_t *list)
244 {
245 list->num_engines = 0;
246 list->engines = NULL;
247
248 return 0;
249 }
250
rec_engine_list_deinit_shallow(rec_engine_list_t * list)251 void rec_engine_list_deinit_shallow(rec_engine_list_t *list)
252 {
253 if (list->engines) {
254 free(list->engines);
255 list->engines = NULL;
256 }
257 list->num_engines = 0;
258 }
259
260 /* Full, deep deinit */
261 /* This function doesn't make sense as no one would have the chance to
262 call free on all of the rec_engine_t *s
263 void rec_engine_list_deinit(rec_engine_list_t *list)
264 {
265 int i;
266
267 for (i=0; i < list->num_engines; i++) {
268 rec_engine_deinit(list->engines[i]);
269 }
270 rec_engine_list_deinit_shallow(list);
271 }
272 */
273
rec_engine_list_append(rec_engine_list_t * list,rec_engine_t * engine)274 int rec_engine_list_append(rec_engine_list_t *list, rec_engine_t *engine)
275 {
276 rec_engine_t **new_engines;
277
278 list->num_engines++;
279
280 new_engines = realloc(list->engines, list->num_engines * sizeof(rec_engine_t *));
281 if (new_engines == NULL) {
282 fprintf(stderr, "%s: Out of memory.\n", __FUNCTION__);
283 list->num_engines--;
284 return ENOMEM;
285 }
286
287 list->engines = new_engines;
288 list->engines[list->num_engines - 1] = engine;
289 engine->num = list->num_engines - 1;
290
291 return 0;
292 }
293