Add parser
This commit is contained in:
parent
e028c2aca5
commit
5b5e780680
@ -20,7 +20,7 @@
|
||||
Barwin*
|
||||
barwin_new(Window parent, int x, int y, int w, int h, Color fg, Color bg, bool entermask)
|
||||
{
|
||||
Barwin *b;
|
||||
Barwin *b = (Barwin*)xcalloc(1, sizeof(Barwin));
|
||||
XSetWindowAttributes at =
|
||||
{
|
||||
.override_redirect = True,
|
||||
@ -28,8 +28,6 @@ barwin_new(Window parent, int x, int y, int w, int h, Color fg, Color bg, bool e
|
||||
.event_mask = BARWIN_MASK
|
||||
};
|
||||
|
||||
b = (Barwin*)xcalloc(1, sizeof(Barwin));
|
||||
|
||||
if(entermask)
|
||||
at.event_mask |= BARWIN_ENTERMASK;
|
||||
|
||||
@ -76,9 +74,6 @@ barwin_remove(Barwin *b)
|
||||
void
|
||||
barwin_resize(Barwin *b, int w, int h)
|
||||
{
|
||||
if(b->geo.w == w && b->geo.h == h)
|
||||
return;
|
||||
|
||||
/* Frame */
|
||||
XFreePixmap(W->dpy, b->dr);
|
||||
|
||||
|
||||
627
wmfs2/src/parse.c
Executable file
627
wmfs2/src/parse.c
Executable file
@ -0,0 +1,627 @@
|
||||
/*
|
||||
* Copyright (c) 2010 Philippe Pepiot <phil@philpep.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#ifndef _BSD_SOURCE
|
||||
#define _BSD_SOURCE
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "parse.h"
|
||||
#include "util.h"
|
||||
|
||||
extern char *__progname;
|
||||
|
||||
enum keyword_t { SEC_START, SEC_END, INCLUDE, WORD, EQUAL, LIST_START, LIST_END, NONE };
|
||||
|
||||
#ifdef DEBUG
|
||||
static struct {
|
||||
const char *name;
|
||||
enum keyword_t type;
|
||||
} kw_t_name[] = {
|
||||
{"SEC_START", SEC_START},
|
||||
{"SEC_END", SEC_END},
|
||||
{"INCLUDE", INCLUDE},
|
||||
{"WORD", WORD},
|
||||
{"EQUAL", EQUAL},
|
||||
{"LIST_START", LIST_START},
|
||||
{"LIST_END", LIST_END},
|
||||
{"NONE", NONE},
|
||||
};
|
||||
#endif
|
||||
|
||||
struct files {
|
||||
char *name;
|
||||
struct files *parent;
|
||||
};
|
||||
|
||||
struct keyword {
|
||||
enum keyword_t type;
|
||||
/* if WORD */
|
||||
int line;
|
||||
struct files *file;
|
||||
char *name;
|
||||
struct keyword *next;
|
||||
};
|
||||
|
||||
struct state {
|
||||
bool quote;
|
||||
bool comment;
|
||||
char quote_char;
|
||||
};
|
||||
|
||||
/* TO REMOVE (use a identifier for config and fallback XDG in api functions) */
|
||||
TAILQ_HEAD(, conf_sec) config;
|
||||
static struct keyword *keywords = NULL;
|
||||
|
||||
static struct keyword *
|
||||
push_keyword(struct keyword *tail, enum keyword_t type, char *buf, size_t *offset, struct files *file, int line)
|
||||
{
|
||||
struct keyword *kw;
|
||||
#ifdef DEBUG
|
||||
int i = 0;
|
||||
#endif
|
||||
|
||||
if (type == WORD && *offset == 0)
|
||||
return tail;
|
||||
|
||||
kw = xcalloc(1, sizeof(*kw));
|
||||
kw->type = type;
|
||||
kw->line = line;
|
||||
kw->file = file;
|
||||
kw->next = NULL;
|
||||
|
||||
if (*offset != 0) {
|
||||
buf[*offset] = '\0';
|
||||
if (!strcmp(buf, INCLUDE_CMD))
|
||||
kw->type = INCLUDE;
|
||||
else
|
||||
kw->name = strdup(buf);
|
||||
*offset = 0;
|
||||
}
|
||||
else
|
||||
kw->name = NULL;
|
||||
|
||||
if (tail)
|
||||
tail->next = kw;
|
||||
|
||||
#ifdef DEBUG
|
||||
for (i = 0; kw_t_name[i].type != NONE; i++) {
|
||||
if (kw_t_name[i].type == kw->type) {
|
||||
warnx("%s %s %s:%d\n", kw_t_name[i].name,
|
||||
(kw->name) ? kw->name : "",
|
||||
kw->file->name, kw->line);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return kw;
|
||||
}
|
||||
|
||||
static void
|
||||
syntax(struct keyword *kw, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
fprintf(stderr, "%s:", __progname);
|
||||
|
||||
if (kw && kw->file && kw->file->name)
|
||||
fprintf(stderr, "%s:%d", kw->file->name, kw->line);
|
||||
|
||||
if (kw && kw->name)
|
||||
fprintf(stderr, ", near '%s'", kw->name);
|
||||
fprintf(stderr, ": ");
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
|
||||
#define PUSH_KEYWORD(type) tail = push_keyword(tail, type, bufname, &j, file, line)
|
||||
static struct keyword *
|
||||
parse_keywords(const char *filename)
|
||||
{
|
||||
int fd;
|
||||
struct stat st;
|
||||
char *buf;
|
||||
|
||||
struct keyword *head = NULL;
|
||||
struct keyword *tail = NULL;
|
||||
struct files *file;
|
||||
enum keyword_t type; /* keyword type to push */
|
||||
struct state s = { False, False, '\0'};
|
||||
char *bufname;
|
||||
char path[PATH_MAX];
|
||||
size_t i, j;
|
||||
int line;
|
||||
bool error = False;
|
||||
|
||||
|
||||
if ((fd = open(filename, O_RDONLY)) == -1 || stat(filename, &st) == -1) {
|
||||
warn("%s", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (st.st_size == 0) {
|
||||
warnx("%s: empty file", filename);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!realpath(filename, path)) {
|
||||
warn("%s", filename);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = xmalloc(1, st.st_size+1);
|
||||
|
||||
if (read(fd, buf, st.st_size) == -1) {
|
||||
warn("%s", filename);
|
||||
free(buf);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf[st.st_size] = '\0';
|
||||
|
||||
file = xcalloc(1, sizeof(*file));
|
||||
bufname = xcalloc(BUFSIZ, sizeof(*bufname));
|
||||
file->name = strdup(path);
|
||||
file->parent = NULL;
|
||||
|
||||
for(i = 0, j = 0, line = 1; i < (size_t)st.st_size; i++) {
|
||||
|
||||
if (!head && tail)
|
||||
head = tail;
|
||||
|
||||
if (buf[i] == '\n' && s.comment == True) {
|
||||
line++;
|
||||
s.comment = False;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (buf[i] == '#' && s.quote == False) {
|
||||
s.comment = True;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (s.comment == True)
|
||||
continue;
|
||||
|
||||
if (s.quote == True && buf[i] == s.quote_char) {
|
||||
/* end of quotted string */
|
||||
PUSH_KEYWORD(WORD);
|
||||
s.quote = False;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (s.quote == False) {
|
||||
if ((buf[i] == '"' || buf[i] == '\'')) {
|
||||
PUSH_KEYWORD(WORD);
|
||||
/* begin quotted string */
|
||||
s.quote_char = buf[i];
|
||||
s.quote = True;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (buf[i] == '[') {
|
||||
PUSH_KEYWORD(WORD);
|
||||
if (buf[i+1] == '/') {
|
||||
i +=2;
|
||||
type = SEC_END;
|
||||
}
|
||||
else {
|
||||
i++;
|
||||
type = SEC_START;
|
||||
}
|
||||
|
||||
/* get section name */
|
||||
while (buf[i] != ']') {
|
||||
|
||||
if (i >= ((size_t)st.st_size-1) || j >= (BUFSIZ-1)) {
|
||||
bufname[j] = '\0';
|
||||
syntax(NULL, "word too long in %s:%d near '%s'",
|
||||
file->name, line, bufname);
|
||||
error = True;
|
||||
break;
|
||||
}
|
||||
|
||||
bufname[j++] = buf[i++];
|
||||
}
|
||||
PUSH_KEYWORD(type);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (buf[i] == '{') {
|
||||
PUSH_KEYWORD(WORD);
|
||||
PUSH_KEYWORD(LIST_START);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (buf[i] == '}') {
|
||||
PUSH_KEYWORD(WORD);
|
||||
PUSH_KEYWORD(LIST_END);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (buf[i] == ',') {
|
||||
PUSH_KEYWORD(WORD);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (buf[i] == '=') {
|
||||
PUSH_KEYWORD(WORD);
|
||||
PUSH_KEYWORD(EQUAL);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strchr("\t\n ", buf[i])) {
|
||||
PUSH_KEYWORD(WORD);
|
||||
|
||||
if (buf[i] == '\n')
|
||||
line++;
|
||||
|
||||
continue;
|
||||
}
|
||||
} /* s.quote == False */
|
||||
|
||||
if (j >= (BUFSIZ - 1)) {
|
||||
bufname[j] = '\0';
|
||||
syntax(NULL, "word too long in %s:%d near '%s'",
|
||||
file->name, line, bufname);
|
||||
error = True;
|
||||
break;
|
||||
}
|
||||
|
||||
bufname[j++] = buf[i];
|
||||
}
|
||||
|
||||
free(buf);
|
||||
free(bufname);
|
||||
close(fd);
|
||||
warnx("%s read", file->name);
|
||||
|
||||
return (error ? NULL: head);
|
||||
}
|
||||
|
||||
/*
|
||||
* return NULL on failure and head->next if
|
||||
* no config found (of file doesn't exist)
|
||||
* NOTE to devs: head->name is the file to include
|
||||
*/
|
||||
static struct keyword *
|
||||
include(struct keyword *head)
|
||||
{
|
||||
struct keyword *kw;
|
||||
struct keyword *tail;
|
||||
struct files *file;
|
||||
struct passwd *user;
|
||||
char *filename = NULL;
|
||||
char *base = NULL;
|
||||
|
||||
head = head->next;
|
||||
|
||||
if (!head || head->type != WORD) {
|
||||
syntax(head, "missing filename to include");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* replace ~ by user directory */
|
||||
if (head->name && head->name[0] == '~') {
|
||||
if ( (user = getpwuid(getuid())) && user->pw_dir)
|
||||
xasprintf(&filename, "%s%s", user->pw_dir, head->name+1);
|
||||
else if (getenv("HOME"))
|
||||
xasprintf(&filename, "%s%s", getenv("HOME"), head->name+1);
|
||||
else /* to warning ? */
|
||||
filename = head->name;
|
||||
}
|
||||
/* relative path from parent file */
|
||||
else if (head->name && head->name[0] != '/') {
|
||||
base = strdup(head->file->name);
|
||||
xasprintf(&filename, "%s/%s", dirname(base), head->name);
|
||||
free(base);
|
||||
}
|
||||
else
|
||||
filename = head->name;
|
||||
|
||||
if (!(kw = parse_keywords(filename))) {
|
||||
warnx("no config found in include file %s", head->name);
|
||||
|
||||
if (filename != head->name)
|
||||
free(filename);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kw->file->parent = head->file;
|
||||
|
||||
/* detect circular include */
|
||||
for (file = kw->file->parent; file != NULL; file = file->parent) {
|
||||
if (!strcmp(file->name, kw->file->name)) {
|
||||
syntax(kw, "circular include of %s", kw->file->name);
|
||||
|
||||
if (filename != head->name)
|
||||
free(filename);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (filename != head->name)
|
||||
free(filename);
|
||||
|
||||
head = head->next;
|
||||
|
||||
if (kw) {
|
||||
for (tail = kw; tail->next; tail = tail->next);
|
||||
tail->next = head;
|
||||
}
|
||||
|
||||
return kw;
|
||||
}
|
||||
|
||||
static void *
|
||||
free_opt(struct conf_opt *o)
|
||||
{
|
||||
free(o);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct conf_opt *
|
||||
get_option(struct keyword **head)
|
||||
{
|
||||
struct conf_opt *o;
|
||||
size_t j = 0;
|
||||
struct keyword *kw = *head;
|
||||
|
||||
o = xcalloc(1, sizeof(*o));
|
||||
o->name = kw->name;
|
||||
o->used = False;
|
||||
o->line = kw->line;
|
||||
o->filename = kw->file->name;
|
||||
|
||||
kw = kw->next;
|
||||
|
||||
if (kw->type != EQUAL) {
|
||||
syntax(kw, "missing '=' here");
|
||||
return free_opt(o);
|
||||
}
|
||||
|
||||
kw = kw->next;
|
||||
|
||||
if (!kw) {
|
||||
syntax(kw, "missing value");
|
||||
return free_opt(o);
|
||||
}
|
||||
|
||||
|
||||
switch (kw->type) {
|
||||
case INCLUDE:
|
||||
if (!(kw = include(kw)))
|
||||
return free_opt(o);
|
||||
break;
|
||||
case WORD:
|
||||
o->val[0] = kw->name;
|
||||
o->val[1] = NULL;
|
||||
kw = kw->next;
|
||||
break;
|
||||
case LIST_START:
|
||||
kw = kw->next;
|
||||
while (kw && kw->type != LIST_END) {
|
||||
switch (kw->type) {
|
||||
case WORD:
|
||||
if (j >= (PARSE_MAX_LIST - 1)) {
|
||||
syntax(kw, "too much values in list");
|
||||
return free_opt(o);
|
||||
}
|
||||
o->val[j++] = kw->name;
|
||||
kw = kw->next;
|
||||
break;
|
||||
case INCLUDE:
|
||||
if (!(kw = include(kw)))
|
||||
return free_opt(o);
|
||||
break;
|
||||
default:
|
||||
syntax(kw, "declaration into a list");
|
||||
return free_opt(o);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!kw) {
|
||||
syntax(kw, "list unclosed");
|
||||
return free_opt(o);
|
||||
}
|
||||
|
||||
kw = kw->next;
|
||||
break;
|
||||
default:
|
||||
syntax(kw, "missing value");
|
||||
return free_opt(o);
|
||||
break;
|
||||
}
|
||||
|
||||
*head = kw;
|
||||
return o;
|
||||
}
|
||||
|
||||
static void *
|
||||
free_sec(struct conf_sec *sec)
|
||||
{
|
||||
struct conf_opt *o;
|
||||
struct conf_sec *s;
|
||||
|
||||
if (sec) {
|
||||
while (!SLIST_EMPTY(&sec->optlist)) {
|
||||
o = SLIST_FIRST(&sec->optlist);
|
||||
SLIST_REMOVE_HEAD(&sec->optlist, entry);
|
||||
free_opt(o);
|
||||
}
|
||||
while (!TAILQ_EMPTY(&sec->sub)) {
|
||||
s = TAILQ_FIRST(&sec->sub);
|
||||
TAILQ_REMOVE(&sec->sub, s, entry);
|
||||
free_sec(s);
|
||||
}
|
||||
free(sec);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct conf_sec *
|
||||
get_section(struct keyword **head)
|
||||
{
|
||||
struct conf_sec *s;
|
||||
struct conf_opt *o;
|
||||
struct conf_sec *sub;
|
||||
struct keyword *kw = *head;
|
||||
|
||||
s = xcalloc(1, sizeof(*s));
|
||||
s->name = kw->name;
|
||||
TAILQ_INIT(&s->sub);
|
||||
SLIST_INIT(&s->optlist);
|
||||
|
||||
kw = kw->next;
|
||||
|
||||
while (kw && kw->type != SEC_END) {
|
||||
switch (kw->type) {
|
||||
case INCLUDE:
|
||||
if (!(kw = include(kw)))
|
||||
return free_sec(s);
|
||||
break;
|
||||
case SEC_START:
|
||||
if (!(sub = get_section(&kw)))
|
||||
return free_sec(s);
|
||||
TAILQ_INSERT_TAIL(&s->sub, sub, entry);
|
||||
s->nsub++;
|
||||
break;
|
||||
case WORD:
|
||||
if (!(o = get_option(&kw)))
|
||||
return free_sec(s);
|
||||
SLIST_INSERT_HEAD(&s->optlist, o, entry);
|
||||
s->nopt++;
|
||||
break;
|
||||
default:
|
||||
syntax(kw, "syntax error");
|
||||
return free_sec(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!kw || strcmp(kw->name, s->name)) {
|
||||
syntax(kw, "missing end section %s", s->name);
|
||||
return free_sec(s);
|
||||
}
|
||||
|
||||
kw = kw->next;
|
||||
*head = kw;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
free_conf(void)
|
||||
{
|
||||
struct conf_sec *s;
|
||||
struct keyword *kw, *nkw;
|
||||
struct files **f = NULL;
|
||||
int i, nf = 0;
|
||||
|
||||
while (!TAILQ_EMPTY(&config)) {
|
||||
s = TAILQ_FIRST(&config);
|
||||
TAILQ_REMOVE(&config, s, entry);
|
||||
free_sec(s);
|
||||
}
|
||||
|
||||
kw = keywords;
|
||||
|
||||
while (kw) {
|
||||
nkw = kw->next;
|
||||
|
||||
free(kw->name);
|
||||
|
||||
for (i = 0; i < nf; i++) {
|
||||
if (f[i] == kw->file) {
|
||||
if (!(f = realloc(f, sizeof(*f) * (++i))))
|
||||
err(EXIT_FAILURE, "realloc");
|
||||
f[i-1] = kw->file;
|
||||
}
|
||||
}
|
||||
|
||||
kw = nkw;
|
||||
}
|
||||
|
||||
if (nf > 0) {
|
||||
for (i = 0; i < nf; i++) {
|
||||
free(f[i]->name);
|
||||
free(f[i]);
|
||||
}
|
||||
free(f);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
get_conf(const char *filename)
|
||||
{
|
||||
struct conf_sec *s;
|
||||
struct keyword *head, *kw;
|
||||
|
||||
kw = head = parse_keywords(filename);
|
||||
|
||||
if (!head)
|
||||
return -1; /* TODO ERREUR */
|
||||
|
||||
keywords = head;
|
||||
|
||||
TAILQ_INIT(&config);
|
||||
|
||||
while (kw) {
|
||||
switch (kw->type) {
|
||||
case INCLUDE:
|
||||
if (!(kw = include(kw)))
|
||||
return free_conf();
|
||||
break;
|
||||
case SEC_START:
|
||||
if (!(s = get_section(&kw)))
|
||||
return free_conf();
|
||||
TAILQ_INSERT_TAIL(&config, s, entry);
|
||||
break;
|
||||
default:
|
||||
syntax(kw, "out of any section");
|
||||
return free_conf();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
114
wmfs2/src/parse.h
Executable file
114
wmfs2/src/parse.h
Executable file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2010 Philippe Pepiot <phil@philpep.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PARSE_H
|
||||
#define PARSE_H
|
||||
|
||||
#include "wmfs.h"
|
||||
|
||||
#define INCLUDE_CMD "@include"
|
||||
#define PARSE_MAX_LIST 32
|
||||
|
||||
struct conf_opt {
|
||||
char *name;
|
||||
char *val[PARSE_MAX_LIST];
|
||||
size_t nval;
|
||||
bool used;
|
||||
int line;
|
||||
char *filename;
|
||||
SLIST_ENTRY(conf_opt) entry;
|
||||
};
|
||||
|
||||
struct conf_sec {
|
||||
char *name;
|
||||
SLIST_HEAD(, conf_opt) optlist;
|
||||
TAILQ_HEAD(, conf_sec) sub;
|
||||
size_t nopt;
|
||||
size_t nsub;
|
||||
TAILQ_ENTRY(conf_sec) entry;
|
||||
};
|
||||
|
||||
struct opt_type {
|
||||
long int num;
|
||||
float fnum;
|
||||
bool boolean;
|
||||
char *str;
|
||||
};
|
||||
|
||||
/*
|
||||
* Create config from file
|
||||
* return -1 on failure
|
||||
*/
|
||||
int get_conf(const char *);
|
||||
|
||||
/*
|
||||
* Print unused option name from section s (and subsections).
|
||||
* If s == NULL print unused option name for all config struct.
|
||||
*/
|
||||
void print_unused(struct conf_sec *s);
|
||||
|
||||
/*
|
||||
* Free the config struct.
|
||||
* WARNING: This make all string
|
||||
* returned by fetch_(opt|section)(_first) unusable.
|
||||
*/
|
||||
int free_conf(void);
|
||||
|
||||
/*
|
||||
* Get all subsection matching the given name on the given
|
||||
* section.
|
||||
* If section == NULL, return subsections from root section.
|
||||
* Return a NULL terminated array.
|
||||
* Subsections are returned in order as they are in config file
|
||||
* WARNING : This MUST be free() after use.
|
||||
*/
|
||||
struct conf_sec **fetch_section(struct conf_sec *, char *);
|
||||
|
||||
/*
|
||||
* Get first subsection matching the given name
|
||||
* on the given section. (first found on the file)
|
||||
*/
|
||||
struct conf_sec *fetch_section_first(struct conf_sec *, char *);
|
||||
|
||||
/*
|
||||
* Count member of a conf_sec **
|
||||
*/
|
||||
size_t fetch_section_count(struct conf_sec **);
|
||||
|
||||
/*
|
||||
* Return all options matching the given name on the given subsection.
|
||||
* If none match or section == NULL return opt_type build with the
|
||||
* given default param.
|
||||
* WARNING: This MUST be free() after use.
|
||||
* WARNING: The string member is directly taken from the config struct.
|
||||
* WARNING: Returned in reverse order as they are in config file.
|
||||
* (I think the last option MUST overwrite all others)
|
||||
*/
|
||||
struct opt_type fetch_opt_first(struct conf_sec *, char *, char *);
|
||||
|
||||
/*
|
||||
* Get first (last in config file) option matching the given name
|
||||
* on the given section.
|
||||
* WARNING: The string member is directly taken from the config struct.
|
||||
*/
|
||||
struct opt_type *fetch_opt(struct conf_sec *, char *, char *);
|
||||
|
||||
/*
|
||||
* Count member of a opt_type *
|
||||
*/
|
||||
size_t fetch_opt_count(struct opt_type *);
|
||||
|
||||
#endif /* PARSE_H */
|
||||
199
wmfs2/src/parse_api.c
Executable file
199
wmfs2/src/parse_api.c
Executable file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright (c) 2010 Philippe Pepiot <phil@philpep.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _BSD_SOURCE
|
||||
#define _BSD_SOURCE
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "wmfs.h"
|
||||
#include "parse.h"
|
||||
#include "util.h"
|
||||
|
||||
extern TAILQ_HEAD(, conf_sec) config;
|
||||
|
||||
static const struct opt_type opt_type_null = { 0, 0, False, NULL };
|
||||
|
||||
static struct opt_type
|
||||
string_to_opt(char *s)
|
||||
{
|
||||
struct opt_type ret = opt_type_null;
|
||||
|
||||
if (!s || !strlen(s))
|
||||
return ret;
|
||||
|
||||
ret.num = strtol(s, (char**)NULL, 10);
|
||||
ret.fnum = strtod(s, NULL);
|
||||
|
||||
if (!strcmp(s, "true") || !strcmp(s, "True") ||
|
||||
!strcmp(s, "TRUE") || !strcmp(s, "1"))
|
||||
ret.boolean = True;
|
||||
else
|
||||
ret.boolean = False;
|
||||
|
||||
ret.str = s;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
print_unused(struct conf_sec *sec)
|
||||
{
|
||||
struct conf_sec *s;
|
||||
struct conf_opt *o;
|
||||
|
||||
if (!sec)
|
||||
{
|
||||
TAILQ_FOREACH(s, &config, entry)
|
||||
print_unused(s);
|
||||
return;
|
||||
}
|
||||
|
||||
SLIST_FOREACH(o, &sec->optlist, entry)
|
||||
if (o->used == False)
|
||||
warnx("%s:%d, unused param %s",
|
||||
o->filename, o->line, o->name);
|
||||
|
||||
TAILQ_FOREACH(s, &sec->sub, entry)
|
||||
if (!TAILQ_EMPTY(&s->sub))
|
||||
print_unused(s);
|
||||
}
|
||||
|
||||
struct conf_sec **
|
||||
fetch_section(struct conf_sec *s, char *name)
|
||||
{
|
||||
struct conf_sec **ret;
|
||||
struct conf_sec *sec;
|
||||
size_t i = 0;
|
||||
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
if (!s) {
|
||||
ret = xcalloc(2, sizeof(struct conf_sec *));
|
||||
TAILQ_FOREACH(sec, &config, entry)
|
||||
if (!strcmp(sec->name, name)) {
|
||||
ret[0] = sec;
|
||||
ret[1] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ret = xcalloc(s->nsub+1, sizeof(struct conf_sec *));
|
||||
TAILQ_FOREACH(sec, &s->sub, entry) {
|
||||
if (!strcmp(sec->name, name) && i < s->nsub)
|
||||
ret[i++] = sec;
|
||||
}
|
||||
ret[i] = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct conf_sec *
|
||||
fetch_section_first(struct conf_sec *s, char *name)
|
||||
{
|
||||
struct conf_sec *sec, *ret = NULL;
|
||||
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
if (!s)
|
||||
{
|
||||
TAILQ_FOREACH(sec, &config, entry)
|
||||
if(sec->name && !strcmp(sec->name, name)) {
|
||||
ret = sec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TAILQ_FOREACH(sec, &s->sub, entry)
|
||||
if (sec->name && !strcmp(sec->name, name)) {
|
||||
ret = sec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t
|
||||
fetch_section_count(struct conf_sec **s)
|
||||
{
|
||||
size_t ret;
|
||||
for (ret = 0; s[ret]; ret++);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct opt_type *
|
||||
fetch_opt(struct conf_sec *s, char *dfl, char *name)
|
||||
{
|
||||
struct conf_opt *o;
|
||||
struct opt_type *ret;
|
||||
size_t i = 0;
|
||||
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
ret = xcalloc(10, sizeof(struct opt_type));
|
||||
|
||||
if (s) {
|
||||
SLIST_FOREACH(o, &s->optlist, entry)
|
||||
if (!strcmp(o->name, name)) {
|
||||
while (o->val[i]) {
|
||||
o->used = True;
|
||||
ret[i] = string_to_opt(o->val[i]);
|
||||
i++;
|
||||
}
|
||||
ret[i] = opt_type_null;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret[0] = string_to_opt(dfl);
|
||||
ret[1] = opt_type_null;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct opt_type
|
||||
fetch_opt_first(struct conf_sec *s, char *dfl, char *name)
|
||||
{
|
||||
struct conf_opt *o;
|
||||
|
||||
if (!name)
|
||||
return opt_type_null;
|
||||
else if (s)
|
||||
SLIST_FOREACH(o, &s->optlist, entry)
|
||||
if (!strcmp(o->name, name)) {
|
||||
o->used = True;
|
||||
return string_to_opt(o->val[0]);
|
||||
}
|
||||
return string_to_opt(dfl);
|
||||
}
|
||||
|
||||
size_t
|
||||
fetch_opt_count(struct opt_type *o)
|
||||
{
|
||||
size_t ret;
|
||||
for(ret = 0; o[ret].str; ret++);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -43,6 +43,27 @@ xcalloc(size_t nmemb, size_t size)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** asprintf wrapper
|
||||
* \param strp target string
|
||||
* \param fmt format
|
||||
* \return non zero integer
|
||||
*/
|
||||
int
|
||||
xasprintf(char **strp, const char *fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
ret = vasprintf(strp, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (ret == -1)
|
||||
err(EXIT_FAILURE, "asprintf(%s)", fmt);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Execute a system command
|
||||
* \param cmd Command
|
||||
* \return child pid
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
|
||||
void *xmalloc(size_t nmemb, size_t size);
|
||||
void *xcalloc(size_t nmemb, size_t size);
|
||||
int xasprintf(char **strp, const char *fmt, ...);
|
||||
pid_t spawn(const char *format, ...);
|
||||
|
||||
#endif /* UTIL_H */
|
||||
|
||||
@ -40,6 +40,7 @@ typedef struct Scr33n Scr33n;
|
||||
typedef struct Tag Tag;
|
||||
typedef struct Client Client;
|
||||
typedef struct Keybind Keybind;
|
||||
typedef struct Mousebind Mousebind;
|
||||
|
||||
struct Geo
|
||||
{
|
||||
@ -98,6 +99,28 @@ struct Keybind
|
||||
SLIST_ENTRY(Keybind) next;
|
||||
};
|
||||
|
||||
struct Mousebind
|
||||
{
|
||||
unsigned int button;
|
||||
Geo area;
|
||||
bool use_area;
|
||||
void (*func)(Uicb);
|
||||
Uicb cmd;
|
||||
SLIST_ENTRY(Keybind) next;
|
||||
};
|
||||
|
||||
struct Config
|
||||
{
|
||||
/* Misc section */
|
||||
struct
|
||||
{
|
||||
char *font;
|
||||
bool focus_follow_mouse;
|
||||
bool focus_follow_movement;
|
||||
bool focus_pointer_click;
|
||||
} misc;
|
||||
};
|
||||
|
||||
/* Global struct */
|
||||
struct Wmfs
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user