text: /*
     +----------------------------------------------------------------------+
     | PHP Version 4                                                        |
     +----------------------------------------------------------------------+
     | Copyright (c) 1997-2003 The PHP Group                                |
     +----------------------------------------------------------------------+
     | This source file is subject to version 2.02 of the PHP license,      |
     | that is bundled with this package in the file LICENSE, and is        |
     | available at through the world-wide-web at                           |
     | http://www.php.net/license/2_02.txt.                                 |
     | If you did not receive a copy of the PHP license and are unable to   |
     | obtain it through the world-wide-web, please send a note to          |
     | license@php.net so we can mail you a copy immediately.               |
     +----------------------------------------------------------------------+
     | Authors: Sascha Schumann <sascha@schumann.cx>                        |
     |          Marcus Boerger <helly@php.net>                              |
     +----------------------------------------------------------------------+
   */
  
  /* $Id: dba_cdb.c,v 1.23.2.6 2003/04/16 19:14:29 helly Exp $ */
  
  #ifdef HAVE_CONFIG_H
  #include "config.h"
  #endif
  
  #include "php.h"
  
  #if DBA_CDB
  #include "php_cdb.h"
  
  #include <sys/types.h>
  #ifdef HAVE_UNISTD_H
  #include <unistd.h>
  #endif
  #include <fcntl.h>
  
  #if DBA_CDB_BUILTIN
  # include "libcdb/cdb.h"
  # include "libcdb/cdb_make.h"
  # include "libcdb/uint32.h"
  #else
  # ifdef CDB_INCLUDE_FILE
  #  include CDB_INCLUDE_FILE
  # endif
  #endif
  
  #define CDB_INFO \
  	dba_cdb *cdb = (dba_cdb *) info->dbf
  
  typedef struct {
  	struct cdb c;
  #if DBA_CDB_BUILTIN
  	struct cdb_make m;
  	php_stream *file;
  	int make;
  #else
  	int file;
  #endif
  	uint32 eod; /* size of constant database */
  	uint32 pos; /* current position for traversing */
  } dba_cdb;
  
  DBA_OPEN_FUNC(cdb)
  {
  #if DBA_CDB_BUILTIN
  	php_stream* file = 0;
  	int make;
  #else
  	int file = 0;
  #endif
  	dba_cdb *cdb;
  	dba_info *pinfo = (dba_info *) info;
  
  	switch (info->mode) {
  		case DBA_READER: 
  #if DBA_CDB_BUILTIN
  			make = 0;
  			file = info->fp;
  #else
  			file = VCWD_OPEN(info->path, O_RDONLY);
  			if (file < 0) {
  				*error = "Unable to open file";
  				return FAILURE;
  			}
  #endif
  			break;
  #if DBA_CDB_BUILTIN
  		case DBA_TRUNC:
  			make = 1;
  			file = info->fp;
  			break;
  		case DBA_CREAT:
  		case DBA_WRITER:
  			*error = "Update operations are not supported";
  			return FAILURE; /* not supported */
  #endif
  		default: 
  			*error = "Currently not supported";
  			return FAILURE;
  	}
  
  	cdb = pemalloc(sizeof(dba_cdb), info->flags&DBA_PERSISTENT);
  	memset(cdb, 0, sizeof(dba_cdb));
  
  #if DBA_CDB_BUILTIN
  	if (make) {
  		cdb_make_start(&cdb->m, file TSRMLS_CC);
  	} else {
  		cdb_init(&cdb->c, file TSRMLS_CC);
  	}
  	cdb->make = make;
  #else
  	cdb_init(&cdb->c, file);
  #endif
  	cdb->file = file;
  	
  	pinfo->dbf = cdb;
  	return SUCCESS;
  }
  
  DBA_CLOSE_FUNC(cdb)
  {
  	CDB_INFO;
  
  	/* cdb_free does not close associated file */
  #if DBA_CDB_BUILTIN
  	if (cdb->make) {
  		cdb_make_finish(&cdb->m TSRMLS_CC);
  	} else {
  		cdb_free(&cdb->c TSRMLS_CC);
  	}
  #else
  	cdb_free(&cdb->c);
  	close(cdb->file);
  #endif
  	pefree(cdb, info->flags&DBA_PERSISTENT);
  }
  
  #if DBA_CDB_BUILTIN
  # define php_cdb_read(cdb, buf, len, pos) cdb_read(cdb, buf, len, pos TSRMLS_CC)
  # define php_cdb_findnext(cdb, key, len) cdb_findnext(cdb, key, len TSRMLS_CC)
  # define php_cdb_find(cdb, key, len) cdb_find(cdb, key, len TSRMLS_CC)
  #else
  # define php_cdb_read(cdb, buf, len, pos) cdb_read(cdb, buf, len, pos)
  # define php_cdb_findnext(cdb, key, len) cdb_findnext(cdb, key, len)
  # define php_cdb_find(cdb, key, len) cdb_find(cdb, key, len)
  #endif
  
  DBA_FETCH_FUNC(cdb)
  {
  	CDB_INFO;
  	unsigned int len;
  	char *new_entry = NULL;
  	
  #if DBA_CDB_BUILTIN
  	if (cdb->make)
  		return NULL; /* database was opened writeonly */
  #endif
  	if (php_cdb_find(&cdb->c, key, keylen) == 1) {
  		while(skip--) {
  			if (php_cdb_findnext(&cdb->c, key, keylen) != 1) {
  				return NULL;
  			}
  		}
  		len = cdb_datalen(&cdb->c);
  		new_entry = safe_emalloc(len, 1, 1);
  		
  		if (php_cdb_read(&cdb->c, new_entry, len, cdb_datapos(&cdb->c)) == -1) {
  			efree(new_entry);
  			return NULL;
  		}
  		new_entry[len] = 0;
  		if (newlen) 
  			*newlen = len;
  	}
  	
  	return new_entry;
  }
  
  DBA_UPDATE_FUNC(cdb)
  {
  #if DBA_CDB_BUILTIN
  	CDB_INFO;
  
  	if (!cdb->make)
  		return FAILURE; /* database was opened readonly */
  	if (!mode)
  		return FAILURE; /* cdb_make dosn't know replace */
  	if (cdb_make_add(&cdb->m, key, keylen, val, vallen TSRMLS_CC) != -1)
  		return SUCCESS;
  #endif
  	return FAILURE;
  }
  
  DBA_EXISTS_FUNC(cdb)
  {
  	CDB_INFO;
  
  #if DBA_CDB_BUILTIN
  	if (cdb->make)
  		return FAILURE; /* database was opened writeonly */
  #endif
  	if (php_cdb_find(&cdb->c, key, keylen) == 1)
  		return SUCCESS;
  	return FAILURE;
  }
  
  DBA_DELETE_FUNC(cdb)
  {
  	return FAILURE; /* cdb doesn't support delete */
  }
  
  /* {{{ cdb_file_read */
  #if DBA_CDB_BUILTIN
  # define cdb_file_read(fildes, buf, size) php_stream_read(fildes, buf, size)
  #else
  # define cdb_file_read(fildes, buf, size) read(fildes, buf, size)
  #endif
  /* }}} */
  
  #define CREAD(n) do { \
  	if (cdb_file_read(cdb->file, buf, n) < n) return NULL; \
  } while (0)
  
  /* {{{ cdb_file_lseek 
   php_stream_seek does not return actual position */
  #if DBA_CDB_BUILTIN
  int cdb_file_lseek(php_stream *fp, off_t offset, int whence TSRMLS_DC) {
  	php_stream_seek(fp, offset, whence);
  	return php_stream_tell(fp);
  }
  #else
  int cdb_file_lseek(int fd, off_t offset, int whence TSRMLS_DC) {
  	return lseek(fd, offset, whence);
  }
  #endif
  /* }}} */
  
  #define CSEEK(n) do { \
  	if (n >= cdb->eod) return NULL; \
  	if (cdb_file_lseek(cdb->file, (off_t)n, SEEK_SET TSRMLS_CC) != (off_t) n) return NULL; \
  } while (0)
  
  
  DBA_FIRSTKEY_FUNC(cdb)
  {
  	CDB_INFO;
  	uint32 klen, dlen;
  	char buf[8];
  	char *key;
  
  #if DBA_CDB_BUILTIN
  	if (cdb->make)
  		return NULL; /* database was opened writeonly */
  #endif
  
  	cdb->eod = -1;
  	CSEEK(0);
  	CREAD(4);
  	
  	/* Total length of file in bytes */
  	uint32_unpack(buf, &cdb->eod);
  	
  	CSEEK(2048);
  	CREAD(8);
  	
  	/* The first four bytes contain the length of the key */
  	uint32_unpack(buf, &klen);
  	uint32_unpack(buf + 4, &dlen);
  
  	key = safe_emalloc(klen, 1, 1);
  	if (cdb_file_read(cdb->file, key, klen) < klen) {
  		efree(key);
  		key = NULL;
  	} else {
  		key[klen] = '\0';
  		if (newlen) *newlen = klen;
  	}
  
  	/*       header + klenlen + dlenlen + klen + dlen */
  	cdb->pos = 2048 + 4       + 4       + klen + dlen;
  		
  	return key;
  }
  
  DBA_NEXTKEY_FUNC(cdb)
  {
  	CDB_INFO;
  	uint32 klen, dlen;
  	char buf[8];
  	char *key;
  
  #if DBA_CDB_BUILTIN
  	if (cdb->make)
  		return NULL; /* database was opened writeonly */
  #endif
  
  	CSEEK(cdb->pos);
  	CREAD(8);
  	uint32_unpack(buf, &klen);
  	uint32_unpack(buf + 4, &dlen);
  	
  	key = safe_emalloc(klen, 1, 1);
  	if (cdb_file_read(cdb->file, key, klen) < klen) {
  		efree(key);
  		key = NULL;
  	} else {
  		key[klen] = '\0';
  		if (newlen) *newlen = klen;
  	}
  	
  	cdb->pos += 8 + klen + dlen;
  	
  	return key;
  }
  
  DBA_OPTIMIZE_FUNC(cdb)
  {
  	return SUCCESS;
  }
  
  DBA_SYNC_FUNC(cdb)
  {
  	/* this is read-only */
  	return SUCCESS;
  }
  
  DBA_INFO_FUNC(cdb)
  {
  #if DBA_CDB_BUILTIN
  	if (!strcmp(hnd->name, "cdb")) {
  		return estrdup(cdb_version());
  	} else {
  		return estrdup(cdb_make_version());
  	}
  #else
  	return estrdup("External");
  #endif
  }
  
  #endif
  
  /*
   * Local variables:
   * tab-width: 4
   * c-basic-offset: 4
   * End:
   * vim600: sw=4 ts=4 fdm=marker
   * vim<600: sw=4 ts=4
   */
  