--- /dev/null
+/*
+ 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;
+}
+