/*
  Copyright 1993 by Robert Withrow, Swampscott MA, 01907, USA.
  All rights reserved.

  Permission is granted to copy and use this file for any purpose
  as long as the above Copyright statment is retained in the file.
*/

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

#include "tmp/c.h"
#include "obj/fmgr.h"

static DynamicFunctionList *get_text_symbols(char *filename, char **err);

static char msg[255];		/* Holds error messages */

DynamicFunctionList *
dynamic_file_load(char **err, char *filename, char **address, long *size)
{
  /* 
    We use the dl library to attach shared objects
    We never do a dlclose so that reloads accumulate in the address
    space of the backend.  This is because there is no dynamic_file_reaload
    call and no space to leave the handle to the old loaded code.  This
    is a design flaw in the dynloading design of postgres.
  */
  void * dlhandle;
  DynamicFunctionList *list, *l;

  dlhandle = dlopen(filename,RTLD_LAZY);
  if (dlhandle == NULL) {
    sprintf(msg,"\"dlopen(%s,RTLD_LAZY)\" failed",filename);
    *err = msg;
    return(NULL);
  }

  /*
    The shared object has been attached to the address space of postgres,
    but we don't know what text symbols it contains...
  */

  list = get_text_symbols(filename,err);

  /*
    Now, fill in the address of the text symbols returned.
  */
  l = list;
  while(l) {
    l->func = (func_ptr)dlsym(dlhandle,l->funcname);
    l = l->next;
  }

  /*
    Since the dl stuff mmaps, this is bogus!  Why are these variables
    here anyway?
  */
  *address = NULL;
  *size = 0;
  return(list);
}

/*
  This is sorta hacky, but the elf_ routines have too much hair for
  me, and nlist() didn't work...

  Returns the list with the ->func field unfilled.
*/
#define BSIZE (255)

static DynamicFunctionList *get_text_symbols(char *filename, char **err)
{
  DynamicFunctionList *list = NULL;
  char command[BSIZE], line[BSIZE];
  FILE *p;

  sprintf(command,"nm -p %s | grep ' T '",filename);

  p = popen(command,"r");

  if (p == NULL) {
    sprintf(msg,"\"%s\" failed",command);
    *err = msg;
    return NULL;
  }

  while (fgets(line,BSIZE,p) != NULL) {
    DynamicFunctionList *item = malloc(sizeof(DynamicFunctionList));
    int garb1;
    char garb2[BSIZE], name[BSIZE];

    if (item) {
      sscanf(line,"%d %s %s",&garb1, garb2, name);
      if (name[0] == '_') {
	free(item);
      } else {
	strncpy(item->funcname,name,16);
	item->next = list;
	list = item;
      }
    }
  }

  (void) pclose(p);
  return(list);
}
