1 |
/* |
2 |
openisis - an open implementation of the CDS/ISIS database |
3 |
Version 0.8.x (patchlevel see file Version) |
4 |
Copyright (C) 2001-2003 by Erik Grziwotz, erik@openisis.org |
5 |
|
6 |
This library is free software; you can redistribute it and/or |
7 |
modify it under the terms of the GNU Lesser General Public |
8 |
License as published by the Free Software Foundation; either |
9 |
version 2.1 of the License, or (at your option) any later version. |
10 |
|
11 |
This library is distributed in the hope that it will be useful, |
12 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 |
Lesser General Public License for more details. |
15 |
|
16 |
You should have received a copy of the GNU Lesser General Public |
17 |
License along with this library; if not, write to the Free Software |
18 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 |
|
20 |
see README for more information |
21 |
EOH */ |
22 |
|
23 |
/* |
24 |
$Id: lfdt.c,v 1.25 2003/06/15 15:57:43 mawag Exp $ |
25 |
implementation of FDT calls and static FDTs. |
26 |
*/ |
27 |
|
28 |
#include <limits.h> /* CHAR_MAX,PATH_MAX */ |
29 |
#include <stdio.h> |
30 |
#include <string.h> |
31 |
|
32 |
#include "openisis.h" |
33 |
#include "loi.h" |
34 |
#include "lfdt.h" |
35 |
#include "luti.h" |
36 |
|
37 |
#define FDF_EXT ".fdt" |
38 |
#define FDF_NAMLEN 30 |
39 |
#define FDF_PATLEN 20 /* format of *.fdt */ |
40 |
#define FDF_TOOLEN 6 |
41 |
|
42 |
#if FDF_NAMLEN >= FD_NAMELEN |
43 |
fix me |
44 |
#endif |
45 |
|
46 |
/* ************************************************************ |
47 |
private types |
48 |
*/ |
49 |
|
50 |
/* ************************************************************ |
51 |
private data |
52 |
*/ |
53 |
|
54 |
#define _FD_DFLTDB \ |
55 |
{ OPENISIS_SC_DFLTDB, 0, FTX, 0, 0, DBNLEN, "defaultdb", \ |
56 |
"Name of default db", 0, 0, 0, 0 } |
57 |
|
58 |
#define _FD_DPATH \ |
59 |
{ OPENISIS_DPATH, 0, FTX, 0, 0, PATH_MAX, "dbpath", \ |
60 |
"Database Path", 0, 0, 0, 0 } |
61 |
|
62 |
#define _FD_DENC \ |
63 |
{ OPENISIS_DENC, 0, FTX, 0, 0, 32, "encoding", \ |
64 |
"Encoding", 0, 0, 0, 0 } |
65 |
|
66 |
static Fd _fdsys[] = { |
67 |
/* 700 ... OpenIsis system parameters */ |
68 |
{ OPENISIS_SPATH, 0, FTX, 0, 0, PATH_MAX, "syspath", |
69 |
"Global Database Path", 0, 0, 0, 0 }, |
70 |
{ OPENISIS_SLOGF, 0, FTX, 0, 0, PATH_MAX, "logfile", |
71 |
"Logfile Name", 0, 0, 0, 0 }, |
72 |
{ OPENISIS_SLOGV, 0, FTE, 0, 0, 16, "v", |
73 |
"Verbosity of Logging", 0, 0, 0, 0 }, |
74 |
{ OPENISIS_SLOGV, 0, FTV, 0, 0, 0, "off", |
75 |
"don't log anything", 0, 0, 0, 0 }, |
76 |
{ OPENISIS_SLOGV, 0, FTV, 0, 0, 1, "fatal", "", 0, 0, 0, 0 }, |
77 |
{ OPENISIS_SLOGV, 0, FTV, 0, 0, 3, "syserr", "", 0, 0, 0, 0 }, |
78 |
{ OPENISIS_SLOGV, 0, FTV, 0, 0, 4, "error", "", 0, 0, 0, 0 }, |
79 |
{ OPENISIS_SLOGV, 0, FTV, 0, 0, 5, "warn", "", 0, 0, 0, 0 }, |
80 |
{ OPENISIS_SLOGV, 0, FTV, 0, 0, 6, "info", "", 0, 0, 0, 0 }, |
81 |
{ OPENISIS_SLOGV, 0, FTV, 0, 0, 7, "verbose", "", 0, 0, 0, 0 }, |
82 |
{ OPENISIS_SLOGV, 0, FTV, 0, 0, 8, "trace", "", 0, 0, 0, 0 }, |
83 |
{ OPENISIS_SLOGV, 0, FTV, 0, 0, 9, "debug", "", 0, 0, 0, 0 }, |
84 |
{ OPENISIS_SLOGV, 0, FTV, 0, 0, 10, "all", "", 0, 0, 0, 0 }, |
85 |
_FD_DFLTDB, |
86 |
_FD_DPATH, |
87 |
_FD_DENC |
88 |
}; |
89 |
static Fdt _fdtsys = { |
90 |
sizeof (_fdsys) / sizeof (_fdsys[0]), |
91 |
_fdsys, |
92 |
0 |
93 |
}; |
94 |
|
95 |
static Fd _fdsch[] = { |
96 |
{ OPENISIS_SC_NAME, 0, FTX, 0, 0, SCNLEN, "name", |
97 |
"Identification of remote scheme", 0, 0, 0, 0 }, |
98 |
{ OPENISIS_SC_HOST, 0, FTX, 0, 0, 64, "host", |
99 |
"Hostname of remote scheme", 0, 0, 0, 0 }, |
100 |
{ OPENISIS_SC_PORT, 0, FTN, 0, 0, 5, "port", |
101 |
"Port of remote scheme", 0, 0, 0, 0 }, |
102 |
_FD_DFLTDB, |
103 |
_FD_DPATH, |
104 |
_FD_DENC |
105 |
}; |
106 |
static Fdt _fdtsch = { |
107 |
sizeof (_fdsch) / sizeof (_fdsch[0]), |
108 |
_fdsch, |
109 |
0 |
110 |
}; |
111 |
|
112 |
static Fd _fddb[] = { |
113 |
{ OPENISIS_DNAME, 0, FTX, 0, 0, DBNLEN, "db", |
114 |
"Identification of database", 0, 0, 0, 0 }, |
115 |
{ OPENISIS_DTYPE, 0, FTE, 0, 0, 256, "format", |
116 |
"Database Format", 0, 0, 0, 0 }, |
117 |
{ OPENISIS_DTYPE, 0, FTV, 0, 0, 0, "autoformat", |
118 |
"Database Format", 0, 0, 0, 0 }, |
119 |
{ OPENISIS_DTYPE, 0, FTV, 0, 0, 1, "naligned", |
120 |
"Database Format", 0, 0, 0, 0 }, |
121 |
{ OPENISIS_DTYPE, 0, FTV, 0, 0, 2, "aligned", |
122 |
"Database Format", 0, 0, 0, 0 }, |
123 |
{ OPENISIS_DRO , 0, FTB, 0, 0, 1, "ro", |
124 |
"Readonly Flag", 0, 0, 0, 0 }, |
125 |
_FD_DPATH, |
126 |
{ OPENISIS_DDUMP, 0, FTB, 0, 0, 1, "internaldump", |
127 |
"Internal Dump Flag", 0, 0, 0, 0 }, |
128 |
_FD_DENC, |
129 |
{ OPENISIS_DFDT, 0, FTX, 0, 0, 256, "fdt", |
130 |
"Path to fdt", 0, 0, 0, 0 } |
131 |
}; |
132 |
static Fdt _fdtdb = { |
133 |
sizeof (_fddb) / sizeof (_fddb[0]), |
134 |
_fddb, |
135 |
0 |
136 |
}; |
137 |
|
138 |
static Fd _fdfd[] = { |
139 |
{ OPENISIS_FDID, 0, FTN, 0, 0, 10, "tag", |
140 |
"Tag number of field", 0, 0, 0, 0 }, |
141 |
{ OPENISIS_FDSUB, 0, FTX, 0, 0, 1, "subfield", |
142 |
"Subfield", 0, 0, 0, 0 }, |
143 |
{ OPENISIS_FDTYPE, 0, FTE, 0, 0, 2, "type", |
144 |
"Field type", 0, 0, 0, 0 }, |
145 |
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTX, "alphanum", |
146 |
"Field type", 0, 0, 0, 0 }, |
147 |
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTA, "alpha", |
148 |
"Field type", 0, 0, 0, 0 }, |
149 |
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTN, "numeric", |
150 |
"Field type", 0, 0, 0, 0 }, |
151 |
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTP, "pattern", |
152 |
"Field type", 0, 0, 0, 0 }, |
153 |
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTI, "iso", |
154 |
"Field type", 0, 0, 0, 0 }, |
155 |
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTE, "enum", |
156 |
"Field type", 0, 0, 0, 0 }, |
157 |
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTB, "boolean", |
158 |
"Field type", 0, 0, 0, 0 }, |
159 |
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTT, "table", |
160 |
"Field type", 0, 0, 0, 0 }, |
161 |
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTS, "structure", |
162 |
"Field type", 0, 0, 0, 0 }, |
163 |
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTF | FTX, "subalphanum", |
164 |
"Subfield type", 0, 0, 0, 0 }, |
165 |
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTF | FTA, "subalpha", |
166 |
"Subfield type", 0, 0, 0, 0 }, |
167 |
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTF | FTN, "subnumeric", |
168 |
"Subfield type", 0, 0, 0, 0 }, |
169 |
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTF | FTP, "subpattern", |
170 |
"Subfield type", 0, 0, 0, 0 }, |
171 |
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTF | FTI, "subiso", |
172 |
"Subfield type", 0, 0, 0, 0 }, |
173 |
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTF | FTE, "subenum", |
174 |
"Subfield type", 0, 0, 0, 0 }, |
175 |
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTF | FTB, "subbool", |
176 |
"Subfield type", 0, 0, 0, 0 }, |
177 |
{ OPENISIS_FDTYPE, 0, FTV, 0, 0, FTV, "enum value", |
178 |
"Enumeration value", 0, 0, 0, 0 }, |
179 |
{ OPENISIS_FDREP, 0, FTB, 0, 0, 1, "repeatable", |
180 |
"Repeatable flag", 0, 0, 0, 0 }, |
181 |
{ OPENISIS_FDNUMC, 0, FTN, 0, 0, 2, "numchilds", |
182 |
"Number of subfield childs", 0, 0, 0, 0 }, |
183 |
{ OPENISIS_FDLEN, 0, FTN, 0, 0, 10, "length", |
184 |
"Field length or enum value", 0, 0, 0, 0 }, |
185 |
{ OPENISIS_FDNAME, 0, FTX, 0, 0, 30, "name", |
186 |
"Field name", 0, 0, 0, 0 }, |
187 |
{ OPENISIS_FDDESC, 0, FTX, 0, 0, 31, "description", |
188 |
"Description", 0, 0, 0, 0 }, |
189 |
{ OPENISIS_FDPAT, 0, FTX, 0, 0, 128, "pattern", |
190 |
"Pattern", 0, 0, 0, 0 }, |
191 |
{ OPENISIS_FDDFLT, 0, FTX, 0, 0, 1024, "default", |
192 |
"Default value", 0, 0, 0, 0 }, |
193 |
{ OPENISIS_FDINFO, 0, FTS, 0, 0, 1, "info", |
194 |
"Embedded info record", 0, 0, 0, 0 }, |
195 |
{ OPENISIS_FDCHLD, 0, FTX, 1, 0, 1, "children", |
196 |
"Subfield childs", 0, 0, 0, 0 } |
197 |
}; |
198 |
static Fdt _fdtfd = { |
199 |
sizeof (_fdfd) / sizeof (_fdfd[0]), |
200 |
_fdfd, |
201 |
0 |
202 |
}; |
203 |
|
204 |
#define _FD_FDT \ |
205 |
{ OPENISIS_FDT_LEN, 0, FTN, 0, 0, 3, "flen", \ |
206 |
"Length of fdt", 0, 0, 0, 0 }, \ |
207 |
{ OPENISIS_FDT_FD, 0, FTS, 1, 0, 1, "fd", \ |
208 |
"Field description", 0, 0, 0, 0 }, \ |
209 |
{ OPENISIS_FDT_REC, 0, FTS, 0, 0, 1, "frec", \ |
210 |
"Embedded info record", 0, 0, 0, 0 } |
211 |
|
212 |
static Fd _fdfdt[] = { |
213 |
_FD_FDT |
214 |
}; |
215 |
static Fdt _fdtfdt = { |
216 |
sizeof (_fdfdt) / sizeof (_fdfdt[0]), |
217 |
_fdfdt, |
218 |
0 |
219 |
}; |
220 |
|
221 |
#define _FD_COM \ |
222 |
{ OPENISIS_COM_SID, 0, FTN, 0, 0, 2, "sid", \ |
223 |
"Client Session Id", 0, 0, 0, 0 }, \ |
224 |
{ OPENISIS_COM_SER, 0, FTN, 0, 0, 5, "ser", \ |
225 |
"Request Serial No.", 0, 0, 0, 0 }, \ |
226 |
{ OPENISIS_COM_DBN, 0, FTX, 0, 0, DBNLEN, "db", \ |
227 |
"DB Identification", 0, 0, 0, 0 }, \ |
228 |
{ OPENISIS_COM_TMS, 0, FTN, 0, 0, 10, "tms", \ |
229 |
"Server Db Timestamp", 0, 0, 0, 0 }, \ |
230 |
{ OPENISIS_COM_ROW, 0, FTN, 0, 0, 10, "rowid", \ |
231 |
"RowId", 0, 0, 0, 0 }, \ |
232 |
_FD_FDT, \ |
233 |
{ OPENISIS_COM_CFG, 0, FTS, 0, 0, 0, "config", \ |
234 |
"Config", 0, 0, 0, 0 }, \ |
235 |
{ OPENISIS_COM_REC, 0, FTS, 1, 0, 0, "rec", \ |
236 |
"Data", 0, 0, 0, 0 } |
237 |
|
238 |
static Fd _fdrqs[] = { |
239 |
_FD_COM, |
240 |
{ OPENISIS_RQS_TYPE, 0, FTE, 0, 0, 32, "type", |
241 |
"Request type", 0, 0, 0, 0 }, |
242 |
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_OPEN, "open", |
243 |
"open db", 0, 0, 0, 0 }, |
244 |
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_CLOS, "close", |
245 |
"close db", 0, 0, 0, 0 }, |
246 |
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_MNT, "mount", |
247 |
"mount db", 0, 0, 0, 0 }, |
248 |
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_LSDB, "ls", |
249 |
"list dbs", 0, 0, 0, 0 }, |
250 |
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_MROW, "maxrow", |
251 |
"get maxrowid", 0, 0, 0, 0 }, |
252 |
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_QRY, "query", |
253 |
"exec query", 0, 0, 0, 0 }, |
254 |
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_READ, "read", |
255 |
"fetch row", 0, 0, 0, 0 }, |
256 |
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_INS, "insert", |
257 |
"insert rec", 0, 0, 0, 0 }, |
258 |
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_UPD, "update", |
259 |
"update rec", 0, 0, 0, 0 }, |
260 |
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_DEL, "delete", |
261 |
"delete row", 0, 0, 0, 0 }, |
262 |
{ OPENISIS_RQS_TYPE, 0, FTV, 0, 0, OPENISIS_RQST_EVAL, "eval", |
263 |
"evaluate command", 0, 0, 0, 0 }, |
264 |
{ OPENISIS_RQS_FLG, 0, FTN, 0, 0, 4, "flags", |
265 |
"Request flags", 0, 0, 0, 0 }, |
266 |
{ OPENISIS_RQS_QMOD, 0, FTN, 0, 0, 5, "mode", |
267 |
"Query Mode", 0, 0, 0, 0 }, |
268 |
{ OPENISIS_RQS_SKIP, 0, FTN, 0, 0, 5, "skip", |
269 |
"Query Skip", 0, 0, 0, 0 }, |
270 |
{ OPENISIS_RQS_SIZE, 0, FTN, 0, 0, 5, "size", |
271 |
"Result Length", 0, 0, 0, 0 }, |
272 |
{ OPENISIS_RQS_KEY, 0, FTX, 0, 0, OPENISIS_QRY_KEYLEN, "key", |
273 |
"Query Key", 0, 0, 0, 0 }, |
274 |
{ OPENISIS_RQS_IDX, 0, FTS, 0, 0, 0, "idx", |
275 |
"Index to Update", 0, 0, 0, 0 } |
276 |
}; |
277 |
static Fdt _fdtrqs = { |
278 |
sizeof (_fdrqs) / sizeof (_fdrqs[0]), |
279 |
_fdrqs, |
280 |
0 |
281 |
}; |
282 |
|
283 |
static Fd _fdrsp[] = { |
284 |
_FD_COM, |
285 |
{ OPENISIS_RSP_DBID, 0, FTN, 0, 0, 2, "dbid", |
286 |
"Id of local db", 0, 0, 0, 0 }, |
287 |
{ OPENISIS_RSP_ERR, 0, FTN, 0, 0, 5, "error", |
288 |
"Error Code", 0, 0, 0, 0 }, |
289 |
{ OPENISIS_RSP_MSG, 0, FTX, 0, 0, OPENISIS_ERRMSGLEN, "msg", |
290 |
"Error Message", 0, 0, 0, 0 }, |
291 |
{ OPENISIS_RSP_NUMT, 0, FTN, 0, 0, 5, "total", |
292 |
"Total No. of Records", 0, 0, 0, 0 }, |
293 |
{ OPENISIS_RSP_NUMR, 0, FTN, 0, 0, 5, "size", |
294 |
"Number of Records", 0, 0, 0, 0 }, |
295 |
{ OPENISIS_RSP_CERR, 0, FTN, 0, 0, 5, "error2", |
296 |
"Client Side Error", 0, 0, 0, 0 } |
297 |
}; |
298 |
static Fdt _fdtrsp = { |
299 |
sizeof (_fdrsp) / sizeof (_fdrsp[0]), |
300 |
_fdrsp, |
301 |
0 |
302 |
}; |
303 |
|
304 |
/* ************************************************************ |
305 |
public data |
306 |
*/ |
307 |
|
308 |
const Fdt *openIsisFdtSyspar = &_fdtsys; |
309 |
const Fdt *openIsisFdtScheme = &_fdtsch; |
310 |
const Fdt *openIsisFdtDbpar = &_fdtdb; |
311 |
const Fdt *openIsisFdtFd = &_fdtfd; |
312 |
const Fdt *openIsisFdtFdt = &_fdtfdt; |
313 |
const Fdt *openIsisFdtRqs = &_fdtrqs; |
314 |
const Fdt *openIsisFdtRsp = &_fdtrsp; |
315 |
|
316 |
|
317 |
/* ************************************************************ |
318 |
private functions |
319 |
*/ |
320 |
|
321 |
static char *fFileGets (FILE *fp) { |
322 |
static char buf[4096]; |
323 |
char *res; |
324 |
int len; |
325 |
while (1) { |
326 |
nxtl: |
327 |
if (0 == (res = fgets (buf, sizeof(buf) - 1, fp))) { |
328 |
break; |
329 |
} |
330 |
buf[sizeof(buf) - 1] = 0; |
331 |
if (!(len = strlen (res))) { |
332 |
continue; |
333 |
} |
334 |
--len; |
335 |
while (0 <= len) { |
336 |
if ('\n' != res[len] && '\r' != res[len]) { |
337 |
break; |
338 |
} |
339 |
res[len] = 0; |
340 |
if (0 > --len) { |
341 |
goto nxtl; |
342 |
} |
343 |
} |
344 |
break; |
345 |
} |
346 |
return res; |
347 |
} |
348 |
|
349 |
static void strrtrim (char *str) { |
350 |
char *p = str + strlen (str) - 1; |
351 |
while (p >= str && (' ' == *p || '\t' == *p)) { |
352 |
*p-- = 0; |
353 |
} |
354 |
} |
355 |
|
356 |
static void fDesc2Name (char *d, char *n) { |
357 |
while (1) { |
358 |
if (!(*n = *d)) { |
359 |
return; |
360 |
} |
361 |
if ('A' <= *n && 'Z' >= *n) { |
362 |
*n += 'a' - 'A'; |
363 |
++n; |
364 |
++d; |
365 |
continue; |
366 |
} |
367 |
if ('_' == *n || |
368 |
('a' <= *n && 'z' >= *n) || |
369 |
('0' <= *n && '9' >= *n)) { |
370 |
++n; |
371 |
++d; |
372 |
continue; |
373 |
} |
374 |
while (1) { |
375 |
++d; |
376 |
if (!*d) { |
377 |
*n = 0; |
378 |
return; |
379 |
} |
380 |
if (('A' <= *d && 'Z' >= *d) || |
381 |
('a' <= *d && 'z' >= *d) || |
382 |
('0' <= *d && '9' >= *d)) { |
383 |
break; |
384 |
} |
385 |
} |
386 |
*n++ = '_'; |
387 |
} |
388 |
} |
389 |
|
390 |
static int fLine2Fd (char *line, Fd **fd, int *num) { |
391 |
char name[FD_NAMELEN]; |
392 |
char pat[1 + FDF_PATLEN]; |
393 |
Fd buff, bufs; |
394 |
char *P; |
395 |
char *L = line; |
396 |
int tag, len, typ, rep, idx; |
397 |
if (FDF_NAMLEN + FDF_PATLEN >= strlen (L)) { |
398 |
return sMsg (ERR_INVAL, "fFileFd: illegal line <%s>", line); |
399 |
} |
400 |
strncpy (name, L, FDF_NAMLEN) [FDF_NAMLEN] = 0; |
401 |
strrtrim (name); |
402 |
if (! *name) { |
403 |
return sMsg (ERR_INVAL, "fFileFd: no descr in line <%s>", line); |
404 |
} |
405 |
L += FDF_NAMLEN; |
406 |
strncpy (pat, L, FDF_PATLEN) [FDF_PATLEN] = 0; |
407 |
strrtrim (pat); |
408 |
L += FDF_PATLEN; |
409 |
if (4 != sscanf (L, "%d %d %d %d", &tag, &len, &typ, &rep)) { |
410 |
return sMsg (ERR_INVAL, "fFileFd: no type in line <%s>", line); |
411 |
} |
412 |
switch (typ) { |
413 |
case 0: typ = FTX; break; |
414 |
case 1: typ = FTA; break; |
415 |
case 2: typ = FTN; break; |
416 |
case 3: typ = FTP; break; |
417 |
default: return sMsg (ERR_INVAL, |
418 |
"fFileFd: unrecognized type %d in line <%s>", typ, line); |
419 |
} |
420 |
memset (&buff, 0, sizeof (Fd)); |
421 |
buff.id = tag; |
422 |
buff.type = typ; |
423 |
buff.rep = 0 != rep; |
424 |
buff.len = len; |
425 |
strcpy (buff.desc, name); |
426 |
fDesc2Name (name, buff.name); |
427 |
if (! *buff.name) { |
428 |
return sMsg (ERR_INVAL, "fFileFd: illegal name in line <%s>", line); |
429 |
} |
430 |
if (FTP == typ) { |
431 |
if (! *pat) { |
432 |
return sMsg (ERR_INVAL, "fFileFd: illegal pat in line <%s>", line); |
433 |
} |
434 |
buff.pat = mDup (pat, -1); |
435 |
if (! buff.pat) { |
436 |
return sMsg (ERR_NOMEM, "fFileFd: cannot allocate pat"); |
437 |
} |
438 |
} |
439 |
idx = luti_ptrincr (fd, num, 1, sizeof(Fd), -1); |
440 |
if (0 > idx) { |
441 |
return sMsg (ERR_NOMEM, |
442 |
"fFileFd: cannot extend fd array %d", *num); |
443 |
} |
444 |
memcpy (*fd + idx, &buff, sizeof(Fd)); |
445 |
if (FTP != typ) { |
446 |
for (P = pat; *P; ++P) { |
447 |
memcpy (&bufs, &buff, sizeof(Fd)); |
448 |
bufs.subf = *P; |
449 |
bufs.type = FTX; |
450 |
idx = luti_ptrincr (fd, num, 1, sizeof(Fd), -1); |
451 |
if (0 > idx) { |
452 |
return sMsg (ERR_NOMEM, |
453 |
"fFileFd: cannot extend fd array %d", *num); |
454 |
} |
455 |
memcpy (*fd + idx, &bufs, sizeof(Fd)); |
456 |
} |
457 |
} |
458 |
return 0; |
459 |
} |
460 |
|
461 |
static int fLine2Tool (char *line, Rec **rec) { |
462 |
char tool[1 + FDF_TOOLEN]; |
463 |
char *L = line; |
464 |
int len, typ; |
465 |
switch (*L) { |
466 |
case 'w': |
467 |
case 'W': |
468 |
typ = OPENISIS_DFMT; |
469 |
break; |
470 |
case 'f': |
471 |
case 'F': |
472 |
typ = OPENISIS_DPFT; |
473 |
break; |
474 |
case 's': |
475 |
case 'S': |
476 |
typ = OPENISIS_DFST; |
477 |
break; |
478 |
default: |
479 |
return sMsg (ERR_INVAL, "fLine2Tool: illegal line <%s>", line); |
480 |
} |
481 |
L += 2; |
482 |
len = strlen (L); |
483 |
while (0 < len) { |
484 |
strncpy (tool, L, FDF_TOOLEN) [FDF_TOOLEN] = 0; |
485 |
strrtrim (tool); |
486 |
RADDS (*rec, typ, tool, !0); |
487 |
if (! *rec) { |
488 |
return sMsg (ERR_NOMEM, "fLine2Tool: cannot extend rec"); |
489 |
} |
490 |
L += FDF_TOOLEN; |
491 |
len -= FDF_TOOLEN; |
492 |
} |
493 |
return 0; |
494 |
} |
495 |
|
496 |
static int fResolveChilds (Fd *fd, int len) { |
497 |
char msg[256] = { 0 }; |
498 |
Fd *buf[CHAR_MAX]; |
499 |
Fd **C; |
500 |
Fd *F, *G; |
501 |
int numc; |
502 |
int err = 0; |
503 |
for (F = fd + len; --F >= fd; ) { |
504 |
if (! F->subf) { |
505 |
numc = 0; |
506 |
C = buf; |
507 |
for (G = fd + len; --G >= fd; ) { |
508 |
if (G->subf && (! G->id || G->id == F->id)) { |
509 |
if (CHAR_MAX == numc) { |
510 |
err = ERR_INVAL; |
511 |
sprintf (msg, |
512 |
"fResolveChilds: too many childs for %s", |
513 |
F->name); |
514 |
break; |
515 |
} |
516 |
*C++ = G; |
517 |
++numc; |
518 |
} |
519 |
} |
520 |
if (numc) { |
521 |
C = mAlloc (numc * sizeof(Fd)); |
522 |
if (! C) { |
523 |
return sMsg (ERR_NOMEM, "fResolveChilds"); |
524 |
} |
525 |
F->subs = (Fd**) memcpy (C, buf, numc * sizeof(Fd)); |
526 |
F->slen = numc; |
527 |
} |
528 |
} |
529 |
} |
530 |
if (err) { |
531 |
return sMsg (err, msg); |
532 |
} |
533 |
return 0; |
534 |
} |
535 |
|
536 |
static void fFreeFd (Fd *fd) { |
537 |
if (fd) { |
538 |
if (fd->pat) { |
539 |
mFree (fd->pat); |
540 |
} |
541 |
if (fd->dflt) { |
542 |
mFree (fd->dflt); |
543 |
} |
544 |
if (fd->info) { |
545 |
mFree (fd->info); |
546 |
} |
547 |
if (fd->subs) { |
548 |
mFree (fd->subs); |
549 |
} |
550 |
} |
551 |
} |
552 |
|
553 |
static Fdt* fCleanupArr (Fdt *fdt, Fd *arr, int len) { |
554 |
Fd *F; |
555 |
for (F = arr + len; --F >= arr; ) { |
556 |
fFreeFd (F); |
557 |
} |
558 |
mFree (arr); |
559 |
mFree (fdt); |
560 |
return 0; |
561 |
} |
562 |
|
563 |
/* ************************************************************ |
564 |
package functions |
565 |
*/ |
566 |
|
567 |
/* ************************************************************ |
568 |
public functions |
569 |
*/ |
570 |
|
571 |
Fd* fById ( const Fdt *fdt, int id, int subf ) |
572 |
{ |
573 |
Fd *f, *e; |
574 |
if (! fdt) { |
575 |
return 0; |
576 |
} |
577 |
for (e = (f = fdt->fd) + fdt->len; --e >= f; ) { |
578 |
if (id == e->id && subf == e->subf && ! (0xf0 & e->type)) { |
579 |
return e; |
580 |
} |
581 |
} |
582 |
return 0; |
583 |
} |
584 |
|
585 |
Fd* fByName ( const Fdt *fdt, const char *name ) |
586 |
{ |
587 |
Fd *f, *e, *g; |
588 |
const char *p; |
589 |
int l, cnt; |
590 |
if (! fdt || ! name) { |
591 |
return 0; |
592 |
} |
593 |
f = fdt->fd; |
594 |
e = f + fdt->len; |
595 |
if ( '-' == *name ) /* ignore leading dash */ |
596 |
name++; |
597 |
if (! *name) { |
598 |
return 0; |
599 |
} |
600 |
if ( '0' <= *name && *name <= '9' ) |
601 |
return fById( fdt, a2i( name, -1 ), 0 ); |
602 |
p = name; |
603 |
while ( 'a' <= *p ? *p <= 'z' : '9' >= *p ? *p >= '0' : '_' == *p ) |
604 |
p++; |
605 |
l = p - name; |
606 |
if ( ! l || l > FD_NAMELEN - 1 ) |
607 |
return 0; |
608 |
for ( cnt = 0, g = 0; f < e; f++ ) { |
609 |
if ( *name == *f->name |
610 |
&& !(0xf0 & f->type) /* is field */ |
611 |
&& !memcmp( name, f->name, l ) ) { |
612 |
if (!f->name[l]) { |
613 |
return f; |
614 |
} |
615 |
g = f; |
616 |
++cnt; |
617 |
} |
618 |
} |
619 |
return 1 == cnt ? g : 0; |
620 |
} |
621 |
|
622 |
/** |
623 |
lookup enum: |
624 |
if name is numeric, the value is returned, if legal |
625 |
considered are value entries with given id or id 0 |
626 |
- if there is an exact match with same id, this is used |
627 |
- if there is an exact match with id 0, this is used |
628 |
- if name is a unique prefix on given id, this is used |
629 |
- if name is no prefix on given id, but a unique prefix on 0, this is used |
630 |
*/ |
631 |
int fEnum ( Fdt *fdt, int id, const char *name ) |
632 |
{ |
633 |
Fd *f = fdt->fd, *e = f + fdt->len, |
634 |
*x0 = 0, *pi = 0, *p0 = 0; |
635 |
int ui = 1, u0 = 1; /* unique */ |
636 |
int l = strlen( name ); |
637 |
if ( ! l || l > FD_NAMELEN - 1 ) |
638 |
return NOENUM; |
639 |
if ( ('0' <= *name && *name <= '9') |
640 |
|| ('-' == *name && '0' <= name[1] && name[1] <= '9') |
641 |
) { |
642 |
int v = a2i( name, l ); |
643 |
for ( ; f < e; f++ ) { |
644 |
if ( FTV == f->type && v == f->len && (f->id == id || !f->id) ) |
645 |
return v; |
646 |
} |
647 |
return NOENUM; |
648 |
} |
649 |
for ( ; f < e; f++ ) { |
650 |
if ( FTV != f->type |
651 |
|| *name != *f->name |
652 |
|| memcmp( name, f->name, l ) |
653 |
|| (f->id && f->id != id) |
654 |
) |
655 |
continue; |
656 |
if ( !f->name[l] ) { /* exact match */ |
657 |
if ( f->id == id ) |
658 |
return f->len; |
659 |
x0 = f; /* f->id is 0 */ |
660 |
continue; |
661 |
} |
662 |
/* prefix match */ |
663 |
if ( f->id == id ) { |
664 |
if ( pi ) |
665 |
ui = 0; |
666 |
else |
667 |
pi = f; |
668 |
} else |
669 |
if ( p0 ) |
670 |
u0 = 0; |
671 |
else |
672 |
p0 = f; |
673 |
} |
674 |
return x0 ? x0->len |
675 |
: pi ? (ui ? pi->len : NOENUM) |
676 |
: p0 && u0 ? p0->len : NOENUM; |
677 |
} |
678 |
|
679 |
Fdt* fFree ( Fdt *fdt ) { |
680 |
Fd *F, *E; |
681 |
if (fdt) { |
682 |
if (fdt->fd) { |
683 |
for (E = (F = fdt->fd) + fdt->len; --E >= F; ) { |
684 |
fFreeFd (E); |
685 |
} |
686 |
mFree (fdt->fd); |
687 |
} |
688 |
if (fdt->rec) { |
689 |
mFree (fdt->rec); |
690 |
} |
691 |
mFree (fdt); |
692 |
} |
693 |
return 0; |
694 |
} |
695 |
|
696 |
Fdt* fFromFile (char *path) { |
697 |
FILE *fp; |
698 |
char *line; |
699 |
Fdt *res; |
700 |
Fd *fd; |
701 |
Rec *rec; |
702 |
int len, err; |
703 |
|
704 |
/* ldb::setext */ |
705 |
len = strlen (path) - 4; |
706 |
memcpy (path + len, FDF_EXT, 4); |
707 |
if ( 'A'<=path[len-1] && path[len-1]<= 'Z' ) { |
708 |
char *p = path + len; |
709 |
for ( ;*p; p++ ) /* use uppercase extensions */ |
710 |
if ( 'a' <= *p && *p <= 'z' ) |
711 |
*p -= 'a'-'A'; |
712 |
} |
713 |
|
714 |
fp = fopen (path, "r"); |
715 |
if (! fp) { |
716 |
sMsg (LOG_INFO | ERR_BADF, "no such fdt: %s", path); |
717 |
return 0; |
718 |
} |
719 |
res = mAlloc (sizeof(Fdt)); |
720 |
if (! res) { |
721 |
fclose (fp); |
722 |
sMsg (ERR_NOMEM, "fFromFile"); |
723 |
return 0; |
724 |
} |
725 |
sMsg (LOG_VERBOSE, "> reading fdt: %s", path); |
726 |
|
727 |
fd = 0; |
728 |
rec = 0; |
729 |
err = len = 0; |
730 |
while ((line = fFileGets (fp))) { |
731 |
if ('*' == *line) { |
732 |
continue; |
733 |
} |
734 |
if (':' == line[1]) { |
735 |
if (-ERR_NOMEM == (err = fLine2Tool (line, &rec))) { |
736 |
break; |
737 |
} |
738 |
continue; |
739 |
} |
740 |
if (-ERR_NOMEM == (err = fLine2Fd (line, &fd, &len))) { |
741 |
break; |
742 |
} |
743 |
} |
744 |
|
745 |
fclose (fp); |
746 |
res->fd = fd; |
747 |
res->rec = rec; |
748 |
res->len = len; |
749 |
|
750 |
if (-ERR_NOMEM == err) { |
751 |
return fFree (res); |
752 |
} |
753 |
|
754 |
sMsg (LOG_VERBOSE, "< %d entries in fdt", len); |
755 |
return res; |
756 |
} |
757 |
|
758 |
#define ADDFDS(tag,val) \ |
759 |
RADDS (rec, tag, val, !0); \ |
760 |
if (! rec) { return 0; } |
761 |
|
762 |
Rec* fFd2Rec (const Fd *fd, Rec *rec, int embchld) { |
763 |
char buf[16]; |
764 |
Fd **E, **F; |
765 |
Rec *child; |
766 |
if (! fd) { |
767 |
return rec; |
768 |
} |
769 |
i2a (buf, fd->id); |
770 |
ADDFDS (OPENISIS_FDID, buf); |
771 |
if ((*buf = fd->subf)) { |
772 |
buf[1] = 0; |
773 |
ADDFDS (OPENISIS_FDSUB, buf); |
774 |
} |
775 |
i2a (buf, fd->type); |
776 |
ADDFDS (OPENISIS_FDTYPE, buf); |
777 |
i2a (buf, fd->rep); |
778 |
ADDFDS (OPENISIS_FDREP, buf); |
779 |
i2a (buf, fd->len); |
780 |
ADDFDS (OPENISIS_FDLEN, buf); |
781 |
ADDFDS (OPENISIS_FDNAME, fd->name); |
782 |
ADDFDS (OPENISIS_FDDESC, fd->desc); |
783 |
if (fd->pat) { |
784 |
ADDFDS (OPENISIS_FDPAT, fd->pat); |
785 |
} |
786 |
if (fd->dflt) { |
787 |
ADDFDS (OPENISIS_FDDFLT, fd->dflt); |
788 |
} |
789 |
if (fd->info) { |
790 |
rec = luti_wrap (rec, fd->info, OPENISIS_FDINFO); |
791 |
if (! rec) { |
792 |
return 0; |
793 |
} |
794 |
} |
795 |
if (embchld && fd->slen) { |
796 |
for (E = (F = fd->subs) + fd->slen; rec && F < E; ++F) { |
797 |
child = fFd2Rec (*F, 0, 0); |
798 |
if (! child) { |
799 |
return rec; |
800 |
} |
801 |
rec = luti_wrap (rec, child, OPENISIS_FDCHLD); |
802 |
} |
803 |
if (rec) { |
804 |
rec = rAddI (rec, OPENISIS_FDNUMC, fd->slen, !0); |
805 |
} |
806 |
} |
807 |
return rec; |
808 |
} |
809 |
|
810 |
Rec* fFdt2Rec (const Fdt *fdt, Rec *rec, int embchld) { |
811 |
Fd *E, *F; |
812 |
Rec *R; |
813 |
int len; |
814 |
if (! fdt) { |
815 |
return rec; |
816 |
} |
817 |
if (fdt->rec) { |
818 |
rec = luti_wrap (rec, fdt->rec, OPENISIS_FDT_REC); |
819 |
if (! rec) { return 0; } |
820 |
} |
821 |
for (E = (F = fdt->fd) + fdt->len, len = 0; F < E; ++F) { |
822 |
if (! F->subf || ! embchld) { |
823 |
R = fFd2Rec (F, 0, embchld); |
824 |
if (! R) { |
825 |
return rec; |
826 |
} |
827 |
rec = luti_wrap (rec, R, OPENISIS_FDT_FD); |
828 |
mFree (R); |
829 |
if (! rec) { |
830 |
return 0; |
831 |
} |
832 |
++len; |
833 |
} |
834 |
} |
835 |
rec = rAddI (rec, OPENISIS_FDT_LEN, len, !0); |
836 |
return rec; |
837 |
} |
838 |
|
839 |
Fd *fRec2Fd (Rec *rec, Fd *buf) { |
840 |
char name[FD_NAMELEN]; |
841 |
Field *F, *E; |
842 |
Fd *fd; |
843 |
int got = 0; |
844 |
if (! rec) { |
845 |
return 0; |
846 |
} |
847 |
if (! (fd = buf)) { |
848 |
fd = mAlloc (sizeof(Fd)); |
849 |
if (! fd) { |
850 |
return 0; |
851 |
} |
852 |
} |
853 |
*name = 0; |
854 |
for (E = (F = rec->field) + rec->len; F < E; ++F) { |
855 |
switch (F->tag) { |
856 |
case OPENISIS_FDID: |
857 |
got |= 0x01; |
858 |
fd->id = a2id (F->val, F->len, 0); |
859 |
break; |
860 |
case OPENISIS_FDSUB: |
861 |
if (! (1 == F->len || (2 == F->len && ! F->val[1]))) { |
862 |
sMsg (ERR_INVAL, |
863 |
"fRec2Fd: ignoring illegal subfield id (%s)", name); |
864 |
} |
865 |
else { |
866 |
fd->subf = F->val[0]; |
867 |
} |
868 |
break; |
869 |
case OPENISIS_FDTYPE: |
870 |
got |= 0x02; |
871 |
fd->type = (char) a2id (F->val, F->len, 0); |
872 |
break; |
873 |
case OPENISIS_FDREP: |
874 |
if (! (1 == F->len || (2 == F->len && ! F->val[1]))) { |
875 |
sMsg (ERR_INVAL, |
876 |
"fRec2Fd: ignoring illegal repeatable flag (%s)", name); |
877 |
} |
878 |
else { |
879 |
fd->rep = F->val[0] && '0' != F->val[0]; |
880 |
} |
881 |
break; |
882 |
case OPENISIS_FDLEN: |
883 |
fd->len = (short) a2id (F->val, F->len, 0); |
884 |
break; |
885 |
case OPENISIS_FDNAME: |
886 |
got |= 0x04; |
887 |
if (FD_NAMELEN <= F->len) { |
888 |
memcpy (name, F->val, FD_NAMELEN - 1); |
889 |
name[FD_NAMELEN - 1] = 0; |
890 |
sMsg (ERR_INVAL, |
891 |
"fRec2Fd: name too long (%d) - truncated to %s", |
892 |
F->len, name); |
893 |
} |
894 |
else { |
895 |
memcpy (name, F->val, F->len); |
896 |
name[F->len] = 0; |
897 |
} |
898 |
if (! *fd->desc) { |
899 |
strcpy (fd->desc, name); |
900 |
} |
901 |
fDesc2Name (name, fd->name); |
902 |
if (!*(fd->name)) { |
903 |
sMsg (ERR_INVAL, |
904 |
"fRec2Fd: illegal name (%s)", name); |
905 |
got &= ~0x04; |
906 |
} |
907 |
break; |
908 |
case OPENISIS_FDDESC: |
909 |
if (FD_NAMELEN <= F->len) { |
910 |
memcpy (fd->desc, F->val, FD_NAMELEN - 1); |
911 |
fd->desc[FD_NAMELEN - 1] = 0; |
912 |
sMsg (ERR_INVAL, |
913 |
"fRec2Fd: descr too long (%d) - truncated to %s (%s)", |
914 |
F->len, fd->desc, name); |
915 |
} |
916 |
else { |
917 |
memcpy (fd->desc, F->val, F->len); |
918 |
fd->desc[F->len] = 0; |
919 |
} |
920 |
break; |
921 |
case OPENISIS_FDPAT: |
922 |
if (fd->pat) { |
923 |
sMsg (ERR_INVAL, |
924 |
"fRec2Fd: ignoring multiple occurences of pattern (%s)", |
925 |
name); |
926 |
} |
927 |
else { |
928 |
fd->pat = (char*) mAlloc (1 + F->len); |
929 |
if (! fd->pat) { |
930 |
goto err; |
931 |
} |
932 |
memcpy (fd->pat, F->val, F->len); |
933 |
fd->pat[F->len] = 0; |
934 |
} |
935 |
break; |
936 |
case OPENISIS_FDDFLT: |
937 |
if (fd->dflt) { |
938 |
sMsg (ERR_INVAL, |
939 |
"fRec2Fd: ignoring multiple occurences of dflt (%s)", |
940 |
name); |
941 |
} |
942 |
else { |
943 |
fd->dflt = (char*) mAlloc (1 + F->len); |
944 |
if (! fd->dflt) { |
945 |
goto err; |
946 |
} |
947 |
memcpy (fd->dflt, F->val, F->len); |
948 |
fd->dflt[F->len] = 0; |
949 |
} |
950 |
break; |
951 |
case OPENISIS_FDINFO: |
952 |
if (fd->info) { |
953 |
sMsg (ERR_INVAL, |
954 |
"fRec2Fd: ignoring multiple occurences of info (%s)", |
955 |
name); |
956 |
} |
957 |
else { |
958 |
int pos = F - rec->field; |
959 |
fd->info = luti_unwrap (rec, &pos, OPENISIS_FDINFO, -1); |
960 |
if (! fd->info) { |
961 |
goto err; |
962 |
} |
963 |
F = rec->field + pos - 1; |
964 |
} |
965 |
break; |
966 |
default: |
967 |
sMsg (ERR_INVAL, |
968 |
"fRec2Fd: ignoring unexpected tag %d (%s)", |
969 |
F->tag, name); |
970 |
} |
971 |
} |
972 |
if (0x07 != got) { |
973 |
sMsg (ERR_TRASH, |
974 |
"fRec2Fd: incomplete field description [%x] (%s)", got, name); |
975 |
err: |
976 |
if (fd->pat) { mFree (fd->pat); } |
977 |
if (fd->dflt) { mFree (fd->dflt); } |
978 |
if (fd->info) { mFree (fd->info); } |
979 |
if (fd != buf) { mFree (fd); } |
980 |
return 0; |
981 |
} |
982 |
return fd; |
983 |
} |
984 |
|
985 |
Fdt *fRec2Fdt (Rec *rec) { |
986 |
Rec *R, *cfg; |
987 |
Fdt *fdt; |
988 |
Fd fdbuf; |
989 |
Fd *F, *arr; |
990 |
int err, num, len, pos; |
991 |
if (!rec) { |
992 |
return 0; |
993 |
} |
994 |
num = rInt (rec, OPENISIS_FDT_LEN, 0, 0); |
995 |
if (0 >= num) { |
996 |
return 0; |
997 |
} |
998 |
arr = (Fd*) mAlloc (num * sizeof (Fd)); |
999 |
if (!arr) { |
1000 |
return 0; |
1001 |
} |
1002 |
fdt = (Fdt*) mAlloc (sizeof(Fdt)); |
1003 |
if (! fdt) { |
1004 |
mFree (arr); |
1005 |
return 0; |
1006 |
} |
1007 |
for (F = arr, len = pos = 0; num; --num) { |
1008 |
R = luti_unwrap (rec, &pos, OPENISIS_FDT_FD, -1); |
1009 |
if (!R) { |
1010 |
return fCleanupArr (fdt, arr, len); |
1011 |
} |
1012 |
memset (&fdbuf, 0, sizeof(Fd)); |
1013 |
if (fRec2Fd (R, &fdbuf)) { |
1014 |
memcpy (F, &fdbuf, sizeof(Fd)); |
1015 |
++len; |
1016 |
++F; |
1017 |
} |
1018 |
mFree (R); |
1019 |
} |
1020 |
if (len != num) { |
1021 |
num = len * sizeof(Fd); |
1022 |
F = (Fd*) mAlloc (num); |
1023 |
if (! F) { |
1024 |
return fCleanupArr (fdt, arr, len); |
1025 |
} |
1026 |
memcpy (F, arr, num); |
1027 |
mFree (arr); |
1028 |
arr = F; |
1029 |
} |
1030 |
cfg = luti_unwrap (rec, 0, OPENISIS_FDT_REC, -1); |
1031 |
fdt->len = len; |
1032 |
fdt->fd = arr; |
1033 |
fdt->rec = cfg; |
1034 |
err = fResolveChilds (arr, len); |
1035 |
if (-ERR_NOMEM == err) { |
1036 |
return fFree (fdt); |
1037 |
} |
1038 |
return fdt; |
1039 |
} |
1040 |
|