xref: /plan9-contrib/sys/src/libscribble/hre_api.c (revision 80ee5cbfe36716af62da8896207e9763b8e3d760)
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 
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
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
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 
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 
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 
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 
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 
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 
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
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*
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 
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 
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 
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 
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(recognizer_get_context(rec));
443 }
444 
445 /*
446  * recognizer_clear-Clear buffer and recognition context.
447  * Return 0 if success, else -1.
448 */
449 
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 
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 
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 
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 
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**
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
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 
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 
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 
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 
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 
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     if (dirstat(rechome, &dir) == 0) {
784 		if (dir.mode & CHDIR) {
785 			free(rechome);
786 			return 0;
787 		}
788 	} else {
789 		int fd;
790 		if ((fd = create(rechome, OREAD, CHDIR|0755)) >= 0) {
791 			close(fd);
792     		free(rechome);
793     		return(0);
794 		}
795     }
796 	free(rechome);
797 	return(-1);
798 }
799 
800 /*
801  * Constructor functions for making structures.
802  *
803  *    The general philosophy here is that we control all memory
804  *    in connected data structures, *except* for pen_point arrays.
805  *    There are likely to be lots and lots of points, they are likely
806  *    to come from the window system; so if we wanted to control them,
807  *    we would have to copy which would be slow. We require the client
808  *    to deal with them directly, or the client can give us permission
809  *    to delete them.
810 */
811 
812 /*
813  * recognizer
814 */
815 
816 
817 recognizer make_recognizer(rec_info* rif)
818 {
819     recognizer rec;
820 
821     /*Allocate it.*/
822 
823     rec = (recognizer)safe_malloc(sizeof(*rec));
824     rec->recognizer_magic = REC_MAGIC;
825     rec->recognizer_version = REC_VERSION;
826     rec->recognizer_info = rif;
827     rec->recognizer_specific = nil;
828     rec->recognizer_end_magic = REC_END_MAGIC;
829     rec->recognizer_load_state = nil;
830     rec->recognizer_save_state = nil;
831     rec->recognizer_load_dictionary = nil;
832     rec->recognizer_save_dictionary = nil;
833     rec->recognizer_free_dictionary = nil;
834     rec->recognizer_add_to_dictionary = nil;
835     rec->recognizer_delete_from_dictionary = nil;
836     rec->recognizer_error = nil;
837     rec->recognizer_set_context = nil;
838     rec->recognizer_get_context = nil;
839     rec->recognizer_clear = nil;
840     rec->recognizer_get_buffer = nil;
841     rec->recognizer_set_buffer = nil;
842     rec->recognizer_translate = nil;
843     rec->recognizer_get_extension_functions = nil;
844     rec->recognizer_get_gesture_names = nil;
845     rec->recognizer_set_gesture_action = nil;
846     return(rec);
847 }
848 
849 void delete_recognizer(recognizer rec)
850 {
851 
852     if( rec != nil ) {
853 	if( rec->recognizer_info != nil ) {
854 	    delete_rec_info(rec->recognizer_info);
855 	}
856 	free(rec);
857     }
858 }
859 
860 /*
861  * rec_alternative
862 */
863 
864 rec_alternative* make_rec_alternative_array(uint size)
865 {
866     int i;
867     rec_alternative* ri;
868 
869     ri = (rec_alternative*) safe_malloc(size * sizeof(rec_alternative));
870 
871     for( i = 0; i < size; i++ ) {
872         ri[i].ra_elem.re_type = REC_NONE;
873 	ri[i].ra_elem.re_result.aval = nil;
874 	ri[i].ra_elem.re_conf = 0;
875 	ri[i].ra_nalter = 0;
876 	ri[i].ra_next = nil;
877     }
878 
879     return(ri);
880 }
881 
882 rec_alternative*
883   initialize_rec_alternative(rec_alternative* ra, uint nelm)
884 {
885   if( ra != nil ) {
886     if( (ra->ra_next = make_rec_alternative_array(nelm)) == nil ) {
887       return(nil);
888     }
889 
890     ra->ra_nalter = nelm;
891   }
892 
893   return(ra);
894 }
895 
896 void delete_rec_alternative_array(uint nalter,
897 				  rec_alternative* ra,
898 				  bool delete_points_p)
899 {
900   int i;
901 
902     if( ra != nil ) {
903 
904       for( i = 0; i < nalter; i++ ) {
905 	cleanup_rec_element(&ra[i].ra_elem,delete_points_p);
906 
907 	/*Now do the next one down the line.*/
908 
909 	if( ra[i].ra_nalter > 0 ) {
910 	  delete_rec_alternative_array(ra[i].ra_nalter,
911 				       ra[i].ra_next,
912 				       delete_points_p);
913         }
914       }
915 
916       free(ra);
917     }
918 }
919 
920 
921 /*initialize_rec_element-Initialize a recognition element.*/
922 
923 rec_element*
924 initialize_rec_element(rec_element* re,
925 		       char type,
926 		       uint size,
927 		       void* trans,
928 		       rec_confidence conf)
929 {
930     if( re != nil ) {
931 
932 	re->re_type = type;
933 	re->re_conf = conf;
934 	re->re_result.aval = nil;
935 
936 	switch (type) {
937 
938 	  case REC_GESTURE:
939 	    if( size > 0 && trans != nil ) {
940 		re->re_result.gval =
941 		     (gesture*)safe_malloc(sizeof(gesture));
942 		memcpy((void*)re->re_result.gval,trans,sizeof(gesture));
943 	    }
944 	    break;
945 
946 	  case REC_ASCII:
947 	  case REC_VAR:
948 	  case REC_OTHER:
949 	    if( size > 0 && trans != nil ) {
950 		re->re_result.aval =
951 		     (char*)safe_malloc((size+1)*sizeof(char));
952 		memcpy((void*)re->re_result.aval,trans,size*sizeof(char));
953 		re->re_result.aval[size] = '\000';
954 	    }
955 	    break;
956 
957 	  case REC_WCHAR:
958 	    if( size > 0 && trans != nil ) {
959 		re->re_result.wval =
960 		     (wchar_t*)safe_malloc((size+1)*sizeof(wchar_t));
961 		memcpy((void*)re->re_result.wval,trans,size*sizeof(wchar_t));
962 		re->re_result.wval[size] = '\000';
963 	    }
964 	    break;
965 
966 	  case REC_CORR:
967 	    if( size > 0 && trans != nil ) {
968 	      re->re_result.rcval =
969 		   (rec_correlation*)safe_malloc(sizeof(rec_correlation));
970 	      memcpy((void*)re->re_result.rcval,
971 		     trans,
972 		     sizeof(rec_correlation));
973 	    }
974 	    break;
975 
976 	  default:
977 	    return(nil);
978 	}
979 
980     }
981 
982     return(re);
983 }
984 
985 static void cleanup_rec_element(rec_element* re,bool delete_points_p)
986 {
987   switch(re->re_type) {
988 
989   case REC_NONE:
990     break;
991 
992   case REC_ASCII:
993   case REC_VAR:
994   case REC_WCHAR:
995   case REC_OTHER:
996     free(re->re_result.aval);
997     break;
998 
999   case REC_GESTURE:
1000     delete_gesture_array(1,re->re_result.gval,true);
1001     break;
1002 
1003   case REC_CORR:
1004     delete_rec_correlation(re->re_result.rcval,
1005 			   delete_points_p);
1006     break;
1007 
1008   }
1009 
1010 }
1011 
1012 /*
1013  * rec_correlation
1014 */
1015 
1016 
1017 rec_correlation*
1018 make_rec_correlation(char type,
1019 		     uint size,
1020 		     void* trans,
1021 		     rec_confidence conf,
1022 		     uint ps_size)
1023 {
1024   rec_correlation* rc;
1025 
1026     rc = (rec_correlation*)safe_malloc(sizeof(rec_correlation));
1027 
1028     rc->ro_nstrokes = ps_size;
1029 
1030     /*First initialize element.*/
1031 
1032     if( initialize_rec_element(&(rc->ro_elem),
1033 			       type,
1034 			       size,
1035 			       trans,
1036 			       conf) == nil ) {
1037       return(nil);
1038     }
1039 
1040     if( (rc->ro_strokes = make_Stroke_array(ps_size)) == nil ) {
1041       return(nil);
1042     }
1043 
1044     rc->ro_start = (uint*)safe_malloc(ps_size * sizeof(int));
1045     rc->ro_stop = (uint*)safe_malloc(ps_size * sizeof(int));
1046     return(rc);
1047 }
1048 
1049 void delete_rec_correlation(rec_correlation* rc,bool delete_points_p)
1050 {
1051   if( rc != nil ) {
1052 
1053     cleanup_rec_element(&rc->ro_elem,delete_points_p);
1054 
1055     delete_Stroke_array(rc->ro_nstrokes,rc->ro_strokes,delete_points_p);
1056 
1057     if( rc->ro_start != nil ) {
1058       free(rc->ro_start);
1059     }
1060 
1061     if( rc->ro_stop != nil ) {
1062       free(rc->ro_stop);
1063     }
1064 
1065     free(rc);
1066   }
1067 
1068 }
1069 
1070 
1071 /*
1072  * rec_fn
1073 */
1074 
1075 
1076 rec_fn* make_rec_fn_array(uint size)
1077 {
1078     rec_fn* ri = (rec_fn*)safe_malloc((size + 1) * sizeof(rec_fn));
1079     int i;
1080 
1081     for( i = 0; i < size; i++ ) {
1082 	ri[i] = nil;
1083     }
1084 
1085     ri[i] = nil;
1086 
1087     return(ri);
1088 }
1089 
1090 void delete_rec_fn_array(rec_fn* rf)
1091 {
1092     if( rf != nil ) {
1093 	free(rf);
1094     }
1095 }
1096 
1097 /*
1098  * Stroke
1099 */
1100 
1101 
1102 Stroke* make_Stroke_array(uint size)
1103 {
1104     int i;
1105     Stroke* ri;
1106 
1107     ri = (Stroke*) safe_malloc(size * sizeof(Stroke));
1108     for( i = 0; i < size; i++ ) {
1109 	ri[i].npts = 0;
1110 	ri[i].pts = nil;
1111     }
1112 
1113     return(ri);
1114 }
1115 
1116 Stroke* initialize_Stroke(Stroke* ps,
1117 				  uint npts,
1118 				  pen_point* pts)
1119 {
1120   if( ps != nil ) {
1121     ps->npts = npts;
1122     ps->pts = pts;
1123   }
1124   return (ps);
1125 }
1126 
1127 void delete_Stroke_array(uint size,Stroke* ps,bool delete_points_p)
1128 {
1129   int i;
1130 
1131     if( ps != nil ) {
1132 
1133       for( i = 0; i < size; i++ ) {
1134 	    if( delete_points_p ) {
1135 		delete_pen_point_array(ps[i].pts);
1136 	    }
1137       }
1138 
1139       free(ps);
1140     }
1141 }
1142 
1143 /*
1144  * pen_point
1145 */
1146 
1147 void delete_pen_point_array(pen_point* pp)
1148 {
1149     if( pp != nil ) {
1150 	free(pp);
1151     }
1152 }
1153 
1154 /*
1155  * gesture
1156 */
1157 
1158 gesture*
1159 make_gesture_array(uint size)
1160 {
1161     return((gesture*)safe_malloc(size * sizeof(gesture)));
1162 }
1163 
1164 gesture* initialize_gesture(gesture* g,
1165 			    char* name,
1166 			    uint nhs,
1167 			    pen_point* hspots,
1168 			    pen_rect bbox,
1169 			    xgesture fn,
1170 			    void* wsinfo)
1171 {
1172 	if( g != nil ) {
1173 
1174 		/*We don't do points, 'cause they come from the window system.*/
1175 
1176 		g->g_nhs = nhs;
1177 		g->g_hspots = hspots;
1178 
1179 		g->g_name = strdup(name);
1180 
1181 		g->g_bbox = bbox;
1182 		g->g_action = fn;
1183 		g->g_wsinfo = wsinfo;
1184 	}
1185 	return(g);
1186 }
1187 
1188 void
1189 delete_gesture_array(uint size,gesture* ga,bool delete_points_p)
1190 {
1191     int i;
1192 
1193     if( ga != nil ) {
1194 
1195       for( i = 0; i < size; i++ ) {
1196 
1197 	free(ga[i].g_name);
1198 
1199 	if( delete_points_p ) {
1200 	  delete_pen_point_array(ga[i].g_hspots);
1201 	}
1202       }
1203 
1204       free(ga);
1205     }
1206 }
1207 
1208 /*
1209  * copy fns for stroke buffer management.
1210 */
1211 
1212 static Stroke*
1213 copy_Stroke(Stroke* ps1,Stroke* ps2)
1214 {
1215   initialize_Stroke(ps1,
1216 			ps2->npts,
1217 			ps2->pts);
1218   return(ps1);
1219 
1220 }
1221 
1222 Stroke*
1223  copy_Stroke_array(uint nstrokes,
1224 		    Stroke* strokes)
1225 {
1226   int i;
1227   Stroke* ps = make_Stroke_array(nstrokes);
1228 
1229   if( ps != nil ) {
1230 
1231     for( i = 0; i < nstrokes; i++ ) {
1232 
1233       copy_Stroke(&ps[i],&strokes[i]);
1234 
1235     }
1236 
1237   }
1238 
1239   return(ps);
1240 }
1241 
1242 uint*
1243  copy_state_trans_array(uint ntrans,uint* trans)
1244 {
1245   uint* pt = (uint*)safe_malloc(ntrans*sizeof(uint));
1246   int i;
1247 
1248   for( i = 0; i < ntrans; i++ ) {
1249     pt[i] = trans[i];
1250   }
1251   return(pt);
1252 
1253 }
1254 
1255 Stroke*
1256 concatenate_Strokes(int nstrokes1,
1257 			Stroke* strokes1,
1258 			int nstrokes2,
1259 			Stroke* strokes2,
1260 			int* nstrokes3,
1261 			Stroke** strokes3)
1262 {
1263   int i;
1264   int ns;
1265   Stroke* ps;
1266 
1267   /*Measure new strokes*/
1268 
1269   ns = nstrokes1 + nstrokes2;
1270 
1271   /*Allocate memory*/
1272 
1273   if( (ps = make_Stroke_array(ns)) == nil ) {
1274     return(nil);
1275   }
1276 
1277   /*Copy old ones into new.*/
1278 
1279   for( i = 0; i < nstrokes1; i++ ) {
1280     if( copy_Stroke(&ps[i],&strokes1[i]) == nil ) {
1281       delete_Stroke_array(ns,ps,false);
1282       return(nil);
1283     }
1284   }
1285 
1286   for( ; i < ns; i++ ) {
1287     if( copy_Stroke(&ps[i],&strokes2[i - nstrokes1]) == nil ) {
1288       delete_Stroke_array(ns,ps,false);
1289       return(nil);
1290     }
1291   }
1292 
1293   *nstrokes3 = ns;
1294   *strokes3 = ps;
1295 
1296   return(ps);
1297 }
1298