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