Skip to content

Instantly share code, notes, and snippets.

@iratqq
Created January 18, 2011 09:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iratqq/784223 to your computer and use it in GitHub Desktop.
Save iratqq/784223 to your computer and use it in GitHub Desktop.
/*
* Copyright (c) 2011 Iwata <iwata@quasiquote.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <locale.h>
#include <langinfo.h>
#include <sys/types.h>
#include <sys/time.h>
#ifdef HAVE_KQUEUE
#include <sys/event.h>
#else
#include <poll.h>
#endif
#include <iconv.h>
#include <uim.h>
#include <uim-helper.h>
#include <uim-scm.h>
int dzen2_uim_fd = 0;
int dzen2_uim_fatal = 0;
int dzen2_uim_ready = 0;
#ifdef HAVE_KQUEUE
int dzen2_uim_kq;
struct kevent dzen2_uim_kev;
#endif
static char dzen2_im_name[16];
static char dzen2_im_mode[16];
char *dzen2_uim_lang = "UTF-8";
void
dzen2_uim_helper_disconnect_cb()
{
dzen2_uim_fd = -1;
}
static int
iconv_convert(char **outstr, char *instr, const char *fromcode)
{
iconv_t cd;
size_t ins;
char *in;
size_t outbufsiz, outs;
char *outbuf, *out;
size_t ret = 0, irr = 0;
size_t idx = 0;
size_t nconv = 0;
char *str = NULL;
cd = iconv_open(dzen2_uim_lang, fromcode);
if (cd == (iconv_t)-1) {
dzen2_uim_fatal = 1;
close(dzen2_uim_fd);
dzen2_uim_fd = 0;
return -1;
}
ins = strlen(instr);
in = instr;
outbufsiz = BUFSIZ;
out = outbuf = uim_malloc(outbufsiz);
while (ins > 0) {
out = outbuf;
outs = outbufsiz;
ret = iconv(cd, &in, &ins, &out, &outs);
nconv = outbufsiz - outs;
if (ret == (size_t)-1) {
switch (errno) {
case EINVAL:
goto err;
case E2BIG:
outbufsiz *= 2;
out = uim_realloc(outbuf, outbufsiz);
outbuf = out;
break;
default:
goto err;
}
} else {
irr += ret;
}
if (nconv > 0) {
char *newstr;
if (str == NULL)
newstr = uim_malloc(nconv + 1);
else
newstr = uim_realloc(str, idx + nconv + 1);
str = newstr;
memcpy(&str[idx], outbuf, nconv);
idx += nconv;
}
}
do {
out = outbuf;
outs = outbufsiz;
ret = iconv(cd, NULL, NULL, &out, &outs);
nconv = outbufsiz - outs;
if (ret == (size_t)-1) {
outbufsiz *= 2;
out = uim_realloc(outbuf, outbufsiz);
outbuf = out;
} else {
irr += ret;
}
if (nconv > 0) {
char *newstr;
if (str == NULL)
newstr = uim_malloc(nconv + 1);
else
newstr = uim_realloc(str, idx + nconv + 1);
str = newstr;
memcpy(&str[idx], outbuf, nconv);
idx += nconv;
}
} while (ret == (size_t)-1);
if (str == NULL)
str = uim_strdup("");
else
str[idx] = '\0';
if (!str)
goto err;
free(outbuf);
*outstr = str;
iconv_close(cd);
return irr;
err:
free(str);
free(outbuf);
outstr = NULL;
iconv_close(cd);
return -1;
}
#define MAXTOKENS 128
void
dzen2_uim_parse_prop_list(char *msg)
{
int branch;
char *eol;
if(uim_scm_symbol_value_bool("toolbar-show-action-based-switcher-button?"))
branch = -1;
else
branch = 0;
if ((eol = strchr(msg, '\n')) != NULL)
*eol = '\0';
else
return;
if (strcmp("prop_list_update", msg) == 0) {
char *head, *tail;
char *charset;
char *leaf;
head = eol + 1;
if ((eol = strchr(head, '\n')) != NULL) {
*eol = '\0';
} else {
return;
}
if (strncmp(head, "charset=", 8) == 0)
charset = head + 8;
else
return;
head = eol + 1;
if (0 <= iconv_convert(&leaf, head, charset)) {
head = leaf;
} else {
head = leaf = strdup("?");
}
while (head && *head) {
char *p, *tokens[MAXTOKENS];
char *last;
int i = 0;
size_t len;
tail = strchr(head, '\n');
if (tail)
*tail = '\0';
else
break;
len = strlen(head);
for ((p = strtok_r(head, "\t", &last)); p;
(p = strtok_r(NULL, "\t", &last))) {
if (i < MAXTOKENS - 1)
tokens[i++] = p;
}
tokens[i] = NULL;
if (strcmp(tokens[0], "branch") == 0 && i == 4) {
branch++;
if (i < 2) {
strlcpy(dzen2_im_name, "?", sizeof(dzen2_im_name));
strlcpy(dzen2_im_mode, "-", sizeof(dzen2_im_mode));
break;
}
if (branch == 0)
strlcpy(dzen2_im_name, tokens[3], sizeof(dzen2_im_name));
if (branch == 1) {
strlcpy(dzen2_im_mode, tokens[2], sizeof(dzen2_im_mode));
break;
}
}
head = tail + 1;
}
free(leaf);
leaf = NULL;
}
}
#ifdef HAVE_KQUEUE
static int
event_setup()
{
if ((dzen2_uim_kq = kqueue()) >= 0) {
EV_SET(&dzen2_uim_kev, dzen2_uim_fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
}
if (kevent(dzen2_uim_kq, &dzen2_uim_kev, 1, NULL, 0, NULL) < 0)
return 0;
return 1;
}
#else
static int
event_setup()
{
return 1;
}
#endif
void
dzen2_uim_init()
{
setlocale(LC_ALL, "");
/*
dzen2_uim_lang = nl_langinfo(CODESET);
*/
uim_init();
dzen2_uim_fd = uim_helper_init_client_fd(dzen2_uim_helper_disconnect_cb);
if (dzen2_uim_fd < 0) {
dzen2_uim_fatal = 1;
return;
}
if (!event_setup()) {
dzen2_uim_fatal = 1;
close(dzen2_uim_fd);
dzen2_uim_fd = 0;
return;
}
/* call once */
uim_helper_client_get_prop_list();
dzen2_uim_ready = 1;
return;
}
/* no wait */
static const struct timespec dzen2_uim_waitspec = { 0, 0 };
#ifdef HAVE_KQUEUE
static int
event_ready()
{
return (kevent(dzen2_uim_kq, NULL, 0, &dzen2_uim_kev, 1, &dzen2_uim_waitspec) == 1);
}
#else
static int
event_ready()
{
struct pollfd pfd;
int ndfs;
pfd.fd = dzen2_uim_fd;
pfd.events = POLLIN;
ndfs = poll(&pfd, 1, 0);
if (ndfs < 0) {
perror("poll");
return 0;
} else if (ndfs == 0)
return 0;
else
return 1;
}
#endif
static void
uim_printstate(void)
{
if (!dzen2_uim_ready) {
if (dzen2_uim_fatal && dzen2_uim_fd < 0) {
strlcpy(dzen2_im_name, "!", sizeof(dzen2_im_name));
strlcpy(dzen2_im_mode, "!", sizeof(dzen2_im_mode));
} else {
strlcpy(dzen2_im_name, "-", sizeof(dzen2_im_name));
strlcpy(dzen2_im_mode, "-", sizeof(dzen2_im_mode));
dzen2_uim_init();
}
}
if (dzen2_uim_ready && !dzen2_uim_fatal) {
if (event_ready()) {
char *msg;
uim_helper_read_proc(dzen2_uim_fd);
while ((msg = uim_helper_get_message()) != NULL) {
dzen2_uim_parse_prop_list(msg);
free(msg);
}
}
}
printf("%s - %s\n", dzen2_im_name, dzen2_im_mode);
fflush(stdout);
}
int
main(int argc, char *argv[])
{
while (1) {
sleep(1);
uim_printstate();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment