/* 
   Vmapsmodule.c - Python Arrays on mmap()
   Copyright (c) 2002 Mark Lamb

   1/12/02 - Version 1.0
   1/22/02 - 1.1; errorcheck in atswap, add 2d colget()

   LICENSE:

   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 "Python.h"

#include <sys/types.h>
#include <sys/mman.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_FTIME
#include <sys/timeb.h>
#endif /* HAVE_FTIME */
#include <time.h>

#include <sched.h>

#define HEADALIGN (64) /* keep elements from misalignment by padding header out */

#define DFL_MM_FLAGS  (MAP_ANON|MAP_PRIVATE)
#define DFL_MM_PROT   (PROT_READ|PROT_WRITE)

/* whether to return tuple or lists SEE ALSO the CTOPY_ARRAY macros */
//#define NEWRSEQ PyTuple_New
//#define SETRSEQ PyTuple_SET_ITEM
#define NEWRSEQ PyList_New
#define SETRSEQ PyList_SET_ITEM

/* TYPE CODES */
#define VMT_RAW  (0)    /* Char    array of bytes (a string) */
#define VMT_SA   (1)    /* FixChar array of 'fixed' len strings */
#define VMT_LLA  (3)    /* FixLong array of python longs ('fixed' size) */
#define VMT_IA   (8)    /* Int     array of ints */
#define VMT_DA   (9)    /* Float   array of floats (double) */
#define VMT_LL   (10)   /* Long    array of python longs (long long) [speed over LLA] */
#define VMT_2IA   (16)  /* Int2d   2D array of ints */
#define VMT_2LA   (17)  /* Long2d  2D array of PyLong / c long long */
#define VMT_2FA   (18)  /* Float2d 2D array of PyFloat / c double */

/* Behavior / interpretation flags */
#define VM_AUTOPEN      (1<< 1)  /* try mmap() on access if not mapped already */
#define VM_STAYOPEN     (1<< 2)  /* do not munmap() after access */
#define VM_ADVOPEN      (1<< 3)  /* do madvise() on open */
#define VM_SYNCLOSE     (1<< 4)  /* do sync msync() on close/unmap */
#define VM_ASYNCLOSE    (1<< 5)  /* do async msync() on close/unmap */
#define VM_KEEPTS       (1<< 6)  /* update timestamps on access */
#define VM_DOFILL       (1<< 8)  /* (zero) fill bytes not set in assigned data */
#define VM_LLALE        (1<< 9)  /* LLA type data is little endian */
#define VM_LLASG        (1<<10)  /* LLA type data is signed */
#define VM_HEADER       (1<<16)  /* has a header, use it (lockit) */
#define VM_HDRLOCK      (1<<17)  /* do we try to lock header */
#define VM_HDRFAIL      (1<<18)  /* do we fail to open if we fail to load/lock header */
#define VM_HDRTYPE      (1<<19)  /* use type/elbytes from header */
#define VM_HDRLEN       (1<<20)  /* use elcount header (be a "list") */

#define DFL_VM_FLAGS  (VM_STAYOPEN|VM_ASYNCLOSE|VM_DOFILL)
#define DFL_VM_TYPE   (0)   /* but see also the swith in Vmap_setype */


#define VM_MAGIC ( 0x566d6170 ) /* */
#define VM_MAGIC_SWAP ( 0x6170566d ) /* */

/* =============================================================================================
   sys/arch dependant
*/


#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
static int
my_getpagesize(void)
{
    return sysconf(_SC_PAGESIZE);
}
#else
#define my_getpagesize getpagesize
#endif

#undef __HAVE_ATSWAP 
#if defined (ARCH_IA32) 
/* ------------------------------------------ */
#define __HAVE_ATSWAP 1
inline int at_swapw( void *wrd, int i ) {
  asm __volatile__ (" xchgl (%1), %0 " : "=&r" (i)  :"r" (wrd), "0"(i) : "memory" );
  return i;
}
#elif defined(ARCH_SPARC)
 /* ------------------------------------------ */
#define __HAVE_ATSWAP 1
inline int at_swapw( void *wrd, int i ) {
  asm  __volatile__ (" swap [%1], %0 " : "=&r" (i) :"r" (wrd), "0"(i) : "memory");
  return i;
}
#else 
/* ------------------------------------------ */
#undef __HAVE_ATSWAP 
#warning "=========================== No atomic swap"
static int at_swapw( void *byte, int newv ) {
  return newv;
}
/* ------------------------------------------ */
#endif /* __HAVE_ATSWAP */

/* ===================================================================================== Vmap
 */
static PyObject *ErrorObject;



/* Vmap Header */
typedef struct {
  long magic;   /* id and lock  */
  long hsize;   /* offset at which user data starts */
  long type;    /* VMT_something */
  long elbytes; /* Vmap->elbytes */
  long elcount; /* "length" with VM_HDRLEN */
} SharedHead; 

/* Vmap Python object */
typedef struct {
  PyObject_HEAD

  /* general behavior */
  long  flags;
  int fill;

  /* mmap() */
  void  *mm_data;
  int fd;
  int mm_flags;
  int mm_prot;
  size_t mm_size;
  size_t start;

  /* madvise() */
  int mm_advflags;

  /* data access */
  void  *data;  /* ptr to data */
  size_t size;  /* size of data */
  int headsize; /* offset of data start */ 
  int eltype;  /* what access methods to use */
  int elsize;  /* size in elements */
  int elbytes; /* how large is an element */

  /* timestamps */
  double rts; /* read */
  double wts; /* write */
  double sts; /* sync */
  double ots; /* open */
  double cts; /* close */

  /* locking */
  long hspins;     /* header lock spins */
  long husec;      /* header lock usleep() */ 

  /* type func ptr */

  /* seq access */
  PyObject *(*f_item)( PyObject *s , int i);
  int (*f_aitem)(PyObject *s , int i, PyObject *v);
  PyObject *(*f_slice)(PyObject *s , int il, int ih );
  int (*f_aslice)(PyObject *s , int il, int ih, PyObject *v);

  /* for sort */
  int (*f_elcmp)(const void *p1, const void *p2);

  /* for find and contains */
  int (*f_search)(PyObject *s ,PyObject *v );
  /* funcs that must error check */
  void *f_meth; /* other methods */


} VmapObject;
staticforward PyTypeObject Vmaptype;
#define is_VmapObject(v)		((v)->ob_type == &Vmaptype)

/* ---------------------------------------------------------------------------- lower level */
static VmapObject * newVmapObject(PyObject *arg) {
  VmapObject *map;
  map = PyObject_NEW(VmapObject, &Vmaptype);
  if (map == NULL)
    return NULL;
  return map;
}
static void Vmap_dealloc(VmapObject *vmap) {
  if(vmap->data!=NULL) {
    /* msync(self->mm_data, self->mm_size, MS_SYNC); */
    munmap(vmap->mm_data, vmap->mm_size);
    vmap->mm_data=NULL;
  }
  PyObject_DEL(vmap);
}
/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  */
/*  example seen in timemodule.c */
inline double vm_timestamp(void) {
  double now;
#if defined(HAVE_FTIME)
  struct timeb t;
  ftime(&t);
  now= (double)t.time + (double)t.millitm * (double)0.001;
#else /* !HAVE_FTIME */
  time_t x;
  time(&x);
  now = (double)x;
#endif /* !HAVE_FTIME */
  return now;
}
/* keep a counter? */
inline void vm_lockwait(VmapObject * self) {
  // give up timeslice
  (void) sched_yield( );
  //usleep(0);
  return;
}
/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  */
static int vm_initheader(VmapObject *self, long bytes) {
  int hsize=0, wc=0;
  SharedHead *hdr= self->mm_data;
  hdr->type = self->eltype;
  hdr->elbytes = self->elbytes;
  hdr->elcount=0;
  hsize= sizeof(SharedHead);
  /* do some roundoff */
  hsize += bytes;
  wc = (hsize / HEADALIGN);
  if (hsize % HEADALIGN) wc +=1;
  hsize = wc * HEADALIGN;

  hdr->hsize = hsize ;

  hdr->magic = VM_MAGIC; /* "unlock" */
  return 1;
}
static void vm_swapheader(VmapObject *self ) {
  void *iptr;
  char *p;
  long sz=0,i=0;
  SharedHead *hdr= self->mm_data;
  iptr= self->mm_data + sizeof(long);
  sz=sizeof(SharedHead)-sizeof(long);
  for (p=iptr; i<sz ;  i += 4,p += 4) {
    char p0 = p[0];
    char p1 = p[1];
    p[0] = p[3];
    p[1] = p[2];
    p[2] = p1;
    p[3] = p0;
  }
  hdr->magic = VM_MAGIC; /* unlock */
  return ;
}
/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  */
#ifdef __HAVE_ATSWAP
#define HEADER_LOCK() \
do { \
  if (self->flags & VM_HDRLOCK) { while (lspins--) { \
    hmagic = at_swapw( &hdr->magic, -1 ); \
    if (hmagic != -1) break; \
    if (lusec >0) vm_lockwait(self); \
  }}  else { hmagic = VM_MAGIC; } \
} while (0)
#else /* ! __HAVE_ATSWAP */
#define HEADER_LOCK() \
do { \
  if (self->flags & VM_HDRLOCK){ hmagic=VM_MAGIC; lusec=lspins=0; }\
}while (0)
#endif
/* HEADER_LOCK */

static int Vmap_setype(VmapObject *self, int tp, int size); /* defined after types */
inline int vm_getypehdr(VmapObject *self) {
  SharedHead *hdr= self->mm_data;
  long hmagic=0,lspins=self->hspins,lusec=self->husec;
  HEADER_LOCK();
  if (hmagic != VM_MAGIC) { /* uninitialized/locked */
    self->headsize=0;
    self->data = self->mm_data;
    self->size = self->mm_size;
    self->elsize= (int) self->size / self->elbytes;
    return 0;
  }
  self->headsize = hdr->hsize;
  self->data = self->mm_data +  hdr->hsize;
  self->size = self->mm_size - (size_t) hdr->hsize;
  if (self->flags & VM_HDRTYPE ) {
    /*  (hdr overrrides self) */
    hdr->type = Vmap_setype( self, hdr->type, hdr->elbytes );
    if (self->flags & VM_HDRLEN) {
      /* use the count */
      self->elsize= hdr->elcount;
    } 
    else {
      /* all data addressable */
      self->elsize= (int) self->size / self->elbytes;
    }
  } /* if type */
  if (self->flags & VM_HDRLOCK) hdr->magic = VM_MAGIC; /* unlock */
  return 1;
}
inline int vm_setypehdr(VmapObject *self) {
  SharedHead *hdr= self->mm_data;
  long hmagic=0,lspins=self->hspins,lusec=self->husec;
  HEADER_LOCK();
  if (hmagic != VM_MAGIC) /* lock fail */
    return 0;
  hdr->type = self->eltype;
  hdr->elbytes = self->elbytes;
  /* if (self->flags & VM_HDRLEN) ... we dont care */
  if (self->flags & VM_HDRLOCK) hdr->magic = VM_MAGIC; /* unlock */
  return 1;
}
/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  */
inline int vm_hdrcntget(VmapObject *self ) {
  SharedHead *hdr= self->mm_data;
  long hmagic=0,lspins=self->hspins,lusec=self->husec;
  long oldc;
  HEADER_LOCK();
  if (hmagic != VM_MAGIC) /* lock fail */
    return -1;
  oldc = hdr->elcount;
  if (self->flags & VM_HDRLOCK) hdr->magic = VM_MAGIC; /* unlock */
  return oldc;
}
inline int vm_hdrcntinc(VmapObject *self, int toadd ) {
  SharedHead *hdr= self->mm_data;
  long hmagic=0,lspins=self->hspins,lusec=self->husec;
  long oldc,max;
  HEADER_LOCK();
  if (hmagic != VM_MAGIC) /* lock fail */
    return -1;
  oldc = hdr->elcount;
  max= (long) self->size / self->elbytes;
  if ((oldc + toadd) > max) toadd= (max - oldc);
  hdr->elcount += toadd;
  if (self->flags & VM_HDRLOCK) hdr->magic = VM_MAGIC; /* unlock */
  return toadd;
}
inline int vm_hdrcntdec(VmapObject *self, int tosub ) {
  SharedHead *hdr= self->mm_data;
  long hmagic=0,lspins=self->hspins,lusec=self->husec;
  long oldc;
  HEADER_LOCK();
  if (hmagic != VM_MAGIC) /* lock fail */
    return -1;
  oldc = hdr->elcount;
  if ((oldc - tosub) <0 ) tosub=oldc;
  hdr->elcount -= tosub;
  if (self->flags & VM_HDRLOCK) hdr->magic = VM_MAGIC; /* unlock */
  return tosub;
}

