fix format to use two streams, including a memory buffer; simpler

This commit is contained in:
Vitor Santos Costa 2016-05-12 11:40:22 +01:00
parent 407280ea3b
commit e92062886b

View File

@ -263,61 +263,118 @@ output is directed to the stream used by format/2.
#define FORMAT_MAX_SIZE 1024 #define FORMAT_MAX_SIZE 1024
typedef struct { typedef struct {
Int len, start; /* tab point */
Int filler; /* character to dump */ Int filler; /* character to dump */
char *pad; /* ok, it's not standard english */ int phys; /* position in buffer */
} pads; int log; /* columnn as wide chsh */
} gap_t;
typedef struct format_status { typedef struct format_status {
char *mem; // direct access to stream fields
int format_error; int format_error;
pads pad_entries[16]; gap_t gap[16];
int padders; // number of octets
int phys_start;
// number of characters
int lstart;
int gapi;
} format_info; } format_info;
static int fill(int sno, int n, wchar_t nch) { static bool format_synch(int sno, int sno0, format_info *fg ) {
int (*f_putc)(int, wchar_t); int (*f_putc)(int, int);
f_putc = GLOBAL_Stream[sno].stream_wputc; const char *s;
int n;
f_putc = GLOBAL_Stream[sno0].stream_putc;
#if MAY_WRITE
if (fflush(GLOBAL_Stream[sno].file) == 0) {
s = GLOBAL_Stream[sno].nbuf;
n = ftell(GLOBAL_Stream[sno].file);
} else
return false;
#else
s = GLOBAL_Stream[sno].u.mem_string.buf;
n = GLOBAL_Stream[sno].u.mem_string.pos;
#endif
while (n--) while (n--)
f_putc(sno, nch); f_putc(sno0, *s++);
return nch; #if MAY_WRITE
} rewind(GLOBAL_Stream[sno].file);
#else
static int f_puts(int sno, char *s, int n) { GLOBAL_Stream[sno].u.mem_string.pos = 0;
int (*f_putc)(int, wchar_t); #endif
f_putc = GLOBAL_Stream[sno].stream_wputc; GLOBAL_Stream[sno].linecount = 1;
while (n--) GLOBAL_Stream[sno].linepos = 0;
f_putc(sno, *s++); GLOBAL_Stream[sno].charcount = 0;
return *s; fg->lstart = 0;
fg->phys_start=0;
fg->gapi=0;
return true;
} }
// uses directly the buffer in the memory stream. // uses directly the buffer in the memory stream.
static bool fill_pads(int sno, int nchars, format_info *fg USES_REGS) { static bool fill_pads(int sno, int sno0, int total, format_info *fg USES_REGS) {
int nfillers, fill_space, lfill_space; int nfillers, fill_space, lfill_space, nchars;
int (*f_putc)(int, int);
const char *buf;
int phys_end;
f_putc = GLOBAL_Stream[sno0].stream_putc;
#if MAY_WRITE
if (fflush(GLOBAL_Stream[sno].file) == 0) {
buf = GLOBAL_Stream[sno].nbuf;
phys_end = ftell(GLOBAL_Stream[sno].file);
} else
return false;
#else
buf = GLOBAL_Stream[sno].u.mem_string.buf;
phys_end = GLOBAL_Stream[sno].u.mem_string.pos;
#endif
if (fg->gapi == 0) {
fg->gap[0].phys = phys_end;
fg->gap[0].filler = ' ';
fg->gapi = 1;
}
nchars = total - GLOBAL_Stream[sno].linepos;
if (nchars < 0) if (nchars < 0)
nchars = 0; /* ignore */ nchars = 0; /* ignore */
nfillers = fg->padders; nfillers = fg->gapi;
if (fg->padders == 0) {
return fill(sno, nchars, ' ');
}
fill_space = nchars / nfillers; fill_space = nchars / nfillers;
lfill_space = nchars % nfillers; lfill_space = nchars % nfillers;
pads *padi = fg->pad_entries; int i = fg->phys_start;
gap_t *padi = fg->gap;
while (fg->padders--) { while (i < phys_end) {
if (!fg->padders) if (i == padi->phys) {
fill_space += lfill_space; int j;
// give remainder to last block. for (j=0; j < fill_space; j++)
fill(sno, fill_space, padi->filler); f_putc(sno0, padi->filler);
if (padi->pad) { padi++;
f_puts(sno, (char *)padi->pad, padi->len); /* last gap??*/
free(padi->pad); if (padi-fg->gap == fg->gapi) {
padi->pad = NULL; for (j=0; j < fill_space; j++)
f_putc(sno0, padi->filler);
}
} }
padi++; f_putc(sno0,buf[i++]);
} }
// final gap
if (i == padi->phys) {
int j;
for (j=0; j < fill_space+lfill_space; j++)
f_putc(sno0, padi->filler);
};
#if MAY_WRITE
rewind(GLOBAL_Stream[sno].file);
#else
GLOBAL_Stream[sno].u.mem_string.pos = 0;
#endif
GLOBAL_Stream[sno].linecount = 1;
GLOBAL_Stream[sno].linepos += nchars;
GLOBAL_Stream[sno].charcount = 0;
fg->phys_start=0;
fg->lstart = GLOBAL_Stream[sno].linepos;
fg->gapi=0;
return true; return true;
} }
@ -425,7 +482,9 @@ static Int format_copy_args(Term args, Term *targs, Int tsz) {
static void static void
format_clean_up(int sno, const char *fstr, const Term *targs) { format_clean_up(int sno, int sno0, format_info *finf, const char *fstr, const Term *targs) {
format_synch( sno, sno0, finf);
Yap_CloseStream(sno);
if (fstr) { if (fstr) {
Yap_FreeAtomSpace((void *)fstr); Yap_FreeAtomSpace((void *)fstr);
} }
@ -458,7 +517,7 @@ static wchar_t base_dig(Int dig, Int ch) {
#define TMP_STRING_SIZE 1024 #define TMP_STRING_SIZE 1024
static Int doformat(volatile Term otail, volatile Term oargs, static Int doformat(volatile Term otail, volatile Term oargs,
int sno USES_REGS) { int sno0 USES_REGS) {
char tmp1[TMP_STRING_SIZE], *tmpbase; char tmp1[TMP_STRING_SIZE], *tmpbase;
int ch; int ch;
Term mytargs[8], *targs; Term mytargs[8], *targs;
@ -467,18 +526,16 @@ static Int doformat(volatile Term otail, volatile Term oargs,
Term args; Term args;
Term tail; Term tail;
int (*f_putc)(int, wchar_t); int (*f_putc)(int, wchar_t);
int osno = 0; int sno = sno0;
jmp_buf format_botch; jmp_buf format_botch;
volatile void *old_handler; volatile void *old_handler;
volatile int old_pos; volatile int old_pos;
format_info finfo; format_info finfo;
unsigned char *ubuf = NULL;
Term fmod = CurrentModule; Term fmod = CurrentModule;
size_t sz = 0;
finfo.padders = 0;
finfo.format_error = FALSE; finfo.format_error = FALSE;
if (GLOBAL_Stream[sno].status & InMemory_Stream_f) { if (GLOBAL_Stream[sno0].status & InMemory_Stream_f) {
old_handler = GLOBAL_Stream[sno].u.mem_string.error_handler; old_handler = GLOBAL_Stream[sno].u.mem_string.error_handler;
GLOBAL_Stream[sno].u.mem_string.error_handler = (void *)&format_botch; GLOBAL_Stream[sno].u.mem_string.error_handler = (void *)&format_botch;
old_pos = GLOBAL_Stream[sno].u.mem_string.pos; old_pos = GLOBAL_Stream[sno].u.mem_string.pos;
@ -573,12 +630,20 @@ static Int doformat(volatile Term otail, volatile Term oargs,
tnum = 0; tnum = 0;
targs = mytargs; targs = mytargs;
} }
finfo.format_error = false;
// it starts here
finfo.format_error = false;
finfo.gapi = 0;
sno0 = sno;
sno = Yap_OpenBufWriteStream(PASS_REGS1);
finfo.format_error = false;
finfo.gapi = 0;
finfo.phys_start = 0;
finfo.lstart = 0;
f_putc = GLOBAL_Stream[sno].stream_wputc; f_putc = GLOBAL_Stream[sno].stream_wputc;
while ((ch = *fptr++)) { while ((ch = *fptr++)) {
Term t = TermNil; Term t = TermNil;
int has_repeats = FALSE; int has_repeats = false;
int repeats = 0; int repeats = 0;
if (ch == '~') { if (ch == '~') {
@ -928,7 +993,7 @@ static Int doformat(volatile Term otail, volatile Term oargs,
if (GLOBAL_Stream[sno].status & InMemory_Stream_f) { if (GLOBAL_Stream[sno].status & InMemory_Stream_f) {
GLOBAL_Stream[sno].u.mem_string.error_handler = old_handler; GLOBAL_Stream[sno].u.mem_string.error_handler = old_handler;
} }
format_clean_up(sno, (char *)fstr, targs); format_clean_up(sno, sno0, &finfo, (char *)fstr, targs);
Yap_RaiseException(); Yap_RaiseException();
return false; return false;
} }
@ -957,73 +1022,55 @@ static Int doformat(volatile Term otail, volatile Term oargs,
goto do_consistency_error; goto do_consistency_error;
f_putc(sno, (int)'~'); f_putc(sno, (int)'~');
break; break;
case 'n': case 'n':
if (!has_repeats) if (!has_repeats)
repeats = 1; repeats = 1;
while (repeats--) { while (repeats--) {
f_putc(sno, (int)'\n'); f_putc(sno, (int)'\n');
} }
finfo.padders = 0; format_synch( sno, sno0, &finfo);
break; break;
case 'N': case 'N':
if (!has_repeats) if (!has_repeats)
has_repeats = 1; has_repeats = 1;
if (GLOBAL_Stream[sno].linepos != 0) { if (GLOBAL_Stream[sno].linepos != 0) {
f_putc(sno, '\n'); f_putc(sno, '\n');
finfo.padders = 0; format_synch( sno, sno0, &finfo);
} }
if (repeats > 1) { if (repeats > 1) {
Int i; Int i;
for (i = 1; i < repeats; i++) for (i = 1; i < repeats; i++)
f_putc(sno, '\n'); f_putc(sno, '\n');
finfo.padders = 0;
} }
format_synch( sno, sno0, &finfo);
break; break;
/* padding */ /* padding */
case '|': case '|':
if (osno) { fill_pads(sno, sno0, repeats, &finfo PASS_REGS);
Yap_CloseStream(sno);
sno = osno;
osno = 0;
}
repeats -= GLOBAL_Stream[sno].linepos;
repeats = (repeats < 0 ? 0 : repeats);
fill_pads(sno, repeats, &finfo PASS_REGS);
break; break;
case '+': case '+':
if (osno) { fill_pads(sno, sno0, finfo.lstart+repeats, &finfo PASS_REGS);
Yap_CloseStream(sno);
sno = osno;
osno = 0;
}
repeats = (repeats < 0 ? 0 : repeats);
fill_pads(sno, repeats, &finfo PASS_REGS);
break; break;
case 't': { case 't': {
int nsno; #if MAY_WRITE
if (fflush(GLOBAL_Stream[sno].file) == 0) {
finfo.pad_entries[finfo.padders].len = sz; finfo.gap[finfo.gapi].phys =
finfo.pad_entries[finfo.padders].pad = (char *)ubuf; ftell(GLOBAL_Stream[sno].file);
nsno = Yap_open_buf_write_stream(GLOBAL_Stream[sno].encoding, 0);
if (osno) {
GLOBAL_Stream[nsno].linepos = GLOBAL_Stream[sno].linepos;
GLOBAL_Stream[nsno].linecount = GLOBAL_Stream[sno].linecount;
GLOBAL_Stream[nsno].charcount = GLOBAL_Stream[sno].charcount;
Yap_CloseStream(sno);
} else {
osno = sno;
GLOBAL_Stream[nsno].linepos = GLOBAL_Stream[sno].linepos;
GLOBAL_Stream[nsno].linecount = GLOBAL_Stream[sno].linecount;
GLOBAL_Stream[nsno].charcount = GLOBAL_Stream[sno].charcount;
} }
sno = nsno; #else
finfo.pad_entries[finfo.padders].start = GLOBAL_Stream[sno].linepos; finfo.gap[finfo.gapi].phys =
if (!has_repeats) GLOBAL_Stream[sno].u.mem_string.pos;
finfo.pad_entries[finfo.padders].filler = ' '; #endif
finfo.gap[finfo.gapi].log = GLOBAL_Stream[sno].linepos;
if (has_repeats)
finfo.gap[finfo.gapi].filler = fptr[-2];
else else
finfo.pad_entries[finfo.padders].filler = fptr[-2]; finfo.gap[finfo.gapi].filler = ' ';
finfo.padders++; finfo.gapi++;
} break; }
break;
do_instantiation_error: do_instantiation_error:
LOCAL_Error_TYPE = INSTANTIATION_ERROR; LOCAL_Error_TYPE = INSTANTIATION_ERROR;
goto do_default_error; goto do_default_error;
@ -1062,7 +1109,7 @@ static Int doformat(volatile Term otail, volatile Term oargs,
if (GLOBAL_Stream[sno].status & InMemory_Stream_f) { if (GLOBAL_Stream[sno].status & InMemory_Stream_f) {
GLOBAL_Stream[sno].u.mem_string.error_handler = old_handler; GLOBAL_Stream[sno].u.mem_string.error_handler = old_handler;
} }
format_clean_up(sno, fstr, targs); format_clean_up(sno, sno0, &finfo, fstr, targs);
LOCAL_Error_TYPE = YAP_NO_ERROR; LOCAL_Error_TYPE = YAP_NO_ERROR;
return FALSE; return FALSE;
} }
@ -1070,16 +1117,13 @@ static Int doformat(volatile Term otail, volatile Term oargs,
/* ok, now we should have a command */ /* ok, now we should have a command */
} }
} else { } else {
if (ch == '\n') {
format_synch( sno, sno0, &finfo);
}
f_putc(sno, ch); f_putc(sno, ch);
} }
} }
if (finfo.padders) {
if (osno) {
Yap_CloseStream(sno);
sno = osno;
}
// fill_pads( sno, 0, &finfo); // fill_pads( sno, 0, &finfo);
}
if (IsAtomTerm(tail) || IsStringTerm(tail)) { if (IsAtomTerm(tail) || IsStringTerm(tail)) {
fstr = NULL; fstr = NULL;
} }
@ -1088,14 +1132,13 @@ static Int doformat(volatile Term otail, volatile Term oargs,
if (GLOBAL_Stream[sno].status & InMemory_Stream_f) { if (GLOBAL_Stream[sno].status & InMemory_Stream_f) {
GLOBAL_Stream[sno].u.mem_string.error_handler = old_handler; GLOBAL_Stream[sno].u.mem_string.error_handler = old_handler;
} }
format_clean_up(sno, fstr, targs); format_clean_up(sno, sno0, &finfo, fstr, targs);
return (TRUE); return (TRUE);
} }
/** /**
* @pred with_output_to(+ _Ouput_,: _Goal_) * @pred with_output_to(+ _Ouput_,: _Goal_)
Run _Goal_ as once/1, while characters written to the current Run _Goal_ as once/1, while characters written to the current
output are sent to _Output_. The predicate was introduced by SWI-Prolog. output are sent to _Output_. The predicate was introduced by SWI-Prolog.