public inbox for java-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* RFC: Enabling Corba
@ 2005-11-19  0:04 Mark Wielaard
  2005-11-20 19:10 ` Mark Wielaard
  0 siblings, 1 reply; 5+ messages in thread
From: Mark Wielaard @ 2005-11-19  0:04 UTC (permalink / raw)
  To: java-patches; +Cc: tromey


[-- Attachment #1.1: Type: text/plain, Size: 1319 bytes --]

Hi,

I wish I had found this earlier. But while checking all the tests and
results I found that we were currently disabling all of Corba. I didn't
find this before because I was only looking for regressions and
apparently since the start of the "big-merge" these packages were
disabled.

The reason for that was probably because one missing feature
(VMStackWalker) in libgcj and a wrong-code generation with gcj -C. Both
are easily worked around however with a simple override file.

We could easily implement VMStackWalker I think instead of this
workaround using the system class loader. But I wanted this patch to be
as simple as possible to get this in asap.

2005-11-18  Mark Wielaard  <mark@klomp.org>

    * standard.omit.in: Remove javax/rmi, org/omg, gnu/CORBA and
    gnu/javax/rmi.
    * scripts/makemake.tcl: Set javax/rmi, org/omg, gnu/CORBA and
    gnu/javax/rmi to bc.
    * gnu/CORBA/ObjectCreator.java: New override file for missing
    VMStackWalker issue.
    * gnu/CORBA/DynAn/gnuDynValue.java: New override file for bug #24938
    * gnu/CORBA/DynAn/RecordAny.java: Likewise
    * sources.am: Regenerated.
    * Makefile.in: Regenerated

With this I can run the cool swing/Corba example game from GNU
Classpath. OK for the trunk and new 4.1 branch?

Cheers,

Mark

[-- Attachment #1.2: enable-corba.patch --]
[-- Type: text/x-patch, Size: 43514 bytes --]

Index: scripts/makemake.tcl
===================================================================
--- scripts/makemake.tcl	(revision 107195)
+++ scripts/makemake.tcl	(working copy)
@@ -46,6 +46,10 @@
 set package_map(gnu/javax/sound/midi) bc
 set package_map(org/xml) bc
 set package_map(org/w3c) bc
+set package_map(javax/rmi) bc
+set package_map(org/omg) bc
+set package_map(gnu/CORBA) bc
+set package_map(gnu/javax/rmi) bc
 
 # This is handled specially by the Makefile.
 # We still want it byte-compiled so it isn't in the .omit file.
Index: gnu/CORBA/ObjectCreator.java
===================================================================
--- gnu/CORBA/ObjectCreator.java	(revision 0)
+++ gnu/CORBA/ObjectCreator.java	(revision 0)
@@ -0,0 +1,596 @@
+/* ObjectCreator.java --
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.CORBA;
+
+import gnu.CORBA.CDR.UnknownExceptionCtxHandler;
+import gnu.CORBA.CDR.BufferredCdrInput;
+import gnu.CORBA.CDR.BufferedCdrOutput;
+import gnu.CORBA.CDR.AbstractCdrInput;
+import gnu.CORBA.GIOP.ServiceContext;
+import gnu.CORBA.typecodes.RecordTypeCode;
+// GCJ LOCAL - We don't have this yet.
+// import gnu.classpath.VMStackWalker;
+
+import org.omg.CORBA.Any;
+import org.omg.CORBA.CompletionStatus;
+import org.omg.CORBA.CompletionStatusHelper;
+import org.omg.CORBA.MARSHAL;
+import org.omg.CORBA.SystemException;
+import org.omg.CORBA.TCKind;
+import org.omg.CORBA.UNKNOWN;
+import org.omg.CORBA.UserException;
+import org.omg.CORBA.portable.IDLEntity;
+import org.omg.CORBA.portable.InputStream;
+import org.omg.CORBA.portable.OutputStream;
+import org.omg.CORBA.portable.ValueBase;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import javax.rmi.CORBA.Util;
+
+/**
+ * Creates java objects from the agreed IDL names for the simple case when the
+ * CORBA object is directly mapped into the locally defined java class.
+ * 
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class ObjectCreator
+{
+  /**
+   * The standard OMG prefix.
+   */
+  public static final String OMG_PREFIX = "omg.org/";
+
+  /**
+   * The standard java prefix.
+   */
+  public static final String JAVA_PREFIX = "org.omg.";
+
+  /**
+   * The prefix for classes that are placed instide the gnu.CORBA namespace.
+   */
+  public static final String CLASSPATH_PREFIX = "gnu.CORBA.";
+
+  /**
+   * Maps classes to they IDL or RMI names. Computing RMI name is an expensive
+   * operations, so frequently used RMI keys are reused. The map must be weak to
+   * ensure that the class can be unloaded, when applicable.
+   */
+  public static Map m_names = new WeakHashMap();
+
+  /**
+   * Maps IDL strings into known classes. The map must be weak to ensure that
+   * the class can be unloaded, when applicable.
+   */
+  public static Map m_classes = new WeakHashMap();
+
+  /**
+   * Maps IDL types to they helpers.
+   */
+  public static Map m_helpers = new WeakHashMap();
+
+  /**
+   * Try to instantiate an object with the given IDL name. The object must be
+   * mapped to the local java class. The omg.org domain must be mapped into the
+   * object in either org/omg or gnu/CORBA namespace.
+   * 
+   * @param IDL name
+   * @return instantiated object instance or null if no such available.
+   */
+  public static java.lang.Object createObject(String idl, String suffix)
+  {
+    synchronized (m_classes)
+      {
+        Class known = (Class) (suffix == null ? m_classes.get(idl)
+          : m_classes.get(idl + 0xff + suffix));
+        Object object;
+
+        if (known != null)
+          {
+            try
+              {
+                return known.newInstance();
+              }
+            catch (Exception ex)
+              {
+                RuntimeException rex = new RuntimeException(idl + " suffix "
+                  + suffix, ex);
+                throw rex;
+              }
+          }
+        else
+          {
+            if (suffix == null)
+              suffix = "";
+            try
+              {
+                known = forName(toClassName(JAVA_PREFIX, idl) + suffix);
+                object = known.newInstance();
+              }
+            catch (Exception ex)
+              {
+                try
+                  {
+                    known = forName(toClassName(CLASSPATH_PREFIX, idl)
+                      + suffix);
+                    object = known.newInstance();
+                  }
+                catch (Exception exex)
+                  {
+                    return null;
+                  }
+              }
+            m_classes.put(idl + 0xff + suffix, known);
+            return object;
+          }
+      }
+  }
+
+  /**
+   * Read the system exception from the given stream.
+   * 
+   * @param input the CDR stream to read from.
+   * @param contexts the service contexts in request/reply header/
+   * 
+   * @return the exception that has been stored in the stream (IDL name, minor
+   * code and completion status).
+   */
+  public static SystemException readSystemException(InputStream input,
+    ServiceContext[] contexts)
+  {
+    SystemException exception;
+
+    String idl = input.read_string();
+    int minor = input.read_ulong();
+    CompletionStatus completed = CompletionStatusHelper.read(input);
+
+    try
+      {
+        exception = (SystemException) createObject(idl, null);
+        exception.minor = minor;
+        exception.completed = completed;
+      }
+    catch (Exception ex)
+      {
+        UNKNOWN u = new UNKNOWN("Unsupported system exception " + idl, minor,
+          completed);
+        u.initCause(ex);
+        throw u;
+      }
+
+    try
+      {
+        // If UnknownExceptionInfo is present in the contexts, read it and
+        // set as a cause of this exception.
+        ServiceContext uEx = ServiceContext.find(
+          ServiceContext.UnknownExceptionInfo, contexts);
+
+        if (uEx != null)
+          {
+            BufferredCdrInput in = new BufferredCdrInput(uEx.context_data);
+            in.setOrb(in.orb());
+            if (input instanceof AbstractCdrInput)
+              {
+                ((AbstractCdrInput) input).cloneSettings(in);
+              }
+
+            Throwable t = UnknownExceptionCtxHandler.read(in, contexts);
+            exception.initCause(t);
+          }
+      }
+    catch (Exception ex)
+      {
+        // Unsupported context format. Do not terminate as the user program may
+        // not need it.
+      }
+
+    return exception;
+  }
+
+  /**
+   * Reads the user exception, having the given Id, from the input stream. The
+   * id is expected to be in the form like
+   * 'IDL:test/org/omg/CORBA/ORB/communication/ourUserException:1.0'
+   * 
+   * @param idl the exception idl name.
+   * @param input the stream to read from.
+   * 
+   * @return the loaded exception.
+   * @return null if the helper class cannot be found.
+   */
+  public static UserException readUserException(String idl, InputStream input)
+  {
+    try
+      {
+        Class helperClass = findHelper(idl);
+
+        Method read = helperClass.getMethod("read",
+          new Class[] { org.omg.CORBA.portable.InputStream.class });
+
+        return (UserException) read.invoke(null, new Object[] { input });
+      }
+    catch (MARSHAL mex)
+      {
+        // This one is ok to throw
+        throw mex;
+      }
+    catch (Exception ex)
+      {
+        ex.printStackTrace();
+        return null;
+      }
+  }
+
+  /**
+   * Gets the helper class name from the string like
+   * 'IDL:test/org/omg/CORBA/ORB/communication/ourUserException:1.0'
+   * 
+   * @param IDL the idl name.
+   */
+  public static String toHelperName(String IDL)
+  {
+    String s = IDL;
+    int a = s.indexOf(':') + 1;
+    int b = s.lastIndexOf(':');
+
+    s = IDL.substring(a, b);
+
+    if (s.startsWith(OMG_PREFIX))
+      s = JAVA_PREFIX + s.substring(OMG_PREFIX.length());
+
+    return s.replace('/', '.') + "Helper";
+  }
+
+  /**
+   * Writes the system exception data to CDR output stream.
+   * 
+   * @param output a stream to write data to.
+   * @param ex an exception to write.
+   */
+  public static void writeSystemException(OutputStream output,
+    SystemException ex)
+  {
+    String exIDL = getRepositoryId(ex.getClass());
+    output.write_string(exIDL);
+    output.write_ulong(ex.minor);
+    CompletionStatusHelper.write(output, ex.completed);
+  }
+
+  /**
+   * Converts the given IDL name to class name.
+   * 
+   * @param IDL the idl name.
+   * 
+   */
+  protected static String toClassName(String prefix, String IDL)
+  {
+    String s = IDL;
+    int a = s.indexOf(':') + 1;
+    int b = s.lastIndexOf(':');
+
+    s = IDL.substring(a, b);
+
+    if (s.startsWith(OMG_PREFIX))
+      s = prefix + s.substring(OMG_PREFIX.length());
+
+    return s.replace('/', '.');
+  }
+
+  /**
+   * Converts the given IDL name to class name and tries to load the matching
+   * class. The OMG prefix (omg.org) is replaced by the java prefix org.omg. No
+   * other prefixes are added.
+   * 
+   * @param IDL the idl name.
+   * 
+   * @return the matching class or null if no such is available.
+   */
+  public static Class Idl2class(String IDL)
+  {
+    synchronized (m_classes)
+      {
+        Class c = (Class) m_classes.get(IDL);
+
+        if (c != null)
+          return c;
+        else
+          {
+            String s = IDL;
+            int a = s.indexOf(':') + 1;
+            int b = s.lastIndexOf(':');
+
+            s = IDL.substring(a, b);
+
+            if (s.startsWith(OMG_PREFIX))
+              s = JAVA_PREFIX + s.substring(OMG_PREFIX.length());
+
+            String cn = s.replace('/', '.');
+
+            try
+              {
+                c = forName(cn);
+                m_classes.put(IDL, c);
+                return c;
+              }
+            catch (ClassNotFoundException ex)
+              {
+                return null;
+              }
+          }
+      }
+  }
+
+  /**
+   * Converts the given IDL name to class name, tries to load the matching class
+   * and create an object instance with parameterless constructor. The OMG
+   * prefix (omg.org) is replaced by the java prefix org.omg. No other prefixes
+   * are added.
+   * 
+   * @param IDL the idl name.
+   * 
+   * @return instantiated object instance or null if such attempt was not
+   * successful.
+   */
+  public static java.lang.Object Idl2Object(String IDL)
+  {
+    Class cx = Idl2class(IDL);
+
+    try
+      {
+        if (cx != null)
+          return cx.newInstance();
+        else
+          return null;
+      }
+    catch (Exception ex)
+      {
+        return null;
+      }
+  }
+
+  /**
+   * Convert the class name to IDL or RMI name (repository id). If the class
+   * inherits from IDLEntity, ValueBase or SystemException, returns repository
+   * Id in the IDL:(..) form. If it does not, returns repository Id in the
+   * RMI:(..) form.
+   * 
+   * @param cx the class for that the name must be computed.
+   * 
+   * @return the idl or rmi name.
+   */
+  public static synchronized String getRepositoryId(Class cx)
+  {
+    String name = (String) m_names.get(cx);
+    if (name != null)
+      return name;
+
+    String cn = cx.getName();
+    if (!(IDLEntity.class.isAssignableFrom(cx)
+      || ValueBase.class.isAssignableFrom(cx) || SystemException.class.isAssignableFrom(cx)))
+      {
+        // Not an IDL entity.
+        name = Util.createValueHandler().getRMIRepositoryID(cx);
+      }
+    else
+      {
+        if (cn.startsWith(JAVA_PREFIX))
+          cn = OMG_PREFIX
+            + cn.substring(JAVA_PREFIX.length()).replace('.', '/');
+        else if (cn.startsWith(CLASSPATH_PREFIX))
+          cn = OMG_PREFIX
+            + cn.substring(CLASSPATH_PREFIX.length()).replace('.', '/');
+
+        name = "IDL:" + cn + ":1.0";
+      }
+    m_names.put(cx, name);
+    return name;
+  }
+
+  /**
+   * Insert the passed parameter into the given Any, assuming that the helper
+   * class is available. The helper class must have the "Helper" suffix and be
+   * in the same package as the class of the object being inserted.
+   * 
+   * @param into the target to insert.
+   * 
+   * @param object the object to insert. It can be any object as far as the
+   * corresponding helper is provided.
+   * 
+   * @return true on success, false otherwise.
+   */
+  public static boolean insertWithHelper(Any into, Object object)
+  {
+    try
+      {
+        String helperClassName = object.getClass().getName() + "Helper";
+        Class helperClass = forName(helperClassName);
+
+        Method insert = helperClass.getMethod("insert", new Class[] {
+          Any.class, object.getClass() });
+
+        insert.invoke(null, new Object[] { into, object });
+
+        return true;
+      }
+    catch (Exception exc)
+      {
+        // Failed due some reason.
+        return false;
+      }
+  }
+
+  /**
+   * Insert the system exception into the given Any.
+   */
+  public static boolean insertSysException(Any into, SystemException exception)
+  {
+    try
+      {
+        BufferedCdrOutput output = new BufferedCdrOutput();
+
+        String m_exception_id = getRepositoryId(exception.getClass());
+        output.write_string(m_exception_id);
+        output.write_ulong(exception.minor);
+        CompletionStatusHelper.write(output, exception.completed);
+
+        String name = getDefaultName(m_exception_id);
+
+        GeneralHolder h = new GeneralHolder(output);
+
+        into.insert_Streamable(h);
+
+        RecordTypeCode r = new RecordTypeCode(TCKind.tk_except);
+        r.setId(m_exception_id);
+        r.setName(name);
+        into.type(r);
+
+        return true;
+      }
+    catch (Exception ex)
+      {
+        ex.printStackTrace();
+        return false;
+      }
+  }
+
+  /**
+   * Get the type name from the IDL string.
+   */
+  public static String getDefaultName(String idl)
+  {
+    int f1 = idl.lastIndexOf("/");
+    int p1 = (f1 < 0) ? 0 : f1;
+    int p2 = idl.indexOf(":", p1);
+    if (p2 < 0)
+      p2 = idl.length();
+
+    String name = idl.substring(f1 + 1, p2);
+    return name;
+  }
+
+  /**
+   * Insert this exception into the given Any. On failure, insert the UNKNOWN
+   * exception.
+   */
+  public static void insertException(Any into, Throwable exception)
+  {
+    boolean ok = false;
+    if (exception instanceof SystemException)
+      ok = insertSysException(into, (SystemException) exception);
+    else if (exception instanceof UserException)
+      ok = insertWithHelper(into, exception);
+
+    if (!ok)
+      ok = insertSysException(into, new UNKNOWN());
+    if (!ok)
+      throw new InternalError("Exception wrapping broken");
+  }
+
+  /**
+   * Find helper for the class with the given name.
+   */
+  public static Class findHelper(String idl)
+  {
+    synchronized (m_helpers)
+      {
+        Class c = (Class) m_helpers.get(idl);
+        if (c != null)
+          return c;
+        try
+          {
+            String helper = toHelperName(idl);
+            c = forName(helper);
+
+            m_helpers.put(idl, c);
+            return c;
+          }
+        catch (Exception ex)
+          {
+            return null;
+          }
+      }
+  }
+  
+  /**
+   * Load the class with the given name. This method tries to use the context
+   * class loader first. If this fails, it searches for the suitable class
+   * loader in the caller stack trace. This method is a central point where all
+   * requests to find a class by name are delegated.
+   */
+  public static Class forName(String className) throws ClassNotFoundException
+  {
+    try
+      {
+        return Class.forName(className, true,
+                             Thread.currentThread().getContextClassLoader());
+      }
+    catch (ClassNotFoundException nex)
+      {
+        /**
+         * Returns the first user defined class loader on the call stack, or
+         * null when no non-null class loader was found.
+         */
+
+// GCJ LOCAL - We don't have VMStackWalker yet.
+// We only try the SystemClassLoader for now.
+//        Class[] ctx = VMStackWalker.getClassContext();
+//        for (int i = 0; i < ctx.length; i++)
+//          {
+//            // Since we live in a class loaded by the bootstrap
+//            // class loader, getClassLoader is safe to call without
+//            // needing to be wrapped in a privileged action.
+//            ClassLoader cl = ctx[i].getClassLoader();
+	    ClassLoader cl = ClassLoader.getSystemClassLoader();
+            try
+              {
+                if (cl != null)
+                  return Class.forName(className, true, cl);
+              }
+            catch (ClassNotFoundException nex2)
+              {
+                // Try next.
+              }
+//          }
+
+      }
+    throw new ClassNotFoundException(className);
+  }
+}
Index: gnu/CORBA/DynAn/gnuDynValue.java
===================================================================
--- gnu/CORBA/DynAn/gnuDynValue.java	(revision 0)
+++ gnu/CORBA/DynAn/gnuDynValue.java	(revision 0)
@@ -0,0 +1,386 @@
+/* gnuDynValue.java --
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.CORBA.DynAn;
+
+import gnu.CORBA.Minor;
+import gnu.CORBA.Unexpected;
+
+import org.omg.CORBA.Any;
+import org.omg.CORBA.BAD_PARAM;
+import org.omg.CORBA.MARSHAL;
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.TCKind;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.VM_TRUNCATABLE;
+import org.omg.CORBA.portable.OutputStream;
+import org.omg.CORBA.portable.ValueFactory;
+import org.omg.DynamicAny.DynAny;
+import org.omg.DynamicAny.DynAnyPackage.InvalidValue;
+import org.omg.DynamicAny.DynAnyPackage.TypeMismatch;
+import org.omg.DynamicAny.DynStruct;
+import org.omg.DynamicAny.DynValue;
+import org.omg.DynamicAny.DynValueCommon;
+import org.omg.DynamicAny.DynValueOperations;
+import org.omg.DynamicAny.NameDynAnyPair;
+import org.omg.DynamicAny.NameValuePair;
+
+import java.io.Serializable;
+
+/**
+ * Implementation of DynValue.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class gnuDynValue extends RecordAny implements DynValue,
+  Serializable
+{
+  /**
+   * Use serialVersionUID for interoperability.
+   */
+  private static final long serialVersionUID = 1;
+
+  /**
+   * If true, the value of this ValueType is set to null.
+   */
+  boolean isNull;
+
+  /**
+   * Create an instance.
+   */
+  public gnuDynValue(TypeCode oType, TypeCode aType,
+    gnuDynAnyFactory aFactory, ORB anOrb
+  )
+  {
+    super(oType, aType, aFactory, anOrb);
+
+    // Initialise fields. The array of fields also includes all inherited
+    // fields.
+    try
+      {
+        array = new DynAny[ final_type.member_count() ];
+        fNames = new String[ array.length ];
+        for (int i = 0; i < array.length; i++)
+          {
+            array [ i ] =
+              factory.create_dyn_any_from_type_code(final_type.member_type(i));
+            fNames [ i ] = final_type.member_name(i);
+          }
+
+        // Search of inherited members.
+        if (final_type.type_modifier() == VM_TRUNCATABLE.value)
+          {
+            TypeCode parent = final_type.concrete_base_type();
+            DynAny ancestor = factory.create_dyn_any_from_type_code(parent);
+
+            if (ancestor instanceof DynValue)
+              {
+                // Add members of ancestor in front of the curren members.
+                DynValue anc = (DynValue) ancestor;
+                anc.set_to_value();
+
+                NameDynAnyPair[] aar = anc.get_members_as_dyn_any();
+                inheritFields(aar);
+              }
+            else if (ancestor instanceof DynStruct)
+              {
+                // Add members of ancestor in front of the curren members.
+                DynStruct anc = (DynStruct) ancestor;
+                NameDynAnyPair[] aar = anc.get_members_as_dyn_any();
+                inheritFields(aar);
+              }
+            else
+              throw new BAD_PARAM("The parent of " + final_type.id() + ", " +
+                parent.id() + ", is not structure nor value."
+              );
+          }
+      }
+    catch (Exception e)
+      {
+        throw new Unexpected(e);
+      }
+
+    set_to_null();
+  }
+
+  /**
+   * Inherit the provided fields.
+   */
+  private void inheritFields(NameDynAnyPair[] aar)
+  {
+    DynAny[] nArray = new DynAny[ array.length + aar.length ];
+    String[] nNames = new String[ array.length + aar.length ];
+    int p = 0;
+    for (int i = 0; i < aar.length; i++)
+      {
+        nArray [ p ] = aar [ i ].value;
+        nNames [ p ] = aar [ i ].id;
+        p++;
+      }
+
+    for (int i = 0; i < array.length; i++)
+      {
+        nArray [ p ] = array [ i ];
+        nNames [ p ] = fNames [ i ];
+        p++;
+      }
+
+    array = nArray;
+    fNames = nNames;
+  }
+
+  /** @inheritDoc */
+  public TCKind current_member_kind() throws TypeMismatch, InvalidValue
+  {
+    if (isNull)
+      throw new TypeMismatch(ISNULL);
+    else
+      return super.current_member_kind();
+  }
+  ;
+
+  /** @inheritDoc */
+  public String current_member_name() throws TypeMismatch, InvalidValue
+  {
+    if (isNull)
+      throw new TypeMismatch(ISNULL);
+    else
+      return super.current_member_name();
+  }
+  ;
+
+  /** @inheritDoc */
+  public NameDynAnyPair[] get_members_as_dyn_any() throws InvalidValue
+  {
+    if (isNull)
+      throw new InvalidValue(ISNULL);
+    return super.gnu_get_members_as_dyn_any();
+  }
+  ;
+
+  /** @inheritDoc */
+  public NameValuePair[] get_members() throws InvalidValue
+  {
+    if (isNull)
+      throw new InvalidValue(ISNULL);
+    else
+      return super.gnu_get_members();
+  }
+  ;
+
+  /** @inheritDoc */
+  public void set_members_as_dyn_any(NameDynAnyPair[] value)
+    throws TypeMismatch, InvalidValue
+  {
+    super.set_members_as_dyn_any(value);
+    isNull = false;
+  }
+  ;
+
+  /** @inheritDoc */
+  public void set_members(NameValuePair[] value)
+    throws TypeMismatch, InvalidValue
+  {
+    super.set_members(value);
+    isNull = false;
+  }
+  ;
+
+  /** @inheritDoc */
+  public boolean is_null()
+  {
+    return isNull;
+  }
+
+  /** @inheritDoc */
+  public void set_to_null()
+  {
+    isNull = true;
+    valueChanged();
+  }
+
+  /** @inheritDoc */
+  public void set_to_value()
+  {
+    isNull = false;
+    valueChanged();
+  }
+
+  /**
+   * Create a new instance.
+   */
+  protected RecordAny newInstance(TypeCode oType, TypeCode aType,
+    gnuDynAnyFactory aFactory, ORB anOrb
+  )
+  {
+    gnuDynValue v = new gnuDynValue(oType, aType, aFactory, anOrb);
+    if (isNull)
+      v.set_to_null();
+    else
+      v.set_to_value();
+    return v;
+  }
+
+  /**
+   * Compare for equality, minding null values.
+   */
+  public boolean equal(DynAny other)
+  {
+    if (other instanceof DynValueOperations)
+      {
+        DynValueCommon o = (DynValueCommon) other;
+        if (isNull)
+          return o.is_null() && o.type().equal(official_type);
+        else
+          return !o.is_null() && record_equal(other); // GCJ LOCAL bug #24938
+      }
+    else
+      return false;
+  }
+
+  /**
+   * Get the focused component, throwing exception if the current value is null.
+   */
+  protected DynAny focused() throws InvalidValue, TypeMismatch
+  {
+    if (isNull)
+      throw new TypeMismatch(ISNULL);
+    else
+      return super.focused();
+  }
+
+  /**
+   * Convert into Any.
+   */
+  public Any to_any()
+  {
+    if (isNull)
+      {
+        Any a0 = createAny();
+        a0.type(orb.get_primitive_tc(TCKind.tk_null));
+        return a0;
+      }
+    else
+      {
+        try
+          {
+            ValueFactory factory =
+              ((org.omg.CORBA_2_3.ORB) orb).lookup_value_factory(official_type.id());
+            if (factory == null)
+              {
+                MARSHAL m = new MARSHAL("Factory for " + official_type.id() +
+                " not registered.");
+                m.minor = Minor.Factory;
+                throw m;
+              }
+
+            OutputStream out = orb.create_output_stream();
+
+            for (int i = 0; i < array.length; i++)
+              array [ i ].to_any().write_value(out);
+
+            org.omg.CORBA_2_3.portable.InputStream in =
+              (org.omg.CORBA_2_3.portable.InputStream) out.create_input_stream();
+            Serializable v = factory.read_value(in);
+
+            Any g = createAny();
+            g.type(official_type);
+            g.insert_Value(v, official_type);
+
+            return g;
+          }
+        catch (Exception e)
+          {
+            throw new Unexpected(e);
+          }
+      }
+  }
+
+  /** @inheritDoc */
+  public void assign(DynAny from) throws TypeMismatch
+  {
+    checkType(official_type, from.type());
+
+    if (from instanceof DynValue)
+      {
+        DynValue other = (DynValue) from;
+        if (other.is_null())
+          set_to_null();
+        else
+          {
+            set_to_value();
+            try
+              {
+                DynValueOperations src = (DynValueOperations) from;
+                set_members_as_dyn_any(src.get_members_as_dyn_any());
+              }
+            catch (InvalidValue e)
+              {
+                TypeMismatch t = new TypeMismatch("Invalid value");
+                t.initCause(e);
+                throw t;
+              }
+          }
+      }
+    else
+      throw new TypeMismatch("Not a DynValue");
+  }
+
+  /**
+   * Get the number of components.
+   */
+  public int component_count()
+  {
+    return isNull ? 0 : record_component_count(); // GCJ LOCAL bug #24938
+  }
+
+  /** {@inheritDoc} */
+  public Serializable get_val() throws TypeMismatch, InvalidValue
+  {
+    return to_any().extract_Value();
+  }
+
+  /** {@inheritDoc} */
+  public void insert_val(Serializable a_x) throws InvalidValue, TypeMismatch
+  {
+    Any a = to_any();
+    a.insert_Value(a_x);
+    from_any(a);
+    valueChanged();
+  }
+}
Index: gnu/CORBA/DynAn/RecordAny.java
===================================================================
--- gnu/CORBA/DynAn/RecordAny.java	(revision 0)
+++ gnu/CORBA/DynAn/RecordAny.java	(revision 0)
@@ -0,0 +1,416 @@
+/* RecordAny.java --
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath 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.
+
+GNU Classpath 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 GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.CORBA.DynAn;
+
+import gnu.CORBA.Unexpected;
+import gnu.CORBA.HolderLocator;
+
+import org.omg.CORBA.Any;
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.TCKind;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.TypeCodePackage.BadKind;
+import org.omg.CORBA.TypeCodePackage.Bounds;
+import org.omg.CORBA.portable.Streamable;
+import org.omg.DynamicAny.DynAny;
+import org.omg.DynamicAny.DynAnyPackage.InvalidValue;
+import org.omg.DynamicAny.DynAnyPackage.TypeMismatch;
+import org.omg.DynamicAny.DynStruct;
+import org.omg.DynamicAny.DynValueCommonOperations;
+import org.omg.DynamicAny.NameDynAnyPair;
+import org.omg.DynamicAny.NameValuePair;
+
+import java.io.Serializable;
+
+import java.lang.reflect.Field;
+
+/**
+ * A shared base for both dynamic structure an dynamic value final_type.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public abstract class RecordAny
+  extends DivideableAny
+  implements DynAny, Serializable
+{
+  /**
+   * Use serialVersionUID for interoperability.
+   */
+  private static final long serialVersionUID = 1;
+  String[] fNames;
+
+  /**
+   * Creates the structure with the given typecode.
+   *
+   * @param fields The DynAny's, representing the fields of the structure.
+   */
+  public RecordAny(TypeCode oType, TypeCode aType,
+                        gnuDynAnyFactory aFactory, ORB anOrb
+                       )
+  {
+    super(oType, aType, aFactory, anOrb);
+  }
+
+  /** @inheritDoc */
+  public TCKind current_member_kind()
+                             throws TypeMismatch, InvalidValue
+  {
+    if (array.length == 0)
+      throw new TypeMismatch(EMPTY);
+    try
+      {
+        return final_type.member_type(pos).kind();
+      }
+    catch (BadKind e)
+      {
+        TypeMismatch t = new TypeMismatch();
+        t.initCause(e);
+        throw t;
+      }
+    catch (Bounds e)
+      {
+        InvalidValue t = new InvalidValue();
+        t.initCause(e);
+        throw t;
+      }
+  }
+
+  /** @inheritDoc */
+  public String current_member_name()
+                             throws TypeMismatch, InvalidValue
+  {
+    if (array.length == 0)
+      throw new TypeMismatch(EMPTY);
+    try
+      {
+        return final_type.member_name(pos);
+      }
+    catch (BadKind e)
+      {
+        TypeMismatch t = new TypeMismatch();
+        t.initCause(e);
+        throw t;
+      }
+    catch (Bounds e)
+      {
+        InvalidValue t = new InvalidValue();
+        t.initCause(e);
+        throw t;
+      }
+  }
+
+  /**
+   * Get content of the structure. This method must be defined on a different
+   * name because get_members_as_dyn_any() throws exception only in some of the
+   * supported interfaces.
+   */
+  public NameDynAnyPair[] gnu_get_members_as_dyn_any()
+  {
+    NameDynAnyPair[] r = new NameDynAnyPair[ array.length ];
+    for (int i = 0; i < r.length; i++)
+      {
+        try
+          {
+            r [ i ] = new NameDynAnyPair(fNames [ i ], array [ i ]);
+          }
+        catch (Exception ex)
+          {
+            throw new Unexpected(ex);
+          }
+      }
+    return r;
+  }
+
+  /**
+   * Get content of the structure. This method must be defined on a different
+   * name because get_members_as_dyn_any() throws exception only in some of the
+   * supported interfaces.
+   */
+  public NameValuePair[] gnu_get_members()
+  {
+    NameValuePair[] r = new NameValuePair[ array.length ];
+    for (int i = 0; i < r.length; i++)
+      {
+        try
+          {
+            r [ i ] = new NameValuePair(fNames [ i ], array [ i ].to_any());
+          }
+        catch (Exception ex)
+          {
+            throw new Unexpected(ex);
+          }
+      }
+    return r;
+  }
+
+  /**
+   * Set members from the provided array.
+   */
+  public void set_members_as_dyn_any(NameDynAnyPair[] value)
+                              throws TypeMismatch, InvalidValue
+  {
+    if (value.length != array.length)
+      throw new InvalidValue(sizeMismatch(array.length, value.length));
+
+    for (int i = 0; i < value.length; i++)
+      {
+        DynAny dynAny = value [ i ].value;
+        checkType(dynAny.type(), i);
+        checkName(value [ i ].id, i);
+
+        array [ i ] = dynAny;
+      }
+    pos = 0;
+  }
+
+  /**
+   * Check the name at the given position ("" matches everything).
+   */
+  private void checkName(String xName, int i)
+                  throws TypeMismatch
+  {
+    if (xName.length() > 0 && fNames [ i ].length() > 0)
+      if (!xName.equals(fNames [ i ]))
+        throw new TypeMismatch("Field name mismatch " + xName + " expected " +
+                               fNames [ i ]
+                              );
+  }
+
+  /**
+   * Check the type at the given position.
+   */
+  private void checkType(TypeCode t, int i)
+                  throws TypeMismatch
+  {
+    if (!array [ i ].type().equal(t))
+      throw new TypeMismatch(typeMismatch(array [ i ].type(), t) + " field " +
+                             i
+                            );
+  }
+
+  /**
+   * Set members from the provided array.
+   */
+  public void set_members(NameValuePair[] value)
+                   throws TypeMismatch, InvalidValue
+  {
+    if (value.length != array.length)
+      throw new InvalidValue(sizeMismatch(array.length, value.length));
+
+    for (int i = 0; i < value.length; i++)
+      {
+        Any any = value [ i ].value;
+        checkType(any.type(), i);
+        checkName(value [ i ].id, i);
+
+        array [ i ].from_any(any);
+      }
+    pos = 0;
+  }
+
+  /** @inheritDoc */
+  public void assign(DynAny from)
+              throws TypeMismatch
+  {
+    checkType(official_type, from.type());
+    if (from instanceof DynStruct)
+      {
+        try
+          {
+            set_members_as_dyn_any(((DynStruct) from).get_members_as_dyn_any());
+          }
+        catch (InvalidValue e)
+          {
+            TypeMismatch t = new TypeMismatch("Invalid value");
+            t.initCause(e);
+            throw t;
+          }
+      }
+    else
+      throw new TypeMismatch("Not a DynStruct");
+  }
+
+  /**
+   * Create a copy.
+   */
+  public DynAny copy()
+  {
+    DynAny[] c = new DynAny[ array.length ];
+    for (int i = 0; i < c.length; i++)
+      {
+        c [ i ] = array [ i ].copy();
+      }
+
+    RecordAny d = newInstance(official_type, final_type, factory, orb);
+    d.array = c;
+    return d;
+  }
+
+  /**
+   * Create a new instance when copying.
+   */
+  protected abstract RecordAny newInstance(TypeCode oType, TypeCode aType,
+                                                gnuDynAnyFactory aFactory,
+                                                ORB anOrb
+                                               );
+
+  /**
+   * Done via reflection.
+   */
+  public Any to_any()
+  {
+    try
+      {
+        Streamable sHolder = HolderLocator.createHolder(official_type);
+
+        Class sHolderClass = sHolder.getClass();
+        Field sHolderValue = sHolderClass.getField("value");
+        Class sClass = sHolderValue.getType();
+
+        Object structure = sClass.newInstance();
+        Object member;
+        Any am;
+        Field vread;
+        Field vwrite;
+        Streamable memberHolder;
+
+        for (int i = 0; i < array.length; i++)
+          {
+            am = array [ i ].to_any();
+            memberHolder = am.extract_Streamable();
+            vwrite = structure.getClass().getField(final_type.member_name(i));
+            vread = memberHolder.getClass().getField("value");
+            member = vread.get(memberHolder);
+            vwrite.set(structure, member);
+          }
+
+        Any g = createAny();
+        sHolderValue.set(sHolder, structure);
+        g.insert_Streamable(sHolder);
+        g.type(official_type);
+        return g;
+      }
+    catch (Exception e)
+      {
+        throw new Unexpected(e);
+      }
+  }
+
+  /**
+   * Done via reflection.
+   */
+  public void from_any(Any an_any)
+                throws TypeMismatch, InvalidValue
+  {
+    checkType(official_type, an_any.type());
+    try
+      {
+        Streamable s = an_any.extract_Streamable();
+        if (s == null)
+          {
+            if (this instanceof DynValueCommonOperations)
+              {
+                ((DynValueCommonOperations) this).set_to_null();
+                return;
+              }
+            else
+              throw new InvalidValue(ISNULL);
+          }
+
+        Object structure = s.getClass().getField("value").get(s);
+        if (structure == null && (this instanceof DynValueCommonOperations))
+          {
+            ((DynValueCommonOperations) this).set_to_null();
+            return;
+          }
+
+        Any member;
+        Streamable holder;
+        Object field;
+        TypeCode fType;
+        Field fField;
+
+        for (int i = 0; i < array.length; i++)
+          {
+            fField = structure.getClass().getField(fNames [ i ]);
+            field = fField.get(structure);
+            fType = array [ i ].type();
+            holder = HolderLocator.createHolder(fType);
+
+            member = createAny();
+            holder.getClass().getField("value").set(holder, field);
+            member.insert_Streamable(holder);
+            member.type(fType);
+
+            array [ i ].from_any(member);
+          }
+
+        if (this instanceof DynValueCommonOperations)
+          ((DynValueCommonOperations) this).set_to_value();
+      }
+    catch (InvalidValue v)
+      {
+        throw v;
+      }
+    catch (NoSuchFieldException ex)
+      {
+        TypeMismatch v =
+          new TypeMismatch("holder value does not match typecode");
+        v.initCause(ex);
+        throw v;
+      }
+    catch (Exception ex)
+      {
+        TypeMismatch t = new TypeMismatch();
+        t.initCause(ex);
+        throw t;
+      }
+  }
+
+// GCJ LOCAL - package private delegates to work around bug in gnuDynValue.
+  int record_component_count()
+  {
+    return component_count();
+  }
+
+  boolean record_equal(DynAny o)
+  {
+    return equal(o);
+  }
+}
Index: standard.omit.in
===================================================================
--- standard.omit.in	(revision 107195)
+++ standard.omit.in	(working copy)
@@ -3,10 +3,6 @@
 java/lang/PosixProcess.java
 gnu/java/awt/peer/gtk/Test.java
 gnu/java/awt/peer/gtk/TestAWT.java
-javax/rmi
-org/omg
-gnu/CORBA
-gnu/javax/rmi
 gnu/java/nio/charset/iconv
 java/util/zip/DeflaterConstants.java
 java/util/zip/DeflaterEngine.java

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: RFC: Enabling Corba
  2005-11-19  0:04 RFC: Enabling Corba Mark Wielaard
@ 2005-11-20 19:10 ` Mark Wielaard
  2005-11-24 16:19   ` Mark Wielaard
  0 siblings, 1 reply; 5+ messages in thread
From: Mark Wielaard @ 2005-11-20 19:10 UTC (permalink / raw)
  To: java-patches; +Cc: tromey

[-- Attachment #1: Type: text/plain, Size: 807 bytes --]

On Sat, 2005-11-19 at 01:04 +0100, Mark Wielaard wrote:
> 2005-11-18  Mark Wielaard  <mark@klomp.org>
> 
>     * standard.omit.in: Remove javax/rmi, org/omg, gnu/CORBA and
>     gnu/javax/rmi.
>     * scripts/makemake.tcl: Set javax/rmi, org/omg, gnu/CORBA and
>     gnu/javax/rmi to bc.
>     * gnu/CORBA/ObjectCreator.java: New override file for missing
>     VMStackWalker issue.
>     * gnu/CORBA/DynAn/gnuDynValue.java: New override file for bug #24938
>     * gnu/CORBA/DynAn/RecordAny.java: Likewise
>     * sources.am: Regenerated.
>     * Makefile.in: Regenerated
> 
> With this I can run the cool swing/Corba example game from GNU
> Classpath. OK for the trunk and new 4.1 branch?

BTW I did bootstrap this on i686-pc-linux-gnu and
powerpc-unknown-linux-gnu.

Cheers,

Mark

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: RFC: Enabling Corba
  2005-11-20 19:10 ` Mark Wielaard
