xref: /plan9/sys/src/libscribble/hre_api.c (revision 12fd1c83b21b4d1deeab2b58fe2c202d2038c714)
1 /*
2  *  hre_api.c:        Implementation of HRE API
3  *  Author:           James &
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
7  *  Update Count:     137
8  *  Copyright (c) 1994 by Sun Microsystems Computer Company
9  *  All rights reserved.
10  *
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
15  *  laws.
16  *
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
20  */
21 
22 #include <u.h>
23 #include <libc.h>
24 #include <draw.h>
25 #include <scribble.h>
26 
27 #include "scribbleimpl.h"
28 #include "hre_internal.h"
29 
30 /* ari -- prototype for rii function */
31 recognizer __recognizer_internal_initialize(rec_info* ri);
32 
33 /*Version number of API.*/
34 
35 char* REC_VERSION = "2.0";
36 
37 /*Domain name for internationalized text.*/
38 
39 #define INTL_DOMAIN "recognition_manager"
40 
41 /* XXX -- Intl Hack -- Jay & Ari */
42 #define	dgettext(domain, msg)	(msg)
43 #define	bindtextdomain(dirname,	domain)
44 
45 /*
46  * These magic numbers are used to ensure the integrity of the
47  * recognizer structure.
48 */
49 
50 
51 #define REC_MAGIC       0xfeed
52 #define REC_END_MAGIC   0xbeef
53 
54 /*Check the recognizer for validity*/
55 
56 #define RI_CHECK_MAGIC(rec) \
57   ( (rec != nil) && \
58     (((recognizer)rec)->recognizer_magic == REC_MAGIC) && \
59    (((recognizer)rec)->recognizer_end_magic == REC_END_MAGIC) &&\
60    (((recognizer)rec)->recognizer_version == REC_VERSION) )
61 
62 /*The name of the initialization & finalization functions.*/
63 
64 /* static char rii_name[] = "__recognizer_internal_initialize";
65 static char rif_name[] = "__recognizer_internal_finalize";  */
66 
67 /*User home directory for recognizer info.*/
68 /* ari -- changed USERRECHOME from ".recognizers" */
69 #define HOME "HOME"
70 #define USERRECHOME ".classifiers"
71 
72 /*Local functions*/
73 
74 static char* shared_library_name(char* directory,char* locale,char* name);
75 static rec_info* make_rec_info(char* directory,char* name,char** subset);
76 static void delete_rec_info(rec_info* ri);
77 static int check_for_user_home(void);
78 static void intl_initialize(void);
79 
80 static void cleanup_rec_element(rec_element* re,bool delete_points_p);
81 
82 /*The last error.*/
83 
84 static char* the_last_error = nil;
85 
safe_malloc(int nbytes)86 static char *safe_malloc (int nbytes)
87 {
88   char *res = malloc(nbytes);
89   if (res == nil) {
90     sysfatal("malloc failure");
91   }
92   return (res);
93 }
94 
95 
96 /*
97  * Implementation of API functions
98 */
99 
100 /*
101  * recognizer_load - Load the recognizer matching the rec_info struct.
102  * If name is not null, then load the recognizer having that name. Returns
103  * the recognizer object, or null if it can't load the recognizer, and
104  * sets errno to indicate why.
105 */
106 
107 recognizer
recognizer_load(char * directory,char * name,char ** subset)108 recognizer_load(char* directory, char* name, char** subset)
109 {
110     recognizer	rec;				/*the recognizer*/
111     rec_info*	rinf;				/*rec_info for recognizer information*/
112     static bool	intl_init = false;	/*true if recog. manager initted.*/
113 
114     if( intl_init == false ) {
115       intl_init = true;
116       intl_initialize();
117     }
118 
119     /*The name takes precedence.*/
120     rinf = make_rec_info(directory, name, subset);
121     if (rinf == nil) {
122 	the_last_error =
123 	  dgettext(INTL_DOMAIN,
124 		   "Ran out of memory during prelinking initialization.");
125 	return((recognizer)nil);
126     }
127 /* fprint(2, "Got past make_rec_info.\n"); */
128 
129     /*Let recognition code create recognizer and initialize*/
130     rec = __recognizer_internal_initialize(rinf);
131     if (rec == nil) {
132 	return((recognizer)nil);
133     }
134 /* fprint(2, "Did rii.\n"); */
135     /*Check whether it's been correctly initialized*/
136 
137     if( rec->recognizer_load_state == nil ||
138         rec->recognizer_save_state == nil ||
139         rec->recognizer_load_dictionary == nil ||
140         rec->recognizer_save_dictionary == nil ||
141         rec->recognizer_free_dictionary == nil ||
142         rec->recognizer_add_to_dictionary == nil ||
143         rec->recognizer_delete_from_dictionary == nil ||
144         rec->recognizer_error == nil ||
145         rec->recognizer_set_context == nil ||
146         rec->recognizer_get_context == nil ||
147         rec->recognizer_clear == nil ||
148         rec->recognizer_get_buffer == nil ||
149         rec->recognizer_set_buffer == nil ||
150         rec->recognizer_translate == nil ||
151         rec->recognizer_get_extension_functions == nil ||
152         rec->recognizer_get_gesture_names == nil ||
153         rec->recognizer_set_gesture_action == nil
154        ) {
155 
156 	recognizer_unload(rec);
157 /* fprint(2, "Unloading b/c null function pointer.\n"); */
158 	the_last_error =
159 	  dgettext(INTL_DOMAIN,
160 		   "One or more recognizer function pointers is nil.");
161 	return((recognizer)nil);
162     }
163 
164 
165     /*Set the rec_info structure.*/
166 
167     rec->recognizer_info = rinf;
168 
169     /*Check whether home directory is there for recognizer info.*/
170 
171 /*
172  *  ari -- don't bother.  We're not going to load from each user's
173  *  home directory at this point.  Instead, we'll use a stupid
174  *  little a-b-c file because it loads FAST.
175  *
176  *    if( check_for_user_home() < 0 ) {
177  *	recognizer_unload(rec);
178  *	return((recognizer)nil);
179  *   }
180  */
181     /*We got it!*/
182 /* fprint(2, "Done.\n"); */
183 
184     return(rec);
185 }
186 
187 /*
188  * recognizer_unload - Unload the recognizer.
189 */
190 
191 int
recognizer_unload(recognizer rec)192 recognizer_unload(recognizer rec)
193 {
194     /*Make sure magic numbers right.*/
195 
196 	if( !RI_CHECK_MAGIC(rec) ) {
197 		the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
198 		return(-1);
199 	}
200 
201 	return __recognizer_internal_finalize(rec);
202 }
203 
204 /*
205  * recognizer_load_state-Get any recognizer state associated with name
206  * in dir. Note that name may not be simple file name, since
207  * there may be more than one file involved. Return 0 if successful,
208  * -1 if not.
209 */
210 
recognizer_load_state(recognizer rec,char * dir,char * name)211 int recognizer_load_state(recognizer rec, char* dir, char* name)
212 {
213     /*Make sure magic numbers right.*/
214 
215     if( !RI_CHECK_MAGIC(rec) ) {
216 		the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
217 		return(-1);
218     }
219 
220     /*Do the function.*/
221 
222     return(rec->recognizer_load_state(rec, dir, name));
223 }
224 
225 /*
226  * recognizer_save_state-Save any recognizer state to name
227  * in dir. Note that name may not be a simple file name, since
228  * there may be more than one file involved. Return 0 if successful,
229  * -1 if not.
230 */
231 
recognizer_save_state(recognizer rec,char * dir,char * name)232 int recognizer_save_state(recognizer rec,char* dir,char* name)
233 {
234     /*Make sure magic numbers right.*/
235 
236     if( !RI_CHECK_MAGIC(rec) ) {
237 	the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
238 	return(-1);
239     }
240 
241     /*Do the function.*/
242 
243     return(rec->recognizer_save_state(rec,dir,name));
244 }
245 
246 /*
247  * recognizer_load_dictionary-Load dictionary, return pointer
248  * to it, or nil if error.
249 */
250 
recognizer_load_dictionary(recognizer rec,char * dir,char * name)251 wordset recognizer_load_dictionary(recognizer rec,char* dir,char* name)
252 {
253     /*Make sure magic numbers right.*/
254 
255     if( !RI_CHECK_MAGIC(rec) ) {
256 	the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
257 	return(nil);
258     }
259 
260     /*Do the function.*/
261 
262     return(rec->recognizer_load_dictionary(rec,dir,name));
263 }
264 
265 /*
266  * recognizer_save_dictionary-Save the  dictionary to the file, return 0 if
267  * OK, -1 if error.
268 */
269 
recognizer_save_dictionary(recognizer rec,char * dir,char * name,wordset dict)270 int recognizer_save_dictionary(recognizer rec,char* dir,char* name,wordset dict)
271 {
272     /*Make sure magic numbers right.*/
273 
274     if( !RI_CHECK_MAGIC(rec) ) {
275 	the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
276 	return(-1);
277     }
278 
279     /*Do the function.*/
280 
281     return(rec->recognizer_save_dictionary(rec,dir,name,dict));
282 }
283 
284 /*
285  * recognizer_free_dictionary-Free the dictionary, return 0 if
286  * OK, -1 if error.
287 */
288 
recognizer_free_dictionary(recognizer rec,wordset dict)289 int recognizer_free_dictionary(recognizer rec,wordset dict)
290 {
291     /*Make sure magic numbers right.*/
292 
293     if( !RI_CHECK_MAGIC(rec) ) {
294 	the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
295 	return(-1);
296     }
297 
298     /*Do the function.*/
299 
300     return(rec->recognizer_free_dictionary(rec,dict));
301 }
302 
303 /*
304  * recognizer_add_to_dictionary-Add word to the dictionary,
305  * return 0 if OK, -1 if error.
306 */
307 
308 
recognizer_add_to_dictionary(recognizer rec,letterset * word,wordset dict)309 int recognizer_add_to_dictionary(recognizer rec,letterset* word,wordset dict)
310 {
311     /*Make sure magic numbers right.*/
312 
313     if( !RI_CHECK_MAGIC(rec) ) {
314 	the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
315 	return(-1);
316     }
317 
318     /*Do the function.*/
319 
320     return(rec->recognizer_add_to_dictionary(rec,word,dict));
321 }
322 
323 /*
324  * recognizer_delete_from_dictionary-Delete word from the dictionary,
325  * return 0 if OK, -1 if error.
326 */
327 
328 int
recognizer_delete_from_dictionary(recognizer rec,letterset * word,wordset dict)329 recognizer_delete_from_dictionary(recognizer rec,letterset* word,wordset dict)
330 {
331     /*Make sure magic numbers right.*/
332 
333     if( !RI_CHECK_MAGIC(rec) ) {
334 	the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
335 	return(-1);
336     }
337 
338     /*Do the function.*/
339 
340     return(rec->recognizer_delete_from_dictionary(rec,word,dict));
341 }
342 
343 /*
344  * recognizer_get_info-Get a pointers to the rec_info
345  * giving the locales and subsets supported by the recognizer
346  * and the shared library pathname.
347 */
348 
349 const rec_info*
recognizer_get_info(recognizer rec)350 recognizer_get_info(recognizer rec)
351 {
352     /*Make sure magic numbers right.*/
353 
354     if( !RI_CHECK_MAGIC(rec) ) {
355 	the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
356 	return((rec_info*)nil);
357     }
358 
359     /*Return the rec_info object.*/
360 
361     return(rec->recognizer_info);
362 }
363 
364 /*
365  * recognizer_manager_version-Return the version number string of the
366  * recognition manager.
367 */
368 
recognizer_manager_version(recognizer rec)369 const char* recognizer_manager_version(recognizer rec)
370 {
371     /*Make sure magic numbers right.*/
372 
373     if( !RI_CHECK_MAGIC(rec) ) {
374 	the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
375 	return(nil);
376     }
377 
378     return(rec->recognizer_version);
379 
380 }
381 /*
382  * recognizer_error-Return the last error message, or nil if none.
383 */
384 
recognizer_error(recognizer rec)385 char* recognizer_error(recognizer rec)
386 {
387 
388     /*Make sure magic numbers right and function there.*/
389 
390     if( !RI_CHECK_MAGIC(rec) && the_last_error == nil ) {
391       return(dgettext(INTL_DOMAIN,"Bad recognizer object."));
392 
393     } else if( the_last_error != nil ) {
394       char* error = the_last_error;
395 
396       the_last_error = nil;
397       return(error);
398     }
399 
400     /*Do the function.*/
401 
402     return(rec->recognizer_error(rec));
403 }
404 
405 /*
406  * recognizer_set_context-Set the recognition context for translation.
407  * Return 0 if successful, -1 if error.
408 */
409 
recognizer_set_context(recognizer rec,rc * rec_xt)410 int recognizer_set_context(recognizer rec,rc* rec_xt)
411 {
412 
413     /*Make sure magic numbers right.*/
414 
415     if( !RI_CHECK_MAGIC(rec) ) {
416 	the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
417 	return(-1);
418     }
419 
420     /*Do the function.*/
421 
422     return(rec->recognizer_set_context(rec,rec_xt));
423 }
424 
425 /*
426  * recognzier_get_context-Get the recognition context for translation.
427  * If none or error, return nil.
428 */
429 
recognizer_get_context(recognizer rec)430 rc* recognizer_get_context(recognizer rec)
431 {
432 
433     /*Make sure magic numbers right.*/
434 
435     if( !RI_CHECK_MAGIC(rec) ) {
436 	the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
437 	return(nil);
438     }
439 
440     /*Do the function.*/
441 
442     return(rec->recognizer_get_context(rec));
443 }
444 
445 /*
446  * recognizer_clear-Clear buffer and recognition context.
447  * Return 0 if success, else -1.
448 */
449 
recognizer_clear(recognizer rec,bool delete_points_p)450 int recognizer_clear(recognizer rec,bool delete_points_p)
451 {
452 
453     /*Make sure magic numbers right.*/
454 
455     if( !RI_CHECK_MAGIC(rec) ) {
456 	the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
457 	return(-1);
458     }
459 
460     /*Do the function.*/
461 
462     return(rec->recognizer_clear(rec,delete_points_p));
463 }
464 
465 /*recognizer_get_buffer-Get stroke buffer. Return 0 if success, else -1.*/
466 
467 
recognizer_get_buffer(recognizer rec,uint * nstrokes,Stroke ** strokes)468 int recognizer_get_buffer(recognizer rec, uint* nstrokes,Stroke** strokes)
469 {
470 
471     /*Make sure magic numbers right.*/
472 
473     if( !RI_CHECK_MAGIC(rec) ) {
474 	the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
475 	return(-1);
476     }
477 
478     /*Do the function.*/
479 
480     return(rec->recognizer_get_buffer(rec,nstrokes,strokes));
481 
482 }
483 
484 /*
485  * recognizer_set_buffer-Set stroke buffer to arg. Return 0 if success, else
486  * return -1.
487 */
488 
recognizer_set_buffer(recognizer rec,uint nstrokes,Stroke * strokes)489 int recognizer_set_buffer(recognizer rec,uint nstrokes,Stroke* strokes)
490 {
491 
492     /*Make sure magic numbers right.*/
493 
494     if( !RI_CHECK_MAGIC(rec) ) {
495 	the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
496 	return(-1);
497     }
498 
499     /*Do the function.*/
500 
501     return(rec->recognizer_set_buffer(rec,nstrokes,strokes));
502 
503 }
504 
505 /*
506  * recognizer_translate-Translate the strokes in the current context, including
507  * buffered strokes. If nstrokes == 0 or strokes == nil, return
508  * translation of stroke buffer.
509 */
510 
recognizer_translate(recognizer rec,uint nstrokes,Stroke * strokes,bool correlate_p,int * nret,rec_alternative ** ret)511 int recognizer_translate(recognizer rec,
512 			 uint nstrokes,
513 			 Stroke* strokes,
514 			 bool correlate_p,
515 			 int* nret,
516 			 rec_alternative** ret)
517 {
518     int retval;
519     char msg[80];
520     /*Make sure magic numbers right.*/
521 
522     if( !RI_CHECK_MAGIC(rec) ) {
523 	the_last_error = dgettext(INTL_DOMAIN, msg);
524 	return(-1);
525     }
526 
527 /* ari */
528 /*    {
529  *      uint i;
530  *      Stroke ari_pstr;
531  *      pen_point* ari_pts;
532  *      int ari;
533  *      for (i = 0; i < nstrokes; i++) {
534  *	ari_pstr = strokes[i];
535  *	ari_pts = ari_pstr.ps_pts;
536  *	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);
537  *	for (ari = 0; ari < ari_pstr.ps_npts; ari++)
538  *	   fprint(2, "%ld -- (%d, %d)  ", ari_pts[ari], ari_pts[ari].x, ari_pts[ari].y);
539  *      }
540  *    }
541 */
542     /*Do the function.*/
543 /* ari -- this is calling cmu_recognizer_translate */
544     retval = rec->recognizer_translate(rec,
545 				     nstrokes,
546 				     strokes,
547 				     correlate_p,
548 				     nret,
549 				     ret);
550     return (retval);
551 }
552 
553 
554 /*
555  * recognizer_get_extension_functions-Return a null terminated array
556  * of functions providing extended functionality. Their interfaces
557  * will change depending on the recognizer.
558 */
559 
recognizer_get_extension_functions(recognizer rec)560 rec_fn* recognizer_get_extension_functions(recognizer rec)
561 {
562     /*Make sure magic numbers right.*/
563 
564     if( !RI_CHECK_MAGIC(rec) ) {
565 	the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
566 	return((rec_fn*)nil);
567     }
568 
569     /*Do the function.*/
570 
571     return(rec->recognizer_get_extension_functions(rec));
572 }
573 
574 
575 /*
576  * recognizer_get_gesture_names - Return a null terminated array of
577  * gesture name strings.
578 */
579 
580 char**
recognizer_get_gesture_names(recognizer rec)581 recognizer_get_gesture_names(recognizer rec)
582 {
583     /*Make sure magic numbers right.*/
584 
585     if( !RI_CHECK_MAGIC(rec) ) {
586 	the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
587 	return(nil);
588     }
589 
590     /*Do the function.*/
591 
592     return(rec->recognizer_get_gesture_names(rec));
593 }
594 
595 /*
596  * recognizer_set_gesture_action-Set the action function for the gesture.
597 */
598 
599 xgesture
recognizer_train_gestures(recognizer rec,char * name,xgesture fn,void * wsinfo)600 recognizer_train_gestures(recognizer rec,char* name,xgesture fn,void* wsinfo)
601 {
602     /*Make sure magic numbers right.*/
603 
604     if( !RI_CHECK_MAGIC(rec) ) {
605 	the_last_error = dgettext(INTL_DOMAIN,"Bad recognizer object.");
606 	return((xgesture)-1);
607     }
608 
609     /*Do the function.*/
610 
611     return(rec->recognizer_set_gesture_action(rec,name,fn,wsinfo));
612 }
613 
614 /*
615  * Local functions.
616 */
617 
618 /*
619  * shared_library_name-Get the full pathname to the shared library,
620  *    based on the recognizer name and the environment.
621 */
622 
623 
shared_library_name(char * directory,char * locale,char * name)624 static char* shared_library_name(char* directory,char* locale,char* name)
625 {
626     char* ret;
627     int len = strlen(name);
628 
629     /*If directory is there, it takes precedence.*/
630 
631     if( directory != nil ) {
632 		ret = (char*)safe_malloc(strlen(directory) + len + 2);
633 		strcpy(ret,directory);
634 		strcat(ret,"/");
635 		strcat(ret,name);
636     } else {
637 		char* dir;
638 
639 		/*First try the environment variable.*/
640 
641 		if( (dir = getenv(RECHOME)) == nil ) {
642 		    dir = "REC_DEFAULT_HOME_DIR";
643 
644 		  }
645 
646 		ret = (char*)safe_malloc(strlen(dir) + strlen(locale) + len + 3);
647 		/*Form the pathname.*/
648 		strcpy(ret,dir);
649 		strcat(ret,"/");
650 		strcat(ret,locale);
651 		strcat(ret,"/");
652 		strcat(ret,name);
653 	}
654 
655     return(ret);
656 }
657 
658 /*
659  * intl_initialize-Initialize the internationaliztion of messages for
660  * the recognition manager.
661 */
662 
intl_initialize(void)663 static void intl_initialize(void)
664 {
665 	char* dirname;
666 
667 	/*Get recognizer home directory name from environment.*/
668 
669 	if( (dirname = getenv(RECHOME)) == nil ) {
670 		dirname = "REC_DEFAULT_HOME_DIR";
671 	}
672 
673 	/*Bind the text domain.*/
674 	USED(dirname);
675 	bindtextdomain(dirname, INTL_DOMAIN);
676 }
677 
678 
679 /*make_rec_info-Create a rec_info structure*/
680 
make_rec_info(char *,char *,char ** subset)681 static rec_info* make_rec_info(char*, char*, char** subset)
682 {
683     int i,len;
684     rec_info* ri;
685     char* locale;
686 
687     ri = (rec_info*)safe_malloc(sizeof(rec_info));
688     ri->ri_locale = nil;
689     ri->ri_name = nil;
690     ri->ri_subset = nil;
691 
692     /*Get locale*/
693 
694     if( (locale = getenv(LANG)) == nil ) {
695 		locale = strdup(REC_DEFAULT_LOCALE);
696     }
697 
698     if( (ri->ri_locale = strdup(locale)) == nil ) {
699 		delete_rec_info(ri);
700 		return(nil);
701     }
702 
703     /*Get shared library pathname.*/
704 
705     /*Initialize the subset information.*/
706 
707     if( subset != nil ) {
708 
709 	/*Count the subset strings.*/
710 
711 	for( len = 1; subset[len] != nil; len++ ) ;
712 
713 	/*Copy the subset strings.*/
714 
715 	ri->ri_subset = (char**)safe_malloc((len +1)*sizeof(char*));
716 
717 	for( i = 0; i < len; i++ ) {
718 	    if( subset[i] != nil ) {
719 		if( (ri->ri_subset[i] = strdup(subset[i])) == nil ) {
720 		    delete_rec_info(ri);
721 		    return(nil);
722 		}
723 	    } else {
724 		ri->ri_subset[i] = subset[i];
725 	    }
726 	}
727 
728 	ri->ri_subset[i] = nil;
729 
730     } else {
731 
732 	ri->ri_subset = nil;
733     }
734 
735     return(ri);
736 }
737 
delete_rec_info(rec_info * ri)738 static void delete_rec_info(rec_info* ri)
739 {
740     if( ri != nil ) {
741 	if( ri->ri_locale != nil ) {
742 	    free(ri->ri_locale);
743 	}
744 /*
745  *	if( ri->ri_name != nil ) {
746  *	    free(ri->ri_name);
747  *	}
748  */
749 	if( ri->ri_subset != nil ) {
750 	    int i;
751 	    for( i = 0; ri->ri_subset[i] != nil; i++) {
752 		free(ri->ri_subset[i]);
753 	    }
754 	    free(ri->ri_subset);
755 	}
756 	free(ri);
757     }
758 }
759 
760 /*check_for_user_home-Check whether USERRECHOME has been created.*/
761 
check_for_user_home()762 static int check_for_user_home()
763 {
764 	char* homedir = getenv(HOME);
765 	char* rechome;
766 	Dir *dir;
767 
768 	if( homedir == nil ) {
769 		the_last_error = "Home environment variable HOME not set.";
770 		return(-1);
771 	}
772 
773     rechome = (char*)safe_malloc(strlen(homedir) + strlen(USERRECHOME) + 2);
774 
775     /*Form name.*/
776 
777     strcpy(rechome,homedir);
778     strcat(rechome,"/");
779     strcat(rechome,USERRECHOME);
780 
781     /*Create directory.*/
782 
783     dir = dirstat(rechome);
784     if (dir != nil) {
785 		if (dir->mode & DMDIR) {
786 			free(dir);
787 			free(rechome);
788 			return 0;
789 		}
790 		free(dir);
791 	} else {
792 		int fd;
793 		if ((fd = create(rechome, OREAD, DMDIR|0755)) >= 0) {
794 			close(fd);
795     		free(rechome);
796     		return(0);
797 		}
798     }
799 	free(rechome);
800 	return(-1);
801 }
802 
803 /*
804  * Constructor functions for making structures.
805  *
806  *    The general philosophy here is that we control all memory
807  *    in connected data structures, *except* for pen_point arrays.
808  *    There are likely to be lots and lots of points, they are likely
809  *    to come from the window system; so if we wanted to control them,
810  *    we would have to copy which would be slow. We require the client
811  *    to deal with them directly, or the client can give us permission
812  *    to delete them.
813 */
814 
815 /*
816  * recognizer
817 */
818 
819 
make_recognizer(rec_info * rif)820 recognizer make_recognizer(rec_info* rif)
821 {
822     recognizer rec;
823 
824     /*Allocate it.*/
825 
826     rec = (recognizer)safe_malloc(sizeof(*rec));
827     rec->recognizer_magic = REC_MAGIC;
828     rec->recognizer_version = REC_VERSION;
829     rec->recognizer_info = rif;
830     rec->recognizer_specific = nil;
831     rec->recognizer_end_magic = REC_END_MAGIC;
832     rec->recognizer_load_state = nil;
833     rec->recognizer_save_state = nil;
834     rec->recognizer_load_dictionary = nil;
835     rec->recognizer_save_dictionary = nil;
836     rec->recognizer_free_dictionary = nil;
837     rec->recognizer_add_to_dictionary = nil;
838     rec->recognizer_delete_from_dictionary = nil;
839     rec->recognizer_error = nil;
840     rec->recognizer_set_context = nil;
841     rec->recognizer_get_context = nil;
842     rec->recognizer_clear = nil;
843     rec->recognizer_get_buffer = nil;
844     rec->recognizer_set_buffer = nil;
845     rec->recognizer_translate = nil;
846     rec->recognizer_get_extension_functions = nil;
847     rec->recognizer_get_gesture_names = nil;
848     rec->recognizer_set_gesture_action = nil;
849     return(rec);
850 }
851 
delete_recognizer(recognizer rec)852 void delete_recognizer(recognizer rec)
853 {
854 
855     if( rec != nil ) {
856 	if( rec->recognizer_info != nil ) {
857 	    delete_rec_info(rec->recognizer_info);
858 	}
859 	free(rec);
860     }
861 }
862 
863 /*
864  * rec_alternative
865 */
866 
make_rec_alternative_array(uint size)867 rec_alternative* make_rec_alternative_array(uint size)
868 {
869     int i;
870     rec_alternative* ri;
871 
872     ri = (rec_alternative*) safe_malloc(size * sizeof(rec_alternative));
873 
874     for( i = 0; i < size; i++ ) {
875         ri[i].ra_elem.re_type = REC_NONE;
876 	ri[i].ra_elem.re_result.aval = nil;
877 	ri[i].ra_elem.re_conf = 0;
878 	ri[i].ra_nalter = 0;
879 	ri[i].ra_next = nil;
880     }
881 
882     return(ri);
883 }
884 
885 rec_alternative*
initialize_rec_alternative(rec_alternative * ra,uint nelm)886   initialize_rec_alternative(rec_alternative* ra, uint nelm)
887 {
888   if( ra != nil ) {
889     if( (ra->ra_next = make_rec_alternative_array(nelm)) == nil ) {
890       return(nil);
891     }
892 
893     ra->ra_nalter = nelm;
894   }
895 
896   return(ra);
897 }
898 
delete_rec_alternative_array(uint nalter,rec_alternative * ra,bool delete_points_p)899 void delete_rec_alternative_array(uint nalter,
900 				  rec_alternative* ra,
901 				  bool delete_points_p)
902 {
903   int i;
904 
905     if( ra != nil ) {
906 
907       for( i = 0; i < nalter; i++ ) {
908 	cleanup_rec_element(&ra[i].ra_elem,delete_points_p);
909 
910 	/*Now do the next one down the line.*/
911 
912 	if( ra[i].ra_nalter > 0 ) {
913 	  delete_rec_alternative_array(ra[i].ra_nalter,
914 				       ra[i].ra_next,
915 				       delete_points_p);
916         }
917       }
918 
919       free(ra);
920     }
921 }
922 
923 
924 /*initialize_rec_element-Initialize a recognition element.*/
925 
926 rec_element*
initialize_rec_element(rec_element * re,char type,uint size,void * trans,rec_confidence conf)927 initialize_rec_element(rec_element* re,
928 		       char type,
929 		       uint size,
930 		       void* trans,
931 		       rec_confidence conf)
932 {
933     if( re != nil ) {
934 
935 	re->re_type = type;
936 	re->re_conf = conf;
937 	re->re_result.aval = nil;
938 
939 	switch (type) {
940 
941 	  case REC_GESTURE:
942 	    if( size > 0 && trans != nil ) {
943 		re->re_result.gval =
944 		     (gesture*)safe_malloc(sizeof(gesture));
945 		memcpy((void*)re->re_result.gval,trans,sizeof(gesture));
946 	    }
947 	    break;
948 
949 	  case REC_ASCII:
950 	  case REC_VAR:
951 	  case REC_OTHER:
952 	    if( size > 0 && trans != nil ) {
953 		re->re_result.aval =
954 		     (char*)safe_malloc((size+1)*sizeof(char));
955 		memcpy((void*)re->re_result.aval,trans,size*sizeof(char));
956 		re->re_result.aval[size] = '\000';
957 	    }
958 	    break;
959 
960 	  case REC_WCHAR:
961 	    if( size > 0 && trans != nil ) {
962 		re->re_result.wval =
963 		     (wchar_t*)safe_malloc((size+1)*sizeof(wchar_t));
964 		memcpy((void*)re->re_result.wval,trans,size*sizeof(wchar_t));
965 		re->re_result.wval[size] = '\000';
966 	    }
967 	    break;
968 
969 	  case REC_CORR:
970 	    if( size > 0 && trans != nil ) {
971 	      re->re_result.rcval =
972 		   (rec_correlation*)safe_malloc(sizeof(rec_correlation));
973 	      memcpy((void*)re->re_result.rcval,
974 		     trans,
975 		     sizeof(rec_correlation));
976 	    }
977 	    break;
978 
979 	  default:
980 	    return(nil);
981 	}
982 
983     }
984 
985     return(re);
986 }
987 
cleanup_rec_element(rec_element * re,bool delete_points_p)988 static void cleanup_rec_element(rec_element* re,bool delete_points_p)
989 {
990   switch(re->re_type) {
991 
992   case REC_NONE:
993     break;
994 
995   case REC_ASCII:
996   case REC_VAR:
997   case REC_WCHAR:
998   case REC_OTHER:
999     free(re->re_result.aval);
1000     break;
1001 
1002   case REC_GESTURE:
1003     delete_gesture_array(1,re->re_result.gval,true);
1004     break;
1005 
1006   case REC_CORR:
1007     delete_rec_correlation(re->re_result.rcval,
1008 			   delete_points_p);
1009     break;
1010 
1011   }
1012 
1013 }
1014 
1015 /*
1016  * rec_correlation
1017 */
1018 
1019 
1020 rec_correlation*
make_rec_correlation(char type,uint size,void * trans,rec_confidence conf,uint ps_size)1021 make_rec_correlation(char type,
1022 		     uint size,
1023 		     void* trans,
1024 		     rec_confidence conf,
1025 		     uint ps_size)
1026 {
1027   rec_correlation* rc;
1028 
1029     rc = (rec_correlation*)safe_malloc(sizeof(rec_correlation));
1030 
1031     rc->ro_nstrokes = ps_size;
1032 
1033     /*First initialize element.*/
1034 
1035     if( initialize_rec_element(&(rc->ro_elem),
1036 			       type,
1037 			       size,
1038 			       trans,
1039 			       conf) == nil ) {
1040       return(nil);
1041     }
1042 
1043     if( (rc->ro_strokes = make_Stroke_array(ps_size)) == nil ) {
1044       return(nil);
1045     }
1046 
1047     rc->ro_start = (uint*)safe_malloc(ps_size * sizeof(int));
1048     rc->ro_stop = (uint*)safe_malloc(ps_size * sizeof(int));
1049     return(rc);
1050 }
1051 
delete_rec_correlation(rec_correlation * rc,bool delete_points_p)1052 void delete_rec_correlation(rec_correlation* rc,bool delete_points_p)
1053 {
1054   if( rc != nil ) {
1055 
1056     cleanup_rec_element(&rc->ro_elem,delete_points_p);
1057 
1058     delete_Stroke_array(rc->ro_nstrokes,rc->ro_strokes,delete_points_p);
1059 
1060     if( rc->ro_start != nil ) {
1061       free(rc->ro_start);
1062     }
1063 
1064     if( rc->ro_stop != nil ) {
1065       free(rc->ro_stop);
1066     }
1067 
1068     free(rc);
1069   }
1070 
1071 }
1072 
1073 
1074 /*
1075  * rec_fn
1076 */
1077 
1078 
make_rec_fn_array(uint size)1079 rec_fn* make_rec_fn_array(uint size)
1080 {
1081     rec_fn* ri = (rec_fn*)safe_malloc((size + 1) * sizeof(rec_fn));
1082     int i;
1083 
1084     for( i = 0; i < size; i++ ) {
1085 	ri[i] = nil;
1086     }
1087 
1088     ri[i] = nil;
1089 
1090     return(ri);
1091 }
1092 
delete_rec_fn_array(rec_fn * rf)1093 void delete_rec_fn_array(rec_fn* rf)
1094 {
1095     if( rf != nil ) {
1096 	free(rf);
1097     }
1098 }
1099 
1100 /*
1101  * Stroke
1102 */
1103 
1104 
make_Stroke_array(uint size)1105 Stroke* make_Stroke_array(uint size)
1106 {
1107     int i;
1108     Stroke* ri;
1109 
1110     ri = (Stroke*) safe_malloc(size * sizeof(Stroke));
1111     for( i = 0; i < size; i++ ) {
1112 	ri[i].npts = 0;
1113 	ri[i].pts = nil;
1114     }
1115 
1116     return(ri);
1117 }
1118 
initialize_Stroke(Stroke * ps,uint npts,pen_point * pts)1119 Stroke* initialize_Stroke(Stroke* ps,
1120 				  uint npts,
1121 				  pen_point* pts)
1122 {
1123   if( ps != nil ) {
1124     ps->npts = npts;
1125     ps->pts = pts;
1126   }
1127   return (ps);
1128 }
1129 
delete_Stroke_array(uint size,Stroke * ps,bool delete_points_p)1130 void delete_Stroke_array(uint size,Stroke* ps,bool delete_points_p)
1131 {
1132   int i;
1133 
1134     if( ps != nil ) {
1135 
1136       for( i = 0; i < size; i++ ) {
1137 	    if( delete_points_p ) {
1138 		delete_pen_point_array(ps[i].pts);
1139 	    }
1140       }
1141 
1142       free(ps);
1143     }
1144 }
1145 
1146 /*
1147  * pen_point
1148 */
1149 
delete_pen_point_array(pen_point * pp)1150 void delete_pen_point_array(pen_point* pp)
1151 {
1152     if( pp != nil ) {
1153 	free(pp);
1154     }
1155 }
1156 
1157 /*
1158  * gesture
1159 */
1160 
1161 gesture*
make_gesture_array(uint size)1162 make_gesture_array(uint size)
1163 {
1164     return((gesture*)safe_malloc(size * sizeof(gesture)));
1165 }
1166 
initialize_gesture(gesture * g,char * name,uint nhs,pen_point * hspots,pen_rect bbox,xgesture fn,void * wsinfo)1167 gesture* initialize_gesture(gesture* g,
1168 			    char* name,
1169 			    uint nhs,
1170 			    pen_point* hspots,
1171 			    pen_rect bbox,
1172 			    xgesture fn,
1173 			    void* wsinfo)
1174 {
1175 	if( g != nil ) {
1176 
1177 		/*We don't do points, 'cause they come from the window system.*/
1178 
1179 		g->g_nhs = nhs;
1180 		g->g_hspots = hspots;
1181 
1182 		g->g_name = strdup(name);
1183 
1184 		g->g_bbox = bbox;
1185 		g->g_action = fn;
1186 		g->g_wsinfo = wsinfo;
1187 	}
1188 	return(g);
1189 }
1190 
1191 void
delete_gesture_array(uint size,gesture * ga,bool delete_points_p)1192 delete_gesture_array(uint size,gesture* ga,bool delete_points_p)
1193 {
1194     int i;
1195 
1196     if( ga != nil ) {
1197 
1198       for( i = 0; i < size; i++ ) {
1199 
1200 	free(ga[i].g_name);
1201 
1202 	if( delete_points_p ) {
1203 	  delete_pen_point_array(ga[i].g_hspots);
1204 	}
1205       }
1206 
1207       free(ga);
1208     }
1209 }
1210 
1211 /*
1212  * copy fns for stroke buffer management.
1213 */
1214 
1215 static Stroke*
copy_Stroke(Stroke * ps1,Stroke * ps2)1216 copy_Stroke(Stroke* ps1,Stroke* ps2)
1217 {
1218   initialize_Stroke(ps1,
1219 			ps2->npts,
1220 			ps2->pts);
1221   return(ps1);
1222 
1223 }
1224 
1225 Stroke*
copy_Stroke_array(uint nstrokes,Stroke * strokes)1226  copy_Stroke_array(uint nstrokes,
1227 		    Stroke* strokes)
1228 {
1229   int i;
1230   Stroke* ps = make_Stroke_array(nstrokes);
1231 
1232   if( ps != nil ) {
1233 
1234     for( i = 0; i < nstrokes; i++ ) {
1235 
1236       copy_Stroke(&ps[i],&strokes[i]);
1237 
1238     }
1239 
1240   }
1241 
1242   return(ps);
1243 }
1244 
1245 uint*
copy_state_trans_array(uint ntrans,uint * trans)1246  copy_state_trans_array(uint ntrans,uint* trans)
1247 {
1248   uint* pt = (uint*)safe_malloc(ntrans*sizeof(uint));
1249   int i;
1250 
1251   for( i = 0; i < ntrans; i++ ) {
1252     pt[i] = trans[i];
1253   }
1254   return(pt);
1255 
1256 }
1257 
1258 Stroke*
concatenate_Strokes(int nstrokes1,Stroke * strokes1,int nstrokes2,Stroke * strokes2,int * nstrokes3,Stroke ** strokes3)1259 concatenate_Strokes(int nstrokes1,
1260 			Stroke* strokes1,
1261 			int nstrokes2,
1262 			Stroke* strokes2,
1263 			int* nstrokes3,
1264 			Stroke** strokes3)
1265 {
1266   int i;
1267   int ns;
1268   Stroke* ps;
1269 
1270   /*Measure new strokes*/
1271 
1272   ns = nstrokes1 + nstrokes2;
1273 
1274   /*Allocate memory*/
1275 
1276   if( (ps = make_Stroke_array(ns)) == nil ) {
1277     return(nil);
1278   }
1279 
1280   /*Copy old ones into new.*/
1281 
1282   for( i = 0; i < nstrokes1; i++ ) {
1283     if( copy_Stroke(&ps[i],&strokes1[i]) == nil ) {
1284       delete_Stroke_array(ns,ps,false);
1285       return(nil);
1286     }
1287   }
1288 
1289   for( ; i < ns; i++ ) {
1290     if( copy_Stroke(&ps[i],&strokes2[i - nstrokes1]) == nil ) {
1291       delete_Stroke_array(ns,ps,false);
1292       return(nil);
1293     }
1294   }
1295 
1296   *nstrokes3 = ns;
1297   *strokes3 = ps;
1298 
1299   return(ps);
1300 }
1301