diff options
Diffstat (limited to 'src/core/lt_path.c')
-rw-r--r-- | src/core/lt_path.c | 242 |
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 = <_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(<_upath[plen],path); + strcpy(<_vpath[plen],path); + + *lt_vmark++ = <_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 >= <_upath[plen])) + return lt_sunlock(1); + + if ((mark > lt_upath) && (mark[-1] != ':')) + return lt_sunlock(1); + + mark = <_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(<_upath[offset],pathv[-1],slen); + memcpy(<_vpath[offset],<_upath[offset],slen); + + if (pathv < lt_vmark) + lt_upath[offset + slen] = ':'; + + pathv[0] = pathv[-1]; + + if (pathv[-1] == mark) { + offset = mark - lt_vpath; + strcpy(<_vpath[offset],path); + memcpy(<_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); +} |