mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-26 16:26:24 +01:00
Delete expat_erl, stringprep, xml and xml_stream; replaced by exmpp (EJAB-991)
SVN Revision: 2409
This commit is contained in:
parent
35c1c3774c
commit
f5868a0952
1
README
1
README
@ -8,7 +8,6 @@ Quickstart guide
|
||||
To compile ejabberd you need:
|
||||
- GNU Make
|
||||
- GCC
|
||||
- Libexpat 1.95 or higher
|
||||
- Erlang/OTP R12B-5. Support for R13 or higher is experimental.
|
||||
- exmpp 0.9.1 or higher
|
||||
- OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL
|
||||
|
@ -335,7 +335,6 @@ as long as your system have all the dependencies.</P><P> <A NAME="installreq"></
|
||||
</P><UL CLASS="itemize"><LI CLASS="li-itemize">
|
||||
GNU Make
|
||||
</LI><LI CLASS="li-itemize">GCC
|
||||
</LI><LI CLASS="li-itemize">Libexpat 1.95 or higher
|
||||
</LI><LI CLASS="li-itemize">Erlang/OTP R12B-5. Support for R13 or higher is experimental.
|
||||
</LI><LI CLASS="li-itemize">exmpp 0.9.1 or higher
|
||||
</LI><LI CLASS="li-itemize">OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended.
|
||||
|
@ -299,7 +299,6 @@ To compile \ejabberd{} on a `Unix-like' operating system, you need:
|
||||
\begin{itemize}
|
||||
\item GNU Make
|
||||
\item GCC
|
||||
\item Libexpat 1.95 or higher
|
||||
\item Erlang/OTP R12B-5. Support for R13 or higher is experimental.
|
||||
\item exmpp 0.9.1 or higher
|
||||
\item OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended.
|
||||
|
@ -63,8 +63,8 @@ endif
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
|
||||
SUBDIRS = @mod_pubsub@ @mod_muc@ @mod_proxy65@ @eldap@ @pam@ @web@ stringprep @tls@ @odbc@ @ejabberd_zlib@
|
||||
ERLSHLIBS = expat_erl.so
|
||||
SUBDIRS = @mod_pubsub@ @mod_muc@ @mod_proxy65@ @eldap@ @pam@ @web@ @tls@ @odbc@ @ejabberd_zlib@
|
||||
ERLSHLIBS =
|
||||
ERLBEHAVS = cyrsasl.erl gen_mod.erl p1_fsm.erl
|
||||
SOURCES_ALL = $(wildcard *.erl)
|
||||
SOURCES = $(filter-out $(ERLBEHAVS),$(SOURCES_ALL))
|
||||
|
494
src/configure
vendored
494
src/configure
vendored
@ -578,6 +578,7 @@ PACKAGE_VERSION='version'
|
||||
PACKAGE_STRING='ejabberd.erl version'
|
||||
PACKAGE_BUGREPORT='ejabberd@process-one.net'
|
||||
|
||||
ac_default_prefix=/
|
||||
# Factoring default headers for most tests.
|
||||
ac_includes_default="\
|
||||
#include <stdio.h>
|
||||
@ -614,7 +615,6 @@ ac_includes_default="\
|
||||
# include <unistd.h>
|
||||
#endif"
|
||||
|
||||
ac_default_prefix=/
|
||||
ac_subst_vars='SHELL
|
||||
PATH_SEPARATOR
|
||||
PACKAGE_NAME
|
||||
@ -669,8 +669,6 @@ ERLANG_EXMPP
|
||||
CPP
|
||||
GREP
|
||||
EGREP
|
||||
EXPAT_CFLAGS
|
||||
EXPAT_LIBS
|
||||
LIBOBJS
|
||||
mod_muc
|
||||
make_mod_muc
|
||||
@ -1311,7 +1309,6 @@ Optional Packages:
|
||||
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
|
||||
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
|
||||
--with-erlang=PREFIX path to erlc and erl
|
||||
--with-expat=PREFIX prefix where EXPAT is installed
|
||||
--with-zlib=PREFIX prefix where zlib is installed
|
||||
--with-pam=PREFIX prefix where PAM is installed
|
||||
--with-openssl=PREFIX prefix where OPENSSL is installed
|
||||
@ -3034,8 +3031,123 @@ echo "$as_me: error: erlang program was not properly executed, (conftest.out was
|
||||
|
||||
|
||||
|
||||
#locating libexpat
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
|
||||
{ echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
|
||||
echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_c_const+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
else
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
/* FIXME: Include the comments suggested by Paul. */
|
||||
#ifndef __cplusplus
|
||||
/* Ultrix mips cc rejects this. */
|
||||
typedef int charset[2];
|
||||
const charset cs;
|
||||
/* SunOS 4.1.1 cc rejects this. */
|
||||
char const *const *pcpcc;
|
||||
char **ppc;
|
||||
/* NEC SVR4.0.2 mips cc rejects this. */
|
||||
struct point {int x, y;};
|
||||
static struct point const zero = {0,0};
|
||||
/* AIX XL C 1.02.0.0 rejects this.
|
||||
It does not let you subtract one const X* pointer from another in
|
||||
an arm of an if-expression whose if-part is not a constant
|
||||
expression */
|
||||
const char *g = "string";
|
||||
pcpcc = &g + (g ? g-g : 0);
|
||||
/* HPUX 7.0 cc rejects these. */
|
||||
++pcpcc;
|
||||
ppc = (char**) pcpcc;
|
||||
pcpcc = (char const *const *) ppc;
|
||||
{ /* SCO 3.2v4 cc rejects this. */
|
||||
char *t;
|
||||
char const *s = 0 ? (char *) 0 : (char const *) 0;
|
||||
|
||||
*t++ = 0;
|
||||
if (s) return 0;
|
||||
}
|
||||
{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
|
||||
int x[] = {25, 17};
|
||||
const int *foo = &x[0];
|
||||
++foo;
|
||||
}
|
||||
{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
|
||||
typedef const int *iptr;
|
||||
iptr p = 0;
|
||||
++p;
|
||||
}
|
||||
{ /* AIX XL C 1.02.0.0 rejects this saying
|
||||
"k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
|
||||
struct s { int j; const int *ap[3]; };
|
||||
struct s *b; b->j = 5;
|
||||
}
|
||||
{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
|
||||
const int foo = 10;
|
||||
if (!foo) return 0;
|
||||
}
|
||||
return !cs[0] && !zero.x;
|
||||
#endif
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
rm -f conftest.$ac_objext
|
||||
if { (ac_try="$ac_compile"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_compile") 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } && {
|
||||
test -z "$ac_c_werror_flag" ||
|
||||
test ! -s conftest.err
|
||||
} && test -s conftest.$ac_objext; then
|
||||
ac_cv_c_const=yes
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
ac_cv_c_const=no
|
||||
fi
|
||||
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
fi
|
||||
{ echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5
|
||||
echo "${ECHO_T}$ac_cv_c_const" >&6; }
|
||||
if test $ac_cv_c_const = no; then
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define const
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Check Erlang headers are installed
|
||||
#AC_CHECK_HEADER(erl_driver.h,,[AC_MSG_ERROR([cannot find Erlang header files])])
|
||||
|
||||
# Change default prefix
|
||||
|
||||
|
||||
# Checks for library functions.
|
||||
ac_ext=c
|
||||
ac_cpp='$CPP $CPPFLAGS'
|
||||
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
|
||||
@ -3673,371 +3785,6 @@ done
|
||||
|
||||
|
||||
|
||||
# Check whether --with-expat was given.
|
||||
if test "${with_expat+set}" = set; then
|
||||
withval=$with_expat;
|
||||
fi
|
||||
|
||||
|
||||
EXPAT_CFLAGS=
|
||||
EXPAT_LIBS=
|
||||
if test x"$with_expat" != x; then
|
||||
EXPAT_CFLAGS="-I$with_expat/include"
|
||||
EXPAT_LIBS="-L$with_expat/lib"
|
||||
fi
|
||||
|
||||
{ echo "$as_me:$LINENO: checking for XML_ParserCreate in -lexpat" >&5
|
||||
echo $ECHO_N "checking for XML_ParserCreate in -lexpat... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_lib_expat_XML_ParserCreate+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lexpat "$EXPAT_LIBS" $LIBS"
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char XML_ParserCreate ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return XML_ParserCreate ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
rm -f conftest.$ac_objext conftest$ac_exeext
|
||||
if { (ac_try="$ac_link"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_link") 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } && {
|
||||
test -z "$ac_c_werror_flag" ||
|
||||
test ! -s conftest.err
|
||||
} && test -s conftest$ac_exeext &&
|
||||
$as_test_x conftest$ac_exeext; then
|
||||
ac_cv_lib_expat_XML_ParserCreate=yes
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
ac_cv_lib_expat_XML_ParserCreate=no
|
||||
fi
|
||||
|
||||
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ echo "$as_me:$LINENO: result: $ac_cv_lib_expat_XML_ParserCreate" >&5
|
||||
echo "${ECHO_T}$ac_cv_lib_expat_XML_ParserCreate" >&6; }
|
||||
if test $ac_cv_lib_expat_XML_ParserCreate = yes; then
|
||||
EXPAT_LIBS="$EXPAT_LIBS -lexpat"
|
||||
expat_found=yes
|
||||
else
|
||||
expat_found=no
|
||||
fi
|
||||
|
||||
if test $expat_found = no; then
|
||||
{ { echo "$as_me:$LINENO: error: Could not find development files of Expat library" >&5
|
||||
echo "$as_me: error: Could not find development files of Expat library" >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
fi
|
||||
expat_save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $EXPAT_CFLAGS"
|
||||
expat_save_CPPFLAGS="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $EXPAT_CFLAGS"
|
||||
|
||||
for ac_header in expat.h
|
||||
do
|
||||
as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||
if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
|
||||
{ echo "$as_me:$LINENO: checking for $ac_header" >&5
|
||||
echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
|
||||
if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
fi
|
||||
ac_res=`eval echo '${'$as_ac_Header'}'`
|
||||
{ echo "$as_me:$LINENO: result: $ac_res" >&5
|
||||
echo "${ECHO_T}$ac_res" >&6; }
|
||||
else
|
||||
# Is the header compilable?
|
||||
{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
|
||||
echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
$ac_includes_default
|
||||
#include <$ac_header>
|
||||
_ACEOF
|
||||
rm -f conftest.$ac_objext
|
||||
if { (ac_try="$ac_compile"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_compile") 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } && {
|
||||
test -z "$ac_c_werror_flag" ||
|
||||
test ! -s conftest.err
|
||||
} && test -s conftest.$ac_objext; then
|
||||
ac_header_compiler=yes
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
ac_header_compiler=no
|
||||
fi
|
||||
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
|
||||
echo "${ECHO_T}$ac_header_compiler" >&6; }
|
||||
|
||||
# Is the header present?
|
||||
{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
|
||||
echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
#include <$ac_header>
|
||||
_ACEOF
|
||||
if { (ac_try="$ac_cpp conftest.$ac_ext"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } >/dev/null && {
|
||||
test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
|
||||
test ! -s conftest.err
|
||||
}; then
|
||||
ac_header_preproc=yes
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
ac_header_preproc=no
|
||||
fi
|
||||
|
||||
rm -f conftest.err conftest.$ac_ext
|
||||
{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
|
||||
echo "${ECHO_T}$ac_header_preproc" >&6; }
|
||||
|
||||
# So? What about this header?
|
||||
case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
|
||||
yes:no: )
|
||||
{ echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
|
||||
echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
|
||||
echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
|
||||
ac_header_preproc=yes
|
||||
;;
|
||||
no:yes:* )
|
||||
{ echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
|
||||
echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
|
||||
echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
|
||||
echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
|
||||
echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
|
||||
echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
|
||||
echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
|
||||
( cat <<\_ASBOX
|
||||
## --------------------------------------- ##
|
||||
## Report this to ejabberd@process-one.net ##
|
||||
## --------------------------------------- ##
|
||||
_ASBOX
|
||||
) | sed "s/^/$as_me: WARNING: /" >&2
|
||||
;;
|
||||
esac
|
||||
{ echo "$as_me:$LINENO: checking for $ac_header" >&5
|
||||
echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
|
||||
if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
else
|
||||
eval "$as_ac_Header=\$ac_header_preproc"
|
||||
fi
|
||||
ac_res=`eval echo '${'$as_ac_Header'}'`
|
||||
{ echo "$as_me:$LINENO: result: $ac_res" >&5
|
||||
echo "${ECHO_T}$ac_res" >&6; }
|
||||
|
||||
fi
|
||||
if test `eval echo '${'$as_ac_Header'}'` = yes; then
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
|
||||
_ACEOF
|
||||
|
||||
else
|
||||
expat_found=no
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
if test $expat_found = no; then
|
||||
{ { echo "$as_me:$LINENO: error: Could not find expat.h" >&5
|
||||
echo "$as_me: error: Could not find expat.h" >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
fi
|
||||
CFLAGS="$expat_save_CFLAGS"
|
||||
CPPFLAGS="$expat_save_CPPFLAGS"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
{ echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
|
||||
echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_c_const+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
else
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
/* FIXME: Include the comments suggested by Paul. */
|
||||
#ifndef __cplusplus
|
||||
/* Ultrix mips cc rejects this. */
|
||||
typedef int charset[2];
|
||||
const charset cs;
|
||||
/* SunOS 4.1.1 cc rejects this. */
|
||||
char const *const *pcpcc;
|
||||
char **ppc;
|
||||
/* NEC SVR4.0.2 mips cc rejects this. */
|
||||
struct point {int x, y;};
|
||||
static struct point const zero = {0,0};
|
||||
/* AIX XL C 1.02.0.0 rejects this.
|
||||
It does not let you subtract one const X* pointer from another in
|
||||
an arm of an if-expression whose if-part is not a constant
|
||||
expression */
|
||||
const char *g = "string";
|
||||
pcpcc = &g + (g ? g-g : 0);
|
||||
/* HPUX 7.0 cc rejects these. */
|
||||
++pcpcc;
|
||||
ppc = (char**) pcpcc;
|
||||
pcpcc = (char const *const *) ppc;
|
||||
{ /* SCO 3.2v4 cc rejects this. */
|
||||
char *t;
|
||||
char const *s = 0 ? (char *) 0 : (char const *) 0;
|
||||
|
||||
*t++ = 0;
|
||||
if (s) return 0;
|
||||
}
|
||||
{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
|
||||
int x[] = {25, 17};
|
||||
const int *foo = &x[0];
|
||||
++foo;
|
||||
}
|
||||
{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
|
||||
typedef const int *iptr;
|
||||
iptr p = 0;
|
||||
++p;
|
||||
}
|
||||
{ /* AIX XL C 1.02.0.0 rejects this saying
|
||||
"k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
|
||||
struct s { int j; const int *ap[3]; };
|
||||
struct s *b; b->j = 5;
|
||||
}
|
||||
{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
|
||||
const int foo = 10;
|
||||
if (!foo) return 0;
|
||||
}
|
||||
return !cs[0] && !zero.x;
|
||||
#endif
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
rm -f conftest.$ac_objext
|
||||
if { (ac_try="$ac_compile"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_compile") 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } && {
|
||||
test -z "$ac_c_werror_flag" ||
|
||||
test ! -s conftest.err
|
||||
} && test -s conftest.$ac_objext; then
|
||||
ac_cv_c_const=yes
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
ac_cv_c_const=no
|
||||
fi
|
||||
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
fi
|
||||
{ echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5
|
||||
echo "${ECHO_T}$ac_cv_c_const" >&6; }
|
||||
if test $ac_cv_c_const = no; then
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define const
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Check Erlang headers are installed
|
||||
#AC_CHECK_HEADER(erl_driver.h,,[AC_MSG_ERROR([cannot find Erlang header files])])
|
||||
|
||||
# Change default prefix
|
||||
|
||||
|
||||
# Checks for library functions.
|
||||
|
||||
for ac_header in stdlib.h
|
||||
do
|
||||
as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||
@ -5226,7 +4973,7 @@ fi
|
||||
|
||||
|
||||
|
||||
ac_config_files="$ac_config_files Makefile $make_mod_muc $make_mod_pubsub $make_mod_proxy65 $make_eldap $make_pam $make_web stringprep/Makefile $make_tls $make_odbc $make_ejabberd_zlib"
|
||||
ac_config_files="$ac_config_files Makefile $make_mod_muc $make_mod_pubsub $make_mod_proxy65 $make_eldap $make_pam $make_web $make_tls $make_odbc $make_ejabberd_zlib"
|
||||
|
||||
#openssl
|
||||
|
||||
@ -6219,7 +5966,6 @@ do
|
||||
"$make_eldap") CONFIG_FILES="$CONFIG_FILES $make_eldap" ;;
|
||||
"$make_pam") CONFIG_FILES="$CONFIG_FILES $make_pam" ;;
|
||||
"$make_web") CONFIG_FILES="$CONFIG_FILES $make_web" ;;
|
||||
"stringprep/Makefile") CONFIG_FILES="$CONFIG_FILES stringprep/Makefile" ;;
|
||||
"$make_tls") CONFIG_FILES="$CONFIG_FILES $make_tls" ;;
|
||||
"$make_odbc") CONFIG_FILES="$CONFIG_FILES $make_odbc" ;;
|
||||
"$make_ejabberd_zlib") CONFIG_FILES="$CONFIG_FILES $make_ejabberd_zlib" ;;
|
||||
@ -6337,8 +6083,6 @@ ERLANG_EXMPP!$ERLANG_EXMPP$ac_delim
|
||||
CPP!$CPP$ac_delim
|
||||
GREP!$GREP$ac_delim
|
||||
EGREP!$EGREP$ac_delim
|
||||
EXPAT_CFLAGS!$EXPAT_CFLAGS$ac_delim
|
||||
EXPAT_LIBS!$EXPAT_LIBS$ac_delim
|
||||
LIBOBJS!$LIBOBJS$ac_delim
|
||||
mod_muc!$mod_muc$ac_delim
|
||||
make_mod_muc!$make_mod_muc$ac_delim
|
||||
@ -6373,7 +6117,7 @@ INSTALLUSER!$INSTALLUSER$ac_delim
|
||||
LTLIBOBJS!$LTLIBOBJS$ac_delim
|
||||
_ACEOF
|
||||
|
||||
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 88; then
|
||||
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 86; then
|
||||
break
|
||||
elif $ac_last_try; then
|
||||
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
|
||||
|
@ -14,8 +14,6 @@ fi
|
||||
|
||||
#locating erlang
|
||||
AM_WITH_ERLANG
|
||||
#locating libexpat
|
||||
AM_WITH_EXPAT
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
@ -98,7 +96,6 @@ AC_CONFIG_FILES([Makefile
|
||||
$make_eldap
|
||||
$make_pam
|
||||
$make_web
|
||||
stringprep/Makefile
|
||||
$make_tls
|
||||
$make_odbc
|
||||
$make_ejabberd_zlib])
|
||||
|
@ -99,19 +99,7 @@ init() ->
|
||||
LogPath = get_log_path(),
|
||||
error_logger:add_report_handler(ejabberd_logger_h, LogPath),
|
||||
erl_ddll:load_driver(ejabberd:get_so_path(), tls_drv),
|
||||
case erl_ddll:load_driver(ejabberd:get_so_path(), expat_erl) of
|
||||
ok -> ok;
|
||||
{error, already_loaded} -> ok
|
||||
end,
|
||||
Port = open_port({spawn, expat_erl}, [binary]),
|
||||
loop(Port).
|
||||
|
||||
|
||||
loop(Port) ->
|
||||
receive
|
||||
_ ->
|
||||
loop(Port)
|
||||
end.
|
||||
ok.
|
||||
|
||||
db_init() ->
|
||||
case mnesia:system_info(extra_db_nodes) of
|
||||
|
190
src/expat_erl.c
190
src/expat_erl.c
@ -1,190 +0,0 @@
|
||||
/*
|
||||
* ejabberd, Copyright (C) 2002-2009 ProcessOne
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <erl_driver.h>
|
||||
#include <ei.h>
|
||||
#include <expat.h>
|
||||
|
||||
|
||||
#define XML_START 0
|
||||
#define XML_END 1
|
||||
#define XML_CDATA 2
|
||||
#define XML_ERROR 3
|
||||
|
||||
#define PARSE_COMMAND 0
|
||||
#define PARSE_FINAL_COMMAND 1
|
||||
|
||||
ei_x_buff event_buf;
|
||||
|
||||
typedef struct {
|
||||
ErlDrvPort port;
|
||||
XML_Parser parser;
|
||||
} expat_data;
|
||||
|
||||
void *erlXML_StartElementHandler(expat_data *d,
|
||||
const XML_Char *name,
|
||||
const XML_Char **atts)
|
||||
{
|
||||
int i;
|
||||
|
||||
ei_x_encode_list_header(&event_buf, 1);
|
||||
ei_x_encode_tuple_header(&event_buf, 2);
|
||||
ei_x_encode_long(&event_buf, XML_START);
|
||||
ei_x_encode_tuple_header(&event_buf, 2);
|
||||
ei_x_encode_string(&event_buf, name);
|
||||
|
||||
for (i = 0; atts[i]; i += 2) {}
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
ei_x_encode_list_header(&event_buf, i/2);
|
||||
|
||||
for (i = 0; atts[i]; i += 2)
|
||||
{
|
||||
ei_x_encode_tuple_header(&event_buf, 2);
|
||||
ei_x_encode_string(&event_buf, atts[i]);
|
||||
ei_x_encode_string(&event_buf, atts[i+1]);
|
||||
}
|
||||
}
|
||||
|
||||
ei_x_encode_empty_list(&event_buf);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *erlXML_EndElementHandler(expat_data *d,
|
||||
const XML_Char *name)
|
||||
{
|
||||
ei_x_encode_list_header(&event_buf, 1);
|
||||
ei_x_encode_tuple_header(&event_buf, 2);
|
||||
ei_x_encode_long(&event_buf, XML_END);
|
||||
ei_x_encode_string(&event_buf, name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *erlXML_CharacterDataHandler(expat_data *d,
|
||||
const XML_Char *s,
|
||||
int len)
|
||||
{
|
||||
ei_x_encode_list_header(&event_buf, 1);
|
||||
ei_x_encode_tuple_header(&event_buf, 2);
|
||||
ei_x_encode_long(&event_buf, XML_CDATA);
|
||||
ei_x_encode_binary(&event_buf, s, len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static ErlDrvData expat_erl_start(ErlDrvPort port, char *buff)
|
||||
{
|
||||
expat_data* d = (expat_data*)driver_alloc(sizeof(expat_data));
|
||||
d->port = port;
|
||||
d->parser = XML_ParserCreate("UTF-8");
|
||||
XML_SetUserData(d->parser, d);
|
||||
|
||||
set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
|
||||
|
||||
XML_SetStartElementHandler(
|
||||
d->parser, (XML_StartElementHandler)erlXML_StartElementHandler);
|
||||
XML_SetEndElementHandler(
|
||||
d->parser, (XML_EndElementHandler)erlXML_EndElementHandler);
|
||||
XML_SetCharacterDataHandler(
|
||||
d->parser, (XML_CharacterDataHandler)erlXML_CharacterDataHandler);
|
||||
|
||||
|
||||
return (ErlDrvData)d;
|
||||
}
|
||||
|
||||
static void expat_erl_stop(ErlDrvData handle)
|
||||
{
|
||||
XML_ParserFree(((expat_data *)handle)->parser);
|
||||
driver_free((char*)handle);
|
||||
}
|
||||
|
||||
static int expat_erl_control(ErlDrvData drv_data,
|
||||
unsigned int command,
|
||||
char *buf, int len,
|
||||
char **rbuf, int rlen)
|
||||
{
|
||||
expat_data* d = (expat_data*)drv_data;
|
||||
int res, errcode;
|
||||
char *errstring;
|
||||
ErlDrvBinary *b;
|
||||
size_t size;
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case PARSE_COMMAND:
|
||||
case PARSE_FINAL_COMMAND:
|
||||
ei_x_new_with_version(&event_buf);
|
||||
res = XML_Parse(d->parser, buf, len, command == PARSE_FINAL_COMMAND);
|
||||
|
||||
if(!res)
|
||||
{
|
||||
errcode = XML_GetErrorCode(d->parser);
|
||||
errstring = (char *)XML_ErrorString(errcode);
|
||||
|
||||
ei_x_encode_list_header(&event_buf, 1);
|
||||
ei_x_encode_tuple_header(&event_buf, 2);
|
||||
ei_x_encode_long(&event_buf, XML_ERROR);
|
||||
ei_x_encode_tuple_header(&event_buf, 2);
|
||||
ei_x_encode_long(&event_buf, errcode);
|
||||
ei_x_encode_string(&event_buf, errstring);
|
||||
}
|
||||
|
||||
ei_x_encode_empty_list(&event_buf);
|
||||
|
||||
size = event_buf.index;
|
||||
|
||||
b = driver_alloc_binary(size);
|
||||
memcpy(b->orig_bytes, event_buf.buff, size);
|
||||
|
||||
ei_x_free(&event_buf);
|
||||
|
||||
*rbuf = (char *)b;
|
||||
return size;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ErlDrvEntry expat_driver_entry = {
|
||||
NULL, /* F_PTR init, N/A */
|
||||
expat_erl_start, /* L_PTR start, called when port is opened */
|
||||
expat_erl_stop, /* F_PTR stop, called when port is closed */
|
||||
NULL, /* F_PTR output, called when erlang has sent */
|
||||
NULL, /* F_PTR ready_input, called when input descriptor ready */
|
||||
NULL, /* F_PTR ready_output, called when output descriptor ready */
|
||||
"expat_erl", /* char *driver_name, the argument to open_port */
|
||||
NULL, /* F_PTR finish, called when unloaded */
|
||||
NULL, /* handle */
|
||||
expat_erl_control, /* F_PTR control, port_command callback */
|
||||
NULL, /* F_PTR timeout, reserved */
|
||||
NULL /* F_PTR outputv, reserved */
|
||||
};
|
||||
|
||||
DRIVER_INIT(expat_erl) /* must match name in driver_entry */
|
||||
{
|
||||
return &expat_driver_entry;
|
||||
}
|
||||
|
||||
|
@ -566,7 +566,7 @@ get_user_list(_, User, Server)
|
||||
%% If Dir = in, User@Server is the destination account (To).
|
||||
check_packet(_, User, Server,
|
||||
#userlist{list = List, needdb = NeedDb},
|
||||
{From, To, #xmlel{name = PName, attrs = Attrs}},
|
||||
{From, To, #xmlel{name = PName} = El},
|
||||
Dir) when
|
||||
PName =:= message ;
|
||||
PName =:= iq ;
|
||||
@ -579,7 +579,7 @@ check_packet(_, User, Server,
|
||||
'message' -> message;
|
||||
'iq' -> iq;
|
||||
'presence' ->
|
||||
case xml:get_attr_s("type", Attrs) of
|
||||
case exmpp_xml:get_attribute(El, type, '') of
|
||||
%% notification
|
||||
'' -> presence;
|
||||
'unavailable' -> presence;
|
||||
|
@ -1,60 +0,0 @@
|
||||
# $Id$
|
||||
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBS = @LIBS@
|
||||
|
||||
ERLANG_CFLAGS = @ERLANG_CFLAGS@
|
||||
ERLANG_LIBS = @ERLANG_LIBS@
|
||||
|
||||
# Assume Linux-style dynamic library flags
|
||||
DYNAMIC_LIB_CFLAGS = -fpic -shared
|
||||
ifeq ($(shell uname),Darwin)
|
||||
DYNAMIC_LIB_CFLAGS = -fPIC -bundle -flat_namespace -undefined suppress
|
||||
endif
|
||||
ifeq ($(shell uname),SunOs)
|
||||
DYNAMIC_LIB_CFLAGS = -KPIC -G -z text
|
||||
endif
|
||||
|
||||
|
||||
EFLAGS += -I ..
|
||||
EFLAGS += -pz ..
|
||||
|
||||
# make debug=true to compile Erlang module with debug informations.
|
||||
ifdef debug
|
||||
EFLAGS+=+debug_info
|
||||
endif
|
||||
|
||||
ERLSHLIBS = ../stringprep_drv.so
|
||||
OUTDIR = ..
|
||||
SOURCES = $(wildcard *.erl)
|
||||
BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam))
|
||||
|
||||
|
||||
all: $(BEAMS) $(ERLSHLIBS)
|
||||
|
||||
$(OUTDIR)/%.beam: %.erl
|
||||
@ERLC@ -W $(EFLAGS) -o $(OUTDIR) $<
|
||||
|
||||
#all: $(ERLSHLIBS)
|
||||
# erl -s make all report "{outdir, \"..\"}" -noinput -s erlang halt
|
||||
|
||||
$(ERLSHLIBS): ../%.so: %.c uni_data.c uni_norm.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(INCLUDES) \
|
||||
$(subst ../,,$(subst .so,.c,$@)) $(LIBS) \
|
||||
$(ERLANG_LIBS) \
|
||||
$(ERLANG_CFLAGS) \
|
||||
-o $@ \
|
||||
$(DYNAMIC_LIB_CFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f $(BEAMS) $(ERLSHLIBS)
|
||||
|
||||
distclean: clean
|
||||
rm -f Makefile
|
||||
|
||||
TAGS:
|
||||
etags *.erl
|
||||
|
@ -1,40 +0,0 @@
|
||||
|
||||
include ..\Makefile.inc
|
||||
|
||||
EFLAGS = -I .. -pz ..
|
||||
|
||||
OUTDIR = ..
|
||||
BEAMS = ..\stringprep.beam ..\stringprep_sup.beam
|
||||
|
||||
SOURCE = stringprep_drv.c
|
||||
AUXIL = uni_data.c uni_norm.c
|
||||
OBJECT = stringprep_drv.o
|
||||
DLL = $(OUTDIR)\stringprep_drv.dll
|
||||
|
||||
ALL : $(DLL) $(BEAMS)
|
||||
|
||||
CLEAN :
|
||||
-@erase $(DLL)
|
||||
-@erase $(OUTDIR)\stringprep_drv.exp
|
||||
-@erase $(OUTDIR)\stringprep_drv.lib
|
||||
-@erase $(OBJECT)
|
||||
-@erase $(BEAMS)
|
||||
|
||||
$(OUTDIR)\stringprep.beam : stringprep.erl
|
||||
erlc -W $(EFLAGS) -o $(OUTDIR) stringprep.erl
|
||||
|
||||
$(OUTDIR)\stringprep_sup.beam : stringprep_sup.erl
|
||||
erlc -W $(EFLAGS) -o $(OUTDIR) stringprep_sup.erl
|
||||
|
||||
CC=cl.exe
|
||||
CC_FLAGS=-nologo -D__WIN32__ -DWIN32 -DWINDOWS -D_WIN32 -DNT -MD -Ox -I"$(ERLANG_DIR)\usr\include" -I"$(EI_DIR)\include"
|
||||
|
||||
LD=link.exe
|
||||
LD_FLAGS=-release -nologo -incremental:no -dll "$(EI_DIR)\lib\ei_md.lib" "$(EI_DIR)\lib\erl_interface_md.lib" MSVCRT.LIB kernel32.lib advapi32.lib gdi32.lib user32.lib comctl32.lib comdlg32.lib shell32.lib
|
||||
|
||||
$(DLL) : $(OBJECT)
|
||||
$(LD) $(LD_FLAGS) -out:$(DLL) $(OBJECT)
|
||||
|
||||
$(OBJECT) : $(SOURCE) $(AUXIL)
|
||||
$(CC) $(CC_FLAGS) -c -Fo$(OBJECT) $(SOURCE)
|
||||
|
@ -1,113 +0,0 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : stringprep.erl
|
||||
%%% Author : Alexey Shchepin <alexey@process-one.net>
|
||||
%%% Purpose : Interface to stringprep_drv
|
||||
%%% Created : 16 Feb 2003 by Alexey Shchepin <alexey@proces-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
%%% 02111-1307 USA
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-module(stringprep).
|
||||
-author('alexey@process-one.net').
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
||||
-export([start/0, start_link/0,
|
||||
tolower/1,
|
||||
nameprep/1,
|
||||
nodeprep/1,
|
||||
resourceprep/1]).
|
||||
|
||||
%% Internal exports, call-back functions.
|
||||
-export([init/1,
|
||||
handle_call/3,
|
||||
handle_cast/2,
|
||||
handle_info/2,
|
||||
code_change/3,
|
||||
terminate/2]).
|
||||
|
||||
-define(STRINGPREP_PORT, stringprep_port).
|
||||
|
||||
-define(NAMEPREP_COMMAND, 1).
|
||||
-define(NODEPREP_COMMAND, 2).
|
||||
-define(RESOURCEPREP_COMMAND, 3).
|
||||
|
||||
start() ->
|
||||
gen_server:start({local, ?MODULE}, ?MODULE, [], []).
|
||||
|
||||
start_link() ->
|
||||
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
||||
|
||||
init([]) ->
|
||||
case erl_ddll:load_driver(ejabberd:get_so_path(), stringprep_drv) of
|
||||
ok -> ok;
|
||||
{error, already_loaded} -> ok
|
||||
end,
|
||||
Port = open_port({spawn, stringprep_drv}, []),
|
||||
register(?STRINGPREP_PORT, Port),
|
||||
{ok, Port}.
|
||||
|
||||
|
||||
%%% --------------------------------------------------------
|
||||
%%% The call-back functions.
|
||||
%%% --------------------------------------------------------
|
||||
|
||||
handle_call(_, _, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
handle_cast(_, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
handle_info({'EXIT', Port, Reason}, Port) ->
|
||||
{stop, {port_died, Reason}, Port};
|
||||
handle_info({'EXIT', _Pid, _Reason}, Port) ->
|
||||
{noreply, Port};
|
||||
handle_info(_, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
terminate(_Reason, Port) ->
|
||||
Port ! {self, close},
|
||||
ok.
|
||||
|
||||
|
||||
|
||||
tolower(String) ->
|
||||
control(0, String).
|
||||
|
||||
nameprep(String) ->
|
||||
control(?NAMEPREP_COMMAND, String).
|
||||
|
||||
nodeprep(String) ->
|
||||
control(?NODEPREP_COMMAND, String).
|
||||
|
||||
resourceprep(String) ->
|
||||
control(?RESOURCEPREP_COMMAND, String).
|
||||
|
||||
control(Command, String) ->
|
||||
case port_control(?STRINGPREP_PORT, Command, String) of
|
||||
[0 | _] -> error;
|
||||
[1 | Res] -> Res
|
||||
end.
|
||||
|
||||
|
||||
|
@ -1,410 +0,0 @@
|
||||
/*
|
||||
* ejabberd, Copyright (C) 2002-2009 ProcessOne
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <erl_driver.h>
|
||||
#include <ei.h>
|
||||
|
||||
#include "uni_data.c"
|
||||
#include "uni_norm.c"
|
||||
|
||||
#define NAMEPREP_COMMAND 1
|
||||
#define NODEPREP_COMMAND 2
|
||||
#define RESOURCEPREP_COMMAND 3
|
||||
|
||||
typedef struct {
|
||||
ErlDrvPort port;
|
||||
} stringprep_data;
|
||||
|
||||
|
||||
static ErlDrvData stringprep_erl_start(ErlDrvPort port, char *buff)
|
||||
{
|
||||
stringprep_data* d = (stringprep_data*)driver_alloc(sizeof(stringprep_data));
|
||||
d->port = port;
|
||||
|
||||
//set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
|
||||
|
||||
return (ErlDrvData)d;
|
||||
}
|
||||
|
||||
static void stringprep_erl_stop(ErlDrvData handle)
|
||||
{
|
||||
driver_free((char*)handle);
|
||||
}
|
||||
|
||||
|
||||
/* Hangul constants */
|
||||
#define SBase 0xAC00
|
||||
#define LBase 0x1100
|
||||
#define VBase 0x1161
|
||||
#define TBase 0x11A7
|
||||
#define LCount 19
|
||||
#define VCount 21
|
||||
#define TCount 28
|
||||
#define NCount (VCount * TCount)
|
||||
#define SCount (LCount * NCount)
|
||||
|
||||
/*
|
||||
* "canonical_ordering" and "compose" functions are based on nfkc.c from Gnome
|
||||
* library
|
||||
*/
|
||||
|
||||
static void canonical_ordering(int *str, int len)
|
||||
{
|
||||
int i, j, t;
|
||||
int last, next;
|
||||
|
||||
last = GetUniCharCClass(str[0]);
|
||||
for (i = 0; i < len - 1; i++)
|
||||
{
|
||||
next = GetUniCharCClass(str[i + 1]);
|
||||
if (next != 0 && last > next)
|
||||
{
|
||||
for (j = i; j >= 0; j--)
|
||||
{
|
||||
if (GetUniCharCClass(str[j]) <= next)
|
||||
break;
|
||||
t = str[j + 1];
|
||||
str[j + 1] = str[j];
|
||||
str[j] = t;
|
||||
}
|
||||
next = last;
|
||||
}
|
||||
last = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int compose(int ch1, int ch2)
|
||||
{
|
||||
int info1, info2;
|
||||
|
||||
if (LBase <= ch1 && ch1 < LBase + LCount &&
|
||||
VBase <= ch2 && ch2 < VBase + VCount) {
|
||||
return SBase + ((ch1 - LBase) * VCount + (ch2 - VBase)) * TCount;
|
||||
}
|
||||
|
||||
if (SBase <= ch1 && ch1 < SBase + SCount && ((ch1 - SBase) % TCount) == 0 &&
|
||||
TBase <= ch2 && ch2 < TBase + TCount) {
|
||||
return ch1 + ch2 - TBase;
|
||||
}
|
||||
|
||||
info1 = GetUniCharCompInfo(ch1);
|
||||
if (info1 != -1 && info1 & CompSingleMask) {
|
||||
if (!(info1 & CompSecondMask) &&
|
||||
ch2 == compFirstList[info1 & CompMask][0]) {
|
||||
return compFirstList[info1 & CompMask][1];
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
info2 = GetUniCharCompInfo(ch2);
|
||||
if (info2 != -1 && info2 & CompSingleMask) {
|
||||
if ((info2 & CompSecondMask) &&
|
||||
ch1 == compSecondList[info2 & CompMask][0]) {
|
||||
return compSecondList[info2 & CompMask][1];
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info1 != -1 && info2 != -1 &&
|
||||
!(info1 & CompSecondMask) && (info2 & CompSecondMask))
|
||||
return compBothList[info1][info2 & CompMask];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define ADD_UCHAR(ruc) \
|
||||
if (ruc <= 0x7F) { \
|
||||
if (pos >= size) { \
|
||||
size = 2*size + 1; \
|
||||
rstring = driver_realloc(rstring, size); \
|
||||
} \
|
||||
rstring[pos] = (char) ruc; \
|
||||
pos++; \
|
||||
} else if (ruc <= 0x7FF) { \
|
||||
if (pos + 1 >= size) { \
|
||||
size = 2*size + 2; \
|
||||
rstring = driver_realloc(rstring, size); \
|
||||
} \
|
||||
rstring[pos] = (char) ((ruc >> 6) | 0xC0); \
|
||||
rstring[pos+1] = (char) ((ruc | 0x80) & 0xBF); \
|
||||
pos += 2; \
|
||||
} else if (ruc <= 0xFFFF) { \
|
||||
if (pos + 2 >= size) { \
|
||||
size = 2*size + 3; \
|
||||
rstring = driver_realloc(rstring, size); \
|
||||
} \
|
||||
rstring[pos] = (char) ((ruc >> 12) | 0xE0); \
|
||||
rstring[pos+1] = (char) (((ruc >> 6) | 0x80) & 0xBF); \
|
||||
rstring[pos+2] = (char) ((ruc | 0x80) & 0xBF); \
|
||||
pos += 3; \
|
||||
} else if (ruc <= 0x1FFFFF) { \
|
||||
if (pos + 3 >= size) { \
|
||||
size = 2*size + 4; \
|
||||
rstring = driver_realloc(rstring, size); \
|
||||
} \
|
||||
rstring[pos] = (char) ((ruc >> 18) | 0xF0); \
|
||||
rstring[pos+1] = (char) (((ruc >> 12) | 0x80) & 0xBF); \
|
||||
rstring[pos+2] = (char) (((ruc >> 6) | 0x80) & 0xBF); \
|
||||
rstring[pos+3] = (char) ((ruc | 0x80) & 0xBF); \
|
||||
pos += 4; \
|
||||
}
|
||||
|
||||
#define ADD_UCHAR32(str, pos, len, ch) \
|
||||
if (pos >= len) { \
|
||||
len = 2*len + 1; \
|
||||
str = driver_realloc(str, len * sizeof(int)); \
|
||||
} \
|
||||
str[pos] = ch; \
|
||||
pos++;
|
||||
|
||||
|
||||
#define 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); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int stringprep_erl_control(ErlDrvData drv_data,
|
||||
unsigned int command,
|
||||
char *buf, int len,
|
||||
char **rbuf, int rlen)
|
||||
{
|
||||
int i, j, pos=1;
|
||||
unsigned char c;
|
||||
int bad = 0;
|
||||
int uc = 0, ruc;
|
||||
int size;
|
||||
int info;
|
||||
int prohibit = 0, tolower = 0;
|
||||
char *rstring;
|
||||
int *mc;
|
||||
int *str32;
|
||||
int str32len, str32pos = 0;
|
||||
int decomp_len, decomp_shift;
|
||||
int comp_pos, comp_starter_pos;
|
||||
int cclass_prev, cclass2;
|
||||
int ch1, ch2;
|
||||
int first_ral, last_ral, have_ral, have_l;
|
||||
|
||||
size = len + 1;
|
||||
|
||||
rstring = driver_alloc(size);
|
||||
rstring[0] = 0;
|
||||
|
||||
str32len = len + 1;
|
||||
|
||||
str32 = driver_alloc(str32len * sizeof(int));
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case 0:
|
||||
prohibit = ACMask;
|
||||
tolower = 1;
|
||||
break;
|
||||
|
||||
case NAMEPREP_COMMAND:
|
||||
prohibit = ACMask;
|
||||
tolower = 1;
|
||||
break;
|
||||
|
||||
case NODEPREP_COMMAND:
|
||||
prohibit = ACMask | C11Mask | C21Mask | XNPMask;
|
||||
tolower = 1;
|
||||
break;
|
||||
|
||||
case RESOURCEPREP_COMMAND:
|
||||
prohibit = ACMask | C21Mask;
|
||||
tolower = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
c = buf[i];
|
||||
if (c < 0x80) {
|
||||
uc = c;
|
||||
} else if (c < 0xC0) {
|
||||
bad = 1;
|
||||
} else if (c < 0xE0) {
|
||||
if (i+1 < len && (buf[i+1] & 0xC0) == 0x80) {
|
||||
uc = ((c & 0x1F) << 6) | (buf[i+1] & 0x3F);
|
||||
i++;
|
||||
} else {
|
||||
bad = 1;
|
||||
}
|
||||
} else if (c < 0xF0) {
|
||||
if (i+2 < len && (buf[i+1] & 0xC0) == 0x80 &&
|
||||
(buf[i+2] & 0xC0) == 0x80) {
|
||||
uc = ((c & 0x0F) << 12)
|
||||
| ((buf[i+1] & 0x3F) << 6)
|
||||
| (buf[i+2] & 0x3F);
|
||||
i += 2;
|
||||
} else {
|
||||
bad = 1;
|
||||
}
|
||||
} else if (c < 0xF8) {
|
||||
if (i+3 < len &&
|
||||
(buf[i+1] & 0xC0) == 0x80 &&
|
||||
(buf[i+2] & 0xC0) == 0x80 &&
|
||||
(buf[i+3] & 0xC0) == 0x80) {
|
||||
uc = ((c & 0x07) << 18)
|
||||
| ((buf[i+1] & 0x3F) << 12)
|
||||
| ((buf[i+2] & 0x3F) << 6)
|
||||
| (buf[i+3] & 0x3F);
|
||||
i += 3;
|
||||
if (uc > 0x10FFFF)
|
||||
bad = 1;
|
||||
} else {
|
||||
bad = 1;
|
||||
}
|
||||
} else {
|
||||
bad = 1;
|
||||
}
|
||||
|
||||
if (bad) {
|
||||
*rbuf = rstring;
|
||||
driver_free(str32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
info = GetUniCharInfo(uc);
|
||||
|
||||
if (!(info & B1Mask))
|
||||
{
|
||||
if (tolower) {
|
||||
if (!(info & MCMask))
|
||||
{
|
||||
ruc = uc + GetDelta(info);
|
||||
ADD_DECOMP(ruc);
|
||||
} else {
|
||||
mc = GetMC(info);
|
||||
for (j = 1; j <= mc[0]; j++) {
|
||||
ruc = mc[j];
|
||||
ADD_DECOMP(ruc);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ruc = uc;
|
||||
ADD_DECOMP(ruc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (str32pos == 0) {
|
||||
rstring[0] = 1;
|
||||
*rbuf = rstring;
|
||||
driver_free(str32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
canonical_ordering(str32, str32pos);
|
||||
|
||||
comp_pos = 1;
|
||||
comp_starter_pos = 0;
|
||||
ch1 = str32[0];
|
||||
cclass_prev = GetUniCharCClass(ch1);
|
||||
for (i = 1; i < str32pos; i++)
|
||||
{
|
||||
ch2 = str32[i];
|
||||
cclass2 = GetUniCharCClass(ch2);
|
||||
if ((cclass_prev == 0 || cclass2 > cclass_prev) &&
|
||||
(ruc = compose(ch1, ch2))) {
|
||||
ch1 = ruc;
|
||||
} else {
|
||||
if (cclass2 == 0) {
|
||||
str32[comp_starter_pos] = ch1;
|
||||
comp_starter_pos = comp_pos++;
|
||||
ch1 = ch2;
|
||||
cclass_prev = 0;
|
||||
} else {
|
||||
str32[comp_pos++] = ch2;
|
||||
cclass_prev = cclass2;
|
||||
}
|
||||
}
|
||||
}
|
||||
str32[comp_starter_pos] = ch1;
|
||||
str32pos = comp_pos;
|
||||
|
||||
last_ral = have_ral = have_l = 0;
|
||||
info = GetUniCharInfo(str32[0]);
|
||||
first_ral = info & D1Mask;
|
||||
for (i = 0; i < str32pos; i++)
|
||||
{
|
||||
ruc = str32[i];
|
||||
info = GetUniCharInfo(ruc);
|
||||
if (info & prohibit) {
|
||||
*rbuf = rstring;
|
||||
driver_free(str32);
|
||||
return 1;
|
||||
}
|
||||
last_ral = info & D1Mask;
|
||||
have_ral = have_ral || last_ral;
|
||||
have_l = info & D2Mask;
|
||||
ADD_UCHAR(ruc);
|
||||
}
|
||||
|
||||
if (have_ral && (!first_ral || !last_ral || have_l)) {
|
||||
*rbuf = rstring;
|
||||
driver_free(str32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rstring[0] = 1;
|
||||
*rbuf = rstring;
|
||||
driver_free(str32);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ErlDrvEntry stringprep_driver_entry = {
|
||||
NULL, /* F_PTR init, N/A */
|
||||
stringprep_erl_start, /* L_PTR start, called when port is opened */
|
||||
stringprep_erl_stop, /* F_PTR stop, called when port is closed */
|
||||
NULL, /* F_PTR output, called when erlang has sent */
|
||||
NULL, /* F_PTR ready_input, called when input descriptor ready */
|
||||
NULL, /* F_PTR ready_output, called when output descriptor ready */
|
||||
"stringprep_drv", /* char *driver_name, the argument to open_port */
|
||||
NULL, /* F_PTR finish, called when unloaded */
|
||||
NULL, /* handle */
|
||||
stringprep_erl_control, /* F_PTR control, port_command callback */
|
||||
NULL, /* F_PTR timeout, reserved */
|
||||
NULL /* F_PTR outputv, reserved */
|
||||
};
|
||||
|
||||
DRIVER_INIT(stringprep_erl) /* must match name in driver_entry */
|
||||
{
|
||||
return &stringprep_driver_entry;
|
||||
}
|
||||
|
@ -1,68 +0,0 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% File : stringprep_sup.erl
|
||||
%%% Author : Mickael Remond <mremond@process-one.net>
|
||||
%%% Description : Supervisor for the Stringprep worker.
|
||||
%%% Created : 29 Jun 2007 by Mickael Remond <mremond@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
%%% 02111-1307 USA
|
||||
%%%
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
-module(stringprep_sup).
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
||||
%% API
|
||||
-export([start_link/0]).
|
||||
|
||||
%% Supervisor callbacks
|
||||
-export([init/1]).
|
||||
|
||||
-define(SERVER, ?MODULE).
|
||||
|
||||
%%====================================================================
|
||||
%% API functions
|
||||
%%====================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
|
||||
%% Description: Starts the supervisor
|
||||
%%--------------------------------------------------------------------
|
||||
start_link() ->
|
||||
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
|
||||
|
||||
%%====================================================================
|
||||
%% Supervisor callbacks
|
||||
%%====================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Func: init(Args) -> {ok, {SupFlags, [ChildSpec]}} |
|
||||
%% ignore |
|
||||
%% {error, Reason}
|
||||
%% Description: Whenever a supervisor is started using
|
||||
%% supervisor:start_link/[2,3], this function is called by the new process
|
||||
%% to find out about restart strategy, maximum restart frequency and child
|
||||
%% specifications.
|
||||
%%--------------------------------------------------------------------
|
||||
init([]) ->
|
||||
StringPrep = {stringprep,
|
||||
{stringprep, start_link, []},
|
||||
permanent,
|
||||
brutal_kill,
|
||||
worker,
|
||||
[stringprep]},
|
||||
{ok,{{one_for_all,10,1}, [StringPrep]}}.
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,437 +0,0 @@
|
||||
# uni_parse.tcl --
|
||||
#
|
||||
# This program parses the UnicodeData file and generates the
|
||||
# corresponding uni_data.c file with compressed character
|
||||
# data tables. The input to this program should be rfc3454.txt
|
||||
#
|
||||
# Copyright (c) 1998-1999 by Scriptics Corporation.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Modified for ejabberd by Alexey Shchepin
|
||||
#
|
||||
# RCS: @(#) $Id$
|
||||
|
||||
|
||||
namespace eval uni {
|
||||
set shift 8; # number of bits of data within a page
|
||||
# This value can be adjusted to find the
|
||||
# best split to minimize table size
|
||||
|
||||
variable pMap; # map from page to page index, each entry is
|
||||
# an index into the pages table, indexed by
|
||||
# page number
|
||||
variable pages; # map from page index to page info, each
|
||||
# entry is a list of indices into the groups
|
||||
# table, the list is indexed by the offset
|
||||
variable groups; # list of character info values, indexed by
|
||||
# group number, initialized with the
|
||||
# unassigned character group
|
||||
}
|
||||
|
||||
proc uni::getValue {i} {
|
||||
variable casemap
|
||||
variable casemap2
|
||||
variable tablemap
|
||||
|
||||
if {[info exists tablemap($i)]} {
|
||||
set tables $tablemap($i)
|
||||
} else {
|
||||
set tables {}
|
||||
}
|
||||
|
||||
if {[info exists casemap2($i)]} {
|
||||
set multicase 1
|
||||
set delta $casemap2($i)
|
||||
} else {
|
||||
set multicase 0
|
||||
if {[info exists casemap($i)]} {
|
||||
set delta $casemap($i)
|
||||
} else {
|
||||
set delta 0
|
||||
}
|
||||
}
|
||||
|
||||
if {abs($delta) > 0xFFFFF} {
|
||||
puts "delta must be less than 22 bits wide"
|
||||
exit
|
||||
}
|
||||
|
||||
set ac 0
|
||||
set c11 0
|
||||
set c21 0
|
||||
set b1 0
|
||||
set d1 0
|
||||
set d2 0
|
||||
set xnp 0
|
||||
|
||||
foreach tab $tables {
|
||||
switch -glob -- $tab {
|
||||
C.1.1 {set c11 1}
|
||||
C.2.1 {set c21 1}
|
||||
C.* {set ac 1}
|
||||
A.1 {set ac 1}
|
||||
B.1 {set b1 1}
|
||||
D.1 {set d1 1}
|
||||
D.2 {set d2 1}
|
||||
XNP {set xnp 1}
|
||||
}
|
||||
}
|
||||
|
||||
set val [expr {($ac << 0) |
|
||||
($c11 << 1) |
|
||||
($c21 << 2) |
|
||||
($b1 << 3) |
|
||||
($d1 << 4) |
|
||||
($d2 << 5) |
|
||||
($xnp << 6) |
|
||||
($multicase << 7) |
|
||||
($delta << 11)}]
|
||||
|
||||
return $val
|
||||
}
|
||||
|
||||
proc uni::getGroup {value} {
|
||||
variable groups
|
||||
|
||||
set gIndex [lsearch -exact $groups $value]
|
||||
if {$gIndex == -1} {
|
||||
set gIndex [llength $groups]
|
||||
lappend groups $value
|
||||
}
|
||||
return $gIndex
|
||||
}
|
||||
|
||||
proc uni::addPage {info} {
|
||||
variable pMap
|
||||
variable pages
|
||||
variable pages_map
|
||||
|
||||
if {[info exists pages_map($info)]} {
|
||||
lappend pMap $pages_map($info)
|
||||
} else {
|
||||
set pIndex [llength $pages]
|
||||
lappend pages $info
|
||||
set pages_map($info) $pIndex
|
||||
lappend pMap $pIndex
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
proc uni::load_tables {data} {
|
||||
variable casemap
|
||||
variable casemap2
|
||||
variable multicasemap
|
||||
variable tablemap
|
||||
|
||||
set multicasemap {}
|
||||
set table ""
|
||||
|
||||
foreach line [split $data \n] {
|
||||
if {$table == ""} {
|
||||
if {[regexp { ----- Start Table (.*) -----} $line temp table]} {
|
||||
#puts "Start table '$table'"
|
||||
}
|
||||
} else {
|
||||
if {[regexp { ----- End Table (.*) -----} $line temp table1]} {
|
||||
set table ""
|
||||
} else {
|
||||
if {$table == "B.1"} {
|
||||
if {[regexp {^ ([[:xdigit:]]+); ;} $line \
|
||||
temp val]} {
|
||||
scan $val %x val
|
||||
if {$val <= 0x10ffff} {
|
||||
lappend tablemap($val) $table
|
||||
}
|
||||
}
|
||||
} elseif {$table == "B.2"} {
|
||||
if {[regexp {^ ([[:xdigit:]]+); ([[:xdigit:]]+);} $line \
|
||||
temp from to]} {
|
||||
scan $from %x from
|
||||
scan $to %x to
|
||||
if {$from <= 0x10ffff && $to <= 0x10ffff} {
|
||||
set casemap($from) [expr {$to - $from}]
|
||||
}
|
||||
} elseif {[regexp {^ ([[:xdigit:]]+); ([[:xdigit:]]+) ([[:xdigit:]]+);} $line \
|
||||
temp from to1 to2]} {
|
||||
scan $from %x from
|
||||
scan $to1 %x to1
|
||||
scan $to2 %x to2
|
||||
if {$from <= 0x10ffff && \
|
||||
$to1 <= 0x10ffff && $to2 <= 0x10ffff} {
|
||||
set casemap2($from) [llength $multicasemap]
|
||||
lappend multicasemap [list $to1 $to2]
|
||||
}
|
||||
} elseif {[regexp {^ ([[:xdigit:]]+); ([[:xdigit:]]+) ([[:xdigit:]]+) ([[:xdigit:]]+);} $line \
|
||||
temp from to1 to2 to3]} {
|
||||
scan $from %x from
|
||||
scan $to1 %x to1
|
||||
scan $to2 %x to2
|
||||
scan $to3 %x to3
|
||||
if {$from <= 0x10ffff && \
|
||||
$to1 <= 0x10ffff && $to2 <= 0x10ffff && \
|
||||
$to3 <= 0x10ffff} {
|
||||
set casemap2($from) [llength $multicasemap]
|
||||
lappend multicasemap [list $to1 $to2 $to3]
|
||||
}
|
||||
} else {
|
||||
#puts "missed: $line"
|
||||
}
|
||||
|
||||
} elseif {$table != "B.3"} {
|
||||
if {[regexp {^ ([[:xdigit:]]+)-([[:xdigit:]]+)} $line \
|
||||
temp from to]} {
|
||||
scan $from %x from
|
||||
scan $to %x to
|
||||
for {set i $from} {$i <= $to && $i <= 0x10ffff} {incr i} {
|
||||
lappend tablemap($i) $table
|
||||
}
|
||||
} elseif {[regexp {^ ([[:xdigit:]]+)} $line \
|
||||
temp val]} {
|
||||
scan $val %x val
|
||||
if {$val <= 0x10ffff} {
|
||||
lappend tablemap($val) $table
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# XMPP nodeprep prohibited
|
||||
foreach val {22 26 27 2f 3a 3c 3e 40} {
|
||||
scan $val %x val
|
||||
lappend tablemap($val) XNP
|
||||
}
|
||||
}
|
||||
|
||||
proc uni::buildTables {} {
|
||||
variable shift
|
||||
|
||||
variable casemap
|
||||
variable tablemap
|
||||
|
||||
variable pMap {}
|
||||
variable pages {}
|
||||
variable groups {}
|
||||
set info {} ;# temporary page info
|
||||
|
||||
set mask [expr {(1 << $shift) - 1}]
|
||||
|
||||
set next 0
|
||||
|
||||
for {set i 0} {$i <= 0x10ffff} {incr i} {
|
||||
set gIndex [getGroup [getValue $i]]
|
||||
|
||||
# Split character index into offset and page number
|
||||
set offset [expr {$i & $mask}]
|
||||
set page [expr {($i >> $shift)}]
|
||||
|
||||
# Add the group index to the info for the current page
|
||||
lappend info $gIndex
|
||||
|
||||
# If this is the last entry in the page, add the page
|
||||
if {$offset == $mask} {
|
||||
addPage $info
|
||||
set info {}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
proc uni::main {} {
|
||||
global argc argv0 argv
|
||||
variable pMap
|
||||
variable pages
|
||||
variable groups
|
||||
variable shift
|
||||
variable multicasemap
|
||||
|
||||
if {$argc != 2} {
|
||||
puts stderr "\nusage: $argv0 <datafile> <outdir>\n"
|
||||
exit 1
|
||||
}
|
||||
set f [open [lindex $argv 0] r]
|
||||
set data [read $f]
|
||||
close $f
|
||||
|
||||
load_tables $data
|
||||
buildTables
|
||||
puts "X = [llength $pMap] Y= [llength $pages] A= [llength $groups]"
|
||||
set size [expr {[llength $pMap] + [llength $pages]*(1<<$shift)}]
|
||||
puts "shift = $shift, space = $size"
|
||||
|
||||
set f [open [file join [lindex $argv 1] uni_data.c] w]
|
||||
fconfigure $f -translation lf
|
||||
puts $f "/*
|
||||
* uni_data.c --
|
||||
*
|
||||
* Declarations of Unicode character information tables. This file is
|
||||
* automatically generated by the uni_parse.tcl script. Do not
|
||||
* modify this file by hand.
|
||||
*
|
||||
* Copyright (c) 1998 by Scriptics Corporation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Modified for ejabberd by Alexey Shchepin
|
||||
*
|
||||
* RCS: @(#) \$Id\$
|
||||
*/
|
||||
|
||||
/*
|
||||
* A 16-bit Unicode character is split into two parts in order to index
|
||||
* into the following tables. The lower OFFSET_BITS comprise an offset
|
||||
* into a page of characters. The upper bits comprise the page number.
|
||||
*/
|
||||
|
||||
#define OFFSET_BITS $shift
|
||||
|
||||
/*
|
||||
* The pageMap is indexed by page number and returns an alternate page number
|
||||
* that identifies a unique page of characters. Many Unicode characters map
|
||||
* to the same alternate page number.
|
||||
*/
|
||||
|
||||
static unsigned char pageMap\[\] = {"
|
||||
set line " "
|
||||
set last [expr {[llength $pMap] - 1}]
|
||||
for {set i 0} {$i <= $last} {incr i} {
|
||||
append line [lindex $pMap $i]
|
||||
if {$i != $last} {
|
||||
append line ", "
|
||||
}
|
||||
if {[string length $line] > 70} {
|
||||
puts $f $line
|
||||
set line " "
|
||||
}
|
||||
}
|
||||
puts $f $line
|
||||
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.
|
||||
*/
|
||||
|
||||
static unsigned short int groupMap\[\] = {"
|
||||
set line " "
|
||||
set lasti [expr {[llength $pages] - 1}]
|
||||
for {set i 0} {$i <= $lasti} {incr i} {
|
||||
set page [lindex $pages $i]
|
||||
set lastj [expr {[llength $page] - 1}]
|
||||
for {set j 0} {$j <= $lastj} {incr j} {
|
||||
append line [lindex $page $j]
|
||||
if {$j != $lastj || $i != $lasti} {
|
||||
append line ", "
|
||||
}
|
||||
if {[string length $line] > 70} {
|
||||
puts $f $line
|
||||
set line " "
|
||||
}
|
||||
}
|
||||
}
|
||||
puts $f $line
|
||||
puts $f "};
|
||||
|
||||
/*
|
||||
* Each group represents a unique set of character attributes. The attributes
|
||||
* are encoded into a 32-bit value as follows:
|
||||
*
|
||||
* Bit 0 A.1 | C.1.2 | C.2.2 | C.3 -- C.9
|
||||
*
|
||||
* Bit 1 C.1.1
|
||||
*
|
||||
* Bit 2 C.2.1
|
||||
*
|
||||
* Bit 3 B.1
|
||||
*
|
||||
* Bit 4 D.1
|
||||
*
|
||||
* Bit 5 D.2
|
||||
*
|
||||
* Bit 6 XNP
|
||||
*
|
||||
* Bit 7 Case maps to several characters
|
||||
*
|
||||
* Bits 8-10 Reserved for future use.
|
||||
*
|
||||
* Bits 11-31 Case delta: delta for case conversions. This should be the
|
||||
* highest field so we can easily sign extend.
|
||||
*/
|
||||
|
||||
static int groups\[\] = {"
|
||||
set line " "
|
||||
set last [expr {[llength $groups] - 1}]
|
||||
for {set i 0} {$i <= $last} {incr i} {
|
||||
set val [lindex $groups $i]
|
||||
|
||||
append line [format "%d" $val]
|
||||
if {$i != $last} {
|
||||
append line ", "
|
||||
}
|
||||
if {[string length $line] > 65} {
|
||||
puts $f $line
|
||||
set line " "
|
||||
}
|
||||
}
|
||||
puts $f $line
|
||||
puts $f "};
|
||||
|
||||
/*
|
||||
* Table for characters that lowercased to multiple ones
|
||||
*/
|
||||
|
||||
static int multiCaseTable\[\]\[4\] = {"
|
||||
set last [expr {[llength $multicasemap] - 1}]
|
||||
for {set i 0} {$i <= $last} {incr i} {
|
||||
set val [lindex $multicasemap $i]
|
||||
|
||||
set line " "
|
||||
append line [format "{%d, %s}" [llength $val] [join $val ", "]]
|
||||
if {$i != $last} {
|
||||
append line ", "
|
||||
}
|
||||
puts $f $line
|
||||
}
|
||||
puts $f "};
|
||||
|
||||
/*
|
||||
* The following constants are used to determine the category of a
|
||||
* Unicode character.
|
||||
*/
|
||||
|
||||
#define ACMask (1 << 0)
|
||||
#define C11Mask (1 << 1)
|
||||
#define C21Mask (1 << 2)
|
||||
#define B1Mask (1 << 3)
|
||||
#define D1Mask (1 << 4)
|
||||
#define D2Mask (1 << 5)
|
||||
#define XNPMask (1 << 6)
|
||||
#define MCMask (1 << 7)
|
||||
|
||||
/*
|
||||
* The following macros extract the fields of the character info. The
|
||||
* GetDelta() macro is complicated because we can't rely on the C compiler
|
||||
* to do sign extension on right shifts.
|
||||
*/
|
||||
|
||||
#define GetCaseType(info) (((info) & 0xE0) >> 5)
|
||||
#define GetCategory(info) ((info) & 0x1F)
|
||||
#define GetDelta(info) (((info) > 0) ? ((info) >> 11) : (~(~((info)) >> 11)))
|
||||
#define GetMC(info) (multiCaseTable\[GetDelta(info)\])
|
||||
|
||||
/*
|
||||
* This macro extracts the information about a character from the
|
||||
* Unicode character tables.
|
||||
*/
|
||||
|
||||
#define GetUniCharInfo(ch) (groups\[groupMap\[(pageMap\[(((int)(ch)) & 0x1fffff) >> OFFSET_BITS\] << OFFSET_BITS) | ((ch) & ((1 << OFFSET_BITS)-1))\]\])
|
||||
"
|
||||
|
||||
close $f
|
||||
}
|
||||
|
||||
uni::main
|
||||
|
||||
return
|
@ -1,702 +0,0 @@
|
||||
# uni_parse2.tcl --
|
||||
#
|
||||
# This program parses the UnicodeData file and generates the
|
||||
# corresponding uni_norm.c file with compressed character
|
||||
# data tables. The input to this program should be
|
||||
# UnicodeData-3.2.0.txt and CompositionExclusions-3.2.0.txt files from:
|
||||
# ftp://ftp.unicode.org/Public/UNIDATA/
|
||||
#
|
||||
# Copyright (c) 1998-1999 by Scriptics Corporation.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Modified for ejabberd by Alexey Shchepin
|
||||
#
|
||||
# RCS: @(#) $Id$
|
||||
|
||||
|
||||
namespace eval uni {
|
||||
set cclass_shift 8
|
||||
set decomp_shift 8
|
||||
set comp_shift 8
|
||||
set shift 5; # number of bits of data within a page
|
||||
# This value can be adjusted to find the
|
||||
# best split to minimize table size
|
||||
|
||||
variable pMap; # map from page to page index, each entry is
|
||||
# an index into the pages table, indexed by
|
||||
# page number
|
||||
variable pages; # map from page index to page info, each
|
||||
# entry is a list of indices into the groups
|
||||
# table, the list is indexed by the offset
|
||||
variable groups; # list of character info values, indexed by
|
||||
# group number, initialized with the
|
||||
# unassigned character group
|
||||
|
||||
variable categories {
|
||||
Cn Lu Ll Lt Lm Lo Mn Me Mc Nd Nl No Zs Zl Zp
|
||||
Cc Cf Co Cs Pc Pd Ps Pe Pi Pf Po Sm Sc Sk So
|
||||
}; # Ordered list of character categories, must
|
||||
# match the enumeration in the header file.
|
||||
|
||||
variable titleCount 0; # Count of the number of title case
|
||||
# characters. This value is used in the
|
||||
# regular expression code to allocate enough
|
||||
# space for the title case variants.
|
||||
}
|
||||
|
||||
proc uni::getValue {items index} {
|
||||
variable categories
|
||||
variable titleCount
|
||||
|
||||
# Extract character info
|
||||
|
||||
set category [lindex $items 2]
|
||||
if {[scan [lindex $items 12] %4x toupper] == 1} {
|
||||
set toupper [expr {$index - $toupper}]
|
||||
} else {
|
||||
set toupper {}
|
||||
}
|
||||
if {[scan [lindex $items 13] %4x tolower] == 1} {
|
||||
set tolower [expr {$tolower - $index}]
|
||||
} else {
|
||||
set tolower {}
|
||||
}
|
||||
if {[scan [lindex $items 14] %4x totitle] == 1} {
|
||||
set totitle [expr {$index - $totitle}]
|
||||
} else {
|
||||
set totitle {}
|
||||
}
|
||||
|
||||
set categoryIndex [lsearch -exact $categories $category]
|
||||
if {$categoryIndex < 0} {
|
||||
puts "Unexpected character category: $index($category)"
|
||||
set categoryIndex 0
|
||||
} elseif {$category == "Lt"} {
|
||||
incr titleCount
|
||||
}
|
||||
|
||||
return "$categoryIndex,$toupper,$tolower,$totitle"
|
||||
}
|
||||
|
||||
proc uni::getGroup {value} {
|
||||
variable groups
|
||||
|
||||
set gIndex [lsearch -exact $groups $value]
|
||||
if {$gIndex == -1} {
|
||||
set gIndex [llength $groups]
|
||||
lappend groups $value
|
||||
}
|
||||
return $gIndex
|
||||
}
|
||||
|
||||
proc uni::addPage {info} {
|
||||
variable pMap
|
||||
variable pages
|
||||
|
||||
set pIndex [lsearch -exact $pages $info]
|
||||
if {$pIndex == -1} {
|
||||
set pIndex [llength $pages]
|
||||
lappend pages $info
|
||||
}
|
||||
lappend pMap $pIndex
|
||||
return
|
||||
}
|
||||
|
||||
proc uni::addPage {map_var pages_var info} {
|
||||
variable $map_var
|
||||
variable $pages_var
|
||||
|
||||
set pIndex [lsearch -exact [set $pages_var] $info]
|
||||
if {$pIndex == -1} {
|
||||
set pIndex [llength [set $pages_var]]
|
||||
lappend $pages_var $info
|
||||
}
|
||||
lappend $map_var $pIndex
|
||||
return
|
||||
}
|
||||
|
||||
proc uni::load_exclusions {data} {
|
||||
variable exclusions
|
||||
|
||||
foreach line [split $data \n] {
|
||||
if {$line == ""} continue
|
||||
|
||||
set items [split $line " "]
|
||||
|
||||
if {[lindex $items 0] == "#"} continue
|
||||
|
||||
scan [lindex $items 0] %x index
|
||||
|
||||
set exclusions($index) ""
|
||||
}
|
||||
}
|
||||
|
||||
proc uni::load_tables {data} {
|
||||
variable cclass_map
|
||||
variable decomp_map
|
||||
variable comp_map
|
||||
variable comp_first
|
||||
variable comp_second
|
||||
variable exclusions
|
||||
|
||||
foreach line [split $data \n] {
|
||||
if {$line == ""} continue
|
||||
|
||||
set items [split $line \;]
|
||||
|
||||
scan [lindex $items 0] %x index
|
||||
set cclass [lindex $items 3]
|
||||
set decomp [lindex $items 5]
|
||||
|
||||
set cclass_map($index) $cclass
|
||||
#set decomp_map($index) $cclass
|
||||
|
||||
if {$decomp != ""} {
|
||||
if {[string index [lindex $decomp 0] 0] == "<"} {
|
||||
set decomp1 [lreplace $decomp 0 0]
|
||||
set decomp {}
|
||||
foreach ch $decomp1 {
|
||||
scan $ch %x ch
|
||||
lappend decomp $ch
|
||||
}
|
||||
set decomp_map($index) $decomp
|
||||
} else {
|
||||
switch -- [llength $decomp] {
|
||||
1 {
|
||||
scan $decomp %x ch
|
||||
set decomp_map($index) $ch
|
||||
}
|
||||
2 {
|
||||
scan $decomp "%x %x" ch1 ch2
|
||||
set decomp [list $ch1 $ch2]
|
||||
set decomp_map($index) $decomp
|
||||
# hackish
|
||||
if {(![info exists cclass_map($ch1)] || \
|
||||
$cclass_map($ch1) == 0) && \
|
||||
![info exists exclusions($index)]} {
|
||||
if {[info exists comp_first($ch1)]} {
|
||||
incr comp_first($ch1)
|
||||
} else {
|
||||
set comp_first($ch1) 1
|
||||
}
|
||||
if {[info exists comp_second($ch2)]} {
|
||||
incr comp_second($ch2)
|
||||
} else {
|
||||
set comp_second($ch2) 1
|
||||
}
|
||||
set comp_map($decomp) $index
|
||||
} else {
|
||||
puts "Excluded $index"
|
||||
}
|
||||
}
|
||||
default {
|
||||
puts "Bad canonical decomposition: $line"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#puts "[format 0x%0.4x $index]\t$cclass\t$decomp_map($index)"
|
||||
}
|
||||
}
|
||||
#puts [array get comp_first]
|
||||
#puts [array get comp_second]
|
||||
}
|
||||
|
||||
proc uni::buildTables {} {
|
||||
variable cclass_shift
|
||||
variable decomp_shift
|
||||
variable comp_shift
|
||||
|
||||
variable cclass_map
|
||||
variable cclass_pmap {}
|
||||
variable cclass_pages {}
|
||||
variable decomp_map
|
||||
variable decomp_pmap {}
|
||||
variable decomp_pages {}
|
||||
variable decomp_list {}
|
||||
variable comp_map
|
||||
variable comp_pmap {}
|
||||
variable comp_pages {}
|
||||
variable comp_first
|
||||
variable comp_second
|
||||
variable comp_first_list {}
|
||||
variable comp_second_list {}
|
||||
variable comp_x_list {}
|
||||
variable comp_y_list {}
|
||||
variable comp_both_map {}
|
||||
|
||||
set cclass_info {}
|
||||
set decomp_info {}
|
||||
set comp_info {}
|
||||
|
||||
set cclass_mask [expr {(1 << $cclass_shift) - 1}]
|
||||
set decomp_mask [expr {(1 << $decomp_shift) - 1}]
|
||||
set comp_mask [expr {(1 << $comp_shift) - 1}]
|
||||
|
||||
foreach comp [array names comp_map] {
|
||||
set ch1 [lindex $comp 0]
|
||||
if {[info exists comp_first($ch1)] && $comp_first($ch1) > 0 && \
|
||||
[info exists comp_second($ch1)] && $comp_second($ch1) > 0} {
|
||||
if {[lsearch -exact $comp_x_list $ch1] < 0} {
|
||||
set i [llength $comp_x_list]
|
||||
lappend comp_x_list $ch1
|
||||
set comp_info_map($ch1) $i
|
||||
lappend comp_y_list $ch1
|
||||
set comp_info_map($ch1) $i
|
||||
puts "There should be no symbols which appears on"
|
||||
puts "both first and second place in composition"
|
||||
exit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach comp [array names comp_map] {
|
||||
set ch1 [lindex $comp 0]
|
||||
set ch2 [lindex $comp 1]
|
||||
|
||||
if {$comp_first($ch1) == 1 && ![info exists comp_second($ch1)]} {
|
||||
set i [llength $comp_first_list]
|
||||
lappend comp_first_list [list $ch2 $comp_map($comp)]
|
||||
set comp_info_map($ch1) [expr {$i | (1 << 16)}]
|
||||
} elseif {$comp_second($ch2) == 1 && ![info exists comp_first($ch2)]} {
|
||||
set i [llength $comp_second_list]
|
||||
lappend comp_second_list [list $ch1 $comp_map($comp)]
|
||||
set comp_info_map($ch2) [expr {$i | (1 << 16) | (1 << 17)}]
|
||||
} else {
|
||||
if {[lsearch -exact $comp_x_list $ch1] < 0} {
|
||||
set i [llength $comp_x_list]
|
||||
lappend comp_x_list $ch1
|
||||
set comp_info_map($ch1) $i
|
||||
}
|
||||
if {[lsearch -exact $comp_y_list $ch2] < 0} {
|
||||
set i [llength $comp_y_list]
|
||||
lappend comp_y_list $ch2
|
||||
set comp_info_map($ch2) [expr {$i | (1 << 17)}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set next 0
|
||||
|
||||
for {set i 0} {$i <= 0x10ffff} {incr i} {
|
||||
#set gIndex [getGroup [getValue $i]]
|
||||
|
||||
set cclass_offset [expr {$i & $cclass_mask}]
|
||||
|
||||
if {[info exists cclass_map($i)]} {
|
||||
set cclass $cclass_map($i)
|
||||
} else {
|
||||
set cclass 0
|
||||
}
|
||||
lappend cclass_info $cclass
|
||||
|
||||
if {$cclass_offset == $cclass_mask} {
|
||||
addPage cclass_pmap cclass_pages $cclass_info
|
||||
set cclass_info {}
|
||||
}
|
||||
|
||||
|
||||
set decomp_offset [expr {$i & $decomp_mask}]
|
||||
|
||||
if {[info exists decomp_map($i)]} {
|
||||
set decomp $decomp_map($i)
|
||||
set b 1
|
||||
while {$b} {
|
||||
set b 0
|
||||
for {set j 0} {$j < [llength $decomp]} {incr j} {
|
||||
if {[info exists \
|
||||
decomp_map([set ch1 [lindex $decomp $j]])]} {
|
||||
#puts -$decomp
|
||||
set decomp [eval [list lreplace $decomp $j $j] \
|
||||
$decomp_map($ch1)]
|
||||
#puts +$decomp
|
||||
set b 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if {[info exists decomp_used($decomp)]} {
|
||||
lappend decomp_info $decomp_used($decomp)
|
||||
} else {
|
||||
set val [expr {([llength $decomp] << 16) + \
|
||||
[llength $decomp_list]}]
|
||||
#set val [expr {[llength $decomp_list]}]
|
||||
lappend decomp_info $val
|
||||
set decomp_used($decomp) $val
|
||||
#puts "$val $decomp"
|
||||
foreach d $decomp {
|
||||
lappend decomp_list $d
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lappend decomp_info -1
|
||||
}
|
||||
|
||||
if {$decomp_offset == $decomp_mask} {
|
||||
addPage decomp_pmap decomp_pages $decomp_info
|
||||
set decomp_info {}
|
||||
}
|
||||
|
||||
|
||||
set comp_offset [expr {$i & $comp_mask}]
|
||||
|
||||
if {[info exists comp_info_map($i)]} {
|
||||
set comp $comp_info_map($i)
|
||||
} else {
|
||||
set comp -1
|
||||
}
|
||||
lappend comp_info $comp
|
||||
|
||||
if {$comp_offset == $comp_mask} {
|
||||
addPage comp_pmap comp_pages $comp_info
|
||||
set comp_info {}
|
||||
}
|
||||
}
|
||||
|
||||
#puts [array get decomp_map]
|
||||
#puts $decomp_list
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
proc uni::main {} {
|
||||
global argc argv0 argv
|
||||
variable cclass_shift
|
||||
variable cclass_pmap
|
||||
variable cclass_pages
|
||||
variable decomp_shift
|
||||
variable decomp_pmap
|
||||
variable decomp_pages
|
||||
variable decomp_list
|
||||
variable comp_shift
|
||||
variable comp_map
|
||||
variable comp_pmap
|
||||
variable comp_pages
|
||||
variable comp_first_list
|
||||
variable comp_second_list
|
||||
variable comp_x_list
|
||||
variable comp_y_list
|
||||
variable pages
|
||||
variable groups {}
|
||||
variable titleCount
|
||||
|
||||
if {$argc != 3} {
|
||||
puts stderr "\nusage: $argv0 <datafile> <exclusionsfile> <outdir>\n"
|
||||
exit 1
|
||||
}
|
||||
set f [open [lindex $argv 1] r]
|
||||
set data [read $f]
|
||||
close $f
|
||||
|
||||
load_exclusions $data
|
||||
|
||||
set f [open [lindex $argv 0] r]
|
||||
set data [read $f]
|
||||
close $f
|
||||
|
||||
load_tables $data
|
||||
buildTables
|
||||
#puts "X = [llength $pMap] Y= [llength $pages] A= [llength $groups]"
|
||||
#set size [expr {[llength $pMap] + [llength $pages]*(1<<$shift)}]
|
||||
#puts "shift = 6, space = $size"
|
||||
#puts "title case count = $titleCount"
|
||||
|
||||
set f [open [file join [lindex $argv 2] uni_norm.c] w]
|
||||
fconfigure $f -translation lf
|
||||
puts $f "/*
|
||||
* uni_norm.c --
|
||||
*
|
||||
* Declarations of Unicode character information tables. This file is
|
||||
* automatically generated by the uni_parse2.tcl script. Do not
|
||||
* modify this file by hand.
|
||||
*
|
||||
* Copyright (c) 1998 by Scriptics Corporation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Modified for ejabberd by Alexey Shchepin
|
||||
*
|
||||
* RCS: @(#) \$Id\$
|
||||
*/
|
||||
|
||||
/*
|
||||
* A 16-bit Unicode character is split into two parts in order to index
|
||||
* into the following tables. The lower CCLASS_OFFSET_BITS comprise an offset
|
||||
* into a page of characters. The upper bits comprise the page number.
|
||||
*/
|
||||
|
||||
#define CCLASS_OFFSET_BITS $cclass_shift
|
||||
|
||||
/*
|
||||
* The pageMap is indexed by page number and returns an alternate page number
|
||||
* that identifies a unique page of characters. Many Unicode characters map
|
||||
* to the same alternate page number.
|
||||
*/
|
||||
|
||||
static unsigned char cclassPageMap\[\] = {"
|
||||
set line " "
|
||||
set last [expr {[llength $cclass_pmap] - 1}]
|
||||
for {set i 0} {$i <= $last} {incr i} {
|
||||
append line [lindex $cclass_pmap $i]
|
||||
if {$i != $last} {
|
||||
append line ", "
|
||||
}
|
||||
if {[string length $line] > 70} {
|
||||
puts $f $line
|
||||
set line " "
|
||||
}
|
||||
}
|
||||
puts $f $line
|
||||
puts $f "};
|
||||
|
||||
/*
|
||||
* The cclassGroupMap is indexed by combining the alternate page number with
|
||||
* the page offset and returns a combining class number.
|
||||
*/
|
||||
|
||||
static unsigned char cclassGroupMap\[\] = {"
|
||||
set line " "
|
||||
set lasti [expr {[llength $cclass_pages] - 1}]
|
||||
for {set i 0} {$i <= $lasti} {incr i} {
|
||||
set page [lindex $cclass_pages $i]
|
||||
set lastj [expr {[llength $page] - 1}]
|
||||
for {set j 0} {$j <= $lastj} {incr j} {
|
||||
append line [lindex $page $j]
|
||||
if {$j != $lastj || $i != $lasti} {
|
||||
append line ", "
|
||||
}
|
||||
if {[string length $line] > 70} {
|
||||
puts $f $line
|
||||
set line " "
|
||||
}
|
||||
}
|
||||
}
|
||||
puts $f $line
|
||||
puts $f "};
|
||||
|
||||
#define GetUniCharCClass(ch) (cclassGroupMap\[(cclassPageMap\[(((int)(ch)) & 0x1fffff) >> CCLASS_OFFSET_BITS\] << CCLASS_OFFSET_BITS) | ((ch) & ((1 << CCLASS_OFFSET_BITS)-1))\])
|
||||
|
||||
|
||||
#define DECOMP_OFFSET_BITS $decomp_shift
|
||||
|
||||
/*
|
||||
* The pageMap is indexed by page number and returns an alternate page number
|
||||
* that identifies a unique page of characters. Many Unicode characters map
|
||||
* to the same alternate page number.
|
||||
*/
|
||||
|
||||
static unsigned char decompPageMap\[\] = {"
|
||||
set line " "
|
||||
set last [expr {[llength $decomp_pmap] - 1}]
|
||||
for {set i 0} {$i <= $last} {incr i} {
|
||||
append line [lindex $decomp_pmap $i]
|
||||
if {$i != $last} {
|
||||
append line ", "
|
||||
}
|
||||
if {[string length $line] > 70} {
|
||||
puts $f $line
|
||||
set line " "
|
||||
}
|
||||
}
|
||||
puts $f $line
|
||||
puts $f "};
|
||||
|
||||
/*
|
||||
* 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\[\] = {"
|
||||
set line " "
|
||||
set lasti [expr {[llength $decomp_pages] - 1}]
|
||||
for {set i 0} {$i <= $lasti} {incr i} {
|
||||
set page [lindex $decomp_pages $i]
|
||||
set lastj [expr {[llength $page] - 1}]
|
||||
for {set j 0} {$j <= $lastj} {incr j} {
|
||||
append line [lindex $page $j]
|
||||
if {$j != $lastj || $i != $lasti} {
|
||||
append line ", "
|
||||
}
|
||||
if {[string length $line] > 70} {
|
||||
puts $f $line
|
||||
set line " "
|
||||
}
|
||||
}
|
||||
}
|
||||
puts $f $line
|
||||
puts $f "};
|
||||
|
||||
/*
|
||||
* List of decomposition sequences
|
||||
*/
|
||||
|
||||
static int decompList\[\] = {"
|
||||
set line " "
|
||||
set last [expr {[llength $decomp_list] - 1}]
|
||||
for {set i 0} {$i <= $last} {incr i} {
|
||||
set val [lindex $decomp_list $i]
|
||||
|
||||
append line [format "%d" $val]
|
||||
if {$i != $last} {
|
||||
append line ", "
|
||||
}
|
||||
if {[string length $line] > 70} {
|
||||
puts $f $line
|
||||
set line " "
|
||||
}
|
||||
}
|
||||
puts $f $line
|
||||
puts $f "};
|
||||
|
||||
|
||||
/*
|
||||
* This macro extracts the information about a character from the
|
||||
* Unicode character tables.
|
||||
*/
|
||||
|
||||
#define GetUniCharDecompInfo(ch) (decompGroupMap\[(decompPageMap\[(((int)(ch)) & 0x1fffff) >> DECOMP_OFFSET_BITS\] << DECOMP_OFFSET_BITS) | ((ch) & ((1 << DECOMP_OFFSET_BITS)-1))\])
|
||||
|
||||
#define GetDecompShift(info) ((info) & 0xffff)
|
||||
#define GetDecompLen(info) ((info) >> 16)
|
||||
|
||||
|
||||
#define COMP_OFFSET_BITS $comp_shift
|
||||
|
||||
/*
|
||||
* The pageMap is indexed by page number and returns an alternate page number
|
||||
* that identifies a unique page of characters. Many Unicode characters map
|
||||
* to the same alternate page number.
|
||||
*/
|
||||
|
||||
static unsigned char compPageMap\[\] = {"
|
||||
set line " "
|
||||
set last [expr {[llength $comp_pmap] - 1}]
|
||||
for {set i 0} {$i <= $last} {incr i} {
|
||||
append line [lindex $comp_pmap $i]
|
||||
if {$i != $last} {
|
||||
append line ", "
|
||||
}
|
||||
if {[string length $line] > 70} {
|
||||
puts $f $line
|
||||
set line " "
|
||||
}
|
||||
}
|
||||
puts $f $line
|
||||
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.
|
||||
*/
|
||||
|
||||
static int compGroupMap\[\] = {"
|
||||
set line " "
|
||||
set lasti [expr {[llength $comp_pages] - 1}]
|
||||
for {set i 0} {$i <= $lasti} {incr i} {
|
||||
set page [lindex $comp_pages $i]
|
||||
set lastj [expr {[llength $page] - 1}]
|
||||
for {set j 0} {$j <= $lastj} {incr j} {
|
||||
append line [lindex $page $j]
|
||||
if {$j != $lastj || $i != $lasti} {
|
||||
append line ", "
|
||||
}
|
||||
if {[string length $line] > 70} {
|
||||
puts $f $line
|
||||
set line " "
|
||||
}
|
||||
}
|
||||
}
|
||||
puts $f $line
|
||||
puts $f "};
|
||||
|
||||
/*
|
||||
* Lists of compositions for characters that appears only in one composition
|
||||
*/
|
||||
|
||||
static int compFirstList\[\]\[2\] = {"
|
||||
set line " "
|
||||
set last [expr {[llength $comp_first_list] - 1}]
|
||||
for {set i 0} {$i <= $last} {incr i} {
|
||||
set val [lindex $comp_first_list $i]
|
||||
|
||||
append line [format "{%d, %d}" [lindex $val 0] [lindex $val 1]]
|
||||
if {$i != $last} {
|
||||
append line ", "
|
||||
}
|
||||
if {[string length $line] > 60} {
|
||||
puts $f $line
|
||||
set line " "
|
||||
}
|
||||
}
|
||||
puts $f $line
|
||||
puts $f "};
|
||||
|
||||
static int compSecondList\[\]\[2\] = {"
|
||||
set line " "
|
||||
set last [expr {[llength $comp_second_list] - 1}]
|
||||
for {set i 0} {$i <= $last} {incr i} {
|
||||
set val [lindex $comp_second_list $i]
|
||||
|
||||
append line [format "{%d, %d}" [lindex $val 0] [lindex $val 1]]
|
||||
if {$i != $last} {
|
||||
append line ", "
|
||||
}
|
||||
if {[string length $line] > 60} {
|
||||
puts $f $line
|
||||
set line " "
|
||||
}
|
||||
}
|
||||
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}]
|
||||
for {set i 0} {$i <= $lastx} {incr i} {
|
||||
puts $f " \{"
|
||||
set line " "
|
||||
for {set j 0} {$j <= $lasty} {incr j} {
|
||||
set comp [list [lindex $comp_x_list $i] [lindex $comp_y_list $j]]
|
||||
if {[info exists comp_map($comp)]} {
|
||||
set val $comp_map($comp)
|
||||
} else {
|
||||
set val 0
|
||||
}
|
||||
|
||||
append line [format "%d" $val]
|
||||
if {$j != $lasty} {
|
||||
append line ", "
|
||||
}
|
||||
if {[string length $line] > 70} {
|
||||
puts $f $line
|
||||
set line " "
|
||||
}
|
||||
}
|
||||
puts $f $line
|
||||
if {$j != $lasty} {
|
||||
puts $f " \},"
|
||||
} else {
|
||||
puts $f " \}"
|
||||
}
|
||||
}
|
||||
puts $f "};
|
||||
|
||||
|
||||
#define GetUniCharCompInfo(ch) (compGroupMap\[(compPageMap\[(((int)(ch)) & 0x1fffff) >> COMP_OFFSET_BITS\] << COMP_OFFSET_BITS) | ((ch) & ((1 << COMP_OFFSET_BITS)-1))\])
|
||||
|
||||
#define CompSingleMask (1 << 16)
|
||||
#define CompMask ((1 << 16) - 1)
|
||||
#define CompSecondMask (1 << 17)
|
||||
"
|
||||
|
||||
close $f
|
||||
}
|
||||
|
||||
uni::main
|
||||
|
||||
return
|
234
src/xml.erl
234
src/xml.erl
@ -1,234 +0,0 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : xml.erl
|
||||
%%% Author : Alexey Shchepin <alexey@process-one.net>
|
||||
%%% Purpose : XML utils
|
||||
%%% Created : 20 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
%%% 02111-1307 USA
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-module(xml).
|
||||
-author('alexey@process-one.net').
|
||||
|
||||
-export([element_to_string/1,
|
||||
crypt/1, make_text_node/1,
|
||||
remove_cdata/1,
|
||||
get_cdata/1, get_tag_cdata/1,
|
||||
get_attr/2, get_attr_s/2,
|
||||
get_tag_attr/2, get_tag_attr_s/2,
|
||||
get_subtag/2, get_subtag_cdata/2,
|
||||
get_path_s/2,
|
||||
replace_tag_attr/3]).
|
||||
|
||||
%% Select at compile time how to escape characters in binary text
|
||||
%% nodes.
|
||||
%% Can be choosen with ./configure --enable-full-xml
|
||||
-ifdef(FULL_XML_SUPPORT).
|
||||
-define(ESCAPE_BINARY(CData), make_text_node(CData)).
|
||||
-else.
|
||||
-define(ESCAPE_BINARY(CData), crypt(CData)).
|
||||
-endif.
|
||||
|
||||
element_to_string(El) ->
|
||||
case El of
|
||||
{xmlelement, Name, Attrs, Els} ->
|
||||
if
|
||||
Els /= [] ->
|
||||
[$<, Name, attrs_to_list(Attrs), $>,
|
||||
[element_to_string(E) || E <- Els],
|
||||
$<, $/, Name, $>];
|
||||
true ->
|
||||
[$<, Name, attrs_to_list(Attrs), $/, $>]
|
||||
end;
|
||||
%% We do not crypt CDATA binary, but we enclose it in XML CDATA
|
||||
{xmlcdata, CData} when is_binary(CData) ->
|
||||
?ESCAPE_BINARY(CData);
|
||||
%% We crypt list and possibly binaries if full XML usage is
|
||||
%% disabled unsupported (implies a conversion to list).
|
||||
{xmlcdata, CData} ->
|
||||
crypt(CData)
|
||||
end.
|
||||
|
||||
attrs_to_list(Attrs) ->
|
||||
[attr_to_list(A) || A <- Attrs].
|
||||
|
||||
attr_to_list({Name, Value}) ->
|
||||
[$\s, crypt(Name), $=, $', crypt(Value), $'].
|
||||
|
||||
crypt(S) when is_list(S) ->
|
||||
[case C of
|
||||
$& -> "&";
|
||||
$< -> "<";
|
||||
$> -> ">";
|
||||
$" -> """;
|
||||
$' -> "'";
|
||||
_ -> C
|
||||
end || C <- S];
|
||||
crypt(S) when is_binary(S) ->
|
||||
crypt(binary_to_list(S)).
|
||||
|
||||
%% Make a cdata_binary depending on what characters it contains
|
||||
make_text_node(CData) ->
|
||||
case cdata_need_escape(CData) of
|
||||
cdata ->
|
||||
CDATA1 = <<"<![CDATA[">>,
|
||||
CDATA2 = <<"]]>">>,
|
||||
concat_binary([CDATA1, CData, CDATA2]);
|
||||
none ->
|
||||
CData;
|
||||
{cdata, EndTokens} ->
|
||||
EscapedCData = escape_cdata(CData, EndTokens),
|
||||
concat_binary(EscapedCData)
|
||||
end.
|
||||
|
||||
%% Returns escape type needed for the text node
|
||||
%% none, cdata, {cdata, [Positions]}
|
||||
%% Positions is a list a integer containing positions of CDATA end
|
||||
%% tokens, so that they can be escaped
|
||||
cdata_need_escape(CData) ->
|
||||
cdata_need_escape(CData, 0, false, []).
|
||||
cdata_need_escape(<<>>, _, false, _) ->
|
||||
none;
|
||||
cdata_need_escape(<<>>, _, true, []) ->
|
||||
cdata;
|
||||
cdata_need_escape(<<>>, _, true, CDataEndTokens) ->
|
||||
{cdata, lists:reverse(CDataEndTokens)};
|
||||
cdata_need_escape(<<$],$],$>,Rest/binary>>, CurrentPosition,
|
||||
_XMLEscape, CDataEndTokens) ->
|
||||
NewPosition = CurrentPosition + 3,
|
||||
cdata_need_escape(Rest, NewPosition, true,
|
||||
[CurrentPosition+1|CDataEndTokens]);
|
||||
%% Only <, & need to be escaped in XML text node
|
||||
%% See reference: http://www.w3.org/TR/xml11/#syntax
|
||||
cdata_need_escape(<<$<,Rest/binary>>, CurrentPosition,
|
||||
_XMLEscape, CDataEndTokens) ->
|
||||
cdata_need_escape(Rest, CurrentPosition+1, true, CDataEndTokens);
|
||||
cdata_need_escape(<<$&,Rest/binary>>, CurrentPosition,
|
||||
_XMLEscape, CDataEndTokens) ->
|
||||
cdata_need_escape(Rest, CurrentPosition+1, true, CDataEndTokens);
|
||||
cdata_need_escape(<<_:8,Rest/binary>>, CurrentPosition,
|
||||
XMLEscape, CDataEndTokens) ->
|
||||
cdata_need_escape(Rest, CurrentPosition+1, XMLEscape,
|
||||
CDataEndTokens).
|
||||
|
||||
%% escape cdata that contain CDATA end tokens
|
||||
%% EndTokens is a list of position of end tokens (integer)
|
||||
%% This is supposed to be a very rare case: You need to generate several
|
||||
%% fields, splitting it in the middle of the end token.
|
||||
%% See example: http://en.wikipedia.org/wiki/CDATA#Uses_of_CDATA_sections
|
||||
escape_cdata(CData, EndTokens) ->
|
||||
escape_cdata(CData, 0, EndTokens, []).
|
||||
escape_cdata(<<>>, _CurrentPosition, [], Acc) ->
|
||||
lists:reverse(Acc);
|
||||
escape_cdata(Rest, CurrentPosition, [], Acc) ->
|
||||
CDATA1 = <<"<![CDATA[">>,
|
||||
CDATA2 = <<"]]>">>,
|
||||
escape_cdata(<<>>, CurrentPosition, [], [CDATA2, Rest, CDATA1|Acc]);
|
||||
escape_cdata(CData, Index, [Pos|Positions], Acc) ->
|
||||
CDATA1 = <<"<![CDATA[">>,
|
||||
CDATA2 = <<"]]>">>,
|
||||
Split = Pos-Index,
|
||||
{Part, Rest} = split_binary(CData, Split+1),
|
||||
%% Note: We build the list in reverse to optimize construction
|
||||
escape_cdata(Rest, Pos+1, Positions, [CDATA2, Part, CDATA1|Acc]).
|
||||
|
||||
remove_cdata_p({xmlelement, _Name, _Attrs, _Els}) -> true;
|
||||
remove_cdata_p(_) -> false.
|
||||
|
||||
remove_cdata(L) -> [E || E <- L, remove_cdata_p(E)].
|
||||
|
||||
get_cdata(L) ->
|
||||
binary_to_list(list_to_binary(get_cdata(L, ""))).
|
||||
|
||||
get_cdata([{xmlcdata, CData} | L], S) ->
|
||||
get_cdata(L, [S, CData]);
|
||||
get_cdata([_ | L], S) ->
|
||||
get_cdata(L, S);
|
||||
get_cdata([], S) ->
|
||||
S.
|
||||
|
||||
get_tag_cdata({xmlelement, _Name, _Attrs, Els}) ->
|
||||
get_cdata(Els).
|
||||
|
||||
get_attr(AttrName, Attrs) ->
|
||||
case lists:keysearch(AttrName, 1, Attrs) of
|
||||
{value, {_, Val}} ->
|
||||
{value, Val};
|
||||
_ ->
|
||||
false
|
||||
end.
|
||||
|
||||
get_attr_s(AttrName, Attrs) ->
|
||||
case lists:keysearch(AttrName, 1, Attrs) of
|
||||
{value, {_, Val}} ->
|
||||
Val;
|
||||
_ ->
|
||||
""
|
||||
end.
|
||||
|
||||
get_tag_attr(AttrName, {xmlelement, _Name, Attrs, _Els}) ->
|
||||
get_attr(AttrName, Attrs).
|
||||
|
||||
get_tag_attr_s(AttrName, {xmlelement, _Name, Attrs, _Els}) ->
|
||||
get_attr_s(AttrName, Attrs).
|
||||
|
||||
|
||||
get_subtag({xmlelement, _, _, Els}, Name) ->
|
||||
get_subtag1(Els, Name).
|
||||
|
||||
get_subtag1([El | Els], Name) ->
|
||||
case El of
|
||||
{xmlelement, Name, _, _} ->
|
||||
El;
|
||||
_ ->
|
||||
get_subtag1(Els, Name)
|
||||
end;
|
||||
get_subtag1([], _) ->
|
||||
false.
|
||||
|
||||
get_subtag_cdata(Tag, Name) ->
|
||||
case get_subtag(Tag, Name) of
|
||||
false ->
|
||||
"";
|
||||
Subtag ->
|
||||
get_tag_cdata(Subtag)
|
||||
end.
|
||||
|
||||
get_path_s(El, []) ->
|
||||
El;
|
||||
get_path_s(El, [{elem, Name} | Path]) ->
|
||||
case get_subtag(El, Name) of
|
||||
false ->
|
||||
"";
|
||||
SubEl ->
|
||||
get_path_s(SubEl, Path)
|
||||
end;
|
||||
get_path_s(El, [{attr, Name}]) ->
|
||||
get_tag_attr_s(Name, El);
|
||||
get_path_s(El, [cdata]) ->
|
||||
get_tag_cdata(El).
|
||||
|
||||
|
||||
replace_tag_attr(Attr, Value, {xmlelement, Name, Attrs, Els}) ->
|
||||
Attrs1 = lists:keydelete(Attr, 1, Attrs),
|
||||
Attrs2 = [{Attr, Value} | Attrs1],
|
||||
{xmlelement, Name, Attrs2, Els}.
|
||||
|
||||
|
@ -1,190 +0,0 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : xml_stream.erl
|
||||
%%% Author : Alexey Shchepin <alexey@process-one.net>
|
||||
%%% Purpose : Parse XML streams
|
||||
%%% Created : 17 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
%%% 02111-1307 USA
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-module(xml_stream).
|
||||
-author('alexey@process-one.net').
|
||||
|
||||
-export([new/1,
|
||||
new/2,
|
||||
parse/2,
|
||||
close/1,
|
||||
parse_element/1]).
|
||||
|
||||
-define(XML_START, 0).
|
||||
-define(XML_END, 1).
|
||||
-define(XML_CDATA, 2).
|
||||
-define(XML_ERROR, 3).
|
||||
|
||||
-define(PARSE_COMMAND, 0).
|
||||
-define(PARSE_FINAL_COMMAND, 1).
|
||||
|
||||
-record(xml_stream_state, {callback_pid, port, stack, size, maxsize}).
|
||||
|
||||
process_data(CallbackPid, Stack, Data) ->
|
||||
case Data of
|
||||
{?XML_START, {Name, Attrs}} ->
|
||||
if
|
||||
Stack == [] ->
|
||||
catch gen_fsm:send_event(CallbackPid,
|
||||
{xmlstreamstart, Name, Attrs});
|
||||
true ->
|
||||
ok
|
||||
end,
|
||||
[{xmlelement, Name, Attrs, []} | Stack];
|
||||
{?XML_END, EndName} ->
|
||||
case Stack of
|
||||
[{xmlelement, Name, Attrs, Els} | Tail] ->
|
||||
NewEl = {xmlelement, Name, Attrs, lists:reverse(Els)},
|
||||
case Tail of
|
||||
[] ->
|
||||
catch gen_fsm:send_event(CallbackPid,
|
||||
{xmlstreamend, EndName}),
|
||||
Tail;
|
||||
[_] ->
|
||||
catch gen_fsm:send_event(CallbackPid,
|
||||
{xmlstreamelement, NewEl}),
|
||||
Tail;
|
||||
[{xmlelement, Name1, Attrs1, Els1} | Tail1] ->
|
||||
[{xmlelement, Name1, Attrs1, [NewEl | Els1]} |
|
||||
Tail1]
|
||||
end
|
||||
end;
|
||||
{?XML_CDATA, CData} ->
|
||||
case Stack of
|
||||
[El] ->
|
||||
[El];
|
||||
%% Merge CDATA nodes if they are contiguous
|
||||
%% This does not change the semantic: the split in
|
||||
%% several CDATA nodes depends on the TCP/IP packet
|
||||
%% fragmentation
|
||||
[{xmlelement, Name, Attrs,
|
||||
[{xmlcdata, PreviousCData}|Els]} | Tail] ->
|
||||
[{xmlelement, Name, Attrs,
|
||||
[{xmlcdata, concat_binary([PreviousCData, CData])} | Els]} | Tail];
|
||||
%% No previous CDATA
|
||||
[{xmlelement, Name, Attrs, Els} | Tail] ->
|
||||
[{xmlelement, Name, Attrs, [{xmlcdata, CData} | Els]} |
|
||||
Tail];
|
||||
[] -> []
|
||||
end;
|
||||
{?XML_ERROR, Err} ->
|
||||
catch gen_fsm:send_event(CallbackPid, {xmlstreamerror, Err})
|
||||
end.
|
||||
|
||||
|
||||
new(CallbackPid) ->
|
||||
new(CallbackPid, infinity).
|
||||
|
||||
new(CallbackPid, MaxSize) ->
|
||||
Port = open_port({spawn, expat_erl}, [binary]),
|
||||
#xml_stream_state{callback_pid = CallbackPid,
|
||||
port = Port,
|
||||
stack = [],
|
||||
size = 0,
|
||||
maxsize = MaxSize}.
|
||||
|
||||
|
||||
parse(#xml_stream_state{callback_pid = CallbackPid,
|
||||
port = Port,
|
||||
stack = Stack,
|
||||
size = Size,
|
||||
maxsize = MaxSize} = State, Str) ->
|
||||
StrSize = if
|
||||
is_list(Str) -> length(Str);
|
||||
is_binary(Str) -> size(Str)
|
||||
end,
|
||||
Res = port_control(Port, ?PARSE_COMMAND, Str),
|
||||
{NewStack, NewSize} =
|
||||
lists:foldl(
|
||||
fun(Data, {St, Sz}) ->
|
||||
NewSt = process_data(CallbackPid, St, Data),
|
||||
case NewSt of
|
||||
[_] -> {NewSt, 0};
|
||||
_ -> {NewSt, Sz}
|
||||
end
|
||||
end, {Stack, Size + StrSize}, binary_to_term(Res)),
|
||||
if
|
||||
NewSize > MaxSize ->
|
||||
catch gen_fsm:send_event(CallbackPid,
|
||||
{xmlstreamerror, "XML stanza is too big"});
|
||||
true ->
|
||||
ok
|
||||
end,
|
||||
State#xml_stream_state{stack = NewStack, size = NewSize}.
|
||||
|
||||
close(#xml_stream_state{port = Port}) ->
|
||||
port_close(Port).
|
||||
|
||||
|
||||
parse_element(Str) ->
|
||||
Port = open_port({spawn, expat_erl}, [binary]),
|
||||
Res = port_control(Port, ?PARSE_FINAL_COMMAND, Str),
|
||||
port_close(Port),
|
||||
process_element_events(binary_to_term(Res)).
|
||||
|
||||
process_element_events(Events) ->
|
||||
process_element_events(Events, []).
|
||||
|
||||
process_element_events([], _Stack) ->
|
||||
{error, parse_error};
|
||||
process_element_events([Event | Events], Stack) ->
|
||||
case Event of
|
||||
{?XML_START, {Name, Attrs}} ->
|
||||
process_element_events(
|
||||
Events, [{xmlelement, Name, Attrs, []} | Stack]);
|
||||
{?XML_END, _EndName} ->
|
||||
case Stack of
|
||||
[{xmlelement, Name, Attrs, Els} | Tail] ->
|
||||
NewEl = {xmlelement, Name, Attrs, lists:reverse(Els)},
|
||||
case Tail of
|
||||
[] ->
|
||||
if
|
||||
Events == [] ->
|
||||
NewEl;
|
||||
true ->
|
||||
{error, parse_error}
|
||||
end;
|
||||
[{xmlelement, Name1, Attrs1, Els1} | Tail1] ->
|
||||
process_element_events(
|
||||
Events,
|
||||
[{xmlelement, Name1, Attrs1, [NewEl | Els1]} |
|
||||
Tail1])
|
||||
end
|
||||
end;
|
||||
{?XML_CDATA, CData} ->
|
||||
case Stack of
|
||||
[{xmlelement, Name, Attrs, Els} | Tail] ->
|
||||
process_element_events(
|
||||
Events,
|
||||
[{xmlelement, Name, Attrs, [{xmlcdata, CData} | Els]} |
|
||||
Tail]);
|
||||
[] ->
|
||||
process_element_events(Events, [])
|
||||
end;
|
||||
{?XML_ERROR, Err} ->
|
||||
{error, Err}
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user