/*************************************************************************************************
 * Emulation of system calls
 *                                                      Copyright (C) 2000-2003 Mikio Hirabayashi
 * This file is part of QDBM, Quick Database Manager.
 * QDBM is free software; you can redistribute it and/or modify it under the terms of the GNU
 * Lesser General Public License as published by the Free Software Foundation; either version
 * 2.1 of the License or any later version.  QDBM 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 Lesser General Public License for more
 * details.
 * You should have received a copy of the GNU Lesser General Public License along with QDBM; if
 * not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 * 02111-1307 USA.
 *************************************************************************************************/


#include "myconf.h"



/*************************************************************************************************
 * for systems without mmap
 *************************************************************************************************/


#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_) || defined(_SYS_RISCOS_) || defined(MYNOMMAP)


void *_qdbm_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset){
  char *buf, *wp;
  int rv, rlen;
  if(flags & MAP_FIXED) return MAP_FAILED;
  if(lseek(fd, SEEK_SET, offset) == -1) return MAP_FAILED;
  if(!(buf = malloc(sizeof(int) * 3 + length))) return MAP_FAILED;
  wp = buf;
  *(int *)wp = fd;
  wp += sizeof(int);
  *(int *)wp = offset;
  wp += sizeof(int);
  *(int *)wp = prot;
  wp += sizeof(int);
  rlen = 0;
  while((rv = read(fd, wp + rlen, length - rlen)) > 0){
    rlen += rv;
  }
  if(rv == -1 || rlen != length){
    free(buf);
    return MAP_FAILED;
  }
  return wp;
}


int _qdbm_munmap(void *start, size_t length){
  char *buf, *rp;
  int fd, offset, prot, rv, wlen;
  buf = (char *)start - sizeof(int) * 3;
  rp = buf;
  fd = *(int *)rp;
  rp += sizeof(int);
  offset = *(int *)rp;
  rp += sizeof(int);
  prot = *(int *)rp;
  rp += sizeof(int);
  if(prot & PROT_WRITE){
    if(lseek(fd, offset, SEEK_SET) == -1){
      free(buf);
      return -1;
    }
    wlen = 0;
    while(wlen < length){
      rv = write(fd, rp + wlen, length - wlen);
      if(rv == -1){
        if(errno == EINTR) continue;
        free(buf);
        return -1;
      }
      wlen += rv;
    }
  }
  free(buf);
  return 0;
}


int _qdbm_msync(const void *start, size_t length, int flags){
  char *buf, *rp;
  int fd, offset, prot, rv, wlen;
  buf = (char *)start - sizeof(int) * 3;
  rp = buf;
  fd = *(int *)rp;
  rp += sizeof(int);
  offset = *(int *)rp;
  rp += sizeof(int);
  prot = *(int *)rp;
  rp += sizeof(int);
  if(prot & PROT_WRITE){
    if(lseek(fd, offset, SEEK_SET) == -1) return -1;
    wlen = 0;
    while(wlen < length){
      rv = write(fd, rp + wlen, length - wlen);
      if(rv == -1){
        if(errno == EINTR) continue;
        return -1;
      }
      wlen += rv;
    }
  }
  return 0;
}


#endif



/*************************************************************************************************
 * for Win32
 *************************************************************************************************/


#if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)


int _qdbm_win32_fcntl(int fd, int cmd, struct flock *lock){
  HANDLE fh;
  OVERLAPPED ol;
  fh = (HANDLE)_get_osfhandle(fd);
  memset(&ol, 0, sizeof(OVERLAPPED));
  ol.Offset = 0;
  ol.OffsetHigh = 0;
  ol.hEvent = 0;
  if(!LockFileEx(fh, lock->l_type == F_WRLCK ? LOCKFILE_EXCLUSIVE_LOCK : 0, 0, 0, 1, &ol))
    return -1;
  return 0;
}


#endif


#if defined(_SYS_MSVC_)


DIR *_qdbm_win32_opendir(const char *name){
  char expr[1024];
  DIR *dir;
  HANDLE fh;
  WIN32_FIND_DATA data;
  sprintf(expr, "%s%c*", name, MYPATHCHR);
  if((fh = FindFirstFile(expr, &data)) == INVALID_HANDLE_VALUE) return NULL;
  if(!(dir = malloc(sizeof(DIR)))){
    FindClose(fh);
    return NULL;
  }
  dir->fh = fh;
  dir->data = data;
  dir->first = TRUE;
  return dir;
}


int _qdbm_win32_closedir(DIR *dir){
  if(!FindClose(dir->fh)){
    free(dir);
    return -1;
  }
  free(dir);
  return 0;
}


struct dirent *_qdbm_win32_readdir(DIR *dir){
  if(dir->first){
    sprintf(dir->de.d_name, "%s", dir->data.cFileName);
    dir->first = FALSE;
    return &(dir->de);
  }
  if(!FindNextFile(dir->fh, &(dir->data))) return NULL;
  sprintf(dir->de.d_name, "%s", dir->data.cFileName);
  return &(dir->de);
}


