5 #include <jim-subcmd.h>
7 /* -----------------------------------------------------------------------------
9 * ---------------------------------------------------------------------------*/
11 int Jim_PackageProvide(Jim_Interp
*interp
, const char *name
, const char *ver
, int flags
)
13 /* If the package was already provided returns an error. */
14 if (Jim_FindHashEntry(&interp
->packages
, name
) != NULL
) {
15 if (flags
& JIM_ERRMSG
) {
16 Jim_SetResultFormatted(interp
, "package \"%s\" was already provided", name
);
20 Jim_AddHashEntry(&interp
->packages
, name
, (char *)ver
);
24 static char *JimFindPackage(Jim_Interp
*interp
, char **prefixes
, int prefixc
, const char *pkgName
)
28 for (i
= 0; i
< prefixc
; i
++) {
29 char buf
[JIM_PATH_LEN
];
31 if (prefixes
[i
] == NULL
)
34 if (strcmp(prefixes
[i
], ".") == 0) {
35 snprintf(buf
, sizeof(buf
), "%s.tcl", pkgName
);
38 snprintf(buf
, sizeof(buf
), "%s/%s.tcl", prefixes
[i
], pkgName
);
41 if (access(buf
, R_OK
) == 0) {
42 return Jim_StrDup(buf
);
45 snprintf(buf
, sizeof(buf
), "%s/%s.so", prefixes
[i
], pkgName
);
46 if (access(buf
, R_OK
) == 0) {
47 return Jim_StrDup(buf
);
53 /* Search for a suitable package under every dir specified by JIM_LIBPATH,
54 * and load it if possible. If a suitable package was loaded with success
55 * JIM_OK is returned, otherwise JIM_ERR is returned. */
56 static int JimLoadPackage(Jim_Interp
*interp
, const char *name
, int flags
)
58 Jim_Obj
*libPathObjPtr
;
59 char **prefixes
, *path
;
60 int prefixc
, i
, retCode
= JIM_ERR
;
62 libPathObjPtr
= Jim_GetGlobalVariableStr(interp
, JIM_LIBPATH
, JIM_NONE
);
63 if (libPathObjPtr
== NULL
) {
68 Jim_IncrRefCount(libPathObjPtr
);
69 prefixc
= Jim_ListLength(interp
, libPathObjPtr
);
72 prefixes
= Jim_Alloc(sizeof(char *) * prefixc
);
73 for (i
= 0; i
< prefixc
; i
++) {
74 Jim_Obj
*prefixObjPtr
;
76 if (Jim_ListIndex(interp
, libPathObjPtr
, i
, &prefixObjPtr
, JIM_NONE
) != JIM_OK
) {
80 prefixes
[i
] = Jim_StrDup(Jim_GetString(prefixObjPtr
, NULL
));
83 /* Scan every directory for the the first match */
84 path
= JimFindPackage(interp
, prefixes
, prefixc
, name
);
86 char *p
= strrchr(path
, '.');
88 /* Try to load/source it */
89 if (p
&& strcmp(p
, ".tcl") == 0) {
90 retCode
= Jim_EvalFile(interp
, path
);
94 retCode
= Jim_LoadLibrary(interp
, path
);
102 for (i
= 0; i
< prefixc
; i
++)
103 Jim_Free(prefixes
[i
]);
106 Jim_DecrRefCount(interp
, libPathObjPtr
);
110 int Jim_PackageRequire(Jim_Interp
*interp
, const char *name
, int flags
)
116 /* Start with an empty error string */
117 Jim_SetResultString(interp
, "", 0);
119 he
= Jim_FindHashEntry(&interp
->packages
, name
);
121 /* Try to load the package. */
122 retcode
= JimLoadPackage(interp
, name
, flags
);
123 if (retcode
!= JIM_OK
) {
124 if (flags
& JIM_ERRMSG
) {
127 Jim_GetString(Jim_GetResult(interp
), &len
);
128 Jim_SetResultFormatted(interp
, "%#s%sCan't load package %s",
129 Jim_GetResult(interp
), len
? "\n" : "", name
);
134 he
= Jim_FindHashEntry(&interp
->packages
, name
);
136 /* Did not call package provide, so we do it for them */
137 Jim_PackageProvide(interp
, name
, "1.0", 0);
149 Jim_SetResultString(interp
, version
, -1);
154 *----------------------------------------------------------------------
156 * package provide name ?version?
158 * This procedure is invoked to declare that a particular version
159 * of a particular package is now present in an interpreter. There
160 * must not be any other version of this package already
161 * provided in the interpreter.
164 * Returns JIM_OK and sets the package version (or 1.0 if not specified).
166 *----------------------------------------------------------------------
168 static int package_cmd_provide(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
170 const char *version
= "1.0";
173 version
= Jim_GetString(argv
[1], NULL
);
175 return Jim_PackageProvide(interp
, Jim_GetString(argv
[0], NULL
), version
, JIM_ERRMSG
);
179 *----------------------------------------------------------------------
181 * package require name ?version?
183 * This procedure is load a given package.
184 * Note that the version is ignored.
187 * Returns JIM_OK and sets the package version.
189 *----------------------------------------------------------------------
191 static int package_cmd_require(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
193 /* package require failing is important enough to add to the stack */
194 interp
->addStackTrace
++;
196 return Jim_PackageRequire(interp
, Jim_GetString(argv
[0], NULL
), JIM_ERRMSG
);
200 *----------------------------------------------------------------------
204 * Returns a list of known packages
207 * Returns JIM_OK and sets a list of known packages.
209 *----------------------------------------------------------------------
211 static int package_cmd_list(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
213 Jim_HashTableIterator
*htiter
;
215 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
217 htiter
= Jim_GetHashTableIterator(&interp
->packages
);
218 while ((he
= Jim_NextHashEntry(htiter
)) != NULL
) {
219 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, he
->key
, -1));
221 Jim_FreeHashTableIterator(htiter
);
223 Jim_SetResult(interp
, listObjPtr
);
228 static const jim_subcmd_type package_command_table
[] = {
230 .args
= "name ?version?",
231 .function
= package_cmd_provide
,
234 .description
= "Indicates that the current script provides the given package"},
236 .args
= "name ?version?",
237 .function
= package_cmd_require
,
240 .description
= "Loads the given package by looking in standard places"},
242 .function
= package_cmd_list
,
245 .description
= "Lists all known packages"},
249 int Jim_packageInit(Jim_Interp
*interp
)
251 Jim_CreateCommand(interp
, "package", Jim_SubCmdProc
, (void *)package_command_table
, NULL
);