/[webpac]/trunk/openisis/tcl/openisistcl.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/openisis/tcl/openisistcl.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 239 - (show annotations)
Mon Mar 8 17:49:13 2004 UTC (17 years, 4 months ago) by dpavlin
File MIME type: text/plain
File size: 57085 byte(s)
including openisis 0.9.0 into webpac tree

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: openisistcl.c,v 1.77 2003/06/24 11:01:53 mawag Exp $
25 tcl/tk binding
26 */
27
28
29 #include "openisis.h"
30 #include "openisistcl.h"
31 #include "luti.h"
32 /* luti_getembed,
33 * luti_ptrincr,
34 * luti_parse_path,
35 * luti_free,
36 * luti_append
37 */
38 #include "ldsp.h" /* openIsisEnc2Utf8,openIsisEval */
39 #include "lses.h" /* SESGET() */
40
41 /*
42 include this after the Tcl stuff for the benefit of those
43 who use the 150% braindead gcc 2.96
44 which barfs on
45 declaration of `index' shadows global declaration
46 in generic/tclDecls.h
47 cause string.h declares
48 char *index(const char *s, int c)
49 */
50 #include <errno.h>
51 #include <limits.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55
56 #ifdef WIN32
57 #define snprintf _snprintf
58 #endif
59
60 /*
61 #ifdef _REENTRANT
62 unusable because of POSIX stdfoo.h braindamage
63 -- they mix up MT with reentrant.
64
65 Hmm, actually, _REENTRANT *is* the wrong flag for threads.
66 But, unfortunately, the *thread* thing #define errno *errnolocation()
67 is bound to this flag by POSIX (mas o menos).
68 You need the reentrant functions in every stupid single threaded signal handler.
69 Therefore, it's a pretty poor idea of Solaris (albeit very POSIX compliant)
70 to not define them unless _REENTRANT.
71
72 *sigh*
73
74 from /opt/TclTk/tcl8.3.5/unix/configure:
75 SunOS-5.[0-6]*)
76
77 # Note: If _REENTRANT isn't defined, then Solaris
78 # won't define thread-safe library routines.
79
80 cat >> confdefs.h <<\EOF
81 #define _REENTRANT 1
82 EOF
83 */
84 #ifdef TCL_THREADS
85 extern int openisis_threaded;
86 static int *link_dummy = &openisis_threaded; /* force correct linkage */
87 #endif
88
89
90 /* ============================ types ==================================
91 */
92
93 /* name of local schema */
94 #define OIT_STB0 "openIsisRoot"
95
96 typedef enum {
97 /* record commands */
98 RC_ADD,
99 RC_CLON,
100 RC_COPY,
101 RC_DB, /* stub, too */
102 RC_DEL,
103 RC_DESER,
104 RC_DO,
105 RC_DONE, /* stub, too */
106 RC_FDT, /* stub, too */
107 RC_FMT,
108 RC_GET,
109 RC_ROW,
110 RC_LEN,
111 RC_SERI,
112 RC_SET,
113 RC_WRAP,
114 RC_LAST = RC_WRAP, /* used for checking last rec cmd */
115 /* stub commands */
116 SC_NEW,
117 SC_RECV,
118 SC_RQS,
119 SC_ARQS,
120 SC_ARSP
121 } OITCmd;
122
123 static const char *OITOpts[] = {
124 /* record commands */
125 "add",
126 "clone",
127 "copy",
128 "db",
129 "delete",
130 "deserialize",
131 "do",
132 "done",
133 "fdt",
134 "format",
135 "get",
136 "rowid",
137 "length",
138 "serialize",
139 "set",
140 "wrap",
141 /* stub commands */
142 "new",
143 "recv",
144 "request",
145 ".req",
146 ".res",
147 0
148 };
149
150 #define OIT_RS_SZM 0x000FF /* size mask */
151 #define OIT_RS_RQS 0x00100 /* schemas request rec */
152 #define OIT_RS_RSP 0x00200 /* schemas response rec */
153 #define OIT_RS_STC 0x00400 /* schemas config rec */
154 #define OIT_RS_DBC 0x00800 /* db config rec */
155 #define OIT_RS_DBF 0x01000 /* db fdt rec */
156 #define OIT_RS_USED 0x10000 /* rec is in use */
157 #define OIT_RS_FRE 0x20000 /* free associated memory */
158 #define OIT_RS_OWNF 0x40000 /* record has own fdt that must be freed */
159
160 #define RecType(r) (0x01F00 & (r)->stat)
161 #define NonWritable(r) (0x01A00 & (r)->stat)
162 #define NonDeletable(r) (0x00700 & (r)->stat)
163
164 typedef struct OITSess OITSess;
165
166 typedef struct {
167 OpenIsisRec *rec;
168 OpenIsisDb *db; /* own db; tmp set to target db in rqs */
169 const OpenIsisFdt *fdt; /* own fdt */
170 const char *cmd; /* associated tcl ip cmd */
171 int sid; /* allocator */
172 int stat;
173 } OITRec;
174
175 #define RecSess(r) \
176 (0 <= ((OITRec*)(r))->sid && NumSessions > ((OITRec*)(r))->sid ? \
177 Sessions + ((OITRec*)(r))->sid : 0)
178
179 typedef struct {
180 OITRec env;
181 OpenIsisStub stb;
182 OITRec **recs; /* embedded recs */
183 int numr;
184 } OITCont;
185
186 #define OIT_ST_ROOT 0x0001
187 #define OIT_ST_TCL 0x0002
188 #define OIT_ST_OINIT 0x0004
189
190 typedef struct {
191 OpenIsisStub stb;
192 OITRec cfg; /* direct schema copy allocated by ses0 */
193 OITCont *rqs;
194 OITCont *rsp;
195 const char *cmd; /* associated tcl ip cmd */
196 Tcl_Obj *dfltproc;
197 Tcl_Obj *actproc;
198 int ases; /* act session of rqs and rsp */
199 int stat;
200 } OITStub;
201
202 #define StbSess(s) (0 <= (s)->ases && NumSessions > (s)->ases ? \
203 Sessions + (s)->ases : 0)
204
205 struct OITSess {
206 Tcl_Interp *ip;
207 OITRec **recs;
208 int numr;
209 int six;
210 };
211
212 static OITSess *Sessions = 0;
213 static int NumSessions = 0;
214
215 /* ============================ records ================================
216 */
217
218 #define OIT_RECINCR 32
219 #define OIT_MAXRECS 65535
220 #define OIT_SESSINCR 1
221 #define OIT_MAXSESS 255
222
223 static void CtorRec (OITRec *that, int sid, int siz) {
224 memset (that, 0, (unsigned)siz);
225 that->stat = siz;
226 that->sid = sid;
227 }
228
229 static int AllcRec (OITSess *ois, int siz, int type) {
230 int j;
231 if (siz > OIT_RS_SZM) {
232 return openIsisSMsg (OPENISIS_ERR_TRASH,
233 "[openIsisTcl] AllcRec: unexpected size %d", siz);
234 }
235 for (j = ois->numr; 0 <= --j; ) {
236 if (! ois->recs[j]) {
237 goto allcj;
238 }
239 if (! (OIT_RS_USED & ois->recs[j]->stat) &&
240 siz == (OIT_RS_SZM & ois->recs[j]->stat) /* may be <= */
241 ) {
242 goto done;
243 }
244 }
245 j = luti_ptrincr (
246 &ois->recs, &ois->numr, OIT_RECINCR, sizeof (OITRec*), OIT_MAXRECS);
247 if (0 > j) {
248 return openIsisSMsg (OPENISIS_ERR_TRASH,
249 "[openIsisTcl] AllcRec: out of memory");
250 }
251 allcj:
252 ois->recs[j] = (OITRec*) openIsisMAlloc (siz);
253 if (! ois->recs[j]) {
254 return openIsisSMsg (OPENISIS_ERR_TRASH,
255 "[openIsisTcl] AllcRec: out of memory");
256 }
257 CtorRec (ois->recs[j], ois->six, siz);
258 done:
259 ois->recs[j]->stat |= type | OIT_RS_USED;
260 return j;
261 }
262
263 static int NewRec (
264 OITSess *ois, OpenIsisDb *db, const OpenIsisFdt *fdt, int type
265 ) {
266 int j = AllcRec (ois, sizeof (OITRec), type);
267 if (0 <= j) {
268 ois->recs[j]->db = db;
269 ois->recs[j]->fdt = fdt;
270 }
271 return j;
272 }
273
274 static int NewCont (OITSess *ois, const OpenIsisFdt *fdt, int type) {
275 int j = AllcRec (ois, sizeof (OITCont), type);
276 if (0 <= j) {
277 ois->recs[j]->fdt = fdt;
278 }
279 return j;
280 }
281
282 static void DtorRecs (OITRec **recs, int numr, int frmem);
283
284 static void DtorRec (OITRec *that, int frmem) {
285 if (that) {
286 OITCont *con;
287 OITSess *ois;
288 int siz, type;
289 ois = RecSess (that);
290 if (! ois) {
291 openIsisSMsg (OPENISIS_ERR_TRASH,
292 "[openIsisTcl] DtorRec: illegal sid %d(%d)",
293 that->sid, NumSessions);
294 return;
295 }
296 if (that->cmd) {
297 if (frmem) {
298 that->stat |= OIT_RS_FRE;
299 }
300 Tcl_DeleteCommand (ois->ip, (char*)that->cmd);
301 return;
302 }
303 type = RecType (that);
304 siz = OIT_RS_SZM & that->stat;
305 switch (type) {
306 case 0:
307 case OIT_RS_DBF:
308 if (that->rec) {
309 openIsisMFree (that->rec);
310 }
311 break;
312 case OIT_RS_DBC:
313 /* that->rec = 0; readonly cfg handled by db */
314 break;
315 case OIT_RS_RQS:
316 if (that->rec) {
317 openIsisMFree (that->rec);
318 }
319 /* fall thru */
320 case OIT_RS_RSP:
321 /* that->rec = 0; response record handled by stub */
322 con = (OITCont*)that;
323 DtorRecs (con->recs, con->numr, 0);
324 break;
325 default:
326 /* OIT_RS_STC embedded in OITStub and handled by stub */
327 openIsisSMsg (OPENISIS_ERR_TRASH,
328 "[openIsisTcl] DtorRec: unexpected type %x", type);
329 return;
330 }
331 if ((OIT_RS_OWNF & that->stat)) {
332 openIsisFFree ((OpenIsisFdt*)that->fdt);
333 }
334 if (frmem || (OIT_RS_FRE & that->stat)) {
335 openIsisMFree (that);
336 }
337 else {
338 CtorRec (that, ois->six, siz);
339 }
340 }
341 }
342
343 static void DtorRecs (OITRec **recs, int numr, int frmem) {
344 if (recs) {
345 while (0 <= --numr) {
346 DtorRec (recs[numr], frmem);
347 }
348 openIsisMFree (recs);
349 }
350 }
351
352 static int CtorSess (Tcl_Interp *ip) {
353 int j = luti_ptrincr (
354 &Sessions, &NumSessions, OIT_SESSINCR, sizeof (OITSess), OIT_MAXSESS);
355 if (0 > j) {
356 return -1;
357 }
358 Sessions[j].ip = ip;
359 Sessions[j].six = j;
360 return j;
361 }
362
363 static void DtorSess (OITSess *that) {
364 DtorRecs (that->recs, that->numr, !0);
365 }
366
367 static void ExitSess () {
368 int j;
369 if (NumSessions) {
370 for (j = NumSessions; 0 <= --j; ) {
371 DtorSess (Sessions + j);
372 }
373 openIsisMFree (Sessions);
374 Sessions = 0;
375 NumSessions = 0;
376 }
377 }
378
379 /* ---------------------------------------------------------------------
380 */
381
382 static unsigned _RecId = 0;
383
384 static char* NewRecId (char *buf) {
385 sprintf (buf, "openIsisRec%u", ++_RecId);
386 return buf;
387 }
388
389 static void TclDelRec (ClientData cld) {
390 OITRec *that = (OITRec*)cld;
391 if (that->cmd) {
392 openIsisMFree ((void*)that->cmd);
393 that->cmd = 0;
394 }
395 DtorRec ((OITRec*)cld, 0);
396 }
397
398 static int CmdRec (
399 ClientData rid, Tcl_Interp *ip, int argc, Tcl_Obj* const argv[]
400 );
401
402 static int CrtRecCmd (OITSess *ois, const char *name, OITRec *rec, int srst) {
403 char buf[64];
404 if (! name || ! *name) {
405 name = NewRecId (buf);
406 }
407 rec->cmd = (const char*) openIsisMDup (name, -1);
408 if (! rec->cmd) {
409 Tcl_AppendResult (ois->ip, "CrtRecCmd: out of memory", 0);
410 return TCL_ERROR;
411 }
412 Tcl_CreateObjCommand (ois->ip, (char*)name, &CmdRec, rec, &TclDelRec);
413 if (srst) {
414 Tcl_SetResult (ois->ip, (char*)name, TCL_VOLATILE);
415 }
416 return TCL_OK;
417 }
418
419 static char **ToArgv (
420 Tcl_Obj* const objv[], int objc, char* buf, int siz
421 ) {
422 char *str, *nb;
423 char *res = buf;
424 int posp = 0;
425 int stav = objc * sizeof (char*);
426 int posv = stav;
427 int j, len, nsz;
428 for (j = 0; objc > j; ++j) {
429 str = Tcl_GetStringFromObj (objv[j], &len);
430 nsz = posv + 1 + len;
431 if (siz < nsz) {
432 char **S, **T;
433 int k, diff;
434 nsz *= 2;
435 nb = (char*) openIsisMAlloc (nsz);
436 if (! nb) {
437 openIsisSMsg (OPENISIS_ERR_NOMEM,
438 "[openIsisTcl] ToArgv: out of memory");
439 return 0;
440 }
441 diff = nb - res;
442 for (k = j, S = (char**)res, T = (char**)nb ; 0 <= --k; ) {
443 *T++ = *S++ + diff;
444 }
445 memcpy (nb + stav, res + stav, (unsigned)(posv - stav));
446 if (res != buf) {
447 openIsisMFree (res);
448 }
449 siz = nsz;
450 res = nb;
451 }
452 *(char**)(res + posp) = res + posv;
453 ((char*) memcpy (res + posv, str, len)) [len] = 0;
454 posp += sizeof (char*);
455 posv += 1 + len;
456 }
457 return (char**)res;
458 }
459
460 static OITRec* TclCmd2Rec (
461 Tcl_Interp *ip, const char *cmd, const char *arg0
462 ) {
463 Tcl_CmdInfo info;
464 if (! cmd) {
465 if (arg0) {
466 Tcl_AppendResult (ip, arg0, ": record command not given", 0);
467 }
468 return 0;
469 }
470 if (! Tcl_GetCommandInfo (ip, cmd, &info)) {
471 if (arg0) {
472 Tcl_AppendResult (ip, arg0, ": no such record: ", cmd, 0);
473 }
474 return 0;
475 }
476 if (info.objProc != &CmdRec) {
477 if (arg0) {
478 Tcl_AppendResult (ip, arg0, ": ", cmd, " is not a record", 0);
479 }
480 return 0;
481 }
482 if (! info.objClientData) {
483 if (arg0) {
484 Tcl_AppendResult (ip, arg0, ": ", cmd, " is corrupted", 0);
485 }
486 return 0;
487 }
488 return (OITRec*) info.objClientData;
489 }
490
491 static int BuildEmbRecs (
492 OITCont *that, OpenIsisRec **recs, int numr, int frr
493 ) {
494 OITSess *ois;
495 OITRec **oirs;
496 int buf[1000];
497 int *idx = buf;
498 int j;
499 ois = RecSess (that);
500 if (! ois) {
501 return openIsisSMsg (OPENISIS_ERR_TRASH,
502 "[openIsisTcl] BuildEmbRecs: illegal sid %d(%d)",
503 that->env.sid, NumSessions);
504 }
505 oirs = (OITRec**) openIsisMAlloc ( (int) (numr * sizeof (OITRec*)));
506 if (! oirs) {
507 if (frr) {
508 luti_free ((void**)recs, numr);
509 }
510 return openIsisSMsg (OPENISIS_ERR_NOMEM,
511 "[openIsisTcl] BuildEmbRecs(%d): out of memory", numr);
512 }
513 if (1000 < numr) {
514 idx = (int*) openIsisMAlloc ( (int) (numr * sizeof (int)));
515 if (! idx) {
516 if (frr) {
517 luti_free ((void**)recs, numr);
518 }
519 openIsisMFree (oirs);
520 return openIsisSMsg (OPENISIS_ERR_NOMEM,
521 "[openIsisTcl] BuildEmbRecs(%d): out of memory", numr);
522 }
523 }
524 for (j = numr; 0 <= --j; ) {
525 idx[j] = NewRec (ois, 0, 0, 0);
526 if (0 > idx[j]) {
527 if (frr) {
528 luti_free ((void**)recs, numr);
529 }
530 openIsisMFree (oirs);
531 if (idx != buf) {
532 openIsisMFree (idx);
533 }
534 return openIsisSMsg (OPENISIS_ERR_NOMEM,
535 "[openIsisTcl] BuildEmbRecs(%d): out of memory", numr);
536 }
537 }
538 for (j = numr; 0 <= --j; ) {
539 oirs[j] = ois->recs[idx[j]];
540 oirs[j]->rec = recs[j];
541 }
542 that->recs = oirs;
543 that->numr = numr;
544 if (idx != buf) {
545 openIsisMFree (idx);
546 }
547 if (frr) {
548 openIsisMFree (recs);
549 }
550 return numr;
551 }
552
553 static int BuildRqsRecs (OITCont *that) {
554 OpenIsisRec *recs[4] = { 0, 0, 0, 0 }; /* REC, IDX, CFG, fdt */
555 int numr;
556 numr = BuildEmbRecs (that, recs, 4, 0);
557 if (4 == numr) {
558 if ((that->recs[0]->db = that->env.db)) {
559 that->recs[0]->fdt = that->env.db->fdt;
560 }
561 that->recs[2]->fdt = openIsisFdtDbpar;
562 that->recs[3]->fdt = openIsisFdtFdt;
563 }
564 return numr;
565 }
566
567 static int BuildRspRecs (OITCont *that, Tcl_Interp *ip, const char *arg0) {
568 OpenIsisRec **recs;
569 OpenIsisDb *db;
570 int *rows; /* save rowid in recs */
571 int numr, j;
572 numr = openIsisNGetResult (that->stb, &rows, &recs, &db, 0);
573 if (0 > numr) {
574 Tcl_AppendResult (ip, arg0,
575 ": child allocation failure", 0);
576 return numr;
577 }
578 if (rows) {
579 openIsisMFree (rows);
580 }
581 if (0 == numr || ! recs) {
582 return 0;
583 }
584 j = BuildEmbRecs (that, recs, numr, !0);
585 if (j != numr) {
586 Tcl_AppendResult (ip, arg0,
587 ": child allocation failure", 0);
588 return j;
589 }
590 if (db) {
591 for (j = numr; 0 <= --j; ) {
592 that->recs[j]->db = db;
593 that->recs[j]->fdt = db->fdt;
594 }
595 }
596 return numr;
597 }
598
599 static int UsageRec (Tcl_Interp *ip, const char *arg0) {
600 if (! arg0) {
601 arg0 = "<openIsisRecord>";
602 }
603 Tcl_AppendResult (ip,
604 "usage: ", arg0,
605 " add field value ?field value ...? |",
606 " clone ?options? newname ?field value ...? |",
607 " copy source |",
608 " db ?options? |",
609 " delete ?field ...? |",
610 " deserialize line |",
611 " do ?tagvar? valvar body |",
612 " done |",
613 " fdt ?options? |",
614 " format ?options? format |",
615 " get ?-tags | -tagnames | field ...? |",
616 " rowid |",
617 " serialize |",
618 " set field ?value field value ...? |",
619 " wrap ?options? recname |",
620 " .path ?option arg ...?",
621 0);
622 return TCL_ERROR;
623 }
624
625 static int OpPath (
626 OITRec *that, Tcl_Interp *ip, const char *arg0,
627 Tcl_Obj *arg1, int argc, Tcl_Obj* const argv[]
628 );
629
630 static int OpDb (Tcl_Interp *ip,
631 OITSess *ois, OpenIsisDb *db, int argc, Tcl_Obj* const argv[]
632 ) {
633 OITRec *oir;
634 int rt;
635 rt = NewRec (ois, 0, openIsisFdtDbpar, OIT_RS_DBC);
636 if (0 > rt) {
637 Tcl_AppendResult (ip, "openIsisDb: out of memory", 0);
638 return TCL_ERROR;
639 }
640 oir = ois->recs[rt];
641 oir->rec = db->cfg;
642 if (argc) {
643 rt = OpPath (oir, ip, "openIsisDb", argv[0], argc - 1, argv + 1);
644 DtorRec (oir, 0);
645 return rt;
646 }
647 return CrtRecCmd (ois, 0, oir, !0);
648 }
649
650 static int OpFdt (Tcl_Interp *ip,
651 OITSess *ois, const OpenIsisFdt *fdt, int argc, Tcl_Obj* const argv[]
652 ) {
653 OITRec *oir;
654 int rt;
655 rt = NewRec (ois, 0, openIsisFdtFdt, OIT_RS_DBF);
656 if (0 > rt) {
657 Tcl_AppendResult (ip, "openIsisFdt: out of memory", 0);
658 return TCL_ERROR;
659 }
660 oir = ois->recs[rt];
661 oir->rec = openIsisFFdt2Rec (fdt, 0, 0);
662 if (argc) {
663 rt = OpPath (oir, ip, "openIsisFdt", argv[0], argc - 1, argv + 1);
664 DtorRec (oir, 0);
665 return rt;
666 }
667 return CrtRecCmd (ois, 0, oir, !0);
668 }
669
670 #define FldObj( f ) Tcl_NewStringObj( (f)->val, (f)->len )
671
672 static Tcl_Obj* FdObj (OpenIsisField *fld, const OpenIsisFdt *fdt) {
673 if (fdt) {
674 OpenIsisFd *fd = openIsisFById (fdt, fld->tag, 0);
675 if (fd) {
676 return Tcl_NewStringObj (fd->name, -1);
677 }
678 }
679 return Tcl_NewIntObj (fld->tag);
680 }
681
682 static int OpRec (
683 OITRec *that, Tcl_Interp *ip, const char *arg0,
684 const OITCmd cmd, int argc, Tcl_Obj* const argv[]
685 ) {
686 OITSess *ois = RecSess (that);
687 if (! ois) {
688 Tcl_AppendResult (ip, arg0, ": record corrupted", 0);
689 return TCL_ERROR;
690 }
691
692 switch (cmd) {
693
694 case RC_SET:
695 case RC_ADD: {
696 char buf[2048];
697 OpenIsisRec *oldrec;
698 char **argp = 0;
699 char **args = 0;
700 int setf = 0;
701 int len;
702 if (0 == argc) {
703 return UsageRec (ip, arg0);
704 }
705 if (RC_SET == cmd) {
706 if (1 == argc) {
707 goto op_get;
708 }
709 if ( that->rec ) {
710 setf = OPENISIS_RCHG;
711 }
712 }
713 if (NonWritable (that)) {
714 Tcl_AppendResult (ip, arg0, ": readonly record", 0);
715 return TCL_ERROR;
716 }
717 args = argp = ToArgv (argv, argc, buf, sizeof (buf));
718 if (! argp) {
719 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
720 return TCL_ERROR;
721 }
722 while (argc) {
723 if ('-' != args[0][0]) {
724 break;
725 }
726 len = strlen (args[0]);
727 if (1 == len || '-' == args[0][1]) {
728 break;
729 }
730 if (0 == strncmp ("-ignore", args[0], len)) {
731 setf |= OPENISIS_RIGN;
732 ++args;
733 --argc;
734 continue;
735 }
736 if (RC_SET != cmd) {
737 break;
738 }
739 if (0 == strncmp ("-default", args[0], len)) {
740 setf = OPENISIS_RDFLT | (OPENISIS_RIGN & setf);
741 ++args;
742 --argc;
743 continue;
744 }
745 break;
746 }
747 oldrec = that->rec;
748 that->rec = openIsisRSet (oldrec,
749 OPENISIS_RARGV | OPENISIS_RFDT | OPENISIS_RDIS | setf | argc,
750 that->fdt, args);
751 if (argp != (char**)buf) {
752 openIsisMFree (argp);
753 }
754 if (! that->rec && (oldrec || (argc && !(OPENISIS_RIGN & setf)))) {
755 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
756 return TCL_ERROR;
757 }
758 return TCL_OK;
759 } /* RC_SET, RC_ADD */
760
761 case RC_CLON: {
762 char buf[64];
763 OITRec *nrec;
764 char *opt = 0;
765 char *name = 0;
766 int empty = 0;
767 int nn = 0;
768 int j, len, rt, id;
769 if ((OIT_RS_RQS | OIT_RS_RSP) & that->stat) {
770 Tcl_AppendResult (ip, arg0,
771 ": container cloning not allowed", 0);
772 return TCL_ERROR;
773 }
774 for (j = 0; argc > j; ++j) {
775 opt = Tcl_GetStringFromObj (argv[j], &len);
776 if (0 == len) {
777 return UsageRec (ip, arg0);
778 }
779 if ('-' != *opt) {
780 break;
781 }
782 if (0 == opt[1]) {
783 nn = !0;
784 ++j;
785 break;
786 }
787 if (0 == strncmp ("-empty", opt, len)) {
788 empty = !0;
789 continue;
790 }
791 return UsageRec (ip, arg0);
792 }
793 if (argc > j && ! nn) {
794 name = Tcl_GetStringFromObj (argv[j], &len);
795 if (0 == len) {
796 return UsageRec (ip, arg0);
797 }
798 ++j;
799 }
800 if (! name) {
801 name = NewRecId (buf);
802 }
803 id = NewRec (ois, that->db, that->fdt, 0);
804 if (0 > id) {
805 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
806 return TCL_ERROR;
807 }
808 nrec = ois->recs[id];
809 if (! empty) {
810 nrec->rec = openIsisRDup (that->rec, 0, 0);
811 }
812 if (argc > j) {
813 rt = OpRec (nrec,
814 ip, name, RC_SET, argc - j, argv + j);
815 if (TCL_OK != rt) {
816 return rt;
817 }
818 }
819 rt = CrtRecCmd (ois, name, ois->recs[id], !0);
820 return rt;
821 } /* RC_CLON */
822
823 case RC_COPY: {
824 char buf[64];
825 OITRec *src;
826 Field *fld;
827 int j;
828 if (1 != argc) {
829 return UsageRec (ip, arg0);
830 }
831 src = TclCmd2Rec (ip, Tcl_GetStringFromObj (argv[0], 0), arg0);
832 if (! src) {
833 return TCL_ERROR;
834 }
835 if (! src->rec || ! src->rec->len) {
836 Tcl_SetResult (ip, "0", TCL_STATIC);
837 return TCL_OK;
838 }
839 fld = src->rec->field;
840 j = src->rec->len;
841 sprintf (buf, "%d", j);
842 Tcl_SetResult (ip, buf, TCL_VOLATILE);
843 while (j) {
844 OPENISIS_RADD (that->rec, fld->tag, fld->val, fld->len, !0);
845 ++fld;
846 --j;
847 }
848 return TCL_OK;
849 } /* RC_COPY */
850
851 case RC_DB:
852 if (! that->db) {
853 Tcl_AppendResult (ip, arg0, ": no db", 0);
854 return TCL_ERROR;
855 }
856 return OpDb (ip, ois, that->db, argc, argv);
857
858 case RC_DEL: {
859 if (NonWritable (that)) {
860 Tcl_AppendResult (ip, arg0, ": readonly record", 0);
861 return TCL_ERROR;
862 }
863 if (argc) {
864 char buf[2048];
865 char **argp = ToArgv (argv, argc, buf, sizeof (buf));
866 if (! argp) {
867 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
868 return TCL_ERROR;
869 }
870 that->rec = openIsisRSet (that->rec,
871 OPENISIS_RARGV | OPENISIS_RFDT | OPENISIS_RDEL | argc,
872 that->fdt, argp);
873 if (argp != (char**)buf) {
874 openIsisMFree (argp);
875 }
876 return TCL_OK;
877 }
878 if (that->rec) {
879 OPENISIS_CLRREC( that->rec );
880 }
881 if (OIT_RS_RQS == RecType (that)) {
882 OITCont *con = (OITCont*)that;
883 if (con->numr) {
884 DtorRecs (con->recs, con->numr, 0);
885 con->numr = 0;
886 con->recs = 0;
887 }
888 }
889 return TCL_OK;
890 } /* RC_DEL */
891
892 case RC_DO: {
893 Tcl_Obj *tagvar = 0;
894 Tcl_Obj *valvar;
895 Tcl_Obj *tag = 0;
896 Tcl_Obj *val;
897 Tcl_Obj *body;
898 OpenIsisField *f;
899 int i, rt;
900 if ( 2 > argc )
901 return UsageRec (ip, arg0);
902 body = argv[--argc];
903 valvar = argv[--argc];
904 if ( 1 == argc )
905 tagvar = argv[0];
906 #ifndef DONTREUSE
907 /* prepare object for var */
908 if ( ! Tcl_ObjSetVar2( ip, valvar, 0,
909 val = Tcl_NewObj(), TCL_LEAVE_ERR_MSG )
910 )
911 return TCL_ERROR;
912 if ( tagvar && ! Tcl_ObjSetVar2( ip, tagvar, 0,
913 tag = Tcl_NewIntObj(0), TCL_LEAVE_ERR_MSG )
914 )
915 return TCL_ERROR;
916 #endif
917
918 /* go loop */
919 rt = TCL_OK;
920 for ( i = that->rec->len, f = that->rec->field; i--; f++ ) {
921 #ifndef DONTREUSE
922 /*
923 if somebody shares the object, we have to set a new one
924 (or Tcl_SetStringObj will panic).
925 if it's not owned by the var, it's either owned by someone else
926 or nobody, i.e. deleted
927 */
928 if ( val == Tcl_ObjGetVar2( ip, valvar, 0, TCL_LEAVE_ERR_MSG )
929 && !Tcl_IsShared( val )
930 )
931 Tcl_SetStringObj( val, (char*)f->val, f->len );
932 else
933 #endif
934 if ( !Tcl_ObjSetVar2( ip, valvar, 0,
935 val = FldObj( f ), TCL_LEAVE_ERR_MSG )
936 )
937 return TCL_ERROR;
938 if ( tagvar ) {
939 #ifndef DONTREUSE
940 if ( tag == Tcl_ObjGetVar2( ip, tagvar, 0, TCL_LEAVE_ERR_MSG )
941 && !Tcl_IsShared( tag )
942 )
943 Tcl_SetIntObj( tag, f->tag );
944 else
945 #endif
946 if ( !Tcl_ObjSetVar2( ip, tagvar, 0,
947 tag = Tcl_NewIntObj( f->tag ), TCL_LEAVE_ERR_MSG )
948 )
949 return TCL_ERROR;
950 } /* tagvar */
951 switch (rt = Tcl_EvalObjEx( ip, body, 0 )) {
952 case TCL_CONTINUE:
953 rt = TCL_OK;
954 case TCL_OK:
955 continue;
956 case TCL_BREAK:
957 rt = TCL_OK;
958 case TCL_RETURN:
959 case TCL_ERROR:
960 default:
961 return rt;
962 }
963 }
964 return rt;
965 } /* RC_DO */
966
967 case RC_DONE: {
968 if (! that->cmd) {
969 Tcl_AppendResult (ip, arg0, ": no command bound to rec", 0);
970 return TCL_ERROR;
971 }
972 if (strcmp (that->cmd, arg0)) {
973 Tcl_AppendResult (ip, arg0, ": command mismatch: ", that->cmd, 0);
974 return TCL_ERROR;
975 }
976 if (NonDeletable (that)) {
977 Tcl_AppendResult (ip, arg0, ": record not deletable", 0);
978 return TCL_ERROR;
979 }
980 Tcl_DeleteCommand (ip, (char*)arg0);
981 return TCL_OK;
982 } /* RC_DONE */
983
984 case RC_FDT:
985 if (! that->fdt) {
986 Tcl_AppendResult (ip, arg0, ": no fdt", 0);
987 return TCL_ERROR;
988 }
989 return OpFdt (ip, ois, that->fdt, argc, argv);
990
991 case RC_FMT: {
992 Tcl_AppendResult (ip, arg0, ": sorry, format not implemented yet", 0);
993 return TCL_ERROR;
994 } /* RC_FMT */
995
996 case RC_GET:
997 op_get: {
998 OpenIsisField *fld;
999 const char *path, *rem;
1000 int tag, occ, i, j, objc, len, reclen;
1001 int witht = 0;
1002 int usedf = !0;
1003 Tcl_Obj *list, *dflt, *val;
1004 Tcl_Obj **objv;
1005
1006 Tcl_ResetResult (ip);
1007 reclen = that->rec ? that->rec->len : 0;
1008 list = val = 0;
1009 if (1 == argc) {
1010 path = Tcl_GetStringFromObj (argv[0], &i);
1011 if (3 < i && *path == '-') {
1012 if (0 == strncmp ("-tags", path, i)) {
1013 --argc;
1014 witht = 1;
1015 }
1016 else if (0 == strncmp ("-tagnames", path, i)) {
1017 --argc;
1018 witht = 2;
1019 }
1020 }
1021 }
1022 if (! argc) {
1023 list = Tcl_NewListObj( 0, 0 );
1024 if (reclen) {
1025 for (i = reclen, fld = that->rec->field; i--; fld++) {
1026 if (witht) {
1027 if (TCL_OK != Tcl_ListObjAppendElement (ip, list,
1028 FdObj (fld, 2 == witht ? that->fdt : 0))) {
1029 goto geterr;
1030 }
1031 }
1032 if (TCL_OK != Tcl_ListObjAppendElement (ip, list,
1033 FldObj (fld))) {
1034 goto geterr;
1035 }
1036 }
1037 }
1038 Tcl_SetObjResult( ip, list );
1039 return TCL_OK;
1040 }
1041 for (j = 0; argc > j; ) {
1042 path = Tcl_GetStringFromObj (argv[j], &len);
1043 if (3 <= len &&
1044 '-' == *path &&
1045 0 == strncmp ("-nodefaults", path, len)) {
1046 usedf = 0;
1047 ++j;
1048 continue;
1049 }
1050 val = dflt = 0;
1051 if (usedf &&
1052 TCL_OK ==
1053 Tcl_ListObjGetElements (0, argv[j], &objc, &objv) &&
1054 2 == objc
1055 ) {
1056 path = Tcl_GetStringFromObj (objv[0], 0);
1057 dflt = objv[1];
1058 }
1059 rem = luti_parse_path (path, that->fdt, 0, &tag, &occ);
1060 if (! rem || *rem) {
1061 Tcl_ResetResult (ip);
1062 Tcl_AppendResult (ip, arg0,
1063 ": no such path: ", path, 0);
1064 goto geterr;
1065 }
1066 if (reclen) {
1067 if ( 0 > occ ) {
1068 for ( i = reclen, fld = that->rec->field;
1069 i--;
1070 fld++ ) {
1071 if ( tag == fld->tag ) {
1072 if (! val) {
1073 val = Tcl_NewListObj (0, 0);
1074 }
1075 if (TCL_OK != Tcl_ListObjAppendElement (
1076 ip, val, FldObj(fld))) {
1077 goto geterr;
1078 }
1079 }
1080 }
1081 }
1082 else { /* specific occ wanted */
1083 fld = openIsisROccurence (that->rec, tag, occ);
1084 if (fld) {
1085 val = FldObj(fld);
1086 }
1087 }
1088 }
1089 if (! val) {
1090 if (! dflt) {
1091 Tcl_ResetResult (ip);
1092 Tcl_AppendResult (ip, arg0,
1093 ": no such field: ", path, 0);
1094 goto geterr;
1095 }
1096 /* don't force a list even for empty default
1097 -- take the default as list.
1098 A literal default foo IS the list containing foo.
1099 If you REALLY wan't a list with one empty element as default,
1100 you can explicitly specify one.
1101 if (0 > occ) {
1102 Tcl_Obj *tmp[1];
1103 tmp[0] = dflt;
1104 val = Tcl_NewListObj (1, tmp);
1105 } else
1106 */
1107 val = dflt;
1108 }
1109 if (++j >= argc) {
1110 if (! list) {
1111 Tcl_SetObjResult( ip, val );
1112 return TCL_OK;
1113 }
1114 if (TCL_OK != Tcl_ListObjAppendElement(ip, list, val)) {
1115 goto geterr;
1116 }
1117 break;
1118 }
1119 if (! list) {
1120 list = Tcl_NewListObj( 0, 0 );
1121 }
1122 if (TCL_OK != Tcl_ListObjAppendElement(ip, list, val)) {
1123 goto geterr;
1124 }
1125 }
1126 if (! list) {
1127 return UsageRec (ip, arg0);
1128 }
1129 Tcl_SetObjResult( ip, list );
1130 return TCL_OK;
1131 geterr:
1132 /* free */
1133 if (val) {
1134 Tcl_DecrRefCount (val);
1135 }
1136 if (list) {
1137 Tcl_DecrRefCount( list );
1138 }
1139 return TCL_ERROR;
1140 } /* RC_GET */
1141
1142 case RC_ROW:
1143 Tcl_SetObjResult( ip, Tcl_NewIntObj(
1144 (that->rec && 0<that->rec->rowid) ? that->rec->rowid : 0
1145 ) );
1146 return TCL_OK;
1147
1148 case RC_LEN:
1149 Tcl_SetObjResult( ip, Tcl_NewIntObj(
1150 (that->rec && 0<that->rec->len) ? that->rec->len : 0
1151 ) );
1152 return TCL_OK;
1153
1154 case RC_SERI: {
1155 char buf[2048];
1156 char *b;
1157 int len;
1158
1159 if (! that->rec) {
1160 Tcl_ResetResult (ip);
1161 return TCL_OK;
1162 }
1163 len = sizeof (buf);
1164 b = openIsisRSerializeAlloc (that->rec, buf, &len);
1165 if (! b) {
1166 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
1167 return TCL_ERROR;
1168 }
1169 /* do NOT include the final blankline */
1170 Tcl_SetObjResult( ip, Tcl_NewStringObj( b, len-1 ) );
1171 /*
1172 faster, but not allowed :(
1173 Tcl_Obj *ret = Tcl_NewStringObj(0,0);
1174 Tcl_SetObjLength( ret, that->rec->used );
1175 Tcl_SetObjLength( ret, openIsisRSerialize( ret->bytes, that->rec ) );
1176 */
1177 if ( buf != b )
1178 mFree( b );
1179 return TCL_OK;
1180 } /* RC_SERI */
1181
1182 case RC_DESER: {
1183 char *b;
1184 int len;
1185
1186 if ( 1 != argc )
1187 return UsageRec (ip, arg0);
1188 if (NonWritable (that)) {
1189 Tcl_AppendResult (ip, arg0, ": readonly record", 0);
1190 return TCL_ERROR;
1191 }
1192 b = Tcl_GetStringFromObj( argv[0], &len );
1193 if ( ! b )
1194 Tcl_ResetResult (ip);
1195 else {
1196 int ret = openIsisRDeserialize( &that->rec,
1197 b, len, OPENISIS_RDIS|OPENISIS_STOPONEMPTY );
1198 Tcl_SetObjResult( ip, Tcl_NewIntObj( ret ) );
1199 }
1200
1201 return TCL_OK;
1202 } /* RC_DESER */
1203
1204 case RC_WRAP: {
1205 char buf[2048];
1206 OITRec *emb = 0;
1207 char **argp = (char**)buf;
1208 char *name = 0;
1209 char *tgnm = 0;
1210 int tag = -1;
1211 int num = -1;
1212 int del = 0;
1213 int len, j;
1214
1215 if (NonWritable (that)) {
1216 Tcl_AppendResult (ip, arg0, ": readonly record", 0);
1217 return TCL_ERROR;
1218 }
1219 argp = ToArgv (argv, argc, buf, sizeof(buf));
1220 if (! argp) {
1221 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
1222 return TCL_ERROR;
1223 }
1224 for (j = 0; argc > j; ++j) {
1225 if (! *argp[j]) {
1226 goto wuserr;
1227 }
1228 if ('-' == *argp[j]) {
1229 len = strlen (argp[j]);
1230 if (2 > len) {
1231 goto wuserr;
1232 }
1233 if (0 == strncmp ("-done", argp[j], len)) {
1234 del = !0;
1235 continue;
1236 }
1237 if (0 == strncmp ("-number", argp[j], len)) {
1238 if (argc <= ++j) {
1239 goto wuserr;
1240 }
1241 num = openIsisA2id (argp[j], -1, -1);
1242 if (0 > num) {
1243 goto wuserr;
1244 }
1245 continue;
1246 }
1247 if (0 == strncmp ("-tag", argp[j], len)) {
1248 if (argc <= ++j) {
1249 goto wuserr;
1250 }
1251 tag = openIsisA2id (argp[j], -1, 0);
1252 if (0 >= tag) {
1253 goto wuserr;
1254 }
1255 continue;
1256 }
1257 goto wuserr;
1258 }
1259 if (0 > tag && 0 == tgnm) {
1260 tgnm = argp[j];
1261 continue;
1262 }
1263 if (name) {
1264 goto wuserr;
1265 }
1266 name = argp[j];
1267 emb = TclCmd2Rec (ip, name, arg0);
1268 if (! emb) {
1269 goto wrperr;
1270 }
1271 } /* for argc */
1272
1273 if (tgnm) {
1274 OpenIsisFd *fd = openIsisFByName (that->fdt, tgnm);
1275 if (! fd) {
1276 Tcl_AppendResult (ip, arg0,
1277 ": no such field description: ", tgnm, 0);
1278 goto wrperr;
1279 }
1280 tag = fd->id;
1281 }
1282 if (0 > tag) {
1283 goto wuserr;
1284 }
1285 if (num && ! emb) {
1286 Tcl_AppendResult (ip, arg0, ": record to embed not given", 0);
1287 goto wrperr;
1288 }
1289
1290 if (0 <= num) {
1291 that->rec = openIsisRAddI (that->rec, tag, num, !0);
1292 if (num) {
1293 if (! emb->rec || ! (len = emb->rec->len)) {
1294 Tcl_AppendResult (ip, arg0,
1295 ": record to embed is empty", 0);
1296 goto wrperr;
1297 }
1298 that->rec = luti_append (that->rec, emb->rec);
1299 }
1300 if (! that->rec) {
1301 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
1302 goto wrperr;
1303 }
1304 }
1305 else {
1306 len = that->rec || emb->rec;
1307 that->rec = luti_wrap (that->rec, emb->rec, tag);
1308 if (len && ! that->rec) {
1309 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
1310 goto wrperr;
1311 }
1312 }
1313
1314 if (del && emb) {
1315 len = OpRec (emb, ip, name, RC_DONE, 0, 0);
1316 if (TCL_OK != len) {
1317 goto wrperr;
1318 }
1319 }
1320 if (argp != (char**)buf) {
1321 openIsisMFree (argp);
1322 }
1323 return TCL_OK;
1324
1325 wuserr:
1326 Tcl_AppendResult (ip, "usage: " , arg0, " wrap [-done] ",
1327 "[-number <numsubrecs>] {-tag <tag> | <tagname>} recname", 0);
1328 wrperr:
1329 if (argp != (char**)buf) {
1330 openIsisMFree (argp);
1331 }
1332 return TCL_ERROR;
1333 } /* RC_WRAP */
1334
1335 default: {
1336 char buf[654];
1337 openIsisI2a (buf, cmd);
1338 Tcl_AppendResult (ip, arg0, ": unrecognized command ", buf, 0);
1339 return TCL_ERROR;
1340 } /* default */
1341
1342 } /* switch */
1343 }
1344
1345 static int OpPath (
1346 OITRec *that, Tcl_Interp *ip, const char *arg0,
1347 Tcl_Obj *arg1, int argc, Tcl_Obj* const argv[]
1348 ) {
1349 char buf[128];
1350 OITSess *ois;
1351 const char *path;
1352 int cmd, rt;
1353
1354 if (! arg1) {
1355 return UsageRec (ip, arg0);
1356 }
1357 if (! arg0) {
1358 arg0 = "<openIsisRecord>";
1359 }
1360 if (! that || ! (ois = RecSess (that))) {
1361 Tcl_AppendResult (ip, arg0, ": record corrupted", 0);
1362 return TCL_ERROR;
1363 }
1364 if (ip != ois->ip) {
1365 Tcl_AppendResult (ip, arg0, ": session corrupted", 0);
1366 return TCL_ERROR;
1367 }
1368
1369 path = Tcl_GetStringFromObj (arg1, 0);
1370
1371 /* path to embedded rec */
1372 if ('.' == *path) {
1373 int type = RecType (that);
1374 switch (type) {
1375 case OIT_RS_RQS:
1376 { OITCont *con;
1377 OITRec *rec;
1378 const char *p2;
1379 int tag, occ;
1380 con = (OITCont*) that;
1381 if (strncmp (".fdt", path, 4)) {
1382 p2 = luti_parse_path (path, openIsisFdtRqs,
1383 0, &tag, &occ);
1384 if (0 == p2 || 0 < occ) {
1385 Tcl_AppendResult (ip, arg0,
1386 ": no such child: ", path, 0);
1387 return TCL_ERROR;
1388 }
1389 }
1390 else {
1391 p2 = path + 4;
1392 tag = -42;
1393 occ = 0;
1394 }
1395 if (! con->numr) {
1396 rt = BuildRqsRecs (con);
1397 if (0 > rt) {
1398 Tcl_AppendResult (ip, arg0,
1399 ": child allocation failure", 0);
1400 return TCL_ERROR;
1401 }
1402 }
1403 switch (tag) {
1404 case OPENISIS_COM_REC: rec = con->recs[0]; break;
1405 case OPENISIS_RQS_IDX: rec = con->recs[1]; break;
1406 case OPENISIS_COM_CFG: rec = con->recs[2]; break;
1407 case -42: rec = con->recs[3]; break;
1408 default:
1409 Tcl_AppendResult (ip, arg0,
1410 ": no such child: ", path, 0);
1411 return TCL_ERROR;
1412 }
1413 NewRecId (buf);
1414 if (*p2) {
1415 Tcl_Obj *obj = Tcl_NewStringObj (p2, (int) strlen (p2));
1416 if (obj) {
1417 Tcl_IncrRefCount (obj);
1418 rt = OpPath (rec, ip, buf, obj, argc, argv);
1419 Tcl_DecrRefCount (obj);
1420 return rt;
1421 }
1422 return TCL_ERROR;
1423 }
1424 if (! argc) {
1425 return CrtRecCmd (ois, buf, rec, !0);
1426 }
1427 return OpPath (rec, ip, buf, argv[0], argc - 1, argv + 1);
1428 }
1429 case OIT_RS_RSP:
1430 { OITCont *con;
1431 OITRec *rec;
1432 const char *p2;
1433 int tag, occ;
1434 con = (OITCont*) that;
1435 p2 = luti_parse_path (path, openIsisFdtRsp,
1436 0, &tag, &occ);
1437 if (0 == p2 ||
1438 OPENISIS_COM_REC != tag
1439 ) {
1440 Tcl_AppendResult (ip, arg0,
1441 ": no such child: ", path, 0);
1442 return TCL_ERROR;
1443 }
1444 if (!(rt = con->numr)) {
1445 rt = BuildRspRecs (con, ip, arg0);
1446 if (0 > rt) {
1447 return TCL_ERROR;
1448 }
1449 }
1450 if (0 > occ) {
1451 occ = 0;
1452 }
1453 if (rt <= occ) {
1454 sprintf (buf, "%d", rt);
1455 Tcl_AppendResult (ip, arg0, ": no such child: ", path,
1456 ", have ", buf, " childs", 0);
1457 return TCL_ERROR;
1458 }
1459 rec = con->recs[occ];
1460 NewRecId (buf);
1461 if (*p2) {
1462 Tcl_Obj *obj = Tcl_NewStringObj (p2, (int) strlen (p2));
1463 if (obj) {
1464 Tcl_IncrRefCount (obj);
1465 rt = OpPath (rec, ip, buf, obj, argc, argv);
1466 Tcl_DecrRefCount (obj);
1467 return rt;
1468 }
1469 return TCL_ERROR;
1470 }
1471 if (! argc) {
1472 return CrtRecCmd (ois, buf, rec, !0);
1473 }
1474 return OpPath (rec, ip, buf, argv[0], argc - 1, argv + 1);
1475 }
1476 default:
1477 { OpenIsisRec *rec;
1478 OITRec *oir;
1479 rec = luti_getembed (that->rec, path, that->fdt);
1480 if (! rec) {
1481 Tcl_AppendResult (ip, arg0,
1482 ": no such child: ", path, 0);
1483 return TCL_ERROR;
1484 }
1485 rt = NewRec (ois, 0,
1486 OIT_RS_DBF == RecType(that) ? openIsisFdtFd : 0,
1487 0);
1488 if (0 > rt) {
1489 Tcl_AppendResult (ip, "OpPath: out of memory", 0);
1490 return TCL_ERROR;
1491 }
1492 oir = ois->recs[rt];
1493 oir->rec = rec;
1494 NewRecId (buf);
1495 if (! argc) {
1496 return CrtRecCmd (ois, buf, oir, !0);
1497 }
1498 rt = OpPath (oir, ip, buf, argv[0], argc - 1, argv + 1);
1499 DtorRec (oir, 0);
1500 return rt;
1501 }
1502 }
1503 } /* path */
1504
1505 rt = Tcl_GetIndexFromObj (ip, arg1, OITOpts, "option", 0, &cmd);
1506 if (TCL_OK != rt) {
1507 return TCL_ERROR;
1508 }
1509 if (RC_LAST < cmd) {
1510 return UsageRec (ip, arg0);
1511 }
1512
1513 return OpRec (that, ip, arg0, (OITCmd)cmd, argc, argv);
1514 }
1515
1516 static int CmdRec (
1517 ClientData cld, Tcl_Interp *ip, int argc, Tcl_Obj* const argv[]
1518 ) {
1519 const char *arg0 = 0 >= argc ? 0 : Tcl_GetStringFromObj (argv[0], 0);
1520 if (1 >= argc) {
1521 return UsageRec (ip, arg0);
1522 }
1523 return OpPath ((OITRec*)cld, ip, arg0, argv[1], argc - 2, argv + 2);
1524 }
1525
1526 /* ============================== stubs ================================
1527 */
1528
1529 static int RspCb (
1530 void *cld, OpenIsisStub stb, OpenIsisRec *rsp, OpenIsisDb *db
1531 ) {
1532 OITStub *that = (OITStub*) cld;
1533 OITSess *ois;
1534 const char *res;
1535 int rt;
1536
1537 (void)db;
1538 if (! that) {
1539 return openIsisSMsg (OPENISIS_ERR_TRASH,
1540 "[openIsisTcl] RspCb: response without stub");
1541 }
1542 if (stb != that->stb) {
1543 return openIsisSMsg (OPENISIS_ERR_TRASH,
1544 "[openIsisTcl] RspCb: stub changed");
1545 }
1546 ois = StbSess (that);
1547 if (! ois) {
1548 return openIsisSMsg (OPENISIS_ERR_TRASH,
1549 "[openIsisTcl] RspCb: response without session");
1550 }
1551 if (! that->rqs) {
1552 return openIsisSMsg (OPENISIS_ERR_TRASH,
1553 "[openIsisTcl] RspCb: response without request");
1554 }
1555 if (that->rsp) {
1556 if (that->rsp->env.rec) {
1557 openIsisSMsg (OPENISIS_ERR_TRASH,
1558 "[openIsisTcl] RspCb: multiple responses");
1559 DtorRec ((OITRec*)that->rsp, 0);
1560 }
1561 }
1562
1563 rt = NewCont (ois, openIsisFdtRsp, OIT_RS_RSP);
1564 if (0 > rt) {
1565 return rt;
1566 }
1567 that->rsp = (OITCont*) ois->recs[rt];
1568 that->rsp->env.rec = rsp;
1569 that->rsp->stb = that->stb;
1570
1571 if (! that->actproc) {
1572 if (! that->dfltproc) {
1573 return 0;
1574 }
1575 rt = Tcl_EvalObj (ois->ip, that->dfltproc);
1576 }
1577 else {
1578 rt = Tcl_EvalObj (ois->ip, that->actproc);
1579 }
1580 res = Tcl_GetStringResult (ois->ip);
1581 if (! res) {
1582 res = "<null>";
1583 }
1584 if (TCL_ERROR == rt) {
1585 return openIsisSMsg (OPENISIS_ERR_IDIOT,
1586 "[openIsisTcl] callback eval: %s", res);
1587 }
1588 if (TCL_OK != rt) {
1589 openIsisSMsg (OPENISIS_LOG_WARN,
1590 "[openIsisTcl] callback eval = %d, %s", rt, res);
1591 return 0;
1592 }
1593 openIsisSMsg (OPENISIS_LOG_INFO,
1594 "[openIsisTcl] callback eval : %s", res);
1595 return 0;
1596 }
1597
1598 static void StbDelCb (void *cld, OpenIsisStub stb, void *cbd);
1599 static void TclDelStb (ClientData cld);
1600 static int CmdStub (
1601 ClientData cld, Tcl_Interp *ip, int argc, Tcl_Obj* const argv[]
1602 );
1603
1604 static OITStub* CtorStub (Tcl_Interp *ip,
1605 const char *name, int argc, const char **argv, const char *proc
1606 ) {
1607 OpenIsisStubCbData scd;
1608 OpenIsisSchema *sch;
1609 OITStub *that;
1610 int stat = 0;
1611
1612 if (! name) {
1613 name = OIT_STB0;
1614 stat = OIT_ST_ROOT;
1615 }
1616 if (! NumSessions) {
1617 openIsisSMsg (OPENISIS_ERR_TRASH,
1618 "[openIsisTcl] CtorStub(%s): no root session", name);
1619 return 0;
1620 }
1621 if (ip != Sessions->ip) {
1622 openIsisSMsg (OPENISIS_ERR_TRASH,
1623 "[openIsisTcl] CtorStub(%s): must not create stub in derived session",
1624 name);
1625 return 0;
1626 }
1627 that = (OITStub*) openIsisMAlloc (sizeof (OITStub));
1628 if (! that) {
1629 openIsisSMsg (OPENISIS_ERR_NOMEM,
1630 "[openIsisTcl] CtorStub(%s): out of memory", name);
1631 return 0;
1632 }
1633 that->cmd = openIsisMDup (name, -1);
1634 if (! that->cmd) {
1635 openIsisMFree (that);
1636 openIsisSMsg (OPENISIS_ERR_NOMEM,
1637 "[openIsisTcl] CtorStub(%s): out of memory", name);
1638 return 0;
1639 }
1640 that->ases = -1;
1641
1642 memset (&scd, 0, sizeof (OpenIsisStubCbData));
1643 scd.dfltcb = &RspCb;
1644 scd.delcb = &StbDelCb;
1645 scd.dfltcld = scd.delcld = that;
1646
1647 if (OIT_ST_ROOT & stat) {
1648 that->cfg.fdt = openIsisFdtSyspar;
1649 that->stb = openIsisNInit (argc, argv, &scd);
1650 }
1651 else {
1652 that->cfg.fdt = openIsisFdtScheme;
1653 that->stb = openIsisNOpen (name, argc, argv, &scd);
1654 }
1655 if (! that->stb) {
1656 openIsisMFree ((void*)that->cmd);
1657 openIsisMFree (that);
1658 openIsisSMsg (OPENISIS_ERR_IDIOT,
1659 "[openIsisTcl] CtorStub(%s): deficient configuration", name);
1660 return 0;
1661 }
1662
1663 sch = openIsisNSchema (that->stb);
1664 that->cfg.rec = sch->cfg;
1665 that->cfg.sid = 0;
1666 that->cfg.stat = OIT_RS_USED | OIT_RS_STC;
1667
1668 if (proc) {
1669 that->dfltproc = Tcl_NewStringObj (proc, (int) strlen (proc));
1670 if (that->dfltproc) {
1671 Tcl_IncrRefCount (that->dfltproc);
1672 }
1673 }
1674
1675 that->stat = stat | OIT_ST_TCL | OIT_ST_OINIT;
1676
1677 Tcl_CreateObjCommand (ip, (char*)that->cmd, &CmdStub, that, &TclDelStb);
1678 Tcl_SetResult (ip, (char*)that->cmd, TCL_VOLATILE);
1679 return that;
1680 }
1681
1682 static void DtorStub (OITStub *that, int where) {
1683 const char *cmd = that->cmd;
1684 if (! cmd) {
1685 cmd = "<<NULL>>";
1686 }
1687 if (! NumSessions) {
1688 openIsisSMsg (OPENISIS_ERR_TRASH,
1689 "[openIsisTcl] DtorStub(%s): no root session", cmd);
1690 return;
1691 }
1692 that->stat &= ~where;
1693 if (OIT_ST_TCL & that->stat) {
1694 if (! that->cmd) {
1695 openIsisSMsg (OPENISIS_ERR_TRASH,
1696 "[openIsisTcl] DtorStub: no command");
1697 return;
1698 }
1699 Tcl_DeleteCommand (Sessions->ip, (char*)that->cmd);
1700 return;
1701 }
1702 if (OIT_ST_OINIT & that->stat) {
1703 if (OIT_ST_ROOT & that->stat) {
1704 openIsisNDeinit ();
1705 }
1706 else {
1707 openIsisNClose (that->stb);
1708 }
1709 return;
1710 }
1711 if (that->dfltproc) {
1712 Tcl_DecrRefCount (that->dfltproc);
1713 }
1714 if (that->actproc) {
1715 Tcl_DecrRefCount (that->actproc);
1716 }
1717 if (that->rqs) {
1718 DtorRec ((OITRec*)that->rqs, 0);
1719 }
1720 if (that->rsp) {
1721 DtorRec ((OITRec*)that->rsp, 0);
1722 }
1723 /* that->cfg.rec holds the same ref as stub->cfg,
1724 which is freed in openIsisNClose
1725 */
1726 if (that->cmd) {
1727 openIsisMFree ((void*)that->cmd);
1728 }
1729 openIsisMFree (that);
1730 }
1731
1732 static void TclDelStb (ClientData cld) {
1733 DtorStub ((OITStub*)cld, OIT_ST_TCL);
1734 }
1735
1736 static void StbDelCb (void *cld, OpenIsisStub stb, void *cbd) {
1737 (void) stb;
1738 if (cbd) {
1739 if (((OITStub*)cbd)->actproc) {
1740 Tcl_DecrRefCount (((OITStub*)cbd)->actproc);
1741 ((OITStub*)cbd)->actproc = 0;
1742 }
1743 return;
1744 }
1745 DtorStub ((OITStub*)cld, OIT_ST_OINIT);
1746 }
1747
1748 static int BuildRqsCont (OITStub *that, Tcl_Interp *ip,
1749 const char *arg0, OITSess *ois, int *argc, Tcl_Obj* const **argv
1750 ) {
1751 OpenIsisDb *db;
1752 char *dbn;
1753 int rt;
1754 if (! that->rqs) {
1755 rt = NewCont (ois, openIsisFdtRqs, OIT_RS_RQS);
1756 if (0 > rt) {
1757 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
1758 return 0;
1759 }
1760 that->rqs = (OITCont*) ois->recs[rt];
1761 }
1762 if (1 < *argc &&
1763 0 == strcmp ("-db", Tcl_GetStringFromObj ((*argv)[0], 0))) {
1764 dbn = Tcl_GetStringFromObj ((*argv)[1], 0);
1765 db = openIsisNDbByName (that->stb, dbn);
1766 if (! db) {
1767 Tcl_AppendResult (ip, arg0, ": no such db: ", dbn, 0);
1768 return 0;
1769 }
1770 that->rqs->env.db = db;
1771 *argc -= 2;
1772 *argv += 2;
1773 }
1774 return !0;
1775 }
1776
1777 static const OpenIsisFdt* SysFdtFromName (const char *dbn, int len) {
1778 switch (dbn[1]) {
1779 case 'd':
1780 if (0 == strncmp (dbn, "-dbpar", len)) {
1781 return openIsisFdtDbpar;
1782 }
1783 return 0;
1784 case 'f':
1785 if ('d' == dbn[2]) {
1786 if (0 == dbn[3]) {
1787 return openIsisFdtFd;
1788 }
1789 if ('t' == dbn[3] && 0 == dbn[4]) {
1790 return openIsisFdtFdt;
1791 }
1792 }
1793 return 0;
1794 case 'r':
1795 if (3 < len) {
1796 if (0 == strncmp (dbn, "-request", len)) {
1797 return openIsisFdtRqs;
1798 }
1799 if (0 == strncmp (dbn, "-response", len)) {
1800 return openIsisFdtRsp;
1801 }
1802 }
1803 return 0;
1804 case 's':
1805 if (2 < len) {
1806 if (0 == strncmp (dbn, "-syspar", len)) {
1807 return openIsisFdtSyspar;
1808 }
1809 if (0 == strncmp (dbn, "-scheme", len)) {
1810 return openIsisFdtScheme;
1811 }
1812 }
1813 return 0;
1814 }
1815 return 0;
1816 }
1817
1818 static int UsageStub (Tcl_Interp *ip, const char *argv0) {
1819 Tcl_AppendResult (ip,
1820 "usage: ",
1821 (argv0 ? argv0 : "<openIsisStub>"),
1822 " db db ?option ...? |",
1823 " fdt db ?option ...? |",
1824 " new -schema name ?-cfg val ...? |",
1825 " new ?-db db? ?name? |",
1826 " recv |",
1827 " request ?-db db? ?-param val? |",
1828 " .req ?-db db? ?option ...? |",
1829 " .res ?option ...?",
1830 0);
1831 return TCL_ERROR;
1832 }
1833
1834 static int CmdStub (
1835 ClientData cld, Tcl_Interp *ip, int argc, Tcl_Obj* const argv[]
1836 ) {
1837 OITStub *that = (OITStub*) cld;
1838 OITSess *ois;
1839 const char *arg0;
1840 OITCmd cmd;
1841 int rt;
1842
1843 if (1 > argc) {
1844 return TCL_ERROR;
1845 }
1846 arg0 = Tcl_GetStringFromObj (argv[0], 0);
1847 if (2 > argc) {
1848 return UsageStub (ip, arg0);
1849 }
1850
1851 ois = StbSess (that);
1852 if (! ois) {
1853 if (! NumSessions) {
1854 Tcl_AppendResult (ip, arg0, ": no session", 0);
1855 return TCL_ERROR;
1856 }
1857 ois = Sessions;
1858 that->ases = 0;
1859 }
1860 if (ip != ois->ip) {
1861 Tcl_AppendResult (ip, arg0, ": session changed", 0);
1862 return TCL_ERROR;
1863 }
1864
1865 rt = Tcl_GetIndexFromObj (ip, argv[1], OITOpts, "option", 0, (int*)&cmd);
1866 if (TCL_OK != rt) {
1867 return UsageStub (ip, arg0);
1868 }
1869
1870 argc -= 2;
1871 argv += 2;
1872
1873 switch (cmd) {
1874
1875 case RC_DB: {
1876 OpenIsisDb *db;
1877 char *dbn;
1878 if (! argc) {
1879 return UsageStub (ip, arg0);
1880 }
1881 dbn = Tcl_GetStringFromObj (argv[0], 0);
1882 db = openIsisNDbByName (that->stb, dbn);
1883 if (! db) {
1884 Tcl_AppendResult (ip, arg0, ": no such db <", dbn, ">", 0);
1885 return TCL_ERROR;
1886 }
1887 return OpDb (ip, ois, db, argc - 1, argv + 1);
1888 } /* RC_DB */
1889
1890 case RC_DONE:
1891 Tcl_DeleteCommand (ip, (char*)arg0);
1892 return TCL_OK;
1893
1894 case RC_FDT: {
1895 const OpenIsisFdt *fdt = 0;
1896 OpenIsisDb *db;
1897 char *dbn;
1898 int len;
1899 if (! argc) {
1900 return UsageStub (ip, arg0);
1901 }
1902 dbn = Tcl_GetStringFromObj (argv[0], &len);
1903 if (1 < len && '-' == *dbn) {
1904 fdt = SysFdtFromName (dbn, len);
1905 }
1906 if (! fdt) {
1907 db = openIsisNDbByName (that->stb, dbn);
1908 if (! db) {
1909 Tcl_AppendResult (ip, arg0, ": no such db <", dbn, ">", 0);
1910 return TCL_ERROR;
1911 }
1912 fdt = db->fdt;
1913 if (! fdt) {
1914 Tcl_AppendResult (ip, arg0, ": ", dbn, " has no fdt", 0);
1915 return TCL_ERROR;
1916 }
1917 }
1918 return OpFdt (ip, ois, fdt, argc - 1, argv + 1);
1919 } /* RC_FDT */
1920
1921 case SC_NEW: {
1922 char buf[2048];
1923 OITStub *nstb = 0;
1924 const OpenIsisFdt *fdt = 0;
1925 OpenIsisDb *db = 0;
1926 const char *arg2 = 0;
1927 const char *dbn = 0;
1928 const char *proc = 0;
1929 char *name = 0;
1930 char **argp = 0;
1931 int len = 0;
1932 int dbl = 0;
1933
1934 switch (argc) {
1935 /* new record */
1936 case 0:
1937 goto newrec;
1938 case 1:
1939 name = Tcl_GetStringFromObj (argv[0], 0);
1940 goto newrec;
1941 case 3:
1942 arg2 = Tcl_GetStringFromObj (argv[0], &len);
1943 if (2 > len || 0 != strncmp ("-db", arg2, len)) {
1944 return UsageStub (ip, arg0);
1945 }
1946 dbn = Tcl_GetStringFromObj (argv[1], &dbl);
1947 name = Tcl_GetStringFromObj (argv[2], 0);
1948 newrec:
1949 if (1 < dbl && '-' == *dbn) {
1950 fdt = SysFdtFromName (dbn, dbl);
1951 }
1952 if (! fdt) {
1953 if (! dbn) {
1954 dbn = openIsisRString (that->cfg.rec,
1955 OPENISIS_SC_DFLTDB, 0, buf, sizeof(buf));
1956 if (! dbn) {
1957 Tcl_AppendResult (ip, arg0,
1958 ": no db specified", 0);
1959 return TCL_ERROR;
1960 }
1961 }
1962 db = openIsisNDbByName (that->stb, dbn);
1963 if (! db) {
1964 Tcl_AppendResult (ip, arg0,
1965 ": no such db <", dbn, ">", 0);
1966 return TCL_ERROR;
1967 }
1968 fdt = db->fdt;
1969 }
1970 rt = NewRec (ois, db, fdt, 0);
1971 if (0 > rt) {
1972 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
1973 return TCL_ERROR;
1974 }
1975 rt = CrtRecCmd (ois, name, ois->recs[rt], !0);
1976 return rt;
1977
1978 /* new stub */
1979 default:
1980 arg2 = Tcl_GetStringFromObj (argv[0], &len);
1981 if (2 > len) {
1982 return UsageStub (ip, arg0);
1983 }
1984 if (2 == argc && 0 == strncmp ("-db", arg2, len)) {
1985 dbn = Tcl_GetStringFromObj (argv[1], &dbl);
1986 goto newrec;
1987 }
1988 if (strncmp ("-schema", arg2, len) &&
1989 strncmp ("schema", arg2, len)) {
1990 return UsageStub (ip, arg0);
1991 }
1992 name = Tcl_GetStringFromObj (argv[1], 0);
1993 argc -= 2;
1994 argv += 2;
1995 if (0 < argc) {
1996 int j;
1997 argp = ToArgv (argv, argc, buf, sizeof (buf));
1998 if (! argp) {
1999 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
2000 return TCL_ERROR;
2001 }
2002 for (j = 0; argc > j; ++j) {
2003 if (0 == strcmp ("-async", argp[j]) &&
2004 argc > ++j) {
2005 proc = argp[j];
2006 }
2007 }
2008 }
2009 nstb = CtorStub (ip, name, argc, (const char**)argp, proc);
2010 if (argp && argp != (char**)buf) {
2011 openIsisMFree (argp);
2012 }
2013 if (! nstb) {
2014 Tcl_AppendResult (ip, arg0,
2015 ": deficient configuration for ", name,
2016 " or out of memory", 0);
2017 return TCL_ERROR;
2018 }
2019 return TCL_OK;
2020
2021 } /* switch (argc) */
2022 } /* SC_NEW */
2023
2024 case SC_RECV: {
2025 if (that->rsp && that->rsp->env.rec) {
2026 return TCL_OK;
2027 }
2028 Tcl_AppendResult (ip, arg0,
2029 ": waiting for response in async mode not implemented yet", 0);
2030 return TCL_ERROR;
2031 } /* SC_RECV */
2032
2033 case SC_RQS: {
2034 OpenIsisRec *rqs;
2035 if (that->rsp) {
2036 DtorRec ((OITRec*) that->rsp, 0);
2037 }
2038 if (! BuildRqsCont (that, ip, arg0, ois, &argc, &argv)) {
2039 return TCL_ERROR;
2040 }
2041 if (0 < argc) {
2042 Tcl_Obj *setcmd = Tcl_NewStringObj ("set", 3);
2043 if (! setcmd) {
2044 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
2045 return TCL_ERROR;
2046 }
2047 Tcl_IncrRefCount (setcmd);
2048 rt = OpPath (
2049 (OITRec*)that->rqs, ip, 0, setcmd, argc, argv);
2050 Tcl_DecrRefCount (setcmd);
2051 if (TCL_OK != rt) {
2052 return rt;
2053 }
2054 }
2055 rqs = that->rqs->env.rec;
2056 if (that->rqs->numr) {
2057 OpenIsisRec *rec;
2058 if ((rec = that->rqs->recs[0]->rec)) {
2059 rqs = luti_wrap (rqs, rec, OPENISIS_COM_REC);
2060 }
2061 if ((rec = that->rqs->recs[1]->rec)) {
2062 rqs = luti_wrap (rqs, rec, OPENISIS_RQS_IDX);
2063 }
2064 if ((rec = that->rqs->recs[2]->rec)) {
2065 rqs = luti_wrap (rqs, rec, OPENISIS_COM_CFG);
2066 }
2067 if ((rec = that->rqs->recs[3]->rec)) {
2068 rqs = luti_append (rqs, rec);
2069 }
2070 }
2071 if (! openIsisRGet (rqs, OPENISIS_COM_DBN, 0) && that->rqs->env.db) {
2072 OPENISIS_RADDS (rqs, OPENISIS_COM_DBN, that->rqs->env.db->name, !0);
2073 }
2074 rt = openIsisNSend (that->stb, that->rqs->env.rec = rqs, 0, 0, !0);
2075 that->rqs->env.db = 0; /* do never remember */
2076 if (0 != rt) {
2077 char buf[64];
2078 sprintf (buf, "%x", rt);
2079 Tcl_AppendResult (ip, arg0, ": error ", buf,
2080 " sending request", 0);
2081 return TCL_ERROR;
2082 }
2083 return TCL_OK;
2084 } /* SC_RQS */
2085
2086 case SC_ARQS: {
2087 if (! BuildRqsCont (that, ip, arg0, ois, &argc, &argv)) {
2088 return TCL_ERROR;
2089 }
2090 if (1 > argc) {
2091 return UsageStub (ip, arg0);
2092 }
2093 rt = OpPath (
2094 (OITRec*)that->rqs, ip, 0, argv[0], argc - 1, argv + 1);
2095 return rt;
2096 } /* SC_ARQS */
2097
2098 case SC_ARSP: {
2099 int hasrsp = that->rsp && that->rsp->env.rec;
2100 if (1 > argc) {
2101 Tcl_SetObjResult (ip, Tcl_NewBooleanObj (hasrsp));
2102 return TCL_OK;
2103 }
2104 if (! hasrsp) {
2105 Tcl_AppendResult (ip, arg0, ": no response available", 0);
2106 return TCL_ERROR;
2107 }
2108 rt = OpPath (
2109 (OITRec*)that->rsp, ip, 0, argv[0], argc - 1, argv + 1);
2110 return rt;
2111 } /* SC_ARSP */
2112
2113 default: {
2114 /* record commands */
2115 OpenIsisSchema *sch;
2116 rt = OpRec (&that->cfg, ip, arg0, cmd, argc, argv);
2117 sch = openIsisNSchema (that->stb);
2118 /* sch->cfg is a reference to our cfg at every time,
2119 OpRec changes with RDIS, so we dont free the old rec here
2120 */
2121 sch->cfg = that->cfg.rec;
2122 return rt;
2123 } /* default */
2124
2125 } /* switch cmd */
2126 }
2127
2128 static int CmdInit (
2129 ClientData cld, Tcl_Interp *ip, int argc, const char *argv[]
2130 ) {
2131 OITStub *news;
2132 const char *proc = 0;
2133 int j, len;
2134
2135 (void)cld;
2136
2137 if (openisis_stub0) {
2138 Tcl_CmdInfo info;
2139 if (Tcl_GetCommandInfo (ip, OIT_STB0, &info)) {
2140 Tcl_SetResult (ip, OIT_STB0, TCL_STATIC);
2141 return TCL_OK;
2142 }
2143 }
2144
2145 for (j = 1; argc > j; ++j) {
2146 if (! argv[j] || ! (len = strlen (argv[j]))) {
2147 goto usage;
2148 }
2149 if ('-' == *argv[j]) {
2150 if (! strncmp ("-async", argv[j], (unsigned) len)) {
2151 if (argc <= ++j) {
2152 goto usage;
2153 }
2154 proc = argv[j];
2155 continue;
2156 }
2157 }
2158 break;
2159 }
2160
2161 /* openIsisNInit can be called multiple times */
2162 news = CtorStub (ip, 0, argc - j, argv + j, proc);
2163 if (! news) {
2164 Tcl_AppendResult (ip, OIT_STB0, ": out of memory", 0);
2165 return TCL_ERROR;
2166 }
2167 return TCL_OK;
2168
2169 usage:
2170 Tcl_AppendResult (ip,
2171 "usage: ", argv[0], " ?-async <cb>? ?options?", 0);
2172 return TCL_ERROR;
2173 }
2174
2175 static int CmdOIR (
2176 ClientData cld, Tcl_Interp *ip, int argc, Tcl_Obj* const argv[]
2177 ) {
2178 OITSess *ois;
2179 OITRec *rec, *rfdt;
2180 const OpenIsisFdt *fdt;
2181 char *fname;
2182 const char *rname;
2183 char buf[64];
2184 int j, rt, len, ownf;
2185
2186 (void)cld;
2187 if (! NumSessions) {
2188 Tcl_AppendResult (ip, "session not initialized", 0);
2189 return TCL_ERROR;
2190 }
2191 ois = Sessions;
2192
2193 rec = 0;
2194 rname = 0;
2195 fdt = 0;
2196 ownf = 0;
2197 for (j = 1; argc > j; ++j) {
2198 fname = Tcl_GetStringFromObj (argv[j], &len);
2199 if (! fdt && 2 <= len && 0 == strncmp ("-fdt", fname, len)) {
2200 if (argc <= ++j) {
2201 Tcl_AppendResult (ip,
2202 "usage: openIsisRec ?-fdt name? ?options...?", 0);
2203 return TCL_ERROR;
2204 }
2205 fname = Tcl_GetStringFromObj (argv[j], &len);
2206 if (len && '-' == *fname) {
2207 fdt = SysFdtFromName (fname, len);
2208 }
2209 if (! fdt) {
2210 rfdt = TclCmd2Rec (ip, fname, "openIsisRec");
2211 if (! rfdt) {
2212 return TCL_ERROR;
2213 }
2214 fdt = openIsisFRec2Fdt (rfdt->rec);
2215 if (! fdt) {
2216 Tcl_AppendResult (ip, fname, " is an illegal fdt", 0);
2217 return TCL_ERROR;
2218 }
2219 ownf = !0;
2220 }
2221 if (rname) {
2222 ++j;
2223 break;
2224 }
2225 continue;
2226 }
2227 if (rname) {
2228 break;
2229 }
2230 rname = fname;
2231 }
2232
2233 if (! rname || ! *rname) {
2234 rname = NewRecId (buf);
2235 }
2236
2237 rt = NewRec (ois, 0, fdt, ownf ? OIT_RS_OWNF : 0);
2238 if (0 > rt) {
2239 Tcl_AppendResult (ip, Tcl_GetStringFromObj (argv[0], 0),
2240 ": out of memory", 0);
2241 goto error;
2242 }
2243 rec = ois->recs[rt];
2244
2245 if (j < argc - 1) {
2246 rt = OpPath (rec, ip, rname, argv[j], argc - (j+1), argv + (j+1));
2247 if (TCL_OK != rt) {
2248 goto error;
2249 }
2250 }
2251
2252 rt = CrtRecCmd (ois, rname, rec, !0);
2253 if (TCL_OK == rt) {
2254 return TCL_OK;
2255 }
2256 error:
2257 if (rec) {
2258 DtorRec (rec, 0);
2259 }
2260 else if (ownf) {
2261 openIsisFFree ((OpenIsisFdt*)fdt);
2262 }
2263 return TCL_ERROR;
2264 }
2265
2266 static void FreeEnc ();
2267 static void AtExit (ClientData cld) {
2268 (void)cld;
2269 openIsisNDeinit ();
2270 ExitSess ();
2271 FreeEnc ();
2272 }
2273
2274 static void AddCmds (Tcl_Interp *ip, int root) {
2275 Tcl_CreateCommand (ip, "openIsis",
2276 (Tcl_CmdProc*)CmdInit, 0, root ? &AtExit : 0);
2277 Tcl_CreateObjCommand (ip, "openIsisRec", &CmdOIR, 0, 0);
2278 }
2279
2280 /* ===================== command evaluation ============================
2281 */
2282
2283 static int CmdEval (OpenIsisRec *cmd, OpenIsisRec **rsp) {
2284 Tcl_DString ds;
2285 OpenIsisField *F, *E;
2286 OpenIsisSession ois;
2287 OpenIsisRec *recs[1] = { 0 };
2288 int rid[1];
2289 int rt;
2290
2291 ois = SESGET ();
2292 if (NumSessions <= ois->id) {
2293 return openIsisSMsg (OPENISIS_ERR_TRASH,
2294 "[openIsisTcl] CmdEval: no ip for ses %d[%d]",
2295 ois->id, NumSessions);
2296 }
2297
2298 rid[0] = openIsisTclCreateRecCmd (ois->id, "result", 0, 0);
2299 if (0 > rid[0]) {
2300 return openIsisSMsg (OPENISIS_ERR_NOMEM,
2301 "[openIsisTcl] CmdEval: cannot allocate result cmd");
2302 }
2303
2304 rt = 0;
2305 Tcl_DStringInit (&ds);
2306 for (E = (F = cmd->field) + cmd->len; E > F; ++F) {
2307 if (rt) {
2308 Tcl_DStringAppend (&ds, ";", 1);
2309 }
2310 rt = !0;
2311 Tcl_DStringAppend (&ds, F->val, F->len);
2312 }
2313 rt = openIsisTclEval (ois->id, 1, rid, recs, Tcl_DStringValue (&ds));
2314 Tcl_DStringFree (&ds);
2315
2316 /* record freed in ldsp */
2317 Sessions[ois->id].recs[rid[0]]->rec = 0;
2318 *rsp = recs[0];
2319
2320 return rt;
2321 }
2322
2323 OpenIsisEvalFunc *openIsisEval = &CmdEval;
2324
2325 /* =========================== encoding ================================
2326 */
2327
2328 static Tcl_HashTable Encodings;
2329 static int InitEnc = 0;
2330
2331 static Tcl_Encoding GetEnc (Tcl_Interp *ip, const char *name, int *frs) {
2332 Tcl_HashEntry *he;
2333 Tcl_Encoding enc;
2334 int nw;
2335 if (! InitEnc) {
2336 Tcl_InitHashTable (&Encodings, TCL_STRING_KEYS);
2337 InitEnc = !0;
2338 }
2339 he = Tcl_FindHashEntry (&Encodings, name);
2340 if (he) {
2341 return (Tcl_Encoding) Tcl_GetHashValue (he);
2342 }
2343 enc = Tcl_GetEncoding (ip, name);
2344 he = Tcl_CreateHashEntry (&Encodings, name, &nw);
2345 Tcl_SetHashValue (he, enc);
2346 if (frs && ! enc) {
2347 *frs = !0;
2348 }
2349 return enc;
2350 }
2351
2352 static void FreeEnc () {
2353 if (InitEnc) {
2354 Tcl_Encoding enc;
2355 Tcl_HashSearch hs;
2356 Tcl_HashEntry *he;
2357 for (he = Tcl_FirstHashEntry (&Encodings, &hs);
2358 he;
2359 he = Tcl_NextHashEntry (&hs)
2360 ) {
2361 enc = (Tcl_Encoding) Tcl_GetHashValue (he);
2362 if (enc) {
2363 Tcl_FreeEncoding (enc);
2364 }
2365 }
2366 Tcl_DeleteHashTable (&Encodings);
2367 InitEnc = 0;
2368 }
2369 }
2370
2371 static const char* TrfEnc (const char *ename,
2372 const char *src, int slen, char *dst, int dlen, int invert
2373 ) {
2374 Tcl_Encoding enc;
2375 Tcl_DString str;
2376 char *tgt;
2377 int tlen, frs;
2378
2379 if (! ename) {
2380 if (src) {
2381 openIsisMFree ((void*)src);
2382 }
2383 return 0;
2384 }
2385
2386 if (! src || 0 >= slen) {
2387 return src;
2388 }
2389 /* tclEncoding.c says that a null interp is ok */
2390 frs = 0;
2391 enc = GetEnc (0, ename, &frs);
2392 if (frs) {
2393 openIsisSMsg (OPENISIS_ERR_INVAL,
2394 "[openIsisTcl] TrfEnc: no such encoding <%s>", ename);
2395 return src;
2396 }
2397
2398 Tcl_DStringInit (&str);
2399 if (invert) {
2400 tgt = Tcl_UtfToExternalDString (enc, src, slen, &str);
2401 }
2402 else {
2403 tgt = Tcl_ExternalToUtfDString (enc, src, slen, &str);
2404 }
2405 tlen = Tcl_DStringLength (&str);
2406 if (! dst || tlen >= dlen) {
2407 dst = (char*) openIsisMAlloc (1 + tlen);
2408 if (! dst) {
2409 return 0;
2410 }
2411 }
2412 memcpy (dst, tgt, tlen);
2413 dst[tlen] = 0;
2414 Tcl_DStringFree (&str);
2415 return dst;
2416 }
2417
2418 OpenIsisEnc2Utf8Func *openIsisEnc2Utf8 = &TrfEnc;
2419
2420 /* ************************************************************
2421 public functions
2422 */
2423
2424 int openIsisTclNewSession (Tcl_Interp *ip) {
2425 int id;
2426 for (id = 0; NumSessions > id; ++id) {
2427 if (ip == Sessions[id].ip) {
2428 return id;
2429 }
2430 }
2431 id = CtorSess (ip);
2432 if (0 <= id) {
2433 AddCmds (ip, 0 == id);
2434 }
2435 return id;
2436 }
2437
2438 int openIsisTclGetSession (int sid, Tcl_Interp **ip) {
2439 if (0 > sid || NumSessions <= sid) {
2440 return 0;
2441 }
2442 if (ip) {
2443 *ip = Sessions[sid].ip;
2444 }
2445 return !0;
2446 }
2447
2448 /*
2449 void openIsisTclDelSession (int sid) {
2450 if (! sid) {
2451 ExitSess ();
2452 return;
2453 }
2454 if (0 < sid && NumSessions > sid) {
2455 DtorSess (Sessions + sid);
2456 }
2457 }
2458 */
2459
2460
2461 int openIsisTclCreateRecCmd (
2462 int sid, const char *nam, const char *fn, int flg
2463 ) {
2464 OITSess *ois = Sessions+sid;
2465 OpenIsisFdt *fdt = 0;
2466 int rid;
2467 (void)flg; /* TODO: set readonly */
2468 if (fn) {
2469 OITRec *oitf = TclCmd2Rec (ois->ip, fn, 0);
2470 if (! oitf) {
2471 openIsisSMsg (OPENISIS_ERR_INVAL,
2472 "[openIsisTcl] createRecCmd: no such fdt %s", fn);
2473 }
2474 fdt = openIsisFRec2Fdt (oitf->rec);
2475 if (! fdt) {
2476 openIsisSMsg (OPENISIS_ERR_INVAL,
2477 "[openIsisTcl] createRecCmd: illegal fdt %s", fn);
2478 }
2479 }
2480 rid = NewRec( ois, 0, fdt, fdt ? OIT_RS_OWNF : 0 );
2481 if ( 0 <= rid ) {
2482 CrtRecCmd( ois, nam, ois->recs[rid], 0 );
2483 }
2484 return rid;
2485 } /* openIsisTclCreateRecCmd */
2486
2487
2488 int openIsisTclEval ( int sid,
2489 int cnt, const int *ids, OpenIsisRec **recs, char *script )
2490 {
2491 OITSess *ois = Sessions+sid;
2492 int ret, i;
2493
2494 if ( recs )
2495 for ( i=cnt; i--; )
2496 ois->recs[ ids[i] ]->rec = recs[i];
2497 ret = Tcl_Eval( ois->ip, script );
2498 if ( recs )
2499 for ( i=cnt; i--; )
2500 recs[i] = ois->recs[ ids[i] ]->rec;
2501 return ret;
2502 } /* openIsisTclEval */
2503
2504
2505 int openIsisTclInit (Tcl_Interp *ip) {
2506 if (! NumSessions) {
2507 CtorSess (ip);
2508 }
2509 AddCmds (ip, !0);
2510 Tcl_CreateExitHandler (&AtExit, 0);
2511 return TCL_OK;
2512 }
2513

  ViewVC Help
Powered by ViewVC 1.1.26