/*************************************************
*     Exim - an Internet mail transport agent    *
*************************************************/

/* Copyright (c) University of Cambridge 1995 - 1999 */
/* See the file NOTICE for conditions of use and distribution. */

#include "../exim.h"
#include "lsearch.h"


/* Compile these functions only if LOOKUP_DBM is defined. However, some
compilers don't like compiling empty modules, so keep them happy with a dummy
when skipping the rest. Make it reference itself to stop picky compilers
complaining that it is unused, and put in a dummy argument to stop even pickier
compilers complaining about infinite loops.

Also, some linkers are unhappy if an archive has no functions in it at all.
This could happen if no lookup types at all are selected. That is most
unlikely, but we might as well cater for it by making the dummy function here a
global function. There is no need to do it for any other lookup type; one is
enough. */

#ifndef LOOKUP_LSEARCH
void lsearch_dummy(int x) { lsearch_dummy(x-1); }
#else


/*************************************************
*              Open entry point                  *
*************************************************/

/* See local README for interface description */

void *
lsearch_open(char *filename, char **errmsg)
{
FILE *f = fopen(filename, "r");
if (f == NULL)
  {
  int save_errno = errno;
  *errmsg = string_open_failed(errno, "%s for linear search", filename);
  errno = save_errno;
  return NULL;
  }
return f;
}



/*************************************************
*             Check entry point                  *
*************************************************/

BOOL
lsearch_check(void *handle, char *filename, int modemask, int *owners,
  int *owngroups, char **errmsg)
{
return search_check_file(fileno((FILE *)handle), filename, modemask,
  owners, owngroups, "lsearch", errmsg) == 0;
}



/*************************************************
*              Find entry point                  *
*************************************************/

/* See local README for interface description */

int
lsearch_find(void *handle, char *filename, char *keystring, int length,
  char **result, char **errmsg)
{
FILE *f = (FILE *)handle;
char buffer[4096];

filename = filename;  /* Keep picky compilers happy */
errmsg = errmsg;

rewind(f);
while (fgets(buffer, sizeof(buffer), f) != NULL)
  {
  int ptr, size;
  int p = (int)strlen(buffer);
  char *yield;
  char *s = buffer;

  while (p > 0 && isspace(buffer[p-1])) p--;
  buffer[p] = 0;
  if (buffer[0] == 0 || buffer[0] == '#' || isspace(buffer[0])) continue;
  while (*s != 0 && *s != ':' && !isspace(*s)) s++;
  if (s-buffer != length || strncmpic(buffer, keystring, length) != 0)
    continue;

  while (isspace(*s)) s++;
  if (*s == ':')
    {
    s++;
    while (isspace(*s)) s++;
    }

  size = 100;
  ptr = 0;
  yield = store_get(size);
  if (*s != 0)
    yield = string_cat(yield, &size, &ptr, s, (int)strlen(s));

  while (fgets(buffer, sizeof(buffer), f) != NULL)
    {
    p = (int)strlen(buffer);
    while (p > 0 && isspace(buffer[p-1])) p--;
    buffer[p] = 0;
    if (buffer[0] == 0 || buffer[0] == '#') continue;
    if (!isspace(buffer[0])) break;
    s = buffer;
    while (isspace(*s)) s++;
    *(--s) = ' ';
    yield = string_cat(yield, &size, &ptr, s, (int)strlen(s));
    }

  yield[ptr] = 0;
  *result = yield;
  return OK;
  }

return FAIL;
}



/*************************************************
*              Close entry point                 *
*************************************************/

/* See local README for interface description */

void
lsearch_close(void *handle)
{
fclose((FILE *)handle);
}

#endif  /* LOOKUP_LSEARCH */

/* End of lookups/lsearch.c */
