Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/processone/ejabberd.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlexey Shchepin <alexey@process-one.net>2003-10-09 22:09:05 +0400
committerAlexey Shchepin <alexey@process-one.net>2003-10-09 22:09:05 +0400
commit7df146166a7229a66e5d7d4fe8476a5a4c646e0b (patch)
tree4160eed36b115426b948f3944476ce41a1cf9fa6 /src
parent8e7106dd748b8b07da95f91a328ef145dc002997 (diff)
* src/ejabberd_c2s.erl: Added authentification logging
* src/ejabberd_listener.erl: Added logging of accepted connections * src/stringprep/stringprep_drv.c: Cleanup * src/jd2ejd.erl: Added support for iq:private importing * src/mod_configure.erl: Fixed user removal * src/mod_private.erl: Added remove_user/1 * doc/guide.tex: Updated * src/mod_disco.erl: Added "extra_domains" option SVN Revision: 146
Diffstat (limited to 'src')
-rw-r--r--src/ejabberd_c2s.erl26
-rw-r--r--src/ejabberd_listener.erl16
-rw-r--r--src/jd2ejd.erl42
-rw-r--r--src/mod_configure.erl28
-rw-r--r--src/mod_disco.erl24
-rw-r--r--src/mod_private.erl20
-rw-r--r--src/stringprep/stringprep_drv.c53
-rw-r--r--src/stringprep/uni_norm.c21
-rw-r--r--src/stringprep/uni_parse2.tcl21
9 files changed, 160 insertions, 91 deletions
diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
index a9a82d036..b18b02d6a 100644
--- a/src/ejabberd_c2s.erl
+++ b/src/ejabberd_c2s.erl
@@ -212,6 +212,10 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
case ejabberd_auth:check_password(
U, P, StateData#state.streamid, D) of
true ->
+ ?INFO_MSG(
+ "(~w) Accepted legacy authentification for ~s",
+ [StateData#state.socket,
+ jlib:jid_to_string(JID)]),
ejabberd_sm:open_session(U, R),
Res = jlib:make_result_iq_reply(El),
send_element(StateData, Res),
@@ -230,12 +234,19 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
pres_t = ?SETS:from_list(Ts),
privacy_list = PrivList}};
_ ->
+ ?INFO_MSG(
+ "(~w) Failed legacy authentification for ~s",
+ [StateData#state.socket,
+ jlib:jid_to_string(JID)]),
Err = jlib:make_error_reply(
El, ?ERR_FORBIDDEN),
send_element(StateData, Err),
{next_state, wait_for_auth, StateData}
end;
_ ->
+ ?INFO_MSG("(~w) Forbidden legacy authentification for ~s",
+ [StateData#state.socket,
+ jlib:jid_to_string(JID)]),
Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED),
send_element(StateData, Err),
{next_state, wait_for_auth, StateData}
@@ -286,6 +297,9 @@ wait_for_sasl_auth({xmlstreamelement, El}, StateData) ->
JID = #jid{user = U, resource = R} =
jlib:string_to_jid(
xml:get_attr_s(authzid, Props)),
+ ?INFO_MSG("(~w) Accepted authentification for ~s",
+ [StateData#state.socket,
+ jlib:jid_to_string(JID)]),
{next_state, wait_for_stream,
StateData#state{authentificated = true,
user = U,
@@ -350,6 +364,9 @@ wait_for_sasl_response({xmlstreamelement, El}, StateData) ->
[{"xmlns", ?NS_SASL}], []}),
JID = #jid{user = U, resource = R} =
jlib:string_to_jid(xml:get_attr_s(authzid, Props)),
+ ?INFO_MSG("(~w) Accepted authentification for ~s",
+ [StateData#state.socket,
+ jlib:jid_to_string(JID)]),
{next_state, wait_for_stream,
StateData#state{authentificated = true,
user = U,
@@ -410,6 +427,9 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
JID = jlib:make_jid(U, StateData#state.server, R),
case acl:match_rule(StateData#state.access, JID) of
allow ->
+ ?INFO_MSG("(~w) Opened session for ~s",
+ [StateData#state.socket,
+ jlib:jid_to_string(JID)]),
ejabberd_sm:open_session(U, R),
Res = jlib:make_result_iq_reply(El),
send_element(StateData, Res),
@@ -425,6 +445,9 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
pres_t = ?SETS:from_list(Ts),
privacy_list = PrivList}};
_ ->
+ ?INFO_MSG("(~w) Forbidden session for ~s",
+ [StateData#state.socket,
+ jlib:jid_to_string(JID)]),
Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED),
send_element(StateData, Err),
{next_state, wait_for_session, StateData}
@@ -700,6 +723,9 @@ terminate(Reason, StateName, StateData) ->
"" ->
ok;
_ ->
+ ?INFO_MSG("(~w) Close session for ~s",
+ [StateData#state.socket,
+ jlib:jid_to_string(StateData#state.jid)]),
ejabberd_sm:close_session(StateData#state.user,
StateData#state.resource),
From = StateData#state.jid,
diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl
index 73ffc9a21..9de102be0 100644
--- a/src/ejabberd_listener.erl
+++ b/src/ejabberd_listener.erl
@@ -15,6 +15,8 @@
init_ssl/4
]).
+-include("ejabberd.hrl").
+
start_link() ->
supervisor:start_link({local, ejabberd_listeners}, ?MODULE, []).
@@ -56,6 +58,13 @@ init(Port, Module, Opts) ->
accept(ListenSocket, Module, Opts) ->
case gen_tcp:accept(ListenSocket) of
{ok, Socket} ->
+ case {inet:sockname(Socket), inet:peername(Socket)} of
+ {{ok, Addr}, {ok, PAddr}} ->
+ ?INFO_MSG("(~w) Accepted connection ~w -> ~w",
+ [Socket, PAddr, Addr]);
+ _ ->
+ ok
+ end,
{ok, Pid} = Module:start({gen_tcp, Socket}, Opts),
%{ok, Pid} =
% supervisor:start_child(
@@ -82,6 +91,13 @@ init_ssl(Port, Module, Opts, SSLOpts) ->
accept_ssl(ListenSocket, Module, Opts) ->
case ssl:accept(ListenSocket) of
{ok, Socket} ->
+ case {ssl:sockname(Socket), ssl:peername(Socket)} of
+ {{ok, Addr}, {ok, PAddr}} ->
+ ?INFO_MSG("(~w) Accepted SSL connection ~w -> ~w",
+ [Socket, PAddr, Addr]);
+ _ ->
+ ok
+ end,
apply(Module, start_link, [{ssl, Socket}, Opts]),
accept_ssl(ListenSocket, Module, Opts)
end.
diff --git a/src/jd2ejd.erl b/src/jd2ejd.erl
index 456fc0a65..6c3815d3b 100644
--- a/src/jd2ejd.erl
+++ b/src/jd2ejd.erl
@@ -93,9 +93,7 @@ wait_for_xdb(closed, StateData) ->
xdb_data({xmlstreamelement, El}, StateData) ->
{xmlelement, Name, Attrs, Els} = El,
Server = StateData#state.server,
- From = {StateData#state.user,
- Server,
- ""},
+ From = jlib:make_jid(StateData#state.user, Server, ""),
NewState =
case xml:get_attr_s("xmlns", Attrs) of
?NS_AUTH ->
@@ -109,9 +107,9 @@ xdb_data({xmlstreamelement, El}, StateData) ->
mod_roster:set_items(StateData#state.user, El),
StateData;
?NS_VCARD ->
- Res = mod_vcard:process_local_iq(From,
- {"", ?MYNAME, ""},
- {iq, "", set, ?NS_VCARD, El}),
+ Res = mod_vcard:process_sm_iq(From,
+ jlib:make_jid("", ?MYNAME, ""),
+ {iq, "", set, ?NS_VCARD, El}),
StateData;
"jabber:x:offline" ->
process_offline(From, El),
@@ -124,8 +122,22 @@ xdb_data({xmlstreamelement, El}, StateData) ->
% io:format("user ~s~n", [User]),
% StateData;
XMLNS ->
- io:format("jd2ejd: Unknown namespace \"~s\"~n", [XMLNS]),
- StateData
+ case xml:get_attr_s("j_private_flag", Attrs) of
+ "1" ->
+ mod_private:process_local_iq(
+ From,
+ jlib:make_jid("", ?MYNAME, ""),
+ {iq, "", set, ?NS_PRIVATE,
+ {xmlelement, "query", [],
+ [jlib:remove_attr(
+ "j_private_flag",
+ jlib:remove_attr("xdbns", El))]}}),
+ StateData;
+ _ ->
+ io:format("jd2ejd: Unknown namespace \"~s\"~n",
+ [XMLNS]),
+ StateData
+ end
end,
{next_state, xdb_data, NewState};
@@ -191,7 +203,7 @@ handle_info(_, StateName, StateData) ->
%% Returns: any
%%----------------------------------------------------------------------
terminate(Reason, StateName, StateData) ->
- StateData#state.pid ! {jd2ejd, exited},
+ StateData#state.pid ! {jd2ejd, Reason},
ok.
%%%----------------------------------------------------------------------
@@ -217,12 +229,20 @@ process_offline(To, {xmlelement, _, _, Els}) ->
import_file(File) ->
+ clear_queue(),
start(File),
receive
- M -> M
- after 1000 -> ok
+ {jd2ejd, Result} -> Result
+ after 4000 -> timeout
end.
+clear_queue() ->
+ receive
+ {jd2ejd, _Result} -> clear_queue
+ after 0 -> ok
+ end.
+
+
import_dir(Dir) ->
{ok, Files} = file:list_dir(Dir),
MsgFiles = lists:filter(
diff --git a/src/mod_configure.erl b/src/mod_configure.erl
index 95bf4e417..18cdbdc90 100644
--- a/src/mod_configure.erl
+++ b/src/mod_configure.erl
@@ -665,13 +665,16 @@ set_form(["config", "remusers"], Lang, XData) ->
fun({Var, Vals}) ->
case Vals of
["1"] ->
- ejabberd_sm ! {route, {"", "", ""}, {Var, "", ""},
+ ejabberd_sm ! {route,
+ jlib:make_jid("", "", ""),
+ jlib:make_jid(Var, "", ""),
{xmlelement, "broadcast", [],
[{exit, "User removed"}]}},
catch ejabberd_auth:remove_user(Var),
catch mod_roster:remove_user(Var),
catch mod_offline:remove_user(Var),
- catch mod_vcard:remove_user(Var);
+ catch mod_vcard:remove_user(Var),
+ catch mod_private:remove_user(Var);
_ ->
ok
end
@@ -703,7 +706,7 @@ process_sm_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
deny ->
{iq, ID, error, XMLNS, [SubEl, ?ERR_NOT_ALLOWED]};
allow ->
- {User, _, _} = To,
+ #jid{user = User} = To,
Lang = xml:get_tag_attr_s("xml:lang", SubEl),
case Type of
set ->
@@ -790,5 +793,24 @@ get_sm_form(_, _, Lang) ->
{error, ?ERR_SERVICE_UNAVAILABLE}.
+set_sm_form(User, [], Lang, XData) ->
+ case lists:keysearch("action", 1, XData) of
+ {value, {_, ["edit"]}} ->
+ {error, ?ERR_FEATURE_NOT_IMPLEMENTED};
+ {value, {_, ["remove"]}} ->
+ ejabberd_sm ! {route,
+ jlib:make_jid("", "", ""),
+ jlib:make_jid(User, "", ""),
+ {xmlelement, "broadcast", [],
+ [{exit, "User removed"}]}},
+ catch ejabberd_auth:remove_user(User),
+ catch mod_roster:remove_user(User),
+ catch mod_offline:remove_user(User),
+ catch mod_vcard:remove_user(User),
+ catch mod_private:remove_user(User),
+ {result, []};
+ _ ->
+ {error, ?ERR_BAD_REQUEST}
+ end;
set_sm_form(_, _, Lang, XData) ->
{error, ?ERR_SERVICE_UNAVAILABLE}.
diff --git a/src/mod_disco.erl b/src/mod_disco.erl
index a85553d3b..f658b58f8 100644
--- a/src/mod_disco.erl
+++ b/src/mod_disco.erl
@@ -19,7 +19,9 @@
process_sm_iq_items/3,
process_sm_iq_info/3,
register_feature/1,
- unregister_feature/1]).
+ unregister_feature/1,
+ register_extra_domain/1,
+ unregister_extra_domain/1]).
-include("ejabberd.hrl").
-include("jlib.hrl").
@@ -42,6 +44,9 @@ start(Opts) ->
register_feature("iq"),
register_feature("presence"),
register_feature("presence-invisible"),
+ catch ets:new(disco_extra_domains, [named_table, ordered_set, public]),
+ ExtraDomains = gen_mod:get_opt(extra_domains, Opts, []),
+ lists:foreach(fun register_extra_domain/1, ExtraDomains),
ok.
stop() ->
@@ -59,6 +64,14 @@ unregister_feature(Feature) ->
catch ets:new(disco_features, [named_table, ordered_set, public]),
ets:delete(disco_features, Feature).
+register_extra_domain(Domain) ->
+ catch ets:new(disco_extra_domains, [named_table, ordered_set, public]),
+ ets:insert(disco_extra_domains, {Domain}).
+
+unregister_extra_domain(Domain) ->
+ catch ets:new(disco_extra_domains, [named_table, ordered_set, public]),
+ ets:delete(disco_extra_domains, Domain).
+
process_local_iq_items(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
Lang = xml:get_tag_attr_s("xml:lang", SubEl),
case Type of
@@ -180,10 +193,11 @@ process_local_iq_info(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
feature_to_xml({Feature}) ->
{xmlelement, "feature", [{"var", Feature}], []}.
+domain_to_xml({Domain}) ->
+ {xmlelement, "item", [{"jid", Domain}], []};
domain_to_xml(Domain) ->
{xmlelement, "item", [{"jid", Domain}], []}.
-
-define(NODE(Name, Node),
{xmlelement, "item",
[{"jid", Server},
@@ -193,12 +207,14 @@ domain_to_xml(Domain) ->
get_services_only() ->
lists:map(fun domain_to_xml/1,
- ejabberd_router:dirty_get_all_routes()).
+ ejabberd_router:dirty_get_all_routes()) ++
+ lists:map(fun domain_to_xml/1, ets:tab2list(disco_extra_domains)).
get_local_items([], Server, Lang) ->
Domains =
lists:map(fun domain_to_xml/1,
- ejabberd_router:dirty_get_all_routes()),
+ ejabberd_router:dirty_get_all_routes()) ++
+ lists:map(fun domain_to_xml/1, ets:tab2list(disco_extra_domains)),
{result,
Domains ++
[?NODE("Configuration", "config"),
diff --git a/src/mod_private.erl b/src/mod_private.erl
index 8b091433f..a4ec97d1d 100644
--- a/src/mod_private.erl
+++ b/src/mod_private.erl
@@ -14,7 +14,8 @@
-export([start/1,
stop/0,
- process_local_iq/3]).
+ process_local_iq/3,
+ remove_user/1]).
-include("ejabberd.hrl").
-include("jlib.hrl").
@@ -95,3 +96,20 @@ get_data(LUser, [El | Els], Res) ->
_ ->
get_data(LUser, Els, Res)
end.
+
+
+remove_user(User) ->
+ LUser = jlib:nodeprep(User),
+ F = fun() ->
+ lists:foreach(
+ fun({U, _} = Key) ->
+ if
+ U == LUser ->
+ mnesia:delete({private_storage, Key});
+ true ->
+ ok
+ end
+ end, mnesia:all_keys(private_storage))
+ end,
+ mnesia:transaction(F).
+
diff --git a/src/stringprep/stringprep_drv.c b/src/stringprep/stringprep_drv.c
index 906ea6207..43dd2b87a 100644
--- a/src/stringprep/stringprep_drv.c
+++ b/src/stringprep/stringprep_drv.c
@@ -37,7 +37,7 @@ static void stringprep_erl_stop(ErlDrvData handle)
* library
*/
-void canonical_ordering(int *str, int len)
+static void canonical_ordering(int *str, int len)
{
int i, j, t;
int last, next;
@@ -232,13 +232,6 @@ static int stringprep_erl_control(ErlDrvData drv_data,
}
info = GetUniCharInfo(uc);
- //if(info & prohibit) {
- // *rbuf = rstring;
- // driver_free(str32);
- // return 1;
- //}
-
- //printf("Got %x\r\n", uc);
if(!(info & B1Mask))
{
@@ -247,34 +240,10 @@ static int stringprep_erl_control(ErlDrvData drv_data,
{
ruc = uc + GetDelta(info);
ADD_DECOMP(ruc);
-
- //info = GetUniCharDecompInfo(ruc);
- //if(info >= 0) {
- // decomp_len = GetDecompLen(info);
- // decomp_shift = GetDecompShift(info);
- // for(j = 0; j < decomp_len; j++) {
- // ADD_UCHAR32(str32, str32pos, str32len,
- // decompList[decomp_shift + j]);
- // }
- //} else {
- // ADD_UCHAR32(str32, str32pos, str32len, ruc);
- //}
-
- //info = GetUniCharDecompInfo(ruc);
- //if(info >= 0) {
- // printf("Decomposition %x: ", ruc);
- // for(j = 0; j < GetDecompLen(info); j++) {
- // printf("%x ", decompList[GetDecompShift(info) + j]);
- // }
- // printf("\r\n");
- //}
-
- //ADD_UCHAR(ruc);
} else {
mc = GetMC(info);
for(j = 1; j <= mc[0]; j++) {
ruc = mc[j];
- //printf("Char %x cclass %d\r\n", ruc, GetUniCharCClass(ruc));
ADD_DECOMP(ruc);
}
}
@@ -292,19 +261,8 @@ static int stringprep_erl_control(ErlDrvData drv_data,
return 1;
}
- //printf("\r\n");
- //printf("DECOMPOSED:\t");
- //for(i = 0; i < str32pos; i++)
- // printf("%4x ", str32[i]);
- //printf("\r\n");
-
canonical_ordering(str32, str32pos);
- //printf("ORDERED:\t");
- //for(i = 0; i < str32pos; i++)
- // printf("%4x ", str32[i]);
- //printf("\r\n");
-
comp_pos = 1;
comp_starter_pos = 0;
ch1 = str32[0];
@@ -314,7 +272,6 @@ static int stringprep_erl_control(ErlDrvData drv_data,
{
ch2 = str32[i];
cclass2 = GetUniCharCClass(ch2);
- //printf("Compose: %x + %x = %x\r\n", ch1, ch2, compose(ch1, ch2));
if(cclass1 == 0 && cclass2 > cclass_prev && (ruc = compose(ch1, ch2))) {
ch1 = ruc;
} else {
@@ -332,11 +289,6 @@ static int stringprep_erl_control(ErlDrvData drv_data,
str32[comp_starter_pos] = ch1;
str32pos = comp_pos;
- //printf("COMPOSED:\t");
- //for(i = 0; i < str32pos; i++)
- // printf("%4x ", str32[i]);
- //printf("\r\n");
-
for(i = 0; i < str32pos; i++)
{
ruc = str32[i];
@@ -349,9 +301,6 @@ static int stringprep_erl_control(ErlDrvData drv_data,
ADD_UCHAR(ruc);
}
- //printf("Compose: %x\r\n", compose(0x438, 0x301));
- //printf("Pos: %d\r\n", pos);
-
rstring[0] = 1;
*rbuf = rstring;
driver_free(str32);
diff --git a/src/stringprep/uni_norm.c b/src/stringprep/uni_norm.c
index d95ad5ba0..fe7281b46 100644
--- a/src/stringprep/uni_norm.c
+++ b/src/stringprep/uni_norm.c
@@ -77,9 +77,8 @@ static unsigned char cclassPageMap[] = {
};
/*
- * The groupMap is indexed by combining the alternate page number with
- * the page offset and returns a group number that identifies a unique
- * set of character attributes.
+ * The cclassGroupMap is indexed by combining the alternate page number with
+ * the page offset and returns a combining class number.
*/
static unsigned char cclassGroupMap[] = {
@@ -297,9 +296,9 @@ static unsigned char decompPageMap[] = {
};
/*
- * The groupMap is indexed by combining the alternate page number with
- * the page offset and returns a group number that identifies a unique
- * set of character attributes.
+ * The decompGroupMap is indexed by combining the alternate page number with
+ * the page offset and returns a group number that identifies a length and
+ * shift of decomposition sequence in decompList
*/
static int decompGroupMap[] = {
@@ -839,7 +838,7 @@ static int decompGroupMap[] = {
};
/*
- * Each group represents a unique set of character attributes. The attributes...
+ * List of decomposition sequences
*/
static int decompList[] = {
@@ -1295,8 +1294,6 @@ static int decompList[] = {
* Unicode character tables.
*/
-//#define GetUniCharInfo(ch) (groups[groupMap[(pageMap[(((int)(ch)) & 0xffff) >> CCLASS_OFFSET_BITS] << CCLASS_OFFSET_BITS) | ((ch) & ((1 << CCLASS_OFFSET_BITS)-1))]])
-
#define GetUniCharDecompInfo(ch) (decompGroupMap[(decompPageMap[(((int)(ch)) & 0xffff) >> DECOMP_OFFSET_BITS] << DECOMP_OFFSET_BITS) | ((ch) & ((1 << DECOMP_OFFSET_BITS)-1))])
#define GetDecompShift(info) ((info) & 0xffff)
@@ -1556,7 +1553,7 @@ static int compGroupMap[] = {
};
/*
- * ...
+ * Lists of compositions for characters that appears only in one composition
*/
static int compFirstList[][2] = {
@@ -1612,6 +1609,10 @@ static int compSecondList[][2] = {
{1575, 1570}, {1575, 1573}
};
+/*
+ * Compositions matrix
+ */
+
static int compBothList[144][37] = {
{
8179, 8060, 974, 0, 8032, 0, 8033, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
diff --git a/src/stringprep/uni_parse2.tcl b/src/stringprep/uni_parse2.tcl
index 2f3ef7ecd..968f262b7 100644
--- a/src/stringprep/uni_parse2.tcl
+++ b/src/stringprep/uni_parse2.tcl
@@ -423,9 +423,8 @@ static unsigned char cclassPageMap\[\] = {"
puts $f "};
/*
- * The groupMap is indexed by combining the alternate page number with
- * the page offset and returns a group number that identifies a unique
- * set of character attributes.
+ * The cclassGroupMap is indexed by combining the alternate page number with
+ * the page offset and returns a combining class number.
*/
static unsigned char cclassGroupMap\[\] = {"
@@ -476,9 +475,9 @@ static unsigned char decompPageMap\[\] = {"
puts $f "};
/*
- * The groupMap is indexed by combining the alternate page number with
- * the page offset and returns a group number that identifies a unique
- * set of character attributes.
+ * The decompGroupMap is indexed by combining the alternate page number with
+ * the page offset and returns a group number that identifies a length and
+ * shift of decomposition sequence in decompList
*/
static int decompGroupMap\[\] = {"
@@ -502,7 +501,7 @@ static int decompGroupMap\[\] = {"
puts $f "};
/*
- * Each group represents a unique set of character attributes. The attributes...
+ * List of decomposition sequences
*/
static int decompList\[\] = {"
@@ -529,8 +528,6 @@ static int decompList\[\] = {"
* Unicode character tables.
*/
-//#define GetUniCharInfo(ch) (groups\[groupMap\[(pageMap\[(((int)(ch)) & 0xffff) >> CCLASS_OFFSET_BITS\] << CCLASS_OFFSET_BITS) | ((ch) & ((1 << CCLASS_OFFSET_BITS)-1))\]\])
-
#define GetUniCharDecompInfo(ch) (decompGroupMap\[(decompPageMap\[(((int)(ch)) & 0xffff) >> DECOMP_OFFSET_BITS\] << DECOMP_OFFSET_BITS) | ((ch) & ((1 << DECOMP_OFFSET_BITS)-1))\])
#define GetDecompShift(info) ((info) & 0xffff)
@@ -588,7 +585,7 @@ static int compGroupMap\[\] = {"
puts $f "};
/*
- * ...
+ * Lists of compositions for characters that appears only in one composition
*/
static int compFirstList\[\]\[2\] = {"
@@ -627,6 +624,10 @@ static int compSecondList\[\]\[2\] = {"
puts $f $line
puts $f "};
+/*
+ * Compositions matrix
+ */
+
static int compBothList\[[llength $comp_x_list]\]\[[llength $comp_y_list]\] = {"
set lastx [expr {[llength $comp_x_list] - 1}]
set lasty [expr {[llength $comp_y_list] - 1}]