/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  */
inline PyObject * vm_getuserhdr(VmapObject *self) {
  PyObject *rt;
  long size=0,ofs=0;
  SharedHead *hdr= self->mm_data;
  long hmagic=0,lspins=self->hspins,lusec=self->husec;
  HEADER_LOCK();
  if (hmagic != VM_MAGIC) /* lock fail */
    return NULL;
  ofs = (sizeof(SharedHead));
  size = hdr->hsize - ofs;
  rt= PyString_FromStringAndSize( self->mm_data + ofs, size);
  if (self->flags & VM_HDRLOCK) hdr->magic = VM_MAGIC; /* unlock */
  return rt;
}
inline int vm_setuserhdr(VmapObject *self, char *in, int insz) {
  long size=0,ofs=0;
  SharedHead *hdr= self->mm_data;
  long hmagic=0,lspins=self->hspins,lusec=self->husec;
  HEADER_LOCK();
  if (hmagic != VM_MAGIC) /* lock fail */
    return -1;
  ofs = (sizeof(SharedHead));
  size = hdr->hsize - ofs;
  if (insz < size) size=insz;
  memcpy( self->mm_data+ofs, in, size);
  if (self->flags & VM_HDRLOCK) hdr->magic = VM_MAGIC; /* unlock */
  return size;
}
/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  */
inline int vm_map(VmapObject *self) {
  if ( (self->mm_data==NULL)  ) {
    if (self->flags & VM_AUTOPEN) {
      self->mm_data= mmap(NULL, self->mm_size, 
			  self->mm_prot, self->mm_flags, self->fd, self->start);
      if ( (self->mm_data==NULL) || (self->mm_data==MAP_FAILED) ) {
	self->mm_data=NULL;
	return 0;
      }
    }
    else {
      return 0;
    } /* endif autoopen */
    if (self->flags & VM_ADVOPEN) {
      if (-1 == madvise(self->mm_data, self->mm_size, self->mm_advflags)) {
	;/* oops, but who cares */
      }
    }
    if (self->flags & VM_KEEPTS) self->ots = vm_timestamp();
  } /* endif map was closed */
  if (self->flags & VM_HEADER) {
    if ( (!vm_getypehdr( self )) && (self->flags &VM_HDRFAIL) ) 
      return 0;
  }
  else {
    // XXXX ??
    self->headsize=0;
    self->data = self->mm_data;
    self->size = self->mm_size;
    self->elsize= (int) self->size / self->elbytes;
  } /* endif header */
  return 1;
}

#define CHECK_VALID(err)\
do {\
 if ( vm_map(self)==0 ) { \
   PyErr_SetString(PyExc_IOError, "Vmap closed"); \
   return err; \
 } \
} while (0) 
/* CHECK_VALID */

static PyObject * Vmap_open(VmapObject *self, PyObject *args) {
  int x=0;
  long extra=0;
  if (!PyArg_ParseTuple(args, "|ll:open", &x, &extra))
    return NULL;
  if ( (self->mm_data==NULL)  ) {
    self->mm_data= mmap(NULL, self->mm_size, 
			self->mm_prot, self->mm_flags, self->fd, self->start);
  }
  if ( (self->mm_data==NULL) || (self->mm_data==MAP_FAILED) ) {
    PyErr_SetString(PyExc_IOError, "Vmap not open, mmap () failed");
    return NULL;
  }
  if (self->flags & VM_ADVOPEN) {
    if (-1 == madvise(self->mm_data, self->mm_size, self->mm_advflags)) {
      ;/* oops, but who cares */
    }
  }
  /* is open */
  if (x != 0) vm_initheader(self, extra);
  if (self->flags & VM_HEADER) {
    if ( (!vm_getypehdr( self )) && (self->flags &VM_HDRFAIL) ) {
      PyErr_SetString(PyExc_IOError, "Vmap read header failed");
      return NULL;
    }
  }
  else {
    self->eltype = Vmap_setype( self, self->eltype, self->elbytes );
    self->headsize=0;
    self->data = self->mm_data;
    self->size = self->mm_size;
    self->elsize= (int) self->size / self->elbytes;
  } /* endif header */
  if (self->flags & VM_KEEPTS) self->ots = vm_timestamp();
  Py_INCREF (Py_None);
  return (Py_None);
}
/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  */
inline void vm_unmap(VmapObject *self) {
  if (self->flags & VM_STAYOPEN) {
    return;
  }
  else if (self->flags & VM_ASYNCLOSE) {
    msync(self->mm_data, self->mm_size, MS_ASYNC) ;
    if (self->flags & VM_KEEPTS) self->sts = vm_timestamp();
  }
  else if (self->flags & VM_SYNCLOSE) {
    msync(self->mm_data, self->mm_size, MS_SYNC) ;
    if (self->flags & VM_KEEPTS) self->sts = vm_timestamp();
  }
  munmap(self->mm_data, self->mm_size);
  if (self->flags & VM_KEEPTS) self->cts = vm_timestamp();
  self->mm_data = NULL;
  return;
}
static PyObject * Vmap_close(VmapObject *self, PyObject *args) {
  if (!PyArg_ParseTuple(args, ":close"))
    return NULL;
  if ( (self->mm_data==NULL) ) {
    /* already closed */;
  }
  else {
    if (self->flags & VM_ASYNCLOSE) {
      msync(self->mm_data, self->mm_size, MS_ASYNC) ;
      if (self->flags & VM_KEEPTS) self->sts = vm_timestamp();
    }
    else if (self->flags & VM_SYNCLOSE) {
      msync(self->mm_data, self->mm_size, MS_SYNC) ;
      if (self->flags & VM_KEEPTS) self->sts = vm_timestamp();
    }
    munmap(self->mm_data, self->mm_size);
    self->mm_data = NULL;
    self->data = NULL;
  }
  if (self->flags & VM_KEEPTS) self->cts = vm_timestamp();
  Py_INCREF (Py_None);
  return (Py_None);
}
/* ---------------------------------------------------------------------------- data types */
/* ------------------------------------------------------------------------ NUMERICS
  ***************************************************  CTOPY macro 
ASTAG - asInt, asLL, etc
CTYPE - int, double, long long
CTOPY - PyInt_FromLong, etc
PYARG - "i", "L", etc
PYTOC - PyLong_AsLongLong etc
PTCHK - PyLong_Check
SEARCHCMP - (iptr[i] == x)
RSEQ - List or Tuple
 */
