aboutsummaryrefslogtreecommitdiffstats
path: root/src/afs-config.c
blob: 70a6d4751387cce81e2095872fcc1da4bc67c122 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
@media (prefers-color-scheme: light) {
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
}
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"

SRC_URI =+ "${SOURCEFORGE_MIRROR}/freetype/ft2demos-${PV}.tar.bz2;name=ft2demos \
           file://0001-Makefile-dont-build-gfx-demos.patch;patchdir=../ft2demos-${PV} \
          "
SRC_URI[ft2demos.md5sum] = "c6c209b37f10621d6ff100620b8292b4"
SRC_URI[ft2demos.sha256sum] = "f8f4bc2a2e76e0dbe61838e452c5a7daf1d4bd9dfa44691940bf308f776d32b6"

PACKAGES =+ "${PN}-demos"

do_compile_append () {
	oe_runmake -C ${WORKDIR}/ft2demos-${PV} TOP_DIR=${WORKDIR}/${BPN}-${PV}
}

do_install_append () {
	install -d -m 0755 ${D}/${bindir}
	for x in ftbench ftdump ftlint ftvalid ttdebug; do 
		install -m 0755 ${WORKDIR}/ft2demos-${PV}/bin/$x ${D}/${bindir}
	done
}

FILES_${PN}-demos = "\
   ${bindir}/ftbench \
   ${bindir}/ftdump \
   ${bindir}/ftlint \
   ${bindir}/ftvalid \
   ${bindir}/ttdebug \
"
66' href='#n366'>366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
/*
 * Copyright (C) 2015-2018 "IoT.bzh"
 * Author José Bollo <jose.bollo@iot.bzh>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define _GNU_SOURCE

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <limits.h>
#include <unistd.h>

#include "verbose.h"
#include "afs-config.h"

#if !defined(AFB_VERSION)
#  error "you should define AFB_VERSION"
#endif

#if !defined(AFS_SUPERVISOR_TOKEN)
#  define AFS_SUPERVISOR_TOKEN    ""
#endif
#if !defined(AFS_SUPERVISOR_PORT)
#  define AFS_SUPERVISOR_PORT     1619
#endif
#define _STRINGIFY_(x) #x
#define STRINGIFY(x) _STRINGIFY_(x)

// default
#define DEFLT_CNTX_TIMEOUT  32000000	// default Client Connection
					// Timeout: few more than one year
#define DEFLT_API_TIMEOUT   20		// default Plugin API Timeout [0=NoLimit
					// for Debug Only]
#define DEFLT_CACHE_TIMEOUT 100000	// default Static File Chache
					// [Client Side Cache
					// 100000~=1day]
#define CTX_NBCLIENTS       10		// allow a default of 10 authenticated
					// clients


// Define command line option
#define SET_ROOT_DIR       6
#define SET_ROOT_BASE      7
#define SET_ROOT_API       8

#define SET_CACHE_TIMEOUT  10
#define SET_SESSION_DIR    11

#define SET_APITIMEOUT     14
#define SET_CNTXTIMEOUT    15

#define SET_SESSIONMAX     23

#define SET_ROOT_HTTP      26

#define DISPLAY_HELP       'h'
#define SET_NAME           'n'
#define SET_TCP_PORT       'p'
#define SET_QUIET          'q'
#define WS_SERVICE         's'
#define SET_AUTH_TOKEN     't'
#define SET_UPLOAD_DIR     'u'
#define DISPLAY_VERSION    'V'
#define SET_VERBOSE        'v'
#define SET_WORK_DIR       'w'

const char shortopts[] =
	"hn:p:qrs:t:u:Vvw:"
;

// Command line structure hold cli --command + help text
typedef struct {
	int val;		// command number within application
	int has_arg;		// command number within application
	char *name;		// command as used in --xxxx cli
	char *help;		// help text
} AFB_options;

// Supported option
static AFB_options cliOptions[] = {
/* *INDENT-OFF* */
	{SET_VERBOSE,       0, "verbose",     "Verbose Mode, repeat to increase verbosity"},
	{SET_QUIET,         0, "quiet",       "Quiet Mode, repeat to decrease verbosity"},

	{SET_NAME,          1, "name",        "Set the visible name"},

	{SET_TCP_PORT,      1, "port",        "HTTP listening TCP port  [default " STRINGIFY(AFS_SUPERVISOR_PORT) "]"},
	{SET_ROOT_HTTP,     1, "roothttp",    "HTTP Root Directory [default no root http (files not served but apis still available)]"},
	{SET_ROOT_BASE,     1, "rootbase",    "Angular Base Root URL [default /opa]"},
	{SET_ROOT_API,      1, "rootapi",     "HTML Root API URL [default /api]"},

	{SET_APITIMEOUT,    1, "apitimeout",  "Binding API timeout in seconds [default 10]"},
	{SET_CNTXTIMEOUT,   1, "cntxtimeout", "Client Session Context Timeout [default 900]"},
	{SET_CACHE_TIMEOUT, 1, "cache-eol",   "Client cache end of live [default 3600]"},

	{SET_WORK_DIR,      1, "workdir",     "Set the working directory [default: $PWD or current working directory]"},
	{SET_UPLOAD_DIR,    1, "uploaddir",   "Directory for uploading files [default: workdir]"},
	{SET_ROOT_DIR,      1, "rootdir",     "Root Directory of the application [default: workdir]"},
	{SET_SESSION_DIR,   1, "sessiondir",  "OBSOLETE (was: Sessions file path)"},

	{SET_AUTH_TOKEN,    1, "token",       "Initial Secret [default=" AFS_SUPERVISOR_TOKEN ", use --token="" to allow any token]"},

	{WS_SERVICE,        1, "ws-server",   "Provide supervisor as websocket"},
	{DISPLAY_VERSION,   0, "version",     "Display version and copyright"},
	{DISPLAY_HELP,      0, "help",        "Display this help"},

	{SET_SESSIONMAX,    1, "session-max", "Max count of session simultaneously [default 10]"},

	{0, 0, NULL, NULL}
