php-src/ext/dba/libcdb/cdb.c
Xinchen Hui d64d9e3351 year++
2012-09-05 23:08:05 +08:00

195 lines
4.2 KiB
C

/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2012 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.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. |
+----------------------------------------------------------------------+
| Author: Marcus Boerger <helly@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
/* incorporated from D.J.Bernstein's cdb-0.75 (http://cr.yp.to/cdb.html)*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include <sys/types.h>
#include <sys/stat.h>
#ifndef PHP_WIN32
#include <sys/mman.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <errno.h>
#include "cdb.h"
#ifndef EPROTO
# define EPROTO -15 /* cdb 0.75's default for PROTOless systems */
#endif
/* {{{ cdb_match */
static int cdb_match(struct cdb *c, char *key, unsigned int len, uint32 pos TSRMLS_DC)
{
char buf[32];
unsigned int n;
while (len > 0) {
n = sizeof(buf);
if (n > len)
n = len;
if (cdb_read(c, buf, n, pos TSRMLS_CC) == -1)
return -1;
if (memcmp(buf, key, n))
return 0;
pos += n;
key += n;
len -= n;
}
return 1;
}
/* }}} */
/* {{{ cdb_hash */
uint32 cdb_hash(char *buf, unsigned int len)
{
uint32 h;
const unsigned char * b = (unsigned char *)buf;
h = CDB_HASHSTART;
while (len--) {
h = ( h + (h << 5)) ^ (*b++);
}
return h;
}
/* }}} */
/* {{{ cdb_free */
void cdb_free(struct cdb *c TSRMLS_DC)
{
}
/* }}} */
/* {{{ cdb_findstart */
void cdb_findstart(struct cdb *c TSRMLS_DC)
{
c->loop = 0;
}
/* }}} */
/* {{{ cdb_init */
void cdb_init(struct cdb *c, php_stream *fp TSRMLS_DC)
{
cdb_free(c TSRMLS_CC);
cdb_findstart(c TSRMLS_CC);
c->fp = fp;
}
/* }}} */
/* {{{ cdb_read */
int cdb_read(struct cdb *c, char *buf, unsigned int len, uint32 pos TSRMLS_DC)
{
if (php_stream_seek(c->fp, pos, SEEK_SET) == -1) {
errno = EPROTO;
return -1;
}
while (len > 0) {
int r;
do {
r = php_stream_read(c->fp, buf, len);
} while ((r == -1) && (errno == EINTR));
if (r == -1)
return -1;
if (r == 0) {
errno = EPROTO;
return -1;
}
buf += r;
len -= r;
}
return 0;
}
/* }}} */
/* {{{ cdb_findnext */
int cdb_findnext(struct cdb *c, char *key, unsigned int len TSRMLS_DC)
{
char buf[8];
uint32 pos;
uint32 u;
if (!c->loop) {
u = cdb_hash(key, len);
if (cdb_read(c, buf, 8, (u << 3) & 2047 TSRMLS_CC) == -1)
return -1;
uint32_unpack(buf + 4,&c->hslots);
if (!c->hslots)
return 0;
uint32_unpack(buf, &c->hpos);
c->khash = u;
u >>= 8;
u %= c->hslots;
u <<= 3;
c->kpos = c->hpos + u;
}
while (c->loop < c->hslots) {
if (cdb_read(c, buf, 8, c->kpos TSRMLS_CC) == -1)
return -1;
uint32_unpack(buf + 4, &pos);
if (!pos)
return 0;
c->loop += 1;
c->kpos += 8;
if (c->kpos == c->hpos + (c->hslots << 3))
c->kpos = c->hpos;
uint32_unpack(buf, &u);
if (u == c->khash) {
if (cdb_read(c, buf, 8, pos TSRMLS_CC) == -1)
return -1;
uint32_unpack(buf, &u);
if (u == len)
switch(cdb_match(c, key, len, pos + 8 TSRMLS_CC)) {
case -1:
return -1;
case 1:
uint32_unpack(buf + 4, &c->dlen);
c->dpos = pos + 8 + len;
return 1;
}
}
}
return 0;
}
/* }}} */
/* {{{ cdb_find */
int cdb_find(struct cdb *c, char *key, unsigned int len TSRMLS_DC)
{
cdb_findstart(c TSRMLS_CC);
return cdb_findnext(c, key, len TSRMLS_CC);
}
/* }}} */
/* {{{ cdb_version */
char *cdb_version()
{
return "0.75, $Id$";
}
/* }}} */