Karsten Hopp 48bd44
To: vim_dev@googlegroups.com
Karsten Hopp 48bd44
Subject: Patch 7.3.1047
Karsten Hopp 48bd44
Fcc: outbox
Karsten Hopp 48bd44
From: Bram Moolenaar <Bram@moolenaar.net>
Karsten Hopp 48bd44
Mime-Version: 1.0
Karsten Hopp 48bd44
Content-Type: text/plain; charset=UTF-8
Karsten Hopp 48bd44
Content-Transfer-Encoding: 8bit
Karsten Hopp 48bd44
------------
Karsten Hopp 48bd44
Karsten Hopp 48bd44
Patch 7.3.1047
Karsten Hopp 48bd44
Problem:    Python: dir() does not work properly.
Karsten Hopp 48bd44
Solution:   Python patch 8.  Add __dir__ method to all objects with custom
Karsten Hopp 48bd44
	    tp_getattr supplemented by __members__ attribute for at least
Karsten Hopp 48bd44
	    python-2* versions.  __members__ is not mentioned in python-3*
Karsten Hopp 48bd44
	    dir() output even if it is accessible. (ZyX)
Karsten Hopp 48bd44
Files:	    src/if_py_both.h, src/if_python3.c, src/if_python.c,
Karsten Hopp 48bd44
	    src/testdir/test86.in, src/testdir/test86.ok,
Karsten Hopp 48bd44
	    src/testdir/test87.in, src/testdir/test87.ok
Karsten Hopp 48bd44
Karsten Hopp 48bd44
Karsten Hopp 48bd44
*** ../vim-7.3.1046/src/if_py_both.h	2013-05-29 22:26:15.000000000 +0200
Karsten Hopp 48bd44
--- src/if_py_both.h	2013-05-29 22:29:26.000000000 +0200
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 117,122 ****
Karsten Hopp 48bd44
--- 117,175 ----
Karsten Hopp 48bd44
      return (char_u *) p;
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
+     static int
Karsten Hopp 48bd44
+ add_string(PyObject *list, char *s)
Karsten Hopp 48bd44
+ {
Karsten Hopp 48bd44
+     PyObject	*string;
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
+     if (!(string = PyString_FromString(s)))
Karsten Hopp 48bd44
+ 	return -1;
Karsten Hopp 48bd44
+     if (PyList_Append(list, string))
Karsten Hopp 48bd44
+     {
Karsten Hopp 48bd44
+ 	Py_DECREF(string);
Karsten Hopp 48bd44
+ 	return -1;
Karsten Hopp 48bd44
+     }
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
+     Py_DECREF(string);
Karsten Hopp 48bd44
+     return 0;
Karsten Hopp 48bd44
+ }
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
+     static PyObject *
Karsten Hopp 48bd44
+ ObjectDir(PyObject *self, char **attributes)
Karsten Hopp 48bd44
+ {
Karsten Hopp 48bd44
+     PyMethodDef	*method;
Karsten Hopp 48bd44
+     char	**attr;
Karsten Hopp 48bd44
+     PyObject	*r;
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
+     if (!(r = PyList_New(0)))
Karsten Hopp 48bd44
+ 	return NULL;
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
+     if (self)
Karsten Hopp 48bd44
+ 	for (method = self->ob_type->tp_methods ; method->ml_name != NULL ; ++method)
Karsten Hopp 48bd44
+ 	    if (add_string(r, (char *) method->ml_name))
Karsten Hopp 48bd44
+ 	    {
Karsten Hopp 48bd44
+ 		Py_DECREF(r);
Karsten Hopp 48bd44
+ 		return NULL;
Karsten Hopp 48bd44
+ 	    }
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
+     for (attr = attributes ; *attr ; ++attr)
Karsten Hopp 48bd44
+ 	if (add_string(r, *attr))
Karsten Hopp 48bd44
+ 	{
Karsten Hopp 48bd44
+ 	    Py_DECREF(r);
Karsten Hopp 48bd44
+ 	    return NULL;
Karsten Hopp 48bd44
+ 	}
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
+ #if PY_MAJOR_VERSION < 3
Karsten Hopp 48bd44
+     if (add_string(r, "__members__"))
Karsten Hopp 48bd44
+     {
Karsten Hopp 48bd44
+ 	Py_DECREF(r);
Karsten Hopp 48bd44
+ 	return NULL;
Karsten Hopp 48bd44
+     }
Karsten Hopp 48bd44
+ #endif
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
+     return r;
Karsten Hopp 48bd44
+ }
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
  /* Output buffer management
Karsten Hopp 48bd44
   */
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 132,137 ****
Karsten Hopp 48bd44
--- 185,201 ----
Karsten Hopp 48bd44
      long error;
Karsten Hopp 48bd44
  } OutputObject;
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
+ static char *OutputAttrs[] = {
Karsten Hopp 48bd44
+     "softspace",
Karsten Hopp 48bd44
+     NULL
Karsten Hopp 48bd44
+ };
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
+     static PyObject *
Karsten Hopp 48bd44
+ OutputDir(PyObject *self)
Karsten Hopp 48bd44
+ {
Karsten Hopp 48bd44
+     return ObjectDir(self, OutputAttrs);
Karsten Hopp 48bd44
+ }
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
      static int
Karsten Hopp 48bd44
  OutputSetattr(OutputObject *self, char *name, PyObject *val)
Karsten Hopp 48bd44
  {
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 291,296 ****
Karsten Hopp 48bd44
--- 355,361 ----
Karsten Hopp 48bd44
      {"write",	    (PyCFunction)OutputWrite,		METH_VARARGS,	""},
Karsten Hopp 48bd44
      {"writelines",  (PyCFunction)OutputWritelines,	METH_VARARGS,	""},
Karsten Hopp 48bd44
      {"flush",	    (PyCFunction)OutputFlush,		METH_NOARGS,	""},
Karsten Hopp 48bd44
+     {"__dir__",	    (PyCFunction)OutputDir,		METH_NOARGS,	""},
Karsten Hopp 48bd44
      { NULL,	    NULL,				0,		NULL}
Karsten Hopp 48bd44
  };
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 826,831 ****
Karsten Hopp 48bd44
--- 891,907 ----
Karsten Hopp 48bd44
      DESTRUCTOR_FINISH(self);
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
+ static char *DictionaryAttrs[] = {
Karsten Hopp 48bd44
+     "locked", "scope",
Karsten Hopp 48bd44
+     NULL
Karsten Hopp 48bd44
+ };
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
+     static PyObject *
Karsten Hopp 48bd44
+ DictionaryDir(PyObject *self)
Karsten Hopp 48bd44
+ {
Karsten Hopp 48bd44
+     return ObjectDir(self, DictionaryAttrs);
Karsten Hopp 48bd44
+ }
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
      static int
Karsten Hopp 48bd44
  DictionarySetattr(DictionaryObject *self, char *name, PyObject *val)
Karsten Hopp 48bd44
  {
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 985,991 ****
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  static struct PyMethodDef DictionaryMethods[] = {
Karsten Hopp 48bd44
      {"keys",	(PyCFunction)DictionaryListKeys,	METH_NOARGS,	""},
Karsten Hopp 48bd44
!     { NULL,	NULL,					0,		NULL }
Karsten Hopp 48bd44
  };
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  static PyTypeObject ListType;
Karsten Hopp 48bd44
--- 1061,1068 ----
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  static struct PyMethodDef DictionaryMethods[] = {
Karsten Hopp 48bd44
      {"keys",	(PyCFunction)DictionaryListKeys,	METH_NOARGS,	""},
Karsten Hopp 48bd44
!     {"__dir__",	(PyCFunction)DictionaryDir,		METH_NOARGS,	""},
Karsten Hopp 48bd44
!     { NULL,	NULL,					0,		NULL}
Karsten Hopp 48bd44
  };
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  static PyTypeObject ListType;
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 1331,1336 ****
Karsten Hopp 48bd44
--- 1408,1424 ----
Karsten Hopp 48bd44
      return (PyObject *)(self);
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
+ static char *ListAttrs[] = {
Karsten Hopp 48bd44
+     "locked",
Karsten Hopp 48bd44
+     NULL
Karsten Hopp 48bd44
+ };
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
+     static PyObject *
Karsten Hopp 48bd44
+ ListDir(PyObject *self)
Karsten Hopp 48bd44
+ {
Karsten Hopp 48bd44
+     return ObjectDir(self, ListAttrs);
Karsten Hopp 48bd44
+ }
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
      static int
Karsten Hopp 48bd44
  ListSetattr(ListObject *self, char *name, PyObject *val)
Karsten Hopp 48bd44
  {
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 1368,1375 ****
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  static struct PyMethodDef ListMethods[] = {
Karsten Hopp 48bd44
!     {"extend",	(PyCFunction)ListConcatInPlace,	METH_O,	""},
Karsten Hopp 48bd44
!     { NULL,	NULL,				0,	NULL }
Karsten Hopp 48bd44
  };
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  typedef struct
Karsten Hopp 48bd44
--- 1456,1464 ----
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  static struct PyMethodDef ListMethods[] = {
Karsten Hopp 48bd44
!     {"extend",	(PyCFunction)ListConcatInPlace,	METH_O,		""},
Karsten Hopp 48bd44
!     {"__dir__",	(PyCFunction)ListDir,		METH_NOARGS,	""},
Karsten Hopp 48bd44
!     { NULL,	NULL,				0,		NULL}
Karsten Hopp 48bd44
  };
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  typedef struct
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 1408,1413 ****
Karsten Hopp 48bd44
--- 1497,1513 ----
Karsten Hopp 48bd44
      DESTRUCTOR_FINISH(self);
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
+ static char *FunctionAttrs[] = {
Karsten Hopp 48bd44
+     "softspace",
Karsten Hopp 48bd44
+     NULL
Karsten Hopp 48bd44
+ };
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
+     static PyObject *
Karsten Hopp 48bd44
+ FunctionDir(PyObject *self)
Karsten Hopp 48bd44
+ {
Karsten Hopp 48bd44
+     return ObjectDir(self, FunctionAttrs);
Karsten Hopp 48bd44
+ }
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
      static PyObject *
Karsten Hopp 48bd44
  FunctionCall(FunctionObject *self, PyObject *argsObject, PyObject *kwargs)
Karsten Hopp 48bd44
  {
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 1472,1479 ****
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  static struct PyMethodDef FunctionMethods[] = {
Karsten Hopp 48bd44
!     {"__call__",    (PyCFunction)FunctionCall,	METH_VARARGS|METH_KEYWORDS, ""},
Karsten Hopp 48bd44
!     { NULL,	    NULL,			0,			   NULL}
Karsten Hopp 48bd44
  };
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  /*
Karsten Hopp 48bd44
--- 1572,1580 ----
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  static struct PyMethodDef FunctionMethods[] = {
Karsten Hopp 48bd44
!     {"__call__",(PyCFunction)FunctionCall,  METH_VARARGS|METH_KEYWORDS,	""},
Karsten Hopp 48bd44
!     {"__dir__",	(PyCFunction)FunctionDir,   METH_NOARGS,		""},
Karsten Hopp 48bd44
!     { NULL,	NULL,			0,				NULL}
Karsten Hopp 48bd44
  };
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  /*
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 1842,1847 ****
Karsten Hopp 48bd44
--- 1943,1959 ----
Karsten Hopp 48bd44
      DESTRUCTOR_FINISH(self);
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
+ static char *TabPageAttrs[] = {
Karsten Hopp 48bd44
+     "windows", "number", "vars", "window", "valid",
Karsten Hopp 48bd44
+     NULL
Karsten Hopp 48bd44
+ };
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
+     static PyObject *
Karsten Hopp 48bd44
+ TabPageDir(PyObject *self)
Karsten Hopp 48bd44
+ {
Karsten Hopp 48bd44
+     return ObjectDir(self, TabPageAttrs);
Karsten Hopp 48bd44
+ }
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
      static PyObject *
Karsten Hopp 48bd44
  TabPageAttrValid(TabPageObject *self, char *name)
Karsten Hopp 48bd44
  {
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 1873,1878 ****
Karsten Hopp 48bd44
--- 1985,1992 ----
Karsten Hopp 48bd44
  	else
Karsten Hopp 48bd44
  	    return WindowNew(self->tab->tp_curwin, self->tab);
Karsten Hopp 48bd44
      }
Karsten Hopp 48bd44
+     else if (strcmp(name, "__members__") == 0)
Karsten Hopp 48bd44
+ 	return ObjectDir(NULL, TabPageAttrs);
Karsten Hopp 48bd44
      return NULL;
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 1901,1908 ****
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  static struct PyMethodDef TabPageMethods[] = {
Karsten Hopp 48bd44
!     /* name,	    function,		calling,    documentation */
Karsten Hopp 48bd44
!     { NULL,	    NULL,		0,	    NULL }
Karsten Hopp 48bd44
  };
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  /*
Karsten Hopp 48bd44
--- 2015,2023 ----
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  static struct PyMethodDef TabPageMethods[] = {
Karsten Hopp 48bd44
!     /* name,	    function,			calling,	documentation */
Karsten Hopp 48bd44
!     {"__dir__",	    (PyCFunction)TabPageDir,	METH_NOARGS,	""},
Karsten Hopp 48bd44
!     { NULL,	    NULL,			0,		NULL}
Karsten Hopp 48bd44
  };
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  /*
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 2049,2054 ****
Karsten Hopp 48bd44
--- 2164,2180 ----
Karsten Hopp 48bd44
      else
Karsten Hopp 48bd44
  	return firstwin;
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
+ static char *WindowAttrs[] = {
Karsten Hopp 48bd44
+     "buffer", "cursor", "height", "vars", "options", "number", "row", "col",
Karsten Hopp 48bd44
+     "tabpage", "valid",
Karsten Hopp 48bd44
+     NULL
Karsten Hopp 48bd44
+ };
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
+     static PyObject *
Karsten Hopp 48bd44
+ WindowDir(PyObject *self)
Karsten Hopp 48bd44
+ {
Karsten Hopp 48bd44
+     return ObjectDir(self, WindowAttrs);
Karsten Hopp 48bd44
+ }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
      static PyObject *
Karsten Hopp 48bd44
  WindowAttrValid(WindowObject *self, char *name)
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 2103,2111 ****
Karsten Hopp 48bd44
  	Py_INCREF(self->tabObject);
Karsten Hopp 48bd44
  	return (PyObject *)(self->tabObject);
Karsten Hopp 48bd44
      }
Karsten Hopp 48bd44
!     else if (strcmp(name,"__members__") == 0)
Karsten Hopp 48bd44
! 	return Py_BuildValue("[ssssssssss]", "buffer", "cursor", "height",
Karsten Hopp 48bd44
! 		"vars", "options", "number", "row", "col", "tabpage", "valid");
Karsten Hopp 48bd44
      else
Karsten Hopp 48bd44
  	return NULL;
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
--- 2229,2236 ----
Karsten Hopp 48bd44
  	Py_INCREF(self->tabObject);
Karsten Hopp 48bd44
  	return (PyObject *)(self->tabObject);
Karsten Hopp 48bd44
      }
Karsten Hopp 48bd44
!     else if (strcmp(name, "__members__") == 0)
Karsten Hopp 48bd44
! 	return ObjectDir(NULL, WindowAttrs);
Karsten Hopp 48bd44
      else
Karsten Hopp 48bd44
  	return NULL;
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 2228,2235 ****
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  static struct PyMethodDef WindowMethods[] = {
Karsten Hopp 48bd44
!     /* name,	    function,		calling,    documentation */
Karsten Hopp 48bd44
!     { NULL,	    NULL,		0,	    NULL }
Karsten Hopp 48bd44
  };
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  /*
Karsten Hopp 48bd44
--- 2353,2361 ----
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  static struct PyMethodDef WindowMethods[] = {
Karsten Hopp 48bd44
!     /* name,	    function,			calling,	documentation */
Karsten Hopp 48bd44
!     {"__dir__",	    (PyCFunction)WindowDir,	METH_NOARGS,	""},
Karsten Hopp 48bd44
!     { NULL,	    NULL,			0,		NULL}
Karsten Hopp 48bd44
  };
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  /*
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 3122,3127 ****
Karsten Hopp 48bd44
--- 3248,3264 ----
Karsten Hopp 48bd44
      return RBSlice(self->buf, lo, hi, self->start, self->end);
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
+ static char *RangeAttrs[] = {
Karsten Hopp 48bd44
+     "start", "end",
Karsten Hopp 48bd44
+     NULL
Karsten Hopp 48bd44
+ };
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
+     static PyObject *
Karsten Hopp 48bd44
+ RangeDir(PyObject *self)
Karsten Hopp 48bd44
+ {
Karsten Hopp 48bd44
+     return ObjectDir(self, RangeAttrs);
Karsten Hopp 48bd44
+ }
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
      static PyObject *
Karsten Hopp 48bd44
  RangeAppend(RangeObject *self, PyObject *args)
Karsten Hopp 48bd44
  {
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 3162,3168 ****
Karsten Hopp 48bd44
  static struct PyMethodDef RangeMethods[] = {
Karsten Hopp 48bd44
      /* name,	function,			calling,	documentation */
Karsten Hopp 48bd44
      {"append",	(PyCFunction)RangeAppend,	METH_VARARGS,	"Append data to the Vim range" },
Karsten Hopp 48bd44
!     { NULL,	NULL,				0,		NULL }
Karsten Hopp 48bd44
  };
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  static PyTypeObject BufferType;
Karsten Hopp 48bd44
--- 3299,3306 ----
Karsten Hopp 48bd44
  static struct PyMethodDef RangeMethods[] = {
Karsten Hopp 48bd44
      /* name,	function,			calling,	documentation */
Karsten Hopp 48bd44
      {"append",	(PyCFunction)RangeAppend,	METH_VARARGS,	"Append data to the Vim range" },
Karsten Hopp 48bd44
!     {"__dir__",	(PyCFunction)RangeDir,		METH_NOARGS,	""},
Karsten Hopp 48bd44
!     { NULL,	NULL,				0,		NULL}
Karsten Hopp 48bd44
  };
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  static PyTypeObject BufferType;
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 3239,3244 ****
Karsten Hopp 48bd44
--- 3377,3393 ----
Karsten Hopp 48bd44
      return RBSlice(self, lo, hi, 1, -1);
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
+ static char *BufferAttrs[] = {
Karsten Hopp 48bd44
+     "name", "number", "vars", "options", "valid",
Karsten Hopp 48bd44
+     NULL
Karsten Hopp 48bd44
+ };
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
+     static PyObject *
Karsten Hopp 48bd44
+ BufferDir(PyObject *self)
Karsten Hopp 48bd44
+ {
Karsten Hopp 48bd44
+     return ObjectDir(self, BufferAttrs);
Karsten Hopp 48bd44
+ }
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
      static PyObject *
Karsten Hopp 48bd44
  BufferAttrValid(BufferObject *self, char *name)
Karsten Hopp 48bd44
  {
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 3265,3273 ****
Karsten Hopp 48bd44
      else if (strcmp(name, "options") == 0)
Karsten Hopp 48bd44
  	return OptionsNew(SREQ_BUF, self->buf, (checkfun) CheckBuffer,
Karsten Hopp 48bd44
  			(PyObject *) self);
Karsten Hopp 48bd44
!     else if (strcmp(name,"__members__") == 0)
Karsten Hopp 48bd44
! 	return Py_BuildValue("[sssss]", "name", "number", "vars", "options",
Karsten Hopp 48bd44
! 		"valid");
Karsten Hopp 48bd44
      else
Karsten Hopp 48bd44
  	return NULL;
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
--- 3414,3421 ----
Karsten Hopp 48bd44
      else if (strcmp(name, "options") == 0)
Karsten Hopp 48bd44
  	return OptionsNew(SREQ_BUF, self->buf, (checkfun) CheckBuffer,
Karsten Hopp 48bd44
  			(PyObject *) self);
Karsten Hopp 48bd44
!     else if (strcmp(name, "__members__") == 0)
Karsten Hopp 48bd44
! 	return ObjectDir(NULL, BufferAttrs);
Karsten Hopp 48bd44
      else
Karsten Hopp 48bd44
  	return NULL;
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 3403,3412 ****
Karsten Hopp 48bd44
      {"append",	    (PyCFunction)BufferAppend,	METH_VARARGS,	"Append data to Vim buffer" },
Karsten Hopp 48bd44
      {"mark",	    (PyCFunction)BufferMark,	METH_VARARGS,	"Return (row,col) representing position of named mark" },
Karsten Hopp 48bd44
      {"range",	    (PyCFunction)BufferRange,	METH_VARARGS,	"Return a range object which represents the part of the given buffer between line numbers s and e" },
Karsten Hopp 48bd44
! #if PY_VERSION_HEX >= 0x03000000
Karsten Hopp 48bd44
!     {"__dir__",	    (PyCFunction)BufferDir,	METH_NOARGS,	"List buffer attributes" },
Karsten Hopp 48bd44
! #endif
Karsten Hopp 48bd44
!     { NULL,	    NULL,			0,		NULL }
Karsten Hopp 48bd44
  };
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  /*
Karsten Hopp 48bd44
--- 3551,3558 ----
Karsten Hopp 48bd44
      {"append",	    (PyCFunction)BufferAppend,	METH_VARARGS,	"Append data to Vim buffer" },
Karsten Hopp 48bd44
      {"mark",	    (PyCFunction)BufferMark,	METH_VARARGS,	"Return (row,col) representing position of named mark" },
Karsten Hopp 48bd44
      {"range",	    (PyCFunction)BufferRange,	METH_VARARGS,	"Return a range object which represents the part of the given buffer between line numbers s and e" },
Karsten Hopp 48bd44
!     {"__dir__",	    (PyCFunction)BufferDir,	METH_NOARGS,	""},
Karsten Hopp 48bd44
!     { NULL,	    NULL,			0,		NULL}
Karsten Hopp 48bd44
  };
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
  /*
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 3538,3543 ****
Karsten Hopp 48bd44
--- 3684,3700 ----
Karsten Hopp 48bd44
  /* Current items object
Karsten Hopp 48bd44
   */
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
+ static char *CurrentAttrs[] = {
Karsten Hopp 48bd44
+     "buffer", "window", "line", "range", "tabpage",
Karsten Hopp 48bd44
+     NULL
Karsten Hopp 48bd44
+ };
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
+     static PyObject *
Karsten Hopp 48bd44
+ CurrentDir(PyObject *self)
Karsten Hopp 48bd44
+ {
Karsten Hopp 48bd44
+     return ObjectDir(self, CurrentAttrs);
Karsten Hopp 48bd44
+ }
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
      static PyObject *
Karsten Hopp 48bd44
  CurrentGetattr(PyObject *self UNUSED, char *name)
Karsten Hopp 48bd44
  {
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 3551,3564 ****
Karsten Hopp 48bd44
  	return GetBufferLine(curbuf, (PyInt)curwin->w_cursor.lnum);
Karsten Hopp 48bd44
      else if (strcmp(name, "range") == 0)
Karsten Hopp 48bd44
  	return RangeNew(curbuf, RangeStart, RangeEnd);
Karsten Hopp 48bd44
!     else if (strcmp(name,"__members__") == 0)
Karsten Hopp 48bd44
! 	return Py_BuildValue("[sssss]", "buffer", "window", "line", "range",
Karsten Hopp 48bd44
! 		"tabpage");
Karsten Hopp 48bd44
      else
Karsten Hopp 48bd44
!     {
Karsten Hopp 48bd44
! 	PyErr_SetString(PyExc_AttributeError, name);
Karsten Hopp 48bd44
  	return NULL;
Karsten Hopp 48bd44
!     }
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
      static int
Karsten Hopp 48bd44
--- 3708,3721 ----
Karsten Hopp 48bd44
  	return GetBufferLine(curbuf, (PyInt)curwin->w_cursor.lnum);
Karsten Hopp 48bd44
      else if (strcmp(name, "range") == 0)
Karsten Hopp 48bd44
  	return RangeNew(curbuf, RangeStart, RangeEnd);
Karsten Hopp 48bd44
!     else if (strcmp(name, "__members__") == 0)
Karsten Hopp 48bd44
! 	return ObjectDir(NULL, CurrentAttrs);
Karsten Hopp 48bd44
      else
Karsten Hopp 48bd44
! #if PY_MAJOR_VERSION < 3
Karsten Hopp 48bd44
! 	return Py_FindMethod(WindowMethods, self, name);
Karsten Hopp 48bd44
! #else
Karsten Hopp 48bd44
  	return NULL;
Karsten Hopp 48bd44
! #endif
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
      static int
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 3661,3666 ****
Karsten Hopp 48bd44
--- 3818,3829 ----
Karsten Hopp 48bd44
      }
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
+ static struct PyMethodDef CurrentMethods[] = {
Karsten Hopp 48bd44
+     /* name,	    function,			calling,	documentation */
Karsten Hopp 48bd44
+     {"__dir__",	    (PyCFunction)CurrentDir,	METH_NOARGS,	""},
Karsten Hopp 48bd44
+     { NULL,	    NULL,			0,		NULL}
Karsten Hopp 48bd44
+ };
Karsten Hopp 48bd44
+ 
Karsten Hopp 48bd44
      static void
Karsten Hopp 48bd44
  init_range_cmd(exarg_T *eap)