@ 2005-11-24 16:19   ` Mark Wielaard
  2005-11-25 19:22     ` Tom Tromey
  0 siblings, 1 reply; 5+ messages in thread
From: Mark Wielaard @ 2005-11-24 16:19 UTC (permalink / raw)
  To: java-patches; +Cc: tromey

[-- Attachment #1: Type: text/plain, Size: 906 bytes --]

On Sun, 2005-11-20 at 20:11 +0100, Mark Wielaard wrote:
> On Sat, 2005-11-19 at 01:04 +0100, Mark Wielaard wrote:
> > 2005-11-18  Mark Wielaard  <mark@klomp.org>
> > 
> >     * standard.omit.in: Remove javax/rmi, org/omg, gnu/CORBA and
> >     gnu/javax/rmi.
> >     * scripts/makemake.tcl: Set javax/rmi, org/omg, gnu/CORBA and
> >     gnu/javax/rmi to bc.
> >     * gnu/CORBA/ObjectCreator.java: New override file for missing
> >     VMStackWalker issue.
> >     * gnu/CORBA/DynAn/gnuDynValue.java: New override file for bug #24938
> >     * gnu/CORBA/DynAn/RecordAny.java: Likewise
> >     * sources.am: Regenerated.
> >     * Makefile.in: Regenerated
> > 
> > With this I can run the cool swing/Corba example game from GNU
> > Classpath. OK for the trunk and new 4.1 branch?
> 
> BTW I did bootstrap this on i686-pc-linux-gnu and
> powerpc-unknown-linux-gnu.

Ping. Any comments?

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: RFC: Enabling Corba
  2005-11-24 16:19   ` Mark Wielaard
@ 2005-11-25 19:22     ` Tom Tromey
  2005-11-26  0:53       ` Mark Wielaard
  0 siblings, 1 reply; 5+ messages in thread
From: Tom Tromey @ 2005-11-25 19:22 UTC (permalink / raw)
  To: Mark Wielaard; +Cc: java-patches, tromey

>>>>> "Mark" == Mark Wielaard <mark@klomp.org> writes:

>> >     * scripts/makemake.tcl: Set javax/rmi, org/omg, gnu/CORBA and
>> >     gnu/javax/rmi to bc.

Mark> Ping. Any comments?

This is ok.
I'd like to make sure we can eventually get rid of this override
though.  At the very least we need to update the existing PR to
account for this...

Tom

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: RFC: Enabling Corba
  2005-11-25 19:22     ` Tom Tromey
@ 2005-11-26  0:53       ` Mark Wielaard
  0 siblings, 0 replies; 5+ messages in thread
From: Mark Wielaard @ 2005-11-26  0:53 UTC (permalink / raw)
  To: tromey; +Cc: java-patches

[-- Attachment #1: Type: text/plain, Size: 420 bytes --]

Hi Tom,

On Fri, 2005-11-25 at 12:10 -0700, Tom Tromey wrote:
> This is ok.

Retested and committed to trunk and 4.1 branch.

> I'd like to make sure we can eventually get rid of this override
> though.  At the very least we need to update the existing PR to
> account for this...

I updated the bug report to mention the override files. And the commit
message references the bug number.

Cheers,

Mark

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2005-11-26  0:53 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-11-19  0:04 RFC: Enabling Corba Mark Wielaard
2005-11-20 19:10 ` Mark Wielaard
2005-11-24 16:19   ` Mark Wielaard
2005-11-25 19:22     ` Tom Tromey
2005-11-26  0:53       ` Mark Wielaard

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).