@Added dba handler inifiles to support ini files. (Marcus)

This commit is contained in:
Marcus Boerger 2003-02-22 17:20:06 +00:00
parent 8c2dbd5f0f
commit 8ab1924ca3
7 changed files with 977 additions and 6 deletions

View file

@ -380,6 +380,25 @@ AC_ARG_WITH(cdb,
])
AC_DBA_STD_RESULT(cdb)
AC_DEFUN(PHP_DBA_BUILTIN_INI,[
PHP_ADD_BUILD_DIR($ext_builddir/libini)
AC_DEFINE(DBA_INIFILE, 1, [ ])
ini_sources="libinifile/inifile.c"
THIS_RESULT="builtin"
])
AC_ARG_WITH(inifile,
[ --with-inifile DBA: Include INI support],[
if test "$withval" != "no"; then
PHP_DBA_BUILTIN_INI
fi
],[
if test "$PHP_DBA" != "no"; then
PHP_DBA_BUILTIN_INI
fi
])
AC_DBA_STD_RESULT(inifile,INI File)
AC_DEFUN(PHP_DBA_BUILTIN_FLATFILE,[
PHP_ADD_BUILD_DIR($ext_builddir/libflatfile)
AC_DEFINE(DBA_FLATFILE, 1, [ ])
@ -406,7 +425,7 @@ AC_MSG_CHECKING(whether to enable DBA interface)
if test "$HAVE_DBA" = "1"; then
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_DBA, 1, [ ])
PHP_NEW_EXTENSION(dba, dba.c dba_cdb.c dba_db2.c dba_dbm.c dba_gdbm.c dba_ndbm.c dba_db3.c dba_db4.c dba_flatfile.c $cdb_sources $flat_sources, $ext_shared)
PHP_NEW_EXTENSION(dba, dba.c dba_cdb.c dba_db2.c dba_dbm.c dba_gdbm.c dba_ndbm.c dba_db3.c dba_db4.c dba_flatfile.c dba_inifile.c $cdb_sources $flat_sources $ini_sources, $ext_shared)
PHP_SUBST(DBA_SHARED_LIBADD)
else
AC_MSG_RESULT(no)

View file

@ -47,6 +47,7 @@
#include "php_db3.h"
#include "php_db4.h"
#include "php_flatfile.h"
#include "php_inifile.h"
/* {{{ dba_functions[]
*/
@ -189,6 +190,9 @@ static dba_handler handler[] = {
#if DBA_DB4
DBA_HND(db4, DBA_LOCK_ALL) /* No lock in lib */
#endif
#if DBA_INIFILE
DBA_HND(inifile, DBA_STREAM_OPEN|DBA_LOCK_ALL) /* No lock in lib */
#endif
#if DBA_FLATFILE
DBA_HND(flatfile, DBA_STREAM_OPEN|DBA_LOCK_ALL) /* No lock in lib */
#endif
@ -212,6 +216,7 @@ static dba_handler handler[] = {
#else
#define DBA_DEFAULT ""
#endif
/* cdb/cdb_make and ini are no option here */
ZEND_BEGIN_MODULE_GLOBALS(dba)
char *default_handler;
@ -729,8 +734,29 @@ PHP_FUNCTION(dba_fetch)
int len = 0;
DBA_ID_GET2_3;
if (ac==3 && strcmp(info->hnd->name, "cdb")) {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Handler %s does not support optional skip parameter", info->hnd->name);
if (ac==3) {
if (!strcmp(info->hnd->name, "cdb")) {
if (skip < 0) {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Handler %s accepts only skip values greater than or equal to zero, using skip=0", info->hnd->name);
skip = 0;
}
} else if (!strcmp(info->hnd->name, "inifile")) {
/* "-1" is compareable to 0 but allows a non restrictive
* access which is fater. For example 'inifile' uses this
* to allow faster access when the key was already found
* using firstkey/nextkey. However explicitly setting the
* value to 0 ensures the first value.
*/
if (skip < -1) {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Handler %s accepts only skip value -1 and greater, using skip=0", info->hnd->name);
skip = 0;
}
} else {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Handler %s does not support optional skip parameter, the value will be ignored", info->hnd->name);
skip = 0;
}
} else {
skip = 0;
}
if((val = info->hnd->fetch(info, VALLEN(key), skip, &len TSRMLS_CC)) != NULL) {
if (val && PG(magic_quotes_runtime)) {
@ -773,7 +799,8 @@ PHP_FUNCTION(dba_nextkey)
/* }}} */
/* {{{ proto bool dba_delete(string key, int handle)
Deletes the entry associated with key */
Deletes the entry associated with key
If inifile: remove all other key lines */
PHP_FUNCTION(dba_delete)
{
DBA_ID_GET2;
@ -787,7 +814,8 @@ PHP_FUNCTION(dba_delete)
/* }}} */
/* {{{ proto bool dba_insert(string key, string value, int handle)
Inserts value as key, returns false, if key exists already */
If not inifile: Insert value as key, return false, if key exists already
If inifile: Add vakue as key (next instance of key) */
PHP_FUNCTION(dba_insert)
{
php_dba_update(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
@ -795,7 +823,8 @@ PHP_FUNCTION(dba_insert)
/* }}} */
/* {{{ proto bool dba_replace(string key, string value, int handle)
Inserts value as key, replaces key, if key exists already */
Inserts value as key, replaces key, if key exists already
If inifile: remove all other key lines */
PHP_FUNCTION(dba_replace)
{
php_dba_update(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);

186
ext/dba/dba_inifile.c Normal file
View file

@ -0,0 +1,186 @@
/*
+----------------------------------------------------------------------+
| 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. |
+----------------------------------------------------------------------+
| Author: Marcus Boerger <helly@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#if DBA_INIFILE
#include "php_inifile.h"
#include "libinifile/inifile.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define INIFILE_DATA \
inifile *dba = info->dbf
#define INIFILE_GKEY \
key_type ini_key = inifile_key_split((char*)key) /* keylen not needed here */
#define INIFILE_DONE \
inifile_key_free(&ini_key)
DBA_OPEN_FUNC(inifile)
{
info->dbf = inifile_alloc(info->fp, info->mode == DBA_READER, info->flags&DBA_PERSISTENT TSRMLS_CC);
return info->dbf ? SUCCESS : FAILURE;
}
DBA_CLOSE_FUNC(inifile)
{
INIFILE_DATA;
inifile_free(dba, info->flags&DBA_PERSISTENT);
}
DBA_FETCH_FUNC(inifile)
{
val_type ini_val;
INIFILE_DATA;
INIFILE_GKEY;
ini_val = inifile_fetch(dba, &ini_key, skip TSRMLS_CC);
*newlen = ini_val.value ? strlen(ini_val.value) : 0;
INIFILE_DONE;
return ini_val.value;
}
DBA_UPDATE_FUNC(inifile)
{
val_type ini_val;
int res;
INIFILE_DATA;
INIFILE_GKEY;
ini_val.value = val;
if (mode == 1) {
res = inifile_append(dba, &ini_key, &ini_val TSRMLS_CC);
} else {
res = inifile_replace(dba, &ini_key, &ini_val TSRMLS_CC);
}
INIFILE_DONE;
switch(res) {
case -1:
php_error_docref1(NULL TSRMLS_CC, key, E_WARNING, "Operation not possible");
return FAILURE;
default:
case 0:
return SUCCESS;
case 1:
php_error_docref1(NULL TSRMLS_CC, key, E_WARNING, "Key already exists");
return SUCCESS;
}
}
DBA_EXISTS_FUNC(inifile)
{
val_type ini_val;
INIFILE_DATA;
INIFILE_GKEY;
ini_val = inifile_fetch(dba, &ini_key, 0 TSRMLS_CC);
INIFILE_DONE;
if (ini_val.value) {
inifile_val_free(&ini_val);
return SUCCESS;
}
return FAILURE;
}
DBA_DELETE_FUNC(inifile)
{
INIFILE_DATA;
INIFILE_GKEY;
int res = inifile_delete(dba, &ini_key TSRMLS_CC);
INIFILE_DONE;
return (res == -1 ? FAILURE : SUCCESS);
}
DBA_FIRSTKEY_FUNC(inifile)
{
INIFILE_DATA;
if (inifile_firstkey(dba TSRMLS_CC)) {
char *result = inifile_key_string(&dba->curr.key);
*newlen = strlen(result);
return result;
} else {
return NULL;
}
}
DBA_NEXTKEY_FUNC(inifile)
{
INIFILE_DATA;
if (!dba->curr.key.group && !dba->curr.key.name) {
return NULL;
}
if (inifile_nextkey(dba TSRMLS_CC)) {
char *result = inifile_key_string(&dba->curr.key);
*newlen = strlen(result);
return result;
} else {
return NULL;
}
}
DBA_OPTIMIZE_FUNC(inifile)
{
/* dummy */
return SUCCESS;
}
DBA_SYNC_FUNC(inifile)
{
/* dummy */
return SUCCESS;
}
DBA_INFO_FUNC(inifile)
{
return estrdup(inifile_version());
}
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: sw=4 ts=4 fdm=marker
* vim<600: sw=4 ts=4
*/

View file

@ -0,0 +1,629 @@
/*
+----------------------------------------------------------------------+
| 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. |
+----------------------------------------------------------------------+
| Author: Marcus Boerger <helly@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_globals.h"
#include "safe_mode.h"
#include "php_network.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "inifile.h"
/* ret = -1 means that database was opened for read-only
* ret = 0 success
* ret = 1 key already exists - nothing done
*/
/* {{{ inifile_version */
char *inifile_version()
{
return "1.0, $Revision$";
}
/* }}} */
/* {{{ inifile_free_key */
void inifile_key_free(key_type *key)
{
if (key->group) {
efree(key->group);
}
if (key->name) {
efree(key->name);
}
memset(key, 0, sizeof(key_type));
}
/* }}} */
/* {{{ inifile_free_val */
void inifile_val_free(val_type *val)
{
if (val->value) {
efree(val->value);
}
memset(val, 0, sizeof(val_type));
}
/* }}} */
/* {{{ inifile_free_val */
void inifile_line_free(line_type *ln)
{
inifile_key_free(&ln->key);
inifile_val_free(&ln->val);
ln->pos = 0;
}
/* }}} */
/* {{{ inifile_alloc */
inifile * inifile_alloc(php_stream *fp, int readonly, int persistent TSRMLS_DC)
{
inifile *dba;
int fd = 0;
if (!readonly) {
if (php_stream_is(fp, PHP_STREAM_IS_SOCKET)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't truncate sockets");
return NULL;
}
if (SUCCESS != php_stream_cast(fp, PHP_STREAM_AS_FD, (void*)&fd, 1)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not cast stream");
return NULL;
}
}
dba = pemalloc(sizeof(inifile), persistent);
memset(dba, 0, sizeof(inifile));
dba->fp = fp;
dba->fd = fd;
dba->readonly = readonly;
return dba;
}
/* }}} */
/* {{{ inifile_free */
void inifile_free(inifile *dba, int persistent)
{
if (dba) {
inifile_line_free(&dba->curr);
inifile_line_free(&dba->next);
pefree(dba, persistent);
}
}
/* }}} */
/* {{{ inifile_key_split */
key_type inifile_key_split(const char *group_name)
{
key_type key;
char *name;
if (group_name[0] == '[' && (name = strchr(group_name, ']')) != NULL) {
key.group = estrndup(group_name+1, name - (group_name + 1));
key.name = estrdup(name+1);
} else {
key.group = estrdup("");
key.name = estrdup(group_name);
}
return key;
}
/* }}} */
/* {{{ inifile_key_string */
char * inifile_key_string(const key_type *key)
{
if (key->group && *key->group) {
char *result;
spprintf(&result, 0, "[%s]%s", key->group, key->name ? key->name : "");
return result;
} else if (key->name) {
return estrdup(key->name);
} else {
return NULL;
}
}
/* }}} */
/* {{{ etrim */
static char *etrim(const char *str)
{
char *val;
size_t l;
if (!str) {
return NULL;
}
val = (char*)str;
while (strchr(" \t\r\n", *val)) {
val++;
}
l = strlen(val);
while (l && (strchr(" \t\r\n", val[l-1]))) {
l--;
}
return estrndup(val, l);
}
/* }}} */
/* {{{ inifile_findkey
*/
static int inifile_read(inifile *dba, line_type *ln TSRMLS_DC) {
char *fline;
char *pos;
inifile_val_free(&ln->val);
while ((fline = php_stream_gets(dba->fp, NULL, 0)) != NULL) {
if (fline) {
if (fline[0] == '[') {
/* A value name cannot start with '['
* So either we find a ']' or we found an error
*/
pos = strchr(fline+1, ']');
if (pos) {
*pos = '\0';
inifile_key_free(&ln->key);
ln->key.group = etrim(fline+1);
ln->key.name = estrdup("");
ln->pos = php_stream_tell(dba->fp);
efree(fline);
return 1;
} else {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "The following group was started with '[' but not ended with ']': '%s'", fline+1);
efree(fline);
continue;
}
} else {
pos = strchr(fline, '=');
if (pos) {
*pos = '\0';
/* keep group or make empty if not existent */
if (!ln->key.group) {
ln->key.group = estrdup("");
}
if (ln->key.name) {
efree(ln->key.name);
}
ln->key.name = etrim(fline);
ln->val.value = etrim(pos+1);
ln->pos = php_stream_tell(dba->fp);
efree(fline);
return 1;
} else {
/* simply ignore lines without '='
* those should be comments
*/
efree(fline);
continue;
}
}
}
}
inifile_line_free(ln);
return 0;
}
/* }}} */
/* {{{ inifile_key_cmp */
/* 0 = EQUAL
* 1 = GROUP-EQUAL,NAME-DIFFERENT
* 2 = DIFFERENT
*/
static int inifile_key_cmp(const key_type *k1, const key_type *k2 TSRMLS_DC)
{
assert(k1->group && k1->name && k2->group && k2->name);
if (!strcmp(k1->group, k2->group)) {
if (!strcmp(k1->name, k2->name)) {
return 0;
} else {
return 1;
}
} else {
return 2;
}
}
/* }}} */
/* {{{ inifile_fetch
*/
val_type inifile_fetch(inifile *dba, const key_type *key, int skip TSRMLS_DC) {
line_type ln = {{NULL,NULL},{NULL}};
val_type val;
int res, grp_eq = 0;
if (skip == -1) {
if (dba->next.key.group && dba->next.key.name && !inifile_key_cmp(&dba->next.key, key TSRMLS_CC)) {
/* we got it already from last fetch */
val.value = estrdup(dba->next.val.value ? dba->next.val.value : "");
/* allow faster access by automatically getting next key */
php_stream_seek(dba->fp, dba->next.pos, SEEK_SET);
ln.key.group = estrdup(dba->next.key.group ? dba->next.key.group : "");
inifile_read(dba, &ln TSRMLS_CC);
inifile_line_free(&dba->next);
dba->next = ln;
return val;
} else if (dba->curr.key.group && dba->curr.key.name && !inifile_key_cmp(&dba->curr.key, key TSRMLS_CC)) {
/* we got it already from firstkey/lastkey */
/*
* this optimisation does not work when firstkey/nextkey found
* any instance other than the one instance wanted.
*/
val.value = estrdup(dba->curr.val.value ? dba->curr.val.value : "");
/* allow faster access by automatically getting next key
* we must use the line pointer 'next' since we cannot change the
* line pointer of firstkey/nextkey
*/
php_stream_seek(dba->fp, dba->curr.pos, SEEK_SET);
ln.key.group = estrdup(dba->curr.key.group ? dba->curr.key.group : "");
inifile_read(dba, &ln TSRMLS_CC);
inifile_line_free(&dba->next);
dba->next = ln;
return val;
}
}
/* the slow way: restart and seacrch */
if (skip != -1 || !dba->next.key.group || !dba->next.key.name || inifile_key_cmp(&dba->next.key, key TSRMLS_CC)) {
/* specific instance or not same key -> restart search */
php_stream_rewind(dba->fp);
}
inifile_line_free(&dba->next);
if (skip == -1) {
skip = 0;
}
while(inifile_read(dba, &ln TSRMLS_CC)) {
if (!(res=inifile_key_cmp(&ln.key, key TSRMLS_CC))) {
if (!skip) {
val.value = estrdup(ln.val.value ? ln.val.value : "");
/* allow faster access by automatically getting next key */
inifile_read(dba, &ln TSRMLS_CC);
inifile_line_free(&dba->next);
dba->next = ln;
return val;
}
skip--;
} else if (res == 1) {
grp_eq = 1;
} else if (grp_eq) {
/* we are leaving group now: that means we cannot find the key */
break;
}
}
inifile_line_free(&ln);
inifile_line_free(&dba->next);
return ln.val;
}
/* }}} */
/* {{{ inifile_firstkey
*/
int inifile_firstkey(inifile *dba TSRMLS_DC) {
inifile_line_free(&dba->curr);
dba->curr.pos = 0;
return inifile_nextkey(dba TSRMLS_CC);
}
/* }}} */
/* {{{ inifile_nextkey
*/
int inifile_nextkey(inifile *dba TSRMLS_DC) {
line_type ln = {{NULL,NULL},{NULL}};
/*inifile_line_free(&dba->next); ??? */
php_stream_seek(dba->fp, dba->curr.pos, SEEK_SET);
ln.key.group = estrdup(dba->curr.key.group ? dba->curr.key.group : "");
inifile_read(dba, &ln TSRMLS_CC);
inifile_line_free(&dba->curr);
dba->curr = ln;
return ln.key.group || ln.key.name;
}
/* }}} */
/* {{{ inifile_truncate
*/
static int inifile_truncate(inifile *dba, size_t size TSRMLS_DC)
{
int res;
if ((res=ftruncate(dba->fd, size)) != 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error in ftruncate: %d", res);
return FAILURE;
}
php_stream_seek(dba->fp, size, SEEK_SET);
return SUCCESS;
}
/* }}} */
/* {{{ inifile_find_group
* if found pos_grp_start points to "[group_name]"
*/
static int inifile_find_group(inifile *dba, const key_type *key, size_t *pos_grp_start TSRMLS_DC)
{
int ret = FAILURE;
php_stream_flush(dba->fp);
php_stream_seek(dba->fp, 0, SEEK_SET);
inifile_line_free(&dba->curr);
inifile_line_free(&dba->next);
if (key->group && strlen(key->group)) {
int res;
line_type ln = {{NULL,NULL},{NULL}};
res = 1;
while(inifile_read(dba, &ln TSRMLS_CC)) {
if ((res=inifile_key_cmp(&ln.key, key TSRMLS_CC)) < 2) {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found group: %d", *pos_grp_start);
ret = SUCCESS;
break;
}
*pos_grp_start = php_stream_tell(dba->fp);
}
inifile_line_free(&ln);
} else {
*pos_grp_start = 0;
ret = SUCCESS;
}
if (ret == FAILURE) {
*pos_grp_start = php_stream_tell(dba->fp);
}
return ret;
}
/* }}} */
/* {{{ inifile_next_group
* only valid after a call to inifile_find_group
* if any next group is found pos_grp_start points to "[group_name]" or whitespace before that
*/
static int inifile_next_group(inifile *dba, const key_type *key, size_t *pos_grp_start TSRMLS_DC)
{
int ret = FAILURE;
line_type ln = {{NULL,NULL},{NULL}};
*pos_grp_start = php_stream_tell(dba->fp);
ln.key.group = estrdup(key->group);
while(inifile_read(dba, &ln TSRMLS_CC)) {
if (inifile_key_cmp(&ln.key, key TSRMLS_CC) == 2) {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found next group: %d", *pos_grp_start);
ret = SUCCESS;
break;
}
*pos_grp_start = php_stream_tell(dba->fp);
}
inifile_line_free(&ln);
return ret;
}
/* }}} */
/* {{{ inifile_copy_to
*/
static int inifile_copy_to(inifile *dba, size_t pos_start, size_t pos_end, inifile **ini_copy TSRMLS_DC)
{
php_stream *fp;
if (pos_start == pos_end) {
*ini_copy = NULL;
return SUCCESS;
}
if ((fp = php_stream_temp_create(0, 64 * 1024)) == NULL) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not create temporary stream");
*ini_copy = NULL;
return FAILURE;
}
if ((*ini_copy = inifile_alloc(fp, 1, 0 TSRMLS_CC)) == NULL) {
/* writes error */
return FAILURE;
}
php_stream_seek(dba->fp, pos_start, SEEK_SET);
if (!php_stream_copy_to_stream(dba->fp, fp, pos_end - pos_start)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not copy group [%d - %d] to temporary stream", pos_start, pos_end);
return FAILURE;
}
return SUCCESS;
}
/* }}} */
/* {{{ inifile_filter
* copy from to dba while ignoring key name (group must equal)
*/
static int inifile_filter(inifile *dba, inifile *from, const key_type *key TSRMLS_DC)
{
size_t pos_start = 0, pos_next = 0, pos_curr;
int ret = SUCCESS;
line_type ln = {{NULL,NULL},{NULL}};
php_stream_seek(from->fp, 0, SEEK_SET);
php_stream_seek(dba->fp, 0, SEEK_END);
while(inifile_read(from, &ln TSRMLS_CC)) {
switch(inifile_key_cmp(&ln.key, key TSRMLS_CC)) {
case 0:
pos_curr = php_stream_tell(from->fp);
if (pos_start != pos_next) {
php_stream_seek(from->fp, pos_start, SEEK_SET);
if (!php_stream_copy_to_stream(from->fp, dba->fp, pos_next - pos_start)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not copy [%d - %d] from temporary stream", pos_next, pos_start);
ret = FAILURE;
}
php_stream_seek(from->fp, pos_curr, SEEK_SET);
}
pos_next = pos_start = pos_curr;
break;
case 1:
pos_next = php_stream_tell(from->fp);
break;
case 2:
/* the function is meant to process only entries from same group */
assert(0);
break;
}
}
if (pos_start != pos_next) {
php_stream_seek(from->fp, pos_start, SEEK_SET);
if (!php_stream_copy_to_stream(from->fp, dba->fp, pos_next - pos_start)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not copy [%d - %d] from temporary stream", pos_next, pos_start);
ret = FAILURE;
}
}
inifile_line_free(&ln);
return SUCCESS;
}
/* }}} */
/* {{{ inifile_delete_replace_append
*/
static int inifile_delete_replace_append(inifile *dba, const key_type *key, const val_type *value, int append TSRMLS_DC)
{
size_t pos_grp_start, pos_grp_next;
inifile *ini_tmp = NULL;
php_stream *fp_tmp = NULL;
int ret;
/* 1) Search group start
* 2) Search next group
* 3) If not append: Copy group to ini_tmp
* 4) Open temp_stream and copy remainder
* 5) Truncate stream
* 6) If not append AND key.name given: Filtered copy back from ini_tmp
* to stream. Otherwise the user wanted to delete the group.
* 7) Append value if given
* 8) Append temporary stream
*/
assert(!append || (key->name && value)); /* missuse */
/* 1 - 3 */
inifile_find_group(dba, key, &pos_grp_start TSRMLS_CC);
inifile_next_group(dba, key, &pos_grp_next TSRMLS_CC);
if (append) {
ret = SUCCESS;
} else {
ret = inifile_copy_to(dba, pos_grp_start, pos_grp_next, &ini_tmp TSRMLS_CC);
}
/* 4 */
if (ret == SUCCESS) {
fp_tmp = php_stream_temp_create(0, 64 * 1024);
if (!fp_tmp) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not create temporary stream");
ret = FAILURE;
} else {
php_stream_seek(dba->fp, 0, SEEK_END);
if (pos_grp_next != php_stream_tell(dba->fp)) {
php_stream_seek(dba->fp, pos_grp_next, SEEK_SET);
if (!php_stream_copy_to_stream(dba->fp, fp_tmp, PHP_STREAM_COPY_ALL)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not copy remainder to temporary stream");
ret = FAILURE;
}
}
}
}
/* 5 */
if (ret == SUCCESS) {
ret = inifile_truncate(dba, append ? pos_grp_next : pos_grp_start TSRMLS_CC); /* writes error on fail */
}
if (ret == SUCCESS) {
if (key->name && strlen(key->name)) {
/* 6 */
if (!append && ini_tmp) {
ret = inifile_filter(dba, ini_tmp, key TSRMLS_CC);
}
/* 7 */
/* important: do not query ret==SUCCESS again: inifile_filter might fail but
* however next operation must be done.
*/
if (value) {
if (pos_grp_start == pos_grp_next && key->group && strlen(key->group)) {
php_stream_printf(dba->fp TSRMLS_CC, "[%s]\n", key->group);
}
php_stream_printf(dba->fp TSRMLS_CC, "%s=%s\n", key->name, value->value ? value->value : "");
}
}
/* 8 */
/* important: do not query ret==SUCCESS again: inifile_filter might fail but
* however next operation must be done.
*/
if (fp_tmp && php_stream_tell(fp_tmp)) {
php_stream_seek(fp_tmp, 0, SEEK_SET);
php_stream_seek(dba->fp, 0, SEEK_END);
if (!php_stream_copy_to_stream(fp_tmp, dba->fp, PHP_STREAM_COPY_ALL)) {
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Could not copy from temporary stream - ini file truncated");
ret = FAILURE;
}
}
}
if (ini_tmp) {
php_stream_close(ini_tmp->fp);
inifile_free(ini_tmp, 0);
}
if (fp_tmp) {
php_stream_close(fp_tmp);
}
php_stream_flush(dba->fp);
php_stream_seek(dba->fp, 0, SEEK_SET);
return ret;
}
/* }}} */
/* {{{ inifile_delete
*/
int inifile_delete(inifile *dba, const key_type *key TSRMLS_DC)
{
return inifile_delete_replace_append(dba, key, NULL, 0 TSRMLS_CC);
}
/* }}} */
/* {{{ inifile_relace
*/
int inifile_replace(inifile *dba, const key_type *key, const val_type *value TSRMLS_DC)
{
return inifile_delete_replace_append(dba, key, value, 0 TSRMLS_CC);
}
/* }}} */
/* {{{ inifile_append
*/
int inifile_append(inifile *dba, const key_type *key, const val_type *value TSRMLS_DC)
{
return inifile_delete_replace_append(dba, key, value, 1 TSRMLS_CC);
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: sw=4 ts=4 fdm=marker
* vim<600: sw=4 ts=4
*/

View file

@ -0,0 +1,67 @@
/*
+----------------------------------------------------------------------+
| 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. |
+----------------------------------------------------------------------+
| Author: Marcus Boerger <helly@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef PHP_LIB_INIFILE_H
#define PHP_LIB_INIFILE_H
typedef struct {
char *group;
char *name;
} key_type;
typedef struct {
char *value;
} val_type;
typedef struct {
key_type key;
val_type val;
size_t pos;
} line_type;
typedef struct {
char *lockfn;
int lockfd;
php_stream *fp;
int fd;
int readonly;
line_type curr;
line_type next;
} inifile;
val_type inifile_fetch(inifile *dba, const key_type *key, int skip TSRMLS_DC);
int inifile_firstkey(inifile *dba TSRMLS_DC);
int inifile_nextkey(inifile *dba TSRMLS_DC);
int inifile_delete(inifile *dba, const key_type *key TSRMLS_DC);
int inifile_replace(inifile *dba, const key_type *key, const val_type *val TSRMLS_DC);
int inifile_append(inifile *dba, const key_type *key, const val_type *val TSRMLS_DC);
char *inifile_version();
key_type inifile_key_split(const char *group_name);
char * inifile_key_string(const key_type *key);
void inifile_key_free(key_type *key);
void inifile_val_free(val_type *val);
void inifile_line_free(line_type *ln);
inifile * inifile_alloc(php_stream *fp, int readonly, int persistent TSRMLS_DC);
void inifile_free(inifile *dba, int persistent);
#endif

12
ext/dba/php_inifile.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef PHP_INIFILE_H
#define PHP_INIFILE_H
#if DBA_INIFILE
#include "php_dba.h"
DBA_FUNCS(inifile);
#endif
#endif

View file

@ -0,0 +1,29 @@
--TEST--
DBA INIFILE handler test
--SKIPIF--
<?php
require_once('skipif.inc');
if (!in_array('inifile', dba_handlers())) die('skip INIFILE handler not available');
?>
--FILE--
<?php
require_once('test.inc');
$handler = 'inifile';
require_once('dba_handler.inc');
?>
--EXPECT--
database handler: inifile
3NYNYY
Content String 2
Content 2 replaced
Read during write: not allowed
Content 2 replaced 2nd time
The 6th value
array(3) {
["key number 6"]=>
string(13) "The 6th value"
["key2"]=>
string(27) "Content 2 replaced 2nd time"
["key5"]=>
string(23) "The last content string"
}