18static char SccsId[] =
"%W% %G%";
286#define S_ISDIR(x) (((x)&_S_IFDIR) == _S_IFDIR)
296format_clean_up(
int sno,
int sno0,
format_info *finfo) {
297 if (sno >= 0 && sno != sno0) {
298 sno = format_synch(sno, sno0, finfo);
299 Yap_CloseStream(sno);
301 pop_text_stack(finfo->lvl);
305static int format_print_str(Int sno, Int size, Int has_size, Term args,
308 if (IsStringTerm(args)) {
309 const unsigned char *pt = UStringOfTerm(args);
310 while (*pt && (!has_size || size > 0)) {
313 if ((pt += get_utf8(pt, -1, &ch)) > 0) {
317 }
else if (IsAtomTerm(args)) {
318 if (args == TermNil) {
321 const unsigned char *pt = RepAtom(AtomOfTerm(args))->UStrOfAE;
322 while (*pt && (!has_size || size > 0)) {
325 if ((pt += get_utf8(pt, -1, &ch)) > 0) {
330 while (!has_size || size > 0) {
331 bool maybe_chars =
true, maybe_codes =
true;
332 if (IsVarTerm(args)) {
333 format_clean_up(sno, finfo->sno0, finfo);
334 Yap_ThrowError(INSTANTIATION_ERROR, args,
"~s expects a bound argument");
336 }
else if (args == TermNil) {
338 }
else if (!IsPairTerm(args)) {
339 format_clean_up(sno, finfo->sno0, finfo);
340 Yap_ThrowError(TYPE_ERROR_TEXT, args,
"format expects an atom, string, or list of codes or chars ");
343 arghd = HeadOfTerm(args);
344 args = TailOfTerm(args);
345 if (IsVarTerm(arghd)) {
346 format_clean_up(sno, finfo->sno0, finfo);
347 Yap_ThrowError(INSTANTIATION_ERROR, arghd,
"~s expects a bound argument");
349 }
else if (maybe_codes && IsIntTerm(arghd)) {
350 f_putc(sno, (
int) IntOfTerm(arghd));
353 }
else if (maybe_chars && IsAtomTerm(arghd)) {
354 unsigned char *fptr = RepAtom(AtomOfTerm(arghd))->UStrOfAE;
356 fptr += get_utf8(fptr, -1, &ch);
357 if (fptr[0] !=
'\0') {
358 format_clean_up(sno, finfo->sno0, finfo);
359 Yap_ThrowError(TYPE_ERROR_TEXT, arghd,
"~s expects a list of chars ");
366 format_clean_up(sno, finfo->sno0, finfo);
367 Yap_ThrowError(TYPE_ERROR_TEXT, arghd,
"~s expects an atom, string, or list of codes or chars ");
375static Int format_copy_args(Term args, Term *targs, Int tsz,
int sno,
format_info *finfo) {
377 while (args != TermNil) {
378 if (IsVarTerm(args)) {
379 format_clean_up(sno, finfo->sno0, finfo);
380 Yap_ThrowError(INSTANTIATION_ERROR, args,
"format/2");
381 return FORMAT_COPY_ARGS_ERROR;
383 if (!IsPairTerm(args)) {
384 format_clean_up(sno, finfo->sno0, finfo);
385 Yap_ThrowError(TYPE_ERROR_LIST, args,
"format/2");
386 return FORMAT_COPY_ARGS_ERROR;
389 return FORMAT_COPY_ARGS_OVERFLOW;
391 targs[n] = HeadOfTerm(args);
392 args = TailOfTerm(args);
398static Int fetch_index_from_args(Term t) {
403 if (!IsIntegerTerm(t))
405 i = IntegerOfTerm(t);
411static wchar_t base_dig(Int dig, Int ch) {
415 return (dig - 10) +
'a';
417 return (dig - 10) +
'A';
420#define TMP_STRING_SIZE 1024
422static bool tabulated(
const unsigned char *fptr)
424 const unsigned char *pt = fptr;
426 while ((off = get_utf8(pt, -1, &ch))>0 &&
427 (ch = *(pt + off)) >0) {
430 while ((off = get_utf8(pt, -1, &ch))>0 &&
431 (isdigit((ch=pt[off]))|| ch !=
'*'))
433 if (ch ==
'|' || ch ==
'+' || ch ==
't') {
443#define TOO_FEW_ARGUMENTS(Needs, Has_Repeats) \
444 if (targ > tnum - Needs || Has_Repeats) {\
445 format_clean_up(sno, sno0, finfo);\
446 Yap_ThrowError(DOMAIN_ERROR_FORMAT_CONTROL_SEQUENCE, MkIntTerm(fptr-fstr), "command %c in format string %s has no arguments %s", ch,\
450static Int doformat(
volatile Term otail,
volatile Term oargs,
451 int sno0 USES_REGS) {
452 char *tmp1, *tmpbase;
456 const unsigned char *fstr, *fptr;
459 int (*f_putc)(int, wchar_t);
461 jmp_buf format_botch;
462 Term fmod = CurrentModule;
463 bool alloc_fstr =
false;
464 LOCAL_Error_TYPE = YAP_NO_ERROR;
465 int l = push_text_stack();
466 tmp1 =
Malloc(TMP_STRING_SIZE + 1);
471 finfo->phys_start = 0;
474 finfo->old_handler = GLOBAL_Stream[sno].u.mem_string.error_handler;
475 GLOBAL_Stream[sno].u.mem_string.error_handler = (
void *) &format_botch;
476 finfo->old_pos = GLOBAL_Stream[sno].u.mem_string.pos;
478 if (setjmp(format_botch)) {
479 restore_machine_regs();
482 if (!Yap_growheap(FALSE, LOCAL_Error_Size, NULL)) {
484 Yap_ThrowError(RESOURCE_ERROR_HEAP, otail,
"format/2");
489 GLOBAL_Stream[sno].u.mem_string.pos = finfo->old_pos;
496 if (IsVarTerm(tail)) {
497 format_clean_up(sno0, sno, finfo);
498 Yap_ThrowError(INSTANTIATION_ERROR, tail,
"format/2");
500 }
else if ((fstr = Yap_TextToUTF8Buffer(tail))) {
504 format_clean_up(sno0, sno, finfo);
505 Yap_ThrowError(TYPE_ERROR_TEXT, tail,
"format/2");
508 if (IsVarTerm(args)) {
509 format_clean_up(sno0, sno, finfo);
510 Yap_ThrowError(INSTANTIATION_ERROR, args,
"format/2");
513 args = Yap_YapStripModule(args, &fmod);
515 if (IsVarTerm(fmod)) {
516 format_clean_up(sno0, sno, finfo);
517 Yap_ThrowError(INSTANTIATION_ERROR, fmod,
"format/2");
520 if (!IsAtomTerm(fmod)) {
521 format_clean_up(sno0, sno, finfo);
522 Yap_ThrowError(TYPE_ERROR_ATOM, fmod,
"format/2");
525 if (IsVarTerm(args)) {
526 format_clean_up(sno0, sno, finfo);
527 Yap_ThrowError(INSTANTIATION_ERROR, args,
"format/2");
530 if (IsPairTerm(args)) {
533 targs =
Malloc(tsz *
sizeof(Term));
535 tnum = format_copy_args(args, targs, tsz, sno, finfo);
536 if (tnum == FORMAT_COPY_ARGS_ERROR ||
537 tnum == FORMAT_COPY_ARGS_OVERFLOW) {
538 format_clean_up(sno0, sno, finfo);
540 }
else if (tnum == tsz) {
542 targs = Realloc(targs, tsz *
sizeof(Term));
546 }
else if (args != TermNil) {
548 targs =
Malloc(
sizeof(Term));
553 sno = Yap_OpenBufWriteStream(PASS_REGS1);
557 format_clean_up(sno, sno0, finfo);
560 f_putc = GLOBAL_Stream[sno].stream_wputc;
561 GLOBAL_Stream[sno].status |= CloseOnException_Stream_f;
562 while ((fptr += get_utf8(fptr, -1, &ch)) && ch) {
564 int has_repeats =
false;
569 fptr += get_utf8(fptr, -1, &ch);
571 fptr += get_utf8(fptr, -1, &ch);
573 repeats = fetch_index_from_args(targs[targ++]);
575 format_clean_up(sno, sno0, finfo);
576 Yap_ThrowError(DOMAIN_ERROR_FORMAT_CONTROL_SEQUENCE, targs[targ],
"command %c in format %s", ch,
579 }
else if (ch ==
'`') {
582 fptr += get_utf8(fptr, -1, &repeats);
583 fptr += get_utf8(fptr, -1, &ch);
584 }
else if (ch >=
'0' && ch <=
'9') {
587 while (ch >=
'0' && ch <=
'9') {
588 repeats = repeats * 10 + (ch -
'0');
589 fptr += get_utf8(fptr, -1, &ch);
595 TOO_FEW_ARGUMENTS(1, has_repeats);
598 format_clean_up(sno, sno0, finfo);
599 Yap_ThrowError(INSTANTIATION_ERROR, t,
"command %c in format %s", ch, fstr);
601 if (!IsAtomTerm(t)) {
602 format_clean_up(sno, sno0, finfo);
603 Yap_ThrowError(TYPE_ERROR_ATOM, t,
"command %c in format %s", ch, fstr);
606 Yap_plwrite(t, GLOBAL_Stream + sno, 0,
612 TOO_FEW_ARGUMENTS(1,
false);
615 format_clean_up(sno, sno0, finfo);
616 Yap_ThrowError(INSTANTIATION_ERROR, t,
"command %c in format %s", ch, fstr);
618 if (!IsIntegerTerm(t)) {
619 format_clean_up(sno, sno0, finfo);
620 Yap_ThrowError(TYPE_ERROR_INTEGER, t,
"command %c in format %s", ch, fstr);
622 nch = IntegerOfTerm(t);
624 format_clean_up(sno, sno0, finfo);
625 Yap_ThrowError(DOMAIN_ERROR_NOT_LESS_THAN_ZERO, t,
"command %c in format %s", ch,
630 for (i = 0; i < repeats; i++)
642 TOO_FEW_ARGUMENTS(1,
false);
643 if (targ > tnum - 1) {
644 format_clean_up(sno, sno0, finfo);
645 Yap_ThrowError(DOMAIN_ERROR_FORMAT_CONTROL_SEQUENCE, targs[targ],
"command ~c in format %s",
650 format_clean_up(sno, sno0, finfo);
651 Yap_ThrowError(INSTANTIATION_ERROR, t,
"command %c in format %s", ch, fstr);
654 format_clean_up(sno, sno0, finfo);
655 Yap_ThrowError(TYPE_ERROR_NUMBER, t,
"command %c in format %s", ch, fstr);
657 if (IsIntegerTerm(t)) {
658 fl = (Float) IntegerOfTerm(t);
660 }
else if (IsBigIntTerm(t)) {
661 fl = Yap_gmp_to_float(t);
672 snprintf(ptr, 31 - 5,
"%d", repeats);
674 sprintf(ptr,
"%d", repeats);
681 unsigned char *uptr = (
unsigned char *) tmp1;
683 snprintf(tmp1, repeats + 10, fmt, fl);
685 sprintf(tmp1, fmt, fl);
687 while ((uptr += get_utf8(uptr, -1, &ch)) && ch != 0)
694 TOO_FEW_ARGUMENTS(1,
false);
697 format_clean_up(sno, sno0, finfo);
698 Yap_ThrowError(INSTANTIATION_ERROR, t,
"command %c in format %s", ch, fstr);
700 if (!IsIntegerTerm(t)
706 format_clean_up(sno, sno0, finfo);
707 Yap_ThrowError(TYPE_ERROR_INTEGER, t,
"command %c in format %s", ch, fstr);
714 if (IsIntegerTerm(t)) {
715 Int il = IntegerOfTerm(t);
717 snprintf(tmp1, 256,
"%ld", (
long int) il);
719 sprintf(tmp1,
"%ld", (
long int)il);
725 }
else if (IsBigIntTerm(t) && RepAppl(t)[1] == BIG_INT) {
731 !(res = Yap_gmp_to_string(t, tmpbase, TMP_STRING_SIZE, 10))) {
732 if (tmpbase == tmp1) {
736 format_clean_up(sno, sno0, finfo);
737 Yap_ThrowError(DOMAIN_ERROR_INTEGER, targs[targ],
"command %c in format %s", ch, fstr);
744 siz = strlen(tmpbase);
747 format_clean_up(sno, sno0, finfo);
748 Yap_ThrowError(TYPE_ERROR_INTEGER, targs[targ],
"command %c in format %s", ch, fstr);
752 if (tmpbase[0] ==
'-') {
753 f_putc(sno, (
int)
'-');
759 while (siz > repeats) {
760 if ((siz - repeats) % 3 == 0 && !first) {
761 f_putc(sno, (
int)
',');
763 f_putc(sno, (
int) (*ptr++));
768 while (siz > repeats) {
769 f_putc(sno, (
int) (*ptr++));
774 if (ptr == tmpbase || ptr[-1] ==
'-') {
775 f_putc(sno, (
int)
'0');
777 f_putc(sno, (
int)
'.');
778 while (repeats > siz) {
779 f_putc(sno, (
int)
'0');
783 f_putc(sno, (
int) (*ptr++));
793 UInt divfactor = 1, size = 1, i;
797 TOO_FEW_ARGUMENTS(1,
false);
800 format_clean_up(sno, sno0, finfo);
801 Yap_ThrowError(INSTANTIATION_ERROR, t,
"command %c in format %s", ch,
808 if (radix > 36 || radix < 2) {
809 format_clean_up(sno, sno0, finfo);
810 Yap_ThrowError(DOMAIN_ERROR_RADIX, targs[targ],
"command %c in format %s", ch,
814 if (IsBigIntTerm(t) && RepAppl(t)[1] == BIG_INT) {
819 res = Yap_gmp_to_string(t, tmpbase, TMP_STRING_SIZE, radix))) {
820 if (tmpbase == tmp1) {
825 format_clean_up(sno, sno0, finfo);
826 Yap_ThrowError(TYPE_ERROR_INTEGER, targs[targ],
"command %c in format %s", ch, fstr);
838 if (!IsIntegerTerm(t)) {
839 format_clean_up(sno, sno0, finfo);
840 Yap_ThrowError(TYPE_ERROR_INTEGER, targs[targ],
"command %c in format %s", ch,
843 numb = IntegerOfTerm(t);
846 f_putc(sno, (
int)
'-');
848 while (numb / divfactor >= radix) {
852 for (i = 1; i < size; i++) {
853 Int dig = numb / divfactor;
854 och = base_dig(dig, ch);
859 och = base_dig(numb, ch);
865 TOO_FEW_ARGUMENTS(1,
false);
868 format_clean_up(sno, sno0, finfo);
869 Yap_ThrowError(INSTANTIATION_ERROR, targs[targ],
"command %c in format %s", ch,
872 if (!format_print_str(sno, repeats, has_repeats, t, f_putc, finfo)) {
878 if (targ > tnum - 1 || has_repeats) {
879 format_clean_up(sno, finfo->sno0, finfo);
880 Yap_ThrowError(DOMAIN_ERROR_FORMAT_CONTROL_SEQUENCE, targs[targ],
881 "command ~c in format %s", ch,
887 TOO_FEW_ARGUMENTS(1, has_repeats);
889 yhandle_t sl = Yap_StartSlots();
890 Yap_plwrite(t, GLOBAL_Stream + sno, 0, HR,
891 Quote_illegal_f | Ignore_ops_f | To_heap_f | Handle_cyclics_f,
897 yhandle_t sl0 = Yap_StartSlots(), s1 = Yap_PushHandle(ARG1),
898 sl = Yap_InitSlots(tnum - targ, targs + targ);
901 int os = LOCAL_c_output_stream;
902 LOCAL_c_output_stream = sno;
903 res = Yap_execute_goal(t, 0, fmod,
true);
904 LOCAL_c_output_stream = os;
905 if (Yap_HasException())
910 format_clean_up(sno, sno0, finfo);
913 ARG1 = Yap_GetFromHandle(s1);
914 Yap_RecoverHandles(tnum - targ, sl);
919 TOO_FEW_ARGUMENTS(1,has_repeats);
922 Int sl = Yap_InitSlot(args);
923 Yap_plwrite(t, GLOBAL_Stream + sno, 0, HR,
924 Handle_vars_f | Use_portray_f | To_heap_f | Handle_cyclics_f,
927 args = Yap_GetFromSlot(sl);
930 if (Yap_HasException()) {
935 if (IsAtomTerm(tail)) {
943 format_clean_up(sno, sno0, finfo);
949 TOO_FEW_ARGUMENTS(1,has_repeats);
952 yhandle_t sl0 = Yap_StartSlots();
953 Yap_plwrite(t, GLOBAL_Stream + sno, 0, HR,
954 Handle_vars_f | Quote_illegal_f | To_heap_f | Handle_cyclics_f,
960 TOO_FEW_ARGUMENTS(1,has_repeats);
963 yhandle_t slf = Yap_StartSlots();
964 Yap_plwrite(t, GLOBAL_Stream + sno, 0, HR,
965 Handle_vars_f | To_heap_f | Handle_cyclics_f,
971 TOO_FEW_ARGUMENTS(2,has_repeats);
973 yhandle_t slf = Yap_StartSlots();
974 Yap_WriteTerm(sno, targs[targ], targs[targ + 1] PASS_REGS);
980 TOO_FEW_ARGUMENTS(0,has_repeats);
981 f_putc(sno, (
int)
'~');
987 f_putc(sno, (
int)
'\n');
989 sno = format_synch(sno, sno0, finfo);
994 if (GLOBAL_Stream[sno].linestart !=
995 GLOBAL_Stream[sno].charcount ) {
997 sno = format_synch(sno, sno0, finfo);
1001 for (i = 1; i < repeats; i++)
1005 sno = format_synch(sno, sno0, finfo);
1011 fill_pads(sno, sno0, repeats, finfo PASS_REGS);
1014 fill_pads(sno, sno0, finfo->lstart + repeats, finfo PASS_REGS);
1018 if (fflush(GLOBAL_Stream[sno].file) == 0) {
1019 finfo->gap[finfo->gapi].phys = ftell(GLOBAL_Stream[sno].file);
1022 finfo->gap[finfo->gapi].phys = GLOBAL_Stream[sno].u.mem_string.pos;
1024 finfo->gap[finfo->gapi].log = GLOBAL_Stream[sno].charcount-GLOBAL_Stream[sno].linestart;
1026 finfo->gap[finfo->gapi].filler = fptr[-2];
1028 finfo->gap[finfo->gapi].filler =
' ';
1035 if (IsAtomTerm(tail)) {
1042 format_clean_up(sno, sno0, finfo);
1043 Yap_ThrowError(LOCAL_Error_TYPE,
1044 Yap_MkApplTerm(Yap_MkFunctor(AtomFormat, 2), 2, ta),
1045 "arguments to format");
1053 format_clean_up(sno, sno0, finfo);
1060 sno = format_synch(sno, sno0, finfo);
1067 if (IsAtomTerm(tail) || IsStringTerm(tail)) {
1074 format_clean_up(sno, sno0, finfo);
1079static Term memStreamToTerm(
int output_stream,
Functor f, Term inp) {
1080 const char *s = Yap_MemExportStreamPtr(output_stream);
1082 encoding_t enc = GLOBAL_Stream[output_stream].encoding;
1083 if (f == FunctorAtom) {
1084 return MkAtomTerm(Yap_LookupAtom(s));
1085 }
else if (f == FunctorCodes) {
1086 return Yap_CharsToDiffListOfCodes(s, ArgOfTerm(2, inp), enc PASS_REGS);
1087 }
else if (f == FunctorCodes1) {
1088 return Yap_CharsToListOfCodes(s, enc PASS_REGS);
1089 }
else if (f == FunctorChars) {
1090 return Yap_CharsToDiffListOfAtoms(s, ArgOfTerm(2, inp), enc PASS_REGS);
1091 }
else if (f == FunctorChars1) {
1092 return Yap_CharsToListOfAtoms(s, enc PASS_REGS);
1093 }
else if (f == FunctorString1) {
1094 return Yap_CharsToString(s, enc PASS_REGS);
1096 Yap_ThrowError(DOMAIN_ERROR_FORMAT_OUTPUT, inp, NULL);
1147static Int with_output_to(USES_REGS1) {
1148 int old_out = LOCAL_c_output_stream;
1150 Term tin = Deref(ARG1);
1153 bool mem_stream =
false;
1154 yhandle_t hdl = Yap_PushHandle(tin);
1155 if (IsVarTerm(tin)) {
1156 Yap_ThrowError(INSTANTIATION_ERROR, tin,
"with_output_to/3");
1159 if (IsApplTerm(tin) && (f = FunctorOfTerm(tin))) {
1160 if (f == FunctorAtom || f == FunctorString || f == FunctorCodes1 ||
1161 f == FunctorCodes || f == FunctorChars1 || f == FunctorChars) {
1162 output_stream = Yap_OpenBufWriteStream(PASS_REGS1);
1167 output_stream = Yap_CheckStream(ARG1, Output_Stream_f,
"format/3");
1170 if (output_stream == -1) {
1173 LOCAL_c_output_stream = output_stream;
1174 UNLOCK(GLOBAL_Stream[output_stream].streamlock);
1175 out = Yap_Execute(Deref(ARG2) PASS_REGS);
1176 LOCK(GLOBAL_Stream[output_stream].streamlock);
1177 LOCAL_c_output_stream = old_out;
1180 Term inp = Yap_GetFromHandle(hdl);
1182 tat = memStreamToTerm(output_stream, f, inp);
1183 out = Yap_unify(tat, ArgOfTerm(1, inp));
1186 Yap_CloseStream(output_stream);
1190static Int format(Term tf, Term tas, Term tout USES_REGS) {
1194 if (IsVarTerm(tout)) {
1195 Yap_ThrowError(INSTANTIATION_ERROR, tout,
"format/3");
1198 yhandle_t hl = Yap_StartHandles();
1199 if (IsApplTerm(tout) && (f = FunctorOfTerm(tout)) &&
1200 (f == FunctorAtom || f == FunctorString1 || f == FunctorCodes1 ||
1201 f == FunctorCodes || f == FunctorChars1 || f == FunctorChars)) {
1202 output_stream = Yap_OpenBufWriteStream(PASS_REGS1);
1204 output_stream = Yap_CheckStream(tout, Output_Stream_f,
"format/3");
1206 if (output_stream == -1) {
1207 UNLOCK(GLOBAL_Stream[output_stream].streamlock);
1210 Term out = doformat(tf, tas, output_stream PASS_REGS);
1211 UNLOCK(GLOBAL_Stream[output_stream].streamlock);
1214 Yap_CloseHandles(hl);
1223static Int format2(USES_REGS1) {
1226 res = doformat(Deref(ARG1), Deref(ARG2), LOCAL_c_output_stream PASS_REGS);
1234static Int format3(USES_REGS1) {
1236 res = format(Deref(ARG2), Deref(ARG3), Deref(ARG1) PASS_REGS);
1240void Yap_InitFormat(
void) {
1241 Yap_InitCPred(
"format", 2, format2, SyncPredFlag);
1242 Yap_InitCPred(
"format", 3, format3, SyncPredFlag);
1243 Yap_InitCPred(
"with_output_to", 2, with_output_to, SyncPredFlag);
bool Yap_RaiseException()
let's go
void * Malloc(size_t sz USES_REGS)
allocate a temporary text block