1 /* XEmacs routines to deal with CONCORD.
2 Copyright (C) 2005,2006 MORIOKA Tomohiko
4 This file is part of XEmacs.
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* Synched up with: Not in FSF. */
23 /* Written by MORIOKA Tomohiko */
33 EXFUN (Fread_from_string, 3);
37 Lisp_Object Qconcord_object;
38 Lisp_Object Qgenre, Q_id;
40 Lisp_Object Vconcord_ds_hash_table;
41 Lisp_Object Vconcord_genre_hash_table;
44 typedef struct Lisp_CONCORD_DS Lisp_CONCORD_DS;
45 DECLARE_LRECORD (concord_ds, Lisp_CONCORD_DS);
47 Lisp_Object Qconcord_dsp;
49 struct Lisp_CONCORD_DS
51 struct lcrecord_header header;
55 #define XCONCORD_DS(x) XRECORD (x, concord_ds, Lisp_CONCORD_DS)
56 #define XSET_CONCORD_DS(x, p) XSETRECORD (x, p, concord_ds)
57 #define CONCORD_DS_P(x) RECORDP (x, concord_ds)
58 #define CHECK_CONCORD_DS(x) CHECK_RECORD (x, concord_ds)
59 #define CONCHECK_CONCORD_DS(x) CONCHECK_RECORD (x, concord_ds)
61 static Lisp_CONCORD_DS*
62 allocate_concord_ds (void)
65 = alloc_lcrecord_type (Lisp_CONCORD_DS, &lrecord_concord_ds);
72 mark_concord_ds (Lisp_Object object)
78 print_concord_ds (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
80 Lisp_CONCORD_DS* lds = XCONCORD_DS (obj);
83 error ("printing unreadable object #<concord_ds 0x%x>", lds->header.uid);
85 write_c_string ("#<concord_ds \"", printcharfun);
86 write_c_string (concord_ds_location (lds->ds), printcharfun);
87 write_c_string ("\">", printcharfun);
91 finalize_concord_ds (void *header, int for_disksave)
93 Lisp_CONCORD_DS *lds = (Lisp_CONCORD_DS *) header;
98 XSET_CONCORD_DS (object, lds);
101 ("Can't dump an emacs containing concord_ds objects", object);
103 if ( lds->ds != NULL)
104 concord_close_ds (lds->ds);
107 DEFINE_LRECORD_IMPLEMENTATION ("concord_ds", concord_ds,
108 mark_concord_ds, print_concord_ds,
109 finalize_concord_ds, 0, 0, 0,
112 DEFUN ("concord-close-ds", Fconcord_close_ds, 1, 1, 0, /*
113 Close concord-ds CONCORD-DS.
117 Lisp_CONCORD_DS* lds;
118 lds = XCONCORD_DS (concord_ds);
119 if ( lds->ds != NULL)
120 concord_close_ds (lds->ds);
125 DEFUN ("concord-ds-p", Fconcord_ds_p, 1, 1, 0, /*
126 Return t if OBJECT is a concord-ds.
130 return CONCORD_DS_P (object) ? Qt : Qnil;
133 DEFUN ("concord-open-ds", Fconcord_open_ds, 1, 4, 0, /*
134 Return a new concord-ds object opened on DIRECTORY.
135 Optional arguments TYPE and SUBTYPE specify the concord_ds type.
136 Optional argument MODE gives the permissions to use when opening DIRECTORY,
137 and defaults to 0755.
139 (directory, type, subtype, mode))
142 Lisp_CONCORD_DS* lds = NULL;
148 CHECK_STRING (directory);
150 directory = Ffile_name_as_directory (Fexpand_file_name (directory, Qnil));
153 retval = Fgethash (directory, Vconcord_ds_hash_table, Qunbound);
154 if (!UNBOUNDP (retval))
159 TO_EXTERNAL_FORMAT (LISP_STRING, directory,
160 C_STRING_ALLOCA, pathname,
165 modemask = 0755; /* rwxr-xr-x */
170 modemask = XINT (mode);
173 ds = concord_open_ds (CONCORD_Backend_Berkeley_DB,
174 pathname, 0, modemask);
178 lds = allocate_concord_ds ();
180 XSET_CONCORD_DS (retval, lds);
181 Fputhash (directory, retval, Vconcord_ds_hash_table);
185 DEFUN ("concord-ds-directory", Fconcord_ds_directory, 1, 1, 0, /*
186 Return directory of concord-ds DS.
190 Lisp_CONCORD_DS* lds;
193 CHECK_CONCORD_DS (ds);
194 lds = XCONCORD_DS (ds);
198 directory = concord_ds_location (lds->ds);
199 if (directory == NULL)
202 return build_ext_string (directory, Qfile_name);
206 DEFUN ("concord-assign-genre", Fconcord_assign_genre, 2, 2, 0, /*
207 Assign data-source DIRECTORY to GENRE.
213 CHECK_SYMBOL (genre);
214 if ( CONCORD_DS_P (directory) )
219 CHECK_STRING (directory);
222 = Ffile_name_as_directory (Fexpand_file_name (directory, Qnil));
225 Fputhash (genre, directory, Vconcord_genre_hash_table);
229 DEFUN ("concord-genre-directory", Fconcord_genre_directory, 1, 1, 0, /*
230 Return pathname of GENRE.
235 CHECK_SYMBOL (genre);
237 retval = Fgethash (genre, Vconcord_genre_hash_table, Qunbound);
238 if ( STRINGP (retval) )
240 else if ( CONCORD_DS_P (retval) )
241 return Fconcord_ds_directory (retval);
245 DEFUN ("concord-genre-ds", Fconcord_genre_ds, 1, 1, 0, /*
246 Return concord-ds of GENRE.
252 CHECK_SYMBOL (genre);
254 retval = Fgethash (genre, Vconcord_genre_hash_table, Qunbound);
255 if ( STRINGP (retval) )
257 retval = Fconcord_open_ds (retval, Qnil, Qnil, Qnil);
258 if ( !NILP (retval) )
259 Fputhash (genre, retval, Vconcord_genre_hash_table);
262 else if ( CONCORD_DS_P (retval) )
268 struct closure_to_list_feature
270 Lisp_Object feature_list;
271 } *concord_feature_list_closure;
274 add_feature_to_list_mapper (CONCORD_Genre genre, char* name)
276 /* This function can GC */
277 concord_feature_list_closure->feature_list
278 = Fcons (intern (name), concord_feature_list_closure->feature_list);
282 DEFUN ("concord-feature-list", Fconcord_feature_list, 1, 2, 0, /*
283 Return the list of all existing features in GENRE.
287 Lisp_CONCORD_DS* lds;
289 CONCORD_Genre c_genre;
292 CHECK_SYMBOL (genre);
294 ds = Fconcord_genre_ds (genre);
295 CHECK_CONCORD_DS (ds);
296 lds = XCONCORD_DS (ds);
299 genre = Fsymbol_name (genre);
300 TO_EXTERNAL_FORMAT (LISP_STRING, genre,
301 C_STRING_ALLOCA, genre_name,
303 c_genre = concord_ds_get_genre (lds->ds, genre_name);
306 concord_feature_list_closure
307 = alloca (sizeof (struct closure_to_list_feature));
308 concord_feature_list_closure->feature_list = Qnil;
309 GCPRO1 (concord_feature_list_closure->feature_list);
310 concord_genre_foreach_feature_name (c_genre,
311 add_feature_to_list_mapper);
313 return concord_feature_list_closure->feature_list;
317 typedef struct Lisp_CONCORD_Object Lisp_CONCORD_Object;
318 DECLARE_LRECORD (concord_object, Lisp_CONCORD_Object);
320 Lisp_Object Qconcord_objectp;
322 struct Lisp_CONCORD_Object
324 struct lcrecord_header header;
329 #define XCONCORD_OBJECT(x) XRECORD (x, concord_object, Lisp_CONCORD_Object)
330 #define XSET_CONCORD_OBJECT(x, p) XSETRECORD (x, p, concord_object)
331 #define CONCORD_OBJECT_P(x) RECORDP (x, concord_object)
332 #define CHECK_CONCORD_OBJECT(x) CHECK_RECORD (x, concord_object)
333 #define CONCHECK_CONCORD_OBJECT(x) CONCHECK_RECORD (x, concord_object)
334 #define CONCORD_OBJECT_GENRE(x) ((x)->genre)
335 #define CONCORD_OBJECT_ID(x) ((x)->id)
336 #define XCONCORD_OBJECT_ID(x) CONCORD_OBJECT_ID (XCONCORD_OBJECT(x))
337 #define XCONCORD_OBJECT_GENRE(x) CONCORD_OBJECT_GENRE (XCONCORD_OBJECT(x))
339 static Lisp_CONCORD_Object*
340 allocate_concord_object (void)
342 Lisp_CONCORD_Object* lcobj
343 = alloc_lcrecord_type (Lisp_CONCORD_Object, &lrecord_concord_object);
346 lcobj->id = Qunbound;
351 mark_concord_object (Lisp_Object object)
353 mark_object (XCONCORD_OBJECT_ID(object));
358 print_concord_object (Lisp_Object obj,
359 Lisp_Object printcharfun, int escapeflag)
361 Lisp_CONCORD_Object* lcobj = XCONCORD_OBJECT (obj);
362 struct gcpro gcpro1, gcpro2;
365 error ("printing unreadable object #<concord_object 0x%x>",
368 write_c_string ("#<concord_object \"", printcharfun);
369 write_c_string (concord_ds_location
370 (concord_genre_get_data_source (lcobj->genre)),
372 write_c_string (":", printcharfun);
373 write_c_string (concord_genre_get_name (lcobj->genre), printcharfun);
374 write_c_string (";", printcharfun);
375 GCPRO2 (obj, printcharfun);
376 print_internal (lcobj->id, printcharfun, escapeflag);
378 write_c_string ("\">", printcharfun);
382 finalize_concord_object (void *header, int for_disksave)
384 Lisp_CONCORD_Object* lcobj = (Lisp_CONCORD_Object *) header;
389 XSET_CONCORD_OBJECT (object, lcobj);
392 ("Can't dump an emacs containing concord_object objects", object);
396 static const struct lrecord_description concord_object_description[] = {
397 { XD_LISP_OBJECT, offsetof (Lisp_CONCORD_Object, id) },
401 DEFINE_LRECORD_IMPLEMENTATION ("concord_object", concord_object,
402 mark_concord_object, print_concord_object,
403 finalize_concord_object, 0, 0,
404 concord_object_description,
405 Lisp_CONCORD_Object);
407 DEFUN ("concord-make-object",
408 Fconcord_make_object, 1, 3, 0, /*
409 Make and return a Concord-object from ID and GENRE.
410 Optional argument DS specifies the data-source of the GENRE.
414 Lisp_CONCORD_DS* lds;
416 CONCORD_Genre c_genre;
417 Lisp_CONCORD_Object* lcobj;
421 ds = Fconcord_genre_ds (genre);
422 CHECK_CONCORD_DS (ds);
423 lds = XCONCORD_DS (ds);
426 if ( !STRINGP(genre) )
427 genre = Fsymbol_name (genre);
428 TO_EXTERNAL_FORMAT (LISP_STRING, genre,
429 C_STRING_ALLOCA, genre_name,
431 c_genre = concord_ds_get_genre (lds->ds, genre_name);
434 lcobj = allocate_concord_object ();
435 lcobj->genre = c_genre;
437 XSET_CONCORD_OBJECT (retval, lcobj);
441 DEFUN ("concord-object-p",
442 Fconcord_object_p, 1, 1, 0, /*
443 Return t if OBJECT is a concord-object.
447 return CONCORD_OBJECT_P (object) ? Qt : Qnil;
450 DEFUN ("concord-object-id",
451 Fconcord_object_id, 1, 1, 0, /*
452 Return an id of Concord-object OBJECT.
456 CHECK_CONCORD_OBJECT (object);
457 return XCONCORD_OBJECT_ID (object);
460 DEFUN ("concord-decode-object",
461 Fconcord_decode_object, 2, 4, 0, /*
462 Make and return a Concord-object from FEATURE and VALUE.
463 Optional argument GENRE specifies the GENRE of the object.
464 Optional argument DS specifies the data-source of the GENRE.
466 (feature, value, genre, ds))
468 Lisp_CONCORD_DS* lds;
470 CONCORD_Genre c_genre;
472 CONCORD_INDEX c_index;
473 Lisp_Object value_string;
475 CONCORD_String_Tank st_id;
478 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
481 ds = Fconcord_genre_ds (genre);
482 CHECK_CONCORD_DS (ds);
483 lds = XCONCORD_DS (ds);
486 if ( !STRINGP(feature) )
487 feature = Fsymbol_name (feature);
488 if ( !STRINGP(genre) )
489 genre = Fsymbol_name (genre);
490 TO_EXTERNAL_FORMAT (LISP_STRING, genre,
491 C_STRING_ALLOCA, genre_name,
493 c_genre = concord_ds_get_genre (lds->ds, genre_name);
499 TO_EXTERNAL_FORMAT (LISP_STRING, feature,
500 C_STRING_ALLOCA, feature_name,
502 c_index = concord_genre_get_index (c_genre, feature_name);
508 GCPRO5 (feature, value, genre, ds, value_string);
509 value_string = Fprin1_to_string (value, Qnil);
511 TO_EXTERNAL_FORMAT (LISP_STRING,
512 value_string, C_STRING_ALLOCA, strid,
514 status = concord_index_strid_get_obj_string (c_index, strid, &st_id);
517 GCPRO3 (genre, ds, obj);
519 obj = read_from_c_string (CONCORD_String_data (&st_id),
520 CONCORD_String_size (&st_id) );
522 obj = Fcar (Fread_from_string (make_ext_string
523 ((char*)CONCORD_String_data (&st_id),
524 CONCORD_String_size (&st_id),
529 return Fconcord_make_object (obj, genre, ds);
534 DEFUN ("concord-object-get",
535 Fconcord_object_get, 2, 2, 0, /*
536 Return the value of OBJECT's FEATURE.
540 struct gcpro gcpro1, gcpro2;
541 Lisp_Object obj_string;
543 CONCORD_Genre c_genre;
545 CONCORD_Feature c_feature;
547 CONCORD_String_Tank st_value;
549 CHECK_CONCORD_OBJECT (object);
550 if ( !STRINGP(feature) )
551 feature = Fsymbol_name (feature);
552 GCPRO2 (object, feature);
553 obj_string = Fprin1_to_string (XCONCORD_OBJECT_ID(object), Qnil);
555 TO_EXTERNAL_FORMAT (LISP_STRING, obj_string,
556 C_STRING_ALLOCA, c_obj, Qfile_name);
557 c_genre = XCONCORD_OBJECT_GENRE(object);
558 TO_EXTERNAL_FORMAT (LISP_STRING, feature,
559 C_STRING_ALLOCA, feature_name,
561 c_feature = concord_genre_get_feature (c_genre, feature_name);
562 if (c_feature == NULL)
566 status = concord_obj_get_feature_value_string (c_obj, c_feature,
571 Fcar (Fread_from_string (make_ext_string
572 ((char*)CONCORD_String_data (&st_value),
573 CONCORD_String_size (&st_value),
580 DEFUN ("concord-object-put",
581 Fconcord_object_put, 3, 3, 0, /*
582 Store a VALUE of OBJECT's FEATURE.
584 (object, feature, value))
586 struct gcpro gcpro1, gcpro2, gcpro3;
587 Lisp_Object obj_string;
589 CONCORD_Genre c_genre;
591 CONCORD_Feature c_feature;
593 Lisp_Object value_string;
596 CHECK_CONCORD_OBJECT (object);
597 if ( !STRINGP(feature) )
598 feature = Fsymbol_name (feature);
599 GCPRO3 (object, feature, value);
600 obj_string = Fprin1_to_string (XCONCORD_OBJECT_ID(object), Qnil);
602 TO_EXTERNAL_FORMAT (LISP_STRING, obj_string,
603 C_STRING_ALLOCA, c_obj, Qfile_name);
604 c_genre = XCONCORD_OBJECT_GENRE(object);
605 TO_EXTERNAL_FORMAT (LISP_STRING, feature,
606 C_STRING_ALLOCA, feature_name,
608 c_feature = concord_genre_get_feature (c_genre, feature_name);
609 if (c_feature == NULL)
613 GCPRO3 (object, feature, value);
614 value_string = Fprin1_to_string (value, Qnil);
616 TO_EXTERNAL_FORMAT (LISP_STRING, value_string,
617 C_STRING_ALLOCA, c_value,
619 status = concord_obj_put_feature_value_str (c_obj, c_feature,
620 (unsigned char*)c_value);
623 status = chise_feature_sync (c_feature);
629 struct closure_for_object_spec
633 } *concord_object_spec_closure;
636 add_feature_to_spec_mapper (CONCORD_Genre genre, char* name)
638 /* This function can GC */
639 CONCORD_String_Tank st_value;
640 CONCORD_Feature c_feature;
643 c_feature = concord_genre_get_feature (genre, name);
644 if (c_feature == NULL)
648 concord_obj_get_feature_value_string
649 (concord_object_spec_closure->object_id, c_feature, &st_value);
652 concord_object_spec_closure->spec
653 = Fcons (Fcons (intern (name),
654 Fcar (Fread_from_string
656 ((char*)CONCORD_String_data (&st_value),
657 CONCORD_String_size (&st_value),
660 concord_object_spec_closure->spec);
665 DEFUN ("concord-object-spec", Fconcord_object_spec, 1, 1, 0, /*
666 Return the spec of OBJECT.
670 Lisp_Object obj_string;
672 CONCORD_Genre c_genre;
673 struct gcpro gcpro1, gcpro2;
675 CHECK_CONCORD_OBJECT (object);
677 obj_string = Fprin1_to_string (XCONCORD_OBJECT_ID(object), Qnil);
679 TO_EXTERNAL_FORMAT (LISP_STRING, obj_string,
680 C_STRING_ALLOCA, c_obj, Qfile_name);
681 c_genre = XCONCORD_OBJECT_GENRE(object);
682 concord_object_spec_closure
683 = alloca (sizeof (struct closure_for_object_spec));
684 concord_object_spec_closure->object_id = c_obj;
685 concord_object_spec_closure->spec = Qnil;
686 GCPRO2 (object, concord_object_spec_closure->spec);
687 concord_genre_foreach_feature_name (c_genre,
688 add_feature_to_spec_mapper);
690 return concord_object_spec_closure->spec;
693 struct closure_for_each_object
695 Lisp_Object function;
699 } *for_each_object_closure;
702 func_for_each_object (CONCORD_String object_id,
703 CONCORD_Feature feature,
704 CONCORD_String value)
706 Lisp_Object obj, val, ret;
709 obj = read_from_c_string (CONCORD_String_data (object_id),
710 CONCORD_String_size (object_id) );
712 obj = Fcar (Fread_from_string (make_ext_string
713 ((char*)CONCORD_String_data (object_id),
714 CONCORD_String_size (object_id),
718 obj = Fconcord_make_object (obj,
719 for_each_object_closure->genre,
720 for_each_object_closure->ds);
722 val = read_from_c_string (CONCORD_String_data (value),
723 CONCORD_String_size (value) );
725 val = Fcar (Fread_from_string (make_ext_string
726 ((char*)CONCORD_String_data (value),
727 CONCORD_String_size (value),
731 ret = call2 (for_each_object_closure->function, obj, val);
732 for_each_object_closure->ret = ret;
736 DEFUN ("concord-for-each-object-in-feature",
737 Fconcord_foreach_object_in_feature, 2, 4, 0, /*
738 Do FUNCTION over objects in FEATURE, calling it with two args,
739 each key and value in the FEATURE table.
740 Optional argument GENRE specifies the genre of the FEATURE.
741 When the FUNCTION returns non-nil, it breaks the repeat.
743 (function, feature, genre, ds))
745 Lisp_CONCORD_DS* lds;
747 CONCORD_Genre c_genre;
749 CONCORD_Feature c_feature;
752 ds = Fconcord_genre_ds (genre);
753 CHECK_CONCORD_DS (ds);
754 lds = XCONCORD_DS (ds);
757 if ( !STRINGP(feature) )
758 feature = Fsymbol_name (feature);
759 if ( !STRINGP(genre) )
760 genre = Fsymbol_name (genre);
761 TO_EXTERNAL_FORMAT (LISP_STRING, genre,
762 C_STRING_ALLOCA, genre_name,
764 c_genre = concord_ds_get_genre (lds->ds, genre_name);
768 CHECK_STRING (feature);
769 TO_EXTERNAL_FORMAT (LISP_STRING, feature,
770 C_STRING_ALLOCA, feature_name,
772 c_feature = concord_genre_get_feature (c_genre, feature_name);
773 if (c_feature == NULL)
775 for_each_object_closure
776 = alloca (sizeof (struct closure_for_each_object));
777 for_each_object_closure->function = function;
778 for_each_object_closure->genre = genre;
779 for_each_object_closure->ds = ds;
780 for_each_object_closure->ret = Qnil;
781 concord_feature_foreach_obj_string (c_feature, func_for_each_object);
783 return for_each_object_closure->ret;
788 concord_name_validate (Lisp_Object keyword, Lisp_Object value,
791 if (ERRB_EQ (errb, ERROR_ME))
793 CHECK_SYMBOL (value);
797 return SYMBOLP (value);
801 concord_object_validate (Lisp_Object data, Error_behavior errb)
803 Lisp_Object valw = Qnil;
804 Lisp_Object genre = Qnil;
805 Lisp_Object oid = Qnil;
807 data = Fcdr (data); /* skip over Qconcord_object */
810 Lisp_Object keyw = Fcar (data);
815 if (EQ (keyw, Qgenre))
817 else if (EQ (keyw, Q_id))
825 maybe_error (Qconcord_object, errb, "No genre given");
830 maybe_error (Qconcord_object, errb, "No object-id given");
834 if (NILP (Fconcord_make_object (oid, genre, Qnil)))
836 maybe_signal_simple_error_2 ("No such Concord-object",
837 oid, genre, Qconcord_object, errb);
845 concord_object_instantiate (Lisp_Object data)
847 return Fconcord_make_object (Fplist_get (data, Q_id, Qnil),
848 Fplist_get (data, Qgenre, Qnil),
854 syms_of_concord (void)
856 INIT_LRECORD_IMPLEMENTATION (concord_ds);
857 INIT_LRECORD_IMPLEMENTATION (concord_object);
859 defsymbol (&Qconcord, "concord");
860 defsymbol (&Qconcord_dsp, "concord-dsp");
861 defsymbol (&Qconcord_objectp, "concord-objectp");
862 defsymbol (&Qconcord_object, "concord-object");
863 defsymbol (&Qgenre, "genre");
864 defsymbol (&Q_id, "=id");
866 DEFSUBR (Fconcord_open_ds);
867 DEFSUBR (Fconcord_ds_p);
868 DEFSUBR (Fconcord_close_ds);
869 DEFSUBR (Fconcord_ds_directory);
871 DEFSUBR (Fconcord_assign_genre);
872 DEFSUBR (Fconcord_genre_directory);
873 DEFSUBR (Fconcord_genre_ds);
874 DEFSUBR (Fconcord_feature_list);
876 DEFSUBR (Fconcord_make_object);
877 DEFSUBR (Fconcord_object_p);
878 DEFSUBR (Fconcord_object_id);
879 DEFSUBR (Fconcord_decode_object);
880 DEFSUBR (Fconcord_object_get);
881 DEFSUBR (Fconcord_object_put);
882 DEFSUBR (Fconcord_object_spec);
883 DEFSUBR (Fconcord_foreach_object_in_feature);
887 structure_type_create_concord (void)
889 struct structure_type *st;
891 st = define_structure_type (Qconcord_object,
892 concord_object_validate,
893 concord_object_instantiate);
895 define_structure_type_keyword (st, Qgenre, concord_name_validate);
896 define_structure_type_keyword (st, Q_id, concord_name_validate);
900 vars_of_concord (void)
904 staticpro (&Vconcord_ds_hash_table);
905 Vconcord_ds_hash_table
906 = make_lisp_hash_table (8, HASH_TABLE_NON_WEAK, HASH_TABLE_EQUAL);
908 staticpro (&Vconcord_genre_hash_table);
909 Vconcord_genre_hash_table
910 = make_lisp_hash_table (16, HASH_TABLE_NON_WEAK, HASH_TABLE_EQ);