#define CTOPY_ARRAY( ASTAG, CTYPE, CTOPY, PYARG, PYTOC, PTCHK, SEARCHCMP, RSEQ ) \
static int Vmap_ ## ASTAG ## _elcmp( const void *p1, const void *p2 ) { \
  CTYPE a = *((CTYPE *) p1);\
  CTYPE x = *((CTYPE *) p2);\
  if ( SEARCHCMP ) return 0;\
  if (a > x) return (1);\
  if (a < x) return (-1);\
  return (0);\
}\
static PyObject * Vmap_ ## ASTAG ## _item(VmapObject *self, int i) {\
  CTYPE *iptr;\
  iptr = self->data;\
  return CTOPY ( iptr[i] );\
}\
static int Vmap_  ## ASTAG ## _ass_item(VmapObject *self, int i, PyObject *v) {\
  CTYPE *iptr;\
  CTYPE x;\
  if (!PyArg_Parse(v, #PYARG  ";Vmap item wrong type", &x))\
    return -1;\
  iptr = self->data;\
  iptr[i]=x;\
  return 0;\
}\
static PyObject * Vmap_ ## ASTAG ## _slice(VmapObject *self, int ilow, int ihigh) {\
  CTYPE *iptr;\
  int i, ri=0;\
  PyObject *rt;\
  rt = Py ## RSEQ ## _New(ihigh - ilow);\
  if (rt == NULL ) return NULL;\
  iptr = self->data;\
  for (i=ilow ; i<ihigh ; i++,ri++ ) \
    Py ## RSEQ ## _SET_ITEM( rt, ri, CTOPY ( iptr[i] )  );\
  if (PyErr_Occurred()) {\
    Py_DECREF(rt);\
    return NULL;\
  }\
  return rt;\
}\
static int Vmap_  ## ASTAG ## _ass_slice(VmapObject *self, int ilow, int ihigh, PyObject *v) {\
  CTYPE *iptr;\
  CTYPE x;\
  int csz, i, ri=0;\
  PyObject *tpl, *iv;\
  tpl = PySequence_Fast( v, "Vmap slice assign must be sequence" );\
  csz= PySequence_Size(tpl);\
  if (csz != (ihigh - ilow) ) {\
    PyErr_SetString(PyExc_IndexError, "Vmap slice assignment is wrong size");\
    Py_DECREF(tpl);\
    return -1;\
  }\
  iptr = self->data;\
  for (i=ilow ; i<ihigh ; i++,ri++ ) {\
    iv = PySequence_Fast_GET_ITEM(tpl, ri);\
    if ( PTCHK (iv) ) x= PYTOC (iv);\
    else x=0;\
    iptr[i]=x;\
  }\
  if (PyErr_Occurred()) PyErr_Clear();\
  Py_DECREF(tpl);\
  return 0;\
}\
static int Vmap_  ## ASTAG ##  _dosearch(VmapObject *self, PyObject *v) {\
  CTYPE *iptr;\
  CTYPE x, a;\
  int i=0, start=0,end=self->elsize;\
  iptr=self->data;\
  if ( (v == NULL) || (v == Py_None) ) return -1;\
  else if ( PTCHK (v) ) {\
    x= PYTOC (v);\
    for (i=start ; i< end ; i++ ) {\
      a=iptr[i];\
      if ( SEARCHCMP ) return i;\
    }\
    return -1;\
  }\
  if (!PyArg_ParseTuple (v, #PYARG "|ll:find", &x, &start, &end )) {\
    PyErr_Clear();\
    return -1;\
  }\
  if (start<0) start=0;\
  if (end>self->elsize) end=self->elsize;\
  for (i=start ; i< end ; i++ ) {\
    a=iptr[i];\
    if ( SEARCHCMP ) return i;\
  }\
  return -1;\
}\
static PyObject *Vmap_ ## ASTAG ## _setrange(VmapObject *self, PyObject *args) {\
  CTYPE *iptr;\
  CTYPE x;\
  int i, ilow=0, ihigh=-1;\
  if (!PyArg_ParseTuple (args, #PYARG "|ll:setrange", &x, &ilow, &ihigh )) return NULL;\
  if ( vm_map(self)==0 ) { \
    PyErr_SetString(PyExc_IOError, "Vmap closed"); \
    return NULL; \
  } \
  if (ihigh ==-1) ihigh=self->elsize;\
  iptr = self->data; \
  for (i=ilow ; i<ihigh ; i++ ) iptr[i] = x;\
  if (self->flags & VM_KEEPTS) self->wts = vm_timestamp();\
  vm_unmap(self);\
  Py_INCREF (Py_None);\
  return (Py_None);\
}\
static PyObject *Vmap_ ## ASTAG ## _minmax(VmapObject *self, PyObject *args) {\
  CTYPE *iptr;\
  CTYPE fmin=0,fmax=0;\
  PyObject *rt;\
  int i, maxi=-1,mini=-1, ilow=0, ihigh=-1;\
  rt = Py ## RSEQ ## _New(2);\
  if (rt == NULL ) return NULL;\
  if (!PyArg_ParseTuple (args, "|" #PYARG #PYARG "ll:minmax", &fmin, &fmax, &ilow, &ihigh ))\
    return NULL;\
  if ( vm_map(self)==0 ) { \
    PyErr_SetString(PyExc_IOError, "Vmap closed"); \
    return NULL; \
  } \
  if (ihigh ==-1) ihigh=self->elsize;\
  iptr = self->data; \
  for (i=ilow ; i<ihigh ; i++ ) {\
    if (iptr[i] < fmin) {\
      fmin = iptr[i];\
      mini=i;\
    }\
    if (iptr[i] > fmax) {\
      fmax = iptr[i];\
      maxi=i;\
    }\
  }\
  if (self->flags & VM_KEEPTS) self->rts = vm_timestamp();\
  vm_unmap(self);\
  Py ## RSEQ ## _SET_ITEM( rt, 0, PyInt_FromLong( mini ) );\
  Py ## RSEQ ## _SET_ITEM( rt, 1, PyInt_FromLong( maxi ) );\
  return rt;\
}\
static PyObject *Vmap_ ## ASTAG ## _sumrange(VmapObject *self, PyObject *args) {\
  CTYPE *iptr;\
  CTYPE x=0;\
  int i, ilow=0, ihigh=-1;\
  if (!PyArg_ParseTuple (args, "|ll:sumrange", &ilow, &ihigh )) return NULL;\
  if ( vm_map(self)==0 ) { \
    PyErr_SetString(PyExc_IOError, "Vmap closed"); \
    return NULL; \
  } \
  if (ihigh ==-1) ihigh=self->elsize;\
  iptr = self->data; \
  for (i=ilow ; i<ihigh ; i++ )  x += iptr[i];\
  if (self->flags & VM_KEEPTS) self->rts = vm_timestamp();\
  vm_unmap(self);\
  return CTOPY ( x );\
}\
static PyObject *Vmap_ ## ASTAG ## _cntbndrange(VmapObject *self, PyObject *args) {\
  CTYPE *iptr;\
  CTYPE vlo=-1,vhi=1;\
  unsigned long cnt=0;\
  int i, ilow=0, ihigh=-1;\
  if (!PyArg_ParseTuple (args, "|" #PYARG #PYARG "ll:cntbndrange",&vlo, &vhi, &ilow, &ihigh )) return NULL;\
  if ( vm_map(self)==0 ) { \
    PyErr_SetString(PyExc_IOError, "Vmap closed"); \
    return NULL; \
  } \
  if (ihigh ==-1) ihigh=self->elsize;\
  iptr = self->data; \
  for (i=ilow ; i<ihigh ; i++ ) {\
    if ( (iptr[i] > vlo) && (iptr[i] < vhi)  ) cnt++;\
  }\
  if (self->flags & VM_KEEPTS) self->rts = vm_timestamp();\
  vm_unmap(self);\
  return PyInt_FromLong ( cnt );\
}\

/* *******************************  end macro */
/* ------------------------------------------------------------------------ Int */
CTOPY_ARRAY( asInt, long, PyInt_FromLong, l, 
	     PyInt_AS_LONG, PyInt_Check, (a == x), List );
/* ------------------------------- */
#ifdef __HAVE_ATSWAP
static PyObject *Vmap_asInt_atswap(VmapObject *self, PyObject *args) {
  long *iptr;
  long x,r, el=0;
  if (!PyArg_ParseTuple(args, "ll:atswap", &el, &x )) return NULL;
  CHECK_VALID(NULL);
  if (el < 0 || el >= self->elsize) {
    PyErr_SetString(PyExc_IndexError, "Vmap index out of range");
    vm_unmap(self);
    return NULL;
  }
  iptr = self->data;
  r=at_swapw( &iptr[el], x );
  if (self->flags & VM_KEEPTS) self->rts = self->wts = vm_timestamp();
  vm_unmap(self);
  return PyInt_FromLong( r );
}
#endif
/* ------------------------------- */
static PyMethodDef Vmap_asInt_methods[] = {
  {"setrange",	(PyCFunction)Vmap_asInt_setrange,	METH_VARARGS}, 
  {"sumrange",	(PyCFunction)Vmap_asInt_sumrange,	METH_VARARGS}, 
  {"cntbndrange",	(PyCFunction)Vmap_asInt_cntbndrange,	METH_VARARGS}, 
  {"minmax",	(PyCFunction)Vmap_asInt_minmax,	METH_VARARGS}, 
#ifdef __HAVE_ATSWAP
  {"atswap",	(PyCFunction)Vmap_asInt_atswap,	METH_VARARGS}, 
#endif
  // {"",	(PyCFunction)Vmap_asInt_,	METH_VARARGS}, 
  {NULL,NULL}  
};
/* ------------------------------------------------------------------------ LongLong */
CTOPY_ARRAY( asLL, long long, PyLong_FromLongLong, L, 
	     PyLong_AsLongLong, PyLong_Check, (a == x), List );
/* ------------------------------- */
static PyMethodDef Vmap_asLL_methods[] = {
  {"setrange",	(PyCFunction)Vmap_asLL_setrange,	METH_VARARGS}, 
  {"sumrange",	(PyCFunction)Vmap_asLL_sumrange,	METH_VARARGS}, 
  {"cntbndrange",	(PyCFunction)Vmap_asLL_cntbndrange,	METH_VARARGS}, 
  {"minmax",	(PyCFunction)Vmap_asLL_minmax,	METH_VARARGS}, 
  // {"",	(PyCFunction)Vmap_asLL_,	METH_VARARGS}, 
  {NULL,NULL}   
}; 
/* ------------------------------------------------------------------------ Float */
CTOPY_ARRAY( asFlt, double, PyFloat_FromDouble, d, 
	     PyFloat_AS_DOUBLE, PyFloat_Check, ( (abs(a - x) < 0.0000001 )), List );
/* ------------------------------- */
static PyMethodDef Vmap_asFlt_methods[] = {
  {"setrange",	(PyCFunction)Vmap_asFlt_setrange,	METH_VARARGS}, 
  {"sumrange",	(PyCFunction)Vmap_asFlt_sumrange,	METH_VARARGS}, 
  {"cntbndrange",	(PyCFunction)Vmap_asFlt_cntbndrange,	METH_VARARGS}, 
  {"minmax",	(PyCFunction)Vmap_asFlt_minmax,	METH_VARARGS}, 
  // {"",	(PyCFunction)Vmap_asFlt_,	METH_VARARGS}, 
  {NULL,NULL}   
}; 
/*  ***************************************************  CTOPY_2D macro 
ASTAG - asInt, asLL, etc
CTYPE - int, double, long long
CTOPY - PyInt_FromLong, etc
PYARG - "i", "L", etc
PYTOC - PyLong_AsLongLong etc
PTCHK - PyLong_Check
SEARCHCMP - (iptr[i] == x)
RSEQ - List or Tuple
 */
#define CTOPY_ARRAY_2D( ASTAG, CTYPE, CTOPY, PYARG, PYTOC, PTCHK, SEARCHCMP, RSEQ ) \
static int Vmap_ ## ASTAG ## _elcmp( const void *p1, const void *p2 ) { \
  CTYPE a = *((CTYPE *) p1);\
  CTYPE x = *((CTYPE *) p2);\
  if ( SEARCHCMP ) return 0;\
  if (a > x) return (1);\
  if (a < x) return (-1);\
  return (0);\
}\
static PyObject * Vmap_ ## ASTAG ## _item(VmapObject *self, int i) {\
  CTYPE *iptr;\
  PyObject *rt;\
  long ri, al;\
  al=(self->elbytes / sizeof(CTYPE));\
  rt= Py ## RSEQ ## _New( al );\
  if (rt == NULL) return NULL;\
  iptr = self->data + (i * self->elbytes);\
  for (ri=0 ; ri<al ; ri++ )\
    Py ## RSEQ ## _SET_ITEM( rt, ri, CTOPY ( iptr[ri] ) );\
  if (PyErr_Occurred()) {\
    Py_DECREF(rt);\
    return NULL;\
  }\
  return rt;\
}\
static int Vmap_  ## ASTAG ## _ass_item(VmapObject *self, int i, PyObject *v) {\
  CTYPE *iptr;\
  CTYPE x;\
  PyObject *tpl, *iv;\
  long tsz, ri, al=(self->elbytes / sizeof(CTYPE));\
  if (!PySequence_Check(v)) return -1;\
  tpl = PySequence_Fast( v, "Vmap item assign must be sequence" );\
  tsz = PySequence_Size(tpl);\
  if (tsz != al) {\
    PyErr_SetString(PyExc_IndexError, "Vmap assignment is wrong size");\
    Py_DECREF(tpl);\
    return -1;\
  }\
  iptr = self->data + (i * self->elbytes);\
  for (ri=0 ; ri<al ; ri++,i++ ) {\
    iv = PySequence_Fast_GET_ITEM(tpl, ri);\
    if ( PTCHK (iv) ) x= PYTOC (iv);\
    else x=0;\
    iptr[ri]=x;\
  }\
  Py_DECREF(tpl);\
  return 0;\
}\
static PyObject * Vmap_ ## ASTAG ## _slice(VmapObject *self, int ilow, int ihigh) {\
  CTYPE *iptr;\
  int i, ii, ri=0, al;\
  PyObject *rt, *iv;\
  al=(self->elbytes / sizeof(CTYPE));\
  rt = Py ## RSEQ ## _New(ihigh - ilow);\
  if (rt == NULL ) return NULL;\
  for (i=ilow ; i<ihigh ; i++,ri++ ) {\
    iv = Py ## RSEQ ## _New(al);\
    if (iv==NULL) break;\
    iptr = self->data + (i * self->elbytes);\
    for (ii=0 ; ii<al ; ii++ )\
      Py ## RSEQ ## _SET_ITEM( iv, ii, CTOPY ( iptr[ii] ) );\
    Py ## RSEQ ## _SET_ITEM( rt, ri, iv  );\
  }\
  if (PyErr_Occurred()) {\
    Py_DECREF(rt);/* leak? */\
    return NULL;\
  }\
  return rt;\
}\
static int Vmap_  ## ASTAG ## _ass_slice(VmapObject *self, int ilow, int ihigh, PyObject *v) {\
  CTYPE *iptr;\
  CTYPE x;\
  int csz, i, ii, ri=0, al=(self->elbytes / sizeof(CTYPE));\
  PyObject *tpl, *itpl, *iv, *ix;\
  tpl = PySequence_Fast( v, "Vmap slice assign must be sequence" );\
  csz= PySequence_Size(tpl);\
  if (csz != (ihigh - ilow) ) {\
    PyErr_SetString(PyExc_IndexError, "Vmap slice assignment is wrong size");\
    Py_DECREF(tpl);\
    return -1;\
  }\
  for (i=ilow ; i<ihigh ; i++,ri++ ) {\
    iv = PySequence_Fast_GET_ITEM(tpl, ri);\
    itpl = PySequence_Fast( iv, "Vmap slice el assign must be sequence" );\
    if (PySequence_Size(itpl) != al ) {\
      PyErr_SetString(PyExc_IndexError, "Vmap slice el assignment is wrong size");\
      Py_DECREF(tpl);\
      return -1;\
    }\
    iptr = self->data + (i * self->elbytes);\
    for (ii=0 ; ii<al;  ii++ ) {\
      ix = PySequence_Fast_GET_ITEM(itpl, ii);\
      if ( PTCHK (ix) ) x= PYTOC (ix);\
      else x=0;\
      iptr[ii]=x;\
    }\
    Py_DECREF(itpl);\
  }\
  if (PyErr_Occurred()) PyErr_Clear();\
  Py_DECREF(tpl);\
  return 0;\
}\
static int Vmap_  ## ASTAG ##  _dosearch(VmapObject *self, PyObject *v) {\
  CTYPE *iptr;\
  CTYPE x, a;\
  int i=0, start=0, al=(self->elbytes / sizeof(CTYPE)),  end=(self->elsize * al) ;\
  iptr=self->data;\
  if ( (v == NULL) || (v == Py_None) ) return -1;\
  else if ( PTCHK (v) ) {\
    x= PYTOC (v);\
    for (i=start ; i< end  ; i++ ) {\
      a=iptr[i];\
      if ( SEARCHCMP ) return (i / al );\
    }\
    return -1;\
  }\
  if (!PyArg_ParseTuple (v, #PYARG "|ll:find", &x, &start, &end )) {\
    PyErr_Clear();\
    return -1;\
  }\
  if (start<0) start=0;\
  if (end>self->elsize) end=self->elsize;\
  end = end * al;\
  for (i=start ; i< end ; i++ ) {\
    a=iptr[i];\
    if ( SEARCHCMP ) return (i / al);\
  }\
  return -1;\
}\
static PyObject *Vmap_ ## ASTAG ## _colxchg(VmapObject *self, PyObject *args) {\
  CTYPE *iptr;\
  CTYPE x;\
  int i, cols=0, ca=0,cb=0, ilow=0, ihigh=-1;\
  if (!PyArg_ParseTuple (args, "ll|ll:swapcol", &ca, &cb, &ilow, &ihigh )) return NULL;\
  if (ca == cb) {\
    Py_INCREF (Py_None);\
    return (Py_None);\
  }\
  if ( vm_map(self)==0 ) { \
    PyErr_SetString(PyExc_IOError, "Vmap closed"); \
    return NULL; \
  } \
  if (ihigh ==-1) ihigh=self->elsize;\
  cols=(self->elbytes / sizeof(CTYPE));\
  if ( (ca>cols) && (cb>cols) ) {\
    PyErr_SetString(PyExc_IndexError, "Vmap columns out of range"); \
    return NULL; \
  }\
  for (i=ilow ; i<ihigh ; i++ ){\
    iptr = self->data + (i * self->elbytes);\
    x = iptr[cb];\
    iptr[cb] = iptr[ca];\
    iptr[ca] = x;\
  }\
  if (self->flags & VM_KEEPTS) self->rts = self->wts = vm_timestamp();\
  vm_unmap(self);\
  Py_INCREF (Py_None);\
  return (Py_None);\
}\
static PyObject *Vmap_ ## ASTAG ## _colget(VmapObject *self, PyObject *args) {\
  CTYPE *iptr;\
  CTYPE x;\
  int el=0, col=0, cols=0;\
  if (!PyArg_ParseTuple (args, "ll:colget", &el, &col )) return NULL;\
  if ( vm_map(self)==0 ) { \
    PyErr_SetString(PyExc_IOError, "Vmap closed"); \
    return NULL; \
  } \
  if (el < 0 || el >= self->elsize) {\
    PyErr_SetString(PyExc_IndexError, "Vmap index out of range");\
    vm_unmap(self);\
    return NULL;\
  }\
  cols=(self->elbytes / sizeof(long));\
  if ( (col>cols) ) {\
    PyErr_SetString(PyExc_IndexError, "Vmap column out of range"); \
    return NULL; \
  }\
  iptr = self->data + (el * self->elbytes);\
  x=iptr[col];\
  if (self->flags & VM_KEEPTS) self->rts = vm_timestamp();\
  vm_unmap(self);\
  return PyInt_FromLong( x );\
}\
/* *******************************  end macro */
/* ------------------------------------------------------------------------ INT 2D */
CTOPY_ARRAY_2D( as2I, long, PyInt_FromLong, l, 
	     PyInt_AS_LONG, PyInt_Check, (a == x), List );
