2 * hre_api.c: Implementation of HRE API
4 * Created On: Wed Dec 9 13:49:14 1992
5 * Last Modified By: James Kempf
6 * Last Modified On: Fri Sep 23 13:49:04 1994
8 * Copyright (c) 1994 by Sun Microsystems Computer Company
11 * Use and copying of this software and preparation of
12 * derivative works based upon this software are permitted.
13 * Any distribution of this software or derivative works
14 * must comply with all applicable United States export control
17 * This software is made available as is, and Sun Microsystems
18 * Computer Company makes no warranty about the software, its
19 * performance, or its conformity to any specification
27 #include "scribbleimpl.h"
28 #include "hre_internal.h"
30 /* ari -- prototype for rii function */
31 recognizer __recognizer_internal_initialize(rec_info* ri);
33 /*Version number of API.*/
35 char* REC_VERSION = "2.0";
37 /*Domain name for internationalized text.*/
39 #define INTL_DOMAIN "recognition_manager"
41 /* XXX -- Intl Hack -- Jay & Ari */
42 #define dgettext(domain, msg) (msg)
43 #define bindtextdomain(dirname, domain)
46 * These magic numbers are used to ensure the integrity of the
47 * recognizer structure.
51 #define REC_MAGIC 0xfeed
52 #define REC_END_MAGIC 0xbeef
54 /*Check the recognizer for validity*/
56 #define RI_CHECK_MAGIC(rec) \
58 (((recognizer)rec)->recognizer_magic == REC_MAGIC) && \
59 (((recognizer)rec)->recognizer_end_magic == REC_END_MAGIC) &&\
60 (((recognizer)rec)->recognizer_version == REC_VERSION) )
62 /*The name of the initialization & finalization functions.*/
64 /* static char rii_name[] = "__recognizer_internal_initialize";
65 static char rif_name[] = "__recognizer_internal_finalize"; */
67 /*User home directory for recognizer info.*/
68 /* ari -- changed USERRECHOME from ".recognizers" */
70 #define USERRECHOME ".classifiers"
74 static rec_info* make_rec_info(char* directory,char* name,char** subset);
75 static void delete_rec_info(rec_info* ri);
76 static void intl_initialize(void);
78 static void cleanup_rec_element(rec_element* re,bool delete_points_p);
82 static char* the_last_error = nil;
84 static char *safe_malloc (int nbytes)
86 char *res = malloc(nbytes);
88 sysfatal("malloc failure");
95 * Implementation of API functions
99 * recognizer_load - Load the recognizer matching the rec_info struct.
100 * If name is not null, then load the recognizer having that name. Returns
101 * the recognizer object, or null if it can't load the recognizer, and
102 * sets errno to indicate why.
106 recognizer_load(char* directory, char* name, char** subset)
108 recognizer rec; /*the recognizer*/
109 rec_info* rinf; /*rec_info for recognizer information*/
110 static bool intl_init = false; /*true if recog. manager initted.*/
112 if( intl_init == false ) {
117 /*The name takes precedence.*/
118 rinf = make_rec_info(directory, name, subset);
121 dgettext(INTL_DOMAIN,
122 "Ran out of memory during prelinking initialization.");
123 return((recognizer)nil);
125 /* fprint(2, "Got past make_rec_info.\n"); */
127 /*Let recognition code create recognizer and initialize*/
128 rec = __recognizer_internal_initialize(rinf);
130 return((recognizer)nil);
132 /* fprint(2, "Did rii.\n"); */
133 /*Check whether it's been correctly initialized*/
135 if( rec->recognizer_load_state == nil ||
136 rec->recognizer_save_state == nil ||
137 rec->recognizer_load_dictionary == nil ||
138 rec->recognizer_save_dictionary == nil ||
139 rec->recognizer_free_dictionary == nil ||
140 rec->recognizer_add_to_dictionary == nil ||
141 rec->recognizer_delete_from_dictionary == nil ||
142 rec->recognizer_error == nil ||
143 rec->recognizer_set_context == nil ||
144 rec->recognizer_get_context == nil ||
145 rec->recognizer_clear == nil ||
146 rec->recognizer_get_buffer == nil ||
147 rec->recognizer_set_buffer == nil ||
148 rec->recognizer_translate == nil ||
149 rec->recognizer_get_extension_functions == nil ||
150 rec->recognizer_get_gesture_names == nil ||
151 rec->recognizer_set_gesture_action == nil
154 recognizer_unload(rec);
155 /* fprint(2, "Unloading b/c null function pointer.\n"); */
157 dgettext(INTL_DOMAIN,
158 "One or more recognizer function pointers is nil.");
159 return((recognizer)nil);
163 /*Set the rec_info structure.*/
165 rec->recognizer_info = rinf;
171 * recognizer_unload - Unload the recognizer.
175 recognizer_unload(recognizer rec)
177 /*Make sure magic numbers right.*/
179 if( !RI_CHECK_MAGIC(rec) ) {
180 the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
184 return __recognizer_internal_finalize(rec);
188 * recognizer_load_state-Get any recognizer state associated with name
189 * in dir. Note that name may not be simple file name, since
190 * there may be more than one file involved. Return 0 if successful,
194 int recognizer_load_state(recognizer rec, char* dir, char* name)
196 /*Make sure magic numbers right.*/
198 if( !RI_CHECK_MAGIC(rec) ) {
199 the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
205 return(rec->recognizer_load_state(rec, dir, name));
209 * recognizer_save_state-Save any recognizer state to name
210 * in dir. Note that name may not be a simple file name, since
211 * there may be more than one file involved. Return 0 if successful,
215 int recognizer_save_state(recognizer rec,char* dir,char* name)
217 /*Make sure magic numbers right.*/
219 if( !RI_CHECK_MAGIC(rec) ) {
220 the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
226 return(rec->recognizer_save_state(rec,dir,name));
230 * recognizer_load_dictionary-Load dictionary, return pointer
231 * to it, or nil if error.
234 wordset recognizer_load_dictionary(recognizer rec,char* dir,char* name)
236 /*Make sure magic numbers right.*/
238 if( !RI_CHECK_MAGIC(rec) ) {
239 the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
245 return(rec->recognizer_load_dictionary(rec,dir,name));
249 * recognizer_save_dictionary-Save the dictionary to the file, return 0 if
253 int recognizer_save_dictionary(recognizer rec,char* dir,char* name,wordset dict)
255 /*Make sure magic numbers right.*/
257 if( !RI_CHECK_MAGIC(rec) ) {
258 the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
264 return(rec->recognizer_save_dictionary(rec,dir,name,dict));
268 * recognizer_free_dictionary-Free the dictionary, return 0 if
272 int recognizer_free_dictionary(recognizer rec,wordset dict)
274 /*Make sure magic numbers right.*/
276 if( !RI_CHECK_MAGIC(rec) ) {
277 the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
283 return(rec->recognizer_free_dictionary(rec,dict));
287 * recognizer_add_to_dictionary-Add word to the dictionary,
288 * return 0 if OK, -1 if error.
292 int recognizer_add_to_dictionary(recognizer rec,letterset* word,wordset dict)
294 /*Make sure magic numbers right.*/
296 if( !RI_CHECK_MAGIC(rec) ) {
297 the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
303 return(rec->recognizer_add_to_dictionary(rec,word,dict));
307 * recognizer_delete_from_dictionary-Delete word from the dictionary,
308 * return 0 if OK, -1 if error.
312 recognizer_delete_from_dictionary(recognizer rec,letterset* word,wordset dict)
314 /*Make sure magic numbers right.*/
316 if( !RI_CHECK_MAGIC(rec) ) {
317 the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
323 return(rec->recognizer_delete_from_dictionary(rec,word,dict));
327 * recognizer_get_info-Get a pointers to the rec_info
328 * giving the locales and subsets supported by the recognizer
329 * and the shared library pathname.
333 recognizer_get_info(recognizer rec)
335 /*Make sure magic numbers right.*/
337 if( !RI_CHECK_MAGIC(rec) ) {
338 the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
339 return((rec_info*)nil);
342 /*Return the rec_info object.*/
344 return(rec->recognizer_info);
348 * recognizer_manager_version-Return the version number string of the
349 * recognition manager.
352 const char* recognizer_manager_version(recognizer rec)
354 /*Make sure magic numbers right.*/
356 if( !RI_CHECK_MAGIC(rec) ) {
357 the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
361 return(rec->recognizer_version);
365 * recognizer_error-Return the last error message, or nil if none.
368 char* recognizer_error(recognizer rec)
371 /*Make sure magic numbers right and function there.*/
373 if( !RI_CHECK_MAGIC(rec) && the_last_error == nil ) {
374 return(dgettext(INTL_DOMAIN,"Bad recognizer object."));
376 } else if( the_last_error != nil ) {
377 char* error = the_last_error;
379 the_last_error = nil;
385 return(rec->recognizer_error(rec));
389 * recognizer_set_context-Set the recognition context for translation.
390 * Return 0 if successful, -1 if error.
393 int recognizer_set_context(recognizer rec,rc* rec_xt)
396 /*Make sure magic numbers right.*/
398 if( !RI_CHECK_MAGIC(rec) ) {
399 the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
405 return(rec->recognizer_set_context(rec,rec_xt));
409 * recognzier_get_context-Get the recognition context for translation.
410 * If none or error, return nil.
413 rc* recognizer_get_context(recognizer rec)
416 /*Make sure magic numbers right.*/
418 if( !RI_CHECK_MAGIC(rec) ) {
419 the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
425 return(rec->recognizer_get_context(rec));
429 * recognizer_clear-Clear buffer and recognition context.
430 * Return 0 if success, else -1.
433 int recognizer_clear(recognizer rec,bool delete_points_p)
436 /*Make sure magic numbers right.*/
438 if( !RI_CHECK_MAGIC(rec) ) {
439 the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
445 return(rec->recognizer_clear(rec,delete_points_p));
448 /*recognizer_get_buffer-Get stroke buffer. Return 0 if success, else -1.*/
451 int recognizer_get_buffer(recognizer rec, uint* nstrokes,Stroke** strokes)
454 /*Make sure magic numbers right.*/
456 if( !RI_CHECK_MAGIC(rec) ) {
457 the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
463 return(rec->recognizer_get_buffer(rec,nstrokes,strokes));
468 * recognizer_set_buffer-Set stroke buffer to arg. Return 0 if success, else
472 int recognizer_set_buffer(recognizer rec,uint nstrokes,Stroke* strokes)
475 /*Make sure magic numbers right.*/
477 if( !RI_CHECK_MAGIC(rec) ) {
478 the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
484 return(rec->recognizer_set_buffer(rec,nstrokes,strokes));
489 * recognizer_translate-Translate the strokes in the current context, including
490 * buffered strokes. If nstrokes == 0 or strokes == nil, return
491 * translation of stroke buffer.
494 int recognizer_translate(recognizer rec,
499 rec_alternative** ret)
503 /*Make sure magic numbers right.*/
505 if( !RI_CHECK_MAGIC(rec) ) {
506 the_last_error = dgettext(INTL_DOMAIN, msg);
514 * pen_point* ari_pts;
516 * for (i = 0; i < nstrokes; i++) {
517 * ari_pstr = strokes[i];
518 * ari_pts = ari_pstr.ps_pts;
519 * fprint(2, "\nrecognizer_translate: ari_pts = %ld, sizeof(Time) = %d, sizeof(ari_pts[0] = %d, %d points are...\n", ari_pts, sizeof(Time), sizeof(ari_pts[0]), ari_pstr.ps_npts);
520 * for (ari = 0; ari < ari_pstr.ps_npts; ari++)
521 * fprint(2, "%ld -- (%d, %d) ", ari_pts[ari], ari_pts[ari].x, ari_pts[ari].y);
526 /* ari -- this is calling cmu_recognizer_translate */
527 retval = rec->recognizer_translate(rec,
538 * recognizer_get_extension_functions-Return a null terminated array
539 * of functions providing extended functionality. Their interfaces
540 * will change depending on the recognizer.
543 rec_fn* recognizer_get_extension_functions(recognizer rec)
545 /*Make sure magic numbers right.*/
547 if( !RI_CHECK_MAGIC(rec) ) {
548 the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
549 return((rec_fn*)nil);
554 return(rec->recognizer_get_extension_functions(rec));
559 * recognizer_get_gesture_names - Return a null terminated array of
560 * gesture name strings.
564 recognizer_get_gesture_names(recognizer rec)
566 /*Make sure magic numbers right.*/
568 if( !RI_CHECK_MAGIC(rec) ) {
569 the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
575 return(rec->recognizer_get_gesture_names(rec));
579 * recognizer_set_gesture_action-Set the action function for the gesture.
583 recognizer_train_gestures(recognizer rec,char* name,xgesture fn,void* wsinfo)
585 /*Make sure magic numbers right.*/
587 if( !RI_CHECK_MAGIC(rec) ) {
588 the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
589 return((xgesture)-1);
594 return(rec->recognizer_set_gesture_action(rec,name,fn,wsinfo));
602 * intl_initialize-Initialize the internationaliztion of messages for
603 * the recognition manager.
606 static void intl_initialize(void)
610 /*Get recognizer home directory name from environment.*/
612 if( (dirname = getenv(RECHOME)) == nil ) {
613 dirname = "REC_DEFAULT_HOME_DIR";
616 /*Bind the text domain.*/
618 bindtextdomain(dirname, INTL_DOMAIN);
622 /*make_rec_info-Create a rec_info structure*/
624 static rec_info* make_rec_info(char*, char*, char** subset)
630 ri = (rec_info*)safe_malloc(sizeof(rec_info));
637 if( (locale = getenv(LANG)) == nil ) {
638 locale = strdup(REC_DEFAULT_LOCALE);
641 if( (ri->ri_locale = strdup(locale)) == nil ) {
646 /*Get shared library pathname.*/
648 /*Initialize the subset information.*/
650 if( subset != nil ) {
652 /*Count the subset strings.*/
654 for( len = 1; subset[len] != nil; len++ ) ;
656 /*Copy the subset strings.*/
658 ri->ri_subset = (char**)safe_malloc((len +1)*sizeof(char*));
660 for( i = 0; i < len; i++ ) {
661 if( subset[i] != nil ) {
662 if( (ri->ri_subset[i] = strdup(subset[i])) == nil ) {
667 ri->ri_subset[i] = subset[i];
671 ri->ri_subset[i] = nil;
681 static void delete_rec_info(rec_info* ri)
684 if( ri->ri_locale != nil ) {
688 * if( ri->ri_name != nil ) {
692 if( ri->ri_subset != nil ) {
694 for( i = 0; ri->ri_subset[i] != nil; i++) {
695 free(ri->ri_subset[i]);
704 * Constructor functions for making structures.
706 * The general philosophy here is that we control all memory
707 * in connected data structures, *except* for pen_point arrays.
708 * There are likely to be lots and lots of points, they are likely
709 * to come from the window system; so if we wanted to control them,
710 * we would have to copy which would be slow. We require the client
711 * to deal with them directly, or the client can give us permission
720 recognizer make_recognizer(rec_info* rif)
726 rec = (recognizer)safe_malloc(sizeof(*rec));
727 rec->recognizer_magic = REC_MAGIC;
728 rec->recognizer_version = REC_VERSION;
729 rec->recognizer_info = rif;
730 rec->recognizer_specific = nil;
731 rec->recognizer_end_magic = REC_END_MAGIC;
732 rec->recognizer_load_state = nil;
733 rec->recognizer_save_state = nil;
734 rec->recognizer_load_dictionary = nil;
735 rec->recognizer_save_dictionary = nil;
736 rec->recognizer_free_dictionary = nil;
737 rec->recognizer_add_to_dictionary = nil;
738 rec->recognizer_delete_from_dictionary = nil;
739 rec->recognizer_error = nil;
740 rec->recognizer_set_context = nil;
741 rec->recognizer_get_context = nil;
742 rec->recognizer_clear = nil;
743 rec->recognizer_get_buffer = nil;
744 rec->recognizer_set_buffer = nil;
745 rec->recognizer_translate = nil;
746 rec->recognizer_get_extension_functions = nil;
747 rec->recognizer_get_gesture_names = nil;
748 rec->recognizer_set_gesture_action = nil;
752 void delete_recognizer(recognizer rec)
756 if( rec->recognizer_info != nil ) {
757 delete_rec_info(rec->recognizer_info);
767 rec_alternative* make_rec_alternative_array(uint size)
772 ri = (rec_alternative*) safe_malloc(size * sizeof(rec_alternative));
774 for( i = 0; i < size; i++ ) {
775 ri[i].ra_elem.re_type = REC_NONE;
776 ri[i].ra_elem.re_result.aval = nil;
777 ri[i].ra_elem.re_conf = 0;
786 initialize_rec_alternative(rec_alternative* ra, uint nelm)
789 if( (ra->ra_next = make_rec_alternative_array(nelm)) == nil ) {
793 ra->ra_nalter = nelm;
799 void delete_rec_alternative_array(uint nalter,
801 bool delete_points_p)
807 for( i = 0; i < nalter; i++ ) {
808 cleanup_rec_element(&ra[i].ra_elem,delete_points_p);
810 /*Now do the next one down the line.*/
812 if( ra[i].ra_nalter > 0 ) {
813 delete_rec_alternative_array(ra[i].ra_nalter,
824 /*initialize_rec_element-Initialize a recognition element.*/
827 initialize_rec_element(rec_element* re,
837 re->re_result.aval = nil;
842 if( size > 0 && trans != nil ) {
844 (gesture*)safe_malloc(sizeof(gesture));
845 memcpy((void*)re->re_result.gval,trans,sizeof(gesture));
852 if( size > 0 && trans != nil ) {
854 (char*)safe_malloc((size+1)*sizeof(char));
855 memcpy((void*)re->re_result.aval,trans,size*sizeof(char));
856 re->re_result.aval[size] = '\000';
861 if( size > 0 && trans != nil ) {
863 (wchar_t*)safe_malloc((size+1)*sizeof(wchar_t));
864 memcpy((void*)re->re_result.wval,trans,size*sizeof(wchar_t));
865 re->re_result.wval[size] = '\000';
870 if( size > 0 && trans != nil ) {
871 re->re_result.rcval =
872 (rec_correlation*)safe_malloc(sizeof(rec_correlation));
873 memcpy((void*)re->re_result.rcval,
875 sizeof(rec_correlation));
888 static void cleanup_rec_element(rec_element* re,bool delete_points_p)
890 switch(re->re_type) {
899 free(re->re_result.aval);
903 delete_gesture_array(1,re->re_result.gval,true);
907 delete_rec_correlation(re->re_result.rcval,
921 make_rec_correlation(char type,
929 rc = (rec_correlation*)safe_malloc(sizeof(rec_correlation));
931 rc->ro_nstrokes = ps_size;
933 /*First initialize element.*/
935 if( initialize_rec_element(&(rc->ro_elem),
943 if( (rc->ro_strokes = make_Stroke_array(ps_size)) == nil ) {
947 rc->ro_start = (uint*)safe_malloc(ps_size * sizeof(int));
948 rc->ro_stop = (uint*)safe_malloc(ps_size * sizeof(int));
952 void delete_rec_correlation(rec_correlation* rc,bool delete_points_p)
956 cleanup_rec_element(&rc->ro_elem,delete_points_p);
958 delete_Stroke_array(rc->ro_nstrokes,rc->ro_strokes,delete_points_p);
960 if( rc->ro_start != nil ) {
964 if( rc->ro_stop != nil ) {
979 rec_fn* make_rec_fn_array(uint size)
981 rec_fn* ri = (rec_fn*)safe_malloc((size + 1) * sizeof(rec_fn));
984 for( i = 0; i < size; i++ ) {
993 void delete_rec_fn_array(rec_fn* rf)
1005 Stroke* make_Stroke_array(uint size)
1010 ri = (Stroke*) safe_malloc(size * sizeof(Stroke));
1011 for( i = 0; i < size; i++ ) {
1019 Stroke* initialize_Stroke(Stroke* ps,
1030 void delete_Stroke_array(uint size,Stroke* ps,bool delete_points_p)
1036 for( i = 0; i < size; i++ ) {
1037 if( delete_points_p ) {
1038 delete_pen_point_array(ps[i].pts);
1050 void delete_pen_point_array(pen_point* pp)
1062 make_gesture_array(uint size)
1064 return((gesture*)safe_malloc(size * sizeof(gesture)));
1067 gesture* initialize_gesture(gesture* g,
1077 /*We don't do points, 'cause they come from the window system.*/
1080 g->g_hspots = hspots;
1082 g->g_name = strdup(name);
1086 g->g_wsinfo = wsinfo;
1092 delete_gesture_array(uint size,gesture* ga,bool delete_points_p)
1098 for( i = 0; i < size; i++ ) {
1102 if( delete_points_p ) {
1103 delete_pen_point_array(ga[i].g_hspots);
1112 * copy fns for stroke buffer management.
1116 copy_Stroke(Stroke* ps1,Stroke* ps2)
1118 initialize_Stroke(ps1,
1126 copy_Stroke_array(uint nstrokes,
1130 Stroke* ps = make_Stroke_array(nstrokes);
1134 for( i = 0; i < nstrokes; i++ ) {
1136 copy_Stroke(&ps[i],&strokes[i]);
1146 copy_state_trans_array(uint ntrans,uint* trans)
1148 uint* pt = (uint*)safe_malloc(ntrans*sizeof(uint));
1151 for( i = 0; i < ntrans; i++ ) {
1159 concatenate_Strokes(int nstrokes1,
1170 /*Measure new strokes*/
1172 ns = nstrokes1 + nstrokes2;
1176 if( (ps = make_Stroke_array(ns)) == nil ) {
1180 /*Copy old ones into new.*/
1182 for( i = 0; i < nstrokes1; i++ ) {
1183 if( copy_Stroke(&ps[i],&strokes1[i]) == nil ) {
1184 delete_Stroke_array(ns,ps,false);
1189 for( ; i < ns; i++ ) {
1190 if( copy_Stroke(&ps[i],&strokes2[i - nstrokes1]) == nil ) {
1191 delete_Stroke_array(ns,ps,false);