/* *INDENT-ON* */
};


struct enumdesc
{
	const char *name;
	int value;
};

/*----------------------------------------------------------
 | printversion
 |   print version and copyright
 +--------------------------------------------------------- */
static void printVersion(FILE * file)
{
	static const char version[] =
		"\n"
		"  afs-supervisor [Application Framework Supervisor] version="AFB_VERSION"\n"
		"\n"
		"  Copyright (C) 2015-2018 \"IoT.bzh\"\n"
		"  afs-supervisor comes with ABSOLUTELY NO WARRANTY.\n"
		"  Licence Apache 2\n"
		"\n";

	fprintf(file, "%s", version);
}

/*----------------------------------------------------------
 | printHelp
 |   print information from long option array
 +--------------------------------------------------------- */

static void printHelp(FILE * file, const char *name)
{
	int ind;
	char command[50];

	fprintf(file, "%s:\nallowed options\n", name);
	for (ind = 0; cliOptions[ind].name != NULL; ind++) {
		strcpy(command, cliOptions[ind].name);
		if (cliOptions[ind].has_arg)
			strcat(command, "=xxxx");
		fprintf(file, "  --%-15s %s\n", command, cliOptions[ind].help);
	}
	fprintf(file,
		"Example:\n  %s  --verbose --port=1234 --token='azerty'\n",
		name);
}


/*---------------------------------------------------------
 |   helpers for argument scanning
 +--------------------------------------------------------- */

static const char *name_of_option(int optc)
{
	AFB_options *o = cliOptions;
	while (o->name && o->val != optc)
		o++;
	return o->name ? : "<unknown-option-name>";
}

static const char *current_argument(int optc)
{
	if (optarg == 0) {
		ERROR("option [--%s] needs a value i.e. --%s=xxx",
		      name_of_option(optc), name_of_option(optc));
		exit(1);
	}
	return optarg;
}

static char *argvalstr(int optc)
{
	char *result = strdup(current_argument(optc));
	if (result == NULL) {
		ERROR("can't alloc memory");
		exit(1);
	}
	return result;
}

static int argvalint(int optc, int mini, int maxi, int base)
{
	const char *beg, *end;
	long int val;
	beg = current_argument(optc);
	val = strtol(beg, (char**)&end, base);
	if (*end || end == beg) {
		ERROR("option [--%s] requires a valid integer (found %s)",
			name_of_option(optc), beg);
		exit(1);
	}
	if (val < (long int)mini || val > (long int)maxi) {
		ERROR("option [--%s] value out of bounds (not %d<=%ld<=%d)",
			name_of_option(optc), mini, val, maxi);
		exit(1);
	}
	return (int)val;
}

static int argvalintdec(int optc, int mini, int maxi)
{
	return argvalint(optc, mini, maxi, 10);
}

static void noarg(int optc)
{
	if (optarg != 0) {
		ERROR("option [--%s] need no value (found %s)", name_of_option(optc), optarg);
		exit(1);
	}
}

/*---------------------------------------------------------
 |   Parse option and launch action
 +--------------------------------------------------------- */