/* ------------------------------- */
#ifdef __HAVE_ATSWAP
static PyObject *Vmap_as2I_atswap(VmapObject *self, PyObject *args) {
  long *iptr;
  long cols,x=0, el=0, col=0;
  if (!PyArg_ParseTuple(args, "lll:atswap", &el, &col, &x )) return NULL;
  CHECK_VALID(NULL);
  if (el < 0 || el >= self->elsize) {
    PyErr_SetString(PyExc_IndexError, "Vmap index out of range");
    vm_unmap(self);
    return NULL;
  }
  cols=(self->elbytes / sizeof(long));
  if ( (col>cols) ) {
    PyErr_SetString(PyExc_IndexError, "Vmap column out of range"); 
    return NULL; 
  }
  iptr = self->data + (el * self->elbytes);
  x=at_swapw( &iptr[col], x );
  if (self->flags & VM_KEEPTS) self->rts = self->wts = vm_timestamp();
  vm_unmap(self);
  return PyInt_FromLong( x );
}
#endif
/* ------------------------------- */
static PyMethodDef Vmap_as2I_methods[] = {
   {"colxchg",	(PyCFunction)Vmap_as2I_colxchg,	METH_VARARGS}, 
   {"colget",	(PyCFunction)Vmap_as2I_colget,	METH_VARARGS}, 
#ifdef __HAVE_ATSWAP
   {"atswap",	(PyCFunction)Vmap_as2I_atswap,	METH_VARARGS}, 
#endif
   // {"",	(PyCFunction)Vmap_as2I_,	METH_VARARGS}, 
  {NULL,NULL}   
}; 
/* ------------------------------------------------------------------------ LongLong 2D */
CTOPY_ARRAY_2D( as2LL, long long, PyLong_FromLongLong, L, 
	     PyLong_AsLongLong, PyLong_Check, (a == x), List );
/* ------------------------------- */
static PyMethodDef Vmap_as2LL_methods[] = {
   {"colxchg",	(PyCFunction)Vmap_as2LL_colxchg,	METH_VARARGS}, 
   {"colget",	(PyCFunction)Vmap_as2LL_colget,	METH_VARARGS}, 
  // {"",	(PyCFunction)Vmap_as2LL_,	METH_VARARGS}, 
  {NULL,NULL}   
}; 
/* ------------------------------------------------------------------------ Float 2D */
CTOPY_ARRAY_2D( as2Flt, double, PyFloat_FromDouble, d, 
	     PyFloat_AS_DOUBLE, PyFloat_Check, ( (abs(a - x) < 0.0000001 )), List );
