00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "xsb_config.h"
00026 #include "xsb_debug.h"
00027
00028 #include <stdio.h>
00029 #include <signal.h>
00030 #include <errno.h>
00031 #include <string.h>
00032 #include <stdlib.h>
00033 #ifndef WIN_NT
00034 #include <unistd.h>
00035 #endif
00036 #include <sys/stat.h>
00037
00038 #include "setjmp_xsb.h"
00039 #include "auxlry.h"
00040 #include "cell_xsb.h"
00041 #include "context.h"
00042 #include "error_xsb.h"
00043 #include "cinterf.h"
00044 #include "memory_xsb.h"
00045 #include "psc_xsb.h"
00046 #include "heap_xsb.h"
00047 #include "register.h"
00048 #include "flags_xsb.h"
00049 #include "inst_xsb.h"
00050 #include "loader_xsb.h"
00051 #include "subp.h"
00052 #include "tries.h"
00053 #include "choice.h"
00054 #include "macro_xsb.h"
00055 #include "io_builtins_xsb.h"
00056 #include "wind2unix.h"
00057 #include "binding.h"
00058 #include "deref.h"
00059 #include "findall.h"
00060 #include "heap_defs_xsb.h"
00061
00062 stream_record open_files[MAX_OPEN_FILES];
00063
00064
00065
00066 struct fmt_spec {
00067 char type;
00068
00069
00070
00071
00072
00073
00074
00075
00076 char size;
00077 char *fmt;
00078 };
00079
00080 struct next_fmt_state {
00081 int _current_substr_start;
00082 VarString *_workspace;
00083 char _saved_char;
00084 };
00085 #define current_substr_start (fmt_state->_current_substr_start)
00086 #define workspace (*(fmt_state->_workspace))
00087 #define saved_char (fmt_state->_saved_char)
00088
00089 void next_format_substr(CTXTdeclc char*, struct next_fmt_state*, struct fmt_spec *, int, int);
00090 char *p_charlist_to_c_string(CTXTdeclc prolog_term, VarString*, char*, char*);
00091
00092
00093 #define TYPE_ERROR_CHK(ch_type, Label) \
00094 if (current_fmt_spec->type != ch_type) { \
00095 xsb_abort("[%s] in argument value %d. Expected %c, got %c.", Label, i,current_fmt_spec->type,ch_type); \
00096 }
00097
00098 #define PRINT_ARG(arg) switch (current_fmt_spec->size) { \
00099 case 1: fprintf(fptr, current_fmt_spec->fmt, arg); \
00100 break; \
00101 case 2: fprintf(fptr, current_fmt_spec->fmt, width, arg); \
00102 break; \
00103 case 3: fprintf(fptr, current_fmt_spec->fmt, width, precision, arg); \
00104 break; \
00105 }
00106 #define CHECK_ARITY(i, Arity, Label) if (i > Arity) { \
00107 xsb_abort("[%s] Not enough arguments for given format", Label); \
00108 }
00109
00110 #ifdef HAVE_SNPRINTF
00111
00112 #define SPRINT_ARG(arg) \
00113 XSB_StrEnsureSize(&OutString, OutString.length+SAFE_OUT_SIZE); \
00114 switch (current_fmt_spec->size) { \
00115 case 1: bytes_formatted=snprintf(OutString.string+OutString.length, \
00116 SAFE_OUT_SIZE, \
00117 current_fmt_spec->fmt, arg); \
00118 break; \
00119 case 2: bytes_formatted=snprintf(OutString.string+OutString.length, \
00120 SAFE_OUT_SIZE, \
00121 current_fmt_spec->fmt, width, arg); \
00122 break; \
00123 case 3: bytes_formatted=snprintf(OutString.string+OutString.length, \
00124 SAFE_OUT_SIZE, \
00125 current_fmt_spec->fmt, \
00126 width, precision, arg); \
00127 break; \
00128 } \
00129 OutString.length += bytes_formatted; \
00130 XSB_StrNullTerminate(&OutString);
00131
00132 #else
00133
00134
00135
00136
00137
00138 #define SPRINT_ARG(arg) \
00139 XSB_StrEnsureSize(&OutString, OutString.length+SAFE_OUT_SIZE); \
00140 switch (current_fmt_spec->size) { \
00141 case 1: sprintf(OutString.string+OutString.length, \
00142 current_fmt_spec->fmt, arg); \
00143 bytes_formatted = strlen(OutString.string+OutString.length); \
00144 break; \
00145 case 2: sprintf(OutString.string+OutString.length, \
00146 current_fmt_spec->fmt, width, arg); \
00147 bytes_formatted = strlen(OutString.string+OutString.length); \
00148 break; \
00149 case 3: sprintf(OutString.string+OutString.length, \
00150 current_fmt_spec->fmt, \
00151 width, precision, arg); \
00152 bytes_formatted = strlen(OutString.string+OutString.length); \
00153 break; \
00154 } \
00155 OutString.length += bytes_formatted; \
00156 XSB_StrNullTerminate(&OutString);
00157 #endif
00158
00159
00160 xsbBool fmt_write(CTXTdecl);
00161 xsbBool fmt_write_string(CTXTdecl);
00162 xsbBool fmt_read(CTXTdecl);
00163
00164
00165 #include "ptoc_tag_xsb_i.h"
00166
00167
00168 xsbBool formatted_io (CTXTdecl)
00169 {
00170 switch (ptoc_int(CTXTc 1)) {
00171 case FMT_WRITE: return fmt_write(CTXT);
00172 case FMT_WRITE_STRING: return fmt_write_string(CTXT);
00173 case FMT_READ: return fmt_read(CTXT);
00174 default:
00175 xsb_abort("[FORMATTED_IO] Invalid operation number: %d", ptoc_int(CTXTc 1));
00176 }
00177 return TRUE;
00178 }
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193 #define FmtBuf (*tsgSBuff1)
00194 #define StrArgBuf (*tsgSBuff2)
00195
00196 xsbBool fmt_write(CTXTdecl)
00197 {
00198 FILE *fptr;
00199 struct next_fmt_state fmt_state;
00200 char *Fmt=NULL, *str_arg;
00201 char aux_msg[50];
00202 prolog_term ValTerm, Arg, Fmt_term;
00203 int i, Arity=0;
00204 long int_arg;
00205 double float_arg;
00206 struct fmt_spec *current_fmt_spec = (struct fmt_spec *)mem_alloc(sizeof(struct fmt_spec),LEAK_SPACE);
00207 int width=0, precision=0;
00208
00209 XSB_StrSet(&FmtBuf,"");
00210 XSB_StrSet(&StrArgBuf,"");
00211 fmt_state._workspace = tsgLBuff2;
00212 XSB_StrSet(fmt_state._workspace,"");
00213
00214 SET_FILEPTR(fptr, ptoc_int(CTXTc 2));
00215 Fmt_term = reg_term(CTXTc 3);
00216 if (is_list(Fmt_term))
00217 Fmt = p_charlist_to_c_string(CTXTc Fmt_term,&FmtBuf,"FMT_WRITE","format string");
00218 else if (isstring(Fmt_term))
00219 Fmt = string_val(Fmt_term);
00220 else
00221 xsb_abort("[FMT_WRITE] Format must be an atom or a character string");
00222 ValTerm = reg_term(CTXTc 4);
00223 if (isconstr(ValTerm) && !isboxed(ValTerm))
00224 Arity = get_arity(get_str_psc(ValTerm));
00225 else if (isref(ValTerm))
00226
00227 Arity = 0;
00228 else {
00229
00230 prolog_term TmpValTerm=p2p_new(CTXT);
00231
00232 c2p_functor(CTXTc "arg", 1, TmpValTerm);
00233 if (isstring(ValTerm))
00234 c2p_string(CTXTc string_val(ValTerm), p2p_arg(TmpValTerm,1));
00235 else if (isinteger(ValTerm)|isboxedinteger(ValTerm))
00236 c2p_int(CTXTc oint_val(ValTerm), p2p_arg(TmpValTerm,1));
00237 else if (isofloat(ValTerm))
00238 c2p_float(CTXTc ofloat_val(ValTerm), p2p_arg(TmpValTerm,1));
00239 else
00240 xsb_abort("Usage: fmt_write([+IOport,] +FmtStr, +args(A1,A2,...))");
00241 ValTerm = TmpValTerm;
00242 Arity = 1;
00243 }
00244
00245 next_format_substr(CTXTc Fmt, &fmt_state,current_fmt_spec,
00246 1,
00247 0);
00248 xsb_segfault_message =
00249 "++FMT_WRITE: Argument type doesn't match format specifier\n";
00250 signal(SIGSEGV, &xsb_segfault_catcher);
00251
00252 i=0;
00253 while (i <= Arity) {
00254
00255 if (current_fmt_spec->type == '.') {
00256 PRINT_ARG("");
00257 if (i < Arity)
00258 xsb_warn("[FMT_WRITE] More arguments than format specifiers");
00259 goto EXIT_WRITE;
00260 }
00261
00262 i++;
00263
00264 if (current_fmt_spec->size > 1) {
00265 Arg = p2p_arg(ValTerm,i++);
00266 width = (int) int_val(Arg);
00267 }
00268 CHECK_ARITY(i, Arity, "FMT_WRITE");
00269
00270 if (current_fmt_spec->size == 3) {
00271 Arg = p2p_arg(ValTerm,i++);
00272 precision = (int) int_val(Arg);
00273 }
00274 CHECK_ARITY(i, Arity, "FMT_WRITE");
00275
00276 Arg = p2p_arg(ValTerm,i);
00277
00278 if (current_fmt_spec->type == '!') {
00279 } else if (current_fmt_spec->type == 'S') {
00280
00281 XSB_StrSet(&StrArgBuf,"");
00282 print_pterm(CTXTc Arg, TRUE, &StrArgBuf);
00283 PRINT_ARG(StrArgBuf.string);
00284 } else if (isstring(Arg) && !isnil(Arg)) {
00285 TYPE_ERROR_CHK('s', "FMT_WRITE");
00286 str_arg = string_val(Arg);
00287 PRINT_ARG(str_arg);
00288 } else if (islist(Arg) || isnil(Arg)) {
00289 TYPE_ERROR_CHK('s', "FMT_WRITE");
00290 sprintf(aux_msg, "argument %d", i);
00291 str_arg = p_charlist_to_c_string(CTXTc Arg, &StrArgBuf, "FMT_WRITE", aux_msg);
00292 PRINT_ARG(str_arg);
00293 } else if (isinteger(Arg)|isboxedinteger(Arg)) {
00294 TYPE_ERROR_CHK('i', "FMT_WRITE");
00295 int_arg = oint_val(Arg);
00296 PRINT_ARG(int_arg);
00297 } else if (isofloat(Arg)) {
00298 TYPE_ERROR_CHK('f', "FMT_WRITE")
00299 float_arg = ofloat_val(Arg);
00300 PRINT_ARG(float_arg);
00301 } else {
00302 xsb_abort("[FMT_WRITE] Argument %d has illegal type", i);
00303 }
00304 next_format_substr(CTXTc Fmt, &fmt_state,current_fmt_spec,
00305 0 ,
00306 0 );
00307 }
00308
00309
00310 if (current_fmt_spec->type == '.')
00311 PRINT_ARG("");
00312
00313 EXIT_WRITE:
00314 xsb_segfault_message = xsb_default_segfault_msg;
00315 signal(SIGSEGV, xsb_default_segfault_handler);
00316
00317 mem_dealloc(current_fmt_spec,sizeof(struct fmt_spec),LEAK_SPACE);
00318 return TRUE;
00319 }
00320
00321 #undef FmtBuf
00322 #undef StrArgBuf
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333 #define MAX_SPRINTF_STRING_SIZE MAX_IO_BUFSIZE
00334
00335
00336 #ifdef HAVE_SNPRINTF
00337 #define SAFE_OUT_SIZE MAX_SPRINTF_STRING_SIZE
00338 int sprintf(char *s, const char *format, ...);
00339 #else
00340 #define SAFE_OUT_SIZE MAX_SPRINTF_STRING_SIZE/2
00341 #endif
00342
00343 #define OutString (*tsgLBuff1)
00344 #define FmtBuf (*tsgSBuff1)
00345 #define StrArgBuf (*tsgSBuff2)
00346
00347 xsbBool fmt_write_string(CTXTdecl)
00348 {
00349 char *Fmt=NULL, *str_arg;
00350 struct next_fmt_state fmt_state;
00351 char aux_msg[50];
00352 prolog_term ValTerm, Arg, Fmt_term;
00353 int i, Arity;
00354 long int_arg;
00355 double float_arg;
00356 struct fmt_spec *current_fmt_spec = (struct fmt_spec *)mem_alloc(sizeof(struct fmt_spec),LEAK_SPACE);
00357 int width=0, precision=0;
00358
00359 int bytes_formatted=0;
00360
00361 XSB_StrSet(&OutString,"");
00362 XSB_StrSet(&FmtBuf,"");
00363 XSB_StrSet(&StrArgBuf,"");
00364 fmt_state._workspace = tsgLBuff2;
00365 XSB_StrSet(fmt_state._workspace,"");
00366
00367 if (isnonvar(reg_term(CTXTc 2)))
00368 xsb_abort("[FMT_WRITE_STRING] Arg 1 must be an unbound variable");
00369
00370 Fmt_term = reg_term(CTXTc 3);
00371 if (islist(Fmt_term))
00372 Fmt = p_charlist_to_c_string(CTXTc Fmt_term, &FmtBuf,
00373 "FMT_WRITE_STRING", "format string");
00374 else if (isstring(Fmt_term))
00375 Fmt = string_val(Fmt_term);
00376 else
00377 xsb_abort("[FMT_WRITE_STRING] Format must be an atom or a character string");
00378
00379 ValTerm = reg_term(CTXTc 4);
00380 if (isconstr(ValTerm) && ! isboxed(ValTerm))
00381 Arity = get_arity(get_str_psc(ValTerm));
00382 else if (isref(ValTerm))
00383
00384 Arity = 0;
00385 else {
00386
00387 prolog_term TmpValTerm=p2p_new(CTXT);
00388
00389 c2p_functor(CTXTc "arg", 1, TmpValTerm);
00390 if (isstring(ValTerm))
00391 c2p_string(CTXTc string_val(ValTerm), p2p_arg(TmpValTerm,1));
00392 else if (isinteger(ValTerm)|isboxedinteger(ValTerm))
00393 c2p_int(CTXTc oint_val(ValTerm), p2p_arg(TmpValTerm,1));
00394 else if (isofloat(ValTerm))
00395 c2p_float(CTXTc ofloat_val(ValTerm), p2p_arg(TmpValTerm,1));
00396 else
00397 xsb_abort("Usage: fmt_write_string(-OutStr, +FmtStr, +args(A1,A2,...))");
00398
00399 ValTerm = TmpValTerm;
00400 Arity = 1;
00401 }
00402
00403 next_format_substr(CTXTc Fmt, &fmt_state,current_fmt_spec,
00404 1,
00405 0);
00406 xsb_segfault_message =
00407 "++FMT_WRITE_STRING: Argument type doesn't match format specifier\n";
00408 signal(SIGSEGV, &xsb_segfault_catcher);
00409
00410 i=0;
00411 while (i <= Arity) {
00412
00413 if (current_fmt_spec->type == '.') {
00414 SPRINT_ARG("");
00415 if (i < Arity)
00416 xsb_warn("[FMT_WRITE_STRING] More arguments than format specifiers");
00417 goto EXIT_WRITE_STRING;
00418 }
00419
00420 i++;
00421
00422 if (current_fmt_spec->size > 1) {
00423 Arg = p2p_arg(ValTerm,i++);
00424 width = (int) int_val(Arg);
00425 }
00426 CHECK_ARITY(i, Arity, "FMT_WRITE_STRING");
00427
00428 if (current_fmt_spec->size == 3) {
00429 Arg = p2p_arg(ValTerm,i++);
00430 precision = (int) int_val(Arg);
00431 }
00432 CHECK_ARITY(i, Arity, "FMT_WRITE_STRING");
00433
00434 Arg = p2p_arg(ValTerm,i);
00435
00436 if (current_fmt_spec->type == '!') {
00437 } else if (current_fmt_spec->type == 'S') {
00438
00439 XSB_StrSet(&StrArgBuf,"");
00440 print_pterm(CTXTc Arg, TRUE, &StrArgBuf);
00441 SPRINT_ARG(StrArgBuf.string);
00442 } else if (isstring(Arg)) {
00443 TYPE_ERROR_CHK('s', "FMT_WRITE_STRING");
00444 str_arg = string_val(Arg);
00445 SPRINT_ARG(str_arg);
00446 } else if (islist(Arg)) {
00447 TYPE_ERROR_CHK('s', "FMT_WRITE_STRING");
00448 sprintf(aux_msg, "argument %d", i);
00449 str_arg = p_charlist_to_c_string(CTXTc Arg, &StrArgBuf,
00450 "FMT_WRITE_STRING", aux_msg);
00451 SPRINT_ARG(str_arg);
00452 } else if (isinteger(Arg)|isboxedinteger(Arg)) {
00453 TYPE_ERROR_CHK('i', "FMT_WRITE_STRING");
00454 int_arg = oint_val(Arg);
00455 SPRINT_ARG(int_arg);
00456 } else if (isofloat(Arg)) {
00457 TYPE_ERROR_CHK('f', "FMT_WRITE_STRING");
00458 float_arg = ofloat_val(Arg);
00459 SPRINT_ARG(float_arg);
00460 } else {
00461 xsb_abort("[FMT_WRITE_STRING] Argument %d has illegal type", i);
00462 }
00463 next_format_substr(CTXTc Fmt, &fmt_state,current_fmt_spec,
00464 0 ,
00465 0 );
00466 }
00467
00468
00469 if (current_fmt_spec->type == '.') {
00470 SPRINT_ARG("");
00471 }
00472
00473 EXIT_WRITE_STRING:
00474 xsb_segfault_message = xsb_default_segfault_msg;
00475 signal(SIGSEGV, xsb_default_segfault_handler);
00476
00477 mem_dealloc(current_fmt_spec,sizeof(struct fmt_spec),LEAK_SPACE);
00478
00479
00480
00481 ctop_string(CTXTc 2, string_find(OutString.string,1));
00482
00483 return TRUE;
00484 }
00485 #undef OutString
00486 #undef FmtBuf
00487 #undef StrArgBuf
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499 #define FmtBuf (*tsgSBuff1)
00500 #define StrArgBuf (*tsgSBuff2)
00501 #define aux_fmt (*tsgLBuff1)
00502
00503 xsbBool fmt_read(CTXTdecl)
00504 {
00505 FILE *fptr;
00506 char *Fmt=NULL;
00507 struct next_fmt_state fmt_state;
00508 prolog_term AnsTerm, Arg, Fmt_term;
00509 Integer i ;
00510 long int_arg;
00511 float float_arg;
00512 struct fmt_spec *current_fmt_spec = (struct fmt_spec *)mem_alloc(sizeof(struct fmt_spec),LEAK_SPACE);
00513 int Arity=0;
00514 int number_of_successes=0, curr_assignment=0;
00515 int cont;
00516 int chars_accumulator=0, curr_chars_consumed=0;
00517
00518 XSB_StrSet(&FmtBuf,"");
00519 XSB_StrSet(&StrArgBuf,"");
00520 XSB_StrSet(&aux_fmt,"");
00521 fmt_state._workspace = tsgLBuff2;
00522 XSB_StrSet(fmt_state._workspace,"");
00523
00524 SET_FILEPTR(fptr, ptoc_int(CTXTc 2));
00525 Fmt_term = reg_term(CTXTc 3);
00526 if (islist(Fmt_term))
00527 Fmt = p_charlist_to_c_string(CTXTc Fmt_term,&FmtBuf,"FMT_READ","format string");
00528 else if (isstring(Fmt_term))
00529 Fmt = string_val(Fmt_term);
00530 else
00531 xsb_abort("[FMT_READ] Format must be an atom or a character string");
00532
00533 AnsTerm = reg_term(CTXTc 4);
00534 if (isconstr(AnsTerm))
00535 Arity = get_arity(get_str_psc(AnsTerm));
00536 else if (isref(AnsTerm)) {
00537
00538 prolog_term TmpAnsTerm=p2p_new(CTXT), TmpArg;
00539
00540 Arity = 1;
00541 c2p_functor(CTXTc "arg", 1, TmpAnsTerm);
00542
00543
00544
00545
00546
00547
00548 TmpArg = p2p_arg(TmpAnsTerm,1);
00549 p2p_unify(CTXTc TmpArg, AnsTerm);
00550 AnsTerm = TmpAnsTerm;
00551 } else
00552 xsb_abort("Usage: fmt_read([IOport,] FmtStr, args(A1,A2,...), Feedback)");
00553
00554
00555 if (isnonvar(reg_term(CTXTc 5)))
00556 xsb_abort("[FMT_READ] Arg 4 must be an unbound variable");
00557
00558 next_format_substr(CTXTc Fmt, &fmt_state,current_fmt_spec,
00559 1,
00560 1);
00561 XSB_StrSet(&aux_fmt, current_fmt_spec->fmt);
00562 XSB_StrAppend(&aux_fmt,"%n");
00563
00564 for (i = 1; (i <= Arity); i++) {
00565 Arg = p2p_arg(AnsTerm,i);
00566 cont = 0;
00567 curr_chars_consumed=0;
00568
00569
00570 if (current_fmt_spec->size == 0)
00571 current_fmt_spec->type = '-';
00572
00573 switch (current_fmt_spec->type) {
00574 case '-':
00575
00576
00577 fscanf(fptr, aux_fmt.string, &curr_chars_consumed);
00578 curr_assignment = 0;
00579 i--;
00580 cont = 1;
00581 break;
00582 case '.':
00583 curr_assignment = fscanf(fptr, current_fmt_spec->fmt);
00584 if (isref(Arg))
00585 xsb_warn("[FMT_READ] More arguments than format specifiers");
00586 goto EXIT_READ;
00587 case 's':
00588 XSB_StrEnsureSize(&StrArgBuf, MAX_IO_BUFSIZE);
00589 curr_assignment = fscanf(fptr, aux_fmt.string,
00590 StrArgBuf.string,
00591 &curr_chars_consumed);
00592
00593
00594 if (curr_assignment <= 0) {
00595 if (isref(Arg)) break;
00596 else goto EXIT_READ_FALSE;
00597 }
00598 if (isref(Arg))
00599 c2p_string(CTXTc StrArgBuf.string,Arg);
00600 else if (strcmp(StrArgBuf.string, string_val(Arg)))
00601 goto EXIT_READ_FALSE;
00602 break;
00603 case 'n':
00604 int_arg = -1;
00605 curr_assignment = fscanf(fptr, current_fmt_spec->fmt, &int_arg);
00606 if (int_arg < 0) break;
00607 cont = 1;
00608 curr_chars_consumed = int_arg;
00609 int_arg += chars_accumulator;
00610 if (isref(Arg))
00611 c2p_int(CTXTc int_arg,Arg);
00612 else xsb_abort("[FMT_READ] Argument %i must be a variable", i);
00613 break;
00614 case 'i':
00615 curr_assignment = fscanf(fptr, aux_fmt.string,
00616 &int_arg, &curr_chars_consumed);
00617
00618
00619 if (curr_assignment <= 0) {
00620 if (isref(Arg)) break;
00621 else goto EXIT_READ_FALSE;
00622 }
00623 if (isref(Arg))
00624 c2p_int(CTXTc int_arg,Arg);
00625 else if (int_arg != (Integer)oint_val(Arg)) goto EXIT_READ_FALSE;
00626 break;
00627 case 'f':
00628 curr_assignment = fscanf(fptr, aux_fmt.string,
00629 &float_arg, &curr_chars_consumed);
00630
00631 if (!isref(Arg)) goto EXIT_READ_FALSE;
00632
00633 if (curr_assignment <= 0) break;
00634 c2p_float(CTXTc float_arg, Arg);
00635 break;
00636 default:
00637 xsb_abort("[FMT_READ] Unsupported format specifier for argument %d", i);
00638 }
00639
00640 chars_accumulator +=curr_chars_consumed;
00641
00642
00643 if (curr_assignment > 0 || cont)
00644 number_of_successes =
00645 (curr_assignment ? number_of_successes+1 : number_of_successes);
00646 else
00647 break;
00648
00649 next_format_substr(CTXTc Fmt, &fmt_state,current_fmt_spec,
00650 0 ,
00651 1 );
00652 XSB_StrSet(&aux_fmt, current_fmt_spec->fmt);
00653 XSB_StrAppend(&aux_fmt,"%n");
00654 }
00655
00656
00657
00658
00659
00660 if (current_fmt_spec->type == '.')
00661 curr_assignment = fscanf(fptr, current_fmt_spec->fmt);
00662
00663 if (current_fmt_spec->size == 0)
00664 fscanf(fptr, aux_fmt.string, &curr_chars_consumed);
00665
00666
00667 if ((number_of_successes == 0) && (curr_assignment < 0))
00668 number_of_successes = -1;
00669
00670 EXIT_READ:
00671 mem_dealloc(current_fmt_spec,sizeof(struct fmt_spec),LEAK_SPACE);
00672 ctop_int(CTXTc 5, number_of_successes);
00673 return TRUE;
00674
00675 EXIT_READ_FALSE:
00676 mem_dealloc(current_fmt_spec,sizeof(struct fmt_spec),LEAK_SPACE);
00677 return FALSE;
00678 }
00679 #undef FmtBuf
00680 #undef StrArgBuf
00681 #undef aux_fmt
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695 static Psc prevpsc = 0;
00696
00697
00698
00699
00700
00701
00702
00703
00704 CPtr init_term_buffer(CTXTdeclc int *findall_chunk_index) {
00705 *findall_chunk_index = findall_init_c(CTXT);
00706 current_findall = findall_solutions + *findall_chunk_index;
00707 return current_findall->top_of_chunk ;
00708 }
00709
00710 #define ensure_term_space(ptr,size) \
00711 if ((ptr+size) > (current_findall->current_chunk + FINDALL_CHUNCK_SIZE -1)) {\
00712 if (!get_more_chunk(CTXT)) xsb_abort("Cannot allocate space for term buffer") ;\
00713 ptr = current_findall->top_of_chunk ;\
00714 }
00715
00716 #define free_term_buffer() findall_free(CTXTc findall_chunk_index)
00717
00718 static int read_can_error(CTXTdeclc FILE *filep, STRFILE *instr, int prevchar, Cell prologvar, int findall_chunk_index)
00719 {
00720 char *ptr;
00721
00722 xsb_error("READ_CAN_ERROR: illegal format. Next tokens:");
00723 while ((token->type != TK_EOC) && (token->type != TK_EOF)) {
00724 ptr = token->value;
00725 switch (token->type) {
00726 case TK_PUNC : fprintf(stderr,"%c ", *ptr); break;
00727 case TK_VARFUNC : fprintf(stderr,"%s ", ptr); break;
00728 case TK_VAR : fprintf(stderr,"%s ", ptr); break;
00729 case TK_FUNC : fprintf(stderr,"%s ", ptr); break;
00730 case TK_INT : fprintf(stderr,"%d ", *(int *)ptr); break;
00731 case TK_ATOM : fprintf(stderr,"%s ", ptr); break;
00732 case TK_VVAR : fprintf(stderr,"%s ", ptr); break;
00733 case TK_VVARFUNC : fprintf(stderr,"%s ", ptr); break;
00734 case TK_REAL : fprintf(stderr,"%f ", *(double *)ptr); break;
00735 case TK_STR : fprintf(stderr,"%s ", ptr); break;
00736 case TK_LIST : fprintf(stderr,"%s ", ptr); break;
00737 case TK_HPUNC : fprintf(stderr,"%c ", *ptr); break;
00738 case TK_INTFUNC : fprintf(stderr,"%d ", *(int *)ptr); break;
00739 case TK_REALFUNC : fprintf(stderr,"%f ", *(double *)ptr); break;
00740 }
00741 token = GetToken(CTXTc filep,instr,prevchar);
00742 prevchar = token-> nextch;
00743 }
00744 if (token->type == TK_EOC)
00745 fprintf(stderr,".\n");
00746 else
00747 fprintf(stderr,"\n");
00748 free_term_buffer();
00749 unify(CTXTc prologvar,makestring(string_find("read_canonical_error",1)));
00750 return 0;
00751 }
00752
00753
00754
00755
00756
00757
00758 #define INIT_STK_SIZE 32
00759 #define MAX_INIT_STK_SIZE 1000
00760
00761 #define FUNFUN 0
00762 #define FUNLIST 1
00763 #define FUNDTLIST 2
00764 #define FUNCOMMALIST 3
00765
00766 #ifndef MULTI_THREAD
00767 int opstk_size = 0;
00768 int funstk_size = 0;
00769 struct funstktype *funstk;
00770 struct opstktype *opstk;
00771 struct vartype rc_vars[MAXVAR];
00772 #endif
00773
00774 #define setvar(loc,op1) \
00775 if (rc_vars[opstk[op1].op].varval) \
00776 cell(loc) = rc_vars[opstk[op1].op].varval; \
00777 else { \
00778 cell(loc) = (Cell) loc; \
00779 rc_vars[opstk[op1].op].varval = (Cell) loc; \
00780 }
00781
00782 #define expand_opstk {\
00783 opstk_size = opstk_size+opstk_size;\
00784 opstk = (struct opstktype *)mem_realloc(opstk,(opstk_size/2)*sizeof(struct opstktype),\
00785 opstk_size*sizeof(struct opstktype),READ_CAN_SPACE);\
00786 if (!opstk) xsb_abort("[READ_CANONICAL] Out of space for operand stack");\
00787 \
00788 }
00789 #define expand_funstk {\
00790 funstk_size = funstk_size+funstk_size;\
00791 funstk = (struct funstktype *)mem_realloc(funstk,(funstk_size/2)*sizeof(struct funstktype),\
00792 funstk_size*sizeof(struct funstktype),READ_CAN_SPACE);\
00793 if (!funstk) xsb_abort("[READ CANONICAL] Out of space for function stack");\
00794 \
00795 }
00796
00797 int read_canonical(CTXTdecl)
00798 {
00799 FILE *filep;
00800 STRFILE *instr;
00801 long tempfp;
00802
00803 tempfp = ptoc_int(CTXTc 1);
00804 if (tempfp == -1000) {
00805 prevpsc = 0;
00806 return TRUE;
00807 }
00808
00809 if ((tempfp < 0) && (tempfp >= -MAXIOSTRS)) {
00810 instr = strfileptr(tempfp);
00811 filep = NULL;
00812 } else {
00813 instr = NULL;
00814 SET_FILEPTR(filep, tempfp);
00815 }
00816 ctop_int(CTXTc 3,read_canonical_term(CTXTc filep, instr, 1));
00817 return TRUE;
00818 }
00819
00820 Cell read_canonical_return_var(CTXTdeclc int code) {
00821 if (code == 1) {
00822 return (Cell)ptoc_tag(CTXTc 2);
00823 } else if (code == 2) {
00824 Cell op1, op;
00825 op = ptoc_tag(CTXTc 4);
00826 op1 = cell(clref_val(op)+1);
00827 XSB_Deref(op1);
00828 return op1;
00829 } else return (Cell)NULL;
00830 }
00831
00832
00833 #ifndef FAST_FLOATS
00834 inline void bld_boxedfloat_here(CTXTdeclc CPtr *h, CPtr addr, Float value)
00835 {
00836 Float tempFloat = value;
00837 new_heap_functor((*h),box_psc);
00838 bld_int(*h,((ID_BOXED_FLOAT << BOX_ID_OFFSET ) | FLOAT_HIGH_16_BITS(tempFloat) ));
00839 (*h)++;
00840 bld_int(*h,FLOAT_MIDDLE_24_BITS(tempFloat)); (*h)++;
00841 bld_int(*h,FLOAT_LOW_24_BITS(tempFloat)); (*h)++;
00842 cell(addr) = makecs((*h)-4);
00843 }
00844 #else
00845 inline void bld_boxedfloat_here(CTXTdeclc CPtr *h, CPtr addr, Float value) {
00846 bld_float(addr,value);
00847 }
00848 #endif
00849
00850
00851 int read_canonical_term(CTXTdeclc FILE *filep, STRFILE *instr, int return_location_code)
00852 {
00853 int findall_chunk_index;
00854 int funtop = 0;
00855 int optop = 0;
00856 int cvarbot = MAXVAR-1;
00857 int prevchar, arity, i, size;
00858 CPtr h;
00859 int j, op1, retpscptr;
00860 Pair sym;
00861 Float float_temp;
00862 Psc headpsc, termpsc;
00863 char *cvar;
00864 int postopreq = FALSE, varfound = FALSE;
00865 prolog_term term;
00866 Cell prologvar = read_canonical_return_var(CTXTc return_location_code);
00867
00868 if (opstk_size == 0) {
00869 opstk =
00870 (struct opstktype *)mem_alloc(INIT_STK_SIZE*sizeof(struct opstktype),READ_CAN_SPACE);
00871 opstk_size = INIT_STK_SIZE;
00872 funstk =
00873 (struct funstktype *)mem_alloc(INIT_STK_SIZE*sizeof(struct funstktype),READ_CAN_SPACE);
00874 funstk_size = INIT_STK_SIZE;
00875 }
00876
00877
00878 h = init_term_buffer(CTXTc &findall_chunk_index);
00879 size = 0;
00880
00881 prevchar = 10;
00882 while (1) {
00883 token = GetToken(CTXTc filep,instr,prevchar);
00884
00885 prevchar = token->nextch;
00886 if (postopreq) {
00887 if (token->type == TK_PUNC) {
00888 if (*token->value == ')') {
00889 CPtr this_term;
00890 funtop--;
00891 if (funstk[funtop].funtyp == FUNFUN) {
00892 arity = optop - funstk[funtop].funop;
00893 ensure_term_space(h,arity+1);
00894 this_term = h;
00895 op1 = funstk[funtop].funop;
00896 if ((arity == 2) && !(strcmp(funstk[funtop].fun,"."))) {
00897 if (opstk[op1].typ == TK_VAR) { setvar(h,op1) }
00898 else cell(h) = opstk[op1].op;
00899 h++;
00900 if (opstk[op1+1].typ == TK_VAR) { setvar(h,op1+1) }
00901 else cell(h) = opstk[op1+1].op;
00902 h++;
00903 opstk[op1].op = makelist(this_term);
00904 opstk[op1].typ = TK_FUNC;
00905 size += 2;
00906 } else {
00907 size += arity+1;
00908 sym = (Pair)insert(funstk[funtop].fun,(char)arity,
00909 (Psc)flags[CURRENT_MODULE],&i);
00910 new_heap_functor(h, sym->psc_ptr);
00911 for (j=op1; j<optop; h++,j++) {
00912 if (opstk[j].typ == TK_VAR) { setvar(h,j) }
00913 else cell(h) = opstk[j].op;
00914 }
00915 opstk[op1].op = makecs(this_term);
00916 opstk[op1].typ = TK_FUNC;
00917 }
00918 optop = op1+1;
00919 } else if (funstk[funtop].funtyp == FUNCOMMALIST) {
00920 op1 = funstk[funtop].funop;
00921 if ((op1+1) == optop) {
00922 } else {
00923 CPtr prev_tail;
00924 ensure_term_space(h,3);
00925 this_term = h;
00926
00927 new_heap_functor(h, comma_psc);
00928
00929 if (opstk[op1].typ == TK_VAR) { setvar(h,op1) }
00930 else cell(h) = opstk[op1].op;
00931 h++;
00932 prev_tail = h;
00933 h++;
00934 size += 3;
00935 for (j=op1+1; j<optop-1; j++) {
00936 ensure_term_space(h,3);
00937 cell(prev_tail) = makecs(h);
00938 new_heap_functor(h, comma_psc);
00939 if (opstk[j].typ == TK_VAR) { setvar(h,j) }
00940 else cell(h) = opstk[j].op;
00941 h++;
00942 prev_tail = h;
00943 h++;
00944 size += 3;
00945 }
00946 j = optop-1;
00947 if (opstk[j].typ == TK_VAR) { setvar(prev_tail,j) }
00948 else cell(prev_tail) = opstk[j].op;
00949 opstk[op1].op = makecs(this_term);
00950 opstk[op1].typ = TK_FUNC;
00951 optop = op1+1;
00952 }
00953 } else {
00954 return read_can_error(CTXTc filep,instr,prevchar,prologvar,findall_chunk_index);
00955 }
00956 } else if (*token->value == ']') {
00957 CPtr this_term, prev_tail;
00958 funtop--;
00959 if (funstk[funtop].funtyp == FUNFUN || funstk[funtop].funtyp == FUNCOMMALIST)
00960 return read_can_error(CTXTc filep,instr,prevchar,prologvar,findall_chunk_index);
00961 ensure_term_space(h,2);
00962 this_term = h;
00963 op1 = funstk[funtop].funop;
00964
00965 if (opstk[op1].typ == TK_VAR) { setvar(h,op1) }
00966 else cell(h) = opstk[op1].op;
00967 h++;
00968 size += 2;
00969 if ((op1+1) == optop) {
00970 cell(h) = makenil;
00971 h++;
00972 } else {
00973 prev_tail = h;
00974 h++;
00975 for (j=op1+1; j<optop-1; j++) {
00976 ensure_term_space(h,2);
00977 cell(prev_tail) = makelist(h);
00978 if (opstk[j].typ == TK_VAR) { setvar(h,j) }
00979 else cell(h) = opstk[j].op;
00980 h++;
00981 prev_tail = h;
00982 h++;
00983 size += 2;
00984 }
00985 j = optop-1;
00986 if (funstk[funtop].funtyp == FUNLIST) {
00987 ensure_term_space(h,2);
00988 cell(prev_tail) = makelist(h);
00989 if (opstk[j].typ == TK_VAR) { setvar(h,j) }
00990 else cell(h) = opstk[j].op;
00991 h++;
00992 prev_tail = h;
00993 h++;
00994 cell(prev_tail) = makenil;
00995 size += 2;
00996 } else {
00997 if (opstk[j].typ == TK_VAR) { setvar(prev_tail,j) }
00998 else cell(prev_tail) = opstk[j].op;
00999 }
01000 }
01001 opstk[op1].op = makelist(this_term);
01002 opstk[op1].typ = TK_FUNC;
01003 optop = op1+1;
01004 } else if (*token->value == ',') {
01005 postopreq = FALSE;
01006 } else if (*token->value == '|') {
01007 postopreq = FALSE;
01008 if (funstk[funtop-1].funtyp != FUNLIST)
01009 return read_can_error(CTXTc filep,instr,prevchar,prologvar,findall_chunk_index);
01010 funstk[funtop-1].funtyp = FUNDTLIST;
01011 } else return read_can_error(CTXTc filep,instr,prevchar,prologvar,findall_chunk_index);
01012 } else {
01013 if (opstk[optop-1].typ == TK_ATOM &&
01014 !strcmp("-",string_val(opstk[optop-1].op))) {
01015 if (token->type == TK_INT) {
01016 opstk[optop-1].typ = TK_INT;
01017 opstk[optop-1].op = makeint(-(*(int *)token->value));
01018 } else if (token->type == TK_REAL) {
01019 float_temp = (Float) *(double *)(token->value);
01020 #ifdef FAST_FLOATS
01021 opstk[optop-1].typ = TK_REAL;
01022 opstk[optop-1].op = makefloat((float)-float_temp);
01023 #else
01024 ensure_term_space(h,4);
01025 opstk[optop-1].typ = TK_FUNC;
01026 bld_boxedfloat_here(CTXTc &h, &opstk[optop-1].op, -float_temp);
01027 #endif
01028 } else return read_can_error(CTXTc filep,instr,prevchar,prologvar,findall_chunk_index);
01029 } else return read_can_error(CTXTc filep,instr,prevchar,prologvar,findall_chunk_index);
01030 }
01031 } else {
01032 switch (token->type) {
01033 case TK_PUNC:
01034 if (*token->value == '[') {
01035 if(token->nextch == ']') {
01036 if (optop >= opstk_size) expand_opstk;
01037 token = GetToken(CTXTc filep,instr,prevchar);
01038
01039 prevchar = token->nextch;
01040 opstk[optop].typ = TK_ATOM;
01041 opstk[optop].op = makenil;
01042 optop++;
01043 postopreq = TRUE;
01044 } else {
01045 if (funtop >= funstk_size) expand_funstk;
01046 funstk[funtop].funop = optop;
01047 funstk[funtop].funtyp = FUNLIST;
01048 funtop++;
01049 }
01050 break;
01051 } else if (*token->value == '(') {
01052 if (funtop >= funstk_size) expand_funstk;
01053 funstk[funtop].funop = optop;
01054 funstk[funtop].funtyp = FUNCOMMALIST;
01055 funtop++;
01056 break;
01057 }
01058
01059 case TK_FUNC:
01060 if (funtop >= funstk_size) expand_funstk;
01061 funstk[funtop].fun = (char *)string_find(token->value,1);
01062 funstk[funtop].funop = optop;
01063 funstk[funtop].funtyp = FUNFUN;
01064 funtop++;
01065
01066 if (token->nextch != '(')
01067 return read_can_error(CTXTc filep,instr,prevchar,prologvar,findall_chunk_index);
01068 token = GetToken(CTXTc filep,instr,prevchar);
01069
01070 prevchar = token->nextch;
01071 break;
01072 case TK_VVAR:
01073 if ((token->value)[1] == 0) {
01074 if (cvarbot < 0)
01075 xsb_abort("[READ_CANONICAL] too many variables in term");
01076 i = cvarbot;
01077 rc_vars[cvarbot].varid = (Cell) "_";
01078 rc_vars[cvarbot].varval = 0;
01079 cvarbot--;
01080 if (optop >= opstk_size) expand_opstk;
01081 opstk[optop].typ = TK_VAR;
01082 opstk[optop].op = (prolog_term) i;
01083 optop++;
01084 postopreq = TRUE;
01085 break;
01086 }
01087 case TK_VAR:
01088 varfound = TRUE;
01089 cvar = (char *)string_find(token->value,1);
01090 i = MAXVAR-1;
01091 while (i>cvarbot) {
01092 if (cvar == (char *)rc_vars[i].varid) break;
01093 i--;
01094 }
01095 if (i == cvarbot) {
01096 if (cvarbot < 0)
01097 xsb_abort("[READ_CANONICAL] too many variables in term");
01098 rc_vars[cvarbot].varid = (Cell) cvar;
01099 rc_vars[cvarbot].varval = 0;
01100 cvarbot--;
01101 }
01102 if (optop >= opstk_size) expand_opstk;
01103 opstk[optop].typ = TK_VAR;
01104 opstk[optop].op = (prolog_term) i;
01105 optop++;
01106 postopreq = TRUE;
01107 break;
01108 case TK_REAL:
01109 if (optop >= opstk_size) expand_opstk;
01110 float_temp = (Float)* (double *)(token->value);
01111 #ifdef FAST_FLOATS
01112 opstk[optop].typ = TK_REAL;
01113 opstk[optop].op = makefloat((float)float_temp);
01114 #else
01115 ensure_term_space(h,4);
01116 opstk[optop].typ = TK_FUNC;
01117 bld_boxedfloat_here(CTXTc &h, &opstk[optop].op, float_temp);
01118 #endif
01119 optop++;
01120 postopreq = TRUE;
01121 break;
01122 case TK_INT:
01123 if (optop >= opstk_size) expand_opstk;
01124 opstk[optop].typ = TK_INT;
01125 opstk[optop].op = makeint(*(long *)token->value);
01126 optop++;
01127 postopreq = TRUE;
01128 break;
01129 case TK_ATOM:
01130 if (optop >= opstk_size) expand_opstk;
01131 opstk[optop].typ = TK_ATOM;
01132 opstk[optop].op = makestring((char *)string_find(token->value,1));
01133 optop++;
01134 postopreq = TRUE;
01135 break;
01136 case TK_LIST:
01137 if (optop >= opstk_size) expand_opstk;
01138 if ((token->value)[0] == 0) {
01139 opstk[optop].typ = TK_ATOM;
01140 opstk[optop].op = makenil;
01141 optop++;
01142 postopreq = TRUE;
01143 break;
01144 } else {
01145 CPtr this_term, prev_tail;
01146 char *charptr = token->value;
01147 ensure_term_space(h,2);
01148 this_term = h;
01149 cell(h) = makeint((int)*charptr); charptr++;
01150 h++;
01151 prev_tail = h;
01152 h++;
01153 size += 2;
01154 while (*charptr != 0) {
01155 ensure_term_space(h,2);
01156 cell(prev_tail) = makelist(h);
01157 cell(h) = makeint((int)*charptr); charptr++;
01158 h++;
01159 prev_tail = h;
01160 h++;
01161 size += 2;
01162 }
01163 cell(prev_tail) = makenil;
01164 opstk[optop].op = makelist(this_term);
01165 opstk[optop].typ = TK_FUNC;
01166 optop++;
01167 postopreq = TRUE;
01168 break;
01169 }
01170 case TK_EOF:
01171 free_term_buffer();
01172 if (isnonvar(prologvar))
01173 xsb_abort("[READ_CANONICAL] Argument must be a variable");
01174 unify(CTXTc prologvar,makestring(string_find("end_of_file",1)));
01175 return 0;
01176 default: return read_can_error(CTXTc filep,instr,prevchar,prologvar,findall_chunk_index);
01177 }
01178 }
01179 if (funtop == 0) {
01180 token = GetToken(CTXTc filep,instr,prevchar);
01181
01182 prevchar = token->nextch;
01183 if (token->type != TK_EOF && token->type != TK_EOC)
01184 return read_can_error(CTXTc filep,instr,prevchar,prologvar,findall_chunk_index);
01185
01186 if (opstk[0].typ != TK_VAR) {
01187 if (isnonvar(prologvar))
01188 xsb_abort("[READ_CANONICAL] Argument must be a variable");
01189 term = opstk[0].op;
01190
01191 check_glstack_overflow(5, pcreg, (size+1)*sizeof(Cell)) ;
01192
01193 prologvar = read_canonical_return_var(CTXTc return_location_code);
01194 gl_bot = (CPtr)glstack.low; gl_top = (CPtr)glstack.high;
01195 bind_ref((CPtr)prologvar,hreg);
01196 new_heap_free(hreg);
01197 gl_bot = (CPtr)glstack.low; gl_top = (CPtr)glstack.high;
01198 findall_copy_to_heap(CTXTc term,(CPtr)prologvar,&hreg) ;
01199 free_term_buffer();
01200
01201 XSB_Deref(prologvar);
01202 term = (prolog_term) prologvar;
01203 if ((isinteger(term)|isboxedinteger(term)) ||
01204 isofloat(term) ||
01205 isstring(term) ||
01206 varfound) {
01207 retpscptr = 0;
01208 prevpsc = 0;
01209 } else {
01210 termpsc = get_str_psc(term);
01211 if (termpsc == if_psc) {
01212 if (!isconstr(p2p_arg(term,1))) headpsc = 0;
01213 else headpsc = get_str_psc(p2p_arg(term,1));
01214 } else {
01215 headpsc = termpsc;
01216 }
01217 if (headpsc == prevpsc) {
01218 retpscptr = (Integer)prevpsc;
01219 } else {
01220 prevpsc = headpsc;
01221 retpscptr = 0;
01222 }
01223 }
01224 } else {
01225 retpscptr = 0;
01226 prevpsc = 0;
01227 }
01228
01229 if (opstk_size > MAX_INIT_STK_SIZE) {
01230 mem_dealloc(opstk,opstk_size,READ_CAN_SPACE); opstk = NULL;
01231 mem_dealloc(funstk,funstk_size,READ_CAN_SPACE); funstk = NULL;
01232 opstk_size = 0; funstk_size = 0;
01233 }
01234 return retpscptr;
01235 }
01236 }
01237 }
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250 void next_format_substr(CTXTdeclc char *format, struct next_fmt_state *fmt_state,
01251 struct fmt_spec *result,
01252 int initialize, int read_op)
01253 {
01254 int pos, keep_going;
01255 char *ptr;
01256
01257 char *exclude, *expect;
01258
01259 if (initialize) {
01260 current_substr_start = 0;
01261 XSB_StrSet(&workspace,format);
01262 } else {
01263
01264 workspace.string[current_substr_start] = saved_char;
01265 }
01266
01267 pos = current_substr_start;
01268 result->type = '?';
01269 result->size = 1;
01270
01271
01272 if (current_substr_start >= workspace.length) {
01273 result->type = '.';
01274 result->fmt = "";
01275 return;
01276 }
01277
01278
01279 do {
01280
01281 if ((ptr=strchr(workspace.string+pos, '%')) == NULL) {
01282 current_substr_start = workspace.length;
01283 result->type = '.';
01284 result->fmt = workspace.string+pos;
01285 return;
01286 }
01287
01288 pos = (ptr - workspace.string) + 1;
01289 if (workspace.string[pos] == '%')
01290 pos++;
01291 else break;
01292 } while (1);
01293
01294
01295
01296 keep_going = TRUE;
01297 expect = exclude = "";
01298 while ((pos < workspace.length) && keep_going) {
01299 if (strchr(exclude, workspace.string[pos]) != NULL) {
01300 xsb_abort("[FMT_READ/WRITE] Illegal format specifier `%c' in: %s",
01301 workspace.string[pos],
01302 workspace.string+current_substr_start);
01303 }
01304 if (strlen(expect) && strchr(expect, workspace.string[pos]) == NULL) {
01305 xsb_abort("[FMT_READ/WRITE] Illegal format specifier `%c' in: %s",
01306 workspace.string[pos],
01307 workspace.string+current_substr_start);
01308 }
01309
01310 expect = exclude = "";
01311
01312 switch (workspace.string[pos++]) {
01313 case '1':
01314 case '2':
01315 case '3':
01316 case '4':
01317 case '5':
01318 case '6':
01319 case '7':
01320 case '8':
01321 case '9':
01322 exclude = "+- #[]";
01323 break;
01324 case '.':
01325 exclude = "+- #[]";
01326 expect = "0123456789*";
01327 break;
01328 case '0':
01329 case '+':
01330 case '-':
01331 exclude = "+-[]";
01332 break;
01333 case 'h':
01334 case 'l':
01335 exclude = "+- #[]hlL";
01336 expect = "diouxXn";
01337 break;
01338 case 'L':
01339 expect = "eEfgG";
01340 exclude = "+- #[]hlL";
01341 break;
01342 case ' ':
01343 case '#':
01344 exclude = "+- #[]hlL";
01345 break;
01346 case 'c':
01347 if (read_op)
01348 result->type = 's';
01349 else
01350 result->type = 'i';
01351 keep_going = FALSE;
01352 break;
01353 case 'd':
01354 case 'i':
01355 case 'u':
01356 case 'o':
01357 case 'x':
01358 case 'X':
01359 keep_going = FALSE;
01360 result->type = 'i';
01361 break;
01362 case 'e':
01363 case 'E':
01364 case 'f':
01365 case 'g':
01366 case 'G':
01367 keep_going = FALSE;
01368 result->type = 'f';
01369 break;
01370 case 's':
01371 keep_going = FALSE;
01372 result->type = 's';
01373 break;
01374 case 'S':
01375 keep_going = FALSE;
01376 result->type = 'S';
01377 workspace.string[pos-1] = 's';
01378 break;
01379 case 'p':
01380 xsb_abort("[FMT_READ/WRITE] Format specifier %%p not supported: %s",
01381 workspace.string+current_substr_start);
01382 case 'n':
01383 if (read_op) {
01384 result->type = 'n';
01385
01386 keep_going = FALSE;
01387 break;
01388 }
01389 xsb_abort("[FMT_WRITE] Format specifier %%n not supported: %s",
01390 workspace.string+current_substr_start);
01391 case '[':
01392
01393 if (!read_op) {
01394 xsb_abort("[FMT_WRITE] Format specifier [ is invalid for output: %s",
01395 workspace.string+current_substr_start);
01396 }
01397 while ((pos < workspace.length) && (workspace.string[pos++] != ']'));
01398 if (workspace.string[pos-1] != ']') {
01399 xsb_abort("[FMT_READ] Format specifier [ has no matching ] in: %s",
01400 workspace.string+current_substr_start);
01401 }
01402 result->type = 's';
01403 keep_going = FALSE;
01404 break;
01405
01406 case '*':
01407 if (read_op) {
01408 result->size = 0;
01409 break;
01410 }
01411 if (strncmp(workspace.string+pos, ".*", 2) == 0) {
01412 pos = pos+2;
01413 expect = "feEgEscdiuoxX";
01414 result->size = 3;
01415 } else if (workspace.string[pos] == '.') {
01416 pos++;
01417 expect = "0123456789";
01418 result->size = 2;
01419 } else {
01420 result->size = 2;
01421 expect = "feEgEscdiuoxX";
01422 }
01423 break;
01424
01425 case '!':
01426 printf("set !\n");
01427 result->type = '!';
01428 keep_going = FALSE;
01429 break;
01430
01431 default:
01432 xsb_abort("[FMT_READ/WRITE] Character `%c' in illegal format context: %s",
01433 workspace.string[pos-1],
01434 workspace.string+current_substr_start);
01435 }
01436 }
01437
01438 saved_char = workspace.string[pos];
01439 workspace.string[pos] = '\0';
01440 result->fmt = workspace.string+current_substr_start;
01441 current_substr_start = pos;
01442 return;
01443 }
01444
01445
01446
01447
01448
01449 int xsb_intern_fileptr(FILE *fptr, char *context,char* name,char *strmode)
01450 {
01451 int i;
01452 char mode = '\0';
01453
01454
01455
01456 if (!fptr) return -1;
01457
01458 if (!strcmp(strmode,"rb") || !strcmp(strmode,"r"))
01459 mode = 'r';
01460 else if (!strcmp(strmode,"wb") || !strcmp(strmode,"w"))
01461 mode = 'w';
01462 else if (!strcmp(strmode,"ab") || !strcmp(strmode,"a"))
01463 mode = 'a';
01464 else if (!strcmp(strmode,"rb+") || !strcmp(strmode,"r+") || !strcmp(strmode,"r+b"))
01465 mode = 's';
01466 else if (!strcmp(strmode,"wb+") || !strcmp(strmode,"w+") || !strcmp(strmode,"w+b"))
01467 mode = 'x';
01468 else if (!strcmp(strmode,"ab+") || !strcmp(strmode,"a+") || !strcmp(strmode,"a+b"))
01469 mode = 'b';
01470
01471 for (i=MIN_USR_OPEN_FILE; i < MAX_OPEN_FILES && open_files[i].file_ptr != NULL; i++);
01472 if (i == MAX_OPEN_FILES) {
01473 xsb_warn("[%s] Too many open files", context);
01474 return -1;
01475 } else {
01476 open_files[i].file_ptr = fptr;
01477 open_files[i].file_name = string_find(name,1);
01478 open_files[i].io_mode = mode;
01479 return i;
01480 }
01481 }
01482
01483
01484
01485
01486
01487
01488
01489
01490 int xsb_intern_file(char *context,char *addr, int *ioport,char *strmode,int opennew)
01491 {
01492 FILE *fptr;
01493 int i, first_null, stream_found;
01494 char mode = '\0';
01495
01496
01497
01498 if (!strcmp(strmode,"rb") || !strcmp(strmode,"r"))
01499 mode = 'r';
01500 else if (!strcmp(strmode,"wb") || !strcmp(strmode,"w"))
01501 mode = 'w';
01502 else if (!strcmp(strmode,"ab") || !strcmp(strmode,"a"))
01503 mode = 'a';
01504 else if (!strcmp(strmode,"rb+") || !strcmp(strmode,"r+") || !strcmp(strmode,"r+b"))
01505 mode = 's';
01506 else if (!strcmp(strmode,"wb+") || !strcmp(strmode,"w+") || !strcmp(strmode,"w+b"))
01507 mode = 'x';
01508 else if (!strcmp(strmode,"ab+") || !strcmp(strmode,"a+") || !strcmp(strmode,"a+b"))
01509 mode = 'b';
01510
01511 for (i=MIN_USR_OPEN_FILE, stream_found = -1, first_null = -1;
01512 i < MAX_OPEN_FILES;
01513 i++) {
01514 if (open_files[i].file_ptr != NULL) {
01515 if (!opennew && open_files[i].file_name != NULL &&
01516 !strcmp(addr,open_files[i].file_name) &&
01517 open_files[i].io_mode == mode) {
01518 stream_found = i;
01519 break;
01520 } } else if (first_null < 0) {first_null = i; if (opennew) break;}
01521 }
01522
01523
01524
01525
01526
01527
01528
01529 if (stream_found < 0 && first_null < 0) {
01530 for (i=MIN_USR_OPEN_FILE;
01531 i < MAX_OPEN_FILES ;
01532 i++) printf("File Ptr %p Name %s\n",open_files[i].file_ptr, open_files[i].file_name);
01533
01534 xsb_warn("[%s] Too many open files", context);
01535 *ioport = 0;
01536 return -1;
01537 }
01538 else if (stream_found >= 0) {
01539 fptr = open_files[i].file_ptr;
01540 *ioport = stream_found;
01541 return 0;
01542 }
01543 else {
01544 struct stat stat_buff;
01545 fptr = fopen(addr, strmode);
01546 if (!fptr) {*ioport = 0; return -1;}
01547 else if (!stat(addr, &stat_buff) && !S_ISDIR(stat_buff.st_mode)) {
01548
01549 open_files[first_null].file_ptr = fptr;
01550 open_files[first_null].file_name = string_find(addr,1);
01551 open_files[first_null].io_mode = mode;
01552 *ioport = first_null;
01553 return 0;
01554 } else {
01555 xsb_warn("FILE_OPEN: File %s is a directory, cannot open!", addr);
01556 fclose(fptr);
01557 return -1;
01558 }
01559 }
01560 }
01561
01562 void mark_open_filenames() {
01563 int i;
01564
01565 for (i=MIN_USR_OPEN_FILE; i < MAX_OPEN_FILES; i++) {
01566 if (open_files[i].file_ptr != NULL) {
01567 mark_string(open_files[i].file_name,"Filename");
01568 }
01569 }
01570 }
01571
01572
01573
01574
01575 xsbBool quotes_are_needed(char *string)
01576 {
01577 int nextchar;
01578 int ctr, flag;
01579
01580 if (*string == '\0') return TRUE;
01581 if (!strcmp(string,"[]")) return FALSE;
01582 if (string[0] == '/' && string[1] == '*') return TRUE;
01583 ctr = 0;
01584 nextchar = (int) string[0];
01585 flag = 0;
01586 if (nextchar >= 97 && nextchar <= 122) {
01587 while (nextchar != '\0' && !flag) {
01588 if (nextchar < 48
01589 || (nextchar > 57 && nextchar < 65)
01590 || ((nextchar > 90 && nextchar < 97) && nextchar != 95)
01591 || (nextchar > 122))
01592 flag = 1;
01593 ctr++;
01594 nextchar = (int) string[ctr];
01595 }
01596 if (!flag) return FALSE;
01597 }
01598
01599 if (string[1] == '\0') {
01600 if ((int) string[0] == 33 )
01601 return FALSE;
01602 if ((int) string[0] == 46) return TRUE;
01603 }
01604
01605 nextchar = (int) string[0];
01606 ctr = 0;
01607 while (nextchar != '\0' && !flag) {
01608 switch(nextchar) {
01609 case 35: case 36: case 38: case 42: case 43: case 45: case 46:
01610 case 47: case 58: case 60: case 61: case 62: case 63: case 64:
01611 case 92: case 94: case 96: case 126:
01612 nextchar++;
01613 break;
01614 default:
01615 flag = 1;
01616 }
01617 ctr++;
01618 nextchar = (int) string[ctr];
01619 }
01620 return flag;
01621 }
01622
01623
01624 void double_quotes(char *string, char *new_string)
01625 {
01626 int ctr = 0, nctr = 0;
01627
01628 while (string[ctr] != '\0') {
01629 if (string[ctr] == '\'') {
01630 new_string[nctr] = '\'';
01631 nctr++;
01632 } else if (string[ctr] == '\\') {
01633 char ch = string[ctr+1];
01634 if (ch == 'a' || ch == 'b' || ch == 'f' || ch == 'n' ||
01635 ch == 'r' || ch == 't' || ch == 'v' || ch == 'x' ||
01636 ch == '0' || ch == '1' || ch == '2' || ch == '3' ||
01637 ch == '4' || ch == '5' || ch == '6' || ch == '7' ||
01638 ch == '\\' || ch == '"' || ch == '`') {
01639 new_string[nctr] = '\\';
01640 nctr++;
01641 }
01642 }
01643 new_string[nctr] = string[ctr];
01644 nctr++; ctr++;
01645 }
01646 new_string[nctr] = '\0';
01647 }
01648
01649 void write_quotedname(FILE *file, char *string)
01650 {
01651 if (*string == '\0')
01652 fprintf(file,"''");
01653 else {
01654 if (!quotes_are_needed(string)) {
01655 fprintf(file,"%s",string);
01656 }
01657 else {
01658 int neededlen = 2*strlen(string)+1;
01659 if (neededlen < 1000) {
01660 char lnew_string[1000];
01661 double_quotes(string,lnew_string);
01662 fprintf(file,"\'%s\'",lnew_string);
01663 } else {
01664 char* new_string;
01665 new_string = (char *)mem_alloc(neededlen,LEAK_SPACE);
01666 double_quotes(string,new_string);
01667 fprintf(file,"\'%s\'",new_string);
01668 mem_dealloc(new_string,neededlen,LEAK_SPACE);
01669 }
01670 }
01671 }
01672 }
01673
01674
01675
01676 static Psc dollar_var_psc = NULL;
01677 #define wcan_string tsgLBuff1
01678 #define wcan_atombuff tsgLBuff2
01679 #define wcan_buff tsgSBuff1
01680
01681 void call_conv write_canonical_term_rec(CTXTdeclc Cell prologterm, int letter_flag)
01682 {
01683 XSB_Deref(prologterm);
01684 switch (cell_tag(prologterm))
01685 {
01686 case XSB_INT:
01687 sprintf(wcan_buff->string,"%ld",(long)int_val(prologterm));
01688 XSB_StrAppendV(wcan_string,wcan_buff);
01689 break;
01690 case XSB_STRING:
01691 if (quotes_are_needed(string_val(prologterm))) {
01692 int len_needed = 2*strlen(string_val(prologterm))+1;
01693 XSB_StrEnsureSize(wcan_atombuff,len_needed);
01694 double_quotes(string_val(prologterm),wcan_atombuff->string);
01695 XSB_StrAppendC(wcan_string,'\'');
01696 XSB_StrAppend(wcan_string,wcan_atombuff->string);
01697 XSB_StrAppendC(wcan_string,'\'');
01698 } else XSB_StrAppend(wcan_string,string_val(prologterm));
01699 break;
01700 case XSB_FLOAT:
01701
01702 sprintf(wcan_buff->string,"%.15g",float_val(prologterm));
01703 XSB_StrAppendV(wcan_string,wcan_buff);
01704 break;
01705 case XSB_REF:
01706 case XSB_REF1: {
01707 int varval;
01708 XSB_StrAppendC(wcan_string,'_');
01709 if (prologterm >= (Cell)glstack.low && prologterm <= (Cell)top_of_heap) {
01710 XSB_StrAppendC(wcan_string,'h');
01711 varval = (long) ((prologterm-(Cell)glstack.low+1)/sizeof(CPtr));
01712 } else {
01713 if (prologterm >= (Cell)top_of_localstk && prologterm <= (Cell)glstack.high) {
01714 XSB_StrAppendC(wcan_string,'l');
01715 varval = (long) (((Cell)glstack.high-prologterm+1)/sizeof(CPtr));
01716 } else varval = prologterm;
01717 }
01718 sprintf(wcan_buff->string,"%d",varval);
01719 XSB_StrAppendV(wcan_string,wcan_buff);
01720 }
01721 break;
01722 case XSB_STRUCT:
01723
01724
01725
01726 if (isboxedinteger(prologterm))
01727 {
01728 sprintf(wcan_buff->string,"%ld",(long)boxedint_val(prologterm));
01729 XSB_StrAppendV(wcan_string,wcan_buff);
01730 break;
01731 }
01732 else if (isboxedfloat(prologterm))
01733 {
01734
01735 sprintf(wcan_buff->string,"%.15g",boxedfloat_val(prologterm));
01736 XSB_StrAppendV(wcan_string,wcan_buff);
01737 break;
01738 }
01739
01740 if (!dollar_var_psc) {
01741 int new_indicator;
01742 dollar_var_psc = pair_psc(insert("$VAR", 1, global_mod, &new_indicator));
01743 }
01744 if (letter_flag && (get_str_psc(prologterm) == dollar_var_psc)) {
01745 int ival, letter;
01746 Cell tempi = cell(clref_val(prologterm)+1);
01747 XSB_Deref(tempi);
01748 if (!isinteger(tempi)) xsb_abort("[write_canonical]: illegal $VAR argument");
01749 ival = int_val(tempi);
01750 letter = ival % 26;
01751 ival = ival / 26;
01752 XSB_StrAppendC(wcan_string,(char)(letter+'A'));
01753 if (ival != 0) {
01754 sprintf(wcan_buff->string,"%d",ival);
01755 XSB_StrAppendV(wcan_string,wcan_buff);
01756 }
01757 } else {
01758 int i;
01759 char *fnname = get_name(get_str_psc(prologterm));
01760 if (quotes_are_needed(fnname)) {
01761 int len_needed = 2*strlen(fnname)+1;
01762 XSB_StrEnsureSize(wcan_atombuff,len_needed);
01763 double_quotes(fnname,wcan_atombuff->string);
01764 XSB_StrAppendC(wcan_string,'\'');
01765 XSB_StrAppend(wcan_string,wcan_atombuff->string);
01766 XSB_StrAppendC(wcan_string,'\'');
01767 } else XSB_StrAppend(wcan_string,fnname);
01768 XSB_StrAppendC(wcan_string,'(');
01769 for (i = 1; i < get_arity(get_str_psc(prologterm)); i++) {
01770 write_canonical_term_rec(CTXTc cell(clref_val(prologterm)+i),letter_flag);
01771 XSB_StrAppendC(wcan_string,',');
01772 }
01773 write_canonical_term_rec(CTXTc cell(clref_val(prologterm)+i),letter_flag);
01774 XSB_StrAppendC(wcan_string,')');
01775 }
01776 break;
01777 case XSB_LIST:
01778 {Cell tail;
01779 XSB_StrAppendC(wcan_string,'[');
01780 write_canonical_term_rec(CTXTc cell(clref_val(prologterm)),letter_flag);
01781 tail = cell(clref_val(prologterm)+1);
01782 XSB_Deref(tail);
01783 while (islist(tail)) {
01784 XSB_StrAppendC(wcan_string,',');
01785 write_canonical_term_rec(CTXTc cell(clref_val(tail)),letter_flag);
01786 tail = cell(clref_val(tail)+1);
01787 XSB_Deref(tail);
01788 }
01789 if (!isnil(tail)) {
01790 XSB_StrAppendC(wcan_string,'|');
01791 write_canonical_term_rec(CTXTc tail,letter_flag);
01792 }
01793 XSB_StrAppendC(wcan_string,']');
01794 }
01795 break;
01796 default:
01797 xsb_abort("Unsupported subterm tag");
01798 return;
01799 }
01800 return;
01801 }
01802
01803 DllExport void call_conv write_canonical_term(CTXTdeclc Cell prologterm, int letter_flag)
01804 {
01805 XSB_StrSet(wcan_string,"");
01806 XSB_StrEnsureSize(wcan_buff,40);
01807 write_canonical_term_rec(CTXTc prologterm, letter_flag);
01808 }
01809
01810 void print_term_canonical(CTXTdeclc FILE *fptr, Cell prologterm, int letterflag)
01811 {
01812
01813 write_canonical_term(CTXTc prologterm, letterflag);
01814 fprintf(fptr, "%s", wcan_string->string);
01815 }
01816
01817 #undef wcan_string
01818 #undef wcan_atombuff
01819 #undef wcan_buff