diff options
author | José Bollo <jose.bollo@iot.bzh> | 2015-12-09 16:21:09 +0100 |
---|---|---|
committer | José Bollo <jose.bollo@iot.bzh> | 2015-12-09 16:21:09 +0100 |
commit | 63f8720a3e610c0dc37bda3138d2e8de98ec1a78 (patch) | |
tree | 3842354238d7fca759cfb74cc95d7b497df41b78 /src/wgt.c | |
parent | ec5ef9fdf2e608149c6ad308c5184820c51c39a6 (diff) |
refactoring widget library
Change-Id: I9662573ed677d34daa393f0e207a4cd4a822f8ad
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
Diffstat (limited to 'src/wgt.c')
-rw-r--r-- | src/wgt.c | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/src/wgt.c b/src/wgt.c new file mode 100644 index 0000000..dd889d5 --- /dev/null +++ b/src/wgt.c @@ -0,0 +1,268 @@ +/* + Copyright 2015 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 <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <assert.h> +#include <limits.h> +#include <string.h> +#include <ctype.h> + + +#include "wgt.h" + +struct wgt { + int rootfd; + int nrlocales; + char **locales; +}; + +static int validsubpath(const char *subpath) +{ + int l = 0, i = 0; + if (subpath[i] == '/') + return 0; + while(subpath[i]) { + switch(subpath[i++]) { + case '.': + if (!subpath[i]) + break; + if (subpath[i] == '/') { + i++; + break; + } + if (subpath[i++] == '.') { + if (!subpath[i]) { + l--; + break; + } + if (subpath[i++] == '/') { + l--; + break; + } + } + default: + while(subpath[i] && subpath[i] != '/') + i++; + l++; + case '/': + break; + } + } + return l >= 0; +} + +struct wgt *wgt_create() +{ + struct wgt *wgt = malloc(sizeof * wgt); + if (wgt) { + wgt->rootfd = -1; + wgt->nrlocales = 0; + wgt->locales = NULL; + } + return wgt; +} + +void wgt_disconnect(struct wgt *wgt) +{ + assert(wgt); + if (wgt->rootfd >= 0) + close(wgt->rootfd); + wgt->rootfd = -1; +} + +void wgt_locales_reset(struct wgt *wgt) +{ + assert(wgt); + while(wgt->nrlocales) + free(wgt->locales[--wgt->nrlocales]); +} + +void wgt_destroy(struct wgt *wgt) +{ + if (wgt) { + wgt_disconnect(wgt); + wgt_locales_reset(wgt); + free(wgt->locales); + free(wgt); + } +} + +int wgt_connect(struct wgt *wgt, const char *pathname) +{ + int rfd; + + assert(wgt); + + rfd = AT_FDCWD; + if (pathname) { + rfd = openat(rfd, pathname, O_PATH|O_DIRECTORY); + if (rfd < 0) + return rfd; + } + if (wgt->rootfd >= 0) + close(wgt->rootfd); + wgt->rootfd = rfd; + return 0; +} + +int wgt_is_connected(struct wgt *wgt) +{ + assert(wgt); + return wgt->rootfd != -1; +} + +int wgt_has(struct wgt *wgt, const char *filename) +{ + assert(wgt); + assert(wgt_is_connected(wgt)); + if (!validsubpath(filename)) { + errno = EINVAL; + return -1; + } + return 0 == faccessat(wgt->rootfd, filename, F_OK, 0); +} + +int wgt_open_read(struct wgt *wgt, const char *filename) +{ + assert(wgt); + assert(wgt_is_connected(wgt)); + if (!validsubpath(filename)) { + errno = EINVAL; + return -1; + } + return openat(wgt->rootfd, filename, O_RDONLY); +} + +static int locadd(struct wgt *wgt, const char *locstr, int length) +{ + int i; + char *item, **ptr; + + item = strndup(locstr, length); + if (item != NULL) { + for (i = 0 ; item[i] ; i++) + item[i] = tolower(item[i]); + for (i = 0 ; i < wgt->nrlocales ; i++) + if (!strcmp(item, wgt->locales[i])) { + free(item); + return 0; + } + + ptr = realloc(wgt->locales, (1 + wgt->nrlocales) * sizeof(wgt->locales[0])); + if (ptr) { + wgt->locales = ptr; + wgt->locales[wgt->nrlocales++] = item; + return 0; + } + free(item); + } + errno = ENOMEM; + return -1; +} + +int wgt_locales_add(struct wgt *wgt, const char *locstr) +{ + const char *stop, *next; + assert(wgt); + while (*locstr) { + stop = strchrnul(locstr, ','); + next = stop + !!*stop; + while (locstr != stop) { + if (locadd(wgt, locstr, stop - locstr)) + return -1; + do { stop--; } while(stop > locstr && *stop != '-'); + } + locstr = next; + } + return 0; +} + +int wgt_locales_score(struct wgt *wgt, const char *lang) +{ + int i; + + assert(wgt); + if (lang) + for (i = 0 ; i < wgt->nrlocales ; i++) + if (!strcasecmp(lang, wgt->locales[i])) + return i; + + return INT_MAX; +} + +static const char *localize(struct wgt *wgt, const char *filename, char path[PATH_MAX]) +{ + int i; + + if (!validsubpath(filename)) { + errno = EINVAL; + return NULL; + } + for (i = 0 ; i < wgt->nrlocales ; i++) { + if (snprintf(path, PATH_MAX, "locales/%s/%s", wgt->locales[i], filename) >= PATH_MAX) { + errno = EINVAL; + return NULL; + } + if (0 == faccessat(wgt->rootfd, path, F_OK, 0)) + return path; + } + if (0 == faccessat(wgt->rootfd, filename, F_OK, 0)) + return filename; + errno = ENOENT; + return NULL; +} + +char *wgt_locales_locate(struct wgt *wgt, const char *filename) +{ + char path[PATH_MAX]; + char * result; + const char * loc; + + assert(wgt); + assert(wgt_is_connected(wgt)); + loc = localize(wgt, filename, path); + if (!loc) + result = NULL; + else { + result = strdup(loc); + if (!result) + errno = ENOMEM; + } + return result; +} + + +int wgt_locales_open_read(struct wgt *wgt, const char *filename) +{ + char path[PATH_MAX]; + const char *loc; + + assert(wgt); + assert(wgt_is_connected(wgt)); + loc = localize(wgt, filename, path); + if (!loc) + return -1; + + return openat(wgt->rootfd, loc, O_RDONLY); +} + + |