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) 1997-2006 Cisco Systems, Inc. All Rights Reserved. 18 * 19 * Contributor(s): 20 * 21 * END LICENSE BLOCK */ 22 23/* 24 * ECLiPSe LIBRARY MODULE 25 * 26 * $Id: embed.c,v 1.7 2013/04/17 01:34:21 jschimpf Exp $ 27 * 28 * 29 * IDENTIFICATION: embed.c 30 * 31 * AUTHOR: Joachim Schimpf 32 * AUTHOR: Stefano Novello 33 * 34 * CONTENTS: name/arity 35 * 36 * DESCRIPTION: 37 * Call interface to embedded eclipse 38 */ 39 40 41#include "config.h" 42#include "sepia.h" 43#include "types.h" 44#include "error.h" 45#include "mem.h" 46#include "dict.h" 47#include "module.h" 48#include "emu_export.h" 49#include "embed.h" 50#include "os_support.h" 51 52#include <errno.h> 53 54#ifdef STDC_HEADERS 55#include <stdarg.h> 56#include <string.h> 57#include <limits.h> 58#else 59#include <varargs.h> 60extern char * strcat(); 61extern char * strcpy(); 62#endif 63 64 65/* 66 * EXTERN declarations 67 */ 68 69extern int eclipse_global_init(int init_flags); 70extern int eclipse_boot(char *initfile); 71extern int mem_init(int flags); 72 73 74/* 75 * Global state 76 */ 77 78#ifdef _WIN32 79static void *resume_thread = NULL; 80#endif 81 82 83/*---------------------------------------------------------------------- 84 * Setting the initialisation options 85 *----------------------------------------------------------------------*/ 86 87/* backwards compatibility */ 88int Winapi 89ec_set_option_int(int opt, int val) 90{ 91 return ec_set_option_long(opt, (word) val); 92} 93 94int Winapi 95ec_set_option_long(int opt, word val) 96{ 97 switch (opt) { 98 case EC_OPTION_PARALLEL_WORKER: ec_options.parallel_worker = (int) val; break; 99 case EC_OPTION_ARGC: ec_options.Argc = (int) val; break; 100 case EC_OPTION_LOCALSIZE: ec_options.localsize = val; break; 101 case EC_OPTION_GLOBALSIZE: ec_options.globalsize = val; break; 102 case EC_OPTION_PRIVATESIZE: ec_options.privatesize = val; break; 103 case EC_OPTION_SHAREDSIZE: ec_options.sharedsize = val; break; 104 case EC_OPTION_ALLOCATION: ec_options.allocation = (int) val; break; 105 case EC_OPTION_IO: ec_options.io_option = (int) val; break; 106 case EC_OPTION_INIT: ec_options.init_flags = val; break; 107 case EC_OPTION_DEBUG_LEVEL: ec_options.debug_level = val; break; 108 case EC_OPTION_CWD_SEPARATE:ec_use_own_cwd = (int) val; break; 109 default: return RANGE_ERROR; 110 } 111 return PSUCCEED; 112} 113 114int Winapi 115ec_set_option_ptr(int opt, void *val) 116{ 117 switch (opt) { 118 case EC_OPTION_MAPFILE: ec_options.mapfile = (char *) val; break; 119 case EC_OPTION_ARGV: ec_options.Argv = (char **) val; break; 120 case EC_OPTION_PANIC: ec_options.user_panic = (void(*)(const char*,const char *)) val; break; 121 case EC_OPTION_DEFAULT_MODULE: ec_options.default_module = (char *) val; break; 122 case EC_OPTION_DEFAULT_LANGUAGE: ec_options.default_language = (char *) val; break; 123 case EC_OPTION_ECLIPSEDIR: ec_options.eclipse_home = (char *) val; break; 124 default: return RANGE_ERROR; 125 } 126 return PSUCCEED; 127} 128 129/*---------------------------------------------------------------------- 130 * Initialising an embedded Eclipse 131 *----------------------------------------------------------------------*/ 132 133int Winapi 134ec_init(void) 135{ 136 char * initfile = (char *) 0; 137 char filename_buf[MAX_PATH_LEN]; 138 pword goal,module; 139 int res; 140 141 142 /*---------------------------------------------------------------- 143 * Make the connection to the shared heap, if any. 144 * Because of mmap problems on some machines this should 145 * happen AFTER initializing the message passing system. 146 *----------------------------------------------------------------*/ 147 mem_init(ec_options.init_flags); /* depends on -c and -m options */ 148 149 /* 150 * Init the global (shared) eclipse structures, dictionary, code... 151 * Maybe load a saved state. 152 * Note that we don't have an engine yet! 153 */ 154 eclipse_global_init(ec_options.init_flags); 155 156 157 /*---------------------------------------------------------------- 158 * Setup the Prolog engine 159 *----------------------------------------------------------------*/ 160 /* 161 * Initialize the Prolog engine 162 */ 163 emu_init(ec_options.init_flags, 0); 164 165 initfile = strcat(strcpy(filename_buf, ec_eclipse_home), "/lib/kernel.eco"); 166 if (ec_access(initfile, R_OK) < 0) 167 { 168 initfile = strcat(strcpy(filename_buf, ec_eclipse_home), "/lib/kernel.pl"); 169 if (ec_access(initfile, R_OK) < 0) 170 { 171 ec_panic("Aborting: Can't find boot file! Please check either\na) your program's setting for eclipsedir in ec_set_option(), or\nb) your setting for ECLIPSEDIR environment variable.\n","ec_init()"); 172 } 173 } 174 175 res = eclipse_boot(initfile); 176 if (res != PSUCCEED) 177 return res; 178 179 goal = ec_term(ec_did("main",1), ec_long(ec_options.init_flags & INIT_SHARED ? 0 : 1)); 180 module.val.did = ec_.d.kernel_sepia; 181 module.tag.kernel = ModuleTag(ec_.d.kernel_sepia); 182 if (main_emulc_noexit(goal.val, goal.tag, module.val, module.tag) != PYIELD) 183 return PFAIL; 184 return PSUCCEED; 185} 186 187void 188ec_embed_fini(void) 189{ 190#ifdef _WIN32 191 if (resume_thread) 192 { 193 (void) ec_thread_terminate(resume_thread, 3000/*ms timeout*/); 194 resume_thread = NULL; 195 } 196#endif 197 hp_free(ec_eclipse_home); 198 ec_eclipse_home = 0; 199} 200 201/*---------------------------------------------------------------------- 202 * Posting goals 203 *----------------------------------------------------------------------*/ 204 205void Winapi 206ec_post_goal(const pword goal) 207{ 208 pword *pw; 209 210 if (g_emu_.nesting_level > 1) 211 ec_panic("can't post goal to nested engine","ec_post_goal()"); 212 213 pw = TG; /* new list element */ 214 Push_List_Frame(); 215 pw[0] = goal; 216 Make_Var(&pw[1]); 217 218 Bind_(POSTED_LAST.val.ptr, pw, TLIST); /* append */ 219 ec_assign(&POSTED_LAST, pw[1].val, pw[1].tag); 220} 221 222static pword 223_get_posted_goals(void) 224{ 225 pword posted, empty; 226 227 /* terminate the posted-goals-list and copy its beginning */ 228 Bind_(POSTED_LAST.val.ptr, 0, TNIL); 229 posted = POSTED; 230 231 /* reinitialise the list to an empty difference list */ 232 Make_Ref(&empty, TG); 233 Push_Var(); 234 ec_assign(&POSTED, empty.val, empty.tag); 235 ec_assign(&POSTED_LAST, empty.val, empty.tag); 236 237 return posted; 238} 239 240void Winapi 241ec_post_string(const char *callstring) 242{ 243 ec_post_goal(ec_term(ec_.d.colon, 244 ec_atom(ec_.d.kernel_sepia), 245 ec_term(ec_did("exec_string",2), ec_string(callstring), ec_newvar()))); 246} 247 248void Winapi 249ec_post_exdr(int length, const char *exdr_string) 250{ 251 ec_post_goal(ec_term(ec_.d.colon, 252 ec_atom(ec_.d.kernel_sepia), 253 ec_term(ec_did("exec_exdr",1), ec_length_string(length, exdr_string)))); 254} 255 256int Winapi 257ec_exec_string( 258 char *callstring, 259 ec_ref varsref) /* NULL is allowed */ 260{ 261 pword vars; 262 dident exec_string_2 = enter_dict("exec_string",2); 263 264 vars = ec_newvar(); 265 if (varsref) 266 ec_ref_set(varsref, vars); 267 ec_post_goal(ec_term(ec_.d.colon, 268 ec_atom(ec_.d.kernel_sepia), 269 ec_term(exec_string_2, ec_string(callstring), vars))); 270 271 return ec_resume1(0); 272} 273 274 275/*---------------------------------------------------------------------- 276 * Resuming Eclipse execution 277 *----------------------------------------------------------------------*/ 278 279int Winapi 280ec_resume(void) 281{ 282 return ec_resume1(0); 283} 284 285int Winapi 286ec_resume1(ec_ref chp) 287{ 288 return ec_resume2(_get_posted_goals(), chp); 289} 290 291int Winapi 292ec_resume2(const pword term, ec_ref chp) 293{ 294 int res; 295 pword * pw; 296 pword tterm; 297 /* this assignment is needed to get around a compiler bug on Alpha Linux 298 that otherwise corrupts chp 299 */ 300 tterm = term; 301 302 if (g_emu_.nesting_level > 1) 303 ec_panic("can't resume nested engine","ec_resume2()"); 304 305 if (ec_running()) 306 return PRUNNING; 307 308 A[1] = tterm; 309 Make_Integer(&A[2], RESUME_CONT); 310 res = restart_emulc(); 311 if (res != PYIELD) 312 ec_panic("eclipse emulator did not yield properly","ec_resume()"); 313 314 if (chp) 315 ec_ref_set(chp,A[2]); 316 317 pw = &A[1]; 318 Dereference_(pw) 319 if (IsInteger(pw->tag)) 320 return pw->val.nint; 321 else 322 return TYPE_ERROR; 323} 324 325int Winapi 326ec_resume_long(long int *to_c) 327{ 328 int res; 329 pword * pw; 330 331 if (g_emu_.nesting_level > 1) 332 ec_panic("can't resume nested engine","ec_resume_long()"); 333 334 if (ec_running()) 335 return PRUNNING; 336 337 A[1] = _get_posted_goals(); 338 Make_Integer(&A[2], RESUME_CONT); 339 340 res = restart_emulc(); 341 if (res != PYIELD) 342 ec_panic("eclipse emulator did not yield properly","ec_resume_long()"); 343 344 pw = &A[2]; 345 Dereference_(pw) 346 if (IsInteger(pw->tag)) 347 *to_c = pw->val.nint; 348 else 349 *to_c = 0; 350 351 pw = &A[1]; 352 Dereference_(pw) 353 if (IsInteger(pw->tag)) 354 return pw->val.nint; 355 else 356 return TYPE_ERROR; 357} 358 359 360 361int Winapi 362ec_running(void) 363{ 364#ifdef _WIN32 365 int res; 366 if (resume_thread && !ec_thread_stopped(resume_thread, &res)) 367 return 1; 368#endif 369 return 0; 370} 371 372#ifdef _WIN32 373 374/* this will be called in a thread */ 375static int 376restart_emulc_thread(void *dummy_arg_for_thread) 377{ 378 return restart_emulc(); 379} 380 381#endif 382 383int Winapi 384ec_resume_async(void) 385{ 386 if (g_emu_.nesting_level > 1) 387 ec_panic("can't resume nested engine","ec_resume2()"); 388 389#ifdef _WIN32 390 if (!resume_thread) /* if we don't have a thread yet, make one */ 391 { 392 resume_thread = ec_make_thread(); 393 if (!resume_thread) 394 return SYS_ERROR; 395 } 396 else /* make sure the thread is not running */ 397 { 398 if (ec_running()) 399 return PRUNNING; 400 } 401#endif 402 403 A[1] = _get_posted_goals(); 404 Make_Integer(&A[2], RESUME_CONT); 405 406#ifdef _WIN32 407 if (!ec_start_thread(resume_thread, restart_emulc_thread, NULL)) 408 return SYS_ERROR; 409#endif 410 411 return PSUCCEED; 412} 413 414 415int Winapi 416ec_resume_status(void) 417{ 418 long dummy; 419 return ec_resume_status_long(&dummy); 420} 421 422int Winapi 423ec_resume_status_long(long int *to_c) 424{ 425 return ec_wait_resume_status_long(to_c, 0); 426} 427 428int Winapi 429ec_wait_resume_status_long(long int *to_c, int timeout) 430{ 431 pword *pw; 432 int res; 433 434#ifdef _WIN32 435 /* This is supposed to be called only after a resume_async! */ 436 if (!resume_thread) 437 return PERROR; 438 if (!ec_thread_wait(resume_thread, &res, timeout)) 439 return PRUNNING; 440#else 441 /* We don't have threads: resume here in order to make resume_async- 442 * resume_status sequences work anyway, so we can write portable code. 443 */ 444 res = restart_emulc(); 445#endif 446 if (res != PYIELD) 447 ec_panic("eclipse emulator did not yield properly","ec_resume_long()"); 448 449 pw = &A[2]; 450 Dereference_(pw) 451 if (IsInteger(pw->tag)) 452 *to_c = pw->val.nint; 453 else 454 *to_c = 0; 455 456 pw = &A[1]; 457 Dereference_(pw) 458 if (IsInteger(pw->tag)) 459 return pw->val.nint; 460 else 461 return TYPE_ERROR; 462} 463 464 465/*---------------------------------------------------------------------- 466 * Resuming Eclipse without continuing 467 * just create an opportunity for event handling 468 * Return values: 469 * PRUNNING 470 * engine not yet ready (previous resume_async) 471 * PFLUSHIO,PWAITIO 472 * nested request from within handler 473 * PSUCCEED 474 * handler finished 475 * PFAIL,PTHROW 476 * should never occur (prevented by yield/3) 477 * PYIELD 478 * programmer error (yield/2 in handler) 479 *----------------------------------------------------------------------*/ 480 481int Winapi 482ec_handle_events(long int *to_c) 483{ 484 int res; 485 pword * pw; 486 487 if (g_emu_.nesting_level > 1) 488 ec_panic("can't resume nested engine","ec_handle_events()"); 489 490 if (ec_running()) 491 return PRUNNING; 492 493 Make_Nil(&A[1]) /* don't care */ 494 Make_Integer(&A[2], RESUME_SIMPLE); 495 res = restart_emulc(); 496 if (res != PYIELD) 497 ec_panic("eclipse emulator did not yield properly","ec_handle_events()"); 498 499 pw = &A[2]; 500 Dereference_(pw) 501 if (IsInteger(pw->tag)) 502 *to_c = pw->val.nint; 503 else 504 *to_c = 0; 505 506 pw = &A[1]; 507 Dereference_(pw) 508 if (IsInteger(pw->tag)) 509 return pw->val.nint; 510 else 511 return TYPE_ERROR; 512} 513 514 515/*---------------------------------------------------------------------- 516 * External references: 517 * 518 * States of external references: 519 * 520 * EC_REF_C: hp_allocated, simple value, not in global list 521 * 522 * This is the state just after an ec_refs has been created by a 523 * call to ec_refs_create(), or after backtracking to such a point. 524 * It is not "initialised" yet, i.e. no array (structure) for the 525 * n slots has been allocated on the global stack, and it is not 526 * yet known to the garbage collector. The var-field preliminarily 527 * holds the init-value instead of a pointer to a global stack array. 528 * 529 * EC_REF_C_P: hp_allocated, prolog value, in global list 530 * 531 * This is the normal working state: the ec_refs is used from the 532 * C program, its var-field points to a global stack array of arity 533 * n, and it is known to the garbage collector via the global list. 534 * The transition from EC_REF_C to EC_REF_C_P happens on the first 535 * access to the ec_refs: a global stack arary is allocated and its 536 * slots initialised with the requested init value. 537 * 538 * EC_REF_FREE: deallocated, no value, not in global list 539 * 540 * This state only exists temporarily just before deallocation. 541 * 542 * Allowed transitions: 543 * (none) --create--> EC_REF_C 544 * EC_REF_C --init--> EC_REF_C_P 545 * EC_REF_C --destroy--> EC_REF_FREE 546 * EC_REF_C --untrail--> EC_REF_C 547 * EC_REF_C_P --destroy--> EC_REF_FREE 548 * EC_REF_C_P --untrail--> EC_REF_C 549 *----------------------------------------------------------------------*/ 550 551void Winapi 552ec_refs_destroy(ec_refs variable) 553{ 554 if (!(variable->refstate & EC_REF_C)) 555 ec_panic("ec_ref already freed from C","ec_refs_destroy()"); 556 if (variable->refstate & EC_REF_P) 557 { 558 /* Unlink the ec_ref to make the global stack array become garbage */ 559 variable->next->prev = variable->prev; 560 variable->prev->next = variable->next; 561 } 562 variable->refstate = EC_REF_FREE; 563 hp_free_size((generic_ptr)variable, sizeof(struct eclipse_ref_)); 564} 565 566/*ARGSUSED*/ 567static void 568_ec_refs_untrail(pword *parray, word *pdata, int size, int flags) 569{ 570 ec_refs variable = g_emu_.allrefs.next; 571 /* Find the ec_ref corresponding to parray in the global list. */ 572 /* If it's not in there, then it has already been destroyed! */ 573 while (variable != &g_emu_.allrefs) 574 { 575 if (variable->var.val.ptr == parray) 576 { 577 if (!(variable->refstate == EC_REF_C_P)) 578 ec_panic("ec_ref already untrailed","_ec_refs_untrail()"); 579 variable->refstate &= ~EC_REF_P; 580 variable->next->prev = variable->prev; /* unlink */ 581 variable->prev->next = variable->next; 582 variable->var = *((pword*) pdata); /* reset value */ 583 return; 584 } 585 variable = variable->next; 586 } 587} 588 589int Winapi 590ec_refs_size(const ec_refs variable) 591{ 592 return variable->size; 593} 594 595ec_refs Winapi 596ec_refs_create_newvars(int n) 597{ 598 ec_ref new; 599 600 new = hp_alloc_size(sizeof(struct eclipse_ref_)); 601 new->var = g_emu_.allrefs.var; 602 new->refstate = EC_REF_C; 603 new->size = n; 604 new->next = new->prev = 0; 605 return new; 606} 607 608ec_refs Winapi 609ec_refs_create(int n, const pword initpw) 610{ 611 ec_ref new; 612 613 if (!(IsSimple(initpw.tag) || IsPersistent(initpw.tag))) 614 ec_panic("non-atomic initializer","ec_refs_create()"); 615 new = hp_alloc_size(sizeof(struct eclipse_ref_)); 616 new->var = initpw; 617 new->refstate = EC_REF_C; 618 new->size = n; 619 new->next = new->prev = 0; 620 return new; 621} 622 623static void 624_ec_ref_init(ec_refs variable) 625{ 626 pword * pw, initpw; 627 int i; 628 int n = variable->size; 629 630 if (variable->refstate != EC_REF_C) 631 ec_panic("ec_refs already freed from C","_ec_ref_init()"); 632 633 initpw = variable->var; 634 variable->refstate = EC_REF_C_P; 635 636 /* Use the global stack array as trail item, so the trail entry */ 637 /* gets garbage collected together with it. */ 638 pw = TG; 639 ec_trail_undo(_ec_refs_untrail, pw, NULL, 640 (word *) &initpw, sizeof(pword)/sizeof(word), TRAILED_PWORD); 641 642 Make_Struct(&(variable->var), pw); 643 Push_Struct_Frame(ec_did("",n)); 644 if (IsRef(initpw.tag)) 645 { 646 for (i=1; i<=n; i++) 647 { /* brackets important */ 648 Make_Var(pw+i); 649 } 650 } 651 else 652 { 653 for (i=1; i<=n; i++) 654 pw[i] = initpw; 655 } 656 variable->next = g_emu_.allrefs.next; 657 variable->prev = &g_emu_.allrefs; 658 g_emu_.allrefs.next->prev = variable; 659 g_emu_.allrefs.next = variable; 660} 661 662void Winapi 663ec_refs_set(ec_refs variable, int i, const pword w) 664{ 665 if (variable->refstate != EC_REF_C_P) 666 _ec_ref_init(variable); 667 if (i >= variable->size) 668 ec_panic("out of bounds","ec_refs_set()"); 669 670 (void) ec_assign(variable->var.val.ptr+i+1, w.val,w.tag); 671} 672 673pword Winapi 674ec_refs_get(const ec_refs variable, int i) 675{ 676 if (variable->refstate != EC_REF_C_P) 677 _ec_ref_init(variable); 678 if (i >= variable->size) 679 ec_panic("out of bounds","ec_refs_get()"); 680 681 return variable->var.val.ptr[i+1]; 682} 683 684 685ec_ref Winapi 686ec_ref_create(pword initpw) 687{ 688 return (ec_ref) ec_refs_create(1, initpw); 689} 690 691ec_ref Winapi 692ec_ref_create_newvar(void) 693{ 694 return (ec_ref) ec_refs_create_newvars(1); 695} 696 697void Winapi 698ec_ref_set(ec_ref variable, const pword w) 699{ 700 ec_refs_set((ec_refs) variable, 0, w); 701} 702 703pword Winapi 704ec_ref_get(const ec_ref variable) 705{ 706 return ec_refs_get((ec_refs) variable, 0); 707} 708 709void Winapi 710ec_ref_destroy(ec_ref variable) 711{ 712 ec_refs_destroy((ec_refs) variable); 713} 714 715 716/*---------------------------------------------------------------------- 717 * Choicepoints and cuts 718 *----------------------------------------------------------------------*/ 719 720void Winapi 721ec_cut_to_chp(ec_ref chp) 722{ 723 ec_post_goal(ec_term(ec_.d.call_explicit, 724 ec_term(ec_.d.cut_to,ec_ref_get(chp)), 725 ec_atom(ec_.d.kernel_sepia))); 726} 727 728 729/*---------------------------------------------------------------------- 730 * C->Prolog and Prolog->C type conversions 731 *----------------------------------------------------------------------*/ 732 733pword Winapi 734ec_atom(const dident a) 735{ 736 pword w; 737 if (a == ec_.d.nil) 738 { 739 Make_Nil(&w); 740 } 741 else 742 { 743 Make_Atom(&w,a); 744 } 745 return w; 746} 747 748int Winapi 749ec_get_atom(const pword w, dident *a) 750{ 751 const pword * pw = &w; 752 Dereference_(pw); 753 if (IsAtom(pw->tag)) 754 *a = pw->val.did; 755 else if (IsNil(pw->tag)) 756 *a = ec_.d.nil; 757 else if (IsRef(pw->tag)) 758 return INSTANTIATION_FAULT; 759 else 760 return TYPE_ERROR; 761 return PSUCCEED; 762} 763 764pword Winapi 765ec_string(const char *s) 766{ 767 pword w; 768 Make_String(&w, (char *) s); 769 return w; 770} 771 772pword Winapi 773ec_length_string(int l, const char *s) 774{ 775 pword w; 776 char *s1; 777 w.tag.kernel = TSTRG; 778 w.val.ptr = TG; 779 Push_Buffer(l+1); 780 s1 = (char *) BufferStart(w.val.ptr); 781 Copy_Bytes(s1, (char *) s, l); 782 s1[l] = 0; 783 return w; 784} 785 786int Winapi 787ec_get_string(const pword w, char **s) 788{ 789 const pword *pw = &w; 790 Dereference_(pw); 791 792 if (IsString(pw->tag)) 793 *s = StringStart(pw->val); 794 else if (IsAtom(pw->tag)) 795 *s = DidName(pw->val.did); 796 else if (IsNil(pw->tag)) 797 *s = DidName(ec_.d.nil); 798 else if (IsRef(pw->tag)) 799 return INSTANTIATION_FAULT; 800 else 801 return TYPE_ERROR; 802 return PSUCCEED; 803} 804 805int Winapi 806ec_get_string_length(const pword w, char **s, long int *l) 807{ 808 const pword *pw = &w; 809 Dereference_(pw); 810 811 if (IsString(pw->tag)) 812 { 813 *s = StringStart(pw->val); 814 *l = StringLength(pw->val); 815 } 816 else if (IsAtom(pw->tag)) 817 { 818 *s = DidName(pw->val.did); 819 *l = DidLength(pw->val.did); 820 } 821 else if (IsNil(pw->tag)) 822 { 823 *s = DidName(ec_.d.nil); 824 *l = 2; 825 } 826 else if (IsRef(pw->tag)) 827 return INSTANTIATION_FAULT; 828 else 829 return TYPE_ERROR; 830 return PSUCCEED; 831} 832 833pword Winapi 834ec_long(const long int l) 835{ 836 pword w; 837 Make_Integer(&w,(word)l); 838 return w; 839} 840 841int Winapi 842ec_get_long(const pword w, long int *l) 843{ 844 const pword *pw = &w; 845 Dereference_(pw); 846 847 if (IsInteger(pw->tag)) 848 { 849#if SIZEOF_WORD > SIZEOF_LONG 850 /* range error if val.nint is too large for long */ 851 if (pw->val.nint > LONG_MAX || pw->val.nint < LONG_MIN) 852 return RANGE_ERROR; 853#endif 854 *l = pw->val.nint; 855 } else if (IsBignum(pw->tag)) 856 return RANGE_ERROR; 857 else if (IsRef(pw->tag)) 858 return INSTANTIATION_FAULT; 859 else 860 return TYPE_ERROR; 861 return PSUCCEED; 862} 863 864#ifdef HAVE_LONG_LONG 865#ifndef SIZEOF_LONG_LONG 866#ifdef __SIZEOF_LONG_LONG__ 867#define SIZEOF_LONG_LONG __SIZEOF_LONG_LONG__ 868#else 869#define SIZEOF_LONG_LONG 8 870#endif 871#endif 872 873pword Winapi 874ec_long_long(const long long int l) 875{ 876 pword w; 877 tag_desc[TBIG].arith_op[ARITH_BOXLONGLONG](l, &w); 878 return w; 879} 880 881int Winapi 882ec_get_long_long(const pword w, long long int *l) 883{ 884 const pword *pw = &w; 885 Dereference_(pw); 886 887 if (IsInteger(pw->tag)) { 888#if SIZEOF_WORD > SIZEOF_LONG_LONG 889 /* range error if val.nint is too large for long long */ 890 if (pw->val.nint > LLONG_MAX || pw->val.nint < LLONG_MIN) 891 return RANGE_ERROR; 892#endif 893 *l = pw->val.nint; 894 } else if (IsBignum(pw->tag)) 895 return tag_desc[TBIG].arith_op[ARITH_TOCLONGLONG](&w, l) < 0 ? RANGE_ERROR : PSUCCEED; 896 else if (IsRef(pw->tag)) 897 return INSTANTIATION_FAULT; 898 else 899 return TYPE_ERROR; 900 return PSUCCEED; 901} 902#endif 903 904pword Winapi 905ec_double(const double d) 906{ 907 pword result; 908 909 Make_Double(&result, d); 910 return result; 911} 912 913int Winapi 914ec_get_double(const pword w, double *d) 915{ 916 const pword *pw = &w; 917 Dereference_(pw); 918 919 if (IsDouble(pw->tag)) 920 *d = Dbl(pw->val); 921 else if (IsInteger(pw->tag)) 922 *d = (double) pw->val.nint; 923 else if (IsRef(pw->tag)) 924 return INSTANTIATION_FAULT; 925 else 926 return TYPE_ERROR; 927 return PSUCCEED; 928} 929 930 931#ifdef STDC_HEADERS 932 933pword 934ec_term(dident functor, ...) 935{ 936 va_list ap; 937 int arity = DidArity(functor); 938 pword * pw; 939 pword result; 940 int i; 941 942 va_start(ap, functor); 943 944 pw = TG; 945 Push_Struct_Frame(functor); 946 for (i=1 ; i <= arity ; i++) 947 pw[i] = va_arg(ap,pword); 948 va_end(ap); 949 950 Make_Struct(&result,pw); 951 return result; 952} 953 954#else 955 956pword 957ec_term(va_alist) 958va_dcl 959{ 960 va_list ap; 961 dident functor; 962 int arity; 963 pword * pw; 964 pword result; 965 int i; 966 967 va_start(ap); 968 969 functor = va_arg(ap,dident); 970 arity = DidArity(functor); 971 972 pw = TG; 973 Push_Struct_Frame(functor); 974 for (i=1 ; i <= arity ; i++) 975 pw[i] = va_arg(ap,pword); 976 va_end(ap); 977 978 Make_Struct(&result,pw); 979 return result; 980} 981 982#endif 983 984pword Winapi 985ec_term_array(const dident functor, const pword *args) 986{ 987 int arity; 988 pword * pw; 989 pword result; 990 991 arity = DidArity(functor); 992 993 pw = TG; 994 Make_Struct(&result,pw); 995 Push_Struct_Frame(functor); 996 pw++; 997 998 while(arity--) 999 *pw++ = *args++; 1000 1001 return result; 1002} 1003 1004 1005pword Winapi 1006ec_matrixofdouble(int n, int m, const double *darr) 1007{ 1008 dident row_functor = enter_dict("[]", n); 1009 dident col_functor = enter_dict("[]", m); 1010 pword *rows, *col; 1011 pword result; 1012 int i,j; 1013 1014 rows = TG; 1015 Push_Struct_Frame(row_functor); 1016 for(i=1; i<=n; ++i) 1017 { 1018 col = TG; 1019 Make_Struct(&rows[i], col); 1020 Push_Struct_Frame(col_functor); 1021 for(j=1; j<=m; ++j) 1022 { 1023 Make_Double(&col[j], *darr++); 1024 } 1025 } 1026 Make_Struct(&result,rows); 1027 return result; 1028} 1029 1030pword Winapi 1031ec_arrayofdouble(int n, const double *darr) 1032{ 1033 dident functor = enter_dict("[]", n); 1034 pword result; 1035 pword *row; 1036 int i; 1037 1038 row = TG; 1039 Push_Struct_Frame(functor); 1040 for(i=1; i<=n; ++i) 1041 { 1042 Make_Double(&row[i], *darr++) 1043 } 1044 Make_Struct(&result,row); 1045 return result; 1046} 1047 1048 1049pword Winapi 1050ec_list(const pword head, const pword tail) 1051{ 1052 pword * pw; 1053 pword result; 1054 1055 pw = TG; 1056 Push_List_Frame(); 1057 pw[0] = head; 1058 pw[1] = tail; 1059 1060 Make_List(&result,pw); 1061 return result; 1062} 1063 1064pword Winapi 1065ec_listofdouble(int length, const double *array) 1066{ 1067 pword result; 1068 pword *pw = &result; 1069 while (length-- > 0) 1070 { 1071 Make_List(pw,TG); 1072 pw = TG; 1073 Push_List_Frame(); 1074 *pw++ = ec_double(*array++); 1075 } 1076 Make_Nil(pw); 1077 return result; 1078} 1079 1080pword Winapi 1081ec_listoflong(int length, const long int *array) 1082{ 1083 pword result; 1084 pword *pw = &result; 1085 while (length-- > 0) 1086 { 1087 Make_List(pw,TG); 1088 pw = TG; 1089 Push_List_Frame(); 1090 *pw++ = ec_long(*array++); 1091 } 1092 Make_Nil(pw); 1093 return result; 1094} 1095 1096pword Winapi 1097ec_listofchar(int length, const char *array) 1098{ 1099 pword result; 1100 pword *pw = &result; 1101 while (length-- > 0) 1102 { 1103 Make_List(pw,TG); 1104 pw = TG; 1105 Push_List_Frame(); 1106 *pw++ = ec_long(*array++); 1107 } 1108 Make_Nil(pw); 1109 return result; 1110} 1111 1112pword Winapi 1113ec_listofrefs(ec_refs refs) 1114{ 1115 pword result; 1116 pword *pw = &result; 1117 int length = refs->size; 1118 int i; 1119 1120 if (refs->refstate != EC_REF_C_P) 1121 _ec_ref_init(refs); 1122 1123 for (i=1; i<=length; i++) 1124 { 1125 Make_List(pw,TG); 1126 pw = TG; 1127 Push_List_Frame(); 1128 *pw++ = refs->var.val.ptr[i]; 1129 } 1130 Make_Nil(pw); 1131 return result; 1132} 1133 1134int Winapi 1135ec_get_nil(const pword list) 1136{ 1137 const pword * pw = &list; 1138 Dereference_(pw); 1139 return IsNil(pw->tag)? PSUCCEED: PFAIL; 1140} 1141 1142int Winapi 1143ec_is_var(const pword w) 1144{ 1145 const pword * pw = &w; 1146 Dereference_(pw); 1147 return IsRef(pw->tag)? PSUCCEED: PFAIL; 1148} 1149 1150int Winapi 1151ec_get_list(const pword list, pword *car, pword *cdr) 1152{ 1153 const pword * pw = &list; 1154 Dereference_(pw); 1155 1156 if (IsList(pw->tag)) 1157 { 1158 *car = pw->val.ptr[0]; 1159 *cdr = pw->val.ptr[1]; 1160 return PSUCCEED; 1161 } 1162 else if (IsNil(pw->tag)) 1163 return PFAIL; 1164 else if (IsRef(pw->tag)) 1165 return INSTANTIATION_FAULT; 1166 else 1167 return TYPE_ERROR; 1168} 1169 1170int Winapi 1171ec_get_arg(const int n, pword term, pword *arg) 1172{ 1173 pword * pw = &term; 1174 Dereference_(pw); 1175 1176 if (IsStructure(pw->tag)) 1177 if (n < 1 || n > DidArity(pw->val.ptr->val.did)) 1178 return RANGE_ERROR; 1179 else 1180 *arg = pw->val.ptr[n]; 1181 else if (IsList(pw->tag)) 1182 if (n < 1 || n > 2) 1183 return RANGE_ERROR; 1184 else 1185 *arg = pw->val.ptr[n-1]; 1186 else if (IsRef(pw->tag)) 1187 return INSTANTIATION_FAULT; 1188 else 1189 return TYPE_ERROR; 1190 return PSUCCEED; 1191} 1192 1193int Winapi 1194ec_get_functor(const pword term, dident *d) 1195{ 1196 const pword * pw = &term; 1197 Dereference_(pw); 1198 1199 if (IsStructure(pw->tag)) 1200 *d = pw->val.ptr->val.did; 1201 else if (IsList(pw->tag)) 1202 *d = ec_.d.list; 1203 else if (IsRef(pw->tag)) 1204 return INSTANTIATION_FAULT; 1205 else 1206 return TYPE_ERROR; 1207 return PSUCCEED; 1208} 1209 1210int Winapi 1211ec_arity(const pword term) 1212{ 1213 const pword * pw = &term; 1214 Dereference_(pw); 1215 if (IsList(pw->tag)) 1216 return 2; 1217 1218 if (IsStructure(pw->tag)) 1219 return DidArity(pw->val.ptr->val.did); 1220 1221 return 0; 1222} 1223 1224pword Winapi 1225ec_newvar(void) 1226{ 1227 pword * pw; 1228 1229 pw = TG++; 1230 Make_Ref(pw,pw); 1231 return *pw; 1232 1233} 1234 1235pword Winapi 1236ec_nil(void) 1237{ 1238 pword p; 1239 1240 Make_Nil(&p); 1241 return p; 1242} 1243 1244static void 1245ec_deref(pword *ppw) /* dereference in place */ 1246{ 1247 if (IsRef(ppw->tag)) 1248 { 1249 pword *ppw1 = ppw; 1250 Dereference_(ppw); 1251 *ppw1 = *ppw; 1252 } 1253} 1254 1255 1256int Winapi 1257ec_var_lookup(ec_ref vars, char *name, pword *var) 1258{ 1259 pword list; 1260 pword pair; 1261 pword varname; 1262 1263 list = ec_ref_get(vars); 1264 while (ec_deref(&list),IsList(list.tag)) 1265 { 1266 if ( PSUCCEED == ec_get_arg(1,list,&pair) && 1267 (ec_deref(&pair), IsList(pair.tag)) && 1268 PSUCCEED == ec_get_arg(1,pair,&varname) && 1269 (ec_deref(&varname), IsAtom(varname.tag)) && 1270 0 == strcmp(DidName(varname.val.did),name) ) 1271 { 1272 ec_get_arg(2,pair,var); 1273 return PSUCCEED; 1274 } 1275 else 1276 { 1277 if (PSUCCEED != ec_get_arg(2,list,&list)) 1278 return PFAIL; 1279 } 1280 } 1281 return PFAIL; 1282} 1283 1284 1285/*---------------------------------------------------------------------- 1286 * Support for external C predicates 1287 *----------------------------------------------------------------------*/ 1288 1289int Winapi 1290ec_unify(pword pw1, pword pw2) 1291{ 1292 return ec_unify_(pw1.val, pw1.tag, pw2.val, pw2.tag, &MU); 1293} 1294 1295 1296int Winapi 1297ec_unify_arg(int n, pword term) 1298{ 1299#ifdef __STDC__ 1300 static type tref = {TREF}; 1301#else 1302 type tref; 1303 tref.kernel = TREF; 1304#endif 1305 return ec_unify_(A[n].val, A[n].tag, term.val, term.tag, &MU); 1306} 1307 1308int Winapi 1309ec_compare(pword pw1, pword pw2) 1310{ 1311 pword *ppw1 = &pw1; 1312 pword *ppw2 = &pw2; 1313 Dereference_(ppw1); 1314 Dereference_(ppw2); 1315 return ec_compare_terms(ppw1->val, ppw1->tag, ppw2->val, ppw2->tag); 1316} 1317 1318pword Winapi 1319ec_arg(int n) 1320{ 1321 return A[n]; 1322} 1323 1324int Winapi 1325ec_schedule_suspensions(pword attr, int pos) 1326{ 1327 Check_Structure(attr.tag); 1328 if (pos < 1 || pos > DidArity(attr.val.ptr[0].val.did)) 1329 return RANGE_ERROR; 1330 return ec_schedule_susps(&(attr.val.ptr[pos])); 1331} 1332 1333int Winapi 1334ec_visible_procedure(dident proc_did, pword module, void **pproc) 1335{ 1336 pri *proc = visible_procedure(proc_did, module.val.did, module.tag, 0); 1337 if (!proc) 1338 { 1339 int res; 1340 Get_Bip_Error(res); 1341 return res; 1342 } 1343 *pproc = (void*) proc; 1344 return PSUCCEED; 1345} 1346 1347 1348/*---------------------------------------------------------------------- 1349 * Some predefined external data types 1350 *----------------------------------------------------------------------*/ 1351 1352/* 1353 * double [] 1354 */ 1355 1356static pword 1357_double_arr_get(t_ext_ptr h, int i) 1358{ 1359 return ec_double(((double*)h)[i]); 1360} 1361 1362static int 1363_double_arr_set(t_ext_ptr h, int i, pword pw) 1364{ 1365 return ec_get_double(pw, &((double*)h)[i]); 1366} 1367 1368t_ext_type ec_xt_double_arr = { 1369 0, 0, 0, 0, 0, 0, 0, 1370 _double_arr_get, 1371 _double_arr_set 1372}; 1373 1374 1375/* 1376 * long [] 1377 */ 1378 1379static pword 1380_long_arr_get(t_ext_ptr h, int i) 1381{ 1382 return ec_long(((long*)h)[i]); 1383} 1384 1385static int 1386_long_arr_set(t_ext_ptr h, int i, pword pw) 1387{ 1388 return ec_get_long(pw, &((long*)h)[i]); 1389} 1390 1391t_ext_type ec_xt_long_arr = { 1392 0, 0, 0, 0, 0, 0, 0, 1393 _long_arr_get, 1394 _long_arr_set 1395}; 1396 1397 1398/* 1399 * char [] 1400 */ 1401 1402static pword 1403_char_arr_get(t_ext_ptr h, int i) 1404{ 1405 return ec_long((long) ((char*)h)[i]); 1406} 1407 1408static int 1409_char_arr_set(t_ext_ptr h, int i, pword pw) 1410{ 1411 long l; 1412 int err = ec_get_long(pw, &l); 1413 if (err == PSUCCEED) 1414 ((char*) h)[i] = (char) l; 1415 return err; 1416} 1417 1418static int 1419_char_arr_ss(t_ext_ptr h, int quoted) 1420{ 1421 return strlen((char*) h) + (quoted? 2: 0); 1422} 1423 1424static int 1425_char_arr_tos(t_ext_ptr h, char *buf, int quoted) 1426{ 1427 char *dest = buf; 1428 char *src = (char*) h; 1429 if (quoted) 1430 { 1431 *dest++ = '"'; 1432 while (*dest++ = *src++) 1433 ; 1434 *(dest-1) = '"'; 1435 *dest++ = 0; 1436 } 1437 else 1438 { 1439 while (*dest++ = *src++) 1440 ; 1441 } 1442 return dest-buf-1; 1443} 1444 1445t_ext_type ec_xt_char_arr = { 1446 0, 0, 0, 1447 _char_arr_ss, 1448 _char_arr_tos, 1449 0, 0, 1450 _char_arr_get, 1451 _char_arr_set 1452}; 1453 1454