/* ------------------------------- */
static PyMethodDef Vmap_as2Flt_methods[] = {
   {"colxchg",	(PyCFunction)Vmap_as2Flt_colxchg,	METH_VARARGS}, 
   {"colget",	(PyCFunction)Vmap_as2Flt_colget,	METH_VARARGS}, 
  // {"",	(PyCFunction)Vmap_as2Flt_,	METH_VARARGS}, 
  {NULL,NULL}   
}; 
/* ------------------------------------------------------------------------ "varlen" */
/* Copid from Python 2.2 stringobject.c */
static int mymemfind(const char *mem, int len, const char *pat, int pat_len) {
  register int ii;
  /* pattern can not occur in the last pat_len-1 chars */
  len -= pat_len;
  for (ii = 0; ii <= len; ii++) {
    if (mem[ii] == pat[0] && memcmp(&mem[ii], pat, pat_len) == 0) return ii;
  }
  return -1;
}
/* ------------------------------------------------------------------------ Raw */
static int Vmap_asRaw_elcmp( const void *p1, const void *p2 ) {
  char i = *((char *)p1);
  char j = *((char *)p2);
  if (i > j) return (1);
  if (i < j) return (-1);
  return (0);
}
/* ------------------------------- */
static PyObject * Vmap_asRaw_item(VmapObject *self, int i) {
  char *iptr;
  PyObject *rt;
  iptr=self->data+i;
  rt=PyString_FromStringAndSize( iptr, 1);
  return rt;
}
static int Vmap_asRaw_ass_item(VmapObject *self, int i, PyObject *v) {
  int insize;
  char *iptr;
  char *buf;
  iptr=self->data;
  if ( (v == NULL) || (v == Py_None) ) {
    if (self->flags & VM_DOFILL) iptr[i] = (char)self->fill;
    return 0;
  }
  if (!PyString_Check(v) ) {
    PyErr_SetString(PyExc_ValueError, "Vmap assignment expected string");
    return -1;
  }
  insize = PyString_Size(v);
  if (insize == 0) {
    if (self->flags & VM_DOFILL) iptr[i] = (char)self->fill;
  }
  else {
    buf = PyString_AsString(v);
    iptr[i] =  buf[0];
  }
  return 0;
}
/* ------------------------------- */
static PyObject * Vmap_asRaw_slice(VmapObject *self, int ilow, int ihigh) {
  PyObject *rt;
  rt=PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
  return rt;
}
static int Vmap_asRaw_ass_slice(VmapObject *self, int ilow, int ihigh, PyObject *v) {
  int insize;
  char *buf;
  void *iptr;
  if ( (v == NULL) || (v == Py_None) ) insize = 0;
  else if (!PyString_Check(v) ) {
    PyErr_SetString(PyExc_ValueError, "Vmap assignment expected string");
    return -1;
  }
  else  insize = PyString_Size(v);
  if (insize > (ihigh-ilow)) insize=ihigh-ilow;
  if (insize > self->elsize) insize=self->elsize;
  iptr = self->data + ilow;
  if (insize == 0) {
    if (self->flags & VM_DOFILL) memset(iptr, self->fill, (ihigh-ilow));
  }
  else {
    buf = PyString_AsString(v);
    memcpy(iptr, buf, insize);
  }
  return 0;
}
/* ------------------------------- */
static int Vmap_asRaw_dosearch(VmapObject *self, PyObject *v) {
  char *buf;
  int insize=0,start=0,end=self->size;
  if ( (v == NULL) || (v == Py_None) ) return -1;
  else if (PyString_Check(v) ) {
    return mymemfind( self->data, self->size, PyString_AsString(v), PyString_Size(v) );
  }
  if (!PyArg_ParseTuple (v, "z#|ll:find", &buf, &insize, &start, &end )) {
    PyErr_Clear();
    return -1;
  }
  if (insize==0)
    return -1;
  if (start<0) start=0;
  if (end>self->size) end=self->size;
  return mymemfind( (self->data +start), end, buf, insize );
}
/* ---------------------------------------------------------- */
// .stripped(lo,hi) ?
// .replace()
static PyMethodDef Vmap_asRaw_methods[] = {
  // {"",	(PyCFunction)Vmap_as_,	METH_VARARGS}, 
  {NULL,NULL}  
};
/* ------------------------------------------------------------------------ StrA */
static int Vmap_asSA_elcmp( const void *p1, const void *p2 ) {
  // XXX needs elbytes
  char i = *((char *)p1);
  char j = *((char *)p2);
  if (i > j) return (1);
  if (i < j) return (-1);
  return (0);
}
/* ------------------------------- */
static PyObject * Vmap_asSA_item(VmapObject *self, int i) {
  char *iptr;
  iptr = self->data + (i * self->elbytes);
  return PyString_FromStringAndSize(iptr, self->elbytes);
}
static int Vmap_asSA_ass_item(VmapObject *self, int i, PyObject *v) {
  void *iptr;
  int insize;
  char * buf;
  if ( (v == NULL) || (v == Py_None) ) insize = 0;
  else if (!PyString_Check(v) ) {
    PyErr_SetString(PyExc_ValueError, "Vmap assignment expected string");
    return -1;
  }
  else  insize = PyString_Size(v);
  if (insize > self->elbytes) insize=self->elbytes;
  iptr = self->data + (i * self->elbytes);
  if (insize == 0)  memset(iptr, self->fill, self->elbytes);
  else {
    buf = PyString_AsString(v);
    memcpy(iptr, buf, insize);
    if ( (self->flags & VM_DOFILL) && (insize< self->elbytes) ) {
      memset(iptr+insize, self->fill, self->elbytes - insize  );
    }
  }
  return 0;
}
/* ------------------------------- */
static PyObject * Vmap_asSA_slice(VmapObject *self, int ilow, int ihigh) {
  int i, ri=0;
  PyObject *rt;
  rt = NEWRSEQ (ihigh - ilow);
  if (rt == NULL ) return NULL;
  for (i=ilow ; i<ihigh ; i++,ri++ ) {
    SETRSEQ ( rt, ri, 
		      PyString_FromStringAndSize( self->data + (i * self->elbytes), self->elbytes)
		      );
  }
  if (PyErr_Occurred()) {
    Py_DECREF(rt);
    return NULL;
  }
  return rt;
}
static int Vmap_asSA_ass_slice(VmapObject *self, int ilow, int ihigh, PyObject *v) {
  char *buf, *iptr;
  int csz, insize, i, ri=0;
  PyObject *tpl, *iv;
  if (!PySequence_Check(v)) {
    PyErr_SetString(PyExc_ValueError, "Vmap assignment expected sequence");
    return -1;
  }
  tpl = PySequence_Fast( v, "Vmap slice assign must be sequence" );
  csz= PySequence_Size(tpl);
  if (csz != (ihigh - ilow) ) {
    PyErr_SetString(PyExc_IndexError, "Vmap slice assignment is wrong size");
    Py_DECREF(tpl);
    return -1;
  }
  for (i=ilow ; i<ihigh ; i++,ri++ ) {
    iv = PySequence_Fast_GET_ITEM(tpl, ri);
    if ( (iv == NULL) || (iv == Py_None) ) insize = 0;
    else if (!PyString_Check(iv) ) {
      PyErr_SetString(PyExc_ValueError, "Vmap assignment expected string");
      Py_DECREF(tpl);
      return -1;
    }
    insize = PyString_Size(iv);
    if (insize > self->elbytes) insize=self->elbytes;
    iptr = self->data + (i * self->elbytes);
    if (insize == 0)  memset(iptr, self->fill, self->elbytes);
    else {
      buf = PyString_AsString(iv);
      memcpy(iptr, buf, insize);
      if ( (self->flags & VM_DOFILL) && (insize< self->elbytes) ) {
	memset(iptr+insize, self->fill, self->elbytes - insize  );
      }
    }
  }
  if (PyErr_Occurred()) PyErr_Clear();
  Py_DECREF(tpl);
  return 0;
}
/* ------------------------------- */
static int Vmap_asSA_dosearch(VmapObject *self, PyObject *v) {
  char *buf;
  int i=0, insize=0,start=0,end=self->elsize;
  if ( (v == NULL) || (v == Py_None) ) return -1;
  else if (PyString_Check(v) ) {
    buf=PyString_AsString(v);
    insize=PyString_Size(v);
    for (i=start ; i< self->elsize ; i++ ) {
      if (mymemfind( self->data + (i * self->elbytes), self->elbytes, buf, insize ) != -1)
	return i;
    }
    return -1;
  }
  if (!PyArg_ParseTuple (v, "z#|ll:find", &buf, &insize, &start, &end )) {
    PyErr_Clear();
    return -1;
  }
  if (insize==0)
    return -1;
  if (start<0) start=0;
  if (end>self->elsize) end=self->elsize;
  for (i=start ; i< self->elsize ; i++ ) {
    if (mymemfind( self->data + (i * self->elbytes), self->elbytes, buf, insize ) != -1)
      return i;
    }
  return -1;
}
/* ---------------------------------------------------------- */
static PyObject *Vmap_asSA_size(VmapObject *self, PyObject *v) {
  int newsz=self->elbytes;
  if (!PyArg_ParseTuple (v, "|l:size", &newsz )) 
    return NULL;
  CHECK_VALID(NULL);
  if ((newsz<1) || (newsz>self->size)) return NULL;
  if (newsz!=self->elbytes) {
    self->elbytes=newsz;
    if (!(self->flags & VM_HDRLEN) ) self->elsize= self->size / newsz;
    if (self->flags & (VM_HEADER | VM_HDRTYPE)) {
      if ( (!vm_setypehdr(self)) && (self->flags & VM_HDRFAIL) ) {
	vm_unmap( self );
	PyErr_SetString(PyExc_IOError, "Vmaps header lock failed");
	return NULL;
      }
    } /* endif header */
  }
  vm_unmap(self);
  return PyInt_FromLong( self->elbytes );
}
/* ------------------------------- */
// Return stripped mode?
static PyMethodDef Vmap_asSA_methods[] = {
  {"resize",	(PyCFunction)Vmap_asSA_size,	METH_VARARGS}, 
  //{"",	(PyCFunction)Vmap_,	METH_VARARGS}, 
  {NULL,NULL}  
};
/* ------------------------------------------------------------------------ PyLongArray */
static int Vmap_asLLA_elcmp( const void *p1, const void *p2 ) {
  // XXX needs elbytes
  char i = *((char *)p1);
  char j = *((char *)p2);
  if (i > j) return (1);
  if (i < j) return (-1);
  return (0);
}
/* ------------------------------- */
static PyObject * Vmap_asLLA_item(VmapObject *self, int i) {
  char *iptr;
  iptr = self->data + (i * self->elbytes);
  return _PyLong_FromByteArray(iptr, self->elbytes, 
			       ((self->flags & VM_LLALE)!=0),((self->flags & VM_LLASG)!=0)  );
}
static int Vmap_asLLA_ass_item(VmapObject *self, int i, PyObject *v) {
  void *iptr;
  if (!PyLong_Check(v) ) {
    PyErr_SetString(PyExc_ValueError, "Vmap assignment expected long");
    return -1;
  }
  iptr = self->data + (i * self->elbytes);
  return _PyLong_AsByteArray((PyLongObject *)v, iptr, self->elbytes, 
			       ((self->flags & VM_LLALE)!=0),((self->flags & VM_LLASG)!=0)  );
}
/* ------------------------------- */
static PyObject * Vmap_asLLA_slice(VmapObject *self, int ilow, int ihigh) {
  int i, ri=0;
  PyObject *rt;
  rt = NEWRSEQ (ihigh - ilow);
  if (rt == NULL ) return NULL;
  for (i=ilow ; i<ihigh ; i++,ri++ ) {
    SETRSEQ ( rt, ri, 
	      _PyLong_FromByteArray(self->data + (i * self->elbytes), self->elbytes, 
		     ((self->flags & VM_LLALE)!=0),((self->flags & VM_LLASG)!=0)  )
	      );
  }
  if (PyErr_Occurred()) {
    Py_DECREF(rt);
    return NULL;
  }
  return rt;
}
static int Vmap_asLLA_ass_slice(VmapObject *self, int ilow, int ihigh, PyObject *v) {
  char *iptr;
  int csz, i, ri=0;
  PyObject *tpl, *iv;
  if (!PySequence_Check(v)) {
    PyErr_SetString(PyExc_ValueError, "Vmap assignment expected sequence");
    return -1;
  }
  tpl = PySequence_Fast( v, "Vmap slice assign must be sequence" );
  csz= PySequence_Size(tpl);
  if (csz != (ihigh - ilow) ) {
    PyErr_SetString(PyExc_IndexError, "Vmap slice assignment is wrong size");
    Py_DECREF(tpl);
    return -1;
  }
  for (i=ilow ; i<ihigh ; i++,ri++ ) {
    iv = PySequence_Fast_GET_ITEM(tpl, ri);
    if (!PyLong_Check(iv) ) {
      PyErr_SetString(PyExc_ValueError, "Vmap assignment expected long");
      Py_DECREF(tpl);
      return -1;
    }
    iptr = self->data + (i * self->elbytes);
    (void) _PyLong_AsByteArray((PyLongObject*) iv, iptr, self->elbytes, 
			       ((self->flags & VM_LLALE)!=0),((self->flags & VM_LLASG)!=0)  );
  }
  if (PyErr_Occurred()) PyErr_Clear();
  Py_DECREF(tpl);
  return 0;
}
/* ------------------------------- */
static int Vmap_asLLA_dosearch(VmapObject *self, PyObject *v) {
  // whooo
  return -1;
}
/* ---------------------------------------------------------- */
static PyObject *Vmap_asLLA_size(VmapObject *self, PyObject *v) {
  int newsz=self->elbytes;
  if (!PyArg_ParseTuple (v, "|l:size", &newsz )) 
    return NULL;
  CHECK_VALID(NULL);
  if ((newsz<1) || (newsz>self->size)) return NULL;
  if (newsz!=self->elbytes) {
    self->elbytes=newsz;
    if (!(self->flags & VM_HDRLEN) ) self->elsize= self->size / newsz;
    if (self->flags & (VM_HEADER | VM_HDRTYPE)) {
      if ( (!vm_setypehdr(self)) && (self->flags & VM_HDRFAIL) ) {
	vm_unmap( self );
	PyErr_SetString(PyExc_IOError, "Vmaps header lock failed");
	return NULL;
      }
    } /* endif header */
  }
  vm_unmap(self);
  return PyInt_FromLong( self->elbytes );
}
/* ------------------------------- */
static PyMethodDef Vmap_asLLA_methods[] = {
  {"resize",	(PyCFunction)Vmap_asLLA_size,	METH_VARARGS}, 
  //{"",	(PyCFunction)Vmap_,	METH_VARARGS}, 
  {NULL,NULL}  
};
/*   ---------------------------------------------------------------------------- type switch */
#define _SET_TYPE_FUNCS(ASTAG)\
do{\
  self->f_elcmp = (void *)&Vmap_ ## ASTAG ## _elcmp;\
  self->f_item = (void *)&Vmap_ ## ASTAG ## _item;\
  self->f_aitem = (void *)&Vmap_ ## ASTAG ## _ass_item;\
  self->f_slice = (void *)&Vmap_ ## ASTAG ## _slice;\
  self->f_aslice = (void *)&Vmap_ ## ASTAG ## _ass_slice;\
  self->f_search = (void *)&Vmap_ ## ASTAG ## _dosearch;\
  self->f_meth = &Vmap_ ## ASTAG ## _methods;\
} while (0)
/* _SET_TYPE_FUNCS */
static int Vmap_setype(VmapObject *self, int tp, int size) {
  /* no shared data here */
  switch (tp) {
  default:
    /* FALLTHRU */
  case VMT_RAW:
    self->eltype=VMT_RAW;
    self->elbytes=1;
    self->f_elcmp = (void *)&Vmap_asRaw_elcmp;
    _SET_TYPE_FUNCS( asRaw );
    break;

  case VMT_SA:
    self->eltype=tp;
    self->elbytes=size;
    _SET_TYPE_FUNCS( asSA );
    self->f_elcmp = NULL; /* (void *)&Vmap_asSA_elcmp; // it dont work */ 
    break;

  case VMT_LLA:
    self->eltype=tp;
    self->elbytes=size;
    _SET_TYPE_FUNCS( asLLA );
    self->f_elcmp = NULL; /* (void *)&Vmap_asLLA_elcmp; // it dont work */ 
    break;

  case VMT_IA:
    self->eltype=tp;
    self->elbytes=sizeof(long);
    _SET_TYPE_FUNCS( asInt );
    break;

  case VMT_DA:
    self->eltype=tp;
    self->elbytes=sizeof(double);
    _SET_TYPE_FUNCS( asFlt );
    break;

  case VMT_LL:
    self->eltype=tp;
    self->elbytes=sizeof(long long);
    _SET_TYPE_FUNCS( asLL );
    break;

  case VMT_2IA:
    self->eltype=tp;
    self->elbytes=(size * sizeof(long));
    _SET_TYPE_FUNCS( as2I );
    break;

  case VMT_2LA:
    self->eltype=tp;
    self->elbytes=(size * sizeof(long long));
    _SET_TYPE_FUNCS( as2LL );
    break;

  case VMT_2FA:
    self->eltype=tp;
    self->elbytes=(size * sizeof(double));
    _SET_TYPE_FUNCS( as2Flt );
    break;
  }
  // XXXXXXXXXXXX ?
  self->elsize=(int)self->size/self->elbytes;
  return tp;
}
/* ---------------------------------------------------------------------------- generic methods
   ---------------------------------------------------------------------------- (all types)
 */
