/*
openisis - an open implementation of the CDS/ISIS database
Version 0.8.x (patchlevel see file Version)
Copyright (C) 2001-2003 by Erik Grziwotz, erik@openisis.org
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; either
version 2.1 of the License, or (at your option) any later version.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
see README for more information
EOH */
/*
$Id: lfdt.c,v 1.25 2003/06/15 15:57:43 mawag Exp $
implementation of FDT calls and static FDTs.
*/
#include <limits.h> /* CHAR_MAX,PATH_MAX */
#include <stdio.h>
#include <string.h>
#include "openisis.h"
#include "loi.h"
#include "lfdt.h"
#include "luti.h"
#define FDF_EXT ".fdt"
#define FDF_NAMLEN 30
#define FDF_PATLEN 20 /* format of *.fdt */
#define FDF_TOOLEN 6
#if FDF_NAMLEN >= FD_NAMELEN
fix me
#endif
/* ************************************************************
private types
*/
/* ************************************************************
private data
*/
#define _FD_DFLTDB \
{ OPENISIS_SC_DFLTDB, 0, FTX, 0, 0, DBNLEN, "defaultdb", \
"Name of default db", 0, 0, 0, 0 }
#define _FD_DPATH \
{ OPENISIS_DPATH, 0, FTX, 0, 0, PATH_MAX, "dbpath", \
"Database Path", 0, 0, 0, 0 }
#define _FD_DENC \
{ OPENISIS_DENC, 0, FTX, 0, 0, 32, "encoding", \
"Encoding", 0, 0, 0, 0 }
static Fd _fdsys[] = {
/* 700 ... OpenIsis system parameters */
{ OPENISIS_SPATH, 0, FTX, 0, 0, PATH_MAX, "syspath",
"Global Database Path", 0, 0, 0, 0 },
{ OPENISIS_SLOGF, 0, FTX, 0, 0, PATH_MAX, "logfile",
"Logfile Name", 0, 0, 0, 0 },
{ OPENISIS_SLOGV, 0, FTE, 0, 0, 16, "v",
"Verbosity of Logging", 0, 0, 0, 0 },
{ OPENISIS_SLOGV, 0, FTV, 0, 0, 0, "off",
"don't log anything", 0, 0, 0, 0 },
{ OPENISIS_SLOGV, 0, FTV, 0, 0, 1, "fatal", "", 0, 0, 0, 0 },
{ OPENISIS_SLOGV, 0, FTV, 0, 0, 3, "syserr", "", 0, 0, 0, 0 },
{ OPENISIS_SLOGV, 0, FTV, 0, 0, 4, "error", "", 0, 0, 0, 0 },
{ OPENISIS_SLOGV, 0, FTV, 0, 0, 5, "warn", "", 0, 0, 0, 0 },
{ OPENISIS_SLOGV, 0, FTV, 0, 0, 6, "info", "", 0, 0, 0, 0 },
{ OPENISIS_SLOGV, 0, FTV, 0, 0, 7, "verbose", "", 0, 0, 0, 0 },
{ OPENISIS_SLOGV, 0, FTV, 0, 0, 8, "trace", "", 0, 0, 0, 0 },
{ OPENISIS_SLOGV, 0, FTV, 0, 0, 9, "debug", "", 0, 0, 0, 0 },
{ OPENISIS_SLOGV, 0, FTV, 0, 0, 10, "all", "", 0, 0, 0, 0 },
_FD_DFLTDB,
_FD_DPATH,
_FD_DENC
};
static Fdt _fdtsys = {
sizeof (_fdsys) / sizeof (_fdsys[0]),
_fdsys,
0
};
static Fd _fdsch[] = {
{ OPENISIS_SC_NAME, 0, FTX, 0, 0, SCNLEN, "name",
"Identification of remote scheme", 0, 0, 0, 0 },
{ OPENISIS_SC_HOST, 0, FTX, 0, 0, 64, "host",
"Hostname of remote scheme", 0, 0, 0, 0 },
{ OPENISIS_SC_PORT, 0, FTN, 0, 0, 5, "port",
"Port of remote scheme", 0, 0, 0, 0 },
_FD_DFLTDB,
_FD_DPATH,
_FD_DENC
};
static Fdt _fdtsch = {
sizeof (_fdsch) / sizeof (_fdsch[0]),
_fdsch,
0
};
static Fd _fddb[] = {
{ OPENISIS_DNAME, 0, FTX, 0, 0, DBNLEN, "db",
"Identification of database", 0, 0, 0, 0 },
{ OPENISIS_DTYPE, 0, FTE, 0, 0, 256, "format",
"Database Format", 0, 0, 0, 0 },
{ OPENISIS_DTYPE, 0, FTV, 0, 0, 0, "autoformat",
"Database Format", 0, 0, 0, 0 },
{ OPENISIS_DTYPE, 0, FTV, 0, 0, 1, "naligned",
"Database Format", 0, 0, 0, 0 },
{ OPENISIS_DTYPE, 0, FTV, 0, 0, 2, "aligned",
"Database Format", 0, 0, 0, 0 },
{ OPENISIS_DRO , 0, FTB, 0, 0, 1, "ro",
"Readonly Flag", 0, 0, 0, 0 },
_FD_DPATH,
{ OPENISIS_DDUMP, 0, FTB, 0, 0, 1, "internaldump",
"Internal Dump Flag", 0, 0, 0, 0 },
_FD_DENC,
{ OPENISIS_DFDT, 0, FTX, 0, 0, 256, "fdt",
"Path to fdt", 0, 0, 0, 0 }
};
static Fdt _fdtdb = {
sizeof (_fddb) / sizeof (_fddb[0]),
_fddb,
0
};
static Fd _fdfd[] = {
{ OPENISIS_FDID, 0, FTN, 0, 0, 10, "tag",
"Tag number of field", 0, 0, 0, 0 },
{ OPENISIS_FDSUB, 0, FTX, 0, 0, 1, "subfield",
"Subfield", 0, 0, 0, 0 },
{ OPENISIS_FDTYPE, 0, FTE, 0, 0, 2, "type",
"Field type", 0, 0, 0, 0 },
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTX, "alphanum",
"Field type", 0, 0, 0, 0 },
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTA, "alpha",
"Field type", 0, 0, 0, 0 },
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTN, "numeric",
"Field type", 0, 0, 0, 0 },
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTP, "pattern",
"Field type", 0, 0, 0, 0 },
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTI, "iso",
"Field type", 0, 0, 0, 0 },
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTE, "enum",
"Field type", 0, 0, 0, 0 },
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTB, "boolean",
"Field type", 0, 0, 0, 0 },
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTT, "table",
"Field type", 0, 0, 0, 0 },
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTS, "structure",
"Field type", 0, 0, 0, 0 },
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTF | FTX, "subalphanum",
"Subfield type", 0, 0, 0, 0 },
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTF | FTA, "subalpha",
"Subfield type", 0, 0, 0, 0 },
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTF | FTN, "subnumeric",
"Subfield type", 0, 0, 0, 0 },
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTF | FTP, "subpattern",
"Subfield type", 0, 0, 0, 0 },
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTF | FTI, "subiso",
"Subfield type", 0, 0, 0, 0 },
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTF | FTE, "subenum",
"Subfield type", 0, 0, 0, 0 },
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTF | FTB, "subbool",
"Subfield type", 0, 0, 0, 0 },
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTV, "enum value",
"Enumeration value", 0, 0, 0, 0 },
{ OPENISIS_FDREP, 0, FTB, 0, 0, 1, "repeatable",
"Repeatable flag", 0, 0, 0, 0 },
{ OPENISIS_FDNUMC, 0, FTN, 0, 0, 2, "numchilds",
"Number of subfield childs", 0, 0, 0, 0 },
{ OPENISIS_FDLEN, 0, FTN, 0, 0, 10, "length",
"Field length or enum value", 0, 0, 0, 0 },
{ OPENISIS_FDNAME, 0, FTX, 0, 0, 30, "name",
"Field name", 0, 0, 0, 0 },
{ OPENISIS_FDDESC, 0, FTX, 0, 0, 31, "description",
"Description", 0, 0, 0, 0 },
{ OPENISIS_FDPAT, 0, FTX, 0, 0, 128, "pattern",
"Pattern", 0, 0, 0, 0 },
{ OPENISIS_FDDFLT, 0, FTX, 0, 0, 1024, "default",
"Default value", 0, 0, 0, 0 },
{ OPENISIS_FDINFO, 0, FTS, 0, 0, 1, "info",
"Embedded info record", 0, 0, 0, 0 },
{ OPENISIS_FDCHLD, 0, FTX, 1, 0, 1, "children",
"Subfield childs", 0, 0, 0, 0 }
};
static Fdt _fdtfd = {
sizeof (_fdfd) / sizeof (_fdfd[0]),
_fdfd,
0
};
#define _FD_FDT \
{ OPENISIS_FDT_LEN, 0, FTN, 0, 0, 3, "flen", \
"Length of fdt", 0, 0, 0, 0 }, \
{ OPENISIS_FDT_FD, 0, FTS, 1, 0, 1, "fd", \
"Field description", 0, 0, 0, 0 }, \
{ OPENISIS_FDT_REC, 0, FTS, 0, 0, 1, "frec", \
"Embedded info record", 0, 0, 0, 0 }
static Fd _fdfdt[] = {
_FD_FDT
};
static Fdt _fdtfdt = {
sizeof (_fdfdt) / sizeof (_fdfdt[0]),
_fdfdt,
0
};
#define _FD_COM \
{ OPENISIS_COM_SID, 0, FTN, 0, 0, 2, "sid", \
"Client Session Id", 0, 0, 0, 0 }, \
{ OPENISIS_COM_SER, 0, FTN, 0, 0, 5, "ser", \
"Request Serial No.", 0, 0, 0, 0 }, \
{ OPENISIS_COM_DBN, 0, FTX, 0, 0, DBNLEN, "db", \
"DB Identification", 0, 0, 0, 0 }, \
{ OPENISIS_COM_TMS, 0, FTN, 0, 0, 10, "tms", \
"Server Db Timestamp", 0, 0, 0, 0 }, \
{ OPENISIS_COM_ROW, 0, FTN, 0, 0, 10, "rowid", \
"RowId", 0, 0, 0, 0 }, \
_FD_FDT, \
{ OPENISIS_COM_CFG, 0, FTS, 0, 0, 0, "config", \
"Config", 0, 0, 0, 0 }, \
{ OPENISIS_COM_REC, 0, FTS, 1, 0, 0, "rec", \
"Data", 0, 0, 0, 0 }
static Fd _fdrqs[] = {
_FD_COM,
{ OPENISIS_RQS_TYPE, 0, FTE, 0, 0, 32, "type",
"Request type", 0, 0, 0, 0 },
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_OPEN, "open",
"open db", 0, 0, 0, 0 },
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_CLOS, "close",
"close db", 0, 0, 0, 0 },
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_MNT, "mount",
"mount db", 0, 0, 0, 0 },
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_LSDB, "ls",
"list dbs", 0, 0, 0, 0 },
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_MROW, "maxrow",
"get maxrowid", 0, 0, 0, 0 },
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_QRY, "query",
"exec query", 0, 0, 0, 0 },
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_READ, "read",
"fetch row", 0, 0, 0, 0 },
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_INS, "insert",
"insert rec", 0, 0, 0, 0 },
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_UPD, "update",
"update rec", 0, 0, 0, 0 },
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_DEL, "delete",
"delete row", 0, 0, 0, 0 },
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_EVAL, "eval",
"evaluate command", 0, 0, 0, 0 },
{ OPENISIS_RQS_FLG, 0, FTN, 0, 0, 4, "flags",
"Request flags", 0, 0, 0, 0 },
{ OPENISIS_RQS_QMOD, 0, FTN, 0, 0, 5, "mode",
"Query Mode", 0, 0, 0, 0 },
{ OPENISIS_RQS_SKIP, 0, FTN, 0, 0, 5, "skip",
"Query Skip", 0, 0, 0, 0 },
{ OPENISIS_RQS_SIZE, 0, FTN, 0, 0, 5, "size",
"Result Length", 0, 0, 0, 0 },
{ OPENISIS_RQS_KEY, 0, FTX, 0, 0, OPENISIS_QRY_KEYLEN, "key",
"Query Key", 0, 0, 0, 0 },
{ OPENISIS_RQS_IDX, 0, FTS, 0, 0, 0, "idx",
"Index to Update", 0, 0, 0, 0 }
};
static Fdt _fdtrqs = {
sizeof (_fdrqs) / sizeof (_fdrqs[0]),
_fdrqs,
0
};
static Fd _fdrsp[] = {
_FD_COM,
{ OPENISIS_RSP_DBID, 0, FTN, 0, 0, 2, "dbid",
"Id of local db", 0, 0, 0, 0 },
{ OPENISIS_RSP_ERR, 0, FTN, 0, 0, 5, "error",
"Error Code", 0, 0, 0, 0 },
{ OPENISIS_RSP_MSG, 0, FTX, 0, 0, OPENISIS_ERRMSGLEN, "msg",
"Error Message", 0, 0, 0, 0 },
{ OPENISIS_RSP_NUMT, 0, FTN, 0, 0, 5, "total",
"Total No. of Records", 0, 0, 0, 0 },
{ OPENISIS_RSP_NUMR, 0, FTN, 0, 0, 5, "size",
"Number of Records", 0, 0, 0, 0 },
{ OPENISIS_RSP_CERR, 0, FTN, 0, 0, 5, "error2",
"Client Side Error", 0, 0, 0, 0 }
};
static Fdt _fdtrsp = {
sizeof (_fdrsp) / sizeof (_fdrsp[0]),
_fdrsp,
0
};
/* ************************************************************
public data
*/
const Fdt *openIsisFdtSyspar = &_fdtsys;
const Fdt *openIsisFdtScheme = &_fdtsch;
const Fdt *openIsisFdtDbpar = &_fdtdb;
const Fdt *openIsisFdtFd = &_fdtfd;
const Fdt *openIsisFdtFdt = &_fdtfdt;
const Fdt *openIsisFdtRqs = &_fdtrqs;
const Fdt *openIsisFdtRsp = &_fdtrsp;
/* ************************************************************
private functions
*/
static char *fFileGets (FILE *fp) {
static char buf[4096];
char *res;
int len;
while (1) {
nxtl:
if (0 == (res = fgets (buf, sizeof(buf) - 1, fp))) {
break;
}
buf[sizeof(buf) - 1] = 0;
if (!(len = strlen (res))) {
continue;
}
--len;
while (0 <= len) {
if ('\n' != res[len] && '\r' != res[len]) {
break;
}
res[len] = 0;
if (0 > --len) {
goto nxtl;
}
}
break;
}
return res;
}
static void strrtrim (char *str) {
char *p = str + strlen (str) - 1;
while (p >= str && (' ' == *p || '\t' == *p)) {
*p-- = 0;
}
}
static void fDesc2Name (char *d, char *n) {
while (1) {
if (!(*n = *d)) {
return;
}
if ('A' <= *n && 'Z' >= *n) {
*n += 'a' - 'A';
++n;
++d;
continue;
}
if ('_' == *n ||
('a' <= *n && 'z' >= *n) ||
('0' <= *n && '9' >= *n)) {
++n;
++d;
continue;
}
while (1) {
++d;
if (!*d) {
*n = 0;
return;
}
if (('A' <= *d && 'Z' >= *d) ||
('a' <= *d && 'z' >= *d) ||
('0' <= *d && '9' >= *d)) {
break;
}
}
*n++ = '_';
}
}
static int fLine2Fd (char *line, Fd **fd, int *num) {
char name[FD_NAMELEN];
char pat[1 + FDF_PATLEN];
Fd buff, bufs;
char *P;
char *L = line;
int tag, len, typ, rep, idx;
if (FDF_NAMLEN + FDF_PATLEN >= strlen (L)) {
return sMsg (ERR_INVAL, "fFileFd: illegal line <%s>", line);
}
strncpy (name, L, FDF_NAMLEN) [FDF_NAMLEN] = 0;
strrtrim (name);
if (! *name) {
return sMsg (ERR_INVAL, "fFileFd: no descr in line <%s>", line);
}
L += FDF_NAMLEN;
strncpy (pat, L, FDF_PATLEN) [FDF_PATLEN] = 0;
strrtrim (pat);
L += FDF_PATLEN;
if (4 != sscanf (L, "%d %d %d %d", &tag, &len, &typ, &rep)) {
return sMsg (ERR_INVAL, "fFileFd: no type in line <%s>", line);
}
switch (typ) {
case 0: typ = FTX; break;
case 1: typ = FTA; break;
case 2: typ = FTN; break;
case 3: typ = FTP; break;
default: return sMsg (ERR_INVAL,
"fFileFd: unrecognized type %d in line <%s>", typ, line);
}
memset (&buff, 0, sizeof (Fd));
buff.id = tag;
buff.type = typ;
buff.rep = 0 != rep;
buff.len = len;
strcpy (buff.desc, name);
fDesc2Name (name, buff.name);
if (! *buff.name) {
return sMsg (ERR_INVAL, "fFileFd: illegal name in line <%s>", line);
}
if (FTP == typ) {
if (! *pat) {
return sMsg (ERR_INVAL, "fFileFd: illegal pat in line <%s>", line);
}
buff.pat = mDup (pat, -1);
if (! buff.pat) {
return sMsg (ERR_NOMEM, "fFileFd: cannot allocate pat");
}
}
idx = luti_ptrincr (fd, num, 1, sizeof(Fd), -1);
if (0 > idx) {
return sMsg (ERR_NOMEM,
"fFileFd: cannot extend fd array %d", *num);
}
memcpy (*fd + idx, &buff, sizeof(Fd));
if (FTP != typ) {
for (P = pat; *P; ++P) {
memcpy (&bufs, &buff, sizeof(Fd));
bufs.subf = *P;
bufs.type = FTX;
idx = luti_ptrincr (fd, num, 1, sizeof(Fd), -1);
if (0 > idx) {
return sMsg (ERR_NOMEM,
"fFileFd: cannot extend fd array %d", *num);
}
memcpy (*fd + idx, &bufs, sizeof(Fd));
}
}
return 0;
}
static int fLine2Tool (char *line, Rec **rec) {
char tool[1 + FDF_TOOLEN];
char *L = line;
int len, typ;
switch (*L) {
case 'w':
case 'W':
typ = OPENISIS_DFMT;
break;
case 'f':
case 'F':
typ = OPENISIS_DPFT;
break;
case 's':
case 'S':
typ = OPENISIS_DFST;
break;
default:
return sMsg (ERR_INVAL, "fLine2Tool: illegal line <%s>", line);
}
L += 2;
len = strlen (L);
while (0 < len) {
strncpy (tool, L, FDF_TOOLEN) [FDF_TOOLEN] = 0;
strrtrim (tool);
RADDS (*rec, typ, tool, !0);
if (! *rec) {
return sMsg (ERR_NOMEM, "fLine2Tool: cannot extend rec");
}
L += FDF_TOOLEN;
len -= FDF_TOOLEN;
}
return 0;
}
static int fResolveChilds (Fd *fd, int len) {
char msg[256] = { 0 };
Fd *buf[CHAR_MAX];
Fd **C;
Fd *F, *G;
int numc;
int err = 0;
for (F = fd + len; --F >= fd; ) {
if (! F->subf) {
numc = 0;
C = buf;
for (G = fd + len; --G >= fd; ) {
if (G->subf && (! G->id || G->id == F->id)) {
if (CHAR_MAX == numc) {
err = ERR_INVAL;
sprintf (msg,
"fResolveChilds: too many childs for %s",
F->name);
break;
}
*C++ = G;
++numc;
}
}
if (numc) {
C = mAlloc (numc * sizeof(Fd));
if (! C) {
return sMsg (ERR_NOMEM, "fResolveChilds");
}
F->subs = (Fd**) memcpy (C, buf, numc * sizeof(Fd));
F->slen = numc;
}
}
}
if (err) {
return sMsg (err, msg);
}
return 0;
}
static void fFreeFd (Fd *fd) {
if (fd) {
if (fd->pat) {
mFree (fd->pat);
}
if (fd->dflt) {
mFree (fd->dflt);
}
if (fd->info) {
mFree (fd->info);
}
if (fd->subs) {
mFree (fd->subs);
}
}
}
static Fdt* fCleanupArr (Fdt *fdt, Fd *arr, int len) {
Fd *F;
for (F = arr + len; --F >= arr; ) {
fFreeFd (F);
}
mFree (arr);
mFree (fdt);
return 0;
}
/* ************************************************************
package functions
*/
/* ************************************************************
public functions
*/
Fd* fById ( const Fdt *fdt, int id, int subf )
{
Fd *f, *e;
if (! fdt) {
return 0;
}
for (e = (f = fdt->fd) + fdt->len; --e >= f; ) {
if (id == e->id && subf == e->subf && ! (0xf0 & e->type)) {
return e;
}
}
return 0;
}
Fd* fByName ( const Fdt *fdt, const char *name )
{
Fd *f, *e, *g;
const char *p;
int l, cnt;
if (! fdt || ! name) {
return 0;
}
f = fdt->fd;
e = f + fdt->len;
if ( '-' == *name ) /* ignore leading dash */
name++;
if (! *name) {
return 0;
}
if ( '0' <= *name && *name <= '9' )
return fById( fdt, a2i( name, -1 ), 0 );
p = name;
while ( 'a' <= *p ? *p <= 'z' : '9' >= *p ? *p >= '0' : '_' == *p )
p++;
l = p - name;
if ( ! l || l > FD_NAMELEN - 1 )
return 0;
for ( cnt = 0, g = 0; f < e; f++ ) {
if ( *name == *f->name
&& !(0xf0 & f->type) /* is field */
&& !memcmp( name, f->name, l ) ) {
if (!f->name[l]) {
return f;
}
g = f;
++cnt;
}
}
return 1 == cnt ? g : 0;
}
/**
lookup enum:
if name is numeric, the value is returned, if legal
considered are value entries with given id or id 0
- if there is an exact match with same id, this is used
- if there is an exact match with id 0, this is used
- if name is a unique prefix on given id, this is used
- if name is no prefix on given id, but a unique prefix on 0, this is used
*/
int fEnum ( Fdt *fdt, int id, const char *name )
{
Fd *f = fdt->fd, *e = f + fdt->len,
*x0 = 0, *pi = 0, *p0 = 0;
int ui = 1, u0 = 1; /* unique */
int l = strlen( name );
if ( ! l || l > FD_NAMELEN - 1 )
return NOENUM;
if ( ('0' <= *name && *name <= '9')
|| ('-' == *name && '0' <= name[1] && name[1] <= '9')
) {
int v = a2i( name, l );
for ( ; f < e; f++ ) {
if ( FTV == f->type && v == f->len && (f->id == id || !f->id) )
return v;
}
return NOENUM;
}
for ( ; f < e; f++ ) {
if ( FTV != f->type
|| *name != *f->name
|| memcmp( name, f->name, l )
|| (f->id && f->id != id)
)
continue;
if ( !f->name[l] ) { /* exact match */
if ( f->id == id )
return f->len;
x0 = f; /* f->id is 0 */
continue;
}
/* prefix match */
if ( f->id == id ) {
if ( pi )
ui = 0;
else
pi = f;
} else
if ( p0 )
u0 = 0;
else
p0 = f;
}
return x0 ? x0->len
: pi ? (ui ? pi->len : NOENUM)
: p0 && u0 ? p0->len : NOENUM;
}
Fdt* fFree ( Fdt *fdt ) {
Fd *F, *E;
if (fdt) {
if (fdt->fd) {
for (E = (F = fdt->fd) + fdt->len; --E >= F; ) {
fFreeFd (E);
}
mFree (fdt->fd);
}
if (fdt->rec) {
mFree (fdt->rec);
}
mFree (fdt);
}
return 0;
}
Fdt* fFromFile (char *path) {
FILE *fp;
char *line;
Fdt *res;
Fd *fd;
Rec *rec;
int len, err;
/* ldb::setext */
len = strlen (path) - 4;
memcpy (path + len, FDF_EXT, 4);
if ( 'A'<=path[len-1] && path[len-1]<= 'Z' ) {
char *p = path + len;
for ( ;*p; p++ ) /* use uppercase extensions */
if ( 'a' <= *p && *p <= 'z' )
*p -= 'a'-'A';
}
fp = fopen (path, "r");
if (! fp) {
sMsg (LOG_INFO | ERR_BADF, "no such fdt: %s", path);
return 0;
}
res = mAlloc (sizeof(Fdt));
if (! res) {
fclose (fp);
sMsg (ERR_NOMEM, "fFromFile");
return 0;
}
sMsg (LOG_VERBOSE, "> reading fdt: %s", path);
fd = 0;
rec = 0;
err = len = 0;
while ((line = fFileGets (fp))) {
if ('*' == *line) {
continue;
}
if (':' == line[1]) {
if (-ERR_NOMEM == (err = fLine2Tool (line, &rec))) {
break;
}
continue;
}
if (-ERR_NOMEM == (err = fLine2Fd (line, &fd, &len))) {
break;
}
}
fclose (fp);
res->fd = fd;
res->rec = rec;
res->len = len;
if (-ERR_NOMEM == err) {
return fFree (res);
}
sMsg (LOG_VERBOSE, "< %d entries in fdt", len);
return res;
}
#define ADDFDS(tag,val) \
RADDS (rec, tag, val, !0); \
if (! rec) { return 0; }
Rec* fFd2Rec (const Fd *fd, Rec *rec, int embchld) {
char buf[16];
Fd **E, **F;
Rec *child;
if (! fd) {
return rec;
}
i2a (buf, fd->id);
ADDFDS (OPENISIS_FDID, buf);
if ((*buf = fd->subf)) {
buf[1] = 0;
ADDFDS (OPENISIS_FDSUB, buf);
}
i2a (buf, fd->type);
ADDFDS (OPENISIS_FDTYPE, buf);
i2a (buf, fd->rep);
ADDFDS (OPENISIS_FDREP, buf);
i2a (buf, fd->len);
ADDFDS (OPENISIS_FDLEN, buf);
ADDFDS (OPENISIS_FDNAME, fd->name);
ADDFDS (OPENISIS_FDDESC, fd->desc);
if (fd->pat) {
ADDFDS (OPENISIS_FDPAT, fd->pat);
}
if (fd->dflt) {
ADDFDS (OPENISIS_FDDFLT, fd->dflt);
}
if (fd->info) {
rec = luti_wrap (rec, fd->info, OPENISIS_FDINFO);
if (! rec) {
return 0;
}
}
if (embchld && fd->slen) {
for (E = (F = fd->subs) + fd->slen; rec && F < E; ++F) {
child = fFd2Rec (*F, 0, 0);
if (! child) {
return rec;
}
rec = luti_wrap (rec, child, OPENISIS_FDCHLD);
}
if (rec) {
rec = rAddI (rec, OPENISIS_FDNUMC, fd->slen, !0);
}
}
return rec;
}
Rec* fFdt2Rec (const Fdt *fdt, Rec *rec, int embchld) {
Fd *E, *F;
Rec *R;
int len;
if (! fdt) {
return rec;
}
if (fdt->rec) {
rec = luti_wrap (rec, fdt->rec, OPENISIS_FDT_REC);
if (! rec) { return 0; }
}
for (E = (F = fdt->fd) + fdt->len, len = 0; F < E; ++F) {
if (! F->subf || ! embchld) {
R = fFd2Rec (F, 0, embchld);
if (! R) {
return rec;
}
rec = luti_wrap (rec, R, OPENISIS_FDT_FD);
mFree (R);
if (! rec) {
return 0;
}
++len;
}
}
rec = rAddI (rec, OPENISIS_FDT_LEN, len, !0);
return rec;
}
Fd *fRec2Fd (Rec *rec, Fd *buf) {
char name[FD_NAMELEN];
Field *F, *E;
Fd *fd;
int got = 0;
if (! rec) {
return 0;
}
if (! (fd = buf)) {
fd = mAlloc (sizeof(Fd));
if (! fd) {
return 0;
}
}
*name = 0;
for (E = (F = rec->field) + rec->len; F < E; ++F) {
switch (F->tag) {
case OPENISIS_FDID:
got |= 0x01;
fd->id = a2id (F->val, F->len, 0);
break;
case OPENISIS_FDSUB:
if (! (1 == F->len || (2 == F->len && ! F->val[1]))) {
sMsg (ERR_INVAL,
"fRec2Fd: ignoring illegal subfield id (%s)", name);
}
else {
fd->subf = F->val[0];
}
break;
case OPENISIS_FDTYPE:
got |= 0x02;
fd->type = (char) a2id (F->val, F->len, 0);
break;
case OPENISIS_FDREP:
if (! (1 == F->len || (2 == F->len && ! F->val[1]))) {
sMsg (ERR_INVAL,
"fRec2Fd: ignoring illegal repeatable flag (%s)", name);
}
else {
fd->rep = F->val[0] && '0' != F->val[0];
}
break;
case OPENISIS_FDLEN:
fd->len = (short) a2id (F->val, F->len, 0);
break;
case OPENISIS_FDNAME:
got |= 0x04;
if (FD_NAMELEN <= F->len) {
memcpy (name, F->val, FD_NAMELEN - 1);
name[FD_NAMELEN - 1] = 0;
sMsg (ERR_INVAL,
"fRec2Fd: name too long (%d) - truncated to %s",
F->len, name);
}
else {
memcpy (name, F->val, F->len);
name[F->len] = 0;
}
if (! *fd->desc) {
strcpy (fd->desc, name);
}
fDesc2Name (name, fd->name);
if (!*(fd->name)) {
sMsg (ERR_INVAL,
"fRec2Fd: illegal name (%s)", name);
got &= ~0x04;
}
break;
case OPENISIS_FDDESC:
if (FD_NAMELEN <= F->len) {
memcpy (fd->desc, F->val, FD_NAMELEN - 1);
fd->desc[FD_NAMELEN - 1] = 0;
sMsg (ERR_INVAL,
"fRec2Fd: descr too long (%d) - truncated to %s (%s)",
F->len, fd->desc, name);
}
else {
memcpy (fd->desc, F->val, F->len);
fd->desc[F->len] = 0;
}
break;
case OPENISIS_FDPAT:
if (fd->pat) {
sMsg (ERR_INVAL,
"fRec2Fd: ignoring multiple occurences of pattern (%s)",
name);
}
else {
fd->pat = (char*) mAlloc (1 + F->len);
if (! fd->pat) {
goto err;
}
memcpy (fd->pat, F->val, F->len);
fd->pat[F->len] = 0;
}
break;
case OPENISIS_FDDFLT:
if (fd->dflt) {
sMsg (ERR_INVAL,
"fRec2Fd: ignoring multiple occurences of dflt (%s)",
name);
}
else {
fd->dflt = (char*) mAlloc (1 + F->len);
if (! fd->dflt) {
goto err;
}
memcpy (fd->dflt, F->val, F->len);
fd->dflt[F->len] = 0;
}
break;
case OPENISIS_FDINFO:
if (fd->info) {
sMsg (ERR_INVAL,
"fRec2Fd: ignoring multiple occurences of info (%s)",
name);
}
else {
int pos = F - rec->field;
fd->info = luti_unwrap (rec, &pos, OPENISIS_FDINFO, -1);
if (! fd->info) {
goto err;
}
F = rec->field + pos - 1;
}
break;
default:
sMsg (ERR_INVAL,
"fRec2Fd: ignoring unexpected tag %d (%s)",
F->tag, name);
}
}
if (0x07 != got) {
sMsg (ERR_TRASH,
"fRec2Fd: incomplete field description [%x] (%s)", got, name);
err:
if (fd->pat) { mFree (fd->pat); }
if (fd->dflt) { mFree (fd->dflt); }
if (fd->info) { mFree (fd->info); }
if (fd != buf) { mFree (fd); }
return 0;
}
return fd;
}
Fdt *fRec2Fdt (Rec *rec) {
Rec *R, *cfg;
Fdt *fdt;
Fd fdbuf;
Fd *F, *arr;
int err, num, len, pos;
if (!rec) {
return 0;
}
num = rInt (rec, OPENISIS_FDT_LEN, 0, 0);
if (0 >= num) {
return 0;
}
arr = (Fd*) mAlloc (num * sizeof (Fd));
if (!arr) {
return 0;
}
fdt = (Fdt*) mAlloc (sizeof(Fdt));
if (! fdt) {
mFree (arr);
return 0;
}
for (F = arr, len = pos = 0; num; --num) {
R = luti_unwrap (rec, &pos, OPENISIS_FDT_FD, -1);
if (!R) {
return fCleanupArr (fdt, arr, len);
}
memset (&fdbuf, 0, sizeof(Fd));
if (fRec2Fd (R, &fdbuf)) {
memcpy (F, &fdbuf, sizeof(Fd));
++len;
++F;
}
mFree (R);
}
if (len != num) {
num = len * sizeof(Fd);
F = (Fd*) mAlloc (num);
if (! F) {
return fCleanupArr (fdt, arr, len);
}
memcpy (F, arr, num);
mFree (arr);
arr = F;
}
cfg = luti_unwrap (rec, 0, OPENISIS_FDT_REC, -1);
fdt->len = len;
fdt->fd = arr;
fdt->rec = cfg;
err = fResolveChilds (arr, len);
if (-ERR_NOMEM == err) {
return fFree (fdt);
}
return fdt;
}