summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <monty@work.mysql.com>2001-04-11 13:04:03 +0200
committerunknown <monty@work.mysql.com>2001-04-11 13:04:03 +0200
commit8dd2e5b8d93d79965e833e3b979675240478c591 (patch)
tree9ad58a68370fc8feb8195b7b9c6423d58372093a
parent0c971641774f4d06f5442ef23af5d8c7ef9058ab (diff)
downloadmariadb-git-8dd2e5b8d93d79965e833e3b979675240478c591.tar.gz
Added all changes from old 4.0 version:
PSTACK, libmysqld and MySQL filesystem UPDATE ... ORDER BY DELETE ... ORDER BY New faster fulltext handling Faster compressed keys Makefile.am: Added support for pstack and libmysqld_dir acconfig.h: MySQL filesystem and PSTACK acinclude.m4: MySQL File system client/mysql.cc: Support for --xml configure.in: Pstack, MySQL FS and libmysqld_dir include/ft_global.h: Faster fulltext include/my_pthread.h: Made c++ safe include/myisam.h: Update for faster fulltext include/mysql_com.h: new my_net_read() include/violite.h: libmysqld libmysql/net.c: New protocol that supports big packets myisam/Makefile.am: Faster fulltext myisam/ft_parser.c: Faster fulltext myisam/ft_search.c: Faster fulltext myisam/ft_update.c: Faster fulltext myisam/ftdefs.h: Faster fulltext myisam/mi_check.c: Faster fulltext myisam/mi_open.c: Faster compressed keys myisam/mi_search.c: Faster compressed keys myisam/mi_update.c: Faster compressed keys myisam/myisamdef.h: Faster compressed keys myisam/sort.c: Faster compressed keys mysql-test/mysql-test-run.sh: --skip-innobase and --skip-bdb sql/ChangeLog: Changelog sql/Makefile.am: PSTACK sql/mysql_priv.h: New ORDER BY options and libmysqld sql/mysqld.cc: PSTACK sql/net_serv.cc: New protocol that supports big packets sql/share/estonian/errmsg.txt: New error messages sql/sql_base.cc: Better list_open_tabels sql/sql_delete.cc: ORDER BY for delete sql/sql_lex.cc: Added language convertation of all strings sql/sql_parse.cc: Changes for libmysqld Use new ORDER BY options sql/sql_show.cc: Character set convertations Use new list_open_tables function. sql/sql_update.cc: UPDATE ... ORDER BY sql/sql_yacc.yy: Clean up symbol definitions DELETE .. ORDER BY UPDATE .. ORDER BY sql/table.h: new OPEN_TABLE_LIST structure BitKeeper/etc/logging_ok: Logging to logging@openlogging.org accepted
-rwxr-xr-xBUILD/compile-pentium-mysqlfs-debug13
-rw-r--r--BitKeeper/etc/logging_ok2
-rw-r--r--Makefile.am17
-rw-r--r--acconfig.h6
-rw-r--r--acinclude.m447
-rw-r--r--client/mysql.cc110
-rw-r--r--configure.in66
-rw-r--r--fs/CorbaFS.idl38
-rw-r--r--fs/Makefile.am93
-rw-r--r--fs/README58
-rwxr-xr-xfs/RunServer.sh2
-rw-r--r--fs/database.c629
-rw-r--r--fs/dump.sql28
-rw-r--r--fs/korbit-kernel-2.4.1-patch35661
-rw-r--r--fs/libmysqlfs.c153
-rw-r--r--fs/libmysqlfs.h81
-rw-r--r--fs/my.cnf5
-rw-r--r--fs/mysqlcorbafs.c992
-rw-r--r--fs/mysqlcorbafs.h159
-rw-r--r--fs/mysqlcorbafs_test.c92
-rwxr-xr-xfs/mysqlfsck11
-rw-r--r--include/ft_global.h7
-rw-r--r--include/my_pthread.h8
-rw-r--r--include/myisam.h12
-rw-r--r--include/mysql_com.h2
-rw-r--r--include/violite.h4
-rw-r--r--libmysql/net.c285
-rw-r--r--libmysqld/Makefile.am106
-rw-r--r--libmysqld/README26
-rw-r--r--libmysqld/WHITEPAPER16
-rw-r--r--libmysqld/copyright14
-rw-r--r--libmysqld/lib_load.cc41
-rw-r--r--libmysqld/lib_sql.cc650
-rw-r--r--libmysqld/lib_vio.c236
-rw-r--r--libmysqld/libmysqld.c2299
-rw-r--r--myisam/Makefile.am13
-rw-r--r--myisam/ft_boolean_search.c222
-rw-r--r--myisam/ft_dump.c214
-rw-r--r--myisam/ft_nlq_search.c191
-rw-r--r--myisam/ft_parser.c138
-rw-r--r--myisam/ft_search.c173
-rw-r--r--myisam/ft_update.c71
-rw-r--r--myisam/ftdefs.h47
-rw-r--r--myisam/mi_check.c96
-rw-r--r--myisam/mi_open.c7
-rw-r--r--myisam/mi_search.c1238
-rw-r--r--myisam/mi_update.c4
-rw-r--r--myisam/myisamdef.h14
-rw-r--r--myisam/sort.c152
-rw-r--r--mysql-test/mysql-test-run.sh6
-rw-r--r--mysql-test/r/fulltext_distinct.result10
-rw-r--r--mysql-test/t/fulltext_distinct.test39
-rw-r--r--pstack/Makefile.am25
-rw-r--r--pstack/aout/aout64.h475
-rw-r--r--pstack/aout/stab.def264
-rw-r--r--pstack/aout/stab_gnu.h37
-rw-r--r--pstack/bucomm.c238
-rw-r--r--pstack/bucomm.h85
-rw-r--r--pstack/budbg.h58
-rw-r--r--pstack/debug.c3509
-rw-r--r--pstack/debug.h798
-rw-r--r--pstack/demangle.h90
-rw-r--r--pstack/filemode.c266
-rw-r--r--pstack/ieee.c7602
-rw-r--r--pstack/ieee.h139
-rw-r--r--pstack/libiberty.h180
-rw-r--r--pstack/linuxthreads.c90
-rw-r--r--pstack/linuxthreads.h28
-rw-r--r--pstack/pstack.c2746
-rw-r--r--pstack/pstack.h22
-rw-r--r--pstack/pstacktrace.h24
-rw-r--r--pstack/rddbg.c462
-rw-r--r--pstack/stabs.c5082
-rw-r--r--sql/ChangeLog5
-rw-r--r--sql/Makefile.am3
-rw-r--r--sql/mysql_priv.h15
-rw-r--r--sql/mysqld.cc81
-rw-r--r--sql/net_serv.cc287
-rw-r--r--sql/share/estonian/errmsg.txt24
-rw-r--r--sql/sql_base.cc93
-rw-r--r--sql/sql_delete.cc41
-rw-r--r--sql/sql_lex.cc8
-rw-r--r--sql/sql_parse.cc92
-rw-r--r--sql/sql_show.cc127
-rw-r--r--sql/sql_update.cc46
-rw-r--r--sql/sql_yacc.yy423
-rw-r--r--sql/table.h7
87 files changed, 66678 insertions, 1398 deletions
diff --git a/BUILD/compile-pentium-mysqlfs-debug b/BUILD/compile-pentium-mysqlfs-debug
new file mode 100755
index 00000000000..2455c086532
--- /dev/null
+++ b/BUILD/compile-pentium-mysqlfs-debug
@@ -0,0 +1,13 @@
+#! /bin/sh
+
+path=`dirname $0`
+. "$path/SETUP.sh"
+
+extra_flags="$pentium_cflags $debug_cflags"
+c_warnings="$c_warnings $debug_extra_warnings"
+cxx_warnings="$cxx_warnings $debug_extra_warnings"
+extra_configs="$pentium_configs $debug_configs"
+
+extra_configs="$extra_configs --with-debug=full --with-mysqlfs --without-server --without-pstack"
+
+. "$path/FINISH.sh"
diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok
index 1c3bdac2b9f..0440a97c09e 100644
--- a/BitKeeper/etc/logging_ok
+++ b/BitKeeper/etc/logging_ok
@@ -1 +1 @@
-heikki@donna.mysql.fi
+monty@work.mysql.com
diff --git a/Makefile.am b/Makefile.am
index bfe6a8a2e43..7343f617449 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -22,15 +22,18 @@ TAR = gtar
EXTRA_DIST = INSTALL-SOURCE README \
COPYING COPYING.LIB MIRRORS
SUBDIRS = include @docs_dirs@ @readline_dir@ \
- @thread_dirs@ @sql_client_dirs@ \
- @sql_server_dirs@ scripts tests man \
- @bench_dirs@ support-files
+ @thread_dirs@ @pstack_dirs@ @sql_client_dirs@ \
+ @sql_server_dirs@ @libmysqld_dirs@ scripts tests man \
+ @bench_dirs@ support-files @fs_dirs@
# Relink after clean
-CLEANFILES = linked_client_sources linked_server_sources linked_libmysql_sources linked_libmysql_r_sources linked_include_sources
+linked_sources = linked_client_sources linked_server_sources \
+ linked_libmysql_sources linked_libmysql_r_sources \
+ linked_libmysqld_sources linked_include_sources
+CLEANFILES = $(linked_sources)
# This is just so that the linking is done early.
-config.h: linked_include_sources linked_client_sources linked_server_sources linked_libmysql_sources linked_libmysql_r_sources
+config.h: $(linked_sources)
linked_include_sources:
cd include; $(MAKE) link_sources
@@ -47,6 +50,10 @@ linked_libmysql_r_sources: linked_libmysql_sources
cd libmysql_r; $(MAKE) link_sources
echo timestamp > linked_libmysql_r_sources
+linked_libmysqld_sources:
+ cd libmysqld; $(MAKE) link_sources
+ echo timestamp > linked_libmysqld_sources
+
#avoid recursive make calls in sql directory
linked_server_sources:
cd sql; rm -f mini_client_errors.c;@LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c
diff --git a/acconfig.h b/acconfig.h
index 12024a344b0..f8dd1b52c0b 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -111,6 +111,9 @@
/* sigwait with one argument */
#undef HAVE_NONPOSIX_SIGWAIT
+/* ORBIT */
+#undef HAVE_ORBIT
+
/* pthread_attr_setscope */
#undef HAVE_PTHREAD_ATTR_SETSCOPE
@@ -230,6 +233,9 @@
#undef USE_MB
#undef USE_MB_IDENT
+/* the pstack backtrace library */
+#undef USE_PSTACK
+
/* Use MySQL RAID */
#undef USE_RAID
diff --git a/acinclude.m4 b/acinclude.m4
index cd6ded3b8cc..c9bee07c7ae 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -605,6 +605,53 @@ fi
AC_MSG_RESULT($ac_cv_conv_longlong_to_float)
])
+AC_DEFUN(MYSQL_CHECK_MYSQLFS, [
+ AC_ARG_WITH([mysqlfs],
+ [\
+ --with-mysqlfs Include the corba-based MySQL file system],
+ [mysqlfs="$withval"],
+ [mysqlfs=no])
+
+dnl Call MYSQL_CHECK_ORBIT even if mysqlfs == no, so that @orbit_*@
+dnl get substituted.
+ MYSQL_CHECK_ORBIT
+
+ if test "$mysqlfs" = "yes"
+ then
+ if test -n "$orbit_exec_prefix"
+ then
+ fs_dirs=fs
+ else
+ AC_MSG_ERROR([mysqlfs requires ORBit, the CORBA ORB])
+ fi
+ else
+ fs_dirs=
+ fi
+ AC_SUBST([fs_dirs])
+])
+
+AC_DEFUN(MYSQL_CHECK_ORBIT, [
+AC_MSG_CHECKING(for ORBit)
+if test `which orbit-config`
+then
+ orbit_exec_prefix=`orbit-config --exec-prefix`
+ orbit_includes=`orbit-config --cflags server`
+ orbit_libs=`orbit-config --libs server`
+ orbit_idl="$orbit_exec_prefix/bin/orbit-idl"
+ AC_MSG_RESULT(found!)
+ AC_DEFINE(HAVE_ORBIT)
+else
+ orbit_exec_prefix=
+ orbit_includes=
+ orbit_libs=
+ orbit_idl=
+ AC_MSG_RESULT(not found)
+fi
+AC_SUBST(orbit_includes)
+AC_SUBST(orbit_libs)
+AC_SUBST(orbit_idl)
+])
+
dnl ---------------------------------------------------------------------------
dnl Macro: MYSQL_CHECK_BDB
dnl Sets HAVE_BERKELEY_DB if inst library is found
diff --git a/client/mysql.cc b/client/mysql.cc
index 8935e459f68..66f5bcff642 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -19,9 +19,11 @@
*
* Written by:
* Michael 'Monty' Widenius
- * Andi Gutmans <andi@zend.com>
+ * Andi Gutmans <andi@zend.com>
* Zeev Suraski <zeev@zend.com>
* Jani Tolonen <jani@mysql.com>
+ * Matt Wagner <mwagner@mysql.com>
+ * Jeremy Cole <jcole@mysql.com>
*
**/
@@ -39,7 +41,7 @@
#include "my_readline.h"
#include <signal.h>
-const char *VER="11.13";
+const char *VER="11.14";
/* Don't try to make a nice table if the data is too big */
#define MAX_COLUMN_LENGTH 1024
@@ -120,7 +122,7 @@ static bool info_flag=0,ignore_errors=0,wait_flag=0,quick=0,
no_rehash=0,skip_updates=0,safe_updates=0,one_database=0,
opt_compress=0,
vertical=0,skip_line_numbers=0,skip_column_names=0,opt_html=0,
- opt_nopager=1, opt_outfile=0, no_named_cmds=1;
+ opt_xml=0,opt_nopager=1, opt_outfile=0, no_named_cmds=1;
static uint verbose=0,opt_silent=0,opt_mysql_port=0;
static my_string opt_mysql_unix_port=0;
static int connect_flag=CLIENT_INTERACTIVE;
@@ -131,6 +133,11 @@ static String glob_buffer,old_buffer;
static int wait_time = 5;
static STATUS status;
static ulong select_limit,max_join_size,opt_connect_timeout=0;
+static char *xmlmeta[] = {
+ "&", "&amp;",
+ "<", "&lt;",
+ 0, 0
+};
static char default_pager[FN_REFLEN];
char pager[FN_REFLEN], outfile[FN_REFLEN];
FILE *PAGER, *OUTFILE;
@@ -166,6 +173,9 @@ static int sql_connect(char *host,char *database,char *user,char *password,
uint silent);
static int put_info(const char *str,INFO_TYPE info,uint error=0);
static void safe_put_field(const char *pos,ulong length);
+static char *array_value(char **array, char *key);
+static char *xmlencode(char *dest, char *src);
+static void my_chomp(char *end);
static void init_pager();
static void end_pager();
static void init_tee();
@@ -250,6 +260,7 @@ static bool add_line(String &buffer,char *line,char *in_string);
static void remove_cntrl(String &buffer);
static void print_table_data(MYSQL_RES *result);
static void print_table_data_html(MYSQL_RES *result);
+static void print_table_data_xml(MYSQL_RES *result);
static void print_tab_data(MYSQL_RES *result);
static void print_table_data_vertically(MYSQL_RES *result);
static ulong start_timer(void);
@@ -313,7 +324,7 @@ int main(int argc,char *argv[])
#ifdef HAVE_READLINE
initialize_readline(my_progname);
- if (!status.batch && !quick && !opt_html)
+ if (!status.batch && !quick && !opt_html && !opt_xml)
{
/*read-history from file, default ~/.mysql_history*/
if (getenv("MYSQL_HISTFILE"))
@@ -351,7 +362,7 @@ sig_handler mysql_end(int sig)
if (connected)
mysql_close(&mysql);
#ifdef HAVE_READLINE
- if (!status.batch && !quick && ! opt_html)
+ if (!status.batch && !quick && !opt_html && !opt_xml)
{
/* write-history */
if (verbose)
@@ -396,6 +407,7 @@ static struct option long_options[] =
{"force", no_argument, 0, 'f'},
{"help", no_argument, 0, '?'},
{"html", no_argument, 0, 'H'},
+ {"xml", no_argument, 0, 'X'},
{"host", required_argument, 0, 'h'},
{"ignore-spaces", no_argument, 0, 'i'},
{"no-auto-rehash",no_argument, 0, 'A'},
@@ -490,6 +502,7 @@ static void usage(int version)
-i, --ignore-space Ignore space after function names.\n\
-h, --host=... Connect to host.\n\
-H, --html Produce HTML output.\n\
+ -X, --xml Produce XML output.\n\
-L, --skip-line-numbers\n\
Don't write line number for errors.\n");
#ifndef __WIN__
@@ -564,7 +577,7 @@ static int get_options(int argc, char **argv)
set_all_changeable_vars(changeable_vars);
while ((c=getopt_long(argc,argv,
- "?ABCD:LfgGHinNoqrstTU::vVw::WEe:h:O:P:S:u:#::p::",
+ "?ABCD:LfgGHXinNoqrstTU::vVw::WEe:h:O:P:S:u:#::p::",
long_options, &option_index)) != EOF)
{
switch(c) {
@@ -676,6 +689,7 @@ static int get_options(int argc, char **argv)
case 'G': no_named_cmds=0; break;
case 'g': no_named_cmds=1; break;
case 'H': opt_html=1; break;
+ case 'X': opt_xml=1; break;
case 'i': connect_flag|= CLIENT_IGNORE_SPACE; break;
case 'B':
if (!status.batch)
@@ -1433,6 +1447,8 @@ com_go(String *buffer,char *line __attribute__((unused)))
init_pager();
if (opt_html)
print_table_data_html(result);
+ else if (opt_xml)
+ print_table_data_xml(result);
else if (vertical)
print_table_data_vertically(result);
else if (opt_silent && verbose <= 2 && !output_tables)
@@ -1635,6 +1651,49 @@ print_table_data_html(MYSQL_RES *result)
}
+static void
+print_table_data_xml(MYSQL_RES *result)
+{
+ MYSQL_ROW cur;
+ MYSQL_FIELD *fields;
+
+ mysql_field_seek(result,0);
+
+ char *statement;
+ statement=(char*) my_malloc(strlen(glob_buffer.ptr())*5+1, MYF(MY_WME));
+ xmlencode(statement, (char*) glob_buffer.ptr());
+
+ (void) my_chomp(strend(statement));
+
+ tee_fprintf(PAGER,"<?xml version=\"1.0\"?>\n\n<resultset statement=\"%s\">", statement);
+
+ my_free(statement,MYF(MY_ALLOW_ZERO_PTR));
+
+ fields = mysql_fetch_fields(result);
+
+ while ((cur = mysql_fetch_row(result)))
+ {
+ (void) tee_fputs("\n <row>\n", PAGER);
+ for (uint i=0; i < mysql_num_fields(result); i++)
+ {
+ char *data;
+ ulong *lengths=mysql_fetch_lengths(result);
+ data=(char*) my_malloc(lengths[i]*5+1, MYF(MY_WME));
+ tee_fprintf(PAGER, "\t<%s>", (fields[i].name ?
+ (fields[i].name[0] ? fields[i].name :
+ " &nbsp; ") : "NULL"));
+ xmlencode(data, cur[i]);
+ safe_put_field(data, strlen(data));
+ tee_fprintf(PAGER, "</%s>\n", (fields[i].name ?
+ (fields[i].name[0] ? fields[i].name :
+ " &nbsp; ") : "NULL"));
+ my_free(data,MYF(MY_ALLOW_ZERO_PTR));
+ }
+ (void) tee_fputs(" </row>\n", PAGER);
+ }
+ (void) tee_fputs("</resultset>\n", PAGER);
+}
+
static void
print_table_data_vertically(MYSQL_RES *result)
@@ -1666,6 +1725,43 @@ print_table_data_vertically(MYSQL_RES *result)
}
}
+static char
+*array_value(char **array, char *key) {
+ int x;
+ for(x=0; array[x]; x+=2)
+ if(!strcmp(array[x], key))
+ return array[x+1];
+ return 0;
+}
+
+static char
+*xmlencode(char *dest, char *src) {
+ char *p = src;
+ char *t;
+ char s[2] = { 0, 0 };
+ *dest = 0;
+
+ do {
+ s[0] = *p;
+ if(!(t=array_value(xmlmeta, s))) t = s;
+ strcat(dest, t);
+ } while(*p++);
+ return dest;
+}
+
+static void
+my_chomp(char *end) {
+ char *mend;
+ mend = end;
+
+ do {
+ if (isspace(*mend)) {
+ *mend = '\0';
+ } else
+ mend--;
+ } while (mend && *mend);
+}
+
static void
safe_put_field(const char *pos,ulong length)
@@ -1696,7 +1792,7 @@ safe_put_field(const char *pos,ulong length)
tee_fputs("\\n", PAGER); // This too
else if (*pos == '\\')
tee_fputs("\\\\", PAGER);
- else
+ else
tee_putc(*pos, PAGER);
}
}
diff --git a/configure.in b/configure.in
index cf399baacfa..0fb841df1d3 100644
--- a/configure.in
+++ b/configure.in
@@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script.
AC_INIT(sql/mysqld.cc)
AC_CANONICAL_SYSTEM
# The Docs Makefile.am parses this line!
-AM_INIT_AUTOMAKE(mysql, 3.23.37)
+AM_INIT_AUTOMAKE(mysql, 4.0.0)
AM_CONFIG_HEADER(config.h)
PROTOCOL_VERSION=10
@@ -177,7 +177,7 @@ AC_DEFUN(AC_SYS_COMPILER_FLAG,
[
CFLAGS="[$]OLD_CFLAGS $1"
AC_TRY_RUN([int main(){exit(0);}],mysql_cv_option_$2=yes,mysql_cv_option_$2=no,mysql_cv_option_$2=no)
- ])
+ ])
CFLAGS="[$]OLD_CFLAGS"
@@ -654,6 +654,39 @@ int main()
if test -z "$atom_ops"; then atom_ops="no"; fi
AC_MSG_RESULT($atom_ops)
+
+ AC_ARG_WITH(pstack,
+ [ --without-pstack Don't use the pstack backtrace library],
+ [USE_PSTACK=$withval],
+ [USE_PSTACK=yes])
+ pstack_libs= pstack_dirs=
+ if test "$USE_PSTACK" = yes
+ then
+ have_libiberty= have_libbfd=
+ my_save_LIBS="$LIBS"
+dnl I have no idea if this is a good test - can't find docs for libiberty
+ AC_CHECK_LIB([iberty], [fdmatch],
+ [have_libiberty=yes
+ AC_CHECK_LIB([bfd], [bfd_openr], [have_libbfd=yes], , [-liberty])])
+ LIBS="$my_save_LIBS"
+
+ AC_MSG_CHECKING([for pstack libs])
+ if test x"$have_libiberty" = xyes -a x"$have_libbfd" = xyes
+ then
+ pstack_dirs='$(top_srcdir)'/pstack
+ pstack_libs="$pstack_dirs/libpstack.a -lbfd -liberty"
+ AC_SUBST([pstack_dirs])
+ AC_SUBST([pstack_libs])
+ AC_DEFINE([USE_PSTACK])
+ AC_MSG_RESULT([yes])
+dnl This check isn't needed, but might be nice to give some feedback....
+dnl AC_CHECK_HEADER(libiberty.h,
+dnl have_libiberty_h=yes,
+dnl have_libiberty_h=no)
+ else
+ AC_MSG_RESULT([no (missing libbfd)])
+ fi
+ fi
fi
# Check for gtty if termio.h doesn't exists
@@ -1581,6 +1614,27 @@ AC_ARG_WITH(server,
[with_server=yes]
)
+AC_ARG_WITH(embedded-server,
+ [ --with-embedded-server Build the embedded server (libmysqld).],
+ [with_embedded_server=$withval],
+ [with_embedded_server=no]
+)
+
+MYSQL_CHECK_MYSQLFS
+
+libmysqld_dirs=
+if test "$with_embedded_server" = "yes"
+then
+ libmysqld_dirs=libmysqld
+ # We can't build embedded library without building the server, because
+ # we depend on libmysys, libmystrings, libmyisam, etc.
+ with_server=yes
+fi
+# XXX: We need to add @libmysqld_extra_libs@ (or whatever) so that
+# mysql_config --libmysqld-libs will print out something like
+# -L/path/to/lib/mysql -lmysqld -lmyisam -lmysys -lmystrings -ldbug ...
+AC_SUBST([libmysqld_dirs])
+
# Shall we build the docs?
AC_ARG_WITH(docs,
[ --without-docs Skip building of the documentation.],
@@ -2017,13 +2071,13 @@ AC_OUTPUT(Makefile extra/Makefile mysys/Makefile isam/Makefile \
strings/Makefile regex/Makefile heap/Makefile \
bdb/Makefile \
myisam/Makefile myisammrg/Makefile \
- man/Makefile \
- readline/Makefile libmysql_r/Makefile libmysql/Makefile client/Makefile \
- sql/Makefile sql/share/Makefile \
+ man/Makefile readline/Makefile \
+ libmysql_r/Makefile libmysqld/Makefile libmysql/Makefile client/Makefile \
+ pstack/Makefile sql/Makefile sql/share/Makefile \
merge/Makefile dbug/Makefile scripts/Makefile \
include/Makefile sql-bench/Makefile \
tests/Makefile Docs/Makefile support-files/Makefile \
- mysql-test/Makefile \
+ mysql-test/Makefile fs/Makefile \
include/mysql_version.h
, , [
test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h
diff --git a/fs/CorbaFS.idl b/fs/CorbaFS.idl
new file mode 100644
index 00000000000..8fe089bd13c
--- /dev/null
+++ b/fs/CorbaFS.idl
@@ -0,0 +1,38 @@
+// -----------------------------------------------------------------------------
+// CorbaDS Module - Implement Kernel functionality in korbit
+// -----------------------------------------------------------------------------
+//
+// Main source of information:
+// http://www.cse.unsw.edu.au/~neilb/oss/linux-commentary/vfs.html
+//
+module CorbaFS {
+
+ struct dirent
+ {
+ long inode; // inode number
+ string name; // file name (null-terminated)
+ };
+
+ typedef sequence<dirent> DirEntSeq;
+ typedef sequence<octet> Buffer;
+
+ interface Inode {
+ void getStatus(out unsigned short mode, out unsigned long uid, out unsigned long gid,
+ out unsigned long size, out unsigned long inodeNum, out unsigned short numLinks,
+ out long atime, out long mtime, out long ctime);
+ void readpage(out Buffer buffer, in long size, in long offset);
+ void release();
+ };
+
+ interface FileSystem {
+ Inode getInode(in string path);
+
+ // DirectoryInode getStatus implementation must have S_IFDIR in the S_IFMT
+ // field of the mode value.
+ DirEntSeq readdir(in string path);
+
+ // SymlinkInode getStatus implementation must have S_IFLNK in the S_IFMT
+ // field of the mode value.
+ string readlink(in string filename);
+ };
+};
diff --git a/fs/Makefile.am b/fs/Makefile.am
new file mode 100644
index 00000000000..33d1acd913d
--- /dev/null
+++ b/fs/Makefile.am
@@ -0,0 +1,93 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# 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
+
+#called from the top level Makefile
+
+CFLAGS = $(ORBIT_CFLAGS) -g
+LFLAGS = $(ORBIT_LIBS)
+orbit_idl = @orbit_idl@
+orbit_includes = @orbit_includes@
+orbit_libs = @orbit_libs@
+
+DISTCLEANFILES = CorbaFS-common.* CorbaFS-stubs.* CorbaFS-skels.* CorbaFS.h
+
+MYSQLDATAdir = $(localstatedir)
+MYSQLSHAREdir = $(pkgdatadir)
+MYSQLBASEdir= $(prefix)
+INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include \
+ -I$(srcdir)/../regex \
+ -I$(srcdir) -I../include -I.. -I. \
+ -I$(srcdir) -I../include -I.. -I. \
+ $(orbit_includes)
+WRAPLIBS= @WRAPLIBS@
+libexec_PROGRAMS = mysqlcorbafsd
+noinst_PROGRAMS =mysqlfs_test
+LDADD = ../libmysql/libmysqlclient.la $(orbit_libs)
+mysqlcorbafsd_LDADD = $(LDADD) $(CXXLDFLAGS)
+noinst_HEADERS =
+mysqlfs_test_SOURCES = mysqlcorbafs_test.c CorbaFS-common.c CorbaFS-stubs.c libmysqlfs.c
+mysqlcorbafsd_SOURCES = mysqlcorbafs.c CorbaFS-skels.c database.c CorbaFS-common.c libmysqlfs.c
+
+DEFS = -DMYSQL_SERVER \
+ -DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \
+ -DDATADIR="\"$(MYSQLDATAdir)\"" \
+ -DSHAREDIR="\"$(MYSQLSHAREdir)\"" \
+ @DEFS@
+# Don't put lex_hash.h in BUILT_SOURCES as this will give infinite recursion
+BUILT_SOURCES = CorbaFS-common.c CorbaFS-stubs.c CorbaFS-skels.c CorbaFS.h
+EXTRA_DIST = $(BUILT_SOURCES)
+#YFLAGS = -d
+
+OMIT_DEPENDENCIES = pthread.h stdio.h __stdio.h stdlib.h __stdlib.h math.h\
+ __math.h time.h __time.h unistd.h __unistd.h types.h \
+ xtypes.h ac-types.h posix.h string.h __string.h \
+ errno.h socket.h inet.h dirent.h netdb.h \
+ cleanup.h cond.h debug_out.h fd.h kernel.h mutex.h \
+ prio_queue.h pthread_attr.h pthread_once.h queue.h\
+ sleep.h specific.h version.h pwd.h timers.h uio.h \
+ cdefs.h machdep.h signal.h __signal.h util.h lex.h \
+ wait.h
+
+link_sources:
+ rm -f mini_client_errors.c
+ @LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c
+
+
+# Don't update the files from bitkeeper
+%::SCCS/s.%
+
+idltargets : CorbaFS.idl
+ $(ORBIT_IDL) CorbaFS.idl
+ $(orbit_idl) CorbaFS.idl
+
+# individual rules
+
+CorbaFS-stubs.c : CorbaFS.idl
+ $(orbit_idl) CorbaFS.idl
+
+CorbaFS-common.c : CorbaFS.idl
+ $(orbit_idl) CorbaFS.idl
+
+CorbaFS-skels.c : CorbaFS.idl
+ $(orbit_idl) CorbaFS.idl
+
+#CorbaFS-client.c : CorbaFS.h
+
+#CorbaFS-server.c : CorbaFS.h
+
+CorbaFS.h : CorbaFS.idl
+ $(orbit_idl) CorbaFS.idl
+
diff --git a/fs/README b/fs/README
new file mode 100644
index 00000000000..5d86da3a7e4
--- /dev/null
+++ b/fs/README
@@ -0,0 +1,58 @@
+MySQL Filesystem
+Tõnu Samuel - tonu@mysql.com
+Some additional information is available on http://no.spam.ee/~tonu/mysqlfs.html
+
+WARNING: Experimental code and known to crash computer.
+
+Instructions, how to get this stuff working:
+1. Make sure you have ORBit, includeing development libraries installed. They should be version 0.5.3 or later.
+- I am lazy man and use default ones included with my RedHat:
+ [root@localhost /root]# rpm -qa | grep ORBit
+ ORBit-0.5.3-2
+ ORBit-devel-0.5.3-2
+ [root@localhost /root]#
+
+2. Prepare kernel to include korbit:
+- Get Linux 2.4.1 kernel source. (very possibly this patch works on 2.4.0 without modifications too)
+- unpack it
+- apply patch named "korbit-kernel-2.4.1-patch" on it.
+- make menuconfig
+- In section "Networking options":
+ ...
+ [*] Kernel ORB (EXPERIMENTAL)
+ ...
+ <M> CORBA User-space FileSystem (EXPERIMENTAL)
+ ...
+- make dep ; make bzlilo ; make modules ; make modules_install
+- reboot
+- Execute: insmod /lib/modules/$(uname -r)/kernel/net/korbit/modules/CorbaFS/client/corba-corbafs-client.o
+ You should see "gethostname() = localhost". Look at known bug 3 in the end of this doc.
+
+3. Make sure MySQL server is working on your system
+- On my RedHat 7.0 I execute "/etc/init.d/mysqld start"
+
+4. Prepare MySQL FS daemon
+- Get MySQL 4.0 from repository OR get MySQL FS source from http://no.spam.ee/~tonu/mysqlfs.html
+- unpack it. In MySQL 4.0 source this is located in directory named "fs". cd into it.
+- make
+- Execute command "./RunServer"
+
+5. mount MySQL server to disk tree
+- Execute command "mkdir /mnt/mysql"
+- Execute command "mount -t corbafs -o `cat /tmp/mysqlcorbafs.ior` none /mnt/mysql/"
+- Check you SQL server content by executing "ls -la /mnt/mysql/"
+
+Known bugs:
+
+1. User bugs. fix user ;)
+
+2. MySQL FS daemon will crash or will be stopped when cobrafs is mounted, then there is no way
+to unmount disks anymore. This is korbit business to handle such cases and I had no time to dig
+into korbit code.
+
+3. host name returned by gethostname() should be "localhost" or korbit will crash. Also "localhost"
+must be first string after 127.0.0.1 in /etc/hosts
+
+
+
+
diff --git a/fs/RunServer.sh b/fs/RunServer.sh
new file mode 100755
index 00000000000..22d152bb20b
--- /dev/null
+++ b/fs/RunServer.sh
@@ -0,0 +1,2 @@
+.libs/mysqlcorbafsd -ORBIIOPUSock=0 -ORBIIOPIPv4=1 --debug='d:t:o,~/mysqlfsd.trace' $*
+#.libs/mysqlcorbafsd -ORBIIOPUSock=0 -ORBIIOPIPv4=1 $*
diff --git a/fs/database.c b/fs/database.c
new file mode 100644
index 00000000000..2e93f87376a
--- /dev/null
+++ b/fs/database.c
@@ -0,0 +1,629 @@
+/* Copyright (C) 2000 db AB & db Finland AB & TCX DataKonsult AB
+ *
+ * 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
+ */
+
+/*
+ * Database functions
+ *
+ * Using these functions we emulate filesystem behaviour on top of SQL
+ * database.
+ * Written by Tõnu Samuel <tonu@please.do.not.remove.this.spam.ee>
+ *
+ * FIXME:
+ * - Direct handling of database handlers without SQL parsing overhead
+ * - connection pool
+ * - configurable function name/file name mappings
+ */
+
+
+#include "libmysqlfs.h"
+#include "mysqlcorbafs.h"
+#include <unistd.h>
+#include <string.h>
+#include <my_sys.h>
+
+DYNAMIC_ARRAY field_array;
+
+/*
+ * ** dbConnect -- connects to the host and selects DB.
+ * ** Also checks whether the tablename is a valid table name.
+ * */
+int db_connect(char *host, char *user,char *passwd)
+{
+ DBUG_ENTER("db_connect");
+ DBUG_PRINT("enter",("host: '%s', user: '%s', passwd: '%s'", host, user, passwd));
+
+ if (verbose)
+ {
+ fprintf(stderr, "# Connecting to %s...\n", host ? host : "localhost");
+ }
+ mysql_init(&connection);
+ if (opt_compress)
+ mysql_options(&connection,MYSQL_OPT_COMPRESS,NullS);
+#ifdef HAVE_OPENSSL
+ if (opt_use_ssl)
+ mysql_ssl_set(&connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
+ opt_ssl_capath);
+#endif
+ if (!(sock= mysql_real_connect(&connection,host,user,passwd,
+ NULL,opt_mysql_port,opt_mysql_unix_port,0)))
+ {
+ DBerror(&connection, "when trying to connect");
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+} /* dbConnect */
+
+
+/*
+ * ** dbDisconnect -- disconnects from the host.
+ * */
+void db_disconnect(char *host)
+{
+ DBUG_ENTER("db_disconnect");
+ DBUG_PRINT("enter",("host: '%s'", host));
+ if (verbose)
+ fprintf(stderr, "# Disconnecting from %s...\n", host ? host : "localhost");
+ mysql_close(sock);
+ DBUG_VOID_RETURN;
+} /* dbDisconnect */
+
+#define OUTPUT(x) strcpy(buffptr,x); buffptr+=strlen(x);
+#define OUTPUT_TOP(x) strcpy(topptr,x); topptr+=strlen(x);
+#define OUTPUT_MIDDLE(x) strcpy(midptr,x); midptr+=strlen(x);
+#define OUTPUT_BOTTOM(x) strcpy(botptr,x); botptr+=strlen(x);
+#define OUTPUT_HEADER(x) strcpy(hdrptr,x); hdrptr+=strlen(x);
+
+void db_show_result(MYSQL* sock, char *b, struct format *f)
+{
+ MYSQL_ROW row;
+ MYSQL_RES *result;
+ MYSQL_FIELD *field;
+ char *buffptr;
+ char topseparator[BUFLEN]="";
+ char middleseparator[BUFLEN]="";
+ char bottomseparator[BUFLEN]="";
+ char header[BUFLEN]="";
+ char *topptr=topseparator;
+ char *midptr=middleseparator;
+ char *botptr=bottomseparator;
+ char *hdrptr=header;
+ uint i,count, length;
+
+ DBUG_ENTER("db_show_result");
+ DBUG_PRINT("enter",("b: '%s', f '%x'", b, f));
+
+ result=mysql_store_result(sock);
+
+ buffptr=b;
+ OUTPUT(f->tablestart)
+
+ OUTPUT_TOP(f->leftuppercorner);
+ OUTPUT_MIDDLE(f->leftcross);
+ OUTPUT_BOTTOM(f->leftdowncorner);
+ OUTPUT_HEADER(f->headerrowstart);
+
+
+ count=mysql_num_fields(result);
+// while ((field = mysql_fetch_field(result)))
+ for(i=0 ; i < count ; ++i)
+ {
+ field = mysql_fetch_field(result);
+ length=(uint) strlen(field->name);
+ OUTPUT_HEADER(f->headercellstart);
+
+ length=max(length,field->max_length);
+ if (length < 4 && !IS_NOT_NULL(field->flags))
+ length=4; // Room for "NULL"
+ field->max_length=length;
+
+ memset(topptr,'=',field->max_length);
+ memset(midptr,'-',field->max_length);
+ memset(botptr,'=',field->max_length);
+
+ sprintf(hdrptr,"%-*s",field->max_length,field->name);
+ //num_flag[off]= IS_NUM(field->type);
+
+ topptr+=field->max_length;
+ midptr+=field->max_length;
+ botptr+=field->max_length;
+ hdrptr+=field->max_length;
+
+ if(i<count-1) {
+ OUTPUT_TOP(f->topcross);
+ OUTPUT_MIDDLE(f->middlecross);
+ OUTPUT_BOTTOM(f->bottomcross);
+ OUTPUT_HEADER(f->headercellseparator);
+ }
+ }
+ OUTPUT_TOP(f->rightuppercorner);
+ OUTPUT_MIDDLE(f->rightcross);
+ OUTPUT_BOTTOM(f->rightdowncorner);
+
+ OUTPUT_HEADER(f->headercellend);
+ OUTPUT_HEADER(f->headerrowend);
+
+ OUTPUT(topseparator);
+ OUTPUT(header);
+ OUTPUT(middleseparator);
+ while(row=mysql_fetch_row(result)) {
+ mysql_field_seek(result,0);
+
+ OUTPUT(f->contentrowstart);
+ for(i=0 ; i < mysql_field_count(sock); ++i) {
+ field = mysql_fetch_field(result);
+ OUTPUT(f->contentcellstart);
+ sprintf(buffptr,"%-*s",field->max_length,row[i]);
+ buffptr+=field->max_length;
+
+ if(i==mysql_field_count(sock))
+ {
+ OUTPUT(f->contentcellend);
+ } else {
+ OUTPUT(f->contentcellseparator);
+ }
+ }
+ OUTPUT(f->contentrowend);
+ }
+ OUTPUT(bottomseparator);
+ OUTPUT(f->tableend);
+
+ mysql_free_result(result);
+ DBUG_VOID_RETURN;
+}
+
+
+int db_function(char *b,const char *server, const char *database,const char *table,const char *field, const char *value, const char* path, struct func_st *function)
+{
+ char buff[BUFLEN];
+ int i;
+ DBUG_ENTER("db_function");
+ DBUG_PRINT("enter",("buffer: '%s', database: '%s', table: '%s', field: '%s', path: '%s'", b, database, table, field,path));
+
+ if(*database) {
+ if (mysql_select_db(sock,database))
+ {
+ printf("error when changing database to'%s'\n",database);
+ DBUG_RETURN(-1);
+ }
+ }
+
+ sprintf(buff,"%s",function->function);
+ search_and_replace("$database",database,buff);
+ search_and_replace("$table",table,buff);
+ search_and_replace("$field",field,buff);
+ search_and_replace("$value",value,buff);
+ DBUG_PRINT("info",("path: '%s'",path));
+ DBUG_PRINT("info",("sum: '%d'",(database[0] ? strlen(database)+1 : 0) +(table[0] ? strlen(table)+1 : 0) +(field[0] ? strlen(field)+1 : 0) +(value[0] ? strlen(value)+1 : 0) +1));
+ search_and_replace("$*",path+
+ (server[0] ? strlen(server)+1 : 0) +
+ (database[0] ? strlen(database)+1 : 0) +
+ (table[0] ? strlen(table)+1 : 0) +
+ (field[0] ? strlen(field)+1 : 0) +
+ (value[0] ? strlen(value)+1 : 0) +
+ function->length +
+ 1,buff);
+ DBUG_PRINT("info",("Executing constructed function query: '%s'", buff));
+ if (mysql_query(sock, buff))
+ {
+ printf("error when executing '%s'\n",buff);
+ sprintf(b,"ERROR %d: %s",mysql_error(sock),mysql_error(sock));
+ DBUG_VOID_RETURN;
+ }
+
+ db_show_result(sock, b, &Human);
+ DBUG_PRINT("info",("Returning: %s", b));
+ DBUG_RETURN(1);
+}
+
+int db_show_field(char *b,const char *database,const char *table, const char *field,const char *value, const char *param)
+{
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ char buff[BUFLEN];
+ int i=0;
+ my_string *ptr;
+ DBUG_ENTER("db_show_field");
+ DBUG_PRINT("enter",("buffer: '%s', database: '%s', table: '%s', field: '%s' value: '%s'", b, database, table, field, value));
+
+ /* We cant output fields when one of these variables is missing */
+ if (!(database[0] && table[0] && field[0]))
+ DBUG_RETURN(-1);
+
+ init_dynamic_array(&field_array, sizeof(buff), 4096, 1024);
+
+ if (mysql_select_db(sock,database))
+ {
+ printf("error when changing database to'%s'\n",database);
+ delete_dynamic(&field_array);
+ DBUG_RETURN(-1);
+ }
+
+ if(param) {
+ sprintf(buff,"%s",param);
+ } else {
+ sprintf(buff,"select %s from %s where %s='%s' LIMIT 1",field,table,field,value);
+ }
+ if (mysql_query(sock, buff))
+ {
+ printf("error when executing '%s'\n",buff);
+ delete_dynamic(&field_array);
+ DBUG_RETURN(-1);
+ }
+
+
+ db_show_result(sock,b,&Human);
+/* if(result=mysql_use_result(sock)) {
+ while(row=mysql_fetch_row(result))
+ {
+ strcpy(&b[i][BUFLEN],row[0]);
+ DBUG_PRINT("info",("field %s at %x", &b[i*BUFLEN],&b[i*BUFLEN]));
+// ptr = (*dynamic_element(&field_array,i,row[0]));
+ i++;
+ }
+ }
+// fix_filenames((char *)b);
+ mysql_free_result(result);
+ */
+ delete_dynamic(&field_array);
+ DBUG_RETURN(i);
+
+}
+int db_show_fields(char *b,const char *database,const char *table)
+{
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ MYSQL_FIELD *field;
+ char buff[BUFLEN];
+ int i=0;
+
+ DBUG_ENTER("show_fields");
+ DBUG_PRINT("enter",("buffer: '%s', database: '%s', table: '%s'", b, database, table));
+ if (mysql_select_db(sock,database))
+ {
+ printf("error when changing database to'%s'\n",database);
+ DBUG_RETURN(-1);
+ }
+ if(result=mysql_list_fields(sock,buff,NULL)) {
+
+ while(row=mysql_fetch_row(result))
+ {
+ strcpy(&b[i*BUFLEN],row[0]);
+ DBUG_PRINT("info",("field %s at %x", &b[i*BUFLEN],&b[i*BUFLEN]));
+ i++;
+ }
+ }
+ mysql_free_result(result);
+ DBUG_RETURN(i);
+}
+
+int db_show_primary_keys(char *b,const char *database, const char *table)
+{
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ char buff[BUFLEN];
+ char buff2[BUFLEN];
+ unsigned int i;
+
+ DBUG_ENTER("db_show_primary_keys");
+ DBUG_PRINT("enter",("buffer: '%s', database: '%s', table: '%s'", b, database, table));
+ if (mysql_select_db(sock,database))
+ {
+ printf("error when changing database to '%s'\n",database);
+ DBUG_RETURN(-1);
+ }
+ sprintf(buff,"show keys from %s",table);
+ if (mysql_query(sock, buff))
+ {
+ printf("error when executing '%s'\n",buff);
+ DBUG_RETURN(0);
+ }
+ buff2[0]='\0';
+ if(result=mysql_use_result(sock)) {
+ while(row=mysql_fetch_row(result)) {
+ if(!strcasecmp(row[2],"PRIMARY")) {
+ strcat(buff2,row[4]);
+ strcat(buff2,",\"_\",");
+ }
+ }
+ buff2[strlen(buff2)-5]='\0';
+ if(!buff2[0])
+ DBUG_RETURN(-1); // No PRIMARY keys in table
+ DBUG_PRINT("info",("Keys: %s<- \n", buff2));
+ } else
+ DBUG_RETURN(-1); // No keys in table
+
+ sprintf(buff,"SELECT CONCAT(%s) AS X FROM %s LIMIT 256",buff2,table);
+ if (mysql_query(sock, buff))
+ {
+ printf("error when executing '%s'\n",buff);
+ DBUG_RETURN(0);
+ }
+ i=0;
+ if(result=mysql_use_result(sock)) {
+ while(row=mysql_fetch_row(result))
+ {
+ strcpy(&b[i*BUFLEN],row[0]);
+ fix_filenames(&b[i*BUFLEN]);
+ DBUG_PRINT("info",("primarykey %s at %x, %i", &b[i*BUFLEN],&b[i*BUFLEN],i));
+ if(i++ >= MAXDIRS)
+ break;
+ }
+ }
+ mysql_free_result(result);
+ DBUG_RETURN(i);
+}
+
+
+int db_show_keys(char *b,const char *database, const char *table)
+{
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ char buff[BUFLEN];
+ int i=0;
+
+ DBUG_ENTER("show_keys");
+ DBUG_PRINT("enter",("buffer: '%s', database: '%s', table: '%s'", b, database, table));
+ if (mysql_select_db(sock,database))
+ {
+ printf("error when changing database to'%s'\n",database);
+ DBUG_RETURN(-1);
+ }
+ sprintf(buff,"show keys from %s",table);
+ if (mysql_query(sock, buff))
+ {
+ printf("error when executing '%s'\n",buff);
+ DBUG_RETURN(0);
+ }
+ if(result=mysql_use_result(sock)) {
+ while(row=mysql_fetch_row(result))
+ {
+ strcpy(&b[i*BUFLEN],row[0]);
+ DBUG_PRINT("info",("Key %s at %x", &b[i*BUFLEN],&b[i*BUFLEN]));
+ i++;
+ }
+ }
+ mysql_free_result(result);
+ DBUG_RETURN(i);
+}
+
+
+int db_show_tables(char *b,const char *database)
+{
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ char buff[BUFLEN];
+ int i=0;
+
+ DBUG_ENTER("db_show_tables");
+ DBUG_PRINT("enter",("buffer: '%s', database: '%s'", b, database));
+ if (mysql_select_db(sock,database))
+ {
+ printf("error when changing database to '%s'\n",database);
+ DBUG_RETURN(-1);
+ }
+
+ if(result=mysql_list_tables(sock,NULL)) {
+ while(row=mysql_fetch_row(result))
+ {
+ strcpy(&b[i*BUFLEN],row[0]);
+ DBUG_PRINT("info",("table %s at %x", &b[i*BUFLEN],&b[i*BUFLEN]));
+ i++;
+ }
+ }
+ mysql_free_result(result);
+ DBUG_RETURN(i);
+}
+
+/*
+ * Finds all servers we are connected to
+ * and stores them in array supplied.
+ * returns count of servers
+ */
+int
+db_show_servers(char *b,int size)
+{
+ char* bufptr;
+ char* buff[BUFLEN*2];
+ DBUG_ENTER("db_show_servers");
+ DBUG_PRINT("enter",("buffer: '%s', size: '%d'", b, size));
+ bufptr=mysql_get_host_info(sock);
+ // FIXME: Actually we need to escape prohibited symbols in filenames
+ fix_filenames(bufptr);
+ strcpy(b,bufptr);
+ DBUG_RETURN(1);
+}
+
+/*
+ * Finds all databases in server
+ * and stores them in array supplied.
+ * returns count of databases
+ */
+int
+db_show_databases(char *b,int size)
+{
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ char buff[BUFLEN];
+ int i=0;
+
+ DBUG_ENTER("db_show_databases");
+ DBUG_PRINT("enter",("buffer: '%s', size: '%d'", b, size));
+ result=mysql_list_dbs(sock,NULL);
+ while(row=mysql_fetch_row(result))
+ {
+ strcpy(&b[i*BUFLEN],row[0]);
+ DBUG_PRINT("info",("database %s at %x", &b[i*BUFLEN],&b[i*BUFLEN]));
+ i++;
+ }
+ mysql_free_result(result);
+ DBUG_RETURN(i);
+}
+
+void db_load_formats()
+{
+
+ /* In future we should read these variables
+ * from configuration file/database here */
+
+ /* HTML output */
+ HTML.tablestart="<table>\n";
+
+ HTML.headerrowstart="<tr>";
+ HTML.headercellstart="<th>";
+ HTML.headercellseparator="</th><th>";
+ HTML.headercellend="</th>";
+ HTML.headerrowend="</tr>\n";
+ HTML.headerformat=0;
+
+ HTML.leftuppercorner="";
+ HTML.rightuppercorner="";
+ HTML.leftdowncorner="";
+ HTML.rightdowncorner="";
+ HTML.topcross="";
+ HTML.middlecross="";
+ HTML.bottomcross="";
+ HTML.leftcross="";
+ HTML.rightcross="";
+ HTML.bottomcross="";
+
+ HTML.contentrowstart="<tr>";
+ HTML.contentcellstart="<td>";
+ HTML.contentcellseparator="</td><td>";
+ HTML.contentcellend="</td>";
+ HTML.contentrowend="</tr>\n";
+ HTML.headerformat=0;
+
+ HTML.footerrowstart="";
+ HTML.footercellstart="";
+ HTML.footercellseparator="";
+ HTML.footercellend="";
+ HTML.footerrowend="\n";
+ HTML.footerformat=0;
+
+ HTML.tableend="</table>\n";
+
+/* Nice to look mysql client like output */
+
+ Human.tablestart="\n";
+
+ Human.headerrowstart="| ";
+ Human.headercellstart="";
+ Human.headercellseparator=" | ";
+ Human.headercellend=" |";
+ Human.headerrowend="\n";
+ Human.headerformat=1;
+
+ Human.leftuppercorner="/=";
+ Human.rightuppercorner="=\\\n";
+ Human.leftdowncorner="\\=";
+ Human.rightdowncorner="=/\n";
+ Human.leftcross="+-";
+ Human.rightcross="-+\n";
+ Human.topcross="=T=";
+ Human.middlecross="-+-";
+ Human.bottomcross="=`=";
+
+ Human.contentrowstart="| ";
+ Human.contentcellstart="";
+ Human.contentcellseparator=" | ";
+ Human.contentcellend=" |";
+ Human.contentrowend="\n";
+ Human.contentformat=1;
+
+ Human.footerrowstart="";
+ Human.footercellstart="";
+ Human.footercellseparator="";
+ Human.footercellend="";
+ Human.footerrowend="\n";
+ Human.footerformat=1;
+
+ Human.tableend="\n";
+
+/* Comma-separated format. For machine reading */
+
+ /* XML */
+
+/*
+ tee_fprintf(PAGER,"<?xml version=\"1.0\"?>\n\n<resultset statement=\"%s\">", statement);
+ (void) tee_fputs("\n <row>\n", PAGER);
+ data=(char*) my_malloc(lengths[i]*5+1, MYF(MY_WME));
+ tee_fprintf(PAGER, "\t<%s>", (fields[i].name ?
+ (fields[i].name[0] ? fields[i].name :
+ " &nbsp; ") : "NULL"));
+ xmlencode(data, cur[i]);
+ tee_fprintf(PAGER, "</%s>\n", (fields[i].name ?
+ (fields[i].name[0] ? fields[i].name :
+ " &nbsp; ") : "NULL"));
+ </row>\n" </resultset>\n*/
+}
+
+gptr db_load_functions()
+{
+ char *functions[]={
+ "database",".tables","SHOW TABLES","0",
+ "table",".status","SHOW TABLE STATUS FROM $table","0",
+ "table",".count","SELECT COUNT(*) FROM $table","0",
+ "table",".table","SELECT * FROM $table","0",
+ "table",".check","CHECK TABLE $table","0",
+ "table",".repair","REPAIR TABLE $table","0",
+ "key",".min","SELECT MIN($key) FROM $table","0",
+ "key",".max","SELECT MAX($key) FROM $table","0",
+ "key",".avg","SELECT AVG($key) FROM $table","0",
+ "server",".uptime","SHOW STATUS like 'Uptime'","0",
+ "server",".version","SELECT VERSION()","0",
+ "server",".execute","$*","1",
+ "root",".connect","CONNECT $*","0",
+ NULL,NULL,NULL,NULL
+ };
+ char buff[BUFLEN];
+ int i=0;
+ struct func_st func;
+ DBUG_ENTER("db_load_functions");
+ init_dynamic_array(&functions_array, sizeof(struct func_st), 4096, 1024);
+ while(functions[i]) {
+ strcpy(func.type_s, functions[i]); /* Type in string: "table"` */
+ strcpy(func.filename, functions[i+1]); /* Name like it appears on FS: "count" */
+ strcpy(func.function, functions[i+2]); /* Query: "SELECT COUNT(*) FROM `%table`" */
+ func.continuous= atoi(functions[i+3]); /* Query: "If command can be continued" */
+
+ if(!strcasecmp(func.type_s,"server"))
+ func.type=SERVER_FUNCTION;
+ else if(!strcasecmp(func.type_s,"table"))
+ func.type=TABLE_FUNCTION;
+ else if(!strcasecmp(func.type_s,"key"))
+ func.type=KEY_FUNCTION;
+ else if(!strcasecmp(func.type_s,"database"))
+ func.type=DATABASE_FUNCTION;
+ else if(!strcasecmp(func.type_s,"field"))
+ func.type=FIELD_FUNCTION;
+ else if(!strcasecmp(func.type_s,"root"))
+ func.type=ROOT_FUNCTION;
+ else func.type=NONE_FUNCTION;
+
+ func.length=strlen(func.filename); /* Filename length */
+ DBUG_PRINT("info",("func.type_s: %s",func.type_s));
+ DBUG_PRINT("info",("func.filename: %s",func.filename));
+ DBUG_PRINT("info",("func.function: %s",func.function));
+ DBUG_PRINT("info",("func.type: %d",func.type));
+ DBUG_PRINT("info",("func.continuous: %d",func.continuous));
+ DBUG_PRINT("info",("i: %d",i));
+ insert_dynamic(&functions_array,(gptr)&func);
+ i+=4;
+ }
+ DBUG_RETURN((gptr)&functions_array);
+}
+
diff --git a/fs/dump.sql b/fs/dump.sql
new file mode 100644
index 00000000000..c61669cecb5
--- /dev/null
+++ b/fs/dump.sql
@@ -0,0 +1,28 @@
+# MySQL dump 8.12
+#
+# Host: localhost Database: mysqlfs
+#--------------------------------------------------------
+# Server version 3.23.33
+
+#
+# Table structure for table 'functions'
+#
+
+CREATE TABLE functions (
+ type enum('server','database','table','field','key') NOT NULL default 'server',
+ name char(20) NOT NULL default '',
+ sql char(128) NOT NULL default '',
+ PRIMARY KEY (type,name)
+) TYPE=MyISAM;
+
+#
+# Dumping data for table 'functions'
+#
+
+INSERT INTO functions VALUES ('server','uptime','SHOW STATUS like \'Uptime\'');
+INSERT INTO functions VALUES ('server','version','SELECT VERSION()');
+INSERT INTO functions VALUES ('table','count','SELECT COUNT(*) FROM `%table`');
+INSERT INTO functions VALUES ('key','min','SELECT MIN(%key) FROM `%table`');
+INSERT INTO functions VALUES ('key','max','SELECT MAX(%key) FROM `%table`');
+INSERT INTO functions VALUES ('key','avg','SELECT AVG(%key) FROM `%table`');
+
diff --git a/fs/korbit-kernel-2.4.1-patch b/fs/korbit-kernel-2.4.1-patch
new file mode 100644
index 00000000000..d97b1dac344
--- /dev/null
+++ b/fs/korbit-kernel-2.4.1-patch
@@ -0,0 +1,35661 @@
+diff -urN linux-2.4.1/.cvsignore linux-2.4.1-korbit/.cvsignore
+--- linux-2.4.1/.cvsignore Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/.cvsignore Thu Feb 1 11:46:48 2001
+@@ -0,0 +1 @@
++makekorbit.sh
+diff -urN linux-2.4.1/KORBit.Announce linux-2.4.1-korbit/KORBit.Announce
+--- linux-2.4.1/KORBit.Announce Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/KORBit.Announce Thu Feb 1 11:46:48 2001
+@@ -0,0 +1,62 @@
++From sabre@nondot.org Fri Dec 8 15:15:43 2000
++Date: Fri, 8 Dec 2000 17:10:47 -0600 (CST)
++From: Chris Lattner <sabre@nondot.org>
++To: linux-kernel@vger.kernel.org, orbit-list@gnome.org
++Cc: korbit-cvs@lists.sourceforge.net
++Subject: ANNOUNCE: Linux Kernel ORB: kORBit
++
++
++This email is here to announce the availability of a port of ORBit (the
++GNOME ORB) to the Linux kernel. This ORB, named kORBit, is available from
++our sourceforge web site (http://korbit.sourceforge.net/). A kernel ORB
++allows you to write kernel extensions in CORBA and have the kernel call
++into them, or to call into the kernel through CORBA. This opens the door
++to a wide range of experiments/hacks:
++
++* We can now write device drivers in perl, and let them run on the iMAC
++ across the hall from you. :)
++* Through the use of a LD_PRELOAD'd syscall wrapper library, you can
++ forward system calls through CORBA to an arbitrary local/remote machine.
++* CORBA servers are implemented as Linux kernel modules, so they may be
++ dynamically loaded or unloaded from a running system at any time. CORBA
++ servers expose their IOR's through a /proc/corba filesystem.
++* Filesystems may be implemented as remote CORBA objects and mounted on
++ the local machine, by using 'mount -t corbafs -o IOR:... none /mnt/corba'
++
++This are just some of the features available _RIGHT_NOW_ that are
++supported by kORBit. I'm sure that YOU can think of many more.
++
++Implementation:
++We implemented this port by providing a user->kernel mapping layer that
++consists of providing standard system header files for the "user" code to
++#include. In these header files, we do the mapping required. For
++example, we implement a <stdio.h> that #defines printf to printk (as a
++trivial example). Only user level code sees or uses these wrappers... all
++of our modifications to the Linux kernel are contained within the
++linux/net/korbit subdirectory.
++
++This is currently implemented with a 2.4.0test10 kernel, although forward
++porting should be very easy. This project was implemented as a cs423
++semester project by Chris Lattner, Fredrik Vraalsen, Andy Reitz, and Keith
++Wessel at the University of Illinois @ Urbana Champaign.
++
++Unresolved issues:
++* Our poll model is not optimial. Currently we actually do a real poll on
++ a (struct socket *) set. This causes relatively high latencies (on the
++ order 1 second, worst case) for CORBA requests. Our waitqueues are not
++ working quite as well as they should. :)
++* Security is completely unimplemented. Someone could use corba
++ interfaces to read any file on your system, for example (if the
++ CORBA-FileServer module is installed). Thus, this is really more for
++ prototyping and development than actual real world use. :)
++
++If you have any questions or comments, please feel free to contact us at:
++
++Chris Lattner, Fredrik Vraalsen, Andy Reitz, Keith Wessel
++<korbit-cvs@lists.sourceforge.net>
++
++btw, yes we are quite crazy, but what good is it to be normal and
++conformist afterall? :)
++
++
++
+diff -urN linux-2.4.1/Makefile linux-2.4.1-korbit/Makefile
+--- linux-2.4.1/Makefile Tue Jan 30 09:19:26 2001
++++ linux-2.4.1-korbit/Makefile Thu Feb 1 15:48:45 2001
+@@ -70,7 +70,7 @@
+ # images. Uncomment if you want to place them anywhere other than root.
+ #
+
+-#export INSTALL_PATH=/boot
++export INSTALL_PATH=/boot
+
+ #
+ # INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory
+diff -urN linux-2.4.1/README.korbit linux-2.4.1-korbit/README.korbit
+--- linux-2.4.1/README.korbit Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/README.korbit Thu Feb 1 11:46:48 2001
+@@ -0,0 +1,83 @@
++ ====================
++ KORBit: A CORBA ORB
++ For The Linux Kernel
++ ====================
++
++ Submitted as a final project in CS423 by
++ Chris Lattner <lattner@uiuc.edu>,
++ Andy Reitz <areitz@uiuc.edu>,
++ Fredrik Vraalsen <vraalsen@uiuc.edu>, and
++ Keith Wessel <kwessel@uiuc.edu>
++
++ December 8, 2000
++
++
++About:
++======
++KORBit is a port of the CORBA Object Request Broker ORBit to the Linux
++kernel. For more information, see http://korbit.sourceforge.net/
++
++In order to use this code, you need to have ORBit-0.5.3 or later
++installed (including the development environment). The KORBit server
++modules make use of the ORBit IDL Compiler during the build process.
++
++Building The Code:
++==================
++In order to compile and run KORBit you need a recent 2.4.0-test
++version of the Linux kernel (KORBit is developed on 2.4.0-test10).
++
++To obtain a copy of the KORBit source code, see the webpage above.
++Once you have untar'ed the source code, copy the contents of the linux
++subdirectory of KORBit into the Linux root source directory
++(e.g. /usr/src/linux).
++
++Run your favourite configuration option for Linux (e.g. 'make
++menuconfig'). To enable KORBit support in the kernel, go into the
++'Networking options' section of the configuration and enable 'Kernel
++ORB'. Then add the various CORBA services that you wish to run in the
++kernel.
++
++NOTE: The Kernel ORB *must* be compiled statically into the kernel
++(answer 'Y') and CORBA services *must* be compiled as modules (answer
++'M') at the moment.
++
++Then compile and install the Linux kernel in the standard way, e.g.:
++
++make dep ; make clean ; make bzImage ; make modules ; make modules_install
++
++Copy System.map and arch/<i386|whatever>/boot/bzImage to the proper
++places (/boot), edit your lilo.conf, run lilo and reboot.
++
++You should now be able to use CORBA in your Linux kernel! Remember,
++this is *pre-alpha* software! Use on your own risk! Don't come to us
++crying if your machine blows up...
++
++Using Our Example KORBit Objects:
++=================================
++The "CORBA Echo Server" is effectively our "hello world" object. Once
++loaded into the kernel, module will instantiate an object that
++implements the "echoString()" interface. This method allows the client
++to send a string, which will be printed on the system console. Then,
++it will return a random number, which the client will print. Thus,
++after running this test, you will verify that two-way communication is
++working between KORBit and your ORB of choice.
++
++To insert this module into your newly-compiled kernel, type
++
++insmod /lib/modules/2.4.0-test10/kernel/net/korbit/modules/Echo/server/corba-echo-server.o
++
++Next verify that this module is actually loaded, by invoking
++"lsmod". You should see something like this:
++
++ Module Size Used by
++ corba-echo-server 3344 0 (unused)
++
++Now, you can grab the IOR to this object by typing "cat
++/proc/corba/echo-server". Now, you need to build the echo client,
++which will use this IOR in order to connect to the echo server. This
++can be accomplished by simply changing to the
++"/usr/src/linux/net/korbit/modules/Echo/client" directory, and then
++typing "make". Once finished, simply type "./echo-client `cat
++/proc/corba/echo-server`", and then cross your fingers!
++
++
+diff -urN linux-2.4.1/Rules.make linux-2.4.1-korbit/Rules.make
+--- linux-2.4.1/Rules.make Sat Dec 30 00:07:19 2000
++++ linux-2.4.1-korbit/Rules.make Thu Feb 1 15:46:07 2001
+@@ -222,9 +222,9 @@
+
+ $(MODINCL)/%.ver: %.c
+ @if [ ! -r $(MODINCL)/$*.stamp -o $(MODINCL)/$*.stamp -ot $< ]; then \
+- echo '$(CC) $(CFLAGS) -E -D__GENKSYMS__ $<'; \
++ echo '$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E -D__GENKSYMS__ $<'; \
+ echo '| $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp'; \
+- $(CC) $(CFLAGS) -E -D__GENKSYMS__ $< \
++ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E -D__GENKSYMS__ $< \
+ | $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp; \
+ if [ -r $@ ] && cmp -s $@ $@.tmp; then echo $@ is unchanged; rm -f $@.tmp; \
+ else echo mv $@.tmp $@; mv -f $@.tmp $@; fi; \
+diff -urN linux-2.4.1/korbit.patch linux-2.4.1-korbit/korbit.patch
+--- linux-2.4.1/korbit.patch Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/korbit.patch Thu Feb 1 11:46:48 2001
+@@ -0,0 +1,43 @@
++--- linux/Rules.make.orig Wed Jan 31 22:50:40 2001
+++++ linux/Rules.make Thu Feb 1 01:39:46 2001
++@@ -222,9 +222,9 @@
++
++ $(MODINCL)/%.ver: %.c
++ @if [ ! -r $(MODINCL)/$*.stamp -o $(MODINCL)/$*.stamp -ot $< ]; then \
++- echo '$(CC) $(CFLAGS) -E -D__GENKSYMS__ $<'; \
+++ echo '$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E -D__GENKSYMS__ $<'; \
++ echo '| $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp'; \
++- $(CC) $(CFLAGS) -E -D__GENKSYMS__ $< \
+++ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E -D__GENKSYMS__ $< \
++ | $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp; \
++ if [ -r $@ ] && cmp -s $@ $@.tmp; then echo $@ is unchanged; rm -f $@.tmp; \
++ else echo mv $@.tmp $@; mv -f $@.tmp $@; fi; \
++--- linux/net/Config.in.orig Wed Jan 31 22:39:32 2001
+++++ linux/net/Config.in Thu Feb 1 01:40:02 2001
++@@ -30,6 +30,7 @@
++ fi
++ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
++ source net/khttpd/Config.in
+++ source net/korbit/Config.in
++ fi
++ fi
++ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
++--- linux/net/Makefile.orig Thu Feb 1 01:41:42 2001
+++++ linux/net/Makefile Thu Feb 1 01:41:35 2001
++@@ -7,7 +7,7 @@
++
++ O_TARGET := network.o
++
++-mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda atm netlink sched
+++mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda atm netlink sched korbit
++ export-objs := netsyms.o
++
++ subdir-y := core ethernet
++@@ -27,6 +27,7 @@
++ endif
++
++ subdir-$(CONFIG_KHTTPD) += khttpd
+++subdir-$(CONFIG_KORBIT) += korbit
++ subdir-$(CONFIG_NETLINK) += netlink
++ subdir-$(CONFIG_PACKET) += packet
++ subdir-$(CONFIG_NET_SCHED) += sched
+diff -urN linux-2.4.1/makekorbit.sh linux-2.4.1-korbit/makekorbit.sh
+--- linux-2.4.1/makekorbit.sh Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/makekorbit.sh Thu Feb 1 11:46:48 2001
+@@ -0,0 +1,4 @@
++#!/bin/sh
++
++make CFLAGS="-D__KERNEL__ -I`pwd`/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -march=k6 -DHAVE_CONFIG_H -DHAVE_UNISTD_H -I. -I.. -I../include -nostdinc" -C net/korbit TOPDIR=`pwd`
++
+diff -urN linux-2.4.1/net/CVS/Entries linux-2.4.1-korbit/net/CVS/Entries
+--- linux-2.4.1/net/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/CVS/Entries Thu Feb 1 11:46:49 2001
+@@ -0,0 +1 @@
++D
+diff -urN linux-2.4.1/net/CVS/Entries.Log linux-2.4.1-korbit/net/CVS/Entries.Log
+--- linux-2.4.1/net/CVS/Entries.Log Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/CVS/Entries.Log Thu Feb 1 11:46:49 2001
+@@ -0,0 +1 @@
++A D/korbit////
+diff -urN linux-2.4.1/net/CVS/Repository linux-2.4.1-korbit/net/CVS/Repository
+--- linux-2.4.1/net/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/CVS/Repository Thu Feb 1 11:46:49 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net
+diff -urN linux-2.4.1/net/CVS/Root linux-2.4.1-korbit/net/CVS/Root
+--- linux-2.4.1/net/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/CVS/Root Thu Feb 1 11:46:49 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/Config.in linux-2.4.1-korbit/net/Config.in
+--- linux-2.4.1/net/Config.in Tue Oct 10 19:33:52 2000
++++ linux-2.4.1-korbit/net/Config.in Thu Feb 1 15:46:07 2001
+@@ -30,6 +30,7 @@
+ fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ source net/khttpd/Config.in
++ source net/korbit/Config.in
+ fi
+ fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+diff -urN linux-2.4.1/net/Makefile linux-2.4.1-korbit/net/Makefile
+--- linux-2.4.1/net/Makefile Sat Dec 30 00:07:24 2000
++++ linux-2.4.1-korbit/net/Makefile Thu Feb 1 15:46:07 2001
+@@ -7,7 +7,7 @@
+
+ O_TARGET := network.o
+
+-mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda atm netlink sched
++mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda atm netlink sched korbit
+ export-objs := netsyms.o
+
+ subdir-y := core ethernet
+@@ -27,6 +27,7 @@
+ endif
+
+ subdir-$(CONFIG_KHTTPD) += khttpd
++subdir-$(CONFIG_KORBIT) += korbit
+ subdir-$(CONFIG_NETLINK) += netlink
+ subdir-$(CONFIG_PACKET) += packet
+ subdir-$(CONFIG_NET_SCHED) += sched
+diff -urN linux-2.4.1/net/korbit/CVS/Entries linux-2.4.1-korbit/net/korbit/CVS/Entries
+--- linux-2.4.1/net/korbit/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/CVS/Entries Thu Feb 1 11:46:49 2001
+@@ -0,0 +1,6 @@
++/Config.in/1.3/Thu Feb 1 09:46:49 2001//
++/Makefile/1.7/Thu Feb 1 09:46:49 2001//
++/config.h/1.2/Thu Feb 1 09:46:49 2001//
++/exported_symbols.c/1.8/Thu Feb 1 09:46:49 2001//
++/korbit.h/1.2/Thu Feb 1 09:46:49 2001//
++D
+diff -urN linux-2.4.1/net/korbit/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/CVS/Entries.Log
+--- linux-2.4.1/net/korbit/CVS/Entries.Log Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/CVS/Entries.Log Thu Feb 1 11:47:15 2001
+@@ -0,0 +1,7 @@
++A D/IIOP////
++A D/ORBitutil////
++A D/include////
++A D/kglib////
++A D/modules////
++A D/orb////
++A D/sup////
+diff -urN linux-2.4.1/net/korbit/CVS/Repository linux-2.4.1-korbit/net/korbit/CVS/Repository
+--- linux-2.4.1/net/korbit/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/CVS/Repository Thu Feb 1 11:46:49 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit
+diff -urN linux-2.4.1/net/korbit/CVS/Root linux-2.4.1-korbit/net/korbit/CVS/Root
+--- linux-2.4.1/net/korbit/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/CVS/Root Thu Feb 1 11:46:49 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/Config.in linux-2.4.1-korbit/net/korbit/Config.in
+--- linux-2.4.1/net/korbit/Config.in Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/Config.in Thu Feb 1 11:46:49 2001
+@@ -0,0 +1,8 @@
++#
++# KORBit
++#
++
++#tristate ' Kernel ORB (EXPERIMENTAL)' CONFIG_KORBIT
++bool ' Kernel ORB (EXPERIMENTAL)' CONFIG_KORBIT
++
++source net/korbit/modules/Config.in
+diff -urN linux-2.4.1/net/korbit/IIOP/CVS/Entries linux-2.4.1-korbit/net/korbit/IIOP/CVS/Entries
+--- linux-2.4.1/net/korbit/IIOP/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/CVS/Entries Thu Feb 1 11:46:51 2001
+@@ -0,0 +1,15 @@
++/IIOP-config.h/1.1.1.1/Thu Feb 1 09:46:50 2001//
++/IIOP-design.txt/1.1.1.1/Thu Feb 1 09:46:50 2001//
++/IIOP-private.h/1.2/Thu Feb 1 09:46:50 2001//
++/IIOP-types.h/1.1.1.1/Thu Feb 1 09:46:50 2001//
++/IIOP.h/1.1.1.1/Thu Feb 1 09:46:50 2001//
++/Makefile/1.4/Thu Feb 1 09:46:51 2001//
++/connection.c/1.19/Thu Feb 1 09:46:51 2001//
++/encoders.c/1.1.1.1/Thu Feb 1 09:46:51 2001//
++/giop-msg-buffer.c/1.12/Thu Feb 1 09:46:51 2001//
++/giop-msg-buffer.h/1.1.1.1/Thu Feb 1 09:46:51 2001//
++/iiop-encoders.h/1.1.1.1/Thu Feb 1 09:46:51 2001//
++/iiop-endian.c/1.1.1.1/Thu Feb 1 09:46:51 2001//
++/iiop-endian.h/1.1.1.1/Thu Feb 1 09:46:51 2001//
++/iiop-endianP.h/1.1.1.1/Thu Feb 1 09:46:51 2001//
++D
+diff -urN linux-2.4.1/net/korbit/IIOP/CVS/Repository linux-2.4.1-korbit/net/korbit/IIOP/CVS/Repository
+--- linux-2.4.1/net/korbit/IIOP/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/CVS/Repository Thu Feb 1 11:46:50 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/IIOP
+diff -urN linux-2.4.1/net/korbit/IIOP/CVS/Root linux-2.4.1-korbit/net/korbit/IIOP/CVS/Root
+--- linux-2.4.1/net/korbit/IIOP/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/CVS/Root Thu Feb 1 11:46:49 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/IIOP/IIOP-config.h linux-2.4.1-korbit/net/korbit/IIOP/IIOP-config.h
+--- linux-2.4.1/net/korbit/IIOP/IIOP-config.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/IIOP-config.h Thu Feb 1 11:46:50 2001
+@@ -0,0 +1,5 @@
++/* The size of the chunks that are used for indirect pieces of messages.
++ Too low, and you'll have a lot of malloc overhead. Too high, and you'll
++ get wasted mem.
++*/
++#define GIOP_INDIRECT_CHUNK_SIZE 1024
+diff -urN linux-2.4.1/net/korbit/IIOP/IIOP-design.txt linux-2.4.1-korbit/net/korbit/IIOP/IIOP-design.txt
+--- linux-2.4.1/net/korbit/IIOP/IIOP-design.txt Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/IIOP-design.txt Thu Feb 1 11:46:50 2001
+@@ -0,0 +1,14 @@
++
++void Hello_hello(CORBA_Object anobj, const char *arg1, CORBA_Environment *ev)
++
++If we're doing a local call (i.e. shared library object activation),
++just do it.
++
++If we're doing a remote call, we need to setup generic header
++(utilfunc), setup request header (utilfunc), encode arguments (stubs),
++send the message headers & body (utilfunc) and wait for a reply (XXX
++define more clearly). When we get the reply, we need to read the
++reply(utilfunc), decode the return value & out/inout arguments(stubs)
++& fill them in (or decode the exception that resulted (utilfunc)), and
++return.
++
+diff -urN linux-2.4.1/net/korbit/IIOP/IIOP-private.h linux-2.4.1-korbit/net/korbit/IIOP/IIOP-private.h
+--- linux-2.4.1/net/korbit/IIOP/IIOP-private.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/IIOP-private.h Thu Feb 1 11:46:50 2001
+@@ -0,0 +1,46 @@
++#ifndef IIOP_PRIVATE_H
++#define IIOP_PRIVATE_H 1
++
++
++#include "config.h"
++
++#if defined(HAVE_POLL) && defined(I_WANT_POLL)
++#define USE_POLL
++#else
++#undef USE_POLL
++#endif
++
++#ifdef HAVE_SYS_POLL_H
++#include <sys/poll.h>
++#endif
++
++#include <sys/time.h>
++#include <sys/types.h>
++#include <unistd.h>
++
++#include <glib.h>
++
++typedef struct {
++ GList *list;
++ gboolean connection_list_changed;
++#ifndef __KORBIT__
++ GPtrArray *fd_to_connection_mapping;
++#else /* __KORBIT__ */
++ GHashTable *fd_to_connection_mapping;
++#endif /* __KORBIT__ */
++# ifdef USE_POLL
++ GArray *pollset;
++# else
++ fd_set selectset_rd, selectset_ex;
++# endif
++ int max_fd;
++} GIOPConnectionList;
++
++extern GIOPConnectionList giop_connection_list;
++
++/* If you get a buffer that you didn't want, add it to the list! */
++void giop_received_list_push(GIOPRecvBuffer *recv_buffer);
++GIOPRecvBuffer *giop_received_list_pop(void);
++
++
++#endif
+diff -urN linux-2.4.1/net/korbit/IIOP/IIOP-types.h linux-2.4.1-korbit/net/korbit/IIOP/IIOP-types.h
+--- linux-2.4.1/net/korbit/IIOP/IIOP-types.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/IIOP-types.h Thu Feb 1 11:46:50 2001
+@@ -0,0 +1,76 @@
++#ifndef IIOP_TYPES_H
++#define IIOP_TYPES_H 1
++
++/* XXX todo sync this up with basic_types.h if needed */
++#include <unistd.h>
++#include <netinet/in.h>
++#include <sys/un.h>
++
++#include <ORBitutil/basic_types.h>
++
++typedef enum {
++ GIOP_CONNECTION_SERVER, /* Not a real connection to any place - just
++ listening */
++ GIOP_CONNECTION_CLIENT
++} GIOPConnectionClass;
++
++typedef struct _GIOPConnection GIOPConnection;
++struct _GIOPConnection {
++ enum { GIOP_CONNECTION_NONE, GIOP_CONNECTION_IIOP } connection_type;
++ void (*destroy_func)(GIOPConnection *connection);
++
++ gint refcount;
++ GIOPConnectionClass connection_class;
++
++ int fd;
++
++ /* You can access these if you wish. */
++ gpointer orb_data;
++ gpointer user_data;
++ /* end accessable stuff */
++
++ guchar is_valid, was_initiated, is_auth;
++
++ gpointer incoming_msg; /* GIOPRecvBuffer */
++};
++
++#define GIOP_CONNECTION(x) ((GIOPConnection *)(x))
++#define GIOP_CONNECTION_GET_FD(x) (GIOP_CONNECTION((x))->fd)
++
++typedef enum { IIOP_IPV4, IIOP_IPV6, IIOP_USOCK } IIOPConnectionType;
++
++typedef struct {
++ GIOPConnection giop_connection;
++
++ gboolean is_serversock;
++ IIOPConnectionType icnxtype;
++ union {
++ struct {
++ char *hostname;
++ struct sockaddr_in location;
++ } ipv4;
++ struct sockaddr_un usock;
++ /* Yes this is a config.h define, and no it doesn't matter,
++ because this structure should only be used internally anyways */
++#ifdef HAVE_IPV6
++ struct {
++ char *hostname;
++ struct sockaddr_in6 location;
++ } ipv6;
++#endif
++ } u;
++} IIOPConnection;
++
++#define IIOP_CONNECTION(x) ((IIOPConnection *)(x))
++
++#if defined(DEBUG_sopwith_connection_refcounting)
++#define giop_connection_ref(x) G_STMT_START{ (GIOP_CONNECTION(x)->refcount++); g_print("! reffing fd %d in " __PRETTY_FUNCTION__ ":%d to %d\n", GIOP_CONNECTION_GET_FD(x), __LINE__, GIOP_CONNECTION(x)->refcount); }G_STMT_END
++
++#define giop_connection_unref(x) G_STMT_START{ GIOP_CONNECTION(x)->refcount--; g_print("! dereffing fd %d in " __PRETTY_FUNCTION__ ":%d to %d\n", GIOP_CONNECTION_GET_FD(x), __LINE__, GIOP_CONNECTION(x)->refcount); if(GIOP_CONNECTION(x)->refcount <= 0) giop_connection_free(x); }G_STMT_END
++#else
++#define giop_connection_ref(x) G_STMT_START{ (GIOP_CONNECTION(x)->refcount++); }G_STMT_END
++
++#define giop_connection_unref(x) G_STMT_START{ GIOP_CONNECTION(x)->refcount--; if(GIOP_CONNECTION(x)->refcount <= 0) giop_connection_free(x); }G_STMT_END
++#endif
++
++#endif /* IIOP_TYPES_H */
+diff -urN linux-2.4.1/net/korbit/IIOP/IIOP.h linux-2.4.1-korbit/net/korbit/IIOP/IIOP.h
+--- linux-2.4.1/net/korbit/IIOP/IIOP.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/IIOP.h Thu Feb 1 16:19:47 2001
+@@ -0,0 +1,52 @@
++#ifndef IIOP_H
++#define IIOP_H 1
++
++#include <unistd.h>
++#include <ORBitutil/util.h>
++#include "IIOP-config.h"
++#include "IIOP-types.h"
++#include "giop-msg-buffer.h"
++#include "iiop-encoders.h"
++#include "iiop-endian.h"
++
++/* We don't speak GIOP 1.0, sosumi */
++#define GIOP_1_1
++
++
++void giop_init(const char *argv0);
++
++/* You use this to get a pointer to a new (or existing) connection
++ that has the specified host/port characteristics */
++IIOPConnection *iiop_connection_get(const char *host, gushort port,
++ gboolean existing_only);
++/* Similar, but for UNIX sockets */
++IIOPConnection *iiop_connection_unix_get(const char *sockpath,
++ gboolean existing_only);
++
++/* gives us a local socket that other people can connect to... */
++IIOPConnection *iiop_connection_server(void);
++IIOPConnection *iiop_connection_server_ipv6(void);
++IIOPConnection *iiop_connection_server_unix(const char *sockpath);
++
++void giop_main_quit(void);
++void giop_main(void); /* main loop for the program if none other is given,
++ and also used while waiting for a reply */
++void giop_main_iterate(gboolean blocking);
++void giop_main_handle_connection(GIOPConnection *connection);
++void giop_main_handle_connection_exception(GIOPConnection *connection);
++GIOPRecvBuffer *giop_main_next_message(gboolean blocking);
++GIOPRecvBuffer *giop_main_next_message_2(gboolean blocking,
++ GIOPConnection *monitor);
++GIOPConnection *giop_check_connections(gboolean block_for_reply);
++
++/* This assumes that the appropriate GIOP_CLOSECONNECTION message
++ has been sent to the peer */
++void giop_connection_free(GIOPConnection *connection);
++
++/* Called when a connection is created */
++extern void (*IIOPAddConnectionHandler)(GIOPConnection *newcnx);
++/* Called when a connection is about to be destroyed */
++extern void (*IIOPRemoveConnectionHandler)(GIOPConnection *oldcnx);
++extern void (*IIOPIncomingMessageHandler)(GIOPRecvBuffer *recv_buffer);
++
++#endif /* IIOP_H */
+diff -urN linux-2.4.1/net/korbit/IIOP/Makefile linux-2.4.1-korbit/net/korbit/IIOP/Makefile
+--- linux-2.4.1/net/korbit/IIOP/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/Makefile Thu Feb 1 11:46:51 2001
+@@ -0,0 +1,18 @@
++#
++# Makefile for KORBit/IIOP
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .o file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := IIOPlib.o
++
++#obj-m := $(O_TARGET)
++obj-y := connection.o encoders.o giop-msg-buffer.o iiop-endian.o
++
++
++EXTRA_CFLAGS = -D__KORBIT__ -DHAVE_CONFIG_H -I. -I.. -I../include -I../kglib -I../ORBitutil -nostdinc
++
++include $(TOPDIR)/Rules.make
+diff -urN linux-2.4.1/net/korbit/IIOP/connection.c linux-2.4.1-korbit/net/korbit/IIOP/connection.c
+--- linux-2.4.1/net/korbit/IIOP/connection.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/connection.c Thu Feb 1 19:26:07 2001
+@@ -0,0 +1,1565 @@
++#include "config.h"
++
++#if defined(HAVE_POLL) && defined(I_WANT_POLL)
++#define USE_POLL
++#else
++#undef USE_POLL
++#endif
++
++#ifndef _XOPEN_SOURCE_EXTENDED
++# define _XOPEN_SOURCE_EXTENDED 1
++# define WE_DEFINED_XOPEN_SOURCE_EXTENDED 1
++#endif
++#include "iiop-endianP.h"
++#ifdef WE_DEFINED_XOPEN_SOURCE_EXTENDED
++# undef _XOPEN_SOURCE_EXTENDED
++#endif
++#include "IIOP.h"
++#include "IIOP-private.h"
++#include "giop-msg-buffer.h"
++#include <stdlib.h>
++#include <unistd.h>
++#ifdef ORBIT_DEBUG
++#include <errno.h>
++#endif
++#include <sys/types.h>
++#include <fcntl.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#ifndef _XOPEN_SOURCE_EXTENDED
++# define _XOPEN_SOURCE_EXTENDED 1
++#endif
++#include <arpa/inet.h>
++#include <netdb.h>
++#ifdef WE_DEFINED_XOPEN_SOURCE_EXTENDED
++# undef _XOPEN_SOURCE_EXTENDED
++#endif
++#include <ctype.h>
++#include <string.h>
++#include <sys/time.h>
++#include <sys/ioctl.h>
++#include <signal.h>
++#include <syslog.h>
++#include <stdio.h>
++
++/*
++#ifdef O_NONBLOCK
++#undef O_NONBLOCK
++#endif
++#define O_NONBLOCK 0
++*/
++
++#if defined(HAVE_TCPD_H) && defined(HAVE_HOSTS_ACCESS)
++#include <tcpd.h>
++#endif
++
++#if 0
++#include <malloc.h>
++
++static struct mallinfo mi1, mi2;
++
++#define AM() mi1 = mallinfo();
++#define PM(x) mi2 = mallinfo(); printf(x ": used %d, now %d\n", \
++mi2.uordblks - mi1.uordblks, mi2.uordblks);
++#endif
++
++#ifdef HAVE_POLL
++#include <sys/poll.h>
++#endif
++
++#ifndef SUN_LEN
++/* This system is not POSIX.1g. */
++#define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
++ + strlen ((ptr)->sun_path))
++#endif
++
++void (*IIOPAddConnectionHandler)(GIOPConnection *newcnx) = NULL;
++void (*IIOPRemoveConnectionHandler)(GIOPConnection *oldcnx) = NULL;
++void (*IIOPIncomingMessageHandler)(GIOPRecvBuffer *recv_buffer) = NULL;
++
++static void giop_connection_add_to_list (GIOPConnection *cnx);
++static void giop_connection_remove_from_list (GIOPConnection *cnx);
++
++static void iiop_init (void);
++static void iiop_connection_server_accept (GIOPConnection *connection);
++static void iiop_connection_destroy (IIOPConnection *connection);
++static IIOPConnection *iiop_connection_new (const char *host, gushort port);
++static IIOPConnection *iiop_connection_unix_new (const char *sockpath);
++static void iiop_unlink_unix_sockets (void);
++
++DEFINE_LOCK(giop_connection_list);
++GIOPConnectionList giop_connection_list;
++static GSList *iiop_unix_socket_list = NULL;
++
++#if defined(HAVE_HOSTS_ACCESS) && defined (HAVE_TCPD_H)
++static const char *argv0_val = NULL;
++#endif
++
++struct fd_hash_elem
++{
++ guint fd;
++ GIOPConnection *cnx;
++};
++
++static guint fd_hash_func(gconstpointer key)
++{
++ const guint *key_ptr = (guint *)key;
++ guint result = *key_ptr >> 2;
++ return result;
++}
++
++static gint fd_compare_func(gconstpointer a, gconstpointer b)
++{
++ const guint *a_ptr = (guint *)a;
++ const guint *b_ptr = (guint *)b;
++ return *a_ptr == *b_ptr;
++}
++
++static gboolean fd_hash_clear(gpointer key, gpointer value, gpointer user_data)
++{
++ struct fd_hash_elem *el = (struct fd_hash_elem *)value;
++ g_free(el);
++ return TRUE;
++}
++
++/*
++ * giop_init
++ *
++ * Inputs: None
++ * Outputs: None
++ *
++ * Side effects: Initializes giop_connection_list
++ * Global data structures used: giop_connection_list
++ *
++ * Description: Initializes giop_connection_list. Calls
++ * giop_message_buffer_init() to initialize the
++ * message_buffer subsystem. Calls iiop_init()
++ * to perform IIOP-specific initialization.
++ */
++
++void giop_init(const char *argv0)
++{
++#ifndef __KERNEL__
++ struct sigaction mypipe;
++#endif
++ g_assert(sizeof(GIOPMessageHeader) == 12);
++
++#if defined(HAVE_HOSTS_ACCESS) && defined (HAVE_TCPD_H)
++ argv0_val = g_strdup(g_basename(argv0)); /* For TCP wrappers */
++#endif
++
++#ifndef __KERNEL__
++ memset(&mypipe, '\0', sizeof(mypipe));
++ mypipe.sa_handler = SIG_IGN;
++
++ sigaction(SIGPIPE, &mypipe, NULL);
++#endif
++
++ giop_message_buffer_init();
++
++ INIT_LOCK(giop_connection_list);
++
++ giop_connection_list.list = NULL;
++ giop_connection_list.connection_list_changed = FALSE;
++
++#ifdef USE_POLL
++ giop_connection_list.pollset = g_array_new(FALSE, FALSE,
++ sizeof(struct pollfd));
++#else
++ FD_ZERO(&giop_connection_list.selectset_rd);
++ FD_ZERO(&giop_connection_list.selectset_ex);
++#endif
++
++#ifndef __KORBIT__
++ giop_connection_list.fd_to_connection_mapping = g_ptr_array_new();
++#else
++ giop_connection_list.fd_to_connection_mapping =
++ g_hash_table_new(&fd_hash_func,
++ &fd_compare_func);
++#endif
++
++ /*
++ * This also needs to do any transport-specific initialization
++ * as appropriate
++ */
++ iiop_init();
++}
++
++/*** giop_connection_init
++ *
++ * Inputs: 'giop_connection' - memory region allocated for use as a
++ * GIOPConnection.
++ * 'cnxclass' - the class of connection that will be stored
++ * here (SERVER, CLIENT)
++ *
++ * Outputs: None
++ *
++ * Side effects: Initializes 'giop_connection'.
++ *
++ * Description: Basic setup of a GIOPConnection.
++ * Sets is_valid to FALSE because it is the responsibility of
++ * the transport-specific initialization routine to make
++ * a connection valid.
++ */
++
++static void giop_connection_init(GIOPConnection *giop_connection,
++ GIOPConnectionClass cnxclass)
++{
++ giop_connection->connection_type = GIOP_CONNECTION_NONE;
++ giop_connection->refcount = 0;
++ giop_connection->connection_class = cnxclass;
++ giop_connection->is_valid = FALSE;
++ giop_connection->is_auth = FALSE;
++ giop_connection->was_initiated = FALSE;
++}
++
++/*
++ * giop_connection_free
++ * Inputs: 'connection'
++ * Outputs: None
++ * Side effects: Makes the 'connection' invalid as a GIOPConnection
++ * and as a gpointer.
++ *
++ * Description: Calls giop_connection_remove_from_list() to
++ * stop the connection from being used for incoming.
++ *
++ * If a transport-specific finalization function has
++ * been provided, call it.
++ *
++ * Free the memory block at '*connection'.
++ *
++ */
++void giop_connection_free(GIOPConnection *connection)
++{
++ g_return_if_fail(connection != NULL);
++ giop_connection_remove_from_list(connection);
++
++ if(connection->is_valid && connection->destroy_func)
++ connection->destroy_func(connection);
++
++ connection->is_valid = FALSE;
++
++ if(connection->incoming_msg) {
++ GIOPRecvBuffer *buf;
++
++ buf = connection->incoming_msg;
++ connection->incoming_msg = NULL;
++ giop_recv_buffer_unuse(buf);
++ }
++
++ g_free(connection);
++}
++
++/*
++ * giop_connection_list_recreate
++ *
++ * Inputs: None
++ * Outputs: None
++ *
++ * Side effects: giop_connection_list changes.
++ *
++ * Global data structures used: giop_connection_list
++ *
++ * Description:
++ * When new connections are added to giop_connection_list.list,
++ * the data structures passed to poll() or select() (OS-dependant)
++ * must be recreated to match this list.
++ *
++ * [We do this at add-connection/remove-connection time
++ * instead of every time a poll/select is done in order to
++ * speed things up a little]
++ *
++ * This function reinitializes the OS-specific file
++ * descriptor data structure and then adds all the file
++ * descriptors in the list to it.
++ *
++ * It also regenerates the array that maps file descriptors
++ * into GIOPConnection*'s
++ *
++ */
++static void
++giop_connection_list_recreate(void)
++{
++ int curfd;
++ GList *item;
++ GIOPConnection *cnx;
++#ifdef USE_POLL
++ struct pollfd new_poll;
++
++ new_poll.revents = 0;
++#endif
++
++ giop_connection_list.max_fd = 0;
++ for(item = giop_connection_list.list; item; item = g_list_next(item))
++ {
++ cnx = item->data;
++ curfd = GIOP_CONNECTION_GET_FD(cnx);
++
++ if(curfd > giop_connection_list.max_fd)
++ giop_connection_list.max_fd = curfd;
++ }
++
++#ifndef __KORBIT__
++ g_ptr_array_set_size(giop_connection_list.fd_to_connection_mapping,
++ giop_connection_list.max_fd + 1);
++#else
++ g_hash_table_foreach_remove(giop_connection_list.fd_to_connection_mapping,
++ fd_hash_clear,
++ NULL);
++#endif
++
++#ifdef USE_POLL
++ g_array_set_size(giop_connection_list.pollset, 0);
++#else
++ FD_ZERO(&giop_connection_list.selectset_rd);
++ FD_ZERO(&giop_connection_list.selectset_ex);
++#endif
++
++ for(item = giop_connection_list.list; item; item = g_list_next(item))
++ {
++ struct fd_hash_elem *el;
++
++ cnx = item->data;
++ curfd = GIOP_CONNECTION_GET_FD(cnx);
++
++#ifndef __KORBIT__
++ giop_connection_list.fd_to_connection_mapping->pdata[curfd] = cnx;
++#else
++ el = g_new(struct fd_hash_elem, 1);
++ el->fd = curfd;
++ el->cnx = cnx;
++ g_hash_table_insert(giop_connection_list.fd_to_connection_mapping,
++ &(el->fd),
++ el);
++#endif
++
++# ifdef USE_POLL
++ new_poll.fd = curfd;
++ new_poll.events = POLLIN|POLLPRI;
++ g_array_append_val(giop_connection_list.pollset,
++ new_poll);
++# else
++ FD_SET(curfd, &giop_connection_list.selectset_rd);
++ FD_SET(curfd, &giop_connection_list.selectset_ex);
++# endif
++ }
++}
++
++/*
++ * giop_connection_add_to_list
++ *
++ * Inputs: 'cnx' - a GIOPConnection that the user wishes added to the list
++ * Outputs: None
++ *
++ * Side effects: Modifies giop_connection_list
++ * Global data structures used: giop_connection_list
++ * Bugs: Does not check for duplicate additions.
++ *
++ * Description:
++ * Adds a connection to the list of active connections.
++ */
++static void
++giop_connection_add_to_list(GIOPConnection *cnx)
++{
++ g_return_if_fail(cnx->is_valid == FALSE);
++
++ cnx->is_valid = TRUE;
++
++ GET_LOCK(giop_connection_list);
++ giop_connection_list.list = g_list_prepend(giop_connection_list.list, cnx);
++
++ giop_connection_list_recreate();
++
++ RELEASE_LOCK(giop_connection_list);
++
++ if(IIOPAddConnectionHandler)
++ IIOPAddConnectionHandler(cnx);
++
++ giop_connection_ref(cnx);
++}
++
++/*
++ * giop_connection_remove_from_list
++ *
++ * Inputs: 'cnx' - a GIOPConnection that the user wishes
++ * Outputs: None
++ *
++ * Side effects: Modifies giop_connection_list
++ * Global data structures used: giop_connection_list
++ *
++ * Description:
++ * Removes a connection from the list of active connections.
++ * Calls the library user's "I removed connection" handler if it
++ * exists.
++ *
++ * Bugs: Does not check for duplicate removals. This may not be "bad" though.
++ */
++void
++giop_connection_remove_from_list(GIOPConnection *cnx)
++{
++ GList *link;
++
++ GET_LOCK(giop_connection_list);
++
++ link = g_list_find(giop_connection_list.list, cnx);
++
++ if(!link)
++ goto out;
++
++ if(IIOPRemoveConnectionHandler && cnx->is_valid)
++ IIOPRemoveConnectionHandler(cnx);
++
++ giop_connection_list.list = g_list_remove_link(giop_connection_list.list,
++ link);
++ g_list_free_1(link);
++
++ giop_connection_unref(cnx);
++
++ giop_connection_list_recreate();
++ out:
++ RELEASE_LOCK(giop_connection_list);
++}
++
++/************************************************
++ * Routines specific to the IIOP/IPv4 transport *
++ ************************************************/
++
++/*
++ * iiop_init
++ *
++ * Inputs: None
++ * Outputs: None
++ *
++ * Side effects: Initializes iiop_unix_socket_list
++ * Global data structures used: iiop_unix_socket_list
++ *
++ * Description: Initializes iiop_unix_socket_list.
++ * Registers Unix domain sockets for
++ * removal at server termination.
++ */
++static void
++iiop_init(void)
++{
++#ifndef __KERNEL__
++ g_atexit(iiop_unlink_unix_sockets);
++#endif
++}
++
++/*
++ * iiop_connection_init
++ *
++ * Inputs: 'connection' - a memory region that needs to be initialized as
++ * an 'IIOPConnection'.
++ *
++ * Side effects: initializes 'connection'
++ *
++ * Description: Performs the IIOP-specific initialization of an
++ * IIOPConnection. giop_connection_init is called.
++ *
++ */
++void
++iiop_connection_init(IIOPConnection *connection,
++ GIOPConnectionClass cnxclass,
++ IIOPConnectionType iioptype)
++{
++ giop_connection_init(GIOP_CONNECTION(connection), cnxclass);
++
++ GIOP_CONNECTION(connection)->connection_type =
++ GIOP_CONNECTION_IIOP;
++
++ GIOP_CONNECTION(connection)->destroy_func =
++ (void (*)(GIOPConnection *))iiop_connection_destroy;
++
++ connection->icnxtype = iioptype;
++}
++
++/*
++ * iiop_connection_from_fd
++ *
++ * Inputs: 'fd' - a file descriptor that attention should be paid to
++ * Outputs: 'fd_cnx' - the created connection
++ *
++ * Description: This is intended to be used on a file descriptor
++ * that has been accept()'d. It creates the connection
++ * and fills in the connection information, then adds
++ * it to the active list.
++ */
++IIOPConnection *
++iiop_connection_from_fd(int fd, IIOPConnection *parent)
++{
++ IIOPConnection *fd_cnx;
++ struct hostent *hent;
++ socklen_t n;
++
++ g_assert(fd >= 0);
++
++ fd_cnx = g_new0(IIOPConnection, 1);
++
++ iiop_connection_init(fd_cnx, GIOP_CONNECTION_CLIENT, parent->icnxtype);
++
++ GIOP_CONNECTION(fd_cnx)->fd = fd;
++
++ switch(parent->icnxtype) {
++ case IIOP_IPV4:
++ n = sizeof(struct sockaddr_in);
++ if(getpeername(GIOP_CONNECTION_GET_FD(fd_cnx), (struct sockaddr *)&fd_cnx->u.ipv4.location, &n))
++ {
++ fd_cnx->u.ipv4.hostname = g_strdup("");
++ }
++ else
++ {
++ hent = gethostbyaddr((const char *)&fd_cnx->u.ipv4.location.sin_addr.s_addr, 4, AF_INET);
++ if(hent)
++ {
++ fd_cnx->u.ipv4.hostname = g_strdup(hent->h_name);
++ }
++ else
++ {
++ fd_cnx->u.ipv4.hostname = inet_ntoa(*((struct in_addr *)&fd_cnx->u.ipv4.location.sin_addr));
++ }
++ }
++ break;
++
++ case IIOP_USOCK:
++ n = sizeof(struct sockaddr_un);
++ fd_cnx->u.usock.sun_family = AF_UNIX;
++ getpeername(GIOP_CONNECTION_GET_FD(fd_cnx),
++ (struct sockaddr *)&fd_cnx->u.usock, &n);
++ break;
++
++#ifdef HAVE_IPV6
++ case IIOP_IPV6:
++ n = sizeof(struct sockaddr_in6);
++ getpeername(GIOP_CONNECTION_GET_FD(fd_cnx),
++ (struct sockaddr *)&fd_cnx->u.ipv6.location, &n);
++ hent = gethostbyaddr((const char *)&fd_cnx->u.ipv6.location.sin6_addr,
++ sizeof(fd_cnx->u.ipv6.location.sin6_addr), AF_INET6);
++ fd_cnx->u.ipv6.hostname = g_strdup(hent->h_name);
++ break;
++#endif
++
++ default:
++ g_error("Unsupported connection type %d", parent->icnxtype);
++ }
++
++ fcntl(GIOP_CONNECTION_GET_FD(fd_cnx), F_SETFD,
++ fcntl(GIOP_CONNECTION_GET_FD(fd_cnx), F_GETFD, 0)
++ | FD_CLOEXEC);
++ fcntl(GIOP_CONNECTION_GET_FD(fd_cnx), F_SETFL,
++ fcntl(GIOP_CONNECTION_GET_FD(fd_cnx), F_GETFL, 0)
++ | O_NONBLOCK);
++
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug,
++ "iiop_connection_from_fd connect [%d]\n",
++ GIOP_CONNECTION_GET_FD(fd_cnx));
++
++ giop_connection_add_to_list(GIOP_CONNECTION(fd_cnx));
++
++ return fd_cnx;
++}
++
++/*
++ * iiop_connection_server
++ *
++ * Outputs: 'server_cnx'
++ *
++ * Description: Creates a special IIOPConnection on which incoming
++ * connections come.
++ */
++IIOPConnection *
++iiop_connection_server(void)
++{
++ struct hostent *hent;
++ char hn_tmp[65];
++ socklen_t n;
++ IIOPConnection *server_cnx = g_new0(IIOPConnection, 1);
++
++ iiop_connection_init(server_cnx, GIOP_CONNECTION_SERVER, IIOP_IPV4);
++
++ server_cnx->is_serversock = TRUE;
++ GIOP_CONNECTION(server_cnx)->fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
++
++ if(GIOP_CONNECTION_GET_FD(server_cnx) < 0) {
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_server: socket_error: %s\n", strerror(errno));
++ goto failed;
++ }
++
++ server_cnx->u.ipv4.location.sin_family = AF_INET;
++ server_cnx->u.ipv4.location.sin_addr.s_addr = INADDR_ANY;
++ bind(GIOP_CONNECTION_GET_FD(server_cnx),
++ (struct sockaddr *)&server_cnx->u.ipv4.location,
++ sizeof(struct sockaddr_in));
++
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_SETFD,
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_GETFD, 0)
++ | FD_CLOEXEC);
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_SETFL,
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_GETFL, 0)
++ | O_NONBLOCK);
++
++ n = sizeof(struct sockaddr_in);
++ getsockname(GIOP_CONNECTION_GET_FD(server_cnx),
++ (struct sockaddr *)&server_cnx->u.ipv4.location, &n);
++
++ gethostname(hn_tmp, sizeof(hn_tmp) - 1);
++
++ hent = gethostbyname(hn_tmp);
++ if(hent)
++ {
++ if (strchr (hent->h_name, '.'))
++ server_cnx->u.ipv4.hostname = g_strdup(hent->h_name);
++ else
++ {
++ struct in_addr * addr = (struct in_addr *) hent->h_addr_list[0];
++ g_assert (hent->h_length == sizeof (struct in_addr) && addr);
++ server_cnx->u.ipv4.hostname = g_strdup (inet_ntoa (*addr));
++ }
++ }
++ else
++ server_cnx->u.ipv4.hostname = g_strdup(hn_tmp);
++
++ listen(GIOP_CONNECTION_GET_FD(server_cnx), 5);
++
++ giop_connection_add_to_list(GIOP_CONNECTION(server_cnx));
++
++ return server_cnx;
++
++failed:
++ close(GIOP_CONNECTION_GET_FD(server_cnx));
++ GIOP_CONNECTION(server_cnx)->fd = -1;
++ giop_connection_free(GIOP_CONNECTION(server_cnx));
++ server_cnx = NULL;
++ /*
++ * FIXME: GET_LOCK and DEFINE_LOCK never called for server_cnx
++ RELEASE_LOCK(server_cnx);
++ */
++ return NULL;
++}
++
++/*
++ * iiop_connection_server_ipv6
++ * Outputs: 'server_cnx'
++ *
++ * Description: Create a special IIOPConnection on which incoming
++ * connections come.
++ */
++IIOPConnection *
++iiop_connection_server_ipv6(void)
++{
++#ifdef HAVE_IPV6
++ struct hostent *hent, *hent2;
++
++ char hn_tmp[65];
++ int n;
++ IIOPConnection *server_cnx;
++
++ g_error("IPv6 support is baroquen! (Actually just never worked)");
++
++ server_cnx = g_new0(IIOPConnection, 1);
++
++ iiop_connection_init(server_cnx, GIOP_CONNECTION_SERVER, IIOP_IPV6);
++
++ server_cnx->is_serversock = TRUE;
++ GIOP_CONNECTION(server_cnx)->fd = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
++
++ if(GIOP_CONNECTION_GET_FD(server_cnx) < 0) {
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_server_ipv6: socket_error: %s\n", strerror(errno));
++ goto failed;
++ }
++
++ server_cnx->u.ipv6.location.sin6_family = AF_INET6;
++ bind(GIOP_CONNECTION_GET_FD(server_cnx),
++ (struct sockaddr *)&server_cnx->u.ipv6.location,
++ sizeof(struct sockaddr_in6));
++
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_SETFD,
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_GETFD, 0)
++ | FD_CLOEXEC);
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_SETFL,
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_GETFL, 0)
++ | O_NONBLOCK);
++
++ n = sizeof(struct sockaddr_in6);
++ getsockname(GIOP_CONNECTION_GET_FD(server_cnx), &server_cnx->u.ipv6.location, &n);
++
++ gethostname(hn_tmp, sizeof(hn_tmp) - 1);
++
++ hent = gethostbyname(hn_tmp);
++ if(hent) {
++ hent2 = gethostbyaddr(hent->h_addr, sizeof(server_cnx->u.ipv6.location.sin6_addr), AF_INET6);
++ if(hent2)
++ server_cnx->hostname = g_strdup(hent2->h_name);
++ else
++ server_cnx->hostname = g_strdup(hn_tmp);
++ } else
++ server_cnx->hostname = g_strdup(hn_tmp);
++
++ listen(GIOP_CONNECTION_GET_FD(server_cnx), 5);
++
++ giop_connection_add_to_list(GIOP_CONNECTION(server_cnx));
++
++ return server_cnx;
++
++failed:
++ close(GIOP_CONNECTION_GET_FD(server_cnx));
++ GIOP_CONNECTION(server_cnx)->fd = -1;
++ giop_connection_free(GIOP_CONNECTION(server_cnx));
++ server_cnx = NULL;
++ /*
++ * FIXME: GET_LOCK and DEFINE_LOCK never called for server_cnx
++ RELEASE_LOCK(server_cnx);
++ */
++#endif
++ return NULL;
++}
++
++/*
++ * iiop_connection_server_unix
++ *
++ * Outputs: 'server_cnx_unix'
++ *
++ * Side effects: Initializes 'server_cnx_unix' if not initialized.
++ *
++ * Description: Return a special IIOPConnection on which incoming connections
++ * come. If not already initialized, it creates the connection,
++ * otherwise it returns the existing one.
++ * This is
++ */
++IIOPConnection *
++iiop_connection_server_unix(const char *sockpath)
++{
++ IIOPConnection *server_cnx_unix;
++
++ g_assert(sockpath && *sockpath);
++
++ server_cnx_unix = g_new0(IIOPConnection, 1);
++
++ iiop_connection_init(server_cnx_unix, GIOP_CONNECTION_SERVER, IIOP_USOCK);
++
++ server_cnx_unix->is_serversock = TRUE;
++ GIOP_CONNECTION(server_cnx_unix)->fd = socket(AF_UNIX, SOCK_STREAM, 0);
++
++ if(GIOP_CONNECTION_GET_FD(server_cnx_unix) < 0) {
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_server_unix: socket_error: %s\n", strerror(errno));
++ goto failed;
++ }
++
++ strcpy(server_cnx_unix->u.usock.sun_path, sockpath);
++
++ server_cnx_unix->u.usock.sun_family = AF_UNIX;
++ if(bind(GIOP_CONNECTION_GET_FD(server_cnx_unix),
++ (struct sockaddr *)&server_cnx_unix->u.usock,
++ SUN_LEN(&server_cnx_unix->u.usock)) != 0) {
++ /* see the comment in iiop_connection_destroy switch as to why we
++ close it here. bad hack */
++ close(GIOP_CONNECTION_GET_FD(server_cnx_unix));
++ GIOP_CONNECTION(server_cnx_unix)->fd = -1;
++ goto failed;
++ }
++
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx_unix), F_SETFD,
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx_unix), F_GETFD, 0)
++ | FD_CLOEXEC);
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx_unix), F_SETFL,
++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx_unix), F_GETFL, 0)
++ | O_NONBLOCK);
++
++ if(listen(GIOP_CONNECTION_GET_FD(server_cnx_unix), 5) != 0)
++ goto failed;
++
++ giop_connection_add_to_list(GIOP_CONNECTION(server_cnx_unix));
++ iiop_unix_socket_list = g_slist_prepend(iiop_unix_socket_list,
++ server_cnx_unix);
++
++ /*
++ * FIXME: GET_LOCK and DEFINE_LOCK never called for server_cnx_unix
++ RELEASE_LOCK(server_cnx_unix);
++ */
++
++ return server_cnx_unix;
++
++failed:
++ close(GIOP_CONNECTION_GET_FD(server_cnx_unix));
++ GIOP_CONNECTION(server_cnx_unix)->fd = -1;
++ giop_connection_free(GIOP_CONNECTION(server_cnx_unix));
++ server_cnx_unix = NULL;
++ /*
++ * FIXME: GET_LOCK and DEFINE_LOCK never called for server_cnx_unix
++ RELEASE_LOCK(server_cnx_unix);
++ */
++ return NULL;
++}
++
++/*
++ * iiop_unlink_unix_sockets(void)
++ *
++ * Inputs: None
++ * Outputs: None
++ *
++ * Side effects: Modifies iiop_unix_socket_list
++ * Global data structures used: iiop_unix_socket_list
++ *
++ * Description:
++ * Unlinks any Unix server sockets created.
++ * Called during program termination.
++ */
++static void
++iiop_unlink_unix_sockets(void)
++{
++ GSList *item;
++
++ for (item = iiop_unix_socket_list;
++ item; item = g_slist_next(item)) {
++ GIOPConnection *cnx;
++
++ cnx = GIOP_CONNECTION(item->data);
++ if(cnx->connection_class == GIOP_CONNECTION_SERVER)
++ unlink(IIOP_CONNECTION(cnx)->u.usock.sun_path);
++ }
++
++ if (iiop_unix_socket_list) {
++ g_slist_free(iiop_unix_socket_list);
++ iiop_unix_socket_list = NULL;
++ }
++}
++
++/*
++ * iiop_connection_get
++ *
++ * Inputs: 'host' - the hostname (or dotted quad) of the remote host that
++ * will be connected
++ * 'port' - the port number on the above host to connect to.
++ * 'existing_only' - don't create a new connection if
++ * an existing one with the specified host:port
++ * doesn't exist.
++ *
++ * Outputs: 'cnx' - the connection to the specified host:port, or
++ * NULL upon error.
++ *
++ * Description: Returns an IIOPConnection that is connected to the
++ * specified host:port. If a connection already exists to the
++ * host:port, just returns it. Otherwise, calls
++ * 'iiop_connection_new' to create a new connection
++ * to host:port.
++ */
++IIOPConnection *
++iiop_connection_get(const char *host, gushort port, gboolean existing_only)
++{
++ IIOPConnection *cnx = NULL, *tmp;
++ GList *link;
++
++ g_assert(host);
++ g_assert(port);
++
++ GET_LOCK(giop_connection_list);
++ for(link = giop_connection_list.list; link; link = link->next)
++ {
++ tmp = IIOP_CONNECTION(link->data);
++ if(GIOP_CONNECTION(tmp)->connection_type != GIOP_CONNECTION_IIOP)
++ continue;
++
++ if(!GIOP_CONNECTION(tmp)->is_valid)
++ continue;
++
++ if(GIOP_CONNECTION(tmp)->connection_class != GIOP_CONNECTION_CLIENT)
++ continue;
++
++ if(IIOP_CONNECTION(tmp)->icnxtype != IIOP_IPV4)
++ continue;
++
++ if(!strcmp(host, tmp->u.ipv4.hostname)
++ && htons(port) == tmp->u.ipv4.location.sin_port) {
++ cnx = tmp;
++ break;
++ }
++ }
++ RELEASE_LOCK(giop_connection_list);
++
++ if(!cnx && !existing_only)
++ cnx = iiop_connection_new(host, port);
++
++ return cnx;
++}
++
++
++/*
++ * iiop_connection_new
++ *
++ * Inputs: same meanings as in 'iiop_connection_get'
++ * Outputs: 'retval' - newly created IIOPConnection
++ *
++ * Description: Allocates and initializes a new IIOPConnection,
++ * turns 'host' into an IP address, and then makes a TCP
++ * connection to host:port. Adds it to the list of active
++ * connections.
++ */
++IIOPConnection *
++iiop_connection_new(const char *host, gushort port)
++{
++ IIOPConnection *retval;
++
++ g_return_val_if_fail(host != NULL && port != 0, NULL);
++
++ retval = g_new0(IIOPConnection, 1);
++
++ iiop_connection_init(retval, GIOP_CONNECTION_CLIENT, IIOP_IPV4);
++
++ GIOP_CONNECTION(retval)->fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
++ if(GIOP_CONNECTION_GET_FD(retval) < 0) {
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_new: socket_error: %s\n", strerror(errno));
++ goto failed;
++ }
++
++ retval->u.ipv4.hostname = g_strdup(host);
++
++ retval->u.ipv4.location.sin_port = htons(port);
++ retval->u.ipv4.location.sin_family = AF_INET;
++ if(!inet_aton(host, &retval->u.ipv4.location.sin_addr))
++ {
++ struct hostent *hent;
++ hent = gethostbyname(host);
++ if(!hent) {
++ /* a (char *)h_strerror(int) function would be nice here */
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_new: gethostbyname error: %d\n", h_errno);
++ goto failed;
++ }
++ memcpy(&retval->u.ipv4.location.sin_addr, hent->h_addr, (size_t) sizeof(retval->u.ipv4.location.sin_addr));
++ }
++ if(connect(GIOP_CONNECTION_GET_FD(retval), (struct sockaddr *)&retval->u.ipv4.location, sizeof(retval->u.ipv4.location)) < 0) {
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_new: connect error: %s\n", strerror(errno));
++ goto failed;
++ }
++
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug,
++ "iiop_connection_new connect [%d] to %s:%d\n",
++ GIOP_CONNECTION_GET_FD(retval),
++ host, (guint)port);
++
++
++ fcntl(GIOP_CONNECTION_GET_FD(retval), F_SETFD, FD_CLOEXEC);
++ fcntl(GIOP_CONNECTION_GET_FD(retval), F_SETFL,
++ fcntl(GIOP_CONNECTION_GET_FD(retval), F_GETFL, 0)
++ | O_NONBLOCK);
++
++ GIOP_CONNECTION(retval)->was_initiated = TRUE;
++ GIOP_CONNECTION(retval)->is_auth = TRUE;
++
++ giop_connection_add_to_list(GIOP_CONNECTION(retval));
++
++ return retval;
++
++failed:
++ close(GIOP_CONNECTION_GET_FD(retval));
++ GIOP_CONNECTION(retval)->fd = -1;
++ giop_connection_free(GIOP_CONNECTION(retval));
++ return NULL;
++}
++
++/*
++ * iiop_connection_unix_get
++ *
++ * Inputs: 'sockpath' - Of the format 'path'
++ *
++ * Outputs: 'cnx' - the connection to the specified path, or
++ * NULL upon error.
++ *
++ * Description: Returns an IIOPConnection that is connected to the
++ * specified UNIX socket, if possible. If a connection
++ * already exists, just returns it. Otherwise,
++ * calls 'iiop_connection_unix_new' to create a new
++ * connection to sockpath.
++ */
++IIOPConnection *
++iiop_connection_unix_get(const char *sockpath, gboolean existing_only)
++{
++ IIOPConnection *cnx = NULL, *tmp;
++ GList *link;
++
++ GET_LOCK(giop_connection_list);
++ for(link = giop_connection_list.list; link; link = link->next)
++ {
++ tmp = IIOP_CONNECTION(link->data);
++
++ if(GIOP_CONNECTION(tmp)->connection_type != GIOP_CONNECTION_IIOP)
++ continue;
++
++ if(!GIOP_CONNECTION(tmp)->is_valid)
++ continue;
++
++ if(GIOP_CONNECTION(tmp)->connection_class != GIOP_CONNECTION_CLIENT)
++ continue;
++
++ if(IIOP_CONNECTION(tmp)->icnxtype != IIOP_USOCK)
++ continue;
++
++ if(!strcmp(sockpath, tmp->u.usock.sun_path)) {
++ cnx = tmp;
++ break;
++ }
++ }
++ RELEASE_LOCK(giop_connection_list);
++
++ if(!cnx && !existing_only)
++ cnx = iiop_connection_unix_new(sockpath);
++
++ return cnx;
++}
++
++/*
++ * iiop_connection_unix_new
++ *
++ * Inputs:
++ *
++ * Outputs: 'retval' - newly created IIOPConnection, or NULL upon error
++ *
++ * Description: Creates a connection to a UNIX socket (if possible)
++ * Adds it to the list of active connections.
++ */
++static IIOPConnection *
++iiop_connection_unix_new(const char *sockpath)
++{
++ IIOPConnection *retval;
++
++ retval = g_new0(IIOPConnection, 1);
++
++ retval->u.usock.sun_family = AF_UNIX;
++
++ g_snprintf(retval->u.usock.sun_path,
++ sizeof(retval->u.usock.sun_path), "%s", sockpath);
++
++ iiop_connection_init(retval, GIOP_CONNECTION_CLIENT, IIOP_USOCK);
++
++ GIOP_CONNECTION(retval)->fd = socket(AF_UNIX, SOCK_STREAM, 0);
++ if(GIOP_CONNECTION_GET_FD(retval) < 0) {
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_new: socket_error: %s\n", strerror(errno));
++ goto failed;
++ }
++
++ if(connect(GIOP_CONNECTION_GET_FD(retval), (struct sockaddr *)&retval->u.usock, SUN_LEN(&retval->u.usock)) < 0) {
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_new: connect error: %s\n", strerror(errno));
++ goto failed;
++ }
++
++ GIOP_CONNECTION(retval)->was_initiated = TRUE;
++ GIOP_CONNECTION(retval)->is_auth = TRUE;
++
++ fcntl(GIOP_CONNECTION_GET_FD(retval), F_SETFD, FD_CLOEXEC);
++ fcntl(GIOP_CONNECTION_GET_FD(retval), F_SETFL,
++ fcntl(GIOP_CONNECTION_GET_FD(retval), F_GETFL, 0)
++ | O_NONBLOCK);
++
++ giop_connection_add_to_list(GIOP_CONNECTION(retval));
++
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug,
++ "iiop_connection_unix_new connect [%d] to %s\n",
++ GIOP_CONNECTION_GET_FD(retval),
++ sockpath);
++
++ return retval;
++
++failed:
++ close(GIOP_CONNECTION_GET_FD(retval));
++ GIOP_CONNECTION(retval)->fd = -1;
++ giop_connection_free(GIOP_CONNECTION(retval));
++ return NULL;
++}
++
++/*
++ * iiop_connection_server_accept
++ * Inputs: 'connection' - a server IIOPConnection.
++ *
++ * Description: Performs accept(), TCP wrapper, access checking and related
++ * duties on a connection
++ */
++int allow_severity = LOG_INFO, deny_severity = LOG_NOTICE;
++
++#if defined(HAVE_HOSTS_ACCESS) && defined(HAVE_TCPD_H)
++DEFINE_LOCK(tcp_wrappers_usage);
++
++#endif
++static void
++iiop_connection_server_accept(GIOPConnection *connection)
++{
++ struct sockaddr sock;
++ socklen_t n;
++ int newfd;
++ GIOPConnection *newcnx;
++
++// printk("iiop_conncetion_server_accept( %d )\n",
++// GIOP_CONNECTION_GET_FD(connection));
++
++ n = sizeof(sock);
++
++ switch(IIOP_CONNECTION(connection)->icnxtype) {
++ case IIOP_IPV4: sock.sa_family = AF_INET; break;
++ case IIOP_USOCK: sock.sa_family = AF_UNIX; break;
++ case IIOP_IPV6:
++#ifdef HAVE_IPV6
++ sock.sa_family = AF_INET6;
++#endif
++ break;
++ }
++
++ newfd = accept(GIOP_CONNECTION_GET_FD(connection), &sock, &n);
++
++#if defined(HAVE_HOSTS_ACCESS) && defined(HAVE_TCPD_H)
++ /* tcp wrappers access checking */
++ switch(IIOP_CONNECTION(connection)->icnxtype) {
++ case IIOP_IPV4:
++ {
++ struct request_info request;
++
++ GET_LOCK(tcp_wrappers_usage);
++
++ request_init(&request, RQ_DAEMON, argv0_val, RQ_FILE, newfd, 0);
++
++ fromhost(&request);
++ if(!hosts_access(&request)) {
++ syslog(deny_severity, "[orbit] refused connect from %s", eval_client(&request));
++ close(newfd); newfd = -1;
++ } else
++ syslog(allow_severity, "[orbit] connect from %s", eval_client(&request));
++
++ RELEASE_LOCK(tcp_wrappers_usage);
++ }
++ break;
++ default:
++ /* No access controls for these transports */
++ break;
++ }
++#endif
++
++ if(newfd >= 0) {
++ newcnx = GIOP_CONNECTION(iiop_connection_from_fd(newfd,
++ IIOP_CONNECTION(connection)));
++ GIOP_CONNECTION(newcnx)->orb_data = connection->orb_data;
++ switch(IIOP_CONNECTION(connection)->icnxtype) {
++ case IIOP_USOCK: newcnx->is_auth = TRUE; break;
++ default:
++ break;
++ }
++ }
++}
++
++/*
++ * iiop_connection_destroy
++ *
++ * Inputs: 'iiop_connection' - an IIOPConnection to be finalized
++ *
++ * Side effects: invalidates 'iiop_connection' for use as an IIOPConnection
++ *
++ * Description: Performs the IIOP-specific parts of connection shutdown,
++ * including sending a CLOSECONNECTION message to the remote side.
++ */
++static void
++iiop_connection_destroy(IIOPConnection *iiop_connection)
++{
++ const GIOPMessageHeader mh = {"GIOP", {1,0}, FLAG_ENDIANNESS,
++ GIOP_CLOSECONNECTION, 0};
++
++ switch(iiop_connection->icnxtype) {
++ case IIOP_IPV4:
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug,
++ "iiop_connection_destroy connect [%d] of %s:%d\n",
++ GIOP_CONNECTION_GET_FD(iiop_connection),
++ iiop_connection->u.ipv4.hostname,
++ ntohs(iiop_connection->u.ipv4.location.sin_port));
++ g_free(iiop_connection->u.ipv4.hostname);
++ break;
++ case IIOP_IPV6:
++#ifdef HAVE_IPV6
++ g_free(iiop_connection->u.ipv6.hostname);
++#else
++ g_warning("IPv6 unsupported, can't free it!");
++#endif
++ break;
++ case IIOP_USOCK:
++ /* why do we check if fd is > 0 here?
++ the orb code tries to reuse existing socket connection points.
++ If binding to any of those fails because another process is using it,
++ we don't want to unlink the other server's socket!
++ if the bind fails, iiop_connection_server_unix closes the fd for us */
++ if(GIOP_CONNECTION(iiop_connection)->connection_class == GIOP_CONNECTION_SERVER
++ && GIOP_CONNECTION(iiop_connection)->fd >= 0)
++ unlink(iiop_connection->u.usock.sun_path);
++ break;
++ default:
++ break;
++ }
++
++ if(GIOP_CONNECTION_GET_FD(iiop_connection) >= 0) {
++ if(GIOP_CONNECTION(iiop_connection)->is_valid
++ && !GIOP_CONNECTION(iiop_connection)->was_initiated)
++ {
++ write(GIOP_CONNECTION_GET_FD(iiop_connection), &mh, sizeof(mh));
++ }
++
++ shutdown(GIOP_CONNECTION_GET_FD(iiop_connection), 2);
++ close(GIOP_CONNECTION_GET_FD(iiop_connection));
++ GIOP_CONNECTION(iiop_connection)->fd = -1;
++ }
++}
++
++static int giop_nloops = 0;
++
++void giop_main_quit(void) { giop_nloops--; }
++
++void
++giop_main(void)
++{
++ int looplevel;
++
++ looplevel = ++giop_nloops;
++
++ while(giop_nloops > 0) {
++
++ giop_main_iterate(TRUE);
++
++ if(giop_nloops != looplevel) {
++ giop_nloops = --looplevel;
++ return;
++ }
++ }
++}
++
++GIOPRecvBuffer *
++giop_main_next_message(gboolean blocking)
++{
++ return giop_main_next_message_2(blocking, NULL);
++}
++
++GIOPRecvBuffer *
++giop_main_next_message_2(gboolean blocking,
++ GIOPConnection *monitor)
++{
++ GIOPConnection *connection;
++ GIOPRecvBuffer *recv_buffer = NULL;
++
++ do {
++ recv_buffer = giop_received_list_pop();
++// printk("giop_main_next_message_2 : recv_buffer = 0x%08X\n", recv_buffer);
++ if(recv_buffer)
++ break;
++
++ connection = giop_check_connections(blocking);
++// printk("giop_main_next_message_2 : connection = 0x%08X\n", connection);
++ if(!connection)
++ {
++ return NULL;
++ }
++
++ if(GIOP_CONNECTION_GET_FD(connection) < 0) {
++ g_assert(!"connection has -ve fd!");
++ }
++
++// printk("giop_main_next_message_2 : connection class = %d\n",
++// connection->connection_class);
++ if(connection->connection_class == GIOP_CONNECTION_SERVER)
++ iiop_connection_server_accept(connection);
++ else
++ recv_buffer = giop_recv_message_buffer_use(connection);
++
++ if(monitor && !monitor->is_valid)
++ {
++ return NULL;
++ }
++
++ } while(!recv_buffer);
++
++ return recv_buffer;
++}
++
++void
++giop_main_handle_connection(GIOPConnection *connection)
++{
++ GIOPRecvBuffer *recv_buffer;
++
++ //printk("giop_main_handle_connection\n");
++
++ g_return_if_fail(connection != NULL);
++ g_return_if_fail(connection->is_valid);
++
++ if(connection->connection_class == GIOP_CONNECTION_SERVER) {
++ iiop_connection_server_accept(connection);
++ return;
++ } else
++ recv_buffer = giop_recv_message_buffer_use(connection);
++
++ if(recv_buffer) {
++ if(IIOPIncomingMessageHandler)
++ IIOPIncomingMessageHandler(recv_buffer);
++ else
++ giop_received_list_push(recv_buffer);
++ }
++}
++
++/*
++ * giop_main_handle_connection_exception
++ *
++ * Input: GIOPConnection *connection
++ *
++ * Output:
++ *
++ * Side effects: invalidates connection
++ *
++ * Description:
++ * When poll() or select() indicates that a file descriptor
++ * has been closed at the remote end, we must invalidate the associated
++ * GIOPConnection structure.
++ */
++void
++giop_main_handle_connection_exception(GIOPConnection *connection)
++{
++ g_return_if_fail(connection != NULL);
++ g_return_if_fail(connection->is_valid);
++
++// printk("giop_main_handle_connection_exception(0x%X)\n", GIOP_CONNECTION_GET_FD(connection));
++
++ giop_connection_ref(connection);
++
++ giop_connection_remove_from_list(connection);
++
++ shutdown(GIOP_CONNECTION_GET_FD(connection), 2);
++ close(GIOP_CONNECTION_GET_FD(connection));
++ GIOP_CONNECTION(connection)->fd = -1;
++ connection->is_valid = FALSE;
++
++ if(connection->incoming_msg) {
++ giop_recv_buffer_unuse(connection->incoming_msg);
++ connection->incoming_msg = NULL;
++ }
++
++ giop_connection_unref(connection);
++}
++
++/*
++ * giop_main_iterate
++ *
++ * Input: 'blocking' - flag to indicate whether to wait for incoming
++ * messages (TRUE), or whether to return immediately if no
++ * incoming messages are available (FALSE).
++ * Output: None
++ * Description:
++ * Gets the next message into recv_buffer (see
++ * giop_main_next_message) If we have a handler for incoming
++ * messages, then pass recv_buffer to the handler (handler
++ * becomes the new owner of recv_buffer's contents). Otherwise,
++ * tosses it onto the list of received-but-unprocessed buffers.
++ *
++ * Warnings:
++ * If you don't have an IIOPIncomingMessageHandler set, you're
++ * probably really screwed in the long run.
++ */
++void
++giop_main_iterate(gboolean blocking)
++{
++ GIOPRecvBuffer *recv_buffer;
++
++// printk("giop_main_iterate: blocking: %d\n", blocking);
++schedule();
++
++ recv_buffer = giop_main_next_message(blocking);
++
++// printk("giop_main_iterate: recv_buffer = 0x%08X\n", recv_buffer);
++
++ if(recv_buffer) {
++ if(IIOPIncomingMessageHandler)
++ IIOPIncomingMessageHandler(recv_buffer);
++ else
++ giop_received_list_push(recv_buffer);
++ }
++}
++
++/*
++ * giop_check_connections
++ *
++ * Inputs: 'block_for_reply' - If no incoming data is immediately available
++ * should this routine wait for incoming data (TRUE) or return
++ * immediately (FALSE).
++ *
++ * Outputs: 'connection' - the first connection that has incoming
++ * data available for reading (supposedly a GIOP message, but
++ * could be anything).
++ *
++ * Side effects: Removes closed connections from the active list.
++ *
++ * Global data structures used: giop_connection_list
++ *
++ * Description: Does a poll or select (OS-dependant) on the list of file
++ * descriptors in giop_connection_list.
++ *
++ * If a file descriptor has been closed, call
++ * giop_connection_handle_exception() on it and (as
++ * appropriated by 'block_for_reply') either return
++ * NULL or do another poll/select.
++ *
++ * If a file descriptor has data available for
++ * reading, find the associated GIOPConnection (using
++ * giop_connection_list.fd_to_connection_mapping) and
++ * return that.
++ *
++ */
++GIOPConnection *
++giop_check_connections(gboolean block_for_reply)
++{
++ GIOPConnection *connection = NULL;
++ int pollret;
++ int numcnx_checks;
++ int i;
++#ifndef USE_POLL
++ fd_set selectset_rd, selectset_ex;
++
++ struct timeval immediate_timeout = {0,0};
++#endif
++
++// printk("giop_check_connections\n");
++
++ do_read_msg:
++
++ if(!giop_connection_list.list)
++ {
++// printk("giop_check_connections : list = NULL\n");
++ BUG();
++ return NULL;
++ }
++
++#if 0
++ giop_connection_list_recreate(); /* easiest way to get valid
++ select sets... */
++#endif
++
++#ifdef USE_POLL
++ numcnx_checks = giop_connection_list.pollset->len;
++#else
++ memcpy(&selectset_rd, &giop_connection_list.selectset_rd,
++ sizeof(selectset_rd));
++ memcpy(&selectset_ex, &giop_connection_list.selectset_ex,
++ sizeof(selectset_ex));
++
++ numcnx_checks = giop_connection_list.max_fd+1;
++#endif
++
++ restart:
++#ifdef USE_POLL
++ pollret = poll((struct pollfd *)giop_connection_list.pollset->data,
++ giop_connection_list.pollset->len,
++ block_for_reply?-1:0);
++
++#if KORBIT_DEBUG_WRITING
++{
++ int ix;
++ struct pollfd *fds = (struct pollfd *)giop_connection_list.pollset->data;
++// printk("back from poll(#fds = %d, block = %d) = %d)\n", giop_connection_list.pollset->len, block_for_reply, pollret);
++// for (ix = 0; ix < giop_connection_list.pollset->len; ix++)
++ // printk(" [fd = 0x%X, event = 0x%X, revent = 0x%X]\n",
++// fds[ix].fd, fds[ix].events, fds[ix].revents);
++
++}
++#endif /* KORBIT_DEBUG_WRITING */
++
++
++# else /* !USE_POLL */
++
++ {
++ pollret = select (giop_connection_list.max_fd + 1,
++ &selectset_rd,
++ NULL, &selectset_ex,
++ block_for_reply?NULL:&immediate_timeout);
++ }
++# endif /* !USE_POLL */
++
++// printk("giop_check_connections : pollret == %d\n", pollret);
++ if(pollret <= 0) {
++ if(pollret < 0) {
++ if(errno == EINTR)
++ goto restart;
++ else
++ g_warning("Error code from select/poll: %s", g_strerror(errno));
++ } else
++ return NULL;
++ }
++
++ /* Check for data to be read on the fd's.
++ Note we have to do the hangup/exception checking in a separate loop,
++ because there may be data waiting to be read on a connection that the
++ other end has closed. */
++ for(i = 0; i < numcnx_checks; i++) {
++ struct fd_hash_elem *el;
++
++#ifdef USE_POLL
++ struct pollfd *p =
++ &g_array_index(giop_connection_list.pollset,
++ struct pollfd,
++ i);
++ g_assert(p->fd <= giop_connection_list.max_fd);
++#ifndef __KORBIT__
++ connection = giop_connection_list.fd_to_connection_mapping->pdata[p->fd];
++#else
++ el = g_hash_table_lookup(giop_connection_list.fd_to_connection_mapping,
++ &(p->fd));
++ if (el)
++ connection = el->cnx;
++#endif
++ if(p->revents & POLLIN)
++ goto got_connection;
++#else
++#ifndef __KORBIT__
++ connection = giop_connection_list.fd_to_connection_mapping->pdata[i];
++#else
++ el = g_hash_table_lookup(giop_connection_list.fd_to_connection_mapping,
++ &i);
++ if (el)
++ connection = el->cnx;
++#endif
++ if (FD_ISSET(i, &selectset_rd)) {
++ goto got_connection;
++ }
++#endif
++ }
++
++ /* Handle fd exceptions */
++ for(i = 0; i < numcnx_checks; i++)
++ {
++ struct fd_hash_elem *el;
++#ifdef USE_POLL
++ struct pollfd *p =
++ &g_array_index(giop_connection_list.pollset,
++ struct pollfd,
++ i);
++
++ g_assert(p->fd <= giop_connection_list.max_fd);
++ if(p->revents & (POLLHUP|POLLNVAL)) {
++#ifndef __KORBIT__
++ connection = giop_connection_list.fd_to_connection_mapping->pdata[p->fd];
++#else
++ el = g_hash_table_lookup(giop_connection_list.fd_to_connection_mapping,
++ &(p->fd));
++ if (el)
++ connection = el->cnx;
++#endif
++ giop_main_handle_connection_exception(connection);
++ }
++#else /* !USE_POLL */
++ if(FD_ISSET(i, &selectset_ex)) {
++#ifndef __KORBIT__
++ connection = giop_connection_list.fd_to_connection_mapping->pdata[i];
++#else
++ el = g_hash_table_lookup(giop_connection_list.fd_to_connection_mapping,
++ &i);
++ if (el)
++ connection = el->cnx;
++#endif
++ giop_main_handle_connection_exception(connection);
++ }
++#endif /* !USE_POLL */
++ }
++
++ /* Only reached if we didn't find a connection to read data from */
++ if(block_for_reply)
++ goto do_read_msg;
++
++ got_connection:
++// printk("giop_check_connections : got connection\n");
++ return connection;
++}
++
+diff -urN linux-2.4.1/net/korbit/IIOP/encoders.c linux-2.4.1-korbit/net/korbit/IIOP/encoders.c
+--- linux-2.4.1/net/korbit/IIOP/encoders.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/encoders.c Thu Feb 1 11:46:51 2001
+@@ -0,0 +1,46 @@
++#include "config.h"
++#include <string.h>
++#include "IIOP.h"
++
++ENCODER_DEC(IOP_ServiceContext)
++{
++ APA(&mem->context_id, sizeof(mem->context_id));
++ ENCODER_CALL(CORBA_sequence_octet, &mem->context_data);
++}
++
++ENCODER_DEC(IOP_ServiceContextList)
++{
++ int i;
++
++ if(!mem)
++ {
++ APA((gpointer)giop_scratch_space, sizeof(mem->_length));
++ return;
++ }
++
++ APA(&mem->_length, sizeof(mem->_length));
++
++ for(i = 0; i < mem->_length; i++)
++ ENCODER_CALL(IOP_ServiceContext, &mem->_buffer[i]);
++}
++
++ENCODER_DEC(CORBA_sequence_octet)
++{
++ if(!mem)
++ {
++ APA((gpointer)giop_scratch_space, sizeof(mem->_length));
++ return;
++ }
++
++ APIA(&mem->_length, sizeof(mem->_length));
++ if(mem->_length > 0)
++ AP(mem->_buffer, mem->_length);
++}
++
++ENCODER_DEC(CORBA_char)
++{
++ GIOP_unsigned_long len = strlen(mem) + 1;
++
++ APIA(&len, sizeof(len));
++ AP(mem, len);
++}
+diff -urN linux-2.4.1/net/korbit/IIOP/giop-msg-buffer.c linux-2.4.1-korbit/net/korbit/IIOP/giop-msg-buffer.c
+--- linux-2.4.1/net/korbit/IIOP/giop-msg-buffer.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/giop-msg-buffer.c Fri Feb 2 01:23:46 2001
+@@ -0,0 +1,1443 @@
++/* The big picture:
++ * For every outgoing request, we have to have the network-ready data
++ * somewhere in memory.
++ *
++ * Using writev, any pieces that do not need endian conversion can
++ * be written in-place.
++ *
++ * The pieces that do need endian conversion can be put into one or more
++ * buffers.
++ *
++ * WHOA WHOA newsflash
++ * Because IIOP lets the message sender specify the endianness,
++ * we do not need to do endian conversion _ever_! The receiver can do all
++ * conversions if need be, or if they are the same endianness as sender they
++ * can just pull it in right off the wire :)
++ *
++ */
++
++#include "config.h"
++#include "iiop-endianP.h"
++#include <string.h>
++#include <unistd.h>
++#include <stdio.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <fcntl.h>
++#include <string.h>
++
++#ifdef HAVE_POLL
++# include <sys/poll.h>
++#else
++# include <sys/types.h>
++# include <sys/time.h>
++#endif
++#include "IIOP.h"
++#include "IIOP-private.h"
++
++#ifdef HAVE_LIMITED_WRITEV
++#define writev g_writev
++#endif
++
++/*
++#ifdef O_NONBLOCK
++#undef O_NONBLOCK
++#endif
++#define O_NONBLOCK 0
++*/
++
++
++/* type defs */
++
++#ifdef __GNUC__
++#define PACKED __attribute__((packed))
++#else
++#define PACKED
++#endif
++
++/*
++ * Overlaps with struct _GIOPMessageHeader on purpose
++ * - we save time because this stuff never changes
++ */
++struct _GIOPMessageHeaderConstants {
++ GIOP_char magic[4];
++ GIOP_char GIOP_version[2];
++ GIOP_octet flags;
++} PACKED;
++
++/* functions */
++static gint giop_recv_decode_message(GIOPRecvBuffer *buf);
++static gboolean num_on_list(GIOP_unsigned_long num,
++ const GIOP_unsigned_long *request_ids,
++ GIOP_unsigned_long req_count);
++static gint giop_recv_reply_decode_message(GIOPRecvBuffer *buf);
++static gint giop_recv_request_decode_message(GIOPRecvBuffer *buf);
++static gint giop_recv_locate_reply_decode_message(GIOPRecvBuffer *buf);
++static gint giop_recv_locate_request_decode_message(GIOPRecvBuffer *buf);
++static GIOPRecvBuffer *giop_received_list_check_reply(GIOP_unsigned_long request_id);
++
++#ifdef NOT_REENTRANT
++extern DEFINE_LOCK(iiop_connection_list);
++#endif
++GList *iiop_connection_list = NULL;
++
++/* global variables */
++char giop_scratch_space[2048];
++
++static const struct _GIOPMessageHeaderConstants
++giop_message_header_constants = {
++ "GIOP",
++ {1,0},
++ FLAG_ENDIANNESS,
++};
++
++struct iovec
++giop_first_message_vec = {NULL,
++ sizeof(struct _GIOPMessageHeaderConstants)};
++
++DEFINE_LOCK(sendbufferlist);
++GSList *sendbufferlist = NULL;
++
++DEFINE_LOCK(recvbufferlist);
++GSList *recvbufferlist = NULL;
++
++DEFINE_LOCK(incoming_bufs);
++GList *incoming_bufs = NULL; /* List of incoming messages that had to be
++ shunted aside */
++
++DEFINE_LOCK(sendbuffers);
++DEFINE_LOCK(recvbuffers);
++GMemChunk *sendbuffers = NULL, *recvbuffers = NULL;
++
++DEFINE_LOCK(request_id_counter);
++GIOP_unsigned_long request_id_counter;
++
++#if 0
++inline
++void giop_message_buffer_append_iovec(GIOPMessageBuffer *msgbuf,
++ const struct iovec *iovec)
++{
++ /* g_print("Appending iovec %d bytes @ %p\n", iovec->iov_len, iovec->iov_base); */
++ g_array_append_val(msgbuf->iovecs, *iovec);
++}
++#else
++#define giop_message_buffer_append_iovec(msgbuf, iovec) g_array_append_val((msgbuf)->iovecs, *(iovec))
++#endif
++
++void
++giop_message_buffer_init(void)
++{
++ giop_first_message_vec.iov_base = (gpointer)&giop_message_header_constants;
++ INIT_LOCK(sendbufferlist);
++ INIT_LOCK(recvbufferlist);
++ request_id_counter = 1;
++ INIT_LOCK(request_id_counter);
++
++ INIT_LOCK(sendbuffers);
++ sendbuffers = g_mem_chunk_create(GIOPSendBuffer, 2, G_ALLOC_ONLY);
++ INIT_LOCK(recvbuffers);
++ recvbuffers = g_mem_chunk_create(GIOPRecvBuffer, 2, G_ALLOC_ONLY);
++}
++
++static void
++giop_message_buffer_new(GIOPMessageBuffer *buf)
++{
++ buf->iovecs = g_array_new(FALSE, FALSE, sizeof(struct iovec));
++}
++
++#define STRUCT_OFFSET(t, f) ((int) ((char*) &((t*) 0)->f))
++
++/* Send buffers only */
++static GIOPSendBuffer *
++giop_send_buffer_new(void)
++{
++ GIOPSendBuffer *msgbuf;
++ struct iovec firstvec;
++
++ GET_LOCK(sendbuffers);
++ msgbuf = g_chunk_new(GIOPSendBuffer, sendbuffers);
++ RELEASE_LOCK(sendbuffers);
++
++ giop_message_buffer_new(GIOP_MESSAGE_BUFFER(msgbuf));
++
++ giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(msgbuf),
++ &giop_first_message_vec);
++
++ firstvec.iov_base = &(GIOP_MESSAGE_BUFFER(msgbuf)->message_header.message_type);
++ firstvec.iov_len = sizeof(GIOPMessageHeader)
++ - STRUCT_OFFSET(GIOPMessageHeader, message_type);
++ GIOP_MESSAGE_BUFFER(msgbuf)->message_header.message_size = 0;
++
++ msgbuf->indirects = g_mem_chunk_create(char[GIOP_INDIRECT_CHUNK_SIZE],
++ 2, G_ALLOC_ONLY);
++
++ giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(msgbuf), &firstvec);
++
++ return msgbuf;
++}
++
++gint
++giop_send_buffer_write(GIOPSendBuffer *send_buffer)
++{
++ gulong nvecs;
++ glong res, sum, t;
++ struct iovec *curvec;
++ int fd;
++ GIOPConnection *cnx;
++ gint retval = -1;
++
++// printf("giop_send_buffer_write\n");
++
++ cnx = GIOP_MESSAGE_BUFFER(send_buffer)->connection;
++ if(!cnx->is_valid)
++ return -1;
++
++ fd = GIOP_CONNECTION_GET_FD(cnx);
++ nvecs = GIOP_MESSAGE_BUFFER(send_buffer)->iovecs->len;
++ curvec = (struct iovec *)GIOP_MESSAGE_BUFFER(send_buffer)->iovecs->data;
++
++#if defined(ORBIT_DEBUG) && 0
++ g_print("Message of length %d looks like:\n",
++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size);
++{ int i = 0;
++ for(sum = 0; i < nvecs; i++) {
++ sum += curvec[i].iov_len;
++ g_print(" [%p, %d]: %d\n", curvec[i].iov_base, curvec[i].iov_len,
++ sum);
++ }
++}
++#endif
++
++ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
++ res = writev(fd, curvec, nvecs);
++// printk("writev wrote %d byte\n", res);
++
++ sum = (GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size + sizeof(GIOPMessageHeader));
++ if(res < sum) {
++ if(res < 0) {
++//printf("writev returned %d\n", res);
++ if(errno != EAGAIN) {
++ giop_main_handle_connection_exception(cnx);
++ goto out;
++ }
++
++ res = 0;
++ }
++
++ /* wrote 7, iovecs 3, 2, 2, 4:
++ 0 + 3 !> 7
++ 3 + 2 !> 7
++ 5 + 2 !> 7
++ */
++
++ for(t = 0; ; t += curvec->iov_len, curvec++, nvecs--) {
++ if((t + curvec->iov_len) > res)
++ break;
++ }
++ if((res - t) > 0) {
++ curvec->iov_len -= (res - t);
++ curvec->iov_base = (gpointer)((char *)curvec->iov_base + (res - t));
++ }
++
++
++ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
++ t = writev(fd, curvec, nvecs);
++
++ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
++
++ if((t < 0) || ((res + t) < sum)) {
++//printf("crap, t = %d res = %d sum = %d\n", t, res, sum);
++ giop_main_handle_connection_exception(cnx);
++ goto out;
++ }
++ }
++
++ retval = 0;
++
++ out:
++
++ return retval;
++}
++
++static GIOPSendBuffer *
++giop_send_buffer_use(GIOPConnection *connection)
++{
++ GIOPSendBuffer *retval;
++
++ if(!connection->is_valid)
++ return NULL;
++
++ GET_LOCK(sendbufferlist);
++
++ if(sendbufferlist)
++ {
++ GSList *head;
++
++ retval = sendbufferlist->data;
++
++ head = sendbufferlist;
++ sendbufferlist = g_slist_remove_link(sendbufferlist, sendbufferlist);
++ g_slist_free_1 (head);
++
++ g_array_set_size(GIOP_MESSAGE_BUFFER(retval)->iovecs, 2);
++ GIOP_MESSAGE_BUFFER(retval)->message_header.message_size = 0;
++ }
++ else
++ retval = giop_send_buffer_new();
++
++ RELEASE_LOCK(sendbufferlist);
++
++ giop_connection_ref(connection);
++ GIOP_MESSAGE_BUFFER(retval)->connection = connection;
++
++ g_mem_chunk_reset(retval->indirects);
++ retval->indirect = g_chunk_new(gpointer, retval->indirects);
++#ifdef ORBIT_DEBUG
++ memset(retval->indirect, '\xFE', GIOP_INDIRECT_CHUNK_SIZE);
++#endif
++ retval->indirect_used = 0;
++
++ return retval;
++}
++
++GIOPSendBuffer *
++giop_send_reply_buffer_use(GIOPConnection *connection,
++ const IOP_ServiceContextList *service_context,
++ GIOP_unsigned_long request_id,
++ GIOPReplyStatusType reply_status)
++{
++ GIOPSendBuffer *send_buffer;
++
++ send_buffer = giop_send_buffer_use(connection);
++
++ if(!send_buffer)
++ return NULL;
++
++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_type = GIOP_REPLY;
++
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ sizeof(GIOP_unsigned_long));
++ if(!service_context) {
++ static const GIOP_unsigned_long sc_zero_int = 0;
++ AP(&sc_zero_int, sizeof(service_context->_length));
++ } else {
++ int i, n;
++ n = service_context->_length;
++ AP(&service_context->_length, sizeof(service_context->_length));
++ for(i = 0; i < n; i++) {
++ int j, o;
++ CORBA_sequence_octet *seqo;
++
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ sizeof(GIOP_unsigned_long));
++ AP(&service_context->_buffer[i].context_id,
++ sizeof(service_context->_buffer[i].context_id));
++ seqo = &service_context->_buffer[i].context_data;
++ o = seqo->_length;
++ AP(&seqo->_length, sizeof(GIOP_unsigned_long));
++ for(j = 0; j < o; j++)
++ AP(seqo->_buffer, seqo->_length);
++ }
++ }
++ send_buffer->message.u.reply.request_id = request_id;
++ send_buffer->message.u.reply.reply_status = reply_status;
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ sizeof(GIOP_unsigned_long));
++ AP(&send_buffer->message.u.reply.request_id,
++ sizeof(GIOP_unsigned_long));
++ AP(&send_buffer->message.u.reply.reply_status,
++ sizeof(GIOP_unsigned_long));
++
++ return send_buffer;
++}
++
++GIOPSendBuffer *
++giop_send_locate_reply_buffer_use(GIOPConnection *connection,
++ GIOP_unsigned_long request_id,
++ GIOPLocateStatusType locate_reply_status)
++{
++ GIOPSendBuffer *send_buffer;
++
++ send_buffer = giop_send_buffer_use(connection);
++
++ if(!send_buffer)
++ return NULL;
++
++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_type = GIOP_LOCATEREPLY;
++
++ APIA(&request_id, sizeof(request_id));
++ APIA(&locate_reply_status, sizeof(locate_reply_status));
++
++ return send_buffer;
++}
++
++GIOPSendBuffer *
++giop_send_request_buffer_use(GIOPConnection *connection,
++ const IOP_ServiceContextList *service_context,
++ GIOP_unsigned_long request_id,
++ GIOP_boolean response_expected,
++ const struct iovec *object_key_vec,
++ const struct iovec *operation_vec,
++ const struct iovec *principal_vec)
++{
++ GIOPSendBuffer *send_buffer;
++#if 0
++ static const struct {
++ CORBA_unsigned_long _length;
++ char _buffer[7];
++ } default_principal = { sizeof("nobody"), "nobody" };
++ static const struct iovec default_principal_vec =
++ {(void *)&default_principal,
++ sizeof(CORBA_unsigned_long) + sizeof("nobody")};
++#endif
++
++ if (!connection)
++ return NULL;
++ if(!object_key_vec)
++ return NULL;
++ if(!operation_vec)
++ return NULL;
++
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug,
++ "Sending request %s id %d to %s\n",
++ ((guchar *)operation_vec->iov_base) + 4,
++ request_id, ((guchar *)object_key_vec->iov_base) + 4);
++
++ send_buffer = giop_send_buffer_use(connection);
++
++ if (!send_buffer)
++ return NULL;
++
++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_type = GIOP_REQUEST;
++
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ sizeof(GIOP_unsigned_long));
++ if(!service_context) {
++ static const GIOP_unsigned_long sc_zero_int = 0;
++ AP(&sc_zero_int, sizeof(GIOP_unsigned_long));
++ } else {
++ int i, n;
++ n = service_context->_length;
++ AP(&service_context->_length, sizeof(service_context->_length));
++ for(i = 0; i < n; i++) {
++ int j, o;
++ CORBA_sequence_octet *seqo;
++
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ sizeof(GIOP_unsigned_long));
++ AP(&service_context->_buffer[i].context_id,
++ sizeof(service_context->_buffer[i].context_id));
++ seqo = &service_context->_buffer[i].context_data;
++ o = seqo->_length;
++ AP(&seqo->_length, sizeof(GIOP_unsigned_long));
++ for(j = 0; j < o; j++)
++ AP(seqo->_buffer, seqo->_length);
++ }
++ }
++ send_buffer->message.u.request.request_id = request_id;
++ send_buffer->message.u.request.response_expected = response_expected;
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ sizeof(GIOP_unsigned_long));
++ AP(&send_buffer->message.u.request.request_id,
++ sizeof(GIOP_unsigned_long));
++ AP(&send_buffer->message.u.request.response_expected,
++ sizeof(GIOP_boolean));
++#if 0
++ API(&response_expected, 1);
++ AP((gpointer)giop_scratch_space, 3);
++#endif
++
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ sizeof(CORBA_unsigned_long));
++ giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(send_buffer),
++ object_key_vec);
++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size +=
++ object_key_vec->iov_len;
++
++ /*
++ * We can know the length at compile time - don't calculate it at runtime
++ * if we can help it :)
++ */
++ /* ENCODER_CALL(CORBA_string, (CORBA_string *)operation); */
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ sizeof(CORBA_unsigned_long));
++ giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(send_buffer),
++ operation_vec);
++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size +=
++ operation_vec->iov_len;
++
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ sizeof(CORBA_unsigned_long));
++ giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(send_buffer),
++ principal_vec);
++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size +=
++ principal_vec->iov_len;
++
++ return send_buffer;
++}
++
++GIOPSendBuffer *
++giop_send_locate_request_buffer_use(GIOPConnection *connection,
++ GIOP_unsigned_long request_id,
++ const struct iovec *object_key_vec)
++{
++ GIOPSendBuffer *send_buffer;
++
++ if (!connection)
++ return NULL;
++ if (!object_key_vec)
++ return NULL;
++
++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug,
++ "Sending locate request id %d to %s\n",
++ request_id, ((guchar *)object_key_vec->iov_base) + 4);
++
++ send_buffer = giop_send_buffer_use(connection);
++
++ if (!send_buffer)
++ return NULL;
++
++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_type = GIOP_LOCATEREQUEST;
++
++ APIA(&request_id, sizeof(request_id));
++
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ sizeof(CORBA_unsigned_long));
++ giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(send_buffer),
++ object_key_vec);
++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size +=
++ object_key_vec->iov_len;
++
++ return send_buffer;
++}
++
++void
++giop_send_buffer_unuse(GIOPSendBuffer *send_buffer)
++{
++ if (send_buffer == NULL)
++ return;
++
++ giop_connection_unref(GIOP_MESSAGE_BUFFER(send_buffer)->connection);
++
++ GET_LOCK(sendbufferlist);
++ sendbufferlist = g_slist_prepend(sendbufferlist, send_buffer);
++ RELEASE_LOCK(sendbufferlist);
++}
++
++gulong
++giop_message_buffer_do_alignment(GIOPMessageBuffer *buffer,
++ gulong align_for)
++{
++ struct iovec newvec;
++ struct iovec *lastvec;
++ guint alignme;
++ gulong real_msgsize;
++ gulong align_diff;
++
++ if(align_for < 2) return 0;
++ if(align_for >
++ MAX(sizeof(GIOP_long_long),sizeof(GIOP_long_double)))
++ align_for = MAX(sizeof(GIOP_long_long), sizeof(GIOP_long_double));
++
++ real_msgsize = buffer->message_header.message_size+sizeof(GIOPMessageHeader);
++
++ alignme = (gulong)ALIGN_ADDRESS(real_msgsize, align_for);
++
++ align_diff = alignme - real_msgsize;
++ if(align_diff > 0)
++ {
++ lastvec = (struct iovec *)(buffer->iovecs->data)
++ + buffer->iovecs->len - 1;
++
++ if(lastvec->iov_base == giop_scratch_space)
++ {
++ newvec.iov_len = align_diff;
++ lastvec->iov_len += align_diff;
++ buffer->message_header.message_size += align_diff;
++ }
++ else
++ {
++ newvec.iov_base = (gpointer)giop_scratch_space;
++ newvec.iov_len = align_diff;
++ buffer->message_header.message_size += align_diff;
++ giop_message_buffer_append_iovec(buffer, &newvec);
++ }
++ return newvec.iov_len;
++ }
++ else
++ return 0;
++}
++
++void
++giop_message_buffer_append_mem_a(GIOPMessageBuffer *buffer,
++ gconstpointer mem_region,
++ gulong mem_region_length)
++{
++ struct iovec newvec;
++ struct iovec *lastvec;
++ gint alignfor;
++
++ alignfor = giop_message_buffer_do_alignment(buffer, mem_region_length);
++
++ lastvec = (struct iovec *)(buffer->iovecs->data) +
++ + buffer->iovecs->len - 1;
++
++ if((mem_region == giop_scratch_space && lastvec->iov_base == giop_scratch_space)
++ || (alignfor == 0 && (((guchar *)lastvec->iov_base) + lastvec->iov_len) == mem_region))
++ {
++ lastvec->iov_len += mem_region_length;
++ }
++ else
++ {
++ newvec.iov_base = (gpointer)mem_region;
++ newvec.iov_len = mem_region_length;
++ giop_message_buffer_append_iovec(buffer, &newvec);
++ }
++
++ buffer->message_header.message_size += mem_region_length;
++}
++
++void
++giop_message_buffer_append_mem(GIOPMessageBuffer *buffer,
++ gconstpointer mem_region,
++ gulong mem_region_length)
++{
++ struct iovec newvec;
++ struct iovec *lastvec;
++
++ lastvec = (struct iovec *)(buffer->iovecs->data)
++ + buffer->iovecs->len - 1;
++
++ if((mem_region == giop_scratch_space
++ && lastvec->iov_base == giop_scratch_space)
++ || ((((guchar *)lastvec->iov_base) + lastvec->iov_len) == mem_region))
++ {
++ lastvec->iov_len += mem_region_length;
++ }
++ else
++ {
++ newvec.iov_base = (gpointer)mem_region;
++ newvec.iov_len = mem_region_length;
++ giop_message_buffer_append_iovec(buffer, &newvec);
++ }
++
++ buffer->message_header.message_size += mem_region_length;
++}
++
++/* I think we need a WE_WANT_NEW_CRAPPY_BUGGY_CODE ifdef here - this
++ tiny routine seems to be horribly hard to get right.
++
++ Basically we have to paste the whole of 'mem_region' into our
++ memory chunks, possibly subdividing it up to fit it into multiple
++ 1K chunks. Because we have to return the first paste point in case
++ the client wants to manipulate it afterwards, if mem_region_length
++ >= sizeof(CORBA_unsigned_long), we also have to guarantee that the
++ pasted stuff doesn't get divided on a finer boundary than
++ sizeof(CORBA_unsigned_long).
++*/
++gpointer
++giop_send_buffer_append_mem_indirect(GIOPSendBuffer *send_buffer,
++ gconstpointer mem_region,
++ gulong mem_region_length)
++{
++ gulong offset = 0, thisblock_size;
++ gpointer blockstart = NULL;
++
++ while(offset < mem_region_length) {
++ thisblock_size = MIN(mem_region_length - offset,
++ GIOP_INDIRECT_CHUNK_SIZE - send_buffer->indirect_used);
++
++ if((thisblock_size >= sizeof(CORBA_unsigned_long))
++ || (mem_region_length - offset) < sizeof(CORBA_unsigned_long)) {
++ if (!blockstart)
++ blockstart =
++ ((guchar*) send_buffer->indirect) + send_buffer->indirect_used;
++
++ memcpy((guchar*)send_buffer->indirect + send_buffer->indirect_used,
++ (guchar*)mem_region + offset, thisblock_size);
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer),
++ (guchar*)send_buffer->indirect +
++ send_buffer->indirect_used,
++ thisblock_size);
++ offset += thisblock_size;
++ send_buffer->indirect_used += thisblock_size;
++ }
++
++ if(send_buffer->indirect_used >= (GIOP_INDIRECT_CHUNK_SIZE - sizeof(CORBA_unsigned_long))) {
++#ifdef I_CANT_FIGURE_OUT_WHAT_THIS_LOGIC_WAS_MEANT_TO_DO
++ || (thisblock_size >= sizeof(CORBA_unsigned_long)
++ && (mem_region_length - offset) > 0)) {
++#endif
++ send_buffer->indirect_used = 0;
++ send_buffer->indirect = g_chunk_new(gpointer,
++ send_buffer->indirects);
++ }
++ }
++
++ return blockstart;
++}
++
++#ifdef WE_WANT_OLD_DEAD_CRAPPY_BUGGY_CODE
++gpointer
++_giop_send_buffer_append_mem_indirect(GIOPSendBuffer *send_buffer,
++ gconstpointer mem_region,
++ gulong mem_region_length)
++{
++ gpointer blockstart = NULL;
++ gulong offset, new_offset;
++
++ for(offset = new_offset = 0; new_offset < mem_region_length;)
++ {
++ new_offset =
++ MIN(mem_region_length - offset,
++ GIOP_INDIRECT_CHUNK_SIZE - send_buffer->indirect_used);
++
++ if((new_offset - offset) > sizeof(CORBA_unsigned_long)
++ || mem_region_length >= sizeof(CORBA_unsigned_long)) {
++
++ if(!blockstart)
++ blockstart = send_buffer->indirect + send_buffer->indirect_used;
++ }
++
++ memcpy(send_buffer->indirect + send_buffer->indirect_used,
++ mem_region + offset, new_offset - offset);
++
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer),
++ send_buffer->indirect + send_buffer->indirect_used,
++ new_offset - offset);
++
++ send_buffer->indirect_used += new_offset - offset;
++
++ offset = new_offset;
++
++ if(new_offset >= GIOP_INDIRECT_CHUNK_SIZE)
++ {
++ send_buffer->indirect_used = 0;
++ send_buffer->indirect = g_chunk_new(gpointer,
++ send_buffer->indirects);
++#ifdef ORBIT_DEBUG
++ memset(send_buffer->indirect, '\xFE', GIOP_INDIRECT_CHUNK_SIZE);
++#endif
++ }
++ }
++
++ return blockstart;
++}
++#endif
++
++gpointer
++giop_send_buffer_append_mem_indirect_a(GIOPSendBuffer *send_buffer,
++ gconstpointer mem_region,
++ gulong mem_region_length)
++{
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer),
++ mem_region_length);
++ return giop_send_buffer_append_mem_indirect(send_buffer,
++ mem_region, mem_region_length);
++}
++
++GIOP_unsigned_long
++giop_get_request_id(void)
++{
++ GIOP_unsigned_long retval;
++ GET_LOCK(request_id_counter);
++ retval = request_id_counter++;
++ RELEASE_LOCK(request_id_counter);
++ return retval;
++}
++
++/****************************************************
++ * GIOPRecvBuffer routines
++ ****************************************************/
++
++static GIOPRecvBuffer *
++giop_recv_buffer_new(void)
++{
++ GIOPRecvBuffer *msgbuf;
++
++ GET_LOCK(recvbuffers);
++ msgbuf = g_chunk_new(GIOPRecvBuffer, recvbuffers);
++ RELEASE_LOCK(recvbuffers);
++
++ giop_message_buffer_new(GIOP_MESSAGE_BUFFER(msgbuf));
++ msgbuf->message_body = NULL;
++
++ return msgbuf;
++}
++
++void
++giop_recv_buffer_unuse(GIOPRecvBuffer *buffer)
++{
++ if (buffer == NULL)
++ return;
++
++ if(buffer->message_body) {
++ buffer->message_body = ((guchar *)buffer->message_body)
++ - sizeof(GIOPMessageHeader);
++
++ g_free(buffer->message_body);
++ buffer->message_body = NULL;
++ }
++
++ if(GIOP_MESSAGE_BUFFER(buffer)->connection->incoming_msg == buffer)
++ GIOP_MESSAGE_BUFFER(buffer)->connection->incoming_msg = NULL;
++
++ giop_connection_unref(GIOP_MESSAGE_BUFFER(buffer)->connection);
++
++ GET_LOCK(recvbufferlist);
++ recvbufferlist = g_slist_prepend(recvbufferlist, buffer);
++ RELEASE_LOCK(recvbufferlist);
++}
++
++static GIOPRecvBuffer *
++giop_recv_buffer_use(GIOPConnection *connection)
++{
++ GIOPRecvBuffer *retval;
++
++ if(!connection || !connection->is_valid)
++ return NULL;
++
++ GET_LOCK(recvbufferlist);
++
++ if(recvbufferlist)
++ {
++ GSList *head;
++
++ retval = recvbufferlist->data;
++
++ head = recvbufferlist;
++ recvbufferlist = g_slist_remove_link(recvbufferlist, recvbufferlist);
++ g_slist_free_1 (head);
++
++ GIOP_MESSAGE_BUFFER(retval)->message_header.message_size = 0;
++ retval->message_body = NULL;
++ }
++ else
++ retval = giop_recv_buffer_new();
++
++ retval->state = GIOP_MSG_READING_HEADER;
++ retval->left_to_read = sizeof(GIOPMessageHeader);
++
++ RELEASE_LOCK(recvbufferlist);
++
++ giop_connection_ref(connection);
++ GIOP_MESSAGE_BUFFER(retval)->connection = connection;
++
++ return retval;
++}
++
++GIOPRecvBuffer *
++giop_recv_message_buffer_use(GIOPConnection *connection)
++{
++ GIOPRecvBuffer *retval;
++ char *bptr;
++ int sysret;
++ guint message_size;
++
++// printf("giop_recv_message_buffer_use: connection = 0x%X\n", connection);
++
++ if(!connection || !connection->is_valid)
++ return NULL;
++
++ if(connection->incoming_msg)
++ retval = connection->incoming_msg;
++ else {
++ retval = giop_recv_buffer_use(connection);
++ connection->incoming_msg = retval;
++ }
++
++ if(!retval) return NULL;
++
++ do {
++ switch(retval->state) {
++ case GIOP_MSG_READING_HEADER:
++ bptr = ((char *)&(GIOP_MESSAGE_BUFFER(retval)->message_header));
++ bptr += sizeof(GIOP_MESSAGE_BUFFER(retval)->message_header)
++ - retval->left_to_read;
++ break;
++ case GIOP_MSG_READING_BODY:
++ bptr = retval->cur; /* Reason for not using retval->message_body:
++ See note XXX1 below */
++ bptr += GIOP_MESSAGE_BUFFER(retval)->message_header.message_size;
++ bptr -= retval->left_to_read;
++ break;
++ default:
++ bptr = NULL;
++ }
++
++//printf("#1p1: READ %d bytes: errno %d state = %d\n", retval->left_to_read, errno, retval->state);
++ sysret = read(GIOP_CONNECTION_GET_FD(connection), bptr,
++ retval->left_to_read);
++
++ if((sysret == 0)
++ || ((sysret < 0) && (errno != EAGAIN))) {
++//printf("#1: sysret = %d bptr = 0x%X errno = %d\n", sysret, bptr, errno);
++ goto errout;
++ }
++
++ if(sysret > 0)
++ retval->left_to_read -= sysret;
++
++ if(retval->left_to_read == 0) {
++ /* we change states here */
++
++ switch(retval->state) {
++ case GIOP_MSG_READING_HEADER:
++ /* Check the magic stuff */
++ if(strncmp(GIOP_MESSAGE_BUFFER(retval)->message_header.magic, "GIOP", 4)
++ || GIOP_MESSAGE_BUFFER(retval)->message_header.GIOP_version[0] != 1) {
++//printf("#2: Not a GIOP thinger? '%s'\n", GIOP_MESSAGE_BUFFER(retval)->message_header.magic);
++ goto errout;
++ }
++ if(GIOP_MESSAGE_BUFFER(retval)->message_header.message_size == 0
++ && GIOP_MESSAGE_BUFFER(retval)->message_header.message_type != GIOP_CLOSECONNECTION) {
++// printf("Unexpected 0-length IIOP message\n");
++ goto errout;
++ }
++
++ if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(retval))) {
++ CORBA_unsigned_long t = GIOP_MESSAGE_BUFFER(retval)->message_header.message_size;
++ retval->decoder = (void (*)(gpointer, gpointer, gulong))iiop_byteswap;
++
++ iiop_byteswap((gpointer)&GIOP_MESSAGE_BUFFER(retval)->message_header.message_size,
++ (gpointer)&t, sizeof(t));
++ } else {
++#ifdef __KERNEL__
++ retval->decoder = (void (*)(gpointer,gpointer,gulong))__memcpy;
++#else
++ retval->decoder = (void (*)(gpointer,gpointer,gulong))memcpy;
++#endif
++ }
++
++ message_size = GIOP_MESSAGE_BUFFER(retval)->message_header.message_size;
++ if(!connection->is_auth
++ && message_size > 131072) {
++// printf("message size is bigger than 128k (%d)\n", message_size);
++ goto errout;
++ }
++
++ retval->message_body = g_malloc(message_size+sizeof(GIOPMessageHeader));
++ /* XXX1 This is a lame hack to work with the fact that
++ alignment is relative to the MessageHeader, not the RequestHeader */
++ retval->message_body = ((guchar *)retval->message_body) + sizeof(GIOPMessageHeader);
++ retval->cur = retval->message_body;
++ retval->state = GIOP_MSG_READING_BODY;
++ retval->left_to_read = message_size;
++ break;
++ case GIOP_MSG_READING_BODY:
++ if(giop_recv_decode_message(retval)) {
++//printf("giop_recv_decode_message FAILURE!\n");
++ goto errout;
++ }
++ connection->incoming_msg = NULL;
++ retval->state = GIOP_MSG_READY;
++ break;
++ default:
++ break;
++ }
++ } else if(retval->left_to_read < 0) {
++// printf("Whoa, we overstepped the number of bytes we were supposed to read by %d\n", -retval->left_to_read);
++ goto errout;
++ } else /* retval->left_to_read > 0 */ {
++ /* couldn't read the whole piece, save it */
++ retval = NULL;
++ }
++ } while(retval && retval->state != GIOP_MSG_READY);
++
++ return retval;
++
++ errout:
++ giop_recv_buffer_unuse(retval);
++ giop_main_handle_connection_exception(connection);
++ return NULL;
++}
++
++void
++giop_received_list_push(GIOPRecvBuffer *recv_buffer)
++{
++ GET_LOCK(incoming_bufs);
++ incoming_bufs = g_list_prepend(incoming_bufs, recv_buffer);
++ RELEASE_LOCK(incoming_bufs);
++}
++
++GIOPRecvBuffer *giop_received_list_pop(void)
++{
++ GList *head;
++ GIOPRecvBuffer *retval;
++
++ GET_LOCK(incoming_bufs);
++
++ head = incoming_bufs;
++
++ if(!head)
++ return NULL;
++
++ retval = head->data;
++ incoming_bufs = g_list_remove_link(incoming_bufs, head);
++ g_list_free_1 (head);
++
++ RELEASE_LOCK(incoming_bufs);
++
++ return retval;
++}
++
++static GIOPRecvBuffer *
++giop_received_list_check_reply(GIOP_unsigned_long request_id)
++{
++ GIOPRecvBuffer *retval = NULL;
++ GList *item = NULL;
++
++ GET_LOCK(incoming_bufs);
++
++ for(item = incoming_bufs; item; item = g_list_next(item))
++ {
++ if(GIOP_MESSAGE_BUFFER(item->data)->message_header.message_type == GIOP_REPLY
++ && GIOP_RECV_BUFFER(item->data)->message.u.reply.request_id == request_id) {
++ retval = item->data;
++ break;
++ }
++ }
++
++ if(retval)
++ incoming_bufs = g_list_remove(incoming_bufs, retval);
++
++ RELEASE_LOCK(incoming_bufs);
++
++ return retval;
++}
++
++/** giop_recv_reply_buffer_use_multiple
++ */
++GIOPRecvBuffer *
++giop_recv_reply_buffer_use_multiple(GArray *request_ids,
++ gboolean block_for_reply)
++{
++ return giop_recv_reply_buffer_use_multiple_2(NULL, request_ids, block_for_reply);
++}
++
++/* here is how it will be:
++ one routine for getting next message with a specified reply ID.
++ */
++
++GIOPRecvBuffer *
++giop_recv_reply_buffer_use_multiple_2(GIOPConnection *request_cnx,
++ GArray *request_ids,
++ gboolean block_for_reply)
++{
++ int i;
++ GIOPRecvBuffer *retval = NULL;
++ GSList *pushme = NULL;
++
++ do {
++ /*
++ * We _do_ want to put this inside the loop,
++ * because we may call ourselves recursively for different request_id's
++ */
++ for(i = 0; i < request_ids->len && !retval; i++)
++ retval = giop_received_list_check_reply(g_array_index(request_ids, GIOP_unsigned_long, i));
++
++ if(retval)
++ break;
++
++ retval = giop_main_next_message_2(block_for_reply, request_cnx);
++
++ if(retval) {
++ if(GIOP_MESSAGE_BUFFER(retval)->message_header.message_type == GIOP_REPLY) {
++ if(num_on_list(retval->message.u.reply.request_id,
++ (GIOP_unsigned_long *)request_ids->data,
++ request_ids->len))
++ break;
++ else {
++ pushme = g_slist_prepend(pushme, retval); retval = NULL;
++ }
++ } else {
++ if(IIOPIncomingMessageHandler)
++ IIOPIncomingMessageHandler(retval);
++ else {
++ pushme = g_slist_prepend(pushme, retval); retval = NULL;
++ }
++ retval = NULL;
++ }
++ } else
++ return NULL;
++
++ } while(!retval && block_for_reply);
++
++ g_slist_foreach(pushme, (GFunc)giop_received_list_push, NULL);
++ g_slist_free(pushme);
++
++ return retval;
++}
++
++GIOPRecvBuffer *
++giop_recv_reply_buffer_use(GIOP_unsigned_long request_id,
++ gboolean block_for_reply)
++{
++ return giop_recv_reply_buffer_use_2(NULL, request_id, block_for_reply);
++}
++
++GIOPRecvBuffer *
++giop_recv_reply_buffer_use_2(GIOPConnection *request_cnx,
++ GIOP_unsigned_long request_id,
++ gboolean block_for_reply)
++{
++ GArray fakeme;
++
++ fakeme.len = 1;
++ fakeme.data = (gpointer)&request_id;
++
++ return giop_recv_reply_buffer_use_multiple_2(request_cnx,
++ &fakeme,
++ block_for_reply);
++}
++
++GIOPRecvBuffer *
++giop_recv_locate_reply_buffer_use(GIOP_unsigned_long request_id,
++ gboolean block_for_reply)
++{
++ GIOPRecvBuffer *retval = NULL;
++
++ do {
++ /*
++ * We _do_ want to put this inside the loop,
++ * because we may call ourselves recursively for different request_id's
++ */
++ retval = giop_received_list_check_reply(request_id);
++
++ if(retval)
++ break;
++
++ retval = giop_main_next_message_2(TRUE, NULL);
++
++ if(retval) {
++ if(GIOP_MESSAGE_BUFFER(retval)->message_header.message_type == GIOP_LOCATEREPLY
++ && retval->message.u.locate_reply.request_id == request_id)
++ break;
++ else {
++ if(IIOPIncomingMessageHandler)
++ IIOPIncomingMessageHandler(retval);
++ else
++ giop_received_list_push(retval);
++ retval = NULL;
++ }
++ } else
++ return NULL;
++ } while(!retval && block_for_reply);
++
++ return retval;
++}
++
++static gint
++giop_recv_decode_message(GIOPRecvBuffer *buf)
++{
++ switch(GIOP_MESSAGE_BUFFER(buf)->message_header.message_type)
++ {
++ case GIOP_REPLY:
++ return giop_recv_reply_decode_message(buf);
++ break;
++ case GIOP_REQUEST:
++ return giop_recv_request_decode_message(buf);
++ break;
++ case GIOP_LOCATEREQUEST:
++ return(giop_recv_locate_request_decode_message(buf));
++ break;
++ case GIOP_LOCATEREPLY:
++ return(giop_recv_locate_reply_decode_message(buf));
++ break;
++ case GIOP_CLOSECONNECTION:
++ return 0;
++ break;
++ default:
++// printf("Don't know how to decode message type %d\n",
++// GIOP_MESSAGE_BUFFER(buf)->message_header.message_type);
++ return -1;
++ }
++}
++
++/* if(currptr+len > end || currptr + len < currptr) */
++
++/* This whole mess needs redoing. */
++#define CHECK_NEW_POS(buf, requested_increment) \
++if(!( (( ((guchar*)GIOP_RECV_BUFFER(buf)->cur) \
++ + (requested_increment) ) \
++ <= ( ((guchar *)GIOP_RECV_BUFFER(buf)->message_body) \
++ + GIOP_MESSAGE_BUFFER(buf)->message_header.message_size)) \
++ && ( ( ((guchar*)GIOP_RECV_BUFFER(buf)->cur) \
++ + (requested_increment) ) \
++ >= ((guchar*)GIOP_RECV_BUFFER(buf)->cur) ))) goto out;
++
++#define NEW_POS_OUT out: return -1
++
++#define SAFE_ALIGN_ADDRESS(buf, amt) G_STMT_START { \
++guchar *newval; \
++newval = ALIGN_ADDRESS(GIOP_RECV_BUFFER(buf)->cur, amt); \
++CHECK_NEW_POS(buf, newval-((guchar *)GIOP_RECV_BUFFER(buf)->cur)); \
++GIOP_RECV_BUFFER(buf)->cur = newval; \
++} G_STMT_END
++
++#define GET_ULONG(x) G_STMT_START{ \
++ (x) = GUINT32_SWAP_LE_BE((*(CORBA_unsigned_long *)buf->cur)); \
++ CHECK_NEW_POS(buf, sizeof(CORBA_unsigned_long)); \
++ buf->cur = ((guchar *)buf->cur) + sizeof(CORBA_unsigned_long); \
++ }G_STMT_END
++
++#define GET_ULONG_NC(x) G_STMT_START{ \
++ *(x) = (*((CORBA_unsigned_long *)(buf->cur))); \
++ CHECK_NEW_POS(buf, sizeof(CORBA_unsigned_long)); \
++ buf->cur = ((guchar *)buf->cur) + sizeof(CORBA_unsigned_long); \
++ }G_STMT_END
++
++/* There be dragons in here. */
++static gint
++giop_recv_reply_decode_message(GIOPRecvBuffer *buf)
++{
++ /*
++ enum ReplyStatusType {
++ NO_EXCEPTION,
++ USER_EXCEPTION,
++ SYSTEM_EXCEPTION,
++ LOCATION_FORWARD
++ };
++
++ struct ReplyHeader {
++ IOP::ServiceContextList service_context;
++ unsigned long request_id;
++ ReplyStatusType reply_status;
++ };
++ */
++ int i;
++
++ buf->message.u.reply.service_context._maximum = 0;
++ if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(buf)))
++ {
++ GET_ULONG(buf->message.u.reply.service_context._length);
++/* XXX bad hardcoded hack until someone gives a "right answer" to how to
++solve this problem */
++ if(buf->message.u.reply.service_context._length > 128) return -1;
++ buf->message.u.reply.service_context._buffer =
++ g_new(IOP_ServiceContext, buf->message.u.reply.service_context._length);
++
++ for(i = 0; i < buf->message.u.reply.service_context._length; i++)
++ {
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG(buf->message.u.reply.service_context._buffer[i].context_id);
++ GET_ULONG(buf->message.u.reply.service_context._buffer[i].context_data._length);
++ buf->message.u.reply.service_context._buffer[i].context_data._buffer =
++ buf->cur;
++ CHECK_NEW_POS(buf, buf->message.u.reply.service_context._buffer[i].context_data._length);
++ buf->cur = ((guchar *)buf->cur) + buf->message.u.reply.service_context._buffer[i].context_data._length;
++ }
++ GET_ULONG(buf->message.u.reply.request_id);
++ GET_ULONG(buf->message.u.reply.reply_status);
++ }
++ else
++ {
++
++ GET_ULONG_NC(&buf->message.u.reply.service_context._length);
++/* XXX bad hardcoded hack until someone gives a "right answer" to how to
++solve this problem */
++ if(buf->message.u.reply.service_context._length > 128) return -1;
++ buf->message.u.reply.service_context._buffer =
++ g_new(IOP_ServiceContext, buf->message.u.reply.service_context._length);
++
++ for(i = 0; i < buf->message.u.reply.service_context._length; i++)
++ {
++ SAFE_ALIGN_ADDRESS(buf, sizeof(CORBA_unsigned_long));
++ GET_ULONG_NC(&buf->message.u.reply.service_context._buffer[i].context_id);
++ GET_ULONG_NC(&buf->message.u.reply.service_context._buffer[i].context_data._length);
++ buf->message.u.reply.service_context._buffer[i].context_data._buffer =
++ buf->cur;
++ CHECK_NEW_POS(buf, buf->message.u.reply.service_context._buffer[i].context_data._length);
++ buf->cur = ((guchar *)buf->cur) + buf->message.u.reply.service_context._buffer[i].context_data._length;
++ }
++ GET_ULONG_NC(&buf->message.u.reply.request_id);
++ GET_ULONG_NC(&buf->message.u.reply.reply_status);
++ }
++
++#if 0
++ g_message("[%d] Received reply %d size %d to request %d",
++ getpid(),
++ buf->message.u.reply.reply_status,
++ GIOP_MESSAGE_BUFFER(buf)->message_header.message_size,
++ buf->message.u.reply.request_id);
++#endif
++
++ return 0;
++
++ NEW_POS_OUT;
++}
++
++static gint
++giop_recv_locate_reply_decode_message(GIOPRecvBuffer *buf)
++{
++ if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(buf)))
++ {
++ GET_ULONG(buf->message.u.locate_reply.request_id);
++ GET_ULONG(buf->message.u.locate_reply.locate_status);
++ }
++ else
++ {
++ GET_ULONG_NC(&buf->message.u.locate_reply.request_id);
++ GET_ULONG_NC(&buf->message.u.locate_reply.locate_status);
++ }
++
++ return 0;
++ NEW_POS_OUT;
++}
++
++static gint
++giop_recv_request_decode_message(GIOPRecvBuffer *buf)
++{
++ GIOP_unsigned_long len;
++ int i;
++
++ buf->message.u.request.service_context._maximum = 0;
++ if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(buf)))
++ {
++ GET_ULONG(buf->message.u.request.service_context._length);
++
++ /* XXX bad hardcoded hack until someone gives a "right answer"
++ to how to solve this problem */
++
++ if(buf->message.u.request.service_context._length > 128) return -1;
++ buf->message.u.request.service_context._buffer =
++ g_new(IOP_ServiceContext, buf->message.u.request.service_context._length);
++
++ for(i = 0; i < buf->message.u.request.service_context._length; i++)
++ {
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG(buf->message.u.request.service_context._buffer[i].context_id);
++ GET_ULONG(buf->message.u.request.service_context._buffer[i].context_data._length);
++ buf->message.u.request.service_context._buffer[i].context_data._buffer =
++ buf->cur;
++ CHECK_NEW_POS(buf, buf->message.u.request.service_context._buffer[i].context_data._length);
++ buf->cur = ((guchar *)buf->cur) + buf->message.u.request.service_context._buffer[i].context_data._length;
++ }
++
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG(buf->message.u.request.request_id);
++ buf->message.u.request.response_expected = *((GIOP_boolean *)buf->cur);
++ CHECK_NEW_POS(buf, sizeof(GIOP_boolean));
++ buf->cur = ((guchar *)buf->cur) + sizeof(GIOP_boolean);
++
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG(buf->message.u.request.object_key._length);
++ buf->message.u.request.object_key._buffer = buf->cur;
++
++ CHECK_NEW_POS(buf, buf->message.u.request.object_key._length);
++ buf->cur = ((guchar *)buf->cur) + buf->message.u.request.object_key._length;
++
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG(len);
++ buf->message.u.request.operation = buf->cur;
++
++ CHECK_NEW_POS(buf, len);
++ buf->cur = ((guchar *)buf->cur) + len;
++
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG(buf->message.u.request.requesting_principal._length);
++ buf->message.u.request.requesting_principal._buffer = buf->cur;
++
++ CHECK_NEW_POS(buf, buf->message.u.request.requesting_principal._length);
++ buf->cur = ((guchar *)buf->cur) + buf->message.u.request.requesting_principal._length;
++ }
++ else
++ {
++ GET_ULONG_NC(&buf->message.u.request.service_context._length);
++
++ /* XXX bad hardcoded hack until someone gives a "right answer"
++ to how to solve this problem */
++ if(buf->message.u.request.service_context._length > 128) return -1;
++ buf->message.u.request.service_context._buffer =
++ g_new(IOP_ServiceContext, buf->message.u.request.service_context._length);
++
++ for(i = 0; i < buf->message.u.request.service_context._length; i++)
++ {
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG_NC(&buf->message.u.request.service_context._buffer[i].context_id);
++ GET_ULONG_NC(&buf->message.u.request.service_context._buffer[i].context_data._length);
++ buf->message.u.request.service_context._buffer[i].context_data._buffer =
++ buf->cur;
++ CHECK_NEW_POS(buf, buf->message.u.request.service_context._buffer[i].context_data._length);
++ buf->cur = ((guchar *)buf->cur) + buf->message.u.request.service_context._buffer[i].context_data._length;
++ }
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG_NC(&buf->message.u.request.request_id);
++ buf->message.u.request.response_expected = *((GIOP_boolean *)buf->cur);
++ CHECK_NEW_POS(buf, sizeof(GIOP_boolean));
++ buf->cur = ((guchar *)buf->cur) + sizeof(GIOP_boolean);
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG_NC(&buf->message.u.request.object_key._length);
++ buf->message.u.request.object_key._buffer = buf->cur;
++ CHECK_NEW_POS(buf, buf->message.u.request.object_key._length);
++ buf->cur = ((guchar *)buf->cur) + buf->message.u.request.object_key._length;
++
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG_NC(&len);
++ buf->message.u.request.operation = buf->cur;
++ CHECK_NEW_POS(buf, len);
++ buf->cur = ((guchar *)buf->cur) + len;
++
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG_NC(&buf->message.u.request.requesting_principal._length);
++ buf->message.u.request.requesting_principal._buffer = buf->cur;
++ CHECK_NEW_POS(buf, buf->message.u.request.requesting_principal._length);
++ buf->cur = ((guchar *)buf->cur) + buf->message.u.request.requesting_principal._length;
++ }
++
++#if 0
++ g_message("[%d] Received request %s size %d ID %d",
++ getpid(),
++ buf->message.u.request.operation,
++ GIOP_MESSAGE_BUFFER(buf)->message_header.message_size,
++ buf->message.u.request.request_id);
++#endif
++
++ return 0;
++
++ NEW_POS_OUT;
++}
++
++static gint
++giop_recv_locate_request_decode_message(GIOPRecvBuffer *buf)
++{
++ if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(buf)))
++ {
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG(buf->message.u.locate_request.request_id);
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG(buf->message.u.locate_request.object_key._length);
++ buf->message.u.locate_request.object_key._buffer = buf->cur;
++ CHECK_NEW_POS(buf, buf->message.u.locate_request.object_key._length);
++ buf->cur = ((guchar *)buf->cur) + buf->message.u.locate_request.object_key._length;
++ }
++ else
++ {
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG_NC(&buf->message.u.locate_request.request_id);
++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long));
++ GET_ULONG_NC(&buf->message.u.locate_request.object_key._length);
++ buf->message.u.locate_request.object_key._buffer = buf->cur;
++ CHECK_NEW_POS(buf, buf->message.u.locate_request.object_key._length);
++ buf->cur = ((guchar *)buf->cur) + buf->message.u.locate_request.object_key._length;
++ }
++
++ return 0;
++
++ NEW_POS_OUT;
++}
++
++gboolean
++num_on_list(GIOP_unsigned_long num,
++ const GIOP_unsigned_long *request_ids,
++ GIOP_unsigned_long req_count)
++{
++ int i;
++ for(i = 0; i < req_count; i++)
++ {
++ if(num == request_ids[i])
++ return TRUE;
++ }
++
++ return FALSE;
++}
+diff -urN linux-2.4.1/net/korbit/IIOP/giop-msg-buffer.h linux-2.4.1-korbit/net/korbit/IIOP/giop-msg-buffer.h
+--- linux-2.4.1/net/korbit/IIOP/giop-msg-buffer.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/giop-msg-buffer.h Thu Feb 1 16:19:47 2001
+@@ -0,0 +1,228 @@
++#ifndef GIOP_MSG_BUFFER_H
++#define GIOP_MSG_BUFFER_H 1
++
++#include "IIOP.h"
++/* For struct iovec */
++#include <sys/uio.h>
++
++typedef enum {
++ GIOP_REQUEST,
++ GIOP_REPLY,
++ GIOP_CANCELREQUEST,
++ GIOP_LOCATEREQUEST,
++ GIOP_LOCATEREPLY,
++ GIOP_CLOSECONNECTION,
++ GIOP_MESSAGEERROR,
++ GIOP_FRAGMENT
++} GIOPMsgType;
++
++/* GIOP message header */
++typedef struct _GIOPMessageHeader {
++ GIOP_char magic[4];
++ GIOP_char GIOP_version[2];
++ GIOP_octet flags;
++
++ /*
++ * We should really use GIOPMsgType
++ * but that enum winds up being an int...
++ */
++ GIOP_octet message_type;
++
++ GIOP_unsigned_long message_size;
++} GIOPMessageHeader;
++
++#define GIOP_MESSAGE_BUFFER(x) ((GIOPMessageBuffer *)x)
++typedef struct _GIOPMessageBuffer
++{
++ /* The connection that this message will go out over... */
++ GIOPConnection *connection;
++
++ GArray *iovecs;
++ GIOPMessageHeader message_header;
++} GIOPMessageBuffer;
++
++#include "../orb/iop.h"
++
++/* GIOP_REQUEST header */
++typedef enum {
++ GIOP_NO_EXCEPTION,
++ GIOP_USER_EXCEPTION,
++ GIOP_SYSTEM_EXCEPTION,
++ GIOP_LOCATION_FORWARD
++} GIOPReplyStatusType;
++
++typedef struct _GIOPMessageRequest {
++ IOP_ServiceContextList service_context;
++ GIOP_unsigned_long request_id;
++ GIOP_boolean response_expected;
++ CORBA_sequence_octet object_key;
++ CORBA_char *operation;
++ CORBA_Principal requesting_principal;
++} GIOPMessageRequest;
++
++typedef struct _GIOPMessageReply {
++ IOP_ServiceContextList service_context;
++ GIOP_unsigned_long request_id;
++ GIOPReplyStatusType reply_status;
++} GIOPMessageReply;
++
++typedef struct _GIOPMessageCancelRequest {
++ GIOP_unsigned_long request_id;
++} GIOPMessageCancelRequest;
++
++typedef struct _GIOPMessageLocateRequest {
++ GIOP_unsigned_long request_id;
++ CORBA_sequence_octet object_key;
++} GIOPMessageLocateRequest;
++
++typedef enum {
++ GIOP_UNKNOWN_OBJECT,
++ GIOP_OBJECT_HERE,
++ GIOP_OBJECT_FORWARD
++} GIOPLocateStatusType;
++
++typedef struct _GIOPMessageLocateReply {
++ GIOP_unsigned_long request_id;
++ GIOPLocateStatusType locate_status;
++} GIOPMessageLocateReply;
++
++typedef struct _GIOPMessage
++{
++ union {
++ GIOPMessageRequest request;
++ GIOPMessageReply reply;
++ GIOPMessageCancelRequest cancel_request;
++ GIOPMessageLocateRequest locate_request;
++ GIOPMessageLocateReply locate_reply;
++ } u;
++} GIOPMessage;
++
++typedef enum {
++ GIOP_MSG_READING_HEADER,
++ GIOP_MSG_READING_BODY,
++ GIOP_MSG_READY
++} GIOPMessageBufferState;
++
++#define GIOP_SEND_BUFFER(x) ((GIOPSendBuffer *)x)
++typedef struct _GIOPSendBuffer
++{
++ GIOPMessageBuffer message_buffer;
++
++ gpointer indirect;
++
++ GMemChunk *indirects; /* Request buffers only (at present) */
++ gulong indirect_used;
++
++ GIOPMessage message;
++ CORBA_unsigned_long scontext_tmp;
++} GIOPSendBuffer;
++
++#define GIOP_RECV_BUFFER(x) ((GIOPRecvBuffer *)x)
++typedef struct _GIOPRecvBuffer
++{
++ GIOPMessageBuffer message_buffer;
++ GIOPMessage message;
++
++ gpointer message_body;
++ gpointer cur;
++
++ void (*decoder)(gpointer dest, gpointer src, gulong len);
++
++ GIOPMessageBufferState state;
++ gint left_to_read;
++} GIOPRecvBuffer;
++
++/* This function needs to be called before useful things happen */
++void giop_message_buffer_init(void);
++
++gint giop_send_buffer_write(GIOPSendBuffer *request_buffer);
++
++void
++giop_message_buffer_append_mem_a(GIOPMessageBuffer *request_buffer,
++ gconstpointer mem_region,
++ gulong mem_region_length);
++void
++giop_message_buffer_append_mem(GIOPMessageBuffer *request_buffer,
++ gconstpointer mem_region,
++ gulong mem_region_length);
++
++/*
++ * This copies the value into a request-specific buffer before
++ * adding it to the list
++ */
++gpointer
++giop_send_buffer_append_mem_indirect_a(GIOPSendBuffer *request_buffer,
++ gconstpointer mem_region,
++ gulong mem_region_length);
++gpointer
++giop_send_buffer_append_mem_indirect(GIOPSendBuffer *request_buffer,
++ gconstpointer mem_region,
++ gulong mem_region_length);
++
++GIOPSendBuffer *
++giop_send_request_buffer_use(GIOPConnection *connection,
++ const IOP_ServiceContextList *service_context,
++ GIOP_unsigned_long request_id,
++ GIOP_boolean response_expected,
++ const struct iovec *object_key_vec,
++ const struct iovec *operation_vec,
++ const struct iovec *principal_vec);
++GIOPSendBuffer *
++giop_send_reply_buffer_use(GIOPConnection *connection,
++ const IOP_ServiceContextList *service_context,
++ GIOP_unsigned_long request_id,
++ GIOPReplyStatusType reply_status);
++GIOPSendBuffer *
++giop_send_locate_request_buffer_use(GIOPConnection *connection,
++ GIOP_unsigned_long request_id,
++ const struct iovec *object_key_vec);
++GIOPSendBuffer *
++giop_send_locate_reply_buffer_use(GIOPConnection *connection,
++ GIOP_unsigned_long request_id,
++ GIOPLocateStatusType reply_status);
++
++void giop_send_buffer_unuse(GIOPSendBuffer *send_buffer);
++
++GIOP_unsigned_long giop_get_request_id(void);
++
++GIOPRecvBuffer *
++giop_recv_reply_buffer_use(GIOP_unsigned_long request_id,
++ gboolean block_for_reply);
++GIOPRecvBuffer *
++giop_recv_reply_buffer_use_2(GIOPConnection *request_cnx,
++ GIOP_unsigned_long request_id,
++ gboolean block_for_reply);
++
++/* For DII - hands back the first received request matching an id on the list */
++GIOPRecvBuffer *
++giop_recv_reply_buffer_use_multiple(GArray *request_ids,
++ gboolean block_for_reply);
++GIOPRecvBuffer *
++giop_recv_reply_buffer_use_multiple_2(GIOPConnection *request_cnx,
++ GArray *request_ids,
++ gboolean block_for_reply);
++
++GIOPRecvBuffer *
++giop_recv_locate_reply_buffer_use(GIOP_unsigned_long request_id,
++ gboolean block_for_reply);
++
++/*
++ * For server-side use. It's the responsibility of the caller to do
++ * any select()ion desired
++ */
++GIOPRecvBuffer *
++giop_recv_message_buffer_use(GIOPConnection *connection);
++
++void giop_recv_buffer_unuse(GIOPRecvBuffer *buffer);
++
++/*
++ * This is used for sending (and recving, if we ever
++ * get zero-copy receives implemented) alignment bytes
++ */
++extern char giop_scratch_space[2048];
++gulong giop_message_buffer_do_alignment(GIOPMessageBuffer *buffer,
++ gulong align_for);
++
++#define giop_msg_conversion_needed(msgbuf) (conversion_needed(GIOP_MESSAGE_BUFFER(msgbuf)->message_header.flags & 1))
++
++#endif /* GIOP_MSG_BUFFER_H */
+diff -urN linux-2.4.1/net/korbit/IIOP/iiop-encoders.h linux-2.4.1-korbit/net/korbit/IIOP/iiop-encoders.h
+--- linux-2.4.1/net/korbit/IIOP/iiop-encoders.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/iiop-encoders.h Thu Feb 1 11:46:51 2001
+@@ -0,0 +1,25 @@
++#ifndef ENCODERS_H
++#define ENCODERS_H 1
++
++#define ENCODER_DEC(typename) \
++void giop_encoder_##typename##(GIOPSendBuffer *send_buffer, \
++ const typename *mem)
++
++#define ENCODER_CALL(typename, mem) \
++giop_encoder_##typename##(send_buffer, mem)
++
++#define AP(m, l) giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer), m, l)
++#define APA(m, l) giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(send_buffer), m, l)
++
++#define API(m, l) giop_send_buffer_append_mem_indirect(send_buffer, m, l)
++#define APIA(m, l) giop_send_buffer_append_mem_indirect_a(send_buffer, m, l)
++
++ENCODER_DEC(IOP_ServiceContext);
++ENCODER_DEC(IOP_ServiceContextList);
++ENCODER_DEC(CORBA_sequence_octet);
++ENCODER_DEC(CORBA_Principal);
++#define giop_encoder_CORBA_Principal(rb, mem) \
++ giop_encoder_CORBA_sequence_octet(rb, mem)
++ENCODER_DEC(CORBA_char);
++
++#endif /* ENCODERS_H */
+diff -urN linux-2.4.1/net/korbit/IIOP/iiop-endian.c linux-2.4.1-korbit/net/korbit/IIOP/iiop-endian.c
+--- linux-2.4.1/net/korbit/IIOP/iiop-endian.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/iiop-endian.c Thu Feb 1 11:46:51 2001
+@@ -0,0 +1,12 @@
++#define IIOP_DO_NOT_INLINE_IIOP_BYTESWAP
++#include "iiop-endian.h"
++
++void iiop_byteswap(guchar *outdata,
++ const guchar *data,
++ gulong datalen)
++{
++ const guchar *source_ptr = data;
++ guchar *dest_ptr = (guchar *)outdata + datalen - 1;
++ while(dest_ptr >= outdata)
++ *dest_ptr-- = *source_ptr++;
++}
+diff -urN linux-2.4.1/net/korbit/IIOP/iiop-endian.h linux-2.4.1-korbit/net/korbit/IIOP/iiop-endian.h
+--- linux-2.4.1/net/korbit/IIOP/iiop-endian.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/iiop-endian.h Thu Feb 1 11:46:51 2001
+@@ -0,0 +1,42 @@
++#ifndef IIOP_ENDIAN_H
++#define IIOP_ENDIAN_H 1
++
++#include <glib.h>
++
++#if G_BYTE_ORDER == G_BIG_ENDIAN
++
++# define FLAG_ENDIANNESS FLAG_BIG_ENDIAN
++# define conversion_needed(to_endianness) ((to_endianness)!=FLAG_BIG_ENDIAN)
++
++#elif G_BYTE_ORDER == G_LITTLE_ENDIAN
++
++# define FLAG_ENDIANNESS FLAG_LITTLE_ENDIAN
++# define conversion_needed(to_endianness) ((to_endianness)!=FLAG_LITTLE_ENDIAN)
++
++#else
++
++#error "Unsupported endianness on this system."
++
++#endif
++
++#define FLAG_BIG_ENDIAN 0
++#define FLAG_LITTLE_ENDIAN 1
++
++/* This is also defined in IIOP-types.c */
++void iiop_byteswap(guchar *outdata,
++ const guchar *data,
++ gulong datalen);
++
++#if defined(G_CAN_INLINE) && !defined(IIOP_DO_NOT_INLINE_IIOP_BYTESWAP)
++G_INLINE_FUNC void iiop_byteswap(guchar *outdata,
++ const guchar *data,
++ gulong datalen)
++{
++ const guchar *source_ptr = data;
++ guchar *dest_ptr = outdata + datalen - 1;
++ while(dest_ptr >= outdata)
++ *dest_ptr-- = *source_ptr++;
++}
++#endif
++
++#endif
+diff -urN linux-2.4.1/net/korbit/IIOP/iiop-endianP.h linux-2.4.1-korbit/net/korbit/IIOP/iiop-endianP.h
+--- linux-2.4.1/net/korbit/IIOP/iiop-endianP.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/IIOP/iiop-endianP.h Thu Feb 1 16:19:47 2001
+@@ -0,0 +1,11 @@
++#ifndef IIOP_ENDIANP_H
++#define IIOP_ENDIANP_H 1
++
++/* This is pretty much "here" */
++
++#include "config.h"
++#include "IIOP.h"
++
++#include "iiop-endian.h"
++
++#endif /* !IIOP_ENDIANP_H */
+diff -urN linux-2.4.1/net/korbit/Makefile linux-2.4.1-korbit/net/korbit/Makefile
+--- linux-2.4.1/net/korbit/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/Makefile Thu Feb 1 15:57:33 2001
+@@ -0,0 +1,22 @@
++#
++# Makefile for KORBit
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := korbit.o
++
++subdir-y := kglib orb IIOP ORBitutil modules
++subdir-m := modules
++
++obj-y := kglib/kglib.o orb/orblib.o IIOP/IIOPlib.o ORBitutil/ORBitutillib.o exported_symbols.o
++
++export-objs := exported_symbols.o
++
++EXTRA_CFLAGS = -D__KORBIT__ -DHAVE_CONFIG_H -I. -I./include -I./kglib -I./ORBitutil -nostdinc
++
++include $(TOPDIR)/Rules.make
++
+diff -urN linux-2.4.1/net/korbit/ORBitutil/CVS/Entries linux-2.4.1-korbit/net/korbit/ORBitutil/CVS/Entries
+--- linux-2.4.1/net/korbit/ORBitutil/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/CVS/Entries Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,13 @@
++/Makefile/1.4/Thu Feb 1 09:46:52 2001//
++/basic_types.h/1.1.1.1/Thu Feb 1 09:46:52 2001//
++/compat.c/1.1.1.1/Thu Feb 1 09:46:52 2001//
++/compat.h/1.1.1.1/Thu Feb 1 09:46:52 2001//
++/orbit-os-config.h/1.2/Thu Feb 1 09:46:52 2001//
++/os-feature-alloca.h/1.1.1.1/Thu Feb 1 09:46:52 2001//
++/os-specifics.h/1.1.1.1/Thu Feb 1 09:46:52 2001//
++/thread-safety.c/1.1.1.1/Thu Feb 1 09:46:52 2001//
++/thread-safety.h/1.1.1.1/Thu Feb 1 09:46:52 2001//
++/trace.c/1.2/Thu Feb 1 09:46:52 2001//
++/trace.h/1.1.1.1/Thu Feb 1 09:46:52 2001//
++/util.h/1.1.1.1/Thu Feb 1 09:46:52 2001//
++D
+diff -urN linux-2.4.1/net/korbit/ORBitutil/CVS/Repository linux-2.4.1-korbit/net/korbit/ORBitutil/CVS/Repository
+--- linux-2.4.1/net/korbit/ORBitutil/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/CVS/Repository Thu Feb 1 11:46:51 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/ORBitutil
+diff -urN linux-2.4.1/net/korbit/ORBitutil/CVS/Root linux-2.4.1-korbit/net/korbit/ORBitutil/CVS/Root
+--- linux-2.4.1/net/korbit/ORBitutil/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/CVS/Root Thu Feb 1 11:46:51 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/ORBitutil/Makefile linux-2.4.1-korbit/net/korbit/ORBitutil/Makefile
+--- linux-2.4.1/net/korbit/ORBitutil/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/Makefile Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,17 @@
++#
++# Makefile for KORBit/ORBitutil
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .o file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := ORBitutillib.o
++
++#obj-m := $(O_TARGET)
++obj-y := compat.o thread-safety.o trace.o
++
++EXTRA_CFLAGS = -D__KORBIT__ -DHAVE_CONFIG_H -I. -I.. -I../include -I../kglib -I../ORBitutil -nostdinc
++
++include $(TOPDIR)/Rules.make
+diff -urN linux-2.4.1/net/korbit/ORBitutil/basic_types.h linux-2.4.1-korbit/net/korbit/ORBitutil/basic_types.h
+--- linux-2.4.1/net/korbit/ORBitutil/basic_types.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/basic_types.h Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,46 @@
++#ifndef BASIC_TYPES_H
++#define BASIC_TYPES_H 1
++
++#include <glib.h>
++
++typedef gint16 CORBA_short;
++typedef gint32 CORBA_long;
++typedef guint16 CORBA_unsigned_short;
++typedef guint32 CORBA_unsigned_long;
++typedef gfloat CORBA_float;
++typedef gdouble CORBA_double;
++typedef char CORBA_char;
++typedef guchar CORBA_boolean;
++typedef guchar CORBA_octet;
++typedef gdouble CORBA_long_double;
++typedef guint16 CORBA_wchar; /* I'm not sure what size a wchar is supposed to be */
++
++/* Just a peeve */
++typedef CORBA_char GIOP_char;
++typedef CORBA_wchar GIOP_wchar;
++typedef CORBA_short GIOP_short;
++typedef CORBA_long GIOP_long;
++typedef CORBA_unsigned_short GIOP_unsigned_short;
++typedef CORBA_unsigned_long GIOP_unsigned_long;
++typedef CORBA_octet GIOP_octet;
++typedef CORBA_long GIOP_enum;
++typedef CORBA_boolean GIOP_boolean;
++typedef CORBA_float GIOP_float;
++typedef CORBA_double GIOP_double;
++typedef CORBA_long_double GIOP_long_double;
++
++#ifdef G_HAVE_GINT64
++#define HAVE_CORBA_LONG_LONG
++/* According to the spec, these two are optional. We support them if we can. */
++typedef gint64 CORBA_long_long;
++typedef guint64 CORBA_unsigned_long_long;
++typedef CORBA_long_long GIOP_long_long;
++typedef CORBA_unsigned_long_long GIOP_unsigned_long_long;
++#else
++#warning ""
++#warning "You don't G_HAVE_GINT64 defined in glib."
++#warning "Please make sure you don't have an old glibconfig.h lying around."
++#warning ""
++#endif
++
++#endif
+diff -urN linux-2.4.1/net/korbit/ORBitutil/compat.c linux-2.4.1-korbit/net/korbit/ORBitutil/compat.c
+--- linux-2.4.1/net/korbit/ORBitutil/compat.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/compat.c Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,43 @@
++#include "config.h"
++#include "util.h"
++
++#define MAX_IOVS 16
++
++int g_writev(int fd, const struct iovec * vector, size_t count)
++{
++ int retval = 0;
++
++ while(count > MAX_IOVS) {
++ retval += writev(fd, vector, MAX_IOVS);
++ vector += MAX_IOVS; count -= MAX_IOVS;
++ }
++
++ return writev(fd, vector, count) + retval;
++}
++
++#ifndef HAVE_INET_ATON
++#include <netinet/in.h>
++#include <string.h>
++int inet_aton(const char *cp, struct in_addr *inp)
++{
++ union {
++ unsigned int n;
++ char parts[4];
++ } u;
++ int a=0,b=0,c=0,d=0, i;
++
++ i = sscanf(cp, "%d.%d.%d.%d%*s", &a, &b, &c, &d);
++
++ if(i != 4)
++ return 0;
++
++ u.parts[0] = a;
++ u.parts[1] = b;
++ u.parts[2] = c;
++ u.parts[3] = d;
++
++ inp->s_addr = u.n;
++
++ return 1;
++}
++#endif
+diff -urN linux-2.4.1/net/korbit/ORBitutil/compat.h linux-2.4.1-korbit/net/korbit/ORBitutil/compat.h
+--- linux-2.4.1/net/korbit/ORBitutil/compat.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/compat.h Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,8 @@
++#ifndef ORBITUTIL_COMPAT_H
++#define ORBITUTIL_COMPAT_H 1
++#include <sys/types.h>
++#include <sys/uio.h>
++
++int g_writev(int fd, const struct iovec * vector, size_t count);
++
++#endif /*#define ORBITUTIL_COMPAT_H 1 */
+diff -urN linux-2.4.1/net/korbit/ORBitutil/orbit-os-config.h linux-2.4.1-korbit/net/korbit/ORBitutil/orbit-os-config.h
+--- linux-2.4.1/net/korbit/ORBitutil/orbit-os-config.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/orbit-os-config.h Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,8 @@
++#ifndef OS_CONFIG_H
++#define OS_CONFIG_H 1
++
++#ifndef __KORBIT__
++#define ORBIT_HAVE_ALLOCA_H 1
++#endif
++
++#endif
+diff -urN linux-2.4.1/net/korbit/ORBitutil/os-feature-alloca.h linux-2.4.1-korbit/net/korbit/ORBitutil/os-feature-alloca.h
+--- linux-2.4.1/net/korbit/ORBitutil/os-feature-alloca.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/os-feature-alloca.h Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,26 @@
++#ifndef OS_FEATURE_ALLOCA_H
++#define OS_FEATURE_ALLOCA_H 1
++
++# if ORBIT_HAVE_ALLOCA_H
++# include <alloca.h>
++# endif
++
++# include <string.h>
++
++# if defined(__GNUC__)
++
++# if defined(__STRICT_ANSI__)
++# define alloca __builtin_alloca
++# endif
++
++# elif !(ORBIT_HAVE_ALLOCA_H)
++
++# if defined(_AIX)
++ #pragma alloca
++# elif !defined(alloca) /* predefined by HP cc +Olibcalls */
++char *alloca ();
++# endif
++
++# endif /* __GNUC__ etc. */
++
++#endif /* OS_FEATURE_ALLOCA_H */
+diff -urN linux-2.4.1/net/korbit/ORBitutil/os-specifics.h linux-2.4.1-korbit/net/korbit/ORBitutil/os-specifics.h
+--- linux-2.4.1/net/korbit/ORBitutil/os-specifics.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/os-specifics.h Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,12 @@
++#ifndef ORBITUTIL_OS_SPECIFICS_H
++#define ORBITUTIL_OS_SPECIFICS_H 1
++
++#include <ORBitutil/orbit-os-config.h>
++
++#include <ORBitutil/os-feature-alloca.h>
++
++/* This file should be a bunch of #ifdef's to #include the
++ os-<osname>.h for the current OS. It is intended to abstract the
++ gunkiness necessary to get some OS's to build ORBit properly. */
++
++#endif
+diff -urN linux-2.4.1/net/korbit/ORBitutil/thread-safety.c linux-2.4.1-korbit/net/korbit/ORBitutil/thread-safety.c
+--- linux-2.4.1/net/korbit/ORBitutil/thread-safety.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/thread-safety.c Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,19 @@
++#include "util.h"
++
++#ifdef NOT_REENTRANT
++#include <pthread.h>
++
++pthread_key_t thread_data;
++
++void init_thread_data(void) __attribute__ ((constructor));
++
++void init_thread_data(void)
++{
++ pthread_key_create(&thread_data, NULL);
++}
++
++#else
++
++gpointer prog_data = NULL;
++
++#endif
+diff -urN linux-2.4.1/net/korbit/ORBitutil/thread-safety.h linux-2.4.1-korbit/net/korbit/ORBitutil/thread-safety.h
+--- linux-2.4.1/net/korbit/ORBitutil/thread-safety.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/thread-safety.h Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,36 @@
++#ifndef THREAD_SAFETY_H
++#define THREAD_SAFETY_H 1
++
++#ifdef NOT_REENTRANT
++
++#include <pthread.h>
++
++#define DEFINE_LOCK(x) pthread_mutex_t x##_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
++#define INIT_LOCK(x) /* We use static initialization, see above */
++#define GET_LOCK(x) pthread_mutex_lock(&x##_lock)
++#define RELEASE_LOCK(x) pthread_mutex_unlock(&x##_lock)
++#define PARAM_LOCK(x) pthread_mutex_t x##_lock
++#define LOCK_NAME(x) x##_lock
++#define EXTERN_LOCK(x) extern pthread_mutex_t x##_lock
++extern pthread_key_t thread_data;
++#define GET_THREAD_DATA() pthread_getspecific(thread_data)
++#define SET_THREAD_DATA(x) pthread_setspecific(thread_data, (x))
++
++#else
++
++/* stupid work around ANSI & empty semicolons. */
++#define DEFINE_LOCK(x)
++#define INIT_LOCK(x)
++#define GET_LOCK(x)
++#define RELEASE_LOCK(x)
++#define PARAM_LOCK(x) gpointer x##_lock
++#define LOCK_NAME(x) NULL
++#define EXTERN_LOCK(x)
++
++extern gpointer prog_data;
++#define GET_THREAD_DATA() prog_data
++#define SET_THREAD_DATA(x) (prog_data = (x))
++
++#endif
++
++#endif /* THREAD_SAFETY_H */
+diff -urN linux-2.4.1/net/korbit/ORBitutil/trace.c linux-2.4.1-korbit/net/korbit/ORBitutil/trace.c
+--- linux-2.4.1/net/korbit/ORBitutil/trace.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/trace.c Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,94 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@acm.org>
++ *
++ */
++
++#include <stdio.h>
++#include <stdarg.h>
++
++#include "trace.h"
++
++/*
++ * The function to call to handle trace messages, or NULL to use the default
++ * of printing to stderr.
++ */
++#ifdef ORBIT_DEBUG
++static int (* TraceCallback)(char *, va_list)=NULL;
++static int TraceModules=0;
++static ORBit_TraceLevel TraceMaxLevel=0;
++
++const char *ORBit_Trace_levellist[] = {
++ "ALERT ",
++ "CRITICAL",
++ "ERROR ",
++ "WARNING ",
++ "NOTICE ",
++ "INFO ",
++ "DEBUG "
++};
++
++void ORBit_Trace_setCallback(int (*cbf)(char *, va_list))
++{
++ TraceCallback=cbf;
++}
++
++int (*ORBit_Trace_getCallback(void))(char *, va_list)
++{
++ return(TraceCallback);
++}
++
++void ORBit_Trace_setModules(int modules)
++{
++ TraceModules=modules;
++}
++
++void ORBit_Trace_setLevel(ORBit_TraceLevel level)
++{
++ TraceMaxLevel=level;
++}
++
++int ORBit_Trace(ORBit_TraceModule module, ORBit_TraceLevel level, char *fmt, ...)
++{
++ va_list args;
++
++ if(!BitTest(TraceModules, module))
++ return 0;
++ if(TraceMaxLevel < level)
++ return 0;
++
++ va_start(args, fmt);
++ if(TraceCallback!=NULL)
++ return((*TraceCallback)(fmt, args));
++
++#ifdef __KORBIT__
++ printf("[%s]: ", ORBit_Trace_levellist[level]);
++
++ printf("%s", g_strdup_vprintf(fmt, args));
++ return 0; // breaks semantics, but return value is never used
++#else /* !__KORBIT__ */
++ fprintf(stderr, "[%s]: ", ORBit_Trace_levellist[level]);
++
++ return vfprintf(stderr, fmt, args);
++#endif /* !__KORBIT__ */
++}
++#endif
+diff -urN linux-2.4.1/net/korbit/ORBitutil/trace.h linux-2.4.1-korbit/net/korbit/ORBitutil/trace.h
+--- linux-2.4.1/net/korbit/ORBitutil/trace.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/trace.h Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,68 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@acm.org>
++ *
++ */
++
++#ifndef _ORBIT_TRACE_H_
++#define _ORBIT_TRACE_H_
++
++#include <stdarg.h>
++#include "util.h"
++
++typedef enum {
++ TraceMod_ORB,
++ TraceMod_CDR,
++ TraceMod_IIOP,
++ TraceMod_TC,
++ TraceMod_IR,
++ TraceMod_User=32
++} ORBit_TraceModule;
++
++typedef enum {
++ TraceLevel_Alert=0,
++ TraceLevel_Critical,
++ TraceLevel_Error,
++ TraceLevel_Warning,
++ TraceLevel_Notice,
++ TraceLevel_Info,
++ TraceLevel_Debug
++} ORBit_TraceLevel;
++
++extern const char *ORBit_Trace_levellist[];
++
++#ifdef ORBIT_DEBUG
++extern void ORBit_Trace_setCallback(int (*)(char *, va_list));
++extern int (*ORBit_Trace_getCallback(void))(char *, va_list);
++extern void ORBit_Trace_setModules(int);
++extern void ORBit_Trace_setLevel(ORBit_TraceLevel);
++extern int ORBit_Trace(ORBit_TraceModule, ORBit_TraceLevel, char *, ...);
++#else
++#define ORBit_Trace_setCallback(x)
++#define ORBit_Trace_getCallback() NULL
++#define ORBit_Trace_setModules(x)
++#define ORBit_Trace_setLevel(x)
++#define ORBit_Trace(module,level,fmt,args...)
++#endif
++
++
++#endif /* !_ORBIT_TRACE_H_ */
+diff -urN linux-2.4.1/net/korbit/ORBitutil/util.h linux-2.4.1-korbit/net/korbit/ORBitutil/util.h
+--- linux-2.4.1/net/korbit/ORBitutil/util.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/ORBitutil/util.h Thu Feb 1 11:46:52 2001
+@@ -0,0 +1,35 @@
++#ifndef UTIL_H
++#define UTIL_H 1
++
++#include <glib.h>
++
++#define ORBIT_DEBUG 1
++
++#ifdef ORBIT_DEBUG
++#define ORBIT_DEBUG_NOTE(x) (x)
++#else
++#define ORBIT_DEBUG_NOTE(x)
++#endif
++
++
++#define BitTest(f, bit) ((f) & (1<<(bit)))
++#define BitSet(f, bit) ((f) |= (1<<(bit)))
++#define BitClr(f, bit) ((f) &= ~(1<<(bit)))
++/* Align an address upward to a boundary, expressed as a number of bytes.
++ E.g. align to an 8-byte boundary with argument of 8. */
++
++/*
++ * (this + boundary - 1)
++ * &
++ * ~(boundary - 1)
++ */
++
++#define ALIGN_ADDRESS(this, boundary) \
++ ((gpointer)((( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))))
++
++#include <ORBitutil/thread-safety.h>
++#include <ORBitutil/trace.h>
++#include <ORBitutil/compat.h>
++#include <ORBitutil/os-specifics.h>
++
++#endif
+diff -urN linux-2.4.1/net/korbit/config.h linux-2.4.1-korbit/net/korbit/config.h
+--- linux-2.4.1/net/korbit/config.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/config.h Thu Feb 1 11:46:49 2001
+@@ -0,0 +1,73 @@
++
++/* Define if you have alloca, as a function or macro. */
++#define HAVE_ALLOCA 1
++
++#define HAVE_ATEXIT 1
++#define NO_SYS_SIGLIST 1 /* reduce dependencies */
++#define NO_SYS_ERRLIST 1 /* reduce dependencies */
++
++/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
++/* #define HAVE_ALLOCA_H 1 */
++
++/* Define if you have the vprintf function. */
++#define HAVE_VPRINTF 1
++
++/* Define if you have the ANSI C header files. */
++#define STDC_HEADERS 1
++
++#define HAVE_INET_ATON 1
++/* #undef ORBIT_SERIAL */
++
++/* Define to 'int' if it isn't defined in the header files. */
++/* #undef socklen_t */
++
++#define ALIGNOF_CORBA_BOOLEAN 1
++#define ALIGNOF_CORBA_CHAR 1
++#define ALIGNOF_CORBA_DOUBLE 4
++#define ALIGNOF_CORBA_FLOAT 4
++#define ALIGNOF_CORBA_LONG 4
++#define ALIGNOF_CORBA_LONG_DOUBLE 4
++#define ALIGNOF_CORBA_LONG_LONG 4
++#define ALIGNOF_CORBA_OCTET 1
++#define ALIGNOF_CORBA_SHORT 2
++#define ALIGNOF_CORBA_STRUCT 1
++#define ALIGNOF_CORBA_UNSIGNED_LONG 4
++#define ALIGNOF_CORBA_UNSIGNED_LONG_LONG 4
++#define ALIGNOF_CORBA_UNSIGNED_SHORT 2
++#define ALIGNOF_CORBA_WCHAR 2
++#define ALIGNOF_CORBA_POINTER 4
++
++/* TCP wrappers */
++#define HAVE_TCPD_H 1
++
++#ifdef HAVE_ALLOCA_H
++#include <alloca.h>
++#endif
++
++/* Define if you have the basename function. */
++#define HAVE_BASENAME 1
++
++/* Define if you have the poll function. */
++#define HAVE_POLL 1
++#define I_WANT_POLL 1
++
++/* Define if you have the <endian.h> header file. */
++#define HAVE_ENDIAN_H 1
++
++/* Define if you have the <fcntl.h> header file. */
++#define HAVE_FCNTL_H 1
++
++/* Define if you have the <stddef.h> header file. */
++#define HAVE_STDDEF_H 1
++
++/* Define if you have the <sys/poll.h> header file. */
++#define HAVE_SYS_POLL_H 1
++
++/* Define if you have the <tcpd.h> header file. */
++#define HAVE_TCPD_H 1
++
++/* Define if you have the <unistd.h> header file. */
++#define HAVE_UNISTD_H 1
++
++/* Define if you have the <wchar.h> header file. */
++#define HAVE_WCHAR_H 1
+diff -urN linux-2.4.1/net/korbit/exported_symbols.c linux-2.4.1-korbit/net/korbit/exported_symbols.c
+--- linux-2.4.1/net/korbit/exported_symbols.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/exported_symbols.c Thu Feb 1 11:46:49 2001
+@@ -0,0 +1,93 @@
++/*
++ * #include whatever it takes to get the EXPORT_SYMBOL macro, and
++ * whatever header files from korbit (for things that are being
++ * exported.
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include "errno.h"
++#include "orb/orbit.h"
++
++/*
++ * Stuff that's good to export
++ */
++EXPORT_SYMBOL(errno);
++
++/*
++ * kglib exports...
++ */
++EXPORT_SYMBOL(g_malloc0);
++EXPORT_SYMBOL(g_free);
++EXPORT_SYMBOL(g_snprintf);
++
++/*
++ * Mainline CORBA symbols.
++ */
++EXPORT_SYMBOL(CORBA_exception_init);
++EXPORT_SYMBOL(CORBA_ORB_init);
++EXPORT_SYMBOL(CORBA_ORB_resolve_initial_references);
++EXPORT_SYMBOL(CORBA_ORB_object_to_string);
++EXPORT_SYMBOL(CORBA_free);
++EXPORT_SYMBOL(CORBA_ORB_run);
++EXPORT_SYMBOL(CORBA_Object_release);
++EXPORT_SYMBOL(CORBA_Object_duplicate);
++EXPORT_SYMBOL(CORBA_octet_allocbuf);
++EXPORT_SYMBOL(CORBA_exception_set);
++EXPORT_SYMBOL(CORBA_string__free);
++EXPORT_SYMBOL(CORBA_ORB_string_to_object);
++EXPORT_SYMBOL(CORBA_string_alloc);
++EXPORT_SYMBOL(CORBA_exception_set_system);
++
++/*
++ * ORBIT Specific symbols to export
++ */
++EXPORT_SYMBOL(ORBit_TypeCode_epv);
++EXPORT_SYMBOL(ORBit_send_system_exception);
++EXPORT_SYMBOL(ORBit_register_class);
++EXPORT_SYMBOL(ORBit_marshal_object);
++EXPORT_SYMBOL(ORBit_alloc);
++EXPORT_SYMBOL(ORBit_free);
++EXPORT_SYMBOL(ORBit_send_user_exception);
++EXPORT_SYMBOL(ORBit_delete_profiles);
++EXPORT_SYMBOL(ORBit_demarshal_object);
++EXPORT_SYMBOL(_ORBit_object_get_connection);
++EXPORT_SYMBOL(ORBit_handle_exception);
++EXPORT_SYMBOL(ORBit_object_get_forwarded_connection);
++EXPORT_SYMBOL(ORBit_default_principal_iovec);
++EXPORT_SYMBOL(ORBit_demarshal_IOR);
++
++/*
++ * CORBA giop functions
++ */
++EXPORT_SYMBOL(giop_send_buffer_write);
++EXPORT_SYMBOL(giop_send_buffer_unuse);
++EXPORT_SYMBOL(giop_message_buffer_do_alignment);
++EXPORT_SYMBOL(giop_message_buffer_append_mem);
++EXPORT_SYMBOL(giop_send_reply_buffer_use);
++EXPORT_SYMBOL(giop_send_request_buffer_use);
++EXPORT_SYMBOL(giop_recv_buffer_unuse);
++EXPORT_SYMBOL(giop_recv_reply_buffer_use_2);
++
++/*
++ * POA Symbols.
++ */
++EXPORT_SYMBOL(PortableServer_POAManager_activate);
++EXPORT_SYMBOL(PortableServer_POA_activate_object_with_id);
++EXPORT_SYMBOL(PortableServer_POA_servant_to_reference);
++EXPORT_SYMBOL(PortableServer_POA_deactivate_object);
++EXPORT_SYMBOL(PortableServer_POA__get_the_POAManager);
++EXPORT_SYMBOL(PortableServer_ServantBase__init);
++EXPORT_SYMBOL(PortableServer_ServantBase__fini);
++EXPORT_SYMBOL(PortableServer_POA_reference_to_servant);
++EXPORT_SYMBOL(PortableServer_POA_servant_to_id);
++EXPORT_SYMBOL(PortableServer_POA_activate_object);
++EXPORT_SYMBOL(PortableServer_POA_reference_to_id);
++
++/*
++ * TC Stuff (whatever that is)
++ */
++EXPORT_SYMBOL(TC_octet_struct);
++EXPORT_SYMBOL(TC_long_struct);
++EXPORT_SYMBOL(TC_ulong_struct);
++EXPORT_SYMBOL(TC_short_struct);
++EXPORT_SYMBOL(TC_string_struct);
+diff -urN linux-2.4.1/net/korbit/include/.cvsignore linux-2.4.1-korbit/net/korbit/include/.cvsignore
+--- linux-2.4.1/net/korbit/include/.cvsignore Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/.cvsignore Thu Feb 1 11:46:53 2001
+@@ -0,0 +1 @@
++stdarg.h
+diff -urN linux-2.4.1/net/korbit/include/CVS/Entries linux-2.4.1-korbit/net/korbit/include/CVS/Entries
+--- linux-2.4.1/net/korbit/include/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/CVS/Entries Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,24 @@
++/.cvsignore/1.1/Thu Feb 1 09:46:53 2001//
++/alloca.h/1.3/Thu Feb 1 09:46:53 2001//
++/assert.h/1.1.1.1/Thu Feb 1 09:46:53 2001//
++/ctype.h/1.1.1.1/Thu Feb 1 09:46:53 2001//
++/dirent.h/1.1.1.1/Thu Feb 1 09:46:53 2001//
++/errno.h/1.2/Thu Feb 1 09:46:53 2001//
++/fcntl.h/1.3/Thu Feb 1 09:46:53 2001//
++/host_list.h/1.7/Thu Feb 1 09:46:53 2001//
++/limits.h/1.1.1.1/Thu Feb 1 09:46:53 2001//
++/locale.h/1.1.1.1/Thu Feb 1 09:46:53 2001//
++/math.h/1.2/Thu Feb 1 09:46:53 2001//
++/netdb.h/1.17/Thu Feb 1 09:46:53 2001//
++/pwd.h/1.1.1.1/Thu Feb 1 09:46:53 2001//
++/signal.h/1.1.1.1/Thu Feb 1 09:46:53 2001//
++/stdarg.h/1.3/Thu Feb 1 09:46:54 2001//
++/stddef.h/1.1.1.1/Thu Feb 1 09:46:54 2001//
++/stdio.h/1.19/Thu Feb 1 09:46:54 2001//
++/stdlib.h/1.4/Thu Feb 1 09:46:54 2001//
++/string.h/1.3/Thu Feb 1 09:46:54 2001//
++/syslog.h/1.1.1.1/Thu Feb 1 09:46:54 2001//
++/time.h/1.1.1.1/Thu Feb 1 09:46:54 2001//
++/unistd.h/1.3/Thu Feb 1 09:46:54 2001//
++/utime.h/1.1.1.1/Thu Feb 1 09:46:54 2001//
++D
+diff -urN linux-2.4.1/net/korbit/include/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/include/CVS/Entries.Log
+--- linux-2.4.1/net/korbit/include/CVS/Entries.Log Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/CVS/Entries.Log Thu Feb 1 11:46:55 2001
+@@ -0,0 +1,3 @@
++A D/arpa////
++A D/netinet////
++A D/sys////
+diff -urN linux-2.4.1/net/korbit/include/CVS/Repository linux-2.4.1-korbit/net/korbit/include/CVS/Repository
+--- linux-2.4.1/net/korbit/include/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/CVS/Repository Thu Feb 1 11:46:53 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/include
+diff -urN linux-2.4.1/net/korbit/include/CVS/Root linux-2.4.1-korbit/net/korbit/include/CVS/Root
+--- linux-2.4.1/net/korbit/include/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/CVS/Root Thu Feb 1 11:46:53 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/include/alloca.h linux-2.4.1-korbit/net/korbit/include/alloca.h
+--- linux-2.4.1/net/korbit/include/alloca.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/alloca.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,6 @@
++#ifndef __KORBIT_ALLOCA_H__
++#define __KORBIT_ALLOCA_H__
++
++#include <stdlib.h>
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/arpa/CVS/Entries linux-2.4.1-korbit/net/korbit/include/arpa/CVS/Entries
+--- linux-2.4.1/net/korbit/include/arpa/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/arpa/CVS/Entries Thu Feb 1 11:46:55 2001
+@@ -0,0 +1,2 @@
++/inet.h/1.4/Thu Feb 1 09:46:54 2001//
++D
+diff -urN linux-2.4.1/net/korbit/include/arpa/CVS/Repository linux-2.4.1-korbit/net/korbit/include/arpa/CVS/Repository
+--- linux-2.4.1/net/korbit/include/arpa/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/arpa/CVS/Repository Thu Feb 1 11:46:54 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/include/arpa
+diff -urN linux-2.4.1/net/korbit/include/arpa/CVS/Root linux-2.4.1-korbit/net/korbit/include/arpa/CVS/Root
+--- linux-2.4.1/net/korbit/include/arpa/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/arpa/CVS/Root Thu Feb 1 11:46:54 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/include/arpa/inet.h linux-2.4.1-korbit/net/korbit/include/arpa/inet.h
+--- linux-2.4.1/net/korbit/include/arpa/inet.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/arpa/inet.h Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,50 @@
++#ifndef __KORBIT_ARPA_INET_H__
++#define __KORBIT_ARPA_INET_H__
++
++#include <linux/inet.h>
++#include <linux/in.h>
++
++static inline char* inet_ntoa(struct in_addr in)
++{
++ return in_ntoa(in.s_addr);
++}
++
++static inline int inet_aton(const char *cp, struct in_addr *inp)
++{
++ unsigned long l;
++ unsigned int val;
++ int i;
++
++ if (!cp || !inp)
++ return 0;
++
++ l = 0;
++ for (i = 0; i < 4; i++)
++ {
++ l <<= 8;
++ if (*cp != '\0')
++ {
++ val = 0;
++ while (*cp != '\0' && *cp != '.')
++ {
++ if (*cp < '0' || '9' < *cp)
++ return 0;
++
++ val *= 10;
++ val += *cp - '0';
++ cp++;
++ }
++ if (val > 255)
++ return 0;
++
++ l |= val;
++ if (*cp != '\0')
++ cp++;
++ }
++ }
++ inp->s_addr = htonl(l);
++
++ return 1;
++}
++
++#endif /* __KORBIT_ARPA_INET_H__ */
+diff -urN linux-2.4.1/net/korbit/include/assert.h linux-2.4.1-korbit/net/korbit/include/assert.h
+--- linux-2.4.1/net/korbit/include/assert.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/assert.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,3 @@
++#ifndef __KORBIT_ASSERT_H__
++#define __KORBIT_ASSERT_H__
++#endif
+diff -urN linux-2.4.1/net/korbit/include/ctype.h linux-2.4.1-korbit/net/korbit/include/ctype.h
+--- linux-2.4.1/net/korbit/include/ctype.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/ctype.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,4 @@
++#ifndef __KORBIT_CTYPE_H__
++#define __KORBIT_CTYPE_H__
++#include <linux/ctype.h>
++#endif
+diff -urN linux-2.4.1/net/korbit/include/dirent.h linux-2.4.1-korbit/net/korbit/include/dirent.h
+--- linux-2.4.1/net/korbit/include/dirent.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/dirent.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,3 @@
++#ifndef __KORBIT_DIRENT_H__
++#define __KORBIT_DIRENT_H__
++#endif
+diff -urN linux-2.4.1/net/korbit/include/errno.h linux-2.4.1-korbit/net/korbit/include/errno.h
+--- linux-2.4.1/net/korbit/include/errno.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/errno.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,9 @@
++#ifndef __KORBIT_ERRNO_H__
++#define __KORBIT_ERRNO_H__
++
++#include <asm/errno.h>
++
++#define errno korbit_errno
++extern int korbit_errno;
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/fcntl.h linux-2.4.1-korbit/net/korbit/include/fcntl.h
+--- linux-2.4.1/net/korbit/include/fcntl.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/fcntl.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,49 @@
++#ifndef __KORBIT_FCNTL_H__
++#define __KORBIT_FCNTL_H__
++
++#include <linux/mm.h>
++#include <linux/file.h>
++#include <linux/smp_lock.h>
++
++#include <asm/fcntl.h>
++
++#include <stdio.h>
++
++#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC)
++
++static inline int fcntl(int fd, int cmd, long arg)
++{
++ struct file *filp = fd2file(fd);
++ long err = -EINVAL;
++
++ switch (cmd)
++ {
++ case F_SETFD:
++ case F_GETFD:
++ err = 0;
++ break;
++ case F_GETFL:
++ if (filp)
++ err = filp->f_flags;
++ break;
++ case F_SETFL:
++ if (filp)
++ {
++ lock_kernel();
++
++ /* required for strict SunOS emulation */
++ if (O_NONBLOCK != O_NDELAY)
++ if (arg & O_NDELAY)
++ arg |= O_NONBLOCK;
++
++ filp->f_flags = (arg & SETFL_MASK) |
++ (filp->f_flags & ~SETFL_MASK);
++ err = 0;
++ unlock_kernel();
++ }
++ break;
++ }
++ return err;
++}
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/host_list.h linux-2.4.1-korbit/net/korbit/include/host_list.h
+--- linux-2.4.1/net/korbit/include/host_list.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/host_list.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,24 @@
++/*
++ * A statically-allocated list of Hostnames<->IPv4 addresses.
++ */
++#ifndef __KORBIT_HOST_LIST_H
++#define __KORBIT_HOST_LIST_H
++
++static struct {
++ char *name;
++ char *IP;
++} host_table[] = {
++ {"redefine.dyndns.org", "206.221.225.140"},
++ {"csil-sunb4.cs.uiuc.edu", "128.174.243.204"},
++ {"kazoo.cs.uiuc.edu", "128.174.237.133"},
++ {"opus0.cs.uiuc.edu", "128.174.236.20"},
++ {"wakeland-56.flexabit.net", "64.198.239.56"},
++ {"es-dcl-border1.cso.uiuc.edu", "127.0.0.1"},
++ {"es-dcl-border1", "127.0.0.1"}
++// {"es-dcl-border1.cso.uiuc.edu", "130.126.112.222"},
++// {"es-dcl-border1", "130.126.112.222"}
++};
++
++#define __MAX_STATIC_NAMES (sizeof(host_table) / sizeof(host_table[0]))
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/limits.h linux-2.4.1-korbit/net/korbit/include/limits.h
+--- linux-2.4.1/net/korbit/include/limits.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/limits.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,7 @@
++#ifndef __KORBIT_LIMITS_H__
++#define __KORBIT_LIMITS_H__
++
++#include <linux/limits.h>
++#include <linux/kernel.h>
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/locale.h linux-2.4.1-korbit/net/korbit/include/locale.h
+--- linux-2.4.1/net/korbit/include/locale.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/locale.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,3 @@
++#ifndef __KORBIT_LOCALE_H__
++#define __KORBIT_LOCALE_H__
++#endif
+diff -urN linux-2.4.1/net/korbit/include/math.h linux-2.4.1-korbit/net/korbit/include/math.h
+--- linux-2.4.1/net/korbit/include/math.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/math.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,16 @@
++#ifndef __KORBIT_MATH_H__
++#define __KORBIT_MATH_H__
++
++#include <asm/page.h>
++
++static inline double pow(double x, double y) {
++ double Q = 1.0;
++ if (y < 0)
++ BUG();
++/* return 1.0/pow(x,-y);*/
++ while (y-- > 0)
++ Q *= x;
++ return Q;
++}
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/netdb.h linux-2.4.1-korbit/net/korbit/include/netdb.h
+--- linux-2.4.1/net/korbit/include/netdb.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/netdb.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,197 @@
++#ifndef __KORBIT_NETDB_H__
++#define __KORBIT_NETDB_H__
++
++#include <sys/socket.h>
++#include <linux/in.h>
++#include <arpa/inet.h>
++#include "host_list.h"
++
++#define h_errno 0
++/* static int h_errno; */
++
++/* Description of data base entry for a single host. */
++struct hostent
++{
++ char *h_name; /* Official name of host. */
++ char **h_aliases; /* Alias list. */
++ int h_addrtype; /* Host address type. */
++ socklen_t h_length; /* Length of address. */
++ char **h_addr_list; /* List of addresses from name server. */
++#define h_addr h_addr_list[0] /* Address, for backward compatibility. */
++};
++
++/* Is this defined somewhere else? */
++/*struct in_addr {
++ __uint32_t s_addr;
++};*/
++
++/*
++ * Set h_errno?
++ * #define HOST_NOT_FOUND 1
++ * #define TRY_AGAIN 2
++ * #define NO_RECOVERY 3
++ * #define NO_DATA 4
++ */
++static inline struct hostent *gethostbyname (char *host)
++{
++ int c;
++ static struct in_addr tmp_in;
++ static struct hostent ret_host;
++ static char *aliases[2];
++ static char *addrs[2];
++
++ if (host == NULL)
++ {
++ printf ("** gethostbyname() Error: Got NULL parameter! **\n");
++ return (NULL);
++ }
++
++ /*
++ * The actual lookup.
++ */
++ for (c = 0; c < __MAX_STATIC_NAMES; c++)
++ {
++ if (host_table[c].name && strncmp (host, host_table[c].name, strlen(host_table[c].name)) == 0)
++ {
++/* printf ("Name '%s' found at position %d!\n", argv[1], c);*/
++/* printf ("IP address is: '%s'.\n", IPs[c]);*/
++ break;
++ }
++ }
++
++ if (c == __MAX_STATIC_NAMES)
++ {
++ /* Host not found, return NULL. */
++ return (NULL);
++ }
++ /* else, names[c] is gold! */
++
++ /* make a new hostent, ret_host */
++
++ ret_host.h_addrtype = AF_INET;
++ ret_host.h_aliases = aliases;
++ aliases[0] = host_table[c].name;
++ aliases[1] = NULL;
++ ret_host.h_name = host_table[c].name;
++ if (!inet_aton (host_table[c].IP, &tmp_in))
++ {
++ printf ("** gethostbyname() Error: Invalid IP address in table! **\n");
++ return (NULL);
++ }
++ ret_host.h_addr_list = addrs;
++ addrs[0] = (char *)&tmp_in.s_addr;
++ addrs[1] = NULL;
++ ret_host.h_length = sizeof (tmp_in.s_addr);
++ return (&ret_host);
++} /* End gethostbyname(). */
++
++/*
++ * TODO: getpeername(), gethostbyaddr(), getsockname(), gethostname()
++ * Everything from here-on has been untested (in userland). Buyer beware.
++ */
++static inline struct hostent *gethostbyaddr (const char *addr, int len, int type)
++{
++ struct in_addr tin;
++ char *inp_addr;
++ int c;
++ static struct hostent ret_host;
++ static char *aliases[1];
++ static char *addrs[2];
++ static struct in_addr tmp_in;
++
++
++ if ((type != AF_INET) || (len != 4))
++ {
++ printf ("** gethostbyaddr Error: Don't know how to deal with non-AF_INET addresses! **\n");
++ return (NULL);
++ }
++
++ tin.s_addr = *((__u32 *)addr);
++ inp_addr = inet_ntoa (tin);
++ if (inp_addr == NULL)
++ {
++ /* We got some invalid input, baby. */
++ return (NULL);
++
++ }
++
++ /*
++ * The actual lookup.
++ */
++ for (c = 0; c < __MAX_STATIC_NAMES; c++)
++ {
++ if (host_table[c].IP && strncmp (inp_addr, host_table[c].IP, strlen(host_table[c].IP)) == 0)
++ {
++ break;
++ }
++ }
++
++ if (c == __MAX_STATIC_NAMES)
++ {
++ /* Host not found, return NULL. */
++ return (NULL);
++ }
++ /* else, host_table[c].IP is gold! */
++
++ ret_host.h_addrtype = AF_INET;
++ ret_host.h_aliases = aliases;
++ aliases[0] = NULL;
++ ret_host.h_name = host_table[c].name;
++ if (!inet_aton (host_table[c].IP, &tmp_in))
++ {
++ printf ("** gethostbyname() Error: Invalid IP address in table! **\n");
++ return (NULL);
++ }
++ ret_host.h_addr_list = addrs;
++ addrs[0] = (char *)&tmp_in.s_addr;
++ addrs[1] = NULL;
++ ret_host.h_length = sizeof (tmp_in.s_addr);
++ return (&ret_host);
++} /* End gethostbyaddr(). */
++
++/*
++ * If successful, return 0. Else, return -1 and set errno.
++ * Errors:
++ * EBADF The argument s is not a valid file descriptor.
++ *
++ * ENOMEM
++ * There was insufficient memory available for the opera-
++ * tion to complete.
++ *
++ * ENOSR There were insufficient STREAMS resources available
++ * for the operation to complete.
++ *
++ * ENOTSOCK
++ * The argument s is not a socket.
++ */
++static inline int getsockname (int s, struct sockaddr *name, socklen_t *namelen)
++{
++ struct socket *sock = fd2sock(s);
++
++ if (sock == NULL)
++ return -1;
++
++ /*
++ * getname() wants an 'int *' for the length, will it by this
++ * 'socklen_t *' business? (even though it is just an 'int *'?).
++ */
++ if (sock->ops->getname(sock, name, namelen, 0) == 0)
++ return 0;
++ else
++ return -1; /* should normally also set errno */
++} /* End getsockname(). */
++
++static inline int getpeername (int s, struct sockaddr *name, socklen_t *namelen)
++{
++ struct socket *sock = fd2sock(s);
++
++ if (sock == NULL)
++ return -1;
++
++ if (sock->ops->getname(sock, name, namelen, 1) == 0)
++ return 0;
++ else
++ return -1; /* should normally also set errno */
++} /* End getpeername(). */
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/netinet/CVS/Entries linux-2.4.1-korbit/net/korbit/include/netinet/CVS/Entries
+--- linux-2.4.1/net/korbit/include/netinet/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/netinet/CVS/Entries Thu Feb 1 11:46:55 2001
+@@ -0,0 +1,2 @@
++/in.h/1.1.1.1/Thu Feb 1 09:46:55 2001//
++D
+diff -urN linux-2.4.1/net/korbit/include/netinet/CVS/Repository linux-2.4.1-korbit/net/korbit/include/netinet/CVS/Repository
+--- linux-2.4.1/net/korbit/include/netinet/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/netinet/CVS/Repository Thu Feb 1 11:46:55 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/include/netinet
+diff -urN linux-2.4.1/net/korbit/include/netinet/CVS/Root linux-2.4.1-korbit/net/korbit/include/netinet/CVS/Root
+--- linux-2.4.1/net/korbit/include/netinet/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/netinet/CVS/Root Thu Feb 1 11:46:55 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/include/netinet/in.h linux-2.4.1-korbit/net/korbit/include/netinet/in.h
+--- linux-2.4.1/net/korbit/include/netinet/in.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/netinet/in.h Thu Feb 1 11:46:55 2001
+@@ -0,0 +1,5 @@
++#ifndef __KORBIT_NETINET_IN_H__
++#define __KORBIT_NETINET_IN_H__
++#include <linux/socket.h>
++#include <linux/in.h>
++#endif
+diff -urN linux-2.4.1/net/korbit/include/pwd.h linux-2.4.1-korbit/net/korbit/include/pwd.h
+--- linux-2.4.1/net/korbit/include/pwd.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/pwd.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,3 @@
++#ifndef __KORBIT_PWD_H__
++#define __KORBIT_PWD_H__
++#endif
+diff -urN linux-2.4.1/net/korbit/include/signal.h linux-2.4.1-korbit/net/korbit/include/signal.h
+--- linux-2.4.1/net/korbit/include/signal.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/signal.h Thu Feb 1 11:46:53 2001
+@@ -0,0 +1,6 @@
++#ifndef __KORBIT_SIGNAL_H__
++#define __KORBIT_SIGNAL_H__
++
++#include <asm/signal.h>
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/stdarg.h linux-2.4.1-korbit/net/korbit/include/stdarg.h
+--- linux-2.4.1/net/korbit/include/stdarg.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/stdarg.h Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,13 @@
++#ifndef __KORBIT_STDARG_H__
++#define __KORBIT_STDARG_H__
++
++#define ANDY 1
++
++#if FREDRIK
++#include "/usr/lib/gcc-lib/i386-glibc21-linux/egcs-2.91.66/include/stdarg.h"
++#elif CHRIS
++#include "/usr/lib/gcc-lib/i586-mandrake-linux/egcs-2.91.66/include/stdarg.h"
++#elif ANDY
++#include "/usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/include/stdarg.h"
++#endif
++#endif
+diff -urN linux-2.4.1/net/korbit/include/stddef.h linux-2.4.1-korbit/net/korbit/include/stddef.h
+--- linux-2.4.1/net/korbit/include/stddef.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/stddef.h Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,3 @@
++#ifndef __KORBIT_STDDEF_H__
++#define __KORBIT_STDDEF_H__
++#endif
+diff -urN linux-2.4.1/net/korbit/include/stdio.h linux-2.4.1-korbit/net/korbit/include/stdio.h
+--- linux-2.4.1/net/korbit/include/stdio.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/stdio.h Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,402 @@
++#ifndef __KORBIT_STDIO_H__
++#define __KORBIT_STDIO_H__
++
++#include <asm/segment.h>
++#include <asm/uaccess.h>
++#include <linux/smp_lock.h>
++#include <linux/kernel.h>
++#include <linux/fs.h>
++#include <linux/sched.h>
++#include <linux/uio.h>
++#include <linux/dcache.h>
++#include <linux/file.h>
++#include <linux/highuid.h>
++#include <sys/socket.h>
++
++#include <errno.h>
++
++#define KORBIT_DEBUG_WRITING 0
++
++
++#define printf(format,args...) printk(format,##args)
++#define fflush(x)
++
++#define SEEK_SET 0 /* Seek from beginning of file. */
++#define SEEK_CUR 1 /* Seek from current position. */
++#define SEEK_END 2 /* Seek from end of file. */
++
++static inline int unlink(const char *pathname) {
++ printf("KERNEL UNLINK('%s') CALLED!\n", pathname);
++ return -1;
++}
++
++static inline struct file *fd2file(int fd) {
++ if (fd & 1) /* can't convert a socket! */
++ return NULL;
++
++ return (struct file *)(-(fd & ~1));
++}
++
++static inline int open(const char *filename, int flags, int mode) {
++ struct file *RetVal = filp_open(filename, flags, mode);
++ if (IS_ERR(RetVal))
++ {
++ errno = PTR_ERR(RetVal);
++ return -1;
++ }
++ return -(int)RetVal;
++}
++
++static inline int creat(const char *filename, mode_t mode)
++{
++ return open(filename, O_CREAT | O_WRONLY | O_TRUNC, mode);
++}
++
++static inline int lseek(int fd, long offset, int whence)
++{
++ if ((fd & 1) == 1)
++ {
++ printk("KERNEL FSEEK() CALLED ON SOCKET!\n");
++ return -1;
++ }
++ else
++ {
++ struct file *F = fd2file(fd);
++ loff_t (*fn)(struct file *, loff_t, int);
++ int retval = -1;
++
++ if (whence <= 2)
++ {
++ fn = default_llseek;
++ if (F->f_op && F->f_op->llseek)
++ fn = F->f_op->llseek;
++
++ lock_kernel();
++ retval = fn(F, offset, whence);
++ unlock_kernel();
++ }
++ if (retval < 0)
++ {
++ errno = -retval;
++ retval = -1;
++ }
++ return retval;
++ }
++}
++
++
++asmlinkage long sys_newstat(char * filename, struct stat * statbuf);
++static inline int stat(char *filename, struct stat *buf)
++{
++ mm_segment_t oldfs;
++ int retval;
++
++ oldfs = get_fs(); set_fs(KERNEL_DS);
++ retval = sys_newstat(filename, buf);
++ set_fs(oldfs);
++ if (retval < 0)
++ {
++ errno = -retval;
++ retval = -1;
++ }
++ return retval;
++}
++
++asmlinkage long sys_newlstat(char * filename, struct stat * statbuf);
++static inline int lstat(char *filename, struct stat *buf)
++{
++ mm_segment_t oldfs;
++ int retval;
++
++ oldfs = get_fs(); set_fs(KERNEL_DS);
++ retval = sys_newlstat(filename, buf);
++ set_fs(oldfs);
++ if (retval < 0)
++ {
++ errno = -retval;
++ retval = -1;
++ }
++ return retval;
++}
++
++
++static inline int do_revalidate(struct dentry *dentry)
++{
++ struct inode * inode = dentry->d_inode;
++ if (inode->i_op && inode->i_op->revalidate)
++ return inode->i_op->revalidate(dentry);
++ return 0;
++}
++
++
++static inline int cp_new_stat(struct inode * inode, struct stat * statbuf)
++{
++ struct stat tmp;
++
++ memset(&tmp, 0, sizeof(tmp));
++ tmp.st_dev = kdev_t_to_nr(inode->i_dev);
++ tmp.st_ino = inode->i_ino;
++ tmp.st_mode = inode->i_mode;
++ tmp.st_nlink = inode->i_nlink;
++ SET_STAT_UID(tmp, inode->i_uid);
++ SET_STAT_GID(tmp, inode->i_gid);
++ tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
++#if BITS_PER_LONG == 32
++ if (inode->i_size > 0x7fffffff)
++ return -EOVERFLOW;
++ else
++#endif
++ {
++ tmp.st_size = inode->i_size;
++ tmp.st_atime = inode->i_atime;
++ tmp.st_mtime = inode->i_mtime;
++ tmp.st_ctime = inode->i_ctime;
++
++ tmp.st_blocks = inode->i_blocks;
++ tmp.st_blksize = inode->i_blksize;
++
++ memcpy(statbuf, &tmp, sizeof(tmp));
++ return 0;
++ }
++}
++
++
++static inline int fstat(int fd, struct stat *buf)
++{
++ if ((fd & 1) == 1)
++ {
++ printk("TODO : FSTAT FOR SOCKETS, DO WE WANT THIS?\n");
++ errno = EBADF;
++ return -1;
++ }
++ else
++ {
++ struct file *file = fd2file(fd);
++ struct dentry *dentry;
++ int retval = -EBADF;
++
++ if (file)
++ {
++ dentry = file->f_dentry;
++ retval = do_revalidate(dentry);
++
++ if (!retval)
++ retval = cp_new_stat(dentry->d_inode, buf);
++ }
++ if (retval < 0)
++ {
++ errno = -retval;
++ retval = -1;
++ }
++ return retval;
++ }
++}
++
++
++asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz);
++static inline int readlink(const char *path, char *buf, size_t bufsiz)
++{
++ int retval;
++ mm_segment_t oldfs;
++
++ oldfs = get_fs(); set_fs(KERNEL_DS);
++ retval = sys_readlink(path, buf, bufsiz);
++ set_fs(oldfs);
++ if (retval < 0)
++ {
++ errno = -retval;
++ retval = -1;
++ }
++ return retval;
++}
++
++
++static inline int read(int fd, void *buffer, size_t count) {
++ if ((fd & 1) == 1)
++ {
++ struct socket *sock = fd2sock(fd);
++ struct iovec iov;
++ struct msghdr msg;
++ mm_segment_t oldfs;
++ int flags = 0;
++ int RetVal;
++
++ msg.msg_name = NULL;
++ msg.msg_namelen = 0;
++ msg.msg_iov = &iov;
++ msg.msg_iovlen = 1;
++ msg.msg_control = NULL;
++ msg.msg_controllen = 0;
++ msg.msg_flags = 0;
++ iov.iov_base = buffer;
++ iov.iov_len = count;
++ oldfs = get_fs(); set_fs(KERNEL_DS);
++ RetVal = sock_recvmsg(sock, &msg, count, flags);
++ set_fs(oldfs);
++ if (RetVal < 0)
++ {
++ errno = -RetVal;
++ RetVal = -1;
++ }
++ return RetVal;
++ }
++ else
++ {
++ struct file *F = fd2file(fd);
++ mm_segment_t oldfs;
++ int RetVal;
++
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ RetVal = F->f_op->read(F, buffer, count, &F->f_pos);
++ set_fs(oldfs);
++ if (RetVal < 0)
++ {
++ errno = -RetVal;
++ RetVal = -1;
++ }
++ return RetVal;
++ }
++}
++
++static inline int write(int fd, const void *buffer, size_t count) {
++ if ((fd & 1) == 1)
++ {
++ struct socket *sock = fd2sock(fd);
++ struct iovec iov;
++ struct msghdr msg;
++ mm_segment_t oldfs;
++ int RetVal;
++ msg.msg_name = NULL;
++ msg.msg_namelen = 0;
++ msg.msg_iov = &iov;
++ msg.msg_iovlen = 1;
++ msg.msg_control = NULL;
++ msg.msg_controllen = 0;
++ msg.msg_flags = MSG_NOSIGNAL;
++ if (sock->type == SOCK_SEQPACKET)
++ msg.msg_flags |= MSG_EOR;
++ iov.iov_base = (void *)buffer;
++ iov.iov_len = count;
++
++ oldfs = get_fs(); set_fs(KERNEL_DS);
++ RetVal = sock_sendmsg(sock, &msg, count);
++ set_fs(oldfs);
++ if (RetVal < 0)
++ {
++ errno = -RetVal;
++ RetVal = -1;
++ }
++ return RetVal;
++ }
++ else
++ {
++ struct file *F = fd2file(fd);
++ mm_segment_t oldfs;
++ int RetVal;
++
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ RetVal = F->f_op->write(F, buffer, count, &F->f_pos);
++ set_fs(oldfs);
++ if (RetVal < 0)
++ {
++ errno = -RetVal;
++ RetVal = -1;
++ }
++ return RetVal;
++ }
++}
++
++static inline int writev(int fd, const struct iovec *vector, int count) {
++#ifndef DONT_USE_SIMPLE_WRITEV
++ int i, amount = 0;
++#if KORBIT_DEBUG_WRITING
++ printk("writev (fd = 0x%X, vec=0x%p, count = %d)\n", fd, vector, count);
++#endif
++ for (i = 0; i < count; i++) {
++ char *Buf = vector[i].iov_base;
++ int Amount = vector[i].iov_len;
++ while (Amount > 0) {
++ int A = write(fd, Buf, Amount);
++//#if KORBIT_DEBUG_WRITING
++if (A < Amount)
++ printk(" write(fd = 0x%X, buf = 0x%p, size = 0x%X) "
++ "= 0x%X errno = 0x%X\n", fd, Buf, Amount, A, errno);
++//#endif
++ Amount -= A;
++ amount += A;
++ Buf += A;
++ if (Amount > 0) schedule(); // Behave somewhat nicely...
++ }
++ }
++
++#if KORBIT_DEBUG_WRITING
++ printk("writev returning 0x%X[%d]\n", amount, amount);
++#endif
++ return amount;
++
++#else
++ if ((fd & 1) == 1)
++ {
++ struct socket *sock = fd2sock(fd);
++ struct msghdr msg;
++ mm_segment_t oldfs;
++ int i, RetVal;
++ size_t tot_len = 0;
++
++ for (i = 0; i < count; i++)
++ tot_len += vector[i].iov_len;
++
++ msg.msg_name = NULL;
++ msg.msg_namelen = 0;
++ msg.msg_iov = (struct iovec *)vector;
++ msg.msg_iovlen = count;
++ msg.msg_control = NULL;
++ msg.msg_controllen = 0;
++ if (sock->type == SOCK_SEQPACKET)
++ msg.msg_flags |= MSG_EOR;
++
++ oldfs = get_fs(); set_fs(KERNEL_DS);
++ RetVal = sock_sendmsg(sock, &msg, tot_len);
++ set_fs(oldfs);
++ if (RetVal < 0)
++ {
++ errno = -RetVal;
++ RetVal = -1;
++ }
++ return RetVal;
++ }
++ else
++ {
++ struct file *F = fd2file(fd);
++ mm_segment_t oldfs;
++ int RetVal;
++
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ RetVal = F->f_op->writev(F, vector, (unsigned)count, &F->f_pos);
++ set_fs(oldfs);
++ if (RetVal < 0)
++ {
++ errno = -RetVal;
++ RetVal = -1;
++ }
++ return RetVal;
++ }
++#endif
++}
++
++static inline int close(int fd) {
++ int err = 0;
++ if ((fd & 1) == 1) {
++ struct socket *sock = fd2sock(fd);
++ sock_release(sock);
++ } else {
++ struct file *file = fd2file(fd);
++ fput(file);
++ }
++ return err;
++}
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/stdlib.h linux-2.4.1-korbit/net/korbit/include/stdlib.h
+--- linux-2.4.1/net/korbit/include/stdlib.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/stdlib.h Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,99 @@
++#ifndef __KORBIT_STDLIB_H__
++#define __KORBIT_STDLIB_H__
++
++#include <linux/kernel.h>
++#include <linux/malloc.h>
++#include <linux/types.h>
++#include <asm/string.h>
++
++#define strtol(nptr,endptr,base) simple_strtol(nptr,endptr,base)
++
++#if 0
++#define malloc(size) kmalloc(size, GFP_KERNEL)
++#define free(ptr) kfree(ptr)
++#endif
++
++static inline void *malloc(size_t size)
++{
++ void *ptr = NULL;
++
++ if (size == 0)
++ size = 4;
++
++ ptr = kmalloc(size + sizeof(size), GFP_KERNEL);
++
++ if (ptr)
++ {
++ *((size_t *)ptr) = size;
++ ptr = (size_t *)ptr + 1;
++ }
++
++ return ptr;
++}
++
++static inline void free(void *ptr)
++{
++ if (ptr)
++ kfree((size_t *)ptr - 1);
++}
++
++#define alloca(size) malloc(size)
++
++/* freeca(ptr) - free a mem allocation if ptr points to one, otherwise do
++ * nothing.
++ */
++static inline void freeca(void *ptr)
++{
++ if (ptr != NULL) { /* Don't free it if it's already free */
++ free(ptr);
++ }
++}
++
++static inline void *calloc(size_t nmemb, size_t size)
++{
++ void *ptr = malloc(nmemb*size);
++ if (ptr)
++ memset(ptr,0,nmemb*size);
++ return ptr;
++}
++
++static inline void *realloc(void *ptr, size_t size)
++{
++ void *newptr = NULL;
++
++ if (size != 0)
++ newptr = malloc(size);
++
++ if (ptr && newptr) /* Copy old contents */
++ {
++ size_t *p1 = (size_t *)ptr - 1;
++ size_t *p2 = (size_t *)newptr - 1;
++ size_t n = *p1 < *p2 ? *p1 : *p2;
++ memcpy(newptr, ptr, n);
++ }
++
++ if (ptr)
++ free(ptr);
++
++ return newptr;
++}
++
++/* Returned by `div'. */
++typedef struct
++{
++ int quot; /* Quotient. */
++ int rem; /* Remainder. */
++} div_t;
++
++static inline div_t div(int number, int denom)
++{
++ div_t result;
++ result.quot = number/denom;
++ result.rem = number-(number*result.quot);
++ return result;
++}
++
++#define atexit(fn) -1
++#define getenv(name) 0
++
++#endif /* __KORBIT_STDLIB_H__ */
+diff -urN linux-2.4.1/net/korbit/include/string.h linux-2.4.1-korbit/net/korbit/include/string.h
+--- linux-2.4.1/net/korbit/include/string.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/string.h Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,11 @@
++#ifndef __KORBIT_STRING_H__
++#define __KORBIT_STRING_H__
++
++#include <linux/types.h>
++#include <asm/string.h>
++
++#include <glib.h>
++
++#define strerror(errno) g_strerror(errno)
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/sys/CVS/Entries linux-2.4.1-korbit/net/korbit/include/sys/CVS/Entries
+--- linux-2.4.1/net/korbit/include/sys/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/CVS/Entries Thu Feb 1 11:46:56 2001
+@@ -0,0 +1,10 @@
++/ioctl.h/1.1.1.1/Thu Feb 1 09:46:55 2001//
++/poll.h/1.25/Thu Feb 1 09:46:55 2001//
++/socket.h/1.20/Thu Feb 1 09:46:55 2001//
++/stat.h/1.1.1.1/Thu Feb 1 09:46:55 2001//
++/time.h/1.1.1.1/Thu Feb 1 09:46:55 2001//
++/types.h/1.1.1.1/Thu Feb 1 09:46:56 2001//
++/uio.h/1.1.1.1/Thu Feb 1 09:46:56 2001//
++/un.h/1.1.1.1/Thu Feb 1 09:46:56 2001//
++/wait.h/1.1.1.1/Thu Feb 1 09:46:56 2001//
++D
+diff -urN linux-2.4.1/net/korbit/include/sys/CVS/Repository linux-2.4.1-korbit/net/korbit/include/sys/CVS/Repository
+--- linux-2.4.1/net/korbit/include/sys/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/CVS/Repository Thu Feb 1 11:46:55 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/include/sys
+diff -urN linux-2.4.1/net/korbit/include/sys/CVS/Root linux-2.4.1-korbit/net/korbit/include/sys/CVS/Root
+--- linux-2.4.1/net/korbit/include/sys/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/CVS/Root Thu Feb 1 11:46:55 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/include/sys/ioctl.h linux-2.4.1-korbit/net/korbit/include/sys/ioctl.h
+--- linux-2.4.1/net/korbit/include/sys/ioctl.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/ioctl.h Thu Feb 1 11:46:55 2001
+@@ -0,0 +1,3 @@
++#ifndef __KORBIT_SYS_IOCTL_H__
++#define __KORBIT_SYS_IOCTL_H__
++#endif
+diff -urN linux-2.4.1/net/korbit/include/sys/poll.h linux-2.4.1-korbit/net/korbit/include/sys/poll.h
+--- linux-2.4.1/net/korbit/include/sys/poll.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/poll.h Fri Feb 2 01:22:10 2001
+@@ -0,0 +1,112 @@
++#ifndef __KORBIT_SYS_POLL_H__
++#define __KORBIT_SYS_POLL_H__
++
++#include <asm/poll.h>
++#include <asm/param.h>
++#include <linux/net.h>
++#include <linux/tcp.h>
++#include <linux/socket.h>
++#include <net/tcp.h>
++#include <net/sock.h>
++#include <linux/skbuff.h>
++#include <linux/sched.h>
++#include "stdlib.h"
++#include "sys/socket.h"
++
++/* Poll the file descriptors described by the NFDS structures starting at
++ * FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
++ * an event to occur; if TIMEOUT is -1, block until an event occurs.
++ * Returns the number of file descriptors with events, zero if timed
++ * out, or -1 for errors.
++ */
++
++/* This implementation of poll assumes that we are sitting on the wait
++ * queues for all of the file descriptors already. Therefore if we are about
++ * to block, all we have to do is perform the schedule call which will
++ * automatically cause us to "block".
++ */
++static int poll_CheckFDs(struct pollfd *fds, unsigned long int nfds)
++{
++ int NumReady = 0, i;
++
++ // Loop over the file descriptors seeing if there is already work to be
++ // done...
++ for (i = 0; i < nfds; i++) {
++ struct socket *sock = fd2sock(fds[i].fd);
++ fds[i].revents = 0;
++
++ // Check to see if stuff is available to read
++ if (sock) {
++ // It's a socket baby
++ fds[i].revents = tcp_poll(0, sock, 0);
++
++ // Apparently tcp_poll doesn't look at the CLOSE_WAIT value,
++ // and we have a lot of sockets that end up in this state.
++ // This is a hack to shortcircuit some read failures from
++ // later. This breaks "poll semantics" strictly speaking, but
++ // it's basically the "right thing to do" (tm).
++ if (sock->sk->state == TCP_CLOSE_WAIT)
++ fds[i].revents = POLLHUP;
++ fds[i].revents &= fds[i].events | POLLERR | POLLHUP;
++ } else {
++ // It's a file
++ //struct file *f = fd2file(fd);
++// printk("POLL NOT IMPLEMENTED FOR FILES YET\n");
++ BUG();
++ }
++
++ if (fds[i].revents) {
++ NumReady++;
++// printk("FD #%d: Event = 0x%X\n", i, fds[i].revents);
++ }
++
++ } /* for */
++
++ return NumReady;
++} /* End poll_CheckFDs(). */
++
++
++static int poll(struct pollfd *fds, unsigned long int nfds, int timeout) {
++ wait_queue_t *WaitQueues = 0;
++ int NumReady = poll_CheckFDs(fds, nfds);
++ int i;
++
++ if (NumReady || timeout == 0)
++ return NumReady;
++
++// printk("Starting to Poll... %d fds...\n", nfds);
++ WaitQueues = (wait_queue_t*)malloc(nfds*sizeof(wait_queue_t));
++ if (WaitQueues == 0) return 0; // Crap, nomem...
++
++ for (i = 0; i < nfds; i++) {
++ struct socket *sock = fd2sock(fds[i].fd);
++ init_waitqueue_entry(WaitQueues+i, current);
++
++ if (sock)
++ add_wait_queue_exclusive(sock->sk->sleep, WaitQueues+i);
++// else
++// printk("I don't know how to wait on fd #%d = 0x%X\n", i, fds[i].fd);
++ }
++
++ // Wait for us to get notified by one of the socket wait queue notifiers!
++ do {
++ // Change our task state so that we are not immediately rescheduled.
++ // This lets the scheduler know that we are waiting for something to happen
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule();
++ } while (!(NumReady = poll_CheckFDs(fds, nfds)));
++
++ set_current_state(TASK_RUNNING);
++
++ for (i = 0; i < nfds; i++) {
++ struct socket *sock = fd2sock(fds[i].fd);
++ if (sock)
++ remove_wait_queue(sock->sk->sleep, WaitQueues+i);
++ }
++
++ free(WaitQueues);
++// printk("Returning %d\n", NumReady);
++ return NumReady;
++}
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/sys/socket.h linux-2.4.1-korbit/net/korbit/include/sys/socket.h
+--- linux-2.4.1/net/korbit/include/sys/socket.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/socket.h Thu Feb 1 11:46:55 2001
+@@ -0,0 +1,126 @@
++#ifndef __KORBIT_SYS_SOCKET_H__
++#define __KORBIT_SYS_SOCKET_H__
++typedef unsigned int socklen_t;
++
++#include <linux/socket.h>
++#include <linux/wait.h>
++#include <asm/semaphore.h>
++#include <net/sock.h>
++
++/* These functions are declared in net/socket.c */
++asmlinkage long sys_socket(int family, int type, int protocol);
++struct socket *sockfd_lookup(int fd, int *err);
++
++
++static inline int sock2fd(struct socket *s)
++{
++ return (-(int)s) | 1;
++}
++
++static inline struct socket *fd2sock(int sockfd)
++{
++ if ((sockfd & 1) == 0) /* can't convert a file! */
++ return NULL;
++
++ return (struct socket *)(-(sockfd & ~1));
++}
++
++
++static inline int socket(int domain, int type, int protocol) {
++ struct socket *sock;
++ int retval = sock_create(domain, type, protocol, &sock);
++
++ if (retval < 0) return (int)NULL;
++ return sock2fd(sock);
++}
++
++
++static inline int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen)
++{
++ struct socket *sock = fd2sock(sockfd);
++
++ if (sock == NULL)
++ return -1;
++ if (!sock->ops->bind(sock, my_addr, addrlen))
++ return 0;
++ else
++ return -1; /* should normally also set errno */
++}
++
++
++static inline int connect(int sockfd, const struct sockaddr *serv_addr,
++ socklen_t addrlen)
++{
++ struct socket *sock = fd2sock(sockfd);
++ int flags = 0; /* TODO : what is flags supposed to be? */
++
++ if (sock == NULL)
++ return -1;
++
++ if (sock->ops->connect(sock, (struct sockaddr *)serv_addr, addrlen, flags) == 0)
++ return 0;
++ else
++ return -1; /* should normally also set errno */
++}
++
++
++static inline int listen(int sockfd, int backlog)
++{
++ struct socket *sock = fd2sock(sockfd);
++
++ if (sock == NULL)
++ return -1;
++
++ if (sock->ops->listen(sock, backlog) == 0)
++ return 0;
++ else
++ return -1; /* should normally also set errno */
++}
++
++
++static inline int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
++{
++ struct socket *sock = fd2sock(sockfd);
++ struct socket *newsock;
++ struct sockaddr_in *newaddr = (struct sockaddr_in *)addr; /* check? */
++ int flags = 0; /* Should be ok */
++
++ if (sock == 0)
++ return -1;
++
++ newsock = sock_alloc();
++ if (newsock == 0)
++ return -1;
++
++ newsock->type = sock->type;
++ newsock->ops = sock->ops;
++ if (sock->ops->accept(sock, newsock, flags) < 0)
++ {
++ sock_release(newsock);
++ return -1; /* should normally also set errno */
++ }
++
++ newaddr->sin_family = AF_INET;
++ newaddr->sin_port = newsock->sk->dport;
++ newaddr->sin_addr.s_addr = newsock->sk->daddr;
++
++ *addrlen = sizeof(newaddr);
++
++ return sock2fd(newsock);
++}
++
++
++static inline int shutdown(int sockfd, int how)
++{
++ struct socket *sock = fd2sock(sockfd);
++
++ if (sock == NULL)
++ return -1;
++
++ if (sock->ops->shutdown(sock, how) == 0)
++ return 0;
++ else
++ return -1; /* should normally also set errno */
++}
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/sys/stat.h linux-2.4.1-korbit/net/korbit/include/sys/stat.h
+--- linux-2.4.1/net/korbit/include/sys/stat.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/stat.h Thu Feb 1 11:46:55 2001
+@@ -0,0 +1,3 @@
++#ifndef __KORBIT_SYS_STAT_H__
++#define __KORBIT_SYS_STAT_H__
++#endif
+diff -urN linux-2.4.1/net/korbit/include/sys/time.h linux-2.4.1-korbit/net/korbit/include/sys/time.h
+--- linux-2.4.1/net/korbit/include/sys/time.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/time.h Thu Feb 1 11:46:55 2001
+@@ -0,0 +1,6 @@
++#ifndef __KORBIT_TIME_H__
++#define __KORBIT_TIME_H__
++
++#include <linux/time.h>
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/sys/types.h linux-2.4.1-korbit/net/korbit/include/sys/types.h
+--- linux-2.4.1/net/korbit/include/sys/types.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/types.h Thu Feb 1 11:46:56 2001
+@@ -0,0 +1,4 @@
++#ifndef __KORBIT_SYS_TYPES_H__
++#define __KORBIT_SYS_TYPES_H__
++#include <linux/types.h>
++#endif
+diff -urN linux-2.4.1/net/korbit/include/sys/uio.h linux-2.4.1-korbit/net/korbit/include/sys/uio.h
+--- linux-2.4.1/net/korbit/include/sys/uio.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/uio.h Thu Feb 1 11:46:56 2001
+@@ -0,0 +1,4 @@
++#ifndef __KORBIT_SYS_UIO_H__
++#define __KORBIT_SYS_UIO_H__
++#include <linux/uio.h>
++#endif
+diff -urN linux-2.4.1/net/korbit/include/sys/un.h linux-2.4.1-korbit/net/korbit/include/sys/un.h
+--- linux-2.4.1/net/korbit/include/sys/un.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/un.h Thu Feb 1 11:46:56 2001
+@@ -0,0 +1,5 @@
++#ifndef __KORBIT_SYS_UN_H__
++#define __KORBIT_SYS_UN_H__
++#include <linux/socket.h>
++#include <linux/un.h>
++#endif
+diff -urN linux-2.4.1/net/korbit/include/sys/wait.h linux-2.4.1-korbit/net/korbit/include/sys/wait.h
+--- linux-2.4.1/net/korbit/include/sys/wait.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/sys/wait.h Thu Feb 1 11:46:56 2001
+@@ -0,0 +1,3 @@
++#ifndef __KORBIT_SYS_WAIT_H__
++#define __KORBIT_SYS_WAIT_H__
++#endif
+diff -urN linux-2.4.1/net/korbit/include/syslog.h linux-2.4.1-korbit/net/korbit/include/syslog.h
+--- linux-2.4.1/net/korbit/include/syslog.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/syslog.h Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,7 @@
++#ifndef __KORBIT_SYSLOG_H__
++#define __KORBIT_SYSLOG_H__
++
++#define LOG_NOTICE 5 /* normal but significant condition */
++#define LOG_INFO 6 /* informational */
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/time.h linux-2.4.1-korbit/net/korbit/include/time.h
+--- linux-2.4.1/net/korbit/include/time.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/time.h Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,4 @@
++#ifndef __KORBIT_TIME_H__
++#define __KORBIT_TIME_H__
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/unistd.h linux-2.4.1-korbit/net/korbit/include/unistd.h
+--- linux-2.4.1/net/korbit/include/unistd.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/unistd.h Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,19 @@
++#ifndef __KORBIT_UNISTD_H__
++#define __KORBIT_UNISTD_H__
++
++#include <linux/types.h>
++#include <linux/utsname.h>
++#include <asm/string.h>
++#include <asm/semaphore.h>
++/* extern char *getcwd(char * buf, size_t size); */
++
++static inline int gethostname(char *name, size_t len) {
++ down_read(&uts_sem);
++ strncpy(name, system_utsname.nodename, len);
++ up_read(&uts_sem);
++printk("gethostname() = %s\n", name);
++ return 0;
++}
++
++
++#endif
+diff -urN linux-2.4.1/net/korbit/include/utime.h linux-2.4.1-korbit/net/korbit/include/utime.h
+--- linux-2.4.1/net/korbit/include/utime.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/include/utime.h Thu Feb 1 11:46:54 2001
+@@ -0,0 +1,4 @@
++#ifndef __KORBIT_UTIME_H__
++#define __KORBIT_UTIME_H__
++#include <linux/utime.h>
++#endif
+diff -urN linux-2.4.1/net/korbit/kglib/CVS/Entries linux-2.4.1-korbit/net/korbit/kglib/CVS/Entries
+--- linux-2.4.1/net/korbit/kglib/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/CVS/Entries Thu Feb 1 11:46:57 2001
+@@ -0,0 +1,15 @@
++/Makefile/1.4/Thu Feb 1 09:46:56 2001//
++/garray.c/1.3/Thu Feb 1 09:46:56 2001//
++/ghash.c/1.2/Thu Feb 1 09:46:56 2001//
++/glib.h/1.3/Thu Feb 1 09:46:56 2001//
++/glibconfig.h/1.2/Thu Feb 1 09:46:56 2001//
++/glist.c/1.1.1.1/Thu Feb 1 09:46:57 2001//
++/gmem.c/1.2/Thu Feb 1 09:46:57 2001//
++/gprimes.c/1.1.1.1/Thu Feb 1 09:46:57 2001//
++/gslist.c/1.1.1.1/Thu Feb 1 09:46:57 2001//
++/gstrfuncs.c/1.2/Thu Feb 1 09:46:57 2001//
++/gstring.c/1.1.1.1/Thu Feb 1 09:46:57 2001//
++/gtree.c/1.1.1.1/Thu Feb 1 09:46:57 2001//
++/gutils.c/1.2/Thu Feb 1 09:46:57 2001//
++/korbit_errno.c/1.1/Thu Feb 1 09:46:57 2001//
++D
+diff -urN linux-2.4.1/net/korbit/kglib/CVS/Repository linux-2.4.1-korbit/net/korbit/kglib/CVS/Repository
+--- linux-2.4.1/net/korbit/kglib/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/CVS/Repository Thu Feb 1 11:46:56 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/kglib
+diff -urN linux-2.4.1/net/korbit/kglib/CVS/Root linux-2.4.1-korbit/net/korbit/kglib/CVS/Root
+--- linux-2.4.1/net/korbit/kglib/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/CVS/Root Thu Feb 1 11:46:56 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/kglib/Makefile linux-2.4.1-korbit/net/korbit/kglib/Makefile
+--- linux-2.4.1/net/korbit/kglib/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/Makefile Thu Feb 1 11:46:56 2001
+@@ -0,0 +1,18 @@
++#
++# Makefile for KORBit/kglib
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := kglib.o
++
++#obj-m := $(O_TARGET)
++obj-y := garray.o glist.o gprimes.o gstrfuncs.o gtree.o \
++ ghash.o gmem.o gslist.o gstring.o gutils.o korbit_errno.o
++
++EXTRA_CFLAGS = -D__KORBIT__ -DHAVE_CONFIG_H -DHAVE_UNISTD_H -I. -I.. -I../include -nostdinc
++include $(TOPDIR)/Rules.make
++
+diff -urN linux-2.4.1/net/korbit/kglib/garray.c linux-2.4.1-korbit/net/korbit/kglib/garray.c
+--- linux-2.4.1/net/korbit/kglib/garray.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/garray.c Thu Feb 1 11:46:56 2001
+@@ -0,0 +1,431 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/*
++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS
++ * file for a list of people on the GLib Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GLib at ftp://ftp.gtk.org/pub/gtk/.
++ */
++
++#include <string.h>
++#include "glib.h"
++
++
++#define MIN_ARRAY_SIZE 16
++
++
++typedef struct _GRealArray GRealArray;
++
++struct _GRealArray
++{
++ guint8 *data;
++ guint len;
++ guint alloc;
++ guint elt_size;
++ guint zero_terminated : 1;
++ guint clear : 1;
++};
++
++
++static gint g_nearest_pow (gint num);
++static void g_array_maybe_expand (GRealArray *array,
++ gint len);
++
++static GMemChunk *array_mem_chunk = NULL;
++G_LOCK_DEFINE_STATIC (array_mem_chunk);
++
++GArray*
++g_array_new (gboolean zero_terminated,
++ gboolean clear,
++ guint elt_size)
++{
++ GRealArray *array;
++
++ G_LOCK (array_mem_chunk);
++ if (!array_mem_chunk)
++ array_mem_chunk = g_mem_chunk_new ("array mem chunk",
++ sizeof (GRealArray),
++ 1024, G_ALLOC_AND_FREE);
++
++ array = g_chunk_new (GRealArray, array_mem_chunk);
++ G_UNLOCK (array_mem_chunk);
++
++ array->data = NULL;
++ array->len = 0;
++ array->alloc = 0;
++ array->zero_terminated = (zero_terminated ? 1 : 0);
++ array->clear = (clear ? 1 : 0);
++ array->elt_size = elt_size;
++
++ return (GArray*) array;
++}
++
++void
++g_array_free (GArray *array,
++ gboolean free_segment)
++{
++ if (free_segment)
++ g_free (array->data);
++
++ G_LOCK (array_mem_chunk);
++ g_mem_chunk_free (array_mem_chunk, array);
++ G_UNLOCK (array_mem_chunk);
++}
++
++GArray*
++g_array_append_vals (GArray *farray,
++ gconstpointer data,
++ guint len)
++{
++ GRealArray *array = (GRealArray*) farray;
++
++ g_array_maybe_expand (array, len);
++
++ memcpy (array->data + array->elt_size * array->len, data, array->elt_size * len);
++
++ array->len += len;
++
++ return farray;
++}
++
++GArray*
++g_array_prepend_vals (GArray *farray,
++ gconstpointer data,
++ guint len)
++{
++ GRealArray *array = (GRealArray*) farray;
++
++ g_array_maybe_expand (array, len);
++
++ g_memmove (array->data + array->elt_size * len, array->data, array->elt_size * array->len);
++
++ memcpy (array->data, data, len * array->elt_size);
++
++ array->len += len;
++
++ return farray;
++}
++
++GArray*
++g_array_insert_vals (GArray *farray,
++ guint index,
++ gconstpointer data,
++ guint len)
++{
++ GRealArray *array = (GRealArray*) farray;
++
++ g_array_maybe_expand (array, len);
++
++ g_memmove (array->data + array->elt_size * (len + index),
++ array->data + array->elt_size * index,
++ array->elt_size * (array->len - index));
++
++ memcpy (array->data + array->elt_size * index, data, len * array->elt_size);
++
++ array->len += len;
++
++ return farray;
++}
++
++GArray*
++g_array_set_size (GArray *farray,
++ guint length)
++{
++ GRealArray *array = (GRealArray*) farray;
++
++ if (array->len < length)
++ g_array_maybe_expand (array, length - array->len);
++
++ array->len = length;
++
++ return farray;
++}
++
++GArray*
++g_array_remove_index (GArray* farray,
++ guint index)
++{
++ GRealArray* array = (GRealArray*) farray;
++
++ g_return_val_if_fail (array, NULL);
++
++ g_return_val_if_fail (index < array->len, NULL);
++
++ if (index != array->len - 1)
++ g_memmove (array->data + array->elt_size * index,
++ array->data + array->elt_size * (index + 1),
++ array->elt_size * (array->len - index - 1));
++
++ if (array->zero_terminated)
++ memset (array->data + array->elt_size * (array->len - 1), 0,
++ array->elt_size);
++
++ array->len -= 1;
++
++ return farray;
++}
++
++GArray*
++g_array_remove_index_fast (GArray* farray,
++ guint index)
++{
++ GRealArray* array = (GRealArray*) farray;
++
++ g_return_val_if_fail (array, NULL);
++
++ g_return_val_if_fail (index < array->len, NULL);
++
++ if (index != array->len - 1)
++ g_memmove (array->data + array->elt_size * index,
++ array->data + array->elt_size * (array->len - 1),
++ array->elt_size);
++
++ if (array->zero_terminated)
++ memset (array->data + array->elt_size * (array->len - 1), 0,
++ array->elt_size);
++
++ array->len -= 1;
++
++ return farray;
++}
++
++static gint
++g_nearest_pow (gint num)
++{
++ gint n = 1;
++
++ while (n < num)
++ n <<= 1;
++
++ return n;
++}
++
++static void
++g_array_maybe_expand (GRealArray *array,
++ gint len)
++{
++ guint want_alloc = (array->len + len + array->zero_terminated) * array->elt_size;
++
++ if (want_alloc > array->alloc)
++ {
++ guint old_alloc = array->alloc;
++
++ array->alloc = g_nearest_pow (want_alloc);
++ array->alloc = MAX (array->alloc, MIN_ARRAY_SIZE);
++
++ array->data = g_realloc (array->data, array->alloc);
++
++ if (array->clear || array->zero_terminated)
++ memset (array->data + old_alloc, 0, array->alloc - old_alloc);
++ }
++}
++
++/* Pointer Array
++ */
++
++typedef struct _GRealPtrArray GRealPtrArray;
++
++struct _GRealPtrArray
++{
++ gpointer *pdata;
++ guint len;
++ guint alloc;
++};
++
++static void g_ptr_array_maybe_expand (GRealPtrArray *array,
++ gint len);
++
++static GMemChunk *ptr_array_mem_chunk = NULL;
++G_LOCK_DEFINE_STATIC (ptr_array_mem_chunk);
++
++
++GPtrArray*
++g_ptr_array_new (void)
++{
++ GRealPtrArray *array;
++
++ G_LOCK (ptr_array_mem_chunk);
++ if (!ptr_array_mem_chunk)
++ ptr_array_mem_chunk = g_mem_chunk_new ("array mem chunk",
++ sizeof (GRealPtrArray),
++ 1024, G_ALLOC_AND_FREE);
++
++ array = g_chunk_new (GRealPtrArray, ptr_array_mem_chunk);
++ G_UNLOCK (ptr_array_mem_chunk);
++
++ array->pdata = NULL;
++ array->len = 0;
++ array->alloc = 0;
++
++ return (GPtrArray*) array;
++}
++
++void
++g_ptr_array_free (GPtrArray *array,
++ gboolean free_segment)
++{
++ g_return_if_fail (array);
++
++ if (free_segment)
++ g_free (array->pdata);
++
++ G_LOCK (ptr_array_mem_chunk);
++ g_mem_chunk_free (ptr_array_mem_chunk, array);
++ G_UNLOCK (ptr_array_mem_chunk);
++}
++
++static void
++g_ptr_array_maybe_expand (GRealPtrArray *array,
++ gint len)
++{
++ guint old_alloc;
++
++ if ((array->len + len) > array->alloc)
++ {
++ old_alloc = array->alloc;
++
++ array->alloc = g_nearest_pow (array->len + len);
++ array->alloc = MAX (array->alloc, MIN_ARRAY_SIZE);
++ if (array->pdata)
++ array->pdata = g_realloc (array->pdata, sizeof(gpointer) * array->alloc);
++ else
++ array->pdata = g_new0 (gpointer, array->alloc);
++
++ memset (array->pdata + old_alloc, 0,
++ sizeof (gpointer) * (array->alloc - old_alloc));
++ }
++}
++
++void
++g_ptr_array_set_size (GPtrArray *farray,
++ gint length)
++{
++ GRealPtrArray* array = (GRealPtrArray*) farray;
++
++ g_return_if_fail (array);
++
++ if (length > array->len)
++ g_ptr_array_maybe_expand (array, (length - array->len));
++
++ array->len = length;
++}
++
++gpointer
++g_ptr_array_remove_index (GPtrArray* farray,
++ guint index)
++{
++ GRealPtrArray* array = (GRealPtrArray*) farray;
++ gpointer result;
++
++ g_return_val_if_fail (array, NULL);
++
++ g_return_val_if_fail (index < array->len, NULL);
++
++ result = array->pdata[index];
++
++ if (index != array->len - 1)
++ g_memmove (array->pdata + index, array->pdata + index + 1,
++ sizeof (gpointer) * (array->len - index - 1));
++
++ array->pdata[array->len - 1] = NULL;
++
++ array->len -= 1;
++
++ return result;
++}
++
++gpointer
++g_ptr_array_remove_index_fast (GPtrArray* farray,
++ guint index)
++{
++ GRealPtrArray* array = (GRealPtrArray*) farray;
++ gpointer result;
++
++ g_return_val_if_fail (array, NULL);
++
++ g_return_val_if_fail (index < array->len, NULL);
++
++ result = array->pdata[index];
++
++ if (index != array->len - 1)
++ array->pdata[index] = array->pdata[array->len - 1];
++
++ array->pdata[array->len - 1] = NULL;
++
++ array->len -= 1;
++
++ return result;
++}
++
++gboolean
++g_ptr_array_remove (GPtrArray* farray,
++ gpointer data)
++{
++ GRealPtrArray* array = (GRealPtrArray*) farray;
++ int i;
++
++ g_return_val_if_fail (array, FALSE);
++
++ for (i = 0; i < array->len; i += 1)
++ {
++ if (array->pdata[i] == data)
++ {
++ g_ptr_array_remove_index (farray, i);
++ return TRUE;
++ }
++ }
++
++ return FALSE;
++}
++
++gboolean
++g_ptr_array_remove_fast (GPtrArray* farray,
++ gpointer data)
++{
++ GRealPtrArray* array = (GRealPtrArray*) farray;
++ int i;
++
++ g_return_val_if_fail (array, FALSE);
++
++ for (i = 0; i < array->len; i += 1)
++ {
++ if (array->pdata[i] == data)
++ {
++ g_ptr_array_remove_index_fast (farray, i);
++ return TRUE;
++ }
++ }
++
++ return FALSE;
++}
++
++void
++g_ptr_array_add (GPtrArray* farray,
++ gpointer data)
++{
++ GRealPtrArray* array = (GRealPtrArray*) farray;
++
++ g_return_if_fail (array);
++
++ g_ptr_array_maybe_expand (array, 1);
++
++ array->pdata[array->len++] = data;
++}
++
+diff -urN linux-2.4.1/net/korbit/kglib/ghash.c linux-2.4.1-korbit/net/korbit/kglib/ghash.c
+--- linux-2.4.1/net/korbit/kglib/ghash.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/ghash.c Thu Feb 1 11:46:56 2001
+@@ -0,0 +1,404 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/*
++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS
++ * file for a list of people on the GLib Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GLib at ftp://ftp.gtk.org/pub/gtk/.
++ */
++
++#include "glib.h"
++
++
++#define HASH_TABLE_MIN_SIZE 11
++#define HASH_TABLE_MAX_SIZE 13845163
++
++
++typedef struct _GHashNode GHashNode;
++
++struct _GHashNode
++{
++ gpointer key;
++ gpointer value;
++ GHashNode *next;
++};
++
++struct _GHashTable
++{
++ gint size;
++ gint nnodes;
++ guint frozen;
++ GHashNode **nodes;
++ GHashFunc hash_func;
++ GCompareFunc key_compare_func;
++};
++
++
++static void g_hash_table_resize (GHashTable *hash_table);
++static GHashNode** g_hash_table_lookup_node (GHashTable *hash_table,
++ gconstpointer key);
++static GHashNode* g_hash_node_new (gpointer key,
++ gpointer value);
++static void g_hash_node_destroy (GHashNode *hash_node);
++static void g_hash_nodes_destroy (GHashNode *hash_node);
++
++
++G_LOCK_DEFINE_STATIC (g_hash_global);
++
++static GMemChunk *node_mem_chunk = NULL;
++static GHashNode *node_free_list = NULL;
++
++
++GHashTable*
++g_hash_table_new (GHashFunc hash_func,
++ GCompareFunc key_compare_func)
++{
++ GHashTable *hash_table;
++ guint i;
++
++ hash_table = g_new (GHashTable, 1);
++ hash_table->size = HASH_TABLE_MIN_SIZE;
++ hash_table->nnodes = 0;
++ hash_table->frozen = FALSE;
++ hash_table->hash_func = hash_func ? hash_func : g_direct_hash;
++ hash_table->key_compare_func = key_compare_func;
++ hash_table->nodes = g_new (GHashNode*, hash_table->size);
++
++ for (i = 0; i < hash_table->size; i++)
++ hash_table->nodes[i] = NULL;
++
++ return hash_table;
++}
++
++void
++g_hash_table_destroy (GHashTable *hash_table)
++{
++ guint i;
++
++ g_return_if_fail (hash_table != NULL);
++
++ for (i = 0; i < hash_table->size; i++)
++ g_hash_nodes_destroy (hash_table->nodes[i]);
++
++ g_free (hash_table->nodes);
++ g_free (hash_table);
++}
++
++static inline GHashNode**
++g_hash_table_lookup_node (GHashTable *hash_table,
++ gconstpointer key)
++{
++ GHashNode **node;
++
++ node = &hash_table->nodes
++ [(* hash_table->hash_func) (key) % hash_table->size];
++
++ /* Hash table lookup needs to be fast.
++ * We therefore remove the extra conditional of testing
++ * whether to call the key_compare_func or not from
++ * the inner loop.
++ */
++ if (hash_table->key_compare_func)
++ while (*node && !(*hash_table->key_compare_func) ((*node)->key, key))
++ node = &(*node)->next;
++ else
++ while (*node && (*node)->key != key)
++ node = &(*node)->next;
++
++ return node;
++}
++
++gpointer
++g_hash_table_lookup (GHashTable *hash_table,
++ gconstpointer key)
++{
++ GHashNode *node;
++
++ g_return_val_if_fail (hash_table != NULL, NULL);
++
++ node = *g_hash_table_lookup_node (hash_table, key);
++
++ return node ? node->value : NULL;
++}
++
++void
++g_hash_table_insert (GHashTable *hash_table,
++ gpointer key,
++ gpointer value)
++{
++ GHashNode **node;
++
++ g_return_if_fail (hash_table != NULL);
++
++ node = g_hash_table_lookup_node (hash_table, key);
++
++ if (*node)
++ {
++ /* do not reset node->key in this place, keeping
++ * the old key might be intended.
++ * a g_hash_table_remove/g_hash_table_insert pair
++ * can be used otherwise.
++ *
++ * node->key = key; */
++ (*node)->value = value;
++ }
++ else
++ {
++ *node = g_hash_node_new (key, value);
++ hash_table->nnodes++;
++ if (!hash_table->frozen)
++ g_hash_table_resize (hash_table);
++ }
++}
++
++void
++g_hash_table_remove (GHashTable *hash_table,
++ gconstpointer key)
++{
++ GHashNode **node, *dest;
++
++ g_return_if_fail (hash_table != NULL);
++
++ node = g_hash_table_lookup_node (hash_table, key);
++
++ if (*node)
++ {
++ dest = *node;
++ (*node) = dest->next;
++ g_hash_node_destroy (dest);
++ hash_table->nnodes--;
++
++ if (!hash_table->frozen)
++ g_hash_table_resize (hash_table);
++ }
++}
++
++gboolean
++g_hash_table_lookup_extended (GHashTable *hash_table,
++ gconstpointer lookup_key,
++ gpointer *orig_key,
++ gpointer *value)
++{
++ GHashNode *node;
++
++ g_return_val_if_fail (hash_table != NULL, FALSE);
++
++ node = *g_hash_table_lookup_node (hash_table, lookup_key);
++
++ if (node)
++ {
++ if (orig_key)
++ *orig_key = node->key;
++ if (value)
++ *value = node->value;
++ return TRUE;
++ }
++ else
++ return FALSE;
++}
++
++void
++g_hash_table_freeze (GHashTable *hash_table)
++{
++ g_return_if_fail (hash_table != NULL);
++
++ hash_table->frozen++;
++}
++
++void
++g_hash_table_thaw (GHashTable *hash_table)
++{
++ g_return_if_fail (hash_table != NULL);
++
++ if (hash_table->frozen)
++ if (!(--hash_table->frozen))
++ g_hash_table_resize (hash_table);
++}
++
++guint
++g_hash_table_foreach_remove (GHashTable *hash_table,
++ GHRFunc func,
++ gpointer user_data)
++{
++ GHashNode *node, *prev;
++ guint i;
++ guint deleted = 0;
++
++ g_return_val_if_fail (hash_table != NULL, 0);
++ g_return_val_if_fail (func != NULL, 0);
++
++ for (i = 0; i < hash_table->size; i++)
++ {
++ restart:
++
++ prev = NULL;
++
++ for (node = hash_table->nodes[i]; node; prev = node, node = node->next)
++ {
++ if ((* func) (node->key, node->value, user_data))
++ {
++ deleted += 1;
++
++ hash_table->nnodes -= 1;
++
++ if (prev)
++ {
++ prev->next = node->next;
++ g_hash_node_destroy (node);
++ node = prev;
++ }
++ else
++ {
++ hash_table->nodes[i] = node->next;
++ g_hash_node_destroy (node);
++ goto restart;
++ }
++ }
++ }
++ }
++
++ if (!hash_table->frozen)
++ g_hash_table_resize (hash_table);
++
++ return deleted;
++}
++
++void
++g_hash_table_foreach (GHashTable *hash_table,
++ GHFunc func,
++ gpointer user_data)
++{
++ GHashNode *node;
++ gint i;
++
++ g_return_if_fail (hash_table != NULL);
++ g_return_if_fail (func != NULL);
++
++ for (i = 0; i < hash_table->size; i++)
++ for (node = hash_table->nodes[i]; node; node = node->next)
++ (* func) (node->key, node->value, user_data);
++}
++
++/* Returns the number of elements contained in the hash table. */
++guint
++g_hash_table_size (GHashTable *hash_table)
++{
++ g_return_val_if_fail (hash_table != NULL, 0);
++
++ return hash_table->nnodes;
++}
++
++static void
++g_hash_table_resize (GHashTable *hash_table)
++{
++ GHashNode **new_nodes;
++ GHashNode *node;
++ GHashNode *next;
++#ifdef __KORBIT__
++ guint nodes_per_list;
++#else
++ gfloat nodes_per_list;
++#endif
++ guint hash_val;
++ gint new_size;
++ gint i;
++
++ nodes_per_list = (hash_table->nnodes * 10) / hash_table->size;
++
++ if ((nodes_per_list > 3 || hash_table->size <= HASH_TABLE_MIN_SIZE) &&
++ (nodes_per_list < 30 || hash_table->size >= HASH_TABLE_MAX_SIZE))
++ return;
++
++ new_size = CLAMP(g_spaced_primes_closest (hash_table->nnodes),
++ HASH_TABLE_MIN_SIZE,
++ HASH_TABLE_MAX_SIZE);
++ new_nodes = g_new0 (GHashNode*, new_size);
++
++ for (i = 0; i < hash_table->size; i++)
++ for (node = hash_table->nodes[i]; node; node = next)
++ {
++ next = node->next;
++
++ hash_val = (* hash_table->hash_func) (node->key) % new_size;
++
++ node->next = new_nodes[hash_val];
++ new_nodes[hash_val] = node;
++ }
++
++ g_free (hash_table->nodes);
++ hash_table->nodes = new_nodes;
++ hash_table->size = new_size;
++}
++
++static GHashNode*
++g_hash_node_new (gpointer key,
++ gpointer value)
++{
++ GHashNode *hash_node;
++
++ G_LOCK (g_hash_global);
++ if (node_free_list)
++ {
++ hash_node = node_free_list;
++ node_free_list = node_free_list->next;
++ }
++ else
++ {
++ if (!node_mem_chunk)
++ node_mem_chunk = g_mem_chunk_new ("hash node mem chunk",
++ sizeof (GHashNode),
++ 1024, G_ALLOC_ONLY);
++
++ hash_node = g_chunk_new (GHashNode, node_mem_chunk);
++ }
++ G_UNLOCK (g_hash_global);
++
++ hash_node->key = key;
++ hash_node->value = value;
++ hash_node->next = NULL;
++
++ return hash_node;
++}
++
++static void
++g_hash_node_destroy (GHashNode *hash_node)
++{
++ G_LOCK (g_hash_global);
++ hash_node->next = node_free_list;
++ node_free_list = hash_node;
++ G_UNLOCK (g_hash_global);
++}
++
++static void
++g_hash_nodes_destroy (GHashNode *hash_node)
++{
++ if (hash_node)
++ {
++ GHashNode *node = hash_node;
++
++ while (node->next)
++ node = node->next;
++
++ G_LOCK (g_hash_global);
++ node->next = node_free_list;
++ node_free_list = hash_node;
++ G_UNLOCK (g_hash_global);
++ }
++}
+diff -urN linux-2.4.1/net/korbit/kglib/glib.h linux-2.4.1-korbit/net/korbit/kglib/glib.h
+--- linux-2.4.1/net/korbit/kglib/glib.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/glib.h Thu Feb 1 11:46:56 2001
+@@ -0,0 +1,1671 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#ifndef __G_LIB_H__
++#define __G_LIB_H__
++
++#ifdef __KORBIT__
++#define G_DISABLE_ASSERT 1
++#include <stdio.h>
++#endif
++
++#include "config.h"
++
++/* system specific config file glibconfig.h provides definitions for
++ * the extrema of many of the standard types. These are:
++ *
++ * G_MINSHORT, G_MAXSHORT
++ * G_MININT, G_MAXINT
++ * G_MINLONG, G_MAXLONG
++ * G_MINFLOAT, G_MAXFLOAT
++ * G_MINDOUBLE, G_MAXDOUBLE
++ *
++ * It also provides the following typedefs:
++ *
++ * gint8, guint8
++ * gint16, guint16
++ * gint32, guint32
++ * gint64, guint64
++ *
++ * It defines the G_BYTE_ORDER symbol to one of G_*_ENDIAN (see later in
++ * this file).
++ *
++ * And it provides a way to store and retrieve a `gint' in/from a `gpointer'.
++ * This is useful to pass an integer instead of a pointer to a callback.
++ *
++ * GINT_TO_POINTER(i), GUINT_TO_POINTER(i)
++ * GPOINTER_TO_INT(p), GPOINTER_TO_UINT(p)
++ *
++ * Finally, it provide the following wrappers to STDC functions:
++ *
++ * g_ATEXIT
++ * To register hooks which are executed on exit().
++ * Usually a wrapper for STDC atexit.
++ *
++ * void *g_memmove(void *dest, const void *src, guint count);
++ * A wrapper for STDC memmove, or an implementation, if memmove doesn't
++ * exist. The prototype looks like the above, give or take a const,
++ * or size_t.
++ */
++#include <glibconfig.h>
++
++/* include varargs functions for assertment macros
++ */
++#include <stdarg.h>
++
++#define G_DIR_SEPARATOR '/'
++#define G_DIR_SEPARATOR_S "/"
++#define G_SEARCHPATH_SEPARATOR ':'
++#define G_SEARCHPATH_SEPARATOR_S ":"
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++
++/* Provide definitions for some commonly used macros.
++ * Some of them are only provided if they haven't already
++ * been defined. It is assumed that if they are already
++ * defined then the current definition is correct.
++ */
++#ifndef NULL
++#define NULL ((void*) 0)
++#endif
++
++#ifndef FALSE
++#define FALSE (0)
++#endif
++
++#ifndef TRUE
++#define TRUE (!FALSE)
++#endif
++
++#undef MAX
++#define MAX(a, b) (((a) > (b)) ? (a) : (b))
++
++#undef MIN
++#define MIN(a, b) (((a) < (b)) ? (a) : (b))
++
++#undef ABS
++#define ABS(a) (((a) < 0) ? -(a) : (a))
++
++#undef CLAMP
++#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
++
++
++/* Define G_VA_COPY() to do the right thing for copying va_list variables.
++ * glibconfig.h may have already defined G_VA_COPY as va_copy or __va_copy.
++ */
++#if !defined (G_VA_COPY)
++# if defined (__GNUC__) && defined (__PPC__) && (defined (_CALL_SYSV) || defined (_WIN32))
++# define G_VA_COPY(ap1, ap2) (*(ap1) = *(ap2))
++# elif defined (G_VA_COPY_AS_ARRAY)
++# define G_VA_COPY(ap1, ap2) g_memmove ((ap1), (ap2), sizeof (va_list))
++# else /* va_list is a pointer */
++# define G_VA_COPY(ap1, ap2) ((ap1) = (ap2))
++# endif /* va_list is a pointer */
++#endif /* !G_VA_COPY */
++
++
++/* Provide convenience macros for handling structure
++ * fields through their offsets.
++ */
++#define G_STRUCT_OFFSET(struct_type, member) \
++ ((gulong) ((gchar*) &((struct_type*) 0)->member))
++#define G_STRUCT_MEMBER_P(struct_p, struct_offset) \
++ ((gpointer) ((gchar*) (struct_p) + (gulong) (struct_offset)))
++#define G_STRUCT_MEMBER(member_type, struct_p, struct_offset) \
++ (*(member_type*) G_STRUCT_MEMBER_P ((struct_p), (struct_offset)))
++
++
++/* inlining hassle. for compilers that don't allow the `inline' keyword,
++ * mostly because of strict ANSI C compliance or dumbness, we try to fall
++ * back to either `__inline__' or `__inline'.
++ * we define G_CAN_INLINE, if the compiler seems to be actually
++ * *capable* to do function inlining, in which case inline function bodys
++ * do make sense. we also define G_INLINE_FUNC to properly export the
++ * function prototypes if no inlining can be performed.
++ * we special case most of the stuff, so inline functions can have a normal
++ * implementation by defining G_INLINE_FUNC to extern and G_CAN_INLINE to 1.
++ */
++#ifndef G_INLINE_FUNC
++# define G_CAN_INLINE 1
++#endif
++#ifdef G_HAVE_INLINE
++# if defined (__GNUC__) && defined (__STRICT_ANSI__)
++# undef inline
++# define inline __inline__
++# endif
++#else /* !G_HAVE_INLINE */
++# undef inline
++# if defined (G_HAVE___INLINE__)
++# define inline __inline__
++# else /* !inline && !__inline__ */
++# if defined (G_HAVE___INLINE)
++# define inline __inline
++# else /* !inline && !__inline__ && !__inline */
++# define inline /* don't inline, then */
++# ifndef G_INLINE_FUNC
++# undef G_CAN_INLINE
++# endif
++# endif
++# endif
++#endif
++#ifndef G_INLINE_FUNC
++# ifdef __GNUC__
++# ifdef __OPTIMIZE__
++# define G_INLINE_FUNC extern inline
++# else
++# undef G_CAN_INLINE
++# define G_INLINE_FUNC extern
++# endif
++# else /* !__GNUC__ */
++# ifdef G_CAN_INLINE
++# define G_INLINE_FUNC static inline
++# else
++# define G_INLINE_FUNC extern
++# endif
++# endif /* !__GNUC__ */
++#endif /* !G_INLINE_FUNC */
++
++
++/* Provide simple macro statement wrappers (adapted from Perl):
++ * G_STMT_START { statements; } G_STMT_END;
++ * can be used as a single statement, as in
++ * if (x) G_STMT_START { ... } G_STMT_END; else ...
++ *
++ * For gcc we will wrap the statements within `({' and `})' braces.
++ * For SunOS they will be wrapped within `if (1)' and `else (void) 0',
++ * and otherwise within `do' and `while (0)'.
++ */
++#if !(defined (G_STMT_START) && defined (G_STMT_END))
++# if defined (__GNUC__) && !defined (__STRICT_ANSI__) && !defined (__cplusplus)
++# define G_STMT_START (void)(
++# define G_STMT_END )
++# else
++# if (defined (sun) || defined (__sun__))
++# define G_STMT_START if (1)
++# define G_STMT_END else (void)0
++# else
++# define G_STMT_START do
++# define G_STMT_END while (0)
++# endif
++# endif
++#endif
++
++
++/* Provide macros to feature the GCC function attribute.
++ */
++#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
++#define G_GNUC_PRINTF( format_idx, arg_idx ) \
++ __attribute__((format (printf, format_idx, arg_idx)))
++#define G_GNUC_SCANF( format_idx, arg_idx ) \
++ __attribute__((format (scanf, format_idx, arg_idx)))
++#define G_GNUC_FORMAT( arg_idx ) \
++ __attribute__((format_arg (arg_idx)))
++#define G_GNUC_NORETURN \
++ __attribute__((noreturn))
++#define G_GNUC_CONST \
++ __attribute__((const))
++#define G_GNUC_UNUSED \
++ __attribute__((unused))
++#else /* !__GNUC__ */
++#define G_GNUC_PRINTF( format_idx, arg_idx )
++#define G_GNUC_SCANF( format_idx, arg_idx )
++#define G_GNUC_FORMAT( arg_idx )
++#define G_GNUC_NORETURN
++#define G_GNUC_CONST
++#define G_GNUC_UNUSED
++#endif /* !__GNUC__ */
++
++
++/* Wrap the gcc __PRETTY_FUNCTION__ and __FUNCTION__ variables with
++ * macros, so we can refer to them as strings unconditionally.
++ */
++#ifdef __GNUC__
++#define G_GNUC_FUNCTION __FUNCTION__
++#define G_GNUC_PRETTY_FUNCTION __PRETTY_FUNCTION__
++#else /* !__GNUC__ */
++#define G_GNUC_FUNCTION ""
++#define G_GNUC_PRETTY_FUNCTION ""
++#endif /* !__GNUC__ */
++
++/* we try to provide a usefull equivalent for ATEXIT if it is
++ * not defined, but use is actually abandoned. people should
++ * use g_atexit() instead.
++ */
++#ifndef ATEXIT
++# define ATEXIT(proc) g_ATEXIT(proc)
++#else
++# define G_NATIVE_ATEXIT
++#endif /* ATEXIT */
++
++/* Hacker macro to place breakpoints for elected machines.
++ * Actual use is strongly deprecated of course ;)
++ */
++#if defined (__i386__) && defined (__GNUC__) && __GNUC__ >= 2
++#define G_BREAKPOINT() G_STMT_START{ __asm__ __volatile__ ("int $03"); }G_STMT_END
++#elif defined (__alpha__) && defined (__GNUC__) && __GNUC__ >= 2
++#define G_BREAKPOINT() G_STMT_START{ __asm__ __volatile__ ("bpt"); }G_STMT_END
++#else /* !__i386__ && !__alpha__ */
++#define G_BREAKPOINT()
++#endif /* __i386__ */
++
++
++/* Provide macros for easily allocating memory. The macros
++ * will cast the allocated memory to the specified type
++ * in order to avoid compiler warnings. (Makes the code neater).
++ */
++
++#ifdef __DMALLOC_H__
++# define g_new(type, count) (ALLOC (type, count))
++# define g_new0(type, count) (CALLOC (type, count))
++# define g_renew(type, mem, count) (REALLOC (mem, type, count))
++#else /* __DMALLOC_H__ */
++# define g_new(type, count) \
++ ((type *) g_malloc ((unsigned) sizeof (type) * (count)))
++# define g_new0(type, count) \
++ ((type *) g_malloc0 ((unsigned) sizeof (type) * (count)))
++# define g_renew(type, mem, count) \
++ ((type *) g_realloc (mem, (unsigned) sizeof (type) * (count)))
++#endif /* __DMALLOC_H__ */
++
++#define g_mem_chunk_create(type, pre_alloc, alloc_type) ( \
++ g_mem_chunk_new (#type " mem chunks (" #pre_alloc ")", \
++ sizeof (type), \
++ sizeof (type) * (pre_alloc), \
++ (alloc_type)) \
++)
++#define g_chunk_new(type, chunk) ( \
++ (type *) g_mem_chunk_alloc (chunk) \
++)
++#define g_chunk_new0(type, chunk) ( \
++ (type *) g_mem_chunk_alloc0 (chunk) \
++)
++#define g_chunk_free(mem, mem_chunk) G_STMT_START { \
++ g_mem_chunk_free ((mem_chunk), (mem)); \
++} G_STMT_END
++
++
++#define g_string(x) #x
++
++
++/* Provide macros for error handling. The "assert" macros will
++ * exit on failure. The "return" macros will exit the current
++ * function. Two different definitions are given for the macros
++ * if G_DISABLE_ASSERT is not defined, in order to support gcc's
++ * __PRETTY_FUNCTION__ capability.
++ */
++
++#ifdef G_DISABLE_ASSERT
++
++#define g_assert(expr)
++#define g_assert_not_reached()
++
++#else /* !G_DISABLE_ASSERT */
++
++#ifdef __GNUC__
++
++#define g_assert(expr) G_STMT_START{ \
++ if (!(expr)) \
++ g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_ERROR, \
++ "file %s: line %d (%s): assertion failed: (%s)", \
++ __FILE__, \
++ __LINE__, \
++ __PRETTY_FUNCTION__, \
++ #expr); }G_STMT_END
++
++#define g_assert_not_reached() G_STMT_START{ \
++ g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_ERROR, \
++ "file %s: line %d (%s): should not be reached", \
++ __FILE__, \
++ __LINE__, \
++ __PRETTY_FUNCTION__); }G_STMT_END
++
++#else /* !__GNUC__ */
++
++#define g_assert(expr) G_STMT_START{ \
++ if (!(expr)) \
++ g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_ERROR, \
++ "file %s: line %d: assertion failed: (%s)", \
++ __FILE__, \
++ __LINE__, \
++ #expr); }G_STMT_END
++
++#define g_assert_not_reached() G_STMT_START{ \
++ g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_ERROR, \
++ "file %s: line %d: should not be reached", \
++ __FILE__, \
++ __LINE__); }G_STMT_END
++
++#endif /* __GNUC__ */
++
++#endif /* !G_DISABLE_ASSERT */
++
++
++#ifdef __KORBIT__
++
++#define g_return_if_fail(expr) G_STMT_START{ \
++ if (!(expr)) \
++ { \
++ return; \
++ }; }G_STMT_END
++
++#define g_return_val_if_fail(expr,val) G_STMT_START{ \
++ if (!(expr)) \
++ { \
++ return val; \
++ }; }G_STMT_END
++
++#else /* !__KORBIT__ */
++
++#ifdef G_DISABLE_CHECKS
++
++#define g_return_if_fail(expr)
++#define g_return_val_if_fail(expr,val)
++
++#else /* !G_DISABLE_CHECKS */
++
++#ifdef __GNUC__
++
++#define g_return_if_fail(expr) G_STMT_START{ \
++ if (!(expr)) \
++ { \
++ g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_CRITICAL, \
++ "file %s: line %d (%s): assertion `%s' failed.", \
++ __FILE__, \
++ __LINE__, \
++ __PRETTY_FUNCTION__, \
++ #expr); \
++ return; \
++ }; }G_STMT_END
++
++#define g_return_val_if_fail(expr,val) G_STMT_START{ \
++ if (!(expr)) \
++ { \
++ g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_CRITICAL, \
++ "file %s: line %d (%s): assertion `%s' failed.", \
++ __FILE__, \
++ __LINE__, \
++ __PRETTY_FUNCTION__, \
++ #expr); \
++ return val; \
++ }; }G_STMT_END
++
++#else /* !__GNUC__ */
++
++#define g_return_if_fail(expr) G_STMT_START{ \
++ if (!(expr)) \
++ { \
++ g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_CRITICAL, \
++ "file %s: line %d: assertion `%s' failed.", \
++ __FILE__, \
++ __LINE__, \
++ #expr); \
++ return; \
++ }; }G_STMT_END
++
++#define g_return_val_if_fail(expr, val) G_STMT_START{ \
++ if (!(expr)) \
++ { \
++ g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_CRITICAL, \
++ "file %s: line %d: assertion `%s' failed.", \
++ __FILE__, \
++ __LINE__, \
++ #expr); \
++ return val; \
++ }; }G_STMT_END
++
++#endif /* !__GNUC__ */
++
++#endif /* !G_DISABLE_CHECKS */
++
++#endif /* !__KORBIT__ */
++
++
++/* Provide type definitions for commonly used types.
++ * These are useful because a "gint8" can be adjusted
++ * to be 1 byte (8 bits) on all platforms. Similarly and
++ * more importantly, "gint32" can be adjusted to be
++ * 4 bytes (32 bits) on all platforms.
++ */
++
++typedef char gchar;
++typedef short gshort;
++typedef long glong;
++typedef int gint;
++typedef gint gboolean;
++
++typedef unsigned char guchar;
++typedef unsigned short gushort;
++typedef unsigned long gulong;
++typedef unsigned int guint;
++
++typedef float gfloat;
++typedef double gdouble;
++
++/* HAVE_LONG_DOUBLE doesn't work correctly on all platforms.
++ * Since gldouble isn't used anywhere, just disable it for now */
++
++#if 0
++#ifdef HAVE_LONG_DOUBLE
++typedef long double gldouble;
++#else /* HAVE_LONG_DOUBLE */
++typedef double gldouble;
++#endif /* HAVE_LONG_DOUBLE */
++#endif /* 0 */
++
++typedef void* gpointer;
++typedef const void *gconstpointer;
++
++
++typedef gint32 gssize;
++typedef guint32 gsize;
++typedef guint32 GQuark;
++typedef gint32 GTime;
++
++
++/* Portable endian checks and conversions
++ *
++ * glibconfig.h defines G_BYTE_ORDER which expands to one of
++ * the below macros.
++ */
++#define G_LITTLE_ENDIAN 1234
++#define G_BIG_ENDIAN 4321
++#define G_PDP_ENDIAN 3412 /* unused, need specific PDP check */
++
++
++/* Basic bit swapping functions
++ */
++#define GUINT16_SWAP_LE_BE_CONSTANT(val) ((guint16) ( \
++ (((guint16) (val) & (guint16) 0x00ffU) << 8) | \
++ (((guint16) (val) & (guint16) 0xff00U) >> 8)))
++#define GUINT32_SWAP_LE_BE_CONSTANT(val) ((guint32) ( \
++ (((guint32) (val) & (guint32) 0x000000ffU) << 24) | \
++ (((guint32) (val) & (guint32) 0x0000ff00U) << 8) | \
++ (((guint32) (val) & (guint32) 0x00ff0000U) >> 8) | \
++ (((guint32) (val) & (guint32) 0xff000000U) >> 24)))
++
++/* Intel specific stuff for speed
++ */
++#if defined (__i386__) && defined (__GNUC__) && __GNUC__ >= 2
++# define GUINT16_SWAP_LE_BE_X86(val) \
++ (__extension__ \
++ ({ register guint16 __v; \
++ if (__builtin_constant_p (val)) \
++ __v = GUINT16_SWAP_LE_BE_CONSTANT (val); \
++ else \
++ __asm__ __const__ ("rorw $8, %w0" \
++ : "=r" (__v) \
++ : "0" ((guint16) (val))); \
++ __v; }))
++# define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_X86 (val))
++# if !defined(__i486__) && !defined(__i586__) \
++ && !defined(__pentium__) && !defined(__i686__) && !defined(__pentiumpro__)
++# define GUINT32_SWAP_LE_BE_X86(val) \
++ (__extension__ \
++ ({ register guint32 __v; \
++ if (__builtin_constant_p (val)) \
++ __v = GUINT32_SWAP_LE_BE_CONSTANT (val); \
++ else \
++ __asm__ __const__ ("rorw $8, %w0\n\t" \
++ "rorl $16, %0\n\t" \
++ "rorw $8, %w0" \
++ : "=r" (__v) \
++ : "0" ((guint32) (val))); \
++ __v; }))
++# else /* 486 and higher has bswap */
++# define GUINT32_SWAP_LE_BE_X86(val) \
++ (__extension__ \
++ ({ register guint32 __v; \
++ if (__builtin_constant_p (val)) \
++ __v = GUINT32_SWAP_LE_BE_CONSTANT (val); \
++ else \
++ __asm__ __const__ ("bswap %0" \
++ : "=r" (__v) \
++ : "0" ((guint32) (val))); \
++ __v; }))
++# endif /* processor specific 32-bit stuff */
++# define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_X86 (val))
++#else /* !__i386__ */
++# define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_CONSTANT (val))
++# define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_CONSTANT (val))
++#endif /* __i386__ */
++
++#ifdef G_HAVE_GINT64
++# define GUINT64_SWAP_LE_BE_CONSTANT(val) ((guint64) ( \
++ (((guint64) (val) & \
++ (guint64) G_GINT64_CONSTANT(0x00000000000000ffU)) << 56) | \
++ (((guint64) (val) & \
++ (guint64) G_GINT64_CONSTANT(0x000000000000ff00U)) << 40) | \
++ (((guint64) (val) & \
++ (guint64) G_GINT64_CONSTANT(0x0000000000ff0000U)) << 24) | \
++ (((guint64) (val) & \
++ (guint64) G_GINT64_CONSTANT(0x00000000ff000000U)) << 8) | \
++ (((guint64) (val) & \
++ (guint64) G_GINT64_CONSTANT(0x000000ff00000000U)) >> 8) | \
++ (((guint64) (val) & \
++ (guint64) G_GINT64_CONSTANT(0x0000ff0000000000U)) >> 24) | \
++ (((guint64) (val) & \
++ (guint64) G_GINT64_CONSTANT(0x00ff000000000000U)) >> 40) | \
++ (((guint64) (val) & \
++ (guint64) G_GINT64_CONSTANT(0xff00000000000000U)) >> 56)))
++# if defined (__i386__) && defined (__GNUC__) && __GNUC__ >= 2
++# define GUINT64_SWAP_LE_BE_X86(val) \
++ (__extension__ \
++ ({ union { guint64 __ll; \
++ guint32 __l[2]; } __r; \
++ if (__builtin_constant_p (val)) \
++ __r.__ll = GUINT64_SWAP_LE_BE_CONSTANT (val); \
++ else \
++ { \
++ union { guint64 __ll; \
++ guint32 __l[2]; } __w; \
++ __w.__ll = ((guint64) val); \
++ __r.__l[0] = GUINT32_SWAP_LE_BE (__w.__l[1]); \
++ __r.__l[1] = GUINT32_SWAP_LE_BE (__w.__l[0]); \
++ } \
++ __r.__ll; }))
++# define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_X86 (val))
++# else /* !__i386__ */
++# define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_CONSTANT(val))
++# endif
++#endif
++
++#define GUINT16_SWAP_LE_PDP(val) ((guint16) (val))
++#define GUINT16_SWAP_BE_PDP(val) (GUINT16_SWAP_LE_BE (val))
++#define GUINT32_SWAP_LE_PDP(val) ((guint32) ( \
++ (((guint32) (val) & (guint32) 0x0000ffffU) << 16) | \
++ (((guint32) (val) & (guint32) 0xffff0000U) >> 16)))
++#define GUINT32_SWAP_BE_PDP(val) ((guint32) ( \
++ (((guint32) (val) & (guint32) 0x00ff00ffU) << 8) | \
++ (((guint32) (val) & (guint32) 0xff00ff00U) >> 8)))
++
++/* The G*_TO_?E() macros are defined in glibconfig.h.
++ * The transformation is symmetric, so the FROM just maps to the TO.
++ */
++#define GINT16_FROM_LE(val) (GINT16_TO_LE (val))
++#define GUINT16_FROM_LE(val) (GUINT16_TO_LE (val))
++#define GINT16_FROM_BE(val) (GINT16_TO_BE (val))
++#define GUINT16_FROM_BE(val) (GUINT16_TO_BE (val))
++#define GINT32_FROM_LE(val) (GINT32_TO_LE (val))
++#define GUINT32_FROM_LE(val) (GUINT32_TO_LE (val))
++#define GINT32_FROM_BE(val) (GINT32_TO_BE (val))
++#define GUINT32_FROM_BE(val) (GUINT32_TO_BE (val))
++
++#ifdef G_HAVE_GINT64
++#define GINT64_FROM_LE(val) (GINT64_TO_LE (val))
++#define GUINT64_FROM_LE(val) (GUINT64_TO_LE (val))
++#define GINT64_FROM_BE(val) (GINT64_TO_BE (val))
++#define GUINT64_FROM_BE(val) (GUINT64_TO_BE (val))
++#endif
++
++#define GLONG_FROM_LE(val) (GLONG_TO_LE (val))
++#define GULONG_FROM_LE(val) (GULONG_TO_LE (val))
++#define GLONG_FROM_BE(val) (GLONG_TO_BE (val))
++#define GULONG_FROM_BE(val) (GULONG_TO_BE (val))
++
++#define GINT_FROM_LE(val) (GINT_TO_LE (val))
++#define GUINT_FROM_LE(val) (GUINT_TO_LE (val))
++#define GINT_FROM_BE(val) (GINT_TO_BE (val))
++#define GUINT_FROM_BE(val) (GUINT_TO_BE (val))
++
++
++/* Portable versions of host-network order stuff
++ */
++#define g_ntohl(val) (GUINT32_FROM_BE (val))
++#define g_ntohs(val) (GUINT16_FROM_BE (val))
++#define g_htonl(val) (GUINT32_TO_BE (val))
++#define g_htons(val) (GUINT16_TO_BE (val))
++
++
++/* Glib version.
++ * we prefix variable declarations so they can
++ * properly get exported in windows dlls.
++ */
++#define GUTILS_C_VAR extern
++
++
++GUTILS_C_VAR const guint glib_major_version;
++GUTILS_C_VAR const guint glib_minor_version;
++GUTILS_C_VAR const guint glib_micro_version;
++GUTILS_C_VAR const guint glib_interface_age;
++GUTILS_C_VAR const guint glib_binary_age;
++
++#define GLIB_CHECK_VERSION(major,minor,micro) \
++ (GLIB_MAJOR_VERSION > (major) || \
++ (GLIB_MAJOR_VERSION == (major) && GLIB_MINOR_VERSION > (minor)) || \
++ (GLIB_MAJOR_VERSION == (major) && GLIB_MINOR_VERSION == (minor) && \
++ GLIB_MICRO_VERSION >= (micro)))
++
++/* Forward declarations of glib types.
++ */
++typedef struct _GAllocator GAllocator;
++typedef struct _GArray GArray;
++typedef struct _GByteArray GByteArray;
++typedef struct _GDebugKey GDebugKey;
++typedef struct _GHashTable GHashTable;
++typedef struct _GList GList;
++typedef struct _GMemChunk GMemChunk;
++typedef struct _GNode GNode;
++typedef struct _GPtrArray GPtrArray;
++typedef struct _GSList GSList;
++typedef struct _GString GString;
++typedef struct _GStringChunk GStringChunk;
++typedef struct _GTree GTree;
++typedef struct _GTuples GTuples;
++
++/* Tree traverse flags */
++typedef enum
++{
++ G_TRAVERSE_LEAFS = 1 << 0,
++ G_TRAVERSE_NON_LEAFS = 1 << 1,
++ G_TRAVERSE_ALL = G_TRAVERSE_LEAFS | G_TRAVERSE_NON_LEAFS,
++ G_TRAVERSE_MASK = 0x03
++} GTraverseFlags;
++
++/* Tree traverse orders */
++typedef enum
++{
++ G_IN_ORDER,
++ G_PRE_ORDER,
++ G_POST_ORDER,
++ G_LEVEL_ORDER
++} GTraverseType;
++
++/* Log level shift offset for user defined
++ * log levels (0-7 are used by GLib).
++ */
++#define G_LOG_LEVEL_USER_SHIFT (8)
++
++/* Glib log levels and flags.
++ */
++typedef enum
++{
++ /* log flags */
++ G_LOG_FLAG_RECURSION = 1 << 0,
++ G_LOG_FLAG_FATAL = 1 << 1,
++
++ /* GLib log levels */
++ G_LOG_LEVEL_ERROR = 1 << 2, /* always fatal */
++ G_LOG_LEVEL_CRITICAL = 1 << 3,
++ G_LOG_LEVEL_WARNING = 1 << 4,
++ G_LOG_LEVEL_MESSAGE = 1 << 5,
++ G_LOG_LEVEL_INFO = 1 << 6,
++ G_LOG_LEVEL_DEBUG = 1 << 7,
++
++ G_LOG_LEVEL_MASK = ~(G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL)
++} GLogLevelFlags;
++
++/* GLib log levels that are considered fatal by default */
++#define G_LOG_FATAL_MASK (G_LOG_FLAG_RECURSION | G_LOG_LEVEL_ERROR)
++
++
++typedef gint (*GCompareFunc) (gconstpointer a,
++ gconstpointer b);
++typedef gchar* (*GCompletionFunc) (gpointer);
++typedef void (*GDestroyNotify) (gpointer data);
++typedef void (*GDataForeachFunc) (GQuark key_id,
++ gpointer data,
++ gpointer user_data);
++typedef void (*GFunc) (gpointer data,
++ gpointer user_data);
++typedef guint (*GHashFunc) (gconstpointer key);
++typedef void (*GFreeFunc) (gpointer data);
++typedef void (*GHFunc) (gpointer key,
++ gpointer value,
++ gpointer user_data);
++typedef gboolean (*GHRFunc) (gpointer key,
++ gpointer value,
++ gpointer user_data);
++typedef void (*GLogFunc) (const gchar *log_domain,
++ GLogLevelFlags log_level,
++ const gchar *message,
++ gpointer user_data);
++typedef gboolean (*GNodeTraverseFunc) (GNode *node,
++ gpointer data);
++typedef void (*GNodeForeachFunc) (GNode *node,
++ gpointer data);
++typedef gint (*GSearchFunc) (gpointer key,
++ gpointer data);
++typedef gint (*GTraverseFunc) (gpointer key,
++ gpointer value,
++ gpointer data);
++typedef void (*GVoidFunc) (void);
++
++
++struct _GList
++{
++ gpointer data;
++ GList *next;
++ GList *prev;
++};
++
++struct _GSList
++{
++ gpointer data;
++ GSList *next;
++};
++
++struct _GString
++{
++ gchar *str;
++ gint len;
++};
++
++struct _GArray
++{
++ gchar *data;
++ guint len;
++};
++
++struct _GByteArray
++{
++ guint8 *data;
++ guint len;
++};
++
++struct _GPtrArray
++{
++ gpointer *pdata;
++ guint len;
++};
++
++struct _GTuples
++{
++ guint len;
++};
++
++struct _GDebugKey
++{
++ gchar *key;
++ guint value;
++};
++
++
++/* Doubly linked lists
++ */
++void g_list_push_allocator (GAllocator *allocator);
++void g_list_pop_allocator (void);
++GList* g_list_alloc (void);
++void g_list_free (GList *list);
++void g_list_free_1 (GList *list);
++GList* g_list_append (GList *list,
++ gpointer data);
++GList* g_list_prepend (GList *list,
++ gpointer data);
++GList* g_list_insert (GList *list,
++ gpointer data,
++ gint position);
++GList* g_list_insert_sorted (GList *list,
++ gpointer data,
++ GCompareFunc func);
++GList* g_list_concat (GList *list1,
++ GList *list2);
++GList* g_list_remove (GList *list,
++ gpointer data);
++GList* g_list_remove_link (GList *list,
++ GList *llink);
++GList* g_list_reverse (GList *list);
++GList* g_list_copy (GList *list);
++GList* g_list_nth (GList *list,
++ guint n);
++GList* g_list_find (GList *list,
++ gpointer data);
++GList* g_list_find_custom (GList *list,
++ gpointer data,
++ GCompareFunc func);
++gint g_list_position (GList *list,
++ GList *llink);
++gint g_list_index (GList *list,
++ gpointer data);
++GList* g_list_last (GList *list);
++GList* g_list_first (GList *list);
++guint g_list_length (GList *list);
++void g_list_foreach (GList *list,
++ GFunc func,
++ gpointer user_data);
++GList* g_list_sort (GList *list,
++ GCompareFunc compare_func);
++gpointer g_list_nth_data (GList *list,
++ guint n);
++#define g_list_previous(list) ((list) ? (((GList *)(list))->prev) : NULL)
++#define g_list_next(list) ((list) ? (((GList *)(list))->next) : NULL)
++
++
++/* Singly linked lists
++ */
++void g_slist_push_allocator (GAllocator *allocator);
++void g_slist_pop_allocator (void);
++GSList* g_slist_alloc (void);
++void g_slist_free (GSList *list);
++void g_slist_free_1 (GSList *list);
++GSList* g_slist_append (GSList *list,
++ gpointer data);
++GSList* g_slist_prepend (GSList *list,
++ gpointer data);
++GSList* g_slist_insert (GSList *list,
++ gpointer data,
++ gint position);
++GSList* g_slist_insert_sorted (GSList *list,
++ gpointer data,
++ GCompareFunc func);
++GSList* g_slist_concat (GSList *list1,
++ GSList *list2);
++GSList* g_slist_remove (GSList *list,
++ gpointer data);
++GSList* g_slist_remove_link (GSList *list,
++ GSList *llink);
++GSList* g_slist_reverse (GSList *list);
++GSList* g_slist_copy (GSList *list);
++GSList* g_slist_nth (GSList *list,
++ guint n);
++GSList* g_slist_find (GSList *list,
++ gpointer data);
++GSList* g_slist_find_custom (GSList *list,
++ gpointer data,
++ GCompareFunc func);
++gint g_slist_position (GSList *list,
++ GSList *llink);
++gint g_slist_index (GSList *list,
++ gpointer data);
++GSList* g_slist_last (GSList *list);
++guint g_slist_length (GSList *list);
++void g_slist_foreach (GSList *list,
++ GFunc func,
++ gpointer user_data);
++GSList* g_slist_sort (GSList *list,
++ GCompareFunc compare_func);
++gpointer g_slist_nth_data (GSList *list,
++ guint n);
++#define g_slist_next(slist) ((slist) ? (((GSList *)(slist))->next) : NULL)
++
++
++/* Hash tables
++ */
++GHashTable* g_hash_table_new (GHashFunc hash_func,
++ GCompareFunc key_compare_func);
++void g_hash_table_destroy (GHashTable *hash_table);
++void g_hash_table_insert (GHashTable *hash_table,
++ gpointer key,
++ gpointer value);
++void g_hash_table_remove (GHashTable *hash_table,
++ gconstpointer key);
++gpointer g_hash_table_lookup (GHashTable *hash_table,
++ gconstpointer key);
++gboolean g_hash_table_lookup_extended(GHashTable *hash_table,
++ gconstpointer lookup_key,
++ gpointer *orig_key,
++ gpointer *value);
++void g_hash_table_freeze (GHashTable *hash_table);
++void g_hash_table_thaw (GHashTable *hash_table);
++void g_hash_table_foreach (GHashTable *hash_table,
++ GHFunc func,
++ gpointer user_data);
++guint g_hash_table_foreach_remove (GHashTable *hash_table,
++ GHRFunc func,
++ gpointer user_data);
++guint g_hash_table_size (GHashTable *hash_table);
++
++
++
++
++/* Balanced binary trees
++ */
++GTree* g_tree_new (GCompareFunc key_compare_func);
++void g_tree_destroy (GTree *tree);
++void g_tree_insert (GTree *tree,
++ gpointer key,
++ gpointer value);
++void g_tree_remove (GTree *tree,
++ gpointer key);
++gpointer g_tree_lookup (GTree *tree,
++ gpointer key);
++void g_tree_traverse (GTree *tree,
++ GTraverseFunc traverse_func,
++ GTraverseType traverse_type,
++ gpointer data);
++gpointer g_tree_search (GTree *tree,
++ GSearchFunc search_func,
++ gpointer data);
++gint g_tree_height (GTree *tree);
++gint g_tree_nnodes (GTree *tree);
++
++
++
++/* N-way tree implementation
++ */
++struct _GNode
++{
++ gpointer data;
++ GNode *next;
++ GNode *prev;
++ GNode *parent;
++ GNode *children;
++};
++
++#define G_NODE_IS_ROOT(node) (((GNode*) (node))->parent == NULL && \
++ ((GNode*) (node))->prev == NULL && \
++ ((GNode*) (node))->next == NULL)
++#define G_NODE_IS_LEAF(node) (((GNode*) (node))->children == NULL)
++
++void g_node_push_allocator (GAllocator *allocator);
++void g_node_pop_allocator (void);
++GNode* g_node_new (gpointer data);
++void g_node_destroy (GNode *root);
++void g_node_unlink (GNode *node);
++GNode* g_node_insert (GNode *parent,
++ gint position,
++ GNode *node);
++GNode* g_node_insert_before (GNode *parent,
++ GNode *sibling,
++ GNode *node);
++GNode* g_node_prepend (GNode *parent,
++ GNode *node);
++guint g_node_n_nodes (GNode *root,
++ GTraverseFlags flags);
++GNode* g_node_get_root (GNode *node);
++gboolean g_node_is_ancestor (GNode *node,
++ GNode *descendant);
++guint g_node_depth (GNode *node);
++GNode* g_node_find (GNode *root,
++ GTraverseType order,
++ GTraverseFlags flags,
++ gpointer data);
++
++/* convenience macros */
++#define g_node_append(parent, node) \
++ g_node_insert_before ((parent), NULL, (node))
++#define g_node_insert_data(parent, position, data) \
++ g_node_insert ((parent), (position), g_node_new (data))
++#define g_node_insert_data_before(parent, sibling, data) \
++ g_node_insert_before ((parent), (sibling), g_node_new (data))
++#define g_node_prepend_data(parent, data) \
++ g_node_prepend ((parent), g_node_new (data))
++#define g_node_append_data(parent, data) \
++ g_node_insert_before ((parent), NULL, g_node_new (data))
++
++/* traversal function, assumes that `node' is root
++ * (only traverses `node' and its subtree).
++ * this function is just a high level interface to
++ * low level traversal functions, optimized for speed.
++ */
++void g_node_traverse (GNode *root,
++ GTraverseType order,
++ GTraverseFlags flags,
++ gint max_depth,
++ GNodeTraverseFunc func,
++ gpointer data);
++
++/* return the maximum tree height starting with `node', this is an expensive
++ * operation, since we need to visit all nodes. this could be shortened by
++ * adding `guint height' to struct _GNode, but then again, this is not very
++ * often needed, and would make g_node_insert() more time consuming.
++ */
++guint g_node_max_height (GNode *root);
++
++void g_node_children_foreach (GNode *node,
++ GTraverseFlags flags,
++ GNodeForeachFunc func,
++ gpointer data);
++void g_node_reverse_children (GNode *node);
++guint g_node_n_children (GNode *node);
++GNode* g_node_nth_child (GNode *node,
++ guint n);
++GNode* g_node_last_child (GNode *node);
++GNode* g_node_find_child (GNode *node,
++ GTraverseFlags flags,
++ gpointer data);
++gint g_node_child_position (GNode *node,
++ GNode *child);
++gint g_node_child_index (GNode *node,
++ gpointer data);
++
++GNode* g_node_first_sibling (GNode *node);
++GNode* g_node_last_sibling (GNode *node);
++
++#define g_node_prev_sibling(node) ((node) ? \
++ ((GNode*) (node))->prev : NULL)
++#define g_node_next_sibling(node) ((node) ? \
++ ((GNode*) (node))->next : NULL)
++#define g_node_first_child(node) ((node) ? \
++ ((GNode*) (node))->children : NULL)
++
++
++
++/* Fatal error handlers.
++ * g_on_error_query() will prompt the user to either
++ * [E]xit, [H]alt, [P]roceed or show [S]tack trace.
++ * g_on_error_stack_trace() invokes gdb, which attaches to the current
++ * process and shows a stack trace.
++ * These function may cause different actions on non-unix platforms.
++ * The prg_name arg is required by gdb to find the executable, if it is
++ * passed as NULL, g_on_error_query() will try g_get_prgname().
++ */
++void g_on_error_query (const gchar *prg_name);
++void g_on_error_stack_trace (const gchar *prg_name);
++
++
++/* Logging mechanism
++ */
++extern const gchar *g_log_domain_glib;
++guint g_log_set_handler (const gchar *log_domain,
++ GLogLevelFlags log_levels,
++ GLogFunc log_func,
++ gpointer user_data);
++void g_log_remove_handler (const gchar *log_domain,
++ guint handler_id);
++void g_log_default_handler (const gchar *log_domain,
++ GLogLevelFlags log_level,
++ const gchar *message,
++ gpointer unused_data);
++#ifdef __KORBIT__
++#define g_log(log_domain, log_level, format, args...) \
++G_STMT_START { printf(format, ##args); printf("\n"); } G_STMT_END
++#define g_logv(log_domain, log_level, format, args...)
++#else /* !__KORBIT__ */
++void g_log (const gchar *log_domain,
++ GLogLevelFlags log_level,
++ const gchar *format,
++ ...) G_GNUC_PRINTF (3, 4);
++void g_logv (const gchar *log_domain,
++ GLogLevelFlags log_level,
++ const gchar *format,
++ va_list args);
++#endif /* !__KORBIT__ */
++GLogLevelFlags g_log_set_fatal_mask (const gchar *log_domain,
++ GLogLevelFlags fatal_mask);
++GLogLevelFlags g_log_set_always_fatal (GLogLevelFlags fatal_mask);
++#ifndef G_LOG_DOMAIN
++#define G_LOG_DOMAIN ((gchar*) 0)
++#endif /* G_LOG_DOMAIN */
++#ifdef __GNUC__
++#define g_error(format, args...) g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_ERROR, \
++ format, ##args)
++#define g_message(format, args...) g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_MESSAGE, \
++ format, ##args)
++#define g_warning(format, args...) g_log (G_LOG_DOMAIN, \
++ G_LOG_LEVEL_WARNING, \
++ format, ##args)
++#else /* !__GNUC__ */
++static void
++g_error (const gchar *format,
++ ...)
++{
++ va_list args;
++ va_start (args, format);
++ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, format, args);
++ va_end (args);
++}
++static void
++g_message (const gchar *format,
++ ...)
++{
++ va_list args;
++ va_start (args, format);
++ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, format, args);
++ va_end (args);
++}
++static void
++g_warning (const gchar *format,
++ ...)
++{
++ va_list args;
++ va_start (args, format);
++ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, format, args);
++ va_end (args);
++}
++#endif /* !__GNUC__ */
++
++typedef void (*GPrintFunc) (const gchar *string);
++#ifdef __KORBIT__
++#define g_print(format, args...) printf(format, ##args)
++#else
++void g_print (const gchar *format,
++ ...) G_GNUC_PRINTF (1, 2);
++#endif
++GPrintFunc g_set_print_handler (GPrintFunc func);
++void g_printerr (const gchar *format,
++ ...) G_GNUC_PRINTF (1, 2);
++GPrintFunc g_set_printerr_handler (GPrintFunc func);
++
++/* deprecated compatibility functions, use g_log_set_handler() instead */
++typedef void (*GErrorFunc) (const gchar *str);
++typedef void (*GWarningFunc) (const gchar *str);
++GErrorFunc g_set_error_handler (GErrorFunc func);
++GWarningFunc g_set_warning_handler (GWarningFunc func);
++GPrintFunc g_set_message_handler (GPrintFunc func);
++
++
++gpointer g_malloc (gulong size);
++gpointer g_malloc0 (gulong size);
++gpointer g_realloc (gpointer mem,
++ gulong size);
++void g_free (gpointer mem);
++
++/* Generic allocators
++ */
++GAllocator* g_allocator_new (const gchar *name,
++ guint n_preallocs);
++void g_allocator_free (GAllocator *allocator);
++
++#define G_ALLOCATOR_LIST (1)
++#define G_ALLOCATOR_SLIST (2)
++#define G_ALLOCATOR_NODE (3)
++
++
++/* "g_mem_chunk_new" creates a new memory chunk.
++ * Memory chunks are used to allocate pieces of memory which are
++ * always the same size. Lists are a good example of such a data type.
++ * The memory chunk allocates and frees blocks of memory as needed.
++ * Just be sure to call "g_mem_chunk_free" and not "g_free" on data
++ * allocated in a mem chunk. ("g_free" will most likely cause a seg
++ * fault...somewhere).
++ *
++ * Oh yeah, GMemChunk is an opaque data type. (You don't really
++ * want to know what's going on inside do you?)
++ */
++
++/* ALLOC_ONLY MemChunk's can only allocate memory. The free operation
++ * is interpreted as a no op. ALLOC_ONLY MemChunk's save 4 bytes per
++ * atom. (They are also useful for lists which use MemChunk to allocate
++ * memory but are also part of the MemChunk implementation).
++ * ALLOC_AND_FREE MemChunk's can allocate and free memory.
++ */
++
++#define G_ALLOC_ONLY 1
++#define G_ALLOC_AND_FREE 2
++
++GMemChunk* g_mem_chunk_new (gchar *name,
++ gint atom_size,
++ gulong area_size,
++ gint type);
++void g_mem_chunk_destroy (GMemChunk *mem_chunk);
++gpointer g_mem_chunk_alloc (GMemChunk *mem_chunk);
++gpointer g_mem_chunk_alloc0 (GMemChunk *mem_chunk);
++void g_mem_chunk_free (GMemChunk *mem_chunk,
++ gpointer mem);
++void g_mem_chunk_clean (GMemChunk *mem_chunk);
++void g_mem_chunk_reset (GMemChunk *mem_chunk);
++void g_mem_chunk_print (GMemChunk *mem_chunk);
++void g_mem_chunk_info (void);
++
++/* Ah yes...we have a "g_blow_chunks" function.
++ * "g_blow_chunks" simply compresses all the chunks. This operation
++ * consists of freeing every memory area that should be freed (but
++ * which we haven't gotten around to doing yet). And, no,
++ * "g_blow_chunks" doesn't follow the naming scheme, but it is a
++ * much better name than "g_mem_chunk_clean_all" or something
++ * similar.
++ */
++void g_blow_chunks (void);
++
++
++/* String utility functions that modify a string argument or
++ * return a constant string that must not be freed.
++ */
++#define G_STR_DELIMITERS "_-|> <."
++gchar* g_strdelimit (gchar *string,
++ const gchar *delimiters,
++ gchar new_delimiter);
++#ifndef __KORBIT__
++gdouble g_strtod (const gchar *nptr,
++ gchar **endptr);
++#endif /* !__KORBIT__ */
++gchar* g_strerror (gint errnum);
++gchar* g_strsignal (gint signum);
++gint g_strcasecmp (const gchar *s1,
++ const gchar *s2);
++gint g_strncasecmp (const gchar *s1,
++ const gchar *s2,
++ guint n);
++void g_strdown (gchar *string);
++void g_strup (gchar *string);
++void g_strreverse (gchar *string);
++/* removes leading spaces */
++gchar* g_strchug (gchar *string);
++/* removes trailing spaces */
++gchar* g_strchomp (gchar *string);
++/* removes leading & trailing spaces */
++#define g_strstrip( string ) g_strchomp (g_strchug (string))
++
++/* String utility functions that return a newly allocated string which
++ * ought to be freed from the caller at some point.
++ */
++gchar* g_strdup (const gchar *str);
++gchar* g_strdup_printf (const gchar *format,
++ ...) G_GNUC_PRINTF (1, 2);
++gchar* g_strdup_vprintf (const gchar *format,
++ va_list args);
++gchar* g_strndup (const gchar *str,
++ guint n);
++gchar* g_strnfill (guint length,
++ gchar fill_char);
++gchar* g_strconcat (const gchar *string1,
++ ...); /* NULL terminated */
++gchar* g_strjoin (const gchar *separator,
++ ...); /* NULL terminated */
++gchar* g_strescape (gchar *string);
++gpointer g_memdup (gconstpointer mem,
++ guint byte_size);
++
++/* NULL terminated string arrays.
++ * g_strsplit() splits up string into max_tokens tokens at delim and
++ * returns a newly allocated string array.
++ * g_strjoinv() concatenates all of str_array's strings, sliding in an
++ * optional separator, the returned string is newly allocated.
++ * g_strfreev() frees the array itself and all of its strings.
++ */
++gchar** g_strsplit (const gchar *string,
++ const gchar *delimiter,
++ gint max_tokens);
++gchar* g_strjoinv (const gchar *separator,
++ gchar **str_array);
++void g_strfreev (gchar **str_array);
++
++
++
++/* calculate a string size, guarranteed to fit format + args.
++ */
++guint g_printf_string_upper_bound (const gchar* format,
++ va_list args);
++
++
++/* Retrive static string info
++ */
++gchar* g_get_user_name (void);
++gchar* g_get_real_name (void);
++gchar* g_get_home_dir (void);
++gchar* g_get_tmp_dir (void);
++gchar* g_get_prgname (void);
++void g_set_prgname (const gchar *prgname);
++
++
++/* Miscellaneous utility functions
++ */
++guint g_parse_debug_string (const gchar *string,
++ GDebugKey *keys,
++ guint nkeys);
++gint g_snprintf (gchar *string,
++ gulong n,
++ gchar const *format,
++ ...) G_GNUC_PRINTF (3, 4);
++gint g_vsnprintf (gchar *string,
++ gulong n,
++ gchar const *format,
++ va_list args);
++gchar* g_basename (const gchar *file_name);
++/* Check if a file name is an absolute path */
++gboolean g_path_is_absolute (const gchar *file_name);
++/* In case of absolute paths, skip the root part */
++gchar* g_path_skip_root (gchar *file_name);
++
++/* strings are newly allocated with g_malloc() */
++gchar* g_dirname (const gchar *file_name);
++gchar* g_get_current_dir (void);
++gchar* g_getenv (const gchar *variable);
++
++
++/* we use a GLib function as a replacement for ATEXIT, so
++ * the programmer is not required to check the return value
++ * (if there is any in the implementation) and doesn't encounter
++ * missing include files.
++ */
++void g_atexit (GVoidFunc func);
++
++
++/* Bit tests
++ */
++G_INLINE_FUNC gint g_bit_nth_lsf (guint32 mask,
++ gint nth_bit);
++#ifdef G_CAN_INLINE
++G_INLINE_FUNC gint
++g_bit_nth_lsf (guint32 mask,
++ gint nth_bit)
++{
++ do
++ {
++ nth_bit++;
++ if (mask & (1 << (guint) nth_bit))
++ return nth_bit;
++ }
++ while (nth_bit < 32);
++ return -1;
++}
++#endif /* G_CAN_INLINE */
++
++G_INLINE_FUNC gint g_bit_nth_msf (guint32 mask,
++ gint nth_bit);
++#ifdef G_CAN_INLINE
++G_INLINE_FUNC gint
++g_bit_nth_msf (guint32 mask,
++ gint nth_bit)
++{
++ if (nth_bit < 0)
++ nth_bit = 32;
++ do
++ {
++ nth_bit--;
++ if (mask & (1 << (guint) nth_bit))
++ return nth_bit;
++ }
++ while (nth_bit > 0);
++ return -1;
++}
++#endif /* G_CAN_INLINE */
++
++G_INLINE_FUNC guint g_bit_storage (guint number);
++#ifdef G_CAN_INLINE
++G_INLINE_FUNC guint
++g_bit_storage (guint number)
++{
++ register guint n_bits = 0;
++
++ do
++ {
++ n_bits++;
++ number >>= 1;
++ }
++ while (number);
++ return n_bits;
++}
++#endif /* G_CAN_INLINE */
++
++/* String Chunks
++ */
++GStringChunk* g_string_chunk_new (gint size);
++void g_string_chunk_free (GStringChunk *chunk);
++gchar* g_string_chunk_insert (GStringChunk *chunk,
++ const gchar *string);
++gchar* g_string_chunk_insert_const (GStringChunk *chunk,
++ const gchar *string);
++
++
++/* Strings
++ */
++GString* g_string_new (const gchar *init);
++GString* g_string_sized_new (guint dfl_size);
++void g_string_free (GString *string,
++ gint free_segment);
++GString* g_string_assign (GString *lval,
++ const gchar *rval);
++GString* g_string_truncate (GString *string,
++ gint len);
++GString* g_string_append (GString *string,
++ const gchar *val);
++GString* g_string_append_c (GString *string,
++ gchar c);
++GString* g_string_prepend (GString *string,
++ const gchar *val);
++GString* g_string_prepend_c (GString *string,
++ gchar c);
++GString* g_string_insert (GString *string,
++ gint pos,
++ const gchar *val);
++GString* g_string_insert_c (GString *string,
++ gint pos,
++ gchar c);
++GString* g_string_erase (GString *string,
++ gint pos,
++ gint len);
++GString* g_string_down (GString *string);
++GString* g_string_up (GString *string);
++void g_string_sprintf (GString *string,
++ const gchar *format,
++ ...) G_GNUC_PRINTF (2, 3);
++void g_string_sprintfa (GString *string,
++ const gchar *format,
++ ...) G_GNUC_PRINTF (2, 3);
++
++
++/* Resizable arrays, remove fills any cleared spot and shortens the
++ * array, while preserving the order. remove_fast will distort the
++ * order by moving the last element to the position of the removed
++ */
++
++#define g_array_append_val(a,v) g_array_append_vals (a, &v, 1)
++#define g_array_prepend_val(a,v) g_array_prepend_vals (a, &v, 1)
++#define g_array_insert_val(a,i,v) g_array_insert_vals (a, i, &v, 1)
++#define g_array_index(a,t,i) (((t*) (a)->data) [(i)])
++
++GArray* g_array_new (gboolean zero_terminated,
++ gboolean clear,
++ guint element_size);
++void g_array_free (GArray *array,
++ gboolean free_segment);
++GArray* g_array_append_vals (GArray *array,
++ gconstpointer data,
++ guint len);
++GArray* g_array_prepend_vals (GArray *array,
++ gconstpointer data,
++ guint len);
++GArray* g_array_insert_vals (GArray *array,
++ guint index,
++ gconstpointer data,
++ guint len);
++GArray* g_array_set_size (GArray *array,
++ guint length);
++GArray* g_array_remove_index (GArray *array,
++ guint index);
++GArray* g_array_remove_index_fast (GArray *array,
++ guint index);
++
++/* Resizable pointer array. This interface is much less complicated
++ * than the above. Add appends appends a pointer. Remove fills any
++ * cleared spot and shortens the array. remove_fast will again distort
++ * order.
++ */
++#define g_ptr_array_index(array,index) (array->pdata)[index]
++GPtrArray* g_ptr_array_new (void);
++void g_ptr_array_free (GPtrArray *array,
++ gboolean free_seg);
++void g_ptr_array_set_size (GPtrArray *array,
++ gint length);
++gpointer g_ptr_array_remove_index (GPtrArray *array,
++ guint index);
++gpointer g_ptr_array_remove_index_fast (GPtrArray *array,
++ guint index);
++gboolean g_ptr_array_remove (GPtrArray *array,
++ gpointer data);
++gboolean g_ptr_array_remove_fast (GPtrArray *array,
++ gpointer data);
++void g_ptr_array_add (GPtrArray *array,
++ gpointer data);
++
++/* Hash Functions
++ */
++gint g_str_equal (gconstpointer v,
++ gconstpointer v2);
++guint g_str_hash (gconstpointer v);
++
++gint g_int_equal (gconstpointer v,
++ gconstpointer v2);
++guint g_int_hash (gconstpointer v);
++
++/* This "hash" function will just return the key's adress as an
++ * unsigned integer. Useful for hashing on plain adresses or
++ * simple integer values.
++ * passing NULL into g_hash_table_new() as GHashFunc has the
++ * same effect as passing g_direct_hash().
++ */
++guint g_direct_hash (gconstpointer v);
++gint g_direct_equal (gconstpointer v,
++ gconstpointer v2);
++
++
++
++/* Prime numbers.
++ */
++
++/* This function returns prime numbers spaced by approximately 1.5-2.0
++ * and is for use in resizing data structures which prefer
++ * prime-valued sizes. The closest spaced prime function returns the
++ * next largest prime, or the highest it knows about which is about
++ * MAXINT/4.
++ */
++guint g_spaced_primes_closest (guint num);
++
++
++
++#ifndef __KORBIT__
++/* GLib Thread support
++ */
++typedef struct _GMutex GMutex;
++typedef struct _GCond GCond;
++typedef struct _GPrivate GPrivate;
++typedef struct _GStaticPrivate GStaticPrivate;
++typedef struct _GThreadFunctions GThreadFunctions;
++struct _GThreadFunctions
++{
++ GMutex* (*mutex_new) (void);
++ void (*mutex_lock) (GMutex *mutex);
++ gboolean (*mutex_trylock) (GMutex *mutex);
++ void (*mutex_unlock) (GMutex *mutex);
++ void (*mutex_free) (GMutex *mutex);
++ GCond* (*cond_new) (void);
++ void (*cond_signal) (GCond *cond);
++ void (*cond_broadcast) (GCond *cond);
++ void (*cond_wait) (GCond *cond,
++ GMutex *mutex);
++ gboolean (*cond_timed_wait) (GCond *cond,
++ GMutex *mutex,
++ GTimeVal *end_time);
++ void (*cond_free) (GCond *cond);
++ GPrivate* (*private_new) (GDestroyNotify destructor);
++ gpointer (*private_get) (GPrivate *private_key);
++ void (*private_set) (GPrivate *private_key,
++ gpointer data);
++};
++
++GUTILS_C_VAR GThreadFunctions g_thread_functions_for_glib_use;
++GUTILS_C_VAR gboolean g_thread_use_default_impl;
++GUTILS_C_VAR gboolean g_threads_got_initialized;
++
++/* initializes the mutex/cond/private implementation for glib, might
++ * only be called once, and must not be called directly or indirectly
++ * from another glib-function, e.g. as a callback.
++ */
++void g_thread_init (GThreadFunctions *vtable);
++
++/* internal function for fallback static mutex implementation */
++GMutex* g_static_mutex_get_mutex_impl (GMutex **mutex);
++
++/* shorthands for conditional and unconditional function calls */
++#define G_THREAD_UF(name, arglist) \
++ (*g_thread_functions_for_glib_use . name) arglist
++#define G_THREAD_CF(name, fail, arg) \
++ (g_thread_supported () ? G_THREAD_UF (name, arg) : (fail))
++/* keep in mind, all those mutexes and static mutexes are not
++ * recursive in general, don't rely on that
++ */
++#define g_thread_supported() (g_threads_got_initialized)
++#define g_mutex_new() G_THREAD_UF (mutex_new, ())
++#define g_mutex_lock(mutex) G_THREAD_CF (mutex_lock, (void)0, (mutex))
++#define g_mutex_trylock(mutex) G_THREAD_CF (mutex_trylock, TRUE, (mutex))
++#define g_mutex_unlock(mutex) G_THREAD_CF (mutex_unlock, (void)0, (mutex))
++#define g_mutex_free(mutex) G_THREAD_CF (mutex_free, (void)0, (mutex))
++#define g_cond_new() G_THREAD_UF (cond_new, ())
++#define g_cond_signal(cond) G_THREAD_CF (cond_signal, (void)0, (cond))
++#define g_cond_broadcast(cond) G_THREAD_CF (cond_broadcast, (void)0, (cond))
++#define g_cond_wait(cond, mutex) G_THREAD_CF (cond_wait, (void)0, (cond, \
++ mutex))
++#define g_cond_free(cond) G_THREAD_CF (cond_free, (void)0, (cond))
++#define g_cond_timed_wait(cond, mutex, abs_time) G_THREAD_CF (cond_timed_wait, \
++ TRUE, \
++ (cond, mutex, \
++ abs_time))
++#define g_private_new(destructor) G_THREAD_UF (private_new, (destructor))
++#define g_private_get(private_key) G_THREAD_CF (private_get, \
++ ((gpointer)private_key), \
++ (private_key))
++#define g_private_set(private_key, value) G_THREAD_CF (private_set, \
++ (void) (private_key = \
++ (GPrivate*) (value)), \
++ (private_key, value))
++/* GStaticMutexes can be statically initialized with the value
++ * G_STATIC_MUTEX_INIT, and then they can directly be used, that is
++ * much easier, than having to explicitly allocate the mutex before
++ * use
++ */
++#define g_static_mutex_lock(mutex) \
++ g_mutex_lock (g_static_mutex_get_mutex (mutex))
++#define g_static_mutex_trylock(mutex) \
++ g_mutex_trylock (g_static_mutex_get_mutex (mutex))
++#define g_static_mutex_unlock(mutex) \
++ g_mutex_unlock (g_static_mutex_get_mutex (mutex))
++struct _GStaticPrivate
++{
++ guint index;
++};
++#define G_STATIC_PRIVATE_INIT { 0 }
++gpointer g_static_private_get (GStaticPrivate *private_key);
++void g_static_private_set (GStaticPrivate *private_key,
++ gpointer data,
++ GDestroyNotify notify);
++#endif /* __KORBIT__ */
++
++/* these are some convenience macros that expand to nothing if GLib
++ * was configured with --disable-threads. for using StaticMutexes,
++ * you define them with G_LOCK_DEFINE_STATIC (name) or G_LOCK_DEFINE (name)
++ * if you need to export the mutex. With G_LOCK_EXTERN (name) you can
++ * declare such an globally defined lock. name is a unique identifier
++ * for the protected varibale or code portion. locking, testing and
++ * unlocking of such mutexes can be done with G_LOCK(), G_UNLOCK() and
++ * G_TRYLOCK() respectively.
++ */
++#ifdef __KORBIT__
++#undef G_THREADS_ENABLED
++#endif
++
++extern void glib_dummy_decl (void);
++#define G_LOCK_NAME(name) (g__ ## name ## _lock)
++#ifdef G_THREADS_ENABLED
++# define G_LOCK_DEFINE_STATIC(name) static G_LOCK_DEFINE (name)
++# define G_LOCK_DEFINE(name) \
++ GStaticMutex G_LOCK_NAME (name) = G_STATIC_MUTEX_INIT
++# define G_LOCK_EXTERN(name) extern GStaticMutex G_LOCK_NAME (name)
++
++# define G_LOCK(name) g_static_mutex_lock (&G_LOCK_NAME (name))
++# define G_UNLOCK(name) g_static_mutex_unlock (&G_LOCK_NAME (name))
++# define G_TRYLOCK(name) g_static_mutex_trylock (&G_LOCK_NAME (name))
++#else /* !G_THREADS_ENABLED */
++# define G_LOCK_DEFINE_STATIC(name) extern void glib_dummy_decl (void)
++# define G_LOCK_DEFINE(name) extern void glib_dummy_decl (void)
++# define G_LOCK_EXTERN(name) extern void glib_dummy_decl (void)
++# define G_LOCK(name)
++# define G_UNLOCK(name)
++# define G_TRYLOCK(name) (FALSE)
++#endif /* !G_THREADS_ENABLED */
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++
++#endif /* __G_LIB_H__ */
+diff -urN linux-2.4.1/net/korbit/kglib/glibconfig.h linux-2.4.1-korbit/net/korbit/kglib/glibconfig.h
+--- linux-2.4.1/net/korbit/kglib/glibconfig.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/glibconfig.h Thu Feb 1 11:46:56 2001
+@@ -0,0 +1,131 @@
++/* glibconfig.h
++ *
++ * This is a generated file. Please modify `configure.in'
++ */
++
++#ifndef GLIBCONFIG_H
++#define GLIBCONFIG_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++#include <limits.h>
++/*#include <float.h>*/
++#define GLIB_HAVE_SYS_POLL_H
++
++#define G_MINFLOAT FLT_MIN
++#define G_MAXFLOAT FLT_MAX
++#define G_MINDOUBLE DBL_MIN
++#define G_MAXDOUBLE DBL_MAX
++#define G_MINSHORT SHRT_MIN
++#define G_MAXSHORT SHRT_MAX
++#define G_MININT INT_MIN
++#define G_MAXINT INT_MAX
++#define G_MINLONG LONG_MIN
++#define G_MAXLONG LONG_MAX
++
++typedef signed char gint8;
++typedef unsigned char guint8;
++typedef signed short gint16;
++typedef unsigned short guint16;
++typedef signed int gint32;
++typedef unsigned int guint32;
++
++#if defined (__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8))
++# define G_GNUC_EXTENSION __extension__
++#else
++# define G_GNUC_EXTENSION
++#endif
++
++#define G_HAVE_GINT64 1
++
++G_GNUC_EXTENSION typedef signed long long gint64;
++G_GNUC_EXTENSION typedef unsigned long long guint64;
++
++#define G_GINT64_CONSTANT(val) (G_GNUC_EXTENSION (val##LL))
++
++#define GPOINTER_TO_INT(p) ((gint) (p))
++#define GPOINTER_TO_UINT(p) ((guint) (p))
++
++#define GINT_TO_POINTER(i) ((gpointer) (i))
++#define GUINT_TO_POINTER(u) ((gpointer) (u))
++
++#ifdef NeXT /* @#%@! NeXTStep */
++# define g_ATEXIT(proc) (!atexit (proc))
++#else
++# define g_ATEXIT(proc) (atexit (proc))
++#endif
++
++#define g_memmove(d,s,n) G_STMT_START { memmove ((d), (s), (n)); } G_STMT_END
++
++#define GLIB_MAJOR_VERSION 1
++#define GLIB_MINOR_VERSION 2
++#define GLIB_MICRO_VERSION 8
++
++
++#define G_VA_COPY __va_copy
++
++#ifdef __cplusplus
++#define G_HAVE_INLINE 1
++#else /* !__cplusplus */
++#define G_HAVE_INLINE 1
++#define G_HAVE___INLINE 1
++#define G_HAVE___INLINE__ 1
++#endif /* !__cplusplus */
++
++#define G_THREADS_ENABLED
++#define G_THREADS_IMPL_POSIX
++typedef struct _GStaticMutex GStaticMutex;
++struct _GStaticMutex
++{
++ struct _GMutex *runtime_mutex;
++ union {
++ char pad[24];
++ double dummy_double;
++ void *dummy_pointer;
++ long dummy_long;
++ } aligned_pad_u;
++};
++#define G_STATIC_MUTEX_INIT { NULL, { { 0,0,0,0,0,0,77,88,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} } }
++#define g_static_mutex_get_mutex(mutex) (g_thread_use_default_impl ? ((GMutex*) &((mutex)->aligned_pad_u)) : g_static_mutex_get_mutex_impl (&((mutex)->runtime_mutex)))
++
++#define GINT16_TO_BE(val) ((gint16) (val))
++#define GUINT16_TO_BE(val) ((guint16) (val))
++#define GINT16_TO_LE(val) ((gint16) GUINT16_SWAP_LE_BE (val))
++#define GUINT16_TO_LE(val) (GUINT16_SWAP_LE_BE (val))
++#define GINT32_TO_BE(val) ((gint32) (val))
++#define GUINT32_TO_BE(val) ((guint32) (val))
++#define GINT32_TO_LE(val) ((gint32) GUINT32_SWAP_LE_BE (val))
++#define GUINT32_TO_LE(val) (GUINT32_SWAP_LE_BE (val))
++#define GINT64_TO_BE(val) ((gint64) (val))
++#define GUINT64_TO_BE(val) ((guint64) (val))
++#define GINT64_TO_LE(val) ((gint64) GUINT64_SWAP_LE_BE (val))
++#define GUINT64_TO_LE(val) (GUINT64_SWAP_LE_BE (val))
++#define GLONG_TO_LE(val) ((glong) GINT32_TO_LE (val))
++#define GULONG_TO_LE(val) ((gulong) GUINT32_TO_LE (val))
++#define GLONG_TO_BE(val) ((glong) GINT32_TO_BE (val))
++#define GULONG_TO_BE(val) ((gulong) GUINT32_TO_BE (val))
++#define GINT_TO_LE(val) ((gint) GINT32_TO_LE (val))
++#define GUINT_TO_LE(val) ((guint) GUINT32_TO_LE (val))
++#define GINT_TO_BE(val) ((gint) GINT32_TO_BE (val))
++#define GUINT_TO_BE(val) ((guint) GUINT32_TO_BE (val))
++#define G_BYTE_ORDER G_LITTLE_ENDIAN
++
++#define GLIB_SYSDEF_POLLIN =1
++#define GLIB_SYSDEF_POLLOUT =4
++#define GLIB_SYSDEF_POLLPRI =2
++#define GLIB_SYSDEF_POLLERR =8
++#define GLIB_SYSDEF_POLLHUP =16
++#define GLIB_SYSDEF_POLLNVAL =32
++
++
++#define G_HAVE_WCHAR_H 1
++#define G_HAVE_WCTYPE_H 1
++
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* GLIBCONFIG_H */
+diff -urN linux-2.4.1/net/korbit/kglib/glist.c linux-2.4.1-korbit/net/korbit/kglib/glist.c
+--- linux-2.4.1/net/korbit/kglib/glist.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/glist.c Thu Feb 1 11:46:57 2001
+@@ -0,0 +1,666 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/*
++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS
++ * file for a list of people on the GLib Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GLib at ftp://ftp.gtk.org/pub/gtk/.
++ */
++
++#include "glib.h"
++
++
++struct _GAllocator /* from gmem.c */
++{
++ gchar *name;
++ guint16 n_preallocs;
++ guint is_unused : 1;
++ guint type : 4;
++ GAllocator *last;
++ GMemChunk *mem_chunk;
++ GList *free_lists; /* implementation specific */
++};
++
++static GAllocator *current_allocator = NULL;
++G_LOCK_DEFINE_STATIC (current_allocator);
++
++/* HOLDS: current_allocator_lock */
++static void
++g_list_validate_allocator (GAllocator *allocator)
++{
++ g_return_if_fail (allocator != NULL);
++ g_return_if_fail (allocator->is_unused == TRUE);
++
++ if (allocator->type != G_ALLOCATOR_LIST)
++ {
++ allocator->type = G_ALLOCATOR_LIST;
++ if (allocator->mem_chunk)
++ {
++ g_mem_chunk_destroy (allocator->mem_chunk);
++ allocator->mem_chunk = NULL;
++ }
++ }
++
++ if (!allocator->mem_chunk)
++ {
++ allocator->mem_chunk = g_mem_chunk_new (allocator->name,
++ sizeof (GList),
++ sizeof (GList) * allocator->n_preallocs,
++ G_ALLOC_ONLY);
++ allocator->free_lists = NULL;
++ }
++
++ allocator->is_unused = FALSE;
++}
++
++void
++g_list_push_allocator(GAllocator *allocator)
++{
++ G_LOCK (current_allocator);
++ g_list_validate_allocator ( allocator );
++ allocator->last = current_allocator;
++ current_allocator = allocator;
++ G_UNLOCK (current_allocator);
++}
++
++void
++g_list_pop_allocator (void)
++{
++ G_LOCK (current_allocator);
++ if (current_allocator)
++ {
++ GAllocator *allocator;
++
++ allocator = current_allocator;
++ current_allocator = allocator->last;
++ allocator->last = NULL;
++ allocator->is_unused = TRUE;
++ }
++ G_UNLOCK (current_allocator);
++}
++
++GList*
++g_list_alloc (void)
++{
++ GList *list;
++
++ G_LOCK (current_allocator);
++ if (!current_allocator)
++ {
++ GAllocator *allocator = g_allocator_new ("GLib default GList allocator",
++ 128);
++ g_list_validate_allocator (allocator);
++ allocator->last = NULL;
++ current_allocator = allocator;
++ }
++ if (!current_allocator->free_lists)
++ {
++ list = g_chunk_new (GList, current_allocator->mem_chunk);
++ list->data = NULL;
++ }
++ else
++ {
++ if (current_allocator->free_lists->data)
++ {
++ list = current_allocator->free_lists->data;
++ current_allocator->free_lists->data = list->next;
++ list->data = NULL;
++ }
++ else
++ {
++ list = current_allocator->free_lists;
++ current_allocator->free_lists = list->next;
++ }
++ }
++ G_UNLOCK (current_allocator);
++ list->next = NULL;
++ list->prev = NULL;
++
++ return list;
++}
++
++void
++g_list_free (GList *list)
++{
++ if (list)
++ {
++ list->data = list->next;
++ G_LOCK (current_allocator);
++ list->next = current_allocator->free_lists;
++ current_allocator->free_lists = list;
++ G_UNLOCK (current_allocator);
++ }
++}
++
++void
++g_list_free_1 (GList *list)
++{
++ if (list)
++ {
++ list->data = NULL;
++ G_LOCK (current_allocator);
++ list->next = current_allocator->free_lists;
++ current_allocator->free_lists = list;
++ G_UNLOCK (current_allocator);
++ }
++}
++
++GList*
++g_list_append (GList *list,
++ gpointer data)
++{
++ GList *new_list;
++ GList *last;
++
++ new_list = g_list_alloc ();
++ new_list->data = data;
++
++ if (list)
++ {
++ last = g_list_last (list);
++ /* g_assert (last != NULL); */
++ last->next = new_list;
++ new_list->prev = last;
++
++ return list;
++ }
++ else
++ return new_list;
++}
++
++GList*
++g_list_prepend (GList *list,
++ gpointer data)
++{
++ GList *new_list;
++
++ new_list = g_list_alloc ();
++ new_list->data = data;
++
++ if (list)
++ {
++ if (list->prev)
++ {
++ list->prev->next = new_list;
++ new_list->prev = list->prev;
++ }
++ list->prev = new_list;
++ new_list->next = list;
++ }
++
++ return new_list;
++}
++
++GList*
++g_list_insert (GList *list,
++ gpointer data,
++ gint position)
++{
++ GList *new_list;
++ GList *tmp_list;
++
++ if (position < 0)
++ return g_list_append (list, data);
++ else if (position == 0)
++ return g_list_prepend (list, data);
++
++ tmp_list = g_list_nth (list, position);
++ if (!tmp_list)
++ return g_list_append (list, data);
++
++ new_list = g_list_alloc ();
++ new_list->data = data;
++
++ if (tmp_list->prev)
++ {
++ tmp_list->prev->next = new_list;
++ new_list->prev = tmp_list->prev;
++ }
++ new_list->next = tmp_list;
++ tmp_list->prev = new_list;
++
++ if (tmp_list == list)
++ return new_list;
++ else
++ return list;
++}
++
++GList *
++g_list_concat (GList *list1, GList *list2)
++{
++ GList *tmp_list;
++
++ if (list2)
++ {
++ tmp_list = g_list_last (list1);
++ if (tmp_list)
++ tmp_list->next = list2;
++ else
++ list1 = list2;
++ list2->prev = tmp_list;
++ }
++
++ return list1;
++}
++
++GList*
++g_list_remove (GList *list,
++ gpointer data)
++{
++ GList *tmp;
++
++ tmp = list;
++ while (tmp)
++ {
++ if (tmp->data != data)
++ tmp = tmp->next;
++ else
++ {
++ if (tmp->prev)
++ tmp->prev->next = tmp->next;
++ if (tmp->next)
++ tmp->next->prev = tmp->prev;
++
++ if (list == tmp)
++ list = list->next;
++
++ g_list_free_1 (tmp);
++
++ break;
++ }
++ }
++ return list;
++}
++
++GList*
++g_list_remove_link (GList *list,
++ GList *link)
++{
++ if (link)
++ {
++ if (link->prev)
++ link->prev->next = link->next;
++ if (link->next)
++ link->next->prev = link->prev;
++
++ if (link == list)
++ list = list->next;
++
++ link->next = NULL;
++ link->prev = NULL;
++ }
++
++ return list;
++}
++
++GList*
++g_list_copy (GList *list)
++{
++ GList *new_list = NULL;
++
++ if (list)
++ {
++ GList *last;
++
++ new_list = g_list_alloc ();
++ new_list->data = list->data;
++ last = new_list;
++ list = list->next;
++ while (list)
++ {
++ last->next = g_list_alloc ();
++ last->next->prev = last;
++ last = last->next;
++ last->data = list->data;
++ list = list->next;
++ }
++ }
++
++ return new_list;
++}
++
++GList*
++g_list_reverse (GList *list)
++{
++ GList *last;
++
++ last = NULL;
++ while (list)
++ {
++ last = list;
++ list = last->next;
++ last->next = last->prev;
++ last->prev = list;
++ }
++
++ return last;
++}
++
++GList*
++g_list_nth (GList *list,
++ guint n)
++{
++ while ((n-- > 0) && list)
++ list = list->next;
++
++ return list;
++}
++
++gpointer
++g_list_nth_data (GList *list,
++ guint n)
++{
++ while ((n-- > 0) && list)
++ list = list->next;
++
++ return list ? list->data : NULL;
++}
++
++GList*
++g_list_find (GList *list,
++ gpointer data)
++{
++ while (list)
++ {
++ if (list->data == data)
++ break;
++ list = list->next;
++ }
++
++ return list;
++}
++
++GList*
++g_list_find_custom (GList *list,
++ gpointer data,
++ GCompareFunc func)
++{
++ g_return_val_if_fail (func != NULL, list);
++
++ while (list)
++ {
++ if (! func (list->data, data))
++ return list;
++ list = list->next;
++ }
++
++ return NULL;
++}
++
++
++gint
++g_list_position (GList *list,
++ GList *link)
++{
++ gint i;
++
++ i = 0;
++ while (list)
++ {
++ if (list == link)
++ return i;
++ i++;
++ list = list->next;
++ }
++
++ return -1;
++}
++
++gint
++g_list_index (GList *list,
++ gpointer data)
++{
++ gint i;
++
++ i = 0;
++ while (list)
++ {
++ if (list->data == data)
++ return i;
++ i++;
++ list = list->next;
++ }
++
++ return -1;
++}
++
++GList*
++g_list_last (GList *list)
++{
++ if (list)
++ {
++ while (list->next)
++ list = list->next;
++ }
++
++ return list;
++}
++
++GList*
++g_list_first (GList *list)
++{
++ if (list)
++ {
++ while (list->prev)
++ list = list->prev;
++ }
++
++ return list;
++}
++
++guint
++g_list_length (GList *list)
++{
++ guint length;
++
++ length = 0;
++ while (list)
++ {
++ length++;
++ list = list->next;
++ }
++
++ return length;
++}
++
++void
++g_list_foreach (GList *list,
++ GFunc func,
++ gpointer user_data)
++{
++ while (list)
++ {
++ (*func) (list->data, user_data);
++ list = list->next;
++ }
++}
++
++
++GList*
++g_list_insert_sorted (GList *list,
++ gpointer data,
++ GCompareFunc func)
++{
++ GList *tmp_list = list;
++ GList *new_list;
++ gint cmp;
++
++ g_return_val_if_fail (func != NULL, list);
++
++ if (!list)
++ {
++ new_list = g_list_alloc();
++ new_list->data = data;
++ return new_list;
++ }
++
++ cmp = (*func) (data, tmp_list->data);
++
++ while ((tmp_list->next) && (cmp > 0))
++ {
++ tmp_list = tmp_list->next;
++ cmp = (*func) (data, tmp_list->data);
++ }
++
++ new_list = g_list_alloc();
++ new_list->data = data;
++
++ if ((!tmp_list->next) && (cmp > 0))
++ {
++ tmp_list->next = new_list;
++ new_list->prev = tmp_list;
++ return list;
++ }
++
++ if (tmp_list->prev)
++ {
++ tmp_list->prev->next = new_list;
++ new_list->prev = tmp_list->prev;
++ }
++ new_list->next = tmp_list;
++ tmp_list->prev = new_list;
++
++ if (tmp_list == list)
++ return new_list;
++ else
++ return list;
++}
++
++static GList *
++g_list_sort_merge (GList *l1,
++ GList *l2,
++ GCompareFunc compare_func)
++{
++ GList list, *l, *lprev;
++
++ l = &list;
++ lprev = NULL;
++
++ while (l1 && l2)
++ {
++ if (compare_func (l1->data, l2->data) < 0)
++ {
++ l->next = l1;
++ l = l->next;
++ l->prev = lprev;
++ lprev = l;
++ l1 = l1->next;
++ }
++ else
++ {
++ l->next = l2;
++ l = l->next;
++ l->prev = lprev;
++ lprev = l;
++ l2 = l2->next;
++ }
++ }
++ l->next = l1 ? l1 : l2;
++ l->next->prev = l;
++
++ return list.next;
++}
++
++GList*
++g_list_sort (GList *list,
++ GCompareFunc compare_func)
++{
++ GList *l1, *l2;
++
++ if (!list)
++ return NULL;
++ if (!list->next)
++ return list;
++
++ l1 = list;
++ l2 = list->next;
++
++ while ((l2 = l2->next) != NULL)
++ {
++ if ((l2 = l2->next) == NULL)
++ break;
++ l1 = l1->next;
++ }
++ l2 = l1->next;
++ l1->next = NULL;
++
++ return g_list_sort_merge (g_list_sort (list, compare_func),
++ g_list_sort (l2, compare_func),
++ compare_func);
++}
++
++GList*
++g_list_sort2 (GList *list,
++ GCompareFunc compare_func)
++{
++ GSList *runs = NULL;
++ GList *tmp;
++
++ /* Degenerate case. */
++ if (!list) return NULL;
++
++ /* Assume: list = [12,2,4,11,2,4,6,1,1,12]. */
++ for (tmp = list; tmp; )
++ {
++ GList *tmp2;
++ for (tmp2 = tmp;
++ tmp2->next && compare_func (tmp2->data, tmp2->next->data) <= 0;
++ tmp2 = tmp2->next)
++ /* Nothing */;
++ runs = g_slist_append (runs, tmp);
++ tmp = tmp2->next;
++ tmp2->next = NULL;
++ }
++ /* Now: runs = [[12],[2,4,11],[2,4,6],[1,1,12]]. */
++
++ while (runs->next)
++ {
++ /* We have more than one run. Merge pairwise. */
++ GSList *dst, *src, *dstprev = NULL;
++ dst = src = runs;
++ while (src && src->next)
++ {
++ dst->data = g_list_sort_merge (src->data,
++ src->next->data,
++ compare_func);
++ dstprev = dst;
++ dst = dst->next;
++ src = src->next->next;
++ }
++
++ /* If number of runs was odd, just keep the last. */
++ if (src)
++ {
++ dst->data = src->data;
++ dstprev = dst;
++ dst = dst->next;
++ }
++
++ dstprev->next = NULL;
++ g_slist_free (dst);
++ }
++
++ /* After 1st loop: runs = [[2,4,11,12],[1,1,2,4,6,12]]. */
++ /* After 2nd loop: runs = [[1,1,2,2,4,4,6,11,12,12]]. */
++
++ list = runs->data;
++ g_slist_free (runs);
++ return list;
++}
+diff -urN linux-2.4.1/net/korbit/kglib/gmem.c linux-2.4.1-korbit/net/korbit/kglib/gmem.c
+--- linux-2.4.1/net/korbit/kglib/gmem.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/gmem.c Thu Feb 1 11:46:57 2001
+@@ -0,0 +1,767 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/*
++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS
++ * file for a list of people on the GLib Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GLib at ftp://ftp.gtk.org/pub/gtk/.
++ *
++ * Mutilated on 10/22/00 by Fredrik and Chris
++ */
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#include <stdlib.h>
++#include <string.h>
++#include "glib.h"
++
++#define MEM_PROFILE_TABLE_SIZE 8192
++#define ENTER_MEM_CHUNK_ROUTINE()
++#define LEAVE_MEM_CHUNK_ROUTINE()
++
++/*
++ * This library can check for some attempts to do illegal things to
++ * memory (ENABLE_MEM_CHECK), and can do profiling
++ * (ENABLE_MEM_PROFILE). Both features are implemented by storing
++ * words before the start of the memory chunk.
++ *
++ * The first, at offset -2*SIZEOF_LONG, is used only if
++ * ENABLE_MEM_CHECK is set, and stores 0 after the memory has been
++ * allocated and 1 when it has been freed. The second, at offset
++ * -SIZEOF_LONG, is used if either flag is set and stores the size of
++ * the block.
++ *
++ * The MEM_CHECK flag is checked when memory is realloc'd and free'd,
++ * and it can be explicitly checked before using a block by calling
++ * g_mem_check().
++ */
++
++#define MEM_AREA_SIZE 4L
++
++#define MEM_ALIGN sizeof(long)
++
++
++typedef struct _GFreeAtom GFreeAtom;
++typedef struct _GMemArea GMemArea;
++typedef struct _GRealMemChunk GRealMemChunk;
++
++struct _GFreeAtom
++{
++ GFreeAtom *next;
++};
++
++struct _GMemArea
++{
++ GMemArea *next; /* the next mem area */
++ GMemArea *prev; /* the previous mem area */
++ gulong index; /* the current index into the "mem" array */
++ gulong free; /* the number of free bytes in this mem area */
++ gulong allocated; /* the number of atoms allocated from this area */
++ gulong mark; /* is this mem area marked for deletion */
++ gchar mem[MEM_AREA_SIZE]; /* the mem array from which atoms get allocated
++ * the actual size of this array is determined by
++ * the mem chunk "area_size". ANSI says that it
++ * must be declared to be the maximum size it
++ * can possibly be (even though the actual size
++ * may be less).
++ */
++};
++
++struct _GRealMemChunk
++{
++ gchar *name; /* name of this MemChunk...used for debugging output */
++ gint type; /* the type of MemChunk: ALLOC_ONLY or ALLOC_AND_FREE */
++ gint num_mem_areas; /* the number of memory areas */
++ gint num_marked_areas; /* the number of areas marked for deletion */
++ guint atom_size; /* the size of an atom */
++ gulong area_size; /* the size of a memory area */
++ GMemArea *mem_area; /* the current memory area */
++ GMemArea *mem_areas; /* a list of all the mem areas owned by this chunk */
++ GMemArea *free_mem_area; /* the free area...which is about to be destroyed */
++ GFreeAtom *free_atoms; /* the free atoms list */
++ GTree *mem_tree; /* tree of mem areas sorted by memory address */
++ GRealMemChunk *next; /* pointer to the next chunk */
++ GRealMemChunk *prev; /* pointer to the previous chunk */
++};
++
++
++static gulong g_mem_chunk_compute_size (gulong size,
++ gulong min_size);
++static gint g_mem_chunk_area_compare (GMemArea *a,
++ GMemArea *b);
++static gint g_mem_chunk_area_search (GMemArea *a,
++ gchar *addr);
++
++
++/* here we can't use StaticMutexes, as they depend upon a working
++ * g_malloc, the same holds true for StaticPrivate */
++#ifndef __KORBIT__
++static GMutex* mem_chunks_lock = NULL;
++#endif /* !__KORBIT__ */
++static GRealMemChunk *mem_chunks = NULL;
++
++
++gpointer
++g_malloc (gulong size)
++{
++ gpointer p;
++
++ if (size == 0)
++ return NULL;
++
++ p = (gpointer) malloc (size);
++ if (!p)
++ g_error ("could not allocate %ld bytes", size);
++
++ return p;
++}
++
++gpointer
++g_malloc0 (gulong size)
++{
++ gpointer p;
++
++ if (size == 0)
++ return NULL;
++
++ p = (gpointer) calloc (size, 1);
++ if (!p)
++ g_error ("could not allocate %ld bytes", size);
++
++ return p;
++}
++
++gpointer
++g_realloc (gpointer mem,
++ gulong size)
++{
++ gpointer p;
++
++ if (size == 0)
++ {
++ g_free (mem);
++
++ return NULL;
++ }
++
++ if (!mem)
++ {
++#ifdef REALLOC_0_WORKS
++ p = (gpointer) realloc (NULL, size);
++#else /* !REALLOC_0_WORKS */
++ p = (gpointer) malloc (size);
++#endif /* !REALLOC_0_WORKS */
++ }
++ else
++ {
++ p = (gpointer) realloc (mem, size);
++ }
++
++ if (!p)
++ g_error ("could not reallocate %lu bytes", (gulong) size);
++
++ return p;
++}
++
++void
++g_free (gpointer mem)
++{
++ if (mem)
++ {
++ free (mem);
++ }
++}
++
++
++void
++g_mem_profile (void)
++{
++}
++
++void
++g_mem_check (gpointer mem)
++{
++}
++
++GMemChunk*
++g_mem_chunk_new (gchar *name,
++ gint atom_size,
++ gulong area_size,
++ gint type)
++{
++ GRealMemChunk *mem_chunk;
++ gulong rarea_size;
++
++ g_return_val_if_fail (atom_size > 0, NULL);
++ g_return_val_if_fail (area_size >= atom_size, NULL);
++
++ ENTER_MEM_CHUNK_ROUTINE();
++
++ area_size = (area_size + atom_size - 1) / atom_size;
++ area_size *= atom_size;
++
++ mem_chunk = g_new (struct _GRealMemChunk, 1);
++ mem_chunk->name = name;
++ mem_chunk->type = type;
++ mem_chunk->num_mem_areas = 0;
++ mem_chunk->num_marked_areas = 0;
++ mem_chunk->mem_area = NULL;
++ mem_chunk->free_mem_area = NULL;
++ mem_chunk->free_atoms = NULL;
++ mem_chunk->mem_tree = NULL;
++ mem_chunk->mem_areas = NULL;
++ mem_chunk->atom_size = atom_size;
++
++ if (mem_chunk->type == G_ALLOC_AND_FREE)
++ mem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare);
++
++ if (mem_chunk->atom_size % MEM_ALIGN)
++ mem_chunk->atom_size += MEM_ALIGN - (mem_chunk->atom_size % MEM_ALIGN);
++
++ rarea_size = area_size + sizeof (GMemArea) - MEM_AREA_SIZE;
++ rarea_size = g_mem_chunk_compute_size (rarea_size, atom_size + sizeof (GMemArea) - MEM_AREA_SIZE);
++ mem_chunk->area_size = rarea_size - (sizeof (GMemArea) - MEM_AREA_SIZE);
++
++#ifndef __KORBIT__
++ g_mutex_lock (mem_chunks_lock);
++#endif /* !__KORBIT__ */
++ mem_chunk->next = mem_chunks;
++ mem_chunk->prev = NULL;
++ if (mem_chunks)
++ mem_chunks->prev = mem_chunk;
++ mem_chunks = mem_chunk;
++#ifndef __KORBIT__
++ g_mutex_unlock (mem_chunks_lock);
++#endif /* !__KORBIT__ */
++
++ LEAVE_MEM_CHUNK_ROUTINE();
++
++ return ((GMemChunk*) mem_chunk);
++}
++
++void
++g_mem_chunk_destroy (GMemChunk *mem_chunk)
++{
++ GRealMemChunk *rmem_chunk;
++ GMemArea *mem_areas;
++ GMemArea *temp_area;
++
++ g_return_if_fail (mem_chunk != NULL);
++
++ ENTER_MEM_CHUNK_ROUTINE();
++
++ rmem_chunk = (GRealMemChunk*) mem_chunk;
++
++ mem_areas = rmem_chunk->mem_areas;
++ while (mem_areas)
++ {
++ temp_area = mem_areas;
++ mem_areas = mem_areas->next;
++ g_free (temp_area);
++ }
++
++ if (rmem_chunk->next)
++ rmem_chunk->next->prev = rmem_chunk->prev;
++ if (rmem_chunk->prev)
++ rmem_chunk->prev->next = rmem_chunk->next;
++
++#ifndef __KORBIT__
++ g_mutex_lock (mem_chunks_lock);
++#endif /* !__KORBIT__ */
++ if (rmem_chunk == mem_chunks)
++ mem_chunks = mem_chunks->next;
++#ifndef __KORBIT__
++ g_mutex_unlock (mem_chunks_lock);
++#endif /* !__KORBIT__ */
++
++ if (rmem_chunk->type == G_ALLOC_AND_FREE)
++ g_tree_destroy (rmem_chunk->mem_tree);
++
++ g_free (rmem_chunk);
++
++ LEAVE_MEM_CHUNK_ROUTINE();
++}
++
++gpointer
++g_mem_chunk_alloc (GMemChunk *mem_chunk)
++{
++ GRealMemChunk *rmem_chunk;
++ GMemArea *temp_area;
++ gpointer mem;
++
++ ENTER_MEM_CHUNK_ROUTINE();
++
++ g_return_val_if_fail (mem_chunk != NULL, NULL);
++
++ rmem_chunk = (GRealMemChunk*) mem_chunk;
++
++ while (rmem_chunk->free_atoms)
++ {
++ /* Get the first piece of memory on the "free_atoms" list.
++ * We can go ahead and destroy the list node we used to keep
++ * track of it with and to update the "free_atoms" list to
++ * point to its next element.
++ */
++ mem = rmem_chunk->free_atoms;
++ rmem_chunk->free_atoms = rmem_chunk->free_atoms->next;
++
++ /* Determine which area this piece of memory is allocated from */
++ temp_area = g_tree_search (rmem_chunk->mem_tree,
++ (GSearchFunc) g_mem_chunk_area_search,
++ mem);
++
++ /* If the area has been marked, then it is being destroyed.
++ * (ie marked to be destroyed).
++ * We check to see if all of the segments on the free list that
++ * reference this area have been removed. This occurs when
++ * the ammount of free memory is less than the allocatable size.
++ * If the chunk should be freed, then we place it in the "free_mem_area".
++ * This is so we make sure not to free the mem area here and then
++ * allocate it again a few lines down.
++ * If we don't allocate a chunk a few lines down then the "free_mem_area"
++ * will be freed.
++ * If there is already a "free_mem_area" then we'll just free this mem area.
++ */
++ if (temp_area->mark)
++ {
++ /* Update the "free" memory available in that area */
++ temp_area->free += rmem_chunk->atom_size;
++
++ if (temp_area->free == rmem_chunk->area_size)
++ {
++ if (temp_area == rmem_chunk->mem_area)
++ rmem_chunk->mem_area = NULL;
++
++ if (rmem_chunk->free_mem_area)
++ {
++ rmem_chunk->num_mem_areas -= 1;
++
++ if (temp_area->next)
++ temp_area->next->prev = temp_area->prev;
++ if (temp_area->prev)
++ temp_area->prev->next = temp_area->next;
++ if (temp_area == rmem_chunk->mem_areas)
++ rmem_chunk->mem_areas = rmem_chunk->mem_areas->next;
++
++ if (rmem_chunk->type == G_ALLOC_AND_FREE)
++ g_tree_remove (rmem_chunk->mem_tree, temp_area);
++ g_free (temp_area);
++ }
++ else
++ rmem_chunk->free_mem_area = temp_area;
++
++ rmem_chunk->num_marked_areas -= 1;
++ }
++ }
++ else
++ {
++ /* Update the number of allocated atoms count.
++ */
++ temp_area->allocated += 1;
++
++ /* The area wasn't marked...return the memory
++ */
++ goto outa_here;
++ }
++ }
++
++ /* If there isn't a current mem area or the current mem area is out of space
++ * then allocate a new mem area. We'll first check and see if we can use
++ * the "free_mem_area". Otherwise we'll just malloc the mem area.
++ */
++ if ((!rmem_chunk->mem_area) ||
++ ((rmem_chunk->mem_area->index + rmem_chunk->atom_size) > rmem_chunk->area_size))
++ {
++ if (rmem_chunk->free_mem_area)
++ {
++ rmem_chunk->mem_area = rmem_chunk->free_mem_area;
++ rmem_chunk->free_mem_area = NULL;
++ }
++ else
++ {
++ rmem_chunk->mem_area = (GMemArea*) g_malloc (sizeof (GMemArea) -
++ MEM_AREA_SIZE +
++ rmem_chunk->area_size);
++
++ rmem_chunk->num_mem_areas += 1;
++ rmem_chunk->mem_area->next = rmem_chunk->mem_areas;
++ rmem_chunk->mem_area->prev = NULL;
++
++ if (rmem_chunk->mem_areas)
++ rmem_chunk->mem_areas->prev = rmem_chunk->mem_area;
++ rmem_chunk->mem_areas = rmem_chunk->mem_area;
++
++ if (rmem_chunk->type == G_ALLOC_AND_FREE)
++ g_tree_insert (rmem_chunk->mem_tree, rmem_chunk->mem_area, rmem_chunk->mem_area);
++ }
++
++ rmem_chunk->mem_area->index = 0;
++ rmem_chunk->mem_area->free = rmem_chunk->area_size;
++ rmem_chunk->mem_area->allocated = 0;
++ rmem_chunk->mem_area->mark = 0;
++ }
++
++ /* Get the memory and modify the state variables appropriately.
++ */
++ mem = (gpointer) &rmem_chunk->mem_area->mem[rmem_chunk->mem_area->index];
++ rmem_chunk->mem_area->index += rmem_chunk->atom_size;
++ rmem_chunk->mem_area->free -= rmem_chunk->atom_size;
++ rmem_chunk->mem_area->allocated += 1;
++
++outa_here:
++
++ LEAVE_MEM_CHUNK_ROUTINE();
++
++ return mem;
++}
++
++gpointer
++g_mem_chunk_alloc0 (GMemChunk *mem_chunk)
++{
++ gpointer mem;
++
++ mem = g_mem_chunk_alloc (mem_chunk);
++ if (mem)
++ {
++ GRealMemChunk *rmem_chunk = (GRealMemChunk*) mem_chunk;
++
++ memset (mem, 0, rmem_chunk->atom_size);
++ }
++
++ return mem;
++}
++
++void
++g_mem_chunk_free (GMemChunk *mem_chunk,
++ gpointer mem)
++{
++ GRealMemChunk *rmem_chunk;
++ GMemArea *temp_area;
++ GFreeAtom *free_atom;
++
++ g_return_if_fail (mem_chunk != NULL);
++ g_return_if_fail (mem != NULL);
++
++ ENTER_MEM_CHUNK_ROUTINE();
++
++ rmem_chunk = (GRealMemChunk*) mem_chunk;
++
++ /* Don't do anything if this is an ALLOC_ONLY chunk
++ */
++ if (rmem_chunk->type == G_ALLOC_AND_FREE)
++ {
++ /* Place the memory on the "free_atoms" list
++ */
++ free_atom = (GFreeAtom*) mem;
++ free_atom->next = rmem_chunk->free_atoms;
++ rmem_chunk->free_atoms = free_atom;
++
++ temp_area = g_tree_search (rmem_chunk->mem_tree,
++ (GSearchFunc) g_mem_chunk_area_search,
++ mem);
++
++ temp_area->allocated -= 1;
++
++ if (temp_area->allocated == 0)
++ {
++ temp_area->mark = 1;
++ rmem_chunk->num_marked_areas += 1;
++ }
++ }
++
++ LEAVE_MEM_CHUNK_ROUTINE();
++}
++
++/* This doesn't free the free_area if there is one */
++void
++g_mem_chunk_clean (GMemChunk *mem_chunk)
++{
++ GRealMemChunk *rmem_chunk;
++ GMemArea *mem_area;
++ GFreeAtom *prev_free_atom;
++ GFreeAtom *temp_free_atom;
++ gpointer mem;
++
++ g_return_if_fail (mem_chunk != NULL);
++
++ rmem_chunk = (GRealMemChunk*) mem_chunk;
++
++ if (rmem_chunk->type == G_ALLOC_AND_FREE)
++ {
++ prev_free_atom = NULL;
++ temp_free_atom = rmem_chunk->free_atoms;
++
++ while (temp_free_atom)
++ {
++ mem = (gpointer) temp_free_atom;
++
++ mem_area = g_tree_search (rmem_chunk->mem_tree,
++ (GSearchFunc) g_mem_chunk_area_search,
++ mem);
++
++ /* If this mem area is marked for destruction then delete the
++ * area and list node and decrement the free mem.
++ */
++ if (mem_area->mark)
++ {
++ if (prev_free_atom)
++ prev_free_atom->next = temp_free_atom->next;
++ else
++ rmem_chunk->free_atoms = temp_free_atom->next;
++ temp_free_atom = temp_free_atom->next;
++
++ mem_area->free += rmem_chunk->atom_size;
++ if (mem_area->free == rmem_chunk->area_size)
++ {
++ rmem_chunk->num_mem_areas -= 1;
++ rmem_chunk->num_marked_areas -= 1;
++
++ if (mem_area->next)
++ mem_area->next->prev = mem_area->prev;
++ if (mem_area->prev)
++ mem_area->prev->next = mem_area->next;
++ if (mem_area == rmem_chunk->mem_areas)
++ rmem_chunk->mem_areas = rmem_chunk->mem_areas->next;
++ if (mem_area == rmem_chunk->mem_area)
++ rmem_chunk->mem_area = NULL;
++
++ if (rmem_chunk->type == G_ALLOC_AND_FREE)
++ g_tree_remove (rmem_chunk->mem_tree, mem_area);
++ g_free (mem_area);
++ }
++ }
++ else
++ {
++ prev_free_atom = temp_free_atom;
++ temp_free_atom = temp_free_atom->next;
++ }
++ }
++ }
++}
++
++void
++g_mem_chunk_reset (GMemChunk *mem_chunk)
++{
++ GRealMemChunk *rmem_chunk;
++ GMemArea *mem_areas;
++ GMemArea *temp_area;
++
++ g_return_if_fail (mem_chunk != NULL);
++
++ rmem_chunk = (GRealMemChunk*) mem_chunk;
++
++ mem_areas = rmem_chunk->mem_areas;
++ rmem_chunk->num_mem_areas = 0;
++ rmem_chunk->mem_areas = NULL;
++ rmem_chunk->mem_area = NULL;
++
++ while (mem_areas)
++ {
++ temp_area = mem_areas;
++ mem_areas = mem_areas->next;
++ g_free (temp_area);
++ }
++
++ rmem_chunk->free_atoms = NULL;
++
++ if (rmem_chunk->mem_tree)
++ g_tree_destroy (rmem_chunk->mem_tree);
++ rmem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare);
++}
++
++void
++g_mem_chunk_print (GMemChunk *mem_chunk)
++{
++ GRealMemChunk *rmem_chunk;
++ GMemArea *mem_areas;
++ gulong mem;
++
++ g_return_if_fail (mem_chunk != NULL);
++
++ rmem_chunk = (GRealMemChunk*) mem_chunk;
++ mem_areas = rmem_chunk->mem_areas;
++ mem = 0;
++
++ while (mem_areas)
++ {
++ mem += rmem_chunk->area_size - mem_areas->free;
++ mem_areas = mem_areas->next;
++ }
++
++ g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
++ "%s: %ld bytes using %d mem areas",
++ rmem_chunk->name, mem, rmem_chunk->num_mem_areas);
++}
++
++void
++g_mem_chunk_info (void)
++{
++ GRealMemChunk *mem_chunk;
++ gint count;
++
++ count = 0;
++#ifndef __KORBIT__
++ g_mutex_lock (mem_chunks_lock);
++#endif /* !__KORBIT__ */
++ mem_chunk = mem_chunks;
++ while (mem_chunk)
++ {
++ count += 1;
++ mem_chunk = mem_chunk->next;
++ }
++#ifndef __KORBIT__
++ g_mutex_unlock (mem_chunks_lock);
++#endif /* !__KORBIT__ */
++ g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%d mem chunks", count);
++
++#ifndef __KORBIT__
++ g_mutex_lock (mem_chunks_lock);
++#endif /* !__KORBIT__ */
++ mem_chunk = mem_chunks;
++#ifndef __KORBIT__
++ g_mutex_unlock (mem_chunks_lock);
++#endif /* !__KORBIT__ */
++
++ while (mem_chunk)
++ {
++ g_mem_chunk_print ((GMemChunk*) mem_chunk);
++ mem_chunk = mem_chunk->next;
++ }
++}
++
++void
++g_blow_chunks (void)
++{
++ GRealMemChunk *mem_chunk;
++
++#ifndef __KORBIT__
++ g_mutex_lock (mem_chunks_lock);
++#endif /* !__KORBIT__ */
++ mem_chunk = mem_chunks;
++#ifndef __KORBIT__
++ g_mutex_unlock (mem_chunks_lock);
++#endif /* !__KORBIT__ */
++ while (mem_chunk)
++ {
++ g_mem_chunk_clean ((GMemChunk*) mem_chunk);
++ mem_chunk = mem_chunk->next;
++ }
++}
++
++
++static gulong
++g_mem_chunk_compute_size (gulong size,
++ gulong min_size)
++{
++ gulong power_of_2;
++ gulong lower, upper;
++
++ power_of_2 = 16;
++ while (power_of_2 < size)
++ power_of_2 <<= 1;
++
++ lower = power_of_2 >> 1;
++ upper = power_of_2;
++
++ if (size - lower < upper - size && lower >= min_size)
++ return lower;
++ else
++ return upper;
++}
++
++static gint
++g_mem_chunk_area_compare (GMemArea *a,
++ GMemArea *b)
++{
++ if (a->mem > b->mem)
++ return 1;
++ else if (a->mem < b->mem)
++ return -1;
++ return 0;
++}
++
++static gint
++g_mem_chunk_area_search (GMemArea *a,
++ gchar *addr)
++{
++ if (a->mem <= addr)
++ {
++ if (addr < &a->mem[a->index])
++ return 0;
++ return 1;
++ }
++ return -1;
++}
++
++/* generic allocators
++ */
++struct _GAllocator /* from gmem.c */
++{
++ gchar *name;
++ guint16 n_preallocs;
++ guint is_unused : 1;
++ guint type : 4;
++ GAllocator *last;
++ GMemChunk *mem_chunk;
++ gpointer dummy; /* implementation specific */
++};
++
++GAllocator*
++g_allocator_new (const gchar *name,
++ guint n_preallocs)
++{
++ GAllocator *allocator;
++
++ g_return_val_if_fail (name != NULL, NULL);
++
++ allocator = g_new0 (GAllocator, 1);
++ allocator->name = g_strdup (name);
++ allocator->n_preallocs = CLAMP (n_preallocs, 1, 65535);
++ allocator->is_unused = TRUE;
++ allocator->type = 0;
++ allocator->last = NULL;
++ allocator->mem_chunk = NULL;
++ allocator->dummy = NULL;
++
++ return allocator;
++}
++
++void
++g_allocator_free (GAllocator *allocator)
++{
++ g_return_if_fail (allocator != NULL);
++ g_return_if_fail (allocator->is_unused == TRUE);
++
++ g_free (allocator->name);
++ if (allocator->mem_chunk)
++ g_mem_chunk_destroy (allocator->mem_chunk);
++
++ g_free (allocator);
++}
++
++void
++g_mem_init (void)
++{
++#ifndef __KORBIT__
++ mem_chunks_lock = g_mutex_new();
++#endif /* !__KORBIT__ */
++}
+diff -urN linux-2.4.1/net/korbit/kglib/gprimes.c linux-2.4.1-korbit/net/korbit/kglib/gprimes.c
+--- linux-2.4.1/net/korbit/kglib/gprimes.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/gprimes.c Thu Feb 1 11:46:57 2001
+@@ -0,0 +1,79 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/*
++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS
++ * file for a list of people on the GLib Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GLib at ftp://ftp.gtk.org/pub/gtk/.
++ */
++
++#include "glib.h"
++
++static const guint g_primes[] =
++{
++ 11,
++ 19,
++ 37,
++ 73,
++ 109,
++ 163,
++ 251,
++ 367,
++ 557,
++ 823,
++ 1237,
++ 1861,
++ 2777,
++ 4177,
++ 6247,
++ 9371,
++ 14057,
++ 21089,
++ 31627,
++ 47431,
++ 71143,
++ 106721,
++ 160073,
++ 240101,
++ 360163,
++ 540217,
++ 810343,
++ 1215497,
++ 1823231,
++ 2734867,
++ 4102283,
++ 6153409,
++ 9230113,
++ 13845163,
++};
++
++static const guint g_nprimes = sizeof (g_primes) / sizeof (g_primes[0]);
++
++guint
++g_spaced_primes_closest (guint num)
++{
++ gint i;
++
++ for (i = 0; i < g_nprimes; i++)
++ if (g_primes[i] > num)
++ return g_primes[i];
++
++ return g_primes[g_nprimes - 1];
++}
+diff -urN linux-2.4.1/net/korbit/kglib/gslist.c linux-2.4.1-korbit/net/korbit/kglib/gslist.c
+--- linux-2.4.1/net/korbit/kglib/gslist.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/gslist.c Thu Feb 1 11:46:57 2001
+@@ -0,0 +1,591 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/*
++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS
++ * file for a list of people on the GLib Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GLib at ftp://ftp.gtk.org/pub/gtk/.
++ */
++
++#include "glib.h"
++
++
++struct _GAllocator /* from gmem.c */
++{
++ gchar *name;
++ guint16 n_preallocs;
++ guint is_unused : 1;
++ guint type : 4;
++ GAllocator *last;
++ GMemChunk *mem_chunk;
++ GSList *free_lists; /* implementation specific */
++};
++
++G_LOCK_DEFINE_STATIC (current_allocator);
++static GAllocator *current_allocator = NULL;
++
++/* HOLDS: current_allocator_lock */
++static void
++g_slist_validate_allocator (GAllocator *allocator)
++{
++ g_return_if_fail (allocator != NULL);
++ g_return_if_fail (allocator->is_unused == TRUE);
++
++ if (allocator->type != G_ALLOCATOR_SLIST)
++ {
++ allocator->type = G_ALLOCATOR_SLIST;
++ if (allocator->mem_chunk)
++ {
++ g_mem_chunk_destroy (allocator->mem_chunk);
++ allocator->mem_chunk = NULL;
++ }
++ }
++
++ if (!allocator->mem_chunk)
++ {
++ allocator->mem_chunk = g_mem_chunk_new (allocator->name,
++ sizeof (GSList),
++ sizeof (GSList) * allocator->n_preallocs,
++ G_ALLOC_ONLY);
++ allocator->free_lists = NULL;
++ }
++
++ allocator->is_unused = FALSE;
++}
++
++void
++g_slist_push_allocator (GAllocator *allocator)
++{
++ G_LOCK (current_allocator);
++ g_slist_validate_allocator (allocator);
++ allocator->last = current_allocator;
++ current_allocator = allocator;
++ G_UNLOCK (current_allocator);
++}
++
++void
++g_slist_pop_allocator (void)
++{
++ G_LOCK (current_allocator);
++ if (current_allocator)
++ {
++ GAllocator *allocator;
++
++ allocator = current_allocator;
++ current_allocator = allocator->last;
++ allocator->last = NULL;
++ allocator->is_unused = TRUE;
++ }
++ G_UNLOCK (current_allocator);
++}
++
++GSList*
++g_slist_alloc (void)
++{
++ GSList *list;
++
++ G_LOCK (current_allocator);
++ if (!current_allocator)
++ {
++ GAllocator *allocator = g_allocator_new ("GLib default GSList allocator",
++ 128);
++ g_slist_validate_allocator (allocator);
++ allocator->last = NULL;
++ current_allocator = allocator;
++ }
++ if (!current_allocator->free_lists)
++ {
++ list = g_chunk_new (GSList, current_allocator->mem_chunk);
++ list->data = NULL;
++ }
++ else
++ {
++ if (current_allocator->free_lists->data)
++ {
++ list = current_allocator->free_lists->data;
++ current_allocator->free_lists->data = list->next;
++ list->data = NULL;
++ }
++ else
++ {
++ list = current_allocator->free_lists;
++ current_allocator->free_lists = list->next;
++ }
++ }
++ G_UNLOCK (current_allocator);
++
++ list->next = NULL;
++
++ return list;
++}
++
++void
++g_slist_free (GSList *list)
++{
++ if (list)
++ {
++ list->data = list->next;
++ G_LOCK (current_allocator);
++ list->next = current_allocator->free_lists;
++ current_allocator->free_lists = list;
++ G_UNLOCK (current_allocator);
++ }
++}
++
++void
++g_slist_free_1 (GSList *list)
++{
++ if (list)
++ {
++ list->data = NULL;
++ G_LOCK (current_allocator);
++ list->next = current_allocator->free_lists;
++ current_allocator->free_lists = list;
++ G_UNLOCK (current_allocator);
++ }
++}
++
++GSList*
++g_slist_append (GSList *list,
++ gpointer data)
++{
++ GSList *new_list;
++ GSList *last;
++
++ new_list = g_slist_alloc ();
++ new_list->data = data;
++
++ if (list)
++ {
++ last = g_slist_last (list);
++ /* g_assert (last != NULL); */
++ last->next = new_list;
++
++ return list;
++ }
++ else
++ return new_list;
++}
++
++GSList*
++g_slist_prepend (GSList *list,
++ gpointer data)
++{
++ GSList *new_list;
++
++ new_list = g_slist_alloc ();
++ new_list->data = data;
++ new_list->next = list;
++
++ return new_list;
++}
++
++GSList*
++g_slist_insert (GSList *list,
++ gpointer data,
++ gint position)
++{
++ GSList *prev_list;
++ GSList *tmp_list;
++ GSList *new_list;
++
++ if (position < 0)
++ return g_slist_append (list, data);
++ else if (position == 0)
++ return g_slist_prepend (list, data);
++
++ new_list = g_slist_alloc ();
++ new_list->data = data;
++
++ if (!list)
++ return new_list;
++
++ prev_list = NULL;
++ tmp_list = list;
++
++ while ((position-- > 0) && tmp_list)
++ {
++ prev_list = tmp_list;
++ tmp_list = tmp_list->next;
++ }
++
++ if (prev_list)
++ {
++ new_list->next = prev_list->next;
++ prev_list->next = new_list;
++ }
++ else
++ {
++ new_list->next = list;
++ list = new_list;
++ }
++
++ return list;
++}
++
++GSList *
++g_slist_concat (GSList *list1, GSList *list2)
++{
++ if (list2)
++ {
++ if (list1)
++ g_slist_last (list1)->next = list2;
++ else
++ list1 = list2;
++ }
++
++ return list1;
++}
++
++GSList*
++g_slist_remove (GSList *list,
++ gpointer data)
++{
++ GSList *tmp;
++ GSList *prev;
++
++ prev = NULL;
++ tmp = list;
++
++ while (tmp)
++ {
++ if (tmp->data == data)
++ {
++ if (prev)
++ prev->next = tmp->next;
++ if (list == tmp)
++ list = list->next;
++
++ tmp->next = NULL;
++ g_slist_free (tmp);
++
++ break;
++ }
++
++ prev = tmp;
++ tmp = tmp->next;
++ }
++
++ return list;
++}
++
++GSList*
++g_slist_remove_link (GSList *list,
++ GSList *link)
++{
++ GSList *tmp;
++ GSList *prev;
++
++ prev = NULL;
++ tmp = list;
++
++ while (tmp)
++ {
++ if (tmp == link)
++ {
++ if (prev)
++ prev->next = tmp->next;
++ if (list == tmp)
++ list = list->next;
++
++ tmp->next = NULL;
++ break;
++ }
++
++ prev = tmp;
++ tmp = tmp->next;
++ }
++
++ return list;
++}
++
++GSList*
++g_slist_copy (GSList *list)
++{
++ GSList *new_list = NULL;
++
++ if (list)
++ {
++ GSList *last;
++
++ new_list = g_slist_alloc ();
++ new_list->data = list->data;
++ last = new_list;
++ list = list->next;
++ while (list)
++ {
++ last->next = g_slist_alloc ();
++ last = last->next;
++ last->data = list->data;
++ list = list->next;
++ }
++ }
++
++ return new_list;
++}
++
++GSList*
++g_slist_reverse (GSList *list)
++{
++ GSList *prev = NULL;
++
++ while (list)
++ {
++ GSList *next = list->next;
++
++ list->next = prev;
++
++ prev = list;
++ list = next;
++ }
++
++ return prev;
++}
++
++GSList*
++g_slist_nth (GSList *list,
++ guint n)
++{
++ while ((n-- > 0) && list)
++ list = list->next;
++
++ return list;
++}
++
++gpointer
++g_slist_nth_data (GSList *list,
++ guint n)
++{
++ while ((n-- > 0) && list)
++ list = list->next;
++
++ return list ? list->data : NULL;
++}
++
++GSList*
++g_slist_find (GSList *list,
++ gpointer data)
++{
++ while (list)
++ {
++ if (list->data == data)
++ break;
++ list = list->next;
++ }
++
++ return list;
++}
++
++GSList*
++g_slist_find_custom (GSList *list,
++ gpointer data,
++ GCompareFunc func)
++{
++ g_return_val_if_fail (func != NULL, list);
++
++ while (list)
++ {
++ if (! func (list->data, data))
++ return list;
++ list = list->next;
++ }
++
++ return NULL;
++}
++
++gint
++g_slist_position (GSList *list,
++ GSList *link)
++{
++ gint i;
++
++ i = 0;
++ while (list)
++ {
++ if (list == link)
++ return i;
++ i++;
++ list = list->next;
++ }
++
++ return -1;
++}
++
++gint
++g_slist_index (GSList *list,
++ gpointer data)
++{
++ gint i;
++
++ i = 0;
++ while (list)
++ {
++ if (list->data == data)
++ return i;
++ i++;
++ list = list->next;
++ }
++
++ return -1;
++}
++
++GSList*
++g_slist_last (GSList *list)
++{
++ if (list)
++ {
++ while (list->next)
++ list = list->next;
++ }
++
++ return list;
++}
++
++guint
++g_slist_length (GSList *list)
++{
++ guint length;
++
++ length = 0;
++ while (list)
++ {
++ length++;
++ list = list->next;
++ }
++
++ return length;
++}
++
++void
++g_slist_foreach (GSList *list,
++ GFunc func,
++ gpointer user_data)
++{
++ while (list)
++ {
++ (*func) (list->data, user_data);
++ list = list->next;
++ }
++}
++
++GSList*
++g_slist_insert_sorted (GSList *list,
++ gpointer data,
++ GCompareFunc func)
++{
++ GSList *tmp_list = list;
++ GSList *prev_list = NULL;
++ GSList *new_list;
++ gint cmp;
++
++ g_return_val_if_fail (func != NULL, list);
++
++ if (!list)
++ {
++ new_list = g_slist_alloc();
++ new_list->data = data;
++ return new_list;
++ }
++
++ cmp = (*func) (data, tmp_list->data);
++
++ while ((tmp_list->next) && (cmp > 0))
++ {
++ prev_list = tmp_list;
++ tmp_list = tmp_list->next;
++ cmp = (*func) (data, tmp_list->data);
++ }
++
++ new_list = g_slist_alloc();
++ new_list->data = data;
++
++ if ((!tmp_list->next) && (cmp > 0))
++ {
++ tmp_list->next = new_list;
++ return list;
++ }
++
++ if (prev_list)
++ {
++ prev_list->next = new_list;
++ new_list->next = tmp_list;
++ return list;
++ }
++ else
++ {
++ new_list->next = list;
++ return new_list;
++ }
++}
++
++static GSList*
++g_slist_sort_merge (GSList *l1,
++ GSList *l2,
++ GCompareFunc compare_func)
++{
++ GSList list, *l;
++
++ l=&list;
++
++ while (l1 && l2)
++ {
++ if (compare_func(l1->data,l2->data) < 0)
++ {
++ l=l->next=l1;
++ l1=l1->next;
++ }
++ else
++ {
++ l=l->next=l2;
++ l2=l2->next;
++ }
++ }
++ l->next= l1 ? l1 : l2;
++
++ return list.next;
++}
++
++GSList*
++g_slist_sort (GSList *list,
++ GCompareFunc compare_func)
++{
++ GSList *l1, *l2;
++
++ if (!list)
++ return NULL;
++ if (!list->next)
++ return list;
++
++ l1 = list;
++ l2 = list->next;
++
++ while ((l2 = l2->next) != NULL)
++ {
++ if ((l2 = l2->next) == NULL)
++ break;
++ l1=l1->next;
++ }
++ l2 = l1->next;
++ l1->next = NULL;
++
++ return g_slist_sort_merge (g_slist_sort (list, compare_func),
++ g_slist_sort (l2, compare_func),
++ compare_func);
++}
+diff -urN linux-2.4.1/net/korbit/kglib/gstrfuncs.c linux-2.4.1-korbit/net/korbit/kglib/gstrfuncs.c
+--- linux-2.4.1/net/korbit/kglib/gstrfuncs.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/gstrfuncs.c Thu Feb 1 11:46:57 2001
+@@ -0,0 +1,1308 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/*
++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS
++ * file for a list of people on the GLib Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GLib at ftp://ftp.gtk.org/pub/gtk/.
++ */
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#include <stdarg.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <locale.h>
++#include <ctype.h> /* For tolower() */
++#if !defined (HAVE_STRSIGNAL) || !defined(NO_SYS_SIGLIST_DECL)
++#include <signal.h>
++#endif
++#include "glib.h"
++/* do not include <unistd.h> in this place since it
++ * inteferes with g_strsignal() on some OSes
++ */
++
++gchar*
++g_strdup (const gchar *str) {
++ gchar *new_str;
++
++ if (str)
++ {
++ new_str = g_new (char, strlen (str) + 1);
++ strcpy (new_str, str);
++ }
++ else
++ new_str = NULL;
++
++ return new_str;
++}
++
++gpointer
++g_memdup (gconstpointer mem,
++ guint byte_size)
++{
++ gpointer new_mem;
++
++ if (mem)
++ {
++ new_mem = g_malloc (byte_size);
++ memcpy (new_mem, mem, byte_size);
++ }
++ else
++ new_mem = NULL;
++
++ return new_mem;
++}
++
++gchar*
++g_strndup (const gchar *str,
++ guint n)
++{
++ gchar *new_str;
++
++ if (str)
++ {
++ new_str = g_new (gchar, n + 1);
++ strncpy (new_str, str, n);
++ new_str[n] = '\0';
++ }
++ else
++ new_str = NULL;
++
++ return new_str;
++}
++
++gchar*
++g_strnfill (guint length,
++ gchar fill_char)
++{
++ register gchar *str, *s, *end;
++
++ str = g_new (gchar, length + 1);
++ s = str;
++ end = str + length;
++ while (s < end)
++ *(s++) = fill_char;
++ *s = 0;
++
++ return str;
++}
++
++gchar*
++g_strdup_vprintf (const gchar *format,
++ va_list args1)
++{
++ gchar *buffer;
++ va_list args2;
++
++ G_VA_COPY (args2, args1);
++
++ buffer = g_new (gchar, g_printf_string_upper_bound (format, args1));
++
++ vsprintf (buffer, format, args2);
++ va_end (args2);
++
++ return buffer;
++}
++
++gchar*
++g_strdup_printf (const gchar *format,
++ ...)
++{
++ gchar *buffer;
++ va_list args;
++
++ va_start (args, format);
++ buffer = g_strdup_vprintf (format, args);
++ va_end (args);
++
++ return buffer;
++}
++
++gchar*
++g_strconcat (const gchar *string1, ...)
++{
++ guint l;
++ va_list args;
++ gchar *s;
++ gchar *concat;
++
++ g_return_val_if_fail (string1 != NULL, NULL);
++
++ l = 1 + strlen (string1);
++ va_start (args, string1);
++ s = va_arg (args, gchar*);
++ while (s)
++ {
++ l += strlen (s);
++ s = va_arg (args, gchar*);
++ }
++ va_end (args);
++
++ concat = g_new (gchar, l);
++ concat[0] = 0;
++
++ strcat (concat, string1);
++ va_start (args, string1);
++ s = va_arg (args, gchar*);
++ while (s)
++ {
++ strcat (concat, s);
++ s = va_arg (args, gchar*);
++ }
++ va_end (args);
++
++ return concat;
++}
++
++#ifndef __KORBIT__
++gdouble
++g_strtod (const gchar *nptr,
++ gchar **endptr)
++{
++ gchar *fail_pos_1;
++ gchar *fail_pos_2;
++ gdouble val_1;
++ gdouble val_2 = 0;
++
++ g_return_val_if_fail (nptr != NULL, 0);
++
++ fail_pos_1 = NULL;
++ fail_pos_2 = NULL;
++
++ val_1 = strtod (nptr, &fail_pos_1);
++
++ if (fail_pos_1 && fail_pos_1[0] != 0)
++ {
++ gchar *old_locale;
++
++ old_locale = g_strdup (setlocale (LC_NUMERIC, NULL));
++ setlocale (LC_NUMERIC, "C");
++ val_2 = strtod (nptr, &fail_pos_2);
++ setlocale (LC_NUMERIC, old_locale);
++ g_free (old_locale);
++ }
++
++ if (!fail_pos_1 || fail_pos_1[0] == 0 || fail_pos_1 >= fail_pos_2)
++ {
++ if (endptr)
++ *endptr = fail_pos_1;
++ return val_1;
++ }
++ else
++ {
++ if (endptr)
++ *endptr = fail_pos_2;
++ return val_2;
++ }
++}
++#endif /* !__KORBIT__ */
++
++gchar*
++g_strerror (gint errnum)
++{
++#ifndef __KORBIT__
++ static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT;
++ char *msg;
++#endif
++
++#ifdef __KORBIT__
++#undef HAVE_STRERROR
++#define NO_SYS_ERRLIST 1
++#endif
++
++#if defined(HAVE_STRERROR)
++ return strerror (errnum);
++#elif NO_SYS_ERRLIST
++ switch (errnum)
++ {
++#ifdef E2BIG
++ case E2BIG: return "argument list too long";
++#endif
++#ifdef EACCES
++ case EACCES: return "permission denied";
++#endif
++#ifdef EADDRINUSE
++ case EADDRINUSE: return "address already in use";
++#endif
++#ifdef EADDRNOTAVAIL
++ case EADDRNOTAVAIL: return "can't assign requested address";
++#endif
++#ifdef EADV
++ case EADV: return "advertise error";
++#endif
++#ifdef EAFNOSUPPORT
++ case EAFNOSUPPORT: return "address family not supported by protocol family";
++#endif
++#ifdef EAGAIN
++ case EAGAIN: return "try again";
++#endif
++#ifdef EALIGN
++ case EALIGN: return "EALIGN";
++#endif
++#ifdef EALREADY
++ case EALREADY: return "operation already in progress";
++#endif
++#ifdef EBADE
++ case EBADE: return "bad exchange descriptor";
++#endif
++#ifdef EBADF
++ case EBADF: return "bad file number";
++#endif
++#ifdef EBADFD
++ case EBADFD: return "file descriptor in bad state";
++#endif
++#ifdef EBADMSG
++ case EBADMSG: return "not a data message";
++#endif
++#ifdef EBADR
++ case EBADR: return "bad request descriptor";
++#endif
++#ifdef EBADRPC
++ case EBADRPC: return "RPC structure is bad";
++#endif
++#ifdef EBADRQC
++ case EBADRQC: return "bad request code";
++#endif
++#ifdef EBADSLT
++ case EBADSLT: return "invalid slot";
++#endif
++#ifdef EBFONT
++ case EBFONT: return "bad font file format";
++#endif
++#ifdef EBUSY
++ case EBUSY: return "mount device busy";
++#endif
++#ifdef ECHILD
++ case ECHILD: return "no children";
++#endif
++#ifdef ECHRNG
++ case ECHRNG: return "channel number out of range";
++#endif
++#ifdef ECOMM
++ case ECOMM: return "communication error on send";
++#endif
++#ifdef ECONNABORTED
++ case ECONNABORTED: return "software caused connection abort";
++#endif
++#ifdef ECONNREFUSED
++ case ECONNREFUSED: return "connection refused";
++#endif
++#ifdef ECONNRESET
++ case ECONNRESET: return "connection reset by peer";
++#endif
++#if defined(EDEADLK) && (!defined(EWOULDBLOCK) || (EDEADLK != EWOULDBLOCK)) && (!defined(EDEADLOCK) || (EDEADLK != EDEADLOCK))
++ case EDEADLK: return "resource deadlock avoided";
++#endif
++#ifdef EDEADLOCK
++ case EDEADLOCK: return "resource deadlock avoided";
++#endif
++#ifdef EDESTADDRREQ
++ case EDESTADDRREQ: return "destination address required";
++#endif
++#ifdef EDIRTY
++ case EDIRTY: return "mounting a dirty fs w/o force";
++#endif
++#ifdef EDOM
++ case EDOM: return "math argument out of range";
++#endif
++#ifdef EDOTDOT
++ case EDOTDOT: return "cross mount point";
++#endif
++#ifdef EDQUOT
++ case EDQUOT: return "disk quota exceeded";
++#endif
++#ifdef EDUPPKG
++ case EDUPPKG: return "duplicate package name";
++#endif
++#ifdef EEXIST
++ case EEXIST: return "file already exists";
++#endif
++#ifdef EFAULT
++ case EFAULT: return "bad address in system call argument";
++#endif
++#ifdef EFBIG
++ case EFBIG: return "file too large";
++#endif
++#ifdef EHOSTDOWN
++ case EHOSTDOWN: return "host is down";
++#endif
++#ifdef EHOSTUNREACH
++ case EHOSTUNREACH: return "host is unreachable";
++#endif
++#ifdef EIDRM
++ case EIDRM: return "identifier removed";
++#endif
++#ifdef EINIT
++ case EINIT: return "initialization error";
++#endif
++#ifdef EINPROGRESS
++ case EINPROGRESS: return "operation now in progress";
++#endif
++#ifdef EINTR
++ case EINTR: return "interrupted system call";
++#endif
++#ifdef EINVAL
++ case EINVAL: return "invalid argument";
++#endif
++#ifdef EIO
++ case EIO: return "I/O error";
++#endif
++#ifdef EISCONN
++ case EISCONN: return "socket is already connected";
++#endif
++#ifdef EISDIR
++ case EISDIR: return "illegal operation on a directory";
++#endif
++#ifdef EISNAME
++ case EISNAM: return "is a name file";
++#endif
++#ifdef ELBIN
++ case ELBIN: return "ELBIN";
++#endif
++#ifdef EL2HLT
++ case EL2HLT: return "level 2 halted";
++#endif
++#ifdef EL2NSYNC
++ case EL2NSYNC: return "level 2 not synchronized";
++#endif
++#ifdef EL3HLT
++ case EL3HLT: return "level 3 halted";
++#endif
++#ifdef EL3RST
++ case EL3RST: return "level 3 reset";
++#endif
++#ifdef ELIBACC
++ case ELIBACC: return "can not access a needed shared library";
++#endif
++#ifdef ELIBBAD
++ case ELIBBAD: return "accessing a corrupted shared library";
++#endif
++#ifdef ELIBEXEC
++ case ELIBEXEC: return "can not exec a shared library directly";
++#endif
++#ifdef ELIBMAX
++ case ELIBMAX: return "attempting to link in more shared libraries than system limit";
++#endif
++#ifdef ELIBSCN
++ case ELIBSCN: return ".lib section in a.out corrupted";
++#endif
++#ifdef ELNRNG
++ case ELNRNG: return "link number out of range";
++#endif
++#ifdef ELOOP
++ case ELOOP: return "too many levels of symbolic links";
++#endif
++#ifdef EMFILE
++ case EMFILE: return "too many open files";
++#endif
++#ifdef EMLINK
++ case EMLINK: return "too many links";
++#endif
++#ifdef EMSGSIZE
++ case EMSGSIZE: return "message too long";
++#endif
++#ifdef EMULTIHOP
++ case EMULTIHOP: return "multihop attempted";
++#endif
++#ifdef ENAMETOOLONG
++ case ENAMETOOLONG: return "file name too long";
++#endif
++#ifdef ENAVAIL
++ case ENAVAIL: return "not available";
++#endif
++#ifdef ENET
++ case ENET: return "ENET";
++#endif
++#ifdef ENETDOWN
++ case ENETDOWN: return "network is down";
++#endif
++#ifdef ENETRESET
++ case ENETRESET: return "network dropped connection on reset";
++#endif
++#ifdef ENETUNREACH
++ case ENETUNREACH: return "network is unreachable";
++#endif
++#ifdef ENFILE
++ case ENFILE: return "file table overflow";
++#endif
++#ifdef ENOANO
++ case ENOANO: return "anode table overflow";
++#endif
++#if defined(ENOBUFS) && (!defined(ENOSR) || (ENOBUFS != ENOSR))
++ case ENOBUFS: return "no buffer space available";
++#endif
++#ifdef ENOCSI
++ case ENOCSI: return "no CSI structure available";
++#endif
++#ifdef ENODATA
++ case ENODATA: return "no data available";
++#endif
++#ifdef ENODEV
++ case ENODEV: return "no such device";
++#endif
++#ifdef ENOENT
++ case ENOENT: return "no such file or directory";
++#endif
++#ifdef ENOEXEC
++ case ENOEXEC: return "exec format error";
++#endif
++#ifdef ENOLCK
++ case ENOLCK: return "no locks available";
++#endif
++#ifdef ENOLINK
++ case ENOLINK: return "link has be severed";
++#endif
++#ifdef ENOMEM
++ case ENOMEM: return "not enough memory";
++#endif
++#ifdef ENOMSG
++ case ENOMSG: return "no message of desired type";
++#endif
++#ifdef ENONET
++ case ENONET: return "machine is not on the network";
++#endif
++#ifdef ENOPKG
++ case ENOPKG: return "package not installed";
++#endif
++#ifdef ENOPROTOOPT
++ case ENOPROTOOPT: return "bad proocol option";
++#endif
++#ifdef ENOSPC
++ case ENOSPC: return "no space left on device";
++#endif
++#ifdef ENOSR
++ case ENOSR: return "out of stream resources";
++#endif
++#ifdef ENOSTR
++ case ENOSTR: return "not a stream device";
++#endif
++#ifdef ENOSYM
++ case ENOSYM: return "unresolved symbol name";
++#endif
++#ifdef ENOSYS
++ case ENOSYS: return "function not implemented";
++#endif
++#ifdef ENOTBLK
++ case ENOTBLK: return "block device required";
++#endif
++#ifdef ENOTCONN
++ case ENOTCONN: return "socket is not connected";
++#endif
++#ifdef ENOTDIR
++ case ENOTDIR: return "not a directory";
++#endif
++#ifdef ENOTEMPTY
++ case ENOTEMPTY: return "directory not empty";
++#endif
++#ifdef ENOTNAM
++ case ENOTNAM: return "not a name file";
++#endif
++#ifdef ENOTSOCK
++ case ENOTSOCK: return "socket operation on non-socket";
++#endif
++#ifdef ENOTTY
++ case ENOTTY: return "inappropriate device for ioctl";
++#endif
++#ifdef ENOTUNIQ
++ case ENOTUNIQ: return "name not unique on network";
++#endif
++#ifdef ENXIO
++ case ENXIO: return "no such device or address";
++#endif
++#ifdef EOPNOTSUPP
++ case EOPNOTSUPP: return "operation not supported on socket";
++#endif
++#ifdef EPERM
++ case EPERM: return "not owner";
++#endif
++#ifdef EPFNOSUPPORT
++ case EPFNOSUPPORT: return "protocol family not supported";
++#endif
++#ifdef EPIPE
++ case EPIPE: return "broken pipe";
++#endif
++#ifdef EPROCLIM
++ case EPROCLIM: return "too many processes";
++#endif
++#ifdef EPROCUNAVAIL
++ case EPROCUNAVAIL: return "bad procedure for program";
++#endif
++#ifdef EPROGMISMATCH
++ case EPROGMISMATCH: return "program version wrong";
++#endif
++#ifdef EPROGUNAVAIL
++ case EPROGUNAVAIL: return "RPC program not available";
++#endif
++#ifdef EPROTO
++ case EPROTO: return "protocol error";
++#endif
++#ifdef EPROTONOSUPPORT
++ case EPROTONOSUPPORT: return "protocol not suppored";
++#endif
++#ifdef EPROTOTYPE
++ case EPROTOTYPE: return "protocol wrong type for socket";
++#endif
++#ifdef ERANGE
++ case ERANGE: return "math result unrepresentable";
++#endif
++#if defined(EREFUSED) && (!defined(ECONNREFUSED) || (EREFUSED != ECONNREFUSED))
++ case EREFUSED: return "EREFUSED";
++#endif
++#ifdef EREMCHG
++ case EREMCHG: return "remote address changed";
++#endif
++#ifdef EREMDEV
++ case EREMDEV: return "remote device";
++#endif
++#ifdef EREMOTE
++ case EREMOTE: return "pathname hit remote file system";
++#endif
++#ifdef EREMOTEIO
++ case EREMOTEIO: return "remote i/o error";
++#endif
++#ifdef EREMOTERELEASE
++ case EREMOTERELEASE: return "EREMOTERELEASE";
++#endif
++#ifdef EROFS
++ case EROFS: return "read-only file system";
++#endif
++#ifdef ERPCMISMATCH
++ case ERPCMISMATCH: return "RPC version is wrong";
++#endif
++#ifdef ERREMOTE
++ case ERREMOTE: return "object is remote";
++#endif
++#ifdef ESHUTDOWN
++ case ESHUTDOWN: return "can't send afer socket shutdown";
++#endif
++#ifdef ESOCKTNOSUPPORT
++ case ESOCKTNOSUPPORT: return "socket type not supported";
++#endif
++#ifdef ESPIPE
++ case ESPIPE: return "invalid seek";
++#endif
++#ifdef ESRCH
++ case ESRCH: return "no such process";
++#endif
++#ifdef ESRMNT
++ case ESRMNT: return "srmount error";
++#endif
++#ifdef ESTALE
++ case ESTALE: return "stale remote file handle";
++#endif
++#ifdef ESUCCESS
++ case ESUCCESS: return "Error 0";
++#endif
++#ifdef ETIME
++ case ETIME: return "timer expired";
++#endif
++#ifdef ETIMEDOUT
++ case ETIMEDOUT: return "connection timed out";
++#endif
++#ifdef ETOOMANYREFS
++ case ETOOMANYREFS: return "too many references: can't splice";
++#endif
++#ifdef ETXTBSY
++ case ETXTBSY: return "text file or pseudo-device busy";
++#endif
++#ifdef EUCLEAN
++ case EUCLEAN: return "structure needs cleaning";
++#endif
++#ifdef EUNATCH
++ case EUNATCH: return "protocol driver not attached";
++#endif
++#ifdef EUSERS
++ case EUSERS: return "too many users";
++#endif
++#ifdef EVERSION
++ case EVERSION: return "version mismatch";
++#endif
++#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
++ case EWOULDBLOCK: return "operation would block";
++#endif
++#ifdef EXDEV
++ case EXDEV: return "cross-domain link";
++#endif
++#ifdef EXFULL
++ case EXFULL: return "message tables full";
++#endif
++ }
++#else /* NO_SYS_ERRLIST */
++ extern int sys_nerr;
++ extern char *sys_errlist[];
++
++ if ((errnum > 0) && (errnum <= sys_nerr))
++ return sys_errlist [errnum];
++#endif /* NO_SYS_ERRLIST */
++
++#ifndef __KORBIT__
++ msg = g_static_private_get (&msg_private);
++ if (!msg)
++ {
++ msg = g_new (gchar, 64);
++ g_static_private_set (&msg_private, msg, g_free);
++ }
++
++ sprintf (msg, "unknown error (%d)", errnum);
++
++ return msg;
++#else
++ return "unknown error";
++#endif /* !__KORBIT__ */
++}
++
++gchar*
++g_strsignal (gint signum)
++{
++#ifndef __KORBIT__
++ static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT;
++ char *msg;
++#endif
++
++#ifdef HAVE_STRSIGNAL
++ extern char *strsignal (int sig);
++ return strsignal (signum);
++#elif NO_SYS_SIGLIST
++ switch (signum)
++ {
++#ifdef SIGHUP
++ case SIGHUP: return "Hangup";
++#endif
++#ifdef SIGINT
++ case SIGINT: return "Interrupt";
++#endif
++#ifdef SIGQUIT
++ case SIGQUIT: return "Quit";
++#endif
++#ifdef SIGILL
++ case SIGILL: return "Illegal instruction";
++#endif
++#ifdef SIGTRAP
++ case SIGTRAP: return "Trace/breakpoint trap";
++#endif
++#ifdef SIGABRT
++ case SIGABRT: return "IOT trap/Abort";
++#endif
++#ifdef SIGBUS
++ case SIGBUS: return "Bus error";
++#endif
++#ifdef SIGFPE
++ case SIGFPE: return "Floating point exception";
++#endif
++#ifdef SIGKILL
++ case SIGKILL: return "Killed";
++#endif
++#ifdef SIGUSR1
++ case SIGUSR1: return "User defined signal 1";
++#endif
++#ifdef SIGSEGV
++ case SIGSEGV: return "Segmentation fault";
++#endif
++#ifdef SIGUSR2
++ case SIGUSR2: return "User defined signal 2";
++#endif
++#ifdef SIGPIPE
++ case SIGPIPE: return "Broken pipe";
++#endif
++#ifdef SIGALRM
++ case SIGALRM: return "Alarm clock";
++#endif
++#ifdef SIGTERM
++ case SIGTERM: return "Terminated";
++#endif
++#ifdef SIGSTKFLT
++ case SIGSTKFLT: return "Stack fault";
++#endif
++#ifdef SIGCHLD
++ case SIGCHLD: return "Child exited";
++#endif
++#ifdef SIGCONT
++ case SIGCONT: return "Continued";
++#endif
++#ifdef SIGSTOP
++ case SIGSTOP: return "Stopped (signal)";
++#endif
++#ifdef SIGTSTP
++ case SIGTSTP: return "Stopped";
++#endif
++#ifdef SIGTTIN
++ case SIGTTIN: return "Stopped (tty input)";
++#endif
++#ifdef SIGTTOU
++ case SIGTTOU: return "Stopped (tty output)";
++#endif
++#ifdef SIGURG
++ case SIGURG: return "Urgent condition";
++#endif
++#ifdef SIGXCPU
++ case SIGXCPU: return "CPU time limit exceeded";
++#endif
++#ifdef SIGXFSZ
++ case SIGXFSZ: return "File size limit exceeded";
++#endif
++#ifdef SIGVTALRM
++ case SIGVTALRM: return "Virtual time alarm";
++#endif
++#ifdef SIGPROF
++ case SIGPROF: return "Profile signal";
++#endif
++#ifdef SIGWINCH
++ case SIGWINCH: return "Window size changed";
++#endif
++#ifdef SIGIO
++ case SIGIO: return "Possible I/O";
++#endif
++#ifdef SIGPWR
++ case SIGPWR: return "Power failure";
++#endif
++#ifdef SIGUNUSED
++ case SIGUNUSED: return "Unused signal";
++#endif
++ }
++#else /* NO_SYS_SIGLIST */
++
++#ifdef NO_SYS_SIGLIST_DECL
++ extern char *sys_siglist[]; /*(see Tue Jan 19 00:44:24 1999 in changelog)*/
++#endif
++
++ return (char*) /* this function should return const --josh */ sys_siglist [signum];
++#endif /* NO_SYS_SIGLIST */
++
++#ifndef __KORBIT__
++ msg = g_static_private_get (&msg_private);
++ if (!msg)
++ {
++ msg = g_new (gchar, 64);
++ g_static_private_set (&msg_private, msg, g_free);
++ }
++
++ sprintf (msg, "unknown signal (%d)", signum);
++
++ return msg;
++#else
++ return "unknown error";
++#endif /* !__KORBIT__ */
++}
++
++guint
++g_printf_string_upper_bound (const gchar* format,
++ va_list args)
++{
++ guint len = 1;
++
++ while (*format)
++ {
++ gboolean long_int = FALSE;
++ gboolean extra_long = FALSE;
++ gchar c;
++
++ c = *format++;
++
++ if (c == '%')
++ {
++ gboolean done = FALSE;
++
++ while (*format && !done)
++ {
++ switch (*format++)
++ {
++ gchar *string_arg;
++
++ case '*':
++ len += va_arg (args, int);
++ break;
++ case '1':
++ case '2':
++ case '3':
++ case '4':
++ case '5':
++ case '6':
++ case '7':
++ case '8':
++ case '9':
++ /* add specified format length, since it might exceed the
++ * size we assume it to have.
++ */
++ format -= 1;
++ len += strtol (format, (char**) &format, 10);
++ break;
++ case 'h':
++ /* ignore short int flag, since all args have at least the
++ * same size as an int
++ */
++ break;
++ case 'l':
++ if (long_int)
++ extra_long = TRUE; /* linux specific */
++ else
++ long_int = TRUE;
++ break;
++ case 'q':
++ case 'L':
++ long_int = TRUE;
++ extra_long = TRUE;
++ break;
++ case 's':
++ string_arg = va_arg (args, char *);
++ if (string_arg)
++ len += strlen (string_arg);
++ else
++ {
++ /* add enough padding to hold "(null)" identifier */
++ len += 16;
++ }
++ done = TRUE;
++ break;
++ case 'd':
++ case 'i':
++ case 'o':
++ case 'u':
++ case 'x':
++ case 'X':
++#ifdef G_HAVE_GINT64
++ if (extra_long)
++ (void) va_arg (args, gint64);
++ else
++#endif /* G_HAVE_GINT64 */
++ {
++ if (long_int)
++ (void) va_arg (args, long);
++ else
++ (void) va_arg (args, int);
++ }
++ len += extra_long ? 64 : 32;
++ done = TRUE;
++ break;
++ case 'D':
++ case 'O':
++ case 'U':
++ (void) va_arg (args, long);
++ len += 32;
++ done = TRUE;
++ break;
++ case 'e':
++ case 'E':
++ case 'f':
++ case 'g':
++#ifdef HAVE_LONG_DOUBLE
++ if (extra_long)
++ (void) va_arg (args, long double);
++ else
++#endif /* HAVE_LONG_DOUBLE */
++ (void) va_arg (args, double);
++ len += extra_long ? 128 : 64;
++ done = TRUE;
++ break;
++ case 'c':
++ (void) va_arg (args, int);
++ len += 1;
++ done = TRUE;
++ break;
++ case 'p':
++ case 'n':
++ (void) va_arg (args, void*);
++ len += 32;
++ done = TRUE;
++ break;
++ case '%':
++ len += 1;
++ done = TRUE;
++ break;
++ default:
++ /* ignore unknow/invalid flags */
++ break;
++ }
++ }
++ }
++ else
++ len += 1;
++ }
++
++ return len;
++}
++
++void
++g_strdown (gchar *string)
++{
++ register guchar *s;
++
++ g_return_if_fail (string != NULL);
++
++ s = string;
++
++ while (*s)
++ {
++ *s = tolower (*s);
++ s++;
++ }
++}
++
++void
++g_strup (gchar *string)
++{
++ register guchar *s;
++
++ g_return_if_fail (string != NULL);
++
++ s = string;
++
++ while (*s)
++ {
++ *s = toupper (*s);
++ s++;
++ }
++}
++
++void
++g_strreverse (gchar *string)
++{
++ g_return_if_fail (string != NULL);
++
++ if (*string)
++ {
++ register gchar *h, *t;
++
++ h = string;
++ t = string + strlen (string) - 1;
++
++ while (h < t)
++ {
++ register gchar c;
++
++ c = *h;
++ *h = *t;
++ h++;
++ *t = c;
++ t--;
++ }
++ }
++}
++
++gint
++g_strcasecmp (const gchar *s1,
++ const gchar *s2)
++{
++#ifdef HAVE_STRCASECMP
++ g_return_val_if_fail (s1 != NULL, 0);
++ g_return_val_if_fail (s2 != NULL, 0);
++
++ return strcasecmp (s1, s2);
++#else
++ gint c1, c2;
++
++ g_return_val_if_fail (s1 != NULL, 0);
++ g_return_val_if_fail (s2 != NULL, 0);
++
++ while (*s1 && *s2)
++ {
++ /* According to A. Cox, some platforms have islower's that
++ * don't work right on non-uppercase
++ */
++ c1 = isupper ((guchar)*s1) ? tolower ((guchar)*s1) : *s1;
++ c2 = isupper ((guchar)*s2) ? tolower ((guchar)*s2) : *s2;
++ if (c1 != c2)
++ return (c1 - c2);
++ s1++; s2++;
++ }
++
++ return (((gint)(guchar) *s1) - ((gint)(guchar) *s2));
++#endif
++}
++
++gint
++g_strncasecmp (const gchar *s1,
++ const gchar *s2,
++ guint n)
++{
++#ifdef HAVE_STRNCASECMP
++ return strncasecmp (s1, s2, n);
++#else
++ gint c1, c2;
++
++ g_return_val_if_fail (s1 != NULL, 0);
++ g_return_val_if_fail (s2 != NULL, 0);
++
++ while (n-- && *s1 && *s2)
++ {
++ /* According to A. Cox, some platforms have islower's that
++ * don't work right on non-uppercase
++ */
++ c1 = isupper ((guchar)*s1) ? tolower ((guchar)*s1) : *s1;
++ c2 = isupper ((guchar)*s2) ? tolower ((guchar)*s2) : *s2;
++ if (c1 != c2)
++ return (c1 - c2);
++ s1++; s2++;
++ }
++
++ if (n)
++ return (((gint)(guchar) *s1) - ((gint)(guchar) *s2));
++ else
++ return 0;
++#endif
++}
++
++gchar*
++g_strdelimit (gchar *string,
++ const gchar *delimiters,
++ gchar new_delim)
++{
++ register gchar *c;
++
++ g_return_val_if_fail (string != NULL, NULL);
++
++ if (!delimiters)
++ delimiters = G_STR_DELIMITERS;
++
++ for (c = string; *c; c++)
++ {
++ if (strchr (delimiters, *c))
++ *c = new_delim;
++ }
++
++ return string;
++}
++
++gchar*
++g_strescape (gchar *string)
++{
++ gchar *q;
++ gchar *escaped;
++ guint backslashes = 0;
++ gchar *p = string;
++
++ g_return_val_if_fail (string != NULL, NULL);
++
++ while (*p != '\000')
++ backslashes += (*p++ == '\\');
++
++ if (!backslashes)
++ return g_strdup (string);
++
++ escaped = g_new (gchar, strlen (string) + backslashes + 1);
++
++ p = string;
++ q = escaped;
++
++ while (*p != '\000')
++ {
++ if (*p == '\\')
++ *q++ = '\\';
++ *q++ = *p++;
++ }
++ *q = '\000';
++
++ return escaped;
++}
++
++/* blame Elliot for these next five routines */
++gchar*
++g_strchug (gchar *string)
++{
++ guchar *start;
++
++ g_return_val_if_fail (string != NULL, NULL);
++
++ for (start = string; *start && isspace (*start); start++)
++ ;
++
++ g_memmove(string, start, strlen(start) + 1);
++
++ return string;
++}
++
++gchar*
++g_strchomp (gchar *string)
++{
++ gchar *s;
++
++ g_return_val_if_fail (string != NULL, NULL);
++
++ if (!*string)
++ return string;
++
++ for (s = string + strlen (string) - 1; s >= string && isspace ((guchar)*s);
++ s--)
++ *s = '\0';
++
++ return string;
++}
++
++gchar**
++g_strsplit (const gchar *string,
++ const gchar *delimiter,
++ gint max_tokens)
++{
++ GSList *string_list = NULL, *slist;
++ gchar **str_array, *s;
++ guint i, n = 1;
++
++ g_return_val_if_fail (string != NULL, NULL);
++ g_return_val_if_fail (delimiter != NULL, NULL);
++
++ if (max_tokens < 1)
++ max_tokens = G_MAXINT;
++
++ s = strstr (string, delimiter);
++ if (s)
++ {
++ guint delimiter_len = strlen (delimiter);
++
++ do
++ {
++ guint len;
++ gchar *new_string;
++
++ len = s - string;
++ new_string = g_new (gchar, len + 1);
++ strncpy (new_string, string, len);
++ new_string[len] = 0;
++ string_list = g_slist_prepend (string_list, new_string);
++ n++;
++ string = s + delimiter_len;
++ s = strstr (string, delimiter);
++ }
++ while (--max_tokens && s);
++ }
++ if (*string)
++ {
++ n++;
++ string_list = g_slist_prepend (string_list, g_strdup (string));
++ }
++
++ str_array = g_new (gchar*, n);
++
++ i = n - 1;
++
++ str_array[i--] = NULL;
++ for (slist = string_list; slist; slist = slist->next)
++ str_array[i--] = slist->data;
++
++ g_slist_free (string_list);
++
++ return str_array;
++}
++
++void
++g_strfreev (gchar **str_array)
++{
++ if (str_array)
++ {
++ int i;
++
++ for(i = 0; str_array[i] != NULL; i++)
++ g_free(str_array[i]);
++
++ g_free (str_array);
++ }
++}
++
++gchar*
++g_strjoinv (const gchar *separator,
++ gchar **str_array)
++{
++ gchar *string;
++
++ g_return_val_if_fail (str_array != NULL, NULL);
++
++ if (separator == NULL)
++ separator = "";
++
++ if (*str_array)
++ {
++ guint i, len;
++ guint separator_len;
++
++ separator_len = strlen (separator);
++ len = 1 + strlen (str_array[0]);
++ for(i = 1; str_array[i] != NULL; i++)
++ len += separator_len + strlen(str_array[i]);
++
++ string = g_new (gchar, len);
++ *string = 0;
++ strcat (string, *str_array);
++ for (i = 1; str_array[i] != NULL; i++)
++ {
++ strcat (string, separator);
++ strcat (string, str_array[i]);
++ }
++ }
++ else
++ string = g_strdup ("");
++
++ return string;
++}
++
++gchar*
++g_strjoin (const gchar *separator,
++ ...)
++{
++ gchar *string, *s;
++ va_list args;
++ guint len;
++ guint separator_len;
++
++ if (separator == NULL)
++ separator = "";
++
++ separator_len = strlen (separator);
++
++ va_start (args, separator);
++
++ s = va_arg (args, gchar*);
++
++ if (s)
++ {
++ len = strlen (s);
++
++ s = va_arg (args, gchar*);
++ while (s)
++ {
++ len += separator_len + strlen (s);
++ s = va_arg (args, gchar*);
++ }
++ va_end (args);
++
++ string = g_new (gchar, len + 1);
++ *string = 0;
++
++ va_start (args, separator);
++
++ s = va_arg (args, gchar*);
++ strcat (string, s);
++
++ s = va_arg (args, gchar*);
++ while (s)
++ {
++ strcat (string, separator);
++ strcat (string, s);
++ s = va_arg (args, gchar*);
++ }
++ }
++ else
++ string = g_strdup ("");
++
++ va_end (args);
++
++ return string;
++}
+diff -urN linux-2.4.1/net/korbit/kglib/gstring.c linux-2.4.1-korbit/net/korbit/kglib/gstring.c
+--- linux-2.4.1/net/korbit/kglib/gstring.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/gstring.c Thu Feb 1 11:46:57 2001
+@@ -0,0 +1,508 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/*
++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS
++ * file for a list of people on the GLib Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GLib at ftp://ftp.gtk.org/pub/gtk/.
++ */
++
++#include <stdarg.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <ctype.h>
++#include "glib.h"
++
++
++typedef struct _GRealStringChunk GRealStringChunk;
++typedef struct _GRealString GRealString;
++
++struct _GRealStringChunk
++{
++ GHashTable *const_table;
++ GSList *storage_list;
++ gint storage_next;
++ gint this_size;
++ gint default_size;
++};
++
++struct _GRealString
++{
++ gchar *str;
++ gint len;
++ gint alloc;
++};
++
++G_LOCK_DEFINE_STATIC (string_mem_chunk);
++static GMemChunk *string_mem_chunk = NULL;
++
++/* Hash Functions.
++ */
++
++gint
++g_str_equal (gconstpointer v, gconstpointer v2)
++{
++ return strcmp ((const gchar*) v, (const gchar*)v2) == 0;
++}
++
++/* 31 bit hash function */
++guint
++g_str_hash (gconstpointer key)
++{
++ const char *p = key;
++ guint h = *p;
++
++ if (h)
++ for (p += 1; *p != '\0'; p++)
++ h = (h << 5) - h + *p;
++
++ return h;
++}
++
++/* String Chunks.
++ */
++
++GStringChunk*
++g_string_chunk_new (gint default_size)
++{
++ GRealStringChunk *new_chunk = g_new (GRealStringChunk, 1);
++ gint size = 1;
++
++ while (size < default_size)
++ size <<= 1;
++
++ new_chunk->const_table = NULL;
++ new_chunk->storage_list = NULL;
++ new_chunk->storage_next = size;
++ new_chunk->default_size = size;
++ new_chunk->this_size = size;
++
++ return (GStringChunk*) new_chunk;
++}
++
++void
++g_string_chunk_free (GStringChunk *fchunk)
++{
++ GRealStringChunk *chunk = (GRealStringChunk*) fchunk;
++ GSList *tmp_list;
++
++ g_return_if_fail (chunk != NULL);
++
++ if (chunk->storage_list)
++ {
++ for (tmp_list = chunk->storage_list; tmp_list; tmp_list = tmp_list->next)
++ g_free (tmp_list->data);
++
++ g_slist_free (chunk->storage_list);
++ }
++
++ if (chunk->const_table)
++ g_hash_table_destroy (chunk->const_table);
++
++ g_free (chunk);
++}
++
++gchar*
++g_string_chunk_insert (GStringChunk *fchunk,
++ const gchar *string)
++{
++ GRealStringChunk *chunk = (GRealStringChunk*) fchunk;
++ gint len = strlen (string);
++ char* pos;
++
++ g_return_val_if_fail (chunk != NULL, NULL);
++
++ if ((chunk->storage_next + len + 1) > chunk->this_size)
++ {
++ gint new_size = chunk->default_size;
++
++ while (new_size < len+1)
++ new_size <<= 1;
++
++ chunk->storage_list = g_slist_prepend (chunk->storage_list,
++ g_new (char, new_size));
++
++ chunk->this_size = new_size;
++ chunk->storage_next = 0;
++ }
++
++ pos = ((char*)chunk->storage_list->data) + chunk->storage_next;
++
++ strcpy (pos, string);
++
++ chunk->storage_next += len + 1;
++
++ return pos;
++}
++
++gchar*
++g_string_chunk_insert_const (GStringChunk *fchunk,
++ const gchar *string)
++{
++ GRealStringChunk *chunk = (GRealStringChunk*) fchunk;
++ char* lookup;
++
++ g_return_val_if_fail (chunk != NULL, NULL);
++
++ if (!chunk->const_table)
++ chunk->const_table = g_hash_table_new (g_str_hash, g_str_equal);
++
++ lookup = (char*) g_hash_table_lookup (chunk->const_table, (gchar *)string);
++
++ if (!lookup)
++ {
++ lookup = g_string_chunk_insert (fchunk, string);
++ g_hash_table_insert (chunk->const_table, lookup, lookup);
++ }
++
++ return lookup;
++}
++
++/* Strings.
++ */
++static gint
++nearest_pow (gint num)
++{
++ gint n = 1;
++
++ while (n < num)
++ n <<= 1;
++
++ return n;
++}
++
++static void
++g_string_maybe_expand (GRealString* string, gint len)
++{
++ if (string->len + len >= string->alloc)
++ {
++ string->alloc = nearest_pow (string->len + len + 1);
++ string->str = g_realloc (string->str, string->alloc);
++ }
++}
++
++GString*
++g_string_sized_new (guint dfl_size)
++{
++ GRealString *string;
++
++ G_LOCK (string_mem_chunk);
++ if (!string_mem_chunk)
++ string_mem_chunk = g_mem_chunk_new ("string mem chunk",
++ sizeof (GRealString),
++ 1024, G_ALLOC_AND_FREE);
++
++ string = g_chunk_new (GRealString, string_mem_chunk);
++ G_UNLOCK (string_mem_chunk);
++
++ string->alloc = 0;
++ string->len = 0;
++ string->str = NULL;
++
++ g_string_maybe_expand (string, MAX (dfl_size, 2));
++ string->str[0] = 0;
++
++ return (GString*) string;
++}
++
++GString*
++g_string_new (const gchar *init)
++{
++ GString *string;
++
++ string = g_string_sized_new (2);
++
++ if (init)
++ g_string_append (string, init);
++
++ return string;
++}
++
++void
++g_string_free (GString *string,
++ gint free_segment)
++{
++ g_return_if_fail (string != NULL);
++
++ if (free_segment)
++ g_free (string->str);
++
++ G_LOCK (string_mem_chunk);
++ g_mem_chunk_free (string_mem_chunk, string);
++ G_UNLOCK (string_mem_chunk);
++}
++
++GString*
++g_string_assign (GString *lval,
++ const gchar *rval)
++{
++ g_return_val_if_fail (lval != NULL, NULL);
++ g_return_val_if_fail (rval != NULL, NULL);
++
++ g_string_truncate (lval, 0);
++ g_string_append (lval, rval);
++
++ return lval;
++}
++
++GString*
++g_string_truncate (GString* fstring,
++ gint len)
++{
++ GRealString *string = (GRealString*)fstring;
++
++ g_return_val_if_fail (string != NULL, NULL);
++ g_return_val_if_fail (len >= 0, NULL);
++
++ string->len = len;
++
++ string->str[len] = 0;
++
++ return fstring;
++}
++
++GString*
++g_string_append (GString *fstring,
++ const gchar *val)
++{
++ GRealString *string = (GRealString*)fstring;
++ int len;
++
++ g_return_val_if_fail (string != NULL, NULL);
++ g_return_val_if_fail (val != NULL, fstring);
++
++ len = strlen (val);
++ g_string_maybe_expand (string, len);
++
++ strcpy (string->str + string->len, val);
++
++ string->len += len;
++
++ return fstring;
++}
++
++GString*
++g_string_append_c (GString *fstring,
++ gchar c)
++{
++ GRealString *string = (GRealString*)fstring;
++
++ g_return_val_if_fail (string != NULL, NULL);
++ g_string_maybe_expand (string, 1);
++
++ string->str[string->len++] = c;
++ string->str[string->len] = 0;
++
++ return fstring;
++}
++
++GString*
++g_string_prepend (GString *fstring,
++ const gchar *val)
++{
++ GRealString *string = (GRealString*)fstring;
++ gint len;
++
++ g_return_val_if_fail (string != NULL, NULL);
++ g_return_val_if_fail (val != NULL, fstring);
++
++ len = strlen (val);
++ g_string_maybe_expand (string, len);
++
++ g_memmove (string->str + len, string->str, string->len);
++
++ strncpy (string->str, val, len);
++
++ string->len += len;
++
++ string->str[string->len] = 0;
++
++ return fstring;
++}
++
++GString*
++g_string_prepend_c (GString *fstring,
++ gchar c)
++{
++ GRealString *string = (GRealString*)fstring;
++
++ g_return_val_if_fail (string != NULL, NULL);
++ g_string_maybe_expand (string, 1);
++
++ g_memmove (string->str + 1, string->str, string->len);
++
++ string->str[0] = c;
++
++ string->len += 1;
++
++ string->str[string->len] = 0;
++
++ return fstring;
++}
++
++GString*
++g_string_insert (GString *fstring,
++ gint pos,
++ const gchar *val)
++{
++ GRealString *string = (GRealString*)fstring;
++ gint len;
++
++ g_return_val_if_fail (string != NULL, NULL);
++ g_return_val_if_fail (val != NULL, fstring);
++ g_return_val_if_fail (pos >= 0, fstring);
++ g_return_val_if_fail (pos <= string->len, fstring);
++
++ len = strlen (val);
++ g_string_maybe_expand (string, len);
++
++ g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
++
++ strncpy (string->str + pos, val, len);
++
++ string->len += len;
++
++ string->str[string->len] = 0;
++
++ return fstring;
++}
++
++GString *
++g_string_insert_c (GString *fstring,
++ gint pos,
++ gchar c)
++{
++ GRealString *string = (GRealString*)fstring;
++
++ g_return_val_if_fail (string != NULL, NULL);
++ g_return_val_if_fail (pos <= string->len, fstring);
++
++ g_string_maybe_expand (string, 1);
++
++ g_memmove (string->str + pos + 1, string->str + pos, string->len - pos);
++
++ string->str[pos] = c;
++
++ string->len += 1;
++
++ string->str[string->len] = 0;
++
++ return fstring;
++}
++
++GString*
++g_string_erase (GString *fstring,
++ gint pos,
++ gint len)
++{
++ GRealString *string = (GRealString*)fstring;
++
++ g_return_val_if_fail (string != NULL, NULL);
++ g_return_val_if_fail (len >= 0, fstring);
++ g_return_val_if_fail (pos >= 0, fstring);
++ g_return_val_if_fail (pos <= string->len, fstring);
++ g_return_val_if_fail (pos + len <= string->len, fstring);
++
++ if (pos + len < string->len)
++ g_memmove (string->str + pos, string->str + pos + len, string->len - (pos + len));
++
++ string->len -= len;
++
++ string->str[string->len] = 0;
++
++ return fstring;
++}
++
++GString*
++g_string_down (GString *fstring)
++{
++ GRealString *string = (GRealString*)fstring;
++ guchar *s;
++
++ g_return_val_if_fail (string != NULL, NULL);
++
++ s = string->str;
++
++ while (*s)
++ {
++ *s = tolower (*s);
++ s++;
++ }
++
++ return fstring;
++}
++
++GString*
++g_string_up (GString *fstring)
++{
++ GRealString *string = (GRealString*)fstring;
++ guchar *s;
++
++ g_return_val_if_fail (string != NULL, NULL);
++
++ s = string->str;
++
++ while (*s)
++ {
++ *s = toupper (*s);
++ s++;
++ }
++
++ return fstring;
++}
++
++static void
++g_string_sprintfa_int (GString *string,
++ const gchar *fmt,
++ va_list args)
++{
++ gchar *buffer;
++
++ buffer = g_strdup_vprintf (fmt, args);
++ g_string_append (string, buffer);
++ g_free (buffer);
++}
++
++void
++g_string_sprintf (GString *string,
++ const gchar *fmt,
++ ...)
++{
++ va_list args;
++
++ g_string_truncate (string, 0);
++
++ va_start (args, fmt);
++ g_string_sprintfa_int (string, fmt, args);
++ va_end (args);
++}
++
++void
++g_string_sprintfa (GString *string,
++ const gchar *fmt,
++ ...)
++{
++ va_list args;
++
++ va_start (args, fmt);
++ g_string_sprintfa_int (string, fmt, args);
++ va_end (args);
++}
+diff -urN linux-2.4.1/net/korbit/kglib/gtree.c linux-2.4.1-korbit/net/korbit/kglib/gtree.c
+--- linux-2.4.1/net/korbit/kglib/gtree.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/gtree.c Thu Feb 1 11:46:57 2001
+@@ -0,0 +1,740 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/*
++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS
++ * file for a list of people on the GLib Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GLib at ftp://ftp.gtk.org/pub/gtk/.
++ */
++
++#include "glib.h"
++
++
++typedef struct _GRealTree GRealTree;
++typedef struct _GTreeNode GTreeNode;
++
++struct _GRealTree
++{
++ GTreeNode *root;
++ GCompareFunc key_compare;
++};
++
++struct _GTreeNode
++{
++ gint balance; /* height (left) - height (right) */
++ GTreeNode *left; /* left subtree */
++ GTreeNode *right; /* right subtree */
++ gpointer key; /* key for this node */
++ gpointer value; /* value stored at this node */
++};
++
++
++static GTreeNode* g_tree_node_new (gpointer key,
++ gpointer value);
++static void g_tree_node_destroy (GTreeNode *node);
++static GTreeNode* g_tree_node_insert (GTreeNode *node,
++ GCompareFunc compare,
++ gpointer key,
++ gpointer value,
++ gint *inserted);
++static GTreeNode* g_tree_node_remove (GTreeNode *node,
++ GCompareFunc compare,
++ gpointer key);
++static GTreeNode* g_tree_node_balance (GTreeNode *node);
++static GTreeNode* g_tree_node_remove_leftmost (GTreeNode *node,
++ GTreeNode **leftmost);
++static GTreeNode* g_tree_node_restore_left_balance (GTreeNode *node,
++ gint old_balance);
++static GTreeNode* g_tree_node_restore_right_balance (GTreeNode *node,
++ gint old_balance);
++static gpointer g_tree_node_lookup (GTreeNode *node,
++ GCompareFunc compare,
++ gpointer key);
++static gint g_tree_node_count (GTreeNode *node);
++static gint g_tree_node_pre_order (GTreeNode *node,
++ GTraverseFunc traverse_func,
++ gpointer data);
++static gint g_tree_node_in_order (GTreeNode *node,
++ GTraverseFunc traverse_func,
++ gpointer data);
++static gint g_tree_node_post_order (GTreeNode *node,
++ GTraverseFunc traverse_func,
++ gpointer data);
++static gpointer g_tree_node_search (GTreeNode *node,
++ GSearchFunc search_func,
++ gpointer data);
++static gint g_tree_node_height (GTreeNode *node);
++static GTreeNode* g_tree_node_rotate_left (GTreeNode *node);
++static GTreeNode* g_tree_node_rotate_right (GTreeNode *node);
++static void g_tree_node_check (GTreeNode *node);
++
++
++G_LOCK_DEFINE_STATIC (g_tree_global);
++static GMemChunk *node_mem_chunk = NULL;
++static GTreeNode *node_free_list = NULL;
++
++
++static GTreeNode*
++g_tree_node_new (gpointer key,
++ gpointer value)
++{
++ GTreeNode *node;
++
++ G_LOCK (g_tree_global);
++ if (node_free_list)
++ {
++ node = node_free_list;
++ node_free_list = node->right;
++ }
++ else
++ {
++ if (!node_mem_chunk)
++ node_mem_chunk = g_mem_chunk_new ("GLib GTreeNode mem chunk",
++ sizeof (GTreeNode),
++ 1024,
++ G_ALLOC_ONLY);
++
++ node = g_chunk_new (GTreeNode, node_mem_chunk);
++ }
++ G_UNLOCK (g_tree_global);
++
++ node->balance = 0;
++ node->left = NULL;
++ node->right = NULL;
++ node->key = key;
++ node->value = value;
++
++ return node;
++}
++
++static void
++g_tree_node_destroy (GTreeNode *node)
++{
++ if (node)
++ {
++ g_tree_node_destroy (node->right);
++ g_tree_node_destroy (node->left);
++ G_LOCK (g_tree_global);
++ node->right = node_free_list;
++ node_free_list = node;
++ G_UNLOCK (g_tree_global);
++ }
++}
++
++
++GTree*
++g_tree_new (GCompareFunc key_compare_func)
++{
++ GRealTree *rtree;
++
++ g_return_val_if_fail (key_compare_func != NULL, NULL);
++
++ rtree = g_new (GRealTree, 1);
++ rtree->root = NULL;
++ rtree->key_compare = key_compare_func;
++
++ return (GTree*) rtree;
++}
++
++void
++g_tree_destroy (GTree *tree)
++{
++ GRealTree *rtree;
++
++ g_return_if_fail (tree != NULL);
++
++ rtree = (GRealTree*) tree;
++
++ g_tree_node_destroy (rtree->root);
++ g_free (rtree);
++}
++
++void
++g_tree_insert (GTree *tree,
++ gpointer key,
++ gpointer value)
++{
++ GRealTree *rtree;
++ gint inserted;
++
++ g_return_if_fail (tree != NULL);
++
++ rtree = (GRealTree*) tree;
++
++ inserted = FALSE;
++ rtree->root = g_tree_node_insert (rtree->root, rtree->key_compare,
++ key, value, &inserted);
++}
++
++void
++g_tree_remove (GTree *tree,
++ gpointer key)
++{
++ GRealTree *rtree;
++
++ g_return_if_fail (tree != NULL);
++
++ rtree = (GRealTree*) tree;
++
++ rtree->root = g_tree_node_remove (rtree->root, rtree->key_compare, key);
++}
++
++gpointer
++g_tree_lookup (GTree *tree,
++ gpointer key)
++{
++ GRealTree *rtree;
++
++ g_return_val_if_fail (tree != NULL, NULL);
++
++ rtree = (GRealTree*) tree;
++
++ return g_tree_node_lookup (rtree->root, rtree->key_compare, key);
++}
++
++void
++g_tree_traverse (GTree *tree,
++ GTraverseFunc traverse_func,
++ GTraverseType traverse_type,
++ gpointer data)
++{
++ GRealTree *rtree;
++
++ g_return_if_fail (tree != NULL);
++
++ rtree = (GRealTree*) tree;
++
++ if (!rtree->root)
++ return;
++
++ switch (traverse_type)
++ {
++ case G_PRE_ORDER:
++ g_tree_node_pre_order (rtree->root, traverse_func, data);
++ break;
++
++ case G_IN_ORDER:
++ g_tree_node_in_order (rtree->root, traverse_func, data);
++ break;
++
++ case G_POST_ORDER:
++ g_tree_node_post_order (rtree->root, traverse_func, data);
++ break;
++
++ case G_LEVEL_ORDER:
++ g_warning ("g_tree_traverse(): traverse type G_LEVEL_ORDER isn't implemented.");
++ break;
++ }
++}
++
++gpointer
++g_tree_search (GTree *tree,
++ GSearchFunc search_func,
++ gpointer data)
++{
++ GRealTree *rtree;
++
++ g_return_val_if_fail (tree != NULL, NULL);
++
++ rtree = (GRealTree*) tree;
++
++ if (rtree->root)
++ return g_tree_node_search (rtree->root, search_func, data);
++ else
++ return NULL;
++}
++
++gint
++g_tree_height (GTree *tree)
++{
++ GRealTree *rtree;
++
++ g_return_val_if_fail (tree != NULL, 0);
++
++ rtree = (GRealTree*) tree;
++
++ if (rtree->root)
++ return g_tree_node_height (rtree->root);
++ else
++ return 0;
++}
++
++gint
++g_tree_nnodes (GTree *tree)
++{
++ GRealTree *rtree;
++
++ g_return_val_if_fail (tree != NULL, 0);
++
++ rtree = (GRealTree*) tree;
++
++ if (rtree->root)
++ return g_tree_node_count (rtree->root);
++ else
++ return 0;
++}
++
++static GTreeNode*
++g_tree_node_insert (GTreeNode *node,
++ GCompareFunc compare,
++ gpointer key,
++ gpointer value,
++ gint *inserted)
++{
++ gint old_balance;
++ gint cmp;
++
++ if (!node)
++ {
++ *inserted = TRUE;
++ return g_tree_node_new (key, value);
++ }
++
++ cmp = (* compare) (key, node->key);
++ if (cmp == 0)
++ {
++ *inserted = FALSE;
++ node->value = value;
++ return node;
++ }
++
++ if (cmp < 0)
++ {
++ if (node->left)
++ {
++ old_balance = node->left->balance;
++ node->left = g_tree_node_insert (node->left, compare, key, value, inserted);
++
++ if ((old_balance != node->left->balance) && node->left->balance)
++ node->balance -= 1;
++ }
++ else
++ {
++ *inserted = TRUE;
++ node->left = g_tree_node_new (key, value);
++ node->balance -= 1;
++ }
++ }
++ else if (cmp > 0)
++ {
++ if (node->right)
++ {
++ old_balance = node->right->balance;
++ node->right = g_tree_node_insert (node->right, compare, key, value, inserted);
++
++ if ((old_balance != node->right->balance) && node->right->balance)
++ node->balance += 1;
++ }
++ else
++ {
++ *inserted = TRUE;
++ node->right = g_tree_node_new (key, value);
++ node->balance += 1;
++ }
++ }
++
++ if (*inserted)
++ {
++ if ((node->balance < -1) || (node->balance > 1))
++ node = g_tree_node_balance (node);
++ }
++
++ return node;
++}
++
++static GTreeNode*
++g_tree_node_remove (GTreeNode *node,
++ GCompareFunc compare,
++ gpointer key)
++{
++ GTreeNode *new_root;
++ gint old_balance;
++ gint cmp;
++
++ if (!node)
++ return NULL;
++
++ cmp = (* compare) (key, node->key);
++ if (cmp == 0)
++ {
++ GTreeNode *garbage;
++
++ garbage = node;
++
++ if (!node->right)
++ {
++ node = node->left;
++ }
++ else
++ {
++ old_balance = node->right->balance;
++ node->right = g_tree_node_remove_leftmost (node->right, &new_root);
++ new_root->left = node->left;
++ new_root->right = node->right;
++ new_root->balance = node->balance;
++ node = g_tree_node_restore_right_balance (new_root, old_balance);
++ }
++
++ G_LOCK (g_tree_global);
++ garbage->right = node_free_list;
++ node_free_list = garbage;
++ G_UNLOCK (g_tree_global);
++ }
++ else if (cmp < 0)
++ {
++ if (node->left)
++ {
++ old_balance = node->left->balance;
++ node->left = g_tree_node_remove (node->left, compare, key);
++ node = g_tree_node_restore_left_balance (node, old_balance);
++ }
++ }
++ else if (cmp > 0)
++ {
++ if (node->right)
++ {
++ old_balance = node->right->balance;
++ node->right = g_tree_node_remove (node->right, compare, key);
++ node = g_tree_node_restore_right_balance (node, old_balance);
++ }
++ }
++
++ return node;
++}
++
++static GTreeNode*
++g_tree_node_balance (GTreeNode *node)
++{
++ if (node->balance < -1)
++ {
++ if (node->left->balance > 0)
++ node->left = g_tree_node_rotate_left (node->left);
++ node = g_tree_node_rotate_right (node);
++ }
++ else if (node->balance > 1)
++ {
++ if (node->right->balance < 0)
++ node->right = g_tree_node_rotate_right (node->right);
++ node = g_tree_node_rotate_left (node);
++ }
++
++ return node;
++}
++
++static GTreeNode*
++g_tree_node_remove_leftmost (GTreeNode *node,
++ GTreeNode **leftmost)
++{
++ gint old_balance;
++
++ if (!node->left)
++ {
++ *leftmost = node;
++ return node->right;
++ }
++
++ old_balance = node->left->balance;
++ node->left = g_tree_node_remove_leftmost (node->left, leftmost);
++ return g_tree_node_restore_left_balance (node, old_balance);
++}
++
++static GTreeNode*
++g_tree_node_restore_left_balance (GTreeNode *node,
++ gint old_balance)
++{
++ if (!node->left)
++ node->balance += 1;
++ else if ((node->left->balance != old_balance) &&
++ (node->left->balance == 0))
++ node->balance += 1;
++
++ if (node->balance > 1)
++ return g_tree_node_balance (node);
++ return node;
++}
++
++static GTreeNode*
++g_tree_node_restore_right_balance (GTreeNode *node,
++ gint old_balance)
++{
++ if (!node->right)
++ node->balance -= 1;
++ else if ((node->right->balance != old_balance) &&
++ (node->right->balance == 0))
++ node->balance -= 1;
++
++ if (node->balance < -1)
++ return g_tree_node_balance (node);
++ return node;
++}
++
++static gpointer
++g_tree_node_lookup (GTreeNode *node,
++ GCompareFunc compare,
++ gpointer key)
++{
++ gint cmp;
++
++ if (!node)
++ return NULL;
++
++ cmp = (* compare) (key, node->key);
++ if (cmp == 0)
++ return node->value;
++
++ if (cmp < 0)
++ {
++ if (node->left)
++ return g_tree_node_lookup (node->left, compare, key);
++ }
++ else if (cmp > 0)
++ {
++ if (node->right)
++ return g_tree_node_lookup (node->right, compare, key);
++ }
++
++ return NULL;
++}
++
++static gint
++g_tree_node_count (GTreeNode *node)
++{
++ gint count;
++
++ count = 1;
++ if (node->left)
++ count += g_tree_node_count (node->left);
++ if (node->right)
++ count += g_tree_node_count (node->right);
++
++ return count;
++}
++
++static gint
++g_tree_node_pre_order (GTreeNode *node,
++ GTraverseFunc traverse_func,
++ gpointer data)
++{
++ if ((*traverse_func) (node->key, node->value, data))
++ return TRUE;
++ if (node->left)
++ {
++ if (g_tree_node_pre_order (node->left, traverse_func, data))
++ return TRUE;
++ }
++ if (node->right)
++ {
++ if (g_tree_node_pre_order (node->right, traverse_func, data))
++ return TRUE;
++ }
++
++ return FALSE;
++}
++
++static gint
++g_tree_node_in_order (GTreeNode *node,
++ GTraverseFunc traverse_func,
++ gpointer data)
++{
++ if (node->left)
++ {
++ if (g_tree_node_in_order (node->left, traverse_func, data))
++ return TRUE;
++ }
++ if ((*traverse_func) (node->key, node->value, data))
++ return TRUE;
++ if (node->right)
++ {
++ if (g_tree_node_in_order (node->right, traverse_func, data))
++ return TRUE;
++ }
++
++ return FALSE;
++}
++
++static gint
++g_tree_node_post_order (GTreeNode *node,
++ GTraverseFunc traverse_func,
++ gpointer data)
++{
++ if (node->left)
++ {
++ if (g_tree_node_post_order (node->left, traverse_func, data))
++ return TRUE;
++ }
++ if (node->right)
++ {
++ if (g_tree_node_post_order (node->right, traverse_func, data))
++ return TRUE;
++ }
++ if ((*traverse_func) (node->key, node->value, data))
++ return TRUE;
++
++ return FALSE;
++}
++
++static gpointer
++g_tree_node_search (GTreeNode *node,
++ GSearchFunc search_func,
++ gpointer data)
++{
++ gint dir;
++
++ if (!node)
++ return NULL;
++
++ do {
++ dir = (* search_func) (node->key, data);
++ if (dir == 0)
++ return node->value;
++
++ if (dir < 0)
++ node = node->left;
++ else if (dir > 0)
++ node = node->right;
++ } while (node && (dir != 0));
++
++ return NULL;
++}
++
++static gint
++g_tree_node_height (GTreeNode *node)
++{
++ gint left_height;
++ gint right_height;
++
++ if (node)
++ {
++ left_height = 0;
++ right_height = 0;
++
++ if (node->left)
++ left_height = g_tree_node_height (node->left);
++
++ if (node->right)
++ right_height = g_tree_node_height (node->right);
++
++ return MAX (left_height, right_height) + 1;
++ }
++
++ return 0;
++}
++
++static GTreeNode*
++g_tree_node_rotate_left (GTreeNode *node)
++{
++ GTreeNode *left;
++ GTreeNode *right;
++ gint a_bal;
++ gint b_bal;
++
++ left = node->left;
++ right = node->right;
++
++ node->right = right->left;
++ right->left = node;
++
++ a_bal = node->balance;
++ b_bal = right->balance;
++
++ if (b_bal <= 0)
++ {
++ if (a_bal >= 1)
++ right->balance = b_bal - 1;
++ else
++ right->balance = a_bal + b_bal - 2;
++ node->balance = a_bal - 1;
++ }
++ else
++ {
++ if (a_bal <= b_bal)
++ right->balance = a_bal - 2;
++ else
++ right->balance = b_bal - 1;
++ node->balance = a_bal - b_bal - 1;
++ }
++
++ return right;
++}
++
++static GTreeNode*
++g_tree_node_rotate_right (GTreeNode *node)
++{
++ GTreeNode *left;
++ gint a_bal;
++ gint b_bal;
++
++ left = node->left;
++
++ node->left = left->right;
++ left->right = node;
++
++ a_bal = node->balance;
++ b_bal = left->balance;
++
++ if (b_bal <= 0)
++ {
++ if (b_bal > a_bal)
++ left->balance = b_bal + 1;
++ else
++ left->balance = a_bal + 2;
++ node->balance = a_bal - b_bal + 1;
++ }
++ else
++ {
++ if (a_bal <= -1)
++ left->balance = b_bal + 1;
++ else
++ left->balance = a_bal + b_bal + 2;
++ node->balance = a_bal + 1;
++ }
++
++ return left;
++}
++
++static void
++g_tree_node_check (GTreeNode *node)
++{
++ gint left_height;
++ gint right_height;
++ gint balance;
++
++ if (node)
++ {
++ left_height = 0;
++ right_height = 0;
++
++ if (node->left)
++ left_height = g_tree_node_height (node->left);
++ if (node->right)
++ right_height = g_tree_node_height (node->right);
++
++ balance = right_height - left_height;
++ if (balance != node->balance)
++ g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
++ "g_tree_node_check: failed: %d ( %d )\n",
++ balance, node->balance);
++
++ if (node->left)
++ g_tree_node_check (node->left);
++ if (node->right)
++ g_tree_node_check (node->right);
++ }
++}
+diff -urN linux-2.4.1/net/korbit/kglib/gutils.c linux-2.4.1-korbit/net/korbit/kglib/gutils.c
+--- linux-2.4.1/net/korbit/kglib/gutils.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/gutils.c Thu Feb 1 11:46:57 2001
+@@ -0,0 +1,915 @@
++/* GLIB - Library of useful routines for C programming
++ * Copyright (C) 1995-1998 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/*
++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS
++ * file for a list of people on the GLib Team. See the ChangeLog
++ * files for a list of changes. These files are distributed with
++ * GLib at ftp://ftp.gtk.org/pub/gtk/.
++ */
++
++#define G_INLINE_FUNC extern
++#define G_CAN_INLINE 1
++
++#ifdef HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <stdarg.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <errno.h>
++#ifdef HAVE_PWD_H
++#include <pwd.h>
++#endif
++#include <sys/types.h>
++#ifdef HAVE_SYS_PARAM_H
++#include <sys/param.h>
++#endif
++
++#ifdef NATIVE_WIN32
++# define STRICT /* Strict typing, please */
++# include <windows.h>
++# include <direct.h>
++# include <errno.h>
++# include <ctype.h>
++# ifdef _MSC_VER
++# include <io.h>
++# endif /* _MSC_VER */
++#endif /* NATIVE_WIN32 */
++
++/* implement Glib's inline functions
++ */
++#include "glib.h"
++
++#ifdef MAXPATHLEN
++#define G_PATH_LENGTH (MAXPATHLEN + 1)
++#elif defined (PATH_MAX)
++#define G_PATH_LENGTH (PATH_MAX + 1)
++#else /* !MAXPATHLEN */
++#define G_PATH_LENGTH (2048 + 1)
++#endif /* !MAXPATHLEN && !PATH_MAX */
++
++const guint glib_major_version = 1;
++const guint glib_minor_version = 2;
++const guint glib_micro_version = 8;
++const guint glib_interface_age = 8;
++const guint glib_binary_age = 8;
++
++#if defined (NATIVE_WIN32) && defined (__LCC__)
++int __stdcall
++LibMain (void *hinstDll,
++ unsigned long dwReason,
++ void *reserved)
++{
++ return 1;
++}
++#endif /* NATIVE_WIN32 && __LCC__ */
++
++void
++g_atexit (GVoidFunc func)
++{
++ gint result;
++ gchar *error = NULL;
++
++ /* keep this in sync with glib.h */
++
++#ifdef G_NATIVE_ATEXIT
++ result = ATEXIT (func);
++ if (result)
++ error = g_strerror (errno);
++#elif defined (HAVE_ATEXIT)
++# ifdef NeXT /* @#%@! NeXTStep */
++ result = !atexit ((void (*)(void)) func);
++ if (result)
++ error = g_strerror (errno);
++# else
++ result = atexit ((void (*)(void)) func);
++ if (result)
++ error = g_strerror (errno);
++# endif /* NeXT */
++#elif defined (HAVE_ON_EXIT)
++ result = on_exit ((void (*)(int, void *)) func, NULL);
++ if (result)
++ error = g_strerror (errno);
++#else
++ result = 0;
++ error = "no implementation";
++#endif /* G_NATIVE_ATEXIT */
++
++ if (error)
++ g_error ("Could not register atexit() function: %s", error);
++}
++
++gint
++g_snprintf (gchar *str,
++ gulong n,
++ gchar const *fmt,
++ ...)
++{
++#ifdef HAVE_VSNPRINTF
++ va_list args;
++ gint retval;
++
++ g_return_val_if_fail (str != NULL, 0);
++ g_return_val_if_fail (n > 0, 0);
++ g_return_val_if_fail (fmt != NULL, 0);
++
++ va_start (args, fmt);
++ retval = vsnprintf (str, n, fmt, args);
++ va_end (args);
++
++ if (retval < 0)
++ {
++ str[n-1] = '\0';
++ retval = strlen (str);
++ }
++
++ return retval;
++#else /* !HAVE_VSNPRINTF */
++ gchar *printed;
++ va_list args;
++
++ g_return_val_if_fail (str != NULL, 0);
++ g_return_val_if_fail (n > 0, 0);
++ g_return_val_if_fail (fmt != NULL, 0);
++
++ va_start (args, fmt);
++ printed = g_strdup_vprintf (fmt, args);
++ va_end (args);
++
++ strncpy (str, printed, n);
++ str[n-1] = '\0';
++
++ g_free (printed);
++
++ return strlen (str);
++#endif /* !HAVE_VSNPRINTF */
++}
++
++gint
++g_vsnprintf (gchar *str,
++ gulong n,
++ gchar const *fmt,
++ va_list args)
++{
++#ifdef HAVE_VSNPRINTF
++ gint retval;
++
++ g_return_val_if_fail (str != NULL, 0);
++ g_return_val_if_fail (n > 0, 0);
++ g_return_val_if_fail (fmt != NULL, 0);
++
++ retval = vsnprintf (str, n, fmt, args);
++
++ if (retval < 0)
++ {
++ str[n-1] = '\0';
++ retval = strlen (str);
++ }
++
++ return retval;
++#else /* !HAVE_VSNPRINTF */
++ gchar *printed;
++
++ g_return_val_if_fail (str != NULL, 0);
++ g_return_val_if_fail (n > 0, 0);
++ g_return_val_if_fail (fmt != NULL, 0);
++
++ printed = g_strdup_vprintf (fmt, args);
++ strncpy (str, printed, n);
++ str[n-1] = '\0';
++
++ g_free (printed);
++
++ return strlen (str);
++#endif /* !HAVE_VSNPRINTF */
++}
++
++guint
++g_parse_debug_string (const gchar *string,
++ GDebugKey *keys,
++ guint nkeys)
++{
++ guint i;
++ guint result = 0;
++
++ g_return_val_if_fail (string != NULL, 0);
++
++ if (!g_strcasecmp (string, "all"))
++ {
++ for (i=0; i<nkeys; i++)
++ result |= keys[i].value;
++ }
++ else
++ {
++ gchar *str = g_strdup (string);
++ gchar *p = str;
++ gchar *q;
++ gboolean done = FALSE;
++
++ while (*p && !done)
++ {
++ q = strchr (p, ':');
++ if (!q)
++ {
++ q = p + strlen(p);
++ done = TRUE;
++ }
++
++ *q = 0;
++
++ for (i=0; i<nkeys; i++)
++ if (!g_strcasecmp(keys[i].key, p))
++ result |= keys[i].value;
++
++ p = q+1;
++ }
++
++ g_free (str);
++ }
++
++ return result;
++}
++
++gchar*
++g_basename (const gchar *file_name)
++{
++ register gchar *base;
++
++ g_return_val_if_fail (file_name != NULL, NULL);
++
++ base = strrchr (file_name, G_DIR_SEPARATOR);
++ if (base)
++ return base + 1;
++
++#ifdef NATIVE_WIN32
++ if (isalpha (file_name[0]) && file_name[1] == ':')
++ return (gchar*) file_name + 2;
++#endif /* NATIVE_WIN32 */
++
++ return (gchar*) file_name;
++}
++
++gboolean
++g_path_is_absolute (const gchar *file_name)
++{
++ g_return_val_if_fail (file_name != NULL, FALSE);
++
++ if (file_name[0] == G_DIR_SEPARATOR)
++ return TRUE;
++
++#ifdef NATIVE_WIN32
++ if (isalpha (file_name[0]) && file_name[1] == ':' && file_name[2] == G_DIR_SEPARATOR)
++ return TRUE;
++#endif
++
++ return FALSE;
++}
++
++gchar*
++g_path_skip_root (gchar *file_name)
++{
++ g_return_val_if_fail (file_name != NULL, NULL);
++
++ if (file_name[0] == G_DIR_SEPARATOR)
++ return file_name + 1;
++
++#ifdef NATIVE_WIN32
++ if (isalpha (file_name[0]) && file_name[1] == ':' && file_name[2] == G_DIR_SEPARATOR)
++ return file_name + 3;
++#endif
++
++ return NULL;
++}
++
++gchar*
++g_dirname (const gchar *file_name)
++{
++ register gchar *base;
++ register guint len;
++
++ g_return_val_if_fail (file_name != NULL, NULL);
++
++ base = strrchr (file_name, G_DIR_SEPARATOR);
++ if (!base)
++ return g_strdup (".");
++ while (base > file_name && *base == G_DIR_SEPARATOR)
++ base--;
++ len = (guint) 1 + base - file_name;
++
++ base = g_new (gchar, len + 1);
++ g_memmove (base, file_name, len);
++ base[len] = 0;
++
++ return base;
++}
++
++#ifndef __KORBIT__
++gchar*
++g_get_current_dir (void)
++{
++ gchar *buffer;
++ gchar *dir;
++
++ buffer = g_new (gchar, G_PATH_LENGTH);
++ *buffer = 0;
++
++ /* We don't use getcwd(3) on SUNOS, because, it does a popen("pwd")
++ * and, if that wasn't bad enough, hangs in doing so.
++ */
++#if defined (sun) && !defined (__SVR4)
++ dir = getwd (buffer);
++#else /* !sun */
++ dir = getcwd (buffer, G_PATH_LENGTH - 1);
++#endif /* !sun */
++
++ if (!dir || !*buffer)
++ {
++ /* hm, should we g_error() out here?
++ * this can happen if e.g. "./" has mode \0000
++ */
++ buffer[0] = G_DIR_SEPARATOR;
++ buffer[1] = 0;
++ }
++
++ dir = g_strdup (buffer);
++ g_free (buffer);
++
++ return dir;
++}
++#endif /* !__KORBIT__ */
++
++gchar*
++g_getenv (const gchar *variable)
++{
++#ifndef NATIVE_WIN32
++ g_return_val_if_fail (variable != NULL, NULL);
++
++ return getenv (variable);
++#else
++ gchar *v;
++ guint k;
++ static gchar *p = NULL;
++ static gint l;
++ gchar dummy[2];
++
++ g_return_val_if_fail (variable != NULL, NULL);
++
++ v = getenv (variable);
++ if (!v)
++ return NULL;
++
++ /* On Windows NT, it is relatively typical that environment variables
++ * contain references to other environment variables. Handle that by
++ * calling ExpandEnvironmentStrings.
++ */
++
++ /* First check how much space we need */
++ k = ExpandEnvironmentStrings (v, dummy, 2);
++ /* Then allocate that much, and actualy do the expansion */
++ if (p == NULL)
++ {
++ p = g_malloc (k);
++ l = k;
++ }
++ else if (k > l)
++ {
++ p = g_realloc (p, k);
++ l = k;
++ }
++ ExpandEnvironmentStrings (v, p, k);
++ return p;
++#endif
++}
++
++
++G_LOCK_DEFINE_STATIC (g_utils_global);
++
++static gchar *g_tmp_dir = NULL;
++static gchar *g_user_name = NULL;
++static gchar *g_real_name = NULL;
++static gchar *g_home_dir = NULL;
++
++/* HOLDS: g_utils_global_lock */
++static void
++g_get_any_init (void)
++{
++ if (!g_tmp_dir)
++ {
++ g_tmp_dir = g_strdup (g_getenv ("TMPDIR"));
++ if (!g_tmp_dir)
++ g_tmp_dir = g_strdup (g_getenv ("TMP"));
++ if (!g_tmp_dir)
++ g_tmp_dir = g_strdup (g_getenv ("TEMP"));
++
++#ifdef P_tmpdir
++ if (!g_tmp_dir)
++ {
++ int k;
++ g_tmp_dir = g_strdup (P_tmpdir);
++ k = strlen (g_tmp_dir);
++ if (g_tmp_dir[k-1] == G_DIR_SEPARATOR)
++ g_tmp_dir[k-1] = '\0';
++ }
++#endif
++
++ if (!g_tmp_dir)
++ {
++#ifndef NATIVE_WIN32
++ g_tmp_dir = g_strdup ("/tmp");
++#else /* NATIVE_WIN32 */
++ g_tmp_dir = g_strdup ("C:\\");
++#endif /* NATIVE_WIN32 */
++ }
++
++ if (!g_home_dir)
++ g_home_dir = g_strdup (g_getenv ("HOME"));
++
++#ifdef NATIVE_WIN32
++ if (!g_home_dir)
++ {
++ /* The official way to specify a home directory on NT is
++ * the HOMEDRIVE and HOMEPATH environment variables.
++ *
++ * This is inside #ifdef NATIVE_WIN32 because with the cygwin dll,
++ * HOME should be a POSIX style pathname.
++ */
++
++ if (getenv ("HOMEDRIVE") != NULL && getenv ("HOMEPATH") != NULL)
++ {
++ gchar *homedrive, *homepath;
++
++ homedrive = g_strdup (g_getenv ("HOMEDRIVE"));
++ homepath = g_strdup (g_getenv ("HOMEPATH"));
++
++ g_home_dir = g_strconcat (homedrive, homepath, NULL);
++ g_free (homedrive);
++ g_free (homepath);
++ }
++ }
++#endif /* !NATIVE_WIN32 */
++
++#ifdef HAVE_PWD_H
++ {
++ struct passwd *pw = NULL;
++ gpointer buffer = NULL;
++
++# ifdef HAVE_GETPWUID_R
++ struct passwd pwd;
++ guint bufsize = 64;
++ gint error;
++
++ do
++ {
++ g_free (buffer);
++ buffer = g_malloc (bufsize);
++ errno = 0;
++
++# ifdef HAVE_GETPWUID_R_POSIX
++ error = getpwuid_r (getuid (), &pwd, buffer, bufsize, &pw);
++ error = error < 0 ? errno : error;
++# else /* !HAVE_GETPWUID_R_POSIX */
++# ifdef _AIX
++ error = getpwuid_r (getuid (), &pwd, buffer, bufsize);
++ pw = error == 0 ? &pwd : NULL;
++# else /* !_AIX */
++ pw = getpwuid_r (getuid (), &pwd, buffer, bufsize);
++ error = pw ? 0 : errno;
++# endif /* !_AIX */
++# endif /* !HAVE_GETPWUID_R_POSIX */
++
++ if (!pw)
++ {
++ /* we bail out prematurely if the user id can't be found
++ * (should be pretty rare case actually), or if the buffer
++ * should be sufficiently big and lookups are still not
++ * successfull.
++ */
++ if (error == 0 || error == ENOENT)
++ {
++ g_warning ("getpwuid_r(): failed due to: No such user %d.",
++ getuid ());
++ break;
++ }
++ if (bufsize > 32 * 1024)
++ {
++ g_warning ("getpwuid_r(): failed due to: %s.",
++ g_strerror (error));
++ break;
++ }
++
++ bufsize *= 2;
++ }
++ }
++ while (!pw);
++# endif /* !HAVE_GETPWUID_R */
++
++ if (!pw)
++ {
++ setpwent ();
++ pw = getpwuid (getuid ());
++ endpwent ();
++ }
++ if (pw)
++ {
++ g_user_name = g_strdup (pw->pw_name);
++ g_real_name = g_strdup (pw->pw_gecos);
++ if (!g_home_dir)
++ g_home_dir = g_strdup (pw->pw_dir);
++ }
++ g_free (buffer);
++ }
++
++#else /* !HAVE_PWD_H */
++
++# ifdef NATIVE_WIN32
++ {
++ guint len = 17;
++ gchar buffer[17];
++
++ if (GetUserName (buffer, &len))
++ {
++ g_user_name = g_strdup (buffer);
++ g_real_name = g_strdup (buffer);
++ }
++ }
++# endif /* NATIVE_WIN32 */
++
++#endif /* !HAVE_PWD_H */
++
++ if (!g_user_name)
++ g_user_name = g_strdup ("somebody");
++ if (!g_real_name)
++ g_real_name = g_strdup ("Unknown");
++ else
++ {
++ gchar *p;
++
++ for (p = g_real_name; *p; p++)
++ if (*p == ',')
++ {
++ *p = 0;
++ p = g_strdup (g_real_name);
++ g_free (g_real_name);
++ g_real_name = p;
++ break;
++ }
++ }
++ }
++}
++
++gchar*
++g_get_user_name (void)
++{
++ G_LOCK (g_utils_global);
++ if (!g_tmp_dir)
++ g_get_any_init ();
++ G_UNLOCK (g_utils_global);
++
++ return g_user_name;
++}
++
++gchar*
++g_get_real_name (void)
++{
++ G_LOCK (g_utils_global);
++ if (!g_tmp_dir)
++ g_get_any_init ();
++ G_UNLOCK (g_utils_global);
++
++ return g_real_name;
++}
++
++/* Return the home directory of the user. If there is a HOME
++ * environment variable, its value is returned, otherwise use some
++ * system-dependent way of finding it out. If no home directory can be
++ * deduced, return NULL.
++ */
++
++gchar*
++g_get_home_dir (void)
++{
++ G_LOCK (g_utils_global);
++ if (!g_tmp_dir)
++ g_get_any_init ();
++ G_UNLOCK (g_utils_global);
++
++ return g_home_dir;
++}
++
++/* Return a directory to be used to store temporary files. This is the
++ * value of the TMPDIR, TMP or TEMP environment variables (they are
++ * checked in that order). If none of those exist, use P_tmpdir from
++ * stdio.h. If that isn't defined, return "/tmp" on POSIXly systems,
++ * and C:\ on Windows.
++ */
++
++gchar*
++g_get_tmp_dir (void)
++{
++ G_LOCK (g_utils_global);
++ if (!g_tmp_dir)
++ g_get_any_init ();
++ G_UNLOCK (g_utils_global);
++
++ return g_tmp_dir;
++}
++
++static gchar *g_prgname = NULL;
++
++gchar*
++g_get_prgname (void)
++{
++ gchar* retval;
++
++ G_LOCK (g_utils_global);
++ retval = g_prgname;
++ G_UNLOCK (g_utils_global);
++
++ return retval;
++}
++
++void
++g_set_prgname (const gchar *prgname)
++{
++ gchar *c;
++
++ G_LOCK (g_utils_global);
++ c = g_prgname;
++ g_prgname = g_strdup (prgname);
++ g_free (c);
++ G_UNLOCK (g_utils_global);
++}
++
++guint
++g_direct_hash (gconstpointer v)
++{
++ return GPOINTER_TO_UINT (v);
++}
++
++gint
++g_direct_equal (gconstpointer v1,
++ gconstpointer v2)
++{
++ return v1 == v2;
++}
++
++gint
++g_int_equal (gconstpointer v1,
++ gconstpointer v2)
++{
++ return *((const gint*) v1) == *((const gint*) v2);
++}
++
++guint
++g_int_hash (gconstpointer v)
++{
++ return *(const gint*) v;
++}
++
++#if 0 /* Old IO Channels */
++
++GIOChannel*
++g_iochannel_new (gint fd)
++{
++ GIOChannel *channel = g_new (GIOChannel, 1);
++
++ channel->fd = fd;
++
++#ifdef NATIVE_WIN32
++ channel->peer = 0;
++ channel->peer_fd = 0;
++ channel->offset = 0;
++ channel->need_wakeups = 0;
++#endif /* NATIVE_WIN32 */
++
++ return channel;
++}
++
++void
++g_iochannel_free (GIOChannel *channel)
++{
++ g_return_if_fail (channel != NULL);
++
++ g_free (channel);
++}
++
++void
++g_iochannel_close_and_free (GIOChannel *channel)
++{
++ g_return_if_fail (channel != NULL);
++
++ close (channel->fd);
++
++ g_iochannel_free (channel);
++}
++
++#undef g_iochannel_wakeup_peer
++
++void
++g_iochannel_wakeup_peer (GIOChannel *channel)
++{
++#ifdef NATIVE_WIN32
++ static guint message = 0;
++#endif
++
++ g_return_if_fail (channel != NULL);
++
++#ifdef NATIVE_WIN32
++ if (message == 0)
++ message = RegisterWindowMessage ("gdk-pipe-readable");
++
++# if 0
++ g_print ("g_iochannel_wakeup_peer: calling PostThreadMessage (%#x, %d, %d, %d)\n",
++ channel->peer, message, channel->peer_fd, channel->offset);
++# endif
++ PostThreadMessage (channel->peer, message,
++ channel->peer_fd, channel->offset);
++#endif /* NATIVE_WIN32 */
++}
++
++#endif /* Old IO Channels */
++
++#ifdef NATIVE_WIN32
++#ifdef _MSC_VER
++
++int
++gwin_ftruncate (gint fd,
++ guint size)
++{
++ HANDLE hfile;
++ guint curpos;
++
++ g_return_val_if_fail (fd >= 0, -1);
++
++ hfile = (HANDLE) _get_osfhandle (fd);
++ curpos = SetFilePointer (hfile, 0, NULL, FILE_CURRENT);
++ if (curpos == 0xFFFFFFFF
++ || SetFilePointer (hfile, size, NULL, FILE_BEGIN) == 0xFFFFFFFF
++ || !SetEndOfFile (hfile))
++ {
++ gint error = GetLastError ();
++
++ switch (error)
++ {
++ case ERROR_INVALID_HANDLE:
++ errno = EBADF;
++ break;
++ default:
++ errno = EIO;
++ break;
++ }
++
++ return -1;
++ }
++
++ return 0;
++}
++
++DIR*
++gwin_opendir (const char *dirname)
++{
++ DIR *result;
++ gchar *mask;
++ guint k;
++
++ g_return_val_if_fail (dirname != NULL, NULL);
++
++ result = g_new0 (DIR, 1);
++ result->find_file_data = g_new0 (WIN32_FIND_DATA, 1);
++ result->dir_name = g_strdup (dirname);
++
++ k = strlen (result->dir_name);
++ if (k && result->dir_name[k - 1] == '\\')
++ {
++ result->dir_name[k - 1] = '\0';
++ k--;
++ }
++ mask = g_strdup_printf ("%s\\*", result->dir_name);
++
++ result->find_file_handle = (guint) FindFirstFile (mask,
++ (LPWIN32_FIND_DATA) result->find_file_data);
++ g_free (mask);
++
++ if (result->find_file_handle == (guint) INVALID_HANDLE_VALUE)
++ {
++ int error = GetLastError ();
++
++ g_free (result->dir_name);
++ g_free (result->find_file_data);
++ g_free (result);
++ switch (error)
++ {
++ default:
++ errno = EIO;
++ return NULL;
++ }
++ }
++ result->just_opened = TRUE;
++
++ return result;
++}
++
++struct dirent*
++gwin_readdir (DIR *dir)
++{
++ static struct dirent result;
++
++ g_return_val_if_fail (dir != NULL, NULL);
++
++ if (dir->just_opened)
++ dir->just_opened = FALSE;
++ else
++ {
++ if (!FindNextFile ((HANDLE) dir->find_file_handle,
++ (LPWIN32_FIND_DATA) dir->find_file_data))
++ {
++ int error = GetLastError ();
++
++ switch (error)
++ {
++ case ERROR_NO_MORE_FILES:
++ return NULL;
++ default:
++ errno = EIO;
++ return NULL;
++ }
++ }
++ }
++ strcpy (result.d_name, g_basename (((LPWIN32_FIND_DATA) dir->find_file_data)->cFileName));
++
++ return &result;
++}
++
++void
++gwin_rewinddir (DIR *dir)
++{
++ gchar *mask;
++
++ g_return_if_fail (dir != NULL);
++
++ if (!FindClose ((HANDLE) dir->find_file_handle))
++ g_warning ("gwin_rewinddir(): FindClose() failed\n");
++
++ mask = g_strdup_printf ("%s\\*", dir->dir_name);
++ dir->find_file_handle = (guint) FindFirstFile (mask,
++ (LPWIN32_FIND_DATA) dir->find_file_data);
++ g_free (mask);
++
++ if (dir->find_file_handle == (guint) INVALID_HANDLE_VALUE)
++ {
++ int error = GetLastError ();
++
++ switch (error)
++ {
++ default:
++ errno = EIO;
++ return;
++ }
++ }
++ dir->just_opened = TRUE;
++}
++
++gint
++gwin_closedir (DIR *dir)
++{
++ g_return_val_if_fail (dir != NULL, -1);
++
++ if (!FindClose ((HANDLE) dir->find_file_handle))
++ {
++ int error = GetLastError ();
++
++ switch (error)
++ {
++ default:
++ errno = EIO; return -1;
++ }
++ }
++
++ g_free (dir->dir_name);
++ g_free (dir->find_file_data);
++ g_free (dir);
++
++ return 0;
++}
++
++#endif /* _MSC_VER */
++
++#endif /* NATIVE_WIN32 */
+diff -urN linux-2.4.1/net/korbit/kglib/korbit_errno.c linux-2.4.1-korbit/net/korbit/kglib/korbit_errno.c
+--- linux-2.4.1/net/korbit/kglib/korbit_errno.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/kglib/korbit_errno.c Thu Feb 1 11:46:57 2001
+@@ -0,0 +1 @@
++int korbit_errno;
+diff -urN linux-2.4.1/net/korbit/korbit.h linux-2.4.1-korbit/net/korbit/korbit.h
+--- linux-2.4.1/net/korbit/korbit.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/korbit.h Thu Feb 1 11:46:49 2001
+@@ -0,0 +1,53 @@
++
++#ifndef KORBIT_H
++#define KORBIT_H
++
++#ifdef __KERNEL__
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/proc_fs.h>
++#endif
++
++#include "stdlib.h"
++
++#ifdef __KERNEL__
++static int korbit_get_ior_func(char *buffer, char **start, off_t offset,
++ int length, int *eof, void *data) {
++ int Len = strlen((char*)data);
++ memcpy(buffer, data, Len); // Data is the ior...
++ buffer[Len++] = '\n'; // Add a newline to make fredrik happy
++ buffer[Len] = 0; // Null terminate the buffer...
++ *start = buffer + offset;
++ *eof = 1;
++
++ Len -= offset;
++ if (Len > length)
++ Len = length;
++ if (Len < 0)
++ Len = 0;
++
++ return Len;
++}
++
++#endif
++
++
++static inline void korbit_register_ior(const char *name, CORBA_Object obj,
++ CORBA_ORB orb, CORBA_Environment *ev) {
++ char *retval = CORBA_ORB_object_to_string(orb, obj, ev);
++#if defined(__KERNEL__) && defined(CONFIG_PROC_FS)
++ char *procdirname = malloc(strlen(name)+7); // 7 = len("corba/\0")
++ strcpy(procdirname, "corba/");
++ strcpy(procdirname+6, name);
++
++ create_proc_read_entry(procdirname, 0, 0, korbit_get_ior_func, retval);
++
++ free(procdirname);
++ // Don't free the ior in the /proc handling case...
++#else
++ // No procfs support, just print to console... :(
++ g_print("%s IOR:\n%s\n", name, retval);
++ CORBA_free(retval);
++#endif
++}
++#endif
+diff -urN linux-2.4.1/net/korbit/modules/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CVS/Entries Thu Feb 1 11:46:58 2001
+@@ -0,0 +1,5 @@
++/Config.in/1.8/Thu Feb 1 09:46:58 2001//
++/Makefile/1.8/Thu Feb 1 09:46:58 2001//
++/Makefile.module/1.2/Thu Feb 1 09:46:58 2001//
++/README/1.1/Thu Feb 1 09:46:58 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/CVS/Entries.Log
+--- linux-2.4.1/net/korbit/modules/CVS/Entries.Log Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CVS/Entries.Log Thu Feb 1 11:47:09 2001
+@@ -0,0 +1,6 @@
++A D/CharDev////
++A D/Console////
++A D/CorbaFS////
++A D/Echo////
++A D/FileServer////
++A D/UserFS////
+diff -urN linux-2.4.1/net/korbit/modules/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CVS/Repository Thu Feb 1 11:46:57 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules
+diff -urN linux-2.4.1/net/korbit/modules/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CVS/Root
+--- linux-2.4.1/net/korbit/modules/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CVS/Root Thu Feb 1 11:46:57 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/CharDev/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Entries Thu Feb 1 11:46:58 2001
+@@ -0,0 +1,4 @@
++/Makefile/1.3/Thu Feb 1 09:46:58 2001//
++/README/1.1/Thu Feb 1 09:46:58 2001//
++/chardev.idl/1.1/Thu Feb 1 09:46:58 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Entries.Log
+--- linux-2.4.1/net/korbit/modules/CharDev/CVS/Entries.Log Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Entries.Log Thu Feb 1 11:47:00 2001
+@@ -0,0 +1,3 @@
++A D/kernel////
++A D/kernel-perl////
++A D/userspace////
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/CharDev/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Repository Thu Feb 1 11:46:58 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/CharDev
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Root
+--- linux-2.4.1/net/korbit/modules/CharDev/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Root Thu Feb 1 11:46:58 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/Makefile linux-2.4.1-korbit/net/korbit/modules/CharDev/Makefile
+--- linux-2.4.1/net/korbit/modules/CharDev/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/Makefile Thu Feb 1 11:46:58 2001
+@@ -0,0 +1,11 @@
++#
++# Makefile for KORBit - CharDev
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++
++subdir-$(CONFIG_CORBA_CHARDEV) := kernel
++
++include $(TOPDIR)/Rules.make
++
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/README linux-2.4.1-korbit/net/korbit/modules/CharDev/README
+--- linux-2.4.1/net/korbit/modules/CharDev/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/README Thu Feb 1 11:46:58 2001
+@@ -0,0 +1 @@
++This module is used to implement a character device with kORBit.
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/chardev.idl linux-2.4.1-korbit/net/korbit/modules/CharDev/chardev.idl
+--- linux-2.4.1/net/korbit/modules/CharDev/chardev.idl Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/chardev.idl Thu Feb 1 11:46:58 2001
+@@ -0,0 +1,5 @@
++typedef sequence<octet> Buffer;
++
++interface CharDev {
++ long read(out Buffer buffer, in long size);
++};
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/CVS/Entries Thu Feb 1 11:46:59 2001
+@@ -0,0 +1,4 @@
++/Makefile/1.2/Thu Feb 1 09:46:59 2001//
++/README/1.2/Thu Feb 1 09:46:59 2001//
++/chardev-kernel.c/1.9/Thu Feb 1 09:46:59 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/CVS/Repository Thu Feb 1 11:46:59 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/CharDev/kernel
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/CVS/Root
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/CVS/Root Thu Feb 1 11:46:59 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel/Makefile linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/Makefile
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/Makefile Thu Feb 1 11:46:59 2001
+@@ -0,0 +1,20 @@
++#
++# Makefile for KORBit / chardev
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := corba-chardev-kernel.o
++
++obj-y := chardev-common.o chardev-stubs.o chardev-kernel.o
++obj-m := $(O_TARGET)
++
++include ../../Makefile.module
++
++chardev-kernel.c: chardev.h
++
++chardev.h chardev-stubs.c chardev-common.c: ../chardev.idl
++ $(ORBIT_IDL) ../chardev.idl
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel/README linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/README
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/README Thu Feb 1 11:46:59 2001
+@@ -0,0 +1,5 @@
++This module is used to implement the kernel side of the CORBA Character
++device.
++
++ORB: kORBit
++Status: Working!!!
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel/chardev-kernel.c linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/chardev-kernel.c
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel/chardev-kernel.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/chardev-kernel.c Thu Feb 1 11:46:59 2001
+@@ -0,0 +1,140 @@
++//-----------------------------------------------------------------------------
++//
++// chardev-kernel - Kernel miscdevice to CORBA glue.
++//
++// This file implements a standard Linux Kernel "miscdevice". This device
++// operates by forwarding all calls across to a remote CORBA server. This
++// server is located by reading the file /tmp/chardev-ior at the time the
++// device is opened. The device exported is major #10, minor #42. Create this
++// device with 'mknod' like all the others.
++//
++// No implementations of CORBA functions should block, although I think it
++// might be just fine, I'm not sure. Let's just make this a TODO. :) -CAL
++//
++// TODO: Locking, finish exporting all "miscdevice" functions, send position
++// on READ request.
++//
++// History:
++// Keith Wessel - Initial hack, initial idea
++// Andy Reitz - Get it to compile
++// Chris Lattner - Make it work. :)
++//
++//-----------------------------------------------------------------------------
++
++
++#include "chardev.h"
++#include <stdio.h>
++#include "orb/orbit.h"
++#include "korbit.h"
++#include <linux/miscdevice.h>
++
++#define DEV_MINOR 42
++
++CORBA_ORB orb;
++CORBA_Environment *ev;
++
++static int open_dev(struct inode *inode, struct file *file) {
++ char *iorstr = (char *)malloc(10240);
++ int error = -EINVAL;
++ int fd, len;
++
++ if (iorstr == 0) return -ENOMEM;
++
++ if ((fd = open ("/tmp/chardev-ior", O_RDONLY, 0)) == -1) {
++ printk("kORBit: chararacter driver couldn't open /tmp/chardev-ior!\n");
++ goto outfree;
++ }
++
++ len = read(fd, iorstr, 10240);
++ close(fd);
++ if (len == -1)
++ goto outfree;
++
++ iorstr[len] = 0; // Null terminate string!
++
++ printk("CharDEV IOR String = %s\n", iorstr);
++ file->private_data = (void*)CORBA_ORB_string_to_object(orb, iorstr, ev);
++ if (!file->private_data)
++ goto outfree;
++
++ // TODO: Send create_dev message out over CORBA
++
++ error = 0;
++ outfree:
++ free(iorstr);
++ return error;
++}
++
++static int release_dev(struct inode *inode, struct file *file) {
++ // TODO: Send release_dev message out over CORBA...
++ if (file->private_data)
++ CORBA_free(file->private_data);
++ return 0;
++}
++
++
++static ssize_t read_dev(struct file * file, char * buf, size_t count,
++ loff_t *ppos) {
++ Buffer *octet_buffer = NULL;
++ if (!file->private_data) return -EINVAL;
++ if (!count) return 0;
++
++ if (!access_ok(VERIFY_WRITE, buf, count))
++ return -EFAULT;
++
++ CharDev_read(file->private_data, &octet_buffer, count, ev);
++
++ if (!octet_buffer)
++ return -EPERM;
++
++ if (copy_to_user(buf, octet_buffer->_buffer, octet_buffer->_length))
++ return -EFAULT;
++
++ // TODO: Should free octet_buffer here!?!?!?
++
++ return octet_buffer->_length;
++}
++
++
++//-----------------------------------------------------------------------------
++// Kernel Callbacks for miscdevice
++//-----------------------------------------------------------------------------
++
++
++static struct file_operations dev_fops = {
++ owner: THIS_MODULE,
++ open: open_dev,
++ read: read_dev,
++ release: release_dev,
++ // mmap: mmap_dev,
++ // llseek: llseek_dev,
++ // write: write_dev,
++};
++
++static struct miscdevice cdev = {
++ DEV_MINOR,
++ "CORBA Character device",
++ &dev_fops
++};
++
++
++//-----------------------------------------------------------------------------
++// Module Initializion/Finalization
++//-----------------------------------------------------------------------------
++
++static int __init CharDev_init(void) {
++ int argc = 1;
++ char *argv[] = { "CharDev-kernel", 0 };
++ ev = g_new0(CORBA_Environment,1);
++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev);
++
++ // Register the device
++ return misc_register(&cdev);
++}
++
++static void __exit CharDev_exit(void) {
++ misc_deregister(&cdev);
++}
++
++module_init(CharDev_init)
++module_exit(CharDev_exit)
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/CVS/Entries Thu Feb 1 11:46:59 2001
+@@ -0,0 +1,3 @@
++/PerlTest/1.1/Thu Feb 1 09:46:59 2001//
++/README/1.1/Thu Feb 1 09:46:59 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/CVS/Repository Thu Feb 1 11:46:59 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/CharDev/kernel-perl
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/CVS/Root
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/CVS/Root Thu Feb 1 11:46:59 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/PerlTest linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/PerlTest
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/PerlTest Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/PerlTest Thu Feb 1 11:46:59 2001
+@@ -0,0 +1,17 @@
++#!/usr/bin/perl -w
++
++use CORBA::ORBit idl => [ qw(../chardev.idl) ];
++use Error qw(:try);
++use strict;
++
++my $orb = CORBA::ORB_init("orbit-local-orb");
++open IOR, "/tmp/chardev-ior" or die "no chardev server found!";
++my $ior = <IOR>;
++close IOR;
++#chomp($ior); # Kill fredrik's newline...
++
++my $chardev = $orb->string_to_object($ior);
++# Echo echoString(in string astring, out long anum);
++my ($ressize, $buf) = $chardev->read(10);
++
++print "Return size = $ressize\nresult = $buf\n";
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/README linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/README
+--- linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/README Thu Feb 1 11:46:59 2001
+@@ -0,0 +1,6 @@
++This module is used to test the user side of the CORBA Character
++device. It doesn't do anything really complex, just implements a quick
++sanity test for the server.
++
++ORB: ORBit - Perl
++Status: Working!
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/CharDev/userspace/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/CVS/Entries Thu Feb 1 11:47:00 2001
+@@ -0,0 +1,6 @@
++/Makefile/1.5/Thu Feb 1 09:47:00 2001//
++/README/1.1/Thu Feb 1 09:47:00 2001//
++/RunServer.sh/1.1/Thu Feb 1 09:47:00 2001//
++/chardev-server.c/1.5/Thu Feb 1 09:47:00 2001//
++/chardev-skelimpl.c/1.5/Thu Feb 1 09:47:00 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/CharDev/userspace/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/CVS/Repository Thu Feb 1 11:47:00 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/CharDev/userspace
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/CVS/Root
+--- linux-2.4.1/net/korbit/modules/CharDev/userspace/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/CVS/Root Thu Feb 1 11:47:00 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/Makefile linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/Makefile
+--- linux-2.4.1/net/korbit/modules/CharDev/userspace/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/Makefile Thu Feb 1 11:47:00 2001
+@@ -0,0 +1,30 @@
++#
++# Makefile for KORBit / CharDev
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++CFLAGS = -Wall -I/usr/lib/glib/include
++LDFLAGS = -lORBit -lIIOP -lORBitutil
++OBJS = chardev-common.o chardev-skels.o chardev-server.o
++ORBIT-IDL = /usr/bin/orbit-idl
++
++chardev-server: $(OBJS)
++ gcc -o chardev-server $(OBJS) $(LDFLAGS)
++
++chardev-server.o: chardev.h chardev-skelimpl.c
++
++chardev.h chardev-skels.c chardev-common.c: ../chardev.idl
++ $(ORBIT-IDL) ../chardev.idl
++
++chardev-skelimpl.c:
++
++%.o: %.c
++ gcc -c $< $(CFLAGS)
++clean:
++ rm -f $(OBJS) chardev-server chardev-common.c chardev-skels.c \
++ chardev-stubs.c chardev.h
++
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/README linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/README
+--- linux-2.4.1/net/korbit/modules/CharDev/userspace/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/README Thu Feb 1 11:47:00 2001
+@@ -0,0 +1,4 @@
++This is an example character driver.
++
++ORB: ORBit
++Status: not yet working
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/RunServer.sh linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/RunServer.sh
+--- linux-2.4.1/net/korbit/modules/CharDev/userspace/RunServer.sh Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/RunServer.sh Thu Feb 1 11:47:00 2001
+@@ -0,0 +1 @@
++./chardev-server -ORBIIOPUSock=0 -ORBIIOPIPv4=1
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/chardev-server.c linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/chardev-server.c
+--- linux-2.4.1/net/korbit/modules/CharDev/userspace/chardev-server.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/chardev-server.c Thu Feb 1 11:47:00 2001
+@@ -0,0 +1,77 @@
++//-----------------------------------------------------------------------------
++//
++// chardev-server.c - TEST Kernel miscdevice implementation
++//
++// This file implements the standard server code for a userspace server. This
++// is basically cut and paste boilerplate code adapted from the CorbaFS server
++// by Fredrik Vraalsen.
++//
++// TODO: Locking, finish exporting all "miscdevice" functions, send position
++// on READ request.
++//
++// History:
++// Keith Wessel - Initial hack, initial idea
++// Andy Reitz - Get it to compile
++// Chris Lattner - Hack'n'slash, make it work, comment it, kill warnings.
++//
++//-----------------------------------------------------------------------------
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <signal.h>
++#include <orb/orbit.h>
++
++// #include the C file because all the functions are static. Bizarre.
++#include "chardev-skelimpl.c"
++
++int main(int argc, char *argv[]) {
++ PortableServer_POA poa;
++ PortableServer_POAManager pm;
++
++ CharDev chardev = CORBA_OBJECT_NIL;
++ impl_POA_CharDev *chardev_impl;
++ PortableServer_ObjectId *objid;
++
++ CORBA_Environment ev;
++ char *retval;
++ CORBA_ORB orb;
++ FILE *IORFILE;
++
++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", &ev);
++ poa = (PortableServer_POA)CORBA_ORB_resolve_initial_references(orb, "RootPOA", &ev);
++
++ chardev = impl_CharDev__create(poa, &ev);
++ pm = PortableServer_POA__get_the_POAManager(poa, &ev);
++ PortableServer_POAManager_activate(pm, &ev);
++
++ if (!chardev) {
++ printf("Cannot get objref\n");
++ return 1;
++ }
++
++ chardev_impl = PortableServer_POA_reference_to_servant(poa, chardev, &ev);
++ objid = PortableServer_POA_servant_to_id(poa, chardev_impl, &ev);
++
++ retval = CORBA_ORB_object_to_string(orb, chardev, &ev);
++
++ g_print("FYI, this also goes into /tmp/chardev-ior for you.\n");
++ g_print("%s\n", retval); fflush(stdout);
++
++ IORFILE = fopen ("/tmp/chardev-ior", "w");
++ if (IORFILE == NULL) {
++ perror("ERROR: IOR_WRITE_TO_DISK");
++ exit(1);
++ }
++
++ fprintf(IORFILE, "%s", retval);
++ fclose(IORFILE);
++
++ CORBA_free(retval); // Free the corba string like a good little CORBear
++
++
++ // La dee dah... I will never return for you mister.
++ CORBA_ORB_run(orb, &ev);
++ return 0;
++}
++
+diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/chardev-skelimpl.c linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/chardev-skelimpl.c
+--- linux-2.4.1/net/korbit/modules/CharDev/userspace/chardev-skelimpl.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/chardev-skelimpl.c Thu Feb 1 11:47:00 2001
+@@ -0,0 +1,119 @@
++//-----------------------------------------------------------------------------
++//
++// chardev-skelimpl.c - TEST Kernel miscdevice implementation
++//
++// This file implements a CORBA "miscdevice" (character device node).
++// This device simply outputs a fixed string (set by "message", below) when
++// cat'd. Pretty simple stuff, but you can obviously do much more creative
++// things with it.
++//
++// TODO: Locking, finish exporting all "miscdevice" functions, send position
++// on READ request.
++//
++// Right now we have ONE server object with global state, so that when you
++// read the string from that object, it is finished. This should be reset
++// whenever an open request is had or when the file position is reset (duh).
++//
++// History:
++// Keith Wessel - Initial hack, initial idea
++// Andy Reitz - Get it to compile
++// Chris Lattner - Make it work, comment it, no warnings.
++//
++//-----------------------------------------------------------------------------
++
++#include "chardev.h"
++
++// The message to spit out.
++const char *message = "Hello world!\nI love kORBit\n";
++
++
++/*** App-specific servant structures ***/
++
++typedef struct
++{
++ POA_CharDev servant;
++ PortableServer_POA poa;
++ int AmountRead;
++
++}
++impl_POA_CharDev;
++
++/*** Implementation stub prototypes ***/
++
++static inline void impl_CharDev__destroy(impl_POA_CharDev * servant,
++ CORBA_Environment * ev);
++static CORBA_long
++impl_CharDev_read(impl_POA_CharDev * servant,
++ Buffer ** buffer, CORBA_long size, CORBA_Environment * ev);
++
++/*** epv structures ***/
++
++static PortableServer_ServantBase__epv impl_CharDev_base_epv = {
++ NULL, /* _private data */
++ NULL, /* finalize routine */
++ NULL, /* default_POA routine */
++};
++static POA_CharDev__epv impl_CharDev_epv = {
++ NULL, /* _private */
++ (gpointer) & impl_CharDev_read,
++
++};
++
++/*** vepv structures ***/
++
++static POA_CharDev__vepv impl_CharDev_vepv = {
++ &impl_CharDev_base_epv,
++ &impl_CharDev_epv,
++};
++
++/*** Stub implementations ***/
++
++static CharDev
++impl_CharDev__create(PortableServer_POA poa, CORBA_Environment * ev)
++{
++ CharDev retval;
++ impl_POA_CharDev *newservant;
++ PortableServer_ObjectId *objid;
++
++ newservant = g_new0(impl_POA_CharDev, 1);
++ newservant->servant.vepv = &impl_CharDev_vepv;
++ newservant->poa = poa;
++ newservant->AmountRead = 0; // Initialize chardev stuff...
++
++ POA_CharDev__init((PortableServer_Servant) newservant, ev);
++ objid = PortableServer_POA_activate_object(poa, newservant, ev);
++ CORBA_free(objid);
++ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev);
++
++ return retval;
++}
++
++static inline void
++impl_CharDev__destroy(impl_POA_CharDev * servant, CORBA_Environment * ev)
++{
++ PortableServer_ObjectId *objid;
++
++ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev);
++ PortableServer_POA_deactivate_object(servant->poa, objid, ev);
++ CORBA_free(objid);
++
++ POA_CharDev__fini((PortableServer_Servant) servant, ev);
++ g_free(servant);
++}
++
++static CORBA_long
++impl_CharDev_read(impl_POA_CharDev * servant,
++ Buffer ** buffer, CORBA_long ReqSize, CORBA_Environment * ev)
++{
++ int AvailSize = strlen(message)-servant->AmountRead;
++ CORBA_long retval = (ReqSize > AvailSize) ? AvailSize : ReqSize;
++
++ *buffer = Buffer__alloc();
++ (*buffer)->_buffer = CORBA_octet_allocbuf(retval);
++ (*buffer)->_length = retval;
++
++ strncpy((*buffer)->_buffer, message + servant->AmountRead, retval);
++ servant->AmountRead += retval;
++ return retval;
++}
++
+diff -urN linux-2.4.1/net/korbit/modules/Config.in linux-2.4.1-korbit/net/korbit/modules/Config.in
+--- linux-2.4.1/net/korbit/modules/Config.in Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Config.in Thu Feb 1 11:46:58 2001
+@@ -0,0 +1,11 @@
++# Console server
++#
++dep_tristate ' CORBA Console Server (EXPERIMENTAL)' CONFIG_CORBA_CONSOLE $CONFIG_KORBIT
++
++dep_tristate ' CORBA Echo Server (EXPERIMENTAL)' CONFIG_CORBA_ECHO $CONFIG_KORBIT
++
++dep_tristate ' CORBA FileSystem Access (EXPERIMENTAL)' CONFIG_CORBA_FILESERVER $CONFIG_KORBIT
++
++dep_tristate ' CORBA User-space FileSystem (EXPERIMENTAL)' CONFIG_CORBA_CORBAFS $CONFIG_KORBIT
++
++dep_tristate ' CORBA Character Device Interface (EXPERIMENTAL)' CONFIG_CORBA_CHARDEV $CONFIG_KORBIT
+diff -urN linux-2.4.1/net/korbit/modules/Console/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/Console/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Entries Thu Feb 1 11:47:01 2001
+@@ -0,0 +1,4 @@
++/Makefile/1.2/Thu Feb 1 09:47:00 2001//
++/README/1.1/Thu Feb 1 09:47:00 2001//
++/console.idl/1.1/Thu Feb 1 09:47:00 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/Console/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Entries.Log
+--- linux-2.4.1/net/korbit/modules/Console/CVS/Entries.Log Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Entries.Log Thu Feb 1 11:47:02 2001
+@@ -0,0 +1,3 @@
++A D/PerlClient////
++A D/client////
++A D/server////
+diff -urN linux-2.4.1/net/korbit/modules/Console/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/Console/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Repository Thu Feb 1 11:47:00 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/Console
+diff -urN linux-2.4.1/net/korbit/modules/Console/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Root
+--- linux-2.4.1/net/korbit/modules/Console/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Root Thu Feb 1 11:47:00 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/Console/Makefile linux-2.4.1-korbit/net/korbit/modules/Console/Makefile
+--- linux-2.4.1/net/korbit/modules/Console/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/Makefile Thu Feb 1 11:47:00 2001
+@@ -0,0 +1,11 @@
++#
++# Makefile for KORBit/modules/Console
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++
++subdir-$(CONFIG_CORBA_CONSOLE) := server
++
++include $(TOPDIR)/Rules.make
++
+diff -urN linux-2.4.1/net/korbit/modules/Console/PerlClient/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/Console/PerlClient/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/CVS/Entries Thu Feb 1 11:47:01 2001
+@@ -0,0 +1,3 @@
++/Client/1.1/Thu Feb 1 09:47:01 2001//
++/README/1.1/Thu Feb 1 09:47:01 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/Console/PerlClient/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/Console/PerlClient/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/CVS/Repository Thu Feb 1 11:47:01 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/Console/PerlClient
+diff -urN linux-2.4.1/net/korbit/modules/Console/PerlClient/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/CVS/Root
+--- linux-2.4.1/net/korbit/modules/Console/PerlClient/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/CVS/Root Thu Feb 1 11:47:01 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/Console/PerlClient/Client linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/Client
+--- linux-2.4.1/net/korbit/modules/Console/PerlClient/Client Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/Client Thu Feb 1 11:47:01 2001
+@@ -0,0 +1,14 @@
++#!/usr/bin/perl -w
++
++use CORBA::ORBit idl => [ qw(../console.idl) ];
++use Error qw(:try);
++use strict;
++
++my $orb = CORBA::ORB_init("orbit-local-orb");
++open IOR, "/proc/corba/console-server" or die "no console server found!";
++my $ior = <IOR>;
++close IOR;
++chomp($ior); # Kill fredrik's newline...
++
++my $console = $orb->string_to_object($ior);
++$console->print("Hello Strange World");
+diff -urN linux-2.4.1/net/korbit/modules/Console/PerlClient/README linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/README
+--- linux-2.4.1/net/korbit/modules/Console/PerlClient/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/README Thu Feb 1 11:47:01 2001
+@@ -0,0 +1,3 @@
++This is a perl client for the Console server.
++
++ORB: ORBit
+diff -urN linux-2.4.1/net/korbit/modules/Console/README linux-2.4.1-korbit/net/korbit/modules/Console/README
+--- linux-2.4.1/net/korbit/modules/Console/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/README Thu Feb 1 11:47:00 2001
+@@ -0,0 +1 @@
++The "hello world" testcase. This is used to write a string to the linux console.
+diff -urN linux-2.4.1/net/korbit/modules/Console/client/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Console/client/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/Console/client/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/client/CVS/Entries Thu Feb 1 11:47:01 2001
+@@ -0,0 +1,4 @@
++/Makefile/1.2/Thu Feb 1 09:47:01 2001//
++/README/1.1/Thu Feb 1 09:47:01 2001//
++/console-client.c/1.1/Thu Feb 1 09:47:01 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/Console/client/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Console/client/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/Console/client/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/client/CVS/Repository Thu Feb 1 11:47:01 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/Console/client
+diff -urN linux-2.4.1/net/korbit/modules/Console/client/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Console/client/CVS/Root
+--- linux-2.4.1/net/korbit/modules/Console/client/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/client/CVS/Root Thu Feb 1 11:47:01 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/Console/client/Makefile linux-2.4.1-korbit/net/korbit/modules/Console/client/Makefile
+--- linux-2.4.1/net/korbit/modules/Console/client/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/client/Makefile Thu Feb 1 11:47:01 2001
+@@ -0,0 +1,32 @@
++#
++# Makefile for KORBit
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++PROJECT = console
++
++CFLAGS = -Wall `orbit-config --cflags client` -I../../..
++LDFLAGS = `orbit-config --libs client`
++OBJS = $(PROJECT)-common.o $(PROJECT)-stubs.o $(PROJECT)-client.o
++ORBIT-IDL = orbit-idl
++
++$(PROJECT)-client: $(OBJS)
++ gcc -o $(PROJECT)-client $(OBJS) $(LDFLAGS)
++
++$(PROJECT)-client.c: $(PROJECT).h
++
++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-stubs.c: ../$(PROJECT).idl
++ $(ORBIT-IDL) --noskels ../$(PROJECT).idl
++
++clean:
++ rm -f $(OBJS) $(PROJECT)-client
++
++realclean: clean
++ rm -f $(PROJECT).h
++ rm -f $(PROJECT)-common.c
++ rm -f $(PROJECT)-stubs.c
++ rm -f *~
+diff -urN linux-2.4.1/net/korbit/modules/Console/client/README linux-2.4.1-korbit/net/korbit/modules/Console/client/README
+--- linux-2.4.1/net/korbit/modules/Console/client/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/client/README Thu Feb 1 11:47:01 2001
+@@ -0,0 +1,3 @@
++C Client to access console server.
++
++ORB: ORBit
+diff -urN linux-2.4.1/net/korbit/modules/Console/client/console-client.c linux-2.4.1-korbit/net/korbit/modules/Console/client/console-client.c
+--- linux-2.4.1/net/korbit/modules/Console/client/console-client.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/client/console-client.c Thu Feb 1 11:47:01 2001
+@@ -0,0 +1,63 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <orb/orbit.h>
++
++#include "console.h"
++
++Console console_client;
++
++int
++main (int argc, char *argv[])
++{
++ CORBA_Environment ev;
++ CORBA_ORB orb;
++ char *Message = "Hey dood, nice hair";
++ int i;
++
++ int niters = 10;
++
++ CORBA_exception_init(&ev);
++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", &ev);
++
++#if 0
++ for(i = 0; i < (sizeof(theblah) - 1); i++)
++ theblah[i] = 'a';
++ theblah[sizeof(theblah) - 1] = '\0';
++#endif
++
++ if(argc < 2)
++ {
++ printf("Need a binding ID thing as argv[1]\n");
++ return 1;
++ }
++
++ if(argc >= 3)
++ niters = atoi(argv[2]);
++
++ if (argc >= 4)
++ Message = argv[3];
++
++ console_client = CORBA_ORB_string_to_object(orb, argv[1], &ev);
++ if (!console_client) {
++ printf("Cannot bind to %s\n", argv[1]);
++ return 1;
++ }
++
++ printf("corba = %d, console = %d, foobar = %d\n",
++ CORBA_Object_is_a(console_client, "IDL:CORBA/Object:1.0", &ev),
++ CORBA_Object_is_a(console_client, "IDL:Empty:1.0", &ev),
++ CORBA_Object_is_a(console_client, "IDL:Foo/Bar:1.0", &ev));
++
++ for(i = 0; i < niters; i++) {
++ Console_print(console_client, Message, &ev);
++ if(ev._major != CORBA_NO_EXCEPTION) {
++ printf("we got exception %d from doNothing!\n", ev._major);
++ return 1;
++ }
++ }
++
++ CORBA_Object_release(console_client, &ev);
++ CORBA_Object_release((CORBA_Object)orb, &ev);
++
++ return 0;
++}
+diff -urN linux-2.4.1/net/korbit/modules/Console/console.idl linux-2.4.1-korbit/net/korbit/modules/Console/console.idl
+--- linux-2.4.1/net/korbit/modules/Console/console.idl Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/console.idl Thu Feb 1 11:47:00 2001
+@@ -0,0 +1,3 @@
++interface Console {
++ void print(in string TheString);
++};
+diff -urN linux-2.4.1/net/korbit/modules/Console/server/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Console/server/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/Console/server/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/CVS/Entries Thu Feb 1 11:47:02 2001
+@@ -0,0 +1,5 @@
++/Makefile/1.7/Thu Feb 1 09:47:02 2001//
++/Makefile.user/1.1/Thu Feb 1 09:47:02 2001//
++/README/1.1/Thu Feb 1 09:47:02 2001//
++/console-server.c/1.7/Thu Feb 1 09:47:02 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/Console/server/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Console/server/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/Console/server/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/CVS/Repository Thu Feb 1 11:47:02 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/Console/server
+diff -urN linux-2.4.1/net/korbit/modules/Console/server/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Console/server/CVS/Root
+--- linux-2.4.1/net/korbit/modules/Console/server/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/CVS/Root Thu Feb 1 11:47:02 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/Console/server/Makefile linux-2.4.1-korbit/net/korbit/modules/Console/server/Makefile
+--- linux-2.4.1/net/korbit/modules/Console/server/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/Makefile Thu Feb 1 11:47:02 2001
+@@ -0,0 +1,21 @@
++#
++# Makefile for KORBit
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := corba-cons-server.o
++
++obj-y := console-server.o console-skels.o console-common.o
++obj-m := $(O_TARGET)
++
++include ../../Makefile.module
++
++console-server.c: console.h console-common.c console-skels.c
++
++
++console.h console-skels.c: ../console.idl
++ $(ORBIT_IDL) ../console.idl
+diff -urN linux-2.4.1/net/korbit/modules/Console/server/Makefile.user linux-2.4.1-korbit/net/korbit/modules/Console/server/Makefile.user
+--- linux-2.4.1/net/korbit/modules/Console/server/Makefile.user Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/Makefile.user Thu Feb 1 11:47:02 2001
+@@ -0,0 +1,32 @@
++#
++# Makefile for KORBit
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++PROJECT = console
++
++CFLAGS = -Wall `orbit-config --cflags server` -I../../..
++LDFLAGS = `orbit-config --libs server`
++OBJS = $(PROJECT)-common.o $(PROJECT)-skels.o $(PROJECT)-server.o
++ORBIT-IDL = orbit-idl
++
++$(PROJECT)-server: $(OBJS)
++ gcc -o $(PROJECT)-server $(OBJS) $(LDFLAGS)
++
++$(PROJECT)-server.c: $(PROJECT).h
++
++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-skels.c: ../$(PROJECT).idl
++ $(ORBIT-IDL) --nostubs ../$(PROJECT).idl
++
++clean:
++ rm -f $(OBJS) $(PROJECT)-server
++
++realclean: clean
++ rm -f $(PROJECT).h
++ rm -f $(PROJECT)-common.c
++ rm -f $(PROJECT)-skels.c
++ rm -f *~
+diff -urN linux-2.4.1/net/korbit/modules/Console/server/README linux-2.4.1-korbit/net/korbit/modules/Console/server/README
+--- linux-2.4.1/net/korbit/modules/Console/server/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/README Thu Feb 1 11:47:02 2001
+@@ -0,0 +1 @@
++Kernel module to implement Console server.
+diff -urN linux-2.4.1/net/korbit/modules/Console/server/console-server.c linux-2.4.1-korbit/net/korbit/modules/Console/server/console-server.c
+--- linux-2.4.1/net/korbit/modules/Console/server/console-server.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/console-server.c Thu Feb 1 11:47:02 2001
+@@ -0,0 +1,85 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <signal.h>
++#include <orb/orbit.h>
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include "console.h"
++#include "glib.h"
++#include "korbit.h"
++
++Console console_client = CORBA_OBJECT_NIL;
++
++static void corba_console_print(PortableServer_Servant _servant,
++ CORBA_char *TheString,
++ CORBA_Environment *ev);
++
++PortableServer_ServantBase__epv base_epv = {
++ NULL,
++ NULL,
++ NULL
++};
++POA_Console__epv console_epv = { NULL, corba_console_print };
++POA_Console__vepv poa_console_vepv = { &base_epv, &console_epv };
++POA_Console poa_console_servant = { NULL, &poa_console_vepv };
++
++// MAke this global so that I can unregister the module...
++PortableServer_ObjectId objid = {0, sizeof("myFoo"), "myFoo"};
++CORBA_Environment *ev;
++PortableServer_POA poa;
++
++#ifdef __KERNEL__
++int __init corba_console_init(void)
++#else
++int main(int argc, char *argv[])
++#endif
++{
++#ifdef __KERNEL__
++ int argc = 1; char *argv[] = { "server", 0 };
++#endif
++ CORBA_ORB orb;
++
++ ev = g_new0(CORBA_Environment, 1);
++ CORBA_exception_init(ev);
++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev);
++
++ poa = (PortableServer_POA)CORBA_ORB_resolve_initial_references(orb, "RootPOA", ev);
++ PortableServer_POAManager_activate(PortableServer_POA__get_the_POAManager(poa, ev), ev);
++
++ POA_Console__init(&poa_console_servant, ev);
++
++ PortableServer_POA_activate_object_with_id(poa,
++ &objid, &poa_console_servant, ev);
++
++ console_client =
++ PortableServer_POA_servant_to_reference(poa, &poa_console_servant, ev);
++ if (!console_client) {
++ printf("Cannot get objref\n");
++ return 1;
++ }
++
++ korbit_register_ior("console-server", console_client, orb, ev);
++
++ CORBA_ORB_run(orb, ev);
++
++ return 0;
++}
++
++#ifdef __KERNEL__
++void corba_console_exit(void) {
++ PortableServer_POA_deactivate_object(poa, &objid, ev);
++ remove_proc_entry("corba/console-server", 0);
++}
++
++module_init(corba_console_init)
++module_exit(corba_console_exit)
++#endif
++
++static void corba_console_print(PortableServer_Servant _servant,
++ CORBA_char *TheString,
++ CORBA_Environment *ev) {
++ printf("Yo. Dood. You said: '%s'!\n", TheString);
++}
++
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Entries Thu Feb 1 11:47:02 2001
+@@ -0,0 +1,4 @@
++/CorbaFS.idl/1.7/Thu Feb 1 09:47:02 2001//
++/Makefile/1.4/Thu Feb 1 09:47:02 2001//
++/README/1.2/Thu Feb 1 09:47:02 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Entries.Log
+--- linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Entries.Log Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Entries.Log Thu Feb 1 11:47:04 2001
+@@ -0,0 +1,3 @@
++A D/client////
++A D/server////
++A D/server-perl////
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Repository Thu Feb 1 11:47:02 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/CorbaFS
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Root
+--- linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Root Thu Feb 1 11:47:02 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/CorbaFS.idl linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CorbaFS.idl
+--- linux-2.4.1/net/korbit/modules/CorbaFS/CorbaFS.idl Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CorbaFS.idl Thu Feb 1 11:47:02 2001
+@@ -0,0 +1,38 @@
++// -----------------------------------------------------------------------------
++// CorbaDS Module - Implement Kernel functionality in Korba
++// -----------------------------------------------------------------------------
++//
++// Main source of information:
++// http://www.cse.unsw.edu.au/~neilb/oss/linux-commentary/vfs.html
++//
++module CorbaFS {
++
++ struct dirent
++ {
++ long inode; // inode number
++ string name; // file name (null-terminated)
++ };
++
++ typedef sequence<dirent> DirEntSeq;
++ typedef sequence<octet> Buffer;
++
++ interface Inode {
++ void getStatus(out unsigned short mode, out unsigned long uid, out unsigned long gid,
++ out unsigned long size, out unsigned long inodeNum, out unsigned short numLinks,
++ out long atime, out long mtime, out long ctime);
++ void readpage(out Buffer buffer, in long size, in long offset);
++ void release();
++ };
++
++ interface FileSystem {
++ Inode getInode(in string path);
++
++ // DirectoryInode getStatus implementation must have S_IFDIR in the S_IFMT
++ // field of the mode value.
++ DirEntSeq readdir(in string path);
++
++ // SymlinkInode getStatus implementation must have S_IFLNK in the S_IFMT
++ // field of the mode value.
++ string readlink(in string filename);
++ };
++};
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/Makefile linux-2.4.1-korbit/net/korbit/modules/CorbaFS/Makefile
+--- linux-2.4.1/net/korbit/modules/CorbaFS/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/Makefile Thu Feb 1 11:47:02 2001
+@@ -0,0 +1,11 @@
++#
++# Makefile for KORBit - CorbaFS
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++
++subdir-$(CONFIG_CORBA_CORBAFS) := client
++
++include $(TOPDIR)/Rules.make
++
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/README linux-2.4.1-korbit/net/korbit/modules/CorbaFS/README
+--- linux-2.4.1/net/korbit/modules/CorbaFS/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/README Thu Feb 1 11:47:02 2001
+@@ -0,0 +1,14 @@
++This interface is used to implement linux FileSystems in CORBA.
++
++Status: Working for readonly filesystems. Write capability is a todo.
++
++This lets you do all kinds of interesting things (just like the user level
++filesystem proposals would let you do):
++ server/ implements NFS like capability of just exporting an existing FS
++ TODO: webfs, ftpfs, cvsfs, mysqlfs...
++
++Usage:
++ insmod corba-corbafs.o
++ mount -t corbafs -o IOR:... none /mnt/corbafs
++
++Where the IOR comes from a filesystem server that you run somewhere...
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CVS/Entries Thu Feb 1 11:47:03 2001
+@@ -0,0 +1,6 @@
++/CorbaFS-client.c/1.9/Thu Feb 1 09:47:03 2001//
++/CorbaFS-user-client.c/1.3/Thu Feb 1 09:47:03 2001//
++/Makefile/1.4/Thu Feb 1 09:47:03 2001//
++/Makefile.user/1.1/Thu Feb 1 09:47:03 2001//
++/README/1.1/Thu Feb 1 09:47:03 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CVS/Repository Thu Feb 1 11:47:03 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/CorbaFS/client
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CVS/Root
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CVS/Root Thu Feb 1 11:47:03 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-client.c linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-client.c
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-client.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-client.c Fri Feb 2 02:20:21 2001
+@@ -0,0 +1,469 @@
++/*
++ * corbafs - Interface glue between native linux VFS layer and CORBA
++ */
++
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/pagemap.h>
++#include <linux/init.h>
++#include <linux/string.h>
++#include <linux/locks.h>
++#include <linux/dirent.h>
++#include <linux/module.h>
++
++#include <asm/uaccess.h>
++#include "CorbaFS.h"
++
++/* some random number */
++#define CORBAFS_MAGIC 0xC02BAF5
++
++// CORBA Stuff...
++CORBA_ORB orb;
++CORBA_Environment *ev;
++
++
++/*
++ * FILE OPERATIONS FILE OPERATIONS FILE OPERATIONS FILE OPERATIONS
++ */
++
++/* Declarations for the file_operations structure for normal files...
++ */
++static struct file_operations corbafs_file_operations = {
++ read: generic_file_read,
++};
++
++
++/* Declarations for the file_operations structure for directories...
++ */
++static int corbafs_readdir(struct file *file, void *data, filldir_t filldir);
++
++static struct file_operations corbafs_dir_operations = {
++ read: generic_read_dir,
++ readdir: corbafs_readdir,
++};
++
++
++/*
++ * INODE OPERATIONS INODE OPERATIONS INODE OPERATIONS INODE OPERATIONS
++ */
++
++/* Declarations for the inode_operations structure for symlinks...
++ */
++static int corbafs_readlink(struct dentry *dentry, char *buffer, int buflen);
++static int corbafs_followlink(struct dentry *link, struct nameidata *nd);
++
++static struct inode_operations corbafs_symlink_inode_operations = {
++ readlink: corbafs_readlink,
++ follow_link: corbafs_followlink,
++};
++
++
++/* Declarations for the inode_operations structure for directories...
++ */
++static struct dentry *corbafs_lookup(struct inode *dir, struct dentry *dentry);
++
++static struct inode_operations corbafs_dir_inode_operations = {
++ lookup: corbafs_lookup,
++};
++
++
++/*
++ * OTHER OPERATIONS OTHER OPERATIONS OTHER OPERATIONS OTHER OPERATIONS
++ */
++
++/* Declarations for the corba FS's address space ops...
++ */
++static int corbafs_readpage(struct file *file, struct page * page);
++
++static struct address_space_operations corbafs_aops = {
++ readpage: corbafs_readpage,
++};
++
++
++/* Declarations for the super_operations structure...
++ */
++static int corbafs_statfs(struct super_block *sb, struct statfs *buf);
++static void corbafs_delete_inode(struct inode *);
++
++static struct super_operations corbafs_ops = {
++ statfs: corbafs_statfs,
++ delete_inode: corbafs_delete_inode,
++};
++
++
++
++
++/* do_local_path - Modified version of d_path that is used to get the remote
++ * filename that a dentry represents...
++ */
++static char *d_local_path(struct dentry *dentry, char *buffer, int buflen) {
++ char * end = buffer+buflen;
++ char * retval;
++ int namelen;
++
++ *--end = '\0';
++ buflen--;
++
++ /* Get '/' right */
++ retval = end-1;
++ *retval = '/';
++ for (;;) {
++ if (IS_ROOT(dentry)) {
++ if (dentry->d_name.len > 1 ||
++ dentry->d_name.name[0] != '/' ||
++ retval != end) { /* Only for root directory */
++ namelen = dentry->d_name.len;
++ buflen -= namelen;
++ if (buflen >= 0) {
++ end -= namelen;
++ memcpy(end, dentry->d_name.name, namelen);
++ }
++ }
++ return end;
++ }
++ namelen = dentry->d_name.len;
++ buflen -= namelen + 1;
++ if (buflen < 0)
++ break;
++ end -= namelen;
++ memcpy(end, dentry->d_name.name, namelen);
++ *--end = '/';
++ retval = end;
++ if (dentry == dentry->d_parent) break;
++ dentry = dentry->d_parent;
++ }
++ return retval;
++}
++
++
++/* corbafs_readpage - This request should be between a file_open and a
++ * file_release, so file_fd(f) should be valid. Just read the buffer...
++ */
++static int corbafs_readpage(struct file *f, struct page * page)
++{
++ struct inode *d_inode = f->f_dentry->d_inode;
++ CorbaFS_Inode inode;
++ CorbaFS_Buffer *buffer = NULL;
++
++ int offset = page->index*PAGE_CACHE_SIZE;
++ int bytesRead;
++
++#if 0
++ printk("*** READPAGE 0x%p: 0x%lX->0x%lX to 0x%p\n",
++ f,
++ page->index,
++ page->index*PAGE_CACHE_SIZE,
++ page_address(page));
++#endif
++
++ inode = d_inode->u.generic_ip;
++ if (!inode) return -EPERM;
++
++ CorbaFS_Inode_readpage(inode, &buffer, PAGE_CACHE_SIZE, offset, ev);
++ if (!buffer) return -EPERM; /* ??? */
++
++ bytesRead = buffer->_length;
++ memcpy(page_address(page), buffer->_buffer, bytesRead);
++
++ if (bytesRead != PAGE_CACHE_SIZE) { /* EOF? */
++ /* Zero out rest of page for security. */
++ memset((void*)(page_address(page)+bytesRead), 0,
++ PAGE_CACHE_SIZE-bytesRead);
++ }
++
++ SetPageUptodate(page);
++ UnlockPage(page);
++ return 0;
++}
++
++
++
++struct inode *corbafs_get_inode(struct super_block *sb, const char *path)
++{
++ struct inode * inode = get_empty_inode();
++ CorbaFS_FileSystem fs_client;
++ CorbaFS_Inode newInode;
++
++ if (!inode) return 0;
++
++ inode->i_sb = sb;
++ inode->i_dev = sb->s_dev;
++
++ fs_client = sb->u.generic_sbp;
++//printk("\n \n \nCorbaFS_FileSystem_getInode(0x%X, %s)\n", fs_client, path);
++ newInode = CorbaFS_FileSystem_getInode(fs_client, path, ev);
++//printk("NewInode = 0x%X\n \n \n \n", newInode);
++ if (!newInode) {
++ iput(inode);
++ return NULL;
++ }
++
++//printk("CorbaFS_Inode_getStatus\n");
++ CorbaFS_Inode_getStatus(newInode,
++ &inode->i_mode, &inode->i_uid, &inode->i_gid,
++ (CORBA_unsigned_long *)&inode->i_size,
++ (CORBA_unsigned_long *)&inode->i_ino,
++ &inode->i_nlink,
++ (CORBA_long *)&inode->i_atime,
++ (CORBA_long *)&inode->i_mtime,
++ (CORBA_long *)&inode->i_ctime,
++ ev);
++//printk("Back from CorbaFS_Inode_getStatus\n \n \n \n");
++
++ inode->u.generic_ip = (void*)newInode;
++
++ /* TODO: Map things back correctly??? */
++ inode->i_uid = 0 /*current->fsuid */;
++ inode->i_gid = 0 /*current->fsgid */;
++
++ inode->i_blksize = PAGE_CACHE_SIZE;
++ inode->i_blocks = 0;
++ inode->i_rdev = 0;
++ inode->i_op = NULL;
++ inode->i_fop = NULL;
++ inode->i_mapping->a_ops = &corbafs_aops;
++ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
++
++ switch (inode->i_mode & S_IFMT) {
++ default:
++ /* Do I really want to expose device inodes? */
++ init_special_inode(inode, inode->i_mode, sb->s_dev);
++ break;
++ case S_IFREG:
++ inode->i_fop = &corbafs_file_operations;
++ break;
++ case S_IFDIR:
++ inode->i_op = &corbafs_dir_inode_operations;
++ inode->i_fop = &corbafs_dir_operations;
++ break;
++ case S_IFLNK:
++ inode->i_op = &corbafs_symlink_inode_operations;
++ break;
++ }
++ insert_inode_hash(inode);
++
++ return inode;
++}
++
++static int corbafs_readdir(struct file *file, void *data, filldir_t filldir)
++{
++ struct inode *inode = file->f_dentry->d_inode;
++ struct super_block *sb = file->f_dentry->d_sb;
++ unsigned offset = file->f_pos;
++ char *path, *page = (char *)__get_free_page(GFP_KERNEL);
++ int i;
++ unsigned char d_type = DT_UNKNOWN;
++ CorbaFS_FileSystem fs_client;
++ CorbaFS_DirEntSeq *dirEntSeq;
++ CorbaFS_dirent *dirEnts;
++
++ if (offset >= inode->i_size) return 0;
++
++ path = d_local_path(file->f_dentry, page, PAGE_SIZE);
++
++ fs_client = sb->u.generic_sbp;
++ if (!fs_client)
++ return -EPERM; /* ??? */
++
++// printk("\n \n \nCorbaFS_FileSystem_readdir(%s)\n", path);
++
++ dirEntSeq = CorbaFS_FileSystem_readdir(fs_client, path, ev);
++
++// printk("CorbaFS_FileSystem_readdir = %d\n \n \n \n", dirEntSeq->_length);
++
++ if (dirEntSeq->_length == 0) goto full;
++
++ dirEnts = dirEntSeq->_buffer;
++ i = 0;
++ if (offset) { // We have read PART of the directory
++ int idxadj = offset; // Start reading now from where we left
++ while (idxadj > 0) { // off...
++ idxadj -= sizeof(struct dirent)+
++ strlen(dirEnts[i].name);
++ i++;
++ }
++
++ if (idxadj < 0) { // We should end up with exactly 0.
++ printf("Alert! Readdir can't resume in the middle "
++ "of a directory! stopage.\n");
++ goto full;
++ }
++ }
++
++ for (; i < dirEntSeq->_length; i++) {
++ int myinode = dirEnts[i].inode;
++ char *myname = dirEnts[i].name;
++ int namelen = strlen(myname);
++
++ if (filldir(data, myname, namelen, offset, myinode, d_type))
++ goto full;
++ offset += sizeof(struct dirent)+namelen;
++ }
++
++ full:
++ file->f_pos = offset;
++ return 0;
++}
++
++static int corbafs_statfs(struct super_block *sb, struct statfs *buf) {
++ buf->f_type = CORBAFS_MAGIC;
++ buf->f_bsize = PAGE_CACHE_SIZE;
++ buf->f_namelen = 255;
++ return 0;
++}
++
++/*
++ * Lookup the data. Most of the grunt work is done by corbafs_get_inode.
++ */
++static struct dentry *corbafs_lookup(struct inode *dir, struct dentry *dentry)
++{
++ struct inode *New;
++ char *Path, *Page = (char *)__get_free_page(GFP_KERNEL);
++ if (Page == 0) goto out; /* nomem? */
++
++ Path = d_local_path(dentry, Page, PAGE_SIZE);
++
++ New = corbafs_get_inode(dir->i_sb, Path);
++ free_page((unsigned long)Page);
++
++ if (New) {
++ d_add(dentry, New);
++ return 0;
++ }
++
++out:
++ d_add(dentry, NULL);
++ return 0;
++}
++
++
++static char *corbafs_read_a_link(struct dentry *dentry) {
++ char *path, *page, *s = 0;
++ struct super_block *sb = dentry->d_sb;
++ CorbaFS_FileSystem fs_client;
++
++ page = (char *)__get_free_page(GFP_KERNEL);
++ if (page == 0) goto out; /* nomem? */
++
++ path = d_local_path(dentry, page, PAGE_SIZE);
++
++ fs_client = sb->u.generic_sbp;
++// printk("\n \n \nCorbaFS_FileSystem_readlink(%s)\n", path);
++ s = CorbaFS_FileSystem_readlink(fs_client, path, ev);
++// printk("CorbaFS_FileSystem_readlink = %s\n \n \n \n", s);
++
++ if (ev->_major != CORBA_NO_EXCEPTION) {
++ if (s) {
++ // CORBA_string_free(s,..);
++ s = 0;
++ }
++ goto outfree;
++ }
++ outfree:
++ free_page((unsigned long)page);
++ out:
++ return s;
++}
++
++
++static int corbafs_readlink(struct dentry *dentry, char *buffer, int buflen) {
++ char *str = corbafs_read_a_link(dentry);
++ int error = -EINVAL;
++
++ if (str) {
++ error = vfs_readlink(dentry, buffer, buflen, str);
++ // TODO: CORBA_string__free the string str.
++ }
++ return error;
++}
++
++/* Fill in nd->dentry
++ */
++static int corbafs_followlink(struct dentry *link, struct nameidata *nd) {
++ int Error = -ENOMEM;
++ char *Path = corbafs_read_a_link(link);
++ if (!Path) goto out;
++
++#if 1
++ printk("Followlink: %s\n", Path);
++#endif
++ Error = vfs_follow_link(nd, Path);
++ // TODO: CORBA_string__free the string str.
++
++ out:
++ return Error;
++}
++
++static void corbafs_delete_inode(struct inode *inode) {
++ CorbaFS_Inode Inode = inode->u.generic_ip;
++// printk("\n \n \nCorbaFS_Inode_Release\n");
++ CorbaFS_Inode_release(Inode, ev);
++// printk("CorbaFS_Inode_Release done\n \n \n \n");
++}
++
++static void corbafs_put_super(struct super_block *sb) {
++// MOD_DEC_USE_COUNT;
++}
++
++static struct super_block *corbafs_read_super(struct super_block * sb, void * data, int silent) {
++ struct dentry *root = 0;
++ struct inode *root_inode = 0;
++
++ CorbaFS_FileSystem fs_client;
++
++ sb->s_blocksize = PAGE_CACHE_SIZE;
++ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
++ sb->s_magic = CORBAFS_MAGIC;
++ sb->s_op = &corbafs_ops;
++
++//printk("corbafs_read_super: '%s'\n", (char*)data);
++
++ // Note that the CORBA IOR is now in *data
++ fs_client = CORBA_ORB_string_to_object(orb, data, ev);
++
++//printk("fs_client: 0x%X\n", fs_client);
++ if (!fs_client)
++ return NULL;
++
++ sb->u.generic_sbp = fs_client;
++
++ root_inode = corbafs_get_inode(sb, "/");
++//printk("root_inode = 0x%X\n", root_inode);
++ root = d_alloc_root(root_inode);
++ if (!root) {
++ iput(root_inode);
++ return NULL;
++ }
++ sb->s_root = root;
++
++// MOD_INC_USE_COUNT;
++ return sb;
++}
++
++static DECLARE_FSTYPE(corbafs_fs_type, "corbafs", corbafs_read_super, 0);
++
++static int __init init_corbafs_fs(void) {
++ int argc = 1;
++ char *argv[] = { "client", 0 };
++ ev = g_new0(CORBA_Environment,1);
++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev);
++
++ return register_filesystem(&corbafs_fs_type);
++}
++
++static void __exit exit_corbafs_fs(void)
++{
++ // remove object from orb.
++ printf("\n \n \nCorbaFS_exit()\n");
++ unregister_filesystem(&corbafs_fs_type);
++ CORBA_Object_release((CORBA_Object)orb, ev);
++}
++
++module_init(init_corbafs_fs)
++module_exit(exit_corbafs_fs)
++
++/*
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-common.c linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-common.c
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-common.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-common.c Thu Feb 1 16:36:08 2001
+@@ -0,0 +1,370 @@
++/*
++ * This file was generated by orbit-idl - DO NOT EDIT!
++ */
++
++#include <string.h>
++#include "CorbaFS.h"
++
++#if ( (TC_IMPL_TC_CorbaFS_dirent_0 == 'C') \
++&& (TC_IMPL_TC_CorbaFS_dirent_1 == 'o') \
++&& (TC_IMPL_TC_CorbaFS_dirent_2 == 'r') \
++&& (TC_IMPL_TC_CorbaFS_dirent_3 == 'b') \
++&& (TC_IMPL_TC_CorbaFS_dirent_4 == 'a') \
++&& (TC_IMPL_TC_CorbaFS_dirent_5 == 'F') \
++&& (TC_IMPL_TC_CorbaFS_dirent_6 == 'S') \
++) && !defined(TC_DEF_TC_CorbaFS_dirent)
++#define TC_DEF_TC_CorbaFS_dirent 1
++static const char *anon_subnames_array1[] = { "inode", "name" };
++static const CORBA_TypeCode anon_subtypes_array2[] =
++ { (CORBA_TypeCode) & TC_CORBA_long_struct,
++ (CORBA_TypeCode) & TC_CORBA_string_struct };
++const struct CORBA_TypeCode_struct TC_CorbaFS_dirent_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_struct, "dirent", "IDL:CorbaFS/dirent:1.0",
++ 0, 2,
++ (const char **) anon_subnames_array1,
++ (CORBA_TypeCode *) anon_subtypes_array2,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++#if ( (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_0 == 'C') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_1 == 'o') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_2 == 'r') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_3 == 'b') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_4 == 'a') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_5 == 'F') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_6 == 'S') \
++) && !defined(TC_DEF_TC_CORBA_sequence_CorbaFS_dirent)
++#define TC_DEF_TC_CORBA_sequence_CorbaFS_dirent 1
++static const CORBA_TypeCode anon_subtypes_array6[] =
++ { (CORBA_TypeCode) & TC_CorbaFS_dirent_struct };
++const struct CORBA_TypeCode_struct TC_CORBA_sequence_CorbaFS_dirent_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_sequence, NULL, NULL,
++ 0, 1,
++ NULL,
++ (CORBA_TypeCode *) anon_subtypes_array6,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++#if ( (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_0 == 'C') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_1 == 'o') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_2 == 'r') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_3 == 'b') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_4 == 'a') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_5 == 'F') \
++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_6 == 'S') \
++) && !defined(TC_DEF_TC_CORBA_sequence_CorbaFS_dirent)
++#define TC_DEF_TC_CORBA_sequence_CorbaFS_dirent 1
++static const CORBA_TypeCode anon_subtypes_array15[] =
++ { (CORBA_TypeCode) & TC_CorbaFS_dirent_struct };
++const struct CORBA_TypeCode_struct TC_CORBA_sequence_CorbaFS_dirent_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_sequence, NULL, NULL,
++ 0, 1,
++ NULL,
++ (CORBA_TypeCode *) anon_subtypes_array15,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++#if ( (TC_IMPL_TC_CorbaFS_DirEntSeq_0 == 'C') \
++&& (TC_IMPL_TC_CorbaFS_DirEntSeq_1 == 'o') \
++&& (TC_IMPL_TC_CorbaFS_DirEntSeq_2 == 'r') \
++&& (TC_IMPL_TC_CorbaFS_DirEntSeq_3 == 'b') \
++&& (TC_IMPL_TC_CorbaFS_DirEntSeq_4 == 'a') \
++&& (TC_IMPL_TC_CorbaFS_DirEntSeq_5 == 'F') \
++&& (TC_IMPL_TC_CorbaFS_DirEntSeq_6 == 'S') \
++) && !defined(TC_DEF_TC_CorbaFS_DirEntSeq)
++#define TC_DEF_TC_CorbaFS_DirEntSeq 1
++static const CORBA_TypeCode anon_subtypes_array19[] =
++ { (CORBA_TypeCode) & TC_CORBA_sequence_CorbaFS_dirent_struct };
++const struct CORBA_TypeCode_struct TC_CorbaFS_DirEntSeq_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_alias, "DirEntSeq", "IDL:CorbaFS/DirEntSeq:1.0",
++ 0, 1,
++ NULL,
++ (CORBA_TypeCode *) anon_subtypes_array19,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++#if ( (TC_IMPL_TC_CORBA_sequence_CORBA_octet_0 == 'C') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_1 == 'o') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_2 == 'r') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_3 == 'b') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_4 == 'a') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_5 == 'F') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_6 == 'S') \
++) && !defined(TC_DEF_TC_CORBA_sequence_CORBA_octet)
++#define TC_DEF_TC_CORBA_sequence_CORBA_octet 1
++static const CORBA_TypeCode anon_subtypes_array23[] =
++ { (CORBA_TypeCode) & TC_CORBA_octet_struct };
++const struct CORBA_TypeCode_struct TC_CORBA_sequence_CORBA_octet_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_sequence, NULL, NULL,
++ 0, 1,
++ NULL,
++ (CORBA_TypeCode *) anon_subtypes_array23,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++#if ( (TC_IMPL_TC_CORBA_sequence_CORBA_octet_0 == 'C') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_1 == 'o') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_2 == 'r') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_3 == 'b') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_4 == 'a') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_5 == 'F') \
++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_6 == 'S') \
++) && !defined(TC_DEF_TC_CORBA_sequence_CORBA_octet)
++#define TC_DEF_TC_CORBA_sequence_CORBA_octet 1
++static const CORBA_TypeCode anon_subtypes_array32[] =
++ { (CORBA_TypeCode) & TC_CORBA_octet_struct };
++const struct CORBA_TypeCode_struct TC_CORBA_sequence_CORBA_octet_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_sequence, NULL, NULL,
++ 0, 1,
++ NULL,
++ (CORBA_TypeCode *) anon_subtypes_array32,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++#if ( (TC_IMPL_TC_CorbaFS_Buffer_0 == 'C') \
++&& (TC_IMPL_TC_CorbaFS_Buffer_1 == 'o') \
++&& (TC_IMPL_TC_CorbaFS_Buffer_2 == 'r') \
++&& (TC_IMPL_TC_CorbaFS_Buffer_3 == 'b') \
++&& (TC_IMPL_TC_CorbaFS_Buffer_4 == 'a') \
++&& (TC_IMPL_TC_CorbaFS_Buffer_5 == 'F') \
++&& (TC_IMPL_TC_CorbaFS_Buffer_6 == 'S') \
++) && !defined(TC_DEF_TC_CorbaFS_Buffer)
++#define TC_DEF_TC_CorbaFS_Buffer 1
++static const CORBA_TypeCode anon_subtypes_array36[] =
++ { (CORBA_TypeCode) & TC_CORBA_sequence_CORBA_octet_struct };
++const struct CORBA_TypeCode_struct TC_CorbaFS_Buffer_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_alias, "Buffer", "IDL:CorbaFS/Buffer:1.0",
++ 0, 1,
++ NULL,
++ (CORBA_TypeCode *) anon_subtypes_array36,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++#if ( (TC_IMPL_TC_CorbaFS_Inode_0 == 'C') \
++&& (TC_IMPL_TC_CorbaFS_Inode_1 == 'o') \
++&& (TC_IMPL_TC_CorbaFS_Inode_2 == 'r') \
++&& (TC_IMPL_TC_CorbaFS_Inode_3 == 'b') \
++&& (TC_IMPL_TC_CorbaFS_Inode_4 == 'a') \
++&& (TC_IMPL_TC_CorbaFS_Inode_5 == 'F') \
++&& (TC_IMPL_TC_CorbaFS_Inode_6 == 'S') \
++) && !defined(TC_DEF_TC_CorbaFS_Inode)
++#define TC_DEF_TC_CorbaFS_Inode 1
++const struct CORBA_TypeCode_struct TC_CorbaFS_Inode_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_objref, "Inode", "IDL:CorbaFS/Inode:1.0",
++ 0, 0,
++ NULL,
++ NULL,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++#if ( (TC_IMPL_TC_CorbaFS_FileSystem_0 == 'C') \
++&& (TC_IMPL_TC_CorbaFS_FileSystem_1 == 'o') \
++&& (TC_IMPL_TC_CorbaFS_FileSystem_2 == 'r') \
++&& (TC_IMPL_TC_CorbaFS_FileSystem_3 == 'b') \
++&& (TC_IMPL_TC_CorbaFS_FileSystem_4 == 'a') \
++&& (TC_IMPL_TC_CorbaFS_FileSystem_5 == 'F') \
++&& (TC_IMPL_TC_CorbaFS_FileSystem_6 == 'S') \
++) && !defined(TC_DEF_TC_CorbaFS_FileSystem)
++#define TC_DEF_TC_CorbaFS_FileSystem 1
++const struct CORBA_TypeCode_struct TC_CorbaFS_FileSystem_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_objref, "FileSystem", "IDL:CorbaFS/FileSystem:1.0",
++ 0, 0,
++ NULL,
++ NULL,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++gpointer
++CorbaFS_dirent__free(gpointer mem, gpointer dat, CORBA_boolean free_strings)
++{
++ CorbaFS_dirent *var = mem;
++
++ if (free_strings) {
++ CORBA_string__free(&(var->name), NULL, free_strings);
++ }
++ return (gpointer) (var + 1);
++}
++
++CorbaFS_dirent *
++CorbaFS_dirent__alloc(void)
++{
++ CorbaFS_dirent *retval;
++
++ retval =
++ ORBit_alloc(sizeof(CorbaFS_dirent),
++ (ORBit_free_childvals) CorbaFS_dirent__free,
++ GUINT_TO_POINTER(1));
++ memset(&(retval->name), '\0', sizeof(retval->name));
++ return retval;
++}
++
++#if ( (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_0 == 'C') \
++&& (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_1 == 'o') \
++&& (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_2 == 'r') \
++&& (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_3 == 'b') \
++&& (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_4 == 'a') \
++&& (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_5 == 'F') \
++&& (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_6 == 'S') \
++) && !defined(ORBIT_DEF_CORBA_sequence_CorbaFS_dirent)
++#define ORBIT_DEF_CORBA_sequence_CorbaFS_dirent 1
++
++gpointer
++CORBA_sequence_CorbaFS_dirent__free(gpointer mem, gpointer dat,
++ CORBA_boolean free_strings)
++{
++ CORBA_sequence_CorbaFS_dirent *val = mem;
++
++ if (val->_release)
++ ORBit_free(val->_buffer, free_strings);
++ return (gpointer) (val + 1);
++}
++
++CORBA_sequence_CorbaFS_dirent *
++CORBA_sequence_CorbaFS_dirent__alloc(void)
++{
++ CORBA_sequence_CorbaFS_dirent *retval;
++
++ retval =
++ ORBit_alloc(sizeof(CORBA_sequence_CorbaFS_dirent),
++ (ORBit_free_childvals) CORBA_sequence_CorbaFS_dirent__free,
++ GUINT_TO_POINTER(1));
++ retval->_maximum = 0;
++ retval->_length = 0;
++ retval->_buffer = NULL;
++ retval->_release = CORBA_FALSE;
++ return retval;
++}
++
++CorbaFS_dirent *
++CORBA_sequence_CorbaFS_dirent_allocbuf(CORBA_unsigned_long len)
++{
++ CorbaFS_dirent *retval =
++ ORBit_alloc(sizeof(CorbaFS_dirent) * len,
++ (ORBit_free_childvals) CorbaFS_dirent__free,
++ GUINT_TO_POINTER(len));
++
++ memset(retval, '\0', sizeof(CorbaFS_dirent) * len);
++ return retval;
++}
++#endif
++
++gpointer
++CorbaFS_DirEntSeq__free(gpointer mem, gpointer dat,
++ CORBA_boolean free_strings)
++{
++ return CORBA_sequence_CorbaFS_dirent__free(mem, dat, free_strings);
++}
++
++CorbaFS_DirEntSeq *
++CorbaFS_DirEntSeq__alloc(void)
++{
++ return CORBA_sequence_CorbaFS_dirent__alloc();
++}
++
++#if ( (ORBIT_IMPL_CORBA_sequence_CORBA_octet_0 == 'C') \
++&& (ORBIT_IMPL_CORBA_sequence_CORBA_octet_1 == 'o') \
++&& (ORBIT_IMPL_CORBA_sequence_CORBA_octet_2 == 'r') \
++&& (ORBIT_IMPL_CORBA_sequence_CORBA_octet_3 == 'b') \
++&& (ORBIT_IMPL_CORBA_sequence_CORBA_octet_4 == 'a') \
++&& (ORBIT_IMPL_CORBA_sequence_CORBA_octet_5 == 'F') \
++&& (ORBIT_IMPL_CORBA_sequence_CORBA_octet_6 == 'S') \
++) && !defined(ORBIT_DEF_CORBA_sequence_CORBA_octet)
++#define ORBIT_DEF_CORBA_sequence_CORBA_octet 1
++
++gpointer
++CORBA_sequence_CORBA_octet__free(gpointer mem, gpointer dat,
++ CORBA_boolean free_strings)
++{
++ CORBA_sequence_CORBA_octet *val = mem;
++
++ if (val->_release)
++ ORBit_free(val->_buffer, free_strings);
++ return (gpointer) (val + 1);
++}
++
++CORBA_sequence_CORBA_octet *
++CORBA_sequence_CORBA_octet__alloc(void)
++{
++ CORBA_sequence_CORBA_octet *retval;
++
++ retval =
++ ORBit_alloc(sizeof(CORBA_sequence_CORBA_octet),
++ (ORBit_free_childvals) CORBA_sequence_CORBA_octet__free,
++ GUINT_TO_POINTER(1));
++ retval->_maximum = 0;
++ retval->_length = 0;
++ retval->_buffer = NULL;
++ retval->_release = CORBA_FALSE;
++ return retval;
++}
++
++CORBA_octet *
++CORBA_sequence_CORBA_octet_allocbuf(CORBA_unsigned_long len)
++{
++ CORBA_octet *retval =
++ ORBit_alloc(sizeof(CORBA_octet) * len, (ORBit_free_childvals) NULL,
++ GUINT_TO_POINTER(len));
++
++ return retval;
++}
++#endif
++
++gpointer
++CorbaFS_Buffer__free(gpointer mem, gpointer dat, CORBA_boolean free_strings)
++{
++ return CORBA_sequence_CORBA_octet__free(mem, dat, free_strings);
++}
++
++CorbaFS_Buffer *
++CorbaFS_Buffer__alloc(void)
++{
++ return CORBA_sequence_CORBA_octet__alloc();
++}
++
++CORBA_unsigned_long CorbaFS_Inode__classid = 0;
++CORBA_unsigned_long CorbaFS_FileSystem__classid = 0;
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-stubs.c linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-stubs.c
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-stubs.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-stubs.c Thu Feb 1 16:36:08 2001
+@@ -0,0 +1,791 @@
++/*
++ * This file was generated by orbit-idl - DO NOT EDIT!
++ */
++
++#include <string.h>
++#include "CorbaFS.h"
++
++void
++CorbaFS_Inode_getStatus(CorbaFS_Inode _obj, CORBA_unsigned_short * mode,
++ CORBA_unsigned_long * uid, CORBA_unsigned_long * gid,
++ CORBA_unsigned_long * size,
++ CORBA_unsigned_long * inodeNum,
++ CORBA_unsigned_short * numLinks, CORBA_long * atime,
++ CORBA_long * mtime, CORBA_long * ctime,
++ CORBA_Environment * ev)
++{
++ register GIOP_unsigned_long _ORBIT_request_id,
++ _ORBIT_system_exception_minor;
++ register CORBA_completion_status _ORBIT_completion_status;
++ register GIOPSendBuffer *_ORBIT_send_buffer;
++ register GIOPRecvBuffer *_ORBIT_recv_buffer;
++ register GIOPConnection *_cnx;
++
++ if (_obj->servant && _obj->vepv && CorbaFS_Inode__classid) {
++
++ ((POA_CorbaFS_Inode__epv *) _obj->vepv[CorbaFS_Inode__classid])->
++ getStatus(_obj->servant, mode, uid, gid, size, inodeNum, numLinks,
++ atime, mtime, ctime, ev);
++ return;
++ }
++ _cnx = ORBit_object_get_connection(_obj);
++ _ORBIT_retry_request:
++ _ORBIT_send_buffer = NULL;
++ _ORBIT_recv_buffer = NULL;
++ _ORBIT_completion_status = CORBA_COMPLETED_NO;
++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0));
++ { /* marshalling */
++ static const struct
++ {
++ CORBA_unsigned_long len;
++ char opname[10];
++ }
++ _ORBIT_operation_name_data =
++ {
++ 10, "getStatus"};
++ static const struct iovec _ORBIT_operation_vec =
++ { (gpointer) & _ORBIT_operation_name_data, 14 };
++
++ _ORBIT_send_buffer =
++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id,
++ CORBA_TRUE,
++ &(_obj->active_profile->object_key_vec),
++ &_ORBIT_operation_vec,
++ &ORBit_default_principal_iovec);
++
++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE;
++ if (!_ORBIT_send_buffer)
++ goto _ORBIT_system_exception;
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE;
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ _ORBIT_send_buffer = NULL;
++ }
++ { /* demarshalling */
++ register guchar *_ORBIT_curptr;
++
++ _ORBIT_recv_buffer =
++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE);
++ if (!_ORBIT_recv_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_completion_status = CORBA_COMPLETED_YES;
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status !=
++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception;
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 2);
++
++ (*((guint16 *) & ((*mode)))) =
++ GUINT16_SWAP_LE_BE(*((guint16 *) _ORBIT_curptr));
++ _ORBIT_curptr += 2;
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++
++ (*((guint32 *) & ((*uid)))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++ (*((guint32 *) & ((*gid)))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++ (*((guint32 *) & ((*size)))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++ (*((guint32 *) & ((*inodeNum)))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++ (*((guint16 *) & ((*numLinks)))) =
++ GUINT16_SWAP_LE_BE(*((guint16 *) _ORBIT_curptr));
++ _ORBIT_curptr += 2;
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++
++ (*((guint32 *) & ((*atime)))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++ (*((guint32 *) & ((*mtime)))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++ (*((guint32 *) & ((*ctime)))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));} else {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 2);
++ (*mode) = *((CORBA_unsigned_short *) _ORBIT_curptr);
++ _ORBIT_curptr += 2;
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++ (*uid) = *((CORBA_unsigned_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++ (*gid) = *((CORBA_unsigned_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++ (*size) = *((CORBA_unsigned_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++ (*inodeNum) = *((CORBA_unsigned_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++ (*numLinks) = *((CORBA_unsigned_short *) _ORBIT_curptr);
++ _ORBIT_curptr += 2;
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++ (*atime) = *((CORBA_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++ (*mtime) = *((CORBA_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++ (*ctime) = *((CORBA_long *) _ORBIT_curptr);
++ }
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return;
++ _ORBIT_system_exception:
++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor,
++ _ORBIT_completion_status);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ return;
++ _ORBIT_msg_exception:
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status ==
++ GIOP_LOCATION_FORWARD) {
++ if (_obj->forward_locations != NULL)
++ ORBit_delete_profiles(_obj->forward_locations);
++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer);
++ _cnx = ORBit_object_get_forwarded_connection(_obj);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++
++ goto _ORBIT_retry_request;
++ } else {
++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return;
++ }
++ }
++}
++void
++CorbaFS_Inode_readpage(CorbaFS_Inode _obj, CorbaFS_Buffer ** buffer,
++ const CORBA_long size, const CORBA_long offset,
++ CORBA_Environment * ev)
++{
++ register GIOP_unsigned_long _ORBIT_request_id,
++ _ORBIT_system_exception_minor;
++ register CORBA_completion_status _ORBIT_completion_status;
++ register GIOPSendBuffer *_ORBIT_send_buffer;
++ register GIOPRecvBuffer *_ORBIT_recv_buffer;
++ register GIOPConnection *_cnx;
++ register CORBA_unsigned_long _ORBIT_tmpvar_1;
++
++ if (_obj->servant && _obj->vepv && CorbaFS_Inode__classid) {
++
++ ((POA_CorbaFS_Inode__epv *) _obj->vepv[CorbaFS_Inode__classid])->
++ readpage(_obj->servant, buffer, size, offset, ev);
++ return;
++ }
++ _cnx = ORBit_object_get_connection(_obj);
++ _ORBIT_retry_request:
++ _ORBIT_send_buffer = NULL;
++ _ORBIT_recv_buffer = NULL;
++ _ORBIT_completion_status = CORBA_COMPLETED_NO;
++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0));
++ { /* marshalling */
++ static const struct
++ {
++ CORBA_unsigned_long len;
++ char opname[9];
++ }
++ _ORBIT_operation_name_data =
++ {
++ 9, "readpage"};
++ static const struct iovec _ORBIT_operation_vec =
++ { (gpointer) & _ORBIT_operation_name_data, 13 };
++
++ _ORBIT_send_buffer =
++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id,
++ CORBA_TRUE,
++ &(_obj->active_profile->object_key_vec),
++ &_ORBIT_operation_vec,
++ &ORBit_default_principal_iovec);
++
++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE;
++ if (!_ORBIT_send_buffer)
++ goto _ORBIT_system_exception;
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), 4);
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer),
++ &(size), sizeof(size));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer),
++ &(offset), sizeof(offset));
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE;
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ _ORBIT_send_buffer = NULL;
++ }
++ { /* demarshalling */
++ register guchar *_ORBIT_curptr;
++
++ _ORBIT_recv_buffer =
++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE);
++ if (!_ORBIT_recv_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_completion_status = CORBA_COMPLETED_YES;
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status !=
++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception;
++ *buffer = CorbaFS_Buffer__alloc();
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++
++ (*((guint32 *) & (((**buffer))._length))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++
++ ((**buffer))._buffer =
++ CORBA_sequence_CORBA_octet_allocbuf(((**buffer))._length);
++ ((**buffer))._release = CORBA_TRUE;
++ memcpy(((**buffer))._buffer, _ORBIT_curptr,
++ sizeof(((**buffer))._buffer[_ORBIT_tmpvar_1]) *
++ ((**buffer))._length);
++ _ORBIT_curptr +=
++ sizeof(((**buffer))._buffer[_ORBIT_tmpvar_1]) *
++ ((**buffer))._length;
++ } else {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++ ((**buffer))._length = *((CORBA_unsigned_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++
++ ((**buffer))._buffer =
++ CORBA_sequence_CORBA_octet_allocbuf(((**buffer))._length);
++ ((**buffer))._release = CORBA_TRUE;
++ memcpy(((**buffer))._buffer, _ORBIT_curptr,
++ sizeof(((**buffer))._buffer[_ORBIT_tmpvar_1]) *
++ ((**buffer))._length);
++ _ORBIT_curptr +=
++ sizeof(((**buffer))._buffer[_ORBIT_tmpvar_1]) *
++ ((**buffer))._length;
++ }
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return;
++ _ORBIT_system_exception:
++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor,
++ _ORBIT_completion_status);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ return;
++ _ORBIT_msg_exception:
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status ==
++ GIOP_LOCATION_FORWARD) {
++ if (_obj->forward_locations != NULL)
++ ORBit_delete_profiles(_obj->forward_locations);
++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer);
++ _cnx = ORBit_object_get_forwarded_connection(_obj);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++
++ goto _ORBIT_retry_request;
++ } else {
++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return;
++ }
++ }
++}
++void
++CorbaFS_Inode_release(CorbaFS_Inode _obj, CORBA_Environment * ev)
++{
++ register GIOP_unsigned_long _ORBIT_request_id,
++ _ORBIT_system_exception_minor;
++ register CORBA_completion_status _ORBIT_completion_status;
++ register GIOPSendBuffer *_ORBIT_send_buffer;
++ register GIOPRecvBuffer *_ORBIT_recv_buffer;
++ register GIOPConnection *_cnx;
++
++ if (_obj->servant && _obj->vepv && CorbaFS_Inode__classid) {
++
++ ((POA_CorbaFS_Inode__epv *) _obj->vepv[CorbaFS_Inode__classid])->
++ release(_obj->servant, ev);
++ return;
++ }
++ _cnx = ORBit_object_get_connection(_obj);
++ _ORBIT_retry_request:
++ _ORBIT_send_buffer = NULL;
++ _ORBIT_recv_buffer = NULL;
++ _ORBIT_completion_status = CORBA_COMPLETED_NO;
++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0));
++ { /* marshalling */
++ static const struct
++ {
++ CORBA_unsigned_long len;
++ char opname[8];
++ }
++ _ORBIT_operation_name_data =
++ {
++ 8, "release"};
++ static const struct iovec _ORBIT_operation_vec =
++ { (gpointer) & _ORBIT_operation_name_data, 12 };
++
++ _ORBIT_send_buffer =
++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id,
++ CORBA_TRUE,
++ &(_obj->active_profile->object_key_vec),
++ &_ORBIT_operation_vec,
++ &ORBit_default_principal_iovec);
++
++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE;
++ if (!_ORBIT_send_buffer)
++ goto _ORBIT_system_exception;
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE;
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ _ORBIT_send_buffer = NULL;
++ }
++ { /* demarshalling */
++ register guchar *_ORBIT_curptr;
++
++ _ORBIT_recv_buffer =
++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE);
++ if (!_ORBIT_recv_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_completion_status = CORBA_COMPLETED_YES;
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status !=
++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception;
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) {
++ } else {
++ }
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return;
++ _ORBIT_system_exception:
++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor,
++ _ORBIT_completion_status);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ return;
++ _ORBIT_msg_exception:
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status ==
++ GIOP_LOCATION_FORWARD) {
++ if (_obj->forward_locations != NULL)
++ ORBit_delete_profiles(_obj->forward_locations);
++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer);
++ _cnx = ORBit_object_get_forwarded_connection(_obj);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++
++ goto _ORBIT_retry_request;
++ } else {
++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return;
++ }
++ }
++}
++CorbaFS_Inode
++CorbaFS_FileSystem_getInode(CorbaFS_FileSystem _obj, const CORBA_char * path,
++ CORBA_Environment * ev)
++{
++ register GIOP_unsigned_long _ORBIT_request_id,
++ _ORBIT_system_exception_minor;
++ register CORBA_completion_status _ORBIT_completion_status;
++ register GIOPSendBuffer *_ORBIT_send_buffer;
++ register GIOPRecvBuffer *_ORBIT_recv_buffer;
++ register GIOPConnection *_cnx;
++ CorbaFS_Inode _ORBIT_retval;
++
++ if (_obj->servant && _obj->vepv && CorbaFS_FileSystem__classid) {
++ _ORBIT_retval =
++ ((POA_CorbaFS_FileSystem__epv *) _obj->
++ vepv[CorbaFS_FileSystem__classid])->getInode(_obj->servant, path,
++ ev);
++ return _ORBIT_retval;
++ }
++ _cnx = ORBit_object_get_connection(_obj);
++ _ORBIT_retry_request:
++ _ORBIT_send_buffer = NULL;
++ _ORBIT_recv_buffer = NULL;
++ _ORBIT_completion_status = CORBA_COMPLETED_NO;
++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0));
++ { /* marshalling */
++ static const struct
++ {
++ CORBA_unsigned_long len;
++ char opname[9];
++ }
++ _ORBIT_operation_name_data =
++ {
++ 9, "getInode"};
++ static const struct iovec _ORBIT_operation_vec =
++ { (gpointer) & _ORBIT_operation_name_data, 13 };
++ register CORBA_unsigned_long _ORBIT_tmpvar_0;
++ CORBA_unsigned_long _ORBIT_tmpvar_1;
++
++ _ORBIT_send_buffer =
++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id,
++ CORBA_TRUE,
++ &(_obj->active_profile->object_key_vec),
++ &_ORBIT_operation_vec,
++ &ORBit_default_principal_iovec);
++
++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE;
++ if (!_ORBIT_send_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_tmpvar_1 = strlen(path) + 1;
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), 4);
++ {
++ guchar *_ORBIT_t;
++
++ _ORBIT_t = alloca(sizeof(_ORBIT_tmpvar_1));
++ memcpy(_ORBIT_t, &(_ORBIT_tmpvar_1), sizeof(_ORBIT_tmpvar_1));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), (_ORBIT_t),
++ sizeof(_ORBIT_tmpvar_1));
++ }
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer),
++ (path),
++ sizeof(path[_ORBIT_tmpvar_0]) *
++ _ORBIT_tmpvar_1);
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE;
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ _ORBIT_send_buffer = NULL;
++ }
++ { /* demarshalling */
++ register guchar *_ORBIT_curptr;
++
++ _ORBIT_recv_buffer =
++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE);
++ if (!_ORBIT_recv_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_completion_status = CORBA_COMPLETED_YES;
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status !=
++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception;
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) {
++ GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur = _ORBIT_curptr;
++ _ORBIT_retval =
++ ORBit_demarshal_object(_ORBIT_recv_buffer,
++ GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)->
++ connection->orb_data);
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ } else {
++ GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur = _ORBIT_curptr;
++ _ORBIT_retval =
++ ORBit_demarshal_object(_ORBIT_recv_buffer,
++ GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)->
++ connection->orb_data);
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ }
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ _ORBIT_system_exception:
++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor,
++ _ORBIT_completion_status);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ return _ORBIT_retval;
++ _ORBIT_msg_exception:
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status ==
++ GIOP_LOCATION_FORWARD) {
++ if (_obj->forward_locations != NULL)
++ ORBit_delete_profiles(_obj->forward_locations);
++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer);
++ _cnx = ORBit_object_get_forwarded_connection(_obj);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++
++ goto _ORBIT_retry_request;
++ } else {
++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ }
++ }
++}
++CorbaFS_DirEntSeq *
++CorbaFS_FileSystem_readdir(CorbaFS_FileSystem _obj, const CORBA_char * path,
++ CORBA_Environment * ev)
++{
++ register GIOP_unsigned_long _ORBIT_request_id,
++ _ORBIT_system_exception_minor;
++ register CORBA_completion_status _ORBIT_completion_status;
++ register GIOPSendBuffer *_ORBIT_send_buffer;
++ register GIOPRecvBuffer *_ORBIT_recv_buffer;
++ register GIOPConnection *_cnx;
++ CorbaFS_DirEntSeq *_ORBIT_retval;
++ register CORBA_unsigned_long _ORBIT_tmpvar_5;
++ register CORBA_unsigned_long _ORBIT_tmpvar_6;
++ CORBA_unsigned_long _ORBIT_tmpvar_7;
++
++ if (_obj->servant && _obj->vepv && CorbaFS_FileSystem__classid) {
++ _ORBIT_retval =
++ ((POA_CorbaFS_FileSystem__epv *) _obj->
++ vepv[CorbaFS_FileSystem__classid])->readdir(_obj->servant, path,
++ ev);
++ return _ORBIT_retval;
++ }
++ _cnx = ORBit_object_get_connection(_obj);
++ _ORBIT_retry_request:
++ _ORBIT_send_buffer = NULL;
++ _ORBIT_recv_buffer = NULL;
++ _ORBIT_completion_status = CORBA_COMPLETED_NO;
++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0));
++ { /* marshalling */
++ static const struct
++ {
++ CORBA_unsigned_long len;
++ char opname[8];
++ }
++ _ORBIT_operation_name_data =
++ {
++ 8, "readdir"};
++ static const struct iovec _ORBIT_operation_vec =
++ { (gpointer) & _ORBIT_operation_name_data, 12 };
++ register CORBA_unsigned_long _ORBIT_tmpvar_0;
++ CORBA_unsigned_long _ORBIT_tmpvar_1;
++
++ _ORBIT_send_buffer =
++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id,
++ CORBA_TRUE,
++ &(_obj->active_profile->object_key_vec),
++ &_ORBIT_operation_vec,
++ &ORBit_default_principal_iovec);
++
++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE;
++ if (!_ORBIT_send_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_tmpvar_1 = strlen(path) + 1;
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), 4);
++ {
++ guchar *_ORBIT_t;
++
++ _ORBIT_t = alloca(sizeof(_ORBIT_tmpvar_1));
++ memcpy(_ORBIT_t, &(_ORBIT_tmpvar_1), sizeof(_ORBIT_tmpvar_1));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), (_ORBIT_t),
++ sizeof(_ORBIT_tmpvar_1));
++ }
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer),
++ (path),
++ sizeof(path[_ORBIT_tmpvar_0]) *
++ _ORBIT_tmpvar_1);
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE;
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ _ORBIT_send_buffer = NULL;
++ }
++ { /* demarshalling */
++ register guchar *_ORBIT_curptr;
++
++ _ORBIT_recv_buffer =
++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE);
++ if (!_ORBIT_recv_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_completion_status = CORBA_COMPLETED_YES;
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status !=
++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception;
++ _ORBIT_retval = CorbaFS_DirEntSeq__alloc();
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++
++ (*((guint32 *) & ((*_ORBIT_retval)._length))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++
++ (*_ORBIT_retval)._buffer =
++ CORBA_sequence_CorbaFS_dirent_allocbuf((*_ORBIT_retval)._length);
++ (*_ORBIT_retval)._release = CORBA_TRUE;
++ for (_ORBIT_tmpvar_5 = 0; _ORBIT_tmpvar_5 < (*_ORBIT_retval)._length;
++ _ORBIT_tmpvar_5++) {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++
++ (*
++ ((guint32 *) &
++ ((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].inode))) =
++GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++
++ (*((guint32 *) & (_ORBIT_tmpvar_7))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++
++ (*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].name =
++ CORBA_string_alloc(_ORBIT_tmpvar_7);
++ memcpy((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].name,
++ _ORBIT_curptr,
++ sizeof((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].
++ name[_ORBIT_tmpvar_6]) * _ORBIT_tmpvar_7);
++ _ORBIT_curptr +=
++ sizeof((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].
++ name[_ORBIT_tmpvar_6]) * _ORBIT_tmpvar_7;
++ }
++
++ } else {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++ (*_ORBIT_retval)._length = *((CORBA_unsigned_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++
++ (*_ORBIT_retval)._buffer =
++ CORBA_sequence_CorbaFS_dirent_allocbuf((*_ORBIT_retval)._length);
++ (*_ORBIT_retval)._release = CORBA_TRUE;
++ for (_ORBIT_tmpvar_5 = 0; _ORBIT_tmpvar_5 < (*_ORBIT_retval)._length;
++ _ORBIT_tmpvar_5++) {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++ (*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].inode = *((CORBA_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++ _ORBIT_tmpvar_7 = *((CORBA_unsigned_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++
++ (*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].name =
++ CORBA_string_alloc(_ORBIT_tmpvar_7);
++ memcpy((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].name,
++ _ORBIT_curptr,
++ sizeof((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].
++ name[_ORBIT_tmpvar_6]) * _ORBIT_tmpvar_7);
++ _ORBIT_curptr +=
++ sizeof((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].
++ name[_ORBIT_tmpvar_6]) * _ORBIT_tmpvar_7;
++ }
++
++ }
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ _ORBIT_system_exception:
++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor,
++ _ORBIT_completion_status);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ return _ORBIT_retval;
++ _ORBIT_msg_exception:
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status ==
++ GIOP_LOCATION_FORWARD) {
++ if (_obj->forward_locations != NULL)
++ ORBit_delete_profiles(_obj->forward_locations);
++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer);
++ _cnx = ORBit_object_get_forwarded_connection(_obj);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++
++ goto _ORBIT_retry_request;
++ } else {
++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ }
++ }
++}
++CORBA_char *
++CorbaFS_FileSystem_readlink(CorbaFS_FileSystem _obj,
++ const CORBA_char * filename,
++ CORBA_Environment * ev)
++{
++ register GIOP_unsigned_long _ORBIT_request_id,
++ _ORBIT_system_exception_minor;
++ register CORBA_completion_status _ORBIT_completion_status;
++ register GIOPSendBuffer *_ORBIT_send_buffer;
++ register GIOPRecvBuffer *_ORBIT_recv_buffer;
++ register GIOPConnection *_cnx;
++ CORBA_char *_ORBIT_retval;
++ register CORBA_unsigned_long _ORBIT_tmpvar_4;
++ CORBA_unsigned_long _ORBIT_tmpvar_5;
++
++ if (_obj->servant && _obj->vepv && CorbaFS_FileSystem__classid) {
++ _ORBIT_retval =
++ ((POA_CorbaFS_FileSystem__epv *) _obj->
++ vepv[CorbaFS_FileSystem__classid])->readlink(_obj->servant,
++ filename, ev);
++ return _ORBIT_retval;
++ }
++ _cnx = ORBit_object_get_connection(_obj);
++ _ORBIT_retry_request:
++ _ORBIT_send_buffer = NULL;
++ _ORBIT_recv_buffer = NULL;
++ _ORBIT_completion_status = CORBA_COMPLETED_NO;
++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0));
++ { /* marshalling */
++ static const struct
++ {
++ CORBA_unsigned_long len;
++ char opname[9];
++ }
++ _ORBIT_operation_name_data =
++ {
++ 9, "readlink"};
++ static const struct iovec _ORBIT_operation_vec =
++ { (gpointer) & _ORBIT_operation_name_data, 13 };
++ register CORBA_unsigned_long _ORBIT_tmpvar_0;
++ CORBA_unsigned_long _ORBIT_tmpvar_1;
++
++ _ORBIT_send_buffer =
++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id,
++ CORBA_TRUE,
++ &(_obj->active_profile->object_key_vec),
++ &_ORBIT_operation_vec,
++ &ORBit_default_principal_iovec);
++
++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE;
++ if (!_ORBIT_send_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_tmpvar_1 = strlen(filename) + 1;
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), 4);
++ {
++ guchar *_ORBIT_t;
++
++ _ORBIT_t = alloca(sizeof(_ORBIT_tmpvar_1));
++ memcpy(_ORBIT_t, &(_ORBIT_tmpvar_1), sizeof(_ORBIT_tmpvar_1));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), (_ORBIT_t),
++ sizeof(_ORBIT_tmpvar_1));
++ }
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer),
++ (filename),
++ sizeof(filename[_ORBIT_tmpvar_0]) *
++ _ORBIT_tmpvar_1);
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE;
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ _ORBIT_send_buffer = NULL;
++ }
++ { /* demarshalling */
++ register guchar *_ORBIT_curptr;
++
++ _ORBIT_recv_buffer =
++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE);
++ if (!_ORBIT_recv_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_completion_status = CORBA_COMPLETED_YES;
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status !=
++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception;
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++
++ (*((guint32 *) & (_ORBIT_tmpvar_5))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++ _ORBIT_retval = CORBA_string_alloc(_ORBIT_tmpvar_5);
++ memcpy(_ORBIT_retval, _ORBIT_curptr,
++ sizeof(_ORBIT_retval[_ORBIT_tmpvar_4]) * _ORBIT_tmpvar_5);
++ _ORBIT_curptr +=
++ sizeof(_ORBIT_retval[_ORBIT_tmpvar_4]) * _ORBIT_tmpvar_5;
++ } else {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++ _ORBIT_tmpvar_5 = *((CORBA_unsigned_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++ _ORBIT_retval = CORBA_string_alloc(_ORBIT_tmpvar_5);
++ memcpy(_ORBIT_retval, _ORBIT_curptr,
++ sizeof(_ORBIT_retval[_ORBIT_tmpvar_4]) * _ORBIT_tmpvar_5);
++ _ORBIT_curptr +=
++ sizeof(_ORBIT_retval[_ORBIT_tmpvar_4]) * _ORBIT_tmpvar_5;
++ }
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ _ORBIT_system_exception:
++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor,
++ _ORBIT_completion_status);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ return _ORBIT_retval;
++ _ORBIT_msg_exception:
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status ==
++ GIOP_LOCATION_FORWARD) {
++ if (_obj->forward_locations != NULL)
++ ORBit_delete_profiles(_obj->forward_locations);
++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer);
++ _cnx = ORBit_object_get_forwarded_connection(_obj);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++
++ goto _ORBIT_retry_request;
++ } else {
++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ }
++ }
++}
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-user-client.c linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-user-client.c
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-user-client.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-user-client.c Thu Feb 1 11:47:03 2001
+@@ -0,0 +1,92 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <orb/orbit.h>
++
++#include "CorbaFS.h"
++
++CorbaFS_FileSystem fs;
++
++int
++main (int argc, char *argv[])
++{
++ CORBA_Environment ev;
++ CORBA_ORB orb;
++ CorbaFS_Inode inode;
++ CorbaFS_Buffer *buffer;
++ CorbaFS_DirEntSeq *dirents;
++ CorbaFS_dirent *dirent;
++
++ CORBA_unsigned_short mode;
++ CORBA_unsigned_long uid;
++ CORBA_unsigned_long gid;
++ CORBA_unsigned_long size;
++ CORBA_unsigned_long inodeNum;
++ CORBA_unsigned_short numLinks;
++ CORBA_long atime;
++ CORBA_long mtime;
++ CORBA_long ctime;
++
++ int i;
++
++ int niters = 10;
++
++ CORBA_exception_init(&ev);
++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", &ev);
++
++ if(argc < 2)
++ {
++ printf("Need a binding ID thing as argv[1]\n");
++ return 1;
++ }
++
++
++ fs = CORBA_ORB_string_to_object(orb, argv[1], &ev);
++ if (!fs) {
++ printf("Cannot bind to %s\n", argv[1]);
++ return 1;
++ }
++
++ if (argc >= 3)
++ inode = CorbaFS_FileSystem_getInode(fs, argv[2], &ev);
++ else
++ inode = CorbaFS_FileSystem_getInode(fs, "/proc/cpuinfo", &ev);
++
++ if (!inode)
++ {
++ printf("Cannot get inode\n");
++ }
++
++ CorbaFS_Inode_getStatus(inode,
++ &mode,
++ &uid,
++ &gid,
++ &size,
++ &inodeNum,
++ &numLinks,
++ &atime,
++ &mtime,
++ &ctime,
++ &ev);
++
++ printf("inode = %x\n", inode);
++ CorbaFS_Inode_readpage(inode, &buffer, 1000, 100, &ev);
++ printf("readpage got %d bytes\n", buffer->_length);
++ printf("readpage returned : %s\n", buffer->_buffer);
++
++ if (argc >= 3)
++ dirents = CorbaFS_FileSystem_readdir(fs, argv[2], &ev);
++ else
++ dirents = CorbaFS_FileSystem_readdir(fs, "/", &ev);
++
++ dirent = dirents->_buffer;
++ for (i = 0; i < dirents->_length; i++)
++ {
++ printf("%d = %s\n", dirent->inode, dirent->name);
++ dirent++;
++ }
++
++ CORBA_Object_release(fs, &ev);
++ CORBA_Object_release((CORBA_Object)orb, &ev);
++
++ return 0;
++}
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS.h linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS.h
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS.h Thu Feb 1 16:36:08 2001
+@@ -0,0 +1,349 @@
++/*
++ * This file was generated by orbit-idl - DO NOT EDIT!
++ */
++
++#include <glib.h>
++#define ORBIT_IDL_SERIAL 9
++#include <orb/orbit.h>
++
++#ifndef CorbaFS_H
++#define CorbaFS_H 1
++#ifdef __cplusplus
++extern "C"
++{
++#endif /* __cplusplus */
++
++/** typedefs **/
++#if !defined(_CorbaFS_dirent_defined)
++#define _CorbaFS_dirent_defined 1
++ typedef struct
++ {
++ CORBA_long inode;
++ CORBA_char *name;
++ }
++ CorbaFS_dirent;
++
++#if !defined(TC_IMPL_TC_CorbaFS_dirent_0)
++#define TC_IMPL_TC_CorbaFS_dirent_0 'C'
++#define TC_IMPL_TC_CorbaFS_dirent_1 'o'
++#define TC_IMPL_TC_CorbaFS_dirent_2 'r'
++#define TC_IMPL_TC_CorbaFS_dirent_3 'b'
++#define TC_IMPL_TC_CorbaFS_dirent_4 'a'
++#define TC_IMPL_TC_CorbaFS_dirent_5 'F'
++#define TC_IMPL_TC_CorbaFS_dirent_6 'S'
++ extern const struct CORBA_TypeCode_struct TC_CorbaFS_dirent_struct;
++#define TC_CorbaFS_dirent ((CORBA_TypeCode)&TC_CorbaFS_dirent_struct)
++#endif
++ extern CorbaFS_dirent *CorbaFS_dirent__alloc(void);
++ extern gpointer CorbaFS_dirent__free(gpointer mem, gpointer dat,
++ CORBA_boolean free_strings); /* ORBit internal use */
++#endif
++#if !defined(ORBIT_DECL_CORBA_sequence_CorbaFS_dirent) && !defined(_CORBA_sequence_CorbaFS_dirent_defined)
++#define ORBIT_DECL_CORBA_sequence_CorbaFS_dirent 1
++#define _CORBA_sequence_CorbaFS_dirent_defined 1
++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_0 'C'
++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_1 'o'
++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_2 'r'
++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_3 'b'
++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_4 'a'
++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_5 'F'
++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_6 'S'
++ typedef struct
++ {
++ CORBA_unsigned_long _maximum,
++ _length;
++ CorbaFS_dirent *_buffer;
++ CORBA_boolean _release;
++ }
++ CORBA_sequence_CorbaFS_dirent;
++#if !defined(TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_0)
++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_0 'C'
++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_1 'o'
++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_2 'r'
++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_3 'b'
++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_4 'a'
++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_5 'F'
++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_6 'S'
++ extern const struct CORBA_TypeCode_struct
++ TC_CORBA_sequence_CorbaFS_dirent_struct;
++#define TC_CORBA_sequence_CorbaFS_dirent ((CORBA_TypeCode)&TC_CORBA_sequence_CorbaFS_dirent_struct)
++#endif
++ extern CORBA_sequence_CorbaFS_dirent
++ *CORBA_sequence_CorbaFS_dirent__alloc(void);
++ extern gpointer CORBA_sequence_CorbaFS_dirent__free(gpointer mem,
++ gpointer dat,
++ CORBA_boolean free_strings); /* ORBit internal use */
++ CorbaFS_dirent *CORBA_sequence_CorbaFS_dirent_allocbuf(CORBA_unsigned_long
++ len);
++#endif
++#if !defined(_CorbaFS_DirEntSeq_defined)
++#define _CorbaFS_DirEntSeq_defined 1
++ typedef CORBA_sequence_CorbaFS_dirent CorbaFS_DirEntSeq;
++#if !defined(TC_IMPL_TC_CorbaFS_DirEntSeq_0)
++#define TC_IMPL_TC_CorbaFS_DirEntSeq_0 'C'
++#define TC_IMPL_TC_CorbaFS_DirEntSeq_1 'o'
++#define TC_IMPL_TC_CorbaFS_DirEntSeq_2 'r'
++#define TC_IMPL_TC_CorbaFS_DirEntSeq_3 'b'
++#define TC_IMPL_TC_CorbaFS_DirEntSeq_4 'a'
++#define TC_IMPL_TC_CorbaFS_DirEntSeq_5 'F'
++#define TC_IMPL_TC_CorbaFS_DirEntSeq_6 'S'
++ extern const struct CORBA_TypeCode_struct TC_CorbaFS_DirEntSeq_struct;
++#define TC_CorbaFS_DirEntSeq ((CORBA_TypeCode)&TC_CorbaFS_DirEntSeq_struct)
++#endif
++ extern CorbaFS_DirEntSeq *CorbaFS_DirEntSeq__alloc(void);
++ extern gpointer CorbaFS_DirEntSeq__free(gpointer mem, gpointer dat,
++ CORBA_boolean free_strings); /* ORBit internal use */
++#endif
++#if !defined(ORBIT_DECL_CORBA_sequence_CORBA_octet) && !defined(_CORBA_sequence_CORBA_octet_defined)
++#define ORBIT_DECL_CORBA_sequence_CORBA_octet 1
++#define _CORBA_sequence_CORBA_octet_defined 1
++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_0 'C'
++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_1 'o'
++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_2 'r'
++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_3 'b'
++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_4 'a'
++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_5 'F'
++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_6 'S'
++ typedef struct
++ {
++ CORBA_unsigned_long _maximum,
++ _length;
++ CORBA_octet *_buffer;
++ CORBA_boolean _release;
++ }
++ CORBA_sequence_CORBA_octet;
++#if !defined(TC_IMPL_TC_CORBA_sequence_CORBA_octet_0)
++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_0 'C'
++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_1 'o'
++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_2 'r'
++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_3 'b'
++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_4 'a'
++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_5 'F'
++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_6 'S'
++ extern const struct CORBA_TypeCode_struct
++ TC_CORBA_sequence_CORBA_octet_struct;
++#define TC_CORBA_sequence_CORBA_octet ((CORBA_TypeCode)&TC_CORBA_sequence_CORBA_octet_struct)
++#endif
++ extern CORBA_sequence_CORBA_octet *CORBA_sequence_CORBA_octet__alloc(void);
++ extern gpointer CORBA_sequence_CORBA_octet__free(gpointer mem,
++ gpointer dat,
++ CORBA_boolean free_strings); /* ORBit internal use */
++ CORBA_octet *CORBA_sequence_CORBA_octet_allocbuf(CORBA_unsigned_long len);
++#endif
++#if !defined(_CorbaFS_Buffer_defined)
++#define _CorbaFS_Buffer_defined 1
++ typedef CORBA_sequence_CORBA_octet CorbaFS_Buffer;
++#if !defined(TC_IMPL_TC_CorbaFS_Buffer_0)
++#define TC_IMPL_TC_CorbaFS_Buffer_0 'C'
++#define TC_IMPL_TC_CorbaFS_Buffer_1 'o'
++#define TC_IMPL_TC_CorbaFS_Buffer_2 'r'
++#define TC_IMPL_TC_CorbaFS_Buffer_3 'b'
++#define TC_IMPL_TC_CorbaFS_Buffer_4 'a'
++#define TC_IMPL_TC_CorbaFS_Buffer_5 'F'
++#define TC_IMPL_TC_CorbaFS_Buffer_6 'S'
++ extern const struct CORBA_TypeCode_struct TC_CorbaFS_Buffer_struct;
++#define TC_CorbaFS_Buffer ((CORBA_TypeCode)&TC_CorbaFS_Buffer_struct)
++#endif
++ extern CorbaFS_Buffer *CorbaFS_Buffer__alloc(void);
++ extern gpointer CorbaFS_Buffer__free(gpointer mem, gpointer dat,
++ CORBA_boolean free_strings); /* ORBit internal use */
++#endif
++#if !defined(ORBIT_DECL_CorbaFS_Inode) && !defined(_CorbaFS_Inode_defined)
++#define ORBIT_DECL_CorbaFS_Inode 1
++#define _CorbaFS_Inode_defined 1
++#define CorbaFS_Inode__free CORBA_Object__free
++ typedef CORBA_Object CorbaFS_Inode;
++ extern CORBA_unsigned_long CorbaFS_Inode__classid;
++#if !defined(TC_IMPL_TC_CorbaFS_Inode_0)
++#define TC_IMPL_TC_CorbaFS_Inode_0 'C'
++#define TC_IMPL_TC_CorbaFS_Inode_1 'o'
++#define TC_IMPL_TC_CorbaFS_Inode_2 'r'
++#define TC_IMPL_TC_CorbaFS_Inode_3 'b'
++#define TC_IMPL_TC_CorbaFS_Inode_4 'a'
++#define TC_IMPL_TC_CorbaFS_Inode_5 'F'
++#define TC_IMPL_TC_CorbaFS_Inode_6 'S'
++ extern const struct CORBA_TypeCode_struct TC_CorbaFS_Inode_struct;
++#define TC_CorbaFS_Inode ((CORBA_TypeCode)&TC_CorbaFS_Inode_struct)
++#endif
++#endif
++#if !defined(ORBIT_DECL_CorbaFS_FileSystem) && !defined(_CorbaFS_FileSystem_defined)
++#define ORBIT_DECL_CorbaFS_FileSystem 1
++#define _CorbaFS_FileSystem_defined 1
++#define CorbaFS_FileSystem__free CORBA_Object__free
++ typedef CORBA_Object CorbaFS_FileSystem;
++ extern CORBA_unsigned_long CorbaFS_FileSystem__classid;
++#if !defined(TC_IMPL_TC_CorbaFS_FileSystem_0)
++#define TC_IMPL_TC_CorbaFS_FileSystem_0 'C'
++#define TC_IMPL_TC_CorbaFS_FileSystem_1 'o'
++#define TC_IMPL_TC_CorbaFS_FileSystem_2 'r'
++#define TC_IMPL_TC_CorbaFS_FileSystem_3 'b'
++#define TC_IMPL_TC_CorbaFS_FileSystem_4 'a'
++#define TC_IMPL_TC_CorbaFS_FileSystem_5 'F'
++#define TC_IMPL_TC_CorbaFS_FileSystem_6 'S'
++ extern const struct CORBA_TypeCode_struct TC_CorbaFS_FileSystem_struct;
++#define TC_CorbaFS_FileSystem ((CORBA_TypeCode)&TC_CorbaFS_FileSystem_struct)
++#endif
++#endif
++
++/** POA structures **/
++ typedef struct
++ {
++ void *_private;
++ void (*getStatus) (PortableServer_Servant _servant,
++ CORBA_unsigned_short * mode,
++ CORBA_unsigned_long * uid, CORBA_unsigned_long * gid,
++ CORBA_unsigned_long * size,
++ CORBA_unsigned_long * inodeNum,
++ CORBA_unsigned_short * numLinks, CORBA_long * atime,
++ CORBA_long * mtime, CORBA_long * ctime,
++ CORBA_Environment * ev);
++ void (*readpage) (PortableServer_Servant _servant,
++ CorbaFS_Buffer ** buffer, const CORBA_long size,
++ const CORBA_long offset, CORBA_Environment * ev);
++ void (*release) (PortableServer_Servant _servant,
++ CORBA_Environment * ev);
++ }
++ POA_CorbaFS_Inode__epv;
++ typedef struct
++ {
++ PortableServer_ServantBase__epv *_base_epv;
++ POA_CorbaFS_Inode__epv *CorbaFS_Inode_epv;
++ }
++ POA_CorbaFS_Inode__vepv;
++ typedef struct
++ {
++ void *_private;
++ POA_CorbaFS_Inode__vepv *vepv;
++ }
++ POA_CorbaFS_Inode;
++ extern void POA_CorbaFS_Inode__init(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++ extern void POA_CorbaFS_Inode__fini(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++ typedef struct
++ {
++ void *_private;
++
++ CorbaFS_Inode(*getInode) (PortableServer_Servant _servant,
++ const CORBA_char * path,
++ CORBA_Environment * ev);
++ CorbaFS_DirEntSeq *(*readdir) (PortableServer_Servant _servant,
++ const CORBA_char * path,
++ CORBA_Environment * ev);
++ CORBA_char *(*readlink) (PortableServer_Servant _servant,
++ const CORBA_char * filename,
++ CORBA_Environment * ev);
++ }
++ POA_CorbaFS_FileSystem__epv;
++ typedef struct
++ {
++ PortableServer_ServantBase__epv *_base_epv;
++ POA_CorbaFS_FileSystem__epv *CorbaFS_FileSystem_epv;
++ }
++ POA_CorbaFS_FileSystem__vepv;
++ typedef struct
++ {
++ void *_private;
++ POA_CorbaFS_FileSystem__vepv *vepv;
++ }
++ POA_CorbaFS_FileSystem;
++ extern void POA_CorbaFS_FileSystem__init(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++ extern void POA_CorbaFS_FileSystem__fini(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++
++/** prototypes **/
++ void CorbaFS_Inode_getStatus(CorbaFS_Inode _obj,
++ CORBA_unsigned_short * mode,
++ CORBA_unsigned_long * uid,
++ CORBA_unsigned_long * gid,
++ CORBA_unsigned_long * size,
++ CORBA_unsigned_long * inodeNum,
++ CORBA_unsigned_short * numLinks,
++ CORBA_long * atime, CORBA_long * mtime,
++ CORBA_long * ctime, CORBA_Environment * ev);
++ void CorbaFS_Inode_readpage(CorbaFS_Inode _obj, CorbaFS_Buffer ** buffer,
++ const CORBA_long size, const CORBA_long offset,
++ CORBA_Environment * ev);
++ void CorbaFS_Inode_release(CorbaFS_Inode _obj, CORBA_Environment * ev);
++ CorbaFS_Inode CorbaFS_FileSystem_getInode(CorbaFS_FileSystem _obj,
++ const CORBA_char * path,
++ CORBA_Environment * ev);
++ CorbaFS_DirEntSeq *CorbaFS_FileSystem_readdir(CorbaFS_FileSystem _obj,
++ const CORBA_char * path,
++ CORBA_Environment * ev);
++ CORBA_char *CorbaFS_FileSystem_readlink(CorbaFS_FileSystem _obj,
++ const CORBA_char * filename,
++ CORBA_Environment * ev);
++
++ void _ORBIT_skel_CorbaFS_Inode_getStatus(POA_CorbaFS_Inode *
++ _ORBIT_servant,
++ GIOPRecvBuffer *
++ _ORBIT_recv_buffer,
++ CORBA_Environment * ev,
++ void (*_impl_getStatus)
++ (PortableServer_Servant _servant,
++ CORBA_unsigned_short * mode,
++ CORBA_unsigned_long * uid,
++ CORBA_unsigned_long * gid,
++ CORBA_unsigned_long * size,
++ CORBA_unsigned_long * inodeNum,
++ CORBA_unsigned_short * numLinks,
++ CORBA_long * atime,
++ CORBA_long * mtime,
++ CORBA_long * ctime,
++ CORBA_Environment * ev));
++ void _ORBIT_skel_CorbaFS_Inode_readpage(POA_CorbaFS_Inode * _ORBIT_servant,
++ GIOPRecvBuffer *
++ _ORBIT_recv_buffer,
++ CORBA_Environment * ev,
++ void (*_impl_readpage)
++ (PortableServer_Servant _servant,
++ CorbaFS_Buffer ** buffer,
++ const CORBA_long size,
++ const CORBA_long offset,
++ CORBA_Environment * ev));
++ void _ORBIT_skel_CorbaFS_Inode_release(POA_CorbaFS_Inode * _ORBIT_servant,
++ GIOPRecvBuffer * _ORBIT_recv_buffer,
++ CORBA_Environment * ev,
++ void (*_impl_release)
++ (PortableServer_Servant _servant,
++ CORBA_Environment * ev));
++ void _ORBIT_skel_CorbaFS_FileSystem_getInode(POA_CorbaFS_FileSystem *
++ _ORBIT_servant,
++ GIOPRecvBuffer *
++ _ORBIT_recv_buffer,
++ CORBA_Environment * ev,
++ CorbaFS_Inode(*_impl_getInode)
++ (PortableServer_Servant
++ _servant,
++ const CORBA_char * path,
++ CORBA_Environment * ev));
++ void _ORBIT_skel_CorbaFS_FileSystem_readdir(POA_CorbaFS_FileSystem *
++ _ORBIT_servant,
++ GIOPRecvBuffer *
++ _ORBIT_recv_buffer,
++ CORBA_Environment * ev,
++ CorbaFS_DirEntSeq *
++ (*_impl_readdir)
++ (PortableServer_Servant
++ _servant,
++ const CORBA_char * path,
++ CORBA_Environment * ev));
++ void _ORBIT_skel_CorbaFS_FileSystem_readlink(POA_CorbaFS_FileSystem *
++ _ORBIT_servant,
++ GIOPRecvBuffer *
++ _ORBIT_recv_buffer,
++ CORBA_Environment * ev,
++ CORBA_char *
++ (*_impl_readlink)
++ (PortableServer_Servant
++ _servant,
++ const CORBA_char * filename,
++ CORBA_Environment * ev));
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif
++#undef ORBIT_IDL_SERIAL
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/Makefile linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/Makefile
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/Makefile Thu Feb 1 11:47:03 2001
+@@ -0,0 +1,20 @@
++#
++# Makefile for KORBit CorbaFS client
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := corba-corbafs-client.o
++
++obj-y := CorbaFS-common.o CorbaFS-stubs.o CorbaFS-client.o
++obj-m := $(O_TARGET)
++
++include ../../Makefile.module
++
++CorbaFS-client.c: CorbaFS.h
++
++CorbaFS.h CorbaFS-common.c CorbaFS-stubs.c: ../CorbaFS.idl
++ $(ORBIT_IDL) --noskels ../CorbaFS.idl
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/Makefile.user linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/Makefile.user
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/Makefile.user Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/Makefile.user Thu Feb 1 11:47:03 2001
+@@ -0,0 +1,32 @@
++#
++# Makefile for KORBit
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++PROJECT = CorbaFS
++
++CFLAGS = -Wall `orbit-config --cflags client` -I../../..
++LDFLAGS = `orbit-config --libs client`
++OBJS = $(PROJECT)-common.o $(PROJECT)-stubs.o $(PROJECT)-user-client.o
++ORBIT-IDL = orbit-idl
++
++$(PROJECT)-user-client: $(OBJS)
++ gcc -o $(PROJECT)-user-client $(OBJS) $(LDFLAGS)
++
++$(PROJECT)-user-client.o: $(PROJECT).h
++
++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-stubs.c: ../$(PROJECT).idl
++ $(ORBIT-IDL) --noskels ../$(PROJECT).idl
++
++clean:
++ rm -f $(OBJS) $(PROJECT)-user-client
++
++realclean: clean
++ rm -f $(PROJECT).h
++ rm -f $(PROJECT)-common.c
++ rm -f $(PROJECT)-skels.c
++ rm -f *~
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/README linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/README
+--- linux-2.4.1/net/korbit/modules/CorbaFS/client/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/README Thu Feb 1 11:47:03 2001
+@@ -0,0 +1,4 @@
++This module implements the kernel VFS->kORBit interface. This is called a 'client'
++because it actually USES a CORBA object that is exported from someplace else.
++
++ORB: kORBit
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CVS/Entries Thu Feb 1 11:47:04 2001
+@@ -0,0 +1,6 @@
++/CorbaFS-server.c/1.8/Thu Feb 1 09:47:03 2001//
++/CorbaFS-skelimpl.c/1.10/Thu Feb 1 09:47:04 2001//
++/Makefile/1.5/Thu Feb 1 09:47:04 2001//
++/README/1.2/Thu Feb 1 09:47:04 2001//
++/RunServer.sh/1.1/Thu Feb 1 09:47:04 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CVS/Repository Thu Feb 1 11:47:03 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/CorbaFS/server
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CVS/Root
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CVS/Root Thu Feb 1 11:47:03 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/CorbaFS-server.c linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CorbaFS-server.c
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server/CorbaFS-server.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CorbaFS-server.c Thu Feb 1 11:47:03 2001
+@@ -0,0 +1,37 @@
++#include <stdio.h>
++#include "CorbaFS-skelimpl.c"
++
++CORBA_ORB orb;
++PortableServer_POA poa;
++CORBA_Environment *ev;
++PortableServer_ObjectId *objid;
++
++int main(int argc, char *argv[]) {
++ CorbaFS_FileSystem fs;
++ impl_POA_CorbaFS_FileSystem *fs_impl;
++
++ PortableServer_POAManager pm;
++ ev = g_new0(CORBA_Environment,1);
++
++ CORBA_exception_init(ev);
++ printf("Make sure you use TCP/IP and not Unix sockets!\n");
++
++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev);
++ poa = (PortableServer_POA)
++ CORBA_ORB_resolve_initial_references(orb,
++ "RootPOA",
++ ev);
++ fs = impl_CorbaFS_FileSystem__create(poa, ev);
++
++ pm = PortableServer_POA__get_the_POAManager(poa, ev);
++ PortableServer_POAManager_activate(pm, ev);
++
++ fs_impl = PortableServer_POA_reference_to_servant( poa, fs, ev );
++ objid = PortableServer_POA_servant_to_id( poa, fs_impl, ev );
++
++ printf("CorbaFS-server:\n%s\n", CORBA_ORB_object_to_string(orb, fs, ev));
++
++ CORBA_ORB_run(orb, ev);
++
++ return 0;
++}
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/CorbaFS-skelimpl.c linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CorbaFS-skelimpl.c
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server/CorbaFS-skelimpl.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CorbaFS-skelimpl.c Thu Feb 1 11:47:04 2001
+@@ -0,0 +1,353 @@
++#include <sys/param.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <dirent.h>
++
++#include "CorbaFS.h"
++
++/*** App-specific servant structures ***/
++
++#define printf(fmt, args...) fprintf(stderr, fmt, ##args);
++
++typedef struct
++{
++ POA_CorbaFS_Inode servant;
++ PortableServer_POA poa;
++
++ CORBA_char *path;
++#if 0
++ CORBA_unsigned_short mode;
++ CORBA_unsigned_long uid;
++ CORBA_unsigned_long gid;
++ CORBA_unsigned_long size;
++ CORBA_unsigned_long inodeNum;
++ CORBA_unsigned_short numLinks;
++ CORBA_long atime;
++ CORBA_long mtime;
++ CORBA_long ctime;
++#endif
++}
++impl_POA_CorbaFS_Inode;
++
++typedef struct
++{
++ POA_CorbaFS_FileSystem servant;
++ PortableServer_POA poa;
++
++}
++impl_POA_CorbaFS_FileSystem;
++
++/*** Implementation stub prototypes ***/
++
++static void impl_CorbaFS_Inode__destroy(impl_POA_CorbaFS_Inode * servant,
++ CORBA_Environment * ev);
++static void
++impl_CorbaFS_Inode_getStatus(impl_POA_CorbaFS_Inode * servant,
++ CORBA_unsigned_short * mode,
++ CORBA_unsigned_long * uid,
++ CORBA_unsigned_long * gid,
++ CORBA_unsigned_long * size,
++ CORBA_unsigned_long * inodeNum,
++ CORBA_unsigned_short * numLinks,
++ CORBA_long * atime,
++ CORBA_long * mtime,
++ CORBA_long * ctime, CORBA_Environment * ev);
++
++static void
++impl_CorbaFS_Inode_readpage(impl_POA_CorbaFS_Inode * servant,
++ CorbaFS_Buffer ** buffer,
++ CORBA_long size,
++ CORBA_long offset, CORBA_Environment * ev);
++
++static void
++impl_CorbaFS_Inode_release(impl_POA_CorbaFS_Inode * servant,
++ CORBA_Environment * ev);
++
++static void impl_CorbaFS_FileSystem__destroy(impl_POA_CorbaFS_FileSystem *
++ servant, CORBA_Environment * ev);
++static CorbaFS_Inode
++impl_CorbaFS_FileSystem_getInode(impl_POA_CorbaFS_FileSystem * servant,
++ CORBA_char * path, CORBA_Environment * ev);
++
++static CorbaFS_DirEntSeq
++ *impl_CorbaFS_FileSystem_readdir(impl_POA_CorbaFS_FileSystem * servant,
++ CORBA_char * path,
++
++ CORBA_Environment * ev);
++
++static CORBA_char
++ *impl_CorbaFS_FileSystem_readlink(impl_POA_CorbaFS_FileSystem * servant,
++ CORBA_char * filename,
++ CORBA_Environment * ev);
++
++/*** epv structures ***/
++
++static PortableServer_ServantBase__epv impl_CorbaFS_Inode_base_epv = {
++ NULL, /* _private data */
++ NULL, /* finalize routine */
++ NULL, /* default_POA routine */
++};
++static POA_CorbaFS_Inode__epv impl_CorbaFS_Inode_epv = {
++ NULL, /* _private */
++ (gpointer) & impl_CorbaFS_Inode_getStatus,
++
++ (gpointer) & impl_CorbaFS_Inode_readpage,
++
++ (gpointer) & impl_CorbaFS_Inode_release,
++
++};
++static PortableServer_ServantBase__epv impl_CorbaFS_FileSystem_base_epv = {
++ NULL, /* _private data */
++ NULL, /* finalize routine */
++ NULL, /* default_POA routine */
++};
++static POA_CorbaFS_FileSystem__epv impl_CorbaFS_FileSystem_epv = {
++ NULL, /* _private */
++ (gpointer) & impl_CorbaFS_FileSystem_getInode,
++
++ (gpointer) & impl_CorbaFS_FileSystem_readdir,
++
++ (gpointer) & impl_CorbaFS_FileSystem_readlink,
++
++};
++
++/*** vepv structures ***/
++
++static POA_CorbaFS_Inode__vepv impl_CorbaFS_Inode_vepv = {
++ &impl_CorbaFS_Inode_base_epv,
++ &impl_CorbaFS_Inode_epv,
++};
++static POA_CorbaFS_FileSystem__vepv impl_CorbaFS_FileSystem_vepv = {
++ &impl_CorbaFS_FileSystem_base_epv,
++ &impl_CorbaFS_FileSystem_epv,
++};
++
++/*** Stub implementations ***/
++
++static CorbaFS_Inode
++impl_CorbaFS_Inode__create(PortableServer_POA poa, CORBA_Environment * ev)
++{
++ CorbaFS_Inode retval;
++ impl_POA_CorbaFS_Inode *newservant;
++ PortableServer_ObjectId *objid;
++
++ newservant = g_new0(impl_POA_CorbaFS_Inode, 1);
++ newservant->servant.vepv = &impl_CorbaFS_Inode_vepv;
++ newservant->poa = poa;
++ POA_CorbaFS_Inode__init((PortableServer_Servant) newservant, ev);
++ objid = PortableServer_POA_activate_object(poa, newservant, ev);
++ CORBA_free(objid);
++ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev);
++
++ return retval;
++}
++
++static void
++impl_CorbaFS_Inode__destroy(impl_POA_CorbaFS_Inode * servant,
++ CORBA_Environment * ev)
++{
++ PortableServer_ObjectId *objid;
++
++ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev);
++ PortableServer_POA_deactivate_object(servant->poa, objid, ev);
++ CORBA_free(objid);
++
++ POA_CorbaFS_Inode__fini((PortableServer_Servant) servant, ev);
++ g_free(servant);
++}
++
++static void
++impl_CorbaFS_Inode_getStatus(impl_POA_CorbaFS_Inode * servant,
++ CORBA_unsigned_short * mode,
++ CORBA_unsigned_long * uid,
++ CORBA_unsigned_long * gid,
++ CORBA_unsigned_long * size,
++ CORBA_unsigned_long * inodeNum,
++ CORBA_unsigned_short * numLinks,
++ CORBA_long * atime,
++ CORBA_long * mtime,
++ CORBA_long * ctime, CORBA_Environment * ev)
++{
++ struct stat buf;
++
++ printf("Inode_getStatus()\n");
++ printf("Inode path = %s\n", servant->path);
++ lstat(servant->path, &buf);
++
++ *mode = buf.st_mode;
++ *uid = buf.st_uid;
++ *gid = buf.st_gid;
++ *size = buf.st_size;
++ *inodeNum = buf.st_ino;
++ *numLinks = buf.st_nlink;
++ *atime = buf.st_atime;
++ *mtime = buf.st_mtime;
++ *ctime = buf.st_ctime;
++}
++
++static void
++impl_CorbaFS_Inode_readpage(impl_POA_CorbaFS_Inode * servant,
++ CorbaFS_Buffer ** buffer,
++ CORBA_long size,
++ CORBA_long offset, CORBA_Environment * ev)
++{
++ int fd = -1, c = 0;
++
++ printf("Inode_readpage(buffer, %d, %d)\n", size, offset);
++ printf("Inode_readpage : path = %s\n", servant->path);
++
++ *buffer = CorbaFS_Buffer__alloc();
++ (*buffer)->_maximum = size;
++ (*buffer)->_buffer = CORBA_octet_allocbuf(size);
++
++ memset((*buffer)->_buffer, size, 0);
++
++ fd = open(servant->path, O_RDONLY);
++ printf("Inode_readpage : fd = %d\n", fd);
++ lseek(fd, offset, SEEK_SET);
++ c = read(fd, (*buffer)->_buffer, size);
++ printf("Inode_readpage : read %d bytes\n", c);
++ (*buffer)->_length = c;
++ close(fd);
++}
++
++static void
++impl_CorbaFS_Inode_release(impl_POA_CorbaFS_Inode * servant,
++ CORBA_Environment * ev)
++{
++ printf("Inode_release()\n");
++}
++
++static CorbaFS_FileSystem
++impl_CorbaFS_FileSystem__create(PortableServer_POA poa,
++ CORBA_Environment * ev)
++{
++ CorbaFS_FileSystem retval;
++ impl_POA_CorbaFS_FileSystem *newservant;
++ PortableServer_ObjectId *objid;
++
++ newservant = g_new0(impl_POA_CorbaFS_FileSystem, 1);
++ newservant->servant.vepv = &impl_CorbaFS_FileSystem_vepv;
++ newservant->poa = poa;
++ POA_CorbaFS_FileSystem__init((PortableServer_Servant) newservant, ev);
++ objid = PortableServer_POA_activate_object(poa, newservant, ev);
++ CORBA_free(objid);
++ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev);
++
++ return retval;
++}
++
++static void
++impl_CorbaFS_FileSystem__destroy(impl_POA_CorbaFS_FileSystem * servant,
++ CORBA_Environment * ev)
++{
++ PortableServer_ObjectId *objid;
++
++ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev);
++ PortableServer_POA_deactivate_object(servant->poa, objid, ev);
++ CORBA_free(objid);
++
++ POA_CorbaFS_FileSystem__fini((PortableServer_Servant) servant, ev);
++ g_free(servant);
++}
++
++static CorbaFS_Inode
++impl_CorbaFS_FileSystem_getInode(impl_POA_CorbaFS_FileSystem * servant,
++ CORBA_char * path, CORBA_Environment * ev)
++{
++ CorbaFS_Inode retval;
++ impl_POA_CorbaFS_Inode *inode;
++
++ printf("FileSystem_getInode(%s)\n", path);
++
++ retval = impl_CorbaFS_Inode__create(servant->poa, ev);
++
++ inode = PortableServer_POA_reference_to_servant( servant->poa, retval, ev );
++ inode->path = CORBA_string_dup(path);
++#if 0
++ inode->mode = 0040777; /* world-readable directory */
++ inode->uid = 0;
++ inode->gid = 0;
++ inode->size = 4096;
++ inode->inodeNum = inodeNum++;
++ inode->numLinks = 1;
++ inode->atime = 0;
++ inode->mtime = 100;
++ inode->ctime = 10000;
++#endif
++
++ return retval;
++}
++
++static CorbaFS_DirEntSeq *
++impl_CorbaFS_FileSystem_readdir(impl_POA_CorbaFS_FileSystem * servant,
++ CORBA_char * path, CORBA_Environment * ev)
++{
++ CorbaFS_DirEntSeq *retval;
++ CorbaFS_dirent *dirent;
++
++ DIR *dir;
++ struct dirent *dirp;
++ int c;
++
++ printf("FileSystem_readdir(%s)\n", path);
++
++ retval = CorbaFS_DirEntSeq__alloc();
++ retval->_maximum = 0;
++ retval->_length = 0;
++
++ dir = opendir(path);
++ if (dir == NULL)
++ return retval;
++
++ c = 0;
++ while ((dirp = readdir(dir)))
++ c++;
++
++ rewinddir(dir);
++
++ printf("%d directories\n", c);
++
++ retval->_buffer = CORBA_sequence_CorbaFS_dirent_allocbuf(c);
++ retval->_maximum = c;
++ dirent = retval->_buffer;
++
++ c = 0;
++ while ((dirp = readdir(dir)) && (c < retval->_maximum))
++ {
++ printf("Adding directory %d : %s (%d)\n", c, dirp->d_name, dirp->d_ino);
++
++ dirent[c].inode = dirp->d_ino;
++ dirent[c].name = CORBA_string_dup(dirp->d_name);
++ c++;
++ }
++ retval->_length = c;
++
++ closedir(dir);
++
++ return retval;
++}
++
++static CORBA_char *
++impl_CorbaFS_FileSystem_readlink(impl_POA_CorbaFS_FileSystem * servant,
++ CORBA_char * filename,
++ CORBA_Environment * ev)
++{
++ CORBA_char *retval = CORBA_OBJECT_NIL;
++ char tmp[MAXPATHLEN + 1];
++ int len;
++
++ printf("FileSystem_readlink(%s) = ", filename);
++ len = readlink(filename, tmp, MAXPATHLEN);
++ if (len != -1)
++ {
++ tmp[len] = '\0';
++ retval = CORBA_string_dup(tmp);
++ }
++
++ printf("%s\n", retval);
++
++ return retval;
++}
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/Makefile linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/Makefile
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/Makefile Thu Feb 1 11:47:04 2001
+@@ -0,0 +1,32 @@
++#
++# Makefile for KORBit
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++PROJECT = CorbaFS
++
++CFLAGS = -Wall `orbit-config --cflags server` -I../../..
++LDFLAGS = `orbit-config --libs server`
++OBJS = $(PROJECT)-common.o $(PROJECT)-skels.o $(PROJECT)-server.o
++ORBIT-IDL = orbit-idl
++
++$(PROJECT)-server: $(OBJS)
++ gcc -o $(PROJECT)-server $(OBJS) $(LDFLAGS)
++
++$(PROJECT)-server.o: $(PROJECT).h $(PROJECT)-skelimpl.c
++
++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-skels.c: ../$(PROJECT).idl
++ $(ORBIT-IDL) --nostubs ../$(PROJECT).idl
++
++clean:
++ rm -f $(OBJS) $(PROJECT)-server
++
++realclean: clean
++ rm -f $(PROJECT).h
++ rm -f $(PROJECT)-common.c
++ rm -f $(PROJECT)-skels.c
++ rm -f *~
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/README linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/README
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/README Thu Feb 1 11:47:04 2001
+@@ -0,0 +1,8 @@
++This server provides an NFS like capability of exporting an existing filesystem.
++
++ORB: ORBit
++Status: Working! (for readonly fs's)
++
++NOTE!!!!: When starting this server make sure you pass ORBit the options to
++ have it use ipv4 sockets and not unix domain sockets, or else bad
++ things will happen. You can use the included RunServer script.
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/RunServer.sh linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/RunServer.sh
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server/RunServer.sh Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/RunServer.sh Thu Feb 1 11:47:04 2001
+@@ -0,0 +1 @@
++./CorbaFS-server -ORBIIOPUSock=0 -ORBIIOPIPv4=1
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/CVS/Entries Thu Feb 1 11:47:04 2001
+@@ -0,0 +1,3 @@
++/PerlServer/1.2/Thu Feb 1 09:47:04 2001//
++/README/1.1/Thu Feb 1 09:47:04 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/CVS/Repository Thu Feb 1 11:47:04 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/CorbaFS/server-perl
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/CVS/Root
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/CVS/Root Thu Feb 1 11:47:04 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/PerlServer linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/PerlServer
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/PerlServer Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/PerlServer Thu Feb 1 11:47:04 2001
+@@ -0,0 +1,67 @@
++#!/usr/bin/perl -w
++use CORBA::ORBit idl => [ qw(../CorbaFS.idl) ];
++use Error qw(:try);
++use strict;
++
++
++package MyFSInode;
++@MyFSInode::ISA = qw(POA_CorbaFS::Inode);
++
++sub new {
++ my $self = bless { name => shift };
++ print "INODE CREATED: $self->{name}!\n";
++}
++
++sub getStatus {
++ my ($self) = @_;
++ print "$self->getStatus()\n";
++}
++
++sub readpage {
++ return "";
++}
++
++sub release {
++}
++
++
++package MyFileSystem;
++@MyFileSystem::ISA = qw(POA_CorbaFS::FileSystem);
++
++sub new {
++ my $self = bless { root => '/home' };
++}
++
++sub getInode {
++ my $path = shift;
++ print "getInode($path)\n";
++ return new MyFSInode($path);
++}
++
++sub readdir {
++ my $path = shift;
++ print "readdir($path)\n";
++ return [ { inode => 1, name => '...' } ];
++}
++
++sub readlink {
++ my $path = shift;
++ print "readlink($path)\n";
++ return "fredrik";
++}
++
++
++package Main;
++
++my $orb = CORBA::ORB_init("orbit-local-orb");
++my $poa = $orb->resolve_initial_references("RootPOA");
++
++my $Server = new MyFileSystem();
++my $id = $poa->activate_object($Server);
++my $ref = $orb->object_to_string($poa->id_to_reference($id));
++
++print "$ref\n";
++
++print "Running orb:\n";
++$orb->run();
++exit(0);
+diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/README linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/README
+--- linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/README Thu Feb 1 11:47:04 2001
+@@ -0,0 +1,4 @@
++Test filesystem implementation in Perl.
++
++ORB: ORBit/Perl
++Status: horribly broken
+diff -urN linux-2.4.1/net/korbit/modules/Echo/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/Echo/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Entries Thu Feb 1 11:47:05 2001
+@@ -0,0 +1,4 @@
++/Makefile/1.3/Thu Feb 1 09:47:04 2001//
++/README/1.1/Thu Feb 1 09:47:05 2001//
++/echo.idl/1.1/Thu Feb 1 09:47:05 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/Echo/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Entries.Log
+--- linux-2.4.1/net/korbit/modules/Echo/CVS/Entries.Log Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Entries.Log Thu Feb 1 11:47:06 2001
+@@ -0,0 +1,3 @@
++A D/client////
++A D/client-perl////
++A D/server////
+diff -urN linux-2.4.1/net/korbit/modules/Echo/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/Echo/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Repository Thu Feb 1 11:47:04 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/Echo
+diff -urN linux-2.4.1/net/korbit/modules/Echo/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Root
+--- linux-2.4.1/net/korbit/modules/Echo/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Root Thu Feb 1 11:47:04 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/Echo/Makefile linux-2.4.1-korbit/net/korbit/modules/Echo/Makefile
+--- linux-2.4.1/net/korbit/modules/Echo/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/Makefile Thu Feb 1 11:47:04 2001
+@@ -0,0 +1,11 @@
++#
++# Makefile for KORBit/modules/Console
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++
++subdir-$(CONFIG_CORBA_ECHO) := client server
++
++include $(TOPDIR)/Rules.make
++
+diff -urN linux-2.4.1/net/korbit/modules/Echo/README linux-2.4.1-korbit/net/korbit/modules/Echo/README
+--- linux-2.4.1/net/korbit/modules/Echo/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/README Thu Feb 1 11:47:05 2001
+@@ -0,0 +1,2 @@
++The Echo test is very similar to the console test, but it also "returns" a
++"random" number. The random number, in our case, is simply a constant.
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Echo/client/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/Echo/client/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/CVS/Entries Thu Feb 1 11:47:05 2001
+@@ -0,0 +1,6 @@
++/Makefile/1.4/Thu Feb 1 09:47:05 2001//
++/Makefile.user/1.1/Thu Feb 1 09:47:05 2001//
++/README/1.1/Thu Feb 1 09:47:05 2001//
++/RunClient.sh/1.1/Thu Feb 1 09:47:05 2001//
++/echo-client.c/1.6/Thu Feb 1 09:47:05 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Echo/client/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/Echo/client/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/CVS/Repository Thu Feb 1 11:47:05 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/Echo/client
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Echo/client/CVS/Root
+--- linux-2.4.1/net/korbit/modules/Echo/client/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/CVS/Root Thu Feb 1 11:47:05 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/Makefile linux-2.4.1-korbit/net/korbit/modules/Echo/client/Makefile
+--- linux-2.4.1/net/korbit/modules/Echo/client/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/Makefile Thu Feb 1 11:47:05 2001
+@@ -0,0 +1,20 @@
++#
++# Makefile for KORBit
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := corba-echo-client.o
++
++obj-y := echo-common.o echo-stubs.o echo-client.o
++obj-m := $(O_TARGET)
++
++include ../../Makefile.module
++
++echo-client.c: echo.h
++
++echo.h echo-common.c echo-stubs.c: ../echo.idl
++ $(ORBIT_IDL) --noskels ../echo.idl
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/Makefile.user linux-2.4.1-korbit/net/korbit/modules/Echo/client/Makefile.user
+--- linux-2.4.1/net/korbit/modules/Echo/client/Makefile.user Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/Makefile.user Thu Feb 1 11:47:05 2001
+@@ -0,0 +1,32 @@
++#
++# Makefile for KORBit
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++PROJECT = echo
++
++CFLAGS = -Wall `orbit-config --cflags client` -I../../..
++LDFLAGS = `orbit-config --libs client`
++OBJS = $(PROJECT)-common.o $(PROJECT)-stubs.o $(PROJECT)-client.o
++ORBIT-IDL = orbit-idl
++
++$(PROJECT)-client: $(OBJS)
++ gcc -o $(PROJECT)-client $(OBJS) $(LDFLAGS)
++
++$(PROJECT)-client.c: $(PROJECT).h
++
++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-stubs.c: ../$(PROJECT).idl
++ $(ORBIT-IDL) --noskels ../$(PROJECT).idl
++
++clean:
++ rm -f $(OBJS) $(PROJECT)-client
++
++realclean: clean
++ rm -f $(PROJECT).h
++ rm -f $(PROJECT)-common.c
++ rm -f $(PROJECT)-stubs.c
++ rm -f *~
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/README linux-2.4.1-korbit/net/korbit/modules/Echo/client/README
+--- linux-2.4.1/net/korbit/modules/Echo/client/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/README Thu Feb 1 11:47:05 2001
+@@ -0,0 +1,4 @@
++This simply tests the Echo service.
++
++ORB: ORBit
++Status: working
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/RunClient.sh linux-2.4.1-korbit/net/korbit/modules/Echo/client/RunClient.sh
+--- linux-2.4.1/net/korbit/modules/Echo/client/RunClient.sh Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/RunClient.sh Thu Feb 1 11:47:05 2001
+@@ -0,0 +1,3 @@
++#!/bin/sh
++date
++./echo-client `cat /proc/corba/echo-server` 5
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/echo-client.c linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo-client.c
+--- linux-2.4.1/net/korbit/modules/Echo/client/echo-client.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo-client.c Thu Feb 1 11:47:05 2001
+@@ -0,0 +1,119 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <sys/time.h>
++#include <unistd.h>
++#include <orb/orbit.h>
++
++#ifdef __KERNEL__
++#include <linux/init.h>
++#include <linux/module.h>
++#include "korbit.h"
++#endif
++#include "echo.h"
++
++Echo echo_client, bec;
++
++#define BATCH_SIZE 1
++
++
++#ifndef __KERNEL__
++int main (int argc, char *argv[]) {
++#else
++int __init corba_echo_init(void) {
++ int argc = 1; char *argv[] = { "echo-client", 0, 0 };
++#endif
++ CORBA_Environment ev;
++ CORBA_ORB orb;
++ CORBA_long rv;
++ char buf[30];
++ int i, j;
++
++ int niters = 5;
++
++#ifndef __KERNEL__
++ struct timeval start, end;
++ long diff, diffsum = 0;
++#endif
++
++ CORBA_exception_init(&ev);
++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", &ev);
++
++#ifdef __KERNEL__
++ {
++ int c, fd = open("/tmp/echo-ior", O_RDONLY, 0);
++ if (fd == -1)
++ return -1;
++ printf("Reading IOR from /tmp/echo-ior\n");
++ argv[1] = malloc(501);
++ c = read(fd, argv[1], 500);
++ argv[1][c] = '\0';
++ printf("Reading %d bytes: %s\n", c, argv[1]);
++ }
++#else
++ if(argc < 2)
++ {
++ printf("Need an IOR as argv[1]\n");
++ return 1;
++ }
++
++ if(argc == 3)
++ niters = atoi(argv[2]);
++#endif
++
++ echo_client = CORBA_ORB_string_to_object(orb, argv[1], &ev);
++ if (!echo_client) {
++ printf("Cannot bind to %s\n", argv[1]);
++ return 1;
++ }
++
++ for(i = 0; i < niters; i++) {
++ g_snprintf(buf, sizeof(buf), "Hello, world [%d]", i);
++#ifdef __KERNEL__
++ bec = Echo_echoString(echo_client, buf, &rv, &ev);
++#else
++ gettimeofday(&start, NULL);
++ for (j = BATCH_SIZE; j > 0; j--) {
++ bec = Echo_echoString(echo_client, buf, &rv, &ev);
++ if (j != 1) CORBA_Object_release(bec, &ev);
++ }
++ gettimeofday(&end, NULL);
++ diff = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
++ diff /= BATCH_SIZE;
++ diffsum += diff;
++
++ printf("duration = %d usec\t", diff);
++#endif
++
++ if(ev._major != CORBA_NO_EXCEPTION) {
++ printf("\nWe got exception %d from echoString!\n", ev._major);
++ return 1;
++ }
++
++ CORBA_Object_release(echo_client, &ev);
++ if(ev._major != CORBA_NO_EXCEPTION) {
++ printf("we got exception %d from release!\n", ev._major);
++ return 1;
++ }
++
++ printf("[client] %d\n", rv);
++
++ echo_client = bec; bec = CORBA_OBJECT_NIL;
++ }
++
++#ifndef __KERNEL__
++ printf("duration average = %d usec\n", diffsum / niters);
++ CORBA_Object_release(echo_client, &ev);
++ CORBA_Object_release((CORBA_Object)orb, &ev);
++#endif
++
++ return 0;
++}
++
++
++#ifdef __KERNEL__
++void corba_echo_exit(void) {
++}
++
++module_init(corba_echo_init)
++module_exit(corba_echo_exit)
++#endif
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/echo-common.c linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo-common.c
+--- linux-2.4.1/net/korbit/modules/Echo/client/echo-common.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo-common.c Thu Feb 1 16:36:36 2001
+@@ -0,0 +1,27 @@
++/*
++ * This file was generated by orbit-idl - DO NOT EDIT!
++ */
++
++#include <string.h>
++#include "echo.h"
++
++#if ( (TC_IMPL_TC_Echo_0 == 'e') \
++&& (TC_IMPL_TC_Echo_1 == 'c') \
++&& (TC_IMPL_TC_Echo_2 == 'h') \
++&& (TC_IMPL_TC_Echo_3 == 'o') \
++) && !defined(TC_DEF_TC_Echo)
++#define TC_DEF_TC_Echo 1
++const struct CORBA_TypeCode_struct TC_Echo_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_objref, "Echo", "IDL:Echo:1.0",
++ 0, 0,
++ NULL,
++ NULL,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++CORBA_unsigned_long Echo__classid = 0;
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/echo-stubs.c linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo-stubs.c
+--- linux-2.4.1/net/korbit/modules/Echo/client/echo-stubs.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo-stubs.c Thu Feb 1 16:36:36 2001
+@@ -0,0 +1,134 @@
++/*
++ * This file was generated by orbit-idl - DO NOT EDIT!
++ */
++
++#include <string.h>
++#include "echo.h"
++
++Echo
++Echo_echoString(Echo _obj, const CORBA_char * astring, CORBA_long * anum,
++ CORBA_Environment * ev)
++{
++ register GIOP_unsigned_long _ORBIT_request_id,
++ _ORBIT_system_exception_minor;
++ register CORBA_completion_status _ORBIT_completion_status;
++ register GIOPSendBuffer *_ORBIT_send_buffer;
++ register GIOPRecvBuffer *_ORBIT_recv_buffer;
++ register GIOPConnection *_cnx;
++ Echo _ORBIT_retval;
++
++ if (_obj->servant && _obj->vepv && Echo__classid) {
++ _ORBIT_retval =
++ ((POA_Echo__epv *) _obj->vepv[Echo__classid])->echoString(_obj->
++ servant,
++ astring,
++ anum, ev);
++ return _ORBIT_retval;
++ }
++ _cnx = ORBit_object_get_connection(_obj);
++ _ORBIT_retry_request:
++ _ORBIT_send_buffer = NULL;
++ _ORBIT_recv_buffer = NULL;
++ _ORBIT_completion_status = CORBA_COMPLETED_NO;
++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0));
++ { /* marshalling */
++ static const struct
++ {
++ CORBA_unsigned_long len;
++ char opname[11];
++ }
++ _ORBIT_operation_name_data =
++ {
++ 11, "echoString"};
++ static const struct iovec _ORBIT_operation_vec =
++ { (gpointer) & _ORBIT_operation_name_data, 15 };
++ register CORBA_unsigned_long _ORBIT_tmpvar_0;
++ CORBA_unsigned_long _ORBIT_tmpvar_1;
++
++ _ORBIT_send_buffer =
++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id,
++ CORBA_TRUE,
++ &(_obj->active_profile->object_key_vec),
++ &_ORBIT_operation_vec,
++ &ORBit_default_principal_iovec);
++
++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE;
++ if (!_ORBIT_send_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_tmpvar_1 = strlen(astring) + 1;
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), 4);
++ {
++ guchar *_ORBIT_t;
++
++ _ORBIT_t = alloca(sizeof(_ORBIT_tmpvar_1));
++ memcpy(_ORBIT_t, &(_ORBIT_tmpvar_1), sizeof(_ORBIT_tmpvar_1));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), (_ORBIT_t),
++ sizeof(_ORBIT_tmpvar_1));
++ }
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer),
++ (astring),
++ sizeof(astring[_ORBIT_tmpvar_0]) *
++ _ORBIT_tmpvar_1);
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE;
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ _ORBIT_send_buffer = NULL;
++ }
++ { /* demarshalling */
++ register guchar *_ORBIT_curptr;
++
++ _ORBIT_recv_buffer =
++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE);
++ if (!_ORBIT_recv_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_completion_status = CORBA_COMPLETED_YES;
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status !=
++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception;
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) {
++ GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur = _ORBIT_curptr;
++ _ORBIT_retval =
++ ORBit_demarshal_object(_ORBIT_recv_buffer,
++ GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)->
++ connection->orb_data);
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++
++ (*((guint32 *) & ((*anum)))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));} else {
++ GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur = _ORBIT_curptr;
++ _ORBIT_retval =
++ ORBit_demarshal_object(_ORBIT_recv_buffer,
++ GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)->
++ connection->orb_data);
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++ (*anum) = *((CORBA_long *) _ORBIT_curptr);
++ }
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ _ORBIT_system_exception:
++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor,
++ _ORBIT_completion_status);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ return _ORBIT_retval;
++ _ORBIT_msg_exception:
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status ==
++ GIOP_LOCATION_FORWARD) {
++ if (_obj->forward_locations != NULL)
++ ORBit_delete_profiles(_obj->forward_locations);
++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer);
++ _cnx = ORBit_object_get_forwarded_connection(_obj);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++
++ goto _ORBIT_retry_request;
++ } else {
++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ }
++ }
++}
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client/echo.h linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo.h
+--- linux-2.4.1/net/korbit/modules/Echo/client/echo.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo.h Thu Feb 1 16:36:36 2001
+@@ -0,0 +1,77 @@
++/*
++ * This file was generated by orbit-idl - DO NOT EDIT!
++ */
++
++#include <glib.h>
++#define ORBIT_IDL_SERIAL 9
++#include <orb/orbit.h>
++
++#ifndef echo_H
++#define echo_H 1
++#ifdef __cplusplus
++extern "C"
++{
++#endif /* __cplusplus */
++
++/** typedefs **/
++#if !defined(ORBIT_DECL_Echo) && !defined(_Echo_defined)
++#define ORBIT_DECL_Echo 1
++#define _Echo_defined 1
++#define Echo__free CORBA_Object__free
++ typedef CORBA_Object Echo;
++ extern CORBA_unsigned_long Echo__classid;
++#if !defined(TC_IMPL_TC_Echo_0)
++#define TC_IMPL_TC_Echo_0 'e'
++#define TC_IMPL_TC_Echo_1 'c'
++#define TC_IMPL_TC_Echo_2 'h'
++#define TC_IMPL_TC_Echo_3 'o'
++ extern const struct CORBA_TypeCode_struct TC_Echo_struct;
++#define TC_Echo ((CORBA_TypeCode)&TC_Echo_struct)
++#endif
++#endif
++
++/** POA structures **/
++ typedef struct
++ {
++ void *_private;
++
++ Echo(*echoString) (PortableServer_Servant _servant,
++ const CORBA_char * astring, CORBA_long * anum,
++ CORBA_Environment * ev);
++ }
++ POA_Echo__epv;
++ typedef struct
++ {
++ PortableServer_ServantBase__epv *_base_epv;
++ POA_Echo__epv *Echo_epv;
++ }
++ POA_Echo__vepv;
++ typedef struct
++ {
++ void *_private;
++ POA_Echo__vepv *vepv;
++ }
++ POA_Echo;
++ extern void POA_Echo__init(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++ extern void POA_Echo__fini(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++
++/** prototypes **/
++ Echo Echo_echoString(Echo _obj, const CORBA_char * astring,
++ CORBA_long * anum, CORBA_Environment * ev);
++
++ void _ORBIT_skel_Echo_echoString(POA_Echo * _ORBIT_servant,
++ GIOPRecvBuffer * _ORBIT_recv_buffer,
++ CORBA_Environment * ev,
++ Echo(*_impl_echoString)
++ (PortableServer_Servant _servant,
++ const CORBA_char * astring,
++ CORBA_long * anum,
++ CORBA_Environment * ev));
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif
++#undef ORBIT_IDL_SERIAL
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client-perl/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/Echo/client-perl/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/CVS/Entries Thu Feb 1 11:47:06 2001
+@@ -0,0 +1,3 @@
++/PerlTest/1.2/Thu Feb 1 09:47:06 2001//
++/README/1.1/Thu Feb 1 09:47:06 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client-perl/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/Echo/client-perl/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/CVS/Repository Thu Feb 1 11:47:06 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/Echo/client-perl
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client-perl/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/CVS/Root
+--- linux-2.4.1/net/korbit/modules/Echo/client-perl/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/CVS/Root Thu Feb 1 11:47:06 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client-perl/PerlTest linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/PerlTest
+--- linux-2.4.1/net/korbit/modules/Echo/client-perl/PerlTest Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/PerlTest Thu Feb 1 11:47:06 2001
+@@ -0,0 +1,17 @@
++#!/usr/bin/perl -w
++
++use CORBA::ORBit idl => [ qw(../echo.idl) ];
++use Error qw(:try);
++use strict;
++
++my $orb = CORBA::ORB_init("orbit-local-orb");
++open IOR, "/proc/corba/echo-server" or die "no console server found!";
++my $ior = <IOR>;
++close IOR;
++chomp($ior); # Kill fredrik's newline...
++
++my $echo = $orb->string_to_object($ior);
++# Echo echoString(in string astring, out long anum);
++my ($echo2, $num) = $echo->echoString("Echo Strange World");
++
++print "Return Echo = $echo2\nnum = $num\n";
+diff -urN linux-2.4.1/net/korbit/modules/Echo/client-perl/README linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/README
+--- linux-2.4.1/net/korbit/modules/Echo/client-perl/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/README Thu Feb 1 11:47:06 2001
+@@ -0,0 +1,4 @@
++Another test of the echo server.
++
++ORB: ORBit/Perl
++Status: Working fine
+diff -urN linux-2.4.1/net/korbit/modules/Echo/echo.idl linux-2.4.1-korbit/net/korbit/modules/Echo/echo.idl
+--- linux-2.4.1/net/korbit/modules/Echo/echo.idl Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/echo.idl Thu Feb 1 11:47:05 2001
+@@ -0,0 +1,3 @@
++interface Echo {
++ Echo echoString(in string astring, out long anum);
++};
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Echo/server/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/Echo/server/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/CVS/Entries Thu Feb 1 11:47:06 2001
+@@ -0,0 +1,6 @@
++/Makefile/1.2/Thu Feb 1 09:47:06 2001//
++/Makefile.user/1.3/Thu Feb 1 09:47:06 2001//
++/README/1.1/Thu Feb 1 09:47:06 2001//
++/RunServer.sh/1.1/Thu Feb 1 09:47:06 2001//
++/echo-server.c/1.8/Thu Feb 1 09:47:06 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Echo/server/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/Echo/server/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/CVS/Repository Thu Feb 1 11:47:06 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/Echo/server
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Echo/server/CVS/Root
+--- linux-2.4.1/net/korbit/modules/Echo/server/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/CVS/Root Thu Feb 1 11:47:06 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/Makefile linux-2.4.1-korbit/net/korbit/modules/Echo/server/Makefile
+--- linux-2.4.1/net/korbit/modules/Echo/server/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/Makefile Thu Feb 1 11:47:06 2001
+@@ -0,0 +1,21 @@
++#
++# Makefile for KORBit
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := corba-echo-server.o
++
++obj-y := echo-server.o echo-skels.o echo-common.o
++obj-m := $(O_TARGET)
++
++include ../../Makefile.module
++
++echo-server.c: echo.h echo-skels.c
++
++
++echo.h echo-common.c echo-skels.c: ../echo.idl
++ $(ORBIT_IDL) ../echo.idl
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/Makefile.user linux-2.4.1-korbit/net/korbit/modules/Echo/server/Makefile.user
+--- linux-2.4.1/net/korbit/modules/Echo/server/Makefile.user Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/Makefile.user Thu Feb 1 11:47:06 2001
+@@ -0,0 +1,27 @@
++#
++# Makefile for user level server
++#
++
++PROJECT = echo
++
++CFLAGS = -Wall `orbit-config --cflags server` -I../../..
++LDFLAGS = `orbit-config --libs server`
++OBJS = $(PROJECT)-common.o $(PROJECT)-skels.o $(PROJECT)-server.o
++ORBIT-IDL = orbit-idl
++
++$(PROJECT)-server: $(OBJS)
++ gcc -o $(PROJECT)-server $(OBJS) $(LDFLAGS)
++
++$(PROJECT)-server.c: $(PROJECT).h
++
++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-skels.c: ../$(PROJECT).idl
++ $(ORBIT-IDL) --nostubs ../$(PROJECT).idl
++
++clean:
++ rm -f $(OBJS) $(PROJECT)-server
++
++realclean: clean
++ rm -f $(PROJECT).h
++ rm -f $(PROJECT)-common.c
++ rm -f $(PROJECT)-skels.c
++ rm -f *~
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/README linux-2.4.1-korbit/net/korbit/modules/Echo/server/README
+--- linux-2.4.1/net/korbit/modules/Echo/server/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/README Thu Feb 1 11:47:06 2001
+@@ -0,0 +1,5 @@
++This server implements the kernel side interface in terms of printk.
++
++This server also builds in user space with ORBit. Build with
++ make -f Makefile.user
++
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/RunServer.sh linux-2.4.1-korbit/net/korbit/modules/Echo/server/RunServer.sh
+--- linux-2.4.1/net/korbit/modules/Echo/server/RunServer.sh Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/RunServer.sh Thu Feb 1 11:47:06 2001
+@@ -0,0 +1 @@
++./echo-server -ORBIIOPUSock=0 -ORBIIOPIPv4=1
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/echo-common.c linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-common.c
+--- linux-2.4.1/net/korbit/modules/Echo/server/echo-common.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-common.c Thu Feb 1 16:36:57 2001
+@@ -0,0 +1,27 @@
++/*
++ * This file was generated by orbit-idl - DO NOT EDIT!
++ */
++
++#include <string.h>
++#include "echo.h"
++
++#if ( (TC_IMPL_TC_Echo_0 == 'e') \
++&& (TC_IMPL_TC_Echo_1 == 'c') \
++&& (TC_IMPL_TC_Echo_2 == 'h') \
++&& (TC_IMPL_TC_Echo_3 == 'o') \
++) && !defined(TC_DEF_TC_Echo)
++#define TC_DEF_TC_Echo 1
++const struct CORBA_TypeCode_struct TC_Echo_struct = {
++
++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1},
++ ORBIT_PSEUDO_TYPECODE},
++
++ CORBA_tk_objref, "Echo", "IDL:Echo:1.0",
++ 0, 0,
++ NULL,
++ NULL,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++CORBA_unsigned_long Echo__classid = 0;
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/echo-server.c linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-server.c
+--- linux-2.4.1/net/korbit/modules/Echo/server/echo-server.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-server.c Thu Feb 1 11:47:06 2001
+@@ -0,0 +1,103 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <signal.h>
++#include <orb/orbit.h>
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include "echo.h"
++#include "glib.h"
++#include "korbit.h"
++
++Echo echo_client = CORBA_OBJECT_NIL;
++
++static CORBA_Object
++do_echoString(PortableServer_Servant servant,
++ CORBA_char *astring,
++ CORBA_long *outnum,
++ CORBA_Environment *ev);
++
++PortableServer_ServantBase__epv base_epv = {
++ NULL,
++ NULL,
++ NULL
++};
++POA_Echo__epv echo_epv = { NULL, do_echoString };
++POA_Echo__vepv poa_echo_vepv = { &base_epv, &echo_epv };
++POA_Echo poa_echo_servant = { NULL, &poa_echo_vepv };
++
++PortableServer_ObjectId objid = {0, sizeof("myEchoString"), "myEchoString"};
++PortableServer_POA poa;
++CORBA_Environment *ev;
++
++#ifdef __KERNEL__
++int __init corba_echo_init(void)
++#else
++int main(int argc, char *argv[])
++#endif
++{
++#ifdef __KERNEL__
++ int argc = 1; char *argv[] = { "server", 0 };
++#endif
++ CORBA_ORB orb;
++ ev = g_new0(CORBA_Environment, 1);
++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev);
++ if (!orb) {
++ printf("Error getting ORB!\n");
++ return 1;
++ }
++
++ poa = (PortableServer_POA)
++ CORBA_ORB_resolve_initial_references(orb, "RootPOA", ev);
++ if (!poa) {
++ printf("Error getting POA!\n");
++ return 1;
++ }
++
++ PortableServer_POAManager_activate(
++ PortableServer_POA__get_the_POAManager(poa, ev), ev);
++
++
++ POA_Echo__init(&poa_echo_servant, ev);
++ PortableServer_POA_activate_object_with_id(poa,
++ &objid, &poa_echo_servant, ev);
++
++ echo_client = PortableServer_POA_servant_to_reference(poa,
++ &poa_echo_servant,
++ ev);
++ if (!echo_client) {
++ printf("Cannot get objref\n");
++ return 1;
++ }
++
++ korbit_register_ior("echo-server", echo_client, orb, ev);
++
++ CORBA_ORB_run(orb, ev);
++ return 0;
++}
++
++#ifdef __KERNEL__
++void corba_echo_exit(void) {
++ PortableServer_POA_deactivate_object(poa, &objid, ev);
++ remove_proc_entry("corba/echo-server", 0);
++}
++
++module_init(corba_echo_init)
++module_exit(corba_echo_exit)
++#endif
++
++static CORBA_Object
++do_echoString(PortableServer_Servant servant,
++ CORBA_char *astring,
++ CORBA_long *outnum,
++ CORBA_Environment *ev)
++{
++ *outnum = 12345678;
++
++#if 1
++ g_message("[server] %s -> %d", astring, *outnum);
++#endif
++
++ return CORBA_Object_duplicate(echo_client, ev);
++}
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/echo-skels.c linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-skels.c
+--- linux-2.4.1/net/korbit/modules/Echo/server/echo-skels.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-skels.c Thu Feb 1 16:36:57 2001
+@@ -0,0 +1,115 @@
++/*
++ * This file was generated by orbit-idl - DO NOT EDIT!
++ */
++
++#include <string.h>
++#include "echo.h"
++
++void
++_ORBIT_skel_Echo_echoString(POA_Echo * _ORBIT_servant,
++ GIOPRecvBuffer * _ORBIT_recv_buffer,
++ CORBA_Environment * ev,
++ Echo(*_impl_echoString) (PortableServer_Servant
++ _servant,
++ const CORBA_char *
++ astring,
++ CORBA_long * anum,
++ CORBA_Environment * ev))
++{
++ Echo _ORBIT_retval;
++ CORBA_char *astring;
++ CORBA_long anum;
++
++ { /* demarshalling */
++ guchar *_ORBIT_curptr;
++ register CORBA_unsigned_long _ORBIT_tmpvar_2;
++ CORBA_unsigned_long _ORBIT_tmpvar_3;
++
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++
++ (*((guint32 *) & (_ORBIT_tmpvar_3))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));
++ _ORBIT_curptr += 4;
++ astring = (void *) _ORBIT_curptr;
++ _ORBIT_curptr += sizeof(astring[_ORBIT_tmpvar_2]) * _ORBIT_tmpvar_3;
++ } else {
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++ _ORBIT_tmpvar_3 = *((CORBA_unsigned_long *) _ORBIT_curptr);
++ _ORBIT_curptr += 4;
++ astring = (void *) _ORBIT_curptr;
++ _ORBIT_curptr += sizeof(astring[_ORBIT_tmpvar_2]) * _ORBIT_tmpvar_3;
++ }
++ }
++ _ORBIT_retval = _impl_echoString(_ORBIT_servant, astring, &(anum), ev);
++ { /* marshalling */
++ register GIOPSendBuffer *_ORBIT_send_buffer;
++
++ _ORBIT_send_buffer =
++ giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)->
++ connection, NULL,
++ _ORBIT_recv_buffer->message.u.request.
++ request_id, ev->_major);
++ if (_ORBIT_send_buffer) {
++ if (ev->_major == CORBA_NO_EXCEPTION) {
++ ORBit_marshal_object(_ORBIT_send_buffer, _ORBIT_retval);
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), 4);
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), &(anum),
++ sizeof(anum));
++ } else
++ ORBit_send_system_exception(_ORBIT_send_buffer, ev);
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ }
++ if (ev->_major == CORBA_NO_EXCEPTION)
++ CORBA_Object_release(_ORBIT_retval, ev);
++ }
++}
++static ORBitSkeleton
++get_skel_Echo(POA_Echo * servant,
++ GIOPRecvBuffer * _ORBIT_recv_buffer, gpointer * impl)
++{
++ gchar *opname = _ORBIT_recv_buffer->message.u.request.operation;
++
++ switch (opname[0]) {
++ case 'e':
++ if (strcmp((opname + 1), "choString"))
++ break;
++ *impl = (gpointer) servant->vepv->Echo_epv->echoString;
++ return (ORBitSkeleton) _ORBIT_skel_Echo_echoString;
++ break;
++ default:
++ break;
++ }
++ return NULL;
++}
++
++static void
++init_local_objref_Echo(CORBA_Object obj, POA_Echo * servant)
++{
++ obj->vepv[Echo__classid] = servant->vepv->Echo_epv;
++}
++
++void
++POA_Echo__init(PortableServer_Servant servant, CORBA_Environment * env)
++{
++ static const PortableServer_ClassInfo class_info =
++ { (ORBit_impl_finder) & get_skel_Echo, "IDL:Echo:1.0",
++ (ORBit_local_objref_init) & init_local_objref_Echo };
++
++ PortableServer_ServantBase__init(((PortableServer_ServantBase *) servant),
++ env);
++ ORBIT_OBJECT_KEY(((PortableServer_ServantBase *) servant)->_private)->
++ class_info = (PortableServer_ClassInfo *) & class_info;
++ if (!Echo__classid)
++ Echo__classid = ORBit_register_class(&class_info);
++}
++
++void
++POA_Echo__fini(PortableServer_Servant servant, CORBA_Environment * env)
++{
++ PortableServer_ServantBase__fini(servant, env);
++}
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/echo-stubs.c linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-stubs.c
+--- linux-2.4.1/net/korbit/modules/Echo/server/echo-stubs.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-stubs.c Thu Feb 1 16:36:57 2001
+@@ -0,0 +1,134 @@
++/*
++ * This file was generated by orbit-idl - DO NOT EDIT!
++ */
++
++#include <string.h>
++#include "echo.h"
++
++Echo
++Echo_echoString(Echo _obj, const CORBA_char * astring, CORBA_long * anum,
++ CORBA_Environment * ev)
++{
++ register GIOP_unsigned_long _ORBIT_request_id,
++ _ORBIT_system_exception_minor;
++ register CORBA_completion_status _ORBIT_completion_status;
++ register GIOPSendBuffer *_ORBIT_send_buffer;
++ register GIOPRecvBuffer *_ORBIT_recv_buffer;
++ register GIOPConnection *_cnx;
++ Echo _ORBIT_retval;
++
++ if (_obj->servant && _obj->vepv && Echo__classid) {
++ _ORBIT_retval =
++ ((POA_Echo__epv *) _obj->vepv[Echo__classid])->echoString(_obj->
++ servant,
++ astring,
++ anum, ev);
++ return _ORBIT_retval;
++ }
++ _cnx = ORBit_object_get_connection(_obj);
++ _ORBIT_retry_request:
++ _ORBIT_send_buffer = NULL;
++ _ORBIT_recv_buffer = NULL;
++ _ORBIT_completion_status = CORBA_COMPLETED_NO;
++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0));
++ { /* marshalling */
++ static const struct
++ {
++ CORBA_unsigned_long len;
++ char opname[11];
++ }
++ _ORBIT_operation_name_data =
++ {
++ 11, "echoString"};
++ static const struct iovec _ORBIT_operation_vec =
++ { (gpointer) & _ORBIT_operation_name_data, 15 };
++ register CORBA_unsigned_long _ORBIT_tmpvar_0;
++ CORBA_unsigned_long _ORBIT_tmpvar_1;
++
++ _ORBIT_send_buffer =
++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id,
++ CORBA_TRUE,
++ &(_obj->active_profile->object_key_vec),
++ &_ORBIT_operation_vec,
++ &ORBit_default_principal_iovec);
++
++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE;
++ if (!_ORBIT_send_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_tmpvar_1 = strlen(astring) + 1;
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), 4);
++ {
++ guchar *_ORBIT_t;
++
++ _ORBIT_t = alloca(sizeof(_ORBIT_tmpvar_1));
++ memcpy(_ORBIT_t, &(_ORBIT_tmpvar_1), sizeof(_ORBIT_tmpvar_1));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER
++ (_ORBIT_send_buffer), (_ORBIT_t),
++ sizeof(_ORBIT_tmpvar_1));
++ }
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer),
++ (astring),
++ sizeof(astring[_ORBIT_tmpvar_0]) *
++ _ORBIT_tmpvar_1);
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE;
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ _ORBIT_send_buffer = NULL;
++ }
++ { /* demarshalling */
++ register guchar *_ORBIT_curptr;
++
++ _ORBIT_recv_buffer =
++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE);
++ if (!_ORBIT_recv_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_completion_status = CORBA_COMPLETED_YES;
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status !=
++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception;
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) {
++ GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur = _ORBIT_curptr;
++ _ORBIT_retval =
++ ORBit_demarshal_object(_ORBIT_recv_buffer,
++ GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)->
++ connection->orb_data);
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++
++ (*((guint32 *) & ((*anum)))) =
++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));} else {
++ GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur = _ORBIT_curptr;
++ _ORBIT_retval =
++ ORBit_demarshal_object(_ORBIT_recv_buffer,
++ GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)->
++ connection->orb_data);
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4);
++ (*anum) = *((CORBA_long *) _ORBIT_curptr);
++ }
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ _ORBIT_system_exception:
++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor,
++ _ORBIT_completion_status);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ return _ORBIT_retval;
++ _ORBIT_msg_exception:
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status ==
++ GIOP_LOCATION_FORWARD) {
++ if (_obj->forward_locations != NULL)
++ ORBit_delete_profiles(_obj->forward_locations);
++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer);
++ _cnx = ORBit_object_get_forwarded_connection(_obj);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++
++ goto _ORBIT_retry_request;
++ } else {
++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ }
++ }
++}
+diff -urN linux-2.4.1/net/korbit/modules/Echo/server/echo.h linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo.h
+--- linux-2.4.1/net/korbit/modules/Echo/server/echo.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo.h Thu Feb 1 16:36:57 2001
+@@ -0,0 +1,77 @@
++/*
++ * This file was generated by orbit-idl - DO NOT EDIT!
++ */
++
++#include <glib.h>
++#define ORBIT_IDL_SERIAL 9
++#include <orb/orbit.h>
++
++#ifndef echo_H
++#define echo_H 1
++#ifdef __cplusplus
++extern "C"
++{
++#endif /* __cplusplus */
++
++/** typedefs **/
++#if !defined(ORBIT_DECL_Echo) && !defined(_Echo_defined)
++#define ORBIT_DECL_Echo 1
++#define _Echo_defined 1
++#define Echo__free CORBA_Object__free
++ typedef CORBA_Object Echo;
++ extern CORBA_unsigned_long Echo__classid;
++#if !defined(TC_IMPL_TC_Echo_0)
++#define TC_IMPL_TC_Echo_0 'e'
++#define TC_IMPL_TC_Echo_1 'c'
++#define TC_IMPL_TC_Echo_2 'h'
++#define TC_IMPL_TC_Echo_3 'o'
++ extern const struct CORBA_TypeCode_struct TC_Echo_struct;
++#define TC_Echo ((CORBA_TypeCode)&TC_Echo_struct)
++#endif
++#endif
++
++/** POA structures **/
++ typedef struct
++ {
++ void *_private;
++
++ Echo(*echoString) (PortableServer_Servant _servant,
++ const CORBA_char * astring, CORBA_long * anum,
++ CORBA_Environment * ev);
++ }
++ POA_Echo__epv;
++ typedef struct
++ {
++ PortableServer_ServantBase__epv *_base_epv;
++ POA_Echo__epv *Echo_epv;
++ }
++ POA_Echo__vepv;
++ typedef struct
++ {
++ void *_private;
++ POA_Echo__vepv *vepv;
++ }
++ POA_Echo;
++ extern void POA_Echo__init(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++ extern void POA_Echo__fini(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++
++/** prototypes **/
++ Echo Echo_echoString(Echo _obj, const CORBA_char * astring,
++ CORBA_long * anum, CORBA_Environment * ev);
++
++ void _ORBIT_skel_Echo_echoString(POA_Echo * _ORBIT_servant,
++ GIOPRecvBuffer * _ORBIT_recv_buffer,
++ CORBA_Environment * ev,
++ Echo(*_impl_echoString)
++ (PortableServer_Servant _servant,
++ const CORBA_char * astring,
++ CORBA_long * anum,
++ CORBA_Environment * ev));
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif
++#undef ORBIT_IDL_SERIAL
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/FileServer/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Entries Thu Feb 1 11:47:07 2001
+@@ -0,0 +1,4 @@
++/FileServer.idl/1.3/Thu Feb 1 09:47:07 2001//
++/Makefile/1.2/Thu Feb 1 09:47:07 2001//
++/README/1.1/Thu Feb 1 09:47:07 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Entries.Log
+--- linux-2.4.1/net/korbit/modules/FileServer/CVS/Entries.Log Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Entries.Log Thu Feb 1 11:47:09 2001
+@@ -0,0 +1,4 @@
++A D/client////
++A D/server////
++A D/server-user////
++A D/wrapper////
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/FileServer/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Repository Thu Feb 1 11:47:07 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/FileServer
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/CVS/Root linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Root
+--- linux-2.4.1/net/korbit/modules/FileServer/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Root Thu Feb 1 11:47:07 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/FileServer.idl linux-2.4.1-korbit/net/korbit/modules/FileServer/FileServer.idl
+--- linux-2.4.1/net/korbit/modules/FileServer/FileServer.idl Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/FileServer.idl Thu Feb 1 11:47:07 2001
+@@ -0,0 +1,158 @@
++// -----------------------------------------------------------------------------
++// FileServer.idl
++// -----------------------------------------------------------------------------
++//
++// This file is used to define the Kernel CORBA API for accessing the filesystem
++// on a machine. This defines mappings both to access the files in the kernel
++// and to implement a filesystem for the kernel. This should probably be split
++// into two files eventually.
++//
++// Currently unimplemented: KernelAccessAPI::FileSystem::ReadDirectory
++// KernelAccessAPI::FileSystem::Select
++// KernelImplementationAPI::SuperBlock::getDiskQuotaOps
++//
++// -----------------------------------------------------------------------------
++
++
++// These are the exceptions that may be thrown and what they map to in the
++// Linux kernel. This interface is extended by other interfaces so that the
++// names don't have to be typedef'd into each interface that wants to use these
++// errors.
++//
++interface Errors {
++ exception IsDirectory {}; // EISDIR
++ exception PermissionDenied {}; // EACCES
++ exception FileExists {}; // EEXIST
++ exception FileNotFound {}; // ENOENT
++ exception IsNotDirectory {}; // ENOTDIR
++ exception ReadOnlyFile {}; // EROFS, ETXTBSY
++ exception RecursiveSymlink {}; // ELOOP
++ exception IsBusy {}; // EBUSY
++ exception OtherError{}; // Misc other ones...
++};
++
++
++// -----------------------------------------------------------------------------
++// KernelAccessAPI Module - Allow user level programs to call into the kernel
++// -----------------------------------------------------------------------------
++
++module FileServer {
++ struct FileStatus { // Corba equilivant of struct stat
++ long DeviceNum; // st_dev
++ long InodeNum; // st_ino
++ short Mode; // st_mode
++ short NumLinks; // st_nlink
++ long UserID; // st_uid
++ long GroupID; // st_gid
++ long DeviceType; // st_rdev
++ unsigned long Size; // st_size
++ unsigned long BlockSize; // st_blksize
++ unsigned long NumBlocks; // st_blocks;
++ unsigned long AccessTime; // st_blocks;
++ unsigned long ModifiedTime; // st_blocks;
++ unsigned long ChangeTime; // st_blocks;
++ };
++
++ typedef sequence<octet> buffer;
++
++ // ---------------------------------------------------------------------------
++ // FileSystem Interface - Access to filesystem and File object factory
++ // ---------------------------------------------------------------------------
++
++ interface File : Errors {
++ void Read(in long count, out buffer buf)
++ raises (IsDirectory, OtherError);
++ void Write(in buffer buf)
++ raises (OtherError);
++ void Close();
++
++ long FileControl(in long command) raises (OtherError);
++
++ FileStatus GetStatus() raises (OtherError);
++
++ void ChangeDirectoryTo() // This implements fchdir...
++ raises (IsNotDirectory, PermissionDenied, OtherError);
++
++ enum SeekDirection { FromStart, FromCurrent, FromEnd };
++ long Seek(in long Offset, in SeekDirection Direction) raises (OtherError);
++
++ File Duplicate() raises (OtherError);
++ };
++
++
++
++ // ---------------------------------------------------------------------------
++ // FileSystem Interface - Access to filesystem and File object factory
++ // ---------------------------------------------------------------------------
++
++ interface FileSystem : Errors {
++
++ // -------------------------------------------------------------------------
++ // File Manipulation Routines
++ // -------------------------------------------------------------------------
++
++ File Open(in string Filename, in long openFlags, in short mode)
++ raises (FileExists, IsDirectory, PermissionDenied, FileNotFound,
++ IsNotDirectory, ReadOnlyFile, RecursiveSymlink, OtherError);
++
++ File Create(in string Filename, in short mode)
++ raises (FileExists, IsDirectory, PermissionDenied, FileNotFound,
++ IsNotDirectory, ReadOnlyFile, RecursiveSymlink, OtherError);
++
++ void Link(in string FromPath, in string ToPath)
++ raises (PermissionDenied, IsNotDirectory, RecursiveSymlink, FileExists);
++
++ void Unlink(in string Filename)
++ raises (PermissionDenied, FileNotFound, IsNotDirectory, IsDirectory);
++
++ void Rename(in string OldName, in string NewName)
++ raises (IsDirectory, FileExists, IsBusy, IsNotDirectory, PermissionDenied,
++ RecursiveSymlink);
++
++ void ReadLink(in string Linkname, out string LinkValue)
++ raises (FileNotFound, PermissionDenied, RecursiveSymlink, OtherError);
++
++
++ FileStatus GetStatus(in string Filename)
++ raises (FileNotFound, PermissionDenied, RecursiveSymlink, IsNotDirectory,
++ OtherError);
++
++ FileStatus GetLinkStatus(in string Filename)
++ raises (FileNotFound, PermissionDenied, RecursiveSymlink, IsNotDirectory,
++ OtherError);
++
++
++ // -------------------------------------------------------------------------
++ // Directory Manipulation Routines
++ // -------------------------------------------------------------------------
++
++ void MakeDirectory(in string PathName, in short mode)
++ raises (FileExists, PermissionDenied, FileNotFound, IsNotDirectory,
++ ReadOnlyFile, RecursiveSymlink, OtherError);
++
++ void RemoveDirectory(in string PathName)
++ raises (PermissionDenied, FileNotFound, IsNotDirectory);
++
++ // ChangeDirectory returns CWD so that you can implement getcwd as
++ // { return ChangeDirectory("."); }
++ string ChangeDirectory(in string PathName)
++ raises (IsNotDirectory, PermissionDenied, FileNotFound, RecursiveSymlink);
++
++
++ // -------------------------------------------------------------------------
++ // Special Purpose Routines...
++ // -------------------------------------------------------------------------
++
++ void MakeNode(in string FileName, in short Mode, in long DeviceNum)
++ raises (PermissionDenied, FileExists, FileNotFound, IsNotDirectory,
++ RecursiveSymlink);
++
++ void Mount(in string DeviceFile, in string Location, in string FSType,
++ in long Flags)
++ raises (PermissionDenied, FileNotFound, IsBusy, IsNotDirectory);
++
++ void Unmount(in string Filename)
++ raises (PermissionDenied, FileNotFound, IsBusy);
++ };
++
++};
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/Makefile linux-2.4.1-korbit/net/korbit/modules/FileServer/Makefile
+--- linux-2.4.1/net/korbit/modules/FileServer/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/Makefile Thu Feb 1 11:47:07 2001
+@@ -0,0 +1,11 @@
++#
++# Makefile for KORBit/modules/CorbaFS
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++
++subdir-$(CONFIG_CORBA_FILESERVER) := server
++
++include $(TOPDIR)/Rules.make
++
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/README linux-2.4.1-korbit/net/korbit/modules/FileServer/README
+--- linux-2.4.1/net/korbit/modules/FileServer/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/README Thu Feb 1 11:47:07 2001
+@@ -0,0 +1,8 @@
++This interface lets you export file related syscalls through CORBA. This is
++genuinely useful, however, when you use the 'wrapper' library, that can be
++LD_PRELOADED before you run your application. This allows you to forward
++filesystem calls through CORBA without having to modify your application.
++
++Being able to forward filesystem calls though CORBA, of course, means that
++you can attach to any remote machine you want. :)
++
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/client/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/FileServer/client/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/FileServer/client/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/client/CVS/Entries Thu Feb 1 11:47:07 2001
+@@ -0,0 +1,4 @@
++/FileServer-client.cpp/1.1/Thu Feb 1 09:47:07 2001//
++/Makefile/1.1/Thu Feb 1 09:47:07 2001//
++/README/1.1/Thu Feb 1 09:47:07 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/client/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/FileServer/client/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/FileServer/client/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/client/CVS/Repository Thu Feb 1 11:47:07 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/FileServer/client
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/client/CVS/Root linux-2.4.1-korbit/net/korbit/modules/FileServer/client/CVS/Root
+--- linux-2.4.1/net/korbit/modules/FileServer/client/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/client/CVS/Root Thu Feb 1 11:47:07 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/client/FileServer-client.cpp linux-2.4.1-korbit/net/korbit/modules/FileServer/client/FileServer-client.cpp
+--- linux-2.4.1/net/korbit/modules/FileServer/client/FileServer-client.cpp Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/client/FileServer-client.cpp Thu Feb 1 11:47:07 2001
+@@ -0,0 +1,78 @@
++#include <OB/CORBA.h>
++#include <OB/Util.h>
++#include <OB/CosNaming.h>
++#include <stdlib.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++
++#include "FileServer.h"
++
++int main(int argc, char* argv[])
++{
++ if (argc < 3)
++ {
++ cout << "Usage : " << argv[0] << " ior filename" << endl;
++ exit(1);
++ }
++
++ cout << "FileServer client initializing" << endl;
++
++ CORBA_ORB_var orb = CORBA_ORB_init(argc, argv);
++ cout << "ORB initialized" << endl;
++
++ try
++ {
++ CORBA_Object_var obj = orb->string_to_object( argv[1] );
++ assert(!CORBA_is_nil(obj));
++ cout << "got object... " << orb->object_to_string(obj) << endl;
++
++ FileServer_FileSystem_var fs = FileServer_FileSystem::_narrow(obj);
++ assert(!CORBA_is_nil(fs));
++ cout << "it's a FileServer!" << endl;
++
++ obj = fs->Open(argv[2], O_RDONLY, 0);
++ assert(!CORBA_is_nil(obj));
++ cout << "got object... " << orb->object_to_string(obj) << endl;
++
++ FileServer_File_var file = FileServer_File::_narrow(obj);
++ assert(!CORBA_is_nil(file));
++ cout << "it's a FileServer_File!" << endl;
++
++ FileServer_buffer *buf = new FileServer_buffer;
++ cout << "reading 1000 bytes" << endl;
++ file->Read(1000, buf);
++
++ cout << "got " << buf->length() << " bytes" << endl;
++ cout << buf->data() << endl;
++
++ file->Close();
++
++ delete buf;
++ }
++ catch (const CORBA_SystemException& ex) {
++ OBPrintException(ex);
++ return 1;
++ }
++ catch (const Errors::FileNotFound& ex) {
++ cout << "ERROR : File not found" << endl;
++ return 1;
++ }
++ catch (const Errors::PermissionDenied& ex) {
++ cout << "ERROR : Permission denied" << endl;
++ return 1;
++ }
++ catch (const Errors::IsDirectory& ex) {
++ cout << "ERROR : Is directory" << endl;
++ return 1;
++ }
++ catch (const Errors::OtherError& ex) {
++ cout << "ERROR : Other error" << endl;
++ return 1;
++ }
++ catch (const CORBA_UserException& ex)
++ {
++ cout << "ERROR : Uncaught exception" << endl;
++ return 1;
++ }
++}
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/client/Makefile linux-2.4.1-korbit/net/korbit/modules/FileServer/client/Makefile
+--- linux-2.4.1/net/korbit/modules/FileServer/client/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/client/Makefile Thu Feb 1 11:47:07 2001
+@@ -0,0 +1,32 @@
++CC = CC -mt -pta
++OBDIR = /home/class/cs423/local
++IDL = $(OBDIR)/bin/idl
++CPPFLAGS = -I. -I$(OBDIR)/include
++LDFLAGS = -L$(OBDIR)/lib
++LIBS = -lCosNaming -lOB -lJTC -lsocket -lnsl -lposix4
++
++all: FileServer-client
++
++FileServer-client: FileServer.o FileServer-client.o
++ $(CC) $(LDFLAGS) -o FileServer-client FileServer-client.o FileServer.o $(LIBS)
++
++nameserv:
++ nameserv -i -OAport 10000
++
++FileServer.h FileServer.cpp: ../FileServer.idl
++ rm -f FileServer.cpp FileServer.h
++ rm -f FileServer_skel.h FileServer_skel.cpp
++ $(IDL) ../FileServer.idl
++
++FileServer_skel.cpp FileServer_skel.h: FileServer.cpp
++
++%.o: %.cpp
++ $(CC) $(CPPFLAGS) -c $<
++
++clean:
++ rm -f FileServer-client *.o *~
++
++realclean: clean
++ rm -f FileServer.h FileServer.cpp
++ rm -f FileServer_skel.h FileServer_skel.cpp
++ rm -rf SunWS_cache
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/client/README linux-2.4.1-korbit/net/korbit/modules/FileServer/client/README
+--- linux-2.4.1/net/korbit/modules/FileServer/client/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/client/README Thu Feb 1 11:47:07 2001
+@@ -0,0 +1,4 @@
++Very minimal test of the FileServer capability.
++
++ORB: Orbacus
++
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/FileServer/server/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/FileServer/server/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/CVS/Entries Thu Feb 1 11:47:08 2001
+@@ -0,0 +1,6 @@
++/FileServer-server.c/1.2/Thu Feb 1 09:47:08 2001//
++/FileServer-skelimpl.c/1.8/Thu Feb 1 09:47:08 2001//
++/Makefile/1.3/Thu Feb 1 09:47:08 2001//
++/Makefile.user/1.4/Thu Feb 1 09:47:08 2001//
++/README/1.1/Thu Feb 1 09:47:08 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/FileServer/server/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/FileServer/server/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/CVS/Repository Thu Feb 1 11:47:08 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/FileServer/server
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/CVS/Root linux-2.4.1-korbit/net/korbit/modules/FileServer/server/CVS/Root
+--- linux-2.4.1/net/korbit/modules/FileServer/server/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/CVS/Root Thu Feb 1 11:47:08 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/FileServer-server.c linux-2.4.1-korbit/net/korbit/modules/FileServer/server/FileServer-server.c
+--- linux-2.4.1/net/korbit/modules/FileServer/server/FileServer-server.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/FileServer-server.c Thu Feb 1 11:47:08 2001
+@@ -0,0 +1,57 @@
++#include <stdio.h>
++#include "FileServer-skelimpl.c"
++#include "korbit.h"
++
++CORBA_ORB orb;
++PortableServer_POA poa;
++CORBA_Environment *ev;
++PortableServer_ObjectId *objid;
++
++#ifdef __KERNEL__
++int __init FileServer_init(void) {
++#else
++int main(int argc, char *argv[]) {
++#endif
++ FileServer_FileSystem fs;
++ impl_POA_FileServer_FileSystem *fs_impl;
++
++ PortableServer_POAManager pm;
++#ifdef __KERNEL__
++ int argc = 1;
++ char *argv[] = { "server", 0 };
++#endif
++ ev = g_new0(CORBA_Environment,1);
++
++ CORBA_exception_init(ev);
++
++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev);
++ poa = (PortableServer_POA)
++ CORBA_ORB_resolve_initial_references(orb,
++ "RootPOA",
++ ev);
++ fs = impl_FileServer_FileSystem__create(poa, ev);
++
++ pm = PortableServer_POA__get_the_POAManager(poa, ev);
++ PortableServer_POAManager_activate(pm, ev);
++
++ fs_impl = PortableServer_POA_reference_to_servant( poa, fs, ev );
++ objid = PortableServer_POA_servant_to_id( poa, fs_impl, ev );
++
++ korbit_register_ior("FileServer-server", fs, orb, ev);
++
++ CORBA_ORB_run(orb, ev);
++
++ return 0;
++}
++
++#ifdef __KERNEL__
++void FileServer_exit(void)
++{
++ PortableServer_POA_deactivate_object(poa, objid, ev);
++ remove_proc_entry("corba/FileServer-server", 0);
++ printf("FileServer_exit()\n");
++}
++
++module_init(FileServer_init)
++module_exit(FileServer_exit)
++#endif
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/FileServer-skelimpl.c linux-2.4.1-korbit/net/korbit/modules/FileServer/server/FileServer-skelimpl.c
+--- linux-2.4.1/net/korbit/modules/FileServer/server/FileServer-skelimpl.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/FileServer-skelimpl.c Thu Feb 1 11:47:08 2001
+@@ -0,0 +1,804 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <errno.h>
++
++#include "FileServer.h"
++
++static void set_exception(int errno, CORBA_Environment *ev)
++{
++ switch (errno)
++ {
++ case ENOENT:
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_Errors_FileNotFound,
++ Errors_FileNotFound__alloc());
++ break;
++ case EEXIST:
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_Errors_FileExists,
++ Errors_FileExists__alloc());
++ break;
++ case EACCES:
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_Errors_PermissionDenied,
++ Errors_PermissionDenied__alloc());
++ break;
++ case EISDIR:
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_Errors_IsDirectory,
++ Errors_IsDirectory__alloc());
++ break;
++ case ENOTDIR:
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_Errors_IsNotDirectory,
++ Errors_IsNotDirectory__alloc());
++ break;
++ case EROFS:
++ case ETXTBSY:
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_Errors_ReadOnlyFile,
++ Errors_ReadOnlyFile__alloc());
++ break;
++ case ELOOP:
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_Errors_RecursiveSymlink,
++ Errors_RecursiveSymlink__alloc());
++ break;
++ case EBUSY:
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_Errors_IsBusy,
++ Errors_IsBusy__alloc());
++ break;
++ default:
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_Errors_OtherError,
++ Errors_OtherError__alloc());
++ break;
++ }
++}
++
++
++/*** App-specific servant structures ***/
++typedef struct
++{
++ POA_Errors servant;
++ PortableServer_POA poa;
++
++}
++impl_POA_Errors;
++
++typedef struct
++{
++ POA_FileServer_File servant;
++ PortableServer_POA poa;
++
++ int fd;
++}
++impl_POA_FileServer_File;
++
++typedef struct
++{
++ POA_FileServer_FileSystem servant;
++ PortableServer_POA poa;
++
++}
++impl_POA_FileServer_FileSystem;
++
++/*** Implementation stub prototypes ***/
++static void impl_Errors__destroy(impl_POA_Errors * servant,
++ CORBA_Environment * ev);
++
++static void impl_FileServer_File__destroy(impl_POA_FileServer_File * servant,
++ CORBA_Environment * ev);
++static void
++impl_FileServer_File_Read(impl_POA_FileServer_File * servant,
++ CORBA_long count,
++ FileServer_buffer ** buf, CORBA_Environment * ev);
++
++static void
++impl_FileServer_File_Write(impl_POA_FileServer_File * servant,
++ FileServer_buffer * buf, CORBA_Environment * ev);
++
++static void
++impl_FileServer_File_Close(impl_POA_FileServer_File * servant,
++ CORBA_Environment * ev);
++
++static CORBA_long
++impl_FileServer_File_FileControl(impl_POA_FileServer_File * servant,
++ CORBA_long command, CORBA_Environment * ev);
++
++static FileServer_FileStatus
++impl_FileServer_File_GetStatus(impl_POA_FileServer_File * servant,
++ CORBA_Environment * ev);
++
++static void
++impl_FileServer_File_ChangeDirectoryTo(impl_POA_FileServer_File * servant,
++ CORBA_Environment * ev);
++
++static CORBA_long
++impl_FileServer_File_Seek(impl_POA_FileServer_File * servant,
++ CORBA_long Offset,
++ FileServer_File_SeekDirection Direction,
++ CORBA_Environment * ev);
++
++static FileServer_File
++impl_FileServer_File_Duplicate(impl_POA_FileServer_File * servant,
++ CORBA_Environment * ev);
++
++static void impl_FileServer_FileSystem__destroy(impl_POA_FileServer_FileSystem
++ * servant,
++
++ CORBA_Environment * ev);
++static FileServer_File
++impl_FileServer_FileSystem_Open(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Filename, CORBA_long openFlags,
++ CORBA_short mode, CORBA_Environment * ev);
++
++static FileServer_File
++impl_FileServer_FileSystem_Create(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Filename,
++ CORBA_short mode, CORBA_Environment * ev);
++
++static void
++impl_FileServer_FileSystem_Link(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * FromPath,
++ CORBA_char * ToPath, CORBA_Environment * ev);
++
++static void
++impl_FileServer_FileSystem_Unlink(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Filename,
++
++ CORBA_Environment * ev);
++
++static void
++impl_FileServer_FileSystem_Rename(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * OldName,
++ CORBA_char * NewName,
++
++ CORBA_Environment * ev);
++
++static void
++impl_FileServer_FileSystem_ReadLink(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Linkname,
++ CORBA_char ** LinkValue,
++ CORBA_Environment * ev);
++
++static FileServer_FileStatus
++impl_FileServer_FileSystem_GetStatus(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Filename,
++ CORBA_Environment * ev);
++
++static FileServer_FileStatus
++impl_FileServer_FileSystem_GetLinkStatus(impl_POA_FileServer_FileSystem *
++ servant, CORBA_char * Filename,
++ CORBA_Environment * ev);
++
++static void
++impl_FileServer_FileSystem_MakeDirectory(impl_POA_FileServer_FileSystem *
++ servant, CORBA_char * PathName,
++ CORBA_short mode,
++ CORBA_Environment * ev);
++
++static void
++impl_FileServer_FileSystem_RemoveDirectory(impl_POA_FileServer_FileSystem *
++ servant, CORBA_char * PathName,
++ CORBA_Environment * ev);
++
++static CORBA_char
++ *impl_FileServer_FileSystem_ChangeDirectory(impl_POA_FileServer_FileSystem
++ * servant,
++ CORBA_char * PathName,
++ CORBA_Environment * ev);
++
++static void
++impl_FileServer_FileSystem_MakeNode(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * FileName,
++ CORBA_short Mode,
++ CORBA_long DeviceNum,
++
++ CORBA_Environment * ev);
++
++static void
++impl_FileServer_FileSystem_Mount(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * DeviceFile,
++ CORBA_char * Location,
++ CORBA_char * FSType,
++ CORBA_long Flags, CORBA_Environment * ev);
++
++static void
++impl_FileServer_FileSystem_Unmount(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Filename,
++
++ CORBA_Environment * ev);
++
++/*** epv structures ***/
++static PortableServer_ServantBase__epv impl_Errors_base_epv = {
++ NULL, /* _private data */
++ NULL, /* finalize routine */
++ NULL, /* default_POA routine */
++};
++static POA_Errors__epv impl_Errors_epv = {
++ NULL, /* _private */
++
++};
++
++static PortableServer_ServantBase__epv impl_FileServer_File_base_epv = {
++ NULL, /* _private data */
++ NULL, /* finalize routine */
++ NULL, /* default_POA routine */
++};
++static POA_FileServer_File__epv impl_FileServer_File_epv = {
++ NULL, /* _private */
++ (gpointer) & impl_FileServer_File_Read,
++
++ (gpointer) & impl_FileServer_File_Write,
++
++ (gpointer) & impl_FileServer_File_Close,
++
++ (gpointer) & impl_FileServer_File_FileControl,
++
++ (gpointer) & impl_FileServer_File_GetStatus,
++
++ (gpointer) & impl_FileServer_File_ChangeDirectoryTo,
++
++ (gpointer) & impl_FileServer_File_Seek,
++
++ (gpointer) & impl_FileServer_File_Duplicate,
++
++};
++static POA_Errors__epv impl_FileServer_File_Errors_epv = {
++ NULL, /* _private */
++};
++static PortableServer_ServantBase__epv impl_FileServer_FileSystem_base_epv = {
++ NULL, /* _private data */
++ NULL, /* finalize routine */
++ NULL, /* default_POA routine */
++};
++static POA_FileServer_FileSystem__epv impl_FileServer_FileSystem_epv = {
++ NULL, /* _private */
++ (gpointer) & impl_FileServer_FileSystem_Open,
++
++ (gpointer) & impl_FileServer_FileSystem_Create,
++
++ (gpointer) & impl_FileServer_FileSystem_Link,
++
++ (gpointer) & impl_FileServer_FileSystem_Unlink,
++
++ (gpointer) & impl_FileServer_FileSystem_Rename,
++
++ (gpointer) & impl_FileServer_FileSystem_ReadLink,
++
++ (gpointer) & impl_FileServer_FileSystem_GetStatus,
++
++ (gpointer) & impl_FileServer_FileSystem_GetLinkStatus,
++
++ (gpointer) & impl_FileServer_FileSystem_MakeDirectory,
++
++ (gpointer) & impl_FileServer_FileSystem_RemoveDirectory,
++
++ (gpointer) & impl_FileServer_FileSystem_ChangeDirectory,
++
++ (gpointer) & impl_FileServer_FileSystem_MakeNode,
++
++ (gpointer) & impl_FileServer_FileSystem_Mount,
++
++ (gpointer) & impl_FileServer_FileSystem_Unmount,
++
++};
++static POA_Errors__epv impl_FileServer_FileSystem_Errors_epv = {
++ NULL, /* _private */
++};
++
++/*** vepv structures ***/
++static POA_Errors__vepv impl_Errors_vepv = {
++ &impl_Errors_base_epv,
++ &impl_Errors_epv,
++};
++
++static POA_FileServer_File__vepv impl_FileServer_File_vepv = {
++ &impl_FileServer_File_base_epv,
++ &impl_FileServer_File_Errors_epv,
++ &impl_FileServer_File_epv,
++};
++static POA_FileServer_FileSystem__vepv impl_FileServer_FileSystem_vepv = {
++ &impl_FileServer_FileSystem_base_epv,
++ &impl_FileServer_FileSystem_Errors_epv,
++ &impl_FileServer_FileSystem_epv,
++};
++
++/*** Stub implementations ***/
++static Errors
++impl_Errors__create(PortableServer_POA poa, CORBA_Environment * ev)
++{
++ Errors retval;
++ impl_POA_Errors *newservant;
++ PortableServer_ObjectId *objid;
++
++ newservant = g_new0(impl_POA_Errors, 1);
++ newservant->servant.vepv = &impl_Errors_vepv;
++ newservant->poa = poa;
++ POA_Errors__init((PortableServer_Servant) newservant, ev);
++ objid = PortableServer_POA_activate_object(poa, newservant, ev);
++ CORBA_free(objid);
++ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev);
++
++ return retval;
++}
++
++static void
++impl_Errors__destroy(impl_POA_Errors * servant, CORBA_Environment * ev)
++{
++ PortableServer_ObjectId *objid;
++
++ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev);
++ PortableServer_POA_deactivate_object(servant->poa, objid, ev);
++ CORBA_free(objid);
++
++ POA_Errors__fini((PortableServer_Servant) servant, ev);
++ g_free(servant);
++}
++
++static FileServer_File
++impl_FileServer_File__create(PortableServer_POA poa, CORBA_Environment * ev)
++{
++ FileServer_File retval;
++ impl_POA_FileServer_File *newservant;
++ PortableServer_ObjectId *objid;
++
++ newservant = g_new0(impl_POA_FileServer_File, 1);
++ newservant->servant.vepv = &impl_FileServer_File_vepv;
++ newservant->poa = poa;
++ newservant->fd = -1;
++
++ POA_FileServer_File__init((PortableServer_Servant) newservant, ev);
++ objid = PortableServer_POA_activate_object(poa, newservant, ev);
++ CORBA_free(objid);
++ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev);
++
++ return retval;
++}
++
++static void
++impl_FileServer_File__destroy(impl_POA_FileServer_File * servant,
++ CORBA_Environment * ev)
++{
++ PortableServer_ObjectId *objid;
++
++ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev);
++ PortableServer_POA_deactivate_object(servant->poa, objid, ev);
++ CORBA_free(objid);
++
++ POA_FileServer_File__fini((PortableServer_Servant) servant, ev);
++ g_free(servant);
++}
++
++static void
++impl_FileServer_File_Read(impl_POA_FileServer_File * servant,
++ CORBA_long count,
++ FileServer_buffer ** buf, CORBA_Environment * ev)
++{
++ size_t num_read;
++
++ *buf = FileServer_buffer__alloc();
++ (*buf)->_maximum = count;
++ (*buf)->_buffer = CORBA_octet_allocbuf(count);
++ (*buf)->_length = 0;
++
++ printf("File->Read(%d, char *buf)\n", count);
++
++ if (servant->fd == -1) /* Trying to read from a closed file */
++ {
++ printf("File->Read ERROR : fd == -1\n");
++ set_exception(EBADF, ev);
++ return;
++ }
++
++ num_read = read(servant->fd, (*buf)->_buffer, count);
++ if (num_read == -1)
++ {
++ printf("File->Read ERROR : %d\n", errno);
++ set_exception(errno, ev);
++ return;
++ }
++
++ (*buf)->_length = num_read;
++}
++
++static void
++impl_FileServer_File_Write(impl_POA_FileServer_File * servant,
++ FileServer_buffer * buf, CORBA_Environment * ev)
++{
++ printf("UNIMP: FileServer::File::Write called and unimplemented\n");
++}
++
++static void
++impl_FileServer_File_Close(impl_POA_FileServer_File * servant,
++ CORBA_Environment * ev)
++{
++ printf("File->Close()\n");
++
++ if (servant->fd == -1) /* This should never happen !?! */
++ {
++ printf("File->Close ERROR : fd == -1\n");
++ set_exception(EBADF, ev);
++ return;
++ }
++
++ close(servant->fd);
++ servant->fd = 0;
++ impl_FileServer_File__destroy(servant, ev);
++}
++
++static CORBA_long
++impl_FileServer_File_FileControl(impl_POA_FileServer_File * servant,
++ CORBA_long command, CORBA_Environment * ev)
++{
++ CORBA_long retval;
++
++ if (servant->fd == -1)
++ {
++ printf("File->FileControl ERROR : fd == -1\n");
++ set_exception(EBADF, ev);
++ return -1;
++ }
++
++ retval = fcntl(servant->fd, command, 0); /* FIXME arg? */
++ if (retval == -1)
++ {
++ printf("File->FileControl ERROR : %d\n", errno);
++ set_exception(errno, ev);
++ }
++
++ return retval;
++}
++
++
++FileServer_FileStatus
++stat2FileStatus(struct stat buf)
++{
++ FileServer_FileStatus retval;
++
++ retval.DeviceNum = buf.st_dev;
++ retval.InodeNum = buf.st_ino;
++ retval.Mode = buf.st_mode;
++ retval.NumLinks = buf.st_nlink;
++ retval.UserID = buf.st_uid;
++ retval.GroupID = buf.st_gid;
++ retval.DeviceType = buf.st_rdev;
++ retval.Size = buf.st_size;
++ retval.BlockSize = buf.st_blksize;
++ retval.NumBlocks = buf.st_blocks;
++ retval.AccessTime = buf.st_atime;
++ retval.ModifiedTime = buf.st_mtime;
++ retval.ChangeTime = buf.st_ctime;
++
++ return retval;
++}
++
++
++static FileServer_FileStatus
++impl_FileServer_File_GetStatus(impl_POA_FileServer_File * servant,
++ CORBA_Environment * ev)
++{
++ FileServer_FileStatus retval;
++
++ struct stat buf;
++ int res;
++
++ if (servant->fd == -1)
++ {
++ printf("File->GetStatus ERROR : fd == -1\n");
++ set_exception(EBADF, ev);
++ return retval;
++ }
++
++ res = fstat(servant->fd, &buf);
++ if (res == -1)
++ {
++ printf("File->GetStatus ERROR : %d\n", errno);
++ set_exception(errno, ev);
++ return retval;
++ }
++
++ retval = stat2FileStatus(buf);
++
++ return retval;
++}
++
++static void
++impl_FileServer_File_ChangeDirectoryTo(impl_POA_FileServer_File * servant,
++ CORBA_Environment * ev)
++{
++ printf("UNIMP: impl_FileServer_File_ChangeDirectoryTo\n");
++}
++
++static CORBA_long
++impl_FileServer_File_Seek(impl_POA_FileServer_File * servant,
++ CORBA_long Offset,
++ FileServer_File_SeekDirection Direction,
++ CORBA_Environment * ev)
++{
++ CORBA_long retval = -1;
++ int whence;
++
++ if (servant->fd == -1)
++ {
++ printf("File->Seek ERROR : fd == -1\n");
++ set_exception(EBADF, ev);
++ return retval;
++ }
++
++ switch (Direction)
++ {
++ case FileServer_File_FromStart :
++ whence = SEEK_SET;
++ break;
++ case FileServer_File_FromCurrent :
++ whence = SEEK_CUR;
++ break;
++ case FileServer_File_FromEnd :
++ whence = SEEK_END;
++ break;
++ default :
++ set_exception(EINVAL, ev);
++ return retval;
++ }
++
++ retval = lseek(servant->fd, Offset, whence);
++ if (retval == -1)
++ {
++ printf("File->Seek ERROR : %d\n", errno);
++ set_exception(errno, ev);
++ }
++
++ return retval;
++}
++
++static FileServer_File
++impl_FileServer_File_Duplicate(impl_POA_FileServer_File * servant,
++ CORBA_Environment * ev)
++{
++ FileServer_File retval;
++ printf("UNIMP: impl_FileServer_File_Duplicate\n");
++ return retval;
++}
++
++static FileServer_FileSystem
++impl_FileServer_FileSystem__create(PortableServer_POA poa,
++ CORBA_Environment * ev)
++{
++ FileServer_FileSystem retval;
++ impl_POA_FileServer_FileSystem *newservant;
++ PortableServer_ObjectId *objid;
++
++ newservant = g_new0(impl_POA_FileServer_FileSystem, 1);
++ newservant->servant.vepv = &impl_FileServer_FileSystem_vepv;
++ newservant->poa = poa;
++ POA_FileServer_FileSystem__init((PortableServer_Servant) newservant, ev);
++ objid = PortableServer_POA_activate_object(poa, newservant, ev);
++ CORBA_free(objid);
++ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev);
++
++ return retval;
++}
++
++static void
++impl_FileServer_FileSystem__destroy(impl_POA_FileServer_FileSystem * servant,
++ CORBA_Environment * ev)
++{
++ PortableServer_ObjectId *objid;
++
++ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev);
++ PortableServer_POA_deactivate_object(servant->poa, objid, ev);
++ CORBA_free(objid);
++
++ POA_FileServer_FileSystem__fini((PortableServer_Servant) servant, ev);
++ g_free(servant);
++}
++
++static FileServer_File
++impl_FileServer_FileSystem_Open(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Filename,
++ CORBA_long openFlags,
++ CORBA_short mode, CORBA_Environment * ev)
++{
++ FileServer_File retval = CORBA_OBJECT_NIL;
++
++ impl_POA_FileServer_File *file;
++
++ printf("FileSystem->Open(%s,%x)\n", Filename, openFlags);
++
++ retval = impl_FileServer_File__create(servant->poa, ev);
++
++ file = PortableServer_POA_reference_to_servant( servant->poa, retval, ev );
++ file->fd = open(Filename, openFlags, mode);
++
++ if (file->fd == -1) {
++ printf("FileSystem->Open ERROR : %d\n", errno);
++ set_exception(errno, ev);
++ }
++
++ return retval;
++}
++
++static FileServer_File
++impl_FileServer_FileSystem_Create(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Filename,
++ CORBA_short mode, CORBA_Environment * ev)
++{
++ FileServer_File retval = CORBA_OBJECT_NIL;
++
++ impl_POA_FileServer_File *file;
++
++ printf("FileSystem->Create(%s,%x)\n", Filename, mode);
++
++ retval = impl_FileServer_File__create(servant->poa, ev);
++
++ file = PortableServer_POA_reference_to_servant( servant->poa, retval, ev );
++ file->fd = creat(Filename, mode);
++
++ if (file->fd == -1) {
++ printf("FileSystem->Create ERROR : %d\n", errno);
++ set_exception(errno, ev);
++ }
++
++ return retval;
++}
++
++static void
++impl_FileServer_FileSystem_Link(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * FromPath,
++ CORBA_char * ToPath, CORBA_Environment * ev)
++{
++ printf("UNIMP: impl_FileServer_FileSystem_Link\n");
++}
++
++static void
++impl_FileServer_FileSystem_Unlink(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Filename,
++ CORBA_Environment * ev)
++{
++ printf("UNIMP: impl_FileServer_FileSystem_Unlink\n");
++}
++
++static void
++impl_FileServer_FileSystem_Rename(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * OldName,
++ CORBA_char * NewName,
++ CORBA_Environment * ev)
++{
++ printf("UNIMP: impl_FileServer_FileSystem_Rename\n");
++}
++
++static void
++impl_FileServer_FileSystem_ReadLink(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Linkname,
++ CORBA_char ** LinkValue,
++ CORBA_Environment * ev)
++{
++ char tmp[PATH_MAX + 1];
++ int res, len;
++
++ printf("FileSystem->ReadLink(%s, value)\n", Linkname);
++
++ res = readlink(Linkname, tmp, PATH_MAX);
++ if (res == -1)
++ {
++ set_exception(errno, ev);
++ return;
++ }
++
++ len = strlen(tmp);
++ *LinkValue = (char *)malloc(len * sizeof(char));
++ memcpy(*LinkValue, tmp, len);
++ (*LinkValue)[len] = '\0';
++}
++
++static FileServer_FileStatus
++impl_FileServer_FileSystem_GetStatus(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Filename,
++ CORBA_Environment * ev)
++{
++ FileServer_FileStatus retval;
++ struct stat buf;
++ int res;
++
++ printf("FileSystem->GetStatus(%s)\n", Filename);
++
++ res = stat(Filename, &buf);
++
++ if (res == -1)
++ {
++ printf("FileSystem->GetStatus(%s)\n", Filename);
++ set_exception(errno, ev);
++ return retval;
++ }
++
++ retval = stat2FileStatus(buf);
++
++ return retval;
++}
++
++static FileServer_FileStatus
++impl_FileServer_FileSystem_GetLinkStatus(impl_POA_FileServer_FileSystem *
++ servant, CORBA_char * Filename,
++ CORBA_Environment * ev)
++{
++ FileServer_FileStatus retval;
++ struct stat buf;
++ int res;
++
++ printf("FileSystem->GetLinkStatus(%s)\n", Filename);
++
++ res = lstat(Filename, &buf);
++
++ if (res == -1)
++ {
++ printf("FileSystem->GetLinkStatus(%s)\n", Filename);
++ set_exception(errno, ev);
++ return retval;
++ }
++
++ retval = stat2FileStatus(buf);
++
++ return retval;
++}
++
++static void
++impl_FileServer_FileSystem_MakeDirectory(impl_POA_FileServer_FileSystem *
++ servant, CORBA_char * PathName,
++ CORBA_short mode,
++ CORBA_Environment * ev)
++{
++ printf("UNIMP: impl_FileServer_FileSystem_MakeDirectory\n");
++}
++
++static void
++impl_FileServer_FileSystem_RemoveDirectory(impl_POA_FileServer_FileSystem *
++ servant, CORBA_char * PathName,
++ CORBA_Environment * ev)
++{
++ printf("UNIMP: impl_FileServer_FileSystem_RemoveDirectory\n");
++}
++
++static CORBA_char *
++impl_FileServer_FileSystem_ChangeDirectory(impl_POA_FileServer_FileSystem *
++ servant, CORBA_char * PathName,
++ CORBA_Environment * ev)
++{
++ CORBA_char *retval;
++ printf("UNIMP: impl_FileServer_FileSystem_ChangeDirectory\n");
++ return retval;
++}
++
++static void
++impl_FileServer_FileSystem_MakeNode(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * FileName,
++ CORBA_short Mode,
++ CORBA_long DeviceNum,
++ CORBA_Environment * ev)
++{
++ printf("UNIMP: impl_FileServer_FileSystem_MakeNode\n");
++}
++
++static void
++impl_FileServer_FileSystem_Mount(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * DeviceFile,
++ CORBA_char * Location,
++ CORBA_char * FSType,
++ CORBA_long Flags, CORBA_Environment * ev)
++{
++ printf("UNIMP: impl_FileServer_FileSystem_Mount: ARE YOU CRAZY!?!?\n");
++}
++
++static void
++impl_FileServer_FileSystem_Unmount(impl_POA_FileServer_FileSystem * servant,
++ CORBA_char * Filename,
++ CORBA_Environment * ev)
++{
++ printf("UNIMP: impl_FileServer_FileSystem_Unmount: Ha ha ha funny guy!\n");
++}
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/Makefile linux-2.4.1-korbit/net/korbit/modules/FileServer/server/Makefile
+--- linux-2.4.1/net/korbit/modules/FileServer/server/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/Makefile Thu Feb 1 11:47:08 2001
+@@ -0,0 +1,20 @@
++#
++# Makefile for KORBit / FileServer
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := corba-fileserver-server.o
++
++obj-y := FileServer-common.o FileServer-skels.o FileServer-server.o
++obj-m := $(O_TARGET)
++
++include ../../Makefile.module
++
++FileServer-server.c: FileServer.h FileServer-common.c FileServer-skels.c FileServer-skelimpl.c
++
++FileServer.h FileServer-skels.c FileServer-common.c: ../FileServer.idl
++ $(ORBIT_IDL) ../FileServer.idl
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/Makefile.user linux-2.4.1-korbit/net/korbit/modules/FileServer/server/Makefile.user
+--- linux-2.4.1/net/korbit/modules/FileServer/server/Makefile.user Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/Makefile.user Thu Feb 1 11:47:08 2001
+@@ -0,0 +1,32 @@
++#
++# Makefile for KORBit
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++PROJECT = FileServer
++
++CFLAGS = -Wall `orbit-config --cflags server` -I../../..
++LDFLAGS = `orbit-config --libs server`
++OBJS = $(PROJECT)-common.o $(PROJECT)-skels.o $(PROJECT)-server.o
++ORBIT-IDL = orbit-idl
++
++$(PROJECT)-server: $(OBJS)
++ gcc -o $(PROJECT)-server $(OBJS) $(LDFLAGS)
++
++$(PROJECT)-server.c: $(PROJECT).h $(PROJECT)-skelimpl.c
++
++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-skels.c $(PROJECT)-skelimpl.c: ../$(PROJECT).idl
++ $(ORBIT-IDL) --nostubs ../$(PROJECT).idl
++
++clean:
++ rm -f $(OBJS) $(PROJECT)-server
++
++realclean: clean
++ rm -f $(PROJECT).h
++ rm -f $(PROJECT)-common.c
++ rm -f $(PROJECT)-skels.c
++ rm -f *~
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/README linux-2.4.1-korbit/net/korbit/modules/FileServer/server/README
+--- linux-2.4.1/net/korbit/modules/FileServer/server/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/README Thu Feb 1 11:47:08 2001
+@@ -0,0 +1,4 @@
++Kernel side implementation of the file server functionality.
++
++ORB: kORBit
++Status: Mostly unimplemented.
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server-user/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/FileServer/server-user/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/CVS/Entries Thu Feb 1 11:47:08 2001
+@@ -0,0 +1,4 @@
++/FileServer-server.c/1.1/Thu Feb 1 09:47:08 2001//
++/Makefile/1.1/Thu Feb 1 09:47:08 2001//
++/README/1.1/Thu Feb 1 09:47:08 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server-user/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/FileServer/server-user/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/CVS/Repository Thu Feb 1 11:47:08 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/FileServer/server-user
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server-user/CVS/Root linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/CVS/Root
+--- linux-2.4.1/net/korbit/modules/FileServer/server-user/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/CVS/Root Thu Feb 1 11:47:08 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server-user/FileServer-server.c linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/FileServer-server.c
+--- linux-2.4.1/net/korbit/modules/FileServer/server-user/FileServer-server.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/FileServer-server.c Thu Feb 1 11:47:08 2001
+@@ -0,0 +1,234 @@
++#include <OB/CORBA.h>
++#include <OB/Util.h>
++#include <OB/CosNaming.h>
++#include <stdlib.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <errno.h>
++
++#include "FileServer_skel.h"
++
++static void ThrowErr() {
++ switch (errno) {
++ case 0: return;
++ case EISDIR:
++ throw Errors::IsDirectory();
++ case EPERM:
++ throw Errors::PermissionDenied();
++ case EEXIST:
++ throw Errors::FileExists();
++ case ENOENT:
++ throw Errors::FileNotFound();
++ case ENOTDIR:
++ throw Errors::IsNotDirectory();
++ case EROFS:
++ case ETXTBSY:
++ throw Errors::ReadOnlyFile();
++ case ELOOP:
++ throw Errors::RecursiveSymlink();
++ case EBUSY:
++ throw Errors::IsBusy();
++ default:
++ throw Errors::OtherError();
++ }
++}
++
++
++class FileServer_File_impl : public FileServer_File_skel {
++ int FD;
++ public:
++ FileServer_File_impl(int fd) { FD = fd; }
++
++ virtual void Read(CORBA_Long count, FileServer_buffer*& buf) {
++ errno = 0;
++ cout << "Read\n";
++ buf = new FileServer_buffer();
++ ThrowErr();
++ }
++
++ virtual void Write(const FileServer_buffer& buf) {
++ errno = 0;
++ cout << "Write\n";
++ ThrowErr();
++ }
++
++ virtual void Close() {
++ errno = 0;
++ close(FD);
++ cout << "Close()\n";
++ ThrowErr();
++ }
++
++ virtual CORBA_Long FileControl(CORBA_Long command) {
++ errno = 0;
++ cout << "filecontrol\n";
++ ThrowErr();
++ return 0;
++ }
++
++ virtual FileServer_FileStatus GetStatus() {
++ errno = 0;
++ cout << "stat\n";
++ FileServer_FileStatus Stat;
++ ThrowErr();
++ return Stat;
++ }
++
++ virtual void ChangeDirectoryTo() {
++ errno = 0;
++ cout << "ChangeDirectoryTo()\n";
++ ThrowErr();
++ }
++
++ virtual CORBA_Long Seek(CORBA_Long Offset, SeekDirection Direction) {
++ errno = 0;
++ cout << "Seek(" << Offset << ")\n";
++ ThrowErr();
++ return -1;
++ }
++
++ virtual FileServer_File_ptr Duplicate() {
++ errno = 0;
++ cout << "Duplicate!\n";
++ ThrowErr();
++ return 0;
++ }
++};
++
++
++class FileServer_impl : public FileServer_FileSystem_skel {
++ public :
++ virtual FileServer_File_ptr Open(const char* Filename,
++ CORBA_Long openFlags,
++ CORBA_Short mode) {
++ errno = 0;
++ int fd = open(Filename, openFlags, mode);
++ if (fd != -1) return new FileServer_File_impl(fd);
++ cout << "open\n";
++ ThrowErr();
++ return 0;
++ }
++
++ virtual FileServer_File_ptr Create(const char* Filename,
++ CORBA_Short mode) {
++ errno = 0;
++ cout << "create\n";
++ ThrowErr();
++ return 0;
++ }
++
++
++ virtual void Link(const char* FromPath,
++ const char* ToPath) {
++ errno = 0;
++ cout << "link\n";
++ ThrowErr();
++ }
++
++ virtual void Unlink(const char* Filename) {
++ errno = 0;
++ cout << "unlink\n";
++ ThrowErr();
++ }
++
++ virtual void Rename(const char* OldName,
++ const char* NewName) {
++ errno = 0;
++ cout << "rename\n";
++ ThrowErr();
++ }
++
++
++ virtual void ReadLink(const char* Linkname,
++ char*& LinkValue) {
++ errno = 0;
++ cout << "readlink\n";
++ ThrowErr();
++ }
++
++ virtual FileServer_FileStatus GetStatus(const char* Filename) {
++ errno = 0;
++ cout << "stat\n";
++ FileServer_FileStatus Stat;
++ ThrowErr();
++ return Stat;
++ }
++
++
++ virtual FileServer_FileStatus GetLinkStatus(const char* Filename) {
++ errno = 0;
++ cout << "lstat\n";
++ FileServer_FileStatus Stat;
++ ThrowErr();
++ return Stat;
++ }
++
++
++ virtual void MakeDirectory(const char* PathName,
++ CORBA_Short mode) {
++ errno = 0;
++ cout << "mkdir\n";
++ ThrowErr();
++ }
++
++ virtual void RemoveDirectory(const char* PathName) {
++ errno = 0;
++ cout << "rmdir\n";
++ ThrowErr();
++ }
++
++
++ virtual char* ChangeDirectory(const char* PathName) {
++ errno = 0;
++ cout << "chdir\n";
++ ThrowErr();
++ return CORBA_string_dup("hello");
++ }
++
++ virtual void MakeNode(const char* FileName,
++ CORBA_Short Mode,
++ CORBA_Long DeviceNum) {
++ errno = 0;
++ cout << "mknod\n";
++ ThrowErr();
++ }
++
++
++ virtual void Mount(const char* DeviceFile,
++ const char* Location,
++ const char* FSType,
++ CORBA_Long Flags) {
++ errno = 0;
++ cout << "Mount\n";
++ ThrowErr();
++ }
++
++ virtual void Unmount(const char* Filename) {
++ errno = 0;
++ cout << "Unmount\n";
++ ThrowErr();
++ }
++};
++
++
++int main(int argc, char* argv[]) {
++ cout << "FileServer UserSpace Server initializing" << endl;
++
++ try {
++ CORBA_ORB_var orb = CORBA_ORB_init(argc, argv);
++ CORBA_BOA_var boa = orb->BOA_init(argc, argv);
++
++ FileServer_FileSystem_var FS = new FileServer_impl();
++
++ cout << orb->object_to_string(FS) << endl;
++
++ //
++ // Run implementation
++ //
++ boa -> impl_is_ready(CORBA_ImplementationDef::_nil());
++ } catch(CORBA_SystemException& ex) {
++ OBPrintException(ex);
++ return 1;
++ }
++}
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server-user/Makefile linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/Makefile
+--- linux-2.4.1/net/korbit/modules/FileServer/server-user/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/Makefile Thu Feb 1 11:47:08 2001
+@@ -0,0 +1,29 @@
++CC = CC -mt -pta
++OBDIR = /home/class/cs423/local
++IDL = $(OBDIR)/bin/idl
++CPPFLAGS = -I. -I$(OBDIR)/include
++LDFLAGS = -L$(OBDIR)/lib
++LIBS = -lCosNaming -lOB -lJTC -lsocket -lnsl -lposix4
++
++all: FileServer
++
++FileServer: FileServer.o FileServer-server.o FileServer_skel.o
++ $(CC) $(LDFLAGS) -o FileServer FileServer-server.o FileServer.o FileServer_skel.o $(LIBS)
++
++FileServer.h FileServer.cpp: ../FileServer.idl
++ rm -f FileServer.cpp FileServer.h
++ rm -f FileServer_skel.h FileServer_skel.cpp
++ $(IDL) ../FileServer.idl
++
++FileServer_skel.cpp FileServer_skel.h: FileServer.cpp
++
++%.o: %.cpp
++ $(CC) $(CPPFLAGS) -c $<
++
++clean:
++ rm -f FileServer *.o *~
++
++realclean: clean
++ rm -f FileServer.h FileServer.cpp
++ rm -f FileServer_skel.h FileServer_skel.cpp
++ rm -rf SunWS_cache
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/server-user/README linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/README
+--- linux-2.4.1/net/korbit/modules/FileServer/server-user/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/README Thu Feb 1 11:47:08 2001
+@@ -0,0 +1 @@
++This is a user space implementation of the FileServer interface.
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/CVS/Entries Thu Feb 1 11:47:09 2001
+@@ -0,0 +1,6 @@
++/FileServer_wrapper.cpp/1.2/Thu Feb 1 09:47:09 2001//
++/FileServer_wrapper.h/1.2/Thu Feb 1 09:47:09 2001//
++/Makefile/1.1/Thu Feb 1 09:47:09 2001//
++/README/1.1/Thu Feb 1 09:47:09 2001//
++/test.c/1.2/Thu Feb 1 09:47:09 2001//
++D
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/CVS/Repository Thu Feb 1 11:47:09 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/FileServer/wrapper
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/CVS/Root linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/CVS/Root
+--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/CVS/Root Thu Feb 1 11:47:09 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.cpp linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.cpp
+--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.cpp Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.cpp Thu Feb 1 11:47:09 2001
+@@ -0,0 +1,135 @@
++/*
++ * FileServer_wrapper.cpp
++ *
++ * We want to intercept *all* file I/O, so that once the LD_PRELOAD
++ * variable is set, everything you see is on the remote side.
++ *
++ * Needed environment variables:
++ * LD_PRELOAD - duh (what's the lib name?)
++ * KORBIT_IOR - IOR of the file servin' ORB to connect to.
++ *
++ */
++
++#include <stdio.h>
++#include <dlfcn.h>
++#include <stdarg.h>
++#include <stdlib.h>
++#include <string.h>
++#include <dirent.h>
++#include <errno.h>
++
++#include "OB/CORBA.h"
++//#include "OB/Util.h"
++//#include "OB/CosNaming.h"
++
++#include "FileServer.h"
++#include "FileServer_wrapper.h"
++
++#define DEBUG
++
++#ifdef DEBUG
++#define debugOut(X) cerr << X << flush;
++#else
++#define debugOut(X)
++#endif
++
++
++FileSystemState::FileSystemState() {
++ char *argv[] = { (char*)"/usr/bin/mkdir", 0 };
++ int argc = 1;
++
++ debugOut ("FS_wrapper: InitializeOrb(): start.\n");
++
++ /* Set 'PerformingInitialization = true'? */
++
++ orb = CORBA_ORB_init(argc, argv);
++ if (CORBA_is_nil(orb)) {
++ cerr << "Error initializing ORB!\n";
++ exit(1);
++ }
++ debugOut ("\tORB initialized successfully.\n");
++
++ const char *env = getenv("KORBIT_IOR");
++ if (!env) {
++ // This should check /proc/corba/FileServer-server also!
++ cerr << "InitializeOrb Error: KORBIT_IOR not found in environment!\n";
++ exit(1);
++ }
++
++ cout << "IOR = " << env << endl;
++
++ // WHY DO I HANG IN string_to_object??
++ CORBA_Object_var obj = orb->string_to_object(env);
++ debugOut("\tORB initialized successfully.\n");
++
++ if (CORBA_is_nil(obj)) {
++ cerr << "InitializeOrb Error: IOR is invalid: " << env << endl;
++ exit (1);
++ }
++
++ debugOut ("\tORB initialized successfully.\n");
++ try {
++ FS = FileServer_FileSystem::_narrow(obj);
++ } catch (...) {
++ cerr << "InitializeOrb Error: Got an exception from _narrow().\n";
++ exit (1);
++ }
++
++ /* Initialize my data structure 'o file descriptors. */
++
++ // Set up mapping for stdin, stdout, stderr. Set up a new fd, #4 for
++ // console/debug output
++
++ // stderr can go to console for now.
++
++ debugOut ("FS_wrapper: InitializeOrb(): finished successfully.\n");
++} /* End InitializeOrb(). */
++
++
++FileSystemState::~FileSystemState() (void) {
++} /* End CleanupOrb(). */
++
++
++void HandleException(CORBA_UserException &Exception) {
++ try {
++ throw Exception; // get the type back...
++ } catch (Errors::FileExists &) {
++ errno = EEXIST;
++ } catch (Errors::PermissionDenied &) {
++ errno = EACCES;
++ } catch (Errors::FileNotFound &) {
++ errno = ENOENT;
++ } catch (Errors::IsNotDirectory &) {
++ errno = ENOTDIR;
++ } catch (Errors::ReadOnlyFile &) {
++ errno = EROFS;
++ } catch (Errors::RecursiveSymlink &) {
++ errno = ELOOP;
++ } catch (Errors::OtherError &) {
++ errno = EIO; /* I/O error */
++ } catch (CORBA_UserException &Exception) {
++ cerr << "unknown exception occurred! \n";
++ }
++}
++
++//int open(const char *path, int oflag, mode_t mode) {
++
++
++// return -1;
++//}
++
++int mkdir(const char *pathname, mode_t mode) {
++ debugOut("FS_wrapper: mkdir(" << pathname << "): start.\n");
++
++ try {
++ FileSystemState::get().getFS()->MakeDirectory(pathname, mode);
++ } catch (CORBA_UserException &ex) {
++ HandleException(ex);
++ return -1;
++ }
++
++ // Success!
++ debugOut("FS wrapper: mkdir(): finish successfully.\n");
++ return 0;
++} // End mkdir()
++
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.h linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.h
+--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.h Thu Feb 1 11:47:09 2001
+@@ -0,0 +1,81 @@
++// The KORBit FileServer wrapper, which is a shared library that gets
++// hit with the LD_PRELOAD action, so as to redirect all FS calls
++// out the CORBA hole.
++//
++// Note that most of these functions have the side effect of modifying errno.
++//
++#ifndef FILESERVER_WRAPPER_H
++#define FILESERVER_WRAPPER_H
++
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++
++// This class contains all the global variables for this file. It is very
++// important that we use this mechanism so that our library is initialized as
++// early as possible, but no earlier. In particular this means that we cannot
++// be initialized before iostreams are, which we use for debugging. This scheme
++// the only way to that we are constructed and descructed on demand.
++//
++class FileSystemState {
++private:
++ FileSystemState(); // private ctor/dtor. The only way to get one of these is
++ ~FileSystemState(); // to call FileSystemState::get()
++
++ FileSystemState(const FileSystemState &); // do not implement
++ FileSystemState &operator=(const FileSystemState &); // do not implement
++
++
++ CORBA_ORB_var orb; // Global reference to the orb.
++ FileServer_FileSystem_var FS; // Global reference to FS object...
++public:
++ static FileSystemState &get() {
++ // Static objects like this are intialized the first time they are used, and
++ // destroyed when the project shuts down. This is exactly the semantics we
++ // want.
++ static FileSystemState FSS;
++ return FSS;
++ }
++
++ CORBA_ORB_var getORB() { return orb; }
++ FileServer_FileSystem_var getFS() { return FS; }
++};
++
++extern "C" {
++
++ //
++ // interface File
++ //
++ // pread, readv, pwrite, writev
++ int read(int FD, void *Buffer, size_t NumBytes);
++ int write(int FD, void *Buffer, size_t NumBytes);
++ int close(int FD);
++ // fcntl
++ // fstat
++ // fchdir
++ // seek
++ int dup(int FD);
++ int dup2(int FDFrom, int FDTo);
++
++ //
++ // interface FileSystem
++ //
++ // int open(const char *path, int oflag, mode_t mode);
++ int creat(const char *path, mode_t mode);
++
++// link
++// unlink
++// rename
++// readlink
++// stat
++// lstat
++ int mkdir(const char *Path, mode_t Mode);
++// rmdir
++ int chdir(const char *Path);
++}
++
++//
++// Local function prototypes.
++//
++
++#endif
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/Makefile linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/Makefile
+--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/Makefile Thu Feb 1 11:47:09 2001
+@@ -0,0 +1,29 @@
++CC = CC -mt -pta -g
++OBDIR = /home/class/cs423/local
++IDL = $(OBDIR)/bin/idl
++CPPFLAGS = -I. -I$(OBDIR)/include
++LDFLAGS = -L$(OBDIR)/lib -G -fPIC
++LIBS = -lCosNaming -lOB -lJTC -lsocket -lnsl -lposix4 -lCstd -lCrun
++
++all: libfswrapper.so
++
++libfswrapper.so: FileServer.o FileServer_wrapper.o
++ CC $(LDFLAGS) -o $@ FileServer_wrapper.o FileServer.o $(LIBS)
++
++FileServer.h FileServer.cpp: ../FileServer.idl
++ rm -f FileServer.cpp FileServer.h
++ rm -f FileServer_skel.h FileServer_skel.cpp
++ $(IDL) ../FileServer.idl
++
++FileServer_skel.cpp FileServer_skel.h: FileServer.cpp
++
++%.o: %.cpp
++ $(CC) $(CPPFLAGS) -c $<
++
++clean:
++ rm -f libfswrapper.so *.o *~
++
++realclean: clean
++ rm -f FileServer.h FileServer.cpp
++ rm -f FileServer_skel.h FileServer_skel.cpp
++ rm -rf SunWS_cache
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/README linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/README
+--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/README Thu Feb 1 11:47:09 2001
+@@ -0,0 +1,5 @@
++This is a library that may be LD_PRELOAD'd to forward filesystem related calls
++through the FileServer interface.
++
++ORB: ORBacus
++Status: Mostly not working
+diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/test.c linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/test.c
+--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/test.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/test.c Thu Feb 1 11:47:09 2001
+@@ -0,0 +1,15 @@
++#include <stdlib.h>
++#include <stdio.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++
++int main(void)
++{
++ if (mkdir("test", 0666) == -1)
++ {
++ perror ("mkdir failed because: ");
++ return (1);
++ }
++
++ return (0);
++}
+diff -urN linux-2.4.1/net/korbit/modules/Makefile linux-2.4.1-korbit/net/korbit/modules/Makefile
+--- linux-2.4.1/net/korbit/modules/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Makefile Thu Feb 1 11:46:58 2001
+@@ -0,0 +1,15 @@
++#
++# Makefile for KORBit/modules
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++
++subdir-$(CONFIG_CORBA_CONSOLE) += Console
++subdir-$(CONFIG_CORBA_ECHO) += Echo
++subdir-$(CONFIG_CORBA_FILESERVER) += FileServer
++subdir-$(CONFIG_CORBA_CORBAFS) += CorbaFS
++subdir-$(CONFIG_CORBA_CHARDEV) += CharDev
++
++include $(TOPDIR)/Rules.make
++
+diff -urN linux-2.4.1/net/korbit/modules/Makefile.module linux-2.4.1-korbit/net/korbit/modules/Makefile.module
+--- linux-2.4.1/net/korbit/modules/Makefile.module Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/Makefile.module Thu Feb 1 11:46:58 2001
+@@ -0,0 +1,9 @@
++M_OBJS := $(O_TARGET)
++
++EXTRA_CFLAGS = -D__KORBIT__ -DHAVE_CONFIG_H -I. -I../../.. -I../../../include -I../../../kglib -nostdinc
++
++
++ORBIT_IDL = orbit-idl
++
++include $(TOPDIR)/Rules.make
++
+diff -urN linux-2.4.1/net/korbit/modules/README linux-2.4.1-korbit/net/korbit/modules/README
+--- linux-2.4.1/net/korbit/modules/README Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/README Thu Feb 1 11:46:58 2001
+@@ -0,0 +1,7 @@
++Modules included so far:
++
++CharDev : Implement Linux character device drivers
++Console : Print strings to the Linux console
++CorbaFS : Implement Linux filesystems through the VFS layer
++Echo : Testcase to test orb two-way communication
++FileServer: Access a filesystem through CORBA
+diff -urN linux-2.4.1/net/korbit/modules/UserFS/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/UserFS/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Entries Thu Feb 1 11:47:09 2001
+@@ -0,0 +1 @@
++D
+diff -urN linux-2.4.1/net/korbit/modules/UserFS/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Entries.Log
+--- linux-2.4.1/net/korbit/modules/UserFS/CVS/Entries.Log Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Entries.Log Thu Feb 1 11:47:10 2001
+@@ -0,0 +1 @@
++A D/client////
+diff -urN linux-2.4.1/net/korbit/modules/UserFS/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/UserFS/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Repository Thu Feb 1 11:47:09 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/UserFS
+diff -urN linux-2.4.1/net/korbit/modules/UserFS/CVS/Root linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Root
+--- linux-2.4.1/net/korbit/modules/UserFS/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Root Thu Feb 1 11:47:09 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/modules/UserFS/client/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/UserFS/client/CVS/Entries
+--- linux-2.4.1/net/korbit/modules/UserFS/client/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/client/CVS/Entries Thu Feb 1 11:47:10 2001
+@@ -0,0 +1 @@
++D
+diff -urN linux-2.4.1/net/korbit/modules/UserFS/client/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/UserFS/client/CVS/Repository
+--- linux-2.4.1/net/korbit/modules/UserFS/client/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/client/CVS/Repository Thu Feb 1 11:47:10 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/modules/UserFS/client
+diff -urN linux-2.4.1/net/korbit/modules/UserFS/client/CVS/Root linux-2.4.1-korbit/net/korbit/modules/UserFS/client/CVS/Root
+--- linux-2.4.1/net/korbit/modules/UserFS/client/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/client/CVS/Root Thu Feb 1 11:47:10 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/orb/CVS/Entries linux-2.4.1-korbit/net/korbit/orb/CVS/Entries
+--- linux-2.4.1/net/korbit/orb/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/CVS/Entries Thu Feb 1 11:47:14 2001
+@@ -0,0 +1,60 @@
++/Makefile/1.6/Thu Feb 1 09:47:10 2001//
++/allocator-defs.h/1.1.1.1/Thu Feb 1 09:47:10 2001//
++/allocators.c/1.2/Thu Feb 1 09:47:10 2001//
++/allocators.h/1.1.1.1/Thu Feb 1 09:47:10 2001//
++/cdr.c/1.1.1.1/Thu Feb 1 09:47:10 2001//
++/cdr.h/1.1.1.1/Thu Feb 1 09:47:10 2001//
++/corba_any.c/1.3/Thu Feb 1 09:47:10 2001//
++/corba_any.h/1.1.1.1/Thu Feb 1 09:47:10 2001//
++/corba_any_proto.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_any_type.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_basic_sequences_type.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_context.c/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_context.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_env.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_env_type.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_object.c/1.7/Thu Feb 1 09:47:11 2001//
++/corba_object.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_object_type.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_orb.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_orb_type.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_portableserver.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_portableserver_type.h/1.1.1.1/Thu Feb 1 09:47:11 2001//
++/corba_sequences.h/1.1.1.1/Thu Feb 1 09:47:12 2001//
++/corba_sequences_type.h/1.1.1.1/Thu Feb 1 09:47:12 2001//
++/corba_typecode.h/1.1.1.1/Thu Feb 1 09:47:12 2001//
++/corba_typecode_type.h/1.3/Thu Feb 1 09:47:12 2001//
++/dii.c/1.2/Thu Feb 1 09:47:12 2001//
++/dii.h/1.2/Thu Feb 1 09:47:12 2001//
++/env.c/1.2/Thu Feb 1 09:47:12 2001//
++/env.h/1.2/Thu Feb 1 09:47:12 2001//
++/genrand.c/1.4/Thu Feb 1 09:47:12 2001//
++/genrand.h/1.1.1.1/Thu Feb 1 09:47:12 2001//
++/iop.h/1.1.1.1/Thu Feb 1 09:47:12 2001//
++/ir.c/1.1.1.1/Thu Feb 1 09:47:12 2001//
++/ir.h/1.1.1.1/Thu Feb 1 09:47:12 2001//
++/options.c/1.2/Thu Feb 1 09:47:12 2001//
++/options.h/1.2/Thu Feb 1 09:47:13 2001//
++/orb.c/1.13/Thu Feb 1 09:47:13 2001//
++/orb.h/1.2/Thu Feb 1 09:47:13 2001//
++/orbit.c/1.1.1.1/Thu Feb 1 09:47:13 2001//
++/orbit.h/1.2/Thu Feb 1 09:47:13 2001//
++/orbit.h.in/1.1.1.1/Thu Feb 1 09:47:13 2001//
++/orbit_config.h/1.1.1.1/Thu Feb 1 09:47:13 2001//
++/orbit_object.c/1.1.1.1/Thu Feb 1 09:47:13 2001//
++/orbit_object.h/1.1.1.1/Thu Feb 1 09:47:13 2001//
++/orbit_object_type.h/1.1.1.1/Thu Feb 1 09:47:13 2001//
++/orbit_poa.c/1.1.1.1/Thu Feb 1 09:47:13 2001//
++/orbit_poa.h/1.3/Thu Feb 1 09:47:13 2001//
++/orbit_poa_type.h/1.1.1.1/Thu Feb 1 09:47:13 2001//
++/orbit_typecode.c/1.1.1.1/Thu Feb 1 09:47:14 2001//
++/orbit_typecode.h/1.1.1.1/Thu Feb 1 09:47:14 2001//
++/orbit_types.h/1.1.1.1/Thu Feb 1 09:47:14 2001//
++/poa.c/1.1.1.1/Thu Feb 1 09:47:14 2001//
++/poa.h/1.1.1.1/Thu Feb 1 09:47:14 2001//
++/sequences.c/1.1.1.1/Thu Feb 1 09:47:14 2001//
++/sequences.h/1.1.1.1/Thu Feb 1 09:47:14 2001//
++/server.c/1.5/Thu Feb 1 09:47:14 2001//
++/typecode.c/1.1.1.1/Thu Feb 1 09:47:14 2001//
++/typecode.h/1.1.1.1/Thu Feb 1 09:47:14 2001//
++D
+diff -urN linux-2.4.1/net/korbit/orb/CVS/Repository linux-2.4.1-korbit/net/korbit/orb/CVS/Repository
+--- linux-2.4.1/net/korbit/orb/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/CVS/Repository Thu Feb 1 11:47:10 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/orb
+diff -urN linux-2.4.1/net/korbit/orb/CVS/Root linux-2.4.1-korbit/net/korbit/orb/CVS/Root
+--- linux-2.4.1/net/korbit/orb/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/CVS/Root Thu Feb 1 11:47:10 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
+diff -urN linux-2.4.1/net/korbit/orb/Makefile linux-2.4.1-korbit/net/korbit/orb/Makefile
+--- linux-2.4.1/net/korbit/orb/Makefile Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/Makefile Thu Feb 1 11:47:10 2001
+@@ -0,0 +1,25 @@
++#
++# Makefile for KORBit/orb
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .o file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET := orblib.o
++
++#obj-m := $(O_TARGET)
++obj-y := allocators.o options.o poa.o \
++ cdr.o env.o orb.o sequences.o \
++ corba_any.o genrand.o orbit.o server.o \
++ corba_context.o orbit_object.o typecode.o \
++ corba_object.o orbit_poa.o \
++ dii.o ir.o orbit_typecode.o
++
++EXTRA_CFLAGS = -D__KORBIT__ -DHAVE_CONFIG_H -I. -I.. -I../include -I../kglib -I../ORBitutil -nostdinc \
++ -DORBit_SYSRC=\"/etc/orbitrc\" \
++ -DORBIT_MAJOR_VERSION="0" -DORBIT_MINOR_VERSION="5" -DORBIT_MICRO_VERSION="3" -DORBIT_VERSION=\"0.5.3\"
++
++include $(TOPDIR)/Rules.make
++
+diff -urN linux-2.4.1/net/korbit/orb/allocator-defs.h linux-2.4.1-korbit/net/korbit/orb/allocator-defs.h
+--- linux-2.4.1/net/korbit/orb/allocator-defs.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/allocator-defs.h Thu Feb 1 11:47:10 2001
+@@ -0,0 +1,40 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/* By Elliot Lee. Copyright (c) 1998 Red Hat Software */
++
++
++/********************************************************
++ * Never include this header file directly. Only allocators.[ch]
++ * should do this
++ ********************************************************/
++
++/* Macro crap */
++
++#ifdef ALLOCATOR_DEFINITION
++
++#define ORBIT_DEFINE_CHUNK(x, xsize) \
++DEFINE_LOCK(x##_allocator); \
++GMemChunk *x##_allocator = NULL
++
++#elif defined(ALLOCATOR_INITIALIZATION)
++
++#define ORBIT_DEFINE_CHUNK(x, xsize) INIT_LOCK(x##_allocator); \
++x##_allocator = g_mem_chunk_new(#x, (xsize), \
++(xsize) * ORBIT_CHUNKS_PREALLOC, G_ALLOC_AND_FREE)
++
++#else
++
++#define ORBIT_DEFINE_CHUNK(x, xsize) \
++EXTERN_LOCK(x##_allocator); \
++extern GMemChunk *x##_allocator
++
++#endif
++
++/*****************************************************
++ * Here's where we define the actual chunks that are used
++ *****************************************************/
++ORBIT_DEFINE_CHUNK(CORBA_TypeCode, sizeof(struct CORBA_TypeCode_struct));
++ORBIT_DEFINE_CHUNK(CORBA_Object, sizeof(struct CORBA_Object_struct));
++ORBIT_DEFINE_CHUNK(CORBA_NVList, sizeof(struct CORBA_NVList_type));
++
++#undef ORBIT_DEFINE_CHUNK
+diff -urN linux-2.4.1/net/korbit/orb/allocators.c linux-2.4.1-korbit/net/korbit/orb/allocators.c
+--- linux-2.4.1/net/korbit/orb/allocators.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/allocators.c Thu Feb 1 11:47:10 2001
+@@ -0,0 +1,241 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/* By Elliot Lee. Copyright (c) 1998 Red Hat Software */
++
++#include "orbit.h"
++
++#if 0
++#define CORBA_Object_release(x, y) ({ g_message(__FILE__ ":%d Releasing object %#x from %d", __LINE__, \
++x, ORBIT_ROOT_OBJECT(x)->refs); CORBA_Object_release(x, y); })
++#define CORBA_Object_duplicate(x, y) ({ g_message(__FILE__ ":%d Duping object %#x from %d", __LINE__, \
++x, ORBIT_ROOT_OBJECT(x)->refs); CORBA_Object_duplicate(x, y); })
++#endif
++
++/* The memory chunk stuff */
++
++#define ALLOCATOR_DEFINITION
++#include "allocator-defs.h"
++#undef ALLOCATOR_DEFINITION
++
++void
++ORBit_chunks_init(void)
++{
++#define ALLOCATOR_INITIALIZATION
++#include "allocator-defs.h"
++#undef ALLOCATOR_INTIALIZATION
++}
++
++gpointer
++ORBit_chunk_alloc(GMemChunk *chunk,
++ PARAM_LOCK(chunk))
++{
++ gpointer retval;
++
++ GET_LOCK(chunk);
++ retval = g_mem_chunk_alloc(chunk);
++ RELEASE_LOCK(chunk);
++
++ return retval;
++}
++
++void
++ORBit_chunk_free(GMemChunk *chunk,
++ PARAM_LOCK(chunk),
++ gpointer mem)
++{
++ GET_LOCK(chunk);
++ g_mem_chunk_free(chunk, mem);
++ RELEASE_LOCK(chunk);
++}
++
++/* end memory chunk routines */
++
++/****************************************************************/
++
++/************* begin funky memory alloc/free system */
++
++/****** functions */
++
++gpointer ORBit_alloc(size_t block_size,
++ ORBit_free_childvals freefunc,
++ gpointer func_data)
++{
++ return ORBit_alloc_2(block_size, freefunc, func_data, 0);
++}
++
++gpointer
++ORBit_alloc_2(size_t block_size,
++ ORBit_free_childvals freefunc,
++ gpointer func_data,
++ size_t before_size)
++{
++ ORBit_mem_info *block;
++
++ if(block_size == 0) return NULL;
++
++ block = (ORBit_mem_info *)((char *)
++ g_malloc(block_size + sizeof(ORBit_mem_info) + before_size)
++ + before_size);
++
++#ifdef ORBIT_DEBUG
++ block->magic = 0xdeadbeef;
++#endif
++ block->free = freefunc;
++ block->func_data = func_data;
++
++ return MEMINFO_TO_PTR(block);
++}
++
++/*
++ ORBit_free
++ ----------
++
++ Frees a corba primitive type.
++
++ mem = pointer to the memory block. (must have a preceeding pointer to a meminfo block)
++
++ 1)obtains a pointer to the preceeding meminfo structure
++ 2)Uses the meminfo structure to find the number of elements in the memory block
++ 3)iterates through the memory block, calling the free function for each item.
++
++ */
++
++void
++ORBit_free(gpointer mem, CORBA_boolean free_strings)
++{
++ ORBit_mem_info *block;
++
++ if(!mem)
++ return;
++
++ block = PTR_TO_MEMINFO(mem);
++
++#ifdef ORBIT_DEBUG
++ g_assert(block->magic == 0xdeadbeef);
++#endif
++
++ if(block->free) {
++ int i;
++ gpointer x;
++ gpointer my_data;
++
++ if((gpointer)block->free == (gpointer)ORBit_free_via_TypeCode)
++ my_data = ((guchar *)block) - sizeof(CORBA_TypeCode);
++ else
++ my_data = NULL;
++
++#ifdef ORBIT_DEBUG
++ if(block->func_data == NULL)
++ g_warning("block with freefunc %p has no items", block->free);
++#endif
++
++ for(i = 0, x = mem; i < (gulong)block->func_data; i++)
++ x = block->free(x, my_data, free_strings);
++
++ if((gpointer)block->free == (gpointer)ORBit_free_via_TypeCode)
++ /* ((guchar *)block) -= sizeof(CORBA_TypeCode); */
++ block = (ORBit_mem_info *)
++ (((guchar *)block) - sizeof(CORBA_TypeCode));
++ g_free(block);
++ } else
++ g_free(block);
++}
++
++/******************************************************************/
++/* These aren't currently used... */
++
++gpointer
++ORBit_free_via_TypeCode(gpointer mem, gpointer tcp, gboolean free_strings)
++{
++ CORBA_TypeCode tc = *(CORBA_TypeCode *)tcp, subtc;
++ int i;
++ guchar *retval = NULL;
++
++ switch(tc->kind) {
++ case CORBA_tk_any:
++ {
++ CORBA_any *anyval = mem;
++ if(anyval->_release)
++ CORBA_free(anyval->_value);
++ retval = (guchar *)(anyval + 1);
++ }
++ break;
++ case CORBA_tk_TypeCode:
++ case CORBA_tk_objref:
++ {
++ CORBA_Object_release(*(CORBA_Object *)mem, NULL);
++
++ retval = (guchar *)mem + sizeof(CORBA_Object);
++ }
++ break;
++ case CORBA_tk_Principal:
++ {
++ CORBA_Principal *pval = mem;
++ if(pval->_release)
++ CORBA_free(pval->_buffer);
++ retval = (guchar *)(pval + 1);
++ }
++ break;
++ case CORBA_tk_except:
++ case CORBA_tk_struct:
++ mem = ALIGN_ADDRESS(mem, ORBit_find_alignment(tc));
++ for(i = 0; i < tc->sub_parts; i++) {
++ subtc = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)tc->subtypes[i], NULL);
++ mem = ORBit_free_via_TypeCode(mem, &subtc,
++ free_strings);
++ }
++ retval = mem;
++ break;
++ case CORBA_tk_union:
++ subtc = (CORBA_TypeCode)CORBA_Object_duplicate(
++ (CORBA_Object)ORBit_get_union_tag(tc, &mem, TRUE), NULL);
++ {
++ int sz = 0;
++ int al = 1;
++ for(i = 0; i < tc->sub_parts; i++) {
++ al = MAX(al, ORBit_find_alignment(tc->subtypes[i]));
++ sz = MAX(sz, ORBit_gather_alloc_info(tc->subtypes[i]));
++ }
++ mem = ALIGN_ADDRESS(mem, al);
++ ORBit_free_via_TypeCode(mem, &subtc, free_strings);
++ /* the end of the body (subtc) may not be the
++ * same as the end of the union */
++ retval = mem + sz;
++ }
++ break;
++ case CORBA_tk_wstring:
++ case CORBA_tk_string:
++ if(free_strings)
++ CORBA_free(*(char **)mem);
++ retval = (guchar *)mem + sizeof(char *);
++ break;
++ case CORBA_tk_sequence:
++ {
++ CORBA_sequence_octet *pval = mem;
++ if(pval->_release)
++ CORBA_free(pval->_buffer);
++
++ retval = (guchar *)mem + sizeof(CORBA_sequence_octet);
++ }
++ break;
++ case CORBA_tk_array:
++ for(i = 0; i < tc->length; i++) {
++ subtc = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)tc->subtypes[0], NULL);
++ mem = ORBit_free_via_TypeCode(mem, &subtc,
++ free_strings);
++ }
++ retval = mem;
++ break;
++ case CORBA_tk_alias:
++ subtc = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)tc->subtypes[0], NULL);
++ retval = ORBit_free_via_TypeCode(mem, &subtc, free_strings);
++ break;
++ default:
++ retval = ((guchar *)mem) + ORBit_gather_alloc_info(tc);
++ break;
++ }
++
++ CORBA_Object_release((CORBA_Object)tc, NULL);
++
++ return (gpointer)retval;
++}
+diff -urN linux-2.4.1/net/korbit/orb/allocators.h linux-2.4.1-korbit/net/korbit/orb/allocators.h
+--- linux-2.4.1/net/korbit/orb/allocators.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/allocators.h Thu Feb 1 11:47:10 2001
+@@ -0,0 +1,61 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/* By Elliot Lee. Copyright (c) 1998 Red Hat Software */
++
++#ifndef ALLOCATORS_H
++#define ALLOCATORS_H 1
++
++#include <orb/orbit.h>
++
++#include <orb/allocator-defs.h>
++
++#define ORBIT_CHUNK_ALLOC(typename) \
++ORBit_chunk_alloc(typename##_allocator, LOCK_NAME(typename##_allocator))
++
++#define ORBIT_CHUNK_FREE(typename, mem) \
++ORBit_chunk_free(typename##_allocator, LOCK_NAME(typename##_allocator), (mem))
++
++void ORBit_chunks_init(void);
++
++gpointer ORBit_chunk_alloc(GMemChunk *chunk,
++ PARAM_LOCK(chunk_lock));
++
++void ORBit_chunk_free(GMemChunk *chunk,
++ PARAM_LOCK(chunk_lock),
++ gpointer mem);
++
++/* General memory allocation routines */
++
++#define PTR_TO_MEMINFO(x) (((ORBit_mem_info *)(x)) - 1)
++#define MEMINFO_TO_PTR(x) ((gpointer)((x) + 1))
++
++typedef gpointer (*ORBit_free_childvals)(gpointer mem,
++ gpointer func_data,
++ CORBA_boolean free_strings);
++
++typedef struct {
++#ifdef ORBIT_DEBUG
++ gulong magic;
++#endif
++ /* If this routine returns FALSE, it indicates that it already free'd
++ the memory block itself */
++ ORBit_free_childvals free; /* function pointer to free function */
++ gpointer func_data;
++} ORBit_mem_info;
++
++gpointer ORBit_alloc(size_t block_size,
++ ORBit_free_childvals freefunc,
++ gpointer func_data);
++gpointer ORBit_alloc_2(size_t block_size,
++ ORBit_free_childvals freefunc,
++ gpointer func_data,
++ size_t before_size);
++
++void ORBit_free(gpointer mem, CORBA_boolean free_strings);
++
++/* internal stuff */
++gpointer ORBit_free_via_TypeCode(gpointer mem,
++ gpointer tcp,
++ gboolean free_strings);
++
++#endif /* ALLOCATORS_H */
+diff -urN linux-2.4.1/net/korbit/orb/cdr.c linux-2.4.1-korbit/net/korbit/orb/cdr.c
+--- linux-2.4.1/net/korbit/orb/cdr.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/cdr.c Thu Feb 1 11:47:10 2001
+@@ -0,0 +1,643 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#include "config.h"
++#include "../IIOP/iiop-endianP.h"
++#include <stdlib.h>
++#include <string.h>
++#include <ctype.h>
++#include <assert.h>
++
++#include "orbit.h"
++
++#define CDR_GROW_AMOUNT 128
++
++static CORBA_boolean CDR_buffer_grow(CDR_Codec *codec, const unsigned int growth)
++{
++ unsigned int real_growth;
++ div_t divvy;
++
++ if(codec->release_buffer) {
++ divvy=div(growth, CDR_GROW_AMOUNT);
++ real_growth=CDR_GROW_AMOUNT * (divvy.quot+1);
++
++ codec->buffer=(CORBA_octet *)g_realloc(codec->buffer,
++ codec->buf_len
++ +real_growth);
++ }
++
++ return CORBA_TRUE;
++}
++
++static void CDR_buffer_puts(CDR_Codec *codec, const void *data, const unsigned int len)
++{
++ if(codec->wptr+len > codec->buf_len) {
++ CORBA_boolean res=CDR_buffer_grow(codec, len);
++
++ if(res==CORBA_FALSE) {
++ /* just bail out for now */
++ g_assert(!"Malloc error");
++ }
++ }
++
++ memcpy(&codec->buffer[codec->wptr], data, len);
++ codec->wptr+=len;
++}
++
++CORBA_boolean CDR_buffer_gets(CDR_Codec *codec, void *dest, const unsigned int len)
++{
++ if(codec->rptr+len > codec->buf_len) {
++ ORBit_Trace(TraceMod_CDR, TraceLevel_Debug, "CDR_buffer_gets: attempt to read past end of buffer\n");
++ return(CORBA_FALSE);
++ }
++
++ memcpy(dest, &codec->buffer[codec->rptr], len);
++ codec->rptr+=len;
++
++ return(CORBA_TRUE);
++}
++
++static void CDR_buffer_put(CDR_Codec *codec, void *datum)
++{
++ if(codec->wptr+1 > codec->buf_len) {
++ CORBA_boolean res=CDR_buffer_grow(codec, 1);
++
++ if(res==CORBA_FALSE) {
++ /* just bail out for now */
++ g_assert(!"Malloc error");
++ }
++ }
++
++ codec->buffer[codec->wptr++]=*(unsigned char *)datum;
++}
++
++static CORBA_boolean CDR_buffer_get(CDR_Codec *codec, void *dest)
++{
++ if(codec->rptr+1 > codec->buf_len) {
++ ORBit_Trace(TraceMod_CDR, TraceLevel_Debug, "CDR_buffer_get: attempt to read past end of buffer\n");
++ return(CORBA_FALSE);
++ }
++
++ *(CORBA_octet *)dest=codec->buffer[codec->rptr++];
++ return(CORBA_TRUE);
++}
++
++#ifdef lame_slow_code
++static void CDR_buffer_put2(CDR_Codec *codec, void *datum)
++{
++ unsigned long align;
++
++ g_assert(codec!=NULL);
++ g_assert(codec->readonly!=CORBA_TRUE);
++ g_assert(codec->wptr<=codec->buf_len);
++
++ align=((codec->wptr+1)&~1L);
++
++ if(align+2 > codec->buf_len) {
++ CORBA_boolean res=CDR_buffer_grow(codec, align+2-codec->wptr);
++
++ if(res==CORBA_FALSE) {
++ /* just bail out for now */
++ g_assert(!"Malloc error");
++ }
++ }
++
++ while(codec->wptr < align) {
++ codec->buffer[codec->wptr++]='\0';
++ }
++
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[0];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[1];
++}
++
++static CORBA_boolean CDR_buffer_get2(CDR_Codec *codec, void *dest)
++{
++ unsigned long align;
++
++ g_assert(codec!=NULL);
++ g_assert(dest!=NULL);
++ g_assert(codec->rptr<=codec->buf_len);
++
++ align=((codec->rptr+1)&~1L);
++
++ if(align+2 > codec->buf_len) {
++ ORBit_Trace(TraceMod_CDR, TraceLevel_Debug, "CDR_buffer_get2: attempt to read past end of buffer\n");
++ return(CORBA_FALSE);
++ }
++
++ codec->rptr=align;
++
++ ((CORBA_octet *)dest)[0]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[1]=codec->buffer[codec->rptr++];
++
++ return(CORBA_TRUE);
++}
++
++static void CDR_buffer_put4(CDR_Codec *codec, void *datum)
++{
++ unsigned long align;
++
++ g_assert(codec!=NULL);
++ g_assert(codec->readonly!=CORBA_TRUE);
++ g_assert(codec->wptr<=codec->buf_len);
++
++ align=((codec->wptr+3)&~3L);
++
++ if(align+4 > codec->buf_len) {
++ CORBA_boolean res=CDR_buffer_grow(codec, align+4-codec->wptr);
++
++ if(res==CORBA_FALSE) {
++ /* just bail out for now */
++ g_assert(!"Malloc error");
++ }
++ }
++
++ while(codec->wptr < align) {
++ codec->buffer[codec->wptr++]='\0';
++ }
++
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[0];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[1];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[2];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[3];
++}
++
++static CORBA_boolean CDR_buffer_get4(CDR_Codec *codec, void *dest)
++{
++ unsigned long align;
++
++ g_assert(codec!=NULL);
++ g_assert(dest!=NULL);
++ g_assert(codec->rptr<=codec->buf_len);
++
++ align=((codec->rptr+3)&~3L);
++
++ if(align+4 > codec->buf_len) {
++ ORBit_Trace(TraceMod_CDR, TraceLevel_Debug, "CDR_buffer_get4: attempt to read past end of buffer\n");
++ return(CORBA_FALSE);
++ }
++
++ codec->rptr=align;
++
++ ((CORBA_octet *)dest)[0]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[1]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[2]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[3]=codec->buffer[codec->rptr++];
++
++ return(CORBA_TRUE);
++}
++
++static void CDR_buffer_put8(CDR_Codec *codec, void *datum)
++{
++ unsigned long align;
++
++ g_assert(codec!=NULL);
++ g_assert(codec->readonly!=CORBA_TRUE);
++ g_assert(codec->wptr<=codec->buf_len);
++
++ align=((codec->wptr+7)&~7L);
++
++ if(align+8 > codec->buf_len) {
++ CORBA_boolean res=CDR_buffer_grow(codec, align+8-codec->wptr);
++
++ if(res==CORBA_FALSE) {
++ /* just bail out for now */
++ g_assert(!"Malloc error");
++ }
++ }
++
++ while(codec->wptr < align) {
++ codec->buffer[codec->wptr++]='\0';
++ }
++
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[0];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[1];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[2];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[3];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[4];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[5];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[6];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[7];
++}
++
++#if 0
++static CORBA_boolean CDR_buffer_get8(CDR_Codec *codec, void *dest)
++{
++ unsigned long align;
++
++ g_assert(codec!=NULL);
++ g_assert(dest!=NULL);
++ g_assert(codec->rptr<=codec->buf_len);
++
++ align=((codec->rptr+7)&~7L);
++
++ if(align+8 > codec->buf_len) {
++ ORBit_Trace(TraceMod_CDR, TraceLevel_Debug, "CDR_buffer_get8: attempt to read past end of buffer\n");
++ return(CORBA_FALSE);
++ }
++
++ codec->rptr=align;
++
++ ((CORBA_octet *)dest)[0]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[1]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[2]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[3]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[4]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[5]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[6]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[7]=codec->buffer[codec->rptr++];
++
++ return(CORBA_TRUE);
++}
++#endif
++
++static void CDR_buffer_put16(CDR_Codec *codec, void *datum)
++{
++ unsigned long align;
++
++ g_assert(codec!=NULL);
++ g_assert(codec->readonly!=CORBA_TRUE);
++ g_assert(codec->wptr<=codec->buf_len);
++
++ align=((codec->wptr+15)&~15L);
++
++ if(align+16 > codec->buf_len) {
++ CORBA_boolean res=CDR_buffer_grow(codec, align+16-codec->wptr);
++
++ if(res==CORBA_FALSE) {
++ /* just bail out for now */
++ g_assert(!"Malloc error");
++ }
++ }
++
++ while(codec->wptr < align) {
++ codec->buffer[codec->wptr++]='\0';
++ }
++
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[0];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[1];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[2];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[3];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[4];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[5];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[6];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[7];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[8];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[9];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[10];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[11];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[12];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[13];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[14];
++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[15];
++}
++
++#if 0
++static CORBA_boolean CDR_buffer_get16(CDR_Codec *codec, void *dest)
++{
++ unsigned long align;
++
++ g_assert(codec!=NULL);
++ g_assert(dest!=NULL);
++ g_assert(codec->rptr<=codec->buf_len);
++
++ align=((codec->rptr+15)&~15L);
++
++ if(align+16 > codec->buf_len) {
++ ORBit_Trace(TraceMod_CDR, TraceLevel_Debug, "CDR_buffer_get16: attempt to read past end of buffer\n");
++ return(CORBA_FALSE);
++ }
++
++ codec->rptr=align;
++
++ ((CORBA_octet *)dest)[0]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[1]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[2]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[3]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[4]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[5]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[6]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[7]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[8]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[9]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[10]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[11]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[12]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[13]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[14]=codec->buffer[codec->rptr++];
++ ((CORBA_octet *)dest)[15]=codec->buffer[codec->rptr++];
++
++ return(CORBA_TRUE);
++}
++#endif
++#endif /* lame_slow_code */
++
++#define CDR_buffer_put2(codec, datum) CDR_buffer_putn(codec, datum, 2)
++#define CDR_buffer_put4(codec, datum) CDR_buffer_putn(codec, datum, 4)
++#define CDR_buffer_put8(codec, datum) CDR_buffer_putn(codec, datum, 8)
++#define CDR_buffer_put16(codec, datum) CDR_buffer_putn(codec, datum, 16)
++#define CDR_buffer_get2(codec, dest) CDR_buffer_getn(codec, dest, 2)
++#define CDR_buffer_get4(codec, dest) CDR_buffer_getn(codec, dest, 4)
++#define CDR_buffer_get8(codec, dest) CDR_buffer_getn(codec, dest, 8)
++#define CDR_buffer_get16(codec, dest) CDR_buffer_getn(codec, dest, 16)
++
++static CORBA_boolean
++CDR_buffer_getn(CDR_Codec *codec, void *dest, int bsize)
++{
++ codec->rptr = (unsigned long)ALIGN_ADDRESS(codec->rptr, bsize);
++ if(codec->host_endian==codec->data_endian)
++ memcpy(dest, codec->buffer + codec->rptr, bsize);
++ else
++ iiop_byteswap(dest, codec->buffer + codec->rptr, bsize);
++ codec->rptr += bsize;
++
++ return CORBA_TRUE;
++}
++
++static CORBA_boolean
++CDR_buffer_putn(CDR_Codec *codec, void *datum, int bsize)
++{
++ codec->wptr = (unsigned long)ALIGN_ADDRESS(codec->wptr, bsize);
++ if(codec->host_endian==codec->data_endian)
++ memcpy(codec->buffer + codec->wptr, datum, bsize);
++ else
++ iiop_byteswap(codec->buffer + codec->wptr, datum, bsize);
++ codec->wptr += bsize;
++
++ return CORBA_TRUE;
++}
++
++#define CDR_swap2(d,s) iiop_byteswap((d), (s), 2)
++#define CDR_swap4(d,s) iiop_byteswap((d), (s), 4)
++#define CDR_swap8(d,s) iiop_byteswap((d), (s), 8)
++#define CDR_swap16(d,s) iiop_byteswap((d), (s), 16)
++
++#ifdef lame_slow_code
++static void CDR_swap2(void *d, void *s)
++{
++ ((CORBA_octet *)d)[0]=((CORBA_octet *)s)[1];
++ ((CORBA_octet *)d)[1]=((CORBA_octet *)s)[0];
++}
++
++static void CDR_swap4(void *d, void *s)
++{
++ ((CORBA_octet *)d)[0]=((CORBA_octet *)s)[3];
++ ((CORBA_octet *)d)[1]=((CORBA_octet *)s)[2];
++ ((CORBA_octet *)d)[2]=((CORBA_octet *)s)[1];
++ ((CORBA_octet *)d)[3]=((CORBA_octet *)s)[0];
++}
++
++static void CDR_swap8(void *d, void *s)
++{
++ ((CORBA_octet *)d)[0]=((CORBA_octet *)s)[7];
++ ((CORBA_octet *)d)[1]=((CORBA_octet *)s)[6];
++ ((CORBA_octet *)d)[2]=((CORBA_octet *)s)[5];
++ ((CORBA_octet *)d)[3]=((CORBA_octet *)s)[4];
++ ((CORBA_octet *)d)[4]=((CORBA_octet *)s)[3];
++ ((CORBA_octet *)d)[5]=((CORBA_octet *)s)[2];
++ ((CORBA_octet *)d)[6]=((CORBA_octet *)s)[1];
++ ((CORBA_octet *)d)[7]=((CORBA_octet *)s)[0];
++}
++
++static void CDR_swap16(void *d, void *s)
++{
++ ((CORBA_octet *)d)[0]=((CORBA_octet *)s)[15];
++ ((CORBA_octet *)d)[1]=((CORBA_octet *)s)[14];
++ ((CORBA_octet *)d)[2]=((CORBA_octet *)s)[13];
++ ((CORBA_octet *)d)[3]=((CORBA_octet *)s)[12];
++ ((CORBA_octet *)d)[4]=((CORBA_octet *)s)[11];
++ ((CORBA_octet *)d)[5]=((CORBA_octet *)s)[10];
++ ((CORBA_octet *)d)[6]=((CORBA_octet *)s)[9];
++ ((CORBA_octet *)d)[7]=((CORBA_octet *)s)[8];
++ ((CORBA_octet *)d)[8]=((CORBA_octet *)s)[7];
++ ((CORBA_octet *)d)[9]=((CORBA_octet *)s)[6];
++ ((CORBA_octet *)d)[10]=((CORBA_octet *)s)[5];
++ ((CORBA_octet *)d)[11]=((CORBA_octet *)s)[4];
++ ((CORBA_octet *)d)[12]=((CORBA_octet *)s)[3];
++ ((CORBA_octet *)d)[13]=((CORBA_octet *)s)[2];
++ ((CORBA_octet *)d)[14]=((CORBA_octet *)s)[1];
++ ((CORBA_octet *)d)[15]=((CORBA_octet *)s)[0];
++}
++#endif
++
++
++void CDR_put_short(CDR_Codec *codec, CORBA_short s)
++{
++ CDR_buffer_put2(codec, &s);
++}
++
++CORBA_boolean CDR_get_short(CDR_Codec *codec, CORBA_short *s)
++{
++ return CDR_buffer_get2(codec, s);
++}
++
++void CDR_put_ushort(CDR_Codec *codec, CORBA_unsigned_short us)
++{
++ CDR_buffer_put2(codec, &us);
++}
++
++CORBA_boolean CDR_get_ushort(CDR_Codec *codec, CORBA_unsigned_short *us)
++{
++ return CDR_buffer_get2(codec, us);
++}
++
++void CDR_put_long(CDR_Codec *codec, CORBA_long l)
++{
++ CDR_buffer_put4(codec, &l);
++}
++
++CORBA_boolean CDR_get_long(CDR_Codec *codec, CORBA_long *l)
++{
++ return CDR_buffer_get4(codec, l);
++}
++
++void CDR_put_ulong(CDR_Codec *codec, CORBA_unsigned_long ul)
++{
++ CDR_buffer_put4(codec, &ul);
++}
++
++CORBA_boolean CDR_get_ulong(CDR_Codec *codec, CORBA_unsigned_long *ul)
++{
++ return CDR_buffer_get4(codec, ul);
++}
++
++#ifdef HAVE_CORBA_LONG_LONG
++CORBA_boolean CDR_get_long_long(CDR_Codec *codec, CORBA_long_long *ul)
++{
++ return CDR_buffer_get8(codec, ul);
++}
++
++void CDR_put_long_long(CDR_Codec *codec, CORBA_long_long ll)
++{
++ CDR_buffer_put8(codec, &ll);
++}
++
++void CDR_put_ulong_long(CDR_Codec *codec, CORBA_unsigned_long_long ll)
++{
++ CDR_buffer_put8(codec, &ll);
++}
++
++CORBA_boolean CDR_get_ulong_long(CDR_Codec *codec, CORBA_unsigned_long_long *ull)
++{
++ return CDR_buffer_get8(codec, ull);
++}
++#endif
++
++void CDR_put_float(CDR_Codec *codec, CORBA_float f)
++{
++ CDR_buffer_put4(codec, &f);
++}
++
++void CDR_put_double(CDR_Codec *codec, CORBA_double d)
++{
++ CDR_buffer_put8(codec, &d);
++}
++
++void CDR_put_long_double(CDR_Codec *codec, CORBA_long_double ld)
++{
++ CDR_buffer_put16(codec, &ld);
++}
++
++void CDR_put_octet(CDR_Codec *codec, CORBA_octet datum)
++{
++ CDR_buffer_put(codec, &datum);
++}
++
++CORBA_boolean CDR_get_octet(CDR_Codec *codec, CORBA_octet *datum)
++{
++ return(CDR_buffer_get(codec, datum));
++}
++
++void CDR_put_octets(CDR_Codec *codec, void *data, unsigned long len)
++{
++ CDR_buffer_puts(codec, data, len);
++}
++
++void CDR_put_char(CDR_Codec *codec, CORBA_char c)
++{
++ CDR_buffer_put(codec, &c);
++}
++
++CORBA_boolean CDR_get_char(CDR_Codec *codec, CORBA_char *c)
++{
++ return CDR_buffer_get(codec, c);
++}
++
++void CDR_put_boolean(CDR_Codec *codec, CORBA_boolean datum)
++{
++ datum = datum&&1;
++ CDR_buffer_put(codec, &datum);
++}
++
++CORBA_boolean CDR_get_boolean(CDR_Codec *codec, CORBA_boolean *b)
++{
++ return CDR_buffer_get(codec, b);
++}
++
++void CDR_put_string(CDR_Codec *codec, const char *str)
++{
++ unsigned int len;
++
++ len=strlen(str)+1;
++
++ CDR_put_ulong(codec, len);
++ CDR_buffer_puts(codec, str, len);
++}
++
++CORBA_boolean CDR_get_string_static(CDR_Codec *codec,
++ CORBA_char **str)
++{
++ CORBA_unsigned_long len;
++
++ if(CDR_get_ulong(codec, &len)==CORBA_FALSE)
++ return CORBA_FALSE;
++
++ if((codec->rptr + len) > codec->buf_len)
++ return CORBA_FALSE;
++
++ *str = ((CORBA_char *)codec->buffer) + codec->rptr;
++
++ codec->rptr += len;
++
++ return CORBA_TRUE;
++}
++
++CORBA_boolean CDR_get_string(CDR_Codec *codec, CORBA_char **str)
++{
++ CORBA_unsigned_long len;
++
++ if(CDR_get_ulong(codec, &len)==CORBA_FALSE)
++ return(CORBA_FALSE);
++
++ if(len==0)
++ return(CORBA_FALSE);
++
++ *str=g_new(CORBA_char, len);
++
++ if(CDR_buffer_gets(codec, *str, len)==CORBA_FALSE) {
++ g_free(*str);
++ return(CORBA_FALSE);
++ }
++
++ if((*str)[len-1]!='\0') {
++ ORBit_Trace(TraceMod_CDR, TraceLevel_Notice, "CDR_get_string: string was not NULL-terminated, terminating it now\n");
++ (*str)[len-1]='\0';
++ }
++
++ return(CORBA_TRUE);
++}
++
++CORBA_boolean CDR_get_seq_begin(CDR_Codec *codec, CORBA_unsigned_long *ul)
++{
++ return(CDR_get_ulong(codec, ul));
++}
++
++CDR_Codec *CDR_codec_init_static(CDR_Codec *codec)
++{
++ memset(codec, 0, sizeof(CDR_Codec));
++
++ codec->host_endian = FLAG_ENDIANNESS;
++
++ return codec;
++}
++
++CDR_Codec *CDR_codec_init(void)
++{
++ CDR_Codec *new;
++
++ new=g_new0(CDR_Codec, 1);
++ CDR_codec_init_static(new);
++ new->release_buffer = CORBA_TRUE;
++
++ return(new);
++}
++
++void CDR_codec_free(CDR_Codec *codec)
++{
++ if(codec->release_buffer)
++ g_free(codec->buffer);
++
++ g_free(codec);
++}
+diff -urN linux-2.4.1/net/korbit/orb/cdr.h linux-2.4.1-korbit/net/korbit/orb/cdr.h
+--- linux-2.4.1/net/korbit/orb/cdr.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/cdr.h Thu Feb 1 16:22:12 2001
+@@ -0,0 +1,83 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CDR_H_
++#define _ORBIT_CDR_H_
++
++#include "orbit_types.h"
++
++typedef enum {
++ BigEndian=0,
++ LittleEndian=1
++} CDR_Endianness;
++
++typedef struct {
++ CDR_Endianness host_endian;
++ CDR_Endianness data_endian;
++ CORBA_octet *buffer;
++ unsigned int buf_len;
++ unsigned int wptr, rptr;
++ CORBA_boolean readonly;
++ CORBA_boolean release_buffer;
++} CDR_Codec;
++
++#define HEXDIGIT(c) (isdigit((guchar)(c))?(c)-'0':tolower((guchar)(c))-'a'+10)
++#define HEXOCTET(a,b) ((HEXDIGIT((a)) << 4) | HEXDIGIT((b)))
++
++extern CDR_Codec *CDR_codec_init(void);
++extern CDR_Codec *CDR_codec_init_static(CDR_Codec *codec);
++extern void CDR_codec_free(CDR_Codec *);
++
++extern void CDR_put_short(CDR_Codec *codec, CORBA_short s);
++extern void CDR_put_ushort(CDR_Codec *codec, CORBA_unsigned_short us);
++extern void CDR_put_long(CDR_Codec *codec, CORBA_long l);
++extern void CDR_put_ulong(CDR_Codec *codec, CORBA_unsigned_long ul);
++#ifdef HAVE_CORBA_LONG_LONG
++extern void CDR_put_long_long(CDR_Codec *codec, CORBA_long_long ll);
++extern void CDR_put_ulong_long(CDR_Codec *codec, CORBA_unsigned_long_long ull);
++extern CORBA_boolean CDR_get_ulong_long(CDR_Codec *codec, CORBA_unsigned_long_long *ul);
++extern CORBA_boolean CDR_get_long_long(CDR_Codec *codec, CORBA_long_long *ul);
++#endif
++extern void CDR_put_float(CDR_Codec *codec, CORBA_float f);
++extern void CDR_put_double(CDR_Codec *codec, CORBA_double d);
++extern void CDR_put_long_double(CDR_Codec *codec, CORBA_long_double ld);
++extern void CDR_put_octet(CDR_Codec *codec, CORBA_octet datum);
++extern void CDR_put_octets(CDR_Codec *codec, void *data, unsigned long len);
++extern void CDR_put_char(CDR_Codec *codec, CORBA_char c);
++extern void CDR_put_boolean(CDR_Codec *codec, CORBA_boolean datum);
++extern void CDR_put_string(CDR_Codec *codec, const char *str);
++extern CORBA_boolean CDR_buffer_gets(CDR_Codec *codec, void *dest, const unsigned int len);
++extern CORBA_boolean CDR_get_short(CDR_Codec *codec, CORBA_short *us);
++extern CORBA_boolean CDR_get_ushort(CDR_Codec *codec, CORBA_unsigned_short *us);
++extern CORBA_boolean CDR_get_long(CDR_Codec *codec, CORBA_long *l);
++extern CORBA_boolean CDR_get_ulong(CDR_Codec *codec, CORBA_unsigned_long *ul);
++extern CORBA_boolean CDR_get_octet(CDR_Codec *codec, CORBA_octet *datum);
++extern CORBA_boolean CDR_get_boolean(CDR_Codec *codec, CORBA_boolean *b);
++extern CORBA_boolean CDR_get_char(CDR_Codec *codec, CORBA_char *c);
++extern CORBA_boolean CDR_get_string(CDR_Codec *codec, CORBA_char **str);
++extern CORBA_boolean CDR_get_string_static(CDR_Codec *codec, CORBA_char **str);
++extern CORBA_boolean CDR_get_seq_begin(CDR_Codec *codec, CORBA_unsigned_long *ul);
++
++#endif /* !_ORBIT_CDR_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_any.c linux-2.4.1-korbit/net/korbit/orb/corba_any.c
+--- linux-2.4.1/net/korbit/orb/corba_any.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_any.c Thu Feb 1 11:47:10 2001
+@@ -0,0 +1,914 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Red Hat Software
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Elliot Lee <sopwith@redhat.com>
++ *
++ */
++
++#include <config.h>
++#include <IIOP/IIOP.h>
++#include "orbit.h"
++
++#if 0
++#define CORBA_Object_release(x, y) ({ g_message(__FILE__ ":%d Releasing object %#x from %d", __LINE__, \
++x, ORBIT_ROOT_OBJECT(x)->refs); CORBA_Object_release(x, y); })
++#define CORBA_Object_duplicate(x, y) ({ g_message(__FILE__ ":%d Duping object %#x from %d", __LINE__, \
++x, ORBIT_ROOT_OBJECT(x)->refs); CORBA_Object_duplicate(x, y); })
++#endif
++
++gint
++ORBit_find_alignment(CORBA_TypeCode tc)
++{
++ gint retval = 1;
++ int i;
++
++ switch(tc->kind) {
++ case CORBA_tk_union:
++ retval = MAX(retval, ORBit_find_alignment(tc->discriminator));
++ case CORBA_tk_except:
++ case CORBA_tk_struct:
++#if ALIGNOF_CORBA_STRUCT > 1
++ retval = MAX(retval, ALIGNOF_CORBA_STRUCT);
++#endif
++ for(i = 0; i < tc->sub_parts; i++)
++ retval = MAX(retval, ORBit_find_alignment(tc->subtypes[i]));
++ return retval;
++ case CORBA_tk_ulong:
++ case CORBA_tk_long:
++ case CORBA_tk_enum:
++ return ALIGNOF_CORBA_LONG;
++ case CORBA_tk_ushort:
++ case CORBA_tk_short:
++ case CORBA_tk_wchar:
++ return ALIGNOF_CORBA_SHORT;
++ case CORBA_tk_longlong:
++ case CORBA_tk_ulonglong:
++ return ALIGNOF_CORBA_LONG_LONG;
++ case CORBA_tk_longdouble:
++ return ALIGNOF_CORBA_LONG_DOUBLE;
++ case CORBA_tk_float:
++ return ALIGNOF_CORBA_FLOAT;
++ case CORBA_tk_double:
++ return ALIGNOF_CORBA_DOUBLE;
++ case CORBA_tk_boolean:
++ case CORBA_tk_char:
++ case CORBA_tk_octet:
++ return ALIGNOF_CORBA_CHAR;
++ case CORBA_tk_string:
++ case CORBA_tk_wstring:
++ case CORBA_tk_TypeCode:
++ case CORBA_tk_objref:
++ return ALIGNOF_CORBA_POINTER;
++ case CORBA_tk_sequence:
++ case CORBA_tk_any:
++ return MAX(MAX(ALIGNOF_CORBA_LONG, ALIGNOF_CORBA_STRUCT), ALIGNOF_CORBA_POINTER);
++ case CORBA_tk_array:
++ case CORBA_tk_alias:
++ return ORBit_find_alignment(tc->subtypes[0]);
++ case CORBA_tk_fixed:
++ return MAX(ALIGNOF_CORBA_SHORT, ALIGNOF_CORBA_STRUCT);
++ default:
++ return 1;
++ }
++}
++
++static void
++ORBit_marshal_value(GIOPSendBuffer *buf,
++ gpointer *val,
++ CORBA_TypeCode tc,
++ ORBit_marshal_value_info *mi)
++{
++ CORBA_unsigned_long i, ulval;
++ gpointer subval;
++ ORBit_marshal_value_info submi;
++
++#if 0
++ g_message("Marshalling a %d value from %#x to offset %d",
++ tc->kind, (gulong)*val,
++ GIOP_MESSAGE_BUFFER(buf)->message_header.message_size);
++#endif
++
++ switch(tc->kind) {
++ case CORBA_tk_wchar:
++ case CORBA_tk_ushort:
++ case CORBA_tk_short:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_SHORT);
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_short));
++ *val = ((guchar *)*val) + sizeof(CORBA_short);
++ break;
++ case CORBA_tk_enum:
++ case CORBA_tk_long:
++ case CORBA_tk_ulong:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG);
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_long));
++ *val = ((guchar *)*val) + sizeof(CORBA_long);
++ break;
++ case CORBA_tk_float:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_FLOAT);
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_float));
++ *val = ((guchar *)*val) + sizeof(CORBA_float);
++ break;
++ case CORBA_tk_double:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_DOUBLE);
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_double));
++ *val = ((guchar *)*val) + sizeof(CORBA_double);
++ break;
++ case CORBA_tk_boolean:
++ case CORBA_tk_char:
++ case CORBA_tk_octet:
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_octet));
++ *val = ((guchar *)*val) + sizeof(CORBA_octet);
++ break;
++ case CORBA_tk_any:
++ *val = ALIGN_ADDRESS(*val, MAX(ALIGNOF_CORBA_STRUCT, ALIGNOF_CORBA_POINTER));
++ ORBit_marshal_any(buf, *val);
++ *val = ((guchar *)*val) + sizeof(CORBA_any);
++ break;
++ case CORBA_tk_TypeCode:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER);
++ ORBit_encode_CORBA_TypeCode(*val, buf);
++ *val = ((guchar *)*val) + sizeof(CORBA_TypeCode);
++ break;
++ case CORBA_tk_Principal:
++ *val = ALIGN_ADDRESS(*val,
++ MAX(MAX(ALIGNOF_CORBA_LONG, ALIGNOF_CORBA_STRUCT),
++ ALIGNOF_CORBA_POINTER));
++
++ ulval = *(CORBA_unsigned_long *)(*val);
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_unsigned_long));
++
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(buf),
++ *(char**)((char *)*val+sizeof(CORBA_unsigned_long)),
++ ulval);
++ *val = ((guchar *)*val) + sizeof(CORBA_Principal);
++ break;
++ case CORBA_tk_objref:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER);
++ ORBit_marshal_object(buf, *val);
++ *val = ((guchar *)*val) + sizeof(CORBA_Object);
++ break;
++ case CORBA_tk_except:
++ case CORBA_tk_struct:
++ *val = ALIGN_ADDRESS(*val, ORBit_find_alignment(tc));
++ for(i = 0; i < tc->sub_parts; i++) {
++ ORBit_marshal_value(buf, val, tc->subtypes[i], mi);
++ }
++ break;
++ case CORBA_tk_union:
++ /* Basic algorithm:
++ marshal the discriminator
++ find out which value we want to use */
++ {
++ CORBA_TypeCode utc;
++
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_STRUCT);
++
++ utc = ORBit_get_union_tag(tc, val, TRUE);
++
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_STRUCT);
++
++ ORBit_marshal_value(buf, val, tc->discriminator, mi);
++ *val = ALIGN_ADDRESS(*val, ORBit_find_alignment(tc));
++ ORBit_marshal_value(buf, val, utc, mi);
++ }
++ break;
++ case CORBA_tk_wstring:
++ ulval = strlen(*(char **)*val) + 1;
++
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER);
++ giop_send_buffer_append_mem_indirect_a(buf,
++ &ulval,
++ sizeof(CORBA_unsigned_long));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(buf), *(char **)*val, ulval);
++
++ *val = ((guchar *)*val) + sizeof(char *);
++ break;
++ case CORBA_tk_string:
++ ulval = strlen(*(char **)*val) + 1;
++
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER);
++
++ giop_send_buffer_append_mem_indirect_a(buf,
++ &ulval,
++ sizeof(CORBA_unsigned_long));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(buf), *(char **)*val, ulval);
++
++ *val = ((guchar *)*val) + sizeof(char *);
++ break;
++ case CORBA_tk_sequence:
++ {
++ CORBA_sequence_octet *sval = *val;
++
++ *val = ALIGN_ADDRESS(*val,
++ MAX(MAX(ALIGNOF_CORBA_LONG, ALIGNOF_CORBA_STRUCT), ALIGNOF_CORBA_POINTER));
++
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf),
++ &sval->_length,
++ sizeof(sval->_length));
++
++ subval = sval->_buffer;
++
++ for(i = 0; i < sval->_length; i++)
++ ORBit_marshal_value(buf, &subval, tc->subtypes[0], mi);
++
++ *val = ((guchar *)*val) + sizeof(CORBA_sequence_octet);
++ }
++ break;
++ case CORBA_tk_array:
++ submi.alias_element_type = tc->subtypes[0];
++ for(i = 0; i < tc->length; i++) {
++ ORBit_marshal_value(buf, val, submi.alias_element_type, &submi);
++ *val = ALIGN_ADDRESS(*val, ORBit_find_alignment(tc->subtypes[0]));
++ }
++ break;
++ case CORBA_tk_alias:
++ submi.alias_element_type = tc->subtypes[0];
++ ORBit_marshal_value(buf, val, submi.alias_element_type, &submi);
++ break;
++ case CORBA_tk_longlong:
++ case CORBA_tk_ulonglong:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG_LONG);
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_long_long));
++ return /* *val + sizeof(CORBA_long_long)*/;
++ break;
++ case CORBA_tk_longdouble:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG_DOUBLE);
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_long_double));
++ return /* *val + sizeof(CORBA_long_double)*/;
++ break;
++ case CORBA_tk_fixed:
++ /* XXX todo */
++ g_error("CORBA_fixed NYI");
++
++ break;
++ case CORBA_tk_null:
++ case CORBA_tk_void:
++ break;
++ default:
++ g_error("Can't encode unknown type %d", tc->kind);
++ }
++}
++
++static glong ORBit_get_union_switch(CORBA_TypeCode tc, gpointer *val, gboolean update)
++{
++#ifdef __KORBIT__
++ glong retval = 0;
++#else
++ glong retval;
++#endif
++
++ switch(tc->kind) {
++ case CORBA_tk_ulong:
++ case CORBA_tk_long:
++ case CORBA_tk_enum:
++ retval = *(CORBA_long *)*val;
++ if(update) *val += sizeof(CORBA_long);
++ break;
++ case CORBA_tk_ushort:
++ case CORBA_tk_short:
++ retval = *(CORBA_short *)*val;
++ if(update) *val += sizeof(CORBA_short);
++ break;
++ case CORBA_tk_char:
++ case CORBA_tk_boolean:
++ case CORBA_tk_octet:
++ retval = *(CORBA_octet *)*val;
++ if(update) *val += sizeof(CORBA_char);
++ break;
++ case CORBA_tk_alias:
++ return ORBit_get_union_switch(tc->subtypes[0], val, update);
++ break;
++ default:
++ g_error("Wow, some nut has passed us a weird type[%d] as a union discriminator!", tc->kind);
++ }
++
++ return retval;
++}
++
++/* This function (and the one above it) exist for the
++ sole purpose of finding out which CORBA_TypeCode a union discriminator value
++ indicates.
++
++ If {update} is TRUE, {*val} will be advanced by the native size
++ of the descriminator type.
++
++ Hairy stuff.
++*/
++CORBA_TypeCode
++ORBit_get_union_tag(CORBA_TypeCode union_tc, gpointer *val, gboolean update)
++{
++ glong discrim_val, case_val;
++ int i;
++ CORBA_TypeCode retval = CORBA_OBJECT_NIL;
++
++ discrim_val = ORBit_get_union_switch(union_tc->discriminator, val, update);
++
++ for(i = 0; i < union_tc->sub_parts; i++) {
++ if(i == union_tc->default_index)
++ continue;
++
++ case_val = ORBit_get_union_switch(union_tc->sublabels[i]._type,
++ &union_tc->sublabels[i]._value, FALSE);
++ if(case_val == discrim_val) {
++ retval = union_tc->subtypes[i];
++ break;
++ }
++ }
++
++ if(retval)
++ return retval;
++ else if(union_tc->default_index >= 0)
++ return union_tc->subtypes[union_tc->default_index];
++ else {
++ return TC_null;
++ }
++}
++
++void
++ORBit_marshal_arg(GIOPSendBuffer *buf,
++ gpointer val,
++ CORBA_TypeCode tc)
++{
++ ORBit_marshal_value_info mi;
++
++ ORBit_marshal_value(buf, &val, tc, &mi);
++}
++
++
++void
++ORBit_marshal_any(GIOPSendBuffer *buf, const CORBA_any *val)
++{
++ ORBit_marshal_value_info mi;
++
++ gpointer mval = val->_value;
++
++ ORBit_encode_CORBA_TypeCode(val->_type, buf);
++
++ ORBit_marshal_value(buf, &mval, val->_type, &mi);
++}
++
++size_t
++ORBit_gather_alloc_info(CORBA_TypeCode tc)
++{
++ int i, n, align=1, prevalign, sum, prev;
++ size_t block_size;
++
++ switch(tc->kind) {
++ case CORBA_tk_long:
++ case CORBA_tk_ulong:
++ case CORBA_tk_enum:
++ return sizeof(CORBA_long);
++ break;
++ case CORBA_tk_short:
++ case CORBA_tk_ushort:
++ return sizeof(CORBA_short);
++ break;
++ case CORBA_tk_float:
++ return sizeof(CORBA_float);
++ break;
++ case CORBA_tk_double:
++ return sizeof(CORBA_double);
++ break;
++ case CORBA_tk_boolean:
++ case CORBA_tk_char:
++ case CORBA_tk_octet:
++ return sizeof(CORBA_octet);
++ break;
++ case CORBA_tk_any:
++ return sizeof(CORBA_any);
++ break;
++ case CORBA_tk_TypeCode:
++ return sizeof(CORBA_TypeCode);
++ break;
++ case CORBA_tk_Principal:
++ return sizeof(CORBA_Principal);
++ break;
++ case CORBA_tk_objref:
++ return sizeof(CORBA_Object);
++ break;
++ case CORBA_tk_except:
++ case CORBA_tk_struct:
++ sum = 0;
++ for(i = 0; i < tc->sub_parts; i++) {
++ sum = GPOINTER_TO_INT(ALIGN_ADDRESS(sum, ORBit_find_alignment(tc->subtypes[i])));
++ sum += ORBit_gather_alloc_info(tc->subtypes[i]);
++ }
++ sum = GPOINTER_TO_INT(ALIGN_ADDRESS(sum, ORBit_find_alignment(tc)));
++ return sum;
++ break;
++ case CORBA_tk_union:
++ sum = ORBit_gather_alloc_info(tc->discriminator);
++ n = -1;
++ align = 1;
++ for(prev = prevalign = i = 0; i < tc->sub_parts; i++) {
++ prevalign = align;
++ align = ORBit_find_alignment(tc->subtypes[i]);
++ if(align > prevalign)
++ n = i;
++
++ prev = MAX(prev, ORBit_gather_alloc_info(tc->subtypes[i]));
++ }
++ if(n >= 0)
++ sum = GPOINTER_TO_INT(ALIGN_ADDRESS(sum, ORBit_find_alignment(tc->subtypes[n])));
++ sum += prev;
++ sum = GPOINTER_TO_INT(ALIGN_ADDRESS(sum, ORBit_find_alignment(tc)));
++ return sum;
++ break;
++ case CORBA_tk_wstring:
++ case CORBA_tk_string:
++ return sizeof(char *);
++ break;
++ case CORBA_tk_sequence:
++ return sizeof(CORBA_sequence_octet);
++ break;
++ case CORBA_tk_array:
++ block_size = ORBit_gather_alloc_info(tc->subtypes[0]);
++ return block_size * tc->length;
++ break;
++ case CORBA_tk_alias:
++ return ORBit_gather_alloc_info(tc->subtypes[0]);
++ case CORBA_tk_longlong:
++ case CORBA_tk_ulonglong:
++ return sizeof(CORBA_long_long);
++ case CORBA_tk_longdouble:
++ return sizeof(CORBA_long_double);
++ case CORBA_tk_wchar:
++ return sizeof(CORBA_wchar);
++ case CORBA_tk_fixed:
++ return sizeof(CORBA_fixed_d_s);
++ default:
++ return 0;
++ }
++}
++
++/* to allocate a block, we need to know of any important data
++ contained in it.
++*/
++static gpointer
++ORBit_demarshal_allocate_mem(CORBA_TypeCode tc, gint nelements)
++{
++ size_t block_size;
++ gpointer retval = NULL;
++
++ if(!nelements) return retval;
++
++ block_size = ORBit_gather_alloc_info(tc);
++
++ if(block_size) {
++ retval = ORBit_alloc_2(block_size * nelements,
++ (ORBit_free_childvals)ORBit_free_via_TypeCode,
++ GINT_TO_POINTER(nelements),
++ sizeof(CORBA_TypeCode));
++
++ *(CORBA_TypeCode *)((char *)retval-sizeof(ORBit_mem_info)-sizeof(CORBA_TypeCode)) = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)tc, NULL);
++ }
++
++ return retval;
++}
++
++#define DM_GET_ATOM(x, n) G_STMT_START{ GIOP_RECV_BUFFER(buf)->decoder(x, (GIOP_RECV_BUFFER(buf)->cur), n); GIOP_RECV_BUFFER(buf)->cur = ((guchar *)GIOP_RECV_BUFFER(buf)->cur) + n; }G_STMT_END
++
++static void
++ORBit_demarshal_value(GIOPRecvBuffer *buf,
++ gpointer *val,
++ CORBA_TypeCode tc,
++ gboolean dup_strings,
++ CORBA_ORB orb)
++{
++ CORBA_long i, n;
++
++#if 0
++ g_message("Demarshalling a %d value from offset %d into %#x",
++ tc->kind, buf->cur - buf->message_body, (gulong)*val);
++#endif
++
++ switch(tc->kind) {
++ case CORBA_tk_short:
++ case CORBA_tk_ushort:
++ case CORBA_tk_wchar:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_SHORT);
++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_short));
++ DM_GET_ATOM(*val, sizeof(CORBA_short));
++ *val = ((guchar *)*val) + sizeof(CORBA_short);
++ break;
++ case CORBA_tk_long:
++ case CORBA_tk_ulong:
++ case CORBA_tk_enum:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG);
++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_long));
++ DM_GET_ATOM(*val, sizeof(CORBA_long));
++ *val = ((guchar *)*val) + sizeof(CORBA_long);
++ break;
++ case CORBA_tk_longlong:
++ case CORBA_tk_ulonglong:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG_LONG);
++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_long_long));
++ DM_GET_ATOM(*val, sizeof(CORBA_long_long));
++ *val = ((guchar *)*val) + sizeof(CORBA_long_long);
++ break;
++ case CORBA_tk_longdouble:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG_DOUBLE);
++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_long_double));
++ DM_GET_ATOM(*val, sizeof(CORBA_long_double));
++ *val = ((guchar *)*val) + sizeof(CORBA_long_double);
++ break;
++ case CORBA_tk_float:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_FLOAT);
++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_float));
++ DM_GET_ATOM(*val, sizeof(CORBA_float));
++ *val = ((guchar *)*val) + sizeof(CORBA_float);
++ break;
++ case CORBA_tk_double:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_DOUBLE);
++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_double));
++ DM_GET_ATOM(*val, sizeof(CORBA_double));
++ *val = ((guchar *)*val) + sizeof(CORBA_double);
++ break;
++ case CORBA_tk_boolean:
++ case CORBA_tk_char:
++ case CORBA_tk_octet:
++ DM_GET_ATOM(*val, sizeof(CORBA_octet));
++ *val = ((guchar *)*val) + sizeof(CORBA_octet);
++ break;
++ case CORBA_tk_any:
++ {
++ CORBA_any *decoded;
++
++ *val = ALIGN_ADDRESS(*val,
++ MAX(ALIGNOF_CORBA_LONG,
++ MAX(ALIGNOF_CORBA_POINTER, ALIGNOF_CORBA_STRUCT)));
++ decoded = *val;
++ decoded->_release = CORBA_FALSE;
++ ORBit_demarshal_any(buf, decoded, dup_strings, orb);
++ *val = ((guchar *)*val) + sizeof(CORBA_any);
++ }
++ break;
++ case CORBA_tk_TypeCode:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER);
++ ORBit_decode_CORBA_TypeCode(*val, buf);
++ CORBA_Object_duplicate(*(CORBA_Object *)*val, NULL);
++ *val = ((guchar *)*val) + sizeof(CORBA_TypeCode);
++ break;
++ case CORBA_tk_Principal:
++ {
++ CORBA_Principal *p;
++
++ *val = ALIGN_ADDRESS(*val, MAX(ALIGNOF_CORBA_STRUCT,
++ MAX(ALIGNOF_CORBA_LONG, ALIGNOF_CORBA_POINTER)));
++
++ p = *val;
++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_long));
++ CORBA_sequence_set_release(p, dup_strings);
++ DM_GET_ATOM(&p->_length, sizeof(CORBA_long));
++ p->_buffer = ORBit_alloc(p->_length, NULL, GINT_TO_POINTER(1));
++ memcpy(p->_buffer, buf->cur, p->_length);
++ buf->cur = ((guchar *)buf->cur) + p->_length;
++ *val = ((guchar *)*val) + sizeof(CORBA_sequence_octet);
++ }
++ break;
++ case CORBA_tk_objref:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER);
++ *(CORBA_Object *)*val = ORBit_demarshal_object(buf, orb);
++ *val = ((guchar *)*val) + sizeof(CORBA_Object);
++ break;
++ case CORBA_tk_except:
++ case CORBA_tk_struct:
++ *val = ALIGN_ADDRESS(*val, ORBit_find_alignment(tc));
++ for(i = 0; i < tc->sub_parts; i++) {
++ ORBit_demarshal_value(buf, val, tc->subtypes[i], dup_strings, orb);
++ }
++ break;
++ case CORBA_tk_union:
++ {
++ gpointer discrimptr;
++
++ discrimptr = *val = ALIGN_ADDRESS(*val, ORBit_find_alignment(tc));
++ ORBit_demarshal_value(buf, val, tc->discriminator, dup_strings, orb);
++ n = 1;
++ for(i = 0; i < tc->sub_parts; i++) {
++ n = MAX(n, ORBit_find_alignment(tc->subtypes[i]));
++ }
++ *val = ALIGN_ADDRESS(*val, n);
++ ORBit_demarshal_value(buf, val,
++ ORBit_get_union_tag(tc, &discrimptr, FALSE),
++ dup_strings, orb);
++ }
++ break;
++ case CORBA_tk_string:
++ case CORBA_tk_wstring:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER);
++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_long));
++ DM_GET_ATOM(&i, sizeof(CORBA_long));
++ if(dup_strings)
++ *(char **)*val = CORBA_string_dup(buf->cur);
++ else
++ *(char **)*val = buf->cur;
++ *val = ((guchar *)*val) + sizeof(CORBA_char *);
++ buf->cur = (gpointer)((char *)buf->cur + i);
++ break;
++ case CORBA_tk_sequence:
++ {
++ CORBA_sequence_octet *p;
++ gpointer subval;
++
++ *val = ALIGN_ADDRESS(*val, MAX(ALIGNOF_CORBA_STRUCT,
++ MAX(ALIGNOF_CORBA_LONG, ALIGNOF_CORBA_POINTER)));
++ p = *val;
++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_long));
++ DM_GET_ATOM(&p->_length, sizeof(CORBA_long));
++ if(tc->subtypes[0]->kind == CORBA_tk_octet
++ || tc->subtypes[0]->kind == CORBA_tk_boolean
++ || tc->subtypes[0]->kind == CORBA_tk_char) {
++ /* This special-casing could be taken further to apply to
++ all atoms... */
++ p->_buffer = ORBit_alloc(p->_length, NULL, GINT_TO_POINTER(1));
++ memcpy(p->_buffer, buf->cur, p->_length);
++ buf->cur = ((guchar *)buf->cur) + p->_length;
++ } else {
++ p->_buffer = ORBit_demarshal_allocate_mem(tc->subtypes[0],
++ p->_length);
++ subval = p->_buffer;
++
++ for(i = 0; i < p->_length; i++)
++ ORBit_demarshal_value(buf, &subval,
++ tc->subtypes[0],
++ dup_strings,
++ orb);
++ }
++
++ *val = ((guchar *)*val) + sizeof(CORBA_sequence_octet);
++ }
++ break;
++ case CORBA_tk_array:
++ for(i = 0; i < tc->length; i++)
++ ORBit_demarshal_value(buf, val, tc->subtypes[0], dup_strings, orb);
++ break;
++ case CORBA_tk_alias:
++ ORBit_demarshal_value(buf, val, tc->subtypes[0], dup_strings, orb);
++ break;
++ case CORBA_tk_fixed:
++ g_error("CORBA_fixed NYI");
++ break;
++ default:
++ break;
++ }
++}
++
++gpointer
++ORBit_demarshal_arg(GIOPRecvBuffer *buf,
++ CORBA_TypeCode tc,
++ gboolean dup_strings,
++ CORBA_ORB orb)
++{
++ gpointer retval, val;
++
++ retval = val = ORBit_demarshal_allocate_mem(tc, 1);
++
++ ORBit_demarshal_value(buf, &val, tc, dup_strings, orb);
++
++ return retval;
++}
++
++void
++ORBit_demarshal_any(GIOPRecvBuffer *buf, CORBA_any *retval,
++ gboolean dup_strings,
++ CORBA_ORB orb)
++{
++ gpointer val;
++
++#if 0
++ /* I wish I knew whether this was correct or not. It breaks things like 'any anop();' for sure,
++ since we can't always initialize every single possible 'any' underneath _ORBIT_retval */
++ if(retval->_release)
++ CORBA_free(retval->_value);
++#endif
++
++ CORBA_any_set_release(retval, CORBA_TRUE);
++
++ ORBit_decode_CORBA_TypeCode(&retval->_type, buf);
++ CORBA_Object_duplicate((CORBA_Object)retval->_type, NULL);
++
++ val = retval->_value = ORBit_demarshal_allocate_mem(retval->_type, 1);
++ ORBit_demarshal_value(buf, &val, retval->_type, dup_strings, orb);
++}
++
++void
++_ORBit_copy_value(gpointer *val, gpointer *newval, CORBA_TypeCode tc)
++{
++ CORBA_long i;
++ gpointer pval1, pval2;
++
++ switch(tc->kind) {
++ case CORBA_tk_wchar:
++ case CORBA_tk_short:
++ case CORBA_tk_ushort:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_SHORT);
++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_SHORT);
++ *(CORBA_short *)*newval = *(CORBA_short *)*val;
++ *val = ((guchar *)*val) + sizeof(CORBA_short);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_short);
++ break;
++ case CORBA_tk_enum:
++ case CORBA_tk_long:
++ case CORBA_tk_ulong:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG);
++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_LONG);
++ *(CORBA_long *)*newval = *(CORBA_long *)*val;
++ *val = ((guchar *)*val) + sizeof(CORBA_long);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_long);
++ break;
++ case CORBA_tk_longlong:
++ case CORBA_tk_ulonglong:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG_LONG);
++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_LONG_LONG);
++ *(CORBA_long_long *)*newval = *(CORBA_long_long *)*val;
++ *val = ((guchar *)*val) + sizeof(CORBA_long_long);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_long_long);
++ break;
++ case CORBA_tk_longdouble:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG_DOUBLE);
++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_LONG_DOUBLE);
++ *(CORBA_long_double *)*newval = *(CORBA_long_double *)*val;
++ *val = ((guchar *)*val) + sizeof(CORBA_long_double);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_long_double);
++ break;
++ case CORBA_tk_float:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_FLOAT);
++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_FLOAT);
++ *(CORBA_long *)*newval = *(CORBA_long *)*val;
++ *val = ((guchar *)*val) + sizeof(CORBA_float);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_float);
++ break;
++ case CORBA_tk_double:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_DOUBLE);
++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_DOUBLE);
++ *(CORBA_double *)*newval = *(CORBA_double *)*val;
++ *val = ((guchar *)*val) + sizeof(CORBA_double);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_double);
++ break;
++ case CORBA_tk_boolean:
++ case CORBA_tk_char:
++ case CORBA_tk_octet:
++ *(CORBA_octet *)*newval = *(CORBA_octet *)*val;
++ *val = ((guchar *)*val) + sizeof(CORBA_octet);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_octet);
++ break;
++ case CORBA_tk_any:
++ {
++ CORBA_any *oldany, *newany;
++ *val = ALIGN_ADDRESS(*val, MAX(ALIGNOF_CORBA_STRUCT, ALIGNOF_CORBA_POINTER));
++ *newval = ALIGN_ADDRESS(*newval, MAX(ALIGNOF_CORBA_STRUCT, ALIGNOF_CORBA_POINTER));
++ oldany = *val;
++ newany = *newval;
++ newany->_type = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)oldany->_type, NULL);
++ /* XXX are we supposed to do this even if oldany->_release
++ == FALSE? */
++ newany->_value = ORBit_copy_value(oldany->_value, oldany->_type);
++ newany->_release = CORBA_TRUE;
++ *val = ((guchar *)*val) + sizeof(CORBA_any);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_any);
++ }
++ break;
++ case CORBA_tk_Principal:
++ *val = ALIGN_ADDRESS(*val,
++ MAX(MAX(ALIGNOF_CORBA_LONG,
++ ALIGNOF_CORBA_STRUCT),
++ ALIGNOF_CORBA_POINTER));
++ *newval = ALIGN_ADDRESS(*newval,
++ MAX(MAX(ALIGNOF_CORBA_LONG,
++ ALIGNOF_CORBA_STRUCT),
++ ALIGNOF_CORBA_POINTER));
++ *(CORBA_Principal *)*newval = *(CORBA_Principal *)*val;
++ ((CORBA_Principal *)*newval)->_buffer =
++ CORBA_octet_allocbuf(((CORBA_Principal *)*newval)->_length);
++ memcpy(((CORBA_Principal *)*newval)->_buffer,
++ ((CORBA_Principal *)*val)->_buffer,
++ ((CORBA_Principal *)*val)->_length);
++ *val = ((guchar *)*val) + sizeof(CORBA_Principal);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_Principal);
++ break;
++ case CORBA_tk_TypeCode:
++ case CORBA_tk_objref:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER);
++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_POINTER);
++ *(CORBA_Object *)*newval = CORBA_Object_duplicate(*(CORBA_Object *)*val,
++ NULL);
++ *val = ((guchar *)*val) + sizeof(CORBA_Object);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_Object);
++ break;
++ case CORBA_tk_struct:
++ case CORBA_tk_except:
++ *val = ALIGN_ADDRESS(*val, ORBit_find_alignment(tc));
++ *newval = ALIGN_ADDRESS(*newval, ORBit_find_alignment(tc));
++ for(i = 0; i < tc->sub_parts; i++) {
++ _ORBit_copy_value(val, newval, tc->subtypes[i]);
++ }
++ break;
++ case CORBA_tk_union:
++ {
++ CORBA_TypeCode utc = ORBit_get_union_tag(tc, val, FALSE);
++ gint union_align = ORBit_find_alignment(tc);
++ size_t union_size = ORBit_gather_alloc_info(tc);
++
++ /* need to advance val,newval by size of union, not just
++ * current tagged field within it */
++ pval1 = *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_STRUCT);
++ pval2 = *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_STRUCT);
++ _ORBit_copy_value(&pval1, &pval2, tc->discriminator);
++ pval1 = ALIGN_ADDRESS(pval1, union_align);
++ pval2 = ALIGN_ADDRESS(pval2, union_align);
++ _ORBit_copy_value(&pval1, &pval2, utc);
++ *val = ((guchar *)*val) + union_size;
++ *newval = ((guchar *)*newval) + union_size;
++ }
++ break;
++ case CORBA_tk_wstring:
++ case CORBA_tk_string:
++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER);
++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_POINTER);
++
++ *(CORBA_char **)*newval = CORBA_string_dup(*(CORBA_char **)*val);
++ *val = ((guchar *)*val) + sizeof(CORBA_char *);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_char *);
++ break;
++ case CORBA_tk_sequence:
++ *val = ALIGN_ADDRESS(*val,
++ MAX(MAX(ALIGNOF_CORBA_LONG,
++ ALIGNOF_CORBA_STRUCT),
++ ALIGNOF_CORBA_POINTER));
++ *newval = ALIGN_ADDRESS(*newval,
++ MAX(MAX(ALIGNOF_CORBA_LONG,
++ ALIGNOF_CORBA_STRUCT),
++ ALIGNOF_CORBA_POINTER));
++ ((CORBA_Principal *)*newval)->_release = CORBA_TRUE;
++ ((CORBA_Principal *)*newval)->_length =
++ ((CORBA_Principal *)*newval)->_maximum =
++ ((CORBA_Principal *)*val)->_length;
++ ((CORBA_Principal *)*newval)->_buffer = pval2 =
++ ORBit_demarshal_allocate_mem(tc->subtypes[0],
++ ((CORBA_Principal *)*val)->_length);
++ pval1 = ((CORBA_Principal *)*val)->_buffer;
++
++ for(i = 0; i < ((CORBA_Principal *)*newval)->_length; i++) {
++ _ORBit_copy_value(&pval1, &pval2, tc->subtypes[0]);
++ }
++ *val = ((guchar *)*val) + sizeof(CORBA_sequence_octet);
++ *newval = ((guchar *)*newval) + sizeof(CORBA_sequence_octet);
++ break;
++ case CORBA_tk_array:
++ for(i = 0; i < tc->length; i++) {
++ _ORBit_copy_value(val, newval, tc->subtypes[0]);
++ }
++ break;
++ case CORBA_tk_alias:
++ _ORBit_copy_value(val, newval, tc->subtypes[0]);
++ break;
++ case CORBA_tk_fixed:
++ g_error("CORBA_fixed NYI!");
++ break;
++ case CORBA_tk_void:
++ case CORBA_tk_null:
++ *val = NULL;
++ break;
++ default:
++ g_error("Can't handle copy of value kind %d", tc->kind);
++ }
++}
++
++gpointer
++ORBit_copy_value(gpointer value, CORBA_TypeCode tc)
++{
++ gpointer retval, newval;
++
++ retval = newval = ORBit_demarshal_allocate_mem(tc, 1);
++ _ORBit_copy_value(&value, &newval, tc);
++
++ return retval;
++}
++
++void
++CORBA_any__copy(CORBA_any *out, CORBA_any *in)
++{
++ out->_type = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)in->_type,
++ NULL);
++ out->_value = ORBit_copy_value(in->_value, in->_type);
++ out->_release = CORBA_TRUE;
++}
+diff -urN linux-2.4.1/net/korbit/orb/corba_any.h linux-2.4.1-korbit/net/korbit/orb/corba_any.h
+--- linux-2.4.1/net/korbit/orb/corba_any.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_any.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,45 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_ANY_H_
++#define _ORBIT_CORBA_ANY_H_
++
++#include "orbit_types.h"
++#include "corba_typecode.h"
++
++#include <unistd.h>
++
++typedef struct CORBA_any_type CORBA_any;
++
++size_t ORBit_gather_alloc_info(CORBA_TypeCode tc);
++gint ORBit_find_alignment(CORBA_TypeCode tc);
++CORBA_TypeCode ORBit_get_union_tag(CORBA_TypeCode union_tc,
++ gpointer *val, gboolean update);
++gpointer ORBit_copy_value(gpointer value, CORBA_TypeCode tc);
++void _ORBit_copy_value(gpointer *val, gpointer *newval, CORBA_TypeCode tc);
++
++void CORBA_any__copy(CORBA_any *out, CORBA_any *in);
++
++#endif /* !_ORBIT_CORBA_ANY_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_any_proto.h linux-2.4.1-korbit/net/korbit/orb/corba_any_proto.h
+--- linux-2.4.1/net/korbit/orb/corba_any_proto.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_any_proto.h Thu Feb 1 11:47:11 2001
+@@ -0,0 +1,16 @@
++#ifndef _ORBIT_CORBA_ANY_PROTO_H_
++#define _ORBIT_CORBA_ANY_PROTO_H_
++
++void ORBit_marshal_arg(GIOPSendBuffer *buf,
++ gpointer val,
++ CORBA_TypeCode tc);
++void ORBit_marshal_any(GIOPSendBuffer *buf, const CORBA_any *val);
++gpointer ORBit_demarshal_arg(GIOPRecvBuffer *buf,
++ CORBA_TypeCode tc,
++ gboolean dup_strings,
++ CORBA_ORB orb);
++void ORBit_demarshal_any(GIOPRecvBuffer *buf, CORBA_any *retval,
++ gboolean dup_strings,
++ CORBA_ORB orb);
++
++#endif /* !_ORBIT_CORBA_ANY_PROTO_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_any_type.h linux-2.4.1-korbit/net/korbit/orb/corba_any_type.h
+--- linux-2.4.1/net/korbit/orb/corba_any_type.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_any_type.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,48 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@acm.org>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_ANY_TYPE_H_
++#define _ORBIT_CORBA_ANY_TYPE_H_
++
++#include "corba_any.h"
++#include "corba_typecode.h"
++
++struct CORBA_any_type {
++ CORBA_TypeCode _type;
++ gpointer _value;
++ CORBA_boolean _release;
++};
++
++typedef struct ORBit_marshal_value_info_struct {
++ CORBA_TypeCode alias_element_type;
++} ORBit_marshal_value_info;
++
++#define CORBA_ANYFLAGS_RELEASE 1
++
++
++#endif /* !_ORBIT_CORBA_ANY_TYPE_H_ */
++
++
++
+diff -urN linux-2.4.1/net/korbit/orb/corba_basic_sequences_type.h linux-2.4.1-korbit/net/korbit/orb/corba_basic_sequences_type.h
+--- linux-2.4.1/net/korbit/orb/corba_basic_sequences_type.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_basic_sequences_type.h Thu Feb 1 11:47:11 2001
+@@ -0,0 +1,43 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_BASIC_SEQUENCES_TYPE_H_
++#define _ORBIT_CORBA_BASIC_SEQUENCES_TYPE_H_
++
++#include <ORBitutil/basic_types.h>
++
++#ifndef _CORBA_sequence_octet_defined
++#define _CORBA_sequence_octet_defined 1
++
++typedef struct CORBA_sequence_octet_struct {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ CORBA_octet *_buffer;
++ CORBA_boolean _release;
++} CORBA_sequence_octet;
++#endif /* !_CORBA_sequence_octet_defined */
++
++#include <orb/corba_sequences.h>
++#endif /* !_ORBIT_CORBA_BASIC_SEQUENCES_TYPE_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_context.c linux-2.4.1-korbit/net/korbit/orb/corba_context.c
+--- linux-2.4.1/net/korbit/orb/corba_context.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_context.c Thu Feb 1 11:47:11 2001
+@@ -0,0 +1,390 @@
++#include "orb/orbit.h"
++
++#define o_return_val_if_fail(expr, val) if(!(expr)) { CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM, CORBA_COMPLETED_NO); return (val); }
++#define o_return_if_fail(expr) if(!(expr)) { CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM, CORBA_COMPLETED_NO); return; }
++
++static gboolean
++free_entry(gpointer key, gpointer value, gpointer user_data)
++{
++ g_free(key);
++ g_free(value);
++
++ return TRUE;
++}
++
++static void
++ORBit_Context_release(CORBA_Context ctx, CORBA_Environment *ev);
++
++static gboolean
++free_child(gpointer value, gpointer user_data)
++{
++ CORBA_Context ctx = value;
++
++ ORBIT_ROOT_OBJECT(ctx)->refs = 1;
++ ctx->parent_ctx = CORBA_OBJECT_NIL;
++ ORBit_Context_release(ctx, NULL);
++
++ return TRUE;
++}
++
++static void
++ORBit_Context_release(CORBA_Context ctx,
++ CORBA_Environment *ev)
++{
++ ORBIT_ROOT_OBJECT_UNREF(ctx);
++
++ if(ORBIT_ROOT_OBJECT(ctx)->refs <= 0) {
++ if(ctx->children) {
++ g_slist_foreach(ctx->children, (GFunc)free_child, ctx);
++ g_slist_free(ctx->children);
++ }
++
++ if(ctx->mappings) {
++ g_hash_table_foreach_remove(ctx->mappings, free_entry, ctx);
++ g_hash_table_destroy(ctx->mappings);
++ }
++
++ if(ctx->parent_ctx != CORBA_OBJECT_NIL)
++ ctx->parent_ctx->children = g_slist_remove(ctx->parent_ctx->children, ctx->the_name);
++
++ g_free(ctx->the_name);
++
++ g_free(ctx);
++ }
++}
++
++static const ORBit_RootObject_Interface CORBA_Context_epv =
++{
++ (void (*)(gpointer, CORBA_Environment *))ORBit_Context_release,
++};
++
++static CORBA_Context
++CORBA_Context_new(CORBA_Context parent, const char *name, CORBA_Environment *ev)
++{
++ CORBA_Context retval;
++
++ retval = g_new0(struct CORBA_Context_type, 1);
++
++ ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(retval), ORBIT_PSEUDO_CONTEXT, ev);
++
++ ORBIT_ROOT_OBJECT(retval)->refs = 0;
++ ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(retval), (gpointer)&CORBA_Context_epv, ev);
++
++ if(name)
++ retval->the_name = g_strdup(name);
++
++ retval->parent_ctx = parent;
++ if(parent)
++ parent->children = g_slist_prepend(parent->children, retval);
++
++ return retval;
++}
++
++/* Section 5.6.1 */
++CORBA_Status CORBA_ORB_get_default_context(CORBA_ORB orb, CORBA_Context *ctx, CORBA_Environment *ev)
++{
++ g_return_if_fail(ev != NULL);
++ o_return_if_fail(orb && ctx);
++
++ if(!orb->default_ctx)
++ orb->default_ctx = CORBA_Context_new(CORBA_OBJECT_NIL, NULL, ev);
++
++ *ctx = (CORBA_Context)CORBA_Object_duplicate((CORBA_Object)orb->default_ctx, ev);
++}
++
++/********* XXX todo - CORBA_Context support */
++CORBA_Status CORBA_Context_set_one_value(CORBA_Context ctx, CORBA_Identifier prop_name, char *value, CORBA_Environment *ev)
++{
++ gpointer old_nom, old_value;
++ g_return_if_fail(ev != NULL);
++ o_return_if_fail(ctx && prop_name && value);
++
++ if(!ctx->mappings)
++ ctx->mappings = g_hash_table_new(g_str_hash, g_str_equal);
++
++ if(g_hash_table_lookup_extended(ctx->mappings, prop_name, &old_nom, &old_value)) {
++ g_free(old_nom);
++ g_free(old_value);
++ }
++
++ g_hash_table_insert(ctx->mappings, g_strdup(prop_name), g_strdup(value));
++}
++
++/* Section 5.6.3 */
++CORBA_Status CORBA_Context_set_values(CORBA_Context ctx, CORBA_NVList *values, CORBA_Environment *ev)
++{
++ int i;
++
++ for(i = 0; i < values->list->len; i++) {
++ CORBA_NamedValue *nvp;
++
++ nvp = ((CORBA_NamedValue *)values->list->data) + i;
++
++ g_assert(nvp->argument._type == TC_string);
++
++ CORBA_Context_set_one_value(ctx, nvp->name, nvp->argument._value, ev);
++ }
++}
++
++/* Section 5.6.4 */
++
++typedef struct {
++ CORBA_Context ctx;
++ CORBA_Identifier prop_name;
++ CORBA_NVList *values;
++ CORBA_Environment *ev;
++ int len;
++} CTXSearchInfo;
++
++static gboolean
++list_has_key(CORBA_NVList *list, const char *key)
++{
++ int i;
++
++ for(i = 0; i < list->list->len; i++) {
++ CORBA_NamedValue *nvp;
++
++ nvp = ((CORBA_NamedValue *)list->list->data) + i;
++
++ if(!strcmp(nvp->name, key))
++ return TRUE;
++ }
++
++ return FALSE;
++}
++
++static void
++search_props(gpointer key, gpointer value, CTXSearchInfo *csi)
++{
++ if(strncmp(key, csi->prop_name, csi->len))
++ return;
++
++ if(list_has_key(csi->values, key))
++ return;
++
++ CORBA_NVList_add_item(csi->values, key, TC_string, &value, strlen(value) + 1, CORBA_IN_COPY_VALUE, NULL);
++}
++
++static void
++ctx_get_values(CORBA_Context ctx, CORBA_Flags op_flags,
++ CORBA_Identifier prop_name, CORBA_NVList **values,
++ gint is_wc,
++ CORBA_Environment *ev)
++{
++ gboolean go_up = FALSE;
++
++ if(is_wc >= 0) {
++ CTXSearchInfo csi;
++
++ csi.ctx = ctx;
++ csi.prop_name = prop_name;
++ csi.values = *values;
++ csi.ev = ev;
++ csi.len = is_wc;
++
++ if(ctx->mappings)
++ g_hash_table_foreach(ctx->mappings, (GHFunc)search_props, &csi);
++
++ go_up = TRUE;
++
++ } else {
++ char *val = NULL;
++
++ if(ctx->mappings)
++ val = g_hash_table_lookup(ctx->mappings, prop_name);
++
++ if(val)
++ CORBA_NVList_add_item(*values, prop_name, TC_string, &val, strlen(val) + 1, CORBA_IN_COPY_VALUE, ev);
++ else
++ go_up = TRUE;
++ }
++
++ if(go_up
++ && ctx->parent_ctx
++ && !(op_flags & CORBA_CTX_RESTRICT_SCOPE))
++ ctx_get_values(ctx->parent_ctx, op_flags, prop_name, values, is_wc, ev);
++}
++
++CORBA_Status CORBA_Context_get_values(CORBA_Context ctx,
++ CORBA_Identifier start_scope,
++ CORBA_Flags op_flags,
++ CORBA_Identifier prop_name,
++ CORBA_NVList **values,
++ CORBA_Environment *ev)
++{
++ char *ctmp;
++ int wc_pos;
++
++ CORBA_ORB_create_list(CORBA_OBJECT_NIL, 0, values, ev);
++
++ if(start_scope && *start_scope) {
++ while(ctx && (!ctx->the_name || strcmp(ctx->the_name, start_scope)))
++ ctx = ctx->parent_ctx;
++
++ if(!ctx) {
++ CORBA_exception_set_system(ev, ex_CORBA_INV_IDENT, CORBA_COMPLETED_NO);
++ return;
++ }
++ }
++
++ ctmp = strchr(prop_name, '*');
++ if(ctmp)
++ wc_pos = ctmp - prop_name;
++ else
++ wc_pos = -1;
++
++ CORBA_ORB_create_list(CORBA_OBJECT_NIL, 0, values, ev);
++
++ ctx_get_values(ctx, op_flags, prop_name, values, (prop_name[strlen(prop_name) - 1] == '*'), ev);
++
++ if((*values)->list->len == 0)
++ {
++ CORBA_NVList_free(*values, ev);
++ *values = NULL;
++ CORBA_exception_set_system(ev, ex_CORBA_UNKNOWN, CORBA_COMPLETED_NO);
++ }
++}
++
++/* Section 5.6.5 */
++static void
++delete_props(gpointer key, gpointer value, CTXSearchInfo *csi)
++{
++ if(strncmp(key, csi->prop_name, csi->len))
++ return;
++
++ g_hash_table_remove(csi->ctx->mappings, key);
++ g_free(key);
++ g_free(value);
++}
++
++CORBA_Status CORBA_Context_delete_values(CORBA_Context ctx, CORBA_Identifier prop_name, CORBA_Environment *ev)
++{
++ char *ctmp;
++ int wc_pos;
++
++ if(!ctx->mappings)
++ return;
++
++ ctmp = strchr(prop_name, '*');
++ if(ctmp)
++ wc_pos = ctmp - prop_name;
++ else
++ wc_pos = -1;
++
++ if(wc_pos >= 0) {
++ CTXSearchInfo csi;
++
++ memset(&csi, 0, sizeof(csi));
++ csi.ctx = ctx;
++ csi.prop_name = prop_name;
++ csi.ev = ev;
++ csi.len = wc_pos;
++
++ g_hash_table_foreach(ctx->mappings, (GHFunc)delete_props, &csi);
++ } else {
++ gpointer old_nom, old_value;
++
++ if(g_hash_table_lookup_extended(ctx->mappings, prop_name, &old_nom, &old_value)) {
++ g_free(old_nom);
++ g_free(old_value);
++ }
++ }
++}
++
++/* Section 5.6.6 */
++CORBA_Status CORBA_Context_create_child(CORBA_Context ctx, CORBA_Identifier ctx_name, CORBA_Context *child_ctx, CORBA_Environment *ev)
++{
++ *child_ctx = CORBA_Context_new(ctx, ctx_name, ev);
++}
++
++/* Section 5.6.7 */
++CORBA_Status CORBA_Context_delete(CORBA_Context ctx, CORBA_Flags del_flags, CORBA_Environment *ev)
++{
++ if((del_flags & CORBA_CTX_DELETE_DESCENDENTS)
++ || !ctx->children)
++ free_child(ctx, NULL);
++}
++
++void
++ORBit_Context_marshal(CORBA_Context ctx, const ORBit_ContextMarshalItem *mlist, CORBA_unsigned_long nitems, GIOPSendBuffer *buf)
++{
++ int i;
++ CORBA_unsigned_long *real_nitems, ltmp;
++
++ real_nitems = giop_send_buffer_append_mem_indirect_a(buf, &nitems, sizeof(nitems));
++ if(!ctx->mappings) {
++ *real_nitems = 0;
++ return;
++ }
++
++ for(*real_nitems = i = 0; i < nitems; i++) {
++ char *value;
++
++ value = g_hash_table_lookup(ctx->mappings, mlist[i].str);
++ if(!value)
++ continue;
++
++ /* Key */
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), &(mlist[i].len), sizeof(mlist[i].len));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(buf), mlist[i].str, mlist[i].len);
++ (*real_nitems)++;
++
++ /* Value */
++ ltmp = strlen(value) + 1;
++ giop_send_buffer_append_mem_indirect_a(buf, &ltmp, sizeof(ltmp));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(buf), value, ltmp);
++ (*real_nitems)++;
++ }
++}
++
++#define GET_ATOM(x) G_STMT_START{ GIOP_RECV_BUFFER(recv_buffer)->decoder(&x, (GIOP_RECV_BUFFER(recv_buffer)->cur), sizeof(x)); \
++GIOP_RECV_BUFFER(recv_buffer)->cur = ((guchar *)GIOP_RECV_BUFFER(recv_buffer)->cur) + sizeof(x); \
++}G_STMT_END
++#define ALIGNFOR(x) recv_buffer->cur = ALIGN_ADDRESS(recv_buffer->cur, sizeof(x))
++
++void
++ORBit_Context_demarshal(CORBA_Context parent, CORBA_Context initme, GIOPRecvBuffer *recv_buffer)
++{
++ CORBA_unsigned_long nstrings, keylen, vallen, i;
++ char *key, *value;
++
++ memset(initme, 0, sizeof(struct CORBA_Context_type));
++ ORBIT_ROOT_OBJECT(initme)->refs = -1;
++
++ initme->parent_ctx = parent;
++
++ ALIGNFOR(nstrings);
++ GET_ATOM(nstrings);
++
++ if(nstrings)
++ initme->mappings = g_hash_table_new(g_str_hash, g_str_equal);
++ else
++ return;
++
++ g_hash_table_freeze(initme->mappings);
++ for(i = 0; i < nstrings; ) {
++ ALIGNFOR(keylen);
++ GET_ATOM(keylen);
++ key = recv_buffer->cur;
++ recv_buffer->cur = ((char *)recv_buffer->cur) + keylen;
++ i++;
++
++ if(i >= nstrings)
++ break;
++
++ ALIGNFOR(vallen);
++ GET_ATOM(vallen);
++ value = recv_buffer->cur;
++ recv_buffer->cur = ((char *)recv_buffer->cur) + vallen;
++ i++;
++
++ g_hash_table_insert(initme->mappings, key, value);
++ }
++ g_hash_table_thaw(initme->mappings);
++}
++
++void
++ORBit_Context_server_free(CORBA_Context ctx)
++{
++ g_hash_table_destroy(ctx->mappings);
++}
+diff -urN linux-2.4.1/net/korbit/orb/corba_context.h linux-2.4.1-korbit/net/korbit/orb/corba_context.h
+--- linux-2.4.1/net/korbit/orb/corba_context.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_context.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,65 @@
++#ifndef CORBA_CONTEXT_H
++#define CORBA_CONTEXT_H 1
++
++#include "orbit_object_type.h"
++#include "orbit_object.h"
++
++typedef struct {
++ CORBA_unsigned_long len;
++ const CORBA_char *str;
++} ORBit_ContextMarshalItem;
++
++typedef struct CORBA_Context_type *CORBA_Context;
++
++struct CORBA_Context_type {
++ struct ORBit_PseudoObject_struct parent;
++ GHashTable *mappings;
++ GSList *children;
++
++ char *the_name;
++
++ CORBA_Context parent_ctx;
++};
++
++
++extern CORBA_Status CORBA_Context_set_one_value(
++ CORBA_Context ctx,
++ CORBA_Identifier prop_name,
++ char *value,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_Context_set_values(
++ CORBA_Context ctx,
++ CORBA_NVList *values,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_Context_get_values(
++ CORBA_Context ctx,
++ CORBA_Identifier start_scope,
++ CORBA_Flags op_flags,
++ CORBA_Identifier prop_name,
++ CORBA_NVList **values,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_Context_delete_values(
++ CORBA_Context ctx,
++ CORBA_Identifier prop_name,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_Context_create_child(
++ CORBA_Context ctx,
++ CORBA_Identifier ctx_name,
++ CORBA_Context *child_ctx,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_Context_delete(
++ CORBA_Context ctx,
++ CORBA_Flags del_flags,
++ CORBA_Environment *ev);
++
++void ORBit_Context_marshal(CORBA_Context ctx, const ORBit_ContextMarshalItem *mlist,
++ CORBA_unsigned_long nitems, GIOPSendBuffer *buf);
++void ORBit_Context_demarshal(CORBA_Context parent, CORBA_Context initme, GIOPRecvBuffer *recv_buffer);
++void ORBit_Context_server_free(CORBA_Context ctx);
++
++#endif
+diff -urN linux-2.4.1/net/korbit/orb/corba_env.h linux-2.4.1-korbit/net/korbit/orb/corba_env.h
+--- linux-2.4.1/net/korbit/orb/corba_env.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_env.h Thu Feb 1 11:47:11 2001
+@@ -0,0 +1,79 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_ENV_H_
++#define _ORBIT_CORBA_ENV_H_
++
++typedef struct CORBA_Environment_type CORBA_Environment;
++
++/* 3.15 */
++typedef enum {
++ CORBA_COMPLETED_YES=0,
++ CORBA_COMPLETED_NO,
++ CORBA_COMPLETED_MAYBE
++} CORBA_completion_status;
++
++typedef enum {
++ CORBA_NO_EXCEPTION=0,
++ CORBA_USER_EXCEPTION,
++ CORBA_SYSTEM_EXCEPTION
++} CORBA_exception_type;
++
++
++#define ex_CORBA_UNKNOWN 1
++#define ex_CORBA_BAD_PARAM 2
++#define ex_CORBA_NO_MEMORY 3
++#define ex_CORBA_IMP_LIMIT 4
++#define ex_CORBA_COMM_FAILURE 5
++#define ex_CORBA_INV_OBJREF 6
++#define ex_CORBA_NO_PERMISSION 7
++#define ex_CORBA_INTERNAL 8
++#define ex_CORBA_MARSHAL 9
++#define ex_CORBA_INITIALIZE 10
++#define ex_CORBA_NO_IMPLEMENT 11
++#define ex_CORBA_BAD_TYPECODE 12
++#define ex_CORBA_BAD_OPERATION 13
++#define ex_CORBA_NO_RESOURCES 14
++#define ex_CORBA_NO_RESPONSE 15
++#define ex_CORBA_PERSIST_STORE 16
++#define ex_CORBA_BAD_INV_ORDER 17
++#define ex_CORBA_TRANSIENT 18
++#define ex_CORBA_FREE_MEM 19
++#define ex_CORBA_INV_IDENT 20
++#define ex_CORBA_INV_FLAG 21
++#define ex_CORBA_INTF_REPOS 22
++#define ex_CORBA_BAD_CONTEXT 23
++#define ex_CORBA_OBJ_ADAPTER 24
++#define ex_CORBA_DATA_CONVERSION 25
++#define ex_CORBA_OBJECT_NOT_EXIST 26
++#define ex_CORBA_TRANSACTION_REQUIRED 27
++#define ex_CORBA_TRANSACTION_ROLLEDBACK 28
++#define ex_CORBA_INVALID_TRANSACTION 29
++
++
++#endif /* !_ORBIT_CORBA_ENV_H_ */
++
++
++
+diff -urN linux-2.4.1/net/korbit/orb/corba_env_type.h linux-2.4.1-korbit/net/korbit/orb/corba_env_type.h
+--- linux-2.4.1/net/korbit/orb/corba_env_type.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_env_type.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,79 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_ENV_TYPE_H_
++#define _ORBIT_CORBA_ENV_TYPE_H_
++
++#include "corba_env.h"
++#include "corba_any.h"
++
++typedef struct CORBA_system_exception {
++ CORBA_unsigned_long minor;
++ CORBA_completion_status completed;
++} CORBA_SystemException;
++
++#define SYSEXC(name) typedef CORBA_SystemException name;
++
++SYSEXC(CORBA_UNKNOWN)
++SYSEXC(CORBA_BAD_PARAM)
++SYSEXC(CORBA_NO_MEMORY)
++SYSEXC(CORBA_IMP_LIMIT)
++SYSEXC(CORBA_COMM_FAILURE)
++SYSEXC(CORBA_INV_OBJREF)
++SYSEXC(CORBA_NO_PERMISSION)
++SYSEXC(CORBA_INTERNAL)
++SYSEXC(CORBA_MARSHAL)
++SYSEXC(CORBA_INITIALIZE)
++SYSEXC(CORBA_NO_IMPLEMENT)
++SYSEXC(CORBA_BAD_TYPECODE)
++SYSEXC(CORBA_BAD_OPERATION)
++SYSEXC(CORBA_NO_RESOURCES)
++SYSEXC(CORBA_NO_RESPONSE)
++SYSEXC(CORBA_PERSIST_STORE)
++SYSEXC(CORBA_BAD_INV_ORDER)
++SYSEXC(CORBA_TRANSIENT)
++SYSEXC(CORBA_FREE_MEM)
++SYSEXC(CORBA_INV_IDENT)
++SYSEXC(CORBA_INV_FLAG)
++SYSEXC(CORBA_INTF_REPOS)
++SYSEXC(CORBA_BAD_CONTEXT)
++SYSEXC(CORBA_OBJ_ADAPTER)
++SYSEXC(CORBA_DATA_CONVERSION)
++SYSEXC(CORBA_OBJECT_NOT_EXIST)
++SYSEXC(CORBA_TRANSACTION_REQUIRED)
++SYSEXC(CORBA_TRANSACTION_ROLLEDBACK)
++SYSEXC(CORBA_INVALID_TRANSACTION)
++
++
++/* 19.22 */
++struct CORBA_Environment_type {
++ CORBA_exception_type _major;
++ CORBA_char *_repo_id;
++ void *_params;
++ CORBA_any *_any;
++};
++
++
++#endif /* !_ORBIT_CORBA_ENV_TYPE_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_object.c linux-2.4.1-korbit/net/korbit/orb/corba_object.c
+--- linux-2.4.1/net/korbit/orb/corba_object.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_object.c Thu Feb 1 11:47:11 2001
+@@ -0,0 +1,467 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ * Elliot Lee <sopwith@redhat.com>
++ *
++ */
++
++#include "config.h"
++#include <IIOP/IIOP.h>
++#include "orbit_types.h"
++#include "corba_object.h"
++#include "corba_object_type.h"
++#include "env.h"
++#include "orb.h"
++#ifdef __KORBIT__
++#include "orbit.h"
++#else /* !__KORBIT__ */
++#include "interface_repository.h"
++#endif /* !__KORBIT__ */
++#include <signal.h>
++#include <sys/types.h>
++#include <sys/wait.h>
++#include <alloca.h>
++
++#ifndef __KERNEL__
++#define freeca(ptr)
++#endif
++
++#ifndef __KORBIT__
++/* Section 4.2.1 */
++CORBA_InterfaceDef CORBA_Object_get_interface(CORBA_Object obj, CORBA_Environment *ev)
++{
++ CORBA_Repository repo;
++ CORBA_InterfaceDef interface;
++
++ if(obj==CORBA_OBJECT_NIL)
++ return(CORBA_OBJECT_NIL); /* no exception defined in spec */
++
++ repo=CORBA_ORB_resolve_initial_references(obj->orb, "InterfaceRepository", ev);
++ if(repo==CORBA_OBJECT_NIL)
++ return(CORBA_OBJECT_NIL);
++
++ interface=CORBA_Repository_lookup_id(repo, obj->object_id, ev);
++ CORBA_Object_release(repo, ev);
++
++ return(interface);
++}
++#endif /* !__KORBIT__ */
++
++/* Section 4.2.3 */
++CORBA_boolean CORBA_Object_is_nil(CORBA_Object obj, CORBA_Environment *ev)
++{
++ if(obj==CORBA_OBJECT_NIL) {
++ return(CORBA_TRUE);
++ } else {
++ return(CORBA_FALSE);
++ }
++}
++
++/* Section 4.2.2 */
++/* XXXX Big warning: lots of places inside ORBit expect this to
++ always return 'obj'. Do not change this, upon pain
++ of death... */
++CORBA_Object CORBA_Object_duplicate(CORBA_Object obj, CORBA_Environment *ev)
++{
++ if(obj == CORBA_OBJECT_NIL)
++ return CORBA_OBJECT_NIL;
++
++ if(ORBIT_ROOT_OBJECT(obj)->refs >= 0)
++ ORBIT_ROOT_OBJECT_REF(obj);
++
++ return(obj);
++}
++
++
++/* Section 4.2.2 */
++void CORBA_Object_release(CORBA_Object obj, CORBA_Environment *ev)
++{
++ if(obj != CORBA_OBJECT_NIL)
++ ORBIT_ROOT_OBJECT_release(obj,ev);
++}
++
++extern GHashTable *ORBit_class_assignments;
++
++void ORBit_impl_CORBA_Object_is_a(gpointer servant,
++ GIOPRecvBuffer * _ORBIT_recv_buffer,
++ CORBA_Environment *ev,
++ gpointer dummy)
++{
++ GIOPSendBuffer *_ORBIT_send_buffer;
++ struct CORBA_Object_struct objdummy; /* XXX badhack to save backwards compat */
++ CORBA_boolean retval;
++ char *repo_id;
++ CORBA_unsigned_long slen;
++ guchar *curptr;
++ ORBit_ObjectKey *objkey;
++ gpointer *tmp_vepv;
++ guint sz;
++ CORBA_unsigned_long clsid;
++ PortableServer_ServantBase *_ORBIT_servant;
++
++ _ORBIT_servant = servant;
++
++ /* XXX security implications */
++ curptr = _ORBIT_recv_buffer->cur;
++ curptr = ALIGN_ADDRESS(curptr, 4);
++ if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)))
++ iiop_byteswap((guchar *)&slen, curptr, sizeof(CORBA_unsigned_long));
++ else
++ slen = *((CORBA_unsigned_long *)curptr);
++ curptr += 4;
++ repo_id = curptr;
++
++ repo_id[slen] = '\0';
++
++ objkey = ORBIT_OBJECT_KEY(_ORBIT_servant->_private);
++
++ sz = sizeof(gpointer) * (ORBit_class_assignment_counter + 1);
++ tmp_vepv = alloca(sz);
++ memset(tmp_vepv, '\0', sz);
++
++ objdummy.vepv = tmp_vepv;
++ objkey->class_info->init_local_objref(&objdummy, servant);
++
++ clsid = GPOINTER_TO_UINT(g_hash_table_lookup(ORBit_class_assignments, repo_id));
++ retval = (clsid && tmp_vepv[clsid]);
++
++ _ORBIT_send_buffer = giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)->connection, NULL,
++ _ORBIT_recv_buffer->message.u.request.request_id, ev->_major);
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer), &retval, sizeof(retval));
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ freeca(tmp_vepv);
++}
++
++/* Section 4.2.4 */
++CORBA_boolean CORBA_Object_is_a(CORBA_Object obj, CORBA_char *logical_type_id, CORBA_Environment *ev)
++{
++ if(obj == CORBA_OBJECT_NIL)
++ return CORBA_FALSE;
++
++ if (obj->servant && obj->vepv) {
++ CORBA_unsigned_long clsid;
++
++ clsid = GPOINTER_TO_UINT(g_hash_table_lookup(ORBit_class_assignments, logical_type_id));
++
++ return (clsid && (clsid < obj->vepv_size) && obj->vepv[clsid]);
++ } else if(!strcmp(obj->object_id, logical_type_id)
++ || !strcmp("IDL:CORBA/Object:1.0", logical_type_id)) {
++ return CORBA_TRUE;
++ } else {
++ /* Cut and paste from orbit-idl output */
++ /* XXX security implications */
++ GIOP_unsigned_long _ORBIT_request_id;
++ register GIOP_unsigned_long _ORBIT_system_exception_minor;
++ register CORBA_completion_status _ORBIT_completion_status;
++ register GIOPSendBuffer *_ORBIT_send_buffer;
++ register GIOPRecvBuffer *_ORBIT_recv_buffer;
++ register GIOPConnection *_cnx;
++
++ _cnx = ORBit_object_get_connection(obj);
++
++ _ORBIT_retry_request:
++ _ORBIT_send_buffer = NULL;
++ _ORBIT_recv_buffer = NULL;
++ _ORBIT_completion_status = CORBA_COMPLETED_NO;
++ /* A unique uint pointer is anything on the stack,
++ so set this variable to point to its own address on the
++ stack. :) */
++ _ORBIT_request_id = GPOINTER_TO_UINT(&_ORBIT_request_id);
++ { /* marshalling */
++ static const struct {
++ CORBA_unsigned_long len;
++ char opname[6];
++ } _ORBIT_operation_name_data = {
++ 6, "_is_a"
++ };
++ static const struct iovec _ORBIT_operation_vec =
++ {(gpointer) & _ORBIT_operation_name_data, 10};
++ register CORBA_unsigned_long _ORBIT_tmpvar_0;
++ CORBA_unsigned_long _ORBIT_tmpvar_1;
++
++ _ORBIT_send_buffer =
++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id, CORBA_TRUE,
++ &(obj->active_profile->object_key_vec), &_ORBIT_operation_vec, &ORBit_default_principal_iovec);
++
++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE;
++ if (!_ORBIT_send_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_tmpvar_1 = strlen(logical_type_id) + 1;
++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer), 4);
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer), &(_ORBIT_tmpvar_1), sizeof(_ORBIT_tmpvar_1));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer), (logical_type_id), sizeof(logical_type_id[_ORBIT_tmpvar_0]) * _ORBIT_tmpvar_1);
++ giop_send_buffer_write(_ORBIT_send_buffer);
++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE;
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ _ORBIT_send_buffer = NULL;
++ }
++ { /* demarshalling */
++ register guchar *_ORBIT_curptr;
++ CORBA_boolean _ORBIT_retval;
++
++ _ORBIT_recv_buffer = giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE);
++ if (!_ORBIT_recv_buffer)
++ goto _ORBIT_system_exception;
++ _ORBIT_completion_status = CORBA_COMPLETED_YES;
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status != GIOP_NO_EXCEPTION)
++ goto _ORBIT_msg_exception;
++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) {
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ _ORBIT_retval = *((CORBA_boolean *) _ORBIT_curptr);
++ } else {
++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur;
++ _ORBIT_retval = *((CORBA_boolean *) _ORBIT_curptr);
++ }
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ _ORBIT_system_exception:
++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor, _ORBIT_completion_status);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ giop_send_buffer_unuse(_ORBIT_send_buffer);
++ return _ORBIT_retval;
++ _ORBIT_msg_exception:
++ if (_ORBIT_recv_buffer->message.u.reply.reply_status == GIOP_LOCATION_FORWARD) {
++ if (obj->forward_locations != NULL)
++ ORBit_delete_profiles(obj->forward_locations);
++ obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer);
++ _cnx = ORBit_object_get_forwarded_connection(obj);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++
++ goto _ORBIT_retry_request;
++ } else {
++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, obj->orb);
++ giop_recv_buffer_unuse(_ORBIT_recv_buffer);
++ return _ORBIT_retval;
++ }
++ }
++
++ }
++}
++
++/* Section 4.2.5 */
++#ifndef __KORBIT__
++static void do_exit(int signum) {
++ _exit(5);
++#warning "This should be removed... use BUG instead..."
++}
++#endif
++
++/* Lovely hack to try and figure out without hanging whether an object exists or not. */
++CORBA_boolean CORBA_Object_non_existent(CORBA_Object obj, CORBA_Environment *ev)
++{
++#ifndef __KORBIT__
++ int childpid, exitstatus, itmp;
++#endif
++
++ ev->_major = CORBA_NO_EXCEPTION;
++
++ if(obj == CORBA_OBJECT_NIL)
++ return TRUE;
++
++ if(obj->servant)
++ return FALSE;
++
++ if(obj->connection && obj->connection->is_valid)
++ return FALSE;
++
++#ifndef __KORBIT__
++ childpid = fork();
++
++ if(!childpid) {
++ GIOPConnection* cnx = NULL;
++ struct sigaction sa;
++
++ memset(&sa, 0, sizeof(sa));
++ sa.sa_handler = do_exit;
++ sigaction(SIGALRM, &sa, NULL);
++ alarm(2);
++ cnx = _ORBit_object_get_connection(obj);
++
++ /* XXX todo - try invoking a strange operation on the object, and see what type of exception we get. */
++
++ _exit((cnx == NULL)?1:0);
++ }
++
++ itmp = waitpid(childpid, &exitstatus, 0);
++
++ if(itmp < 0) return TRUE;
++ return WEXITSTATUS(exitstatus) && TRUE;
++#else /* __KORBIT__ */
++ return FALSE;
++#endif /* __KORBIT__ */
++}
++
++gboolean
++g_CORBA_Object_equal(CORBA_Object obj1, CORBA_Object obj2)
++{
++ gboolean retval;
++ CORBA_Environment ev;
++
++ CORBA_exception_init(&ev);
++
++ retval = (gboolean)CORBA_Object_is_equivalent(obj1, obj2, &ev);
++
++ CORBA_exception_free(&ev);
++
++ return retval;
++}
++
++/* Section 4.2.6 */
++CORBA_boolean CORBA_Object_is_equivalent(CORBA_Object obj, CORBA_Object other_object, CORBA_Environment *ev)
++{
++ ORBit_Object_info *obj_profile, *other_object_profile;
++ int i,j, obj_profile_count, other_object_profile_count;
++
++ if(obj == CORBA_OBJECT_NIL
++ && other_object == CORBA_OBJECT_NIL)
++ return CORBA_TRUE;
++
++ if(obj == CORBA_OBJECT_NIL
++ || other_object == CORBA_OBJECT_NIL)
++ goto ret_false;
++
++ /*
++ * If one profile in "obj" matches one in "other_object", then these
++ * objects are equivalent.
++ *
++ * This is O(n*m) at worst case :-( Hopefully though most objects will
++ * only have 1 or 2 profiles.
++ *
++ * The profile list could be indexed as a hash table (the linked list
++ * is still needed, as the profile order is significant)
++ */
++
++ obj_profile_count = g_slist_length(obj->profile_list);
++ other_object_profile_count = g_slist_length(other_object->profile_list);
++
++ for(i=0;i<obj_profile_count;i++) {
++ obj_profile=(ORBit_Object_info *)g_slist_nth_data(obj->profile_list, i);
++
++ for(j=0;j<other_object_profile_count;j++) {
++ other_object_profile=(ORBit_Object_info *)g_slist_nth_data(other_object->profile_list, j);
++
++ if(obj_profile->profile_type != other_object_profile->profile_type)
++ continue;
++
++ if(obj_profile->object_key._length != other_object_profile->object_key._length)
++ continue;
++
++ if(memcmp(obj_profile->object_key._buffer, other_object_profile->object_key._buffer, obj_profile->object_key._length))
++ continue;
++
++ if(obj_profile->profile_type == IOP_TAG_INTERNET_IOP) {
++ TAG_INTERNET_IOP_info *ii1, *ii2;
++
++ ii1 = &obj_profile->tag.iopinfo;
++ ii2 = &other_object_profile->tag.iopinfo;
++
++ if(ii1->port != ii2->port)
++ continue;
++ if(strcmp(ii1->host, ii2->host))
++ continue;
++
++ return(CORBA_TRUE);
++ } else if(obj_profile->profile_type == IOP_TAG_ORBIT_SPECIFIC) {
++ TAG_ORBIT_SPECIFIC_info *oi1, *oi2;
++
++ oi1 = &obj_profile->tag.orbitinfo;
++ oi2 = &other_object_profile->tag.orbitinfo;
++
++ if(strcmp(oi1->unix_sock_path, oi2->unix_sock_path))
++ continue;
++ if(oi1->ipv6_port != oi2->ipv6_port)
++ continue;
++
++ return(CORBA_TRUE);
++ }
++ }
++ }
++
++ ret_false:
++ return CORBA_FALSE;
++}
++
++guint
++g_CORBA_Object_hash(CORBA_Object obj)
++{
++ guint retval;
++ CORBA_Environment ev;
++
++ CORBA_exception_init(&ev);
++
++ retval = (guint)CORBA_Object_hash(obj, UINT_MAX, &ev);
++
++ CORBA_exception_free(&ev);
++
++ return retval;
++}
++
++static void profile_hash(gpointer item, gpointer data)
++{
++ ORBit_Object_info *info = (ORBit_Object_info *)item;
++ CORBA_unsigned_long *retval = (CORBA_unsigned_long *)data;
++
++ g_assert(info);
++ g_assert(retval);
++
++ *retval ^= info->object_key._length;
++
++ if(info->profile_type == IOP_TAG_INTERNET_IOP) {
++ *retval ^= !info->tag.iopinfo.port;
++ } else if(info->profile_type == IOP_TAG_ORBIT_SPECIFIC) {
++ *retval ^= g_str_hash(info->tag.orbitinfo.unix_sock_path);
++ *retval ^= !info->tag.orbitinfo.ipv6_port;
++ }
++}
++
++/* Section 4.2.6 */
++CORBA_unsigned_long CORBA_Object_hash(CORBA_Object obj,
++ CORBA_unsigned_long maximum,
++ CORBA_Environment *ev)
++{
++ CORBA_unsigned_long retval = 0;
++ char *tptr;
++
++ g_assert(obj);
++
++ tptr = obj->object_id;
++ while(*tptr) {
++ retval = (retval << 8) ^ *tptr;
++ tptr++;
++ }
++
++ if(g_slist_length(obj->profile_list)>0) {
++ g_slist_foreach(obj->profile_list, profile_hash, &retval);
++ } else {
++ g_warning("Object of type %s doesn't seem to have any connection info!", obj->object_id);
++ }
++
++ return (retval % maximum);
++}
++
++/* Section 4.2.7 */
++CORBA_Policy CORBA_Object_get_policy(CORBA_Object obj, CORBA_PolicyType policy_type, CORBA_Environment *ev)
++{
++ g_assert(!"Not yet implemented");
++ return(NULL);
++}
+diff -urN linux-2.4.1/net/korbit/orb/corba_object.h linux-2.4.1-korbit/net/korbit/orb/corba_object.h
+--- linux-2.4.1/net/korbit/orb/corba_object.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_object.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,59 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_OBJECT_H_
++#define _ORBIT_CORBA_OBJECT_H_
++
++#include <ORBitutil/basic_types.h>
++
++#include "corba_env.h"
++#include "corba_orb.h"
++#include "corba_sequences.h"
++
++#define CORBA_OBJECT_NIL NULL
++
++typedef struct CORBA_Object_struct *CORBA_Object;
++
++#define CORBA_OBJECT(x) ((CORBA_Object)(x))
++
++/* Used for internal stuff mostly, but also good if you want to store
++ a hash of objects */
++gboolean g_CORBA_Object_equal(CORBA_Object obj1, CORBA_Object obj2);
++guint g_CORBA_Object_hash(CORBA_Object obj);
++
++void ORBit_impl_CORBA_Object_is_a(gpointer servant,
++ GIOPRecvBuffer * _ORBIT_recv_buffer,
++ CORBA_Environment *ev, gpointer dummy);
++#define ORBIT_IMPLEMENTS_IS_A
++
++extern CORBA_boolean CORBA_Object_is_a(
++ CORBA_Object obj,
++ CORBA_char *logical_type_id,
++ CORBA_Environment *ev);
++
++#endif /* !_ORBIT_CORBA_OBJECT_H_ */
++
++
++
+diff -urN linux-2.4.1/net/korbit/orb/corba_object_type.h linux-2.4.1-korbit/net/korbit/orb/corba_object_type.h
+--- linux-2.4.1/net/korbit/orb/corba_object_type.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_object_type.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,54 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_OBJECT_TYPE_H_
++#define _ORBIT_CORBA_OBJECT_TYPE_H_
++
++#include <sys/uio.h> /* for struct iovec */
++
++#include <IIOP/IIOP.h> /* for giop_connection */
++
++#include "corba_object.h"
++#include "corba_basic_sequences_type.h"
++
++#include "orbit_object_type.h"
++
++struct CORBA_Object_struct {
++ struct ORBit_RootObject_struct parent;
++ CORBA_ORB orb;
++ GIOPConnection *connection;
++ CORBA_char *object_id;
++ GSList *profile_list;
++ GSList *forward_locations;
++ ORBit_Object_info *active_profile; /* points at a member of profile_list or forward_locations */
++
++ /* Used for direct calls */
++ gpointer *vepv;
++ /* PortableServer_Servant - looping includes :( */ gpointer servant;
++ guint vepv_size;
++};
++
++
++#endif /* !_ORBIT_CORBA_OBJECT_TYPE_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_orb.h linux-2.4.1-korbit/net/korbit/orb/corba_orb.h
+--- linux-2.4.1/net/korbit/orb/corba_orb.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_orb.h Thu Feb 1 11:47:11 2001
+@@ -0,0 +1,48 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_ORB_H_
++#define _ORBIT_CORBA_ORB_H_
++
++typedef char *CORBA_ORB_ObjectId;
++
++#ifndef CORBA_POLICY_TYPE
++#define CORBA_POLICY_TYPE 1
++/* We need to define this in corba_orb_type.h as well, sometimes... */
++typedef struct CORBA_Policy_type *CORBA_Policy;
++#endif
++
++typedef CORBA_unsigned_long CORBA_PolicyType;
++
++typedef struct CORBA_ORB_type *CORBA_ORB;
++
++typedef struct CORBA_DomainManager_type *CORBA_DomainManager;
++
++typedef struct CORBA_ConstructionPolicy_type *CORBA_ConstructionPolicy;
++
++#define ex_CORBA_ORB_InvalidName "IDL:CORBA/ORB/InvalidName:1.0"
++
++#endif /* !_ORBIT_CORBA_ORB_H_ */
++
+diff -urN linux-2.4.1/net/korbit/orb/corba_orb_type.h linux-2.4.1-korbit/net/korbit/orb/corba_orb_type.h
+--- linux-2.4.1/net/korbit/orb/corba_orb_type.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_orb_type.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,77 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_ORB_TYPE_H_
++#define _ORBIT_CORBA_ORB_TYPE_H_
++
++#include "corba_object.h"
++
++struct CORBA_ORB_type {
++ struct ORBit_PseudoObject_struct parent;
++ CORBA_ORBid orb_identifier;
++ CORBA_RepositoryId repoid;
++ CORBA_boolean use_poa;
++
++ CORBA_Object imr, ir, naming, root_poa;
++ struct {
++ GIOPConnection *ipv4;
++ GIOPConnection *ipv6;
++ GIOPConnection *usock;
++ } cnx;
++
++ GHashTable *objrefs;
++
++ GPtrArray *poas;
++
++ CORBA_Context default_ctx;
++};
++
++#define CORBA_ORB_CAST(orb) ((CORBA_ORB)orb)
++
++typedef struct CORBA_ORB_InvalidName {
++ int dummy;
++} CORBA_ORB_InvalidName;
++
++struct CORBA_Policy_type {
++ struct ORBit_PseudoObject_struct parent;
++ CORBA_PolicyType policy_type;
++};
++#ifndef CORBA_POLICY_TYPE
++#define CORBA_POLICY_TYPE 1
++typedef struct CORBA_Policy_type *CORBA_Policy;
++#endif
++
++struct CORBA_DomainManager_type {
++ struct ORBit_PseudoObject_struct parent;
++};
++
++#define CORBA_SecConstruction (11)
++
++struct CORBA_ConstructionPolicy_type {
++ int fill_me_in;
++};
++
++
++#endif /* !_ORBIT_CORBA_ORB_TYPE_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_portableserver.h linux-2.4.1-korbit/net/korbit/orb/corba_portableserver.h
+--- linux-2.4.1/net/korbit/orb/corba_portableserver.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_portableserver.h Thu Feb 1 11:47:11 2001
+@@ -0,0 +1,80 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_PORTABLESERVER_H_
++#define _ORBIT_CORBA_PORTABLESERVER_H_
++
++typedef struct PortableServer_ThreadPolicy_type *PortableServer_ThreadPolicy;
++typedef struct PortableServer_LifespanPolicy_type *PortableServer_LifespanPolicy;
++typedef struct PortableServer_IdUniquenessPolicy_type *PortableServer_IdUniquenessPolicy;
++typedef struct PortableServer_IdAssignmentPolicy_type *PortableServer_IdAssignmentPolicy;
++typedef struct PortableServer_ImplicitActivationPolicy_type *PortableServer_ImplicitActivationPolicy;
++typedef struct PortableServer_ServantRetentionPolicy_type *PortableServer_ServantRetentionPolicy;
++typedef struct PortableServer_RequestProcessingPolicy_type *PortableServer_RequestProcessingPolicy;
++typedef struct PortableServer_POAManager_type* PortableServer_POAManager;
++typedef struct PortableServer_AdapterActivator_type *PortableServer_AdapterActivator;
++typedef struct PortableServer_ServantManager_type *PortableServer_ServantManager;
++typedef struct PortableServer_ServantActivator_type *PortableServer_ServantActivator;
++typedef struct PortableServer_ServantLocator_type *PortableServer_ServantLocator;
++typedef struct PortableServer_POA_type *PortableServer_POA;
++typedef struct PortableServer_Current_type *PortableServer_Current;
++
++typedef enum {
++ PortableServer_ORB_CTRL_MODEL=0,
++ PortableServer_SINGLE_THREAD_MODEL
++} PortableServer_ThreadPolicyValue;
++
++typedef enum {
++ PortableServer_TRANSIENT=0,
++ PortableServer_PERSISTENT
++} PortableServer_LifespanPolicyValue;
++
++typedef enum {
++ PortableServer_UNIQUE_ID=0,
++ PortableServer_MULTIPLE_ID
++} PortableServer_IdUniquenessPolicyValue;
++
++typedef enum {
++ PortableServer_USER_ID=0,
++ PortableServer_SYSTEM_ID
++} PortableServer_IdAssignmentPolicyValue;
++
++typedef enum {
++ PortableServer_IMPLICIT_ACTIVATION=0,
++ PortableServer_NO_IMPLICIT_ACTIVATION
++} PortableServer_ImplicitActivationPolicyValue;
++
++typedef enum {
++ PortableServer_RETAIN=0,
++ PortableServer_NON_RETAIN
++} PortableServer_ServantRetentionPolicyValue;
++
++typedef enum {
++ PortableServer_USE_ACTIVE_OBJECT_MAP_ONLY=0,
++ PortableServer_USE_DEFAULT_SERVANT,
++ PortableServer_USE_SERVANT_MANAGER
++} PortableServer_RequestProcessingPolicyValue;
++
++#endif /* !_ORBIT_CORBA_PORTABLESERVER_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_portableserver_type.h linux-2.4.1-korbit/net/korbit/orb/corba_portableserver_type.h
+--- linux-2.4.1/net/korbit/orb/corba_portableserver_type.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_portableserver_type.h Thu Feb 1 11:47:11 2001
+@@ -0,0 +1,361 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_PORTABLESERVER_TYPE_H_
++#define _ORBIT_CORBA_PORTABLESERVER_TYPE_H_
++
++/* 19.26 */
++
++typedef void *PortableServer_ServantLocator_Cookie;
++typedef void *PortableServer_Servant;
++
++#ifndef _PortableServer_ForwardRequest_defined
++#define _PortableServer_ForwardRequest_defined
++
++typedef struct PortableServer_ForwardRequest {
++ CORBA_Object forward_reference;
++} PortableServer_ForwardRequest;
++
++#define ex_PortableServer_ForwardRequest "IDL:PortableServer/ForwardRequest:1.0"
++#endif /* !_PortableServer_ForwardRequest_defined */
++
++#define PortableServer_THREAD_POLICY_ID 16
++struct PortableServer_ThreadPolicy_type {
++ struct CORBA_Policy_type corba_policy;
++ PortableServer_ThreadPolicyValue value;
++};
++
++#define PortableServer_LIFESPAN_POLICY_ID 17
++extern const CORBA_PolicyType PortableServer_LifespanPolicy_PolicyType;
++struct PortableServer_LifespanPolicy_type {
++ struct CORBA_Policy_type corba_policy;
++ PortableServer_LifespanPolicyValue value;
++};
++
++#define PortableServer_ID_UNIQUENESS_POLICY_ID 18
++struct PortableServer_IdUniquenessPolicy_type {
++ struct CORBA_Policy_type corba_policy;
++ PortableServer_IdUniquenessPolicyValue value;
++};
++
++#define PortableServer_ID_ASSIGNMENT_POLICY_ID 19
++struct PortableServer_IdAssignmentPolicy_type {
++ struct CORBA_Policy_type corba_policy;
++ PortableServer_IdAssignmentPolicyValue value;
++};
++
++#define PortableServer_IMPLICIT_ACTIVATION_POLICY_ID 20
++struct PortableServer_ImplicitActivationPolicy_type {
++ struct CORBA_Policy_type corba_policy;
++ PortableServer_ImplicitActivationPolicyValue value;
++};
++
++#define PortableServer_SERVANT_RETENTION_POLICY_ID 21
++struct PortableServer_ServantRetentionPolicy_type {
++ struct CORBA_Policy_type corba_policy;
++ PortableServer_ServantRetentionPolicyValue value;
++};
++
++#define PortableServer_REQUEST_PROCESSING_POLICY_ID 22
++struct PortableServer_RequestProcessingPolicy_type {
++ struct CORBA_Policy_type corba_policy;
++ PortableServer_RequestProcessingPolicyValue value;
++};
++
++#ifndef _PortableServer_POAManager_AdapterInactive_defined
++#define _PortableServer_POAManager_AdapterInactive_defined
++
++typedef struct PortableServer_POAManager_AdapterInactive {
++ int fill_me_in;
++} PortableServer_POAManager_AdapterInactive;
++
++#define ex_PortableServer_POAManager_AdapterInactive "IDL:PortableServer/POAManager/AdapterInactive:1.0"
++#endif /* !_PortableServer_POAManager_AdapterInactive_defined */
++
++typedef enum { PortableServer_POAManager_HOLDING,
++ PortableServer_POAManager_ACTIVE,
++ PortableServer_POAManager_DISCARDING,
++ PortableServer_POAManager_INACTIVE
++} PortableServer_POAManager_State;
++
++struct PortableServer_POAManager_type {
++ struct ORBit_PseudoObject_struct parent;
++ GSList* poa_collection;
++ CORBA_ORB orb;
++ PortableServer_POAManager_State state;
++};
++
++struct PortableServer_AdapterActivator_type {
++ int fill_me_in;
++};
++
++struct PortableServer_ServantManager_type {
++ int fill_me_in;
++};
++
++#ifndef _PortableServer_POA_AdapterAlreadyExists_defined
++#define _PortableServer_POA_AdapterAlreadyExists_defined
++
++typedef struct PortableServer_POA_AdapterAlreadyExists {
++ int fill_me_in;
++} PortableServer_POA_AdapterAlreadyExists;
++
++#define ex_PortableServer_POA_AdapterAlreadyExists "IDL:PortableServer/POA/AdapterAlreadyExists:1.0"
++#endif /* !_PortableServer_POA_AdapterAlreadyExists_defined */
++
++#ifndef _PortableServer_POAManager_AdapterInactive_defined
++#define _PortableServer_POAManager_AdapterInactive_defined
++
++typedef struct PortableServer_POAManager_AdapterInactive {
++ int fill_me_in;
++} PortableServer_POAManager_AdapterInactive;
++
++#define ex_PortableServer_POAManager_AdapterInactive "IDL:PortableServer/POAManager/AdapterInactive:1.0"
++#endif /* !_PortableServer_POAManager_AdapterInactive_defined */
++
++#ifndef _PortableServer_POA_AdapterNonExistent_defined
++#define _PortableServer_POA_AdapterNonExistent_defined
++
++typedef struct PortableServer_POA_AdapterNonExistent {
++ int fill_me_in;
++} PortableServer_POA_AdapterNonExistent;
++
++#define ex_PortableServer_POA_AdapterNonExistent "IDL:PortableServer/POA/AdapterNonExistent:1.0"
++#endif /* !_PortableServer_POA_AdapterNonExistent_defined */
++
++#ifndef _PortableServer_POA_InvalidPolicy_defined
++#define _PortableServer_POA_InvalidPolicy_defined
++
++typedef struct PortableServer_POA_InvalidPolicy {
++ CORBA_unsigned_short index;
++} PortableServer_POA_InvalidPolicy;
++
++#define ex_PortableServer_POA_InvalidPolicy "IDL:PortableServer/POA/InvalidPolicy:1.0"
++#endif /* !_PortableServer_POA_InvalidPolicy_defined */
++
++#ifndef _PortableServer_POA_NoServant_defined
++#define _PortableServer_POA_NoServant_defined
++
++typedef struct PortableServer_POA_NoServant {
++ int fill_me_in;
++} PortableServer_POA_NoServant;
++
++#define ex_PortableServer_POA_NoServant "IDL:PortableServer/POA/NoServant:1.0"
++#endif /* !_PortableServer_POA_NoServant_defined */
++
++#ifndef _PortableServer_POA_ObjectAlreadyActive_defined
++#define _PortableServer_POA_ObjectAlreadyActive_defined
++
++typedef struct PortableServer_POA_ObjectAlreadyActive {
++ int fill_me_in;
++} PortableServer_POA_ObjectAlreadyActive;
++
++#define ex_PortableServer_POA_ObjectAlreadyActive "IDL:PortableServer/POA/ObjectAlreadyActive:1.0"
++#endif /* !_PortableServer_POA_ObjectAlreadyActive_defined */
++
++#ifndef _PortableServer_POA_ObjectNotActive_defined
++#define _PortableServer_POA_ObjectNotActive_defined
++
++typedef struct PortableServer_POA_ObjectNotActive {
++ int fill_me_in;
++} PortableServer_POA_ObjectNotActive;
++
++#define ex_PortableServer_POA_ObjectNotActive "IDL:PortableServer/POA/ObjectNotActive:1.0"
++#endif /* !_PortableServer_POA_ObjectNotActive_defined */
++
++#ifndef _PortableServer_POA_ServantAlreadyActive_defined
++#define _PortableServer_POA_ServantAlreadyActive_defined
++
++typedef struct PortableServer_POA_ServantAlreadyActive {
++ int fill_me_in;
++} PortableServer_POA_ServantAlreadyActive;
++
++#define ex_PortableServer_POA_ServantAlreadyActive "IDL:PortableServer/POA/ServantAlreadyActive:1.0"
++#endif /* !_PortableServer_POA_ServantAlreadyActive_defined */
++
++#ifndef _PortableServer_POA_ServantNotActive_defined
++#define _PortableServer_POA_ServantNotActive_defined
++
++typedef struct PortableServer_POA_ServantNotActive {
++ int fill_me_in;
++} PortableServer_POA_ServantNotActive;
++
++#define ex_PortableServer_POA_ServantNotActive "IDL:PortableServer/POA/ServantNotActive:1.0"
++#endif /* !_PortableServer_POA_ServantNotActive_defined */
++
++#ifndef _PortableServer_POA_WrongAdapter_defined
++#define _PortableServer_POA_WrongAdapter_defined
++
++typedef struct PortableServer_POA_WrongAdapter {
++ int fill_me_in;
++} PortableServer_POA_WrongAdapter;
++
++#define ex_PortableServer_POA_WrongAdapter "IDL:PortableServer/POA/WrongAdapter:1.0"
++#endif /* !_PortableServer_POA_WrongAdapter_defined */
++
++#ifndef _PortableServer_POA_WrongPolicy_defined
++#define _PortableServer_POA_WrongPolicy_defined
++
++typedef struct PortableServer_POA_WrongPolicy {
++ int fill_me_in;
++} PortableServer_POA_WrongPolicy;
++
++#define ex_PortableServer_POA_WrongPolicy "IDL:PortableServer/POA/WrongPolicy:1.0"
++#endif /* !_PortableServer_POA_WrongPolicy_defined */
++
++#ifndef _PortableServer_Current_NoContext_defined
++#define _PortableServer_Current_NoContext_defined
++
++typedef struct PortableServer_Current_NoContext {
++ int fill_me_in;
++} PortableServer_Current_NoContext;
++
++#define ex_PortableServer_Current_NoContext "IDL:PortableServer/Current/NoContext:1.0"
++#endif /* !_PortableServer_Current_NoContext_defined */
++
++struct PortableServer_Current_type {
++ int fill_me_in;
++};
++
++typedef struct PortableServer_ServantBase__epv {
++ void *_private;
++ void (*finalize)(PortableServer_Servant, CORBA_Environment *);
++ PortableServer_POA (*default_POA)(PortableServer_Servant, CORBA_Environment *);
++} PortableServer_ServantBase__epv;
++
++typedef PortableServer_ServantBase__epv *PortableServer_ServantBase__vepv;
++
++typedef struct PortableServer_ServantBase {
++ void *_private;
++ PortableServer_ServantBase__vepv *vepv;
++} PortableServer_ServantBase;
++
++/* 19.27 */
++
++typedef void (*PortableServer_DynamicImplRoutine) (PortableServer_Servant servant, CORBA_ServerRequest request);
++
++typedef struct PortableServer_DynamicImpl__epv {
++ void *_private;
++ PortableServer_DynamicImplRoutine invoke;
++ CORBA_RepositoryId (*primary_interface) (PortableServer_Servant svt, PortableServer_ObjectId id, PortableServer_POA poa, CORBA_Environment *env);
++} PortableServer_DynamicImpl__epv;
++
++typedef struct PortableServer_DynamicImpl__vepv {
++ PortableServer_ServantBase__epv *_base_epv;
++ PortableServer_DynamicImpl__epv *PortableServer_DynamicImpl_epv;
++} PortableServer_DynamicImpl__vepv;
++
++typedef struct PortableServer_DynamicImpl {
++ void *_private;
++ PortableServer_DynamicImpl__vepv *vepv;
++} PortableServer_DynamicImpl;
++
++typedef struct {
++ void *_private;
++} POA_PortableServer_ServantManager__epv;
++
++typedef struct {
++ void *_private;
++
++ PortableServer_Servant (*incarnate) (PortableServer_Servant servant,
++ PortableServer_ObjectId * oid,
++ PortableServer_POA adapter,
++ CORBA_Environment * ev);
++
++ void (*etherealize) (PortableServer_Servant servant,
++ PortableServer_ObjectId* oid,
++ PortableServer_POA adapter,
++ PortableServer_Servant serv,
++ CORBA_boolean cleanup_in_progress,
++ CORBA_boolean remaining_activations,
++ CORBA_Environment * ev);
++
++} POA_PortableServer_ServantActivator__epv;
++
++typedef struct {
++ PortableServer_ServantBase__epv *_base_epv;
++ POA_PortableServer_ServantManager__epv *PortableServer_ServantManager_epv;
++ POA_PortableServer_ServantActivator__epv *PortableServer_ServantActivator_epv;
++} POA_PortableServer_ServantActivator__vepv;
++
++typedef struct {
++ void *_private;
++ POA_PortableServer_ServantActivator__vepv *vepv;
++} POA_PortableServer_ServantActivator;
++
++extern void
++POA_PortableServer_ServantActivator__init(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++extern void
++POA_PortableServer_ServantActivator__fini(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++
++typedef struct {
++ void *_private;
++
++ PortableServer_Servant (*preinvoke) (PortableServer_Servant servant,
++ PortableServer_ObjectId * oid,
++ PortableServer_POA adapter,
++ CORBA_Identifier operation,
++ PortableServer_ServantLocator_Cookie *the_cookie,
++ CORBA_Environment * ev);
++
++ void (*postinvoke) (PortableServer_Servant servant,
++ PortableServer_ObjectId * oid,
++ PortableServer_POA adapter,
++ CORBA_Identifier operation,
++ PortableServer_ServantLocator_Cookie the_cookie,
++ PortableServer_Servant the_servant,
++ CORBA_Environment * ev);
++} POA_PortableServer_ServantLocator__epv;
++
++typedef struct {
++ PortableServer_ServantBase__epv *_base_epv;
++ POA_PortableServer_ServantManager__epv *PortableServer_ServantManager_epv;
++ POA_PortableServer_ServantLocator__epv *PortableServer_ServantLocator_epv;
++} POA_PortableServer_ServantLocator__vepv;
++
++typedef struct {
++ void *_private;
++ POA_PortableServer_ServantLocator__vepv *vepv;
++} POA_PortableServer_ServantLocator;
++
++extern void
++POA_PortableServer_ServantLocator__init(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++extern void
++POA_PortableServer_ServantLocator__fini(PortableServer_Servant servant,
++ CORBA_Environment * ev);
++
++struct CORBA_ServerRequest_type {
++ struct ORBit_PseudoObject_struct parent;
++ GIOPRecvBuffer *rbuf;
++ GIOPSendBuffer *sbuf;
++ CORBA_NVList *params;
++ CORBA_ORB orb;
++ guchar did_ctx, did_exc;
++};
++
++#endif /* !_ORBIT_CORBA_PORTABLESERVER_TYPE_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_sequences.h linux-2.4.1-korbit/net/korbit/orb/corba_sequences.h
+--- linux-2.4.1/net/korbit/orb/corba_sequences.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_sequences.h Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,74 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_SEQUENCES_H_
++#define _ORBIT_CORBA_SEQUENCES_H_
++
++
++/* moved from sequences.h */
++#include "corba_basic_sequences_type.h"
++
++typedef CORBA_sequence_octet CORBA_ReferenceData;
++
++#define _CORBA_sequence_ServiceOption_defined
++typedef struct CORBA_sequence_ServiceOption CORBA_sequence_ServiceOption;
++
++#define _CORBA_sequence_ServiceDetail_defined
++typedef struct CORBA_sequence_ServiceDetail CORBA_sequence_ServiceDetail;
++
++#define _CORBA_sequence_ORB_ObjectId_defined
++typedef struct CORBA_sequence_ORB_ObjectId CORBA_ORB_ObjectIdList;
++
++#define _CORBA_sequence_NameValuePair_defined
++typedef struct CORBA_sequence_NameValuePair CORBA_NameValuePairSeq;
++
++#define _CORBA_sequence_CORBA_any_defined
++typedef struct CORBA_sequence_CORBA_any_struct CORBA_AnySeq;
++typedef struct CORBA_sequence_CORBA_any_struct CORBA_sequence_CORBA_any;
++
++#define _CORBA_sequence_Policy_defined
++typedef struct CORBA_sequence_Policy CORBA_PolicyList;
++
++#define _CORBA_sequence_DomainManager_defined
++typedef struct CORBA_sequence_DomainManager CORBA_DomainManagerList;
++
++#define _PortableServer_sequence_octet_defined
++typedef struct PortableServer_sequence_octet PortableServer_ObjectId;
++
++
++/* Moved from orbit_types.h */
++#ifndef HAVE_CORBA_PRINCIPAL
++#define HAVE_CORBA_PRINCIPAL 1
++typedef CORBA_sequence_octet CORBA_Principal;
++#endif
++typedef CORBA_sequence_octet CORBA_DynAny_OctetSeq;
++typedef CORBA_sequence_octet CORBA_DynFixed_OctetSeq;
++typedef CORBA_sequence_octet CORBA_DynEnum_OctetSeq;
++typedef CORBA_sequence_octet CORBA_DynStruct_OctetSeq;
++typedef CORBA_sequence_octet CORBA_DynUnion_OctetSeq;
++typedef CORBA_sequence_octet CORBA_DynSequence_OctetSeq;
++typedef CORBA_sequence_octet CORBA_DynArray_OctetSeq;
++
++#endif /* !_ORBIT_CORBA_SEQUENCES_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_sequences_type.h linux-2.4.1-korbit/net/korbit/orb/corba_sequences_type.h
+--- linux-2.4.1/net/korbit/orb/corba_sequences_type.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_sequences_type.h Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,98 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_SEQUENCES_TYPE_H_
++#define _ORBIT_CORBA_SEQUENCES_TYPE_H_
++
++#include "corba_sequences.h"
++
++struct CORBA_sequence_ServiceOption {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ CORBA_ServiceOption *_buffer;
++ CORBA_boolean _release;
++};
++
++struct CORBA_sequence_ServiceDetail {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ CORBA_ServiceDetail *_buffer;
++ CORBA_boolean _release;
++};
++
++struct CORBA_sequence_ORB_ObjectId {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ CORBA_ORB_ObjectId *_buffer;
++ CORBA_boolean _release;
++};
++
++struct CORBA_sequence_NameValuePair {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ struct CORBA_NameValuePair *_buffer;
++ CORBA_boolean _release;
++};
++
++struct CORBA_sequence_CORBA_any_struct {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ CORBA_any *_buffer;
++ CORBA_boolean _release;
++};
++
++struct CORBA_sequence_Policy {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ CORBA_Policy *_buffer;
++ CORBA_boolean _release;
++};
++
++struct CORBA_sequence_DomainManager {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ CORBA_DomainManager *_buffer;
++ CORBA_boolean _release;
++};
++
++struct PortableServer_sequence_octet {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ CORBA_octet *_buffer;
++ CORBA_boolean _release;
++};
++
++/* Generic sequence */
++struct CORBA_Sequence_type {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ void *_buffer;
++ CORBA_boolean _release;
++};
++
++#define CORBA_SEQFLAGS_RELEASE 1
++
++
++#endif /* !_ORBIT_CORBA_SEQUENCES_TYPE_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/corba_typecode.h linux-2.4.1-korbit/net/korbit/orb/corba_typecode.h
+--- linux-2.4.1/net/korbit/orb/corba_typecode.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_typecode.h Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,167 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_TYPECODE_H_
++#define _ORBIT_CORBA_TYPECODE_H_
++
++/* moved from orbit_types.h */
++typedef struct CORBA_TypeCode_struct *CORBA_TypeCode;
++
++typedef enum {
++ CORBA_tk_null=0,
++ CORBA_tk_void=1,
++ CORBA_tk_short=2,
++ CORBA_tk_long=3,
++ CORBA_tk_ushort=4,
++ CORBA_tk_ulong=5,
++ CORBA_tk_float=6,
++ CORBA_tk_double=7,
++ CORBA_tk_boolean=8,
++ CORBA_tk_char=9,
++ CORBA_tk_octet=10,
++ CORBA_tk_any=11,
++ CORBA_tk_TypeCode=12,
++ CORBA_tk_Principal=13,
++ CORBA_tk_objref=14,
++ CORBA_tk_struct=15,
++ CORBA_tk_union=16,
++ CORBA_tk_enum=17,
++ CORBA_tk_string=18,
++ CORBA_tk_sequence=19,
++ CORBA_tk_array=20,
++ CORBA_tk_alias=21,
++ CORBA_tk_except=22,
++ CORBA_tk_longlong=23,
++ CORBA_tk_ulonglong=24,
++ CORBA_tk_longdouble=25,
++ CORBA_tk_wchar=26,
++ CORBA_tk_wstring=27,
++ CORBA_tk_fixed=28,
++ CORBA_tk_recursive=0xffffffff,
++ CORBA_tk_last=29 /* hack for GIOP */
++} CORBA_TCKind;
++
++#define TC_CORBA_short TC_short
++#define TC_CORBA_long TC_long
++#define TC_CORBA_longlong TC_longlong
++#define TC_CORBA_long_long TC_longlong
++#define TC_CORBA_ushort TC_ushort
++#define TC_CORBA_unsigned_short TC_ushort
++#define TC_CORBA_ulong TC_ulong
++#define TC_CORBA_unsigned_long TC_ulong
++#define TC_CORBA_ulonglong TC_ulonglong
++#define TC_CORBA_unsigned_long_long TC_ulonglong
++#define TC_CORBA_float TC_float
++#define TC_CORBA_double TC_double
++#define TC_CORBA_longdouble TC_longdouble
++#define TC_CORBA_long_double TC_longdouble
++#define TC_CORBA_boolean TC_boolean
++#define TC_CORBA_char TC_char
++#define TC_CORBA_wchar TC_wchar
++#define TC_CORBA_octet TC_octet
++#define TC_CORBA_any TC_any
++#define TC_CORBA_TypeCode TC_TypeCode
++#define TC_CORBA_Principal TC_Principal
++#define TC_CORBA_Object TC_Object
++#define TC_CORBA_string TC_string
++#define TC_CORBA_wstring TC_wstring
++
++#define TC_null ((CORBA_TypeCode)&TC_null_struct)
++#define TC_void ((CORBA_TypeCode)&TC_void_struct)
++#define TC_short ((CORBA_TypeCode)&TC_short_struct)
++#define TC_long ((CORBA_TypeCode)&TC_long_struct)
++#define TC_longlong ((CORBA_TypeCode)&TC_longlong_struct)
++#define TC_ushort ((CORBA_TypeCode)&TC_ushort_struct)
++#define TC_ulong ((CORBA_TypeCode)&TC_ulong_struct)
++#define TC_ulonglong ((CORBA_TypeCode)&TC_ulonglong_struct)
++#define TC_float ((CORBA_TypeCode)&TC_float_struct)
++#define TC_double ((CORBA_TypeCode)&TC_double_struct)
++#define TC_longdouble ((CORBA_TypeCode)&TC_longdouble_struct)
++#define TC_boolean ((CORBA_TypeCode)&TC_boolean_struct)
++#define TC_char ((CORBA_TypeCode)&TC_char_struct)
++#define TC_wchar ((CORBA_TypeCode)&TC_wchar_struct)
++#define TC_octet ((CORBA_TypeCode)&TC_octet_struct)
++#define TC_any ((CORBA_TypeCode)&TC_any_struct)
++#define TC_TypeCode ((CORBA_TypeCode)&TC_TypeCode_struct)
++#define TC_Principal ((CORBA_TypeCode)&TC_Principal_struct)
++#define TC_Object ((CORBA_TypeCode)&TC_Object_struct)
++#define TC_string ((CORBA_TypeCode)&TC_string_struct)
++#define TC_wstring ((CORBA_TypeCode)&TC_wstring_struct)
++#define TC_CORBA_NamedValue ((CORBA_TypeCode)&TC_CORBA_NamedValue_struct)
++
++#define TC_CORBA_short_struct TC_short_struct
++#define TC_CORBA_long_struct TC_long_struct
++#define TC_CORBA_longlong_struct TC_longlong_struct
++#define TC_CORBA_long_long_struct TC_longlong_struct
++#define TC_CORBA_ushort_struct TC_ushort_struct
++#define TC_CORBA_unsigned_short_struct TC_ushort_struct
++#define TC_CORBA_ulong_struct TC_ulong_struct
++#define TC_CORBA_unsigned_long_struct TC_ulong_struct
++#define TC_CORBA_ulonglong_struct TC_ulonglong_struct
++#define TC_CORBA_unsigned_long_long_struct TC_ulonglong_struct
++#define TC_CORBA_float_struct TC_float_struct
++#define TC_CORBA_double_struct TC_double_struct
++#define TC_CORBA_longdouble_struct TC_longdouble_struct
++#define TC_CORBA_long_double_struct TC_longdouble_struct
++#define TC_CORBA_boolean_struct TC_boolean_struct
++#define TC_CORBA_char_struct TC_char_struct
++#define TC_CORBA_wchar_struct TC_wchar_struct
++#define TC_CORBA_octet_struct TC_octet_struct
++#define TC_CORBA_any_struct TC_any_struct
++#define TC_CORBA_TypeCode_struct TC_TypeCode_struct
++#define TC_CORBA_Principal_struct TC_Principal_struct
++#define TC_CORBA_Object_struct TC_Object_struct
++#define TC_CORBA_string_struct TC_string_struct
++#define TC_CORBA_wstring_struct TC_wstring_struct
++
++extern const struct CORBA_TypeCode_struct TC_null_struct;
++extern const struct CORBA_TypeCode_struct TC_void_struct;
++extern const struct CORBA_TypeCode_struct TC_short_struct;
++extern const struct CORBA_TypeCode_struct TC_long_struct;
++extern const struct CORBA_TypeCode_struct TC_longlong_struct;
++extern const struct CORBA_TypeCode_struct TC_ushort_struct;
++extern const struct CORBA_TypeCode_struct TC_ulong_struct;
++extern const struct CORBA_TypeCode_struct TC_ulonglong_struct;
++extern const struct CORBA_TypeCode_struct TC_float_struct;
++extern const struct CORBA_TypeCode_struct TC_double_struct;
++extern const struct CORBA_TypeCode_struct TC_longdouble_struct;
++extern const struct CORBA_TypeCode_struct TC_boolean_struct;
++extern const struct CORBA_TypeCode_struct TC_char_struct;
++extern const struct CORBA_TypeCode_struct TC_wchar_struct;
++extern const struct CORBA_TypeCode_struct TC_octet_struct;
++extern const struct CORBA_TypeCode_struct TC_any_struct;
++extern const struct CORBA_TypeCode_struct TC_TypeCode_struct;
++extern const struct CORBA_TypeCode_struct TC_Principal_struct;
++extern const struct CORBA_TypeCode_struct TC_Object_struct;
++extern const struct CORBA_TypeCode_struct TC_string_struct;
++extern const struct CORBA_TypeCode_struct TC_wstring_struct;
++extern const struct CORBA_TypeCode_struct TC_CORBA_NamedValue_struct;
++
++
++#endif /* !_ORBIT_CORBA_TYPECODE_H_ */
++
++
++
++
+diff -urN linux-2.4.1/net/korbit/orb/corba_typecode_type.h linux-2.4.1-korbit/net/korbit/orb/corba_typecode_type.h
+--- linux-2.4.1/net/korbit/orb/corba_typecode_type.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/corba_typecode_type.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,66 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_CORBA_TYPECODE_TYPE_H_
++#define _ORBIT_CORBA_TYPECODE_TYPE_H_
++
++#include <ORBitutil/basic_types.h>
++#include "corba_typecode.h"
++#include "corba_any.h"
++
++typedef struct CORBA_TypeCode_Bounds {
++ int dummy;
++} CORBA_TypeCode_Bounds;
++
++typedef struct CORBA_TypeCode_BadKind {
++ int dummy;
++} CORBA_TypeCode_BadKind;
++
++struct CORBA_TypeCode_struct {
++ struct ORBit_PseudoObject_struct parent;
++ CORBA_TCKind kind;
++#ifndef __KORBIT__
++ const
++#endif
++ char *name;
++#ifndef __KORBIT__
++ const
++#endif
++ char *repo_id;
++ CORBA_unsigned_long length;
++ CORBA_unsigned_long sub_parts;
++ const char **subnames; /* for struct, exception, union, enum */
++ CORBA_TypeCode *subtypes; /* for struct, exception, union, alias, array, sequence */
++ CORBA_any *sublabels; /* for union */
++ CORBA_TypeCode discriminator; /* for union */
++ CORBA_unsigned_long recurse_depth; /* for recursive sequence */
++ CORBA_long default_index; /* for union */
++ CORBA_unsigned_short digits; /* for fixed */
++ CORBA_short scale; /* for fixed */
++};
++
++
++#endif /* !_ORBIT_CORBA_TYPECODE_TYPE_H_ */
++
+diff -urN linux-2.4.1/net/korbit/orb/dii.c linux-2.4.1-korbit/net/korbit/orb/dii.c
+--- linux-2.4.1/net/korbit/orb/dii.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/dii.c Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,454 @@
++/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Red Hat Software, Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Elliot Lee <sopwith@redhat.com>
++ * Dick Porter <dick@cymru.net>
++ *
++ */
++
++#include <stdlib.h>
++#include <string.h>
++#include <assert.h>
++
++#include "orbit.h"
++#ifndef __KORBIT__
++#include "interface_repository.h"
++#endif /* !__KORBIT__ */
++
++struct CORBA_Request_type {
++ struct ORBit_PseudoObject_struct parent;
++
++ CORBA_Object obj;
++ CORBA_Context ctx;
++
++ CORBA_Flags req_flags;
++ CORBA_Identifier operation;
++
++ CORBA_NamedValue *result;
++ CORBA_NVList *arg_list;
++
++ CORBA_unsigned_long request_id;
++ GIOPSendBuffer *request_buffer;
++ GIOPRecvBuffer *reply_buffer;
++};
++
++static const ORBit_RootObject_Interface interface_CORBA_Request = {
++ (void (*)(gpointer,CORBA_Environment *))CORBA_Request_delete
++};
++
++/* Section 5.2.1 */
++CORBA_Status
++CORBA_Object_create_request(CORBA_Object obj,
++ CORBA_Context ctx,
++ CORBA_Identifier operation,
++ CORBA_NVList *arg_list,
++ CORBA_NamedValue *result,
++ CORBA_Request *request,
++ CORBA_Flags req_flags,
++ CORBA_Environment *ev)
++{
++ CORBA_Request new;
++
++ new=g_new0(struct CORBA_Request_type, 1);
++ ORBit_pseudo_object_init((ORBit_PseudoObject)new, ORBIT_PSEUDO_REQUEST, ev);
++ ORBit_RootObject_set_interface((ORBit_RootObject)new,
++ (ORBit_RootObject_Interface *)&interface_CORBA_Request, ev);
++
++ if(new==NULL) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_NO_MEMORY,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ new->obj=CORBA_Object_duplicate(obj, ev);
++ new->ctx=(CORBA_Context)CORBA_Object_duplicate((CORBA_Object)ctx, ev);
++ new->operation=CORBA_string_dup(operation);
++
++ new->result=result;
++
++ new->req_flags=req_flags;
++ new->request_id = giop_get_request_id();
++ new->arg_list = arg_list;
++
++ *request=(CORBA_Request)CORBA_Object_duplicate((CORBA_Object)new, ev);
++}
++
++/* Section 5.2, 5.2.2 */
++CORBA_Status
++CORBA_Request_add_arg(CORBA_Request req,
++ CORBA_Identifier name,
++ CORBA_TypeCode arg_type,
++ void *value,
++ CORBA_long len,
++ CORBA_Flags arg_flags,
++ CORBA_Environment *ev)
++{
++ gpointer new_value;
++
++ g_assert(req!=NULL);
++
++ if((arg_flags & CORBA_IN_COPY_VALUE) && (arg_flags & CORBA_ARG_IN)) {
++ new_value = ORBit_copy_value(value, arg_type);
++ if(new_value==NULL) {
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++ } else
++ new_value=value;
++
++ CORBA_NVList_add_item(req->arg_list, name, arg_type,
++ new_value, len, arg_flags | req->req_flags, ev);
++}
++
++/* Section 5.2, 5.2.3 */
++CORBA_Status
++CORBA_Request_invoke(CORBA_Request req,
++ CORBA_Flags invoke_flags,
++ CORBA_Environment *ev)
++{
++ CORBA_Request_send(req, invoke_flags, ev);
++ if(ev->_major == CORBA_NO_EXCEPTION)
++ CORBA_Request_get_response(req, invoke_flags, ev);
++}
++
++/* Section 5.2, 5.2.4 */
++CORBA_Status CORBA_Request_delete(CORBA_Request req, CORBA_Environment *ev)
++{
++ CORBA_Object_release(req->obj, ev);
++ CORBA_Object_release((CORBA_Object)req->ctx, ev);
++
++ if(req->operation != NULL)
++ CORBA_free(req->operation);
++
++ if(req->arg_list != NULL) {
++ if(req->req_flags & CORBA_OUT_LIST_MEMORY)
++ CORBA_NVList_free(req->arg_list, ev);
++ else {
++ int i;
++ for(i = 0; i < req->arg_list->list->len; i++)
++ ORBit_NamedValue_free(&g_array_index(req->arg_list->list,
++ CORBA_NamedValue, i));
++ g_array_free(req->arg_list->list, TRUE);
++
++ g_free(req->arg_list);
++ }
++ }
++
++ if(req->result!=NULL)
++ ORBit_NamedValue_free(req->result);
++
++ if(req->request_buffer)
++ giop_send_buffer_unuse(req->request_buffer);
++
++ if(req->reply_buffer)
++ giop_recv_buffer_unuse(req->reply_buffer);
++
++ g_free(req);
++}
++
++/* Section 5.2, 5.3.1 */
++CORBA_Status
++CORBA_Request_send(CORBA_Request req,
++ CORBA_Flags invoke_flags,
++ CORBA_Environment *ev)
++{
++ int i;
++ GIOPConnection *cnx;
++
++ struct { CORBA_unsigned_long opstrlen; char opname[1]; } *opnameinfo;
++ struct iovec opvec = { NULL, 0 };
++
++ opvec.iov_len = strlen(req->operation)+1+sizeof(CORBA_unsigned_long);
++
++ opnameinfo = g_malloc(strlen(req->operation)+1+sizeof(CORBA_unsigned_long));
++ opvec.iov_base = (gpointer)opnameinfo;
++ opnameinfo->opstrlen = strlen(req->operation) + 1;
++ strcpy(opnameinfo->opname, req->operation);
++
++ cnx = ORBit_object_get_connection(req->obj);
++
++ g_assert(req->obj->active_profile);
++ req->request_buffer =
++ giop_send_request_buffer_use(req->obj->connection,
++ NULL,
++ req->request_id,
++ req->result?TRUE:FALSE,
++ &(req->obj->active_profile->object_key_vec),
++ &opvec,
++ &ORBit_default_principal_iovec
++ );
++
++ if(!req->request_buffer) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_COMM_FAILURE,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ for(i = 0; i < req->arg_list->list->len; i++) {
++ CORBA_NamedValue *nv;
++
++ nv = &g_array_index(req->arg_list->list, CORBA_NamedValue, i);
++
++ if((nv->arg_modes & CORBA_ARG_IN)
++ || (nv->arg_modes & CORBA_ARG_INOUT))
++ ORBit_marshal_arg(req->request_buffer,
++ nv->argument._value,
++ nv->argument._type);
++ }
++
++ giop_send_buffer_write(req->request_buffer);
++
++ giop_send_buffer_unuse(req->request_buffer);
++ req->request_buffer = 0;
++
++ g_free(opnameinfo);
++}
++
++/* Section 5.3.2 */
++CORBA_Status
++CORBA_send_multiple_requests(CORBA_Request *reqs,
++ CORBA_Environment *env,
++ CORBA_long count,
++ CORBA_Flags invoke_flags)
++{
++ int i;
++
++ for(i = 0; i < count; i++)
++ CORBA_Request_send(reqs[i], invoke_flags, env);
++}
++
++void
++ORBit_handle_dii_reply(CORBA_Request req, CORBA_Environment *ev)
++{
++ int i;
++
++ /* XXX TODO - handle exceptions, location forwards(?), all that */
++ req->result->argument._value =
++ ORBit_demarshal_arg(req->reply_buffer, req->result->argument._type,
++ TRUE, req->obj->orb);
++ req->result->argument._release = CORBA_TRUE;
++
++ for(i = 0; i < req->arg_list->list->len; i++) {
++ CORBA_NamedValue *nv;
++
++ nv = &g_array_index(req->arg_list->list, CORBA_NamedValue, i);
++
++ if(nv->arg_modes & CORBA_ARG_INOUT) {
++ CORBA_Object_duplicate((CORBA_Object)nv->argument._type, NULL);
++ CORBA_any__free(&nv->argument, NULL, TRUE);
++ }
++
++ if((nv->arg_modes & CORBA_ARG_OUT)
++ || (nv->arg_modes & CORBA_ARG_INOUT))
++ nv->argument._value = ORBit_demarshal_arg(req->reply_buffer,
++ nv->argument._type,
++ TRUE, req->obj->orb);
++ }
++
++ giop_recv_buffer_unuse(req->reply_buffer);
++ req->reply_buffer = 0;
++}
++
++/* Section 5.2, 5.3.3
++ *
++ * Raises: WrongTransaction
++ */
++CORBA_Status
++CORBA_Request_get_response(CORBA_Request req,
++ CORBA_Flags response_flags,
++ CORBA_Environment *ev)
++{
++ req->reply_buffer = giop_recv_reply_buffer_use(req->request_id,
++ !(response_flags & CORBA_RESP_NO_WAIT));
++
++ if(!req->reply_buffer) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_COMM_FAILURE,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ ORBit_handle_dii_reply(req, ev);
++}
++
++/* Section 5.3.4
++ *
++ * Raises: WrongTransaction
++ */
++CORBA_Status
++CORBA_Request_get_next_response(CORBA_Environment *env,
++ CORBA_Flags response_flags,
++ CORBA_Request *req)
++{
++ int i;
++ GIOPRecvBuffer *rb;
++ GArray *reqids = g_array_new(FALSE, FALSE,
++ sizeof(CORBA_unsigned_long));
++
++ for(i = 0; req[i]; i++) {
++ g_array_append_val(reqids, req[i]->request_id);
++ }
++
++ rb = giop_recv_reply_buffer_use_multiple(reqids,
++ !(response_flags & CORBA_RESP_NO_WAIT));
++
++ if(rb) {
++ for(i = 0; i < reqids->len; i++) {
++ if(g_array_index(reqids, CORBA_unsigned_long, i)
++ == rb->message.u.reply.request_id) {
++ req[i]->reply_buffer = rb;
++ break;
++ }
++ }
++
++ if(i < reqids->len)
++ ORBit_handle_dii_reply(req[i], env);
++ }
++
++ g_array_free(reqids, TRUE);
++}
++
++
++/* Section 5.4.1 */
++CORBA_Status
++CORBA_ORB_create_list(CORBA_ORB orb,
++ CORBA_long count,
++ CORBA_NVList **new_list,
++ CORBA_Environment *ev)
++{
++ CORBA_NVList *new;
++
++ new = g_new0(CORBA_NVList, 1);
++ if(new==NULL) goto new_alloc_failed;
++
++ new->list = g_array_new(FALSE, TRUE, sizeof(CORBA_NamedValue));
++
++ *new_list = new;
++
++ return;
++
++ new_alloc_failed:
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++}
++
++#ifndef __KORBIT__
++/* Section 5.4.6 */
++CORBA_Status
++CORBA_ORB_create_operation_list(CORBA_ORB orb,
++ CORBA_OperationDef oper,
++ CORBA_NVList **new_list,
++ CORBA_Environment *ev)
++{
++ if(!new_list) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ g_warning("CORBA_ORB_create_operation_list NYI");
++
++ CORBA_exception_set_system(ev,
++ ex_CORBA_IMP_LIMIT,
++ CORBA_COMPLETED_NO);
++}
++#endif /* !__KORBIT__ */
++
++/* Section 5.4.2 */
++CORBA_Status
++CORBA_NVList_add_item(CORBA_NVList *list,
++ CORBA_Identifier item_name,
++ CORBA_TypeCode item_type,
++ void *value,
++ CORBA_long value_len,
++ CORBA_Flags item_flags,
++ CORBA_Environment *ev)
++{
++ CORBA_NamedValue newval;
++
++ g_assert(list!=NULL);
++
++ newval.name = CORBA_string_dup(item_name);
++ newval.argument._type = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)item_type, ev);
++ if(item_flags & CORBA_IN_COPY_VALUE) {
++ newval.argument._value = ORBit_copy_value(value, item_type);
++ newval.argument._release = CORBA_TRUE;
++ } else {
++ newval.argument._value = value;
++ newval.argument._release = CORBA_FALSE;
++ }
++
++ newval.len = value_len; /* Is this even useful? *sigh* */
++ newval.arg_modes = item_flags;
++
++ g_array_append_val(list->list, newval);
++}
++
++void ORBit_NamedValue_free(CORBA_NamedValue *nv)
++{
++ CORBA_free(nv->name);
++}
++
++/* Section 5.4.3 */
++CORBA_Status
++CORBA_NVList_free(CORBA_NVList *list,
++ CORBA_Environment *ev)
++{
++ int i;
++
++ CORBA_NVList_free_memory(list, ev);
++
++ for(i = 0; i < list->list->len; i++)
++ ORBit_NamedValue_free(&g_array_index(list->list, CORBA_NamedValue, i));
++
++ g_array_free(list->list, TRUE);
++
++ g_free(list);
++}
++
++/* Section 5.4.4 */
++CORBA_Status
++CORBA_NVList_free_memory(CORBA_NVList *list,
++ CORBA_Environment *ev)
++{
++ int i;
++
++ for(i = 0; i < list->list->len; i++) {
++ CORBA_free(g_array_index(list->list, CORBA_NamedValue, i).argument._value);
++ g_array_index(list->list, CORBA_NamedValue, i).argument._value = NULL;
++ CORBA_Object_release((CORBA_Object)g_array_index(list->list, CORBA_NamedValue, i).argument._type, ev);
++ g_array_index(list->list, CORBA_NamedValue, i).argument._release = CORBA_FALSE;
++ }
++}
++
++
++/* Section 5.4.5 */
++CORBA_Status
++CORBA_NVList_get_count(CORBA_NVList *list,
++ CORBA_long *count,
++ CORBA_Environment *ev)
++{
++ *count = list->list->len;
++}
++
+diff -urN linux-2.4.1/net/korbit/orb/dii.h linux-2.4.1-korbit/net/korbit/orb/dii.h
+--- linux-2.4.1/net/korbit/orb/dii.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/dii.h Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,124 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_DII_H_
++#define _ORBIT_DII_H_
++
++#include "orb/orbit_types.h"
++#ifndef __KORBIT__
++#include "orb/interface_repository.h"
++#endif /* !__KORBIT__ */
++
++extern CORBA_Status CORBA_Object_create_request(
++ CORBA_Object obj,
++ CORBA_Context ctx,
++ CORBA_Identifier operation,
++ CORBA_NVList *arg_list,
++ CORBA_NamedValue *result,
++ CORBA_Request *request,
++ CORBA_Flags req_flags,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_Request_add_arg(
++ CORBA_Request req,
++ CORBA_Identifier name,
++ CORBA_TypeCode arg_type,
++ void *value,
++ CORBA_long len,
++ CORBA_Flags arg_flags,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_Request_invoke(
++ CORBA_Request req,
++ CORBA_Flags invoke_flags,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_Request_delete(
++ CORBA_Request req,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_Request_send(
++ CORBA_Request req,
++ CORBA_Flags invoke_flags,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_send_multiple_requests(
++ CORBA_Request reqs[],
++ CORBA_Environment *env,
++ CORBA_long count,
++ CORBA_Flags invoke_flags);
++
++extern CORBA_Status CORBA_Request_get_response(
++ CORBA_Request req,
++ CORBA_Flags response_flags,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_get_next_response(
++ CORBA_Environment *env,
++ CORBA_Flags response_flags,
++ CORBA_Request *req);
++
++extern CORBA_Status CORBA_NVList_add_item(
++ CORBA_NVList *list,
++ CORBA_Identifier item_name,
++ CORBA_TypeCode item_type,
++ void *value,
++ CORBA_long value_len,
++ CORBA_Flags item_flags,
++ CORBA_Environment *ev);
++
++extern void ORBit_NamedValue_free(
++ CORBA_NamedValue *nv);
++
++
++extern CORBA_Status CORBA_ORB_create_list(
++ CORBA_ORB orb,
++ CORBA_long count,
++ CORBA_NVList **new_list,
++ CORBA_Environment *ev);
++
++#ifndef __KORBIT__
++extern CORBA_Status CORBA_ORB_create_operation_list(
++ CORBA_ORB orb,
++ CORBA_OperationDef oper,
++ CORBA_NVList **new_list,
++ CORBA_Environment *ev);
++#endif /* !__KORBIT__ */
++
++extern CORBA_Status CORBA_NVList_free(CORBA_NVList *list,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_NVList_free_memory(
++ CORBA_NVList *list,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_NVList_get_count(
++ CORBA_NVList *list,
++ CORBA_long *count,
++ CORBA_Environment *ev);
++
++extern const int sizeofs[], container_sizeofs[];
++
++#endif /* _ORBIT_DII_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/env.c linux-2.4.1-korbit/net/korbit/orb/env.c
+--- linux-2.4.1/net/korbit/orb/env.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/env.c Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,345 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++/*
++ * CORBA_Environment handling functions
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <assert.h>
++
++#include "orbit.h"
++#ifndef __KORBIT__
++#include "interface_repository.h"
++#endif /* !__KORBIT__ */
++
++struct SysExInfo {
++ const char *repo_id;
++ const int exnum;
++};
++
++static const struct SysExInfo exception_table[] = {
++ {NULL, 0},
++ {"IDL:CORBA/UNKNOWN:1.0", 1},
++ {"IDL:CORBA/BAD_PARAM:1.0", 2},
++ {"IDL:CORBA/NO_MEMORY:1.0", 3},
++ {"IDL:CORBA/IMP_LIMIT:1.0", 4},
++ {"IDL:CORBA/COMM_FAILURE:1.0", 5},
++ {"IDL:CORBA/INV_OBJREF:1.0", 6},
++ {"IDL:CORBA/NO_PERMISSION:1.0", 7},
++ {"IDL:CORBA/INTERNAL:1.0", 8},
++ {"IDL:CORBA/MARSHAL:1.0", 9},
++ {"IDL:CORBA/INITIALIZE:1.0", 10},
++ {"IDL:CORBA/NO_IMPLEMENT:1.0", 11},
++ {"IDL:CORBA/BAD_TYPECODE:1.0", 12},
++ {"IDL:CORBA/BAD_OPERATION:1.0", 13},
++ {"IDL:CORBA/NO_RESOURCES:1.0", 14},
++ {"IDL:CORBA/NO_RESPONSE:1.0", 15},
++ {"IDL:CORBA/PERSIST_STORE:1.0", 16},
++ {"IDL:CORBA/BAD_INV_ORDER:1.0", 17},
++ {"IDL:CORBA/TRANSIENT:1.0", 18},
++ {"IDL:CORBA/FREE_MEM:1.0", 19},
++ {"IDL:CORBA/INV_IDENT:1.0", 20},
++ {"IDL:CORBA/INV_FLAG:1.0", 21},
++ {"IDL:CORBA/INTF_REPOS:1.0", 22},
++ {"IDL:CORBA/BAD_CONTEXT:1.0", 23},
++ {"IDL:CORBA/OBJ_ADAPTER:1.0", 24},
++ {"IDL:CORBA/DATA_CONVERSION:1.0", 25},
++ {"IDL:CORBA/OBJECT_NOT_EXIST:1.0", 26},
++ {"IDL:CORBA/TRANSACTION_REQUIRED:1.0", 27},
++ {"IDL:CORBA/TRANSACTION_ROLLEDBACK:1.0", 28},
++ {"IDL:CORBA/INVALID_TRANSACTION:1.0", 29},
++ {NULL,0}
++};
++
++void CORBA_exception_free(CORBA_Environment *ev)
++{
++ g_assert(ev!=NULL);
++
++ ev->_major=CORBA_NO_EXCEPTION;
++
++ if(ev->_repo_id) {
++ CORBA_free(ev->_repo_id);
++ ev->_repo_id=NULL;
++ }
++
++ if(ev->_params) {
++ CORBA_free(ev->_params);
++ ev->_params=NULL;
++ }
++
++ if(ev->_any) {
++ CORBA_free(ev->_any);
++ ev->_any=NULL;
++ }
++}
++
++void CORBA_exception_set(CORBA_Environment *ev, CORBA_exception_type major,
++ const CORBA_char *except_repos_id, void *param)
++{
++ g_assert(ev!=NULL);
++
++ if(ev->_major != CORBA_NO_EXCEPTION)
++ CORBA_exception_free(ev);
++
++ ev->_major=major;
++
++ if(except_repos_id==NULL) {
++ ev->_repo_id=NULL;
++ } else {
++ ev->_repo_id=CORBA_string_dup(except_repos_id);
++ }
++
++ ev->_params=param;
++}
++
++void CORBA_exception_set_system(CORBA_Environment *ev, CORBA_unsigned_long ex_value,
++ CORBA_completion_status completed)
++{
++ CORBA_SystemException *new;
++
++ new=ORBit_alloc(sizeof(CORBA_SystemException), NULL, NULL);
++ if(new!=NULL) {
++ new->minor=0;
++ new->completed=completed;
++
++ /* XXX what should the repo ID be? */
++ CORBA_exception_set(ev, CORBA_SYSTEM_EXCEPTION,
++ exception_table[ex_value].repo_id,
++ new);
++ }
++}
++
++void CORBA_exception_init(CORBA_Environment *ev)
++{
++ g_assert(ev!=NULL);
++
++ ev->_major=CORBA_NO_EXCEPTION;
++ ev->_repo_id=NULL;
++ ev->_params=NULL;
++ ev->_any=NULL;
++}
++
++CORBA_char *CORBA_exception_id(CORBA_Environment *ev)
++{
++ g_assert(ev!=NULL);
++
++ if(ev->_major==CORBA_NO_EXCEPTION) {
++ return(NULL);
++ } else {
++ return(ev->_repo_id);
++ }
++}
++
++void *CORBA_exception_value(CORBA_Environment *ev)
++{
++ g_assert(ev!=NULL);
++
++ if(ev->_major==CORBA_NO_EXCEPTION) {
++ return(NULL);
++ } else {
++ return(ev->_params);
++ }
++}
++
++#ifndef __KORBIT__
++CORBA_any *CORBA_exception_as_any(CORBA_Environment *ev)
++{
++ g_assert(ev!=NULL);
++
++ if(ev->_major==CORBA_NO_EXCEPTION) {
++ return(NULL);
++ }
++
++ if(ev->_any!=NULL) {
++ return(ev->_any);
++ }
++
++ ev->_any=g_new(CORBA_any, 1);
++ if(ev->_any!=NULL) {
++ /* XXX is this the correct type? */
++ ev->_any->_type = (CORBA_TypeCode)TC_CORBA_ExceptionDescription;
++ ev->_any->_value = ev->_params;
++ ev->_any->_release = 0;
++ }
++
++ return(ev->_any);
++}
++#endif /* !__KORBIT__ */
++
++/**** ORBit_handle_exception
++ Inputs: 'rb' - a receive buffer for which an exception condition has
++ been determined
++ 'ev' - memory in which to store the exception information
++
++ 'user_exceptions' - list of user exceptions raisable
++ for this particular operation.
++ Side-effects: reinitializes '*ev'
++
++ Description:
++ During demarshalling a reply, if reply_status != CORBA_NO_EXCEPTION,
++ we must find out what exception was raised and place that information
++ in '*ev'. */
++
++void ORBit_handle_exception(GIOPRecvBuffer *rb, CORBA_Environment *ev,
++ const ORBit_exception_demarshal_info *user_exceptions,
++ CORBA_ORB orb)
++{
++ CORBA_SystemException *new;
++ CORBA_unsigned_long len, completion_status;
++ CORBA_char *my_repoid;
++
++ g_return_if_fail(GIOP_MESSAGE_BUFFER(rb)->message_header.message_type == GIOP_REPLY);
++
++ CORBA_exception_free(ev);
++
++ rb->cur = ALIGN_ADDRESS(rb->cur, sizeof(len));
++ rb->decoder(&len, rb->cur, sizeof(len));
++ /* (guchar *)rb->cur += sizeof(len); */
++ rb->cur = ((guchar *)rb->cur) + sizeof(len);
++
++ if(len) {
++ my_repoid = rb->cur;
++ rb->cur = ((guchar *)rb->cur) + len;
++ } else
++ my_repoid = NULL;
++
++ if(rb->message.u.reply.reply_status == CORBA_SYSTEM_EXCEPTION) {
++ CORBA_unsigned_long minor;
++
++ ev->_major = CORBA_SYSTEM_EXCEPTION;
++
++ rb->cur = ALIGN_ADDRESS(rb->cur, sizeof(minor));
++ rb->decoder(&minor, rb->cur, sizeof(minor));
++ rb->cur = ((guchar *)rb->cur) + sizeof(minor);
++
++ rb->cur = ALIGN_ADDRESS(rb->cur, sizeof(completion_status));
++ rb->decoder(&completion_status, rb->cur, sizeof(completion_status));
++ rb->cur = ((guchar *)rb->cur) + sizeof(completion_status);
++
++ new=ORBit_alloc(sizeof(CORBA_SystemException), NULL, NULL);
++
++ if(new!=NULL) {
++ new->minor=minor;
++ new->completed=completion_status;
++
++ /* XXX what should the repo ID be? */
++ CORBA_exception_set(ev, CORBA_SYSTEM_EXCEPTION,
++ my_repoid,
++ new);
++ }
++ } else if(rb->message.u.reply.reply_status == CORBA_USER_EXCEPTION) {
++ int i;
++
++ if(!user_exceptions) {
++ /* weirdness; they raised an exception that we don't
++ know about */
++ CORBA_exception_set_system(ev, ex_CORBA_MARSHAL,
++ CORBA_COMPLETED_MAYBE);
++ } else {
++ for(i = 0; user_exceptions[i].tc != CORBA_OBJECT_NIL;
++ i++) {
++ if(!strcmp(user_exceptions[i].tc->repo_id,
++ my_repoid))
++ break;
++ }
++
++ if(user_exceptions[i].tc == CORBA_OBJECT_NIL) {
++ /* weirdness; they raised an exception
++ that we don't know about */
++ CORBA_exception_set_system(ev, ex_CORBA_MARSHAL,
++ CORBA_COMPLETED_MAYBE);
++ } else {
++ user_exceptions[i].demarshal(rb, ev);
++ }
++ }
++ };
++
++ /* ignore LOCATION_FORWARD here, that gets handled in the stub */
++}
++
++void
++ORBit_send_system_exception(GIOPSendBuffer *send_buffer,
++ CORBA_Environment *ev)
++{
++ CORBA_unsigned_long minor;
++ CORBA_unsigned_long completion_status;
++ CORBA_SystemException *se = ev->_params;
++
++ minor = se->minor;
++ completion_status = se->completed;
++
++ ENCODER_CALL(CORBA_char, ev->_repo_id);
++ giop_send_buffer_append_mem_indirect_a(send_buffer, &minor,
++ sizeof(minor));
++ giop_send_buffer_append_mem_indirect_a(send_buffer,
++ &completion_status,
++ sizeof(completion_status));
++}
++
++void
++ORBit_send_user_exception(GIOPSendBuffer *send_buffer,
++ CORBA_Environment *ev,
++ const ORBit_exception_marshal_info *user_exceptions)
++{
++ int i;
++
++ for(i = 0; user_exceptions[i].tc != CORBA_OBJECT_NIL; i++) {
++ if(!strcmp(user_exceptions[i].tc->repo_id, ev->_repo_id))
++ break;
++ }
++
++ if(user_exceptions[i].tc == CORBA_OBJECT_NIL) {
++ CORBA_Environment fakeev;
++ CORBA_exception_init(&fakeev);
++ CORBA_exception_set_system(&fakeev, ex_CORBA_UNKNOWN,
++ CORBA_COMPLETED_MAYBE);
++ ORBit_send_system_exception(send_buffer, &fakeev);
++ CORBA_exception_free(&fakeev);
++ } else {
++ ENCODER_CALL(CORBA_char, ev->_repo_id);
++
++ if(user_exceptions[i].marshal && ev->_params)
++ user_exceptions[i].marshal(send_buffer, ev);
++ }
++}
++
++void
++ORBit_handle_system_exception(CORBA_Environment *ev,
++ CORBA_unsigned_long system_exception_minor,
++ CORBA_unsigned_long completion_status,
++ GIOPRecvBuffer *recv_buffer,
++ GIOPSendBuffer *send_buffer)
++{
++ CORBA_exception_set_system(ev, system_exception_minor, completion_status);
++
++ if(send_buffer)
++ giop_send_buffer_unuse(send_buffer);
++
++ if(recv_buffer)
++ giop_recv_buffer_unuse(recv_buffer);
++}
+diff -urN linux-2.4.1/net/korbit/orb/env.h linux-2.4.1-korbit/net/korbit/orb/env.h
+--- linux-2.4.1/net/korbit/orb/env.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/env.h Thu Feb 1 16:21:56 2001
+@@ -0,0 +1,79 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998, 1999 Richard H. Porter, Red Hat Software
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_ENV_H_
++#define _ORBIT_ENV_H_
++
++#include "orbit_types.h"
++
++extern void CORBA_exception_set(CORBA_Environment *ev,
++ CORBA_exception_type major,
++ const CORBA_char *except_repos_id,
++ void *param);
++
++extern void CORBA_exception_set_system(CORBA_Environment *ev,
++ CORBA_unsigned_long ex_value,
++ CORBA_completion_status completed);
++
++extern void CORBA_exception_init(CORBA_Environment *ev);
++
++extern CORBA_char *CORBA_exception_id(CORBA_Environment *e);
++
++extern void *CORBA_exception_value(CORBA_Environment *ev);
++
++extern void CORBA_exception_free(CORBA_Environment *ev);
++
++#ifndef __KORBIT__
++extern CORBA_any *CORBA_exception_as_any(CORBA_Environment *ev);
++#endif /* !__KORBIT__ */
++
++typedef struct {
++ const CORBA_TypeCode tc;
++ void (*demarshal)(GIOPRecvBuffer *_ORBIT_recv_buffer, CORBA_Environment *ev);
++} ORBit_exception_demarshal_info;
++
++typedef struct {
++ const CORBA_TypeCode tc;
++ void (*marshal)(GIOPSendBuffer *_ORBIT_send_buffer, CORBA_Environment *ev);
++} ORBit_exception_marshal_info;
++
++/* ORBit-specific */
++void ORBit_handle_exception(GIOPRecvBuffer *rb, CORBA_Environment *ev,
++ const ORBit_exception_demarshal_info *user_exceptions,
++ CORBA_ORB orb);
++void ORBit_send_system_exception(GIOPSendBuffer *send_buffer,
++ CORBA_Environment *ev);
++void ORBit_send_user_exception(GIOPSendBuffer *send_buffer,
++ CORBA_Environment *ev,
++ const ORBit_exception_marshal_info *user_exceptions);
++
++/* Used by stubs */
++void ORBit_handle_system_exception(CORBA_Environment *ev,
++ CORBA_unsigned_long system_exception_minor,
++ CORBA_unsigned_long completion_status,
++ GIOPRecvBuffer *recv_buffer,
++ GIOPSendBuffer *send_buffer);
++
++#endif /* !_ORBIT_ENV_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/genrand.c linux-2.4.1-korbit/net/korbit/orb/genrand.c
+--- linux-2.4.1/net/korbit/orb/genrand.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/genrand.c Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,131 @@
++#include "genrand.h"
++#include "ORBitutil/util.h"
++#include <unistd.h>
++#include <sys/types.h>
++#include <fcntl.h>
++#include <glib.h>
++#include <signal.h>
++#include <sys/time.h>
++#include <limits.h>
++#include <stdio.h>
++#ifdef __KERNEL__
++#include <linux/random.h>
++#endif
++
++static gboolean
++genrand_dev(guchar *buffer, int buf_len)
++{
++#ifdef __KERNEL__
++ get_random_bytes(buffer, buf_len);
++#else /*! __KERNEL__*/
++ int fd;
++
++ fd = open("/dev/urandom", O_RDONLY);
++ if(fd < 0)
++ return FALSE;
++
++ if(read(fd, buffer, buf_len) < buf_len)
++ {
++ close(fd);
++ return FALSE;
++ }
++
++ close(fd);
++#endif /*! __KERNEL__*/
++
++ return TRUE;
++}
++
++#ifndef __KORBIT__
++static volatile int received_alarm = 0;
++
++static void
++handle_alarm(int signum)
++{
++ received_alarm = 1;
++}
++
++static inline guchar
++hashlong(long val)
++{
++ guchar retval, *ptr;
++ int i;
++
++ for(ptr = (guchar *)&val, i = 0; i < sizeof(val); i++)
++ retval ^= ptr[i];
++
++ return retval;
++}
++
++static gboolean
++genrand_unix(guchar *buffer, int buf_len)
++{
++ struct sigaction sa, oldsa;
++ struct itimerval it, oldit;
++ int i;
++ long min, max;
++ long *counts;
++ double diff;
++ long *uninit;
++
++ counts = alloca(buf_len * sizeof(long));
++
++ memset(&sa, 0, sizeof(sa));
++ sa.sa_handler = handle_alarm;
++ sigaction(SIGALRM, &sa, &oldsa);
++ memset(&it, 0, sizeof(it));
++ it.it_value.tv_usec = 1;
++ getitimer(ITIMER_REAL, &oldit);
++
++ for(i = 0, min = LONG_MAX, max = 0; i < buf_len; i++)
++ {
++ received_alarm = 0;
++ setitimer(ITIMER_REAL, &it, NULL);
++ for(counts[i] = 0; !received_alarm; counts[i]++);
++
++ max = MAX(counts[i], max);
++ min = MIN(counts[i], min);
++ }
++
++ if(!(max - min))
++ {
++ freeca(counts);
++ return FALSE;
++ }
++
++ diff = max - min;
++
++ uninit = alloca(buf_len * sizeof(long)); /* Purposely not initialized */
++ for(i = 0; i < buf_len; i++)
++ {
++ long diffval;
++ diffval = counts[i] - min;
++
++ buffer[i] ^= (guchar)( ((double) (diffval*256) / diff )) ^ hashlong(uninit[i]);
++ }
++
++ setitimer(ITIMER_REAL, &oldit, NULL);
++ sigaction(SIGALRM, &oldsa, NULL);
++
++ freeca(counts);
++ freeca(uninit);
++
++ return TRUE;
++}
++#endif /* !__KORBIT__ */
++
++void
++orbit_genrand(guchar *buffer, int buf_len)
++{
++ g_return_if_fail(buf_len);
++
++ if(genrand_dev(buffer, buf_len))
++ return;
++#ifndef __KORBIT__
++ else if(genrand_unix(buffer, buf_len))
++ return;
++#endif
++ else
++ g_error("Couldn't generate random data!");
++}
++
+diff -urN linux-2.4.1/net/korbit/orb/genrand.h linux-2.4.1-korbit/net/korbit/orb/genrand.h
+--- linux-2.4.1/net/korbit/orb/genrand.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/genrand.h Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,8 @@
++#ifndef ORBIT_GENRAND_H
++#define ORBIT_GENRAND_H 1
++
++#include <glib.h>
++
++void orbit_genrand(guchar *buffer, int buf_len);
++
++#endif /* ORBIT_GENRAND_H */
+diff -urN linux-2.4.1/net/korbit/orb/iop.h linux-2.4.1-korbit/net/korbit/orb/iop.h
+--- linux-2.4.1/net/korbit/orb/iop.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/iop.h Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,207 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_IOP_H_
++#define _ORBIT_IOP_H_
++
++#include <ORBitutil/basic_types.h>
++
++#include <orb/corba_basic_sequences_type.h>
++
++#ifndef HAVE_CORBA_PRINCIPAL
++#define HAVE_CORBA_PRINCIPAL 1
++typedef CORBA_sequence_octet CORBA_Principal;
++#endif
++
++typedef CORBA_unsigned_long IOP_ProfileId;
++
++#define IOP_TAG_INTERNET_IOP 0
++#define IOP_TAG_MULTIPLE_COMPONENTS 1
++#define IOP_TAG_ORBIT_SPECIFIC 0xbadfaecal
++
++typedef struct IOP_TaggedProfile {
++ IOP_ProfileId tag;
++ CORBA_sequence_octet profile_data;
++} IOP_TaggedProfile;
++
++typedef struct CORBA_sequence_TaggedProfile {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ IOP_TaggedProfile *_buffer;
++} CORBA_sequence_TaggedProfile;
++
++typedef struct IOP_IOR {
++ CORBA_char *type_id;
++ CORBA_sequence_TaggedProfile profiles;
++} IOP_IOR;
++
++typedef CORBA_unsigned_long IOP_ComponentId;
++
++typedef struct IOP_TaggedComponent {
++ IOP_ComponentId tag;
++ CORBA_sequence_octet component_data;
++} IOP_TaggedComponent;
++
++typedef struct CORBA_sequence_TaggedComponent {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ IOP_TaggedComponent *_buffer;
++} CORBA_sequence_TaggedComponent;
++
++typedef struct CORBA_sequence_TaggedComponent IOP_MultipleComponentProfile;
++
++#define IOP_TAG_ORB_TYPE 0
++#define IOP_TAG_CODE_SETS 1
++#define IOP_TAG_SEC_NAME 14
++#define IOP_TAG_ASSOCIATION_OPTIONS 13
++#define IOP_TAG_GENERIC_SEC_MECH 12
++
++typedef CORBA_unsigned_long IOP_ServiceId;
++
++typedef struct IOP_ServiceContext {
++ IOP_ServiceId context_id;
++ CORBA_sequence_octet context_data;
++} IOP_ServiceContext;
++
++typedef struct CORBA_sequence_ServiceContext {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ IOP_ServiceContext *_buffer;
++} CORBA_sequence_ServiceContext;
++
++typedef struct CORBA_sequence_ServiceContext IOP_ServiceContextList;
++
++#define IOP_TransactionService 0
++#define IOP_CodeSets 1
++
++typedef CORBA_unsigned_long CONV_FRAME_CodeSetId;
++
++typedef struct CORBA_sequence_CodeSetId {
++ CORBA_unsigned_long _maximum;
++ CORBA_unsigned_long _length;
++ CONV_FRAME_CodeSetId *_buffer;
++} CORBA_sequence_CodeSetId;
++
++typedef struct CONV_FRAME_CodeSetComponent {
++ CONV_FRAME_CodeSetId native_code_set;
++ CORBA_sequence_CodeSetId conversion_code_sets;
++} CONV_FRAME_CodeSetComponent;
++
++typedef struct CONV_FRAME_CodeSetComponentInfo {
++ CONV_FRAME_CodeSetComponent ForCharData;
++ CONV_FRAME_CodeSetComponent ForWcharData;
++} CONV_FRAME_CodeSetComponentInfo;
++
++typedef struct CONV_FRAME_CodeSetContext {
++ CONV_FRAME_CodeSetId char_data;
++ CONV_FRAME_CodeSetId wchar_data;
++} CONV_FRAME_CodeSetContext;
++
++typedef struct GIOP_Version {
++ CORBA_octet major;
++ CORBA_octet minor;
++} GIOP_Version;
++
++typedef enum {
++ GIOP_Request=0,
++ GIOP_Reply,
++ GIOP_CancelRequest,
++ GIOP_LocateRequest,
++ GIOP_LocateReply,
++ GIOP_CloseConnection,
++ GIOP_MessageError
++} GIOP_MsgType_1_0;
++
++typedef struct GIOP_MessageHeader_1_0 {
++ CORBA_char magic[4];
++ GIOP_Version GIOP_version;
++ CORBA_boolean byte_order;
++ CORBA_octet message_type;
++ CORBA_unsigned_long message_size;
++} GIOP_MessageHeader_1_0;
++
++typedef struct GIOP_MessageHeader_1_1 {
++ CORBA_char magic[4];
++ GIOP_Version GIOP_version;
++ CORBA_octet flags;
++ CORBA_octet message_type;
++ CORBA_unsigned_long message_size;
++} GIOP_MessageHeader_1_1;
++
++typedef struct GIOP_RequestHeader_1_0 {
++ IOP_ServiceContextList service_context;
++ CORBA_unsigned_long request_id;
++ CORBA_boolean response_expected;
++ CORBA_sequence_octet object_key;
++ CORBA_char *operation;
++ CORBA_Principal requesting_principal;
++} GIOP_RequestHeader_1_0;
++
++typedef struct GIOP_RequestHeader_1_1 {
++ IOP_ServiceContextList service_context;
++ CORBA_unsigned_long request_id;
++ CORBA_boolean response_expected;
++ CORBA_octet reserved[3];
++ CORBA_sequence_octet object_key;
++ CORBA_char *operation;
++ CORBA_Principal requesting_principal;
++} GIOP_RequestHeader_1_1;
++
++typedef struct GIOP_SystemExceptionReplyBody {
++ CORBA_char *exception_id;
++ CORBA_unsigned_long minor_code_value;
++ CORBA_unsigned_long completion_status;
++} GIOP_SystemExceptionReplyBody;
++
++typedef struct GIOP_CancelRequestHeader {
++ CORBA_unsigned_long request_id;
++} GIOP_CancelRequestHeader;
++
++typedef struct GIOP_LocateRequestHeader {
++ CORBA_unsigned_long request_id;
++ CORBA_sequence_octet object_key;
++} GIOP_LocateRequestHeader;
++
++typedef struct IIOP_Version {
++ CORBA_octet major;
++ CORBA_octet minor;
++} IIOP_Version;
++
++typedef struct IIOP_ProfileBody_1_0 {
++ IIOP_Version iiop_version;
++ CORBA_char *host;
++ CORBA_unsigned_short port;
++ CORBA_sequence_octet object_key;
++} IIOP_ProfileBody_1_0;
++
++typedef struct IIOP_ProfileBody_1_1 {
++ IIOP_Version iiop_version;
++ CORBA_char *host;
++ CORBA_unsigned_short port;
++ CORBA_sequence_octet object_key;
++ CORBA_sequence_TaggedComponent components;
++} IIOP_ProfileBody_1_1;
++
++#endif /* !_ORBIT_IOP_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/ir.c linux-2.4.1-korbit/net/korbit/orb/ir.c
+--- linux-2.4.1/net/korbit/orb/ir.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/ir.c Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,293 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#include <stdlib.h>
++#include <assert.h>
++
++#include "orbit.h"
++
++/* FIXME: Right now this function doesn't record whether or not it has
++ already visited a given TypeCode. I'm not sure if every recursive
++ type will have a tk_recursive node in it; if not, then this will
++ need to be reworked a bit. */
++CORBA_boolean CORBA_TypeCode_equal(CORBA_TypeCode obj, CORBA_TypeCode tc, CORBA_Environment *ev)
++{
++ int i;
++
++ g_return_val_if_fail(obj!=NULL, CORBA_FALSE);
++ g_return_val_if_fail(tc!=NULL, CORBA_FALSE);
++
++ if (obj->kind != tc->kind) {
++ return CORBA_FALSE;
++ }
++
++ switch (obj->kind) {
++ case CORBA_tk_wstring:
++ case CORBA_tk_string:
++ return obj->length == tc->length;
++ case CORBA_tk_objref:
++ return ! strcmp (obj->repo_id, tc->repo_id);
++ case CORBA_tk_except:
++ case CORBA_tk_struct:
++ if (strcmp (obj->repo_id, tc->repo_id)
++ || obj->sub_parts != tc->sub_parts)
++ return CORBA_FALSE;
++ for (i = 0; i < obj->sub_parts; ++i)
++ if (! CORBA_TypeCode_equal (obj->subtypes[i],
++ tc->subtypes[i], ev))
++ return CORBA_FALSE;
++ break;
++ case CORBA_tk_union:
++ if (strcmp (obj->repo_id, tc->repo_id)
++ || obj->sub_parts != tc->sub_parts
++ || ! CORBA_TypeCode_equal (obj->discriminator,
++ tc->discriminator, ev)
++ || obj->default_index != tc->default_index)
++ return CORBA_FALSE;
++ for (i = 0; i < obj->sub_parts; ++i)
++
++ if (! CORBA_TypeCode_equal (obj->subtypes[i],
++ tc->subtypes[i], ev)
++ || ! ORBit_any_equivalent (obj->sublabels[i],
++ tc->sublabels[i], ev))
++ return CORBA_FALSE;
++
++ break;
++ case CORBA_tk_enum:
++ if (obj->sub_parts != tc->sub_parts
++ || strcmp (obj->repo_id, tc->repo_id))
++ return CORBA_FALSE;
++ for (i = 0; i < obj->sub_parts; ++i)
++ if (strcmp (obj->subnames[i], tc->subnames[i]))
++ return CORBA_FALSE;
++ break;
++ case CORBA_tk_sequence:
++ case CORBA_tk_array:
++ if (obj->length != tc->length)
++ return CORBA_FALSE;
++ g_assert (obj->sub_parts == 1);
++ g_assert (tc->sub_parts == 1);
++ return CORBA_TypeCode_equal (obj->subtypes[0], tc->subtypes[0],
++ ev);
++ case CORBA_tk_alias:
++ if (strcmp (obj->repo_id, tc->repo_id))
++ return CORBA_FALSE;
++
++ g_assert (obj->sub_parts == 1);
++ g_assert (tc->sub_parts == 1);
++
++ return CORBA_TypeCode_equal (obj->subtypes[0], tc->subtypes[0],
++ ev);
++ break;
++ case CORBA_tk_recursive:
++ return obj->recurse_depth == tc->recurse_depth;
++ case CORBA_tk_fixed:
++ return obj->digits == tc->digits && obj->scale == tc->scale;
++
++ default:
++ /* Everything else is primitive. */
++ break;
++ }
++
++ return CORBA_TRUE;
++}
++
++CORBA_TCKind CORBA_TypeCode_kind(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ return obj->kind;
++}
++
++static void bad_kind (CORBA_Environment *ev)
++{
++ CORBA_TypeCode_BadKind *err;
++ err = g_new (CORBA_TypeCode_BadKind, 1);
++ if (err == NULL) {
++ CORBA_exception_set_system (ev, ex_CORBA_NO_MEMORY,
++ CORBA_COMPLETED_NO);
++ } else {
++ err->dummy = 23;
++ CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
++ "IDL:omg.org/CORBA/TypeCode/BadKind/1.0",
++ err);
++ }
++}
++
++CORBA_RepositoryId CORBA_TypeCode_id(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ if (! (obj->kind == CORBA_tk_objref || obj->kind == CORBA_tk_struct
++ || obj->kind == CORBA_tk_enum || obj->kind == CORBA_tk_alias
++ || obj->kind == CORBA_tk_except)) {
++ bad_kind (ev);
++ return NULL;
++ }
++ return obj->repo_id;
++}
++
++CORBA_Identifier CORBA_TypeCode_name(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ if (! (obj->kind == CORBA_tk_objref || obj->kind == CORBA_tk_struct
++ || obj->kind == CORBA_tk_enum || obj->kind == CORBA_tk_alias
++ || obj->kind == CORBA_tk_except)) {
++ bad_kind (ev);
++ return NULL;
++ }
++
++ return obj->name;
++}
++
++CORBA_unsigned_long CORBA_TypeCode_member_count(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ if (! (obj->kind == CORBA_tk_struct || obj->kind == CORBA_tk_union
++ || obj->kind == CORBA_tk_enum)) {
++ bad_kind (ev);
++ return 0;
++ }
++ return obj->sub_parts;
++}
++
++static void bounds_error (CORBA_Environment *ev)
++{
++ CORBA_TypeCode_Bounds *err;
++ err = g_new (CORBA_TypeCode_Bounds, 1);
++ if (err == NULL) {
++ CORBA_exception_set_system (ev, ex_CORBA_NO_MEMORY,
++ CORBA_COMPLETED_NO);
++ } else {
++ err->dummy = 23;
++ CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
++ "IDL:omg.org/CORBA/TypeCode/Bounds/1.0",
++ err);
++ }
++}
++
++CORBA_Identifier CORBA_TypeCode_member_name(CORBA_TypeCode obj, CORBA_unsigned_long index, CORBA_Environment *ev)
++{
++ if (! (obj->kind == CORBA_tk_struct || obj->kind == CORBA_tk_union
++ || obj->kind == CORBA_tk_enum)) {
++ bad_kind (ev);
++ return NULL;
++ }
++ if (index > obj->sub_parts) {
++ bounds_error (ev);
++ return NULL;
++ }
++ return obj->subnames[index];
++}
++
++CORBA_TypeCode CORBA_TypeCode_member_type(CORBA_TypeCode obj, CORBA_unsigned_long index, CORBA_Environment *ev)
++{
++ if (! (obj->kind == CORBA_tk_struct || obj->kind == CORBA_tk_union
++ || obj->kind == CORBA_tk_enum)) {
++ bad_kind (ev);
++ return NULL;
++ }
++ if (index > obj->sub_parts) {
++ bounds_error (ev);
++ return NULL;
++ }
++ return obj->subtypes[index];
++}
++
++CORBA_any *CORBA_TypeCode_member_label(CORBA_TypeCode obj, CORBA_unsigned_long index, CORBA_Environment *ev)
++{
++ if (obj->kind != CORBA_tk_union) {
++ bad_kind (ev);
++ return NULL;
++ }
++ if (index > obj->sub_parts) {
++ bounds_error (ev);
++ return NULL;
++ }
++ return &obj->sublabels[index];
++}
++
++CORBA_TypeCode CORBA_TypeCode_discriminator_type(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ if (obj->kind != CORBA_tk_union) {
++ bad_kind (ev);
++ return NULL;
++ }
++ return obj->discriminator;
++}
++
++CORBA_long CORBA_TypeCode_default_index(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ if (obj->kind != CORBA_tk_union) {
++ bad_kind (ev);
++ return 0;
++ }
++ return obj->default_index;
++}
++
++CORBA_unsigned_long CORBA_TypeCode_length(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ if (! (obj->kind == CORBA_tk_string || obj->kind == CORBA_tk_wstring
++ || obj->kind == CORBA_tk_array)) {
++ bad_kind (ev);
++ return 0;
++ }
++ return obj->length;
++}
++
++CORBA_TypeCode CORBA_TypeCode_content_type(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ if (! (obj->kind == CORBA_tk_sequence || obj->kind == CORBA_tk_array
++ || obj->kind == CORBA_tk_alias)) {
++ bad_kind (ev);
++ return NULL;
++ }
++ g_assert (obj->sub_parts == 1);
++ return obj->subtypes[0];
++}
++
++CORBA_unsigned_short CORBA_TypeCode_fixed_digits(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ if (obj->kind != CORBA_tk_fixed) {
++ bad_kind (ev);
++ return 0;
++ }
++ return obj->digits;
++}
++
++CORBA_short CORBA_TypeCode_fixed_scale(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ if (obj->kind != CORBA_tk_fixed) {
++ bad_kind (ev);
++ return 0;
++ }
++ return obj->scale;
++}
++
++CORBA_long CORBA_TypeCode_param_count(CORBA_TypeCode obj, CORBA_Environment *ev)
++{
++ g_assert(!"Deprecated");
++ return(0);
++}
++
++CORBA_any *CORBA_TypeCode_parameter(CORBA_TypeCode obj, CORBA_long index, CORBA_Environment *ev)
++{
++ g_assert(!"Deprecated");
++ return(NULL);
++}
+diff -urN linux-2.4.1/net/korbit/orb/ir.h linux-2.4.1-korbit/net/korbit/orb/ir.h
+--- linux-2.4.1/net/korbit/orb/ir.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/ir.h Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,100 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_IR_H_
++#define _ORBIT_IR_H_
++
++#include "orbit_types.h"
++
++extern CORBA_boolean CORBA_TypeCode_equal(
++ CORBA_TypeCode obj,
++ CORBA_TypeCode tc,
++ CORBA_Environment *ev);
++
++extern CORBA_TCKind CORBA_TypeCode_kind(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_RepositoryId CORBA_TypeCode_id(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_Identifier CORBA_TypeCode_name(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_unsigned_long CORBA_TypeCode_member_count(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_Identifier CORBA_TypeCode_member_name(
++ CORBA_TypeCode obj,
++ CORBA_unsigned_long index,
++ CORBA_Environment *ev);
++
++extern CORBA_TypeCode CORBA_TypeCode_member_type(
++ CORBA_TypeCode obj,
++ CORBA_unsigned_long index,
++ CORBA_Environment *ev);
++
++extern CORBA_any *CORBA_TypeCode_member_label(
++ CORBA_TypeCode obj,
++ CORBA_unsigned_long index,
++ CORBA_Environment *ev);
++
++extern CORBA_TypeCode CORBA_TypeCode_discriminator_type(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_long CORBA_TypeCode_default_index(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_unsigned_long CORBA_TypeCode_length(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_TypeCode CORBA_TypeCode_content_type(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_unsigned_short CORBA_TypeCode_fixed_digits(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_short CORBA_TypeCode_fixed_scale(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_long CORBA_TypeCode_param_count(
++ CORBA_TypeCode obj,
++ CORBA_Environment *ev);
++
++extern CORBA_any *CORBA_TypeCode_parameter(
++ CORBA_TypeCode obj,
++ CORBA_long index,
++ CORBA_Environment *ev);
++
++#endif /* !_ORBIT_IR_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/options.c linux-2.4.1-korbit/net/korbit/orb/options.c
+--- linux-2.4.1/net/korbit/orb/options.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/options.c Thu Feb 1 11:47:12 2001
+@@ -0,0 +1,160 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++/*
++ * Option parsing
++ *
++ * All ORB options are stripped from the application's argv, and argc is
++ * adjusted accordingly
++ */
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <glib.h>
++
++#include "options.h"
++
++#ifndef __KORBIT__
++void ORBit_option_set(ORBit_orb_options *option, const char *val)
++{
++ g_assert(option!=NULL);
++
++ if(option->type==no_arg && option->arg!=NULL) {
++ /* Treat as an int arg with val=1
++ */
++ int *int_arg=(int *)option->arg;
++
++ *int_arg=1;
++ } else {
++ if(option->type==string_arg && option->arg!=NULL) {
++ char **str_arg=(char **)option->arg;
++
++ /* free any existing value */
++ if(*str_arg!=NULL) {
++ g_free(*str_arg);
++ }
++ *str_arg=g_strdup(val);
++ } else if(option->type==int_arg && option->arg!=NULL) {
++ int *int_arg=(int *)option->arg;
++
++ *int_arg=atoi(val);
++ }
++
++ }
++}
++
++void ORBit_option_parse(int *argc, char **argv, ORBit_orb_options *options)
++{
++ int i,j,numargs;
++ char name[1024], *val;
++ ORBit_orb_options *search=NULL;
++ int *erase;
++
++ numargs=*argc;
++
++ erase=g_new0(int, *argc);
++
++ for(i=1; i< *argc; i++) {
++ if(argv[i][0]!='-') {
++ if(search==NULL) {
++ /* Skip non-option */
++ continue;
++ } else {
++ /* an required option value has been found */
++ erase[i]=1;
++ numargs-=1;
++
++ if(search->arg==NULL) {
++ /* dont store any values, just strip
++ * the argv
++ */
++ search=NULL;
++ continue;
++ }
++
++ ORBit_option_set(search, argv[i]);
++
++ search=NULL;
++ continue;
++ }
++ } else {
++ if(search!=NULL &&
++ (search->type==string_arg || search->type==int_arg)) {
++ fprintf(stderr, "Option %s requires an argument\n", search->name);
++ }
++ }
++
++ val=argv[i];
++ while(*val && *val=='-')
++ val++;
++
++ strncpy(name,val,1023);
++ name[1023]='\0';
++
++ val=strchr(name, '=');
++ if(val!=NULL) {
++ *val++='\0';
++ }
++
++ for(search=options;search->name!=NULL;search++) {
++ if(!strcmp(name, search->name)) {
++ break;
++ }
++ }
++
++ if(search->name==NULL) {
++ /* Didn't find it in our list of interesting options */
++ search=NULL;
++ } else {
++ /* Found it */
++ erase[i]=1;
++ numargs-=1;
++
++ if(search->type==no_arg || val!=NULL) {
++ ORBit_option_set(search, val);
++ search=NULL;
++ }
++ }
++ }
++
++ j=1;
++ for(i=1; i< *argc; i++) {
++ if(erase[i]==1) {
++ continue;
++ } else {
++ if(j<numargs) {
++ argv[j++]=argv[i];
++ } else {
++ argv[j++]='\0';
++ }
++ }
++ }
++
++ *argc=numargs;
++
++ g_free(erase);
++}
++#endif /* !__KORBIT__ */
+diff -urN linux-2.4.1/net/korbit/orb/options.h linux-2.4.1-korbit/net/korbit/orb/options.h
+--- linux-2.4.1/net/korbit/orb/options.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/options.h Thu Feb 1 11:47:13 2001
+@@ -0,0 +1,46 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_OPTIONS_H_
++#define _ORBIT_OPTIONS_H_
++
++typedef enum {
++ no_arg=0,
++ string_arg,
++ int_arg
++} ORBit_opt_type;
++
++typedef struct {
++ char *name;
++ ORBit_opt_type type;
++ void *arg;
++} ORBit_orb_options;
++
++#ifndef __KORBIT__
++extern void ORBit_option_set(ORBit_orb_options *found, const char *val);
++extern void ORBit_option_parse(int *argc, char **argv, ORBit_orb_options *options);
++#endif
++
++#endif /* !_ORBIT_OPTIONS_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/orb.c linux-2.4.1-korbit/net/korbit/orb/orb.c
+--- linux-2.4.1/net/korbit/orb/orb.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orb.c Thu Feb 1 11:47:13 2001
+@@ -0,0 +1,1700 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@acm.org>
++ * Elliot Lee <sopwith@redhat.com>
++ *
++ */
++
++#define o_return_val_if_fail(expr, val) if(!(expr)) { CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM, CORBA_COMPLETED_NO); return (val); }
++#define o_return_if_fail(expr) if(!(expr)) { CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM, CORBA_COMPLETED_NO); return; }
++
++#include "config.h"
++
++#include <unistd.h>
++#include <errno.h>
++#include <sys/stat.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <ctype.h>
++#include <assert.h>
++#include <pwd.h>
++#include <time.h>
++#include <sys/types.h>
++#include <dirent.h>
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#include <utime.h>
++
++#include "../IIOP/iiop-endianP.h"
++#include "orbit.h"
++
++#include "orbit_poa.h"
++#include "orbit_object.h"
++#include "orbit_object_type.h"
++
++#ifndef __KERNEL__
++#define freeca(ptr)
++#endif
++
++#ifndef SUN_LEN
++/* This system is not POSIX.1g. */
++#define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
++ + strlen ((ptr)->sun_path))
++#endif
++
++static void ORBit_ORB_release(CORBA_ORB orb, CORBA_Environment *ev);
++
++static const ORBit_RootObject_Interface CORBA_ORB_epv =
++{
++ (void (*)(gpointer, CORBA_Environment *))ORBit_ORB_release
++};
++
++
++static int ORBit_ORBid_setup(CORBA_ORB orb, CORBA_ORBid id)
++{
++ g_assert(orb!=NULL);
++ g_assert(id!=NULL);
++
++ if(strcmp(id, "orbit-local-orb")) {
++#ifdef __KORBIT__
++ printf("ORBit_ORBid_setup: Unknown ORB id: %s\n", id);
++#else
++ fprintf(stderr, "ORBit_ORBid_setup: Unknown ORB id: %s\n", id);
++#endif
++ return(0);
++ }
++
++ orb->orb_identifier=g_strdup(id);
++
++ return(1);
++}
++
++#ifndef __KORBIT__
++static gboolean
++free_key_and_data(gpointer key, gpointer data, gpointer user_data)
++{
++ g_free(key); g_free(data);
++
++ return TRUE;
++}
++
++static void ORBit_rc_load(const char *rcfile, ORBit_orb_options *options)
++{
++ FILE *fp;
++ GHashTable *read_options;
++ ORBit_orb_options *search;
++
++ fp=fopen(rcfile, "r");
++
++ if(fp==NULL)
++ return;
++
++ read_options=g_hash_table_new(g_str_hash, g_str_equal);
++
++ while(!feof(fp)) {
++ char buf[1024];
++
++ if(fgets(buf, 1024, fp)!=NULL) {
++ guchar *bptr, *tmp, *key, *data;
++ size_t start, len;
++
++ if(buf[0]=='#')
++ continue;
++
++ bptr=buf;
++ tmp=strpbrk(bptr, " \t\n=");
++ if(tmp==NULL) continue;
++ *tmp++='\0';
++ key=g_strdup(bptr);
++ bptr=tmp;
++
++ start=0;
++ while(bptr+start != '\0' &&
++ (isspace(bptr[start]) || bptr[start]=='='))
++ start++;
++ len=strcspn(bptr+start, " \t\n");
++ bptr[start+len]='\0';
++ if(len>0) {
++ data=g_strdup(bptr+start);
++ } else {
++ data=g_strdup("TRUE");
++ }
++
++ g_hash_table_insert(read_options, key, data);
++ }
++ }
++ fclose(fp);
++
++ for(search=options;search->name!=NULL;search++) {
++ char *read_val;
++
++ read_val=g_hash_table_lookup(read_options, search->name);
++ if(read_val!=NULL) {
++ ORBit_option_set(search, read_val);
++ }
++ }
++
++ g_hash_table_foreach_remove(read_options, free_key_and_data, NULL);
++ g_hash_table_destroy(read_options);
++}
++#endif /* !__KORBIT__ */
++
++static void ORBit_ORB_release(CORBA_ORB orb, CORBA_Environment *ev)
++{
++ g_assert(orb!=NULL);
++
++ if(--(ORBIT_ROOT_OBJECT(orb)->refs))
++ return;
++
++ if(orb->orb_identifier!=NULL) {
++ g_free(orb->orb_identifier);
++ }
++ if(!CORBA_Object_is_nil(orb->imr, ev)) {
++ CORBA_Object_release(orb->imr, ev);
++ }
++ if(!CORBA_Object_is_nil(orb->ir, ev)) {
++ CORBA_Object_release(orb->ir, ev);
++ }
++ if(!CORBA_Object_is_nil(orb->naming, ev)) {
++ CORBA_Object_release(orb->naming, ev);
++ }
++ if(!CORBA_Object_is_nil(orb->root_poa, ev)) {
++ CORBA_Object_release(orb->root_poa, ev);
++ }
++ if(orb->cnx.ipv4)
++ giop_connection_unref(orb->cnx.ipv4);
++ if(orb->cnx.ipv6)
++ giop_connection_unref(orb->cnx.ipv6);
++#ifndef __KORBIT__
++ if(orb->cnx.usock)
++ giop_connection_unref(orb->cnx.usock);
++#endif
++
++ g_free(orb);
++}
++
++#ifndef __KORBIT__
++static GIOPConnection*
++ORBit_ORB_make_usock_connection(void)
++{
++ GIOPConnection *retval = NULL;
++ GString *tmpstr;
++ struct stat statbuf;
++
++ tmpstr = g_string_new(NULL);
++
++ g_string_sprintf(tmpstr, "/tmp/orbit-%s", g_get_user_name());
++
++ if(mkdir(tmpstr->str, 0700) != 0) {
++ int e = errno;
++
++ switch (e) {
++ case 0:
++ case EEXIST:
++ if (stat(tmpstr->str, &statbuf) != 0)
++ g_error ("Can not stat %s\n", tmpstr->str);
++
++ if (statbuf.st_uid != getuid ())
++ g_error ("Owner of %s is not the current user\n",
++ tmpstr->str);
++
++ if((statbuf.st_mode & (S_IRWXG|S_IRWXO))
++ || !S_ISDIR(statbuf.st_mode))
++ g_error ("Wrong permissions for %s\n",
++ tmpstr->str);
++ break;
++
++ default:
++ g_error("Unknown error on directory creation of %s (%s)\n",
++ tmpstr->str, g_strerror (e));
++ }
++ }
++
++ {
++ struct utimbuf utb;
++ memset(&utb, 0, sizeof(utb));
++ utime(tmpstr->str, &utb);
++ }
++
++
++#ifdef WE_DONT_CARE_ABOUT_STUPID_2DOT0DOTX_KERNELS
++ g_string_sprintf(tmpstr, "/tmp/orbit-%s",
++ g_get_user_name());
++ dirh = opendir(tmpstr->str);
++ while(!retval && (dent = readdir(dirh))) {
++ int usfd, ret;
++ struct sockaddr_un saddr;
++
++ saddr.sun_family = AF_UNIX;
++
++ if(strncmp(dent->d_name, "orb-", 4))
++ continue;
++
++ g_snprintf(saddr.sun_path, sizeof(saddr.sun_path),
++ "/tmp/orbit-%s/%s",
++ g_get_user_name(), dent->d_name);
++
++ usfd = socket(AF_UNIX, SOCK_STREAM, 0);
++ g_assert(usfd >= 0);
++
++ ret = connect(usfd, &saddr, SUN_LEN(&saddr));
++ close(usfd);
++
++ if(ret >= 0)
++ continue;
++
++ unlink(saddr.sun_path);
++ }
++ closedir(dirh);
++#endif /* WE_DONT_CARE_ABOUT_STUPID_2DOT0DOTX_KERNELS */
++
++ srand(time(NULL));
++ while(!retval) {
++ g_string_sprintf(tmpstr, "/tmp/orbit-%s/orb-%d%d",
++ g_get_user_name(), rand(), rand());
++ retval =
++ GIOP_CONNECTION(iiop_connection_server_unix(tmpstr->str));
++ }
++
++ g_string_free(tmpstr, TRUE);
++
++ return retval;
++}
++#endif /* !__KORBIT__ */
++
++
++// Synchronize between the user process starting up the orb and the ORB thread
++// this mutex gets released when the orb is all fired up and ready to go.
++static DECLARE_MUTEX(StartupSem);
++static CORBA_ORB TheOneTrueOrb = 0;
++
++struct CORBA_ORB_init_args { // A pointer to this struct is passed to
++ int *argc; // __CORBA_ORB_init
++ char **argv;
++ CORBA_ORBid orb_identifier;
++ CORBA_Environment *ev;
++};
++
++
++CORBA_ORB __CORBA_ORB_init(struct CORBA_ORB_init_args *Args) {
++ int *argc = Args->argc;
++ char **argv = Args->argv;
++ CORBA_ORBid orb_identifier = Args->orb_identifier;
++ CORBA_Environment *ev = Args->ev;
++
++ int no_iiop_server=0;
++ int no_iiop_proxy=0;
++#ifdef __KORBIT__
++ int use_ipv4=1;
++#else
++ int use_ipv4=0;
++#endif
++ int use_ipv6=0;
++ int use_usock=1;
++ int debug_level=0;
++ int debug_modules=0;
++ int nosysrc=0;
++ int nouserrc=0;
++ char *imr_ior=NULL, *imr_addr=NULL;
++ char *ir_ior=NULL, *ir_addr=NULL;
++ char *naming_ior=NULL, *naming_addr=NULL;
++ char *root_poa_ior=NULL, *root_poa_addr=NULL;
++ char *orb_id_opt=NULL;
++#ifndef __KORBIT__
++ char *ctmp;
++#endif
++ CORBA_ORB orb = 0;
++
++ /* The variable addresses in these structs need to be assigned at
++ * run-time if you want to compile with -pedantic
++ *
++ * (You will also get scads of warnings about "long long" too)
++ */
++
++ ORBit_orb_options pre_rc_options[]={
++ {"ORBNoSystemRC", no_arg, NULL},
++ {"ORBNoUserRC", no_arg, NULL},
++ {NULL, 0, NULL},
++ };
++
++ /* These options are compatible with MICO */
++ ORBit_orb_options options[]={
++ {"ORBNoIIOPServer", no_arg, NULL},
++ {"ORBNoIIOPProxy", no_arg, NULL},
++ {"ORBid", string_arg, NULL},
++ {"ORBImplRepoIOR", string_arg, NULL},
++ {"ORBImplRepoAddr", string_arg, NULL},
++ {"ORBIfaceRepoIOR", string_arg, NULL},
++ {"ORBIfaceRepoAddr", string_arg, NULL},
++ {"ORBNamingIOR", string_arg, NULL},
++ {"ORBNamingAddr", string_arg, NULL},
++ {"ORBDebugLevel", int_arg, NULL},
++ {"ORBBindAddr", string_arg, NULL}, /* XXX need to make
++ libIIOP support this */
++ {"ORBIIOPAddr", string_arg, NULL},
++
++ /* These options aren't */
++ {"ORBDebugModules", int_arg, NULL},
++ {"ORBRootPOAIOR", string_arg, NULL},
++ {"ORBRootPOAAddr", string_arg, NULL},
++ {"ORBIIOPUSock", int_arg, NULL},
++ {"ORBIIOPIPv4", int_arg, NULL},
++ {"ORBIIOPIPv6", int_arg, NULL},
++ {NULL,0,NULL},
++ };
++
++ if (ev == NULL || !argc || !argv || !orb_identifier) {
++ if (ev) {
++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ }
++ up(&StartupSem); // Okay, let the insmod thread continue...
++ return 0;
++ }
++
++ pre_rc_options[0].arg = (void *) &nosysrc;
++ pre_rc_options[1].arg = (void *) &nouserrc;
++ options[0].arg = (void *) &no_iiop_server;
++ options[1].arg = (void *) &no_iiop_proxy;
++ options[2].arg = (void *) &orb_id_opt;
++ options[3].arg = (void *) &imr_ior;
++ options[4].arg = (void *) &imr_addr;
++ options[5].arg = (void *) &ir_ior;
++ options[6].arg = (void *) &ir_addr;
++ options[7].arg = (void *) &naming_ior;
++ options[8].arg = (void *) &naming_addr;
++ options[9].arg = (void *) &debug_level;
++ options[12].arg = (void *) &debug_modules;
++ options[13].arg = (void *) &root_poa_ior;
++ options[14].arg = (void *) &root_poa_addr;
++ options[15].arg = (void *) &use_usock;
++ options[16].arg = (void *) &use_ipv4;
++ options[17].arg = (void *) &use_ipv6;
++
++#ifndef __KORBIT__
++ ORBit_option_parse(argc, argv, pre_rc_options);
++
++ if(!nosysrc) {
++ ORBit_rc_load(ORBit_SYSRC, options);
++ }
++
++ if(!nouserrc) {
++ char *buf;
++
++ ctmp = g_get_home_dir();
++
++ buf = alloca(strlen(ctmp) + sizeof("/.orbitrc"));
++ sprintf(buf, "%s/.orbitrc", ctmp);
++ ORBit_rc_load(buf, options);
++ freeca(buf);
++ }
++
++ ORBit_option_parse(argc, argv, options);
++#endif /* !__KORBIT__ */
++
++ ORBit_Trace_setLevel(debug_level);
++ ORBit_Trace_setModules(debug_modules);
++
++ CORBA_exception_init(ev);
++
++ ORBit_chunks_init();
++
++ giop_init(argv[0]);
++
++ orb=g_new0(struct CORBA_ORB_type, 1);
++
++ if(orb==NULL) {
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ goto error;
++ }
++
++ ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(orb), ORBIT_PSEUDO_ORB, ev);
++
++ ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(orb),
++ (gpointer)&CORBA_ORB_epv, ev);
++
++ ORBIT_ROOT_OBJECT(orb)->refs = 1;
++
++ if(orb_id_opt!=NULL) {
++ if(!ORBit_ORBid_setup(orb, orb_id_opt))
++ goto error;
++ g_free(orb_id_opt);
++ } else if(orb_identifier!=NULL) {
++ if(!ORBit_ORBid_setup(orb, orb_identifier))
++ goto error;
++ } else {
++ orb->orb_identifier=g_strdup("orbit-local-orb");
++ }
++
++ if(orb->orb_identifier==NULL) {
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ goto error;
++ }
++
++ if(use_ipv4) {
++ orb->cnx.ipv4 = GIOP_CONNECTION(iiop_connection_server());
++
++ giop_connection_ref(orb->cnx.ipv4);
++ GIOP_CONNECTION(orb->cnx.ipv4)->orb_data = orb;
++ }
++
++ if(use_ipv6) {
++ orb->cnx.ipv6 = GIOP_CONNECTION(iiop_connection_server_ipv6());
++ giop_connection_ref(orb->cnx.ipv6);
++ GIOP_CONNECTION(orb->cnx.ipv6)->orb_data = orb;
++ }
++
++#ifndef __KORBIT__
++ if(use_usock) {
++ orb->cnx.usock = ORBit_ORB_make_usock_connection();
++
++ giop_connection_ref(orb->cnx.usock);
++ GIOP_CONNECTION(orb->cnx.usock)->orb_data = orb;
++ }
++#endif
++
++ orb->objrefs = g_hash_table_new((GHashFunc)g_CORBA_Object_hash,
++ (GCompareFunc)g_CORBA_Object_equal);
++ orb->poas = g_ptr_array_new();
++
++ /* when I figure out what MICO is doing with the iiop_proxy and
++ * iiop_server stuff, it'll get handled here.
++ */
++
++ /*
++ * Connect to / create implementation repository
++ */
++
++ {
++ CORBA_Object imr=NULL;
++
++ if(imr_ior!=NULL) {
++ imr=CORBA_ORB_string_to_object(orb, imr_ior, ev);
++ g_free(imr_ior);
++ } else if(imr_addr!=NULL) {
++ /*imr=CORBA_ORB_bind(orb, "IDL:omg.org/CORBA/ImplRepository:1.0", imr_addr, ev);*/
++ g_free(imr_addr);
++ }
++
++ if(!CORBA_Object_is_nil(imr, ev)) {
++ CORBA_ORB_set_initial_reference(orb, "ImplementationRepository", imr, ev);
++ }
++ }
++
++ /*
++ * Connect to / create interface repository
++ */
++
++ {
++ CORBA_Object ir=NULL;
++
++ if(ir_ior!=NULL) {
++ ir=CORBA_ORB_string_to_object(orb, ir_ior, ev);
++ g_free(ir_ior);
++ } else if(ir_addr!=NULL) {
++ /*ir=CORBA_ORB_bind(orb, "IDL:omg.org/CORBA/Repository:1.0", ir_addr, ev);*/
++ g_free(ir_addr);
++ }
++
++ if(!CORBA_Object_is_nil(ir, ev)) {
++ CORBA_ORB_set_initial_reference(orb, "InterfaceRepository", ir, ev);
++ }
++ }
++
++ /*
++ * Connect to naming service
++ */
++
++ {
++ CORBA_Object naming=NULL;
++
++ if(naming_ior!=NULL) {
++ naming=CORBA_ORB_string_to_object(orb, naming_ior, ev);
++ g_free(naming_ior);
++ } else if(naming_addr!=NULL) {
++ /*CORBA_ORB_ObjectTag tag=CORBA_ORB_string_to_tag(orb, "root", ev);*/
++
++ /*naming=CORBA_ORB_bind_tag(orb, "IDL:omg.org/CosNaming/NamingContext:1.0", tag, naming_addr, ev);*/
++ g_free(naming_addr);
++ }
++
++ if(!CORBA_Object_is_nil(naming, ev)) {
++ CORBA_ORB_set_initial_reference(orb, "NameService", naming, ev);
++ }
++ }
++
++ /*
++ * Connect to / create RootPOA
++ */
++
++ {
++ PortableServer_POA root_poa=CORBA_OBJECT_NIL;
++
++ if(root_poa_ior!=NULL) {
++ root_poa=(PortableServer_POA)
++ CORBA_ORB_string_to_object(orb,
++ root_poa_ior, ev);
++ g_free(root_poa_ior);
++ }
++
++ /* And attatch it to the orb */
++
++ if(!CORBA_Object_is_nil((CORBA_Object)root_poa, ev)) {
++ CORBA_ORB_set_initial_reference((CORBA_ORB)orb,
++ "RootPOA",
++ (CORBA_Object)root_poa,
++ ev);
++ }
++ }
++
++ ORBit_custom_run_setup(orb, ev);
++
++ if (!strcmp("server", argv[0])) // Only do this for servers.
++ TheOneTrueOrb = orb;
++ up(&StartupSem); // Okay, let the insmod thread continue...
++ return orb;
++
++error:
++ if(orb!=NULL) {
++ ORBit_ORB_release(orb, ev);
++ orb = NULL;
++ }
++ g_free(imr_ior);
++ g_free(imr_addr);
++ g_free(ir_ior);
++ g_free(ir_addr);
++ g_free(naming_ior);
++ g_free(naming_addr);
++ g_free(root_poa_ior);
++ g_free(root_poa_addr);
++ g_free(orb_id_opt);
++
++ TheOneTrueOrb = 0;
++ up(&StartupSem); // Okay, let the insmod thread continue...
++ return 0;
++}
++
++
++#if __KERNEL__
++#include <linux/smp_lock.h>
++#include <linux/proc_fs.h>
++
++// This is the main corba thread function...
++//
++void __CORBA_ORB_run(CORBA_ORB orb, CORBA_Environment *ev);
++int MainCORBAThread(void *Args) {
++ // Make a directory in /proc... yaay...
++ proc_mkdir("corba", 0);
++
++ __CORBA_ORB_init((struct CORBA_ORB_init_args*)Args);
++ if (TheOneTrueOrb == 0) return 0;
++
++ strcpy(current->comm, "korbit"); // Set the thread name...
++
++ lock_kernel(); /* This seems to be required for exit_mm */
++ exit_mm(current);
++
++ __CORBA_ORB_run(TheOneTrueOrb,
++ ((struct CORBA_ORB_init_args*)Args)->ev);
++ return 0;
++}
++#endif
++
++
++/* Section 4.4
++ *
++ * Adjusts argc and argv appropriately
++ */
++
++CORBA_ORB CORBA_ORB_init(int *argc, char **argv, CORBA_ORBid orb_identifier,
++ CORBA_Environment *ev) {
++
++ struct CORBA_ORB_init_args Args;
++ Args.argc = argc;
++ Args.argv = argv;
++ Args.orb_identifier = orb_identifier;
++ Args.ev = ev;
++
++#ifdef __KERNEL__
++ if (!strcmp(argv[0], "server")) { // Are we a server?
++ down(&StartupSem); // Grab the semaphore...
++ if (TheOneTrueOrb) {
++ CORBA_exception_init(ev);
++ goto out_success;
++ }
++
++ // This releases the semaphore when it is done initializing.
++ (void)kernel_thread(MainCORBAThread, &Args,
++ CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
++
++ // This will block until the semaphore is released by the
++ // ORB thread.
++ down(&StartupSem);
++ } else { // If we are a corba client, like CorbaFS...
++ return __CORBA_ORB_init(&Args);
++ }
++
++ out_success:
++ up(&StartupSem); // Okay, we're now here.
++#else
++ __CORBA_ORB_init(&Args);
++#endif
++ if (TheOneTrueOrb)
++ return (CORBA_ORB)CORBA_Object_duplicate((CORBA_Object)TheOneTrueOrb, ev);
++ return 0;
++}
++
++
++
++
++typedef struct {
++ CORBA_Object obj;
++ CDR_Codec *codec;
++ gboolean emit_active;
++} profile_user_data;
++
++static void ORBit_emit_profile(gpointer item, gpointer userdata)
++{
++ ORBit_Object_info *profile=(ORBit_Object_info *)item;
++ profile_user_data *data=(profile_user_data *)userdata;
++ CORBA_Object obj=data->obj;
++ CDR_Codec encaps_codec_d;
++ CDR_Codec *codec=data->codec, *encaps = &encaps_codec_d;
++ gboolean emit_active=data->emit_active;
++ static const CORBA_octet iiopversion[] = {1,0};
++ CORBA_octet codecbuf[2048];
++
++ g_assert(obj!=NULL);
++ g_assert(codec!=NULL);
++ g_assert(profile!=NULL);
++
++ if((profile == obj->active_profile) && (emit_active == FALSE))
++ return; /* we already did this one */
++
++ switch(profile->profile_type) {
++ case IOP_TAG_INTERNET_IOP:
++ CDR_codec_init_static(encaps);
++ encaps->buffer = codecbuf;
++ encaps->release_buffer = CORBA_FALSE;
++ encaps->buf_len = 2048;
++ encaps->readonly = CORBA_FALSE;
++ encaps->host_endian = encaps->data_endian = FLAG_ENDIANNESS;
++
++ CDR_put_ulong(codec, IOP_TAG_INTERNET_IOP);
++ CDR_put_octet(encaps, FLAG_ENDIANNESS);
++ CDR_put_octets(encaps, (gpointer)iiopversion, sizeof(iiopversion));
++ CDR_put_string(encaps, profile->tag.iopinfo.host);
++ CDR_put_ushort(encaps, profile->tag.iopinfo.port);
++ CDR_put_ulong(encaps, profile->object_key._length);
++ CDR_put_octets(encaps, profile->object_key._buffer,
++ profile->object_key._length);
++ CDR_put_ulong(codec, encaps->wptr);
++ CDR_put_octets(codec, encaps->buffer, encaps->wptr);
++ break;
++
++ case IOP_TAG_ORBIT_SPECIFIC:
++ CDR_codec_init_static(encaps);
++ encaps->buffer = codecbuf;
++ encaps->release_buffer = CORBA_FALSE;
++ encaps->buf_len = 2048;
++ encaps->readonly = CORBA_FALSE;
++ encaps->host_endian = encaps->data_endian = FLAG_ENDIANNESS;
++
++ CDR_put_ulong(codec, IOP_TAG_ORBIT_SPECIFIC);
++ CDR_put_octet(encaps, FLAG_ENDIANNESS);
++ CDR_put_octets(encaps, (gpointer)iiopversion, sizeof(iiopversion));
++ CDR_put_string(encaps, profile->tag.orbitinfo.unix_sock_path);
++ CDR_put_ushort(encaps, profile->tag.orbitinfo.ipv6_port);
++ CDR_put_ulong(encaps, profile->object_key._length);
++ CDR_put_octets(encaps, profile->object_key._buffer,
++ profile->object_key._length);
++ CDR_put_ulong(codec, encaps->wptr);
++ CDR_put_octets(codec, encaps->buffer, encaps->wptr);
++ break;
++
++ default:
++ g_warning("Skipping tag %d", profile->profile_type);
++ break;
++ }
++}
++
++CORBA_char *CORBA_ORB_object_to_string(CORBA_ORB orb,
++ CORBA_Object obj,
++ CORBA_Environment *ev)
++{
++ int i;
++ CDR_Codec codec_d;
++ CDR_Codec *codec = &codec_d;
++ CORBA_char *rc = NULL;
++ CORBA_unsigned_long ntags;
++ profile_user_data data;
++ CORBA_octet codecbuf[2048];
++ char *ctmp;
++
++ g_return_val_if_fail(ev, NULL);
++ o_return_val_if_fail(orb && obj, NULL);
++
++ if(!obj || !orb) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return NULL;
++ }
++
++ if(ORBIT_ROOT_OBJECT(obj)->is_pseudo_object) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_MARSHAL,
++ CORBA_COMPLETED_NO);
++ return NULL;
++ }
++
++ CDR_codec_init_static(codec);
++
++ codec->buffer = codecbuf;
++ codec->release_buffer = CORBA_FALSE;
++ codec->buf_len = 2048;
++ codec->readonly = CORBA_FALSE;
++ codec->host_endian = codec->data_endian = FLAG_ENDIANNESS;
++
++ CDR_put_octet(codec, FLAG_ENDIANNESS);
++
++ CDR_put_string(codec, obj->object_id);
++ ntags = g_slist_length(obj->profile_list);
++ CDR_put_ulong(codec, ntags);
++
++ data.obj=obj;
++ data.codec=codec;
++ data.emit_active=TRUE;
++ if(obj->active_profile != NULL)
++ ORBit_emit_profile(obj->active_profile, &data); /* do this one first */
++
++ data.emit_active=FALSE;
++ g_slist_foreach(obj->profile_list, ORBit_emit_profile, &data);
++
++ rc = CORBA_string_alloc(4 + (codec->wptr * 2) + 1);
++ strcpy(rc, "IOR:");
++
++#define hexdigit(n) (((n)>9)?(n+'a'-10):(n+'0'))
++
++ for(i = 0, ctmp = rc + strlen("IOR:"); i < codec->wptr; i++) {
++ *(ctmp++) = hexdigit((((codec->buffer[i]) & 0xF0) >> 4));
++ *(ctmp++) = hexdigit(((codec->buffer[i]) & 0xF));
++ }
++ *ctmp = '\0';
++
++ {
++ /* Debug check */
++ CORBA_Object obj;
++ CORBA_Environment myev;
++
++ CORBA_exception_init(&myev);
++
++ obj = CORBA_ORB_string_to_object(orb, rc, &myev);
++
++ if (CORBA_Object_is_nil(obj, &myev)) {
++ g_warning("Bug in %s, created bad IOR `%s'\n",
++ __FUNCTION__, rc);
++ CORBA_free(rc);
++ return NULL;
++ }
++
++ CORBA_Object_release(obj, &myev);
++ }
++
++ return rc;
++}
++
++/* Quote from the GNU libc manual:
++
++ "If you try to allocate more storage than the machine can provide,
++ you don't get a clean error message. Instead you get a fatal
++ signal like the one you would get from an infinite recursion;
++ probably a segmentation violation (see section Program Error
++ Signals)."
++
++ The man page claims alloca() returns NULL on failure; this appears
++ to be a load of shit on Linux where you just get flaming death, but
++ we check anyway in case other systems work that way.
++
++ On Linux we check that the size is less than MAX_STACK_ALLOC
++
++ Note that the CORBA_alloc() calls in here can still cause
++ program abort, and really that should be fixed in a similar
++ way since our lengths are coming in from unpredictable sources
++ like files or the network.
++*/
++
++#define MAX_STACK_ALLOC 8192
++
++CORBA_Object CORBA_ORB_string_to_object(CORBA_ORB orb, CORBA_char *str,
++ CORBA_Environment *ev)
++{
++ GSList *profiles=NULL;
++ CORBA_Object retval = NULL;
++ CORBA_char *type_id;
++ ORBit_Object_info *object_info;
++ CDR_Codec codec_d, encaps_codec_d;
++ CDR_Codec *codec = &codec_d, *encaps_codec = &encaps_codec_d;
++ CORBA_octet *buffer, endian;
++ int i, j;
++ CORBA_unsigned_long len, seq_len, misclen;
++
++ g_return_val_if_fail(ev, CORBA_OBJECT_NIL);
++ o_return_val_if_fail(orb && str, CORBA_OBJECT_NIL);
++
++ if(strncmp(str, "IOR:", 4)) {
++ CORBA_exception_set_system(ev, ex_CORBA_MARSHAL,
++ CORBA_COMPLETED_NO);
++ return(CORBA_OBJECT_NIL);
++ }
++
++ CDR_codec_init_static(codec);
++ len = strlen(str);
++
++ if((len % 2) || len <= 4) {
++ CORBA_exception_set_system(ev, ex_CORBA_MARSHAL,
++ CORBA_COMPLETED_NO);
++ return(CORBA_OBJECT_NIL);
++ }
++
++ codec->buf_len = (len-4)/2;
++ buffer = alloca(codec->buf_len);
++
++ codec->buffer=buffer;
++ codec->release_buffer = CORBA_FALSE;
++ codec->readonly = TRUE;
++
++ for(j = 0, i = 4; i < len; i+=2) {
++ buffer[j++] = HEXOCTET(str[i], str[i+1]);
++ };
++
++ CDR_get_octet(codec, &endian);
++
++ codec->data_endian = endian;
++ codec->host_endian = FLAG_ENDIANNESS;
++
++ CDR_get_string_static(codec, &type_id);
++
++ CDR_get_seq_begin(codec, &seq_len);
++
++ for(i = 0; i < seq_len; i++) {
++ IOP_ProfileId tag;
++
++ object_info=g_new0(ORBit_Object_info, 1);
++
++ if (!CDR_get_ulong(codec, &tag))
++ goto error_out;
++
++ switch(tag) {
++ case IOP_TAG_INTERNET_IOP:
++ if (!CDR_get_ulong(codec, &misclen))
++ goto error_out;
++
++ CDR_codec_init_static(encaps_codec);
++
++ if (misclen > MAX_STACK_ALLOC)
++ goto error_out;
++
++ encaps_codec->buffer = alloca(misclen);
++ if (encaps_codec->buffer == NULL)
++ /* misclen was probably junk */
++ goto error_out;
++
++ encaps_codec->release_buffer = FALSE;
++ if(!CDR_buffer_gets(codec, encaps_codec->buffer, misclen))
++ goto error_out;
++
++ encaps_codec->buf_len = misclen;
++ encaps_codec->readonly = CORBA_TRUE;
++ if(!CDR_get_octet(encaps_codec, &endian))
++ goto error_out;
++ encaps_codec->data_endian = endian;
++ encaps_codec->host_endian = FLAG_ENDIANNESS;
++
++ if (encaps_codec->data_endian > 1)
++ goto error_out;
++
++ object_info->profile_type = IOP_TAG_INTERNET_IOP;
++ if(!CDR_get_octet(encaps_codec, &object_info->iiop_major))
++ goto error_out;
++ if(object_info->iiop_major != 1)
++ goto error_out;
++ if(!CDR_get_octet(encaps_codec, &object_info->iiop_minor))
++ goto error_out;
++ if(!CDR_get_string(encaps_codec, &object_info->tag.iopinfo.host))
++ goto error_out;
++ if(!CDR_get_ushort(encaps_codec, &object_info->tag.iopinfo.port))
++ goto error_out;
++ if(!CDR_get_seq_begin(encaps_codec, &object_info->object_key._length))
++ goto error_out;
++
++ object_info->object_key._maximum = 0;
++
++ /* The POA gives out ORBit_alloc()d profiles, so we have to too */
++ object_info->object_key._buffer = ORBit_alloc(object_info->object_key._length, NULL, NULL);
++ if(!CDR_buffer_gets(encaps_codec, object_info->object_key._buffer,
++ object_info->object_key._length))
++ goto error_out;
++
++ ORBit_set_object_key(object_info);
++ profiles=g_slist_append(profiles, object_info);
++ break;
++
++ case IOP_TAG_MULTIPLE_COMPONENTS:
++ /* Just skip any multiple_components data, for now */
++ if(!CDR_get_ulong(codec, &misclen))
++ goto error_out;
++
++ CDR_codec_init_static(encaps_codec);
++
++ if (misclen > MAX_STACK_ALLOC)
++ goto error_out;
++
++ encaps_codec->buf_len = misclen;
++ encaps_codec->buffer = alloca(misclen);
++ if (encaps_codec->buffer == NULL)
++ /* misclen was probably junk */
++ goto error_out;
++
++ encaps_codec->release_buffer = FALSE;
++ encaps_codec->readonly = CORBA_TRUE;
++ if(!CDR_buffer_gets(codec, encaps_codec->buffer, misclen))
++ goto error_out;
++ break;
++
++ case IOP_TAG_ORBIT_SPECIFIC:
++ if(!CDR_get_ulong(codec, &misclen))
++ goto error_out;
++
++ CDR_codec_init_static(encaps_codec);
++
++ if (misclen > MAX_STACK_ALLOC)
++ goto error_out;
++
++ encaps_codec->buffer = alloca(misclen);
++ if (encaps_codec->buffer == NULL)
++ /* misclen was probably junk */
++ goto error_out;
++
++ encaps_codec->release_buffer = FALSE;
++ if(!CDR_buffer_gets(codec, encaps_codec->buffer, misclen))
++ goto error_out;
++
++ encaps_codec->buf_len = misclen;
++ encaps_codec->readonly = CORBA_TRUE;
++
++ if(!CDR_get_octet(encaps_codec, &endian))
++ goto error_out;
++
++ encaps_codec->data_endian = endian;
++ encaps_codec->host_endian = FLAG_ENDIANNESS;
++
++ if (encaps_codec->data_endian > 1)
++ goto error_out;
++
++ object_info->profile_type=IOP_TAG_ORBIT_SPECIFIC;
++ if(!CDR_get_octet(encaps_codec, &object_info->iiop_major))
++ goto error_out;
++
++ if(object_info->iiop_major != 1)
++ goto error_out;
++ if(!CDR_get_octet(encaps_codec, &object_info->iiop_minor))
++ goto error_out;
++
++ if(!CDR_get_string(encaps_codec, &object_info->tag.orbitinfo.unix_sock_path))
++ goto error_out;
++
++ if(!CDR_get_ushort(encaps_codec, &object_info->tag.orbitinfo.ipv6_port))
++ goto error_out;
++ if(!CDR_get_seq_begin(encaps_codec, &object_info->object_key._length))
++ goto error_out;
++ object_info->object_key._maximum = 0;
++
++ /* The POA gives out ORBit_alloc()d profiles, so we have to too */
++ object_info->object_key._buffer = ORBit_alloc(object_info->object_key._length, NULL, NULL);
++ if(!CDR_buffer_gets(encaps_codec, object_info->object_key._buffer,
++ object_info->object_key._length))
++ goto error_out;
++
++ ORBit_set_object_key(object_info);
++ profiles=g_slist_append(profiles, object_info);
++ break;
++ default:
++ g_warning("Unknown tag 0x%x", tag);
++
++ /* Skip it */
++ if(!CDR_get_ulong(codec, &misclen))
++ goto error_out;
++
++ CDR_codec_init_static(encaps_codec);
++
++ if (misclen > MAX_STACK_ALLOC)
++ goto error_out;
++
++ encaps_codec->buf_len = misclen;
++ encaps_codec->buffer = alloca(misclen);
++ if (encaps_codec->buffer == NULL)
++ /* misclen was probably junk */
++ goto error_out;
++
++ encaps_codec->release_buffer = FALSE;
++ encaps_codec->readonly = CORBA_TRUE;
++ if(!CDR_buffer_gets(codec, encaps_codec->buffer, misclen))
++ goto error_out;
++
++ break;
++ }
++ }
++
++ freeca(buffer); /* Same as codec->buffer */
++ freeca(encaps_codec->buffer);
++
++ return ORBit_create_object_with_info(profiles, type_id, orb, ev);
++
++ error_out:
++
++ if(object_info) {
++ CORBA_free(object_info->object_key._buffer);
++ g_free(object_info);
++ ORBit_delete_profiles(profiles);
++ }
++
++ freeca(buffer); /* Same as codec->buffer */
++ freeca(encaps_codec->buffer);
++
++ return retval;
++}
++
++/* Section 4.1.2 */
++CORBA_boolean CORBA_ORB_get_service_information(CORBA_ORB orb, CORBA_ServiceType service_type, CORBA_ServiceInformation *service_information, CORBA_Environment *ev)
++{
++ g_assert(!"Not yet implemented");
++ return(CORBA_FALSE);
++}
++
++CORBA_Current *CORBA_ORB_get_current(CORBA_ORB orb, CORBA_Environment *ev)
++{
++ g_return_val_if_fail(ev, NULL);
++ o_return_val_if_fail(orb, NULL);
++
++ /* XXX check this over */
++ return (CORBA_Current *)GET_THREAD_DATA();
++}
++
++/* Section 4.5 */
++CORBA_ORB_ObjectIdList *CORBA_ORB_list_initial_services(CORBA_ORB orb, CORBA_Environment *ev)
++{
++ static const char *services[] = {"RootPOA"};
++ CORBA_ORB_ObjectIdList *list;
++
++ g_return_val_if_fail(ev, NULL);
++ o_return_val_if_fail(orb, NULL);
++
++ list = (CORBA_ORB_ObjectIdList *)CORBA_sequence_octet__alloc();
++ list->_maximum=list->_length= 1;
++ list->_buffer = (CORBA_ORB_ObjectId *)services;
++ CORBA_sequence_set_release((void *)list, CORBA_FALSE);
++
++ /* defined reserved references are:
++ * RootPOA
++ * POACurrent
++ * InterfaceRepository
++ * NameService
++ * TradingService
++ * SecurityCurrent
++ * TransactionCurrent
++ */
++
++ return list;
++}
++
++/* Section 4.5
++ *
++ * raises InvalidName
++ */
++CORBA_Object CORBA_ORB_resolve_initial_references(CORBA_ORB orb, CORBA_ORB_ObjectId identifier, CORBA_Environment *ev)
++{
++ g_return_val_if_fail(ev, CORBA_OBJECT_NIL);
++ o_return_val_if_fail(orb, CORBA_OBJECT_NIL);
++
++ if(!strcmp(identifier, "ImplementationRepository"))
++ return CORBA_Object_duplicate(orb->imr, ev);
++ else if(!strcmp(identifier, "InterfaceRepository"))
++ return CORBA_Object_duplicate(orb->ir, ev);
++ else if(!strcmp(identifier, "NameService"))
++ return CORBA_Object_duplicate(orb->naming, ev);
++ else if(!strcmp(identifier, "RootPOA")) {
++ if(CORBA_Object_is_nil(orb->root_poa, ev)) {
++ CORBA_PolicyList policies = {0,0,NULL,CORBA_FALSE};
++ PortableServer_POAManager poa_mgr;
++ /* Create a poa manager */
++ poa_mgr = ORBit_POAManager_new(ev);
++ poa_mgr->orb = orb;
++
++ /* Create the root poa */
++ orb->root_poa = (CORBA_Object)
++ ORBit_POA_new(orb,
++ "RootPOA",
++ poa_mgr,
++ &policies,
++ ev);
++ CORBA_Object_duplicate(orb->root_poa, ev);
++ }
++
++ return CORBA_Object_duplicate(orb->root_poa, ev);
++ }
++
++ /* throw user exception: InvalidName */
++ CORBA_exception_set(ev,CORBA_USER_EXCEPTION,
++ ex_CORBA_ORB_InvalidName,
++ NULL);
++
++ goto error;
++error:
++ return(NULL);
++}
++
++/* This is a MICO extension
++ *
++ * raises InvalidName
++ */
++void CORBA_ORB_set_initial_reference(CORBA_ORB orb, CORBA_ORB_ObjectId identifier, CORBA_Object obj, CORBA_Environment *ev)
++{
++ g_return_if_fail(ev);
++ o_return_if_fail(orb && identifier && obj);
++
++ if(!strcmp(identifier, "ImplementationRepository")) {
++ if(!CORBA_Object_is_nil(orb->imr, ev)) {
++ CORBA_Object_release(orb->imr, ev);
++ }
++ orb->imr=CORBA_Object_duplicate(obj, ev);
++ } else if(!strcmp(identifier, "InterfaceRepository")) {
++ if(!CORBA_Object_is_nil(orb->ir, ev)) {
++ CORBA_Object_release(orb->ir, ev);
++ }
++ orb->ir=CORBA_Object_duplicate(obj, ev);
++ } else if(!strcmp(identifier, "NameService")) {
++ if(!CORBA_Object_is_nil(orb->naming, ev)) {
++ CORBA_Object_release(orb->naming, ev);
++ }
++ orb->naming=CORBA_Object_duplicate(obj, ev);
++ } else if(!strcmp(identifier, "RootPOA")) {
++ if(!CORBA_Object_is_nil(orb->root_poa, ev)) {
++ CORBA_Object_release(orb->root_poa, ev);
++ }
++ orb->root_poa=CORBA_Object_duplicate(obj, ev);
++ } else {
++ /* throw user exception: InvalidName */
++ CORBA_exception_set(ev,CORBA_USER_EXCEPTION,ex_CORBA_ORB_InvalidName,NULL);
++ goto error;
++ }
++
++ return;
++error:
++ return;
++}
++
++/* Section 4.9.1 */
++CORBA_boolean CORBA_ORB_work_pending(CORBA_ORB orb, CORBA_Environment *ev)
++{
++ g_assert(!"Not yet implemented");
++ return(CORBA_FALSE);
++}
++
++/* Section 4.9.2 */
++void CORBA_ORB_perform_work(CORBA_ORB orb, CORBA_Environment *ev)
++{
++ g_assert(!"Not yet implemented");
++ return;
++}
++
++/* Section 4.9.4 */
++void
++CORBA_ORB_shutdown(CORBA_ORB orb,
++ CORBA_boolean wait_for_completion,
++ CORBA_Environment *ev)
++{
++ g_return_if_fail(ev);
++ o_return_if_fail(orb);
++
++ /* XXX implement on a per-ORB basis, and also
++ handle whatever wait_for_completion means */
++
++ if(orb->cnx.ipv4)
++ giop_connection_unref(orb->cnx.ipv4);
++ if(orb->cnx.ipv6)
++ giop_connection_unref(orb->cnx.ipv6);
++#ifndef __KORBIT__
++ if(orb->cnx.usock)
++ giop_connection_unref(orb->cnx.usock);
++#endif
++
++ giop_main_quit();
++}
++
++/* Section 4.9.3 */
++/* CORBA_ORB_run is in server.c */
++
++/* Section 4.7 */
++CORBA_PolicyType
++CORBA_Policy__get_policy_type(CORBA_Policy obj, CORBA_Environment *ev)
++{
++ g_return_val_if_fail(ev, 0);
++ o_return_val_if_fail(obj, 0);
++
++ return obj->policy_type;
++}
++
++/* Section 4.7 */
++CORBA_Policy CORBA_Policy_copy(CORBA_Policy obj, CORBA_Environment *ev)
++{
++ g_return_val_if_fail(ev, CORBA_OBJECT_NIL);
++ o_return_val_if_fail(obj, CORBA_OBJECT_NIL);
++
++ ORBIT_ROOT_OBJECT_REF(obj);
++
++ return obj;
++}
++
++/* Section 4.7
++ *
++ * raises CORBA_NO_PERMISSION
++ */
++void CORBA_Policy_destroy(CORBA_Policy obj, CORBA_Environment *ev)
++{
++ g_return_if_fail(ev);
++ o_return_if_fail(obj);
++
++ ORBIT_ROOT_OBJECT_UNREF(obj);
++ if(ORBIT_ROOT_OBJECT(obj)->refs <= 0)
++ ORBIT_ROOT_OBJECT_release(obj, ev);
++}
++
++#ifndef __KORBIT__
++/* Section 4.8.2 */
++CORBA_Policy CORBA_DomainManager_get_domain_policy(CORBA_DomainManager obj, CORBA_PolicyType policy_type, CORBA_Environment *ev)
++{
++ g_return_val_if_fail(ev, CORBA_OBJECT_NIL);
++ o_return_val_if_fail(obj, CORBA_OBJECT_NIL);
++
++ g_assert(!"Not yet implemented");
++ return(NULL);
++}
++
++/* Section 4.8.2 */
++void CORBA_ConstructionPolicy_make_domain_manager(CORBA_ConstructionPolicy obj, CORBA_InterfaceDef object_type, CORBA_boolean constr_policy, CORBA_Environment *
++ev)
++{
++ g_return_if_fail(ev);
++ o_return_if_fail(obj && object_type);
++
++ g_assert(!"Not yet implemented");
++ return;
++}
++
++/* Section 4.2.8 */
++CORBA_DomainManagerList *CORBA_Object_get_domain_managers(CORBA_Object obj, CORBA_Environment *ev)
++{
++ g_return_val_if_fail(ev, NULL);
++ o_return_val_if_fail(obj, NULL);
++
++ g_assert(!"Not yet implemented");
++ return(NULL);
++}
++
++CORBA_TypeCode CORBA_ORB_create_struct_tc(CORBA_ORB obj, CORBA_RepositoryId id, CORBA_Identifier name, CORBA_StructMemberSeq members, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++ int i;
++
++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc == NULL)
++ goto tc_alloc_failed;
++
++ tc->subtypes=g_new0(CORBA_TypeCode, members._length);
++ if(tc->subtypes == NULL)
++ goto subtypes_alloc_failed;
++
++ tc->subnames=g_new0(char *, members._length);
++ if(tc->subnames == NULL)
++ goto subnames_alloc_failed;
++
++ tc->kind=CORBA_tk_struct;
++ tc->name=g_strdup(name);
++ tc->repo_id=g_strdup(id);
++ tc->sub_parts=members._length;
++ tc->length=members._length;
++
++ for(i=0;i<members._length;i++) {
++ CORBA_StructMember *mem=(CORBA_StructMember *)&(members._buffer[i]);
++
++ g_assert(&(mem->type)!=NULL);
++
++ tc->subtypes[i] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ memcpy(tc->subtypes[i], mem->type, (size_t)sizeof(struct CORBA_TypeCode_struct));
++ tc->subnames[i]=g_strdup(mem->name);
++ }
++
++ return(tc);
++
++ subnames_alloc_failed:
++ g_free(tc->subtypes);
++ subtypes_alloc_failed:
++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc);
++ tc_alloc_failed:
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return NULL;
++}
++
++CORBA_TypeCode
++CORBA_ORB_create_union_tc(CORBA_ORB obj, CORBA_RepositoryId id,
++ CORBA_Identifier name,
++ CORBA_TypeCode discriminator_type,
++ CORBA_UnionMemberSeq members,
++ CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++ int i;
++
++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++
++ if(tc == NULL)
++ goto tc_alloc_failed;
++
++ tc->discriminator = ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++
++ if(tc->discriminator == NULL)
++ goto discriminator_alloc_failed;
++
++ memcpy(tc->discriminator, discriminator_type, (size_t)sizeof(CORBA_TypeCode));
++
++ tc->subtypes=g_new0(CORBA_TypeCode, members._length);
++ if(tc->subtypes==NULL)
++ goto subtypes_alloc_failed;
++
++ tc->subnames=g_new0(char *, members._length);
++ if(tc->subnames==NULL)
++ goto subnames_alloc_failed;
++
++ tc->sublabels=g_new0(CORBA_any, members._length);
++ if(tc->sublabels == NULL)
++ goto sublabels_alloc_failed;
++
++ tc->kind=CORBA_tk_union;
++ tc->name=g_strdup(name);
++ tc->repo_id=g_strdup(id);
++ tc->sub_parts=members._length;
++ tc->length=members._length;
++ tc->default_index=-1;
++
++ for(i=0;i<members._length;i++) {
++ CORBA_UnionMember *mem=(CORBA_UnionMember *)&(members._buffer[i]);
++
++ g_assert(&(mem->label)!=NULL);
++ memcpy(&(tc->sublabels[i]), &(mem->label), (size_t)sizeof(CORBA_any));
++ g_assert(&(mem->type)!=NULL);
++ tc->subtypes[i] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ memcpy(tc->subtypes[i], mem->type, (size_t)sizeof(struct CORBA_TypeCode_struct));
++ tc->subnames[i]=g_strdup(mem->name);
++
++ if(mem->label._type->kind==CORBA_tk_octet) {
++ tc->default_index=i;
++ }
++ }
++
++ return(tc);
++
++sublabels_alloc_failed:
++ g_free(tc->sublabels);
++subnames_alloc_failed:
++ g_free(tc->subtypes);
++subtypes_alloc_failed:
++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc->discriminator);
++discriminator_alloc_failed:
++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc);
++ tc_alloc_failed:
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return NULL;
++}
++
++CORBA_TypeCode CORBA_ORB_create_enum_tc(CORBA_ORB obj, CORBA_RepositoryId id, CORBA_Identifier name, CORBA_EnumMemberSeq members, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++ int i;
++
++ tc = ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc == NULL)
++ goto tc_alloc_failed;
++
++ tc->subnames=g_new0(char *, members._length);
++ if(tc->subnames==NULL)
++ goto subnames_alloc_failed;
++
++ tc->kind = CORBA_tk_enum;
++ tc->name = g_strdup(name);
++ tc->repo_id = g_strdup(id);
++ tc->sub_parts = members._length;
++ tc->length = members._length;
++
++ for(i=0;i<members._length;i++) {
++ tc->subnames[i]=g_strdup(members._buffer[i]);
++ }
++
++ return(tc);
++
++ subnames_alloc_failed:
++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc);
++ tc_alloc_failed:
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return(NULL);
++}
++
++CORBA_TypeCode CORBA_ORB_create_alias_tc(CORBA_ORB obj, CORBA_RepositoryId id, CORBA_Identifier name, CORBA_TypeCode original_type, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++
++ tc = ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc==NULL)
++ goto tc_alloc_failed;
++
++ /* Can't use chunks here, because it's sometimes an array. Doh! */
++ tc->subtypes=g_new0(CORBA_TypeCode, 1);
++ if(tc->subtypes==NULL)
++ goto subtypes_alloc_failed;
++
++ tc->kind=CORBA_tk_alias;
++ tc->name=g_strdup(name);
++ tc->repo_id=g_strdup(id);
++ tc->sub_parts=1;
++ tc->length=1;
++
++ tc->subtypes[0] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ memcpy(tc->subtypes[0], original_type, (size_t)sizeof(struct CORBA_TypeCode_struct));
++
++ return(tc);
++ subtypes_alloc_failed:
++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc);
++tc_alloc_failed:
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return NULL;
++}
++
++CORBA_TypeCode CORBA_ORB_create_exception_tc(CORBA_ORB obj, CORBA_RepositoryId id, CORBA_Identifier name, CORBA_StructMemberSeq members, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++ int i;
++
++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc==NULL)
++ goto tc_alloc_failed;
++
++ tc->subtypes=g_new0(CORBA_TypeCode, members._length);
++ if(tc->subtypes==NULL)
++ goto subtypes_alloc_failed;
++
++ tc->subnames=g_new0(char *, members._length);
++ if(tc->subnames==NULL)
++ goto subnames_alloc_failed;
++
++ tc->kind=CORBA_tk_except;
++ tc->name=g_strdup(name);
++ tc->repo_id=g_strdup(id);
++ tc->sub_parts=members._length;
++ tc->length=members._length;
++
++ for(i=0;i<members._length;i++) {
++ CORBA_StructMember *mem=(CORBA_StructMember *)&(members._buffer[i]);
++
++ g_assert(mem->type != NULL);
++ tc->subtypes[i] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ memcpy(tc->subtypes[i], mem->type, (size_t)sizeof(struct CORBA_TypeCode_struct));
++ tc->subnames[i]=g_strdup(mem->name);
++ }
++
++ return(tc);
++
++ subnames_alloc_failed:
++ g_free(tc->subtypes);
++ subtypes_alloc_failed:
++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc);
++ tc_alloc_failed:
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return(NULL);
++}
++
++CORBA_TypeCode CORBA_ORB_create_interface_tc(CORBA_ORB obj, CORBA_RepositoryId id, CORBA_Identifier name, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++
++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc==NULL) {
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY,
++ CORBA_COMPLETED_NO);
++ return(NULL);
++ }
++
++ tc->kind=CORBA_tk_objref;
++ tc->name=g_strdup(name);
++ tc->repo_id=g_strdup(id);
++
++ return(tc);
++}
++
++CORBA_TypeCode CORBA_ORB_create_string_tc(CORBA_ORB obj, CORBA_unsigned_long bound, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++
++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc==NULL) {
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return(NULL);
++ }
++
++ tc->kind=CORBA_tk_string;
++ tc->length=bound;
++
++ return(tc);
++}
++
++CORBA_TypeCode CORBA_ORB_create_wstring_tc(CORBA_ORB obj, CORBA_unsigned_long bound, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++
++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc==NULL) {
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return(NULL);
++ }
++
++ tc->kind=CORBA_tk_wstring;
++ tc->length=bound;
++
++ return(tc);
++}
++
++CORBA_TypeCode CORBA_ORB_create_fixed_tc(CORBA_ORB obj, CORBA_unsigned_short digits, CORBA_short scale, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++
++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc==NULL) {
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return(NULL);
++ }
++
++ tc->kind=CORBA_tk_fixed;
++ tc->digits=digits;
++ tc->scale=scale;
++
++ return(tc);
++}
++
++CORBA_TypeCode CORBA_ORB_create_sequence_tc(CORBA_ORB obj, CORBA_unsigned_long bound, CORBA_TypeCode element_type, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++
++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc==NULL)
++ goto tc_alloc_failed;
++
++ /* Can't use chunks here because we can only be sure of getting
++ one consecutive chunk from glib */
++ tc->subtypes=g_new0(CORBA_TypeCode, 1);
++ if(tc->subtypes==NULL)
++ goto subtypes_alloc_failed;
++
++ tc->kind=CORBA_tk_sequence;
++ tc->sub_parts=1;
++ tc->length=bound;
++
++ tc->subtypes[0] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ memcpy(tc->subtypes[0], element_type,
++ (size_t)sizeof(struct CORBA_TypeCode_struct));
++
++ return(tc);
++
++ subtypes_alloc_failed:
++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc);
++ tc_alloc_failed:
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return(NULL);
++}
++
++CORBA_TypeCode CORBA_ORB_create_recursive_sequence_tc(CORBA_ORB obj, CORBA_unsigned_long bound, CORBA_unsigned_long offset, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++
++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc==NULL)
++ goto tc_alloc_failed;
++
++ tc->subtypes=g_new0(CORBA_TypeCode, 1);
++ if(tc->subtypes==NULL)
++ goto subtypes_alloc_failed;
++
++ tc->kind=CORBA_tk_sequence;
++ tc->sub_parts=1;
++ tc->length=bound;
++
++ tc->subtypes[0] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ tc->subtypes[0]->kind=CORBA_tk_recursive;
++ tc->subtypes[0]->recurse_depth=offset;
++
++ return(tc);
++
++ subtypes_alloc_failed:
++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc);
++ tc_alloc_failed:
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return(NULL);
++}
++
++CORBA_TypeCode CORBA_ORB_create_array_tc(CORBA_ORB obj, CORBA_unsigned_long length, CORBA_TypeCode element_type, CORBA_Environment *ev)
++{
++ CORBA_TypeCode tc;
++
++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ if(tc==NULL)
++ goto tc_alloc_failed;
++
++ tc->subtypes=g_new0(CORBA_TypeCode, 1);
++ if(tc->subtypes==NULL)
++ goto subtypes_alloc_failed;
++
++ tc->kind=CORBA_tk_array;
++ tc->sub_parts=1;
++ tc->length=length;
++
++ tc->subtypes[0] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode);
++ memcpy(tc->subtypes[0], element_type, (size_t)sizeof(CORBA_TypeCode));
++
++ return(tc);
++
++ subtypes_alloc_failed:
++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc);
++ tc_alloc_failed:
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ return(NULL);
++}
++#endif /* !__KORBIT__ */
+diff -urN linux-2.4.1/net/korbit/orb/orb.h linux-2.4.1-korbit/net/korbit/orb/orb.h
+--- linux-2.4.1/net/korbit/orb/orb.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orb.h Thu Feb 1 11:47:13 2001
+@@ -0,0 +1,231 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_ORB_H_
++#define _ORBIT_ORB_H_
++
++#include "orb/orbit_types.h"
++#ifndef __KORBIT__
++#include "orb/interface_repository.h"
++#endif /* !__KORBIT__ */
++
++extern CORBA_ORB CORBA_ORB_init(
++ int *argc,
++ char **argv,
++ CORBA_ORBid orb_identifier,
++ CORBA_Environment *ev);
++
++extern CORBA_char *CORBA_ORB_object_to_string(
++ CORBA_ORB orb,
++ CORBA_Object obj,
++ CORBA_Environment *ev);
++
++extern CORBA_Object CORBA_ORB_string_to_object(
++ CORBA_ORB orb,
++ CORBA_char *str,
++ CORBA_Environment *ev);
++
++extern CORBA_Status CORBA_ORB_get_default_context(
++ CORBA_ORB orb,
++ CORBA_Context *ctx,
++ CORBA_Environment *ev);
++
++extern CORBA_boolean CORBA_ORB_get_service_information(
++ CORBA_ORB orb,
++ CORBA_ServiceType service_type,
++ CORBA_ServiceInformation *service_information,
++ CORBA_Environment *ev);
++
++extern CORBA_Current *CORBA_ORB_get_current(
++ CORBA_ORB orb,
++ CORBA_Environment *ev);
++
++extern CORBA_ORB_ObjectIdList* CORBA_ORB_list_initial_services(
++ CORBA_ORB orb,
++ CORBA_Environment *ev);
++
++extern CORBA_Object CORBA_ORB_resolve_initial_references(
++ CORBA_ORB orb,
++ CORBA_ORB_ObjectId identifier,
++ CORBA_Environment *ev);
++
++extern void CORBA_ORB_set_initial_reference(
++ CORBA_ORB orb,
++ CORBA_ORB_ObjectId identifier,
++ CORBA_Object obj,
++ CORBA_Environment *ev);
++
++extern CORBA_boolean CORBA_ORB_work_pending(
++ CORBA_ORB orb,
++ CORBA_Environment *ev);
++
++extern void CORBA_ORB_perform_work(
++ CORBA_ORB orb,
++ CORBA_Environment *ev);
++
++extern void CORBA_ORB_shutdown(
++ CORBA_ORB orb,
++ CORBA_boolean wait_for_completion,
++ CORBA_Environment *ev);
++
++extern void CORBA_ORB_run(
++ CORBA_ORB orb,
++ CORBA_Environment *ev);
++
++extern CORBA_PolicyType CORBA_Policy__get_policy_type(
++ CORBA_Policy obj,
++ CORBA_Environment *ev);
++
++extern CORBA_Policy CORBA_Policy_copy(
++ CORBA_Policy obj,
++ CORBA_Environment *ev);
++
++extern void CORBA_Policy_destroy(
++ CORBA_Policy obj,
++ CORBA_Environment *ev);
++
++#ifndef __KORBIT__
++extern CORBA_InterfaceDef CORBA_Object_get_interface(
++ CORBA_Object obj,
++ CORBA_Environment *ev);
++#endif /* !__KORBIT__ */
++
++extern CORBA_boolean CORBA_Object_is_nil(
++ CORBA_Object obj,
++ CORBA_Environment *ev);
++
++extern CORBA_Object CORBA_Object_duplicate(
++ CORBA_Object obj,
++ CORBA_Environment *ev);
++
++extern void CORBA_Object_release(
++ CORBA_Object obj,
++ CORBA_Environment *ev);
++
++extern CORBA_boolean CORBA_Object_non_existent(
++ CORBA_Object obj,
++ CORBA_Environment *ev);
++
++extern CORBA_boolean CORBA_Object_is_equivalent(
++ CORBA_Object obj,
++ CORBA_Object other_object,
++ CORBA_Environment *ev);
++
++extern CORBA_unsigned_long CORBA_Object_hash(
++ CORBA_Object obj,
++ CORBA_unsigned_long maximum,
++ CORBA_Environment *ev);
++
++extern CORBA_Policy CORBA_Object_get_policy(
++ CORBA_Object obj,
++ CORBA_PolicyType policy_type,
++ CORBA_Environment *ev);
++
++#ifndef __KORBIT__
++extern CORBA_DomainManagerList *CORBA_Object_get_domain_managers(
++ CORBA_Object obj,
++ CORBA_Environment *ev);
++
++extern CORBA_Policy CORBA_DomainManager_get_domain_policy(
++ CORBA_DomainManager obj,
++ CORBA_PolicyType policy_type,
++ CORBA_Environment *ev);
++
++extern void CORBA_ConstructionPolicy_make_domain_manager(
++ CORBA_ConstructionPolicy obj,
++ CORBA_Object /*CORBA_InterfaceDef*/ object_type,
++ CORBA_boolean constr_policy,
++ CORBA_Environment *ev);
++
++CORBA_TypeCode CORBA_ORB_create_struct_tc(CORBA_ORB obj,
++ CORBA_RepositoryId id,
++ CORBA_Identifier name,
++ CORBA_StructMemberSeq members,
++ CORBA_Environment *ev);
++
++CORBA_TypeCode CORBA_ORB_create_union_tc(CORBA_ORB obj,
++ CORBA_RepositoryId id,
++ CORBA_Identifier name,
++ CORBA_TypeCode discriminator_type,
++ CORBA_UnionMemberSeq members,
++ CORBA_Environment *ev);
++
++CORBA_TypeCode CORBA_ORB_create_enum_tc(CORBA_ORB obj,
++ CORBA_RepositoryId id,
++ CORBA_Identifier name,
++ CORBA_EnumMemberSeq members,
++ CORBA_Environment *ev);
++
++CORBA_TypeCode CORBA_ORB_create_alias_tc(CORBA_ORB obj,
++ CORBA_RepositoryId id,
++ CORBA_Identifier name,
++ CORBA_TypeCode original_type,
++ CORBA_Environment *ev);
++
++CORBA_TypeCode CORBA_ORB_create_exception_tc(CORBA_ORB obj,
++ CORBA_RepositoryId id,
++ CORBA_Identifier name,
++ CORBA_StructMemberSeq members,
++ CORBA_Environment *ev);
++
++CORBA_TypeCode CORBA_ORB_create_interface_tc(CORBA_ORB obj,
++ CORBA_RepositoryId id,
++ CORBA_Identifier name,
++ CORBA_Environment *ev);
++
++CORBA_TypeCode CORBA_ORB_create_string_tc(CORBA_ORB obj,
++ CORBA_unsigned_long bound,
++ CORBA_Environment *ev);
++
++CORBA_TypeCode CORBA_ORB_create_wstring_tc(CORBA_ORB obj,
++ CORBA_unsigned_long bound,
++ CORBA_Environment *ev);
++
++CORBA_TypeCode CORBA_ORB_create_fixed_tc(CORBA_ORB obj,
++ CORBA_unsigned_short digits,
++ CORBA_short scale,
++ CORBA_Environment *ev);
++
++extern CORBA_TypeCode CORBA_ORB_create_sequence_tc(
++ CORBA_ORB obj,
++ CORBA_unsigned_long bound,
++ CORBA_TypeCode element_type,
++ CORBA_Environment *ev);
++
++extern CORBA_TypeCode CORBA_ORB_create_recursive_sequence_tc(
++ CORBA_ORB obj,
++ CORBA_unsigned_long bound,
++ CORBA_unsigned_long offset,
++ CORBA_Environment *ev);
++
++extern CORBA_TypeCode CORBA_ORB_create_array_tc(
++ CORBA_ORB obj,
++ CORBA_unsigned_long length,
++ CORBA_TypeCode element_type,
++ CORBA_Environment *ev);
++
++#endif /* !__KORBIT__ */
++
++#endif /* !_ORBIT_ORB_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/orbit.c linux-2.4.1-korbit/net/korbit/orb/orbit.c
+--- linux-2.4.1/net/korbit/orb/orbit.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit.c Thu Feb 1 11:47:13 2001
+@@ -0,0 +1,387 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++/*
++ * This file is a repository for random functions that don't fit anywhere
++ * else, and for ORBit-specific stuff.
++ */
++
++#include <stdlib.h>
++#include <string.h>
++#include <sys/types.h>
++#include <netdb.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++#include <assert.h>
++#include <math.h>
++
++#include "orbit.h"
++
++const guint orbit_major_version = ORBIT_MAJOR_VERSION,
++ orbit_minor_version = ORBIT_MINOR_VERSION,
++ orbit_micro_version = ORBIT_MICRO_VERSION;
++const char orbit_version[] = ORBIT_VERSION;
++
++typedef struct ORBitClassInfo ORBitClassInfo;
++
++typedef void (*ORBitObjectInitFunc)(CORBA_Object _handle_to_be, gpointer class_data);
++
++struct ORBitClassInfo {
++ char *name;
++ gulong id;
++ gpointer method_stubs, method_skels;
++ ORBitObjectInitFunc class_vtable_init_func;
++ ORBitClassInfo **parent_classes;
++};
++
++GHashTable *orbit_class_list = NULL, *orbit_class_byid;
++glong class_id_counter = -1;
++
++void CORBA_any_set_release(CORBA_any *any, CORBA_boolean flag)
++{
++ g_assert(any!=NULL);
++
++ if(flag==CORBA_TRUE) {
++ any->_release |= CORBA_ANYFLAGS_RELEASE;
++ } else {
++ any->_release &= ~CORBA_ANYFLAGS_RELEASE;
++ }
++
++}
++
++CORBA_boolean CORBA_any_get_release(CORBA_any *any)
++{
++ g_assert(any!=NULL);
++
++ if(any->_release & CORBA_ANYFLAGS_RELEASE)
++ return(CORBA_TRUE);
++ else
++ return(CORBA_FALSE);
++}
++
++void CORBA_sequence_set_release(void *seq, CORBA_boolean flag)
++{
++ struct CORBA_Sequence_type *sequence;
++
++ g_assert(seq!=NULL);
++
++ sequence=(struct CORBA_Sequence_type *)seq;
++
++ if(flag==CORBA_TRUE) {
++ sequence->_release |= CORBA_ANYFLAGS_RELEASE;
++ } else {
++ sequence->_release &= ~CORBA_ANYFLAGS_RELEASE;
++ }
++}
++
++CORBA_boolean CORBA_sequence_get_release(void *seq)
++{
++ struct CORBA_Sequence_type *sequence;
++
++ g_assert(seq!=NULL);
++
++ sequence=(struct CORBA_Sequence_type *)seq;
++
++ if(sequence->_release & CORBA_ANYFLAGS_RELEASE)
++ return(CORBA_TRUE);
++ else
++ return(CORBA_FALSE);
++}
++
++/*
++ * As far as I understand, values returned by CORBA_*_alloc() are supposed to be
++ * freeable by CORBA_free(), so we can't use memory chunks here in any reasonable
++ * fashion.
++ */
++gpointer
++CORBA_any__free(gpointer mem, gpointer func_data, CORBA_boolean free_strings)
++{
++ CORBA_any *aval = mem;
++
++ if(aval->_release)
++ ORBit_free(aval->_value, free_strings);
++ CORBA_Object_release((CORBA_Object)aval->_type, NULL);
++
++ return aval + 1;
++}
++
++CORBA_any *CORBA_any_alloc(void)
++{
++ CORBA_any *retval = ORBit_alloc(sizeof(CORBA_any), &CORBA_any__free,
++ GINT_TO_POINTER(1));
++
++ memset(retval, 0, sizeof(CORBA_any)); /* Make things easier on stubs */
++
++ return retval;
++}
++
++/*
++ * Compares the typecodes of each any
++ */
++CORBA_boolean ORBit_any_equivalent(CORBA_any obj, CORBA_any any, CORBA_Environment *ev)
++{
++ return(CORBA_FALSE);
++}
++
++/* This is needed by skels, that generate a __free function when they see
++ the TypeCode interface */
++gpointer
++CORBA_TypeCode__free(gpointer mem, gpointer func_data, CORBA_boolean free_strings)
++{
++ CORBA_Object_release(*(CORBA_Object *)mem, NULL);
++ return ((guchar *)mem) + sizeof(CORBA_TypeCode);
++}
++
++CORBA_char *CORBA_string_dup(const CORBA_char *string)
++{
++ if(!string)
++ return NULL;
++
++ return strcpy(ORBit_alloc(strlen(string)+1, NULL, NULL), string);
++}
++
++CORBA_char *CORBA_string_alloc(CORBA_unsigned_long len)
++{
++ return ORBit_alloc(len + 1, NULL, NULL);
++}
++
++CORBA_wchar *CORBA_wstring_alloc(CORBA_unsigned_long len)
++{
++ return ORBit_alloc(len + 1, NULL, NULL);
++}
++
++gpointer
++CORBA_string__free(gpointer str, gpointer dat, CORBA_boolean free_strings)
++{
++ if(free_strings)
++ CORBA_free(*((gpointer *)str));
++ return (gpointer)((guchar *)str + sizeof(CORBA_char *));
++}
++
++gpointer CORBA_Object__free(gpointer str, gpointer dat, CORBA_boolean free_strings)
++{
++ CORBA_Environment ev;
++ CORBA_exception_init(&ev);
++ CORBA_Object_release(*((gpointer *)str), &ev);
++ CORBA_exception_free(&ev);
++ return (gpointer)((guchar *)str + sizeof(CORBA_Object));
++}
++
++/* 19.14 */
++
++/* The big picture for fixeds.
++ We have to represent a number in memory.
++
++ 1 2 3 . 4 5 6 7
++
++ There are three pieces of information in a fixed:
++
++ - Number of significant digits. (_digits)
++
++ - The scale. The number of places the decimal point is to the right
++ of the first significant digit. (_scale)
++
++ - The digits themselves (_value)
++
++ */
++CORBA_long CORBA_fixed_integer_part(const void *fp)
++{
++ CORBA_long retval = 0;
++ int i, power_of_ten, digit;
++ const CORBA_fixed_d_s *val = fp;
++
++ g_return_val_if_fail(fp != NULL, INT_MIN);
++
++ for(i = 0; i < (val->_digits - val->_scale); i++) {
++ power_of_ten = val->_digits - i - val->_scale - 1;
++ digit = val->_value[i];
++ retval += digit * ((int)pow(10, power_of_ten));
++ }
++
++ return retval;
++}
++
++CORBA_long CORBA_fixed_fraction_part(const void *fp)
++{
++ CORBA_long retval = 0;
++ int i, power_of_ten, digit;
++ const CORBA_fixed_d_s *val = fp;
++
++ g_return_val_if_fail(fp != NULL, INT_MIN);
++
++ for(i = val->_digits - val->_scale; i < val->_digits; i++){
++ power_of_ten = val->_digits - i - 1;
++ digit = val->_value[i];
++ retval += digit * ((int)pow(10, power_of_ten));
++ }
++
++ return retval;
++}
++
++static inline
++CORBA_long do_div (CORBA_long *n)
++{
++ int __res;
++
++ __res = (*n) % (unsigned) 10;
++ *n = (*n) / (unsigned) 10;
++
++ return __res;
++}
++
++void CORBA_fixed_set(void *rp, CORBA_long i, CORBA_long f)
++{
++ CORBA_fixed_d_s *val = rp;
++ CORBA_long left_to_eat, cur;
++ signed char sign = 1;
++
++ g_return_if_fail(rp != NULL);
++
++ memset(val->_value, 0, val->_digits);
++
++ if(i) sign = i/abs(i);
++ val->_sign = sign;
++ i = abs(i);
++ f = abs(f);
++
++ for(cur = 0, left_to_eat = i;
++ left_to_eat != 0 && cur < val->_digits; cur++) {
++ val->_value[cur] = do_div(&left_to_eat) * sign;
++ sign = 1;
++ }
++
++ val->_scale = cur - 1;
++
++ for(left_to_eat = f;
++ left_to_eat != 0 && cur < val->_digits; cur++) {
++ val->_value[cur] = do_div(&left_to_eat);
++ }
++}
++
++void CORBA_fixed_add(void *rp, const void *f1p, const void *f2p)
++{
++ g_assert(!"Not yet implemented");
++}
++
++void CORBA_fixed_sub(void *rp, const void *f1p, const void *f2p)
++{
++ g_assert(!"Not yet implemented");
++}
++
++void CORBA_fixed_mul(void *rp, const void *f1p, const void *f2p)
++{
++ g_assert(!"Not yet implemented");
++}
++
++void CORBA_fixed_div(void *rp, const void *f1p, const void *f2p)
++{
++ g_assert(!"Not yet implemented");
++}
++
++CORBA_fixed_d_s *CORBA_fixed_alloc(CORBA_unsigned_short d)
++{
++ return (CORBA_fixed_d_s *)
++ g_malloc(sizeof(CORBA_fixed_d_s) + d + 1);
++}
++
++void CORBA_free(void *storage)
++{
++ ORBit_free(storage, CORBA_TRUE);
++}
++
++int ORBit_parse_unixsock(CORBA_Object obj,
++ char *sockpath,
++ gboolean existing_only)
++{
++ if(!sockpath || !*sockpath)
++ return -1;
++
++ obj->connection =
++ GIOP_CONNECTION(iiop_connection_unix_get(sockpath,
++ existing_only));
++
++ if(!obj->connection)
++ return -1;
++
++ giop_connection_ref(obj->connection);
++ return 0;
++}
++
++int ORBit_parse_inet(CORBA_Object obj, char *hostname, unsigned short port,
++ gboolean existing_only)
++{
++ obj->connection = GIOP_CONNECTION(iiop_connection_get(hostname, port, existing_only));
++
++ if(!obj->connection)
++ return -1;
++ giop_connection_ref(obj->connection);
++ return 0;
++}
++
++static const CORBA_unsigned_long zero_int = 0;
++struct iovec ORBit_default_principal_iovec = {(gpointer)&zero_int, sizeof(zero_int)};
++
++void ORBit_set_default_principal(CORBA_Principal *principal)
++{
++ gpointer t;
++
++ if((gpointer)ORBit_default_principal_iovec.iov_base != (gpointer)&zero_int)
++ g_free(ORBit_default_principal_iovec.iov_base);
++
++ ORBit_default_principal_iovec.iov_len = principal->_length
++ + sizeof(CORBA_unsigned_long);
++
++ t = ORBit_default_principal_iovec.iov_base =
++ g_malloc(ORBit_default_principal_iovec.iov_len);
++
++ memcpy(t, &principal->_length, sizeof(principal->_length));
++
++ t = ((guchar *)t) + sizeof(principal->_length);
++ memcpy(t, principal->_buffer, principal->_length);
++}
++
++CORBA_unsigned_long ORBit_class_assignment_counter = 0;
++GHashTable *ORBit_class_assignments = NULL;
++
++/* XXX not thread-safe */
++CORBA_unsigned_long
++ORBit_register_class(const PortableServer_ClassInfo *class_info)
++{
++ CORBA_unsigned_long retval;
++
++ if(!ORBit_class_assignments)
++ ORBit_class_assignments = g_hash_table_new(g_str_hash, g_str_equal);
++
++ /* This needs to be pre-increment - we don't want to give out
++ classid 0, because (a) that is reserved for the base Object class
++ (b) all the routines allocate a new id if the variable
++ storing their ID == 0 */
++ retval = ++ORBit_class_assignment_counter;
++
++ g_hash_table_insert(ORBit_class_assignments, (gpointer)class_info->class_name,
++ GINT_TO_POINTER(retval));
++
++ return retval;
++}
+diff -urN linux-2.4.1/net/korbit/orb/orbit.h linux-2.4.1-korbit/net/korbit/orb/orbit.h
+--- linux-2.4.1/net/korbit/orb/orbit.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit.h Thu Feb 1 11:47:13 2001
+@@ -0,0 +1,207 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@acm.org>
++ * Elliot Lee <sopwith@redhat.com>
++ *
++ */
++
++/* these two blocks are outside of the main header for good reason...
++ People may include headers from many different stubs, and we want to
++ have the version checked on all of them.
++ */
++#ifndef ORBIT_SERIAL
++#define ORBIT_SERIAL 9
++#endif
++
++#ifdef ORBIT_IDL_SERIAL
++#if ORBIT_IDL_SERIAL < 9
++#error "You need to rerun 'orbit-idl' on the .idl file whose stubs you are using. These stubs were generated with an older version of ORBit, and need to be regenerated."
++#endif
++#endif
++
++#ifndef _ORBIT_H_
++#define _ORBIT_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++#include <glib.h>
++
++#define BACKWARDS_COMPAT_0_4
++#undef NOT_BACKWARDS_COMPAT_0_4
++
++#include <sys/types.h>
++#include <sys/uio.h>
++#include <IIOP/IIOP.h>
++#include <ORBitutil/util.h>
++#include <orb/orbit_config.h>
++#include <orb/orbit_types.h>
++#include <orb/allocators.h>
++#include <orb/cdr.h>
++#include <orb/dii.h>
++#ifndef __KORBIT__
++#include <orb/dynany.h>
++#endif
++#include <orb/env.h>
++#include <orb/iop.h>
++#include <orb/ir.h>
++#include <orb/options.h>
++#include <orb/orb.h>
++#include <orb/poa.h>
++#include <orb/sequences.h>
++#include <orb/orbit_typecode.h>
++#include <orb/typecode.h>
++
++#ifndef ORBIT_MAJOR_VERSION
++#define ORBIT_MAJOR_VERSION (0)
++#define ORBIT_MINOR_VERSION (5)
++#define ORBIT_MICRO_VERSION (3)
++#endif
++
++extern const guint orbit_major_version,
++ orbit_minor_version,
++ orbit_micro_version;
++extern const char orbit_version[];
++
++extern void CORBA_any_set_release(
++ CORBA_any *,
++ CORBA_boolean);
++
++extern CORBA_boolean CORBA_any_get_release(
++ CORBA_any *);
++
++extern void CORBA_sequence_set_release(
++ void *,
++ CORBA_boolean);
++
++extern CORBA_boolean CORBA_sequence_get_release(
++ void *);
++
++#define CORBA_any__alloc CORBA_any_alloc
++extern CORBA_any *CORBA_any_alloc(
++ void);
++
++extern gpointer CORBA_any__free(gpointer mem, gpointer func_data,
++ CORBA_boolean free_strings);
++extern gpointer CORBA_TypeCode__free(gpointer mem, gpointer func_data,
++ CORBA_boolean free_strings);
++
++extern CORBA_boolean ORBit_any_equivalent(
++ CORBA_any obj,
++ CORBA_any any,
++ CORBA_Environment *ev);
++
++extern CORBA_char *CORBA_string_dup(const CORBA_char *string);
++extern CORBA_char *CORBA_string_alloc(CORBA_unsigned_long len);
++extern gpointer CORBA_string__free(gpointer str, gpointer dat, CORBA_boolean free_strings);
++
++gpointer CORBA_Object__free(gpointer str, gpointer dat, CORBA_boolean free_strings);
++
++extern CORBA_wchar *CORBA_wstring_alloc(CORBA_unsigned_long len);
++#define CORBA_wstring_free CORBA_string_free
++
++/* 19.14 */
++extern CORBA_long CORBA_fixed_integer_part(
++ const void *fp);
++
++extern CORBA_long CORBA_fixed_fraction_part(
++ const void *fp);
++
++extern void CORBA_fixed_set(
++ void *rp,
++ CORBA_long i,
++ CORBA_long f);
++
++extern void CORBA_fixed_add(
++ void *rp,
++ const void *f1p,
++ const void *f2p);
++
++extern void CORBA_fixed_sub(
++ void *rp,
++ const void *f1p,
++ const void *f2p);
++
++extern void CORBA_fixed_mul(
++ void *rp,
++ const void *f1p,
++ const void *f2p);
++
++extern void CORBA_fixed_div(
++ void *rp,
++ const void *f1p,
++ const void *f2p);
++
++extern CORBA_fixed_d_s *CORBA_fixed_alloc(
++ CORBA_unsigned_short d);
++
++extern void CORBA_free(
++ void *storage);
++
++extern int ORBit_parse_inet(
++ CORBA_Object obj,
++ char *hostname,
++ unsigned short port,
++ gboolean existing_only);
++
++extern int ORBit_parse_unixsock(CORBA_Object obj,
++ char *sockpath,
++ gboolean existing_only);
++
++/****
++ This function lets you use your own event loop, if you so wish.
++ Also see IIOP.h's IIOP{Add,Remove}ConnectionHandler function pointers,
++ which are app-settable (you should set them before CORBA_ORB_init,
++ if you want them to be useful)
++ ****/
++
++ /* needs to be called by your event loop when data comes in on one of the
++ GIOPConnection fd's */
++void ORBit_custom_run_setup(CORBA_ORB orb, CORBA_Environment *ev);
++ void ORBit_handle_incoming(GIOPConnection *connection);
++
++/* Returns CORBA_TRUE if the request is OK to proceed. */
++typedef enum {
++ ORBIT_MESSAGE_BAD,
++ ORBIT_MESSAGE_ALLOW,
++ ORBIT_MESSAGE_ALLOW_ALL /* Allow all subsequent messages on
++ this connection with no checking */
++} ORBit_MessageValidationResult;
++typedef ORBit_MessageValidationResult (*ORBit_request_validate)
++ (CORBA_unsigned_long request_id,
++ CORBA_Principal *principal,
++ CORBA_char *operation);
++void ORBit_set_request_validation_handler(ORBit_request_validate validator);
++
++extern struct iovec ORBit_default_principal_iovec;
++void ORBit_set_default_principal(CORBA_Principal *principal);
++
++extern CORBA_unsigned_long ORBit_class_assignment_counter;
++
++CORBA_unsigned_long ORBit_register_class(const PortableServer_ClassInfo *class_info);
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* !_ORBIT_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/orbit.h.in linux-2.4.1-korbit/net/korbit/orb/orbit.h.in
+--- linux-2.4.1/net/korbit/orb/orbit.h.in Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit.h.in Thu Feb 1 11:47:13 2001
+@@ -0,0 +1,205 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@acm.org>
++ * Elliot Lee <sopwith@redhat.com>
++ *
++ */
++
++/* these two blocks are outside of the main header for good reason...
++ People may include headers from many different stubs, and we want to
++ have the version checked on all of them.
++ */
++#ifndef ORBIT_SERIAL
++#define ORBIT_SERIAL @ORBIT_SERIAL@
++#endif
++
++#ifdef ORBIT_IDL_SERIAL
++#if ORBIT_IDL_SERIAL < @ORBIT_SERIAL@
++#error "You need to rerun 'orbit-idl' on the .idl file whose stubs you are using. These stubs were generated with an older version of ORBit, and need to be regenerated."
++#endif
++#endif
++
++#ifndef _ORBIT_H_
++#define _ORBIT_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++#include <glib.h>
++
++#define BACKWARDS_COMPAT_0_4
++#undef NOT_BACKWARDS_COMPAT_0_4
++
++#include <sys/types.h>
++#include <sys/uio.h>
++#include <IIOP/IIOP.h>
++#include <ORBitutil/util.h>
++#include <orb/orbit_config.h>
++#include <orb/orbit_types.h>
++#include <orb/allocators.h>
++#include <orb/cdr.h>
++#include <orb/dii.h>
++#include <orb/dynany.h>
++#include <orb/env.h>
++#include <orb/iop.h>
++#include <orb/ir.h>
++#include <orb/options.h>
++#include <orb/orb.h>
++#include <orb/poa.h>
++#include <orb/sequences.h>
++#include <orb/orbit_typecode.h>
++#include <orb/typecode.h>
++
++#ifndef ORBIT_MAJOR_VERSION
++#define ORBIT_MAJOR_VERSION (@ORBIT_MAJOR_VERSION@)
++#define ORBIT_MINOR_VERSION (@ORBIT_MINOR_VERSION@)
++#define ORBIT_MICRO_VERSION (@ORBIT_MICRO_VERSION@)
++#endif
++
++extern const guint orbit_major_version,
++ orbit_minor_version,
++ orbit_micro_version;
++extern const char orbit_version[];
++
++extern void CORBA_any_set_release(
++ CORBA_any *,
++ CORBA_boolean);
++
++extern CORBA_boolean CORBA_any_get_release(
++ CORBA_any *);
++
++extern void CORBA_sequence_set_release(
++ void *,
++ CORBA_boolean);
++
++extern CORBA_boolean CORBA_sequence_get_release(
++ void *);
++
++#define CORBA_any__alloc CORBA_any_alloc
++extern CORBA_any *CORBA_any_alloc(
++ void);
++
++extern gpointer CORBA_any__free(gpointer mem, gpointer func_data,
++ CORBA_boolean free_strings);
++extern gpointer CORBA_TypeCode__free(gpointer mem, gpointer func_data,
++ CORBA_boolean free_strings);
++
++extern CORBA_boolean ORBit_any_equivalent(
++ CORBA_any obj,
++ CORBA_any any,
++ CORBA_Environment *ev);
++
++extern CORBA_char *CORBA_string_dup(const CORBA_char *string);
++extern CORBA_char *CORBA_string_alloc(CORBA_unsigned_long len);
++extern gpointer CORBA_string__free(gpointer str, gpointer dat, CORBA_boolean free_strings);
++
++gpointer CORBA_Object__free(gpointer str, gpointer dat, CORBA_boolean free_strings);
++
++extern CORBA_wchar *CORBA_wstring_alloc(CORBA_unsigned_long len);
++#define CORBA_wstring_free CORBA_string_free
++
++/* 19.14 */
++extern CORBA_long CORBA_fixed_integer_part(
++ const void *fp);
++
++extern CORBA_long CORBA_fixed_fraction_part(
++ const void *fp);
++
++extern void CORBA_fixed_set(
++ void *rp,
++ CORBA_long i,
++ CORBA_long f);
++
++extern void CORBA_fixed_add(
++ void *rp,
++ const void *f1p,
++ const void *f2p);
++
++extern void CORBA_fixed_sub(
++ void *rp,
++ const void *f1p,
++ const void *f2p);
++
++extern void CORBA_fixed_mul(
++ void *rp,
++ const void *f1p,
++ const void *f2p);
++
++extern void CORBA_fixed_div(
++ void *rp,
++ const void *f1p,
++ const void *f2p);
++
++extern CORBA_fixed_d_s *CORBA_fixed_alloc(
++ CORBA_unsigned_short d);
++
++extern void CORBA_free(
++ void *storage);
++
++extern int ORBit_parse_inet(
++ CORBA_Object obj,
++ char *hostname,
++ unsigned short port,
++ gboolean existing_only);
++
++extern int ORBit_parse_unixsock(CORBA_Object obj,
++ char *sockpath,
++ gboolean existing_only);
++
++/****
++ This function lets you use your own event loop, if you so wish.
++ Also see IIOP.h's IIOP{Add,Remove}ConnectionHandler function pointers,
++ which are app-settable (you should set them before CORBA_ORB_init,
++ if you want them to be useful)
++ ****/
++
++ /* needs to be called by your event loop when data comes in on one of the
++ GIOPConnection fd's */
++void ORBit_custom_run_setup(CORBA_ORB orb, CORBA_Environment *ev);
++ void ORBit_handle_incoming(GIOPConnection *connection);
++
++/* Returns CORBA_TRUE if the request is OK to proceed. */
++typedef enum {
++ ORBIT_MESSAGE_BAD,
++ ORBIT_MESSAGE_ALLOW,
++ ORBIT_MESSAGE_ALLOW_ALL /* Allow all subsequent messages on
++ this connection with no checking */
++} ORBit_MessageValidationResult;
++typedef ORBit_MessageValidationResult (*ORBit_request_validate)
++ (CORBA_unsigned_long request_id,
++ CORBA_Principal *principal,
++ CORBA_char *operation);
++void ORBit_set_request_validation_handler(ORBit_request_validate validator);
++
++extern struct iovec ORBit_default_principal_iovec;
++void ORBit_set_default_principal(CORBA_Principal *principal);
++
++extern CORBA_unsigned_long ORBit_class_assignment_counter;
++
++CORBA_unsigned_long ORBit_register_class(const PortableServer_ClassInfo *class_info);
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* !_ORBIT_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/orbit_config.h linux-2.4.1-korbit/net/korbit/orb/orbit_config.h
+--- linux-2.4.1/net/korbit/orb/orbit_config.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit_config.h Thu Feb 1 11:47:13 2001
+@@ -0,0 +1,9 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++#ifndef ORB_CONFIG_H
++#define ORB_CONFIG_H 1
++
++/* When creating a memory pool for a particular type, how many chunks
++ do we want to pre-allocated? */
++#define ORBIT_CHUNKS_PREALLOC 2
++
++#endif /* ORB_CONFIG_H */
+diff -urN linux-2.4.1/net/korbit/orb/orbit_object.c linux-2.4.1-korbit/net/korbit/orb/orbit_object.c
+--- linux-2.4.1/net/korbit/orb/orbit_object.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit_object.c Thu Feb 1 11:47:13 2001
+@@ -0,0 +1,699 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Phil Dawes <philipd@parallax.co.uk>
++ * Elliot Lee <sopwith@redhat.com>
++ *
++ */
++
++/*
++ * ORBit specific CORBA_Object functions.
++ *
++ */
++
++#include <string.h>
++#include "config.h"
++#include "../IIOP/iiop-endianP.h"
++#include "orbit_object_type.h"
++#include "corba_object_type.h"
++#include "allocators.h"
++#include "iop.h"
++#include <IIOP/IIOP.h>
++
++static void ORBit_object_try_existing_connections(CORBA_Object obj);
++static void CORBA_Object_release_fn(CORBA_Object obj, CORBA_Environment *ev);
++
++static ORBit_RootObject_Interface CORBA_Object_epv =
++{
++ (void (*)(gpointer, CORBA_Environment *))CORBA_Object_release_fn,
++};
++
++void ORBit_pseudo_object_init(ORBit_PseudoObject obj,
++ ORBit_PseudoObject_type obj_type,
++ CORBA_Environment *ev)
++{
++ ORBIT_ROOT_OBJECT(obj)->is_pseudo_object = TRUE;
++ ORBIT_ROOT_OBJECT(obj)->refs = 0;
++ ORBIT_PSEUDO_OBJECT(obj)->pseudo_object_type = obj_type;
++}
++
++static const ORBit_RootObject_Interface CORBA_Policy__epv =
++{
++ (void (*)(gpointer, CORBA_Environment *))CORBA_Policy_destroy
++};
++
++void ORBit_policy_object_init(CORBA_Policy obj,
++ CORBA_PolicyType obj_type,
++ CORBA_Environment *ev)
++{
++ ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(obj),
++ ORBIT_PSEUDO_POLICY, ev);
++
++ obj->policy_type = obj_type;
++
++ ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(obj),
++ (gpointer)&CORBA_Policy__epv,
++ ev);
++}
++
++void ORBit_object_reference_init(CORBA_Object obj, CORBA_Environment *ev)
++{
++ /* set the interface up */
++ ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(obj),&CORBA_Object_epv,ev);
++ /* initialise the reference count */
++ ORBIT_ROOT_OBJECT(obj)->refs = 0;
++ ORBIT_ROOT_OBJECT(obj)->is_pseudo_object = FALSE;
++}
++
++CORBA_Object
++ORBit_CORBA_Object_new(CORBA_Environment *ev)
++{
++ CORBA_Object obj;
++ /* Create the object */
++ obj = ORBIT_CHUNK_ALLOC(CORBA_Object);
++ memset(obj, '\0', sizeof(struct CORBA_Object_struct));
++
++ ORBit_object_reference_init(obj, ev);
++
++ return obj;
++
++}
++
++void
++ORBit_set_object_key(ORBit_Object_info *info)
++{
++ g_assert(info);
++
++ g_assert(info->object_key._length);
++
++ info->object_key_data = g_malloc(sizeof(CORBA_unsigned_long) + info->object_key._length);
++ info->object_key_data->_length = info->object_key._length;
++ memcpy(info->object_key_data->_buffer, info->object_key._buffer, info->object_key._length);
++
++ info->object_key_vec.iov_base =
++ (gpointer)info->object_key_data;
++ info->object_key_vec.iov_len = sizeof(CORBA_unsigned_long) + info->object_key._length;
++}
++
++static void ORBit_free_profile(gpointer item, gpointer data)
++{
++ ORBit_Object_info *info=(ORBit_Object_info *)item;
++
++ g_assert(info);
++
++ g_free(info->object_key_data);
++ CORBA_free(info->object_key._buffer);
++
++ if(info->profile_type == IOP_TAG_INTERNET_IOP) {
++ g_free(info->tag.iopinfo.host);
++ } else if(info->profile_type == IOP_TAG_ORBIT_SPECIFIC) {
++ g_free(info->tag.orbitinfo.unix_sock_path);
++ } else {
++ g_warning("ORBit_free_profile asked to free type %d", info->profile_type);
++ }
++
++ g_free(info); /* Check its safe to free the item within a foreach func */
++}
++
++void ORBit_delete_profiles(GSList *profile_list)
++{
++ g_slist_foreach(profile_list, ORBit_free_profile, NULL);
++ g_slist_free(profile_list);
++}
++
++/* this function is wired up to the RootObject interface */
++void
++CORBA_Object_release_fn(CORBA_Object obj, CORBA_Environment *ev)
++{
++
++ g_assert(obj!=NULL);
++
++ ORBIT_ROOT_OBJECT_UNREF(obj);
++
++ if(ORBIT_ROOT_OBJECT(obj)->refs <= 0) {
++ g_hash_table_remove(obj->orb->objrefs, obj);
++
++ if(obj->connection)
++ giop_connection_unref(obj->connection);
++
++ g_free(obj->object_id);
++ ORBit_delete_profiles(obj->profile_list);
++ ORBit_delete_profiles(obj->forward_locations);
++
++ ORBIT_CHUNK_FREE(CORBA_Object, obj);
++ }
++}
++
++
++/* Sets the interface member in the RootObject to the epv specified*/
++void
++ORBit_RootObject_set_interface(ORBit_RootObject obj,
++ ORBit_RootObject_Interface* epv,
++ CORBA_Environment *ev)
++{
++ g_assert(obj!=NULL);
++ g_assert(epv!=NULL);
++
++ obj->interface = epv;
++}
++
++#define GET_ATOM(x) G_STMT_START{ GIOP_RECV_BUFFER(recv_buffer)->decoder(&x, (GIOP_RECV_BUFFER(recv_buffer)->cur), sizeof(x)); \
++GIOP_RECV_BUFFER(recv_buffer)->cur = ((guchar *)GIOP_RECV_BUFFER(recv_buffer)->cur) + sizeof(x); \
++}G_STMT_END
++#define ALIGNFOR(x) recv_buffer->cur = ALIGN_ADDRESS(recv_buffer->cur, sizeof(x))
++
++CORBA_Object
++ORBit_create_object_with_info(GSList *profiles,
++ const CORBA_char *type_id,
++ CORBA_ORB orb,
++ CORBA_Environment *ev)
++{
++ CORBA_Object new;
++ struct CORBA_Object_struct refcheck;
++
++ if(!type_id || !*type_id) {
++ g_warning("Failing object creation because object has no type");
++ CORBA_exception_set_system(ev, ex_CORBA_MARSHAL,
++ CORBA_COMPLETED_MAYBE);
++ return CORBA_OBJECT_NIL;
++ }
++
++ if(g_slist_length(profiles) < 1) {
++ g_warning("Failing object creation because object has no profiles");
++ CORBA_exception_set_system(ev, ex_CORBA_MARSHAL,
++ CORBA_COMPLETED_MAYBE);
++ return CORBA_OBJECT_NIL;
++ }
++
++ /* XXX badhack :) */
++ refcheck.object_id = type_id;
++ refcheck.profile_list = profiles;
++
++ new = g_hash_table_lookup(orb->objrefs, &refcheck);
++ if(new) {
++ ORBit_delete_profiles(profiles);
++ return CORBA_Object_duplicate(new, ev);
++ }
++
++ new = ORBit_CORBA_Object_new(ev);
++ new->connection = NULL;
++ new->object_id = g_strdup(type_id);
++ new->orb = (CORBA_ORB)CORBA_Object_duplicate((CORBA_Object)orb, ev);
++ new->profile_list = profiles;
++ new->active_profile = NULL;
++
++ ORBit_object_try_existing_connections(new);
++
++ g_hash_table_insert(orb->objrefs, new, new);
++
++ return CORBA_Object_duplicate(new, ev);
++}
++
++static ORBit_Object_info *
++ORBit_demarshal_profile(GIOPRecvBuffer *recv_buffer, IOP_ProfileId profile_id)
++{
++ ORBit_Object_info *object_info;
++ CORBA_unsigned_long subpart_len;
++ CORBA_octet o;
++ CDR_Codec codec_d;
++ CDR_Codec *codec=&codec_d;
++
++ object_info = g_new0(ORBit_Object_info, 1);
++
++ switch(profile_id) {
++ case IOP_TAG_INTERNET_IOP:
++ GET_ATOM(subpart_len); /* The length of the embedded sequence */
++ CDR_codec_init_static(codec);
++ codec->buffer = recv_buffer->cur;
++ codec->release_buffer = CORBA_FALSE;
++ recv_buffer->cur = ((guchar *)recv_buffer->cur) + subpart_len;
++
++ codec->readonly = CORBA_TRUE;
++ codec->host_endian = codec->data_endian = FLAG_ENDIANNESS;
++ codec->buf_len = subpart_len;
++
++ CDR_get_octet(codec, &o);
++ codec->data_endian = o;
++
++ object_info->profile_type = IOP_TAG_INTERNET_IOP;
++ CDR_get_octet(codec, &object_info->iiop_major);
++
++ if(object_info->iiop_major != 1)
++ goto error_exit;
++ /* XXX should we check for a specific minor version? */
++ CDR_get_octet(codec, &object_info->iiop_minor);
++
++ CDR_get_string(codec, &object_info->tag.iopinfo.host);
++
++ CDR_get_ushort(codec, &object_info->tag.iopinfo.port);
++
++ CDR_get_seq_begin(codec, &object_info->object_key._length);
++ object_info->object_key._buffer =
++ ORBit_alloc(object_info->object_key._length, NULL, NULL);
++ CDR_buffer_gets(codec, object_info->object_key._buffer,
++ object_info->object_key._length);
++ object_info->object_key._maximum = object_info->object_key._release = 0;
++
++ ORBit_set_object_key(object_info);
++
++ return(object_info);
++ break;
++
++ case IOP_TAG_MULTIPLE_COMPONENTS:
++ default:
++ GET_ATOM(subpart_len);
++ g_warning("IOP_TAG_MULTIPLE_COMPONENTS decoding needs finishing");
++ object_info->profile_type = IOP_TAG_MULTIPLE_COMPONENTS;
++ recv_buffer->cur = ((guchar *)recv_buffer->cur) + subpart_len;
++ return(object_info);
++ break;
++
++ case IOP_TAG_ORBIT_SPECIFIC:
++ GET_ATOM(subpart_len);
++ CDR_codec_init_static(codec);
++ codec->buffer = recv_buffer->cur;
++ codec->release_buffer = CORBA_FALSE;
++ recv_buffer->cur = ((guchar *)recv_buffer->cur) + subpart_len;
++
++ codec->readonly = CORBA_TRUE;
++ codec->host_endian = codec->data_endian = FLAG_ENDIANNESS;
++ codec->buf_len = subpart_len;
++
++ CDR_get_octet(codec, &o);
++ codec->data_endian = o;
++
++ object_info->profile_type = IOP_TAG_ORBIT_SPECIFIC;
++ CDR_get_octet(codec, &object_info->iiop_major);
++
++ if(object_info->iiop_major != 1)
++ goto error_exit;
++ /* XXX should we check for a specific minor version? */
++ CDR_get_octet(codec, &object_info->iiop_minor);
++
++ CDR_get_string(codec, &object_info->tag.orbitinfo.unix_sock_path);
++ CDR_get_ushort(codec, &object_info->tag.orbitinfo.ipv6_port);
++
++ CDR_get_seq_begin(codec, &object_info->object_key._length);
++ object_info->object_key._buffer =
++ ORBit_alloc(object_info->object_key._length, NULL, NULL);
++ CDR_buffer_gets(codec, object_info->object_key._buffer,
++ object_info->object_key._length);
++ object_info->object_key._maximum = object_info->object_key._release = 0;
++
++ ORBit_set_object_key(object_info);
++
++ return(object_info);
++ break;
++ }
++
++error_exit:
++ g_message("demarshal_profile(): IIOP major is %d",
++ object_info->iiop_major);
++ g_free(object_info);
++
++ return(NULL);
++}
++
++GSList *ORBit_demarshal_IOR(GIOPRecvBuffer *recv_buffer)
++{
++ GSList *profiles=NULL;
++ ORBit_Object_info *object_info;
++ CORBA_unsigned_long len, seq_len;
++ IOP_ProfileId profile_id;
++ int i;
++
++ /* Get type_id */
++ ALIGNFOR(CORBA_unsigned_long);
++ GET_ATOM(len);
++
++ if(len == 0)
++ return(NULL);
++
++ recv_buffer->cur = ((guchar *)recv_buffer->cur) + len;
++
++ /* Decode the sequence<TaggedProfile> */
++ ALIGNFOR(CORBA_unsigned_long);
++ GET_ATOM(seq_len);
++ for(i = 0; i < seq_len; i++) {
++ ALIGNFOR(CORBA_unsigned_long);
++ GET_ATOM(profile_id);
++ object_info=ORBit_demarshal_profile(recv_buffer, profile_id);
++ if(object_info==NULL) {
++ goto error_exit;
++ } else {
++ profiles=g_slist_append(profiles, object_info);
++ }
++ }
++
++ return(profiles);
++
++error_exit:
++ ORBit_delete_profiles(profiles);
++ return(NULL);
++}
++
++CORBA_Object
++ORBit_demarshal_object(GIOPRecvBuffer *recv_buffer, CORBA_ORB orb)
++{
++ GSList *profiles=NULL;
++ ORBit_Object_info *object_info;
++ CORBA_char *type_id;
++ CORBA_unsigned_long len, seq_len;
++ IOP_ProfileId profile_id;
++ int i;
++ CORBA_Environment ev;
++ CORBA_Object retval;
++
++ CORBA_exception_init(&ev);
++
++ /* Get type_id */
++ ALIGNFOR(CORBA_unsigned_long);
++ GET_ATOM(len);
++
++ type_id = recv_buffer->cur;
++ recv_buffer->cur = ((guchar *)recv_buffer->cur) + len;
++
++ /* Decode the sequence<TaggedProfile> */
++ ALIGNFOR(CORBA_unsigned_long);
++ GET_ATOM(seq_len);
++
++ if(!seq_len)
++ return CORBA_OBJECT_NIL;
++
++ for(i = 0; i < seq_len; i++) {
++ ALIGNFOR(CORBA_unsigned_long);
++ GET_ATOM(profile_id);
++ object_info=ORBit_demarshal_profile(recv_buffer, profile_id);
++ if(object_info)
++ profiles=g_slist_append(profiles, object_info);
++ }
++
++ if(!profiles)
++ goto error_exit;
++
++ retval = ORBit_create_object_with_info(profiles, type_id, orb, &ev);
++
++ return retval;
++
++ error_exit:
++ ORBit_delete_profiles(profiles);
++
++ CORBA_exception_set_system(&ev, ex_CORBA_MARSHAL,
++ CORBA_COMPLETED_MAYBE);
++ return CORBA_OBJECT_NIL;
++}
++
++static void ORBit_marshal_profile(gpointer item, gpointer data)
++{
++ ORBit_Object_info *info = (ORBit_Object_info *)item;
++ GIOPSendBuffer *send_buffer = (GIOPSendBuffer *)data;
++ static const CORBA_unsigned_long ioptag = IOP_TAG_INTERNET_IOP,
++ orbittag = IOP_TAG_ORBIT_SPECIFIC;
++ CDR_Codec codec_d;
++ CDR_Codec *codec = &codec_d;
++ CORBA_unsigned_long len;
++ CORBA_octet codecbuf[2048];
++ static const CORBA_octet oc_endian = FLAG_ENDIANNESS;
++ static const CORBA_octet iiopversion[] = {1,0};
++
++ g_assert(info);
++ g_assert(send_buffer);
++
++ if(info->profile_type == IOP_TAG_INTERNET_IOP) {
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer),
++ &ioptag, sizeof(ioptag));
++
++ CDR_codec_init_static(codec);
++ codec->buffer = codecbuf;
++ codec->buf_len = 2048;
++ codec->release_buffer = CORBA_FALSE;
++ codec->readonly = CORBA_FALSE;
++ codec->data_endian = codec->host_endian = FLAG_ENDIANNESS;
++ CDR_put_octet(codec, oc_endian);
++ CDR_put_octet(codec, iiopversion[0]);
++ CDR_put_octet(codec, iiopversion[1]);
++ CDR_put_string(codec, info->tag.iopinfo.host);
++ CDR_put_ushort(codec, info->tag.iopinfo.port);
++ CDR_put_ulong(codec, info->object_key._length);
++ CDR_put_octets(codec, info->object_key._buffer,
++ info->object_key._length);
++ len = codec->wptr;
++ giop_send_buffer_append_mem_indirect_a(send_buffer,
++ &len, sizeof(len));
++ giop_send_buffer_append_mem_indirect(send_buffer,
++ codec->buffer, codec->wptr);
++ } else if(info->profile_type==IOP_TAG_ORBIT_SPECIFIC) {
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(send_buffer),
++ &orbittag, sizeof(orbittag));
++ CDR_codec_init_static(codec);
++ codec->buffer = codecbuf;
++ codec->release_buffer = CORBA_FALSE;
++ codec->buf_len = 2048;
++ codec->readonly = CORBA_FALSE;
++ codec->data_endian = codec->host_endian = FLAG_ENDIANNESS;
++ CDR_put_octet(codec, oc_endian);
++ CDR_put_octets(codec, (gpointer)iiopversion, sizeof(iiopversion));
++ CDR_put_string(codec, info->tag.orbitinfo.unix_sock_path);
++ CDR_put_ushort(codec, info->tag.orbitinfo.ipv6_port);
++ CDR_put_ulong(codec, info->object_key._length);
++ CDR_put_octets(codec, info->object_key._buffer,
++ info->object_key._length);
++ len = codec->wptr;
++ giop_send_buffer_append_mem_indirect_a(send_buffer,
++ &len, sizeof(len));
++ giop_send_buffer_append_mem_indirect(send_buffer,
++ codec->buffer, codec->wptr);
++ } else {
++ g_warning("ORBit_marshal_profile ask to marshal type %d\n", info->profile_type);
++ }
++}
++
++void
++ORBit_marshal_object(GIOPSendBuffer *send_buffer, CORBA_Object obj)
++{
++ CORBA_unsigned_long len;
++
++
++ if(!obj) {
++ static const CORBA_unsigned_long zero = 0, one = 1;
++ /* zero-length typename */
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(send_buffer),
++ &one, sizeof(one));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer),
++ &zero, 1);
++
++ /* zero profiles */
++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(send_buffer),
++ &zero, sizeof(zero));
++ return;
++ }
++ g_return_if_fail(ORBIT_ROOT_OBJECT(obj)->refs > 0);
++
++ len = strlen(obj->object_id) + 1;
++ giop_send_buffer_append_mem_indirect_a(send_buffer, &len,
++ sizeof(len));
++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer),
++ obj->object_id, len);
++
++ len = g_slist_length(obj->profile_list);
++ giop_send_buffer_append_mem_indirect_a(GIOP_SEND_BUFFER(send_buffer),
++ &len, sizeof(len));
++
++ /* Marshal active first? */
++ g_slist_foreach(obj->profile_list, ORBit_marshal_profile, send_buffer);
++}
++
++static void ORBit_test_profile(gpointer item, gpointer data)
++{
++ ORBit_Object_info *info = (ORBit_Object_info *)item;
++ CORBA_Object obj = (CORBA_Object)data;
++
++ if(obj->active_profile != NULL)
++ return; /* we already have a good profile */
++
++ if(info->profile_type == IOP_TAG_ORBIT_SPECIFIC) {
++ if(!ORBit_parse_unixsock(obj, info->tag.orbitinfo.unix_sock_path, TRUE)) {
++ /* success */
++ obj->active_profile=info;
++ }
++ } else if(info->profile_type == IOP_TAG_INTERNET_IOP) {
++ if(!ORBit_parse_inet(obj, info->tag.iopinfo.host, info->tag.iopinfo.port, TRUE)) {
++ /* success */
++ obj->active_profile=info;
++ }
++ }
++}
++
++static void
++ORBit_object_try_existing_connections(CORBA_Object obj)
++{
++ g_slist_foreach(obj->profile_list, ORBit_test_profile, obj);
++}
++
++static void ORBit_activate_profile(gpointer item, gpointer data)
++{
++ ORBit_Object_info *info = (ORBit_Object_info *)item;
++ CORBA_Object obj = (CORBA_Object)data;
++
++ if(obj->active_profile != NULL)
++ return; /* we already have a good profile */
++
++ if(info->profile_type == IOP_TAG_ORBIT_SPECIFIC) {
++ if(!ORBit_parse_unixsock(obj, info->tag.orbitinfo.unix_sock_path, FALSE)) {
++ /* success */
++ obj->active_profile=info;
++ }
++ } else if(info->profile_type == IOP_TAG_INTERNET_IOP) {
++ if(!ORBit_parse_inet(obj, info->tag.iopinfo.host, info->tag.iopinfo.port, FALSE)) {
++ /* success */
++ obj->active_profile=info;
++ }
++ }
++}
++
++GIOPConnection *
++_ORBit_object_get_connection(CORBA_Object obj)
++{
++ g_return_val_if_fail(obj, NULL);
++
++ if (obj->connection) {
++ giop_connection_unref(obj->connection);
++ obj->connection = NULL;
++ obj->active_profile = NULL;
++ }
++
++ g_slist_foreach(obj->profile_list, ORBit_activate_profile, obj);
++
++ if(obj->active_profile == NULL || !obj->connection)
++ return NULL;
++
++ obj->connection->orb_data = obj->orb;
++
++ return obj->connection;
++}
++
++GIOPConnection *
++ORBit_object_get_forwarded_connection(CORBA_Object obj)
++{
++ g_return_val_if_fail(obj, NULL);
++
++ if (obj->connection) {
++ giop_connection_unref(obj->connection);
++ obj->connection = NULL;
++ obj->active_profile = NULL;
++ }
++
++ g_slist_foreach(obj->forward_locations, ORBit_activate_profile, obj);
++
++ if(obj->active_profile == NULL || !obj->connection)
++ return NULL;
++
++ obj->connection->orb_data = obj->orb;
++
++ return obj->connection;
++}
++
++/* This function is heavily based on the idl stubs output. Any changes there
++ will probably have to be reflected here also. */
++
++void ORBit_object_locate(CORBA_Object obj, CORBA_Environment *ev)
++{
++ GIOPConnection *cnx;
++ GIOPSendBuffer *send_buffer;
++ GIOPRecvBuffer *recv_buffer;
++ GIOP_unsigned_long request_id;
++
++ g_return_if_fail(obj!=NULL);
++ g_return_if_fail(ev!=NULL);
++
++ /* Send a LOCATE_REQUEST, wait for a LOCATE_REPLY. The reply will
++ either say "Object here", or will carry a new location. We set
++ obj->active_profile appropriately */
++
++ cnx=ORBit_object_get_connection(obj);
++ if((cnx==NULL) || (obj->active_profile==NULL)) {
++ CORBA_exception_set_system(ev, ex_CORBA_COMM_FAILURE, CORBA_COMPLETED_NO);
++ return;
++ }
++ request_id=giop_get_request_id();
++ send_buffer=giop_send_locate_request_buffer_use(cnx, request_id, &(obj->active_profile->object_key_vec));
++ if(!send_buffer) {
++ CORBA_exception_set_system(ev, ex_CORBA_COMM_FAILURE, CORBA_COMPLETED_NO);
++ return;
++ }
++
++ giop_send_buffer_write(send_buffer);
++ giop_send_buffer_unuse(send_buffer);
++
++ recv_buffer=giop_recv_locate_reply_buffer_use(request_id, TRUE);
++ if(recv_buffer==NULL || recv_buffer->message_buffer.message_header.message_type!=GIOP_LOCATEREPLY) {
++ CORBA_exception_set_system(ev, ex_CORBA_COMM_FAILURE, CORBA_COMPLETED_MAYBE);
++ if(recv_buffer)
++ giop_recv_buffer_unuse(recv_buffer);
++
++ return;
++ }
++
++ ev->_major=CORBA_NO_EXCEPTION;
++ switch(recv_buffer->message.u.locate_reply.locate_status) {
++ case GIOP_UNKNOWN_OBJECT:
++ CORBA_exception_set_system(ev, ex_CORBA_OBJECT_NOT_EXIST, CORBA_COMPLETED_NO);
++ break;
++
++ case GIOP_OBJECT_HERE:
++ /* No further processing necessary */
++ break;
++
++ case GIOP_OBJECT_FORWARD:
++ /* We've been forwarded onto somewhere else. The message body
++ contains the new IOR */
++ if(obj->forward_locations != NULL) {
++ ORBit_delete_profiles(obj->forward_locations);
++ }
++ obj->forward_locations=ORBit_demarshal_IOR(recv_buffer);
++
++ /* This will adjust obj->active_profile */
++ cnx=ORBit_object_get_forwarded_connection(obj);
++ break;
++
++ default:
++ g_message("Bad Reply in ORBit_locate_object()\n");
++ break;
++
++ }
++
++ giop_recv_buffer_unuse(recv_buffer);
++}
++
++GIOPConnection *
++ORBit_handle_location_forward(GIOPRecvBuffer *rb, CORBA_Object obj)
++{
++ GIOPConnection *retval;
++
++ if(obj->forward_locations)
++ ORBit_delete_profiles(obj->forward_locations);
++ obj->forward_locations = ORBit_demarshal_IOR(rb);
++
++ retval = ORBit_object_get_forwarded_connection(obj);
++ giop_recv_buffer_unuse(rb);
++
++ return retval;
++}
+diff -urN linux-2.4.1/net/korbit/orb/orbit_object.h linux-2.4.1-korbit/net/korbit/orb/orbit_object.h
+--- linux-2.4.1/net/korbit/orb/orbit_object.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit_object.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,114 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Phil Dawes <philipd@parallax.co.uk>
++ *
++ */
++
++/*
++ * ORBit specific CORBA_Object funcitons.
++ *
++ */
++#ifndef _ORBIT_ORBIT_OBJECT_H_
++#define _ORBIT_ORBIT_OBJECT_H_
++
++#include <IIOP/IIOP.h>
++#include "corba_object.h"
++
++extern CORBA_Object ORBit_CORBA_Object_new(CORBA_Environment *ev);
++extern void ORBit_CORBA_Object_free(CORBA_Object obj, CORBA_Environment *ev);
++
++
++typedef enum {
++ ORBIT_PSEUDO_ORB,
++ ORBIT_PSEUDO_POA,
++ ORBIT_PSEUDO_POAMANAGER,
++ ORBIT_PSEUDO_POLICY,
++ ORBIT_PSEUDO_TYPECODE,
++ ORBIT_PSEUDO_REQUEST,
++ ORBIT_PSEUDO_SERVERREQUEST,
++ ORBIT_PSEUDO_CONTEXT
++} ORBit_PseudoObject_type;
++typedef struct ORBit_PseudoObject_struct *ORBit_PseudoObject;
++
++void ORBit_pseudo_object_init(ORBit_PseudoObject obj,
++ ORBit_PseudoObject_type obj_type,
++ CORBA_Environment *ev);
++void ORBit_policy_object_init(CORBA_Policy obj,
++ CORBA_PolicyType obj_type,
++ CORBA_Environment *ev);
++
++/* Use ORBit_CORBA_Object_new() */
++void ORBit_object_reference_init(CORBA_Object obj, CORBA_Environment *ev);
++
++typedef struct {
++ CORBA_char *host;
++ CORBA_unsigned_short port;
++} TAG_INTERNET_IOP_info;
++
++typedef struct {
++ CORBA_char *unix_sock_path;
++ CORBA_unsigned_short ipv6_port;
++} TAG_ORBIT_SPECIFIC_info;
++
++typedef struct {
++ int fill_me_in;
++} TAG_MULTIPLE_COMPONENTS_info;
++
++typedef struct {
++ CORBA_octet iiop_major, iiop_minor;
++ IOP_ProfileId profile_type;
++ union {
++ TAG_INTERNET_IOP_info iopinfo;
++ TAG_ORBIT_SPECIFIC_info orbitinfo;
++ TAG_MULTIPLE_COMPONENTS_info mcinfo;
++ } tag;
++
++ /* If the object key is invariant wrt to the various profiles, then
++ this should probably go in CORBA_Object_struct
++ */
++ CORBA_sequence_octet object_key;
++ struct { CORBA_unsigned_long _length; char _buffer[1]; } *object_key_data;
++ struct iovec object_key_vec;
++} ORBit_Object_info;
++
++void ORBit_set_object_key(ORBit_Object_info *info);
++
++CORBA_Object ORBit_create_object_with_info(GSList *profiles,
++ const CORBA_char *type_id,
++ CORBA_ORB orb,
++ CORBA_Environment *ev);
++
++#define ORBit_object_get_connection(obj) \
++ ((obj)->connection && (obj)->connection->is_valid)?((obj)->connection):_ORBit_object_get_connection(obj)
++GIOPConnection *_ORBit_object_get_connection(CORBA_Object obj);
++GIOPConnection *ORBit_object_get_forwarded_connection(CORBA_Object obj);
++void ORBit_object_locate(CORBA_Object obj, CORBA_Environment *ev);
++
++void ORBit_marshal_object(GIOPSendBuffer *send_buffer, CORBA_Object obj);
++CORBA_Object ORBit_demarshal_object(GIOPRecvBuffer *recv_buffer,
++ CORBA_ORB orb);
++GSList *ORBit_demarshal_IOR(GIOPRecvBuffer *recv_buffer);
++
++extern void ORBit_delete_profiles(GSList *profile_list);
++GIOPConnection *ORBit_handle_location_forward(GIOPRecvBuffer *rb, CORBA_Object obj);
++
++#endif /* _ORBIT_ORBIT_OBJECT_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/orbit_object_type.h linux-2.4.1-korbit/net/korbit/orb/orbit_object_type.h
+--- linux-2.4.1/net/korbit/orb/orbit_object_type.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit_object_type.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,87 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ * Philip Dawes
++ * Elliot Lee <sopwith@redhat.com>
++ *
++ */
++
++#ifndef _ORBIT_ORBIT_OBJECT_TYPE_H_
++#define _ORBIT_ORBIT_OBJECT_TYPE_H_
++
++#include "orbit_object.h"
++
++
++/****** Root object **********/
++/*****************************/
++
++typedef struct ORBit_RootObject_Interface_struct ORBit_RootObject_Interface;
++struct ORBit_RootObject_Interface_struct
++{
++ void (*release)(gpointer obj, CORBA_Environment *ev);
++};
++
++
++
++#define ORBIT_ROOT_OBJECT(x) ((ORBit_RootObject)(x))
++
++
++typedef struct ORBit_RootObject_struct *ORBit_RootObject;
++struct ORBit_RootObject_struct {
++ ORBit_RootObject_Interface* interface; /* the interface */
++
++ guchar is_pseudo_object;
++ gint refs;
++};
++
++
++/* Reference counting interface */
++
++#define ORBIT_ROOT_OBJECT_REF(obj) (ORBIT_ROOT_OBJECT(obj)->refs++)
++#define ORBIT_ROOT_OBJECT_UNREF(obj) (ORBIT_ROOT_OBJECT(obj)->refs--)
++
++
++ /* Virtual function interface*/
++
++#define ORBIT_ROOT_OBJECT_release(obj,ev) \
++(ORBIT_ROOT_OBJECT(obj)->interface->release(obj,ev))
++
++
++
++extern void ORBit_RootObject_set_interface(ORBit_RootObject obj,
++ ORBit_RootObject_Interface* epv,
++ CORBA_Environment *ev);
++
++
++
++/****** Pseudo object --> RootObject ********/
++/*********************************************/
++
++#define ORBIT_PSEUDO_OBJECT(x) ((ORBit_PseudoObject)(x))
++
++struct ORBit_PseudoObject_struct {
++ struct ORBit_RootObject_struct parent;
++ ORBit_PseudoObject_type pseudo_object_type;
++};
++
++
++#endif /* !_ORBIT_CORBA_OBJECT_TYPE_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/orbit_poa.c linux-2.4.1-korbit/net/korbit/orb/orbit_poa.c
+--- linux-2.4.1/net/korbit/orb/orbit_poa.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit_poa.c Thu Feb 1 11:47:13 2001
+@@ -0,0 +1,809 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Phil Dawes <philipd@parallax.co.uk>
++ * Elliot Lee <sopwith@redhat.com>
++ *
++ */
++
++/*
++ * ORBit specific POA funcitons.
++ *
++ */
++
++#include <string.h>
++#include "orbit.h"
++#include "orbit_poa_type.h"
++#include "orbit_poa.h"
++#include "genrand.h"
++
++#define POA_KEY_LEN (sizeof(CORBA_unsigned_long) + ORBIT_RAND_KEY_LEN)
++#define OBJ_KEY_LEN (sizeof(CORBA_unsigned_long) + ORBIT_RAND_KEY_LEN)
++
++static void ORBit_POAManager_release(PortableServer_POAManager poa_mgr,
++ CORBA_Environment *ev);
++
++static void ORBit_POA_release(PortableServer_POA poa,
++ CORBA_Environment *ev);
++
++static PortableServer_Servant
++ORBit_POA_ServantManager_use_servant(PortableServer_POA poa,
++ GIOPRecvBuffer *recv_buffer,
++ PortableServer_ServantLocator_Cookie *the_cookie,
++ PortableServer_ObjectId *oid,
++ ORBit_POAObject *fake_obj_impl,
++ CORBA_Environment *ev);
++static void
++ORBit_POA_ServantManager_unuse_servant(PortableServer_Servant servant,
++ PortableServer_POA poa,
++ GIOPRecvBuffer *recv_buffer,
++ PortableServer_ServantLocator_Cookie cookie,
++ PortableServer_ObjectId *oid,
++ ORBit_POAObject *fake_obj_impl,
++ CORBA_Environment *ev);
++
++static const ORBit_RootObject_Interface CORBA_POAManager_epv =
++{
++ (void (*)(gpointer, CORBA_Environment *))ORBit_POAManager_release,
++};
++
++static const ORBit_RootObject_Interface CORBA_POA_epv =
++{
++ (void (*)(gpointer, CORBA_Environment *))ORBit_POA_release,
++};
++
++guint
++g_sequence_octet_hash(CORBA_sequence_octet *so)
++{
++ const char *s = (char*)so->_buffer;
++ const char *p, *e = ((char *)so->_buffer) + so->_length;
++ guint h=0, g;
++
++ for(p = s; p < e; p ++) {
++ h = ( h << 4 ) + *p;
++ if ( ( g = h & 0xf0000000 ) ) {
++ h = h ^ (g >> 24);
++ h = h ^ g;
++ }
++ }
++
++ return h;
++}
++
++gint
++g_sequence_octet_compare(CORBA_sequence_octet *s1, CORBA_sequence_octet *s2)
++{
++ if(s2->_length != s1->_length)
++ return FALSE;
++
++ return !memcmp(s1->_buffer, s2->_buffer, s1->_length);
++}
++
++PortableServer_POAManager
++ORBit_POAManager_new(CORBA_Environment *ev)
++{
++ PortableServer_POAManager poa_mgr;
++
++ poa_mgr = g_new0(struct PortableServer_POAManager_type, 1);
++
++ if(poa_mgr == NULL) {
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ goto error;
++ }
++
++ /* Initialise poa manager */
++
++ ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(poa_mgr),
++ ORBIT_PSEUDO_POAMANAGER, ev);
++ ORBIT_ROOT_OBJECT(poa_mgr)->refs = 0;
++ ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(poa_mgr),
++ (gpointer)&CORBA_POAManager_epv, ev);
++
++ poa_mgr->poa_collection = NULL;
++ poa_mgr->state = PortableServer_POAManager_HOLDING;
++
++ return poa_mgr;
++
++error:
++ if(poa_mgr != NULL){
++ ORBit_POAManager_release(poa_mgr, ev);
++ }
++ return NULL;
++}
++
++static void
++ORBit_POAManager_release(PortableServer_POAManager poa_mgr,
++ CORBA_Environment *ev)
++{
++
++ if(--(ORBIT_ROOT_OBJECT(poa_mgr)->refs) > 0)
++ return;
++
++ if(poa_mgr != NULL) {
++ if(poa_mgr->poa_collection != NULL) {
++ g_slist_free(poa_mgr->poa_collection);
++ poa_mgr->poa_collection = NULL;
++ }
++ g_free(poa_mgr);
++ poa_mgr = NULL;
++ }
++}
++
++static void
++ORBit_POAManager_register_poa(PortableServer_POAManager poa_mgr,
++ PortableServer_POA poa,
++ CORBA_Environment *ev)
++{
++ poa_mgr->poa_collection = g_slist_remove(poa_mgr->poa_collection, poa);
++ poa_mgr->poa_collection =
++ g_slist_append(poa_mgr->poa_collection, poa);
++}
++
++static void
++ORBit_POAManager_unregister_poa(PortableServer_POAManager poa_mgr,
++ PortableServer_POA poa,
++ CORBA_Environment *ev)
++{
++ poa_mgr->poa_collection = g_slist_remove(poa_mgr->poa_collection, poa);
++}
++
++static void
++ORBit_POA_set_policy(PortableServer_POA poa,
++ CORBA_Policy policy,
++ CORBA_Environment *ev)
++{
++ switch(policy->policy_type) {
++ case PortableServer_THREAD_POLICY_ID:
++ poa->thread = ((PortableServer_ThreadPolicy)policy)->value;
++ break;
++ case PortableServer_LIFESPAN_POLICY_ID:
++ poa->lifespan = ((PortableServer_LifespanPolicy)policy)->value;
++ break;
++ case PortableServer_ID_UNIQUENESS_POLICY_ID:
++ poa->id_uniqueness = ((PortableServer_IdUniquenessPolicy)policy)->value;
++ break;
++ case PortableServer_ID_ASSIGNMENT_POLICY_ID:
++ poa->id_assignment = ((PortableServer_IdAssignmentPolicy)policy)->value;
++ break;
++ case PortableServer_IMPLICIT_ACTIVATION_POLICY_ID:
++ poa->implicit_activation = ((PortableServer_ImplicitActivationPolicy)policy)->value;
++ break;
++ case PortableServer_SERVANT_RETENTION_POLICY_ID:
++ poa->servant_retention = ((PortableServer_ServantRetentionPolicy)policy)->value;
++ break;
++ case PortableServer_REQUEST_PROCESSING_POLICY_ID:
++ poa->request_processing = ((PortableServer_ServantRetentionPolicy)policy)->value;
++ break;
++ default:
++ g_warning("Unknown policy type, cannot set it on this POA");
++ }
++}
++
++
++static void
++ORBit_POA_check_policy_conflicts(PortableServer_POA poa,
++ CORBA_Environment *ev)
++{
++
++ /* Check for those policy combinations that aren't allowed */
++ if ((poa->servant_retention == PortableServer_NON_RETAIN &&
++ poa->request_processing == PortableServer_USE_ACTIVE_OBJECT_MAP_ONLY) ||
++
++ (poa->request_processing == PortableServer_USE_DEFAULT_SERVANT &&
++ poa->id_uniqueness == PortableServer_UNIQUE_ID) ||
++
++ (poa->implicit_activation == PortableServer_IMPLICIT_ACTIVATION &&
++ (poa->id_assignment == PortableServer_USER_ID ||
++ poa->servant_retention == PortableServer_NON_RETAIN))
++ )
++ {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_InvalidPolicy,
++ NULL);
++ }
++}
++
++
++static void
++ORBit_POA_set_policylist(PortableServer_POA poa,
++ CORBA_PolicyList *policies,
++ CORBA_Environment *ev)
++{
++ CORBA_unsigned_long i;
++
++ for(i = 0; i < policies->_length; i++) {
++ if(ev->_major != CORBA_NO_EXCEPTION)
++ break;
++ ORBit_POA_set_policy(poa, policies->_buffer[i], ev);
++ }
++}
++
++PortableServer_POA
++ORBit_POA_new(CORBA_ORB orb,
++ CORBA_char *adapter_name,
++ PortableServer_POAManager the_POAManager,
++ CORBA_PolicyList *policies,
++ CORBA_Environment *ev)
++{
++ PortableServer_POA poa;
++
++ /* Create the object */
++ poa = (PortableServer_POA) g_new0(struct PortableServer_POA_type, 1);
++ if(poa == NULL) {
++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
++ goto error;
++ }
++
++ ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(poa), ORBIT_PSEUDO_POA, ev);
++
++ ORBIT_ROOT_OBJECT(poa)->refs = 0;
++ ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(poa),
++ (gpointer)&CORBA_POA_epv, ev);
++
++ if(ev->_major != CORBA_NO_EXCEPTION) goto error;
++
++ /* If no POAManager was specified, create one */
++ if(the_POAManager == NULL) {
++ the_POAManager = ORBit_POAManager_new(ev);
++ }
++
++ /* Register this poa with the poa manager */
++ if(the_POAManager != NULL)
++ ORBit_POAManager_register_poa(the_POAManager,poa,ev);
++ if(ev->_major != CORBA_NO_EXCEPTION) goto error;
++
++ /* Wire up the poa_manager */
++ poa->the_POAManager = the_POAManager;
++
++ /* Initialise the child poas table */
++ poa->child_POAs = NULL; /* initialise the slist */
++
++ poa->held_requests = NULL;
++
++ poa->poaID = orb->poas->len;
++ g_ptr_array_set_size(orb->poas, orb->poas->len + 1);
++ g_ptr_array_index(orb->poas, poa->poaID) = poa;
++
++ poa->orb = orb;
++
++ g_return_val_if_fail(ev->_major == CORBA_NO_EXCEPTION, NULL);
++
++ /* Need to initialise poa policies etc.. here */
++ poa->thread = PortableServer_ORB_CTRL_MODEL;
++ poa->lifespan = PortableServer_TRANSIENT;
++ poa->id_uniqueness = PortableServer_UNIQUE_ID;
++ poa->id_assignment = PortableServer_SYSTEM_ID;
++ poa->servant_retention = PortableServer_RETAIN;
++ poa->request_processing = PortableServer_USE_ACTIVE_OBJECT_MAP_ONLY;
++ poa->implicit_activation = PortableServer_NO_IMPLICIT_ACTIVATION;
++ if (policies) {
++ ORBit_POA_set_policylist(poa, policies, ev);
++ ORBit_POA_check_policy_conflicts(poa, ev);
++ if(ev->_major != CORBA_NO_EXCEPTION) goto error;
++ }
++
++ /* copy the name */
++ poa->the_name = CORBA_string_dup(adapter_name);
++
++ poa->active_object_map = g_hash_table_new((GHashFunc)g_sequence_octet_hash,
++ (GCompareFunc)g_sequence_octet_compare);
++ poa->objnum_to_obj = g_ptr_array_new();
++ g_ptr_array_set_size(poa->objnum_to_obj, 1);
++ g_ptr_array_index(poa->objnum_to_obj, 0) = NULL;
++
++ orbit_genrand(poa->rand_data, ORBIT_RAND_KEY_LEN);
++
++ return poa;
++
++error:
++ if(poa && poa->the_name){
++ CORBA_free(poa->the_name);
++ }
++
++ if(poa != NULL){
++ ORBit_POA_release(poa, NULL);
++ }
++ return NULL;
++}
++
++static void
++ORBit_POA_release(PortableServer_POA poa,
++ CORBA_Environment *ev)
++{
++ ORBIT_ROOT_OBJECT_UNREF(poa);
++
++ if(ORBIT_ROOT_OBJECT(poa)->refs <= 0) {
++ CORBA_free(poa->the_name);
++
++ g_slist_foreach(poa->child_POAs, (GFunc)CORBA_Object_release,
++ ev);
++
++ if(poa->parent_poa)
++ ORBit_POA_remove_child(poa->parent_poa, poa, ev);
++
++ ORBit_POAManager_unregister_poa(poa->the_POAManager,
++ poa, ev);
++
++ g_ptr_array_index(poa->orb->poas, poa->poaID) = NULL;
++
++ g_free(poa);
++ }
++}
++
++void
++ORBit_POA_add_child(PortableServer_POA poa,
++ PortableServer_POA child_poa,
++ CORBA_Environment *ev)
++
++{
++ g_return_if_fail(poa != NULL);
++ g_return_if_fail(child_poa != NULL);
++
++ poa->child_POAs = g_slist_prepend(poa->child_POAs, child_poa);
++}
++
++void
++ORBit_POA_remove_child(PortableServer_POA poa,
++ PortableServer_POA child_poa,
++ CORBA_Environment *ev)
++{
++ g_return_if_fail(poa != NULL);
++ g_return_if_fail(child_poa != NULL);
++
++ poa->child_POAs = g_slist_remove(poa->child_POAs, child_poa);
++}
++
++extern ORBit_request_validate ORBIT_request_validator;
++
++gboolean
++ORBit_POA_handle_request(GIOPRecvBuffer *recv_buffer,
++ PortableServer_POA poa)
++{
++ PortableServer_ServantBase *servant;
++ PortableServer_ServantLocator_Cookie cookie;
++ ORBit_POAObject *obj_impl = NULL, tmp_obj_impl;
++ ORBitSkeleton skel;
++ gpointer imp = NULL;
++ CORBA_Environment ev;
++ GIOPSendBuffer *send_buffer;
++ guchar *opname;
++ PortableServer_ObjectId *oid = NULL;
++
++ CORBA_exception_init(&ev);
++
++ switch(poa->the_POAManager->state) {
++ case PortableServer_POAManager_HOLDING:
++ poa->held_requests = g_slist_prepend(poa->held_requests,
++ recv_buffer);
++ return FALSE;
++ break;
++ case PortableServer_POAManager_DISCARDING:
++ send_buffer = giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(recv_buffer)->connection,
++ NULL,
++ recv_buffer->message.u.request.request_id,
++ CORBA_SYSTEM_EXCEPTION);
++ CORBA_exception_set_system(&ev,
++ ex_CORBA_TRANSIENT,
++ CORBA_COMPLETED_NO);
++ ORBit_send_system_exception(send_buffer, &ev);
++ giop_send_buffer_write(send_buffer);
++ giop_recv_buffer_unuse(recv_buffer);
++ giop_send_buffer_unuse(send_buffer);
++ CORBA_exception_free(&ev);
++ return TRUE;
++ break;
++ case PortableServer_POAManager_INACTIVE:
++ send_buffer = giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(recv_buffer)->connection,
++ NULL,
++ recv_buffer->message.u.request.request_id,
++ CORBA_SYSTEM_EXCEPTION);
++ CORBA_exception_set_system(&ev,
++ ex_CORBA_OBJ_ADAPTER,
++ CORBA_COMPLETED_NO);
++ ORBit_send_system_exception(send_buffer, &ev);
++ giop_send_buffer_write(send_buffer);
++ giop_recv_buffer_unuse(recv_buffer);
++ giop_send_buffer_unuse(send_buffer);
++ CORBA_exception_free(&ev);
++ return TRUE;
++ break;
++ case PortableServer_POAManager_ACTIVE:
++ default:
++ break;
++ }
++
++ servant = NULL;
++
++ if(recv_buffer->message.u.request.object_key._length
++ < (POA_KEY_LEN + sizeof(CORBA_unsigned_long))) {
++ CORBA_exception_set_system(&ev,
++ ex_CORBA_OBJECT_NOT_EXIST,
++ CORBA_COMPLETED_NO);
++ goto errout;
++ }
++
++ obj_impl = ORBit_POA_find_oid_for_object_key(poa, &(recv_buffer->message.u.request.object_key), &oid);
++
++ if(poa->servant_retention == PortableServer_RETAIN
++ && obj_impl) {
++ servant = obj_impl->servant;
++ oid = obj_impl->object_id;
++ }
++
++ if(!servant) {
++ switch(poa->request_processing) {
++ case PortableServer_USE_SERVANT_MANAGER:
++ servant = ORBit_POA_ServantManager_use_servant(poa,
++ recv_buffer,
++ &cookie,
++ oid,
++ &tmp_obj_impl,
++ &ev);
++ break;
++ case PortableServer_USE_DEFAULT_SERVANT:
++ servant = poa->default_servant;
++ if(servant == NULL) {
++ CORBA_exception_set_system(&ev,
++ ex_CORBA_OBJ_ADAPTER,
++ CORBA_COMPLETED_NO);
++ goto errout;
++ }
++ break;
++ default:
++ break;
++ }
++ }
++
++ if(!poa || !servant || !servant->_private) {
++ CORBA_exception_set_system(&ev,
++ ex_CORBA_OBJECT_NOT_EXIST,
++ CORBA_COMPLETED_NO);
++ goto errout;
++ }
++
++ opname = recv_buffer->message.u.request.operation;
++
++ skel = ORBIT_OBJECT_KEY(servant->_private)->class_info->relay_call(servant, recv_buffer, &imp);
++
++ if(!skel) {
++ if (opname[0] == '_' && strcmp(opname + 1, "is_a") == 0) {
++ skel = (gpointer)&ORBit_impl_CORBA_Object_is_a;
++ }
++ else {
++ CORBA_exception_set_system(&ev, ex_CORBA_BAD_OPERATION,
++ CORBA_COMPLETED_NO);
++ goto errout;
++ }
++ }
++ else if (!imp) {
++ CORBA_exception_set_system(&ev, ex_CORBA_NO_IMPLEMENT,
++ CORBA_COMPLETED_NO);
++ goto errout;
++ }
++
++ /* If it got through the random keys, and nobody else had the opportunity to say otherwise, it must be auth'd */
++
++ if(!ORBIT_request_validator)
++ GIOP_MESSAGE_BUFFER(recv_buffer)->connection->is_auth = TRUE;
++
++ skel(servant, recv_buffer, &ev, imp);
++
++ if(poa->request_processing == PortableServer_USE_SERVANT_MANAGER) {
++ ORBit_POA_ServantManager_unuse_servant(servant,
++ poa,
++ recv_buffer,
++ cookie, oid,
++ &tmp_obj_impl,
++ &ev);
++ }
++
++ if(!obj_impl)
++ CORBA_free(oid);
++
++ CORBA_exception_free(&ev);
++
++ return TRUE;
++
++ errout:
++ if(ev._major == CORBA_SYSTEM_EXCEPTION) {
++ GIOPSendBuffer *reply_buf;
++
++ reply_buf =
++ giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(recv_buffer)->connection,
++ NULL,
++ recv_buffer->message.u.request.request_id,
++ CORBA_SYSTEM_EXCEPTION);
++
++ ORBit_send_system_exception(reply_buf, &ev);
++
++ giop_send_buffer_write(reply_buf);
++ giop_send_buffer_unuse(reply_buf);
++ } else /* User exceptions are handled in the skels! */
++ g_assert(ev._major == CORBA_NO_EXCEPTION);
++
++ if(!obj_impl)
++ CORBA_free(oid);
++
++ CORBA_exception_free(&ev);
++
++ return TRUE;
++}
++
++PortableServer_POA
++ORBit_POA_find_POA_for_object_key(PortableServer_POA root_poa,
++ CORBA_sequence_octet *key)
++{
++ CORBA_unsigned_long pid;
++
++ if(key->_length < (sizeof(CORBA_unsigned_long) + ORBIT_RAND_KEY_LEN))
++ return NULL;
++
++ pid = *((CORBA_unsigned_long *)key->_buffer);
++
++ if(pid < root_poa->orb->poas->len) {
++ PortableServer_POA poa;
++ poa = g_ptr_array_index(root_poa->orb->poas, pid);
++ if(!poa)
++ return NULL;
++ if(memcmp(poa->rand_data, key->_buffer + sizeof(CORBA_unsigned_long), ORBIT_RAND_KEY_LEN))
++ return NULL;
++ return poa;
++ } else
++ return NULL;
++}
++
++void
++ORBit_POA_find_object_key_for_oid(PortableServer_POA poa,
++ ORBit_POAObject *obj,
++ PortableServer_ObjectId *oid,
++ CORBA_sequence_octet *retval)
++{
++ CORBA_long *vptr;
++
++ g_return_if_fail(poa && (obj || oid));
++ g_return_if_fail(retval);
++
++ if(oid)
++ g_assert(!oid->_buffer[oid->_length - 1]);
++
++ if(obj)
++ retval->_length = POA_KEY_LEN + OBJ_KEY_LEN;
++ else
++ retval->_length = POA_KEY_LEN + sizeof(CORBA_long) + oid->_length;
++ retval->_buffer = CORBA_octet_allocbuf(retval->_length);
++ CORBA_sequence_set_release(retval, CORBA_TRUE);
++
++ vptr = (CORBA_long *)retval->_buffer;
++ *vptr = poa->poaID;
++ memcpy(retval->_buffer + sizeof(CORBA_unsigned_long), poa->rand_data, ORBIT_RAND_KEY_LEN);
++
++ vptr = (CORBA_long *)(retval->_buffer + POA_KEY_LEN);
++ if(obj) {
++ *vptr = obj->objnum;
++ memcpy(retval->_buffer + POA_KEY_LEN + sizeof(CORBA_unsigned_long), obj->rand_data, ORBIT_RAND_KEY_LEN);
++ } else {
++ *vptr = -((CORBA_long)oid->_length);
++ memcpy(retval->_buffer + POA_KEY_LEN + sizeof(CORBA_unsigned_long), oid->_buffer, oid->_length);
++ }
++}
++
++ORBit_POAObject *
++ORBit_POA_find_oid_for_object_key(PortableServer_POA poa,
++ CORBA_sequence_octet *object_key,
++ PortableServer_ObjectId **oid)
++{
++ CORBA_long onum;
++ guchar *nptr;
++ ORBit_POAObject *objinfo;
++
++ *oid = NULL;
++ nptr = object_key->_buffer + POA_KEY_LEN;
++
++ if(object_key->_length < (POA_KEY_LEN + sizeof(CORBA_long))) {
++ return NULL;
++ }
++
++ onum = *((CORBA_long *)nptr);
++
++ if(onum < 0) {
++ /* onum will be the -strlen(ObjectId) */
++ if(object_key->_length < (POA_KEY_LEN + sizeof(CORBA_long) - onum))
++ return NULL;
++
++ *oid = (PortableServer_ObjectId *)CORBA_sequence_octet__alloc();
++ (*oid)->_length = -onum;
++ (*oid)->_buffer = CORBA_octet_allocbuf((*oid)->_length);
++ memcpy((*oid)->_buffer, object_key->_buffer + POA_KEY_LEN + sizeof(CORBA_long), (*oid)->_length);
++
++ return NULL;
++ }
++
++ if(onum >= poa->objnum_to_obj->len)
++ return NULL;
++
++ objinfo = g_ptr_array_index(poa->objnum_to_obj, onum);
++
++ if(GPOINTER_TO_UINT(objinfo) <= poa->objnum_to_obj->len)
++ return NULL;
++
++ if(object_key->_length < (POA_KEY_LEN + OBJ_KEY_LEN))
++ return NULL;
++
++ if(memcmp(object_key->_buffer + POA_KEY_LEN + sizeof(CORBA_long), objinfo->rand_data, ORBIT_RAND_KEY_LEN))
++ return NULL;
++
++ return objinfo;
++}
++
++DEFINE_LOCK(id_assignment_counter);
++static int id_assignment_counter = 0;
++
++PortableServer_ObjectId *
++ORBit_POA_allocate_oid(PortableServer_POA poa,
++ const char *basis)
++{
++ PortableServer_ObjectId *new_objid;
++ char buf[512];
++ int len;
++
++ new_objid = (PortableServer_ObjectId *)CORBA_sequence_octet__alloc();
++
++ GET_LOCK(id_assignment_counter);
++ g_snprintf(buf, sizeof(buf), "%s%d", basis?basis:"Object",
++ id_assignment_counter);
++ id_assignment_counter++;
++ RELEASE_LOCK(id_assignment_counter);
++
++ len = strlen(buf)+1;
++ new_objid->_buffer = CORBA_octet_allocbuf(len);
++ new_objid->_length = len;
++ new_objid->_maximum = len;
++ new_objid->_release = CORBA_TRUE;
++
++ strcpy((CORBA_char *)new_objid->_buffer, buf);
++
++ return new_objid;
++}
++
++static PortableServer_Servant
++ORBit_POA_ServantManager_use_servant(PortableServer_POA poa,
++ GIOPRecvBuffer *recv_buffer,
++ PortableServer_ServantLocator_Cookie *the_cookie,
++ PortableServer_ObjectId *oid,
++ ORBit_POAObject *fake_obj_impl,
++ CORBA_Environment *ev)
++{
++ if(poa->servant_retention == PortableServer_RETAIN) {
++ POA_PortableServer_ServantActivator *sm;
++ POA_PortableServer_ServantActivator__epv *epv;
++
++ sm = (POA_PortableServer_ServantActivator *)poa->servant_manager;
++ epv = sm->vepv->PortableServer_ServantActivator_epv;
++ return epv->incarnate(sm, oid, poa, ev);
++ } else {
++ POA_PortableServer_ServantLocator *sm;
++ POA_PortableServer_ServantLocator__epv *epv;
++ PortableServer_ServantBase *retval;
++
++ sm = (POA_PortableServer_ServantLocator *)poa->servant_manager;
++ epv = sm->vepv->PortableServer_ServantLocator_epv;
++ retval = epv->preinvoke(sm, oid,
++ poa, recv_buffer->message.u.request.operation,
++ the_cookie,
++ ev);
++
++ ((ORBit_ObjectKey *)retval->_private)->object = fake_obj_impl;
++ fake_obj_impl->object_id = oid;
++ fake_obj_impl->poa = poa;
++ fake_obj_impl->orb = poa->orb;
++ fake_obj_impl->objnum = -1;
++#ifdef NOT_BACKWARDS_COMPAT_0_4
++ fake_obj_impl->use_count = NULL;
++ fake_obj_impl->death_callback = NULL;
++#endif
++
++ return retval;
++ }
++}
++
++static void
++ORBit_POA_ServantManager_unuse_servant(PortableServer_Servant servant,
++ PortableServer_POA poa,
++ GIOPRecvBuffer *recv_buffer,
++ PortableServer_ServantLocator_Cookie cookie,
++ PortableServer_ObjectId *oid,
++ ORBit_POAObject *fake_obj_impl,
++ CORBA_Environment *ev)
++{
++ POA_PortableServer_ServantLocator *sm;
++ POA_PortableServer_ServantLocator__epv *epv;
++
++ if(poa->servant_retention != PortableServer_NON_RETAIN)
++ return;
++
++ sm = (POA_PortableServer_ServantLocator *)poa->servant_manager;
++ epv = sm->vepv->PortableServer_ServantLocator_epv;
++
++ ((ORBit_ObjectKey *)((PortableServer_ServantBase *)servant)->_private)->object = NULL;
++ epv->postinvoke(sm, oid,
++ poa, recv_buffer->message.u.request.operation,
++ cookie, servant, ev);
++
++}
++
++typedef struct {
++ PortableServer_POA poa;
++ CORBA_Environment *ev;
++} EtherealizeInfo;
++
++void
++ORBit_POA_etherealize_object(PortableServer_ObjectId *oid,
++ ORBit_POAObject *obj_impl,
++ EtherealizeInfo *ei)
++{
++ POA_PortableServer_ServantActivator__epv *epv;
++ POA_PortableServer_ServantActivator *sm;
++
++ g_assert(ei->poa->servant_manager);
++
++ g_hash_table_remove(ei->poa->active_object_map,
++ obj_impl->object_id);
++
++ sm = (POA_PortableServer_ServantActivator *)ei->poa->servant_manager;
++ epv = sm->vepv->PortableServer_ServantActivator_epv;
++ epv->etherealize(sm, obj_impl->object_id, ei->poa,
++ obj_impl->servant,
++ CORBA_TRUE, CORBA_FALSE, ei->ev);
++}
++
++void
++ORBit_POA_etherealize_objects(PortableServer_POA poa,
++ CORBA_Environment *ev)
++{
++ EtherealizeInfo ei;
++
++ ei.poa = poa;
++ ei.ev = ev;
++
++ if(poa->servant_retention == PortableServer_RETAIN
++ && poa->request_processing == PortableServer_USE_SERVANT_MANAGER) {
++
++ g_hash_table_foreach(poa->active_object_map,
++ (GHFunc)ORBit_POA_etherealize_object,
++ &ei);
++ }
++}
++
++#ifdef NOT_BACKWARDS_COMPAT_0_4
++void ORBit_servant_set_deathwatch(PortableServer_ServantBase *servant,
++ int *use_count,
++ GFunc death_func,
++ gpointer user_data)
++{
++ ORBit_POAObject *pobj;
++
++ pobj = ORBIT_OBJECT_KEY(servant->_private)->object;
++
++ pobj->use_count = use_count;
++ pobj->death_callback = death_func;
++ pobj->user_data = user_data;
++}
++#endif
+diff -urN linux-2.4.1/net/korbit/orb/orbit_poa.h linux-2.4.1-korbit/net/korbit/orb/orbit_poa.h
+--- linux-2.4.1/net/korbit/orb/orbit_poa.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit_poa.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,89 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Phil Dawes <philipd@parallax.co.uk>
++ *
++ */
++
++/*
++ * ORBit specific POA funcitons.
++ *
++ */
++
++#ifndef _ORBIT_ORBIT_POA_H_
++#define _ORBIT_ORBIT_POA_H_
++
++#include "orbit_types.h"
++#include "orbit_poa_type.h"
++
++/*
++ * Creates a new POAManager
++ */
++
++extern PortableServer_POAManager ORBit_POAManager_new(CORBA_Environment *ev);
++
++extern void ORBit_POAManager_free(PortableServer_POAManager poa_mgr,
++ CORBA_Environment *ev);
++
++extern PortableServer_POA ORBit_POA_new(CORBA_ORB orb,
++ CORBA_char *adapter_name,
++ PortableServer_POAManager the_POAManager,
++ CORBA_PolicyList *policies,
++ CORBA_Environment *ev);
++
++extern void ORBit_POA_free(PortableServer_POA poa, CORBA_Environment *ev);
++
++extern void ORBit_POA_add_child(PortableServer_POA poa,
++ PortableServer_POA child_poa,
++ CORBA_Environment *ev);
++void ORBit_POA_remove_child(PortableServer_POA poa,
++ PortableServer_POA child_poa,
++ CORBA_Environment *ev);
++
++gboolean ORBit_POA_handle_request(GIOPRecvBuffer *recv_buffer,
++ PortableServer_POA poa);
++PortableServer_POA
++ORBit_POA_find_POA_for_object_key(PortableServer_POA root_poa,
++ CORBA_sequence_octet *key);
++void
++ORBit_POA_find_object_key_for_oid(PortableServer_POA poa,
++ ORBit_POAObject *obj,
++ PortableServer_ObjectId *oid,
++ CORBA_sequence_octet *retval);
++ORBit_POAObject *
++ORBit_POA_find_oid_for_object_key(PortableServer_POA poa,
++ CORBA_sequence_octet *object_key,
++ PortableServer_ObjectId **oid);
++
++PortableServer_ObjectId *ORBit_POA_allocate_oid(PortableServer_POA poa,
++ const char *basis);
++
++void ORBit_POA_etherealize_objects(PortableServer_POA poa, CORBA_Environment *ev);
++
++#ifdef NOT_BACKWARDS_COMPAT_0_4
++/* Bad hack for shared libraries */
++void ORBit_servant_set_deathwatch(PortableServer_ServantBase *servant,
++ int *use_count,
++ GFunc death_func,
++ gpointer user_data);
++#endif
++
++#endif /* !_ORBIT_ORBIT_POA_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/orbit_poa_type.h linux-2.4.1-korbit/net/korbit/orb/orbit_poa_type.h
+--- linux-2.4.1/net/korbit/orb/orbit_poa_type.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit_poa_type.h Thu Feb 1 11:47:13 2001
+@@ -0,0 +1,112 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Phil Dawes <philipd@parallax.co.uk>
++ *
++ */
++
++/*
++ * ORBit specific POA funcitons.
++ *
++ */
++
++#ifndef _ORBIT_ORBIT_POA_TYPE_H_
++#define _ORBIT_ORBIT_POA_TYPE_H_
++
++typedef void (*ORBitSkeleton)(PortableServer_ServantBase *_ORBIT_servant,
++ gpointer _ORBIT_recv_buffer,
++ CORBA_Environment *ev,
++ gpointer implementation);
++typedef ORBitSkeleton (*ORBit_impl_finder)(PortableServer_ServantBase *servant,
++ gpointer _ORBIT_recv_buffer,
++ gpointer *implementation);
++typedef void (*ORBit_local_objref_init)(CORBA_Object obj,
++ PortableServer_ServantBase *servant);
++typedef struct {
++ ORBit_impl_finder relay_call;
++ const gchar *class_name;
++ ORBit_local_objref_init init_local_objref;
++} PortableServer_ClassInfo;
++
++#define ORBIT_RAND_KEY_LEN 8
++
++typedef struct {
++ PortableServer_ObjectId *object_id;
++ PortableServer_Servant servant;
++ PortableServer_POA poa;
++ CORBA_ORB orb;
++ CORBA_unsigned_long objnum;
++
++ /* Stuff for doing shared libraries nicely */
++ guchar rand_data[ORBIT_RAND_KEY_LEN];
++
++#ifdef NOT_BACKWARDS_COMPAT_0_4
++ int *use_count;
++ GFunc death_callback;
++ gpointer user_data;
++#endif
++} ORBit_POAObject;
++
++typedef struct {
++ PortableServer_ClassInfo *class_info;
++ ORBit_POAObject *object;
++} ORBit_ObjectKey;
++
++#define ORBIT_OBJECT_KEY(x) ((ORBit_ObjectKey *)(x))
++
++struct PortableServer_POA_type {
++ struct ORBit_PseudoObject_struct parent;
++
++ PortableServer_POA parent_poa;
++ CORBA_ORB orb;
++ CORBA_unsigned_long poaID;
++
++ GHashTable *active_object_map;
++ GPtrArray *objnum_to_obj; /* maps objnums to ORBit_POAObject's */
++ CORBA_long first_free_id;
++
++ /* Requests received while in a HOLDING state */
++ GSList *held_requests;
++
++ /* this'll be a hash table when I can be arsed to look up
++ how to implement efficient hash tables - Phil.*/
++ GSList *child_POAs;
++
++ CORBA_char *the_name;
++ PortableServer_POAManager the_POAManager;
++
++ PortableServer_AdapterActivator the_activator;
++
++ PortableServer_ServantManager servant_manager;
++ PortableServer_Servant default_servant;
++
++ PortableServer_ThreadPolicyValue thread;
++ PortableServer_LifespanPolicyValue lifespan;
++ PortableServer_IdUniquenessPolicyValue id_uniqueness;
++ PortableServer_IdAssignmentPolicyValue id_assignment;
++ PortableServer_ImplicitActivationPolicyValue implicit_activation;
++ PortableServer_ServantRetentionPolicyValue servant_retention;
++ PortableServer_RequestProcessingPolicyValue request_processing;
++
++ guchar rand_data[ORBIT_RAND_KEY_LEN];
++};
++
++#endif /* !_ORBIT_ORBIT_POA_TYPE_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/orbit_typecode.c linux-2.4.1-korbit/net/korbit/orb/orbit_typecode.c
+--- linux-2.4.1/net/korbit/orb/orbit_typecode.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit_typecode.c Thu Feb 1 11:47:14 2001
+@@ -0,0 +1,593 @@
++#include "orbit.h"
++#include "orbit_typecode.h"
++#include "cdr.h"
++#include "corba_typecode_type.h"
++#include <IIOP/giop-msg-buffer.h>
++#include "../IIOP/iiop-endianP.h"
++
++#if 0
++#define CORBA_Object_release(x, y) ({ g_message(__FILE__ ":%d Releasing object %#x from %d", __LINE__, \
++x, ORBIT_ROOT_OBJECT(x)->refs); CORBA_Object_release(x, y); })
++#define CORBA_Object_duplicate(x, y) ({ g_message(__FILE__ ":%d Duping object %#x from %d", __LINE__, \
++x, ORBIT_ROOT_OBJECT(x)->refs); CORBA_Object_duplicate(x, y); })
++#endif
++
++typedef struct{
++ CORBA_TypeCode tc;
++ guint index;
++}TCRecursionNode;
++
++typedef struct{
++ GSList* prior_tcs; /* Could be a hash table by typecode */
++ guint current_idx; /* The "top-level" index of the start of the current codec */
++}TCEncodeContext;
++
++typedef struct{
++ GSList* prior_tcs; /* Could be a hash table by offset */
++ guint current_idx;
++}TCDecodeContext;
++
++
++
++static void tc_enc(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec(CORBA_TypeCode* t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_objref(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_objref(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_sequence(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_sequence(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_string(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_string(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_struct(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_struct(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_union(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_union(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_enum(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_enum(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_alias(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_alias(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_except(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_except(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_array(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_array(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_fixed(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_fixed(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++static void tc_enc_tk_wstring(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx);
++static void tc_dec_tk_wstring(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx);
++
++
++
++typedef void
++(*CORBA_TypeCodeEncoder)(CORBA_TypeCode t,
++ CDR_Codec* c,
++ TCEncodeContext* ctx);
++
++typedef void
++(*CORBA_TypeCodeDecoder)(CORBA_TypeCode t,
++ CDR_Codec* c,
++ TCDecodeContext* ctx);
++
++
++typedef enum{
++ TK_EMPTY,
++ TK_SIMPLE,
++ TK_COMPLEX
++} TkType;
++
++typedef struct{
++ TkType type;
++ CORBA_TypeCodeEncoder encoder;
++ CORBA_TypeCodeDecoder decoder;
++} TkInfo;
++
++static const TkInfo tk_info[CORBA_tk_last]={
++ {TK_EMPTY, NULL, NULL}, /* tk_null */
++ {TK_EMPTY, NULL, NULL}, /* tk_void */
++ {TK_EMPTY, NULL, NULL}, /* tk_short */
++ {TK_EMPTY, NULL, NULL}, /* tk_long */
++ {TK_EMPTY, NULL, NULL}, /* tk_ushort */
++ {TK_EMPTY, NULL, NULL}, /* tk_ulong */
++ {TK_EMPTY, NULL, NULL}, /* tk_float */
++ {TK_EMPTY, NULL, NULL}, /* tk_double */
++ {TK_EMPTY, NULL, NULL}, /* tk_boolean */
++ {TK_EMPTY, NULL, NULL}, /* tk_char */
++ {TK_EMPTY, NULL, NULL}, /* tk_octet */
++ {TK_EMPTY, NULL, NULL}, /* tk_any */
++ {TK_EMPTY, NULL, NULL}, /* tk_TypeCode */
++ {TK_EMPTY, NULL, NULL}, /* tk_Principal */
++ {TK_COMPLEX, tc_enc_tk_objref, tc_dec_tk_objref}, /* tk_objref */
++ {TK_COMPLEX, tc_enc_tk_struct, tc_dec_tk_struct}, /* tk_struct */
++ {TK_COMPLEX, tc_enc_tk_union, tc_dec_tk_union}, /* tk_union */
++ {TK_COMPLEX, tc_enc_tk_enum, tc_dec_tk_enum}, /* tk_enum */
++ {TK_SIMPLE, tc_enc_tk_string, tc_dec_tk_string}, /* tk_string */
++ {TK_COMPLEX, tc_enc_tk_sequence, tc_dec_tk_sequence}, /* tk_sequence */
++ {TK_COMPLEX, tc_enc_tk_array, tc_dec_tk_array}, /* tk_array */
++ {TK_COMPLEX, tc_enc_tk_alias, tc_dec_tk_alias}, /* tk_alias */
++ {TK_COMPLEX, tc_enc_tk_except, tc_dec_tk_except}, /* tk_except */
++ {TK_EMPTY, NULL, NULL}, /* tk_longlong */
++ {TK_EMPTY, NULL, NULL}, /* tk_ulonglong */
++ {TK_EMPTY, NULL, NULL}, /* tk_longdouble */
++ {TK_EMPTY, NULL, NULL}, /* tk_wchar */
++ {TK_SIMPLE, tc_enc_tk_wstring, tc_dec_tk_wstring}, /* tk_wstring */
++ {TK_SIMPLE, tc_enc_tk_fixed, tc_dec_tk_fixed} /* tk_fixed */
++};
++
++void ORBit_encode_CORBA_TypeCode(CORBA_TypeCode t, GIOPSendBuffer* buf)
++{
++ CDR_Codec codec_d;
++ CDR_Codec* codec = &codec_d;
++ TCEncodeContext ctx;
++ GSList* l;
++ CORBA_octet codecbuf[2048];
++
++ CDR_codec_init_static(codec);
++
++ codec->wptr = 0;
++ codec->buffer = codecbuf;
++ codec->release_buffer = FALSE;
++ codec->buf_len = 2048;
++ codec->data_endian=FLAG_ENDIANNESS;
++
++ ctx.current_idx=0;
++ ctx.prior_tcs=NULL;
++ tc_enc(t, codec, &ctx);
++ for(l=ctx.prior_tcs;l;l=l->next)
++ g_free(l->data);
++ g_slist_free(ctx.prior_tcs);
++ giop_send_buffer_append_mem_indirect(buf,
++ codec->buffer,
++ codec->wptr);
++}
++
++void ORBit_decode_CORBA_TypeCode(CORBA_TypeCode* t, GIOPRecvBuffer* buf)
++{
++ CDR_Codec codec_d;
++ CDR_Codec* codec = &codec_d;
++ TCDecodeContext ctx;
++ GSList* l;
++
++ CDR_codec_init_static(codec);
++ codec->buffer=buf->cur;
++ codec->release_buffer=CORBA_FALSE;
++ codec->readonly=CORBA_TRUE;
++ codec->buf_len = /* hope this is correct */
++ ((guchar *)buf->message_body) +
++ GIOP_MESSAGE_BUFFER(buf)->message_header.message_size
++ - ((guchar *)buf->cur);
++
++ codec->data_endian=GIOP_MESSAGE_BUFFER(buf)->message_header.flags & 1;
++
++ ctx.current_idx=0;
++ ctx.prior_tcs=NULL;
++ tc_dec(t, codec, &ctx);
++ for(l=ctx.prior_tcs;l;l=l->next)
++ g_free(l->data);
++ g_slist_free(ctx.prior_tcs);
++ buf->cur = ((guchar *)buf->cur) + codec->rptr;
++}
++
++
++/* Encode a typecode to a codec, possibly recursively */
++
++static void tc_enc(CORBA_TypeCode tc,
++ CDR_Codec* codec,
++ TCEncodeContext* ctx)
++{
++ TCRecursionNode* node;
++ const TkInfo* info;
++ GSList* l;
++ CORBA_octet codecbuf[2048];
++ CDR_Codec encaps_d;
++ CDR_Codec* encaps = &encaps_d;
++
++ g_assert(CLAMP(0, tc->kind, CORBA_tk_last) == tc->kind);
++
++ for(l=ctx->prior_tcs;l;l=l->next){
++ TCRecursionNode* node=l->data;
++ /* CORBA_CORBA_TypeCode_equal might save space, but is slow.. */
++ if(node->tc==tc){
++ CDR_put_ulong(codec, CORBA_tk_recursive);
++ CDR_put_long(codec,
++ node->index
++ -ctx->current_idx
++ -codec->wptr);
++ return;
++ }
++ }
++
++ /* All right, this isn't a previously met type. So record it. */
++ /* NOTE: put kind before recording index so alignment is dealt with! */
++ CDR_put_ulong(codec, tc->kind);
++
++ node=g_new(TCRecursionNode, 1);
++ node->tc=tc;
++ node->index=ctx->current_idx+codec->wptr - 4; /* -4 for kind */
++ ctx->prior_tcs=g_slist_prepend(ctx->prior_tcs, node);
++
++ info=&tk_info[tc->kind];
++ switch(info->type){
++ guint tmp_index;
++ case TK_EMPTY:
++ break;
++ case TK_COMPLEX:
++ tmp_index=ctx->current_idx;
++ ctx->current_idx+=codec->wptr+4; /* +4 for the length */
++ CDR_codec_init_static(encaps);
++ encaps->wptr = 0;
++ encaps->buffer = codecbuf;
++ encaps->release_buffer = FALSE;
++ encaps->buf_len = 2048;
++ encaps->data_endian=FLAG_ENDIANNESS;
++ CDR_put_octet(encaps, FLAG_ENDIANNESS);
++ (info->encoder)(tc, encaps, ctx);
++ CDR_put_ulong(codec, encaps->wptr);
++ /* Now this is a time hog */
++ CDR_put_octets(codec, encaps->buffer, encaps->wptr);
++ ctx->current_idx=tmp_index;
++ break;
++ case TK_SIMPLE:
++ (info->encoder)(tc, codec, ctx);
++ }
++}
++
++static void
++ORBit_TypeCode_release(gpointer obj, CORBA_Environment *ev)
++{
++ /* we will initialize the TC_ constants with a negative refcount */
++ if(ORBIT_ROOT_OBJECT(obj)->refs >= 0) {
++ ORBIT_ROOT_OBJECT_UNREF(obj);
++
++ if(ORBIT_ROOT_OBJECT(obj)->refs <= 0) {
++ CORBA_TypeCode tc = obj;
++ int i;
++
++ g_free(tc->name);
++ g_free(tc->repo_id);
++
++ for(i = 0; i < tc->sub_parts; i++) {
++ if(tc->subnames)
++ g_free(tc->subnames[i]);
++
++ if(tc->subtypes)
++ CORBA_Object_release((CORBA_Object)tc->subtypes[i], ev);
++
++ if(tc->sublabels)
++ CORBA_any__free(&tc->sublabels[i], NULL, TRUE);
++ }
++
++ g_free(tc->subnames);
++ g_free(tc->subtypes);
++ g_free(tc->sublabels);
++
++ if(tc->discriminator)
++ CORBA_Object_release((CORBA_Object)tc->discriminator, ev);
++
++ g_free(obj);
++ }
++
++ }
++}
++
++const ORBit_RootObject_Interface ORBit_TypeCode_epv = {
++ &ORBit_TypeCode_release
++};
++
++static void tc_dec(CORBA_TypeCode* t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ CORBA_TCKind kind;
++ CORBA_TypeCode tc;
++ const TkInfo* info;
++ TCRecursionNode* node;
++ CDR_Codec encaps_d;
++ CDR_Codec* encaps = &encaps_d;
++
++ CDR_get_ulong(c, &kind);
++
++ g_assert(CLAMP(0, kind, CORBA_tk_last) == kind);
++
++ if(kind==CORBA_tk_recursive){
++ CORBA_long offset;
++ GSList* l;
++ CDR_get_ulong(c, &offset);
++ for(l=ctx->prior_tcs;l;l=l->next){
++ node=l->data;
++ /* NOTE: below, -4 is b/c we already read offset */
++ if(node->index==ctx->current_idx+c->rptr+offset-4){
++ *t=node->tc;
++ return;
++ }
++ }
++ ORBit_Trace(TraceMod_ORB, TraceLevel_Error,
++ "tc_dec: Invalid CORBA_TypeCode recursion offset "
++ "in input buffer\n");
++ g_assert_not_reached();
++ }
++
++ ORBit_Trace(TraceMod_TC, TraceLevel_Debug, "codec->host_endian: %d, codec->data_endian: %d\n", c->host_endian, c->data_endian);
++ ORBit_Trace(TraceMod_TC, TraceLevel_Debug, "kind: %d, CORBA_tk_last: %d\n", kind, CORBA_tk_last);
++ g_assert(kind<CORBA_tk_last);
++
++ node=g_new(TCRecursionNode, 1);
++ node->index=ctx->current_idx+c->rptr-4; /* -4 for the TCKind */
++ info=&tk_info[kind];
++
++ tc=g_new0(struct CORBA_TypeCode_struct, 1);
++
++ /* Passing in NULL for CORBA_Environment is patently dangerous. */
++ ORBit_pseudo_object_init((ORBit_PseudoObject)tc,
++ ORBIT_PSEUDO_TYPECODE, NULL);
++ ORBit_RootObject_set_interface((ORBit_RootObject)tc,
++ (ORBit_RootObject_Interface *)&ORBit_TypeCode_epv,
++ NULL);
++
++ tc->kind=kind;
++ switch(info->type){
++ guint tmp_index;
++ CORBA_octet o;
++
++ case TK_EMPTY:
++ break;
++
++ case TK_COMPLEX:
++ tmp_index=ctx->current_idx;
++ CDR_codec_init_static(encaps);
++ CDR_get_ulong(c, &encaps->buf_len);
++ ctx->current_idx+=c->rptr;
++ encaps->buffer=&c->buffer[c->rptr];
++ encaps->release_buffer=CORBA_FALSE;
++ CDR_get_octet(encaps, &o);
++ encaps->data_endian=o;
++ (info->decoder)(tc, encaps, ctx);
++ c->rptr += encaps->buf_len;
++ ctx->current_idx=tmp_index;
++ break;
++ case TK_SIMPLE:
++ (info->decoder)(tc, c, ctx);
++ break;
++ }
++ node->tc=tc;
++ ctx->prior_tcs=g_slist_prepend(ctx->prior_tcs, node);
++ *t=tc;
++}
++
++
++
++static void tc_enc_tk_objref(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ CDR_put_string(c, t->repo_id);
++ CDR_put_string(c, t->name);
++}
++
++static void tc_dec_tk_objref(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ CDR_get_string(c, &t->repo_id);
++ CDR_get_string(c, &t->name);
++}
++
++static void tc_enc_tk_sequence(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ tc_enc(*t->subtypes, c, ctx);
++ CDR_put_ulong(c, t->length);
++}
++
++static void tc_dec_tk_sequence(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ t->subtypes=g_new(CORBA_TypeCode, 1);
++ tc_dec(&t->subtypes[0], c, ctx);
++ CORBA_Object_duplicate((CORBA_Object)t->subtypes[0], NULL);
++ CDR_get_ulong(c, &t->length);
++}
++
++static void tc_enc_tk_string(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ CDR_put_ulong(c, t->length);
++}
++
++static void tc_dec_tk_string(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ CDR_get_ulong(c, &t->length);
++}
++
++static void tc_enc_tk_struct(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ CORBA_unsigned_long i;
++ CDR_put_string(c, t->repo_id);
++ CDR_put_string(c, t->name);
++ CDR_put_ulong(c, t->sub_parts);
++ for(i=0;i<t->sub_parts;i++){
++ CDR_put_string(c, t->subnames[i]);
++ tc_enc(t->subtypes[i], c, ctx);
++ }
++}
++
++static void tc_dec_tk_struct(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ CORBA_unsigned_long i;
++ CDR_get_string(c, &t->repo_id);
++ CDR_get_string(c, &t->name);
++ CDR_get_ulong(c, &t->sub_parts);
++ t->subnames=g_new(gchar*, t->sub_parts);
++ t->subtypes=g_new(CORBA_TypeCode, t->sub_parts);
++ for(i=0;i<t->sub_parts;i++){
++ CDR_get_string(c, &t->subnames[i]);
++ tc_dec(&t->subtypes[i], c, ctx);
++ CORBA_Object_duplicate((CORBA_Object)t->subtypes[i], NULL);
++ }
++}
++
++#define UNION_MEMBERS(dir) \
++ MEMBER_LOOPER_##dir(ulong, long, long); \
++ case CORBA_tk_enum: /* fall through */ \
++ MEMBER_LOOPER_##dir(ulong, unsigned_long, ulong); \
++ MEMBER_LOOPER_##dir(octet, boolean, boolean); \
++ MEMBER_LOOPER_##dir(octet, char, char); \
++ MEMBER_LOOPER_##dir(ushort, short, short); \
++ MEMBER_LOOPER_##dir(ushort, unsigned_short, ushort); \
++ MEMBER_LOOPER_##dir(ulong_long, long_long, longlong); \
++ MEMBER_LOOPER_##dir(ulong_long, unsigned_long_long, ulonglong); \
++ /* MEMBER_LOOPER_##dir(wchar, wchar, wchar); */
++
++
++static void tc_enc_tk_union(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ CORBA_unsigned_long i;
++ CDR_put_string(c, t->repo_id);
++ CDR_put_string(c, t->name);
++ tc_enc(t->discriminator, c, ctx);
++ CDR_put_long(c, t->default_index);
++ CDR_put_ulong(c, t->sub_parts);
++ i=t->sub_parts;
++ /* Thank goodness the discriminator types are rather limited,
++ we can do the marshalling inline.. */
++#define MEMBER_LOOPER_ENC(putname, typename, tkname) \
++ case CORBA_tk_##tkname: \
++ for(i=0;i<t->sub_parts;i++){ \
++ CDR_put_##putname(c, *(CORBA_##typename*) \
++ (t->sublabels[i]._value)); \
++ CDR_put_string(c, t->subnames[i]); \
++ tc_enc(t->subtypes[i], c, ctx); \
++ } \
++ break
++
++ switch(t->discriminator->kind){
++ UNION_MEMBERS(ENC);
++ default:
++ ORBit_Trace(TraceMod_ORB, TraceLevel_Error,
++ "tc_enc_tk_union: Illegal union discriminator "
++ "type %s\n", t->discriminator->name);
++ }
++}
++
++static void tc_dec_tk_union(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ CORBA_unsigned_long i;
++ CDR_get_string(c, &t->repo_id);
++ CDR_get_string(c, &t->name);
++ tc_dec(&t->discriminator, c, ctx);
++ CORBA_Object_duplicate((CORBA_Object)t->discriminator, NULL);
++ CDR_get_ulong(c, &t->default_index);
++ CDR_get_ulong(c, &t->sub_parts);
++
++ t->sublabels=g_new(CORBA_any, t->sub_parts);
++ t->subnames=g_new(gchar*, t->sub_parts);
++ t->subtypes=g_new(CORBA_TypeCode, t->sub_parts);
++
++#define MEMBER_LOOPER_DEC(getname, typename, tkname) \
++ case CORBA_tk_##tkname: \
++ for(i=0;i<t->sub_parts;i++){ \
++ t->sublabels[i]._type = \
++ CORBA_Object_duplicate((CORBA_Object)t->discriminator, NULL); \
++ t->sublabels[i]._value = g_new(CORBA_##typename,1); \
++ t->sublabels[i]._release = CORBA_TRUE; \
++ CDR_get_##getname(c, t->sublabels[i]._value); \
++ CDR_get_string(c, &t->subnames[i]); \
++ tc_dec(&t->subtypes[i], c, ctx); \
++ CORBA_Object_duplicate((CORBA_Object)t->subtypes[i], NULL); \
++ } \
++ break
++
++ switch(t->discriminator->kind){
++ UNION_MEMBERS(DEC);
++ default:
++ /* XXX: what is correct error handling */
++ g_assert(!"Not yet implemented.");
++ }
++}
++
++static void tc_enc_tk_enum(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ CORBA_unsigned_long i;
++ CDR_put_string(c, t->repo_id);
++ CDR_put_string(c, t->name);
++ CDR_put_ulong(c, t->sub_parts);
++ for(i=0;i<t->sub_parts;i++)
++ CDR_put_string(c, t->subnames[i]);
++}
++
++static void tc_dec_tk_enum(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ CORBA_unsigned_long i;
++ CDR_get_string(c, &t->repo_id);
++ CDR_get_string(c, &t->name);
++ CDR_get_ulong(c, &t->sub_parts);
++ t->subnames=g_new(gchar*, t->sub_parts);
++ for(i=0;i<t->sub_parts;i++)
++ CDR_get_string(c, &t->subnames[i]);
++}
++
++static void tc_enc_tk_alias(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ CDR_put_string(c, t->repo_id);
++ CDR_put_string(c, t->name);
++ tc_enc(*t->subtypes, c, ctx);
++}
++
++static void tc_dec_tk_alias(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ CDR_get_string(c, &t->repo_id);
++ CDR_get_string(c, &t->name);
++ t->subtypes=g_new(CORBA_TypeCode, 1);
++ tc_dec(t->subtypes, c, ctx);
++ CORBA_Object_duplicate((CORBA_Object)t->subtypes[0], NULL);
++}
++
++
++static void tc_enc_tk_except(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ gulong i;
++ CDR_put_string(c, t->repo_id);
++ CDR_put_string(c, t->name);
++ CDR_put_ulong(c, t->sub_parts);
++ for(i=0;i<t->length;i++){
++ CDR_put_string(c, t->subnames[i]);
++ tc_enc(t->subtypes[i], c, ctx);
++ }
++}
++
++static void tc_dec_tk_except(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ gulong i;
++ CDR_get_string(c, &t->repo_id);
++ CDR_get_string(c, &t->name);
++ CDR_get_ulong(c, &t->sub_parts);
++ t->subtypes=g_new(CORBA_TypeCode, t->sub_parts);
++ t->subnames=g_new(gchar*, t->sub_parts);
++ for(i=0;i<t->length;i++){
++ CDR_get_string(c, &t->subnames[i]);
++ tc_dec(&t->subtypes[i], c, ctx);
++ CORBA_Object_duplicate((CORBA_Object)t->subtypes[i], NULL);
++ }
++}
++
++static void tc_enc_tk_array(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ tc_enc(*t->subtypes, c, ctx);
++ CDR_put_ulong(c, t->length);
++}
++
++static void tc_dec_tk_array(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ t->subtypes=g_new(CORBA_TypeCode, 1);
++ tc_dec(t->subtypes, c, ctx);
++ CORBA_Object_duplicate((CORBA_Object)t->subtypes[0], NULL);
++ CDR_get_ulong(c, &t->length);
++}
++
++static void tc_enc_tk_wstring(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ g_assert(!"Not yet implemented.");
++}
++
++static void tc_dec_tk_wstring(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ g_assert(!"Not yet implemented.");
++}
++
++static void tc_enc_tk_fixed(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx)
++{
++ g_assert(!"Not yet implemented.");
++}
++
++static void tc_dec_tk_fixed(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx)
++{
++ g_assert(!"Not yet implemented.");
++}
+diff -urN linux-2.4.1/net/korbit/orb/orbit_typecode.h linux-2.4.1-korbit/net/korbit/orb/orbit_typecode.h
+--- linux-2.4.1/net/korbit/orb/orbit_typecode.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit_typecode.h Thu Feb 1 16:21:53 2001
+@@ -0,0 +1,10 @@
++#ifndef _ORBIT_ORBIT_TYPECODE_H_
++#define _ORBIT_ORBIT_TYPECODE_H_
++
++#include "orbit_types.h"
++
++extern const ORBit_RootObject_Interface ORBit_TypeCode_epv;
++void ORBit_encode_CORBA_TypeCode(CORBA_TypeCode tc, GIOPSendBuffer* buf);
++void ORBit_decode_CORBA_TypeCode(CORBA_TypeCode* tc, GIOPRecvBuffer* buf);
++
++#endif
+diff -urN linux-2.4.1/net/korbit/orb/orbit_types.h linux-2.4.1-korbit/net/korbit/orb/orbit_types.h
+--- linux-2.4.1/net/korbit/orb/orbit_types.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/orbit_types.h Thu Feb 1 16:20:50 2001
+@@ -0,0 +1,176 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_TYPES_H_
++#define _ORBIT_TYPES_H_
++
++#include <stddef.h> /* for wchar_t */
++#include <sys/types.h> /* for sysdep types */
++#include <netinet/in.h> /* for sockaddr_in */
++#include <sys/uio.h> /* for struct iovec */
++
++#include <ORBitutil/basic_types.h>
++
++#define CORBA_TRUE 1
++#define CORBA_FALSE 0
++
++typedef CORBA_char *CORBA_ORBid;
++
++typedef CORBA_unsigned_long CORBA_ServiceOption;
++typedef CORBA_unsigned_long CORBA_ServiceDetailType;
++
++#include "corba_orb.h"
++
++/*
++ * CORBA_RepositoryId and CORBA_Identifier are defined in the Interface
++ * Repository, but are needed in other interfaces in the ORB itself.
++ */
++#if !defined(_CORBA_Identifier_defined)
++#define _CORBA_Identifier_defined 1
++typedef CORBA_char *CORBA_Identifier;
++#define CORBA_Identifier__free CORBA_string__free
++#endif
++
++#if !defined(_CORBA_RepositoryId_defined)
++#define _CORBA_RepositoryId_defined 1
++typedef CORBA_char *CORBA_RepositoryId;
++#define CORBA_RepositoryId__free CORBA_string__free
++#endif
++
++#include "corba_any.h"
++
++typedef struct CORBA_ServiceDetail_type CORBA_ServiceDetail;
++typedef struct CORBA_Request_type *CORBA_Request;
++typedef struct CORBA_ServerRequest_type *CORBA_ServerRequest;
++typedef struct CORBA_DynFixed_type *CORBA_DynFixed;
++typedef struct CORBA_Current_type *CORBA_Current;
++typedef void CORBA_Status;
++typedef CORBA_unsigned_long CORBA_enum;
++typedef CORBA_unsigned_long CORBA_Flags;
++
++typedef struct CORBA_NVList_type {
++ CORBA_Flags flags;
++ GArray *list;
++} CORBA_NVList;
++
++#include "corba_context.h"
++
++#include "corba_portableserver.h"
++
++#include "corba_env.h"
++
++#include "corba_sequences_type.h"
++
++#include "corba_basic_sequences_type.h"
++
++#include "corba_object.h"
++
++#include "orbit_object_type.h"
++
++#include "corba_object_type.h"
++
++#include "corba_orb_type.h"
++
++#include "corba_typecode.h"
++#include "corba_typecode_type.h"
++#include "corba_any_type.h"
++#include "corba_any_proto.h"
++
++#if !defined(TC_IMPL_TC_CORBA_Identifier_0)
++#define TC_IMPL_TC_CORBA_Identifier_0 '/'
++#define TC_CORBA_Identifier ((CORBA_TypeCode)&TC_CORBA_Identifier_struct)
++extern const struct CORBA_TypeCode_struct TC_CORBA_Identifier_struct;
++#endif
++
++#if !defined(TC_IMPL_TC_CORBA_RepositoryId_0)
++#define TC_IMPL_TC_CORBA_RepositoryId_0 '/'
++extern const struct CORBA_TypeCode_struct TC_CORBA_RepositoryId_struct;
++#define TC_CORBA_RepositoryId ((CORBA_TypeCode)&TC_CORBA_RepositoryId_struct)
++#endif
++
++/* 19.14 */
++
++/* XXX */
++typedef struct CORBA_fixed_d_s {
++ CORBA_unsigned_short _digits;
++ CORBA_short _scale;
++ signed char _sign;
++ signed char _value[1];
++} CORBA_fixed_d_s;
++
++#include "corba_env_type.h"
++
++
++typedef struct CORBA_WrongTransaction {
++ int dummy;
++} CORBA_WrongTransaction;
++
++#define CORBA_ARG_IN (1<<0)
++#define CORBA_ARG_OUT (1<<1)
++#define CORBA_ARG_INOUT (1<<2)
++#define CORBA_CTX_RESTRICT_SCOPE (1<<3)
++#define CORBA_CTX_DELETE_DESCENDENTS (1<<4)
++#define CORBA_OUT_LIST_MEMORY (1<<5)
++#define CORBA_IN_COPY_VALUE (1<<6)
++#define CORBA_DEPENDENT_LIST (1<<7)
++#define CORBA_INV_NO_RESPONSE (1<<8)
++#define CORBA_INV_TERM_ON_ERROR (1<<9)
++#define CORBA_RESP_NO_WAIT (1<<10)
++
++typedef struct CORBA_NamedValue {
++ CORBA_Identifier name; /* argument name */
++ CORBA_any argument; /* argument */
++ CORBA_long len; /* length/count of argument value */
++ CORBA_Flags arg_modes; /* argument mode flags */
++} CORBA_NamedValue;
++
++typedef CORBA_char *CORBA_FieldName;
++
++typedef struct CORBA_NameValuePair {
++ CORBA_FieldName id;
++ CORBA_any value;
++} CORBA_NameValuePair;
++
++struct CORBA_Current_type {
++ int fill_me_in;
++};
++
++#include "corba_portableserver_type.h"
++
++typedef CORBA_unsigned_short CORBA_ServiceType;
++
++#define CORBA_Security (1)
++
++struct CORBA_ServiceDetail_type {
++ CORBA_ServiceDetailType service_detail_type;
++ CORBA_sequence_octet service_detail;
++};
++
++typedef struct CORBA_ServiceInformation_struct {
++ CORBA_sequence_ServiceOption service_options;
++ CORBA_sequence_ServiceDetail service_details;
++} CORBA_ServiceInformation;
++
++#endif /* !_ORBIT_TYPES_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/poa.c linux-2.4.1-korbit/net/korbit/orb/poa.c
+--- linux-2.4.1/net/korbit/orb/poa.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/poa.c Thu Feb 1 11:47:14 2001
+@@ -0,0 +1,1387 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter, and Red Hat Software
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ * Elliot Lee <sopwith@redhat.com>
++ *
++ */
++
++#include <string.h>
++#include <stdio.h>
++#include <assert.h>
++
++#include "orbit.h"
++#include "orbit_poa.h"
++#include "genrand.h"
++
++PortableServer_ThreadPolicyValue
++PortableServer_ThreadPolicy__get_value(PortableServer_ThreadPolicy obj, CORBA_Environment *ev)
++{
++ if(!obj) {
++ ev->_major = 2 ;
++ goto error_exit;
++ }
++ ev->_major = CORBA_NO_EXCEPTION;
++
++ return obj->value;
++
++error_exit:
++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO);
++ return 0;
++}
++
++PortableServer_LifespanPolicyValue
++PortableServer_LifespanPolicy__get_value(PortableServer_LifespanPolicy obj, CORBA_Environment *ev)
++{
++ if(!obj) {
++ ev->_major = 2 ;
++ goto error_exit;
++ }
++
++ ev->_major = CORBA_NO_EXCEPTION;
++ return obj->value;
++
++error_exit:
++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO);
++ return 0;
++}
++
++PortableServer_IdUniquenessPolicyValue
++PortableServer_IdUniquenessPolicy__get_value(PortableServer_IdUniquenessPolicy obj, CORBA_Environment *ev)
++{
++ if(!obj) {
++ ev->_major = 2 ;
++ goto error_exit;
++ }
++
++ ev->_major = CORBA_NO_EXCEPTION;
++ return obj->value;
++
++error_exit:
++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO);
++ return 0;
++}
++
++PortableServer_IdAssignmentPolicyValue
++PortableServer_IdAssignmentPolicy__get_value(PortableServer_IdAssignmentPolicy obj, CORBA_Environment *ev)
++{
++ if(!obj) {
++ ev->_major = 2 ;
++ goto error_exit;
++ }
++
++ ev->_major = CORBA_NO_EXCEPTION;
++ return obj->value;
++
++error_exit:
++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO);
++ return 0;
++}
++
++PortableServer_ImplicitActivationPolicyValue
++PortableServer_ImplicitActivationPolicy__get_value(PortableServer_ImplicitActivationPolicy obj, CORBA_Environment *ev)
++{
++ if(!obj) {
++ ev->_major = 2 ;
++ goto error_exit;
++ }
++
++ ev->_major = CORBA_NO_EXCEPTION;
++ return obj->value;
++
++error_exit:
++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO);
++ return 0;
++}
++
++PortableServer_ServantRetentionPolicyValue
++PortableServer_ServantRetentionPolicy__get_value(PortableServer_ServantRetentionPolicy obj, CORBA_Environment *ev)
++{
++ if(!obj) {
++ ev->_major = 2 ;
++ goto error_exit;
++ }
++
++ ev->_major = CORBA_NO_EXCEPTION;
++ return obj->value;
++
++error_exit:
++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO);
++ return 0;
++}
++
++PortableServer_RequestProcessingPolicyValue
++PortableServer_RequestProcessingPolicy__get_value(PortableServer_RequestProcessingPolicy obj, CORBA_Environment *ev)
++{
++ if(!obj) {
++ ev->_major = 2 ;
++ goto error_exit;
++ }
++
++ ev->_major = CORBA_NO_EXCEPTION;
++ return obj->value;
++
++error_exit:
++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO);
++ return 0;
++}
++
++/* make emacs happy; */
++
++PortableServer_POAManager_State
++PortableServer_POAManager_get_state(PortableServer_POAManager obj,
++ CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return -1;
++ }
++
++ ev->_major = CORBA_NO_EXCEPTION;
++ return obj->state;
++}
++
++/**** PortableServer_POAManager_activate
++ Inputs: 'obj' - a POAManager to activate
++ Outputs: '*ev' - result of the activate operation
++
++ Side effect: Clears the 'held_requests' lists for all POA's
++ associated with the 'obj' POAManager.
++
++ Description: Sets the POAManager state to 'ACTIVE', then
++ goes through all the POA's associated with this
++ POAManager, and makes them re-process their
++ 'held_requests'
++ */
++void
++PortableServer_POAManager_activate(PortableServer_POAManager obj,
++ CORBA_Environment *ev)
++{
++ GSList *todo;
++ GSList *curitem;
++ PortableServer_POA curpoa;
++
++ if(!obj) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ if(obj->state == PortableServer_POAManager_INACTIVE) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POAManager_AdapterInactive,
++ NULL);
++ return;
++ }
++
++ obj->state = PortableServer_POAManager_ACTIVE;
++
++ for(curitem = obj->poa_collection; curitem;
++ curitem = g_slist_next(curitem)) {
++ curpoa = (PortableServer_POA)curitem->data;
++
++ todo = curpoa->held_requests;
++ curpoa->held_requests = NULL;
++
++ g_slist_foreach(todo, (GFunc)ORBit_POA_handle_request,
++ curpoa);
++ g_slist_foreach(todo, (GFunc)giop_recv_buffer_unuse,
++ NULL);
++
++ g_slist_free(todo);
++ }
++ ev->_major = CORBA_NO_EXCEPTION;
++}
++
++void
++PortableServer_POAManager_hold_requests(PortableServer_POAManager obj,
++ CORBA_boolean wait_for_completion,
++ CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ if(obj->state == PortableServer_POAManager_INACTIVE) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POAManager_AdapterInactive,
++ NULL);
++ return;
++ }
++
++ obj->state = PortableServer_POAManager_HOLDING;
++ if(!wait_for_completion)
++ g_warning("hold_requests not finished - don't know how to kill outstanding request fulfillments");
++
++ ev->_major = CORBA_NO_EXCEPTION;
++}
++
++void
++PortableServer_POAManager_discard_requests(PortableServer_POAManager obj,
++ CORBA_boolean wait_for_completion,
++ CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ if(obj->state == PortableServer_POAManager_INACTIVE) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POAManager_AdapterInactive,
++ NULL);
++ return;
++ }
++
++ obj->state = PortableServer_POAManager_DISCARDING;
++ if(!wait_for_completion)
++ g_warning("discard_requests not finished - don't know how to kill outstanding request fulfillments");
++ ev->_major = CORBA_NO_EXCEPTION;
++}
++
++void
++PortableServer_POAManager_deactivate(PortableServer_POAManager obj,
++ CORBA_boolean etherealize_objects,
++ CORBA_boolean wait_for_completion,
++ CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ if(obj->state == PortableServer_POAManager_INACTIVE) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POAManager_AdapterInactive,
++ NULL);
++ return;
++ }
++
++ obj->state = PortableServer_POAManager_INACTIVE;
++
++ if(etherealize_objects)
++ g_slist_foreach(obj->poa_collection, (GFunc)ORBit_POA_etherealize_objects, ev);
++ ev->_major = CORBA_NO_EXCEPTION;
++}
++
++
++CORBA_boolean
++PortableServer_AdapterActivator_unknown_adapter(PortableServer_AdapterActivator obj,
++ PortableServer_POA parent,
++ CORBA_char *name,
++ CORBA_Environment *ev)
++{
++ g_assert(!"Not yet implemented");
++ return(CORBA_FALSE);
++}
++
++
++/**** PortableServer_ServantActivator_incarnate
++ */
++PortableServer_Servant
++
++PortableServer_ServantActivator_incarnate
++(PortableServer_ServantActivator obj,
++ PortableServer_ObjectId *oid,
++ PortableServer_POA adapter,
++ CORBA_Environment *ev)
++{
++ g_assert(!"Not yet implemented");
++ return(NULL);
++}
++
++void
++PortableServer_ServantActivator_etherealize
++(PortableServer_ServantActivator obj,
++ PortableServer_ObjectId *oid, PortableServer_POA adapter,
++ PortableServer_Servant serv,
++ CORBA_boolean cleanup_in_progress,
++ CORBA_boolean remaining_activations,
++ CORBA_Environment *ev)
++{
++ g_assert(!"Not yet implemented");
++ return;
++}
++
++PortableServer_POA
++PortableServer_POA_create_POA
++ (PortableServer_POA poa,
++ CORBA_char *adapter_name,
++ PortableServer_POAManager a_POAManager,
++ CORBA_PolicyList* policies,
++ CORBA_Environment *ev)
++{
++ PortableServer_POA new_poa = NULL;
++ PortableServer_POA check_poa = NULL;
++
++ /* Check for a child POA by the same name in parent */
++ check_poa = PortableServer_POA_find_POA(poa,adapter_name,
++ FALSE, ev);
++ CORBA_exception_free (ev);
++
++ if (!check_poa) {
++ new_poa = ORBit_POA_new(poa->orb,
++ adapter_name, a_POAManager, policies, ev);
++ } else {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_AdapterAlreadyExists,
++ NULL);
++ new_poa = NULL;
++ }
++
++ if(ev->_major == CORBA_NO_EXCEPTION) {
++ new_poa->parent_poa = poa;
++ ORBit_POA_add_child(poa, new_poa, ev);
++ }
++
++ return new_poa;
++}
++
++/**** PortableServer_POA_find_POA
++ Inputs: 'obj' - a POA
++ 'activate_it' - whether to activate unknown POA's
++
++ Outputs: 'child_poa'
++
++ Description: Finds (and optionally activates) a child POA of 'obj'
++ with the specified names.
++
++ TODO: Activate non-existent adapters if asked.
++
++ */
++PortableServer_POA
++PortableServer_POA_find_POA(PortableServer_POA obj,
++ CORBA_char *adapter_name,
++ CORBA_boolean activate_it,
++ CORBA_Environment *ev)
++{
++ GSList *curitem;
++ PortableServer_POA child_poa;
++
++ for(curitem = obj->child_POAs; curitem;
++ curitem = g_slist_next(curitem)) {
++ child_poa = (PortableServer_POA)curitem->data;
++ if(!strcmp(child_poa->the_name, adapter_name)) {
++ ev->_major = CORBA_NO_EXCEPTION;
++ return child_poa;
++ }
++ }
++
++ if(activate_it)
++ g_warning("Don't yet know how to activate POA named \"%s\"",
++ adapter_name);
++
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_AdapterNonExistent,
++ NULL);
++
++ return NULL;
++}
++
++/**** PortableServer_POA_destroy
++ Inputs: 'obj' - the POA to be destroyed
++ 'etherealize_objects' - flag indicating whether any servant
++ manager should be asked to etherealize
++ objects in the active object map
++ 'wait_for_completion' - flag indicating whether to wait for
++ requests currently being handled
++ */
++void
++PortableServer_POA_destroy(PortableServer_POA obj,
++ CORBA_boolean etherealize_objects,
++ CORBA_boolean wait_for_completion,
++ CORBA_Environment *ev)
++{
++ if(etherealize_objects || !wait_for_completion)
++ g_warning("PortableServer_POA_destroy not yet fully implemented; ignoring flags");
++
++ if(ORBIT_ROOT_OBJECT(obj)->refs > 1)
++ g_warning("POA has multiple refs [%d]",
++ ORBIT_ROOT_OBJECT(obj)->refs);
++
++ CORBA_Object_release((CORBA_Object)obj, ev);
++ ev->_major = CORBA_NO_EXCEPTION;
++}
++
++PortableServer_ThreadPolicy PortableServer_POA_create_thread_policy(PortableServer_POA obj, PortableServer_ThreadPolicyValue value, CORBA_Environment *ev)
++{
++ PortableServer_ThreadPolicy retval;
++
++ retval = g_new(struct PortableServer_ThreadPolicy_type, 1);
++ ORBit_policy_object_init((CORBA_Policy)retval,
++ PortableServer_THREAD_POLICY_ID, ev);
++
++ retval->value = value;
++
++ return (PortableServer_ThreadPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev);
++}
++
++PortableServer_LifespanPolicy PortableServer_POA_create_lifespan_policy(PortableServer_POA obj, PortableServer_LifespanPolicyValue value, CORBA_Environment *ev)
++{
++ PortableServer_LifespanPolicy retval;
++
++ retval = g_new(struct PortableServer_LifespanPolicy_type, 1);
++ ORBit_policy_object_init((CORBA_Policy)retval,
++ PortableServer_LIFESPAN_POLICY_ID, ev);
++
++ retval->value = value;
++
++ return (PortableServer_LifespanPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev);
++}
++
++PortableServer_IdUniquenessPolicy PortableServer_POA_create_id_uniqueness_policy(PortableServer_POA obj, PortableServer_IdUniquenessPolicyValue value, CORBA_Environment *ev)
++{
++ PortableServer_IdUniquenessPolicy retval;
++
++ retval = g_new(struct PortableServer_IdUniquenessPolicy_type, 1);
++ ORBit_policy_object_init((CORBA_Policy)retval,
++ PortableServer_ID_UNIQUENESS_POLICY_ID,
++ ev);
++
++ retval->value = value;
++
++ return (PortableServer_IdUniquenessPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev);
++}
++
++PortableServer_IdAssignmentPolicy PortableServer_POA_create_id_assignment_policy(PortableServer_POA obj, PortableServer_IdAssignmentPolicyValue value, CORBA_Environment *ev)
++{
++ PortableServer_IdAssignmentPolicy retval;
++
++ retval = g_new(struct PortableServer_IdAssignmentPolicy_type, 1);
++ ORBit_policy_object_init((CORBA_Policy)retval,
++ PortableServer_ID_ASSIGNMENT_POLICY_ID, ev);
++
++ retval->value = value;
++
++ return (PortableServer_IdAssignmentPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev);
++}
++
++PortableServer_ImplicitActivationPolicy PortableServer_POA_create_implicit_activation_policy(PortableServer_POA obj, PortableServer_ImplicitActivationPolicyValue value, CORBA_Environment *ev)
++{
++ PortableServer_ImplicitActivationPolicy retval;
++
++ retval = g_new(struct PortableServer_ImplicitActivationPolicy_type, 1);
++ ORBit_policy_object_init((CORBA_Policy)retval,
++ PortableServer_IMPLICIT_ACTIVATION_POLICY_ID, ev);
++
++ retval->value = value;
++
++ return (PortableServer_ImplicitActivationPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev);
++}
++
++PortableServer_ServantRetentionPolicy PortableServer_POA_create_servant_retention_policy(PortableServer_POA obj, PortableServer_ServantRetentionPolicyValue value, CORBA_Environment *ev)
++{
++ PortableServer_ServantRetentionPolicy retval;
++
++ retval = g_new(struct PortableServer_ServantRetentionPolicy_type, 1);
++ ORBit_policy_object_init((CORBA_Policy)retval,
++ PortableServer_SERVANT_RETENTION_POLICY_ID, ev);
++
++ retval->value = value;
++
++ return (PortableServer_ServantRetentionPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev);
++}
++
++PortableServer_RequestProcessingPolicy PortableServer_POA_create_request_processing_policy(PortableServer_POA obj, PortableServer_RequestProcessingPolicyValue value, CORBA_Environment *ev)
++{
++ PortableServer_RequestProcessingPolicy retval;
++
++ retval = g_new(struct PortableServer_RequestProcessingPolicy_type, 1);
++ ORBit_policy_object_init((CORBA_Policy)retval,
++ PortableServer_REQUEST_PROCESSING_POLICY_ID, ev);
++
++ retval->value = value;
++
++ return (PortableServer_RequestProcessingPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev);
++}
++
++CORBA_char *PortableServer_POA__get_the_name(PortableServer_POA obj, CORBA_Environment *ev)
++{
++ g_assert(obj);
++ g_assert(obj->the_name);
++ return obj->the_name;
++}
++
++PortableServer_POA
++PortableServer_POA__get_the_parent(PortableServer_POA obj,
++ CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return NULL;
++ }
++
++ return obj->parent_poa;
++}
++
++PortableServer_POAManager
++PortableServer_POA__get_the_POAManager(PortableServer_POA obj,
++ CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return NULL;
++ }
++
++ return obj->the_POAManager;
++}
++
++PortableServer_AdapterActivator PortableServer_POA__get_the_activator(PortableServer_POA obj, CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return NULL;
++ }
++
++ return obj->the_activator;
++}
++
++void PortableServer_POA__set_the_activator(PortableServer_POA obj, PortableServer_AdapterActivator the_activator, CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev,
++ ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ obj->the_activator = the_activator;
++}
++
++PortableServer_ServantManager PortableServer_POA_get_servant_manager(PortableServer_POA obj, CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return NULL;
++ }
++
++ if(obj->request_processing != PortableServer_USE_SERVANT_MANAGER) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_WrongPolicy,
++ NULL);
++ return NULL;
++ }
++
++ return obj->servant_manager;
++}
++
++void PortableServer_POA_set_servant_manager(PortableServer_POA obj, PortableServer_ServantManager imgr, CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ if(obj->request_processing != PortableServer_USE_SERVANT_MANAGER) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_WrongPolicy,
++ NULL);
++ return;
++ }
++
++ obj->servant_manager = imgr;
++}
++
++PortableServer_Servant PortableServer_POA_get_servant(PortableServer_POA obj, CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return NULL;
++ }
++
++ if(obj->request_processing != PortableServer_USE_DEFAULT_SERVANT) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_WrongPolicy,
++ NULL);
++ return NULL;
++ }
++
++ return obj->default_servant;
++}
++
++void PortableServer_POA_set_servant(PortableServer_POA obj, PortableServer_Servant p_servant, CORBA_Environment *ev)
++{
++ if(!obj) {
++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ if(obj->request_processing != PortableServer_USE_DEFAULT_SERVANT) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_WrongPolicy,
++ NULL);
++ return;
++ }
++
++ obj->default_servant = p_servant;
++}
++
++static CORBA_unsigned_long
++get_objnum_for_obj(PortableServer_POA poa, ORBit_POAObject *obj)
++{
++ CORBA_unsigned_long retval;
++
++ if(poa->first_free_id) {
++ retval = poa->first_free_id;
++ poa->first_free_id = GPOINTER_TO_UINT(g_ptr_array_index(poa->objnum_to_obj,
++ retval));
++ g_ptr_array_index(poa->objnum_to_obj, retval) = obj;
++ } else {
++ retval = poa->objnum_to_obj->len;
++ g_ptr_array_add(poa->objnum_to_obj,
++ obj);
++ }
++
++ return retval;
++}
++
++static CORBA_ORB
++get_orb_for_poa(PortableServer_POA poa)
++{
++ if(poa->orb)
++ return poa->orb;
++ if(poa->parent_poa)
++ return get_orb_for_poa(poa->parent_poa);
++
++ return CORBA_OBJECT_NIL;
++}
++
++PortableServer_ObjectId *
++PortableServer_POA_activate_object(PortableServer_POA obj,
++ PortableServer_Servant p_servant,
++ CORBA_Environment *ev)
++{
++ PortableServer_ServantBase *servant;
++ PortableServer_ObjectId *new_objid;
++ ORBit_POAObject *new_obj;
++
++ servant = p_servant;
++
++ if(obj->servant_retention != PortableServer_RETAIN
++ || obj->id_assignment != PortableServer_SYSTEM_ID) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_WrongPolicy,
++ NULL);
++ return NULL;
++ }
++
++ /* Servant Already Active */
++ if((obj->id_uniqueness==PortableServer_UNIQUE_ID) &&
++ (ORBIT_OBJECT_KEY(servant->_private)->object != 0)) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_ServantAlreadyActive,
++ NULL);
++ return NULL;
++ }
++
++
++ new_obj = g_new0(ORBit_POAObject, 1);
++ new_obj->object_id = (PortableServer_ObjectId*)CORBA_sequence_octet__alloc();
++
++ new_objid =
++ ORBit_POA_allocate_oid(obj,
++ ORBIT_OBJECT_KEY(servant->_private)->class_info->class_name);
++
++ new_obj->object_id->_buffer = CORBA_octet_allocbuf(new_objid->_length);
++ new_obj->object_id->_length = new_objid->_length;
++ memcpy(new_obj->object_id->_buffer, new_objid->_buffer,
++ new_objid->_length);
++ CORBA_sequence_set_release(new_obj->object_id, CORBA_TRUE);
++
++ new_obj->servant = p_servant;
++ ORBIT_OBJECT_KEY(servant->_private)->object = new_obj;
++ new_obj->orb = get_orb_for_poa(obj);
++ new_obj->poa = obj;
++ new_obj->objnum = get_objnum_for_obj(obj, new_obj);
++ orbit_genrand(new_obj->rand_data, ORBIT_RAND_KEY_LEN);
++
++ g_hash_table_insert(obj->active_object_map,
++ new_obj->object_id,
++ new_obj);
++
++ ev->_major = CORBA_NO_EXCEPTION;
++
++ return new_objid;
++}
++
++void
++PortableServer_POA_activate_object_with_id(PortableServer_POA obj,
++ PortableServer_ObjectId *id,
++ PortableServer_Servant p_servant,
++ CORBA_Environment *ev)
++{
++ PortableServer_ServantBase *servant = p_servant;
++ ORBit_POAObject *newobj;
++
++ if(!obj || !id || !p_servant) {
++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ newobj = g_hash_table_lookup(obj->active_object_map,
++ id);
++
++ if(newobj) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_ObjectAlreadyActive, NULL);
++ return;
++ }
++
++ newobj = g_new0(ORBit_POAObject, 1);
++ newobj->object_id = (PortableServer_ObjectId *)CORBA_sequence_octet__alloc();
++ newobj->object_id->_length = id->_length;
++ newobj->object_id->_buffer = CORBA_octet_allocbuf(id->_length);
++ newobj->object_id->_release = CORBA_TRUE;
++ memcpy(newobj->object_id->_buffer, id->_buffer, id->_length);
++ newobj->poa = obj;
++ newobj->orb = get_orb_for_poa(obj);
++ newobj->objnum = get_objnum_for_obj(obj, newobj);
++ orbit_genrand(newobj->rand_data, ORBIT_RAND_KEY_LEN);
++
++ newobj->servant = p_servant;
++
++ g_hash_table_insert(obj->active_object_map,
++ newobj->object_id,
++ newobj);
++
++ ORBIT_OBJECT_KEY(servant->_private)->object = newobj;
++
++ ev->_major = CORBA_NO_EXCEPTION;
++}
++
++void
++PortableServer_POA_deactivate_object(PortableServer_POA obj,
++ PortableServer_ObjectId *oid,
++ CORBA_Environment *ev)
++{
++ ORBit_POAObject *oldobj;
++
++ if(!obj || !oid) {
++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ oldobj = g_hash_table_lookup(obj->active_object_map,
++ oid);
++
++ if(!oldobj) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_ObjectNotActive,
++ NULL);
++ return;
++ }
++
++ g_ptr_array_index(obj->objnum_to_obj, oldobj->objnum) = GUINT_TO_POINTER(obj->first_free_id);
++ obj->first_free_id = oldobj->objnum;
++
++ g_hash_table_remove(obj->active_object_map, oid);
++
++ if(obj->request_processing == PortableServer_USE_SERVANT_MANAGER) {
++ POA_PortableServer_ServantActivator__epv *epv;
++ POA_PortableServer_ServantActivator *sm;
++
++ sm = (POA_PortableServer_ServantActivator *)obj->servant_manager;
++ epv = sm->vepv->PortableServer_ServantActivator_epv;
++ epv->etherealize(sm, oldobj->object_id, obj,
++ oldobj->servant,
++ CORBA_FALSE,
++ CORBA_FALSE,
++ ev);
++ }
++
++ CORBA_free(oldobj->object_id);
++
++ g_free(oldobj);
++ ev->_major = CORBA_NO_EXCEPTION;
++}
++
++CORBA_Object
++PortableServer_POA_create_reference(PortableServer_POA obj,
++ CORBA_RepositoryId intf,
++ CORBA_Environment *ev)
++{
++ g_assert(!"Not yet implemented");
++ return(NULL);
++}
++
++PortableServer_ObjectId *PortableServer_POA_servant_to_id(PortableServer_POA obj, PortableServer_Servant p_servant, CORBA_Environment *ev)
++{
++ PortableServer_ObjectId *retval, *orig;
++ PortableServer_ServantBase *serv = p_servant;
++ g_return_val_if_fail(p_servant != NULL, NULL);
++
++ orig = ORBIT_OBJECT_KEY(serv->_private)->object->object_id;
++ retval = (PortableServer_ObjectId *)CORBA_sequence_octet__alloc();
++ retval->_length = retval->_maximum = orig->_length;
++ retval->_buffer = CORBA_octet_allocbuf(retval->_length);
++ memcpy(retval->_buffer, orig->_buffer, retval->_length);
++ CORBA_sequence_set_release(retval, CORBA_TRUE);
++
++ return retval;
++}
++
++CORBA_Object
++PortableServer_POA_servant_to_reference(PortableServer_POA obj, PortableServer_Servant p_servant, CORBA_Environment *ev)
++{
++ CORBA_Object retval;
++ PortableServer_ObjectId *orig_id;
++ PortableServer_ServantBase *servant = p_servant;
++ ORBit_ObjectKey *obj_key = ORBIT_OBJECT_KEY(servant->_private);
++
++ int implicit = (obj->implicit_activation == PortableServer_IMPLICIT_ACTIVATION);
++ int activate_able = (obj_key->object == 0) ||
++ (obj->id_uniqueness==PortableServer_MULTIPLE_ID);
++ /* ImplicitActivationPolicy */
++ if( implicit && activate_able) {
++ orig_id = PortableServer_POA_activate_object(obj, p_servant, ev);
++ } else {
++ orig_id = obj_key->object->object_id;
++ }
++ retval = PortableServer_POA_id_to_reference(obj,orig_id,ev);
++
++ return retval;
++}
++
++PortableServer_Servant
++PortableServer_POA_reference_to_servant(PortableServer_POA obj, CORBA_Object reference, CORBA_Environment *ev)
++{
++ GSList *cur;
++
++ g_assert(reference);
++
++ if(obj->request_processing != PortableServer_USE_DEFAULT_SERVANT
++ && obj->servant_retention != PortableServer_RETAIN) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_WrongPolicy,
++ NULL);
++ return NULL;
++ }
++
++ if(reference->servant)
++ return reference->servant;
++
++ for(cur = reference->profile_list; cur; cur = cur->next) {
++ PortableServer_ObjectId *oid;
++ ORBit_Object_info *curprof = cur->data;
++ ORBit_POAObject *objinfo;
++
++ objinfo = ORBit_POA_find_oid_for_object_key(obj, &(curprof->object_key), &oid);
++ CORBA_free(oid);
++ if(objinfo)
++ return objinfo->servant;
++ }
++
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_ObjectNotActive,
++ NULL);
++ return NULL;
++}
++
++PortableServer_ObjectId *PortableServer_POA_reference_to_id(PortableServer_POA obj, CORBA_Object reference, CORBA_Environment *ev)
++{
++ PortableServer_ObjectId *retval;
++ ORBit_POAObject *objinfo;
++
++ g_assert(reference);
++ g_assert(reference->active_profile);
++
++ if(obj->request_processing != PortableServer_USE_DEFAULT_SERVANT
++ && obj->servant_retention != PortableServer_RETAIN) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_WrongPolicy,
++ NULL);
++ return NULL;
++ }
++
++ objinfo = ORBit_POA_find_oid_for_object_key(obj, &(reference->active_profile->object_key), &retval);
++ if(objinfo) {
++ CORBA_free(retval);
++ retval = (PortableServer_ObjectId *)CORBA_sequence_octet__alloc();
++ retval->_length = retval->_maximum = objinfo->object_id->_length;
++ retval->_buffer = CORBA_octet_allocbuf(retval->_length);
++ memcpy(retval->_buffer, objinfo->object_id->_buffer, retval->_length);
++ CORBA_sequence_set_release(retval, CORBA_TRUE);
++ return retval;
++ } else if(retval)
++ return retval;
++
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_ObjectNotActive,
++ NULL);
++ return NULL;
++}
++
++PortableServer_Servant PortableServer_POA_id_to_servant(PortableServer_POA obj, PortableServer_ObjectId *oid, CORBA_Environment *ev)
++{
++ ORBit_POAObject *objinfo;
++
++ if(obj->servant_retention != PortableServer_RETAIN) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_WrongPolicy,
++ NULL);
++ return NULL;
++ }
++
++ objinfo = g_hash_table_lookup(obj->active_object_map,
++ oid);
++
++ if(!objinfo) {
++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION,
++ ex_PortableServer_POA_WrongPolicy,
++ NULL);
++ return NULL;
++ }
++
++ return objinfo->servant;
++}
++
++static CORBA_Object
++my_PortableServer_POA_id_to_reference(PortableServer_POA obj,
++ PortableServer_ObjectId *oid,
++ const char *type_id,
++ CORBA_Environment *ev)
++{
++ GSList *profiles=NULL;
++ ORBit_Object_info *object_info;
++ CORBA_Object retval;
++ CORBA_ORB orb;
++ ORBit_POAObject *pobj;
++ ORBit_ObjectKey *objkey = NULL;
++
++ orb = obj->the_POAManager->orb;
++
++ g_assert(!oid->_buffer[oid->_length - 1]);
++
++ pobj = g_hash_table_lookup(obj->active_object_map, oid);
++
++ if(pobj) {
++ objkey = ORBIT_OBJECT_KEY(((PortableServer_ServantBase *)pobj->servant)->_private);
++ type_id= objkey->class_info->class_name;
++ }
++
++ /* Do the local connection first, so it will be attempted first by
++ the client parsing the IOR string
++ */
++ if(orb->cnx.ipv6 || orb->cnx.usock) {
++ object_info = g_new0(ORBit_Object_info, 1);
++
++ object_info->profile_type=IOP_TAG_ORBIT_SPECIFIC;
++ object_info->iiop_major = 1;
++ object_info->iiop_minor = 0;
++
++ ORBit_POA_find_object_key_for_oid(obj, pobj, oid, &object_info->object_key);
++
++#ifdef HAVE_IPV6
++ if(orb->cnx.ipv6) {
++ object_info->tag.orbitinfo.ipv6_port =
++ ntohs(IIOP_CONNECTION(orb->cnx.ipv6)->u.ipv6.location.sin_port);
++ }
++#endif
++ if(orb->cnx.usock) {
++ object_info->tag.orbitinfo.unix_sock_path =
++ g_strdup(IIOP_CONNECTION(orb->cnx.usock)->u.usock.sun_path);
++ }
++ ORBit_set_object_key(object_info);
++ profiles=g_slist_append(profiles, object_info);
++ }
++
++ if(orb->cnx.ipv4) {
++ object_info=g_new0(ORBit_Object_info, 1);
++
++ object_info->profile_type = IOP_TAG_INTERNET_IOP;
++ object_info->iiop_major = 1;
++ object_info->iiop_minor = 0;
++ ORBit_POA_find_object_key_for_oid(obj, pobj, oid, &object_info->object_key);
++
++ object_info->tag.iopinfo.host = g_strdup(IIOP_CONNECTION(orb->cnx.ipv4)->u.ipv4.hostname);
++ object_info->tag.iopinfo.port = ntohs(IIOP_CONNECTION(orb->cnx.ipv4)->u.ipv4.location.sin_port);
++
++ ORBit_set_object_key(object_info);
++ profiles=g_slist_append(profiles, object_info);
++ }
++
++ retval = ORBit_create_object_with_info(profiles, type_id, orb, ev);
++
++ if(retval != CORBA_OBJECT_NIL
++ && ev->_major == CORBA_NO_EXCEPTION
++ && objkey && objkey->class_info && objkey->class_info->init_local_objref) {
++ /* XXX potential memleak if we get an already-valid objref */
++ retval->vepv = g_new0(gpointer, ORBit_class_assignment_counter + 1);
++ retval->vepv_size = ORBit_class_assignment_counter + 1;
++ objkey->class_info->init_local_objref(retval, pobj->servant);
++ retval->servant = pobj->servant;
++ } else
++ retval->vepv = retval->servant = NULL;
++
++ return retval;
++}
++
++CORBA_Object PortableServer_POA_id_to_reference(PortableServer_POA obj,
++ PortableServer_ObjectId *oid,
++ CORBA_Environment *ev)
++{
++ return my_PortableServer_POA_id_to_reference(obj, oid, NULL, ev);
++}
++
++CORBA_Object
++PortableServer_POA_create_reference_with_id(PortableServer_POA obj,
++ PortableServer_ObjectId *oid,
++ CORBA_RepositoryId intf,
++ CORBA_Environment *ev)
++{
++ return my_PortableServer_POA_id_to_reference(obj, oid, intf, ev);
++}
++
++PortableServer_POA PortableServer_Current_get_POA(PortableServer_Current obj, CORBA_Environment *ev)
++{
++ g_assert(!"Not yet implemented");
++ return(NULL);
++}
++
++PortableServer_ObjectId *PortableServer_Current_get_object_id(PortableServer_Current obj, CORBA_Environment *ev)
++{
++ g_assert(!"Not yet implemented");
++ return(NULL);
++}
++
++
++CORBA_char *PortableServer_ObjectId_to_string(PortableServer_ObjectId *id, CORBA_Environment *env)
++{
++ return CORBA_string_dup((CORBA_char *)id->_buffer);
++}
++
++CORBA_wchar *PortableServer_ObjectId_to_wstring(PortableServer_ObjectId *id, CORBA_Environment *env)
++{
++ g_assert(!"Not yet implemented");
++ return(NULL);
++}
++
++PortableServer_ObjectId *PortableServer_string_to_ObjectId(CORBA_char *str, CORBA_Environment *env)
++{
++ PortableServer_ObjectId *retval;
++
++ retval = (PortableServer_ObjectId *)CORBA_sequence_octet__alloc();
++
++ retval->_length = strlen(str) + 1;
++ retval->_buffer = CORBA_octet_allocbuf(retval->_length);
++
++ memcpy(retval->_buffer, str, retval->_length);
++
++ return retval;
++}
++
++PortableServer_ObjectId *PortableServer_wstring_to_ObjectId(CORBA_wchar *str, CORBA_Environment *env)
++{
++ g_assert(!"Not yet implemented");
++ return(NULL);
++}
++
++
++PortableServer_POA PortableServer_ServantBase__default_POA(PortableServer_Servant servant, CORBA_Environment *ev)
++{
++ g_return_val_if_fail(servant, NULL);
++
++ return ORBIT_OBJECT_KEY(((PortableServer_ServantBase *)servant)->_private)->object->poa;
++}
++
++void PortableServer_ServantLocator_preinvoke(PortableServer_ObjectId *oid, PortableServer_POA adapter, CORBA_Identifier op_name, PortableServer_ServantLocator_Cookie *cookie)
++{
++ g_assert(!"Not yet implemented");
++ return;
++}
++
++void PortableServer_ServantLocator_postinvoke(PortableServer_ObjectId *oid, PortableServer_POA adapter, CORBA_Identifier op_name, PortableServer_ServantLocator_Cookie cookie, PortableServer_Servant servant)
++{
++ g_assert(!"Not yet implemented");
++ return;
++}
++
++void PortableServer_ServantBase__init(PortableServer_Servant servant,
++ CORBA_Environment *ev)
++{
++ PortableServer_ServantBase *serv = servant;
++
++ if(!serv->_private) /* If not already initialized, create the place to
++ stick our info */
++ serv->_private = g_new0(ORBit_ObjectKey, 1);
++}
++
++void PortableServer_ServantBase__fini(PortableServer_Servant servant,
++ CORBA_Environment *ev)
++{
++ PortableServer_ServantBase *serv = servant;
++
++ g_free(serv->_private);
++ serv->_private = NULL;
++}
++
++
++/************************ ServerRequest stuff ********************/
++
++CORBA_Identifier CORBA_ServerRequest_operation(CORBA_ServerRequest req, CORBA_Environment *env)
++{
++ return CORBA_string_dup(req->rbuf->message.u.request.operation);
++}
++
++CORBA_Context
++CORBA_ServerRequest_ctx(CORBA_ServerRequest req, CORBA_Environment *env)
++{
++ if(!req->params || req->did_ctx) {
++ CORBA_exception_set_system(env, ex_CORBA_BAD_INV_ORDER,
++ CORBA_COMPLETED_NO);
++ return NULL;
++ }
++
++ return NULL;
++}
++
++void
++CORBA_ServerRequest_arguments(CORBA_ServerRequest req,
++ CORBA_NVList *parameters,
++ CORBA_Environment *env)
++{
++ int i;
++
++ if(req->params) {
++ CORBA_exception_set_system(env, ex_CORBA_BAD_INV_ORDER,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ req->params = parameters;
++
++ for(i = 0; i < parameters->list->len; i++) {
++ CORBA_NamedValue *cur;
++
++ cur = &g_array_index(parameters->list, CORBA_NamedValue, i);
++
++ if(cur->arg_modes & CORBA_ARG_OUT) continue;
++ cur->argument._value = ORBit_demarshal_arg(req->rbuf,
++ cur->argument._type,
++ TRUE,
++ (CORBA_ORB)req->orb);
++ CORBA_any_set_release(&cur->argument, TRUE);
++ }
++}
++
++void
++CORBA_ServerRequest_set_result(CORBA_ServerRequest req,
++ CORBA_any *value,
++ CORBA_Environment *env)
++{
++ if(req->sbuf) {
++ CORBA_exception_set_system(env, ex_CORBA_BAD_INV_ORDER,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ req->sbuf = giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(req->rbuf)->connection,
++ NULL,
++ req->rbuf->message.u.request.request_id,
++ CORBA_NO_EXCEPTION);
++ if(!req->sbuf) {
++ CORBA_exception_set_system(env, ex_CORBA_COMM_FAILURE,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ ORBit_marshal_arg(req->sbuf, value->_value, value->_type);
++}
++
++void
++CORBA_ServerRequest_set_exception(CORBA_ServerRequest req,
++ CORBA_exception_type major,
++ CORBA_any *value,
++ CORBA_Environment *env)
++{
++ if(req->sbuf) {
++ CORBA_exception_set_system(env, ex_CORBA_BAD_INV_ORDER,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ req->sbuf = giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(req->rbuf)->connection,
++ NULL,
++ req->rbuf->message.u.request.request_id,
++ major);
++ if(!req->sbuf) {
++ CORBA_exception_set_system(env, ex_CORBA_COMM_FAILURE,
++ CORBA_COMPLETED_NO);
++ return;
++ }
++
++ req->did_exc = TRUE;
++
++ /* XXX do we really need to copy the repo_id into the
++ send buffer? Or is there a way to assume that the CORBA_TypeCode
++ value->_type will be around until after we send the message? */
++ {
++ CORBA_unsigned_long slen;
++ slen = strlen(value->_type->repo_id) + 1;
++ giop_send_buffer_append_mem_indirect_a(req->sbuf, &slen,
++ sizeof(slen));
++ giop_send_buffer_append_mem_indirect(req->sbuf,
++ value->_type->repo_id,
++ slen);
++ }
++
++ ORBit_marshal_arg(req->sbuf, value->_value, value->_type);
++}
++
++void
++POA_PortableServer_ServantActivator__init(PortableServer_Servant servant,
++ CORBA_Environment * ev)
++{
++ static const PortableServer_ClassInfo class_info =
++ {NULL,
++ "IDL:omg.org/PortableServer/ServantActivator:1.0",
++ NULL};
++
++ PortableServer_ServantBase__init(((PortableServer_ServantBase *) servant), ev);
++
++ ORBIT_OBJECT_KEY(((PortableServer_ServantBase *)servant)->_private)->class_info = (gpointer)&class_info;
++}
++
++void
++POA_PortableServer_ServantActivator__fini(PortableServer_Servant servant,
++ CORBA_Environment * ev)
++{
++ PortableServer_ServantBase__fini(servant, ev);
++}
++
++void
++POA_PortableServer_ServantLocator__init(PortableServer_Servant servant,
++ CORBA_Environment * ev)
++{
++ static const PortableServer_ClassInfo class_info =
++ {NULL,
++ "IDL:omg.org/PortableServer/ServantLocator:1.0",
++ NULL};
++
++ PortableServer_ServantBase__init(((PortableServer_ServantBase *)servant), ev);
++
++ ORBIT_OBJECT_KEY(((PortableServer_ServantBase *)servant)->_private)->class_info = (gpointer)&class_info;
++}
++
++void
++POA_PortableServer_ServantLocator__fini(PortableServer_Servant servant,
++ CORBA_Environment * ev)
++{
++ PortableServer_ServantBase__fini(servant, ev);
++}
++
++/* POA-related DSI stuff */
++static void
++dynamic_impl_skel(PortableServer_DynamicImpl *_ORBIT_servant,
++ GIOPRecvBuffer *_ORBIT_recv_buffer,
++ CORBA_Environment *ev,
++ PortableServer_DynamicImplRoutine invoke)
++{
++ /* here the magic occurs... */
++ struct CORBA_ServerRequest_type sr;
++
++ ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(&sr),
++ ORBIT_PSEUDO_SERVERREQUEST, ev);
++
++ CORBA_Object_duplicate((CORBA_Object)&sr, ev); /* just to make
++ sure it doesn't die
++ elsewhere */
++
++ sr.rbuf = _ORBIT_recv_buffer;
++ sr.orb = GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)->connection->orb_data;
++
++ _ORBIT_servant->vepv->PortableServer_DynamicImpl_epv->invoke(_ORBIT_servant,
++ &sr);
++
++ if(sr.sbuf) {
++ int i;
++ for(i = 0; i < sr.params->list->len; i++) {
++ CORBA_NamedValue *cur;
++
++ cur = &g_array_index(sr.params->list, CORBA_NamedValue, i);
++
++ if(cur->arg_modes & CORBA_ARG_IN) continue;
++
++ ORBit_marshal_arg(sr.sbuf, cur->argument._value,
++ cur->argument._type);
++ }
++
++ giop_send_buffer_write(sr.sbuf);
++ giop_send_buffer_unuse(sr.sbuf);
++ } else
++ g_warning("Yo, your DSI code is messed up! You forgot to set_result|set_exception");
++
++ CORBA_NVList_free(sr.params, ev);
++}
++
++static ORBitSkeleton
++dynamic_impl_get_skel(PortableServer_DynamicImpl * servant,
++ GIOPRecvBuffer * _ORBIT_recv_buffer,
++ gpointer * impl)
++{
++ *impl = (gpointer)servant->vepv->PortableServer_DynamicImpl_epv->invoke;
++
++ return (ORBitSkeleton)dynamic_impl_skel;
++}
++
++void
++PortableServer_DynamicImpl__init(PortableServer_Servant servant,
++ CORBA_Environment *ev)
++{
++ static const PortableServer_ClassInfo class_info =
++ {(ORBitSkeleton (*)(PortableServer_ServantBase *, gpointer, gpointer *))
++ &dynamic_impl_get_skel, "IDL:CORBA/Object:1.0", NULL};
++
++ PortableServer_ServantBase__init(servant, ev);
++
++ ORBIT_OBJECT_KEY(((PortableServer_ServantBase *)servant)->_private)->class_info =
++ (PortableServer_ClassInfo *) & class_info;
++
++}
++
++void PortableServer_DynamicImpl__fini(PortableServer_Servant servant,
++ CORBA_Environment *ev)
++{
++ PortableServer_ServantBase__fini(servant, ev);
++}
++
+diff -urN linux-2.4.1/net/korbit/orb/poa.h linux-2.4.1-korbit/net/korbit/orb/poa.h
+--- linux-2.4.1/net/korbit/orb/poa.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/poa.h Thu Feb 1 11:47:14 2001
+@@ -0,0 +1,337 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_POA_H_
++#define _ORBIT_POA_H_
++
++#include "orbit_types.h"
++
++extern PortableServer_ThreadPolicyValue PortableServer_ThreadPolicy__get_value(
++ PortableServer_ThreadPolicy obj,
++ CORBA_Environment *ev);
++
++extern PortableServer_LifespanPolicyValue PortableServer_LifespanPolicy__get_value(
++ PortableServer_LifespanPolicy obj,
++ CORBA_Environment *ev);
++
++extern PortableServer_IdUniquenessPolicyValue PortableServer_IdUniquenessPolicy__get_value(
++ PortableServer_IdUniquenessPolicy obj,
++ CORBA_Environment *ev);
++
++extern PortableServer_IdAssignmentPolicyValue PortableServer_IdAssignmentPolicy__get_value(
++ PortableServer_IdAssignmentPolicy obj,
++ CORBA_Environment *ev);
++
++extern PortableServer_ImplicitActivationPolicyValue PortableServer_ImplicitActivationPolicy__get_value(
++ PortableServer_ImplicitActivationPolicy obj,
++ CORBA_Environment *ev);
++
++extern PortableServer_ServantRetentionPolicyValue PortableServer_ServantRetentionPolicy__get_value(
++ PortableServer_ServantRetentionPolicy obj,
++ CORBA_Environment *ev);
++
++extern PortableServer_RequestProcessingPolicyValue PortableServer_RequestProcessingPolicy__get_value(
++ PortableServer_RequestProcessingPolicy obj,
++ CORBA_Environment *ev);
++
++PortableServer_POAManager_State
++PortableServer_POAManager_get_state(PortableServer_POAManager obj,
++ CORBA_Environment *ev);
++
++extern void PortableServer_POAManager_activate(
++ PortableServer_POAManager obj,
++ CORBA_Environment *ev);
++
++extern void PortableServer_POAManager_hold_requests(
++ PortableServer_POAManager obj,
++ CORBA_boolean wait_for_completion,
++ CORBA_Environment *ev);
++
++extern void PortableServer_POAManager_discard_requests(
++ PortableServer_POAManager obj,
++ CORBA_boolean wait_for_completion,
++ CORBA_Environment *ev);
++
++extern void PortableServer_POAManager_deactivate(
++ PortableServer_POAManager obj,
++ CORBA_boolean etherealize_objects,
++ CORBA_boolean wait_for_completion,
++ CORBA_Environment *ev);
++
++extern CORBA_boolean PortableServer_AdapterActivator_unknown_adapter(
++ PortableServer_AdapterActivator obj,
++ PortableServer_POA parent,
++ CORBA_char *name,
++ CORBA_Environment *ev);
++
++extern PortableServer_Servant PortableServer_ServantActivator_incarnate(
++ PortableServer_ServantActivator obj,
++ PortableServer_ObjectId *oid,
++ PortableServer_POA adapter,
++ CORBA_Environment *ev);
++
++extern void PortableServer_ServantActivator_etherealize(
++ PortableServer_ServantActivator obj,
++ PortableServer_ObjectId *oid,
++ PortableServer_POA adapter,
++ PortableServer_Servant serv,
++ CORBA_boolean cleanup_in_progress,
++ CORBA_boolean remaining_activations,
++ CORBA_Environment *ev);
++
++extern PortableServer_POA PortableServer_POA_create_POA(
++ PortableServer_POA obj,
++ CORBA_char *adapter_name,
++ PortableServer_POAManager a_POAManager,
++ CORBA_PolicyList *policies,
++ CORBA_Environment *ev);
++
++extern PortableServer_POA PortableServer_POA_find_POA(
++ PortableServer_POA obj,
++ CORBA_char *adapter_name,
++ CORBA_boolean activate_it,
++ CORBA_Environment *ev);
++
++extern void PortableServer_POA_destroy(
++ PortableServer_POA obj,
++ CORBA_boolean etherealize_objects,
++ CORBA_boolean wait_for_completion,
++ CORBA_Environment *ev);
++
++extern PortableServer_ThreadPolicy PortableServer_POA_create_thread_policy(
++ PortableServer_POA obj,
++ PortableServer_ThreadPolicyValue value,
++ CORBA_Environment *ev);
++
++extern PortableServer_LifespanPolicy PortableServer_POA_create_lifespan_policy(
++ PortableServer_POA obj,
++ PortableServer_LifespanPolicyValue value,
++ CORBA_Environment *ev);
++
++extern PortableServer_IdUniquenessPolicy PortableServer_POA_create_id_uniqueness_policy(
++ PortableServer_POA obj,
++ PortableServer_IdUniquenessPolicyValue value,
++ CORBA_Environment *ev);
++
++extern PortableServer_IdAssignmentPolicy PortableServer_POA_create_id_assignment_policy(
++ PortableServer_POA obj,
++ PortableServer_IdAssignmentPolicyValue value,
++ CORBA_Environment *ev);
++
++extern PortableServer_ImplicitActivationPolicy PortableServer_POA_create_implicit_activation_policy(
++ PortableServer_POA obj,
++ PortableServer_ImplicitActivationPolicyValue value,
++ CORBA_Environment *ev);
++
++extern PortableServer_ServantRetentionPolicy PortableServer_POA_create_servant_retention_policy(
++ PortableServer_POA obj,
++ PortableServer_ServantRetentionPolicyValue value,
++ CORBA_Environment *ev);
++
++extern PortableServer_RequestProcessingPolicy PortableServer_POA_create_request_processing_policy(
++ PortableServer_POA obj,
++ PortableServer_RequestProcessingPolicyValue value,
++ CORBA_Environment *ev);
++
++extern CORBA_char *PortableServer_POA__get_the_name(
++ PortableServer_POA obj,
++ CORBA_Environment *ev);
++
++extern PortableServer_POA PortableServer_POA__get_the_parent(
++ PortableServer_POA obj,
++ CORBA_Environment *ev);
++
++extern PortableServer_POAManager PortableServer_POA__get_the_POAManager(
++ PortableServer_POA obj,
++ CORBA_Environment *ev);
++
++extern PortableServer_AdapterActivator PortableServer_POA__get_the_activator(
++ PortableServer_POA obj,
++ CORBA_Environment *ev);
++
++extern void PortableServer_POA__set_the_activator(
++ PortableServer_POA obj,
++ PortableServer_AdapterActivator the_activator,
++ CORBA_Environment *ev);
++
++extern PortableServer_ServantManager PortableServer_POA_get_servant_manager(
++ PortableServer_POA obj,
++ CORBA_Environment *ev);
++
++extern void PortableServer_POA_set_servant_manager(
++ PortableServer_POA obj,
++ PortableServer_ServantManager imgr,
++ CORBA_Environment *ev);
++
++extern PortableServer_Servant PortableServer_POA_get_servant(
++ PortableServer_POA obj,
++ CORBA_Environment *ev);
++
++extern void PortableServer_POA_set_servant(
++ PortableServer_POA obj,
++ PortableServer_Servant p_servant,
++ CORBA_Environment *ev);
++
++extern PortableServer_ObjectId *PortableServer_POA_activate_object(
++ PortableServer_POA obj,
++ PortableServer_Servant p_servant,
++ CORBA_Environment *ev);
++
++extern void PortableServer_POA_activate_object_with_id(
++ PortableServer_POA obj,
++ PortableServer_ObjectId *id,
++ PortableServer_Servant p_servant,
++ CORBA_Environment *ev);
++
++extern void PortableServer_POA_deactivate_object(
++ PortableServer_POA obj,
++ PortableServer_ObjectId *oid,
++ CORBA_Environment *ev);
++
++extern CORBA_Object PortableServer_POA_create_reference(
++ PortableServer_POA obj,
++ CORBA_RepositoryId intf,
++ CORBA_Environment *ev);
++
++extern CORBA_Object PortableServer_POA_create_reference_with_id(
++ PortableServer_POA obj,
++ PortableServer_ObjectId *oid,
++ CORBA_RepositoryId intf,
++ CORBA_Environment *ev);
++
++extern PortableServer_ObjectId *PortableServer_POA_servant_to_id(
++ PortableServer_POA obj,
++ PortableServer_Servant p_servant,
++ CORBA_Environment *ev);
++
++extern CORBA_Object PortableServer_POA_servant_to_reference(
++ PortableServer_POA obj,
++ PortableServer_Servant p_servant,
++ CORBA_Environment *ev);
++
++extern PortableServer_Servant PortableServer_POA_reference_to_servant(
++ PortableServer_POA obj,
++ CORBA_Object reference,
++ CORBA_Environment *ev);
++
++extern PortableServer_ObjectId *PortableServer_POA_reference_to_id(
++ PortableServer_POA obj,
++ CORBA_Object reference,
++ CORBA_Environment *ev);
++
++extern PortableServer_Servant PortableServer_POA_id_to_servant(
++ PortableServer_POA obj,
++ PortableServer_ObjectId *oid,
++ CORBA_Environment *ev);
++
++extern CORBA_Object PortableServer_POA_id_to_reference(
++ PortableServer_POA obj,
++ PortableServer_ObjectId *oid,
++ CORBA_Environment *ev);
++
++extern PortableServer_POA PortableServer_Current_get_POA(
++ PortableServer_Current obj,
++ CORBA_Environment *ev);
++
++extern PortableServer_ObjectId *PortableServer_Current_get_object_id(
++ PortableServer_Current obj,
++ CORBA_Environment *ev);
++
++extern CORBA_char *PortableServer_ObjectId_to_string(
++ PortableServer_ObjectId *id,
++ CORBA_Environment *env);
++
++extern CORBA_wchar *PortableServer_ObjectId_to_wstring(
++ PortableServer_ObjectId *id,
++ CORBA_Environment *env);
++
++extern PortableServer_ObjectId *PortableServer_string_to_ObjectId(
++ CORBA_char *str,
++ CORBA_Environment *env);
++
++extern PortableServer_ObjectId *PortableServer_wstring_to_ObjectId(
++ CORBA_wchar *str,
++ CORBA_Environment *env);
++
++extern PortableServer_POA PortableServer_ServantBase__default_POA(
++ PortableServer_Servant,
++ CORBA_Environment *);
++
++extern void PortableServer_ServantLocator_preinvoke(
++ PortableServer_ObjectId *oid,
++ PortableServer_POA adapter,
++ CORBA_Identifier op_name,
++ PortableServer_ServantLocator_Cookie *cookie);
++
++extern void PortableServer_ServantLocator_postinvoke(
++ PortableServer_ObjectId *oid,
++ PortableServer_POA adapter,
++ CORBA_Identifier op_name,
++ PortableServer_ServantLocator_Cookie cookie,
++ PortableServer_Servant servant);
++
++extern void PortableServer_ServantBase__init(
++ PortableServer_Servant,
++ CORBA_Environment *);
++
++extern void PortableServer_ServantBase__fini(
++ PortableServer_Servant,
++ CORBA_Environment *);
++
++/* 19.27 */
++extern CORBA_Identifier CORBA_ServerRequest_operation(
++ CORBA_ServerRequest req,
++ CORBA_Environment *env);
++
++extern CORBA_Context CORBA_ServerRequest_ctx(
++ CORBA_ServerRequest req,
++ CORBA_Environment *env);
++
++extern void CORBA_ServerRequest_arguments(
++ CORBA_ServerRequest req,
++ CORBA_NVList *parameters,
++ CORBA_Environment *env);
++
++extern void CORBA_ServerRequest_set_result(
++ CORBA_ServerRequest req,
++ CORBA_any *value,
++ CORBA_Environment *env);
++
++extern void CORBA_ServerRequest_set_exception(
++ CORBA_ServerRequest req,
++ CORBA_exception_type major,
++ CORBA_any *value,
++ CORBA_Environment *env);
++
++extern void PortableServer_DynamicImpl__init(PortableServer_Servant,
++ CORBA_Environment *ev);
++
++extern void PortableServer_DynamicImpl__fini(PortableServer_Servant,
++ CORBA_Environment *ev);
++
++
++#include "orbit_poa_type.h"
++
++#endif /* !_ORBIT_POA_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/sequences.c linux-2.4.1-korbit/net/korbit/orb/sequences.c
+--- linux-2.4.1/net/korbit/orb/sequences.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/sequences.c Thu Feb 1 11:47:14 2001
+@@ -0,0 +1,35 @@
++#include "orbit.h"
++#include "sequences.h"
++
++gpointer CORBA_sequence_octet_free(gpointer mem,
++ gpointer func_data)
++{
++ CORBA_sequence_octet *seqo = mem;
++
++ if(seqo->_release)
++ CORBA_free(seqo->_buffer);
++
++ return (gpointer)((guchar *)mem + sizeof(CORBA_sequence_octet));
++}
++
++CORBA_octet *
++CORBA_octet_allocbuf(CORBA_unsigned_long len)
++{
++ return (CORBA_octet *)ORBit_alloc(len, NULL, NULL);
++}
++
++CORBA_sequence_octet *CORBA_sequence_octet__alloc(void)
++{
++ CORBA_sequence_octet *seqo;
++
++ seqo = ORBit_alloc(sizeof(CORBA_sequence_octet),
++ (ORBit_free_childvals)CORBA_sequence_octet_free,
++ GUINT_TO_POINTER(1));
++
++ seqo->_length = seqo->_maximum = 0;
++ seqo->_buffer = NULL;
++ seqo->_release = CORBA_TRUE;
++
++ return seqo;
++}
++
+diff -urN linux-2.4.1/net/korbit/orb/sequences.h linux-2.4.1-korbit/net/korbit/orb/sequences.h
+--- linux-2.4.1/net/korbit/orb/sequences.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/sequences.h Thu Feb 1 16:21:19 2001
+@@ -0,0 +1,35 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_SEQUENCES_H_
++#define _ORBIT_SEQUENCES_H_
++
++/* #include "corba_sequences_type.h" */
++#include "orbit_types.h"
++
++CORBA_octet *CORBA_octet_allocbuf(CORBA_unsigned_long len);
++CORBA_sequence_octet *CORBA_sequence_octet__alloc(void);
++
++#endif /* !_ORBIT_SEQUENCES_H_ */
+diff -urN linux-2.4.1/net/korbit/orb/server.c linux-2.4.1-korbit/net/korbit/orb/server.c
+--- linux-2.4.1/net/korbit/orb/server.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/server.c Thu Feb 1 11:47:14 2001
+@@ -0,0 +1,217 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/* Elliot's stuff */
++/* This is somewhat a mess, because I tried to make it easy to add
++ select() support, and as a result #ifdef's litter the land. */
++
++#include "orbit.h"
++#include "orbit_poa.h"
++#include "orbit_poa_type.h"
++#include <IIOP/IIOP-private.h>
++#ifdef HAVE_SYS_POLL_H
++#include <sys/poll.h>
++#endif
++#include <sys/types.h>
++#include <sys/socket.h>
++
++/* We need:
++ a way to find out what FD's need to be selected on
++ a dummy main loop to implement the CORBA_ORB_run() routine;
++*/
++
++gboolean orb_server_keep_running = FALSE;
++
++ORBit_request_validate ORBIT_request_validator = NULL;
++
++/* function protos */
++static PortableServer_POA ORBit_find_POA_for_request(PortableServer_POA poa,
++ GIOPRecvBuffer *recv_buffer);
++static PortableServer_POA ORBit_find_POA_for_locate_request(PortableServer_POA poa,
++ GIOPRecvBuffer *recv_buffer);
++
++static void ORBit_handle_incoming_message(GIOPRecvBuffer *recv_buffer);
++
++void
++ORBit_custom_run_setup(CORBA_ORB orb, CORBA_Environment *ev)
++{
++ IIOPIncomingMessageHandler = ORBit_handle_incoming_message;
++}
++
++
++#if __KERNEL__
++// Modules don't do anything when they call this...
++void CORBA_ORB_run(CORBA_ORB orb, CORBA_Environment *ev) {
++ // This should probably free the ORB pointer, because it is a
++ // duplicated pointer from the one true orb.
++
++}
++
++// The ORB thread calls __CORBA_ORB_run by itself.
++#define CORBA_ORB_run __CORBA_ORB_run
++
++#endif
++
++void
++CORBA_ORB_run(CORBA_ORB orb, CORBA_Environment *ev)
++{
++ ORBit_custom_run_setup(orb, ev);
++
++ orb_server_keep_running = TRUE;
++
++ giop_main();
++}
++
++static void
++ORBit_handle_incoming_request(GIOPRecvBuffer *recv_buffer)
++{
++ CORBA_ORB orb;
++ PortableServer_POA poa;
++ GIOPConnection *connection;
++ ORBit_MessageValidationResult mvr;
++ gboolean do_unuse = TRUE;
++
++ g_assert(recv_buffer);
++
++ connection = GIOP_MESSAGE_BUFFER(recv_buffer)->connection;
++ g_return_if_fail(connection != NULL);
++
++ orb = connection->orb_data;
++
++ g_return_if_fail(orb != NULL);
++
++ ORBit_Trace(TraceMod_ORB, TraceLevel_Debug,
++ "Received request %s, id %d, on %s",
++ recv_buffer->message.u.request.operation,
++ recv_buffer->message.u.request.request_id,
++ recv_buffer->message.u.request.object_key._buffer);
++
++ if(ORBIT_request_validator)
++ mvr = ORBIT_request_validator(recv_buffer->message.u.request.request_id,
++ &recv_buffer->message.u.request.requesting_principal,
++ recv_buffer->message.u.request.operation);
++ else
++ mvr = ORBIT_MESSAGE_ALLOW;
++
++ if(mvr == ORBIT_MESSAGE_ALLOW_ALL)
++ connection->is_auth = TRUE;
++
++ if(mvr != ORBIT_MESSAGE_BAD) {
++ /* Find the POA for this incoming request */
++ poa = ORBit_find_POA_for_request((PortableServer_POA)orb->root_poa,
++ recv_buffer);
++
++ if(poa)
++ do_unuse = ORBit_POA_handle_request(recv_buffer, poa);
++ else
++ g_warning("No POA found for operation %s [%d]",
++ recv_buffer->message.u.request.operation,
++ recv_buffer->message.u.request.request_id);
++ } else {
++ g_warning("Request %s, ID %d was rejected by the authentication mechanism!",
++ recv_buffer->message.u.request.operation,
++ recv_buffer->message.u.request.request_id);
++ }
++
++ if(do_unuse)
++ giop_recv_buffer_unuse(recv_buffer);
++}
++
++static void
++ORBit_handle_incoming_locate_request(GIOPRecvBuffer *recv_buffer)
++{
++ CORBA_ORB orb;
++ PortableServer_POA poa;
++ GIOPConnection *connection;
++ GIOPSendBuffer *send_buffer;
++
++ g_assert(recv_buffer!=NULL);
++
++ connection = GIOP_MESSAGE_BUFFER(recv_buffer)->connection;
++ g_return_if_fail(connection != NULL);
++
++ orb = connection->orb_data;
++
++ g_return_if_fail(orb != NULL);
++
++ ORBit_Trace(TraceMod_ORB, TraceLevel_Debug,
++ "Received locate request id %d, on %s",
++ recv_buffer->message.u.locate_request.request_id,
++ recv_buffer->message.u.locate_request.object_key._buffer);
++ /* Find the POA for this incoming request */
++ poa = ORBit_find_POA_for_locate_request((PortableServer_POA)orb->root_poa, recv_buffer);
++
++ if(poa) {
++ /* Object found, reply with "Object Here" */
++ send_buffer = giop_send_locate_reply_buffer_use(connection,
++ recv_buffer->message.u.locate_request.request_id,
++ GIOP_OBJECT_HERE);
++ giop_send_buffer_write(send_buffer);
++ giop_send_buffer_unuse(send_buffer);
++ } else {
++ /* Object not found, reply with "Unknown Object" */
++ send_buffer = giop_send_locate_reply_buffer_use(connection,
++ recv_buffer->message.u.locate_request.request_id,
++ GIOP_UNKNOWN_OBJECT);
++ giop_send_buffer_write(send_buffer);
++ giop_send_buffer_unuse(send_buffer);
++ }
++
++ giop_recv_buffer_unuse(recv_buffer);
++}
++
++static void
++ORBit_handle_incoming_message(GIOPRecvBuffer *recv_buffer)
++{
++ GIOPConnection *connection;
++
++ g_assert(recv_buffer);
++
++ connection = GIOP_MESSAGE_BUFFER(recv_buffer)->connection;
++ g_return_if_fail(connection != NULL);
++
++ switch(GIOP_MESSAGE_BUFFER(recv_buffer)->message_header.message_type) {
++ case GIOP_REQUEST:
++ ORBit_handle_incoming_request(recv_buffer);
++ break;
++ case GIOP_LOCATEREQUEST:
++ ORBit_handle_incoming_locate_request(recv_buffer);
++ break;
++ case GIOP_CLOSECONNECTION:
++ /* Lame hack - need to do this in a manner that isn't
++ IIOP-specific */
++ giop_recv_buffer_unuse(recv_buffer);
++ giop_main_handle_connection_exception(connection);
++ break;
++ case GIOP_REPLY:
++ /* the above comment probably applies here also... */
++ giop_received_list_push(recv_buffer);
++ break;
++ default:
++ g_warning("discarding message type %d (id possibly %d)",
++ GIOP_MESSAGE_BUFFER(recv_buffer)->message_header.message_type,
++ GIOP_MESSAGE_BUFFER(recv_buffer)->message_header.message_type?recv_buffer->message.u.reply.request_id:recv_buffer->message.u.request.request_id);
++ break;
++ }
++}
++
++static PortableServer_POA
++ORBit_find_POA_for_request(PortableServer_POA poa,
++ GIOPRecvBuffer *recv_buffer)
++{
++ return ORBit_POA_find_POA_for_object_key(poa,
++ &recv_buffer->message.u.request.object_key);
++}
++
++static PortableServer_POA
++ORBit_find_POA_for_locate_request(PortableServer_POA poa,
++ GIOPRecvBuffer *recv_buffer)
++{
++ return ORBit_POA_find_POA_for_object_key(poa,
++ &recv_buffer->message.u.locate_request.object_key);
++}
++
++void
++ORBit_set_request_validation_handler(ORBit_request_validate validator)
++{
++ ORBIT_request_validator = validator;
++}
+diff -urN linux-2.4.1/net/korbit/orb/typecode.c linux-2.4.1-korbit/net/korbit/orb/typecode.c
+--- linux-2.4.1/net/korbit/orb/typecode.c Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/typecode.c Thu Feb 1 11:47:14 2001
+@@ -0,0 +1,104 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter, Red Hat Software
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ * Elliot Lee <sopwith@cuc.edu>
++ *
++ */
++
++#include "orbit.h"
++#include "orbit_typecode.h"
++
++const struct CORBA_TypeCode_struct TC_null_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_null, "null", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_void_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_void, "void", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_short_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_short, "short", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_long_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_long, "long", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_longlong_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_longlong, "long long", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_ushort_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_ushort, "unsigned short", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_ulong_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_ulong, "unsigned long", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_ulonglong_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_ulonglong, "unsigned long long", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_float_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_float, "float", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_double_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_double, "double", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_longdouble_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_longdouble, "long double", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_boolean_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_boolean, "boolean", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_char_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_char, "char", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_wchar_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_wchar, "wide char", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_octet_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_octet, "octet", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_any_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_any, "any", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_TypeCode_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_TypeCode, "TypeCode", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_Principal_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_Principal, "Principal", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_Object_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_objref, "Object Reference", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_string_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_string, "string", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_wstring_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_wstring, "wide string", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++const struct CORBA_TypeCode_struct TC_CORBA_NamedValue_struct=
++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_struct, "CORBA NamedValue", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0};
++
++static const CORBA_TypeCode anon_subtypes_array7[] =
++{(CORBA_TypeCode) & TC_CORBA_string_struct};
++
++#if (TC_IMPL_TC_CORBA_Identifier_0 == '/')
++const struct CORBA_TypeCode_struct TC_CORBA_Identifier_struct =
++{
++ {
++ {(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1}, ORBIT_PSEUDO_TYPECODE},
++ CORBA_tk_alias, "Identifier", "IDL:omg.org/CORBA/Identifier:1.0",
++ 0, 1,
++ NULL,
++ (CORBA_TypeCode *) anon_subtypes_array7,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
++
++#if (TC_IMPL_TC_CORBA_RepositoryId_0 == '/')
++const struct CORBA_TypeCode_struct TC_CORBA_RepositoryId_struct =
++{
++ {
++ {(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1}, ORBIT_PSEUDO_TYPECODE},
++ CORBA_tk_alias, "RepositoryId", "IDL:omg.org/CORBA/RepositoryId:1.0",
++ 0, 1,
++ NULL,
++ (CORBA_TypeCode *) anon_subtypes_array7,
++ NULL,
++ CORBA_OBJECT_NIL, 0, -1, 0, 0
++};
++#endif
+diff -urN linux-2.4.1/net/korbit/orb/typecode.h linux-2.4.1-korbit/net/korbit/orb/typecode.h
+--- linux-2.4.1/net/korbit/orb/typecode.h Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/orb/typecode.h Thu Feb 1 11:47:14 2001
+@@ -0,0 +1,31 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/*
++ * ORBit: A CORBA v2.2 ORB
++ *
++ * Copyright (C) 1998 Richard H. Porter
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Author: Dick Porter <dick@cymru.net>
++ *
++ */
++
++#ifndef _ORBIT_TYPECODE_H_
++#define _ORBIT_TYPECODE_H_
++
++#include "orbit_types.h"
++
++#endif /* !_ORBIT_TYPECODE_H_ */
+diff -urN linux-2.4.1/net/korbit/sup/CVS/Entries linux-2.4.1-korbit/net/korbit/sup/CVS/Entries
+--- linux-2.4.1/net/korbit/sup/CVS/Entries Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/sup/CVS/Entries Thu Feb 1 11:47:15 2001
+@@ -0,0 +1 @@
++D
+diff -urN linux-2.4.1/net/korbit/sup/CVS/Repository linux-2.4.1-korbit/net/korbit/sup/CVS/Repository
+--- linux-2.4.1/net/korbit/sup/CVS/Repository Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/sup/CVS/Repository Thu Feb 1 11:47:15 2001
+@@ -0,0 +1 @@
++/cvsroot/korbit/linux/net/korbit/sup
+diff -urN linux-2.4.1/net/korbit/sup/CVS/Root linux-2.4.1-korbit/net/korbit/sup/CVS/Root
+--- linux-2.4.1/net/korbit/sup/CVS/Root Thu Jan 1 03:00:00 1970
++++ linux-2.4.1-korbit/net/korbit/sup/CVS/Root Thu Feb 1 11:47:15 2001
+@@ -0,0 +1 @@
++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit
diff --git a/fs/libmysqlfs.c b/fs/libmysqlfs.c
new file mode 100644
index 00000000000..856692d0bd1
--- /dev/null
+++ b/fs/libmysqlfs.c
@@ -0,0 +1,153 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+ *
+ * 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 "libmysqlfs.h"
+
+int search_and_replace(char *search, char* replace, char* string)
+{
+ char buff[1024];
+ int found=0;
+ char *ptr1;
+ const char *ptr2=buff;
+ char *strptr=string;
+
+ DBUG_ENTER("search_and_replace");
+ DBUG_PRINT("enter",("search: '%s' replace:'%s' string:'%s'",search,replace,string));
+ strcpy(buff,string);
+ while(ptr1=strstr(ptr2,search))
+ {
+ strncpy(strptr,ptr2,ptr1-buff);
+ strptr+=ptr1-buff;
+ ptr2+=ptr1-buff+strlen(search);
+ strcpy(strptr,replace);
+ strptr+=strlen(replace);
+ found++;
+ }
+ DBUG_RETURN(found);
+}
+
+int show_functions(char *b, function_type type)
+{
+ int i=0,j=0;
+ struct func_st func;
+ DBUG_ENTER("show_functions");
+ get_dynamic(&functions_array,(gptr)&func,i);
+ while(func.length) {
+ if (func.type == type)
+ strcpy(&b[j++*BUFLEN],func.filename);
+ get_dynamic(&functions_array,(gptr)&func,++i);
+ }
+ DBUG_RETURN(j);
+}
+
+struct func_st * check_if_function(char *name, function_type type)
+{
+ int pathlen;
+ int j,i=0, len;
+ static struct func_st function;
+ char buffer[BUFLEN];
+
+ DBUG_ENTER("check_if_function");
+ DBUG_PRINT("enter",("name: '%s' type: '%d'", name, type));
+ pathlen=strlen(name);
+
+ /* We try to compare last element in path to function names */
+ get_dynamic(&functions_array,(gptr)&function,i);
+ while(function.length) {
+ function.continuous ?
+ (j=!strncasecmp(function.filename, name, function.length))
+ : (j=!strcasecmp(function.filename,name));
+ if(j) { /* This happens when function was matched */
+ DBUG_PRINT("info",("Function %s detected!",function.filename));
+ break;
+ }
+ get_dynamic(&functions_array,(gptr)&function,++i);
+ }
+
+ /* Copy path to buffer and trip function name (if found) from it */
+ if(function.length != 0)
+ {
+ DBUG_RETURN(&function);
+ } else {
+ DBUG_RETURN(0);
+ }
+}
+
+/*
+ * parse - splits "path" into different variables
+ * in way "/server/database/table/(field|key)/(value|function)". If path is shorter,
+ * then other fields will be NULL. If path is longer than four levels or
+ * shorter than one level, FS_NOTEXIST is returned.
+ */
+int parse(const char * path, char *server, char * database, char *table,
+ char* field, char* value, struct func_st **funce)
+{
+ char buffer[BUFLEN];
+ char *p=buffer;
+ char *x;
+ int len;
+
+ DBUG_ENTER("parse");
+ DBUG_PRINT("enter",("path: '%s'", path));
+
+ *server=*database=*table=*field=*value='\0';
+
+ /* Search for first slash and drop it */
+ strcpy(buffer,path);
+ x=strtok_r(p,"/",&p);
+ if(x)
+ {
+ strcpy(server,x); /* First argument is server name */
+ if(*p)
+ strcpy(database,strtok_r(p,"/",&p)); /* Second is database */
+ if(p && *p)
+ strcpy(table ,strtok_r(p,"/",&p)); /* Third is table name */
+ if(p && *p)
+ strcpy(field ,strtok_r(p,"/",&p)); /* Fourth is field or key name */
+ if(p && *p)
+ strcpy(value ,strtok_r(p,"/",&p)); /* Fifth is field/key value or function */
+ }
+
+ /* We have to find if last argument is function,
+ * In which case we clear it
+ */
+ if(*value) {
+ *funce=check_if_function(value,VALUE_FUNCTION);
+ if(*funce) *value='\0';
+ } else if (*field) {
+ *funce=check_if_function(field,FIELD_FUNCTION);
+ if(*funce) *field='\0';
+ } else if (*table) {
+ *funce=check_if_function(table,TABLE_FUNCTION);
+ if(*funce) *table='\0';
+ } else if (*database) {
+ *funce=check_if_function(database,DATABASE_FUNCTION);
+ if(*funce) *database='\0';
+ } else if (*server) {
+ *funce=check_if_function(server,SERVER_FUNCTION);
+ if(*funce) *server='\0';
+ } else
+ *funce=NULL;
+
+ DBUG_PRINT("info",("path: '%s', server: '%s', db: '%s', table: '%s', field: '%s', value: '%s', function: '%x'",
+ buffer, server, database, table, field, value, funce ));
+ if(p && *p) /* Something is in buffer - too deep in levels */
+ DBUG_RETURN(-1)
+ else
+ DBUG_RETURN(0)
+}
+
+
diff --git a/fs/libmysqlfs.h b/fs/libmysqlfs.h
new file mode 100644
index 00000000000..5af78b4c6d6
--- /dev/null
+++ b/fs/libmysqlfs.h
@@ -0,0 +1,81 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+ *
+ * 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 "CorbaFS.h"
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include "mysql.h"
+
+#define BUFLEN 1024
+#define MAXDIRS 1024
+
+typedef enum {
+ FUNC_NONE,
+ FUNC_SERVER_UPTIME,
+ FUNC_SERVER_THREADS,
+ FUNC_SERVER_VERSION,
+ FUNC_DATABASE_CREATED,
+ FUNC_TABLE_COUNT,
+ FUNC_TABLE_CREATED,
+ FUNC_FIELD_LENGTH,
+ FUNC_KEY_AVG,
+ FUNC_KEY_SUM,
+ FUNC_KEY_MAX,
+ FUNC_KEY_MIN
+} func_enum;
+
+
+typedef enum {
+ NONE_FUNCTION,
+ ROOT_FUNCTION,
+ SERVER_FUNCTION,
+ DATABASE_FUNCTION,
+ TABLE_FUNCTION,
+ KEY_FUNCTION,
+ FIELD_FUNCTION,
+ VALUE_FUNCTION
+} function_type;
+
+struct func_st {
+ char type_s[20];
+ char filename[20];
+ char function[80];
+ function_type type;
+ int length;
+ my_bool continuous;
+} ;
+
+
+int parse(const char* path,
+ char* root,
+ char* database,
+ char* table,
+ char* key,
+ char* field,
+ struct func_st **func
+);
+
+gptr db_load_functions();
+int db_function(char *b,const char *server, const char *database,const char *table,const char *field,
+ const char *value, const char *path, struct func_st *function);
+int fix_filenames(char *buf);
+
+DYNAMIC_ARRAY functions_array;
+
+
diff --git a/fs/my.cnf b/fs/my.cnf
new file mode 100644
index 00000000000..e70f2c30cbf
--- /dev/null
+++ b/fs/my.cnf
@@ -0,0 +1,5 @@
+[mysqlcorbafs]
+socket=/var/lib/mysql/mysql.sock
+host=127.0.0.1
+user=root
+#password=xxxxxx
diff --git a/fs/mysqlcorbafs.c b/fs/mysqlcorbafs.c
new file mode 100644
index 00000000000..70db96f64a9
--- /dev/null
+++ b/fs/mysqlcorbafs.c
@@ -0,0 +1,992 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+ *
+ * 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
+ */
+
+
+/*
+ *
+ * fsck.mysql
+ */
+
+#include "libmysqlfs.h"
+#include "mysqlcorbafs.h"
+#include <getopt.h>
+#define MAXPATHLEN 256
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#include <my_sys.h>
+static long inodeNum;
+
+extern DYNAMIC_ARRAY functions_array;
+enum options {OPT_FTB=256, OPT_LTB, OPT_ENC, OPT_O_ENC, OPT_ESC, OPT_KEYWORDS,
+ OPT_LOCKS, OPT_DROP, OPT_OPTIMIZE, OPT_DELAYED, OPT_TABLES,
+ OPT_CHARSETS_DIR, OPT_DEFAULT_CHARSET};
+
+CHANGEABLE_VAR changeable_vars[] = {
+ { "max_allowed_packet", (long*) &max_allowed_packet,24*1024*1024,4096,
+ 24*1024L*1024L,MALLOC_OVERHEAD,1024},
+ { "net_buffer_length", (long*) &net_buffer_length,1024*1024L-1025,4096,
+ 24*1024L*1024L,MALLOC_OVERHEAD,1024},
+ { 0, 0, 0, 0, 0, 0, 0}
+};
+
+CORBA_ORB orb;
+PortableServer_POA poa;
+CORBA_Environment *ev;
+PortableServer_ObjectId *objid;
+static my_bool verbose=0,opt_compress=0,extended_insert=0, lock_tables=0,
+ opt_quoted=0, opt_lock=0, opt_delayed=0, ignore_errors=0;
+
+gptr fptr;
+
+static const char *load_default_groups[]= { "mysqlcorbafs","client",0 };
+static char *default_charset, *current_host, *current_user, *opt_password,
+ *path,*fields_terminated=0, *lines_terminated=0, *enclosed=0,
+ *opt_enclosed=0, *escaped=0;
+
+static struct option long_options[] =
+{
+ {"add-locks", no_argument, 0,OPT_LOCKS},
+ {"character-sets-dir",required_argument,0, OPT_CHARSETS_DIR},
+ {"compress", no_argument, 0, 'C'},
+ {"database",required_argument, 0, 'D'},
+ {"debug",optional_argument, 0, '#'},
+ {"default-character-set", required_argument, 0, OPT_DEFAULT_CHARSET},
+ {"delayed-insert",no_argument, 0, OPT_DELAYED},
+ {"fields-terminated-by", required_argument, 0, (int) OPT_FTB},
+ {"fields-enclosed-by", required_argument,0, (int) OPT_ENC},
+ {"fields-optionally-enclosed-by", required_argument, 0, (int) OPT_O_ENC},
+ {"fields-escaped-by", required_argument,0, (int) OPT_ESC},
+ {"functions",required_argument, 0, 'f'},
+ {"help", no_argument, 0,'?'},
+ {"host", required_argument,0, 'h'},
+ {"lines-terminated-by", required_argument, 0, (int) OPT_LTB},
+ {"lock-tables", no_argument, 0, 'l'},
+ {"no-data", no_argument, 0, 'd'},
+ {"password", optional_argument, 0, 'p'},
+#ifdef __WIN__
+ {"pipe",no_argument,0, 'W'},
+#endif
+ {"port", required_argument,0, 'P'},
+// {"quick", no_argument,0, 'q'},
+ {"quote-names",no_argument,0, 'Q'},
+ {"set-variable",required_argument,0, 'O'},
+ {"socket", required_argument,0, 'S'},
+#include "sslopt-longopts.h"
+#ifndef DONT_ALLOW_USER_CHANGE
+ {"user", required_argument,0, 'u'},
+#endif
+ {"verbose", no_argument,0, 'v'},
+ {"version", no_argument,0, 'V'},
+ {0, 0, 0, 0}
+};
+
+
+/*
+void
+print_table_data(MYSQL_RES *result)
+{
+ String separator(256);
+ MYSQL_ROW cur;
+ MYSQL_FIELD *field;
+ bool *num_flag;
+
+ num_flag=(bool*) my_alloca(sizeof(bool)*mysql_num_fields(result));
+ if (info_flag)
+ {
+ print_field_types(result);
+ mysql_field_seek(result,0);
+ }
+ separator.copy("+",1);
+ while ((field = mysql_fetch_field(result)))
+ {
+ uint length=skip_column_names ? 0 : (uint) strlen(field->name);
+ if (quick)
+ length=max(length,field->length);
+ else
+ length=max(length,field->max_length);
+ if (length < 4 && !IS_NOT_NULL(field->flags))
+ length=4; // Room for "NULL"
+ field->max_length=length+1;
+ separator.fill(separator.length()+length+2,'-');
+ separator.append('+');
+ }
+ tee_puts(separator.c_ptr(), PAGER);
+ if (!skip_column_names)
+ {
+ mysql_field_seek(result,0);
+ (void) tee_fputs("|", PAGER);
+ for (uint off=0; (field = mysql_fetch_field(result)) ; off++)
+ {
+ tee_fprintf(PAGER, " %-*s|",min(field->max_length,MAX_COLUMN_LENGTH),
+ field->name);
+ num_flag[off]= IS_NUM(field->type);
+ }
+ (void) tee_fputs("\n", PAGER);
+ tee_puts(separator.c_ptr(), PAGER);
+ }
+
+ while ((cur = mysql_fetch_row(result)))
+ {
+ (void) tee_fputs("|", PAGER);
+ mysql_field_seek(result,0);
+ for (uint off=0 ; off < mysql_num_fields(result); off++)
+ {
+ const char *str=cur[off] ? cur[off] : "NULL";
+ field = mysql_fetch_field(result);
+ uint length=field->max_length;
+ if (length > MAX_COLUMN_LENGTH)
+ {
+ tee_fputs(str,PAGER); tee_fputs(" |",PAGER);
+ }
+ else
+ tee_fprintf(PAGER, num_flag[off] ? "%*s |" : " %-*s|",
+ length, str);
+ }
+ (void) tee_fputs("\n", PAGER);
+ }
+ tee_puts(separator.c_ptr(), PAGER);
+ my_afree((gptr) num_flag);
+}
+
+void
+print_table_data_html(MYSQL_RES *result)
+{
+ MYSQL_ROW cur;
+ MYSQL_FIELD *field;
+
+ mysql_field_seek(result,0);
+ (void) tee_fputs("<TABLE BORDER=1><TR>", PAGER);
+ if (!skip_column_names)
+ {
+ while((field = mysql_fetch_field(result)))
+ {
+ tee_fprintf(PAGER, "<TH>%s</TH>", (field->name ?
+ (field->name[0] ? field->name :
+ " &nbsp; ") : "NULL"));
+ }
+ (void) tee_fputs("</TR>", PAGER);
+ }
+ while ((cur = mysql_fetch_row(result)))
+ {
+ (void) tee_fputs("<TR>", PAGER);
+ for (uint i=0; i < mysql_num_fields(result); i++)
+ {
+ ulong *lengths=mysql_fetch_lengths(result);
+ (void) tee_fputs("<TD>", PAGER);
+ safe_put_field(cur[i],lengths[i]);
+ (void) tee_fputs("</TD>", PAGER);
+ }
+ (void) tee_fputs("</TR>", PAGER);
+ }
+ (void) tee_fputs("</TABLE>", PAGER);
+}
+
+
+void
+print_table_data_xml(MYSQL_RES *result)
+{
+ MYSQL_ROW cur;
+ MYSQL_FIELD *fields;
+
+ mysql_field_seek(result,0);
+
+ char *statement;
+ statement=(char*) my_malloc(strlen(glob_buffer.ptr())*5+1, MYF(MY_WME));
+ xmlencode(statement, (char*) glob_buffer.ptr());
+
+ (void) my_chomp(strend(statement));
+
+ tee_fprintf(PAGER,"<?xml version=\"1.0\"?>\n\n<resultset statement=\"%s\">", statement);
+
+ my_free(statement,MYF(MY_ALLOW_ZERO_PTR));
+
+ fields = mysql_fetch_fields(result);
+
+ while ((cur = mysql_fetch_row(result)))
+ {
+ (void) tee_fputs("\n <row>\n", PAGER);
+ for (uint i=0; i < mysql_num_fields(result); i++)
+ {
+ char *data;
+ ulong *lengths=mysql_fetch_lengths(result);
+ data=(char*) my_malloc(lengths[i]*5+1, MYF(MY_WME));
+ tee_fprintf(PAGER, "\t<%s>", (fields[i].name ?
+ (fields[i].name[0] ? fields[i].name :
+ " &nbsp; ") : "NULL"));
+ xmlencode(data, cur[i]);
+ safe_put_field(data, strlen(data));
+ tee_fprintf(PAGER, "</%s>\n", (fields[i].name ?
+ (fields[i].name[0] ? fields[i].name :
+ " &nbsp; ") : "NULL"));
+ my_free(data,MYF(MY_ALLOW_ZERO_PTR));
+ }
+ (void) tee_fputs(" </row>\n", PAGER);
+ }
+ (void) tee_fputs("</resultset>\n", PAGER);
+}
+
+
+void
+print_table_data_vertically(MYSQL_RES *result)
+{
+ MYSQL_ROW cur;
+ uint max_length=0;
+ MYSQL_FIELD *field;
+
+ while ((field = mysql_fetch_field(result)))
+ {
+ uint length=(uint) strlen(field->name);
+ if (length > max_length)
+ max_length= length;
+ field->max_length=length;
+ }
+
+ mysql_field_seek(result,0);
+ for (uint row_count=1; (cur= mysql_fetch_row(result)); row_count++)
+ {
+ mysql_field_seek(result,0);
+ tee_fprintf(PAGER,
+ "*************************** %d. row ***************************\n", row_count);
+ for (uint off=0; off < mysql_num_fields(result); off++)
+ {
+ field= mysql_fetch_field(result);
+ tee_fprintf(PAGER, "%*s: ",(int) max_length,field->name);
+ tee_fprintf(PAGER, "%s\n",cur[off] ? (char*) cur[off] : "NULL");
+ }
+ }
+}
+
+
+
+*/
+
+
+
+static my_bool test_if_special_chars(const char *str)
+{
+ for ( ; *str ; str++)
+ if (!isvar(*str) && *str != '$')
+ return 1;
+ return 0;
+} /* test_if_special_chars */
+
+char *quote_name(char *name, char *buff)
+{
+ char *end;
+ DBUG_ENTER("quote_name");
+ if (!opt_quoted && !test_if_special_chars(name))
+ return name;
+ buff[0]=QUOTE_CHAR;
+ *end=strmov(buff+1,name);
+ end[0]=QUOTE_CHAR;
+ end[1]=0;
+ DBUG_RETURN(buff);
+} /* quote_name */
+
+/*
+ * Allow the user to specify field terminator strings like:
+ * "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline)
+ * This is done by doubleing ' and add a end -\ if needed to avoid
+ * syntax errors from the SQL parser.
+ */
+
+char *field_escape(char *to,const char *from,uint length)
+{
+ const char *end;
+ uint end_backslashes=0;
+ DBUG_ENTER("field_escape");
+
+ {
+ *to++= *from;
+ if (*from == '\\')
+ end_backslashes^=1; /* find odd number of backslashes */
+ else {
+ if (*from == '\'' && !end_backslashes)
+ *to++= *from; /* We want a duplicate of "'" for MySQL */
+ end_backslashes=0;
+ }
+ }
+ /* Add missing backslashes if user has specified odd number of backs.*/
+ if (end_backslashes)
+ *to++= '\\';
+ DBUG_RETURN(to);
+} /* field_escape */
+
+void safe_exit(int error)
+{
+ if (!first_error)
+ first_error= error;
+ if (ignore_errors)
+ return;
+ if (sock)
+ mysql_close(sock);
+ exit(error);
+}
+/* safe_exit */
+
+
+/*
+ * ** DBerror -- prints mysql error message and exits the program.
+ */
+void DBerror(MYSQL *mysql, const char *when)
+{
+ DBUG_ENTER("DBerror");
+ my_printf_error(0,"Got error: %d: %s %s", MYF(0),
+ mysql_errno(mysql), mysql_error(mysql), when);
+ safe_exit(EX_MYSQLERR);
+ DBUG_VOID_RETURN;
+} /* DBerror */
+
+void print_version(void)
+{
+ printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,CORBAFS_VERSION,
+ MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
+} /* print_version */
+
+void usage(void)
+{
+ uint i;
+ print_version();
+ puts("By Tõnu Samuel. Some code is partially from other geeks around the world");
+ puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
+ puts("Dumping definition and data mysql database or table");
+ printf("Usage: %s [OPTIONS]\n", my_progname);
+ printf("\n\
+ -#, --debug=... Output debug log. Often this is 'd:t:o,filename`.\n\
+ --character-sets-dir=...\n\
+ Directory where character sets are\n\
+ -?, --help Display this help message and exit.\n\
+ -c, --complete-insert Use complete insert statements.\n\
+ -C, --compress Use compression in server/client protocol.\n\
+ --default-character-set=...\n\
+ Set the default character set\n\
+ -e, --extended-insert Allows utilization of the new, much faster\n\
+ INSERT syntax.\n\
+ --add-locks Add locks around insert statements.\n\
+ --allow-keywords Allow creation of column names that are keywords.\n\
+ --delayed-insert Insert rows with INSERT DELAYED.\n\
+ -f, --force Continue even if we get an sql-error.\n\
+ -h, --host=... Connect to host.\n");
+puts("\
+ -l, --lock-tables Lock all tables for read.\n\
+ -t, --no-create-info Don't write table creation info.\n\
+ -d, --no-data No row information.\n\
+ -O, --set-variable var=option\n\
+ give a variable a value. --help lists variables\n\
+ -p, --password[=...] Password to use when connecting to server.\n\
+ If password is not given it's solicited on the tty.\n");
+#ifdef __WIN__
+ puts("-W, --pipe Use named pipes to connect to server");
+#endif
+ printf("\
+ -P, --port=... Port number to use for connection.\n\
+ -q, --quick Don't buffer query, dump directly to stdout.\n\
+ -S, --socket=... Socket file to use for connection.\n\
+ --tables Overrides option --databases (-B).\n");
+#include "sslopt-usage.h"
+#ifndef DONT_ALLOW_USER_CHANGE
+ printf("\
+ -u, --user=# User for login if not current user.\n");
+#endif
+ printf("\
+ -v, --verbose Print info about the various stages.\n\
+ -V, --version Output version information and exit.\n\
+");
+ print_defaults("my",load_default_groups);
+
+ printf("\nPossible variables for option --set-variable (-O) are:\n");
+ for (i=0 ; changeable_vars[i].name ; i++)
+ printf("%-20s current value: %lu\n",
+ changeable_vars[i].name,
+ (ulong) *changeable_vars[i].varptr);
+} /* usage */
+
+
+
+static int get_options(int *argc,char ***argv)
+{
+ int c,option_index;
+ my_bool tty_password=0;
+ DBUG_ENTER("get_options");
+ load_defaults("my",load_default_groups,argc,argv);
+ set_all_changeable_vars(changeable_vars);
+ while ((c=getopt_long(*argc,*argv,"#::p::h:u:O:P:S:T:EBaAcCdefFlnqtvVw:?Ix",
+ long_options, &option_index)) != EOF)
+ {
+ switch(c) {
+ case 'e':
+ extended_insert=1;
+ break;
+ case OPT_DEFAULT_CHARSET:
+ default_charset= optarg;
+ break;
+ case OPT_CHARSETS_DIR:
+ charsets_dir= optarg;
+ break;
+
+ ignore_errors=1;
+ break;
+ case 'h':
+ my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
+ current_host=my_strdup(optarg,MYF(MY_WME));
+ break;
+#ifndef DONT_ALLOW_USER_CHANGE
+ case 'u':
+ current_user=optarg;
+ break;
+#endif
+ case 'O':
+ if (set_changeable_var(optarg, changeable_vars))
+ {
+ usage();
+ return(1);
+ }
+ break;
+ case 'p':
+ if (optarg)
+ {
+ char *start=optarg;
+ my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
+ opt_password=my_strdup(optarg,MYF(MY_FAE));
+ while (*optarg) *optarg++= 'x'; /* Destroy argument */
+ if (*start)
+ start[1]=0; /* Cut length of argument */
+ } else
+ tty_password=1;
+ break;
+ case 'P':
+ opt_mysql_port= (unsigned int) atoi(optarg);
+ break;
+ case 'S':
+ opt_mysql_unix_port= optarg;
+ break;
+ case 'W':
+#ifdef __WIN__
+ opt_mysql_unix_port=MYSQL_NAMEDPIPE;
+#endif
+ break;
+ case 'T':
+ path= optarg;
+ break;
+ case '#':
+ DBUG_PUSH(optarg ? optarg : "d:t:o");
+ break;
+ case 'C':
+ opt_compress=1;
+ break;
+ case 'l': lock_tables=1; break;
+ case 'Q': opt_quoted=1; break;
+ case 'v': verbose=1; break;
+ case 'V': print_version(); exit(0);
+ default:
+ fprintf(stderr,"%s: Illegal option character '%c'\n",my_progname,opterr);
+ /* Fall throught */
+ case 'I':
+ case '?':
+ usage();
+ exit(0);
+ case (int) OPT_FTB:
+ fields_terminated= optarg;
+ break;
+ case (int) OPT_LTB:
+ lines_terminated= optarg;
+ break;
+ case (int) OPT_ENC:
+ enclosed= optarg;
+ break;
+ case (int) OPT_O_ENC:
+ opt_enclosed= optarg;
+ break;
+ case (int) OPT_ESC:
+ escaped= optarg;
+ break;
+ case (int) OPT_LOCKS:
+ opt_lock=1;
+ break;
+ case (int) OPT_OPTIMIZE:
+ extended_insert=opt_lock=lock_tables=1;
+ break;
+ case (int) OPT_DELAYED:
+ opt_delayed=1;
+ break;
+#include "sslopt-case.h"
+ }
+ }
+ if (opt_delayed)
+ opt_lock=0; /* Can't have lock with delayed */
+ if (!path && (enclosed || opt_enclosed || escaped || lines_terminated ||
+ fields_terminated))
+ {
+ fprintf(stderr, "%s: You must use option --tab with --fields-...\n", my_progname);
+ return(1);
+ }
+
+ if (enclosed && opt_enclosed)
+ {
+ fprintf(stderr, "%s: You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n", my_progname);
+ return(1);
+ }
+ if (default_charset)
+ {
+ if (set_default_charset_by_name(default_charset, MYF(MY_WME)))
+ exit(1);
+ }
+ (*argc)-=optind;
+ (*argv)+=optind;
+ if (tty_password)
+ opt_password=get_tty_password(NullS);
+ DBUG_RETURN(0);
+} /* get_options */
+
+
+/*** epv structures ***/
+
+static PortableServer_ServantBase__epv impl_Inode_base_epv = {
+ NULL, /* _private data */
+ NULL, /* finalize routine */
+ NULL, /* default_POA routine */
+};
+static POA_CorbaFS_Inode__epv impl_Inode_epv = {
+ NULL, /* _private */
+ (gpointer) & impl_Inode_getStatus,
+ (gpointer) & impl_Inode_readpage,
+ (gpointer) & impl_Inode_release,
+
+};
+static PortableServer_ServantBase__epv impl_FileSystem_base_epv = {
+ NULL, /* _private data */
+ NULL, /* finalize routine */
+ NULL, /* default_POA routine */
+};
+static POA_CorbaFS_FileSystem__epv impl_FileSystem_epv = {
+ NULL, /* _private */
+ (gpointer) & impl_FileSystem_getInode,
+ (gpointer) & impl_FileSystem_readdir,
+ (gpointer) & impl_FileSystem_readlink,
+};
+
+/*** vepv structures ***/
+
+static POA_CorbaFS_Inode__vepv impl_Inode_vepv = {
+ &impl_Inode_base_epv,
+ &impl_Inode_epv,
+};
+static POA_CorbaFS_FileSystem__vepv impl_FileSystem_vepv = {
+ &impl_FileSystem_base_epv,
+ &impl_FileSystem_epv,
+};
+
+/*** Stub implementations ***/
+
+static CorbaFS_Inode
+impl_Inode__create(PortableServer_POA poa, CORBA_Environment * ev)
+{
+ CorbaFS_Inode retval;
+ impl_POA_CorbaFS_Inode *newservant;
+ PortableServer_ObjectId *objid;
+
+ DBUG_ENTER("impl_Inode__create");
+ newservant = g_new0(impl_POA_CorbaFS_Inode, 1);
+ newservant->servant.vepv = &impl_Inode_vepv;
+ newservant->poa = poa;
+ POA_CorbaFS_Inode__init((PortableServer_Servant) newservant, ev);
+ objid = PortableServer_POA_activate_object(poa, newservant, ev);
+ CORBA_free(objid);
+ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev);
+
+ DBUG_RETURN(retval);
+}
+
+static void
+impl_Inode__destroy(impl_POA_CorbaFS_Inode * servant,
+ CORBA_Environment * ev)
+{
+ PortableServer_ObjectId *objid;
+
+ DBUG_ENTER("impl_Inode__destroy");
+ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev);
+ PortableServer_POA_deactivate_object(servant->poa, objid, ev);
+ CORBA_free(objid);
+
+ POA_CorbaFS_Inode__fini((PortableServer_Servant) servant, ev);
+ g_free(servant);
+ DBUG_VOID_RETURN;
+}
+
+static void
+impl_Inode_getStatus(impl_POA_CorbaFS_Inode * servant,
+ CORBA_unsigned_short * mode,
+ CORBA_unsigned_long * uid,
+ CORBA_unsigned_long * gid,
+ CORBA_unsigned_long * size,
+ CORBA_unsigned_long * inodeNum,
+ CORBA_unsigned_short * numLinks,
+ CORBA_long * atime,
+ CORBA_long * mtime,
+ CORBA_long * ctime, CORBA_Environment * ev)
+{
+ struct stat buf;
+ char
+ server[BUFLEN],
+ database[BUFLEN],
+ table[BUFLEN],
+ key[BUFLEN],
+ field[BUFLEN],
+ value[BUFLEN];
+
+ struct func_st *func;
+
+ DBUG_ENTER("impl_Inode_getStatus");
+ DBUG_PRINT("enter",("path: '%s', mode: '%o', uid: '%d', gid: '%d', size: '%d',
+ inodeNum: '%d', numLinks: '%d', atime: '%d',mtime: '%d', ctime: '%d'",
+ servant->path, mode, uid, gid, size, inodeNum, numLinks, atime, mtime, ctime));
+ DBUG_PRINT("info",("func: %x",&func));
+ if(parse(servant->path, server, database, table, field, value, &func)>0)
+ {
+ DBUG_PRINT("info",("ENOENT"));
+ *mode=0;
+ } else if (func != NULL){
+ DBUG_PRINT("info",("func: %x",&func));
+ DBUG_PRINT("info",("Argument is function at %x, returning S_IFREG",func));
+ *mode = S_IFREG; // File
+ } else if (*field){
+ DBUG_PRINT("info",("Argument is file, returning S_IFREG"));
+ *mode = S_IFREG; // File
+ } else {
+ DBUG_PRINT("info",("Argument is directory, returning S_IFDIR"));
+ *mode = S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH ; // Dir
+ }
+
+ *mode |= S_IRUSR | S_IRGRP | S_IROTH;
+ *uid = 0;
+ *gid = 0;
+ *size = 4096;
+ *inodeNum = servant->inodeNum;
+ *numLinks = 1;
+ *atime = 3;
+ *mtime = 2;
+ *ctime = 1;
+
+// lstat(servant->path, &buf);
+// *mode = buf.st_mode;
+/* *uid = buf.st_uid;
+ *gid = buf.st_gid;
+ *size = buf.st_size;
+ *inodeNum = buf.st_ino;
+ *numLinks = buf.st_nlink;
+ *atime = buf.st_atime;
+ *mtime = buf.st_mtime;
+ *ctime = buf.st_ctime;*/
+ DBUG_VOID_RETURN;
+}
+
+static void
+impl_Inode_readpage(impl_POA_CorbaFS_Inode * servant,
+ CorbaFS_Buffer ** buffer,
+ CORBA_long size,
+ CORBA_long offset, CORBA_Environment * ev)
+{
+ int type;
+ int fd = -1, c = 0;
+ int res;
+ char
+ server[BUFLEN],
+ database[BUFLEN],
+ table[BUFLEN],
+ key[BUFLEN],
+ field[BUFLEN],
+ value[BUFLEN];
+ struct func_st *func;
+
+ DBUG_ENTER("impl_Inode_readpage");
+ DBUG_PRINT("enter",("path: '%s'", servant->path));
+ *buffer = CorbaFS_Buffer__alloc();
+ (*buffer)->_maximum = size;
+ (*buffer)->_buffer = CORBA_octet_allocbuf(size);
+ printf("requested to read %d bytes\n",size);
+ memset((*buffer)->_buffer, size, 0);
+ type = parse(servant->path, server, database, table, field, value, &func);
+ if (func != NULL)
+ res=db_function((*buffer)->_buffer, server, database, table, field, value, servant->path, func);
+ else
+ res=db_show_field((*buffer)->_buffer, database, table, field, path, value);
+ if(res>0)
+ (*buffer)->_length = strlen((*buffer)->_buffer);
+ else
+ (*buffer)->_length = 0;
+/*
+ fd = open(servant->path, O_RDONLY);
+ printf("Inode_readpage : fd = %d\n", fd);
+ lseek(fd, offset, SEEK_SET);
+ c = read(fd, (*buffer)->_buffer, size);
+ printf("Inode_readpage : read %d bytes\n", c);
+ (*buffer)->_length = c;
+ close(fd);
+*/
+ DBUG_VOID_RETURN;
+}
+
+static void
+impl_Inode_release(impl_POA_CorbaFS_Inode * servant,
+ CORBA_Environment * ev)
+{
+ DBUG_ENTER("impl_Inode_readpage");
+ DBUG_PRINT("enter",("path: '%s'", servant->path));
+ DBUG_VOID_RETURN;
+}
+
+/*
+ * This function is called when we get mounted
+ */
+CorbaFS_FileSystem
+impl_FileSystem__create(PortableServer_POA poa,
+ CORBA_Environment * ev)
+{
+ CorbaFS_FileSystem retval;
+ impl_POA_CorbaFS_FileSystem *newservant;
+ PortableServer_ObjectId *objid;
+
+ DBUG_ENTER("impl_FileSystem__create");
+ newservant = g_new0(impl_POA_CorbaFS_FileSystem, 1);
+ newservant->servant.vepv = &impl_FileSystem_vepv;
+ newservant->poa = poa;
+ POA_CorbaFS_FileSystem__init((PortableServer_Servant) newservant, ev);
+ objid = PortableServer_POA_activate_object(poa, newservant, ev);
+ CORBA_free(objid);
+ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev);
+
+ DBUG_RETURN(retval);
+}
+
+/*
+ * This function is called when we get unmounted
+ */
+static void
+impl_FileSystem__destroy(impl_POA_CorbaFS_FileSystem * servant,
+ CORBA_Environment * ev)
+{
+ PortableServer_ObjectId *objid;
+ DBUG_ENTER("impl_FileSystem__destroy");
+
+ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev);
+ PortableServer_POA_deactivate_object(servant->poa, objid, ev);
+ CORBA_free(objid);
+
+ POA_CorbaFS_FileSystem__fini((PortableServer_Servant) servant, ev);
+ g_free(servant);
+ DBUG_VOID_RETURN;
+}
+
+static CorbaFS_Inode
+impl_FileSystem_getInode(impl_POA_CorbaFS_FileSystem * servant,
+ CORBA_char * path, CORBA_Environment * ev)
+{
+ CorbaFS_Inode retval;
+ impl_POA_CorbaFS_Inode *inode;
+ char
+ database[BUFLEN],
+ table[BUFLEN],
+ key[BUFLEN],
+ field[BUFLEN];
+ char buffer[MAXDIRS][BUFLEN];
+ int c;
+
+ DBUG_ENTER("impl_FileSystem_getInode");
+ DBUG_PRINT("enter",("path: '%s'", path));
+
+ //FIXME: We should verify the existense of file/dir here
+ //
+ retval = impl_Inode__create(servant->poa, ev);
+ inode = PortableServer_POA_reference_to_servant( servant->poa, retval, ev );
+ inode->path = CORBA_string_dup(path);
+ //FIXME: inodeNum Generation goes here
+ //
+ inode->inodeNum= inodeNum++;
+#if 0
+ inode->mode = 0040777; /* world-readable directory */
+ inode->uid = 0;
+ inode->gid = 0;
+ inode->size = 4096;
+ inode->inodeNum = inodeNum++;
+ inode->numLinks = 1;
+ inode->atime = 0;
+ inode->mtime = 100;
+ inode->ctime = 10000;
+#endif
+ DBUG_RETURN(retval);
+}
+
+
+static CorbaFS_DirEntSeq *
+impl_FileSystem_readdir(impl_POA_CorbaFS_FileSystem * servant,
+ CORBA_char * path, CORBA_Environment * ev)
+{
+ CorbaFS_DirEntSeq *retval;
+ CorbaFS_dirent *dirent;
+
+ struct func_st *func;
+ int c, c2,i;
+ char
+ server[BUFLEN],
+ table[BUFLEN],
+ field[BUFLEN],
+ value[BUFLEN],
+ buffer[MAXDIRS][BUFLEN],
+ buffer2[MAXDIRS][BUFLEN],
+ database[BUFLEN];
+
+ DBUG_ENTER("impl_FileSystem_readdir");
+ DBUG_PRINT("enter",("path: '%s'", path));
+ retval = CorbaFS_DirEntSeq__alloc();
+ retval->_maximum = 0;
+ retval->_length = 0;
+
+ parse(path, server, database, table, field, value, &func);
+ if (func != NULL) {
+ c2 = db_function((char *)buffer, server, database, table, field, value, path, func);
+ } else if(!*server) {
+ c2 = db_show_servers(buffer2,MAXDIRS);
+ c = show_functions((char *)buffer, ROOT_FUNCTION);
+ } else if(!*database) {
+ c2 = db_show_databases(buffer2,MAXDIRS);
+ c = show_functions((char *)buffer, SERVER_FUNCTION);
+ } else if(!*table){
+ c2 = db_show_tables(buffer2, database);
+ c = show_functions((char *)buffer, DATABASE_FUNCTION);
+ } else if(!*field){
+ c2 = db_show_primary_keys(buffer2, database,table);
+ if(c2>=0) {
+ c = show_functions((char *)buffer, TABLE_FUNCTION);
+ }
+ } else {
+ c2 = db_show_fields(buffer2, database, table, field);
+ c = show_functions((char *)buffer, FIELD_FUNCTION);
+ c = show_functions((char *)buffer, KEY_FUNCTION);
+ }
+ if(c2 < 0)
+ c=c2=0; // Error occured in database routines
+
+ /* Allocate space to hold all found entries plus "." and ".." */
+ retval->_maximum = c + c2 + 2;
+ retval->_buffer = CORBA_sequence_CorbaFS_dirent_allocbuf(retval->_maximum) ;
+ dirent = retval->_buffer;
+
+ i = 0;
+ while (i < c) {
+ long inode = 123L;
+ dirent[i].inode = inode;
+ dirent[i].name = CORBA_string_dup(buffer[i]);
+ i++;
+ }
+ i = 0;
+ while (i < c2) {
+ long inode = 123L;
+ dirent[c+i].inode = inode;
+ dirent[c+i].name = CORBA_string_dup(buffer2[i]);
+ i++;
+ }
+ dirent[c+i].inode = 123L;
+ dirent[c+i].name = CORBA_string_dup(".");
+ i++;
+ dirent[c+i].inode = 123L;
+ dirent[c+i].name = CORBA_string_dup("..");
+
+ retval->_length = retval->_maximum;
+ DBUG_RETURN(retval);
+}
+
+static CORBA_char *
+impl_FileSystem_readlink(impl_POA_CorbaFS_FileSystem * servant,
+ CORBA_char * filename,
+ CORBA_Environment * ev)
+{
+ CORBA_char *retval = CORBA_OBJECT_NIL;
+ char tmp[MAXPATHLEN + 1];
+ int len;
+
+ DBUG_ENTER("impl_FileSystem_readlink");
+ DBUG_PRINT("enter",("path: '%s'", filename));
+
+/* len = readlink(filename, tmp, MAXPATHLEN);
+ if (len != -1)
+ {
+ tmp[len] = '\0';
+ retval = CORBA_string_dup(tmp);
+ }
+
+ printf("%s\n", retval);
+ */
+ DBUG_RETURN(retval);
+}
+
+int fix_filenames(char *buf)
+{
+ int i;
+ for(i=0; i<strlen(buf);i++)
+ if(buf[i]=='/')
+ buf[i]='_';
+}
+
+int main(int argc, char *argv[]) {
+ CorbaFS_FileSystem fs;
+ impl_POA_CorbaFS_FileSystem *fs_impl;
+ FILE *f;
+ PortableServer_POAManager pm;
+
+ DBUG_ENTER("main");
+ DBUG_PROCESS(argv[0]);
+ ev = g_new0(CORBA_Environment,1);
+ CORBA_exception_init(ev);
+ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev);
+ MY_INIT(argv[0]);
+
+ /*
+ ** Check out the args
+ */
+ if (get_options(&argc, &argv))
+ {
+ my_end(0);
+ exit(EX_USAGE);
+ }
+ if (db_connect(current_host, current_user, opt_password))
+ exit(EX_MYSQLERR);
+ fptr = db_load_functions();
+ db_load_formats();
+ poa = (PortableServer_POA)
+ CORBA_ORB_resolve_initial_references(orb, "RootPOA", ev);
+ fs = impl_FileSystem__create(poa, ev);
+
+ pm = PortableServer_POA__get_the_POAManager(poa, ev);
+ PortableServer_POAManager_activate(pm, ev);
+
+ fs_impl = PortableServer_POA_reference_to_servant( poa, fs, ev );
+ objid = PortableServer_POA_servant_to_id( poa, fs_impl, ev );
+ printf("CorbaFS-server:\n%s\n", CORBA_ORB_object_to_string(orb, fs, ev));
+ f=fopen("/tmp/mysqlcorbafs.ior","w");
+ fputs(CORBA_ORB_object_to_string(orb, fs, ev),f);
+ fclose(f);
+ CORBA_ORB_run(orb, ev);
+ db_disconnect(current_host);
+
+ return 0;
+}
+
diff --git a/fs/mysqlcorbafs.h b/fs/mysqlcorbafs.h
new file mode 100644
index 00000000000..4fd76598d7f
--- /dev/null
+++ b/fs/mysqlcorbafs.h
@@ -0,0 +1,159 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+ *
+ * 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 "CorbaFS.h"
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include "mysql.h"
+
+#define QUOTE_CHAR '`'
+/* Exit codes */
+
+#define EX_USAGE 1
+#define EX_MYSQLERR 2
+#define EX_CONSCHECK 3
+#define EX_EOM 4
+
+#define CORBAFS_VERSION "0.01"
+
+typedef struct
+{
+ POA_CorbaFS_Inode servant;
+ PortableServer_POA poa;
+
+ CORBA_char *path;
+ CORBA_unsigned_long inodeNum;
+#if 0
+ CORBA_unsigned_short mode;
+ CORBA_unsigned_long uid;
+ CORBA_unsigned_long gid;
+ CORBA_unsigned_long size;
+ CORBA_unsigned_short numLinks;
+ CORBA_long atime;
+ CORBA_long mtime;
+ CORBA_long ctime;
+#endif
+}
+impl_POA_CorbaFS_Inode;
+
+typedef struct
+{
+ POA_CorbaFS_FileSystem servant;
+ PortableServer_POA poa;
+
+}
+impl_POA_CorbaFS_FileSystem;
+
+/*** Implementation stub prototypes ***/
+CorbaFS_FileSystem
+impl_FileSystem__create(PortableServer_POA poa, CORBA_Environment * ev);
+
+static void
+impl_Inode__destroy(impl_POA_CorbaFS_Inode * servant,
+ CORBA_Environment * ev);
+static void
+impl_Inode_getStatus(impl_POA_CorbaFS_Inode * servant,
+ CORBA_unsigned_short * mode,
+ CORBA_unsigned_long * uid,
+ CORBA_unsigned_long * gid,
+ CORBA_unsigned_long * size,
+ CORBA_unsigned_long * inodeNum,
+ CORBA_unsigned_short * numLinks,
+ CORBA_long * atime,
+ CORBA_long * mtime,
+ CORBA_long * ctime, CORBA_Environment * ev);
+
+static void
+impl_Inode_readpage(impl_POA_CorbaFS_Inode * servant,
+ CorbaFS_Buffer ** buffer,
+ CORBA_long size,
+ CORBA_long offset, CORBA_Environment * ev);
+
+static void
+impl_Inode_release(impl_POA_CorbaFS_Inode * servant,
+ CORBA_Environment * ev);
+
+static void impl_FileSystem__destroy(impl_POA_CorbaFS_FileSystem *
+ servant, CORBA_Environment * ev);
+
+static CorbaFS_Inode
+impl_FileSystem_getInode(impl_POA_CorbaFS_FileSystem * servant,
+ CORBA_char * path, CORBA_Environment * ev);
+
+static CorbaFS_DirEntSeq *
+impl_FileSystem_readdir(impl_POA_CorbaFS_FileSystem * servant,
+ CORBA_char * path,
+ CORBA_Environment * ev);
+
+static CORBA_char *
+impl_FileSystem_readlink(impl_POA_CorbaFS_FileSystem * servant,
+ CORBA_char * filename,
+ CORBA_Environment * ev);
+
+static my_bool verbose,opt_compress;
+static uint opt_mysql_port=0;
+static my_string opt_mysql_unix_port=0;
+static int first_error=0;
+static MYSQL connection, *sock=0;
+
+extern uint opt_mysql_port;
+extern my_string opt_mysql_unix_port,host,user,password;
+
+
+
+static struct format {
+ char *tablestart;
+
+ char *headerrowstart;
+ char *headercellstart;
+ char *headercellseparator;
+ char *headercellend;
+ char *headerrowend;
+ int headerformat; /* 0 - simple, 1 - left padded, 2 - right padded */
+
+ char *contentrowstart;
+ char *contentcellstart;
+ char *contentcellseparator;
+ char *contentcellend;
+ char *contentrowend;
+ int contentformat;
+
+ char *footerrowstart;
+ char *footercellstart;
+ char *footercellseparator;
+ char *footercellend;
+ char *footerrowend;
+ int footerformat;
+
+ char *tableend;
+
+ char *leftuppercorner;
+ char *rightuppercorner;
+ char *leftdowncorner;
+ char *rightdowncorner;
+ char *leftcross;
+ char *rightcross;
+ char *topcross;
+ char *middlecross;
+ char *bottomcross;
+
+
+} Human, HTML, CSF, XML;
+
+
diff --git a/fs/mysqlcorbafs_test.c b/fs/mysqlcorbafs_test.c
new file mode 100644
index 00000000000..81b76702303
--- /dev/null
+++ b/fs/mysqlcorbafs_test.c
@@ -0,0 +1,92 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <orb/orbit.h>
+
+#include "CorbaFS.h"
+
+CorbaFS_FileSystem fs;
+
+int
+main (int argc, char *argv[])
+{
+ CORBA_Environment ev;
+ CORBA_ORB orb;
+ CorbaFS_Inode inode;
+ CorbaFS_Buffer *buffer;
+ CorbaFS_DirEntSeq *dirents;
+ CorbaFS_dirent *dirent;
+
+ CORBA_unsigned_short mode;
+ CORBA_unsigned_long uid;
+ CORBA_unsigned_long gid;
+ CORBA_unsigned_long size;
+ CORBA_unsigned_long inodeNum;
+ CORBA_unsigned_short numLinks;
+ CORBA_long atime;
+ CORBA_long mtime;
+ CORBA_long ctime;
+
+ int i;
+
+ int niters = 10;
+
+ CORBA_exception_init(&ev);
+ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", &ev);
+
+ if(argc < 2)
+ {
+ printf("Need a binding ID thing as argv[1]\n");
+ return 1;
+ }
+
+
+ fs = CORBA_ORB_string_to_object(orb, argv[1], &ev);
+ if (!fs) {
+ printf("Cannot bind to %s\n", argv[1]);
+ return 1;
+ }
+
+ if (argc >= 3)
+ inode = CorbaFS_FileSystem_getInode(fs, argv[2], &ev);
+ else
+ inode = CorbaFS_FileSystem_getInode(fs, "/proc/cpuinfo", &ev);
+
+ if (!inode)
+ {
+ printf("Cannot get inode\n");
+ }
+
+ CorbaFS_Inode_getStatus(inode,
+ &mode,
+ &uid,
+ &gid,
+ &size,
+ &inodeNum,
+ &numLinks,
+ &atime,
+ &mtime,
+ &ctime,
+ &ev);
+
+ printf("inode = %x\n", inode);
+ CorbaFS_Inode_readpage(inode, &buffer, 100000, 100, &ev);
+ printf("readpage got %d bytes\n", buffer->_length);
+ printf("readpage returned : %s\n", buffer->_buffer);
+
+ if (argc >= 3)
+ dirents = CorbaFS_FileSystem_readdir(fs, argv[2], &ev);
+ else
+ dirents = CorbaFS_FileSystem_readdir(fs, "/", &ev);
+
+ dirent = dirents->_buffer;
+ for (i = 0; i < dirents->_length; i++)
+ {
+ printf("%d = %s\n", dirent->inode, dirent->name);
+ dirent++;
+ }
+
+ CORBA_Object_release(fs, &ev);
+ CORBA_Object_release((CORBA_Object)orb, &ev);
+
+ return 0;
+}
diff --git a/fs/mysqlfsck b/fs/mysqlfsck
new file mode 100755
index 00000000000..7b4e049b1e3
--- /dev/null
+++ b/fs/mysqlfsck
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+mountpoint=$*
+
+if [#($mountpoint) -eq "0"];
+then
+ exit;
+fi
+
+
+
diff --git a/include/ft_global.h b/include/ft_global.h
index 3937bd87c7f..bca13271f34 100644
--- a/include/ft_global.h
+++ b/include/ft_global.h
@@ -47,9 +47,10 @@ void ft_free_stopwords(void);
FT_DOCLIST * ft_init_search(void *, uint, byte *, uint, my_bool);
int ft_read_next(FT_DOCLIST *, char *);
-#define ft_close_search(handler) my_free(((gptr)(handler)),MYF(0))
-#define ft_get_relevance(handler) ((handler)->doc[(handler)->curdoc].weight)
-#define ft_reinit_search(handler) (((FT_DOCLIST *)(handler))->curdoc=-1)
+#define ft_close_search(handler) my_free(((gptr)(handler)),MYF(0))
+#define ft_get_relevance(handler) ((handler)->doc[(handler)->curdoc].weight)
+#define ft_get_docid(handler) ((handler)->doc[(handler)->curdoc].dpos)
+#define ft_reinit_search(handler) (((FT_DOCLIST *)(handler))->curdoc=-1)
#ifdef __cplusplus
}
diff --git a/include/my_pthread.h b/include/my_pthread.h
index 652bdd205c0..487e8d07e5e 100644
--- a/include/my_pthread.h
+++ b/include/my_pthread.h
@@ -25,6 +25,10 @@
#define ETIME ETIMEDOUT /* For FreeBSD */
#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#if defined(__WIN__)
typedef CRITICAL_SECTION pthread_mutex_t;
@@ -576,4 +580,8 @@ extern struct st_my_thread_var *_my_thread_var(void) __attribute__ ((const));
#endif /* SAFE_STATISTICS */
#endif /* HAVE_ATOMIC_ADD */
#endif /* thread_safe_increment */
+
+#ifdef __cplusplus
+}
+#endif
#endif /* _my_ptread_h */
diff --git a/include/myisam.h b/include/myisam.h
index c4e26c5fb22..8139faaa14e 100644
--- a/include/myisam.h
+++ b/include/myisam.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
+
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
-
+
This library 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
Library General Public License for more details.
-
+
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
@@ -219,7 +219,7 @@ extern my_off_t mi_position(struct st_myisam_info *file);
extern int mi_status(struct st_myisam_info *info, MI_ISAMINFO *x, uint flag);
extern int mi_lock_database(struct st_myisam_info *file,int lock_type);
extern int mi_create(const char *name,uint keys,MI_KEYDEF *keydef,
- uint columns, MI_COLUMNDEF *columndef,
+ uint columns, MI_COLUMNDEF *columndef,
uint uniques, MI_UNIQUEDEF *uniquedef,
MI_CREATE_INFO *create_info, uint flags);
extern int mi_delete_table(const char *name);
@@ -295,17 +295,17 @@ typedef struct st_sort_info {
struct st_mi_check_param *param;
enum data_file_type new_data_file_type;
SORT_KEY_BLOCKS *key_block,*key_block_end;
- uint key,find_length;
+ uint key,find_length,real_key_length;
my_off_t pos,max_pos,filepos,start_recpos,filelength,dupp,buff_length;
ha_rows max_records;
ulonglong unique[MI_MAX_KEY_SEG+1];
my_bool fix_datafile;
char *record,*buff;
+ void *wordlist, *wordptr;
MI_KEYDEF *keyinfo;
MI_KEYSEG *keyseg;
} SORT_INFO;
-
typedef struct st_mi_check_param
{
ulonglong auto_increment_value;
diff --git a/include/mysql_com.h b/include/mysql_com.h
index 8a5eea1024c..15a14a508e5 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -165,7 +165,7 @@ int my_net_write(NET *net,const char *packet,unsigned long len);
int net_write_command(NET *net,unsigned char command,const char *packet,
unsigned long len);
int net_real_write(NET *net,const char *packet,unsigned long len);
-unsigned int my_net_read(NET *net);
+unsigned long my_net_read(NET *net);
struct rand_struct {
unsigned long seed1,seed2,max_value;
diff --git a/include/violite.h b/include/violite.h
index 49df6994d53..7b14dae3610 100644
--- a/include/violite.h
+++ b/include/violite.h
@@ -52,6 +52,10 @@ Vio* vio_new_win32pipe(HANDLE hPipe);
#endif
void vio_delete(Vio* vio);
+#ifdef EMBEDDED_LIBRARY
+void vio_reset(Vio *vio);
+#endif
+
/*
* vio_read and vio_write should have the same semantics
* as read(2) and write(2).
diff --git a/libmysql/net.c b/libmysql/net.c
index f60a2a20ce0..44c082c1693 100644
--- a/libmysql/net.c
+++ b/libmysql/net.c
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
+
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
-
+
This library 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
Library General Public License for more details.
-
+
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
@@ -22,6 +22,11 @@
** 3 byte length & 1 byte package-number.
*/
+#ifdef EMBEDDED_LIBRARY
+#define net_read_timeout net_read_timeout1
+#define net_write_timeout net_write_timeout1
+#endif
+
#ifdef __WIN__
#include <winsock.h>
#endif
@@ -35,13 +40,21 @@
#include <errno.h>
#include <sys/types.h>
#include <violite.h>
+#include <assert.h>
#ifdef MYSQL_SERVER
ulong max_allowed_packet=65536;
extern ulong net_read_timeout,net_write_timeout;
extern uint test_flags;
#else
-ulong max_allowed_packet=16*1024*1024L;
+
+/*
+** Give error if a too big packet is found
+** The server can change this with the -O switch, but because the client
+** can't normally do this the client should have a bigger max_allowed_packet.
+*/
+
+ulong max_allowed_packet=~0L;
ulong net_read_timeout= NET_READ_TIMEOUT;
ulong net_write_timeout= NET_WRITE_TIMEOUT;
#endif
@@ -74,7 +87,7 @@ typedef my_bool ALARM;
#define thr_alarm_in_use(A) (*(A))
#define thr_end_alarm(A)
#define thr_alarm(A,B,C) local_thr_alarm((A),(B),(C))
-static inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __attribute__((unused)))
+inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __attribute__((unused)))
{
*A=1;
return 0;
@@ -84,28 +97,25 @@ static inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM
#endif
#ifdef MYSQL_SERVER
-extern ulong bytes_sent, bytes_received;
+extern ulong bytes_sent, bytes_received;
extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
#else
#undef statistic_add
#define statistic_add(A,B,C)
#endif
-/*
-** Give error if a too big packet is found
-** The server can change this with the -O switch, but because the client
-** can't normally do this the client should have a bigger max-buffer.
-*/
-
#define TEST_BLOCKING 8
-static int net_write_buff(NET *net,const char *packet,uint len);
+static int net_write_buff(NET *net,const char *packet,ulong len);
+#define MAX_THREE_BYTES 255L*255L*255L
/* Init with packet info */
int my_net_init(NET *net, Vio* vio)
{
- if (!(net->buff=(uchar*) my_malloc(net_buffer_length,MYF(MY_WME))))
+ if (!(net->buff=(uchar*) my_malloc(net_buffer_length+
+ NET_HEADER_SIZE + COMP_HEADER_SIZE,
+ MYF(MY_WME))))
return 1;
if (net_buffer_length > max_allowed_packet)
max_allowed_packet=net_buffer_length;
@@ -152,8 +162,12 @@ static my_bool net_realloc(NET *net, ulong length)
net->last_errno=ER_NET_PACKET_TOO_LARGE;
return 1;
}
- pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
- if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length, MYF(MY_WME))))
+ pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
+ /* We must allocate some extra bytes for the end 0 and to be able to
+ read big compressed blocks */
+ if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length +
+ NET_HEADER_SIZE + COMP_HEADER_SIZE,
+ MYF(MY_WME))))
{
net->error=1;
#ifdef MYSQL_SERVER
@@ -209,18 +223,34 @@ int net_flush(NET *net)
** Write something to server/client buffer
*****************************************************************************/
-
/*
** Write a logical packet with packet header
** Format: Packet length (3 bytes), packet number(1 byte)
** When compression is used a 3 byte compression length is added
-** NOTE: If compression is used the original package is destroyed!
+** NOTE: If compression is used the original package is modified!
*/
int
my_net_write(NET *net,const char *packet,ulong len)
{
uchar buff[NET_HEADER_SIZE];
+ /*
+ Big packets are handled by splitting them in packets of MAX_THREE_BYTES
+ length. The last packet is always a packet that is < MAX_THREE_BYTES.
+ (The last packet may even have a lengt of 0)
+ */
+ while (len >= MAX_THREE_BYTES)
+ {
+ const ulong z_size = MAX_THREE_BYTES;
+ int3store(buff, z_size);
+ buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
+ if (net_write_buff(net, (char*) buff, NET_HEADER_SIZE) ||
+ net_write_buff(net, packet, z_size))
+ return 1;
+ packet += z_size;
+ len-= z_size;
+ }
+ /* Write last packet */
int3store(buff,len);
buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE))
@@ -228,23 +258,54 @@ my_net_write(NET *net,const char *packet,ulong len)
return net_write_buff(net,packet,len);
}
+/*
+ Send a command to the server.
+ As the command is part of the first data packet, we have to do some data
+ juggling to put the command in there, without having to create a new
+ packet.
+ This function will split big packets into sub-packets if needed.
+ (Each sub packet can only be 2^24 bytes)
+*/
+
int
net_write_command(NET *net,uchar command,const char *packet,ulong len)
{
- uchar buff[NET_HEADER_SIZE+1];
uint length=len+1; /* 1 extra byte for command */
+ uchar buff[NET_HEADER_SIZE+1];
+ uint header_size=NET_HEADER_SIZE+1;
+ buff[4]=command; /* For first packet */
+ if (length >= MAX_THREE_BYTES)
+ {
+ /* Take into account that we have the command in the first header */
+ len= MAX_THREE_BYTES -1;
+ do
+ {
+ int3store(buff, MAX_THREE_BYTES);
+ buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
+ if (net_write_buff(net,(char*) buff, header_size) ||
+ net_write_buff(net,packet,len))
+ return 1;
+ packet+= len;
+ length-= MAX_THREE_BYTES;
+ len=MAX_THREE_BYTES;
+ header_size=NET_HEADER_SIZE;
+ } while (length >= MAX_THREE_BYTES);
+ len=length; /* Data left to be written */
+ }
int3store(buff,length);
buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
- buff[4]=command;
- if (net_write_buff(net,(char*) buff,5))
- return 1;
- return test(net_write_buff(net,packet,len) || net_flush(net));
+ return test(net_write_buff(net,(char*) buff,header_size) ||
+ net_write_buff(net,packet,len) || net_flush(net));
}
+/*
+ Caching the data in a local buffer before sending it.
+ One can force the buffer to be flushed with 'net_flush'.
+*/
static int
-net_write_buff(NET *net,const char *packet,uint len)
+net_write_buff(NET *net,const char *packet,ulong len)
{
uint left_length=(uint) (net->buff_end - net->write_pos);
@@ -263,7 +324,11 @@ net_write_buff(NET *net,const char *packet,uint len)
return 0;
}
-/* Read and write using timeouts */
+
+/*
+ Read and write one packet using timeouts.
+ If needed, the packet is compressed before sending.
+*/
int
net_real_write(NET *net,const char *packet,ulong len)
@@ -271,7 +336,7 @@ net_real_write(NET *net,const char *packet,ulong len)
int length;
char *pos,*end;
thr_alarm_t alarmed;
-#if !defined(__WIN__) && !defined(__EMX__)
+#if !defined(__WIN__)
ALARM alarm_buff;
#endif
uint retry_count=0;
@@ -427,19 +492,25 @@ static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed)
{
my_bool interrupted = vio_should_retry(net->vio);
if (!thr_got_alarm(&alarmed) && interrupted)
- { /* Probably in MIT threads */
+ { /* Probably in MIT threads */
if (retry_count++ < RETRY_COUNT)
continue;
}
return;
}
- remain -=(ulong) length;
- statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received);
+ remain -= length;
+ statistic_add(bytes_received,length,&LOCK_bytes_received);
}
}
#endif /* MYSQL_SERVER */
+/*
+ Reads one packet to net->buff + net->where_b
+ Returns length of packet. Long packets are handled by my_net_read().
+ This function reallocates the net->buff buffer if necessary.
+*/
+
static uint
my_real_read(NET *net, ulong *complen)
{
@@ -576,12 +647,13 @@ my_real_read(NET *net, ulong *complen)
#endif
len=uint3korr(net->buff+net->where_b);
+ if (!len) /* End of big multi-packet */
+ goto end;
helping = max(len,*complen) + net->where_b;
/* The necessary size of net->buff */
if (helping >= net->max_packet)
{
- /* We must allocate one extra byte for the end null */
- if (net_realloc(net,helping+1))
+ if (net_realloc(net,helping))
{
#ifdef MYSQL_SERVER
if (i == 1)
@@ -606,7 +678,21 @@ end:
return(len);
}
-uint
+
+/*
+ Read a packet from the client/server and return it without the internal
+ package header.
+ If the packet is the first packet of a multi-packet packet
+ (which is indicated by the length of the packet = 0xffffff) then
+ all sub packets are read and concatenated.
+ If the packet was compressed, its uncompressed and the length of the
+ uncompressed packet is returned.
+
+ The function returns the length of the found packet or packet_error.
+ net->read_pos points to the read data.
+*/
+
+ulong
my_net_read(NET *net)
{
ulong len,complen;
@@ -615,65 +701,126 @@ my_net_read(NET *net)
if (!net->compress)
{
#endif
- len = my_real_read (net,&complen);
+ len = my_real_read(net,&complen);
+ if (len == MAX_THREE_BYTES)
+ {
+ /* First packet of a multi-packet. Concatenate the packets */
+ int save_pos = net->where_b;
+ ulong total_length=0;
+ do
+ {
+ net->where_b += len;
+ total_length += len;
+ len = my_real_read (net,&complen);
+ } while (len == MAX_THREE_BYTES);
+ if (len != packet_error)
+ len+= total_length;
+ net->where_b = save_pos;
+ }
net->read_pos = net->buff + net->where_b;
if (len != packet_error)
net->read_pos[len]=0; /* Safeguard for mysql_use_result */
return len;
#ifdef HAVE_COMPRESS
}
- if (net->remain_in_buf)
- net->buff[net->buf_length - net->remain_in_buf]=net->save_char;
- for (;;)
+ else
{
+ /* We are using the compressed protocol */
+
+ ulong buf_length= net->buf_length;
+ ulong start_of_packet= net->buf_length - net->remain_in_buf;
+ ulong first_packet_offset=start_of_packet;
+ uint read_length, multi_byte_packet=0;
+
if (net->remain_in_buf)
{
- uchar *pos = net->buff + net->buf_length - net->remain_in_buf;
- if (net->remain_in_buf >= 4)
+ /* Restore the character that was overwritten by the end 0 */
+ net->buff[start_of_packet]=net->save_char;
+ }
+ else
+ {
+ /* reuse buffer, as there is noting in it that we need */
+ buf_length=start_of_packet=first_packet_offset=0;
+ }
+ for (;;)
+ {
+ ulong packet_len;
+
+ if (buf_length - start_of_packet >= NET_HEADER_SIZE)
{
- net->length = uint3korr(pos);
- if (net->length <= net->remain_in_buf - 4)
+ read_length = uint3korr(net->buff+start_of_packet);
+ if (!read_length)
+ {
+ /* End of multi-byte packet */
+ start_of_packet += NET_HEADER_SIZE;
+ break;
+ }
+ if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet)
{
- /* We have a full packet */
- len=net->length;
- net->remain_in_buf -= net->length + 4;
- net->read_pos=pos + 4;
- break; /* We have a full packet */
+ if (multi_byte_packet)
+ {
+ /* Remove packet header for second packet */
+ memmove(net->buff + first_packet_offset + start_of_packet,
+ net->buff + first_packet_offset + start_of_packet +
+ NET_HEADER_SIZE,
+ buf_length - start_of_packet);
+ start_of_packet += read_length;
+ buf_length -= NET_HEADER_SIZE;
+ }
+ else
+ start_of_packet+= read_length + NET_HEADER_SIZE;
+
+ if (read_length != MAX_THREE_BYTES) /* last package */
+ {
+ multi_byte_packet= 0; // No last zero length packet
+ break;
+ }
+ multi_byte_packet= NET_HEADER_SIZE;
+ /* Move data down to read next data packet after current one */
+ if (first_packet_offset)
+ {
+ memmove(net->buff,net->buff+first_packet_offset,
+ buf_length-first_packet_offset);
+ buf_length-=first_packet_offset;
+ start_of_packet -= first_packet_offset;
+ first_packet_offset=0;
+ }
+ continue;
}
}
/* Move data down to read next data packet after current one */
- if (net->buf_length != net->remain_in_buf)
+ if (first_packet_offset)
{
- memmove(net->buff,pos,net->remain_in_buf);
- net->buf_length=net->remain_in_buf;
+ memmove(net->buff,net->buff+first_packet_offset,
+ buf_length-first_packet_offset);
+ buf_length-=first_packet_offset;
+ start_of_packet -= first_packet_offset;
+ first_packet_offset=0;
}
- net->where_b=net->buf_length;
- }
- else
- {
- net->where_b=0;
- net->buf_length=0;
- }
- if ((len = my_real_read(net,&complen)) == packet_error)
- break;
- if (my_uncompress((byte*) net->buff + net->where_b, &len, &complen))
- {
- len= packet_error;
- net->error=2; /* caller will close socket */
+ net->where_b=buf_length;
+ if ((packet_len = my_real_read(net,&complen)) == packet_error)
+ return packet_error;
+ if (my_uncompress((byte*) net->buff + net->where_b, &packet_len,
+ &complen))
+ {
+ net->error=2; /* caller will close socket */
#ifdef MYSQL_SERVER
- net->last_errno=ER_NET_UNCOMPRESS_ERROR;
+ net->last_errno=ER_NET_UNCOMPRESS_ERROR;
#endif
- break;
+ return packet_error;
+ }
+ buf_length+=packet_len;
}
- net->buf_length+=len;
- net->remain_in_buf+=len;
- }
- if (len != packet_error)
- {
+
+ net->read_pos= net->buff+ first_packet_offset + NET_HEADER_SIZE;
+ net->buf_length= buf_length;
+ net->remain_in_buf= buf_length - start_of_packet;
+ len = ((uint) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE -
+ multi_byte_packet);
net->save_char= net->read_pos[len]; /* Must be saved */
net->read_pos[len]=0; /* Safeguard for mysql_use_result */
}
+#endif /* HAVE_COMPRESS */
return len;
-#endif
}
diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am
new file mode 100644
index 00000000000..396213b7e04
--- /dev/null
+++ b/libmysqld/Makefile.am
@@ -0,0 +1,106 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+# MA 02111-1307, USA
+#
+# This file is public domain and comes with NO WARRANTY of any kind
+
+MYSQLDATAdir = $(localstatedir)
+MYSQLSHAREdir = $(pkgdatadir)
+MYSQLBASEdir= $(prefix)
+
+DEFS = -DEMBEDDED_LIBRARY -DMYSQL_SERVER \
+ -DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \
+ -DDATADIR="\"$(MYSQLDATAdir)\"" \
+ -DSHAREDIR="\"$(MYSQLSHAREdir)\""
+INCLUDES = @MT_INCLUDES@ @bdb_includes@ -I$(srcdir)/../include -I../include \
+ -I$(srcdir)/.. -I$(top_srcdir) -I.. -I../sql -I../regex
+
+
+## XXX: should we use client or server LDFLAGS for libmysqld?
+LDADD = @CLIENT_EXTRA_LDFLAGS@ libmysqld.la
+pkglib_LTLIBRARIES = libmysqld.la
+
+libmysqld_la_SOURCES = libmysqld.c lib_sql.cc
+
+libmysqlsources = errmsg.c get_password.c password.c
+## XXX: we should not have to duplicate info from the sources list
+libmysqlobjects = errmsg.lo get_password.lo password.lo
+
+sqlsources = convert.cc derror.cc field.cc field_conv.cc filesort.cc \
+ ha_berkeley.cc ha_heap.cc ha_isam.cc ha_isammrg.cc \
+ ha_myisam.cc ha_myisammrg.cc handler.cc hostname.cc init.cc \
+ item.cc item_buff.cc item_cmpfunc.cc item_create.cc \
+ item_func.cc item_strfunc.cc item_sum.cc item_timefunc.cc \
+ item_uniq.cc key.cc lock.cc log.cc log_event.cc md5.c \
+ mini_client.cc net_pkg.cc net_serv.cc opt_ft.cc opt_range.cc \
+ opt_sum.cc procedure.cc records.cc slave.cc sql_acl.cc \
+ sql_analyse.cc sql_base.cc sql_cache.cc sql_class.cc \
+ sql_crypt.cc sql_db.cc sql_delete.cc sql_insert.cc sql_lex.cc \
+ sql_list.cc sql_load.cc sql_manager.cc sql_map.cc sql_parse.cc \
+ sql_rename.cc sql_repl.cc sql_select.cc sql_show.cc \
+ sql_string.cc sql_table.cc sql_test.cc sql_udf.cc \
+ sql_update.cc sql_yacc.cc table.cc thr_malloc.cc time.cc \
+ unireg.cc
+
+## XXX: we should not have to duplicate info from the sources list
+sqlobjects = convert.lo derror.lo field.lo field_conv.lo filesort.lo \
+ ha_berkeley.lo ha_heap.lo ha_isam.lo ha_isammrg.lo \
+ ha_myisam.lo ha_myisammrg.lo handler.lo hostname.lo init.lo \
+ item.lo item_buff.lo item_cmpfunc.lo item_create.lo \
+ item_func.lo item_strfunc.lo item_sum.lo item_timefunc.lo \
+ item_uniq.lo key.lo lock.lo log.lo log_event.lo md5.lo \
+ mini_client.lo net_pkg.lo net_serv.lo opt_ft.lo opt_range.lo \
+ opt_sum.lo procedure.lo records.lo slave.lo sql_acl.lo \
+ sql_analyse.lo sql_base.lo sql_cache.lo sql_class.lo \
+ sql_crypt.lo sql_db.lo sql_delete.lo sql_insert.lo sql_lex.lo \
+ sql_list.lo sql_load.lo sql_manager.lo sql_map.lo sql_parse.lo \
+ sql_rename.lo sql_repl.lo sql_select.lo sql_show.lo \
+ sql_string.lo sql_table.lo sql_test.lo sql_udf.lo \
+ sql_update.lo sql_yacc.lo table.lo thr_malloc.lo time.lo \
+ unireg.lo
+
+EXTRA_DIST = lib_vio.c
+
+# automake misses these
+sql_yacc.cc sql_yacc.h: $(top_srcdir)/sql/sql_yacc.yy
+
+libmysqld_la_LIBADD = $(sqlobjects) $(libmysqlobjects)
+## XXX: any time the client interface changes, we'll need to bump
+## the version info for libmysqld; however, it's possible for the
+## libmysqld interface to change without affecting the standard
+## libmysqlclient interface. Should we make a separate version
+## string for the two?
+libmysqld_la_LDFLAGS = -version-info @SHARED_LIB_VERSION@
+CLEANFILES = $(libmysqld_la_LIBADD) libmysqld.la
+
+# This is called from the toplevel makefile
+link_sources:
+ set -x; \
+ for f in $(sqlsources); do \
+ rm -f $(srcdir)/$$f; \
+ @LN_CP_F@ $(srcdir)/../sql/$$f $(srcdir)/$$f; \
+ done; \
+ for f in $(libmysqlsources); do \
+ rm -f $(srcdir)/$$f; \
+ @LN_CP_F@ $(srcdir)/../libmysql/$$f $(srcdir)/$$f; \
+ done
+
+clean-local:
+ rm -f `echo $(sqlsources) $(libmysqlsources) | sed "s;\.lo;.c;g"` \
+ $(top_srcdir)/linked_libmysqld_sources
+
+# Don't update the files from bitkeeper
+%::SCCS/s.%
diff --git a/libmysqld/README b/libmysqld/README
new file mode 100644
index 00000000000..c2febf3f19c
--- /dev/null
+++ b/libmysqld/README
@@ -0,0 +1,26 @@
+LIBRARY (ONE_PROCESS VERSION) OF MYSQL CLIENT
+
+Installation steps:
+
+
+1) unpack mysql-3.23.27-beta.tar tarball source version (get from www.mysql.com.sg)
+2) patch mysql-3.23.27-beta with lbver-3.23.27-beta.diff:
+ patch -p0 <lbver-3.23.27-beta.diff
+3) cd mysql-3.23.27-beta
+4) autoconf
+7) ./configure --prefix=/usr/local/mysql --with-library-version
+8) make
+9) make install (should have the root privileges)
+10)mkdir /usr/local/mysql/var (if not already)
+15) cd ../client
+19) ./mysql (start libarary version mysql)
+mysql> create database db1;
+mysql> use db1;
+mysql> create table a123(i integer)
+...... now you can work with library version....
+
+
+
+
+
+
diff --git a/libmysqld/WHITEPAPER b/libmysqld/WHITEPAPER
new file mode 100644
index 00000000000..191cdb4e0fd
--- /dev/null
+++ b/libmysqld/WHITEPAPER
@@ -0,0 +1,16 @@
+LIBRARY VERSION DESIGN (EMBEDDED SERVER)
+
+
+- The library version of MySQL server is the client library that contains embedded server.
+
+- This client DLL has name : libmysqlclient_e (.la)
+
+- The client application that supposed to use MySQL LV need to be rebuilt against libmysqlclient_e.la. The rebuild process is necessary, because libmysqlclient_e is a LIBTOOL object, which has the different LIBS list compared to the original libmysqlclient.la.
+
+- The client and the server code run in the same process and the same thread;
+
+- The server code is invoked when client writes the command to the net, and when connection is established;
+
+
+
+
diff --git a/libmysqld/copyright b/libmysqld/copyright
new file mode 100644
index 00000000000..0b4dd1725a2
--- /dev/null
+++ b/libmysqld/copyright
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2000
+ * SWsoft company
+ *
+ * This material is provided "as is", with absolutely no warranty expressed
+ * or implied. Any use is at your own risk.
+ *
+ * Permission to use or copy this software for any purpose is hereby granted
+ * without fee, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ */
diff --git a/libmysqld/lib_load.cc b/libmysqld/lib_load.cc
new file mode 100644
index 00000000000..7bdc8837878
--- /dev/null
+++ b/libmysqld/lib_load.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2000
+ * SWsoft company
+ *
+ * This material is provided "as is", with absolutely no warranty expressed
+ * or implied. Any use is at your own risk.
+ *
+ * Permission to use or copy this software for any purpose is hereby granted
+ * without fee, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ */
+/* Copy data from a textfile to table */
+
+#include "mysql_priv.h"
+#include <my_dir.h>
+#include <m_ctype.h>
+
+
+int
+mysql_load_internal(THD * thd, sql_exchange * ex, TABLE_LIST * table_list,
+List<Item> & fields, enum enum_duplicates handle_duplicates,
+bool read_file_from_client, thr_lock_type lock_type);
+
+int
+mysql_load(THD * thd, sql_exchange * ex, TABLE_LIST * table_list,
+List<Item> & fields, enum enum_duplicates handle_duplicates,
+bool read_file_from_client, thr_lock_type lock_type)
+{
+ printf("SWSOFT_MYSQL load: \n");
+ read_file_from_client = 0; //server is always in the same process
+ return mysql_load_internal(thd, ex, table_list, fields, handle_duplicates,
+ read_file_from_client, lock_type);
+
+}
+
+#define mysql_load mysql_load_internal
+
+#include "../sql/sql_load.cc"
diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc
new file mode 100644
index 00000000000..8a484301b61
--- /dev/null
+++ b/libmysqld/lib_sql.cc
@@ -0,0 +1,650 @@
+/*
+ * Copyright (c) 2000
+ * SWsoft company
+ *
+ * This material is provided "as is", with absolutely no warranty expressed
+ * or implied. Any use is at your own risk.
+ *
+ * Permission to use or copy this software for any purpose is hereby granted
+ * without fee, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ */
+#include "global.h"
+#include "my_pthread.h"
+#include "sys/types.h"
+#include "../regex/regex.h"
+#include "my_sys.h"
+
+#define main main1
+#define mysql_unix_port mysql_inix_port1
+#define mysql_port mysql_port1
+#define net_read_timeout net_read_timeout1
+#define net_write_timeout net_write_timeout1
+#define changeable_vars changeable_vars1
+//#define mysql_tmpdir mysql_tmpdir1
+
+extern "C"
+{
+#include "mysql_com.h"
+}
+
+
+class THD;
+
+static int
+check_connections1(THD * thd);
+
+static bool
+check_user(THD *thd, enum_server_command command,const char *user, const char *passwd, const char *db, bool check_count);
+
+static int
+check_connections2(THD * thd);
+
+extern void free_defaults(char ** argv);
+void free_defaults_internal(char ** argv){if (argv) free_defaults(argv);}
+#define free_defaults free_defaults_internal
+
+char mysql_data_home[FN_REFLEN];
+char * get_mysql_data_home(){return mysql_data_home;};
+#define mysql_data_home mysql_data_home_internal
+#include "../sql/mysqld.cc"
+#include "lib_vio.c"
+
+#define SCRAMBLE_LENGTH 8
+extern "C" {
+
+/*
+void
+free_defaults(char ** argv) {};
+void
+load_defaults(const char *, const char **, int *, char ***) {};
+*/
+
+char *
+get_mysql_home(){ return mysql_home;};
+char *
+get_mysql_real_data_home(){ return mysql_real_data_home;};
+
+
+bool lib_dispatch_command(enum enum_server_command command, NET *net,
+ const char *arg, ulong length)
+{
+ net_new_transaction(&((THD *)net->vio->dest_thd)->net);
+ return dispatch_command(command, (THD *)net->vio->dest_thd, (char *)arg, length + 1);
+}
+
+
+
+void
+lib_connection_phase(NET * net, int phase)
+{
+ THD * thd;
+ thd = (THD *)(net->vio->dest_thd);
+ if (thd)
+ {
+ switch (phase)
+ {
+ case 2:
+ check_connections2(thd);
+ break;
+ }
+ }
+}
+}
+void start_embedded_conn1(NET * net)
+{
+ THD * thd = new THD;
+ my_net_init(&thd->net,NULL);
+ /* if (protocol_version>9) */
+ thd->net.return_errno=1;
+ thd->thread_id = thread_id++;
+
+ Vio * v = net->vio;
+ if (!v)
+ {
+ v = vio_new(0,VIO_CLOSED,0);
+ net->vio = v;
+ }
+ if (v)
+ {
+ v -> dest_thd = thd;
+ /* v -> dest_net = &thd->net; XXX: Probably not needed? */
+ }
+ thd->net.vio = v;
+ if (thd->store_globals())
+ {
+ printf("store_globals failed.\n");
+ return;
+ }
+
+ thd->mysys_var=my_thread_var;
+ thd->dbug_thread_id=my_thread_id();
+ thd->thread_stack= (char*) &thd;
+
+ if (thd->max_join_size == HA_POS_ERROR)
+ thd->options |= OPTION_BIG_SELECTS;
+ if (thd->client_capabilities & CLIENT_COMPRESS)
+ net->compress=1; // Use compression
+ if (thd->options & OPTION_ANSI_MODE)
+ thd->client_capabilities|=CLIENT_IGNORE_SPACE;
+
+ thd->proc_info=0; // Remove 'login'
+ thd->command=COM_SLEEP;
+ thd->version=refresh_version;
+ thd->set_time();
+ init_sql_alloc(&thd->mem_root,8192,8192);
+
+ check_connections1(thd);
+}
+
+
+
+
+static int
+check_connections1(THD *thd)
+{
+ uint connect_errors=0;
+ NET *net= &thd->net;
+ /*
+ ** store the connection details
+ */
+ DBUG_PRINT("info", (("check_connections called by thread %d"),
+ thd->thread_id));
+ DBUG_PRINT("general",("New connection received on %s",
+ vio_description(net->vio)));
+ if (!thd->host) // If TCP/IP connection
+ {
+ thd->host=(char*) localhost;
+ }
+ else /* Hostname given means that the connection was on a socket */
+ {
+ DBUG_PRINT("general",("Host: %s",thd->host));
+ thd->ip=0;
+ bzero((char*) &thd->remote,sizeof(struct sockaddr));
+ }
+ //vio_keepalive(net->vio, TRUE);
+
+ /* nasty, but any other way? */
+ uint pkt_len = 0;
+
+ char buff[80],*end;
+ int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
+ CLIENT_TRANSACTIONS;
+ LINT_INIT(pkt_len);
+
+ end=strmov(buff,server_version)+1;
+ int4store((uchar*) end,thd->thread_id);
+ end+=4;
+ memcpy(end,thd->scramble,SCRAMBLE_LENGTH+1);
+ end+=SCRAMBLE_LENGTH +1;
+#ifdef HAVE_COMPRESS
+ client_flags |= CLIENT_COMPRESS;
+#endif /* HAVE_COMPRESS */
+ int2store(end,client_flags);
+ end[2]=MY_CHARSET_CURRENT;
+
+#define MIN_HANDSHAKE_SIZE 6
+
+ int2store(end+3,thd->server_status);
+ bzero(end+5,13);
+ end+=18;
+ if (net_write_command(net,protocol_version, buff,
+ (uint) (end-buff)))
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ return(ER_HANDSHAKE_ERROR);
+ }
+ return 0;
+}
+
+static int
+check_connections2(THD * thd)
+{
+uint connect_errors=0;
+uint pkt_len = 0;
+NET * net = &thd -> net;
+if (protocol_version>9) net -> return_errno=1;
+
+ if ( (pkt_len=my_net_read(net)) == packet_error ||
+ pkt_len < MIN_HANDSHAKE_SIZE)
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ return(ER_HANDSHAKE_ERROR);
+ }
+
+#ifdef _CUSTOMCONFIG_
+#include "_cust_sql_parse.h"
+#endif
+ if (connect_errors)
+ reset_host_errors(&thd->remote.sin_addr);
+ if (thd->packet.alloc(net_buffer_length))
+ return(ER_OUT_OF_RESOURCES);
+
+ thd->client_capabilities=uint2korr(net->read_pos);
+
+ thd->max_packet_length=uint3korr(net->read_pos+2);
+ char *user= (char*) net->read_pos+5;
+ char *passwd= strend(user)+1;
+ char *db=0;
+ if (passwd[0] && strlen(passwd) != SCRAMBLE_LENGTH)
+ return ER_HANDSHAKE_ERROR;
+ if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
+ db=strend(passwd)+1;
+ if (thd->client_capabilities & CLIENT_INTERACTIVE)
+ thd->inactive_timeout=net_interactive_timeout;
+ if (thd->client_capabilities & CLIENT_TRANSACTIONS)
+ thd->net.return_status= &thd->server_status;
+ net->timeout=net_read_timeout;
+ if (check_user(thd,COM_CONNECT, user, passwd, db, 1))
+ return (-1);
+ thd->password=test(passwd[0]);
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+static bool check_user(THD *thd,enum_server_command command, const char *user,
+ const char *passwd, const char *db, bool check_count)
+{
+ NET *net= &thd->net;
+ thd->db=0;
+
+ if (!(thd->user = my_strdup(user, MYF(0))))
+ {
+ send_error(net,ER_OUT_OF_RESOURCES);
+ return 1;
+ }
+ thd->master_access=acl_getroot(thd->host, thd->ip, thd->user,
+ passwd, thd->scramble, &thd->priv_user,
+ protocol_version == 9 ||
+ !(thd->client_capabilities &
+ CLIENT_LONG_PASSWORD));
+ DBUG_PRINT("general",
+ ("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'",
+ thd->client_capabilities, thd->max_packet_length,
+ thd->host ? thd->host : thd->ip, thd->priv_user,
+ passwd[0] ? "yes": "no",
+ thd->master_access, thd->db ? thd->db : "*none*"));
+ if (thd->master_access & NO_ACCESS)
+ {
+ net_printf(net, ER_ACCESS_DENIED_ERROR,
+ thd->user,
+ thd->host ? thd->host : thd->ip,
+ passwd[0] ? ER(ER_YES) : ER(ER_NO));
+ mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR),
+ thd->user,
+ thd->host ? thd->host : thd->ip ? thd->ip : "unknown ip",
+ passwd[0] ? ER(ER_YES) : ER(ER_NO));
+ return(1); // Error already given
+ }
+ if (check_count)
+ {
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ bool tmp=(thread_count - delayed_insert_threads >= max_connections &&
+ !(thd->master_access & PROCESS_ACL));
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ if (tmp)
+ { // Too many connections
+ send_error(net, ER_CON_COUNT_ERROR);
+ return(1);
+ }
+ }
+ mysql_log.write(thd,command,
+ (thd->priv_user == thd->user ?
+ (char*) "%s@%s on %s" :
+ (char*) "%s@%s as anonymous on %s"),
+ user,
+ thd->host ? thd->host : thd->ip ? thd->ip : "unknown ip",
+ db ? db : (char*) "");
+ thd->db_access=0;
+ if (db && db[0])
+ return test(mysql_change_db(thd,db));
+ else
+ send_ok(net); // Ready to handle questions
+ return 0; // ok
+}
+
+
+extern "C"{
+void start_embedded_connection(NET * net)
+{
+ start_embedded_conn1(net);
+}
+//====================================================================
+void embedded_srv_init(void)
+{
+ DEBUGGER_OFF;
+ char hostname[FN_REFLEN];
+
+ my_umask=0660; // Default umask for new files
+ my_umask_dir=0700; // Default umask for new directories
+ MY_INIT((char *)"mysqld"); // init my_sys library & pthreads
+ tzset(); // Set tzname
+
+ start_time=time((time_t*) 0);
+#ifdef HAVE_TZNAME
+#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT)
+ {
+ struct tm tm_tmp;
+ localtime_r(&start_time,&tm_tmp);
+ strmov(time_zone,tzname[tm_tmp.tm_isdst == 1 ? 1 : 0]);
+ }
+#else
+ {
+ struct tm *start_tm;
+ start_tm=localtime(&start_time);
+ strmov(time_zone=tzname[start_tm->tm_isdst == 1 ? 1 : 0]);
+ }
+#endif
+#endif
+
+ if (gethostname(hostname,sizeof(hostname)-4) < 0)
+ strmov(hostname,"mysql");
+ strmov(pidfile_name,hostname);
+ strmov(strcend(pidfile_name,'.'),".pid"); // Add extension
+#ifdef DEMO_VERSION
+ strcat(server_version,"-demo");
+#endif
+#ifdef SHAREWARE_VERSION
+ strcat(server_version,"-shareware");
+#endif
+#ifndef DBUG_OFF
+ strcat(server_version,"-debug");
+#endif
+ strcat(server_version,"-library-ver");
+#ifdef _CUSTOMSTARTUPCONFIG_
+ if (_cust_check_startup())
+ {
+ /* _cust_check_startup will report startup failure error */
+ exit( 1 );
+ }
+#endif
+ // load_defaults("my",load_default_groups,&d_argc, (char***)&d_argv);
+ defaults_argv=0;
+ mysql_tmpdir=getenv("TMPDIR"); /* Use this if possible */
+#ifdef __WIN__
+ if (!mysql_tmpdir)
+ mysql_tmpdir=getenv("TEMP");
+ if (!mysql_tmpdir)
+ mysql_tmpdir=getenv("TMP");
+#endif
+ if (!mysql_tmpdir || !mysql_tmpdir[0])
+ mysql_tmpdir=strdup((char*) P_tmpdir);
+ set_options();
+ fix_paths();
+
+ if (opt_log || opt_update_log || opt_slow_log || opt_bin_log)
+ strcat(server_version,"-log");
+ DBUG_PRINT("info",("%s Ver %s for %s on %s\n",my_progname,
+ server_version, SYSTEM_TYPE,MACHINE_TYPE));
+
+ /* These must be set early */
+
+ (void) pthread_cond_init(&COND_thread_count,NULL);
+ (void) pthread_mutex_init(&LOCK_mysql_create_db,NULL);
+ (void) pthread_mutex_init(&LOCK_Acl,NULL);
+ (void) pthread_mutex_init(&LOCK_grant,NULL);
+ (void) pthread_mutex_init(&LOCK_open,NULL);
+ (void) pthread_mutex_init(&LOCK_thread_count,NULL);
+ (void) pthread_mutex_init(&LOCK_mapped_file,NULL);
+ (void) pthread_mutex_init(&LOCK_status,NULL);
+ (void) pthread_mutex_init(&LOCK_error_log,NULL);
+ (void) pthread_mutex_init(&LOCK_delayed_insert,NULL);
+ (void) pthread_mutex_init(&LOCK_delayed_status,NULL);
+ (void) pthread_mutex_init(&LOCK_delayed_create,NULL);
+ (void) pthread_cond_init(&COND_refresh,NULL);
+ (void) pthread_cond_init(&COND_thread_cache,NULL);
+ (void) pthread_cond_init(&COND_flush_thread_cache,NULL);
+ (void) pthread_cond_init(&COND_manager,NULL);
+ (void) pthread_mutex_init(&LOCK_manager,NULL);
+ (void) pthread_mutex_init(&LOCK_crypt,NULL);
+ (void) pthread_mutex_init(&LOCK_bytes_sent,NULL);
+ (void) pthread_mutex_init(&LOCK_bytes_received,NULL);
+ (void) pthread_mutex_init(&LOCK_timezone,NULL);
+ (void) pthread_mutex_init(&LOCK_binlog_update, NULL);
+ (void) pthread_mutex_init(&LOCK_slave, NULL);
+ (void) pthread_mutex_init(&LOCK_server_id, NULL);
+ (void) pthread_cond_init(&COND_binlog_update, NULL);
+ (void) pthread_cond_init(&COND_slave_stopped, NULL);
+
+ if (set_default_charset_by_name(default_charset, MYF(MY_WME)))
+ unireg_abort(1);
+ charsets_list = list_charsets(MYF(MY_COMPILED_SETS|MY_CONFIG_SETS));
+
+
+ if (!(opt_specialflag & SPECIAL_NO_PRIOR))
+ my_pthread_setprio(pthread_self(),CONNECT_PRIOR);
+ /* Parameter for threads created for connections */
+ (void) pthread_attr_init(&connection_attrib);
+ (void) pthread_attr_setdetachstate(&connection_attrib,
+ PTHREAD_CREATE_DETACHED);
+ pthread_attr_setstacksize(&connection_attrib,thread_stack);
+
+ if (!(opt_specialflag & SPECIAL_NO_PRIOR))
+ my_pthread_attr_setprio(&connection_attrib,WAIT_PRIOR);
+ pthread_attr_setscope(&connection_attrib, PTHREAD_SCOPE_SYSTEM);
+
+#ifdef SET_RLIMIT_NOFILE
+ /* connections and databases neads lots of files */
+ {
+ uint wanted_files=10+(uint) max(max_connections*5,
+ max_connections+table_cache_size*2);
+ uint files=set_maximum_open_files(wanted_files);
+ if (files && files < wanted_files) // Some systems return 0
+ {
+ max_connections= (ulong) min((files-10),max_connections);
+ table_cache_size= (ulong) max((files-10-max_connections)/2,64);
+ DBUG_PRINT("warning",
+ ("Changed limits: max_connections: %ld table_cache: %ld",
+ max_connections,table_cache_size));
+ sql_print_error("Warning: Changed limits: max_connections: %ld table_cache: %ld",max_connections,table_cache_size);
+ }
+ }
+#endif
+ unireg_init(opt_specialflag); /* Set up extern variabels */
+ init_errmessage(); /* Read error messages from file */
+ lex_init();
+ item_init();
+ mysys_uses_curses=0;
+#ifdef USE_REGEX
+ regex_init();
+#endif
+ select_thread=pthread_self();
+ select_thread_in_use=1;
+
+ /*
+ ** We have enough space for fiddling with the argv, continue
+ */
+ umask(((~my_umask) & 0666));
+// strcpy(mysql_real_data_home, "/usr/local");
+ //if (my_setwd(mysql_real_data_home,MYF(MY_WME)))
+ //{
+ // unireg_abort(1); /* purecov: inspected */
+ //}
+ //mysql_data_home[0]=FN_CURLIB; // all paths are relative from here
+ //mysql_data_home[1]=0;
+
+ strcpy(get_mysql_data_home(), mysql_real_data_home);
+
+ //server_init();
+ table_cache_init();
+ hostname_cache_init();
+ sql_cache_init();
+ randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2);
+ reset_floating_point_exceptions();
+ init_thr_lock();
+
+ /* Setup log files */
+ if (opt_log)
+ open_log(&mysql_log, hostname, opt_logname, ".log", LOG_NORMAL);
+ if (opt_update_log)
+ open_log(&mysql_update_log, hostname, opt_update_logname, "",
+ LOG_NEW);
+ if (opt_bin_log)
+ {
+ if(server_id)
+ {
+ if (!opt_bin_logname)
+ {
+ char tmp[FN_REFLEN];
+ strnmov(tmp,hostname,FN_REFLEN-5);
+ strmov(strcend(tmp,'.'),"-bin");
+ opt_bin_logname=my_strdup(tmp,MYF(MY_WME));
+ }
+ mysql_bin_log.set_index_file_name(opt_binlog_index_name);
+ open_log(&mysql_bin_log, hostname, opt_bin_logname, "-bin",
+ LOG_BIN);
+ }
+ else
+ sql_print_error("Server id is not set - binary logging disabled");
+ }
+
+ if (opt_slow_log)
+ open_log(&mysql_slow_log, hostname, opt_slow_logname, "-slow.log",
+ LOG_NORMAL);
+ if (ha_init())
+ {
+ sql_print_error("Can't init databases");
+ exit(1);
+ }
+#ifdef HAVE_MLOCKALL
+ if (locked_in_memory && !geteuid())
+ {
+ ha_key_cache();
+ if (mlockall(MCL_CURRENT))
+ {
+ sql_print_error("Warning: Failed to lock memory. Errno: %d\n",errno);
+ }
+ else
+ locked_in_memory=1;
+ }
+#else
+ locked_in_memory=0;
+#endif
+
+ if (opt_myisam_log)
+ (void) mi_log( 1 );
+ ft_init_stopwords(ft_precompiled_stopwords); /* SerG */
+
+ /*
+ init signals & alarm
+ After this we can't quit by a simple unireg_abort
+ */
+ error_handler_hook = my_message_sql;
+ if (pthread_key_create(&THR_THD,NULL) || pthread_key_create(&THR_NET,NULL) ||
+ pthread_key_create(&THR_MALLOC,NULL))
+ {
+ sql_print_error("Can't create thread-keys");
+ exit(1);
+ }
+// init_signals(); // Creates pidfile
+//SWSOFT+
+ opt_noacl = 1;
+ if (acl_init(opt_noacl))
+ {
+ select_thread_in_use=0;
+ (void) pthread_kill(signal_thread,MYSQL_KILL_SIGNAL);
+ exit(1);
+ }
+ if (!opt_noacl)
+ (void) grant_init();
+
+#ifdef HAVE_DLOPEN
+ if (!opt_noacl)
+ udf_init();
+#endif
+
+ if (opt_bootstrap)
+ {
+ int error=bootstrap(stdin);
+ end_thr_alarm(); // Don't allow alarms
+ unireg_abort(error ? 1 : 0);
+ }
+ if (opt_init_file)
+ {
+ if (read_init_file(opt_init_file))
+ {
+ end_thr_alarm(); // Don't allow alarms
+ unireg_abort(1);
+ }
+ }
+ (void) thr_setconcurrency(concurrency); // 10 by default
+
+ if (flush_time && flush_time != ~(ulong) 0L)
+ {
+ pthread_t hThread;
+ if (pthread_create(&hThread,&connection_attrib,handle_manager,0))
+ sql_print_error("Warning: Can't create thread to manage maintenance");
+ }
+
+ // slave thread
+ if(master_host)
+ {
+ if(server_id)
+ {
+ pthread_t hThread;
+ if(!opt_skip_slave_start &&
+ pthread_create(&hThread, &connection_attrib, handle_slave, 0))
+ sql_print_error("Warning: Can't create thread to handle slave");
+ }
+ else
+ sql_print_error("Server id is not set, slave thread will not be started");
+ }
+
+ //printf(ER(ER_READY),my_progname,server_version,"");
+ printf("%s initialized.\n", server_version);
+ fflush(stdout);
+
+
+}
+
+
+void embedded_srv_deinit()
+{
+
+ /* (void) pthread_attr_destroy(&connection_attrib); */
+
+ DBUG_PRINT("quit",("Exiting main thread"));
+
+#ifdef EXTRA_DEBUG
+ sql_print_error("Before Lock_thread_count");
+#endif
+ (void) pthread_mutex_lock(&LOCK_thread_count);
+ select_thread_in_use=0; // For close_connections
+ (void) pthread_cond_broadcast(&COND_thread_count);
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+#ifdef EXTRA_DEBUG
+ sql_print_error("After lock_thread_count");
+#endif
+
+ /* Wait until cleanup is done */
+ (void) pthread_mutex_lock(&LOCK_thread_count);
+ while (!ready_to_exit)
+ {
+ pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
+ }
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+ my_thread_end();
+
+}
+}
+int embedded_do_command(NET * net)
+{
+ THD * thd = (THD *) net ->vio;
+ do_command(thd);
+ return 0;
+}
+
+
+
diff --git a/libmysqld/lib_vio.c b/libmysqld/lib_vio.c
new file mode 100644
index 00000000000..a1cd8ca9565
--- /dev/null
+++ b/libmysqld/lib_vio.c
@@ -0,0 +1,236 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*
+ Note that we can't have assertion on file descriptors; The reason for
+ this is that during mysql shutdown, another thread can close a file
+ we are working on. In this case we should just return read errors from
+ the file descriptior.
+*/
+
+#include <global.h>
+
+#ifndef HAVE_VIO /* is Vio suppored by the Vio lib ? */
+
+#include <errno.h>
+#include <my_sys.h>
+#include "mysql.h"
+#include <violite.h>
+#include <my_sys.h>
+#include <my_net.h>
+#include <m_string.h>
+#include <dbug.h>
+#include <assert.h>
+
+#if defined(__EMX__)
+#include <sys/ioctl.h>
+#define ioctlsocket(A,B,C) ioctl((A),(B),(void *)(C),sizeof(*(C)))
+#undef HAVE_FCNTL
+#endif /* defined(__EMX__) */
+
+#if defined(MSDOS) || defined(__WIN__)
+#ifdef __WIN__
+#undef errno
+#undef EINTR
+#undef EAGAIN
+#define errno WSAGetLastError()
+#define EINTR WSAEINTR
+#define EAGAIN WSAEINPROGRESS
+#endif /* __WIN__ */
+#define O_NONBLOCK 1 /* For emulation of fcntl() */
+#endif
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK EAGAIN
+#endif
+
+#ifndef __WIN__
+#define HANDLE void *
+#endif
+
+struct st_vio
+{
+ my_socket sd; /* my_socket - real or imaginary */
+ HANDLE hPipe;
+ my_bool localhost; /* Are we from localhost? */
+ int fcntl_mode; /* Buffered fcntl(sd,F_GETFL) */
+ struct sockaddr_in local; /* Local internet address */
+ struct sockaddr_in remote; /* Remote internet address */
+ enum enum_vio_type type; /* Type of connection */
+ char desc[30]; /* String description */
+ /* #ifdef EMBEDDED_LIBRARY */
+ /* void *dest_net; */
+ void *dest_thd;
+ char *packets, **last_packet;
+ char *where_in_packet, *end_of_packet;
+ my_bool reading;
+ MEM_ROOT root;
+ /* #endif */
+};
+
+/* Initialize the communication buffer */
+
+Vio *vio_new(my_socket sd, enum enum_vio_type type, my_bool localhost)
+{
+ Vio * vio = NULL;
+ vio = (Vio *) my_malloc (sizeof(*vio),MYF(MY_WME|MY_ZEROFILL));
+ if (vio)
+ {
+ init_alloc_root(&vio->root, 8192, 1024);
+ vio->root.min_malloc = sizeof(char *) + 4;
+ vio->last_packet = &vio->packets;
+ }
+ return (vio);
+}
+
+
+#ifdef __WIN__
+
+Vio *vio_new_win32pipe(HANDLE hPipe)
+{
+ return (NULL);
+}
+
+#endif
+
+void vio_delete(Vio * vio)
+{
+ if (vio)
+ {
+ if (vio->type != VIO_CLOSED) vio_close(vio);
+ free_root(&vio->root, MYF(0));
+ my_free((gptr)vio, MYF(0));
+ }
+}
+
+void vio_reset(Vio *vio)
+{
+ free_root(&vio->root, MYF(MY_KEEP_PREALLOC));
+ vio->packets = vio->where_in_packet = vio->end_of_packet = 0;
+ vio->last_packet = &vio->packets;
+}
+
+int vio_errno(Vio *vio __attribute__((unused)))
+{
+ return errno; /* On Win32 this mapped to WSAGetLastError() */
+}
+
+int vio_read(Vio * vio, gptr buf, int size)
+{
+ vio->reading = 1;
+ if (vio->where_in_packet >= vio->end_of_packet)
+ {
+ dbug_assert(vio->packets);
+ vio->where_in_packet = vio->packets + sizeof(char *) + 4;
+ vio->end_of_packet = vio->where_in_packet +
+ uint4korr(vio->packets + sizeof(char *));
+ vio->packets = *(char **)vio->packets;
+ }
+ memcpy(buf, vio->where_in_packet, size);
+ vio->where_in_packet += size;
+ return (size);
+}
+
+int vio_write(Vio * vio, const gptr buf, int size)
+{
+ char *packet;
+ if (vio->reading)
+ {
+ vio->reading = 0;
+ vio_reset(vio);
+ }
+ if ((packet = alloc_root(&vio->root, sizeof(char*) + 4 + size)))
+ {
+ *vio->last_packet = packet;
+ vio->last_packet = (char **)packet;
+ *((char **)packet) = 0; /* safety */
+ packet += sizeof(char *);
+ int4store(packet, size);
+ memcpy(packet + 4, buf, size);
+ }
+ else
+ size=0;
+ return (size);
+}
+
+int vio_blocking(Vio * vio, my_bool set_blocking_mode)
+{
+ int r=0;
+ return (r);
+}
+
+my_bool
+vio_is_blocking(Vio * vio)
+{
+ my_bool r=0;
+ return(r);
+}
+
+int vio_fastsend(Vio * vio)
+{
+ int r=0;
+ return(r);
+}
+
+int vio_keepalive(Vio* vio, my_bool set_keep_alive)
+{
+ int r=0;
+ return (r);
+}
+
+
+my_bool
+vio_should_retry(Vio * vio __attribute__((unused)))
+{
+ int en = errno;
+ return en == EAGAIN || en == EINTR || en == EWOULDBLOCK;
+}
+
+
+int vio_close(Vio * vio)
+{
+ int r=0;
+ return(r);
+}
+
+
+const char *vio_description(Vio * vio)
+{
+ return "embedded vio";
+}
+
+enum enum_vio_type vio_type(Vio* vio)
+{
+ return VIO_CLOSED;
+}
+
+my_socket vio_fd(Vio* vio)
+{
+ return 0;
+}
+
+
+my_bool vio_peer_addr(Vio * vio, char *buf)
+{
+ return(0);
+}
+
+
+void vio_in_addr(Vio *vio, struct in_addr *in)
+{
+}
+
+#endif /* HAVE_VIO */
diff --git a/libmysqld/libmysqld.c b/libmysqld/libmysqld.c
new file mode 100644
index 00000000000..a9def5c37ef
--- /dev/null
+++ b/libmysqld/libmysqld.c
@@ -0,0 +1,2299 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+#define DONT_USE_RAID
+#if defined(__WIN__) || defined(_WIN32) || defined(_WIN64)
+#include <winsock.h>
+#include <odbcinst.h>
+#endif
+#include <global.h>
+#include <my_sys.h>
+#include <mysys_err.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include "mysql.h"
+#include "mysql_version.h"
+#include "mysqld_error.h"
+#include "errmsg.h"
+#include <violite.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <time.h>
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#if !defined(MSDOS) && !defined(__WIN__)
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#ifdef HAVE_SELECT_H
+# include <select.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#endif
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif
+#if defined(THREAD) && !defined(__WIN__)
+#include <my_pthread.h> /* because of signal() */
+#endif
+#ifndef INADDR_NONE
+#define INADDR_NONE -1
+#endif
+
+static my_bool mysql_client_init=0;
+uint mysql_port=0;
+my_string mysql_unix_port=0;
+
+#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_TRANSACTIONS)
+
+#if defined(MSDOS) || defined(__WIN__)
+#define ERRNO WSAGetLastError()
+#define perror(A)
+#else
+#include <errno.h>
+#define ERRNO errno
+#define SOCKET_ERROR -1
+#define closesocket(A) close(A)
+#endif
+
+/* XXX: this is real ugly... */
+static void mysql_once_init(void);
+extern void embedded_srv_init(void);
+extern void embedded_srv_deinit(void);
+extern void start_embedded_connection(NET * net);
+extern void lib_connection_phase(NET *net, int phase);
+extern bool lib_dispatch_command(enum enum_server_command command, NET *net,
+ const char *arg, ulong length);
+
+static MYSQL_DATA *read_rows (MYSQL *mysql,MYSQL_FIELD *fields,
+ uint field_count);
+static int read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row,
+ ulong *lengths);
+static void end_server(MYSQL *mysql);
+static void read_user_name(char *name);
+static void append_wild(char *to,char *end,const char *wild);
+static my_bool mysql_reconnect(MYSQL *mysql);
+static int send_file_to_server(MYSQL *mysql,const char *filename);
+static sig_handler pipe_sig_handler(int sig);
+static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to,
+ const char *from, ulong length);
+
+/*
+ Let the user specify that we don't want SIGPIPE; This doesn't however work
+ with threaded applications as we can have multiple read in progress.
+*/
+
+#if !defined(__WIN__) && defined(SIGPIPE) && !defined(THREAD)
+#define init_sigpipe_variables sig_return old_signal_handler=(sig_return) 0;
+#define set_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) old_signal_handler=signal(SIGPIPE,pipe_sig_handler)
+#define reset_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) signal(SIGPIPE,old_signal_handler);
+#else
+#define init_sigpipe_variables
+#define set_sigpipe(mysql)
+#define reset_sigpipe(mysql)
+#endif
+
+#if 0
+/****************************************************************************
+* A modified version of connect(). connect2() allows you to specify
+* a timeout value, in seconds, that we should wait until we
+* derermine we can't connect to a particular host. If timeout is 0,
+* connect2() will behave exactly like connect().
+*
+* Base version coded by Steve Bernacki, Jr. <steve@navinet.net>
+*****************************************************************************/
+
+static int connect2(my_socket s, const struct sockaddr *name, uint namelen,
+ uint to)
+{
+#if defined(__WIN__)
+ return connect(s, (struct sockaddr*) name, namelen);
+#else
+ int flags, res, s_err;
+ size_socket s_err_size = sizeof(uint);
+ fd_set sfds;
+ struct timeval tv;
+ time_t start_time, now_time;
+
+ /* If they passed us a timeout of zero, we should behave
+ * exactly like the normal connect() call does.
+ */
+
+ if (to == 0)
+ return connect(s, (struct sockaddr*) name, namelen);
+
+ flags = fcntl(s, F_GETFL, 0); /* Set socket to not block */
+#ifdef O_NONBLOCK
+ fcntl(s, F_SETFL, flags | O_NONBLOCK); /* and save the flags.. */
+#endif
+
+ res = connect(s, (struct sockaddr*) name, namelen);
+ s_err = errno; /* Save the error... */
+ fcntl(s, F_SETFL, flags);
+ if ((res != 0) && (s_err != EINPROGRESS))
+ {
+ errno = s_err; /* Restore it */
+ return(-1);
+ }
+ if (res == 0) /* Connected quickly! */
+ return(0);
+
+ /* Otherwise, our connection is "in progress." We can use
+ * the select() call to wait up to a specified period of time
+ * for the connection to suceed. If select() returns 0
+ * (after waiting howevermany seconds), our socket never became
+ * writable (host is probably unreachable.) Otherwise, if
+ * select() returns 1, then one of two conditions exist:
+ *
+ * 1. An error occured. We use getsockopt() to check for this.
+ * 2. The connection was set up sucessfully: getsockopt() will
+ * return 0 as an error.
+ *
+ * Thanks goes to Andrew Gierth <andrew@erlenstar.demon.co.uk>
+ * who posted this method of timing out a connect() in
+ * comp.unix.programmer on August 15th, 1997.
+ */
+
+ FD_ZERO(&sfds);
+ FD_SET(s, &sfds);
+ /*
+ * select could be interrupted by a signal, and if it is,
+ * the timeout should be adjusted and the select restarted
+ * to work around OSes that don't restart select and
+ * implementations of select that don't adjust tv upon
+ * failure to reflect the time remaining
+ */
+ start_time = time(NULL);
+ for (;;)
+ {
+ tv.tv_sec = (long) to;
+ tv.tv_usec = 0;
+ if ((res = select(s+1, NULL, &sfds, NULL, &tv)) >= 0)
+ break;
+ now_time=time(NULL);
+ to-= (uint) (now_time - start_time);
+ if (errno != EINTR || (int) to <= 0)
+ return -1;
+ }
+
+ /* select() returned something more interesting than zero, let's
+ * see if we have any errors. If the next two statements pass,
+ * we've got an open socket!
+ */
+
+ s_err=0;
+ if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char*) &s_err, &s_err_size) != 0)
+ return(-1);
+
+ if (s_err)
+ { /* getsockopt() could suceed */
+ errno = s_err;
+ return(-1); /* but return an error... */
+ }
+ return(0); /* It's all good! */
+#endif
+}
+#endif /* 0 */
+
+/*
+** Create a named pipe connection
+*/
+
+#ifdef __WIN__
+
+HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host,
+ char **arg_unix_socket)
+{
+ HANDLE hPipe=INVALID_HANDLE_VALUE;
+ char szPipeName [ 257 ];
+ DWORD dwMode;
+ int i;
+ my_bool testing_named_pipes=0;
+ char *host= *arg_host, *unix_socket= *arg_unix_socket;
+
+ if ( ! unix_socket || (unix_socket)[0] == 0x00)
+ unix_socket = mysql_unix_port;
+ if (!host || !strcmp(host,LOCAL_HOST))
+ host=LOCAL_HOST_NAMEDPIPE;
+
+ sprintf( szPipeName, "\\\\%s\\pipe\\%s", host, unix_socket);
+ DBUG_PRINT("info",("Server name: '%s'. Named Pipe: %s",
+ host, unix_socket));
+
+ for (i=0 ; i < 100 ; i++) /* Don't retry forever */
+ {
+ if ((hPipe = CreateFile(szPipeName,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL )) != INVALID_HANDLE_VALUE)
+ break;
+ if (GetLastError() != ERROR_PIPE_BUSY)
+ {
+ net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ /* wait for for an other instance */
+ if (! WaitNamedPipe(szPipeName, connect_timeout*1000) )
+ {
+ net->last_errno=CR_NAMEDPIPEWAIT_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ }
+ if (hPipe == INVALID_HANDLE_VALUE)
+ {
+ net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
+ if ( !SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL) )
+ {
+ CloseHandle( hPipe );
+ net->last_errno=CR_NAMEDPIPESETSTATE_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ *arg_host=host ; *arg_unix_socket=unix_socket; /* connect arg */
+ return (hPipe);
+}
+#endif
+
+
+/*****************************************************************************
+** read a packet from server. Give error message if socket was down
+** or packet is an error message
+*****************************************************************************/
+
+static uint
+net_safe_read(MYSQL *mysql)
+{
+ NET *net= &mysql->net;
+ uint len=0;
+ //init_sigpipe_variables
+ /* Don't give sigpipe errors if the client doesn't want them */
+ set_sigpipe(mysql);
+ if (net->vio != 0)
+ len=my_net_read(net);
+ reset_sigpipe(mysql);
+ if (len == packet_error || len == 0)
+ {
+ DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %d",
+ vio_description(net->vio),len));
+ end_server(mysql);
+ net->last_errno=(net->last_errno == ER_NET_PACKET_TOO_LARGE ?
+ CR_NET_PACKET_TOO_LARGE:
+ CR_SERVER_LOST);
+ strmov(net->last_error,ER(net->last_errno));
+ return(packet_error);
+ }
+ if (net->read_pos[0] == 255)
+ {
+
+ if (len > 3)
+ {
+ char *pos=(char*) net->read_pos+1;
+ if (mysql->protocol_version > 9)
+ { /* New client protocol */
+ net->last_errno=uint2korr(pos);
+ pos+=2;
+ len-=2;
+ }
+ else
+ {
+ net->last_errno=CR_UNKNOWN_ERROR;
+ len--;
+ }
+ (void) strmake(net->last_error,(char*) pos,
+ min(len,sizeof(net->last_error)-1));
+ }
+ else
+ {
+ net->last_errno=CR_UNKNOWN_ERROR;
+ (void) strmov(net->last_error,ER(net->last_errno));
+ }
+ DBUG_PRINT("error",("Got error: %d (%s)", net->last_errno,
+ net->last_error));
+ return(packet_error);
+ }
+ return len;
+}
+
+
+/* Get the length of next field. Change parameter to point at fieldstart */
+static ulong
+net_field_length(uchar **packet)
+{
+ reg1 uchar *pos= *packet;
+ if (*pos < 251)
+ {
+ (*packet)++;
+ return (ulong) *pos;
+ }
+ if (*pos == 251)
+ {
+ (*packet)++;
+ return NULL_LENGTH;
+ }
+ if (*pos == 252)
+ {
+ (*packet)+=3;
+ return (ulong) uint2korr(pos+1);
+ }
+ if (*pos == 253)
+ {
+ (*packet)+=4;
+ return (ulong) uint3korr(pos+1);
+ }
+ (*packet)+=9; /* Must be 254 when here */
+ return (ulong) uint4korr(pos+1);
+}
+
+/* Same as above, but returns ulonglong values */
+
+static my_ulonglong
+net_field_length_ll(uchar **packet)
+{
+ reg1 uchar *pos= *packet;
+ if (*pos < 251)
+ {
+ (*packet)++;
+ return (my_ulonglong) *pos;
+ }
+ if (*pos == 251)
+ {
+ (*packet)++;
+ return (my_ulonglong) NULL_LENGTH;
+ }
+ if (*pos == 252)
+ {
+ (*packet)+=3;
+ return (my_ulonglong) uint2korr(pos+1);
+ }
+ if (*pos == 253)
+ {
+ (*packet)+=4;
+ return (my_ulonglong) uint3korr(pos+1);
+ }
+ (*packet)+=9; /* Must be 254 when here */
+#ifdef NO_CLIENT_LONGLONG
+ return (my_ulonglong) uint4korr(pos+1);
+#else
+ return (my_ulonglong) uint8korr(pos+1);
+#endif
+}
+
+
+static void free_rows(MYSQL_DATA *cur)
+{
+ if (cur)
+ {
+ free_root(&cur->alloc,MYF(0));
+ my_free((gptr) cur,MYF(0));
+ }
+}
+
+
+static int
+simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
+ uint length, my_bool skipp_check)
+{
+ NET *net= &mysql->net;
+ int result= -1;
+ init_sigpipe_variables
+
+ /* Don't give sigpipe errors if the client doesn't want them */
+ set_sigpipe(mysql);
+ if (mysql->net.vio == 0)
+ { /* Do reconnect if possible */
+ if (mysql_reconnect(mysql))
+ {
+ net->last_errno=CR_SERVER_GONE_ERROR;
+ strmov(net->last_error,ER(net->last_errno));
+ goto end;
+ }
+ }
+ if (mysql->status != MYSQL_STATUS_READY)
+ {
+ strmov(net->last_error,ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
+ goto end;
+ }
+
+ mysql->net.last_error[0]=0;
+ mysql->net.last_errno=0;
+ mysql->info=0;
+ mysql->affected_rows= ~(my_ulonglong) 0;
+
+ /* Clear receive buffer and vio packet list */
+ net_clear(net);
+ vio_reset(net->vio);
+
+ if (!arg)
+ arg="";
+
+ result = lib_dispatch_command(command, net, arg,
+ length ? length : (ulong) strlen(arg));
+#if 0
+ if (net_write_command(net,(uchar) command,arg,
+ length ? length : (ulong) strlen(arg)))
+ {
+ DBUG_PRINT("error",("Can't send command to server. Error: %d",errno));
+ end_server(mysql);
+ if (mysql_reconnect(mysql) ||
+ net_write_command(net,(uchar) command,arg,
+ length ? length : (ulong) strlen(arg)))
+ {
+ net->last_errno=CR_SERVER_GONE_ERROR;
+ strmov(net->last_error,ER(net->last_errno));
+ goto end;
+ }
+ }
+#endif
+ if (!skipp_check)
+ result= ((mysql->packet_length=net_safe_read(mysql)) == packet_error ?
+ -1 : 0);
+ end:
+ reset_sigpipe(mysql);
+ return result;
+}
+
+
+static void free_old_query(MYSQL *mysql)
+{
+ DBUG_ENTER("free_old_query");
+ if (mysql->fields)
+ free_root(&mysql->field_alloc,MYF(0));
+ init_alloc_root(&mysql->field_alloc,8192,0); /* Assume rowlength < 8192 */
+ mysql->fields=0;
+ mysql->field_count=0; /* For API */
+ DBUG_VOID_RETURN;
+}
+
+#ifdef HAVE_GETPWUID
+struct passwd *getpwuid(uid_t);
+char* getlogin(void);
+#endif
+
+#if !defined(MSDOS) && ! defined(VMS) && !defined(__WIN__)
+static void read_user_name(char *name)
+{
+ DBUG_ENTER("read_user_name");
+ if (geteuid() == 0)
+ (void) strmov(name,"root"); /* allow use of surun */
+ else
+ {
+#ifdef HAVE_GETPWUID
+ struct passwd *skr;
+ const char *str;
+/*#ifdef __cplusplus
+ extern "C" struct passwd *getpwuid(uid_t);
+ extern "C" { char* getlogin(void); }
+#else
+ char * getlogin();
+ struct passwd *getpwuid(uid_t);
+#endif
+*/
+ if ((str=getlogin()) == NULL)
+ {
+ if ((skr=getpwuid(geteuid())) != NULL)
+ str=skr->pw_name;
+ else if (!(str=getenv("USER")) && !(str=getenv("LOGNAME")) &&
+ !(str=getenv("LOGIN")))
+ str="UNKNOWN_USER";
+ }
+ (void) strmake(name,str,USERNAME_LENGTH);
+#elif HAVE_CUSERID
+ (void) cuserid(name);
+#else
+ strmov(name,"UNKNOWN_USER");
+#endif
+ }
+ DBUG_VOID_RETURN;
+}
+
+#else /* If MSDOS || VMS */
+
+static void read_user_name(char *name)
+{
+ char *str=getenv("USER");
+ strmov(name,str ? str : "ODBC"); /* ODBC will send user variable */
+}
+
+#endif
+
+#ifdef __WIN__
+static my_bool is_NT(void)
+{
+ char *os=getenv("OS");
+ return (os && !strcmp(os, "Windows_NT")) ? 1 : 0;
+}
+#endif
+
+/*
+** Expand wildcard to a sql string
+*/
+
+static void
+append_wild(char *to, char *end, const char *wild)
+{
+ end-=5; /* Some extra */
+ if (wild && wild[0])
+ {
+ to=strmov(to," like '");
+ while (*wild && to < end)
+ {
+ if (*wild == '\\' || *wild == '\'')
+ *to++='\\';
+ *to++= *wild++;
+ }
+ if (*wild) /* Too small buffer */
+ *to++='%'; /* Nicer this way */
+ to[0]='\'';
+ to[1]=0;
+ }
+}
+
+
+
+/**************************************************************************
+** Init debugging if MYSQL_DEBUG environment variable is found
+**************************************************************************/
+
+void STDCALL
+mysql_debug(const char *debug)
+{
+#ifndef DBUG_OFF
+ char *env;
+ if (_db_on_)
+ return; /* Already using debugging */
+ if (debug)
+ {
+ DEBUGGER_ON;
+ DBUG_PUSH(debug);
+ }
+ else if ((env = getenv("MYSQL_DEBUG")))
+ {
+ DEBUGGER_ON;
+ DBUG_PUSH(env);
+#if !defined(_WINVER) && !defined(WINVER)
+ puts("\n-------------------------------------------------------");
+ puts("MYSQL_DEBUG found. libmysql started with the following:");
+ puts(env);
+ puts("-------------------------------------------------------\n");
+#else
+ {
+ char buff[80];
+ strmov(strmov(buff,"libmysql: "),env);
+ MessageBox((HWND) 0,"Debugging variable MYSQL_DEBUG used",buff,MB_OK);
+ }
+#endif
+ }
+#endif
+}
+
+
+/**************************************************************************
+** Close the server connection if we get a SIGPIPE
+ ARGSUSED
+**************************************************************************/
+
+static sig_handler
+pipe_sig_handler(int sig __attribute__((unused)))
+{
+ DBUG_PRINT("info",("Hit by signal %d",sig));
+#ifdef DONT_REMEMBER_SIGNAL
+ (void) signal(SIGPIPE,pipe_sig_handler);
+#endif
+}
+
+
+/**************************************************************************
+** Shut down connection
+**************************************************************************/
+
+static void
+end_server(MYSQL *mysql)
+{
+ DBUG_ENTER("end_server");
+ if (mysql->net.vio != 0)
+ {
+ init_sigpipe_variables
+ DBUG_PRINT("info",("Net: %s", vio_description(mysql->net.vio)));
+ set_sigpipe(mysql);
+ vio_delete(mysql->net.vio);
+ reset_sigpipe(mysql);
+ mysql->net.vio= 0; /* Marker */
+ }
+ net_end(&mysql->net);
+ free_old_query(mysql);
+ DBUG_VOID_RETURN;
+}
+
+
+void STDCALL
+mysql_free_result(MYSQL_RES *result)
+{
+ DBUG_ENTER("mysql_free_result");
+ DBUG_PRINT("enter",("mysql_res: %lx",result));
+ if (result)
+ {
+ if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT)
+ {
+ DBUG_PRINT("warning",("Not all rows in set were read; Ignoring rows"));
+ for (;;)
+ {
+ uint pkt_len;
+ if ((pkt_len=(uint) net_safe_read(result->handle)) == packet_error)
+ break;
+ if (pkt_len == 1 && result->handle->net.read_pos[0] == 254)
+ break; /* End of data */
+ }
+ result->handle->status=MYSQL_STATUS_READY;
+ }
+ free_rows(result->data);
+ if (result->fields)
+ free_root(&result->field_alloc,MYF(0));
+ if (result->row)
+ my_free((gptr) result->row,MYF(0));
+ my_free((gptr) result,MYF(0));
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/****************************************************************************
+** Get options from my.cnf
+****************************************************************************/
+
+static const char *default_options[]=
+{"port","socket","compress","password","pipe", "timeout", "user",
+ "init-command", "host", "database", "debug", "return-found-rows",
+ "ssl_key" ,"ssl_cert" ,"ssl_ca" ,"ssl_capath",
+ "character-set-dir", "default-character-set",
+ NullS
+};
+
+static TYPELIB option_types={array_elements(default_options)-1,
+ "options",default_options};
+
+static void mysql_read_default_options(struct st_mysql_options *options,
+ const char *filename,const char *group)
+{
+ int argc;
+ char *argv_buff[1],**argv;
+ const char *groups[3];
+ DBUG_ENTER("mysql_read_default_options");
+ DBUG_PRINT("enter",("file: %s group: %s",filename,group ? group :"NULL"));
+
+ argc=1; argv=argv_buff; argv_buff[0]= (char*) "client";
+ groups[0]= (char*) "client"; groups[1]= (char*) group; groups[2]=0;
+
+ load_defaults(filename, groups, &argc, &argv);
+ if (argc != 1) /* If some default option */
+ {
+ char **option=argv;
+ while (*++option)
+ {
+ /* DBUG_PRINT("info",("option: %s",option[0])); */
+ if (option[0][0] == '-' && option[0][1] == '-')
+ {
+ char *end=strcend(*option,'=');
+ char *opt_arg=0;
+ if (*end)
+ {
+ opt_arg=end+1;
+ *end=0; /* Remove '=' */
+ }
+ switch (find_type(*option+2,&option_types,2)) {
+ case 1: /* port */
+ if (opt_arg)
+ options->port=atoi(opt_arg);
+ break;
+ case 2: /* socket */
+ if (opt_arg)
+ {
+ my_free(options->unix_socket,MYF(MY_ALLOW_ZERO_PTR));
+ options->unix_socket=my_strdup(opt_arg,MYF(MY_WME));
+ }
+ break;
+ case 3: /* compress */
+ options->compress=1;
+ break;
+ case 4: /* password */
+ if (opt_arg)
+ {
+ my_free(options->password,MYF(MY_ALLOW_ZERO_PTR));
+ options->password=my_strdup(opt_arg,MYF(MY_WME));
+ }
+ break;
+ case 5: /* pipe */
+ options->named_pipe=1; /* Force named pipe */
+ break;
+ case 6: /* timeout */
+ if (opt_arg)
+ options->connect_timeout=atoi(opt_arg);
+ break;
+ case 7: /* user */
+ if (opt_arg)
+ {
+ my_free(options->user,MYF(MY_ALLOW_ZERO_PTR));
+ options->user=my_strdup(opt_arg,MYF(MY_WME));
+ }
+ break;
+ case 8: /* init-command */
+ if (opt_arg)
+ {
+ my_free(options->init_command,MYF(MY_ALLOW_ZERO_PTR));
+ options->init_command=my_strdup(opt_arg,MYF(MY_WME));
+ }
+ break;
+ case 9: /* host */
+ if (opt_arg)
+ {
+ my_free(options->host,MYF(MY_ALLOW_ZERO_PTR));
+ options->host=my_strdup(opt_arg,MYF(MY_WME));
+ }
+ break;
+ case 10: /* database */
+ if (opt_arg)
+ {
+ my_free(options->db,MYF(MY_ALLOW_ZERO_PTR));
+ options->db=my_strdup(opt_arg,MYF(MY_WME));
+ }
+ break;
+ case 11: /* debug */
+ mysql_debug(opt_arg ? opt_arg : "d:t:o,/tmp/client.trace");
+ break;
+ case 12: /* return-found-rows */
+ options->client_flag|=CLIENT_FOUND_ROWS;
+ break;
+ case 13: /* Ignore SSL options */
+ case 14:
+ case 15:
+ case 16:
+ break;
+ case 17: /* charset-lib */
+ my_free(options->charset_dir,MYF(MY_ALLOW_ZERO_PTR));
+ options->charset_dir = my_strdup(opt_arg, MYF(MY_WME));
+ break;
+ case 18:
+ my_free(options->charset_name,MYF(MY_ALLOW_ZERO_PTR));
+ options->charset_name = my_strdup(opt_arg, MYF(MY_WME));
+ break;
+ default:
+ DBUG_PRINT("warning",("unknown option: %s",option[0]));
+ }
+ }
+ }
+ }
+ free_defaults(argv);
+ DBUG_VOID_RETURN;
+}
+
+
+/***************************************************************************
+** Change field rows to field structs
+***************************************************************************/
+
+static MYSQL_FIELD *
+unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
+ my_bool default_value, my_bool long_flag_protocol)
+{
+ MYSQL_ROWS *row;
+ MYSQL_FIELD *field,*result;
+ DBUG_ENTER("unpack_fields");
+
+ field=result=(MYSQL_FIELD*) alloc_root(alloc,sizeof(MYSQL_FIELD)*fields);
+ if (!result)
+ DBUG_RETURN(0);
+
+ for (row=data->data; row ; row = row->next,field++)
+ {
+ field->table= strdup_root(alloc,(char*) row->data[0]);
+ field->name= strdup_root(alloc,(char*) row->data[1]);
+ field->length= (uint) uint3korr(row->data[2]);
+ field->type= (enum enum_field_types) (uchar) row->data[3][0];
+ if (long_flag_protocol)
+ {
+ field->flags= uint2korr(row->data[4]);
+ field->decimals=(uint) (uchar) row->data[4][2];
+ }
+ else
+ {
+ field->flags= (uint) (uchar) row->data[4][0];
+ field->decimals=(uint) (uchar) row->data[4][1];
+ }
+ if (INTERNAL_NUM_FIELD(field))
+ field->flags|= NUM_FLAG;
+ if (default_value && row->data[5])
+ field->def=strdup_root(alloc,(char*) row->data[5]);
+ else
+ field->def=0;
+ field->max_length= 0;
+ }
+ free_rows(data); /* Free old data */
+ DBUG_RETURN(result);
+}
+
+
+/* Read all rows (fields or data) from server */
+
+static MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
+ uint fields)
+{
+ uint field,pkt_len;
+ ulong len;
+ uchar *cp;
+ char *to;
+ MYSQL_DATA *result;
+ MYSQL_ROWS **prev_ptr,*cur;
+ NET *net = &mysql->net;
+ DBUG_ENTER("read_rows");
+
+ if ((pkt_len=(uint) net_safe_read(mysql)) == packet_error)
+ DBUG_RETURN(0);
+ if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA),
+ MYF(MY_WME | MY_ZEROFILL))))
+ {
+ net->last_errno=CR_OUT_OF_MEMORY;
+ strmov(net->last_error,ER(net->last_errno));
+ DBUG_RETURN(0);
+ }
+ init_alloc_root(&result->alloc,8192,0); /* Assume rowlength < 8192 */
+ result->alloc.min_malloc=sizeof(MYSQL_ROWS);
+ prev_ptr= &result->data;
+ result->rows=0;
+ result->fields=fields;
+
+ while (*(cp=net->read_pos) != 254 || pkt_len != 1)
+ {
+ result->rows++;
+ if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc,
+ sizeof(MYSQL_ROWS))) ||
+ !(cur->data= ((MYSQL_ROW)
+ alloc_root(&result->alloc,
+ (fields+1)*sizeof(char *)+pkt_len))))
+ {
+ free_rows(result);
+ net->last_errno=CR_OUT_OF_MEMORY;
+ strmov(net->last_error,ER(net->last_errno));
+ DBUG_RETURN(0);
+ }
+ *prev_ptr=cur;
+ prev_ptr= &cur->next;
+ to= (char*) (cur->data+fields+1);
+ for (field=0 ; field < fields ; field++)
+ {
+ if ((len=(ulong) net_field_length(&cp)) == NULL_LENGTH)
+ { /* null field */
+ cur->data[field] = 0;
+ }
+ else
+ {
+ cur->data[field] = to;
+ memcpy(to,(char*) cp,len); to[len]=0;
+ to+=len+1;
+ cp+=len;
+ if (mysql_fields)
+ {
+ if (mysql_fields[field].max_length < len)
+ mysql_fields[field].max_length=len;
+ }
+ }
+ }
+ cur->data[field]=to; /* End of last field */
+ if ((pkt_len=net_safe_read(mysql)) == packet_error)
+ {
+ free_rows(result);
+ DBUG_RETURN(0);
+ }
+ }
+ *prev_ptr=0; /* last pointer is null */
+ DBUG_PRINT("exit",("Got %d rows",result->rows));
+ DBUG_RETURN(result);
+}
+
+
+/*
+** Read one row. Uses packet buffer as storage for fields.
+** When next packet is read, the previous field values are destroyed
+*/
+
+
+static int
+read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
+{
+ uint field;
+ ulong pkt_len,len;
+ uchar *pos,*prev_pos;
+
+ if ((pkt_len=(uint) net_safe_read(mysql)) == packet_error)
+ return -1;
+ if (pkt_len == 1 && mysql->net.read_pos[0] == 254)
+ return 1; /* End of data */
+ prev_pos= 0; /* allowed to write at packet[-1] */
+ pos=mysql->net.read_pos;
+ for (field=0 ; field < fields ; field++)
+ {
+ if ((len=(ulong) net_field_length(&pos)) == NULL_LENGTH)
+ { /* null field */
+ row[field] = 0;
+ *lengths++=0;
+ }
+ else
+ {
+ row[field] = (char*) pos;
+ pos+=len;
+ *lengths++=len;
+ }
+ if (prev_pos)
+ *prev_pos=0; /* Terminate prev field */
+ prev_pos=pos;
+ }
+ row[field]=(char*) prev_pos+1; /* End of last field */
+ *prev_pos=0; /* Terminate last field */
+ return 0;
+}
+
+/****************************************************************************
+** Init MySQL structure or allocate one
+****************************************************************************/
+
+MYSQL * STDCALL
+mysql_init(MYSQL *mysql)
+{
+ mysql_once_init();
+ if (!mysql)
+ {
+ if (!(mysql=(MYSQL*) my_malloc(sizeof(*mysql),MYF(MY_WME | MY_ZEROFILL))))
+ return 0;
+ mysql->free_me=1;
+ mysql->net.vio = 0;
+ }
+ else
+ bzero((char*) (mysql),sizeof(*(mysql)));
+ return mysql;
+}
+
+
+static void mysql_once_init()
+{
+ if (!mysql_client_init)
+ {
+ mysql_client_init=1;
+ my_init(); /* Will init threads */
+ embedded_srv_init();
+ init_client_errs();
+ mysql_port = MYSQL_PORT;
+ mysql_debug(NullS);
+ }
+#ifdef THREAD
+ else
+ my_thread_init(); /* Init if new thread */
+#endif
+}
+
+/**************************************************************************
+** Connect to sql server
+** If host == 0 then use localhost
+**************************************************************************/
+
+MYSQL * STDCALL
+mysql_connect(MYSQL *mysql,const char *host,
+ const char *user, const char *passwd)
+{
+ MYSQL *res;
+ mysql=mysql_init(mysql); /* Make it thread safe */
+ {
+ DBUG_ENTER("mysql_connect");
+ if (!(res=mysql_real_connect(mysql,host,user,passwd,NullS,0,NullS,0)))
+ {
+ if (mysql->free_me)
+ my_free((gptr) mysql,MYF(0));
+ }
+ DBUG_RETURN(res);
+ }
+}
+
+
+/*
+** Note that the mysql argument must be initialized with mysql_init()
+** before calling mysql_real_connect !
+*/
+
+MYSQL * STDCALL
+mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
+ const char *passwd, const char *db,
+ uint port, const char *unix_socket,uint client_flag)
+{
+ char buff[100],charset_name_buff[16],*end,*host_info, *charset_name;
+ my_socket sock;
+ uint pkt_length;
+ NET *net= &mysql->net;
+ DBUG_ENTER("mysql_real_connect");
+ DBUG_PRINT("enter",("host: %s db: %s user: %s",
+ host ? host : "(Null)",
+ db ? db : "(Null)",
+ user ? user : "(Null)"));
+
+ net->vio = 0; /* If something goes wrong */
+ /* use default options */
+ if (mysql->options.my_cnf_file || mysql->options.my_cnf_group)
+ {
+ mysql_read_default_options(&mysql->options,
+ (mysql->options.my_cnf_file ?
+ mysql->options.my_cnf_file : "my"),
+ mysql->options.my_cnf_group);
+ my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->options.my_cnf_file=mysql->options.my_cnf_group=0;
+ }
+
+ /* Some empty-string-tests are done because of ODBC */
+ if (!host || !host[0])
+ host=mysql->options.host;
+ if (!user || !user[0])
+ user=mysql->options.user;
+ if (!passwd)
+ {
+ passwd=mysql->options.password;
+#ifndef DONT_USE_MYSQL_PWD
+ if (!passwd)
+ passwd=getenv("MYSQL_PWD"); /* get it from environment (haneke) */
+#endif
+ }
+ if (!db || !db[0])
+ db=mysql->options.db;
+ if (!port)
+ port=mysql->options.port;
+ if (!unix_socket)
+ unix_socket=mysql->options.unix_socket;
+
+ mysql->reconnect=1; /* Reconnect as default */
+ mysql->server_status=SERVER_STATUS_AUTOCOMMIT;
+
+ /*
+ ** Grab a socket and connect it to the server
+ */
+
+ unix_socket=0; /* This is not used */
+ if (!port)
+ port=mysql_port;
+ if (!host)
+ host=LOCAL_HOST;
+ sprintf(host_info=buff,ER(CR_TCP_CONNECTION),host);
+ DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host,port));
+ /* _WIN64 ; Assume that the (int) range is enough for socket() */
+ if ((sock = (my_socket) socket(AF_INET,SOCK_STREAM,0)) == SOCKET_ERROR)
+ {
+ net->last_errno=CR_IPSOCK_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),ERRNO);
+ goto error;
+ }
+
+ if (my_net_init(net, net->vio))
+ {
+ vio_delete(net->vio);
+ net->last_errno=CR_OUT_OF_MEMORY;
+ strmov(net->last_error,ER(net->last_errno));
+ goto error;
+ }
+
+ /* Get version info */
+ mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */
+ start_embedded_connection(net);
+
+ if ((pkt_length=net_safe_read(mysql)) == packet_error)
+ goto error;
+
+ /* Check if version of protocoll matches current one */
+
+ mysql->protocol_version= net->read_pos[0];
+ DBUG_DUMP("packet",(char*) net->read_pos,10);
+ DBUG_PRINT("info",("mysql protocol version %d, server=%d",
+ PROTOCOL_VERSION, mysql->protocol_version));
+ if (mysql->protocol_version != PROTOCOL_VERSION &&
+ mysql->protocol_version != PROTOCOL_VERSION-1)
+ {
+ net->last_errno= CR_VERSION_ERROR;
+ sprintf(net->last_error, ER(CR_VERSION_ERROR), mysql->protocol_version,
+ PROTOCOL_VERSION);
+ goto error;
+ }
+ end=strend((char*) net->read_pos+1);
+ mysql->thread_id=uint4korr(end+1);
+ end+=5;
+ strmake(mysql->scramble_buff,end,8);
+ end+=9;
+ if (pkt_length >= (uint) (end+1 - (char*) net->read_pos))
+ mysql->server_capabilities=uint2korr(end);
+ if (pkt_length >= (uint) (end+18 - (char*) net->read_pos))
+ {
+ /* New protocol with 16 bytes to describe server characteristics */
+ mysql->server_language=end[2];
+ mysql->server_status=uint2korr(end+3);
+ }
+
+ /* Set character set */
+ if ((charset_name=mysql->options.charset_name))
+ {
+ const char *save=charsets_dir;
+ if (mysql->options.charset_dir)
+ charsets_dir=mysql->options.charset_dir;
+ mysql->charset=get_charset_by_name(mysql->options.charset_name,
+ MYF(MY_WME));
+ charsets_dir=save;
+ }
+ else if (mysql->server_language)
+ {
+ charset_name=charset_name_buff;
+ sprintf(charset_name,"%d",mysql->server_language); /* In case of errors */
+ mysql->charset=get_charset((uint8) mysql->server_language, MYF(MY_WME));
+ }
+ else
+ mysql->charset=default_charset_info;
+
+ if (!mysql->charset)
+ {
+ net->last_errno=CR_CANT_READ_CHARSET;
+ if (mysql->options.charset_dir)
+ sprintf(net->last_error,ER(net->last_errno),
+ charset_name ? charset_name : "unknown",
+ mysql->options.charset_dir);
+ else
+ {
+ char cs_dir_name[FN_REFLEN];
+ get_charsets_dir(cs_dir_name);
+ sprintf(net->last_error,ER(net->last_errno),
+ charset_name ? charset_name : "unknown",
+ cs_dir_name);
+ }
+ goto error;
+ }
+
+ /* Save connection information */
+ if (!user) user="";
+ if (!passwd) passwd="";
+ if (!my_multi_malloc(MYF(0),
+ &mysql->host_info, (uint) strlen(host_info)+1,
+ &mysql->host, (uint) strlen(host)+1,
+ &mysql->unix_socket,unix_socket ?
+ (uint) strlen(unix_socket)+1 : (uint) 1,
+ &mysql->server_version,
+ (uint) (end - (char*) net->read_pos),
+ NullS) ||
+ !(mysql->user=my_strdup(user,MYF(0))) ||
+ !(mysql->passwd=my_strdup(passwd,MYF(0))))
+ {
+ strmov(net->last_error, ER(net->last_errno=CR_OUT_OF_MEMORY));
+ goto error;
+ }
+ strmov(mysql->host_info,host_info);
+ strmov(mysql->host,host);
+ if (unix_socket)
+ strmov(mysql->unix_socket,unix_socket);
+ else
+ mysql->unix_socket=0;
+ strmov(mysql->server_version,(char*) net->read_pos+1);
+ mysql->port=port;
+ mysql->client_flag=client_flag | mysql->options.client_flag;
+ DBUG_PRINT("info",("Server version = '%s' capabilites: %ld status: %d",
+ mysql->server_version,mysql->server_capabilities,
+ mysql->server_status));
+
+ /* Send client information for access check */
+ client_flag|=CLIENT_CAPABILITIES;
+
+
+ if (db)
+ client_flag|=CLIENT_CONNECT_WITH_DB;
+
+ client_flag&= ~CLIENT_COMPRESS;
+
+
+ int2store(buff,client_flag);
+ mysql->client_flag=client_flag;
+
+
+ int3store(buff+2,max_allowed_packet);
+ if (user && user[0])
+ strmake(buff+5,user,32);
+ else
+ read_user_name((char*) buff+5);
+#ifdef _CUSTOMCONFIG_
+#include "_cust_libmysql.h";
+#endif
+ DBUG_PRINT("info",("user: %s",buff+5));
+ end=scramble(strend(buff+5)+1, mysql->scramble_buff, passwd,
+ (my_bool) (mysql->protocol_version == 9));
+ if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
+ {
+ end=strmov(end+1,db);
+ mysql->db=my_strdup(db,MYF(MY_WME));
+ db=0;
+ }
+ if (my_net_write(net,buff,(uint) (end-buff)) || net_flush(net))
+ goto error;
+
+ lib_connection_phase(net,2);
+
+ if( net_safe_read(mysql) == packet_error)
+ goto error;
+ if (client_flag & CLIENT_COMPRESS) /* We will use compression */
+ net->compress=1;
+ if (db && mysql_select_db(mysql,db))
+ goto error;
+ if (mysql->options.init_command)
+ {
+ my_bool reconnect=mysql->reconnect;
+ mysql->reconnect=0;
+ if (mysql_query(mysql,mysql->options.init_command))
+ goto error;
+ mysql_free_result(mysql_use_result(mysql));
+ mysql->reconnect=reconnect;
+ }
+
+ DBUG_PRINT("exit",("Mysql handler: %lx",mysql));
+ reset_sigpipe(mysql);
+ DBUG_RETURN(mysql);
+
+error:
+ reset_sigpipe(mysql);
+ DBUG_PRINT("error",("message: %u (%s)",net->last_errno,net->last_error));
+ {
+ /* Free alloced memory */
+ my_bool free_me=mysql->free_me;
+ end_server(mysql);
+ mysql->free_me=0;
+ mysql_close(mysql);
+ mysql->free_me=free_me;
+ }
+ DBUG_RETURN(0);
+}
+
+
+static my_bool mysql_reconnect(MYSQL *mysql)
+{
+ MYSQL tmp_mysql;
+ DBUG_ENTER("mysql_reconnect");
+
+ if (!mysql->reconnect ||
+ (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info)
+ {
+ /* Allov reconnect next time */
+ mysql->server_status&= ~SERVER_STATUS_IN_TRANS;
+ DBUG_RETURN(1);
+ }
+ mysql_init(&tmp_mysql);
+ tmp_mysql.options=mysql->options;
+ if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
+ mysql->db, mysql->port, mysql->unix_socket,
+ mysql->client_flag))
+ DBUG_RETURN(1);
+ tmp_mysql.free_me=mysql->free_me;
+ mysql->free_me=0;
+ bzero((char*) &mysql->options,sizeof(mysql->options));
+ mysql_close(mysql);
+ *mysql=tmp_mysql;
+ net_clear(&mysql->net);
+ mysql->affected_rows= ~(my_ulonglong) 0;
+ DBUG_RETURN(0);
+}
+
+
+/**************************************************************************
+** Change user and database
+**************************************************************************/
+
+my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
+ const char *passwd, const char *db)
+{
+ char buff[512],*pos=buff;
+ DBUG_ENTER("mysql_change_user");
+
+ if (!user)
+ user="";
+ if (!passwd)
+ passwd="";
+
+ pos=strmov(pos,user)+1;
+ pos=scramble(pos, mysql->scramble_buff, passwd,
+ (my_bool) (mysql->protocol_version == 9));
+ pos=strmov(pos+1,db ? db : "");
+ if (simple_command(mysql,COM_CHANGE_USER, buff,(uint) (pos-buff),0))
+ DBUG_RETURN(1);
+
+ my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
+
+ mysql->user= my_strdup(user,MYF(MY_WME));
+ mysql->passwd=my_strdup(passwd,MYF(MY_WME));
+ mysql->db= db ? my_strdup(db,MYF(MY_WME)) : 0;
+ DBUG_RETURN(0);
+}
+
+
+/**************************************************************************
+** Set current database
+**************************************************************************/
+
+int STDCALL
+mysql_select_db(MYSQL *mysql, const char *db)
+{
+ int error;
+ DBUG_ENTER("mysql_select_db");
+ DBUG_PRINT("enter",("db: '%s'",db));
+
+ if ((error=simple_command(mysql,COM_INIT_DB,db,(uint) strlen(db),0)))
+ DBUG_RETURN(error);
+ my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->db=my_strdup(db,MYF(MY_WME));
+ DBUG_RETURN(0);
+}
+
+
+/*************************************************************************
+** Send a QUIT to the server and close the connection
+** If handle is alloced by mysql connect free it.
+*************************************************************************/
+
+void STDCALL
+mysql_close(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_close");
+ if (mysql) /* Some simple safety */
+ {
+ if (mysql->net.vio != 0)
+ {
+ free_old_query(mysql);
+ mysql->status=MYSQL_STATUS_READY; /* Force command */
+ simple_command(mysql,COM_QUIT,NullS,0,1);
+ end_server(mysql);
+ }
+ my_free((gptr) mysql->host_info,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.init_command,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.user,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.host,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.password,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.unix_socket,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.db,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.charset_dir,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR));
+ /* Clear pointers for better safety */
+ mysql->host_info=mysql->user=mysql->passwd=mysql->db=0;
+ bzero((char*) &mysql->options,sizeof(mysql->options));
+ mysql->net.vio = 0;
+#ifdef HAVE_OPENSSL
+ ((VioConnectorFd*)(mysql->connector_fd))->delete();
+ mysql->connector_fd = 0;
+#endif /* HAVE_OPENSSL */
+ if (mysql->free_me)
+ my_free((gptr) mysql,MYF(0));
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/**************************************************************************
+** Do a query. If query returned rows, free old rows.
+** Read data by mysql_store_result or by repeat call of mysql_fetch_row
+**************************************************************************/
+
+int STDCALL
+mysql_query(MYSQL *mysql, const char *query)
+{
+ return mysql_real_query(mysql,query, (uint) strlen(query));
+}
+
+
+int STDCALL
+mysql_real_query(MYSQL *mysql, const char *query, uint length)
+{
+ uchar *pos;
+ ulong field_count;
+ MYSQL_DATA *fields;
+ DBUG_ENTER("mysql_real_query");
+ DBUG_PRINT("enter",("handle: %lx",mysql));
+ DBUG_PRINT("query",("Query = \"%s\"",query));
+
+ if (simple_command(mysql,COM_QUERY,query,length,1) ||
+ (length=net_safe_read(mysql)) == packet_error)
+ DBUG_RETURN(-1);
+ free_old_query(mysql); /* Free old result */
+ get_info:
+ pos=(uchar*) mysql->net.read_pos;
+ if ((field_count= net_field_length(&pos)) == 0)
+ {
+ mysql->affected_rows= net_field_length_ll(&pos);
+ mysql->insert_id= net_field_length_ll(&pos);
+ if (mysql->server_capabilities & CLIENT_TRANSACTIONS)
+ {
+ mysql->server_status=uint2korr(pos); pos+=2;
+ }
+ if (pos < mysql->net.read_pos+length && net_field_length(&pos))
+ mysql->info=(char*) pos;
+ DBUG_RETURN(0);
+ }
+ if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
+ {
+ int error=send_file_to_server(mysql,(char*) pos);
+ if ((length=net_safe_read(mysql)) == packet_error || error)
+ DBUG_RETURN(-1);
+ goto get_info; /* Get info packet */
+ }
+ if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
+ mysql->server_status|= SERVER_STATUS_IN_TRANS;
+
+ mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */
+ if (!(fields=read_rows(mysql,(MYSQL_FIELD*) 0,5)))
+ DBUG_RETURN(-1);
+ if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,
+ (uint) field_count,0,
+ (my_bool) test(mysql->server_capabilities &
+ CLIENT_LONG_FLAG))))
+ DBUG_RETURN(-1);
+ mysql->status=MYSQL_STATUS_GET_RESULT;
+ mysql->field_count=field_count;
+ DBUG_RETURN(0);
+}
+
+
+static int
+send_file_to_server(MYSQL *mysql, const char *filename)
+{
+ int fd, readcount;
+ char buf[IO_SIZE*15],*tmp_name;
+ DBUG_ENTER("send_file_to_server");
+
+ fn_format(buf,filename,"","",4); /* Convert to client format */
+ if (!(tmp_name=my_strdup(buf,MYF(0))))
+ {
+ strmov(mysql->net.last_error, ER(mysql->net.last_errno=CR_OUT_OF_MEMORY));
+ DBUG_RETURN(-1);
+ }
+ if ((fd = my_open(tmp_name,O_RDONLY, MYF(0))) < 0)
+ {
+ mysql->net.last_errno=EE_FILENOTFOUND;
+ sprintf(buf,EE(mysql->net.last_errno),tmp_name,errno);
+ strmake(mysql->net.last_error,buf,sizeof(mysql->net.last_error)-1);
+ my_net_write(&mysql->net,"",0); net_flush(&mysql->net);
+ my_free(tmp_name,MYF(0));
+ DBUG_RETURN(-1);
+ }
+
+ while ((readcount = (int) my_read(fd,buf,sizeof(buf),MYF(0))) > 0)
+ {
+ if (my_net_write(&mysql->net,buf,readcount))
+ {
+ mysql->net.last_errno=CR_SERVER_LOST;
+ strmov(mysql->net.last_error,ER(mysql->net.last_errno));
+ DBUG_PRINT("error",("Lost connection to MySQL server during LOAD DATA of local file"));
+ (void) my_close(fd,MYF(0));
+ my_free(tmp_name,MYF(0));
+ DBUG_RETURN(-1);
+ }
+ }
+ (void) my_close(fd,MYF(0));
+ /* Send empty packet to mark end of file */
+ if (my_net_write(&mysql->net,"",0) || net_flush(&mysql->net))
+ {
+ mysql->net.last_errno=CR_SERVER_LOST;
+ sprintf(mysql->net.last_error,ER(mysql->net.last_errno),errno);
+ my_free(tmp_name,MYF(0));
+ DBUG_RETURN(-1);
+ }
+ if (readcount < 0)
+ {
+ mysql->net.last_errno=EE_READ; /* the errmsg for not entire file read */
+ sprintf(buf,EE(mysql->net.last_errno),tmp_name,errno);
+ strmake(mysql->net.last_error,buf,sizeof(mysql->net.last_error)-1);
+ my_free(tmp_name,MYF(0));
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/**************************************************************************
+** Alloc result struct for buffered results. All rows are read to buffer.
+** mysql_data_seek may be used.
+**************************************************************************/
+
+MYSQL_RES * STDCALL
+mysql_store_result(MYSQL *mysql)
+{
+ MYSQL_RES *result;
+ DBUG_ENTER("mysql_store_result");
+
+ if (!mysql->fields)
+ DBUG_RETURN(0);
+ if (mysql->status != MYSQL_STATUS_GET_RESULT)
+ {
+ strmov(mysql->net.last_error,
+ ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
+ DBUG_RETURN(0);
+ }
+ mysql->status=MYSQL_STATUS_READY; /* server is ready */
+ if (!(result=(MYSQL_RES*) my_malloc(sizeof(MYSQL_RES)+
+ sizeof(ulong)*mysql->field_count,
+ MYF(MY_WME | MY_ZEROFILL))))
+ {
+ mysql->net.last_errno=CR_OUT_OF_MEMORY;
+ strmov(mysql->net.last_error, ER(mysql->net.last_errno));
+ DBUG_RETURN(0);
+ }
+ result->eof=1; /* Marker for buffered */
+ result->lengths=(ulong*) (result+1);
+ if (!(result->data=read_rows(mysql,mysql->fields,mysql->field_count)))
+ {
+ my_free((gptr) result,MYF(0));
+ DBUG_RETURN(0);
+ }
+ mysql->affected_rows= result->row_count= result->data->rows;
+ result->data_cursor= result->data->data;
+ result->fields= mysql->fields;
+ result->field_alloc= mysql->field_alloc;
+ result->field_count= mysql->field_count;
+ result->current_field=0;
+ result->current_row=0; /* Must do a fetch first */
+ mysql->fields=0; /* fields is now in result */
+ DBUG_RETURN(result); /* Data fetched */
+}
+
+
+/**************************************************************************
+** Alloc struct for use with unbuffered reads. Data is fetched by domand
+** when calling to mysql_fetch_row.
+** mysql_data_seek is a noop.
+**
+** No other queries may be specified with the same MYSQL handle.
+** There shouldn't be much processing per row because mysql server shouldn't
+** have to wait for the client (and will not wait more than 30 sec/packet).
+**************************************************************************/
+
+MYSQL_RES * STDCALL
+mysql_use_result(MYSQL *mysql)
+{
+ MYSQL_RES *result;
+ DBUG_ENTER("mysql_use_result");
+
+ if (!mysql->fields)
+ DBUG_RETURN(0);
+ if (mysql->status != MYSQL_STATUS_GET_RESULT)
+ {
+ strmov(mysql->net.last_error,
+ ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
+ DBUG_RETURN(0);
+ }
+ if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result)+
+ sizeof(ulong)*mysql->field_count,
+ MYF(MY_WME | MY_ZEROFILL))))
+ DBUG_RETURN(0);
+ result->lengths=(ulong*) (result+1);
+ if (!(result->row=(MYSQL_ROW)
+ my_malloc(sizeof(result->row[0])*(mysql->field_count+1), MYF(MY_WME))))
+ { /* Ptrs: to one row */
+ my_free((gptr) result,MYF(0));
+ DBUG_RETURN(0);
+ }
+ result->fields= mysql->fields;
+ result->field_alloc= mysql->field_alloc;
+ result->field_count= mysql->field_count;
+ result->current_field=0;
+ result->handle= mysql;
+ result->current_row= 0;
+ mysql->fields=0; /* fields is now in result */
+ mysql->status=MYSQL_STATUS_USE_RESULT;
+ DBUG_RETURN(result); /* Data is read to be fetched */
+}
+
+
+
+/**************************************************************************
+** Return next field of the query results
+**************************************************************************/
+
+MYSQL_FIELD * STDCALL
+mysql_fetch_field(MYSQL_RES *result)
+{
+ if (result->current_field >= result->field_count)
+ return(NULL);
+ return &result->fields[result->current_field++];
+}
+
+
+/**************************************************************************
+** Return next row of the query results
+**************************************************************************/
+
+MYSQL_ROW STDCALL
+mysql_fetch_row(MYSQL_RES *res)
+{
+ DBUG_ENTER("mysql_fetch_row");
+ if (!res->data)
+ { /* Unbufferred fetch */
+ if (!res->eof)
+ {
+ if (!(read_one_row(res->handle,res->field_count,res->row, res->lengths)))
+ {
+ res->row_count++;
+ DBUG_RETURN(res->current_row=res->row);
+ }
+ else
+ {
+ DBUG_PRINT("info",("end of data"));
+ res->eof=1;
+ res->handle->status=MYSQL_STATUS_READY;
+ }
+ }
+ DBUG_RETURN((MYSQL_ROW) NULL);
+ }
+ {
+ MYSQL_ROW tmp;
+ if (!res->data_cursor)
+ {
+ DBUG_PRINT("info",("end of data"));
+ DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL);
+ }
+ tmp = res->data_cursor->data;
+ res->data_cursor = res->data_cursor->next;
+ DBUG_RETURN(res->current_row=tmp);
+ }
+}
+
+/**************************************************************************
+** Get column lengths of the current row
+** If one uses mysql_use_result, res->lengths contains the length information,
+** else the lengths are calculated from the offset between pointers.
+**************************************************************************/
+
+ulong * STDCALL
+mysql_fetch_lengths(MYSQL_RES *res)
+{
+ ulong *lengths,*prev_length;
+ byte *start;
+ MYSQL_ROW column,end;
+
+ if (!(column=res->current_row))
+ return 0; /* Something is wrong */
+ if (res->data)
+ {
+ start=0;
+ prev_length=0; /* Keep gcc happy */
+ lengths=res->lengths;
+ for (end=column+res->field_count+1 ; column != end ; column++,lengths++)
+ {
+ if (!*column)
+ {
+ *lengths=0; /* Null */
+ continue;
+ }
+ if (start) /* Found end of prev string */
+ *prev_length= (uint) (*column-start-1);
+ start= *column;
+ prev_length=lengths;
+ }
+ }
+ return res->lengths;
+}
+
+/**************************************************************************
+** Move to a specific row and column
+**************************************************************************/
+
+void STDCALL
+mysql_data_seek(MYSQL_RES *result, my_ulonglong row)
+{
+ MYSQL_ROWS *tmp=0;
+ DBUG_PRINT("info",("mysql_data_seek(%ld)",(long) row));
+ if (result->data)
+ for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ;
+ result->current_row=0;
+ result->data_cursor = tmp;
+}
+
+/*************************************************************************
+** put the row or field cursor one a position one got from mysql_row_tell()
+** This doesn't restore any data. The next mysql_fetch_row or
+** mysql_fetch_field will return the next row or field after the last used
+*************************************************************************/
+
+MYSQL_ROW_OFFSET STDCALL
+mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET row)
+{
+ MYSQL_ROW_OFFSET return_value=result->data_cursor;
+ result->current_row= 0;
+ result->data_cursor= row;
+ return return_value;
+}
+
+
+MYSQL_FIELD_OFFSET STDCALL
+mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET field_offset)
+{
+ MYSQL_FIELD_OFFSET return_value=result->current_field;
+ result->current_field=field_offset;
+ return return_value;
+}
+
+/*****************************************************************************
+** List all databases
+*****************************************************************************/
+
+MYSQL_RES * STDCALL
+mysql_list_dbs(MYSQL *mysql, const char *wild)
+{
+ char buff[255];
+ DBUG_ENTER("mysql_list_dbs");
+
+ append_wild(strmov(buff,"show databases"),buff+sizeof(buff),wild);
+ if (mysql_query(mysql,buff))
+ DBUG_RETURN(0);
+ DBUG_RETURN (mysql_store_result(mysql));
+}
+
+
+/*****************************************************************************
+** List all tables in a database
+** If wild is given then only the tables matching wild is returned
+*****************************************************************************/
+
+MYSQL_RES * STDCALL
+mysql_list_tables(MYSQL *mysql, const char *wild)
+{
+ char buff[255];
+ DBUG_ENTER("mysql_list_tables");
+
+ append_wild(strmov(buff,"show tables"),buff+sizeof(buff),wild);
+ if (mysql_query(mysql,buff))
+ DBUG_RETURN(0);
+ DBUG_RETURN (mysql_store_result(mysql));
+}
+
+
+/**************************************************************************
+** List all fields in a table
+** If wild is given then only the fields matching wild is returned
+** Instead of this use query:
+** show fields in 'table' like "wild"
+**************************************************************************/
+
+MYSQL_RES * STDCALL
+mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)
+{
+ MYSQL_RES *result;
+ MYSQL_DATA *query;
+ char buff[257],*end;
+ DBUG_ENTER("mysql_list_fields");
+ DBUG_PRINT("enter",("table: '%s' wild: '%s'",table,wild ? wild : ""));
+
+ LINT_INIT(query);
+
+ end=strmake(strmake(buff, table,128)+1,wild ? wild : "",128);
+ if (simple_command(mysql,COM_FIELD_LIST,buff,(uint) (end-buff),1) ||
+ !(query = read_rows(mysql,(MYSQL_FIELD*) 0,6)))
+ DBUG_RETURN(NULL);
+
+ free_old_query(mysql);
+ if (!(result = (MYSQL_RES *) my_malloc(sizeof(MYSQL_RES),
+ MYF(MY_WME | MY_ZEROFILL))))
+ {
+ free_rows(query);
+ DBUG_RETURN(NULL);
+ }
+ result->field_alloc=mysql->field_alloc;
+ mysql->fields=0;
+ result->field_count = (uint) query->rows;
+ result->fields= unpack_fields(query,&result->field_alloc,
+ result->field_count,1,
+ (my_bool) test(mysql->server_capabilities &
+ CLIENT_LONG_FLAG));
+ result->eof=1;
+ DBUG_RETURN(result);
+}
+
+/* List all running processes (threads) in server */
+
+MYSQL_RES * STDCALL
+mysql_list_processes(MYSQL *mysql)
+{
+ MYSQL_DATA *fields;
+ uint field_count;
+ uchar *pos;
+ DBUG_ENTER("mysql_list_processes");
+
+ LINT_INIT(fields);
+ if (simple_command(mysql,COM_PROCESS_INFO,0,0,0))
+ DBUG_RETURN(0);
+ free_old_query(mysql);
+ pos=(uchar*) mysql->net.read_pos;
+ field_count=(uint) net_field_length(&pos);
+ if (!(fields = read_rows(mysql,(MYSQL_FIELD*) 0,5)))
+ DBUG_RETURN(NULL);
+ if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,field_count,0,
+ (my_bool) test(mysql->server_capabilities &
+ CLIENT_LONG_FLAG))))
+ DBUG_RETURN(0);
+ mysql->status=MYSQL_STATUS_GET_RESULT;
+ mysql->field_count=field_count;
+ DBUG_RETURN(mysql_store_result(mysql));
+}
+
+
+int STDCALL
+mysql_create_db(MYSQL *mysql, const char *db)
+{
+ DBUG_ENTER("mysql_createdb");
+ DBUG_PRINT("enter",("db: %s",db));
+ DBUG_RETURN(simple_command(mysql,COM_CREATE_DB,db, (uint) strlen(db),0));
+}
+
+
+int STDCALL
+mysql_drop_db(MYSQL *mysql, const char *db)
+{
+ DBUG_ENTER("mysql_drop_db");
+ DBUG_PRINT("enter",("db: %s",db));
+ DBUG_RETURN(simple_command(mysql,COM_DROP_DB,db,(uint) strlen(db),0));
+}
+
+
+int STDCALL
+mysql_shutdown(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_shutdown");
+ DBUG_RETURN(simple_command(mysql,COM_SHUTDOWN,0,0,0));
+}
+
+
+int STDCALL
+mysql_refresh(MYSQL *mysql,uint options)
+{
+ uchar bits[1];
+ DBUG_ENTER("mysql_refresh");
+ bits[0]= (uchar) options;
+ DBUG_RETURN(simple_command(mysql,COM_REFRESH,(char*) bits,1,0));
+}
+
+int STDCALL
+mysql_kill(MYSQL *mysql,ulong pid)
+{
+ char buff[12];
+ DBUG_ENTER("mysql_kill");
+ int4store(buff,pid);
+ DBUG_RETURN(simple_command(mysql,COM_PROCESS_KILL,buff,4,0));
+}
+
+
+int STDCALL
+mysql_dump_debug_info(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_dump_debug_info");
+ DBUG_RETURN(simple_command(mysql,COM_DEBUG,0,0,0));
+}
+
+char * STDCALL
+mysql_stat(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_stat");
+ if (simple_command(mysql,COM_STATISTICS,0,0,0))
+ return mysql->net.last_error;
+ mysql->net.read_pos[mysql->packet_length]=0; /* End of stat string */
+ if (!mysql->net.read_pos[0])
+ {
+ mysql->net.last_errno=CR_WRONG_HOST_INFO;
+ strmov(mysql->net.last_error, ER(mysql->net.last_errno));
+ return mysql->net.last_error;
+ }
+ DBUG_RETURN((char*) mysql->net.read_pos);
+}
+
+
+int STDCALL
+mysql_ping(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_ping");
+ DBUG_RETURN(simple_command(mysql,COM_PING,0,0,0));
+}
+
+
+char * STDCALL
+mysql_get_server_info(MYSQL *mysql)
+{
+ return((char*) mysql->server_version);
+}
+
+
+char * STDCALL
+mysql_get_host_info(MYSQL *mysql)
+{
+ return(mysql->host_info);
+}
+
+
+uint STDCALL
+mysql_get_proto_info(MYSQL *mysql)
+{
+ return (mysql->protocol_version);
+}
+
+char * STDCALL
+mysql_get_client_info(void)
+{
+ return (char*) MYSQL_SERVER_VERSION;
+}
+
+
+int STDCALL
+mysql_options(MYSQL *mysql,enum mysql_option option, const char *arg)
+{
+ DBUG_ENTER("mysql_option");
+ DBUG_PRINT("enter",("option: %d",(int) option));
+ switch (option) {
+ case MYSQL_OPT_CONNECT_TIMEOUT:
+ mysql->options.connect_timeout= *(uint*) arg;
+ break;
+ case MYSQL_OPT_COMPRESS:
+ mysql->options.compress=1; /* Remember for connect */
+ break;
+ case MYSQL_OPT_NAMED_PIPE:
+ mysql->options.named_pipe=1; /* Force named pipe */
+ break;
+ case MYSQL_INIT_COMMAND:
+ my_free(mysql->options.init_command,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->options.init_command=my_strdup(arg,MYF(MY_WME));
+ break;
+ case MYSQL_READ_DEFAULT_FILE:
+ my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->options.my_cnf_file=my_strdup(arg,MYF(MY_WME));
+ break;
+ case MYSQL_READ_DEFAULT_GROUP:
+ my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->options.my_cnf_group=my_strdup(arg,MYF(MY_WME));
+ break;
+ case MYSQL_SET_CHARSET_DIR:
+ my_free(mysql->options.charset_dir,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->options.charset_dir=my_strdup(arg,MYF(MY_WME));
+ break;
+ case MYSQL_SET_CHARSET_NAME:
+ my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->options.charset_name=my_strdup(arg,MYF(MY_WME));
+ break;
+ default:
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+}
+
+/****************************************************************************
+** Functions to get information from the MySQL structure
+** These are functions to make shared libraries more usable.
+****************************************************************************/
+
+/* MYSQL_RES */
+my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res)
+{
+ return res->row_count;
+}
+
+unsigned int STDCALL mysql_num_fields(MYSQL_RES *res)
+{
+ return res->field_count;
+}
+
+my_bool STDCALL mysql_eof(MYSQL_RES *res)
+{
+ return res->eof;
+}
+
+MYSQL_FIELD * STDCALL mysql_fetch_field_direct(MYSQL_RES *res,uint fieldnr)
+{
+ return &(res)->fields[fieldnr];
+}
+
+MYSQL_FIELD * STDCALL mysql_fetch_fields(MYSQL_RES *res)
+{
+ return (res)->fields;
+}
+
+MYSQL_ROWS * STDCALL mysql_row_tell(MYSQL_RES *res)
+{
+ return res->data_cursor;
+}
+
+uint STDCALL mysql_field_tell(MYSQL_RES *res)
+{
+ return (res)->current_field;
+}
+
+/* MYSQL */
+
+unsigned int STDCALL mysql_field_count(MYSQL *mysql)
+{
+ return mysql->field_count;
+}
+
+my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql)
+{
+ return (mysql)->affected_rows;
+}
+
+my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql)
+{
+ return (mysql)->insert_id;
+}
+
+uint STDCALL mysql_errno(MYSQL *mysql)
+{
+ return (mysql)->net.last_errno;
+}
+
+char * STDCALL mysql_error(MYSQL *mysql)
+{
+ return (mysql)->net.last_error;
+}
+
+char *STDCALL mysql_info(MYSQL *mysql)
+{
+ return (mysql)->info;
+}
+
+ulong STDCALL mysql_thread_id(MYSQL *mysql)
+{
+ return (mysql)->thread_id;
+}
+
+const char * STDCALL mysql_character_set_name(MYSQL *mysql)
+{
+ return mysql->charset->name;
+}
+
+
+uint STDCALL mysql_thread_safe(void)
+{
+#ifdef THREAD
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+/****************************************************************************
+** Some support functions
+****************************************************************************/
+
+/*
+** Add escape characters to a string (blob?) to make it suitable for a insert
+** to should at least have place for length*2+1 chars
+** Returns the length of the to string
+*/
+
+ulong STDCALL
+mysql_escape_string(char *to,const char *from,ulong length)
+{
+ return mysql_sub_escape_string(default_charset_info,to,from,length);
+}
+
+ulong STDCALL
+mysql_real_escape_string(MYSQL *mysql, char *to,const char *from,
+ ulong length)
+{
+ return mysql_sub_escape_string(mysql->charset,to,from,length);
+}
+
+
+static ulong
+mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to,
+ const char *from, ulong length)
+{
+ const char *to_start=to;
+ const char *end;
+#ifdef USE_MB
+ my_bool use_mb_flag=use_mb(charset_info);
+#endif
+ for (end=from+length; from != end ; from++)
+ {
+#ifdef USE_MB
+ int l;
+ if (use_mb_flag && (l = my_ismbchar(charset_info, from, end)))
+ {
+ while (l--)
+ *to++ = *from++;
+ from--;
+ continue;
+ }
+#endif
+ switch (*from) {
+ case 0: /* Must be escaped for 'mysql' */
+ *to++= '\\';
+ *to++= '0';
+ break;
+ case '\n': /* Must be escaped for logs */
+ *to++= '\\';
+ *to++= 'n';
+ break;
+ case '\r':
+ *to++= '\\';
+ *to++= 'r';
+ break;
+ case '\\':
+ *to++= '\\';
+ *to++= '\\';
+ break;
+ case '\'':
+ *to++= '\\';
+ *to++= '\'';
+ break;
+ case '"': /* Better safe than sorry */
+ *to++= '\\';
+ *to++= '"';
+ break;
+ case '\032': /* This gives problems on Win32 */
+ *to++= '\\';
+ *to++= 'Z';
+ break;
+ default:
+ *to++= *from;
+ }
+ }
+ *to=0;
+ return (ulong) (to-to_start);
+}
+
+
+char * STDCALL
+mysql_odbc_escape_string(MYSQL *mysql,
+ char *to, ulong to_length,
+ const char *from, ulong from_length,
+ void *param,
+ char * (*extend_buffer)
+ (void *, char *, ulong *))
+{
+ char *to_end=to+to_length-5;
+ const char *end;
+#ifdef USE_MB
+ my_bool use_mb_flag=use_mb(mysql->charset);
+#endif
+
+ for (end=from+from_length; from != end ; from++)
+ {
+ if (to >= to_end)
+ {
+ to_length = (ulong) (end-from)+512; /* We want this much more */
+ if (!(to=(*extend_buffer)(param, to, &to_length)))
+ return to;
+ to_end=to+to_length-5;
+ }
+#ifdef USE_MB
+ {
+ int l;
+ if (use_mb_flag && (l = my_ismbchar(mysql->charset, from, end)))
+ {
+ while (l--)
+ *to++ = *from++;
+ from--;
+ continue;
+ }
+ }
+#endif
+ switch (*from) {
+ case 0: /* Must be escaped for 'mysql' */
+ *to++= '\\';
+ *to++= '0';
+ break;
+ case '\n': /* Must be escaped for logs */
+ *to++= '\\';
+ *to++= 'n';
+ break;
+ case '\r':
+ *to++= '\\';
+ *to++= 'r';
+ break;
+ case '\\':
+ *to++= '\\';
+ *to++= '\\';
+ break;
+ case '\'':
+ *to++= '\\';
+ *to++= '\'';
+ break;
+ case '"': /* Better safe than sorry */
+ *to++= '\\';
+ *to++= '"';
+ break;
+ case '\032': /* This gives problems on Win32 */
+ *to++= '\\';
+ *to++= 'Z';
+ break;
+ default:
+ *to++= *from;
+ }
+ }
+ return to;
+}
+
+void STDCALL
+myodbc_remove_escape(MYSQL *mysql,char *name)
+{
+ char *to;
+#ifdef USE_MB
+ my_bool use_mb_flag=use_mb(mysql->charset);
+ char *end;
+ LINT_INIT(end);
+ if (use_mb_flag)
+ for (end=name; *end ; end++) ;
+#endif
+
+ for (to=name ; *name ; name++)
+ {
+#ifdef USE_MB
+ int l;
+ if (use_mb_flag && (l = my_ismbchar( mysql->charset, name , end ) ) )
+ {
+ while (l--)
+ *to++ = *name++;
+ name--;
+ continue;
+ }
+#endif
+ if (*name == '\\' && name[1])
+ name++;
+ *to++= *name;
+ }
+ *to=0;
+}
+
+
+
+
diff --git a/myisam/Makefile.am b/myisam/Makefile.am
index a18ff55ba9e..6781116043f 100644
--- a/myisam/Makefile.am
+++ b/myisam/Makefile.am
@@ -1,15 +1,15 @@
# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-#
+#
# 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
@@ -17,7 +17,7 @@
EXTRA_DIST = mi_test_all.sh mi_test_all.res
pkgdata_DATA = mi_test_all mi_test_all.res
-INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include
+INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include
LDADD = @CLIENT_EXTRA_LDFLAGS@ libmyisam.a ../mysys/libmysys.a \
../dbug/libdbug.a ../strings/libmystrings.a
pkglib_LIBRARIES = libmyisam.a
@@ -25,13 +25,14 @@ bin_PROGRAMS = myisamchk myisamlog myisampack
myisamchk_DEPENDENCIES= $(LIBRARIES)
myisamlog_DEPENDENCIES= $(LIBRARIES)
myisampack_DEPENDENCIES=$(LIBRARIES)
-noinst_PROGRAMS = mi_test1 mi_test2 mi_test3 ft_test1 ft_eval
+noinst_PROGRAMS = mi_test1 mi_test2 mi_test3 ft_test1 ft_eval ft_dump
noinst_HEADERS = myisamdef.h fulltext.h ftdefs.h ft_test1.h ft_eval.h
mi_test1_DEPENDENCIES= $(LIBRARIES)
mi_test2_DEPENDENCIES= $(LIBRARIES)
mi_test3_DEPENDENCIES= $(LIBRARIES)
ft_test1_DEPENDENCIES= $(LIBRARIES)
ft_eval_DEPENDENCIES= $(LIBRARIES)
+ft_dump_DEPENDENCIES= $(LIBRARIES)
libmyisam_a_SOURCES = mi_open.c mi_extra.c mi_info.c mi_rkey.c \
mi_rnext.c mi_rnext_same.c \
mi_search.c mi_page.c mi_key.c mi_locking.c \
@@ -45,7 +46,7 @@ libmyisam_a_SOURCES = mi_open.c mi_extra.c mi_info.c mi_rkey.c \
mi_changed.c mi_static.c mi_delete_all.c \
mi_delete_table.c mi_rename.c mi_check.c \
ft_parser.c ft_search.c ft_stopwords.c ft_static.c \
- ft_update.c sort.c
+ ft_update.c ft_boolean_search.c ft_nlq_search.c sort.c
CLEANFILES = test?.MY? FT?.MY? isam.log mi_test_all
DEFS = -DMAP_TO_USE_RAID
# Omit dependency for ../mit-pthreads/include/sys that only exits if
diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c
new file mode 100644
index 00000000000..32dd428e493
--- /dev/null
+++ b/myisam/ft_boolean_search.c
@@ -0,0 +1,222 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ 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 */
+
+/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
+
+#include "ftdefs.h"
+
+/* search with boolean queries */
+
+typedef struct st_all_in_one {
+ MI_INFO *info;
+ uint keynr;
+ uchar *keybuff;
+ MI_KEYDEF *keyinfo;
+ my_off_t key_root;
+ TREE dtree;
+ byte *start, *end;
+ uint total_yes, total_no;
+} ALL_IN_ONE;
+
+typedef struct st_ft_superdoc {
+ FT_DOC doc;
+ //FT_WORD *word_ptr;
+ //double tmp_weight;
+ uint yes;
+ uint no;
+ uint wno;
+ ALL_IN_ONE *aio;
+} FT_SUPERDOC;
+
+static int FT_SUPERDOC_cmp(FT_SUPERDOC *p1, FT_SUPERDOC *p2)
+{
+ if (p1->doc.dpos < p2->doc.dpos)
+ return -1;
+ if (p1->doc.dpos == p2->doc.dpos)
+ return 0;
+ return 1;
+}
+
+static int walk_and_copy(FT_SUPERDOC *from,
+ uint32 count __attribute__((unused)), FT_DOC **to)
+{
+ if (from->yes == from->aio->total_yes && !from->no)
+ {
+ (*to)->dpos=from->doc.dpos;
+ (*to)->weight=from->doc.weight;
+ (*to)++;
+ }
+ return 0;
+}
+
+static double _wghts[11]={
+ 0.131687242798354,
+ 0.197530864197531,
+ 0.296296296296296,
+ 0.444444444444444,
+ 0.666666666666667,
+ 1.000000000000000,
+ 1.500000000000000,
+ 2.250000000000000,
+ 3.375000000000000,
+ 5.062500000000000,
+ 7.593750000000000};
+static double *wghts=_wghts+5; // wghts[i] = 1.5**i
+
+static double _nwghts[11]={
+ -0.065843621399177,
+ -0.098765432098766,
+ -0.148148148148148,
+ -0.222222222222222,
+ -0.333333333333334,
+ -0.500000000000000,
+ -0.750000000000000,
+ -1.125000000000000,
+ -1.687500000000000,
+ -2.531250000000000,
+ -3.796875000000000};
+static double *nwghts=_nwghts+5; // nwghts[i] = -0.5*1.5**i
+
+int do_boolean(ALL_IN_ONE *aio, uint nested,
+ int yesno, int plusminus, bool pmsign)
+{
+ int r, res;
+ uint keylen, wno;
+ FT_SUPERDOC sdoc, *sptr;
+ TREE_ELEMENT *selem;
+ FT_WORD w;
+ FTB_PARAM param;
+
+#ifdef EVAL_RUN
+ return 1;
+#endif /* EVAL_RUN */
+
+ param.prev=' ';
+
+ for(wno=1; res=ft_get_word(&aio->start,aio->end,&w,&param); wno++)
+ {
+ r=plusminus+param.plusminus;
+ if (param.pmsign^pmsign)
+ w.weight=nwghts[(r>5)?5:((r<-5)?-5:r)];
+ else
+ w.weight=wghts[(r>5)?5:((r<-5)?-5:r)];
+
+ if (param.yesno>0) aio->total_yes++;
+ if (param.yesno<0) aio->total_no++;
+
+ switch (res) {
+ case FTB_LBR: // (
+ //if (do_boolean(aio,nested+1,my_yesno,plusminus+my_plusminus))
+ // return 1;
+ // ???
+ break;
+ case 1: // word
+ keylen=_ft_make_key(aio->info,aio->keynr,(char*) aio->keybuff,&w,0);
+ keylen-=HA_FT_WLEN;
+
+ r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen,
+ SEARCH_FIND | SEARCH_PREFIX, aio->key_root);
+
+ while (!r)
+ {
+ if (param.trunc)
+ r=_mi_compare_text(default_charset_info,
+ aio->info->lastkey+1,keylen-1,
+ aio->keybuff+1,keylen-1,0);
+ else
+ r=_mi_compare_text(default_charset_info,
+ aio->info->lastkey,keylen,
+ aio->keybuff,keylen,0);
+ if (r) break;
+
+ sdoc.doc.dpos=aio->info->lastpos;
+
+ /* saving document matched into dtree */
+ if (!(selem=tree_insert(&aio->dtree, &sdoc, 0))) return 1;
+
+ sptr=(FT_SUPERDOC *)ELEMENT_KEY((&aio->dtree), selem);
+
+ if (selem->count==1) /* document's first match */
+ {
+ sptr->yes=sptr->no=sptr->doc.weight=0;
+ sptr->aio=aio;
+ sptr->wno=0;
+ }
+ if (sptr->wno != wno)
+ {
+ if (param.yesno>0) sptr->yes++;
+ if (param.yesno<0) sptr->no++;
+ sptr->wno=wno;
+ }
+ sptr->doc.weight+=w.weight;
+
+ if (_mi_test_if_changed(aio->info) == 0)
+ r=_mi_search_next(aio->info, aio->keyinfo, aio->info->lastkey,
+ aio->info->lastkey_length, SEARCH_BIGGER,
+ aio->key_root);
+ else
+ r=_mi_search(aio->info, aio->keyinfo, aio->info->lastkey,
+ aio->info->lastkey_length, SEARCH_BIGGER,
+ aio->key_root);
+ }
+ break;
+ case FTB_RBR: // )
+ break;
+ }
+ }
+ return 0;
+}
+
+FT_DOCLIST *ft_boolean_search(MI_INFO *info, uint keynr, byte *query,
+ uint query_len)
+{
+ ALL_IN_ONE aio;
+ FT_DOC *dptr;
+ FT_DOCLIST *dlist=NULL;
+
+ aio.info=info;
+ aio.keynr=keynr;
+ aio.keybuff=aio.info->lastkey+aio.info->s->base.max_key_length;
+ aio.keyinfo=aio.info->s->keyinfo+keynr;
+ aio.key_root=aio.info->s->state.key_root[keynr];
+ aio.start=query;
+ aio.end=query+query_len;
+ aio.total_yes=aio.total_no=0;
+
+ init_tree(&aio.dtree,0,sizeof(FT_SUPERDOC),(qsort_cmp)&FT_SUPERDOC_cmp,0,
+ NULL);
+
+ if (do_boolean(&aio,0,0,0,0))
+ goto err;
+
+ dlist=(FT_DOCLIST *)my_malloc(sizeof(FT_DOCLIST)+sizeof(FT_DOC)*(aio.dtree.elements_in_tree-1),MYF(0));
+ if(!dlist)
+ goto err;
+
+ dlist->ndocs=aio.dtree.elements_in_tree;
+ dlist->curdoc=-1;
+ dlist->info=aio.info;
+ dptr=dlist->doc;
+
+ tree_walk(&aio.dtree, (tree_walk_action)&walk_and_copy, &dptr, left_root_right);
+
+ dlist->ndocs=dptr - dlist->doc;
+
+err:
+ delete_tree(&aio.dtree);
+ return dlist;
+}
+
diff --git a/myisam/ft_dump.c b/myisam/ft_dump.c
new file mode 100644
index 00000000000..af49d834d0f
--- /dev/null
+++ b/myisam/ft_dump.c
@@ -0,0 +1,214 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ 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 */
+
+/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
+
+#include "ftdefs.h"
+
+static void get_options(int argc,char *argv[]);
+static void usage(char *argv[]);
+static void complain(int val);
+
+static int count=0, stats=0, dump=0, verbose=0;
+static char *query=NULL;
+
+#define MAX (MAX_WORD_LEN+10)
+#define HOW_OFTEN_TO_WRITE 1000
+
+int main(int argc,char *argv[])
+{
+ int error=0;
+ uint keylen, inx, doc_cnt;
+ float weight;
+ double gws, min_gws, avg_gws=0;
+ MI_INFO *info;
+ char buf[MAX], buf2[MAX], buf_maxlen[MAX], buf_min_gws[MAX], *s;
+ ulong total=0, maxlen=0, uniq=0, max_doc_cnt=0;
+#ifdef EVAL_RUN
+ uint cnt;
+ double sum, sum2, suml;
+#endif /* EVAL_RUN */
+ struct { MI_INFO *info; } aio0, *aio=&aio0; /* for GWS_IN_USE */
+
+ MY_INIT(argv[0]);
+ get_options(argc,argv);
+ if (count || dump)
+ verbose=0;
+ else
+ stats=1;
+
+ if (verbose)
+ setbuf(stdout,NULL);
+
+ if (argc-optind < 2)
+ usage(argv);
+
+ if (!(info=mi_open(argv[optind],2,HA_OPEN_ABORT_IF_LOCKED)))
+ goto err;
+
+ inx=atoi(argv[optind+1]);
+ *buf2=0;
+ aio->info=info;
+
+ if ((inx >= info->s->base.keys) || !(info->s->keyinfo[inx].flag & HA_FULLTEXT))
+ {
+ printf("Key %d in table %s is not a FULLTEXT key\n", inx, info->filename);
+ goto err;
+ }
+
+ if (query)
+ {
+ FT_DOCLIST *result;
+ int i;
+
+ ft_init_stopwords(ft_precompiled_stopwords);
+
+ result=ft_init_search(info,inx,query,strlen(query),1);
+ if(!result)
+ goto err;
+
+ if (verbose)
+ printf("%d rows matched\n",result->ndocs);
+
+ for(i=0 ; i<result->ndocs ; i++)
+ printf("%9qx %20.7f\n",result->doc[i].dpos,result->doc[i].weight);
+
+ ft_close_search(result);
+ }
+ else
+ {
+ info->lastpos= HA_OFFSET_ERROR;
+ info->update|= HA_STATE_PREV_FOUND;
+
+ while (!(error=mi_rnext(info,NULL,inx)))
+ {
+ keylen=*(info->lastkey);
+
+#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
+#ifdef EVAL_RUN
+ mi_float4get(weight,info->lastkey+keylen+2);
+#else /* EVAL_RUN */
+ mi_float4get(weight,info->lastkey+keylen+1);
+#endif /* EVAL_RUN */
+#else
+#error
+#endif
+
+#ifdef EVAL_RUN
+ cnt=*(byte *)(info->lastkey+keylen);
+#endif /* EVAL_RUN */
+
+ snprintf(buf,MAX,"%.*s",keylen,info->lastkey+1);
+ for (s=buf;*s;s++) *s=tolower(*s);
+ total++;
+
+ if (count || stats)
+ {
+ doc_cnt++;
+#ifdef EVAL_RUN
+ sum +=cnt;
+ sum2+=cnt*cnt;
+ suml+=cnt*log(cnt);
+#endif /* EVAL_RUN */
+ if (strcmp(buf, buf2))
+ {
+ if (*buf2)
+ {
+ uniq++;
+ avg_gws+=gws=GWS_IN_USE;
+ if (count)
+ printf("%9u %20.7f %s\n",doc_cnt,gws,buf2);
+ if (maxlen<keylen)
+ {
+ maxlen=keylen;
+ strcpy(buf_maxlen, buf2);
+ }
+ if (max_doc_cnt < doc_cnt)
+ {
+ max_doc_cnt=doc_cnt;
+ strcpy(buf_min_gws, buf2);
+ min_gws=gws;
+ }
+ }
+ strcpy(buf2, buf);
+#ifdef EVAL_RUN
+ sum=sum2=suml=
+#endif /* EVAL_RUN */
+ doc_cnt=0;
+ }
+ }
+ if (dump)
+ printf("%9qx %20.7f %s\n",info->lastpos,weight,buf);
+
+ if(verbose && (total%HOW_OFTEN_TO_WRITE)==0)
+ printf("%10ld\r",total);
+ }
+
+ if (stats)
+ printf("Total rows: %qu\nTotal words: %lu\n"
+ "Unique words: %lu\nLongest word: %lu chars (%s)\n"
+ "Average global weight: %f\n"
+ "Most common word: %lu times, weight: %f (%s)\n",
+ (ulonglong)info->state->records, total, uniq, maxlen, buf_maxlen,
+ avg_gws/uniq, max_doc_cnt, min_gws, buf_min_gws);
+ }
+
+err:
+ if (error && error != HA_ERR_END_OF_FILE)
+ printf("got error %d\n",my_errno);
+ if (info)
+ mi_close(info);
+ return 0;
+}
+
+const char *options="dscve:h";
+
+static void get_options(int argc, char *argv[])
+{
+ int c;
+
+ while ((c=getopt(argc,argv,options)) != -1)
+ {
+ switch(c) {
+ case 'd': dump=1; complain(count || query); break;
+ case 's': stats=1; complain(query!=0); break;
+ case 'v': verbose=1; break;
+ case 'c': count=1; complain(dump || query); break;
+ case 'e': query=my_strdup(optarg,MYF(MY_FAE)); complain(dump || count || stats); break;
+ case '?':
+ case 'h':
+ default:
+ usage(argv);
+ }
+ }
+ return;
+} /* get options */
+
+static void usage(char *argv[])
+{
+ printf("Use: %s [-%s] <table_name> <key_no>\n", *argv, options);
+ exit(1);
+}
+
+static void complain(int val) /* Kinda assert :-) */
+{
+ if (val)
+ {
+ printf("You cannot use these options together!\n");
+ exit(1);
+ }
+}
+
diff --git a/myisam/ft_nlq_search.c b/myisam/ft_nlq_search.c
new file mode 100644
index 00000000000..3b4937ca4d9
--- /dev/null
+++ b/myisam/ft_nlq_search.c
@@ -0,0 +1,191 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ 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 */
+
+/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
+
+#include "ftdefs.h"
+
+/* search with natural language queries */
+
+typedef struct st_all_in_one {
+ MI_INFO *info;
+ uint keynr;
+ uchar *keybuff;
+ MI_KEYDEF *keyinfo;
+ my_off_t key_root;
+ TREE dtree;
+} ALL_IN_ONE;
+
+typedef struct st_ft_superdoc {
+ FT_DOC doc;
+ FT_WORD *word_ptr;
+ double tmp_weight;
+} FT_SUPERDOC;
+
+static int FT_SUPERDOC_cmp(FT_SUPERDOC *p1, FT_SUPERDOC *p2)
+{
+ if (p1->doc.dpos < p2->doc.dpos)
+ return -1;
+ if (p1->doc.dpos == p2->doc.dpos)
+ return 0;
+ return 1;
+}
+
+static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio)
+{
+ uint keylen, r, doc_cnt;
+#ifdef EVAL_RUN
+ uint cnt;
+ double sum, sum2, suml;
+#endif /* EVAL_RUN */
+ FT_SUPERDOC sdoc, *sptr;
+ TREE_ELEMENT *selem;
+#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
+ float tmp_weight;
+#else
+#error
+#endif
+
+ word->weight=LWS_FOR_QUERY;
+
+ keylen=_ft_make_key(aio->info,aio->keynr,(char*) aio->keybuff,word,0);
+#ifdef EVAL_RUN
+ keylen-=1+HA_FT_WLEN;
+#else /* EVAL_RUN */
+ keylen-=HA_FT_WLEN;
+#endif /* EVAL_RUN */
+
+#ifdef EVAL_RUN
+ sum=sum2=suml=
+#endif /* EVAL_RUN */
+ doc_cnt=0;
+
+ r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen,
+ SEARCH_FIND | SEARCH_PREFIX, aio->key_root);
+
+ while(!r)
+ {
+ if (_mi_compare_text(default_charset_info,
+ aio->info->lastkey,keylen,
+ aio->keybuff,keylen,0)) break;
+
+#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
+#ifdef EVAL_RUN
+ mi_float4get(tmp_weight,aio->info->lastkey+keylen+1);
+#else /* EVAL_RUN */
+ mi_float4get(tmp_weight,aio->info->lastkey+keylen);
+#endif /* EVAL_RUN */
+#else
+#error
+#endif
+ if(tmp_weight==0) return doc_cnt; /* stopword, doc_cnt should be 0 */
+
+#ifdef EVAL_RUN
+ cnt=*(byte *)(aio->info->lastkey+keylen);
+#endif /* EVAL_RUN */
+
+ sdoc.doc.dpos=aio->info->lastpos;
+
+ /* saving document matched into dtree */
+ if(!(selem=tree_insert(&aio->dtree, &sdoc, 0))) return 1;
+
+ sptr=(FT_SUPERDOC *)ELEMENT_KEY((&aio->dtree), selem);
+
+ if(selem->count==1) /* document's first match */
+ sptr->doc.weight=0;
+ else
+ sptr->doc.weight+=sptr->tmp_weight*sptr->word_ptr->weight;
+
+ sptr->word_ptr=word;
+ sptr->tmp_weight=tmp_weight;
+
+ doc_cnt++;
+#ifdef EVAL_RUN
+ sum +=cnt;
+ sum2+=cnt*cnt;
+ suml+=cnt*log(cnt);
+#endif /* EVAL_RUN */
+
+ if (_mi_test_if_changed(aio->info) == 0)
+ r=_mi_search_next(aio->info, aio->keyinfo, aio->info->lastkey,
+ aio->info->lastkey_length, SEARCH_BIGGER,
+ aio->key_root);
+ else
+ r=_mi_search(aio->info, aio->keyinfo, aio->info->lastkey,
+ aio->info->lastkey_length, SEARCH_BIGGER,
+ aio->key_root);
+ }
+ if(doc_cnt) {
+ word->weight*=GWS_IN_USE;
+ if(word->weight < 0) word->weight=0;
+ }
+
+ return 0;
+}
+
+static int walk_and_copy(FT_SUPERDOC *from,
+ uint32 count __attribute__((unused)), FT_DOC **to)
+{
+ from->doc.weight+=from->tmp_weight*from->word_ptr->weight;
+ (*to)->dpos=from->doc.dpos;
+ (*to)->weight=from->doc.weight;
+ (*to)++;
+ return 0;
+}
+
+FT_DOCLIST *ft_nlq_search(MI_INFO *info, uint keynr, byte *query,
+ uint query_len)
+{
+ TREE *wtree, allocated_wtree;
+ ALL_IN_ONE aio;
+ FT_DOC *dptr;
+ FT_DOCLIST *dlist=NULL;
+
+ aio.info=info;
+ aio.keynr=keynr;
+ aio.keybuff=aio.info->lastkey+aio.info->s->base.max_key_length;
+ aio.keyinfo=aio.info->s->keyinfo+keynr;
+ aio.key_root=aio.info->s->state.key_root[keynr];
+
+ bzero(&allocated_wtree,sizeof(allocated_wtree));
+
+ init_tree(&aio.dtree,0,sizeof(FT_SUPERDOC),(qsort_cmp)&FT_SUPERDOC_cmp,0,
+ NULL);
+
+ if(!(wtree=ft_parse(&allocated_wtree,query,query_len)))
+ return NULL;
+
+ if(tree_walk(wtree, (tree_walk_action)&walk_and_match, &aio,
+ left_root_right))
+ goto err;
+
+ dlist=(FT_DOCLIST *)my_malloc(sizeof(FT_DOCLIST)+sizeof(FT_DOC)*(aio.dtree.elements_in_tree-1),MYF(0));
+ if(!dlist)
+ goto err;
+
+ dlist->ndocs=aio.dtree.elements_in_tree;
+ dlist->curdoc=-1;
+ dlist->info=aio.info;
+ dptr=dlist->doc;
+
+ tree_walk(&aio.dtree, (tree_walk_action)&walk_and_copy, &dptr, left_root_right);
+
+err:
+ delete_tree(wtree);
+ delete_tree(&aio.dtree);
+ return dlist;
+}
+
diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c
index 7ea2e240c36..d1daa581446 100644
--- a/myisam/ft_parser.c
+++ b/myisam/ft_parser.c
@@ -83,13 +83,12 @@ FT_WORD * ft_linearize(MI_INFO *info, uint keynr, byte *keybuf, TREE *wtree)
tree_walk(wtree,(tree_walk_action)&walk_and_copy,&docstat,left_root_right);
}
delete_tree(wtree);
- my_free((char*) wtree,MYF(0));
if (!wlist)
return NULL;
docstat.list->pos=NULL;
- for(p=wlist;p->pos;p++)
+ for (p=wlist;p->pos;p++)
{
p->weight=PRENORM_IN_USE;
#ifdef EVAL_RUN
@@ -104,7 +103,7 @@ FT_WORD * ft_linearize(MI_INFO *info, uint keynr, byte *keybuf, TREE *wtree)
#endif
#endif /* EVAL_RUN */
- for(p=wlist;p->pos;p++)
+ for (p=wlist;p->pos;p++)
{
p->weight/=NORM_IN_USE;
}
@@ -112,40 +111,133 @@ FT_WORD * ft_linearize(MI_INFO *info, uint keynr, byte *keybuf, TREE *wtree)
return wlist;
}
+#define true_word_char(X) (isalnum(X) || (X)=='_')
#ifdef HYPHEN_IS_DELIM
-#define word_char(X) (isalnum(X) || (X)=='_' || (X)=='\'')
+#define misc_word_char(X) ((X)=='\'')
#else
-#define word_char(X) (isalnum(X) || (X)=='_' || (X)=='\'' || (X)=='-')
+#define misc_word_char(X) ((X)=='\'' || (X)=='-')
#endif
+#define word_char(X) (true_word_char(X) || misc_word_char(X))
-/* this is rather dumb first version of the parser */
-TREE * ft_parse(TREE *wtree, byte *doc, int doclen)
+byte ft_get_word(byte **start, byte *end, FT_WORD *word, FTB_PARAM *param)
{
- byte *end=doc+doclen;
- FT_WORD w;
+ byte *doc=*start;
+ int mwc;
+
+ param->yesno=param->plusminus=param->pmsign=0;
- if (!wtree)
+ while (doc<end)
{
- if (!(wtree=(TREE *)my_malloc(sizeof(TREE),MYF(0)))) return NULL;
- init_tree(wtree,0,sizeof(FT_WORD),(qsort_cmp)&FT_WORD_cmp,0,NULL);
+ for (;doc<end;doc++)
+ {
+ if (true_word_char(*doc)) break;
+ if (*doc == FTB_LBR || *doc == FTB_RBR)
+ {
+ param->prev=' ';
+ *start=doc+1;
+ return *doc;
+ }
+ if (param->prev == ' ')
+ {
+ switch (*doc) {
+ case FTB_YES: param->yesno=+1; continue;
+ case FTB_NO: param->yesno=-1; continue;
+ case FTB_INC: param->plusminus++; continue;
+ case FTB_DEC: param->plusminus--; continue;
+ case FTB_NEG: param->pmsign=!param->pmsign; continue;
+ default: break;
+ }
+ }
+ param->prev=*doc;
+ param->yesno=param->plusminus=param->pmsign=0;
+ }
+
+ mwc=0;
+ for (word->pos=doc; doc<end; doc++)
+ if (true_word_char(*doc))
+ mwc=0;
+ else if (!misc_word_char(*doc) || mwc++)
+ break;
+
+ param->prev='A'; // be sure *prev is true_word_char
+ word->len= (uint)(doc-word->pos) - mwc;
+ if (param->trunc=(doc<end && *doc == FTB_TRUNC))
+ doc++;
+
+ if (word->len >= MIN_WORD_LEN && word->len < MAX_WORD_LEN &&
+ !is_stopword(word->pos, word->len))
+ {
+ *start=doc;
+ return 1;
+ }
}
+ return 0;
+}
+
+byte ft_simple_get_word(byte **start, byte *end, FT_WORD *word)
+{
+ byte *doc=*start;
+ int mwc;
- w.weight=0;
while (doc<end)
{
for (;doc<end;doc++)
- if (word_char(*doc)) break;
- for (w.pos=doc; doc<end; doc++)
- if (!word_char(*doc)) break;
- if ((w.len= (uint) (doc-w.pos)) < MIN_WORD_LEN) continue;
- if (w.len >= HA_FT_MAXLEN) continue;
- if (is_stopword(w.pos, w.len)) continue;
- if (!tree_insert(wtree, &w, 0))
{
- delete_tree(wtree);
- my_free((char*) wtree,MYF(0));
- return NULL;
+ if (true_word_char(*doc)) break;
+ }
+
+ mwc=0;
+ for(word->pos=doc; doc<end; doc++)
+ if (true_word_char(*doc))
+ mwc=0;
+ else if (!misc_word_char(*doc) || mwc++)
+ break;
+
+ word->len= (uint)(doc-word->pos) - mwc;
+
+ if (word->len >= MIN_WORD_LEN && word->len < MAX_WORD_LEN &&
+ !is_stopword(word->pos, word->len))
+ {
+ *start=doc;
+ return 1;
}
}
+ return 0;
+}
+
+int is_boolean(byte *q, uint len)
+{
+ if (!len) return 0;
+ if (*q == FTB_YES || *q == FTB_NO) return 1;
+
+ for (++q; --len; ++q)
+ {
+ if ((*q == FTB_YES || *q == FTB_NO) && q[-1] == ' ' && true_word_char(q[1]))
+ return 1;
+ }
+ return 0;
+}
+
+TREE * ft_parse(TREE *wtree, byte *doc, int doclen)
+{
+ byte *end=doc+doclen;
+ int res;
+ FT_WORD w;
+
+ if (!is_tree_inited(wtree))
+ {
+ init_tree(wtree,0,sizeof(FT_WORD),(qsort_cmp)&FT_WORD_cmp,0,NULL);
+ }
+
+ while (res=ft_simple_get_word(&doc,end,&w))
+ {
+ if (!tree_insert(wtree, &w, 0))
+ goto err;
+ }
return wtree;
+
+err:
+ delete_tree(wtree);
+ return NULL;
}
+
diff --git a/myisam/ft_search.c b/myisam/ft_search.c
index 4ca1551e809..711c03722a5 100644
--- a/myisam/ft_search.c
+++ b/myisam/ft_search.c
@@ -18,146 +18,17 @@
#include "ftdefs.h"
-/* queries isam and returns list of documents matched */
-
-typedef struct st_all_in_one {
- MI_INFO *info;
- uint keynr;
- uchar *keybuff;
- MI_KEYDEF *keyinfo;
- my_off_t key_root;
- TREE dtree;
-} ALL_IN_ONE;
-
-typedef struct st_ft_superdoc {
- FT_DOC doc;
- FT_WORD *word_ptr;
- double tmp_weight;
-} FT_SUPERDOC;
-
-static int FT_SUPERDOC_cmp(FT_SUPERDOC *p1, FT_SUPERDOC *p2)
-{
- if (p1->doc.dpos < p2->doc.dpos)
- return -1;
- if (p1->doc.dpos == p2->doc.dpos)
- return 0;
- return 1;
-}
-
-static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio)
-{
- uint keylen, r, doc_cnt;
-#ifdef EVAL_RUN
- uint cnt;
- double sum, sum2, suml;
-#endif /* EVAL_RUN */
- FT_SUPERDOC sdoc, *sptr;
- TREE_ELEMENT *selem;
-#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
- float tmp_weight;
-#else
-#error
-#endif
-
- word->weight=LWS_FOR_QUERY;
-
- keylen=_ft_make_key(aio->info,aio->keynr,(char*) aio->keybuff,word,0);
-#ifdef EVAL_RUN
- keylen-=1+HA_FT_WLEN;
-#else /* EVAL_RUN */
- keylen-=HA_FT_WLEN;
-#endif /* EVAL_RUN */
-
-#ifdef EVAL_RUN
- sum=sum2=suml=
-#endif /* EVAL_RUN */
- doc_cnt=0;
-
- r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen,
- SEARCH_FIND | SEARCH_PREFIX, aio->key_root);
-
- while(!r)
- {
- if (_mi_compare_text(default_charset_info,
- aio->info->lastkey,keylen,
- aio->keybuff,keylen,0)) break;
-
-#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
-#ifdef EVAL_RUN
- mi_float4get(tmp_weight,aio->info->lastkey+keylen+1);
-#else /* EVAL_RUN */
- mi_float4get(tmp_weight,aio->info->lastkey+keylen);
-#endif /* EVAL_RUN */
-#else
-#error
-#endif
- if(tmp_weight==0) return doc_cnt; /* stopword, doc_cnt should be 0 */
-
-#ifdef EVAL_RUN
- cnt=*(byte *)(aio->info->lastkey+keylen);
-#endif /* EVAL_RUN */
-
- sdoc.doc.dpos=aio->info->lastpos;
-
- /* saving document matched into dtree */
- if(!(selem=tree_insert(&aio->dtree, &sdoc, 0))) return 1;
-
- sptr=(FT_SUPERDOC *)ELEMENT_KEY((&aio->dtree), selem);
-
- if(selem->count==1) /* document's first match */
- sptr->doc.weight=0;
- else
- sptr->doc.weight+=sptr->tmp_weight*sptr->word_ptr->weight;
-
- sptr->word_ptr=word;
- sptr->tmp_weight=tmp_weight;
-
- doc_cnt++;
-#ifdef EVAL_RUN
- sum +=cnt;
- sum2+=cnt*cnt;
- suml+=cnt*log(cnt);
-#endif /* EVAL_RUN */
-
- if (_mi_test_if_changed(aio->info) == 0)
- r=_mi_search_next(aio->info, aio->keyinfo, aio->info->lastkey,
- aio->info->lastkey_length, SEARCH_BIGGER,
- aio->key_root);
- else
- r=_mi_search(aio->info, aio->keyinfo, aio->info->lastkey,
- aio->info->lastkey_length, SEARCH_BIGGER,
- aio->key_root);
- }
- if(doc_cnt) {
- word->weight*=GWS_IN_USE;
- if(word->weight < 0) word->weight=0;
- }
-
- return 0;
-}
-
-static int walk_and_copy(FT_SUPERDOC *from,
- uint32 count __attribute__((unused)), FT_DOC **to)
-{
- from->doc.weight+=from->tmp_weight*from->word_ptr->weight;
- (*to)->dpos=from->doc.dpos;
- (*to)->weight=from->doc.weight;
- (*to)++;
- return 0;
-}
+/* queries myisam and returns list of documents matched */
static int FT_DOC_cmp(FT_DOC *a, FT_DOC *b)
{
return sgn(b->weight - a->weight);
}
-FT_DOCLIST * ft_init_search(void *info, uint keynr, byte *key,
- uint key_len, my_bool presort)
+FT_DOCLIST *ft_init_search(void *info, uint keynr, byte *query,
+ uint query_len, my_bool presort)
{
- TREE *wtree;
- ALL_IN_ONE aio;
FT_DOCLIST *dlist;
- FT_DOC *dptr;
my_off_t saved_lastpos=((MI_INFO *)info)->lastpos;
/* black magic ON */
@@ -167,44 +38,16 @@ FT_DOCLIST * ft_init_search(void *info, uint keynr, byte *key,
return NULL;
/* black magic OFF */
- dlist=NULL;
- aio.info=(MI_INFO *)info;
- aio.keynr=keynr;
- aio.keybuff=aio.info->lastkey+aio.info->s->base.max_key_length;
- aio.keyinfo=aio.info->s->keyinfo+keynr;
- aio.key_root=aio.info->s->state.key_root[keynr];
-
- if (!(wtree=ft_parse(NULL,key,key_len))) return NULL;
-
- init_tree(&aio.dtree,0,sizeof(FT_SUPERDOC),(qsort_cmp)&FT_SUPERDOC_cmp,0,
- NULL);
-
- if (tree_walk(wtree, (tree_walk_action)&walk_and_match, &aio,
- left_root_right))
- goto err;
-
- dlist=(FT_DOCLIST *) my_malloc(sizeof(FT_DOCLIST)+sizeof(FT_DOC)*
- (aio.dtree.elements_in_tree-1),MYF(0));
- if (!dlist)
- goto err;
-
- dlist->ndocs=aio.dtree.elements_in_tree;
- dlist->curdoc=-1;
- dlist->info=aio.info;
- dptr=dlist->doc;
-
- tree_walk(&aio.dtree, (tree_walk_action)&walk_and_copy, &dptr,
- left_root_right);
+ if (is_boolean(query, query_len))
+ dlist=ft_boolean_search(info,keynr,query,query_len);
+ else
+ dlist=ft_nlq_search(info,keynr,query,query_len);
- if (presort)
+ if(dlist && presort)
{
qsort(dlist->doc, dlist->ndocs, sizeof(FT_DOC), (qsort_cmp)&FT_DOC_cmp);
}
-err:
- delete_tree(&aio.dtree);
- delete_tree(wtree);
- my_free((char*) wtree,MYF(0));
((MI_INFO *)info)->lastpos=saved_lastpos;
return dlist;
}
diff --git a/myisam/ft_update.c b/myisam/ft_update.c
index 658ea9282f3..f8f1d7769aa 100644
--- a/myisam/ft_update.c
+++ b/myisam/ft_update.c
@@ -29,14 +29,16 @@
/* parses a document i.e. calls _mi_ft_parse for every keyseg */
-static FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, byte *keybuf,
+FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, byte *keybuf,
const byte *record)
{
- TREE *parsed=NULL;
+ TREE *parsed, ptree;
MI_KEYSEG *keyseg;
byte *pos;
uint i;
+ bzero(parsed=&ptree, sizeof(ptree));
+
keyseg=info->s->keyinfo[keynr].seg;
for (i=info->s->keyinfo[keynr].keysegs-FT_SEGS ; i-- ; )
{
@@ -64,7 +66,7 @@ static FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, byte *keybuf,
return NULL;
}
/* Handle the case where all columns are NULL */
- if (!parsed && !(parsed=ft_parse(0, (byte*) "", 0)))
+ if (!is_tree_inited(parsed) && !(parsed=ft_parse(parsed, (byte*) "", 0)))
return NULL;
return ft_linearize(info, keynr, keybuf, parsed);
}
@@ -151,6 +153,69 @@ int _mi_ft_cmp(MI_INFO *info, uint keynr, const byte *rec1, const byte *rec2)
return GEE_THEY_ARE_ABSOLUTELY_IDENTICAL;
}
+/* update a document entry */
+int _mi_ft_update(MI_INFO *info, uint keynr, byte *keybuf,
+ const byte *oldrec, const byte *newrec, my_off_t pos)
+{
+ int error= -1;
+ FT_WORD *oldlist,*newlist, *old_word, *new_word;
+ uint key_length;
+ uint cmp;
+
+ if (!(old_word=oldlist=_mi_ft_parserecord(info, keynr, keybuf, oldrec)))
+ goto err0;
+ if (!(new_word=newlist=_mi_ft_parserecord(info, keynr, keybuf, newrec)))
+ goto err1;
+
+ while(old_word->pos && new_word->pos)
+ {
+ cmp=_mi_compare_text(default_charset_info,
+ (uchar*) old_word->pos,old_word->len,
+ (uchar*) new_word->pos,new_word->len,0);
+ if (cmp==0)
+ {
+ double p=(old_word->weight-new_word->weight)/
+ (old_word->weight+new_word->weight);
+ if (p<1e-5)
+ cmp=0;
+ else
+ cmp=sgn(p);
+ }
+ else
+ cmp=sgn(cmp);
+
+ switch (cmp) {
+ case -1:
+ key_length=_ft_make_key(info,keynr,keybuf,old_word,pos);
+ if (error=_mi_ck_delete(info,keynr,(uchar*) keybuf,key_length))
+ goto err2;
+ old_word++;
+ break;
+ case 0:
+ old_word++;
+ new_word++;
+ break;
+ case 1:
+ key_length=_ft_make_key(info,keynr,keybuf,new_word,pos);
+ if (error=_mi_ck_write(info,keynr,(uchar*) keybuf,key_length))
+ goto err2;
+ new_word++;
+ break;
+ }
+ }
+ if (old_word->pos)
+ error=_mi_ft_erase(info,keynr,keybuf,old_word,pos);
+ else if (new_word->pos)
+ error=_mi_ft_store(info,keynr,keybuf,new_word,pos);
+
+err2:
+ my_free((char*) newlist,MYF(0));
+err1:
+ my_free((char*) oldlist,MYF(0));
+err0:
+ return error;
+}
+
/* adds a document to the collection */
int _mi_ft_add(MI_INFO *info, uint keynr, byte *keybuf, const byte *record,
my_off_t pos)
diff --git a/myisam/ftdefs.h b/myisam/ftdefs.h
index ebf99e84d5a..b0aeb652b36 100644
--- a/myisam/ftdefs.h
+++ b/myisam/ftdefs.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
+
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 */
@@ -23,14 +23,21 @@
#include <my_tree.h>
#define MIN_WORD_LEN 4
+#define MAX_WORD_LEN HA_FT_MAXLEN
+#define MAX_WORD_LEN_FOR_SORT 20
#define HYPHEN_IS_DELIM
#define HYPHEN_IS_CONCAT /* not used for now */
#define COMPILE_STOPWORDS_IN
-/* Most of the formulae were shamelessly stolen from SMART distribution
- ftp://ftp.cs.cornell.edu/pub/smart/smart.11.0.tar.Z
+/* Interested readers may consult SMART
+ (ftp://ftp.cs.cornell.edu/pub/smart/smart.11.0.tar.Z)
+ for an excellent implementation of vector space model we use.
+ It also demonstrate the usage of different weghting techniques.
+ This code, though, is completely original and is not based on the
+ SMART code but was in some cases inspired by it.
+
NORM_PIVOT was taken from the article
A.Singhal, C.Buckley, M.Mitra, "Pivoted Document Length Normalization",
ACM SIGIR'96, 21-29, 1996
@@ -82,6 +89,19 @@ extern ulong collstat;
#define GWS_ENTROPY (1-(suml/sum-log(sum))/log(aio->info->state->records))
/*=================================================================*/
+/* Boolean search operators */
+#define FTB_YES '+'
+#define FTB_NO '-'
+#define FTB_INC '>'
+#define FTB_DEC '<'
+#define FTB_LBR '('
+#define FTB_RBR ')'
+#define FTB_NEG '~'
+#define FTB_TRUNC '*'
+
+// #define FTB_MAX_SUBEXPR 255
+// #define FTB_MAX_DEPTH 16
+
typedef struct st_ft_word {
byte * pos;
uint len;
@@ -91,9 +111,26 @@ typedef struct st_ft_word {
#endif /* EVAL_RUN */
} FT_WORD;
+typedef struct st_ftb_param {
+ byte prev;
+ int yesno;
+ int plusminus;
+ bool pmsign;
+ bool trunc;
+} FTB_PARAM;
+
int is_stopword(char *word, uint len);
+int is_boolean(byte *q, uint len);
uint _ft_make_key(MI_INFO *, uint , byte *, FT_WORD *, my_off_t);
+byte ft_get_word(byte **, byte *, FT_WORD *, FTB_PARAM *);
+byte ft_simple_get_word(byte **, byte *, FT_WORD *);
+
TREE * ft_parse(TREE *, byte *, int);
FT_WORD * ft_linearize(MI_INFO *, uint, byte *, TREE *);
+FT_WORD * _mi_ft_parserecord(MI_INFO *, uint , byte *, const byte *);
+
+FT_DOCLIST * ft_nlq_search(MI_INFO *, uint, byte *, uint);
+FT_DOCLIST * ft_boolean_search(MI_INFO *, uint, byte *, uint);
+
diff --git a/myisam/mi_check.c b/myisam/mi_check.c
index 64fbafca022..d588da23d84 100644
--- a/myisam/mi_check.c
+++ b/myisam/mi_check.c
@@ -16,7 +16,7 @@
/* Descript, check and repair of ISAM tables */
-#include "fulltext.h"
+#include "ftdefs.h"
#include <m_ctype.h>
#include <stdarg.h>
#include <getopt.h>
@@ -45,6 +45,7 @@ static int writekeys(MI_INFO *info,byte *buff,my_off_t filepos);
static int sort_one_index(MI_CHECK *param, MI_INFO *info,MI_KEYDEF *keyinfo,
my_off_t pagepos, File new_file);
static int sort_key_read(SORT_INFO *sort_info,void *key);
+static int sort_ft_key_read(SORT_INFO *sort_info,void *key);
static int sort_get_next_record(SORT_INFO *sort_info);
static int sort_key_cmp(SORT_INFO *sort_info, const void *a,const void *b);
static int sort_key_write(SORT_INFO *sort_info, const void *a);
@@ -53,7 +54,7 @@ static my_off_t get_record_for_key(MI_INFO *info,MI_KEYDEF *keyinfo,
static int sort_insert_key(MI_CHECK *param, reg1 SORT_KEY_BLOCKS *key_block,
uchar *key, my_off_t prev_block);
static int sort_delete_record(MI_CHECK *param);
-static int flush_pending_blocks(MI_CHECK *param);
+/*static int flush_pending_blocks(MI_CHECK *param);*/
static SORT_KEY_BLOCKS *alloc_key_blocks(MI_CHECK *param, uint blocks,
uint buffer_length);
static void update_key_parts(MI_KEYDEF *keyinfo,
@@ -1722,22 +1723,6 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
printf("Data records: %s\n", llstr(start_records,llbuff));
}
- /* Hmm, repair_by_sort uses find_all_keys, and find_all_keys strictly
- implies "one row - one key per keynr", while for ft_key one row/keynr
- can produce as many keys as the number of unique words in the text
- that's why I disabled repair_by_sort for ft-keys. (serg)
- */
- for (i=0 ; i < share->base.keys ; i++)
- {
- if ((((ulonglong) 1 << i) & key_map) &&
- (share->keyinfo[i].flag & HA_FULLTEXT))
- {
- mi_check_print_error(param,
- "Can`t use repair_by_sort with FULLTEXT key");
- DBUG_RETURN(1);
- }
- }
-
bzero((char*) sort_info,sizeof(*sort_info));
if (!(sort_info->key_block=
alloc_key_blocks(param,
@@ -1829,6 +1814,8 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
param->read_cache.end_of_file=sort_info->filelength=
my_seek(param->read_cache.file,0L,MY_SEEK_END,MYF(0));
+ sort_info->wordlist=NULL;
+
if (share->data_file_type == DYNAMIC_RECORD)
length=max(share->base.min_pack_length+1,share->base.min_block_length);
else if (share->data_file_type == COMPRESSED_RECORD)
@@ -1840,7 +1827,6 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
(ha_rows) (sort_info->filelength/length+1));
sort_param.key_cmp=sort_key_cmp;
sort_param.key_write=sort_key_write;
- sort_param.key_read=sort_key_read;
sort_param.lock_in_memory=lock_memory;
sort_param.tmpdir=param->tmpdir;
sort_param.myf_rw=param->myf_rw;
@@ -1886,6 +1872,17 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
info->state->records=info->state->del=share->state.split=0;
info->state->empty=0;
+ if (sort_info->keyinfo->flag & HA_FULLTEXT)
+ {
+ sort_param.max_records=sort_info->max_records=
+ (ha_rows) (sort_info->filelength/MAX_WORD_LEN_FOR_SORT+1);
+
+ sort_param.key_read=sort_ft_key_read;
+ sort_param.key_length+=MAX_WORD_LEN_FOR_SORT-MAX_WORD_LEN;
+ }
+ else
+ sort_param.key_read=sort_key_read;
+
if (_create_index_by_sort(&sort_param,
(my_bool) (!(param->testflag & T_VERBOSE)),
(uint) param->sort_buffer_length))
@@ -1930,8 +1927,8 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
else
info->state->data_file_length=sort_info->max_pos;
- if (flush_pending_blocks(param))
- goto err;
+ /*if (flush_pending_blocks(param))
+ goto err;*/
param->read_cache.file=info->dfile; /* re-init read cache */
reinit_io_cache(&param->read_cache,READ_CACHE,share->pack.header_length,1,
@@ -2055,11 +2052,52 @@ static int sort_key_read(SORT_INFO *sort_info, void *key)
"Found too many records; Can`t continue");
DBUG_RETURN(1);
}
- (void) _mi_make_key(info,sort_info->key,key,sort_info->record,
- sort_info->filepos);
+ sort_info->real_key_length=info->s->rec_reflength+_mi_make_key(info,
+ sort_info->key,key,sort_info->record,sort_info->filepos);
DBUG_RETURN(sort_write_record(sort_info));
} /* sort_key_read */
+static int sort_ft_key_read(SORT_INFO *sort_info, void *key)
+{
+ int error;
+ MI_INFO *info;
+ FT_WORD *wptr;
+ DBUG_ENTER("sort_ft_key_read");
+
+ info=sort_info->info;
+
+ if (!sort_info->wordlist)
+ {
+ do
+ {
+ if ((error=sort_get_next_record(sort_info)))
+ DBUG_RETURN(error);
+ if (!(wptr=_mi_ft_parserecord(info,sort_info->key,key,sort_info->record)))
+ DBUG_RETURN(1);
+ error=sort_write_record(sort_info);
+ }
+ while (!wptr->pos);
+ sort_info->wordptr=sort_info->wordlist=wptr;
+ }
+ else
+ {
+ error=0;
+ wptr=(FT_WORD*)(sort_info->wordptr);
+ }
+
+ sort_info->real_key_length=info->s->rec_reflength+_ft_make_key(info,
+ sort_info->key,key,wptr++,sort_info->filepos);
+ if (!wptr->pos)
+ {
+ my_free((char*) sort_info->wordlist, MYF(0));
+ sort_info->wordlist=0;
+ }
+ else
+ sort_info->wordptr=(void*)wptr;
+
+
+ DBUG_RETURN(error);
+} /* sort_ft_key_read */
/* Read next record from file using parameters in sort_info */
/* Return -1 if end of file, 0 if ok and > 0 if error */
@@ -2714,7 +2752,7 @@ static int sort_delete_record(MI_CHECK *param)
/* Fix all pending blocks and flush everything to disk */
-static int flush_pending_blocks(MI_CHECK *param)
+int flush_pending_blocks(MI_CHECK *param)
{
uint nod_flag,length;
my_off_t filepos,key_file_length;
@@ -3181,15 +3219,7 @@ my_bool mi_test_if_sort_rep(MI_INFO *info, ha_rows rows,
return FALSE; /* Can't use sort */
for (i=0 ; i < share->base.keys ; i++,key++)
{
-/* It's to disable repair_by_sort for ft-keys.
- Another solution would be to make ft-keys just too_big_key_for_sort,
- but then they won't be disabled by dectivate_non_unique_index
- and so they will be created at the first stage. As ft-key creation
- is very time-consuming process, it's better to leave it to repair stage
- but this repair shouldn't be repair_by_sort (serg)
- */
- if ((!force && mi_too_big_key_for_sort(key,rows)) ||
- (key->flag & HA_FULLTEXT))
+ if (!force && mi_too_big_key_for_sort(key,rows))
return FALSE;
}
return TRUE;
diff --git a/myisam/mi_open.c b/myisam/mi_open.c
index de1888bc9b7..28f984006df 100644
--- a/myisam/mi_open.c
+++ b/myisam/mi_open.c
@@ -625,15 +625,20 @@ static void setup_key_functions(register MI_KEYDEF *keyinfo)
}
else if (keyinfo->flag & HA_VAR_LENGTH_KEY)
{
- keyinfo->bin_search=_mi_seq_search;
keyinfo->get_key= _mi_get_pack_key;
if (keyinfo->seg[0].flag & HA_PACK_KEY)
{ /* Prefix compression */
+ if (!keyinfo->seg->charset || use_strcoll(keyinfo->seg->charset) ||
+ (keyinfo->seg->flag & HA_NULL_PART))
+ keyinfo->bin_search=_mi_seq_search;
+ else
+ keyinfo->bin_search=_mi_prefix_search;
keyinfo->pack_key=_mi_calc_var_pack_key_length;
keyinfo->store_key=_mi_store_var_pack_key;
}
else
{
+ keyinfo->bin_search=_mi_seq_search;
keyinfo->pack_key=_mi_calc_var_key_length; /* Variable length key */
keyinfo->store_key=_mi_store_static_key;
}
diff --git a/myisam/mi_search.c b/myisam/mi_search.c
index 7888e73b235..dee1b6e847a 100644
--- a/myisam/mi_search.c
+++ b/myisam/mi_search.c
@@ -22,26 +22,26 @@
#define CMP(a,b) (a<b ? -1 : a == b ? 0 : 1)
static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
- uchar *key, uchar *keypos,
- uint *return_key_length);
+ uchar *key, uchar *keypos,
+ uint *return_key_length);
- /* Check index */
+ /* Check index */
int _mi_check_index(MI_INFO *info, int inx)
{
- if (inx == -1) /* Use last index */
+ if (inx == -1) /* Use last index */
inx=info->lastinx;
if (inx < 0 || ! (((ulonglong) 1 << inx) & info->s->state.key_map))
{
my_errno=HA_ERR_WRONG_INDEX;
return -1;
}
- if (info->lastinx != inx) /* Index changed */
+ if (info->lastinx != inx) /* Index changed */
{
info->lastinx = inx;
info->page_changed=1;
info->update= ((info->update & (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED)) |
- HA_STATE_NEXT_FOUND | HA_STATE_PREV_FOUND);
+ HA_STATE_NEXT_FOUND | HA_STATE_PREV_FOUND);
}
if (info->opt_flag & WRITE_CACHE_USED && flush_io_cache(&info->rec_cache))
return(-1);
@@ -49,15 +49,15 @@ int _mi_check_index(MI_INFO *info, int inx)
} /* mi_check_index */
- /*
- ** Search after row by a key
- ** Position to row is stored in info->lastpos
- ** Return: -1 if not found
- ** 1 if one should continue search on higher level
- */
+ /*
+ ** Search after row by a key
+ ** Position to row is stored in info->lastpos
+ ** Return: -1 if not found
+ ** 1 if one should continue search on higher level
+ */
int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
- uchar *key, uint key_len, uint nextflag, register my_off_t pos)
+ uchar *key, uint key_len, uint nextflag, register my_off_t pos)
{
my_bool last_key;
int error,flag;
@@ -66,25 +66,25 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
uchar lastkey[MI_MAX_KEY_BUFF],*buff;
DBUG_ENTER("_mi_search");
DBUG_PRINT("enter",("pos: %ld nextflag: %d lastpos: %ld",
- pos,nextflag,info->lastpos));
+ pos,nextflag,info->lastpos));
DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,keyinfo->seg,key,key_len););
if (pos == HA_OFFSET_ERROR)
{
- my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
+ my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
info->lastpos= HA_OFFSET_ERROR;
if (!(nextflag & (SEARCH_SMALLER | SEARCH_BIGGER | SEARCH_LAST)))
- DBUG_RETURN(-1); /* Not found ; return error */
- DBUG_RETURN(1); /* Search at upper levels */
+ DBUG_RETURN(-1); /* Not found ; return error */
+ DBUG_RETURN(1); /* Search at upper levels */
}
if (!(buff=_mi_fetch_keypage(info,keyinfo,pos,info->buff,
- test(!(nextflag & SEARCH_SAVE_BUFF)))))
+ test(!(nextflag & SEARCH_SAVE_BUFF)))))
goto err;
DBUG_DUMP("page",(byte*) buff,mi_getint(buff));
flag=(*keyinfo->bin_search)(info,keyinfo,buff,key,key_len,nextflag,
- &keypos,lastkey, &last_key);
+ &keypos,lastkey, &last_key);
if (flag == MI_FOUND_WRONG_KEY)
DBUG_RETURN(-1);
nod_flag=mi_test_if_nod(buff);
@@ -93,35 +93,35 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
if (flag)
{
if ((error=_mi_search(info,keyinfo,key,key_len,nextflag,
- _mi_kpos(nod_flag,keypos))) <= 0)
+ _mi_kpos(nod_flag,keypos))) <= 0)
DBUG_RETURN(error);
if (flag >0)
{
if (nextflag & (SEARCH_SMALLER | SEARCH_LAST) &&
- keypos == buff+2+nod_flag)
- DBUG_RETURN(1); /* Bigger than key */
+ keypos == buff+2+nod_flag)
+ DBUG_RETURN(1); /* Bigger than key */
}
else if (nextflag & SEARCH_BIGGER && keypos >= maxpos)
- DBUG_RETURN(1); /* Smaller than key */
+ DBUG_RETURN(1); /* Smaller than key */
}
else
{
if (nextflag & SEARCH_FIND && (!(keyinfo->flag & HA_NOSAME)
- || key_len) && nod_flag)
+ || key_len) && nod_flag)
{
if ((error=_mi_search(info,keyinfo,key,key_len,SEARCH_FIND,
- _mi_kpos(nod_flag,keypos))) >= 0 ||
- my_errno != HA_ERR_KEY_NOT_FOUND)
- DBUG_RETURN(error);
- info->last_keypage= HA_OFFSET_ERROR; /* Buffer not in memory */
+ _mi_kpos(nod_flag,keypos))) >= 0 ||
+ my_errno != HA_ERR_KEY_NOT_FOUND)
+ DBUG_RETURN(error);
+ info->last_keypage= HA_OFFSET_ERROR; /* Buffer not in memory */
}
}
if (pos != info->last_keypage)
{
uchar *old_buff=buff;
if (!(buff=_mi_fetch_keypage(info,keyinfo,pos,info->buff,
- test(!(nextflag & SEARCH_SAVE_BUFF)))))
+ test(!(nextflag & SEARCH_SAVE_BUFF)))))
goto err;
keypos=buff+(keypos-old_buff);
maxpos=buff+(maxpos-old_buff);
@@ -131,13 +131,13 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
{
uint not_used;
if (_mi_get_prev_key(info,keyinfo, buff, info->lastkey, keypos,
- &info->lastkey_length))
+ &info->lastkey_length))
goto err;
if ((nextflag & SEARCH_LAST) &&
- _mi_key_cmp(keyinfo->seg, info->lastkey, key, key_len, SEARCH_FIND,
- &not_used))
+ _mi_key_cmp(keyinfo->seg, info->lastkey, key, key_len, SEARCH_FIND,
+ &not_used))
{
- my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
+ my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
goto err;
}
}
@@ -156,7 +156,7 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
info->int_keytree_version=keyinfo->version;
info->last_search_keypage=info->last_keypage;
info->page_changed=0;
- info->buff_used= (info->buff != buff); /* If we have to reread buff */
+ info->buff_used= (info->buff != buff); /* If we have to reread buff */
DBUG_PRINT("exit",("found key at %ld",info->lastpos));
DBUG_RETURN(0);
@@ -168,14 +168,14 @@ err:
} /* _mi_search */
- /* Search after key in page-block */
- /* If packed key puts smaller or identical key in buff */
- /* ret_pos point to where find or bigger key starts */
- /* ARGSUSED */
+ /* Search after key in page-block */
+ /* If packed key puts smaller or identical key in buff */
+ /* ret_pos point to where find or bigger key starts */
+ /* ARGSUSED */
int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
- uchar *key, uint key_len, uint comp_flag, uchar **ret_pos,
- uchar *buff __attribute__((unused)), my_bool *last_key)
+ uchar *key, uint key_len, uint comp_flag, uchar **ret_pos,
+ uchar *buff __attribute__((unused)), my_bool *last_key)
{
reg4 int start,mid,end,save_end;
int flag;
@@ -193,17 +193,17 @@ int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
{
mid= (start+end)/2;
if ((flag=_mi_key_cmp(keyinfo->seg,page+(uint) mid*totlength,key,key_len,
- comp_flag,&not_used))
- >= 0)
+ comp_flag,&not_used))
+ >= 0)
end=mid;
else
start=mid+1;
}
if (mid != start)
flag=_mi_key_cmp(keyinfo->seg,page+(uint) start*totlength,key,key_len,
- comp_flag,&not_used);
+ comp_flag,&not_used);
if (flag < 0)
- start++; /* point at next, bigger key */
+ start++; /* point at next, bigger key */
*ret_pos=page+(uint) start*totlength;
*last_key= end == save_end;
DBUG_PRINT("exit",("flag: %d keypos: %d",flag,start));
@@ -211,13 +211,13 @@ int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
} /* _mi_bin_search */
- /* Used instead of _mi_bin_search() when key is packed */
- /* Puts smaller or identical key in buff */
- /* Key is searched sequentially */
+ /* Used instead of _mi_bin_search() when key is packed */
+ /* Puts smaller or identical key in buff */
+ /* Key is searched sequentially */
int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
- uchar *key, uint key_len, uint comp_flag, uchar **ret_pos,
- uchar *buff, my_bool *last_key)
+ uchar *key, uint key_len, uint comp_flag, uchar **ret_pos,
+ uchar *buff, my_bool *last_key)
{
int flag;
uint nod_flag,length,not_used;
@@ -229,7 +229,7 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
nod_flag=mi_test_if_nod(page);
page+=2+nod_flag;
*ret_pos=page;
- t_buff[0]=0; /* Avoid bugs */
+ t_buff[0]=0; /* Avoid bugs */
while (page < end)
{
length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,t_buff);
@@ -237,11 +237,11 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
{
my_errno=HA_ERR_CRASHED;
DBUG_PRINT("error",("Found wrong key: length: %d page: %lx end: %lx",
- length,page,end));
+ length,page,end));
DBUG_RETURN(MI_FOUND_WRONG_KEY);
}
if ((flag=_mi_key_cmp(keyinfo->seg,t_buff,key,key_len,comp_flag,
- &not_used)) >= 0)
+ &not_used)) >= 0)
break;
#ifdef EXTRA_DEBUG
DBUG_PRINT("loop",("page: %lx key: '%s' flag: %d",page,t_buff,flag));
@@ -250,14 +250,216 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
*ret_pos=page;
}
if (flag == 0)
- memcpy(buff,t_buff,length); /* Result is first key */
+ memcpy(buff,t_buff,length); /* Result is first key */
*last_key= page == end;
DBUG_PRINT("exit",("flag: %d ret_pos: %lx",flag,*ret_pos));
DBUG_RETURN(flag);
} /* _mi_seq_search */
+int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
+ uchar *key, uint key_len, uint nextflag, uchar **ret_pos,
+ uchar *buff, my_bool *last_key)
+{
+ /* my_flag is raw comparison result to be changed according to
+ SEARCH_NO_FIND,SEARCH_LAST and HA_REVERSE_SORT flags.
+ flag is the value returned by _mi_key_cmp and as treated as final */
+ int flag=0, my_flag=-1;
+ uint nod_flag, length, len, matched, cmplen, kseg_len, key_len_left;
+ uint prefix_len,suffix_len;
+ int key_len_skip, seg_len_pack;
+ uchar *end, *kseg, *vseg;
+ uchar *sort_order=keyinfo->seg->charset->sort_order;
+ uchar tt_buff[MI_MAX_KEY_BUFF+2], *t_buff=tt_buff+2;
+ uchar *saved_from, *saved_to, *saved_vseg;
+ uint saved_length=0, saved_prefix_len=0;
+ DBUG_ENTER("_mi_prefix_search");
+
+ t_buff[0]=0; /* Avoid bugs */
+ if (!(nextflag & (SEARCH_FIND | SEARCH_NO_FIND | SEARCH_LAST)))
+ key_len=USE_WHOLE_KEY;
+ end= page+mi_getint(page);
+ nod_flag=mi_test_if_nod(page);
+ page+=2+nod_flag;
+ *ret_pos=page;
+ kseg=key;
+ {
+ uint lenght_pack;
+ get_key_pack_length(kseg_len,lenght_pack,kseg);
+ key_len_skip=lenght_pack+kseg_len;
+ key_len_left=key_len-key_len_skip;
+ cmplen=(key_len_left>=0) ? kseg_len : key_len-lenght_pack;
+ }
+
+/*
+ Keys are compressed the following way:
+
+ If the max length of first key segment <= 127 characters the prefix is
+ 1 byte else it's 2 byte
+
+ prefix The high bit is set if this is a prefix for the prev key
+ length Packed length if the previous was a prefix byte
+ [length] Length character of data
+ next-key-seg Next key segments
+*/
+
+ matched=0; /* how many char's from prefix were alredy matched */
+ len=0; /* length of previous key unpacked */
+
+ while (page < end)
+ {
+ uint packed= *page & 128;
+
+ vseg=page;
+ if (keyinfo->seg->length >= 127)
+ {
+ suffix_len=mi_uint2korr(vseg) & 32767;
+ vseg+=2;
+ }
+ else
+ suffix_len= *vseg++ & 127;
+
+ if (packed)
+ {
+ if (suffix_len == 0) /* Same key */
+ prefix_len=len;
+ else
+ {
+ prefix_len=suffix_len;
+ get_key_length(suffix_len,vseg);
+ }
+ }
+ else
+ prefix_len=0;
+
+ len=prefix_len+suffix_len;
+ seg_len_pack=get_pack_length(len);
+ t_buff=tt_buff+3-seg_len_pack;
+ store_key_length(t_buff,len);
- /* Get pos to a key_block */
+ if (prefix_len > saved_prefix_len)
+ memcpy(t_buff+seg_len_pack+saved_prefix_len,saved_vseg,
+ prefix_len-saved_prefix_len);
+ saved_vseg=vseg;
+ saved_prefix_len=prefix_len;
+
+ {
+ uchar *from=vseg+suffix_len;
+ MI_KEYSEG *keyseg;
+ uint l;
+
+ for (keyseg=keyinfo->seg+1 ; keyseg->type ; keyseg++ )
+ {
+
+ if (keyseg->flag & HA_NULL_PART)
+ {
+ if (!(*from++))
+ continue;
+ }
+ if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK))
+ {
+ get_key_length(l,from);
+ }
+ else
+ l=keyseg->length;
+
+ from+=l;
+ }
+ from+=keyseg->length;
+ page=from+nod_flag;
+ length=from-vseg;
+ }
+
+ if (page > end)
+ {
+ my_errno=HA_ERR_CRASHED;
+ DBUG_PRINT("error",("Found wrong key: length: %d page: %lx end: %lx",
+ length,page,end));
+ DBUG_RETURN(MI_FOUND_WRONG_KEY);
+ }
+
+ if (matched >= prefix_len)
+ {
+ /* We have to compare. But we can still skip part of the key */
+ uint left;
+ uchar *k=kseg+prefix_len;
+
+ left=(len>cmplen) ? cmplen-prefix_len : suffix_len;
+
+ matched=prefix_len+left;
+
+ for(my_flag=0;left;left--)
+ if ((my_flag= (int) sort_order[*vseg++] - (int) sort_order[*k++]))
+ break;
+
+ if (my_flag>0) /* mismatch */
+ break;
+ else if (my_flag==0) /* match */
+ { /*
+ ** len cmplen seg_left_len more_segs
+ ** < matched=len; continue search
+ ** > = prefix ? found : (matched=len; continue search)
+ ** > < - ok, found
+ ** = < - ok, found
+ ** = = - ok, found
+ ** = = + next seg
+ */
+ if (len < cmplen)
+ {
+ my_flag=-1;
+ }
+ else if (len > cmplen)
+ {
+ if(my_flag = !(nextflag & SEARCH_PREFIX) && key_len_left>0)
+ break;
+ goto fix_flag;
+ }
+ else if (key_len_left>0)
+ {
+ uint not_used;
+ if ((flag = _mi_key_cmp(keyinfo->seg+1,vseg,
+ k,key_len_left,nextflag,&not_used)) >= 0)
+ break;
+ }
+ else
+ {
+ /* at this line flag==-1 if the following lines were already
+ visited and 0 otherwise, i.e. flag <=0 here always !!! */
+ fix_flag:
+ if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST))
+ flag=(nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
+ if (flag>=0) break;
+ }
+ }
+ matched-=left;
+ }
+ /* else (matched < prefix_len) ---> do nothing. */
+
+ memcpy(buff,t_buff,saved_length=seg_len_pack+prefix_len);
+ saved_to=buff+saved_length;
+ saved_from=saved_vseg;
+ saved_length=length;
+ *ret_pos=page;
+ }
+ if (my_flag)
+ flag=(keyinfo->seg->flag & HA_REVERSE_SORT) ? -my_flag : my_flag;
+ if (flag == 0)
+ {
+ memcpy(buff,t_buff,saved_length=seg_len_pack+prefix_len);
+ saved_to=buff+saved_length;
+ saved_from=saved_vseg;
+ saved_length=length;
+ }
+ if (saved_length)
+ memcpy(saved_to,saved_from,saved_length);
+
+ *last_key= page == end;
+
+ DBUG_PRINT("exit",("flag: %d ret_pos: %lx",flag,*ret_pos));
+ DBUG_RETURN(flag);
+} /* _mi_prefix_search */
+
+
+ /* Get pos to a key_block */
my_off_t _mi_kpos(uint nod_flag, uchar *after_key)
{
@@ -286,14 +488,14 @@ my_off_t _mi_kpos(uint nod_flag, uchar *after_key)
return (my_off_t) (mi_uint2korr(after_key)*MI_KEY_BLOCK_LENGTH);
case 1:
return (uint) (*after_key)*MI_KEY_BLOCK_LENGTH;
- case 0: /* At leaf page */
- default: /* Impossible */
+ case 0: /* At leaf page */
+ default: /* Impossible */
return(HA_OFFSET_ERROR);
}
} /* _kpos */
- /* Save pos to a key_block */
+ /* Save pos to a key_block */
void _mi_kpointer(register MI_INFO *info, register uchar *buff, my_off_t pos)
{
@@ -315,12 +517,12 @@ void _mi_kpointer(register MI_INFO *info, register uchar *buff, my_off_t pos)
case 3: mi_int3store(buff,pos); break;
case 2: mi_int2store(buff,(uint) pos); break;
case 1: buff[0]= (uchar) pos; break;
- default: abort(); /* impossible */
+ default: abort(); /* impossible */
}
} /* _mi_kpointer */
- /* Calc pos to a data-record from a key */
+ /* Calc pos to a data-record from a key */
my_off_t _mi_dpos(MI_INFO *info, uint nod_flag, uchar *after_key)
@@ -335,19 +537,19 @@ my_off_t _mi_dpos(MI_INFO *info, uint nod_flag, uchar *after_key)
case 5: pos= (my_off_t) mi_uint5korr(after_key); break;
#else
case 8: pos= (my_off_t) mi_uint4korr(after_key+4); break;
- case 7: pos= (my_off_t) mi_uint4korr(after_key+3); break;
- case 6: pos= (my_off_t) mi_uint4korr(after_key+2); break;
- case 5: pos= (my_off_t) mi_uint4korr(after_key+1); break;
+ case 7: pos= (my_off_t) mi_uint4korr(after_key+3); break;
+ case 6: pos= (my_off_t) mi_uint4korr(after_key+2); break;
+ case 5: pos= (my_off_t) mi_uint4korr(after_key+1); break;
#endif
case 4: pos= (my_off_t) mi_uint4korr(after_key); break;
case 3: pos= (my_off_t) mi_uint3korr(after_key); break;
case 2: pos= (my_off_t) mi_uint2korr(after_key); break;
default:
- pos=0L; /* Shut compiler up */
+ pos=0L; /* Shut compiler up */
}
return (info->s->options &
- (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos :
- pos*info->s->base.pack_reclength;
+ (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos :
+ pos*info->s->base.pack_reclength;
}
@@ -361,22 +563,22 @@ my_off_t _mi_rec_pos(MYISAM_SHARE *s, uchar *ptr)
case 8:
pos= (my_off_t) mi_uint8korr(ptr);
if (pos == HA_OFFSET_ERROR)
- return HA_OFFSET_ERROR; /* end of list */
+ return HA_OFFSET_ERROR; /* end of list */
break;
case 7:
pos= (my_off_t) mi_uint7korr(ptr);
if (pos == (((my_off_t) 1) << 56) -1)
- return HA_OFFSET_ERROR; /* end of list */
+ return HA_OFFSET_ERROR; /* end of list */
break;
case 6:
pos= (my_off_t) mi_uint6korr(ptr);
if (pos == (((my_off_t) 1) << 48) -1)
- return HA_OFFSET_ERROR; /* end of list */
+ return HA_OFFSET_ERROR; /* end of list */
break;
case 5:
pos= (my_off_t) mi_uint5korr(ptr);
if (pos == (((my_off_t) 1) << 40) -1)
- return HA_OFFSET_ERROR; /* end of list */
+ return HA_OFFSET_ERROR; /* end of list */
break;
#else
case 8:
@@ -401,20 +603,20 @@ my_off_t _mi_rec_pos(MYISAM_SHARE *s, uchar *ptr)
if (pos == (my_off_t) (1 << 16) -1)
return HA_OFFSET_ERROR;
break;
- default: abort(); /* Impossible */
+ default: abort(); /* Impossible */
}
return ((s->options &
- (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos :
- pos*s->base.pack_reclength);
+ (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos :
+ pos*s->base.pack_reclength);
}
- /* save position to record */
+ /* save position to record */
void _mi_dpointer(MI_INFO *info, uchar *buff, my_off_t pos)
{
if (!(info->s->options &
- (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) &&
+ (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) &&
pos != HA_OFFSET_ERROR)
pos/=info->s->base.pack_reclength;
@@ -437,13 +639,13 @@ void _mi_dpointer(MI_INFO *info, uchar *buff, my_off_t pos)
case 4: mi_int4store(buff,pos); break;
case 3: mi_int3store(buff,pos); break;
case 2: mi_int2store(buff,(uint) pos); break;
- default: abort(); /* Impossible */
+ default: abort(); /* Impossible */
}
} /* _mi_dpointer */
int _mi_compare_text(CHARSET_INFO *charset_info, uchar *a, uint a_length,
- uchar *b, uint b_length, my_bool part_key)
+ uchar *b, uint b_length, my_bool part_key)
{
uint length= min(a_length,b_length);
uchar *end= a+ length;
@@ -470,7 +672,7 @@ int _mi_compare_text(CHARSET_INFO *charset_info, uchar *a, uint a_length,
static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
- my_bool part_key)
+ my_bool part_key)
{
uint length= min(a_length,b_length);
uchar *end= a+ length;
@@ -485,19 +687,19 @@ static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
}
- /*
- ** Compare two keys with is bigger
- ** Returns <0, 0, >0 acording to with is bigger
- ** Key_length specifies length of key to use. Number-keys can't
- ** be splited
- ** If flag <> SEARCH_FIND compare also position
- */
+ /*
+ ** Compare two keys with is bigger
+ ** Returns <0, 0, >0 acording to with is bigger
+ ** Key_length specifies length of key to use. Number-keys can't
+ ** be splited
+ ** If flag <> SEARCH_FIND compare also position
+ */
#define FCMP(A,B) ((int) (A) - (int) (B))
int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a,
- register uchar *b, uint key_length, uint nextflag,
- uint *diff_pos)
+ register uchar *b, uint key_length, uint nextflag,
+ uint *diff_pos)
{
int flag;
int16 s_1,s_2;
@@ -522,106 +724,106 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a,
key_length--;
if (*a != *b)
{
- flag = (int) *a - (int) *b;
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ flag = (int) *a - (int) *b;
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
}
b++;
- if (!*a++) /* If key was NULL */
+ if (!*a++) /* If key was NULL */
{
- if (nextflag == (SEARCH_FIND | SEARCH_UPDATE))
- nextflag=SEARCH_SAME; /* Allow duplicate keys */
- next_key_length=key_length;
- continue; /* To next key part */
+ if (nextflag == (SEARCH_FIND | SEARCH_UPDATE))
+ nextflag=SEARCH_SAME; /* Allow duplicate keys */
+ next_key_length=key_length;
+ continue; /* To next key part */
}
}
end= a+ min(keyseg->length,key_length);
next_key_length=key_length-keyseg->length;
switch ((enum ha_base_keytype) keyseg->type) {
- case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */
+ case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */
if (keyseg->flag & HA_SPACE_PACK)
{
- int a_length,b_length,pack_length;
- get_key_length(a_length,a);
- get_key_pack_length(b_length,pack_length,b);
- next_key_length=key_length-b_length-pack_length;
-
- if ((flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length,
- (my_bool) ((nextflag & SEARCH_PREFIX) &&
- next_key_length <= 0))))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
- a+=a_length;
- b+=b_length;
- break;
+ int a_length,b_length,pack_length;
+ get_key_length(a_length,a);
+ get_key_pack_length(b_length,pack_length,b);
+ next_key_length=key_length-b_length-pack_length;
+
+ if ((flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length,
+ (my_bool) ((nextflag & SEARCH_PREFIX) &&
+ next_key_length <= 0))))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ a+=a_length;
+ b+=b_length;
+ break;
}
else
{
- uint length=(uint) (end-a);
- if ((flag=_mi_compare_text(keyseg->charset,a,length,b,length,
- (my_bool) ((nextflag & SEARCH_PREFIX) &&
- next_key_length <= 0))))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
- a=end;
- b+=length;
+ uint length=(uint) (end-a);
+ if ((flag=_mi_compare_text(keyseg->charset,a,length,b,length,
+ (my_bool) ((nextflag & SEARCH_PREFIX) &&
+ next_key_length <= 0))))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ a=end;
+ b+=length;
}
break;
case HA_KEYTYPE_BINARY:
if (keyseg->flag & HA_SPACE_PACK)
{
- int a_length,b_length,pack_length;
- get_key_length(a_length,a);
- get_key_pack_length(b_length,pack_length,b);
- next_key_length=key_length-b_length-pack_length;
-
- if ((flag=compare_bin(a,a_length,b,b_length,
- (my_bool) ((nextflag & SEARCH_PREFIX) &&
- next_key_length <= 0))))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
- a+=a_length;
- b+=b_length;
- break;
+ int a_length,b_length,pack_length;
+ get_key_length(a_length,a);
+ get_key_pack_length(b_length,pack_length,b);
+ next_key_length=key_length-b_length-pack_length;
+
+ if ((flag=compare_bin(a,a_length,b,b_length,
+ (my_bool) ((nextflag & SEARCH_PREFIX) &&
+ next_key_length <= 0))))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ a+=a_length;
+ b+=b_length;
+ break;
}
else
{
- uint length=keyseg->length;
- if ((flag=compare_bin(a,length,b,length,
- (my_bool) ((nextflag & SEARCH_PREFIX) &&
- next_key_length <= 0))))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
- a+=length;
- b+=length;
+ uint length=keyseg->length;
+ if ((flag=compare_bin(a,length,b,length,
+ (my_bool) ((nextflag & SEARCH_PREFIX) &&
+ next_key_length <= 0))))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ a+=length;
+ b+=length;
}
break;
case HA_KEYTYPE_VARTEXT:
{
- int a_length,b_length,pack_length;
- get_key_length(a_length,a);
- get_key_pack_length(b_length,pack_length,b);
- next_key_length=key_length-b_length-pack_length;
-
- if ((flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length,
- (my_bool) ((nextflag & SEARCH_PREFIX) &&
- next_key_length <= 0))))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
- a+=a_length;
- b+=b_length;
- break;
+ int a_length,b_length,pack_length;
+ get_key_length(a_length,a);
+ get_key_pack_length(b_length,pack_length,b);
+ next_key_length=key_length-b_length-pack_length;
+
+ if ((flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length,
+ (my_bool) ((nextflag & SEARCH_PREFIX) &&
+ next_key_length <= 0))))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ a+=a_length;
+ b+=b_length;
+ break;
}
break;
case HA_KEYTYPE_VARBINARY:
{
- int a_length,b_length,pack_length;
- get_key_length(a_length,a);
- get_key_pack_length(b_length,pack_length,b);
- next_key_length=key_length-b_length-pack_length;
-
- if ((flag=compare_bin(a,a_length,b,b_length,
- (my_bool) ((nextflag & SEARCH_PREFIX) &&
- next_key_length <= 0))))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
- a+=a_length;
- b+=b_length;
- break;
+ int a_length,b_length,pack_length;
+ get_key_length(a_length,a);
+ get_key_pack_length(b_length,pack_length,b);
+ next_key_length=key_length-b_length-pack_length;
+
+ if ((flag=compare_bin(a,a_length,b,b_length,
+ (my_bool) ((nextflag & SEARCH_PREFIX) &&
+ next_key_length <= 0))))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ a+=a_length;
+ b+=b_length;
+ break;
}
break;
case HA_KEYTYPE_INT8:
@@ -629,7 +831,7 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a,
int i_1= (int) *((signed char*) a);
int i_2= (int) *((signed char*) b);
if ((flag = CMP(i_1,i_2)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b++;
break;
@@ -638,26 +840,26 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a,
s_1= mi_sint2korr(a);
s_2= mi_sint2korr(b);
if ((flag = CMP(s_1,s_2)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 2; /* sizeof(short int); */
break;
case HA_KEYTYPE_USHORT_INT:
{
- uint16 us_1,us_2;
- us_1= mi_sint2korr(a);
- us_2= mi_sint2korr(b);
- if ((flag = CMP(us_1,us_2)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
- a= end;
- b+=2; /* sizeof(short int); */
- break;
+ uint16 us_1,us_2;
+ us_1= mi_sint2korr(a);
+ us_2= mi_sint2korr(b);
+ if ((flag = CMP(us_1,us_2)))
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ a= end;
+ b+=2; /* sizeof(short int); */
+ break;
}
case HA_KEYTYPE_LONG_INT:
l_1= mi_sint4korr(a);
l_2= mi_sint4korr(b);
if ((flag = CMP(l_1,l_2)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 4; /* sizeof(long int); */
break;
@@ -665,7 +867,7 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a,
u_1= mi_sint4korr(a);
u_2= mi_sint4korr(b);
if ((flag = CMP(u_1,u_2)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 4; /* sizeof(long int); */
break;
@@ -673,7 +875,7 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a,
l_1=mi_sint3korr(a);
l_2=mi_sint3korr(b);
if ((flag = CMP(l_1,l_2)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 3;
break;
@@ -681,7 +883,7 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a,
l_1=mi_uint3korr(a);
l_2=mi_uint3korr(b);
if ((flag = CMP(l_1,l_2)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 3;
break;
@@ -689,7 +891,7 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a,
mi_float4get(f_1,a);
mi_float4get(f_2,b);
if ((flag = CMP(f_1,f_2)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 4; /* sizeof(float); */
break;
@@ -697,65 +899,65 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a,
mi_float8get(d_1,a);
mi_float8get(d_2,b);
if ((flag = CMP(d_1,d_2)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 8; /* sizeof(double); */
break;
- case HA_KEYTYPE_NUM: /* Numeric key */
+ case HA_KEYTYPE_NUM: /* Numeric key */
{
int swap_flag= 0;
int alength,blength;
if (keyseg->flag & HA_REVERSE_SORT)
{
- swap(uchar*,a,b);
- swap_flag=1; /* Remember swap of a & b */
+ swap(uchar*,a,b);
+ swap_flag=1; /* Remember swap of a & b */
end= a+ (int) (end-b);
}
if (keyseg->flag & HA_SPACE_PACK)
{
- alength= *a++; blength= *b++;
- end=a+alength;
- next_key_length=key_length-blength-1;
+ alength= *a++; blength= *b++;
+ end=a+alength;
+ next_key_length=key_length-blength-1;
}
else
{
- alength= (int) (end-a);
- blength=keyseg->length;
- /* remove pre space from keys */
- for ( ; alength && *a == ' ' ; a++, alength--) ;
- for ( ; blength && *b == ' ' ; b++, blength--) ;
+ alength= (int) (end-a);
+ blength=keyseg->length;
+ /* remove pre space from keys */
+ for ( ; alength && *a == ' ' ; a++, alength--) ;
+ for ( ; blength && *b == ' ' ; b++, blength--) ;
}
if (*a == '-')
{
- if (*b != '-')
- return -1;
- a++; b++;
- swap(uchar*,a,b);
- swap(int,alength,blength);
- swap_flag=1-swap_flag;
- alength--; blength--;
- end=a+alength;
+ if (*b != '-')
+ return -1;
+ a++; b++;
+ swap(uchar*,a,b);
+ swap(int,alength,blength);
+ swap_flag=1-swap_flag;
+ alength--; blength--;
+ end=a+alength;
}
else if (*b == '-')
- return 1;
+ return 1;
while (alength && (*a == '+' || *a == '0'))
{
- a++; alength--;
+ a++; alength--;
}
while (blength && (*b == '+' || *b == '0'))
{
- b++; blength--;
+ b++; blength--;
}
if (alength != blength)
- return (alength < blength) ? -1 : 1;
+ return (alength < blength) ? -1 : 1;
while (a < end)
- if (*a++ != *b++)
- return ((int) a[-1] - (int) b[-1]);
+ if (*a++ != *b++)
+ return ((int) a[-1] - (int) b[-1]);
- if (swap_flag) /* Restore pointers */
- swap(uchar*,a,b);
+ if (swap_flag) /* Restore pointers */
+ swap(uchar*,a,b);
break;
}
#ifdef HAVE_LONG_LONG
@@ -765,7 +967,7 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a,
ll_a= mi_sint8korr(a);
ll_b= mi_sint8korr(b);
if ((flag = CMP(ll_a,ll_b)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 8;
break;
@@ -776,14 +978,14 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a,
ll_a= mi_uint8korr(a);
ll_b= mi_uint8korr(b);
if ((flag = CMP(ll_a,ll_b)))
- return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 8;
break;
}
#endif
- case HA_KEYTYPE_END: /* Ready */
- goto end; /* diff_pos is incremented */
+ case HA_KEYTYPE_END: /* Ready */
+ goto end; /* diff_pos is incremented */
}
}
(*diff_pos)++;
@@ -798,33 +1000,33 @@ end:
{
if (*a++ != *b++)
{
- flag= FCMP(a[-1],b[-1]);
- break;
+ flag= FCMP(a[-1],b[-1]);
+ break;
}
}
if (nextflag & SEARCH_SAME)
- return (flag); /* read same */
+ return (flag); /* read same */
if (nextflag & SEARCH_BIGGER)
- return (flag <= 0 ? -1 : 1); /* read next */
- return (flag < 0 ? -1 : 1); /* read previous */
+ return (flag <= 0 ? -1 : 1); /* read next */
+ return (flag < 0 ? -1 : 1); /* read previous */
}
return 0;
} /* _mi_key_cmp */
- /* Get key from key-block */
- /* page points at previous key; its advanced to point at next key */
- /* key should contain previous key */
- /* Returns length of found key + pointers */
- /* nod_flag is a flag if we are on nod */
+ /* Get key from key-block */
+ /* page points at previous key; its advanced to point at next key */
+ /* key should contain previous key */
+ /* Returns length of found key + pointers */
+ /* nod_flag is a flag if we are on nod */
- /* same as _mi_get_key but used with fixed length keys */
+ /* same as _mi_get_key but used with fixed length keys */
uint _mi_get_static_key(register MI_KEYDEF *keyinfo, uint nod_flag,
- register uchar **page, register uchar *key)
+ register uchar **page, register uchar *key)
{
memcpy((byte*) key,(byte*) *page,
- (size_t) (keyinfo->keylength+nod_flag));
+ (size_t) (keyinfo->keylength+nod_flag));
*page+=keyinfo->keylength+nod_flag;
return(keyinfo->keylength);
} /* _mi_get_static_key */
@@ -833,7 +1035,7 @@ uint _mi_get_static_key(register MI_KEYDEF *keyinfo, uint nod_flag,
/* Key with is packed against previous key or key with a NULL column */
uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
- register uchar **page_pos, register uchar *key)
+ register uchar **page_pos, register uchar *key)
{
reg1 MI_KEYSEG *keyseg;
uchar *start_key,*page=*page_pos;
@@ -849,85 +1051,85 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
uint packed= *page & 128,tot_length,rest_length;
if (keyseg->length >= 127)
{
- length=mi_uint2korr(page) & 32767;
- page+=2;
+ length=mi_uint2korr(page) & 32767;
+ page+=2;
}
else
- length= *page++ & 127;
+ length= *page++ & 127;
if (packed)
{
- if (length > (uint) keyseg->length)
- {
- my_errno=HA_ERR_CRASHED;
- return 0; /* Error */
- }
- if (length == 0) /* Same key */
- {
- if (keyseg->flag & HA_NULL_PART)
- *key++=1; /* Can't be NULL */
- get_key_length(length,key);
- key+= length; /* Same diff_key as prev */
- if (length > keyseg->length)
- {
- DBUG_PRINT("error",("Found too long null packed key: %d of %d at %lx",
- length, keyseg->length, *page_pos));
- DBUG_DUMP("key",(char*) *page_pos,16);
- my_errno=HA_ERR_CRASHED;
- return 0;
- }
- continue;
- }
- if (keyseg->flag & HA_NULL_PART)
- key++; /* Skipp null marker*/
-
- get_key_length(rest_length,page);
- tot_length=rest_length+length;
-
- /* If the stored length has changed, we must move the key */
- if (tot_length >= 255 && *start != 255)
- {
- /* length prefix changed from a length of one to a length of 3 */
- bmove_upp((char*) key+length+3,(char*) key+length+1,length);
- *key=255;
- mi_int2store(key+1,tot_length);
- key+=3+length;
- }
- else if (tot_length < 255 && *start == 255)
- {
- bmove(key+1,key+3,length);
- *key=tot_length;
- key+=1+length;
- }
- else
- {
- store_key_length_inc(key,tot_length);
- key+=length;
- }
- memcpy(key,page,rest_length);
- page+=rest_length;
- key+=rest_length;
- continue;
+ if (length > (uint) keyseg->length)
+ {
+ my_errno=HA_ERR_CRASHED;
+ return 0; /* Error */
+ }
+ if (length == 0) /* Same key */
+ {
+ if (keyseg->flag & HA_NULL_PART)
+ *key++=1; /* Can't be NULL */
+ get_key_length(length,key);
+ key+= length; /* Same diff_key as prev */
+ if (length > keyseg->length)
+ {
+ DBUG_PRINT("error",("Found too long null packed key: %d of %d at %lx",
+ length, keyseg->length, *page_pos));
+ DBUG_DUMP("key",(char*) *page_pos,16);
+ my_errno=HA_ERR_CRASHED;
+ return 0;
+ }
+ continue;
+ }
+ if (keyseg->flag & HA_NULL_PART)
+ key++; /* Skipp null marker*/
+
+ get_key_length(rest_length,page);
+ tot_length=rest_length+length;
+
+ /* If the stored length has changed, we must move the key */
+ if (tot_length >= 255 && *start != 255)
+ {
+ /* length prefix changed from a length of one to a length of 3 */
+ bmove_upp((char*) key+length+3,(char*) key+length+1,length);
+ *key=255;
+ mi_int2store(key+1,tot_length);
+ key+=3+length;
+ }
+ else if (tot_length < 255 && *start == 255)
+ {
+ bmove(key+1,key+3,length);
+ *key=tot_length;
+ key+=1+length;
+ }
+ else
+ {
+ store_key_length_inc(key,tot_length);
+ key+=length;
+ }
+ memcpy(key,page,rest_length);
+ page+=rest_length;
+ key+=rest_length;
+ continue;
}
else
{
- if (keyseg->flag & HA_NULL_PART)
- {
- if (!length--) /* Null part */
- {
- *key++=0;
- continue;
- }
- *key++=1; /* Not null */
- }
+ if (keyseg->flag & HA_NULL_PART)
+ {
+ if (!length--) /* Null part */
+ {
+ *key++=0;
+ continue;
+ }
+ *key++=1; /* Not null */
+ }
}
if (length > (uint) keyseg->length)
{
- DBUG_PRINT("error",("Found too long packed key: %d of %d at %lx",
- length, keyseg->length, *page_pos));
- DBUG_DUMP("key",(char*) *page_pos,16);
- my_errno=HA_ERR_CRASHED;
- return 0; /* Error */
+ DBUG_PRINT("error",("Found too long packed key: %d of %d at %lx",
+ length, keyseg->length, *page_pos));
+ DBUG_DUMP("key",(char*) *page_pos,16);
+ my_errno=HA_ERR_CRASHED;
+ return 0; /* Error */
}
store_key_length_inc(key,length);
}
@@ -935,18 +1137,18 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
{
if (keyseg->flag & HA_NULL_PART)
{
- if (!(*key++ = *page++))
- continue;
+ if (!(*key++ = *page++))
+ continue;
}
if (keyseg->flag &
- (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK))
+ (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK))
{
- uchar *tmp=page;
- get_key_length(length,tmp);
- length+=(uint) (tmp-page);
+ uchar *tmp=page;
+ get_key_length(length,tmp);
+ length+=(uint) (tmp-page);
}
else
- length=keyseg->length;
+ length=keyseg->length;
}
memcpy((byte*) key,(byte*) page,(size_t) length);
key+=length;
@@ -963,7 +1165,7 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
/* key that is packed relatively to previous */
uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
- register uchar **page_pos, register uchar *key)
+ register uchar **page_pos, register uchar *key)
{
reg1 MI_KEYSEG *keyseg;
uchar *start_key,*page=*page_pos,*page_end,*from,*from_end;
@@ -978,16 +1180,16 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
if (length > keyinfo->maxlength)
{
DBUG_PRINT("error",("Found too long binary packed key: %d of %d at %lx",
- length, keyinfo->maxlength, *page_pos));
+ length, keyinfo->maxlength, *page_pos));
DBUG_DUMP("key",(char*) *page_pos,16);
my_errno=HA_ERR_CRASHED;
- return 0; /* Wrong key */
+ return 0; /* Wrong key */
}
from=key; from_end=key+length;
}
else
{
- from=page; from_end=page_end; /* Not packed key */
+ from=page; from_end=page_end; /* Not packed key */
}
/*
@@ -1001,7 +1203,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
{
if (from == from_end) { from=page; from_end=page_end; }
if (!(*key++ = *from++))
- continue; /* Null part */
+ continue; /* Null part */
}
if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK))
{
@@ -1009,10 +1211,10 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
if (from == from_end) { from=page; from_end=page_end; }
if ((length= (*key++ = *from++)) == 255)
{
- if (from == from_end) { from=page; from_end=page_end; }
- length= (uint) ((*key++ = *from++)) << 8;
- if (from == from_end) { from=page; from_end=page_end; }
- length+= (uint) ((*key++ = *from++));
+ if (from == from_end) { from=page; from_end=page_end; }
+ length= (uint) ((*key++ = *from++)) << 8;
+ if (from == from_end) { from=page; from_end=page_end; }
+ length+= (uint) ((*key++ = *from++));
}
}
else
@@ -1020,7 +1222,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
if ((tmp=(uint) (from_end-from)) <= length)
{
- key+=tmp; /* Use old key */
+ key+=tmp; /* Use old key */
length-=tmp;
from=page; from_end=page_end;
}
@@ -1031,7 +1233,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
length=keyseg->length+nod_flag;
if ((tmp=(uint) (from_end-from)) <= length)
{
- memcpy(key+tmp,page,length-tmp); /* Get last part of key */
+ memcpy(key+tmp,page,length-tmp); /* Get last part of key */
*page_pos= page+length-tmp;
}
else
@@ -1040,7 +1242,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
{
DBUG_PRINT("error",("Error when unpacking key"));
my_errno=HA_ERR_CRASHED;
- return 0; /* Error */
+ return 0; /* Error */
}
memcpy((byte*) key,(byte*) from,(size_t) length);
*page_pos= from+length;
@@ -1049,11 +1251,11 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
}
- /* Get key at position without knowledge of previous key */
- /* Returns pointer to next key */
+ /* Get key at position without knowledge of previous key */
+ /* Returns pointer to next key */
uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
- uchar *key, uchar *keypos, uint *return_key_length)
+ uchar *key, uchar *keypos, uint *return_key_length)
{
uint nod_flag;
DBUG_ENTER("_mi_get_key");
@@ -1067,14 +1269,14 @@ uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
else
{
page+=2+nod_flag;
- key[0]=0; /* safety */
+ key[0]=0; /* safety */
while (page <= keypos)
{
*return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key);
if (*return_key_length == 0)
{
- my_errno=HA_ERR_CRASHED;
- DBUG_RETURN(0);
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(0);
}
}
}
@@ -1083,12 +1285,12 @@ uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
} /* _mi_get_key */
- /* Get key at position without knowledge of previous key */
- /* Returns 0 if ok */
+ /* Get key at position without knowledge of previous key */
+ /* Returns 0 if ok */
static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
- uchar *key, uchar *keypos,
- uint *return_key_length)
+ uchar *key, uchar *keypos,
+ uint *return_key_length)
{
uint nod_flag;
DBUG_ENTER("_mi_get_prev_key");
@@ -1098,20 +1300,20 @@ static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
{
*return_key_length=keyinfo->keylength;
bmove((byte*) key,(byte*) keypos- *return_key_length-nod_flag,
- *return_key_length);
+ *return_key_length);
DBUG_RETURN(0);
}
else
{
page+=2+nod_flag;
- key[0]=0; /* safety */
+ key[0]=0; /* safety */
while (page < keypos)
{
*return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key);
if (*return_key_length == 0)
{
- my_errno=HA_ERR_CRASHED;
- DBUG_RETURN(1);
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(1);
}
}
}
@@ -1120,11 +1322,11 @@ static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
- /* Get last key from key-page */
- /* Return pointer to where key starts */
+ /* Get last key from key-page */
+ /* Return pointer to where key starts */
uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
- uchar *lastkey, uchar *endpos, uint *return_key_length)
+ uchar *lastkey, uchar *endpos, uint *return_key_length)
{
uint nod_flag;
uchar *lastpos;
@@ -1149,9 +1351,9 @@ uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
*return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,lastkey);
if (*return_key_length == 0)
{
- DBUG_PRINT("error",("Couldn't find last key: page: %lx",page));
- my_errno=HA_ERR_CRASHED;
- DBUG_RETURN(0);
+ DBUG_PRINT("error",("Couldn't find last key: page: %lx",page));
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(0);
}
}
}
@@ -1160,7 +1362,7 @@ uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
} /* _mi_get_last_key */
- /* Calculate length of key */
+ /* Calculate length of key */
uint _mi_keylength(MI_KEYDEF *keyinfo, register uchar *key)
{
@@ -1175,7 +1377,7 @@ uint _mi_keylength(MI_KEYDEF *keyinfo, register uchar *key)
{
if (keyseg->flag & HA_NULL_PART)
if (!*key++)
- continue;
+ continue;
if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH))
{
uint length;
@@ -1189,28 +1391,28 @@ uint _mi_keylength(MI_KEYDEF *keyinfo, register uchar *key)
} /* _mi_keylength */
- /* Move a key */
+ /* Move a key */
uchar *_mi_move_key(MI_KEYDEF *keyinfo, uchar *to, uchar *from)
{
reg1 uint length;
memcpy((byte*) to, (byte*) from,
- (size_t) (length=_mi_keylength(keyinfo,from)));
+ (size_t) (length=_mi_keylength(keyinfo,from)));
return to+length;
}
- /* Find next/previous record with same key */
- /* This can't be used when database is touched after last read */
+ /* Find next/previous record with same key */
+ /* This can't be used when database is touched after last read */
int _mi_search_next(register MI_INFO *info, register MI_KEYDEF *keyinfo,
- uchar *key, uint key_length, uint nextflag, my_off_t pos)
+ uchar *key, uint key_length, uint nextflag, my_off_t pos)
{
int error;
uint nod_flag;
uchar lastkey[MI_MAX_KEY_BUFF];
DBUG_ENTER("_mi_search_next");
DBUG_PRINT("enter",("nextflag: %d lastpos: %ld int_keypos: %lx",
- nextflag,(long) info->lastpos,info->int_keypos));
+ nextflag,(long) info->lastpos,info->int_keypos));
DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,keyinfo->seg,key,key_length););
/* Force full read if we are at last key or if we are not on a leaf
@@ -1225,12 +1427,12 @@ int _mi_search_next(register MI_INFO *info, register MI_KEYDEF *keyinfo,
(info->int_keytree_version != keyinfo->version &&
(info->int_nod_flag || info->buff_used)))
DBUG_RETURN(_mi_search(info,keyinfo,key,key_length,
- nextflag | SEARCH_SAVE_BUFF, pos));
+ nextflag | SEARCH_SAVE_BUFF, pos));
if (info->buff_used)
{
if (!_mi_fetch_keypage(info,keyinfo,info->last_search_keypage,
- info->buff,0))
+ info->buff,0))
DBUG_RETURN(-1);
info->buff_used=0;
}
@@ -1239,36 +1441,36 @@ int _mi_search_next(register MI_INFO *info, register MI_KEYDEF *keyinfo,
nod_flag=mi_test_if_nod(info->buff);
memcpy(lastkey,key,key_length);
- if (nextflag & SEARCH_BIGGER) /* Next key */
+ if (nextflag & SEARCH_BIGGER) /* Next key */
{
my_off_t tmp_pos=_mi_kpos(nod_flag,info->int_keypos);
if (tmp_pos != HA_OFFSET_ERROR)
{
if ((error=_mi_search(info,keyinfo,key,key_length,
- nextflag | SEARCH_SAVE_BUFF, tmp_pos)) <=0)
- DBUG_RETURN(error);
+ nextflag | SEARCH_SAVE_BUFF, tmp_pos)) <=0)
+ DBUG_RETURN(error);
}
if (!(info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,
- &info->int_keypos,lastkey)))
+ &info->int_keypos,lastkey)))
DBUG_RETURN(-1);
}
- else /* Previous key */
+ else /* Previous key */
{
uint length;
/* Find start of previous key */
info->int_keypos=_mi_get_last_key(info,keyinfo,info->buff,lastkey,
- info->int_keypos, &length);
+ info->int_keypos, &length);
if (!info->int_keypos)
DBUG_RETURN(-1);
if (info->int_keypos == info->buff+2)
DBUG_RETURN(_mi_search(info,keyinfo,key,key_length,
- nextflag | SEARCH_SAVE_BUFF, pos));
+ nextflag | SEARCH_SAVE_BUFF, pos));
if ((error=_mi_search(info,keyinfo,key,0,nextflag | SEARCH_SAVE_BUFF,
- _mi_kpos(nod_flag,info->int_keypos))) <= 0)
+ _mi_kpos(nod_flag,info->int_keypos))) <= 0)
DBUG_RETURN(error);
if (! _mi_get_last_key(info,keyinfo,info->buff,lastkey,
- info->int_keypos,&info->lastkey_length))
+ info->int_keypos,&info->lastkey_length))
DBUG_RETURN(-1);
}
memcpy(info->lastkey,lastkey,info->lastkey_length);
@@ -1278,11 +1480,11 @@ int _mi_search_next(register MI_INFO *info, register MI_KEYDEF *keyinfo,
} /* _mi_search_next */
- /* Search after position for the first row in an index */
- /* This is stored in info->lastpos */
+ /* Search after position for the first row in an index */
+ /* This is stored in info->lastpos */
int _mi_search_first(register MI_INFO *info, register MI_KEYDEF *keyinfo,
- register my_off_t pos)
+ register my_off_t pos)
{
uint nod_flag;
uchar *page;
@@ -1307,7 +1509,7 @@ int _mi_search_first(register MI_INFO *info, register MI_KEYDEF *keyinfo,
} while ((pos=_mi_kpos(nod_flag,page)) != HA_OFFSET_ERROR);
info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,
- info->lastkey);
+ info->lastkey);
info->int_keypos=page; info->int_maxpos=info->buff+mi_getint(info->buff)-1;
info->int_nod_flag=nod_flag;
info->int_keytree_version=keyinfo->version;
@@ -1320,11 +1522,11 @@ int _mi_search_first(register MI_INFO *info, register MI_KEYDEF *keyinfo,
} /* _mi_search_first */
- /* Search after position for the last row in an index */
- /* This is stored in info->lastpos */
+ /* Search after position for the last row in an index */
+ /* This is stored in info->lastpos */
int _mi_search_last(register MI_INFO *info, register MI_KEYDEF *keyinfo,
- register my_off_t pos)
+ register my_off_t pos)
{
uint nod_flag;
uchar *buff,*page;
@@ -1332,7 +1534,7 @@ int _mi_search_last(register MI_INFO *info, register MI_KEYDEF *keyinfo,
if (pos == HA_OFFSET_ERROR)
{
- my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
+ my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
info->lastpos= HA_OFFSET_ERROR;
DBUG_RETURN(-1);
}
@@ -1350,7 +1552,7 @@ int _mi_search_last(register MI_INFO *info, register MI_KEYDEF *keyinfo,
} while ((pos=_mi_kpos(nod_flag,page)) != HA_OFFSET_ERROR);
if (!_mi_get_last_key(info,keyinfo,buff,info->lastkey,page,
- &info->lastkey_length))
+ &info->lastkey_length))
DBUG_RETURN(-1);
info->lastpos=_mi_dpos(info,0,info->lastkey+info->lastkey_length);
info->int_keypos=info->int_maxpos=page;
@@ -1370,22 +1572,22 @@ int _mi_search_last(register MI_INFO *info, register MI_KEYDEF *keyinfo,
** Functions to store and pack a key in a page
**
** mi_calc_xx_key_length takes the following arguments:
-** nod_flag If nod: Length of nod-pointer
-** next_key Position to pos after the new key in buffer
-** org_key Key that was before the next key in buffer
-** prev_key Last key before current key
-** key Key that will be stored
-** s_temp Information how next key will be packed
+** nod_flag If nod: Length of nod-pointer
+** next_key Position to pos after the new key in buffer
+** org_key Key that was before the next key in buffer
+** prev_key Last key before current key
+** key Key that will be stored
+** s_temp Information how next key will be packed
****************************************************************************/
/* Static length key */
int
_mi_calc_static_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
- uchar *next_pos __attribute__((unused)),
- uchar *org_key __attribute__((unused)),
- uchar *prev_key __attribute__((unused)),
- uchar *key, MI_KEY_PARAM *s_temp)
+ uchar *next_pos __attribute__((unused)),
+ uchar *org_key __attribute__((unused)),
+ uchar *prev_key __attribute__((unused)),
+ uchar *key, MI_KEY_PARAM *s_temp)
{
s_temp->key=key;
return (int) (s_temp->totlength=keyinfo->keylength+nod_flag);
@@ -1395,10 +1597,10 @@ _mi_calc_static_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
int
_mi_calc_var_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
- uchar *next_pos __attribute__((unused)),
- uchar *org_key __attribute__((unused)),
- uchar *prev_key __attribute__((unused)),
- uchar *key, MI_KEY_PARAM *s_temp)
+ uchar *next_pos __attribute__((unused)),
+ uchar *org_key __attribute__((unused)),
+ uchar *prev_key __attribute__((unused)),
+ uchar *key, MI_KEY_PARAM *s_temp)
{
s_temp->key=key;
return (int) (s_temp->totlength=_mi_keylength(keyinfo,key)+nod_flag);
@@ -1413,10 +1615,10 @@ _mi_calc_var_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
If the max length of first key segment <= 127 characters the prefix is
1 byte else it's 2 byte
- prefix byte The high bit is set if this is a prefix for the prev key
- length Packed length if the previous was a prefix byte
- [length] Length character of data
- next-key-seg Next key segments
+ prefix byte The high bit is set if this is a prefix for the prev key
+ length Packed length if the previous was a prefix byte
+ [length] Length character of data
+ next-key-seg Next key segments
If the first segment can have NULL:
The length is 0 for NULLS and 1+length for not null columns.
@@ -1425,8 +1627,8 @@ _mi_calc_var_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
int
_mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
- uchar *org_key, uchar *prev_key, uchar *key,
- MI_KEY_PARAM *s_temp)
+ uchar *org_key, uchar *prev_key, uchar *key,
+ MI_KEY_PARAM *s_temp)
{
reg1 MI_KEYSEG *keyseg;
int length;
@@ -1467,15 +1669,15 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
s_temp->key=key;
s_temp->ref_length=s_temp->key_length=0;
s_temp->totlength=key_length-1+diff_flag;
- s_temp->next_key_pos=0; /* No next key */
+ s_temp->next_key_pos=0; /* No next key */
return (s_temp->totlength);
}
s_temp->store_not_null=1;
- key_length--; /* We don't store NULL */
+ key_length--; /* We don't store NULL */
if (prev_key && !*prev_key++)
- org_key=prev_key=0; /* Can't pack against prev */
+ org_key=prev_key=0; /* Can't pack against prev */
else if (org_key)
- org_key++; /* Skipp NULL */
+ org_key++; /* Skipp NULL */
}
else
s_temp->store_not_null=0;
@@ -1491,14 +1693,14 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
if (prev_key)
{
get_key_length(org_key_length,prev_key);
- s_temp->prev_key=prev_key; /* Pointer at data */
+ s_temp->prev_key=prev_key; /* Pointer at data */
/* Don't use key-pack if length == 0 */
if (new_key_length && new_key_length == org_key_length)
same_length=1;
else if (new_key_length > org_key_length)
end=key + org_key_length;
- if (sort_order) /* SerG */
+ if (sort_order) /* SerG */
{
while (key < end && sort_order[*key] == sort_order[*prev_key])
{
@@ -1509,7 +1711,7 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
{
while (key < end && *key == *prev_key)
{
- key++; prev_key++;
+ key++; prev_key++;
}
}
}
@@ -1524,15 +1726,15 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
length=(int) key_length-(int) (key_end-start)-length_pack;
length+= diff_flag;
if (next_key)
- { /* Can't combine with next */
- s_temp->n_length= *next_key; /* Needed by _mi_store_key */
+ { /* Can't combine with next */
+ s_temp->n_length= *next_key; /* Needed by _mi_store_key */
next_key=0;
}
}
else
{
if (start != key)
- { /* Starts as prev key */
+ { /* Starts as prev key */
ref_length= (uint) (key-start);
s_temp->ref_length= ref_length + pack_marker;
length= (int) (key_length - ref_length);
@@ -1543,16 +1745,16 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
}
else
{
- s_temp->key_length+=s_temp->store_not_null; /* If null */
+ s_temp->key_length+=s_temp->store_not_null; /* If null */
length= key_length - length_pack+ diff_flag;
}
}
s_temp->totlength=(uint) length;
s_temp->prev_length=0;
DBUG_PRINT("test",("tot_length: %d length: %d uniq_key_length: %d",
- key_length,length,s_temp->key_length));
+ key_length,length,s_temp->key_length));
- /* If something after that hasn't length=0, test if we can combine */
+ /* If something after that hasn't length=0, test if we can combine */
if ((s_temp->next_key_pos=next_key))
{
uint packed,n_length;
@@ -1568,134 +1770,134 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
if (!packed)
n_length-= s_temp->store_not_null;
- if (n_length || packed) /* Don't pack 0 length keys */
+ if (n_length || packed) /* Don't pack 0 length keys */
{
uint next_length_pack, new_ref_length=s_temp->ref_length;
if (packed)
{
- /* If first key and next key is packed (only on delete) */
- if (!prev_key && org_key)
- {
- get_key_length(org_key_length,org_key);
- key=start;
- if (sort_order) /* SerG */
- {
- while (key < end && sort_order[*key] == sort_order[*org_key])
- {
- key++; org_key++;
- }
- }
- else
- {
- while (key < end && *key == *org_key)
- {
- key++; org_key++;
- }
- }
- if ((new_ref_length= (uint) (key - start)))
- new_ref_length+=pack_marker;
- }
-
- if (!n_length)
- {
- /*
- We put a different key between two identical variable length keys
- Extend next key to have same prefix as this key
- */
- if (new_ref_length) /* prefix of previus key */
- { /* make next key longer */
- s_temp->part_of_prev_key= new_ref_length;
- s_temp->prev_length= org_key_length -
- (new_ref_length-pack_marker);
- s_temp->n_ref_length= s_temp->n_length= s_temp->prev_length;
- n_length= get_pack_length(s_temp->prev_length);
- s_temp->prev_key+= (new_ref_length - pack_marker);
- length+= s_temp->prev_length + n_length;
- }
- else
- { /* Can't use prev key */
- s_temp->part_of_prev_key=0;
- s_temp->prev_length= org_key_length;
- s_temp->n_ref_length=s_temp->n_length= org_key_length;
- length+= org_key_length;
- /* +get_pack_length(org_key_length); */
- }
- return (int) length;
- }
-
- ref_length=n_length;
- get_key_pack_length(n_length,next_length_pack,next_key);
-
- /* Test if new keys has fewer characters that match the previous key */
- if (!new_ref_length)
- { /* Can't use prev key */
- s_temp->part_of_prev_key= 0;
- s_temp->prev_length= ref_length;
- s_temp->n_ref_length= s_temp->n_length= n_length+ref_length;
- /* s_temp->prev_key+= get_pack_length(org_key_length); */
- return (int) length+ref_length-next_length_pack;
- }
- if (ref_length+pack_marker > new_ref_length)
- {
- uint new_pack_length=new_ref_length-pack_marker;
- /* We must copy characters from the original key to the next key */
- s_temp->part_of_prev_key= new_ref_length;
- s_temp->prev_length= ref_length - new_pack_length;
- s_temp->n_ref_length=s_temp->n_length=n_length + s_temp->prev_length;
- s_temp->prev_key+= new_pack_length;
-/* +get_pack_length(org_key_length); */
- length= length-get_pack_length(ref_length)+
- get_pack_length(new_pack_length);
- return (int) length + s_temp->prev_length;
- }
+ /* If first key and next key is packed (only on delete) */
+ if (!prev_key && org_key)
+ {
+ get_key_length(org_key_length,org_key);
+ key=start;
+ if (sort_order) /* SerG */
+ {
+ while (key < end && sort_order[*key] == sort_order[*org_key])
+ {
+ key++; org_key++;
+ }
+ }
+ else
+ {
+ while (key < end && *key == *org_key)
+ {
+ key++; org_key++;
+ }
+ }
+ if ((new_ref_length= (uint) (key - start)))
+ new_ref_length+=pack_marker;
+ }
+
+ if (!n_length)
+ {
+ /*
+ We put a different key between two identical variable length keys
+ Extend next key to have same prefix as this key
+ */
+ if (new_ref_length) /* prefix of previus key */
+ { /* make next key longer */
+ s_temp->part_of_prev_key= new_ref_length;
+ s_temp->prev_length= org_key_length -
+ (new_ref_length-pack_marker);
+ s_temp->n_ref_length= s_temp->n_length= s_temp->prev_length;
+ n_length= get_pack_length(s_temp->prev_length);
+ s_temp->prev_key+= (new_ref_length - pack_marker);
+ length+= s_temp->prev_length + n_length;
+ }
+ else
+ { /* Can't use prev key */
+ s_temp->part_of_prev_key=0;
+ s_temp->prev_length= org_key_length;
+ s_temp->n_ref_length=s_temp->n_length= org_key_length;
+ length+= org_key_length;
+ /* +get_pack_length(org_key_length); */
+ }
+ return (int) length;
+ }
+
+ ref_length=n_length;
+ get_key_pack_length(n_length,next_length_pack,next_key);
+
+ /* Test if new keys has fewer characters that match the previous key */
+ if (!new_ref_length)
+ { /* Can't use prev key */
+ s_temp->part_of_prev_key= 0;
+ s_temp->prev_length= ref_length;
+ s_temp->n_ref_length= s_temp->n_length= n_length+ref_length;
+ /* s_temp->prev_key+= get_pack_length(org_key_length); */
+ return (int) length+ref_length-next_length_pack;
+ }
+ if (ref_length+pack_marker > new_ref_length)
+ {
+ uint new_pack_length=new_ref_length-pack_marker;
+ /* We must copy characters from the original key to the next key */
+ s_temp->part_of_prev_key= new_ref_length;
+ s_temp->prev_length= ref_length - new_pack_length;
+ s_temp->n_ref_length=s_temp->n_length=n_length + s_temp->prev_length;
+ s_temp->prev_key+= new_pack_length;
+/* +get_pack_length(org_key_length); */
+ length= length-get_pack_length(ref_length)+
+ get_pack_length(new_pack_length);
+ return (int) length + s_temp->prev_length;
+ }
}
else
{
- /* Next key wasn't a prefix of previous key */
- ref_length=0;
- next_length_pack=0;
+ /* Next key wasn't a prefix of previous key */
+ ref_length=0;
+ next_length_pack=0;
}
DBUG_PRINT("test",("length: %d next_key: %lx",length,next_key));
{
- uint tmp_length;
- key=(start+=ref_length);
- if (key+n_length < key_end) /* Normalize length based */
- key_end=key+n_length;
- if (sort_order) /* SerG */
- {
+ uint tmp_length;
+ key=(start+=ref_length);
+ if (key+n_length < key_end) /* Normalize length based */
+ key_end=key+n_length;
+ if (sort_order) /* SerG */
+ {
while (key < key_end && sort_order[*key] ==
- sort_order[*next_key])
- {
- key++; next_key++;
- }
- }
- else
- {
- while (key < key_end && *key == *next_key)
- {
- key++; next_key++;
- }
- }
- if (!(tmp_length=(uint) (key-start)))
- { /* Key can't be re-packed */
- s_temp->next_key_pos=0;
- return length;
- }
- ref_length+=tmp_length;
- n_length-=tmp_length;
- length-=tmp_length+next_length_pack; /* We gained these chars */
+ sort_order[*next_key])
+ {
+ key++; next_key++;
+ }
+ }
+ else
+ {
+ while (key < key_end && *key == *next_key)
+ {
+ key++; next_key++;
+ }
+ }
+ if (!(tmp_length=(uint) (key-start)))
+ { /* Key can't be re-packed */
+ s_temp->next_key_pos=0;
+ return length;
+ }
+ ref_length+=tmp_length;
+ n_length-=tmp_length;
+ length-=tmp_length+next_length_pack; /* We gained these chars */
}
if (n_length == 0)
{
- s_temp->n_ref_length=pack_marker; /* Same as prev key */
+ s_temp->n_ref_length=pack_marker; /* Same as prev key */
}
else
{
- s_temp->n_ref_length=ref_length | pack_marker;
- length+= get_pack_length(n_length);
- s_temp->n_length=n_length;
+ s_temp->n_ref_length=ref_length | pack_marker;
+ length+= get_pack_length(n_length);
+ s_temp->n_length=n_length;
}
}
}
@@ -1707,15 +1909,15 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
int
_mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
- uchar *org_key, uchar *prev_key, uchar *key,
- MI_KEY_PARAM *s_temp)
+ uchar *org_key, uchar *prev_key, uchar *key,
+ MI_KEY_PARAM *s_temp)
{
uint length,key_length,ref_length;
s_temp->totlength=key_length=_mi_keylength(keyinfo,key)+nod_flag;
s_temp->key=key;
s_temp->prev_key=org_key;
- if (prev_key) /* If not first key in block */
+ if (prev_key) /* If not first key in block */
{
/* pack key against previous key */
/*
@@ -1734,7 +1936,7 @@ _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
s_temp->ref_length=ref_length=0;
length=key_length+1;
}
- if ((s_temp->next_key_pos=next_key)) /* If another key after */
+ if ((s_temp->next_key_pos=next_key)) /* If another key after */
{
/* pack key against next key */
uint next_length,next_length_pack;
@@ -1745,21 +1947,21 @@ _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
{
uchar *end;
for (key= s_temp->key, end=key+next_length ;
- *key == *org_key && key < end;
- key++,org_key++) ;
+ *key == *org_key && key < end;
+ key++,org_key++) ;
ref_length= (uint) (key - s_temp->key);
}
if (next_length > ref_length)
{
/* We put a key with different case between two keys with the same prefix
- Extend next key to have same prefix as
- this key */
+ Extend next key to have same prefix as
+ this key */
s_temp->n_ref_length= ref_length;
s_temp->prev_length= next_length-ref_length;
s_temp->prev_key+= ref_length;
return (int) (length+ s_temp->prev_length - next_length_pack +
- get_pack_length(ref_length));
+ get_pack_length(ref_length));
}
/* Check how many characters are identical to next key */
key= s_temp->key+next_length;
@@ -1767,12 +1969,12 @@ _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
if ((ref_length= (uint) (key - s_temp->key)-1) == next_length)
{
s_temp->next_key_pos=0;
- return length; /* can't pack next key */
+ return length; /* can't pack next key */
}
s_temp->prev_length=0;
s_temp->n_ref_length=ref_length;
return (int) (length-(ref_length - next_length) - next_length_pack +
- get_pack_length(ref_length));
+ get_pack_length(ref_length));
}
return (int) length;
}
@@ -1785,8 +1987,8 @@ _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
/* store key without compression */
void _mi_store_static_key(MI_KEYDEF *keyinfo __attribute__((unused)),
- register uchar *key_pos,
- register MI_KEY_PARAM *s_temp)
+ register uchar *key_pos,
+ register MI_KEY_PARAM *s_temp)
{
memcpy((byte*) key_pos,(byte*) s_temp->key,(size_t) s_temp->totlength);
}
@@ -1800,8 +2002,8 @@ void _mi_store_static_key(MI_KEYDEF *keyinfo __attribute__((unused)),
void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)),
- register uchar *key_pos,
- register MI_KEY_PARAM *s_temp)
+ register uchar *key_pos,
+ register MI_KEY_PARAM *s_temp)
{
uint length;
uchar *start;
@@ -1822,9 +2024,9 @@ void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)),
store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->key_length);
}
bmove((byte*) key_pos,(byte*) s_temp->key,
- (length=s_temp->totlength-(uint) (key_pos-start)));
+ (length=s_temp->totlength-(uint) (key_pos-start)));
- if (!s_temp->next_key_pos) /* No following key */
+ if (!s_temp->next_key_pos) /* No following key */
return;
key_pos+=length;
@@ -1834,14 +2036,14 @@ void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)),
if (s_temp->part_of_prev_key)
{
store_pack_length(s_temp->pack_marker == 128,key_pos,
- s_temp->part_of_prev_key);
+ s_temp->part_of_prev_key);
store_key_length_inc(key_pos,s_temp->n_length);
}
else
{
s_temp->n_length+= s_temp->store_not_null;
store_pack_length(s_temp->pack_marker == 128,key_pos,
- s_temp->n_length);
+ s_temp->n_length);
}
memcpy(key_pos, s_temp->prev_key, s_temp->prev_length);
}
@@ -1849,7 +2051,7 @@ void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)),
{
store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->n_ref_length);
if (s_temp->n_ref_length == s_temp->pack_marker)
- return; /* Identical key */
+ return; /* Identical key */
store_key_length(key_pos,s_temp->n_length);
}
else
@@ -1863,18 +2065,18 @@ void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)),
/* variable length key with prefix compression */
void _mi_store_bin_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)),
- register uchar *key_pos,
- register MI_KEY_PARAM *s_temp)
+ register uchar *key_pos,
+ register MI_KEY_PARAM *s_temp)
{
store_key_length_inc(key_pos,s_temp->ref_length);
memcpy((char*) key_pos,(char*) s_temp->key+s_temp->ref_length,
- (size_t) s_temp->totlength-s_temp->ref_length);
+ (size_t) s_temp->totlength-s_temp->ref_length);
if (s_temp->next_key_pos)
{
key_pos+=(uint) (s_temp->totlength-s_temp->ref_length);
store_key_length_inc(key_pos,s_temp->n_ref_length);
- if (s_temp->prev_length) /* If we must extend key */
+ if (s_temp->prev_length) /* If we must extend key */
{
memcpy(key_pos,s_temp->prev_key,s_temp->prev_length);
}
diff --git a/myisam/mi_update.c b/myisam/mi_update.c
index 185624f3878..ac843dbb6bd 100644
--- a/myisam/mi_update.c
+++ b/myisam/mi_update.c
@@ -98,9 +98,7 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec)
if ((int) i == info->lastinx)
key_changed|=HA_STATE_WRITTEN;
changed|=((ulonglong) 1 << i);
- if (_mi_ft_del(info,i,(char*) old_key,oldrec,pos))
- goto err;
- if (_mi_ft_add(info,i,(char*) new_key,newrec,pos))
+ if (_mi_ft_update(info,i,(char*) old_key,oldrec,newrec,pos))
goto err;
}
}
diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h
index 33fd1b6946f..d309bbc9c8e 100644
--- a/myisam/myisamdef.h
+++ b/myisam/myisamdef.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
+
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 */
@@ -37,7 +37,7 @@ typedef struct st_mi_status_info
my_off_t key_empty; /* lost space in indexfile */
my_off_t key_file_length;
my_off_t data_file_length;
-} MI_STATUS_INFO;
+} MI_STATUS_INFO;
typedef struct st_mi_state_info
{
@@ -285,7 +285,7 @@ struct st_myisam_info {
#define STATE_CHANGED 1
#define STATE_CRASHED 2
-#define STATE_CRASHED_ON_REPAIR 4
+#define STATE_CRASHED_ON_REPAIR 4
#define STATE_NOT_ANALYZED 8
#define STATE_NOT_OPTIMIZED_KEYS 16
#define STATE_NOT_SORTED_PAGES 32
@@ -473,6 +473,9 @@ extern int _mi_bin_search(struct st_myisam_info *info,MI_KEYDEF *keyinfo,
extern int _mi_seq_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *page,
uchar *key,uint key_len,uint comp_flag,
uchar **ret_pos,uchar *buff, my_bool *was_last_key);
+extern int _mi_prefix_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *page,
+ uchar *key,uint key_len,uint comp_flag,
+ uchar **ret_pos,uchar *buff, my_bool *was_last_key);
extern int _mi_compare_text(CHARSET_INFO *, uchar *, uint, uchar *, uint ,
my_bool);
extern my_off_t _mi_kpos(uint nod_flag,uchar *after_key);
@@ -640,6 +643,7 @@ int mi_open_keyfile(MYISAM_SHARE *share);
void mi_check_print_error _VARARGS((MI_CHECK *param, const char *fmt,...));
void mi_check_print_warning _VARARGS((MI_CHECK *param, const char *fmt,...));
void mi_check_print_info _VARARGS((MI_CHECK *param, const char *fmt,...));
+int flush_pending_blocks(MI_CHECK *param);
#ifdef __cplusplus
}
diff --git a/myisam/sort.c b/myisam/sort.c
index e6c7d61e39a..9f16ac35c9b 100644
--- a/myisam/sort.c
+++ b/myisam/sort.c
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
+
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 */
@@ -19,7 +19,7 @@
them in sorted order through SORT_INFO functions.
*/
-#include "myisamdef.h"
+#include "fulltext.h"
#if defined(MSDOS) || defined(__WIN__)
#include <fcntl.h>
#else
@@ -49,10 +49,12 @@ extern void print_error _VARARGS((const char *fmt,...));
static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info,uint keys,
uchar **sort_keys,
- BUFFPEK *buffpek,int *maxbuffer,
- IO_CACHE *tempfile);
+ DYNAMIC_ARRAY *buffpek,int *maxbuffer,
+ IO_CACHE *tempfile,
+ IO_CACHE *tempfile_for_exceptions);
static int NEAR_F write_keys(MI_SORT_PARAM *info,uchar * *sort_keys,
uint count, BUFFPEK *buffpek,IO_CACHE *tempfile);
+static int NEAR_F write_key(MI_SORT_PARAM *info, uchar *key, IO_CACHE *tempfile);
static int NEAR_F write_index(MI_SORT_PARAM *info,uchar * *sort_keys,
uint count);
static int NEAR_F merge_many_buff(MI_SORT_PARAM *info,uint keys,
@@ -67,7 +69,6 @@ static int NEAR_F merge_buffers(MI_SORT_PARAM *info,uint keys,
BUFFPEK *Fb, BUFFPEK *Tb);
static int NEAR_F merge_index(MI_SORT_PARAM *,uint,uchar **,BUFFPEK *, int,
IO_CACHE *);
-static char **make_char_array(uint fields,uint length,myf my_flag);
/* Creates a index of sorted keys */
/* Returns 0 if everything went ok */
@@ -77,15 +78,17 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
{
int error,maxbuffer,skr;
uint memavl,old_memavl,keys,sort_length;
- BUFFPEK *buffpek;
+ DYNAMIC_ARRAY buffpek;
ha_rows records;
uchar **sort_keys;
- IO_CACHE tempfile;
+ IO_CACHE tempfile, tempfile_for_exceptions;
DBUG_ENTER("_create_index_by_sort");
DBUG_PRINT("enter",("sort_length: %d", info->key_length));
my_b_clear(&tempfile);
- buffpek= (BUFFPEK *) NULL; sort_keys= (uchar **) NULL; error= 1;
+ my_b_clear(&tempfile_for_exceptions);
+ bzero((char*) &buffpek,sizeof(buffpek));
+ sort_keys= (uchar **) NULL; error= 1;
maxbuffer=1;
memavl=max(sortbuff_size,MIN_SORT_MEMORY);
@@ -113,14 +116,12 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
}
while ((maxbuffer= (int) (records/(keys-1)+1)) != skr);
- if ((sort_keys= (uchar **) make_char_array(keys,sort_length,MYF(0))))
+ if (sort_keys=(uchar **)my_malloc(keys*(sort_length+sizeof(char*))+HA_FT_MAXLEN, MYF(0)))
{
- if ((buffpek = (BUFFPEK*) my_malloc((uint) (sizeof(BUFFPEK)*
- (uint) maxbuffer),
- MYF(0))))
- break;
- else
+ if (init_dynamic_array(&buffpek, sizeof(BUFFPEK), maxbuffer, maxbuffer/2))
my_free((gptr) sort_keys,MYF(0));
+ else
+ break;
}
old_memavl=memavl;
if ((memavl=memavl/4*3) < MIN_SORT_MEMORY && old_memavl > MIN_SORT_MEMORY)
@@ -136,7 +137,8 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
if (!no_messages)
printf(" - Searching for keys, allocating buffer for %d keys\n",keys);
- if ((records=find_all_keys(info,keys,sort_keys,buffpek,&maxbuffer,&tempfile))
+ if ((records=find_all_keys(info,keys,sort_keys,&buffpek,&maxbuffer,
+ &tempfile,&tempfile_for_exceptions))
== HA_POS_ERROR)
goto err; /* purecov: tested */
if (maxbuffer == 0)
@@ -153,7 +155,8 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
{
if (!no_messages)
printf(" - Merging %lu keys\n",records); /* purecov: tested */
- if (merge_many_buff(info,keys,sort_keys,buffpek,&maxbuffer,&tempfile))
+ if (merge_many_buff(info,keys,sort_keys,
+ dynamic_element(&buffpek,0,BUFFPEK *),&maxbuffer,&tempfile))
goto err; /* purecov: inspected */
}
if (flush_io_cache(&tempfile) ||
@@ -161,17 +164,39 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
goto err; /* purecov: inspected */
if (!no_messages)
puts(" - Last merge and dumping keys"); /* purecov: tested */
- if (merge_index(info,keys,sort_keys,buffpek,maxbuffer,&tempfile))
+ if (merge_index(info,keys,sort_keys,dynamic_element(&buffpek,0,BUFFPEK *),
+ maxbuffer,&tempfile))
goto err; /* purecov: inspected */
}
+
+ if (flush_pending_blocks(info->sort_info->param))
+ goto err;
+
+ if (my_b_inited(&tempfile_for_exceptions))
+ {
+ MI_INFO *index=info->sort_info->info;
+ uint keyno=info->sort_info->key;
+ uint key_length, ref_length=index->s->rec_reflength;
+
+ if (flush_io_cache(&tempfile_for_exceptions) ||
+ reinit_io_cache(&tempfile_for_exceptions,READ_CACHE,0L,0,0))
+ goto err;
+
+ while (!my_b_read(&tempfile_for_exceptions,(byte*)&key_length, sizeof(key_length))
+ && !my_b_read(&tempfile_for_exceptions,(byte*)sort_keys,(uint)key_length))
+ {
+ if (_mi_ck_write(index,keyno,(byte*)sort_keys,key_length-ref_length)) goto err;
+ }
+ }
+
error =0;
err:
if (sort_keys)
my_free((gptr) sort_keys,MYF(0));
- if (buffpek)
- my_free((gptr) buffpek,MYF(0));
+ delete_dynamic(&buffpek);
close_cached_file(&tempfile);
+ close_cached_file(&tempfile_for_exceptions);
DBUG_RETURN(error ? -1 : 0);
} /* _create_index_by_sort */
@@ -180,36 +205,50 @@ err:
/* Search after all keys and place them in a temp. file */
static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info, uint keys,
- uchar **sort_keys, BUFFPEK *buffpek,
- int *maxbuffer, IO_CACHE *tempfile)
+ uchar **sort_keys, DYNAMIC_ARRAY *buffpek,
+ int *maxbuffer, IO_CACHE *tempfile,
+ IO_CACHE *tempfile_for_exceptions)
{
int error;
- uint idx,indexpos;
+ uint idx;
DBUG_ENTER("find_all_keys");
- idx=indexpos=error=0;
+ idx=error=0;
+ sort_keys[0]=(char*)(sort_keys+keys);
- while (!(error=(*info->key_read)(info->sort_info,sort_keys[idx])))
+ while(!(error=(*info->key_read)(info->sort_info,sort_keys[idx])))
{
- if ((uint) ++idx == keys)
+ if (info->sort_info->real_key_length > info->key_length)
{
- if (indexpos >= (uint) *maxbuffer ||
- write_keys(info,sort_keys,idx-1,buffpek+indexpos,tempfile))
- DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
+ if (write_key(info,sort_keys[idx],tempfile_for_exceptions))
+ DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
+ continue;
+ }
+
+ if (++idx == keys)
+ {
+ if (write_keys(info,sort_keys,idx-1,(BUFFPEK *)alloc_dynamic(buffpek),tempfile))
+ DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
+
+ sort_keys[0]=(char*)(sort_keys+keys);
memcpy(sort_keys[0],sort_keys[idx-1],(size_t) info->key_length);
- idx=1; indexpos++;
+ idx=1;
}
+ sort_keys[idx]=sort_keys[idx-1]+info->key_length;
}
if (error > 0)
DBUG_RETURN(HA_POS_ERROR); /* Aborted by get_key */ /* purecov: inspected */
- if (indexpos)
- if (indexpos >= (uint) *maxbuffer ||
- write_keys(info,sort_keys,idx,buffpek+indexpos,tempfile))
+ if (buffpek->elements)
+ {
+ if (write_keys(info,sort_keys,idx,(BUFFPEK *)alloc_dynamic(buffpek),tempfile))
DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
- *maxbuffer=(int) indexpos;
- DBUG_RETURN(indexpos*(keys-1)+idx);
-} /* find_all_keys */
+ *maxbuffer=buffpek->elements-1;
+ }
+ else
+ *maxbuffer=0;
+ DBUG_RETURN((*maxbuffer)*(keys-1)+idx);
+} /* find_all_keys */
/* Write all keys in memory to file for later merge */
@@ -222,11 +261,12 @@ static int NEAR_F write_keys(MI_SORT_PARAM *info, register uchar **sort_keys,
DBUG_ENTER("write_keys");
qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp,
- info->sort_info);
+ info->sort_info);
if (!my_b_inited(tempfile) &&
open_cached_file(tempfile, info->tmpdir, "ST", DISK_BUFFER_SIZE,
info->myf_rw))
DBUG_RETURN(1); /* purecov: inspected */
+
buffpek->file_pos=my_b_tell(tempfile);
buffpek->count=count;
@@ -237,6 +277,22 @@ static int NEAR_F write_keys(MI_SORT_PARAM *info, register uchar **sort_keys,
} /* write_keys */
+static int NEAR_F write_key(MI_SORT_PARAM *info, uchar *key, IO_CACHE *tempfile)
+{
+ uint key_length=info->sort_info->real_key_length;
+ DBUG_ENTER("write_key");
+
+ if (!my_b_inited(tempfile) &&
+ open_cached_file(tempfile, info->tmpdir, "ST", DISK_BUFFER_SIZE,
+ info->myf_rw))
+ DBUG_RETURN(1);
+
+ if (my_b_write(tempfile,(byte*)&key_length,sizeof(key_length)) ||
+ my_b_write(tempfile,(byte*)key,(uint) key_length))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+} /* write_key */
+
/* Write index */
static int NEAR_F write_index(MI_SORT_PARAM *info, register uchar **sort_keys,
@@ -326,7 +382,7 @@ static uint NEAR_F read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
/* If to_file == 0 then use info->key_write */
static int NEAR_F
-merge_buffers(MI_SORT_PARAM *info, uint keys, IO_CACHE *from_file,
+merge_buffers(MI_SORT_PARAM *info, uint keys, IO_CACHE *from_file,
IO_CACHE *to_file, uchar **sort_keys, BUFFPEK *lastbuff,
BUFFPEK *Fb, BUFFPEK *Tb)
{
@@ -472,21 +528,3 @@ merge_index(MI_SORT_PARAM *info, uint keys, uchar **sort_keys,
DBUG_RETURN(0);
} /* merge_index */
-
- /* Make a pointer of arrays to keys */
-
-static char **make_char_array(register uint fields, uint length, myf my_flag)
-{
- register char **pos;
- char **old_pos,*char_pos;
- DBUG_ENTER("make_char_array");
-
- if ((old_pos= (char**) my_malloc( fields*(length+sizeof(char*)), my_flag)))
- {
- pos=old_pos; char_pos=((char*) (pos+fields)) -length;
- while (fields--)
- *(pos++) = (char_pos+= length);
- }
-
- DBUG_RETURN(old_pos);
-} /* make_char_array */
diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh
index 5bb005b60de..8c494d06f75 100644
--- a/mysql-test/mysql-test-run.sh
+++ b/mysql-test/mysql-test-run.sh
@@ -112,6 +112,12 @@ while test $# -gt 0; do
--tmpdir=*) MYSQL_TMP_DIR=`$ECHO "$1" | $SED -e "s;--tmpdir=;;"` ;;
--master_port=*) MASTER_MYPORT=`$ECHO "$1" | $SED -e "s;--master_port=;;"` ;;
--slave_port=*) SLAVE_MYPORT=`$ECHO "$1" | $SED -e "s;--slave_port=;;"` ;;
+ --skip-innobase)
+ EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-innobase"
+ EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-innobase" ;;
+ --skip-bdb)
+ EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-bdb"
+ EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-bdb" ;;
--skip-rpl) NO_SLAVE=1 ;;
--record)
RECORD=1;
diff --git a/mysql-test/r/fulltext_distinct.result b/mysql-test/r/fulltext_distinct.result
new file mode 100644
index 00000000000..9729eb59c10
--- /dev/null
+++ b/mysql-test/r/fulltext_distinct.result
@@ -0,0 +1,10 @@
+id tag value
+1 foo123 bar111
+2 foo123 bar222
+3 bar345 baz333 ar
+id_t2 id_t1 field_number
+12346 3 1
+2231626 64280 0
+2231626 64281 0
+id_t2
+12346
diff --git a/mysql-test/t/fulltext_distinct.test b/mysql-test/t/fulltext_distinct.test
new file mode 100644
index 00000000000..4bd88dde496
--- /dev/null
+++ b/mysql-test/t/fulltext_distinct.test
@@ -0,0 +1,39 @@
+#
+# Test of fulltext index
+# bug reported by Tibor Simko <tibor.simko@cern.ch>
+#
+
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (
+ id mediumint unsigned NOT NULL auto_increment,
+ tag char(6) NOT NULL default '',
+ value text NOT NULL default '',
+ PRIMARY KEY (id),
+ KEY kt(tag),
+ KEY kv(value(15)),
+ FULLTEXT KEY kvf(value)
+ ) TYPE=MyISAM;
+ DROP TABLE IF EXISTS t2;
+ CREATE TABLE t2 (
+ id_t2 mediumint unsigned NOT NULL default '0',
+ id_t1 mediumint unsigned NOT NULL default '0',
+ field_number tinyint unsigned NOT NULL default '0',
+ PRIMARY KEY (id_t2,id_t1,field_number),
+ KEY id_t1(id_t1)
+ ) TYPE=MyISAM;
+
+ INSERT INTO t1 (tag,value) VALUES ('foo123','bar111');
+ INSERT INTO t2 VALUES (2231626,64280,0);
+ INSERT INTO t1 (tag,value) VALUES ('foo123','bar222');
+ INSERT INTO t2 VALUES (2231626,64281,0);
+insert into t1 (tag,value) values ('bar345','baz333 ar');
+insert into t2 values (12346, 3, 1);
+
+select * from t1; select * from t2;
+
+ SELECT DISTINCT t2.id_t2
+ FROM t2, t1
+ WHERE MATCH (t1.value) AGAINST ('baz333')
+ AND t1.id = t2.id_t1;
+
+DROP TABLE t1,t2;
diff --git a/pstack/Makefile.am b/pstack/Makefile.am
new file mode 100644
index 00000000000..1c0978379d0
--- /dev/null
+++ b/pstack/Makefile.am
@@ -0,0 +1,25 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# 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
+
+INCLUDES = -I$(srcdir)/../include -I../include
+pkglib_LIBRARIES = libpstack.a
+noinst_HEADERS = bucomm.h debug.h ieee.h budbg.h demangle.h \
+ linuxthreads.h pstack.h pstacktrace.h
+libpstack_a_SOURCES = bucomm.c filemode.c linuxthreads.c rddbg.c \
+ debug.c ieee.c pstack.c stabs.c
+
+# Don't update the files from bitkeeper
+%::SCCS/s.%
diff --git a/pstack/aout/aout64.h b/pstack/aout/aout64.h
new file mode 100644
index 00000000000..76f1140b682
--- /dev/null
+++ b/pstack/aout/aout64.h
@@ -0,0 +1,475 @@
+/* `a.out' object-file definitions, including extensions to 64-bit fields */
+
+#ifndef __A_OUT_64_H__
+#define __A_OUT_64_H__
+
+/* This is the layout on disk of the 32-bit or 64-bit exec header. */
+
+#ifndef external_exec
+struct external_exec
+{
+ bfd_byte e_info[4]; /* magic number and stuff */
+ bfd_byte e_text[BYTES_IN_WORD]; /* length of text section in bytes */
+ bfd_byte e_data[BYTES_IN_WORD]; /* length of data section in bytes */
+ bfd_byte e_bss[BYTES_IN_WORD]; /* length of bss area in bytes */
+ bfd_byte e_syms[BYTES_IN_WORD]; /* length of symbol table in bytes */
+ bfd_byte e_entry[BYTES_IN_WORD]; /* start address */
+ bfd_byte e_trsize[BYTES_IN_WORD]; /* length of text relocation info */
+ bfd_byte e_drsize[BYTES_IN_WORD]; /* length of data relocation info */
+};
+
+#define EXEC_BYTES_SIZE (4 + BYTES_IN_WORD * 7)
+
+/* Magic numbers for a.out files */
+
+#if ARCH_SIZE==64
+#define OMAGIC 0x1001 /* Code indicating object file */
+#define ZMAGIC 0x1002 /* Code indicating demand-paged executable. */
+#define NMAGIC 0x1003 /* Code indicating pure executable. */
+
+/* There is no 64-bit QMAGIC as far as I know. */
+
+#define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \
+ && N_MAGIC(x) != NMAGIC \
+ && N_MAGIC(x) != ZMAGIC)
+#else
+#define OMAGIC 0407 /* ...object file or impure executable. */
+#define NMAGIC 0410 /* Code indicating pure executable. */
+#define ZMAGIC 0413 /* Code indicating demand-paged executable. */
+#define BMAGIC 0415 /* Used by a b.out object. */
+
+/* This indicates a demand-paged executable with the header in the text.
+ It is used by 386BSD (and variants) and Linux, at least. */
+#ifndef QMAGIC
+#define QMAGIC 0314
+#endif
+# ifndef N_BADMAG
+# define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \
+ && N_MAGIC(x) != NMAGIC \
+ && N_MAGIC(x) != ZMAGIC \
+ && N_MAGIC(x) != QMAGIC)
+# endif /* N_BADMAG */
+#endif
+
+#endif
+
+#ifdef QMAGIC
+#define N_IS_QMAGIC(x) (N_MAGIC (x) == QMAGIC)
+#else
+#define N_IS_QMAGIC(x) (0)
+#endif
+
+/* The difference between TARGET_PAGE_SIZE and N_SEGSIZE is that TARGET_PAGE_SIZE is
+ the finest granularity at which you can page something, thus it
+ controls the padding (if any) before the text segment of a ZMAGIC
+ file. N_SEGSIZE is the resolution at which things can be marked as
+ read-only versus read/write, so it controls the padding between the
+ text segment and the data segment (in memory; on disk the padding
+ between them is TARGET_PAGE_SIZE). TARGET_PAGE_SIZE and N_SEGSIZE are the same
+ for most machines, but different for sun3. */
+
+/* By default, segment size is constant. But some machines override this
+ to be a function of the a.out header (e.g. machine type). */
+
+#ifndef N_SEGSIZE
+#define N_SEGSIZE(x) SEGMENT_SIZE
+#endif
+
+/* Virtual memory address of the text section.
+ This is getting very complicated. A good reason to discard a.out format
+ for something that specifies these fields explicitly. But til then...
+
+ * OMAGIC and NMAGIC files:
+ (object files: text for "relocatable addr 0" right after the header)
+ start at 0, offset is EXEC_BYTES_SIZE, size as stated.
+ * The text address, offset, and size of ZMAGIC files depend
+ on the entry point of the file:
+ * entry point below TEXT_START_ADDR:
+ (hack for SunOS shared libraries)
+ start at 0, offset is 0, size as stated.
+ * If N_HEADER_IN_TEXT(x) is true (which defaults to being the
+ case when the entry point is EXEC_BYTES_SIZE or further into a page):
+ no padding is needed; text can start after exec header. Sun
+ considers the text segment of such files to include the exec header;
+ for BFD's purposes, we don't, which makes more work for us.
+ start at TEXT_START_ADDR + EXEC_BYTES_SIZE, offset is EXEC_BYTES_SIZE,
+ size as stated minus EXEC_BYTES_SIZE.
+ * If N_HEADER_IN_TEXT(x) is false (which defaults to being the case when
+ the entry point is less than EXEC_BYTES_SIZE into a page (e.g. page
+ aligned)): (padding is needed so that text can start at a page boundary)
+ start at TEXT_START_ADDR, offset TARGET_PAGE_SIZE, size as stated.
+
+ Specific configurations may want to hardwire N_HEADER_IN_TEXT,
+ for efficiency or to allow people to play games with the entry point.
+ In that case, you would #define N_HEADER_IN_TEXT(x) as 1 for sunos,
+ and as 0 for most other hosts (Sony News, Vax Ultrix, etc).
+ (Do this in the appropriate bfd target file.)
+ (The default is a heuristic that will break if people try changing
+ the entry point, perhaps with the ld -e flag.)
+
+ * QMAGIC is always like a ZMAGIC for which N_HEADER_IN_TEXT is true,
+ and for which the starting address is TARGET_PAGE_SIZE (or should this be
+ SEGMENT_SIZE?) (TEXT_START_ADDR only applies to ZMAGIC, not to QMAGIC).
+ */
+
+/* This macro is only relevant for ZMAGIC files; QMAGIC always has the header
+ in the text. */
+#ifndef N_HEADER_IN_TEXT
+#define N_HEADER_IN_TEXT(x) (((x).a_entry & (TARGET_PAGE_SIZE-1)) >= EXEC_BYTES_SIZE)
+#endif
+
+/* Sun shared libraries, not linux. This macro is only relevant for ZMAGIC
+ files. */
+#ifndef N_SHARED_LIB
+#define N_SHARED_LIB(x) ((x).a_entry < TEXT_START_ADDR)
+#endif
+
+/* Returning 0 not TEXT_START_ADDR for OMAGIC and NMAGIC is based on
+ the assumption that we are dealing with a .o file, not an
+ executable. This is necessary for OMAGIC (but means we don't work
+ right on the output from ld -N); more questionable for NMAGIC. */
+
+#ifndef N_TXTADDR
+#define N_TXTADDR(x) \
+ (/* The address of a QMAGIC file is always one page in, */ \
+ /* with the header in the text. */ \
+ N_IS_QMAGIC (x) ? TARGET_PAGE_SIZE + EXEC_BYTES_SIZE : \
+ N_MAGIC(x) != ZMAGIC ? 0 : /* object file or NMAGIC */\
+ N_SHARED_LIB(x) ? 0 : \
+ N_HEADER_IN_TEXT(x) ? \
+ TEXT_START_ADDR + EXEC_BYTES_SIZE : /* no padding */\
+ TEXT_START_ADDR /* a page of padding */\
+ )
+#endif
+
+/* If N_HEADER_IN_TEXT is not true for ZMAGIC, there is some padding
+ to make the text segment start at a certain boundary. For most
+ systems, this boundary is TARGET_PAGE_SIZE. But for Linux, in the
+ time-honored tradition of crazy ZMAGIC hacks, it is 1024 which is
+ not what TARGET_PAGE_SIZE needs to be for QMAGIC. */
+
+#ifndef ZMAGIC_DISK_BLOCK_SIZE
+#define ZMAGIC_DISK_BLOCK_SIZE TARGET_PAGE_SIZE
+#endif
+
+#define N_DISK_BLOCK_SIZE(x) \
+ (N_MAGIC(x) == ZMAGIC ? ZMAGIC_DISK_BLOCK_SIZE : TARGET_PAGE_SIZE)
+
+/* Offset in an a.out of the start of the text section. */
+#ifndef N_TXTOFF
+#define N_TXTOFF(x) \
+ (/* For {O,N,Q}MAGIC, no padding. */ \
+ N_MAGIC(x) != ZMAGIC ? EXEC_BYTES_SIZE : \
+ N_SHARED_LIB(x) ? 0 : \
+ N_HEADER_IN_TEXT(x) ? \
+ EXEC_BYTES_SIZE : /* no padding */\
+ ZMAGIC_DISK_BLOCK_SIZE /* a page of padding */\
+ )
+#endif
+/* Size of the text section. It's always as stated, except that we
+ offset it to `undo' the adjustment to N_TXTADDR and N_TXTOFF
+ for ZMAGIC files that nominally include the exec header
+ as part of the first page of text. (BFD doesn't consider the
+ exec header to be part of the text segment.) */
+#ifndef N_TXTSIZE
+#define N_TXTSIZE(x) \
+ (/* For QMAGIC, we don't consider the header part of the text section. */\
+ N_IS_QMAGIC (x) ? (x).a_text - EXEC_BYTES_SIZE : \
+ (N_MAGIC(x) != ZMAGIC || N_SHARED_LIB(x)) ? (x).a_text : \
+ N_HEADER_IN_TEXT(x) ? \
+ (x).a_text - EXEC_BYTES_SIZE: /* no padding */\
+ (x).a_text /* a page of padding */\
+ )
+#endif
+/* The address of the data segment in virtual memory.
+ It is the text segment address, plus text segment size, rounded
+ up to a N_SEGSIZE boundary for pure or pageable files. */
+#ifndef N_DATADDR
+#define N_DATADDR(x) \
+ (N_MAGIC(x)==OMAGIC? (N_TXTADDR(x)+N_TXTSIZE(x)) \
+ : (N_SEGSIZE(x) + ((N_TXTADDR(x)+N_TXTSIZE(x)-1) & ~(N_SEGSIZE(x)-1))))
+#endif
+/* The address of the BSS segment -- immediately after the data segment. */
+
+#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data)
+
+/* Offsets of the various portions of the file after the text segment. */
+
+/* For {Q,Z}MAGIC, there is padding to make the data segment start on
+ a page boundary. Most of the time the a_text field (and thus
+ N_TXTSIZE) already contains this padding. It is possible that for
+ BSDI and/or 386BSD it sometimes doesn't contain the padding, and
+ perhaps we should be adding it here. But this seems kind of
+ questionable and probably should be BSDI/386BSD-specific if we do
+ do it.
+
+ For NMAGIC (at least for hp300 BSD, probably others), there is
+ padding in memory only, not on disk, so we must *not* ever pad here
+ for NMAGIC. */
+
+#ifndef N_DATOFF
+#define N_DATOFF(x) \
+ (N_TXTOFF(x) + N_TXTSIZE(x))
+#endif
+
+#ifndef N_TRELOFF
+#define N_TRELOFF(x) ( N_DATOFF(x) + (x).a_data )
+#endif
+#ifndef N_DRELOFF
+#define N_DRELOFF(x) ( N_TRELOFF(x) + (x).a_trsize )
+#endif
+#ifndef N_SYMOFF
+#define N_SYMOFF(x) ( N_DRELOFF(x) + (x).a_drsize )
+#endif
+#ifndef N_STROFF
+#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms )
+#endif
+
+/* Symbols */
+#ifndef external_nlist
+struct external_nlist {
+ bfd_byte e_strx[BYTES_IN_WORD]; /* index into string table of name */
+ bfd_byte e_type[1]; /* type of symbol */
+ bfd_byte e_other[1]; /* misc info (usually empty) */
+ bfd_byte e_desc[2]; /* description field */
+ bfd_byte e_value[BYTES_IN_WORD]; /* value of symbol */
+};
+#define EXTERNAL_NLIST_SIZE (BYTES_IN_WORD+4+BYTES_IN_WORD)
+#endif
+
+struct internal_nlist {
+ unsigned long n_strx; /* index into string table of name */
+ unsigned char n_type; /* type of symbol */
+ unsigned char n_other; /* misc info (usually empty) */
+ unsigned short n_desc; /* description field */
+ bfd_vma n_value; /* value of symbol */
+};
+
+/* The n_type field is the symbol type, containing: */
+
+#define N_UNDF 0 /* Undefined symbol */
+#define N_ABS 2 /* Absolute symbol -- defined at particular addr */
+#define N_TEXT 4 /* Text sym -- defined at offset in text seg */
+#define N_DATA 6 /* Data sym -- defined at offset in data seg */
+#define N_BSS 8 /* BSS sym -- defined at offset in zero'd seg */
+#define N_COMM 0x12 /* Common symbol (visible after shared lib dynlink) */
+#define N_FN 0x1f /* File name of .o file */
+#define N_FN_SEQ 0x0C /* N_FN from Sequent compilers (sigh) */
+/* Note: N_EXT can only be usefully OR-ed with N_UNDF, N_ABS, N_TEXT,
+ N_DATA, or N_BSS. When the low-order bit of other types is set,
+ (e.g. N_WARNING versus N_FN), they are two different types. */
+#define N_EXT 1 /* External symbol (as opposed to local-to-this-file) */
+#define N_TYPE 0x1e
+#define N_STAB 0xe0 /* If any of these bits are on, it's a debug symbol */
+
+#define N_INDR 0x0a
+
+/* The following symbols refer to set elements.
+ All the N_SET[ATDB] symbols with the same name form one set.
+ Space is allocated for the set in the text section, and each set
+ elements value is stored into one word of the space.
+ The first word of the space is the length of the set (number of elements).
+
+ The address of the set is made into an N_SETV symbol
+ whose name is the same as the name of the set.
+ This symbol acts like a N_DATA global symbol
+ in that it can satisfy undefined external references. */
+
+/* These appear as input to LD, in a .o file. */
+#define N_SETA 0x14 /* Absolute set element symbol */
+#define N_SETT 0x16 /* Text set element symbol */
+#define N_SETD 0x18 /* Data set element symbol */
+#define N_SETB 0x1A /* Bss set element symbol */
+
+/* This is output from LD. */
+#define N_SETV 0x1C /* Pointer to set vector in data area. */
+
+/* Warning symbol. The text gives a warning message, the next symbol
+ in the table will be undefined. When the symbol is referenced, the
+ message is printed. */
+
+#define N_WARNING 0x1e
+
+/* Weak symbols. These are a GNU extension to the a.out format. The
+ semantics are those of ELF weak symbols. Weak symbols are always
+ externally visible. The N_WEAK? values are squeezed into the
+ available slots. The value of a N_WEAKU symbol is 0. The values
+ of the other types are the definitions. */
+#define N_WEAKU 0x0d /* Weak undefined symbol. */
+#define N_WEAKA 0x0e /* Weak absolute symbol. */
+#define N_WEAKT 0x0f /* Weak text symbol. */
+#define N_WEAKD 0x10 /* Weak data symbol. */
+#define N_WEAKB 0x11 /* Weak bss symbol. */
+
+/* Relocations
+
+ There are two types of relocation flavours for a.out systems,
+ standard and extended. The standard form is used on systems where the
+ instruction has room for all the bits of an offset to the operand, whilst
+ the extended form is used when an address operand has to be split over n
+ instructions. Eg, on the 68k, each move instruction can reference
+ the target with a displacement of 16 or 32 bits. On the sparc, move
+ instructions use an offset of 14 bits, so the offset is stored in
+ the reloc field, and the data in the section is ignored.
+*/
+
+/* This structure describes a single relocation to be performed.
+ The text-relocation section of the file is a vector of these structures,
+ all of which apply to the text section.
+ Likewise, the data-relocation section applies to the data section. */
+
+struct reloc_std_external {
+ bfd_byte r_address[BYTES_IN_WORD]; /* offset of of data to relocate */
+ bfd_byte r_index[3]; /* symbol table index of symbol */
+ bfd_byte r_type[1]; /* relocation type */
+};
+
+#define RELOC_STD_BITS_PCREL_BIG ((unsigned int) 0x80)
+#define RELOC_STD_BITS_PCREL_LITTLE ((unsigned int) 0x01)
+
+#define RELOC_STD_BITS_LENGTH_BIG ((unsigned int) 0x60)
+#define RELOC_STD_BITS_LENGTH_SH_BIG 5
+#define RELOC_STD_BITS_LENGTH_LITTLE ((unsigned int) 0x06)
+#define RELOC_STD_BITS_LENGTH_SH_LITTLE 1
+
+#define RELOC_STD_BITS_EXTERN_BIG ((unsigned int) 0x10)
+#define RELOC_STD_BITS_EXTERN_LITTLE ((unsigned int) 0x08)
+
+#define RELOC_STD_BITS_BASEREL_BIG ((unsigned int) 0x08)
+#define RELOC_STD_BITS_BASEREL_LITTLE ((unsigned int) 0x10)
+
+#define RELOC_STD_BITS_JMPTABLE_BIG ((unsigned int) 0x04)
+#define RELOC_STD_BITS_JMPTABLE_LITTLE ((unsigned int) 0x20)
+
+#define RELOC_STD_BITS_RELATIVE_BIG ((unsigned int) 0x02)
+#define RELOC_STD_BITS_RELATIVE_LITTLE ((unsigned int) 0x40)
+
+#define RELOC_STD_SIZE (BYTES_IN_WORD + 3 + 1) /* Bytes per relocation entry */
+
+struct reloc_std_internal
+{
+ bfd_vma r_address; /* Address (within segment) to be relocated. */
+ /* The meaning of r_symbolnum depends on r_extern. */
+ unsigned int r_symbolnum:24;
+ /* Nonzero means value is a pc-relative offset
+ and it should be relocated for changes in its own address
+ as well as for changes in the symbol or section specified. */
+ unsigned int r_pcrel:1;
+ /* Length (as exponent of 2) of the field to be relocated.
+ Thus, a value of 2 indicates 1<<2 bytes. */
+ unsigned int r_length:2;
+ /* 1 => relocate with value of symbol.
+ r_symbolnum is the index of the symbol
+ in files the symbol table.
+ 0 => relocate with the address of a segment.
+ r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS
+ (the N_EXT bit may be set also, but signifies nothing). */
+ unsigned int r_extern:1;
+ /* The next three bits are for SunOS shared libraries, and seem to
+ be undocumented. */
+ unsigned int r_baserel:1; /* Linkage table relative */
+ unsigned int r_jmptable:1; /* pc-relative to jump table */
+ unsigned int r_relative:1; /* "relative relocation" */
+ /* unused */
+ unsigned int r_pad:1; /* Padding -- set to zero */
+};
+
+
+/* EXTENDED RELOCS */
+
+struct reloc_ext_external {
+ bfd_byte r_address[BYTES_IN_WORD]; /* offset of of data to relocate */
+ bfd_byte r_index[3]; /* symbol table index of symbol */
+ bfd_byte r_type[1]; /* relocation type */
+ bfd_byte r_addend[BYTES_IN_WORD]; /* datum addend */
+};
+
+#define RELOC_EXT_BITS_EXTERN_BIG ((unsigned int) 0x80)
+#define RELOC_EXT_BITS_EXTERN_LITTLE ((unsigned int) 0x01)
+
+#define RELOC_EXT_BITS_TYPE_BIG ((unsigned int) 0x1F)
+#define RELOC_EXT_BITS_TYPE_SH_BIG 0
+#define RELOC_EXT_BITS_TYPE_LITTLE ((unsigned int) 0xF8)
+#define RELOC_EXT_BITS_TYPE_SH_LITTLE 3
+
+/* Bytes per relocation entry */
+#define RELOC_EXT_SIZE (BYTES_IN_WORD + 3 + 1 + BYTES_IN_WORD)
+
+enum reloc_type
+{
+ /* simple relocations */
+ RELOC_8, /* data[0:7] = addend + sv */
+ RELOC_16, /* data[0:15] = addend + sv */
+ RELOC_32, /* data[0:31] = addend + sv */
+ /* pc-rel displacement */
+ RELOC_DISP8, /* data[0:7] = addend - pc + sv */
+ RELOC_DISP16, /* data[0:15] = addend - pc + sv */
+ RELOC_DISP32, /* data[0:31] = addend - pc + sv */
+ /* Special */
+ RELOC_WDISP30, /* data[0:29] = (addend + sv - pc)>>2 */
+ RELOC_WDISP22, /* data[0:21] = (addend + sv - pc)>>2 */
+ RELOC_HI22, /* data[0:21] = (addend + sv)>>10 */
+ RELOC_22, /* data[0:21] = (addend + sv) */
+ RELOC_13, /* data[0:12] = (addend + sv) */
+ RELOC_LO10, /* data[0:9] = (addend + sv) */
+ RELOC_SFA_BASE,
+ RELOC_SFA_OFF13,
+ /* P.I.C. (base-relative) */
+ RELOC_BASE10, /* Not sure - maybe we can do this the */
+ RELOC_BASE13, /* right way now */
+ RELOC_BASE22,
+ /* for some sort of pc-rel P.I.C. (?) */
+ RELOC_PC10,
+ RELOC_PC22,
+ /* P.I.C. jump table */
+ RELOC_JMP_TBL,
+ /* reputedly for shared libraries somehow */
+ RELOC_SEGOFF16,
+ RELOC_GLOB_DAT,
+ RELOC_JMP_SLOT,
+ RELOC_RELATIVE,
+
+ RELOC_11,
+ RELOC_WDISP2_14,
+ RELOC_WDISP19,
+ RELOC_HHI22, /* data[0:21] = (addend + sv) >> 42 */
+ RELOC_HLO10, /* data[0:9] = (addend + sv) >> 32 */
+
+ /* 29K relocation types */
+ RELOC_JUMPTARG,
+ RELOC_CONST,
+ RELOC_CONSTH,
+
+ /* All the new ones I can think of, for sparc v9 */
+
+ RELOC_64, /* data[0:63] = addend + sv */
+ RELOC_DISP64, /* data[0:63] = addend - pc + sv */
+ RELOC_WDISP21, /* data[0:20] = (addend + sv - pc)>>2 */
+ RELOC_DISP21, /* data[0:20] = addend - pc + sv */
+ RELOC_DISP14, /* data[0:13] = addend - pc + sv */
+ /* Q .
+ What are the other ones,
+ Since this is a clean slate, can we throw away the ones we dont
+ understand ? Should we sort the values ? What about using a
+ microcode format like the 68k ?
+ */
+ NO_RELOC
+ };
+
+
+struct reloc_internal {
+ bfd_vma r_address; /* offset of of data to relocate */
+ long r_index; /* symbol table index of symbol */
+ enum reloc_type r_type; /* relocation type */
+ bfd_vma r_addend; /* datum addend */
+};
+
+/* Q.
+ Should the length of the string table be 4 bytes or 8 bytes ?
+
+ Q.
+ What about archive indexes ?
+
+ */
+
+#endif /* __A_OUT_64_H__ */
diff --git a/pstack/aout/stab.def b/pstack/aout/stab.def
new file mode 100644
index 00000000000..3c6b456d3a9
--- /dev/null
+++ b/pstack/aout/stab.def
@@ -0,0 +1,264 @@
+/* Table of DBX symbol codes for the GNU system.
+ Copyright (C) 1988, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+
+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. */
+
+/* New stab from Solaris 2. This uses an n_type of 0, which in a.out files
+ overlaps the N_UNDF used for ordinary symbols. In ELF files, the
+ debug information is in a different file section, so there is no conflict.
+ This symbol's n_value gives the size of the string section associated
+ with this file. The symbol's n_strx (relative to the just-updated
+ string section start address) gives the name of the source file,
+ e.g. "foo.c", without any path information. The symbol's n_desc gives
+ the count of upcoming symbols associated with this file (not including
+ this one). */
+/* __define_stab (N_UNDF, 0x00, "UNDF") */
+
+/* Global variable. Only the name is significant.
+ To find the address, look in the corresponding external symbol. */
+__define_stab (N_GSYM, 0x20, "GSYM")
+
+/* Function name for BSD Fortran. Only the name is significant.
+ To find the address, look in the corresponding external symbol. */
+__define_stab (N_FNAME, 0x22, "FNAME")
+
+/* Function name or text-segment variable for C. Value is its address.
+ Desc is supposedly starting line number, but GCC doesn't set it
+ and DBX seems not to miss it. */
+__define_stab (N_FUN, 0x24, "FUN")
+
+/* Data-segment variable with internal linkage. Value is its address.
+ "Static Sym". */
+__define_stab (N_STSYM, 0x26, "STSYM")
+
+/* BSS-segment variable with internal linkage. Value is its address. */
+__define_stab (N_LCSYM, 0x28, "LCSYM")
+
+/* Name of main routine. Only the name is significant. */
+__define_stab (N_MAIN, 0x2a, "MAIN")
+
+/* Solaris2: Read-only data symbols. */
+__define_stab (N_ROSYM, 0x2c, "ROSYM")
+
+/* Global symbol in Pascal.
+ Supposedly the value is its line number; I'm skeptical. */
+__define_stab (N_PC, 0x30, "PC")
+
+/* Number of symbols: 0, files,,funcs,lines according to Ultrix V4.0. */
+__define_stab (N_NSYMS, 0x32, "NSYMS")
+
+/* "No DST map for sym: name, ,0,type,ignored" according to Ultrix V4.0. */
+__define_stab (N_NOMAP, 0x34, "NOMAP")
+
+/* New stab from Solaris 2. Like N_SO, but for the object file. Two in
+ a row provide the build directory and the relative path of the .o from it.
+ Solaris2 uses this to avoid putting the stabs info into the linked
+ executable; this stab goes into the ".stab.index" section, and the debugger
+ reads the real stabs directly from the .o files instead. */
+__define_stab (N_OBJ, 0x38, "OBJ")
+
+/* New stab from Solaris 2. Options for the debugger, related to the
+ source language for this module. E.g. whether to use ANSI
+ integral promotions or traditional integral promotions. */
+__define_stab (N_OPT, 0x3c, "OPT")
+
+/* Register variable. Value is number of register. */
+__define_stab (N_RSYM, 0x40, "RSYM")
+
+/* Modula-2 compilation unit. Can someone say what info it contains? */
+__define_stab (N_M2C, 0x42, "M2C")
+
+/* Line number in text segment. Desc is the line number;
+ value is corresponding address. On Solaris2, the line number is
+ relative to the start of the current function. */
+__define_stab (N_SLINE, 0x44, "SLINE")
+
+/* Similar, for data segment. */
+__define_stab (N_DSLINE, 0x46, "DSLINE")
+
+/* Similar, for bss segment. */
+__define_stab (N_BSLINE, 0x48, "BSLINE")
+
+/* Sun's source-code browser stabs. ?? Don't know what the fields are.
+ Supposedly the field is "path to associated .cb file". THIS VALUE
+ OVERLAPS WITH N_BSLINE! */
+__define_stab_duplicate (N_BROWS, 0x48, "BROWS")
+
+/* GNU Modula-2 definition module dependency. Value is the modification time
+ of the definition file. Other is non-zero if it is imported with the
+ GNU M2 keyword %INITIALIZE. Perhaps N_M2C can be used if there
+ are enough empty fields? */
+__define_stab(N_DEFD, 0x4a, "DEFD")
+
+/* New in Solaris2. Function start/body/end line numbers. */
+__define_stab(N_FLINE, 0x4C, "FLINE")
+
+/* THE FOLLOWING TWO STAB VALUES CONFLICT. Happily, one is for Modula-2
+ and one is for C++. Still,... */
+/* GNU C++ exception variable. Name is variable name. */
+__define_stab (N_EHDECL, 0x50, "EHDECL")
+/* Modula2 info "for imc": name,,0,0,0 according to Ultrix V4.0. */
+__define_stab_duplicate (N_MOD2, 0x50, "MOD2")
+
+/* GNU C++ `catch' clause. Value is its address. Desc is nonzero if
+ this entry is immediately followed by a CAUGHT stab saying what exception
+ was caught. Multiple CAUGHT stabs means that multiple exceptions
+ can be caught here. If Desc is 0, it means all exceptions are caught
+ here. */
+__define_stab (N_CATCH, 0x54, "CATCH")
+
+/* Structure or union element. Value is offset in the structure. */
+__define_stab (N_SSYM, 0x60, "SSYM")
+
+/* Solaris2: Last stab emitted for module. */
+__define_stab (N_ENDM, 0x62, "ENDM")
+
+/* Name of main source file.
+ Value is starting text address of the compilation.
+ If multiple N_SO's appear, the first to contain a trailing / is the
+ compilation directory. The first to not contain a trailing / is the
+ source file name, relative to the compilation directory. Others (perhaps
+ resulting from cfront) are ignored.
+ On Solaris2, value is undefined, but desc is a source-language code. */
+
+__define_stab (N_SO, 0x64, "SO")
+
+/* Automatic variable in the stack. Value is offset from frame pointer.
+ Also used for type descriptions. */
+__define_stab (N_LSYM, 0x80, "LSYM")
+
+/* Beginning of an include file. Only Sun uses this.
+ In an object file, only the name is significant.
+ The Sun linker puts data into some of the other fields. */
+__define_stab (N_BINCL, 0x82, "BINCL")
+
+/* Name of sub-source file (#include file).
+ Value is starting text address of the compilation. */
+__define_stab (N_SOL, 0x84, "SOL")
+
+/* Parameter variable. Value is offset from argument pointer.
+ (On most machines the argument pointer is the same as the frame pointer. */
+__define_stab (N_PSYM, 0xa0, "PSYM")
+
+/* End of an include file. No name.
+ This and N_BINCL act as brackets around the file's output.
+ In an object file, there is no significant data in this entry.
+ The Sun linker puts data into some of the fields. */
+__define_stab (N_EINCL, 0xa2, "EINCL")
+
+/* Alternate entry point. Value is its address. */
+__define_stab (N_ENTRY, 0xa4, "ENTRY")
+
+/* Beginning of lexical block.
+ The desc is the nesting level in lexical blocks.
+ The value is the address of the start of the text for the block.
+ The variables declared inside the block *precede* the N_LBRAC symbol.
+ On Solaris2, the value is relative to the start of the current function. */
+__define_stab (N_LBRAC, 0xc0, "LBRAC")
+
+/* Place holder for deleted include file. Replaces a N_BINCL and everything
+ up to the corresponding N_EINCL. The Sun linker generates these when
+ it finds multiple identical copies of the symbols from an include file.
+ This appears only in output from the Sun linker. */
+__define_stab (N_EXCL, 0xc2, "EXCL")
+
+/* Modula-2 scope information. Can someone say what info it contains? */
+__define_stab (N_SCOPE, 0xc4, "SCOPE")
+
+/* End of a lexical block. Desc matches the N_LBRAC's desc.
+ The value is the address of the end of the text for the block.
+ On Solaris2, the value is relative to the start of the current function. */
+__define_stab (N_RBRAC, 0xe0, "RBRAC")
+
+/* Begin named common block. Only the name is significant. */
+__define_stab (N_BCOMM, 0xe2, "BCOMM")
+
+/* End named common block. Only the name is significant
+ (and it should match the N_BCOMM). */
+__define_stab (N_ECOMM, 0xe4, "ECOMM")
+
+/* Member of a common block; value is offset within the common block.
+ This should occur within a BCOMM/ECOMM pair. */
+__define_stab (N_ECOML, 0xe8, "ECOML")
+
+/* Solaris2: Pascal "with" statement: type,,0,0,offset */
+__define_stab (N_WITH, 0xea, "WITH")
+
+/* These STAB's are used on Gould systems for Non-Base register symbols
+ or something like that. FIXME. I have assigned the values at random
+ since I don't have a Gould here. Fixups from Gould folk welcome... */
+__define_stab (N_NBTEXT, 0xF0, "NBTEXT")
+__define_stab (N_NBDATA, 0xF2, "NBDATA")
+__define_stab (N_NBBSS, 0xF4, "NBBSS")
+__define_stab (N_NBSTS, 0xF6, "NBSTS")
+__define_stab (N_NBLCS, 0xF8, "NBLCS")
+
+/* Second symbol entry containing a length-value for the preceding entry.
+ The value is the length. */
+__define_stab (N_LENG, 0xfe, "LENG")
+
+/* The above information, in matrix format.
+
+ STAB MATRIX
+ _________________________________________________
+ | 00 - 1F are not dbx stab symbols |
+ | In most cases, the low bit is the EXTernal bit|
+
+ | 00 UNDEF | 02 ABS | 04 TEXT | 06 DATA |
+ | 01 |EXT | 03 |EXT | 05 |EXT | 07 |EXT |
+
+ | 08 BSS | 0A INDR | 0C FN_SEQ | 0E WEAKA |
+ | 09 |EXT | 0B | 0D WEAKU | 0F WEAKT |
+
+ | 10 WEAKD | 12 COMM | 14 SETA | 16 SETT |
+ | 11 WEAKB | 13 | 15 | 17 |
+
+ | 18 SETD | 1A SETB | 1C SETV | 1E WARNING|
+ | 19 | 1B | 1D | 1F FN |
+
+ |_______________________________________________|
+ | Debug entries with bit 01 set are unused. |
+ | 20 GSYM | 22 FNAME | 24 FUN | 26 STSYM |
+ | 28 LCSYM | 2A MAIN | 2C ROSYM | 2E |
+ | 30 PC | 32 NSYMS | 34 NOMAP | 36 |
+ | 38 OBJ | 3A | 3C OPT | 3E |
+ | 40 RSYM | 42 M2C | 44 SLINE | 46 DSLINE |
+ | 48 BSLINE*| 4A DEFD | 4C FLINE | 4E |
+ | 50 EHDECL*| 52 | 54 CATCH | 56 |
+ | 58 | 5A | 5C | 5E |
+ | 60 SSYM | 62 ENDM | 64 SO | 66 |
+ | 68 | 6A | 6C | 6E |
+ | 70 | 72 | 74 | 76 |
+ | 78 | 7A | 7C | 7E |
+ | 80 LSYM | 82 BINCL | 84 SOL | 86 |
+ | 88 | 8A | 8C | 8E |
+ | 90 | 92 | 94 | 96 |
+ | 98 | 9A | 9C | 9E |
+ | A0 PSYM | A2 EINCL | A4 ENTRY | A6 |
+ | A8 | AA | AC | AE |
+ | B0 | B2 | B4 | B6 |
+ | B8 | BA | BC | BE |
+ | C0 LBRAC | C2 EXCL | C4 SCOPE | C6 |
+ | C8 | CA | CC | CE |
+ | D0 | D2 | D4 | D6 |
+ | D8 | DA | DC | DE |
+ | E0 RBRAC | E2 BCOMM | E4 ECOMM | E6 |
+ | E8 ECOML | EA WITH | EC | EE |
+ | F0 | F2 | F4 | F6 |
+ | F8 | FA | FC | FE LENG |
+ +-----------------------------------------------+
+ * 50 EHDECL is also MOD2.
+ * 48 BSLINE is also BROWS.
+ */
diff --git a/pstack/aout/stab_gnu.h b/pstack/aout/stab_gnu.h
new file mode 100644
index 00000000000..7d18e14a263
--- /dev/null
+++ b/pstack/aout/stab_gnu.h
@@ -0,0 +1,37 @@
+#ifndef __GNU_STAB__
+
+/* Indicate the GNU stab.h is in use. */
+
+#define __GNU_STAB__
+
+#define __define_stab(NAME, CODE, STRING) NAME=CODE,
+#define __define_stab_duplicate(NAME, CODE, STRING) NAME=CODE,
+
+enum __stab_debug_code
+{
+#include "aout/stab.def"
+LAST_UNUSED_STAB_CODE
+};
+
+#undef __define_stab
+
+/* Definitions of "desc" field for N_SO stabs in Solaris2. */
+
+#define N_SO_AS 1
+#define N_SO_C 2
+#define N_SO_ANSI_C 3
+#define N_SO_CC 4 /* C++ */
+#define N_SO_FORTRAN 5
+#define N_SO_PASCAL 6
+
+/* Solaris2: Floating point type values in basic types. */
+
+#define NF_NONE 0
+#define NF_SINGLE 1 /* IEEE 32-bit */
+#define NF_DOUBLE 2 /* IEEE 64-bit */
+#define NF_COMPLEX 3 /* Fortran complex */
+#define NF_COMPLEX16 4 /* Fortran double complex */
+#define NF_COMPLEX32 5 /* Fortran complex*16 */
+#define NF_LDOUBLE 6 /* Long double (whatever that is) */
+
+#endif /* __GNU_STAB_ */
diff --git a/pstack/bucomm.c b/pstack/bucomm.c
new file mode 100644
index 00000000000..2b44239d1d3
--- /dev/null
+++ b/pstack/bucomm.c
@@ -0,0 +1,238 @@
+/* bucomm.c -- Bin Utils COMmon code.
+ Copyright (C) 1991, 92, 93, 94, 95, 1997 Free Software Foundation, Inc.
+
+ This file is part of GNU Binutils.
+
+ 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. */
+
+/* We might put this in a library someday so it could be dynamically
+ loaded, but for now it's not necessary. */
+
+#include <bfd.h>
+#include <libiberty.h>
+#include "bucomm.h"
+
+#include <sys/stat.h>
+#include <time.h> /* ctime, maybe time_t */
+
+#ifdef ANSI_PROTOTYPES
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+/* Error reporting */
+
+char *program_name;
+
+void
+bfd_nonfatal (string)
+ CONST char *string;
+{
+ CONST char *errmsg = bfd_errmsg (bfd_get_error ());
+
+ if (string)
+ fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg);
+ else
+ fprintf (stderr, "%s: %s\n", program_name, errmsg);
+}
+
+void
+bfd_fatal (string)
+ CONST char *string;
+{
+ bfd_nonfatal (string);
+ xexit (1);
+}
+
+#ifdef ANSI_PROTOTYPES
+void
+fatal (const char *format, ...)
+{
+ va_list args;
+
+ fprintf (stderr, "%s: ", program_name);
+ va_start (args, format);
+ vfprintf (stderr, format, args);
+ va_end (args);
+ putc ('\n', stderr);
+ xexit (1);
+}
+#else
+void
+fatal (va_alist)
+ va_dcl
+{
+ char *Format;
+ va_list args;
+
+ fprintf (stderr, "%s: ", program_name);
+ va_start (args);
+ Format = va_arg (args, char *);
+ vfprintf (stderr, Format, args);
+ va_end (args);
+ putc ('\n', stderr);
+ xexit (1);
+}
+#endif
+
+/* Set the default BFD target based on the configured target. Doing
+ this permits the binutils to be configured for a particular target,
+ and linked against a shared BFD library which was configured for a
+ different target. */
+
+#define TARGET "elf32-i386" /* FIXME: hard-coded! */
+void
+set_default_bfd_target ()
+{
+ /* The macro TARGET is defined by Makefile. */
+ const char *target = TARGET;
+
+ if (! bfd_set_default_target (target))
+ {
+ char *errmsg;
+
+ errmsg = (char *) xmalloc (100 + strlen (target));
+ sprintf (errmsg, "can't set BFD default target to `%s'", target);
+ bfd_fatal (errmsg);
+ }
+}
+
+/* After a false return from bfd_check_format_matches with
+ bfd_get_error () == bfd_error_file_ambiguously_recognized, print
+ the possible matching targets. */
+
+void
+list_matching_formats (p)
+ char **p;
+{
+ fprintf(stderr, "%s: Matching formats:", program_name);
+ while (*p)
+ fprintf(stderr, " %s", *p++);
+ fprintf(stderr, "\n");
+}
+
+/* List the supported targets. */
+
+void
+list_supported_targets (name, f)
+ const char *name;
+ FILE *f;
+{
+ extern bfd_target *bfd_target_vector[];
+ int t;
+
+ if (name == NULL)
+ fprintf (f, "Supported targets:");
+ else
+ fprintf (f, "%s: supported targets:", name);
+ for (t = 0; bfd_target_vector[t] != NULL; t++)
+ fprintf (f, " %s", bfd_target_vector[t]->name);
+ fprintf (f, "\n");
+}
+
+/* Display the archive header for an element as if it were an ls -l listing:
+
+ Mode User\tGroup\tSize\tDate Name */
+
+void
+print_arelt_descr (file, abfd, verbose)
+ FILE *file;
+ bfd *abfd;
+ boolean verbose;
+{
+ struct stat buf;
+
+ if (verbose)
+ {
+ if (bfd_stat_arch_elt (abfd, &buf) == 0)
+ {
+ char modebuf[11];
+ char timebuf[40];
+ time_t when = buf.st_mtime;
+ CONST char *ctime_result = (CONST char *) ctime (&when);
+
+ /* POSIX format: skip weekday and seconds from ctime output. */
+ sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20);
+
+ mode_string (buf.st_mode, modebuf);
+ modebuf[10] = '\0';
+ /* POSIX 1003.2/D11 says to skip first character (entry type). */
+ fprintf (file, "%s %ld/%ld %6ld %s ", modebuf + 1,
+ (long) buf.st_uid, (long) buf.st_gid,
+ (long) buf.st_size, timebuf);
+ }
+ }
+
+ fprintf (file, "%s\n", bfd_get_filename (abfd));
+}
+
+/* Return the name of a temporary file in the same directory as FILENAME. */
+
+char *
+make_tempname (filename)
+ char *filename;
+{
+ static char template[] = "stXXXXXX";
+ char *tmpname;
+ char *slash = strrchr (filename, '/');
+
+#if defined (__DJGPP__) || defined (__GO32__) || defined (_WIN32)
+ if (slash == NULL)
+ slash = strrchr (filename, '\\');
+#endif
+
+ if (slash != (char *) NULL)
+ {
+ char c;
+
+ c = *slash;
+ *slash = 0;
+ tmpname = xmalloc (strlen (filename) + sizeof (template) + 1);
+ strcpy (tmpname, filename);
+ strcat (tmpname, "/");
+ strcat (tmpname, template);
+ mktemp (tmpname);
+ *slash = c;
+ }
+ else
+ {
+ tmpname = xmalloc (sizeof (template));
+ strcpy (tmpname, template);
+ mktemp (tmpname);
+ }
+ return tmpname;
+}
+
+/* Parse a string into a VMA, with a fatal error if it can't be
+ parsed. */
+
+bfd_vma
+parse_vma (s, arg)
+ const char *s;
+ const char *arg;
+{
+ bfd_vma ret;
+ const char *end;
+
+ ret = bfd_scan_vma (s, &end, 0);
+ if (*end != '\0')
+ {
+ fprintf (stderr, "%s: %s: bad number: %s\n", program_name, arg, s);
+ exit (1);
+ }
+ return ret;
+}
diff --git a/pstack/bucomm.h b/pstack/bucomm.h
new file mode 100644
index 00000000000..7712a70f5a2
--- /dev/null
+++ b/pstack/bucomm.h
@@ -0,0 +1,85 @@
+/* bucomm.h -- binutils common include file.
+ Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
+
+This file is part of GNU Binutils.
+
+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. */
+
+#ifndef _BUCOMM_H
+#define _BUCOMM_H
+
+#include "ansidecl.h"
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <string.h>
+
+#include <stdlib.h>
+
+#include <fcntl.h>
+
+#ifdef __GNUC__
+# undef alloca
+# define alloca __builtin_alloca
+#else
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifndef alloca /* predefined by HP cc +Olibcalls */
+# if !defined (__STDC__) && !defined (__hpux)
+char *alloca ();
+# else
+void *alloca ();
+# endif /* __STDC__, __hpux */
+# endif /* alloca */
+# endif /* HAVE_ALLOCA_H */
+#endif
+
+/* bucomm.c */
+void bfd_nonfatal PARAMS ((CONST char *));
+
+void bfd_fatal PARAMS ((CONST char *));
+
+void fatal PARAMS ((CONST char *, ...));
+
+void set_default_bfd_target PARAMS ((void));
+
+void list_matching_formats PARAMS ((char **p));
+
+void list_supported_targets PARAMS ((const char *, FILE *));
+
+void print_arelt_descr PARAMS ((FILE *file, bfd *abfd, boolean verbose));
+
+char *make_tempname PARAMS ((char *));
+
+bfd_vma parse_vma PARAMS ((const char *, const char *));
+
+extern char *program_name;
+
+/* filemode.c */
+void mode_string PARAMS ((unsigned long mode, char *buf));
+
+/* version.c */
+extern void print_version PARAMS ((const char *));
+
+/* libiberty */
+PTR xmalloc PARAMS ((size_t));
+
+PTR xrealloc PARAMS ((PTR, size_t));
+
+#endif /* _BUCOMM_H */
diff --git a/pstack/budbg.h b/pstack/budbg.h
new file mode 100644
index 00000000000..d8ee8895e76
--- /dev/null
+++ b/pstack/budbg.h
@@ -0,0 +1,58 @@
+/* budbg.c -- Interfaces to the generic debugging information routines.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@cygnus.com>.
+
+ This file is part of GNU Binutils.
+
+ 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. */
+
+#ifndef BUDBG_H
+#define BUDBG_H
+
+#include <stdio.h>
+
+/* Routine used to read generic debugging information. */
+
+extern PTR read_debugging_info PARAMS ((bfd *, asymbol **, long));
+
+/* Routine used to print generic debugging information. */
+
+extern boolean print_debugging_info PARAMS ((FILE *, PTR));
+
+/* Routines used to read and write stabs information. */
+
+extern PTR start_stab PARAMS ((PTR, bfd *, boolean, asymbol **, long));
+
+extern boolean finish_stab PARAMS ((PTR, PTR));
+
+extern boolean parse_stab PARAMS ((PTR, PTR, int, int, bfd_vma, const char *));
+
+extern boolean write_stabs_in_sections_debugging_info
+ PARAMS ((bfd *, PTR, bfd_byte **, bfd_size_type *, bfd_byte **,
+ bfd_size_type *));
+
+/* Routines used to read and write IEEE debugging information. */
+
+extern boolean parse_ieee
+ PARAMS ((PTR, bfd *, const bfd_byte *, bfd_size_type));
+
+extern boolean write_ieee_debugging_info PARAMS ((bfd *, PTR));
+
+/* Routine used to read COFF debugging information. */
+
+extern boolean parse_coff PARAMS ((bfd *, asymbol **, long, PTR));
+
+#endif
diff --git a/pstack/debug.c b/pstack/debug.c
new file mode 100644
index 00000000000..ee62bb17062
--- /dev/null
+++ b/pstack/debug.c
@@ -0,0 +1,3509 @@
+/* debug.c -- Handle generic debugging information.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@cygnus.com>.
+
+ This file is part of GNU Binutils.
+
+ 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. */
+
+/* This file implements a generic debugging format. We may eventually
+ have readers which convert different formats into this generic
+ format, and writers which write it out. The initial impetus for
+ this was writing a convertor from stabs to HP IEEE-695 debugging
+ format. */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include <bfd.h>
+#include "bucomm.h"
+#include <libiberty.h>
+#include "debug.h"
+
+/* Global information we keep for debugging. A pointer to this
+ structure is the debugging handle passed to all the routines. */
+
+struct debug_handle
+{
+ /* A linked list of compilation units. */
+ struct debug_unit *units;
+ /* The current compilation unit. */
+ struct debug_unit *current_unit;
+ /* The current source file. */
+ struct debug_file *current_file;
+ /* The current function. */
+ struct debug_function *current_function;
+ /* The current block. */
+ struct debug_block *current_block;
+ /* The current line number information for the current unit. */
+ struct debug_lineno *current_lineno;
+ /* Mark. This is used by debug_write. */
+ unsigned int mark;
+ /* A struct/class ID used by debug_write. */
+ unsigned int class_id;
+ /* The base for class_id for this call to debug_write. */
+ unsigned int base_id;
+ /* The current line number in debug_write. */
+ struct debug_lineno *current_write_lineno;
+ unsigned int current_write_lineno_index;
+ /* A list of classes which have assigned ID's during debug_write.
+ This is linked through the next_id field of debug_class_type. */
+ struct debug_class_id *id_list;
+ /* A list used to avoid recursion during debug_type_samep. */
+ struct debug_type_compare_list *compare_list;
+};
+
+/* Information we keep for a single compilation unit. */
+
+struct debug_unit
+{
+ /* The next compilation unit. */
+ struct debug_unit *next;
+ /* A list of files included in this compilation unit. The first
+ file is always the main one, and that is where the main file name
+ is stored. */
+ struct debug_file *files;
+ /* Line number information for this compilation unit. This is not
+ stored by function, because assembler code may have line number
+ information without function information. */
+ struct debug_lineno *linenos;
+};
+
+/* Information kept for a single source file. */
+
+struct debug_file
+{
+ /* The next source file in this compilation unit. */
+ struct debug_file *next;
+ /* The name of the source file. */
+ const char *filename;
+ /* Global functions, variables, types, etc. */
+ struct debug_namespace *globals;
+};
+
+/* A type. */
+
+struct debug_type
+{
+ /* Kind of type. */
+ enum debug_type_kind kind;
+ /* Size of type (0 if not known). */
+ unsigned int size;
+ /* Type which is a pointer to this type. */
+ debug_type pointer;
+ /* Tagged union with additional information about the type. */
+ union
+ {
+ /* DEBUG_KIND_INDIRECT. */
+ struct debug_indirect_type *kindirect;
+ /* DEBUG_KIND_INT. */
+ /* Whether the integer is unsigned. */
+ boolean kint;
+ /* DEBUG_KIND_STRUCT, DEBUG_KIND_UNION, DEBUG_KIND_CLASS,
+ DEBUG_KIND_UNION_CLASS. */
+ struct debug_class_type *kclass;
+ /* DEBUG_KIND_ENUM. */
+ struct debug_enum_type *kenum;
+ /* DEBUG_KIND_POINTER. */
+ struct debug_type *kpointer;
+ /* DEBUG_KIND_FUNCTION. */
+ struct debug_function_type *kfunction;
+ /* DEBUG_KIND_REFERENCE. */
+ struct debug_type *kreference;
+ /* DEBUG_KIND_RANGE. */
+ struct debug_range_type *krange;
+ /* DEBUG_KIND_ARRAY. */
+ struct debug_array_type *karray;
+ /* DEBUG_KIND_SET. */
+ struct debug_set_type *kset;
+ /* DEBUG_KIND_OFFSET. */
+ struct debug_offset_type *koffset;
+ /* DEBUG_KIND_METHOD. */
+ struct debug_method_type *kmethod;
+ /* DEBUG_KIND_CONST. */
+ struct debug_type *kconst;
+ /* DEBUG_KIND_VOLATILE. */
+ struct debug_type *kvolatile;
+ /* DEBUG_KIND_NAMED, DEBUG_KIND_TAGGED. */
+ struct debug_named_type *knamed;
+ } u;
+};
+
+/* Information kept for an indirect type. */
+
+struct debug_indirect_type
+{
+ /* Slot where the final type will appear. */
+ debug_type *slot;
+ /* Tag. */
+ const char *tag;
+};
+
+/* Information kept for a struct, union, or class. */
+
+struct debug_class_type
+{
+ /* NULL terminated array of fields. */
+ debug_field *fields;
+ /* A mark field which indicates whether the struct has already been
+ printed. */
+ unsigned int mark;
+ /* This is used to uniquely identify unnamed structs when printing. */
+ unsigned int id;
+ /* The remaining fields are only used for DEBUG_KIND_CLASS and
+ DEBUG_KIND_UNION_CLASS. */
+ /* NULL terminated array of base classes. */
+ debug_baseclass *baseclasses;
+ /* NULL terminated array of methods. */
+ debug_method *methods;
+ /* The type of the class providing the virtual function table for
+ this class. This may point to the type itself. */
+ debug_type vptrbase;
+};
+
+/* Information kept for an enum. */
+
+struct debug_enum_type
+{
+ /* NULL terminated array of names. */
+ const char **names;
+ /* Array of corresponding values. */
+ bfd_signed_vma *values;
+};
+
+/* Information kept for a function. FIXME: We should be able to
+ record the parameter types. */
+
+struct debug_function_type
+{
+ /* Return type. */
+ debug_type return_type;
+ /* NULL terminated array of argument types. */
+ debug_type *arg_types;
+ /* Whether the function takes a variable number of arguments. */
+ boolean varargs;
+};
+
+/* Information kept for a range. */
+
+struct debug_range_type
+{
+ /* Range base type. */
+ debug_type type;
+ /* Lower bound. */
+ bfd_signed_vma lower;
+ /* Upper bound. */
+ bfd_signed_vma upper;
+};
+
+/* Information kept for an array. */
+
+struct debug_array_type
+{
+ /* Element type. */
+ debug_type element_type;
+ /* Range type. */
+ debug_type range_type;
+ /* Lower bound. */
+ bfd_signed_vma lower;
+ /* Upper bound. */
+ bfd_signed_vma upper;
+ /* Whether this array is really a string. */
+ boolean stringp;
+};
+
+/* Information kept for a set. */
+
+struct debug_set_type
+{
+ /* Base type. */
+ debug_type type;
+ /* Whether this set is really a bitstring. */
+ boolean bitstringp;
+};
+
+/* Information kept for an offset type (a based pointer). */
+
+struct debug_offset_type
+{
+ /* The type the pointer is an offset from. */
+ debug_type base_type;
+ /* The type the pointer points to. */
+ debug_type target_type;
+};
+
+/* Information kept for a method type. */
+
+struct debug_method_type
+{
+ /* The return type. */
+ debug_type return_type;
+ /* The object type which this method is for. */
+ debug_type domain_type;
+ /* A NULL terminated array of argument types. */
+ debug_type *arg_types;
+ /* Whether the method takes a variable number of arguments. */
+ boolean varargs;
+};
+
+/* Information kept for a named type. */
+
+struct debug_named_type
+{
+ /* Name. */
+ struct debug_name *name;
+ /* Real type. */
+ debug_type type;
+};
+
+/* A field in a struct or union. */
+
+struct debug_field
+{
+ /* Name of the field. */
+ const char *name;
+ /* Type of the field. */
+ struct debug_type *type;
+ /* Visibility of the field. */
+ enum debug_visibility visibility;
+ /* Whether this is a static member. */
+ boolean static_member;
+ union
+ {
+ /* If static_member is false. */
+ struct
+ {
+ /* Bit position of the field in the struct. */
+ unsigned int bitpos;
+ /* Size of the field in bits. */
+ unsigned int bitsize;
+ } f;
+ /* If static_member is true. */
+ struct
+ {
+ const char *physname;
+ } s;
+ } u;
+};
+
+/* A base class for an object. */
+
+struct debug_baseclass
+{
+ /* Type of the base class. */
+ struct debug_type *type;
+ /* Bit position of the base class in the object. */
+ unsigned int bitpos;
+ /* Whether the base class is virtual. */
+ boolean virtual;
+ /* Visibility of the base class. */
+ enum debug_visibility visibility;
+};
+
+/* A method of an object. */
+
+struct debug_method
+{
+ /* The name of the method. */
+ const char *name;
+ /* A NULL terminated array of different types of variants. */
+ struct debug_method_variant **variants;
+};
+
+/* The variants of a method function of an object. These indicate
+ which method to run. */
+
+struct debug_method_variant
+{
+ /* The physical name of the function. */
+ const char *physname;
+ /* The type of the function. */
+ struct debug_type *type;
+ /* The visibility of the function. */
+ enum debug_visibility visibility;
+ /* Whether the function is const. */
+ boolean constp;
+ /* Whether the function is volatile. */
+ boolean volatilep;
+ /* The offset to the function in the virtual function table. */
+ bfd_vma voffset;
+ /* If voffset is VOFFSET_STATIC_METHOD, this is a static method. */
+#define VOFFSET_STATIC_METHOD ((bfd_vma) -1)
+ /* Context of a virtual method function. */
+ struct debug_type *context;
+};
+
+/* A variable. This is the information we keep for a variable object.
+ This has no name; a name is associated with a variable in a
+ debug_name structure. */
+
+struct debug_variable
+{
+ /* Kind of variable. */
+ enum debug_var_kind kind;
+ /* Type. */
+ debug_type type;
+ /* Value. The interpretation of the value depends upon kind. */
+ bfd_vma val;
+};
+
+/* A function. This has no name; a name is associated with a function
+ in a debug_name structure. */
+
+struct debug_function
+{
+ /* Return type. */
+ debug_type return_type;
+ /* Parameter information. */
+ struct debug_parameter *parameters;
+ /* Block information. The first structure on the list is the main
+ block of the function, and describes function local variables. */
+ struct debug_block *blocks;
+};
+
+/* A function parameter. */
+
+struct debug_parameter
+{
+ /* Next parameter. */
+ struct debug_parameter *next;
+ /* Name. */
+ const char *name;
+ /* Type. */
+ debug_type type;
+ /* Kind. */
+ enum debug_parm_kind kind;
+ /* Value (meaning depends upon kind). */
+ bfd_vma val;
+};
+
+/* A typed constant. */
+
+struct debug_typed_constant
+{
+ /* Type. */
+ debug_type type;
+ /* Value. FIXME: We may eventually need to support non-integral
+ values. */
+ bfd_vma val;
+};
+
+/* Information about a block within a function. */
+
+struct debug_block
+{
+ /* Next block with the same parent. */
+ struct debug_block *next;
+ /* Parent block. */
+ struct debug_block *parent;
+ /* List of child blocks. */
+ struct debug_block *children;
+ /* Start address of the block. */
+ bfd_vma start;
+ /* End address of the block. */
+ bfd_vma end;
+ /* Local variables. */
+ struct debug_namespace *locals;
+};
+
+/* Line number information we keep for a compilation unit. FIXME:
+ This structure is easy to create, but can be very space
+ inefficient. */
+
+struct debug_lineno
+{
+ /* More line number information for this block. */
+ struct debug_lineno *next;
+ /* Source file. */
+ struct debug_file *file;
+ /* Line numbers, terminated by a -1 or the end of the array. */
+#define DEBUG_LINENO_COUNT 10
+ unsigned long linenos[DEBUG_LINENO_COUNT];
+ /* Addresses for the line numbers. */
+ bfd_vma addrs[DEBUG_LINENO_COUNT];
+};
+
+/* A namespace. This is a mapping from names to objects. FIXME: This
+ should be implemented as a hash table. */
+
+struct debug_namespace
+{
+ /* List of items in this namespace. */
+ struct debug_name *list;
+ /* Pointer to where the next item in this namespace should go. */
+ struct debug_name **tail;
+};
+
+/* Kinds of objects that appear in a namespace. */
+
+enum debug_object_kind
+{
+ /* A type. */
+ DEBUG_OBJECT_TYPE,
+ /* A tagged type (really a different sort of namespace). */
+ DEBUG_OBJECT_TAG,
+ /* A variable. */
+ DEBUG_OBJECT_VARIABLE,
+ /* A function. */
+ DEBUG_OBJECT_FUNCTION,
+ /* An integer constant. */
+ DEBUG_OBJECT_INT_CONSTANT,
+ /* A floating point constant. */
+ DEBUG_OBJECT_FLOAT_CONSTANT,
+ /* A typed constant. */
+ DEBUG_OBJECT_TYPED_CONSTANT
+};
+
+/* Linkage of an object that appears in a namespace. */
+
+enum debug_object_linkage
+{
+ /* Local variable. */
+ DEBUG_LINKAGE_AUTOMATIC,
+ /* Static--either file static or function static, depending upon the
+ namespace is. */
+ DEBUG_LINKAGE_STATIC,
+ /* Global. */
+ DEBUG_LINKAGE_GLOBAL,
+ /* No linkage. */
+ DEBUG_LINKAGE_NONE
+};
+
+/* A name in a namespace. */
+
+struct debug_name
+{
+ /* Next name in this namespace. */
+ struct debug_name *next;
+ /* Name. */
+ const char *name;
+ /* Mark. This is used by debug_write. */
+ unsigned int mark;
+ /* Kind of object. */
+ enum debug_object_kind kind;
+ /* Linkage of object. */
+ enum debug_object_linkage linkage;
+ /* Tagged union with additional information about the object. */
+ union
+ {
+ /* DEBUG_OBJECT_TYPE. */
+ struct debug_type *type;
+ /* DEBUG_OBJECT_TAG. */
+ struct debug_type *tag;
+ /* DEBUG_OBJECT_VARIABLE. */
+ struct debug_variable *variable;
+ /* DEBUG_OBJECT_FUNCTION. */
+ struct debug_function *function;
+ /* DEBUG_OBJECT_INT_CONSTANT. */
+ bfd_vma int_constant;
+ /* DEBUG_OBJECT_FLOAT_CONSTANT. */
+ double float_constant;
+ /* DEBUG_OBJECT_TYPED_CONSTANT. */
+ struct debug_typed_constant *typed_constant;
+ } u;
+};
+
+/* During debug_write, a linked list of these structures is used to
+ keep track of ID numbers that have been assigned to classes. */
+
+struct debug_class_id
+{
+ /* Next ID number. */
+ struct debug_class_id *next;
+ /* The type with the ID. */
+ struct debug_type *type;
+ /* The tag; NULL if no tag. */
+ const char *tag;
+};
+
+/* During debug_type_samep, a linked list of these structures is kept
+ on the stack to avoid infinite recursion. */
+
+struct debug_type_compare_list
+{
+ /* Next type on list. */
+ struct debug_type_compare_list *next;
+ /* The types we are comparing. */
+ struct debug_type *t1;
+ struct debug_type *t2;
+};
+
+/* Local functions. */
+
+static void debug_error PARAMS ((const char *));
+static struct debug_name *debug_add_to_namespace
+ PARAMS ((struct debug_handle *, struct debug_namespace **, const char *,
+ enum debug_object_kind, enum debug_object_linkage));
+static struct debug_name *debug_add_to_current_namespace
+ PARAMS ((struct debug_handle *, const char *, enum debug_object_kind,
+ enum debug_object_linkage));
+static struct debug_type *debug_make_type
+ PARAMS ((struct debug_handle *, enum debug_type_kind, unsigned int));
+static struct debug_type *debug_get_real_type PARAMS ((PTR, debug_type));
+static boolean debug_write_name
+ PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR,
+ struct debug_name *));
+static boolean debug_write_type
+ PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR,
+ struct debug_type *, struct debug_name *));
+static boolean debug_write_class_type
+ PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR,
+ struct debug_type *, const char *));
+static boolean debug_write_function
+ PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR,
+ const char *, enum debug_object_linkage, struct debug_function *));
+static boolean debug_write_block
+ PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR,
+ struct debug_block *));
+static boolean debug_write_linenos
+ PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR,
+ bfd_vma));
+static boolean debug_set_class_id
+ PARAMS ((struct debug_handle *, const char *, struct debug_type *));
+static boolean debug_type_samep
+ PARAMS ((struct debug_handle *, struct debug_type *, struct debug_type *));
+static boolean debug_class_type_samep
+ PARAMS ((struct debug_handle *, struct debug_type *, struct debug_type *));
+
+/* Issue an error message. */
+
+static void
+debug_error (message)
+ const char *message;
+{
+ fprintf (stderr, "%s\n", message);
+}
+
+/* Add an object to a namespace. */
+
+static struct debug_name *
+debug_add_to_namespace (info, nsp, name, kind, linkage)
+ struct debug_handle *info;
+ struct debug_namespace **nsp;
+ const char *name;
+ enum debug_object_kind kind;
+ enum debug_object_linkage linkage;
+{
+ struct debug_name *n;
+ struct debug_namespace *ns;
+
+ n = (struct debug_name *) xmalloc (sizeof *n);
+ memset (n, 0, sizeof *n);
+
+ n->name = name;
+ n->kind = kind;
+ n->linkage = linkage;
+
+ ns = *nsp;
+ if (ns == NULL)
+ {
+ ns = (struct debug_namespace *) xmalloc (sizeof *ns);
+ memset (ns, 0, sizeof *ns);
+
+ ns->tail = &ns->list;
+
+ *nsp = ns;
+ }
+
+ *ns->tail = n;
+ ns->tail = &n->next;
+
+ return n;
+}
+
+/* Add an object to the current namespace. */
+
+static struct debug_name *
+debug_add_to_current_namespace (info, name, kind, linkage)
+ struct debug_handle *info;
+ const char *name;
+ enum debug_object_kind kind;
+ enum debug_object_linkage linkage;
+{
+ struct debug_namespace **nsp;
+
+ if (info->current_unit == NULL
+ || info->current_file == NULL)
+ {
+ debug_error ("debug_add_to_current_namespace: no current file");
+ return NULL;
+ }
+
+ if (info->current_block != NULL)
+ nsp = &info->current_block->locals;
+ else
+ nsp = &info->current_file->globals;
+
+ return debug_add_to_namespace (info, nsp, name, kind, linkage);
+}
+
+/* Return a handle for debugging information. */
+
+PTR
+debug_init ()
+{
+ struct debug_handle *ret;
+
+ ret = (struct debug_handle *) xmalloc (sizeof *ret);
+ memset (ret, 0, sizeof *ret);
+ return (PTR) ret;
+}
+
+/* Set the source filename. This implicitly starts a new compilation
+ unit. */
+
+boolean
+debug_set_filename (handle, name)
+ PTR handle;
+ const char *name;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_file *nfile;
+ struct debug_unit *nunit;
+
+ if (name == NULL)
+ name = "";
+
+ nfile = (struct debug_file *) xmalloc (sizeof *nfile);
+ memset (nfile, 0, sizeof *nfile);
+
+ nfile->filename = name;
+
+ nunit = (struct debug_unit *) xmalloc (sizeof *nunit);
+ memset (nunit, 0, sizeof *nunit);
+
+ nunit->files = nfile;
+ info->current_file = nfile;
+
+ if (info->current_unit != NULL)
+ info->current_unit->next = nunit;
+ else
+ {
+ assert (info->units == NULL);
+ info->units = nunit;
+ }
+
+ info->current_unit = nunit;
+
+ info->current_function = NULL;
+ info->current_block = NULL;
+ info->current_lineno = NULL;
+
+ return true;
+}
+
+/* Change source files to the given file name. This is used for
+ include files in a single compilation unit. */
+
+boolean
+debug_start_source (handle, name)
+ PTR handle;
+ const char *name;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_file *f, **pf;
+
+ if (name == NULL)
+ name = "";
+
+ if (info->current_unit == NULL)
+ {
+ debug_error ("debug_start_source: no debug_set_filename call");
+ return false;
+ }
+
+ for (f = info->current_unit->files; f != NULL; f = f->next)
+ {
+ if (f->filename[0] == name[0]
+ && f->filename[1] == name[1]
+ && strcmp (f->filename, name) == 0)
+ {
+ info->current_file = f;
+ return true;
+ }
+ }
+
+ f = (struct debug_file *) xmalloc (sizeof *f);
+ memset (f, 0, sizeof *f);
+
+ f->filename = name;
+
+ for (pf = &info->current_file->next;
+ *pf != NULL;
+ pf = &(*pf)->next)
+ ;
+ *pf = f;
+
+ info->current_file = f;
+
+ return true;
+}
+
+/* Record a function definition. This implicitly starts a function
+ block. The debug_type argument is the type of the return value.
+ The boolean indicates whether the function is globally visible.
+ The bfd_vma is the address of the start of the function. Currently
+ the parameter types are specified by calls to
+ debug_record_parameter. FIXME: There is no way to specify nested
+ functions. */
+
+boolean
+debug_record_function (handle, name, return_type, global, addr)
+ PTR handle;
+ const char *name;
+ debug_type return_type;
+ boolean global;
+ bfd_vma addr;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_function *f;
+ struct debug_block *b;
+ struct debug_name *n;
+
+ if (name == NULL)
+ name = "";
+ if (return_type == NULL)
+ return false;
+
+ if (info->current_unit == NULL)
+ {
+ debug_error ("debug_record_function: no debug_set_filename call");
+ return false;
+ }
+
+ f = (struct debug_function *) xmalloc (sizeof *f);
+ memset (f, 0, sizeof *f);
+
+ f->return_type = return_type;
+
+ b = (struct debug_block *) xmalloc (sizeof *b);
+ memset (b, 0, sizeof *b);
+
+ b->start = addr;
+ b->end = (bfd_vma) -1;
+
+ f->blocks = b;
+
+ info->current_function = f;
+ info->current_block = b;
+
+ /* FIXME: If we could handle nested functions, this would be the
+ place: we would want to use a different namespace. */
+ n = debug_add_to_namespace (info,
+ &info->current_file->globals,
+ name,
+ DEBUG_OBJECT_FUNCTION,
+ (global
+ ? DEBUG_LINKAGE_GLOBAL
+ : DEBUG_LINKAGE_STATIC));
+ if (n == NULL)
+ return false;
+
+ n->u.function = f;
+
+ return true;
+}
+
+/* Record a parameter for the current function. */
+
+boolean
+debug_record_parameter (handle, name, type, kind, val)
+ PTR handle;
+ const char *name;
+ debug_type type;
+ enum debug_parm_kind kind;
+ bfd_vma val;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_parameter *p, **pp;
+
+ if (name == NULL || type == NULL)
+ return false;
+
+ if (info->current_unit == NULL
+ || info->current_function == NULL)
+ {
+ debug_error ("debug_record_parameter: no current function");
+ return false;
+ }
+
+ p = (struct debug_parameter *) xmalloc (sizeof *p);
+ memset (p, 0, sizeof *p);
+
+ p->name = name;
+ p->type = type;
+ p->kind = kind;
+ p->val = val;
+
+ for (pp = &info->current_function->parameters;
+ *pp != NULL;
+ pp = &(*pp)->next)
+ ;
+ *pp = p;
+
+ return true;
+}
+
+/* End a function. FIXME: This should handle function nesting. */
+
+boolean
+debug_end_function (handle, addr)
+ PTR handle;
+ bfd_vma addr;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+
+ if (info->current_unit == NULL
+ || info->current_block == NULL
+ || info->current_function == NULL)
+ {
+ debug_error ("debug_end_function: no current function");
+ return false;
+ }
+
+ if (info->current_block->parent != NULL)
+ {
+ debug_error ("debug_end_function: some blocks were not closed");
+ return false;
+ }
+
+ info->current_block->end = addr;
+
+ info->current_function = NULL;
+ info->current_block = NULL;
+
+ return true;
+}
+
+/* Start a block in a function. All local information will be
+ recorded in this block, until the matching call to debug_end_block.
+ debug_start_block and debug_end_block may be nested. The bfd_vma
+ argument is the address at which this block starts. */
+
+boolean
+debug_start_block (handle, addr)
+ PTR handle;
+ bfd_vma addr;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_block *b, **pb;
+
+ /* We must always have a current block: debug_record_function sets
+ one up. */
+ if (info->current_unit == NULL
+ || info->current_block == NULL)
+ {
+ debug_error ("debug_start_block: no current block");
+ return false;
+ }
+
+ b = (struct debug_block *) xmalloc (sizeof *b);
+ memset (b, 0, sizeof *b);
+
+ b->parent = info->current_block;
+ b->start = addr;
+ b->end = (bfd_vma) -1;
+
+ /* This new block is a child of the current block. */
+ for (pb = &info->current_block->children;
+ *pb != NULL;
+ pb = &(*pb)->next)
+ ;
+ *pb = b;
+
+ info->current_block = b;
+
+ return true;
+}
+
+/* Finish a block in a function. This matches the call to
+ debug_start_block. The argument is the address at which this block
+ ends. */
+
+boolean
+debug_end_block (handle, addr)
+ PTR handle;
+ bfd_vma addr;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_block *parent;
+
+ if (info->current_unit == NULL
+ || info->current_block == NULL)
+ {
+ debug_error ("debug_end_block: no current block");
+ return false;
+ }
+
+ parent = info->current_block->parent;
+ if (parent == NULL)
+ {
+ debug_error ("debug_end_block: attempt to close top level block");
+ return false;
+ }
+
+ info->current_block->end = addr;
+
+ info->current_block = parent;
+
+ return true;
+}
+
+/* Associate a line number in the current source file and function
+ with a given address. */
+
+boolean
+debug_record_line (handle, lineno, addr)
+ PTR handle;
+ unsigned long lineno;
+ bfd_vma addr;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_lineno *l;
+ unsigned int i;
+
+ if (info->current_unit == NULL)
+ {
+ debug_error ("debug_record_line: no current unit");
+ return false;
+ }
+
+ l = info->current_lineno;
+ if (l != NULL && l->file == info->current_file)
+ {
+ for (i = 0; i < DEBUG_LINENO_COUNT; i++)
+ {
+ if (l->linenos[i] == (unsigned long) -1)
+ {
+ l->linenos[i] = lineno;
+ l->addrs[i] = addr;
+ return true;
+ }
+ }
+ }
+
+ /* If we get here, then either 1) there is no current_lineno
+ structure, which means this is the first line number in this
+ compilation unit, 2) the current_lineno structure is for a
+ different file, or 3) the current_lineno structure is full.
+ Regardless, we want to allocate a new debug_lineno structure, put
+ it in the right place, and make it the new current_lineno
+ structure. */
+
+ l = (struct debug_lineno *) xmalloc (sizeof *l);
+ memset (l, 0, sizeof *l);
+
+ l->file = info->current_file;
+ l->linenos[0] = lineno;
+ l->addrs[0] = addr;
+ for (i = 1; i < DEBUG_LINENO_COUNT; i++)
+ l->linenos[i] = (unsigned long) -1;
+
+ if (info->current_lineno != NULL)
+ info->current_lineno->next = l;
+ else
+ info->current_unit->linenos = l;
+
+ info->current_lineno = l;
+
+ return true;
+}
+
+/* Start a named common block. This is a block of variables that may
+ move in memory. */
+
+boolean
+debug_start_common_block (handle, name)
+ PTR handle;
+ const char *name;
+{
+ /* FIXME */
+ debug_error ("debug_start_common_block: not implemented");
+ return false;
+}
+
+/* End a named common block. */
+
+boolean
+debug_end_common_block (handle, name)
+ PTR handle;
+ const char *name;
+{
+ /* FIXME */
+ debug_error ("debug_end_common_block: not implemented");
+ return false;
+}
+
+/* Record a named integer constant. */
+
+boolean
+debug_record_int_const (handle, name, val)
+ PTR handle;
+ const char *name;
+ bfd_vma val;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_name *n;
+
+ if (name == NULL)
+ return false;
+
+ n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_INT_CONSTANT,
+ DEBUG_LINKAGE_NONE);
+ if (n == NULL)
+ return false;
+
+ n->u.int_constant = val;
+
+ return true;
+}
+
+/* Record a named floating point constant. */
+
+boolean
+debug_record_float_const (handle, name, val)
+ PTR handle;
+ const char *name;
+ double val;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_name *n;
+
+ if (name == NULL)
+ return false;
+
+ n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_FLOAT_CONSTANT,
+ DEBUG_LINKAGE_NONE);
+ if (n == NULL)
+ return false;
+
+ n->u.float_constant = val;
+
+ return true;
+}
+
+/* Record a typed constant with an integral value. */
+
+boolean
+debug_record_typed_const (handle, name, type, val)
+ PTR handle;
+ const char *name;
+ debug_type type;
+ bfd_vma val;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_name *n;
+ struct debug_typed_constant *tc;
+
+ if (name == NULL || type == NULL)
+ return false;
+
+ n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_TYPED_CONSTANT,
+ DEBUG_LINKAGE_NONE);
+ if (n == NULL)
+ return false;
+
+ tc = (struct debug_typed_constant *) xmalloc (sizeof *tc);
+ memset (tc, 0, sizeof *tc);
+
+ tc->type = type;
+ tc->val = val;
+
+ n->u.typed_constant = tc;
+
+ return true;
+}
+
+/* Record a label. */
+
+boolean
+debug_record_label (handle, name, type, addr)
+ PTR handle;
+ const char *name;
+ debug_type type;
+ bfd_vma addr;
+{
+ /* FIXME. */
+ debug_error ("debug_record_label not implemented");
+ return false;
+}
+
+/* Record a variable. */
+
+boolean
+debug_record_variable (handle, name, type, kind, val)
+ PTR handle;
+ const char *name;
+ debug_type type;
+ enum debug_var_kind kind;
+ bfd_vma val;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_namespace **nsp;
+ enum debug_object_linkage linkage;
+ struct debug_name *n;
+ struct debug_variable *v;
+
+ if (name == NULL || type == NULL)
+ return false;
+
+ if (info->current_unit == NULL
+ || info->current_file == NULL)
+ {
+ debug_error ("debug_record_variable: no current file");
+ return false;
+ }
+
+ if (kind == DEBUG_GLOBAL || kind == DEBUG_STATIC)
+ {
+ nsp = &info->current_file->globals;
+ if (kind == DEBUG_GLOBAL)
+ linkage = DEBUG_LINKAGE_GLOBAL;
+ else
+ linkage = DEBUG_LINKAGE_STATIC;
+ }
+ else
+ {
+ if (info->current_block == NULL)
+ {
+ debug_error ("debug_record_variable: no current block");
+ return false;
+ }
+ nsp = &info->current_block->locals;
+ linkage = DEBUG_LINKAGE_AUTOMATIC;
+ }
+
+ n = debug_add_to_namespace (info, nsp, name, DEBUG_OBJECT_VARIABLE, linkage);
+ if (n == NULL)
+ return false;
+
+ v = (struct debug_variable *) xmalloc (sizeof *v);
+ memset (v, 0, sizeof *v);
+
+ v->kind = kind;
+ v->type = type;
+ v->val = val;
+
+ n->u.variable = v;
+
+ return true;
+}
+
+/* Make a type with a given kind and size. */
+
+/*ARGSUSED*/
+static struct debug_type *
+debug_make_type (info, kind, size)
+ struct debug_handle *info;
+ enum debug_type_kind kind;
+ unsigned int size;
+{
+ struct debug_type *t;
+
+ t = (struct debug_type *) xmalloc (sizeof *t);
+ memset (t, 0, sizeof *t);
+
+ t->kind = kind;
+ t->size = size;
+
+ return t;
+}
+
+/* Make an indirect type which may be used as a placeholder for a type
+ which is referenced before it is defined. */
+
+debug_type
+debug_make_indirect_type (handle, slot, tag)
+ PTR handle;
+ debug_type *slot;
+ const char *tag;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_indirect_type *i;
+
+ t = debug_make_type (info, DEBUG_KIND_INDIRECT, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ i = (struct debug_indirect_type *) xmalloc (sizeof *i);
+ memset (i, 0, sizeof *i);
+
+ i->slot = slot;
+ i->tag = tag;
+
+ t->u.kindirect = i;
+
+ return t;
+}
+
+/* Make a void type. There is only one of these. */
+
+debug_type
+debug_make_void_type (handle)
+ PTR handle;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+
+ return debug_make_type (info, DEBUG_KIND_VOID, 0);
+}
+
+/* Make an integer type of a given size. The boolean argument is true
+ if the integer is unsigned. */
+
+debug_type
+debug_make_int_type (handle, size, unsignedp)
+ PTR handle;
+ unsigned int size;
+ boolean unsignedp;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+
+ t = debug_make_type (info, DEBUG_KIND_INT, size);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t->u.kint = unsignedp;
+
+ return t;
+}
+
+/* Make a floating point type of a given size. FIXME: On some
+ platforms, like an Alpha, you probably need to be able to specify
+ the format. */
+
+debug_type
+debug_make_float_type (handle, size)
+ PTR handle;
+ unsigned int size;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+
+ return debug_make_type (info, DEBUG_KIND_FLOAT, size);
+}
+
+/* Make a boolean type of a given size. */
+
+debug_type
+debug_make_bool_type (handle, size)
+ PTR handle;
+ unsigned int size;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+
+ return debug_make_type (info, DEBUG_KIND_BOOL, size);
+}
+
+/* Make a complex type of a given size. */
+
+debug_type
+debug_make_complex_type (handle, size)
+ PTR handle;
+ unsigned int size;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+
+ return debug_make_type (info, DEBUG_KIND_COMPLEX, size);
+}
+
+/* Make a structure type. The second argument is true for a struct,
+ false for a union. The third argument is the size of the struct.
+ The fourth argument is a NULL terminated array of fields. */
+
+debug_type
+debug_make_struct_type (handle, structp, size, fields)
+ PTR handle;
+ boolean structp;
+ bfd_vma size;
+ debug_field *fields;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_class_type *c;
+
+ t = debug_make_type (info,
+ structp ? DEBUG_KIND_STRUCT : DEBUG_KIND_UNION,
+ size);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ c = (struct debug_class_type *) xmalloc (sizeof *c);
+ memset (c, 0, sizeof *c);
+
+ c->fields = fields;
+
+ t->u.kclass = c;
+
+ return t;
+}
+
+/* Make an object type. The first three arguments after the handle
+ are the same as for debug_make_struct_type. The next arguments are
+ a NULL terminated array of base classes, a NULL terminated array of
+ methods, the type of the object holding the virtual function table
+ if it is not this object, and a boolean which is true if this
+ object has its own virtual function table. */
+
+debug_type
+debug_make_object_type (handle, structp, size, fields, baseclasses,
+ methods, vptrbase, ownvptr)
+ PTR handle;
+ boolean structp;
+ bfd_vma size;
+ debug_field *fields;
+ debug_baseclass *baseclasses;
+ debug_method *methods;
+ debug_type vptrbase;
+ boolean ownvptr;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_class_type *c;
+
+ t = debug_make_type (info,
+ structp ? DEBUG_KIND_CLASS : DEBUG_KIND_UNION_CLASS,
+ size);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ c = (struct debug_class_type *) xmalloc (sizeof *c);
+ memset (c, 0, sizeof *c);
+
+ c->fields = fields;
+ c->baseclasses = baseclasses;
+ c->methods = methods;
+ if (ownvptr)
+ c->vptrbase = t;
+ else
+ c->vptrbase = vptrbase;
+
+ t->u.kclass = c;
+
+ return t;
+}
+
+/* Make an enumeration type. The arguments are a null terminated
+ array of strings, and an array of corresponding values. */
+
+debug_type
+debug_make_enum_type (handle, names, values)
+ PTR handle;
+ const char **names;
+ bfd_signed_vma *values;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_enum_type *e;
+
+ t = debug_make_type (info, DEBUG_KIND_ENUM, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ e = (struct debug_enum_type *) xmalloc (sizeof *e);
+ memset (e, 0, sizeof *e);
+
+ e->names = names;
+ e->values = values;
+
+ t->u.kenum = e;
+
+ return t;
+}
+
+/* Make a pointer to a given type. */
+
+debug_type
+debug_make_pointer_type (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+
+ if (type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ if (type->pointer != DEBUG_TYPE_NULL)
+ return type->pointer;
+
+ t = debug_make_type (info, DEBUG_KIND_POINTER, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t->u.kpointer = type;
+
+ type->pointer = t;
+
+ return t;
+}
+
+/* Make a function returning a given type. FIXME: We should be able
+ to record the parameter types. */
+
+debug_type
+debug_make_function_type (handle, type, arg_types, varargs)
+ PTR handle;
+ debug_type type;
+ debug_type *arg_types;
+ boolean varargs;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_function_type *f;
+
+ if (type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t = debug_make_type (info, DEBUG_KIND_FUNCTION, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ f = (struct debug_function_type *) xmalloc (sizeof *f);
+ memset (f, 0, sizeof *f);
+
+ f->return_type = type;
+ f->arg_types = arg_types;
+ f->varargs = varargs;
+
+ t->u.kfunction = f;
+
+ return t;
+}
+
+/* Make a reference to a given type. */
+
+debug_type
+debug_make_reference_type (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+
+ if (type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t = debug_make_type (info, DEBUG_KIND_REFERENCE, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t->u.kreference = type;
+
+ return t;
+}
+
+/* Make a range of a given type from a lower to an upper bound. */
+
+debug_type
+debug_make_range_type (handle, type, lower, upper)
+ PTR handle;
+ debug_type type;
+ bfd_signed_vma lower;
+ bfd_signed_vma upper;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_range_type *r;
+
+ if (type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t = debug_make_type (info, DEBUG_KIND_RANGE, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ r = (struct debug_range_type *) xmalloc (sizeof *r);
+ memset (r, 0, sizeof *r);
+
+ r->type = type;
+ r->lower = lower;
+ r->upper = upper;
+
+ t->u.krange = r;
+
+ return t;
+}
+
+/* Make an array type. The second argument is the type of an element
+ of the array. The third argument is the type of a range of the
+ array. The fourth and fifth argument are the lower and upper
+ bounds, respectively. The sixth argument is true if this array is
+ actually a string, as in C. */
+
+debug_type
+debug_make_array_type (handle, element_type, range_type, lower, upper,
+ stringp)
+ PTR handle;
+ debug_type element_type;
+ debug_type range_type;
+ bfd_signed_vma lower;
+ bfd_signed_vma upper;
+ boolean stringp;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_array_type *a;
+
+ if (element_type == NULL || range_type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t = debug_make_type (info, DEBUG_KIND_ARRAY, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ a = (struct debug_array_type *) xmalloc (sizeof *a);
+ memset (a, 0, sizeof *a);
+
+ a->element_type = element_type;
+ a->range_type = range_type;
+ a->lower = lower;
+ a->upper = upper;
+ a->stringp = stringp;
+
+ t->u.karray = a;
+
+ return t;
+}
+
+/* Make a set of a given type. For example, a Pascal set type. The
+ boolean argument is true if this set is actually a bitstring, as in
+ CHILL. */
+
+debug_type
+debug_make_set_type (handle, type, bitstringp)
+ PTR handle;
+ debug_type type;
+ boolean bitstringp;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_set_type *s;
+
+ if (type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t = debug_make_type (info, DEBUG_KIND_SET, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ s = (struct debug_set_type *) xmalloc (sizeof *s);
+ memset (s, 0, sizeof *s);
+
+ s->type = type;
+ s->bitstringp = bitstringp;
+
+ t->u.kset = s;
+
+ return t;
+}
+
+/* Make a type for a pointer which is relative to an object. The
+ second argument is the type of the object to which the pointer is
+ relative. The third argument is the type that the pointer points
+ to. */
+
+debug_type
+debug_make_offset_type (handle, base_type, target_type)
+ PTR handle;
+ debug_type base_type;
+ debug_type target_type;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_offset_type *o;
+
+ if (base_type == NULL || target_type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t = debug_make_type (info, DEBUG_KIND_OFFSET, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ o = (struct debug_offset_type *) xmalloc (sizeof *o);
+ memset (o, 0, sizeof *o);
+
+ o->base_type = base_type;
+ o->target_type = target_type;
+
+ t->u.koffset = o;
+
+ return t;
+}
+
+/* Make a type for a method function. The second argument is the
+ return type, the third argument is the domain, and the fourth
+ argument is a NULL terminated array of argument types. */
+
+debug_type
+debug_make_method_type (handle, return_type, domain_type, arg_types, varargs)
+ PTR handle;
+ debug_type return_type;
+ debug_type domain_type;
+ debug_type *arg_types;
+ boolean varargs;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_method_type *m;
+
+ if (return_type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t = debug_make_type (info, DEBUG_KIND_METHOD, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ m = (struct debug_method_type *) xmalloc (sizeof *m);
+ memset (m, 0, sizeof *m);
+
+ m->return_type = return_type;
+ m->domain_type = domain_type;
+ m->arg_types = arg_types;
+ m->varargs = varargs;
+
+ t->u.kmethod = m;
+
+ return t;
+}
+
+/* Make a const qualified version of a given type. */
+
+debug_type
+debug_make_const_type (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+
+ if (type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t = debug_make_type (info, DEBUG_KIND_CONST, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t->u.kconst = type;
+
+ return t;
+}
+
+/* Make a volatile qualified version of a given type. */
+
+debug_type
+debug_make_volatile_type (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+
+ if (type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t = debug_make_type (info, DEBUG_KIND_VOLATILE, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ t->u.kvolatile = type;
+
+ return t;
+}
+
+/* Make an undefined tagged type. For example, a struct which has
+ been mentioned, but not defined. */
+
+debug_type
+debug_make_undefined_tagged_type (handle, name, kind)
+ PTR handle;
+ const char *name;
+ enum debug_type_kind kind;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+
+ if (name == NULL)
+ return DEBUG_TYPE_NULL;
+
+ switch (kind)
+ {
+ case DEBUG_KIND_STRUCT:
+ case DEBUG_KIND_UNION:
+ case DEBUG_KIND_CLASS:
+ case DEBUG_KIND_UNION_CLASS:
+ case DEBUG_KIND_ENUM:
+ break;
+
+ default:
+ debug_error ("debug_make_undefined_type: unsupported kind");
+ return DEBUG_TYPE_NULL;
+ }
+
+ t = debug_make_type (info, kind, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ return debug_tag_type (handle, name, t);
+}
+
+/* Make a base class for an object. The second argument is the base
+ class type. The third argument is the bit position of this base
+ class in the object (always 0 unless doing multiple inheritance).
+ The fourth argument is whether this is a virtual class. The fifth
+ argument is the visibility of the base class. */
+
+/*ARGSUSED*/
+debug_baseclass
+debug_make_baseclass (handle, type, bitpos, virtual, visibility)
+ PTR handle;
+ debug_type type;
+ bfd_vma bitpos;
+ boolean virtual;
+ enum debug_visibility visibility;
+{
+ struct debug_baseclass *b;
+
+ b = (struct debug_baseclass *) xmalloc (sizeof *b);
+ memset (b, 0, sizeof *b);
+
+ b->type = type;
+ b->bitpos = bitpos;
+ b->virtual = virtual;
+ b->visibility = visibility;
+
+ return b;
+}
+
+/* Make a field for a struct. The second argument is the name. The
+ third argument is the type of the field. The fourth argument is
+ the bit position of the field. The fifth argument is the size of
+ the field (it may be zero). The sixth argument is the visibility
+ of the field. */
+
+/*ARGSUSED*/
+debug_field
+debug_make_field (handle, name, type, bitpos, bitsize, visibility)
+ PTR handle;
+ const char *name;
+ debug_type type;
+ bfd_vma bitpos;
+ bfd_vma bitsize;
+ enum debug_visibility visibility;
+{
+ struct debug_field *f;
+
+ f = (struct debug_field *) xmalloc (sizeof *f);
+ memset (f, 0, sizeof *f);
+
+ f->name = name;
+ f->type = type;
+ f->static_member = false;
+ f->u.f.bitpos = bitpos;
+ f->u.f.bitsize = bitsize;
+ f->visibility = visibility;
+
+ return f;
+}
+
+/* Make a static member of an object. The second argument is the
+ name. The third argument is the type of the member. The fourth
+ argument is the physical name of the member (i.e., the name as a
+ global variable). The fifth argument is the visibility of the
+ member. */
+
+/*ARGSUSED*/
+debug_field
+debug_make_static_member (handle, name, type, physname, visibility)
+ PTR handle;
+ const char *name;
+ debug_type type;
+ const char *physname;
+ enum debug_visibility visibility;
+{
+ struct debug_field *f;
+
+ f = (struct debug_field *) xmalloc (sizeof *f);
+ memset (f, 0, sizeof *f);
+
+ f->name = name;
+ f->type = type;
+ f->static_member = true;
+ f->u.s.physname = physname;
+ f->visibility = visibility;
+
+ return f;
+}
+
+/* Make a method. The second argument is the name, and the third
+ argument is a NULL terminated array of method variants. */
+
+/*ARGSUSED*/
+debug_method
+debug_make_method (handle, name, variants)
+ PTR handle;
+ const char *name;
+ debug_method_variant *variants;
+{
+ struct debug_method *m;
+
+ m = (struct debug_method *) xmalloc (sizeof *m);
+ memset (m, 0, sizeof *m);
+
+ m->name = name;
+ m->variants = variants;
+
+ return m;
+}
+
+/* Make a method argument. The second argument is the real name of
+ the function. The third argument is the type of the function. The
+ fourth argument is the visibility. The fifth argument is whether
+ this is a const function. The sixth argument is whether this is a
+ volatile function. The seventh argument is the offset in the
+ virtual function table, if any. The eighth argument is the virtual
+ function context. FIXME: Are the const and volatile arguments
+ necessary? Could we just use debug_make_const_type? */
+
+/*ARGSUSED*/
+debug_method_variant
+debug_make_method_variant (handle, physname, type, visibility, constp,
+ volatilep, voffset, context)
+ PTR handle;
+ const char *physname;
+ debug_type type;
+ enum debug_visibility visibility;
+ boolean constp;
+ boolean volatilep;
+ bfd_vma voffset;
+ debug_type context;
+{
+ struct debug_method_variant *m;
+
+ m = (struct debug_method_variant *) xmalloc (sizeof *m);
+ memset (m, 0, sizeof *m);
+
+ m->physname = physname;
+ m->type = type;
+ m->visibility = visibility;
+ m->constp = constp;
+ m->volatilep = volatilep;
+ m->voffset = voffset;
+ m->context = context;
+
+ return m;
+}
+
+/* Make a static method argument. The arguments are the same as for
+ debug_make_method_variant, except that the last two are omitted
+ since a static method can not also be virtual. */
+
+debug_method_variant
+debug_make_static_method_variant (handle, physname, type, visibility,
+ constp, volatilep)
+ PTR handle;
+ const char *physname;
+ debug_type type;
+ enum debug_visibility visibility;
+ boolean constp;
+ boolean volatilep;
+{
+ struct debug_method_variant *m;
+
+ m = (struct debug_method_variant *) xmalloc (sizeof *m);
+ memset (m, 0, sizeof *m);
+
+ m->physname = physname;
+ m->type = type;
+ m->visibility = visibility;
+ m->constp = constp;
+ m->volatilep = volatilep;
+ m->voffset = VOFFSET_STATIC_METHOD;
+
+ return m;
+}
+
+/* Name a type. */
+
+debug_type
+debug_name_type (handle, name, type)
+ PTR handle;
+ const char *name;
+ debug_type type;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_named_type *n;
+ struct debug_name *nm;
+
+ if (name == NULL || type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ if (info->current_unit == NULL
+ || info->current_file == NULL)
+ {
+ debug_error ("debug_name_type: no current file");
+ return DEBUG_TYPE_NULL;
+ /* return false; */
+ }
+
+ t = debug_make_type (info, DEBUG_KIND_NAMED, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ n = (struct debug_named_type *) xmalloc (sizeof *n);
+ memset (n, 0, sizeof *n);
+
+ n->type = type;
+
+ t->u.knamed = n;
+
+ /* We always add the name to the global namespace. This is probably
+ wrong in some cases, but it seems to be right for stabs. FIXME. */
+
+ nm = debug_add_to_namespace (info, &info->current_file->globals, name,
+ DEBUG_OBJECT_TYPE, DEBUG_LINKAGE_NONE);
+ if (nm == NULL)
+ return DEBUG_TYPE_NULL;
+
+ nm->u.type = t;
+
+ n->name = nm;
+
+ return t;
+}
+
+/* Tag a type. */
+
+debug_type
+debug_tag_type (handle, name, type)
+ PTR handle;
+ const char *name;
+ debug_type type;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_type *t;
+ struct debug_named_type *n;
+ struct debug_name *nm;
+
+ if (name == NULL || type == NULL)
+ return DEBUG_TYPE_NULL;
+
+ if (info->current_file == NULL)
+ {
+ debug_error ("debug_tag_type: no current file");
+ return DEBUG_TYPE_NULL;
+ }
+
+ if (type->kind == DEBUG_KIND_TAGGED)
+ {
+ if (strcmp (type->u.knamed->name->name, name) == 0)
+ return type;
+ debug_error ("debug_tag_type: extra tag attempted");
+ return DEBUG_TYPE_NULL;
+ }
+
+ t = debug_make_type (info, DEBUG_KIND_TAGGED, 0);
+ if (t == NULL)
+ return DEBUG_TYPE_NULL;
+
+ n = (struct debug_named_type *) xmalloc (sizeof *n);
+ memset (n, 0, sizeof *n);
+
+ n->type = type;
+
+ t->u.knamed = n;
+
+ /* We keep a global namespace of tags for each compilation unit. I
+ don't know if that is the right thing to do. */
+
+ nm = debug_add_to_namespace (info, &info->current_file->globals, name,
+ DEBUG_OBJECT_TAG, DEBUG_LINKAGE_NONE);
+ if (nm == NULL)
+ return DEBUG_TYPE_NULL;
+
+ nm->u.tag = t;
+
+ n->name = nm;
+
+ return t;
+}
+
+/* Record the size of a given type. */
+
+/*ARGSUSED*/
+boolean
+debug_record_type_size (handle, type, size)
+ PTR handle;
+ debug_type type;
+ unsigned int size;
+{
+#if 0
+ if (type->size != 0 && type->size != size)
+ fprintf (stderr, "Warning: changing type size from %d to %d\n",
+ type->size, size);
+#endif
+
+ type->size = size;
+
+ return true;
+}
+
+/* Find a named type. */
+
+debug_type
+debug_find_named_type (handle, name)
+ PTR handle;
+ const char *name;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_block *b;
+ struct debug_file *f;
+
+ /* We only search the current compilation unit. I don't know if
+ this is right or not. */
+
+ if (info->current_unit == NULL)
+ {
+ debug_error ("debug_find_named_type: no current compilation unit");
+ return DEBUG_TYPE_NULL;
+ }
+
+ for (b = info->current_block; b != NULL; b = b->parent)
+ {
+ if (b->locals != NULL)
+ {
+ struct debug_name *n;
+
+ for (n = b->locals->list; n != NULL; n = n->next)
+ {
+ if (n->kind == DEBUG_OBJECT_TYPE
+ && n->name[0] == name[0]
+ && strcmp (n->name, name) == 0)
+ return n->u.type;
+ }
+ }
+ }
+
+ for (f = info->current_unit->files; f != NULL; f = f->next)
+ {
+ if (f->globals != NULL)
+ {
+ struct debug_name *n;
+
+ for (n = f->globals->list; n != NULL; n = n->next)
+ {
+ if (n->kind == DEBUG_OBJECT_TYPE
+ && n->name[0] == name[0]
+ && strcmp (n->name, name) == 0)
+ return n->u.type;
+ }
+ }
+ }
+
+ return DEBUG_TYPE_NULL;
+}
+
+/* Find a tagged type. */
+
+debug_type
+debug_find_tagged_type (handle, name, kind)
+ PTR handle;
+ const char *name;
+ enum debug_type_kind kind;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_unit *u;
+
+ /* We search the globals of all the compilation units. I don't know
+ if this is correct or not. It would be easy to change. */
+
+ for (u = info->units; u != NULL; u = u->next)
+ {
+ struct debug_file *f;
+
+ for (f = u->files; f != NULL; f = f->next)
+ {
+ struct debug_name *n;
+
+ if (f->globals != NULL)
+ {
+ for (n = f->globals->list; n != NULL; n = n->next)
+ {
+ if (n->kind == DEBUG_OBJECT_TAG
+ && (kind == DEBUG_KIND_ILLEGAL
+ || n->u.tag->kind == kind)
+ && n->name[0] == name[0]
+ && strcmp (n->name, name) == 0)
+ return n->u.tag;
+ }
+ }
+ }
+ }
+
+ return DEBUG_TYPE_NULL;
+}
+
+/* Get a base type. */
+
+static struct debug_type *
+debug_get_real_type (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ switch (type->kind)
+ {
+ default:
+ return type;
+ case DEBUG_KIND_INDIRECT:
+ if (*type->u.kindirect->slot != NULL)
+ return debug_get_real_type (handle, *type->u.kindirect->slot);
+ return type;
+ case DEBUG_KIND_NAMED:
+ case DEBUG_KIND_TAGGED:
+ return debug_get_real_type (handle, type->u.knamed->type);
+ }
+ /*NOTREACHED*/
+}
+
+/* Get the kind of a type. */
+
+enum debug_type_kind
+debug_get_type_kind (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ if (type == NULL)
+ return DEBUG_KIND_ILLEGAL;
+ type = debug_get_real_type (handle, type);
+ return type->kind;
+}
+
+/* Get the name of a type. */
+
+const char *
+debug_get_type_name (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ if (type->kind == DEBUG_KIND_INDIRECT)
+ {
+ if (*type->u.kindirect->slot != NULL)
+ return debug_get_type_name (handle, *type->u.kindirect->slot);
+ return type->u.kindirect->tag;
+ }
+ if (type->kind == DEBUG_KIND_NAMED
+ || type->kind == DEBUG_KIND_TAGGED)
+ return type->u.knamed->name->name;
+ return NULL;
+}
+
+/* Get the size of a type. */
+
+bfd_vma
+debug_get_type_size (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ if (type == NULL)
+ return 0;
+
+ /* We don't call debug_get_real_type, because somebody might have
+ called debug_record_type_size on a named or indirect type. */
+
+ if (type->size != 0)
+ return type->size;
+
+ switch (type->kind)
+ {
+ default:
+ return 0;
+ case DEBUG_KIND_INDIRECT:
+ if (*type->u.kindirect->slot != NULL)
+ return debug_get_type_size (handle, *type->u.kindirect->slot);
+ return 0;
+ case DEBUG_KIND_NAMED:
+ case DEBUG_KIND_TAGGED:
+ return debug_get_type_size (handle, type->u.knamed->type);
+ }
+ /*NOTREACHED*/
+}
+
+/* Get the return type of a function or method type. */
+
+debug_type
+debug_get_return_type (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ if (type == NULL)
+ return DEBUG_TYPE_NULL;
+ type = debug_get_real_type (handle, type);
+ switch (type->kind)
+ {
+ default:
+ return DEBUG_TYPE_NULL;
+ case DEBUG_KIND_FUNCTION:
+ return type->u.kfunction->return_type;
+ case DEBUG_KIND_METHOD:
+ return type->u.kmethod->return_type;
+ }
+ /*NOTREACHED*/
+}
+
+/* Get the parameter types of a function or method type (except that
+ we don't currently store the parameter types of a function). */
+
+const debug_type *
+debug_get_parameter_types (handle, type, pvarargs)
+ PTR handle;
+ debug_type type;
+ boolean *pvarargs;
+{
+ if (type == NULL)
+ return NULL;
+ type = debug_get_real_type (handle, type);
+ switch (type->kind)
+ {
+ default:
+ return NULL;
+ case DEBUG_KIND_FUNCTION:
+ *pvarargs = type->u.kfunction->varargs;
+ return type->u.kfunction->arg_types;
+ case DEBUG_KIND_METHOD:
+ *pvarargs = type->u.kmethod->varargs;
+ return type->u.kmethod->arg_types;
+ }
+ /*NOTREACHED*/
+}
+
+/* Get the target type of a type. */
+
+debug_type
+debug_get_target_type (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ if (type == NULL)
+ return NULL;
+ type = debug_get_real_type (handle, type);
+ switch (type->kind)
+ {
+ default:
+ return NULL;
+ case DEBUG_KIND_POINTER:
+ return type->u.kpointer;
+ case DEBUG_KIND_REFERENCE:
+ return type->u.kreference;
+ case DEBUG_KIND_CONST:
+ return type->u.kconst;
+ case DEBUG_KIND_VOLATILE:
+ return type->u.kvolatile;
+ }
+ /*NOTREACHED*/
+}
+
+/* Get the NULL terminated array of fields for a struct, union, or
+ class. */
+
+const debug_field *
+debug_get_fields (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ if (type == NULL)
+ return NULL;
+ type = debug_get_real_type (handle, type);
+ switch (type->kind)
+ {
+ default:
+ return NULL;
+ case DEBUG_KIND_STRUCT:
+ case DEBUG_KIND_UNION:
+ case DEBUG_KIND_CLASS:
+ case DEBUG_KIND_UNION_CLASS:
+ return type->u.kclass->fields;
+ }
+ /*NOTREACHED*/
+}
+
+/* Get the type of a field. */
+
+/*ARGSUSED*/
+debug_type
+debug_get_field_type (handle, field)
+ PTR handle;
+ debug_field field;
+{
+ if (field == NULL)
+ return NULL;
+ return field->type;
+}
+
+/* Get the name of a field. */
+
+/*ARGSUSED*/
+const char *
+debug_get_field_name (handle, field)
+ PTR handle;
+ debug_field field;
+{
+ if (field == NULL)
+ return NULL;
+ return field->name;
+}
+
+/* Get the bit position of a field. */
+
+/*ARGSUSED*/
+bfd_vma
+debug_get_field_bitpos (handle, field)
+ PTR handle;
+ debug_field field;
+{
+ if (field == NULL || field->static_member)
+ return (bfd_vma) -1;
+ return field->u.f.bitpos;
+}
+
+/* Get the bit size of a field. */
+
+/*ARGSUSED*/
+bfd_vma
+debug_get_field_bitsize (handle, field)
+ PTR handle;
+ debug_field field;
+{
+ if (field == NULL || field->static_member)
+ return (bfd_vma) -1;
+ return field->u.f.bitsize;
+}
+
+/* Get the visibility of a field. */
+
+/*ARGSUSED*/
+enum debug_visibility
+debug_get_field_visibility (handle, field)
+ PTR handle;
+ debug_field field;
+{
+ if (field == NULL)
+ return DEBUG_VISIBILITY_IGNORE;
+ return field->visibility;
+}
+
+/* Get the physical name of a field. */
+
+const char *
+debug_get_field_physname (handle, field)
+ PTR handle;
+ debug_field field;
+{
+ if (field == NULL || ! field->static_member)
+ return NULL;
+ return field->u.s.physname;
+}
+
+/* Write out the debugging information. This is given a handle to
+ debugging information, and a set of function pointers to call. */
+
+boolean
+debug_write (handle, fns, fhandle)
+ PTR handle;
+ const struct debug_write_fns *fns;
+ PTR fhandle;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_unit *u;
+
+ /* We use a mark to tell whether we have already written out a
+ particular name. We use an integer, so that we don't have to
+ clear the mark fields if we happen to write out the same
+ information more than once. */
+ ++info->mark;
+
+ /* The base_id field holds an ID value which will never be used, so
+ that we can tell whether we have assigned an ID during this call
+ to debug_write. */
+ info->base_id = info->class_id;
+
+ /* We keep a linked list of classes for which was have assigned ID's
+ during this call to debug_write. */
+ info->id_list = NULL;
+
+ for (u = info->units; u != NULL; u = u->next)
+ {
+ struct debug_file *f;
+ boolean first_file;
+
+ info->current_write_lineno = u->linenos;
+ info->current_write_lineno_index = 0;
+
+ if (! (*fns->start_compilation_unit) (fhandle, u->files->filename))
+ return false;
+
+ first_file = true;
+ for (f = u->files; f != NULL; f = f->next)
+ {
+ struct debug_name *n;
+
+ if (first_file)
+ first_file = false;
+ else
+ {
+ if (! (*fns->start_source) (fhandle, f->filename))
+ return false;
+ }
+
+ if (f->globals != NULL)
+ {
+ for (n = f->globals->list; n != NULL; n = n->next)
+ {
+ if (! debug_write_name (info, fns, fhandle, n))
+ return false;
+ }
+ }
+ }
+
+ /* Output any line number information which hasn't already been
+ handled. */
+ if (! debug_write_linenos (info, fns, fhandle, (bfd_vma) -1))
+ return false;
+ }
+
+ return true;
+}
+
+/* Write out an element in a namespace. */
+
+static boolean
+debug_write_name (info, fns, fhandle, n)
+ struct debug_handle *info;
+ const struct debug_write_fns *fns;
+ PTR fhandle;
+ struct debug_name *n;
+{
+ switch (n->kind)
+ {
+ case DEBUG_OBJECT_TYPE:
+ if (! debug_write_type (info, fns, fhandle, n->u.type, n)
+ || ! (*fns->typdef) (fhandle, n->name))
+ return false;
+ return true;
+ case DEBUG_OBJECT_TAG:
+ if (! debug_write_type (info, fns, fhandle, n->u.tag, n))
+ return false;
+ return (*fns->tag) (fhandle, n->name);
+ case DEBUG_OBJECT_VARIABLE:
+ if (! debug_write_type (info, fns, fhandle, n->u.variable->type,
+ (struct debug_name *) NULL))
+ return false;
+ return (*fns->variable) (fhandle, n->name, n->u.variable->kind,
+ n->u.variable->val);
+ case DEBUG_OBJECT_FUNCTION:
+ return debug_write_function (info, fns, fhandle, n->name,
+ n->linkage, n->u.function);
+ case DEBUG_OBJECT_INT_CONSTANT:
+ return (*fns->int_constant) (fhandle, n->name, n->u.int_constant);
+ case DEBUG_OBJECT_FLOAT_CONSTANT:
+ return (*fns->float_constant) (fhandle, n->name, n->u.float_constant);
+ case DEBUG_OBJECT_TYPED_CONSTANT:
+ if (! debug_write_type (info, fns, fhandle, n->u.typed_constant->type,
+ (struct debug_name *) NULL))
+ return false;
+ return (*fns->typed_constant) (fhandle, n->name,
+ n->u.typed_constant->val);
+ default:
+ abort ();
+ return false;
+ }
+ /*NOTREACHED*/
+}
+
+/* Write out a type. If the type is DEBUG_KIND_NAMED or
+ DEBUG_KIND_TAGGED, then the name argument is the name for which we
+ are about to call typedef or tag. If the type is anything else,
+ then the name argument is a tag from a DEBUG_KIND_TAGGED type which
+ points to this one. */
+
+static boolean
+debug_write_type (info, fns, fhandle, type, name)
+ struct debug_handle *info;
+ const struct debug_write_fns *fns;
+ PTR fhandle;
+ struct debug_type *type;
+ struct debug_name *name;
+{
+ unsigned int i;
+ int is;
+ const char *tag;
+
+ /* If we have a name for this type, just output it. We only output
+ typedef names after they have been defined. We output type tags
+ whenever we are not actually defining them. */
+ if ((type->kind == DEBUG_KIND_NAMED
+ || type->kind == DEBUG_KIND_TAGGED)
+ && (type->u.knamed->name->mark == info->mark
+ || (type->kind == DEBUG_KIND_TAGGED
+ && type->u.knamed->name != name)))
+ {
+ if (type->kind == DEBUG_KIND_NAMED)
+ return (*fns->typedef_type) (fhandle, type->u.knamed->name->name);
+ else
+ {
+ struct debug_type *real;
+ unsigned int id;
+
+ real = debug_get_real_type ((PTR) info, type);
+ id = 0;
+ if ((real->kind == DEBUG_KIND_STRUCT
+ || real->kind == DEBUG_KIND_UNION
+ || real->kind == DEBUG_KIND_CLASS
+ || real->kind == DEBUG_KIND_UNION_CLASS)
+ && real->u.kclass != NULL)
+ {
+ if (real->u.kclass->id <= info->base_id)
+ {
+ if (! debug_set_class_id (info,
+ type->u.knamed->name->name,
+ real))
+ return false;
+ }
+ id = real->u.kclass->id;
+ }
+
+ return (*fns->tag_type) (fhandle, type->u.knamed->name->name, id,
+ real->kind);
+ }
+ }
+
+ /* Mark the name after we have already looked for a known name, so
+ that we don't just define a type in terms of itself. We need to
+ mark the name here so that a struct containing a pointer to
+ itself will work. */
+ if (name != NULL)
+ name->mark = info->mark;
+
+ tag = NULL;
+ if (name != NULL
+ && type->kind != DEBUG_KIND_NAMED
+ && type->kind != DEBUG_KIND_TAGGED)
+ {
+ assert (name->kind == DEBUG_OBJECT_TAG);
+ tag = name->name;
+ }
+
+ switch (type->kind)
+ {
+ case DEBUG_KIND_ILLEGAL:
+ debug_error ("debug_write_type: illegal type encountered");
+ return false;
+ case DEBUG_KIND_INDIRECT:
+ if (*type->u.kindirect->slot == DEBUG_TYPE_NULL)
+ return (*fns->empty_type) (fhandle);
+ return debug_write_type (info, fns, fhandle, *type->u.kindirect->slot,
+ name);
+ case DEBUG_KIND_VOID:
+ return (*fns->void_type) (fhandle);
+ case DEBUG_KIND_INT:
+ return (*fns->int_type) (fhandle, type->size, type->u.kint);
+ case DEBUG_KIND_FLOAT:
+ return (*fns->float_type) (fhandle, type->size);
+ case DEBUG_KIND_COMPLEX:
+ return (*fns->complex_type) (fhandle, type->size);
+ case DEBUG_KIND_BOOL:
+ return (*fns->bool_type) (fhandle, type->size);
+ case DEBUG_KIND_STRUCT:
+ case DEBUG_KIND_UNION:
+ if (type->u.kclass != NULL)
+ {
+ if (type->u.kclass->id <= info->base_id)
+ {
+ if (! debug_set_class_id (info, tag, type))
+ return false;
+ }
+
+ if (info->mark == type->u.kclass->mark)
+ {
+ /* We are currently outputting this struct, or we have
+ already output it. I don't know if this can happen,
+ but it can happen for a class. */
+ assert (type->u.kclass->id > info->base_id);
+ return (*fns->tag_type) (fhandle, tag, type->u.kclass->id,
+ type->kind);
+ }
+ type->u.kclass->mark = info->mark;
+ }
+
+ if (! (*fns->start_struct_type) (fhandle, tag,
+ (type->u.kclass != NULL
+ ? type->u.kclass->id
+ : 0),
+ type->kind == DEBUG_KIND_STRUCT,
+ type->size))
+ return false;
+ if (type->u.kclass != NULL
+ && type->u.kclass->fields != NULL)
+ {
+ for (i = 0; type->u.kclass->fields[i] != NULL; i++)
+ {
+ struct debug_field *f;
+
+ f = type->u.kclass->fields[i];
+ if (! debug_write_type (info, fns, fhandle, f->type,
+ (struct debug_name *) NULL)
+ || ! (*fns->struct_field) (fhandle, f->name, f->u.f.bitpos,
+ f->u.f.bitsize, f->visibility))
+ return false;
+ }
+ }
+ return (*fns->end_struct_type) (fhandle);
+ case DEBUG_KIND_CLASS:
+ case DEBUG_KIND_UNION_CLASS:
+ return debug_write_class_type (info, fns, fhandle, type, tag);
+ case DEBUG_KIND_ENUM:
+ if (type->u.kenum == NULL)
+ return (*fns->enum_type) (fhandle, tag, (const char **) NULL,
+ (bfd_signed_vma *) NULL);
+ return (*fns->enum_type) (fhandle, tag, type->u.kenum->names,
+ type->u.kenum->values);
+ case DEBUG_KIND_POINTER:
+ if (! debug_write_type (info, fns, fhandle, type->u.kpointer,
+ (struct debug_name *) NULL))
+ return false;
+ return (*fns->pointer_type) (fhandle);
+ case DEBUG_KIND_FUNCTION:
+ if (! debug_write_type (info, fns, fhandle,
+ type->u.kfunction->return_type,
+ (struct debug_name *) NULL))
+ return false;
+ if (type->u.kfunction->arg_types == NULL)
+ is = -1;
+ else
+ {
+ for (is = 0; type->u.kfunction->arg_types[is] != NULL; is++)
+ if (! debug_write_type (info, fns, fhandle,
+ type->u.kfunction->arg_types[is],
+ (struct debug_name *) NULL))
+ return false;
+ }
+ return (*fns->function_type) (fhandle, is,
+ type->u.kfunction->varargs);
+ case DEBUG_KIND_REFERENCE:
+ if (! debug_write_type (info, fns, fhandle, type->u.kreference,
+ (struct debug_name *) NULL))
+ return false;
+ return (*fns->reference_type) (fhandle);
+ case DEBUG_KIND_RANGE:
+ if (! debug_write_type (info, fns, fhandle, type->u.krange->type,
+ (struct debug_name *) NULL))
+ return false;
+ return (*fns->range_type) (fhandle, type->u.krange->lower,
+ type->u.krange->upper);
+ case DEBUG_KIND_ARRAY:
+ if (! debug_write_type (info, fns, fhandle, type->u.karray->element_type,
+ (struct debug_name *) NULL)
+ || ! debug_write_type (info, fns, fhandle,
+ type->u.karray->range_type,
+ (struct debug_name *) NULL))
+ return false;
+ return (*fns->array_type) (fhandle, type->u.karray->lower,
+ type->u.karray->upper,
+ type->u.karray->stringp);
+ case DEBUG_KIND_SET:
+ if (! debug_write_type (info, fns, fhandle, type->u.kset->type,
+ (struct debug_name *) NULL))
+ return false;
+ return (*fns->set_type) (fhandle, type->u.kset->bitstringp);
+ case DEBUG_KIND_OFFSET:
+ if (! debug_write_type (info, fns, fhandle, type->u.koffset->base_type,
+ (struct debug_name *) NULL)
+ || ! debug_write_type (info, fns, fhandle,
+ type->u.koffset->target_type,
+ (struct debug_name *) NULL))
+ return false;
+ return (*fns->offset_type) (fhandle);
+ case DEBUG_KIND_METHOD:
+ if (! debug_write_type (info, fns, fhandle,
+ type->u.kmethod->return_type,
+ (struct debug_name *) NULL))
+ return false;
+ if (type->u.kmethod->arg_types == NULL)
+ is = -1;
+ else
+ {
+ for (is = 0; type->u.kmethod->arg_types[is] != NULL; is++)
+ if (! debug_write_type (info, fns, fhandle,
+ type->u.kmethod->arg_types[is],
+ (struct debug_name *) NULL))
+ return false;
+ }
+ if (type->u.kmethod->domain_type != NULL)
+ {
+ if (! debug_write_type (info, fns, fhandle,
+ type->u.kmethod->domain_type,
+ (struct debug_name *) NULL))
+ return false;
+ }
+ return (*fns->method_type) (fhandle,
+ type->u.kmethod->domain_type != NULL,
+ is,
+ type->u.kmethod->varargs);
+ case DEBUG_KIND_CONST:
+ if (! debug_write_type (info, fns, fhandle, type->u.kconst,
+ (struct debug_name *) NULL))
+ return false;
+ return (*fns->const_type) (fhandle);
+ case DEBUG_KIND_VOLATILE:
+ if (! debug_write_type (info, fns, fhandle, type->u.kvolatile,
+ (struct debug_name *) NULL))
+ return false;
+ return (*fns->volatile_type) (fhandle);
+ case DEBUG_KIND_NAMED:
+ return debug_write_type (info, fns, fhandle, type->u.knamed->type,
+ (struct debug_name *) NULL);
+ case DEBUG_KIND_TAGGED:
+ return debug_write_type (info, fns, fhandle, type->u.knamed->type,
+ type->u.knamed->name);
+ default:
+ abort ();
+ return false;
+ }
+}
+
+/* Write out a class type. */
+
+static boolean
+debug_write_class_type (info, fns, fhandle, type, tag)
+ struct debug_handle *info;
+ const struct debug_write_fns *fns;
+ PTR fhandle;
+ struct debug_type *type;
+ const char *tag;
+{
+ unsigned int i;
+ unsigned int id;
+ struct debug_type *vptrbase;
+
+ if (type->u.kclass == NULL)
+ {
+ id = 0;
+ vptrbase = NULL;
+ }
+ else
+ {
+ if (type->u.kclass->id <= info->base_id)
+ {
+ if (! debug_set_class_id (info, tag, type))
+ return false;
+ }
+
+ if (info->mark == type->u.kclass->mark)
+ {
+ /* We are currently outputting this class, or we have
+ already output it. This can happen when there are
+ methods for an anonymous class. */
+ assert (type->u.kclass->id > info->base_id);
+ return (*fns->tag_type) (fhandle, tag, type->u.kclass->id,
+ type->kind);
+ }
+ type->u.kclass->mark = info->mark;
+ id = type->u.kclass->id;
+
+ vptrbase = type->u.kclass->vptrbase;
+ if (vptrbase != NULL && vptrbase != type)
+ {
+ if (! debug_write_type (info, fns, fhandle, vptrbase,
+ (struct debug_name *) NULL))
+ return false;
+ }
+ }
+
+ if (! (*fns->start_class_type) (fhandle, tag, id,
+ type->kind == DEBUG_KIND_CLASS,
+ type->size,
+ vptrbase != NULL,
+ vptrbase == type))
+ return false;
+
+ if (type->u.kclass != NULL)
+ {
+ if (type->u.kclass->fields != NULL)
+ {
+ for (i = 0; type->u.kclass->fields[i] != NULL; i++)
+ {
+ struct debug_field *f;
+
+ f = type->u.kclass->fields[i];
+ if (! debug_write_type (info, fns, fhandle, f->type,
+ (struct debug_name *) NULL))
+ return false;
+ if (f->static_member)
+ {
+ if (! (*fns->class_static_member) (fhandle, f->name,
+ f->u.s.physname,
+ f->visibility))
+ return false;
+ }
+ else
+ {
+ if (! (*fns->struct_field) (fhandle, f->name, f->u.f.bitpos,
+ f->u.f.bitsize, f->visibility))
+ return false;
+ }
+ }
+ }
+
+ if (type->u.kclass->baseclasses != NULL)
+ {
+ for (i = 0; type->u.kclass->baseclasses[i] != NULL; i++)
+ {
+ struct debug_baseclass *b;
+
+ b = type->u.kclass->baseclasses[i];
+ if (! debug_write_type (info, fns, fhandle, b->type,
+ (struct debug_name *) NULL))
+ return false;
+ if (! (*fns->class_baseclass) (fhandle, b->bitpos, b->virtual,
+ b->visibility))
+ return false;
+ }
+ }
+
+ if (type->u.kclass->methods != NULL)
+ {
+ for (i = 0; type->u.kclass->methods[i] != NULL; i++)
+ {
+ struct debug_method *m;
+ unsigned int j;
+
+ m = type->u.kclass->methods[i];
+ if (! (*fns->class_start_method) (fhandle, m->name))
+ return false;
+ for (j = 0; m->variants[j] != NULL; j++)
+ {
+ struct debug_method_variant *v;
+
+ v = m->variants[j];
+ if (v->context != NULL)
+ {
+ if (! debug_write_type (info, fns, fhandle, v->context,
+ (struct debug_name *) NULL))
+ return false;
+ }
+ if (! debug_write_type (info, fns, fhandle, v->type,
+ (struct debug_name *) NULL))
+ return false;
+ if (v->voffset != VOFFSET_STATIC_METHOD)
+ {
+ if (! (*fns->class_method_variant) (fhandle, v->physname,
+ v->visibility,
+ v->constp,
+ v->volatilep,
+ v->voffset,
+ v->context != NULL))
+ return false;
+ }
+ else
+ {
+ if (! (*fns->class_static_method_variant) (fhandle,
+ v->physname,
+ v->visibility,
+ v->constp,
+ v->volatilep))
+ return false;
+ }
+ }
+ if (! (*fns->class_end_method) (fhandle))
+ return false;
+ }
+ }
+ }
+
+ return (*fns->end_class_type) (fhandle);
+}
+
+/* Write out information for a function. */
+
+static boolean
+debug_write_function (info, fns, fhandle, name, linkage, function)
+ struct debug_handle *info;
+ const struct debug_write_fns *fns;
+ PTR fhandle;
+ const char *name;
+ enum debug_object_linkage linkage;
+ struct debug_function *function;
+{
+ struct debug_parameter *p;
+ struct debug_block *b;
+
+ if (! debug_write_linenos (info, fns, fhandle, function->blocks->start))
+ return false;
+
+ if (! debug_write_type (info, fns, fhandle, function->return_type,
+ (struct debug_name *) NULL))
+ return false;
+
+ if (! (*fns->start_function) (fhandle, name,
+ linkage == DEBUG_LINKAGE_GLOBAL))
+ return false;
+
+ for (p = function->parameters; p != NULL; p = p->next)
+ {
+ if (! debug_write_type (info, fns, fhandle, p->type,
+ (struct debug_name *) NULL)
+ || ! (*fns->function_parameter) (fhandle, p->name, p->kind, p->val))
+ return false;
+ }
+
+ for (b = function->blocks; b != NULL; b = b->next)
+ {
+ if (! debug_write_block (info, fns, fhandle, b))
+ return false;
+ }
+
+ return (*fns->end_function) (fhandle);
+}
+
+/* Write out information for a block. */
+
+static boolean
+debug_write_block (info, fns, fhandle, block)
+ struct debug_handle *info;
+ const struct debug_write_fns *fns;
+ PTR fhandle;
+ struct debug_block *block;
+{
+ struct debug_name *n;
+ struct debug_block *b;
+
+ if (! debug_write_linenos (info, fns, fhandle, block->start))
+ return false;
+
+ /* I can't see any point to writing out a block with no local
+ variables, so we don't bother, except for the top level block. */
+ if (block->locals != NULL || block->parent == NULL)
+ {
+ if (! (*fns->start_block) (fhandle, block->start))
+ return false;
+ }
+
+ if (block->locals != NULL)
+ {
+ for (n = block->locals->list; n != NULL; n = n->next)
+ {
+ if (! debug_write_name (info, fns, fhandle, n))
+ return false;
+ }
+ }
+
+ for (b = block->children; b != NULL; b = b->next)
+ {
+ if (! debug_write_block (info, fns, fhandle, b))
+ return false;
+ }
+
+ if (! debug_write_linenos (info, fns, fhandle, block->end))
+ return false;
+
+ if (block->locals != NULL || block->parent == NULL)
+ {
+ if (! (*fns->end_block) (fhandle, block->end))
+ return false;
+ }
+
+ return true;
+}
+
+/* Write out line number information up to ADDRESS. */
+
+static boolean
+debug_write_linenos (info, fns, fhandle, address)
+ struct debug_handle *info;
+ const struct debug_write_fns *fns;
+ PTR fhandle;
+ bfd_vma address;
+{
+ while (info->current_write_lineno != NULL)
+ {
+ struct debug_lineno *l;
+
+ l = info->current_write_lineno;
+
+ while (info->current_write_lineno_index < DEBUG_LINENO_COUNT)
+ {
+ if (l->linenos[info->current_write_lineno_index]
+ == (unsigned long) -1)
+ break;
+
+ if (l->addrs[info->current_write_lineno_index] >= address)
+ return true;
+
+ if (! (*fns->lineno) (fhandle, l->file->filename,
+ l->linenos[info->current_write_lineno_index],
+ l->addrs[info->current_write_lineno_index]))
+ return false;
+
+ ++info->current_write_lineno_index;
+ }
+
+ info->current_write_lineno = l->next;
+ info->current_write_lineno_index = 0;
+ }
+
+ return true;
+}
+
+/* Get the ID number for a class. If during the same call to
+ debug_write we find a struct with the same definition with the same
+ name, we use the same ID. This type of things happens because the
+ same struct will be defined by multiple compilation units. */
+
+static boolean
+debug_set_class_id (info, tag, type)
+ struct debug_handle *info;
+ const char *tag;
+ struct debug_type *type;
+{
+ struct debug_class_type *c;
+ struct debug_class_id *l;
+
+ assert (type->kind == DEBUG_KIND_STRUCT
+ || type->kind == DEBUG_KIND_UNION
+ || type->kind == DEBUG_KIND_CLASS
+ || type->kind == DEBUG_KIND_UNION_CLASS);
+
+ c = type->u.kclass;
+
+ if (c->id > info->base_id)
+ return true;
+
+ for (l = info->id_list; l != NULL; l = l->next)
+ {
+ if (l->type->kind != type->kind)
+ continue;
+
+ if (tag == NULL)
+ {
+ if (l->tag != NULL)
+ continue;
+ }
+ else
+ {
+ if (l->tag == NULL
+ || l->tag[0] != tag[0]
+ || strcmp (l->tag, tag) != 0)
+ continue;
+ }
+
+ if (debug_type_samep (info, l->type, type))
+ {
+ c->id = l->type->u.kclass->id;
+ return true;
+ }
+ }
+
+ /* There are no identical types. Use a new ID, and add it to the
+ list. */
+ ++info->class_id;
+ c->id = info->class_id;
+
+ l = (struct debug_class_id *) xmalloc (sizeof *l);
+ memset (l, 0, sizeof *l);
+
+ l->type = type;
+ l->tag = tag;
+
+ l->next = info->id_list;
+ info->id_list = l;
+
+ return true;
+}
+
+/* See if two types are the same. At this point, we don't care about
+ tags and the like. */
+
+static boolean
+debug_type_samep (info, t1, t2)
+ struct debug_handle *info;
+ struct debug_type *t1;
+ struct debug_type *t2;
+{
+ struct debug_type_compare_list *l;
+ struct debug_type_compare_list top;
+ boolean ret;
+
+ if (t1 == NULL)
+ return t2 == NULL;
+ if (t2 == NULL)
+ return false;
+
+ while (t1->kind == DEBUG_KIND_INDIRECT)
+ {
+ t1 = *t1->u.kindirect->slot;
+ if (t1 == NULL)
+ return false;
+ }
+ while (t2->kind == DEBUG_KIND_INDIRECT)
+ {
+ t2 = *t2->u.kindirect->slot;
+ if (t2 == NULL)
+ return false;
+ }
+
+ if (t1 == t2)
+ return true;
+
+ /* As a special case, permit a typedef to match a tag, since C++
+ debugging output will sometimes add a typedef where C debugging
+ output will not. */
+ if (t1->kind == DEBUG_KIND_NAMED
+ && t2->kind == DEBUG_KIND_TAGGED)
+ return debug_type_samep (info, t1->u.knamed->type, t2);
+ else if (t1->kind == DEBUG_KIND_TAGGED
+ && t2->kind == DEBUG_KIND_NAMED)
+ return debug_type_samep (info, t1, t2->u.knamed->type);
+
+ if (t1->kind != t2->kind
+ || t1->size != t2->size)
+ return false;
+
+ /* Get rid of the trivial cases first. */
+ switch (t1->kind)
+ {
+ default:
+ break;
+ case DEBUG_KIND_VOID:
+ case DEBUG_KIND_FLOAT:
+ case DEBUG_KIND_COMPLEX:
+ case DEBUG_KIND_BOOL:
+ return true;
+ case DEBUG_KIND_INT:
+ return t1->u.kint == t2->u.kint;
+ }
+
+ /* We have to avoid an infinite recursion. We do this by keeping a
+ list of types which we are comparing. We just keep the list on
+ the stack. If we encounter a pair of types we are currently
+ comparing, we just assume that they are equal. */
+ for (l = info->compare_list; l != NULL; l = l->next)
+ {
+ if (l->t1 == t1 && l->t2 == t2)
+ return true;
+ }
+
+ top.t1 = t1;
+ top.t2 = t2;
+ top.next = info->compare_list;
+ info->compare_list = &top;
+
+ switch (t1->kind)
+ {
+ default:
+ abort ();
+ ret = false;
+ break;
+
+ case DEBUG_KIND_STRUCT:
+ case DEBUG_KIND_UNION:
+ case DEBUG_KIND_CLASS:
+ case DEBUG_KIND_UNION_CLASS:
+ if (t1->u.kclass == NULL)
+ ret = t2->u.kclass == NULL;
+ else if (t2->u.kclass == NULL)
+ ret = false;
+ else if (t1->u.kclass->id > info->base_id
+ && t1->u.kclass->id == t2->u.kclass->id)
+ ret = true;
+ else
+ ret = debug_class_type_samep (info, t1, t2);
+ break;
+
+ case DEBUG_KIND_ENUM:
+ if (t1->u.kenum == NULL)
+ ret = t2->u.kenum == NULL;
+ else if (t2->u.kenum == NULL)
+ ret = false;
+ else
+ {
+ const char **pn1, **pn2;
+ bfd_signed_vma *pv1, *pv2;
+
+ pn1 = t1->u.kenum->names;
+ pn2 = t2->u.kenum->names;
+ pv1 = t1->u.kenum->values;
+ pv2 = t2->u.kenum->values;
+ while (*pn1 != NULL && *pn2 != NULL)
+ {
+ if (**pn1 != **pn2
+ || *pv1 != *pv2
+ || strcmp (*pn1, *pn2) != 0)
+ break;
+ ++pn1;
+ ++pn2;
+ ++pv1;
+ ++pv2;
+ }
+ ret = *pn1 == NULL && *pn2 == NULL;
+ }
+ break;
+
+ case DEBUG_KIND_POINTER:
+ ret = debug_type_samep (info, t1->u.kpointer, t2->u.kpointer);
+ break;
+
+ case DEBUG_KIND_FUNCTION:
+ if (t1->u.kfunction->varargs != t2->u.kfunction->varargs
+ || ! debug_type_samep (info, t1->u.kfunction->return_type,
+ t2->u.kfunction->return_type)
+ || ((t1->u.kfunction->arg_types == NULL)
+ != (t2->u.kfunction->arg_types == NULL)))
+ ret = false;
+ else if (t1->u.kfunction->arg_types == NULL)
+ ret = true;
+ else
+ {
+ struct debug_type **a1, **a2;
+
+ a1 = t1->u.kfunction->arg_types;
+ a2 = t2->u.kfunction->arg_types;
+ while (*a1 != NULL && *a2 != NULL)
+ if (! debug_type_samep (info, *a1, *a2))
+ break;
+ ret = *a1 == NULL && *a2 == NULL;
+ }
+ break;
+
+ case DEBUG_KIND_REFERENCE:
+ ret = debug_type_samep (info, t1->u.kreference, t2->u.kreference);
+ break;
+
+ case DEBUG_KIND_RANGE:
+ ret = (t1->u.krange->lower == t2->u.krange->lower
+ && t1->u.krange->upper == t2->u.krange->upper
+ && debug_type_samep (info, t1->u.krange->type,
+ t2->u.krange->type));
+
+ case DEBUG_KIND_ARRAY:
+ ret = (t1->u.karray->lower == t2->u.karray->lower
+ && t1->u.karray->upper == t2->u.karray->upper
+ && t1->u.karray->stringp == t2->u.karray->stringp
+ && debug_type_samep (info, t1->u.karray->element_type,
+ t2->u.karray->element_type));
+ break;
+
+ case DEBUG_KIND_SET:
+ ret = (t1->u.kset->bitstringp == t2->u.kset->bitstringp
+ && debug_type_samep (info, t1->u.kset->type, t2->u.kset->type));
+ break;
+
+ case DEBUG_KIND_OFFSET:
+ ret = (debug_type_samep (info, t1->u.koffset->base_type,
+ t2->u.koffset->base_type)
+ && debug_type_samep (info, t1->u.koffset->target_type,
+ t2->u.koffset->target_type));
+ break;
+
+ case DEBUG_KIND_METHOD:
+ if (t1->u.kmethod->varargs != t2->u.kmethod->varargs
+ || ! debug_type_samep (info, t1->u.kmethod->return_type,
+ t2->u.kmethod->return_type)
+ || ! debug_type_samep (info, t1->u.kmethod->domain_type,
+ t2->u.kmethod->domain_type)
+ || ((t1->u.kmethod->arg_types == NULL)
+ != (t2->u.kmethod->arg_types == NULL)))
+ ret = false;
+ else if (t1->u.kmethod->arg_types == NULL)
+ ret = true;
+ else
+ {
+ struct debug_type **a1, **a2;
+
+ a1 = t1->u.kmethod->arg_types;
+ a2 = t2->u.kmethod->arg_types;
+ while (*a1 != NULL && *a2 != NULL)
+ if (! debug_type_samep (info, *a1, *a2))
+ break;
+ ret = *a1 == NULL && *a2 == NULL;
+ }
+ break;
+
+ case DEBUG_KIND_CONST:
+ ret = debug_type_samep (info, t1->u.kconst, t2->u.kconst);
+ break;
+
+ case DEBUG_KIND_VOLATILE:
+ ret = debug_type_samep (info, t1->u.kvolatile, t2->u.kvolatile);
+ break;
+
+ case DEBUG_KIND_NAMED:
+ case DEBUG_KIND_TAGGED:
+ ret = (strcmp (t1->u.knamed->name->name, t2->u.knamed->name->name) == 0
+ && debug_type_samep (info, t1->u.knamed->type,
+ t2->u.knamed->type));
+ break;
+ }
+
+ info->compare_list = top.next;
+
+ return ret;
+}
+
+/* See if two classes are the same. This is a subroutine of
+ debug_type_samep. */
+
+static boolean
+debug_class_type_samep (info, t1, t2)
+ struct debug_handle *info;
+ struct debug_type *t1;
+ struct debug_type *t2;
+{
+ struct debug_class_type *c1, *c2;
+
+ c1 = t1->u.kclass;
+ c2 = t2->u.kclass;
+
+ if ((c1->fields == NULL) != (c2->fields == NULL)
+ || (c1->baseclasses == NULL) != (c2->baseclasses == NULL)
+ || (c1->methods == NULL) != (c2->methods == NULL)
+ || (c1->vptrbase == NULL) != (c2->vptrbase == NULL))
+ return false;
+
+ if (c1->fields != NULL)
+ {
+ struct debug_field **pf1, **pf2;
+
+ for (pf1 = c1->fields, pf2 = c2->fields;
+ *pf1 != NULL && *pf2 != NULL;
+ pf1++, pf2++)
+ {
+ struct debug_field *f1, *f2;
+
+ f1 = *pf1;
+ f2 = *pf2;
+ if (f1->name[0] != f2->name[0]
+ || f1->visibility != f2->visibility
+ || f1->static_member != f2->static_member)
+ return false;
+ if (f1->static_member)
+ {
+ if (strcmp (f1->u.s.physname, f2->u.s.physname) != 0)
+ return false;
+ }
+ else
+ {
+ if (f1->u.f.bitpos != f2->u.f.bitpos
+ || f1->u.f.bitsize != f2->u.f.bitsize)
+ return false;
+ }
+ /* We do the checks which require function calls last. We
+ don't require that the types of fields have the same
+ names, since that sometimes fails in the presence of
+ typedefs and we really don't care. */
+ if (strcmp (f1->name, f2->name) != 0
+ || ! debug_type_samep (info,
+ debug_get_real_type ((PTR) info,
+ f1->type),
+ debug_get_real_type ((PTR) info,
+ f2->type)))
+ return false;
+ }
+ if (*pf1 != NULL || *pf2 != NULL)
+ return false;
+ }
+
+ if (c1->vptrbase != NULL)
+ {
+ if (! debug_type_samep (info, c1->vptrbase, c2->vptrbase))
+ return false;
+ }
+
+ if (c1->baseclasses != NULL)
+ {
+ struct debug_baseclass **pb1, **pb2;
+
+ for (pb1 = c1->baseclasses, pb2 = c2->baseclasses;
+ *pb1 != NULL && *pb2 != NULL;
+ ++pb1, ++pb2)
+ {
+ struct debug_baseclass *b1, *b2;
+
+ b1 = *pb1;
+ b2 = *pb2;
+ if (b1->bitpos != b2->bitpos
+ || b1->virtual != b2->virtual
+ || b1->visibility != b2->visibility
+ || ! debug_type_samep (info, b1->type, b2->type))
+ return false;
+ }
+ if (*pb1 != NULL || *pb2 != NULL)
+ return false;
+ }
+
+ if (c1->methods != NULL)
+ {
+ struct debug_method **pm1, **pm2;
+
+ for (pm1 = c1->methods, pm2 = c2->methods;
+ *pm1 != NULL && *pm2 != NULL;
+ ++pm1, ++pm2)
+ {
+ struct debug_method *m1, *m2;
+
+ m1 = *pm1;
+ m2 = *pm2;
+ if (m1->name[0] != m2->name[0]
+ || strcmp (m1->name, m2->name) != 0
+ || (m1->variants == NULL) != (m2->variants == NULL))
+ return false;
+ if (m1->variants == NULL)
+ {
+ struct debug_method_variant **pv1, **pv2;
+
+ for (pv1 = m1->variants, pv2 = m2->variants;
+ *pv1 != NULL && *pv2 != NULL;
+ ++pv1, ++pv2)
+ {
+ struct debug_method_variant *v1, *v2;
+
+ v1 = *pv1;
+ v2 = *pv2;
+ if (v1->physname[0] != v2->physname[0]
+ || v1->visibility != v2->visibility
+ || v1->constp != v2->constp
+ || v1->volatilep != v2->volatilep
+ || v1->voffset != v2->voffset
+ || (v1->context == NULL) != (v2->context == NULL)
+ || strcmp (v1->physname, v2->physname) != 0
+ || ! debug_type_samep (info, v1->type, v2->type))
+ return false;
+ if (v1->context != NULL)
+ {
+ if (! debug_type_samep (info, v1->context,
+ v2->context))
+ return false;
+ }
+ }
+ if (*pv1 != NULL || *pv2 != NULL)
+ return false;
+ }
+ }
+ if (*pm1 != NULL || *pm2 != NULL)
+ return false;
+ }
+
+ return true;
+}
diff --git a/pstack/debug.h b/pstack/debug.h
new file mode 100644
index 00000000000..1b890b234f1
--- /dev/null
+++ b/pstack/debug.h
@@ -0,0 +1,798 @@
+/* debug.h -- Describe generic debugging information.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@cygnus.com>.
+
+ This file is part of GNU Binutils.
+
+ 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. */
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+/* This header file describes a generic debugging information format.
+ We may eventually have readers which convert different formats into
+ this generic format, and writers which write it out. The initial
+ impetus for this was writing a convertor from stabs to HP IEEE-695
+ debugging format. */
+
+/* Different kinds of types. */
+
+enum debug_type_kind
+{
+ /* Not used. */
+ DEBUG_KIND_ILLEGAL,
+ /* Indirect via a pointer. */
+ DEBUG_KIND_INDIRECT,
+ /* Void. */
+ DEBUG_KIND_VOID,
+ /* Integer. */
+ DEBUG_KIND_INT,
+ /* Floating point. */
+ DEBUG_KIND_FLOAT,
+ /* Complex. */
+ DEBUG_KIND_COMPLEX,
+ /* Boolean. */
+ DEBUG_KIND_BOOL,
+ /* Struct. */
+ DEBUG_KIND_STRUCT,
+ /* Union. */
+ DEBUG_KIND_UNION,
+ /* Class. */
+ DEBUG_KIND_CLASS,
+ /* Union class (can this really happen?). */
+ DEBUG_KIND_UNION_CLASS,
+ /* Enumeration type. */
+ DEBUG_KIND_ENUM,
+ /* Pointer. */
+ DEBUG_KIND_POINTER,
+ /* Function. */
+ DEBUG_KIND_FUNCTION,
+ /* Reference. */
+ DEBUG_KIND_REFERENCE,
+ /* Range. */
+ DEBUG_KIND_RANGE,
+ /* Array. */
+ DEBUG_KIND_ARRAY,
+ /* Set. */
+ DEBUG_KIND_SET,
+ /* Based pointer. */
+ DEBUG_KIND_OFFSET,
+ /* Method. */
+ DEBUG_KIND_METHOD,
+ /* Const qualified type. */
+ DEBUG_KIND_CONST,
+ /* Volatile qualified type. */
+ DEBUG_KIND_VOLATILE,
+ /* Named type. */
+ DEBUG_KIND_NAMED,
+ /* Tagged type. */
+ DEBUG_KIND_TAGGED
+};
+
+/* Different kinds of variables. */
+
+enum debug_var_kind
+{
+ /* Not used. */
+ DEBUG_VAR_ILLEGAL,
+ /* A global variable. */
+ DEBUG_GLOBAL,
+ /* A static variable. */
+ DEBUG_STATIC,
+ /* A local static variable. */
+ DEBUG_LOCAL_STATIC,
+ /* A local variable. */
+ DEBUG_LOCAL,
+ /* A register variable. */
+ DEBUG_REGISTER
+};
+
+/* Different kinds of function parameters. */
+
+enum debug_parm_kind
+{
+ /* Not used. */
+ DEBUG_PARM_ILLEGAL,
+ /* A stack based parameter. */
+ DEBUG_PARM_STACK,
+ /* A register parameter. */
+ DEBUG_PARM_REG,
+ /* A stack based reference parameter. */
+ DEBUG_PARM_REFERENCE,
+ /* A register reference parameter. */
+ DEBUG_PARM_REF_REG
+};
+
+/* Different kinds of visibility. */
+
+enum debug_visibility
+{
+ /* A public field (e.g., a field in a C struct). */
+ DEBUG_VISIBILITY_PUBLIC,
+ /* A protected field. */
+ DEBUG_VISIBILITY_PROTECTED,
+ /* A private field. */
+ DEBUG_VISIBILITY_PRIVATE,
+ /* A field which should be ignored. */
+ DEBUG_VISIBILITY_IGNORE
+};
+
+/* A type. */
+
+typedef struct debug_type *debug_type;
+
+#define DEBUG_TYPE_NULL ((debug_type) NULL)
+
+/* A field in a struct or union. */
+
+typedef struct debug_field *debug_field;
+
+#define DEBUG_FIELD_NULL ((debug_field) NULL)
+
+/* A base class for an object. */
+
+typedef struct debug_baseclass *debug_baseclass;
+
+#define DEBUG_BASECLASS_NULL ((debug_baseclass) NULL)
+
+/* A method of an object. */
+
+typedef struct debug_method *debug_method;
+
+#define DEBUG_METHOD_NULL ((debug_method) NULL)
+
+/* The arguments to a method function of an object. These indicate
+ which method to run. */
+
+typedef struct debug_method_variant *debug_method_variant;
+
+#define DEBUG_METHOD_VARIANT_NULL ((debug_method_variant) NULL)
+
+/* This structure is passed to debug_write. It holds function
+ pointers that debug_write will call based on the accumulated
+ debugging information. */
+
+struct debug_write_fns
+{
+ /* This is called at the start of each new compilation unit with the
+ name of the main file in the new unit. */
+ boolean (*start_compilation_unit) PARAMS ((PTR, const char *));
+
+ /* This is called at the start of each source file within a
+ compilation unit, before outputting any global information for
+ that file. The argument is the name of the file. */
+ boolean (*start_source) PARAMS ((PTR, const char *));
+
+ /* Each writer must keep a stack of types. */
+
+ /* Push an empty type onto the type stack. This type can appear if
+ there is a reference to a type which is never defined. */
+ boolean (*empty_type) PARAMS ((PTR));
+
+ /* Push a void type onto the type stack. */
+ boolean (*void_type) PARAMS ((PTR));
+
+ /* Push an integer type onto the type stack, given the size and
+ whether it is unsigned. */
+ boolean (*int_type) PARAMS ((PTR, unsigned int, boolean));
+
+ /* Push a floating type onto the type stack, given the size. */
+ boolean (*float_type) PARAMS ((PTR, unsigned int));
+
+ /* Push a complex type onto the type stack, given the size. */
+ boolean (*complex_type) PARAMS ((PTR, unsigned int));
+
+ /* Push a boolean type onto the type stack, given the size. */
+ boolean (*bool_type) PARAMS ((PTR, unsigned int));
+
+ /* Push an enum type onto the type stack, given the tag, a NULL
+ terminated array of names and the associated values. If there is
+ no tag, the tag argument will be NULL. If this is an undefined
+ enum, the names and values arguments will be NULL. */
+ boolean (*enum_type) PARAMS ((PTR, const char *, const char **,
+ bfd_signed_vma *));
+
+ /* Pop the top type on the type stack, and push a pointer to that
+ type onto the type stack. */
+ boolean (*pointer_type) PARAMS ((PTR));
+
+ /* Push a function type onto the type stack. The second argument
+ indicates the number of argument types that have been pushed onto
+ the stack. If the number of argument types is passed as -1, then
+ the argument types of the function are unknown, and no types have
+ been pushed onto the stack. The third argument is true if the
+ function takes a variable number of arguments. The return type
+ of the function is pushed onto the type stack below the argument
+ types, if any. */
+ boolean (*function_type) PARAMS ((PTR, int, boolean));
+
+ /* Pop the top type on the type stack, and push a reference to that
+ type onto the type stack. */
+ boolean (*reference_type) PARAMS ((PTR));
+
+ /* Pop the top type on the type stack, and push a range of that type
+ with the given lower and upper bounds onto the type stack. */
+ boolean (*range_type) PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma));
+
+ /* Push an array type onto the type stack. The top type on the type
+ stack is the range, and the next type on the type stack is the
+ element type. These should be popped before the array type is
+ pushed. The arguments are the lower bound, the upper bound, and
+ whether the array is a string. */
+ boolean (*array_type) PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma,
+ boolean));
+
+ /* Pop the top type on the type stack, and push a set of that type
+ onto the type stack. The argument indicates whether this set is
+ a bitstring. */
+ boolean (*set_type) PARAMS ((PTR, boolean));
+
+ /* Push an offset type onto the type stack. The top type on the
+ type stack is the target type, and the next type on the type
+ stack is the base type. These should be popped before the offset
+ type is pushed. */
+ boolean (*offset_type) PARAMS ((PTR));
+
+ /* Push a method type onto the type stack. If the second argument
+ is true, the top type on the stack is the class to which the
+ method belongs; otherwise, the class must be determined by the
+ class to which the method is attached. The third argument is the
+ number of argument types; these are pushed onto the type stack in
+ reverse order (the first type popped is the last argument to the
+ method). A value of -1 for the third argument means that no
+ argument information is available. The fourth argument is true
+ if the function takes a variable number of arguments. The next
+ type on the type stack below the domain and the argument types is
+ the return type of the method. All these types must be popped,
+ and then the method type must be pushed. */
+ boolean (*method_type) PARAMS ((PTR, boolean, int, boolean));
+
+ /* Pop the top type off the type stack, and push a const qualified
+ version of that type onto the type stack. */
+ boolean (*const_type) PARAMS ((PTR));
+
+ /* Pop the top type off the type stack, and push a volatile
+ qualified version of that type onto the type stack. */
+ boolean (*volatile_type) PARAMS ((PTR));
+
+ /* Start building a struct. This is followed by calls to the
+ struct_field function, and finished by a call to the
+ end_struct_type function. The second argument is the tag; this
+ will be NULL if there isn't one. If the second argument is NULL,
+ the third argument is a constant identifying this struct for use
+ with tag_type. The fourth argument is true for a struct, false
+ for a union. The fifth argument is the size. If this is an
+ undefined struct or union, the size will be 0 and struct_field
+ will not be called before end_struct_type is called. */
+ boolean (*start_struct_type) PARAMS ((PTR, const char *, unsigned int,
+ boolean, unsigned int));
+
+ /* Add a field to the struct type currently being built. The type
+ of the field should be popped off the type stack. The arguments
+ are the name, the bit position, the bit size (may be zero if the
+ field is not packed), and the visibility. */
+ boolean (*struct_field) PARAMS ((PTR, const char *, bfd_vma, bfd_vma,
+ enum debug_visibility));
+
+ /* Finish building a struct, and push it onto the type stack. */
+ boolean (*end_struct_type) PARAMS ((PTR));
+
+ /* Start building a class. This is followed by calls to several
+ functions: struct_field, class_static_member, class_baseclass,
+ class_start_method, class_method_variant,
+ class_static_method_variant, and class_end_method. The class is
+ finished by a call to end_class_type. The first five arguments
+ are the same as for start_struct_type. The sixth argument is
+ true if there is a virtual function table; if there is, the
+ seventh argument is true if the virtual function table can be
+ found in the type itself, and is false if the type of the object
+ holding the virtual function table should be popped from the type
+ stack. */
+ boolean (*start_class_type) PARAMS ((PTR, const char *, unsigned int,
+ boolean, unsigned int, boolean,
+ boolean));
+
+ /* Add a static member to the class currently being built. The
+ arguments are the field name, the physical name, and the
+ visibility. The type must be popped off the type stack. */
+ boolean (*class_static_member) PARAMS ((PTR, const char *, const char *,
+ enum debug_visibility));
+
+ /* Add a baseclass to the class currently being built. The type of
+ the baseclass must be popped off the type stack. The arguments
+ are the bit position, whether the class is virtual, and the
+ visibility. */
+ boolean (*class_baseclass) PARAMS ((PTR, bfd_vma, boolean,
+ enum debug_visibility));
+
+ /* Start adding a method to the class currently being built. This
+ is followed by calls to class_method_variant and
+ class_static_method_variant to describe different variants of the
+ method which take different arguments. The method is finished
+ with a call to class_end_method. The argument is the method
+ name. */
+ boolean (*class_start_method) PARAMS ((PTR, const char *));
+
+ /* Describe a variant to the class method currently being built.
+ The type of the variant must be popped off the type stack. The
+ second argument is the physical name of the function. The
+ following arguments are the visibility, whether the variant is
+ const, whether the variant is volatile, the offset in the virtual
+ function table, and whether the context is on the type stack
+ (below the variant type). */
+ boolean (*class_method_variant) PARAMS ((PTR, const char *,
+ enum debug_visibility,
+ boolean, boolean,
+ bfd_vma, boolean));
+
+ /* Describe a static variant to the class method currently being
+ built. The arguments are the same as for class_method_variant,
+ except that the last two arguments are omitted. The type of the
+ variant must be popped off the type stack. */
+ boolean (*class_static_method_variant) PARAMS ((PTR, const char *,
+ enum debug_visibility,
+ boolean, boolean));
+
+ /* Finish describing a class method. */
+ boolean (*class_end_method) PARAMS ((PTR));
+
+ /* Finish describing a class, and push it onto the type stack. */
+ boolean (*end_class_type) PARAMS ((PTR));
+
+ /* Push a type on the stack which was given a name by an earlier
+ call to typdef. */
+ boolean (*typedef_type) PARAMS ((PTR, const char *));
+
+ /* Push a tagged type on the stack which was defined earlier. If
+ the second argument is not NULL, the type was defined by a call
+ to tag. If the second argument is NULL, the type was defined by
+ a call to start_struct_type or start_class_type with a tag of
+ NULL and the number of the third argument. Either way, the
+ fourth argument is the tag kind. Note that this may be called
+ for a struct (class) being defined, in between the call to
+ start_struct_type (start_class_type) and the call to
+ end_struct_type (end_class_type). */
+ boolean (*tag_type) PARAMS ((PTR, const char *, unsigned int,
+ enum debug_type_kind));
+
+ /* Pop the type stack, and typedef it to the given name. */
+ boolean (*typdef) PARAMS ((PTR, const char *));
+
+ /* Pop the type stack, and declare it as a tagged struct or union or
+ enum or whatever. The tag passed down here is redundant, since
+ was also passed when enum_type, start_struct_type, or
+ start_class_type was called. */
+ boolean (*tag) PARAMS ((PTR, const char *));
+
+ /* This is called to record a named integer constant. */
+ boolean (*int_constant) PARAMS ((PTR, const char *, bfd_vma));
+
+ /* This is called to record a named floating point constant. */
+ boolean (*float_constant) PARAMS ((PTR, const char *, double));
+
+ /* This is called to record a typed integer constant. The type is
+ popped off the type stack. */
+ boolean (*typed_constant) PARAMS ((PTR, const char *, bfd_vma));
+
+ /* This is called to record a variable. The type is popped off the
+ type stack. */
+ boolean (*variable) PARAMS ((PTR, const char *, enum debug_var_kind,
+ bfd_vma));
+
+ /* Start writing out a function. The return type must be popped off
+ the stack. The boolean is true if the function is global. This
+ is followed by calls to function_parameter, followed by block
+ information. */
+ boolean (*start_function) PARAMS ((PTR, const char *, boolean));
+
+ /* Record a function parameter for the current function. The type
+ must be popped off the stack. */
+ boolean (*function_parameter) PARAMS ((PTR, const char *,
+ enum debug_parm_kind, bfd_vma));
+
+ /* Start writing out a block. There is at least one top level block
+ per function. Blocks may be nested. The argument is the
+ starting address of the block. */
+ boolean (*start_block) PARAMS ((PTR, bfd_vma));
+
+ /* Finish writing out a block. The argument is the ending address
+ of the block. */
+ boolean (*end_block) PARAMS ((PTR, bfd_vma));
+
+ /* Finish writing out a function. */
+ boolean (*end_function) PARAMS ((PTR));
+
+ /* Record line number information for the current compilation unit. */
+ boolean (*lineno) PARAMS ((PTR, const char *, unsigned long, bfd_vma));
+};
+
+/* Exported functions. */
+
+/* The first argument to most of these functions is a handle. This
+ handle is returned by the debug_init function. The purpose of the
+ handle is to permit the debugging routines to not use static
+ variables, and hence to be reentrant. This would be useful for a
+ program which wanted to handle two executables simultaneously. */
+
+/* Return a debugging handle. */
+
+extern PTR debug_init PARAMS ((void));
+
+/* Set the source filename. This implicitly starts a new compilation
+ unit. */
+
+extern boolean debug_set_filename PARAMS ((PTR, const char *));
+
+/* Change source files to the given file name. This is used for
+ include files in a single compilation unit. */
+
+extern boolean debug_start_source PARAMS ((PTR, const char *));
+
+/* Record a function definition. This implicitly starts a function
+ block. The debug_type argument is the type of the return value.
+ The boolean indicates whether the function is globally visible.
+ The bfd_vma is the address of the start of the function. Currently
+ the parameter types are specified by calls to
+ debug_record_parameter. */
+
+extern boolean debug_record_function
+ PARAMS ((PTR, const char *, debug_type, boolean, bfd_vma));
+
+/* Record a parameter for the current function. */
+
+extern boolean debug_record_parameter
+ PARAMS ((PTR, const char *, debug_type, enum debug_parm_kind, bfd_vma));
+
+/* End a function definition. The argument is the address where the
+ function ends. */
+
+extern boolean debug_end_function PARAMS ((PTR, bfd_vma));
+
+/* Start a block in a function. All local information will be
+ recorded in this block, until the matching call to debug_end_block.
+ debug_start_block and debug_end_block may be nested. The argument
+ is the address at which this block starts. */
+
+extern boolean debug_start_block PARAMS ((PTR, bfd_vma));
+
+/* Finish a block in a function. This matches the call to
+ debug_start_block. The argument is the address at which this block
+ ends. */
+
+extern boolean debug_end_block PARAMS ((PTR, bfd_vma));
+
+/* Associate a line number in the current source file with a given
+ address. */
+
+extern boolean debug_record_line PARAMS ((PTR, unsigned long, bfd_vma));
+
+/* Start a named common block. This is a block of variables that may
+ move in memory. */
+
+extern boolean debug_start_common_block PARAMS ((PTR, const char *));
+
+/* End a named common block. */
+
+extern boolean debug_end_common_block PARAMS ((PTR, const char *));
+
+/* Record a named integer constant. */
+
+extern boolean debug_record_int_const PARAMS ((PTR, const char *, bfd_vma));
+
+/* Record a named floating point constant. */
+
+extern boolean debug_record_float_const PARAMS ((PTR, const char *, double));
+
+/* Record a typed constant with an integral value. */
+
+extern boolean debug_record_typed_const
+ PARAMS ((PTR, const char *, debug_type, bfd_vma));
+
+/* Record a label. */
+
+extern boolean debug_record_label
+ PARAMS ((PTR, const char *, debug_type, bfd_vma));
+
+/* Record a variable. */
+
+extern boolean debug_record_variable
+ PARAMS ((PTR, const char *, debug_type, enum debug_var_kind, bfd_vma));
+
+/* Make an indirect type. The first argument is a pointer to the
+ location where the real type will be placed. The second argument
+ is the type tag, if there is one; this may be NULL; the only
+ purpose of this argument is so that debug_get_type_name can return
+ something useful. This function may be used when a type is
+ referenced before it is defined. */
+
+extern debug_type debug_make_indirect_type
+ PARAMS ((PTR, debug_type *, const char *));
+
+/* Make a void type. */
+
+extern debug_type debug_make_void_type PARAMS ((PTR));
+
+/* Make an integer type of a given size. The boolean argument is true
+ if the integer is unsigned. */
+
+extern debug_type debug_make_int_type PARAMS ((PTR, unsigned int, boolean));
+
+/* Make a floating point type of a given size. FIXME: On some
+ platforms, like an Alpha, you probably need to be able to specify
+ the format. */
+
+extern debug_type debug_make_float_type PARAMS ((PTR, unsigned int));
+
+/* Make a boolean type of a given size. */
+
+extern debug_type debug_make_bool_type PARAMS ((PTR, unsigned int));
+
+/* Make a complex type of a given size. */
+
+extern debug_type debug_make_complex_type PARAMS ((PTR, unsigned int));
+
+/* Make a structure type. The second argument is true for a struct,
+ false for a union. The third argument is the size of the struct.
+ The fourth argument is a NULL terminated array of fields. */
+
+extern debug_type debug_make_struct_type
+ PARAMS ((PTR, boolean, bfd_vma, debug_field *));
+
+/* Make an object type. The first three arguments after the handle
+ are the same as for debug_make_struct_type. The next arguments are
+ a NULL terminated array of base classes, a NULL terminated array of
+ methods, the type of the object holding the virtual function table
+ if it is not this object, and a boolean which is true if this
+ object has its own virtual function table. */
+
+extern debug_type debug_make_object_type
+ PARAMS ((PTR, boolean, bfd_vma, debug_field *, debug_baseclass *,
+ debug_method *, debug_type, boolean));
+
+/* Make an enumeration type. The arguments are a null terminated
+ array of strings, and an array of corresponding values. */
+
+extern debug_type debug_make_enum_type
+ PARAMS ((PTR, const char **, bfd_signed_vma *));
+
+/* Make a pointer to a given type. */
+
+extern debug_type debug_make_pointer_type
+ PARAMS ((PTR, debug_type));
+
+/* Make a function type. The second argument is the return type. The
+ third argument is a NULL terminated array of argument types. The
+ fourth argument is true if the function takes a variable number of
+ arguments. If the third argument is NULL, then the argument types
+ are unknown. */
+
+extern debug_type debug_make_function_type
+ PARAMS ((PTR, debug_type, debug_type *, boolean));
+
+/* Make a reference to a given type. */
+
+extern debug_type debug_make_reference_type PARAMS ((PTR, debug_type));
+
+/* Make a range of a given type from a lower to an upper bound. */
+
+extern debug_type debug_make_range_type
+ PARAMS ((PTR, debug_type, bfd_signed_vma, bfd_signed_vma));
+
+/* Make an array type. The second argument is the type of an element
+ of the array. The third argument is the type of a range of the
+ array. The fourth and fifth argument are the lower and upper
+ bounds, respectively (if the bounds are not known, lower should be
+ 0 and upper should be -1). The sixth argument is true if this
+ array is actually a string, as in C. */
+
+extern debug_type debug_make_array_type
+ PARAMS ((PTR, debug_type, debug_type, bfd_signed_vma, bfd_signed_vma,
+ boolean));
+
+/* Make a set of a given type. For example, a Pascal set type. The
+ boolean argument is true if this set is actually a bitstring, as in
+ CHILL. */
+
+extern debug_type debug_make_set_type PARAMS ((PTR, debug_type, boolean));
+
+/* Make a type for a pointer which is relative to an object. The
+ second argument is the type of the object to which the pointer is
+ relative. The third argument is the type that the pointer points
+ to. */
+
+extern debug_type debug_make_offset_type
+ PARAMS ((PTR, debug_type, debug_type));
+
+/* Make a type for a method function. The second argument is the
+ return type. The third argument is the domain. The fourth
+ argument is a NULL terminated array of argument types. The fifth
+ argument is true if the function takes a variable number of
+ arguments, in which case the array of argument types indicates the
+ types of the first arguments. The domain and the argument array
+ may be NULL, in which case this is a stub method and that
+ information is not available. Stabs debugging uses this, and gets
+ the argument types from the mangled name. */
+
+extern debug_type debug_make_method_type
+ PARAMS ((PTR, debug_type, debug_type, debug_type *, boolean));
+
+/* Make a const qualified version of a given type. */
+
+extern debug_type debug_make_const_type PARAMS ((PTR, debug_type));
+
+/* Make a volatile qualified version of a given type. */
+
+extern debug_type debug_make_volatile_type PARAMS ((PTR, debug_type));
+
+/* Make an undefined tagged type. For example, a struct which has
+ been mentioned, but not defined. */
+
+extern debug_type debug_make_undefined_tagged_type
+ PARAMS ((PTR, const char *, enum debug_type_kind));
+
+/* Make a base class for an object. The second argument is the base
+ class type. The third argument is the bit position of this base
+ class in the object. The fourth argument is whether this is a
+ virtual class. The fifth argument is the visibility of the base
+ class. */
+
+extern debug_baseclass debug_make_baseclass
+ PARAMS ((PTR, debug_type, bfd_vma, boolean, enum debug_visibility));
+
+/* Make a field for a struct. The second argument is the name. The
+ third argument is the type of the field. The fourth argument is
+ the bit position of the field. The fifth argument is the size of
+ the field (it may be zero). The sixth argument is the visibility
+ of the field. */
+
+extern debug_field debug_make_field
+ PARAMS ((PTR, const char *, debug_type, bfd_vma, bfd_vma,
+ enum debug_visibility));
+
+/* Make a static member of an object. The second argument is the
+ name. The third argument is the type of the member. The fourth
+ argument is the physical name of the member (i.e., the name as a
+ global variable). The fifth argument is the visibility of the
+ member. */
+
+extern debug_field debug_make_static_member
+ PARAMS ((PTR, const char *, debug_type, const char *,
+ enum debug_visibility));
+
+/* Make a method. The second argument is the name, and the third
+ argument is a NULL terminated array of method variants. Each
+ method variant is a method with this name but with different
+ argument types. */
+
+extern debug_method debug_make_method
+ PARAMS ((PTR, const char *, debug_method_variant *));
+
+/* Make a method variant. The second argument is the physical name of
+ the function. The third argument is the type of the function,
+ probably constructed by debug_make_method_type. The fourth
+ argument is the visibility. The fifth argument is whether this is
+ a const function. The sixth argument is whether this is a volatile
+ function. The seventh argument is the index in the virtual
+ function table, if any. The eighth argument is the virtual
+ function context. */
+
+extern debug_method_variant debug_make_method_variant
+ PARAMS ((PTR, const char *, debug_type, enum debug_visibility, boolean,
+ boolean, bfd_vma, debug_type));
+
+/* Make a static method argument. The arguments are the same as for
+ debug_make_method_variant, except that the last two are omitted
+ since a static method can not also be virtual. */
+
+extern debug_method_variant debug_make_static_method_variant
+ PARAMS ((PTR, const char *, debug_type, enum debug_visibility, boolean,
+ boolean));
+
+/* Name a type. This returns a new type with an attached name. */
+
+extern debug_type debug_name_type PARAMS ((PTR, const char *, debug_type));
+
+/* Give a tag to a type, such as a struct or union. This returns a
+ new type with an attached tag. */
+
+extern debug_type debug_tag_type PARAMS ((PTR, const char *, debug_type));
+
+/* Record the size of a given type. */
+
+extern boolean debug_record_type_size PARAMS ((PTR, debug_type, unsigned int));
+
+/* Find a named type. */
+
+extern debug_type debug_find_named_type PARAMS ((PTR, const char *));
+
+/* Find a tagged type. */
+
+extern debug_type debug_find_tagged_type
+ PARAMS ((PTR, const char *, enum debug_type_kind));
+
+/* Get the kind of a type. */
+
+extern enum debug_type_kind debug_get_type_kind PARAMS ((PTR, debug_type));
+
+/* Get the name of a type. */
+
+extern const char *debug_get_type_name PARAMS ((PTR, debug_type));
+
+/* Get the size of a type. */
+
+extern bfd_vma debug_get_type_size PARAMS ((PTR, debug_type));
+
+/* Get the return type of a function or method type. */
+
+extern debug_type debug_get_return_type PARAMS ((PTR, debug_type));
+
+/* Get the NULL terminated array of parameter types for a function or
+ method type (actually, parameter types are not currently stored for
+ function types). This may be used to determine whether a method
+ type is a stub method or not. The last argument points to a
+ boolean which is set to true if the function takes a variable
+ number of arguments. */
+
+extern const debug_type *debug_get_parameter_types PARAMS ((PTR,
+ debug_type,
+ boolean *));
+
+/* Get the target type of a pointer or reference or const or volatile
+ type. */
+
+extern debug_type debug_get_target_type PARAMS ((PTR, debug_type));
+
+/* Get the NULL terminated array of fields for a struct, union, or
+ class. */
+
+extern const debug_field *debug_get_fields PARAMS ((PTR, debug_type));
+
+/* Get the type of a field. */
+
+extern debug_type debug_get_field_type PARAMS ((PTR, debug_field));
+
+/* Get the name of a field. */
+
+extern const char *debug_get_field_name PARAMS ((PTR, debug_field));
+
+/* Get the bit position of a field within the containing structure.
+ If the field is a static member, this will return (bfd_vma) -1. */
+
+extern bfd_vma debug_get_field_bitpos PARAMS ((PTR, debug_field));
+
+/* Get the bit size of a field. If the field is a static member, this
+ will return (bfd_vma) -1. */
+
+extern bfd_vma debug_get_field_bitsize PARAMS ((PTR, debug_field));
+
+/* Get the visibility of a field. */
+
+extern enum debug_visibility debug_get_field_visibility
+ PARAMS ((PTR, debug_field));
+
+/* Get the physical name of a field, if it is a static member. If the
+ field is not a static member, this will return NULL. */
+
+extern const char *debug_get_field_physname PARAMS ((PTR, debug_field));
+
+/* Write out the recorded debugging information. This takes a set of
+ function pointers which are called to do the actual writing. The
+ first PTR is the debugging handle. The second PTR is a handle
+ which is passed to the functions. */
+
+extern boolean debug_write PARAMS ((PTR, const struct debug_write_fns *, PTR));
+
+#endif /* DEBUG_H */
diff --git a/pstack/demangle.h b/pstack/demangle.h
new file mode 100644
index 00000000000..00f6a0c3bc0
--- /dev/null
+++ b/pstack/demangle.h
@@ -0,0 +1,90 @@
+/* Defs for interface to demanglers.
+ Copyright 1992, 1995, 1996 Free Software Foundation, Inc.
+
+ 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, 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. */
+
+
+#if !defined (DEMANGLE_H)
+#define DEMANGLE_H
+
+#ifdef IN_GCC
+#include "gansidecl.h"
+#define PARAMS(ARGS) PROTO(ARGS)
+#else /* ! IN_GCC */
+#include <ansidecl.h>
+#endif /* IN_GCC */
+
+/* Options passed to cplus_demangle (in 2nd parameter). */
+
+#define DMGL_NO_OPTS 0 /* For readability... */
+#define DMGL_PARAMS (1 << 0) /* Include function args */
+#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
+#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */
+
+#define DMGL_AUTO (1 << 8)
+#define DMGL_GNU (1 << 9)
+#define DMGL_LUCID (1 << 10)
+#define DMGL_ARM (1 << 11)
+/* If none of these are set, use 'current_demangling_style' as the default. */
+#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM)
+
+/* Enumeration of possible demangling styles.
+
+ Lucid and ARM styles are still kept logically distinct, even though
+ they now both behave identically. The resulting style is actual the
+ union of both. I.E. either style recognizes both "__pt__" and "__rf__"
+ for operator "->", even though the first is lucid style and the second
+ is ARM style. (FIXME?) */
+
+extern enum demangling_styles
+{
+ unknown_demangling = 0,
+ auto_demangling = DMGL_AUTO,
+ gnu_demangling = DMGL_GNU,
+ lucid_demangling = DMGL_LUCID,
+ arm_demangling = DMGL_ARM
+} current_demangling_style;
+
+/* Define string names for the various demangling styles. */
+
+#define AUTO_DEMANGLING_STYLE_STRING "auto"
+#define GNU_DEMANGLING_STYLE_STRING "gnu"
+#define LUCID_DEMANGLING_STYLE_STRING "lucid"
+#define ARM_DEMANGLING_STYLE_STRING "arm"
+
+/* Some macros to test what demangling style is active. */
+
+#define CURRENT_DEMANGLING_STYLE current_demangling_style
+#define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO)
+#define GNU_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU)
+#define LUCID_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_LUCID)
+#define ARM_DEMANGLING (CURRENT_DEMANGLING_STYLE & DMGL_ARM)
+
+extern char *
+cplus_demangle PARAMS ((const char *mangled, int options));
+
+extern int
+cplus_demangle_opname PARAMS ((const char *opname, char *result, int options));
+
+extern const char *
+cplus_mangle_opname PARAMS ((const char *opname, int options));
+
+/* Note: This sets global state. FIXME if you care about multi-threading. */
+
+extern void
+set_cplus_marker_for_demangling PARAMS ((int ch));
+
+#endif /* DEMANGLE_H */
diff --git a/pstack/filemode.c b/pstack/filemode.c
new file mode 100644
index 00000000000..58b52ba7489
--- /dev/null
+++ b/pstack/filemode.c
@@ -0,0 +1,266 @@
+/* filemode.c -- make a string describing file modes
+ Copyright (C) 1985, 90, 91, 94, 95, 1997 Free Software Foundation, Inc.
+
+ 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, 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 "bfd.h"
+#include "bucomm.h"
+
+static char ftypelet PARAMS ((unsigned long));
+static void setst PARAMS ((unsigned long, char *));
+
+/* filemodestring - fill in string STR with an ls-style ASCII
+ representation of the st_mode field of file stats block STATP.
+ 10 characters are stored in STR; no terminating null is added.
+ The characters stored in STR are:
+
+ 0 File type. 'd' for directory, 'c' for character
+ special, 'b' for block special, 'm' for multiplex,
+ 'l' for symbolic link, 's' for socket, 'p' for fifo,
+ '-' for any other file type
+
+ 1 'r' if the owner may read, '-' otherwise.
+
+ 2 'w' if the owner may write, '-' otherwise.
+
+ 3 'x' if the owner may execute, 's' if the file is
+ set-user-id, '-' otherwise.
+ 'S' if the file is set-user-id, but the execute
+ bit isn't set.
+
+ 4 'r' if group members may read, '-' otherwise.
+
+ 5 'w' if group members may write, '-' otherwise.
+
+ 6 'x' if group members may execute, 's' if the file is
+ set-group-id, '-' otherwise.
+ 'S' if it is set-group-id but not executable.
+
+ 7 'r' if any user may read, '-' otherwise.
+
+ 8 'w' if any user may write, '-' otherwise.
+
+ 9 'x' if any user may execute, 't' if the file is "sticky"
+ (will be retained in swap space after execution), '-'
+ otherwise.
+ 'T' if the file is sticky but not executable. */
+
+#if 0
+
+/* This is not used; only mode_string is used. */
+
+void
+filemodestring (statp, str)
+ struct stat *statp;
+ char *str;
+{
+ mode_string ((unsigned long) statp->st_mode, str);
+}
+
+#endif
+
+/* Get definitions for the file permission bits. */
+
+#ifndef S_IRWXU
+#define S_IRWXU 0700
+#endif
+#ifndef S_IRUSR
+#define S_IRUSR 0400
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR 0200
+#endif
+#ifndef S_IXUSR
+#define S_IXUSR 0100
+#endif
+
+#ifndef S_IRWXG
+#define S_IRWXG 0070
+#endif
+#ifndef S_IRGRP
+#define S_IRGRP 0040
+#endif
+#ifndef S_IWGRP
+#define S_IWGRP 0020
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 0010
+#endif
+
+#ifndef S_IRWXO
+#define S_IRWXO 0007
+#endif
+#ifndef S_IROTH
+#define S_IROTH 0004
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH 0002
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 0001
+#endif
+
+/* Like filemodestring, but only the relevant part of the `struct stat'
+ is given as an argument. */
+
+void
+mode_string (mode, str)
+ unsigned long mode;
+ char *str;
+{
+ str[0] = ftypelet ((unsigned long) mode);
+ str[1] = (mode & S_IRUSR) != 0 ? 'r' : '-';
+ str[2] = (mode & S_IWUSR) != 0 ? 'w' : '-';
+ str[3] = (mode & S_IXUSR) != 0 ? 'x' : '-';
+ str[4] = (mode & S_IRGRP) != 0 ? 'r' : '-';
+ str[5] = (mode & S_IWGRP) != 0 ? 'w' : '-';
+ str[6] = (mode & S_IXGRP) != 0 ? 'x' : '-';
+ str[7] = (mode & S_IROTH) != 0 ? 'r' : '-';
+ str[8] = (mode & S_IWOTH) != 0 ? 'w' : '-';
+ str[9] = (mode & S_IXOTH) != 0 ? 'x' : '-';
+ setst ((unsigned long) mode, str);
+}
+
+/* Return a character indicating the type of file described by
+ file mode BITS:
+ 'd' for directories
+ 'b' for block special files
+ 'c' for character special files
+ 'm' for multiplexor files
+ 'l' for symbolic links
+ 's' for sockets
+ 'p' for fifos
+ '-' for any other file type. */
+
+#ifndef S_ISDIR
+#ifdef S_IFDIR
+#define S_ISDIR(i) (((i) & S_IFMT) == S_IFDIR)
+#else /* ! defined (S_IFDIR) */
+#define S_ISDIR(i) (((i) & 0170000) == 040000)
+#endif /* ! defined (S_IFDIR) */
+#endif /* ! defined (S_ISDIR) */
+
+#ifndef S_ISBLK
+#ifdef S_IFBLK
+#define S_ISBLK(i) (((i) & S_IFMT) == S_IFBLK)
+#else /* ! defined (S_IFBLK) */
+#define S_ISBLK(i) 0
+#endif /* ! defined (S_IFBLK) */
+#endif /* ! defined (S_ISBLK) */
+
+#ifndef S_ISCHR
+#ifdef S_IFCHR
+#define S_ISCHR(i) (((i) & S_IFMT) == S_IFCHR)
+#else /* ! defined (S_IFCHR) */
+#define S_ISCHR(i) 0
+#endif /* ! defined (S_IFCHR) */
+#endif /* ! defined (S_ISCHR) */
+
+#ifndef S_ISFIFO
+#ifdef S_IFIFO
+#define S_ISFIFO(i) (((i) & S_IFMT) == S_IFIFO)
+#else /* ! defined (S_IFIFO) */
+#define S_ISFIFO(i) 0
+#endif /* ! defined (S_IFIFO) */
+#endif /* ! defined (S_ISFIFO) */
+
+#ifndef S_ISSOCK
+#ifdef S_IFSOCK
+#define S_ISSOCK(i) (((i) & S_IFMT) == S_IFSOCK)
+#else /* ! defined (S_IFSOCK) */
+#define S_ISSOCK(i) 0
+#endif /* ! defined (S_IFSOCK) */
+#endif /* ! defined (S_ISSOCK) */
+
+#ifndef S_ISLNK
+#ifdef S_IFLNK
+#define S_ISLNK(i) (((i) & S_IFMT) == S_IFLNK)
+#else /* ! defined (S_IFLNK) */
+#define S_ISLNK(i) 0
+#endif /* ! defined (S_IFLNK) */
+#endif /* ! defined (S_ISLNK) */
+
+static char
+ftypelet (bits)
+ unsigned long bits;
+{
+ if (S_ISDIR (bits))
+ return 'd';
+ if (S_ISLNK (bits))
+ return 'l';
+ if (S_ISBLK (bits))
+ return 'b';
+ if (S_ISCHR (bits))
+ return 'c';
+ if (S_ISSOCK (bits))
+ return 's';
+ if (S_ISFIFO (bits))
+ return 'p';
+
+#ifdef S_IFMT
+#ifdef S_IFMPC
+ if ((bits & S_IFMT) == S_IFMPC
+ || (bits & S_IFMT) == S_IFMPB)
+ return 'm';
+#endif
+#ifdef S_IFNWK
+ if ((bits & S_IFMT) == S_IFNWK)
+ return 'n';
+#endif
+#endif
+
+ return '-';
+}
+
+/* Set the 's' and 't' flags in file attributes string CHARS,
+ according to the file mode BITS. */
+
+static void
+setst (bits, chars)
+ unsigned long bits;
+ char *chars;
+{
+#ifdef S_ISUID
+ if (bits & S_ISUID)
+ {
+ if (chars[3] != 'x')
+ /* Set-uid, but not executable by owner. */
+ chars[3] = 'S';
+ else
+ chars[3] = 's';
+ }
+#endif
+#ifdef S_ISGID
+ if (bits & S_ISGID)
+ {
+ if (chars[6] != 'x')
+ /* Set-gid, but not executable by group. */
+ chars[6] = 'S';
+ else
+ chars[6] = 's';
+ }
+#endif
+#ifdef S_ISVTX
+ if (bits & S_ISVTX)
+ {
+ if (chars[9] != 'x')
+ /* Sticky, but not executable by others. */
+ chars[9] = 'T';
+ else
+ chars[9] = 't';
+ }
+#endif
+}
diff --git a/pstack/ieee.c b/pstack/ieee.c
new file mode 100644
index 00000000000..4b6ce69ebc6
--- /dev/null
+++ b/pstack/ieee.c
@@ -0,0 +1,7602 @@
+/* ieee.c -- Read and write IEEE-695 debugging information.
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@cygnus.com>.
+
+ This file is part of GNU Binutils.
+
+ 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. */
+
+/* This file reads and writes IEEE-695 debugging information. */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include <bfd.h>
+#include "ieee.h"
+#include "bucomm.h"
+#include <libiberty.h>
+#include "debug.h"
+#include "budbg.h"
+
+/* This structure holds an entry on the block stack. */
+
+struct ieee_block
+{
+ /* The kind of block. */
+ int kind;
+ /* The source file name, for a BB5 block. */
+ const char *filename;
+ /* The index of the function type, for a BB4 or BB6 block. */
+ unsigned int fnindx;
+ /* True if this function is being skipped. */
+ boolean skip;
+};
+
+/* This structure is the block stack. */
+
+#define BLOCKSTACK_SIZE (16)
+
+struct ieee_blockstack
+{
+ /* The stack pointer. */
+ struct ieee_block *bsp;
+ /* The stack. */
+ struct ieee_block stack[BLOCKSTACK_SIZE];
+};
+
+/* This structure holds information for a variable. */
+
+struct ieee_var
+{
+ /* Start of name. */
+ const char *name;
+ /* Length of name. */
+ unsigned long namlen;
+ /* Type. */
+ debug_type type;
+ /* Slot if we make an indirect type. */
+ debug_type *pslot;
+ /* Kind of variable or function. */
+ enum
+ {
+ IEEE_UNKNOWN,
+ IEEE_EXTERNAL,
+ IEEE_GLOBAL,
+ IEEE_STATIC,
+ IEEE_LOCAL,
+ IEEE_FUNCTION
+ } kind;
+};
+
+/* This structure holds all the variables. */
+
+struct ieee_vars
+{
+ /* Number of slots allocated. */
+ unsigned int alloc;
+ /* Variables. */
+ struct ieee_var *vars;
+};
+
+/* This structure holds information for a type. We need this because
+ we don't want to represent bitfields as real types. */
+
+struct ieee_type
+{
+ /* Type. */
+ debug_type type;
+ /* Slot if this is type is referenced before it is defined. */
+ debug_type *pslot;
+ /* Slots for arguments if we make indirect types for them. */
+ debug_type *arg_slots;
+ /* If this is a bitfield, this is the size in bits. If this is not
+ a bitfield, this is zero. */
+ unsigned long bitsize;
+};
+
+/* This structure holds all the type information. */
+
+struct ieee_types
+{
+ /* Number of slots allocated. */
+ unsigned int alloc;
+ /* Types. */
+ struct ieee_type *types;
+ /* Builtin types. */
+#define BUILTIN_TYPE_COUNT (60)
+ debug_type builtins[BUILTIN_TYPE_COUNT];
+};
+
+/* This structure holds a linked last of structs with their tag names,
+ so that we can convert them to C++ classes if necessary. */
+
+struct ieee_tag
+{
+ /* Next tag. */
+ struct ieee_tag *next;
+ /* This tag name. */
+ const char *name;
+ /* The type of the tag. */
+ debug_type type;
+ /* The tagged type is an indirect type pointing at this slot. */
+ debug_type slot;
+ /* This is an array of slots used when a field type is converted
+ into a indirect type, in case it needs to be later converted into
+ a reference type. */
+ debug_type *fslots;
+};
+
+/* This structure holds the information we pass around to the parsing
+ functions. */
+
+struct ieee_info
+{
+ /* The debugging handle. */
+ PTR dhandle;
+ /* The BFD. */
+ bfd *abfd;
+ /* The start of the bytes to be parsed. */
+ const bfd_byte *bytes;
+ /* The end of the bytes to be parsed. */
+ const bfd_byte *pend;
+ /* The block stack. */
+ struct ieee_blockstack blockstack;
+ /* Whether we have seen a BB1 or BB2. */
+ boolean saw_filename;
+ /* The variables. */
+ struct ieee_vars vars;
+ /* The global variables, after a global typedef block. */
+ struct ieee_vars *global_vars;
+ /* The types. */
+ struct ieee_types types;
+ /* The global types, after a global typedef block. */
+ struct ieee_types *global_types;
+ /* The list of tagged structs. */
+ struct ieee_tag *tags;
+};
+
+/* Basic builtin types, not including the pointers. */
+
+enum builtin_types
+{
+ builtin_unknown = 0,
+ builtin_void = 1,
+ builtin_signed_char = 2,
+ builtin_unsigned_char = 3,
+ builtin_signed_short_int = 4,
+ builtin_unsigned_short_int = 5,
+ builtin_signed_long = 6,
+ builtin_unsigned_long = 7,
+ builtin_signed_long_long = 8,
+ builtin_unsigned_long_long = 9,
+ builtin_float = 10,
+ builtin_double = 11,
+ builtin_long_double = 12,
+ builtin_long_long_double = 13,
+ builtin_quoted_string = 14,
+ builtin_instruction_address = 15,
+ builtin_int = 16,
+ builtin_unsigned = 17,
+ builtin_unsigned_int = 18,
+ builtin_char = 19,
+ builtin_long = 20,
+ builtin_short = 21,
+ builtin_unsigned_short = 22,
+ builtin_short_int = 23,
+ builtin_signed_short = 24,
+ builtin_bcd_float = 25
+};
+
+/* These are the values found in the derivation flags of a 'b'
+ component record of a 'T' type extension record in a C++ pmisc
+ record. These are bitmasks. */
+
+/* Set for a private base class, clear for a public base class.
+ Protected base classes are not supported. */
+#define BASEFLAGS_PRIVATE (0x1)
+/* Set for a virtual base class. */
+#define BASEFLAGS_VIRTUAL (0x2)
+/* Set for a friend class, clear for a base class. */
+#define BASEFLAGS_FRIEND (0x10)
+
+/* These are the values found in the specs flags of a 'd', 'm', or 'v'
+ component record of a 'T' type extension record in a C++ pmisc
+ record. The same flags are used for a 'M' record in a C++ pmisc
+ record. */
+
+/* The lower two bits hold visibility information. */
+#define CXXFLAGS_VISIBILITY (0x3)
+/* This value in the lower two bits indicates a public member. */
+#define CXXFLAGS_VISIBILITY_PUBLIC (0x0)
+/* This value in the lower two bits indicates a private member. */
+#define CXXFLAGS_VISIBILITY_PRIVATE (0x1)
+/* This value in the lower two bits indicates a protected member. */
+#define CXXFLAGS_VISIBILITY_PROTECTED (0x2)
+/* Set for a static member. */
+#define CXXFLAGS_STATIC (0x4)
+/* Set for a virtual override. */
+#define CXXFLAGS_OVERRIDE (0x8)
+/* Set for a friend function. */
+#define CXXFLAGS_FRIEND (0x10)
+/* Set for a const function. */
+#define CXXFLAGS_CONST (0x20)
+/* Set for a volatile function. */
+#define CXXFLAGS_VOLATILE (0x40)
+/* Set for an overloaded function. */
+#define CXXFLAGS_OVERLOADED (0x80)
+/* Set for an operator function. */
+#define CXXFLAGS_OPERATOR (0x100)
+/* Set for a constructor or destructor. */
+#define CXXFLAGS_CTORDTOR (0x400)
+/* Set for a constructor. */
+#define CXXFLAGS_CTOR (0x200)
+/* Set for an inline function. */
+#define CXXFLAGS_INLINE (0x800)
+
+/* Local functions. */
+
+static void ieee_error
+ PARAMS ((struct ieee_info *, const bfd_byte *, const char *));
+static void ieee_eof PARAMS ((struct ieee_info *));
+static char *savestring PARAMS ((const char *, unsigned long));
+static boolean ieee_read_number
+ PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *));
+static boolean ieee_read_optional_number
+ PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *, boolean *));
+static boolean ieee_read_id
+ PARAMS ((struct ieee_info *, const bfd_byte **, const char **,
+ unsigned long *));
+static boolean ieee_read_optional_id
+ PARAMS ((struct ieee_info *, const bfd_byte **, const char **,
+ unsigned long *, boolean *));
+static boolean ieee_read_expression
+ PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *));
+static debug_type ieee_builtin_type
+ PARAMS ((struct ieee_info *, const bfd_byte *, unsigned int));
+static boolean ieee_alloc_type
+ PARAMS ((struct ieee_info *, unsigned int, boolean));
+static boolean ieee_read_type_index
+ PARAMS ((struct ieee_info *, const bfd_byte **, debug_type *));
+static int ieee_regno_to_genreg PARAMS ((bfd *, int));
+static int ieee_genreg_to_regno PARAMS ((bfd *, int));
+static boolean parse_ieee_bb PARAMS ((struct ieee_info *, const bfd_byte **));
+static boolean parse_ieee_be PARAMS ((struct ieee_info *, const bfd_byte **));
+static boolean parse_ieee_nn PARAMS ((struct ieee_info *, const bfd_byte **));
+static boolean parse_ieee_ty PARAMS ((struct ieee_info *, const bfd_byte **));
+static boolean parse_ieee_atn PARAMS ((struct ieee_info *, const bfd_byte **));
+static boolean ieee_read_cxx_misc
+ PARAMS ((struct ieee_info *, const bfd_byte **, unsigned long));
+static boolean ieee_read_cxx_class
+ PARAMS ((struct ieee_info *, const bfd_byte **, unsigned long));
+static boolean ieee_read_cxx_defaults
+ PARAMS ((struct ieee_info *, const bfd_byte **, unsigned long));
+static boolean ieee_read_reference
+ PARAMS ((struct ieee_info *, const bfd_byte **));
+static boolean ieee_require_asn
+ PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *));
+static boolean ieee_require_atn65
+ PARAMS ((struct ieee_info *, const bfd_byte **, const char **,
+ unsigned long *));
+
+/* Report an error in the IEEE debugging information. */
+
+static void
+ieee_error (info, p, s)
+ struct ieee_info *info;
+ const bfd_byte *p;
+ const char *s;
+{
+ if (p != NULL)
+ fprintf (stderr, "%s: 0x%lx: %s (0x%x)\n", bfd_get_filename (info->abfd),
+ (unsigned long) (p - info->bytes), s, *p);
+ else
+ fprintf (stderr, "%s: %s\n", bfd_get_filename (info->abfd), s);
+}
+
+/* Report an unexpected EOF in the IEEE debugging information. */
+
+static void
+ieee_eof (info)
+ struct ieee_info *info;
+{
+ ieee_error (info, (const bfd_byte *) NULL,
+ "unexpected end of debugging information");
+}
+
+/* Save a string in memory. */
+
+static char *
+savestring (start, len)
+ const char *start;
+ unsigned long len;
+{
+ char *ret;
+
+ ret = (char *) xmalloc (len + 1);
+ memcpy (ret, start, len);
+ ret[len] = '\0';
+ return ret;
+}
+
+/* Read a number which must be present in an IEEE file. */
+
+static boolean
+ieee_read_number (info, pp, pv)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ bfd_vma *pv;
+{
+ return ieee_read_optional_number (info, pp, pv, (boolean *) NULL);
+}
+
+/* Read a number in an IEEE file. If ppresent is not NULL, the number
+ need not be there. */
+
+static boolean
+ieee_read_optional_number (info, pp, pv, ppresent)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ bfd_vma *pv;
+ boolean *ppresent;
+{
+ ieee_record_enum_type b;
+
+ if (*pp >= info->pend)
+ {
+ if (ppresent != NULL)
+ {
+ *ppresent = false;
+ return true;
+ }
+ ieee_eof (info);
+ return false;
+ }
+
+ b = (ieee_record_enum_type) **pp;
+ ++*pp;
+
+ if (b <= ieee_number_end_enum)
+ {
+ *pv = (bfd_vma) b;
+ if (ppresent != NULL)
+ *ppresent = true;
+ return true;
+ }
+
+ if (b >= ieee_number_repeat_start_enum && b <= ieee_number_repeat_end_enum)
+ {
+ unsigned int i;
+
+ i = (int) b - (int) ieee_number_repeat_start_enum;
+ if (*pp + i - 1 >= info->pend)
+ {
+ ieee_eof (info);
+ return false;
+ }
+
+ *pv = 0;
+ for (; i > 0; i--)
+ {
+ *pv <<= 8;
+ *pv += **pp;
+ ++*pp;
+ }
+
+ if (ppresent != NULL)
+ *ppresent = true;
+
+ return true;
+ }
+
+ if (ppresent != NULL)
+ {
+ --*pp;
+ *ppresent = false;
+ return true;
+ }
+
+ ieee_error (info, *pp - 1, "invalid number");
+ return false;
+}
+
+/* Read a required string from an IEEE file. */
+
+static boolean
+ieee_read_id (info, pp, pname, pnamlen)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ const char **pname;
+ unsigned long *pnamlen;
+{
+ return ieee_read_optional_id (info, pp, pname, pnamlen, (boolean *) NULL);
+}
+
+/* Read a string from an IEEE file. If ppresent is not NULL, the
+ string is optional. */
+
+static boolean
+ieee_read_optional_id (info, pp, pname, pnamlen, ppresent)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ const char **pname;
+ unsigned long *pnamlen;
+ boolean *ppresent;
+{
+ bfd_byte b;
+ unsigned long len;
+
+ if (*pp >= info->pend)
+ {
+ ieee_eof (info);
+ return false;
+ }
+
+ b = **pp;
+ ++*pp;
+
+ if (b <= 0x7f)
+ len = b;
+ else if ((ieee_record_enum_type) b == ieee_extension_length_1_enum)
+ {
+ len = **pp;
+ ++*pp;
+ }
+ else if ((ieee_record_enum_type) b == ieee_extension_length_2_enum)
+ {
+ len = (**pp << 8) + (*pp)[1];
+ *pp += 2;
+ }
+ else
+ {
+ if (ppresent != NULL)
+ {
+ --*pp;
+ *ppresent = false;
+ return true;
+ }
+ ieee_error (info, *pp - 1, "invalid string length");
+ return false;
+ }
+
+ if ((unsigned long) (info->pend - *pp) < len)
+ {
+ ieee_eof (info);
+ return false;
+ }
+
+ *pname = (const char *) *pp;
+ *pnamlen = len;
+ *pp += len;
+
+ if (ppresent != NULL)
+ *ppresent = true;
+
+ return true;
+}
+
+/* Read an expression from an IEEE file. Since this code is only used
+ to parse debugging information, I haven't bothered to write a full
+ blown IEEE expression parser. I've only thrown in the things I've
+ seen in debugging information. This can be easily extended if
+ necessary. */
+
+static boolean
+ieee_read_expression (info, pp, pv)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ bfd_vma *pv;
+{
+ const bfd_byte *expr_start;
+#define EXPR_STACK_SIZE (10)
+ bfd_vma expr_stack[EXPR_STACK_SIZE];
+ bfd_vma *esp;
+
+ expr_start = *pp;
+
+ esp = expr_stack;
+
+ while (1)
+ {
+ const bfd_byte *start;
+ bfd_vma val;
+ boolean present;
+ ieee_record_enum_type c;
+
+ start = *pp;
+
+ if (! ieee_read_optional_number (info, pp, &val, &present))
+ return false;
+
+ if (present)
+ {
+ if (esp - expr_stack >= EXPR_STACK_SIZE)
+ {
+ ieee_error (info, start, "expression stack overflow");
+ return false;
+ }
+ *esp++ = val;
+ continue;
+ }
+
+ c = (ieee_record_enum_type) **pp;
+
+ if (c >= ieee_module_beginning_enum)
+ break;
+
+ ++*pp;
+
+ if (c == ieee_comma)
+ break;
+
+ switch (c)
+ {
+ default:
+ ieee_error (info, start, "unsupported IEEE expression operator");
+ break;
+
+ case ieee_variable_R_enum:
+ {
+ bfd_vma indx;
+ asection *s;
+
+ if (! ieee_read_number (info, pp, &indx))
+ return false;
+ for (s = info->abfd->sections; s != NULL; s = s->next)
+ if ((bfd_vma) s->target_index == indx)
+ break;
+ if (s == NULL)
+ {
+ ieee_error (info, start, "unknown section");
+ return false;
+ }
+
+ if (esp - expr_stack >= EXPR_STACK_SIZE)
+ {
+ ieee_error (info, start, "expression stack overflow");
+ return false;
+ }
+
+ *esp++ = bfd_get_section_vma (info->abfd, s);
+ }
+ break;
+
+ case ieee_function_plus_enum:
+ case ieee_function_minus_enum:
+ {
+ bfd_vma v1, v2;
+
+ if (esp - expr_stack < 2)
+ {
+ ieee_error (info, start, "expression stack underflow");
+ return false;
+ }
+
+ v1 = *--esp;
+ v2 = *--esp;
+ *esp++ = v1 + v2;
+ }
+ break;
+ }
+ }
+
+ if (esp - 1 != expr_stack)
+ {
+ ieee_error (info, expr_start, "expression stack mismatch");
+ return false;
+ }
+
+ *pv = *--esp;
+
+ return true;
+}
+
+/* Return an IEEE builtin type. */
+
+static debug_type
+ieee_builtin_type (info, p, indx)
+ struct ieee_info *info;
+ const bfd_byte *p;
+ unsigned int indx;
+{
+ PTR dhandle;
+ debug_type type;
+ const char *name;
+
+ if (indx < BUILTIN_TYPE_COUNT
+ && info->types.builtins[indx] != DEBUG_TYPE_NULL)
+ return info->types.builtins[indx];
+
+ dhandle = info->dhandle;
+
+ if (indx >= 32 && indx < 64)
+ {
+ type = debug_make_pointer_type (dhandle,
+ ieee_builtin_type (info, p, indx - 32));
+ assert (indx < BUILTIN_TYPE_COUNT);
+ info->types.builtins[indx] = type;
+ return type;
+ }
+
+ switch ((enum builtin_types) indx)
+ {
+ default:
+ ieee_error (info, p, "unknown builtin type");
+ return NULL;
+
+ case builtin_unknown:
+ type = debug_make_void_type (dhandle);
+ name = NULL;
+ break;
+
+ case builtin_void:
+ type = debug_make_void_type (dhandle);
+ name = "void";
+ break;
+
+ case builtin_signed_char:
+ type = debug_make_int_type (dhandle, 1, false);
+ name = "signed char";
+ break;
+
+ case builtin_unsigned_char:
+ type = debug_make_int_type (dhandle, 1, true);
+ name = "unsigned char";
+ break;
+
+ case builtin_signed_short_int:
+ type = debug_make_int_type (dhandle, 2, false);
+ name = "signed short int";
+ break;
+
+ case builtin_unsigned_short_int:
+ type = debug_make_int_type (dhandle, 2, true);
+ name = "unsigned short int";
+ break;
+
+ case builtin_signed_long:
+ type = debug_make_int_type (dhandle, 4, false);
+ name = "signed long";
+ break;
+
+ case builtin_unsigned_long:
+ type = debug_make_int_type (dhandle, 4, true);
+ name = "unsigned long";
+ break;
+
+ case builtin_signed_long_long:
+ type = debug_make_int_type (dhandle, 8, false);
+ name = "signed long long";
+ break;
+
+ case builtin_unsigned_long_long:
+ type = debug_make_int_type (dhandle, 8, true);
+ name = "unsigned long long";
+ break;
+
+ case builtin_float:
+ type = debug_make_float_type (dhandle, 4);
+ name = "float";
+ break;
+
+ case builtin_double:
+ type = debug_make_float_type (dhandle, 8);
+ name = "double";
+ break;
+
+ case builtin_long_double:
+ /* FIXME: The size for this type should depend upon the
+ processor. */
+ type = debug_make_float_type (dhandle, 12);
+ name = "long double";
+ break;
+
+ case builtin_long_long_double:
+ type = debug_make_float_type (dhandle, 16);
+ name = "long long double";
+ break;
+
+ case builtin_quoted_string:
+ type = debug_make_array_type (dhandle,
+ ieee_builtin_type (info, p,
+ ((unsigned int)
+ builtin_char)),
+ ieee_builtin_type (info, p,
+ ((unsigned int)
+ builtin_int)),
+ 0, -1, true);
+ name = "QUOTED STRING";
+ break;
+
+ case builtin_instruction_address:
+ /* FIXME: This should be a code address. */
+ type = debug_make_int_type (dhandle, 4, true);
+ name = "instruction address";
+ break;
+
+ case builtin_int:
+ /* FIXME: The size for this type should depend upon the
+ processor. */
+ type = debug_make_int_type (dhandle, 4, false);
+ name = "int";
+ break;
+
+ case builtin_unsigned:
+ /* FIXME: The size for this type should depend upon the
+ processor. */
+ type = debug_make_int_type (dhandle, 4, true);
+ name = "unsigned";
+ break;
+
+ case builtin_unsigned_int:
+ /* FIXME: The size for this type should depend upon the
+ processor. */
+ type = debug_make_int_type (dhandle, 4, true);
+ name = "unsigned int";
+ break;
+
+ case builtin_char:
+ type = debug_make_int_type (dhandle, 1, false);
+ name = "char";
+ break;
+
+ case builtin_long:
+ type = debug_make_int_type (dhandle, 4, false);
+ name = "long";
+ break;
+
+ case builtin_short:
+ type = debug_make_int_type (dhandle, 2, false);
+ name = "short";
+ break;
+
+ case builtin_unsigned_short:
+ type = debug_make_int_type (dhandle, 2, true);
+ name = "unsigned short";
+ break;
+
+ case builtin_short_int:
+ type = debug_make_int_type (dhandle, 2, false);
+ name = "short int";
+ break;
+
+ case builtin_signed_short:
+ type = debug_make_int_type (dhandle, 2, false);
+ name = "signed short";
+ break;
+
+ case builtin_bcd_float:
+ ieee_error (info, p, "BCD float type not supported");
+ return DEBUG_TYPE_NULL;
+ }
+
+ if (name != NULL)
+ type = debug_name_type (dhandle, name, type);
+
+ assert (indx < BUILTIN_TYPE_COUNT);
+
+ info->types.builtins[indx] = type;
+
+ return type;
+}
+
+/* Allocate more space in the type table. If ref is true, this is a
+ reference to the type; if it is not already defined, we should set
+ up an indirect type. */
+
+static boolean
+ieee_alloc_type (info, indx, ref)
+ struct ieee_info *info;
+ unsigned int indx;
+ boolean ref;
+{
+ unsigned int nalloc;
+ register struct ieee_type *t;
+ struct ieee_type *tend;
+
+ if (indx >= info->types.alloc)
+ {
+ nalloc = info->types.alloc;
+ if (nalloc == 0)
+ nalloc = 4;
+ while (indx >= nalloc)
+ nalloc *= 2;
+
+ info->types.types = ((struct ieee_type *)
+ xrealloc (info->types.types,
+ nalloc * sizeof *info->types.types));
+
+ memset (info->types.types + info->types.alloc, 0,
+ (nalloc - info->types.alloc) * sizeof *info->types.types);
+
+ tend = info->types.types + nalloc;
+ for (t = info->types.types + info->types.alloc; t < tend; t++)
+ t->type = DEBUG_TYPE_NULL;
+
+ info->types.alloc = nalloc;
+ }
+
+ if (ref)
+ {
+ t = info->types.types + indx;
+ if (t->type == NULL)
+ {
+ t->pslot = (debug_type *) xmalloc (sizeof *t->pslot);
+ *t->pslot = DEBUG_TYPE_NULL;
+ t->type = debug_make_indirect_type (info->dhandle, t->pslot,
+ (const char *) NULL);
+ if (t->type == NULL)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* Read a type index and return the corresponding type. */
+
+static boolean
+ieee_read_type_index (info, pp, ptype)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ debug_type *ptype;
+{
+ const bfd_byte *start;
+ bfd_vma indx;
+
+ start = *pp;
+
+ if (! ieee_read_number (info, pp, &indx))
+ return false;
+
+ if (indx < 256)
+ {
+ *ptype = ieee_builtin_type (info, start, indx);
+ if (*ptype == NULL)
+ return false;
+ return true;
+ }
+
+ indx -= 256;
+ if (! ieee_alloc_type (info, indx, true))
+ return false;
+
+ *ptype = info->types.types[indx].type;
+
+ return true;
+}
+
+/* Parse IEEE debugging information for a file. This is passed the
+ bytes which compose the Debug Information Part of an IEEE file. */
+
+boolean
+parse_ieee (dhandle, abfd, bytes, len)
+ PTR dhandle;
+ bfd *abfd;
+ const bfd_byte *bytes;
+ bfd_size_type len;
+{
+ struct ieee_info info;
+ unsigned int i;
+ const bfd_byte *p, *pend;
+
+ info.dhandle = dhandle;
+ info.abfd = abfd;
+ info.bytes = bytes;
+ info.pend = bytes + len;
+ info.blockstack.bsp = info.blockstack.stack;
+ info.saw_filename = false;
+ info.vars.alloc = 0;
+ info.vars.vars = NULL;
+ info.types.alloc = 0;
+ info.types.types = NULL;
+ info.tags = NULL;
+ for (i = 0; i < BUILTIN_TYPE_COUNT; i++)
+ info.types.builtins[i] = DEBUG_TYPE_NULL;
+
+ p = bytes;
+ pend = info.pend;
+ while (p < pend)
+ {
+ const bfd_byte *record_start;
+ ieee_record_enum_type c;
+
+ record_start = p;
+
+ c = (ieee_record_enum_type) *p++;
+
+ if (c == ieee_at_record_enum)
+ c = (ieee_record_enum_type) (((unsigned int) c << 8) | *p++);
+
+ if (c <= ieee_number_repeat_end_enum)
+ {
+ ieee_error (&info, record_start, "unexpected number");
+ return false;
+ }
+
+ switch (c)
+ {
+ default:
+ ieee_error (&info, record_start, "unexpected record type");
+ return false;
+
+ case ieee_bb_record_enum:
+ if (! parse_ieee_bb (&info, &p))
+ return false;
+ break;
+
+ case ieee_be_record_enum:
+ if (! parse_ieee_be (&info, &p))
+ return false;
+ break;
+
+ case ieee_nn_record:
+ if (! parse_ieee_nn (&info, &p))
+ return false;
+ break;
+
+ case ieee_ty_record_enum:
+ if (! parse_ieee_ty (&info, &p))
+ return false;
+ break;
+
+ case ieee_atn_record_enum:
+ if (! parse_ieee_atn (&info, &p))
+ return false;
+ break;
+ }
+ }
+
+ if (info.blockstack.bsp != info.blockstack.stack)
+ {
+ ieee_error (&info, (const bfd_byte *) NULL,
+ "blocks left on stack at end");
+ return false;
+ }
+
+ return true;
+}
+
+/* Handle an IEEE BB record. */
+
+static boolean
+parse_ieee_bb (info, pp)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+{
+ const bfd_byte *block_start;
+ bfd_byte b;
+ bfd_vma size;
+ const char *name;
+ unsigned long namlen;
+ char *namcopy = NULL;
+ unsigned int fnindx;
+ boolean skip;
+
+ block_start = *pp;
+
+ b = **pp;
+ ++*pp;
+
+ if (! ieee_read_number (info, pp, &size)
+ || ! ieee_read_id (info, pp, &name, &namlen))
+ return false;
+
+ fnindx = (unsigned int) -1;
+ skip = false;
+
+ switch (b)
+ {
+ case 1:
+ /* BB1: Type definitions local to a module. */
+ namcopy = savestring (name, namlen);
+ if (namcopy == NULL)
+ return false;
+ if (! debug_set_filename (info->dhandle, namcopy))
+ return false;
+ info->saw_filename = true;
+
+ /* Discard any variables or types we may have seen before. */
+ if (info->vars.vars != NULL)
+ free (info->vars.vars);
+ info->vars.vars = NULL;
+ info->vars.alloc = 0;
+ if (info->types.types != NULL)
+ free (info->types.types);
+ info->types.types = NULL;
+ info->types.alloc = 0;
+
+ /* Initialize the types to the global types. */
+ if (info->global_types != NULL)
+ {
+ info->types.alloc = info->global_types->alloc;
+ info->types.types = ((struct ieee_type *)
+ xmalloc (info->types.alloc
+ * sizeof (*info->types.types)));
+ memcpy (info->types.types, info->global_types->types,
+ info->types.alloc * sizeof (*info->types.types));
+ }
+
+ break;
+
+ case 2:
+ /* BB2: Global type definitions. The name is supposed to be
+ empty, but we don't check. */
+ if (! debug_set_filename (info->dhandle, "*global*"))
+ return false;
+ info->saw_filename = true;
+ break;
+
+ case 3:
+ /* BB3: High level module block begin. We don't have to do
+ anything here. The name is supposed to be the same as for
+ the BB1, but we don't check. */
+ break;
+
+ case 4:
+ /* BB4: Global function. */
+ {
+ bfd_vma stackspace, typindx, offset;
+ debug_type return_type;
+
+ if (! ieee_read_number (info, pp, &stackspace)
+ || ! ieee_read_number (info, pp, &typindx)
+ || ! ieee_read_expression (info, pp, &offset))
+ return false;
+
+ /* We have no way to record the stack space. FIXME. */
+
+ if (typindx < 256)
+ {
+ return_type = ieee_builtin_type (info, block_start, typindx);
+ if (return_type == DEBUG_TYPE_NULL)
+ return false;
+ }
+ else
+ {
+ typindx -= 256;
+ if (! ieee_alloc_type (info, typindx, true))
+ return false;
+ fnindx = typindx;
+ return_type = info->types.types[typindx].type;
+ if (debug_get_type_kind (info->dhandle, return_type)
+ == DEBUG_KIND_FUNCTION)
+ return_type = debug_get_return_type (info->dhandle,
+ return_type);
+ }
+
+ namcopy = savestring (name, namlen);
+ if (namcopy == NULL)
+ return false;
+ if (! debug_record_function (info->dhandle, namcopy, return_type,
+ true, offset))
+ return false;
+ }
+ break;
+
+ case 5:
+ /* BB5: File name for source line numbers. */
+ {
+ unsigned int i;
+
+ /* We ignore the date and time. FIXME. */
+ for (i = 0; i < 6; i++)
+ {
+ bfd_vma ignore;
+ boolean present;
+
+ if (! ieee_read_optional_number (info, pp, &ignore, &present))
+ return false;
+ if (! present)
+ break;
+ }
+
+ namcopy = savestring (name, namlen);
+ if (namcopy == NULL)
+ return false;
+ if (! debug_start_source (info->dhandle, namcopy))
+ return false;
+ }
+ break;
+
+ case 6:
+ /* BB6: Local function or block. */
+ {
+ bfd_vma stackspace, typindx, offset;
+
+ if (! ieee_read_number (info, pp, &stackspace)
+ || ! ieee_read_number (info, pp, &typindx)
+ || ! ieee_read_expression (info, pp, &offset))
+ return false;
+
+ /* We have no way to record the stack space. FIXME. */
+
+ if (namlen == 0)
+ {
+ if (! debug_start_block (info->dhandle, offset))
+ return false;
+ /* Change b to indicate that this is a block
+ rather than a function. */
+ b = 0x86;
+ }
+ else
+ {
+ /* The MRI C++ compiler will output a fake function named
+ __XRYCPP to hold C++ debugging information. We skip
+ that function. This is not crucial, but it makes
+ converting from IEEE to other debug formats work
+ better. */
+ if (strncmp (name, "__XRYCPP", namlen) == 0)
+ skip = true;
+ else
+ {
+ debug_type return_type;
+
+ if (typindx < 256)
+ {
+ return_type = ieee_builtin_type (info, block_start,
+ typindx);
+ if (return_type == NULL)
+ return false;
+ }
+ else
+ {
+ typindx -= 256;
+ if (! ieee_alloc_type (info, typindx, true))
+ return false;
+ fnindx = typindx;
+ return_type = info->types.types[typindx].type;
+ if (debug_get_type_kind (info->dhandle, return_type)
+ == DEBUG_KIND_FUNCTION)
+ return_type = debug_get_return_type (info->dhandle,
+ return_type);
+ }
+
+ namcopy = savestring (name, namlen);
+ if (namcopy == NULL)
+ return false;
+ if (! debug_record_function (info->dhandle, namcopy,
+ return_type, false, offset))
+ return false;
+ }
+ }
+ }
+ break;
+
+ case 10:
+ /* BB10: Assembler module scope. In the normal case, we
+ completely ignore all this information. FIXME. */
+ {
+ const char *inam, *vstr;
+ unsigned long inamlen, vstrlen;
+ bfd_vma tool_type;
+ boolean present;
+ unsigned int i;
+
+ if (! info->saw_filename)
+ {
+ namcopy = savestring (name, namlen);
+ if (namcopy == NULL)
+ return false;
+ if (! debug_set_filename (info->dhandle, namcopy))
+ return false;
+ info->saw_filename = true;
+ }
+
+ if (! ieee_read_id (info, pp, &inam, &inamlen)
+ || ! ieee_read_number (info, pp, &tool_type)
+ || ! ieee_read_optional_id (info, pp, &vstr, &vstrlen, &present))
+ return false;
+ for (i = 0; i < 6; i++)
+ {
+ bfd_vma ignore;
+
+ if (! ieee_read_optional_number (info, pp, &ignore, &present))
+ return false;
+ if (! present)
+ break;
+ }
+ }
+ break;
+
+ case 11:
+ /* BB11: Module section. We completely ignore all this
+ information. FIXME. */
+ {
+ bfd_vma sectype, secindx, offset, map;
+ boolean present;
+
+ if (! ieee_read_number (info, pp, &sectype)
+ || ! ieee_read_number (info, pp, &secindx)
+ || ! ieee_read_expression (info, pp, &offset)
+ || ! ieee_read_optional_number (info, pp, &map, &present))
+ return false;
+ }
+ break;
+
+ default:
+ ieee_error (info, block_start, "unknown BB type");
+ return false;
+ }
+
+
+ /* Push this block on the block stack. */
+
+ if (info->blockstack.bsp >= info->blockstack.stack + BLOCKSTACK_SIZE)
+ {
+ ieee_error (info, (const bfd_byte *) NULL, "stack overflow");
+ return false;
+ }
+
+ info->blockstack.bsp->kind = b;
+ if (b == 5)
+ info->blockstack.bsp->filename = namcopy;
+ info->blockstack.bsp->fnindx = fnindx;
+ info->blockstack.bsp->skip = skip;
+ ++info->blockstack.bsp;
+
+ return true;
+}
+
+/* Handle an IEEE BE record. */
+
+static boolean
+parse_ieee_be (info, pp)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+{
+ bfd_vma offset;
+
+ if (info->blockstack.bsp <= info->blockstack.stack)
+ {
+ ieee_error (info, *pp, "stack underflow");
+ return false;
+ }
+ --info->blockstack.bsp;
+
+ switch (info->blockstack.bsp->kind)
+ {
+ case 2:
+ /* When we end the global typedefs block, we copy out the the
+ contents of info->vars. This is because the variable indices
+ may be reused in the local blocks. However, we need to
+ preserve them so that we can locate a function returning a
+ reference variable whose type is named in the global typedef
+ block. */
+ info->global_vars = ((struct ieee_vars *)
+ xmalloc (sizeof *info->global_vars));
+ info->global_vars->alloc = info->vars.alloc;
+ info->global_vars->vars = ((struct ieee_var *)
+ xmalloc (info->vars.alloc
+ * sizeof (*info->vars.vars)));
+ memcpy (info->global_vars->vars, info->vars.vars,
+ info->vars.alloc * sizeof (*info->vars.vars));
+
+ /* We also copy out the non builtin parts of info->types, since
+ the types are discarded when we start a new block. */
+ info->global_types = ((struct ieee_types *)
+ xmalloc (sizeof *info->global_types));
+ info->global_types->alloc = info->types.alloc;
+ info->global_types->types = ((struct ieee_type *)
+ xmalloc (info->types.alloc
+ * sizeof (*info->types.types)));
+ memcpy (info->global_types->types, info->types.types,
+ info->types.alloc * sizeof (*info->types.types));
+ memset (info->global_types->builtins, 0,
+ sizeof (info->global_types->builtins));
+
+ break;
+
+ case 4:
+ case 6:
+ if (! ieee_read_expression (info, pp, &offset))
+ return false;
+ if (! info->blockstack.bsp->skip)
+ {
+ if (! debug_end_function (info->dhandle, offset + 1))
+ return false;
+ }
+ break;
+
+ case 0x86:
+ /* This is BE6 when BB6 started a block rather than a local
+ function. */
+ if (! ieee_read_expression (info, pp, &offset))
+ return false;
+ if (! debug_end_block (info->dhandle, offset + 1))
+ return false;
+ break;
+
+ case 5:
+ /* When we end a BB5, we look up the stack for the last BB5, if
+ there is one, so that we can call debug_start_source. */
+ if (info->blockstack.bsp > info->blockstack.stack)
+ {
+ struct ieee_block *bl;
+
+ bl = info->blockstack.bsp;
+ do
+ {
+ --bl;
+ if (bl->kind == 5)
+ {
+ if (! debug_start_source (info->dhandle, bl->filename))
+ return false;
+ break;
+ }
+ }
+ while (bl != info->blockstack.stack);
+ }
+ break;
+
+ case 11:
+ if (! ieee_read_expression (info, pp, &offset))
+ return false;
+ /* We just ignore the module size. FIXME. */
+ break;
+
+ default:
+ /* Other block types do not have any trailing information. */
+ break;
+ }
+
+ return true;
+}
+
+/* Parse an NN record. */
+
+static boolean
+parse_ieee_nn (info, pp)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+{
+ const bfd_byte *nn_start;
+ bfd_vma varindx;
+ const char *name;
+ unsigned long namlen;
+
+ nn_start = *pp;
+
+ if (! ieee_read_number (info, pp, &varindx)
+ || ! ieee_read_id (info, pp, &name, &namlen))
+ return false;
+
+ if (varindx < 32)
+ {
+ ieee_error (info, nn_start, "illegal variable index");
+ return false;
+ }
+ varindx -= 32;
+
+ if (varindx >= info->vars.alloc)
+ {
+ unsigned int alloc;
+
+ alloc = info->vars.alloc;
+ if (alloc == 0)
+ alloc = 4;
+ while (varindx >= alloc)
+ alloc *= 2;
+ info->vars.vars = ((struct ieee_var *)
+ xrealloc (info->vars.vars,
+ alloc * sizeof *info->vars.vars));
+ memset (info->vars.vars + info->vars.alloc, 0,
+ (alloc - info->vars.alloc) * sizeof *info->vars.vars);
+ info->vars.alloc = alloc;
+ }
+
+ info->vars.vars[varindx].name = name;
+ info->vars.vars[varindx].namlen = namlen;
+
+ return true;
+}
+
+/* Parse a TY record. */
+
+static boolean
+parse_ieee_ty (info, pp)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+{
+ const bfd_byte *ty_start, *ty_var_start, *ty_code_start;
+ bfd_vma typeindx, varindx, tc;
+ PTR dhandle;
+ boolean tag, typdef;
+ debug_type *arg_slots;
+ unsigned long type_bitsize;
+ debug_type type;
+
+ ty_start = *pp;
+
+ if (! ieee_read_number (info, pp, &typeindx))
+ return false;
+
+ if (typeindx < 256)
+ {
+ ieee_error (info, ty_start, "illegal type index");
+ return false;
+ }
+
+ typeindx -= 256;
+ if (! ieee_alloc_type (info, typeindx, false))
+ return false;
+
+ if (**pp != 0xce)
+ {
+ ieee_error (info, *pp, "unknown TY code");
+ return false;
+ }
+ ++*pp;
+
+ ty_var_start = *pp;
+
+ if (! ieee_read_number (info, pp, &varindx))
+ return false;
+
+ if (varindx < 32)
+ {
+ ieee_error (info, ty_var_start, "illegal variable index");
+ return false;
+ }
+ varindx -= 32;
+
+ if (varindx >= info->vars.alloc || info->vars.vars[varindx].name == NULL)
+ {
+ ieee_error (info, ty_var_start, "undefined variable in TY");
+ return false;
+ }
+
+ ty_code_start = *pp;
+
+ if (! ieee_read_number (info, pp, &tc))
+ return false;
+
+ dhandle = info->dhandle;
+
+ tag = false;
+ typdef = false;
+ arg_slots = NULL;
+ type_bitsize = 0;
+ switch (tc)
+ {
+ default:
+ ieee_error (info, ty_code_start, "unknown TY code");
+ return false;
+
+ case '!':
+ /* Unknown type, with size. We treat it as int. FIXME. */
+ {
+ bfd_vma size;
+
+ if (! ieee_read_number (info, pp, &size))
+ return false;
+ type = debug_make_int_type (dhandle, size, false);
+ }
+ break;
+
+ case 'A': /* Array. */
+ case 'a': /* FORTRAN array in column/row order. FIXME: Not
+ distinguished from normal array. */
+ {
+ debug_type ele_type;
+ bfd_vma lower, upper;
+
+ if (! ieee_read_type_index (info, pp, &ele_type)
+ || ! ieee_read_number (info, pp, &lower)
+ || ! ieee_read_number (info, pp, &upper))
+ return false;
+ type = debug_make_array_type (dhandle, ele_type,
+ ieee_builtin_type (info, ty_code_start,
+ ((unsigned int)
+ builtin_int)),
+ (bfd_signed_vma) lower,
+ (bfd_signed_vma) upper,
+ false);
+ }
+ break;
+
+ case 'E':
+ /* Simple enumeration. */
+ {
+ bfd_vma size;
+ unsigned int alloc;
+ const char **names;
+ unsigned int c;
+ bfd_signed_vma *vals;
+ unsigned int i;
+
+ if (! ieee_read_number (info, pp, &size))
+ return false;
+ /* FIXME: we ignore the enumeration size. */
+
+ alloc = 10;
+ names = (const char **) xmalloc (alloc * sizeof *names);
+ memset (names, 0, alloc * sizeof *names);
+ c = 0;
+ while (1)
+ {
+ const char *name;
+ unsigned long namlen;
+ boolean present;
+
+ if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
+ return false;
+ if (! present)
+ break;
+
+ if (c + 1 >= alloc)
+ {
+ alloc += 10;
+ names = ((const char **)
+ xrealloc (names, alloc * sizeof *names));
+ }
+
+ names[c] = savestring (name, namlen);
+ if (names[c] == NULL)
+ return false;
+ ++c;
+ }
+
+ names[c] = NULL;
+
+ vals = (bfd_signed_vma *) xmalloc (c * sizeof *vals);
+ for (i = 0; i < c; i++)
+ vals[i] = i;
+
+ type = debug_make_enum_type (dhandle, names, vals);
+ tag = true;
+ }
+ break;
+
+ case 'G':
+ /* Struct with bit fields. */
+ {
+ bfd_vma size;
+ unsigned int alloc;
+ debug_field *fields;
+ unsigned int c;
+
+ if (! ieee_read_number (info, pp, &size))
+ return false;
+
+ alloc = 10;
+ fields = (debug_field *) xmalloc (alloc * sizeof *fields);
+ c = 0;
+ while (1)
+ {
+ const char *name;
+ unsigned long namlen;
+ boolean present;
+ debug_type ftype;
+ bfd_vma bitpos, bitsize;
+
+ if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
+ return false;
+ if (! present)
+ break;
+ if (! ieee_read_type_index (info, pp, &ftype)
+ || ! ieee_read_number (info, pp, &bitpos)
+ || ! ieee_read_number (info, pp, &bitsize))
+ return false;
+
+ if (c + 1 >= alloc)
+ {
+ alloc += 10;
+ fields = ((debug_field *)
+ xrealloc (fields, alloc * sizeof *fields));
+ }
+
+ fields[c] = debug_make_field (dhandle, savestring (name, namlen),
+ ftype, bitpos, bitsize,
+ DEBUG_VISIBILITY_PUBLIC);
+ if (fields[c] == NULL)
+ return false;
+ ++c;
+ }
+
+ fields[c] = NULL;
+
+ type = debug_make_struct_type (dhandle, true, size, fields);
+ tag = true;
+ }
+ break;
+
+ case 'N':
+ /* Enumeration. */
+ {
+ unsigned int alloc;
+ const char **names;
+ bfd_signed_vma *vals;
+ unsigned int c;
+
+ alloc = 10;
+ names = (const char **) xmalloc (alloc * sizeof *names);
+ vals = (bfd_signed_vma *) xmalloc (alloc * sizeof *names);
+ c = 0;
+ while (1)
+ {
+ const char *name;
+ unsigned long namlen;
+ boolean present;
+ bfd_vma val;
+
+ if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
+ return false;
+ if (! present)
+ break;
+ if (! ieee_read_number (info, pp, &val))
+ return false;
+
+ /* If the length of the name is zero, then the value is
+ actually the size of the enum. We ignore this
+ information. FIXME. */
+ if (namlen == 0)
+ continue;
+
+ if (c + 1 >= alloc)
+ {
+ alloc += 10;
+ names = ((const char **)
+ xrealloc (names, alloc * sizeof *names));
+ vals = ((bfd_signed_vma *)
+ xrealloc (vals, alloc * sizeof *vals));
+ }
+
+ names[c] = savestring (name, namlen);
+ if (names[c] == NULL)
+ return false;
+ vals[c] = (bfd_signed_vma) val;
+ ++c;
+ }
+
+ names[c] = NULL;
+
+ type = debug_make_enum_type (dhandle, names, vals);
+ tag = true;
+ }
+ break;
+
+ case 'O': /* Small pointer. We don't distinguish small and large
+ pointers. FIXME. */
+ case 'P': /* Large pointer. */
+ {
+ debug_type t;
+
+ if (! ieee_read_type_index (info, pp, &t))
+ return false;
+ type = debug_make_pointer_type (dhandle, t);
+ }
+ break;
+
+ case 'R':
+ /* Range. */
+ {
+ bfd_vma low, high, signedp, size;
+
+ if (! ieee_read_number (info, pp, &low)
+ || ! ieee_read_number (info, pp, &high)
+ || ! ieee_read_number (info, pp, &signedp)
+ || ! ieee_read_number (info, pp, &size))
+ return false;
+
+ type = debug_make_range_type (dhandle,
+ debug_make_int_type (dhandle, size,
+ ! signedp),
+ (bfd_signed_vma) low,
+ (bfd_signed_vma) high);
+ }
+ break;
+
+ case 'S': /* Struct. */
+ case 'U': /* Union. */
+ {
+ bfd_vma size;
+ unsigned int alloc;
+ debug_field *fields;
+ unsigned int c;
+
+ if (! ieee_read_number (info, pp, &size))
+ return false;
+
+ alloc = 10;
+ fields = (debug_field *) xmalloc (alloc * sizeof *fields);
+ c = 0;
+ while (1)
+ {
+ const char *name;
+ unsigned long namlen;
+ boolean present;
+ bfd_vma tindx;
+ bfd_vma offset;
+ debug_type ftype;
+ bfd_vma bitsize;
+
+ if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
+ return false;
+ if (! present)
+ break;
+ if (! ieee_read_number (info, pp, &tindx)
+ || ! ieee_read_number (info, pp, &offset))
+ return false;
+
+ if (tindx < 256)
+ {
+ ftype = ieee_builtin_type (info, ty_code_start, tindx);
+ bitsize = 0;
+ offset *= 8;
+ }
+ else
+ {
+ struct ieee_type *t;
+
+ tindx -= 256;
+ if (! ieee_alloc_type (info, tindx, true))
+ return false;
+ t = info->types.types + tindx;
+ ftype = t->type;
+ bitsize = t->bitsize;
+ if (bitsize == 0)
+ offset *= 8;
+ }
+
+ if (c + 1 >= alloc)
+ {
+ alloc += 10;
+ fields = ((debug_field *)
+ xrealloc (fields, alloc * sizeof *fields));
+ }
+
+ fields[c] = debug_make_field (dhandle, savestring (name, namlen),
+ ftype, offset, bitsize,
+ DEBUG_VISIBILITY_PUBLIC);
+ if (fields[c] == NULL)
+ return false;
+ ++c;
+ }
+
+ fields[c] = NULL;
+
+ type = debug_make_struct_type (dhandle, tc == 'S', size, fields);
+ tag = true;
+ }
+ break;
+
+ case 'T':
+ /* Typedef. */
+ if (! ieee_read_type_index (info, pp, &type))
+ return false;
+ typdef = true;
+ break;
+
+ case 'X':
+ /* Procedure. FIXME: This is an extern declaration, which we
+ have no way of representing. */
+ {
+ bfd_vma attr;
+ debug_type rtype;
+ bfd_vma nargs;
+ boolean present;
+ struct ieee_var *pv;
+
+ /* FIXME: We ignore the attribute and the argument names. */
+
+ if (! ieee_read_number (info, pp, &attr)
+ || ! ieee_read_type_index (info, pp, &rtype)
+ || ! ieee_read_number (info, pp, &nargs))
+ return false;
+ do
+ {
+ const char *name;
+ unsigned long namlen;
+
+ if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
+ return false;
+ }
+ while (present);
+
+ pv = info->vars.vars + varindx;
+ pv->kind = IEEE_EXTERNAL;
+ if (pv->namlen > 0
+ && debug_get_type_kind (dhandle, rtype) == DEBUG_KIND_POINTER)
+ {
+ /* Set up the return type as an indirect type pointing to
+ the variable slot, so that we can change it to a
+ reference later if appropriate. */
+ pv->pslot = (debug_type *) xmalloc (sizeof *pv->pslot);
+ *pv->pslot = rtype;
+ rtype = debug_make_indirect_type (dhandle, pv->pslot,
+ (const char *) NULL);
+ }
+
+ type = debug_make_function_type (dhandle, rtype, (debug_type *) NULL,
+ false);
+ }
+ break;
+
+ case 'V':
+ /* Void. This is not documented, but the MRI compiler emits it. */
+ type = debug_make_void_type (dhandle);
+ break;
+
+ case 'Z':
+ /* Array with 0 lower bound. */
+ {
+ debug_type etype;
+ bfd_vma high;
+
+ if (! ieee_read_type_index (info, pp, &etype)
+ || ! ieee_read_number (info, pp, &high))
+ return false;
+
+ type = debug_make_array_type (dhandle, etype,
+ ieee_builtin_type (info, ty_code_start,
+ ((unsigned int)
+ builtin_int)),
+ 0, (bfd_signed_vma) high, false);
+ }
+ break;
+
+ case 'c': /* Complex. */
+ case 'd': /* Double complex. */
+ {
+ const char *name;
+ unsigned long namlen;
+
+ /* FIXME: I don't know what the name means. */
+
+ if (! ieee_read_id (info, pp, &name, &namlen))
+ return false;
+
+ type = debug_make_complex_type (dhandle, tc == 'c' ? 4 : 8);
+ }
+ break;
+
+ case 'f':
+ /* Pascal file name. FIXME. */
+ ieee_error (info, ty_code_start, "Pascal file name not supported");
+ return false;
+
+ case 'g':
+ /* Bitfield type. */
+ {
+ bfd_vma signedp, bitsize, dummy;
+ const bfd_byte *hold;
+ boolean present;
+
+ if (! ieee_read_number (info, pp, &signedp)
+ || ! ieee_read_number (info, pp, &bitsize))
+ return false;
+
+ /* I think the documentation says that there is a type index,
+ but some actual files do not have one. */
+ hold = *pp;
+ if (! ieee_read_optional_number (info, pp, &dummy, &present))
+ return false;
+ if (! present)
+ {
+ /* FIXME: This is just a guess. */
+ type = debug_make_int_type (dhandle, 4,
+ signedp ? false : true);
+ }
+ else
+ {
+ *pp = hold;
+ if (! ieee_read_type_index (info, pp, &type))
+ return false;
+ }
+ type_bitsize = bitsize;
+ }
+ break;
+
+ case 'n':
+ /* Qualifier. */
+ {
+ bfd_vma kind;
+ debug_type t;
+
+ if (! ieee_read_number (info, pp, &kind)
+ || ! ieee_read_type_index (info, pp, &t))
+ return false;
+
+ switch (kind)
+ {
+ default:
+ ieee_error (info, ty_start, "unsupported qualifer");
+ return false;
+
+ case 1:
+ type = debug_make_const_type (dhandle, t);
+ break;
+
+ case 2:
+ type = debug_make_volatile_type (dhandle, t);
+ break;
+ }
+ }
+ break;
+
+ case 's':
+ /* Set. */
+ {
+ bfd_vma size;
+ debug_type etype;
+
+ if (! ieee_read_number (info, pp, &size)
+ || ! ieee_read_type_index (info, pp, &etype))
+ return false;
+
+ /* FIXME: We ignore the size. */
+
+ type = debug_make_set_type (dhandle, etype, false);
+ }
+ break;
+
+ case 'x':
+ /* Procedure with compiler dependencies. */
+ {
+ struct ieee_var *pv;
+ bfd_vma attr, frame_type, push_mask, nargs, level, father;
+ debug_type rtype;
+ debug_type *arg_types;
+ boolean varargs;
+ boolean present;
+
+ /* FIXME: We ignore some of this information. */
+
+ pv = info->vars.vars + varindx;
+
+ if (! ieee_read_number (info, pp, &attr)
+ || ! ieee_read_number (info, pp, &frame_type)
+ || ! ieee_read_number (info, pp, &push_mask)
+ || ! ieee_read_type_index (info, pp, &rtype)
+ || ! ieee_read_number (info, pp, &nargs))
+ return false;
+ if (nargs == (bfd_vma) -1)
+ {
+ arg_types = NULL;
+ varargs = false;
+ }
+ else
+ {
+ unsigned int i;
+
+ arg_types = ((debug_type *)
+ xmalloc ((nargs + 1) * sizeof *arg_types));
+ for (i = 0; i < nargs; i++)
+ if (! ieee_read_type_index (info, pp, arg_types + i))
+ return false;
+
+ /* If the last type is pointer to void, this is really a
+ varargs function. */
+ varargs = false;
+ if (nargs > 0)
+ {
+ debug_type last;
+
+ last = arg_types[nargs - 1];
+ if (debug_get_type_kind (dhandle, last) == DEBUG_KIND_POINTER
+ && (debug_get_type_kind (dhandle,
+ debug_get_target_type (dhandle,
+ last))
+ == DEBUG_KIND_VOID))
+ {
+ --nargs;
+ varargs = true;
+ }
+ }
+
+ /* If there are any pointer arguments, turn them into
+ indirect types in case we later need to convert them to
+ reference types. */
+ for (i = 0; i < nargs; i++)
+ {
+ if (debug_get_type_kind (dhandle, arg_types[i])
+ == DEBUG_KIND_POINTER)
+ {
+ if (arg_slots == NULL)
+ {
+ arg_slots = ((debug_type *)
+ xmalloc (nargs * sizeof *arg_slots));
+ memset (arg_slots, 0, nargs * sizeof *arg_slots);
+ }
+ arg_slots[i] = arg_types[i];
+ arg_types[i] =
+ debug_make_indirect_type (dhandle,
+ arg_slots + i,
+ (const char *) NULL);
+ }
+ }
+
+ arg_types[nargs] = DEBUG_TYPE_NULL;
+ }
+ if (! ieee_read_number (info, pp, &level)
+ || ! ieee_read_optional_number (info, pp, &father, &present))
+ return false;
+
+ /* We can't distinguish between a global function and a static
+ function. */
+ pv->kind = IEEE_FUNCTION;
+
+ if (pv->namlen > 0
+ && debug_get_type_kind (dhandle, rtype) == DEBUG_KIND_POINTER)
+ {
+ /* Set up the return type as an indirect type pointing to
+ the variable slot, so that we can change it to a
+ reference later if appropriate. */
+ pv->pslot = (debug_type *) xmalloc (sizeof *pv->pslot);
+ *pv->pslot = rtype;
+ rtype = debug_make_indirect_type (dhandle, pv->pslot,
+ (const char *) NULL);
+ }
+
+ type = debug_make_function_type (dhandle, rtype, arg_types, varargs);
+ }
+ break;
+ }
+
+ /* Record the type in the table. */
+
+ if (type == DEBUG_TYPE_NULL)
+ return false;
+
+ info->vars.vars[varindx].type = type;
+
+ if ((tag || typdef)
+ && info->vars.vars[varindx].namlen > 0)
+ {
+ const char *name;
+
+ name = savestring (info->vars.vars[varindx].name,
+ info->vars.vars[varindx].namlen);
+ if (typdef)
+ type = debug_name_type (dhandle, name, type);
+ else if (tc == 'E' || tc == 'N')
+ type = debug_tag_type (dhandle, name, type);
+ else
+ {
+ struct ieee_tag *it;
+
+ /* We must allocate all struct tags as indirect types, so
+ that if we later see a definition of the tag as a C++
+ record we can update the indirect slot and automatically
+ change all the existing references. */
+ it = (struct ieee_tag *) xmalloc (sizeof *it);
+ memset (it, 0, sizeof *it);
+ it->next = info->tags;
+ info->tags = it;
+ it->name = name;
+ it->slot = type;
+
+ type = debug_make_indirect_type (dhandle, &it->slot, name);
+ type = debug_tag_type (dhandle, name, type);
+
+ it->type = type;
+ }
+ if (type == NULL)
+ return false;
+ }
+
+ info->types.types[typeindx].type = type;
+ info->types.types[typeindx].arg_slots = arg_slots;
+ info->types.types[typeindx].bitsize = type_bitsize;
+
+ /* We may have already allocated type as an indirect type pointing
+ to slot. It does no harm to replace the indirect type with the
+ real type. Filling in slot as well handles the indirect types
+ which are already hanging around. */
+ if (info->types.types[typeindx].pslot != NULL)
+ *info->types.types[typeindx].pslot = type;
+
+ return true;
+}
+
+/* Parse an ATN record. */
+
+static boolean
+parse_ieee_atn (info, pp)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+{
+ const bfd_byte *atn_start, *atn_code_start;
+ bfd_vma varindx;
+ struct ieee_var *pvar;
+ debug_type type;
+ bfd_vma atn_code;
+ PTR dhandle;
+ bfd_vma v, v2, v3, v4, v5;
+ const char *name;
+ unsigned long namlen;
+ char *namcopy;
+ boolean present;
+ int blocktype;
+
+ atn_start = *pp;
+
+ if (! ieee_read_number (info, pp, &varindx)
+ || ! ieee_read_type_index (info, pp, &type))
+ return false;
+
+ atn_code_start = *pp;
+
+ if (! ieee_read_number (info, pp, &atn_code))
+ return false;
+
+ if (varindx == 0)
+ {
+ pvar = NULL;
+ name = "";
+ namlen = 0;
+ }
+ else if (varindx < 32)
+ {
+ ieee_error (info, atn_start, "illegal variable index");
+ return false;
+ }
+ else
+ {
+ varindx -= 32;
+ if (varindx >= info->vars.alloc
+ || info->vars.vars[varindx].name == NULL)
+ {
+ /* The MRI compiler or linker sometimes omits the NN record
+ for a pmisc record. */
+ if (atn_code == 62)
+ {
+ if (varindx >= info->vars.alloc)
+ {
+ unsigned int alloc;
+
+ alloc = info->vars.alloc;
+ if (alloc == 0)
+ alloc = 4;
+ while (varindx >= alloc)
+ alloc *= 2;
+ info->vars.vars = ((struct ieee_var *)
+ xrealloc (info->vars.vars,
+ (alloc
+ * sizeof *info->vars.vars)));
+ memset (info->vars.vars + info->vars.alloc, 0,
+ ((alloc - info->vars.alloc)
+ * sizeof *info->vars.vars));
+ info->vars.alloc = alloc;
+ }
+
+ pvar = info->vars.vars + varindx;
+ pvar->name = "";
+ pvar->namlen = 0;
+ }
+ else
+ {
+ ieee_error (info, atn_start, "undefined variable in ATN");
+ return false;
+ }
+ }
+
+ pvar = info->vars.vars + varindx;
+
+ pvar->type = type;
+
+ name = pvar->name;
+ namlen = pvar->namlen;
+ }
+
+ dhandle = info->dhandle;
+
+ /* If we are going to call debug_record_variable with a pointer
+ type, change the type to an indirect type so that we can later
+ change it to a reference type if we encounter a C++ pmisc 'R'
+ record. */
+ if (pvar != NULL
+ && type != DEBUG_TYPE_NULL
+ && debug_get_type_kind (dhandle, type) == DEBUG_KIND_POINTER)
+ {
+ switch (atn_code)
+ {
+ case 1:
+ case 2:
+ case 3:
+ case 5:
+ case 8:
+ case 10:
+ pvar->pslot = (debug_type *) xmalloc (sizeof *pvar->pslot);
+ *pvar->pslot = type;
+ type = debug_make_indirect_type (dhandle, pvar->pslot,
+ (const char *) NULL);
+ pvar->type = type;
+ break;
+ }
+ }
+
+ switch (atn_code)
+ {
+ default:
+ ieee_error (info, atn_code_start, "unknown ATN type");
+ return false;
+
+ case 1:
+ /* Automatic variable. */
+ if (! ieee_read_number (info, pp, &v))
+ return false;
+ namcopy = savestring (name, namlen);
+ if (type == NULL)
+ type = debug_make_void_type (dhandle);
+ if (pvar != NULL)
+ pvar->kind = IEEE_LOCAL;
+ return debug_record_variable (dhandle, namcopy, type, DEBUG_LOCAL, v);
+
+ case 2:
+ /* Register variable. */
+ if (! ieee_read_number (info, pp, &v))
+ return false;
+ namcopy = savestring (name, namlen);
+ if (type == NULL)
+ type = debug_make_void_type (dhandle);
+ if (pvar != NULL)
+ pvar->kind = IEEE_LOCAL;
+ return debug_record_variable (dhandle, namcopy, type, DEBUG_REGISTER,
+ ieee_regno_to_genreg (info->abfd, v));
+
+ case 3:
+ /* Static variable. */
+ if (! ieee_require_asn (info, pp, &v))
+ return false;
+ namcopy = savestring (name, namlen);
+ if (type == NULL)
+ type = debug_make_void_type (dhandle);
+ if (info->blockstack.bsp <= info->blockstack.stack)
+ blocktype = 0;
+ else
+ blocktype = info->blockstack.bsp[-1].kind;
+ if (pvar != NULL)
+ {
+ if (blocktype == 4 || blocktype == 6)
+ pvar->kind = IEEE_LOCAL;
+ else
+ pvar->kind = IEEE_STATIC;
+ }
+ return debug_record_variable (dhandle, namcopy, type,
+ (blocktype == 4 || blocktype == 6
+ ? DEBUG_LOCAL_STATIC
+ : DEBUG_STATIC),
+ v);
+
+ case 4:
+ /* External function. We don't currently record these. FIXME. */
+ if (pvar != NULL)
+ pvar->kind = IEEE_EXTERNAL;
+ return true;
+
+ case 5:
+ /* External variable. We don't currently record these. FIXME. */
+ if (pvar != NULL)
+ pvar->kind = IEEE_EXTERNAL;
+ return true;
+
+ case 7:
+ if (! ieee_read_number (info, pp, &v)
+ || ! ieee_read_number (info, pp, &v2)
+ || ! ieee_read_optional_number (info, pp, &v3, &present))
+ return false;
+ if (present)
+ {
+ if (! ieee_read_optional_number (info, pp, &v4, &present))
+ return false;
+ }
+
+ /* We just ignore the two optional fields in v3 and v4, since
+ they are not defined. */
+
+ if (! ieee_require_asn (info, pp, &v3))
+ return false;
+
+ /* We have no way to record the column number. FIXME. */
+
+ return debug_record_line (dhandle, v, v3);
+
+ case 8:
+ /* Global variable. */
+ if (! ieee_require_asn (info, pp, &v))
+ return false;
+ namcopy = savestring (name, namlen);
+ if (type == NULL)
+ type = debug_make_void_type (dhandle);
+ if (pvar != NULL)
+ pvar->kind = IEEE_GLOBAL;
+ return debug_record_variable (dhandle, namcopy, type, DEBUG_GLOBAL, v);
+
+ case 9:
+ /* Variable lifetime information. */
+ if (! ieee_read_number (info, pp, &v))
+ return false;
+
+ /* We have no way to record this information. FIXME. */
+ return true;
+
+ case 10:
+ /* Locked register. The spec says that there are two required
+ fields, but at least on occasion the MRI compiler only emits
+ one. */
+ if (! ieee_read_number (info, pp, &v)
+ || ! ieee_read_optional_number (info, pp, &v2, &present))
+ return false;
+
+ /* I think this means a variable that is both in a register and
+ a frame slot. We ignore the frame slot. FIXME. */
+
+ namcopy = savestring (name, namlen);
+ if (type == NULL)
+ type = debug_make_void_type (dhandle);
+ if (pvar != NULL)
+ pvar->kind = IEEE_LOCAL;
+ return debug_record_variable (dhandle, namcopy, type, DEBUG_REGISTER, v);
+
+ case 11:
+ /* Reserved for FORTRAN common. */
+ ieee_error (info, atn_code_start, "unsupported ATN11");
+
+ /* Return true to keep going. */
+ return true;
+
+ case 12:
+ /* Based variable. */
+ v3 = 0;
+ v4 = 0x80;
+ v5 = 0;
+ if (! ieee_read_number (info, pp, &v)
+ || ! ieee_read_number (info, pp, &v2)
+ || ! ieee_read_optional_number (info, pp, &v3, &present))
+ return false;
+ if (present)
+ {
+ if (! ieee_read_optional_number (info, pp, &v4, &present))
+ return false;
+ if (present)
+ {
+ if (! ieee_read_optional_number (info, pp, &v5, &present))
+ return false;
+ }
+ }
+
+ /* We have no way to record this information. FIXME. */
+
+ ieee_error (info, atn_code_start, "unsupported ATN12");
+
+ /* Return true to keep going. */
+ return true;
+
+ case 16:
+ /* Constant. The description of this that I have is ambiguous,
+ so I'm not going to try to implement it. */
+ if (! ieee_read_number (info, pp, &v)
+ || ! ieee_read_optional_number (info, pp, &v2, &present))
+ return false;
+ if (present)
+ {
+ if (! ieee_read_optional_number (info, pp, &v2, &present))
+ return false;
+ if (present)
+ {
+ if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
+ return false;
+ }
+ }
+
+ if ((ieee_record_enum_type) **pp == ieee_e2_first_byte_enum)
+ {
+ if (! ieee_require_asn (info, pp, &v3))
+ return false;
+ }
+
+ return true;
+
+ case 19:
+ /* Static variable from assembler. */
+ v2 = 0;
+ if (! ieee_read_number (info, pp, &v)
+ || ! ieee_read_optional_number (info, pp, &v2, &present)
+ || ! ieee_require_asn (info, pp, &v3))
+ return false;
+ namcopy = savestring (name, namlen);
+ /* We don't really handle this correctly. FIXME. */
+ return debug_record_variable (dhandle, namcopy,
+ debug_make_void_type (dhandle),
+ v2 != 0 ? DEBUG_GLOBAL : DEBUG_STATIC,
+ v3);
+
+ case 62:
+ /* Procedure miscellaneous information. */
+ case 63:
+ /* Variable miscellaneous information. */
+ case 64:
+ /* Module miscellaneous information. */
+ if (! ieee_read_number (info, pp, &v)
+ || ! ieee_read_number (info, pp, &v2)
+ || ! ieee_read_optional_id (info, pp, &name, &namlen, &present))
+ return false;
+
+ if (atn_code == 62 && v == 80)
+ {
+ if (present)
+ {
+ ieee_error (info, atn_code_start,
+ "unexpected string in C++ misc");
+ return false;
+ }
+ return ieee_read_cxx_misc (info, pp, v2);
+ }
+
+ /* We just ignore all of this stuff. FIXME. */
+
+ for (; v2 > 0; --v2)
+ {
+ switch ((ieee_record_enum_type) **pp)
+ {
+ default:
+ ieee_error (info, *pp, "bad misc record");
+ return false;
+
+ case ieee_at_record_enum:
+ if (! ieee_require_atn65 (info, pp, &name, &namlen))
+ return false;
+ break;
+
+ case ieee_e2_first_byte_enum:
+ if (! ieee_require_asn (info, pp, &v3))
+ return false;
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ /*NOTREACHED*/
+}
+
+/* Handle C++ debugging miscellaneous records. This is called for
+ procedure miscellaneous records of type 80. */
+
+static boolean
+ieee_read_cxx_misc (info, pp, count)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ unsigned long count;
+{
+ const bfd_byte *start;
+ bfd_vma category;
+
+ start = *pp;
+
+ /* Get the category of C++ misc record. */
+ if (! ieee_require_asn (info, pp, &category))
+ return false;
+ --count;
+
+ switch (category)
+ {
+ default:
+ ieee_error (info, start, "unrecognized C++ misc record");
+ return false;
+
+ case 'T':
+ if (! ieee_read_cxx_class (info, pp, count))
+ return false;
+ break;
+
+ case 'M':
+ {
+ bfd_vma flags;
+ const char *name;
+ unsigned long namlen;
+
+ /* The IEEE spec indicates that the 'M' record only has a
+ flags field. The MRI compiler also emits the name of the
+ function. */
+
+ if (! ieee_require_asn (info, pp, &flags))
+ return false;
+ if (*pp < info->pend
+ && (ieee_record_enum_type) **pp == ieee_at_record_enum)
+ {
+ if (! ieee_require_atn65 (info, pp, &name, &namlen))
+ return false;
+ }
+
+ /* This is emitted for method functions, but I don't think we
+ care very much. It might help if it told us useful
+ information like the class with which this function is
+ associated, but it doesn't, so it isn't helpful. */
+ }
+ break;
+
+ case 'B':
+ if (! ieee_read_cxx_defaults (info, pp, count))
+ return false;
+ break;
+
+ case 'z':
+ {
+ const char *name, *mangled, *class;
+ unsigned long namlen, mangledlen, classlen;
+ bfd_vma control;
+
+ /* Pointer to member. */
+
+ if (! ieee_require_atn65 (info, pp, &name, &namlen)
+ || ! ieee_require_atn65 (info, pp, &mangled, &mangledlen)
+ || ! ieee_require_atn65 (info, pp, &class, &classlen)
+ || ! ieee_require_asn (info, pp, &control))
+ return false;
+
+ /* FIXME: We should now track down name and change its type. */
+ }
+ break;
+
+ case 'R':
+ if (! ieee_read_reference (info, pp))
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+/* Read a C++ class definition. This is a pmisc type 80 record of
+ category 'T'. */
+
+static boolean
+ieee_read_cxx_class (info, pp, count)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ unsigned long count;
+{
+ const bfd_byte *start;
+ bfd_vma class;
+ const char *tag;
+ unsigned long taglen;
+ struct ieee_tag *it;
+ PTR dhandle;
+ debug_field *fields;
+ unsigned int field_count, field_alloc;
+ debug_baseclass *baseclasses;
+ unsigned int baseclasses_count, baseclasses_alloc;
+ const debug_field *structfields;
+ struct ieee_method
+ {
+ const char *name;
+ unsigned long namlen;
+ debug_method_variant *variants;
+ unsigned count;
+ unsigned int alloc;
+ } *methods;
+ unsigned int methods_count, methods_alloc;
+ debug_type vptrbase;
+ boolean ownvptr;
+ debug_method *dmethods;
+
+ start = *pp;
+
+ if (! ieee_require_asn (info, pp, &class))
+ return false;
+ --count;
+
+ if (! ieee_require_atn65 (info, pp, &tag, &taglen))
+ return false;
+ --count;
+
+ /* Find the C struct with this name. */
+ for (it = info->tags; it != NULL; it = it->next)
+ if (it->name[0] == tag[0]
+ && strncmp (it->name, tag, taglen) == 0
+ && strlen (it->name) == taglen)
+ break;
+ if (it == NULL)
+ {
+ ieee_error (info, start, "undefined C++ object");
+ return false;
+ }
+
+ dhandle = info->dhandle;
+
+ fields = NULL;
+ field_count = 0;
+ field_alloc = 0;
+ baseclasses = NULL;
+ baseclasses_count = 0;
+ baseclasses_alloc = 0;
+ methods = NULL;
+ methods_count = 0;
+ methods_alloc = 0;
+ vptrbase = DEBUG_TYPE_NULL;
+ ownvptr = false;
+
+ structfields = debug_get_fields (dhandle, it->type);
+
+ while (count > 0)
+ {
+ bfd_vma id;
+ const bfd_byte *spec_start;
+
+ spec_start = *pp;
+
+ if (! ieee_require_asn (info, pp, &id))
+ return false;
+ --count;
+
+ switch (id)
+ {
+ default:
+ ieee_error (info, spec_start, "unrecognized C++ object spec");
+ return false;
+
+ case 'b':
+ {
+ bfd_vma flags, cinline;
+ const char *basename, *fieldname;
+ unsigned long baselen, fieldlen;
+ char *basecopy;
+ debug_type basetype;
+ bfd_vma bitpos;
+ boolean virtualp;
+ enum debug_visibility visibility;
+ debug_baseclass baseclass;
+
+ /* This represents a base or friend class. */
+
+ if (! ieee_require_asn (info, pp, &flags)
+ || ! ieee_require_atn65 (info, pp, &basename, &baselen)
+ || ! ieee_require_asn (info, pp, &cinline)
+ || ! ieee_require_atn65 (info, pp, &fieldname, &fieldlen))
+ return false;
+ count -= 4;
+
+ /* We have no way of recording friend information, so we
+ just ignore it. */
+ if ((flags & BASEFLAGS_FRIEND) != 0)
+ break;
+
+ /* I assume that either all of the members of the
+ baseclass are included in the object, starting at the
+ beginning of the object, or that none of them are
+ included. */
+
+ if ((fieldlen == 0) == (cinline == 0))
+ {
+ ieee_error (info, start, "unsupported C++ object type");
+ return false;
+ }
+
+ basecopy = savestring (basename, baselen);
+ basetype = debug_find_tagged_type (dhandle, basecopy,
+ DEBUG_KIND_ILLEGAL);
+ free (basecopy);
+ if (basetype == DEBUG_TYPE_NULL)
+ {
+ ieee_error (info, start, "C++ base class not defined");
+ return false;
+ }
+
+ if (fieldlen == 0)
+ bitpos = 0;
+ else
+ {
+ const debug_field *pf;
+
+ if (structfields == NULL)
+ {
+ ieee_error (info, start, "C++ object has no fields");
+ return false;
+ }
+
+ for (pf = structfields; *pf != DEBUG_FIELD_NULL; pf++)
+ {
+ const char *fname;
+
+ fname = debug_get_field_name (dhandle, *pf);
+ if (fname == NULL)
+ return false;
+ if (fname[0] == fieldname[0]
+ && strncmp (fname, fieldname, fieldlen) == 0
+ && strlen (fname) == fieldlen)
+ break;
+ }
+ if (*pf == DEBUG_FIELD_NULL)
+ {
+ ieee_error (info, start,
+ "C++ base class not found in container");
+ return false;
+ }
+
+ bitpos = debug_get_field_bitpos (dhandle, *pf);
+ }
+
+ if ((flags & BASEFLAGS_VIRTUAL) != 0)
+ virtualp = true;
+ else
+ virtualp = false;
+ if ((flags & BASEFLAGS_PRIVATE) != 0)
+ visibility = DEBUG_VISIBILITY_PRIVATE;
+ else
+ visibility = DEBUG_VISIBILITY_PUBLIC;
+
+ baseclass = debug_make_baseclass (dhandle, basetype, bitpos,
+ virtualp, visibility);
+ if (baseclass == DEBUG_BASECLASS_NULL)
+ return false;
+
+ if (baseclasses_count + 1 >= baseclasses_alloc)
+ {
+ baseclasses_alloc += 10;
+ baseclasses = ((debug_baseclass *)
+ xrealloc (baseclasses,
+ (baseclasses_alloc
+ * sizeof *baseclasses)));
+ }
+
+ baseclasses[baseclasses_count] = baseclass;
+ ++baseclasses_count;
+ baseclasses[baseclasses_count] = DEBUG_BASECLASS_NULL;
+ }
+ break;
+
+ case 'd':
+ {
+ bfd_vma flags;
+ const char *fieldname, *mangledname;
+ unsigned long fieldlen, mangledlen;
+ char *fieldcopy;
+ boolean staticp;
+ debug_type ftype;
+ const debug_field *pf = NULL;
+ enum debug_visibility visibility;
+ debug_field field;
+
+ /* This represents a data member. */
+
+ if (! ieee_require_asn (info, pp, &flags)
+ || ! ieee_require_atn65 (info, pp, &fieldname, &fieldlen)
+ || ! ieee_require_atn65 (info, pp, &mangledname, &mangledlen))
+ return false;
+ count -= 3;
+
+ fieldcopy = savestring (fieldname, fieldlen);
+
+ staticp = (flags & CXXFLAGS_STATIC) != 0 ? true : false;
+
+ if (staticp)
+ {
+ struct ieee_var *pv, *pvend;
+
+ /* See if we can find a definition for this variable. */
+ pv = info->vars.vars;
+ pvend = pv + info->vars.alloc;
+ for (; pv < pvend; pv++)
+ if (pv->namlen == mangledlen
+ && strncmp (pv->name, mangledname, mangledlen) == 0)
+ break;
+ if (pv < pvend)
+ ftype = pv->type;
+ else
+ {
+ /* This can happen if the variable is never used. */
+ ftype = ieee_builtin_type (info, start,
+ (unsigned int) builtin_void);
+ }
+ }
+ else
+ {
+ unsigned int findx;
+
+ if (structfields == NULL)
+ {
+ ieee_error (info, start, "C++ object has no fields");
+ return false;
+ }
+
+ for (pf = structfields, findx = 0;
+ *pf != DEBUG_FIELD_NULL;
+ pf++, findx++)
+ {
+ const char *fname;
+
+ fname = debug_get_field_name (dhandle, *pf);
+ if (fname == NULL)
+ return false;
+ if (fname[0] == mangledname[0]
+ && strncmp (fname, mangledname, mangledlen) == 0
+ && strlen (fname) == mangledlen)
+ break;
+ }
+ if (*pf == DEBUG_FIELD_NULL)
+ {
+ ieee_error (info, start,
+ "C++ data member not found in container");
+ return false;
+ }
+
+ ftype = debug_get_field_type (dhandle, *pf);
+
+ if (debug_get_type_kind (dhandle, ftype) == DEBUG_KIND_POINTER)
+ {
+ /* We might need to convert this field into a
+ reference type later on, so make it an indirect
+ type. */
+ if (it->fslots == NULL)
+ {
+ unsigned int fcnt;
+ const debug_field *pfcnt;
+
+ fcnt = 0;
+ for (pfcnt = structfields;
+ *pfcnt != DEBUG_FIELD_NULL;
+ pfcnt++)
+ ++fcnt;
+ it->fslots = ((debug_type *)
+ xmalloc (fcnt * sizeof *it->fslots));
+ memset (it->fslots, 0,
+ fcnt * sizeof *it->fslots);
+ }
+
+ if (ftype == DEBUG_TYPE_NULL)
+ return false;
+ it->fslots[findx] = ftype;
+ ftype = debug_make_indirect_type (dhandle,
+ it->fslots + findx,
+ (const char *) NULL);
+ }
+ }
+ if (ftype == DEBUG_TYPE_NULL)
+ return false;
+
+ switch (flags & CXXFLAGS_VISIBILITY)
+ {
+ default:
+ ieee_error (info, start, "unknown C++ visibility");
+ return false;
+
+ case CXXFLAGS_VISIBILITY_PUBLIC:
+ visibility = DEBUG_VISIBILITY_PUBLIC;
+ break;
+
+ case CXXFLAGS_VISIBILITY_PRIVATE:
+ visibility = DEBUG_VISIBILITY_PRIVATE;
+ break;
+
+ case CXXFLAGS_VISIBILITY_PROTECTED:
+ visibility = DEBUG_VISIBILITY_PROTECTED;
+ break;
+ }
+
+ if (staticp)
+ {
+ char *mangledcopy;
+
+ mangledcopy = savestring (mangledname, mangledlen);
+
+ field = debug_make_static_member (dhandle, fieldcopy,
+ ftype, mangledcopy,
+ visibility);
+ }
+ else
+ {
+ bfd_vma bitpos, bitsize;
+
+ bitpos = debug_get_field_bitpos (dhandle, *pf);
+ bitsize = debug_get_field_bitsize (dhandle, *pf);
+ if (bitpos == (bfd_vma) -1 || bitsize == (bfd_vma) -1)
+ {
+ ieee_error (info, start, "bad C++ field bit pos or size");
+ return false;
+ }
+ field = debug_make_field (dhandle, fieldcopy, ftype, bitpos,
+ bitsize, visibility);
+ }
+
+ if (field == DEBUG_FIELD_NULL)
+ return false;
+
+ if (field_count + 1 >= field_alloc)
+ {
+ field_alloc += 10;
+ fields = ((debug_field *)
+ xrealloc (fields, field_alloc * sizeof *fields));
+ }
+
+ fields[field_count] = field;
+ ++field_count;
+ fields[field_count] = DEBUG_FIELD_NULL;
+ }
+ break;
+
+ case 'm':
+ case 'v':
+ {
+ bfd_vma flags, voffset, control;
+ const char *name, *mangled;
+ unsigned long namlen, mangledlen;
+ struct ieee_var *pv, *pvend;
+ debug_type type;
+ enum debug_visibility visibility;
+ boolean constp, volatilep;
+ char *mangledcopy;
+ debug_method_variant mv;
+ struct ieee_method *meth;
+ unsigned int im;
+
+ if (! ieee_require_asn (info, pp, &flags)
+ || ! ieee_require_atn65 (info, pp, &name, &namlen)
+ || ! ieee_require_atn65 (info, pp, &mangled, &mangledlen))
+ return false;
+ count -= 3;
+ if (id != 'v')
+ voffset = 0;
+ else
+ {
+ if (! ieee_require_asn (info, pp, &voffset))
+ return false;
+ --count;
+ }
+ if (! ieee_require_asn (info, pp, &control))
+ return false;
+ --count;
+
+ /* We just ignore the control information. */
+
+ /* We have no way to represent friend information, so we
+ just ignore it. */
+ if ((flags & CXXFLAGS_FRIEND) != 0)
+ break;
+
+ /* We should already have seen a type for the function. */
+ pv = info->vars.vars;
+ pvend = pv + info->vars.alloc;
+ for (; pv < pvend; pv++)
+ if (pv->namlen == mangledlen
+ && strncmp (pv->name, mangled, mangledlen) == 0)
+ break;
+
+ if (pv >= pvend)
+ {
+ /* We won't have type information for this function if
+ it is not included in this file. We don't try to
+ handle this case. FIXME. */
+ type = (debug_make_function_type
+ (dhandle,
+ ieee_builtin_type (info, start,
+ (unsigned int) builtin_void),
+ (debug_type *) NULL,
+ false));
+ }
+ else
+ {
+ debug_type return_type;
+ const debug_type *arg_types;
+ boolean varargs;
+
+ if (debug_get_type_kind (dhandle, pv->type)
+ != DEBUG_KIND_FUNCTION)
+ {
+ ieee_error (info, start,
+ "bad type for C++ method function");
+ return false;
+ }
+
+ return_type = debug_get_return_type (dhandle, pv->type);
+ arg_types = debug_get_parameter_types (dhandle, pv->type,
+ &varargs);
+ if (return_type == DEBUG_TYPE_NULL || arg_types == NULL)
+ {
+ ieee_error (info, start,
+ "no type information for C++ method function");
+ return false;
+ }
+
+ type = debug_make_method_type (dhandle, return_type, it->type,
+ (debug_type *) arg_types,
+ varargs);
+ }
+ if (type == DEBUG_TYPE_NULL)
+ return false;
+
+ switch (flags & CXXFLAGS_VISIBILITY)
+ {
+ default:
+ ieee_error (info, start, "unknown C++ visibility");
+ return false;
+
+ case CXXFLAGS_VISIBILITY_PUBLIC:
+ visibility = DEBUG_VISIBILITY_PUBLIC;
+ break;
+
+ case CXXFLAGS_VISIBILITY_PRIVATE:
+ visibility = DEBUG_VISIBILITY_PRIVATE;
+ break;
+
+ case CXXFLAGS_VISIBILITY_PROTECTED:
+ visibility = DEBUG_VISIBILITY_PROTECTED;
+ break;
+ }
+
+ constp = (flags & CXXFLAGS_CONST) != 0 ? true : false;
+ volatilep = (flags & CXXFLAGS_VOLATILE) != 0 ? true : false;
+
+ mangledcopy = savestring (mangled, mangledlen);
+
+ if ((flags & CXXFLAGS_STATIC) != 0)
+ {
+ if (id == 'v')
+ {
+ ieee_error (info, start, "C++ static virtual method");
+ return false;
+ }
+ mv = debug_make_static_method_variant (dhandle, mangledcopy,
+ type, visibility,
+ constp, volatilep);
+ }
+ else
+ {
+ debug_type vcontext;
+
+ if (id != 'v')
+ vcontext = DEBUG_TYPE_NULL;
+ else
+ {
+ /* FIXME: How can we calculate this correctly? */
+ vcontext = it->type;
+ }
+ mv = debug_make_method_variant (dhandle, mangledcopy, type,
+ visibility, constp,
+ volatilep, voffset,
+ vcontext);
+ }
+ if (mv == DEBUG_METHOD_VARIANT_NULL)
+ return false;
+
+ for (meth = methods, im = 0; im < methods_count; meth++, im++)
+ if (meth->namlen == namlen
+ && strncmp (meth->name, name, namlen) == 0)
+ break;
+ if (im >= methods_count)
+ {
+ if (methods_count >= methods_alloc)
+ {
+ methods_alloc += 10;
+ methods = ((struct ieee_method *)
+ xrealloc (methods,
+ methods_alloc * sizeof *methods));
+ }
+ methods[methods_count].name = name;
+ methods[methods_count].namlen = namlen;
+ methods[methods_count].variants = NULL;
+ methods[methods_count].count = 0;
+ methods[methods_count].alloc = 0;
+ meth = methods + methods_count;
+ ++methods_count;
+ }
+
+ if (meth->count + 1 >= meth->alloc)
+ {
+ meth->alloc += 10;
+ meth->variants = ((debug_method_variant *)
+ xrealloc (meth->variants,
+ (meth->alloc
+ * sizeof *meth->variants)));
+ }
+
+ meth->variants[meth->count] = mv;
+ ++meth->count;
+ meth->variants[meth->count] = DEBUG_METHOD_VARIANT_NULL;
+ }
+ break;
+
+ case 'o':
+ {
+ bfd_vma spec;
+
+ /* We have no way to store this information, so we just
+ ignore it. */
+ if (! ieee_require_asn (info, pp, &spec))
+ return false;
+ --count;
+ if ((spec & 4) != 0)
+ {
+ const char *filename;
+ unsigned long filenamlen;
+ bfd_vma lineno;
+
+ if (! ieee_require_atn65 (info, pp, &filename, &filenamlen)
+ || ! ieee_require_asn (info, pp, &lineno))
+ return false;
+ count -= 2;
+ }
+ else if ((spec & 8) != 0)
+ {
+ const char *mangled;
+ unsigned long mangledlen;
+
+ if (! ieee_require_atn65 (info, pp, &mangled, &mangledlen))
+ return false;
+ --count;
+ }
+ else
+ {
+ ieee_error (info, start,
+ "unrecognized C++ object overhead spec");
+ return false;
+ }
+ }
+ break;
+
+ case 'z':
+ {
+ const char *vname, *basename;
+ unsigned long vnamelen, baselen;
+ bfd_vma vsize, control;
+
+ /* A virtual table pointer. */
+
+ if (! ieee_require_atn65 (info, pp, &vname, &vnamelen)
+ || ! ieee_require_asn (info, pp, &vsize)
+ || ! ieee_require_atn65 (info, pp, &basename, &baselen)
+ || ! ieee_require_asn (info, pp, &control))
+ return false;
+ count -= 4;
+
+ /* We just ignore the control number. We don't care what
+ the virtual table name is. We have no way to store the
+ virtual table size, and I don't think we care anyhow. */
+
+ /* FIXME: We can't handle multiple virtual table pointers. */
+
+ if (baselen == 0)
+ ownvptr = true;
+ else
+ {
+ char *basecopy;
+
+ basecopy = savestring (basename, baselen);
+ vptrbase = debug_find_tagged_type (dhandle, basecopy,
+ DEBUG_KIND_ILLEGAL);
+ free (basecopy);
+ if (vptrbase == DEBUG_TYPE_NULL)
+ {
+ ieee_error (info, start, "undefined C++ vtable");
+ return false;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ /* Now that we have seen all the method variants, we can call
+ debug_make_method for each one. */
+
+ if (methods_count == 0)
+ dmethods = NULL;
+ else
+ {
+ unsigned int i;
+
+ dmethods = ((debug_method *)
+ xmalloc ((methods_count + 1) * sizeof *dmethods));
+ for (i = 0; i < methods_count; i++)
+ {
+ char *namcopy;
+
+ namcopy = savestring (methods[i].name, methods[i].namlen);
+ dmethods[i] = debug_make_method (dhandle, namcopy,
+ methods[i].variants);
+ if (dmethods[i] == DEBUG_METHOD_NULL)
+ return false;
+ }
+ dmethods[i] = DEBUG_METHOD_NULL;
+ free (methods);
+ }
+
+ /* The struct type was created as an indirect type pointing at
+ it->slot. We update it->slot to automatically update all
+ references to this struct. */
+ it->slot = debug_make_object_type (dhandle,
+ class != 'u',
+ debug_get_type_size (dhandle,
+ it->slot),
+ fields, baseclasses, dmethods,
+ vptrbase, ownvptr);
+ if (it->slot == DEBUG_TYPE_NULL)
+ return false;
+
+ return true;
+}
+
+/* Read C++ default argument value and reference type information. */
+
+static boolean
+ieee_read_cxx_defaults (info, pp, count)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ unsigned long count;
+{
+ const bfd_byte *start;
+ const char *fnname;
+ unsigned long fnlen;
+ bfd_vma defcount;
+
+ start = *pp;
+
+ /* Giving the function name before the argument count is an addendum
+ to the spec. The function name is demangled, though, so this
+ record must always refer to the current function. */
+
+ if (info->blockstack.bsp <= info->blockstack.stack
+ || info->blockstack.bsp[-1].fnindx == (unsigned int) -1)
+ {
+ ieee_error (info, start, "C++ default values not in a function");
+ return false;
+ }
+
+ if (! ieee_require_atn65 (info, pp, &fnname, &fnlen)
+ || ! ieee_require_asn (info, pp, &defcount))
+ return false;
+ count -= 2;
+
+ while (defcount-- > 0)
+ {
+ bfd_vma type, val;
+ const char *strval;
+ unsigned long strvallen;
+
+ if (! ieee_require_asn (info, pp, &type))
+ return false;
+ --count;
+
+ switch (type)
+ {
+ case 0:
+ case 4:
+ break;
+
+ case 1:
+ case 2:
+ if (! ieee_require_asn (info, pp, &val))
+ return false;
+ --count;
+ break;
+
+ case 3:
+ case 7:
+ if (! ieee_require_atn65 (info, pp, &strval, &strvallen))
+ return false;
+ --count;
+ break;
+
+ default:
+ ieee_error (info, start, "unrecognized C++ default type");
+ return false;
+ }
+
+ /* We have no way to record the default argument values, so we
+ just ignore them. FIXME. */
+ }
+
+ /* Any remaining arguments are indices of parameters that are really
+ reference type. */
+ if (count > 0)
+ {
+ PTR dhandle;
+ debug_type *arg_slots;
+
+ dhandle = info->dhandle;
+ arg_slots = info->types.types[info->blockstack.bsp[-1].fnindx].arg_slots;
+ while (count-- > 0)
+ {
+ bfd_vma indx;
+ debug_type target;
+
+ if (! ieee_require_asn (info, pp, &indx))
+ return false;
+ /* The index is 1 based. */
+ --indx;
+ if (arg_slots == NULL
+ || arg_slots[indx] == DEBUG_TYPE_NULL
+ || (debug_get_type_kind (dhandle, arg_slots[indx])
+ != DEBUG_KIND_POINTER))
+ {
+ ieee_error (info, start, "reference parameter is not a pointer");
+ return false;
+ }
+
+ target = debug_get_target_type (dhandle, arg_slots[indx]);
+ arg_slots[indx] = debug_make_reference_type (dhandle, target);
+ if (arg_slots[indx] == DEBUG_TYPE_NULL)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* Read a C++ reference definition. */
+
+static boolean
+ieee_read_reference (info, pp)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+{
+ const bfd_byte *start;
+ bfd_vma flags;
+ const char *class, *name;
+ unsigned long classlen, namlen;
+ debug_type *pslot;
+ debug_type target;
+
+ start = *pp;
+
+ if (! ieee_require_asn (info, pp, &flags))
+ return false;
+
+ /* Giving the class name before the member name is in an addendum to
+ the spec. */
+ if (flags == 3)
+ {
+ if (! ieee_require_atn65 (info, pp, &class, &classlen))
+ return false;
+ }
+
+ if (! ieee_require_atn65 (info, pp, &name, &namlen))
+ return false;
+
+ pslot = NULL;
+ if (flags != 3)
+ {
+ int pass;
+
+ /* We search from the last variable indices to the first in
+ hopes of finding local variables correctly. We search the
+ local variables on the first pass, and the global variables
+ on the second. FIXME: This probably won't work in all cases.
+ On the other hand, I don't know what will. */
+ for (pass = 0; pass < 2; pass++)
+ {
+ struct ieee_vars *vars;
+ int i;
+ struct ieee_var *pv = NULL;
+
+ if (pass == 0)
+ vars = &info->vars;
+ else
+ {
+ vars = info->global_vars;
+ if (vars == NULL)
+ break;
+ }
+
+ for (i = (int) vars->alloc - 1; i >= 0; i--)
+ {
+ boolean found;
+
+ pv = vars->vars + i;
+
+ if (pv->pslot == NULL
+ || pv->namlen != namlen
+ || strncmp (pv->name, name, namlen) != 0)
+ continue;
+
+ found = false;
+ switch (flags)
+ {
+ default:
+ ieee_error (info, start,
+ "unrecognized C++ reference type");
+ return false;
+
+ case 0:
+ /* Global variable or function. */
+ if (pv->kind == IEEE_GLOBAL
+ || pv->kind == IEEE_EXTERNAL
+ || pv->kind == IEEE_FUNCTION)
+ found = true;
+ break;
+
+ case 1:
+ /* Global static variable or function. */
+ if (pv->kind == IEEE_STATIC
+ || pv->kind == IEEE_FUNCTION)
+ found = true;
+ break;
+
+ case 2:
+ /* Local variable. */
+ if (pv->kind == IEEE_LOCAL)
+ found = true;
+ break;
+ }
+
+ if (found)
+ break;
+ }
+
+ if (i >= 0)
+ {
+ pslot = pv->pslot;
+ break;
+ }
+ }
+ }
+ else
+ {
+ struct ieee_tag *it;
+
+ for (it = info->tags; it != NULL; it = it->next)
+ {
+ if (it->name[0] == class[0]
+ && strncmp (it->name, class, classlen) == 0
+ && strlen (it->name) == classlen)
+ {
+ if (it->fslots != NULL)
+ {
+ const debug_field *pf;
+ unsigned int findx;
+
+ pf = debug_get_fields (info->dhandle, it->type);
+ if (pf == NULL)
+ {
+ ieee_error (info, start,
+ "C++ reference in class with no fields");
+ return false;
+ }
+
+ for (findx = 0; *pf != DEBUG_FIELD_NULL; pf++, findx++)
+ {
+ const char *fname;
+
+ fname = debug_get_field_name (info->dhandle, *pf);
+ if (fname == NULL)
+ return false;
+ if (strncmp (fname, name, namlen) == 0
+ && strlen (fname) == namlen)
+ {
+ pslot = it->fslots + findx;
+ break;
+ }
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (pslot == NULL)
+ {
+ ieee_error (info, start, "C++ reference not found");
+ return false;
+ }
+
+ /* We allocated the type of the object as an indirect type pointing
+ to *pslot, which we can now update to be a reference type. */
+ if (debug_get_type_kind (info->dhandle, *pslot) != DEBUG_KIND_POINTER)
+ {
+ ieee_error (info, start, "C++ reference is not pointer");
+ return false;
+ }
+
+ target = debug_get_target_type (info->dhandle, *pslot);
+ *pslot = debug_make_reference_type (info->dhandle, target);
+ if (*pslot == DEBUG_TYPE_NULL)
+ return false;
+
+ return true;
+}
+
+/* Require an ASN record. */
+
+static boolean
+ieee_require_asn (info, pp, pv)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ bfd_vma *pv;
+{
+ const bfd_byte *start;
+ ieee_record_enum_type c;
+ bfd_vma varindx;
+
+ start = *pp;
+
+ c = (ieee_record_enum_type) **pp;
+ if (c != ieee_e2_first_byte_enum)
+ {
+ ieee_error (info, start, "missing required ASN");
+ return false;
+ }
+ ++*pp;
+
+ c = (ieee_record_enum_type) (((unsigned int) c << 8) | **pp);
+ if (c != ieee_asn_record_enum)
+ {
+ ieee_error (info, start, "missing required ASN");
+ return false;
+ }
+ ++*pp;
+
+ /* Just ignore the variable index. */
+ if (! ieee_read_number (info, pp, &varindx))
+ return false;
+
+ return ieee_read_expression (info, pp, pv);
+}
+
+/* Require an ATN65 record. */
+
+static boolean
+ieee_require_atn65 (info, pp, pname, pnamlen)
+ struct ieee_info *info;
+ const bfd_byte **pp;
+ const char **pname;
+ unsigned long *pnamlen;
+{
+ const bfd_byte *start;
+ ieee_record_enum_type c;
+ bfd_vma name_indx, type_indx, atn_code;
+
+ start = *pp;
+
+ c = (ieee_record_enum_type) **pp;
+ if (c != ieee_at_record_enum)
+ {
+ ieee_error (info, start, "missing required ATN65");
+ return false;
+ }
+ ++*pp;
+
+ c = (ieee_record_enum_type) (((unsigned int) c << 8) | **pp);
+ if (c != ieee_atn_record_enum)
+ {
+ ieee_error (info, start, "missing required ATN65");
+ return false;
+ }
+ ++*pp;
+
+ if (! ieee_read_number (info, pp, &name_indx)
+ || ! ieee_read_number (info, pp, &type_indx)
+ || ! ieee_read_number (info, pp, &atn_code))
+ return false;
+
+ /* Just ignore name_indx. */
+
+ if (type_indx != 0 || atn_code != 65)
+ {
+ ieee_error (info, start, "bad ATN65 record");
+ return false;
+ }
+
+ return ieee_read_id (info, pp, pname, pnamlen);
+}
+
+/* Convert a register number in IEEE debugging information into a
+ generic register number. */
+
+static int
+ieee_regno_to_genreg (abfd, r)
+ bfd *abfd;
+ int r;
+{
+ switch (bfd_get_arch (abfd))
+ {
+ case bfd_arch_m68k:
+ /* For some reasons stabs adds 2 to the floating point register
+ numbers. */
+ if (r >= 16)
+ r += 2;
+ break;
+
+ case bfd_arch_i960:
+ /* Stabs uses 0 to 15 for r0 to r15, 16 to 31 for g0 to g15, and
+ 32 to 35 for fp0 to fp3. */
+ --r;
+ break;
+
+ default:
+ break;
+ }
+
+ return r;
+}
+
+/* Convert a generic register number to an IEEE specific one. */
+
+static int
+ieee_genreg_to_regno (abfd, r)
+ bfd *abfd;
+ int r;
+{
+ switch (bfd_get_arch (abfd))
+ {
+ case bfd_arch_m68k:
+ /* For some reason stabs add 2 to the floating point register
+ numbers. */
+ if (r >= 18)
+ r -= 2;
+ break;
+
+ case bfd_arch_i960:
+ /* Stabs uses 0 to 15 for r0 to r15, 16 to 31 for g0 to g15, and
+ 32 to 35 for fp0 to fp3. */
+ ++r;
+ break;
+
+ default:
+ break;
+ }
+
+ return r;
+}
+
+/* These routines build IEEE debugging information out of the generic
+ debugging information. */
+
+/* We build the IEEE debugging information byte by byte. Rather than
+ waste time copying data around, we use a linked list of buffers to
+ hold the data. */
+
+#define IEEE_BUFSIZE (490)
+
+struct ieee_buf
+{
+ /* Next buffer. */
+ struct ieee_buf *next;
+ /* Number of data bytes in this buffer. */
+ unsigned int c;
+ /* Bytes. */
+ bfd_byte buf[IEEE_BUFSIZE];
+};
+
+/* A list of buffers. */
+
+struct ieee_buflist
+{
+ /* Head of list. */
+ struct ieee_buf *head;
+ /* Tail--last buffer on list. */
+ struct ieee_buf *tail;
+};
+
+/* In order to generate the BB11 blocks required by the HP emulator,
+ we keep track of ranges of addresses which correspond to a given
+ compilation unit. */
+
+struct ieee_range
+{
+ /* Next range. */
+ struct ieee_range *next;
+ /* Low address. */
+ bfd_vma low;
+ /* High address. */
+ bfd_vma high;
+};
+
+/* This structure holds information for a class on the type stack. */
+
+struct ieee_type_class
+{
+ /* The name index in the debugging information. */
+ unsigned int indx;
+ /* The pmisc records for the class. */
+ struct ieee_buflist pmiscbuf;
+ /* The number of pmisc records. */
+ unsigned int pmisccount;
+ /* The name of the class holding the virtual table, if not this
+ class. */
+ const char *vclass;
+ /* Whether this class holds its own virtual table. */
+ boolean ownvptr;
+ /* The largest virtual table offset seen so far. */
+ bfd_vma voffset;
+ /* The current method. */
+ const char *method;
+ /* Additional pmisc records used to record fields of reference type. */
+ struct ieee_buflist refs;
+};
+
+/* This is how we store types for the writing routines. Most types
+ are simply represented by a type index. */
+
+struct ieee_write_type
+{
+ /* Type index. */
+ unsigned int indx;
+ /* The size of the type, if known. */
+ unsigned int size;
+ /* The name of the type, if any. */
+ const char *name;
+ /* If this is a function or method type, we build the type here, and
+ only add it to the output buffers if we need it. */
+ struct ieee_buflist fndef;
+ /* If this is a struct, this is where the struct definition is
+ built. */
+ struct ieee_buflist strdef;
+ /* If this is a class, this is where the class information is built. */
+ struct ieee_type_class *classdef;
+ /* Whether the type is unsigned. */
+ unsigned int unsignedp : 1;
+ /* Whether this is a reference type. */
+ unsigned int referencep : 1;
+ /* Whether this is in the local type block. */
+ unsigned int localp : 1;
+ /* Whether this is a duplicate struct definition which we are
+ ignoring. */
+ unsigned int ignorep : 1;
+};
+
+/* This is the type stack used by the debug writing routines. FIXME:
+ We could generate more efficient output if we remembered when we
+ have output a particular type before. */
+
+struct ieee_type_stack
+{
+ /* Next entry on stack. */
+ struct ieee_type_stack *next;
+ /* Type information. */
+ struct ieee_write_type type;
+};
+
+/* This is a list of associations between a name and some types.
+ These are used for typedefs and tags. */
+
+struct ieee_name_type
+{
+ /* Next type for this name. */
+ struct ieee_name_type *next;
+ /* ID number. For a typedef, this is the index of the type to which
+ this name is typedefed. */
+ unsigned int id;
+ /* Type. */
+ struct ieee_write_type type;
+ /* If this is a tag which has not yet been defined, this is the
+ kind. If the tag has been defined, this is DEBUG_KIND_ILLEGAL. */
+ enum debug_type_kind kind;
+};
+
+/* We use a hash table to associate names and types. */
+
+struct ieee_name_type_hash_table
+{
+ struct bfd_hash_table root;
+};
+
+struct ieee_name_type_hash_entry
+{
+ struct bfd_hash_entry root;
+ /* Information for this name. */
+ struct ieee_name_type *types;
+};
+
+/* This is a list of enums. */
+
+struct ieee_defined_enum
+{
+ /* Next enum. */
+ struct ieee_defined_enum *next;
+ /* Type index. */
+ unsigned int indx;
+ /* Whether this enum has been defined. */
+ boolean defined;
+ /* Tag. */
+ const char *tag;
+ /* Names. */
+ const char **names;
+ /* Values. */
+ bfd_signed_vma *vals;
+};
+
+/* We keep a list of modified versions of types, so that we don't
+ output them more than once. */
+
+struct ieee_modified_type
+{
+ /* Pointer to this type. */
+ unsigned int pointer;
+ /* Function with unknown arguments returning this type. */
+ unsigned int function;
+ /* Const version of this type. */
+ unsigned int const_qualified;
+ /* Volatile version of this type. */
+ unsigned int volatile_qualified;
+ /* List of arrays of this type of various bounds. */
+ struct ieee_modified_array_type *arrays;
+};
+
+/* A list of arrays bounds. */
+
+struct ieee_modified_array_type
+{
+ /* Next array bounds. */
+ struct ieee_modified_array_type *next;
+ /* Type index with these bounds. */
+ unsigned int indx;
+ /* Low bound. */
+ bfd_signed_vma low;
+ /* High bound. */
+ bfd_signed_vma high;
+};
+
+/* This is a list of pending function parameter information. We don't
+ output them until we see the first block. */
+
+struct ieee_pending_parm
+{
+ /* Next pending parameter. */
+ struct ieee_pending_parm *next;
+ /* Name. */
+ const char *name;
+ /* Type index. */
+ unsigned int type;
+ /* Whether the type is a reference. */
+ boolean referencep;
+ /* Kind. */
+ enum debug_parm_kind kind;
+ /* Value. */
+ bfd_vma val;
+};
+
+/* This is the handle passed down by debug_write. */
+
+struct ieee_handle
+{
+ /* BFD we are writing to. */
+ bfd *abfd;
+ /* Whether we got an error in a subroutine called via traverse or
+ map_over_sections. */
+ boolean error;
+ /* Current data buffer list. */
+ struct ieee_buflist *current;
+ /* Current data buffer. */
+ struct ieee_buf *curbuf;
+ /* Filename of current compilation unit. */
+ const char *filename;
+ /* Module name of current compilation unit. */
+ const char *modname;
+ /* List of buffer for global types. */
+ struct ieee_buflist global_types;
+ /* List of finished data buffers. */
+ struct ieee_buflist data;
+ /* List of buffers for typedefs in the current compilation unit. */
+ struct ieee_buflist types;
+ /* List of buffers for variables and functions in the current
+ compilation unit. */
+ struct ieee_buflist vars;
+ /* List of buffers for C++ class definitions in the current
+ compilation unit. */
+ struct ieee_buflist cxx;
+ /* List of buffers for line numbers in the current compilation unit. */
+ struct ieee_buflist linenos;
+ /* Ranges for the current compilation unit. */
+ struct ieee_range *ranges;
+ /* Ranges for all debugging information. */
+ struct ieee_range *global_ranges;
+ /* Nested pending ranges. */
+ struct ieee_range *pending_ranges;
+ /* Type stack. */
+ struct ieee_type_stack *type_stack;
+ /* Next unallocated type index. */
+ unsigned int type_indx;
+ /* Next unallocated name index. */
+ unsigned int name_indx;
+ /* Typedefs. */
+ struct ieee_name_type_hash_table typedefs;
+ /* Tags. */
+ struct ieee_name_type_hash_table tags;
+ /* Enums. */
+ struct ieee_defined_enum *enums;
+ /* Modified versions of types. */
+ struct ieee_modified_type *modified;
+ /* Number of entries allocated in modified. */
+ unsigned int modified_alloc;
+ /* 4 byte complex type. */
+ unsigned int complex_float_index;
+ /* 8 byte complex type. */
+ unsigned int complex_double_index;
+ /* The depth of block nesting. This is 0 outside a function, and 1
+ just after start_function is called. */
+ unsigned int block_depth;
+ /* The name of the current function. */
+ const char *fnname;
+ /* List of buffers for the type of the function we are currently
+ writing out. */
+ struct ieee_buflist fntype;
+ /* List of buffers for the parameters of the function we are
+ currently writing out. */
+ struct ieee_buflist fnargs;
+ /* Number of arguments written to fnargs. */
+ unsigned int fnargcount;
+ /* Pending function parameters. */
+ struct ieee_pending_parm *pending_parms;
+ /* Current line number filename. */
+ const char *lineno_filename;
+ /* Line number name index. */
+ unsigned int lineno_name_indx;
+ /* Filename of pending line number. */
+ const char *pending_lineno_filename;
+ /* Pending line number. */
+ unsigned long pending_lineno;
+ /* Address of pending line number. */
+ bfd_vma pending_lineno_addr;
+ /* Highest address seen at end of procedure. */
+ bfd_vma highaddr;
+};
+
+static boolean ieee_init_buffer
+ PARAMS ((struct ieee_handle *, struct ieee_buflist *));
+static boolean ieee_change_buffer
+ PARAMS ((struct ieee_handle *, struct ieee_buflist *));
+static boolean ieee_append_buffer
+ PARAMS ((struct ieee_handle *, struct ieee_buflist *,
+ struct ieee_buflist *));
+static boolean ieee_real_write_byte PARAMS ((struct ieee_handle *, int));
+static boolean ieee_write_2bytes PARAMS ((struct ieee_handle *, int));
+static boolean ieee_write_number PARAMS ((struct ieee_handle *, bfd_vma));
+static boolean ieee_write_id PARAMS ((struct ieee_handle *, const char *));
+static boolean ieee_write_asn
+ PARAMS ((struct ieee_handle *, unsigned int, bfd_vma));
+static boolean ieee_write_atn65
+ PARAMS ((struct ieee_handle *, unsigned int, const char *));
+static boolean ieee_push_type
+ PARAMS ((struct ieee_handle *, unsigned int, unsigned int, boolean,
+ boolean));
+static unsigned int ieee_pop_type PARAMS ((struct ieee_handle *));
+static void ieee_pop_unused_type PARAMS ((struct ieee_handle *));
+static unsigned int ieee_pop_type_used
+ PARAMS ((struct ieee_handle *, boolean));
+static boolean ieee_add_range
+ PARAMS ((struct ieee_handle *, boolean, bfd_vma, bfd_vma));
+static boolean ieee_start_range PARAMS ((struct ieee_handle *, bfd_vma));
+static boolean ieee_end_range PARAMS ((struct ieee_handle *, bfd_vma));
+static boolean ieee_define_type
+ PARAMS ((struct ieee_handle *, unsigned int, boolean, boolean));
+static boolean ieee_define_named_type
+ PARAMS ((struct ieee_handle *, const char *, unsigned int, unsigned int,
+ boolean, boolean, struct ieee_buflist *));
+static struct ieee_modified_type *ieee_get_modified_info
+ PARAMS ((struct ieee_handle *, unsigned int));
+static struct bfd_hash_entry *ieee_name_type_newfunc
+ PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
+static boolean ieee_write_undefined_tag
+ PARAMS ((struct ieee_name_type_hash_entry *, PTR));
+static boolean ieee_finish_compilation_unit PARAMS ((struct ieee_handle *));
+static void ieee_add_bb11_blocks PARAMS ((bfd *, asection *, PTR));
+static boolean ieee_add_bb11
+ PARAMS ((struct ieee_handle *, asection *, bfd_vma, bfd_vma));
+static boolean ieee_output_pending_parms PARAMS ((struct ieee_handle *));
+static unsigned int ieee_vis_to_flags PARAMS ((enum debug_visibility));
+static boolean ieee_class_method_var
+ PARAMS ((struct ieee_handle *, const char *, enum debug_visibility, boolean,
+ boolean, boolean, bfd_vma, boolean));
+
+static boolean ieee_start_compilation_unit PARAMS ((PTR, const char *));
+static boolean ieee_start_source PARAMS ((PTR, const char *));
+static boolean ieee_empty_type PARAMS ((PTR));
+static boolean ieee_void_type PARAMS ((PTR));
+static boolean ieee_int_type PARAMS ((PTR, unsigned int, boolean));
+static boolean ieee_float_type PARAMS ((PTR, unsigned int));
+static boolean ieee_complex_type PARAMS ((PTR, unsigned int));
+static boolean ieee_bool_type PARAMS ((PTR, unsigned int));
+static boolean ieee_enum_type
+ PARAMS ((PTR, const char *, const char **, bfd_signed_vma *));
+static boolean ieee_pointer_type PARAMS ((PTR));
+static boolean ieee_function_type PARAMS ((PTR, int, boolean));
+static boolean ieee_reference_type PARAMS ((PTR));
+static boolean ieee_range_type PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma));
+static boolean ieee_array_type
+ PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma, boolean));
+static boolean ieee_set_type PARAMS ((PTR, boolean));
+static boolean ieee_offset_type PARAMS ((PTR));
+static boolean ieee_method_type PARAMS ((PTR, boolean, int, boolean));
+static boolean ieee_const_type PARAMS ((PTR));
+static boolean ieee_volatile_type PARAMS ((PTR));
+static boolean ieee_start_struct_type
+ PARAMS ((PTR, const char *, unsigned int, boolean, unsigned int));
+static boolean ieee_struct_field
+ PARAMS ((PTR, const char *, bfd_vma, bfd_vma, enum debug_visibility));
+static boolean ieee_end_struct_type PARAMS ((PTR));
+static boolean ieee_start_class_type
+ PARAMS ((PTR, const char *, unsigned int, boolean, unsigned int, boolean,
+ boolean));
+static boolean ieee_class_static_member
+ PARAMS ((PTR, const char *, const char *, enum debug_visibility));
+static boolean ieee_class_baseclass
+ PARAMS ((PTR, bfd_vma, boolean, enum debug_visibility));
+static boolean ieee_class_start_method PARAMS ((PTR, const char *));
+static boolean ieee_class_method_variant
+ PARAMS ((PTR, const char *, enum debug_visibility, boolean, boolean,
+ bfd_vma, boolean));
+static boolean ieee_class_static_method_variant
+ PARAMS ((PTR, const char *, enum debug_visibility, boolean, boolean));
+static boolean ieee_class_end_method PARAMS ((PTR));
+static boolean ieee_end_class_type PARAMS ((PTR));
+static boolean ieee_typedef_type PARAMS ((PTR, const char *));
+static boolean ieee_tag_type
+ PARAMS ((PTR, const char *, unsigned int, enum debug_type_kind));
+static boolean ieee_typdef PARAMS ((PTR, const char *));
+static boolean ieee_tag PARAMS ((PTR, const char *));
+static boolean ieee_int_constant PARAMS ((PTR, const char *, bfd_vma));
+static boolean ieee_float_constant PARAMS ((PTR, const char *, double));
+static boolean ieee_typed_constant PARAMS ((PTR, const char *, bfd_vma));
+static boolean ieee_variable
+ PARAMS ((PTR, const char *, enum debug_var_kind, bfd_vma));
+static boolean ieee_start_function PARAMS ((PTR, const char *, boolean));
+static boolean ieee_function_parameter
+ PARAMS ((PTR, const char *, enum debug_parm_kind, bfd_vma));
+static boolean ieee_start_block PARAMS ((PTR, bfd_vma));
+static boolean ieee_end_block PARAMS ((PTR, bfd_vma));
+static boolean ieee_end_function PARAMS ((PTR));
+static boolean ieee_lineno
+ PARAMS ((PTR, const char *, unsigned long, bfd_vma));
+
+static const struct debug_write_fns ieee_fns =
+{
+ ieee_start_compilation_unit,
+ ieee_start_source,
+ ieee_empty_type,
+ ieee_void_type,
+ ieee_int_type,
+ ieee_float_type,
+ ieee_complex_type,
+ ieee_bool_type,
+ ieee_enum_type,
+ ieee_pointer_type,
+ ieee_function_type,
+ ieee_reference_type,
+ ieee_range_type,
+ ieee_array_type,
+ ieee_set_type,
+ ieee_offset_type,
+ ieee_method_type,
+ ieee_const_type,
+ ieee_volatile_type,
+ ieee_start_struct_type,
+ ieee_struct_field,
+ ieee_end_struct_type,
+ ieee_start_class_type,
+ ieee_class_static_member,
+ ieee_class_baseclass,
+ ieee_class_start_method,
+ ieee_class_method_variant,
+ ieee_class_static_method_variant,
+ ieee_class_end_method,
+ ieee_end_class_type,
+ ieee_typedef_type,
+ ieee_tag_type,
+ ieee_typdef,
+ ieee_tag,
+ ieee_int_constant,
+ ieee_float_constant,
+ ieee_typed_constant,
+ ieee_variable,
+ ieee_start_function,
+ ieee_function_parameter,
+ ieee_start_block,
+ ieee_end_block,
+ ieee_end_function,
+ ieee_lineno
+};
+
+/* Initialize a buffer to be empty. */
+
+/*ARGSUSED*/
+static boolean
+ieee_init_buffer (info, buflist)
+ struct ieee_handle *info;
+ struct ieee_buflist *buflist;
+{
+ buflist->head = NULL;
+ buflist->tail = NULL;
+ return true;
+}
+
+/* See whether a buffer list has any data. */
+
+#define ieee_buffer_emptyp(buflist) ((buflist)->head == NULL)
+
+/* Change the current buffer to a specified buffer chain. */
+
+static boolean
+ieee_change_buffer (info, buflist)
+ struct ieee_handle *info;
+ struct ieee_buflist *buflist;
+{
+ if (buflist->head == NULL)
+ {
+ struct ieee_buf *buf;
+
+ buf = (struct ieee_buf *) xmalloc (sizeof *buf);
+ buf->next = NULL;
+ buf->c = 0;
+ buflist->head = buf;
+ buflist->tail = buf;
+ }
+
+ info->current = buflist;
+ info->curbuf = buflist->tail;
+
+ return true;
+}
+
+/* Append a buffer chain. */
+
+/*ARGSUSED*/
+static boolean
+ieee_append_buffer (info, mainbuf, newbuf)
+ struct ieee_handle *info;
+ struct ieee_buflist *mainbuf;
+ struct ieee_buflist *newbuf;
+{
+ if (newbuf->head != NULL)
+ {
+ if (mainbuf->head == NULL)
+ mainbuf->head = newbuf->head;
+ else
+ mainbuf->tail->next = newbuf->head;
+ mainbuf->tail = newbuf->tail;
+ }
+ return true;
+}
+
+/* Write a byte into the buffer. We use a macro for speed and a
+ function for the complex cases. */
+
+#define ieee_write_byte(info, b) \
+ ((info)->curbuf->c < IEEE_BUFSIZE \
+ ? ((info)->curbuf->buf[(info)->curbuf->c++] = (b), true) \
+ : ieee_real_write_byte ((info), (b)))
+
+static boolean
+ieee_real_write_byte (info, b)
+ struct ieee_handle *info;
+ int b;
+{
+ if (info->curbuf->c >= IEEE_BUFSIZE)
+ {
+ struct ieee_buf *n;
+
+ n = (struct ieee_buf *) xmalloc (sizeof *n);
+ n->next = NULL;
+ n->c = 0;
+ if (info->current->head == NULL)
+ info->current->head = n;
+ else
+ info->current->tail->next = n;
+ info->current->tail = n;
+ info->curbuf = n;
+ }
+
+ info->curbuf->buf[info->curbuf->c] = b;
+ ++info->curbuf->c;
+
+ return true;
+}
+
+/* Write out two bytes. */
+
+static boolean
+ieee_write_2bytes (info, i)
+ struct ieee_handle *info;
+ int i;
+{
+ return (ieee_write_byte (info, i >> 8)
+ && ieee_write_byte (info, i & 0xff));
+}
+
+/* Write out an integer. */
+
+static boolean
+ieee_write_number (info, v)
+ struct ieee_handle *info;
+ bfd_vma v;
+{
+ bfd_vma t;
+ bfd_byte ab[20];
+ bfd_byte *p;
+ unsigned int c;
+
+ if (v <= (bfd_vma) ieee_number_end_enum)
+ return ieee_write_byte (info, (int) v);
+
+ t = v;
+ p = ab + sizeof ab;
+ while (t != 0)
+ {
+ *--p = t & 0xff;
+ t >>= 8;
+ }
+ c = (ab + 20) - p;
+
+ if (c > (unsigned int) (ieee_number_repeat_end_enum
+ - ieee_number_repeat_start_enum))
+ {
+ fprintf (stderr, "IEEE numeric overflow: 0x");
+ fprintf_vma (stderr, v);
+ fprintf (stderr, "\n");
+ return false;
+ }
+
+ if (! ieee_write_byte (info, (int) ieee_number_repeat_start_enum + c))
+ return false;
+ for (; c > 0; --c, ++p)
+ {
+ if (! ieee_write_byte (info, *p))
+ return false;
+ }
+
+ return true;
+}
+
+/* Write out a string. */
+
+static boolean
+ieee_write_id (info, s)
+ struct ieee_handle *info;
+ const char *s;
+{
+ unsigned int len;
+
+ len = strlen (s);
+ if (len <= 0x7f)
+ {
+ if (! ieee_write_byte (info, len))
+ return false;
+ }
+ else if (len <= 0xff)
+ {
+ if (! ieee_write_byte (info, (int) ieee_extension_length_1_enum)
+ || ! ieee_write_byte (info, len))
+ return false;
+ }
+ else if (len <= 0xffff)
+ {
+ if (! ieee_write_byte (info, (int) ieee_extension_length_2_enum)
+ || ! ieee_write_2bytes (info, len))
+ return false;
+ }
+ else
+ {
+ fprintf (stderr, "IEEE string length overflow: %u\n", len);
+ return false;
+ }
+
+ for (; *s != '\0'; s++)
+ if (! ieee_write_byte (info, *s))
+ return false;
+
+ return true;
+}
+
+/* Write out an ASN record. */
+
+static boolean
+ieee_write_asn (info, indx, val)
+ struct ieee_handle *info;
+ unsigned int indx;
+ bfd_vma val;
+{
+ return (ieee_write_2bytes (info, (int) ieee_asn_record_enum)
+ && ieee_write_number (info, indx)
+ && ieee_write_number (info, val));
+}
+
+/* Write out an ATN65 record. */
+
+static boolean
+ieee_write_atn65 (info, indx, s)
+ struct ieee_handle *info;
+ unsigned int indx;
+ const char *s;
+{
+ return (ieee_write_2bytes (info, (int) ieee_atn_record_enum)
+ && ieee_write_number (info, indx)
+ && ieee_write_number (info, 0)
+ && ieee_write_number (info, 65)
+ && ieee_write_id (info, s));
+}
+
+/* Push a type index onto the type stack. */
+
+static boolean
+ieee_push_type (info, indx, size, unsignedp, localp)
+ struct ieee_handle *info;
+ unsigned int indx;
+ unsigned int size;
+ boolean unsignedp;
+ boolean localp;
+{
+ struct ieee_type_stack *ts;
+
+ ts = (struct ieee_type_stack *) xmalloc (sizeof *ts);
+ memset (ts, 0, sizeof *ts);
+
+ ts->type.indx = indx;
+ ts->type.size = size;
+ ts->type.unsignedp = unsignedp;
+ ts->type.localp = localp;
+
+ ts->next = info->type_stack;
+ info->type_stack = ts;
+
+ return true;
+}
+
+/* Pop a type index off the type stack. */
+
+static unsigned int
+ieee_pop_type (info)
+ struct ieee_handle *info;
+{
+ return ieee_pop_type_used (info, true);
+}
+
+/* Pop an unused type index off the type stack. */
+
+static void
+ieee_pop_unused_type (info)
+ struct ieee_handle *info;
+{
+ (void) ieee_pop_type_used (info, false);
+}
+
+/* Pop a used or unused type index off the type stack. */
+
+static unsigned int
+ieee_pop_type_used (info, used)
+ struct ieee_handle *info;
+ boolean used;
+{
+ struct ieee_type_stack *ts;
+ unsigned int ret;
+
+ ts = info->type_stack;
+ assert (ts != NULL);
+
+ /* If this is a function type, and we need it, we need to append the
+ actual definition to the typedef block now. */
+ if (used && ! ieee_buffer_emptyp (&ts->type.fndef))
+ {
+ struct ieee_buflist *buflist;
+
+ if (ts->type.localp)
+ {
+ /* Make sure we have started the types block. */
+ if (ieee_buffer_emptyp (&info->types))
+ {
+ if (! ieee_change_buffer (info, &info->types)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 1)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, info->modname))
+ return false;
+ }
+ buflist = &info->types;
+ }
+ else
+ {
+ /* Make sure we started the global type block. */
+ if (ieee_buffer_emptyp (&info->global_types))
+ {
+ if (! ieee_change_buffer (info, &info->global_types)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 2)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, ""))
+ return false;
+ }
+ buflist = &info->global_types;
+ }
+
+ if (! ieee_append_buffer (info, buflist, &ts->type.fndef))
+ return false;
+ }
+
+ ret = ts->type.indx;
+ info->type_stack = ts->next;
+ free (ts);
+ return ret;
+}
+
+/* Add a range of bytes included in the current compilation unit. */
+
+static boolean
+ieee_add_range (info, global, low, high)
+ struct ieee_handle *info;
+ boolean global;
+ bfd_vma low;
+ bfd_vma high;
+{
+ struct ieee_range **plist, *r, **pr;
+
+ if (low == (bfd_vma) -1 || high == (bfd_vma) -1 || low == high)
+ return true;
+
+ if (global)
+ plist = &info->global_ranges;
+ else
+ plist = &info->ranges;
+
+ for (r = *plist; r != NULL; r = r->next)
+ {
+ if (high >= r->low && low <= r->high)
+ {
+ /* The new range overlaps r. */
+ if (low < r->low)
+ r->low = low;
+ if (high > r->high)
+ r->high = high;
+ pr = &r->next;
+ while (*pr != NULL && (*pr)->low <= r->high)
+ {
+ struct ieee_range *n;
+
+ if ((*pr)->high > r->high)
+ r->high = (*pr)->high;
+ n = (*pr)->next;
+ free (*pr);
+ *pr = n;
+ }
+ return true;
+ }
+ }
+
+ r = (struct ieee_range *) xmalloc (sizeof *r);
+ memset (r, 0, sizeof *r);
+
+ r->low = low;
+ r->high = high;
+
+ /* Store the ranges sorted by address. */
+ for (pr = plist; *pr != NULL; pr = &(*pr)->next)
+ if ((*pr)->low > high)
+ break;
+ r->next = *pr;
+ *pr = r;
+
+ return true;
+}
+
+/* Start a new range for which we only have the low address. */
+
+static boolean
+ieee_start_range (info, low)
+ struct ieee_handle *info;
+ bfd_vma low;
+{
+ struct ieee_range *r;
+
+ r = (struct ieee_range *) xmalloc (sizeof *r);
+ memset (r, 0, sizeof *r);
+ r->low = low;
+ r->next = info->pending_ranges;
+ info->pending_ranges = r;
+ return true;
+}
+
+/* Finish a range started by ieee_start_range. */
+
+static boolean
+ieee_end_range (info, high)
+ struct ieee_handle *info;
+ bfd_vma high;
+{
+ struct ieee_range *r;
+ bfd_vma low;
+
+ assert (info->pending_ranges != NULL);
+ r = info->pending_ranges;
+ low = r->low;
+ info->pending_ranges = r->next;
+ free (r);
+ return ieee_add_range (info, false, low, high);
+}
+
+/* Start defining a type. */
+
+static boolean
+ieee_define_type (info, size, unsignedp, localp)
+ struct ieee_handle *info;
+ unsigned int size;
+ boolean unsignedp;
+ boolean localp;
+{
+ return ieee_define_named_type (info, (const char *) NULL,
+ (unsigned int) -1, size, unsignedp,
+ localp, (struct ieee_buflist *) NULL);
+}
+
+/* Start defining a named type. */
+
+static boolean
+ieee_define_named_type (info, name, indx, size, unsignedp, localp, buflist)
+ struct ieee_handle *info;
+ const char *name;
+ unsigned int indx;
+ unsigned int size;
+ boolean unsignedp;
+ boolean localp;
+ struct ieee_buflist *buflist;
+{
+ unsigned int type_indx;
+ unsigned int name_indx;
+
+ if (indx != (unsigned int) -1)
+ type_indx = indx;
+ else
+ {
+ type_indx = info->type_indx;
+ ++info->type_indx;
+ }
+
+ name_indx = info->name_indx;
+ ++info->name_indx;
+
+ if (name == NULL)
+ name = "";
+
+ /* If we were given a buffer, use it; otherwise, use either the
+ local or the global type information, and make sure that the type
+ block is started. */
+ if (buflist != NULL)
+ {
+ if (! ieee_change_buffer (info, buflist))
+ return false;
+ }
+ else if (localp)
+ {
+ if (! ieee_buffer_emptyp (&info->types))
+ {
+ if (! ieee_change_buffer (info, &info->types))
+ return false;
+ }
+ else
+ {
+ if (! ieee_change_buffer (info, &info->types)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 1)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, info->modname))
+ return false;
+ }
+ }
+ else
+ {
+ if (! ieee_buffer_emptyp (&info->global_types))
+ {
+ if (! ieee_change_buffer (info, &info->global_types))
+ return false;
+ }
+ else
+ {
+ if (! ieee_change_buffer (info, &info->global_types)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 2)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, ""))
+ return false;
+ }
+ }
+
+ /* Push the new type on the type stack, write out an NN record, and
+ write out the start of a TY record. The caller will then finish
+ the TY record. */
+ if (! ieee_push_type (info, type_indx, size, unsignedp, localp))
+ return false;
+
+ return (ieee_write_byte (info, (int) ieee_nn_record)
+ && ieee_write_number (info, name_indx)
+ && ieee_write_id (info, name)
+ && ieee_write_byte (info, (int) ieee_ty_record_enum)
+ && ieee_write_number (info, type_indx)
+ && ieee_write_byte (info, 0xce)
+ && ieee_write_number (info, name_indx));
+}
+
+/* Get an entry to the list of modified versions of a type. */
+
+static struct ieee_modified_type *
+ieee_get_modified_info (info, indx)
+ struct ieee_handle *info;
+ unsigned int indx;
+{
+ if (indx >= info->modified_alloc)
+ {
+ unsigned int nalloc;
+
+ nalloc = info->modified_alloc;
+ if (nalloc == 0)
+ nalloc = 16;
+ while (indx >= nalloc)
+ nalloc *= 2;
+ info->modified = ((struct ieee_modified_type *)
+ xrealloc (info->modified,
+ nalloc * sizeof *info->modified));
+ memset (info->modified + info->modified_alloc, 0,
+ (nalloc - info->modified_alloc) * sizeof *info->modified);
+ info->modified_alloc = nalloc;
+ }
+
+ return info->modified + indx;
+}
+
+/* Routines for the hash table mapping names to types. */
+
+/* Initialize an entry in the hash table. */
+
+static struct bfd_hash_entry *
+ieee_name_type_newfunc (entry, table, string)
+ struct bfd_hash_entry *entry;
+ struct bfd_hash_table *table;
+ const char *string;
+{
+ struct ieee_name_type_hash_entry *ret =
+ (struct ieee_name_type_hash_entry *) entry;
+
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (ret == NULL)
+ ret = ((struct ieee_name_type_hash_entry *)
+ bfd_hash_allocate (table, sizeof *ret));
+ if (ret == NULL)
+ return NULL;
+
+ /* Call the allocation method of the superclass. */
+ ret = ((struct ieee_name_type_hash_entry *)
+ bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
+ if (ret)
+ {
+ /* Set local fields. */
+ ret->types = NULL;
+ }
+
+ return (struct bfd_hash_entry *) ret;
+}
+
+/* Look up an entry in the hash table. */
+
+#define ieee_name_type_hash_lookup(table, string, create, copy) \
+ ((struct ieee_name_type_hash_entry *) \
+ bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
+
+/* Traverse the hash table. */
+
+#define ieee_name_type_hash_traverse(table, func, info) \
+ (bfd_hash_traverse \
+ (&(table)->root, \
+ (boolean (*) PARAMS ((struct bfd_hash_entry *, PTR))) (func), \
+ (info)))
+
+/* The general routine to write out IEEE debugging information. */
+
+boolean
+write_ieee_debugging_info (abfd, dhandle)
+ bfd *abfd;
+ PTR dhandle;
+{
+ struct ieee_handle info;
+ asection *s;
+ const char *err;
+ struct ieee_buf *b;
+
+ memset (&info, 0, sizeof info);
+ info.abfd = abfd;
+ info.type_indx = 256;
+ info.name_indx = 32;
+
+ if (! bfd_hash_table_init (&info.typedefs.root, ieee_name_type_newfunc)
+ || ! bfd_hash_table_init (&info.tags.root, ieee_name_type_newfunc))
+ return false;
+
+ if (! ieee_init_buffer (&info, &info.global_types)
+ || ! ieee_init_buffer (&info, &info.data)
+ || ! ieee_init_buffer (&info, &info.types)
+ || ! ieee_init_buffer (&info, &info.vars)
+ || ! ieee_init_buffer (&info, &info.cxx)
+ || ! ieee_init_buffer (&info, &info.linenos)
+ || ! ieee_init_buffer (&info, &info.fntype)
+ || ! ieee_init_buffer (&info, &info.fnargs))
+ return false;
+
+ if (! debug_write (dhandle, &ieee_fns, (PTR) &info))
+ return false;
+
+ if (info.filename != NULL)
+ {
+ if (! ieee_finish_compilation_unit (&info))
+ return false;
+ }
+
+ /* Put any undefined tags in the global typedef information. */
+ info.error = false;
+ ieee_name_type_hash_traverse (&info.tags,
+ ieee_write_undefined_tag,
+ (PTR) &info);
+ if (info.error)
+ return false;
+
+ /* Prepend the global typedef information to the other data. */
+ if (! ieee_buffer_emptyp (&info.global_types))
+ {
+ /* The HP debugger seems to have a bug in which it ignores the
+ last entry in the global types, so we add a dummy entry. */
+ if (! ieee_change_buffer (&info, &info.global_types)
+ || ! ieee_write_byte (&info, (int) ieee_nn_record)
+ || ! ieee_write_number (&info, info.name_indx)
+ || ! ieee_write_id (&info, "")
+ || ! ieee_write_byte (&info, (int) ieee_ty_record_enum)
+ || ! ieee_write_number (&info, info.type_indx)
+ || ! ieee_write_byte (&info, 0xce)
+ || ! ieee_write_number (&info, info.name_indx)
+ || ! ieee_write_number (&info, 'P')
+ || ! ieee_write_number (&info, (int) builtin_void + 32)
+ || ! ieee_write_byte (&info, (int) ieee_be_record_enum))
+ return false;
+
+ if (! ieee_append_buffer (&info, &info.global_types, &info.data))
+ return false;
+ info.data = info.global_types;
+ }
+
+ /* Make sure that we have declare BB11 blocks for each range in the
+ file. They are added to info->vars. */
+ info.error = false;
+ if (! ieee_init_buffer (&info, &info.vars))
+ return false;
+ bfd_map_over_sections (abfd, ieee_add_bb11_blocks, (PTR) &info);
+ if (info.error)
+ return false;
+ if (! ieee_buffer_emptyp (&info.vars))
+ {
+ if (! ieee_change_buffer (&info, &info.vars)
+ || ! ieee_write_byte (&info, (int) ieee_be_record_enum))
+ return false;
+
+ if (! ieee_append_buffer (&info, &info.data, &info.vars))
+ return false;
+ }
+
+ /* Now all the data is in info.data. Write it out to the BFD. We
+ normally would need to worry about whether all the other sections
+ are set up yet, but the IEEE backend will handle this particular
+ case correctly regardless. */
+ if (ieee_buffer_emptyp (&info.data))
+ {
+ /* There is no debugging information. */
+ return true;
+ }
+ err = NULL;
+ s = bfd_make_section (abfd, ".debug");
+ if (s == NULL)
+ err = "bfd_make_section";
+ if (err == NULL)
+ {
+ if (! bfd_set_section_flags (abfd, s, SEC_DEBUGGING | SEC_HAS_CONTENTS))
+ err = "bfd_set_section_flags";
+ }
+ if (err == NULL)
+ {
+ bfd_size_type size;
+
+ size = 0;
+ for (b = info.data.head; b != NULL; b = b->next)
+ size += b->c;
+ if (! bfd_set_section_size (abfd, s, size))
+ err = "bfd_set_section_size";
+ }
+ if (err == NULL)
+ {
+ file_ptr offset;
+
+ offset = 0;
+ for (b = info.data.head; b != NULL; b = b->next)
+ {
+ if (! bfd_set_section_contents (abfd, s, b->buf, offset, b->c))
+ {
+ err = "bfd_set_section_contents";
+ break;
+ }
+ offset += b->c;
+ }
+ }
+
+ if (err != NULL)
+ {
+ fprintf (stderr, "%s: %s: %s\n", bfd_get_filename (abfd), err,
+ bfd_errmsg (bfd_get_error ()));
+ return false;
+ }
+
+ bfd_hash_table_free (&info.typedefs.root);
+ bfd_hash_table_free (&info.tags.root);
+
+ return true;
+}
+
+/* Write out information for an undefined tag. This is called via
+ ieee_name_type_hash_traverse. */
+
+static boolean
+ieee_write_undefined_tag (h, p)
+ struct ieee_name_type_hash_entry *h;
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ struct ieee_name_type *nt;
+
+ for (nt = h->types; nt != NULL; nt = nt->next)
+ {
+ unsigned int name_indx;
+ char code;
+
+ if (nt->kind == DEBUG_KIND_ILLEGAL)
+ continue;
+
+ if (ieee_buffer_emptyp (&info->global_types))
+ {
+ if (! ieee_change_buffer (info, &info->global_types)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 2)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, ""))
+ {
+ info->error = true;
+ return false;
+ }
+ }
+ else
+ {
+ if (! ieee_change_buffer (info, &info->global_types))
+ {
+ info->error = true;
+ return false;
+ }
+ }
+
+ name_indx = info->name_indx;
+ ++info->name_indx;
+ if (! ieee_write_byte (info, (int) ieee_nn_record)
+ || ! ieee_write_number (info, name_indx)
+ || ! ieee_write_id (info, nt->type.name)
+ || ! ieee_write_byte (info, (int) ieee_ty_record_enum)
+ || ! ieee_write_number (info, nt->type.indx)
+ || ! ieee_write_byte (info, 0xce)
+ || ! ieee_write_number (info, name_indx))
+ {
+ info->error = true;
+ return false;
+ }
+
+ switch (nt->kind)
+ {
+ default:
+ abort ();
+ info->error = true;
+ return false;
+ case DEBUG_KIND_STRUCT:
+ case DEBUG_KIND_CLASS:
+ code = 'S';
+ break;
+ case DEBUG_KIND_UNION:
+ case DEBUG_KIND_UNION_CLASS:
+ code = 'U';
+ break;
+ case DEBUG_KIND_ENUM:
+ code = 'E';
+ break;
+ }
+ if (! ieee_write_number (info, code)
+ || ! ieee_write_number (info, 0))
+ {
+ info->error = true;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* Start writing out information for a compilation unit. */
+
+static boolean
+ieee_start_compilation_unit (p, filename)
+ PTR p;
+ const char *filename;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ const char *modname;
+ char *c, *s;
+ unsigned int nindx;
+
+ if (info->filename != NULL)
+ {
+ if (! ieee_finish_compilation_unit (info))
+ return false;
+ }
+
+ info->filename = filename;
+ modname = strrchr (filename, '/');
+ if (modname != NULL)
+ ++modname;
+ else
+ {
+ modname = strrchr (filename, '\\');
+ if (modname != NULL)
+ ++modname;
+ else
+ modname = filename;
+ }
+ c = xstrdup (modname);
+ s = strrchr (c, '.');
+ if (s != NULL)
+ *s = '\0';
+ info->modname = c;
+
+ if (! ieee_init_buffer (info, &info->types)
+ || ! ieee_init_buffer (info, &info->vars)
+ || ! ieee_init_buffer (info, &info->cxx)
+ || ! ieee_init_buffer (info, &info->linenos))
+ return false;
+ info->ranges = NULL;
+
+ /* Always include a BB1 and a BB3 block. That is what the output of
+ the MRI linker seems to look like. */
+ if (! ieee_change_buffer (info, &info->types)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 1)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, info->modname))
+ return false;
+
+ nindx = info->name_indx;
+ ++info->name_indx;
+ if (! ieee_change_buffer (info, &info->vars)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 3)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, info->modname))
+ return false;
+
+ return true;
+}
+
+/* Finish up a compilation unit. */
+
+static boolean
+ieee_finish_compilation_unit (info)
+ struct ieee_handle *info;
+{
+ struct ieee_range *r;
+
+ if (! ieee_buffer_emptyp (&info->types))
+ {
+ if (! ieee_change_buffer (info, &info->types)
+ || ! ieee_write_byte (info, (int) ieee_be_record_enum))
+ return false;
+ }
+
+ if (! ieee_buffer_emptyp (&info->cxx))
+ {
+ /* Append any C++ information to the global function and
+ variable information. */
+ assert (! ieee_buffer_emptyp (&info->vars));
+ if (! ieee_change_buffer (info, &info->vars))
+ return false;
+
+ /* We put the pmisc records in a dummy procedure, just as the
+ MRI compiler does. */
+ if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 6)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, "__XRYCPP")
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, info->highaddr - 1)
+ || ! ieee_append_buffer (info, &info->vars, &info->cxx)
+ || ! ieee_change_buffer (info, &info->vars)
+ || ! ieee_write_byte (info, (int) ieee_be_record_enum)
+ || ! ieee_write_number (info, info->highaddr - 1))
+ return false;
+ }
+
+ if (! ieee_buffer_emptyp (&info->vars))
+ {
+ if (! ieee_change_buffer (info, &info->vars)
+ || ! ieee_write_byte (info, (int) ieee_be_record_enum))
+ return false;
+ }
+
+ if (info->pending_lineno_filename != NULL)
+ {
+ /* Force out the pending line number. */
+ if (! ieee_lineno ((PTR) info, (const char *) NULL, 0, (bfd_vma) -1))
+ return false;
+ }
+ if (! ieee_buffer_emptyp (&info->linenos))
+ {
+ if (! ieee_change_buffer (info, &info->linenos)
+ || ! ieee_write_byte (info, (int) ieee_be_record_enum))
+ return false;
+ if (strcmp (info->filename, info->lineno_filename) != 0)
+ {
+ /* We were not in the main file. We just closed the
+ included line number block, and now we must close the
+ main line number block. */
+ if (! ieee_write_byte (info, (int) ieee_be_record_enum))
+ return false;
+ }
+ }
+
+ if (! ieee_append_buffer (info, &info->data, &info->types)
+ || ! ieee_append_buffer (info, &info->data, &info->vars)
+ || ! ieee_append_buffer (info, &info->data, &info->linenos))
+ return false;
+
+ /* Build BB10/BB11 blocks based on the ranges we recorded. */
+ if (! ieee_change_buffer (info, &info->data))
+ return false;
+
+ if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 10)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, info->modname)
+ || ! ieee_write_id (info, "")
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, "GNU objcopy"))
+ return false;
+
+ for (r = info->ranges; r != NULL; r = r->next)
+ {
+ bfd_vma low, high;
+ asection *s;
+ int kind;
+
+ low = r->low;
+ high = r->high;
+
+ /* Find the section corresponding to this range. */
+ for (s = info->abfd->sections; s != NULL; s = s->next)
+ {
+ if (bfd_get_section_vma (info->abfd, s) <= low
+ && high <= (bfd_get_section_vma (info->abfd, s)
+ + bfd_section_size (info->abfd, s)))
+ break;
+ }
+
+ if (s == NULL)
+ {
+ /* Just ignore this range. */
+ continue;
+ }
+
+ /* Coalesce ranges if it seems reasonable. */
+ while (r->next != NULL
+ && high + 0x1000 >= r->next->low
+ && (r->next->high
+ <= (bfd_get_section_vma (info->abfd, s)
+ + bfd_section_size (info->abfd, s))))
+ {
+ r = r->next;
+ high = r->high;
+ }
+
+ if ((s->flags & SEC_CODE) != 0)
+ kind = 1;
+ else if ((s->flags & SEC_READONLY) != 0)
+ kind = 3;
+ else
+ kind = 2;
+
+ if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 11)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, "")
+ || ! ieee_write_number (info, kind)
+ || ! ieee_write_number (info, s->index + IEEE_SECTION_NUMBER_BASE)
+ || ! ieee_write_number (info, low)
+ || ! ieee_write_byte (info, (int) ieee_be_record_enum)
+ || ! ieee_write_number (info, high - low))
+ return false;
+
+ /* Add this range to the list of global ranges. */
+ if (! ieee_add_range (info, true, low, high))
+ return false;
+ }
+
+ if (! ieee_write_byte (info, (int) ieee_be_record_enum))
+ return false;
+
+ return true;
+}
+
+/* Add BB11 blocks describing each range that we have not already
+ described. */
+
+static void
+ieee_add_bb11_blocks (abfd, sec, data)
+ bfd *abfd;
+ asection *sec;
+ PTR data;
+{
+ struct ieee_handle *info = (struct ieee_handle *) data;
+ bfd_vma low, high;
+ struct ieee_range *r;
+
+ low = bfd_get_section_vma (abfd, sec);
+ high = low + bfd_section_size (abfd, sec);
+
+ /* Find the first range at or after this section. The ranges are
+ sorted by address. */
+ for (r = info->global_ranges; r != NULL; r = r->next)
+ if (r->high > low)
+ break;
+
+ while (low < high)
+ {
+ if (r == NULL || r->low >= high)
+ {
+ if (! ieee_add_bb11 (info, sec, low, high))
+ info->error = true;
+ return;
+ }
+
+ if (low < r->low
+ && r->low - low > 0x100)
+ {
+ if (! ieee_add_bb11 (info, sec, low, r->low))
+ {
+ info->error = true;
+ return;
+ }
+ }
+ low = r->high;
+
+ r = r->next;
+ }
+}
+
+/* Add a single BB11 block for a range. We add it to info->vars. */
+
+static boolean
+ieee_add_bb11 (info, sec, low, high)
+ struct ieee_handle *info;
+ asection *sec;
+ bfd_vma low;
+ bfd_vma high;
+{
+ int kind;
+
+ if (! ieee_buffer_emptyp (&info->vars))
+ {
+ if (! ieee_change_buffer (info, &info->vars))
+ return false;
+ }
+ else
+ {
+ const char *filename, *modname;
+ char *c, *s;
+
+ /* Start the enclosing BB10 block. */
+ filename = bfd_get_filename (info->abfd);
+ modname = strrchr (filename, '/');
+ if (modname != NULL)
+ ++modname;
+ else
+ {
+ modname = strrchr (filename, '\\');
+ if (modname != NULL)
+ ++modname;
+ else
+ modname = filename;
+ }
+ c = xstrdup (modname);
+ s = strrchr (c, '.');
+ if (s != NULL)
+ *s = '\0';
+
+ if (! ieee_change_buffer (info, &info->vars)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 10)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, c)
+ || ! ieee_write_id (info, "")
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, "GNU objcopy"))
+ return false;
+
+ free (c);
+ }
+
+ if ((sec->flags & SEC_CODE) != 0)
+ kind = 1;
+ else if ((sec->flags & SEC_READONLY) != 0)
+ kind = 3;
+ else
+ kind = 2;
+
+ if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 11)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, "")
+ || ! ieee_write_number (info, kind)
+ || ! ieee_write_number (info, sec->index + IEEE_SECTION_NUMBER_BASE)
+ || ! ieee_write_number (info, low)
+ || ! ieee_write_byte (info, (int) ieee_be_record_enum)
+ || ! ieee_write_number (info, high - low))
+ return false;
+
+ return true;
+}
+
+/* Start recording information from a particular source file. This is
+ used to record which file defined which types, variables, etc. It
+ is not used for line numbers, since the lineno entry point passes
+ down the file name anyhow. IEEE debugging information doesn't seem
+ to store this information anywhere. */
+
+/*ARGSUSED*/
+static boolean
+ieee_start_source (p, filename)
+ PTR p;
+ const char *filename;
+{
+ return true;
+}
+
+/* Make an empty type. */
+
+static boolean
+ieee_empty_type (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ return ieee_push_type (info, (int) builtin_unknown, 0, false, false);
+}
+
+/* Make a void type. */
+
+static boolean
+ieee_void_type (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ return ieee_push_type (info, (int) builtin_void, 0, false, false);
+}
+
+/* Make an integer type. */
+
+static boolean
+ieee_int_type (p, size, unsignedp)
+ PTR p;
+ unsigned int size;
+ boolean unsignedp;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int indx;
+
+ switch (size)
+ {
+ case 1:
+ indx = (int) builtin_signed_char;
+ break;
+ case 2:
+ indx = (int) builtin_signed_short_int;
+ break;
+ case 4:
+ indx = (int) builtin_signed_long;
+ break;
+ case 8:
+ indx = (int) builtin_signed_long_long;
+ break;
+ default:
+ fprintf (stderr, "IEEE unsupported integer type size %u\n", size);
+ return false;
+ }
+
+ if (unsignedp)
+ ++indx;
+
+ return ieee_push_type (info, indx, size, unsignedp, false);
+}
+
+/* Make a floating point type. */
+
+static boolean
+ieee_float_type (p, size)
+ PTR p;
+ unsigned int size;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int indx;
+
+ switch (size)
+ {
+ case 4:
+ indx = (int) builtin_float;
+ break;
+ case 8:
+ indx = (int) builtin_double;
+ break;
+ case 12:
+ /* FIXME: This size really depends upon the processor. */
+ indx = (int) builtin_long_double;
+ break;
+ case 16:
+ indx = (int) builtin_long_long_double;
+ break;
+ default:
+ fprintf (stderr, "IEEE unsupported float type size %u\n", size);
+ return false;
+ }
+
+ return ieee_push_type (info, indx, size, false, false);
+}
+
+/* Make a complex type. */
+
+static boolean
+ieee_complex_type (p, size)
+ PTR p;
+ unsigned int size;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ char code;
+
+ switch (size)
+ {
+ case 4:
+ if (info->complex_float_index != 0)
+ return ieee_push_type (info, info->complex_float_index, size * 2,
+ false, false);
+ code = 'c';
+ break;
+ case 12:
+ case 16:
+ /* These cases can be output by gcc -gstabs. Outputting the
+ wrong type is better than crashing. */
+ case 8:
+ if (info->complex_double_index != 0)
+ return ieee_push_type (info, info->complex_double_index, size * 2,
+ false, false);
+ code = 'd';
+ break;
+ default:
+ fprintf (stderr, "IEEE unsupported complex type size %u\n", size);
+ return false;
+ }
+
+ /* FIXME: I don't know what the string is for. */
+ if (! ieee_define_type (info, size * 2, false, false)
+ || ! ieee_write_number (info, code)
+ || ! ieee_write_id (info, ""))
+ return false;
+
+ if (size == 4)
+ info->complex_float_index = info->type_stack->type.indx;
+ else
+ info->complex_double_index = info->type_stack->type.indx;
+
+ return true;
+}
+
+/* Make a boolean type. IEEE doesn't support these, so we just make
+ an integer type instead. */
+
+static boolean
+ieee_bool_type (p, size)
+ PTR p;
+ unsigned int size;
+{
+ return ieee_int_type (p, size, true);
+}
+
+/* Make an enumeration. */
+
+static boolean
+ieee_enum_type (p, tag, names, vals)
+ PTR p;
+ const char *tag;
+ const char **names;
+ bfd_signed_vma *vals;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ struct ieee_defined_enum *e;
+ boolean localp, simple;
+ unsigned int indx;
+ int i = 0;
+
+ localp = false;
+ indx = (unsigned int) -1;
+ for (e = info->enums; e != NULL; e = e->next)
+ {
+ if (tag == NULL)
+ {
+ if (e->tag != NULL)
+ continue;
+ }
+ else
+ {
+ if (e->tag == NULL
+ || tag[0] != e->tag[0]
+ || strcmp (tag, e->tag) != 0)
+ continue;
+ }
+
+ if (! e->defined)
+ {
+ /* This enum tag has been seen but not defined. */
+ indx = e->indx;
+ break;
+ }
+
+ if (names != NULL && e->names != NULL)
+ {
+ for (i = 0; names[i] != NULL && e->names[i] != NULL; i++)
+ {
+ if (names[i][0] != e->names[i][0]
+ || vals[i] != e->vals[i]
+ || strcmp (names[i], e->names[i]) != 0)
+ break;
+ }
+ }
+
+ if ((names == NULL && e->names == NULL)
+ || (names != NULL
+ && e->names != NULL
+ && names[i] == NULL
+ && e->names[i] == NULL))
+ {
+ /* We've seen this enum before. */
+ return ieee_push_type (info, e->indx, 0, true, false);
+ }
+
+ if (tag != NULL)
+ {
+ /* We've already seen an enum of the same name, so we must make
+ sure to output this one locally. */
+ localp = true;
+ break;
+ }
+ }
+
+ /* If this is a simple enumeration, in which the values start at 0
+ and always increment by 1, we can use type E. Otherwise we must
+ use type N. */
+
+ simple = true;
+ if (names != NULL)
+ {
+ for (i = 0; names[i] != NULL; i++)
+ {
+ if (vals[i] != i)
+ {
+ simple = false;
+ break;
+ }
+ }
+ }
+
+ if (! ieee_define_named_type (info, tag, indx, 0, true, localp,
+ (struct ieee_buflist *) NULL)
+ || ! ieee_write_number (info, simple ? 'E' : 'N'))
+ return false;
+ if (simple)
+ {
+ /* FIXME: This is supposed to be the enumeration size, but we
+ don't store that. */
+ if (! ieee_write_number (info, 4))
+ return false;
+ }
+ if (names != NULL)
+ {
+ for (i = 0; names[i] != NULL; i++)
+ {
+ if (! ieee_write_id (info, names[i]))
+ return false;
+ if (! simple)
+ {
+ if (! ieee_write_number (info, vals[i]))
+ return false;
+ }
+ }
+ }
+
+ if (! localp)
+ {
+ if (indx == (unsigned int) -1)
+ {
+ e = (struct ieee_defined_enum *) xmalloc (sizeof *e);
+ memset (e, 0, sizeof *e);
+ e->indx = info->type_stack->type.indx;
+ e->tag = tag;
+
+ e->next = info->enums;
+ info->enums = e;
+ }
+
+ e->names = names;
+ e->vals = vals;
+ e->defined = true;
+ }
+
+ return true;
+}
+
+/* Make a pointer type. */
+
+static boolean
+ieee_pointer_type (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ boolean localp;
+ unsigned int indx;
+ struct ieee_modified_type *m = NULL;
+
+ localp = info->type_stack->type.localp;
+ indx = ieee_pop_type (info);
+
+ /* A pointer to a simple builtin type can be obtained by adding 32.
+ FIXME: Will this be a short pointer, and will that matter? */
+ if (indx < 32)
+ return ieee_push_type (info, indx + 32, 0, true, false);
+
+ if (! localp)
+ {
+ m = ieee_get_modified_info (p, indx);
+ if (m == NULL)
+ return false;
+
+ /* FIXME: The size should depend upon the architecture. */
+ if (m->pointer > 0)
+ return ieee_push_type (info, m->pointer, 4, true, false);
+ }
+
+ if (! ieee_define_type (info, 4, true, localp)
+ || ! ieee_write_number (info, 'P')
+ || ! ieee_write_number (info, indx))
+ return false;
+
+ if (! localp)
+ m->pointer = info->type_stack->type.indx;
+
+ return true;
+}
+
+/* Make a function type. This will be called for a method, but we
+ don't want to actually add it to the type table in that case. We
+ handle this by defining the type in a private buffer, and only
+ adding that buffer to the typedef block if we are going to use it. */
+
+static boolean
+ieee_function_type (p, argcount, varargs)
+ PTR p;
+ int argcount;
+ boolean varargs;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ boolean localp;
+ unsigned int *args = NULL;
+ int i;
+ unsigned int retindx;
+ struct ieee_buflist fndef;
+ struct ieee_modified_type *m;
+
+ localp = false;
+
+ if (argcount > 0)
+ {
+ args = (unsigned int *) xmalloc (argcount * sizeof *args);
+ for (i = argcount - 1; i >= 0; i--)
+ {
+ if (info->type_stack->type.localp)
+ localp = true;
+ args[i] = ieee_pop_type (info);
+ }
+ }
+ else if (argcount < 0)
+ varargs = false;
+
+ if (info->type_stack->type.localp)
+ localp = true;
+ retindx = ieee_pop_type (info);
+
+ m = NULL;
+ if (argcount < 0 && ! localp)
+ {
+ m = ieee_get_modified_info (p, retindx);
+ if (m == NULL)
+ return false;
+
+ if (m->function > 0)
+ return ieee_push_type (info, m->function, 0, true, false);
+ }
+
+ /* An attribute of 0x41 means that the frame and push mask are
+ unknown. */
+ if (! ieee_init_buffer (info, &fndef)
+ || ! ieee_define_named_type (info, (const char *) NULL,
+ (unsigned int) -1, 0, true, localp,
+ &fndef)
+ || ! ieee_write_number (info, 'x')
+ || ! ieee_write_number (info, 0x41)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, retindx)
+ || ! ieee_write_number (info, (bfd_vma) argcount + (varargs ? 1 : 0)))
+ return false;
+ if (argcount > 0)
+ {
+ for (i = 0; i < argcount; i++)
+ if (! ieee_write_number (info, args[i]))
+ return false;
+ free (args);
+ }
+ if (varargs)
+ {
+ /* A varargs function is represented by writing out the last
+ argument as type void *, although this makes little sense. */
+ if (! ieee_write_number (info, (bfd_vma) builtin_void + 32))
+ return false;
+ }
+
+ if (! ieee_write_number (info, 0))
+ return false;
+
+ /* We wrote the information into fndef, in case we don't need it.
+ It will be appended to info->types by ieee_pop_type. */
+ info->type_stack->type.fndef = fndef;
+
+ if (m != NULL)
+ m->function = info->type_stack->type.indx;
+
+ return true;
+}
+
+/* Make a reference type. */
+
+static boolean
+ieee_reference_type (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ /* IEEE appears to record a normal pointer type, and then use a
+ pmisc record to indicate that it is really a reference. */
+
+ if (! ieee_pointer_type (p))
+ return false;
+ info->type_stack->type.referencep = true;
+ return true;
+}
+
+/* Make a range type. */
+
+static boolean
+ieee_range_type (p, low, high)
+ PTR p;
+ bfd_signed_vma low;
+ bfd_signed_vma high;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int size;
+ boolean unsignedp, localp;
+
+ size = info->type_stack->type.size;
+ unsignedp = info->type_stack->type.unsignedp;
+ localp = info->type_stack->type.localp;
+ ieee_pop_unused_type (info);
+ return (ieee_define_type (info, size, unsignedp, localp)
+ && ieee_write_number (info, 'R')
+ && ieee_write_number (info, (bfd_vma) low)
+ && ieee_write_number (info, (bfd_vma) high)
+ && ieee_write_number (info, unsignedp ? 0 : 1)
+ && ieee_write_number (info, size));
+}
+
+/* Make an array type. */
+
+/*ARGSUSED*/
+static boolean
+ieee_array_type (p, low, high, stringp)
+ PTR p;
+ bfd_signed_vma low;
+ bfd_signed_vma high;
+ boolean stringp;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int eleindx;
+ boolean localp;
+ unsigned int size;
+ struct ieee_modified_type *m = NULL;
+ struct ieee_modified_array_type *a;
+
+ /* IEEE does not store the range, so we just ignore it. */
+ ieee_pop_unused_type (info);
+ localp = info->type_stack->type.localp;
+ size = info->type_stack->type.size;
+ eleindx = ieee_pop_type (info);
+
+ /* If we don't know the range, treat the size as exactly one
+ element. */
+ if (low < high)
+ size *= (high - low) + 1;
+
+ if (! localp)
+ {
+ m = ieee_get_modified_info (info, eleindx);
+ if (m == NULL)
+ return false;
+
+ for (a = m->arrays; a != NULL; a = a->next)
+ {
+ if (a->low == low && a->high == high)
+ return ieee_push_type (info, a->indx, size, false, false);
+ }
+ }
+
+ if (! ieee_define_type (info, size, false, localp)
+ || ! ieee_write_number (info, low == 0 ? 'Z' : 'C')
+ || ! ieee_write_number (info, eleindx))
+ return false;
+ if (low != 0)
+ {
+ if (! ieee_write_number (info, low))
+ return false;
+ }
+
+ if (! ieee_write_number (info, high + 1))
+ return false;
+
+ if (! localp)
+ {
+ a = (struct ieee_modified_array_type *) xmalloc (sizeof *a);
+ memset (a, 0, sizeof *a);
+
+ a->indx = info->type_stack->type.indx;
+ a->low = low;
+ a->high = high;
+
+ a->next = m->arrays;
+ m->arrays = a;
+ }
+
+ return true;
+}
+
+/* Make a set type. */
+
+static boolean
+ieee_set_type (p, bitstringp)
+ PTR p;
+ boolean bitstringp;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ boolean localp;
+ unsigned int eleindx;
+
+ localp = info->type_stack->type.localp;
+ eleindx = ieee_pop_type (info);
+
+ /* FIXME: We don't know the size, so we just use 4. */
+
+ return (ieee_define_type (info, 0, true, localp)
+ && ieee_write_number (info, 's')
+ && ieee_write_number (info, 4)
+ && ieee_write_number (info, eleindx));
+}
+
+/* Make an offset type. */
+
+static boolean
+ieee_offset_type (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int targetindx, baseindx;
+
+ targetindx = ieee_pop_type (info);
+ baseindx = ieee_pop_type (info);
+
+ /* FIXME: The MRI C++ compiler does not appear to generate any
+ useful type information about an offset type. It just records a
+ pointer to member as an integer. The MRI/HP IEEE spec does
+ describe a pmisc record which can be used for a pointer to
+ member. Unfortunately, it does not describe the target type,
+ which seems pretty important. I'm going to punt this for now. */
+
+ return ieee_int_type (p, 4, true);
+}
+
+/* Make a method type. */
+
+static boolean
+ieee_method_type (p, domain, argcount, varargs)
+ PTR p;
+ boolean domain;
+ int argcount;
+ boolean varargs;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ /* FIXME: The MRI/HP IEEE spec defines a pmisc record to use for a
+ method, but the definition is incomplete. We just output an 'x'
+ type. */
+
+ if (domain)
+ ieee_pop_unused_type (info);
+
+ return ieee_function_type (p, argcount, varargs);
+}
+
+/* Make a const qualified type. */
+
+static boolean
+ieee_const_type (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int size;
+ boolean unsignedp, localp;
+ unsigned int indx;
+ struct ieee_modified_type *m = NULL;
+
+ size = info->type_stack->type.size;
+ unsignedp = info->type_stack->type.unsignedp;
+ localp = info->type_stack->type.localp;
+ indx = ieee_pop_type (info);
+
+ if (! localp)
+ {
+ m = ieee_get_modified_info (info, indx);
+ if (m == NULL)
+ return false;
+
+ if (m->const_qualified > 0)
+ return ieee_push_type (info, m->const_qualified, size, unsignedp,
+ false);
+ }
+
+ if (! ieee_define_type (info, size, unsignedp, localp)
+ || ! ieee_write_number (info, 'n')
+ || ! ieee_write_number (info, 1)
+ || ! ieee_write_number (info, indx))
+ return false;
+
+ if (! localp)
+ m->const_qualified = info->type_stack->type.indx;
+
+ return true;
+}
+
+/* Make a volatile qualified type. */
+
+static boolean
+ieee_volatile_type (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int size;
+ boolean unsignedp, localp;
+ unsigned int indx;
+ struct ieee_modified_type *m = NULL;
+
+ size = info->type_stack->type.size;
+ unsignedp = info->type_stack->type.unsignedp;
+ localp = info->type_stack->type.localp;
+ indx = ieee_pop_type (info);
+
+ if (! localp)
+ {
+ m = ieee_get_modified_info (info, indx);
+ if (m == NULL)
+ return false;
+
+ if (m->volatile_qualified > 0)
+ return ieee_push_type (info, m->volatile_qualified, size, unsignedp,
+ false);
+ }
+
+ if (! ieee_define_type (info, size, unsignedp, localp)
+ || ! ieee_write_number (info, 'n')
+ || ! ieee_write_number (info, 2)
+ || ! ieee_write_number (info, indx))
+ return false;
+
+ if (! localp)
+ m->volatile_qualified = info->type_stack->type.indx;
+
+ return true;
+}
+
+/* Convert an enum debug_visibility into a CXXFLAGS value. */
+
+static unsigned int
+ieee_vis_to_flags (visibility)
+ enum debug_visibility visibility;
+{
+ switch (visibility)
+ {
+ default:
+ abort ();
+ case DEBUG_VISIBILITY_PUBLIC:
+ return CXXFLAGS_VISIBILITY_PUBLIC;
+ case DEBUG_VISIBILITY_PRIVATE:
+ return CXXFLAGS_VISIBILITY_PRIVATE;
+ case DEBUG_VISIBILITY_PROTECTED:
+ return CXXFLAGS_VISIBILITY_PROTECTED;
+ }
+ /*NOTREACHED*/
+}
+
+/* Start defining a struct type. We build it in the strdef field on
+ the stack, to avoid confusing type definitions required by the
+ fields with the struct type itself. */
+
+static boolean
+ieee_start_struct_type (p, tag, id, structp, size)
+ PTR p;
+ const char *tag;
+ unsigned int id;
+ boolean structp;
+ unsigned int size;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ boolean localp, ignorep;
+ boolean copy;
+ char ab[20];
+ const char *look;
+ struct ieee_name_type_hash_entry *h;
+ struct ieee_name_type *nt, *ntlook;
+ struct ieee_buflist strdef;
+
+ localp = false;
+ ignorep = false;
+
+ /* We need to create a tag for internal use even if we don't want
+ one for external use. This will let us refer to an anonymous
+ struct. */
+ if (tag != NULL)
+ {
+ look = tag;
+ copy = false;
+ }
+ else
+ {
+ sprintf (ab, "__anon%u", id);
+ look = ab;
+ copy = true;
+ }
+
+ /* If we already have references to the tag, we must use the
+ existing type index. */
+ h = ieee_name_type_hash_lookup (&info->tags, look, true, copy);
+ if (h == NULL)
+ return false;
+
+ nt = NULL;
+ for (ntlook = h->types; ntlook != NULL; ntlook = ntlook->next)
+ {
+ if (ntlook->id == id)
+ nt = ntlook;
+ else if (! ntlook->type.localp)
+ {
+ /* We are creating a duplicate definition of a globally
+ defined tag. Force it to be local to avoid
+ confusion. */
+ localp = true;
+ }
+ }
+
+ if (nt != NULL)
+ {
+ assert (localp == nt->type.localp);
+ if (nt->kind == DEBUG_KIND_ILLEGAL && ! localp)
+ {
+ /* We've already seen a global definition of the type.
+ Ignore this new definition. */
+ ignorep = true;
+ }
+ }
+ else
+ {
+ nt = (struct ieee_name_type *) xmalloc (sizeof *nt);
+ memset (nt, 0, sizeof *nt);
+ nt->id = id;
+ nt->type.name = h->root.string;
+ nt->next = h->types;
+ h->types = nt;
+ nt->type.indx = info->type_indx;
+ ++info->type_indx;
+ }
+
+ nt->kind = DEBUG_KIND_ILLEGAL;
+
+ if (! ieee_init_buffer (info, &strdef)
+ || ! ieee_define_named_type (info, tag, nt->type.indx, size, true,
+ localp, &strdef)
+ || ! ieee_write_number (info, structp ? 'S' : 'U')
+ || ! ieee_write_number (info, size))
+ return false;
+
+ if (! ignorep)
+ {
+ const char *hold;
+
+ /* We never want nt->type.name to be NULL. We want the rest of
+ the type to be the object set up on the type stack; it will
+ have a NULL name if tag is NULL. */
+ hold = nt->type.name;
+ nt->type = info->type_stack->type;
+ nt->type.name = hold;
+ }
+
+ info->type_stack->type.name = tag;
+ info->type_stack->type.strdef = strdef;
+ info->type_stack->type.ignorep = ignorep;
+
+ return true;
+}
+
+/* Add a field to a struct. */
+
+static boolean
+ieee_struct_field (p, name, bitpos, bitsize, visibility)
+ PTR p;
+ const char *name;
+ bfd_vma bitpos;
+ bfd_vma bitsize;
+ enum debug_visibility visibility;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int size;
+ boolean unsignedp;
+ boolean referencep;
+ boolean localp;
+ unsigned int indx;
+ bfd_vma offset;
+
+ assert (info->type_stack != NULL
+ && info->type_stack->next != NULL
+ && ! ieee_buffer_emptyp (&info->type_stack->next->type.strdef));
+
+ /* If we are ignoring this struct definition, just pop and ignore
+ the type. */
+ if (info->type_stack->next->type.ignorep)
+ {
+ ieee_pop_unused_type (info);
+ return true;
+ }
+
+ size = info->type_stack->type.size;
+ unsignedp = info->type_stack->type.unsignedp;
+ referencep = info->type_stack->type.referencep;
+ localp = info->type_stack->type.localp;
+ indx = ieee_pop_type (info);
+
+ if (localp)
+ info->type_stack->type.localp = true;
+
+ if (info->type_stack->type.classdef != NULL)
+ {
+ unsigned int flags;
+ unsigned int nindx;
+
+ /* This is a class. We must add a description of this field to
+ the class records we are building. */
+
+ flags = ieee_vis_to_flags (visibility);
+ nindx = info->type_stack->type.classdef->indx;
+ if (! ieee_change_buffer (info,
+ &info->type_stack->type.classdef->pmiscbuf)
+ || ! ieee_write_asn (info, nindx, 'd')
+ || ! ieee_write_asn (info, nindx, flags)
+ || ! ieee_write_atn65 (info, nindx, name)
+ || ! ieee_write_atn65 (info, nindx, name))
+ return false;
+ info->type_stack->type.classdef->pmisccount += 4;
+
+ if (referencep)
+ {
+ unsigned int nindx;
+
+ /* We need to output a record recording that this field is
+ really of reference type. We put this on the refs field
+ of classdef, so that it can be appended to the C++
+ records after the class is defined. */
+
+ nindx = info->name_indx;
+ ++info->name_indx;
+
+ if (! ieee_change_buffer (info,
+ &info->type_stack->type.classdef->refs)
+ || ! ieee_write_byte (info, (int) ieee_nn_record)
+ || ! ieee_write_number (info, nindx)
+ || ! ieee_write_id (info, "")
+ || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
+ || ! ieee_write_number (info, nindx)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, 62)
+ || ! ieee_write_number (info, 80)
+ || ! ieee_write_number (info, 4)
+ || ! ieee_write_asn (info, nindx, 'R')
+ || ! ieee_write_asn (info, nindx, 3)
+ || ! ieee_write_atn65 (info, nindx, info->type_stack->type.name)
+ || ! ieee_write_atn65 (info, nindx, name))
+ return false;
+ }
+ }
+
+ /* If the bitsize doesn't match the expected size, we need to output
+ a bitfield type. */
+ if (size == 0 || bitsize == 0 || bitsize == size * 8)
+ offset = bitpos / 8;
+ else
+ {
+ if (! ieee_define_type (info, 0, unsignedp,
+ info->type_stack->type.localp)
+ || ! ieee_write_number (info, 'g')
+ || ! ieee_write_number (info, unsignedp ? 0 : 1)
+ || ! ieee_write_number (info, bitsize)
+ || ! ieee_write_number (info, indx))
+ return false;
+ indx = ieee_pop_type (info);
+ offset = bitpos;
+ }
+
+ /* Switch to the struct we are building in order to output this
+ field definition. */
+ return (ieee_change_buffer (info, &info->type_stack->type.strdef)
+ && ieee_write_id (info, name)
+ && ieee_write_number (info, indx)
+ && ieee_write_number (info, offset));
+}
+
+/* Finish up a struct type. */
+
+static boolean
+ieee_end_struct_type (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ struct ieee_buflist *pb;
+
+ assert (info->type_stack != NULL
+ && ! ieee_buffer_emptyp (&info->type_stack->type.strdef));
+
+ /* If we were ignoring this struct definition because it was a
+ duplicate defintion, just through away whatever bytes we have
+ accumulated. Leave the type on the stack. */
+ if (info->type_stack->type.ignorep)
+ return true;
+
+ /* If this is not a duplicate definition of this tag, then localp
+ will be false, and we can put it in the global type block.
+ FIXME: We should avoid outputting duplicate definitions which are
+ the same. */
+ if (! info->type_stack->type.localp)
+ {
+ /* Make sure we have started the global type block. */
+ if (ieee_buffer_emptyp (&info->global_types))
+ {
+ if (! ieee_change_buffer (info, &info->global_types)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 2)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, ""))
+ return false;
+ }
+ pb = &info->global_types;
+ }
+ else
+ {
+ /* Make sure we have started the types block. */
+ if (ieee_buffer_emptyp (&info->types))
+ {
+ if (! ieee_change_buffer (info, &info->types)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 1)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, info->modname))
+ return false;
+ }
+ pb = &info->types;
+ }
+
+ /* Append the struct definition to the types. */
+ if (! ieee_append_buffer (info, pb, &info->type_stack->type.strdef)
+ || ! ieee_init_buffer (info, &info->type_stack->type.strdef))
+ return false;
+
+ /* Leave the struct on the type stack. */
+
+ return true;
+}
+
+/* Start a class type. */
+
+static boolean
+ieee_start_class_type (p, tag, id, structp, size, vptr, ownvptr)
+ PTR p;
+ const char *tag;
+ unsigned int id;
+ boolean structp;
+ unsigned int size;
+ boolean vptr;
+ boolean ownvptr;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ const char *vclass;
+ struct ieee_buflist pmiscbuf;
+ unsigned int indx;
+ struct ieee_type_class *classdef;
+
+ /* A C++ class is output as a C++ struct along with a set of pmisc
+ records describing the class. */
+
+ /* We need to have a name so that we can associate the struct and
+ the class. */
+ if (tag == NULL)
+ {
+ char *t;
+
+ t = (char *) xmalloc (20);
+ sprintf (t, "__anon%u", id);
+ tag = t;
+ }
+
+ /* We can't write out the virtual table information until we have
+ finished the class, because we don't know the virtual table size.
+ We get the size from the largest voffset we see. */
+ vclass = NULL;
+ if (vptr && ! ownvptr)
+ {
+ vclass = info->type_stack->type.name;
+ assert (vclass != NULL);
+ /* We don't call ieee_pop_unused_type, since the class should
+ get defined. */
+ (void) ieee_pop_type (info);
+ }
+
+ if (! ieee_start_struct_type (p, tag, id, structp, size))
+ return false;
+
+ indx = info->name_indx;
+ ++info->name_indx;
+
+ /* We write out pmisc records into the classdef field. We will
+ write out the pmisc start after we know the number of records we
+ need. */
+ if (! ieee_init_buffer (info, &pmiscbuf)
+ || ! ieee_change_buffer (info, &pmiscbuf)
+ || ! ieee_write_asn (info, indx, 'T')
+ || ! ieee_write_asn (info, indx, structp ? 'o' : 'u')
+ || ! ieee_write_atn65 (info, indx, tag))
+ return false;
+
+ classdef = (struct ieee_type_class *) xmalloc (sizeof *classdef);
+ memset (classdef, 0, sizeof *classdef);
+
+ classdef->indx = indx;
+ classdef->pmiscbuf = pmiscbuf;
+ classdef->pmisccount = 3;
+ classdef->vclass = vclass;
+ classdef->ownvptr = ownvptr;
+
+ info->type_stack->type.classdef = classdef;
+
+ return true;
+}
+
+/* Add a static member to a class. */
+
+static boolean
+ieee_class_static_member (p, name, physname, visibility)
+ PTR p;
+ const char *name;
+ const char *physname;
+ enum debug_visibility visibility;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int flags;
+ unsigned int nindx;
+
+ /* We don't care about the type. Hopefully there will be a call to
+ ieee_variable declaring the physical name and the type, since
+ that is where an IEEE consumer must get the type. */
+ ieee_pop_unused_type (info);
+
+ assert (info->type_stack != NULL
+ && info->type_stack->type.classdef != NULL);
+
+ flags = ieee_vis_to_flags (visibility);
+ flags |= CXXFLAGS_STATIC;
+
+ nindx = info->type_stack->type.classdef->indx;
+
+ if (! ieee_change_buffer (info, &info->type_stack->type.classdef->pmiscbuf)
+ || ! ieee_write_asn (info, nindx, 'd')
+ || ! ieee_write_asn (info, nindx, flags)
+ || ! ieee_write_atn65 (info, nindx, name)
+ || ! ieee_write_atn65 (info, nindx, physname))
+ return false;
+ info->type_stack->type.classdef->pmisccount += 4;
+
+ return true;
+}
+
+/* Add a base class to a class. */
+
+static boolean
+ieee_class_baseclass (p, bitpos, virtual, visibility)
+ PTR p;
+ bfd_vma bitpos;
+ boolean virtual;
+ enum debug_visibility visibility;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ const char *bname;
+ boolean localp;
+ unsigned int bindx;
+ char *fname;
+ unsigned int flags;
+ unsigned int nindx;
+
+ assert (info->type_stack != NULL
+ && info->type_stack->type.name != NULL
+ && info->type_stack->next != NULL
+ && info->type_stack->next->type.classdef != NULL
+ && ! ieee_buffer_emptyp (&info->type_stack->next->type.strdef));
+
+ bname = info->type_stack->type.name;
+ localp = info->type_stack->type.localp;
+ bindx = ieee_pop_type (info);
+
+ /* We are currently defining both a struct and a class. We must
+ write out a field definition in the struct which holds the base
+ class. The stabs debugging reader will create a field named
+ _vb$CLASS for a virtual base class, so we just use that. FIXME:
+ we should not depend upon a detail of stabs debugging. */
+ if (virtual)
+ {
+ fname = (char *) xmalloc (strlen (bname) + sizeof "_vb$");
+ sprintf (fname, "_vb$%s", bname);
+ flags = BASEFLAGS_VIRTUAL;
+ }
+ else
+ {
+ if (localp)
+ info->type_stack->type.localp = true;
+
+ fname = (char *) xmalloc (strlen (bname) + sizeof "_b$");
+ sprintf (fname, "_b$%s", bname);
+
+ if (! ieee_change_buffer (info, &info->type_stack->type.strdef)
+ || ! ieee_write_id (info, fname)
+ || ! ieee_write_number (info, bindx)
+ || ! ieee_write_number (info, bitpos / 8))
+ return false;
+ flags = 0;
+ }
+
+ if (visibility == DEBUG_VISIBILITY_PRIVATE)
+ flags |= BASEFLAGS_PRIVATE;
+
+ nindx = info->type_stack->type.classdef->indx;
+
+ if (! ieee_change_buffer (info, &info->type_stack->type.classdef->pmiscbuf)
+ || ! ieee_write_asn (info, nindx, 'b')
+ || ! ieee_write_asn (info, nindx, flags)
+ || ! ieee_write_atn65 (info, nindx, bname)
+ || ! ieee_write_asn (info, nindx, 0)
+ || ! ieee_write_atn65 (info, nindx, fname))
+ return false;
+ info->type_stack->type.classdef->pmisccount += 5;
+
+ free (fname);
+
+ return true;
+}
+
+/* Start building a method for a class. */
+
+static boolean
+ieee_class_start_method (p, name)
+ PTR p;
+ const char *name;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ assert (info->type_stack != NULL
+ && info->type_stack->type.classdef != NULL
+ && info->type_stack->type.classdef->method == NULL);
+
+ info->type_stack->type.classdef->method = name;
+
+ return true;
+}
+
+/* Define a new method variant, either static or not. */
+
+static boolean
+ieee_class_method_var (info, physname, visibility, staticp, constp,
+ volatilep, voffset, context)
+ struct ieee_handle *info;
+ const char *physname;
+ enum debug_visibility visibility;
+ boolean staticp;
+ boolean constp;
+ boolean volatilep;
+ bfd_vma voffset;
+ boolean context;
+{
+ unsigned int flags;
+ unsigned int nindx;
+ boolean virtual;
+
+ /* We don't need the type of the method. An IEEE consumer which
+ wants the type must track down the function by the physical name
+ and get the type from that. */
+ ieee_pop_unused_type (info);
+
+ /* We don't use the context. FIXME: We probably ought to use it to
+ adjust the voffset somehow, but I don't really know how. */
+ if (context)
+ ieee_pop_unused_type (info);
+
+ assert (info->type_stack != NULL
+ && info->type_stack->type.classdef != NULL
+ && info->type_stack->type.classdef->method != NULL);
+
+ flags = ieee_vis_to_flags (visibility);
+
+ /* FIXME: We never set CXXFLAGS_OVERRIDE, CXXFLAGS_OPERATOR,
+ CXXFLAGS_CTORDTOR, CXXFLAGS_CTOR, or CXXFLAGS_INLINE. */
+
+ if (staticp)
+ flags |= CXXFLAGS_STATIC;
+ if (constp)
+ flags |= CXXFLAGS_CONST;
+ if (volatilep)
+ flags |= CXXFLAGS_VOLATILE;
+
+ nindx = info->type_stack->type.classdef->indx;
+
+ virtual = context || voffset > 0;
+
+ if (! ieee_change_buffer (info,
+ &info->type_stack->type.classdef->pmiscbuf)
+ || ! ieee_write_asn (info, nindx, virtual ? 'v' : 'm')
+ || ! ieee_write_asn (info, nindx, flags)
+ || ! ieee_write_atn65 (info, nindx,
+ info->type_stack->type.classdef->method)
+ || ! ieee_write_atn65 (info, nindx, physname))
+ return false;
+
+ if (virtual)
+ {
+ if (voffset > info->type_stack->type.classdef->voffset)
+ info->type_stack->type.classdef->voffset = voffset;
+ if (! ieee_write_asn (info, nindx, voffset))
+ return false;
+ ++info->type_stack->type.classdef->pmisccount;
+ }
+
+ if (! ieee_write_asn (info, nindx, 0))
+ return false;
+
+ info->type_stack->type.classdef->pmisccount += 5;
+
+ return true;
+}
+
+/* Define a new method variant. */
+
+static boolean
+ieee_class_method_variant (p, physname, visibility, constp, volatilep,
+ voffset, context)
+ PTR p;
+ const char *physname;
+ enum debug_visibility visibility;
+ boolean constp;
+ boolean volatilep;
+ bfd_vma voffset;
+ boolean context;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ return ieee_class_method_var (info, physname, visibility, false, constp,
+ volatilep, voffset, context);
+}
+
+/* Define a new static method variant. */
+
+static boolean
+ieee_class_static_method_variant (p, physname, visibility, constp, volatilep)
+ PTR p;
+ const char *physname;
+ enum debug_visibility visibility;
+ boolean constp;
+ boolean volatilep;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ return ieee_class_method_var (info, physname, visibility, true, constp,
+ volatilep, 0, false);
+}
+
+/* Finish up a method. */
+
+static boolean
+ieee_class_end_method (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ assert (info->type_stack != NULL
+ && info->type_stack->type.classdef != NULL
+ && info->type_stack->type.classdef->method != NULL);
+
+ info->type_stack->type.classdef->method = NULL;
+
+ return true;
+}
+
+/* Finish up a class. */
+
+static boolean
+ieee_end_class_type (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int nindx;
+
+ assert (info->type_stack != NULL
+ && info->type_stack->type.classdef != NULL);
+
+ /* If we were ignoring this class definition because it was a
+ duplicate definition, just through away whatever bytes we have
+ accumulated. Leave the type on the stack. */
+ if (info->type_stack->type.ignorep)
+ return true;
+
+ nindx = info->type_stack->type.classdef->indx;
+
+ /* If we have a virtual table, we can write out the information now. */
+ if (info->type_stack->type.classdef->vclass != NULL
+ || info->type_stack->type.classdef->ownvptr)
+ {
+ if (! ieee_change_buffer (info,
+ &info->type_stack->type.classdef->pmiscbuf)
+ || ! ieee_write_asn (info, nindx, 'z')
+ || ! ieee_write_atn65 (info, nindx, "")
+ || ! ieee_write_asn (info, nindx,
+ info->type_stack->type.classdef->voffset))
+ return false;
+ if (info->type_stack->type.classdef->ownvptr)
+ {
+ if (! ieee_write_atn65 (info, nindx, ""))
+ return false;
+ }
+ else
+ {
+ if (! ieee_write_atn65 (info, nindx,
+ info->type_stack->type.classdef->vclass))
+ return false;
+ }
+ if (! ieee_write_asn (info, nindx, 0))
+ return false;
+ info->type_stack->type.classdef->pmisccount += 5;
+ }
+
+ /* Now that we know the number of pmisc records, we can write out
+ the atn62 which starts the pmisc records, and append them to the
+ C++ buffers. */
+
+ if (! ieee_change_buffer (info, &info->cxx)
+ || ! ieee_write_byte (info, (int) ieee_nn_record)
+ || ! ieee_write_number (info, nindx)
+ || ! ieee_write_id (info, "")
+ || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
+ || ! ieee_write_number (info, nindx)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, 62)
+ || ! ieee_write_number (info, 80)
+ || ! ieee_write_number (info,
+ info->type_stack->type.classdef->pmisccount))
+ return false;
+
+ if (! ieee_append_buffer (info, &info->cxx,
+ &info->type_stack->type.classdef->pmiscbuf))
+ return false;
+ if (! ieee_buffer_emptyp (&info->type_stack->type.classdef->refs))
+ {
+ if (! ieee_append_buffer (info, &info->cxx,
+ &info->type_stack->type.classdef->refs))
+ return false;
+ }
+
+ return ieee_end_struct_type (p);
+}
+
+/* Push a previously seen typedef onto the type stack. */
+
+static boolean
+ieee_typedef_type (p, name)
+ PTR p;
+ const char *name;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ struct ieee_name_type_hash_entry *h;
+ struct ieee_name_type *nt;
+
+ h = ieee_name_type_hash_lookup (&info->typedefs, name, false, false);
+
+ /* h should never be NULL, since that would imply that the generic
+ debugging code has asked for a typedef which it has not yet
+ defined. */
+ assert (h != NULL);
+
+ /* We always use the most recently defined type for this name, which
+ will be the first one on the list. */
+
+ nt = h->types;
+ if (! ieee_push_type (info, nt->type.indx, nt->type.size,
+ nt->type.unsignedp, nt->type.localp))
+ return false;
+
+ /* Copy over any other type information we may have. */
+ info->type_stack->type = nt->type;
+
+ return true;
+}
+
+/* Push a tagged type onto the type stack. */
+
+static boolean
+ieee_tag_type (p, name, id, kind)
+ PTR p;
+ const char *name;
+ unsigned int id;
+ enum debug_type_kind kind;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ boolean localp;
+ boolean copy;
+ char ab[20];
+ struct ieee_name_type_hash_entry *h;
+ struct ieee_name_type *nt;
+
+ if (kind == DEBUG_KIND_ENUM)
+ {
+ struct ieee_defined_enum *e;
+
+ if (name == NULL)
+ abort ();
+ for (e = info->enums; e != NULL; e = e->next)
+ if (e->tag != NULL && strcmp (e->tag, name) == 0)
+ return ieee_push_type (info, e->indx, 0, true, false);
+
+ e = (struct ieee_defined_enum *) xmalloc (sizeof *e);
+ memset (e, 0, sizeof *e);
+
+ e->indx = info->type_indx;
+ ++info->type_indx;
+ e->tag = name;
+ e->defined = false;
+
+ e->next = info->enums;
+ info->enums = e;
+
+ return ieee_push_type (info, e->indx, 0, true, false);
+ }
+
+ localp = false;
+
+ copy = false;
+ if (name == NULL)
+ {
+ sprintf (ab, "__anon%u", id);
+ name = ab;
+ copy = true;
+ }
+
+ h = ieee_name_type_hash_lookup (&info->tags, name, true, copy);
+ if (h == NULL)
+ return false;
+
+ for (nt = h->types; nt != NULL; nt = nt->next)
+ {
+ if (nt->id == id)
+ {
+ if (! ieee_push_type (info, nt->type.indx, nt->type.size,
+ nt->type.unsignedp, nt->type.localp))
+ return false;
+ /* Copy over any other type information we may have. */
+ info->type_stack->type = nt->type;
+ return true;
+ }
+
+ if (! nt->type.localp)
+ {
+ /* This is a duplicate of a global type, so it must be
+ local. */
+ localp = true;
+ }
+ }
+
+ nt = (struct ieee_name_type *) xmalloc (sizeof *nt);
+ memset (nt, 0, sizeof *nt);
+
+ nt->id = id;
+ nt->type.name = h->root.string;
+ nt->type.indx = info->type_indx;
+ nt->type.localp = localp;
+ ++info->type_indx;
+ nt->kind = kind;
+
+ nt->next = h->types;
+ h->types = nt;
+
+ if (! ieee_push_type (info, nt->type.indx, 0, false, localp))
+ return false;
+
+ info->type_stack->type.name = h->root.string;
+
+ return true;
+}
+
+/* Output a typedef. */
+
+static boolean
+ieee_typdef (p, name)
+ PTR p;
+ const char *name;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ struct ieee_write_type type;
+ unsigned int indx;
+ boolean found;
+ boolean localp;
+ struct ieee_name_type_hash_entry *h;
+ struct ieee_name_type *nt;
+
+ type = info->type_stack->type;
+ indx = type.indx;
+
+ /* If this is a simple builtin type using a builtin name, we don't
+ want to output the typedef itself. We also want to change the
+ type index to correspond to the name being used. We recognize
+ names used in stabs debugging output even if they don't exactly
+ correspond to the names used for the IEEE builtin types. */
+ found = false;
+ if (indx <= (unsigned int) builtin_bcd_float)
+ {
+ switch ((enum builtin_types) indx)
+ {
+ default:
+ break;
+
+ case builtin_void:
+ if (strcmp (name, "void") == 0)
+ found = true;
+ break;
+
+ case builtin_signed_char:
+ case builtin_char:
+ if (strcmp (name, "signed char") == 0)
+ {
+ indx = (unsigned int) builtin_signed_char;
+ found = true;
+ }
+ else if (strcmp (name, "char") == 0)
+ {
+ indx = (unsigned int) builtin_char;
+ found = true;
+ }
+ break;
+
+ case builtin_unsigned_char:
+ if (strcmp (name, "unsigned char") == 0)
+ found = true;
+ break;
+
+ case builtin_signed_short_int:
+ case builtin_short:
+ case builtin_short_int:
+ case builtin_signed_short:
+ if (strcmp (name, "signed short int") == 0)
+ {
+ indx = (unsigned int) builtin_signed_short_int;
+ found = true;
+ }
+ else if (strcmp (name, "short") == 0)
+ {
+ indx = (unsigned int) builtin_short;
+ found = true;
+ }
+ else if (strcmp (name, "short int") == 0)
+ {
+ indx = (unsigned int) builtin_short_int;
+ found = true;
+ }
+ else if (strcmp (name, "signed short") == 0)
+ {
+ indx = (unsigned int) builtin_signed_short;
+ found = true;
+ }
+ break;
+
+ case builtin_unsigned_short_int:
+ case builtin_unsigned_short:
+ if (strcmp (name, "unsigned short int") == 0
+ || strcmp (name, "short unsigned int") == 0)
+ {
+ indx = builtin_unsigned_short_int;
+ found = true;
+ }
+ else if (strcmp (name, "unsigned short") == 0)
+ {
+ indx = builtin_unsigned_short;
+ found = true;
+ }
+ break;
+
+ case builtin_signed_long:
+ case builtin_int: /* FIXME: Size depends upon architecture. */
+ case builtin_long:
+ if (strcmp (name, "signed long") == 0)
+ {
+ indx = builtin_signed_long;
+ found = true;
+ }
+ else if (strcmp (name, "int") == 0)
+ {
+ indx = builtin_int;
+ found = true;
+ }
+ else if (strcmp (name, "long") == 0
+ || strcmp (name, "long int") == 0)
+ {
+ indx = builtin_long;
+ found = true;
+ }
+ break;
+
+ case builtin_unsigned_long:
+ case builtin_unsigned: /* FIXME: Size depends upon architecture. */
+ case builtin_unsigned_int: /* FIXME: Like builtin_unsigned. */
+ if (strcmp (name, "unsigned long") == 0
+ || strcmp (name, "long unsigned int") == 0)
+ {
+ indx = builtin_unsigned_long;
+ found = true;
+ }
+ else if (strcmp (name, "unsigned") == 0)
+ {
+ indx = builtin_unsigned;
+ found = true;
+ }
+ else if (strcmp (name, "unsigned int") == 0)
+ {
+ indx = builtin_unsigned_int;
+ found = true;
+ }
+ break;
+
+ case builtin_signed_long_long:
+ if (strcmp (name, "signed long long") == 0
+ || strcmp (name, "long long int") == 0)
+ found = true;
+ break;
+
+ case builtin_unsigned_long_long:
+ if (strcmp (name, "unsigned long long") == 0
+ || strcmp (name, "long long unsigned int") == 0)
+ found = true;
+ break;
+
+ case builtin_float:
+ if (strcmp (name, "float") == 0)
+ found = true;
+ break;
+
+ case builtin_double:
+ if (strcmp (name, "double") == 0)
+ found = true;
+ break;
+
+ case builtin_long_double:
+ if (strcmp (name, "long double") == 0)
+ found = true;
+ break;
+
+ case builtin_long_long_double:
+ if (strcmp (name, "long long double") == 0)
+ found = true;
+ break;
+ }
+
+ if (found)
+ type.indx = indx;
+ }
+
+ h = ieee_name_type_hash_lookup (&info->typedefs, name, true, false);
+ if (h == NULL)
+ return false;
+
+ /* See if we have already defined this type with this name. */
+ localp = type.localp;
+ for (nt = h->types; nt != NULL; nt = nt->next)
+ {
+ if (nt->id == indx)
+ {
+ /* If this is a global definition, then we don't need to
+ do anything here. */
+ if (! nt->type.localp)
+ {
+ ieee_pop_unused_type (info);
+ return true;
+ }
+ }
+ else
+ {
+ /* This is a duplicate definition, so make this one local. */
+ localp = true;
+ }
+ }
+
+ /* We need to add a new typedef for this type. */
+
+ nt = (struct ieee_name_type *) xmalloc (sizeof *nt);
+ memset (nt, 0, sizeof *nt);
+ nt->id = indx;
+ nt->type = type;
+ nt->type.name = name;
+ nt->type.localp = localp;
+ nt->kind = DEBUG_KIND_ILLEGAL;
+
+ nt->next = h->types;
+ h->types = nt;
+
+ if (found)
+ {
+ /* This is one of the builtin typedefs, so we don't need to
+ actually define it. */
+ ieee_pop_unused_type (info);
+ return true;
+ }
+
+ indx = ieee_pop_type (info);
+
+ if (! ieee_define_named_type (info, name, (unsigned int) -1, type.size,
+ type.unsignedp, localp,
+ (struct ieee_buflist *) NULL)
+ || ! ieee_write_number (info, 'T')
+ || ! ieee_write_number (info, indx))
+ return false;
+
+ /* Remove the type we just added to the type stack. This should not
+ be ieee_pop_unused_type, since the type is used, we just don't
+ need it now. */
+ (void) ieee_pop_type (info);
+
+ return true;
+}
+
+/* Output a tag for a type. We don't have to do anything here. */
+
+static boolean
+ieee_tag (p, name)
+ PTR p;
+ const char *name;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ /* This should not be ieee_pop_unused_type, since we want the type
+ to be defined. */
+ (void) ieee_pop_type (info);
+ return true;
+}
+
+/* Output an integer constant. */
+
+static boolean
+ieee_int_constant (p, name, val)
+ PTR p;
+ const char *name;
+ bfd_vma val;
+{
+ /* FIXME. */
+ return true;
+}
+
+/* Output a floating point constant. */
+
+static boolean
+ieee_float_constant (p, name, val)
+ PTR p;
+ const char *name;
+ double val;
+{
+ /* FIXME. */
+ return true;
+}
+
+/* Output a typed constant. */
+
+static boolean
+ieee_typed_constant (p, name, val)
+ PTR p;
+ const char *name;
+ bfd_vma val;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ /* FIXME. */
+ ieee_pop_unused_type (info);
+ return true;
+}
+
+/* Output a variable. */
+
+static boolean
+ieee_variable (p, name, kind, val)
+ PTR p;
+ const char *name;
+ enum debug_var_kind kind;
+ bfd_vma val;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ unsigned int name_indx;
+ unsigned int size;
+ boolean referencep;
+ unsigned int type_indx;
+ boolean asn;
+ int refflag;
+
+ size = info->type_stack->type.size;
+ referencep = info->type_stack->type.referencep;
+ type_indx = ieee_pop_type (info);
+
+ assert (! ieee_buffer_emptyp (&info->vars));
+ if (! ieee_change_buffer (info, &info->vars))
+ return false;
+
+ name_indx = info->name_indx;
+ ++info->name_indx;
+
+ /* Write out an NN and an ATN record for this variable. */
+ if (! ieee_write_byte (info, (int) ieee_nn_record)
+ || ! ieee_write_number (info, name_indx)
+ || ! ieee_write_id (info, name)
+ || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
+ || ! ieee_write_number (info, name_indx)
+ || ! ieee_write_number (info, type_indx))
+ return false;
+ switch (kind)
+ {
+ default:
+ abort ();
+ return false;
+ case DEBUG_GLOBAL:
+ if (! ieee_write_number (info, 8)
+ || ! ieee_add_range (info, false, val, val + size))
+ return false;
+ refflag = 0;
+ asn = true;
+ break;
+ case DEBUG_STATIC:
+ if (! ieee_write_number (info, 3)
+ || ! ieee_add_range (info, false, val, val + size))
+ return false;
+ refflag = 1;
+ asn = true;
+ break;
+ case DEBUG_LOCAL_STATIC:
+ if (! ieee_write_number (info, 3)
+ || ! ieee_add_range (info, false, val, val + size))
+ return false;
+ refflag = 2;
+ asn = true;
+ break;
+ case DEBUG_LOCAL:
+ if (! ieee_write_number (info, 1)
+ || ! ieee_write_number (info, val))
+ return false;
+ refflag = 2;
+ asn = false;
+ break;
+ case DEBUG_REGISTER:
+ if (! ieee_write_number (info, 2)
+ || ! ieee_write_number (info,
+ ieee_genreg_to_regno (info->abfd, val)))
+ return false;
+ refflag = 2;
+ asn = false;
+ break;
+ }
+
+ if (asn)
+ {
+ if (! ieee_write_asn (info, name_indx, val))
+ return false;
+ }
+
+ /* If this is really a reference type, then we just output it with
+ pointer type, and must now output a C++ record indicating that it
+ is really reference type. */
+ if (referencep)
+ {
+ unsigned int nindx;
+
+ nindx = info->name_indx;
+ ++info->name_indx;
+
+ /* If this is a global variable, we want to output the misc
+ record in the C++ misc record block. Otherwise, we want to
+ output it just after the variable definition, which is where
+ the current buffer is. */
+ if (refflag != 2)
+ {
+ if (! ieee_change_buffer (info, &info->cxx))
+ return false;
+ }
+
+ if (! ieee_write_byte (info, (int) ieee_nn_record)
+ || ! ieee_write_number (info, nindx)
+ || ! ieee_write_id (info, "")
+ || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
+ || ! ieee_write_number (info, nindx)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, 62)
+ || ! ieee_write_number (info, 80)
+ || ! ieee_write_number (info, 3)
+ || ! ieee_write_asn (info, nindx, 'R')
+ || ! ieee_write_asn (info, nindx, refflag)
+ || ! ieee_write_atn65 (info, nindx, name))
+ return false;
+ }
+
+ return true;
+}
+
+/* Start outputting information for a function. */
+
+static boolean
+ieee_start_function (p, name, global)
+ PTR p;
+ const char *name;
+ boolean global;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ boolean referencep;
+ unsigned int retindx, typeindx;
+
+ referencep = info->type_stack->type.referencep;
+ retindx = ieee_pop_type (info);
+
+ /* Besides recording a BB4 or BB6 block, we record the type of the
+ function in the BB1 typedef block. We can't write out the full
+ type until we have seen all the parameters, so we accumulate it
+ in info->fntype and info->fnargs. */
+ if (! ieee_buffer_emptyp (&info->fntype))
+ {
+ /* FIXME: This might happen someday if we support nested
+ functions. */
+ abort ();
+ }
+
+ info->fnname = name;
+
+ /* An attribute of 0x40 means that the push mask is unknown. */
+ if (! ieee_define_named_type (info, name, (unsigned int) -1, 0, false, true,
+ &info->fntype)
+ || ! ieee_write_number (info, 'x')
+ || ! ieee_write_number (info, 0x40)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, retindx))
+ return false;
+
+ typeindx = ieee_pop_type (info);
+
+ if (! ieee_init_buffer (info, &info->fnargs))
+ return false;
+ info->fnargcount = 0;
+
+ /* If the function return value is actually a reference type, we
+ must add a record indicating that. */
+ if (referencep)
+ {
+ unsigned int nindx;
+
+ nindx = info->name_indx;
+ ++info->name_indx;
+ if (! ieee_change_buffer (info, &info->cxx)
+ || ! ieee_write_byte (info, (int) ieee_nn_record)
+ || ! ieee_write_number (info, nindx)
+ || ! ieee_write_id (info, "")
+ || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
+ || ! ieee_write_number (info, nindx)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, 62)
+ || ! ieee_write_number (info, 80)
+ || ! ieee_write_number (info, 3)
+ || ! ieee_write_asn (info, nindx, 'R')
+ || ! ieee_write_asn (info, nindx, global ? 0 : 1)
+ || ! ieee_write_atn65 (info, nindx, name))
+ return false;
+ }
+
+ assert (! ieee_buffer_emptyp (&info->vars));
+ if (! ieee_change_buffer (info, &info->vars))
+ return false;
+
+ /* The address is written out as the first block. */
+
+ ++info->block_depth;
+
+ return (ieee_write_byte (info, (int) ieee_bb_record_enum)
+ && ieee_write_byte (info, global ? 4 : 6)
+ && ieee_write_number (info, 0)
+ && ieee_write_id (info, name)
+ && ieee_write_number (info, 0)
+ && ieee_write_number (info, typeindx));
+}
+
+/* Add a function parameter. This will normally be called before the
+ first block, so we postpone them until we see the block. */
+
+static boolean
+ieee_function_parameter (p, name, kind, val)
+ PTR p;
+ const char *name;
+ enum debug_parm_kind kind;
+ bfd_vma val;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+ struct ieee_pending_parm *m, **pm;
+
+ assert (info->block_depth == 1);
+
+ m = (struct ieee_pending_parm *) xmalloc (sizeof *m);
+ memset (m, 0, sizeof *m);
+
+ m->next = NULL;
+ m->name = name;
+ m->referencep = info->type_stack->type.referencep;
+ m->type = ieee_pop_type (info);
+ m->kind = kind;
+ m->val = val;
+
+ for (pm = &info->pending_parms; *pm != NULL; pm = &(*pm)->next)
+ ;
+ *pm = m;
+
+ /* Add the type to the fnargs list. */
+ if (! ieee_change_buffer (info, &info->fnargs)
+ || ! ieee_write_number (info, m->type))
+ return false;
+ ++info->fnargcount;
+
+ return true;
+}
+
+/* Output pending function parameters. */
+
+static boolean
+ieee_output_pending_parms (info)
+ struct ieee_handle *info;
+{
+ struct ieee_pending_parm *m;
+ unsigned int refcount;
+
+ refcount = 0;
+ for (m = info->pending_parms; m != NULL; m = m->next)
+ {
+ enum debug_var_kind vkind;
+
+ switch (m->kind)
+ {
+ default:
+ abort ();
+ return false;
+ case DEBUG_PARM_STACK:
+ case DEBUG_PARM_REFERENCE:
+ vkind = DEBUG_LOCAL;
+ break;
+ case DEBUG_PARM_REG:
+ case DEBUG_PARM_REF_REG:
+ vkind = DEBUG_REGISTER;
+ break;
+ }
+
+ if (! ieee_push_type (info, m->type, 0, false, false))
+ return false;
+ info->type_stack->type.referencep = m->referencep;
+ if (m->referencep)
+ ++refcount;
+ if (! ieee_variable ((PTR) info, m->name, vkind, m->val))
+ return false;
+ }
+
+ /* If there are any reference parameters, we need to output a
+ miscellaneous record indicating them. */
+ if (refcount > 0)
+ {
+ unsigned int nindx, varindx;
+
+ /* FIXME: The MRI compiler outputs the demangled function name
+ here, but we are outputting the mangled name. */
+ nindx = info->name_indx;
+ ++info->name_indx;
+ if (! ieee_change_buffer (info, &info->vars)
+ || ! ieee_write_byte (info, (int) ieee_nn_record)
+ || ! ieee_write_number (info, nindx)
+ || ! ieee_write_id (info, "")
+ || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
+ || ! ieee_write_number (info, nindx)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, 62)
+ || ! ieee_write_number (info, 80)
+ || ! ieee_write_number (info, refcount + 3)
+ || ! ieee_write_asn (info, nindx, 'B')
+ || ! ieee_write_atn65 (info, nindx, info->fnname)
+ || ! ieee_write_asn (info, nindx, 0))
+ return false;
+ for (m = info->pending_parms, varindx = 1;
+ m != NULL;
+ m = m->next, varindx++)
+ {
+ if (m->referencep)
+ {
+ if (! ieee_write_asn (info, nindx, varindx))
+ return false;
+ }
+ }
+ }
+
+ m = info->pending_parms;
+ while (m != NULL)
+ {
+ struct ieee_pending_parm *next;
+
+ next = m->next;
+ free (m);
+ m = next;
+ }
+
+ info->pending_parms = NULL;
+
+ return true;
+}
+
+/* Start a block. If this is the first block, we output the address
+ to finish the BB4 or BB6, and then output the function parameters. */
+
+static boolean
+ieee_start_block (p, addr)
+ PTR p;
+ bfd_vma addr;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ if (! ieee_change_buffer (info, &info->vars))
+ return false;
+
+ if (info->block_depth == 1)
+ {
+ if (! ieee_write_number (info, addr)
+ || ! ieee_output_pending_parms (info))
+ return false;
+ }
+ else
+ {
+ if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 6)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, "")
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, addr))
+ return false;
+ }
+
+ if (! ieee_start_range (info, addr))
+ return false;
+
+ ++info->block_depth;
+
+ return true;
+}
+
+/* End a block. */
+
+static boolean
+ieee_end_block (p, addr)
+ PTR p;
+ bfd_vma addr;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ /* The address we are given is the end of the block, but IEEE seems
+ to want to the address of the last byte in the block, so we
+ subtract one. */
+ if (! ieee_change_buffer (info, &info->vars)
+ || ! ieee_write_byte (info, (int) ieee_be_record_enum)
+ || ! ieee_write_number (info, addr - 1))
+ return false;
+
+ if (! ieee_end_range (info, addr))
+ return false;
+
+ --info->block_depth;
+
+ if (addr > info->highaddr)
+ info->highaddr = addr;
+
+ return true;
+}
+
+/* End a function. */
+
+static boolean
+ieee_end_function (p)
+ PTR p;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ assert (info->block_depth == 1);
+
+ --info->block_depth;
+
+ /* Now we can finish up fntype, and add it to the typdef section.
+ At this point, fntype is the 'x' type up to the argument count,
+ and fnargs is the argument types. We must add the argument
+ count, and we must add the level. FIXME: We don't record varargs
+ functions correctly. In fact, stabs debugging does not give us
+ enough information to do so. */
+ if (! ieee_change_buffer (info, &info->fntype)
+ || ! ieee_write_number (info, info->fnargcount)
+ || ! ieee_change_buffer (info, &info->fnargs)
+ || ! ieee_write_number (info, 0))
+ return false;
+
+ /* Make sure the typdef block has been started. */
+ if (ieee_buffer_emptyp (&info->types))
+ {
+ if (! ieee_change_buffer (info, &info->types)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 1)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, info->modname))
+ return false;
+ }
+
+ if (! ieee_append_buffer (info, &info->types, &info->fntype)
+ || ! ieee_append_buffer (info, &info->types, &info->fnargs))
+ return false;
+
+ info->fnname = NULL;
+ if (! ieee_init_buffer (info, &info->fntype)
+ || ! ieee_init_buffer (info, &info->fnargs))
+ return false;
+ info->fnargcount = 0;
+
+ return true;
+}
+
+/* Record line number information. */
+
+static boolean
+ieee_lineno (p, filename, lineno, addr)
+ PTR p;
+ const char *filename;
+ unsigned long lineno;
+ bfd_vma addr;
+{
+ struct ieee_handle *info = (struct ieee_handle *) p;
+
+ assert (info->filename != NULL);
+
+ /* The HP simulator seems to get confused when more than one line is
+ listed for the same address, at least if they are in different
+ files. We handle this by always listing the last line for a
+ given address, since that seems to be the one that gdb uses. */
+ if (info->pending_lineno_filename != NULL
+ && addr != info->pending_lineno_addr)
+ {
+ /* Make sure we have a line number block. */
+ if (! ieee_buffer_emptyp (&info->linenos))
+ {
+ if (! ieee_change_buffer (info, &info->linenos))
+ return false;
+ }
+ else
+ {
+ info->lineno_name_indx = info->name_indx;
+ ++info->name_indx;
+ if (! ieee_change_buffer (info, &info->linenos)
+ || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 5)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, info->filename)
+ || ! ieee_write_byte (info, (int) ieee_nn_record)
+ || ! ieee_write_number (info, info->lineno_name_indx)
+ || ! ieee_write_id (info, ""))
+ return false;
+ info->lineno_filename = info->filename;
+ }
+
+ if (strcmp (info->pending_lineno_filename, info->lineno_filename) != 0)
+ {
+ if (strcmp (info->filename, info->lineno_filename) != 0)
+ {
+ /* We were not in the main file. Close the block for the
+ included file. */
+ if (! ieee_write_byte (info, (int) ieee_be_record_enum))
+ return false;
+ if (strcmp (info->filename, info->pending_lineno_filename) == 0)
+ {
+ /* We need a new NN record, and we aren't about to
+ output one. */
+ info->lineno_name_indx = info->name_indx;
+ ++info->name_indx;
+ if (! ieee_write_byte (info, (int) ieee_nn_record)
+ || ! ieee_write_number (info, info->lineno_name_indx)
+ || ! ieee_write_id (info, ""))
+ return false;
+ }
+ }
+ if (strcmp (info->filename, info->pending_lineno_filename) != 0)
+ {
+ /* We are not changing to the main file. Open a block for
+ the new included file. */
+ info->lineno_name_indx = info->name_indx;
+ ++info->name_indx;
+ if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
+ || ! ieee_write_byte (info, 5)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_id (info, info->pending_lineno_filename)
+ || ! ieee_write_byte (info, (int) ieee_nn_record)
+ || ! ieee_write_number (info, info->lineno_name_indx)
+ || ! ieee_write_id (info, ""))
+ return false;
+ }
+ info->lineno_filename = info->pending_lineno_filename;
+ }
+
+ if (! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
+ || ! ieee_write_number (info, info->lineno_name_indx)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_number (info, 7)
+ || ! ieee_write_number (info, info->pending_lineno)
+ || ! ieee_write_number (info, 0)
+ || ! ieee_write_asn (info, info->lineno_name_indx,
+ info->pending_lineno_addr))
+ return false;
+ }
+
+ info->pending_lineno_filename = filename;
+ info->pending_lineno = lineno;
+ info->pending_lineno_addr = addr;
+
+ return true;
+}
diff --git a/pstack/ieee.h b/pstack/ieee.h
new file mode 100644
index 00000000000..5ade39d33e3
--- /dev/null
+++ b/pstack/ieee.h
@@ -0,0 +1,139 @@
+/* IEEE Standard 695-1980 "Universal Format for Object Modules" header file
+ Contributed by Cygnus Support. */
+
+#define N_W_VARIABLES 8
+#define Module_Beginning 0xe0
+
+typedef struct ieee_module {
+ char *processor;
+ char *module_name;
+} ieee_module_begin_type;
+
+#define Address_Descriptor 0xec
+typedef struct ieee_address {
+bfd_vma number_of_bits_mau;
+ bfd_vma number_of_maus_in_address;
+
+ unsigned char byte_order;
+#define IEEE_LITTLE 0xcc
+#define IEEE_BIG 0xcd
+} ieee_address_descriptor_type;
+
+typedef union ieee_w_variable {
+ file_ptr offset[N_W_VARIABLES];
+ struct {
+ file_ptr extension_record;
+ file_ptr environmental_record;
+ file_ptr section_part;
+ file_ptr external_part;
+ file_ptr debug_information_part;
+ file_ptr data_part;
+ file_ptr trailer_part;
+ file_ptr me_record;
+ } r;
+} ieee_w_variable_type;
+
+
+
+
+
+typedef enum ieee_record
+{
+ ieee_number_start_enum = 0x00,
+ ieee_number_end_enum=0x7f,
+ ieee_number_repeat_start_enum = 0x80,
+ ieee_number_repeat_end_enum = 0x88,
+ ieee_number_repeat_4_enum = 0x84,
+ ieee_number_repeat_3_enum = 0x83,
+ ieee_number_repeat_2_enum = 0x82,
+ ieee_number_repeat_1_enum = 0x81,
+ ieee_module_beginning_enum = 0xe0,
+ ieee_module_end_enum = 0xe1,
+ ieee_extension_length_1_enum = 0xde,
+ ieee_extension_length_2_enum = 0xdf,
+ ieee_section_type_enum = 0xe6,
+ ieee_section_alignment_enum = 0xe7,
+ ieee_external_symbol_enum = 0xe8,
+ ieee_comma = 0x90,
+ ieee_external_reference_enum = 0xe9,
+ ieee_set_current_section_enum = 0xe5,
+ ieee_address_descriptor_enum = 0xec,
+ ieee_load_constant_bytes_enum = 0xed,
+ ieee_load_with_relocation_enum = 0xe4,
+
+ ieee_variable_A_enum = 0xc1,
+ ieee_variable_B_enum = 0xc2,
+ ieee_variable_C_enum = 0xc3,
+ ieee_variable_D_enum = 0xc4,
+ ieee_variable_E_enum = 0xc5,
+ ieee_variable_F_enum = 0xc6,
+ ieee_variable_G_enum = 0xc7,
+ ieee_variable_H_enum = 0xc8,
+ ieee_variable_I_enum = 0xc9,
+ ieee_variable_J_enum = 0xca,
+ ieee_variable_K_enum = 0xcb,
+ ieee_variable_L_enum = 0xcc,
+ ieee_variable_M_enum = 0xcd,
+ ieee_variable_N_enum = 0xce,
+ ieee_variable_O_enum = 0xcf,
+ ieee_variable_P_enum = 0xd0,
+ ieee_variable_Q_enum = 0xd1,
+ ieee_variable_R_enum = 0xd2,
+ ieee_variable_S_enum = 0xd3,
+ ieee_variable_T_enum = 0xd4,
+ ieee_variable_U_enum = 0xd5,
+ ieee_variable_V_enum = 0xd6,
+ ieee_variable_W_enum = 0xd7,
+ ieee_variable_X_enum = 0xd8,
+ ieee_variable_Y_enum = 0xd9,
+ ieee_variable_Z_enum = 0xda,
+ ieee_function_plus_enum = 0xa5,
+ ieee_function_minus_enum = 0xa6,
+ ieee_function_signed_open_b_enum = 0xba,
+ ieee_function_signed_close_b_enum = 0xbb,
+
+ ieee_function_unsigned_open_b_enum = 0xbc,
+ ieee_function_unsigned_close_b_enum = 0xbd,
+
+ ieee_function_either_open_b_enum = 0xbe,
+ ieee_function_either_close_b_enum = 0xbf,
+ ieee_record_seperator_enum = 0xdb,
+
+ ieee_e2_first_byte_enum = 0xe2,
+ ieee_section_size_enum = 0xe2d3,
+ ieee_physical_region_size_enum = 0xe2c1,
+ ieee_region_base_address_enum = 0xe2c2,
+ ieee_mau_size_enum = 0xe2c6,
+ ieee_m_value_enum = 0xe2cd,
+ ieee_section_base_address_enum = 0xe2cc,
+ ieee_asn_record_enum = 0xe2ce,
+ ieee_section_offset_enum = 0xe2d2,
+ ieee_value_starting_address_enum = 0xe2c7,
+ ieee_assign_value_to_variable_enum = 0xe2d7,
+ ieee_set_current_pc_enum = 0xe2d0,
+ ieee_value_record_enum = 0xe2c9,
+ ieee_nn_record = 0xf0,
+ ieee_at_record_enum = 0xf1,
+ ieee_ty_record_enum = 0xf2,
+ ieee_attribute_record_enum = 0xf1c9,
+ ieee_atn_record_enum = 0xf1ce,
+ ieee_external_reference_info_record_enum = 0xf1d8,
+ ieee_weak_external_reference_enum= 0xf4,
+ ieee_repeat_data_enum = 0xf7,
+ ieee_bb_record_enum = 0xf8,
+ ieee_be_record_enum = 0xf9
+} ieee_record_enum_type;
+
+
+typedef struct ieee_section {
+ unsigned int section_index;
+ unsigned int section_type;
+ char *section_name;
+ unsigned int parent_section_index;
+ unsigned int sibling_section_index;
+ unsigned int context_index;
+} ieee_section_type;
+#define IEEE_REFERENCE_BASE 11
+#define IEEE_PUBLIC_BASE 32
+#define IEEE_SECTION_NUMBER_BASE 1
+
diff --git a/pstack/libiberty.h b/pstack/libiberty.h
new file mode 100644
index 00000000000..ca0043d31c6
--- /dev/null
+++ b/pstack/libiberty.h
@@ -0,0 +1,180 @@
+/* Function declarations for libiberty.
+ Written by Cygnus Support, 1994.
+
+ The libiberty library provides a number of functions which are
+ missing on some operating systems. We do not declare those here,
+ to avoid conflicts with the system header files on operating
+ systems that do support those functions. In this file we only
+ declare those functions which are specific to libiberty. */
+
+#ifndef LIBIBERTY_H
+#define LIBIBERTY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ansidecl.h"
+
+/* Build an argument vector from a string. Allocates memory using
+ malloc. Use freeargv to free the vector. */
+
+extern char **buildargv PARAMS ((char *));
+
+/* Free a vector returned by buildargv. */
+
+extern void freeargv PARAMS ((char **));
+
+/* Duplicate an argument vector. Allocates memory using malloc. Use
+ freeargv to free the vector. */
+
+extern char **dupargv PARAMS ((char **));
+
+
+/* Return the last component of a path name. Note that we can't use a
+ prototype here because the parameter is declared inconsistently
+ across different systems, sometimes as "char *" and sometimes as
+ "const char *" */
+
+#if defined (__GNU_LIBRARY__ ) || defined (__linux__) || defined (__FreeBSD__)
+extern char *basename PARAMS ((const char *));
+#else
+extern char *basename ();
+#endif
+
+/* Concatenate an arbitrary number of strings, up to (char *) NULL.
+ Allocates memory using xmalloc. */
+
+extern char *concat PARAMS ((const char *, ...));
+
+/* Check whether two file descriptors refer to the same file. */
+
+extern int fdmatch PARAMS ((int fd1, int fd2));
+
+/* Get the amount of time the process has run, in microseconds. */
+
+extern long get_run_time PARAMS ((void));
+
+/* Choose a temporary directory to use for scratch files. */
+
+extern char *choose_temp_base PARAMS ((void));
+
+/* Allocate memory filled with spaces. Allocates using malloc. */
+
+extern const char *spaces PARAMS ((int count));
+
+/* Return the maximum error number for which strerror will return a
+ string. */
+
+extern int errno_max PARAMS ((void));
+
+/* Return the name of an errno value (e.g., strerrno (EINVAL) returns
+ "EINVAL"). */
+
+extern const char *strerrno PARAMS ((int));
+
+/* Given the name of an errno value, return the value. */
+
+extern int strtoerrno PARAMS ((const char *));
+
+/* ANSI's strerror(), but more robust. */
+
+extern char *xstrerror PARAMS ((int));
+
+/* Return the maximum signal number for which strsignal will return a
+ string. */
+
+extern int signo_max PARAMS ((void));
+
+/* Return a signal message string for a signal number
+ (e.g., strsignal (SIGHUP) returns something like "Hangup"). */
+/* This is commented out as it can conflict with one in system headers.
+ We still document its existence though. */
+
+/*extern const char *strsignal PARAMS ((int));*/
+
+/* Return the name of a signal number (e.g., strsigno (SIGHUP) returns
+ "SIGHUP"). */
+
+extern const char *strsigno PARAMS ((int));
+
+/* Given the name of a signal, return its number. */
+
+extern int strtosigno PARAMS ((const char *));
+
+/* Register a function to be run by xexit. Returns 0 on success. */
+
+extern int xatexit PARAMS ((void (*fn) (void)));
+
+/* Exit, calling all the functions registered with xatexit. */
+
+#ifndef __GNUC__
+extern void xexit PARAMS ((int status));
+#else
+void xexit PARAMS ((int status)) __attribute__ ((noreturn));
+#endif
+
+/* Set the program name used by xmalloc. */
+
+extern void xmalloc_set_program_name PARAMS ((const char *));
+
+/* Allocate memory without fail. If malloc fails, this will print a
+ message to stderr (using the name set by xmalloc_set_program_name,
+ if any) and then call xexit. */
+
+#ifdef ANSI_PROTOTYPES
+/* Get a definition for size_t. */
+#include <stddef.h>
+#endif
+extern PTR xmalloc PARAMS ((size_t));
+
+/* Reallocate memory without fail. This works like xmalloc.
+
+ FIXME: We do not declare the parameter types for the same reason as
+ xmalloc. */
+
+extern PTR xrealloc PARAMS ((PTR, size_t));
+
+/* Allocate memory without fail and set it to zero. This works like
+ xmalloc. */
+
+extern PTR xcalloc PARAMS ((size_t, size_t));
+
+/* Copy a string into a memory buffer without fail. */
+
+extern char *xstrdup PARAMS ((const char *));
+
+/* hex character manipulation routines */
+
+#define _hex_array_size 256
+#define _hex_bad 99
+extern char _hex_value[_hex_array_size];
+extern void hex_init PARAMS ((void));
+#define hex_p(c) (hex_value (c) != _hex_bad)
+/* If you change this, note well: Some code relies on side effects in
+ the argument being performed exactly once. */
+#define hex_value(c) (_hex_value[(unsigned char) (c)])
+
+/* Definitions used by the pexecute routine. */
+
+#define PEXECUTE_FIRST 1
+#define PEXECUTE_LAST 2
+#define PEXECUTE_ONE (PEXECUTE_FIRST + PEXECUTE_LAST)
+#define PEXECUTE_SEARCH 4
+#define PEXECUTE_VERBOSE 8
+
+/* Execute a program. */
+
+extern int pexecute PARAMS ((const char *, char * const *, const char *,
+ const char *, char **, char **, int));
+
+/* Wait for pexecute to finish. */
+
+extern int pwait PARAMS ((int, int *, int));
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* ! defined (LIBIBERTY_H) */
diff --git a/pstack/linuxthreads.c b/pstack/linuxthreads.c
new file mode 100644
index 00000000000..8624bd21782
--- /dev/null
+++ b/pstack/linuxthreads.c
@@ -0,0 +1,90 @@
+/* $Header$ */
+
+/*
+ * LinuxThreads specific stuff.
+ */
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <limits.h> /* PTHREAD_THREADS_MAX */
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sched.h>
+
+#include "linuxthreads.h"
+
+#define AT_INT(intval) *((int32_t*)(intval))
+
+/*
+ * Internal LinuxThreads variables.
+ * Official interface exposed to GDB.
+ */
+#if 1
+extern volatile int __pthread_threads_debug;
+extern volatile char __pthread_handles;
+extern char __pthread_initial_thread;
+/*extern volatile Elf32_Sym* __pthread_manager_thread;*/
+extern const int __pthread_sizeof_handle;
+extern const int __pthread_offsetof_descr;
+extern const int __pthread_offsetof_pid;
+extern volatile int __pthread_handles_num;
+#endif /* 0 */
+
+/*
+ * Notify others.
+ */
+int
+linuxthreads_notify_others( const int signotify)
+{
+ const pid_t mypid = getpid();
+ //const pthread_t mytid = pthread_self();
+ int i;
+ int threadcount = 0;
+ int threads[PTHREAD_THREADS_MAX];
+ int pid;
+
+ TRACE_FPRINTF((stderr, "theadcount:%d\n", __pthread_handles_num));
+ if (__pthread_handles_num==2) {
+ /* no threads beside the initial thread */
+ return 0;
+ }
+ /*assert(maxthreads>=3);
+ assert(maxthreads>=__pthread_handles_num+2);*/
+
+ // take the initial thread with us
+ pid = AT_INT(&__pthread_initial_thread + __pthread_offsetof_pid);
+ if (pid!=mypid && pid!=0)
+ threads[threadcount++] = pid;
+ // don't know why, but always handles[0]==handles[1]
+ for (i=1; i<__pthread_handles_num; ++i) {
+ const int descr = AT_INT(&__pthread_handles+i*__pthread_sizeof_handle+__pthread_offsetof_descr);
+ assert(descr!=0);
+ pid = AT_INT(descr+__pthread_offsetof_pid);
+ if (pid!=mypid && pid!=0)
+ threads[threadcount++] = pid;
+ }
+ /* TRACE_FPRINTF((stderr, "Stopping threads...")); */
+ //for (i=0; i<threadcount; ++i) {
+ // /* TRACE_FPRINTF((stderr, "%d ", threads[i])); */
+ // fflush(stdout);
+ // kill(threads[i], SIGSTOP); /* Tell thread to stop */
+ //}
+ /* TRACE_FPRINTF((stderr, " done!\n")); */
+ for (i=0; i<threadcount; ++i) {
+ TRACE_FPRINTF((stderr, "--- NOTIFYING %d\n", threads[i]));
+ kill(threads[i], signotify); /* Tell to print stack trace */
+ /* TRACE_FPRINTF((stderr, "--- WAITING FOR %d\n", threads[i])); */
+ /*pause(); Wait for confirmation. */
+ }
+ for (i=0; i<threadcount; ++i)
+ sched_yield();
+ for (i=0; i<threadcount; ++i) {
+ TRACE_FPRINTF((stderr, "--- KILLING %d\n", threads[i]));
+ kill(threads[i], SIGKILL); /* Tell thread die :) */
+ }
+ return __pthread_handles_num;
+}
+
diff --git a/pstack/linuxthreads.h b/pstack/linuxthreads.h
new file mode 100644
index 00000000000..f5eb0f652d8
--- /dev/null
+++ b/pstack/linuxthreads.h
@@ -0,0 +1,28 @@
+/* $Header$ */
+
+/*
+ * LinuxThreads specific stuff.
+ */
+
+#ifndef pstack_linuxthreads_h_
+#define pstack_linuxthreads_h_
+
+#include <pthread.h>
+#include "pstacktrace.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Tell other threads to dump stacks...
+ */
+int
+linuxthreads_notify_others( const int signotify);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* pstack_linuxthreads_h_ */
+
diff --git a/pstack/pstack.c b/pstack/pstack.c
new file mode 100644
index 00000000000..1132dcd83f7
--- /dev/null
+++ b/pstack/pstack.c
@@ -0,0 +1,2746 @@
+/*
+ pstack.c -- asynchronous stack trace of a running process
+ Copyright (c) 1999 Ross Thompson
+ Author: Ross Thompson <ross@whatsis.com>
+ Critical bug fix: Tim Waugh
+*/
+
+/*
+ This file 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.
+*/
+
+/* RESTRICTIONS:
+
+ pstack currently works only on Linux, only on an x86 machine running
+ 32 bit ELF binaries (64 bit not supported). Also, for symbolic
+ information, you need to use a GNU compiler to generate your
+ program, and you can't strip symbols from the binaries. For thread
+ information to be dumped, you have to use the debug-aware version
+ of libpthread.so. (To check, run 'nm' on your libpthread.so, and
+ make sure that the symbol "__pthread_threads_debug" is defined.)
+
+ The details of pulling stuff out of ELF files and running through
+ program images is very platform specific, and I don't want to
+ try to support modes or machine types I can't test in or on.
+ If someone wants to generalize this to other architectures, I would
+ be happy to help and coordinate the activity. Please send me whatever
+ changes you make to support these machines, so that I can own the
+ central font of all truth (at least as regards this program).
+
+ Thanks
+*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+
+#include <assert.h>
+#include <fcntl.h>
+#include <link.h>
+#include <malloc.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include <limits.h> /* PTHREAD_THREADS_MAX */
+
+
+#include <bfd.h>
+
+#include "libiberty.h"
+
+#include "pstack.h" /* just one function */
+#include "budbg.h" /* binutils stuff related to debugging symbols. */
+#include "bucomm.h" /* some common stuff */
+#include "debug.h" /* and more binutils stuff... */
+#include "budbg.h"
+#include "linuxthreads.h" /* LinuxThreads specific stuff... */
+
+
+/*
+ * fprintf for file descriptors :) NOTE: we have to use fixed-size buffer :)(
+ * due to malloc's unavalaibility.
+ */
+int
+fdprintf( int fd,
+ const char* fmt,...)
+{
+ char xbuf[2048];// FIXME: enough?
+ va_list ap;
+ int r;
+ if (fd<0)
+ return -1;
+ va_start(ap, fmt);
+ r = vsnprintf(xbuf, sizeof(xbuf), fmt, ap);
+ va_end(ap);
+ return write(fd, xbuf, r);
+}
+
+int
+fdputc( char c,
+ int fd)
+{
+ if (fd<0)
+ return -1;
+ return write(fd, &c, sizeof(c));
+}
+
+int
+fdputs( const char* s,
+ int fd)
+{
+ if (fd<0)
+ return -1;
+ return write(fd, s, strlen(s));
+}
+
+/*
+ * Use this function to open log file.
+ * Flags: truncate on opening.
+ */
+static const char* path_format = "stack-trace-on-segv-%d.txt";
+static int
+open_log_file( const pthread_t tid,
+ const pid_t pid)
+{
+ char fname[PATH_MAX];
+ int r;
+ snprintf(fname, sizeof(fname), path_format, tid, pid);
+ r = open(fname, O_WRONLY|O_CREAT|O_TRUNC,
+ S_IRUSR|S_IWUSR);
+ if (r<0)
+ perror("open");
+ return r;
+}
+/*
+ * Add additional debugging information for functions.
+ */
+
+/*
+ * Lineno
+ */
+typedef struct {
+ int lineno;
+ bfd_vma addr;
+} debug_lineno_t;
+
+/*
+ * Block - a {} pair.
+ */
+typedef struct debug_block_st {
+ bfd_vma begin_addr; /* where did it start */
+ bfd_vma end_addr; /* where did it end */
+ struct debug_block_st* parent;
+ struct debug_block_st* childs;
+ int childs_count;
+} debug_block_t;
+
+/*
+ * Function parameter.
+ */
+typedef struct {
+ bfd_vma offset; /* Offset in the stack */
+ const char* name; /* And name. */
+} debug_parameter_t;
+
+/*
+ * Extra information about functions.
+ */
+typedef struct {
+ asymbol* symbol; /* mangled function name, addr */
+ debug_lineno_t* lines;
+ int lines_count;
+ int max_lines_count;
+ const char* name;
+ const char* filename;/* a file name it occured in... */
+ debug_block_t* block; /* each function has a block, or not, you know */
+ debug_parameter_t* argv; /* argument types. */
+ int argc;
+ int max_argc;
+} debug_function_t;
+
+/* This is the structure we use as a handle for these routines. */
+struct pr_handle
+{
+ /* File to print information to. */
+ FILE *f;
+ /* Current indentation level. */
+ unsigned int indent;
+ /* Type stack. */
+ struct pr_stack *stack;
+ /* Parameter number we are about to output. */
+ int parameter;
+ debug_block_t* block; /* current block */
+ debug_function_t* function; /* current function */
+ debug_function_t* functions; /* all functions */
+ int functions_size; /* current size */
+ int functions_maxsize; /* maximum size */
+};
+
+/* The type stack. */
+
+struct pr_stack
+{
+ /* Next element on the stack. */
+ struct pr_stack *next;
+ /* This element. */
+ char *type;
+ /* Current visibility of fields if this is a class. */
+ enum debug_visibility visibility;
+ /* Name of the current method we are handling. */
+ const char *method;
+};
+
+static void indent PARAMS ((struct pr_handle *));
+static boolean push_type PARAMS ((struct pr_handle *, const char *));
+static boolean prepend_type PARAMS ((struct pr_handle *, const char *));
+static boolean append_type PARAMS ((struct pr_handle *, const char *));
+static boolean substitute_type PARAMS ((struct pr_handle *, const char *));
+static boolean indent_type PARAMS ((struct pr_handle *));
+static char *pop_type PARAMS ((struct pr_handle *));
+static void print_vma PARAMS ((bfd_vma, char *, boolean, boolean));
+static boolean pr_fix_visibility
+ PARAMS ((struct pr_handle *, enum debug_visibility));
+
+static boolean pr_start_compilation_unit PARAMS ((PTR, const char *));
+static boolean pr_start_source PARAMS ((PTR, const char *));
+static boolean pr_empty_type PARAMS ((PTR));
+static boolean pr_void_type PARAMS ((PTR));
+static boolean pr_int_type PARAMS ((PTR, unsigned int, boolean));
+static boolean pr_float_type PARAMS ((PTR, unsigned int));
+static boolean pr_complex_type PARAMS ((PTR, unsigned int));
+static boolean pr_bool_type PARAMS ((PTR, unsigned int));
+static boolean pr_enum_type
+ PARAMS ((PTR, const char *, const char **, bfd_signed_vma *));
+static boolean pr_pointer_type PARAMS ((PTR));
+static boolean pr_function_type PARAMS ((PTR, int, boolean));
+static boolean pr_reference_type PARAMS ((PTR));
+static boolean pr_range_type PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma));
+static boolean pr_array_type
+ PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma, boolean));
+static boolean pr_set_type PARAMS ((PTR, boolean));
+static boolean pr_offset_type PARAMS ((PTR));
+static boolean pr_method_type PARAMS ((PTR, boolean, int, boolean));
+static boolean pr_const_type PARAMS ((PTR));
+static boolean pr_volatile_type PARAMS ((PTR));
+static boolean pr_start_struct_type
+ PARAMS ((PTR, const char *, unsigned int, boolean, unsigned int));
+static boolean pr_struct_field
+ PARAMS ((PTR, const char *, bfd_vma, bfd_vma, enum debug_visibility));
+static boolean pr_end_struct_type PARAMS ((PTR));
+static boolean pr_start_class_type
+ PARAMS ((PTR, const char *, unsigned int, boolean, unsigned int, boolean,
+ boolean));
+static boolean pr_class_static_member
+ PARAMS ((PTR, const char *, const char *, enum debug_visibility));
+static boolean pr_class_baseclass
+ PARAMS ((PTR, bfd_vma, boolean, enum debug_visibility));
+static boolean pr_class_start_method PARAMS ((PTR, const char *));
+static boolean pr_class_method_variant
+ PARAMS ((PTR, const char *, enum debug_visibility, boolean, boolean,
+ bfd_vma, boolean));
+static boolean pr_class_static_method_variant
+ PARAMS ((PTR, const char *, enum debug_visibility, boolean, boolean));
+static boolean pr_class_end_method PARAMS ((PTR));
+static boolean pr_end_class_type PARAMS ((PTR));
+static boolean pr_typedef_type PARAMS ((PTR, const char *));
+static boolean pr_tag_type
+ PARAMS ((PTR, const char *, unsigned int, enum debug_type_kind));
+static boolean pr_typdef PARAMS ((PTR, const char *));
+static boolean pr_tag PARAMS ((PTR, const char *));
+static boolean pr_int_constant PARAMS ((PTR, const char *, bfd_vma));
+static boolean pr_float_constant PARAMS ((PTR, const char *, double));
+static boolean pr_typed_constant PARAMS ((PTR, const char *, bfd_vma));
+static boolean pr_variable
+ PARAMS ((PTR, const char *, enum debug_var_kind, bfd_vma));
+static boolean pr_start_function PARAMS ((PTR, const char *, boolean));
+static boolean pr_function_parameter
+ PARAMS ((PTR, const char *, enum debug_parm_kind, bfd_vma));
+static boolean pr_start_block PARAMS ((PTR, bfd_vma));
+static boolean pr_end_block PARAMS ((PTR, bfd_vma));
+static boolean pr_end_function PARAMS ((PTR));
+static boolean pr_lineno PARAMS ((PTR, const char *, unsigned long, bfd_vma));
+
+static const struct debug_write_fns pr_fns =
+{
+ pr_start_compilation_unit,
+ pr_start_source,
+ pr_empty_type,
+ pr_void_type,
+ pr_int_type,
+ pr_float_type,
+ pr_complex_type,
+ pr_bool_type,
+ pr_enum_type,
+ pr_pointer_type,
+ pr_function_type,
+ pr_reference_type,
+ pr_range_type,
+ pr_array_type,
+ pr_set_type,
+ pr_offset_type,
+ pr_method_type,
+ pr_const_type,
+ pr_volatile_type,
+ pr_start_struct_type,
+ pr_struct_field,
+ pr_end_struct_type,
+ pr_start_class_type,
+ pr_class_static_member,
+ pr_class_baseclass,
+ pr_class_start_method,
+ pr_class_method_variant,
+ pr_class_static_method_variant,
+ pr_class_end_method,
+ pr_end_class_type,
+ pr_typedef_type,
+ pr_tag_type,
+ pr_typdef,
+ pr_tag,
+ pr_int_constant,
+ pr_float_constant,
+ pr_typed_constant,
+ pr_variable,
+ pr_start_function,
+ pr_function_parameter,
+ pr_start_block,
+ pr_end_block,
+ pr_end_function,
+ pr_lineno
+};
+
+
+/* Indent to the current indentation level. */
+
+static void
+indent (info)
+ struct pr_handle *info;
+{
+ unsigned int i;
+
+ for (i = 0; i < info->indent; i++)
+ TRACE_PUTC ((' ', info->f));
+}
+
+/* Push a type on the type stack. */
+
+static boolean
+push_type (info, type)
+ struct pr_handle *info;
+ const char *type;
+{
+ struct pr_stack *n;
+
+ if (type == NULL)
+ return false;
+
+ n = (struct pr_stack *) xmalloc (sizeof *n);
+ memset (n, 0, sizeof *n);
+
+ n->type = xstrdup (type);
+ n->visibility = DEBUG_VISIBILITY_IGNORE;
+ n->method = NULL;
+ n->next = info->stack;
+ info->stack = n;
+
+ return true;
+}
+
+/* Prepend a string onto the type on the top of the type stack. */
+
+static boolean
+prepend_type (info, s)
+ struct pr_handle *info;
+ const char *s;
+{
+ char *n;
+
+ assert (info->stack != NULL);
+
+ n = (char *) xmalloc (strlen (s) + strlen (info->stack->type) + 1);
+ sprintf (n, "%s%s", s, info->stack->type);
+ free (info->stack->type);
+ info->stack->type = n;
+
+ return true;
+}
+
+/* Append a string to the type on the top of the type stack. */
+
+static boolean
+append_type (info, s)
+ struct pr_handle *info;
+ const char *s;
+{
+ unsigned int len;
+
+ if (s == NULL)
+ return false;
+
+ assert (info->stack != NULL);
+
+ len = strlen (info->stack->type);
+ info->stack->type = (char *) xrealloc (info->stack->type,
+ len + strlen (s) + 1);
+ strcpy (info->stack->type + len, s);
+
+ return true;
+}
+
+/* We use an underscore to indicate where the name should go in a type
+ string. This function substitutes a string for the underscore. If
+ there is no underscore, the name follows the type. */
+
+static boolean
+substitute_type (info, s)
+ struct pr_handle *info;
+ const char *s;
+{
+ char *u;
+
+ assert (info->stack != NULL);
+
+ u = strchr (info->stack->type, '|');
+ if (u != NULL)
+ {
+ char *n;
+
+ n = (char *) xmalloc (strlen (info->stack->type) + strlen (s));
+
+ memcpy (n, info->stack->type, u - info->stack->type);
+ strcpy (n + (u - info->stack->type), s);
+ strcat (n, u + 1);
+
+ free (info->stack->type);
+ info->stack->type = n;
+
+ return true;
+ }
+
+ if (strchr (s, '|') != NULL
+ && (strchr (info->stack->type, '{') != NULL
+ || strchr (info->stack->type, '(') != NULL))
+ {
+ if (! prepend_type (info, "(")
+ || ! append_type (info, ")"))
+ return false;
+ }
+
+ if (*s == '\0')
+ return true;
+
+ return (append_type (info, " ")
+ && append_type (info, s));
+}
+
+/* Indent the type at the top of the stack by appending spaces. */
+
+static boolean
+indent_type (info)
+ struct pr_handle *info;
+{
+ unsigned int i;
+
+ for (i = 0; i < info->indent; i++)
+ {
+ if (! append_type (info, " "))
+ return false;
+ }
+
+ return true;
+}
+
+/* Pop a type from the type stack. */
+
+static char *
+pop_type (info)
+ struct pr_handle *info;
+{
+ struct pr_stack *o;
+ char *ret;
+
+ assert (info->stack != NULL);
+
+ o = info->stack;
+ info->stack = o->next;
+ ret = o->type;
+ free (o);
+
+ return ret;
+}
+
+/* Print a VMA value into a string. */
+
+static void
+print_vma (vma, buf, unsignedp, hexp)
+ bfd_vma vma;
+ char *buf;
+ boolean unsignedp;
+ boolean hexp;
+{
+ if (sizeof (vma) <= sizeof (unsigned long))
+ {
+ if (hexp)
+ sprintf (buf, "0x%lx", (unsigned long) vma);
+ else if (unsignedp)
+ sprintf (buf, "%lu", (unsigned long) vma);
+ else
+ sprintf (buf, "%ld", (long) vma);
+ }
+ else
+ {
+ buf[0] = '0';
+ buf[1] = 'x';
+ sprintf_vma (buf + 2, vma);
+ }
+}
+
+/* Start a new compilation unit. */
+
+static boolean
+pr_start_compilation_unit (p, filename)
+ PTR p;
+ const char *filename;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ assert (info->indent == 0);
+/*
+ TRACE_FPRINTF( (info->f, "%s:\n", filename));
+*/
+ return true;
+}
+
+/* Start a source file within a compilation unit. */
+
+static boolean
+pr_start_source (p, filename)
+ PTR p;
+ const char *filename;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ assert (info->indent == 0);
+/*
+ TRACE_FPRINTF( (info->f, " %s:\n", filename));
+*/
+ return true;
+}
+
+/* Push an empty type onto the type stack. */
+
+static boolean
+pr_empty_type (p)
+ PTR p;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ return push_type (info, "<undefined>");
+}
+
+/* Push a void type onto the type stack. */
+
+static boolean
+pr_void_type (p)
+ PTR p;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ return push_type (info, "void");
+}
+
+/* Push an integer type onto the type stack. */
+
+static boolean
+pr_int_type (p, size, unsignedp)
+ PTR p;
+ unsigned int size;
+ boolean unsignedp;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char ab[10];
+
+ sprintf (ab, "%sint%d", unsignedp ? "u" : "", size * 8);
+ return push_type (info, ab);
+}
+
+/* Push a floating type onto the type stack. */
+
+static boolean
+pr_float_type (p, size)
+ PTR p;
+ unsigned int size;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char ab[10];
+
+ if (size == 4)
+ return push_type (info, "float");
+ else if (size == 8)
+ return push_type (info, "double");
+
+ sprintf (ab, "float%d", size * 8);
+ return push_type (info, ab);
+}
+
+/* Push a complex type onto the type stack. */
+
+static boolean
+pr_complex_type (p, size)
+ PTR p;
+ unsigned int size;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ if (! pr_float_type (p, size))
+ return false;
+
+ return prepend_type (info, "complex ");
+}
+
+/* Push a boolean type onto the type stack. */
+
+static boolean
+pr_bool_type (p, size)
+ PTR p;
+ unsigned int size;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char ab[10];
+
+ sprintf (ab, "bool%d", size * 8);
+
+ return push_type (info, ab);
+}
+
+/* Push an enum type onto the type stack. */
+
+static boolean
+pr_enum_type (p, tag, names, values)
+ PTR p;
+ const char *tag;
+ const char **names;
+ bfd_signed_vma *values;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ unsigned int i;
+ bfd_signed_vma val;
+
+ if (! push_type (info, "enum "))
+ return false;
+ if (tag != NULL)
+ {
+ if (! append_type (info, tag)
+ || ! append_type (info, " "))
+ return false;
+ }
+ if (! append_type (info, "{ "))
+ return false;
+
+ if (names == NULL)
+ {
+ if (! append_type (info, "/* undefined */"))
+ return false;
+ }
+ else
+ {
+ val = 0;
+ for (i = 0; names[i] != NULL; i++)
+ {
+ if (i > 0)
+ {
+ if (! append_type (info, ", "))
+ return false;
+ }
+
+ if (! append_type (info, names[i]))
+ return false;
+
+ if (values[i] != val)
+ {
+ char ab[20];
+
+ print_vma (values[i], ab, false, false);
+ if (! append_type (info, " = ")
+ || ! append_type (info, ab))
+ return false;
+ val = values[i];
+ }
+
+ ++val;
+ }
+ }
+
+ return append_type (info, " }");
+}
+
+/* Turn the top type on the stack into a pointer. */
+
+static boolean
+pr_pointer_type (p)
+ PTR p;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *s;
+
+ assert (info->stack != NULL);
+
+ s = strchr (info->stack->type, '|');
+ if (s != NULL && s[1] == '[')
+ return substitute_type (info, "(*|)");
+ return substitute_type (info, "*|");
+}
+
+/* Turn the top type on the stack into a function returning that type. */
+
+static boolean
+pr_function_type (p, argcount, varargs)
+ PTR p;
+ int argcount;
+ boolean varargs;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char **arg_types;
+ unsigned int len;
+ char *s;
+
+ assert (info->stack != NULL);
+
+ len = 10;
+
+ if (argcount <= 0)
+ {
+ arg_types = NULL;
+ len += 15;
+ }
+ else
+ {
+ int i;
+
+ arg_types = (char **) xmalloc (argcount * sizeof *arg_types);
+ for (i = argcount - 1; i >= 0; i--)
+ {
+ if (! substitute_type (info, ""))
+ return false;
+ arg_types[i] = pop_type (info);
+ if (arg_types[i] == NULL)
+ return false;
+ len += strlen (arg_types[i]) + 2;
+ }
+ if (varargs)
+ len += 5;
+ }
+
+ /* Now the return type is on the top of the stack. */
+
+ s = (char *) xmalloc (len);
+ strcpy (s, "(|) (");
+
+ if (argcount < 0)
+ {
+#if 0
+ /* Turn off unknown arguments. */
+ strcat (s, "/* unknown */");
+#endif
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; i < argcount; i++)
+ {
+ if (i > 0)
+ strcat (s, ", ");
+ strcat (s, arg_types[i]);
+ }
+ if (varargs)
+ {
+ if (i > 0)
+ strcat (s, ", ");
+ strcat (s, "...");
+ }
+ if (argcount > 0)
+ free (arg_types);
+ }
+
+ strcat (s, ")");
+
+ if (! substitute_type (info, s))
+ return false;
+
+ free (s);
+
+ return true;
+}
+
+/* Turn the top type on the stack into a reference to that type. */
+
+static boolean
+pr_reference_type (p)
+ PTR p;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ assert (info->stack != NULL);
+
+ return substitute_type (info, "&|");
+}
+
+/* Make a range type. */
+
+static boolean
+pr_range_type (p, lower, upper)
+ PTR p;
+ bfd_signed_vma lower;
+ bfd_signed_vma upper;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char abl[20], abu[20];
+
+ assert (info->stack != NULL);
+
+ if (! substitute_type (info, ""))
+ return false;
+
+ print_vma (lower, abl, false, false);
+ print_vma (upper, abu, false, false);
+
+ return (prepend_type (info, "range (")
+ && append_type (info, "):")
+ && append_type (info, abl)
+ && append_type (info, ":")
+ && append_type (info, abu));
+}
+
+/* Make an array type. */
+
+/*ARGSUSED*/
+static boolean
+pr_array_type (p, lower, upper, stringp)
+ PTR p;
+ bfd_signed_vma lower;
+ bfd_signed_vma upper;
+ boolean stringp;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *range_type;
+ char abl[20], abu[20], ab[50];
+
+ range_type = pop_type (info);
+ if (range_type == NULL)
+ return false;
+
+ if (lower == 0)
+ {
+ if (upper == -1)
+ sprintf (ab, "|[]");
+ else
+ {
+ print_vma (upper + 1, abu, false, false);
+ sprintf (ab, "|[%s]", abu);
+ }
+ }
+ else
+ {
+ print_vma (lower, abl, false, false);
+ print_vma (upper, abu, false, false);
+ sprintf (ab, "|[%s:%s]", abl, abu);
+ }
+
+ if (! substitute_type (info, ab))
+ return false;
+
+ if (strcmp (range_type, "int") != 0)
+ {
+ if (! append_type (info, ":")
+ || ! append_type (info, range_type))
+ return false;
+ }
+
+ if (stringp)
+ {
+ if (! append_type (info, " /* string */"))
+ return false;
+ }
+
+ return true;
+}
+
+/* Make a set type. */
+
+/*ARGSUSED*/
+static boolean
+pr_set_type (p, bitstringp)
+ PTR p;
+ boolean bitstringp;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ if (! substitute_type (info, ""))
+ return false;
+
+ if (! prepend_type (info, "set { ")
+ || ! append_type (info, " }"))
+ return false;
+
+ if (bitstringp)
+ {
+ if (! append_type (info, "/* bitstring */"))
+ return false;
+ }
+
+ return true;
+}
+
+/* Make an offset type. */
+
+static boolean
+pr_offset_type (p)
+ PTR p;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+
+ if (! substitute_type (info, ""))
+ return false;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return false;
+
+ return (substitute_type (info, "")
+ && prepend_type (info, " ")
+ && prepend_type (info, t)
+ && append_type (info, "::|"));
+}
+
+/* Make a method type. */
+
+static boolean
+pr_method_type (p, domain, argcount, varargs)
+ PTR p;
+ boolean domain;
+ int argcount;
+ boolean varargs;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ unsigned int len;
+ char *domain_type;
+ char **arg_types;
+ char *s;
+
+ len = 10;
+
+ if (! domain)
+ domain_type = NULL;
+ else
+ {
+ if (! substitute_type (info, ""))
+ return false;
+ domain_type = pop_type (info);
+ if (domain_type == NULL)
+ return false;
+ if (strncmp (domain_type, "class ", sizeof "class " - 1) == 0
+ && strchr (domain_type + sizeof "class " - 1, ' ') == NULL)
+ domain_type += sizeof "class " - 1;
+ else if (strncmp (domain_type, "union class ",
+ sizeof "union class ") == 0
+ && (strchr (domain_type + sizeof "union class " - 1, ' ')
+ == NULL))
+ domain_type += sizeof "union class " - 1;
+ len += strlen (domain_type);
+ }
+
+ if (argcount <= 0)
+ {
+ arg_types = NULL;
+ len += 15;
+ }
+ else
+ {
+ int i;
+
+ arg_types = (char **) xmalloc (argcount * sizeof *arg_types);
+ for (i = argcount - 1; i >= 0; i--)
+ {
+ if (! substitute_type (info, ""))
+ return false;
+ arg_types[i] = pop_type (info);
+ if (arg_types[i] == NULL)
+ return false;
+ len += strlen (arg_types[i]) + 2;
+ }
+ if (varargs)
+ len += 5;
+ }
+
+ /* Now the return type is on the top of the stack. */
+
+ s = (char *) xmalloc (len);
+ if (! domain)
+ *s = '\0';
+ else
+ strcpy (s, domain_type);
+ strcat (s, "::| (");
+
+ if (argcount < 0)
+ strcat (s, "/* unknown */");
+ else
+ {
+ int i;
+
+ for (i = 0; i < argcount; i++)
+ {
+ if (i > 0)
+ strcat (s, ", ");
+ strcat (s, arg_types[i]);
+ }
+ if (varargs)
+ {
+ if (i > 0)
+ strcat (s, ", ");
+ strcat (s, "...");
+ }
+ if (argcount > 0)
+ free (arg_types);
+ }
+
+ strcat (s, ")");
+
+ if (! substitute_type (info, s))
+ return false;
+
+ free (s);
+
+ return true;
+}
+
+/* Make a const qualified type. */
+
+static boolean
+pr_const_type (p)
+ PTR p;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ return substitute_type (info, "const |");
+}
+
+/* Make a volatile qualified type. */
+
+static boolean
+pr_volatile_type (p)
+ PTR p;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ return substitute_type (info, "volatile |");
+}
+
+/* Start accumulating a struct type. */
+
+static boolean
+pr_start_struct_type (p, tag, id, structp, size)
+ PTR p;
+ const char *tag;
+ unsigned int id;
+ boolean structp;
+ unsigned int size;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ info->indent += 2;
+
+ if (! push_type (info, structp ? "struct " : "union "))
+ return false;
+ if (tag != NULL)
+ {
+ if (! append_type (info, tag))
+ return false;
+ }
+ else
+ {
+ char idbuf[20];
+
+ sprintf (idbuf, "%%anon%u", id);
+ if (! append_type (info, idbuf))
+ return false;
+ }
+
+ if (! append_type (info, " {"))
+ return false;
+ if (size != 0 || tag != NULL)
+ {
+ char ab[30];
+
+ if (! append_type (info, " /*"))
+ return false;
+
+ if (size != 0)
+ {
+ sprintf (ab, " size %u", size);
+ if (! append_type (info, ab))
+ return false;
+ }
+ if (tag != NULL)
+ {
+ sprintf (ab, " id %u", id);
+ if (! append_type (info, ab))
+ return false;
+ }
+ if (! append_type (info, " */"))
+ return false;
+ }
+ if (! append_type (info, "\n"))
+ return false;
+
+ info->stack->visibility = DEBUG_VISIBILITY_PUBLIC;
+
+ return indent_type (info);
+}
+
+/* Output the visibility of a field in a struct. */
+
+static boolean
+pr_fix_visibility (info, visibility)
+ struct pr_handle *info;
+ enum debug_visibility visibility;
+{
+ const char *s;
+ char *t;
+ unsigned int len;
+
+ assert (info->stack != NULL);
+
+ if (info->stack->visibility == visibility)
+ return true;
+
+ assert (info->stack->visibility != DEBUG_VISIBILITY_IGNORE);
+
+ switch (visibility)
+ {
+ case DEBUG_VISIBILITY_PUBLIC:
+ s = "public";
+ break;
+ case DEBUG_VISIBILITY_PRIVATE:
+ s = "private";
+ break;
+ case DEBUG_VISIBILITY_PROTECTED:
+ s = "protected";
+ break;
+ case DEBUG_VISIBILITY_IGNORE:
+ s = "/* ignore */";
+ break;
+ default:
+ abort ();
+ return false;
+ }
+
+ /* Trim off a trailing space in the struct string, to make the
+ output look a bit better, then stick on the visibility string. */
+
+ t = info->stack->type;
+ len = strlen (t);
+ assert (t[len - 1] == ' ');
+ t[len - 1] = '\0';
+
+ if (! append_type (info, s)
+ || ! append_type (info, ":\n")
+ || ! indent_type (info))
+ return false;
+
+ info->stack->visibility = visibility;
+
+ return true;
+}
+
+/* Add a field to a struct type. */
+
+static boolean
+pr_struct_field (p, name, bitpos, bitsize, visibility)
+ PTR p;
+ const char *name;
+ bfd_vma bitpos;
+ bfd_vma bitsize;
+ enum debug_visibility visibility;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char ab[20];
+ char *t;
+
+ if (! substitute_type (info, name))
+ return false;
+
+ if (! append_type (info, "; /* "))
+ return false;
+
+ if (bitsize != 0)
+ {
+ print_vma (bitsize, ab, true, false);
+ if (! append_type (info, "bitsize ")
+ || ! append_type (info, ab)
+ || ! append_type (info, ", "))
+ return false;
+ }
+
+ print_vma (bitpos, ab, true, false);
+ if (! append_type (info, "bitpos ")
+ || ! append_type (info, ab)
+ || ! append_type (info, " */\n")
+ || ! indent_type (info))
+ return false;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return false;
+
+ if (! pr_fix_visibility (info, visibility))
+ return false;
+
+ return append_type (info, t);
+}
+
+/* Finish a struct type. */
+
+static boolean
+pr_end_struct_type (p)
+ PTR p;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *s;
+
+ assert (info->stack != NULL);
+ assert (info->indent >= 2);
+
+ info->indent -= 2;
+
+ /* Change the trailing indentation to have a close brace. */
+ s = info->stack->type + strlen (info->stack->type) - 2;
+ assert (s[0] == ' ' && s[1] == ' ' && s[2] == '\0');
+
+ *s++ = '}';
+ *s = '\0';
+
+ return true;
+}
+
+/* Start a class type. */
+
+static boolean
+pr_start_class_type (p, tag, id, structp, size, vptr, ownvptr)
+ PTR p;
+ const char *tag;
+ unsigned int id;
+ boolean structp;
+ unsigned int size;
+ boolean vptr;
+ boolean ownvptr;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *tv = NULL;
+
+ info->indent += 2;
+
+ if (vptr && ! ownvptr)
+ {
+ tv = pop_type (info);
+ if (tv == NULL)
+ return false;
+ }
+
+ if (! push_type (info, structp ? "class " : "union class "))
+ return false;
+ if (tag != NULL)
+ {
+ if (! append_type (info, tag))
+ return false;
+ }
+ else
+ {
+ char idbuf[20];
+
+ sprintf (idbuf, "%%anon%u", id);
+ if (! append_type (info, idbuf))
+ return false;
+ }
+
+ if (! append_type (info, " {"))
+ return false;
+ if (size != 0 || vptr || ownvptr || tag != NULL)
+ {
+ if (! append_type (info, " /*"))
+ return false;
+
+ if (size != 0)
+ {
+ char ab[20];
+
+ sprintf (ab, "%u", size);
+ if (! append_type (info, " size ")
+ || ! append_type (info, ab))
+ return false;
+ }
+
+ if (vptr)
+ {
+ if (! append_type (info, " vtable "))
+ return false;
+ if (ownvptr)
+ {
+ if (! append_type (info, "self "))
+ return false;
+ }
+ else
+ {
+ if (! append_type (info, tv)
+ || ! append_type (info, " "))
+ return false;
+ }
+ }
+
+ if (tag != NULL)
+ {
+ char ab[30];
+
+ sprintf (ab, " id %u", id);
+ if (! append_type (info, ab))
+ return false;
+ }
+
+ if (! append_type (info, " */"))
+ return false;
+ }
+
+ info->stack->visibility = DEBUG_VISIBILITY_PRIVATE;
+
+ return (append_type (info, "\n")
+ && indent_type (info));
+}
+
+/* Add a static member to a class. */
+
+static boolean
+pr_class_static_member (p, name, physname, visibility)
+ PTR p;
+ const char *name;
+ const char *physname;
+ enum debug_visibility visibility;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+
+ if (! substitute_type (info, name))
+ return false;
+
+ if (! prepend_type (info, "static ")
+ || ! append_type (info, "; /* ")
+ || ! append_type (info, physname)
+ || ! append_type (info, " */\n")
+ || ! indent_type (info))
+ return false;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return false;
+
+ if (! pr_fix_visibility (info, visibility))
+ return false;
+
+ return append_type (info, t);
+}
+
+/* Add a base class to a class. */
+
+static boolean
+pr_class_baseclass (p, bitpos, virtual, visibility)
+ PTR p;
+ bfd_vma bitpos;
+ boolean virtual;
+ enum debug_visibility visibility;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+ const char *prefix;
+ char ab[20];
+ char *s, *l, *n;
+
+ assert (info->stack != NULL && info->stack->next != NULL);
+
+ if (! substitute_type (info, ""))
+ return false;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return false;
+
+ if (strncmp (t, "class ", sizeof "class " - 1) == 0)
+ t += sizeof "class " - 1;
+
+ /* Push it back on to take advantage of the prepend_type and
+ append_type routines. */
+ if (! push_type (info, t))
+ return false;
+
+ if (virtual)
+ {
+ if (! prepend_type (info, "virtual "))
+ return false;
+ }
+
+ switch (visibility)
+ {
+ case DEBUG_VISIBILITY_PUBLIC:
+ prefix = "public ";
+ break;
+ case DEBUG_VISIBILITY_PROTECTED:
+ prefix = "protected ";
+ break;
+ case DEBUG_VISIBILITY_PRIVATE:
+ prefix = "private ";
+ break;
+ default:
+ prefix = "/* unknown visibility */ ";
+ break;
+ }
+
+ if (! prepend_type (info, prefix))
+ return false;
+
+ if (bitpos != 0)
+ {
+ print_vma (bitpos, ab, true, false);
+ if (! append_type (info, " /* bitpos ")
+ || ! append_type (info, ab)
+ || ! append_type (info, " */"))
+ return false;
+ }
+
+ /* Now the top of the stack is something like "public A / * bitpos
+ 10 * /". The next element on the stack is something like "class
+ xx { / * size 8 * /\n...". We want to substitute the top of the
+ stack in before the {. */
+ s = strchr (info->stack->next->type, '{');
+ assert (s != NULL);
+ --s;
+
+ /* If there is already a ':', then we already have a baseclass, and
+ we must append this one after a comma. */
+ for (l = info->stack->next->type; l != s; l++)
+ if (*l == ':')
+ break;
+ if (! prepend_type (info, l == s ? " : " : ", "))
+ return false;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return false;
+
+ n = (char *) xmalloc (strlen (info->stack->type) + strlen (t) + 1);
+ memcpy (n, info->stack->type, s - info->stack->type);
+ strcpy (n + (s - info->stack->type), t);
+ strcat (n, s);
+
+ free (info->stack->type);
+ info->stack->type = n;
+
+ free (t);
+
+ return true;
+}
+
+/* Start adding a method to a class. */
+
+static boolean
+pr_class_start_method (p, name)
+ PTR p;
+ const char *name;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ assert (info->stack != NULL);
+ info->stack->method = name;
+ return true;
+}
+
+/* Add a variant to a method. */
+
+static boolean
+pr_class_method_variant (p, physname, visibility, constp, volatilep, voffset,
+ context)
+ PTR p;
+ const char *physname;
+ enum debug_visibility visibility;
+ boolean constp;
+ boolean volatilep;
+ bfd_vma voffset;
+ boolean context;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *method_type;
+ char *context_type;
+
+ assert (info->stack != NULL);
+ assert (info->stack->next != NULL);
+
+ /* Put the const and volatile qualifiers on the type. */
+ if (volatilep)
+ {
+ if (! append_type (info, " volatile"))
+ return false;
+ }
+ if (constp)
+ {
+ if (! append_type (info, " const"))
+ return false;
+ }
+
+ /* Stick the name of the method into its type. */
+ if (! substitute_type (info,
+ (context
+ ? info->stack->next->next->method
+ : info->stack->next->method)))
+ return false;
+
+ /* Get the type. */
+ method_type = pop_type (info);
+ if (method_type == NULL)
+ return false;
+
+ /* Pull off the context type if there is one. */
+ if (! context)
+ context_type = NULL;
+ else
+ {
+ context_type = pop_type (info);
+ if (context_type == NULL)
+ return false;
+ }
+
+ /* Now the top of the stack is the class. */
+
+ if (! pr_fix_visibility (info, visibility))
+ return false;
+
+ if (! append_type (info, method_type)
+ || ! append_type (info, " /* ")
+ || ! append_type (info, physname)
+ || ! append_type (info, " "))
+ return false;
+ if (context || voffset != 0)
+ {
+ char ab[20];
+
+ if (context)
+ {
+ if (! append_type (info, "context ")
+ || ! append_type (info, context_type)
+ || ! append_type (info, " "))
+ return false;
+ }
+ print_vma (voffset, ab, true, false);
+ if (! append_type (info, "voffset ")
+ || ! append_type (info, ab))
+ return false;
+ }
+
+ return (append_type (info, " */;\n")
+ && indent_type (info));
+}
+
+/* Add a static variant to a method. */
+
+static boolean
+pr_class_static_method_variant (p, physname, visibility, constp, volatilep)
+ PTR p;
+ const char *physname;
+ enum debug_visibility visibility;
+ boolean constp;
+ boolean volatilep;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *method_type;
+
+ assert (info->stack != NULL);
+ assert (info->stack->next != NULL);
+ assert (info->stack->next->method != NULL);
+
+ /* Put the const and volatile qualifiers on the type. */
+ if (volatilep)
+ {
+ if (! append_type (info, " volatile"))
+ return false;
+ }
+ if (constp)
+ {
+ if (! append_type (info, " const"))
+ return false;
+ }
+
+ /* Mark it as static. */
+ if (! prepend_type (info, "static "))
+ return false;
+
+ /* Stick the name of the method into its type. */
+ if (! substitute_type (info, info->stack->next->method))
+ return false;
+
+ /* Get the type. */
+ method_type = pop_type (info);
+ if (method_type == NULL)
+ return false;
+
+ /* Now the top of the stack is the class. */
+
+ if (! pr_fix_visibility (info, visibility))
+ return false;
+
+ return (append_type (info, method_type)
+ && append_type (info, " /* ")
+ && append_type (info, physname)
+ && append_type (info, " */;\n")
+ && indent_type (info));
+}
+
+/* Finish up a method. */
+
+static boolean
+pr_class_end_method (p)
+ PTR p;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ info->stack->method = NULL;
+ return true;
+}
+
+/* Finish up a class. */
+
+static boolean
+pr_end_class_type (p)
+ PTR p;
+{
+ return pr_end_struct_type (p);
+}
+
+/* Push a type on the stack using a typedef name. */
+
+static boolean
+pr_typedef_type (p, name)
+ PTR p;
+ const char *name;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ return push_type (info, name);
+}
+
+/* Push a type on the stack using a tag name. */
+
+static boolean
+pr_tag_type (p, name, id, kind)
+ PTR p;
+ const char *name;
+ unsigned int id;
+ enum debug_type_kind kind;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ const char *t, *tag;
+ char idbuf[20];
+
+ switch (kind)
+ {
+ case DEBUG_KIND_STRUCT:
+ t = "struct ";
+ break;
+ case DEBUG_KIND_UNION:
+ t = "union ";
+ break;
+ case DEBUG_KIND_ENUM:
+ t = "enum ";
+ break;
+ case DEBUG_KIND_CLASS:
+ t = "class ";
+ break;
+ case DEBUG_KIND_UNION_CLASS:
+ t = "union class ";
+ break;
+ default:
+ abort ();
+ return false;
+ }
+
+ if (! push_type (info, t))
+ return false;
+ if (name != NULL)
+ tag = name;
+ else
+ {
+ sprintf (idbuf, "%%anon%u", id);
+ tag = idbuf;
+ }
+
+ if (! append_type (info, tag))
+ return false;
+ if (name != NULL && kind != DEBUG_KIND_ENUM)
+ {
+ sprintf (idbuf, " /* id %u */", id);
+ if (! append_type (info, idbuf))
+ return false;
+ }
+
+ return true;
+}
+
+/* Output a typedef. */
+
+static boolean
+pr_typdef (p, name)
+ PTR p;
+ const char *name;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *s;
+
+ if (! substitute_type (info, name))
+ return false;
+
+ s = pop_type (info);
+ if (s == NULL)
+ return false;
+/*
+ indent (info);
+ TRACE_FPRINTF( (info->f, "typedef %s;\n", s));
+*/
+ free (s);
+
+ return true;
+}
+
+/* Output a tag. The tag should already be in the string on the
+ stack, so all we have to do here is print it out. */
+
+/*ARGSUSED*/
+static boolean
+pr_tag (p, name)
+ PTR p;
+ const char *name;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return false;
+/*
+ indent (info);
+ TRACE_FPRINTF( (info->f, "%s;\n", t));
+*/
+ free (t);
+
+ return true;
+}
+
+/* Output an integer constant. */
+
+static boolean
+pr_int_constant (p, name, val)
+ PTR p;
+ const char *name;
+ bfd_vma val;
+{
+/*
+ struct pr_handle *info = (struct pr_handle *) p;
+ char ab[20];
+ indent (info);
+ print_vma (val, ab, false, false);
+ TRACE_FPRINTF( (info->f, "const int %s = %s;\n", name, ab));
+ */
+ return true;
+}
+
+/* Output a floating point constant. */
+
+static boolean
+pr_float_constant (p, name, val)
+ PTR p;
+ const char *name;
+ double val;
+{
+/*
+ struct pr_handle *info = (struct pr_handle *) p;
+ indent (info);
+ TRACE_FPRINTF( (info->f, "const double %s = %g;\n", name, val));
+ */
+ return true;
+}
+
+/* Output a typed constant. */
+
+static boolean
+pr_typed_constant (p, name, val)
+ PTR p;
+ const char *name;
+ bfd_vma val;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return false;
+/*
+ char ab[20];
+ indent (info);
+ print_vma (val, ab, false, false);
+ TRACE_FPRINTF( (info->f, "const %s %s = %s;\n", t, name, ab));
+*/
+ free (t);
+
+ return true;
+}
+
+/* Output a variable. */
+
+static boolean
+pr_variable (p, name, kind, val)
+ PTR p;
+ const char *name;
+ enum debug_var_kind kind;
+ bfd_vma val;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+ char ab[20];
+ (void)ab;
+
+ if (! substitute_type (info, name))
+ return false;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return false;
+
+#if 0
+ indent (info);
+ switch (kind)
+ {
+ case DEBUG_STATIC:
+ case DEBUG_LOCAL_STATIC:
+ TRACE_FPRINTF( (info->f, "static "));
+ break;
+ case DEBUG_REGISTER:
+ TRACE_FPRINTF( (info->f, "register "));
+ break;
+ default:
+ break;
+ }
+ print_vma (val, ab, true, true);
+ TRACE_FPRINTF( (info->f, "%s /* %s */;\n", t, ab));
+#else /* 0 */
+#if 0
+ if (kind==DEBUG_STATIC || kind==DEBUG_LOCAL_STATIC) {
+ print_vma (val, ab, true, true);
+ TRACE_FPRINTF( (info->f, "STATIC_VAR: %s /* %s */;\n", t, ab));
+ }
+#endif /* 0 */
+#endif /* !0 */
+
+ free (t);
+
+ return true;
+}
+
+/* Start outputting a function. */
+
+static boolean
+pr_start_function (p, name, global)
+ PTR p;
+ const char *name;
+ boolean global;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+
+ if (! substitute_type (info, name))
+ return false;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return false;
+
+#if 0
+ indent (info);
+ if (! global)
+ TRACE_FPRINTF( (info->f, "static "));
+ TRACE_FPRINTF( (info->f, "%s (", t));
+ info->parameter = 1;
+#else /* 0 */
+ if (info->functions_size==info->functions_maxsize) {
+ info->functions_maxsize *= 2;
+ info->functions = xrealloc(info->functions,
+ info->functions_maxsize*sizeof(debug_function_t));
+ assert(info->functions!=0);
+ }
+ /* info->functions[info->functions_size] = xmalloc(sizeof(debug_function_t)); */
+ info->function = &info->functions[info->functions_size];
+ ++info->functions_size;
+ info->function->symbol = NULL;
+ info->function->lines = NULL;
+ info->function->lines_count = 0;
+ info->function->max_lines_count = 0;
+ info->function->name = t;
+ info->function->filename = NULL;
+ info->function->block = NULL;
+ info->function->argv = NULL;
+ info->function->argc = 0;
+ info->function->max_argc = 0;
+#endif /* !0 */
+ return true;
+}
+
+/* Output a function parameter. */
+
+static boolean
+pr_function_parameter (p, name, kind, val)
+ PTR p;
+ const char *name;
+ enum debug_parm_kind kind;
+ bfd_vma val;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ debug_function_t* f = info->function;
+ char *t;
+ char ab[20];
+ (void)ab;
+
+ if (kind == DEBUG_PARM_REFERENCE
+ || kind == DEBUG_PARM_REF_REG)
+ {
+ if (! pr_reference_type (p))
+ return false;
+ }
+
+ if (! substitute_type (info, name))
+ return false;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return false;
+
+#if 0
+ if (info->parameter != 1)
+ TRACE_FPRINTF( (info->f, ", "));
+
+ if (kind == DEBUG_PARM_REG || kind == DEBUG_PARM_REF_REG)
+ TRACE_FPRINTF( (info->f, "register "));
+
+ print_vma (val, ab, true, true);
+ TRACE_FPRINTF( (info->f, "%s /* %s */", t, ab));
+ free (t);
+ ++info->parameter;
+#else /* 0 */
+ assert(f!=NULL);
+ if (f->argv==NULL) {
+ f->max_argc = 7; /* rarely anyone has more than that many args... */
+ f->argv = xmalloc(sizeof(debug_parameter_t)*f->max_argc);
+ } else if (f->argc==f->max_argc) {
+ f->max_argc *= 2;
+ f->argv = realloc(f->argv,sizeof(debug_parameter_t)*f->max_argc);
+ }
+ f->argv[f->argc].offset = val;
+ f->argv[f->argc].name = t;
+ ++f->argc;
+#endif /* !0 */
+ return true;
+}
+
+/* Start writing out a block. */
+
+static boolean
+pr_start_block (p, addr)
+ PTR p;
+ bfd_vma addr;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char ab[20];
+ debug_block_t* block = 0;
+ (void)ab;
+#if 0
+ if (info->parameter > 0)
+ {
+ TRACE_FPRINTF( (info->f, ")\n"));
+ info->parameter = 0;
+ }
+ indent (info);
+ print_vma (addr, ab, true, true);
+ TRACE_FPRINTF( (info->f, "{ /* %s */\n", ab));
+ info->indent += 2;
+#else
+ if (info->block) {
+ if (info->block->childs_count==0)
+ info->block->childs = xmalloc(sizeof(debug_block_t));
+ else
+ info->block->childs = xrealloc(info->block->childs,
+ info->block->childs_count*sizeof(debug_block_t));
+ block = &info->block->childs[info->block->childs_count];
+ } else {
+ block = xmalloc(sizeof(debug_block_t));
+ info->function->block = block;
+ }
+ block->begin_addr = addr;
+ block->end_addr = 0;
+ block->parent = info->block;
+ block->childs = NULL;
+ block->childs_count = 0;
+ info->block = block;
+#endif
+ return true;
+}
+
+/* Write out line number information. */
+
+static boolean
+pr_lineno (p, filename, lineno, addr)
+ PTR p;
+ const char *filename;
+ unsigned long lineno;
+ bfd_vma addr;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char ab[20];
+ debug_function_t* f = info->function;
+ (void)ab;
+
+#if 0
+ indent (info);
+ print_vma (addr, ab, true, true);
+ TRACE_FPRINTF( (info->f, "/* file %s line %lu addr %s */\n", filename, lineno, ab));
+#else /* 0 */
+ if (f==NULL) /* FIXME: skips junk silently. */
+ return true;
+ /* assert(f!=NULL); */
+ if (f->filename==NULL) {
+ f->filename = filename;
+ assert(f->lines==0);
+ f->max_lines_count = 4;
+ f->lines = xmalloc(sizeof(debug_lineno_t)*f->max_lines_count);
+ }
+ if (f->lines_count==f->max_lines_count) {
+ f->max_lines_count *= 2;
+ f->lines = xrealloc(f->lines, sizeof(debug_lineno_t)*f->max_lines_count);
+ }
+ f->lines[f->lines_count].lineno = lineno;
+ f->lines[f->lines_count].addr = addr;
+ ++f->lines_count;
+#endif /* !0 */
+
+ return true;
+}
+
+/* Finish writing out a block. */
+
+static boolean
+pr_end_block (p, addr)
+ PTR p;
+ bfd_vma addr;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+#if 0
+ char ab[20];
+
+ info->indent -= 2;
+ indent (info);
+ print_vma (addr, ab, true, true);
+ TRACE_FPRINTF( (info->f, "} /* %s */\n", ab));
+#else /* 0 */
+ assert(info->block!=0);
+ info->block->end_addr = addr;
+ info->block = info->block->parent;
+#endif /* !0 */
+
+ return true;
+}
+
+/* Finish writing out a function. */
+
+/*ARGSUSED*/
+static boolean
+pr_end_function (p)
+ PTR p;
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ assert(info->block==0);
+ info->function = NULL;
+ return true;
+}
+
+/* third parameter to segv_action. */
+/* Got it after a bit of head scratching and stack dumping. */
+typedef struct {
+ u_int32_t foo1; /* +0x00 */
+ u_int32_t foo2;
+ u_int32_t foo3;
+ u_int32_t foo4; /* usually 2 */
+ u_int32_t foo5; /* +0x10 */
+ u_int32_t xgs; /* always zero */
+ u_int32_t xfs; /* always zero */
+ u_int32_t xes; /* always es=ds=ss */
+ u_int32_t xds; /* +0x20 */
+ u_int32_t edi;
+ u_int32_t esi;
+ u_int32_t ebp;
+ u_int32_t esp; /* +0x30 */
+ u_int32_t ebx;
+ u_int32_t edx;
+ u_int32_t ecx;
+ u_int32_t eax; /* +0x40 */
+ u_int32_t foo11; /* usually 0xe */
+ u_int32_t foo12; /* usually 0x6 */
+ u_int32_t eip; /* instruction pointer */
+ u_int32_t xcs; /* +0x50 */
+ u_int32_t foo21; /* usually 0x2 */
+ u_int32_t foo22; /* second stack pointer?! Probably. */
+ u_int32_t xss;
+ u_int32_t foo31; /* +0x60 */ /* usually 0x0 */
+ u_int32_t foo32; /* usually 0x2 */
+ u_int32_t fault_addr; /* Address which caused a fault */
+ u_int32_t foo41; /* usually 0x2 */
+} signal_regs_t;
+
+signal_regs_t* ptrace_regs = 0; /* Tells my_ptrace to "ptrace" current process" */
+/*
+ * my_ptrace: small wrapper around ptrace.
+ * Act as normal ptrace if ptrace_regs==0.
+ * Read data from current process if ptrace_regs!=0.
+ */
+static int
+my_ptrace( int request,
+ int pid,
+ int addr,
+ int data)
+{
+ if (ptrace_regs==0)
+ return ptrace(request, pid, addr, data);
+ /* we are tracing ourselves! */
+ switch (request) {
+ case PTRACE_ATTACH: return 0;
+ case PTRACE_CONT: return 0;
+ case PTRACE_DETACH: return 0;
+ case PTRACE_PEEKUSER:
+ switch (addr / 4) {
+ case EIP: return ptrace_regs->eip;
+ case EBP: return ptrace_regs->ebp;
+ default: assert(0);
+ }
+ case PTRACE_PEEKTEXT: /* FALLTHROUGH */
+ case PTRACE_PEEKDATA: return *(int*)(addr);
+ default: assert(0);
+ }
+ errno = 1; /* what to do here? */
+ return 1; /* failed?! */
+}
+
+#define MAXARGS 6
+
+/*
+ * To minimize the number of parameters.
+ */
+typedef struct {
+ asymbol** syms; /* Sorted! */
+ int symcount;
+ debug_function_t** functions;
+ int functions_size;
+} symbol_data_t;
+
+/*
+ * Perform a search. A binary search for a symbol.
+ */
+static void
+decode_symbol( symbol_data_t* symbol_data,
+ const unsigned long addr,
+ char* buf,
+ const int bufsize)
+{
+ asymbol** syms = symbol_data->syms;
+ const int symcount = symbol_data->symcount;
+ int bottom = 0;
+ int top = symcount - 1;
+ int i;
+ if (symcount==0) {
+ sprintf(buf, "????");
+ return;
+ }
+ while (top>bottom+1) {
+ i = (top+bottom) / 2;
+ if (bfd_asymbol_value(syms[i])==addr) {
+ sprintf(buf, "%s", syms[i]->name);
+ return;
+ } else if (bfd_asymbol_value(syms[i]) > addr)
+ top = i;
+ else
+ bottom = i;
+ }
+ i = bottom;
+ if (addr<bfd_asymbol_value(syms[i]) || addr>(syms[i]->section->vma+syms[i]->section->_cooked_size))
+ sprintf(buf, "????");
+ else
+ sprintf(buf, "%s + 0x%lx", syms[i]->name, addr-bfd_asymbol_value(syms[i]));
+}
+
+/*
+ * 1. Perform a binary search for an debug_function_t.
+ * 2. Fill buf/bufsize with name, parameters and lineno, if found
+ * Or with '????' otherwise.
+ */
+static debug_function_t*
+find_debug_function_t( symbol_data_t* symbol_data,
+ const pid_t pid,
+ const unsigned long fp, /* frame pointer */
+ const unsigned long addr,
+ char* buf, /* string buffer */
+ const int bufsize)/* FIXME: not used! */
+{
+ debug_function_t** syms = symbol_data->functions;
+ debug_function_t* f = NULL;
+ debug_block_t* block = NULL;
+ debug_lineno_t* lineno = NULL;
+ const int symcount = symbol_data->functions_size;
+ int bottom = 0;
+ int top = symcount - 1;
+ int i;
+ char* bufptr = buf;
+
+ if (symcount==0) {
+ sprintf(buf, "????");
+ return NULL;
+ }
+ while (top>bottom+1) {
+ i = (top+bottom) / 2;
+ if (syms[i]->block->begin_addr==addr) {
+ f = syms[i];
+ break;
+ } else if (syms[i]->block->begin_addr > addr)
+ top = i;
+ else
+ if (syms[i]->block->end_addr >= addr) {
+ f = syms[i];
+ break;
+ } else
+ bottom = i;
+ }
+ i = bottom;
+ if (f!=0)
+ block = f->block;
+ else {
+ block = syms[i]->block;
+ if (block->begin_addr>=addr && block->end_addr<=addr)
+ f = syms[i];
+ }
+ if (f==0)
+ sprintf(buf, "????");
+ else {
+ /*
+ * Do the backtrace the GDB way...
+ */
+ unsigned long arg;
+ /* assert(f->lines_count>0); */
+ if (f->lines_count>0) {
+ lineno = &f->lines[f->lines_count-1];
+ for (i=1; i<f->lines_count; ++i)
+ if (f->lines[i].addr>addr) {
+ lineno = &f->lines[i-1];
+ break;
+ }
+ }
+ bufptr[0] = 0;
+ bufptr += sprintf(bufptr, "%s+0x%lx (", f->name, addr-block->begin_addr);
+ for (i=0; i<f->argc; ++i) {
+ bufptr += sprintf(bufptr, "%s = ", f->argv[i].name);
+ /* FIXME: better parameter printing */
+ errno = 0;
+ arg = my_ptrace(PTRACE_PEEKDATA, pid, fp+f->argv[i].offset, 0);
+ assert(errno==0);
+ bufptr += sprintf(bufptr, "0x%x", arg);
+ if (i!=f->argc-1)
+ bufptr += sprintf(bufptr, ", ");
+ }
+ if (lineno!=0)
+ bufptr += sprintf(bufptr, ") at %s:%d", f->filename, lineno->lineno);
+ }
+ return f;
+}
+
+/*
+ * Advance through the stacks and display frames as needed.
+ */
+static int
+my_crawl( int pid,
+ symbol_data_t* symbol_data,
+ int fout)
+{
+ unsigned long pc = 0;
+ unsigned long fp = 0;
+ unsigned long nextfp;
+ unsigned long nargs;
+ unsigned long i;
+ unsigned long arg;
+ char buf[8096]; // FIXME: enough?
+ debug_function_t* f = 0;
+
+ errno = 0;
+
+ pc = my_ptrace(PTRACE_PEEKUSER, pid, EIP * 4, 0);
+ if (!errno)
+ fp = my_ptrace(PTRACE_PEEKUSER, pid, EBP * 4, 0);
+
+ if (!errno) {
+#if 1
+ f = find_debug_function_t(symbol_data, pid, fp, pc, buf, sizeof(buf));
+ fdprintf(fout,"0x%08lx: %s", pc, buf);
+ for ( ; !errno && fp; ) {
+ nextfp = my_ptrace(PTRACE_PEEKDATA, pid, fp, 0);
+ if (errno)
+ break;
+
+ if (f==0) {
+ nargs = (nextfp - fp - 8) / 4;
+ if (nargs > MAXARGS)
+ nargs = MAXARGS;
+ if (nargs > 0) {
+ fdputs(" (", fout);
+ for (i = 1; i <= nargs; i++) {
+ arg = my_ptrace(PTRACE_PEEKDATA, pid, fp + 4 * (i + 1), 0);
+ if (errno)
+ break;
+ fdprintf(fout,"%lx", arg);
+ if (i < nargs)
+ fdputs(", ", fout);
+ }
+ fdputc(')', fout);
+ nargs = nextfp - fp - 8 - (4 * nargs);
+ if (!errno && nargs > 0)
+ fdprintf(fout," + %lx\n", nargs);
+ else
+ fdputc('\n', fout);
+ } else
+ fdputc('\n', fout);
+ } else
+ fdputc('\n', fout);
+
+ if (errno || !nextfp)
+ break;
+ pc = my_ptrace(PTRACE_PEEKDATA, pid, fp + 4, 0);
+ fp = nextfp;
+ if (errno)
+ break;
+ f = find_debug_function_t(symbol_data, pid, fp, pc, buf, sizeof(buf));
+ fdprintf(fout,"0x%08lx: %s", pc, buf);
+ }
+#else /* 1 */
+ decode_symbol(symbol_data, pc, buf, sizeof(buf));
+ fdprintf(fout,"0x%08lx: %s", pc, buf);
+ for ( ; !errno && fp; ) {
+ nextfp = my_ptrace(PTRACE_PEEKDATA, pid, fp, 0);
+ if (errno)
+ break;
+
+ nargs = (nextfp - fp - 8) / 4;
+ if (nargs > MAXARGS)
+ nargs = MAXARGS;
+ if (nargs > 0) {
+ fputs(" (", fout);
+ for (i = 1; i <= nargs; i++) {
+ arg = my_ptrace(PTRACE_PEEKDATA, pid, fp + 4 * (i + 1), 0);
+ if (errno)
+ break;
+ fdprintf(fout,"%lx", arg);
+ if (i < nargs)
+ fputs(", ", fout);
+ }
+ fdputc(')', fout);
+ nargs = nextfp - fp - 8 - (4 * nargs);
+ if (!errno && nargs > 0)
+ fdprintf(fout," + %lx\n", nargs);
+ else
+ fdputc('\n', fout);
+ } else
+ fdputc('\n', fout);
+
+ if (errno || !nextfp)
+ break;
+ pc = my_ptrace(PTRACE_PEEKDATA, pid, fp + 4, 0);
+ fp = nextfp;
+ if (errno)
+ break;
+ decode_symbol(symbol_data, pc, buf, sizeof(buf));
+ fdprintf(fout,"0x%08lx: %s", pc, buf);
+ }
+#endif /* !1 */
+ }
+ if (errno)
+ perror("my_crawl");
+ return errno;
+}
+
+/* layout from /usr/src/linux/arch/i386/kernel/process.c */
+static void
+show_regs( signal_regs_t* regs,
+ int fd)
+{
+ /* long cr0 = 0L, cr2 = 0L, cr3 = 0L; */
+
+ fdprintf(fd,"\n");
+ fdprintf(fd,"FAULT ADDR: %08x\n", regs->fault_addr);
+ fdprintf(fd,"EIP: %04x:[<%08x>]",0xffff & regs->xcs,regs->eip);
+ if (regs->xcs & 3)
+ fdprintf(fd," ESP: %04x:%08x",0xffff & regs->xss,regs->esp);
+ /*fdprintf(fd," EFLAGS: %08lx\n",regs->eflags); */
+ fdprintf(fd, "\n");
+ fdprintf(fd,"EAX: %08x EBX: %08x ECX: %08x EDX: %08x\n",
+ regs->eax,regs->ebx,regs->ecx,regs->edx);
+ fdprintf(fd,"ESI: %08x EDI: %08x EBP: %08x",
+ regs->esi, regs->edi, regs->ebp);
+ fdprintf(fd," DS: %04x ES: %04x\n",
+ 0xffff & regs->xds,0xffff & regs->xes);
+ /*
+ __asm__("movl %%cr0, %0": "=r" (cr0));
+ __asm__("movl %%cr2, %0": "=r" (cr2));
+ __asm__("movl %%cr3, %0": "=r" (cr3));
+ fprintf(stderr,"CR0: %08lx CR2: %08lx CR3: %08lx\n", cr0, cr2, cr3); */
+}
+
+/*
+ * Load a BFD for an executable based on PID. Return 0 on failure.
+ */
+static bfd*
+load_bfd( const int pid)
+{
+ char filename[512];
+ bfd* abfd = 0;
+
+ /* Get the contents from procfs. */
+#if 1
+ sprintf(filename, "/proc/%d/exe", pid);
+#else
+ sprintf(filename, "crashing");
+#endif
+
+ if ((abfd = bfd_openr (filename, 0))== NULL)
+ bfd_nonfatal (filename);
+ else {
+ char** matching;
+ assert(bfd_check_format(abfd, bfd_archive)!=true);
+
+ /*
+ * There is no indication in BFD documentation that it should be done.
+ * God knows why...
+ */
+ if (!bfd_check_format_matches (abfd, bfd_object, &matching)) {
+ bfd_nonfatal (bfd_get_filename (abfd));
+ if (bfd_get_error () == bfd_error_file_ambiguously_recognized) {
+ list_matching_formats (matching);
+ free (matching);
+ }
+ }
+ }
+ return abfd;
+}
+
+/*
+ * Those are for qsort. We need only function addresses, so all the others don't count.
+ */
+/*
+ * Compare two BFD::asymbol-s.
+ */
+static int
+compare_symbols(const void* ap,
+ const void* bp)
+{
+ const asymbol *a = *(const asymbol **)ap;
+ const asymbol *b = *(const asymbol **)bp;
+ if (bfd_asymbol_value (a) > bfd_asymbol_value (b))
+ return 1;
+ else if (bfd_asymbol_value (a) < bfd_asymbol_value (b))
+ return -1;
+ return 0;
+}
+
+/*
+ * Compare two debug_asymbol_t-s.
+ */
+static int
+compare_debug_function_t(const void* ap,
+ const void* bp)
+{
+ const debug_function_t *a = *(const debug_function_t **)ap;
+ const debug_function_t *b = *(const debug_function_t **)bp;
+ assert(a->block!=0);
+ assert(b->block!=0);
+ {
+ const bfd_vma addr1 = a->block->begin_addr;
+ const bfd_vma addr2 = b->block->begin_addr;
+ if (addr1 > addr2)
+ return 1;
+ else if (addr2 > addr1)
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Filter out (in place) symbols that are useless for stack tracing.
+ * COUNT is the number of elements in SYMBOLS.
+ * Return the number of useful symbols.
+ */
+
+static long
+remove_useless_symbols( asymbol** symbols,
+ long count)
+{
+ asymbol** in_ptr = symbols;
+ asymbol** out_ptr = symbols;
+
+ while (--count >= 0) {
+ asymbol *sym = *in_ptr++;
+
+ if (sym->name == NULL || sym->name[0] == '\0' || sym->value==0)
+ continue;
+ if (sym->flags & (BSF_DEBUGGING))
+ continue;
+ if (bfd_is_und_section (sym->section) || bfd_is_com_section (sym->section))
+ continue;
+ *out_ptr++ = sym;
+ }
+ return out_ptr - symbols;
+}
+
+/*
+ * Debugging information.
+ */
+static bfd* abfd = 0;
+static PTR dhandle = 0;
+static asymbol** syms = 0;
+static long symcount = 0;
+static asymbol** sorted_syms = 0;
+static long sorted_symcount = 0;
+static debug_function_t** functions = 0;
+static int functions_size = 0;
+static int sigreport = SIGUSR1;
+static pthread_t segv_tid; /* What thread did SEGV? */
+static pid_t segv_pid;
+
+/*
+ * We'll get here after a SIGSEGV. But you can install it on other signals, too :)
+ * Because we are in the middle of the SIGSEGV, we are on our own. We can't do
+ * any malloc(), any fopen(), nothing. The last is actually a sin. We event can't
+ * fprintf(stderr,...)!!!
+ */
+static void
+segv_action(int signo, siginfo_t* siginfo, void* ptr)
+{
+ symbol_data_t symbol_data;
+ int fd = -1;
+
+ segv_pid = getpid();
+ segv_tid = pthread_self();
+ fd = open_log_file(segv_tid, segv_pid);
+ /* signal(SIGSEGV, SIG_DFL); */
+ ptrace_regs = (signal_regs_t*)ptr;
+ assert(ptrace_regs!=0);
+
+ /* Show user how guilty we are. */
+ fdprintf(fd,"--------- SEGV in PROCESS %d, THREAD %d ---------------\n", segv_pid, pthread_self());
+ show_regs(ptrace_regs, fd);
+
+ /* Some form of stack trace, too. */
+ fdprintf(fd, "STACK TRACE:\n");
+
+ symbol_data.syms = sorted_syms;
+ symbol_data.symcount = sorted_symcount;
+ symbol_data.functions = functions;
+ symbol_data.functions_size = functions_size;
+ my_crawl(segv_pid, &symbol_data, fd);
+ //fflush(stdout);
+ close(fd);
+ linuxthreads_notify_others(sigreport);
+}
+
+
+static void
+report_action(int signo, siginfo_t* siginfo, void* ptr)
+{
+ const int pid = getpid();
+ pthread_t tid = pthread_self();
+ symbol_data_t symbol_data;
+ int fd;
+ if (pthread_equal(tid, segv_tid)) {
+ /* We have already printed our stack trace... */
+ return;
+ }
+
+ fd = open_log_file(tid, pid);
+ fdprintf(fd, "REPORT: CURRENT PROCESS:%d, THREAD:%d\n", getpid(), pthread_self());
+ /* signal(SIGSEGV, SIG_DFL); */
+ ptrace_regs = (signal_regs_t*)ptr;
+ assert(ptrace_regs!=0);
+
+ /* Show user how guilty we are. */
+ fdprintf(fd,"--------- STACK TRACE FOR PROCESS %d, THREAD %d ---------------\n", pid, pthread_self());
+ show_regs(ptrace_regs, fd);
+
+ /* Some form of stack trace, too. */
+ fdprintf(fd, "STACK TRACE:\n");
+
+ symbol_data.syms = sorted_syms;
+ symbol_data.symcount = sorted_symcount;
+ symbol_data.functions = functions;
+ symbol_data.functions_size = functions_size;
+ my_crawl(pid, &symbol_data, fd);
+ //fflush(stdout);
+ close(fd);
+ /* Tell segv_thread to proceed after pause(). */
+ /*pthread_kill(segv_tid, sigreport);
+ kill(segv_pid, sigreport);
+ pthread_cancel(tid); */
+}
+
+/*
+ * Main library routine. Just call it on your program.
+ */
+int
+pstack_install_segv_action( const char* path_format_)
+{
+ const int pid = getpid();
+ struct sigaction act;
+
+ /* Store what we have to for later usage. */
+ path_format = path_format_;
+
+ /* We need a signal action for SIGSEGV and sigreport ! */
+ sigreport = SIGUSR1;
+ act.sa_handler = 0;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO|SA_ONESHOT; /* Just one SIGSEGV. */
+ act.sa_sigaction = segv_action;
+ act.sa_restorer = NULL;
+ if (sigaction(SIGSEGV, &act, NULL)!=0) {
+ perror("sigaction");
+ return 1;
+ }
+ act.sa_sigaction = report_action;
+ act.sa_flags = SA_SIGINFO; /* But many sigreports. */
+ if (sigaction(sigreport, &act, NULL)!=0) {
+ perror("sigaction");
+ return 1;
+ }
+
+ /* And a little setup for libiberty. */
+ program_name = "crashing";
+ xmalloc_set_program_name (program_name);
+
+ /* Umm, and initialize BFD, too */
+ bfd_init();
+#if 0
+ list_supported_targets(0, stdout);
+ set_default_bfd_target();
+#endif /* 0 */
+
+ if ((abfd = load_bfd(pid))==0)
+ fprintf(stderr, "BFD load failed..\n");
+ else {
+ long storage_needed = bfd_get_symtab_upper_bound (abfd);
+ long i;
+ (void)i;
+
+ if (storage_needed < 0)
+ fprintf(stderr, "Symbol table size estimation failure.\n");
+ else if (storage_needed > 0) {
+ syms = (asymbol **) xmalloc (storage_needed);
+ symcount = bfd_canonicalize_symtab (abfd, syms);
+
+ TRACE_FPRINTF((stderr, "TOTAL: %ld SYMBOLS.\n", symcount));
+ /* We need debugging info, too! */
+ if (symcount==0 || (dhandle = read_debugging_info (abfd, syms, symcount))==0)
+ fprintf(stderr, "NO DEBUGGING INFORMATION FOUND.\n");
+
+ /* We make a copy of syms to sort. We don't want to sort syms
+ because that will screw up the relocs. */
+ sorted_syms = (asymbol **) xmalloc (symcount * sizeof (asymbol *));
+ memcpy (sorted_syms, syms, symcount * sizeof (asymbol *));
+
+#if 0
+ for (i=0; i<symcount; ++i)
+ if (syms[i]->name!=0 && strlen(syms[i]->name)>0 && syms[i]->value!=0)
+ printf("%08lx T %s\n", syms[i]->section->vma + syms[i]->value, syms[i]->name);
+#endif
+ sorted_symcount = remove_useless_symbols (sorted_syms, symcount);
+ TRACE_FPRINTF((stderr, "SORTED: %ld SYMBOLS.\n", sorted_symcount));
+
+ /* Sort the symbols into section and symbol order */
+ qsort (sorted_syms, sorted_symcount, sizeof (asymbol *), compare_symbols);
+#if 0
+ for (i=0; i<sorted_symcount; ++i)
+ if (sorted_syms[i]->name!=0 && strlen(sorted_syms[i]->name)>0 && sorted_syms[i]->value!=0)
+ printf("%08lx T %s\n", sorted_syms[i]->section->vma + sorted_syms[i]->value, sorted_syms[i]->name);
+#endif
+ /* We have symbols, we need debugging info somehow sorted out. */
+ if (dhandle==0) {
+ fprintf(stderr, "STACK TRACE WILL BE UNCOMFORTABLE.\n");
+ } else {
+ /* Start collecting the debugging information.... */
+ struct pr_handle info;
+
+ info.f = stdout;
+ info.indent = 0;
+ info.stack = NULL;
+ info.parameter = 0;
+ info.block = NULL;
+ info.function = NULL;
+ info.functions_size = 0;
+ info.functions_maxsize = 1000;
+ info.functions = (debug_function_t*)xmalloc(sizeof(debug_function_t)*info.functions_maxsize);
+ debug_write (dhandle, &pr_fns, (PTR) &info);
+ TRACE_FPRINTF((stdout, "\n%d DEBUG SYMBOLS\n", info.functions_size));
+ assert(info.functions_size!=0);
+ functions = xmalloc(sizeof(debug_function_t*)*info.functions_size);
+ functions_size = info.functions_size;
+ for (i=0; i<functions_size; ++i)
+ functions[i] = &info.functions[i];
+ /* Sort the symbols into section and symbol order */
+ qsort (functions, functions_size, sizeof(debug_function_t*),
+ compare_debug_function_t);
+#if 0
+ for (i=0; i<info.functions_size; ++i)
+ fprintf(stdout, "%08lx T %s\n", info.functions[i].block->begin_addr, info.functions[i].name);
+#endif
+ fflush(stdout);
+ }
+ } else /* storage_needed == 0 */
+ fprintf(stderr, "NO SYMBOLS FOUND.\n");
+ }
+ return 0;
+}
+
+/*********************************************************************/
+/*********************************************************************/
+/*********************************************************************/
+
diff --git a/pstack/pstack.h b/pstack/pstack.h
new file mode 100644
index 00000000000..4c4fad7e754
--- /dev/null
+++ b/pstack/pstack.h
@@ -0,0 +1,22 @@
+/* $Header$ */
+
+#ifndef pstack_pstack_h_
+#define pstack_pstack_h_
+
+#include "pstacktrace.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Install the stack-trace-on-SEGV handler....
+ */
+extern int
+pstack_install_segv_action( const char* path_format);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* pstack_pstack_h_ */
+
diff --git a/pstack/pstacktrace.h b/pstack/pstacktrace.h
new file mode 100644
index 00000000000..c884bcb9f87
--- /dev/null
+++ b/pstack/pstacktrace.h
@@ -0,0 +1,24 @@
+/* $Header$ */
+
+/*
+ * Debugging macros.
+ */
+
+#ifndef pstacktrace_h_
+#define pstacktrace_h_
+
+#define PSTACK_DEBUG 1
+#undef PSTACK_DEBUG
+
+#ifdef PSTACK_DEBUG
+# define TRACE_PUTC(a) putc a
+# define TRACE_FPUTS(a) fputs a
+# define TRACE_FPRINTF(a) fprintf a
+#else /* PSTACK_DEBUG */
+# define TRACE_PUTC(a) (void)0
+# define TRACE_FPUTS(a) (void)0
+# define TRACE_FPRINTF(a) (void)0
+#endif /* !PSTACK_DEBUG */
+
+#endif /* pstacktrace_h_ */
+
diff --git a/pstack/rddbg.c b/pstack/rddbg.c
new file mode 100644
index 00000000000..be3dfc21c57
--- /dev/null
+++ b/pstack/rddbg.c
@@ -0,0 +1,462 @@
+/* rddbg.c -- Read debugging information into a generic form.
+ Copyright (C) 1995, 96, 1997 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@cygnus.com>.
+
+ This file is part of GNU Binutils.
+
+ 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. */
+
+/* This file reads debugging information into a generic form. This
+ file knows how to dig the debugging information out of an object
+ file. */
+
+#include <bfd.h>
+#include "bucomm.h"
+#include <libiberty.h>
+#include "debug.h"
+#include "budbg.h"
+
+static boolean read_section_stabs_debugging_info
+ PARAMS ((bfd *, asymbol **, long, PTR, boolean *));
+static boolean read_symbol_stabs_debugging_info
+ PARAMS ((bfd *, asymbol **, long, PTR, boolean *));
+static boolean read_ieee_debugging_info PARAMS ((bfd *, PTR, boolean *));
+static void save_stab PARAMS ((int, int, bfd_vma, const char *));
+static void stab_context PARAMS ((void));
+static void free_saved_stabs PARAMS ((void));
+
+/* Read debugging information from a BFD. Returns a generic debugging
+ pointer. */
+
+PTR
+read_debugging_info (abfd, syms, symcount)
+ bfd *abfd;
+ asymbol **syms;
+ long symcount;
+{
+ PTR dhandle;
+ boolean found;
+
+ dhandle = debug_init ();
+ if (dhandle == NULL)
+ return NULL;
+
+ if (! read_section_stabs_debugging_info (abfd, syms, symcount, dhandle,
+ &found))
+ return NULL;
+
+ if (bfd_get_flavour (abfd) == bfd_target_aout_flavour)
+ {
+ if (! read_symbol_stabs_debugging_info (abfd, syms, symcount, dhandle,
+ &found))
+ return NULL;
+ }
+
+ if (bfd_get_flavour (abfd) == bfd_target_ieee_flavour)
+ {
+ if (! read_ieee_debugging_info (abfd, dhandle, &found))
+ return NULL;
+ }
+
+ /* Try reading the COFF symbols if we didn't find any stabs in COFF
+ sections. */
+ if (! found
+ && bfd_get_flavour (abfd) == bfd_target_coff_flavour
+ && symcount > 0)
+ {
+#if 0
+/*
+ * JZ: Do we need coff?
+ */
+ if (! parse_coff (abfd, syms, symcount, dhandle))
+#else
+ fprintf (stderr, "%s: COFF support temporarily disabled\n",
+ bfd_get_filename (abfd));
+ return NULL;
+#endif
+ return NULL;
+ found = true;
+ }
+
+ if (! found)
+ {
+ fprintf (stderr, "%s: no recognized debugging information\n",
+ bfd_get_filename (abfd));
+ return NULL;
+ }
+
+ return dhandle;
+}
+
+/* Read stabs in sections debugging information from a BFD. */
+
+static boolean
+read_section_stabs_debugging_info (abfd, syms, symcount, dhandle, pfound)
+ bfd *abfd;
+ asymbol **syms;
+ long symcount;
+ PTR dhandle;
+ boolean *pfound;
+{
+ static struct
+ {
+ const char *secname;
+ const char *strsecname;
+ } names[] = { { ".stab", ".stabstr" } };
+ unsigned int i;
+ PTR shandle;
+
+ *pfound = false;
+ shandle = NULL;
+
+ for (i = 0; i < sizeof names / sizeof names[0]; i++)
+ {
+ asection *sec, *strsec;
+
+ sec = bfd_get_section_by_name (abfd, names[i].secname);
+ strsec = bfd_get_section_by_name (abfd, names[i].strsecname);
+ if (sec != NULL && strsec != NULL)
+ {
+ bfd_size_type stabsize, strsize;
+ bfd_byte *stabs, *strings;
+ bfd_byte *stab;
+ bfd_size_type stroff, next_stroff;
+
+ stabsize = bfd_section_size (abfd, sec);
+ stabs = (bfd_byte *) xmalloc (stabsize);
+ if (! bfd_get_section_contents (abfd, sec, stabs, 0, stabsize))
+ {
+ fprintf (stderr, "%s: %s: %s\n",
+ bfd_get_filename (abfd), names[i].secname,
+ bfd_errmsg (bfd_get_error ()));
+ return false;
+ }
+
+ strsize = bfd_section_size (abfd, strsec);
+ strings = (bfd_byte *) xmalloc (strsize);
+ if (! bfd_get_section_contents (abfd, strsec, strings, 0, strsize))
+ {
+ fprintf (stderr, "%s: %s: %s\n",
+ bfd_get_filename (abfd), names[i].strsecname,
+ bfd_errmsg (bfd_get_error ()));
+ return false;
+ }
+
+ if (shandle == NULL)
+ {
+ shandle = start_stab (dhandle, abfd, true, syms, symcount);
+ if (shandle == NULL)
+ return false;
+ }
+
+ *pfound = true;
+
+ stroff = 0;
+ next_stroff = 0;
+ for (stab = stabs; stab < stabs + stabsize; stab += 12)
+ {
+ bfd_size_type strx;
+ int type;
+ int other;
+ int desc;
+ bfd_vma value;
+
+ /* This code presumes 32 bit values. */
+
+ strx = bfd_get_32 (abfd, stab);
+ type = bfd_get_8 (abfd, stab + 4);
+ other = bfd_get_8 (abfd, stab + 5);
+ desc = bfd_get_16 (abfd, stab + 6);
+ value = bfd_get_32 (abfd, stab + 8);
+
+ if (type == 0)
+ {
+ /* Special type 0 stabs indicate the offset to the
+ next string table. */
+ stroff = next_stroff;
+ next_stroff += value;
+ }
+ else
+ {
+ char *f, *s;
+
+ f = NULL;
+ s = (char *) strings + stroff + strx;
+ while (s[strlen (s) - 1] == '\\'
+ && stab + 12 < stabs + stabsize)
+ {
+ char *p;
+
+ stab += 12;
+ p = s + strlen (s) - 1;
+ *p = '\0';
+ s = concat (s,
+ ((char *) strings
+ + stroff
+ + bfd_get_32 (abfd, stab)),
+ (const char *) NULL);
+
+ /* We have to restore the backslash, because, if
+ the linker is hashing stabs strings, we may
+ see the same string more than once. */
+ *p = '\\';
+
+ if (f != NULL)
+ free (f);
+ f = s;
+ }
+
+ save_stab (type, desc, value, s);
+
+ if (! parse_stab (dhandle, shandle, type, desc, value, s))
+ {
+#if 0
+/*
+ * JZ: skip the junk.
+ */
+ stab_context ();
+ free_saved_stabs ();
+ return false;
+#endif
+ }
+
+ /* Don't free f, since I think the stabs code
+ expects strings to hang around. This should be
+ straightened out. FIXME. */
+ }
+ }
+
+ free_saved_stabs ();
+ free (stabs);
+
+ /* Don't free strings, since I think the stabs code expects
+ the strings to hang around. This should be straightened
+ out. FIXME. */
+ }
+ }
+
+ if (shandle != NULL)
+ {
+ if (! finish_stab (dhandle, shandle))
+ return false;
+ }
+
+ return true;
+}
+
+/* Read stabs in the symbol table. */
+
+static boolean
+read_symbol_stabs_debugging_info (abfd, syms, symcount, dhandle, pfound)
+ bfd *abfd;
+ asymbol **syms;
+ long symcount;
+ PTR dhandle;
+ boolean *pfound;
+{
+ PTR shandle;
+ asymbol **ps, **symend;
+
+ shandle = NULL;
+ symend = syms + symcount;
+ for (ps = syms; ps < symend; ps++)
+ {
+ symbol_info i;
+
+ bfd_get_symbol_info (abfd, *ps, &i);
+
+ if (i.type == '-')
+ {
+ const char *s;
+ char *f;
+
+ if (shandle == NULL)
+ {
+ shandle = start_stab (dhandle, abfd, false, syms, symcount);
+ if (shandle == NULL)
+ return false;
+ }
+
+ *pfound = true;
+
+ s = i.name;
+ f = NULL;
+ while (s[strlen (s) - 1] == '\\'
+ && ps + 1 < symend)
+ {
+ char *sc, *n;
+
+ ++ps;
+ sc = xstrdup (s);
+ sc[strlen (sc) - 1] = '\0';
+ n = concat (sc, bfd_asymbol_name (*ps), (const char *) NULL);
+ free (sc);
+ if (f != NULL)
+ free (f);
+ f = n;
+ s = n;
+ }
+
+ save_stab (i.stab_type, i.stab_desc, i.value, s);
+
+ if (! parse_stab (dhandle, shandle, i.stab_type, i.stab_desc,
+ i.value, s))
+ {
+ stab_context ();
+ free_saved_stabs ();
+ return false;
+ }
+
+ /* Don't free f, since I think the stabs code expects
+ strings to hang around. This should be straightened out.
+ FIXME. */
+ }
+ }
+
+ free_saved_stabs ();
+
+ if (shandle != NULL)
+ {
+ if (! finish_stab (dhandle, shandle))
+ return false;
+ }
+
+ return true;
+}
+
+/* Read IEEE debugging information. */
+
+static boolean
+read_ieee_debugging_info (abfd, dhandle, pfound)
+ bfd *abfd;
+ PTR dhandle;
+ boolean *pfound;
+{
+ asection *dsec;
+ bfd_size_type size;
+ bfd_byte *contents;
+
+ /* The BFD backend puts the debugging information into a section
+ named .debug. */
+
+ dsec = bfd_get_section_by_name (abfd, ".debug");
+ if (dsec == NULL)
+ return true;
+
+ size = bfd_section_size (abfd, dsec);
+ contents = (bfd_byte *) xmalloc (size);
+ if (! bfd_get_section_contents (abfd, dsec, contents, 0, size))
+ return false;
+
+ if (! parse_ieee (dhandle, abfd, contents, size))
+ return false;
+
+ free (contents);
+
+ *pfound = true;
+
+ return true;
+}
+
+/* Record stabs strings, so that we can give some context for errors. */
+
+#define SAVE_STABS_COUNT (16)
+
+struct saved_stab
+{
+ int type;
+ int desc;
+ bfd_vma value;
+ char *string;
+};
+
+static struct saved_stab saved_stabs[SAVE_STABS_COUNT];
+static int saved_stabs_index;
+
+/* Save a stabs string. */
+
+static void
+save_stab (type, desc, value, string)
+ int type;
+ int desc;
+ bfd_vma value;
+ const char *string;
+{
+ if (saved_stabs[saved_stabs_index].string != NULL)
+ free (saved_stabs[saved_stabs_index].string);
+ saved_stabs[saved_stabs_index].type = type;
+ saved_stabs[saved_stabs_index].desc = desc;
+ saved_stabs[saved_stabs_index].value = value;
+ saved_stabs[saved_stabs_index].string = xstrdup (string);
+ saved_stabs_index = (saved_stabs_index + 1) % SAVE_STABS_COUNT;
+}
+
+/* Provide context for an error. */
+
+static void
+stab_context ()
+{
+ int i;
+
+ fprintf (stderr, "Last stabs entries before error:\n");
+ fprintf (stderr, "n_type n_desc n_value string\n");
+
+ i = saved_stabs_index;
+ do
+ {
+ struct saved_stab *stabp;
+
+ stabp = saved_stabs + i;
+ if (stabp->string != NULL)
+ {
+ const char *s;
+
+ s = bfd_get_stab_name (stabp->type);
+ if (s != NULL)
+ fprintf (stderr, "%-6s", s);
+ else if (stabp->type == 0)
+ fprintf (stderr, "HdrSym");
+ else
+ fprintf (stderr, "%-6d", stabp->type);
+ fprintf (stderr, " %-6d ", stabp->desc);
+ fprintf_vma (stderr, stabp->value);
+ if (stabp->type != 0)
+ fprintf (stderr, " %s", stabp->string);
+ fprintf (stderr, "\n");
+ }
+ i = (i + 1) % SAVE_STABS_COUNT;
+ }
+ while (i != saved_stabs_index);
+}
+
+/* Free the saved stab strings. */
+
+static void
+free_saved_stabs ()
+{
+ int i;
+
+ for (i = 0; i < SAVE_STABS_COUNT; i++)
+ {
+ if (saved_stabs[i].string != NULL)
+ {
+ free (saved_stabs[i].string);
+ saved_stabs[i].string = NULL;
+ }
+ }
+
+ saved_stabs_index = 0;
+}
diff --git a/pstack/stabs.c b/pstack/stabs.c
new file mode 100644
index 00000000000..076231d19cb
--- /dev/null
+++ b/pstack/stabs.c
@@ -0,0 +1,5082 @@
+/* stabs.c -- Parse stabs debugging information
+ Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@cygnus.com>.
+
+ This file is part of GNU Binutils.
+
+ 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. */
+
+/* This file contains code which parses stabs debugging information.
+ The organization of this code is based on the gdb stabs reading
+ code. The job it does is somewhat different, because it is not
+ trying to identify the correct address for anything. */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include <bfd.h>
+#include "bucomm.h"
+#include <libiberty.h>
+#include "demangle.h"
+#include "debug.h"
+#include "budbg.h"
+
+/* Meaningless definition needs by aout64.h. FIXME. */
+#define BYTES_IN_WORD 4
+
+#include "aout/aout64.h"
+#include "aout/stab_gnu.h"
+
+/* The number of predefined XCOFF types. */
+
+#define XCOFF_TYPE_COUNT 34
+
+/* This structure is used as a handle so that the stab parsing doesn't
+ need to use any static variables. */
+
+struct stab_handle
+{
+ /* The BFD. */
+ bfd *abfd;
+ /* True if this is stabs in sections. */
+ boolean sections;
+ /* The symbol table. */
+ asymbol **syms;
+ /* The number of symbols. */
+ long symcount;
+ /* The accumulated file name string. */
+ char *so_string;
+ /* The value of the last N_SO symbol. */
+ bfd_vma so_value;
+ /* The value of the start of the file, so that we can handle file
+ relative N_LBRAC and N_RBRAC symbols. */
+ bfd_vma file_start_offset;
+ /* The offset of the start of the function, so that we can handle
+ function relative N_LBRAC and N_RBRAC symbols. */
+ bfd_vma function_start_offset;
+ /* The version number of gcc which compiled the current compilation
+ unit, 0 if not compiled by gcc. */
+ int gcc_compiled;
+ /* Whether an N_OPT symbol was seen that was not generated by gcc,
+ so that we can detect the SunPRO compiler. */
+ boolean n_opt_found;
+ /* The main file name. */
+ char *main_filename;
+ /* A stack of unfinished N_BINCL files. */
+ struct bincl_file *bincl_stack;
+ /* A list of finished N_BINCL files. */
+ struct bincl_file *bincl_list;
+ /* Whether we are inside a function or not. */
+ boolean within_function;
+ /* The address of the end of the function, used if we have seen an
+ N_FUN symbol while in a function. This is -1 if we have not seen
+ an N_FUN (the normal case). */
+ bfd_vma function_end;
+ /* The depth of block nesting. */
+ int block_depth;
+ /* List of pending variable definitions. */
+ struct stab_pending_var *pending;
+ /* Number of files for which we have types. */
+ unsigned int files;
+ /* Lists of types per file. */
+ struct stab_types **file_types;
+ /* Predefined XCOFF types. */
+ debug_type xcoff_types[XCOFF_TYPE_COUNT];
+ /* Undefined tags. */
+ struct stab_tag *tags;
+};
+
+/* A list of these structures is used to hold pending variable
+ definitions seen before the N_LBRAC of a block. */
+
+struct stab_pending_var
+{
+ /* Next pending variable definition. */
+ struct stab_pending_var *next;
+ /* Name. */
+ const char *name;
+ /* Type. */
+ debug_type type;
+ /* Kind. */
+ enum debug_var_kind kind;
+ /* Value. */
+ bfd_vma val;
+};
+
+/* A list of these structures is used to hold the types for a single
+ file. */
+
+struct stab_types
+{
+ /* Next set of slots for this file. */
+ struct stab_types *next;
+ /* Types indexed by type number. */
+#define STAB_TYPES_SLOTS (16)
+ debug_type types[STAB_TYPES_SLOTS];
+};
+
+/* We keep a list of undefined tags that we encounter, so that we can
+ fill them in if the tag is later defined. */
+
+struct stab_tag
+{
+ /* Next undefined tag. */
+ struct stab_tag *next;
+ /* Tag name. */
+ const char *name;
+ /* Type kind. */
+ enum debug_type_kind kind;
+ /* Slot to hold real type when we discover it. If we don't, we fill
+ in an undefined tag type. */
+ debug_type slot;
+ /* Indirect type we have created to point at slot. */
+ debug_type type;
+};
+
+static char *savestring PARAMS ((const char *, int));
+static bfd_vma parse_number PARAMS ((const char **, boolean *));
+static void bad_stab PARAMS ((const char *));
+static void warn_stab PARAMS ((const char *, const char *));
+static boolean parse_stab_string
+ PARAMS ((PTR, struct stab_handle *, int, int, bfd_vma, const char *));
+static debug_type parse_stab_type
+ PARAMS ((PTR, struct stab_handle *, const char *, const char **,
+ debug_type **));
+static boolean parse_stab_type_number
+ PARAMS ((const char **, int *));
+static debug_type parse_stab_range_type
+ PARAMS ((PTR, struct stab_handle *, const char *, const char **,
+ const int *));
+static debug_type parse_stab_sun_builtin_type PARAMS ((PTR, const char **));
+static debug_type parse_stab_sun_floating_type
+ PARAMS ((PTR, const char **));
+static debug_type parse_stab_enum_type PARAMS ((PTR, const char **));
+static debug_type parse_stab_struct_type
+ PARAMS ((PTR, struct stab_handle *, const char *, const char **, boolean,
+ const int *));
+static boolean parse_stab_baseclasses
+ PARAMS ((PTR, struct stab_handle *, const char **, debug_baseclass **));
+static boolean parse_stab_struct_fields
+ PARAMS ((PTR, struct stab_handle *, const char **, debug_field **,
+ boolean *));
+static boolean parse_stab_cpp_abbrev
+ PARAMS ((PTR, struct stab_handle *, const char **, debug_field *));
+static boolean parse_stab_one_struct_field
+ PARAMS ((PTR, struct stab_handle *, const char **, const char *,
+ debug_field *, boolean *));
+static boolean parse_stab_members
+ PARAMS ((PTR, struct stab_handle *, const char *, const char **,
+ const int *, debug_method **));
+static debug_type parse_stab_argtypes
+ PARAMS ((PTR, struct stab_handle *, debug_type, const char *, const char *,
+ debug_type, const char *, boolean, boolean, const char **));
+static boolean parse_stab_tilde_field
+ PARAMS ((PTR, struct stab_handle *, const char **, const int *,
+ debug_type *, boolean *));
+static debug_type parse_stab_array_type
+ PARAMS ((PTR, struct stab_handle *, const char **, boolean));
+static void push_bincl PARAMS ((struct stab_handle *, const char *, bfd_vma));
+static const char *pop_bincl PARAMS ((struct stab_handle *));
+static boolean find_excl
+ PARAMS ((struct stab_handle *, const char *, bfd_vma));
+static boolean stab_record_variable
+ PARAMS ((PTR, struct stab_handle *, const char *, debug_type,
+ enum debug_var_kind, bfd_vma));
+static boolean stab_emit_pending_vars PARAMS ((PTR, struct stab_handle *));
+static debug_type *stab_find_slot
+ PARAMS ((struct stab_handle *, const int *));
+static debug_type stab_find_type
+ PARAMS ((PTR, struct stab_handle *, const int *));
+static boolean stab_record_type
+ PARAMS ((PTR, struct stab_handle *, const int *, debug_type));
+static debug_type stab_xcoff_builtin_type
+ PARAMS ((PTR, struct stab_handle *, int));
+static debug_type stab_find_tagged_type
+ PARAMS ((PTR, struct stab_handle *, const char *, int,
+ enum debug_type_kind));
+static debug_type *stab_demangle_argtypes
+ PARAMS ((PTR, struct stab_handle *, const char *, boolean *));
+
+/* Save a string in memory. */
+
+static char *
+savestring (start, len)
+ const char *start;
+ int len;
+{
+ char *ret;
+
+ ret = (char *) xmalloc (len + 1);
+ memcpy (ret, start, len);
+ ret[len] = '\0';
+ return ret;
+}
+
+/* Read a number from a string. */
+
+static bfd_vma
+parse_number (pp, poverflow)
+ const char **pp;
+ boolean *poverflow;
+{
+ unsigned long ul;
+ const char *orig;
+
+ if (poverflow != NULL)
+ *poverflow = false;
+
+ orig = *pp;
+
+ errno = 0;
+ ul = strtoul (*pp, (char **) pp, 0);
+ if (ul + 1 != 0 || errno == 0)
+ return (bfd_vma) ul;
+
+ /* Note that even though strtoul overflowed, it should have set *pp
+ to the end of the number, which is where we want it. */
+
+ if (sizeof (bfd_vma) > sizeof (unsigned long))
+ {
+ const char *p;
+ boolean neg;
+ int base;
+ bfd_vma over, lastdig;
+ boolean overflow;
+ bfd_vma v;
+
+ /* Our own version of strtoul, for a bfd_vma. */
+
+ p = orig;
+
+ neg = false;
+ if (*p == '+')
+ ++p;
+ else if (*p == '-')
+ {
+ neg = true;
+ ++p;
+ }
+
+ base = 10;
+ if (*p == '0')
+ {
+ if (p[1] == 'x' || p[1] == 'X')
+ {
+ base = 16;
+ p += 2;
+ }
+ else
+ {
+ base = 8;
+ ++p;
+ }
+ }
+
+ over = ((bfd_vma) (bfd_signed_vma) -1) / (bfd_vma) base;
+ lastdig = ((bfd_vma) (bfd_signed_vma) -1) % (bfd_vma) base;
+
+ overflow = false;
+ v = 0;
+ while (1)
+ {
+ int d;
+
+ d = *p++;
+ if (isdigit ((unsigned char) d))
+ d -= '0';
+ else if (isupper ((unsigned char) d))
+ d -= 'A';
+ else if (islower ((unsigned char) d))
+ d -= 'a';
+ else
+ break;
+
+ if (d >= base)
+ break;
+
+ if (v > over || (v == over && (bfd_vma) d > lastdig))
+ {
+ overflow = true;
+ break;
+ }
+ }
+
+ if (! overflow)
+ {
+ if (neg)
+ v = - v;
+ return v;
+ }
+ }
+
+ /* If we get here, the number is too large to represent in a
+ bfd_vma. */
+
+ if (poverflow != NULL)
+ *poverflow = true;
+ else
+ warn_stab (orig, "numeric overflow");
+
+ return 0;
+}
+
+/* Give an error for a bad stab string. */
+
+static void
+bad_stab (p)
+ const char *p;
+{
+ fprintf (stderr, "Bad stab: %s\n", p);
+}
+
+/* Warn about something in a stab string. */
+
+static void
+warn_stab (p, err)
+ const char *p;
+ const char *err;
+{
+ fprintf (stderr, "Warning: %s: %s\n", err, p);
+}
+
+/* Create a handle to parse stabs symbols with. */
+
+/*ARGSUSED*/
+PTR
+start_stab (dhandle, abfd, sections, syms, symcount)
+ PTR dhandle;
+ bfd *abfd;
+ boolean sections;
+ asymbol **syms;
+ long symcount;
+{
+ struct stab_handle *ret;
+
+ ret = (struct stab_handle *) xmalloc (sizeof *ret);
+ memset (ret, 0, sizeof *ret);
+ ret->abfd = abfd;
+ ret->sections = sections;
+ ret->syms = syms;
+ ret->symcount = symcount;
+ ret->files = 1;
+ ret->file_types = (struct stab_types **) xmalloc (sizeof *ret->file_types);
+ ret->file_types[0] = NULL;
+ ret->function_end = (bfd_vma) -1;
+ return (PTR) ret;
+}
+
+/* When we have processed all the stabs information, we need to go
+ through and fill in all the undefined tags. */
+
+boolean
+finish_stab (dhandle, handle)
+ PTR dhandle;
+ PTR handle;
+{
+ struct stab_handle *info = (struct stab_handle *) handle;
+ struct stab_tag *st;
+
+ if (info->within_function)
+ {
+ if (! stab_emit_pending_vars (dhandle, info)
+ || ! debug_end_function (dhandle, info->function_end))
+ return false;
+ info->within_function = false;
+ info->function_end = (bfd_vma) -1;
+ }
+
+ for (st = info->tags; st != NULL; st = st->next)
+ {
+ enum debug_type_kind kind;
+
+ kind = st->kind;
+ if (kind == DEBUG_KIND_ILLEGAL)
+ kind = DEBUG_KIND_STRUCT;
+ st->slot = debug_make_undefined_tagged_type (dhandle, st->name, kind);
+ if (st->slot == DEBUG_TYPE_NULL)
+ return false;
+ }
+
+ return true;
+}
+
+/* Handle a single stabs symbol. */
+
+boolean
+parse_stab (dhandle, handle, type, desc, value, string)
+ PTR dhandle;
+ PTR handle;
+ int type;
+ int desc;
+ bfd_vma value;
+ const char *string;
+{
+ struct stab_handle *info = (struct stab_handle *) handle;
+
+ /* gcc will emit two N_SO strings per compilation unit, one for the
+ directory name and one for the file name. We just collect N_SO
+ strings as we see them, and start the new compilation unit when
+ we see a non N_SO symbol. */
+ if (info->so_string != NULL
+ && (type != N_SO || *string == '\0' || value != info->so_value))
+ {
+ if (! debug_set_filename (dhandle, info->so_string))
+ return false;
+ info->main_filename = info->so_string;
+
+ info->gcc_compiled = 0;
+ info->n_opt_found = false;
+
+ /* Generally, for stabs in the symbol table, the N_LBRAC and
+ N_RBRAC symbols are relative to the N_SO symbol value. */
+ if (! info->sections)
+ info->file_start_offset = info->so_value;
+
+ /* We need to reset the mapping from type numbers to types. We
+ can't free the old mapping, because of the use of
+ debug_make_indirect_type. */
+ info->files = 1;
+ info->file_types = ((struct stab_types **)
+ xmalloc (sizeof *info->file_types));
+ info->file_types[0] = NULL;
+
+ info->so_string = NULL;
+
+ /* Now process whatever type we just got. */
+ }
+
+ switch (type)
+ {
+ case N_FN:
+ case N_FN_SEQ:
+ break;
+
+ case N_LBRAC:
+ /* Ignore extra outermost context from SunPRO cc and acc. */
+ if (info->n_opt_found && desc == 1)
+ break;
+
+ if (! info->within_function)
+ {
+ fprintf (stderr, "N_LBRAC not within function\n");
+ return false;
+ }
+
+ /* Start an inner lexical block. */
+ if (! debug_start_block (dhandle,
+ (value
+ + info->file_start_offset
+ + info->function_start_offset)))
+ return false;
+
+ /* Emit any pending variable definitions. */
+ if (! stab_emit_pending_vars (dhandle, info))
+ return false;
+
+ ++info->block_depth;
+ break;
+
+ case N_RBRAC:
+ /* Ignore extra outermost context from SunPRO cc and acc. */
+ if (info->n_opt_found && desc == 1)
+ break;
+
+ /* We shouldn't have any pending variable definitions here, but,
+ if we do, we probably need to emit them before closing the
+ block. */
+ if (! stab_emit_pending_vars (dhandle, info))
+ return false;
+
+ /* End an inner lexical block. */
+ if (! debug_end_block (dhandle,
+ (value
+ + info->file_start_offset
+ + info->function_start_offset)))
+ return false;
+
+ --info->block_depth;
+ if (info->block_depth < 0)
+ {
+ fprintf (stderr, "Too many N_RBRACs\n");
+ return false;
+ }
+ break;
+
+ case N_SO:
+ /* This always ends a function. */
+ if (info->within_function)
+ {
+ bfd_vma endval;
+
+ endval = value;
+ if (*string != '\0'
+ && info->function_end != (bfd_vma) -1
+ && info->function_end < endval)
+ endval = info->function_end;
+ if (! stab_emit_pending_vars (dhandle, info)
+ || ! debug_end_function (dhandle, endval))
+ return false;
+ info->within_function = false;
+ info->function_end = (bfd_vma) -1;
+ }
+
+ /* An empty string is emitted by gcc at the end of a compilation
+ unit. */
+ if (*string == '\0')
+ return true;
+
+ /* Just accumulate strings until we see a non N_SO symbol. If
+ the string starts with '/', we discard the previously
+ accumulated strings. */
+ if (info->so_string == NULL)
+ info->so_string = xstrdup (string);
+ else
+ {
+ char *f;
+
+ f = info->so_string;
+ if (*string == '/')
+ info->so_string = xstrdup (string);
+ else
+ info->so_string = concat (info->so_string, string,
+ (const char *) NULL);
+ free (f);
+ }
+
+ info->so_value = value;
+
+ break;
+
+ case N_SOL:
+ /* Start an include file. */
+ if (! debug_start_source (dhandle, string))
+ return false;
+ break;
+
+ case N_BINCL:
+ /* Start an include file which may be replaced. */
+ push_bincl (info, string, value);
+ if (! debug_start_source (dhandle, string))
+ return false;
+ break;
+
+ case N_EINCL:
+ /* End an N_BINCL include. */
+ if (! debug_start_source (dhandle, pop_bincl (info)))
+ return false;
+ break;
+
+ case N_EXCL:
+ /* This is a duplicate of a header file named by N_BINCL which
+ was eliminated by the linker. */
+ if (! find_excl (info, string, value))
+ return false;
+ break;
+
+ case N_SLINE:
+ if (! debug_record_line (dhandle, desc,
+ value + info->function_start_offset))
+ return false;
+ break;
+
+ case N_BCOMM:
+ if (! debug_start_common_block (dhandle, string))
+ return false;
+ break;
+
+ case N_ECOMM:
+ if (! debug_end_common_block (dhandle, string))
+ return false;
+ break;
+
+ case N_FUN:
+ if (*string == '\0')
+ {
+ if (info->within_function)
+ {
+ /* This always marks the end of a function; we don't
+ need to worry about info->function_end. */
+ if (info->sections)
+ value += info->function_start_offset;
+ if (! stab_emit_pending_vars (dhandle, info)
+ || ! debug_end_function (dhandle, value))
+ return false;
+ info->within_function = false;
+ info->function_end = (bfd_vma) -1;
+ }
+ break;
+ }
+
+ /* A const static symbol in the .text section will have an N_FUN
+ entry. We need to use these to mark the end of the function,
+ in case we are looking at gcc output before it was changed to
+ always emit an empty N_FUN. We can't call debug_end_function
+ here, because it might be a local static symbol. */
+ if (info->within_function
+ && (info->function_end == (bfd_vma) -1
+ || value < info->function_end))
+ info->function_end = value;
+
+ /* Fall through. */
+ /* FIXME: gdb checks the string for N_STSYM, N_LCSYM or N_ROSYM
+ symbols, and if it does not start with :S, gdb relocates the
+ value to the start of the section. gcc always seems to use
+ :S, so we don't worry about this. */
+ /* Fall through. */
+ default:
+ {
+ const char *colon;
+
+ colon = strchr (string, ':');
+ if (colon != NULL
+ && (colon[1] == 'f' || colon[1] == 'F'))
+ {
+ if (info->within_function)
+ {
+ bfd_vma endval;
+
+ endval = value;
+ if (info->function_end != (bfd_vma) -1
+ && info->function_end < endval)
+ endval = info->function_end;
+ if (! stab_emit_pending_vars (dhandle, info)
+ || ! debug_end_function (dhandle, endval))
+ return false;
+ info->function_end = (bfd_vma) -1;
+ }
+ /* For stabs in sections, line numbers and block addresses
+ are offsets from the start of the function. */
+ if (info->sections)
+ info->function_start_offset = value;
+ info->within_function = true;
+ }
+
+ if (! parse_stab_string (dhandle, info, type, desc, value, string))
+ return false;
+ }
+ break;
+
+ case N_OPT:
+ if (string != NULL && strcmp (string, "gcc2_compiled.") == 0)
+ info->gcc_compiled = 2;
+ else if (string != NULL && strcmp (string, "gcc_compiled.") == 0)
+ info->gcc_compiled = 1;
+ else
+ info->n_opt_found = true;
+ break;
+
+ case N_OBJ:
+ case N_ENDM:
+ case N_MAIN:
+ break;
+ }
+
+ return true;
+}
+
+/* Parse the stabs string. */
+
+static boolean
+parse_stab_string (dhandle, info, stabtype, desc, value, string)
+ PTR dhandle;
+ struct stab_handle *info;
+ int stabtype;
+ int desc;
+ bfd_vma value;
+ const char *string;
+{
+ const char *p;
+ char *name;
+ int type;
+ debug_type dtype;
+ boolean synonym;
+ unsigned int lineno;
+ debug_type *slot;
+
+ p = strchr (string, ':');
+ if (p == NULL)
+ return true;
+
+ while (p[1] == ':')
+ {
+ p += 2;
+ p = strchr (p, ':');
+ if (p == NULL)
+ {
+ bad_stab (string);
+ return false;
+ }
+ }
+
+ /* GCC 2.x puts the line number in desc. SunOS apparently puts in
+ the number of bytes occupied by a type or object, which we
+ ignore. */
+ if (info->gcc_compiled >= 2)
+ lineno = desc;
+ else
+ lineno = 0;
+
+ /* FIXME: Sometimes the special C++ names start with '.'. */
+ name = NULL;
+ if (string[0] == '$')
+ {
+ switch (string[1])
+ {
+ case 't':
+ name = "this";
+ break;
+ case 'v':
+ /* Was: name = "vptr"; */
+ break;
+ case 'e':
+ name = "eh_throw";
+ break;
+ case '_':
+ /* This was an anonymous type that was never fixed up. */
+ break;
+ case 'X':
+ /* SunPRO (3.0 at least) static variable encoding. */
+ break;
+ default:
+ warn_stab (string, "unknown C++ encoded name");
+ break;
+ }
+ }
+
+ if (name == NULL)
+ {
+ if (p == string || (string[0] == ' ' && p == string + 1))
+ name = NULL;
+ else
+ name = savestring (string, p - string);
+ }
+
+ ++p;
+ if (isdigit ((unsigned char) *p) || *p == '(' || *p == '-')
+ type = 'l';
+ else
+ type = *p++;
+
+ switch (type)
+ {
+ case 'c':
+ /* c is a special case, not followed by a type-number.
+ SYMBOL:c=iVALUE for an integer constant symbol.
+ SYMBOL:c=rVALUE for a floating constant symbol.
+ SYMBOL:c=eTYPE,INTVALUE for an enum constant symbol.
+ e.g. "b:c=e6,0" for "const b = blob1"
+ (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */
+ if (*p != '=')
+ {
+ bad_stab (string);
+ return false;
+ }
+ ++p;
+ switch (*p++)
+ {
+ case 'r':
+ /* Floating point constant. */
+ if (! debug_record_float_const (dhandle, name, atof (p)))
+ return false;
+ break;
+ case 'i':
+ /* Integer constant. */
+ /* Defining integer constants this way is kind of silly,
+ since 'e' constants allows the compiler to give not only
+ the value, but the type as well. C has at least int,
+ long, unsigned int, and long long as constant types;
+ other languages probably should have at least unsigned as
+ well as signed constants. */
+ if (! debug_record_int_const (dhandle, name, atoi (p)))
+ return false;
+ break;
+ case 'e':
+ /* SYMBOL:c=eTYPE,INTVALUE for a constant symbol whose value
+ can be represented as integral.
+ e.g. "b:c=e6,0" for "const b = blob1"
+ (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL,
+ &p, (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (*p != ',')
+ {
+ bad_stab (string);
+ return false;
+ }
+ if (! debug_record_typed_const (dhandle, name, dtype, atoi (p)))
+ return false;
+ break;
+ default:
+ bad_stab (string);
+ return false;
+ }
+
+ break;
+
+ case 'C':
+ /* The name of a caught exception. */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL,
+ &p, (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (! debug_record_label (dhandle, name, dtype, value))
+ return false;
+ break;
+
+ case 'f':
+ case 'F':
+ /* A function definition. */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (! debug_record_function (dhandle, name, dtype, type == 'F', value))
+ return false;
+
+ /* Sun acc puts declared types of arguments here. We don't care
+ about their actual types (FIXME -- we should remember the whole
+ function prototype), but the list may define some new types
+ that we have to remember, so we must scan it now. */
+ while (*p == ';')
+ {
+ ++p;
+ if (parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL)
+ == DEBUG_TYPE_NULL)
+ return false;
+ }
+
+ break;
+
+ case 'G':
+ {
+ char leading;
+ long c;
+ asymbol **ps;
+
+ /* A global symbol. The value must be extracted from the
+ symbol table. */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ leading = bfd_get_symbol_leading_char (info->abfd);
+ for (c = info->symcount, ps = info->syms; c > 0; --c, ++ps)
+ {
+ const char *n;
+
+ n = bfd_asymbol_name (*ps);
+ if (leading != '\0' && *n == leading)
+ ++n;
+ if (*n == *name && strcmp (n, name) == 0)
+ break;
+ }
+ if (c > 0)
+ value = bfd_asymbol_value (*ps);
+ if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_GLOBAL,
+ value))
+ return false;
+ }
+ break;
+
+ /* This case is faked by a conditional above, when there is no
+ code letter in the dbx data. Dbx data never actually
+ contains 'l'. */
+ case 'l':
+ case 's':
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL,
+ value))
+ return false;
+ break;
+
+ case 'p':
+ /* A function parameter. */
+ if (*p != 'F')
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ else
+ {
+ /* pF is a two-letter code that means a function parameter in
+ Fortran. The type-number specifies the type of the return
+ value. Translate it into a pointer-to-function type. */
+ ++p;
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype != DEBUG_TYPE_NULL)
+ {
+ debug_type ftype;
+
+ ftype = debug_make_function_type (dhandle, dtype,
+ (debug_type *) NULL, false);
+ dtype = debug_make_pointer_type (dhandle, ftype);
+ }
+ }
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_STACK,
+ value))
+ return false;
+
+ /* FIXME: At this point gdb considers rearranging the parameter
+ address on a big endian machine if it is smaller than an int.
+ We have no way to do that, since we don't really know much
+ about the target. */
+
+ break;
+
+ case 'P':
+ if (stabtype == N_FUN)
+ {
+ /* Prototype of a function referenced by this file. */
+ while (*p == ';')
+ {
+ ++p;
+ if (parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL)
+ == DEBUG_TYPE_NULL)
+ return false;
+ }
+ break;
+ }
+ /* Fall through. */
+ case 'R':
+ /* Parameter which is in a register. */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REG,
+ value))
+ return false;
+ break;
+
+ case 'r':
+ /* Register variable (either global or local). */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_REGISTER,
+ value))
+ return false;
+
+ /* FIXME: At this point gdb checks to combine pairs of 'p' and
+ 'r' stabs into a single 'P' stab. */
+
+ break;
+
+ case 'S':
+ /* Static symbol at top level of file */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_STATIC,
+ value))
+ return false;
+ break;
+
+ case 't':
+ /* A typedef. */
+ dtype = parse_stab_type (dhandle, info, name, &p, &slot);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (name == NULL)
+ {
+ /* A nameless type. Nothing to do. */
+ return true;
+ }
+
+ dtype = debug_name_type (dhandle, name, dtype);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+
+ if (slot != NULL)
+ *slot = dtype;
+
+ break;
+
+ case 'T':
+ /* Struct, union, or enum tag. For GNU C++, this can be be followed
+ by 't' which means we are typedef'ing it as well. */
+ if (*p != 't')
+ {
+ synonym = false;
+ /* FIXME: gdb sets synonym to true if the current language
+ is C++. */
+ }
+ else
+ {
+ synonym = true;
+ ++p;
+ }
+
+ dtype = parse_stab_type (dhandle, info, name, &p, &slot);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (name == NULL)
+ return true;
+
+ dtype = debug_tag_type (dhandle, name, dtype);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (slot != NULL)
+ *slot = dtype;
+
+ /* See if we have a cross reference to this tag which we can now
+ fill in. */
+ {
+ register struct stab_tag **pst;
+
+ for (pst = &info->tags; *pst != NULL; pst = &(*pst)->next)
+ {
+ if ((*pst)->name[0] == name[0]
+ && strcmp ((*pst)->name, name) == 0)
+ {
+ (*pst)->slot = dtype;
+ *pst = (*pst)->next;
+ break;
+ }
+ }
+ }
+
+ if (synonym)
+ {
+ dtype = debug_name_type (dhandle, name, dtype);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+
+ if (slot != NULL)
+ *slot = dtype;
+ }
+
+ break;
+
+ case 'V':
+ /* Static symbol of local scope */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ /* FIXME: gdb checks os9k_stabs here. */
+ if (! stab_record_variable (dhandle, info, name, dtype,
+ DEBUG_LOCAL_STATIC, value))
+ return false;
+ break;
+
+ case 'v':
+ /* Reference parameter. */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REFERENCE,
+ value))
+ return false;
+ break;
+
+ case 'a':
+ /* Reference parameter which is in a register. */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REF_REG,
+ value))
+ return false;
+ break;
+
+ case 'X':
+ /* This is used by Sun FORTRAN for "function result value".
+ Sun claims ("dbx and dbxtool interfaces", 2nd ed)
+ that Pascal uses it too, but when I tried it Pascal used
+ "x:3" (local symbol) instead. */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL,
+ value))
+ return false;
+ break;
+
+ default:
+ bad_stab (string);
+ return false;
+ }
+
+ /* FIXME: gdb converts structure values to structure pointers in a
+ couple of cases, depending upon the target. */
+
+ return true;
+}
+
+/* Parse a stabs type. The typename argument is non-NULL if this is a
+ typedef or a tag definition. The pp argument points to the stab
+ string, and is updated. The slotp argument points to a place to
+ store the slot used if the type is being defined. */
+
+static debug_type
+parse_stab_type (dhandle, info, typename, pp, slotp)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char *typename;
+ const char **pp;
+ debug_type **slotp;
+{
+ const char *orig;
+ int typenums[2];
+ int size;
+ boolean stringp;
+ int descriptor;
+ debug_type dtype;
+
+ if (slotp != NULL)
+ *slotp = NULL;
+
+ orig = *pp;
+
+ size = -1;
+ stringp = false;
+
+ /* Read type number if present. The type number may be omitted.
+ for instance in a two-dimensional array declared with type
+ "ar1;1;10;ar1;1;10;4". */
+ if (! isdigit ((unsigned char) **pp) && **pp != '(' && **pp != '-')
+ {
+ /* 'typenums=' not present, type is anonymous. Read and return
+ the definition, but don't put it in the type vector. */
+ typenums[0] = typenums[1] = -1;
+ }
+ else
+ {
+ if (! parse_stab_type_number (pp, typenums))
+ return DEBUG_TYPE_NULL;
+
+ if (**pp != '=')
+ {
+ /* Type is not being defined here. Either it already
+ exists, or this is a forward reference to it. */
+ return stab_find_type (dhandle, info, typenums);
+ }
+
+ /* Only set the slot if the type is being defined. This means
+ that the mapping from type numbers to types will only record
+ the name of the typedef which defines a type. If we don't do
+ this, then something like
+ typedef int foo;
+ int i;
+ will record that i is of type foo. Unfortunately, stabs
+ information is ambiguous about variable types. For this code,
+ typedef int foo;
+ int i;
+ foo j;
+ the stabs information records both i and j as having the same
+ type. This could be fixed by patching the compiler. */
+ if (slotp != NULL && typenums[0] >= 0 && typenums[1] >= 0)
+ *slotp = stab_find_slot (info, typenums);
+
+ /* Type is being defined here. */
+ /* Skip the '='. */
+ ++*pp;
+
+ while (**pp == '@')
+ {
+ const char *p = *pp + 1;
+ const char *attr;
+
+ if (isdigit ((unsigned char) *p) || *p == '(' || *p == '-')
+ {
+ /* Member type. */
+ break;
+ }
+
+ /* Type attributes. */
+ attr = p;
+
+ for (; *p != ';'; ++p)
+ {
+ if (*p == '\0')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ }
+ *pp = p + 1;
+
+ switch (*attr)
+ {
+ case 's':
+ size = atoi (attr + 1);
+ if (size <= 0)
+ size = -1;
+ break;
+
+ case 'S':
+ stringp = true;
+ break;
+
+ default:
+ /* Ignore unrecognized type attributes, so future
+ compilers can invent new ones. */
+ break;
+ }
+ }
+ }
+
+ descriptor = **pp;
+ ++*pp;
+
+ switch (descriptor)
+ {
+ case 'x':
+ {
+ enum debug_type_kind code;
+ const char *q1, *q2, *p;
+
+ /* A cross reference to another type. */
+
+ switch (**pp)
+ {
+ case 's':
+ code = DEBUG_KIND_STRUCT;
+ break;
+ case 'u':
+ code = DEBUG_KIND_UNION;
+ break;
+ case 'e':
+ code = DEBUG_KIND_ENUM;
+ break;
+ default:
+ /* Complain and keep going, so compilers can invent new
+ cross-reference types. */
+ warn_stab (orig, "unrecognized cross reference type");
+ code = DEBUG_KIND_STRUCT;
+ break;
+ }
+ ++*pp;
+
+ q1 = strchr (*pp, '<');
+ p = strchr (*pp, ':');
+ if (p == NULL)
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ while (q1 != NULL && p > q1 && p[1] == ':')
+ {
+ q2 = strchr (q1, '>');
+ if (q2 == NULL || q2 < p)
+ break;
+ p += 2;
+ p = strchr (p, ':');
+ if (p == NULL)
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ }
+
+ dtype = stab_find_tagged_type (dhandle, info, *pp, p - *pp, code);
+
+ *pp = p + 1;
+ }
+ break;
+
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '(':
+ {
+ const char *hold;
+ int xtypenums[2];
+
+ /* This type is defined as another type. */
+
+ (*pp)--;
+ hold = *pp;
+
+ /* Peek ahead at the number to detect void. */
+ if (! parse_stab_type_number (pp, xtypenums))
+ return DEBUG_TYPE_NULL;
+
+ if (typenums[0] == xtypenums[0] && typenums[1] == xtypenums[1])
+ {
+ /* This type is being defined as itself, which means that
+ it is void. */
+ dtype = debug_make_void_type (dhandle);
+ }
+ else
+ {
+ *pp = hold;
+
+ /* Go back to the number and have parse_stab_type get it.
+ This means that we can deal with something like
+ t(1,2)=(3,4)=... which the Lucid compiler uses. */
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL,
+ pp, (debug_type **) NULL);
+ if (dtype == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+ }
+
+ if (typenums[0] != -1)
+ {
+ if (! stab_record_type (dhandle, info, typenums, dtype))
+ return DEBUG_TYPE_NULL;
+ }
+
+ break;
+ }
+
+ case '*':
+ dtype = debug_make_pointer_type (dhandle,
+ parse_stab_type (dhandle, info,
+ (const char *) NULL,
+ pp,
+ (debug_type **) NULL));
+ break;
+
+ case '&':
+ /* Reference to another type. */
+ dtype = (debug_make_reference_type
+ (dhandle,
+ parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL)));
+ break;
+
+ case 'f':
+ /* Function returning another type. */
+ /* FIXME: gdb checks os9k_stabs here. */
+ dtype = (debug_make_function_type
+ (dhandle,
+ parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL),
+ (debug_type *) NULL, false));
+ break;
+
+ case 'k':
+ /* Const qualifier on some type (Sun). */
+ /* FIXME: gdb accepts 'c' here if os9k_stabs. */
+ dtype = debug_make_const_type (dhandle,
+ parse_stab_type (dhandle, info,
+ (const char *) NULL,
+ pp,
+ (debug_type **) NULL));
+ break;
+
+ case 'B':
+ /* Volatile qual on some type (Sun). */
+ /* FIXME: gdb accepts 'i' here if os9k_stabs. */
+ dtype = (debug_make_volatile_type
+ (dhandle,
+ parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL)));
+ break;
+
+ case '@':
+ /* Offset (class & variable) type. This is used for a pointer
+ relative to an object. */
+ {
+ debug_type domain;
+ debug_type memtype;
+
+ /* Member type. */
+
+ domain = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ if (domain == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+
+ if (**pp != ',')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ memtype = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ if (memtype == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+
+ dtype = debug_make_offset_type (dhandle, domain, memtype);
+ }
+ break;
+
+ case '#':
+ /* Method (class & fn) type. */
+ if (**pp == '#')
+ {
+ debug_type return_type;
+
+ ++*pp;
+ return_type = parse_stab_type (dhandle, info, (const char *) NULL,
+ pp, (debug_type **) NULL);
+ if (return_type == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+ dtype = debug_make_method_type (dhandle, return_type,
+ DEBUG_TYPE_NULL,
+ (debug_type *) NULL, false);
+ }
+ else
+ {
+ debug_type domain;
+ debug_type return_type;
+ debug_type *args;
+ unsigned int n;
+ unsigned int alloc;
+ boolean varargs;
+
+ domain = parse_stab_type (dhandle, info, (const char *) NULL,
+ pp, (debug_type **) NULL);
+ if (domain == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+
+ if (**pp != ',')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ return_type = parse_stab_type (dhandle, info, (const char *) NULL,
+ pp, (debug_type **) NULL);
+ if (return_type == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+
+ alloc = 10;
+ args = (debug_type *) xmalloc (alloc * sizeof *args);
+ n = 0;
+ while (**pp != ';')
+ {
+ if (**pp != ',')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ if (n + 1 >= alloc)
+ {
+ alloc += 10;
+ args = ((debug_type *)
+ xrealloc ((PTR) args, alloc * sizeof *args));
+ }
+
+ args[n] = parse_stab_type (dhandle, info, (const char *) NULL,
+ pp, (debug_type **) NULL);
+ if (args[n] == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+ ++n;
+ }
+ ++*pp;
+
+ /* If the last type is not void, then this function takes a
+ variable number of arguments. Otherwise, we must strip
+ the void type. */
+ if (n == 0
+ || debug_get_type_kind (dhandle, args[n - 1]) != DEBUG_KIND_VOID)
+ varargs = true;
+ else
+ {
+ --n;
+ varargs = false;
+ }
+
+ args[n] = DEBUG_TYPE_NULL;
+
+ dtype = debug_make_method_type (dhandle, return_type, domain, args,
+ varargs);
+ }
+ break;
+
+ case 'r':
+ /* Range type. */
+ dtype = parse_stab_range_type (dhandle, info, typename, pp, typenums);
+ break;
+
+ case 'b':
+ /* FIXME: gdb checks os9k_stabs here. */
+ /* Sun ACC builtin int type. */
+ dtype = parse_stab_sun_builtin_type (dhandle, pp);
+ break;
+
+ case 'R':
+ /* Sun ACC builtin float type. */
+ dtype = parse_stab_sun_floating_type (dhandle, pp);
+ break;
+
+ case 'e':
+ /* Enumeration type. */
+ dtype = parse_stab_enum_type (dhandle, pp);
+ break;
+
+ case 's':
+ case 'u':
+ /* Struct or union type. */
+ dtype = parse_stab_struct_type (dhandle, info, typename, pp,
+ descriptor == 's', typenums);
+ break;
+
+ case 'a':
+ /* Array type. */
+ if (**pp != 'r')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ dtype = parse_stab_array_type (dhandle, info, pp, stringp);
+ break;
+
+ case 'S':
+ dtype = debug_make_set_type (dhandle,
+ parse_stab_type (dhandle, info,
+ (const char *) NULL,
+ pp,
+ (debug_type **) NULL),
+ stringp);
+ break;
+
+ default:
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+
+ if (dtype == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+
+ if (typenums[0] != -1)
+ {
+ if (! stab_record_type (dhandle, info, typenums, dtype))
+ return DEBUG_TYPE_NULL;
+ }
+
+ if (size != -1)
+ {
+ if (! debug_record_type_size (dhandle, dtype, (unsigned int) size))
+ return DEBUG_TYPE_NULL;
+ }
+
+ return dtype;
+}
+
+/* Read a number by which a type is referred to in dbx data, or
+ perhaps read a pair (FILENUM, TYPENUM) in parentheses. Just a
+ single number N is equivalent to (0,N). Return the two numbers by
+ storing them in the vector TYPENUMS. */
+
+static boolean
+parse_stab_type_number (pp, typenums)
+ const char **pp;
+ int *typenums;
+{
+ const char *orig;
+
+ orig = *pp;
+
+ if (**pp != '(')
+ {
+ typenums[0] = 0;
+ typenums[1] = (int) parse_number (pp, (boolean *) NULL);
+ }
+ else
+ {
+ ++*pp;
+ typenums[0] = (int) parse_number (pp, (boolean *) NULL);
+ if (**pp != ',')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+ typenums[1] = (int) parse_number (pp, (boolean *) NULL);
+ if (**pp != ')')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+ }
+
+ return true;
+}
+
+/* Parse a range type. */
+
+static debug_type
+parse_stab_range_type (dhandle, info, typename, pp, typenums)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char *typename;
+ const char **pp;
+ const int *typenums;
+{
+ const char *orig;
+ int rangenums[2];
+ boolean self_subrange;
+ debug_type index_type;
+ const char *s2, *s3;
+ bfd_signed_vma n2, n3;
+ boolean ov2, ov3;
+
+ orig = *pp;
+
+ index_type = DEBUG_TYPE_NULL;
+
+ /* First comes a type we are a subrange of.
+ In C it is usually 0, 1 or the type being defined. */
+ if (! parse_stab_type_number (pp, rangenums))
+ return DEBUG_TYPE_NULL;
+
+ self_subrange = (rangenums[0] == typenums[0]
+ && rangenums[1] == typenums[1]);
+
+ if (**pp == '=')
+ {
+ *pp = orig;
+ index_type = parse_stab_type (dhandle, info, (const char *) NULL,
+ pp, (debug_type **) NULL);
+ if (index_type == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+ }
+
+ if (**pp == ';')
+ ++*pp;
+
+ /* The remaining two operands are usually lower and upper bounds of
+ the range. But in some special cases they mean something else. */
+ s2 = *pp;
+ n2 = parse_number (pp, &ov2);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ s3 = *pp;
+ n3 = parse_number (pp, &ov3);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ if (ov2 || ov3)
+ {
+ /* gcc will emit range stabs for long long types. Handle this
+ as a special case. FIXME: This needs to be more general. */
+#define LLLOW "01000000000000000000000;"
+#define LLHIGH "0777777777777777777777;"
+#define ULLHIGH "01777777777777777777777;"
+ if (index_type == DEBUG_TYPE_NULL)
+ {
+ if (strncmp (s2, LLLOW, sizeof LLLOW - 1) == 0
+ && strncmp (s3, LLHIGH, sizeof LLHIGH - 1) == 0)
+ return debug_make_int_type (dhandle, 8, false);
+ if (! ov2
+ && n2 == 0
+ && strncmp (s3, ULLHIGH, sizeof ULLHIGH - 1) == 0)
+ return debug_make_int_type (dhandle, 8, true);
+ }
+
+ warn_stab (orig, "numeric overflow");
+ }
+
+ if (index_type == DEBUG_TYPE_NULL)
+ {
+ /* A type defined as a subrange of itself, with both bounds 0,
+ is void. */
+ if (self_subrange && n2 == 0 && n3 == 0)
+ return debug_make_void_type (dhandle);
+
+ /* A type defined as a subrange of itself, with n2 positive and
+ n3 zero, is a complex type, and n2 is the number of bytes. */
+ if (self_subrange && n3 == 0 && n2 > 0)
+ return debug_make_complex_type (dhandle, n2);
+
+ /* If n3 is zero and n2 is positive, this is a floating point
+ type, and n2 is the number of bytes. */
+ if (n3 == 0 && n2 > 0)
+ return debug_make_float_type (dhandle, n2);
+
+ /* If the upper bound is -1, this is an unsigned int. */
+ if (n2 == 0 && n3 == -1)
+ {
+ /* When gcc is used with -gstabs, but not -gstabs+, it will emit
+ long long int:t6=r1;0;-1;
+ long long unsigned int:t7=r1;0;-1;
+ We hack here to handle this reasonably. */
+ if (typename != NULL)
+ {
+ if (strcmp (typename, "long long int") == 0)
+ return debug_make_int_type (dhandle, 8, false);
+ else if (strcmp (typename, "long long unsigned int") == 0)
+ return debug_make_int_type (dhandle, 8, true);
+ }
+ /* FIXME: The size here really depends upon the target. */
+ return debug_make_int_type (dhandle, 4, true);
+ }
+
+ /* A range of 0 to 127 is char. */
+ if (self_subrange && n2 == 0 && n3 == 127)
+ return debug_make_int_type (dhandle, 1, false);
+
+ /* FIXME: gdb checks for the language CHILL here. */
+
+ if (n2 == 0)
+ {
+ if (n3 < 0)
+ return debug_make_int_type (dhandle, - n3, true);
+ else if (n3 == 0xff)
+ return debug_make_int_type (dhandle, 1, true);
+ else if (n3 == 0xffff)
+ return debug_make_int_type (dhandle, 2, true);
+ /* -1 is used for the upper bound of (4 byte) "unsigned int"
+ and "unsigned long", and we already checked for that, so
+ don't need to test for it here. */
+ }
+ else if (n3 == 0
+ && n2 < 0
+ && (self_subrange || n2 == -8))
+ return debug_make_int_type (dhandle, - n2, true);
+ else if (n2 == - n3 - 1)
+ {
+ if (n3 == 0x7f)
+ return debug_make_int_type (dhandle, 1, false);
+ else if (n3 == 0x7fff)
+ return debug_make_int_type (dhandle, 2, false);
+ else if (n3 == 0x7fffffff)
+ return debug_make_int_type (dhandle, 4, false);
+ }
+ }
+
+ /* At this point I don't have the faintest idea how to deal with a
+ self_subrange type; I'm going to assume that this is used as an
+ idiom, and that all of them are special cases. So . . . */
+ if (self_subrange)
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+
+ index_type = stab_find_type (dhandle, info, rangenums);
+ if (index_type == DEBUG_TYPE_NULL)
+ {
+ /* Does this actually ever happen? Is that why we are worrying
+ about dealing with it rather than just calling error_type? */
+ warn_stab (orig, "missing index type");
+ index_type = debug_make_int_type (dhandle, 4, false);
+ }
+
+ return debug_make_range_type (dhandle, index_type, n2, n3);
+}
+
+/* Sun's ACC uses a somewhat saner method for specifying the builtin
+ typedefs in every file (for int, long, etc):
+
+ type = b <signed> <width>; <offset>; <nbits>
+ signed = u or s. Possible c in addition to u or s (for char?).
+ offset = offset from high order bit to start bit of type.
+ width is # bytes in object of this type, nbits is # bits in type.
+
+ The width/offset stuff appears to be for small objects stored in
+ larger ones (e.g. `shorts' in `int' registers). We ignore it for now,
+ FIXME. */
+
+static debug_type
+parse_stab_sun_builtin_type (dhandle, pp)
+ PTR dhandle;
+ const char **pp;
+{
+ const char *orig;
+ boolean unsignedp;
+ bfd_vma bits;
+
+ orig = *pp;
+
+ switch (**pp)
+ {
+ case 's':
+ unsignedp = false;
+ break;
+ case 'u':
+ unsignedp = true;
+ break;
+ default:
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ /* For some odd reason, all forms of char put a c here. This is strange
+ because no other type has this honor. We can safely ignore this because
+ we actually determine 'char'acterness by the number of bits specified in
+ the descriptor. */
+ if (**pp == 'c')
+ ++*pp;
+
+ /* The first number appears to be the number of bytes occupied
+ by this type, except that unsigned short is 4 instead of 2.
+ Since this information is redundant with the third number,
+ we will ignore it. */
+ (void) parse_number (pp, (boolean *) NULL);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ /* The second number is always 0, so ignore it too. */
+ (void) parse_number (pp, (boolean *) NULL);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ /* The third number is the number of bits for this type. */
+ bits = parse_number (pp, (boolean *) NULL);
+
+ /* The type *should* end with a semicolon. If it are embedded
+ in a larger type the semicolon may be the only way to know where
+ the type ends. If this type is at the end of the stabstring we
+ can deal with the omitted semicolon (but we don't have to like
+ it). Don't bother to complain(), Sun's compiler omits the semicolon
+ for "void". */
+ if (**pp == ';')
+ ++*pp;
+
+ if (bits == 0)
+ return debug_make_void_type (dhandle);
+
+ return debug_make_int_type (dhandle, bits / 8, unsignedp);
+}
+
+/* Parse a builtin floating type generated by the Sun compiler. */
+
+static debug_type
+parse_stab_sun_floating_type (dhandle, pp)
+ PTR dhandle;
+ const char **pp;
+{
+ const char *orig;
+ bfd_vma details;
+ bfd_vma bytes;
+
+ orig = *pp;
+
+ /* The first number has more details about the type, for example
+ FN_COMPLEX. */
+ details = parse_number (pp, (boolean *) NULL);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+
+ /* The second number is the number of bytes occupied by this type */
+ bytes = parse_number (pp, (boolean *) NULL);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+
+ if (details == NF_COMPLEX
+ || details == NF_COMPLEX16
+ || details == NF_COMPLEX32)
+ return debug_make_complex_type (dhandle, bytes);
+
+ return debug_make_float_type (dhandle, bytes);
+}
+
+/* Handle an enum type. */
+
+static debug_type
+parse_stab_enum_type (dhandle, pp)
+ PTR dhandle;
+ const char **pp;
+{
+ const char *orig;
+ const char **names;
+ bfd_signed_vma *values;
+ unsigned int n;
+ unsigned int alloc;
+
+ orig = *pp;
+
+ /* FIXME: gdb checks os9k_stabs here. */
+
+ /* The aix4 compiler emits an extra field before the enum members;
+ my guess is it's a type of some sort. Just ignore it. */
+ if (**pp == '-')
+ {
+ while (**pp != ':')
+ ++*pp;
+ ++*pp;
+ }
+
+ /* Read the value-names and their values.
+ The input syntax is NAME:VALUE,NAME:VALUE, and so on.
+ A semicolon or comma instead of a NAME means the end. */
+ alloc = 10;
+ names = (const char **) xmalloc (alloc * sizeof *names);
+ values = (bfd_signed_vma *) xmalloc (alloc * sizeof *values);
+ n = 0;
+ while (**pp != '\0' && **pp != ';' && **pp != ',')
+ {
+ const char *p;
+ char *name;
+ bfd_signed_vma val;
+
+ p = *pp;
+ while (*p != ':')
+ ++p;
+
+ name = savestring (*pp, p - *pp);
+
+ *pp = p + 1;
+ val = (bfd_signed_vma) parse_number (pp, (boolean *) NULL);
+ if (**pp != ',')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ if (n + 1 >= alloc)
+ {
+ alloc += 10;
+ names = ((const char **)
+ xrealloc ((PTR) names, alloc * sizeof *names));
+ values = ((bfd_signed_vma *)
+ xrealloc ((PTR) values, alloc * sizeof *values));
+ }
+
+ names[n] = name;
+ values[n] = val;
+ ++n;
+ }
+
+ names[n] = NULL;
+ values[n] = 0;
+
+ if (**pp == ';')
+ ++*pp;
+
+ return debug_make_enum_type (dhandle, names, values);
+}
+
+/* Read the description of a structure (or union type) and return an object
+ describing the type.
+
+ PP points to a character pointer that points to the next unconsumed token
+ in the the stabs string. For example, given stabs "A:T4=s4a:1,0,32;;",
+ *PP will point to "4a:1,0,32;;". */
+
+static debug_type
+parse_stab_struct_type (dhandle, info, tagname, pp, structp, typenums)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char *tagname;
+ const char **pp;
+ boolean structp;
+ const int *typenums;
+{
+ const char *orig;
+ bfd_vma size;
+ debug_baseclass *baseclasses;
+ debug_field *fields;
+ boolean statics;
+ debug_method *methods;
+ debug_type vptrbase;
+ boolean ownvptr;
+
+ orig = *pp;
+
+ /* Get the size. */
+ size = parse_number (pp, (boolean *) NULL);
+
+ /* Get the other information. */
+ if (! parse_stab_baseclasses (dhandle, info, pp, &baseclasses)
+ || ! parse_stab_struct_fields (dhandle, info, pp, &fields, &statics)
+ || ! parse_stab_members (dhandle, info, tagname, pp, typenums, &methods)
+ || ! parse_stab_tilde_field (dhandle, info, pp, typenums, &vptrbase,
+ &ownvptr))
+ return DEBUG_TYPE_NULL;
+
+ if (! statics
+ && baseclasses == NULL
+ && methods == NULL
+ && vptrbase == DEBUG_TYPE_NULL
+ && ! ownvptr)
+ return debug_make_struct_type (dhandle, structp, size, fields);
+
+ return debug_make_object_type (dhandle, structp, size, fields, baseclasses,
+ methods, vptrbase, ownvptr);
+}
+
+/* The stabs for C++ derived classes contain baseclass information which
+ is marked by a '!' character after the total size. This function is
+ called when we encounter the baseclass marker, and slurps up all the
+ baseclass information.
+
+ Immediately following the '!' marker is the number of base classes that
+ the class is derived from, followed by information for each base class.
+ For each base class, there are two visibility specifiers, a bit offset
+ to the base class information within the derived class, a reference to
+ the type for the base class, and a terminating semicolon.
+
+ A typical example, with two base classes, would be "!2,020,19;0264,21;".
+ ^^ ^ ^ ^ ^ ^ ^
+ Baseclass information marker __________________|| | | | | | |
+ Number of baseclasses __________________________| | | | | | |
+ Visibility specifiers (2) ________________________| | | | | |
+ Offset in bits from start of class _________________| | | | |
+ Type number for base class ___________________________| | | |
+ Visibility specifiers (2) _______________________________| | |
+ Offset in bits from start of class ________________________| |
+ Type number of base class ____________________________________|
+
+ Return true for success, false for failure. */
+
+static boolean
+parse_stab_baseclasses (dhandle, info, pp, retp)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char **pp;
+ debug_baseclass **retp;
+{
+ const char *orig;
+ unsigned int c, i;
+ debug_baseclass *classes;
+
+ *retp = NULL;
+
+ orig = *pp;
+
+ if (**pp != '!')
+ {
+ /* No base classes. */
+ return true;
+ }
+ ++*pp;
+
+ c = (unsigned int) parse_number (pp, (boolean *) NULL);
+
+ if (**pp != ',')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+
+ classes = (debug_baseclass *) xmalloc ((c + 1) * sizeof (**retp));
+
+ for (i = 0; i < c; i++)
+ {
+ boolean virtual;
+ enum debug_visibility visibility;
+ bfd_vma bitpos;
+ debug_type type;
+
+ switch (**pp)
+ {
+ case '0':
+ virtual = false;
+ break;
+ case '1':
+ virtual = true;
+ break;
+ default:
+ warn_stab (orig, "unknown virtual character for baseclass");
+ virtual = false;
+ break;
+ }
+ ++*pp;
+
+ switch (**pp)
+ {
+ case '0':
+ visibility = DEBUG_VISIBILITY_PRIVATE;
+ break;
+ case '1':
+ visibility = DEBUG_VISIBILITY_PROTECTED;
+ break;
+ case '2':
+ visibility = DEBUG_VISIBILITY_PUBLIC;
+ break;
+ default:
+ warn_stab (orig, "unknown visibility character for baseclass");
+ visibility = DEBUG_VISIBILITY_PUBLIC;
+ break;
+ }
+ ++*pp;
+
+ /* The remaining value is the bit offset of the portion of the
+ object corresponding to this baseclass. Always zero in the
+ absence of multiple inheritance. */
+ bitpos = parse_number (pp, (boolean *) NULL);
+ if (**pp != ',')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+
+ type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ if (type == DEBUG_TYPE_NULL)
+ return false;
+
+ classes[i] = debug_make_baseclass (dhandle, type, bitpos, virtual,
+ visibility);
+ if (classes[i] == DEBUG_BASECLASS_NULL)
+ return false;
+
+ if (**pp != ';')
+ return false;
+ ++*pp;
+ }
+
+ classes[i] = DEBUG_BASECLASS_NULL;
+
+ *retp = classes;
+
+ return true;
+}
+
+/* Read struct or class data fields. They have the form:
+
+ NAME : [VISIBILITY] TYPENUM , BITPOS , BITSIZE ;
+
+ At the end, we see a semicolon instead of a field.
+
+ In C++, this may wind up being NAME:?TYPENUM:PHYSNAME; for
+ a static field.
+
+ The optional VISIBILITY is one of:
+
+ '/0' (VISIBILITY_PRIVATE)
+ '/1' (VISIBILITY_PROTECTED)
+ '/2' (VISIBILITY_PUBLIC)
+ '/9' (VISIBILITY_IGNORE)
+
+ or nothing, for C style fields with public visibility.
+
+ Returns 1 for success, 0 for failure. */
+
+static boolean
+parse_stab_struct_fields (dhandle, info, pp, retp, staticsp)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char **pp;
+ debug_field **retp;
+ boolean *staticsp;
+{
+ const char *orig;
+ const char *p;
+ debug_field *fields;
+ unsigned int c;
+ unsigned int alloc;
+
+ *retp = NULL;
+ *staticsp = false;
+
+ orig = *pp;
+
+ c = 0;
+ alloc = 10;
+ fields = (debug_field *) xmalloc (alloc * sizeof *fields);
+ while (**pp != ';')
+ {
+ /* FIXME: gdb checks os9k_stabs here. */
+
+ p = *pp;
+
+ /* Add 1 to c to leave room for NULL pointer at end. */
+ if (c + 1 >= alloc)
+ {
+ alloc += 10;
+ fields = ((debug_field *)
+ xrealloc ((PTR) fields, alloc * sizeof *fields));
+ }
+
+ /* If it starts with CPLUS_MARKER it is a special abbreviation,
+ unless the CPLUS_MARKER is followed by an underscore, in
+ which case it is just the name of an anonymous type, which we
+ should handle like any other type name. We accept either '$'
+ or '.', because a field name can never contain one of these
+ characters except as a CPLUS_MARKER. */
+
+ if ((*p == '$' || *p == '.') && p[1] != '_')
+ {
+ ++*pp;
+ if (! parse_stab_cpp_abbrev (dhandle, info, pp, fields + c))
+ return false;
+ ++c;
+ continue;
+ }
+
+ /* Look for the ':' that separates the field name from the field
+ values. Data members are delimited by a single ':', while member
+ functions are delimited by a pair of ':'s. When we hit the member
+ functions (if any), terminate scan loop and return. */
+
+ p = strchr (p, ':');
+ if (p == NULL)
+ {
+ bad_stab (orig);
+ return false;
+ }
+
+ if (p[1] == ':')
+ break;
+
+ if (! parse_stab_one_struct_field (dhandle, info, pp, p, fields + c,
+ staticsp))
+ return false;
+
+ ++c;
+ }
+
+ fields[c] = DEBUG_FIELD_NULL;
+
+ *retp = fields;
+
+ return true;
+}
+
+/* Special GNU C++ name. */
+
+static boolean
+parse_stab_cpp_abbrev (dhandle, info, pp, retp)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char **pp;
+ debug_field *retp;
+{
+ const char *orig;
+ int cpp_abbrev;
+ debug_type context;
+ const char *name;
+ const char *typename;
+ debug_type type;
+ bfd_vma bitpos;
+
+ *retp = DEBUG_FIELD_NULL;
+
+ orig = *pp;
+
+ if (**pp != 'v')
+ {
+ bad_stab (*pp);
+ return false;
+ }
+ ++*pp;
+
+ cpp_abbrev = **pp;
+ ++*pp;
+
+ /* At this point, *pp points to something like "22:23=*22...", where
+ the type number before the ':' is the "context" and everything
+ after is a regular type definition. Lookup the type, find it's
+ name, and construct the field name. */
+
+ context = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ if (context == DEBUG_TYPE_NULL)
+ return false;
+
+ switch (cpp_abbrev)
+ {
+ case 'f':
+ /* $vf -- a virtual function table pointer. */
+ name = "_vptr$";
+ break;
+ case 'b':
+ /* $vb -- a virtual bsomethingorother */
+ typename = debug_get_type_name (dhandle, context);
+ if (typename == NULL)
+ {
+ warn_stab (orig, "unnamed $vb type");
+ typename = "FOO";
+ }
+ name = concat ("_vb$", typename, (const char *) NULL);
+ break;
+ default:
+ warn_stab (orig, "unrecognized C++ abbreviation");
+ name = "INVALID_CPLUSPLUS_ABBREV";
+ break;
+ }
+
+ if (**pp != ':')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+
+ type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ if (**pp != ',')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+
+ bitpos = parse_number (pp, (boolean *) NULL);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+
+ *retp = debug_make_field (dhandle, name, type, bitpos, 0,
+ DEBUG_VISIBILITY_PRIVATE);
+ if (*retp == DEBUG_FIELD_NULL)
+ return false;
+
+ return true;
+}
+
+/* Parse a single field in a struct or union. */
+
+static boolean
+parse_stab_one_struct_field (dhandle, info, pp, p, retp, staticsp)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char **pp;
+ const char *p;
+ debug_field *retp;
+ boolean *staticsp;
+{
+ const char *orig;
+ char *name;
+ enum debug_visibility visibility;
+ debug_type type;
+ bfd_vma bitpos;
+ bfd_vma bitsize;
+
+ orig = *pp;
+
+ /* FIXME: gdb checks ARM_DEMANGLING here. */
+
+ name = savestring (*pp, p - *pp);
+
+ *pp = p + 1;
+
+ if (**pp != '/')
+ visibility = DEBUG_VISIBILITY_PUBLIC;
+ else
+ {
+ ++*pp;
+ switch (**pp)
+ {
+ case '0':
+ visibility = DEBUG_VISIBILITY_PRIVATE;
+ break;
+ case '1':
+ visibility = DEBUG_VISIBILITY_PROTECTED;
+ break;
+ case '2':
+ visibility = DEBUG_VISIBILITY_PUBLIC;
+ break;
+ default:
+ warn_stab (orig, "unknown visibility character for field");
+ visibility = DEBUG_VISIBILITY_PUBLIC;
+ break;
+ }
+ ++*pp;
+ }
+
+ type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ if (type == DEBUG_TYPE_NULL)
+ return false;
+
+ if (**pp == ':')
+ {
+ char *varname;
+
+ /* This is a static class member. */
+ ++*pp;
+ p = strchr (*pp, ';');
+ if (p == NULL)
+ {
+ bad_stab (orig);
+ return false;
+ }
+
+ varname = savestring (*pp, p - *pp);
+
+ *pp = p + 1;
+
+ *retp = debug_make_static_member (dhandle, name, type, varname,
+ visibility);
+ *staticsp = true;
+
+ return true;
+ }
+
+ if (**pp != ',')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+
+ bitpos = parse_number (pp, (boolean *) NULL);
+ if (**pp != ',')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+
+ bitsize = parse_number (pp, (boolean *) NULL);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+
+ if (bitpos == 0 && bitsize == 0)
+ {
+ /* This can happen in two cases: (1) at least for gcc 2.4.5 or
+ so, it is a field which has been optimized out. The correct
+ stab for this case is to use VISIBILITY_IGNORE, but that is a
+ recent invention. (2) It is a 0-size array. For example
+ union { int num; char str[0]; } foo. Printing "<no value>"
+ for str in "p foo" is OK, since foo.str (and thus foo.str[3])
+ will continue to work, and a 0-size array as a whole doesn't
+ have any contents to print.
+
+ I suspect this probably could also happen with gcc -gstabs
+ (not -gstabs+) for static fields, and perhaps other C++
+ extensions. Hopefully few people use -gstabs with gdb, since
+ it is intended for dbx compatibility. */
+ visibility = DEBUG_VISIBILITY_IGNORE;
+ }
+
+ /* FIXME: gdb does some stuff here to mark fields as unpacked. */
+
+ *retp = debug_make_field (dhandle, name, type, bitpos, bitsize, visibility);
+
+ return true;
+}
+
+/* Read member function stabs info for C++ classes. The form of each member
+ function data is:
+
+ NAME :: TYPENUM[=type definition] ARGS : PHYSNAME ;
+
+ An example with two member functions is:
+
+ afunc1::20=##15;:i;2A.;afunc2::20:i;2A.;
+
+ For the case of overloaded operators, the format is op$::*.funcs, where
+ $ is the CPLUS_MARKER (usually '$'), `*' holds the place for an operator
+ name (such as `+=') and `.' marks the end of the operator name. */
+
+static boolean
+parse_stab_members (dhandle, info, tagname, pp, typenums, retp)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char *tagname;
+ const char **pp;
+ const int *typenums;
+ debug_method **retp;
+{
+ const char *orig;
+ debug_method *methods;
+ unsigned int c;
+ unsigned int alloc;
+
+ *retp = NULL;
+
+ orig = *pp;
+
+ alloc = 0;
+ methods = NULL;
+ c = 0;
+
+ while (**pp != ';')
+ {
+ const char *p;
+ char *name;
+ debug_method_variant *variants;
+ unsigned int cvars;
+ unsigned int allocvars;
+ debug_type look_ahead_type;
+
+ p = strchr (*pp, ':');
+ if (p == NULL || p[1] != ':')
+ break;
+
+ /* FIXME: Some systems use something other than '$' here. */
+ if ((*pp)[0] != 'o' || (*pp)[1] != 'p' || (*pp)[2] != '$')
+ {
+ name = savestring (*pp, p - *pp);
+ *pp = p + 2;
+ }
+ else
+ {
+ /* This is a completely wierd case. In order to stuff in the
+ names that might contain colons (the usual name delimiter),
+ Mike Tiemann defined a different name format which is
+ signalled if the identifier is "op$". In that case, the
+ format is "op$::XXXX." where XXXX is the name. This is
+ used for names like "+" or "=". YUUUUUUUK! FIXME! */
+ *pp = p + 2;
+ for (p = *pp; *p != '.' && *p != '\0'; p++)
+ ;
+ if (*p != '.')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ name = savestring (*pp, p - *pp);
+ *pp = p + 1;
+ }
+
+ allocvars = 10;
+ variants = ((debug_method_variant *)
+ xmalloc (allocvars * sizeof *variants));
+ cvars = 0;
+
+ look_ahead_type = DEBUG_TYPE_NULL;
+
+ do
+ {
+ debug_type type;
+ boolean stub;
+ char *argtypes;
+ enum debug_visibility visibility;
+ boolean constp, volatilep, staticp;
+ bfd_vma voffset;
+ debug_type context;
+ const char *physname;
+ boolean varargs;
+
+ if (look_ahead_type != DEBUG_TYPE_NULL)
+ {
+ /* g++ version 1 kludge */
+ type = look_ahead_type;
+ look_ahead_type = DEBUG_TYPE_NULL;
+ }
+ else
+ {
+ type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ if (type == DEBUG_TYPE_NULL)
+ return false;
+ if (**pp != ':')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ }
+
+ ++*pp;
+ p = strchr (*pp, ';');
+ if (p == NULL)
+ {
+ bad_stab (orig);
+ return false;
+ }
+
+ stub = false;
+ if (debug_get_type_kind (dhandle, type) == DEBUG_KIND_METHOD
+ && debug_get_parameter_types (dhandle, type, &varargs) == NULL)
+ stub = true;
+
+ argtypes = savestring (*pp, p - *pp);
+ *pp = p + 1;
+
+ switch (**pp)
+ {
+ case '0':
+ visibility = DEBUG_VISIBILITY_PRIVATE;
+ break;
+ case '1':
+ visibility = DEBUG_VISIBILITY_PROTECTED;
+ break;
+ default:
+ visibility = DEBUG_VISIBILITY_PUBLIC;
+ break;
+ }
+ ++*pp;
+
+ constp = false;
+ volatilep = false;
+ switch (**pp)
+ {
+ case 'A':
+ /* Normal function. */
+ ++*pp;
+ break;
+ case 'B':
+ /* const member function. */
+ constp = true;
+ ++*pp;
+ break;
+ case 'C':
+ /* volatile member function. */
+ volatilep = true;
+ ++*pp;
+ break;
+ case 'D':
+ /* const volatile member function. */
+ constp = true;
+ volatilep = true;
+ ++*pp;
+ break;
+ case '*':
+ case '?':
+ case '.':
+ /* File compiled with g++ version 1; no information. */
+ break;
+ default:
+ warn_stab (orig, "const/volatile indicator missing");
+ break;
+ }
+
+ staticp = false;
+ switch (**pp)
+ {
+ case '*':
+ /* virtual member function, followed by index. The sign
+ bit is supposedly set to distinguish
+ pointers-to-methods from virtual function indicies. */
+ ++*pp;
+ voffset = parse_number (pp, (boolean *) NULL);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+ voffset &= 0x7fffffff;
+
+ if (**pp == ';' || *pp == '\0')
+ {
+ /* Must be g++ version 1. */
+ context = DEBUG_TYPE_NULL;
+ }
+ else
+ {
+ /* Figure out from whence this virtual function
+ came. It may belong to virtual function table of
+ one of its baseclasses. */
+ look_ahead_type = parse_stab_type (dhandle, info,
+ (const char *) NULL,
+ pp,
+ (debug_type **) NULL);
+ if (**pp == ':')
+ {
+ /* g++ version 1 overloaded methods. */
+ context = DEBUG_TYPE_NULL;
+ }
+ else
+ {
+ context = look_ahead_type;
+ look_ahead_type = DEBUG_TYPE_NULL;
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return false;
+ }
+ ++*pp;
+ }
+ }
+ break;
+
+ case '?':
+ /* static member function. */
+ ++*pp;
+ staticp = true;
+ voffset = 0;
+ context = DEBUG_TYPE_NULL;
+ if (strncmp (argtypes, name, strlen (name)) != 0)
+ stub = true;
+ break;
+
+ default:
+ warn_stab (orig, "member function type missing");
+ voffset = 0;
+ context = DEBUG_TYPE_NULL;
+ break;
+
+ case '.':
+ ++*pp;
+ voffset = 0;
+ context = DEBUG_TYPE_NULL;
+ break;
+ }
+
+ /* If the type is not a stub, then the argtypes string is
+ the physical name of the function. Otherwise the
+ argtypes string is the mangled form of the argument
+ types, and the full type and the physical name must be
+ extracted from them. */
+ if (! stub)
+ physname = argtypes;
+ else
+ {
+ debug_type class_type, return_type;
+
+ class_type = stab_find_type (dhandle, info, typenums);
+ if (class_type == DEBUG_TYPE_NULL)
+ return false;
+ return_type = debug_get_return_type (dhandle, type);
+ if (return_type == DEBUG_TYPE_NULL)
+ {
+ bad_stab (orig);
+ return false;
+ }
+ type = parse_stab_argtypes (dhandle, info, class_type, name,
+ tagname, return_type, argtypes,
+ constp, volatilep, &physname);
+ if (type == DEBUG_TYPE_NULL)
+ return false;
+ }
+
+ if (cvars + 1 >= allocvars)
+ {
+ allocvars += 10;
+ variants = ((debug_method_variant *)
+ xrealloc ((PTR) variants,
+ allocvars * sizeof *variants));
+ }
+
+ if (! staticp)
+ variants[cvars] = debug_make_method_variant (dhandle, physname,
+ type, visibility,
+ constp, volatilep,
+ voffset, context);
+ else
+ variants[cvars] = debug_make_static_method_variant (dhandle,
+ physname,
+ type,
+ visibility,
+ constp,
+ volatilep);
+ if (variants[cvars] == DEBUG_METHOD_VARIANT_NULL)
+ return false;
+
+ ++cvars;
+ }
+ while (**pp != ';' && **pp != '\0');
+
+ variants[cvars] = DEBUG_METHOD_VARIANT_NULL;
+
+ if (**pp != '\0')
+ ++*pp;
+
+ if (c + 1 >= alloc)
+ {
+ alloc += 10;
+ methods = ((debug_method *)
+ xrealloc ((PTR) methods, alloc * sizeof *methods));
+ }
+
+ methods[c] = debug_make_method (dhandle, name, variants);
+
+ ++c;
+ }
+
+ if (methods != NULL)
+ methods[c] = DEBUG_METHOD_NULL;
+
+ *retp = methods;
+
+ return true;
+}
+
+/* Parse a string representing argument types for a method. Stabs
+ tries to save space by packing argument types into a mangled
+ string. This string should give us enough information to extract
+ both argument types and the physical name of the function, given
+ the tag name. */
+
+static debug_type
+parse_stab_argtypes (dhandle, info, class_type, fieldname, tagname,
+ return_type, argtypes, constp, volatilep, pphysname)
+ PTR dhandle;
+ struct stab_handle *info;
+ debug_type class_type;
+ const char *fieldname;
+ const char *tagname;
+ debug_type return_type;
+ const char *argtypes;
+ boolean constp;
+ boolean volatilep;
+ const char **pphysname;
+{
+ boolean is_full_physname_constructor;
+ boolean is_constructor;
+ boolean is_destructor;
+ debug_type *args;
+ boolean varargs;
+
+ /* Constructors are sometimes handled specially. */
+ is_full_physname_constructor = ((argtypes[0] == '_'
+ && argtypes[1] == '_'
+ && (isdigit ((unsigned char) argtypes[2])
+ || argtypes[2] == 'Q'
+ || argtypes[2] == 't'))
+ || strncmp (argtypes, "__ct", 4) == 0);
+
+ is_constructor = (is_full_physname_constructor
+ || (tagname != NULL
+ && strcmp (fieldname, tagname) == 0));
+ is_destructor = ((argtypes[0] == '_'
+ && (argtypes[1] == '$' || argtypes[1] == '.')
+ && argtypes[2] == '_')
+ || strncmp (argtypes, "__dt", 4) == 0);
+
+ if (is_destructor || is_full_physname_constructor)
+ *pphysname = argtypes;
+ else
+ {
+ unsigned int len;
+ const char *const_prefix;
+ const char *volatile_prefix;
+ char buf[20];
+ unsigned int mangled_name_len;
+ char *physname;
+
+ len = tagname == NULL ? 0 : strlen (tagname);
+ const_prefix = constp ? "C" : "";
+ volatile_prefix = volatilep ? "V" : "";
+
+ if (len == 0)
+ sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
+ else if (tagname != NULL && strchr (tagname, '<') != NULL)
+ {
+ /* Template methods are fully mangled. */
+ sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
+ tagname = NULL;
+ len = 0;
+ }
+ else
+ sprintf (buf, "__%s%s%d", const_prefix, volatile_prefix, len);
+
+ mangled_name_len = ((is_constructor ? 0 : strlen (fieldname))
+ + strlen (buf)
+ + len
+ + strlen (argtypes)
+ + 1);
+
+ if (fieldname[0] == 'o'
+ && fieldname[1] == 'p'
+ && (fieldname[2] == '$' || fieldname[2] == '.'))
+ {
+ const char *opname;
+
+ opname = cplus_mangle_opname (fieldname + 3, 0);
+ if (opname == NULL)
+ {
+ fprintf (stderr, "No mangling for \"%s\"\n", fieldname);
+ return DEBUG_TYPE_NULL;
+ }
+ mangled_name_len += strlen (opname);
+ physname = (char *) xmalloc (mangled_name_len);
+ strncpy (physname, fieldname, 3);
+ strcpy (physname + 3, opname);
+ }
+ else
+ {
+ physname = (char *) xmalloc (mangled_name_len);
+ if (is_constructor)
+ physname[0] = '\0';
+ else
+ strcpy (physname, fieldname);
+ }
+
+ strcat (physname, buf);
+ if (tagname != NULL)
+ strcat (physname, tagname);
+ strcat (physname, argtypes);
+
+ *pphysname = physname;
+ }
+
+ if (*argtypes == '\0' || is_destructor)
+ {
+ args = (debug_type *) xmalloc (sizeof *args);
+ *args = NULL;
+ return debug_make_method_type (dhandle, return_type, class_type, args,
+ false);
+ }
+
+ args = stab_demangle_argtypes (dhandle, info, *pphysname, &varargs);
+ if (args == NULL)
+ return DEBUG_TYPE_NULL;
+
+ return debug_make_method_type (dhandle, return_type, class_type, args,
+ varargs);
+}
+
+/* The tail end of stabs for C++ classes that contain a virtual function
+ pointer contains a tilde, a %, and a type number.
+ The type number refers to the base class (possibly this class itself) which
+ contains the vtable pointer for the current class.
+
+ This function is called when we have parsed all the method declarations,
+ so we can look for the vptr base class info. */
+
+static boolean
+parse_stab_tilde_field (dhandle, info, pp, typenums, retvptrbase, retownvptr)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char **pp;
+ const int *typenums;
+ debug_type *retvptrbase;
+ boolean *retownvptr;
+{
+ const char *orig;
+ const char *hold;
+ int vtypenums[2];
+
+ *retvptrbase = DEBUG_TYPE_NULL;
+ *retownvptr = false;
+
+ orig = *pp;
+
+ /* If we are positioned at a ';', then skip it. */
+ if (**pp == ';')
+ ++*pp;
+
+ if (**pp != '~')
+ return true;
+
+ ++*pp;
+
+ if (**pp == '=' || **pp == '+' || **pp == '-')
+ {
+ /* Obsolete flags that used to indicate the presence of
+ constructors and/or destructors. */
+ ++*pp;
+ }
+
+ if (**pp != '%')
+ return true;
+
+ ++*pp;
+
+ hold = *pp;
+
+ /* The next number is the type number of the base class (possibly
+ our own class) which supplies the vtable for this class. */
+ if (! parse_stab_type_number (pp, vtypenums))
+ return false;
+
+ if (vtypenums[0] == typenums[0]
+ && vtypenums[1] == typenums[1])
+ *retownvptr = true;
+ else
+ {
+ debug_type vtype;
+ const char *p;
+
+ *pp = hold;
+
+ vtype = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ for (p = *pp; *p != ';' && *p != '\0'; p++)
+ ;
+ if (*p != ';')
+ {
+ bad_stab (orig);
+ return false;
+ }
+
+ *retvptrbase = vtype;
+
+ *pp = p + 1;
+ }
+
+ return true;
+}
+
+/* Read a definition of an array type. */
+
+static debug_type
+parse_stab_array_type (dhandle, info, pp, stringp)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char **pp;
+ boolean stringp;
+{
+ const char *orig;
+ const char *p;
+ int typenums[2];
+ debug_type index_type;
+ boolean adjustable;
+ bfd_signed_vma lower, upper;
+ debug_type element_type;
+
+ /* Format of an array type:
+ "ar<index type>;lower;upper;<array_contents_type>".
+ OS9000: "arlower,upper;<array_contents_type>".
+
+ Fortran adjustable arrays use Adigits or Tdigits for lower or upper;
+ for these, produce a type like float[][]. */
+
+ orig = *pp;
+
+ /* FIXME: gdb checks os9k_stabs here. */
+
+ /* If the index type is type 0, we take it as int. */
+ p = *pp;
+ if (! parse_stab_type_number (&p, typenums))
+ return DEBUG_TYPE_NULL;
+ if (typenums[0] == 0 && typenums[1] == 0 && **pp != '=')
+ {
+ index_type = debug_find_named_type (dhandle, "int");
+ if (index_type == DEBUG_TYPE_NULL)
+ {
+ index_type = debug_make_int_type (dhandle, 4, false);
+ if (index_type == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+ }
+ *pp = p;
+ }
+ else
+ {
+ index_type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ }
+
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ adjustable = false;
+
+ if (! isdigit ((unsigned char) **pp) && **pp != '-')
+ {
+ ++*pp;
+ adjustable = true;
+ }
+
+ lower = (bfd_signed_vma) parse_number (pp, (boolean *) NULL);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ if (! isdigit ((unsigned char) **pp) && **pp != '-')
+ {
+ ++*pp;
+ adjustable = true;
+ }
+
+ upper = (bfd_signed_vma) parse_number (pp, (boolean *) NULL);
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
+ ++*pp;
+
+ element_type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ if (element_type == DEBUG_TYPE_NULL)
+ return DEBUG_TYPE_NULL;
+
+ if (adjustable)
+ {
+ lower = 0;
+ upper = -1;
+ }
+
+ return debug_make_array_type (dhandle, element_type, index_type, lower,
+ upper, stringp);
+}
+
+/* This struct holds information about files we have seen using
+ N_BINCL. */
+
+struct bincl_file
+{
+ /* The next N_BINCL file. */
+ struct bincl_file *next;
+ /* The next N_BINCL on the stack. */
+ struct bincl_file *next_stack;
+ /* The file name. */
+ const char *name;
+ /* The hash value. */
+ bfd_vma hash;
+ /* The file index. */
+ unsigned int file;
+ /* The list of types defined in this file. */
+ struct stab_types *file_types;
+};
+
+/* Start a new N_BINCL file, pushing it onto the stack. */
+
+static void
+push_bincl (info, name, hash)
+ struct stab_handle *info;
+ const char *name;
+ bfd_vma hash;
+{
+ struct bincl_file *n;
+
+ n = (struct bincl_file *) xmalloc (sizeof *n);
+ n->next = info->bincl_list;
+ n->next_stack = info->bincl_stack;
+ n->name = name;
+ n->hash = hash;
+ n->file = info->files;
+ n->file_types = NULL;
+ info->bincl_list = n;
+ info->bincl_stack = n;
+
+ ++info->files;
+ info->file_types = ((struct stab_types **)
+ xrealloc ((PTR) info->file_types,
+ (info->files
+ * sizeof *info->file_types)));
+ info->file_types[n->file] = NULL;
+}
+
+/* Finish an N_BINCL file, at an N_EINCL, popping the name off the
+ stack. */
+
+static const char *
+pop_bincl (info)
+ struct stab_handle *info;
+{
+ struct bincl_file *o;
+
+ o = info->bincl_stack;
+ if (o == NULL)
+ return info->main_filename;
+ info->bincl_stack = o->next_stack;
+
+ o->file_types = info->file_types[o->file];
+
+ if (info->bincl_stack == NULL)
+ return info->main_filename;
+ return info->bincl_stack->name;
+}
+
+/* Handle an N_EXCL: get the types from the corresponding N_BINCL. */
+
+static boolean
+find_excl (info, name, hash)
+ struct stab_handle *info;
+ const char *name;
+ bfd_vma hash;
+{
+ struct bincl_file *l;
+
+ ++info->files;
+ info->file_types = ((struct stab_types **)
+ xrealloc ((PTR) info->file_types,
+ (info->files
+ * sizeof *info->file_types)));
+
+ for (l = info->bincl_list; l != NULL; l = l->next)
+ if (l->hash == hash && strcmp (l->name, name) == 0)
+ break;
+ if (l == NULL)
+ {
+ warn_stab (name, "Undefined N_EXCL");
+ info->file_types[info->files - 1] = NULL;
+ return true;
+ }
+
+ info->file_types[info->files - 1] = l->file_types;
+
+ return true;
+}
+
+/* Handle a variable definition. gcc emits variable definitions for a
+ block before the N_LBRAC, so we must hold onto them until we see
+ it. The SunPRO compiler emits variable definitions after the
+ N_LBRAC, so we can call debug_record_variable immediately. */
+
+static boolean
+stab_record_variable (dhandle, info, name, type, kind, val)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char *name;
+ debug_type type;
+ enum debug_var_kind kind;
+ bfd_vma val;
+{
+ struct stab_pending_var *v;
+
+ if ((kind == DEBUG_GLOBAL || kind == DEBUG_STATIC)
+ || ! info->within_function
+ || (info->gcc_compiled == 0 && info->n_opt_found))
+ return debug_record_variable (dhandle, name, type, kind, val);
+
+ v = (struct stab_pending_var *) xmalloc (sizeof *v);
+ memset (v, 0, sizeof *v);
+
+ v->next = info->pending;
+ v->name = name;
+ v->type = type;
+ v->kind = kind;
+ v->val = val;
+ info->pending = v;
+
+ return true;
+}
+
+/* Emit pending variable definitions. This is called after we see the
+ N_LBRAC that starts the block. */
+
+static boolean
+stab_emit_pending_vars (dhandle, info)
+ PTR dhandle;
+ struct stab_handle *info;
+{
+ struct stab_pending_var *v;
+
+ v = info->pending;
+ while (v != NULL)
+ {
+ struct stab_pending_var *next;
+
+ if (! debug_record_variable (dhandle, v->name, v->type, v->kind, v->val))
+ return false;
+
+ next = v->next;
+ free (v);
+ v = next;
+ }
+
+ info->pending = NULL;
+
+ return true;
+}
+
+/* Find the slot for a type in the database. */
+
+static debug_type *
+stab_find_slot (info, typenums)
+ struct stab_handle *info;
+ const int *typenums;
+{
+ int filenum;
+ int index;
+ struct stab_types **ps;
+
+ filenum = typenums[0];
+ index = typenums[1];
+
+ if (filenum < 0 || (unsigned int) filenum >= info->files)
+ {
+ fprintf (stderr, "Type file number %d out of range\n", filenum);
+ return NULL;
+ }
+ if (index < 0)
+ {
+ fprintf (stderr, "Type index number %d out of range\n", index);
+ return NULL;
+ }
+
+ ps = info->file_types + filenum;
+
+ while (index >= STAB_TYPES_SLOTS)
+ {
+ if (*ps == NULL)
+ {
+ *ps = (struct stab_types *) xmalloc (sizeof **ps);
+ memset (*ps, 0, sizeof **ps);
+ }
+ ps = &(*ps)->next;
+ index -= STAB_TYPES_SLOTS;
+ }
+ if (*ps == NULL)
+ {
+ *ps = (struct stab_types *) xmalloc (sizeof **ps);
+ memset (*ps, 0, sizeof **ps);
+ }
+
+ return (*ps)->types + index;
+}
+
+/* Find a type given a type number. If the type has not been
+ allocated yet, create an indirect type. */
+
+static debug_type
+stab_find_type (dhandle, info, typenums)
+ PTR dhandle;
+ struct stab_handle *info;
+ const int *typenums;
+{
+ debug_type *slot;
+
+ if (typenums[0] == 0 && typenums[1] < 0)
+ {
+ /* A negative type number indicates an XCOFF builtin type. */
+ return stab_xcoff_builtin_type (dhandle, info, typenums[1]);
+ }
+
+ slot = stab_find_slot (info, typenums);
+ if (slot == NULL)
+ return DEBUG_TYPE_NULL;
+
+ if (*slot == DEBUG_TYPE_NULL)
+ return debug_make_indirect_type (dhandle, slot, (const char *) NULL);
+
+ return *slot;
+}
+
+/* Record that a given type number refers to a given type. */
+
+static boolean
+stab_record_type (dhandle, info, typenums, type)
+ PTR dhandle;
+ struct stab_handle *info;
+ const int *typenums;
+ debug_type type;
+{
+ debug_type *slot;
+
+ slot = stab_find_slot (info, typenums);
+ if (slot == NULL)
+ return false;
+
+ /* gdb appears to ignore type redefinitions, so we do as well. */
+
+ *slot = type;
+
+ return true;
+}
+
+/* Return an XCOFF builtin type. */
+
+static debug_type
+stab_xcoff_builtin_type (dhandle, info, typenum)
+ PTR dhandle;
+ struct stab_handle *info;
+ int typenum;
+{
+ debug_type rettype;
+ const char *name;
+
+ if (typenum >= 0 || typenum < -XCOFF_TYPE_COUNT)
+ {
+ fprintf (stderr, "Unrecognized XCOFF type %d\n", typenum);
+ return DEBUG_TYPE_NULL;
+ }
+ if (info->xcoff_types[-typenum] != NULL)
+ return info->xcoff_types[-typenum];
+
+ switch (-typenum)
+ {
+ case 1:
+ /* The size of this and all the other types are fixed, defined
+ by the debugging format. */
+ name = "int";
+ rettype = debug_make_int_type (dhandle, 4, false);
+ break;
+ case 2:
+ name = "char";
+ rettype = debug_make_int_type (dhandle, 1, false);
+ break;
+ case 3:
+ name = "short";
+ rettype = debug_make_int_type (dhandle, 2, false);
+ break;
+ case 4:
+ name = "long";
+ rettype = debug_make_int_type (dhandle, 4, false);
+ break;
+ case 5:
+ name = "unsigned char";
+ rettype = debug_make_int_type (dhandle, 1, true);
+ break;
+ case 6:
+ name = "signed char";
+ rettype = debug_make_int_type (dhandle, 1, false);
+ break;
+ case 7:
+ name = "unsigned short";
+ rettype = debug_make_int_type (dhandle, 2, true);
+ break;
+ case 8:
+ name = "unsigned int";
+ rettype = debug_make_int_type (dhandle, 4, true);
+ break;
+ case 9:
+ name = "unsigned";
+ rettype = debug_make_int_type (dhandle, 4, true);
+ case 10:
+ name = "unsigned long";
+ rettype = debug_make_int_type (dhandle, 4, true);
+ break;
+ case 11:
+ name = "void";
+ rettype = debug_make_void_type (dhandle);
+ break;
+ case 12:
+ /* IEEE single precision (32 bit). */
+ name = "float";
+ rettype = debug_make_float_type (dhandle, 4);
+ break;
+ case 13:
+ /* IEEE double precision (64 bit). */
+ name = "double";
+ rettype = debug_make_float_type (dhandle, 8);
+ break;
+ case 14:
+ /* This is an IEEE double on the RS/6000, and different machines
+ with different sizes for "long double" should use different
+ negative type numbers. See stabs.texinfo. */
+ name = "long double";
+ rettype = debug_make_float_type (dhandle, 8);
+ break;
+ case 15:
+ name = "integer";
+ rettype = debug_make_int_type (dhandle, 4, false);
+ break;
+ case 16:
+ name = "boolean";
+ rettype = debug_make_bool_type (dhandle, 4);
+ break;
+ case 17:
+ name = "short real";
+ rettype = debug_make_float_type (dhandle, 4);
+ break;
+ case 18:
+ name = "real";
+ rettype = debug_make_float_type (dhandle, 8);
+ break;
+ case 19:
+ /* FIXME */
+ name = "stringptr";
+ rettype = NULL;
+ break;
+ case 20:
+ /* FIXME */
+ name = "character";
+ rettype = debug_make_int_type (dhandle, 1, true);
+ break;
+ case 21:
+ name = "logical*1";
+ rettype = debug_make_bool_type (dhandle, 1);
+ break;
+ case 22:
+ name = "logical*2";
+ rettype = debug_make_bool_type (dhandle, 2);
+ break;
+ case 23:
+ name = "logical*4";
+ rettype = debug_make_bool_type (dhandle, 4);
+ break;
+ case 24:
+ name = "logical";
+ rettype = debug_make_bool_type (dhandle, 4);
+ break;
+ case 25:
+ /* Complex type consisting of two IEEE single precision values. */
+ name = "complex";
+ rettype = debug_make_complex_type (dhandle, 8);
+ break;
+ case 26:
+ /* Complex type consisting of two IEEE double precision values. */
+ name = "double complex";
+ rettype = debug_make_complex_type (dhandle, 16);
+ break;
+ case 27:
+ name = "integer*1";
+ rettype = debug_make_int_type (dhandle, 1, false);
+ break;
+ case 28:
+ name = "integer*2";
+ rettype = debug_make_int_type (dhandle, 2, false);
+ break;
+ case 29:
+ name = "integer*4";
+ rettype = debug_make_int_type (dhandle, 4, false);
+ break;
+ case 30:
+ /* FIXME */
+ name = "wchar";
+ rettype = debug_make_int_type (dhandle, 2, false);
+ break;
+ case 31:
+ name = "long long";
+ rettype = debug_make_int_type (dhandle, 8, false);
+ break;
+ case 32:
+ name = "unsigned long long";
+ rettype = debug_make_int_type (dhandle, 8, true);
+ break;
+ case 33:
+ name = "logical*8";
+ rettype = debug_make_bool_type (dhandle, 8);
+ break;
+ case 34:
+ name = "integer*8";
+ rettype = debug_make_int_type (dhandle, 8, false);
+ break;
+ default:
+ abort ();
+ }
+
+ rettype = debug_name_type (dhandle, name, rettype);
+
+ info->xcoff_types[-typenum] = rettype;
+
+ return rettype;
+}
+
+/* Find or create a tagged type. */
+
+static debug_type
+stab_find_tagged_type (dhandle, info, p, len, kind)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char *p;
+ int len;
+ enum debug_type_kind kind;
+{
+ char *name;
+ debug_type dtype;
+ struct stab_tag *st;
+
+ name = savestring (p, len);
+
+ /* We pass DEBUG_KIND_ILLEGAL because we want all tags in the same
+ namespace. This is right for C, and I don't know how to handle
+ other languages. FIXME. */
+ dtype = debug_find_tagged_type (dhandle, name, DEBUG_KIND_ILLEGAL);
+ if (dtype != DEBUG_TYPE_NULL)
+ {
+ free (name);
+ return dtype;
+ }
+
+ /* We need to allocate an entry on the undefined tag list. */
+ for (st = info->tags; st != NULL; st = st->next)
+ {
+ if (st->name[0] == name[0]
+ && strcmp (st->name, name) == 0)
+ {
+ if (st->kind == DEBUG_KIND_ILLEGAL)
+ st->kind = kind;
+ free (name);
+ break;
+ }
+ }
+ if (st == NULL)
+ {
+ st = (struct stab_tag *) xmalloc (sizeof *st);
+ memset (st, 0, sizeof *st);
+
+ st->next = info->tags;
+ st->name = name;
+ st->kind = kind;
+ st->slot = DEBUG_TYPE_NULL;
+ st->type = debug_make_indirect_type (dhandle, &st->slot, name);
+ info->tags = st;
+ }
+
+ return st->type;
+}
+
+/* In order to get the correct argument types for a stubbed method, we
+ need to extract the argument types from a C++ mangled string.
+ Since the argument types can refer back to the return type, this
+ means that we must demangle the entire physical name. In gdb this
+ is done by calling cplus_demangle and running the results back
+ through the C++ expression parser. Since we have no expression
+ parser, we must duplicate much of the work of cplus_demangle here.
+
+ We assume that GNU style demangling is used, since this is only
+ done for method stubs, and only g++ should output that form of
+ debugging information. */
+
+/* This structure is used to hold a pointer to type information which
+ demangling a string. */
+
+struct stab_demangle_typestring
+{
+ /* The start of the type. This is not null terminated. */
+ const char *typestring;
+ /* The length of the type. */
+ unsigned int len;
+};
+
+/* This structure is used to hold information while demangling a
+ string. */
+
+struct stab_demangle_info
+{
+ /* The debugging information handle. */
+ PTR dhandle;
+ /* The stab information handle. */
+ struct stab_handle *info;
+ /* The array of arguments we are building. */
+ debug_type *args;
+ /* Whether the method takes a variable number of arguments. */
+ boolean varargs;
+ /* The array of types we have remembered. */
+ struct stab_demangle_typestring *typestrings;
+ /* The number of typestrings. */
+ unsigned int typestring_count;
+ /* The number of typestring slots we have allocated. */
+ unsigned int typestring_alloc;
+};
+
+static void stab_bad_demangle PARAMS ((const char *));
+static unsigned int stab_demangle_count PARAMS ((const char **));
+static boolean stab_demangle_get_count
+ PARAMS ((const char **, unsigned int *));
+static boolean stab_demangle_prefix
+ PARAMS ((struct stab_demangle_info *, const char **));
+static boolean stab_demangle_function_name
+ PARAMS ((struct stab_demangle_info *, const char **, const char *));
+static boolean stab_demangle_signature
+ PARAMS ((struct stab_demangle_info *, const char **));
+static boolean stab_demangle_qualified
+ PARAMS ((struct stab_demangle_info *, const char **, debug_type *));
+static boolean stab_demangle_template
+ PARAMS ((struct stab_demangle_info *, const char **));
+static boolean stab_demangle_class
+ PARAMS ((struct stab_demangle_info *, const char **, const char **));
+static boolean stab_demangle_args
+ PARAMS ((struct stab_demangle_info *, const char **, debug_type **,
+ boolean *));
+static boolean stab_demangle_arg
+ PARAMS ((struct stab_demangle_info *, const char **, debug_type **,
+ unsigned int *, unsigned int *));
+static boolean stab_demangle_type
+ PARAMS ((struct stab_demangle_info *, const char **, debug_type *));
+static boolean stab_demangle_fund_type
+ PARAMS ((struct stab_demangle_info *, const char **, debug_type *));
+static boolean stab_demangle_remember_type
+ PARAMS ((struct stab_demangle_info *, const char *, int));
+
+/* Warn about a bad demangling. */
+
+static void
+stab_bad_demangle (s)
+ const char *s;
+{
+ fprintf (stderr, "bad mangled name `%s'\n", s);
+}
+
+/* Get a count from a stab string. */
+
+static unsigned int
+stab_demangle_count (pp)
+ const char **pp;
+{
+ unsigned int count;
+
+ count = 0;
+ while (isdigit ((unsigned char) **pp))
+ {
+ count *= 10;
+ count += **pp - '0';
+ ++*pp;
+ }
+ return count;
+}
+
+/* Require a count in a string. The count may be multiple digits, in
+ which case it must end in an underscore. */
+
+static boolean
+stab_demangle_get_count (pp, pi)
+ const char **pp;
+ unsigned int *pi;
+{
+ if (! isdigit ((unsigned char) **pp))
+ return false;
+
+ *pi = **pp - '0';
+ ++*pp;
+ if (isdigit ((unsigned char) **pp))
+ {
+ unsigned int count;
+ const char *p;
+
+ count = *pi;
+ p = *pp;
+ do
+ {
+ count *= 10;
+ count += *p - '0';
+ ++p;
+ }
+ while (isdigit ((unsigned char) *p));
+ if (*p == '_')
+ {
+ *pp = p + 1;
+ *pi = count;
+ }
+ }
+
+ return true;
+}
+
+/* This function demangles a physical name, returning a NULL
+ terminated array of argument types. */
+
+static debug_type *
+stab_demangle_argtypes (dhandle, info, physname, pvarargs)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char *physname;
+ boolean *pvarargs;
+{
+ struct stab_demangle_info minfo;
+
+ minfo.dhandle = dhandle;
+ minfo.info = info;
+ minfo.args = NULL;
+ minfo.varargs = false;
+ minfo.typestring_alloc = 10;
+ minfo.typestrings = ((struct stab_demangle_typestring *)
+ xmalloc (minfo.typestring_alloc
+ * sizeof *minfo.typestrings));
+ minfo.typestring_count = 0;
+
+ /* cplus_demangle checks for special GNU mangled forms, but we can't
+ see any of them in mangled method argument types. */
+
+ if (! stab_demangle_prefix (&minfo, &physname))
+ goto error_return;
+
+ if (*physname != '\0')
+ {
+ if (! stab_demangle_signature (&minfo, &physname))
+ goto error_return;
+ }
+
+ free (minfo.typestrings);
+ minfo.typestrings = NULL;
+
+ if (minfo.args == NULL)
+ fprintf (stderr, "no argument types in mangled string\n");
+
+ *pvarargs = minfo.varargs;
+ return minfo.args;
+
+ error_return:
+ if (minfo.typestrings != NULL)
+ free (minfo.typestrings);
+ return NULL;
+}
+
+/* Demangle the prefix of the mangled name. */
+
+static boolean
+stab_demangle_prefix (minfo, pp)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+{
+ const char *scan;
+ unsigned int i;
+
+ /* cplus_demangle checks for global constructors and destructors,
+ but we can't see them in mangled argument types. */
+
+ /* Look for `__'. */
+ scan = *pp;
+ do
+ {
+ scan = strchr (scan, '_');
+ }
+ while (scan != NULL && *++scan != '_');
+
+ if (scan == NULL)
+ {
+ stab_bad_demangle (*pp);
+ return false;
+ }
+
+ --scan;
+
+ /* We found `__'; move ahead to the last contiguous `__' pair. */
+ i = strspn (scan, "_");
+ if (i > 2)
+ scan += i - 2;
+
+ if (scan == *pp
+ && (isdigit ((unsigned char) scan[2])
+ || scan[2] == 'Q'
+ || scan[2] == 't'))
+ {
+ /* This is a GNU style constructor name. */
+ *pp = scan + 2;
+ return true;
+ }
+ else if (scan == *pp
+ && ! isdigit ((unsigned char) scan[2])
+ && scan[2] != 't')
+ {
+ /* Look for the `__' that separates the prefix from the
+ signature. */
+ while (*scan == '_')
+ ++scan;
+ scan = strstr (scan, "__");
+ if (scan == NULL || scan[2] == '\0')
+ {
+ stab_bad_demangle (*pp);
+ return false;
+ }
+
+ return stab_demangle_function_name (minfo, pp, scan);
+ }
+ else if (scan[2] != '\0')
+ {
+ /* The name doesn't start with `__', but it does contain `__'. */
+ return stab_demangle_function_name (minfo, pp, scan);
+ }
+ else
+ {
+ stab_bad_demangle (*pp);
+ return false;
+ }
+ /*NOTREACHED*/
+}
+
+/* Demangle a function name prefix. The scan argument points to the
+ double underscore which separates the function name from the
+ signature. */
+
+static boolean
+stab_demangle_function_name (minfo, pp, scan)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+ const char *scan;
+{
+ const char *name;
+
+ /* The string from *pp to scan is the name of the function. We
+ don't care about the name, since we just looking for argument
+ types. However, for conversion operators, the name may include a
+ type which we must remember in order to handle backreferences. */
+
+ name = *pp;
+ *pp = scan + 2;
+
+ if (*pp - name >= 5
+ && strncmp (name, "type", 4) == 0
+ && (name[4] == '$' || name[4] == '.'))
+ {
+ const char *tem;
+
+ /* This is a type conversion operator. */
+ tem = name + 5;
+ if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL))
+ return false;
+ }
+ else if (name[0] == '_'
+ && name[1] == '_'
+ && name[2] == 'o'
+ && name[3] == 'p')
+ {
+ const char *tem;
+
+ /* This is a type conversion operator. */
+ tem = name + 4;
+ if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL))
+ return false;
+ }
+
+ return true;
+}
+
+/* Demangle the signature. This is where the argument types are
+ found. */
+
+static boolean
+stab_demangle_signature (minfo, pp)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+{
+ const char *orig;
+ boolean expect_func, func_done;
+ const char *hold;
+
+ orig = *pp;
+
+ expect_func = false;
+ func_done = false;
+ hold = NULL;
+
+ while (**pp != '\0')
+ {
+ switch (**pp)
+ {
+ case 'Q':
+ hold = *pp;
+ if (! stab_demangle_qualified (minfo, pp, (debug_type *) NULL)
+ || ! stab_demangle_remember_type (minfo, hold, *pp - hold))
+ return false;
+ expect_func = true;
+ hold = NULL;
+ break;
+
+ case 'S':
+ /* Static member function. FIXME: Can this happen? */
+ if (hold == NULL)
+ hold = *pp;
+ ++*pp;
+ break;
+
+ case 'C':
+ /* Const member function. */
+ if (hold == NULL)
+ hold = *pp;
+ ++*pp;
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (hold == NULL)
+ hold = *pp;
+ if (! stab_demangle_class (minfo, pp, (const char **) NULL)
+ || ! stab_demangle_remember_type (minfo, hold, *pp - hold))
+ return false;
+ expect_func = true;
+ hold = NULL;
+ break;
+
+ case 'F':
+ /* Function. I don't know if this actually happens with g++
+ output. */
+ hold = NULL;
+ func_done = true;
+ ++*pp;
+ if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
+ return false;
+ break;
+
+ case 't':
+ /* Template. */
+ if (hold == NULL)
+ hold = *pp;
+ if (! stab_demangle_template (minfo, pp)
+ || ! stab_demangle_remember_type (minfo, hold, *pp - hold))
+ return false;
+ hold = NULL;
+ expect_func = true;
+ break;
+
+ case '_':
+ /* At the outermost level, we cannot have a return type
+ specified, so if we run into another '_' at this point we
+ are dealing with a mangled name that is either bogus, or
+ has been mangled by some algorithm we don't know how to
+ deal with. So just reject the entire demangling. */
+ stab_bad_demangle (orig);
+ return false;
+
+ default:
+ /* Assume we have stumbled onto the first outermost function
+ argument token, and start processing args. */
+ func_done = true;
+ if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
+ return false;
+ break;
+ }
+
+ if (expect_func)
+ {
+ func_done = true;
+ if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
+ return false;
+ }
+ }
+
+ if (! func_done)
+ {
+ /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and
+ bar__3fooi is 'foo::bar(int)'. We get here when we find the
+ first case, and need to ensure that the '(void)' gets added
+ to the current declp. */
+ if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
+ return false;
+ }
+
+ return true;
+}
+
+/* Demangle a qualified name, such as "Q25Outer5Inner" which is the
+ mangled form of "Outer::Inner". */
+
+static boolean
+stab_demangle_qualified (minfo, pp, ptype)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+ debug_type *ptype;
+{
+ const char *orig;
+ const char *p;
+ unsigned int qualifiers;
+ debug_type context;
+
+ orig = *pp;
+
+ switch ((*pp)[1])
+ {
+ case '_':
+ /* GNU mangled name with more than 9 classes. The count is
+ preceded by an underscore (to distinguish it from the <= 9
+ case) and followed by an underscore. */
+ p = *pp + 2;
+ if (! isdigit ((unsigned char) *p) || *p == '0')
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ qualifiers = atoi (p);
+ while (isdigit ((unsigned char) *p))
+ ++p;
+ if (*p != '_')
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ *pp = p + 1;
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ qualifiers = (*pp)[1] - '0';
+ /* Skip an optional underscore after the count. */
+ if ((*pp)[2] == '_')
+ ++*pp;
+ *pp += 2;
+ break;
+
+ case '0':
+ default:
+ stab_bad_demangle (orig);
+ return false;
+ }
+
+ context = DEBUG_TYPE_NULL;
+
+ /* Pick off the names. */
+ while (qualifiers-- > 0)
+ {
+ if (**pp == '_')
+ ++*pp;
+ if (**pp == 't')
+ {
+ /* FIXME: I don't know how to handle the ptype != NULL case
+ here. */
+ if (! stab_demangle_template (minfo, pp))
+ return false;
+ }
+ else
+ {
+ unsigned int len;
+
+ len = stab_demangle_count (pp);
+ if (strlen (*pp) < len)
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+
+ if (ptype != NULL)
+ {
+ const debug_field *fields;
+
+ fields = NULL;
+ if (context != DEBUG_TYPE_NULL)
+ fields = debug_get_fields (minfo->dhandle, context);
+
+ context = DEBUG_TYPE_NULL;
+
+ if (fields != NULL)
+ {
+ char *name;
+
+ /* Try to find the type by looking through the
+ fields of context until we find a field with the
+ same type. This ought to work for a class
+ defined within a class, but it won't work for,
+ e.g., an enum defined within a class. stabs does
+ not give us enough information to figure out the
+ latter case. */
+
+ name = savestring (*pp, len);
+
+ for (; *fields != DEBUG_FIELD_NULL; fields++)
+ {
+ debug_type ft;
+ const char *dn;
+
+ ft = debug_get_field_type (minfo->dhandle, *fields);
+ if (ft == NULL)
+ return false;
+ dn = debug_get_type_name (minfo->dhandle, ft);
+ if (dn != NULL && strcmp (dn, name) == 0)
+ {
+ context = ft;
+ break;
+ }
+ }
+
+ free (name);
+ }
+
+ if (context == DEBUG_TYPE_NULL)
+ {
+ /* We have to fall back on finding the type by name.
+ If there are more types to come, then this must
+ be a class. Otherwise, it could be anything. */
+
+ if (qualifiers == 0)
+ {
+ char *name;
+
+ name = savestring (*pp, len);
+ context = debug_find_named_type (minfo->dhandle,
+ name);
+ free (name);
+ }
+
+ if (context == DEBUG_TYPE_NULL)
+ {
+ context = stab_find_tagged_type (minfo->dhandle,
+ minfo->info,
+ *pp, len,
+ (qualifiers == 0
+ ? DEBUG_KIND_ILLEGAL
+ : DEBUG_KIND_CLASS));
+ if (context == DEBUG_TYPE_NULL)
+ return false;
+ }
+ }
+ }
+
+ *pp += len;
+ }
+ }
+
+ if (ptype != NULL)
+ *ptype = context;
+
+ return true;
+}
+
+/* Demangle a template. */
+
+static boolean
+stab_demangle_template (minfo, pp)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+{
+ const char *orig;
+ unsigned int r, i;
+
+ orig = *pp;
+
+ ++*pp;
+
+ /* Skip the template name. */
+ r = stab_demangle_count (pp);
+ if (r == 0 || strlen (*pp) < r)
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ *pp += r;
+
+ /* Get the size of the parameter list. */
+ if (stab_demangle_get_count (pp, &r) == 0)
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+
+ for (i = 0; i < r; i++)
+ {
+ if (**pp == 'Z')
+ {
+ /* This is a type parameter. */
+ ++*pp;
+ if (! stab_demangle_type (minfo, pp, (debug_type *) NULL))
+ return false;
+ }
+ else
+ {
+ const char *old_p;
+ boolean pointerp, realp, integralp, charp, boolp;
+ boolean done;
+
+ old_p = *pp;
+ pointerp = false;
+ realp = false;
+ integralp = false;
+ charp = false;
+ boolp = false;
+ done = false;
+
+ /* This is a value parameter. */
+
+ if (! stab_demangle_type (minfo, pp, (debug_type *) NULL))
+ return false;
+
+ while (*old_p != '\0' && ! done)
+ {
+ switch (*old_p)
+ {
+ case 'P':
+ case 'p':
+ case 'R':
+ pointerp = true;
+ done = true;
+ break;
+ case 'C': /* Const. */
+ case 'S': /* Signed. */
+ case 'U': /* Unsigned. */
+ case 'V': /* Volatile. */
+ case 'F': /* Function. */
+ case 'M': /* Member function. */
+ case 'O': /* ??? */
+ ++old_p;
+ break;
+ case 'Q': /* Qualified name. */
+ integralp = true;
+ done = true;
+ break;
+ case 'T': /* Remembered type. */
+ abort ();
+ case 'v': /* Void. */
+ abort ();
+ case 'x': /* Long long. */
+ case 'l': /* Long. */
+ case 'i': /* Int. */
+ case 's': /* Short. */
+ case 'w': /* Wchar_t. */
+ integralp = true;
+ done = true;
+ break;
+ case 'b': /* Bool. */
+ boolp = true;
+ done = true;
+ break;
+ case 'c': /* Char. */
+ charp = true;
+ done = true;
+ break;
+ case 'r': /* Long double. */
+ case 'd': /* Double. */
+ case 'f': /* Float. */
+ realp = true;
+ done = true;
+ break;
+ default:
+ /* Assume it's a user defined integral type. */
+ integralp = true;
+ done = true;
+ break;
+ }
+ }
+
+ if (integralp)
+ {
+ if (**pp == 'm')
+ ++*pp;
+ while (isdigit ((unsigned char) **pp))
+ ++*pp;
+ }
+ else if (charp)
+ {
+ unsigned int val;
+
+ if (**pp == 'm')
+ ++*pp;
+ val = stab_demangle_count (pp);
+ if (val == 0)
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ }
+ else if (boolp)
+ {
+ unsigned int val;
+
+ val = stab_demangle_count (pp);
+ if (val != 0 && val != 1)
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ }
+ else if (realp)
+ {
+ if (**pp == 'm')
+ ++*pp;
+ while (isdigit ((unsigned char) **pp))
+ ++*pp;
+ if (**pp == '.')
+ {
+ ++*pp;
+ while (isdigit ((unsigned char) **pp))
+ ++*pp;
+ }
+ if (**pp == 'e')
+ {
+ ++*pp;
+ while (isdigit ((unsigned char) **pp))
+ ++*pp;
+ }
+ }
+ else if (pointerp)
+ {
+ unsigned int len;
+
+ if (! stab_demangle_get_count (pp, &len))
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ *pp += len;
+ }
+ }
+ }
+
+ return true;
+}
+
+/* Demangle a class name. */
+
+static boolean
+stab_demangle_class (minfo, pp, pstart)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+ const char **pstart;
+{
+ const char *orig;
+ unsigned int n;
+
+ orig = *pp;
+
+ n = stab_demangle_count (pp);
+ if (strlen (*pp) < n)
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+
+ if (pstart != NULL)
+ *pstart = *pp;
+
+ *pp += n;
+
+ return true;
+}
+
+/* Demangle function arguments. If the pargs argument is not NULL, it
+ is set to a NULL terminated array holding the arguments. */
+
+static boolean
+stab_demangle_args (minfo, pp, pargs, pvarargs)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+ debug_type **pargs;
+ boolean *pvarargs;
+{
+ const char *orig;
+ unsigned int alloc, count;
+
+ orig = *pp;
+
+ alloc = 10;
+ if (pargs != NULL)
+ {
+ *pargs = (debug_type *) xmalloc (alloc * sizeof **pargs);
+ *pvarargs = false;
+ }
+ count = 0;
+
+ while (**pp != '_' && **pp != '\0' && **pp != 'e')
+ {
+ if (**pp == 'N' || **pp == 'T')
+ {
+ char temptype;
+ unsigned int r, t;
+
+ temptype = **pp;
+ ++*pp;
+
+ if (temptype == 'T')
+ r = 1;
+ else
+ {
+ if (! stab_demangle_get_count (pp, &r))
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ }
+
+ if (! stab_demangle_get_count (pp, &t))
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+
+ if (t >= minfo->typestring_count)
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ while (r-- > 0)
+ {
+ const char *tem;
+
+ tem = minfo->typestrings[t].typestring;
+ if (! stab_demangle_arg (minfo, &tem, pargs, &count, &alloc))
+ return false;
+ }
+ }
+ else
+ {
+ if (! stab_demangle_arg (minfo, pp, pargs, &count, &alloc))
+ return false;
+ }
+ }
+
+ if (pargs != NULL)
+ (*pargs)[count] = DEBUG_TYPE_NULL;
+
+ if (**pp == 'e')
+ {
+ if (pargs != NULL)
+ *pvarargs = true;
+ ++*pp;
+ }
+
+ return true;
+}
+
+/* Demangle a single argument. */
+
+static boolean
+stab_demangle_arg (minfo, pp, pargs, pcount, palloc)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+ debug_type **pargs;
+ unsigned int *pcount;
+ unsigned int *palloc;
+{
+ const char *start;
+ debug_type type;
+
+ start = *pp;
+ if (! stab_demangle_type (minfo, pp,
+ pargs == NULL ? (debug_type *) NULL : &type)
+ || ! stab_demangle_remember_type (minfo, start, *pp - start))
+ return false;
+
+ if (pargs != NULL)
+ {
+ if (type == DEBUG_TYPE_NULL)
+ return false;
+
+ if (*pcount + 1 >= *palloc)
+ {
+ *palloc += 10;
+ *pargs = ((debug_type *)
+ xrealloc (*pargs, *palloc * sizeof **pargs));
+ }
+ (*pargs)[*pcount] = type;
+ ++*pcount;
+ }
+
+ return true;
+}
+
+/* Demangle a type. If the ptype argument is not NULL, *ptype is set
+ to the newly allocated type. */
+
+static boolean
+stab_demangle_type (minfo, pp, ptype)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+ debug_type *ptype;
+{
+ const char *orig;
+
+ orig = *pp;
+
+ switch (**pp)
+ {
+ case 'P':
+ case 'p':
+ /* A pointer type. */
+ ++*pp;
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return false;
+ if (ptype != NULL)
+ *ptype = debug_make_pointer_type (minfo->dhandle, *ptype);
+ break;
+
+ case 'R':
+ /* A reference type. */
+ ++*pp;
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return false;
+ if (ptype != NULL)
+ *ptype = debug_make_reference_type (minfo->dhandle, *ptype);
+ break;
+
+ case 'A':
+ /* An array. */
+ {
+ unsigned long high;
+
+ ++*pp;
+ high = 0;
+ while (**pp != '\0' && **pp != '_')
+ {
+ if (! isdigit ((unsigned char) **pp))
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ high *= 10;
+ high += **pp - '0';
+ ++*pp;
+ }
+ if (**pp != '_')
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ ++*pp;
+
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return false;
+ if (ptype != NULL)
+ {
+ debug_type int_type;
+
+ int_type = debug_find_named_type (minfo->dhandle, "int");
+ if (int_type == NULL)
+ int_type = debug_make_int_type (minfo->dhandle, 4, false);
+ *ptype = debug_make_array_type (minfo->dhandle, *ptype, int_type,
+ 0, high, false);
+ }
+ }
+ break;
+
+ case 'T':
+ /* A back reference to a remembered type. */
+ {
+ unsigned int i;
+ const char *p;
+
+ ++*pp;
+ if (! stab_demangle_get_count (pp, &i))
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ if (i >= minfo->typestring_count)
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ p = minfo->typestrings[i].typestring;
+ if (! stab_demangle_type (minfo, &p, ptype))
+ return false;
+ }
+ break;
+
+ case 'F':
+ /* A function. */
+ {
+ debug_type *args;
+ boolean varargs;
+
+ ++*pp;
+ if (! stab_demangle_args (minfo, pp,
+ (ptype == NULL
+ ? (debug_type **) NULL
+ : &args),
+ (ptype == NULL
+ ? (boolean *) NULL
+ : &varargs)))
+ return false;
+ if (**pp != '_')
+ {
+ /* cplus_demangle will accept a function without a return
+ type, but I don't know when that will happen, or what
+ to do if it does. */
+ stab_bad_demangle (orig);
+ return false;
+ }
+ ++*pp;
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return false;
+ if (ptype != NULL)
+ *ptype = debug_make_function_type (minfo->dhandle, *ptype, args,
+ varargs);
+
+ }
+ break;
+
+ case 'M':
+ case 'O':
+ {
+ boolean memberp, constp, volatilep;
+ debug_type *args;
+ boolean varargs;
+ unsigned int n;
+ const char *name;
+
+ memberp = **pp == 'M';
+ constp = false;
+ volatilep = false;
+ args = NULL;
+ varargs = false;
+
+ ++*pp;
+ if (! isdigit ((unsigned char) **pp))
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ n = stab_demangle_count (pp);
+ if (strlen (*pp) < n)
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ name = *pp;
+ *pp += n;
+
+ if (memberp)
+ {
+ if (**pp == 'C')
+ {
+ constp = true;
+ ++*pp;
+ }
+ else if (**pp == 'V')
+ {
+ volatilep = true;
+ ++*pp;
+ }
+ if (**pp != 'F')
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ ++*pp;
+ if (! stab_demangle_args (minfo, pp,
+ (ptype == NULL
+ ? (debug_type **) NULL
+ : &args),
+ (ptype == NULL
+ ? (boolean *) NULL
+ : &varargs)))
+ return false;
+ }
+
+ if (**pp != '_')
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ ++*pp;
+
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return false;
+
+ if (ptype != NULL)
+ {
+ debug_type class_type;
+
+ class_type = stab_find_tagged_type (minfo->dhandle, minfo->info,
+ name, (int) n,
+ DEBUG_KIND_CLASS);
+ if (class_type == DEBUG_TYPE_NULL)
+ return false;
+
+ if (! memberp)
+ *ptype = debug_make_offset_type (minfo->dhandle, class_type,
+ *ptype);
+ else
+ {
+ /* FIXME: We have no way to record constp or
+ volatilep. */
+ *ptype = debug_make_method_type (minfo->dhandle, *ptype,
+ class_type, args, varargs);
+ }
+ }
+ }
+ break;
+
+ case 'G':
+ ++*pp;
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return false;
+ break;
+
+ case 'C':
+ ++*pp;
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return false;
+ if (ptype != NULL)
+ *ptype = debug_make_const_type (minfo->dhandle, *ptype);
+ break;
+
+ case 'Q':
+ {
+ const char *hold;
+
+ hold = *pp;
+ if (! stab_demangle_qualified (minfo, pp, ptype))
+ return false;
+ }
+ break;
+
+ default:
+ if (! stab_demangle_fund_type (minfo, pp, ptype))
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+/* Demangle a fundamental type. If the ptype argument is not NULL,
+ *ptype is set to the newly allocated type. */
+
+static boolean
+stab_demangle_fund_type (minfo, pp, ptype)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+ debug_type *ptype;
+{
+ const char *orig;
+ boolean constp, volatilep, unsignedp, signedp;
+ boolean done;
+
+ orig = *pp;
+
+ constp = false;
+ volatilep = false;
+ unsignedp = false;
+ signedp = false;
+
+ done = false;
+ while (! done)
+ {
+ switch (**pp)
+ {
+ case 'C':
+ constp = true;
+ ++*pp;
+ break;
+
+ case 'U':
+ unsignedp = true;
+ ++*pp;
+ break;
+
+ case 'S':
+ signedp = true;
+ ++*pp;
+ break;
+
+ case 'V':
+ volatilep = true;
+ ++*pp;
+ break;
+
+ default:
+ done = true;
+ break;
+ }
+ }
+
+ switch (**pp)
+ {
+ case '\0':
+ case '_':
+ /* cplus_demangle permits this, but I don't know what it means. */
+ stab_bad_demangle (orig);
+ break;
+
+ case 'v': /* void */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle, "void");
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_void_type (minfo->dhandle);
+ }
+ ++*pp;
+ break;
+
+ case 'x': /* long long */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle,
+ (unsignedp
+ ? "long long unsigned int"
+ : "long long int"));
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_int_type (minfo->dhandle, 8, unsignedp);
+ }
+ ++*pp;
+ break;
+
+ case 'l': /* long */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle,
+ (unsignedp
+ ? "long unsigned int"
+ : "long int"));
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp);
+ }
+ ++*pp;
+ break;
+
+ case 'i': /* int */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle,
+ (unsignedp
+ ? "unsigned int"
+ : "int"));
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp);
+ }
+ ++*pp;
+ break;
+
+ case 's': /* short */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle,
+ (unsignedp
+ ? "short unsigned int"
+ : "short int"));
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_int_type (minfo->dhandle, 2, unsignedp);
+ }
+ ++*pp;
+ break;
+
+ case 'b': /* bool */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle, "bool");
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_bool_type (minfo->dhandle, 4);
+ }
+ ++*pp;
+ break;
+
+ case 'c': /* char */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle,
+ (unsignedp
+ ? "unsigned char"
+ : (signedp
+ ? "signed char"
+ : "char")));
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_int_type (minfo->dhandle, 1, unsignedp);
+ }
+ ++*pp;
+ break;
+
+ case 'w': /* wchar_t */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle, "__wchar_t");
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_int_type (minfo->dhandle, 2, true);
+ }
+ ++*pp;
+ break;
+
+ case 'r': /* long double */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle, "long double");
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_float_type (minfo->dhandle, 8);
+ }
+ ++*pp;
+ break;
+
+ case 'd': /* double */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle, "double");
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_float_type (minfo->dhandle, 8);
+ }
+ ++*pp;
+ break;
+
+ case 'f': /* float */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle, "float");
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_float_type (minfo->dhandle, 4);
+ }
+ ++*pp;
+ break;
+
+ case 'G':
+ ++*pp;
+ if (! isdigit ((unsigned char) **pp))
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ /* Fall through. */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ {
+ const char *hold;
+
+ if (! stab_demangle_class (minfo, pp, &hold))
+ return false;
+ if (ptype != NULL)
+ {
+ char *name;
+
+ name = savestring (hold, *pp - hold);
+ *ptype = debug_find_named_type (minfo->dhandle, name);
+ if (*ptype == DEBUG_TYPE_NULL)
+ {
+ /* FIXME: It is probably incorrect to assume that
+ undefined types are tagged types. */
+ *ptype = stab_find_tagged_type (minfo->dhandle, minfo->info,
+ hold, *pp - hold,
+ DEBUG_KIND_ILLEGAL);
+ }
+ free (name);
+ }
+ }
+ break;
+
+ case 't':
+ if (! stab_demangle_template (minfo, pp))
+ return false;
+ if (ptype != NULL)
+ {
+ debug_type t;
+
+ /* FIXME: I really don't know how a template should be
+ represented in the current type system. Perhaps the
+ template should be demangled into a string, and the type
+ should be represented as a named type. However, I don't
+ know what the base type of the named type should be. */
+ t = debug_make_void_type (minfo->dhandle);
+ t = debug_make_pointer_type (minfo->dhandle, t);
+ t = debug_name_type (minfo->dhandle, "TEMPLATE", t);
+ *ptype = t;
+ }
+ break;
+
+ default:
+ stab_bad_demangle (orig);
+ return false;
+ }
+
+ if (ptype != NULL)
+ {
+ if (constp)
+ *ptype = debug_make_const_type (minfo->dhandle, *ptype);
+ if (volatilep)
+ *ptype = debug_make_volatile_type (minfo->dhandle, *ptype);
+ }
+
+ return true;
+}
+
+/* Remember a type string in a demangled string. */
+
+static boolean
+stab_demangle_remember_type (minfo, p, len)
+ struct stab_demangle_info *minfo;
+ const char *p;
+ int len;
+{
+ if (minfo->typestring_count >= minfo->typestring_alloc)
+ {
+ minfo->typestring_alloc += 10;
+ minfo->typestrings = ((struct stab_demangle_typestring *)
+ xrealloc (minfo->typestrings,
+ (minfo->typestring_alloc
+ * sizeof *minfo->typestrings)));
+ }
+
+ minfo->typestrings[minfo->typestring_count].typestring = p;
+ minfo->typestrings[minfo->typestring_count].len = (unsigned int) len;
+ ++minfo->typestring_count;
+
+ return true;
+}
diff --git a/sql/ChangeLog b/sql/ChangeLog
index 2289765afad..a75e9761766 100644
--- a/sql/ChangeLog
+++ b/sql/ChangeLog
@@ -1,3 +1,8 @@
+2000-12-07 Jeremy Cole <jeremy@mysql.com>
+
+* Added UPDATE ... ORDER BY ...
+* Added DELETE ... ORDER BY ...
+
2000-11-11 Jeremy Cole <jeremy@mysql.com>
* Added ALTER TABLE ... ORDER BY ...
diff --git a/sql/Makefile.am b/sql/Makefile.am
index a32383802b1..0c33213a763 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -41,7 +41,8 @@ LDADD = ../isam/libnisam.a \
../regex/libregex.a \
../strings/libmystrings.a
mysqld_LDADD = @MYSQLD_EXTRA_LDFLAGS@ \
- @bdb_libs@ @innobase_libs@ @gemini_libs@ \
+ @bdb_libs@ @innobase_libs@ @pstack_libs@ \
+ @gemini_libs@ \
$(LDADD) $(CXXLDFLAGS) $(WRAPLIBS)
noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
item_strfunc.h item_timefunc.h item_uniq.h \
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 78e9db5652f..0e21340056b 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -241,6 +241,8 @@ void end_thread(THD *thd,bool put_in_cache);
void flush_thread_cache();
void mysql_execute_command(void);
bool do_command(THD *thd);
+bool dispatch_command(enum enum_server_command command, THD *thd,
+ char* packet, uint packet_length);
bool check_stack_overrun(THD *thd,char *dummy);
bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables);
void mysql_rm_db(THD *thd,char *db,bool if_exists);
@@ -251,6 +253,7 @@ void kill_mysql(void);
void close_connection(NET *net,uint errcode=0,bool lock=1);
bool check_access(THD *thd,uint access,const char *db=0,uint *save_priv=0,
bool no_grant=0);
+bool check_table_access(THD *thd,uint want_access, TABLE_LIST *tables);
bool check_process_priv(THD *thd=0);
int generate_table(THD *thd, TABLE_LIST *table_list,
@@ -336,15 +339,16 @@ int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys);
int mysql_drop_index(THD *thd, TABLE_LIST *table_list,
List<Alter_drop> &drop_list);
int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
- List<Item> &values,COND *conds, ha_rows limit,
+ List<Item> &values,COND *conds,
+ ORDER *order, ha_rows limit,
enum enum_duplicates handle_duplicates,
thr_lock_type lock_type);
int mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
List<List_item> &values, enum_duplicates flag,
thr_lock_type lock_type);
void kill_delayed_threads(void);
-int mysql_delete(THD *thd,TABLE_LIST *table,COND *conds,ha_rows rows,
- thr_lock_type lock_type, ulong options);
+int mysql_delete(THD *thd, TABLE_LIST *table, COND *conds, ORDER *order,
+ ha_rows rows, thr_lock_type lock_type, ulong options);
TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update);
TABLE *open_table(THD *thd,const char *db,const char *table,const char *alias,
bool *refresh);
@@ -365,7 +369,7 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
/* sql_list.c */
int mysqld_show_dbs(THD *thd,const char *wild);
-int mysqld_show_open_tables(THD *thd,const char *db,const char *wild);
+int mysqld_show_open_tables(THD *thd,const char *wild);
int mysqld_show_tables(THD *thd,const char *db,const char *wild);
int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild);
int mysqld_show_fields(THD *thd,TABLE_LIST *table, const char *wild,
@@ -432,8 +436,7 @@ bool close_cached_tables(THD *thd, bool wait_for_refresh, TABLE_LIST *tables);
void copy_field_from_tmp_record(Field *field,int offset);
int fill_record(List<Item> &fields,List<Item> &values);
int fill_record(Field **field,List<Item> &values);
-int list_open_tables(THD *thd,List<char> *files, const char *db,const char *wild);
-char* query_table_status(THD *thd,const char *db,const char *table_name);
+OPEN_TABLE_LIST *list_open_tables(THD *thd,const char *wild);
/* sql_calc.cc */
bool eval_const_cond(COND *cond);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index d09ad7513e0..2f534c44a5b 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -37,6 +37,13 @@
#define ONE_THREAD
#endif
+/* do stack traces are only supported on linux intel */
+#if defined(__linux__) && defined(__i386__) && defined(USE_PSTACK)
+#define HAVE_STACK_TRACE_ON_SEGV
+#include "../pstack/pstack.h"
+char pstack_file_name[80];
+#endif /* __linux__ */
+
extern "C" { // Because of SCO 3.2V4.2
#include <errno.h>
#include <sys/stat.h>
@@ -179,6 +186,7 @@ SHOW_COMP_OPTION have_ssl=SHOW_OPTION_NO;
static bool opt_skip_slave_start = 0; // if set, slave is not autostarted
+static bool opt_do_pstack = 0;
static ulong opt_specialflag=SPECIAL_ENGLISH;
static my_socket unix_sock= INVALID_SOCKET,ip_sock= INVALID_SOCKET;
static ulong back_log,connect_timeout,concurrency;
@@ -226,7 +234,7 @@ uint32 server_id = 0;
bool server_id_supplied = 0;
uint mysql_port;
-uint test_flags, select_errors=0, dropping_tables=0,ha_open_options=0;
+uint test_flags = 0, select_errors=0, dropping_tables=0,ha_open_options=0;
uint volatile thread_count=0, thread_running=0, kill_cached_threads=0,
wake_thread=0, global_read_lock=0;
ulong thd_startup_options=(OPTION_UPDATE_LOG | OPTION_AUTO_IS_NULL |
@@ -1105,7 +1113,7 @@ static void start_signal_handler(void)
#ifdef HAVE_LINUXTHREADS
static sig_handler write_core(int sig);
-#ifdef __i386__
+#if defined(__i386__) && !defined(HAVE_STACK_TRACE_ON_SEGV)
#define SIGRETURN_FRAME_COUNT 1
#define PTR_SANE(p) ((char*)p >= heap_start && (char*)p <= heap_end)
@@ -1116,14 +1124,14 @@ inline __volatile__ void print_str(const char* name,
const char* val, int max_len)
{
fprintf(stderr, "%s at %p ", name, val);
- if(!PTR_SANE(val))
- {
- fprintf(stderr, " is invalid pointer\n");
- return;
- }
+ if (!PTR_SANE(val))
+ {
+ fprintf(stderr, " is invalid pointer\n");
+ return;
+ }
fprintf(stderr, "= ");
- for(; max_len && PTR_SANE(val) && *val; --max_len)
+ for (; max_len && PTR_SANE(val) && *val; --max_len)
fputc(*val++, stderr);
fputc('\n', stderr);
}
@@ -1183,8 +1191,7 @@ New value of ebp failed sanity check, terminating backtrace!\n");
ebp = new_ebp;
++frame_count;
}
-
- fprintf(stderr, "Stack trace successful, trying to get some variables.\n\
+ fprintf(stderr, "Stack trace successful, tryint to get some variables.\n\
Some pointers may be invalid and cause the dump to abort...\n");
heap_start = __bss_start;
heap_end = (char*)sbrk(0);
@@ -1197,7 +1204,7 @@ In some cases of really bad corruption, this value may be invalid\n",
fprintf(stderr, "Please use the information above to create a repeatable\n\
test case for the crash, and send it to bugs@lists.mysql.com\n");
}
-#endif
+#endif /* HAVE_LINUXTHREADS */
#endif
static sig_handler handle_segfault(int sig)
@@ -1215,10 +1222,10 @@ The manual section 'Debugging a MySQL server' tells you how to use a\n\
stack trace and/or the core file to produce a readable backtrace that may\n\
help in finding out why mysqld died.\n",sig);
#if defined(HAVE_LINUXTHREADS)
-#ifdef __i386__
+#if defined(__i386__) && !defined(HAVE_STACK_TRACE_ON_SEGV)
trace_stack();
- fflush(stderr);
-#endif /* __i386__ */
+ fflush(stderr);
+#endif /* __i386__ && !HAVE_STACK_TRACE_ON_SEGV */
if (test_flags & TEST_CORE_ON_SIGNAL)
write_core(sig);
#endif /* HAVE_LINUXTHREADS */
@@ -1353,6 +1360,13 @@ static void *signal_hand(void *arg __attribute__((unused)))
(void) my_close(pidFile,MYF(0));
}
}
+#ifdef HAVE_STACK_TRACE_ON_SEGV
+ if (opt_do_pstack)
+ {
+ sprintf(pstack_file_name,"mysqld-%lu-%%d-%%d.backtrace", (ulong)getpid());
+ pstack_install_segv_action(pstack_file_name);
+ }
+#endif /* HAVE_STACK_TRACE_ON_SEGV */
// signal to start_signal_handler that we are ready
(void) pthread_mutex_lock(&LOCK_thread_count);
@@ -1748,7 +1762,7 @@ The server will not act as a slave.");
LOG_BIN);
using_update_log=1;
}
-
+
if (opt_slow_log)
open_log(&mysql_slow_log, glob_hostname, opt_slow_logname, "-slow.log",
LOG_NORMAL);
@@ -1770,7 +1784,7 @@ The server will not act as a slave.");
}
#else
locked_in_memory=0;
-#endif
+#endif
if (opt_myisam_log)
(void) mi_log( 1 );
@@ -2024,7 +2038,7 @@ static int bootstrap(FILE *file)
if (pthread_create(&thd->real_id,&connection_attrib,handle_bootstrap,
(void*) thd))
{
- sql_print_error("Warning: Can't create thread to handle bootstrap");
+ sql_print_error("Warning: Can't create thread to handle bootstrap");
return -1;
}
/* Wait for thread to die */
@@ -2462,7 +2476,7 @@ enum options {
OPT_INNOBASE_FLUSH_LOG_AT_TRX_COMMIT,
OPT_SAFE_SHOW_DB,
OPT_GEMINI_SKIP, OPT_INNOBASE_SKIP,
- OPT_TEMP_POOL, OPT_TX_ISOLATION,
+ OPT_TEMP_POOL, OPT_DO_PSTACK, OPT_TX_ISOLATION,
OPT_GEMINI_FLUSH_LOG, OPT_GEMINI_RECOVER,
OPT_GEMINI_UNBUFFERED_IO, OPT_SKIP_SAFEMALLOC,
};
@@ -2498,6 +2512,8 @@ static struct option long_options[] = {
{"default-table-type", required_argument, 0, (int) OPT_TABLE_TYPE},
{"delay-key-write-for-all-tables",
no_argument, 0, (int) OPT_DELAY_KEY_WRITE},
+ {"do-pstack",
+ no_argument, 0, (int) OPT_DO_PSTACK},
{"enable-locking", no_argument, 0, (int) OPT_ENABLE_LOCK},
{"exit-info", optional_argument, 0, 'T'},
{"flush", no_argument, 0, (int) OPT_FLUSH},
@@ -2551,7 +2567,7 @@ static struct option long_options[] = {
#if !defined(DBUG_OFF) && defined(SAFEMALLOC)
{"safemalloc-mem-limit", required_argument, 0, (int)
OPT_SAFEMALLOC_MEM_LIMIT},
-#endif
+#endif
{"new", no_argument, 0, 'n'},
{"old-protocol", no_argument, 0, 'o'},
#ifdef ONE_THREAD
@@ -2719,7 +2735,7 @@ CHANGEABLE_VAR changeable_vars[] = {
16384, 1024, 1024*1024L, MALLOC_OVERHEAD, 1024 },
{ "net_retry_count", (long*) &mysqld_net_retry_count,
MYSQLD_NET_RETRY_COUNT, 1, ~0L, 0, 1 },
- { "net_read_timeout", (long*) &net_read_timeout,
+ { "net_read_timeout", (long*) &net_read_timeout,
NET_READ_TIMEOUT, 1, 65535, 0, 1 },
{ "net_write_timeout", (long*) &net_write_timeout,
NET_WRITE_TIMEOUT, 1, 65535, 0, 1 },
@@ -2729,7 +2745,7 @@ CHANGEABLE_VAR changeable_vars[] = {
0, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD, IO_SIZE },
{ "record_buffer", (long*) &my_default_record_cache_size,
128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD, IO_SIZE },
- { "slow_launch_time", (long*) &slow_launch_time,
+ { "slow_launch_time", (long*) &slow_launch_time,
2L, 0L, ~0L, 0, 1 },
{ "sort_buffer", (long*) &sortbuff_size,
MAX_SORT_MEMORY, MIN_SORT_MEMORY+MALLOC_OVERHEAD*2, ~0L, MALLOC_OVERHEAD, 1 },
@@ -2804,7 +2820,7 @@ struct show_var_st init_vars[]= {
{"join_buffer_size", (char*) &join_buff_size, SHOW_LONG},
{"key_buffer_size", (char*) &keybuff_size, SHOW_LONG},
{"language", language, SHOW_CHAR},
- {"large_files_support", (char*) &opt_large_files, SHOW_BOOL},
+ {"large_files_support", (char*) &opt_large_files, SHOW_BOOL},
#ifdef HAVE_MLOCKALL
{"locked_in_memory", (char*) &locked_in_memory, SHOW_BOOL},
#endif
@@ -2936,7 +2952,7 @@ static void use_help(void)
{
print_version();
printf("Use '--help' or '--no-defaults --help' for a list of available options\n");
-}
+}
static void usage(void)
{
@@ -3207,11 +3223,11 @@ static void get_options(int argc,char **argv)
case 'P':
mysql_port= (unsigned int) atoi(optarg);
break;
-#if !defined(DBUG_OFF) && defined(SAFEMALLOC)
+#if !defined(DBUG_OFF) && defined(SAFEMALLOC)
case OPT_SAFEMALLOC_MEM_LIMIT:
safemalloc_mem_limit = atoi(optarg);
break;
-#endif
+#endif
case OPT_SOCKET:
mysql_unix_port= optarg;
break;
@@ -3281,14 +3297,14 @@ static void get_options(int argc,char **argv)
break;
// needs to be handled (as no-op) in non-debugging mode for test suite
case (int)OPT_DISCONNECT_SLAVE_EVENT_COUNT:
-#ifndef DBUG_OFF
+#ifndef DBUG_OFF
disconnect_slave_event_count = atoi(optarg);
-#endif
+#endif
break;
case (int)OPT_ABORT_SLAVE_EVENT_COUNT:
-#ifndef DBUG_OFF
+#ifndef DBUG_OFF
abort_slave_event_count = atoi(optarg);
-#endif
+#endif
break;
case (int) OPT_LOG_SLAVE_UPDATES:
opt_log_slave_updates = 1;
@@ -3629,11 +3645,11 @@ static void get_options(int argc,char **argv)
#endif
break;
case OPT_INNOBASE_SKIP:
-#ifdef HAVE_INNOBASE_DB
+#ifdef HAVE_INNOBASE_DB
innobase_skip=1;
have_innobase=SHOW_OPTION_DISABLED;
#endif
- break;
+ break;
case OPT_INNOBASE_DATA_FILE_PATH:
#ifdef HAVE_INNOBASE_DB
innobase_data_file_path=optarg;
@@ -3656,6 +3672,9 @@ static void get_options(int argc,char **argv)
innobase_flush_log_at_trx_commit= optarg ? test(atoi(optarg)) : 1;
break;
#endif /* HAVE_INNOBASE_DB */
+ case OPT_DO_PSTACK:
+ opt_do_pstack = 1;
+ break;
case OPT_MYISAM_RECOVER:
{
if (!optarg || !optarg[0])
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 4c4642034e1..44c082c1693 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
+
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
-
+
This library 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
Library General Public License for more details.
-
+
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
@@ -22,6 +22,11 @@
** 3 byte length & 1 byte package-number.
*/
+#ifdef EMBEDDED_LIBRARY
+#define net_read_timeout net_read_timeout1
+#define net_write_timeout net_write_timeout1
+#endif
+
#ifdef __WIN__
#include <winsock.h>
#endif
@@ -35,13 +40,21 @@
#include <errno.h>
#include <sys/types.h>
#include <violite.h>
+#include <assert.h>
#ifdef MYSQL_SERVER
ulong max_allowed_packet=65536;
extern ulong net_read_timeout,net_write_timeout;
extern uint test_flags;
#else
-ulong max_allowed_packet=16*1024*1024L;
+
+/*
+** Give error if a too big packet is found
+** The server can change this with the -O switch, but because the client
+** can't normally do this the client should have a bigger max_allowed_packet.
+*/
+
+ulong max_allowed_packet=~0L;
ulong net_read_timeout= NET_READ_TIMEOUT;
ulong net_write_timeout= NET_WRITE_TIMEOUT;
#endif
@@ -50,7 +63,7 @@ ulong net_buffer_length=8192; /* Default length. Enlarged if necessary */
#if !defined(__WIN__) && !defined(MSDOS)
#include <sys/socket.h>
#else
-#undef MYSQL_SERVER // Win32 can't handle interrupts
+#undef MYSQL_SERVER /* Win32 can't handle interrupts */
#endif
#if !defined(MSDOS) && !defined(__WIN__) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__BEOS__)
#include <netinet/in_systm.h>
@@ -84,28 +97,25 @@ inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __a
#endif
#ifdef MYSQL_SERVER
-extern ulong bytes_sent, bytes_received;
+extern ulong bytes_sent, bytes_received;
extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
#else
#undef statistic_add
#define statistic_add(A,B,C)
#endif
-/*
-** Give error if a too big packet is found
-** The server can change this with the -O switch, but because the client
-** can't normally do this the client should have a bigger max-buffer.
-*/
-
#define TEST_BLOCKING 8
-static int net_write_buff(NET *net,const char *packet,uint len);
+static int net_write_buff(NET *net,const char *packet,ulong len);
+#define MAX_THREE_BYTES 255L*255L*255L
/* Init with packet info */
int my_net_init(NET *net, Vio* vio)
{
- if (!(net->buff=(uchar*) my_malloc(net_buffer_length,MYF(MY_WME))))
+ if (!(net->buff=(uchar*) my_malloc(net_buffer_length+
+ NET_HEADER_SIZE + COMP_HEADER_SIZE,
+ MYF(MY_WME))))
return 1;
if (net_buffer_length > max_allowed_packet)
max_allowed_packet=net_buffer_length;
@@ -152,8 +162,12 @@ static my_bool net_realloc(NET *net, ulong length)
net->last_errno=ER_NET_PACKET_TOO_LARGE;
return 1;
}
- pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
- if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length, MYF(MY_WME))))
+ pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
+ /* We must allocate some extra bytes for the end 0 and to be able to
+ read big compressed blocks */
+ if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length +
+ NET_HEADER_SIZE + COMP_HEADER_SIZE,
+ MYF(MY_WME))))
{
net->error=1;
#ifdef MYSQL_SERVER
@@ -209,18 +223,34 @@ int net_flush(NET *net)
** Write something to server/client buffer
*****************************************************************************/
-
/*
** Write a logical packet with packet header
** Format: Packet length (3 bytes), packet number(1 byte)
** When compression is used a 3 byte compression length is added
-** NOTE: If compression is used the original package is destroyed!
+** NOTE: If compression is used the original package is modified!
*/
int
my_net_write(NET *net,const char *packet,ulong len)
{
uchar buff[NET_HEADER_SIZE];
+ /*
+ Big packets are handled by splitting them in packets of MAX_THREE_BYTES
+ length. The last packet is always a packet that is < MAX_THREE_BYTES.
+ (The last packet may even have a lengt of 0)
+ */
+ while (len >= MAX_THREE_BYTES)
+ {
+ const ulong z_size = MAX_THREE_BYTES;
+ int3store(buff, z_size);
+ buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
+ if (net_write_buff(net, (char*) buff, NET_HEADER_SIZE) ||
+ net_write_buff(net, packet, z_size))
+ return 1;
+ packet += z_size;
+ len-= z_size;
+ }
+ /* Write last packet */
int3store(buff,len);
buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE))
@@ -228,23 +258,54 @@ my_net_write(NET *net,const char *packet,ulong len)
return net_write_buff(net,packet,len);
}
+/*
+ Send a command to the server.
+ As the command is part of the first data packet, we have to do some data
+ juggling to put the command in there, without having to create a new
+ packet.
+ This function will split big packets into sub-packets if needed.
+ (Each sub packet can only be 2^24 bytes)
+*/
+
int
net_write_command(NET *net,uchar command,const char *packet,ulong len)
{
- uchar buff[NET_HEADER_SIZE+1];
uint length=len+1; /* 1 extra byte for command */
+ uchar buff[NET_HEADER_SIZE+1];
+ uint header_size=NET_HEADER_SIZE+1;
+ buff[4]=command; /* For first packet */
+ if (length >= MAX_THREE_BYTES)
+ {
+ /* Take into account that we have the command in the first header */
+ len= MAX_THREE_BYTES -1;
+ do
+ {
+ int3store(buff, MAX_THREE_BYTES);
+ buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
+ if (net_write_buff(net,(char*) buff, header_size) ||
+ net_write_buff(net,packet,len))
+ return 1;
+ packet+= len;
+ length-= MAX_THREE_BYTES;
+ len=MAX_THREE_BYTES;
+ header_size=NET_HEADER_SIZE;
+ } while (length >= MAX_THREE_BYTES);
+ len=length; /* Data left to be written */
+ }
int3store(buff,length);
buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
- buff[4]=command;
- if (net_write_buff(net,(char*) buff,5))
- return 1;
- return test(net_write_buff(net,packet,len) || net_flush(net));
+ return test(net_write_buff(net,(char*) buff,header_size) ||
+ net_write_buff(net,packet,len) || net_flush(net));
}
+/*
+ Caching the data in a local buffer before sending it.
+ One can force the buffer to be flushed with 'net_flush'.
+*/
static int
-net_write_buff(NET *net,const char *packet,uint len)
+net_write_buff(NET *net,const char *packet,ulong len)
{
uint left_length=(uint) (net->buff_end - net->write_pos);
@@ -263,7 +324,11 @@ net_write_buff(NET *net,const char *packet,uint len)
return 0;
}
-/* Read and write using timeouts */
+
+/*
+ Read and write one packet using timeouts.
+ If needed, the packet is compressed before sending.
+*/
int
net_real_write(NET *net,const char *packet,ulong len)
@@ -418,7 +483,7 @@ static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed)
{
if (!thr_alarm(alarmed,net->timeout,&alarm_buff) ||
(!vio_is_blocking(net->vio) && vio_blocking(net->vio,TRUE) < 0))
- return; // Can't setup, abort
+ return; /* Can't setup, abort */
}
while (remain > 0)
{
@@ -426,20 +491,26 @@ static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed)
if ((int) (length=vio_read(net->vio,(char*) net->buff,remain)) <= 0L)
{
my_bool interrupted = vio_should_retry(net->vio);
- if (!thr_got_alarm(alarmed) && interrupted)
- { /* Probably in MIT threads */
+ if (!thr_got_alarm(&alarmed) && interrupted)
+ { /* Probably in MIT threads */
if (retry_count++ < RETRY_COUNT)
continue;
}
return;
}
- remain -=(ulong) length;
- statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received);
+ remain -= length;
+ statistic_add(bytes_received,length,&LOCK_bytes_received);
}
}
#endif /* MYSQL_SERVER */
+/*
+ Reads one packet to net->buff + net->where_b
+ Returns length of packet. Long packets are handled by my_net_read().
+ This function reallocates the net->buff buffer if necessary.
+*/
+
static uint
my_real_read(NET *net, ulong *complen)
{
@@ -576,12 +647,13 @@ my_real_read(NET *net, ulong *complen)
#endif
len=uint3korr(net->buff+net->where_b);
+ if (!len) /* End of big multi-packet */
+ goto end;
helping = max(len,*complen) + net->where_b;
/* The necessary size of net->buff */
if (helping >= net->max_packet)
{
- /* We must allocate one extra byte for the end null */
- if (net_realloc(net,helping+1))
+ if (net_realloc(net,helping))
{
#ifdef MYSQL_SERVER
if (i == 1)
@@ -606,7 +678,21 @@ end:
return(len);
}
-uint
+
+/*
+ Read a packet from the client/server and return it without the internal
+ package header.
+ If the packet is the first packet of a multi-packet packet
+ (which is indicated by the length of the packet = 0xffffff) then
+ all sub packets are read and concatenated.
+ If the packet was compressed, its uncompressed and the length of the
+ uncompressed packet is returned.
+
+ The function returns the length of the found packet or packet_error.
+ net->read_pos points to the read data.
+*/
+
+ulong
my_net_read(NET *net)
{
ulong len,complen;
@@ -615,65 +701,126 @@ my_net_read(NET *net)
if (!net->compress)
{
#endif
- len = my_real_read (net,&complen);
+ len = my_real_read(net,&complen);
+ if (len == MAX_THREE_BYTES)
+ {
+ /* First packet of a multi-packet. Concatenate the packets */
+ int save_pos = net->where_b;
+ ulong total_length=0;
+ do
+ {
+ net->where_b += len;
+ total_length += len;
+ len = my_real_read (net,&complen);
+ } while (len == MAX_THREE_BYTES);
+ if (len != packet_error)
+ len+= total_length;
+ net->where_b = save_pos;
+ }
net->read_pos = net->buff + net->where_b;
if (len != packet_error)
net->read_pos[len]=0; /* Safeguard for mysql_use_result */
return len;
#ifdef HAVE_COMPRESS
}
- if (net->remain_in_buf)
- net->buff[net->buf_length - net->remain_in_buf]=net->save_char;
- for (;;)
+ else
{
+ /* We are using the compressed protocol */
+
+ ulong buf_length= net->buf_length;
+ ulong start_of_packet= net->buf_length - net->remain_in_buf;
+ ulong first_packet_offset=start_of_packet;
+ uint read_length, multi_byte_packet=0;
+
if (net->remain_in_buf)
{
- uchar *pos = net->buff + net->buf_length - net->remain_in_buf;
- if (net->remain_in_buf >= 4)
+ /* Restore the character that was overwritten by the end 0 */
+ net->buff[start_of_packet]=net->save_char;
+ }
+ else
+ {
+ /* reuse buffer, as there is noting in it that we need */
+ buf_length=start_of_packet=first_packet_offset=0;
+ }
+ for (;;)
+ {
+ ulong packet_len;
+
+ if (buf_length - start_of_packet >= NET_HEADER_SIZE)
{
- net->length = uint3korr(pos);
- if (net->length <= net->remain_in_buf - 4)
+ read_length = uint3korr(net->buff+start_of_packet);
+ if (!read_length)
+ {
+ /* End of multi-byte packet */
+ start_of_packet += NET_HEADER_SIZE;
+ break;
+ }
+ if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet)
{
- /* We have a full packet */
- len=net->length;
- net->remain_in_buf -= net->length + 4;
- net->read_pos=pos + 4;
- break; /* We have a full packet */
+ if (multi_byte_packet)
+ {
+ /* Remove packet header for second packet */
+ memmove(net->buff + first_packet_offset + start_of_packet,
+ net->buff + first_packet_offset + start_of_packet +
+ NET_HEADER_SIZE,
+ buf_length - start_of_packet);
+ start_of_packet += read_length;
+ buf_length -= NET_HEADER_SIZE;
+ }
+ else
+ start_of_packet+= read_length + NET_HEADER_SIZE;
+
+ if (read_length != MAX_THREE_BYTES) /* last package */
+ {
+ multi_byte_packet= 0; // No last zero length packet
+ break;
+ }
+ multi_byte_packet= NET_HEADER_SIZE;
+ /* Move data down to read next data packet after current one */
+ if (first_packet_offset)
+ {
+ memmove(net->buff,net->buff+first_packet_offset,
+ buf_length-first_packet_offset);
+ buf_length-=first_packet_offset;
+ start_of_packet -= first_packet_offset;
+ first_packet_offset=0;
+ }
+ continue;
}
}
/* Move data down to read next data packet after current one */
- if (net->buf_length != net->remain_in_buf)
+ if (first_packet_offset)
{
- memmove(net->buff,pos,net->remain_in_buf);
- net->buf_length=net->remain_in_buf;
+ memmove(net->buff,net->buff+first_packet_offset,
+ buf_length-first_packet_offset);
+ buf_length-=first_packet_offset;
+ start_of_packet -= first_packet_offset;
+ first_packet_offset=0;
}
- net->where_b=net->buf_length;
- }
- else
- {
- net->where_b=0;
- net->buf_length=0;
- }
- if ((len = my_real_read(net,&complen)) == packet_error)
- break;
- if (my_uncompress((byte*) net->buff + net->where_b, &len, &complen))
- {
- len= packet_error;
- net->error=2; /* caller will close socket */
+ net->where_b=buf_length;
+ if ((packet_len = my_real_read(net,&complen)) == packet_error)
+ return packet_error;
+ if (my_uncompress((byte*) net->buff + net->where_b, &packet_len,
+ &complen))
+ {
+ net->error=2; /* caller will close socket */
#ifdef MYSQL_SERVER
- net->last_errno=ER_NET_UNCOMPRESS_ERROR;
+ net->last_errno=ER_NET_UNCOMPRESS_ERROR;
#endif
- break;
+ return packet_error;
+ }
+ buf_length+=packet_len;
}
- net->buf_length+=len;
- net->remain_in_buf+=len;
- }
- if (len != packet_error)
- {
+
+ net->read_pos= net->buff+ first_packet_offset + NET_HEADER_SIZE;
+ net->buf_length= buf_length;
+ net->remain_in_buf= buf_length - start_of_packet;
+ len = ((uint) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE -
+ multi_byte_packet);
net->save_char= net->read_pos[len]; /* Must be saved */
net->read_pos[len]=0; /* Safeguard for mysql_use_result */
}
+#endif /* HAVE_COMPRESS */
return len;
-#endif
}
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
index f1559f4a44d..e807c8d4a64 100644
--- a/sql/share/estonian/errmsg.txt
+++ b/sql/share/estonian/errmsg.txt
@@ -177,19 +177,19 @@
"Can't write, because of unique constraint, to table '%-.64s'",
"BLOB column '%-.64s' used in key specification without a key length",
"All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead",
-"Result consisted of more than one row",
+"Tulemis on rohkem kui üks kirje",
"This table type requires a primary key",
"Antud MySQL ei ole kompileeritud RAID-i toega",
"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
"Key '%-.64s' doesn't exist in table '%-.64s'",
-"Can't open table",
-"The handler for the table doesn't support check/repair",
-"You are not allowed to execute this command in a transaction",
-"Got error %d during COMMIT",
-"Got error %d during ROLLBACK",
-"Got error %d during FLUSH_LOGS",
-"Got error %d during CHECKPOINT",
-"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+"Ei suuda tabelit avada",
+"See tabelitüüp ei toeta käske CHECK/REPAIR",
+"Puudub õigus selle transaktsioonikäsu andmiseks",
+"Sain vea %d COMMIT käsu täitmisel",
+"Sain vea %d ROLLBACK käsu täitmisel",
+"Sain vea %d FLUSH_LOGS käsu täitmisel",
+"Sain vea %d CHECKPOINT käsu täitmisel",
+"Ühendus %ld katkestatud andmebaas: '%-.64s' kasutaja: '%-.32s' masin: `%-.64s' (%-.64s)",
"The handler for the table does not support binary table dump",
"Binlog closed while trying to FLUSH MASTER",
"Failed rebuilding the index of dumped table '%-.64s'",
@@ -198,9 +198,9 @@
"Net error writing to master",
"Can't find FULLTEXT index matching the column list",
"Can't execute the given command because you have active locked tables or an active transaction",
-"Unknown system variable '%-.64'",
-"Table '%-.64s' is marked as crashed and should be repaired",
-"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
+"Tundmatu süsteemne muutja '%-.64'",
+"Tabel '%-.64s' on märgitud vigaseks ja tuleb parandada",
+"Tabel '%-.64s' on märgitud vigaseks ja viimane (automaatne?) parandamiskatse ebaõnnestus",
"Warning: Some non-transactional changed tables couldn't be rolled back",
"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again',
"This operation cannot be performed with a running slave, run SLAVE STOP first",
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 38dfcbdaa7a..9aabe6bb97f 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -111,74 +111,71 @@ static void check_unused(void)
#define check_unused()
#endif
-int list_open_tables(THD *thd,List<char> *tables, const char *db,
- const char *wild)
+OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
{
int result = 0;
uint col_access=thd->col_access;
+ OPEN_TABLE_LIST **start_list, *open_list;
TABLE_LIST table_list;
+ char name[NAME_LEN*2];
DBUG_ENTER("list_open_tables");
+
VOID(pthread_mutex_lock(&LOCK_open));
bzero((char*) &table_list,sizeof(table_list));
+ start_list= &open_list;
+ open_list=0;
for (uint idx=0 ; result == 0 && idx < open_cache.records; idx++)
{
+ OPEN_TABLE_LIST *table;
TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
- if ((!entry->real_name) || strcmp(entry->table_cache_key,db))
- continue;
- if (wild && wild[0] && wild_compare(entry->real_name,wild))
- continue;
- if (db && !(col_access & TABLE_ACLS))
+
+ if ((!entry->real_name))
+ continue; // Shouldn't happen
+ if (wild)
{
- table_list.db= (char*) db;
- table_list.real_name= entry->real_name;/*real name*/
- table_list.grant.privilege=col_access;
- if (check_grant(thd,TABLE_ACLS,&table_list,1))
- continue;
+ strxmov(name,entry->table_cache_key,".",entry->real_name,NullS);
+ if (wild_compare(name,wild))
+ continue;
}
- /* need to check if he have't already listed it */
- List_iterator<char> it(*tables);
- char *table_name;
- int check = 0;
- while (check == 0 && (table_name=it++))
+ /* Check if user has SELECT privilege for any column in the table */
+ table_list.db= (char*) entry->table_cache_key;
+ table_list.real_name= entry->real_name;
+ table_list.grant.privilege=0;
+ if (check_table_access(thd,SELECT_ACL | EXTRA_ACL,&table_list))
+ continue;
+
+ /* need to check if we haven't already listed it */
+ for (table= open_list ; table ; table=table->next)
{
- if (!strcmp(table_name,entry->real_name))
- check++;
+ if (!strcmp(table->table,entry->real_name) &&
+ !strcmp(table->db,entry->table_cache_key))
+ {
+ if (entry->in_use)
+ table->in_use++;
+ if (entry->locked_by_name)
+ table->locked++;
+ break;
+ }
}
- if (check)
+ if (table)
continue;
-
- if (tables->push_back(thd->strdup(entry->real_name)))
+ if (!(*start_list = (OPEN_TABLE_LIST *)
+ sql_alloc(sizeof(OPEN_TABLE_LIST)+entry->key_length)))
{
- result = -1;
+ open_list=0; // Out of memory
+ break;
}
+ (*start_list)->table=(strmov((*start_list)->db=(char*) ((*start_list)+1),
+ entry->table_cache_key)+1,
+ entry->real_name);
+ (*start_list)->in_use= entry->in_use ? 1 : 0;
+ (*start_list)->locked= entry->locked_by_name ? 1 : 0;
+ start_list= &(*start_list)->next;
}
-
VOID(pthread_mutex_unlock(&LOCK_open));
- DBUG_RETURN(result);
-}
-
-char*
-query_table_status(THD *thd,const char *db,const char *table_name)
-{
- int cached = 0, in_use = 0;
- char info[256];
-
- for (uint idx=0 ; idx < open_cache.records; idx++)
- {
- TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
- if (strcmp(entry->table_cache_key,db) ||
- strcmp(entry->real_name,table_name))
- continue;
-
- cached++;
- if (entry->in_use)
- in_use++;
- }
-
- sprintf(info, "cached=%d, in_use=%d", cached, in_use);
- return thd->strdup(info);
+ DBUG_RETURN(open_list);
}
@@ -258,7 +255,7 @@ send_fields(THD *thd,List<Item> &list,uint flag)
if (my_net_write(&thd->net, (char*) packet->ptr(),packet->length()))
break; /* purecov: inspected */
}
- send_eof(&thd->net,(test_flags & TEST_MIT_THREAD) ? 0: 1);
+ send_eof(&thd->net);
return 0;
err:
send_error(&thd->net,ER_OUT_OF_RESOURCES); /* purecov: inspected */
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index c20a656c547..c00389296ae 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -119,8 +119,13 @@ int generate_table(THD *thd, TABLE_LIST *table_list, TABLE *locked_table)
}
-int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit,
- thr_lock_type lock_type, ulong options)
+int mysql_delete(THD *thd,
+ TABLE_LIST *table_list,
+ COND *conds,
+ ORDER *order,
+ ha_rows limit,
+ thr_lock_type lock_type,
+ ulong options)
{
int error;
TABLE *table;
@@ -191,8 +196,33 @@ int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit,
}
(void) table->file->extra(HA_EXTRA_NO_READCHECK);
if (options & OPTION_QUICK)
- (void) table->file->extra(HA_EXTRA_QUICK);
- init_read_record(&info,thd,table,select,-1,1);
+ (void) table->file->extra(HA_EXTRA_QUICK);
+
+ if (order)
+ {
+ uint length;
+ SORT_FIELD *sortorder;
+ TABLE_LIST tables;
+ List<Item> fields;
+ List<Item> all_fields;
+
+ bzero((char*) &tables,sizeof(tables));
+ tables.table = table;
+
+ table->io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
+ MYF(MY_FAE | MY_ZEROFILL));
+ if (setup_order(thd, &tables, fields, all_fields, order) ||
+ !(sortorder=make_unireg_sortorder(order, &length)) ||
+ (table->found_records = filesort(&table, sortorder, length,
+ (SQL_SELECT *) 0, 0L, HA_POS_ERROR))
+ == HA_POS_ERROR)
+ {
+ delete select;
+ DBUG_RETURN(-1); // This will force out message
+ }
+ }
+
+ init_read_record(&info,thd,table,select,1,1);
ulong deleted=0L;
thd->proc_info="updating";
while (!(error=info.read_record(&info)) && !thd->killed)
@@ -218,9 +248,10 @@ int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit,
}
thd->proc_info="end";
end_read_record(&info);
+ /* if (order) free_io_cache(table); */ /* QQ Should not be needed */
(void) table->file->extra(HA_EXTRA_READCHECK);
if (options & OPTION_QUICK)
- (void) table->file->extra(HA_EXTRA_NORMAL);
+ (void) table->file->extra(HA_EXTRA_NORMAL);
using_transactions=table->file->has_transactions();
if (deleted && (error <= 0 || !using_transactions))
{
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index b8d2ee13b0e..0a1ee0649c4 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -196,7 +196,7 @@ static int find_keyword(LEX *lex, uint len, bool function)
/* make a copy of token before ptr and set yytoklen */
-static inline LEX_STRING get_token(LEX *lex,uint length)
+LEX_STRING get_token(LEX *lex,uint length)
{
LEX_STRING tmp;
yyUnget(); // ptr points now after last token char
@@ -509,6 +509,8 @@ int yylex(void *arg)
yySkip(); // next state does a unget
}
yylval->lex_str=get_token(lex,length);
+ if (lex->convert_set)
+ lex->convert_set->convert((char*) yylval->lex_str.str,lex->yytoklen);
return(IDENT);
case STATE_IDENT_SEP: // Found ident and now '.'
@@ -597,6 +599,8 @@ int yylex(void *arg)
case STATE_FOUND_IDENT: // Complete ident
yylval->lex_str=get_token(lex,yyLength());
+ if (lex->convert_set)
+ lex->convert_set->convert((char*) yylval->lex_str.str,lex->yytoklen);
return(IDENT);
case STATE_USER_VARIABLE_DELIMITER:
@@ -604,6 +608,8 @@ int yylex(void *arg)
while ((c=yyGet()) && state_map[c] != STATE_USER_VARIABLE_DELIMITER &&
c != (uchar) NAMES_SEP_CHAR) ;
yylval->lex_str=get_token(lex,yyLength());
+ if (lex->convert_set)
+ lex->convert_set->convert((char*) yylval->lex_str.str,lex->yytoklen);
if (state_map[c] == STATE_USER_VARIABLE_DELIMITER)
yySkip(); // Skipp end `
return(IDENT);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 5ed17d76dff..b44ea605b8e 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -14,6 +14,10 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#ifdef EMBEDDED_LIBRARY
+#define net_read_timeout net_read_timeout1
+#define net_write_timeout net_write_timeout1
+#endif
#include "mysql_priv.h"
#include "sql_acl.h"
@@ -26,7 +30,6 @@
#define SCRAMBLE_LENGTH 8
-
extern int yyparse(void);
extern "C" pthread_mutex_t THR_LOCK_keycache;
#ifdef SOLARIS
@@ -36,7 +39,6 @@ extern "C" int gethostname(char *name, int namelen);
static int check_for_max_user_connections(const char *user, int u_length,
const char *host);
static void decrease_user_connections(const char *user, const char *host);
-static bool check_table_access(THD *thd,uint want_access, TABLE_LIST *tables);
static bool check_db_used(THD *thd,TABLE_LIST *tables);
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
static bool check_dup(THD *thd,const char *db,const char *name,
@@ -701,19 +703,14 @@ err:
}
-
/* Execute one command from socket (query or simple command) */
bool do_command(THD *thd)
{
char *packet;
uint old_timeout,packet_length;
- bool error=0;
NET *net;
enum enum_server_command command;
- // commands which will always take a long time should be marked with
- // this so that they will not get logged to the slow query log
- bool slow_command=FALSE;
DBUG_ENTER("do_command");
net= &thd->net;
@@ -740,7 +737,21 @@ bool do_command(THD *thd)
vio_description(net->vio), command,
command_name[command]));
}
- net->timeout=old_timeout; /* Timeout */
+ net->timeout=old_timeout; // Timeout for writing
+ DBUG_RETURN(dispatch_command(command,thd, packet+1, packet_length));
+}
+
+
+bool dispatch_command(enum enum_server_command command, THD *thd,
+ char* packet, uint packet_length)
+{
+ NET *net= &thd->net;
+ bool error=0;
+ // commands which will always take a long time should be marked with
+ // this so that they will not get logged to the slow query log
+ bool slow_command=FALSE;
+ DBUG_ENTER("dispatch_command");
+
thd->command=command;
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_id=query_id;
@@ -750,22 +761,21 @@ bool do_command(THD *thd)
VOID(pthread_mutex_unlock(&LOCK_thread_count));
thd->set_time();
thd->lex.options=0; // We store status here
- switch(command) {
+ switch (command) {
case COM_INIT_DB:
- if (!mysql_change_db(thd,packet+1))
+ if (!mysql_change_db(thd,packet))
mysql_log.write(thd,command,"%s",thd->db);
break;
case COM_TABLE_DUMP:
{
slow_command = TRUE;
- char* data = packet + 1;
- uint db_len = *data;
- uint tbl_len = *(data + db_len + 1);
+ uint db_len = *(uchar*)packet;
+ uint tbl_len = *(uchar*)(packet + db_len + 1);
char* db = sql_alloc(db_len + tbl_len + 2);
- memcpy(db, data + 1, db_len);
+ memcpy(db, packet + 1, db_len);
char* tbl_name = db + db_len;
*tbl_name++ = 0;
- memcpy(tbl_name, data + db_len + 2, tbl_len);
+ memcpy(tbl_name, packet + db_len + 2, tbl_len);
tbl_name[tbl_len] = 0;
if(mysql_table_dump(thd, db, tbl_name, -1))
send_error(&thd->net); // dump to NET
@@ -774,7 +784,7 @@ bool do_command(THD *thd)
}
case COM_CHANGE_USER:
{
- char *user= (char*) packet+1;
+ char *user= (char*) packet;
char *passwd= strend(user)+1;
char *db= strend(passwd)+1;
@@ -810,7 +820,7 @@ bool do_command(THD *thd)
case COM_QUERY:
{
- char *pos=packet+packet_length; // Point at end null
+ char *pos=packet-1+packet_length; // Point at end null
/* Remove garage at end of query */
while (packet_length > 0 && pos[-1] == ';')
{
@@ -818,7 +828,7 @@ bool do_command(THD *thd)
packet_length--;
}
*pos=0;
- if (!(thd->query= (char*) thd->memdup((gptr) (packet+1),packet_length)))
+ if (!(thd->query= (char*) thd->memdup((gptr) (packet),packet_length)))
break;
thd->packet.shrink(net_buffer_length); // Reclaim some memory
if (!(specialflag & SPECIAL_NO_PRIOR))
@@ -846,8 +856,8 @@ bool do_command(THD *thd)
break;
}
thd->free_list=0;
- table_list.name=table_list.real_name=thd->strdup(packet+1);
- thd->query=fields=thd->strdup(strend(packet+1)+1);
+ table_list.name=table_list.real_name=thd->strdup(packet);
+ thd->query=fields=thd->strdup(strend(packet)+1);
mysql_log.write(thd,command,"%s %s",table_list.real_name,fields);
remove_escape(table_list.real_name); // This can't have wildcards
@@ -869,7 +879,7 @@ bool do_command(THD *thd)
case COM_CREATE_DB:
{
- char *db=thd->strdup(packet+1);
+ char *db=thd->strdup(packet);
// null test to handle EOM
if (!db || !stripp_sp(db) || check_db_name(db))
{
@@ -878,13 +888,13 @@ bool do_command(THD *thd)
}
if (check_access(thd,CREATE_ACL,db,0,1))
break;
- mysql_log.write(thd,command,packet+1);
+ mysql_log.write(thd,command,packet);
mysql_create_db(thd,db,0);
break;
}
case COM_DROP_DB:
{
- char *db=thd->strdup(packet+1);
+ char *db=thd->strdup(packet);
// null test to handle EOM
if (!db || !stripp_sp(db) || check_db_name(db))
{
@@ -907,13 +917,13 @@ bool do_command(THD *thd)
ulong pos;
ushort flags;
uint32 slave_server_id;
- pos = uint4korr(packet + 1);
- flags = uint2korr(packet + 5);
+ pos = uint4korr(packet);
+ flags = uint2korr(packet + 4);
pthread_mutex_lock(&LOCK_server_id);
- kill_zombie_dump_threads(slave_server_id = uint4korr(packet+7));
+ kill_zombie_dump_threads(slave_server_id = uint4korr(packet+6));
thd->server_id = slave_server_id;
pthread_mutex_unlock(&LOCK_server_id);
- mysql_binlog_send(thd, thd->strdup(packet + 11), pos, flags);
+ mysql_binlog_send(thd, thd->strdup(packet + 10), pos, flags);
// fake COM_QUIT -- if we get here, the thread needs to terminate
error = TRUE;
net->error = 0;
@@ -921,7 +931,7 @@ bool do_command(THD *thd)
}
case COM_REFRESH:
{
- uint options=(uchar) packet[1];
+ uint options=(uchar) packet[0];
if (check_access(thd,RELOAD_ACL,any_db))
break;
mysql_log.write(thd,command,NullS);
@@ -980,7 +990,7 @@ bool do_command(THD *thd)
break;
case COM_PROCESS_KILL:
{
- ulong id=(ulong) uint4korr(packet+1);
+ ulong id=(ulong) uint4korr(packet);
kill_one_thread(thd,id);
break;
}
@@ -1508,6 +1518,7 @@ mysql_execute_command(void)
lex->item_list,
lex->value_list,
lex->where,
+ (ORDER *) lex->order_list.first,
lex->select_limit,
lex->duplicates,
lex->lock_option);
@@ -1615,8 +1626,8 @@ mysql_execute_command(void)
if (lex->sql_command == SQLCOM_TRUNCATE && end_active_trans(thd))
res= -1;
else
- res = mysql_delete(thd,tables,lex->where,lex->select_limit,
- lex->lock_option, lex->options);
+ res = mysql_delete(thd,tables, lex->where, (ORDER*)lex->order_list.first,
+ lex->select_limit, lex->lock_option, lex->options);
break;
}
case SQLCOM_DROP_TABLE:
@@ -1679,7 +1690,6 @@ mysql_execute_command(void)
#endif
case SQLCOM_SHOW_TABLES:
/* FALL THROUGH */
- case SQLCOM_SHOW_OPEN_TABLES:
#ifdef DONT_ALLOW_SHOW_COMMANDS
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
DBUG_VOID_RETURN;
@@ -1700,18 +1710,18 @@ mysql_execute_command(void)
if (check_access(thd,SELECT_ACL,db,&thd->col_access))
goto error; /* purecov: inspected */
/* grant is checked in mysqld_show_tables */
- if (lex->sql_command == SQLCOM_SHOW_OPEN_TABLES)
- res= mysqld_show_open_tables(thd,db,
- (lex->wild ? lex->wild->ptr() : NullS));
- else if (lex->options & SELECT_DESCRIBE)
+ if (lex->options & SELECT_DESCRIBE)
res= mysqld_extend_show_tables(thd,db,
- (lex->wild ? lex->wild->ptr() : NullS));
+ (lex->wild ? lex->wild->ptr() : NullS));
else
res= mysqld_show_tables(thd,db,
(lex->wild ? lex->wild->ptr() : NullS));
break;
}
#endif
+ case SQLCOM_SHOW_OPEN_TABLES:
+ res= mysqld_show_open_tables(thd,(lex->wild ? lex->wild->ptr() : NullS));
+ break;
case SQLCOM_SHOW_FIELDS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
@@ -2124,7 +2134,7 @@ bool check_process_priv(THD *thd)
** in the table list for GRANT checking
*/
-static bool
+bool
check_table_access(THD *thd,uint want_access,TABLE_LIST *tables)
{
uint found=0,found_access=0;
@@ -2150,10 +2160,8 @@ check_table_access(THD *thd,uint want_access,TABLE_LIST *tables)
return TRUE; // Access denied
}
if (grant_option)
- {
- want_access &= ~EXTRA_ACL; // Remove SHOW attribute
- return check_grant(thd,want_access,org_tables);
- }
+ return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
+ test(want_access & EXTRA_ACL));
return FALSE;
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 38c068d35c3..faa899b719f 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -81,7 +81,7 @@ mysqld_show_dbs(THD *thd,const char *wild)
(grant_option && !check_grant_db(thd, file_name)))
{
thd->packet.length(0);
- net_store_data(&thd->packet,file_name);
+ net_store_data(&thd->packet, thd->convert_set, file_name);
if (my_net_write(&thd->net, (char*) thd->packet.ptr(),
thd->packet.length()))
DBUG_RETURN(-1);
@@ -95,39 +95,34 @@ mysqld_show_dbs(THD *thd,const char *wild)
** List all open tables in a database
***************************************************************************/
-int mysqld_show_open_tables(THD *thd,const char *db,const char *wild)
+int mysqld_show_open_tables(THD *thd,const char *wild)
{
- Item_string *field=new Item_string("",0);
List<Item> field_list;
- char *end,*table_name;
- List<char> tables;
+ OPEN_TABLE_LIST *open_list;
+ CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_show_open_tables");
- field->name=(char*) thd->alloc(20+(uint) strlen(db)+(wild ? (uint) strlen(wild)+4:0));
- end=strxmov(field->name,"Open_tables_in_",db,NullS);
- if (wild && wild[0])
- strxmov(end," (",wild,")",NullS);
- field->max_length=NAME_LEN;
- field_list.push_back(field);
- field_list.push_back(new Item_empty_string("Comment",80));
+ field_list.push_back(new Item_empty_string("Database",NAME_LEN));
+ field_list.push_back(new Item_empty_string("Table",NAME_LEN));
+ field_list.push_back(new Item_int("In_use",0, 4));
+ field_list.push_back(new Item_int("Name_locked",0, 4));
if (send_fields(thd,field_list,1))
DBUG_RETURN(1);
- if (list_open_tables(thd,&tables,db,wild))
+ if (!(open_list=list_open_tables(thd,wild)))
DBUG_RETURN(-1);
- List_iterator<char> it(tables);
- while ((table_name=it++))
+ for ( ; open_list ; open_list=open_list->next)
{
thd->packet.length(0);
- net_store_data(&thd->packet,table_name);
- net_store_data(&thd->packet,query_table_status(thd,db,table_name));
+ net_store_data(&thd->packet,convert, open_list->db);
+ net_store_data(&thd->packet,convert, open_list->table);
+ net_store_data(&thd->packet,open_list->in_use);
+ net_store_data(&thd->packet,open_list->locked);
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
DBUG_RETURN(-1);
}
-
-
send_eof(&thd->net);
DBUG_RETURN(0);
}
@@ -162,7 +157,7 @@ int mysqld_show_tables(THD *thd,const char *db,const char *wild)
while ((file_name=it++))
{
thd->packet.length(0);
- net_store_data(&thd->packet,file_name);
+ net_store_data(&thd->packet, thd->convert_set, file_name);
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
DBUG_RETURN(-1);
}
@@ -248,6 +243,7 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
char *file_name;
TABLE *table;
String *packet= &thd->packet;
+ CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_extend_show_tables");
(void) sprintf(path,"%s/%s",mysql_data_home,db);
@@ -293,14 +289,14 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
TABLE_LIST table_list;
bzero((char*) &table_list,sizeof(table_list));
packet->length(0);
- net_store_data(packet,file_name);
+ net_store_data(packet,convert, file_name);
table_list.db=(char*) db;
table_list.real_name=table_list.name=file_name;
if (!(table = open_ltable(thd, &table_list, TL_READ)))
{
for (uint i=0 ; i < field_list.elements ; i++)
net_store_null(packet);
- net_store_data(packet,thd->net.last_error);
+ net_store_data(packet,convert, thd->net.last_error);
thd->net.last_error[0]=0;
}
else
@@ -308,8 +304,8 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
struct tm tm_tmp;
handler *file=table->file;
file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK);
- net_store_data(packet, file->table_type());
- net_store_data(packet,
+ net_store_data(packet, convert, file->table_type());
+ net_store_data(packet, convert,
(table->db_options_in_use & HA_OPTION_PACK_RECORD) ?
"Dynamic" :
(table->db_options_in_use & HA_OPTION_COMPRESS_RECORD)
@@ -390,7 +386,7 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
my_raid_type(file->raid_type), file->raid_chunks, file->raid_chunksize/RAID_BLOCK_SIZE);
ptr=strmov(ptr,buff);
}
- net_store_data(packet, option_buff+1,
+ net_store_data(packet, convert, option_buff+1,
(ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1));
}
{
@@ -422,6 +418,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
TABLE *table;
handler *file;
char tmp[MAX_FIELD_WIDTH];
+ CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_show_fields");
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
table_list->real_name));
@@ -476,18 +473,18 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
bool null_default_value=0;
packet->length(0);
- net_store_data(packet,field->field_name);
+ net_store_data(packet,convert,field->field_name);
field->sql_type(type);
- net_store_data(packet,type.ptr(),type.length());
+ net_store_data(packet,convert,type.ptr(),type.length());
pos=(byte*) ((flags & NOT_NULL_FLAG) &&
field->type() != FIELD_TYPE_TIMESTAMP ?
"" : "YES");
- net_store_data(packet,(const char*) pos);
+ net_store_data(packet,convert,(const char*) pos);
pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
(field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
(field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
- net_store_data(packet,(char*) pos);
+ net_store_data(packet,convert,(char*) pos);
if (field->type() == FIELD_TYPE_TIMESTAMP ||
field->unireg_check == Field::NEXT_NUMBER)
@@ -496,17 +493,17 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
{ // Not null by default
type.set(tmp,sizeof(tmp));
field->val_str(&type,&type);
- net_store_data(packet,type.ptr(),type.length());
+ net_store_data(packet,convert,type.ptr(),type.length());
}
else if (field->maybe_null() || null_default_value)
net_store_null(packet); // Null as default
else
- net_store_data(packet,tmp,0);
+ net_store_data(packet,convert,tmp,0);
char *end=tmp;
if (field->unireg_check == Field::NEXT_NUMBER)
end=strmov(tmp,"auto_increment");
- net_store_data(packet,tmp,(uint) (end-tmp));
+ net_store_data(packet,convert,tmp,(uint) (end-tmp));
if (verbose)
{
@@ -521,7 +518,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
end=strmov(end,grant_types.type_names[bitnr]);
}
}
- net_store_data(packet,tmp+1,end == tmp ? 0 : (uint) (end-tmp-1));
+ net_store_data(packet,convert, tmp+1,end == tmp ? 0 : (uint) (end-tmp-1));
}
if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
DBUG_RETURN(1);
@@ -536,6 +533,7 @@ int
mysqld_show_create(THD *thd, TABLE_LIST *table_list)
{
TABLE *table;
+ CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_show_create");
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
table_list->real_name));
@@ -557,7 +555,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
String *packet = &thd->packet;
{
packet->length(0);
- net_store_data(packet, table->table_name);
+ net_store_data(packet,convert, table->table_name);
// a hack - we need to reserve some space for the length before
// we know what it is - let's assume that the length of create table
// statement will fit into 3 bytes ( 16 MB max :-) )
@@ -614,6 +612,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
{
TABLE *table;
char buff[256];
+ CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_show_keys");
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
table_list->real_name));
@@ -655,16 +654,18 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
{
packet->length(0);
- net_store_data(packet,table->table_name);
- net_store_data(packet,((key_info->flags & HA_NOSAME) ? "0" :"1"), 1);
- net_store_data(packet,key_info->name);
+ net_store_data(packet,convert,table->table_name);
+ net_store_data(packet,convert,((key_info->flags & HA_NOSAME) ? "0" :"1"), 1);
+ net_store_data(packet,convert,key_info->name);
end=int10_to_str((long) (j+1),(char*) buff,10);
- net_store_data(packet,buff,(uint) (end-buff));
- net_store_data(packet,key_part->field ? key_part->field->field_name :
+ net_store_data(packet,convert,buff,(uint) (end-buff));
+ net_store_data(packet,convert,
+ key_part->field ? key_part->field->field_name :
"?unknown field?");
if (table->file->option_flag() & HA_READ_ORDER)
- net_store_data(packet,((key_part->key_part_flag & HA_REVERSE_SORT)
- ? "D" : "A"), 1);
+ net_store_data(packet,convert,
+ ((key_part->key_part_flag & HA_REVERSE_SORT) ?
+ "D" : "A"), 1);
else
net_store_null(packet); /* purecov: inspected */
KEY *key=table->key_info+i;
@@ -672,7 +673,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
{
ulong records=(table->file->records / key->rec_per_key[j]);
end=int10_to_str((long) records, buff, 10);
- net_store_data(packet,buff,(uint) (end-buff));
+ net_store_data(packet,convert,buff,(uint) (end-buff));
}
else
net_store_null(packet);
@@ -681,12 +682,13 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
table->field[key_part->fieldnr-1]->key_length())
{
end=int10_to_str((long) key_part->length, buff,10); /* purecov: inspected */
- net_store_data(packet,buff,(uint) (end-buff)); /* purecov: inspected */
+ net_store_data(packet,convert,buff,(uint) (end-buff)); /* purecov: inspected */
}
else
net_store_null(packet);
net_store_null(packet); // No pack_information yet
- net_store_data(packet,key_info->flags & HA_FULLTEXT ? "FULLTEXT":"");
+ net_store_data(packet,convert,
+ key_info->flags & HA_FULLTEXT ? "FULLTEXT":"");
if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
DBUG_RETURN(1); /* purecov: inspected */
}
@@ -731,15 +733,18 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
int
mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
{
+ CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_dump_create_info");
DBUG_PRINT("enter",("table: %s",table->real_name));
+
String* packet = &thd->packet;
packet->length(0);
-
- if(store_create_info(thd,table,packet))
+ if (store_create_info(thd,table,packet))
DBUG_RETURN(-1);
- if(fd < 0)
+ if (convert)
+ convert->convert((char*) packet->ptr(), packet->length());
+ if (fd < 0)
{
if(my_net_write(&thd->net, (char*)packet->ptr(), packet->length()))
DBUG_RETURN(-1);
@@ -950,6 +955,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
List<Item> field_list;
I_List<thread_info> thread_infos;
ulong max_query_length= verbose ? max_allowed_packet : PROCESS_LIST_WIDTH;
+ CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_list_processes");
field_list.push_back(new Item_int("Id",0,7));
@@ -1033,28 +1039,28 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
char buff[20],*end;
packet->length(0);
end=int10_to_str((long) thd_info->thread_id, buff,10);
- net_store_data(packet,buff,(uint) (end-buff));
- net_store_data(packet,thd_info->user);
- net_store_data(packet,thd_info->host);
+ net_store_data(packet,convert,buff,(uint) (end-buff));
+ net_store_data(packet,convert,thd_info->user);
+ net_store_data(packet,convert,thd_info->host);
if (thd_info->db)
- net_store_data(packet,thd_info->db);
+ net_store_data(packet,convert,thd_info->db);
else
net_store_null(packet);
if (thd_info->proc_info)
- net_store_data(packet,thd_info->proc_info);
+ net_store_data(packet,convert,thd_info->proc_info);
else
- net_store_data(packet,command_name[thd_info->command]);
+ net_store_data(packet,convert,command_name[thd_info->command]);
if (thd_info->start_time)
- net_store_data(packet,(uint32)
- (time((time_t*) 0) - thd_info->start_time));
+ net_store_data(packet,
+ (uint32) (time((time_t*) 0) - thd_info->start_time));
else
net_store_null(packet);
if (thd_info->state_info)
- net_store_data(packet,thd_info->state_info);
+ net_store_data(packet,convert,thd_info->state_info);
else
net_store_null(packet);
if (thd_info->query)
- net_store_data(packet,thd_info->query);
+ net_store_data(packet,convert,thd_info->query);
else
net_store_null(packet);
if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
@@ -1076,6 +1082,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables)
char buff[8192];
String packet2(buff,sizeof(buff));
List<Item> field_list;
+ CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_show");
field_list.push_back(new Item_empty_string("Variable_name",30));
field_list.push_back(new Item_empty_string("Value",256));
@@ -1089,7 +1096,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables)
if (!(wild && wild[0] && wild_compare(variables[i].name,wild)))
{
packet2.length(0);
- net_store_data(&packet2,variables[i].name);
+ net_store_data(&packet2,convert,variables[i].name);
switch (variables[i].type){
case SHOW_LONG:
case SHOW_LONG_CONST:
@@ -1116,7 +1123,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables)
break;
}
case SHOW_CHAR:
- net_store_data(&packet2,variables[i].value);
+ net_store_data(&packet2,convert, variables[i].value);
break;
case SHOW_STARTTIME:
net_store_data(&packet2,(uint32) (thd->query_start() - start_time));
@@ -1130,7 +1137,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables)
case SHOW_CHAR_PTR:
{
char *value= *(char**) variables[i].value;
- net_store_data(&packet2,value ? value : "");
+ net_store_data(&packet2,convert, value ? value : "");
break;
}
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 87a2f5c7b2b..3cba3b4be6a 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
+
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 */
@@ -40,8 +40,12 @@ static bool compare_record(TABLE *table, ulong query_id)
}
-int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
- List<Item> &values, COND *conds,
+int mysql_update(THD *thd,
+ TABLE_LIST *table_list,
+ List<Item> &fields,
+ List<Item> &values,
+ COND *conds,
+ ORDER *order,
ha_rows limit,
enum enum_duplicates handle_duplicates,
thr_lock_type lock_type)
@@ -163,6 +167,32 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
}
+
+ if (order)
+ {
+ uint length;
+ SORT_FIELD *sortorder;
+ TABLE_LIST tables;
+ List<Item> fields;
+ List<Item> all_fields;
+
+ bzero((char*) &tables,sizeof(tables));
+ tables.table = table;
+
+ table->io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
+ MYF(MY_FAE | MY_ZEROFILL));
+ if (setup_order(thd, &tables, fields, all_fields, order) ||
+ !(sortorder=make_unireg_sortorder(order, &length)) ||
+ (table->found_records = filesort(&table, sortorder, length,
+ (SQL_SELECT *) 0, 0L, HA_POS_ERROR))
+ == HA_POS_ERROR)
+ {
+ delete select;
+ table->time_stamp=save_time_stamp; // Restore timestamp pointer
+ DBUG_RETURN(-1);
+ }
+ }
+
init_read_record(&info,thd,table,select,0,1);
thd->proc_info="searching";
@@ -180,7 +210,7 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
}
else
{
- if (!(test_flags & 512)) /* For debugging */
+ if (!(test_flags & 512)) /* For debugging */
{
DBUG_DUMP("record",(char*) table->record[0],table->reclength);
}
@@ -202,7 +232,7 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
select->cond=0;
}
else
- {
+ {
select= new SQL_SELECT;
select->head=table;
}
@@ -213,7 +243,7 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
{
delete select;
table->time_stamp=save_time_stamp; // Restore timestamp pointer
- DBUG_RETURN(-1);
+ DBUG_RETURN(-1);
}
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 1196d279e5c..055860bac60 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -72,341 +72,351 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token END_OF_INPUT
-%token EQ
-%token EQUAL_SYM
-%token GE
-%token GT_SYM
-%token LE
-%token LT
-%token NE
-%token IS
-%token SHIFT_LEFT
-%token SHIFT_RIGHT
-%token SET_VAR
-
-%token AVG_SYM
-%token COUNT_SYM
-%token MAX_SYM
-%token MIN_SYM
-%token SUM_SYM
-%token STD_SYM
-
+%token ACTION
%token ADD
-%token ALTER
%token AFTER_SYM
-%token ANALYZE_SYM
-%token BEGIN_SYM
-%token CHANGE
-%token COMMENT_SYM
-%token COMMIT_SYM
-%token CREATE
-%token CROSS
-%token DELETE_SYM
-%token DROP
-%token INSERT
-%token FLUSH_SYM
-%token SELECT_SYM
-%token MASTER_SYM
-%token REPAIR
-%token RESET_SYM
-%token PURGE
-%token SLAVE
-%token START_SYM
-%token STOP_SYM
-%token TRUNCATE_SYM
-%token ROLLBACK_SYM
-%token OPTIMIZE
-%token SHOW
-%token UPDATE_SYM
-%token KILL_SYM
-%token LOAD
-%token LOCK_SYM
-%token UNLOCK_SYM
-
-%token ACTION
+%token AGAINST
%token AGGREGATE_SYM
%token ALL
+%token ALTER
+%token ANALYZE_SYM
%token AND
%token AS
%token ASC
-%token AUTO_INC
+%token ATAN
%token AUTOCOMMIT
+%token AUTO_INC
%token AVG_ROW_LENGTH
-%token BACKUP_SYM
+%token AVG_SYM
+%token BACKUP_SYM
+%token BEGIN_SYM
+%token BENCHMARK_SYM
%token BERKELEY_DB_SYM
+%token BETWEEN_SYM
+%token BIGINT
%token BINARY
+%token BIT_AND
+%token BIT_OR
%token BIT_SYM
+%token BLOB_SYM
%token BOOL_SYM
%token BOTH
%token BY
%token CASCADE
+%token CASE_SYM
+%token CHANGE
+%token CHANGED
+%token CHAR_SYM
%token CHECKSUM_SYM
%token CHECK_SYM
-%token COMMITTED_SYM
+%token COALESCE
%token COLUMNS
%token COLUMN_SYM
+%token COMMENT_SYM
+%token COMMITTED_SYM
+%token COMMIT_SYM
+%token COMPRESSED_SYM
+%token CONCAT
+%token CONCAT_WS
%token CONSTRAINT
+%token COUNT_SYM
+%token CREATE
+%token CROSS
+%token CURDATE
+%token CURTIME
+%token DATABASE
%token DATABASES
%token DATA_SYM
+%token DATETIME
+%token DATE_ADD_INTERVAL
+%token DATE_SUB_INTERVAL
+%token DATE_SYM
+%token DAY_HOUR_SYM
+%token DAY_MINUTE_SYM
+%token DAY_SECOND_SYM
+%token DAY_SYM
+%token DECIMAL_SYM
+%token DECODE_SYM
%token DEFAULT
%token DELAYED_SYM
%token DELAY_KEY_WRITE_SYM
+%token DELETE_SYM
%token DESC
%token DESCRIBE
%token DISTINCT
+%token DOUBLE_SYM
+%token DROP
+%token DUMPFILE
%token DYNAMIC_SYM
+%token ELSE
+%token ELT_FUNC
%token ENCLOSED
+%token ENCODE_SYM
+%token ENCRYPT
+%token END
+%token ENUM
+%token EQ
+%token EQUAL_SYM
%token ESCAPED
%token ESCAPE_SYM
%token EXISTS
+%token EXPORT_SET
%token EXTENDED_SYM
+%token EXTRACT_SYM
+%token FAST_SYM
+%token FIELD_FUNC
%token FILE_SYM
%token FIRST_SYM
%token FIXED_SYM
%token FLOAT_NUM
+%token FLOAT_SYM
+%token FLUSH_SYM
%token FOREIGN
+%token FORMAT_SYM
+%token FOR_SYM
%token FROM
+%token FROM_UNIXTIME
%token FULL
-%token FULLTEXT_SYM
-%token GEMINI_SYM
+%token FULLTEXT_SYM
+%token FUNC_ARG0
+%token FUNC_ARG1
+%token FUNC_ARG2
+%token FUNC_ARG3
+%token GE
%token GEMINI_SPIN_RETRIES
-%token GLOBAL_SYM
+%token GEMINI_SYM
+%token GLOBAL_SYM
%token GRANT
%token GRANTS
%token GREATEST_SYM
%token GROUP
+%token GROUP_UNIQUE_USERS
+%token GT_SYM
%token HAVING
%token HEAP_SYM
%token HEX_NUM
%token HIGH_PRIORITY
%token HOSTS_SYM
+%token HOUR_MINUTE_SYM
+%token HOUR_SECOND_SYM
+%token HOUR_SYM
%token IDENT
+%token IDENTIFIED_SYM
+%token IF
%token IGNORE_SYM
%token INDEX
%token INFILE
%token INNER_SYM
%token INNOBASE_SYM
+%token INSERT
+%token INSERT_ID
+%token INTERVAL_SYM
%token INTO
+%token INT_SYM
%token IN_SYM
-%token ISOLATION
+%token IS
%token ISAM_SYM
+%token ISOLATION
%token JOIN_SYM
%token KEYS
%token KEY_SYM
+%token KILL_SYM
+%token LAST_INSERT_ID
+%token LE
%token LEADING
%token LEAST_SYM
-%token LEVEL_SYM
+%token LEFT
+%token LEVEL_SYM
%token LEX_HOSTNAME
%token LIKE
+%token LIMIT
%token LINES
+%token LOAD
%token LOCAL_SYM
+%token LOCATE
+%token LOCK_SYM
%token LOGS_SYM
+%token LONGBLOB
+%token LONGTEXT
%token LONG_NUM
%token LONG_SYM
%token LOW_PRIORITY
-%token MASTER_HOST_SYM
-%token MASTER_USER_SYM
-%token MASTER_LOG_FILE_SYM
-%token MASTER_LOG_POS_SYM
-%token MASTER_PASSWORD_SYM
-%token MASTER_PORT_SYM
-%token MASTER_CONNECT_RETRY_SYM
+%token LT
+%token MAKE_SET_SYM
+%token MASTER_CONNECT_RETRY_SYM
+%token MASTER_HOST_SYM
+%token MASTER_LOG_FILE_SYM
+%token MASTER_LOG_POS_SYM
+%token MASTER_PASSWORD_SYM
+%token MASTER_PORT_SYM
+%token MASTER_SYM
+%token MASTER_USER_SYM
%token MATCH
%token MAX_ROWS
+%token MAX_SYM
+%token MEDIUMBLOB
+%token MEDIUMINT
+%token MEDIUMTEXT
%token MEDIUM_SYM
%token MERGE_SYM
+%token MINUTE_SECOND_SYM
+%token MINUTE_SYM
%token MIN_ROWS
+%token MIN_SYM
+%token MODE_SYM
+%token MODIFY_SYM
+%token MONTH_SYM
%token MYISAM_SYM
%token NATIONAL_SYM
%token NATURAL
%token NCHAR_SYM
+%token NE
%token NOT
+%token NOW_SYM
%token NO_SYM
%token NULL_SYM
%token NUM
+%token NUMERIC_SYM
%token ON
%token OPEN_SYM
+%token OPTIMIZE
%token OPTION
%token OPTIONALLY
%token OR
-%token OR_OR_CONCAT
%token ORDER_SYM
+%token OR_OR_CONCAT
%token OUTER
%token OUTFILE
-%token DUMPFILE
%token PACK_KEYS_SYM
%token PARTIAL
+%token PASSWORD
+%token POSITION_SYM
+%token PRECISION
%token PRIMARY_SYM
%token PRIVILEGES
+%token PROCEDURE
%token PROCESS
%token PROCESSLIST_SYM
+%token PURGE
+%token QUICK
%token RAID_0_SYM
-%token RAID_STRIPED_SYM
-%token RAID_TYPE
%token RAID_CHUNKS
%token RAID_CHUNKSIZE
+%token RAID_STRIPED_SYM
+%token RAID_TYPE
+%token RAND
%token READ_SYM
+%token REAL
%token REAL_NUM
%token REFERENCES
%token REGEXP
%token RELOAD
%token RENAME
+%token REPAIR
%token REPEATABLE_SYM
-%token RESTORE_SYM
+%token REPLACE
+%token RESET_SYM
+%token RESTORE_SYM
%token RESTRICT
%token REVOKE
+%token RIGHT
+%token ROLLBACK_SYM
+%token ROUND
%token ROWS_SYM
%token ROW_FORMAT_SYM
%token ROW_SYM
-%token SET
+%token SECOND_SYM
+%token SELECT_SYM
%token SERIALIZABLE_SYM
%token SESSION_SYM
+%token SET
+%token SET_VAR
+%token SHARE_SYM
+%token SHIFT_LEFT
+%token SHIFT_RIGHT
+%token SHOW
%token SHUTDOWN
+%token SLAVE
+%token SMALLINT
+%token SQL_AUTO_IS_NULL
+%token SQL_BIG_RESULT
+%token SQL_BIG_SELECTS
+%token SQL_BIG_TABLES
+%token SQL_BUFFER_RESULT
+%token SQL_LOG_BIN
+%token SQL_LOG_OFF
+%token SQL_LOG_UPDATE
+%token SQL_LOW_PRIORITY_UPDATES
+%token SQL_MAX_JOIN_SIZE
+%token SQL_QUOTE_SHOW_CREATE
+%token SQL_SAFE_UPDATES
+%token SQL_SELECT_LIMIT
+%token SQL_SMALL_RESULT
+%token SQL_WARNINGS
%token STARTING
+%token START_SYM
%token STATUS_SYM
+%token STD_SYM
+%token STOP_SYM
%token STRAIGHT_JOIN
+%token STRING_SYM
+%token SUBSTRING
+%token SUBSTRING_INDEX
+%token SUM_SYM
%token TABLES
%token TABLE_SYM
%token TEMPORARY
%token TERMINATED
%token TEXT_STRING
-%token TO_SYM
-%token TRAILING
-%token TRANSACTION_SYM
-%token TYPE_SYM
-%token FUNC_ARG0
-%token FUNC_ARG1
-%token FUNC_ARG2
-%token FUNC_ARG3
-%token UDF_RETURNS_SYM
-%token UDF_SONAME_SYM
-%token UDF_SYM
-%token UNCOMMITTED_SYM
-%token UNION_SYM
-%token UNIQUE_SYM
-%token USAGE
-%token USE_SYM
-%token USING
-%token VALUES
-%token VARIABLES
-%token WHERE
-%token WITH
-%token WRITE_SYM
-%token COMPRESSED_SYM
-
-%token BIGINT
-%token BLOB_SYM
-%token CHAR_SYM
-%token CHANGED
-%token COALESCE
-%token DATETIME
-%token DATE_SYM
-%token DECIMAL_SYM
-%token DOUBLE_SYM
-%token ENUM
-%token FAST_SYM
-%token FLOAT_SYM
-%token INT_SYM
-%token LIMIT
-%token LONGBLOB
-%token LONGTEXT
-%token MEDIUMBLOB
-%token MEDIUMINT
-%token MEDIUMTEXT
-%token NUMERIC_SYM
-%token PRECISION
-%token QUICK
-%token REAL
-%token SMALLINT
-%token STRING_SYM
%token TEXT_SYM
+%token THEN_SYM
%token TIMESTAMP
%token TIME_SYM
%token TINYBLOB
%token TINYINT
%token TINYTEXT
-%token UNSIGNED
-%token VARBINARY
-%token VARCHAR
-%token VARYING
-%token ZEROFILL
-
-%token AGAINST
-%token ATAN
-%token BETWEEN_SYM
-%token BIT_AND
-%token BIT_OR
-%token CASE_SYM
-%token CONCAT
-%token CONCAT_WS
-%token CURDATE
-%token CURTIME
-%token DATABASE
-%token DATE_ADD_INTERVAL
-%token DATE_SUB_INTERVAL
-%token DAY_HOUR_SYM
-%token DAY_MINUTE_SYM
-%token DAY_SECOND_SYM
-%token DAY_SYM
-%token DECODE_SYM
-%token ELSE
-%token ELT_FUNC
-%token ENCODE_SYM
-%token ENCRYPT
-%token EXPORT_SET
-%token EXTRACT_SYM
-%token FIELD_FUNC
-%token FORMAT_SYM
-%token FOR_SYM
-%token FROM_UNIXTIME
-%token GROUP_UNIQUE_USERS
-%token HOUR_MINUTE_SYM
-%token HOUR_SECOND_SYM
-%token HOUR_SYM
-%token IDENTIFIED_SYM
-%token IF
-%token INSERT_ID
-%token INTERVAL_SYM
-%token LAST_INSERT_ID
-%token LEFT
-%token LOCATE
-%token MAKE_SET_SYM
-%token MINUTE_SECOND_SYM
-%token MINUTE_SYM
-%token MODE_SYM
-%token MODIFY_SYM
-%token MONTH_SYM
-%token NOW_SYM
-%token PASSWORD
-%token POSITION_SYM
-%token PROCEDURE
-%token RAND
-%token REPLACE
-%token RIGHT
-%token ROUND
-%token SECOND_SYM
-%token SHARE_SYM
-%token SUBSTRING
-%token SUBSTRING_INDEX
+%token TO_SYM
+%token TRAILING
+%token TRANSACTION_SYM
%token TRIM
+%token TRUNCATE_SYM
+%token TYPE_SYM
%token UDA_CHAR_SUM
%token UDA_FLOAT_SUM
%token UDA_INT_SUM
%token UDF_CHAR_FUNC
%token UDF_FLOAT_FUNC
%token UDF_INT_FUNC
+%token UDF_RETURNS_SYM
+%token UDF_SONAME_SYM
+%token UDF_SYM
+%token UNCOMMITTED_SYM
+%token UNION_SYM
+%token UNIQUE_SYM
%token UNIQUE_USERS
%token UNIX_TIMESTAMP
+%token UNLOCK_SYM
+%token UNSIGNED
+%token UPDATE_SYM
+%token USAGE
%token USER
+%token USE_SYM
+%token USING
+%token VALUES
+%token VARBINARY
+%token VARCHAR
+%token VARIABLES
+%token VARYING
%token WEEK_SYM
%token WHEN_SYM
-%token WORK_SYM
+%token WHERE
+%token WITH
+%token WORK_SYM
+%token WRITE_SYM
+%token YEARWEEK
%token YEAR_MONTH_SYM
%token YEAR_SYM
-%token YEARWEEK
-%token BENCHMARK_SYM
-%token END
-%token THEN_SYM
+%token ZEROFILL
%token SQL_BIG_TABLES
%token SQL_BIG_SELECTS
@@ -1240,7 +1250,7 @@ select:
select_options select_item_list select_into select_lock_type
select_into:
- /* empty */
+ limit_clause {}
| select_from
| opt_into select_from
| select_from opt_into
@@ -2128,8 +2138,17 @@ values:
/* Update rows in a table */
update:
- UPDATE_SYM opt_low_priority opt_ignore table SET update_list where_clause delete_limit_clause
- { Lex->sql_command = SQLCOM_UPDATE; }
+ UPDATE_SYM opt_low_priority opt_ignore table
+ SET update_list
+ where_clause
+ opt_order_clause
+ delete_limit_clause
+ {
+ Lex->sql_command = SQLCOM_UPDATE;
+ Lex->order_list.elements=0;
+ Lex->order_list.first=0;
+ Lex->order_list.next= (byte**) &Lex->order_list.first;
+ }
update_list:
update_list ',' simple_ident equal expr
@@ -2151,12 +2170,15 @@ opt_low_priority:
delete:
DELETE_SYM
- {
- Lex->sql_command= SQLCOM_DELETE; Lex->options=0;
+ {
+ Lex->sql_command= SQLCOM_DELETE; Lex->options=0;
Lex->lock_option= current_thd->update_lock_default;
- }
+ Lex->order_list.elements=0;
+ Lex->order_list.first=0;
+ Lex->order_list.next= (byte**) &Lex->order_list.first;
+ }
opt_delete_options FROM table
- where_clause delete_limit_clause
+ where_clause opt_order_clause delete_limit_clause
opt_delete_options:
@@ -2169,8 +2191,15 @@ opt_delete_option:
truncate:
TRUNCATE_SYM opt_table_sym table
- { Lex->sql_command= SQLCOM_TRUNCATE; Lex->options=0;
- Lex->lock_option= current_thd->update_lock_default; }
+ {
+ LEX* lex = Lex;
+ lex->sql_command= SQLCOM_TRUNCATE;
+ lex->options=0;
+ lex->order_list.elements=0;
+ lex->order_list.first=0;
+ lex->order_list.next= (byte**) &lex->order_list.first;
+
+ lex->lock_option= current_thd->update_lock_default; }
opt_table_sym:
/* empty */
diff --git a/sql/table.h b/sql/table.h
index a3b361742c5..a0e037222dc 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -143,3 +143,10 @@ typedef struct st_table_list {
bool straight; /* optimize with prev table */
bool updating; /* for replicate-do/ignore table */
} TABLE_LIST;
+
+typedef struct st_open_table_list
+{
+ struct st_open_table_list *next;
+ char *db,*table;
+ uint32 in_use,locked;
+} OPEN_TABLE_LIST;