cinterf.c

00001 /* File:      cinterf.c
00002 ** Author(s): Jiyang Xu
00003 ** Contact:   xsb-contact@cs.sunysb.edu
00004 ** 
00005 ** Copyright (C) The Research Foundation of SUNY, 1986, 1993-1999
00006 ** Copyright (C) ECRC, Germany, 1990
00007 ** 
00008 ** XSB is free software; you can redistribute it and/or modify it under the
00009 ** terms of the GNU Library General Public License as published by the Free
00010 ** Software Foundation; either version 2 of the License, or (at your option)
00011 ** any later version.
00012 ** 
00013 ** XSB is distributed in the hope that it will be useful, but WITHOUT ANY
00014 ** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00015 ** FOR A PARTICULAR PURPOSE.  See the GNU Library General Public License for
00016 ** more details.
00017 ** 
00018 ** You should have received a copy of the GNU Library General Public License
00019 ** along with XSB; if not, write to the Free Software Foundation,
00020 ** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00021 **
00022 ** $Id: cinterf.c,v 1.66 2006/05/05 21:38:02 dwarren Exp $
00023 ** 
00024 */
00025 
00026 #include "xsb_config.h"
00027 #include "xsb_debug.h"
00028 
00029 #include <stdio.h>
00030 #include <string.h>
00031 #include <stdlib.h>
00032 #if !defined(WIN_NT) || defined(CYGWIN)
00033 #include <unistd.h>
00034 #endif
00035 #include <errno.h>
00036 
00037 #include "auxlry.h"
00038 #include "cell_xsb.h"
00039 #include "memory_xsb.h"
00040 #include "register.h"
00041 #include "psc_xsb.h"
00042 #include "flags_xsb.h"
00043 #include "deref.h"
00044 #include "heap_xsb.h"
00045 #include "binding.h"
00046 #include "tries.h"
00047 #include "choice.h"
00048 #include "subp.h"
00049 #include "emuloop.h"
00050 #include "cinterf.h"
00051 #include "error_xsb.h"
00052 #include "orient_xsb.h"
00053 #include "loader_xsb.h"
00054 #include "context.h"
00055 
00056 /*
00057   This was the old test for being a kosher Prolog string
00058 #define PRINTABLE_OR_ESCAPED_CHAR(Ch) (Ch <= 255 || Ch >= 0)
00059 */
00060 #define PRINTABLE_OR_ESCAPED_CHAR(Ch) \
00061   ((Ch >= (int)' ' && Ch <= (int)'~') || (Ch >= (int)'\a' && Ch <= (int)'\r'))
00062 
00063 /* the following really belongs somewhere else */
00064 extern char *expand_filename(char *);
00065 extern void xsb_sprint_variable(CTXTdeclc char *sptr, CPtr var);
00066 
00067 
00068 char *p_charlist_to_c_string(CTXTdeclc prolog_term term, VarString *buf,
00069                              char *in_func, char *where);
00070 void c_string_to_p_charlist(CTXTdeclc char *name, prolog_term list,
00071                             int regs_to_protect, char *in_func, char *where);
00072 
00073 /*======================================================================*/
00074 /* Low level C interface                                                */
00075 /*======================================================================*/
00076 
00077 DllExport xsbBool call_conv is_var(prolog_term term)
00078 {
00079     Cell t = (Cell)term;
00080     XSB_Deref(t);
00081     return isref(t);
00082 }
00083 
00084 DllExport xsbBool call_conv is_int(prolog_term term)
00085 {
00086     Cell t = (Cell)term;
00087     XSB_Deref(t);
00088     return (isinteger(t) | isboxedinteger(t));
00089 }
00090 
00091 DllExport xsbBool call_conv is_float(prolog_term term)
00092 {
00093     Cell t = (Cell)term;
00094     XSB_Deref(t);
00095     return isofloat(t);
00096 }
00097 
00098 DllExport xsbBool call_conv is_string(prolog_term term)
00099 {
00100     Cell t = (Cell)term;
00101     XSB_Deref(t);
00102     return isstring(t);
00103 }
00104 
00105 DllExport xsbBool call_conv is_atom(prolog_term term)
00106 {
00107     Cell t = (Cell)term;
00108     XSB_Deref(t);
00109     return isatom(t);
00110 }
00111 
00112 DllExport xsbBool call_conv is_list(prolog_term term)
00113 {
00114     Cell t = (Cell)term;
00115     XSB_Deref(t);
00116     return islist(t);
00117 }
00118 
00119 DllExport xsbBool call_conv is_nil(prolog_term term)
00120 {
00121     Cell t = (Cell)term;
00122     XSB_Deref(t);
00123     return isnil(t);
00124 }
00125 
00126 DllExport xsbBool call_conv is_functor(prolog_term term)
00127 {
00128     Cell t = (Cell)term;
00129     XSB_Deref(t);
00130     return isconstr(t);
00131 }
00132 
00133 DllExport xsbBool call_conv is_attv(prolog_term term)
00134 {
00135     Cell t = (Cell)term;
00136     XSB_Deref(t);
00137     return isattv(t);
00138 }
00139 
00140 DllExport prolog_term call_conv reg_term(CTXTdeclc reg_num regnum)
00141 {
00142     register Cell addr;
00143 
00144     addr = cell(reg+regnum);
00145     XSB_Deref(addr);
00146     return (prolog_term)addr;
00147 }
00148 
00149 DllExport xsbBool call_conv c2p_int(CTXTdeclc Integer val, prolog_term var)
00150 {
00151     Cell v = (Cell)var;
00152     if (is_var(v)) {
00153       bind_oint(vptr(v), val);
00154       return TRUE;
00155     } else {
00156       xsb_warn("[C2P_INT] Argument 2 must be a variable");
00157       return FALSE;
00158     }
00159 }
00160 
00161 DllExport xsbBool call_conv c2p_float(CTXTdeclc double val, prolog_term var)
00162 {
00163     Cell v = (Cell)var;
00164     if (is_var(v)) {
00165         bind_boxedfloat(vptr(v), (Float)(val));
00166         return TRUE;
00167     } else {
00168         xsb_warn("[C2P_FLOAT] Argument 2 must be a variable");
00169         return FALSE;
00170     }
00171 }
00172 
00173 DllExport xsbBool call_conv c2p_string(CTXTdeclc char *val, prolog_term var)
00174 {
00175     Cell v = (Cell)var;
00176     if (is_var(v)) {
00177         bind_string(vptr(v), (char *)string_find(val, 1));
00178         return TRUE;
00179     } else {
00180         xsb_warn("[C2P_STRING] Argument 2 must be a variable");
00181         return FALSE;
00182     }
00183 }
00184 
00185 DllExport xsbBool call_conv c2p_list(CTXTdeclc prolog_term var)
00186 {
00187     Cell v = (Cell)var;
00188     if (is_var(v)) {
00189         sreg = hreg;
00190         new_heap_free(hreg);
00191         new_heap_free(hreg);
00192         bind_list(vptr(v), sreg);
00193         return TRUE;
00194     } else {
00195         xsb_warn("[C2P_LIST] Argument must be a variable");
00196         return FALSE;
00197     }
00198 }
00199 
00200 DllExport xsbBool call_conv c2p_nil(CTXTdeclc prolog_term var)
00201 {
00202     Cell v = (Cell)var;
00203     if (is_var(v)) {
00204        bind_nil(vptr(v));
00205        return TRUE;
00206     } else {
00207         xsb_warn("[C2P_NIL] Argument must be a variable");
00208         return FALSE;
00209     }
00210 }
00211 
00212 DllExport void call_conv c2p_setfree(prolog_term var)
00213 {
00214     CPtr v = (CPtr)var;
00215     bld_free(v);
00216 }
00217 
00218 /* space is space in words required; regcnt is number of registers to protect */
00219 DllExport void call_conv ensure_heap_space(CTXTdeclc int space, int regcnt) {
00220   check_glstack_overflow(regcnt,pcreg,space);
00221 }
00222 
00223 DllExport xsbBool call_conv c2p_functor(CTXTdeclc char *functor, int arity, 
00224                                         prolog_term var)
00225 {
00226     Cell v = (Cell)var;
00227     Pair sym;
00228     int i;
00229     if (is_var(v)) {
00230         sym = (Pair)insert(functor, (byte)arity, (Psc)flags[CURRENT_MODULE], &i);
00231         sreg = hreg;
00232         hreg += arity + 1;
00233         bind_cs(vptr(v), sreg);
00234         new_heap_functor(sreg, sym->psc_ptr);
00235         for (i=0; i<arity; sreg++,i++) { bld_free(sreg); }
00236         return TRUE;
00237     } else {
00238         xsb_warn("[C2P_FUNCTOR] Argument 3 must be a variable");
00239         return FALSE;
00240     }
00241 }
00242 
00243 DllExport Integer call_conv p2c_int(prolog_term term)
00244 {
00245     Cell t = (Cell)term;
00246     return oint_val(t);
00247 }
00248 
00249 DllExport double call_conv p2c_float(prolog_term term)
00250 {
00251     Cell t = (Cell)term;
00252     return (double)(ofloat_val(t));
00253 }
00254 
00255 DllExport char* call_conv p2c_string(prolog_term term)
00256 {
00257     Cell t = (Cell)term;
00258     return string_val(t);
00259 }
00260 
00261 DllExport char* call_conv p2c_functor(prolog_term term)
00262 {
00263     Cell t = (Cell)term;
00264     return get_name(get_str_psc(t));
00265 }
00266 
00267 DllExport int call_conv p2c_arity(prolog_term term)
00268 {
00269     Cell t = (Cell)term;
00270     return get_arity(get_str_psc(t));
00271 }
00272 
00273 DllExport prolog_term call_conv p2p_arg(prolog_term term, int argno)
00274 {
00275     Cell t = (Cell)term;
00276     XSB_Deref(t);
00277     t = cell(clref_val(t)+argno);
00278     XSB_Deref(t);
00279     return (prolog_term)t;
00280 }
00281 
00282 DllExport prolog_term call_conv p2p_car(prolog_term term)
00283 {
00284     Cell t = (Cell)term;
00285     XSB_Deref(t);
00286     t = cell(clref_val(t));
00287     XSB_Deref(t);
00288     return (prolog_term)t;
00289 }
00290 
00291 DllExport prolog_term call_conv p2p_cdr(prolog_term term)
00292 {
00293     Cell t = (Cell)term;
00294     XSB_Deref(t);
00295     t = cell(clref_val(t)+1);
00296     XSB_Deref(t);
00297     return (prolog_term)t;
00298 }
00299 
00300 DllExport prolog_term call_conv p2p_new(CTXTdecl)
00301 {
00302     CPtr t = hreg;
00303     new_heap_free(hreg);
00304     return (prolog_term)(cell(t));
00305 }
00306 
00307 DllExport xsbBool call_conv p2p_unify(CTXTdeclc prolog_term term1, prolog_term term2)
00308 {
00309     return unify(CTXTc term1, term2);
00310 }
00311 
00312 DllExport prolog_term call_conv p2p_deref(prolog_term term)
00313 {
00314     Cell t = (Cell)term;
00315     XSB_Deref(t);
00316     return (prolog_term)t;
00317 }
00318 
00319 
00320 /* convert Arg 1 -- prolog list of characters (a.k.a. prolog string) into C
00321    string and return this string. A character is an integer 1 through 255
00322    (i.e., not necessarily printable)
00323    Arg 2: ptr to string buffer where the result is to be returned.
00324           Space for this buffer must already be allocated.
00325    Arg 3: which function was called from.
00326    Arg 4: where in the call this happened.
00327    Args 3 and 4 are used for error reporting.
00328    This function converts escape sequences in the Prolog string
00329    (except octal/hexadecimal escapes) into the corresponding real characters.
00330 */
00331 char *p_charlist_to_c_string(CTXTdeclc prolog_term term, VarString *buf,
00332                              char *in_func, char *where)
00333 {
00334   Integer head_val;
00335   char head_char[1];
00336   int escape_mode=FALSE;
00337   prolog_term list = term, list_head;
00338 
00339   if (!is_list(list) && !is_nil(list)) {
00340     xsb_abort("[%s] %s is not a list of characters", in_func, where);
00341   }
00342 
00343   XSB_StrSet(buf, "");
00344 
00345   while (is_list(list)) {
00346     if (is_nil(list)) break;
00347     list_head = p2p_car(list);
00348     if (!is_int(list_head)) {
00349       xsb_abort("[%s] A Prolog string (a character list) expected, %s",
00350                 in_func, where);
00351     }
00352     head_val = int_val(list_head);
00353     if (! PRINTABLE_OR_ESCAPED_CHAR(head_val) ) {
00354       xsb_abort("[%s] A Prolog string (a character list) expected, %s",
00355                 in_func, where);
00356     }
00357 
00358     *head_char = (char) head_val;
00359     /* convert ecape sequences */
00360     if (escape_mode)
00361       switch (*head_char) {
00362       case 'a':
00363         XSB_StrAppendBlk(buf, "\a", 1);
00364         break;
00365       case 'b':
00366         XSB_StrAppendBlk(buf, "\b", 1);
00367         break;
00368       case 'f':
00369         XSB_StrAppendBlk(buf, "\f", 1);
00370         break;
00371       case 'n':
00372         XSB_StrAppendBlk(buf, "\n", 1);
00373         break;
00374       case 'r':
00375         XSB_StrAppendBlk(buf, "\r", 1);
00376         break;
00377       case 't':
00378         XSB_StrAppendBlk(buf, "\t", 1);
00379         break;
00380       case 'v':
00381         XSB_StrAppendBlk(buf, "\v", 1);
00382         break;
00383       default:
00384         XSB_StrAppendBlk(buf, head_char, 1);
00385       }
00386     else
00387       XSB_StrAppendBlk(buf, head_char, 1);
00388 
00389     if (*head_char == '\\' && !escape_mode) {
00390       escape_mode = TRUE;
00391       buf->length--; /* backout the last char */
00392     }
00393     else {
00394       escape_mode = FALSE;
00395     }
00396     list = p2p_cdr(list);
00397   } /* while */
00398 
00399   XSB_StrNullTerminate(buf);
00400 
00401   return (buf->string);
00402 }
00403 
00404 
00405 /* convert a C string into a prolog list of characters. 
00406    (codelist might be a better suffix.)
00407    LIST must be a Prolog variable. IN_FUNC is a string that should indicate the
00408    high-level function from this c_string_to_p_charlist was called.
00409    regs_to_protect is the number of registers with values (needed for stack expansion)
00410    WHERE is another string with additional info. These two are used to provide
00411    informative error messages to the user. */
00412 void c_string_to_p_charlist(CTXTdeclc char *name, prolog_term list,
00413                             int regs_to_protect, char *in_func, char *where)
00414 {
00415   Cell new_list;
00416   CPtr top = 0;
00417   int len=strlen(name), i;
00418 
00419   if (isnonvar(list)) {
00420     xsb_abort("[%s] A variable expected, %s", in_func, where);
00421   }
00422   if (len == 0) {
00423     bind_nil((CPtr)(list));
00424   } else {
00425     check_glstack_overflow(regs_to_protect, pcreg, 2*len*sizeof(Cell));
00426     new_list = makelist(hreg);
00427     for (i = 0; i < len; i++) {
00428       follow(hreg++) = makeint(*(unsigned char *)name);
00429       name++;
00430       top = hreg++;
00431       follow(top) = makelist(hreg);
00432     } follow(top) = makenil;
00433     unify(CTXTc list, new_list);
00434   } 
00435 }
00436 
00437 
00438 /* The following function checks if a given term is a prolog string of
00439    printable characters.
00440    It also counts the size of the list.
00441    It deals with the same escape sequences as p_charlist_to_c_string.
00442 */
00443 
00444 DllExport xsbBool call_conv is_charlist(prolog_term term, int *size)
00445 {
00446   int escape_mode=FALSE, head_char;
00447   prolog_term list, head;
00448 
00449   list = term;
00450   *size = 0;
00451   
00452   /* apparently, is_nil can be true and is_list false?? */
00453   if(is_nil(list))
00454     return TRUE;
00455 
00456   if (!is_list(list)) 
00457     return FALSE;
00458 
00459   while (is_list(list)) {
00460     if (is_nil(list)) break;
00461 
00462     head = p2p_car(list);
00463     if (!is_int(head)) 
00464       return FALSE;
00465     
00466     head_char = (char) int_val(head);
00467     /* ' ' is the lowest printable ascii and '~' is the highest */
00468     if (! PRINTABLE_OR_ESCAPED_CHAR(head_char) )
00469       return FALSE;
00470 
00471     if (escape_mode)
00472       switch (head_char) {
00473       case 'a':
00474       case 'b':
00475       case 'f':
00476       case 'n':
00477       case 'r':
00478       case 't':
00479       case 'v':
00480         (*size)++;
00481         escape_mode=FALSE;
00482         break;
00483       default:
00484         (*size) += 2;
00485       }
00486     else
00487       if (head_char == '\\') 
00488         escape_mode = TRUE;
00489       else
00490         (*size)++;
00491     list = p2p_cdr(list);
00492   }
00493   return TRUE;
00494 }
00495 
00496 /* the following two functions were introduced by Luis Castro */
00497 /* they extend the c interface to allow for an easy interface for 
00498 lists of characters */
00499 
00500 DllExport char *call_conv p2c_chars(CTXTdeclc prolog_term term, char *buf, int bsize)
00501 {
00502   XSB_StrDefine(bufvar);
00503 
00504   p_charlist_to_c_string(CTXTc term, &bufvar, "p2c_chars", "list -> char*");
00505   
00506   if (strlen(bufvar.string) > (size_t) bsize) {
00507     xsb_abort("Buffer overflow in p2c_chars");
00508   }
00509 
00510   return strcpy(buf,bufvar.string);
00511 }
00512 
00513 DllExport void call_conv c2p_chars(CTXTdeclc char *str, int regs_to_protect, prolog_term term)
00514 {
00515   c_string_to_p_charlist(CTXTc str,term,regs_to_protect,"c2p_chars", "char* -> list");
00516 }
00517 
00518 
00519 /*
00520 ** Constaints and internal data structures
00521 **
00522 */
00523 
00524 #include "setjmp_xsb.h"
00525 
00526 static char *c_dataptr_rest;
00527 
00528 #ifndef MULTI_THREAD
00529 static jmp_buf cinterf_env;
00530 #endif
00531 
00532 /*
00533 ** procedure cppc_error
00534 **
00535 */
00536 
00537 static void cppc_error(CTXTdeclc int num)
00538 {
00539     longjmp(cinterf_env, num);
00540 }
00541 
00542 /*
00543 ** procedure skip_subfmt
00544 **
00545 */
00546 
00547 static char *skip_subfmt(CTXTdeclc char *ptr, char quote)
00548 {
00549     while (*ptr) {
00550         if (*ptr == quote) return ++ptr;
00551         else if (*ptr == '[') ptr = skip_subfmt(CTXTc ++ptr, ']');
00552         else if (*ptr == '(') ptr = skip_subfmt(CTXTc ++ptr, ')');
00553         else ptr++;
00554     }
00555     cppc_error(CTXTc 6);
00556     return ptr; /* never reach here */
00557 }
00558 
00559 /*
00560 ** procedure count_arity
00561 **
00562 ** count Prolog term size (arity). Ignored fields are not counted
00563 */
00564 
00565 static int count_arity(CTXTdeclc char *ptr, int quote)
00566 {
00567     int arity = 0;
00568 
00569     while (*ptr && arity <= MAX_ARITY) {
00570         if (*ptr == quote) return arity;
00571         else if (*ptr == '%') {
00572             if (*(++ptr)!='*') arity++;
00573         } else if (*ptr == '[') ptr = skip_subfmt(CTXTc ++ptr, ']');
00574         else if (*ptr == '(') ptr = skip_subfmt(CTXTc ++ptr, ')');
00575         else ptr++;
00576     }
00577     cppc_error(CTXTc 5);
00578     return -1;  /* never reach here */
00579 }
00580 
00581 /*
00582 ** procedure count_fields
00583 **
00584 ** count number of fields in the primary structure.
00585 ** should be the same as arity + ignored fields.
00586 */
00587 
00588 static int count_fields(CTXTdeclc char *ptr, int quote)
00589 {
00590     int fields = 0;
00591 
00592     while (*ptr && fields <= MAX_ARITY) {
00593         if (*ptr == quote) return fields;
00594         else if (*ptr == '%') { fields++; ptr++; }
00595         else if (*ptr == '[') ptr = skip_subfmt(CTXTc ++ptr, ']');
00596         else if (*ptr == '(') ptr = skip_subfmt(CTXTc ++ptr, ')');
00597         else ptr++;
00598     }
00599     cppc_error(CTXTc 5);
00600     return -1;  /* never reach here */
00601 }
00602 
00603 /*
00604 ** procedure count_csize
00605 **
00606 ** count C struct size (number of bytes). Ignored fields are also counted
00607 */
00608 
00609 static int count_csize(CTXTdeclc char *ptr, int quote)
00610 {
00611     int size = 0;
00612 
00613     while (*ptr) {
00614         if (*ptr == quote) return size;
00615         else if (*ptr == '%') {
00616             if (*(++ptr)=='*') ptr++;
00617             switch (*ptr) {
00618                 case 'f': size += sizeof(float); ptr++; break;
00619                 case 'd': size += sizeof(double); ptr++; break;
00620                 case 'i': size += sizeof(int); ptr++; break;
00621                 case 'c': size += 1; ptr++; break;
00622                 case 's': size += sizeof(char *); ptr++; break;
00623                 case 'z': ptr++; size += 4 * (*ptr-'0'); ptr++; break;
00624                 case 't': size += sizeof(int *);
00625                     ptr += 2;
00626                     skip_subfmt(CTXTc ptr, ')');
00627                     break;
00628                 case 'l': size += sizeof(int *);
00629                     ptr += 2;
00630                     skip_subfmt(CTXTc ptr, ')');
00631                     break;
00632                 case '[': 
00633                     size += count_csize(CTXTc ++ptr, ']');
00634                     skip_subfmt(CTXTc ptr, ']');
00635                     break;
00636                 case '0':
00637                 case '1':
00638                 case '2':
00639                 case '3':
00640                 case '4':
00641                 case '5':
00642                 case '6':
00643                 case '7':
00644                 case '8':
00645                 case '9':
00646                     size += sizeof(int *); ptr++; break;
00647                 default: cppc_error(CTXTc 7); break;
00648             }
00649         }
00650     }
00651     cppc_error(CTXTc 8);
00652     return -1;  /* never reach here */
00653 }
00654 
00655 /*
00656 ** procedure ctop_term0
00657 **
00658 */
00659 
00660 static char *ctop_term0(CTXTdeclc char *ptr, char *c_dataptr, char **subformat,
00661                         prolog_term variable, int ignore)
00662 {
00663     char ch;
00664     int fmtnum;
00665     char *cdptr2;
00666     int  argno, fields, i;
00667     int ignore1;
00668 
00669     if (*ptr++!= '%') cppc_error(CTXTc 1);
00670     ch = *ptr++;
00671     if (ch=='*') ch = *ptr++;
00672     switch (ch) {
00673         case 'i':                       /* int */
00674         
00675         if (!ignore) c2p_int(CTXTc *((int *)(c_dataptr)), variable);
00676         c_dataptr_rest = c_dataptr + sizeof(int);
00677         break;
00678 
00679         case 'c':
00680 
00681         if (!ignore) c2p_int(CTXTc (int)(*(char *)(c_dataptr)), variable);
00682         c_dataptr_rest = c_dataptr + 1;
00683         break;
00684 
00685         case 's':
00686 
00687         if (!ignore) c2p_string(CTXTc *(char **)(c_dataptr), variable);
00688         c_dataptr_rest = c_dataptr + sizeof(char*);
00689         break;
00690 
00691         case 'z':
00692 
00693         if (!ignore) c2p_string(CTXTc c_dataptr, variable);
00694         ch = *ptr++;
00695         c_dataptr_rest = c_dataptr + (ch -'0')*4;
00696         break;
00697 
00698         case 'f':
00699 
00700         if (!ignore) c2p_float(CTXTc (double)(*((float *)(c_dataptr))), variable);
00701         c_dataptr_rest = c_dataptr + sizeof(float);
00702         break;
00703 
00704         case 'd':
00705 
00706         if (!ignore) c2p_float(CTXTc *((double *)(c_dataptr)), variable);
00707         c_dataptr_rest = c_dataptr + sizeof(double);
00708         break;
00709 
00710         case '[':
00711 
00712         fields = count_fields(CTXTc ptr, ']');
00713         if (!ignore) {
00714             argno = count_arity(CTXTc ptr, ']');
00715             if (!is_functor(variable)) c2p_functor(CTXTc "c2p", argno, variable);
00716         }
00717         argno = 0;
00718         for (i = 1; i <= fields; i++) {
00719             if (*(ptr+1)=='*') ignore1 = 1;
00720             else { ignore1 = ignore; argno++; }
00721             ptr = ctop_term0(CTXTc ptr,c_dataptr,subformat,p2p_arg(variable,argno),ignore1);
00722             c_dataptr = c_dataptr_rest;
00723         }
00724         ptr = skip_subfmt(CTXTc ptr, ']');
00725         break;
00726 
00727         case 't':
00728 
00729         if (!ignore) {
00730             if (*(char **)(c_dataptr)) {
00731                 fmtnum = (int)(*ptr-'0');
00732                 subformat[fmtnum] = ptr-2;
00733                 ptr++;
00734                 if (*(ptr++) !='(') cppc_error(CTXTc 2);
00735                 argno = count_arity(CTXTc ptr, ')');
00736                 fields = count_fields(CTXTc ptr, ')');
00737                 if (!is_functor(variable)) c2p_functor(CTXTc "c2p", argno, variable);
00738                 cdptr2 = * (char **)(c_dataptr);
00739                 argno = 0;
00740                 for (i = 1; i <= fields; i++) {
00741                     if (*(ptr+1)=='*') ignore = 1;
00742                     else { ignore = 0; argno++; }
00743                     ptr = ctop_term0(CTXTc ptr,cdptr2,subformat,p2p_arg(variable,argno),ignore);
00744                     cdptr2 = c_dataptr_rest;
00745                 }
00746             } else c2p_nil(CTXTc variable);
00747         }
00748         ptr = skip_subfmt(CTXTc ptr, ')');
00749         c_dataptr_rest = c_dataptr + 4;
00750         break;
00751 
00752         case 'l':
00753         if (!ignore) {
00754             if (*(char **)(c_dataptr)) {
00755                 fmtnum = (int)(*ptr-'0');
00756                 subformat[fmtnum] = ptr-2;
00757                 ptr++;
00758                 if (*(ptr++) != '(') cppc_error(CTXTc 3);
00759                 argno = count_arity(CTXTc ptr, ')');
00760                 fields = count_fields(CTXTc ptr, ')');
00761                 if (!is_list(variable)) c2p_list(CTXTc variable);
00762                 cdptr2 = * (char **)(c_dataptr);
00763                 argno = 0;
00764                 for (i = 1; i <= fields; i++) {
00765                     if (*(ptr+1)=='*') ignore = 1;
00766                     else { ignore = 0; argno++; }
00767                     if (argno==1) 
00768                        ptr = ctop_term0(CTXTc ptr,cdptr2,subformat,p2p_car(variable),ignore);
00769                     else if (argno==2)
00770                        ptr = ctop_term0(CTXTc ptr,cdptr2,subformat,p2p_cdr(variable),ignore);
00771                     else if (argno==0)
00772                        ptr = ctop_term0(CTXTc ptr,cdptr2,subformat,p2p_car(variable),ignore);
00773                        /* always ignored */
00774                     else cppc_error(CTXTc 30);
00775                     cdptr2 = c_dataptr_rest;
00776                 }
00777             } else c2p_nil(CTXTc variable);
00778         }
00779         ptr = skip_subfmt(CTXTc ptr, ')');
00780         c_dataptr_rest = c_dataptr + 4;
00781         break;
00782 
00783         case '0':
00784         case '1':
00785         case '2':
00786         case '3':
00787         case '4':
00788         case '5':
00789         case '6':
00790         case '7':
00791         case '8':
00792         case '9':
00793 
00794         if (!ignore) {
00795             if (*(char **)(c_dataptr)) {
00796                 ctop_term0(CTXTc subformat[ch-'0'], c_dataptr, subformat,variable, 0);
00797             } else c2p_nil(CTXTc variable);
00798         }
00799         c_dataptr_rest = c_dataptr + 4;
00800         break;
00801 
00802         default: cppc_error(CTXTc 4);
00803     }
00804     return ptr;
00805 }
00806 
00807 /*
00808 ** procedure ptoc_term0
00809 **
00810 */
00811 
00812 static char *ptoc_term0(CTXTdeclc char *ptr, char *c_dataptr, char **subformat,
00813                         prolog_term variable, int ignore)
00814 {
00815     char ch;
00816     int fmtnum;
00817     char *cdptr2;
00818     int  argno, fields, i, size;
00819     int ignore1;
00820 
00821     if (*ptr++!= '%') cppc_error(CTXTc 9);
00822     ch = *ptr++;
00823     if (ch=='*') ch = *ptr++;
00824     switch (ch) {
00825         case 'i':                       /* int */
00826 
00827         if (!ignore) {
00828             if (is_int(variable)) *((int *)(c_dataptr)) = p2c_int(variable);
00829             else cppc_error(CTXTc 10);
00830         }
00831         c_dataptr_rest = c_dataptr + sizeof(int);
00832         break;
00833 
00834         case 'c':
00835 
00836         if (!ignore) {
00837             if (is_int(variable)) *((char *)(c_dataptr)) = 
00838                (char)p2c_int(variable);
00839             else cppc_error(CTXTc 11);
00840         }
00841         c_dataptr_rest = c_dataptr + 1;
00842         break;
00843 
00844         case 's':
00845 
00846         if (!ignore) {
00847             if (is_string(variable)) *((char **)(c_dataptr)) =
00848                p2c_string(variable);            /* should make a copy??? */
00849             else cppc_error(CTXTc 12);
00850         }
00851         c_dataptr_rest = c_dataptr + 4;
00852         break;
00853 
00854         case 'z':
00855 
00856         ch = *ptr++;
00857         size = 4 * (ch - '0');
00858         if (!ignore) {
00859             if (is_string(variable)) 
00860                strncpy(c_dataptr, p2c_string(variable), size);
00861             else cppc_error(CTXTc 12);
00862         }
00863         c_dataptr_rest = c_dataptr + size;
00864         break;
00865 
00866         case 'f':
00867 
00868         if (!ignore) {
00869             if (is_float(variable)) 
00870               *((float *)(c_dataptr)) = (float)p2c_float(variable);
00871             else cppc_error(CTXTc 13);
00872         }
00873         c_dataptr_rest = c_dataptr + sizeof(float);
00874         break;
00875 
00876         case 'd':
00877 
00878         if (!ignore) {
00879             if (is_float(variable)) *((double *)(c_dataptr)) =
00880                p2c_float(variable);
00881             else cppc_error(CTXTc 14);
00882         }
00883         c_dataptr_rest = c_dataptr + sizeof(double);
00884         break;
00885 
00886         case '[':
00887 
00888         fields = count_fields(CTXTc ptr, ']');
00889         argno = 0;
00890         for (i = 1; i <= fields; i++) {
00891             if (*(ptr+1)=='*') ignore1 = 1;
00892             else { ignore1 = ignore; argno++; }
00893             ptr = ptoc_term0(CTXTc ptr, c_dataptr,subformat,p2p_arg(variable,argno),ignore1);
00894             c_dataptr = c_dataptr_rest;
00895         }
00896         ptr = skip_subfmt(CTXTc ptr, ']');
00897         break;
00898 
00899         case 't':
00900 
00901         if (!ignore) {
00902             fmtnum = (int)(*ptr-'0');
00903             subformat[fmtnum] = ptr-2;
00904             ptr++;
00905             if (*(ptr++) != '(') cppc_error(CTXTc 15);
00906             fields = count_fields(CTXTc ptr, ')');
00907             size = count_csize(CTXTc ptr, ')');
00908             cdptr2 = (char *)mem_alloc(size,OTHER_SPACE);  /* leak */
00909             *((char **)c_dataptr) = cdptr2;
00910             argno = 0;
00911             for (i = 1; i <= fields; i++) {
00912                 if (*(ptr+1)=='*') ignore = 1;
00913                 else { ignore = 0; argno++; }
00914                 ptr = ptoc_term0(CTXTc ptr,cdptr2,subformat,p2p_arg(variable,argno),ignore);
00915                 cdptr2 = c_dataptr_rest;
00916             }
00917         }
00918         ptr = skip_subfmt(CTXTc ptr, ')');
00919         c_dataptr_rest = c_dataptr + 4;
00920         break;
00921 
00922         case 'l':
00923         if (!ignore) {
00924             fmtnum = (int)(*ptr-'0');
00925             subformat[fmtnum] = ptr-2;
00926             ptr++;
00927             if (*(ptr++)!='(') cppc_error(CTXTc 16);
00928             fields = count_fields(CTXTc ptr, ')');
00929             size = count_csize(CTXTc ptr, ')');
00930             cdptr2 = (char *)mem_alloc(size,OTHER_SPACE);  /* leak */
00931             *((char **)c_dataptr) = cdptr2;
00932             argno = 0;
00933             for (i = 1; i <= fields; i++) {
00934                 if (*(ptr+1)=='*') ignore = 1;
00935                 else { ignore = 0; argno++; }
00936                 if (argno==1)
00937                    ptr = ptoc_term0(CTXTc ptr,cdptr2,subformat,p2p_car(variable),ignore);
00938                 else if (argno==2)
00939                    ptr = ptoc_term0(CTXTc ptr,cdptr2,subformat,p2p_cdr(variable),ignore);
00940                 else cppc_error(CTXTc 31);
00941                 cdptr2 = c_dataptr_rest;
00942             }
00943         }
00944         ptr = skip_subfmt(CTXTc ptr, ')');
00945         c_dataptr_rest = c_dataptr + 4;
00946         break;
00947 
00948         case '0':
00949         case '1':
00950         case '2':
00951         case '3':
00952         case '4':
00953         case '5':
00954         case '6':
00955         case '7':
00956         case '8':
00957         case '9':
00958 
00959         if (!ignore) {
00960             if (!is_nil(variable)) {
00961                 ptoc_term0(CTXTc subformat[ch-'0'], c_dataptr, subformat, variable, 0);
00962             } else *(int *)(c_dataptr) = 0;
00963         }
00964         c_dataptr_rest = c_dataptr + 4;
00965         break;
00966 
00967         default: cppc_error(CTXTc 17);
00968     }
00969     return ptr;
00970 }
00971 
00972 /*
00973 ** procedure ctop_term
00974 **
00975 */
00976 
00977 int ctop_term(CTXTdeclc char *fmt, char *c_dataptr, reg_num regnum)
00978 {
00979     prolog_term variable;
00980     int my_errno;
00981     char *subformat[10];
00982 
00983     variable = reg_term(CTXTc regnum);
00984     if ((my_errno = setjmp(cinterf_env))) return my_errno;  /* catch an exception */
00985     ctop_term0(CTXTc fmt, c_dataptr, subformat, variable, 0);
00986     return 0;
00987 }
00988 
00989 /*
00990 ** procedure ptoc_term
00991 **
00992 */
00993 
00994 int ptoc_term(CTXTdeclc char *fmt, char *c_dataptr, reg_num regnum)
00995 {
00996     prolog_term variable;
00997     int my_errno;
00998     char *subformat[10];
00999 
01000     variable = reg_term(CTXTc regnum);
01001     if ((my_errno = setjmp(cinterf_env))) return my_errno;  /* catch an exception */
01002     ptoc_term0(CTXTc fmt, c_dataptr, subformat, variable, 0);
01003     return 0;
01004 }
01005 
01006 /*
01007 ** procedure c2p_term
01008 **
01009 */
01010 
01011 int c2p_term(CTXTdeclc char *fmt, char *c_dataptr, prolog_term variable)
01012 {
01013     int my_errno;
01014     char *subformat[10];
01015 
01016     if ((my_errno = setjmp(cinterf_env))) return my_errno;  /* catch an exception */
01017     ctop_term0(CTXTc fmt, c_dataptr, subformat, variable, 0);
01018     return 0;
01019 }
01020 
01021 /*
01022 ** procedure p2c_term
01023 **
01024 */
01025 
01026 int p2c_term(CTXTdeclc char *fmt, char *c_dataptr, prolog_term variable)
01027 {
01028     int my_errno;
01029     char *subformat[10];
01030 
01031     if ((my_errno = setjmp(cinterf_env))) return my_errno;  /* catch an exception */
01032     ptoc_term0(CTXTc fmt, c_dataptr, subformat, variable, 0);
01033     return 0;
01034 }
01035 /* quick test to see whether atom must be quoted */
01036 int mustquote(char *atom)
01037 {
01038     int i;
01039 
01040     if (!(atom[0] >= 'a' && atom[0] <= 'z')) return TRUE;
01041     for (i=1; atom[i] != '\0'; i++) {
01042         if (!((atom[i] >= 'a' && atom[i] <= 'z') ||
01043              (atom[i] >= 'A' && atom[i] <= 'Z') ||
01044              (atom[i] == '_') ||
01045              (atom[i] >= '0' && atom[i] <= '9')
01046              )) return TRUE;
01047     }
01048     return FALSE;
01049 }
01050 
01051 /* copy a string (quoted if !toplevel and necessary) into a buffer.  */
01052 void printpstring(char *atom, int toplevel, VarString *straddr)
01053 {
01054     int i;
01055    
01056     if (toplevel || !mustquote(atom)) {
01057       XSB_StrAppend(straddr,atom);
01058     } else {
01059       XSB_StrAppendBlk(straddr, "'", 1);
01060       for (i = 0; atom[i] != '\0'; i++) {
01061         XSB_StrAppendBlk(straddr, atom+i, 1);
01062         if (atom[i] == '\'')
01063           /* double the quotes in a quoted string */
01064           XSB_StrAppendBlk(straddr, "'", 1);
01065       }
01066       XSB_StrAppend(straddr, "'");
01067     }
01068 }
01069     
01070 /* calculate approximate length of a printed term.  For space alloc. */
01071 int clenpterm(prolog_term term)
01072 {
01073   int i, clen;
01074 
01075   if (is_var(term)) return 11;
01076   else if (is_int(term)) return 12;
01077   else if (is_float(term)) return 12;
01078   else if (is_nil(term)) return 2;
01079   else if (is_string(term)) return strlen(p2c_string(term))+5;
01080   else if (is_list(term)) {
01081       clen = 1;
01082       clen += clenpterm(p2p_car(term)) + 1;
01083       while (is_list(term)) {
01084           clen += clenpterm(p2p_car(term)) + 1;
01085           term = p2p_cdr(term);
01086       }
01087       if (!is_nil(term)) {
01088           clen += clenpterm(term) + 1;
01089       }
01090       return clen+1;
01091   } else if (is_functor(term)) {
01092       clen = strlen(p2c_functor(term))+5;
01093       if (p2c_arity(term) > 0) {
01094           clen += clenpterm(p2p_arg(term,1)) + 1;
01095           for (i = 2; i <= p2c_arity(term); i++) {
01096               clen += clenpterm(p2p_arg(term,i)) + 1;
01097           }
01098           return clen + 1;
01099       } else return clen;
01100   } else {
01101       xsb_warn("Unrecognized prolog term type");
01102       return 0;
01103   }
01104 }
01105 
01106 char tempstring[MAXBUFSIZE];
01107 
01108 /* print a prolog_term into a buffer.
01109    Atoms are quoted if !toplevel -- necessary for Prolog reading 
01110    Buffer is a VarString. If the VarString is non-empty, the term is appended
01111    to the current contents of the VarString.
01112 */
01113 DllExport void call_conv print_pterm(CTXTdeclc prolog_term term, int toplevel, 
01114                                      VarString *straddr)
01115 {
01116   int i;
01117 
01118   if (is_var(term)) {
01119     xsb_sprint_variable(CTXTc tempstring, (CPtr) term);
01120     XSB_StrAppend(straddr,tempstring);
01121   } else if (is_attv(term)) {
01122     xsb_sprint_variable(CTXTc tempstring, (CPtr) dec_addr(term));
01123     XSB_StrAppend(straddr,tempstring);
01124   } else if (is_int(term)) {
01125     sprintf(tempstring,"%d", (int) p2c_int(term));
01126     XSB_StrAppend(straddr,tempstring);
01127   } else if (is_float(term)) {
01128     sprintf(tempstring,"%f", (float) p2c_float(term));
01129     XSB_StrAppend(straddr,tempstring);
01130   } else if (is_nil(term)) {
01131     XSB_StrAppend(straddr,"[]");
01132   } else if (is_string(term)) {
01133     printpstring(p2c_string(term),toplevel,straddr);
01134   } else if (is_list(term)) {
01135     XSB_StrAppend(straddr, "[");
01136     print_pterm(CTXTc p2p_car(term),FALSE,straddr);
01137     term = p2p_cdr(term);
01138     while (is_list(term)) {
01139       XSB_StrAppend(straddr, ",");
01140       print_pterm(CTXTc p2p_car(term),FALSE,straddr);
01141       term = p2p_cdr(term);
01142     }
01143     if (!is_nil(term)) {
01144       XSB_StrAppend(straddr, "|");
01145       print_pterm(CTXTc term,FALSE,straddr);
01146     }
01147     XSB_StrAppend(straddr, "]");
01148   } else if (is_functor(term)) {
01149     printpstring(p2c_functor(term),FALSE,straddr);
01150     if (p2c_arity(term) > 0) {
01151       XSB_StrAppend(straddr, "(");
01152       print_pterm(CTXTc p2p_arg(term,1),FALSE,straddr);
01153       for (i = 2; i <= p2c_arity(term); i++) {
01154         XSB_StrAppend(straddr, ",");
01155         print_pterm(CTXTc p2p_arg(term,i),FALSE,straddr);
01156       }
01157       XSB_StrAppend(straddr, ")");
01158     }
01159   } else xsb_warn("[PRINT_PTERM] Unrecognized prolog term type");
01160 }
01161 
01162 /************************************************************************/
01163 /*                                                                      */
01164 /*      xsb_answer_string copies an answer from reg 2 into ans.         */
01165 /*                                                                      */
01166 /************************************************************************/
01167 int xsb_answer_string(CTXTdeclc VarString *ans, char *sep) 
01168 {
01169   int i;
01170   
01171   if (!is_string(reg_term(CTXTc 2))) {
01172     for (i=1; i<p2c_arity(reg_term(CTXTc 2)); i++) {
01173       print_pterm(CTXTc p2p_arg(reg_term(CTXTc 2),i),TRUE,ans);
01174       XSB_StrAppend(ans,sep);
01175     }
01176     print_pterm(CTXTc p2p_arg(reg_term(CTXTc 2),p2c_arity(reg_term(CTXTc 2))),TRUE,ans);
01177   }
01178   return 0;
01179 }
01180 
01181 
01182 static long lastWarningStart = 0L;
01183 static inline void updateWarningStart(void)
01184 {
01185   if(flags[STDERR_BUFFERED])
01186         lastWarningStart = ftell(stderr);
01187 }
01188 
01189 /************************************************************************/
01190 /*                                                                      */
01191 /* xsb_init(argc,argv) initializes XSB to be called from C.             */
01192 /* argc and argv are the arg count and arg vector as passed from the    */
01193 /* command line.  The parameters are used to set space sizes in xsb.    */
01194 /* The parameters MUST include -i, which indicates that the main        */
01195 /* interpreter is to be loaded, AND -n, which indicates that the        */
01196 /* interpreter should not enter the usual read-eval-print loop, but     */
01197 /* instead support the interface to the C caller.                       */
01198 /*   If xsb has been previously initialized, nothing is done and 1 is   */
01199 /* returned.                                                            */
01200 /*                                                                      */
01201 /************************************************************************/
01202 
01203 static int xsb_initted_gl = 0;   /* if xsb has been called */
01204 static int xsb_inquery_gl = 0;   
01205 
01206 DllExport int call_conv xsb_init(CTXTdeclc int argc, char *argv[])
01207 {
01208 int rc = 1;
01209 char executable1[MAXPATHLEN];
01210  char *expfilename;
01211 
01212 updateWarningStart();
01213 if (!xsb_initted_gl)
01214         {
01215         /* we rely on the caller to tell us in argv[0]
01216         the absolute or relative path name to the XSB installation directory */
01217         sprintf(executable1, "%s%cconfig%c%s%cbin%cxsb",
01218         argv[0], SLASH, SLASH, FULL_CONFIG_NAME, SLASH, SLASH);
01219         expfilename = expand_filename(executable1);
01220         strcpy(executable_path_gl, expfilename);
01221         mem_dealloc(expfilename,MAXPATHLEN,OTHER_SPACE);
01222 
01223         if (0 == (rc = xsb(CTXTc 0,argc,argv)))     /* initialize xsb */
01224                 {
01225                 if (0 == (rc = xsb(CTXTc 1,0,0)))       /* enter xsb to set up regs */
01226                 xsb_initted_gl = 1;
01227                 }
01228         }
01229 return(rc);
01230 }
01231 
01232 /************************************************************************/
01233 /*                                                                      */
01234 /*  int xsb_cmd_string(char *cmdline, char **argv) takes a              */
01235 /*  command line string in cmdline, and parses it to return an argv     */
01236 /*  vector in its second argument, and the argc count as the value of   */
01237 /*      the function.  (Will handle a max of 19 args.)                  */
01238 /*                                                                      */
01239 /************************************************************************/
01240 /*FILE *stream_err, *stream_out;*/
01241 
01242 DllExport int call_conv xsb_init_string(CTXTdeclc char *cmdline_param) {
01243         int i = 0, argc = 0;
01244         char **argv, delim;
01245         char cmdline[2*MAXPATHLEN+1];
01246 
01247   updateWarningStart();
01248 
01249         /*stream_err = freopen("XSB_errlog", "w", stderr);
01250           stream_out = freopen("XSB_outlog", "w", stdout);*/
01251 
01252         if (strlen(cmdline_param) > 2*MAXPATHLEN) {
01253             xsb_warn("**************************************************************************");
01254             xsb_warn("[XSB_INIT_STRING] %18s...: command used to call XSB server is too long",
01255                     cmdline_param);
01256             xsb_warn("**************************************************************************");
01257             exit(1);
01258         }
01259         strncpy(cmdline, cmdline_param, 2*MAXPATHLEN - 1);
01260         argv = (char **) mem_alloc(20*sizeof(char *),OTHER_SPACE);  /* count space even if never released */
01261 
01262         while (cmdline[i] == ' ') i++;
01263         while (cmdline[i] != '\0') {
01264                 if ((cmdline[i] == '"') || (cmdline[i] == '\'')) {
01265                         delim = cmdline[i];
01266                         i++;
01267                 } else delim = ' ';
01268                 argv[argc] = &(cmdline[i]);
01269                 argc++;
01270                 if (argc >= 19) {argc--; break;}
01271                 while ((cmdline[i] != delim) && (cmdline[i] != '\0')) i++;
01272                 if (cmdline[i] == '\0') break;
01273                 cmdline[i] = '\0';
01274                 i++;
01275                 while (cmdline[i] == ' ') i++;
01276         }
01277         argv[argc] = 0;
01278         return xsb_init(CTXTc argc,argv);
01279 }
01280 
01281 /************************************************************************/
01282 /*                                                                      */
01283 /* xsb_command() passes the command (i.e. query with no variables) to   */
01284 /* xsb.  The command must be put into xsb's register 1 as a term, by    */
01285 /* the caller who uses the c2p_* (and perhaps p2p_*) functions.         */
01286 /*   It returns 0 if it succeeds, 1 if it fails, in either case         */
01287 /* resetting register 1 back to a free variable.  It returns 2 if there */
01288 /* is an error.                                                         */
01289 /*                                                                      */
01290 /************************************************************************/
01291 
01292 DllExport int call_conv xsb_command(CTXTdecl)
01293 {
01294   if (xsb_inquery_gl) return(2);  /* error */
01295   updateWarningStart();
01296   c2p_int(CTXTc 0,reg_term(CTXTc 3));  /* command for calling a goal */
01297   xsb(CTXTc 1,0,0);
01298   if (is_var(reg_term(CTXTc 1))) return(1);  /* goal failed, so return 1 */
01299   c2p_int(CTXTc 1,reg_term(CTXTc 3));  /* command for next answer */
01300   xsb(CTXTc 1,0,0);
01301   if (is_var(reg_term(CTXTc 1))) return(0);  /* goal succeeded */
01302   (void) xsb_close_query(CTXT);
01303   return(2);
01304 }
01305 
01306 /************************************************************************/
01307 /*                                                                      */
01308 /* xsb_command_string(char *goal) passes the command (e.g. a query      */
01309 /* which only succeeds or fails) to xsb.  The command must a string     */
01310 /* passed in the argument.  It returns 0 if it succeeds, 1 if it        */
01311 /* fails, in either case resetting register 1 back to a free            */
01312 /* variable.  It returns 2 if there is an error.                        */
01313 /*                                                                      */
01314 /************************************************************************/
01315 
01316 DllExport int call_conv xsb_command_string(CTXTdeclc char *goal)
01317 {
01318   if (xsb_inquery_gl) return(2);  /* error */
01319   updateWarningStart();
01320   c2p_string(CTXTc goal,reg_term(CTXTc 1));
01321   c2p_int(CTXTc 2,reg_term(CTXTc 3));  /* command for calling a string goal */
01322   xsb(CTXTc 1,0,0);
01323   if (is_var(reg_term(CTXTc 1))) return(1);  /* goal failed, so return 1 */
01324   c2p_int(CTXTc 1,reg_term(CTXTc 3));  /* command for next answer */
01325   xsb(CTXTc 1,0,0);
01326   if (is_var(reg_term(CTXTc 1))) return(0);  /* goal succeeded */
01327   (void) xsb_close_query(CTXT);
01328   return(2);
01329 }
01330 
01331 /************************************************************************/
01332 /*                                                                      */ 
01333 /* xsb_query() submits a query to xsb. The query must have been put into*/
01334 /* xsb's register 1 by the caller, using p2c_* (and perhaps p2p_*).  Xsb*/
01335 /* will evaluate the query and return with the variables in the query   */
01336 /* bound to the first answer.  In addition, register 2 will contain a   */
01337 /* Prolog term of the form ret(V1,V2,..,Vn) with as many Vi's as        */
01338 /* variables in the original query and with Vi bound to the value for   */
01339 /* that variable in the first answer.  If the query fails, it returns 1.*/
01340 /* If the query succeeds, it returns 0. If there is an error, it returns*/
01341 /* 2.                                                                   */
01342 /*                                                                      */
01343 /************************************************************************/
01344 
01345 DllExport int call_conv xsb_query(CTXTdecl)
01346 {
01347   if (xsb_inquery_gl) return(2);
01348   updateWarningStart();
01349   c2p_int(CTXTc 0,reg_term(CTXTc 3));  /* set command for calling a goal */
01350   xsb(CTXTc 1,0,0);
01351   if (is_var(reg_term(CTXTc 1))) return(1);
01352   xsb_inquery_gl = 1;
01353   return(0);
01354 }
01355 
01356 /************************************************************************/
01357 /*                                                                      */ 
01358 /* xsb_query_string(char *) submits a query to xsb.  The string must
01359    be a goal that will be correctly read by xsb's reader, and it must
01360    be terminated with a period (.).  Register 2 may be a variable or
01361    it may be a term of the form ret(X1,X2,...,Xn), where n is the
01362    number of variables in the query.  The query will be parsed, and an
01363    answer term of the form ret(Y1,Y2,...,Yn) will be constructed where
01364    Y1, .... Yn are the variables in the parsed goal (in left-to-right
01365    order).  This answer term is unified with the argument in register
01366    2.  Then the goal is called.  If the goal succeeds,
01367    xsb_query_string returns 0 and the first answer is in register 2.
01368    If it fails, xsb_query_string returns 1.                             */
01369 /*                                                                      */
01370 /************************************************************************/
01371 
01372 DllExport int call_conv xsb_query_string(CTXTdeclc char *goal)
01373 {
01374   if (xsb_inquery_gl) return(2);
01375   updateWarningStart();
01376   c2p_chars(CTXTc goal,2,reg_term(CTXTc 1));
01377   c2p_int(CTXTc 2,reg_term(CTXTc 3));  /* set command for calling a string goal */
01378   xsb(CTXTc 1,0,0);
01379   if (is_var(reg_term(CTXTc 1))) return(1);
01380   xsb_inquery_gl = 1;
01381   return(0);
01382 }
01383 
01384 /************************************************************************/
01385 /*                                                                      */
01386 /*  xsb_query_string_string calls xsb_query_string and returns          */
01387 /*      the answer in a string.  The answer is copied into ans,         */
01388 /*      a VarString provided by the caller.  Variable                   */
01389 /*      values are separated by the string sep.                         */
01390 /*                                                                      */
01391 /************************************************************************/
01392 
01393 int call_conv xsb_query_string_string(CTXTdeclc char *goal, 
01394                                       VarString *ans, char *sep) 
01395 {
01396   int rc;
01397   
01398   rc = xsb_query_string(CTXTc goal);
01399   if (rc > 0) return rc;
01400   return xsb_answer_string(CTXTc ans,sep);
01401 }
01402 
01403 /************************************************************************/
01404 /*                                                                      */
01405 /*  xsb_query_string_string_b calls xsb_query_string and returns        */
01406 /*      the answer in a string.  The caller provides a buffer and its   */
01407 /*      length.  If the answer fits in the buffer, it is returned       */
01408 /*      there, and its length is returned.  If not, then the length is  */ 
01409 /*      returned, and the answer can be obtained by calling             */
01410 /*      xsb_get_last_answer.                                            */
01411 /*                                                                      */
01412 /************************************************************************/
01413 #ifndef MULTI_THREAD
01414 static XSB_StrDefine(last_answer_lc);
01415 #define last_answer (&last_answer_lc)
01416 #endif
01417 
01418 int call_conv xsb_query_string_string_b(CTXTdeclc
01419              char *goal, char *buff, int buflen, int *anslen, char *sep) 
01420 {
01421   int rc;
01422   
01423   XSB_StrSet(last_answer,"");
01424   rc = xsb_query_string_string(CTXTc goal,last_answer,sep); 
01425   if (rc > 0) return rc;
01426   *anslen = last_answer->length;
01427   XSB_StrNullTerminate(last_answer);
01428   if (last_answer->length < buflen) {
01429     strcpy(buff,last_answer->string);
01430     return rc;
01431   } else return(3);
01432 }
01433 
01434 /************************************************************************/
01435 /*                                                                      */
01436 /*      xsb_get_last_answer_string returns previous answer.             */
01437 /*                                                                      */
01438 /************************************************************************/
01439 DllExport int call_conv 
01440    xsb_get_last_answer_string(CTXTdeclc char *buff, int buflen, int *anslen) {
01441 
01442  *anslen = last_answer->length;
01443   if (last_answer->length < buflen) {
01444     strcpy(buff,last_answer->string);
01445     return 0;
01446   } else 
01447     return(3);
01448 }    
01449 
01450 /************************************************************************/
01451 /*                                                                      */
01452 /* xsb_next() causes xsb to return the next answer.  It (or             */
01453 /* xsb_close_query) must be called after xsb_query.  If there is        */
01454 /* another answer, xsb_next returns 0 and the variables in goal term    */
01455 /* (in xsb register 1) are bound to the answer values.  In addition     */
01456 /* xsb register 2 will contain a term of the form ret(V1,V2,...,Vn)     */
01457 /* where the Vi's are the values for the variables for the next         */
01458 /* answer.                                                              */
01459 /* xsb_next returns 0 if the next is found, 1 if there are no more      */
01460 /* answers, and 3 if an error is encountered. If 1 is returned, then    */
01461 /* the query is automatically closed.                                   */
01462 /*                                                                      */
01463 /************************************************************************/
01464 
01465 DllExport int call_conv xsb_next(CTXTdecl)
01466 {
01467   if (!xsb_inquery_gl) return(2);
01468   updateWarningStart();
01469   c2p_int(CTXTc 0,reg_term(CTXTc 3));  /* set command for next answer */
01470   xsb(CTXTc 1,0,0);
01471   if (is_var(reg_term(CTXTc 1))) {
01472     xsb_inquery_gl = 0;
01473     return(1);
01474   } else return(0);
01475 }
01476 
01477 /************************************************************************/
01478 /*                                                                      */
01479 /*      xsb_next_string(ans,sep) calls xsb_next() and returns the       */
01480 /*      answer in the VarString ans, provided by the caller.            */
01481 /*      sep is a separator for the fields of the answer.                */
01482 /*                                                                      */
01483 /************************************************************************/
01484 
01485 DllExport int call_conv xsb_next_string(CTXTdeclc VarString *ans, char *sep) 
01486 {
01487   int rc = xsb_next(CTXT);
01488   if (rc > 0) return rc;
01489   return xsb_answer_string(CTXTc ans,sep);
01490 }
01491 
01492 /************************************************************************/
01493 /*                                                                      */
01494 /*      xsb_next_string_b(buff,buflen,anslen,sep) calls xsb_next() and  */
01495 /*      returns the answer in buff, provided by the caller.  The length */
01496 /*      of buff is buflen.  The length of the answer is put in anslen.  */
01497 /*      If the buffer is too small for the answer, nothing is put in    */
01498 /*      the buffer.  In this case the caller can allocate a larger      */
01499 /*      and retrieve the buffer using xsb_get_last_answer.              */
01500 /*                                                                      */
01501 /************************************************************************/
01502 
01503 DllExport int call_conv xsb_next_string_b(CTXTdeclc
01504                      char *buff, int buflen, int *anslen, char *sep) 
01505 {
01506   int rc;
01507 
01508   XSB_StrSet(last_answer,"");
01509   rc = xsb_next_string(CTXTc last_answer,sep);
01510   if (rc > 0) return rc;
01511   *anslen = last_answer->length;
01512   XSB_StrNullTerminate(last_answer);
01513   if (last_answer->length < buflen) {
01514     strcpy(buff,last_answer->string);
01515     return rc;
01516   } else return(3);
01517 }
01518 
01519 /************************************************************************/
01520 /*                                                                      */
01521 /* xsb_close_query() closes the current query, so that no more answers  */
01522 /* will be returned, and another query can be opened.                   */
01523 /* If the query was correctly closed, it resets xsb registers 1 and 2   */
01524 /* to be variables, and returns 0.  If there is some error, it returns  */
01525 /* 2.                                                                   */
01526 /*                                                                      */
01527 /************************************************************************/
01528 
01529 DllExport int call_conv xsb_close_query(CTXTdecl)
01530 {
01531   updateWarningStart();
01532   if (!xsb_inquery_gl) return(2);
01533   c2p_int(CTXTc 1,reg_term(CTXTc 3));  /* set command for cut */
01534   xsb(CTXTc 1,0,0);
01535   if (is_var(reg_term(CTXTc 1))) {
01536     xsb_inquery_gl = 0;
01537     return(0);
01538   } else return(2);
01539 }
01540 
01541 /************************************************************************/
01542 /*                                                                      */
01543 /*  xsb_close() is currently just a noop, since it doesn't clean        */
01544 /*  anything up, to allow a re-init.                                    */
01545 /*                                                                      */
01546 /************************************************************************/
01547 
01548 DllExport int call_conv xsb_close(CTXTdecl)
01549 {
01550   updateWarningStart();
01551   if (xsb_initted_gl) return(0);
01552   else return(1);
01553 }
01554 
01555 #if defined(WIN_NT)
01556 //
01557 // From: UNIX Application Migration Guide
01558 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnucmg/html/UCMGch10.asp
01559 //
01560 // The version there won't compile as is, but it can be fixed...
01561 //
01562 #include <io.h>
01563 #include <Basetsd.h>
01564 #if !defined(CYGWIN)
01565 typedef SSIZE_T ssize_t;
01566 #endif
01567 static inline ssize_t pread(int fd, void *buf, size_t count, long offset)
01568 {
01569 if (-1 == lseek(fd,offset,SEEK_SET))
01570         return(-1);
01571 return(read(fd,buf,count));
01572 }
01573 #else
01574 //
01575 // For concurrent access to a file (required for asynchronous I/O (AIO) support)
01576 // requires the pread() and pwrite() system calls to actually work
01577 // so let's use the real thing that way we can safely be multi-threaded.
01578 //
01579 #include <unistd.h>
01580 #endif
01581 
01582 /************************************************************************/
01583 /*                                                                      */
01584 /*      xsb_get_last_error_string returns previous answer.             */
01585 /*                                                                      */
01586 /************************************************************************/
01587 DllExport int call_conv xsb_get_last_error_string(char *buff, int buflen, int *anslen)
01588 {
01589 int rc = 2;
01590 ssize_t bytesRead = 1;
01591 ssize_t totalBytesRead = 0;
01592 
01593 if(!flags[STDERR_BUFFERED])
01594         xsb_warn("[xsb_get_last_error_string] This feature must be activated with the -q option");
01595 else
01596         {
01597         rc = 1;                         // Assume failure on the ftell or read
01598         errno = 0;                      // Setup to detect error in ftell
01599         *anslen = (int)(ftell(stderr) - lastWarningStart);
01600         if((0 == errno) && (-1 < *anslen))
01601                 {                               // ftell worked
01602                 if (*anslen >= buflen)
01603                         rc = 3;         // Not enough room in the target buffer
01604                 else
01605                         {
01606                         while ((totalBytesRead < *anslen) && (0 < bytesRead) && !ferror(stderr))
01607                                 {
01608                                 bytesRead = pread(fileno(stderr),&buff[totalBytesRead],(*anslen - totalBytesRead),(lastWarningStart + totalBytesRead));
01609                                 totalBytesRead += bytesRead;
01610                                 }
01611                         if (!ferror(stderr))
01612                                 {
01613                                 rc = 0;
01614                                 if (-1 == bytesRead)
01615                                         *anslen = totalBytesRead + 1;
01616                                 else
01617                                         *anslen = totalBytesRead;
01618                                 buff[*anslen] = 0x00;
01619                                 }
01620                         }
01621                 }
01622         }
01623 return(rc);
01624 }    

Generated on Wed Jul 26 13:30:40 2006 for XSB by  doxygen 1.4.5