/*
  +----------------------------------------------------------------------+
  | Hidef                                                                |
  +----------------------------------------------------------------------+
  | Copyright (c) 2007 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.               |
  +----------------------------------------------------------------------+
  | Authors: Gopal Vijayaraghavan <gopalv@php.net>                       |
  +----------------------------------------------------------------------+
*/

/* $Id: hidef.c,v 1.4 2007/02/25 21:57:24 pajoye Exp $ */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_ini.h"
#include "php_scandir.h"
#include "zend_globals.h"
#include "ext/standard/info.h"
#include "SAPI.h"

#include "hidef.h"

/* {{{ hidef globals 
 *
 * true globals, no need for thread safety here 
 */
static HashTable hidef_constants_table;
/* }}} */

/* {{{ hidef_functions[]
 *
 * Every user visible function must have an entry in hidef_functions[].
 */
zend_function_entry hidef_functions[] = {
	{NULL, NULL, NULL}	/* Must be the last line in hidef_functions[] */
};
/* }}} */

/* {{{ hidef_module_entry
 */
zend_module_entry hidef_module_entry = {
	STANDARD_MODULE_HEADER,
	"hidef",
	hidef_functions,
	PHP_MINIT(hidef),
	PHP_MSHUTDOWN(hidef),
	NULL,
	NULL,
	PHP_MINFO(hidef),
#if ZEND_MODULE_API_NO >= 20010901
	"0.1.0",
#endif
	STANDARD_MODULE_PROPERTIES
};
/* }}} */

#ifdef COMPILE_DL_HIDEF
ZEND_GET_MODULE(hidef)
#endif

/* {{{ struct hidef_ini_parser_ctxt */
typedef struct _hidef_ini_parser_ctxt 
{
	int module_number;
	const char * filename;
} hidef_ini_parser_ctxt;
/* }}} */

/* {{{ hidef_zval_free */
static void hidef_zval_free(void *p) 
{
	zval * zv = (zval*) p;
	if(zv->type == IS_STRING)
	{
		free(Z_STRVAL_P(zv));
	}
}
/* }}} */

/* {{{ hidef_ini_parser_cb */
static void hidef_ini_parser_cb(zval *arg1, zval *arg2, int callback_type, void *arg) 
{
	char *p;
	char *key = Z_STRVAL_P(arg1);
	int type = IS_STRING;
	zval value;
	zend_constant c;
	hidef_ini_parser_ctxt * ctxt = (hidef_ini_parser_ctxt*)arg;

	TSRMLS_FETCH();
	
	c.flags = CONST_CS | CONST_PERSISTENT;
#ifdef CONST_CT_SUBST
	c.flags |= CONST_CT_SUBST;
#endif
	c.module_number = ctxt->module_number;

	switch (callback_type) 
	{
		case ZEND_INI_PARSER_ENTRY: 
		{
			if(!arg2)
			{
				return;
			}

			if(strncmp(key, "int ", strlen("int ")) == 0)
			{
				type = IS_LONG;
			} 
			else if(strncmp(key, "str ", strlen("str ")) == 0)
			{
				type = IS_STRING;
			} 
			else if(strncmp(key, "float ", strlen("float ")) == 0)
			{
				type = IS_DOUBLE;
			} 
			else if(strncmp(key, "bool ", strlen("bool ")) == 0)
			{
				type = IS_BOOL;
			} 
			else
			{
				/* TODO: error */
				return;
			}
			
			p = strrchr(key, ' ');

			if((p == NULL) || strlen(p) == 1)
			{
				/* TODO: error handling */
				return;	
			}

			p += 1; /* skip ' '*/

			value = *arg2;
			zval_copy_ctor(&value); 

			switch(type) 
			{
				case IS_LONG:
				{
					convert_to_long(&value);
				}
				break;
				case IS_DOUBLE:
				{
					convert_to_double(&value);
				}
				break;
				case IS_BOOL:
				{
					convert_to_boolean(&value);
				}
				break;
				case IS_STRING:
				{
					convert_to_string(&value);
				}
				break;
			}
			
			/* TODO: check conversion results */
			
			c.value = value;
			if(type == IS_STRING) 
			{
				/* TODO: this leaks memory */
				c.value.value.str.val = zend_strndup(Z_STRVAL_P(&c.value), Z_STRLEN_P(&c.value));
			}
			c.name = zend_strndup(p, strlen(p));
			c.name_len = strlen(p)+1;
			if(zend_register_constant(&c TSRMLS_CC) == FAILURE) 
			{
				fprintf(stderr, "Constant '%s' redefined in %s line %d\n", p, 
						ctxt->filename,
						zend_ini_scanner_get_lineno(TSRMLS_C) - 1);
			}

			zend_hash_add(&hidef_constants_table, c.name, c.name_len, &c.value, sizeof(c.value), NULL);
			
			zval_dtor(&value);
		}
		break;
	
#ifdef ZEND_INI_PARSER_POP_ENTRY
		case ZEND_INI_PARSER_POP_ENTRY: 
		{
			/* do nothing here, I suppose */
		}
		break;
#endif

		case ZEND_INI_PARSER_SECTION:
		{
			/* ignore sectioning */
		}
		break;

		default:
			assert(0);
	}
}
/* }}} */

/* {{{ PHP_MINIT_FUNCTION
 */
PHP_MINIT_FUNCTION(hidef)
{
	char ini_path[MAXPATHLEN]={0,};
	char ini_file[MAXPATHLEN]={0,};
	int ndir, i;
	char *p = NULL;
	struct stat sb;
	zend_file_handle fh = {0,};
	struct dirent **namelist = NULL;
	hidef_ini_parser_ctxt ctxt = {0,};

	ctxt.module_number = module_number;
	
	zend_hash_init(&hidef_constants_table, 32,  NULL, hidef_zval_free, 1);

	if (!sapi_module.php_ini_ignore && strlen(PHP_CONFIG_FILE_SCAN_DIR))
	{
		snprintf(ini_path, MAXPATHLEN, "%s%c%s", 
				PHP_CONFIG_FILE_SCAN_DIR, DEFAULT_SLASH, "hidef");
			
		if ((ndir = php_scandir(ini_path, &namelist, 0, php_alphasort)) > 0)
		{
			for (i = 0; i < ndir; i++) 
			{
				/* check for a .ini extension */
				if (!(p = strrchr(namelist[i]->d_name, '.')) 
					|| (p && strcmp(p, ".ini"))) 
				{
					free(namelist[i]);
					continue;
				}
				snprintf(ini_file, MAXPATHLEN, "%s%c%s", 
						ini_path, DEFAULT_SLASH, namelist[i]->d_name);
				if (VCWD_STAT(ini_file, &sb) == 0 && S_ISREG(sb.st_mode)) 
				{
					if ((fh.handle.fp = VCWD_FOPEN(ini_file, "r"))) 
					{
						fh.filename = ini_file;
						ctxt.filename = ini_file;
						fh.type = ZEND_HANDLE_FP;
						zend_parse_ini_file(&fh, 1, hidef_ini_parser_cb, &ctxt);
					}
				}
				free(namelist[i]);
			}
			free(namelist);
		}
	}
	return SUCCESS;
}
/* }}} */

/* {{{ PHP_MSHUTDOWN_FUNCTION
 *  */
PHP_MSHUTDOWN_FUNCTION(hidef)
{
	zend_hash_destroy(&hidef_constants_table);
	return SUCCESS;
}
/* }}} */

/* {{{ PHP_MINFO_FUNCTION
 */
PHP_MINFO_FUNCTION(hidef)
{
	char ini_path[MAXPATHLEN]={0,};
	HashPosition pos;
	zend_constant *val;
	int module_number = zend_module->module_number;
	
	php_info_print_table_start();

	if (!sapi_module.php_ini_ignore && strlen(PHP_CONFIG_FILE_SCAN_DIR))
	{
		snprintf(ini_path, MAXPATHLEN, "%s%c%s", 
				PHP_CONFIG_FILE_SCAN_DIR, DEFAULT_SLASH, "hidef");
	}
	else
	{
		php_info_print_table_row(2, "hidef support", "disabled");
		php_info_print_table_end();
		return;
	}
	
	
	php_info_print_table_row(2, "hidef support", "enabled");
	php_info_print_table_row(2, "ini search path", ini_path);
#ifdef CONST_CT_SUBST
	php_info_print_table_row(2, "substitution mode", "compile time");
#else
	php_info_print_table_row(2, "substitution mode", "runtime");
#endif

	php_info_print_table_end();
	php_info_print_table_start();
	php_info_print_table_header(2, "Constant", "Value");

	
	zend_hash_internal_pointer_reset_ex(EG(zend_constants), &pos);
	while (zend_hash_get_current_data_ex(EG(zend_constants), (void **) &val, &pos) != FAILURE) 
	{
		if (val->module_number == module_number) 
		{
			zval const_val = {0,};
			const_val = val->value;
			zval_copy_ctor(&const_val);
			convert_to_string(&const_val);
			
			php_info_print_table_row(2, val->name, Z_STRVAL_P(&const_val));
			zval_dtor(&const_val);
		}
		zend_hash_move_forward_ex(EG(zend_constants), &pos);
	}

	php_info_print_table_end();
}
/* }}} */

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: noet sw=4 ts=4 fdm=marker
 * vim<600: noet sw=4 ts=4
 */


syntax highlighted by Code2HTML, v. 0.9.1