/*
		                  LCRZO
                             Network library
             Copyright(c) 1999,2000,2001,2002 Laurent Constantin
                                  -----

  Main server    : http://www.laurentconstantin.com/
  Backup servers : http://go.to/laurentconstantin/
                   http://laurentconstantin.est-la.com/
                   http://laurentconstantin.free.fr/
                   http://lauconstantin.multimania.com/
  [my current email address is on the web servers]

                                  -----
  This file is part of Lcrzo.

  Lcrzo is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  Lcrzo 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
  Lesser General Public License for more details (http://www.gnu.org).

------------------------------------------------------------------------
*/

/* -- Note about comments and variable names --
   In versions 1.00 up to 2.08, lcrzo was only written in French (my
   mother tongue). Since version 3.00, lcrzo is written in English, but
   most of comments and variable names are still in French.
   In future versions, I'll try to translate everything into English,
   but as you may guess, that's a quite big work...
   So, for the moment, here are some word translation, if you want to
   be able to understand what's going on in the functions :
     afficher - print     ;  ajouter - add         ;  copie - copy
     dernier - last       ;  donnee - data         ;  ecrire - write
     entete - header      ;  envoye - sent         ;  ferme - close
     fichier - file       ;  lire - read           ;  masque - mask 
     nboct - byte number  ;  ouvre, ouvrir - open  ;  paq, paquet - packet
     plage - range        ;  premier - first       ;  recu - received
     reseau - network     ;  retour - return       ;  taille - size
     tunnel - pipe

*/

#include "lcrzo_incl.h"

/*-------------------------------------------------------------*/
int lcrzo_priv_list_goto_listelem(lcrzo_list *plist,
				  int direction, 
				  lcrzo_int32 distance,
				  lcrzo_bool stoponebefore,
				  lcrzo_listelem **pplistelem);
