aio recvfrom was not null terminating the result
[jimtcl.git] / jim-package.c
blobe7f86baf5856465f1933b4b376df52416d7ec7d2
1 #include <unistd.h>
2 #include <string.h>
4 #include <jim.h>
5 #include <jim-subcmd.h>
7 /* -----------------------------------------------------------------------------
8 * Packages handling
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);
18 return JIM_ERR;
20 Jim_AddHashEntry(&interp->packages, name, (char *)ver);
21 return JIM_OK;
24 static char *JimFindPackage(Jim_Interp *interp, char **prefixes, int prefixc, const char *pkgName)
26 int i;
28 for (i = 0; i < prefixc; i++) {
29 char buf[JIM_PATH_LEN];
31 if (prefixes[i] == NULL)
32 continue;
34 if (strcmp(prefixes[i], ".") == 0) {
35 snprintf(buf, sizeof(buf), "%s.tcl", pkgName);
37 else {
38 snprintf(buf, sizeof(buf), "%s/%s.tcl", prefixes[i], pkgName);
41 if (access(buf, R_OK) == 0) {
42 return Jim_StrDup(buf);
45 snprintf(buf, sizeof(buf), "%s/%s.so", prefixes[i], pkgName);
46 if (access(buf, R_OK) == 0) {
47 return Jim_StrDup(buf);
50 return NULL;
53 /* Search for a suitable package under every dir specified by JIM_LIBPATH,
54 * and load it if possible. If a suitable package was loaded with success
55 * JIM_OK is returned, otherwise JIM_ERR is returned. */
56 static int JimLoadPackage(Jim_Interp *interp, const char *name, int flags)
58 Jim_Obj *libPathObjPtr;
59 char **prefixes, *path;
60 int prefixc, i, retCode = JIM_ERR;
62 libPathObjPtr = Jim_GetGlobalVariableStr(interp, JIM_LIBPATH, JIM_NONE);
63 if (libPathObjPtr == NULL) {
64 prefixc = 0;
65 libPathObjPtr = NULL;
67 else {
68 Jim_IncrRefCount(libPathObjPtr);
69 prefixc = Jim_ListLength(interp, libPathObjPtr);
72 prefixes = Jim_Alloc(sizeof(char *) * prefixc);
73 for (i = 0; i < prefixc; i++) {
74 Jim_Obj *prefixObjPtr;
76 if (Jim_ListIndex(interp, libPathObjPtr, i, &prefixObjPtr, JIM_NONE) != JIM_OK) {
77 prefixes[i] = NULL;
78 continue;
80 prefixes[i] = Jim_StrDup(Jim_GetString(prefixObjPtr, NULL));
83 /* Scan every directory for the the first match */
84 path = JimFindPackage(interp, prefixes, prefixc, name);
85 if (path != NULL) {
86 char *p = strrchr(path, '.');
88 /* Try to load/source it */
89 if (p && strcmp(p, ".tcl") == 0) {
90 retCode = Jim_EvalFile(interp, path);
92 #ifdef jim_ext_load
93 else {
94 retCode = Jim_LoadLibrary(interp, path);
96 #endif
97 Jim_Free(path);
99 else {
100 retCode = JIM_ERR;
102 for (i = 0; i < prefixc; i++)
103 Jim_Free(prefixes[i]);
104 Jim_Free(prefixes);
105 if (libPathObjPtr)
106 Jim_DecrRefCount(interp, libPathObjPtr);
107 return retCode;
110 int Jim_PackageRequire(Jim_Interp *interp, const char *name, int flags)
112 Jim_HashEntry *he;
113 int retcode = 0;
114 const char *version;
116 /* Start with an empty error string */
117 Jim_SetResultString(interp, "", 0);
119 he = Jim_FindHashEntry(&interp->packages, name);
120 if (he == NULL) {
121 /* Try to load the package. */
122 retcode = JimLoadPackage(interp, name, flags);
123 if (retcode != JIM_OK) {
124 if (flags & JIM_ERRMSG) {
125 int len;
127 Jim_GetString(Jim_GetResult(interp), &len);
128 Jim_SetResultFormatted(interp, "%#s%sCan't load package %s",
129 Jim_GetResult(interp), len ? "\n" : "", name);
131 return retcode;
133 else {
134 he = Jim_FindHashEntry(&interp->packages, name);
135 if (he == NULL) {
136 /* Did not call package provide, so we do it for them */
137 Jim_PackageProvide(interp, name, "1.0", 0);
139 version = "1.0";
141 else {
142 version = he->val;
146 else {
147 version = he->val;
149 Jim_SetResultString(interp, version, -1);
150 return retcode;
154 *----------------------------------------------------------------------
156 * package provide name ?version?
158 * This procedure is invoked to declare that a particular version
159 * of a particular package is now present in an interpreter. There
160 * must not be any other version of this package already
161 * provided in the interpreter.
163 * Results:
164 * Returns JIM_OK and sets the package version (or 1.0 if not specified).
166 *----------------------------------------------------------------------
168 static int package_cmd_provide(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
170 const char *version = "1.0";
172 if (argc == 2) {
173 version = Jim_GetString(argv[1], NULL);
175 return Jim_PackageProvide(interp, Jim_GetString(argv[0], NULL), version, JIM_ERRMSG);
179 *----------------------------------------------------------------------
181 * package require name ?version?
183 * This procedure is load a given package.
184 * Note that the version is ignored.
186 * Results:
187 * Returns JIM_OK and sets the package version.
189 *----------------------------------------------------------------------
191 static int package_cmd_require(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
193 /* package require failing is important enough to add to the stack */
194 interp->addStackTrace++;
196 return Jim_PackageRequire(interp, Jim_GetString(argv[0], NULL), JIM_ERRMSG);
200 *----------------------------------------------------------------------
202 * package list
204 * Returns a list of known packages
206 * Results:
207 * Returns JIM_OK and sets a list of known packages.
209 *----------------------------------------------------------------------
211 static int package_cmd_list(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
213 Jim_HashTableIterator *htiter;
214 Jim_HashEntry *he;
215 Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
217 htiter = Jim_GetHashTableIterator(&interp->packages);
218 while ((he = Jim_NextHashEntry(htiter)) != NULL) {
219 Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, he->key, -1));
221 Jim_FreeHashTableIterator(htiter);
223 Jim_SetResult(interp, listObjPtr);
225 return JIM_OK;
228 static const jim_subcmd_type package_command_table[] = {
229 {.cmd = "provide",
230 .args = "name ?version?",
231 .function = package_cmd_provide,
232 .minargs = 1,
233 .maxargs = 2,
234 .description = "Indicates that the current script provides the given package"},
235 {.cmd = "require",
236 .args = "name ?version?",
237 .function = package_cmd_require,
238 .minargs = 1,
239 .maxargs = 2,
240 .description = "Loads the given package by looking in standard places"},
241 {.cmd = "list",
242 .function = package_cmd_list,
243 .minargs = 0,
244 .maxargs = 0,
245 .description = "Lists all known packages"},
249 int Jim_packageInit(Jim_Interp *interp)
251 Jim_CreateCommand(interp, "package", Jim_SubCmdProc, (void *)package_command_table, NULL);
252 return JIM_OK;