4 #include "jimautoconf.h"
5 #include "jim-subcmd.h"
13 /* All packages have a fixed, dummy version */
14 static const char *package_version_1
= "1.0";
16 /* -----------------------------------------------------------------------------
18 * ---------------------------------------------------------------------------*/
20 int Jim_PackageProvide(Jim_Interp
*interp
, const char *name
, const char *ver
, int flags
)
22 /* If the package was already provided returns an error. */
23 Jim_HashEntry
*he
= Jim_FindHashEntry(&interp
->packages
, name
);
25 /* An empty result means the automatic entry. This can be replaced */
26 if (he
&& *(const char *)he
->u
.val
) {
27 if (flags
& JIM_ERRMSG
) {
28 Jim_SetResultFormatted(interp
, "package \"%s\" was already provided", name
);
33 Jim_DeleteHashEntry(&interp
->packages
, name
);
35 Jim_AddHashEntry(&interp
->packages
, name
, (char *)ver
);
39 static char *JimFindPackage(Jim_Interp
*interp
, char **prefixes
, int prefixc
, const char *pkgName
)
42 char *buf
= Jim_Alloc(JIM_PATH_LEN
);
44 for (i
= 0; i
< prefixc
; i
++) {
45 if (prefixes
[i
] == NULL
)
48 /* Loadable modules are tried first */
50 snprintf(buf
, JIM_PATH_LEN
, "%s/%s.so", prefixes
[i
], pkgName
);
51 if (access(buf
, R_OK
) == 0) {
55 if (strcmp(prefixes
[i
], ".") == 0) {
56 snprintf(buf
, JIM_PATH_LEN
, "%s.tcl", pkgName
);
59 snprintf(buf
, JIM_PATH_LEN
, "%s/%s.tcl", prefixes
[i
], pkgName
);
62 if (access(buf
, R_OK
) == 0) {
70 /* Search for a suitable package under every dir specified by JIM_LIBPATH,
71 * and load it if possible. If a suitable package was loaded with success
72 * JIM_OK is returned, otherwise JIM_ERR is returned. */
73 static int JimLoadPackage(Jim_Interp
*interp
, const char *name
, int flags
)
75 Jim_Obj
*libPathObjPtr
;
76 char **prefixes
, *path
;
77 int prefixc
, i
, retCode
= JIM_ERR
;
79 libPathObjPtr
= Jim_GetGlobalVariableStr(interp
, JIM_LIBPATH
, JIM_NONE
);
80 if (libPathObjPtr
== NULL
) {
85 Jim_IncrRefCount(libPathObjPtr
);
86 prefixc
= Jim_ListLength(interp
, libPathObjPtr
);
89 prefixes
= Jim_Alloc(sizeof(char *) * prefixc
);
90 for (i
= 0; i
< prefixc
; i
++) {
91 Jim_Obj
*prefixObjPtr
;
93 if (Jim_ListIndex(interp
, libPathObjPtr
, i
, &prefixObjPtr
, JIM_NONE
) != JIM_OK
) {
97 prefixes
[i
] = Jim_StrDup(Jim_String(prefixObjPtr
));
100 /* Scan every directory for the the first match */
101 path
= JimFindPackage(interp
, prefixes
, prefixc
, name
);
103 char *p
= strrchr(path
, '.');
105 /* Note: Even if the file fails to load, we consider the package loaded.
106 * This prevents issues with recursion.
107 * Use a dummy version of "" to signify this case.
109 Jim_PackageProvide(interp
, name
, "", 0);
111 /* Try to load/source it */
112 if (p
&& strcmp(p
, ".tcl") == 0) {
113 retCode
= Jim_EvalFileGlobal(interp
, path
);
117 retCode
= Jim_LoadLibrary(interp
, path
);
120 if (retCode
!= JIM_OK
) {
121 /* Upon failure, remove the dummy entry */
122 Jim_DeleteHashEntry(&interp
->packages
, name
);
126 for (i
= 0; i
< prefixc
; i
++)
127 Jim_Free(prefixes
[i
]);
130 Jim_DecrRefCount(interp
, libPathObjPtr
);
134 int Jim_PackageRequire(Jim_Interp
*interp
, const char *name
, int flags
)
138 /* Start with an empty error string */
139 Jim_SetResultString(interp
, "", 0);
141 he
= Jim_FindHashEntry(&interp
->packages
, name
);
143 /* Try to load the package. */
144 int retcode
= JimLoadPackage(interp
, name
, flags
);
145 if (retcode
!= JIM_OK
) {
146 if (flags
& JIM_ERRMSG
) {
149 Jim_GetString(Jim_GetResult(interp
), &len
);
150 Jim_SetResultFormatted(interp
, "%#s%sCan't load package %s",
151 Jim_GetResult(interp
), len
? "\n" : "", name
);
156 /* In case the package did no 'package provide' */
157 Jim_PackageProvide(interp
, name
, "1.0", 0);
159 /* Now it must exist */
160 he
= Jim_FindHashEntry(&interp
->packages
, name
);
163 Jim_SetResultString(interp
, he
->u
.val
, -1);
168 *----------------------------------------------------------------------
170 * package provide name ?version?
172 * This procedure is invoked to declare that
173 * a particular package is now present in an interpreter.
174 * The package must not already be provided in the interpreter.
177 * Returns JIM_OK and sets results as "1.0" (the given version is ignored)
179 *----------------------------------------------------------------------
181 static int package_cmd_provide(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
183 return Jim_PackageProvide(interp
, Jim_String(argv
[0]), package_version_1
, JIM_ERRMSG
);
187 *----------------------------------------------------------------------
189 * package require name ?version?
191 * This procedure is load a given package.
192 * Note that the version is ignored.
195 * Returns JIM_OK and sets the package version.
197 *----------------------------------------------------------------------
199 static int package_cmd_require(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
201 /* package require failing is important enough to add to the stack */
202 interp
->addStackTrace
++;
204 return Jim_PackageRequire(interp
, Jim_String(argv
[0]), JIM_ERRMSG
);
208 *----------------------------------------------------------------------
212 * Returns a list of known packages
215 * Returns JIM_OK and sets a list of known packages.
217 *----------------------------------------------------------------------
219 static int package_cmd_list(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
221 Jim_HashTableIterator
*htiter
;
223 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
225 htiter
= Jim_GetHashTableIterator(&interp
->packages
);
226 while ((he
= Jim_NextHashEntry(htiter
)) != NULL
) {
227 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, he
->key
, -1));
229 Jim_FreeHashTableIterator(htiter
);
231 Jim_SetResult(interp
, listObjPtr
);
236 static const jim_subcmd_type package_command_table
[] = {
243 /* Description: Indicates that the current script provides the given package */
251 /* Description: Loads the given package by looking in standard places */
259 /* Description: Lists all known packages */
266 int Jim_packageInit(Jim_Interp
*interp
)
268 Jim_CreateCommand(interp
, "package", Jim_SubCmdProc
, (void *)package_command_table
, NULL
);