/* Nessuslib -- the Nessus Library
 * Copyright (C) 1998 Renaud Deraison
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Arglists management
 */

#define EXPORTING
#include <includes.h>


void * arg_get(arglst, name)
 struct arglist * arglst;
 char * name;
{
 char * toc;
 char **v;
 char * t;
 int id = 0;
 if(!arglst->toc)return(NULL);
 v = arglst->toc;
 toc = *v;
 t = strstr(toc, name);
 if(t)
 {
  char *v = strchr(t, ':');
  int i;
  if(v)id = atoi(v+1);
  for(i=1;i<id;i++)arglst = arglst->next;
  return(arglst->value);
 }
 return(NULL);
}
#define SLOW 1 
ExtFunc
void arg_add_value(arglst, name, type, length, value)
  struct arglist * arglst;
  const char * name;
  int type;
  long length;
  void * value;
{
	char ** toc_ptr;
	char * toc = NULL;
	char * new_toc;
	int id;
	if(!arglst)return;
#ifndef SLOW	
	toc_ptr = arglst->toc;
	if(!toc_ptr){
		toc_ptr = emalloc(sizeof(char*));
		arglst->toc = toc_ptr;
		}
	if(!*toc_ptr){
		toc = emalloc(1);
		*toc_ptr = toc;
		}	
	else toc = *toc_ptr;
#endif	
	/* Go to the end of our list... */
	while(arglst->next && arglst->next->next)arglst = arglst->next;
	id = arglst->id+1;
	if(arglst->next)arglst = arglst->next;
	
	if (type == ARG_STRUCT) {
    	 void* new_val = emalloc(length);
     	memcpy(new_val, value, length);
    	value = new_val;
   	}
#ifndef SLOW	
	new_toc = emalloc(strlen(toc)+strlen(name)+10);
	sprintf(new_toc, "%s;%s:%d",toc,name, id);
	free(toc);
	*toc_ptr = new_toc;
#endif	 
	arglst->name = estrdup(name);
	arglst->value = value;
#ifndef SLOW
	arglst->id    = id;
	arglst->toc   = toc_ptr;
#endif
	arglst->length = length;
	arglst->type = type;
	arglst->next = emalloc(sizeof(struct arglist));
	arglst->next->next = NULL;
}


ExtFunc int 
arg_set_value(arglst, name, length, value)
 struct arglist * arglst;
 const char * name;
 long length;
 void *value;
{
  /* We look for the asked name */
  while(arglst->next && strcmp(arglst->name, name))
    arglst = arglst->next;
  
  if(arglst->next)
    {
      if (arglst->type == ARG_STRUCT) {
	void* new_val = emalloc(length);
	if (arglst->value) efree(&arglst->value);
	memcpy(new_val, value, length);
	value = new_val;
      }
      arglst->value = value;
      arglst->length = length;
      return(0);
    }
  else return(-1); 
}

ExtFunc int 
arg_set_type(arglst, name, type)
 struct arglist * arglst;
 const char * name;
 int type;
{
  while(arglst->next && strcmp(name, arglst->name))arglst=arglst->next;
  if(!(arglst->next))return(-1);
  if (arglst->type == ARG_STRUCT  &&  type != ARG_STRUCT) {
    efree(&arglst->value);
  }
  arglst->type = type;
  return 0;
}
  
  
ExtFunc void * 
arg_get_value(args, name)
 struct arglist * args;
 const char * name;
{
 int flag=0;
 if(!args)return(NULL); 
#ifdef SLOW
  while(args && args->next && !flag)
  	{
        if(args->name && !strcmp(name, args->name))flag=1;
  	else args=args->next;
  	}
  if(flag && args && args->next)return(args->value);
  else return(NULL);
#else
  return(arg_get(args, name));
#endif
}


ExtFunc int 
arg_get_length(args,name)
 struct arglist * args;
 const char * name;
{
  while(args->next && strcmp(name, args->name))args=args->next;
  if(args->next)
    return(args->length);
  else return(0);
}


ExtFunc int 
arg_get_type(args,name)
 struct arglist * args;
 const char * name;
{
  while(args->next && strcmp(name, args->name))args=args->next;
  if(args->next)
    return(args->type);
  else return(-1);
}


ExtFunc void arg_dup(dst, src)
 struct arglist * dst;
 struct arglist * src;
{
 while(src && src->next)
 {
  dst->name = estrdup(src->name);
  dst->type = src->type;
  dst->length = src->length;
  switch(src->type)
  {
   case ARG_INT :
   case ARG_PTR : 
    dst->value = src->value;
    break;
    
   case ARG_STRING :
    if(src->value){
     dst->value = estrdup((char*)src->value);
    }
    break;
    
   case ARG_STRUCT :
     if (src->value) {
       dst->value = emalloc(src->length);
       memcpy(dst->value, src->value, src->length);
       dst->length = src->length;
     }
     break;

 
  case ARG_ARGLIST :
    dst->value = emalloc(sizeof(struct arglist));
    arg_dup((struct arglist *)dst->value, (struct arglist *)src->value);
    break;
  }
  dst->next = emalloc(sizeof(struct arglist));
  dst = dst->next;
  src = src->next;
 }
}


ExtFunc void 
arg_dump(args, level)
 struct arglist * args;
 int level;
{
	const char * spaces = "--------------------";
	if(!args)
	{
		printf("Error ! args == NULL\n");
		return;
	}
	
	while(args && args->next)
	{
		switch(args->type)
		{
			case ARG_STRING :
			
			fprintf(stderr, "%sargs->%s : %s\n",spaces+(20-level),
			args->name,
			(char *)args->value);
			break;
			case ARG_ARGLIST :
			
			fprintf(stderr, "%sargs->%s :\n", spaces+(20-level),
			args->name);
			arg_dump(args->value, level+1);
			break;
			case ARG_INT :
			fprintf(stderr, "%sargs->%s : %d\n",spaces+(20-level),
			args->name,
			(int)args->value);
			break;
			default :
			fprintf(stderr, "%sargs->%s : %d\n",spaces+(20-level),
			args->name,
			(int)args->value);
			break;
		}
		args = args->next;
	}
}


ExtFunc void
arg_free(arg)
 struct arglist* arg;
{
 while(arg)
 {
  struct arglist * next = arg->next;
  if (arg->name) efree (&(arg->name)) ;
  efree(&arg);
  arg = next;
 }
}


ExtFunc void arg_free_all(arg)
 struct arglist* arg;
{
 while(arg)
 {
  struct arglist * next = arg->next;
  switch(arg->type)
  {
   case ARG_ARGLIST :
    arg_free_all(arg->value);
    break;
   case ARG_STRING :
    efree(&arg->value);
    break;
   case ARG_STRUCT :
    efree(&arg->value);
    break;
  }
  if (arg->name) efree (&(arg->name)) ;
  efree(&arg);
  arg = next;
 }
}