#endif



/*************************************************************************************************
 * for ZLIB
 *************************************************************************************************/


#if defined(MYZLIB)


#include <zlib.h>

#define ZLIBBUFSIZ     8192
#define ZLIBCLEVEL     5


static char *_qdbm_deflate_impl(const char *ptr, int size, int *sp);
static char *_qdbm_inflate_impl(const char *ptr, int size, int *sp);


char *(*_qdbm_deflate)(const char *, int, int *) = _qdbm_deflate_impl;
char *(*_qdbm_inflate)(const char *, int, int *) = _qdbm_inflate_impl;


static char *_qdbm_deflate_impl(const char *ptr, int size, int *sp){
  z_stream zs;
  char *buf, *swap;
  unsigned char obuf[ZLIBBUFSIZ];
  int rv, asiz, bsiz, osiz;
  if(size < 0) size = strlen(ptr);
  zs.zalloc = Z_NULL;
  zs.zfree = Z_NULL;
  zs.opaque = Z_NULL;
  if(deflateInit(&zs, ZLIBCLEVEL) != Z_OK) return NULL;
  asiz = ZLIBBUFSIZ;
  if(!(buf = malloc(asiz))){
    deflateEnd(&zs);
    return NULL;
  }
  bsiz = 0;
  zs.next_in = (unsigned char *)ptr;
  zs.avail_in = size;
  zs.next_out = obuf;
  zs.avail_out = ZLIBBUFSIZ;
  while((rv = deflate(&zs, Z_FINISH)) == Z_OK){
    osiz = ZLIBBUFSIZ - zs.avail_out;
    if(bsiz + osiz > asiz){
      asiz = asiz * 2 + osiz;
      if(!(swap = realloc(buf, asiz))){
        free(buf);
        deflateEnd(&zs);
        return NULL;
      }
      buf = swap;
    }
    memcpy(buf + bsiz, obuf, osiz);
    bsiz += osiz;
    zs.next_out = obuf;
    zs.avail_out = ZLIBBUFSIZ;
  }
  if(rv != Z_STREAM_END){
    free(buf);
    deflateEnd(&zs);
    return NULL;
  }
  osiz = ZLIBBUFSIZ - zs.avail_out;
  if(bsiz + osiz > asiz){
    asiz = asiz * 2 + osiz;
    if(!(swap = realloc(buf, asiz))){
      free(buf);
      deflateEnd(&zs);
      return NULL;
    }
    buf = swap;
  }
  memcpy(buf + bsiz, obuf, osiz);
  bsiz += osiz;
  *sp = bsiz;
  deflateEnd(&zs);
  return buf;
}


static char *_qdbm_inflate_impl(const char *ptr, int size, int *sp){
  z_stream zs;
  char *buf, *swap;
  unsigned char obuf[ZLIBBUFSIZ];
  int rv, asiz, bsiz, osiz;
  zs.zalloc = Z_NULL;
  zs.zfree = Z_NULL;
  zs.opaque = Z_NULL;
  if(inflateInit(&zs) != Z_OK) return NULL;
  asiz = ZLIBBUFSIZ;
  if(!(buf = malloc(asiz))){
    deflateEnd(&zs);
    return NULL;
  }
  bsiz = 0;
  zs.next_in = (unsigned char *)ptr;
  zs.avail_in = size;
  zs.next_out = obuf;
  zs.avail_out = ZLIBBUFSIZ;
  while((rv = inflate(&zs, Z_NO_FLUSH)) == Z_OK){
    osiz = ZLIBBUFSIZ - zs.avail_out;
    if(bsiz + osiz >= asiz){
      asiz = asiz * 2 + osiz;
      if(!(swap = realloc(buf, asiz))){
        free(buf);
        deflateEnd(&zs);
        return NULL;
      }
      buf = swap;
    }
    memcpy(buf + bsiz, obuf, osiz);
    bsiz += osiz;
    zs.next_out = obuf;
    zs.avail_out = ZLIBBUFSIZ;
  }
  if(rv != Z_STREAM_END){
    free(buf);
    inflateEnd(&zs);
    return NULL;
  }
  osiz = ZLIBBUFSIZ - zs.avail_out;
  if(bsiz + osiz >= asiz){
    asiz = asiz * 2 + osiz;
    if(!(swap = realloc(buf, asiz))){
      free(buf);
      deflateEnd(&zs);
      return NULL;
    }
    buf = swap;
  }
  memcpy(buf + bsiz, obuf, osiz);
  bsiz += osiz;
  buf[bsiz] = '\0';
  if(sp) *sp = bsiz;
  inflateEnd(&zs);
  return buf;
}


#else


char *(*_qdbm_deflate)(const char *, int, int *) = NULL;
char *(*_qdbm_inflate)(const char *, int, int *) = NULL;


#endif




/*************************************************************************************************
 * common settings
 *************************************************************************************************/


int _qdbm_dummyfunc(void){
  return 0;
}



/* END OF FILE */
