2
** Author(s): Jiyang Xu
3
** Contact: xsb-contact@cs.sunysb.edu
5
** Copyright (C) The Research Foundation of SUNY, 1986, 1993-1999
6
** Copyright (C) ECRC, Germany, 1990
8
** XSB is free software; you can redistribute it and/or modify it under the
9
** terms of the GNU Library General Public License as published by the Free
10
** Software Foundation; either version 2 of the License, or (at your option)
13
** XSB is distributed in the hope that it will be useful, but WITHOUT ANY
14
** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15
** FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for
18
** You should have received a copy of the GNU Library General Public License
19
** along with XSB; if not, write to the Free Software Foundation,
20
** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
** $Id: cinterf.c,v 1.66 2006/05/05 21:38:02 dwarren Exp $
26
#include "xsb_config.h"
27
#include "xsb_debug.h"
32
#if !defined(WIN_NT) || defined(CYGWIN)
39
#include "memory_xsb.h"
42
#include "flags_xsb.h"
51
#include "error_xsb.h"
52
#include "orient_xsb.h"
53
#include "loader_xsb.h"
57
This was the old test for being a kosher Prolog string
58
#define PRINTABLE_OR_ESCAPED_CHAR(Ch) (Ch <= 255 || Ch >= 0)
60
#define PRINTABLE_OR_ESCAPED_CHAR(Ch) \
61
((Ch >= (int)' ' && Ch <= (int)'~') || (Ch >= (int)'\a' && Ch <= (int)'\r'))
63
/* the following really belongs somewhere else */
64
extern char *expand_filename(char *);
65
extern void xsb_sprint_variable(CTXTdeclc char *sptr, CPtr var);
68
char *p_charlist_to_c_string(CTXTdeclc prolog_term term, VarString *buf,
69
char *in_func, char *where);
70
void c_string_to_p_charlist(CTXTdeclc char *name, prolog_term list,
71
int regs_to_protect, char *in_func, char *where);
73
/*======================================================================*/
74
/* Low level C interface */
75
/*======================================================================*/
77
DllExport xsbBool call_conv is_var(prolog_term term)
84
DllExport xsbBool call_conv is_int(prolog_term term)
88
return (isinteger(t) | isboxedinteger(t));
91
DllExport xsbBool call_conv is_float(prolog_term term)
98
DllExport xsbBool call_conv is_string(prolog_term term)
105
DllExport xsbBool call_conv is_atom(prolog_term term)
112
DllExport xsbBool call_conv is_list(prolog_term term)
119
DllExport xsbBool call_conv is_nil(prolog_term term)
126
DllExport xsbBool call_conv is_functor(prolog_term term)
133
DllExport xsbBool call_conv is_attv(prolog_term term)
140
DllExport prolog_term call_conv reg_term(CTXTdeclc reg_num regnum)
144
addr = cell(reg+regnum);
146
return (prolog_term)addr;
149
DllExport xsbBool call_conv c2p_int(CTXTdeclc Integer val, prolog_term var)
153
bind_oint(vptr(v), val);
156
xsb_warn("[C2P_INT] Argument 2 must be a variable");
161
DllExport xsbBool call_conv c2p_float(CTXTdeclc double val, prolog_term var)
165
bind_boxedfloat(vptr(v), (Float)(val));
168
xsb_warn("[C2P_FLOAT] Argument 2 must be a variable");
173
DllExport xsbBool call_conv c2p_string(CTXTdeclc char *val, prolog_term var)
177
bind_string(vptr(v), (char *)string_find(val, 1));
180
xsb_warn("[C2P_STRING] Argument 2 must be a variable");
185
DllExport xsbBool call_conv c2p_list(CTXTdeclc prolog_term var)
192
bind_list(vptr(v), sreg);
195
xsb_warn("[C2P_LIST] Argument must be a variable");
200
DllExport xsbBool call_conv c2p_nil(CTXTdeclc prolog_term var)
207
xsb_warn("[C2P_NIL] Argument must be a variable");
212
DllExport void call_conv c2p_setfree(prolog_term var)
218
/* space is space in words required; regcnt is number of registers to protect */
219
DllExport void call_conv ensure_heap_space(CTXTdeclc int space, int regcnt) {
220
check_glstack_overflow(regcnt,pcreg,space);
223
DllExport xsbBool call_conv c2p_functor(CTXTdeclc char *functor, int arity,
230
sym = (Pair)insert(functor, (byte)arity, (Psc)flags[CURRENT_MODULE], &i);
233
bind_cs(vptr(v), sreg);
234
new_heap_functor(sreg, sym->psc_ptr);
235
for (i=0; i<arity; sreg++,i++) { bld_free(sreg); }
238
xsb_warn("[C2P_FUNCTOR] Argument 3 must be a variable");
243
DllExport Integer call_conv p2c_int(prolog_term term)
249
DllExport double call_conv p2c_float(prolog_term term)
252
return (double)(ofloat_val(t));
255
DllExport char* call_conv p2c_string(prolog_term term)
258
return string_val(t);
261
DllExport char* call_conv p2c_functor(prolog_term term)
264
return get_name(get_str_psc(t));
267
DllExport int call_conv p2c_arity(prolog_term term)
270
return get_arity(get_str_psc(t));
273
DllExport prolog_term call_conv p2p_arg(prolog_term term, int argno)
277
t = cell(clref_val(t)+argno);
279
return (prolog_term)t;
282
DllExport prolog_term call_conv p2p_car(prolog_term term)
286
t = cell(clref_val(t));
288
return (prolog_term)t;
291
DllExport prolog_term call_conv p2p_cdr(prolog_term term)
295
t = cell(clref_val(t)+1);
297
return (prolog_term)t;
300
DllExport prolog_term call_conv p2p_new(CTXTdecl)
304
return (prolog_term)(cell(t));
307
DllExport xsbBool call_conv p2p_unify(CTXTdeclc prolog_term term1, prolog_term term2)
309
return unify(CTXTc term1, term2);
312
DllExport prolog_term call_conv p2p_deref(prolog_term term)
316
return (prolog_term)t;
320
/* convert Arg 1 -- prolog list of characters (a.k.a. prolog string) into C
321
string and return this string. A character is an integer 1 through 255
322
(i.e., not necessarily printable)
323
Arg 2: ptr to string buffer where the result is to be returned.
324
Space for this buffer must already be allocated.
325
Arg 3: which function was called from.
326
Arg 4: where in the call this happened.
327
Args 3 and 4 are used for error reporting.
328
This function converts escape sequences in the Prolog string
329
(except octal/hexadecimal escapes) into the corresponding real characters.
331
char *p_charlist_to_c_string(CTXTdeclc prolog_term term, VarString *buf,
332
char *in_func, char *where)
336
int escape_mode=FALSE;
337
prolog_term list = term, list_head;
339
if (!is_list(list) && !is_nil(list)) {
340
xsb_abort("[%s] %s is not a list of characters", in_func, where);
345
while (is_list(list)) {
346
if (is_nil(list)) break;
347
list_head = p2p_car(list);
348
if (!is_int(list_head)) {
349
xsb_abort("[%s] A Prolog string (a character list) expected, %s",
352
head_val = int_val(list_head);
353
if (! PRINTABLE_OR_ESCAPED_CHAR(head_val) ) {
354
xsb_abort("[%s] A Prolog string (a character list) expected, %s",
358
*head_char = (char) head_val;
359
/* convert ecape sequences */
361
switch (*head_char) {
363
XSB_StrAppendBlk(buf, "\a", 1);
366
XSB_StrAppendBlk(buf, "\b", 1);
369
XSB_StrAppendBlk(buf, "\f", 1);
372
XSB_StrAppendBlk(buf, "\n", 1);
375
XSB_StrAppendBlk(buf, "\r", 1);
378
XSB_StrAppendBlk(buf, "\t", 1);
381
XSB_StrAppendBlk(buf, "\v", 1);
384
XSB_StrAppendBlk(buf, head_char, 1);
387
XSB_StrAppendBlk(buf, head_char, 1);
389
if (*head_char == '\\' && !escape_mode) {
391
buf->length--; /* backout the last char */
396
list = p2p_cdr(list);
399
XSB_StrNullTerminate(buf);
401
return (buf->string);
405
/* convert a C string into a prolog list of characters.
406
(codelist might be a better suffix.)
407
LIST must be a Prolog variable. IN_FUNC is a string that should indicate the
408
high-level function from this c_string_to_p_charlist was called.
409
regs_to_protect is the number of registers with values (needed for stack expansion)
410
WHERE is another string with additional info. These two are used to provide
411
informative error messages to the user. */
412
void c_string_to_p_charlist(CTXTdeclc char *name, prolog_term list,
413
int regs_to_protect, char *in_func, char *where)
417
int len=strlen(name), i;
419
if (isnonvar(list)) {
420
xsb_abort("[%s] A variable expected, %s", in_func, where);
423
bind_nil((CPtr)(list));
425
check_glstack_overflow(regs_to_protect, pcreg, 2*len*sizeof(Cell));
426
new_list = makelist(hreg);
427
for (i = 0; i < len; i++) {
428
follow(hreg++) = makeint(*(unsigned char *)name);
431
follow(top) = makelist(hreg);
432
} follow(top) = makenil;
433
unify(CTXTc list, new_list);
438
/* The following function checks if a given term is a prolog string of
439
printable characters.
440
It also counts the size of the list.
441
It deals with the same escape sequences as p_charlist_to_c_string.
444
DllExport xsbBool call_conv is_charlist(prolog_term term, int *size)
446
int escape_mode=FALSE, head_char;
447
prolog_term list, head;
452
/* apparently, is_nil can be true and is_list false?? */
459
while (is_list(list)) {
460
if (is_nil(list)) break;
462
head = p2p_car(list);
466
head_char = (char) int_val(head);
467
/* ' ' is the lowest printable ascii and '~' is the highest */
468
if (! PRINTABLE_OR_ESCAPED_CHAR(head_char) )
487
if (head_char == '\\')
491
list = p2p_cdr(list);
496
/* the following two functions were introduced by Luis Castro */
497
/* they extend the c interface to allow for an easy interface for
498
lists of characters */
500
DllExport char *call_conv p2c_chars(CTXTdeclc prolog_term term, char *buf, int bsize)
502
XSB_StrDefine(bufvar);
504
p_charlist_to_c_string(CTXTc term, &bufvar, "p2c_chars", "list -> char*");
506
if (strlen(bufvar.string) > (size_t) bsize) {
507
xsb_abort("Buffer overflow in p2c_chars");
510
return strcpy(buf,bufvar.string);
513
DllExport void call_conv c2p_chars(CTXTdeclc char *str, int regs_to_protect, prolog_term term)
515
c_string_to_p_charlist(CTXTc str,term,regs_to_protect,"c2p_chars", "char* -> list");
520
** Constaints and internal data structures
524
#include "setjmp_xsb.h"
526
static char *c_dataptr_rest;
529
static jmp_buf cinterf_env;
533
** procedure cppc_error
537
static void cppc_error(CTXTdeclc int num)
539
longjmp(cinterf_env, num);
543
** procedure skip_subfmt
547
static char *skip_subfmt(CTXTdeclc char *ptr, char quote)
550
if (*ptr == quote) return ++ptr;
551
else if (*ptr == '[') ptr = skip_subfmt(CTXTc ++ptr, ']');
552
else if (*ptr == '(') ptr = skip_subfmt(CTXTc ++ptr, ')');
556
return ptr; /* never reach here */
560
** procedure count_arity
562
** count Prolog term size (arity). Ignored fields are not counted
565
static int count_arity(CTXTdeclc char *ptr, int quote)
569
while (*ptr && arity <= MAX_ARITY) {
570
if (*ptr == quote) return arity;
571
else if (*ptr == '%') {
572
if (*(++ptr)!='*') arity++;
573
} else if (*ptr == '[') ptr = skip_subfmt(CTXTc ++ptr, ']');
574
else if (*ptr == '(') ptr = skip_subfmt(CTXTc ++ptr, ')');
578
return -1; /* never reach here */
582
** procedure count_fields
584
** count number of fields in the primary structure.
585
** should be the same as arity + ignored fields.
588
static int count_fields(CTXTdeclc char *ptr, int quote)
592
while (*ptr && fields <= MAX_ARITY) {
593
if (*ptr == quote) return fields;
594
else if (*ptr == '%') { fields++; ptr++; }
595
else if (*ptr == '[') ptr = skip_subfmt(CTXTc ++ptr, ']');
596
else if (*ptr == '(') ptr = skip_subfmt(CTXTc ++ptr, ')');
600
return -1; /* never reach here */
604
** procedure count_csize
606
** count C struct size (number of bytes). Ignored fields are also counted
609
static int count_csize(CTXTdeclc char *ptr, int quote)
614
if (*ptr == quote) return size;
615
else if (*ptr == '%') {
616
if (*(++ptr)=='*') ptr++;
618
case 'f': size += sizeof(float); ptr++; break;
619
case 'd': size += sizeof(double); ptr++; break;
620
case 'i': size += sizeof(int); ptr++; break;
621
case 'c': size += 1; ptr++; break;
622
case 's': size += sizeof(char *); ptr++; break;
623
case 'z': ptr++; size += 4 * (*ptr-'0'); ptr++; break;
624
case 't': size += sizeof(int *);
626
skip_subfmt(CTXTc ptr, ')');
628
case 'l': size += sizeof(int *);
630
skip_subfmt(CTXTc ptr, ')');
633
size += count_csize(CTXTc ++ptr, ']');
634
skip_subfmt(CTXTc ptr, ']');
646
size += sizeof(int *); ptr++; break;
647
default: cppc_error(CTXTc 7); break;
652
return -1; /* never reach here */
656
** procedure ctop_term0
660
static char *ctop_term0(CTXTdeclc char *ptr, char *c_dataptr, char **subformat,
661
prolog_term variable, int ignore)
666
int argno, fields, i;
669
if (*ptr++!= '%') cppc_error(CTXTc 1);
671
if (ch=='*') ch = *ptr++;
675
if (!ignore) c2p_int(CTXTc *((int *)(c_dataptr)), variable);
676
c_dataptr_rest = c_dataptr + sizeof(int);
681
if (!ignore) c2p_int(CTXTc (int)(*(char *)(c_dataptr)), variable);
682
c_dataptr_rest = c_dataptr + 1;
687
if (!ignore) c2p_string(CTXTc *(char **)(c_dataptr), variable);
688
c_dataptr_rest = c_dataptr + sizeof(char*);
693
if (!ignore) c2p_string(CTXTc c_dataptr, variable);
695
c_dataptr_rest = c_dataptr + (ch -'0')*4;
700
if (!ignore) c2p_float(CTXTc (double)(*((float *)(c_dataptr))), variable);
701
c_dataptr_rest = c_dataptr + sizeof(float);
706
if (!ignore) c2p_float(CTXTc *((double *)(c_dataptr)), variable);
707
c_dataptr_rest = c_dataptr + sizeof(double);
712
fields = count_fields(CTXTc ptr, ']');
714
argno = count_arity(CTXTc ptr, ']');
715
if (!is_functor(variable)) c2p_functor(CTXTc "c2p", argno, variable);
718
for (i = 1; i <= fields; i++) {
719
if (*(ptr+1)=='*') ignore1 = 1;
720
else { ignore1 = ignore; argno++; }
721
ptr = ctop_term0(CTXTc ptr,c_dataptr,subformat,p2p_arg(variable,argno),ignore1);
722
c_dataptr = c_dataptr_rest;
724
ptr = skip_subfmt(CTXTc ptr, ']');
730
if (*(char **)(c_dataptr)) {
731
fmtnum = (int)(*ptr-'0');
732
subformat[fmtnum] = ptr-2;
734
if (*(ptr++) !='(') cppc_error(CTXTc 2);
735
argno = count_arity(CTXTc ptr, ')');
736
fields = count_fields(CTXTc ptr, ')');
737
if (!is_functor(variable)) c2p_functor(CTXTc "c2p", argno, variable);
738
cdptr2 = * (char **)(c_dataptr);
740
for (i = 1; i <= fields; i++) {
741
if (*(ptr+1)=='*') ignore = 1;
742
else { ignore = 0; argno++; }
743
ptr = ctop_term0(CTXTc ptr,cdptr2,subformat,p2p_arg(variable,argno),ignore);
744
cdptr2 = c_dataptr_rest;
746
} else c2p_nil(CTXTc variable);
748
ptr = skip_subfmt(CTXTc ptr, ')');
749
c_dataptr_rest = c_dataptr + 4;
754
if (*(char **)(c_dataptr)) {
755
fmtnum = (int)(*ptr-'0');
756
subformat[fmtnum] = ptr-2;
758
if (*(ptr++) != '(') cppc_error(CTXTc 3);
759
argno = count_arity(CTXTc ptr, ')');
760
fields = count_fields(CTXTc ptr, ')');
761
if (!is_list(variable)) c2p_list(CTXTc variable);
762
cdptr2 = * (char **)(c_dataptr);
764
for (i = 1; i <= fields; i++) {
765
if (*(ptr+1)=='*') ignore = 1;
766
else { ignore = 0; argno++; }
768
ptr = ctop_term0(CTXTc ptr,cdptr2,subformat,p2p_car(variable),ignore);
770
ptr = ctop_term0(CTXTc ptr,cdptr2,subformat,p2p_cdr(variable),ignore);
772
ptr = ctop_term0(CTXTc ptr,cdptr2,subformat,p2p_car(variable),ignore);
774
else cppc_error(CTXTc 30);
775
cdptr2 = c_dataptr_rest;
777
} else c2p_nil(CTXTc variable);
779
ptr = skip_subfmt(CTXTc ptr, ')');
780
c_dataptr_rest = c_dataptr + 4;
795
if (*(char **)(c_dataptr)) {
796
ctop_term0(CTXTc subformat[ch-'0'], c_dataptr, subformat,variable, 0);
797
} else c2p_nil(CTXTc variable);
799
c_dataptr_rest = c_dataptr + 4;
802
default: cppc_error(CTXTc 4);
808
** procedure ptoc_term0
812
static char *ptoc_term0(CTXTdeclc char *ptr, char *c_dataptr, char **subformat,
813
prolog_term variable, int ignore)
818
int argno, fields, i, size;
821
if (*ptr++!= '%') cppc_error(CTXTc 9);
823
if (ch=='*') ch = *ptr++;
828
if (is_int(variable)) *((int *)(c_dataptr)) = p2c_int(variable);
829
else cppc_error(CTXTc 10);
831
c_dataptr_rest = c_dataptr + sizeof(int);
837
if (is_int(variable)) *((char *)(c_dataptr)) =
838
(char)p2c_int(variable);
839
else cppc_error(CTXTc 11);
841
c_dataptr_rest = c_dataptr + 1;
847
if (is_string(variable)) *((char **)(c_dataptr)) =
848
p2c_string(variable); /* should make a copy??? */
849
else cppc_error(CTXTc 12);
851
c_dataptr_rest = c_dataptr + 4;
857
size = 4 * (ch - '0');
859
if (is_string(variable))
860
strncpy(c_dataptr, p2c_string(variable), size);
861
else cppc_error(CTXTc 12);
863
c_dataptr_rest = c_dataptr + size;
869
if (is_float(variable))
870
*((float *)(c_dataptr)) = (float)p2c_float(variable);
871
else cppc_error(CTXTc 13);
873
c_dataptr_rest = c_dataptr + sizeof(float);
879
if (is_float(variable)) *((double *)(c_dataptr)) =
881
else cppc_error(CTXTc 14);
883
c_dataptr_rest = c_dataptr + sizeof(double);
888
fields = count_fields(CTXTc ptr, ']');
890
for (i = 1; i <= fields; i++) {
891
if (*(ptr+1)=='*') ignore1 = 1;
892
else { ignore1 = ignore; argno++; }
893
ptr = ptoc_term0(CTXTc ptr, c_dataptr,subformat,p2p_arg(variable,argno),ignore1);
894
c_dataptr = c_dataptr_rest;
896
ptr = skip_subfmt(CTXTc ptr, ']');
902
fmtnum = (int)(*ptr-'0');
903
subformat[fmtnum] = ptr-2;
905
if (*(ptr++) != '(') cppc_error(CTXTc 15);
906
fields = count_fields(CTXTc ptr, ')');
907
size = count_csize(CTXTc ptr, ')');
908
cdptr2 = (char *)mem_alloc(size,OTHER_SPACE); /* leak */
909
*((char **)c_dataptr) = cdptr2;
911
for (i = 1; i <= fields; i++) {
912
if (*(ptr+1)=='*') ignore = 1;
913
else { ignore = 0; argno++; }
914
ptr = ptoc_term0(CTXTc ptr,cdptr2,subformat,p2p_arg(variable,argno),ignore);
915
cdptr2 = c_dataptr_rest;
918
ptr = skip_subfmt(CTXTc ptr, ')');
919
c_dataptr_rest = c_dataptr + 4;
924
fmtnum = (int)(*ptr-'0');
925
subformat[fmtnum] = ptr-2;
927
if (*(ptr++)!='(') cppc_error(CTXTc 16);
928
fields = count_fields(CTXTc ptr, ')');
929
size = count_csize(CTXTc ptr, ')');
930
cdptr2 = (char *)mem_alloc(size,OTHER_SPACE); /* leak */
931
*((char **)c_dataptr) = cdptr2;
933
for (i = 1; i <= fields; i++) {
934
if (*(ptr+1)=='*') ignore = 1;
935
else { ignore = 0; argno++; }
937
ptr = ptoc_term0(CTXTc ptr,cdptr2,subformat,p2p_car(variable),ignore);
939
ptr = ptoc_term0(CTXTc ptr,cdptr2,subformat,p2p_cdr(variable),ignore);
940
else cppc_error(CTXTc 31);
941
cdptr2 = c_dataptr_rest;
944
ptr = skip_subfmt(CTXTc ptr, ')');
945
c_dataptr_rest = c_dataptr + 4;
960
if (!is_nil(variable)) {
961
ptoc_term0(CTXTc subformat[ch-'0'], c_dataptr, subformat, variable, 0);
962
} else *(int *)(c_dataptr) = 0;
964
c_dataptr_rest = c_dataptr + 4;
967
default: cppc_error(CTXTc 17);
973
** procedure ctop_term
977
int ctop_term(CTXTdeclc char *fmt, char *c_dataptr, reg_num regnum)
979
prolog_term variable;
983
variable = reg_term(CTXTc regnum);
984
if ((my_errno = setjmp(cinterf_env))) return my_errno; /* catch an exception */
985
ctop_term0(CTXTc fmt, c_dataptr, subformat, variable, 0);
990
** procedure ptoc_term
994
int ptoc_term(CTXTdeclc char *fmt, char *c_dataptr, reg_num regnum)
996
prolog_term variable;
1000
variable = reg_term(CTXTc regnum);
1001
if ((my_errno = setjmp(cinterf_env))) return my_errno; /* catch an exception */
1002
ptoc_term0(CTXTc fmt, c_dataptr, subformat, variable, 0);
1007
** procedure c2p_term
1011
int c2p_term(CTXTdeclc char *fmt, char *c_dataptr, prolog_term variable)
1014
char *subformat[10];
1016
if ((my_errno = setjmp(cinterf_env))) return my_errno; /* catch an exception */
1017
ctop_term0(CTXTc fmt, c_dataptr, subformat, variable, 0);
1022
** procedure p2c_term
1026
int p2c_term(CTXTdeclc char *fmt, char *c_dataptr, prolog_term variable)
1029
char *subformat[10];
1031
if ((my_errno = setjmp(cinterf_env))) return my_errno; /* catch an exception */
1032
ptoc_term0(CTXTc fmt, c_dataptr, subformat, variable, 0);
1035
/* quick test to see whether atom must be quoted */
1036
int mustquote(char *atom)
1040
if (!(atom[0] >= 'a' && atom[0] <= 'z')) return TRUE;
1041
for (i=1; atom[i] != '\0'; i++) {
1042
if (!((atom[i] >= 'a' && atom[i] <= 'z') ||
1043
(atom[i] >= 'A' && atom[i] <= 'Z') ||
1045
(atom[i] >= '0' && atom[i] <= '9')
1051
/* copy a string (quoted if !toplevel and necessary) into a buffer. */
1052
void printpstring(char *atom, int toplevel, VarString *straddr)
1056
if (toplevel || !mustquote(atom)) {
1057
XSB_StrAppend(straddr,atom);
1059
XSB_StrAppendBlk(straddr, "'", 1);
1060
for (i = 0; atom[i] != '\0'; i++) {
1061
XSB_StrAppendBlk(straddr, atom+i, 1);
1062
if (atom[i] == '\'')
1063
/* double the quotes in a quoted string */
1064
XSB_StrAppendBlk(straddr, "'", 1);
1066
XSB_StrAppend(straddr, "'");
1070
/* calculate approximate length of a printed term. For space alloc. */
1071
int clenpterm(prolog_term term)
1075
if (is_var(term)) return 11;
1076
else if (is_int(term)) return 12;
1077
else if (is_float(term)) return 12;
1078
else if (is_nil(term)) return 2;
1079
else if (is_string(term)) return strlen(p2c_string(term))+5;
1080
else if (is_list(term)) {
1082
clen += clenpterm(p2p_car(term)) + 1;
1083
while (is_list(term)) {
1084
clen += clenpterm(p2p_car(term)) + 1;
1085
term = p2p_cdr(term);
1087
if (!is_nil(term)) {
1088
clen += clenpterm(term) + 1;
1091
} else if (is_functor(term)) {
1092
clen = strlen(p2c_functor(term))+5;
1093
if (p2c_arity(term) > 0) {
1094
clen += clenpterm(p2p_arg(term,1)) + 1;
1095
for (i = 2; i <= p2c_arity(term); i++) {
1096
clen += clenpterm(p2p_arg(term,i)) + 1;
1101
xsb_warn("Unrecognized prolog term type");
1106
char tempstring[MAXBUFSIZE];
1108
/* print a prolog_term into a buffer.
1109
Atoms are quoted if !toplevel -- necessary for Prolog reading
1110
Buffer is a VarString. If the VarString is non-empty, the term is appended
1111
to the current contents of the VarString.
1113
DllExport void call_conv print_pterm(CTXTdeclc prolog_term term, int toplevel,
1119
xsb_sprint_variable(CTXTc tempstring, (CPtr) term);
1120
XSB_StrAppend(straddr,tempstring);
1121
} else if (is_attv(term)) {
1122
xsb_sprint_variable(CTXTc tempstring, (CPtr) dec_addr(term));
1123
XSB_StrAppend(straddr,tempstring);
1124
} else if (is_int(term)) {
1125
sprintf(tempstring,"%d", (int) p2c_int(term));
1126
XSB_StrAppend(straddr,tempstring);
1127
} else if (is_float(term)) {
1128
sprintf(tempstring,"%f", (float) p2c_float(term));
1129
XSB_StrAppend(straddr,tempstring);
1130
} else if (is_nil(term)) {
1131
XSB_StrAppend(straddr,"[]");
1132
} else if (is_string(term)) {
1133
printpstring(p2c_string(term),toplevel,straddr);
1134
} else if (is_list(term)) {
1135
XSB_StrAppend(straddr, "[");
1136
print_pterm(CTXTc p2p_car(term),FALSE,straddr);
1137
term = p2p_cdr(term);
1138
while (is_list(term)) {
1139
XSB_StrAppend(straddr, ",");
1140
print_pterm(CTXTc p2p_car(term),FALSE,straddr);
1141
term = p2p_cdr(term);
1143
if (!is_nil(term)) {
1144
XSB_StrAppend(straddr, "|");
1145
print_pterm(CTXTc term,FALSE,straddr);
1147
XSB_StrAppend(straddr, "]");
1148
} else if (is_functor(term)) {
1149
printpstring(p2c_functor(term),FALSE,straddr);
1150
if (p2c_arity(term) > 0) {
1151
XSB_StrAppend(straddr, "(");
1152
print_pterm(CTXTc p2p_arg(term,1),FALSE,straddr);
1153
for (i = 2; i <= p2c_arity(term); i++) {
1154
XSB_StrAppend(straddr, ",");
1155
print_pterm(CTXTc p2p_arg(term,i),FALSE,straddr);
1157
XSB_StrAppend(straddr, ")");
1159
} else xsb_warn("[PRINT_PTERM] Unrecognized prolog term type");
1162
/************************************************************************/
1164
/* xsb_answer_string copies an answer from reg 2 into ans. */
1166
/************************************************************************/
1167
int xsb_answer_string(CTXTdeclc VarString *ans, char *sep)
1171
if (!is_string(reg_term(CTXTc 2))) {
1172
for (i=1; i<p2c_arity(reg_term(CTXTc 2)); i++) {
1173
print_pterm(CTXTc p2p_arg(reg_term(CTXTc 2),i),TRUE,ans);
1174
XSB_StrAppend(ans,sep);
1176
print_pterm(CTXTc p2p_arg(reg_term(CTXTc 2),p2c_arity(reg_term(CTXTc 2))),TRUE,ans);
1182
static long lastWarningStart = 0L;
1183
static inline void updateWarningStart(void)
1185
if(flags[STDERR_BUFFERED])
1186
lastWarningStart = ftell(stderr);
1189
/************************************************************************/
1191
/* xsb_init(argc,argv) initializes XSB to be called from C. */
1192
/* argc and argv are the arg count and arg vector as passed from the */
1193
/* command line. The parameters are used to set space sizes in xsb. */
1194
/* The parameters MUST include -i, which indicates that the main */
1195
/* interpreter is to be loaded, AND -n, which indicates that the */
1196
/* interpreter should not enter the usual read-eval-print loop, but */
1197
/* instead support the interface to the C caller. */
1198
/* If xsb has been previously initialized, nothing is done and 1 is */
1201
/************************************************************************/
1203
static int xsb_initted_gl = 0; /* if xsb has been called */
1204
static int xsb_inquery_gl = 0;
1206
DllExport int call_conv xsb_init(CTXTdeclc int argc, char *argv[])
1209
char executable1[MAXPATHLEN];
1212
updateWarningStart();
1213
if (!xsb_initted_gl)
1215
/* we rely on the caller to tell us in argv[0]
1216
the absolute or relative path name to the XSB installation directory */
1217
sprintf(executable1, "%s%cconfig%c%s%cbin%cxsb",
1218
argv[0], SLASH, SLASH, FULL_CONFIG_NAME, SLASH, SLASH);
1219
expfilename = expand_filename(executable1);
1220
strcpy(executable_path_gl, expfilename);
1221
mem_dealloc(expfilename,MAXPATHLEN,OTHER_SPACE);
1223
if (0 == (rc = xsb(CTXTc 0,argc,argv))) /* initialize xsb */
1225
if (0 == (rc = xsb(CTXTc 1,0,0))) /* enter xsb to set up regs */
1232
/************************************************************************/
1234
/* int xsb_cmd_string(char *cmdline, char **argv) takes a */
1235
/* command line string in cmdline, and parses it to return an argv */
1236
/* vector in its second argument, and the argc count as the value of */
1237
/* the function. (Will handle a max of 19 args.) */
1239
/************************************************************************/
1240
/*FILE *stream_err, *stream_out;*/
1242
DllExport int call_conv xsb_init_string(CTXTdeclc char *cmdline_param) {
1243
int i = 0, argc = 0;
1245
char cmdline[2*MAXPATHLEN+1];
1247
updateWarningStart();
1249
/*stream_err = freopen("XSB_errlog", "w", stderr);
1250
stream_out = freopen("XSB_outlog", "w", stdout);*/
1252
if (strlen(cmdline_param) > 2*MAXPATHLEN) {
1253
xsb_warn("**************************************************************************");
1254
xsb_warn("[XSB_INIT_STRING] %18s...: command used to call XSB server is too long",
1256
xsb_warn("**************************************************************************");
1259
strncpy(cmdline, cmdline_param, 2*MAXPATHLEN - 1);
1260
argv = (char **) mem_alloc(20*sizeof(char *),OTHER_SPACE); /* count space even if never released */
1262
while (cmdline[i] == ' ') i++;
1263
while (cmdline[i] != '\0') {
1264
if ((cmdline[i] == '"') || (cmdline[i] == '\'')) {
1268
argv[argc] = &(cmdline[i]);
1270
if (argc >= 19) {argc--; break;}
1271
while ((cmdline[i] != delim) && (cmdline[i] != '\0')) i++;
1272
if (cmdline[i] == '\0') break;
1275
while (cmdline[i] == ' ') i++;
1278
return xsb_init(CTXTc argc,argv);
1281
/************************************************************************/
1283
/* xsb_command() passes the command (i.e. query with no variables) to */
1284
/* xsb. The command must be put into xsb's register 1 as a term, by */
1285
/* the caller who uses the c2p_* (and perhaps p2p_*) functions. */
1286
/* It returns 0 if it succeeds, 1 if it fails, in either case */
1287
/* resetting register 1 back to a free variable. It returns 2 if there */
1290
/************************************************************************/
1292
DllExport int call_conv xsb_command(CTXTdecl)
1294
if (xsb_inquery_gl) return(2); /* error */
1295
updateWarningStart();
1296
c2p_int(CTXTc 0,reg_term(CTXTc 3)); /* command for calling a goal */
1298
if (is_var(reg_term(CTXTc 1))) return(1); /* goal failed, so return 1 */
1299
c2p_int(CTXTc 1,reg_term(CTXTc 3)); /* command for next answer */
1301
if (is_var(reg_term(CTXTc 1))) return(0); /* goal succeeded */
1302
(void) xsb_close_query(CTXT);
1306
/************************************************************************/
1308
/* xsb_command_string(char *goal) passes the command (e.g. a query */
1309
/* which only succeeds or fails) to xsb. The command must a string */
1310
/* passed in the argument. It returns 0 if it succeeds, 1 if it */
1311
/* fails, in either case resetting register 1 back to a free */
1312
/* variable. It returns 2 if there is an error. */
1314
/************************************************************************/
1316
DllExport int call_conv xsb_command_string(CTXTdeclc char *goal)
1318
if (xsb_inquery_gl) return(2); /* error */
1319
updateWarningStart();
1320
c2p_string(CTXTc goal,reg_term(CTXTc 1));
1321
c2p_int(CTXTc 2,reg_term(CTXTc 3)); /* command for calling a string goal */
1323
if (is_var(reg_term(CTXTc 1))) return(1); /* goal failed, so return 1 */
1324
c2p_int(CTXTc 1,reg_term(CTXTc 3)); /* command for next answer */
1326
if (is_var(reg_term(CTXTc 1))) return(0); /* goal succeeded */
1327
(void) xsb_close_query(CTXT);
1331
/************************************************************************/
1333
/* xsb_query() submits a query to xsb. The query must have been put into*/
1334
/* xsb's register 1 by the caller, using p2c_* (and perhaps p2p_*). Xsb*/
1335
/* will evaluate the query and return with the variables in the query */
1336
/* bound to the first answer. In addition, register 2 will contain a */
1337
/* Prolog term of the form ret(V1,V2,..,Vn) with as many Vi's as */
1338
/* variables in the original query and with Vi bound to the value for */
1339
/* that variable in the first answer. If the query fails, it returns 1.*/
1340
/* If the query succeeds, it returns 0. If there is an error, it returns*/
1343
/************************************************************************/
1345
DllExport int call_conv xsb_query(CTXTdecl)
1347
if (xsb_inquery_gl) return(2);
1348
updateWarningStart();
1349
c2p_int(CTXTc 0,reg_term(CTXTc 3)); /* set command for calling a goal */
1351
if (is_var(reg_term(CTXTc 1))) return(1);
1356
/************************************************************************/
1358
/* xsb_query_string(char *) submits a query to xsb. The string must
1359
be a goal that will be correctly read by xsb's reader, and it must
1360
be terminated with a period (.). Register 2 may be a variable or
1361
it may be a term of the form ret(X1,X2,...,Xn), where n is the
1362
number of variables in the query. The query will be parsed, and an
1363
answer term of the form ret(Y1,Y2,...,Yn) will be constructed where
1364
Y1, .... Yn are the variables in the parsed goal (in left-to-right
1365
order). This answer term is unified with the argument in register
1366
2. Then the goal is called. If the goal succeeds,
1367
xsb_query_string returns 0 and the first answer is in register 2.
1368
If it fails, xsb_query_string returns 1. */
1370
/************************************************************************/
1372
DllExport int call_conv xsb_query_string(CTXTdeclc char *goal)
1374
if (xsb_inquery_gl) return(2);
1375
updateWarningStart();
1376
c2p_chars(CTXTc goal,2,reg_term(CTXTc 1));
1377
c2p_int(CTXTc 2,reg_term(CTXTc 3)); /* set command for calling a string goal */
1379
if (is_var(reg_term(CTXTc 1))) return(1);
1384
/************************************************************************/
1386
/* xsb_query_string_string calls xsb_query_string and returns */
1387
/* the answer in a string. The answer is copied into ans, */
1388
/* a VarString provided by the caller. Variable */
1389
/* values are separated by the string sep. */
1391
/************************************************************************/
1393
int call_conv xsb_query_string_string(CTXTdeclc char *goal,
1394
VarString *ans, char *sep)
1398
rc = xsb_query_string(CTXTc goal);
1399
if (rc > 0) return rc;
1400
return xsb_answer_string(CTXTc ans,sep);
1403
/************************************************************************/
1405
/* xsb_query_string_string_b calls xsb_query_string and returns */
1406
/* the answer in a string. The caller provides a buffer and its */
1407
/* length. If the answer fits in the buffer, it is returned */
1408
/* there, and its length is returned. If not, then the length is */
1409
/* returned, and the answer can be obtained by calling */
1410
/* xsb_get_last_answer. */
1412
/************************************************************************/
1413
#ifndef MULTI_THREAD
1414
static XSB_StrDefine(last_answer_lc);
1415
#define last_answer (&last_answer_lc)
1418
int call_conv xsb_query_string_string_b(CTXTdeclc
1419
char *goal, char *buff, int buflen, int *anslen, char *sep)
1423
XSB_StrSet(last_answer,"");
1424
rc = xsb_query_string_string(CTXTc goal,last_answer,sep);
1425
if (rc > 0) return rc;
1426
*anslen = last_answer->length;
1427
XSB_StrNullTerminate(last_answer);
1428
if (last_answer->length < buflen) {
1429
strcpy(buff,last_answer->string);
1434
/************************************************************************/
1436
/* xsb_get_last_answer_string returns previous answer. */
1438
/************************************************************************/
1439
DllExport int call_conv
1440
xsb_get_last_answer_string(CTXTdeclc char *buff, int buflen, int *anslen) {
1442
*anslen = last_answer->length;
1443
if (last_answer->length < buflen) {
1444
strcpy(buff,last_answer->string);
1450
/************************************************************************/
1452
/* xsb_next() causes xsb to return the next answer. It (or */
1453
/* xsb_close_query) must be called after xsb_query. If there is */
1454
/* another answer, xsb_next returns 0 and the variables in goal term */
1455
/* (in xsb register 1) are bound to the answer values. In addition */
1456
/* xsb register 2 will contain a term of the form ret(V1,V2,...,Vn) */
1457
/* where the Vi's are the values for the variables for the next */
1459
/* xsb_next returns 0 if the next is found, 1 if there are no more */
1460
/* answers, and 3 if an error is encountered. If 1 is returned, then */
1461
/* the query is automatically closed. */
1463
/************************************************************************/
1465
DllExport int call_conv xsb_next(CTXTdecl)
1467
if (!xsb_inquery_gl) return(2);
1468
updateWarningStart();
1469
c2p_int(CTXTc 0,reg_term(CTXTc 3)); /* set command for next answer */
1471
if (is_var(reg_term(CTXTc 1))) {
1477
/************************************************************************/
1479
/* xsb_next_string(ans,sep) calls xsb_next() and returns the */
1480
/* answer in the VarString ans, provided by the caller. */
1481
/* sep is a separator for the fields of the answer. */
1483
/************************************************************************/
1485
DllExport int call_conv xsb_next_string(CTXTdeclc VarString *ans, char *sep)
1487
int rc = xsb_next(CTXT);
1488
if (rc > 0) return rc;
1489
return xsb_answer_string(CTXTc ans,sep);
1492
/************************************************************************/
1494
/* xsb_next_string_b(buff,buflen,anslen,sep) calls xsb_next() and */
1495
/* returns the answer in buff, provided by the caller. The length */
1496
/* of buff is buflen. The length of the answer is put in anslen. */
1497
/* If the buffer is too small for the answer, nothing is put in */
1498
/* the buffer. In this case the caller can allocate a larger */
1499
/* and retrieve the buffer using xsb_get_last_answer. */
1501
/************************************************************************/
1503
DllExport int call_conv xsb_next_string_b(CTXTdeclc
1504
char *buff, int buflen, int *anslen, char *sep)
1508
XSB_StrSet(last_answer,"");
1509
rc = xsb_next_string(CTXTc last_answer,sep);
1510
if (rc > 0) return rc;
1511
*anslen = last_answer->length;
1512
XSB_StrNullTerminate(last_answer);
1513
if (last_answer->length < buflen) {
1514
strcpy(buff,last_answer->string);
1519
/************************************************************************/
1521
/* xsb_close_query() closes the current query, so that no more answers */
1522
/* will be returned, and another query can be opened. */
1523
/* If the query was correctly closed, it resets xsb registers 1 and 2 */
1524
/* to be variables, and returns 0. If there is some error, it returns */
1527
/************************************************************************/
1529
DllExport int call_conv xsb_close_query(CTXTdecl)
1531
updateWarningStart();
1532
if (!xsb_inquery_gl) return(2);
1533
c2p_int(CTXTc 1,reg_term(CTXTc 3)); /* set command for cut */
1535
if (is_var(reg_term(CTXTc 1))) {
1541
/************************************************************************/
1543
/* xsb_close() is currently just a noop, since it doesn't clean */
1544
/* anything up, to allow a re-init. */
1546
/************************************************************************/
1548
DllExport int call_conv xsb_close(CTXTdecl)
1550
updateWarningStart();
1551
if (xsb_initted_gl) return(0);
1557
// From: UNIX Application Migration Guide
1558
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnucmg/html/UCMGch10.asp
1560
// The version there won't compile as is, but it can be fixed...
1563
#include <Basetsd.h>
1564
#if !defined(CYGWIN)
1565
typedef SSIZE_T ssize_t;
1567
static inline ssize_t pread(int fd, void *buf, size_t count, long offset)
1569
if (-1 == lseek(fd,offset,SEEK_SET))
1571
return(read(fd,buf,count));
1575
// For concurrent access to a file (required for asynchronous I/O (AIO) support)
1576
// requires the pread() and pwrite() system calls to actually work
1577
// so let's use the real thing that way we can safely be multi-threaded.
1582
/************************************************************************/
1584
/* xsb_get_last_error_string returns previous answer. */
1586
/************************************************************************/
1587
DllExport int call_conv xsb_get_last_error_string(char *buff, int buflen, int *anslen)
1590
ssize_t bytesRead = 1;
1591
ssize_t totalBytesRead = 0;
1593
if(!flags[STDERR_BUFFERED])
1594
xsb_warn("[xsb_get_last_error_string] This feature must be activated with the -q option");
1597
rc = 1; // Assume failure on the ftell or read
1598
errno = 0; // Setup to detect error in ftell
1599
*anslen = (int)(ftell(stderr) - lastWarningStart);
1600
if((0 == errno) && (-1 < *anslen))
1602
if (*anslen >= buflen)
1603
rc = 3; // Not enough room in the target buffer
1606
while ((totalBytesRead < *anslen) && (0 < bytesRead) && !ferror(stderr))
1608
bytesRead = pread(fileno(stderr),&buff[totalBytesRead],(*anslen - totalBytesRead),(lastWarningStart + totalBytesRead));
1609
totalBytesRead += bytesRead;
1611
if (!ferror(stderr))
1614
if (-1 == bytesRead)
1615
*anslen = totalBytesRead + 1;
1617
*anslen = totalBytesRead;
1618
buff[*anslen] = 0x00;