ipc, srv, gtk: the client's text goes over and a take-back comes back
The engine can reach a Hanja reading back into the text the client already holds, but only if the frontend hands that text over and can take some of it away again. GTK 3 has both: retrieve-surrounding brings the text around the cursor and delete-surrounding removes runes before it, and a widget that answers neither leaves the text empty, so nothing is ever reached into or taken from it. The wire grows a control frame for the text, sent like the caret only when it changes, and one byte in every response for the runes to take back. That byte moves the length fields along, so the version goes to 2: an old daemon and a new module, either way round, fail the handshake and the module falls through to GtkIMContextSimple rather than misread a frame. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1
fn.h
1
fn.h
@@ -1,6 +1,7 @@
|
|||||||
void die(char*, ...);
|
void die(char*, ...);
|
||||||
|
|
||||||
int sinit(Str*, char*, int);
|
int sinit(Str*, char*, int);
|
||||||
|
void stail(Str*, char*, int);
|
||||||
void sclear(Str*);
|
void sclear(Str*);
|
||||||
void sputr(Str*, Rune);
|
void sputr(Str*, Rune);
|
||||||
void spopr(Str*);
|
void spopr(Str*);
|
||||||
|
|||||||
63
gtk/main.c
63
gtk/main.c
@@ -24,6 +24,9 @@ struct Im
|
|||||||
int cursorvalid;
|
int cursorvalid;
|
||||||
int caretsent;
|
int caretsent;
|
||||||
unsigned char sent[Ipccaretsz];
|
unsigned char sent[Ipccaretsz];
|
||||||
|
char surround[Ipcfieldmax];
|
||||||
|
int nsurround;
|
||||||
|
int surroundsent;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct ImClass ImClass;
|
typedef struct ImClass ImClass;
|
||||||
@@ -65,6 +68,7 @@ srvdrop(Im *im, int notify)
|
|||||||
im->fd = -1;
|
im->fd = -1;
|
||||||
im->ext = 0;
|
im->ext = 0;
|
||||||
im->caretsent = 0;
|
im->caretsent = 0;
|
||||||
|
im->surroundsent = 0;
|
||||||
if(notify)
|
if(notify)
|
||||||
setpreedit(im, "", 0);
|
setpreedit(im, "", 0);
|
||||||
else{
|
else{
|
||||||
@@ -157,6 +161,58 @@ sendcaret(Im *im)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text just before the cursor, as much of it as a reading can use,
|
||||||
|
* cut on a rune boundary. A widget that keeps none leaves it empty, and
|
||||||
|
* then the daemon never asks for any of it back.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
readsurround(Im *im, GtkIMContext *ctx)
|
||||||
|
{
|
||||||
|
char *text, *p;
|
||||||
|
gint cursor;
|
||||||
|
int start;
|
||||||
|
|
||||||
|
im->nsurround = 0;
|
||||||
|
if(!gtk_im_context_get_surrounding(ctx, &text, &cursor))
|
||||||
|
return;
|
||||||
|
if(cursor < 0 || cursor > (gint)strlen(text)){
|
||||||
|
g_free(text);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
start = cursor > Ipcfieldmax ? cursor - Ipcfieldmax : 0;
|
||||||
|
for(p = text + start; p < text + cursor && (*p & 0xc0) == 0x80; p++)
|
||||||
|
;
|
||||||
|
im->nsurround = text + cursor - p;
|
||||||
|
memcpy(im->surround, p, im->nsurround);
|
||||||
|
g_free(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sent only when it changes, as the caret is. */
|
||||||
|
static int
|
||||||
|
sendsurround(Im *im, GtkIMContext *ctx)
|
||||||
|
{
|
||||||
|
unsigned char hdr[Ipcreqsz];
|
||||||
|
char was[Ipcfieldmax];
|
||||||
|
int nwas;
|
||||||
|
|
||||||
|
if(im->fd < 0 || !im->ext)
|
||||||
|
return 0;
|
||||||
|
nwas = im->nsurround;
|
||||||
|
memcpy(was, im->surround, nwas);
|
||||||
|
readsurround(im, ctx);
|
||||||
|
if(im->surroundsent && nwas == im->nsurround &&
|
||||||
|
memcmp(was, im->surround, nwas) == 0)
|
||||||
|
return 0;
|
||||||
|
ipcpacksurround(hdr, im->nsurround);
|
||||||
|
if(ipcsend(im->fd, hdr, sizeof hdr) < 0 ||
|
||||||
|
(im->nsurround > 0 &&
|
||||||
|
ipcsend(im->fd, im->surround, im->nsurround) < 0))
|
||||||
|
return -1;
|
||||||
|
im->surroundsent = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
srvconnect(Im *im)
|
srvconnect(Im *im)
|
||||||
{
|
{
|
||||||
@@ -286,7 +342,7 @@ kpress(GtkIMContext *ctx, GdkEventKey *ev)
|
|||||||
if(srvconnect(im) < 0)
|
if(srvconnect(im) < 0)
|
||||||
return simplefilter(ctx, ev, 0);
|
return simplefilter(ctx, ev, 0);
|
||||||
/* A retained GDK window may have moved since the last cursor report. */
|
/* A retained GDK window may have moved since the last cursor report. */
|
||||||
if(sendcaret(im) < 0){
|
if(sendcaret(im) < 0 || sendsurround(im, ctx) < 0){
|
||||||
srvclose(im);
|
srvclose(im);
|
||||||
return simplefilter(ctx, ev, 0);
|
return simplefilter(ctx, ev, 0);
|
||||||
}
|
}
|
||||||
@@ -298,6 +354,11 @@ kpress(GtkIMContext *ctx, GdkEventKey *ev)
|
|||||||
}
|
}
|
||||||
if(im->usepreedit && commit[0] != '\0' && im->prelen > 0)
|
if(im->usepreedit && commit[0] != '\0' && im->prelen > 0)
|
||||||
setpreedit(im, "", 0);
|
setpreedit(im, "", 0);
|
||||||
|
/* The reading reached into the widget's own text: give it back. */
|
||||||
|
if(resp.del > 0){
|
||||||
|
gtk_im_context_delete_surrounding(ctx, -resp.del, resp.del);
|
||||||
|
im->surroundsent = 0;
|
||||||
|
}
|
||||||
if(commit[0] != '\0')
|
if(commit[0] != '\0')
|
||||||
g_signal_emit_by_name(ctx, "commit", commit);
|
g_signal_emit_by_name(ctx, "commit", commit);
|
||||||
if(im->usepreedit)
|
if(im->usepreedit)
|
||||||
|
|||||||
38
ipc.c
38
ipc.c
@@ -252,6 +252,22 @@ ipcpackcaret(unsigned char req[Ipccaretsz], int valid, int32_t x,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ipcpacksurround(unsigned char req[Ipcreqsz], size_t n)
|
||||||
|
{
|
||||||
|
memset(req, 0, Ipcreqsz);
|
||||||
|
req[0] = Ipcext;
|
||||||
|
req[1] = Ipcversion;
|
||||||
|
req[2] = Ipcopsurround;
|
||||||
|
putlen(req + 4, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
ipcsurroundlen(const unsigned char req[Ipcreqsz])
|
||||||
|
{
|
||||||
|
return getlen(req + 4);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ipcunpackreq(const unsigned char req[Ipcreqsz], int *want, uint32_t *mod,
|
ipcunpackreq(const unsigned char req[Ipcreqsz], int *want, uint32_t *mod,
|
||||||
uint32_t *key)
|
uint32_t *key)
|
||||||
@@ -281,6 +297,11 @@ ipcreqtype(const unsigned char req[Ipcreqsz])
|
|||||||
if(req[0] != Ipcext || req[3] > 1)
|
if(req[0] != Ipcext || req[3] > 1)
|
||||||
return Ipcunknown;
|
return Ipcunknown;
|
||||||
return Ipccaret;
|
return Ipccaret;
|
||||||
|
case Ipcopsurround:
|
||||||
|
if(req[0] != Ipcext || req[3] != 0 ||
|
||||||
|
getlen(req + 4) > Ipcfieldmax)
|
||||||
|
return Ipcunknown;
|
||||||
|
return Ipcsurround;
|
||||||
}
|
}
|
||||||
return Ipcunknown;
|
return Ipcunknown;
|
||||||
}
|
}
|
||||||
@@ -305,19 +326,21 @@ ipcreqreset(const unsigned char req[Ipcreqsz])
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ipcpackresp(unsigned char *dst, size_t cap, int eaten,
|
ipcpackresp(unsigned char *dst, size_t cap, int eaten, int del,
|
||||||
const char *commit, size_t ncommit, const char *preedit, size_t npreedit,
|
const char *commit, size_t ncommit, const char *preedit, size_t npreedit,
|
||||||
int want)
|
int want)
|
||||||
{
|
{
|
||||||
size_t n;
|
size_t n;
|
||||||
|
|
||||||
if(ncommit > Ipcfieldmax || npreedit > Ipcfieldmax)
|
if(ncommit > Ipcfieldmax || npreedit > Ipcfieldmax ||
|
||||||
|
del < 0 || del > 0xff)
|
||||||
return -1;
|
return -1;
|
||||||
n = Ipcresphdrsz + ncommit + (want ? Ipclensz + npreedit : 0);
|
n = Ipcresphdrsz + ncommit + (want ? Ipclensz + npreedit : 0);
|
||||||
if(cap < n)
|
if(cap < n)
|
||||||
return -1;
|
return -1;
|
||||||
dst[0] = eaten != 0;
|
dst[0] = eaten != 0;
|
||||||
putlen(dst + 1, ncommit);
|
dst[1] = del;
|
||||||
|
putlen(dst + 2, ncommit);
|
||||||
memcpy(dst + Ipcresphdrsz, commit, ncommit);
|
memcpy(dst + Ipcresphdrsz, commit, ncommit);
|
||||||
if(want){
|
if(want){
|
||||||
putlen(dst + Ipcresphdrsz + ncommit, npreedit);
|
putlen(dst + Ipcresphdrsz + ncommit, npreedit);
|
||||||
@@ -398,7 +421,7 @@ readfield(int fd, char *dst, int64_t until)
|
|||||||
int
|
int
|
||||||
ipcreadresp(int fd, int want, char *commit, char *preedit, Ipcresp *resp)
|
ipcreadresp(int fd, int want, char *commit, char *preedit, Ipcresp *resp)
|
||||||
{
|
{
|
||||||
unsigned char eaten;
|
unsigned char head[2];
|
||||||
int64_t until;
|
int64_t until;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
@@ -406,13 +429,14 @@ ipcreadresp(int fd, int want, char *commit, char *preedit, Ipcresp *resp)
|
|||||||
preedit[0] = '\0';
|
preedit[0] = '\0';
|
||||||
memset(resp, 0, sizeof *resp);
|
memset(resp, 0, sizeof *resp);
|
||||||
until = deadline();
|
until = deadline();
|
||||||
if(readwait(fd, &eaten, 1, until) < 0)
|
if(readwait(fd, head, sizeof head, until) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if(eaten > 1){
|
if(head[0] > 1){
|
||||||
errno = EPROTO;
|
errno = EPROTO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
resp->eaten = eaten;
|
resp->eaten = head[0];
|
||||||
|
resp->del = head[1];
|
||||||
n = readfield(fd, commit, until);
|
n = readfield(fd, commit, until);
|
||||||
if(n < 0)
|
if(n < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
21
ipc.h
21
ipc.h
@@ -8,9 +8,11 @@
|
|||||||
* The server identifies the connection as the engine owner; that identity is
|
* The server identifies the connection as the engine owner; that identity is
|
||||||
* not sent on the wire.
|
* not sent on the wire.
|
||||||
* Only Mmask modifier bits are retained.
|
* Only Mmask modifier bits are retained.
|
||||||
* Response: [eaten, commit-length-low, commit-length-high, commit...],
|
* Response: [eaten, take-back, commit-length-low, commit-length-high,
|
||||||
* followed, when requested, by
|
* commit...], followed, when requested, by
|
||||||
* [preedit-length-low, preedit-length-high, preedit...].
|
* [preedit-length-low, preedit-length-high, preedit...].
|
||||||
|
* Take-back is the count of runes of the client's own text, just before the
|
||||||
|
* cursor, to remove before inserting the commit.
|
||||||
* Lengths are little-endian byte counts; fields are at most Ipcfieldmax bytes,
|
* Lengths are little-endian byte counts; fields are at most Ipcfieldmax bytes,
|
||||||
* so callers read them into char[Ipcfieldmax+1].
|
* so callers read them into char[Ipcfieldmax+1].
|
||||||
*
|
*
|
||||||
@@ -19,6 +21,10 @@
|
|||||||
* frames are understood.
|
* frames are understood.
|
||||||
* Caret control is sixteen bytes: [0x80, version, 1, valid, x, y, h],
|
* Caret control is sixteen bytes: [0x80, version, 1, valid, x, y, h],
|
||||||
* with the signed coordinates and height encoded as little-endian 32-bit words.
|
* with the signed coordinates and height encoded as little-endian 32-bit words.
|
||||||
|
* Surrounding-text control is six bytes, [0x80, version, 2, 0, length-low,
|
||||||
|
* length-high], and then that many bytes of the text just before the cursor.
|
||||||
|
* It changes what rides along with the requests that follow and is not
|
||||||
|
* answered.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@@ -26,9 +32,10 @@ enum
|
|||||||
Ipcreqwant = 1<<0,
|
Ipcreqwant = 1<<0,
|
||||||
Ipcreqreset = 1<<1,
|
Ipcreqreset = 1<<1,
|
||||||
Ipcext = 1<<7,
|
Ipcext = 1<<7,
|
||||||
Ipcversion = 1,
|
Ipcversion = 2,
|
||||||
Ipcopcap = 0,
|
Ipcopcap = 0,
|
||||||
Ipcopcaret = 1,
|
Ipcopcaret = 1,
|
||||||
|
Ipcopsurround = 2,
|
||||||
|
|
||||||
Kspec = 0x110000,
|
Kspec = 0x110000,
|
||||||
Kback = Kspec|0x08,
|
Kback = Kspec|0x08,
|
||||||
@@ -57,7 +64,7 @@ enum
|
|||||||
Ipcreqsz = 6,
|
Ipcreqsz = 6,
|
||||||
Ipccaretsz = 16,
|
Ipccaretsz = 16,
|
||||||
Ipclensz = 2,
|
Ipclensz = 2,
|
||||||
Ipcresphdrsz = 1 + Ipclensz,
|
Ipcresphdrsz = 2 + Ipclensz,
|
||||||
Ipcfieldmax = 256,
|
Ipcfieldmax = 256,
|
||||||
Ipcmaxresp = Ipcresphdrsz + Ipcfieldmax + Ipclensz + Ipcfieldmax,
|
Ipcmaxresp = Ipcresphdrsz + Ipcfieldmax + Ipclensz + Ipcfieldmax,
|
||||||
Ipcwaitms = 250,
|
Ipcwaitms = 250,
|
||||||
@@ -69,12 +76,14 @@ enum
|
|||||||
Ipckey,
|
Ipckey,
|
||||||
Ipccap,
|
Ipccap,
|
||||||
Ipccaret,
|
Ipccaret,
|
||||||
|
Ipcsurround,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Ipcresp Ipcresp;
|
typedef struct Ipcresp Ipcresp;
|
||||||
struct Ipcresp
|
struct Ipcresp
|
||||||
{
|
{
|
||||||
int eaten;
|
int eaten;
|
||||||
|
int del; /* runes of the client's own text to take back first */
|
||||||
/* Bytes copied to each caller buffer, excluding its trailing NUL. */
|
/* Bytes copied to each caller buffer, excluding its trailing NUL. */
|
||||||
size_t commitlen;
|
size_t commitlen;
|
||||||
size_t preeditlen;
|
size_t preeditlen;
|
||||||
@@ -86,11 +95,13 @@ void ipcpackreq(unsigned char[Ipcreqsz], int, uint32_t, uint32_t);
|
|||||||
void ipcpackreset(unsigned char[Ipcreqsz], int);
|
void ipcpackreset(unsigned char[Ipcreqsz], int);
|
||||||
void ipcpackcap(unsigned char[Ipcreqsz], int);
|
void ipcpackcap(unsigned char[Ipcreqsz], int);
|
||||||
void ipcpackcaret(unsigned char[Ipccaretsz], int, int32_t, int32_t, int32_t);
|
void ipcpackcaret(unsigned char[Ipccaretsz], int, int32_t, int32_t, int32_t);
|
||||||
|
void ipcpacksurround(unsigned char[Ipcreqsz], size_t);
|
||||||
|
size_t ipcsurroundlen(const unsigned char[Ipcreqsz]);
|
||||||
void ipcunpackreq(const unsigned char[Ipcreqsz], int*, uint32_t*, uint32_t*);
|
void ipcunpackreq(const unsigned char[Ipcreqsz], int*, uint32_t*, uint32_t*);
|
||||||
int ipcunpackcaret(const unsigned char[Ipccaretsz], int*, int32_t*, int32_t*, int32_t*);
|
int ipcunpackcaret(const unsigned char[Ipccaretsz], int*, int32_t*, int32_t*, int32_t*);
|
||||||
int ipcreqtype(const unsigned char[Ipcreqsz]);
|
int ipcreqtype(const unsigned char[Ipcreqsz]);
|
||||||
int ipcreqreset(const unsigned char[Ipcreqsz]);
|
int ipcreqreset(const unsigned char[Ipcreqsz]);
|
||||||
int ipcpackresp(unsigned char*, size_t, int, const char*, size_t, const char*, size_t, int);
|
int ipcpackresp(unsigned char*, size_t, int, int, const char*, size_t, const char*, size_t, int);
|
||||||
int ipcreadn(int, void*, size_t);
|
int ipcreadn(int, void*, size_t);
|
||||||
int ipcsend(int, const void*, size_t);
|
int ipcsend(int, const void*, size_t);
|
||||||
int ipcreadresp(int, int, char*, char*, Ipcresp*);
|
int ipcreadresp(int, int, char*, char*, Ipcresp*);
|
||||||
|
|||||||
20
srv.c
20
srv.c
@@ -31,11 +31,17 @@ srvnote(void *v, char *note)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 0 for a request to make, 1 for a frame that only changes what rides
|
||||||
|
* along with the requests after it, -1 for anything else.
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
srvreadreq(int fd, Keyreq *kr, int *want)
|
srvreadreq(int fd, Keyreq *kr, int *want)
|
||||||
{
|
{
|
||||||
uchar req[Ipccaretsz];
|
uchar req[Ipccaretsz];
|
||||||
|
char text[Ipcfieldmax];
|
||||||
int valid;
|
int valid;
|
||||||
|
size_t n;
|
||||||
int32_t x, y, h;
|
int32_t x, y, h;
|
||||||
|
|
||||||
if(ipcreadn(fd, req, Ipcreqsz) < 0)
|
if(ipcreadn(fd, req, Ipcreqsz) < 0)
|
||||||
@@ -62,6 +68,12 @@ srvreadreq(int fd, Keyreq *kr, int *want)
|
|||||||
kr->caret.y = y;
|
kr->caret.y = y;
|
||||||
kr->caret.h = h;
|
kr->caret.h = h;
|
||||||
return 0;
|
return 0;
|
||||||
|
case Ipcsurround:
|
||||||
|
n = ipcsurroundlen(req);
|
||||||
|
if(n > 0 && ipcreadn(fd, text, n) < 0)
|
||||||
|
return -1;
|
||||||
|
stail(&kr->surround, text, n);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -78,7 +90,7 @@ clientthread(void *arg)
|
|||||||
Keyres res;
|
Keyres res;
|
||||||
uchar out[Ipcmaxresp], token;
|
uchar out[Ipcmaxresp], token;
|
||||||
char commit[Maxutf], preedit[Maxutf];
|
char commit[Maxutf], preedit[Maxutf];
|
||||||
int fd, n, ncommit, npreedit, want;
|
int fd, n, ncommit, npreedit, rv, want;
|
||||||
|
|
||||||
fd = (int)(uintptr)arg;
|
fd = (int)(uintptr)arg;
|
||||||
threadsetname("client %d", fd);
|
threadsetname("client %d", fd);
|
||||||
@@ -86,7 +98,9 @@ clientthread(void *arg)
|
|||||||
kr.reply = chancreate(sizeof(Keyres), 0);
|
kr.reply = chancreate(sizeof(Keyres), 0);
|
||||||
kr.owner = &fd;
|
kr.owner = &fd;
|
||||||
kr.clientpre = 1;
|
kr.clientpre = 1;
|
||||||
while(srvreadreq(fd, &kr, &want) >= 0){
|
while((rv = srvreadreq(fd, &kr, &want)) >= 0){
|
||||||
|
if(rv != 0)
|
||||||
|
continue;
|
||||||
if(kr.op != Keycaret)
|
if(kr.op != Keycaret)
|
||||||
kr.clientpre = want;
|
kr.clientpre = want;
|
||||||
chansend(keyc, &kr);
|
chansend(keyc, &kr);
|
||||||
@@ -97,7 +111,7 @@ clientthread(void *arg)
|
|||||||
npreedit = stoutf(&res.preedit, preedit, sizeof preedit);
|
npreedit = stoutf(&res.preedit, preedit, sizeof preedit);
|
||||||
/* A capability reply is always eaten: it marks the extension. */
|
/* A capability reply is always eaten: it marks the extension. */
|
||||||
n = ipcpackresp(out, sizeof out, kr.op == Keycap || res.eaten,
|
n = ipcpackresp(out, sizeof out, kr.op == Keycap || res.eaten,
|
||||||
commit, ncommit, preedit, npreedit, want);
|
res.del, commit, ncommit, preedit, npreedit, want);
|
||||||
if(n < 0 || ipcsend(fd, out, n) < 0)
|
if(n < 0 || ipcsend(fd, out, n) < 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
15
str.c
15
str.c
@@ -24,6 +24,21 @@ sinit(Str *s, char *src, int n)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The last runes of n bytes of UTF-8, as many as a Str holds. */
|
||||||
|
void
|
||||||
|
stail(Str *s, char *src, int n)
|
||||||
|
{
|
||||||
|
Rune r;
|
||||||
|
char *p;
|
||||||
|
int nr;
|
||||||
|
|
||||||
|
nr = utfnlen(src, n);
|
||||||
|
for(p = src; nr > Maxrunes; nr--)
|
||||||
|
p += chartorune(&r, p);
|
||||||
|
if(!sinit(s, p, n - (p - src)))
|
||||||
|
sclear(s);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sclear(Str *s)
|
sclear(Str *s)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -297,8 +297,8 @@ rejectold(Test *t, char *where)
|
|||||||
static int
|
static int
|
||||||
openreplacement(Test *t)
|
openreplacement(Test *t)
|
||||||
{
|
{
|
||||||
unsigned char selectjp[] = {1, 0, 0, 0, 0};
|
unsigned char selectjp[] = {1, 0, 0, 0, 0, 0};
|
||||||
unsigned char keyk[] = {1, 0, 0, 1, 0, 'k'};
|
unsigned char keyk[] = {1, 0, 0, 0, 1, 0, 'k'};
|
||||||
char path[96];
|
char path[96];
|
||||||
|
|
||||||
t->ipcnew = connectsocket(t->l.socket, nowms() + Calltimeout);
|
t->ipcnew = connectsocket(t->l.socket, nowms() + Calltimeout);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ enum
|
|||||||
Ecaret,
|
Ecaret,
|
||||||
Ekey,
|
Ekey,
|
||||||
Ereset,
|
Ereset,
|
||||||
|
Esurround,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@@ -55,6 +56,7 @@ struct Event
|
|||||||
int32_t x;
|
int32_t x;
|
||||||
int32_t y;
|
int32_t y;
|
||||||
int32_t h;
|
int32_t h;
|
||||||
|
char text[Ipcfieldmax+1];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Server
|
struct Server
|
||||||
@@ -69,6 +71,7 @@ struct Server
|
|||||||
int eaten;
|
int eaten;
|
||||||
int stall;
|
int stall;
|
||||||
int response;
|
int response;
|
||||||
|
int del;
|
||||||
int nclose;
|
int nclose;
|
||||||
char pre[Ipcfieldmax+1];
|
char pre[Ipcfieldmax+1];
|
||||||
Event ev[Maxevent];
|
Event ev[Maxevent];
|
||||||
@@ -83,6 +86,10 @@ struct Siglog
|
|||||||
char shown[Ipcfieldmax+1];
|
char shown[Ipcfieldmax+1];
|
||||||
char commit[Ipcfieldmax+1];
|
char commit[Ipcfieldmax+1];
|
||||||
int prechanged;
|
int prechanged;
|
||||||
|
char around[64]; /* what the widget answers retrieve-surrounding */
|
||||||
|
int aroundcursor;
|
||||||
|
int deloffset;
|
||||||
|
int deln;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -110,13 +117,14 @@ sendresponse(Server *s, int fd, int eaten, int want, int key)
|
|||||||
unsigned char buf[Ipcmaxresp];
|
unsigned char buf[Ipcmaxresp];
|
||||||
const char *commit;
|
const char *commit;
|
||||||
char pre[Ipcfieldmax+1];
|
char pre[Ipcfieldmax+1];
|
||||||
int n, response, stall;
|
int del, n, response, stall;
|
||||||
size_t ncommit, npreedit;
|
size_t ncommit, npreedit;
|
||||||
|
|
||||||
pthread_mutex_lock(&s->lock);
|
pthread_mutex_lock(&s->lock);
|
||||||
memcpy(pre, s->pre, sizeof pre);
|
memcpy(pre, s->pre, sizeof pre);
|
||||||
response = s->response;
|
response = s->response;
|
||||||
stall = s->stall;
|
stall = s->stall;
|
||||||
|
del = key ? s->del : 0;
|
||||||
pthread_mutex_unlock(&s->lock);
|
pthread_mutex_unlock(&s->lock);
|
||||||
if(stall)
|
if(stall)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -135,7 +143,7 @@ sendresponse(Server *s, int fd, int eaten, int want, int key)
|
|||||||
pre[2] = 'y';
|
pre[2] = 'y';
|
||||||
npreedit = 3;
|
npreedit = 3;
|
||||||
}
|
}
|
||||||
n = ipcpackresp(buf, sizeof buf, eaten, commit, ncommit,
|
n = ipcpackresp(buf, sizeof buf, eaten, del, commit, ncommit,
|
||||||
pre, npreedit, want);
|
pre, npreedit, want);
|
||||||
return n >= 0 && ipcsend(fd, buf, n) == 0;
|
return n >= 0 && ipcsend(fd, buf, n) == 0;
|
||||||
}
|
}
|
||||||
@@ -146,6 +154,7 @@ request(Server *s, int fd)
|
|||||||
unsigned char buf[Ipccaretsz];
|
unsigned char buf[Ipccaretsz];
|
||||||
uint32_t mod, key;
|
uint32_t mod, key;
|
||||||
Event e;
|
Event e;
|
||||||
|
size_t n;
|
||||||
int old, type, want;
|
int old, type, want;
|
||||||
|
|
||||||
if(ipcreadn(fd, buf, Ipcreqsz) < 0)
|
if(ipcreadn(fd, buf, Ipcreqsz) < 0)
|
||||||
@@ -168,6 +177,14 @@ request(Server *s, int fd)
|
|||||||
e.type = Ecaret;
|
e.type = Ecaret;
|
||||||
record(s, &e);
|
record(s, &e);
|
||||||
return 1;
|
return 1;
|
||||||
|
case Ipcsurround:
|
||||||
|
n = ipcsurroundlen(buf);
|
||||||
|
if(n > 0 && ipcreadn(fd, e.text, n) < 0)
|
||||||
|
return 0;
|
||||||
|
e.text[n] = '\0';
|
||||||
|
e.type = Esurround;
|
||||||
|
record(s, &e);
|
||||||
|
return 1;
|
||||||
case Ipckey:
|
case Ipckey:
|
||||||
ipcunpackreq(buf, &want, &mod, &key);
|
ipcunpackreq(buf, &want, &mod, &key);
|
||||||
e.want = want;
|
e.want = want;
|
||||||
@@ -513,6 +530,25 @@ clearlog(Siglog *l)
|
|||||||
memset(l, 0, sizeof *l);
|
memset(l, 0, sizeof *l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The widget's half of the surrounding-text contract. */
|
||||||
|
static gboolean
|
||||||
|
retrievearound(GtkIMContext *ctx, Siglog *l)
|
||||||
|
{
|
||||||
|
if(l->around[0] == '\0')
|
||||||
|
return FALSE;
|
||||||
|
gtk_im_context_set_surrounding(ctx, l->around, -1, l->aroundcursor);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
deletearound(GtkIMContext *ctx, gint offset, gint n, Siglog *l)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
l->deloffset = offset;
|
||||||
|
l->deln = n;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static GtkIMContext*
|
static GtkIMContext*
|
||||||
newcontext(Siglog *l)
|
newcontext(Siglog *l)
|
||||||
{
|
{
|
||||||
@@ -520,6 +556,8 @@ newcontext(Siglog *l)
|
|||||||
|
|
||||||
ctx = gtk_im_multicontext_new();
|
ctx = gtk_im_multicontext_new();
|
||||||
gtk_im_multicontext_set_context_id(GTK_IM_MULTICONTEXT(ctx), "strans");
|
gtk_im_multicontext_set_context_id(GTK_IM_MULTICONTEXT(ctx), "strans");
|
||||||
|
g_signal_connect(ctx, "retrieve-surrounding", G_CALLBACK(retrievearound), l);
|
||||||
|
g_signal_connect(ctx, "delete-surrounding", G_CALLBACK(deletearound), l);
|
||||||
g_signal_connect(ctx, "preedit-start", G_CALLBACK(prestart), l);
|
g_signal_connect(ctx, "preedit-start", G_CALLBACK(prestart), l);
|
||||||
g_signal_connect(ctx, "preedit-changed", G_CALLBACK(prechange), l);
|
g_signal_connect(ctx, "preedit-changed", G_CALLBACK(prechange), l);
|
||||||
g_signal_connect(ctx, "preedit-end", G_CALLBACK(preend), l);
|
g_signal_connect(ctx, "preedit-end", G_CALLBACK(preend), l);
|
||||||
@@ -667,7 +705,7 @@ main(int argc, char **argv)
|
|||||||
Check(eventcount(&srv) == 0, "cursor reporting opened the socket");
|
Check(eventcount(&srv) == 0, "cursor reporting opened the socket");
|
||||||
setpre(&srv, "");
|
setpre(&srv, "");
|
||||||
Check(key(ctx, win, GDK_KEY_a), "initial key was not eaten");
|
Check(key(ctx, win, GDK_KEY_a), "initial key was not eaten");
|
||||||
Check(waitcount(&srv, 3), "initial protocol frames timed out");
|
Check(waitcount(&srv, 4), "initial protocol frames timed out");
|
||||||
e = getevent(&srv, 0);
|
e = getevent(&srv, 0);
|
||||||
Check(e.type == Ecap && e.want == 1, "default preedit capability missing");
|
Check(e.type == Ecap && e.want == 1, "default preedit capability missing");
|
||||||
e = getevent(&srv, 1);
|
e = getevent(&srv, 1);
|
||||||
@@ -682,6 +720,9 @@ main(int argc, char **argv)
|
|||||||
e.x, e.y, e.h, (ox + rect.x) * scale,
|
e.x, e.y, e.h, (ox + rect.x) * scale,
|
||||||
(oy + rect.y) * scale, rect.height * scale);
|
(oy + rect.y) * scale, rect.height * scale);
|
||||||
e = getevent(&srv, 2);
|
e = getevent(&srv, 2);
|
||||||
|
Check(e.type == Esurround && e.text[0] == '\0',
|
||||||
|
"a widget that keeps no text sent some");
|
||||||
|
e = getevent(&srv, 3);
|
||||||
Check(e.type == Ekey && e.want == 1, "initial key framing changed");
|
Check(e.type == Ekey && e.want == 1, "initial key framing changed");
|
||||||
Check(log.n == 0, "initial empty preedit emitted %s", log.event);
|
Check(log.n == 0, "initial empty preedit emitted %s", log.event);
|
||||||
setpre(&srv, "ㅋ");
|
setpre(&srv, "ㅋ");
|
||||||
@@ -804,6 +845,38 @@ main(int argc, char **argv)
|
|||||||
"visible-entry key did not reach the daemon");
|
"visible-entry key did not reach the daemon");
|
||||||
gtk_im_context_set_client_window(ctx, win);
|
gtk_im_context_set_client_window(ctx, win);
|
||||||
|
|
||||||
|
/* The widget's own text goes over, and a take-back comes back. */
|
||||||
|
setpre(&srv, "");
|
||||||
|
clearlog(&log);
|
||||||
|
snprintf(log.around, sizeof log.around, "%s", "가나한");
|
||||||
|
log.aroundcursor = 9;
|
||||||
|
first = eventcount(&srv);
|
||||||
|
Check(key(ctx, win, GDK_KEY_j), "surrounding-text key was not eaten");
|
||||||
|
Check(waitcount(&srv, first + 2), "surrounding text did not reach the daemon");
|
||||||
|
e = getevent(&srv, first);
|
||||||
|
Check(e.type == Esurround && strcmp(e.text, "가나한") == 0,
|
||||||
|
"the daemon was sent %s, not the text before the cursor", e.text);
|
||||||
|
Check(getevent(&srv, first + 1).type == Ekey,
|
||||||
|
"the text did not ride ahead of the key");
|
||||||
|
/* Sent again only when it changes. */
|
||||||
|
first = eventcount(&srv);
|
||||||
|
Check(key(ctx, win, GDK_KEY_j), "second surrounding-text key was not eaten");
|
||||||
|
Check(waitcount(&srv, first + 1) && getevent(&srv, first).type == Ekey,
|
||||||
|
"unchanged surrounding text was sent again");
|
||||||
|
setreply(&srv, 1, Rnormal, 0);
|
||||||
|
pthread_mutex_lock(&srv.lock);
|
||||||
|
srv.del = 2;
|
||||||
|
pthread_mutex_unlock(&srv.lock);
|
||||||
|
log.deln = 0;
|
||||||
|
Check(key(ctx, win, GDK_KEY_j), "take-back key was not eaten");
|
||||||
|
Check(log.deloffset == -2 && log.deln == 2,
|
||||||
|
"the widget was told to take back %d runes at %d", log.deln,
|
||||||
|
log.deloffset);
|
||||||
|
pthread_mutex_lock(&srv.lock);
|
||||||
|
srv.del = 0;
|
||||||
|
pthread_mutex_unlock(&srv.lock);
|
||||||
|
log.around[0] = '\0';
|
||||||
|
|
||||||
setpre(&srv, "reset");
|
setpre(&srv, "reset");
|
||||||
clearlog(&log);
|
clearlog(&log);
|
||||||
Check(key(ctx, win, GDK_KEY_e), "reset setup key was not eaten");
|
Check(key(ctx, win, GDK_KEY_e), "reset setup key was not eaten");
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ typedef struct Response Response;
|
|||||||
struct Response
|
struct Response
|
||||||
{
|
{
|
||||||
int eaten;
|
int eaten;
|
||||||
|
int del;
|
||||||
char commit[Ipcfieldmax+1];
|
char commit[Ipcfieldmax+1];
|
||||||
char preedit[Ipcfieldmax+1];
|
char preedit[Ipcfieldmax+1];
|
||||||
};
|
};
|
||||||
@@ -50,7 +51,8 @@ readresponseuntil(int fd, int want, Response *res, int64_t deadline,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
res->eaten = hdr[0] != 0;
|
res->eaten = hdr[0] != 0;
|
||||||
n = getlen(hdr + 1);
|
res->del = hdr[1];
|
||||||
|
n = getlen(hdr + 2);
|
||||||
if(n > Ipcfieldmax){
|
if(n > Ipcfieldmax){
|
||||||
fail("invalid commit length %zu", n);
|
fail("invalid commit length %zu", n);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -119,6 +121,18 @@ sendcap(int fd, int cap)
|
|||||||
return ipcsend(fd, req, sizeof req) == 0;
|
return ipcsend(fd, req, sizeof req) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sendsurround(int fd, char *text)
|
||||||
|
{
|
||||||
|
unsigned char req[Ipcreqsz];
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
n = strlen(text);
|
||||||
|
ipcpacksurround(req, n);
|
||||||
|
return ipcsend(fd, req, sizeof req) == 0 &&
|
||||||
|
(n == 0 || ipcsend(fd, text, n) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
expectresponse(int fd, int want, int eaten, char *commit, char *preedit,
|
expectresponse(int fd, int want, int eaten, char *commit, char *preedit,
|
||||||
char *where)
|
char *where)
|
||||||
@@ -152,6 +166,33 @@ requestkey(int fd, int want, uint32_t mod, uint32_t key, int eaten,
|
|||||||
return expectresponse(fd, want, eaten, commit, preedit, where);
|
return expectresponse(fd, want, eaten, commit, preedit, where);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The Korean habit: 한자 typed, then the Hanja key. The 한 is the
|
||||||
|
* client's by then, so the daemon must ask for it back and answer with
|
||||||
|
* the whole word.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
requesthanja(int fd)
|
||||||
|
{
|
||||||
|
Response res;
|
||||||
|
|
||||||
|
if(!sendsurround(fd, "저는 한"))
|
||||||
|
return fail("send surrounding text: %s", strerror(errno));
|
||||||
|
if(!requestkey(fd, 1, Mctrl, 's', 1, "", "", "select Korean") ||
|
||||||
|
!requestkey(fd, 1, 0, 'w', 1, "", "ㅈ", "jamo") ||
|
||||||
|
!requestkey(fd, 1, 0, 'k', 1, "", "자", "syllable") ||
|
||||||
|
!requestkey(fd, 1, Mctrl, 'h', 1, "", "자", "Hanja search"))
|
||||||
|
return 0;
|
||||||
|
if(!sendkey(fd, 1, 0, Kret))
|
||||||
|
return fail("send Hanja pick: %s", strerror(errno));
|
||||||
|
if(readresponseuntil(fd, 1, &res, nowms() + Calltimeout, 0) != 1)
|
||||||
|
return 0;
|
||||||
|
if(strcmp(res.commit, "漢字") != 0 || res.del != 1)
|
||||||
|
return fail("Hanja pick committed %s and took back %d",
|
||||||
|
res.commit, res.del);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
tryclient(char *path, int64_t deadline, int *client)
|
tryclient(char *path, int64_t deadline, int *client)
|
||||||
{
|
{
|
||||||
@@ -258,7 +299,8 @@ runsmoke(char *path)
|
|||||||
requestkey(client, 1, Mctrl, 'n', 1, "", "",
|
requestkey(client, 1, Mctrl, 'n', 1, "", "",
|
||||||
"select Japanese") &&
|
"select Japanese") &&
|
||||||
requestkey(client, 1, 0, 'k', 1, "", "k", "preedit") &&
|
requestkey(client, 1, 0, 'k', 1, "", "k", "preedit") &&
|
||||||
requestreset(client, 1, 1, "k", "", "reset");
|
requestreset(client, 1, 1, "k", "", "reset") &&
|
||||||
|
requesthanja(client);
|
||||||
close(client);
|
close(client);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,34 +177,37 @@ ipc_runtime_path(struct ct *t)
|
|||||||
void
|
void
|
||||||
ipc_response_pack_boundaries(struct ct *t)
|
ipc_response_pack_boundaries(struct ct *t)
|
||||||
{
|
{
|
||||||
static const uchar withpre[] = { 1, 1, 0, 'A', 2, 0, 'x', 'y' };
|
static const uchar withpre[] = { 1, 3, 1, 0, 'A', 2, 0, 'x', 'y' };
|
||||||
static const uchar withoutpre[] = { 1, 1, 0, 'A' };
|
static const uchar withoutpre[] = { 1, 0, 1, 0, 'A' };
|
||||||
uchar out[Ipcmaxresp+1], field[Ipcfieldmax];
|
uchar out[Ipcmaxresp+1], field[Ipcfieldmax];
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
n = ipcpackresp(out, sizeof out, 7, "A", 1, "xy", 2, 1);
|
n = ipcpackresp(out, sizeof out, 7, 3, "A", 1, "xy", 2, 1);
|
||||||
CT_EQ_INT(t, sizeof withpre, n);
|
CT_EQ_INT(t, sizeof withpre, n);
|
||||||
CT_EQ_MEM(t, withpre, out, sizeof withpre);
|
CT_EQ_MEM(t, withpre, out, sizeof withpre);
|
||||||
n = ipcpackresp(out, sizeof out, 1, "A", 1, "xy", 2, 0);
|
n = ipcpackresp(out, sizeof out, 1, 0, "A", 1, "xy", 2, 0);
|
||||||
CT_EQ_INT(t, sizeof withoutpre, n);
|
CT_EQ_INT(t, sizeof withoutpre, n);
|
||||||
CT_EQ_MEM(t, withoutpre, out, sizeof withoutpre);
|
CT_EQ_MEM(t, withoutpre, out, sizeof withoutpre);
|
||||||
n = ipcpackresp(out, sizeof out, 0, nil, 0, nil, 0, 1);
|
n = ipcpackresp(out, sizeof out, 0, 0, nil, 0, nil, 0, 1);
|
||||||
CT_EQ_INT(t, Ipcresphdrsz + Ipclensz, n);
|
CT_EQ_INT(t, Ipcresphdrsz + Ipclensz, n);
|
||||||
|
|
||||||
memset(field, 'x', sizeof field);
|
memset(field, 'x', sizeof field);
|
||||||
memset(out, 0xa5, sizeof out);
|
memset(out, 0xa5, sizeof out);
|
||||||
n = ipcpackresp(out, Ipcmaxresp, 1,
|
n = ipcpackresp(out, Ipcmaxresp, 1, 0,
|
||||||
(char*)field, sizeof field, (char*)field, sizeof field, 1);
|
(char*)field, sizeof field, (char*)field, sizeof field, 1);
|
||||||
CT_EQ_INT(t, Ipcmaxresp, n);
|
CT_EQ_INT(t, Ipcmaxresp, n);
|
||||||
CT_EQ_INT(t, 0, out[1]);
|
CT_EQ_INT(t, 0, out[2]);
|
||||||
CT_EQ_INT(t, 1, out[2]);
|
CT_EQ_INT(t, 1, out[3]);
|
||||||
CT_EQ_INT(t, 0, out[3+Ipcfieldmax]);
|
CT_EQ_INT(t, 0, out[4+Ipcfieldmax]);
|
||||||
CT_EQ_INT(t, 1, out[4+Ipcfieldmax]);
|
CT_EQ_INT(t, 1, out[5+Ipcfieldmax]);
|
||||||
CT_EQ_INT(t, 0xa5, out[Ipcmaxresp]);
|
CT_EQ_INT(t, 0xa5, out[Ipcmaxresp]);
|
||||||
CT_EQ_INT(t, -1, ipcpackresp(out, Ipcmaxresp-1, 1,
|
CT_EQ_INT(t, -1, ipcpackresp(out, Ipcmaxresp-1, 1, 0,
|
||||||
(char*)field, sizeof field, (char*)field, sizeof field, 1));
|
(char*)field, sizeof field, (char*)field, sizeof field, 1));
|
||||||
CT_EQ_INT(t, -1, ipcpackresp(out, sizeof out, 0,
|
CT_EQ_INT(t, -1, ipcpackresp(out, sizeof out, 0, 0,
|
||||||
(char*)field, Ipcfieldmax+1, "", 0, 0));
|
(char*)field, Ipcfieldmax+1, "", 0, 0));
|
||||||
|
/* A take-back is a rune count and never leaves its byte. */
|
||||||
|
CT_EQ_INT(t, -1, ipcpackresp(out, sizeof out, 0, -1, "", 0, "", 0, 0));
|
||||||
|
CT_EQ_INT(t, -1, ipcpackresp(out, sizeof out, 0, 256, "", 0, "", 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -215,8 +218,8 @@ ipc_response_empty_and_preedit(struct ct *t)
|
|||||||
Ipcresp resp;
|
Ipcresp resp;
|
||||||
int fd[2], nfirst, nsecond;
|
int fd[2], nfirst, nsecond;
|
||||||
|
|
||||||
nfirst = ipcpackresp(first, sizeof first, 0, "", 0, "", 0, 0);
|
nfirst = ipcpackresp(first, sizeof first, 0, 0, "", 0, "", 0, 0);
|
||||||
nsecond = ipcpackresp(second, sizeof second, 1,
|
nsecond = ipcpackresp(second, sizeof second, 1, 0,
|
||||||
"go", 2, "kana", 4, 1);
|
"go", 2, "kana", 4, 1);
|
||||||
if(!CT_CHECK(t, nfirst > 0 && nsecond > 0))
|
if(!CT_CHECK(t, nfirst > 0 && nsecond > 0))
|
||||||
return;
|
return;
|
||||||
@@ -252,9 +255,9 @@ ipc_response_max_and_drain(struct ct *t)
|
|||||||
int fd[2], nfirst, nsecond;
|
int fd[2], nfirst, nsecond;
|
||||||
|
|
||||||
memset(field, 'x', sizeof field);
|
memset(field, 'x', sizeof field);
|
||||||
nfirst = ipcpackresp(first, sizeof first, 1,
|
nfirst = ipcpackresp(first, sizeof first, 1, 0,
|
||||||
(char*)field, sizeof field, (char*)field, sizeof field, 1);
|
(char*)field, sizeof field, (char*)field, sizeof field, 1);
|
||||||
nsecond = ipcpackresp(second, sizeof second, 0, "ok", 2, "", 0, 0);
|
nsecond = ipcpackresp(second, sizeof second, 0, 0, "ok", 2, "", 0, 0);
|
||||||
if(!CT_CHECK(t, nfirst == Ipcmaxresp && nsecond > 0))
|
if(!CT_CHECK(t, nfirst == Ipcmaxresp && nsecond > 0))
|
||||||
return;
|
return;
|
||||||
if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0){
|
if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0){
|
||||||
@@ -285,7 +288,7 @@ ipc_response_fragmented_and_truncated(struct ct *t)
|
|||||||
Ipcresp resp;
|
Ipcresp resp;
|
||||||
int fd[2], i, n;
|
int fd[2], i, n;
|
||||||
|
|
||||||
n = ipcpackresp(frame, sizeof frame, 1, "abc", 3, "xy", 2, 1);
|
n = ipcpackresp(frame, sizeof frame, 1, 2, "abc", 3, "xy", 2, 1);
|
||||||
if(!CT_CHECK(t, n > 0))
|
if(!CT_CHECK(t, n > 0))
|
||||||
return;
|
return;
|
||||||
if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0){
|
if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0){
|
||||||
|
|||||||
@@ -767,7 +767,8 @@ ipcrequest(int fd, uint32_t mod, uint32_t key, unsigned char *want,
|
|||||||
int
|
int
|
||||||
ipcprobe(int fd, char *where)
|
ipcprobe(int fd, char *where)
|
||||||
{
|
{
|
||||||
unsigned char empty[] = {0, 0, 0, 0, 0};
|
/* eaten, take-back, no commit, no preedit */
|
||||||
|
unsigned char empty[] = {0, 0, 0, 0, 0, 0};
|
||||||
|
|
||||||
return ipcrequest(fd, 0, 0, empty, sizeof empty, where);
|
return ipcrequest(fd, 0, 0, empty, sizeof empty, where);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user