Logo Search packages:      
Sourcecode: ksh version File versions  Download package

dllscan.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*          Copyright (c) 1997-2007 AT&T Intellectual Property          *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                    by AT&T Intellectual Property                     *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                                                                      *
***********************************************************************/
#pragma prototyped
/*
 * Glenn Fowler
 * AT&T Research
 */

#define _DLLINFO_PRIVATE_ \
      char* sib[3]; \
      char  sibbuf[64]; \
      char  envbuf[64];

#define _DLLSCAN_PRIVATE_ \
      Dllent_t    entry; \
      Uniq_t*           uniq; \
      int         flags; \
      Vmalloc_t*  vm; \
      Dt_t*       dict; \
      Dtdisc_t    disc; \
      FTS*        fts; \
      FTSENT*           ent; \
      Sfio_t*           tmp; \
      char**            sb; \
      char**            sp; \
      char*       pb; \
      char*       pp; \
      char*       pe; \
      int         off; \
      int         prelen; \
      int         suflen; \
      char**            lib; \
      char        nam[64]; \
      char        pat[64]; \
      char        buf[64];

#define DLL_MATCH_DONE        0x8000
#define DLL_MATCH_NAME        0x4000
#define DLL_MATCH_VERSION     0x2000

#include <ast.h>
#include <cdt.h>
#include <ctype.h>
#include <error.h>
#include <fts.h>
#include <vmalloc.h>

typedef struct Uniq_s
{
      Dtlink_t    link;
      char        name[1];
} Uniq_t;

#include <dlldefs.h>

static char       bin[] = "bin";
static char       lib[] = "lib";

/*
 * we need a sibling dir in PATH to search for dlls
 * the confstr LIBPATH provides the local info
 *
 *    <sibling-dir>[:<env-var>[:<host-pattern>]][,...]
 *
 * if <host-pattern> is present then it must match confstr HOSTTYPE
 */

Dllinfo_t*
dllinfo(void)
{
      register char*          s;
      register char*          h;
      char*             d;
      char*             v;
      char*             p;
      int               dn;
      int               vn;
      int               pn;
      char              pat[256];

      static Dllinfo_t  info;

      if (!info.sibling)
      {
            info.sibling = info.sib;
            if (*(s = astconf("LIBPATH", NiL, NiL)))
            {
                  while (*s == ':' || *s == ',')
                        s++;
                  if (*s)
                  {
                        h = 0;
                        for (;;)
                        {
                              for (d = s; *s && *s != ':' && *s != ','; s++);
                              if (!(dn = s - d))
                                    d = 0;
                              if (*s == ':')
                              {
                                    for (v = ++s; *s && *s != ':' && *s != ','; s++);
                                    if (!(vn = s - v))
                                          v = 0;
                                    if (*s == ':')
                                    {
                                          for (p = ++s; *s && *s != ':' && *s != ','; s++);
                                          if (!(pn = s - p))
                                                p = 0;
                                    }
                                    else
                                          p = 0;
                              }
                              else
                              {
                                    v = 0;
                                    p = 0;
                              }
                              while (*s && *s++ != ',');
                              if (!*s || !p || !h && !*(h = astconf("HOSTTYPE", NiL, NiL)))
                                    break;
                              if (pn >= sizeof(pat))
                                    pn = sizeof(pat) - 1;
                              memcpy(pat, p, pn);
                              pat[pn] = 0;
                              if (strmatch(h, pat))
                                    break;
                        }
                        if (d && dn < sizeof(info.sibbuf))
                        {
                              memcpy(info.sibbuf, d, dn);
                              info.sibling[0] = info.sibbuf;
                        }
                        if (v && vn < sizeof(info.envbuf))
                        {
                              memcpy(info.envbuf, v, vn);
                              info.env = info.envbuf;
                        }
                  }
            }
            if (!info.sibling[0] || streq(info.sibling[0], bin))
                  info.sibling[0] = bin;
            if (!streq(info.sibling[0], lib))
                  info.sibling[1] = lib;
            if (!info.env)
                  info.env = "LD_LIBRARY_PATH";
            info.prefix = astconf("LIBPREFIX", NiL, NiL);
            info.suffix = astconf("LIBSUFFIX", NiL, NiL);
            if (streq(info.suffix, ".dll"))
                  info.flags |= DLL_INFO_PREVER;
            else
                  info.flags |= DLL_INFO_DOTVER;
      }
      return &info;
}

/*
 * fts version sort order
 * higher versions appear first
 */

static int
vercmp(FTSENT* const* ap, FTSENT* const* bp)
{
      register unsigned char* a = (unsigned char*)(*ap)->fts_name;
      register unsigned char* b = (unsigned char*)(*bp)->fts_name;
      register int            n;
      register int            m;
      char*             e;

      for (;;)
      {
            if (isdigit(*a) && isdigit(*b))
            {
                  m = strtol((char*)a, &e, 10);
                  a = (unsigned char*)e;
                  n = strtol((char*)b, &e, 10);
                  b = (unsigned char*)e;
                  if (n -= m)
                        return n;
            }
            if (n = *a - *b)
                  return n;
            if (!*a++)
                  return *b ? 0 : -1;
            if (!*b++)
                  return 1;
      }
      /*NOTREACHED*/
}

