*
* (c) 2001--2006 Robert Spalek <robert@ucw.cz>
* (c) 2003--2012 Martin Mares <mj@ucw.cz>
+ * (c) 2014 Pavel Charvat <pchar@ucw.cz>
*
* This software may be freely distributed and used according to the terms
* of the GNU Lesser General Public License.
#include <ucw/conf-internal.h>
#include <ucw/clists.h>
#include <ucw/fastbuf.h>
+#include <ucw/xtypes.h>
static void
spaces(struct fastbuf *fb, uint nr)
else
bprintf(fb, "??? ");
break;
+ case CT_XTYPE:
+ bprintf(fb, "'%s' ", u->xtype->format(ptr, XTYPE_FMT_DEFAULT, cf_get_pool()));
+ break;
}
}
{
ptr += (uintptr_t) item->ptr;
enum cf_type type = item->type;
- uint size = cf_type_size(item->type, item->u.utype);
+ uint size = cf_type_size(item->type, &item->u);
int i;
spaces(fb, level);
bprintf(fb, "%s: C%s #", item->name, class_names[item->cls]);
else
bprintf(fb, "%d ", item->number);
if (item->cls == CC_STATIC || item->cls == CC_DYNAMIC || item->cls == CC_BITMAP) {
- bprintf(fb, "T%s ", cf_type_names[type]);
if (item->type == CT_USER)
bprintf(fb, "U%s S%d ", item->u.utype->name, size);
+ else if (item->type == CT_XTYPE)
+ bprintf(fb, "X%s S%d ", item->u.xtype->name, size);
+ else
+ bprintf(fb, "T%s ", cf_type_names[type]);
}
if (item->cls == CC_STATIC) {
for (i=0; i<item->number; i++)
*
* (c) 2001--2006 Robert Spalek <robert@ucw.cz>
* (c) 2003--2012 Martin Mares <mj@ucw.cz>
+ * (c) 2014 Pavel Charvat <pchar@ucw.cz>
*
* This software may be freely distributed and used according to the terms
* of the GNU Lesser General Public License.
extern char *cf_op_names[];
extern char *cf_type_names[];
-uint cf_type_size(enum cf_type type, struct cf_user_type *utype);
+uint cf_type_size(enum cf_type type, const union cf_union *u);
char *cf_interpret_line(struct cf_context *cc, char *name, enum cf_operation op, int number, char **pars);
void cf_init_stack(struct cf_context *cc);
int cf_done_stack(struct cf_context *cc);
*
* (c) 2001--2006 Robert Spalek <robert@ucw.cz>
* (c) 2003--2014 Martin Mares <mj@ucw.cz>
+ * (c) 2014 Pavel Charvat <pchar@ucw.cz>
*
* This software may be freely distributed and used according to the terms
* of the GNU Lesser General Public License.
#include <ucw/clists.h>
#include <ucw/gary.h>
#include <ucw/mempool.h>
+#include <ucw/xtypes.h>
#include <string.h>
#include <stdio.h>
};
inline uint
-cf_type_size(enum cf_type type, struct cf_user_type *utype)
+cf_type_size(enum cf_type type, const union cf_union *u)
{
- if (type < CT_USER)
- return parsers[type].size;
- else
- return utype->size;
+ switch (type)
+ {
+ case CT_USER:
+ return u->utype->size;
+ case CT_XTYPE:
+ return u->xtype->size;
+ default:
+ ASSERT(type < ARRAY_SIZE(parsers) - 1);
+ return parsers[type].size;
+ }
}
static char *
for (uint i=0; i<number; i++)
{
char *msg;
- uint size = cf_type_size(type, u->utype);
+ uint size = cf_type_size(type, u);
if (type < CT_LOOKUP)
msg = ((cf_basic_parser*) parsers[type].parser) (pars[i], ptr + i * size);
else if (type == CT_LOOKUP)
msg = cf_parse_lookup(pars[i], ptr + i * size, u->lookup);
else if (type == CT_USER)
msg = u->utype->parser(pars[i], ptr + i * size);
+ else if (type == CT_XTYPE)
+ msg = (char *)u->xtype->parse(pars[i], ptr + i * size, cf_get_pool());
else
ASSERT(0);
if (msg)
interpret_set_dynamic(struct cf_item *item, int number, char **pars, void **ptr)
{
enum cf_type type = item->type;
- uint size = cf_type_size(type, item->u.utype);
+ uint size = cf_type_size(type, &item->u);
cf_journal_block(ptr, sizeof(void*));
// boundary checks done by the caller
*ptr = gary_init(size, number, mp_get_allocator(cf_get_pool()));
{
enum cf_type type = item->type;
void *old_p = *ptr;
- uint size = cf_type_size(item->type, item->u.utype);
+ uint size = cf_type_size(item->type, &item->u);
ASSERT(size >= sizeof(uint));
int old_nr = old_p ? GARY_SIZE(old_p) : 0;
int taken = MIN(number, ABS(item->number)-old_nr);
return "Missing value";
taken = MIN(number, item->number);
*processed = taken;
- uint size = cf_type_size(item->type, item->u.utype);
+ uint size = cf_type_size(item->type, &item->u);
cf_journal_block(ptr, taken * size);
return cf_parse_ary(taken, pars, ptr, item->type, &item->u);
case CC_DYNAMIC:
if (item->type == CT_STRING)
return strcmp(* (char**) i1, * (char**) i2);
else // all numeric types
- return memcmp(i1, i2, cf_type_size(item->type, item->u.utype));
+ return memcmp(i1, i2, cf_type_size(item->type, &item->u));
}
static void *
*
* (c) 2006 Robert Spalek <robert@ucw.cz>
* (c) 2012--2014 Martin Mares <mj@ucw.cz>
+ * (c) 2014 Pavel Charvat <pchar@ucw.cz>
*/
#include <ucw/lib.h>
#include <ucw/clists.h>
#include <ucw/fastbuf.h>
#include <ucw/gary.h>
+#include <ucw/xtypes.h>
#include <stdlib.h>
#include <stdio.h>
static u16 numbers[10] = { 2, 100, 1, 5 };
static u32 bitmap1 = 0xff;
static u32 bitmap2 = 3;
+static intmax_t intmax;
static char *
parse_u16(char *string, u16 *ptr)
CF_IP("ip", &ip),
CF_LOOKUP_DYN("look", &look, alphabet, 1000),
CF_USER_ARY("numbers", numbers, &u16_type, 10),
+ CF_XTYPE("intmax", &intmax, xt_intmax),
CF_BITMAP_INT("bitmap1", &bitmap1),
CF_BITMAP_LOOKUP("bitmap2", &bitmap2, ((const char* const[]) {
"one", "two", "three", "four", "five", "six", "seven", "eight",
bitmap1:remove 3 3
bitmap2:all
bitmap2:remove eleven twelve one
+ intmax 1000000000
};;;;;;
unknown.ignored :-)
*
* (c) 2001--2006 Robert Spalek <robert@ucw.cz>
* (c) 2003--2014 Martin Mares <mj@ucw.cz>
+ * (c) 2014 Pavel Charvat <pchar@ucw.cz>
*
* This software may be freely distributed and used according to the terms
* of the GNU Lesser General Public License.
CT_IP, // IP address
CT_STRING, // string type
CT_LOOKUP, // in a string table
- CT_USER // user-defined type
+ CT_USER, // user-defined type (obsolete)
+ CT_XTYPE // extended type
};
struct fastbuf;
struct cf_section *sec; // declaration of a section or a list
cf_parser *par; // parser function
const char * const *lookup; // NULL-terminated sequence of allowed strings for lookups
- struct cf_user_type *utype; // specification of the user-defined type
+ struct cf_user_type *utype; // specification of the user-defined type (obsolete)
+ const struct xtype *xtype; // specification of the extended type
} u;
enum cf_class cls:16; // attribute class
enum cf_type type:16; // type of a static or dynamic attribute
* See <<custom_parser,creating custom parsers>> section.
**/
#define CF_USER_DYN(n,p,t,c) { .cls = CC_DYNAMIC, .type = CT_USER, .name = n, .number = c, .ptr = p, .u.utype = t }
+/**
+ * An extended type.
+ * See <<xtypes:,extended types>> if you want to know more.
+ **/
+#define CF_XTYPE(n,p,t) { .cls = CC_STATIC, .type = CT_XTYPE, .name = n, .number = 1, .ptr = p, .u.xtype = &t }
+/**
+ * Static array of extended types (all of the same type).
+ * See <<xtypes:,extended types>>.
+ **/
+#define CF_XTYPE_ARY(n,p,t,c) { .cls = CC_STATIC, .type = CT_XTYPE, .name = n, .number = c, .ptr = p, .u.xtype = &t }
+/**
+ * Dynamic array of extended types.
+ * See <<xtypes:,extended types>>.
+ **/
+#define CF_XTYPE_DYN(n,p,t,c) { .cls = CC_DYNAMIC, .type = CT_XTYPE, .name = n, .number = c, .ptr = p, .u.xtype = &t }
/**
* Any number of dynamic array elements
~~~~~~~~~~~~~~~~~~~~~~~
If you need to parse some data type the configuration system can't
-handle, you can write your own parser. But before you start, you
-should know a few things.
+handle, you can write your own <<xtypes:,extended type>>
+and use <<def_CF_XTYPE,`CF_XTYPE`>> macro to declare a new option.
+
+There is also an obsolete way to write a custom parser.
+Before you start, you should know a few things.
The parser needs to support <<journal,journalling>>. To accomplish that,
you have to use the <<alloc,configuration mempool>> for memory allocation.
- Long name: an arbitrary string. Set to NULL if the option has no long form.
- Variable, where the value of the option shall be stored, together with
its <<conf:enum_cf_type,data type>>. The type is either one of the conventional
- types (`int`, `uint`, etc.), or a user-defined type providing its own parser
- function via <<conf:struct_cf_user_type,`cf_user_type`>>.
+ types (`int`, `uint`, etc.), an extended type providing its own parser
+ function via <<xtypes:struct_xtype,`xtype`>>, or an obsolete user-type
+ defined by <<conf:struct_cf_user_type,`cf_user_type`>>.
- <<flags,Flags>> further specifying behavior of the option (whether it is mandatory,
whether it carries a value, whether it can be set repeatedly, etc.).
- Help text, from which the help displayed to the user is constructed.
*
* (c) 2013 Jan Moskyto Matejka <mq@ucw.cz>
* (c) 2014 Martin Mares <mj@ucw.cz>
+ * (c) 2014 Pavel Charvat <pchar@ucw.cz>
*
* This software may be freely distributed and used according to the terms
* of the GNU Lesser General Public License.
opt_failure("Cannot parse the value of %s: %s", THIS_OPT, e);
break;
}
+ case CT_XTYPE:
+ {
+ const char * e = item->u.xtype->parse(value, ptr, cf_get_pool());
+ if (e)
+ opt_failure("Cannot parse the value of %s: %s", THIS_OPT, e);
+ break;
+ }
default:
ASSERT(0);
}
#include <ucw/lib.h>
#include <ucw/conf.h>
+#include <ucw/xtypes.h>
#include <stdlib.h>
#include <stdio.h>
void (* call)(const struct opt_item * opt, const char * value, void * data); // function to call for OPT_CL_CALL
void (* hook)(const struct opt_item * opt, uint event, const char * value, void * data); // function to call for OPT_CL_HOOK
struct cf_user_type * utype; // specification of the user-defined type for CT_USER
+ const struct xtype * xtype; // specification of the extended type for CT_XTYPE
} u;
u16 flags; // as defined below (for hooks, event mask is stored instead)
byte cls; // enum opt_class
/** Multi-valued option of user-defined type. @target should be a growing array of the right kind of items. **/
#define OPT_USER_MULTIPLE(shortopt, longopt, target, ttype, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .u.utype = &ttype, .flags = fl, .help = desc, .cls = OPT_CL_MULTIPLE, .type = CT_USER }
+/**
+ * An option with user-defined syntax. @xtype is a <<xtypes:struct_xtype,`xtype`>>
+ * describing the syntax, @target is a variable of the corresponding type. If the @OPT_REQUIRED_VALUE
+ * flag is not set, the parser must be able to parse a NULL value.
+ **/
+#define OPT_XTYPE(shortopt, longopt, target, ttype, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .u.xtype = &ttype, .flags = fl, .help = desc, .cls = OPT_CL_STATIC, .type = CT_XTYPE }
+
+/** Multi-valued option of extended type. @target should be a growing array of the right kind of items. **/
+#define OPT_XTYPE_MULTIPLE(shortopt, longopt, target, ttype, fl, desc) { .letter = shortopt, .name = longopt, .ptr = &target, .u.xtype = &ttype, .flags = fl, .help = desc, .cls = OPT_CL_MULTIPLE, .type = CT_XTYPE }
+
/** A sub-section. **/
#define OPT_SECTION(sec) { .cls = OPT_CL_SECTION, .u.section = &sec }