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);
39 Lisp_Object Vconcord_ds_hash_table;
40 Lisp_Object Vconcord_genre_hash_table;
43 typedef struct Lisp_CONCORD_DS Lisp_CONCORD_DS;
44 DECLARE_LRECORD (concord_ds, Lisp_CONCORD_DS);
46 Lisp_Object Qconcord_dsp;
48 struct Lisp_CONCORD_DS
50 struct lcrecord_header header;
54 #define XCONCORD_DS(x) XRECORD (x, concord_ds, Lisp_CONCORD_DS)
55 #define XSET_CONCORD_DS(x, p) XSETRECORD (x, p, concord_ds)
56 #define CONCORD_DS_P(x) RECORDP (x, concord_ds)
57 #define CHECK_CONCORD_DS(x) CHECK_RECORD (x, concord_ds)
58 #define CONCHECK_CONCORD_DS(x) CONCHECK_RECORD (x, concord_ds)
60 static Lisp_CONCORD_DS*
61 allocate_concord_ds (void)
64 = alloc_lcrecord_type (Lisp_CONCORD_DS, &lrecord_concord_ds);
71 mark_concord_ds (Lisp_Object object)
77 print_concord_ds (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
79 Lisp_CONCORD_DS* lds = XCONCORD_DS (obj);
82 error ("printing unreadable object #<concord_ds 0x%x>", lds->header.uid);
84 write_c_string ("#<concord_ds \"", printcharfun);
85 write_c_string (concord_ds_location (lds->ds), printcharfun);
86 write_c_string ("\">", printcharfun);
90 finalize_concord_ds (void *header, int for_disksave)
92 Lisp_CONCORD_DS *lds = (Lisp_CONCORD_DS *) header;
97 XSET_CONCORD_DS (object, lds);
100 ("Can't dump an emacs containing concord_ds objects", object);
102 if ( lds->ds != NULL)
103 concord_close_ds (lds->ds);
106 DEFINE_LRECORD_IMPLEMENTATION ("concord_ds", concord_ds,
107 mark_concord_ds, print_concord_ds,
108 finalize_concord_ds, 0, 0, 0,
111 DEFUN ("concord-close-ds", Fconcord_close_ds, 1, 1, 0, /*
112 Close concord-ds CONCORD-DS.
116 Lisp_CONCORD_DS* lds;
117 lds = XCONCORD_DS (concord_ds);
118 if ( lds->ds != NULL)
119 concord_close_ds (lds->ds);
124 DEFUN ("concord-ds-p", Fconcord_ds_p, 1, 1, 0, /*
125 Return t if OBJECT is a concord-ds.
129 return CONCORD_DS_P (object) ? Qt : Qnil;
132 DEFUN ("concord-open-ds", Fconcord_open_ds, 1, 4, 0, /*
133 Return a new concord-ds object opened on DIRECTORY.
134 Optional arguments TYPE and SUBTYPE specify the concord_ds type.
135 Optional argument MODE gives the permissions to use when opening DIRECTORY,
136 and defaults to 0755.
138 (directory, type, subtype, mode))
141 Lisp_CONCORD_DS* lds = NULL;
147 CHECK_STRING (directory);
149 directory = Ffile_name_as_directory (Fexpand_file_name (directory, Qnil));
152 retval = Fgethash (directory, Vconcord_ds_hash_table, Qunbound);
153 if (!UNBOUNDP (retval))
158 TO_EXTERNAL_FORMAT (LISP_STRING, directory,
159 C_STRING_ALLOCA, pathname,
164 modemask = 0755; /* rwxr-xr-x */
169 modemask = XINT (mode);
172 ds = concord_open_ds (CONCORD_Backend_Berkeley_DB,
173 pathname, 0, modemask);
177 lds = allocate_concord_ds ();
179 XSET_CONCORD_DS (retval, lds);
180 Fputhash (directory, retval, Vconcord_ds_hash_table);
184 DEFUN ("concord-ds-directory", Fconcord_ds_directory, 1, 1, 0, /*
185 Return directory of concord-ds DS.
189 Lisp_CONCORD_DS* lds;
190 unsigned char* directory;
192 CHECK_CONCORD_DS (ds);
193 lds = XCONCORD_DS (ds);
197 directory = concord_ds_location (lds->ds);
198 if (directory == NULL)
201 return build_ext_string (directory, Qfile_name);
205 DEFUN ("concord-assign-genre", Fconcord_assign_genre, 2, 2, 0, /*
206 Assign data-source DIRECTORY to GENRE.
212 CHECK_SYMBOL (genre);
213 if ( CONCORD_DS_P (directory) )
218 CHECK_STRING (directory);
221 = Ffile_name_as_directory (Fexpand_file_name (directory, Qnil));
224 Fputhash (genre, directory, Vconcord_genre_hash_table);
228 DEFUN ("concord-genre-directory", Fconcord_genre_directory, 1, 1, 0, /*
229 Return pathname of GENRE.
234 CHECK_SYMBOL (genre);
236 retval = Fgethash (genre, Vconcord_genre_hash_table, Qunbound);
237 if ( STRINGP (retval) )
239 else if ( CONCORD_DS_P (retval) )
240 return Fconcord_ds_directory (retval);
244 DEFUN ("concord-genre-ds", Fconcord_genre_ds, 1, 1, 0, /*
245 Return concord-ds of GENRE.
251 CHECK_SYMBOL (genre);
253 retval = Fgethash (genre, Vconcord_genre_hash_table, Qunbound);
254 if ( STRINGP (retval) )
256 retval = Fconcord_open_ds (retval, Qnil, Qnil, Qnil);
257 if ( !NILP (retval) )
258 Fputhash (genre, retval, Vconcord_genre_hash_table);
261 else if ( CONCORD_DS_P (retval) )
267 struct closure_to_list_feature
269 Lisp_Object feature_list;
270 } *concord_feature_list_closure;
273 add_feature_to_list_mapper (CONCORD_Genre genre, unsigned char* name)
275 /* This function can GC */
276 concord_feature_list_closure->feature_list
277 = Fcons (intern (name), concord_feature_list_closure->feature_list);
281 DEFUN ("concord-feature-list", Fconcord_feature_list, 1, 2, 0, /*
282 Return the list of all existing features in GENRE.
286 Lisp_CONCORD_DS* lds;
287 unsigned char* genre_name;
288 CONCORD_Genre c_genre;
291 CHECK_SYMBOL (genre);
293 ds = Fconcord_genre_ds (genre);
294 CHECK_CONCORD_DS (ds);
295 lds = XCONCORD_DS (ds);
298 genre = Fsymbol_name (genre);
299 TO_EXTERNAL_FORMAT (LISP_STRING, genre,
300 C_STRING_ALLOCA, genre_name,
302 c_genre = concord_ds_get_genre (lds->ds, genre_name);
305 concord_feature_list_closure
306 = alloca (sizeof (struct closure_to_list_feature));
307 concord_feature_list_closure->feature_list = Qnil;
308 GCPRO1 (concord_feature_list_closure->feature_list);
309 concord_genre_foreach_feature_name (c_genre,
310 add_feature_to_list_mapper);
312 return concord_feature_list_closure->feature_list;
316 typedef struct Lisp_CONCORD_Object Lisp_CONCORD_Object;
317 DECLARE_LRECORD (concord_object, Lisp_CONCORD_Object);
319 Lisp_Object Qconcord_objectp;
321 struct Lisp_CONCORD_Object
323 struct lcrecord_header header;
328 #define XCONCORD_OBJECT(x) XRECORD (x, concord_object, Lisp_CONCORD_Object)
329 #define XSET_CONCORD_OBJECT(x, p) XSETRECORD (x, p, concord_object)
330 #define CONCORD_OBJECT_P(x) RECORDP (x, concord_object)
331 #define CHECK_CONCORD_OBJECT(x) CHECK_RECORD (x, concord_object)
332 #define CONCHECK_CONCORD_OBJECT(x) CONCHECK_RECORD (x, concord_object)
333 #define CONCORD_OBJECT_GENRE(x) ((x)->genre)
334 #define CONCORD_OBJECT_ID(x) ((x)->id)
335 #define XCONCORD_OBJECT_ID(x) CONCORD_OBJECT_ID (XCONCORD_OBJECT(x))
336 #define XCONCORD_OBJECT_GENRE(x) CONCORD_OBJECT_GENRE (XCONCORD_OBJECT(x))
338 static Lisp_CONCORD_Object*
339 allocate_concord_object (void)
341 Lisp_CONCORD_Object* lcobj
342 = alloc_lcrecord_type (Lisp_CONCORD_Object, &lrecord_concord_object);
345 lcobj->id = Qunbound;
350 mark_concord_object (Lisp_Object object)
352 mark_object (XCONCORD_OBJECT_ID(object));
357 print_concord_object (Lisp_Object obj,
358 Lisp_Object printcharfun, int escapeflag)
360 Lisp_CONCORD_Object* lcobj = XCONCORD_OBJECT (obj);
361 struct gcpro gcpro1, gcpro2;
364 error ("printing unreadable object #<concord_object 0x%x>",
367 write_c_string ("#<concord_object \"", printcharfun);
368 write_c_string (concord_ds_location
369 (concord_genre_get_data_source (lcobj->genre)),
371 write_c_string (":", printcharfun);
372 write_c_string (concord_genre_get_name (lcobj->genre), printcharfun);
373 write_c_string (";", printcharfun);
374 GCPRO2 (obj, printcharfun);
375 print_internal (lcobj->id, printcharfun, escapeflag);
377 write_c_string ("\">", printcharfun);
381 finalize_concord_object (void *header, int for_disksave)
383 Lisp_CONCORD_Object* lcobj = (Lisp_CONCORD_Object *) header;
388 XSET_CONCORD_OBJECT (object, lcobj);
391 ("Can't dump an emacs containing concord_object objects", object);
395 static const struct lrecord_description concord_object_description[] = {
396 { XD_LISP_OBJECT, offsetof (Lisp_CONCORD_Object, id) },
400 DEFINE_LRECORD_IMPLEMENTATION ("concord_object", concord_object,
401 mark_concord_object, print_concord_object,
402 finalize_concord_object, 0, 0,
403 concord_object_description,
404 Lisp_CONCORD_Object);
406 DEFUN ("concord-make-object",
407 Fconcord_make_object, 1, 3, 0, /*
408 Make and return a Concord-object from ID and GENRE.
409 Optional argument DS specifies the data-source of the GENRE.
413 Lisp_CONCORD_DS* lds;
414 unsigned char* genre_name;
415 CONCORD_Genre c_genre;
416 Lisp_CONCORD_Object* lcobj;
420 ds = Fconcord_genre_ds (genre);
421 CHECK_CONCORD_DS (ds);
422 lds = XCONCORD_DS (ds);
425 if ( !STRINGP(genre) )
426 genre = Fsymbol_name (genre);
427 TO_EXTERNAL_FORMAT (LISP_STRING, genre,
428 C_STRING_ALLOCA, genre_name,
430 c_genre = concord_ds_get_genre (lds->ds, genre_name);
433 lcobj = allocate_concord_object ();
434 lcobj->genre = c_genre;
436 XSET_CONCORD_OBJECT (retval, lcobj);
440 DEFUN ("concord-object-p",
441 Fconcord_object_p, 1, 1, 0, /*
442 Return t if OBJECT is a concord-object.
446 return CONCORD_OBJECT_P (object) ? Qt : Qnil;
449 DEFUN ("concord-object-id",
450 Fconcord_object_id, 1, 1, 0, /*
451 Return an id of Concord-object OBJECT.
455 CHECK_CONCORD_OBJECT (object);
456 return XCONCORD_OBJECT_ID (object);
459 DEFUN ("concord-decode-object",
460 Fconcord_decode_object, 2, 4, 0, /*
461 Make and return a Concord-object from FEATURE and VALUE.
462 Optional argument GENRE specifies the GENRE of the object.
463 Optional argument DS specifies the data-source of the GENRE.
465 (feature, value, genre, ds))
467 Lisp_CONCORD_DS* lds;
468 unsigned char* genre_name;
469 CONCORD_Genre c_genre;
470 unsigned char* feature_name;
471 CONCORD_INDEX c_index;
472 Lisp_Object value_string;
473 unsigned char* strid;
474 CONCORD_String_Tank st_id;
477 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
480 ds = Fconcord_genre_ds (genre);
481 CHECK_CONCORD_DS (ds);
482 lds = XCONCORD_DS (ds);
485 if ( !STRINGP(feature) )
486 feature = Fsymbol_name (feature);
487 if ( !STRINGP(genre) )
488 genre = Fsymbol_name (genre);
489 TO_EXTERNAL_FORMAT (LISP_STRING, genre,
490 C_STRING_ALLOCA, genre_name,
492 c_genre = concord_ds_get_genre (lds->ds, genre_name);
498 TO_EXTERNAL_FORMAT (LISP_STRING, feature,
499 C_STRING_ALLOCA, feature_name,
501 c_index = concord_genre_get_index (c_genre, feature_name);
507 GCPRO5 (feature, value, genre, ds, value_string);
508 value_string = Fprin1_to_string (value, Qnil);
510 TO_EXTERNAL_FORMAT (LISP_STRING,
511 value_string, C_STRING_ALLOCA, strid,
513 status = concord_index_strid_get_obj_string (c_index, strid, &st_id);
516 GCPRO3 (genre, ds, obj);
518 obj = read_from_c_string (CONCORD_String_data (&st_id),
519 CONCORD_String_size (&st_id) );
521 obj = Fcar (Fread_from_string (make_ext_string
522 (CONCORD_String_data (&st_id),
523 CONCORD_String_size (&st_id),
528 return Fconcord_make_object (obj, genre, ds);
533 DEFUN ("concord-object-get",
534 Fconcord_object_get, 2, 2, 0, /*
535 Return the value of OBJECT's FEATURE.
539 struct gcpro gcpro1, gcpro2;
540 Lisp_Object obj_string;
541 unsigned char* c_obj;
542 CONCORD_Genre c_genre;
543 unsigned char* feature_name;
544 CONCORD_Feature c_feature;
546 CONCORD_String_Tank st_value;
548 CHECK_CONCORD_OBJECT (object);
549 if ( !STRINGP(feature) )
550 feature = Fsymbol_name (feature);
551 GCPRO2 (object, feature);
552 obj_string = Fprin1_to_string (XCONCORD_OBJECT_ID(object), Qnil);
554 TO_EXTERNAL_FORMAT (LISP_STRING, obj_string,
555 C_STRING_ALLOCA, c_obj, Qfile_name);
556 c_genre = XCONCORD_OBJECT_GENRE(object);
557 TO_EXTERNAL_FORMAT (LISP_STRING, feature,
558 C_STRING_ALLOCA, feature_name,
560 c_feature = concord_genre_get_feature (c_genre, feature_name);
561 if (c_feature == NULL)
565 status = concord_obj_get_feature_value_string (c_obj, c_feature,
570 Fcar (Fread_from_string (make_ext_string
571 (CONCORD_String_data (&st_value),
572 CONCORD_String_size (&st_value),
579 DEFUN ("concord-object-put",
580 Fconcord_object_put, 3, 3, 0, /*
581 Store a VALUE of OBJECT's FEATURE.
583 (object, feature, value))
585 struct gcpro gcpro1, gcpro2, gcpro3;
586 Lisp_Object obj_string;
587 unsigned char* c_obj;
588 CONCORD_Genre c_genre;
589 unsigned char* feature_name;
590 CONCORD_Feature c_feature;
592 Lisp_Object value_string;
593 unsigned char* c_value;
595 CHECK_CONCORD_OBJECT (object);
596 if ( !STRINGP(feature) )
597 feature = Fsymbol_name (feature);
598 GCPRO3 (object, feature, value);
599 obj_string = Fprin1_to_string (XCONCORD_OBJECT_ID(object), Qnil);
601 TO_EXTERNAL_FORMAT (LISP_STRING, obj_string,
602 C_STRING_ALLOCA, c_obj, Qfile_name);
603 c_genre = XCONCORD_OBJECT_GENRE(object);
604 TO_EXTERNAL_FORMAT (LISP_STRING, feature,
605 C_STRING_ALLOCA, feature_name,
607 c_feature = concord_genre_get_feature (c_genre, feature_name);
608 if (c_feature == NULL)
612 GCPRO3 (object, feature, value);
613 value_string = Fprin1_to_string (value, Qnil);
615 TO_EXTERNAL_FORMAT (LISP_STRING, value_string,
616 C_STRING_ALLOCA, c_value,
618 status = concord_obj_put_feature_value_str (c_obj, c_feature, c_value);
621 status = chise_feature_sync (c_feature);
627 struct closure_for_object_spec
629 unsigned char* object_id;
631 } *concord_object_spec_closure;
634 add_feature_to_spec_mapper (CONCORD_Genre genre, unsigned char* name)
636 /* This function can GC */
637 CONCORD_String_Tank st_value;
638 CONCORD_Feature c_feature;
641 c_feature = concord_genre_get_feature (genre, name);
642 if (c_feature == NULL)
646 concord_obj_get_feature_value_string
647 (concord_object_spec_closure->object_id, c_feature, &st_value);
650 concord_object_spec_closure->spec
651 = Fcons (Fcons (intern (name),
652 Fcar (Fread_from_string
654 (CONCORD_String_data (&st_value),
655 CONCORD_String_size (&st_value),
658 concord_object_spec_closure->spec);
663 DEFUN ("concord-object-spec", Fconcord_object_spec, 1, 1, 0, /*
664 Return the spec of OBJECT.
668 Lisp_Object obj_string;
669 unsigned char* c_obj;
670 CONCORD_Genre c_genre;
671 struct gcpro gcpro1, gcpro2;
673 CHECK_CONCORD_OBJECT (object);
675 obj_string = Fprin1_to_string (XCONCORD_OBJECT_ID(object), Qnil);
677 TO_EXTERNAL_FORMAT (LISP_STRING, obj_string,
678 C_STRING_ALLOCA, c_obj, Qfile_name);
679 c_genre = XCONCORD_OBJECT_GENRE(object);
680 concord_object_spec_closure
681 = alloca (sizeof (struct closure_for_object_spec));
682 concord_object_spec_closure->object_id = c_obj;
683 concord_object_spec_closure->spec = Qnil;
684 GCPRO2 (object, concord_object_spec_closure->spec);
685 concord_genre_foreach_feature_name (c_genre,
686 add_feature_to_spec_mapper);
688 return concord_object_spec_closure->spec;
691 struct closure_for_each_object
693 Lisp_Object function;
697 } *for_each_object_closure;
700 func_for_each_object (CONCORD_String object_id,
701 CONCORD_Feature feature,
702 CONCORD_String value)
704 Lisp_Object obj, val, ret;
707 obj = read_from_c_string (CONCORD_String_data (object_id),
708 CONCORD_String_size (object_id) );
710 obj = Fcar (Fread_from_string (make_ext_string
711 (CONCORD_String_data (object_id),
712 CONCORD_String_size (object_id),
716 obj = Fconcord_make_object (obj,
717 for_each_object_closure->genre,
718 for_each_object_closure->ds);
720 val = read_from_c_string (CONCORD_String_data (value),
721 CONCORD_String_size (value) );
723 val = Fcar (Fread_from_string (make_ext_string
724 (CONCORD_String_data (value),
725 CONCORD_String_size (value),
729 ret = call2 (for_each_object_closure->function, obj, val);
730 for_each_object_closure->ret = ret;
734 DEFUN ("concord-for-each-object-in-feature",
735 Fconcord_foreach_object_in_feature, 2, 4, 0, /*
736 Do FUNCTION over objects in FEATURE, calling it with two args,
737 each key and value in the FEATURE table.
738 Optional argument GENRE specifies the genre of the FEATURE.
739 When the FUNCTION returns non-nil, it breaks the repeat.
741 (function, feature, genre, ds))
743 Lisp_CONCORD_DS* lds;
744 unsigned char* genre_name;
745 CONCORD_Genre c_genre;
746 unsigned char* feature_name;
747 CONCORD_Feature c_feature;
750 ds = Fconcord_genre_ds (genre);
751 CHECK_CONCORD_DS (ds);
752 lds = XCONCORD_DS (ds);
755 if ( !STRINGP(feature) )
756 feature = Fsymbol_name (feature);
757 if ( !STRINGP(genre) )
758 genre = Fsymbol_name (genre);
759 TO_EXTERNAL_FORMAT (LISP_STRING, genre,
760 C_STRING_ALLOCA, genre_name,
762 c_genre = concord_ds_get_genre (lds->ds, genre_name);
766 CHECK_STRING (feature);
767 TO_EXTERNAL_FORMAT (LISP_STRING, feature,
768 C_STRING_ALLOCA, feature_name,
770 c_feature = concord_genre_get_feature (c_genre, feature_name);
771 if (c_feature == NULL)
773 for_each_object_closure
774 = alloca (sizeof (struct closure_for_each_object));
775 for_each_object_closure->function = function;
776 for_each_object_closure->genre = genre;
777 for_each_object_closure->ds = ds;
778 for_each_object_closure->ret = Qnil;
779 concord_feature_foreach_obj_string (c_feature, func_for_each_object);
781 return for_each_object_closure->ret;
785 syms_of_concord (void)
787 INIT_LRECORD_IMPLEMENTATION (concord_ds);
788 INIT_LRECORD_IMPLEMENTATION (concord_object);
790 defsymbol (&Qconcord, "concord");
791 defsymbol (&Qconcord_dsp, "concord-dsp");
792 defsymbol (&Qconcord_objectp, "concord-objectp");
794 DEFSUBR (Fconcord_open_ds);
795 DEFSUBR (Fconcord_ds_p);
796 DEFSUBR (Fconcord_close_ds);
797 DEFSUBR (Fconcord_ds_directory);
799 DEFSUBR (Fconcord_assign_genre);
800 DEFSUBR (Fconcord_genre_directory);
801 DEFSUBR (Fconcord_genre_ds);
802 DEFSUBR (Fconcord_feature_list);
804 DEFSUBR (Fconcord_make_object);
805 DEFSUBR (Fconcord_object_p);
806 DEFSUBR (Fconcord_object_id);
807 DEFSUBR (Fconcord_decode_object);
808 DEFSUBR (Fconcord_object_get);
809 DEFSUBR (Fconcord_object_put);
810 DEFSUBR (Fconcord_object_spec);
811 DEFSUBR (Fconcord_foreach_object_in_feature);
815 vars_of_concord (void)
819 staticpro (&Vconcord_ds_hash_table);
820 Vconcord_ds_hash_table
821 = make_lisp_hash_table (8, HASH_TABLE_NON_WEAK, HASH_TABLE_EQUAL);
823 staticpro (&Vconcord_genre_hash_table);
824 Vconcord_genre_hash_table
825 = make_lisp_hash_table (16, HASH_TABLE_NON_WEAK, HASH_TABLE_EQ);