/*
 * open a scan stream
 */

Dllscan_t*
dllsopen(const char* lib, const char* name, const char* version)
{
      register char*    s;
      register char*    t;
      Dllscan_t*  scan;
      Dllinfo_t*  info;
      Vmalloc_t*  vm;
      int         i;
      char        buf[32];

      if (!(vm = vmopen(Vmdcheap, Vmlast, 0)))
            return 0;
      if (lib && *lib && (*lib != '-' || *(lib + 1)))
      {
            /*
             * grab the local part of the library id
             */

            if (s = strrchr(lib, ':'))
                  lib = (const char*)(s + 1);
            i = 2 * sizeof(char**) + strlen(lib) + 5;
      }
      else
      {
            lib = 0;
            i = 0;
      }
      if (!(scan = vmnewof(vm, 0, Dllscan_t, 1, i)) || !(scan->tmp = sfstropen()))
      {
            vmclose(vm);
            return 0;
      }
      if (lib)
      {
            scan->lib = (char**)(scan + 1);
            s = *scan->lib = (char*)(scan->lib + 2);
            sfsprintf(s, i, "lib/%s", lib);
      }
      scan->vm = vm;
      info = dllinfo();
      scan->flags = info->flags;
      if (!name || !*name || *name == '-' && !*(name + 1))
      {
            name = (const char*)"?*";
            scan->flags |= DLL_MATCH_NAME;
      }
      else if (t = strrchr(name, '/'))
      {
            if (!(scan->pb = vmnewof(vm, 0, char, t - (char*)name, 2)))
                  goto bad;
            memcpy(scan->pb, name, t - (char*)name);
            name = (const char*)(t + 1);
      }
      if (!version || !*version || *version == '-' && !*(version + 1))
      {
            version = 0;
            scan->flags |= DLL_MATCH_VERSION;
            sfsprintf(scan->nam, sizeof(scan->nam), "%s%s%s", info->prefix, name, info->suffix);
      }
      else if (scan->flags & DLL_INFO_PREVER)
      {
            sfprintf(scan->tmp, "%s%s", info->prefix, name);
            for (s = (char*)version; *s; s++)
                  if (isdigit(*s))
                        sfputc(scan->tmp, *s);
            sfprintf(scan->tmp, "%s", info->suffix);
            if (!(s = sfstruse(scan->tmp)))
                  goto bad;
            sfsprintf(scan->nam, sizeof(scan->nam), "%s", s);
      }
      else
      {
            scan->flags |= DLL_MATCH_VERSION;
            sfsprintf(scan->nam, sizeof(scan->nam), "%s%s%s.%s", info->prefix, name, info->suffix, version);
      }
      if (scan->flags & (DLL_MATCH_NAME|DLL_MATCH_VERSION))
      {
            if (scan->flags & DLL_INFO_PREVER)
            {
                  if (!version)
                        version = "*([0-9_])";
                  else
                  {
                        t = buf;
                        for (s = (char*)version; *s; s++)
                              if (isdigit(*s) && t < &buf[sizeof(buf)-1])
                                    *t++ = *s;
                        *t = 0;
                        version = (const char*)buf;
                  }
                  sfsprintf(scan->pat, sizeof(scan->pat), "%s%s%s%s", info->prefix, name, version, info->suffix);
            }
            else if (version)
                  sfsprintf(scan->pat, sizeof(scan->pat), "%s%s@(%s([-.])%s%s|%s.%s)", info->prefix, name, strchr(version, '.') ? "@" : "?", version, info->suffix, info->suffix, version);
            else
            {
                  version = "*([0-9.])";
                  sfsprintf(scan->pat, sizeof(scan->pat), "%s%s@(?([-.])%s%s|%s%s)", info->prefix, name, version, info->suffix, info->suffix, version);
            }
      }
      scan->sp = scan->sb = (scan->lib ? scan->lib : info->sibling);
      scan->prelen = strlen(info->prefix);
      scan->suflen = strlen(info->suffix);
      return scan;
 bad:
      dllsclose(scan);
      return 0;
}

/*
 * close a scan stream
 */

int
dllsclose(Dllscan_t* scan)
{
      if (!scan)
            return -1;
      if (scan->fts)
            fts_close(scan->fts);
      if (scan->dict)
            dtclose(scan->dict);
      if (scan->tmp)
            sfclose(scan->tmp);
      if (scan->vm)
            vmclose(scan->vm);
      return 0;
}

/*
 * return the next scan stream entry
 */

