1/* BEGIN LICENSE BLOCK 2 * Version: CMPL 1.1 3 * 4 * The contents of this file are subject to the Cisco-style Mozilla Public 5 * License Version 1.1 (the "License"); you may not use this file except 6 * in compliance with the License. You may obtain a copy of the License 7 * at www.eclipse-clp.org/license. 8 * 9 * Software distributed under the License is distributed on an "AS IS" 10 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 11 * the License for the specific language governing rights and limitations 12 * under the License. 13 * 14 * The Original Code is The ECLiPSe Constraint Logic Programming System. 15 * The Initial Developer of the Original Code is Cisco Systems, Inc. 16 * Portions created by the Initial Developer are 17 * Copyright (C) 1989-2007 Cisco Systems, Inc. All Rights Reserved. 18 * 19 * Contributor(s): 20 * 21 * END LICENSE BLOCK */ 22 23/* 24 * VERSION $Id: bip_record.c,v 1.3 2012/02/12 02:16:13 jschimpf Exp $ 25 */ 26 27/* ******************************************************************** 28 * 29 * ECLiPSe built-ins for the indexed database 30 * 31 ******************************************************************** */ 32 33#include "config.h" 34#include "sepia.h" 35#include "types.h" 36#include "embed.h" 37#include "mem.h" 38#include "error.h" 39#include "dict.h" 40#include "property.h" 41#include "module.h" 42 43 44#include <stdio.h> /* for sprintf() */ 45 46 47static dident d_visible_; 48 49 50 51/*---------------------------------------------------------------------- 52 * Recorded database primitives 53 * 54 * Data structure is a circular doubly linked list with one dummy 55 * element as header. The header is referred to by the IDB_PROP 56 * property (but could also be passed around as a handle of type 57 * heap_rec_header_tid). 58 * 59 * Individual recorded iterms are identified by their list element 60 * and handles of type heap_rec_tid are used as "db references". 61 * They are always created as part of a record-list, but can continue 62 * to exist independently when their db-reference was obtained and 63 * they were subsequently erased from the list. 64 *----------------------------------------------------------------------*/ 65 66 67/* INSTANCE TYPE DECLARATION */ 68 69typedef struct record_elem { 70 uword ref_ctr; /* one count for list membership */ 71 struct record_elem *next, *prev; /* NULL if not in list */ 72 uword hash; 73 pword term; /* TEND for header cell */ 74} t_heap_rec; 75 76 77/* METHODS */ 78 79 80/* Allocation of both header and proper elements */ 81 82static t_heap_rec * 83_rec_create(void) 84{ 85 t_heap_rec *obj = (t_heap_rec *) hg_alloc_size(sizeof(t_heap_rec)); 86 obj->ref_ctr = 1; 87 obj->next = obj->prev = obj; 88 obj->term.val.nint = 0; 89 obj->term.tag.kernel = TEND; /* remains TEND for header cells */ 90 return obj; 91} 92 93 94t_ext_ptr 95ec_record_create(void) 96{ 97 return (t_ext_ptr) _rec_create(); 98} 99 100 101/* Lose a reference to an element */ 102 103static void 104_rec_free_elem(t_heap_rec *this) 105{ 106 if (--this->ref_ctr <= 0) 107 { 108 if (this->term.tag.kernel == TEND) 109 ec_panic("Trying to free record list header", "_rec_free_elem()"); 110 111#ifdef DEBUG_RECORDS 112 p_fprintf(current_err_, "\n_rec_free_elem(0x%x)", this); 113 ec_flush(current_err_); 114#endif 115 free_heapterm(&this->term); 116 hg_free_size((generic_ptr) this, sizeof(t_heap_rec)); 117 } 118} 119 120 121/* Remove and lose all elements from header's list (but note that the 122 * elements may survive if db-references to them still exist) */ 123 124static void 125_rec_free_elems(t_heap_rec *header) 126{ 127 t_heap_rec *this = header->next; 128 if (header->term.tag.kernel != TEND) 129 ec_panic("Not a record list header", "_rec_free_all()"); 130 131 while (this != header) 132 { 133 t_heap_rec *next = this->next; 134 this->prev = this->next = 0; 135 _rec_free_elem(this); 136 this = next; 137 } 138 header->next = header->prev = header; 139} 140 141 142/* Lose a reference to the whole list identified by header */ 143 144static void 145_rec_free_all(t_heap_rec *header) 146{ 147 if (--header->ref_ctr <= 0) 148 { 149#ifdef DEBUG_RECORDS 150 p_fprintf(current_err_, "\n_rec_free_all(0x%x)", header); 151 ec_flush(current_err_); 152#endif 153 _rec_free_elems(header); 154 hg_free_size((generic_ptr) header, sizeof(t_heap_rec)); 155 } 156} 157 158 159static t_heap_rec * 160_rec_copy_elem(t_heap_rec *this) /* this != NULL */ 161{ 162 ++this->ref_ctr; 163 return this; 164} 165 166 167static void 168_rec_mark_elem(t_heap_rec *this) /* this != NULL */ 169{ 170 mark_dids_from_heapterm(&this->term); 171} 172 173 174static void 175_rec_mark_all(t_heap_rec *header) /* header != NULL */ 176{ 177 t_heap_rec *this = header->next; 178 if (header->term.tag.kernel != TEND) 179 ec_panic("Not a record list header", "_rec_mark_all()"); 180 while (this != header) 181 { 182 _rec_mark_elem(this); 183 this = this->next; 184 } 185} 186 187static int 188_rec_tostr_elem(t_heap_rec *obj, char *buf, int quoted) /* obj != NULL */ 189{ 190#define STRSZ_DBREF 20 191 sprintf(buf, "'DBREF'(16'%08x)", obj); 192 return STRSZ_DBREF; 193} 194 195static int 196_rec_strsz_elem(t_heap_rec *obj, int quoted) /* obj != NULL */ 197{ 198 return STRSZ_DBREF; 199} 200 201 202static int 203_rec_tostr_all(t_heap_rec *obj, char *buf, int quoted) /* obj != NULL */ 204{ 205#define STRSZ_REC 18 206 sprintf(buf, "'REC'(16'%08x)", obj); 207 return STRSZ_REC; 208} 209 210static int 211_rec_strsz_all(t_heap_rec *obj, int quoted) /* obj != NULL */ 212{ 213 return STRSZ_REC; 214} 215 216 217 218/* CLASS DESCRIPTOR (method table) */ 219t_ext_type heap_rec_tid = { 220 (void (*)(t_ext_ptr)) _rec_free_elem, 221 (t_ext_ptr (*)(t_ext_ptr)) _rec_copy_elem, 222 (void (*)(t_ext_ptr)) _rec_mark_elem, 223 (int (*)(t_ext_ptr,int)) _rec_strsz_elem, 224 (int (*)(t_ext_ptr,char*,int)) _rec_tostr_elem, 225 0, /* equal */ 226 (t_ext_ptr (*)(t_ext_ptr)) _rec_copy_elem, 227 0, /* get */ 228 0 /* set */ 229}; 230 231t_ext_type heap_rec_header_tid = { 232 (void (*)(t_ext_ptr)) _rec_free_all, 233 (t_ext_ptr (*)(t_ext_ptr)) _rec_copy_elem, 234 (void (*)(t_ext_ptr)) _rec_mark_all, 235 (int (*)(t_ext_ptr,int)) _rec_strsz_all, 236 (int (*)(t_ext_ptr,char*,int)) _rec_tostr_all, 237 0, /* equal */ 238 (t_ext_ptr (*)(t_ext_ptr)) _rec_copy_elem, 239 0, /* get */ 240 0 /* set */ 241}; 242 243 244/*---------------------------------------------------------------------- 245 * PROLOG INTERFACE 246 *----------------------------------------------------------------------*/ 247 248 249/* get the record header from either the functor key or a handle */ 250 251static int 252_get_rec_list(value vrec, type trec, value vmod, type tmod, t_heap_rec **pheader) 253{ 254 if (SameTypeC(trec, THANDLE)) 255 { 256 Get_Typed_Object(vrec, trec, &heap_rec_header_tid, *pheader); 257 } 258 else 259 { 260 dident key_did; 261 pword *prop; 262 int err; 263 Get_Key_Did(key_did,vrec,trec) 264 prop = get_modular_property(key_did, IDB_PROP, vmod.did, tmod, VISIBLE_PROP, &err); 265 if (!prop) 266 return err == PERROR ? NO_LOCAL_REC : err; 267 *pheader = (t_heap_rec *) prop->val.ptr; 268 if (!IsTag(prop->tag.kernel,TPTR) || !IsTag((*pheader)->term.tag.kernel,TEND)) 269 ec_panic("Not a valid record-property", "_get_rec_list()"); 270 } 271 return PSUCCEED; 272} 273 274 275/* 276 * is_record(Key)@Module checks whether Key is a record key (or handle) 277 * on which recorded terms have been (and still are) stored. 278 */ 279 280static int 281p_is_record_body(value vrec, type trec, value vmod, type tmod) 282{ 283 t_heap_rec *header; 284 int err; 285 286 a_mutex_lock(&PropertyLock); 287 err = _get_rec_list(vrec, trec, vmod, tmod, &header); 288 if (err == NO_LOCAL_REC || err == STALE_HANDLE) 289 err = PFAIL; 290 else if (err == PSUCCEED && header->next == header) 291 err = PFAIL; 292 a_mutex_unlock(&PropertyLock); 293 return err; 294} 295 296 297/* record_create(-Handle) creates an anonymous record */ 298 299static int 300p_record_create(value vrec, type trec) 301{ 302 pword rec; 303 Check_Ref(trec); 304 rec = ec_handle(&heap_rec_header_tid, (t_ext_ptr) _rec_create()); 305 Return_Unify_Pw(vrec, trec, rec.val, rec.tag); 306} 307 308 309static int 310p_local_record_body(value vkey, type tkey, value vmod, type tmod) 311{ 312 pword *prop, *p; 313 dident key_did; 314 int err; 315 316 Get_Functor_Did(vkey, tkey, key_did); 317 318 a_mutex_lock(&PropertyLock); 319 320 prop = set_modular_property(key_did, IDB_PROP, vmod.did, tmod, 321 LOCAL_PROP, &err); 322 if (!prop) 323 { 324 a_mutex_unlock(&PropertyLock); 325 if (err == PERROR) 326 { Succeed_; } /* exists already */ 327 else 328 Bip_Error(err); 329 } 330 prop->val.wptr = (uword *) _rec_create(); 331 prop->tag.kernel = TPTR; 332 a_mutex_unlock(&PropertyLock); 333 Succeed_; 334} 335 336 337static int 338p_global_record_body(value vkey, type tkey, value vmod, type tmod) 339{ 340 pword *prop, *p; 341 dident key_did; 342 int err; 343 344 Get_Functor_Did(vkey, tkey, key_did); 345 346 a_mutex_lock(&PropertyLock); 347 348 prop = set_modular_property(key_did, IDB_PROP, vmod.did, tmod, 349 GLOBAL_PROP, &err); 350 if (!prop) 351 { 352 a_mutex_unlock(&PropertyLock); 353 Bip_Error((err == PERROR) ? LOCAL_REC : err); 354 } 355 prop->val.wptr = (uword *) _rec_create(); 356 prop->tag.kernel = TPTR; 357 a_mutex_unlock(&PropertyLock); 358 Succeed_; 359} 360 361 362static int 363p_abolish_record_body(value vkey, type tkey, value vmod, type tmod) 364{ 365 dident key_did; 366 int err; 367 368 if (IsHandle(tkey)) 369 { 370 return p_handle_free(vkey, tkey); 371 } 372 else 373 { 374 Get_Functor_Did(vkey, tkey, key_did); 375 376 err = erase_modular_property(key_did, IDB_PROP, vmod.did,tmod, LOCAL_PROP); 377 378 if (err < 0) 379 { 380 Bip_Error((err == PERROR) ? NO_LOCAL_REC : err); 381 } 382 else 383 Succeed_; 384 } 385} 386 387 388/* record[az](+Key, ?Term)@Module */ 389 390static int 391p_recorda_body(value vrec, type trec, value vterm, type tterm, value vmod, type tmod) 392{ 393 t_heap_rec *obj, *header; 394 pword copy_pw; 395 int err = PSUCCEED; 396 397 if ((err = create_heapterm(©_pw, vterm, tterm)) != PSUCCEED) 398 { Bip_Error(err); } 399 400 a_mutex_lock(&PropertyLock); 401 err = _get_rec_list(vrec, trec, vmod, tmod, &header); 402 if (err != PSUCCEED) goto _unlock_return_err_; 403 404 obj = _rec_create(); 405 move_heapterm(©_pw, &obj->term); 406 obj->next = header->next; 407 obj->prev = header; 408 header->next->prev = obj; 409 header->next = obj; 410 411_unlock_return_err_: 412 a_mutex_unlock(&PropertyLock); 413 return err; 414} 415 416static int 417p_recordz_body(value vrec, type trec, value vterm, type tterm, value vmod, type tmod) 418{ 419 t_heap_rec *obj, *header; 420 pword copy_pw; 421 int err = PSUCCEED; 422 423 if ((err = create_heapterm(©_pw, vterm, tterm)) != PSUCCEED) 424 { Bip_Error(err); } 425 426 a_mutex_lock(&PropertyLock); 427 err = _get_rec_list(vrec, trec, vmod, tmod, &header); 428 if (err != PSUCCEED) goto _unlock_return_err_; 429 430 obj = _rec_create(); 431 move_heapterm(©_pw, &obj->term); 432 obj->next = header; 433 obj->prev = header->prev; 434 header->prev->next = obj; 435 header->prev = obj; 436 437_unlock_return_err_: 438 a_mutex_unlock(&PropertyLock); 439 return err; 440} 441 442 443/* record[az](+Key, ?Term, -DbRef)@Module */ 444 445static int 446p_recorda3_body(value vrec, type trec, value vterm, type tterm, value vdref, type tdref, value vmod, type tmod) 447{ 448 t_heap_rec *obj, *header; 449 pword copy_pw, ref_pw; 450 int err = PSUCCEED; 451 452 if ((err = create_heapterm(©_pw, vterm, tterm)) != PSUCCEED) 453 { Bip_Error(err); } 454 455 a_mutex_lock(&PropertyLock); 456 err = _get_rec_list(vrec, trec, vmod, tmod, &header); 457 if (err != PSUCCEED) goto _unlock_return_err_; 458 459 obj = _rec_create(); 460 move_heapterm(©_pw, &obj->term); 461 obj->next = header->next; 462 obj->prev = header; 463 header->next->prev = obj; 464 header->next = obj; 465 obj = _rec_copy_elem(obj); 466 a_mutex_unlock(&PropertyLock); 467 ref_pw = ec_handle(&heap_rec_tid, (t_ext_ptr) obj); 468 Return_Unify_Pw(vdref, tdref, ref_pw.val, ref_pw.tag); 469 470_unlock_return_err_: 471 a_mutex_unlock(&PropertyLock); 472 return err; 473} 474 475static int 476p_recordz3_body(value vrec, type trec, value vterm, type tterm, value vdref, type tdref, value vmod, type tmod) 477{ 478 t_heap_rec *obj, *header; 479 pword copy_pw, ref_pw; 480 int err = PSUCCEED; 481 482 if ((err = create_heapterm(©_pw, vterm, tterm)) != PSUCCEED) 483 { Bip_Error(err); } 484 485 a_mutex_lock(&PropertyLock); 486 err = _get_rec_list(vrec, trec, vmod, tmod, &header); 487 if (err != PSUCCEED) goto _unlock_return_err_; 488 489 obj = _rec_create(); 490 move_heapterm(©_pw, &obj->term); 491 obj->next = header; 492 obj->prev = header->prev; 493 header->prev->next = obj; 494 header->prev = obj; 495 obj = _rec_copy_elem(obj); 496 a_mutex_unlock(&PropertyLock); 497 ref_pw = ec_handle(&heap_rec_tid, (t_ext_ptr) obj); 498 Return_Unify_Pw(vdref, tdref, ref_pw.val, ref_pw.tag); 499 500_unlock_return_err_: 501 a_mutex_unlock(&PropertyLock); 502 return err; 503} 504 505 506/* filter for recorded terms: simple tests to reduce the recorded terms 507 returned to the ECLiPSe level, that need to be unified with the filter 508 term. The filter test performs simple comparison on the arguments of the 509 first argument of a recorded term against the filter, This is designed to 510 speed up the matching of dynamic predicates, which are recorded as (H :- B), 511 so that `filtering' is performed on the head H and its arguments. 512*/ 513static int 514_may_match_filter(value vfilter, uword tfilter, value vterm, type tterm) 515{ 516 pword *farg; /* pointer into filter term */ 517 pword *targ; /* pointer into recorded term */ 518 int i; 519 520 /* toplevel term */ 521 if (ISRef(tfilter) || IsRef(tterm)) 522 return 1; 523 if (DifferTypeC(tterm,tfilter)) 524 return 0; 525 if (ISSimple(tfilter)) 526 return SimpleEq(tfilter,vfilter,vterm); 527 if (IsTag(tfilter,TCOMP)) 528 { 529 farg = vfilter.ptr; 530 targ = vterm.ptr; 531 if (farg->val.did != targ->val.did) 532 return 0; 533 ++farg; 534 ++targ; 535 } 536 else if (IsTag(tfilter,TLIST)) 537 { 538 farg = vfilter.ptr; 539 targ = vterm.ptr; 540 } 541 else 542 return 1; /* in case of doubt, succeed (don't filter) */ 543 544 /* first argument (the head in case of a head:-body term */ 545 if (IsRef(farg->tag) || IsRef(targ->tag)) 546 return 1; 547 if (DifferType(farg->tag, targ->tag)) 548 return 0; 549 if (IsSimple(farg->tag)) 550 return SimpleEq(farg->tag.kernel,farg->val,targ->val); 551 switch (TagType(farg->tag)) 552 { 553 case TCOMP: 554 targ = targ->val.ptr; 555 farg = farg->val.ptr; 556 i = DidArity(farg->val.did); 557 if (farg->val.did != targ->val.did) return 0; 558 _check_rec_args: 559 do 560 { 561 pword *f = ++farg; 562 ++targ; 563 Dereference_(f); 564 if (IsRef(f->tag) || IsRef(targ->tag)) 565 continue; 566 if (DifferType(f->tag, targ->tag)) 567 return 0; 568 if (IsSimple(f->tag)) 569 { 570 if (!SimpleEq(f->tag.kernel,f->val,targ->val)) 571 return 0; 572 } 573 else if (IsTag(f->tag.kernel,TCOMP)) 574 { 575 if (f->val.ptr->val.did != targ->val.ptr->val.did) 576 return 0; 577 } 578 } while (--i > 0); 579 break; 580 case TLIST: 581 targ = targ->val.ptr-1; 582 farg = farg->val.ptr-1; 583 i = 2; 584 goto _check_rec_args; 585 } 586 return 1; 587} 588 589 590/* recorded_list(+Key, -Terms)@Module */ 591 592static int 593p_recorded_list_body(value vrec, type trec, value vl, type tl, value vmod, type tmod) 594{ 595 t_heap_rec *header, *obj; 596 int err; 597 598 Check_Output_List(tl); 599 a_mutex_lock(&PropertyLock); 600 err = _get_rec_list(vrec, trec, vmod, tmod, &header); 601 if (err == PSUCCEED) 602 { 603 pword list; 604 pword *tail = &list; 605 for (obj = header->next; obj != header; obj = obj->next) 606 { 607 pword *car = TG; 608 Make_List(tail, car); 609 Push_List_Frame(); 610 get_heapterm(&obj->term, car); 611 tail = car+1; 612 } 613 Make_Nil(tail); 614 a_mutex_unlock(&PropertyLock); 615 Return_Unify_Pw(vl, tl, list.val, list.tag); 616 } 617 else if (err == NO_LOCAL_REC) 618 { 619 a_mutex_unlock(&PropertyLock); 620 Return_Unify_Nil(vl, tl); 621 } 622 else 623 { 624 a_mutex_unlock(&PropertyLock); 625 Bip_Error(err); 626 } 627} 628 629 630/* recorded_refs(+Key, ?Filter, -Refs)@Module */ 631 632static int 633p_recorded_refs_body(value vrec, type trec, value vfilter, type tfilter, value vl, type tl, value vmod, type tmod) 634{ 635 t_heap_rec *header, *obj; 636 int err; 637 638 Check_Output_List(tl); 639 a_mutex_lock(&PropertyLock); 640 err = _get_rec_list(vrec, trec, vmod, tmod, &header); 641 if (err == PSUCCEED) 642 { 643 pword list; 644 pword *tail = &list; 645 for (obj = header->next; obj != header; obj = obj->next) 646 { 647 if (ISRef(tfilter.kernel) || 648 _may_match_filter(vfilter, tfilter.kernel, obj->term.val, obj->term.tag)) 649 { 650 pword *car = TG; 651 Make_List(tail, car); 652 Push_List_Frame(); 653 *car = ec_handle(&heap_rec_tid, (t_ext_ptr) _rec_copy_elem(obj)); 654 tail = car+1; 655 } 656 } 657 Make_Nil(tail); 658 a_mutex_unlock(&PropertyLock); 659 Return_Unify_Pw(vl, tl, list.val, list.tag); 660 } 661 else if (err == NO_LOCAL_REC) 662 { 663 a_mutex_unlock(&PropertyLock); 664 Return_Unify_Nil(vl, tl); 665 } 666 else 667 { 668 a_mutex_unlock(&PropertyLock); 669 Bip_Error(err); 670 } 671} 672 673 674/* erase_all(+Key)@Module */ 675 676static int 677p_erase_all_body(value vrec, type trec, value vmod, type tmod) 678{ 679 t_heap_rec *header; 680 int err; 681 682 a_mutex_lock(&PropertyLock); 683 err = _get_rec_list(vrec, trec, vmod, tmod, &header); 684 if (err == PSUCCEED) 685 { 686 _rec_free_elems(header); 687 } 688 else if (err == NO_LOCAL_REC) 689 { 690 err = PSUCCEED; 691 } 692 a_mutex_unlock(&PropertyLock); 693 Bip_Error(err); 694} 695 696 697/* referenced_record(+DbRef, -Term) */ 698 699static int 700p_referenced_record(value vrec, type trec, value vl, type tl) 701{ 702 t_heap_rec *obj; 703 pword result; 704 705 Get_Typed_Object(vrec, trec, &heap_rec_tid, obj); 706 get_heapterm(&obj->term, &result); 707 if (IsRef(result.tag) && result.val.ptr == &result) 708 { 709 Succeed_; 710 } 711 Return_Unify_Pw(vl, tl, result.val, result.tag); 712} 713 714 715/* erase(+DbRef) */ 716 717static int 718p_erase(value vrec, type trec) 719{ 720 t_heap_rec *obj; 721 pword result; 722 723 Get_Typed_Object(vrec, trec, &heap_rec_tid, obj); 724 a_mutex_lock(&PropertyLock); 725 if (obj->next) 726 { 727 obj->next->prev = obj->prev; 728 obj->prev->next = obj->next; 729 obj->prev = obj->next = 0; 730 _rec_free_elem(obj); 731 a_mutex_unlock(&PropertyLock); 732 Succeed_; 733 } 734 else /* was already removed from record-list */ 735 { 736 a_mutex_unlock(&PropertyLock); 737 Fail_; 738 } 739} 740 741 742/* 743 * Two internal predicates for stepping through the recorded list: 744 * first_recorded(+Key, ?Filter, -Ref)@Module is semidet 745 * next_recorded(+Ref, ?Filter, -Ref) is semidet 746 * These cannot be used for logical update semantics! 747 */ 748 749static int 750p_first_recorded(value vrec, type trec, value vfilter, type tfilter, value vdref, type tdref, value vmod, type tmod) 751{ 752 t_heap_rec *header, *obj; 753 pword ref_pw; 754 int err; 755 756 a_mutex_lock(&PropertyLock); 757 err = _get_rec_list(vrec, trec, vmod, tmod, &header); 758 if (err == PSUCCEED) 759 { 760 for(obj=header->next; obj != header; obj=obj->next) 761 { 762 if (IsRef(tfilter) || 763 _may_match_filter(vfilter, tfilter.kernel, obj->term.val, obj->term.tag)) 764 { 765 obj = _rec_copy_elem(obj); 766 a_mutex_unlock(&PropertyLock); 767 ref_pw = ec_handle(&heap_rec_tid, (t_ext_ptr) obj); 768 Return_Unify_Pw(vdref, tdref, ref_pw.val, ref_pw.tag); 769 } 770 } 771 } 772 else if (err != NO_LOCAL_REC) 773 { 774 a_mutex_unlock(&PropertyLock); 775 Bip_Error(err); 776 } 777 a_mutex_unlock(&PropertyLock); 778 Fail_; 779} 780 781 782static int 783p_next_recorded(value vref1, type tref1, value vfilter, type tfilter, value vref2, type tref2) 784{ 785 t_heap_rec *obj; 786 pword ref_pw; 787 788 Get_Typed_Object(vref1, tref1, &heap_rec_tid, obj); 789 a_mutex_lock(&PropertyLock); 790 for(;;) 791 { 792 obj = obj->next; 793 if (!obj || IsTag(obj->term.tag.kernel,TEND)) 794 { 795 a_mutex_unlock(&PropertyLock); 796 Fail_; 797 } 798 if (IsRef(tfilter) || 799 _may_match_filter(vfilter, tfilter.kernel, obj->term.val, obj->term.tag)) 800 { 801 break; 802 } 803 } 804 obj = _rec_copy_elem(obj); 805 a_mutex_unlock(&PropertyLock); 806 ref_pw = ec_handle(&heap_rec_tid, (t_ext_ptr) obj); 807 Return_Unify_Pw(vref2, tref2, ref_pw.val, ref_pw.tag); 808} 809 810 811/*---------------------------------------------------------------------- 812 * Special purpose record meta_attribute/0 for storing attribute-name 813 * mapping. We assume the record contains [Name|Index] pairs. 814 *----------------------------------------------------------------------*/ 815 816static t_heap_rec *rec_meta_attribute_; 817 818int 819meta_index(dident wd) 820{ 821 t_heap_rec *this; 822 823 for (this = rec_meta_attribute_->next; this != rec_meta_attribute_; this = this->next) 824 { 825 if (this->term.val.ptr[0].val.did == wd) 826 return this->term.val.ptr[1].val.nint; 827 } 828 return 0; 829} 830 831 832dident 833meta_name(int slot) 834{ 835 t_heap_rec *this; 836 837 for (this = rec_meta_attribute_->next; this != rec_meta_attribute_; this = this->next) 838 { 839 if (this->term.val.ptr[1].val.nint == slot) 840 return this->term.val.ptr[0].val.did; 841 } 842 return D_UNKNOWN; 843} 844 845 846/*---------------------------------------------------------------------- 847 * the subsequent BIPs fail on error and set the global variable 848 *----------------------------------------------------------------------*/ 849 850#undef Bip_Error 851#define Bip_Error(N) Bip_Error_Fail(N) 852 853/* 854 * Check if key is a valid key for records 855 */ 856 857/* ARGSUSED */ 858static int 859p_valid_key(value v, type t) 860{ 861 Error_If_Ref(t); 862 if (IsAtom(t) || IsStructure(t) || IsNil(t) || IsList(t)) 863 { Succeed_; } 864 Check_Typed_Object_Handle(v, t, &heap_rec_header_tid); 865 Succeed_; 866} 867 868#undef Bip_Error 869#define Bip_Error(N) return(N); 870 871/*---------------------------------------------------------------------- 872 * End of fail on error BIPs 873 *----------------------------------------------------------------------*/ 874 875void 876bip_record_init(int flags) 877{ 878 pri *pd; 879 type t; 880 value v1, v2; 881 int res; 882 883 d_visible_ = in_dict("visible", 0); 884 885 if (flags & INIT_SHARED) 886 { 887 (void) local_built_in(in_dict("valid_key", 1), 888 p_valid_key, B_SAFE|U_SIMPLE); 889 (void) exported_built_in(in_dict("erase_all_body", 2), 890 p_erase_all_body, B_UNSAFE); 891 (void) exported_built_in(in_dict("is_record_body", 2), 892 p_is_record_body, B_UNSAFE); 893 (void) exported_built_in(in_dict("recorda_body", 3), 894 p_recorda_body, B_UNSAFE); 895 (void) exported_built_in(in_dict("recordz_body", 3), 896 p_recordz_body, B_UNSAFE); 897 (void) exported_built_in(in_dict("recorda_body", 4), 898 p_recorda3_body, B_UNSAFE); 899 (void) exported_built_in(in_dict("recordz_body", 4), 900 p_recordz3_body, B_UNSAFE); 901 exported_built_in(in_dict("recorded_list_body", 3), 902 p_recorded_list_body, B_UNSAFE|U_FRESH) 903 -> mode = BoundArg(2, NONVAR); 904 exported_built_in(in_dict("recorded_refs_body", 4), 905 p_recorded_refs_body, B_UNSAFE|U_FRESH) 906 -> mode = BoundArg(2, NONVAR); 907 exported_built_in(in_dict("referenced_record", 2), 908 p_referenced_record, B_UNSAFE|U_FRESH) 909 -> mode = BoundArg(2, NONVAR); 910 (void) exported_built_in(in_dict("erase", 1), p_erase, B_UNSAFE); 911 (void) exported_built_in(in_dict("record_create", 1), 912 p_record_create, B_UNSAFE); 913 (void) exported_built_in(in_dict("local_record_body", 2), 914 p_local_record_body, B_UNSAFE); 915 (void) local_built_in(in_dict("global_record_body", 2), 916 p_global_record_body, B_UNSAFE); 917 (void) exported_built_in(in_dict("abolish_record_body", 2), 918 p_abolish_record_body, B_UNSAFE); 919 (void) local_built_in(in_dict("first_recorded_", 4), 920 p_first_recorded, B_UNSAFE); 921 (void) local_built_in(in_dict("next_recorded", 3), 922 p_next_recorded, B_UNSAFE); 923 } 924 925 t.kernel = ModuleTag(d_.kernel_sepia); 926 v1.did = in_dict("meta_attribute", 0); 927 v2.did = d_.kernel_sepia; 928 if (flags & INIT_SHARED) 929 { 930 (void) p_local_record_body(v1, tdict, v2, t); 931 } 932 rec_meta_attribute_ = (t_heap_rec *) get_modular_property(v1.did, 933 IDB_PROP, v2.did, t, LOCAL_PROP, &res)->val.ptr; 934} 935 936 937