usbmodeswitch: Updated to v.1.2.6 from shibby's branch.
[tomato.git] / release / src / router / usbmodeswitch / jim / jim-package.c
blob9caec0d8a341090658ae11b3e40fe456976e4f8e
1 #include <unistd.h>
2 #include <string.h>
4 #include "jim.h"
5 #include "jimautoconf.h"
6 #include "jim-subcmd.h"
8 /* -----------------------------------------------------------------------------
9 * Packages handling
10 * ---------------------------------------------------------------------------*/
12 int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags)
14 /* If the package was already provided returns an error. */
15 Jim_HashEntry *he = Jim_FindHashEntry(&interp->packages, name);
17 /* An empty result means the automatic entry. This can be replaced */
18 if (he && *(const char *)he->u.val) {
19 if (flags & JIM_ERRMSG) {
20 Jim_SetResultFormatted(interp, "package \"%s\" was already provided", name);
22 return JIM_ERR;
24 if (he) {
25 Jim_DeleteHashEntry(&interp->packages, name);
27 Jim_AddHashEntry(&interp->packages, name, (char *)ver);
28 return JIM_OK;
31 static char *JimFindPackage(Jim_Interp *interp, char **prefixes, int prefixc, const char *pkgName)
33 int i;
34 char *buf = Jim_Alloc(JIM_PATH_LEN);
36 for (i = 0; i < prefixc; i++) {
37 if (prefixes[i] == NULL)
38 continue;
40 /* Loadable modules are tried first */
41 #ifdef jim_ext_load
42 snprintf(buf, JIM_PATH_LEN, "%s/%s.so", prefixes[i], pkgName);
43 if (access(buf, R_OK) == 0) {
44 return buf;
46 #endif
47 if (strcmp(prefixes[i], ".") == 0) {
48 snprintf(buf, JIM_PATH_LEN, "%s.tcl", pkgName);
50 else {
51 snprintf(buf, JIM_PATH_LEN, "%s/%s.tcl", prefixes[i], pkgName);
54 if (access(buf, R_OK) == 0) {
55 return buf;
58 Jim_Free(buf);
59 return NULL;
62 /* Search for a suitable package under every dir specified by JIM_LIBPATH,
63 * and load it if possible. If a suitable package was loaded with success
64 * JIM_OK is returned, otherwise JIM_ERR is returned. */
65 static int JimLoadPackage(Jim_Interp *interp, const char *name, int flags)
67 Jim_Obj *libPathObjPtr;
68 char **prefixes, *path;
69 int prefixc, i, retCode = JIM_ERR;
71 libPathObjPtr = Jim_GetGlobalVariableStr(interp, JIM_LIBPATH, JIM_NONE);
72 if (libPathObjPtr == NULL) {
73 prefixc = 0;
74 libPathObjPtr = NULL;
76 else {
77 Jim_IncrRefCount(libPathObjPtr);
78 prefixc = Jim_ListLength(interp, libPathObjPtr);
81 prefixes = Jim_Alloc(sizeof(char *) * prefixc);
82 for (i = 0; i < prefixc; i++) {
83 Jim_Obj *prefixObjPtr;
85 if (Jim_ListIndex(interp, libPathObjPtr, i, &prefixObjPtr, JIM_NONE) != JIM_OK) {
86 prefixes[i] = NULL;
87 continue;
89 prefixes[i] = Jim_StrDup(Jim_String(prefixObjPtr));
92 /* Scan every directory for the the first match */
93 path = JimFindPackage(interp, prefixes, prefixc, name);
94 if (path != NULL) {
95 char *p = strrchr(path, '.');
97 /* Note: Even if the file fails to load, we consider the package loaded.
98 * This prevents issues with recursion.
99 * Use a dummy version of "" to signify this case.
101 Jim_PackageProvide(interp, name, "", 0);
103 /* Try to load/source it */
104 if (p && strcmp(p, ".tcl") == 0) {
105 retCode = Jim_EvalFileGlobal(interp, path);
107 #ifdef jim_ext_load
108 else {
109 retCode = Jim_LoadLibrary(interp, path);
111 #endif
112 if (retCode != JIM_OK) {
113 /* Upon failure, remove the dummy entry */
114 Jim_DeleteHashEntry(&interp->packages, name);
116 Jim_Free(path);
118 for (i = 0; i < prefixc; i++)
119 Jim_Free(prefixes[i]);
120 Jim_Free(prefixes);
121 if (libPathObjPtr)
122 Jim_DecrRefCount(interp, libPathObjPtr);
123 return retCode;
126 int Jim_PackageRequire(Jim_Interp *interp, const char *name, int flags)
128 Jim_HashEntry *he;
130 /* Start with an empty error string */
131 Jim_SetResultString(interp, "", 0);
133 he = Jim_FindHashEntry(&interp->packages, name);
134 if (he == NULL) {
135 /* Try to load the package. */
136 int retcode = JimLoadPackage(interp, name, flags);
137 if (retcode != JIM_OK) {
138 if (flags & JIM_ERRMSG) {
139 int len;
141 Jim_GetString(Jim_GetResult(interp), &len);
142 Jim_SetResultFormatted(interp, "%#s%sCan't load package %s",
143 Jim_GetResult(interp), len ? "\n" : "", name);
145 return retcode;
148 /* In case the package did no 'package provide' */
149 Jim_PackageProvide(interp, name, "1.0", 0);
151 /* Now it must exist */
152 he = Jim_FindHashEntry(&interp->packages, name);
155 Jim_SetResultString(interp, he->u.val, -1);
156 return JIM_OK;
160 *----------------------------------------------------------------------
162 * package provide name ?version?
164 * This procedure is invoked to declare that a particular version
165 * of a particular package is now present in an interpreter. There
166 * must not be any other version of this package already
167 * provided in the interpreter.
169 * Results:
170 * Returns JIM_OK and sets the package version (or 1.0 if not specified).
172 *----------------------------------------------------------------------
174 static int package_cmd_provide(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
176 const char *version = "1.0";
178 if (argc == 2) {
179 version = Jim_String(argv[1]);
181 return Jim_PackageProvide(interp, Jim_String(argv[0]), version, JIM_ERRMSG);
185 *----------------------------------------------------------------------
187 * package require name ?version?
189 * This procedure is load a given package.
190 * Note that the version is ignored.
192 * Results:
193 * Returns JIM_OK and sets the package version.
195 *----------------------------------------------------------------------
197 static int package_cmd_require(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
199 /* package require failing is important enough to add to the stack */
200 interp->addStackTrace++;
202 return Jim_PackageRequire(interp, Jim_String(argv[0]), JIM_ERRMSG);
206 *----------------------------------------------------------------------
208 * package list
210 * Returns a list of known packages
212 * Results:
213 * Returns JIM_OK and sets a list of known packages.
215 *----------------------------------------------------------------------
217 static int package_cmd_list(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
219 Jim_HashTableIterator *htiter;
220 Jim_HashEntry *he;
221 Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
223 htiter = Jim_GetHashTableIterator(&interp->packages);
224 while ((he = Jim_NextHashEntry(htiter)) != NULL) {
225 Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, he->key, -1));
227 Jim_FreeHashTableIterator(htiter);
229 Jim_SetResult(interp, listObjPtr);
231 return JIM_OK;
234 static const jim_subcmd_type package_command_table[] = {
235 {.cmd = "provide",
236 .args = "name ?version?",
237 .function = package_cmd_provide,
238 .minargs = 1,
239 .maxargs = 2,
240 .description = "Indicates that the current script provides the given package"},
241 {.cmd = "require",
242 .args = "name ?version?",
243 .function = package_cmd_require,
244 .minargs = 1,
245 .maxargs = 2,
246 .description = "Loads the given package by looking in standard places"},
247 {.cmd = "list",
248 .function = package_cmd_list,
249 .minargs = 0,
250 .maxargs = 0,
251 .description = "Lists all known packages"},
255 int Jim_packageInit(Jim_Interp *interp)
257 Jim_CreateCommand(interp, "package", Jim_SubCmdProc, (void *)package_command_table, NULL);
258 return JIM_OK;