/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  */
static PyObject * Vmap_type(VmapObject *self, PyObject *args) {
  long tp=self->eltype, size=self->elbytes;
  if (!PyArg_ParseTuple (args, "|ll:type", &tp, &size )) 
    return NULL;
  CHECK_VALID(NULL);
  if ( (tp!=self->eltype) ||  (size != self->elbytes) ) {
    Vmap_setype( self, tp, size );
    if (self->flags & (VM_HEADER | VM_HDRTYPE)) {
      if ( !vm_setypehdr(self) ) {
	vm_unmap( self );
	PyErr_SetString(PyExc_IOError, "Vmaps header lock failed");
	return NULL;
      }
    } /* endif header */
  } /*endif chtype */
  vm_unmap(self);
  return PyInt_FromLong( self->eltype );
} 
/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  */
//XXXX push, pop (slice access wrap); insert, remove (w/memmove);
static PyObject * Vmap_count_get(VmapObject *self, PyObject *args) {
  long x=0,r=0;
  if (!PyArg_ParseTuple (args, "|l:count_get", &x  )) 
    return NULL;
  if ( ! (self->flags & VM_HEADER) ) {
    PyErr_SetString(PyExc_ValueError, "Vmap has no count in header"); 
    return NULL;
  }
  CHECK_VALID(NULL);
  r = vm_hdrcntget(self);
  vm_unmap(self);
  return PyInt_FromLong(r);
}
static PyObject * Vmap_count_add(VmapObject *self, PyObject *args) {
  long x=0,r=0;
  if (!PyArg_ParseTuple (args, "|l:count_add", &x  )) 
    return NULL;
  if ( ! (self->flags & VM_HEADER) ) {
    PyErr_SetString(PyExc_ValueError, "Vmap has no count in header"); 
    return NULL;
  }
  if (x<1) return PyInt_FromLong(0);
  CHECK_VALID(NULL);
  r = vm_hdrcntinc(self, x);
  vm_unmap(self);
  return PyInt_FromLong(r);
}
static PyObject * Vmap_count_sub(VmapObject *self, PyObject *args) {
  long x=0,r=0;
  if (!PyArg_ParseTuple (args, "|l:count_sub", &x  )) 
    return NULL;
  if ( ! (self->flags & VM_HEADER) ) {
    PyErr_SetString(PyExc_ValueError, "Vmap has no count in header"); 
    return NULL;
  }
  if (x<1) return PyInt_FromLong(0);
  CHECK_VALID(NULL);
  r = vm_hdrcntdec(self, x);
  vm_unmap(self);
  return PyInt_FromLong(r);
}
/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  */
static PyObject *Vmap_swapheader(VmapObject *self, PyObject *v) {
  if (!PyArg_ParseTuple (v, ":swapheader"  )) 
    return NULL;
  if ( !(self->flags & VM_HEADER) ) {
    PyErr_SetString(PyExc_ValueError, "Vmap has no header"); 
    return NULL;
  }
  CHECK_VALID(NULL);
  vm_swapheader(self);
  vm_unmap(self);
  return PyInt_FromLong( 0 );
}
static PyObject * Vmap_getheader(VmapObject *self, PyObject *args) {
  PyObject *rt;
  long x;
  if (!PyArg_ParseTuple (args, "|l:getheader", &x  )) 
    return NULL;
  if ( !(self->flags & VM_HEADER) ) {
    PyErr_SetString(PyExc_ValueError, "Vmap has no header"); 
    return NULL;
  }
  CHECK_VALID(NULL);
  rt = vm_getuserhdr(self);
  vm_unmap(self);
  return rt;
}
static PyObject * Vmap_setheader(VmapObject *self, PyObject *args) {
  PyObject *v;
  char *buf;
  int rt=0,insz=0;
  if (!PyArg_ParseTuple (args, "O:setheader", &v  )) 
    return NULL;
  if ( !(self->flags & VM_HEADER) ) {
    PyErr_SetString(PyExc_ValueError, "Vmap has no header"); 
    return NULL;
  }
  insz = PyString_Size(v);
  buf = PyString_AsString(v);
  CHECK_VALID(NULL);
  rt = vm_setuserhdr(self,buf,insz);
  vm_unmap(self);
  return PyInt_FromLong(rt);
}
/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  */
static PyObject *Vmap_copyfrom(VmapObject *self, PyObject *args) {
  VmapObject *v;
  size_t bytes=-1,ilow=0, vlow=0;
  
  if (!PyArg_ParseTuple (args, "O!|lll:copyfrom", &Vmaptype, &v,
			 &bytes, &ilow,  &vlow )) {
    return NULL;
  }
  CHECK_VALID(NULL);
  if ( vm_map(v)==0 ) { 
    PyErr_SetString(PyExc_IOError, "Vmap closed"); 
    vm_unmap(self);
    return NULL;
  }
  if (bytes == -1) {
    if ( (self->size - ilow) < (v->size - vlow) ) 
      bytes = (self->size - ilow);
    else 
      bytes=(v->size - vlow);
  }
  if ( (ilow+bytes> self->size) || (vlow+bytes > v->size) ) {
    PyErr_SetString (PyExc_ValueError, "copy offsets out of range");
    vm_unmap(v);
    vm_unmap(self);
    return NULL;
  }
  memmove( v->data+vlow, self->data+ilow, bytes );
  if (v->flags & VM_KEEPTS) v->rts = vm_timestamp();
  if (self->flags & VM_KEEPTS) self->wts = vm_timestamp();
  vm_unmap(v);
  vm_unmap(self);
  return PyInt_FromLong( bytes );
}
/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ */
#define CHECK_OPENANDSIZE()\
do{\
  if ( (self->mm_data==NULL) || (self->mm_data==MAP_FAILED) ) {\
    PyErr_SetString(PyExc_IOError, "Vmaps must be open for that");\
    return NULL;\
  }\
  if (size ==0)\
    size=self->mm_size;\
  if ((offset + size) > self->mm_size) {\
    PyErr_SetString (PyExc_ValueError, "values out of range");\
    return NULL;\
  }\
} while (0)\
/* CHECK_OPENANDSIZE */
static PyObject * Vmap_raw_msync(VmapObject *self, PyObject *args) {
  size_t offset	= 0;
  size_t size = self->mm_size;
  int flags = MS_SYNC;
  CHECK_OPENANDSIZE();
  if (!PyArg_ParseTuple (args, "|lll:raw_msync", &flags, &offset, &size)) 
    return NULL;
  if (-1 == msync(self->mm_data + offset, size, flags)) {
    PyErr_SetFromErrno(ErrorObject);
    return NULL;
  }
  if (self->flags & VM_KEEPTS) self->sts = vm_timestamp();
  Py_INCREF (Py_None);
  return (Py_None);
}
static PyObject * Vmap_raw_madvise(VmapObject *self, PyObject *args) {
  size_t offset	= 0;
  size_t size = self->mm_size;
  int flags = self->mm_advflags;
  CHECK_OPENANDSIZE();
  if (!PyArg_ParseTuple (args, "|lll:raw_madvise", &flags, &offset, &size)) 
    return NULL;
  if (-1 == madvise(self->mm_data + offset, size, flags)) {
    PyErr_SetFromErrno(ErrorObject);
    return NULL;
  }
  Py_INCREF (Py_None);
  return (Py_None);
}
static PyObject * Vmap_raw_mlock(VmapObject *self, PyObject *args) {
  size_t offset	= 0;
  size_t size = self->mm_size;
  CHECK_OPENANDSIZE();
  if (!PyArg_ParseTuple (args, "|ll:raw_mlock",  &offset, &size)) 
    return NULL;
  if (-1 == mlock(self->mm_data + offset, size )) {
    PyErr_SetFromErrno(ErrorObject);
    return NULL;
  }
  Py_INCREF (Py_None);
  return (Py_None);
}
static PyObject * Vmap_raw_munlock(VmapObject *self, PyObject *args) {
  size_t offset	= 0;
  size_t size = self->mm_size;
  CHECK_OPENANDSIZE();
  if (!PyArg_ParseTuple (args, "|ll:raw_munlock",  &offset, &size)) 
    return NULL;
  if (-1 == munlock(self->mm_data + offset, size )) {
    PyErr_SetFromErrno(ErrorObject);
    return NULL;
  }
  Py_INCREF (Py_None);
  return (Py_None);
}
/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  */
static PyObject * Vmap_raw_string(VmapObject *self, PyObject *args) {
  size_t ilow	= 0;
  size_t ihigh = self->mm_size;
  PyObject *r;
  if (!PyArg_ParseTuple (args, "|ll:raw_string", &ilow, &ihigh )) 
    return NULL;
  else if ((ilow + ihigh) > self->mm_size) {
    PyErr_SetString (PyExc_ValueError, "values out of range");
    return NULL;
  }
  if (ilow <0) ilow=0;
  else if (ilow > self->mm_size) ilow=self->mm_size;
  if (ihigh<ilow) ihigh=ilow;
  else if (ihigh > self->mm_size) ihigh=self->mm_size;
  CHECK_VALID(NULL);
  r=PyString_FromStringAndSize(self->mm_data + ilow, ihigh-ilow);
  if (self->flags & VM_KEEPTS) self->rts = vm_timestamp();
  vm_unmap(self);
  return r;
}
/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  */
static PyObject *Vmap_sort(VmapObject *self, PyObject *args) {
  void *iptr, *cmpfunc;
  size_t size, wide;
  long ofs=0,cnt=-1;
  if (!PyArg_ParseTuple (args, "|ll:sort", &ofs, &cnt )) 
    return NULL;
  CHECK_VALID(NULL);
  cmpfunc=self->f_elcmp;
  if (cmpfunc == NULL) {
      vm_unmap(self);
      return NULL;
  }
  if (cnt<0) cnt = self->elsize -ofs;
  if (cnt+ofs > self->elsize) {
    PyErr_SetString (PyExc_ValueError, "sort offsets out of range");
    vm_unmap(self);
    return NULL;
  }
  iptr=self->data + (ofs * self->elbytes);
  size=cnt;
  wide=self->elbytes;
  qsort( iptr, size, wide, cmpfunc );
  if (self->flags & VM_KEEPTS) self->rts = self->wts = vm_timestamp();
  vm_unmap(self);
  Py_INCREF (Py_None);
  return (Py_None);
}
static PyObject *Vmap_byteswap(VmapObject *self, PyObject *args) {
  void *iptr;
  char *p;
  long ofs=0,cnt=-1,sz=0,i=0;
  if (!PyArg_ParseTuple (args, "|ll:byteswap", &ofs, &cnt )) 
    return NULL;
  CHECK_VALID(NULL);
  if (cnt<0) cnt = self->elsize -ofs;
  if (cnt+ofs > self->elsize) {
    PyErr_SetString (PyExc_ValueError, "byteswap offsets out of range");
    vm_unmap(self);
    return NULL;
  }
  iptr= self->data + (ofs * self->elbytes);
  sz=(cnt*self->elbytes);
  switch (self->eltype) {
    /* 4 bytes */
  case VMT_IA:
    /* FALLTHRU */
  case VMT_2IA:
    for (p=iptr; i<sz ;  i += 4,p += 4) {
      char p0 = p[0];
      char p1 = p[1];
      p[0] = p[3];
      p[1] = p[2];
      p[2] = p1;
      p[3] = p0;
    }
    break;
    /* 8 bytes */
  case VMT_DA:
    /* FALLTHRU */
  case VMT_2FA:
    /* FALLTHRU */
  case VMT_LL:
    /* FALLTHRU */
  case VMT_2LA:
    for (p = iptr; i<sz ; i += 8,  p += 8) {
      char p0 = p[0];
      char p1 = p[1];
      char p2 = p[2];
      char p3 = p[3];
      p[0] = p[7];
      p[1] = p[6];
      p[2] = p[5];
      p[3] = p[4];
      p[4] = p3;
      p[5] = p2;
      p[6] = p1;
      p[7] = p0;
    }
    break;
    /* everyhting else */
  default:
    PyErr_SetString (PyExc_TypeError, "not swappable");
    vm_unmap(self);
    return NULL;
    break;
  }
  if (self->flags & VM_KEEPTS) self->rts = self->wts = vm_timestamp();
  vm_unmap(self);
  return PyInt_FromLong( sz);
  Py_INCREF (Py_None);
  return (Py_None);
}
/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  */
static PyObject *Vmap_find(VmapObject *self, PyObject *args) {
  int (*sfunc)(PyObject *s ,PyObject *v );
  long r;
  CHECK_VALID(NULL);
  sfunc= (void*) self->f_search;
  if (sfunc == NULL) {
      vm_unmap(self);
      return NULL;
  }
  r=(int) sfunc((PyObject *)self, args);
  if (self->flags & VM_KEEPTS) self->rts = vm_timestamp();
  vm_unmap( self );
  return PyInt_FromLong( r );
}
/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  */
static PyObject *Vmap_schyield(VmapObject *self, PyObject *v) {
  if (!PyArg_ParseTuple (v, ":schyield"  )) 
    return NULL;
  vm_lockwait(self);
  return PyInt_FromLong( 0 );
}
static PyObject *Vmap_getflag(VmapObject *self, PyObject *v) {
  long x;
  if (!PyArg_ParseTuple (v, "|l:getflag", &x  )) 
    return NULL;
  return PyInt_FromLong( ((self->flags & x)!=0) );
}
static PyObject *Vmap_setflag(VmapObject *self, PyObject *v) {
  long x;
  if (!PyArg_ParseTuple (v, "|l:setflag", &x  )) 
    return NULL;
  self->flags = (self->flags | x );
  return PyInt_FromLong( (self->flags)  );
}
static PyObject *Vmap_clearflag(VmapObject *self, PyObject *v) {
  long x;
  if (!PyArg_ParseTuple (v, "|l:clearflag", &x  )) 
    return NULL;
  self->flags = (self->flags & (~x) );
  return PyInt_FromLong( (self->flags)  );
}
static PyObject *Vmap_times(VmapObject *self, PyObject *args) {
  long reset=0;
  PyObject *rt;
  if (!PyArg_ParseTuple (args, "|l:times", &reset )) 
    return NULL;
  rt = PyTuple_New(5);
  if (rt == NULL ) return NULL;
  PyTuple_SET_ITEM( rt, 0, PyFloat_FromDouble( self->rts ));
  PyTuple_SET_ITEM( rt, 1, PyFloat_FromDouble( self->wts ));
  PyTuple_SET_ITEM( rt, 2, PyFloat_FromDouble( self->sts ));
  PyTuple_SET_ITEM( rt, 3, PyFloat_FromDouble( self->ots ));
  PyTuple_SET_ITEM( rt, 4, PyFloat_FromDouble( self->cts ));
  if (reset !=0) 
    self->rts = self->wts = self->sts = self->ots = self->cts = 0.0;
  return rt;
}
static PyObject *Vmap_elsize(VmapObject *self, PyObject *v) {
  if (!PyArg_ParseTuple (v, ":size"  )) 
    return NULL;
  return PyInt_FromLong( self->elbytes );
}
static PyObject *Vmap_elpage(VmapObject *self, PyObject *v) {
  long eofs=0, x=0,pg=0;
  if (!PyArg_ParseTuple (v, "l:elpage", &x  )) 
    return NULL;
  if (self->flags & VM_HEADER) {
    /* Actually lets just say it has to have been opened
    if ( vm_map(self)==0 ) { 
      PyErr_SetString(PyExc_IOError, "Vmap closed"); 
      return err; 
    }
    vm_unmap(self);
    */
    eofs += self->headsize;
  }
  eofs += (x * self->elbytes);
  pg = eofs / my_getpagesize();
  return PyInt_FromLong( pg );
}
/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  */
static char xx_doc[] = "noneyet";
static PyMethodDef Vmap_methods[] = {
  {"schyield",	(PyCFunction)Vmap_schyield,	METH_VARARGS, xx_doc},
  {"elsize",	(PyCFunction)Vmap_elsize,	METH_VARARGS, xx_doc},
  {"elpage",	(PyCFunction)Vmap_elpage,	METH_VARARGS, xx_doc},
  {"find",	(PyCFunction)Vmap_find,	METH_VARARGS, xx_doc},
  {"count_get",	(PyCFunction)Vmap_count_get,	METH_VARARGS, xx_doc},
  {"count_add",	(PyCFunction)Vmap_count_add,	METH_VARARGS, xx_doc},
  {"count_sub",	(PyCFunction)Vmap_count_sub,	METH_VARARGS, xx_doc},
  {"getheader",	(PyCFunction)Vmap_getheader,	METH_VARARGS, xx_doc},
  {"setheader",	(PyCFunction)Vmap_setheader,	METH_VARARGS, xx_doc},
  {"swapheader",(PyCFunction)Vmap_swapheader,	METH_VARARGS, xx_doc},
  {"raw_msync",	(PyCFunction)Vmap_raw_msync,	METH_VARARGS, xx_doc},
  {"raw_madvise",(PyCFunction)Vmap_raw_madvise,	METH_VARARGS, xx_doc},
  {"raw_mlock",	(PyCFunction)Vmap_raw_mlock,	METH_VARARGS, xx_doc},
  {"raw_munlock",(PyCFunction)Vmap_raw_munlock,	METH_VARARGS, xx_doc},
  {"raw_string",(PyCFunction)Vmap_raw_string,	METH_VARARGS, xx_doc},
  {"copyfrom",	(PyCFunction)Vmap_copyfrom,	METH_VARARGS, xx_doc},
  {"times",	(PyCFunction)Vmap_times,	METH_VARARGS, xx_doc},
  {"sort",	(PyCFunction)Vmap_sort,	METH_VARARGS, xx_doc},
  {"open",	(PyCFunction)Vmap_open,	METH_VARARGS, xx_doc},
  {"close",	(PyCFunction)Vmap_close,	METH_VARARGS, xx_doc},
  {"astype",	(PyCFunction)Vmap_type,	METH_VARARGS, xx_doc},
  {"getflag",	(PyCFunction)Vmap_getflag,	METH_VARARGS, xx_doc},
  {"setflag",	(PyCFunction)Vmap_setflag,	METH_VARARGS, xx_doc},
  {"clearflag",	(PyCFunction)Vmap_clearflag,	METH_VARARGS, xx_doc},
  {"byteswap",	(PyCFunction)Vmap_byteswap,	METH_VARARGS, xx_doc},
  //{"",	(PyCFunction)Vmap_,	METH_VARARGS, xx_doc}, 
  {NULL,		NULL}		/* sentinel */
};
/* ------------------------------------------------------------------------- builtin  */
static PyObject * Vmap_getattr(VmapObject *self, char *name) {
  PyObject *meth;

  /* speed */
  meth = Py_FindMethod(self->f_meth, (PyObject *)self, name);
  if (meth != NULL) return meth;
  PyErr_Clear();
  meth= Py_FindMethod(Vmap_methods, (PyObject *)self, name);
  if (meth != NULL) return meth;
  PyErr_Clear();

  if (strcmp(name, "isopen") == 0) 
    return PyInt_FromLong( (long) ( !((self->mm_data==NULL) || (self->mm_data==MAP_FAILED)) ) );
  if (strcmp(name, "vm_flags") == 0) return PyInt_FromLong( (long) self->flags);
  if (strcmp(name, "vm_type") == 0) return PyInt_FromLong( (long) self->eltype);
  if (strcmp(name, "len") == 0) return PyInt_FromLong( (long) self->elsize);

  if (strcmp(name, "databytes") == 0) return PyInt_FromLong( (long) self->size);
  if (strcmp(name, "headerbytes") == 0) return PyInt_FromLong( (long) self->headsize);
  if (strcmp(name, "overheadbytes") == 0) return PyInt_FromLong( (long) sizeof(SharedHead) );

  if (strcmp(name, "fileno") == 0) return PyInt_FromLong( (long) self->fd);
  if (strcmp(name, "size") == 0) return PyInt_FromLong( (long) self->mm_size);
  if (strcmp(name, "start") == 0) return PyInt_FromLong( (long) self->start);
  if (strcmp(name, "mm_flags") == 0) return PyInt_FromLong( (long) self->mm_flags);
  if (strcmp(name, "mm_prot") == 0) return PyInt_FromLong( (long) self->mm_prot);

  if (strcmp(name, "mm_advflags") == 0) return PyInt_FromLong( (long) self->mm_advflags);
  if (strcmp(name, "fillwith") == 0) return PyInt_FromLong( (long) self->fill);

  if (strcmp(name, "hlckspins") == 0) return PyInt_FromLong( (long) self->hspins);
  if (strcmp(name, "hlkyield") == 0) return PyInt_FromLong( (long) self->husec);

  if (strcmp(name, "__members__") == 0) {
    PyObject *list = PyList_New(14);
    if (list) {
      PyList_SetItem(list, 0, PyString_FromString("isopen"));
      PyList_SetItem(list, 1, PyString_FromString("vm_flags"));
      PyList_SetItem(list, 2, PyString_FromString("vm_type"));
      PyList_SetItem(list, 3, PyString_FromString("databytes"));
      PyList_SetItem(list, 4, PyString_FromString("headerbytes"));
      PyList_SetItem(list, 5, PyString_FromString("overheadbytes"));
      PyList_SetItem(list, 6, PyString_FromString("fileno"));
      PyList_SetItem(list, 7, PyString_FromString("size"));
      PyList_SetItem(list, 8, PyString_FromString("start"));
      PyList_SetItem(list, 9, PyString_FromString("mm_flags"));
      PyList_SetItem(list, 10, PyString_FromString("mm_prot"));
      PyList_SetItem(list, 11, PyString_FromString("mm_advflags"));
      PyList_SetItem(list, 12, PyString_FromString("hlckspins"));
      PyList_SetItem(list, 13, PyString_FromString("hlckyield"));
      if (PyErr_Occurred()) {
	Py_DECREF(list);
	list = NULL;
      }
    }
    return list;
  }
  return NULL;
}
/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  */
static int Vmap_setattr(VmapObject *self, char *name, PyObject *v) {
  int x=0;
  if (strcmp(name, "fillwith") == 0) {
    if (!PyArg_Parse(v, "i;Vmap wanted int", &x)) x=0;
    self->fill = x;
  }
  else if (strcmp(name, "mm_advflags") == 0) {
    if (!PyArg_Parse(v, "i;Vmap wanted int", &x)) x=0;
    self->mm_advflags= x;
  }
  else if (strcmp(name, "hlkyield") == 0) {
    if (!PyArg_Parse(v, "i;Vmap wanted int", &x)) x=0;
    self->husec= x;
  }
  else if (strcmp(name, "hlkspins") == 0) {
    if (!PyArg_Parse(v, "i;Vmap wanted int", &x)) x=0;
    self->hspins= x;
  }
  else if ( ((self->mm_data==NULL) || (self->mm_data==MAP_FAILED)) ) {
    if (strcmp(name, "mm_flags") == 0) {
      if (!PyArg_Parse(v, "i;Vmap wanted int", &x)) x=DFL_MM_FLAGS;
      self->mm_flags= x;
    }
    else if (strcmp(name, "mm_prot") == 0) {
      if (!PyArg_Parse(v, "i;Vmap wanted int", &x)) x=DFL_MM_PROT;
      self->mm_prot= x;
    }
    else if (strcmp(name, "start") == 0) {
      if (!PyArg_Parse(v, "i;Vmap wanted int", &x)) x=0;
      self->start= x;
    }
    else if (strcmp(name, "size") == 0) {
      if (!PyArg_Parse(v, "i;Vmap wanted int", &x)) x=0;
      self->mm_size= x;
    }
    else if (strcmp(name, "fileno") == 0) {
      if (!PyArg_Parse(v, "i;Vmap wanted int", &x)) x=-1;
      self->fd = x;
    }
  } /* it closed */
  return 0;
}

