3 #include "jimautoconf.h"
4 #include <jim-subcmd.h>
12 /* All packages have a fixed, dummy version */
13 static const char *package_version_1
= "1.0";
15 /* -----------------------------------------------------------------------------
17 * ---------------------------------------------------------------------------*/
19 int Jim_PackageProvide(Jim_Interp
*interp
, const char *name
, const char *ver
, int flags
)
21 /* If the package was already provided returns an error. */
22 Jim_HashEntry
*he
= Jim_FindHashEntry(&interp
->packages
, name
);
24 /* An empty result means the automatic entry. This can be replaced */
25 if (he
&& *(const char *)he
->u
.val
) {
26 if (flags
& JIM_ERRMSG
) {
27 Jim_SetResultFormatted(interp
, "package \"%s\" was already provided", name
);
31 Jim_ReplaceHashEntry(&interp
->packages
, name
, (char *)ver
);
36 * Searches along a of paths for the given package.
38 * Returns the allocated path to the package file if found,
39 * or NULL if not found.
41 static char *JimFindPackage(Jim_Interp
*interp
, Jim_Obj
*prefixListObj
, const char *pkgName
)
44 char *buf
= Jim_Alloc(JIM_PATH_LEN
);
45 int prefixc
= Jim_ListLength(interp
, prefixListObj
);
47 for (i
= 0; i
< prefixc
; i
++) {
48 Jim_Obj
*prefixObjPtr
= Jim_ListGetIndex(interp
, prefixListObj
, i
);
49 const char *prefix
= Jim_String(prefixObjPtr
);
51 /* Loadable modules are tried first */
53 snprintf(buf
, JIM_PATH_LEN
, "%s/%s.so", prefix
, pkgName
);
54 if (access(buf
, R_OK
) == 0) {
58 if (strcmp(prefix
, ".") == 0) {
59 snprintf(buf
, JIM_PATH_LEN
, "%s.tcl", pkgName
);
62 snprintf(buf
, JIM_PATH_LEN
, "%s/%s.tcl", prefix
, pkgName
);
65 if (access(buf
, R_OK
) == 0) {
73 /* Search for a suitable package under every dir specified by JIM_LIBPATH,
74 * and load it if possible. If a suitable package was loaded with success
75 * JIM_OK is returned, otherwise JIM_ERR is returned. */
76 static int JimLoadPackage(Jim_Interp
*interp
, const char *name
, int flags
)
78 int retCode
= JIM_ERR
;
79 Jim_Obj
*libPathObjPtr
= Jim_GetGlobalVariableStr(interp
, JIM_LIBPATH
, JIM_NONE
);
83 /* Scan every directory for the the first match */
84 path
= JimFindPackage(interp
, libPathObjPtr
, name
);
88 /* Note: Even if the file fails to load, we consider the package loaded.
89 * This prevents issues with recursion.
90 * Use a dummy version of "" to signify this case.
92 Jim_PackageProvide(interp
, name
, "", 0);
94 /* Try to load/source it */
95 p
= strrchr(path
, '.');
97 if (p
&& strcmp(p
, ".tcl") == 0) {
98 Jim_IncrRefCount(libPathObjPtr
);
99 retCode
= Jim_EvalFileGlobal(interp
, path
);
100 Jim_DecrRefCount(interp
, libPathObjPtr
);
104 retCode
= Jim_LoadLibrary(interp
, path
);
107 if (retCode
!= JIM_OK
) {
108 /* Upon failure, remove the dummy entry */
109 Jim_DeleteHashEntry(&interp
->packages
, name
);
119 int Jim_PackageRequire(Jim_Interp
*interp
, const char *name
, int flags
)
123 /* Start with an empty error string */
124 Jim_SetEmptyResult(interp
);
126 he
= Jim_FindHashEntry(&interp
->packages
, name
);
128 /* Try to load the package. */
129 int retcode
= JimLoadPackage(interp
, name
, flags
);
130 if (retcode
!= JIM_OK
) {
131 if (flags
& JIM_ERRMSG
) {
132 int len
= Jim_Length(Jim_GetResult(interp
));
133 Jim_SetResultFormatted(interp
, "%#s%sCan't load package %s",
134 Jim_GetResult(interp
), len
? "\n" : "", name
);
139 /* In case the package did not 'package provide' */
140 Jim_PackageProvide(interp
, name
, package_version_1
, 0);
142 /* Now it must exist */
143 he
= Jim_FindHashEntry(&interp
->packages
, name
);
146 Jim_SetResultString(interp
, he
->u
.val
, -1);
151 *----------------------------------------------------------------------
153 * package provide name ?version?
155 * This procedure is invoked to declare that
156 * a particular package is now present in an interpreter.
157 * The package must not already be provided in the interpreter.
160 * Returns JIM_OK and sets results as "1.0" (the given version is ignored)
162 *----------------------------------------------------------------------
164 static int package_cmd_provide(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
166 return Jim_PackageProvide(interp
, Jim_String(argv
[0]), package_version_1
, JIM_ERRMSG
);
170 *----------------------------------------------------------------------
172 * package require name ?version?
174 * This procedure is load a given package.
175 * Note that the version is ignored.
178 * Returns JIM_OK and sets the package version.
180 *----------------------------------------------------------------------
182 static int package_cmd_require(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
184 /* package require failing is important enough to add to the stack */
185 interp
->addStackTrace
++;
187 return Jim_PackageRequire(interp
, Jim_String(argv
[0]), JIM_ERRMSG
);
191 *----------------------------------------------------------------------
195 * Returns a list of known packages
198 * Returns JIM_OK and sets a list of known packages.
200 *----------------------------------------------------------------------
202 static int package_cmd_list(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
204 Jim_HashTableIterator
*htiter
;
206 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
208 htiter
= Jim_GetHashTableIterator(&interp
->packages
);
209 while ((he
= Jim_NextHashEntry(htiter
)) != NULL
) {
210 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, he
->key
, -1));
212 Jim_FreeHashTableIterator(htiter
);
214 Jim_SetResult(interp
, listObjPtr
);
219 static const jim_subcmd_type package_command_table
[] = {
226 /* Description: Indicates that the current script provides the given package */
234 /* Description: Loads the given package by looking in standard places */
242 /* Description: Lists all known packages */
249 int Jim_packageInit(Jim_Interp
*interp
)
251 Jim_CreateCommand(interp
, "package", Jim_SubCmdProc
, (void *)package_command_table
, NULL
);