Blame src/w32-ce.c

Packit d7e8d0
/* w32-ce.h
Packit d7e8d0
   Copyright (C) 2010 g10 Code GmbH
Packit d7e8d0
   Copyright (C) 1991,92,97,2000,02 Free Software Foundation, Inc.
Packit d7e8d0
Packit d7e8d0
   This file is part of GPGME.
Packit d7e8d0
Packit d7e8d0
   GPGME is free software; you can redistribute it and/or modify it
Packit d7e8d0
   under the terms of the GNU Lesser General Public License as
Packit d7e8d0
   published by the Free Software Foundation; either version 2.1 of
Packit d7e8d0
   the License, or (at your option) any later version.
Packit d7e8d0
Packit d7e8d0
   GPGME is distributed in the hope that it will be useful, but
Packit d7e8d0
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit d7e8d0
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit d7e8d0
   Lesser General Public License for more details.
Packit d7e8d0
Packit d7e8d0
   You should have received a copy of the GNU Lesser General Public
Packit d7e8d0
   License along with this program; if not, see <https://www.gnu.org/licenses/>.
Packit d7e8d0
 */
Packit d7e8d0
Packit d7e8d0
#ifdef HAVE_CONFIG_H
Packit d7e8d0
#include <config.h>
Packit d7e8d0
#endif
Packit d7e8d0
Packit d7e8d0
#include <string.h>
Packit d7e8d0
#include <errno.h>
Packit d7e8d0
#include <assert.h>
Packit d7e8d0
Packit d7e8d0
#include <gpg-error.h>
Packit d7e8d0
Packit d7e8d0
#define _WIN32_IE 0x0400 /* Required for SHGetSpecialFolderPathW.  */
Packit d7e8d0
Packit d7e8d0
/* We need to include the windows stuff here prior to shlobj.h so that
Packit d7e8d0
   we get the right winsock version.  This is usually done in w32-ce.h
Packit d7e8d0
   but that header also redefines some Windows functions which we need
Packit d7e8d0
   to avoid unless having included shlobj.h.  */
Packit d7e8d0
#include <winsock2.h>
Packit d7e8d0
#include <ws2tcpip.h>
Packit d7e8d0
#include <windows.h>
Packit d7e8d0
#include <shlobj.h>
Packit d7e8d0
Packit d7e8d0
#include "w32-ce.h"
Packit d7e8d0
Packit d7e8d0
/* Return a malloced string encoded in UTF-8 from the wide char input
Packit d7e8d0
   string STRING.  Caller must free this value.  Returns NULL and sets
Packit d7e8d0
   ERRNO on failure.  Calling this function with STRING set to NULL is
Packit d7e8d0
   not defined.  */
