diff options
author | unknown <monty@work.mysql.com> | 2001-04-11 13:04:03 +0200 |
---|---|---|
committer | unknown <monty@work.mysql.com> | 2001-04-11 13:04:03 +0200 |
commit | 8dd2e5b8d93d79965e833e3b979675240478c591 (patch) | |
tree | 9ad58a68370fc8feb8195b7b9c6423d58372093a | |
parent | 0c971641774f4d06f5442ef23af5d8c7ef9058ab (diff) | |
download | mariadb-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
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[] = { + "&", "&", + "<", "<", + 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 : + " ") : "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 : + " ") : "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 : + " ") : "NULL")); + xmlencode(data, cur[i]); + tee_fprintf(PAGER, "</%s>\n", (fields[i].name ? + (fields[i].name[0] ? fields[i].name : + " ") : "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, <mp, 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 : + " ") : "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 : + " ") : "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 : + " ") : "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,¶m); 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(¶m->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, - ¬_used)) + _mi_key_cmp(keyinfo->seg, info->lastkey, key, key_len, SEARCH_FIND, + ¬_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,¬_used)) - >= 0) + comp_flag,¬_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,¬_used); + comp_flag,¬_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, - ¬_used)) >= 0) + ¬_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,¬_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 = ⊤ + + 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, §ype) + || ! 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; |