_XimProtoCreateIC(
    XIM			 xim,
    XIMArg		*arg)
{
    Xim			 im = (Xim)xim;
    Xic			 ic;
    XimDefICValues	 ic_values;
    XIMResourceList	 res;
    unsigned int         num;
    XIMStyle		 input_style;
    INT16		 len;
    CARD16		*buf_s;
    char		*tmp;
    CARD32		 tmp_buf32[BUFSIZE/4];
    char		*tmp_buf = (char *)tmp_buf32;
    char		*buf;
    int			 buf_size;
    char		*data;
    int			 data_len;
    int			 ret_len;
    int			 total;
    XIMArg		*arg_ret;
    CARD32		 reply32[BUFSIZE/4];
    char		*reply = (char *)reply32;
    XPointer		 preply;
    int			 ret_code;

#ifdef XIM_CONNECTABLE
    if (!IS_SERVER_CONNECTED(im) && !IS_CONNECTABLE(im))
	return (XIC)NULL;
#else
    if (!IS_SERVER_CONNECTED(im))
	return (XIC)NULL;
#endif /* XIM_CONNECTABLE */

    if (!(_XimGetInputStyle(arg, &input_style)))
	return (XIC)NULL;

    if ((ic = Xcalloc(1, sizeof(XicRec))) == (Xic)NULL)
	return (XIC)NULL;

    ic->methods = &ic_methods;
    ic->core.im = (XIM)im;
    ic->core.input_style = input_style;

    num = im->core.ic_num_resources;
    len = sizeof(XIMResource) * num;
    if (!(res = Xmalloc(len)))
	goto ErrorOnCreatingIC;
    (void)memcpy((char *)res, (char *)im->core.ic_resources, len);
    ic->private.proto.ic_resources     = res;
    ic->private.proto.ic_num_resources = num;

#ifdef XIM_CONNECTABLE
    if (!_XimSaveICValues(ic, arg))
	return False;

    if (!IS_SERVER_CONNECTED(im)) {
	if (!_XimConnectServer(im)) {
	    if (_XimDelayModeCreateIC(ic, arg, res, num)) {
		return (XIC)ic;
	    }
	    goto ErrorOnCreatingIC;
	}
    }
#endif /* XIM_CONNECTABLE */

    ic->core.filter_events = im->private.proto.forward_event_mask;
    ic->private.proto.forward_event_mask =
				im->private.proto.forward_event_mask;
    ic->private.proto.synchronous_event_mask =
				im->private.proto.synchronous_event_mask;

    num = im->private.proto.ic_num_inner_resources;
    len = sizeof(XIMResource) * num;
    if (!(res = Xmalloc(len)))
	goto ErrorOnCreatingIC;
    (void)memcpy((char *)res,
			 (char *)im->private.proto.ic_inner_resources, len);
    ic->private.proto.ic_inner_resources     = res;
    ic->private.proto.ic_num_inner_resources = num;

    _XimSetICMode(ic->private.proto.ic_resources,
			ic->private.proto.ic_num_resources, input_style);

    _XimSetICMode(ic->private.proto.ic_inner_resources,
			ic->private.proto.ic_num_inner_resources, input_style);

    _XimGetCurrentICValues(ic, &ic_values);
    buf = tmp_buf;
    buf_size = XIM_HEADER_SIZE + sizeof(CARD16) + sizeof(INT16);
    data_len = BUFSIZE - buf_size;
    total = 0;
    arg_ret = arg;
    for (;;) {
	data = &buf[buf_size];
	if (_XimEncodeICATTRIBUTE(ic, ic->private.proto.ic_resources,
		ic->private.proto.ic_num_resources, arg, &arg_ret, data,
		data_len, &ret_len, (XPointer)&ic_values, 0, XIM_CREATEIC)) {
	    goto ErrorOnCreatingIC;
	}

	total += ret_len;
	if (!(arg = arg_ret)) {
	    break;
	}

	buf_size += ret_len;
	if (buf == tmp_buf) {
	    if (!(tmp = Xmalloc(buf_size + data_len))) {
	        goto ErrorOnCreatingIC;
	    }
	    memcpy(tmp, buf, buf_size);
	    buf = tmp;
	} else {
	    if (!(tmp = Xrealloc(buf, (buf_size + data_len)))) {
		Xfree(buf);
	        goto ErrorOnCreatingIC;
	    }
	    buf = tmp;
	}
    }
    _XimSetCurrentICValues(ic, &ic_values);

    if (!(_XimCheckCreateICValues(ic->private.proto.ic_resources,
					ic->private.proto.ic_num_resources)))
	goto ErrorOnCreatingIC;

    _XimRegisterFilter(ic);

    buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
    buf_s[0] = im->private.proto.imid;
    buf_s[1] = (INT16)total;

    len = (INT16)(sizeof(CARD16) + sizeof(INT16) + total);
    _XimSetHeader((XPointer)buf, XIM_CREATE_IC, 0, &len);
    if (!(_XimWrite(im, len, (XPointer)buf))) {
	if (buf != tmp_buf)
	    Xfree(buf);
	goto ErrorOnCreatingIC;
    }
    _XimFlush(im);
    if (buf != tmp_buf)
	Xfree(buf);
    ic->private.proto.waitCallback = True;
    buf_size = BUFSIZE;
    ret_code = _XimRead(im, &len, (XPointer)reply, buf_size,
						 _XimCreateICCheck, 0);
    if (ret_code == XIM_TRUE) {
	preply = reply;
    } else if (ret_code == XIM_OVERFLOW) {
	if (len <= 0) {
	    preply = reply;
	} else {
	    buf_size = (int)len;
	    preply = Xmalloc(buf_size);
	    ret_code = _XimRead(im, &len, preply, buf_size,
						 _XimCreateICCheck, 0);
	    if (ret_code != XIM_TRUE) {
		Xfree(preply);
		ic->private.proto.waitCallback = False;
		goto ErrorOnCreatingIC;
	    }
	}
    } else {
	ic->private.proto.waitCallback = False;
	goto ErrorOnCreatingIC;
    }
    ic->private.proto.waitCallback = False;
    buf_s = (CARD16 *)((char *)preply + XIM_HEADER_SIZE);
    if (*((CARD8 *)preply) == XIM_ERROR) {
	_XimProcError(im, 0, (XPointer)&buf_s[3]);
	if (reply != preply)
	    Xfree(preply);
	goto ErrorOnCreatingIC;
    }

    ic->private.proto.icid = buf_s[1];		/* icid */
    if (reply != preply)
	Xfree(preply);
    MARK_IC_CONNECTED(ic);
    return (XIC)ic;

ErrorOnCreatingIC:
    _XimUnregisterFilter(ic);

    Xfree(ic->private.proto.ic_resources);
    Xfree(ic->private.proto.ic_inner_resources);
    Xfree(ic);
    return (XIC)NULL;
}