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
);
32 Jim_DeleteHashEntry(&interp
->packages
, name
);
34 Jim_AddHashEntry(&interp
->packages
, name
, (char *)ver
);
38 static char *JimFindPackage(Jim_Interp
*interp
, char **prefixes
, int prefixc
, const char *pkgName
)
41 char *buf
= Jim_Alloc(JIM_PATH_LEN
);
43 for (i
= 0; i
< prefixc
; i
++) {
44 if (prefixes
[i
] == NULL
)
47 /* Loadable modules are tried first */
49 snprintf(buf
, JIM_PATH_LEN
, "%s/%s.so", prefixes
[i
], pkgName
);
50 if (access(buf
, R_OK
) == 0) {
54 if (strcmp(prefixes
[i
], ".") == 0) {
55 snprintf(buf
, JIM_PATH_LEN
, "%s.tcl", pkgName
);
58 snprintf(buf
, JIM_PATH_LEN
, "%s/%s.tcl", prefixes
[i
], pkgName
);
61 if (access(buf
, R_OK
) == 0) {
69 /* Search for a suitable package under every dir specified by JIM_LIBPATH,
70 * and load it if possible. If a suitable package was loaded with success
71 * JIM_OK is returned, otherwise JIM_ERR is returned. */
72 static int JimLoadPackage(Jim_Interp
*interp
, const char *name
, int flags
)
74 Jim_Obj
*libPathObjPtr
;
75 char **prefixes
, *path
;
76 int prefixc
, i
, retCode
= JIM_ERR
;
78 libPathObjPtr
= Jim_GetGlobalVariableStr(interp
, JIM_LIBPATH
, JIM_NONE
);
79 if (libPathObjPtr
== NULL
) {
84 Jim_IncrRefCount(libPathObjPtr
);
85 prefixc
= Jim_ListLength(interp
, libPathObjPtr
);
88 prefixes
= Jim_Alloc(sizeof(char *) * prefixc
);
89 for (i
= 0; i
< prefixc
; i
++) {
90 Jim_Obj
*prefixObjPtr
;
92 if (Jim_ListIndex(interp
, libPathObjPtr
, i
, &prefixObjPtr
, JIM_NONE
) != JIM_OK
) {
96 prefixes
[i
] = Jim_StrDup(Jim_String(prefixObjPtr
));
99 /* Scan every directory for the the first match */
100 path
= JimFindPackage(interp
, prefixes
, prefixc
, name
);
102 char *p
= strrchr(path
, '.');
104 /* Note: Even if the file fails to load, we consider the package loaded.
105 * This prevents issues with recursion.
106 * Use a dummy version of "" to signify this case.
108 Jim_PackageProvide(interp
, name
, "", 0);
110 /* Try to load/source it */
111 if (p
&& strcmp(p
, ".tcl") == 0) {
112 retCode
= Jim_EvalFileGlobal(interp
, path
);
116 retCode
= Jim_LoadLibrary(interp
, path
);
119 if (retCode
!= JIM_OK
) {
120 /* Upon failure, remove the dummy entry */
121 Jim_DeleteHashEntry(&interp
->packages
, name
);
125 for (i
= 0; i
< prefixc
; i
++)
126 Jim_Free(prefixes
[i
]);
129 Jim_DecrRefCount(interp
, libPathObjPtr
);
133 int Jim_PackageRequire(Jim_Interp
*interp
, const char *name
, int flags
)
137 /* Start with an empty error string */
138 Jim_SetResultString(interp
, "", 0);
140 he
= Jim_FindHashEntry(&interp
->packages
, name
);
142 /* Try to load the package. */
143 int retcode
= JimLoadPackage(interp
, name
, flags
);
144 if (retcode
!= JIM_OK
) {
145 if (flags
& JIM_ERRMSG
) {
148 Jim_GetString(Jim_GetResult(interp
), &len
);
149 Jim_SetResultFormatted(interp
, "%#s%sCan't load package %s",
150 Jim_GetResult(interp
), len
? "\n" : "", name
);
155 /* In case the package did no 'package provide' */
156 Jim_PackageProvide(interp
, name
, "1.0", 0);
158 /* Now it must exist */
159 he
= Jim_FindHashEntry(&interp
->packages
, name
);
162 Jim_SetResultString(interp
, he
->u
.val
, -1);
167 *----------------------------------------------------------------------
169 * package provide name ?version?
171 * This procedure is invoked to declare that
172 * a particular package is now present in an interpreter.
173 * The package must not already be provided in the interpreter.
176 * Returns JIM_OK and sets results as "1.0" (the given version is ignored)
178 *----------------------------------------------------------------------
180 static int package_cmd_provide(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
182 return Jim_PackageProvide(interp
, Jim_String(argv
[0]), package_version_1
, JIM_ERRMSG
);
186 *----------------------------------------------------------------------
188 * package require name ?version?
190 * This procedure is load a given package.
191 * Note that the version is ignored.
194 * Returns JIM_OK and sets the package version.
196 *----------------------------------------------------------------------
198 static int package_cmd_require(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
200 /* package require failing is important enough to add to the stack */
201 interp
->addStackTrace
++;
203 return Jim_PackageRequire(interp
, Jim_String(argv
[0]), JIM_ERRMSG
);
207 *----------------------------------------------------------------------
211 * Returns a list of known packages
214 * Returns JIM_OK and sets a list of known packages.
216 *----------------------------------------------------------------------
218 static int package_cmd_list(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
220 Jim_HashTableIterator
*htiter
;
222 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
224 htiter
= Jim_GetHashTableIterator(&interp
->packages
);
225 while ((he
= Jim_NextHashEntry(htiter
)) != NULL
) {
226 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, he
->key
, -1));
228 Jim_FreeHashTableIterator(htiter
);
230 Jim_SetResult(interp
, listObjPtr
);
235 static const jim_subcmd_type package_command_table
[] = {
242 /* Description: Indicates that the current script provides the given package */
250 /* Description: Loads the given package by looking in standard places */
258 /* Description: Lists all known packages */
265 int Jim_packageInit(Jim_Interp
*interp
)
267 Jim_CreateCommand(interp
, "package", Jim_SubCmdProc
, (void *)package_command_table
, NULL
);