/* ----------------------------------------------------------- SEQUENCE */
static int Vmap_length(VmapObject *self) {
  int r;
  CHECK_VALID(-1);
  r = self->elsize;
  vm_unmap(self);
  return r;
}
/* ------------------------------- */
static PyObject * Vmap_item(VmapObject *self, int i) {
  PyObject *r;
  CHECK_VALID(NULL);
  if (i < 0 || i >= self->elsize) {
    vm_unmap(self);
    PyErr_SetString(PyExc_IndexError, "Vmap index out of range");
    return NULL;
  }
  r= self->f_item((PyObject *)self, i);
  if (self->flags & VM_KEEPTS) self->rts = vm_timestamp();
  vm_unmap(self);
  return r;
}
static int Vmap_ass_item(VmapObject *self, int i, PyObject *v) {
  int r;
  CHECK_VALID(-1);
  if (i < 0 || i >= self->elsize) {
    PyErr_SetString(PyExc_IndexError, "Vmap index out of range");
    vm_unmap(self);
    return -1;
  }
  r=(int) self->f_aitem((PyObject *)self, i, v);
  if (self->flags & VM_KEEPTS) self->rts = self->wts = vm_timestamp();
  vm_unmap(self);
  return r;
}
/* ------------------------------- */
static PyObject * Vmap_slice(VmapObject *self, int ilow, int ihigh) {
  PyObject *r;
  CHECK_VALID(NULL);
  if (ilow <0) ilow=0;
  else if (ilow > self->elsize) ilow=self->elsize;
  if (ihigh<ilow) ihigh=ilow;
  else if (ihigh > self->elsize) ihigh=self->elsize;
  r= self->f_slice((PyObject *)self, ilow, ihigh);
  if (self->flags & VM_KEEPTS) self->rts = vm_timestamp();
  vm_unmap(self);
  return r;
}
static int Vmap_ass_slice(VmapObject *self, int ilow, int ihigh, PyObject *v) {
  int r;
  CHECK_VALID(-1);
  if (ilow <0) ilow=0;
  else if (ilow > self->elsize) ilow=self->elsize;
  if (ihigh<ilow) ihigh=ilow;
  else if (ihigh > self->elsize) ihigh=self->elsize;
  r=(int) self->f_aslice((PyObject *)self, ilow, ihigh, v);
  if (self->flags & VM_KEEPTS) self->rts = self->wts = vm_timestamp();
  vm_unmap(self);
  return r;
}
/* ------------------------------- */
static int Vmap_contains(VmapObject *self, PyObject *v) {
  /* 0 = does not contain, 1=does contain */
  int (*sfunc)(PyObject *s ,PyObject *v );
  int r;
  CHECK_VALID(-1);
  sfunc=(void*) self->f_search;
  if (sfunc == NULL) {
      vm_unmap(self);
      return -1;
  }
  r=(int) sfunc((PyObject *)self, v);
  if (self->flags & VM_KEEPTS) self->rts = vm_timestamp();
  vm_unmap( self );
  return  (r != -1);
}
/* ------------------------------- */
static PyObject * Vmap_concat(VmapObject *self, PyObject *bb) {
  PyErr_SetString(PyExc_SystemError, "Vmaps don't support concatenation");
  return NULL;
}
static PyObject * Vmap_inplace_concat(VmapObject *self, PyObject *bb) {
  // XXXX be nice to do push()?
  PyErr_SetString(PyExc_SystemError, "Vmaps don't support concatenation");
  return NULL;
}
static PyObject * Vmap_repeat(VmapObject *self, int n) {
  PyErr_SetString(PyExc_SystemError, "Vmaps don't support repeating");
  return NULL;
}
static PyObject * Vmap_inplace_repeat(VmapObject *self, int n) {
  PyErr_SetString(PyExc_SystemError, "Vmaps don't support repeating");
  return NULL;
}
/* ------------------------------- */
static PySequenceMethods Vmap_as_sequence = {
  (inquiry)Vmap_length,		       /*sq_length*/
  (binaryfunc)Vmap_concat,	       /*sq_concat*/
  (intargfunc)Vmap_repeat,	       /*sq_repeat*/
  (intargfunc)Vmap_item,		       /*sq_item*/
  (intintargfunc)Vmap_slice,	       /*sq_slice*/
  (intobjargproc)Vmap_ass_item,	       /*sq_ass_item*/
  (intintobjargproc)Vmap_ass_slice,      /*sq_ass_slice*/
  (objobjproc)Vmap_contains,	        /* sq_contains */
  (binaryfunc)Vmap_inplace_concat,	/* sq_inplace_concat */
  (intargfunc)Vmap_inplace_repeat,	/* sq_inplace_repeat */
  
};
/* ----------------------------------------------------------- BUFFER */
/* XXXX these are prolly borked (might work in STAYOPEN)
   Functions for treating an mmap'ed file as a buffer */
