summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/lt_path.c242
1 files changed, 242 insertions, 0 deletions
diff --git a/src/core/lt_path.c b/src/core/lt_path.c
new file mode 100644
index 0000000..14eb0eb
--- /dev/null
+++ b/src/core/lt_path.c
@@ -0,0 +1,242 @@
+/*******************************************************************/
+/* sltdl: a surrogate ltdl implementation */
+/* Copyright (C) 2019 Z. Gilboa */
+/* Released under the Standard MIT License; see COPYING.SLTDL. */
+/*******************************************************************/
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <sltdl/sltdl.h>
+#include "sltdl_core.h"
+
+static off_t lt_plen;
+static off_t lt_plocs;
+static char * lt_upath;
+static char * lt_vpath;
+static char ** lt_vmark;
+static char ** lt_pathv;
+
+const char * lt_dlgetsearchpath(void)
+{
+ return lt_upath;
+}
+
+static int lt_dlsetsearchpath_locked(const char * path)
+{
+ const char * ch;
+ char * uch;
+ char * vch;
+ char ** pathv;
+ off_t elements;
+
+ if (path[0] != '/')
+ return 1;
+
+ elements = 1;
+
+ for (ch=&path[1]; *ch; ch++) {
+ if (*ch == ':') {
+ if (ch[1] != '/')
+ return 1;
+
+ elements++;
+ }
+ }
+
+ if (++elements > lt_plocs) {
+ if (lt_pathv) {
+ free(lt_pathv);
+ lt_pathv = 0;
+ }
+
+ lt_plocs = elements;
+ lt_plocs += 0x3f;
+ lt_plocs |= 0x3f;
+ lt_plocs ^= 0x3f;
+
+ if (!(lt_pathv = calloc(lt_plocs,sizeof(char *))))
+ return 1;
+ }
+
+ if ((ch - path) > lt_plen) {
+ if (lt_upath) {
+ free(lt_upath);
+ lt_upath = 0;
+ }
+
+ lt_plen = ((ch - path + 1) <= 0x800)
+ ? 0x800 : ch - path + 1;
+
+ lt_plen += 0x7ff;
+ lt_plen |= 0x7ff;
+ lt_plen ^= 0x7ff;
+
+ if (!(lt_upath = calloc(2*lt_plen,1)))
+ return 1;
+
+ lt_vpath = &lt_upath[lt_plen];
+ }
+
+ pathv = lt_pathv;
+ *pathv++ = lt_vpath;
+
+ for (ch=path, uch=lt_upath, vch=lt_vpath; *ch; ch++) {
+ if (*ch == ':') {
+ *uch++ = ch[0];
+ *uch++ = ch[1];
+
+ *vch++ = 0;
+ *pathv = vch;
+ *vch++ = ch[1];
+
+ ch++;
+ pathv++;
+ } else {
+ *uch++ = *ch;
+ *vch++ = *ch;
+ }
+ }
+
+ lt_vmark = pathv;
+
+ return 0;
+}
+
+int lt_dlsetsearchpath(const char * path)
+{
+ lt_slock();
+ return lt_sunlock(lt_dlsetsearchpath_locked(path));
+}
+
+int lt_dladdsearchdir(const char * path)
+{
+ int ret;
+ const char * ch;
+ char * buf;
+ off_t alen;
+ off_t plen;
+
+ if (path[0] != '/')
+ return 1;
+
+ for (ch=path; *ch; ch++)
+ if (*ch == ':')
+ return 1;
+
+ lt_slock();
+
+ alen = strlen(path);
+ plen = strlen(lt_upath);
+
+ /* no allocation needed? */
+ if (!lt_pathv[lt_plocs - 2] && ((plen + 1 + alen + 1) <= lt_plen)) {
+ lt_upath[plen] = ':';
+ lt_vpath[plen] = 0;
+
+ plen++;
+
+ strcpy(&lt_upath[plen],path);
+ strcpy(&lt_vpath[plen],path);
+
+ *lt_vmark++ = &lt_vpath[plen];
+
+ return lt_sunlock(0);
+ }
+
+ /* (allocation needed) */
+ if (!(buf = malloc(plen + 1 + alen + 1)))
+ return lt_sunlock(1);
+
+ sprintf(buf,"%s:%s",lt_upath,path);
+
+ ret = lt_dlsetsearchpath_locked(buf);
+
+ free(buf);
+
+ return lt_sunlock(ret);
+}
+
+int lt_dlinsertsearchdir(const char * mark, const char * path)
+{
+ int ret;
+ const char * ch;
+ char * buf;
+ char * dst;
+ off_t alen;
+ off_t plen;
+ off_t slen;
+ off_t offset;
+ char ** pathv;
+
+ if (path[0] != '/')
+ return 1;
+
+ if (!mark)
+ return lt_dladdsearchdir(path);
+
+ for (ch=path; *ch; ch++)
+ if (*ch == ':')
+ return 1;
+
+ lt_slock();
+
+ alen = strlen(path);
+ plen = strlen(lt_upath);
+
+ if ((mark < lt_upath) || (mark >= &lt_upath[plen]))
+ return lt_sunlock(1);
+
+ if ((mark > lt_upath) && (mark[-1] != ':'))
+ return lt_sunlock(1);
+
+ mark = &lt_vpath[mark - lt_upath];
+
+ /* no allocation needed? */
+ if (!lt_pathv[lt_plocs - 2] && ((plen + 1 + alen + 1) <= lt_plen)) {
+ for (pathv=lt_vmark; pathv>=lt_pathv; pathv--) {
+ slen = strlen(pathv[-1]);
+ offset = pathv[-1] - lt_vpath;
+ offset += alen + 1;
+
+ memcpy(&lt_upath[offset],pathv[-1],slen);
+ memcpy(&lt_vpath[offset],&lt_upath[offset],slen);
+
+ if (pathv < lt_vmark)
+ lt_upath[offset + slen] = ':';
+
+ pathv[0] = pathv[-1];
+
+ if (pathv[-1] == mark) {
+ offset = mark - lt_vpath;
+ strcpy(&lt_vpath[offset],path);
+ memcpy(&lt_upath[offset],path,alen);
+ lt_upath[offset+alen] = ':';
+ lt_vmark++;
+ return lt_sunlock(0);
+ }
+ }
+ }
+
+ /* (allocation needed) */
+ if (!(buf = malloc(plen + 1 + alen + 1)))
+ return lt_sunlock(1);
+
+ for (dst=buf, pathv=lt_pathv; *pathv; pathv++) {
+ if (*pathv == mark)
+ dst += sprintf(dst,"%s:",path);
+
+ if (pathv[1])
+ dst += sprintf(dst,"%s:",*pathv);
+ else
+ dst += sprintf(dst,"%s",*pathv);
+ }
+
+ ret = lt_dlsetsearchpath_locked(buf);
+
+ free(buf);
+
+ return lt_sunlock(ret);
+}