]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libscribble/hre_api.c
Import sources from 2011-03-30 iso image - lib
[plan9front.git] / sys / src / libscribble / hre_api.c
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(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
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     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
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
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
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*
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
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*
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
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* 
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
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
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
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
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
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
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
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*
1162 make_gesture_array(uint size)
1163 {
1164     return((gesture*)safe_malloc(size * sizeof(gesture)));
1165 }
1166
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
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* 
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*
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*
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*
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 }