some more code for the feed-based reader
This commit is contained in:
parent
51c3145b88
commit
e6d204c766
161
bin/main.c
161
bin/main.c
@ -96,6 +96,9 @@ struct xtn_t
|
||||
/*hcl_oop_t sym_errstr;*/
|
||||
};
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
static hcl_t* g_hcl = HCL_NULL;
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
@ -426,12 +429,91 @@ static void vm_checkbc (hcl_t* hcl, hcl_oob_t bcode)
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
static void gc_hcl (hcl_t* hcl)
|
||||
{
|
||||
xtn_t* xtn = (xtn_t*)hcl_getxtn(hcl);
|
||||
/*if (xtn->sym_errstr) xtn->sym_errstr = hcl_moveoop(hcl, xtn->sym_errstr);*/
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
static hcl_oop_t execute_in_interactive_mode (hcl_t* hcl)
|
||||
{
|
||||
hcl_oop_t retv;
|
||||
|
||||
hcl_decode (hcl, 0, hcl_getbclen(hcl));
|
||||
HCL_LOG0 (hcl, HCL_LOG_MNEMONIC, "------------------------------------------\n");
|
||||
g_hcl = hcl;
|
||||
/*setup_tick ();*/
|
||||
|
||||
retv = hcl_execute(hcl);
|
||||
|
||||
/* flush pending output data in the interactive mode(e.g. printf without a newline) */
|
||||
hcl_flushio (hcl);
|
||||
|
||||
if (!retv)
|
||||
{
|
||||
hcl_logbfmt (hcl, HCL_LOG_STDERR, "ERROR: cannot execute - [%d] %js\n", hcl_geterrnum(hcl), hcl_geterrmsg(hcl));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* print the result in the interactive mode regardless 'verbose' */
|
||||
hcl_logbfmt (hcl, HCL_LOG_STDOUT, "%O\n", retv); /* TODO: show this go to the output handler?? */
|
||||
/*
|
||||
* print the value of ERRSTR.
|
||||
hcl_oop_cons_t cons = hcl_getatsysdic(hcl, xtn->sym_errstr);
|
||||
if (cons)
|
||||
{
|
||||
HCL_ASSERT (hcl, HCL_IS_CONS(hcl, cons));
|
||||
HCL_ASSERT (hcl, HCL_CONS_CAR(cons) == xtn->sym_errstr);
|
||||
hcl_print (hcl, HCL_CONS_CDR(cons));
|
||||
}
|
||||
*/
|
||||
}
|
||||
/*cancel_tick();*/
|
||||
g_hcl = HCL_NULL;
|
||||
|
||||
return retv;
|
||||
}
|
||||
|
||||
|
||||
static hcl_oop_t execute_in_batch_mode (hcl_t* hcl, int verbose)
|
||||
{
|
||||
hcl_oop_t retv;
|
||||
|
||||
hcl_decode (hcl, 0, hcl_getbclen(hcl));
|
||||
HCL_LOG2 (hcl, HCL_LOG_MNEMONIC, "BYTECODES bclen = > %zu lflen => %zu\n", hcl_getbclen(hcl), hcl_getlflen(hcl));
|
||||
g_hcl = hcl;
|
||||
/*setup_tick ();*/
|
||||
|
||||
retv = hcl_execute(hcl);
|
||||
hcl_flushio (hcl);
|
||||
|
||||
if (!retv)
|
||||
{
|
||||
hcl_logbfmt (hcl, HCL_LOG_STDERR, "ERROR: cannot execute - [%d] %js\n", hcl_geterrnum(hcl), hcl_geterrmsg(hcl));
|
||||
}
|
||||
else if (verbose)
|
||||
{
|
||||
hcl_logbfmt (hcl, HCL_LOG_STDERR, "EXECUTION OK - EXITED WITH %O\n", retv);
|
||||
}
|
||||
|
||||
/*cancel_tick();*/
|
||||
g_hcl = HCL_NULL;
|
||||
/*hcl_dumpsymtab (hcl);*/
|
||||
|
||||
return retv;
|
||||
}
|
||||
|
||||
static int on_fed_cnode_in_interactive_mode (hcl_t* hcl, hcl_cnode_t* obj)
|
||||
{
|
||||
if (hcl_compile(hcl, obj, HCL_COMPILE_CLEAR_CODE | HCL_COMPILE_CLEAR_FNBLK) <= -1) return -1;
|
||||
execute_in_interactive_mode (hcl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
static int handle_logopt (hcl_t* hcl, const hcl_bch_t* logstr)
|
||||
@ -565,12 +647,6 @@ static int handle_dbgopt (hcl_t* hcl, const hcl_bch_t* str)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
/* ========================================================================= */
|
||||
|
||||
static hcl_t* g_hcl = HCL_NULL;
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
@ -704,7 +780,7 @@ count++;
|
||||
print_synerr (hcl);
|
||||
if (xtn->reader_istty && hcl_getsynerrnum(hcl) != HCL_SYNERR_EOF)
|
||||
{
|
||||
/* TODO: drain remaining data in the reader including the actual inputstream and buffered data in hcl */
|
||||
/* TODO: drain remaining data in the reader including the actual input stream and buffered data in hcl */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -736,66 +812,11 @@ count++;
|
||||
else if (xtn->reader_istty)
|
||||
{
|
||||
/* interactive mode */
|
||||
hcl_oop_t retv;
|
||||
|
||||
hcl_decode (hcl, 0, hcl_getbclen(hcl));
|
||||
HCL_LOG0 (hcl, HCL_LOG_MNEMONIC, "------------------------------------------\n");
|
||||
g_hcl = hcl;
|
||||
/*setup_tick ();*/
|
||||
|
||||
retv = hcl_execute(hcl);
|
||||
|
||||
/* flush pending output data in the interactive mode(e.g. printf without a newline) */
|
||||
hcl_flushio (hcl);
|
||||
|
||||
if (!retv)
|
||||
{
|
||||
hcl_logbfmt (hcl, HCL_LOG_STDERR, "ERROR: cannot execute - [%d] %js\n", hcl_geterrnum(hcl), hcl_geterrmsg(hcl));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* print the result in the interactive mode regardless 'verbose' */
|
||||
hcl_logbfmt (hcl, HCL_LOG_STDOUT, "%O\n", retv); /* TODO: show this go to the output handler?? */
|
||||
|
||||
/*
|
||||
* print the value of ERRSTR.
|
||||
hcl_oop_cons_t cons = hcl_getatsysdic(hcl, xtn->sym_errstr);
|
||||
if (cons)
|
||||
{
|
||||
HCL_ASSERT (hcl, HCL_IS_CONS(hcl, cons));
|
||||
HCL_ASSERT (hcl, HCL_CONS_CAR(cons) == xtn->sym_errstr);
|
||||
hcl_print (hcl, HCL_CONS_CDR(cons));
|
||||
}
|
||||
*/
|
||||
}
|
||||
/*cancel_tick();*/
|
||||
g_hcl = HCL_NULL;
|
||||
execute_in_interactive_mode (hcl);
|
||||
}
|
||||
}
|
||||
|
||||
if (!xtn->reader_istty && hcl_getbclen(hcl) > 0)
|
||||
{
|
||||
hcl_oop_t retv;
|
||||
|
||||
hcl_decode (hcl, 0, hcl_getbclen(hcl));
|
||||
HCL_LOG2 (hcl, HCL_LOG_MNEMONIC, "BYTECODES bclen = > %zu lflen => %zu\n", hcl_getbclen(hcl), hcl_getlflen(hcl));
|
||||
g_hcl = hcl;
|
||||
/*setup_tick ();*/
|
||||
|
||||
retv = hcl_execute(hcl);
|
||||
if (!retv)
|
||||
{
|
||||
hcl_logbfmt (hcl, HCL_LOG_STDERR, "ERROR: cannot execute - [%d] %js\n", hcl_geterrnum(hcl), hcl_geterrmsg(hcl));
|
||||
}
|
||||
else if (verbose)
|
||||
{
|
||||
hcl_logbfmt (hcl, HCL_LOG_STDERR, "EXECUTION OK - EXITED WITH %O\n", retv);
|
||||
}
|
||||
|
||||
/*cancel_tick();*/
|
||||
g_hcl = HCL_NULL;
|
||||
/*hcl_dumpsymtab (hcl);*/
|
||||
}
|
||||
if (!xtn->reader_istty && hcl_getbclen(hcl) > 0) execute_in_batch_mode (hcl, verbose);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -822,7 +843,10 @@ static int feed_loop (hcl_t* hcl, xtn_t* xtn, int cflags, int verbose)
|
||||
}
|
||||
|
||||
/*(setvbuf (fp, NULL, _IONBF, 0);*/
|
||||
|
||||
if (xtn->reader_istty) hcl_beginfeed (hcl, on_fed_cnode_in_interactive_mode); /* override the default cnode handler */
|
||||
|
||||
/* TODO: use the io handler attached .. */
|
||||
while (1)
|
||||
{
|
||||
hcl_ooi_t n;
|
||||
@ -854,7 +878,6 @@ static int feed_loop (hcl_t* hcl, xtn_t* xtn, int cflags, int verbose)
|
||||
/* 'len' must remain 0 in this case */
|
||||
#endif
|
||||
|
||||
/* the compiler must be invoked whenever feed() sees a complete object */
|
||||
if (x <= -1) goto feed_error;
|
||||
}
|
||||
|
||||
@ -884,11 +907,7 @@ static int feed_loop (hcl_t* hcl, xtn_t* xtn, int cflags, int verbose)
|
||||
|
||||
fclose (fp);
|
||||
|
||||
/* TODO: execute code? */
|
||||
if (hcl_getbclen(hcl) > 0)
|
||||
{
|
||||
/* TODO: execute code... */
|
||||
}
|
||||
if (!xtn->reader_istty && hcl_getbclen(hcl) > 0) execute_in_batch_mode (hcl, verbose);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -1025,7 +1044,7 @@ int main (int argc, char* argv[])
|
||||
|
||||
memset (&hclcb, 0, HCL_SIZEOF(hclcb));
|
||||
hclcb.gc = gc_hcl;
|
||||
hclcb.vm_startup = vm_startup;
|
||||
hclcb.vm_startup = vm_startup;
|
||||
hclcb.vm_cleanup = vm_cleanup;
|
||||
/*hclcb.vm_checkbc = vm_checkbc;*/
|
||||
hcl_regcb (hcl, &hclcb);
|
||||
|
@ -702,17 +702,8 @@ struct hcl_compiler_t
|
||||
} u;
|
||||
} lx;
|
||||
|
||||
struct
|
||||
{
|
||||
int code;
|
||||
/*union
|
||||
{
|
||||
|
||||
} u;*/
|
||||
} st[100];
|
||||
hcl_ooi_t top;
|
||||
|
||||
struct hcl_frd_t rd;
|
||||
hcl_on_cnode_t on_cnode;
|
||||
} feed;
|
||||
|
||||
/* == COMPILER STACK == */
|
||||
|
24
lib/hcl.h
24
lib/hcl.h
@ -1459,6 +1459,8 @@ struct hcl_dbgi_t
|
||||
typedef struct hcl_compiler_t hcl_compiler_t;
|
||||
typedef struct hcl_cnode_t hcl_cnode_t;
|
||||
|
||||
typedef int (*hcl_on_cnode_t) (hcl_t* hcl, hcl_cnode_t* obj);
|
||||
|
||||
enum hcl_compile_flag_t
|
||||
{
|
||||
/* clear byte codes at the beginnign of hcl_compile() */
|
||||
@ -2082,7 +2084,6 @@ HCL_EXPORT int hcl_setoption (
|
||||
const void* value
|
||||
);
|
||||
|
||||
|
||||
HCL_EXPORT hcl_cb_t* hcl_regcb (
|
||||
hcl_t* hcl,
|
||||
hcl_cb_t* tmpl
|
||||
@ -2151,9 +2152,9 @@ HCL_EXPORT void hcl_abort (
|
||||
|
||||
|
||||
HCL_EXPORT int hcl_attachio (
|
||||
hcl_t* hcl,
|
||||
hcl_ioimpl_t reader,
|
||||
hcl_ioimpl_t printer
|
||||
hcl_t* hcl,
|
||||
hcl_ioimpl_t reader,
|
||||
hcl_ioimpl_t printer
|
||||
);
|
||||
|
||||
HCL_EXPORT void hcl_detachio (
|
||||
@ -2168,11 +2169,6 @@ HCL_EXPORT hcl_cnode_t* hcl_read (
|
||||
hcl_t* hcl
|
||||
);
|
||||
|
||||
HCL_EXPORT void hcl_freecnode (
|
||||
hcl_t* hcl,
|
||||
hcl_cnode_t* cnode
|
||||
);
|
||||
|
||||
HCL_EXPORT int hcl_print (
|
||||
hcl_t* hcl,
|
||||
hcl_oop_t obj
|
||||
@ -2194,6 +2190,16 @@ HCL_EXPORT hcl_ooi_t hcl_proutufmt (
|
||||
|
||||
#if defined(HCL_INCLUDE_COMPILER)
|
||||
|
||||
HCL_EXPORT void hcl_freecnode (
|
||||
hcl_t* hcl,
|
||||
hcl_cnode_t* cnode
|
||||
);
|
||||
|
||||
HCL_EXPORT void hcl_beginfeed (
|
||||
hcl_t* hcl,
|
||||
hcl_on_cnode_t on_cnode
|
||||
);
|
||||
|
||||
HCL_EXPORT int hcl_feed (
|
||||
hcl_t* hcl,
|
||||
const hcl_ooch_t* data,
|
||||
|
101
lib/read.c
101
lib/read.c
@ -2247,6 +2247,14 @@ hcl_cnodetoobj (hcl_t* hcl, hcl_cnode_t* x)
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static int on_fed_cnode (hcl_t* hcl, hcl_cnode_t* obj)
|
||||
{
|
||||
/* the default handler for a cnode composed via feeding - just compile the object node. */
|
||||
return hcl_compile(hcl, obj, 0);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static void init_feed (hcl_t* hcl)
|
||||
{
|
||||
HCL_MEMSET (&hcl->c->feed, 0, HCL_SIZEOF(hcl->c->feed));
|
||||
@ -2256,31 +2264,11 @@ static void init_feed (hcl_t* hcl)
|
||||
hcl->c->feed.lx.loc.colm = 1;
|
||||
hcl->c->feed.lx.loc.file = HCL_NULL;
|
||||
|
||||
hcl->c->feed.top = -1;
|
||||
hcl->c->feed.on_cnode = on_fed_cnode;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static int fst_push (hcl_t* hcl, int code)
|
||||
{
|
||||
if (hcl->c->feed.top >= HCL_COUNTOF(hcl->c->feed.st) - 1) /* TODO: use a dynamically allocated stack? */
|
||||
{
|
||||
hcl_seterrbfmt (hcl, HCL_EBUFFULL, "feed stack full");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hcl->c->feed.top++;
|
||||
HCL_MEMSET (&hcl->c->feed.st[hcl->c->feed.top], 0, HCL_SIZEOF(hcl->c->feed.st[hcl->c->feed.top]));
|
||||
hcl->c->feed.st[hcl->c->feed.top].code = code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fst_pop (hcl_t* hcl)
|
||||
{
|
||||
HCL_ASSERT (hcl, hcl->c->feed.top >= 0);
|
||||
hcl->c->feed.top--;
|
||||
}
|
||||
|
||||
static int feed_begin_include (hcl_t* hcl)
|
||||
{
|
||||
hcl_ioinarg_t* arg;
|
||||
@ -2327,11 +2315,9 @@ static int feed_end_include (hcl_t* hcl)
|
||||
|
||||
x = hcl->c->reader(hcl, HCL_IO_CLOSE, hcl->c->curinp);
|
||||
|
||||
/* if closing has failed, still destroy the
|
||||
* sio structure first as normal and return
|
||||
* the failure below. this way, the caller
|
||||
* does not call HCL_IO_CLOSE on
|
||||
* hcl->c->curinp again. */
|
||||
/* if closing has failed, still destroy the sio structure
|
||||
* first as normal and return the failure below. this way,
|
||||
* the caller doesn't call HCL_IO_CLOSE on hcl->c->curinp again. */
|
||||
|
||||
cur = hcl->c->curinp;
|
||||
hcl->c->curinp = hcl->c->curinp->includer;
|
||||
@ -2683,7 +2669,8 @@ static int feed_process_token (hcl_t* hcl)
|
||||
/* check if we are at the top frd->level */
|
||||
if (frd->level <= 0)
|
||||
{
|
||||
// TOOD: callback with frd->obj in case it's complete
|
||||
int n;
|
||||
hcl_cb_t* cb;
|
||||
|
||||
/* upon exit, we must be at the top level */
|
||||
HCL_ASSERT (hcl, frd->level == 0);
|
||||
@ -2692,14 +2679,10 @@ static int feed_process_token (hcl_t* hcl)
|
||||
HCL_ASSERT (hcl, hcl->c->r.st == HCL_NULL);
|
||||
HCL_ASSERT (hcl, frd->obj != HCL_NULL);
|
||||
|
||||
/* TODO: error handling, etc */
|
||||
hcl_compile(hcl, frd->obj, HCL_COMPILE_CLEAR_CODE | HCL_COMPILE_CLEAR_FNBLK); /* flags 0 if non-interactive */
|
||||
hcl_freecnode (hcl, frd->obj); /* not needed any more */
|
||||
frd->obj = HCL_NULL;
|
||||
hcl_decode (hcl, 0, hcl_getbclen(hcl));
|
||||
hcl_execute (hcl);
|
||||
hcl_flushio (hcl);
|
||||
|
||||
n = hcl->c->feed.on_cnode(hcl, frd->obj);
|
||||
hcl_freecnode (hcl, frd->obj); /* not needed any more */
|
||||
frd->obj = HCL_NULL;
|
||||
if (n <= -1) goto oops;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2715,7 +2698,6 @@ hcl_flushio (hcl);
|
||||
clear_comma_colon_flag (hcl);
|
||||
}
|
||||
|
||||
|
||||
ok:
|
||||
return 0;
|
||||
|
||||
@ -2949,16 +2931,10 @@ static int flx_start (hcl_t* hcl, hcl_ooci_t c)
|
||||
switch (c)
|
||||
{
|
||||
case HCL_OOCI_EOF:
|
||||
{
|
||||
int n;
|
||||
#if 0
|
||||
n = end_include(hcl);
|
||||
if (n <= -1) return -1;
|
||||
if (n >= 1) goto retry;
|
||||
#endif
|
||||
/* only EOF of the top-level stream is supposed to be fed in.
|
||||
* the internal logic discard EOFs of included streams */
|
||||
FEED_WRAP_UP_WITH_CHARS (hcl, vocas[VOCA_EOF].str, vocas[VOCA_EOF].len, HCL_IOTOK_EOF);
|
||||
goto consumed;
|
||||
}
|
||||
|
||||
case ';':
|
||||
FEED_CONTINUE_WITH_CHAR (hcl, c, HCL_FLX_COMMENT);
|
||||
@ -3706,7 +3682,6 @@ static int feed_char (hcl_t* hcl, hcl_ooci_t c)
|
||||
static int feed_from_included (hcl_t* hcl)
|
||||
{
|
||||
int x;
|
||||
hcl_ooch_t lc;
|
||||
|
||||
HCL_ASSERT (hcl, hcl->c->curinp != HCL_NULL && hcl->c->curinp != &hcl->c->inarg);
|
||||
|
||||
@ -3721,7 +3696,7 @@ static int feed_from_included (hcl_t* hcl)
|
||||
|
||||
if (hcl->c->curinp->xlen <= 0)
|
||||
{
|
||||
/* got EOF */
|
||||
/* got EOF from an included stream */
|
||||
#if 0
|
||||
x = feed_char(hcl, HCL_OOCI_EOF); /* TODO: or call feed_end_include? */
|
||||
if (x <= -1) return -1;
|
||||
@ -3735,17 +3710,18 @@ static int feed_from_included (hcl_t* hcl)
|
||||
hcl->c->curinp->b.len = hcl->c->curinp->xlen;
|
||||
}
|
||||
|
||||
lc = hcl->c->curinp->buf[hcl->c->curinp->b.pos];
|
||||
x = feed_char(hcl, lc);
|
||||
x = feed_char(hcl, hcl->c->curinp->buf[hcl->c->curinp->b.pos]);
|
||||
if (x <= -1) return -1;
|
||||
hcl->c->curinp->b.pos += x;
|
||||
|
||||
if (hcl->c->feed.rd.do_include_file)
|
||||
{
|
||||
/* perform delayed file inclusion. the token buffer must remain unchanged
|
||||
* since do_include_file has been set to true in feed_process_token(). */
|
||||
/* feed_process_token(), called for the "filename" token for the #include
|
||||
* directive, sets hcl->c->feed.rd.do_include_file to 1 instead of attepmting
|
||||
* to include the file. the file inclusion is attempted here after the return
|
||||
* value of feed_char() is used to advance the hcl->c->curinp->b.pos pointer. */
|
||||
hcl->c->feed.rd.do_include_file = 0; /* clear this regardless of inclusion result */
|
||||
if (feed_begin_include(hcl) <= -1) return -1;
|
||||
hcl->c->feed.rd.do_include_file = 0;
|
||||
}
|
||||
}
|
||||
while (hcl->c->curinp != &hcl->c->inarg);
|
||||
@ -3753,6 +3729,11 @@ static int feed_from_included (hcl_t* hcl)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hcl_beginfeed (hcl_t* hcl, hcl_on_cnode_t on_cnode)
|
||||
{
|
||||
hcl->c->feed.on_cnode = on_cnode;
|
||||
}
|
||||
|
||||
int hcl_feed (hcl_t* hcl, const hcl_ooch_t* data, hcl_oow_t len)
|
||||
{
|
||||
/* TODO: need to return the number of processed characters?
|
||||
@ -3761,6 +3742,7 @@ int hcl_feed (hcl_t* hcl, const hcl_ooch_t* data, hcl_oow_t len)
|
||||
hcl_oow_t i;
|
||||
int x;
|
||||
|
||||
|
||||
if (data)
|
||||
{
|
||||
for (i = 0; i < len; )
|
||||
@ -3800,10 +3782,23 @@ int hcl_feed (hcl_t* hcl, const hcl_ooch_t* data, hcl_oow_t len)
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 1;)
|
||||
for (i = 0; i < 1;) /* weird loop in case feed_char() returns 0 */
|
||||
{
|
||||
x = feed_char(hcl, HCL_OOCI_EOF);
|
||||
if (x <= -1) return -1;
|
||||
if (x <= -1)
|
||||
{
|
||||
if (hcl->c->feed.rd.level <= 0 && hcl_geterrnum(hcl) == HCL_ESYNERR && hcl_getsynerrnum(hcl) == HCL_SYNERR_EOF)
|
||||
{
|
||||
/* convert this EOF error to success as the caller knows EOF in the feed mode.
|
||||
* the caller can safely stop feeding after gettting success from hcl_feed(hcl, HCL_NULL, 0);
|
||||
* in the feed mode, this function doesn't set HCL_EFINIS. */
|
||||
x = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
i += x;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user