1999-04-08 05:05:13 +08:00
|
|
|
%{
|
|
|
|
/*
|
|
|
|
+----------------------------------------------------------------------+
|
1999-07-16 21:13:16 +08:00
|
|
|
| PHP version 4.0 |
|
1999-04-08 05:05:13 +08:00
|
|
|
+----------------------------------------------------------------------+
|
1999-07-16 21:13:16 +08:00
|
|
|
| Copyright (c) 1997, 1998, 1999 The PHP Group |
|
1999-04-08 05:05:13 +08:00
|
|
|
+----------------------------------------------------------------------+
|
1999-07-16 21:13:16 +08:00
|
|
|
| This source file is subject to version 2.0 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_0.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. |
|
1999-04-08 05:05:13 +08:00
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
| Authors: Zeev Suraski <zeev@zend.com> |
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* $Id$ */
|
|
|
|
|
|
|
|
#define DEBUG_CFG_PARSER 1
|
|
|
|
#include "php.h"
|
1999-04-10 20:17:20 +08:00
|
|
|
#include "php_globals.h"
|
1999-04-11 00:25:23 +08:00
|
|
|
#include "php_ini.h"
|
1999-04-22 08:25:57 +08:00
|
|
|
#include "ext/standard/dl.h"
|
1999-04-17 08:37:12 +08:00
|
|
|
#include "ext/standard/file.h"
|
|
|
|
#include "ext/standard/php3_browscap.h"
|
1999-04-08 05:05:13 +08:00
|
|
|
#include "zend_extensions.h"
|
|
|
|
|
1999-04-21 12:02:11 +08:00
|
|
|
#undef YYPARSE_PARAM
|
|
|
|
#undef YYLEX_PARAM
|
|
|
|
|
1999-04-08 05:05:13 +08:00
|
|
|
#if WIN32
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
|
|
#include <windows.h>
|
|
|
|
#include <winbase.h>
|
|
|
|
#include "win32/wfile.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#undef YYSTYPE
|
|
|
|
#define YYSTYPE pval
|
|
|
|
|
|
|
|
#define PARSING_MODE_CFG 0
|
|
|
|
#define PARSING_MODE_BROWSCAP 1
|
|
|
|
|
|
|
|
static HashTable configuration_hash;
|
|
|
|
#ifndef THREAD_SAFE
|
|
|
|
extern HashTable browser_hash;
|
1999-04-26 22:00:49 +08:00
|
|
|
PHPAPI extern char *php3_ini_path;
|
1999-04-08 05:05:13 +08:00
|
|
|
#endif
|
1999-08-03 03:17:14 +08:00
|
|
|
static HashTable *active_zend_hash_table;
|
1999-04-08 05:05:13 +08:00
|
|
|
static pval *current_section;
|
|
|
|
static char *currently_parsed_filename;
|
|
|
|
|
|
|
|
static int parsing_mode;
|
|
|
|
|
|
|
|
pval yylval;
|
|
|
|
|
|
|
|
extern int cfglex(pval *cfglval);
|
|
|
|
extern FILE *cfgin;
|
|
|
|
extern int cfglineno;
|
|
|
|
extern void init_cfg_scanner(void);
|
|
|
|
|
|
|
|
pval *cfg_get_entry(char *name, uint name_length)
|
|
|
|
{
|
|
|
|
pval *tmp;
|
|
|
|
|
1999-08-03 03:17:14 +08:00
|
|
|
if (zend_hash_find(&configuration_hash, name, name_length, (void **) &tmp)==SUCCESS) {
|
1999-04-08 05:05:13 +08:00
|
|
|
return tmp;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
PHPAPI int cfg_get_long(char *varname,long *result)
|
|
|
|
{
|
|
|
|
pval *tmp,var;
|
|
|
|
|
1999-08-03 03:17:14 +08:00
|
|
|
if (zend_hash_find(&configuration_hash,varname,strlen(varname)+1,(void **) &tmp)==FAILURE) {
|
1999-04-08 05:05:13 +08:00
|
|
|
*result=(long)NULL;
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
var = *tmp;
|
|
|
|
pval_copy_constructor(&var);
|
|
|
|
convert_to_long(&var);
|
|
|
|
*result = var.value.lval;
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
PHPAPI int cfg_get_double(char *varname,double *result)
|
|
|
|
{
|
|
|
|
pval *tmp,var;
|
|
|
|
|
1999-08-03 03:17:14 +08:00
|
|
|
if (zend_hash_find(&configuration_hash,varname,strlen(varname)+1,(void **) &tmp)==FAILURE) {
|
1999-04-08 05:05:13 +08:00
|
|
|
*result=(double)0;
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
var = *tmp;
|
|
|
|
pval_copy_constructor(&var);
|
|
|
|
convert_to_double(&var);
|
|
|
|
*result = var.value.dval;
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
PHPAPI int cfg_get_string(char *varname, char **result)
|
|
|
|
{
|
|
|
|
pval *tmp;
|
|
|
|
|
1999-08-03 03:17:14 +08:00
|
|
|
if (zend_hash_find(&configuration_hash,varname,strlen(varname)+1,(void **) &tmp)==FAILURE) {
|
1999-04-08 05:05:13 +08:00
|
|
|
*result=NULL;
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
*result = tmp->value.str.val;
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void yyerror(char *str)
|
|
|
|
{
|
|
|
|
fprintf(stderr,"PHP: Error parsing %s on line %d\n",currently_parsed_filename,cfglineno);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-07-10 01:36:12 +08:00
|
|
|
static int pvalue_config_destructor(pval *pvalue)
|
1999-04-08 05:05:13 +08:00
|
|
|
{
|
|
|
|
if (pvalue->type == IS_STRING && pvalue->value.str.val != empty_string) {
|
|
|
|
free(pvalue->value.str.val);
|
|
|
|
}
|
1999-07-10 01:36:12 +08:00
|
|
|
return 1;
|
1999-04-08 05:05:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-07-10 01:36:12 +08:00
|
|
|
static int pvalue_browscap_destructor(pval *pvalue)
|
1999-04-08 05:05:13 +08:00
|
|
|
{
|
|
|
|
if (pvalue->type == IS_OBJECT || pvalue->type == IS_ARRAY) {
|
1999-08-03 03:17:14 +08:00
|
|
|
zend_hash_destroy(pvalue->value.ht);
|
1999-04-08 05:05:13 +08:00
|
|
|
free(pvalue->value.ht);
|
|
|
|
}
|
1999-07-10 01:36:12 +08:00
|
|
|
return 1;
|
1999-04-08 05:05:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int php3_init_config(void)
|
|
|
|
{
|
1999-04-21 12:02:11 +08:00
|
|
|
PLS_FETCH();
|
1999-04-08 05:05:13 +08:00
|
|
|
|
1999-08-03 03:17:14 +08:00
|
|
|
if (zend_hash_init(&configuration_hash, 0, NULL, (int (*)(void *))pvalue_config_destructor, 1)==FAILURE) {
|
1999-04-08 05:05:13 +08:00
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if USE_CONFIG_FILE
|
|
|
|
{
|
|
|
|
char *env_location,*default_location,*php_ini_path;
|
1999-04-10 20:17:20 +08:00
|
|
|
int safe_mode_state = PG(safe_mode);
|
1999-04-22 01:28:54 +08:00
|
|
|
char *open_basedir = PG(open_basedir);
|
1999-04-08 05:05:13 +08:00
|
|
|
char *opened_path;
|
|
|
|
int free_default_location=0;
|
|
|
|
|
|
|
|
env_location = getenv("PHPRC");
|
|
|
|
if (!env_location) {
|
|
|
|
env_location="";
|
|
|
|
}
|
|
|
|
#if WIN32|WINNT
|
|
|
|
{
|
1999-04-24 08:12:00 +08:00
|
|
|
if (php3_ini_path) {
|
|
|
|
default_location = php3_ini_path;
|
1999-04-08 05:05:13 +08:00
|
|
|
} else {
|
|
|
|
default_location = (char *) malloc(512);
|
|
|
|
|
|
|
|
if (!GetWindowsDirectory(default_location,255)) {
|
|
|
|
default_location[0]=0;
|
|
|
|
}
|
|
|
|
free_default_location=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
1999-04-24 08:12:00 +08:00
|
|
|
if (!php3_ini_path) {
|
1999-04-08 05:05:13 +08:00
|
|
|
default_location = CONFIGURATION_FILE_PATH;
|
|
|
|
} else {
|
1999-04-24 08:12:00 +08:00
|
|
|
default_location = php3_ini_path;
|
1999-04-08 05:05:13 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* build a path */
|
|
|
|
php_ini_path = (char *) malloc(sizeof(".")+strlen(env_location)+strlen(default_location)+2+1);
|
|
|
|
|
1999-04-24 08:12:00 +08:00
|
|
|
if (!php3_ini_path) {
|
1999-04-08 05:05:13 +08:00
|
|
|
#if WIN32|WINNT
|
|
|
|
sprintf(php_ini_path,".;%s;%s",env_location,default_location);
|
|
|
|
#else
|
|
|
|
sprintf(php_ini_path,".:%s:%s",env_location,default_location);
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
/* if path was set via -c flag, only look there */
|
|
|
|
strcpy(php_ini_path,default_location);
|
|
|
|
}
|
1999-04-10 20:17:20 +08:00
|
|
|
PG(safe_mode) = 0;
|
1999-04-22 01:28:54 +08:00
|
|
|
PG(open_basedir) = NULL;
|
1999-06-19 21:18:48 +08:00
|
|
|
cfgin = php3_fopen_with_path("php.ini","r",php_ini_path,&opened_path);
|
1999-04-08 05:05:13 +08:00
|
|
|
free(php_ini_path);
|
|
|
|
if (free_default_location) {
|
|
|
|
free(default_location);
|
|
|
|
}
|
1999-04-10 20:17:20 +08:00
|
|
|
PG(safe_mode) = safe_mode_state;
|
1999-04-22 01:28:54 +08:00
|
|
|
PG(open_basedir) = open_basedir;
|
1999-04-08 05:05:13 +08:00
|
|
|
|
|
|
|
if (!cfgin) {
|
|
|
|
# if WIN32|WINNT
|
|
|
|
return FAILURE;
|
|
|
|
# else
|
|
|
|
return SUCCESS; /* having no configuration file is ok */
|
|
|
|
# endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opened_path) {
|
|
|
|
pval tmp;
|
|
|
|
|
|
|
|
tmp.value.str.val = opened_path;
|
|
|
|
tmp.value.str.len = strlen(opened_path);
|
|
|
|
tmp.type = IS_STRING;
|
1999-08-03 03:17:14 +08:00
|
|
|
zend_hash_update(&configuration_hash,"cfg_file_path",sizeof("cfg_file_path"),(void *) &tmp,sizeof(pval),NULL);
|
1999-04-08 05:05:13 +08:00
|
|
|
#if 0
|
1999-08-03 03:17:14 +08:00
|
|
|
php_printf("INI file opened at '%s'\n",opened_path);
|
1999-04-08 05:05:13 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
init_cfg_scanner();
|
1999-08-03 03:17:14 +08:00
|
|
|
active_zend_hash_table = &configuration_hash;
|
1999-04-08 05:05:13 +08:00
|
|
|
parsing_mode = PARSING_MODE_CFG;
|
1999-06-19 21:18:48 +08:00
|
|
|
currently_parsed_filename = "php.ini";
|
1999-04-08 05:05:13 +08:00
|
|
|
yyparse();
|
|
|
|
fclose(cfgin);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-07-27 04:09:08 +08:00
|
|
|
PHP_MINIT_FUNCTION(browscap)
|
1999-04-08 05:05:13 +08:00
|
|
|
{
|
1999-04-11 00:25:23 +08:00
|
|
|
char *browscap = INI_STR("browscap");
|
1999-04-08 05:05:13 +08:00
|
|
|
|
1999-04-11 00:25:23 +08:00
|
|
|
if (browscap) {
|
1999-08-03 03:17:14 +08:00
|
|
|
if (zend_hash_init(&browser_hash, 0, NULL, (int (*)(void *))pvalue_browscap_destructor, 1)==FAILURE) {
|
1999-04-08 05:05:13 +08:00
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
1999-04-11 00:25:23 +08:00
|
|
|
cfgin = fopen(browscap, "r");
|
1999-04-08 05:05:13 +08:00
|
|
|
if (!cfgin) {
|
1999-08-03 03:17:14 +08:00
|
|
|
php_error(E_WARNING,"Cannot open '%s' for reading", browscap);
|
1999-04-08 05:05:13 +08:00
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
init_cfg_scanner();
|
1999-08-03 03:17:14 +08:00
|
|
|
active_zend_hash_table = &browser_hash;
|
1999-04-08 05:05:13 +08:00
|
|
|
parsing_mode = PARSING_MODE_BROWSCAP;
|
1999-04-11 00:25:23 +08:00
|
|
|
currently_parsed_filename = browscap;
|
1999-04-08 05:05:13 +08:00
|
|
|
yyparse();
|
|
|
|
fclose(cfgin);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int php3_shutdown_config(void)
|
|
|
|
{
|
1999-08-03 03:17:14 +08:00
|
|
|
zend_hash_destroy(&configuration_hash);
|
1999-04-08 05:05:13 +08:00
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-07-27 04:09:08 +08:00
|
|
|
PHP_MSHUTDOWN_FUNCTION(browscap)
|
1999-04-08 05:05:13 +08:00
|
|
|
{
|
1999-04-11 00:25:23 +08:00
|
|
|
if (INI_STR("browscap")) {
|
1999-08-03 03:17:14 +08:00
|
|
|
zend_hash_destroy(&browser_hash);
|
1999-04-08 05:05:13 +08:00
|
|
|
}
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void convert_browscap_pattern(pval *pattern)
|
|
|
|
{
|
|
|
|
register int i,j;
|
|
|
|
char *t;
|
|
|
|
|
|
|
|
for (i=0; i<pattern->value.str.len; i++) {
|
|
|
|
if (pattern->value.str.val[i]=='*' || pattern->value.str.val[i]=='?') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i==pattern->value.str.len) { /* no wildcards */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
t = (char *) malloc(pattern->value.str.len*2);
|
|
|
|
|
|
|
|
for (i=0,j=0; i<pattern->value.str.len; i++,j++) {
|
|
|
|
switch (pattern->value.str.val[i]) {
|
|
|
|
case '?':
|
|
|
|
t[j] = '.';
|
|
|
|
break;
|
|
|
|
case '*':
|
|
|
|
t[j++] = '.';
|
|
|
|
t[j] = '*';
|
|
|
|
break;
|
|
|
|
case '.':
|
|
|
|
t[j++] = '\\';
|
|
|
|
t[j] = '.';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
t[j] = pattern->value.str.val[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
t[j]=0;
|
|
|
|
free(pattern->value.str.val);
|
|
|
|
pattern->value.str.val = t;
|
|
|
|
pattern->value.str.len = j;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
%}
|
|
|
|
|
|
|
|
%pure_parser
|
|
|
|
%token TC_STRING
|
|
|
|
%token TC_ENCAPSULATED_STRING
|
|
|
|
%token SECTION
|
|
|
|
%token CFG_TRUE
|
|
|
|
%token CFG_FALSE
|
|
|
|
%token EXTENSION
|
|
|
|
%token T_ZEND_EXTENSION
|
1999-04-27 03:02:59 +08:00
|
|
|
%token T_ZEND_EXTENSION_TS
|
1999-04-27 18:00:54 +08:00
|
|
|
%token T_ZEND_EXTENSION_DEBUG
|
|
|
|
%token T_ZEND_EXTENSION_DEBUG_TS
|
1999-04-08 05:05:13 +08:00
|
|
|
|
|
|
|
%%
|
|
|
|
|
|
|
|
statement_list:
|
|
|
|
statement_list statement
|
|
|
|
| /* empty */
|
|
|
|
;
|
|
|
|
|
|
|
|
statement:
|
|
|
|
string '=' string_or_value {
|
|
|
|
#if 0
|
|
|
|
printf("'%s' = '%s'\n",$1.value.str.val,$3.value.str.val);
|
|
|
|
#endif
|
|
|
|
$3.type = IS_STRING;
|
|
|
|
if (parsing_mode==PARSING_MODE_CFG) {
|
1999-08-03 03:17:14 +08:00
|
|
|
zend_hash_update(active_zend_hash_table, $1.value.str.val, $1.value.str.len+1, &$3, sizeof(pval), NULL);
|
1999-04-08 05:05:13 +08:00
|
|
|
} else if (parsing_mode==PARSING_MODE_BROWSCAP) {
|
|
|
|
php3_str_tolower($1.value.str.val,$1.value.str.len);
|
1999-08-03 03:17:14 +08:00
|
|
|
zend_hash_update(current_section->value.ht, $1.value.str.val, $1.value.str.len+1, &$3, sizeof(pval), NULL);
|
1999-04-08 05:05:13 +08:00
|
|
|
}
|
|
|
|
free($1.value.str.val);
|
|
|
|
}
|
|
|
|
| string { free($1.value.str.val); }
|
|
|
|
| EXTENSION '=' string {
|
|
|
|
pval dummy;
|
|
|
|
#if 0
|
|
|
|
printf("Loading '%s'\n",$3.value.str.val);
|
|
|
|
#endif
|
|
|
|
|
1999-10-14 03:55:25 +08:00
|
|
|
php_dl(&$3,MODULE_PERSISTENT,&dummy);
|
1999-04-08 05:05:13 +08:00
|
|
|
}
|
1999-04-27 03:02:59 +08:00
|
|
|
| T_ZEND_EXTENSION '=' string {
|
1999-05-20 20:06:45 +08:00
|
|
|
#if !defined(ZTS) && !ZEND_DEBUG
|
1999-04-27 03:02:59 +08:00
|
|
|
zend_load_extension($3.value.str.val);
|
|
|
|
#endif
|
|
|
|
free($3.value.str.val);
|
|
|
|
}
|
|
|
|
| T_ZEND_EXTENSION_TS '=' string {
|
1999-05-20 20:06:45 +08:00
|
|
|
#if defined(ZTS) && !ZEND_DEBUG
|
1999-04-27 18:00:54 +08:00
|
|
|
zend_load_extension($3.value.str.val);
|
|
|
|
#endif
|
|
|
|
free($3.value.str.val);
|
|
|
|
}
|
|
|
|
| T_ZEND_EXTENSION_DEBUG '=' string {
|
1999-05-20 20:06:45 +08:00
|
|
|
#if !defined(ZTS) && ZEND_DEBUG
|
1999-04-27 18:00:54 +08:00
|
|
|
zend_load_extension($3.value.str.val);
|
|
|
|
#endif
|
|
|
|
free($3.value.str.val);
|
|
|
|
}
|
|
|
|
| T_ZEND_EXTENSION_DEBUG_TS '=' string {
|
1999-05-20 20:06:45 +08:00
|
|
|
#if defined(ZTS) && ZEND_DEBUG
|
1999-04-27 03:02:59 +08:00
|
|
|
zend_load_extension($3.value.str.val);
|
|
|
|
#endif
|
|
|
|
free($3.value.str.val);
|
|
|
|
}
|
1999-04-08 05:05:13 +08:00
|
|
|
| SECTION {
|
|
|
|
if (parsing_mode==PARSING_MODE_BROWSCAP) {
|
|
|
|
pval tmp;
|
|
|
|
|
|
|
|
/*printf("'%s' (%d)\n",$1.value.str.val,$1.value.str.len+1);*/
|
|
|
|
tmp.value.ht = (HashTable *) malloc(sizeof(HashTable));
|
1999-08-03 03:17:14 +08:00
|
|
|
zend_hash_init(tmp.value.ht, 0, NULL, (int (*)(void *))pvalue_config_destructor, 1);
|
1999-04-08 05:05:13 +08:00
|
|
|
tmp.type = IS_OBJECT;
|
1999-08-03 03:17:14 +08:00
|
|
|
zend_hash_update(active_zend_hash_table, $1.value.str.val, $1.value.str.len+1, (void *) &tmp, sizeof(pval), (void **) ¤t_section);
|
1999-04-08 05:05:13 +08:00
|
|
|
tmp.value.str.val = php3_strndup($1.value.str.val,$1.value.str.len);
|
|
|
|
tmp.value.str.len = $1.value.str.len;
|
|
|
|
tmp.type = IS_STRING;
|
|
|
|
convert_browscap_pattern(&tmp);
|
1999-08-03 03:17:14 +08:00
|
|
|
zend_hash_update(current_section->value.ht,"browser_name_pattern",sizeof("browser_name_pattern"),(void *) &tmp, sizeof(pval), NULL);
|
1999-04-08 05:05:13 +08:00
|
|
|
}
|
|
|
|
free($1.value.str.val);
|
|
|
|
}
|
|
|
|
| '\n'
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
string:
|
|
|
|
TC_STRING { $$ = $1; }
|
|
|
|
| TC_ENCAPSULATED_STRING { $$ = $1; }
|
|
|
|
;
|
|
|
|
|
|
|
|
string_or_value:
|
|
|
|
string { $$ = $1; }
|
|
|
|
| CFG_TRUE { $$ = $1; }
|
|
|
|
| CFG_FALSE { $$ = $1; }
|
|
|
|
| '\n' { $$.value.str.val = strdup(""); $$.value.str.len=0; $$.type = IS_STRING; }
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Local variables:
|
|
|
|
* tab-width: 4
|
|
|
|
* c-basic-offset: 4
|
|
|
|
* End:
|
|
|
|
*/
|