Introduction
The libt3config library provides functions for reading and writing simple structured configuration files.
libt3config is part of the Tilde Terminal Toolkit (T3).
Information is available about the syntax of the configuration files, and schema syntax. Finally there is the API documentation.
Example
The example below shows a small program which loads a configuration file and prints it to screen. It can be passed a schema which will be used for validating the configuration, and can optionally enable the include mechanism.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <locale.h>
#include <unistd.h>
#include <stdarg.h>
#include <t3config/config.h>
#define STRING_DFLT(x, dflt) ((x) != NULL ? (x) : (dflt))
static void fatal(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
exit(EXIT_FAILURE);
}
static void cleanup(void) {
}
int main(int argc, char *argv[]) {
FILE *file = stdin;
const char *path[2] = { NULL, NULL };
const char *name = "<stdin>";
int c;
setlocale(LC_ALL, "");
atexit(cleanup);
while ((c = getopt(argc, argv, "s:hi::")) >= 0) {
switch (c) {
case 's': {
FILE *schema_file;
if (schema != NULL)
fatal("more than one schema option\n");
if ((schema_file = fopen(optarg, "r")) == NULL)
fatal("error opening schema '%s': %m\n", optarg);
fatal(
"%s:%d: error loading schema '%s': %s: %s\n", STRING_DFLT(error.
file_name, optarg),
fclose(schema_file);
break;
}
case 'h':
printf("Usage: test [-s <schema>] [-i[<include dir>]] [<input>]\n");
exit(EXIT_SUCCESS);
case 'i':
path[0] = optarg == 0 ? "." : optarg;
break;
default:
break;
}
}
if (argc - optind == 1) {
if ((file = fopen(argv[optind], "r")) == NULL)
fatal("could not open input '%s': %m\n");
name = argv[optind];
} else if (argc != optind) {
fatal("more than one input specified\n");
}
fatal(
"%s:%d: error loading input: %s: %s\n", STRING_DFLT(error.
file_name, name), error.
line_number,
fclose(file);
fatal(
"%s:%d: error validating input: %s: %s\n", STRING_DFLT(error.
file_name, name), error.
line_number,
if (foo != NULL) {
int bar_int = -1;
}
}
return EXIT_SUCCESS;
}
Guidelines
The API of libt3config is designed such that it is possible to write code that only checks for errors in a limited number of places. That is, functions that fetch or store values in the config, all accept NULL
as the pointer to the (sub-)config to add to, and successful return values are 0 to allow logical OR-ing of the values to check for simple errors. For functions that fetch values, reasonable defaults are provided.So, the following code is guaranteed not to crash:
int has_errors = 0;
has_errors |= config == NULL;