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