int lcrzo_priv_list_goto_listelem(lcrzo_list *plist,
				  int direction, 
				  lcrzo_int32 distance,
				  lcrzo_bool stoponebefore,
				  lcrzo_listelem **pplistelem)
{ int i;

  lcrzo_bool_verifbof(stoponebefore);
  if (stoponebefore) i=1;
  else i=0;
  *pplistelem=(lcrzo_listelem *)plist;

  /*si on parcourt la liste en croissant*/
  if (direction==LCRZO_PRIV_INCREASE)
  { /*on va jusqu'a l'element nous interessant*/
    while (i<distance)
    { *pplistelem=(lcrzo_listelem *)(*pplistelem)->pnext;
      i++;
    }
  }
  else
  { /*on va jusqu'a l'element nous interessant*/
    while (i<distance)
    { *pplistelem=(lcrzo_listelem *)(*pplistelem)->pprecedent;
      i++;
    }
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_list_remove_listelem(lcrzo_list *plist,
				    lcrzo_listelem *plistelem);
int lcrzo_priv_list_remove_listelem(lcrzo_list *plist,
				    lcrzo_listelem *plistelem)
{ lcrzo_listelem *pnext, *pprevious;

  /*unlink the element*/
  pnext = (lcrzo_listelem *)plistelem->pnext;
  pprevious = (lcrzo_listelem *)plistelem->pprecedent;
  pnext->pprecedent = (lcrzo_listelem *)pprevious;
  pprevious->pnext = (lcrzo_listelem *)pnext;

  /*free the memory*/
  if ( plist->pfunc_erase != NULL ) /*dispose d'une procedure*/
    (*plist->pfunc_erase)(plistelem->pelem);
  free(plistelem->pelem);
  free(plistelem);
  plist->elemcount --;

  return(LCRZO_ERR_OK);
}
/*-------------------------------------------------------------*/
/*-------------------------------------------------------------*/
/*-------------------------------------------------------------*/


/*-------------------------------------------------------------*/
int lcrzo_list_init(lcrzo_list *plist, lcrzo_uint32 sizeofelems,
		    int (*pfonceffaceelem)(void *pelem))
{
  /*parameters verification*/
  if (plist==NULL) return(LCRZO_ERR_PANULLPTR);

  plist->pnext=(lcrzo_listelem *)plist;
  plist->pprecedent=(lcrzo_listelem *)plist;
  plist->sizeofelems=sizeofelems;
  plist->elemcount=0;
  plist->pfunc_erase=pfonceffaceelem;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_list_close(lcrzo_list *plist)
{ return(lcrzo_list_remove_all(plist));
}

/*-------------------------------------------------------------*/
int lcrzo_list_add_pos(lcrzo_list *plist, lcrzo_int32 position,
		       const void *pelem)
{ lcrzo_int32 distance;
  int sens;
  lcrzo_listelem *plisteelem, *ptravail1, *ptravail2;
    
  /*parameters verification*/
  if (plist==NULL) return(LCRZO_ERR_PANULLPTR);
  if (pelem==NULL) return(LCRZO_ERR_PANULLPTR);
  /*liste pleine*/
  if (plist->elemcount >= 0x7FFFFFFF) return(LCRZO_ERR_SPLISTFULL);

  /*verification des parametres et affectation des positions*/
  lcrzo_er(lcrzo_priv_manageelempos(plist->elemcount, position, 1,
				     NULL, NULL, &sens, &distance));

  /*allocation de la memoire de mon element*/
  plisteelem=malloc(sizeof(lcrzo_listelem));
  if (plisteelem==NULL) return(LCRZO_ERR_FUMALLOC);
  plisteelem->pelem=malloc(plist->sizeofelems);
  if (plisteelem->pelem==NULL) return(LCRZO_ERR_FUMALLOC);
  memcpy(plisteelem->pelem, pelem, plist->sizeofelems);

  /*we go to the first element (stop one before)*/
  lcrzo_er(lcrzo_priv_list_goto_listelem(plist, sens, distance, 1,
					 &ptravail1));

  /*si on parcourt la liste en croissant*/
  if (sens==LCRZO_PRIV_INCREASE)
  { /*on insere notre element*/
    plisteelem->pnext = ptravail1->pnext;
    plisteelem->pprecedent = (lcrzo_listelem *)ptravail1;
    ptravail2 = (lcrzo_listelem *)ptravail1->pnext;
    ptravail2->pprecedent = (lcrzo_listelem *)plisteelem;
    ptravail1->pnext = (lcrzo_listelem *)plisteelem;
  }
  else
  { /*on insere notre element*/
    plisteelem->pprecedent = ptravail1->pprecedent;
    plisteelem->pnext = (lcrzo_listelem *)ptravail1;
    ptravail2 = (lcrzo_listelem *)ptravail1->pprecedent;
    ptravail2->pnext = (lcrzo_listelem *)plisteelem;
    ptravail1->pprecedent = (lcrzo_listelem *)plisteelem;
  }
  /*on a ajoute un element*/
  plist->elemcount ++;

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_list_add_first(lcrzo_list *plist, const void *pelem)
{ return(lcrzo_list_add_pos(plist, +1, pelem));
}

/*-------------------------------------------------------------*/
int lcrzo_list_add_last(lcrzo_list *plist, const void *pelem)
{ return(lcrzo_list_add_pos(plist, -1, pelem));
}


/*-------------------------------------------------------------*/
int lcrzo_list_remove_pos(lcrzo_list *plist, lcrzo_int32 position)
{ lcrzo_int32 distance;
  int sens;
  lcrzo_listelem *ptravail;

  /*parameters verification*/
  if (plist==NULL) return(LCRZO_ERR_PANULLPTR);
  /*verification des parametres et affectation des positions*/
  lcrzo_er(lcrzo_priv_manageelempos(plist->elemcount, position, 0,
				     NULL, NULL, &sens, &distance));

  /*we go to the element*/
  lcrzo_er(lcrzo_priv_list_goto_listelem(plist, sens, distance, 0, 
					 &ptravail));

  /*on efface l'element*/
  lcrzo_er(lcrzo_priv_list_remove_listelem(plist, ptravail));

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_list_remove_first(lcrzo_list *plist)
{ return(lcrzo_list_remove_pos(plist, +1));
}

/*-------------------------------------------------------------*/
int lcrzo_list_remove_last(lcrzo_list *plist)
{ return(lcrzo_list_remove_pos(plist, -1));
}

/*-------------------------------------------------------------*/
int lcrzo_list_remove_range(lcrzo_list *plist, 
			    lcrzo_int32 posdebut, lcrzo_int32 posfin)
{ lcrzo_int32 infdistance, supdistance, i;
  int infdirection, supdirection;
  lcrzo_listelem *ptravail;

  /*parameters verification*/
  if (plist==NULL) return(LCRZO_ERR_PANULLPTR);
  /*verification des parametres et affectation des positions*/
  if ( plist->elemcount==0 && posdebut==+1 && posfin==-1 )
    return(LCRZO_ERR_OK);
  lcrzo_er(lcrzo_priv_manageelemrangefast(plist->elemcount, posdebut, posfin,
					  NULL, NULL, NULL, NULL,
					  &infdirection, &infdistance,
					  &supdirection, &supdistance));

  /*we go to the first element*/
  lcrzo_er(lcrzo_priv_list_goto_listelem(plist, infdirection, infdistance, 0,
					 &ptravail));

  /*remove the range*/
  i=0;
  if (supdirection==LCRZO_PRIV_INCREASE)
  { ptravail = (lcrzo_listelem *)ptravail->pprecedent;
    while (i<=supdistance)
    { lcrzo_er(lcrzo_priv_list_remove_listelem(plist, ptravail->pnext));
      i++;
    }
  }
  else
  { ptravail = (lcrzo_listelem *)ptravail->pnext;
    while (i<=supdistance)
    { lcrzo_er(lcrzo_priv_list_remove_listelem(plist, ptravail->pprecedent));
      i++;
    }
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_list_remove_all(lcrzo_list *plist)
{ lcrzo_er(lcrzo_list_remove_range(plist, 1, -1));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_list_remove_duplicate_range(lcrzo_list *plist,
				      lcrzo_int32 posdebut,
				      lcrzo_int32 posfin,
				      lcrzo_int8 (*pfonccmpelem)(const void *peleminf,
							  const void *pelemsup,
							  void *pinfos),
				      void *pinfos)
{ lcrzo_int32 infdistance, supdistance, i, j, numremoved;
  int infdirection, supdirection;
  lcrzo_listelem *ptravail, *ptravail2;

  /*parameters verification*/
  if (plist==NULL) return(LCRZO_ERR_PANULLPTR);
  if (pfonccmpelem==NULL) return(LCRZO_ERR_PANULLPTR);
  /*verification des parametres et affectation des positions*/
  if ( plist->elemcount==0 && posdebut==+1 && posfin==-1 )
    return(LCRZO_ERR_OK);
  lcrzo_er(lcrzo_priv_manageelemrangefast(plist->elemcount, posdebut, posfin,
					  NULL, NULL, NULL, NULL,
					  &infdirection, &infdistance,
					  &supdirection, &supdistance));

  /*we go to the first element*/
  lcrzo_er(lcrzo_priv_list_goto_listelem(plist, infdirection, infdistance, 0,
					 &ptravail));

  /*remove the elements in the range*/
  numremoved=0;
  if (supdirection==LCRZO_PRIV_INCREASE)
  { ptravail = (lcrzo_listelem *)ptravail->pprecedent;
    for ( i=0 ; i<=supdistance-numremoved ; i++ )
    { ptravail = (lcrzo_listelem *)ptravail->pnext;
      ptravail2 = (lcrzo_listelem *)ptravail;
      for ( j=i+1 ; j<=supdistance-numremoved ; j++ )
      { if ( !(*pfonccmpelem)(ptravail->pelem, ptravail2->pnext->pelem,
			      pinfos) )
        { lcrzo_er(lcrzo_priv_list_remove_listelem(plist, ptravail2->pnext));
	  numremoved++;
	}
	else
	{ ptravail2 = (lcrzo_listelem *)ptravail2->pnext;
        }
      }
    }
  }
  else
  { ptravail = (lcrzo_listelem *)ptravail->pnext;
    for ( i=0 ; i<=supdistance-numremoved ; i++ )
    { ptravail = (lcrzo_listelem *)ptravail->pprecedent;
      ptravail2 = (lcrzo_listelem *)ptravail;
      for ( j=i+1 ; j<=supdistance-numremoved ; j++ )
      { /*for debug printf("%ld, %ld : %d %d\n", i, j,
	       *(int*)(ptravail->pelem),
	       *(int*)(ptravail2->pprecedent->pelem)
	       );*/
	if ( !(*pfonccmpelem)(ptravail->pelem, ptravail2->pprecedent->pelem,
			      pinfos) )
        { lcrzo_er(lcrzo_priv_list_remove_listelem(plist,
						   ptravail2->pprecedent));
	  numremoved++;
	}
	else
	{ ptravail2 = (lcrzo_listelem *)ptravail2->pprecedent;
        }	
      }
    }
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_list_remove_duplicate_all(lcrzo_list *plist,
				    lcrzo_int8 (*pfonccmpelem)(const void *peleminf,
							const void *pelemsup,
							void *pinfos),
				    void *pinfos)
{ lcrzo_er(lcrzo_list_remove_duplicate_range(plist, 1, -1,
					     pfonccmpelem, pinfos));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_list_remove_criteria_range(lcrzo_list *plist,
				     lcrzo_int32 posdebut,
				     lcrzo_int32 posfin,
				     lcrzo_bool (*pfonccritere)(const void *pelem,
							 void *pinfos),
				     void *pinfos)
{ lcrzo_int32 infdistance, supdistance, i;
  int infdirection, supdirection;
  lcrzo_listelem *ptravail;

  /*parameters verification*/
  if (plist==NULL) return(LCRZO_ERR_PANULLPTR);
  if (pfonccritere==NULL) return(LCRZO_ERR_PANULLPTR);
  /*verification des parametres et affectation des positions*/
  if ( plist->elemcount==0 && posdebut==+1 && posfin==-1 )
    return(LCRZO_ERR_OK);
  lcrzo_er(lcrzo_priv_manageelemrangefast(plist->elemcount, posdebut, posfin,
					  NULL, NULL, NULL, NULL,
					  &infdirection, &infdistance,
					  &supdirection, &supdistance));

  /*we go to the first element*/
  lcrzo_er(lcrzo_priv_list_goto_listelem(plist, infdirection, infdistance, 0,
					 &ptravail));

  /*remove the elements in the range*/
  if (supdirection==LCRZO_PRIV_INCREASE)
  { ptravail = (lcrzo_listelem *)ptravail->pprecedent;
    for ( i=0 ; i<=supdistance; i++ )
    { if ( (*pfonccritere)(ptravail->pnext->pelem, pinfos) )
      { lcrzo_er(lcrzo_priv_list_remove_listelem(plist, ptravail->pnext));
      }
      else
      { ptravail = (lcrzo_listelem *)ptravail->pnext;
      }
    }
  }
  else
  { ptravail = (lcrzo_listelem *)ptravail->pnext;
    for ( i=0 ; i<=supdistance; i++ )
    { if ( (*pfonccritere)(ptravail->pprecedent->pelem, pinfos) )
      { lcrzo_er(lcrzo_priv_list_remove_listelem(plist,
						 ptravail->pprecedent));
      }
      else
      { ptravail = (lcrzo_listelem *)ptravail->pprecedent;
      }
    }
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_list_remove_criteria_all(lcrzo_list *plist,
				   lcrzo_bool (*pfonccritere)(const void *pelem,
						       void *pinfos),
				   void *pinfos)
{ lcrzo_er(lcrzo_list_remove_criteria_range(plist, 1, -1,
					    pfonccritere, pinfos));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_list_replace_pos(lcrzo_list *plist,
			   lcrzo_int32 position,
			   const void *pelem)
{ lcrzo_int32 distance;
  int sens;
  lcrzo_listelem *ptravail;

  /*parameters verification*/
  if (plist==NULL) return(LCRZO_ERR_PANULLPTR);
  if (pelem==NULL) return(LCRZO_ERR_PANULLPTR);
  /*verification des parametres et affectation des positions*/
  lcrzo_er(lcrzo_priv_manageelempos(plist->elemcount, position, 0,
				     NULL, NULL, &sens, &distance));

  /*we go to the element*/
  lcrzo_er(lcrzo_priv_list_goto_listelem(plist, sens, distance, 0, 
					 &ptravail));

  /*replace*/
  if ( plist->pfunc_erase != NULL ) /*dispose d'une procedure*/
    (*plist->pfunc_erase)(ptravail->pelem);
  memcpy(ptravail->pelem, pelem, plist->sizeofelems);

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_list_replace_first(lcrzo_list *plist, const void *pelem)
{ return(lcrzo_list_replace_pos(plist, +1, pelem));
}

/*-------------------------------------------------------------*/
int lcrzo_list_replace_last(lcrzo_list *plist, const void *pelem)
{ return(lcrzo_list_replace_pos(plist, -1, pelem));
}

/*-------------------------------------------------------------*/
int lcrzo_list_switch(lcrzo_list *plist,
		      lcrzo_int32 position1, 
		      lcrzo_int32 position2)
{ lcrzo_int32 distance1, distance2, pospositif1, pospositif2;
  int sens1, sens2;
  lcrzo_listelem *pprec1, *ptrav1, *psuiv1;
  lcrzo_listelem *pprec2, *ptrav2, *psuiv2;

  /*parameters verification*/
  if (plist==NULL) return(LCRZO_ERR_PANULLPTR);
  /*verification des parametres et affectation des positions*/
  lcrzo_er(lcrzo_priv_manageelempos(plist->elemcount, position1, 0,
				     NULL, &pospositif1, &sens1, &distance1));
  lcrzo_er(lcrzo_priv_manageelempos(plist->elemcount, position2, 0,
				     NULL, &pospositif2, &sens2, &distance2));

  /*pas besoin de permutter*/
  if (pospositif1==pospositif2) return(LCRZO_ERR_OK);

  /*we go to the elements*/
  lcrzo_er(lcrzo_priv_list_goto_listelem(plist, sens1, distance1, 0, 
					 &ptrav1));
  lcrzo_er(lcrzo_priv_list_goto_listelem(plist, sens2, distance2, 0, 
					 &ptrav2));

  /*on pointe aussi sur leurs precedents et suivants*/
  pprec1=(lcrzo_listelem *)ptrav1->pprecedent;
  psuiv1=(lcrzo_listelem *)ptrav1->pnext;
  pprec2=(lcrzo_listelem *)ptrav2->pprecedent;
  psuiv2=(lcrzo_listelem *)ptrav2->pnext;

  /*maintenant, on permutte*/
  if (pospositif1+1==pospositif2)
  { ptrav1->pprecedent=(lcrzo_listelem *)ptrav2;
    ptrav1->pnext=(lcrzo_listelem *)psuiv2;
    ptrav2->pprecedent=(lcrzo_listelem *)pprec1;
    ptrav2->pnext=(lcrzo_listelem *)ptrav1;
    pprec1->pnext=(lcrzo_listelem *)ptrav2;
    psuiv2->pprecedent=(lcrzo_listelem *)ptrav1;
  }
  else if (pospositif2+1==pospositif1)
  { ptrav2->pprecedent=(lcrzo_listelem *)ptrav1;
    ptrav2->pnext=(lcrzo_listelem *)psuiv1;
    ptrav1->pprecedent=(lcrzo_listelem *)pprec2;
    ptrav1->pnext=(lcrzo_listelem *)ptrav2;
    pprec2->pnext=(lcrzo_listelem *)ptrav1;
    psuiv1->pprecedent=(lcrzo_listelem *)ptrav2;
  }
  else /* cas standard ou les deux elems ne se suivent pas */
  { ptrav1->pprecedent=(lcrzo_listelem *)pprec2;
    ptrav1->pnext=(lcrzo_listelem *)psuiv2;
    ptrav2->pprecedent=(lcrzo_listelem *)pprec1;
    ptrav2->pnext=(lcrzo_listelem *)psuiv1;
    pprec1->pnext=(lcrzo_listelem *)ptrav2;
    pprec2->pnext=(lcrzo_listelem *)ptrav1;
    psuiv1->pprecedent=(lcrzo_listelem *)ptrav2;
    psuiv2->pprecedent=(lcrzo_listelem *)ptrav1;
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_list_invert_range(lcrzo_list *plist,
			    lcrzo_int32 posdebut,
			    lcrzo_int32 posfin)
{ lcrzo_int32 pospositif1, pospositif2;
  lcrzo_int32 nbapermutter, i;

  /*parameters verification*/
  if (plist==NULL) return(LCRZO_ERR_PANULLPTR);
  /*verification des parametres et affectation des positions*/
  if ( plist->elemcount==0 && posdebut==+1 && posfin==-1 )
    return(LCRZO_ERR_OK);
  lcrzo_er(lcrzo_priv_manageelempos(plist->elemcount, posdebut, 0,
				     NULL, &pospositif1, NULL, NULL));
  lcrzo_er(lcrzo_priv_manageelempos(plist->elemcount, posfin, 0,
				     NULL, &pospositif2, NULL, NULL));

  if ( pospositif2>pospositif1 )
  { nbapermutter=pospositif2-pospositif1+1;
    /*calcul du nombre de permuttations a faire*/
    if (nbapermutter%2) /*impair*/
      nbapermutter=(nbapermutter-1)/2;
    else
      nbapermutter=(nbapermutter)/2;
    /*permuttations*/
    for ( i=0 ; i<nbapermutter ; i++)
    { lcrzo_er(lcrzo_list_switch(plist, pospositif1+i, pospositif2-i));
    }
  }
  else
  { nbapermutter=pospositif1-pospositif2+1;
    /*calcul du nombre de permuttations a faire*/
    if (nbapermutter%2) /*impair*/
      nbapermutter=(nbapermutter-1)/2;
    else
      nbapermutter=(nbapermutter)/2;
    /*permuttations*/
    for ( i=0 ; i<nbapermutter ; i++)
    { lcrzo_er(lcrzo_list_switch(plist, pospositif2+i, pospositif1-i));
    }
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_list_invert_all(lcrzo_list *plist)
{ lcrzo_er(lcrzo_list_invert_range(plist, 1, -1));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_list_value_pos(lcrzo_list *plist, lcrzo_int32 position,
			 void *pelem)
{ int sens;
  lcrzo_listelem *ptravail;
  lcrzo_int32 distance;

  /*verification des parametres et affectation des positions*/
  lcrzo_er(lcrzo_priv_manageelempos(plist->elemcount, position, 0,
				     NULL, NULL, &sens, &distance));

  lcrzo_er(lcrzo_priv_list_goto_listelem(plist, sens, distance, 0, 
					 &ptravail));

  if (pelem!=NULL) memcpy(pelem, ptravail->pelem, plist->sizeofelems);
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_list_value_first(lcrzo_list *plist, void *pelem)
{ return(lcrzo_list_value_pos(plist, +1, pelem));
}

/*-------------------------------------------------------------*/
int lcrzo_list_value_last(lcrzo_list *plist, void *pelem)
{ return(lcrzo_list_value_pos(plist, -1, pelem));
}

/*-------------------------------------------------------------*/
int lcrzo_list_count(lcrzo_list *plist, lcrzo_int32 *pnbelems)
{ if (pnbelems!=NULL) *pnbelems=plist->elemcount;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_list_sort_range(lcrzo_list *plist,
			  lcrzo_int32 startpos,
			  lcrzo_int32 endpos,
			  lcrzo_int8 (*pfonccmpelem)(const void *peleminf,
					      const void *pelemsup,
					      void *pinfos),
			  void *pinfos)
{ lcrzo_int32 startpo, endpo, i, j, idistance, nummini;
  int infsupdirection, idirection;
  lcrzo_listelem *ptrav1, *ptrav2, *pelemmini;

  /*parameters verification*/
  if (plist==NULL) return(LCRZO_ERR_PANULLPTR);
  if (pfonccmpelem==NULL) return(LCRZO_ERR_PANULLPTR);
  /*verification des parametres et affectation des positions*/
  if ( plist->elemcount==0 && startpos==+1 && endpos==-1 )
    return(LCRZO_ERR_OK);
  lcrzo_er(lcrzo_priv_manageelemrange(plist->elemcount, startpos, endpos,
				      NULL, &startpo, NULL, &endpo,
				      NULL, NULL, &infsupdirection, NULL));

  /*sort the elements in the range*/
  if (infsupdirection==LCRZO_PRIV_INCREASE)
  { for ( i=startpo ; i<=endpo ; i++ )
    { /*on va jusqu'a l'element i*/
      lcrzo_er(lcrzo_priv_manageelempos(plist->elemcount, i, 0, 
					 NULL, NULL, &idirection, &idistance));
      lcrzo_er(lcrzo_priv_list_goto_listelem(plist, idirection, idistance,
					     0, &ptrav1));
      /*now we try to find the mini*/
      nummini=i;
      pelemmini=ptrav1->pelem;
      ptrav2=(lcrzo_listelem *)ptrav1->pnext;
      for ( j=i+1 ; j<=endpo ; j++ )
      { /*printf("i=%ld, j=%ld %d\n", i, j, *(int*)(ptrav2->pelem));*/
        if ((*pfonccmpelem)(ptrav2->pelem, pelemmini, pinfos)==-1)
        { nummini=j;
          pelemmini=ptrav2->pelem;
        }
        ptrav2=(lcrzo_listelem *)ptrav2->pnext;
      }
      /*on permutte*/
      lcrzo_er(lcrzo_list_switch(plist, i, nummini));
    }
  }
  else
  { for ( i=startpo ; i>=endpo ; i-- )
    { /*on va jusqu'a l'element i*/
      lcrzo_er(lcrzo_priv_manageelempos(plist->elemcount, i, 0, 
					 NULL, NULL, &idirection, &idistance));
      lcrzo_er(lcrzo_priv_list_goto_listelem(plist, idirection, idistance,
					     0, &ptrav1));
      /*now we try to find the mini*/
      nummini=i;
      pelemmini=ptrav1->pelem;
      ptrav2=(lcrzo_listelem *)ptrav1->pprecedent;
      for ( j=i-1 ; j>=endpo ; j-- )
      { /*printf("i=%ld, j=%ld %d\n", i, j, *(int*)(ptrav2->pelem));*/
        if ((*pfonccmpelem)(ptrav2->pelem, pelemmini, pinfos)==-1)
        { nummini=j;
          pelemmini=ptrav2->pelem;
        }
        ptrav2=(lcrzo_listelem *)ptrav2->pprecedent;
      }
      /*on permutte*/
      lcrzo_er(lcrzo_list_switch(plist, i, nummini));
    }
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_list_sort_all(lcrzo_list *plist,
			lcrzo_int8 (*pfonccmpelem)(const void *peleminf,
					    const void *pelemsup,
					    void *pinfos),
			void *pinfos)
{ lcrzo_er(lcrzo_list_sort_range(plist, 1, -1, pfonccmpelem, pinfos));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_list_search_range(lcrzo_list *plist,
			    lcrzo_int32 startpos,
			    lcrzo_int32 endpos,
			    lcrzo_bool (*pfoncrecherche)(const void *pelem,
						  void *pinfos),
			    void *pinfos,
			    lcrzo_int32 *pposelem,
			    void *pelem)
{ lcrzo_int32 infdistance, supdistance, i, infpospos;
  int infdirection, supdirection;
  lcrzo_listelem *ptravail;

  /*verification des parametres et affectation des positions*/
  if (pfoncrecherche==NULL) return(LCRZO_ERR_PANULLPTR);
  if ( plist->elemcount==0 && startpos==+1 && endpos==-1 )
    return(LCRZO_ERR_OKSEARCHNOTFOUND);
  lcrzo_er(lcrzo_priv_manageelemrange(plist->elemcount, startpos, endpos,
				      NULL, &infpospos, NULL, NULL,
				      &infdirection, &infdistance,
				      &supdirection, &supdistance));

  /*we go to the first element*/
  lcrzo_er(lcrzo_priv_list_goto_listelem(plist, infdirection, infdistance, 0,
					 &ptravail));

  /*compare the elements in the range*/
  if (supdirection==LCRZO_PRIV_INCREASE)
  { for ( i=0 ; i<=supdistance; i++ )
    { if ( (*pfoncrecherche)(ptravail->pelem, pinfos) )
      { if (pposelem!=NULL) *pposelem=i+infpospos;
        if (pelem!=NULL) memcpy(pelem, ptravail->pelem, plist->sizeofelems);
        return(LCRZO_ERR_OK);
      }
      ptravail = (lcrzo_listelem *)ptravail->pnext;
    }
  }
  else
  { for ( i=0 ; i<=supdistance; i++ )
    { if ( (*pfoncrecherche)(ptravail->pelem, pinfos) )
      { if (pposelem!=NULL) *pposelem=infpospos-i;
        if (pelem!=NULL) memcpy(pelem, ptravail->pelem, plist->sizeofelems);
        return(LCRZO_ERR_OK);
      }
      ptravail = (lcrzo_listelem *)ptravail->pprecedent;
    }
  }

  return(LCRZO_ERR_OKSEARCHNOTFOUND);
}

/*-------------------------------------------------------------*/
int lcrzo_list_search_all(lcrzo_list *plist,
			  lcrzo_bool (*pfoncrecherche)(const void *pelem,
						void *pinfos),
			  void *pinfos,
			  lcrzo_int32 *pposelem,
			  void *pelem)
{ lcrzo_er(lcrzo_list_search_range(plist, 1, -1, pfoncrecherche, pinfos,
				   pposelem, pelem));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_list_searchelem_range(lcrzo_list *plist,
				lcrzo_int32 startpos,
				lcrzo_int32 endpos,
				const void *pelemtofind,
				lcrzo_int32 *pposelemfound,
				void *pelemfound)
{ lcrzo_int32 infdistance, supdistance, i, infpospos;
  int infdirection, supdirection;
  lcrzo_listelem *ptravail;

  /*verification des parametres et affectation des positions*/
  if (pelemtofind==NULL) return(LCRZO_ERR_PANULLPTR);
  if ( plist->elemcount==0 && startpos==+1 && endpos==-1 )
    return(LCRZO_ERR_OKSEARCHNOTFOUND);
  lcrzo_er(lcrzo_priv_manageelemrange(plist->elemcount, startpos, endpos,
				      NULL, &infpospos, NULL, NULL,
				      &infdirection, &infdistance,
				      &supdirection, &supdistance));

  /*we go to the first element*/
  lcrzo_er(lcrzo_priv_list_goto_listelem(plist, infdirection, infdistance, 0,
					 &ptravail));

  /*compare the elements in the range*/
  if (supdirection==LCRZO_PRIV_INCREASE)
  { for ( i=0 ; i<=supdistance; i++ )
    { if ( ! memcmp(ptravail->pelem, pelemtofind, plist->sizeofelems) )
      { if (pposelemfound!=NULL) *pposelemfound=i+infpospos;
        if (pelemfound!=NULL)
	  memcpy(pelemfound, ptravail->pelem, plist->sizeofelems);
        return(LCRZO_ERR_OK);
      }
      ptravail = (lcrzo_listelem *)ptravail->pnext;
    }
  }
  else
  { for ( i=0 ; i<=supdistance; i++ )
    { if ( ! memcmp(ptravail->pelem, pelemtofind, plist->sizeofelems) )
      { if (pposelemfound!=NULL) *pposelemfound=infpospos-i;
        if (pelemfound!=NULL)
	  memcpy(pelemfound, ptravail->pelem, plist->sizeofelems);
        return(LCRZO_ERR_OK);
      }
      ptravail = (lcrzo_listelem *)ptravail->pprecedent;
    }
  }

  return(LCRZO_ERR_OKSEARCHNOTFOUND);
}

/*-------------------------------------------------------------*/
int lcrzo_list_searchelem_all(lcrzo_list *plist,
			      const void *pelemtofind,
			      lcrzo_int32 *pposelemfound,
			      void *pelemfound)
{ lcrzo_er(lcrzo_list_searchelem_range(plist, 1, -1, pelemtofind,
				       pposelemfound, pelemfound));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_list_loop_range(lcrzo_list *plist, 
			  lcrzo_int32 startpos,
			  lcrzo_int32 endpos,
			  int (*pfonc)(const void *pelem,
				       void *pinfos),
			  void *pinfos)
{ lcrzo_int32 infdistance, supdistance, i;
  int infdirection, supdirection;
  lcrzo_listelem *ptravail;

  /*verification des parametres et affectation des positions*/
  if (pfonc==NULL) return(LCRZO_ERR_PANULLPTR);
  if ( plist->elemcount==0 && startpos==+1 && endpos==-1 )
    return(LCRZO_ERR_OK);
  lcrzo_er(lcrzo_priv_manageelemrange(plist->elemcount, startpos, endpos,
				      NULL, NULL, NULL, NULL,
				      &infdirection, &infdistance,
				      &supdirection, &supdistance));

  /*we go to the first element*/
  lcrzo_er(lcrzo_priv_list_goto_listelem(plist, infdirection, infdistance, 0,
					 &ptravail));

  /*compare the elements in the range*/
  if (supdirection==LCRZO_PRIV_INCREASE)
  { for ( i=0 ; i<=supdistance; i++ )
    { lcrzo_er(((*pfonc)(ptravail->pelem, pinfos)));
      ptravail = (lcrzo_listelem *)ptravail->pnext;
    }
  }
  else
  { for ( i=0 ; i<=supdistance; i++ )
    { lcrzo_er(((*pfonc)(ptravail->pelem, pinfos)));
      ptravail = (lcrzo_listelem *)ptravail->pprecedent;
    }
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_list_loop_all(lcrzo_list *plist,
			int (*pfonc)(const void *pelem,
				      void *pinfos),
			void *pinfos)
{ return(lcrzo_list_loop_range(plist, 1, -1, pfonc, pinfos));
}


/*-------------------------------------------------------------*/
/*-------------------------------------------------------------*/
int lcrzo_priv_datalist_free(void *pelem);
int lcrzo_priv_datalist_free(void *pelem)
{ lcrzo_datalist *pdatalist;
  pdatalist=(lcrzo_datalist *)pelem;
  return(lcrzo_data_free(pdatalist->pdata));
}

/*-------------------------------------------------------------*/
int lcrzo_datalist_init(lcrzo_list *plist)
{ return(lcrzo_list_init(plist, sizeof(lcrzo_datalist),
			 &lcrzo_priv_datalist_free));
}

/*-------------------------------------------------------------*/
int lcrzo_datalist_add_pos(lcrzo_list *plist,
			   lcrzo_int32 pos,
			   lcrzo_uint32 datatype,
			   lcrzo_constdata data,
			   lcrzo_int32 datasize)
{ lcrzo_datalist datalist;

  /*parameters verification*/
  if (plist==NULL) return(LCRZO_ERR_PANULLPTR);
  if (data==NULL) return(LCRZO_ERR_PANULLPTR);

  /*create the data*/
  datalist.datatype=datatype;
  datalist.datasize=datasize;
  lcrzo_er(lcrzo_data_alloc(datasize, &(datalist.pdata)));
  memcpy(datalist.pdata, data, datasize);

  /*add the data*/
  lcrzo_er(lcrzo_list_add_pos(plist, pos, &datalist));

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_datalist_valuem_pos(lcrzo_list *plist,
			      lcrzo_int32 pos,
			      lcrzo_uint32 *pdatatype,
			      lcrzo_data *pdata,
			      lcrzo_int32 *pdatasize)
{ lcrzo_datalist datalist;

  /*get the value*/
  lcrzo_er(lcrzo_list_value_pos(plist, pos, &datalist));

  if (pdatatype!=NULL) *pdatatype=datalist.datatype;
  return(lcrzo_data_initm_data(datalist.pdata, datalist.datasize, pdata, pdatasize));
}


/*-------------------------------------------------------------*/
int lcrzo_portlist_init(lcrzo_list *plist)
{ return(lcrzo_list_init(plist, sizeof(lcrzo_portlist), NULL));
}

/*-------------------------------------------------------------*/
int lcrzo_portlist_add_range(lcrzo_list *plist,
			     lcrzo_uint16 infport,
			     lcrzo_uint16 support)
{ lcrzo_int32 count, i;
  lcrzo_portlist foundportlist, newportlist;

  if (infport>support) return(LCRZO_ERR_PAINFHIGHERSUP);

  lcrzo_er(lcrzo_list_count(plist, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(plist, i, &foundportlist));
    if ( foundportlist.inf>support )
    { /* add it just before */
      newportlist.inf=infport;
      newportlist.sup=support;
      lcrzo_er(lcrzo_list_add_pos(plist, i, &newportlist));
      return(LCRZO_ERR_OK);
    }
    if ( infport<foundportlist.inf && support<=foundportlist.sup )
    { /* extend current elem */
      foundportlist.inf=infport;
      lcrzo_er(lcrzo_list_replace_pos(plist, i, &foundportlist));
      return(LCRZO_ERR_OK);
    }
    if ( infport>=foundportlist.inf && support<=foundportlist.sup )
    { /* inside current elem */
      return(LCRZO_ERR_OK);
    }
    if ( infport<=foundportlist.sup && support>foundportlist.sup )
    { /* extend current elem */
      foundportlist.sup=support;
      lcrzo_er(lcrzo_list_replace_pos(plist, i, &foundportlist));
      return(LCRZO_ERR_OK);
    }
  }

  /* add it at the end */
  newportlist.inf=infport;
  newportlist.sup=support;
  lcrzo_er(lcrzo_list_add_last(plist, &newportlist));
      
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_portlist_del_range(lcrzo_list *plist,
			     lcrzo_uint16 infport,
			     lcrzo_uint16 support)
{ lcrzo_int32 count, i;
  lcrzo_portlist foundportlist, newportlist;

  if (infport>support) return(LCRZO_ERR_PAINFHIGHERSUP);

  lcrzo_er(lcrzo_list_count(plist, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(plist, i, &foundportlist));
    if ( foundportlist.inf>support )
    { /* nothing to remove */
      return(LCRZO_ERR_OK);
    }
    else if ( infport<=foundportlist.inf && support<foundportlist.sup )
    { /* truncate current elem */
      foundportlist.inf=(lcrzo_uint16)(support+1);
      lcrzo_er(lcrzo_list_replace_pos(plist, i, &foundportlist));
      return(LCRZO_ERR_OK);
    }
    else if ( infport<=foundportlist.inf && support>=foundportlist.sup )
    { /* remove current elem */
      lcrzo_er(lcrzo_list_remove_pos(plist, i));
      /* eventually continue to remove */
      i--; count--;
      continue;
    }
    else if ( infport>foundportlist.inf && support<foundportlist.sup )
    { /* cut the current elem in two */
      newportlist.inf=foundportlist.inf;
      foundportlist.inf=(lcrzo_uint16)(support+1);
      lcrzo_er(lcrzo_list_replace_pos(plist, i, &foundportlist));
      newportlist.sup=(lcrzo_uint16)(infport-1);
      lcrzo_er(lcrzo_list_add_pos(plist, i, &newportlist));
      return(LCRZO_ERR_OK);
    }
    else if ( infport<=foundportlist.sup && support>=foundportlist.sup )
    { /* truncate current elem */
      foundportlist.sup=(lcrzo_uint16)(infport-1);
      lcrzo_er(lcrzo_list_replace_pos(plist, i, &foundportlist));
      /* eventually continue to remove */
      continue;
    }
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_portlist_init_text(lcrzo_conststring porttext,
			     lcrzo_list *plist)
{ lcrzo_string porttext1, porttext2;
  int ret;
  lcrzo_int32 indic, startpos, endpos;
  lcrzo_uint16 infport, support;

  /* suppress unwanted characters */
  lcrzo_er(lcrzo_string_replacem_nchar(porttext, LCRZO_FALSE, +1, -1, 0,
				       " \t", "", &porttext1));
  ret=lcrzo_string_replacem_nchar(porttext1, LCRZO_FALSE, +1, -1, 0,
				  "\r\n", ",", &porttext2);
  lcrzo_string_free(porttext1);
  if (ret!=LCRZO_ERR_OK) return(ret);

  /* construct the list */
  lcrzo_efr(lcrzo_portlist_init(plist), lcrzo_string_free(porttext2));
  indic=0;
  ret=lcrzo_string_token_char(porttext2, LCRZO_FALSE, +1, -1, ',',
			      &indic, NULL, &startpos, NULL, &endpos);
  while (ret==LCRZO_ERR_OK)
  { lcrzo_efr(lcrzo_string_initm_range(porttext2, startpos, endpos, 
				       &porttext1), 
	      lcrzo_string_free(porttext2));
    /* treat special cases */
    if ( strlen(porttext1)==0 )
    { /* do nothing */
    }
    else if ( ! lcrzo_priv_strcasecmp(porttext1, "any") || ! lcrzo_priv_strcasecmp(porttext1, "all") )
    { /* add all range */
      lcrzo_efr(lcrzo_portlist_add_range(plist, 0, 0xFFFF),
		lcrzo_string_free(porttext1);lcrzo_string_free(porttext2));
    }
    else if ( porttext1[0]=='!' )
    { /* remove this range */
      lcrzo_efr(lcrzo_port_init_portrange(porttext1+1, &infport, &support),
		lcrzo_string_free(porttext1);lcrzo_string_free(porttext2));
      lcrzo_efr(lcrzo_portlist_del_range(plist, infport, support),
		lcrzo_string_free(porttext1);lcrzo_string_free(porttext2));
    }
    else
    { /* add this range */
      lcrzo_efr(lcrzo_port_init_portrange(porttext1, &infport, &support),
		lcrzo_string_free(porttext1);lcrzo_string_free(porttext2));
      lcrzo_efr(lcrzo_portlist_add_range(plist, infport, support),
		lcrzo_string_free(porttext1);lcrzo_string_free(porttext2));
    }

    /* get next token */
    lcrzo_string_free(porttext1);
    ret=lcrzo_string_token_char(porttext2, LCRZO_FALSE, +1, -1, ',',
				&indic, NULL, &startpos, NULL, &endpos);
  }

  lcrzo_string_free(porttext2);
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_string_initm_portlist(lcrzo_list *plist,
				lcrzo_string *pporttext)
{ lcrzo_int32 count, i;
  lcrzo_portlist portlist;
  lcrzo_portrange range;
  lcrzo_bool firstrange;

  lcrzo_er(lcrzo_list_count(plist, &count));
  lcrzo_er(lcrzo_string_initm_text("", pporttext));
  firstrange=LCRZO_TRUE;
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(plist, i, &portlist));
    lcrzo_er(lcrzo_portrange_init_port(portlist.inf, portlist.sup, range));
    if (!firstrange) { lcrzo_er(lcrzo_string_appendm_text(",", pporttext)); }
    firstrange=LCRZO_FALSE;
    lcrzo_er(lcrzo_string_appendm_text(range, pporttext)); 
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_portlist_isinlist(lcrzo_list *plist,
			    lcrzo_uint16 port,
			    lcrzo_bool *pyes)
{ lcrzo_int32 count, i;
  lcrzo_portlist portlist;

  lcrzo_er(lcrzo_list_count(plist, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(plist, i, &portlist));
    if ( port>=portlist.inf && port <=portlist.sup )
    { if (pyes!=NULL) *pyes=LCRZO_TRUE;
      return(LCRZO_ERR_OK);
    }
  }
  if (pyes!=NULL) *pyes=LCRZO_FALSE;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_portlist_value_first(lcrzo_list *plist,
			       lcrzo_uint16 *pport)
{ lcrzo_int32 count;
  lcrzo_portlist portlist;

  lcrzo_er(lcrzo_list_count(plist, &count));
  if (count==0) return(LCRZO_ERR_OKDATAEND);

  lcrzo_er(lcrzo_list_value_first(plist, &portlist));
  if ( pport!=NULL ) *pport=portlist.inf;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_portlist_value_next(lcrzo_list *plist,
			      lcrzo_uint16 port,
			      lcrzo_uint16 *pnextport)
{ lcrzo_int32 count, i;
  lcrzo_portlist portlist;

  lcrzo_er(lcrzo_list_count(plist, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(plist, i, &portlist));
    if ( port<portlist.inf )
    { if ( pnextport!=NULL ) *pnextport=portlist.inf;
      return(LCRZO_ERR_OK);
    }
    if ( port>=portlist.inf && port<portlist.sup )
    { if ( pnextport!=NULL ) *pnextport=(lcrzo_uint16)(port+1);
      return(LCRZO_ERR_OK);
    }
  }

  return(LCRZO_ERR_OKDATAEND);
}


/*-------------------------------------------------------------*/
int lcrzo_iplist_init(lcrzo_list *plist)
{ return(lcrzo_list_init(plist, sizeof(lcrzo_iplist), NULL));
}

/*-------------------------------------------------------------*/
int lcrzo_iplist_add_range(lcrzo_list *plist,
			   lcrzo_ipl infipl,
			   lcrzo_ipl supipl)
{ lcrzo_int32 count, i;
  lcrzo_iplist foundiplist, newiplist;

  if (infipl>supipl) return(LCRZO_ERR_PAINFHIGHERSUP);

  lcrzo_er(lcrzo_list_count(plist, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(plist, i, &foundiplist));
    if ( foundiplist.inf>supipl )
    { /* add it just before */
      newiplist.inf=infipl;
      newiplist.sup=supipl;
      lcrzo_er(lcrzo_list_add_pos(plist, i, &newiplist));
      return(LCRZO_ERR_OK);
    }
    if ( infipl<foundiplist.inf && supipl<=foundiplist.sup )
    { /* extend current elem */
      foundiplist.inf=infipl;
      lcrzo_er(lcrzo_list_replace_pos(plist, i, &foundiplist));
      return(LCRZO_ERR_OK);
    }
    if ( infipl>=foundiplist.inf && supipl<=foundiplist.sup )
    { /* inside current elem */
      return(LCRZO_ERR_OK);
    }
    if ( infipl<=foundiplist.sup && supipl>foundiplist.sup )
    { /* extend current elem */
      foundiplist.sup=supipl;
      lcrzo_er(lcrzo_list_replace_pos(plist, i, &foundiplist));
      return(LCRZO_ERR_OK);
    }
  }

  /* add it at the end */
  newiplist.inf=infipl;
  newiplist.sup=supipl;
  lcrzo_er(lcrzo_list_add_last(plist, &newiplist));
      
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_iplist_del_range(lcrzo_list *plist,
			   lcrzo_ipl infipl,
			   lcrzo_ipl supipl)
{ lcrzo_int32 count, i;
  lcrzo_iplist foundiplist, newiplist;

  if (infipl>supipl) return(LCRZO_ERR_PAINFHIGHERSUP);

  lcrzo_er(lcrzo_list_count(plist, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(plist, i, &foundiplist));
    if ( foundiplist.inf>supipl )
    { /* nothing to remove */
      return(LCRZO_ERR_OK);
    }
    else if ( infipl<=foundiplist.inf && supipl<foundiplist.sup )
    { /* truncate current elem */
      foundiplist.inf=supipl+1;
      lcrzo_er(lcrzo_list_replace_pos(plist, i, &foundiplist));
      return(LCRZO_ERR_OK);
    }
    else if ( infipl<=foundiplist.inf && supipl>=foundiplist.sup )
    { /* remove current elem */
      lcrzo_er(lcrzo_list_remove_pos(plist, i));
      /* eventually continue to remove */
      i--; count--;
      continue;
    }
    else if ( infipl>foundiplist.inf && supipl<foundiplist.sup )
    { /* cut the current elem in two */
      newiplist.inf=foundiplist.inf;
      foundiplist.inf=supipl+1;
      lcrzo_er(lcrzo_list_replace_pos(plist, i, &foundiplist));
      newiplist.sup=infipl-1;
      lcrzo_er(lcrzo_list_add_pos(plist, i, &newiplist));
      return(LCRZO_ERR_OK);
    }
    else if ( infipl<=foundiplist.sup && supipl>=foundiplist.sup )
    { /* truncate current elem */
      foundiplist.sup=infipl-1;
      lcrzo_er(lcrzo_list_replace_pos(plist, i, &foundiplist));
      /* eventually continue to remove */
      continue;
    }
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_iplist_init_text(lcrzo_conststring ipltext,
			   lcrzo_list *plist)
{ lcrzo_string ipltext1, ipltext2;
  int ret;
  lcrzo_int32 indic, startpos, endpos;
  lcrzo_ipl infipl, supipl;

  /* suppress unwanted characters */
  lcrzo_er(lcrzo_string_replacem_nchar(ipltext, LCRZO_FALSE, +1, -1, 0,
				       " \t", "", &ipltext1));
  ret=lcrzo_string_replacem_nchar(ipltext1, LCRZO_FALSE, +1, -1, 0,
				  "\r\n", ",", &ipltext2);
  lcrzo_string_free(ipltext1);
  if (ret!=LCRZO_ERR_OK) return(ret);

  /* construct the list */
  lcrzo_efr(lcrzo_iplist_init(plist), lcrzo_string_free(ipltext2));
  indic=0;
  ret=lcrzo_string_token_char(ipltext2, LCRZO_FALSE, +1, -1, ',',
			      &indic, NULL, &startpos, NULL, &endpos);
  while (ret==LCRZO_ERR_OK)
  { lcrzo_efr(lcrzo_string_initm_range(ipltext2, startpos, endpos, 
				       &ipltext1), 
	      lcrzo_string_free(ipltext2));
    /* treat special cases */
    if ( strlen(ipltext1)==0 )
    { /* do nothing */
    }
    else if ( ! lcrzo_priv_strcasecmp(ipltext1, "any") ||
	      ! lcrzo_priv_strcasecmp(ipltext1, "all") )
    { /* add all range */
      lcrzo_efr(lcrzo_iplist_add_range(plist, 0, 0xFFFFFFFFu),
		lcrzo_string_free(ipltext1);lcrzo_string_free(ipltext2));
    }
    else if ( ipltext1[0]=='!' )
    { /* remove this range */
      lcrzo_efr(lcrzo_ipl_init_iprange(ipltext1+1, &infipl, &supipl),
		lcrzo_string_free(ipltext1);lcrzo_string_free(ipltext2));
      lcrzo_efr(lcrzo_iplist_del_range(plist, infipl, supipl),
		lcrzo_string_free(ipltext1);lcrzo_string_free(ipltext2));
    }
    else
    { /* add this range */
      lcrzo_efr(lcrzo_ipl_init_iprange(ipltext1, &infipl, &supipl),
		lcrzo_string_free(ipltext1);lcrzo_string_free(ipltext2));
      lcrzo_efr(lcrzo_iplist_add_range(plist, infipl, supipl),
		lcrzo_string_free(ipltext1);lcrzo_string_free(ipltext2));
    }

    /* get next token */
    lcrzo_string_free(ipltext1);
    ret=lcrzo_string_token_char(ipltext2, LCRZO_FALSE, +1, -1, ',',
				&indic, NULL, &startpos, NULL, &endpos);
  }

  lcrzo_string_free(ipltext2);
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_string_initm_iplist(lcrzo_list *plist,
			      lcrzo_string *pipltext)
{ lcrzo_int32 count, i;
  lcrzo_iplist iplist;
  lcrzo_iprange range;
  lcrzo_bool firstrange;

  lcrzo_er(lcrzo_list_count(plist, &count));
  lcrzo_er(lcrzo_string_initm_text("", pipltext));
  firstrange=LCRZO_TRUE;
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(plist, i, &iplist));
    lcrzo_er(lcrzo_iprange_init_ipl(iplist.inf, iplist.sup, range));
    if (!firstrange) { lcrzo_er(lcrzo_string_appendm_text(",", pipltext)); }
    firstrange=LCRZO_FALSE;
    lcrzo_er(lcrzo_string_appendm_text(range, pipltext)); 
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_iplist_isinlist(lcrzo_list *plist,
			  lcrzo_ipl ipl,
			  lcrzo_bool *pyes)
{ lcrzo_int32 count, i;
  lcrzo_iplist iplist;

  lcrzo_er(lcrzo_list_count(plist, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(plist, i, &iplist));
    if ( ipl>=iplist.inf && ipl <=iplist.sup )
    { if (pyes!=NULL) *pyes=LCRZO_TRUE;
      return(LCRZO_ERR_OK);
    }
  }
  if (pyes!=NULL) *pyes=LCRZO_FALSE;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_iplist_value_first(lcrzo_list *plist,
			     lcrzo_ipl *pipl)
{ lcrzo_int32 count;
  lcrzo_iplist iplist;

  lcrzo_er(lcrzo_list_count(plist, &count));
  if (count==0) return(LCRZO_ERR_OKDATAEND);

  lcrzo_er(lcrzo_list_value_first(plist, &iplist));
  if ( pipl!=NULL ) *pipl=iplist.inf;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_iplist_value_next(lcrzo_list *plist,
			    lcrzo_ipl ipl,
			    lcrzo_ipl *pnextipl)
{ lcrzo_int32 count, i;
  lcrzo_iplist iplist;

  lcrzo_er(lcrzo_list_count(plist, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(plist, i, &iplist));
    if ( ipl<iplist.inf )
    { if ( pnextipl!=NULL ) *pnextipl=iplist.inf;
      return(LCRZO_ERR_OK);
    }
    if ( ipl>=iplist.inf && ipl<iplist.sup )
    { if ( pnextipl!=NULL ) *pnextipl=ipl+1;
      return(LCRZO_ERR_OK);
    }
  }

  return(LCRZO_ERR_OKDATAEND);
}


/*-------------------------------------------------------------*/
int lcrzo_ethlist_init(lcrzo_list *plist)
{ return(lcrzo_list_init(plist, sizeof(lcrzo_ethlist), NULL));
}

/*-------------------------------------------------------------*/
int lcrzo_ethlist_add_range(lcrzo_list *plist,
			    lcrzo_etha infetha,
			    lcrzo_etha supetha)
{ lcrzo_int32 count, i;
  lcrzo_ethlist foundethlist, newethlist;

  if (lcrzo_priv_etha_gt(infetha, supetha)) return(LCRZO_ERR_PAINFHIGHERSUP);

  lcrzo_er(lcrzo_list_count(plist, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(plist, i, &foundethlist));
    if ( lcrzo_priv_etha_gt(foundethlist.inf, supetha) )
    { /* add it just before */
      memcpy(newethlist.inf, infetha, LCRZO_ETHA_MAXBYTES);
      memcpy(newethlist.sup, supetha, LCRZO_ETHA_MAXBYTES);
      lcrzo_er(lcrzo_list_add_pos(plist, i, &newethlist));
      return(LCRZO_ERR_OK);
    }
    if ( lcrzo_priv_etha_lt(infetha, foundethlist.inf) && 
	 lcrzo_priv_etha_le(supetha, foundethlist.sup) )
    { /* extend current elem */
      memcpy(foundethlist.inf, infetha, LCRZO_ETHA_MAXBYTES);
      lcrzo_er(lcrzo_list_replace_pos(plist, i, &foundethlist));
      return(LCRZO_ERR_OK);
    }
    if ( lcrzo_priv_etha_ge(infetha, foundethlist.inf) && 
	 lcrzo_priv_etha_le(supetha, foundethlist.sup) )
    { /* inside current elem */
      return(LCRZO_ERR_OK);
    }
    if ( lcrzo_priv_etha_le(infetha, foundethlist.sup) && 
	 lcrzo_priv_etha_gt(supetha, foundethlist.sup) )
    { /* extend current elem */
      memcpy(foundethlist.sup, supetha, LCRZO_ETHA_MAXBYTES);
      lcrzo_er(lcrzo_list_replace_pos(plist, i, &foundethlist));
      return(LCRZO_ERR_OK);
    }
  }

  /* add it at the end */
  memcpy(newethlist.inf, infetha, LCRZO_ETHA_MAXBYTES);
  memcpy(newethlist.sup, supetha, LCRZO_ETHA_MAXBYTES);
  lcrzo_er(lcrzo_list_add_last(plist, &newethlist));
      
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_ethlist_del_range(lcrzo_list *plist,
			    lcrzo_etha infetha,
			    lcrzo_etha supetha)
{ lcrzo_int32 count, i;
  lcrzo_ethlist foundethlist, newethlist;

  if (lcrzo_priv_etha_gt(infetha, supetha)) return(LCRZO_ERR_PAINFHIGHERSUP);

  lcrzo_er(lcrzo_list_count(plist, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(plist, i, &foundethlist));
    if ( lcrzo_priv_etha_gt(foundethlist.inf, supetha) )
    { /* nothing to remove */
      return(LCRZO_ERR_OK);
    }
    else if ( lcrzo_priv_etha_le(infetha, foundethlist.inf) &&
	      lcrzo_priv_etha_lt(supetha, foundethlist.sup) )
    { /* truncate current elem */
      lcrzo_er(lcrzo_priv_etha_inc(supetha, foundethlist.inf));
      lcrzo_er(lcrzo_list_replace_pos(plist, i, &foundethlist));
      return(LCRZO_ERR_OK);
    }
    else if ( lcrzo_priv_etha_le(infetha, foundethlist.inf) && 
	      lcrzo_priv_etha_ge(supetha, foundethlist.sup) )
    { /* remove current elem */
      lcrzo_er(lcrzo_list_remove_pos(plist, i));
      /* eventually continue to remove */
      i--; count--;
      continue;
    }
    else if ( lcrzo_priv_etha_gt(infetha, foundethlist.inf) && 
	      lcrzo_priv_etha_lt(supetha, foundethlist.sup) )
    { /* cut the current elem in two */
      memcpy(newethlist.inf, foundethlist.inf, LCRZO_ETHA_MAXBYTES);
      lcrzo_er(lcrzo_priv_etha_inc(supetha, foundethlist.inf));
      lcrzo_er(lcrzo_list_replace_pos(plist, i, &foundethlist));
      lcrzo_er(lcrzo_priv_etha_dec(infetha, newethlist.sup));
      lcrzo_er(lcrzo_list_add_pos(plist, i, &newethlist));
      return(LCRZO_ERR_OK);
    }
    else if ( lcrzo_priv_etha_le(infetha, foundethlist.sup) && 
	      lcrzo_priv_etha_ge(supetha, foundethlist.sup) )
    { /* truncate current elem */
      lcrzo_er(lcrzo_priv_etha_dec(infetha, foundethlist.sup));
      lcrzo_er(lcrzo_list_replace_pos(plist, i, &foundethlist));
      /* eventually continue to remove */
      continue;
    }
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_ethlist_init_text(lcrzo_conststring ethatext,
			    lcrzo_list *plist)
{ lcrzo_string ethatext1, ethatext2;
  int ret;
  lcrzo_int32 indic, startpos, endpos;
  lcrzo_etha infetha, supetha;

  /* suppress unwanted characters */
  lcrzo_er(lcrzo_string_replacem_nchar(ethatext, LCRZO_FALSE, +1, -1, 0,
				       " \t", "", &ethatext1));
  ret=lcrzo_string_replacem_nchar(ethatext1, LCRZO_FALSE, +1, -1, 0,
				  "\r\n", ",", &ethatext2);
  lcrzo_string_free(ethatext1);
  if (ret!=LCRZO_ERR_OK) return(ret);

  /* construct the list */
  lcrzo_efr(lcrzo_ethlist_init(plist), lcrzo_string_free(ethatext2));
  indic=0;
  ret=lcrzo_string_token_char(ethatext2, LCRZO_FALSE, +1, -1, ',',
			      &indic, NULL, &startpos, NULL, &endpos);
  while (ret==LCRZO_ERR_OK)
  { lcrzo_efr(lcrzo_string_initm_range(ethatext2, startpos, endpos, 
				       &ethatext1), 
	      lcrzo_string_free(ethatext2));
    /* treat special cases */
    if ( strlen(ethatext1)==0 )
    { /* do nothing */
    }
    else if ( ! lcrzo_priv_strcasecmp(ethatext1, "any") ||
	      ! lcrzo_priv_strcasecmp(ethatext1, "all") )
    { /* add all range */
      lcrzo_efr(lcrzo_etha_init(0, 0, 0, 0, 0, 0, infetha),
		lcrzo_string_free(ethatext1);lcrzo_string_free(ethatext2)); 
      lcrzo_efr(lcrzo_etha_init(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, supetha),
		lcrzo_string_free(ethatext1);lcrzo_string_free(ethatext2)); 
      lcrzo_efr(lcrzo_ethlist_add_range(plist, infetha, supetha),
		lcrzo_string_free(ethatext1);lcrzo_string_free(ethatext2));
    }
    else if ( ethatext1[0]=='!' )
    { /* remove this range */
      lcrzo_efr(lcrzo_etha_init_ethrange(ethatext1+1, infetha, supetha),
		lcrzo_string_free(ethatext1);lcrzo_string_free(ethatext2));
      lcrzo_efr(lcrzo_ethlist_del_range(plist, infetha, supetha),
		lcrzo_string_free(ethatext1);lcrzo_string_free(ethatext2));
    }
    else
    { /* add this range */
      lcrzo_efr(lcrzo_etha_init_ethrange(ethatext1, infetha, supetha),
		lcrzo_string_free(ethatext1);lcrzo_string_free(ethatext2));
      lcrzo_efr(lcrzo_ethlist_add_range(plist, infetha, supetha),
		lcrzo_string_free(ethatext1);lcrzo_string_free(ethatext2));
    }

    /* get next token */
    lcrzo_string_free(ethatext1);
    ret=lcrzo_string_token_char(ethatext2, LCRZO_FALSE, +1, -1, ',',
				&indic, NULL, &startpos, NULL, &endpos);
  }

  lcrzo_string_free(ethatext2);
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_string_initm_ethlist(lcrzo_list *plist,
			      lcrzo_string *pethatext)
{ lcrzo_int32 count, i;
  lcrzo_ethlist ethlist;
  lcrzo_ethrange range;
  lcrzo_bool firstrange;

  lcrzo_er(lcrzo_list_count(plist, &count));
  lcrzo_er(lcrzo_string_initm_text("", pethatext));
  firstrange=LCRZO_TRUE;
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(plist, i, &ethlist));
    lcrzo_er(lcrzo_ethrange_init_etha(ethlist.inf, ethlist.sup, range));
    if (!firstrange)
    { lcrzo_er(lcrzo_string_appendm_text(",", pethatext)); }
    firstrange=LCRZO_FALSE;
    lcrzo_er(lcrzo_string_appendm_text(range, pethatext)); 
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_ethlist_isinlist(lcrzo_list *plist,
			   lcrzo_etha etha,
			   lcrzo_bool *pyes)
{ lcrzo_int32 count, i;
  lcrzo_ethlist ethlist;

  lcrzo_er(lcrzo_list_count(plist, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(plist, i, &ethlist));
    if ( lcrzo_priv_etha_ge(etha, ethlist.inf) && 
	 lcrzo_priv_etha_le(etha, ethlist.sup) )
    { if (pyes!=NULL) *pyes=LCRZO_TRUE;
      return(LCRZO_ERR_OK);
    }
  }
  if (pyes!=NULL) *pyes=LCRZO_FALSE;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_ethlist_value_first(lcrzo_list *plist,
			      lcrzo_etha etha)
{ lcrzo_int32 count;
  lcrzo_ethlist ethlist;

  lcrzo_er(lcrzo_list_count(plist, &count));
  if (count==0) return(LCRZO_ERR_OKDATAEND);

  lcrzo_er(lcrzo_list_value_first(plist, &ethlist));
  if ( etha!=NULL )
  { memcpy(etha, ethlist.inf, LCRZO_ETHA_MAXBYTES);
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_ethlist_value_next(lcrzo_list *plist,
			    lcrzo_etha etha,
			    lcrzo_etha nextetha)
{ lcrzo_int32 count, i;
  lcrzo_ethlist ethlist;

  lcrzo_er(lcrzo_list_count(plist, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(plist, i, &ethlist));
    if ( lcrzo_priv_etha_lt(etha, ethlist.inf) )
    { if ( nextetha!=NULL )
      { memcpy(nextetha, ethlist.inf, LCRZO_ETHA_MAXBYTES);
      }
      return(LCRZO_ERR_OK);
    }
    if ( lcrzo_priv_etha_ge(etha, ethlist.inf) && 
	 lcrzo_priv_etha_lt(etha, ethlist.sup) )
    { lcrzo_er(lcrzo_priv_etha_inc(etha, nextetha));
      return(LCRZO_ERR_OK);
    }
  }

  return(LCRZO_ERR_OKDATAEND);
}

/*-------------------------------------------------------------*/
int lcrzo_ethlist_init_stdin(lcrzo_conststring message,
			     lcrzo_conststring defaultlist,
			     lcrzo_list *plist)
{ char prompt;
  lcrzo_string usertext;
  lcrzo_bool defautisvalid;
  lcrzo_list tmplist;
  int ret;

  /*parameters verification*/
  defautisvalid=LCRZO_FALSE;
  if (defaultlist!=NULL)
  { if (strlen(defaultlist))
    { ret=lcrzo_ethlist_init_text(defaultlist, &tmplist);
      if (ret==LCRZO_ERR_OK)
      { defautisvalid=LCRZO_TRUE;
        lcrzo_list_close(&tmplist);
      }
    }
  }

  prompt=':';
  while(LCRZO_TRUE)
  { /*affichage du message*/
    if (message!=NULL) if (message[0]!='\0')
    { printf("%s ", message);
      if (defautisvalid) printf("[%s]", defaultlist);
      printf("%c ", prompt);
    }
    prompt='>';
    /*saisie de la chaine de l'utilisateur*/
    lcrzo_er(lcrzo_priv_stdin(&usertext, NULL));
    /*si rien n'a ete entre, on met le defaut*/
    if (strlen(usertext)==0 && defautisvalid)
    { lcrzo_string_free(usertext);
      lcrzo_er(lcrzo_ethlist_init_text(defaultlist, plist));
      /*si les tentatives precedentes etaient en erreur
	on est oblige de mettre a zero ici car on ne
	passe plus dans lcrzo_ipa_init_hs()*/
      lcrzo_err_purge();
      break;
    }
    /*conversion*/
    ret=lcrzo_ethlist_init_text(usertext, plist);
    lcrzo_string_free(usertext);
    lcrzo_err_purge();
    if (ret==LCRZO_ERR_OK) break;
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_iplist_init_stdin(lcrzo_conststring message,
			     lcrzo_conststring defaultlist,
			     lcrzo_list *plist)
{ char prompt;
  lcrzo_string usertext;
  lcrzo_bool defautisvalid;
  lcrzo_list tmplist;
  int ret;

  /*parameters verification*/
  defautisvalid=LCRZO_FALSE;
  if (defaultlist!=NULL)
  { if (strlen(defaultlist))
    { ret=lcrzo_iplist_init_text(defaultlist, &tmplist);
      if (ret==LCRZO_ERR_OK)
      { defautisvalid=LCRZO_TRUE;
        lcrzo_list_close(&tmplist);
      }
    }
  }

  prompt=':';
  while(LCRZO_TRUE)
  { /*affichage du message*/
    if (message!=NULL) if (message[0]!='\0')
    { printf("%s ", message);
      if (defautisvalid) printf("[%s]", defaultlist);
      printf("%c ", prompt);
    }
    prompt='>';
    /*saisie de la chaine de l'utilisateur*/
    lcrzo_er(lcrzo_priv_stdin(&usertext, NULL));
    /*si rien n'a ete entre, on met le defaut*/
    if (strlen(usertext)==0 && defautisvalid)
    { lcrzo_string_free(usertext);
      lcrzo_er(lcrzo_iplist_init_text(defaultlist, plist));
      /*si les tentatives precedentes etaient en erreur
	on est oblige de mettre a zero ici car on ne
	passe plus dans lcrzo_ipa_init_hs()*/
      lcrzo_err_purge();
      break;
    }
    /*conversion*/
    ret=lcrzo_iplist_init_text(usertext, plist);
    lcrzo_string_free(usertext);
    lcrzo_err_purge();
    if (ret==LCRZO_ERR_OK) break;
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_portlist_init_stdin(lcrzo_conststring message,
			     lcrzo_conststring defaultlist,
			     lcrzo_list *plist)
{ char prompt;
  lcrzo_string usertext;
  lcrzo_bool defautisvalid;
  lcrzo_list tmplist;
  int ret;

  /*parameters verification*/
  defautisvalid=LCRZO_FALSE;
  if (defaultlist!=NULL)
  { if (strlen(defaultlist))
    { ret=lcrzo_portlist_init_text(defaultlist, &tmplist);
      if (ret==LCRZO_ERR_OK)
      { defautisvalid=LCRZO_TRUE;
        lcrzo_list_close(&tmplist);
      }
    }
  }

  prompt=':';
  while(LCRZO_TRUE)
  { /*affichage du message*/
    if (message!=NULL) if (message[0]!='\0')
    { printf("%s ", message);
      if (defautisvalid) printf("[%s]", defaultlist);
      printf("%c ", prompt);
    }
    prompt='>';
    /*saisie de la chaine de l'utilisateur*/
    lcrzo_er(lcrzo_priv_stdin(&usertext, NULL));
    /*si rien n'a ete entre, on met le defaut*/
    if (strlen(usertext)==0 && defautisvalid)
    { lcrzo_string_free(usertext);
      lcrzo_er(lcrzo_portlist_init_text(defaultlist, plist));
      /*si les tentatives precedentes etaient en erreur
	on est oblige de mettre a zero ici car on ne
	passe plus dans lcrzo_ipa_init_hs()*/
      lcrzo_err_purge();
      break;
    }
    /*conversion*/
    ret=lcrzo_portlist_init_text(usertext, plist);
    lcrzo_string_free(usertext);
    lcrzo_err_purge();
    if (ret==LCRZO_ERR_OK) break;
  }
  return(LCRZO_ERR_OK);
}


