|
|
|
//! Displaying match data
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <macros.h>
|
|
|
|
#include <comp.h>
|
|
|
|
#include <display.h>
|
|
|
|
|
|
|
|
#define FLAGSET(f, flag) (( (f) & (flag) ) == (flag))
|
|
|
|
#define DFLAGSET(f, flagname) FLAGSET(f, DISPF_SHOW_ ## flagname)
|
|
|
|
|
|
|
|
// Returns number of bytes written to `dest`. Otherwise same as `strncpy()`.
|
|
|
|
static usize strncpy_n(char*pOUT dest, const char* restrict src, usize n)
|
|
|
|
{
|
|
|
|
usize i;
|
|
|
|
for(i=0;i<n;i++)
|
|
|
|
if(! (*dest++ = *src++)) return i;
|
|
|
|
dest[i] = 0;
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns number of bytes written to (dest+strlen(dest)). Otherwise same as `strncat()`.
|
|
|
|
static inline usize strncat_n(char*pOUT dest, const char* restrict src, usize n)
|
|
|
|
{
|
|
|
|
usize dl = strlen(dest);
|
|
|
|
return strncpy_n(dest+dl, src, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
//TODO: This works, but seems inherantly unsafe. Rewrite to use the above `strn*_n()` functions for better length tracking.
|
|
|
|
static usize _display_get_fmt(dispflags_t flags, bool matched, usize _len, char str[pOUT _len])
|
|
|
|
{
|
|
|
|
register usize len = _len;
|
|
|
|
static const char* fmts[] = { "match: ", "%lu: ", SLICE_FORMAT, " (len %lu)", "failure: ", (const char*)NULL };
|
|
|
|
#define ADDSTR(s) do { debug_assert((s)); strncat(str, (s), len); w = strlen((s)); w = w > len ? len : w; ifU(len<=w) { str[len-1] = 0; return w; } len -= w; str += w; fw+=w; } while(0)
|
|
|
|
usize fw;
|
|
|
|
usize w = strlen(strncpy(str, matched ? fmts[0]
|
|
|
|
: DFLAGSET(flags, FAILURES) ? fmts[4]
|
|
|
|
: "", len)); if(len<=w || w == 0) { str[len-1] = 0; return 0; } len -= w; str += w; fw = w;
|
|
|
|
if(DFLAGSET(flags, NUMBER)) ADDSTR(fmts[1]);
|
|
|
|
if(DFLAGSET(flags, SLICE)) ADDSTR(fmts[2]);
|
|
|
|
if(DFLAGSET(flags, LENGTH)) ADDSTR(fmts[3]);
|
|
|
|
ADDSTR("\n");
|
|
|
|
TRACE("Output string written: %lu, (rlen %lu)", fw, len);
|
|
|
|
return fw;
|
|
|
|
#undef ADDSTR
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _display_normal(FILE* output, dispin_t*pIN input, dispflags_t flags)
|
|
|
|
{
|
|
|
|
bool matched = input->matched;
|
|
|
|
slice_t cslice = input->cslice;
|
|
|
|
const void* base = input->base;
|
|
|
|
usize i = input->index;
|
|
|
|
|
|
|
|
#ifdef _DEBUG_MANCALC_OFFSETS
|
|
|
|
struct {
|
|
|
|
usize start, end;
|
|
|
|
} pos = {
|
|
|
|
.start = AS(cslice.ptr - base, usize),
|
|
|
|
};
|
|
|
|
pos.end = pos.start + cslice.len;
|
|
|
|
#else
|
|
|
|
let pos = slice_sted((slice_t[]){ SLICE(AS(cslice.ptr - base, usize), cslice.len)});
|
|
|
|
#endif
|
|
|
|
INFO("Mapped region slice for %lu, pre-transform (at %p): " SLICE_FORMAT ", len: %lu", i+1, base, SLICE_FORMAT_ARGS(&cslice), cslice.len);
|
|
|
|
|
|
|
|
//Honour `flags`
|
|
|
|
char fmt[200]; //TODO: Find the realistic max for this.
|
|
|
|
fmt[_display_get_fmt(flags, matched, 100, fmt)] = 0;
|
|
|
|
fprintf(output, fmt, i+1, pos.start, pos.end, pos.end-pos.start);
|
|
|
|
}
|
|
|
|
|
|
|
|
void display_result(FILE* output, dispin_t input, dispkind_t how, dispflags_t flags)
|
|
|
|
{
|
|
|
|
flags = flags ?: DISPLAY_FLAGS_DEFAULT;
|
|
|
|
output = output ?: stdout;
|
|
|
|
|
|
|
|
TRACE("Outputting as %d to %p with flags 0x%08lx", (int)how, output, (usize)flags);
|
|
|
|
switch(how)
|
|
|
|
{
|
|
|
|
case DISPK_NORMAL:
|
|
|
|
_display_normal(output, &input, flags);
|
|
|
|
break;
|
|
|
|
case DISPK_CSV:
|
|
|
|
case DISPK_BINARY:
|
|
|
|
case DISPK_INI:
|
|
|
|
TODO("display kind %d is unimplemented", (int)how);
|
|
|
|
default: COLD_EXPR(FATAL("unknown display kind: %d", (int)how));
|
|
|
|
}
|
|
|
|
}
|