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
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.
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.
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
20 see README for more information
24 $Id: openisistcl.c,v 1.77 2003/06/24 11:01:53 mawag Exp $
30 #include "openisistcl.h"
38 #include "ldsp.h" /* openIsisEnc2Utf8,openIsisEval */
39 #include "lses.h" /* SESGET() */
42 include this after the Tcl stuff for the benefit of those
43 who use the 150% braindead gcc 2.96
45 declaration of `index' shadows global declaration
47 cause string.h declares
48 char *index(const char *s, int c)
57 #define snprintf _snprintf
62 unusable because of POSIX stdfoo.h braindamage
63 -- they mix up MT with reentrant.
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.
74 from /opt/TclTk/tcl8.3.5/unix/configure:
77 # Note: If _REENTRANT isn't defined, then Solaris
78 # won't define thread-safe library routines.
80 cat >> confdefs.h <<\EOF
85 extern int openisis_threaded;
86 static int *link_dummy = &openisis_threaded; /* force correct linkage */
90 /* ============================ types ==================================
93 /* name of local schema */
94 #define OIT_STB0 "openIsisRoot"
101 RC_DB, /* stub, too */
105 RC_DONE, /* stub, too */
106 RC_FDT, /* stub, too */
114 RC_LAST = RC_WRAP, /* used for checking last rec cmd */
123 static const char *OITOpts[] = {
124 /* record commands */
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 */
160 #define RecType(r) (0x01F00 & (r)->stat)
161 #define NonWritable(r) (0x01A00 & (r)->stat)
162 #define NonDeletable(r) (0x00700 & (r)->stat)
164 typedef struct OITSess OITSess;
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 */
176 (0 <= ((OITRec*)(r))->sid && NumSessions > ((OITRec*)(r))->sid ? \
177 Sessions + ((OITRec*)(r))->sid : 0)
182 OITRec **recs; /* embedded recs */
186 #define OIT_ST_ROOT 0x0001
187 #define OIT_ST_TCL 0x0002
188 #define OIT_ST_OINIT 0x0004
192 OITRec cfg; /* direct schema copy allocated by ses0 */
195 const char *cmd; /* associated tcl ip cmd */
198 int ases; /* act session of rqs and rsp */
202 #define StbSess(s) (0 <= (s)->ases && NumSessions > (s)->ases ? \
203 Sessions + (s)->ases : 0)
212 static OITSess *Sessions = 0;
213 static int NumSessions = 0;
215 /* ============================ records ================================
218 #define OIT_RECINCR 32
219 #define OIT_MAXRECS 65535
220 #define OIT_SESSINCR 1
221 #define OIT_MAXSESS 255
223 static void CtorRec (OITRec *that, int sid, int siz) {
224 memset (that, 0, (unsigned)siz);
229 static int AllcRec (OITSess *ois, int siz, int type) {
231 if (siz > OIT_RS_SZM) {
232 return openIsisSMsg (OPENISIS_ERR_TRASH,
233 "[openIsisTcl] AllcRec: unexpected size %d", siz);
235 for (j = ois->numr; 0 <= --j; ) {
236 if (! ois->recs[j]) {
239 if (! (OIT_RS_USED & ois->recs[j]->stat) &&
240 siz == (OIT_RS_SZM & ois->recs[j]->stat) /* may be <= */
246 &ois->recs, &ois->numr, OIT_RECINCR, sizeof (OITRec*), OIT_MAXRECS);
248 return openIsisSMsg (OPENISIS_ERR_TRASH,
249 "[openIsisTcl] AllcRec: out of memory");
252 ois->recs[j] = (OITRec*) openIsisMAlloc (siz);
253 if (! ois->recs[j]) {
254 return openIsisSMsg (OPENISIS_ERR_TRASH,
255 "[openIsisTcl] AllcRec: out of memory");
257 CtorRec (ois->recs[j], ois->six, siz);
259 ois->recs[j]->stat |= type | OIT_RS_USED;
264 OITSess *ois, OpenIsisDb *db, const OpenIsisFdt *fdt, int type
266 int j = AllcRec (ois, sizeof (OITRec), type);
268 ois->recs[j]->db = db;
269 ois->recs[j]->fdt = fdt;
274 static int NewCont (OITSess *ois, const OpenIsisFdt *fdt, int type) {
275 int j = AllcRec (ois, sizeof (OITCont), type);
277 ois->recs[j]->fdt = fdt;
282 static void DtorRecs (OITRec **recs, int numr, int frmem);
284 static void DtorRec (OITRec *that, int frmem) {
289 ois = RecSess (that);
291 openIsisSMsg (OPENISIS_ERR_TRASH,
292 "[openIsisTcl] DtorRec: illegal sid %d(%d)",
293 that->sid, NumSessions);
298 that->stat |= OIT_RS_FRE;
300 Tcl_DeleteCommand (ois->ip, (char*)that->cmd);
303 type = RecType (that);
304 siz = OIT_RS_SZM & that->stat;
309 openIsisMFree (that->rec);
313 /* that->rec = 0; readonly cfg handled by db */
317 openIsisMFree (that->rec);
321 /* that->rec = 0; response record handled by stub */
322 con = (OITCont*)that;
323 DtorRecs (con->recs, con->numr, 0);
326 /* OIT_RS_STC embedded in OITStub and handled by stub */
327 openIsisSMsg (OPENISIS_ERR_TRASH,
328 "[openIsisTcl] DtorRec: unexpected type %x", type);
331 if ((OIT_RS_OWNF & that->stat)) {
332 openIsisFFree ((OpenIsisFdt*)that->fdt);
334 if (frmem || (OIT_RS_FRE & that->stat)) {
335 openIsisMFree (that);
338 CtorRec (that, ois->six, siz);
343 static void DtorRecs (OITRec **recs, int numr, int frmem) {
345 while (0 <= --numr) {
346 DtorRec (recs[numr], frmem);
348 openIsisMFree (recs);
352 static int CtorSess (Tcl_Interp *ip) {
353 int j = luti_ptrincr (
354 &Sessions, &NumSessions, OIT_SESSINCR, sizeof (OITSess), OIT_MAXSESS);
363 static void DtorSess (OITSess *that) {
364 DtorRecs (that->recs, that->numr, !0);
367 static void ExitSess () {
370 for (j = NumSessions; 0 <= --j; ) {
371 DtorSess (Sessions + j);
373 openIsisMFree (Sessions);
379 /* ---------------------------------------------------------------------
382 static unsigned _RecId = 0;
384 static char* NewRecId (char *buf) {
385 sprintf (buf, "openIsisRec%u", ++_RecId);
389 static void TclDelRec (ClientData cld) {
390 OITRec *that = (OITRec*)cld;
392 openIsisMFree ((void*)that->cmd);
395 DtorRec ((OITRec*)cld, 0);
399 ClientData rid, Tcl_Interp *ip, int argc, Tcl_Obj* const argv[]
402 static int CrtRecCmd (OITSess *ois, const char *name, OITRec *rec, int srst) {
404 if (! name || ! *name) {
405 name = NewRecId (buf);
407 rec->cmd = (const char*) openIsisMDup (name, -1);
409 Tcl_AppendResult (ois->ip, "CrtRecCmd: out of memory", 0);
412 Tcl_CreateObjCommand (ois->ip, (char*)name, &CmdRec, rec, &TclDelRec);
414 Tcl_SetResult (ois->ip, (char*)name, TCL_VOLATILE);
419 static char **ToArgv (
420 Tcl_Obj* const objv[], int objc, char* buf, int siz
425 int stav = objc * sizeof (char*);
428 for (j = 0; objc > j; ++j) {
429 str = Tcl_GetStringFromObj (objv[j], &len);
430 nsz = posv + 1 + len;
435 nb = (char*) openIsisMAlloc (nsz);
437 openIsisSMsg (OPENISIS_ERR_NOMEM,
438 "[openIsisTcl] ToArgv: out of memory");
442 for (k = j, S = (char**)res, T = (char**)nb ; 0 <= --k; ) {
445 memcpy (nb + stav, res + stav, (unsigned)(posv - stav));
452 *(char**)(res + posp) = res + posv;
453 ((char*) memcpy (res + posv, str, len)) [len] = 0;
454 posp += sizeof (char*);
460 static OITRec* TclCmd2Rec (
461 Tcl_Interp *ip, const char *cmd, const char *arg0
466 Tcl_AppendResult (ip, arg0, ": record command not given", 0);
470 if (! Tcl_GetCommandInfo (ip, cmd, &info)) {
472 Tcl_AppendResult (ip, arg0, ": no such record: ", cmd, 0);
476 if (info.objProc != &CmdRec) {
478 Tcl_AppendResult (ip, arg0, ": ", cmd, " is not a record", 0);
482 if (! info.objClientData) {
484 Tcl_AppendResult (ip, arg0, ": ", cmd, " is corrupted", 0);
488 return (OITRec*) info.objClientData;
491 static int BuildEmbRecs (
492 OITCont *that, OpenIsisRec **recs, int numr, int frr
499 ois = RecSess (that);
501 return openIsisSMsg (OPENISIS_ERR_TRASH,
502 "[openIsisTcl] BuildEmbRecs: illegal sid %d(%d)",
503 that->env.sid, NumSessions);
505 oirs = (OITRec**) openIsisMAlloc ( (int) (numr * sizeof (OITRec*)));
508 luti_free ((void**)recs, numr);
510 return openIsisSMsg (OPENISIS_ERR_NOMEM,
511 "[openIsisTcl] BuildEmbRecs(%d): out of memory", numr);
514 idx = (int*) openIsisMAlloc ( (int) (numr * sizeof (int)));
517 luti_free ((void**)recs, numr);
519 openIsisMFree (oirs);
520 return openIsisSMsg (OPENISIS_ERR_NOMEM,
521 "[openIsisTcl] BuildEmbRecs(%d): out of memory", numr);
524 for (j = numr; 0 <= --j; ) {
525 idx[j] = NewRec (ois, 0, 0, 0);
528 luti_free ((void**)recs, numr);
530 openIsisMFree (oirs);
534 return openIsisSMsg (OPENISIS_ERR_NOMEM,
535 "[openIsisTcl] BuildEmbRecs(%d): out of memory", numr);
538 for (j = numr; 0 <= --j; ) {
539 oirs[j] = ois->recs[idx[j]];
540 oirs[j]->rec = recs[j];
548 openIsisMFree (recs);
553 static int BuildRqsRecs (OITCont *that) {
554 OpenIsisRec *recs[4] = { 0, 0, 0, 0 }; /* REC, IDX, CFG, fdt */
556 numr = BuildEmbRecs (that, recs, 4, 0);
558 if ((that->recs[0]->db = that->env.db)) {
559 that->recs[0]->fdt = that->env.db->fdt;
561 that->recs[2]->fdt = openIsisFdtDbpar;
562 that->recs[3]->fdt = openIsisFdtFdt;
567 static int BuildRspRecs (OITCont *that, Tcl_Interp *ip, const char *arg0) {
570 int *rows; /* save rowid in recs */
572 numr = openIsisNGetResult (that->stb, &rows, &recs, &db, 0);
574 Tcl_AppendResult (ip, arg0,
575 ": child allocation failure", 0);
579 openIsisMFree (rows);
581 if (0 == numr || ! recs) {
584 j = BuildEmbRecs (that, recs, numr, !0);
586 Tcl_AppendResult (ip, arg0,
587 ": child allocation failure", 0);
591 for (j = numr; 0 <= --j; ) {
592 that->recs[j]->db = db;
593 that->recs[j]->fdt = db->fdt;
599 static int UsageRec (Tcl_Interp *ip, const char *arg0) {
601 arg0 = "<openIsisRecord>";
603 Tcl_AppendResult (ip,
605 " add field value ?field value ...? |",
606 " clone ?options? newname ?field value ...? |",
609 " delete ?field ...? |",
610 " deserialize line |",
611 " do ?tagvar? valvar body |",
614 " format ?options? format |",
615 " get ?-tags | -tagnames | field ...? |",
618 " set field ?value field value ...? |",
619 " wrap ?options? recname |",
620 " .path ?option arg ...?",
626 OITRec *that, Tcl_Interp *ip, const char *arg0,
627 Tcl_Obj *arg1, int argc, Tcl_Obj* const argv[]
630 static int OpDb (Tcl_Interp *ip,
631 OITSess *ois, OpenIsisDb *db, int argc, Tcl_Obj* const argv[]
635 rt = NewRec (ois, 0, openIsisFdtDbpar, OIT_RS_DBC);
637 Tcl_AppendResult (ip, "openIsisDb: out of memory", 0);
643 rt = OpPath (oir, ip, "openIsisDb", argv[0], argc - 1, argv + 1);
647 return CrtRecCmd (ois, 0, oir, !0);
650 static int OpFdt (Tcl_Interp *ip,
651 OITSess *ois, const OpenIsisFdt *fdt, int argc, Tcl_Obj* const argv[]
655 rt = NewRec (ois, 0, openIsisFdtFdt, OIT_RS_DBF);
657 Tcl_AppendResult (ip, "openIsisFdt: out of memory", 0);
661 oir->rec = openIsisFFdt2Rec (fdt, 0, 0);
663 rt = OpPath (oir, ip, "openIsisFdt", argv[0], argc - 1, argv + 1);
667 return CrtRecCmd (ois, 0, oir, !0);
670 #define FldObj( f ) Tcl_NewStringObj( (f)->val, (f)->len )
672 static Tcl_Obj* FdObj (OpenIsisField *fld, const OpenIsisFdt *fdt) {
674 OpenIsisFd *fd = openIsisFById (fdt, fld->tag, 0);
676 return Tcl_NewStringObj (fd->name, -1);
679 return Tcl_NewIntObj (fld->tag);
683 OITRec *that, Tcl_Interp *ip, const char *arg0,
684 const OITCmd cmd, int argc, Tcl_Obj* const argv[]
686 OITSess *ois = RecSess (that);
688 Tcl_AppendResult (ip, arg0, ": record corrupted", 0);
703 return UsageRec (ip, arg0);
710 setf = OPENISIS_RCHG;
713 if (NonWritable (that)) {
714 Tcl_AppendResult (ip, arg0, ": readonly record", 0);
717 args = argp = ToArgv (argv, argc, buf, sizeof (buf));
719 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
723 if ('-' != args[0][0]) {
726 len = strlen (args[0]);
727 if (1 == len || '-' == args[0][1]) {
730 if (0 == strncmp ("-ignore", args[0], len)) {
731 setf |= OPENISIS_RIGN;
739 if (0 == strncmp ("-default", args[0], len)) {
740 setf = OPENISIS_RDFLT | (OPENISIS_RIGN & setf);
748 that->rec = openIsisRSet (oldrec,
749 OPENISIS_RARGV | OPENISIS_RFDT | OPENISIS_RDIS | setf | argc,
751 if (argp != (char**)buf) {
752 openIsisMFree (argp);
754 if (! that->rec && (oldrec || (argc && !(OPENISIS_RIGN & setf)))) {
755 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
759 } /* RC_SET, RC_ADD */
769 if ((OIT_RS_RQS | OIT_RS_RSP) & that->stat) {
770 Tcl_AppendResult (ip, arg0,
771 ": container cloning not allowed", 0);
774 for (j = 0; argc > j; ++j) {
775 opt = Tcl_GetStringFromObj (argv[j], &len);
777 return UsageRec (ip, arg0);
787 if (0 == strncmp ("-empty", opt, len)) {
791 return UsageRec (ip, arg0);
793 if (argc > j && ! nn) {
794 name = Tcl_GetStringFromObj (argv[j], &len);
796 return UsageRec (ip, arg0);
801 name = NewRecId (buf);
803 id = NewRec (ois, that->db, that->fdt, 0);
805 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
808 nrec = ois->recs[id];
810 nrec->rec = openIsisRDup (that->rec, 0, 0);
814 ip, name, RC_SET, argc - j, argv + j);
819 rt = CrtRecCmd (ois, name, ois->recs[id], !0);
829 return UsageRec (ip, arg0);
831 src = TclCmd2Rec (ip, Tcl_GetStringFromObj (argv[0], 0), arg0);
835 if (! src->rec || ! src->rec->len) {
836 Tcl_SetResult (ip, "0", TCL_STATIC);
839 fld = src->rec->field;
841 sprintf (buf, "%d", j);
842 Tcl_SetResult (ip, buf, TCL_VOLATILE);
844 OPENISIS_RADD (that->rec, fld->tag, fld->val, fld->len, !0);
853 Tcl_AppendResult (ip, arg0, ": no db", 0);
856 return OpDb (ip, ois, that->db, argc, argv);
859 if (NonWritable (that)) {
860 Tcl_AppendResult (ip, arg0, ": readonly record", 0);
865 char **argp = ToArgv (argv, argc, buf, sizeof (buf));
867 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
870 that->rec = openIsisRSet (that->rec,
871 OPENISIS_RARGV | OPENISIS_RFDT | OPENISIS_RDEL | argc,
873 if (argp != (char**)buf) {
874 openIsisMFree (argp);
879 OPENISIS_CLRREC( that->rec );
881 if (OIT_RS_RQS == RecType (that)) {
882 OITCont *con = (OITCont*)that;
884 DtorRecs (con->recs, con->numr, 0);
901 return UsageRec (ip, arg0);
903 valvar = argv[--argc];
907 /* prepare object for var */
908 if ( ! Tcl_ObjSetVar2( ip, valvar, 0,
909 val = Tcl_NewObj(), TCL_LEAVE_ERR_MSG )
912 if ( tagvar && ! Tcl_ObjSetVar2( ip, tagvar, 0,
913 tag = Tcl_NewIntObj(0), TCL_LEAVE_ERR_MSG )
920 for ( i = that->rec->len, f = that->rec->field; i--; f++ ) {
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
928 if ( val == Tcl_ObjGetVar2( ip, valvar, 0, TCL_LEAVE_ERR_MSG )
929 && !Tcl_IsShared( val )
931 Tcl_SetStringObj( val, (char*)f->val, f->len );
934 if ( !Tcl_ObjSetVar2( ip, valvar, 0,
935 val = FldObj( f ), TCL_LEAVE_ERR_MSG )
940 if ( tag == Tcl_ObjGetVar2( ip, tagvar, 0, TCL_LEAVE_ERR_MSG )
941 && !Tcl_IsShared( tag )
943 Tcl_SetIntObj( tag, f->tag );
946 if ( !Tcl_ObjSetVar2( ip, tagvar, 0,
947 tag = Tcl_NewIntObj( f->tag ), TCL_LEAVE_ERR_MSG )
951 switch (rt = Tcl_EvalObjEx( ip, body, 0 )) {
969 Tcl_AppendResult (ip, arg0, ": no command bound to rec", 0);
972 if (strcmp (that->cmd, arg0)) {
973 Tcl_AppendResult (ip, arg0, ": command mismatch: ", that->cmd, 0);
976 if (NonDeletable (that)) {
977 Tcl_AppendResult (ip, arg0, ": record not deletable", 0);
980 Tcl_DeleteCommand (ip, (char*)arg0);
986 Tcl_AppendResult (ip, arg0, ": no fdt", 0);
989 return OpFdt (ip, ois, that->fdt, argc, argv);
992 Tcl_AppendResult (ip, arg0, ": sorry, format not implemented yet", 0);
999 const char *path, *rem;
1000 int tag, occ, i, j, objc, len, reclen;
1003 Tcl_Obj *list, *dflt, *val;
1006 Tcl_ResetResult (ip);
1007 reclen = that->rec ? that->rec->len : 0;
1010 path = Tcl_GetStringFromObj (argv[0], &i);
1011 if (3 < i && *path == '-') {
1012 if (0 == strncmp ("-tags", path, i)) {
1016 else if (0 == strncmp ("-tagnames", path, i)) {
1023 list = Tcl_NewListObj( 0, 0 );
1025 for (i = reclen, fld = that->rec->field; i--; fld++) {
1027 if (TCL_OK != Tcl_ListObjAppendElement (ip, list,
1028 FdObj (fld, 2 == witht ? that->fdt : 0))) {
1032 if (TCL_OK != Tcl_ListObjAppendElement (ip, list,
1038 Tcl_SetObjResult( ip, list );
1041 for (j = 0; argc > j; ) {
1042 path = Tcl_GetStringFromObj (argv[j], &len);
1045 0 == strncmp ("-nodefaults", path, len)) {
1053 Tcl_ListObjGetElements (0, argv[j], &objc, &objv) &&
1056 path = Tcl_GetStringFromObj (objv[0], 0);
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);
1068 for ( i = reclen, fld = that->rec->field;
1071 if ( tag == fld->tag ) {
1073 val = Tcl_NewListObj (0, 0);
1075 if (TCL_OK != Tcl_ListObjAppendElement (
1076 ip, val, FldObj(fld))) {
1082 else { /* specific occ wanted */
1083 fld = openIsisROccurence (that->rec, tag, occ);
1091 Tcl_ResetResult (ip);
1092 Tcl_AppendResult (ip, arg0,
1093 ": no such field: ", path, 0);
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.
1104 val = Tcl_NewListObj (1, tmp);
1111 Tcl_SetObjResult( ip, val );
1114 if (TCL_OK != Tcl_ListObjAppendElement(ip, list, val)) {
1120 list = Tcl_NewListObj( 0, 0 );
1122 if (TCL_OK != Tcl_ListObjAppendElement(ip, list, val)) {
1127 return UsageRec (ip, arg0);
1129 Tcl_SetObjResult( ip, list );
1134 Tcl_DecrRefCount (val);
1137 Tcl_DecrRefCount( list );
1143 Tcl_SetObjResult( ip, Tcl_NewIntObj(
1144 (that->rec && 0<that->rec->rowid) ? that->rec->rowid : 0
1149 Tcl_SetObjResult( ip, Tcl_NewIntObj(
1150 (that->rec && 0<that->rec->len) ? that->rec->len : 0
1160 Tcl_ResetResult (ip);
1164 b = openIsisRSerializeAlloc (that->rec, buf, &len);
1166 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
1169 /* do NOT include the final blankline */
1170 Tcl_SetObjResult( ip, Tcl_NewStringObj( b, len-1 ) );
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 ) );
1187 return UsageRec (ip, arg0);
1188 if (NonWritable (that)) {
1189 Tcl_AppendResult (ip, arg0, ": readonly record", 0);
1192 b = Tcl_GetStringFromObj( argv[0], &len );
1194 Tcl_ResetResult (ip);
1196 int ret = openIsisRDeserialize( &that->rec,
1197 b, len, OPENISIS_RDIS|OPENISIS_STOPONEMPTY );
1198 Tcl_SetObjResult( ip, Tcl_NewIntObj( ret ) );
1207 char **argp = (char**)buf;
1215 if (NonWritable (that)) {
1216 Tcl_AppendResult (ip, arg0, ": readonly record", 0);
1219 argp = ToArgv (argv, argc, buf, sizeof(buf));
1221 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
1224 for (j = 0; argc > j; ++j) {
1228 if ('-' == *argp[j]) {
1229 len = strlen (argp[j]);
1233 if (0 == strncmp ("-done", argp[j], len)) {
1237 if (0 == strncmp ("-number", argp[j], len)) {
1241 num = openIsisA2id (argp[j], -1, -1);
1247 if (0 == strncmp ("-tag", argp[j], len)) {
1251 tag = openIsisA2id (argp[j], -1, 0);
1259 if (0 > tag && 0 == tgnm) {
1267 emb = TclCmd2Rec (ip, name, arg0);
1274 OpenIsisFd *fd = openIsisFByName (that->fdt, tgnm);
1276 Tcl_AppendResult (ip, arg0,
1277 ": no such field description: ", tgnm, 0);
1286 Tcl_AppendResult (ip, arg0, ": record to embed not given", 0);
1291 that->rec = openIsisRAddI (that->rec, tag, num, !0);
1293 if (! emb->rec || ! (len = emb->rec->len)) {
1294 Tcl_AppendResult (ip, arg0,
1295 ": record to embed is empty", 0);
1298 that->rec = luti_append (that->rec, emb->rec);
1301 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
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);
1315 len = OpRec (emb, ip, name, RC_DONE, 0, 0);
1316 if (TCL_OK != len) {
1320 if (argp != (char**)buf) {
1321 openIsisMFree (argp);
1326 Tcl_AppendResult (ip, "usage: " , arg0, " wrap [-done] ",
1327 "[-number <numsubrecs>] {-tag <tag> | <tagname>} recname", 0);
1329 if (argp != (char**)buf) {
1330 openIsisMFree (argp);
1337 openIsisI2a (buf, cmd);
1338 Tcl_AppendResult (ip, arg0, ": unrecognized command ", buf, 0);
1346 OITRec *that, Tcl_Interp *ip, const char *arg0,
1347 Tcl_Obj *arg1, int argc, Tcl_Obj* const argv[]
1355 return UsageRec (ip, arg0);
1358 arg0 = "<openIsisRecord>";
1360 if (! that || ! (ois = RecSess (that))) {
1361 Tcl_AppendResult (ip, arg0, ": record corrupted", 0);
1364 if (ip != ois->ip) {
1365 Tcl_AppendResult (ip, arg0, ": session corrupted", 0);
1369 path = Tcl_GetStringFromObj (arg1, 0);
1371 /* path to embedded rec */
1373 int type = RecType (that);
1380 con = (OITCont*) that;
1381 if (strncmp (".fdt", path, 4)) {
1382 p2 = luti_parse_path (path, openIsisFdtRqs,
1384 if (0 == p2 || 0 < occ) {
1385 Tcl_AppendResult (ip, arg0,
1386 ": no such child: ", path, 0);
1396 rt = BuildRqsRecs (con);
1398 Tcl_AppendResult (ip, arg0,
1399 ": child allocation failure", 0);
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;
1409 Tcl_AppendResult (ip, arg0,
1410 ": no such child: ", path, 0);
1415 Tcl_Obj *obj = Tcl_NewStringObj (p2, (int) strlen (p2));
1417 Tcl_IncrRefCount (obj);
1418 rt = OpPath (rec, ip, buf, obj, argc, argv);
1419 Tcl_DecrRefCount (obj);
1425 return CrtRecCmd (ois, buf, rec, !0);
1427 return OpPath (rec, ip, buf, argv[0], argc - 1, argv + 1);
1434 con = (OITCont*) that;
1435 p2 = luti_parse_path (path, openIsisFdtRsp,
1438 OPENISIS_COM_REC != tag
1440 Tcl_AppendResult (ip, arg0,
1441 ": no such child: ", path, 0);
1444 if (!(rt = con->numr)) {
1445 rt = BuildRspRecs (con, ip, arg0);
1454 sprintf (buf, "%d", rt);
1455 Tcl_AppendResult (ip, arg0, ": no such child: ", path,
1456 ", have ", buf, " childs", 0);
1459 rec = con->recs[occ];
1462 Tcl_Obj *obj = Tcl_NewStringObj (p2, (int) strlen (p2));
1464 Tcl_IncrRefCount (obj);
1465 rt = OpPath (rec, ip, buf, obj, argc, argv);
1466 Tcl_DecrRefCount (obj);
1472 return CrtRecCmd (ois, buf, rec, !0);
1474 return OpPath (rec, ip, buf, argv[0], argc - 1, argv + 1);
1479 rec = luti_getembed (that->rec, path, that->fdt);
1481 Tcl_AppendResult (ip, arg0,
1482 ": no such child: ", path, 0);
1485 rt = NewRec (ois, 0,
1486 OIT_RS_DBF == RecType(that) ? openIsisFdtFd : 0,
1489 Tcl_AppendResult (ip, "OpPath: out of memory", 0);
1492 oir = ois->recs[rt];
1496 return CrtRecCmd (ois, buf, oir, !0);
1498 rt = OpPath (oir, ip, buf, argv[0], argc - 1, argv + 1);
1505 rt = Tcl_GetIndexFromObj (ip, arg1, OITOpts, "option", 0, &cmd);
1509 if (RC_LAST < cmd) {
1510 return UsageRec (ip, arg0);
1513 return OpRec (that, ip, arg0, (OITCmd)cmd, argc, argv);
1517 ClientData cld, Tcl_Interp *ip, int argc, Tcl_Obj* const argv[]
1519 const char *arg0 = 0 >= argc ? 0 : Tcl_GetStringFromObj (argv[0], 0);
1521 return UsageRec (ip, arg0);
1523 return OpPath ((OITRec*)cld, ip, arg0, argv[1], argc - 2, argv + 2);
1526 /* ============================== stubs ================================
1530 void *cld, OpenIsisStub stb, OpenIsisRec *rsp, OpenIsisDb *db
1532 OITStub *that = (OITStub*) cld;
1539 return openIsisSMsg (OPENISIS_ERR_TRASH,
1540 "[openIsisTcl] RspCb: response without stub");
1542 if (stb != that->stb) {
1543 return openIsisSMsg (OPENISIS_ERR_TRASH,
1544 "[openIsisTcl] RspCb: stub changed");
1546 ois = StbSess (that);
1548 return openIsisSMsg (OPENISIS_ERR_TRASH,
1549 "[openIsisTcl] RspCb: response without session");
1552 return openIsisSMsg (OPENISIS_ERR_TRASH,
1553 "[openIsisTcl] RspCb: response without request");
1556 if (that->rsp->env.rec) {
1557 openIsisSMsg (OPENISIS_ERR_TRASH,
1558 "[openIsisTcl] RspCb: multiple responses");
1559 DtorRec ((OITRec*)that->rsp, 0);
1563 rt = NewCont (ois, openIsisFdtRsp, OIT_RS_RSP);
1567 that->rsp = (OITCont*) ois->recs[rt];
1568 that->rsp->env.rec = rsp;
1569 that->rsp->stb = that->stb;
1571 if (! that->actproc) {
1572 if (! that->dfltproc) {
1575 rt = Tcl_EvalObj (ois->ip, that->dfltproc);
1578 rt = Tcl_EvalObj (ois->ip, that->actproc);
1580 res = Tcl_GetStringResult (ois->ip);
1584 if (TCL_ERROR == rt) {
1585 return openIsisSMsg (OPENISIS_ERR_IDIOT,
1586 "[openIsisTcl] callback eval: %s", res);
1589 openIsisSMsg (OPENISIS_LOG_WARN,
1590 "[openIsisTcl] callback eval = %d, %s", rt, res);
1593 openIsisSMsg (OPENISIS_LOG_INFO,
1594 "[openIsisTcl] callback eval : %s", res);
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[]
1604 static OITStub* CtorStub (Tcl_Interp *ip,
1605 const char *name, int argc, const char **argv, const char *proc
1607 OpenIsisStubCbData scd;
1608 OpenIsisSchema *sch;
1616 if (! NumSessions) {
1617 openIsisSMsg (OPENISIS_ERR_TRASH,
1618 "[openIsisTcl] CtorStub(%s): no root session", name);
1621 if (ip != Sessions->ip) {
1622 openIsisSMsg (OPENISIS_ERR_TRASH,
1623 "[openIsisTcl] CtorStub(%s): must not create stub in derived session",
1627 that = (OITStub*) openIsisMAlloc (sizeof (OITStub));
1629 openIsisSMsg (OPENISIS_ERR_NOMEM,
1630 "[openIsisTcl] CtorStub(%s): out of memory", name);
1633 that->cmd = openIsisMDup (name, -1);
1635 openIsisMFree (that);
1636 openIsisSMsg (OPENISIS_ERR_NOMEM,
1637 "[openIsisTcl] CtorStub(%s): out of memory", name);
1642 memset (&scd, 0, sizeof (OpenIsisStubCbData));
1643 scd.dfltcb = &RspCb;
1644 scd.delcb = &StbDelCb;
1645 scd.dfltcld = scd.delcld = that;
1647 if (OIT_ST_ROOT & stat) {
1648 that->cfg.fdt = openIsisFdtSyspar;
1649 that->stb = openIsisNInit (argc, argv, &scd);
1652 that->cfg.fdt = openIsisFdtScheme;
1653 that->stb = openIsisNOpen (name, argc, argv, &scd);
1656 openIsisMFree ((void*)that->cmd);
1657 openIsisMFree (that);
1658 openIsisSMsg (OPENISIS_ERR_IDIOT,
1659 "[openIsisTcl] CtorStub(%s): deficient configuration", name);
1663 sch = openIsisNSchema (that->stb);
1664 that->cfg.rec = sch->cfg;
1666 that->cfg.stat = OIT_RS_USED | OIT_RS_STC;
1669 that->dfltproc = Tcl_NewStringObj (proc, (int) strlen (proc));
1670 if (that->dfltproc) {
1671 Tcl_IncrRefCount (that->dfltproc);
1675 that->stat = stat | OIT_ST_TCL | OIT_ST_OINIT;
1677 Tcl_CreateObjCommand (ip, (char*)that->cmd, &CmdStub, that, &TclDelStb);
1678 Tcl_SetResult (ip, (char*)that->cmd, TCL_VOLATILE);
1682 static void DtorStub (OITStub *that, int where) {
1683 const char *cmd = that->cmd;
1687 if (! NumSessions) {
1688 openIsisSMsg (OPENISIS_ERR_TRASH,
1689 "[openIsisTcl] DtorStub(%s): no root session", cmd);
1692 that->stat &= ~where;
1693 if (OIT_ST_TCL & that->stat) {
1695 openIsisSMsg (OPENISIS_ERR_TRASH,
1696 "[openIsisTcl] DtorStub: no command");
1699 Tcl_DeleteCommand (Sessions->ip, (char*)that->cmd);
1702 if (OIT_ST_OINIT & that->stat) {
1703 if (OIT_ST_ROOT & that->stat) {
1707 openIsisNClose (that->stb);
1711 if (that->dfltproc) {
1712 Tcl_DecrRefCount (that->dfltproc);
1714 if (that->actproc) {
1715 Tcl_DecrRefCount (that->actproc);
1718 DtorRec ((OITRec*)that->rqs, 0);
1721 DtorRec ((OITRec*)that->rsp, 0);
1723 /* that->cfg.rec holds the same ref as stub->cfg,
1724 which is freed in openIsisNClose
1727 openIsisMFree ((void*)that->cmd);
1729 openIsisMFree (that);
1732 static void TclDelStb (ClientData cld) {
1733 DtorStub ((OITStub*)cld, OIT_ST_TCL);
1736 static void StbDelCb (void *cld, OpenIsisStub stb, void *cbd) {
1739 if (((OITStub*)cbd)->actproc) {
1740 Tcl_DecrRefCount (((OITStub*)cbd)->actproc);
1741 ((OITStub*)cbd)->actproc = 0;
1745 DtorStub ((OITStub*)cld, OIT_ST_OINIT);
1748 static int BuildRqsCont (OITStub *that, Tcl_Interp *ip,
1749 const char *arg0, OITSess *ois, int *argc, Tcl_Obj* const **argv
1755 rt = NewCont (ois, openIsisFdtRqs, OIT_RS_RQS);
1757 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
1760 that->rqs = (OITCont*) ois->recs[rt];
1763 0 == strcmp ("-db", Tcl_GetStringFromObj ((*argv)[0], 0))) {
1764 dbn = Tcl_GetStringFromObj ((*argv)[1], 0);
1765 db = openIsisNDbByName (that->stb, dbn);
1767 Tcl_AppendResult (ip, arg0, ": no such db: ", dbn, 0);
1770 that->rqs->env.db = db;
1777 static const OpenIsisFdt* SysFdtFromName (const char *dbn, int len) {
1780 if (0 == strncmp (dbn, "-dbpar", len)) {
1781 return openIsisFdtDbpar;
1785 if ('d' == dbn[2]) {
1787 return openIsisFdtFd;
1789 if ('t' == dbn[3] && 0 == dbn[4]) {
1790 return openIsisFdtFdt;
1796 if (0 == strncmp (dbn, "-request", len)) {
1797 return openIsisFdtRqs;
1799 if (0 == strncmp (dbn, "-response", len)) {
1800 return openIsisFdtRsp;
1806 if (0 == strncmp (dbn, "-syspar", len)) {
1807 return openIsisFdtSyspar;
1809 if (0 == strncmp (dbn, "-scheme", len)) {
1810 return openIsisFdtScheme;
1818 static int UsageStub (Tcl_Interp *ip, const char *argv0) {
1819 Tcl_AppendResult (ip,
1821 (argv0 ? argv0 : "<openIsisStub>"),
1822 " db db ?option ...? |",
1823 " fdt db ?option ...? |",
1824 " new -schema name ?-cfg val ...? |",
1825 " new ?-db db? ?name? |",
1827 " request ?-db db? ?-param val? |",
1828 " .req ?-db db? ?option ...? |",
1829 " .res ?option ...?",
1834 static int CmdStub (
1835 ClientData cld, Tcl_Interp *ip, int argc, Tcl_Obj* const argv[]
1837 OITStub *that = (OITStub*) cld;
1846 arg0 = Tcl_GetStringFromObj (argv[0], 0);
1848 return UsageStub (ip, arg0);
1851 ois = StbSess (that);
1853 if (! NumSessions) {
1854 Tcl_AppendResult (ip, arg0, ": no session", 0);
1860 if (ip != ois->ip) {
1861 Tcl_AppendResult (ip, arg0, ": session changed", 0);
1865 rt = Tcl_GetIndexFromObj (ip, argv[1], OITOpts, "option", 0, (int*)&cmd);
1867 return UsageStub (ip, arg0);
1879 return UsageStub (ip, arg0);
1881 dbn = Tcl_GetStringFromObj (argv[0], 0);
1882 db = openIsisNDbByName (that->stb, dbn);
1884 Tcl_AppendResult (ip, arg0, ": no such db <", dbn, ">", 0);
1887 return OpDb (ip, ois, db, argc - 1, argv + 1);
1891 Tcl_DeleteCommand (ip, (char*)arg0);
1895 const OpenIsisFdt *fdt = 0;
1900 return UsageStub (ip, arg0);
1902 dbn = Tcl_GetStringFromObj (argv[0], &len);
1903 if (1 < len && '-' == *dbn) {
1904 fdt = SysFdtFromName (dbn, len);
1907 db = openIsisNDbByName (that->stb, dbn);
1909 Tcl_AppendResult (ip, arg0, ": no such db <", dbn, ">", 0);
1914 Tcl_AppendResult (ip, arg0, ": ", dbn, " has no fdt", 0);
1918 return OpFdt (ip, ois, fdt, argc - 1, argv + 1);
1924 const OpenIsisFdt *fdt = 0;
1926 const char *arg2 = 0;
1927 const char *dbn = 0;
1928 const char *proc = 0;
1939 name = Tcl_GetStringFromObj (argv[0], 0);
1942 arg2 = Tcl_GetStringFromObj (argv[0], &len);
1943 if (2 > len || 0 != strncmp ("-db", arg2, len)) {
1944 return UsageStub (ip, arg0);
1946 dbn = Tcl_GetStringFromObj (argv[1], &dbl);
1947 name = Tcl_GetStringFromObj (argv[2], 0);
1949 if (1 < dbl && '-' == *dbn) {
1950 fdt = SysFdtFromName (dbn, dbl);
1954 dbn = openIsisRString (that->cfg.rec,
1955 OPENISIS_SC_DFLTDB, 0, buf, sizeof(buf));
1957 Tcl_AppendResult (ip, arg0,
1958 ": no db specified", 0);
1962 db = openIsisNDbByName (that->stb, dbn);
1964 Tcl_AppendResult (ip, arg0,
1965 ": no such db <", dbn, ">", 0);
1970 rt = NewRec (ois, db, fdt, 0);
1972 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
1975 rt = CrtRecCmd (ois, name, ois->recs[rt], !0);
1980 arg2 = Tcl_GetStringFromObj (argv[0], &len);
1982 return UsageStub (ip, arg0);
1984 if (2 == argc && 0 == strncmp ("-db", arg2, len)) {
1985 dbn = Tcl_GetStringFromObj (argv[1], &dbl);
1988 if (strncmp ("-schema", arg2, len) &&
1989 strncmp ("schema", arg2, len)) {
1990 return UsageStub (ip, arg0);
1992 name = Tcl_GetStringFromObj (argv[1], 0);
1997 argp = ToArgv (argv, argc, buf, sizeof (buf));
1999 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
2002 for (j = 0; argc > j; ++j) {
2003 if (0 == strcmp ("-async", argp[j]) &&
2009 nstb = CtorStub (ip, name, argc, (const char**)argp, proc);
2010 if (argp && argp != (char**)buf) {
2011 openIsisMFree (argp);
2014 Tcl_AppendResult (ip, arg0,
2015 ": deficient configuration for ", name,
2016 " or out of memory", 0);
2021 } /* switch (argc) */
2025 if (that->rsp && that->rsp->env.rec) {
2028 Tcl_AppendResult (ip, arg0,
2029 ": waiting for response in async mode not implemented yet", 0);
2036 DtorRec ((OITRec*) that->rsp, 0);
2038 if (! BuildRqsCont (that, ip, arg0, ois, &argc, &argv)) {
2042 Tcl_Obj *setcmd = Tcl_NewStringObj ("set", 3);
2044 Tcl_AppendResult (ip, arg0, ": out of memory", 0);
2047 Tcl_IncrRefCount (setcmd);
2049 (OITRec*)that->rqs, ip, 0, setcmd, argc, argv);
2050 Tcl_DecrRefCount (setcmd);
2055 rqs = that->rqs->env.rec;
2056 if (that->rqs->numr) {
2058 if ((rec = that->rqs->recs[0]->rec)) {
2059 rqs = luti_wrap (rqs, rec, OPENISIS_COM_REC);
2061 if ((rec = that->rqs->recs[1]->rec)) {
2062 rqs = luti_wrap (rqs, rec, OPENISIS_RQS_IDX);
2064 if ((rec = that->rqs->recs[2]->rec)) {
2065 rqs = luti_wrap (rqs, rec, OPENISIS_COM_CFG);
2067 if ((rec = that->rqs->recs[3]->rec)) {
2068 rqs = luti_append (rqs, rec);
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);
2074 rt = openIsisNSend (that->stb, that->rqs->env.rec = rqs, 0, 0, !0);
2075 that->rqs->env.db = 0; /* do never remember */
2078 sprintf (buf, "%x", rt);
2079 Tcl_AppendResult (ip, arg0, ": error ", buf,
2080 " sending request", 0);
2087 if (! BuildRqsCont (that, ip, arg0, ois, &argc, &argv)) {
2091 return UsageStub (ip, arg0);
2094 (OITRec*)that->rqs, ip, 0, argv[0], argc - 1, argv + 1);
2099 int hasrsp = that->rsp && that->rsp->env.rec;
2101 Tcl_SetObjResult (ip, Tcl_NewBooleanObj (hasrsp));
2105 Tcl_AppendResult (ip, arg0, ": no response available", 0);
2109 (OITRec*)that->rsp, ip, 0, argv[0], argc - 1, argv + 1);
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
2121 sch->cfg = that->cfg.rec;
2128 static int CmdInit (
2129 ClientData cld, Tcl_Interp *ip, int argc, const char *argv[]
2132 const char *proc = 0;
2137 if (openisis_stub0) {
2139 if (Tcl_GetCommandInfo (ip, OIT_STB0, &info)) {
2140 Tcl_SetResult (ip, OIT_STB0, TCL_STATIC);
2145 for (j = 1; argc > j; ++j) {
2146 if (! argv[j] || ! (len = strlen (argv[j]))) {
2149 if ('-' == *argv[j]) {
2150 if (! strncmp ("-async", argv[j], (unsigned) len)) {
2161 /* openIsisNInit can be called multiple times */
2162 news = CtorStub (ip, 0, argc - j, argv + j, proc);
2164 Tcl_AppendResult (ip, OIT_STB0, ": out of memory", 0);
2170 Tcl_AppendResult (ip,
2171 "usage: ", argv[0], " ?-async <cb>? ?options?", 0);
2176 ClientData cld, Tcl_Interp *ip, int argc, Tcl_Obj* const argv[]
2180 const OpenIsisFdt *fdt;
2184 int j, rt, len, ownf;
2187 if (! NumSessions) {
2188 Tcl_AppendResult (ip, "session not initialized", 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)) {
2201 Tcl_AppendResult (ip,
2202 "usage: openIsisRec ?-fdt name? ?options...?", 0);
2205 fname = Tcl_GetStringFromObj (argv[j], &len);
2206 if (len && '-' == *fname) {
2207 fdt = SysFdtFromName (fname, len);
2210 rfdt = TclCmd2Rec (ip, fname, "openIsisRec");
2214 fdt = openIsisFRec2Fdt (rfdt->rec);
2216 Tcl_AppendResult (ip, fname, " is an illegal fdt", 0);
2233 if (! rname || ! *rname) {
2234 rname = NewRecId (buf);
2237 rt = NewRec (ois, 0, fdt, ownf ? OIT_RS_OWNF : 0);
2239 Tcl_AppendResult (ip, Tcl_GetStringFromObj (argv[0], 0),
2240 ": out of memory", 0);
2243 rec = ois->recs[rt];
2246 rt = OpPath (rec, ip, rname, argv[j], argc - (j+1), argv + (j+1));
2252 rt = CrtRecCmd (ois, rname, rec, !0);
2261 openIsisFFree ((OpenIsisFdt*)fdt);
2266 static void FreeEnc ();
2267 static void AtExit (ClientData cld) {
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);
2280 /* ===================== command evaluation ============================
2283 static int CmdEval (OpenIsisRec *cmd, OpenIsisRec **rsp) {
2285 OpenIsisField *F, *E;
2286 OpenIsisSession ois;
2287 OpenIsisRec *recs[1] = { 0 };
2292 if (NumSessions <= ois->id) {
2293 return openIsisSMsg (OPENISIS_ERR_TRASH,
2294 "[openIsisTcl] CmdEval: no ip for ses %d[%d]",
2295 ois->id, NumSessions);
2298 rid[0] = openIsisTclCreateRecCmd (ois->id, "result", 0, 0);
2300 return openIsisSMsg (OPENISIS_ERR_NOMEM,
2301 "[openIsisTcl] CmdEval: cannot allocate result cmd");
2305 Tcl_DStringInit (&ds);
2306 for (E = (F = cmd->field) + cmd->len; E > F; ++F) {
2308 Tcl_DStringAppend (&ds, ";", 1);
2311 Tcl_DStringAppend (&ds, F->val, F->len);
2313 rt = openIsisTclEval (ois->id, 1, rid, recs, Tcl_DStringValue (&ds));
2314 Tcl_DStringFree (&ds);
2316 /* record freed in ldsp */
2317 Sessions[ois->id].recs[rid[0]]->rec = 0;
2323 OpenIsisEvalFunc *openIsisEval = &CmdEval;
2325 /* =========================== encoding ================================
2328 static Tcl_HashTable Encodings;
2329 static int InitEnc = 0;
2331 static Tcl_Encoding GetEnc (Tcl_Interp *ip, const char *name, int *frs) {
2336 Tcl_InitHashTable (&Encodings, TCL_STRING_KEYS);
2339 he = Tcl_FindHashEntry (&Encodings, name);
2341 return (Tcl_Encoding) Tcl_GetHashValue (he);
2343 enc = Tcl_GetEncoding (ip, name);
2344 he = Tcl_CreateHashEntry (&Encodings, name, &nw);
2345 Tcl_SetHashValue (he, enc);
2352 static void FreeEnc () {
2357 for (he = Tcl_FirstHashEntry (&Encodings, &hs);
2359 he = Tcl_NextHashEntry (&hs)
2361 enc = (Tcl_Encoding) Tcl_GetHashValue (he);
2363 Tcl_FreeEncoding (enc);
2366 Tcl_DeleteHashTable (&Encodings);
2371 static const char* TrfEnc (const char *ename,
2372 const char *src, int slen, char *dst, int dlen, int invert
2381 openIsisMFree ((void*)src);
2386 if (! src || 0 >= slen) {
2389 /* tclEncoding.c says that a null interp is ok */
2391 enc = GetEnc (0, ename, &frs);
2393 openIsisSMsg (OPENISIS_ERR_INVAL,
2394 "[openIsisTcl] TrfEnc: no such encoding <%s>", ename);
2398 Tcl_DStringInit (&str);
2400 tgt = Tcl_UtfToExternalDString (enc, src, slen, &str);
2403 tgt = Tcl_ExternalToUtfDString (enc, src, slen, &str);
2405 tlen = Tcl_DStringLength (&str);
2406 if (! dst || tlen >= dlen) {
2407 dst = (char*) openIsisMAlloc (1 + tlen);
2412 memcpy (dst, tgt, tlen);
2414 Tcl_DStringFree (&str);
2418 OpenIsisEnc2Utf8Func *openIsisEnc2Utf8 = &TrfEnc;
2420 /* ************************************************************
2424 int openIsisTclNewSession (Tcl_Interp *ip) {
2426 for (id = 0; NumSessions > id; ++id) {
2427 if (ip == Sessions[id].ip) {
2433 AddCmds (ip, 0 == id);
2438 int openIsisTclGetSession (int sid, Tcl_Interp **ip) {
2439 if (0 > sid || NumSessions <= sid) {
2443 *ip = Sessions[sid].ip;
2449 void openIsisTclDelSession (int sid) {
2454 if (0 < sid && NumSessions > sid) {
2455 DtorSess (Sessions + sid);
2461 int openIsisTclCreateRecCmd (
2462 int sid, const char *nam, const char *fn, int flg
2464 OITSess *ois = Sessions+sid;
2465 OpenIsisFdt *fdt = 0;
2467 (void)flg; /* TODO: set readonly */
2469 OITRec *oitf = TclCmd2Rec (ois->ip, fn, 0);
2471 openIsisSMsg (OPENISIS_ERR_INVAL,
2472 "[openIsisTcl] createRecCmd: no such fdt %s", fn);
2474 fdt = openIsisFRec2Fdt (oitf->rec);
2476 openIsisSMsg (OPENISIS_ERR_INVAL,
2477 "[openIsisTcl] createRecCmd: illegal fdt %s", fn);
2480 rid = NewRec( ois, 0, fdt, fdt ? OIT_RS_OWNF : 0 );
2482 CrtRecCmd( ois, nam, ois->recs[rid], 0 );
2485 } /* openIsisTclCreateRecCmd */
2488 int openIsisTclEval ( int sid,
2489 int cnt, const int *ids, OpenIsisRec **recs, char *script )
2491 OITSess *ois = Sessions+sid;
2496 ois->recs[ ids[i] ]->rec = recs[i];
2497 ret = Tcl_Eval( ois->ip, script );
2500 recs[i] = ois->recs[ ids[i] ]->rec;
2502 } /* openIsisTclEval */
2505 int openIsisTclInit (Tcl_Interp *ip) {
2506 if (! NumSessions) {
2510 Tcl_CreateExitHandler (&AtExit, 0);