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 /* REVISIT: Move off stack */
30 char buf
[JIM_PATH_LEN
];
32 if (prefixes
[i
] == NULL
)
35 if (strcmp(prefixes
[i
], ".") == 0) {
36 snprintf(buf
, sizeof(buf
), "%s.tcl", pkgName
);
39 snprintf(buf
, sizeof(buf
), "%s/%s.tcl", prefixes
[i
], pkgName
);
42 if (access(buf
, R_OK
) == 0) {
43 return Jim_StrDup(buf
);
47 snprintf(buf
, sizeof(buf
), "%s/%s.so", prefixes
[i
], pkgName
);
48 if (access(buf
, R_OK
) == 0) {
49 return Jim_StrDup(buf
);
56 /* Search for a suitable package under every dir specified by JIM_LIBPATH,
57 * and load it if possible. If a suitable package was loaded with success
58 * JIM_OK is returned, otherwise JIM_ERR is returned. */
59 static int JimLoadPackage(Jim_Interp
*interp
, const char *name
, int flags
)
61 Jim_Obj
*libPathObjPtr
;
62 char **prefixes
, *path
;
63 int prefixc
, i
, retCode
= JIM_ERR
;
65 libPathObjPtr
= Jim_GetGlobalVariableStr(interp
, JIM_LIBPATH
, JIM_NONE
);
66 if (libPathObjPtr
== NULL
) {
71 Jim_IncrRefCount(libPathObjPtr
);
72 prefixc
= Jim_ListLength(interp
, libPathObjPtr
);
75 prefixes
= Jim_Alloc(sizeof(char *) * prefixc
);
76 for (i
= 0; i
< prefixc
; i
++) {
77 Jim_Obj
*prefixObjPtr
;
79 if (Jim_ListIndex(interp
, libPathObjPtr
, i
, &prefixObjPtr
, JIM_NONE
) != JIM_OK
) {
83 prefixes
[i
] = Jim_StrDup(Jim_GetString(prefixObjPtr
, NULL
));
86 /* Scan every directory for the the first match */
87 path
= JimFindPackage(interp
, prefixes
, prefixc
, name
);
89 char *p
= strrchr(path
, '.');
91 /* Try to load/source it */
92 if (p
&& strcmp(p
, ".tcl") == 0) {
93 retCode
= Jim_EvalFile(interp
, path
);
97 retCode
= Jim_LoadLibrary(interp
, path
);
105 for (i
= 0; i
< prefixc
; i
++)
106 Jim_Free(prefixes
[i
]);
109 Jim_DecrRefCount(interp
, libPathObjPtr
);
113 int Jim_PackageRequire(Jim_Interp
*interp
, const char *name
, int flags
)
119 /* Start with an empty error string */
120 Jim_SetResultString(interp
, "", 0);
122 he
= Jim_FindHashEntry(&interp
->packages
, name
);
124 /* Try to load the package. */
125 retcode
= JimLoadPackage(interp
, name
, flags
);
126 if (retcode
!= JIM_OK
) {
127 if (flags
& JIM_ERRMSG
) {
130 Jim_GetString(Jim_GetResult(interp
), &len
);
131 Jim_SetResultFormatted(interp
, "%#s%sCan't load package %s",
132 Jim_GetResult(interp
), len
? "\n" : "", name
);
137 he
= Jim_FindHashEntry(&interp
->packages
, name
);
139 /* Did not call package provide, so we do it for them */
140 Jim_PackageProvide(interp
, name
, "1.0", 0);
152 Jim_SetResultString(interp
, version
, -1);
157 *----------------------------------------------------------------------
159 * package provide name ?version?
161 * This procedure is invoked to declare that a particular version
162 * of a particular package is now present in an interpreter. There
163 * must not be any other version of this package already
164 * provided in the interpreter.
167 * Returns JIM_OK and sets the package version (or 1.0 if not specified).
169 *----------------------------------------------------------------------
171 static int package_cmd_provide(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
173 const char *version
= "1.0";
176 version
= Jim_GetString(argv
[1], NULL
);
178 return Jim_PackageProvide(interp
, Jim_GetString(argv
[0], NULL
), version
, JIM_ERRMSG
);
182 *----------------------------------------------------------------------
184 * package require name ?version?
186 * This procedure is load a given package.
187 * Note that the version is ignored.
190 * Returns JIM_OK and sets the package version.
192 *----------------------------------------------------------------------
194 static int package_cmd_require(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
196 /* package require failing is important enough to add to the stack */
197 interp
->addStackTrace
++;
199 return Jim_PackageRequire(interp
, Jim_GetString(argv
[0], NULL
), JIM_ERRMSG
);
203 *----------------------------------------------------------------------
207 * Returns a list of known packages
210 * Returns JIM_OK and sets a list of known packages.
212 *----------------------------------------------------------------------
214 static int package_cmd_list(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
216 Jim_HashTableIterator
*htiter
;
218 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
220 htiter
= Jim_GetHashTableIterator(&interp
->packages
);
221 while ((he
= Jim_NextHashEntry(htiter
)) != NULL
) {
222 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, he
->key
, -1));
224 Jim_FreeHashTableIterator(htiter
);
226 Jim_SetResult(interp
, listObjPtr
);
231 static const jim_subcmd_type package_command_table
[] = {
233 .args
= "name ?version?",
234 .function
= package_cmd_provide
,
237 .description
= "Indicates that the current script provides the given package"},
239 .args
= "name ?version?",
240 .function
= package_cmd_require
,
243 .description
= "Loads the given package by looking in standard places"},
245 .function
= package_cmd_list
,
248 .description
= "Lists all known packages"},
252 int Jim_packageInit(Jim_Interp
*interp
)
254 Jim_CreateCommand(interp
, "package", Jim_SubCmdProc
, (void *)package_command_table
, NULL
);