static int Vmap_buffer_getreadbuf(VmapObject *self, int index, const void **ptr) {
  CHECK_VALID(-1);
  if ( index != 0 ) {
    PyErr_SetString(PyExc_SystemError,"Accessing non-existent Vmap segment");
    return -1;
  }
  *ptr = self->data;
  return self->size;
}
static int Vmap_buffer_getwritebuf(VmapObject *self, int index, const void **ptr) {  
  CHECK_VALID(-1);
  if ( index != 0 ) {
    PyErr_SetString(PyExc_SystemError, "Accessing non-existent Vmap segment");
    return -1;
  }
  *ptr = self->data;
  return self->size;
}
static int Vmap_buffer_getsegcount(VmapObject *self, int *lenp) {
  CHECK_VALID(-1);
  if (lenp) 
    *lenp = self->size;
  return 1;
}
static int Vmap_buffer_getcharbuffer(VmapObject *self, int index, const void **ptr) {
  CHECK_VALID(-1);
  if ( index != 0 ) {
    PyErr_SetString(PyExc_SystemError,"accessing non-existent buffer segment");
    return -1;
  }
  *ptr = (const char *)self->data;
  return self->size;
}
/* ------------------------------- */
static PyBufferProcs Vmap_as_buffer = {
  (getreadbufferproc)Vmap_buffer_getreadbuf,
  (getwritebufferproc)Vmap_buffer_getwritebuf,
  (getsegcountproc)Vmap_buffer_getsegcount,
  (getcharbufferproc)Vmap_buffer_getcharbuffer,
};
/* -------------------------------------------------------------------------- Object def  */
static PyTypeObject Vmaptype = {
  PyObject_HEAD_INIT(&PyType_Type)
  0,			/*ob_size*/
  "Vmap",			/*tp_name*/
  sizeof(VmapObject),	/*tp_basicsize*/
  0,			/*tp_itemsize*/
  /* methods */
  (destructor)Vmap_dealloc, /*tp_dealloc*/
  0,			/*tp_print*/
  (getattrfunc)Vmap_getattr, /*tp_getattr*/
  (setattrfunc)Vmap_setattr, /*tp_setattr*/
  0,			/*tp_compare*/
  0,			/*tp_repr*/
  0,			/*tp_as_number*/
  &Vmap_as_sequence,			/*tp_as_sequence*/
  0,			/*tp_as_mapping*/
  0,			/*tp_hash*/
  0,                      /*tp_call*/
  0,                      /*tp_str*/
  0,                      /*tp_getattro*/
  0,                      /*tp_setattro*/
  &Vmap_as_buffer,                      /*tp_as_buffer*/
  Py_TPFLAGS_DEFAULT,     /*tp_flags*/
  0,                      /*tp_doc*/
  0,                      /*tp_traverse*/
  0,                      /*tp_clear*/
  0,                      /*tp_richcompare*/
  0,                      /*tp_weaklistoffset*/
  0,                      /*tp_iter*/
  0,                      /*tp_iternext*/
  Vmap_methods,                      /*tp_methods*/
  0,                      /*tp_members*/
  0,                      /*tp_getset*/
  0,                      /*tp_base*/
  0,                      /*tp_dict*/
  0,                      /*tp_descr_get*/
  0,                      /*tp_descr_set*/
  0,                      /*tp_dictoffset*/
  0,                      /*tp_init*/
  0,                      /*tp_alloc*/
  0,                      /*tp_new*/
  0,                      /*tp_free*/
  0,                      /*tp_is_gc*/
};
/* =============================================================================================
                                                                                    MODULE
   =============================================================================================
 */
/* I copied this whole from mmapmodule.c
 ------------------------------- 
   extract the map size from the given PyObject
   The map size is restricted to [0, INT_MAX] because this is the current
   Python limitation on object sizes. Although the mmap object *could* handle
   a larger map size, there is no point because all the useful operations
   (len(), slicing(), sequence indexing) are limited by a C int.
   Returns -1 on error, with an appropriate Python exception raised. On
   success, the map size is returned. */
static int _GetMapSize(PyObject *o) {
  if (PyInt_Check(o)) {
    long i = PyInt_AsLong(o);
    if (PyErr_Occurred())
      return -1;
    if (i < 0)
      goto onnegoverflow;
    if (i > INT_MAX)
      goto onposoverflow;
    return (int)i;
  }
  else if (PyLong_Check(o)) {
    long i = PyLong_AsLong(o);
    if (PyErr_Occurred()) {
      /* yes negative overflow is mistaken for positive overflow
	 but not worth the trouble to check sign of 'i' */
      if (PyErr_ExceptionMatches(PyExc_OverflowError))
	goto onposoverflow;
      else
	return -1;
    }
    if (i < 0)
      goto onnegoverflow;
    if (i > INT_MAX)
      goto onposoverflow;
    return (int)i;
  }
  else {
    PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
    return -1;
  }
  
onnegoverflow:
  PyErr_SetString(PyExc_OverflowError, "memory mapped size must be positive");
  return -1;
  
onposoverflow:
  PyErr_SetString(PyExc_OverflowError, "memory mapped size is too large (limited by C int)");
  return -1;
}
/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ */
static PyObject * Vmaps_new(PyObject *self, PyObject *args, PyObject *kwdict) {
  VmapObject *map;
  PyObject *map_size_obj = NULL;
  PyObject *start_obj = PyInt_FromLong(0);
  int map_size, start;
  int fd,  mm_flags = DFL_MM_FLAGS, prot = DFL_MM_PROT;
  int flags = DFL_VM_FLAGS;
  int otype=DFL_VM_TYPE, osize=1;
  char *keywords[] = {"fileno", "size", "start", "mm_flags", "mm_prot", "vm_flags", 
		      "vm_type",  "elsize", NULL};

  if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|Oiiiii", keywords, 
				   &fd, &map_size_obj, &start_obj, &mm_flags, &prot, 
				   &flags, &otype, &osize)
      ) return NULL;

  map_size = _GetMapSize(map_size_obj);
  if (map_size < 0) return NULL;
  start = _GetMapSize(start_obj);
  if (start < 0) start=0;
  /* could do more error checking */

  map = PyObject_NEW(VmapObject, &Vmaptype);
  if ( map == NULL ) return NULL;

  map->flags = flags;
  /* mmap call */
  map->mm_data=NULL;
  map->data = NULL;
  map->fd = fd;
  map->mm_flags = mm_flags;
  map->mm_prot = prot;
  map->mm_size = map->size = (size_t) map_size - start;
  map->start = (size_t) start;
#ifdef MADV_NORMAL
  map->mm_advflags=MADV_NORMAL;
#else
  map->mm_advflags=0;
#endif
  /* data type */
  Vmap_setype( map, otype, osize );
  map->fill=0;
  /* timestamps */
  map->rts = map->wts = map->sts = map->ots = map->cts = 0.0;
  /* locking */
  map->hspins=32;
  map->husec=1;

  return (PyObject *)map;
}
/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ */
/* List of functions defined in the module */
static char xxmod_doc[] = "noneyet";
static PyMethodDef Vmaps_methods[] = {
  /* gcc complains but works? */
  {"newmap",    (PyCFunction) Vmaps_new,  	METH_VARARGS|METH_KEYWORDS, xxmod_doc},
  {NULL,		NULL}		/* sentinel */
};
/* ======================================================================================== */
#define MDEXPORT( DCT, CVAL ) PyDict_SetItemString ( DCT , #CVAL , PyInt_FromLong( CVAL ) )

/* Initialization function for the module (*must* be called initVmaps) */
DL_EXPORT(void)
initVmaps(void) {
  PyObject *m, *d;
  
  /* Initialize the type of the new type object here; doing it here
   * is required for portability to Windows without requiring C++. 
   wh00 -ml
  */
  Vmaptype.ob_type = &PyType_Type;
  
  /* Create the module and add the functions */
  m = Py_InitModule("Vmaps", Vmaps_methods);
  
  /* Add some symbolic constants to the module */
  d = PyModule_GetDict(m);
  ErrorObject = PyErr_NewException("Vmaps.error", NULL, NULL);
  PyDict_SetItemString(d, "error", ErrorObject);

  /* defaults */
  MDEXPORT( d, DFL_MM_FLAGS );
  MDEXPORT( d, DFL_MM_PROT );
  MDEXPORT( d, DFL_VM_FLAGS );
  MDEXPORT( d, DFL_VM_TYPE );
  MDEXPORT( d, HEADALIGN );

  /* VM_ flags */
  MDEXPORT( d, VM_AUTOPEN );
  MDEXPORT( d, VM_STAYOPEN );
  MDEXPORT( d, VM_ADVOPEN );
  MDEXPORT( d, VM_SYNCLOSE );
  MDEXPORT( d, VM_ASYNCLOSE );
  MDEXPORT( d, VM_KEEPTS );
  MDEXPORT( d, VM_DOFILL );
  MDEXPORT( d, VM_LLALE );
  MDEXPORT( d, VM_LLASG );
  MDEXPORT( d, VM_HEADER );
  MDEXPORT( d, VM_HDRLOCK );
  MDEXPORT( d, VM_HDRFAIL );
  MDEXPORT( d, VM_HDRTYPE );
  MDEXPORT( d, VM_HDRLEN );

  /* TYPES */
  PyDict_SetItemString (d, "Int", PyInt_FromLong(VMT_IA) );
  PyDict_SetItemString (d, "Float", PyInt_FromLong(VMT_DA) );
  PyDict_SetItemString (d, "Long", PyInt_FromLong(VMT_LL) );
  PyDict_SetItemString (d, "Int2d", PyInt_FromLong(VMT_2IA) );
  PyDict_SetItemString (d, "Long2d", PyInt_FromLong(VMT_2LA) );
  PyDict_SetItemString (d, "Float2d", PyInt_FromLong(VMT_2FA) );
  PyDict_SetItemString (d, "Char", PyInt_FromLong(VMT_RAW) );
  PyDict_SetItemString (d, "FixChar", PyInt_FromLong(VMT_SA) );
  PyDict_SetItemString (d, "FixLong", PyInt_FromLong(VMT_LLA) );
  //PyDict_SetItemString (d, "", PyInt_FromLong(VMT_) );

  PyDict_SetItemString (d, "PAGESIZE", PyInt_FromLong( (long)my_getpagesize() ) );
#ifdef PROT_EXEC
  MDEXPORT( d, PROT_EXEC );
#endif
#ifdef PROT_READ
  MDEXPORT( d, PROT_READ );
#endif
#ifdef PROT_WRITE
  MDEXPORT( d, PROT_WRITE );
#endif
#ifdef MAP_SHARED
  MDEXPORT( d, MAP_SHARED );
#endif
#ifdef MAP_PRIVATE
  MDEXPORT( d, MAP_PRIVATE );
#endif
#ifdef MAP_ANON
  MDEXPORT( d, MAP_ANON );
#endif
#ifdef	MAP_NORESERVE	
  MDEXPORT( d, MAP_NORESERVE );
#endif
#ifdef MS_ASYNC
  MDEXPORT( d, MS_ASYNC );
#endif
#ifdef MS_SYNC
  MDEXPORT( d, MS_SYNC );
#endif
#ifdef MS_INVALIDATE
  MDEXPORT( d, MS_INVALIDATE );
#endif
#ifdef MADV_NORMAL
  MDEXPORT( d, MADV_NORMAL );
#endif
#ifdef MADV_RANDOM
  MDEXPORT( d, MADV_RANDOM );
#endif
#ifdef MADV_SEQUENTIAL
  MDEXPORT( d, MADV_SEQUENTIAL );
#endif
#ifdef MADV_WILLNEED
  MDEXPORT( d, MADV_WILLNEED );
#endif
#ifdef MADV_DONTNEED
  MDEXPORT( d, MADV_DONTNEED );
#endif
#ifdef MADV_FREE
  MDEXPORT( d, MADV_FREE );
#endif
}