Karsten Hopp 48bd44
  {
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 4397,4402 ****
Karsten Hopp 48bd44
--- 4560,4566 ----
Karsten Hopp 48bd44
      CurrentType.tp_basicsize = sizeof(CurrentObject);
Karsten Hopp 48bd44
      CurrentType.tp_flags = Py_TPFLAGS_DEFAULT;
Karsten Hopp 48bd44
      CurrentType.tp_doc = "vim current object";
Karsten Hopp 48bd44
+     CurrentType.tp_methods = CurrentMethods;
Karsten Hopp 48bd44
  #if PY_MAJOR_VERSION >= 3
Karsten Hopp 48bd44
      CurrentType.tp_getattro = (getattrofunc)CurrentGetattro;
Karsten Hopp 48bd44
      CurrentType.tp_setattro = (setattrofunc)CurrentSetattro;
Karsten Hopp 48bd44
*** ../vim-7.3.1046/src/if_python3.c	2013-05-29 22:15:26.000000000 +0200
Karsten Hopp 48bd44
--- src/if_python3.c	2013-05-29 22:29:26.000000000 +0200
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 666,672 ****
Karsten Hopp 48bd44
      return PyType_GenericAlloc(type,nitems);
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
- static PyObject *BufferDir(PyObject *);
Karsten Hopp 48bd44
  static PyObject *OutputGetattro(PyObject *, PyObject *);
Karsten Hopp 48bd44
  static int OutputSetattro(PyObject *, PyObject *, PyObject *);
Karsten Hopp 48bd44
  static PyObject *BufferGetattro(PyObject *, PyObject *);
Karsten Hopp 48bd44
--- 666,671 ----
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 1094,1107 ****
Karsten Hopp 48bd44
      return BufferSetattr((BufferObject *)(self), name, val);
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
-     static PyObject *
Karsten Hopp 48bd44
- BufferDir(PyObject *self UNUSED)
Karsten Hopp 48bd44
- {
Karsten Hopp 48bd44
-     return Py_BuildValue("[ssssssss]",
Karsten Hopp 48bd44
- 	    "name", "number", "vars", "options", "valid",
Karsten Hopp 48bd44
- 	    "append", "mark", "range");
Karsten Hopp 48bd44
- }
Karsten Hopp 48bd44
- 
Karsten Hopp 48bd44
  /******************/
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
      static PyObject *
Karsten Hopp 48bd44
--- 1093,1098 ----
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 1368,1375 ****
Karsten Hopp 48bd44
      static PyObject *
Karsten Hopp 48bd44
  CurrentGetattro(PyObject *self, PyObject *nameobj)
Karsten Hopp 48bd44
  {
Karsten Hopp 48bd44
      GET_ATTR_STRING(name, nameobj);
Karsten Hopp 48bd44
!     return CurrentGetattr(self, name);
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
      static int
Karsten Hopp 48bd44
--- 1359,1369 ----
Karsten Hopp 48bd44
      static PyObject *
Karsten Hopp 48bd44
  CurrentGetattro(PyObject *self, PyObject *nameobj)
Karsten Hopp 48bd44
  {
Karsten Hopp 48bd44
+     PyObject	*r;
Karsten Hopp 48bd44
      GET_ATTR_STRING(name, nameobj);
Karsten Hopp 48bd44
!     if (!(r = CurrentGetattr(self, name)))
Karsten Hopp 48bd44
! 	return PyObject_GenericGetAttr(self, nameobj);
Karsten Hopp 48bd44
!     return r;
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
      static int
Karsten Hopp 48bd44
*** ../vim-7.3.1046/src/if_python.c	2013-05-29 22:15:26.000000000 +0200
Karsten Hopp 48bd44
--- src/if_python.c	2013-05-29 22:29:26.000000000 +0200
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 1066,1071 ****
Karsten Hopp 48bd44
--- 1066,1073 ----
Karsten Hopp 48bd44
  {
Karsten Hopp 48bd44
      if (strcmp(name, "softspace") == 0)
Karsten Hopp 48bd44
  	return PyInt_FromLong(((OutputObject *)(self))->softspace);
Karsten Hopp 48bd44
+     else if (strcmp(name, "__members__") == 0)
Karsten Hopp 48bd44
+ 	return ObjectDir(NULL, OutputAttrs);
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
      return Py_FindMethod(OutputMethods, self, name);
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 1177,1182 ****
Karsten Hopp 48bd44
--- 1179,1186 ----
Karsten Hopp 48bd44
  	return Py_BuildValue(Py_ssize_t_fmt, ((RangeObject *)(self))->start - 1);
Karsten Hopp 48bd44
      else if (strcmp(name, "end") == 0)
Karsten Hopp 48bd44
  	return Py_BuildValue(Py_ssize_t_fmt, ((RangeObject *)(self))->end - 1);
Karsten Hopp 48bd44
+     else if (strcmp(name, "__members__") == 0)
Karsten Hopp 48bd44
+ 	return ObjectDir(NULL, RangeAttrs);
Karsten Hopp 48bd44
      else
Karsten Hopp 48bd44
  	return Py_FindMethod(RangeMethods, self, name);
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 1396,1401 ****
Karsten Hopp 48bd44
--- 1400,1407 ----
Karsten Hopp 48bd44
  	return PyInt_FromLong(this->dict->dv_lock);
Karsten Hopp 48bd44
      else if (strcmp(name, "scope") == 0)
Karsten Hopp 48bd44
  	return PyInt_FromLong(this->dict->dv_scope);
Karsten Hopp 48bd44
+     else if (strcmp(name, "__members__") == 0)
Karsten Hopp 48bd44
+ 	return ObjectDir(NULL, DictionaryAttrs);
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
      return Py_FindMethod(DictionaryMethods, self, name);
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 1420,1425 ****
Karsten Hopp 48bd44
--- 1426,1433 ----
Karsten Hopp 48bd44
  {
Karsten Hopp 48bd44
      if (strcmp(name, "locked") == 0)
Karsten Hopp 48bd44
  	return PyInt_FromLong(((ListObject *)(self))->list->lv_lock);
Karsten Hopp 48bd44
+     else if (strcmp(name, "__members__") == 0)
Karsten Hopp 48bd44
+ 	return ObjectDir(NULL, ListAttrs);
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
      return Py_FindMethod(ListMethods, self, name);
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 1431,1436 ****
Karsten Hopp 48bd44
--- 1439,1446 ----
Karsten Hopp 48bd44
  
Karsten Hopp 48bd44
      if (strcmp(name, "name") == 0)
Karsten Hopp 48bd44
  	return PyString_FromString((char *)(this->name));
Karsten Hopp 48bd44
+     else if (strcmp(name, "__members__") == 0)
Karsten Hopp 48bd44
+ 	return ObjectDir(NULL, FunctionAttrs);
Karsten Hopp 48bd44
      else
Karsten Hopp 48bd44
  	return Py_FindMethod(FunctionMethods, self, name);
Karsten Hopp 48bd44
  }
Karsten Hopp 48bd44
*** ../vim-7.3.1046/src/testdir/test86.in	2013-05-29 22:15:26.000000000 +0200
Karsten Hopp 48bd44
--- src/testdir/test86.in	2013-05-29 22:29:26.000000000 +0200
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 691,696 ****
Karsten Hopp 48bd44
--- 691,714 ----
Karsten Hopp 48bd44
      cb.append(expr + ':' + attr + ':' + repr(type(eval(expr)) is getattr(vim, attr)))
Karsten Hopp 48bd44
  EOF
Karsten Hopp 48bd44
  :"
Karsten Hopp 48bd44
+ :" Test __dir__() method
Karsten Hopp 48bd44
+ py << EOF
Karsten Hopp 48bd44
+ for name, o in (
Karsten Hopp 48bd44
+         ('current',    vim.current),
Karsten Hopp 48bd44
+         ('buffer',     vim.current.buffer),
Karsten Hopp 48bd44
+         ('window',     vim.current.window),
Karsten Hopp 48bd44
+         ('tabpage',    vim.current.tabpage),
Karsten Hopp 48bd44
+         ('range',      vim.current.range),
Karsten Hopp 48bd44
+         ('dictionary', vim.bindeval('{}')),
Karsten Hopp 48bd44
+         ('list',       vim.bindeval('[]')),
Karsten Hopp 48bd44
+         ('function',   vim.bindeval('function("tr")')),
Karsten Hopp 48bd44
+         ('output',     sys.stdout),
Karsten Hopp 48bd44
+     ):
Karsten Hopp 48bd44
+     cb.append(name + ':' + ','.join(dir(o)))
Karsten Hopp 48bd44
+ del name
Karsten Hopp 48bd44
+ del o
Karsten Hopp 48bd44
+ EOF
Karsten Hopp 48bd44
+ :"
Karsten Hopp 48bd44
  :" Test exceptions
Karsten Hopp 48bd44
  :fun Exe(e)
Karsten Hopp 48bd44
  :   execute a:e
Karsten Hopp 48bd44
*** ../vim-7.3.1046/src/testdir/test86.ok	2013-05-29 22:15:26.000000000 +0200
Karsten Hopp 48bd44
--- src/testdir/test86.ok	2013-05-29 22:29:26.000000000 +0200
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 382,387 ****
Karsten Hopp 48bd44
--- 382,396 ----
Karsten Hopp 48bd44
  vim.current.range:Range:True
Karsten Hopp 48bd44
  vim.current.window:Window:True
Karsten Hopp 48bd44
  vim.current.tabpage:TabPage:True
Karsten Hopp 48bd44
+ current:__dir__,__members__,buffer,line,range,tabpage,window
Karsten Hopp 48bd44
+ buffer:__dir__,__members__,append,mark,name,number,options,range,valid,vars
Karsten Hopp 48bd44
+ window:__dir__,__members__,buffer,col,cursor,height,number,options,row,tabpage,valid,vars
Karsten Hopp 48bd44
+ tabpage:__dir__,__members__,number,valid,vars,window,windows
Karsten Hopp 48bd44
+ range:__dir__,__members__,append,end,start
Karsten Hopp 48bd44
+ dictionary:__dir__,__members__,keys,locked,scope
Karsten Hopp 48bd44
+ list:__dir__,__members__,extend,locked
Karsten Hopp 48bd44
+ function:__call__,__dir__,__members__,softspace
Karsten Hopp 48bd44
+ output:__dir__,__members__,flush,softspace,write,writelines
Karsten Hopp 48bd44
  (<class 'vim.error'>, error('abc',))
Karsten Hopp 48bd44
  (<class 'vim.error'>, error('def',))
Karsten Hopp 48bd44
  (<class 'vim.error'>, error('ghi',))
Karsten Hopp 48bd44
*** ../vim-7.3.1046/src/testdir/test87.in	2013-05-29 22:15:26.000000000 +0200
Karsten Hopp 48bd44
--- src/testdir/test87.in	2013-05-29 22:29:26.000000000 +0200
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 669,674 ****
Karsten Hopp 48bd44
--- 669,692 ----
Karsten Hopp 48bd44
      cb.append(expr + ':' + attr + ':' + repr(type(eval(expr)) is getattr(vim, attr)))
Karsten Hopp 48bd44
  EOF
Karsten Hopp 48bd44
  :"
Karsten Hopp 48bd44
+ :" Test __dir__() method
Karsten Hopp 48bd44
+ py3 << EOF
Karsten Hopp 48bd44
+ for name, o in (
Karsten Hopp 48bd44
+         ('current',    vim.current),
Karsten Hopp 48bd44
+         ('buffer',     vim.current.buffer),
Karsten Hopp 48bd44
+         ('window',     vim.current.window),
Karsten Hopp 48bd44
+         ('tabpage',    vim.current.tabpage),
Karsten Hopp 48bd44
+         ('range',      vim.current.range),
Karsten Hopp 48bd44
+         ('dictionary', vim.bindeval('{}')),
Karsten Hopp 48bd44
+         ('list',       vim.bindeval('[]')),
Karsten Hopp 48bd44
+         ('function',   vim.bindeval('function("tr")')),
Karsten Hopp 48bd44
+         ('output',     sys.stdout),
Karsten Hopp 48bd44
+     ):
Karsten Hopp 48bd44
+     cb.append(name + ':' + ','.join(dir(o)))
Karsten Hopp 48bd44
+ del name
Karsten Hopp 48bd44
+ del o
Karsten Hopp 48bd44
+ EOF
Karsten Hopp 48bd44
+ :"
Karsten Hopp 48bd44
  :" Test exceptions
Karsten Hopp 48bd44
  :fun Exe(e)
Karsten Hopp 48bd44
  :   execute a:e
Karsten Hopp 48bd44
*** ../vim-7.3.1046/src/testdir/test87.ok	2013-05-29 22:15:26.000000000 +0200
Karsten Hopp 48bd44
--- src/testdir/test87.ok	2013-05-29 22:29:26.000000000 +0200
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 371,376 ****
Karsten Hopp 48bd44
--- 371,385 ----
Karsten Hopp 48bd44
  vim.current.range:Range:True
Karsten Hopp 48bd44
  vim.current.window:Window:True
Karsten Hopp 48bd44
  vim.current.tabpage:TabPage:True
Karsten Hopp 48bd44
+ current:__dir__,buffer,line,range,tabpage,window
Karsten Hopp 48bd44
+ buffer:__dir__,append,mark,name,number,options,range,valid,vars
Karsten Hopp 48bd44
+ window:__dir__,buffer,col,cursor,height,number,options,row,tabpage,valid,vars
Karsten Hopp 48bd44
+ tabpage:__dir__,number,valid,vars,window,windows
Karsten Hopp 48bd44
+ range:__dir__,append,end,start
Karsten Hopp 48bd44
+ dictionary:__dir__,keys,locked,scope
Karsten Hopp 48bd44
+ list:__dir__,extend,locked
Karsten Hopp 48bd44
+ function:__call__,__dir__,softspace
Karsten Hopp 48bd44
+ output:__dir__,flush,softspace,write,writelines
Karsten Hopp 48bd44
  (<class 'vim.error'>, error('abc',))
Karsten Hopp 48bd44
  (<class 'vim.error'>, error('def',))
Karsten Hopp 48bd44
  (<class 'vim.error'>, error('ghi',))
Karsten Hopp 48bd44
*** ../vim-7.3.1046/src/version.c	2013-05-29 22:26:15.000000000 +0200
Karsten Hopp 48bd44
--- src/version.c	2013-05-29 22:35:24.000000000 +0200
Karsten Hopp 48bd44
***************
Karsten Hopp 48bd44
*** 730,731 ****
Karsten Hopp 48bd44
--- 730,733 ----
Karsten Hopp 48bd44
  {   /* Add new patch number below this line */
Karsten Hopp 48bd44
+ /**/
Karsten Hopp 48bd44
+     1047,
Karsten Hopp 48bd44
  /**/
Karsten Hopp 48bd44
Karsten Hopp 48bd44
-- 
Karsten Hopp 48bd44
hundred-and-one symptoms of being an internet addict:
Karsten Hopp 48bd44
22. You've already visited all the links at Yahoo and you're halfway through
Karsten Hopp 48bd44
    Lycos.
Karsten Hopp 48bd44
Karsten Hopp 48bd44
 /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net   \\\
Karsten Hopp 48bd44
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
Karsten Hopp 48bd44
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
Karsten Hopp 48bd44
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///