| /*
* sai-device conf.c
*
* Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#if defined(WIN32) /* complaints about getenv */
#define _CRT_SECURE_NO_WARNINGS
#define read _read
#define close _close
#endif
#include <libwebsockets.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include <fcntl.h>
#include "d-private.h"
/* global part */
static const char * const paths_global[] = {
"home",
"devices[].name",
"devices[].type",
"devices[].compatible",
"devices[].description",
"devices[].ttys[].name",
"devices[].ttys[].tty",
"devices[].ttys[].rate",
"devices[].ttys[].initial_monitor",
"devices[].ttys[].lock",
"devices[].ttys[]",
"devices[]",
};
enum enum_paths_global {
LEJPM_HOME,
LEJPM_DEVICES__NAME,
LEJPM_DEVICES__TYPE,
LEJPM_DEVICES__COMPATIBLE,
LEJPM_DEVICES__DESCRIPTION,
LEJPM_DEVICES__TTYS__NAME,
LEJPM_DEVICES__TTYS__TTY,
LEJPM_DEVICES__TTYS__RATE,
LEJPM_DEVICES__TTYS__INITIAL_MONITOR,
LEJPM_DEVICES__TTYS__LOCK,
LEJPM_DEVICES__TTYS,
LEJPM_DEVICES,
};
struct jpargs {
sai_devices_t *devices;
sai_device_t *dev;
sai_tty_t *tty;
};
static signed char
said_conf_global_cb(struct lejp_ctx *ctx, char reason)
{
struct jpargs *a = (struct jpargs *)ctx->user;
const char **pp;
#if 0
int n;
lwsl_notice("%s: reason: %d, path: %s, match %d\n", __func__,
reason, ctx->path, ctx->path_match);
for (n = 0; n < ctx->wildcount; n++)
lwsl_notice(" %d\n", ctx->wild[n]);
#endif
if (reason == LEJPCB_OBJECT_START &&
ctx->path_match - 1 == LEJPM_DEVICES) {
/*
* We're starting on defining a new device
*/
a->dev = lwsac_use_zero(&a->devices->conf_head, sizeof(*a->dev), 512);
if (!a->dev)
return -1;
lws_dll2_add_tail(&a->dev->list, &a->devices->devices_owner);
a->tty = NULL;
return 0;
}
if (reason == LEJPCB_OBJECT_START &&
ctx->path_match - 1 == LEJPM_DEVICES__TTYS) {
/*
* We're starting on defining a new tty for our device
*/
a->tty = lwsac_use_zero(&a->devices->conf_head, sizeof(*a->tty), 512);
if (!a->tty)
return -1;
lwsl_notice("%s: adding tty\n", __func__);
a->tty->initial_monitor = 1;
a->tty->lock = 1;
a->tty->index = (int)a->dev->ttys_owner.count;
lws_dll2_add_tail(&a->tty->list, &a->dev->ttys_owner);
return 0;
}
/* we only match on the prepared path strings */
if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
return 0;
if (reason == LEJPCB_VAL_NUM_INT &&
ctx->path_match - 1 == LEJPM_DEVICES__TTYS__RATE) {
a->tty->rate = atoi(ctx->buf);
return 0;
}
if (reason == LEJPCB_VAL_FALSE &&
ctx->path_match - 1 == LEJPM_DEVICES__TTYS__INITIAL_MONITOR) {
a->tty->initial_monitor = 0;
return 0;
}
if (reason == LEJPCB_VAL_FALSE &&
ctx->path_match - 1 == LEJPM_DEVICES__TTYS__LOCK) {
a->tty->lock = 0;
return 0;
}
if (reason != LEJPCB_VAL_STR_END)
return 0;
/* only the end part of the string, where we know the length */
switch (ctx->path_match - 1) {
case LEJPM_HOME:
pp = &a->devices->home;
break;
case LEJPM_DEVICES__NAME:
pp = &a->dev->name;
break;
case LEJPM_DEVICES__TYPE:
pp = &a->dev->type;
break;
case LEJPM_DEVICES__COMPATIBLE:
pp = &a->dev->compatible;
break;
case LEJPM_DEVICES__DESCRIPTION:
pp = &a->dev->description;
break;
case LEJPM_DEVICES__TTYS__NAME:
pp = &a->tty->name;
break;
case LEJPM_DEVICES__TTYS__TTY:
pp = &a->tty->tty_path;
lwsl_notice("%s: tty path %.*s\n", __func__, (int)ctx->npos, ctx->buf);
break;
default:
return 0;
}
*pp = lwsac_use(&a->devices->conf_head, ctx->npos + 1u, 512);
if (!*pp)
return 1;
memcpy((char *)(*pp), ctx->buf, ctx->npos);
((char *)(*pp))[ctx->npos] = '\0';
return 0;
}
int
said_config_global(struct sai_devices *devices, const char *d)
{
unsigned char buf[128];
struct lejp_ctx ctx;
int n, m, fd;
struct jpargs a;
memset(&a, 0, sizeof(a));
a.devices = devices;
#if defined(WIN32)
lws_snprintf((char *)buf, sizeof(buf) - 1u, "%s\\conf", d);
#else
lws_snprintf((char *)buf, sizeof(buf) - 1u, "%s/conf", d);
#endif
fd = lws_open((char *)buf, O_RDONLY);
if (fd < 0) {
lwsl_err("Cannot open %s\n", (char *)buf);
return 2;
}
lwsl_info("%s: %s\n", __func__, (char *)buf);
lejp_construct(&ctx, said_conf_global_cb, &a,
paths_global, LWS_ARRAY_SIZE(paths_global));
sai_lejp_enable_comments(&ctx);
do {
n = (int)read(fd, buf, sizeof(buf));
if (!n)
break;
m = lejp_parse(&ctx, buf, n);
} while (m == LEJP_CONTINUE);
close(fd);
n = (int)ctx.line;
lejp_destruct(&ctx);
lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
devices->devices_owner.head) {
sai_device_t *d = lws_container_of(p, sai_device_t, list);
lwsl_info("%s: device '%s', %s, %s, %s\n", __func__,
d->name, d->type, d->compatible, d->description);
lws_start_foreach_dll_safe(struct lws_dll2 *, q, q1,
d->ttys_owner.head) {
sai_tty_t *t = lws_container_of(q, sai_tty_t, list);
lwsl_info("%s: tty %s\n", __func__,
t->tty_path);
} lws_end_foreach_dll_safe(q, q1);
} lws_end_foreach_dll_safe(p, p1);
return 0;
}
void
said_config_destroy(struct sai_devices *devices)
{
lwsac_free(&devices->conf_head);
}
|