/* This file is part of gacopyz.
Copyright (C) 2007, 2008, 2009, 2010 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <gacopyz_priv.h>
typedef struct gacopyz_macro_def *gacopyz_macro_def_t;
struct gacopyz_macro_def {
char *name;
char *value;
};
#define _SRV_CONNECTED 0x0100
#define _SRV_READY 0x0200
#define _SRV_CLRDIS 0x0400
#define _SRV_SYS_MASK 0xff00
struct gacopyz_srv {
char *id; /* Server identifier (not used yet) */
char *portspec; /* Port spec */
struct gacopyz_iod iod;
int flags;
gacopyz_macro_def_t def;
size_t ndefs;
size_t maxdefs;
gacopyz_uint32_t source_addr;
int onerror;
void (*memerror)(gacopyz_srv_t, const char *, unsigned int);
unsigned long version;
unsigned long acts;
unsigned long proto;
char **req_macros[gacopyz_stage_max]; /* Required macros */
int (*cb_reply)(gacopyz_srv_t srv, int cmd, int rcmd, void *data);
void *cb_data;
char *buf;
size_t bufsize;
char *resp_ptr;
size_t resp_size;
};
void
default_memerror(gacopyz_srv_t srv, const char *file, unsigned int line)
{
gacopyz_io_log(&srv->iod, SMI_LOG_FATAL,
_("%s:%lu: not enough memory"),
file, line);
abort();
}
#define GACOPYZ_ASSERT(e) \
if (!(e)) { \
fprintf(stderr, "%s:%d: GACOPYZ usage error: assertion failed: %s\n", \
__FILE__, __LINE__, #e); \
abort(); \
}
#define GACOPYZ_ALLOC(srv, expr) do \
if (!(expr)) { \
srv->memerror(srv, __FILE__, __LINE__); \
if (!(expr)) \
default_memerror(srv, __FILE__, __LINE__); \
} while (0)
static struct gacopyz_macro_def *
find_def(gacopyz_srv_t srv, const char *name, size_t len)
{
size_t i;
for (i = 0; i < srv->ndefs; i++)
if (strncmp(srv->def[i].name, name, len) == 0)
return &srv->def[i];
return NULL;
}
static void
add_def(gacopyz_srv_t srv, const char *name, size_t len, const char *value)
{
struct gacopyz_macro_def *def;
if (def = find_def(srv, name, len))
free(def->value);
else {
if (srv->ndefs == srv->maxdefs) {
size_t maxdefs = srv->maxdefs + 64;
GACOPYZ_ALLOC(srv,
def = realloc(srv->def,
sizeof(srv->def[0]) * maxdefs));
srv->maxdefs = maxdefs;
srv->def = def;
}
def = srv->def + srv->ndefs++;
GACOPYZ_ALLOC(srv, def->name = malloc(len + 1));
memcpy(def->name, name, len);
def->name[len] = 0;
}
GACOPYZ_ALLOC(srv, def->value = strdup(value));
}
void
del_def(gacopyz_srv_t srv, const char *name, size_t len)
{
struct gacopyz_macro_def *def = find_def(srv, name, len);
if (!def)
return;
free(def->name);
free(def->value);
srv->ndefs--;
memmove(def, def + 1,
sizeof(srv->def[0]) *(srv->ndefs - (def - srv->def)));
}
static void
srv_ensure_space(gacopyz_srv_t srv, size_t size)
{
if (size > srv->bufsize) {
char *p;
GACOPYZ_ALLOC(srv, p = realloc(srv->buf, size));
srv->buf = p;
srv->bufsize = size;
}
}
size_t
macro_size(gacopyz_srv_t srv)
{
size_t i;
size_t size = 0;
struct gacopyz_macro_def *def;
for (i = 0, def = srv->def; i < srv->ndefs; i++, def++) {
size_t len = strlen(def->name);
size += len;
if (len > 1 && def->name[0] != '{')
size += 2; /* for {} */
size += 1 + strlen(def->value) + 1;
}
return size;
}
void
srv_format_macros(gacopyz_srv_t srv, unsigned char cmd, size_t *psize)
{
size_t i;
char *p;
size_t size = macro_size(srv) + 1;
struct gacopyz_macro_def *def;
srv_ensure_space(srv, size);
p = srv->buf;
*p++ = cmd;
for (i = 0, def = srv->def; i < srv->ndefs; i++, def++) {
size_t len = strlen(def->name);
if (len > 1 && def->name[0] != '{') {
*p++ = '{';
memcpy(p, def->name, len);
p += len;
*p++ = '}';
*p++ = 0;
} else {
len++;
memcpy(p, def->name, len);
p += len;
}
len = strlen(def->value) + 1;
memcpy(p, def->value, len);
p += len;
}
*psize = size;
}
#define GETNAMELEN(name, len) \
len = strlen(name); \
if (name[0] == '{' && name[len-1] == '}') { \
name++; \
len -= 2; \
}
int
gacopyz_srv_find_macro(gacopyz_srv_t srv, const char *name, const char **pval)
{
struct gacopyz_macro_def *def;
size_t len;
GACOPYZ_ASSERT(srv);
GETNAM
|