⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 inifile.c

📁 PHP v6.0 For Linux 运行环境:Win9X/ WinME/ WinNT/ Win2K/ WinXP
💻 C
字号:
/*   +----------------------------------------------------------------------+   | PHP Version 5                                                        |   +----------------------------------------------------------------------+   | Copyright (c) 1997-2006 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: inifile.c,v 1.18 2006/07/06 23:13:41 iliaa Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include "php.h"#include "php_globals.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: 1.18 $";}/* }}} */ /* {{{ 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;	if (!readonly) {		if (!php_stream_truncate_supported(fp)) {			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't truncate this stream");			return NULL;		}	} 	dba = pemalloc(sizeof(inifile), persistent);	memset(dba, 0, sizeof(inifile));	dba->fp = fp;	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 (*val && 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_ZSTR, 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 {					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 (!strcasecmp(k1->group, k2->group)) {		if (!strcasecmp(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 && dba->next.key.group && dba->next.key.name && !inifile_key_cmp(&dba->next.key, key TSRMLS_CC)) {		/* we got position already from last fetch */		php_stream_seek(dba->fp, dba->next.pos, SEEK_SET);	} else {		/* specific instance or not same key -> restart search */		/* the slow way: restart and seacrch */		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 updating key read into next */				inifile_line_free(&dba->next);				dba->next = ln;				dba->next.pos = php_stream_tell(dba->fp);				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);	dba->next.pos = php_stream_tell(dba->fp);	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=php_stream_truncate_set_size(dba->fp, 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) {				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) {			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 != (size_t)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_RECOVERABLE_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 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -