/*************************************************************************
** ^FILE: arglist.c - argList manipulation routines.
**
** ^DESCRIPTION:
**    This file contains routines to add an item to the end of an arglist,
**    and to delete all items in an arglist.
**
** ^HISTORY:
**    01/02/91	Brad Appleton	<brad@ssd.csd.harris.com>
**       - Added structured comments
**       - Changed arglists to always be kept in FIFO order (hence
**         reverse_list() and cleanup_list() were no longer needed).
**         The lists are maintained in FIFO order by forcing the very
**         first item of the list to maintain an additional link to the
**         last item of the list (to make it easy to append an item).
**       - Added listFree() function
**
**    --/--/--	Peter da Silva	<peter@ferranti.com>	Created
***^^**********************************************************************/

#include <stdio.h>
#include <ctype.h>
#include <useful.h>
#include "strfuncs.h"

#define  PARSEARGS_NARGTYPES  /* exclude arg-type externs */
#include "parseargs.h"

EXTERN  VOID    syserr  ARGS((const char *, ...));
EXTERN  VOID    usrerr  ARGS((const char *, ...));

/***************************************************************************
** ^FUNCTION: listStr - string-list argument translation routine
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
   BOOL listStr( ad, vp, copyf )
/*  
** ^PARAMETERS:
*/
   ARGDESC *ad;
/*    -- the argument descriptor for this parameter.
*/
   char *vp;
/*    -- a pointer to the string input value.
*/
   BOOL copyf;
/*    -- if TRUE, the value will be destroyed later, and so should
**       be copied if it will be retained (as for a string).
*/
#endif  /* !__ANSI_C__ */

/* ^DESCRIPTION:
**    ListStr converts a string-parameter value into its internal form,
**    including validity checking. If <copyf> is TRUE then <vp> is copied
**    to the end of the list, otherwise <vp> itself is placed at the end.
**
** ^REQUIREMENTS:
**    <ad> must point to the argdesc element corresponding to the matched
**    string-list argument. The ad_valp field of ad MUST be either NULL or
**    point to a valid arglist-head structure.
**
** ^SIDE-EFECTS:
**    If successful, arglist pointed to by arg_valp(ad) is appended with
**    the given string, <vp> is unchanged.
**
** ^RETURN-VALUE:
**    TRUE -- if the conversion was successful.  The actual
**            value should be added appended to the list.
**    FALSE -- if the conversion failed.  The reason for failure
**             should be diagnosed using usrerr().
**
** ^ALGORITHM:
**    - verify the validity of <vp> as a string argument
**    - if ( isEmpty(arglist) )
**       - allocate a listhead structure
**       - assign the item pointer to <vp> (or a copy of <vp>)
**       - assign the NEXT and LAST elements to NULL
**    - else
**       - allocate a new arglist structure and append it after
**         listhead.LAST
**       - assign listhead.LAST to the address of the new item
**       - assign the NEXT element of the new item to NULL
**      end-if
***^^**********************************************************************/
#ifdef __ANSI_C__
   BOOL listStr( ARGDESC *ad, char *vp, BOOL copyf )
#endif
{
   char *cp;
   BOOL  badalloc = FALSE;
   argName_t   argname;
   ArgListHead *nl;
   ArgList *nd;

   (VOID) get_name( arg_sname(ad), argname );
   if (copyf) {
      register int i;

      i = strlen(vp) + 1;
      cp = (char *) malloc(i * sizeof(char));
      if(!cp) {
         usrerr("out of memory saving string %s", argname );
         return FALSE;
      }
      memcpy(cp, vp, i);
   }
   else {
      cp = vp;
   }

      /* if list is empty - need to new up a listhead,
      ** otherwise just use a normal link.
      */
   nl = *((ArgListHead **) arg_valp(ad));
   if ( nl ) {
      nd = (ArgList *) malloc( sizeof(ArgList) );
      if ( !nd )  badalloc = TRUE;
   }
   else {
      nl = (ArgListHead *) malloc( sizeof(ArgListHead) );
      nd = (ArgList *)NULL;
      if ( !nl )  badalloc = TRUE;
   }

   if ( badalloc ) {
      usrerr("out of memory saving arg %s", arg_sname(ad));
      if(copyf) free(cp);
      return FALSE;
   }

   if ( nd ) {
      nl -> nl_tail -> nl_next = (ArgList *)nd;
      nl -> nl_tail  = (ArgList *)nd;
      nd -> nl_next  = (ArgList *)NULL;
      nd -> nl_val   = (ARBPTR)cp;
      nd -> nl_flags = arg_flags(ad);
      if ( copyf )  BSET( nd->nl_flags, ARGCOPYF );
   }
   else {
      *((ArgListHead **) arg_valp(ad)) = nl;
      nl -> nl_tail  = (ArgList *)nl;
      nl -> nl_next  = (ArgList *)NULL;
      nl -> nl_val   = (ARBPTR)cp;
      nl -> nl_flags = arg_flags(ad);
      if ( copyf )  BSET( nl->nl_flags, ARGCOPYF );
   }

   return (TRUE);
}


/***************************************************************************
** ^FUNCTION: listFree - free the items in an arglist
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
   VOID listFree( argls )
/*  
** ^PARAMETERS:
*/
   ArgList *argls;
/*    -- the list to be freed
*/
#endif  /* !__ANSI_C__ */

/* ^DESCRIPTION:
**    ListFree will free storage for each node in <argls>. Furthermore,
**    if <copyf> is true then the actual storage for each item in the
**    list is also released.
**
** ^REQUIREMENTS:
**    argls must point to a valid arglist-head structure.
**
** ^SIDE-EFECTS:
**    each item in argls is removed, argls itself should be set to NULL
**    after this routine is invoked.
**
** ^RETURN-VALUE:
**    None.
**
** ^ALGORITHM:
**    - For each node in argls
**       - if ( copyf ) free the item storage
**       - free the node
**      end-for
***^^**********************************************************************/
#ifdef __ANSI_C__
   void listFree( ArgList *argls )
#endif
{
   register  ArgList *ls = argls;
   ArgList  *nd;

   if ( !ls )  return;

   while ( ls ) {
      nd = L_NEXT(ls);
      if ( BTEST(L_FLAGS(ls), ARGCOPYF) )  free( ls->nl_val );
      free( ls );
      ls = nd;
   }/*while*/
}

