/*
* ProFTPD - FTP server daemon
* Copyright (c) 2004 The ProFTPD Project team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* As a special exemption, The ProFTPD Project team and other respective
* copyright holders give permission to link this program with OpenSSL, and
* distribute the resulting executable, without including the source code for
* OpenSSL in the source distribution.
*/
/* Variables API implementation
* $Id: var.c,v 1.3 2004/12/04 07:43:46 castaglia Exp $
*/
#include "conf.h"
struct var {
int v_type;
const char *v_desc;
void *v_val;
void *v_data;
size_t v_datasz;
};
static pool *var_pool = NULL;
static pr_table_t *var_tab = NULL;
typedef const char *(*var_vstr_cb)(void *, size_t);
/* Public API
*/
int pr_var_delete(const char *name) {
if (!name) {
errno = EINVAL;
return -1;
}
if (!var_tab) {
errno = EPERM;
return -1;
}
return pr_table_remove(var_tab, name, NULL) ? 0 : -1;
}
int pr_var_exists(const char *name) {
if (!name) {
errno = EINVAL;
return -1;
}
if (!var_tab) {
errno = EPERM;
return -1;
}
return pr_table_exists(var_tab, name) > 0 ? TRUE : FALSE;
}
const char *pr_var_get(const char *name) {
struct var *v;
if (!name) {
errno = EINVAL;
return NULL;
}
if (!var_tab) {
errno = EPERM;
return NULL;
}
v = pr_table_get(var_tab, name, NULL);
if (!v)
return NULL;
switch (v->v_type) {
case PR_VAR_TYPE_STR:
return (const char *) v->v_val;
break;
case PR_VAR_TYPE_FUNC:
return ((var_vstr_cb) v->v_val)(v->v_data, v->v_datasz);
break;
default:
/* Pass through to the error case. */
;
}
errno = EINVAL;
return NULL;
}
const char *pr_var_next(const char **desc) {
const char *name;
struct var *v;
if (!var_tab) {
errno = EPERM;
return NULL;
}
name = pr_table_next(var_tab);
if (!name)
return NULL;
v = pr_table_get(var_tab, name, NULL);
if (desc)
*desc = v->v_desc;
return name;
}
int pr_var_remove(const char *name) {
if (!name) {
errno = EINVAL;
return -1;
}
if (!var_tab) {
errno = EPERM;
return -1;
}
return pr_table_remove(var_tab, name, NULL) ? 0 : -1;
}
void pr_var_rewind(void) {
if (var_tab)
pr_table_rewind(var_tab);
}
int pr_var_set(pool *p, const char *name, const char *desc, int type,
void *val, void *data, size_t datasz) {
struct var *v;
if (!p || !name || !val) {
errno = EINVAL;
return -1;
}
/* Specifying data, but no length for that data, is an error. */
if (data && datasz == 0) {
errno = EINVAL;
return -1;
}
/* Variable names MUST start with '%{', and end in '}'. */
if (strncmp(name, "%{", 2) != 0 ||
name[strlen(name)-1] != '}') {
errno = EINVAL;
return -1;
}
/* Remove any previously registered value for this name. For names whose
* values change rapidly (e.g. session.xfer.total_bytes), a callback
* function should be used, rather than always setting the same name as an
* update; using a callback avoids the memory consumption that setting does
* (set always allocates a new struct var *).
*/
(void) pr_var_delete(name);
/* Note: if var_pool was used for allocating the struct var *, rather
* than the given pool, then deleting an entry would not necessarily
* lead to such memory consumption (assuming it would even be a problem).
* However, if this was the case, then a churn counter would be needed,
* and var_pool would need to be churned occasionally to limit memory
* growth.
*/
switch (type) {
case PR_VAR_TYPE_STR:
v = pcalloc(p, sizeof(struct var));
if (desc)
v->v_desc = (const char *) pstrdup(p, desc);
v->v_type = PR_VAR_TYPE_STR;
v->v_val = pstrdup(p, (char *) val);
v->v_datasz = strlen((char *) val);
break;
case PR_VAR_TYPE_FUNC:
v = pcalloc(p, sizeof(struct var));
if (desc)
v->v_desc = (const char *) pstrdup(p, desc);
v->v_type = PR_VAR_TYPE_FUNC;
v->v_val = (var_vstr_cb) val;
if (data) {
v->v_data = data;
v->v_datasz = datasz;
}
break;
default:
errno = EINVAL;
return -1;
}
return pr_table_add(var_tab, name, v, sizeof(struct var));
}
int var_init(void) {
if (!var_pool) {
var_pool = make_sub_pool(permanent_pool);
pr_pool_tag(var_pool, "Variables Pool");
}
if (!var_tab)
var_tab = pr_table_alloc(var_pool, 0);
return 0;
}
int var_free(void) {
if (var_pool) {
if (var_tab) {
pr_table_empty(var_tab);
pr_table_free(var_tab);
}
destroy_pool(var_pool);
var_pool = NULL;
var_tab = NULL;
}
return 0;
}
Last Updated: Thu Feb 23 11:07:23 2006
HTML generated by tj's src2html script