static void parse_arguments(int argc, char **argv, struct afs_config *config)
{
	char *programName = argv[0];
	int optc, ind;
	int nbcmd;
	struct option *gnuOptions;

	// ------------------ Process Command Line -----------------------

	// build GNU getopt info from cliOptions
	nbcmd = sizeof(cliOptions) / sizeof(AFB_options);
	gnuOptions = malloc(sizeof(*gnuOptions) * (unsigned)nbcmd);
	for (ind = 0; ind < nbcmd; ind++) {
		gnuOptions[ind].name = cliOptions[ind].name;
		gnuOptions[ind].has_arg = cliOptions[ind].has_arg;
		gnuOptions[ind].flag = 0;
		gnuOptions[ind].val = cliOptions[ind].val;
	}

	// get all options from command line
	while ((optc = getopt_long(argc, argv, shortopts, gnuOptions, NULL)) != EOF) {
		switch (optc) {
		case SET_VERBOSE:
			verbose_inc();
			break;

		case SET_QUIET:
			verbose_dec();
			break;

		case SET_TCP_PORT:
			config->httpdPort = argvalintdec(optc, 1024, 32767);
			break;

		case SET_APITIMEOUT:
			config->apiTimeout = argvalintdec(optc, 0, INT_MAX);
			break;

		case SET_CNTXTIMEOUT:
			config->cntxTimeout = argvalintdec(optc, 0, INT_MAX);
			break;

		case SET_ROOT_DIR:
			config->rootdir = argvalstr(optc);
			INFO("Forcing Rootdir=%s", config->rootdir);
			break;

		case SET_ROOT_HTTP:
			config->roothttp = argvalstr(optc);
			INFO("Forcing Root HTTP=%s", config->roothttp);
			break;

		case SET_ROOT_BASE:
			config->rootbase = argvalstr(optc);
			INFO("Forcing Rootbase=%s", config->rootbase);
			break;

		case SET_ROOT_API:
			config->rootapi = argvalstr(optc);
			INFO("Forcing Rootapi=%s", config->rootapi);
			break;

		case SET_AUTH_TOKEN:
			config->token = argvalstr(optc);
			break;

		case SET_UPLOAD_DIR:
			config->uploaddir = argvalstr(optc);
			break;

		case SET_WORK_DIR:
			config->workdir = argvalstr(optc);
			break;

		case SET_CACHE_TIMEOUT:
			config->cacheTimeout = argvalintdec(optc, 0, INT_MAX);
			break;

		case SET_SESSIONMAX:
			config->nbSessionMax = argvalintdec(optc, 1, INT_MAX);
			break;

		case SET_NAME:
			config->name = argvalstr(optc);
			break;

		case WS_SERVICE:
			config->ws_server = argvalstr(optc);
			break;

		case DISPLAY_VERSION:
			noarg(optc);
			printVersion(stdout);
			exit(0);

		case DISPLAY_HELP:
			printHelp(stdout, programName);
			exit(0);

		default:
			exit(1);
		}
	}
	free(gnuOptions);
}

static void fulfill_config(struct afs_config *config)
{
	// default HTTP port
	if (config->httpdPort == 0)
		config->httpdPort = AFS_SUPERVISOR_PORT;

	// default binding API timeout
	if (config->apiTimeout == 0)
		config->apiTimeout = DEFLT_API_TIMEOUT;

	// cache timeout default one hour
	if (config->cacheTimeout == 0)
		config->cacheTimeout = DEFLT_CACHE_TIMEOUT;

	// cache timeout default one hour
	if (config->cntxTimeout == 0)
		config->cntxTimeout = DEFLT_CNTX_TIMEOUT;

	// max count of sessions
	if (config->nbSessionMax == 0)
		config->nbSessionMax = CTX_NBCLIENTS;

	/* set directories */
	if (config->workdir == NULL)
		config->workdir = ".";

	if (config->rootdir == NULL)
		config->rootdir = ".";

	if (config->uploaddir == NULL)
		config->uploaddir = ".";

	// if no Angular/HTML5 rootbase let's try '/' as default
	if (config->rootbase == NULL)
		config->rootbase = "/opa";

	if (config->rootapi == NULL)
		config->rootapi = "/api";

	if (config->token == NULL)
		config->token = AFS_SUPERVISOR_TOKEN;
}

void afs_config_dump(struct afs_config *config)
{
#define NN(x)   (x)?:""
#define P(...)  fprintf(stderr, __VA_ARGS__)
#define PF(x)   P("-- %15s: ", #x)
#define PE      P("\n")
#define S(x)	PF(x);P("%s",NN(config->x));PE;
#define D(x)	PF(x);P("%d",config->x);PE;

	P("---BEGIN-OF-CONFIG---\n");
	S(rootdir)
	S(roothttp)
	S(rootbase)
	S(rootapi)
	S(workdir)
	S(uploaddir)
	S(token)
	S(name)
	S(ws_server)

	D(httpdPort)
	D(cacheTimeout)
	D(apiTimeout)
	D(cntxTimeout)
	D(nbSessionMax)
	P("---END-OF-CONFIG---\n");

#undef V
#undef E
#undef L
#undef B
#undef D
#undef S
#undef PE
#undef PF
#undef P
#undef NN
}

static void parse_environment(struct afs_config *config)
{
}

struct afs_config *afs_config_parse_arguments(int argc, char **argv)
{
	struct afs_config *result;

	result = calloc(1, sizeof *result);

	parse_environment(result);
	parse_arguments(argc, argv, result);
	fulfill_config(result);
	if (verbose_wants(Log_Level_Info))
		afs_config_dump(result);
	return result;
}