Dllent_t*
dllsread(register Dllscan_t* scan)
{
      register char*          p;
      register char*          b;
      register char*          t;
      register Uniq_t*  u;
      register int            n;
      register int            m;

      if (scan->flags & DLL_MATCH_DONE)
            return 0;
 again:
      do
      {
            while (!scan->ent || !(scan->ent = scan->ent->fts_link))
            {
                  if (scan->fts)
                  {
                        fts_close(scan->fts);
                        scan->fts = 0;
                  }
                  if (!scan->pb)
                        scan->pb = pathbin();
                  else if (!*scan->sp)
                  {
                        scan->sp = scan->sb;
                        if (!*scan->pe++)
                              return 0;
                        scan->pb = scan->pe;
                  }
                  for (p = scan->pp = scan->pb; *p && *p != ':'; p++)
                        if (*p == '/')
                              scan->pp = p;
                  scan->pe = p;
                  if (*scan->sp == bin)
                        scan->off = sfprintf(scan->tmp, "%-.*s", scan->pe - scan->pb, scan->pb);
                  else
                        scan->off = sfprintf(scan->tmp, "%-.*s/%s", scan->pp - scan->pb, scan->pb, *scan->sp);
                  scan->sp++;
                  if (!(scan->flags & DLL_MATCH_NAME))
                  {
                        sfprintf(scan->tmp, "/%s", scan->nam);
                        if (!(p = sfstruse(scan->tmp)))
                              return 0;
                        if (!eaccess(p, R_OK))
                        {
                              b = scan->nam;
                              goto found;
                        }
                        if (errno != ENOENT)
                              continue;
                  }
                  if (scan->flags & (DLL_MATCH_NAME|DLL_MATCH_VERSION))
                  {
                        sfstrseek(scan->tmp, scan->off, SEEK_SET);
                        if (!(t = sfstruse(scan->tmp)))
                              return 0;
                        if ((scan->fts = fts_open((char**)t, FTS_LOGICAL|FTS_NOPOSTORDER|FTS_ONEPATH, vercmp)) && (scan->ent = fts_read(scan->fts)) && (scan->ent = fts_children(scan->fts, FTS_NOSTAT)))
                              break;
                  }
            }
      } while (!strmatch(scan->ent->fts_name, scan->pat));
      b = scan->ent->fts_name;
      sfstrseek(scan->tmp, scan->off, SEEK_SET);
      sfprintf(scan->tmp, "/%s", b);
      if (!(p = sfstruse(scan->tmp)))
            return 0;
 found:
      b = scan->buf + sfsprintf(scan->buf, sizeof(scan->buf), "%s", b + scan->prelen);
      if (!(scan->flags & DLL_INFO_PREVER))
            while (b > scan->buf)
            {
                  if (!isdigit(*(b - 1)) && *(b - 1) != '.')
                        break;
                  b--;
            }
      b -= scan->suflen;
      if (b > (scan->buf + 2) && (*(b - 1) == 'g' || *(b - 1) == 'O') && *(b - 2) == '-')
            b -= 2;
      n = m = 0;
      for (t = b; t > scan->buf; t--)
            if (isdigit(*(t - 1)))
                  n = 1;
            else if (*(t - 1) != m)
            {
                  if (*(t - 1) == '.' || *(t - 1) == '-' || *(t - 1) == '_')
                  {
                        n = 1;
                        if (m)
                        {
                              m = -1;
                              t--;
                              break;
                        }
                        m = *(t - 1);
                  }
                  else
                        break;
            }
      if (n)
      {
            if (isdigit(t[0]) && isdigit(t[1]) && !isdigit(t[2]))
                  n = (t[0] - '0') * 10 + (t[1] - '0');
            else if (isdigit(t[1]) && isdigit(t[2]) && !isdigit(t[3]))
                  n = (t[1] - '0') * 10 + (t[2] - '0');
            else
                  n = 0;
            if (n && !(n & (n - 1)))
            {
                  if (!isdigit(t[0]))
                        t++;
                  m = *(t += 2);
            }
            if (m || (scan->flags & DLL_INFO_PREVER))
                  b = t;
      }
      *b = 0;
      if (!*(b = scan->buf))
            goto again;
      if (scan->uniq)
      {
            if (!scan->dict)
            {
                  scan->disc.key = offsetof(Uniq_t, name);
                  scan->disc.size = 0;
                  scan->disc.link = offsetof(Uniq_t, link);
                  if (!(scan->dict = dtopen(&scan->disc, Dthash)))
                        return 0;
                  dtinsert(scan->dict, scan->uniq);
            }
            if (dtmatch(scan->dict, b))
                  goto again;
            if (!(u = vmnewof(scan->vm, 0, Uniq_t, 1, strlen(b))))
                  return 0;
            strcpy(u->name, b);
            dtinsert(scan->dict, u);
      }
      else if (!(scan->flags & DLL_MATCH_NAME))
            scan->flags |= DLL_MATCH_DONE;
      else if (!(scan->uniq = vmnewof(scan->vm, 0, Uniq_t, 1, strlen(b))))
            return 0;
      else
            strcpy(scan->uniq->name, b);
      scan->entry.name = b;
      scan->entry.path = p;
      return &scan->entry;
}

Generated by  Doxygen 1.6.0   Back to index