Packit d7e8d0
char *
Packit d7e8d0
wchar_to_utf8 (const wchar_t *string)
Packit d7e8d0
{
Packit d7e8d0
  int n;
Packit d7e8d0
  char *result;
Packit d7e8d0
Packit d7e8d0
  n = WideCharToMultiByte (CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
Packit d7e8d0
  if (n < 0)
Packit d7e8d0
    {
Packit d7e8d0
      gpg_err_set_errno (EINVAL);
Packit d7e8d0
      return NULL;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  result = malloc (n+1);
Packit d7e8d0
  if (!result)
Packit d7e8d0
    return NULL;
Packit d7e8d0
Packit d7e8d0
  n = WideCharToMultiByte (CP_UTF8, 0, string, -1, result, n, NULL, NULL);
Packit d7e8d0
  if (n < 0)
Packit d7e8d0
    {
Packit d7e8d0
      free (result);
Packit d7e8d0
      gpg_err_set_errno (EINVAL);
Packit d7e8d0
      result = NULL;
Packit d7e8d0
    }
Packit d7e8d0
  return result;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Return a malloced wide char string from an UTF-8 encoded input
Packit d7e8d0
   string STRING.  Caller must free this value.  Returns NULL and sets
Packit d7e8d0
   ERRNO on failure.  Calling this function with STRING set to NULL is
Packit d7e8d0
   not defined.  */
Packit d7e8d0
wchar_t *
Packit d7e8d0
utf8_to_wchar (const char *string)
Packit d7e8d0
{
Packit d7e8d0
  int n;
Packit d7e8d0
  size_t nbytes;
Packit d7e8d0
  wchar_t *result;
Packit d7e8d0
Packit d7e8d0
  n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
Packit d7e8d0
  if (n < 0)
Packit d7e8d0
    {
Packit d7e8d0
      gpg_err_set_errno (EINVAL);
Packit d7e8d0
      return NULL;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  nbytes = (size_t)(n+1) * sizeof(*result);
Packit d7e8d0
  if (nbytes / sizeof(*result) != (n+1))
Packit d7e8d0
    {
Packit d7e8d0
      gpg_err_set_errno (ENOMEM);
Packit d7e8d0
      return NULL;
Packit d7e8d0
    }
Packit d7e8d0
  result = malloc (nbytes);
Packit d7e8d0
  if (!result)
Packit d7e8d0
    return NULL;
Packit d7e8d0
Packit d7e8d0
  n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
Packit d7e8d0
  if (n < 0)
Packit d7e8d0
    {
Packit d7e8d0
      free (result);
Packit d7e8d0
      gpg_err_set_errno (EINVAL);
Packit d7e8d0
      result = NULL;
Packit d7e8d0
    }
Packit d7e8d0
  return result;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
#define MAX_ENV 30
Packit d7e8d0
Packit d7e8d0
char *environ[MAX_ENV + 1];
Packit d7e8d0
Packit d7e8d0
char *
Packit d7e8d0
getenv (const char *name)
Packit d7e8d0
{
Packit d7e8d0
  static char *past_result;
Packit d7e8d0
  char **envp;
Packit d7e8d0
Packit d7e8d0
  if (past_result)
Packit d7e8d0
    {
Packit d7e8d0
      free (past_result);
Packit d7e8d0
      past_result = NULL;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
#if 0
Packit d7e8d0
  if (! strcmp (name, "DBUS_VERBOSE"))
Packit d7e8d0
    return past_result = get_verbose_setting ();
Packit d7e8d0
  else if (! strcmp (name, "HOMEPATH"))
Packit d7e8d0
    return past_result = find_my_documents_folder ();
Packit d7e8d0
  else if (! strcmp (name, "DBUS_DATADIR"))
Packit d7e8d0
    return past_result = find_inst_subdir ("share");
Packit d7e8d0
#endif
Packit d7e8d0
Packit d7e8d0
  for (envp = environ; *envp != 0; envp++)
Packit d7e8d0
    {
Packit d7e8d0
      const char *varp = name;
Packit d7e8d0
      char *ep = *envp;
Packit d7e8d0
Packit d7e8d0
      while (*varp == *ep && *varp != '\0')
Packit d7e8d0
	{
Packit d7e8d0
	  ++ep;
Packit d7e8d0
	  ++varp;
Packit d7e8d0
	};
Packit d7e8d0
Packit d7e8d0
      if (*varp == '\0' && *ep == '=')
Packit d7e8d0
	return ep + 1;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  return NULL;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
void
Packit d7e8d0
GetSystemTimeAsFileTime (LPFILETIME ftp)
Packit d7e8d0
{
Packit d7e8d0
  SYSTEMTIME st;
Packit d7e8d0
  GetSystemTime (&st);
Packit d7e8d0
  SystemTimeToFileTime (&st, ftp);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
BOOL
Packit d7e8d0
DeleteFileA (LPCSTR lpFileName)
Packit d7e8d0
{
Packit d7e8d0
  wchar_t *filename;
Packit d7e8d0
  BOOL result;
Packit d7e8d0
  int err;
Packit d7e8d0
Packit d7e8d0
  filename = utf8_to_wchar (lpFileName);
Packit d7e8d0
  if (!filename)
Packit d7e8d0
    return FALSE;
Packit d7e8d0
Packit d7e8d0
  result = DeleteFileW (filename);
Packit d7e8d0
Packit d7e8d0
  err = GetLastError ();
Packit d7e8d0
  free (filename);
Packit d7e8d0
  SetLastError (err);
Packit d7e8d0
  return result;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
HANDLE
Packit d7e8d0
CreateFileA (LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwSharedMode,
Packit d7e8d0
	     LPSECURITY_ATTRIBUTES lpSecurityAttributes,
Packit d7e8d0
	     DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
Packit d7e8d0
	     HANDLE hTemplateFile)
Packit d7e8d0
{
Packit d7e8d0
  wchar_t *filename;
Packit d7e8d0
  HANDLE result;
Packit d7e8d0
  int err;
Packit d7e8d0
Packit d7e8d0
  filename = utf8_to_wchar (lpFileName);
Packit d7e8d0
  if (!filename)
Packit d7e8d0
    return INVALID_HANDLE_VALUE;
Packit d7e8d0
Packit d7e8d0
  result = CreateFileW (filename, dwDesiredAccess, dwSharedMode,
Packit d7e8d0
			lpSecurityAttributes, dwCreationDisposition,
Packit d7e8d0
			dwFlagsAndAttributes, hTemplateFile);
Packit d7e8d0
Packit d7e8d0
  err = GetLastError ();
Packit d7e8d0
  free (filename);
Packit d7e8d0
  SetLastError (err);
Packit d7e8d0
  return result;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
BOOL
Packit d7e8d0
CreateProcessA (LPCSTR pszImageName, LPSTR pszCmdLine,
Packit d7e8d0
                LPSECURITY_ATTRIBUTES psaProcess,
Packit d7e8d0
                LPSECURITY_ATTRIBUTES psaThread, BOOL fInheritHandles,
Packit d7e8d0
                DWORD fdwCreate, PVOID pvEnvironment, LPCSTR pszCurDir,
Packit d7e8d0
                LPSTARTUPINFOA psiStartInfo,
Packit d7e8d0
                LPPROCESS_INFORMATION pProcInfo)
Packit d7e8d0
{
Packit d7e8d0
  wchar_t *image_name = NULL;
Packit d7e8d0
  wchar_t *cmd_line = NULL;
Packit d7e8d0
  BOOL result;
Packit d7e8d0
  int err;
Packit d7e8d0
Packit d7e8d0
  assert (psaProcess == NULL);
Packit d7e8d0
  assert (psaThread == NULL);
Packit d7e8d0
  assert (fInheritHandles == FALSE);
Packit d7e8d0
  assert (pvEnvironment == NULL);
Packit d7e8d0
  assert (pszCurDir == NULL);
Packit d7e8d0
  /* psiStartInfo is generally not NULL.  */
Packit d7e8d0
Packit d7e8d0
  if (pszImageName)
Packit d7e8d0
    {
Packit d7e8d0
      image_name = utf8_to_wchar (pszImageName);
Packit d7e8d0
      if (!image_name)
Packit d7e8d0
	return 0;
Packit d7e8d0
    }
Packit d7e8d0
  if (pszCmdLine)
Packit d7e8d0
    {
Packit d7e8d0
      cmd_line = utf8_to_wchar (pszCmdLine);
Packit d7e8d0
      if (!cmd_line)
Packit d7e8d0
        {
Packit d7e8d0
          if (image_name)
Packit d7e8d0
            free (image_name);
Packit d7e8d0
          return 0;
Packit d7e8d0
        }
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  result = CreateProcessW (image_name, cmd_line, NULL, NULL, FALSE,
Packit d7e8d0
                           fdwCreate, NULL, NULL, NULL, pProcInfo);
Packit d7e8d0
Packit d7e8d0
  err = GetLastError ();
Packit d7e8d0
  free (image_name);
Packit d7e8d0
  free (cmd_line);
Packit d7e8d0
  SetLastError (err);
Packit d7e8d0
  return result;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
LONG
Packit d7e8d0
RegOpenKeyExA (HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions,
Packit d7e8d0
               REGSAM samDesired, PHKEY phkResult)
Packit d7e8d0
{
Packit d7e8d0
  wchar_t *subkey;
Packit d7e8d0
  LONG result;
Packit d7e8d0
  int err;
Packit d7e8d0
Packit d7e8d0
  if (lpSubKey)
Packit d7e8d0
    {
Packit d7e8d0
      subkey = utf8_to_wchar (lpSubKey);
Packit d7e8d0
      if (!subkey)
Packit d7e8d0
	return 0;
Packit d7e8d0
    }
Packit d7e8d0
  else
Packit d7e8d0
    subkey = NULL;
Packit d7e8d0
Packit d7e8d0
  result = RegOpenKeyEx (hKey, subkey, ulOptions, samDesired, phkResult);
Packit d7e8d0
Packit d7e8d0
  err = GetLastError ();
Packit d7e8d0
  free (subkey);
Packit d7e8d0
  SetLastError (err);
Packit d7e8d0
  return result;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
LONG WINAPI
Packit d7e8d0
RegQueryValueExA (HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved,
Packit d7e8d0
                  LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
Packit d7e8d0
{
Packit d7e8d0
  wchar_t *name;
Packit d7e8d0
  LONG err;
Packit d7e8d0
  void *data;
Packit d7e8d0
  DWORD data_len;
Packit d7e8d0
  DWORD type;
Packit d7e8d0
Packit d7e8d0
  if (lpValueName)
Packit d7e8d0
    {
Packit d7e8d0
      name = utf8_to_wchar (lpValueName);
Packit d7e8d0
      if (!name)
Packit d7e8d0
	return GetLastError ();
Packit d7e8d0
    }
Packit d7e8d0
  else
Packit d7e8d0
    name = NULL;
Packit d7e8d0
Packit d7e8d0
  data_len = 0;
Packit d7e8d0
  err = RegQueryValueExW (hKey, name, lpReserved, lpType, NULL, &data_len);
Packit d7e8d0
  if (err || !lpcbData)
Packit d7e8d0
    {
Packit d7e8d0
      free (name);
Packit d7e8d0
      return err;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  data = malloc (data_len + sizeof (wchar_t));
Packit d7e8d0
  if (!data)
Packit d7e8d0
    {
Packit d7e8d0
      free (name);
Packit d7e8d0
      return ERROR_NOT_ENOUGH_MEMORY;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  err = RegQueryValueExW (hKey, name, lpReserved, &type, data, &data_len);
Packit d7e8d0
  if (lpType)
Packit d7e8d0
    *lpType = type;
Packit d7e8d0
  free (name);
Packit d7e8d0
  /* If err is ERROR_MORE_DATA, there probably was a race condition.
Packit d7e8d0
     We can punt this to the caller just as well.  */
Packit d7e8d0
  if (err)
Packit d7e8d0
    return err;
Packit d7e8d0
Packit d7e8d0
  /* NOTE: REG_MULTI_SZ and REG_EXPAND_SZ not supported, because they
Packit d7e8d0
     are not needed in this module.  */
Packit d7e8d0
  if (type == REG_SZ)
Packit d7e8d0
    {
Packit d7e8d0
      char *data_c;
Packit d7e8d0
      int data_c_len;
Packit d7e8d0
Packit d7e8d0
      /* This is valid since we allocated one more above.  */
Packit d7e8d0
      ((char*)data)[data_len] = '\0';
Packit d7e8d0
      ((char*)data)[data_len + 1] = '\0';
Packit d7e8d0
Packit d7e8d0
      data_c = wchar_to_utf8 ((wchar_t*) data);
Packit d7e8d0
      if (!data_c)
Packit d7e8d0
        return GetLastError();
Packit d7e8d0
Packit d7e8d0
      data_c_len = strlen (data_c) + 1;
Packit d7e8d0
      assert (data_c_len <= data_len + sizeof (wchar_t));
Packit d7e8d0
      memcpy (data, data_c, data_c_len);
Packit d7e8d0
      data_len = data_c_len;
Packit d7e8d0
      free (data_c);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  /* DATA and DATA_LEN now contain the result.  */
Packit d7e8d0
  if (lpData)
Packit d7e8d0
    {
Packit d7e8d0
      if (data_len > *lpcbData)
Packit d7e8d0
        err = ERROR_MORE_DATA;
Packit d7e8d0
      else
Packit d7e8d0
        memcpy (lpData, data, data_len);
Packit d7e8d0
    }
Packit d7e8d0
  *lpcbData = data_len;
Packit d7e8d0
  return err;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
DWORD
Packit d7e8d0
GetTempPathA (DWORD nBufferLength, LPSTR lpBuffer)
Packit d7e8d0
{
Packit d7e8d0
  wchar_t dummy[1];
Packit d7e8d0
  DWORD len;
Packit d7e8d0
Packit d7e8d0
  len = GetTempPathW (0, dummy);
Packit d7e8d0
  if (len == 0)
Packit d7e8d0
    return 0;
Packit d7e8d0
Packit d7e8d0
  assert (len <= MAX_PATH);
Packit d7e8d0
Packit d7e8d0
  /* Better be safe than sorry.  MSDN doesn't say if len is with or
Packit d7e8d0
     without terminating 0.  */
Packit d7e8d0
  len++;
Packit d7e8d0
Packit d7e8d0
  {
Packit d7e8d0
    wchar_t *buffer_w;
Packit d7e8d0
    DWORD len_w;
Packit d7e8d0
    char *buffer_c;
Packit d7e8d0
    DWORD len_c;
Packit d7e8d0
Packit d7e8d0
    buffer_w = malloc (sizeof (wchar_t) * len);
Packit d7e8d0
    if (! buffer_w)
Packit d7e8d0
      return 0;
Packit d7e8d0
Packit d7e8d0
    len_w = GetTempPathW (len, buffer_w);
Packit d7e8d0
    /* Give up if we still can't get at it.  */
Packit d7e8d0
    if (len_w == 0 || len_w >= len)
Packit d7e8d0
      {
Packit d7e8d0
        free (buffer_w);
Packit d7e8d0
        return 0;
Packit d7e8d0
      }
Packit d7e8d0
Packit d7e8d0
    /* Better be really safe.  */
Packit d7e8d0
    buffer_w[len_w] = '\0';
Packit d7e8d0
Packit d7e8d0
    buffer_c = wchar_to_utf8 (buffer_w);
Packit d7e8d0
    free (buffer_w);
Packit d7e8d0
    if (! buffer_c)
Packit d7e8d0
      return 0;
Packit d7e8d0
Packit d7e8d0
    /* strlen is correct (not _mbstrlen), because we want storage and
Packit d7e8d0
       not string length.  */
Packit d7e8d0
    len_c = strlen (buffer_c) + 1;
Packit d7e8d0
    if (len_c > nBufferLength)
Packit d7e8d0
      return len_c;
Packit d7e8d0
Packit d7e8d0
    strcpy (lpBuffer, buffer_c);
Packit d7e8d0
    free (buffer_c);
Packit d7e8d0
    return len_c - 1;
Packit d7e8d0
  }
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* The symbol is named SHGetSpecialFolderPath and not
Packit d7e8d0
   SHGetSpecialFolderPathW but shlobj.h from cegcc redefines it to *W
Packit d7e8d0
   which is a bug.  Work around it.  */
Packit d7e8d0
#ifdef __MINGW32CE__
Packit d7e8d0
# undef SHGetSpecialFolderPath
Packit d7e8d0
#endif
Packit d7e8d0
BOOL
Packit d7e8d0
SHGetSpecialFolderPathA (HWND hwndOwner, LPSTR lpszPath, int nFolder,
Packit d7e8d0
                         BOOL fCreate)
Packit d7e8d0
{
Packit d7e8d0
  wchar_t path[MAX_PATH];
Packit d7e8d0
  char *path_c;
Packit d7e8d0
  BOOL result;
Packit d7e8d0
Packit d7e8d0
  path[0] = (wchar_t) 0;
Packit d7e8d0
  result = SHGetSpecialFolderPath (hwndOwner, path, nFolder, fCreate);
Packit d7e8d0
  /* Note: May return false even if succeeds.  */
Packit d7e8d0
Packit d7e8d0
  path[MAX_PATH - 1] = (wchar_t) 0;
Packit d7e8d0
  path_c = wchar_to_utf8 (path);
Packit d7e8d0
  if (! path_c)
Packit d7e8d0
    return 0;
Packit d7e8d0
Packit d7e8d0
  strncpy (lpszPath, path_c, MAX_PATH);
Packit d7e8d0
  free (path_c);
Packit d7e8d0
  lpszPath[MAX_PATH - 1] = '\0';
Packit d7e8d0
  return result;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
/* Replacement for the access function.  Note that we can't use fopen
Packit d7e8d0
   here because wince might now allow to have a shared read for an
Packit d7e8d0
   executable; it is better to to read the file attributes.
Packit d7e8d0
Packit d7e8d0
   Limitation:  Only F_OK is supported.
Packit d7e8d0
*/
Packit d7e8d0
int
Packit d7e8d0
_gpgme_wince_access (const char *fname, int mode)
Packit d7e8d0
{
Packit d7e8d0
  DWORD attr;
Packit d7e8d0
  wchar_t *wfname;
Packit d7e8d0
Packit d7e8d0
  (void)mode;
Packit d7e8d0
Packit d7e8d0
  wfname = utf8_to_wchar (fname);
Packit d7e8d0
  if (!wfname)
Packit d7e8d0
    return -1;
Packit d7e8d0
Packit d7e8d0
  attr = GetFileAttributes (wfname);
Packit d7e8d0
  free (wfname);
Packit d7e8d0
  if (attr == (DWORD)(-1))
Packit d7e8d0
    {
Packit d7e8d0
      gpg_err_set_errno (ENOENT);
Packit d7e8d0
      return -1;
Packit d7e8d0
    }
Packit d7e8d0
  return 0;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Perform a binary search for KEY in BASE which has NMEMB elements
Packit d7e8d0
   of SIZE bytes each.  The comparisons are done by (*COMPAR)().
Packit d7e8d0
   Code taken from glibc-2.6. */
Packit d7e8d0
void *
Packit d7e8d0
_gpgme_wince_bsearch (const void *key, const void *base,
Packit d7e8d0
                      size_t nmemb, size_t size,
Packit d7e8d0
                      int (*compar) (const void *, const void *))
Packit d7e8d0
{
Packit d7e8d0
  size_t l, u, idx;
Packit d7e8d0
  const void *p;
Packit d7e8d0
  int comparison;
Packit d7e8d0
Packit d7e8d0
  l = 0;
Packit d7e8d0
  u = nmemb;
Packit d7e8d0
  while (l < u)
Packit d7e8d0
    {
Packit d7e8d0
      idx = (l + u) / 2;
Packit d7e8d0
      p = (void *) (((const char *) base) + (idx * size));
Packit d7e8d0
      comparison = (*compar) (key, p);
Packit d7e8d0
      if (comparison < 0)
Packit d7e8d0
	u = idx;
Packit d7e8d0
      else if (comparison > 0)
Packit d7e8d0
	l = idx + 1;
Packit d7e8d0
      else
Packit d7e8d0
	return (void *) p;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  return NULL;
Packit d7e8d0
}
Packit d7e8d0