www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2001/07/07/12:10:06

From: "Mark E." <snowball3 AT bigfoot DOT com>
To: djgpp-workers AT delorie DOT com
Date: Sat, 7 Jul 2001 12:10:03 -0400
MIME-Version: 1.0
Subject: Re: dosexec.c changes
Message-ID: <3B46FC1B.14992.4A1DB3@localhost>
In-reply-to: <2110-Sat07Jul2001092643+0300-eliz@is.elta.co.il>
References: <3B45C9F9 DOT 1814 DOT A88009 AT localhost> (snowball3 AT bigfoot DOT com)
X-mailer: Pegasus Mail for Win32 (v3.12c)
Reply-To: djgpp-workers AT delorie DOT com
Errors-To: nobody AT delorie DOT com
X-Mailing-List: djgpp-workers AT delorie DOT com
X-Unsubscribes-To: listserv AT delorie DOT com

> Shouldn't we add another test like this after an extension is
> appended?

I have no idea. If you think it's needed, I'll add it.

Rev 3 below:
static int
find_interpreter (const char *path, char *ext)
{
  int i, is_dir;

  for (i = 0; interpreters[i].extension; ++i)
  {
    if (stricmp(ext, interpreters[i].extension) == 0)
      break;
  }

  if (access(path, F_OK) == 0 && (is_dir = access(path, D_OK)) != 0)
    return i;

  errno = is_dir ? EISDIR : ENOENT;
  return -1;
}

static int
find_extension (const char *path, char *ext)
{
  int i, is_dir;

  for (i = 0; interpreters[i].extension; ++i)
  {
    if (interpreters[i].flags & INTERP_FLAG_SKIP_SEARCH)
      continue;
    strcpy(ext, interpreters[i].extension);
    if (access(path, F_OK) == 0 && (is_dir = access(path, D_OK)) != 0)
      return i;
  }

  *ext = 0;
  errno = is_dir ? EISDIR : ENOENT;
  return -1;
}

/* for libc/dosexec.h */
#define SPAWN_FLAG_EXTENSION_SEARCH   1
#define SPAWN_FLAG_INTERP_ONLY_SEARCH 2

#define SPAWN_SEARCH_FLAGS \
  (SPAWN_FLAG_EXTENSION_SEARCH | SPAWN_FLAG_INTERP_ONLY_SEARCH)

int __djgpp_spawn(int mode, const char *path, char *const argv[],
                  char *const envp[], unsigned long flags);

int __spawnve(int mode, const char *path, char *const argv[],
              char *const envp[])
{
  return __djgpp_spawn(mode, path, argv, envp, SPAWN_FLAG_EXTENSION_SEARCH);
}
  
int __djgpp_spawn(int mode, const char *path, char *const argv[],
                     char *const envp[], unsigned long flags)
{
  /* This is the one that does the work! */
  union { char *const *x; char **p; } u;
  const int no_interp_found = -1;
  int i = no_interp_found;
  char **argvp;
  char **envpp;
  char rpath[FILENAME_MAX + 4], *rp, *rd = 0;
  int e = errno;
  int ret_code;

  if (path == 0 || argv[0] == 0)
  {
    errno = EINVAL;
    return -1;
  }
  if (mode == P_NOWAIT)
  {
    errno = ENOSYS;
    return -1;
  }
  if (strlen(path) > FILENAME_MAX - 1)
  {
    errno = ENAMETOOLONG;
    return -1;
  }

  u.x = argv; argvp = u.p;
  u.x = envp; envpp = u.p;

  /* Set defaults for the environment and search method.  */
  if (envpp == NULL)
    envpp = environ;

  if ((flags & SPAWN_SEARCH_FLAGS) == 0)
    flags |= SPAWN_FLAG_EXTENSION_SEARCH;

  /* Copy the path to rpath and also mark where the extension is.  */
  fflush(stdout); /* just in case */
  for (rp=rpath; *path; *rp++ = *path++)
  {
    if (*path == '.')
      rd = rp;
    if (*path == '\\' || *path == '/')
      rd = 0;
  }
  *rp = 0;

  /* Perform an extension search when the flag SPAWN_INTERP_SEARCH is not
     present.  If LFN is supported on the volume where rpath resides, we
     might have something like foo.bar.exe or even foo.exe.com.
     If so, look for RPATH.ext before even trying RPATH itself.
     Otherwise, try to add an extension to a file without one.  */
  if (flags & SPAWN_FLAG_EXTENSION_SEARCH)
  {
    if (_use_lfn(path) || !rd)
    {
      i = find_extension(rpath, rp);
      /* When LFN is supported and an extension search fails, the go32_exec
         interpreter will be selected instead of none.  In this case,
         set the interpreter to none so the interpreter will be selected
         from the existing extension.  */
      if ((i != no_interp_found) && rd && *rp == 0)
        i = no_interp_found;
    }
  }

  /* If no interpreter has already been detected, find one based on the
     extension in rpath.  */
  if (i == no_interp_found)
    i = find_interpreter(rpath, rd ? rd : rp);

  /* The file does not exist. Return with errno set either by find_extension
     or find_interpreter to indicate the error.  */
  if (i == no_interp_found)
    return -1;

  /* If adding an extension makes the path longer than FILENAME_MAX,
     reject the path as too long.  */
  if (*rp && (rp - rpath + 1 + 3) > FILENAME_MAX - 1)
  {
    errno = ENAMETOOLONG;
    return -1;
  }

  errno = e;
  ret_code = interpreters[i].interp(rpath, argvp, envpp);
  if (mode == P_OVERLAY)
    exit(ret_code);
  return ret_code;
}

I notice the 'p' variants of spawn will find foo.sh given foo while spawnve 
wouldn't. It seems to me both should be consistent.


- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019