static char dqs_list_rcsid[]="$Id: dqs_list.c,v 1.1.1.1 1998/08/18 14:39:12 green Exp $";

/*----------------------------------------------------
 * dqs_list.c Tom Green Mon Jan 31 10:42:48 1994
 *
 * Copyright 1993
 *
 * SUPER COMPUTER COMPUTATIONS RESEARCH INSTITUTE
 *            FLORIDA STATE UNIVERSITY
 *
 *
 * SCRI representatives make no claims about the
 * suitability of this software for any purpose.
 * It is provided "as is" without express or
 * implied warranty.
 *
 * $Log: dqs_list.c,v $
 * Revision 1.1.1.1  1998/08/18 14:39:12  green
 * DQS 3.2.0.5 WIP Import
 *
 * Revision 1.4  1998/07/15 17:50:00  hajnal
 * Changed sort_x_seq_no "if" to check
 * sort queues with the same seq_no by their load... 
 *
 * Revision 1.3  1997/10/21 17:08:41  decker
 * Fixed potential Memory error
 *
 * Revision 1.2  1997/04/11 14:42:15  green
 * added Curtis Janssen's patch to dqs_string2list to prevent overrunning
 * the NULL terminator
 *
 * Revision 1.1.1.1  1997/04/10 15:10:32  green
 * DQS 3.1.3.4.1 Distribution
 *
 * Revision 3.18  1996/11/20 23:03:53  nrl
 * Several fixes submitted by or as a result of investigations by
 * Ron Lee, Bodo Bechenback, Guntram Wolski and Frank Dwyyer.
 *
 * Revision 3.17  1996/03/22  04:20:37  nrl
 * Added error cataloguing number to all routines
 *
 * Revision 3.16  1996/03/12  17:12:10  nrl
 * removed aborts and replaced with an error messaging scheme
 * to send email to the dqs adminsitrator and wait for
 * actions by that administrator
 *
 * Revision 3.15  1995/05/14  18:28:51  nrl
 * Plugged one hole in dqs_execd and qmaster handhsaking...
 * added gethostbyname calls to overcome problems with some
 * systems
 *
 * Revision 3.14  1995/03/05  03:47:16  nrl
 * Included Axel Brandes job scheduling mechanism to keep one
 * user from hawging the queue.
 *
 * Revision 3.13  1995/03/01  20:52:54  nrl
 * Added dqs_delete_int0 function and corections to the interrupt
 * handler to remove stale entries from the Chil Head. This fixes the
 * intermittent problems with queue stalls.
 *
 * Revision 3.12  1995/02/23  23:13:51  nrl
 * Cleaned up some dangling pointers which were causing memory
 * corruption.
 *
 * Revision 3.11  1995/02/22  14:29:29  nrl
 * added "FREE" macro to make sure all freed pointers are NULL,
 * replaced all calls to free( ) with FREE.
 *
 * Revision 3.10  1995/02/09  12:49:09  nrl
 * Added "delete complex" and "modify complex"
 *
 * Revision 3.9  1995/02/01  23:17:33  nrl
 * Tidied up and hopefully bulletproofed "tid" management. Reversed
 * tid file naming to sort by time.
 *
 * Revision 3.8  1994/06/23  20:01:40  green
 * Solaris porting mods...
 *
 * Revision 3.7  1994/06/19  14:12:17  green
 * dqs_string2list() should now dijest quotes, """, correctly
 *
 * Revision 3.6  1994/06/18  13:59:18  green
 * cleaned up syntax bug made in last checkin
 *
 * Revision 3.5  1994/06/17  17:35:34  green
 * added check for a null string being passed into dqs_string_to_list()
 *
 * Revision 3.4  1994/06/03  03:44:03  green
 * updated to support p4/mpi
 *
 * Revision 3.3  1994/03/27  05:59:45  green
 * def.h:UNPACKSTR() modified to force a NULL as realloc() doesn't
 * necessarily return clean memory
 *
 * dqs_list.c:dqs_insert(TAIL) had a bug wheninserting to a NULL head
 *
 * may "Last Minute Hack" to dqs_list.c:dqs_showlist() really screwed up
 * some things - yanked...
 *
 * Revision 3.2  1994/03/26  19:58:20  green
 * bug in dqs_list.c:dqs_insert() caused sorts based on the DQS_INT2
 * field to be done incorrectly.
 *
 * Revision 3.1  1994/03/23  15:59:59  green
 * forgot a bang, "!", in dqs_list.c:dqs_sort_queue() causing it to
 * always sort by seq_no.
 *
 * Revision 3.0  1994/03/07  04:13:59  green
 * 3.0 freeze
 *
 * Revision 1.4  1994/03/04  20:07:38  green
 * modified dqs_showlist() to handle NULLs - more gracefully.
 *
 * added a warning for "unknown" requests in dqs_parse.c - this should
 * probably be an exit - but as the code is being relased in 2 days,
 * scared I might break more than I fix....
 *
 * fixed qconf so it no longer drops core if no options.
 *
 * Revision 1.3  1994/02/25  02:54:34  green
 * modified dqs_add_del.c to correct job ordering problem
 *
 * modified dqs_list.c to support ASCENDING on DQS_INT2 DQS_INT3
 *
 * modified dqs_load_avg.c in an attempt to fix CDs on VAX Ultrix -
 * by commenting out the offending code - this needs to be fixed...
 *
 * Revision 1.2  1994/02/02  20:22:10  green
 * cleaned up "qconf.c" to sync with docs
 *
 * Revision 1.1.1.1  1994/02/01  17:57:42  green
 * DQS 3.0 ALPHA
 *
 *--------------------------------------------------*/


#include "h.h"
#include "def.h"
#include "dqs.h"
#include "struct.h"
#include "func.h"
#include "globals.h"
#include "dqs_errno.h"

/**********************************************************************/
dqs_list_type *dqs_args2list(argv, argc)
     char **argv; /* arg list */
     int argc;    /* number of args */               
     
     /*
       dqs_args2list - converts an argument list to linked list
     */
     
{
  
  dqs_list_type *head;               
  
  DENTER_EXT((DQS_EVENT,"dqs_args2list"));
  
  if (!argc) 
    {
      DEXIT;
      return ((dqs_list_type *)NULL);
    }
  
  if (!argv[0]) {
    DEXIT;
    return ((dqs_list_type *)NULL);
  }
  
  if (argv[0][0] == '\0') {
    DEXIT;
    return ((dqs_list_type *)NULL);
  }
  
  /* Copy next argument to dynamic storage */
  head=(dqs_list_type *)dqs_malloc(sizeof(dqs_list_type));
  head->str0=dqs_string_insert(head->str0,argv[0]);
  DPRINTF((DQS_EVENT,"Inserted \">%s<\"",argv[0]));
  /* Put next argument onto list */
  head->next=dqs_args2list(++argv,--argc);
  DEXIT;
  return (head);
  
} /* dqs_args2list */

/**********************************************************************/
char *dqs_string_insert(old_pointer,str)
     char *old_pointer;
     char *str;
     
     /*
       dqs_string_insert - insert a string on a pointer
       mallocs necessary memory
       
       if (old_pointer) free old_pointer
       
       returns :
       pointer to freshly malloced memory
       
     */
     
{
  
  int i;
  
  DENTER_EXT((DQS_EVENT,"dqs_string_insert"));
  
  FREE(old_pointer);
  
  if (!str)
    {
      DEXIT;
      return(NULL);
    }
  
  i=strlen(str);
  if (i>=MAX_STRING_SIZE) {
    CRITICAL((DQS_EVENT,"DQS_ERROR_0270 string too long\"%s\"",str));
    DEXITE;
    return NULL;
  }
  
  if (i) {
    /*Code via Doug Gibson*/
    old_pointer=dqs_malloc(MAX_STRING_SIZE);
    DQS_ASSERT((strcpy(old_pointer,str)!=NULL));
  }
  else
    old_pointer=NULL;
  
  DEXIT;
  return(old_pointer);
  
} /* dqs_string_insert */

/**********************************************************************/
dqs_list_type *dqs_delete_head(head)
     dqs_list_type *head; /* old head */
     
     /*
       dqs_delete_head - deletes first entry in linked list
     */
     
{
  
  dqs_list_type *sp;
  
  DENTER_EXT((DQS_EVENT,"dqs_delete_head"));
  
  if (head==(dqs_list_type *)NULL) {
    DEXIT;
    return((dqs_list_type *)NULL);
  }
  
  sp=head->next;
  head->next=NULL;
  dqs_free_list(head);
  
  DEXIT;
  return (sp);
  
} /* dqs_delete_head */

/**********************************************************************/
dqs_list_type *dqs_del_str0(head,str)
     dqs_list_type *head;
     char *str;
     
     /*
       dqs_del_str0 - delete list entry based on str0 field
     */
     
{
  
  dqs_list_type *freeptr;
  dqs_list_type *tmp;
  dqs_list_type *err_rpt;
  
  DENTER_EXT((DQS_EVENT,"dqs_del_str0"));
  
  if (!head)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0271 error: NULL head passed in"));
      DEXIT;
      return(NULL);
    }
  if (!head->str0)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0272 error: NULL head->str0 passed in"));
      DEXIT;
      return(NULL);
    }
  
  if (!strcmp(head->str0,str))
    {
      freeptr=head;
      head=head->next;
      freeptr->next=NULL;
      freeptr=dqs_free_list(freeptr);
      DEXIT;
      return(head);
    }
  
  tmp=head;
  while(tmp->next)
    {
      if (!tmp->next->str0)
	{
	  CRITICAL((DQS_EVENT,"DQS_ERROR_0273 error: list screwed"));
	  DEXITE;
	  if(me.who==DQS_EXECD){
	    err_rpt=(dqs_list_type *)dqs_malloc(sizeof(dqs_list_type));
	    bzero(&err_rpt,sizeof(err_rpt));
	    err_rpt->chain= head;
	    err_rpt->str1= dqs_string_insert(NULL,
					     " dqs delstr list is screwed");
	    dqs_report_problem(err_rpt, TRUE);      
	  }
	  abort();
	}
      
      if (!dqs_strcasecmp(tmp->next->str0,str))
	{
	  freeptr=tmp->next;
	  tmp->next=tmp->next->next;
	  freeptr->next=NULL;
	  freeptr=dqs_free_list(freeptr);
	  DEXIT;
	  return(head);
	}
      tmp=tmp->next;
    }
  
  DEXITE;
  return(head);
  
} /* dqs_del_str0 */

/**********************************************************************/
dqs_list_type *dqs_del_int0(head,int0)
     dqs_list_type *head;
     int int0;
     
     /*
       dqs_del_str0 - delete list entry based on str0 field
     */
     
{
  
  dqs_list_type *freeptr;
  dqs_list_type *tmp;
  
  DENTER((DQS_EVENT,"dqs_del_int0"));
  
  if (!head)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0274 error: NULL head passed in"));
      DEXIT;
      return(NULL);
    }
  
  if (head->int0== int0)
    {
      freeptr=head;
      head=head->next;
      freeptr->next=NULL;
      freeptr=dqs_free_list(freeptr);
      DEXIT;
      return(head);
    }
  
  tmp=head;
  while(tmp->next)
    {
      if (tmp->next->int0== int0)
	{
	  freeptr=tmp->next;
	  tmp->next=tmp->next->next;
	  freeptr->next=NULL;
	  freeptr=dqs_free_list(freeptr);
	  DEXIT;
	  return(head);
	}
      tmp=tmp->next;
    }
  
  DEXITE;
  return(head);
  
} /* dqs_del_int0 */

/**********************************************************************/
dqs_list_type *dqs_insert(field, direction, head, element)
     u_long32 field;
     int direction;
     dqs_list_type *head;
     dqs_list_type *element;
     
     /*
       dqs_insert - insert entry into linked list.
       
       entry: field     = TYPE, pick insertion point based on type field
       = INT0, pick insertion point based on int0 field
       = INT1, pick insertion point based on int1 field
       = INT2, pick insertion point based on int2 field
       = STR0, pick insertion point based on str0 field
       = STR0, pick insertion point based on str1 field
       direction = HEAD, insert entry at list head
       = TAIL, insert entry at list tail
       = ASCENDING, do ascending order insertion
       = DESCENDING, do descending order insertion
       head      = pointer to list head
       element   = pointer to new list entry
       exit:       returns pointer to (updated) list head
       
     */
     
{
  
  dqs_list_type *hp;         /* pointer to entry at list head */
  dqs_list_type *lp = NULL;  /* pointer to previous list entry */
  dqs_list_type *op;         /* pointer to old list entry */
  int rc;                            /* result of comparison */
  dqs_list_type *sp;         /* pointer to new list entry */
  dqs_list_type *err_rpt;
  
  DENTER_EXT((DQS_EVENT,"dqs_insert"));
  
  /* Copy entry into dynamic storage */
  sp = (dqs_list_type *)dqs_malloc (sizeof(dqs_list_type));
  
  bcopy ((char *)element, (char *)sp, sizeof(dqs_list_type));
  
  sp->next = (dqs_list_type *)NULL;
  
  /* Check list head */
  if (head == (dqs_list_type *)NULL) {
    DEXIT;
    return (sp);
  } /* if */
  
  /* Dispatch to ordered insertion handler */
  switch (direction) {
    
  case HEAD:                      /* insert at list head */
    sp->next = head;
    head = sp;
    DEXIT;
    return (head);
    
  case TAIL:                      /* insert at list tail */
    if (!head)
      {
	DEXIT;
	return(sp);
      }
    
    lp = head;
    
    while (lp->next)
      lp = lp->next;
    
    lp->next = sp;
    DEXIT;
    return (head);
    
  case ASCENDING:                 /* insert in ascending order */
    hp = head;
    op = (dqs_list_type *)NULL;
    while (head != (dqs_list_type *)NULL) {
      
      /* Dispatch to comparator */
      switch (field) {
	
      case DQS_TYPE:              /* compare on type field */
	rc = (head->type < sp->type);
	break;
	
      case DQS_INT0:              /* compare on int0 field */
	rc = (head->int0 < sp->int0);
	break;
	
      case DQS_INT1:              /* compare on int1 field */
	rc = (head->int1 < sp->int1);
	break;
	
      case DQS_INT2:              /* compare on int2 field */
	rc = (head->int2 < sp->int2);
	break;
	
      case DQS_INT3:              /* compare on int3 field */
	rc = (head->int3 < sp->int3);
	break;
	
      case DQS_STR0:              /* compare on str0 field */
	rc = (strcmp(head->str0, sp->str0) < 0);
	break;
	
      case DQS_STR1:          /* compare on str1 field */
	rc = (strcmp(head->str1, sp->str1) < 0);
	break;
	
      case DQS_STR2:          /* compare on str1 field */
	rc = (strcmp(head->str2, sp->str2) < 0);
	break;
	
      case DQS_STR3:          /* compare on str1 field */
	rc = (strcmp(head->str3, sp->str3) < 0);
	break;
	
      } /* switch */
      lp = head;
      if (rc) {
	op = head;
	head = head->next;
      } else {
	if (op != (dqs_list_type *)NULL) {
	  op->next = sp;
	  sp->next = head;
	  DEXIT;
	  return (hp);
	} /* if */
	sp->next = head;
	DEXIT;
	return (sp);
      } /* if */
      
    } /* while */
    break;
    
  case DESCENDING:                /* insert in descending order */
    hp = head;
    op = (dqs_list_type *)NULL;
    while (head != (dqs_list_type *)NULL) {
      
      /* Dispatch to comparator */
      switch (field) {
	
      case DQS_TYPE:                /* compare on type field */
	rc = (head->type > sp->type);
	break;
	
      case DQS_INT0:                /* compare on int0 field */
	rc = (head->int0 > sp->int0);
	break;
	
      case DQS_INT1:              /* compare on int1 field */
	rc = (head->int1 > sp->int1);
	break;
	
      case DQS_INT2:                /* compare on int2 field */
	rc = (head->int2 > sp->int2);
	break;
	
      case DQS_INT3:              /* compare on int3 field */
	rc = (head->int3 > sp->int3);
	break;
	
      case DQS_STR0:                /* compare on str0 field */
	rc = (strcmp(head->str0, sp->str0) > 0);
	break;
	
      case DQS_STR1:              /* compare on str1 field */
	rc = (strcmp(head->str1,sp->str1) > 0);
	break;
	
      case DQS_STR2:                /* compare on str2 field */
	rc = (strcmp(head->str2, sp->str2) > 0);
	break;
	
      case DQS_STR3:              /* compare on str3 field */
	rc = (strcmp(head->str3,sp->str3) > 0);
	break;
	
      } /* switch */
      lp = head;
      if (rc) {
	op = head;
	head = head->next;
      } else {
	if (op != (dqs_list_type *)NULL) {
	  op->next = sp;
	  sp->next = head;
	  DEXIT;
	  return (hp);
	} /* if */
	sp->next = head;
	DEXIT;
	return (sp);
      } /* if */
      
    } /* while */
    break;
    
  default:
    CRITICAL((DQS_EVENT,"DQS_ERROR_0275 unknown insertion ordering in insert"));
    if(me.who==DQS_EXECD){
      err_rpt=(dqs_list_type *)dqs_malloc(sizeof(dqs_list_type));
      bzero(&err_rpt,sizeof(err_rpt));
      err_rpt->chain= head;
      err_rpt->str1= dqs_string_insert(NULL,
				       " unknown insertion ordering in insert");
      dqs_report_problem(err_rpt, TRUE);      
    }          
    abort();
    
  } /* switch */
  
  lp->next = sp;
  DEXIT;
  return (hp);
  
} /* dqs_insert */

/**********************************************************************/
dqs_list_type *dqs_locate_int0(head,int0)
     dqs_list_type *head;
     u_long32         int0;
     
     /*
       dqs_locate_int0 - locate list entry by int0 field
     */
     
{
  
  dqs_list_type *sp;               /* pointer to simple list entry */
  
  DENTER_EXT((DQS_EVENT,"dqs_locate_int0"));
  
  sp=head;
  
  while (sp != (dqs_list_type *)NULL) {
    if (sp->int0==int0) {
      DEXIT;
      return(sp);
    }
    sp=sp->next;
  }
  
  DEXIT;
  return((dqs_list_type *)NULL);
  
} /* dqs_locate_int0 */

/**********************************************************************/
dqs_list_type *dqs_locate_str0(head,str0)
     dqs_list_type *head;
     char             *str0;
     
     /*
       dqs_locate_str0 - locate list entry by str0 field
     */
     
{
  
  dqs_list_type *sp;               /* pointer to simple list entry */
  
  DENTER_EXT((DQS_EVENT,"dqs_locate_str0"));
  
  sp=head;
  
  while (sp) 
    {
      if (!strcmp(sp->str0,str0)) {
	DEXIT;
	return(sp);
      }
      sp=sp->next;
    }
  
  DEXIT;
  return((dqs_list_type *)NULL);
  
} /* dqs_locate_str0 */

/**********************************************************************/
void dqs_showlist(head,how,indent)
     dqs_list_type *head;
     int how;
     int indent;
     
     /*
       dqs_showlist - show linked list
       
       head    *dqs_list_type
       how     DQS_STDOUT|DQS_STDERR|DQS_STDERR|DQS_DEBUG
       DQS_TYPE|DQS_INT0|DQS_INT1|DQS_INT2|DQS_INT3
       DQS_STR0|DQS_STR1|DQS_STR2|DQS_STR3|DQS_CHAIN
       indent  how much to indent
     */
     
{
  
  int           i;
  string        str;
  string        indent_str;
  string        long_str;
  dqs_list_type *sp = head;       /* pointer to simple list entry */
  
  /* !!!DO NOT DENTER_EXT!!! */
  DENTER((DQS_EVENT,"dqs_showlist"));
  
  if (head == (dqs_list_type *)NULL) {
    DEXIT;
    return;
  } /* if */
  
  bzero(indent_str,sizeof(indent_str));
  for (i=0;i<indent;i++)
    strcat(indent_str," ");
  
  /* Traverse linked list */
  while (sp != (dqs_list_type *)NULL) {
    
    if (VALID(DQS_STDOUT,how)) {
      printf("%s",indent_str);
      if (VALID(DQS_TYPE,how))
	printf("%u\t",sp->type);
      if ((VALID(DQS_STR0,how))&&(sp->str0))
	printf("%s\t",sp->str0);
      if ((VALID(DQS_STR1,how))&&(sp->str1))
	printf("%s\t",sp->str1);
      if ((VALID(DQS_STR2,how))&&(sp->str2))
	printf("%s\t",sp->str2);
      if ((VALID(DQS_STR3,how))&&(sp->str3))
	printf("%s\t",sp->str3);
      if (VALID(DQS_INT0,how))
	printf("%u\t",sp->int0);
      if (VALID(DQS_INT1,how))
	printf("%u\t",sp->int1);
      if (VALID(DQS_INT2,how))
	printf("%u\t",sp->int2);
      if (VALID(DQS_INT3,how))
	printf("%u\t",sp->int3);
      printf("\n");
      fflush(stdout);
    }
    
    if (VALID(DQS_STDERR,how)) {
      fprintf(stderr,"%s",indent_str);
      if (VALID(DQS_TYPE,how))
	fprintf(stderr,"%u\t",sp->type);
      if ((VALID(DQS_STR0,how))&&(sp->str0))
	fprintf(stderr,"%s\t",sp->str0);
      if ((VALID(DQS_STR1,how))&&(sp->str1))
	fprintf(stderr,"%s\t",sp->str1);
      if ((VALID(DQS_STR2,how))&&(sp->str2))
	fprintf(stderr,"%s\t",sp->str2);
      if ((VALID(DQS_STR3,how))&&(sp->str3))
	fprintf(stderr,"%s\t",sp->str3);
      if (VALID(DQS_INT0,how))
	fprintf(stderr,"%u\t",sp->int0);
      if (VALID(DQS_INT1,how))
	fprintf(stderr,"%u\t",sp->int1);
      if (VALID(DQS_INT2,how))
	fprintf(stderr,"%u\t",sp->int2);
      if (VALID(DQS_INT3,how))
	fprintf(stderr,"%u\t",sp->int3);
      fprintf(stderr,"\n");
      fflush(stderr);
    }
    
    if (VALID(DQS_DEBUG,how)) {
      bzero(long_str,sizeof(long_str));
      strcat(long_str,indent_str);
      if (VALID(DQS_TYPE,how)) {
	bzero(str,sizeof(str));
	sprintf(str,"%u\t",sp->type);
	strcat(long_str,str);
      }
      if ((VALID(DQS_STR0,how))&&(sp->str0)) {
	bzero(str,sizeof(str));
	sprintf(str,"%s\t",sp->str0);
	strcat(long_str,str);
      }
      if ((VALID(DQS_STR1,how))&&(sp->str1)) {
	bzero(str,sizeof(str));
	sprintf(str,"%s\t",sp->str1);
	strcat(long_str,str);
      }
      if ((VALID(DQS_STR2,how))&&(sp->str2)) {
	bzero(str,sizeof(str));
	sprintf(str,"%s\t",sp->str2);
	strcat(long_str,str);
      }
      if ((VALID(DQS_STR3,how))&&(sp->str3)) {
	bzero(str,sizeof(str));
	sprintf(str,"%s\t",sp->str3);
	strcat(long_str,str);
      }
      if (VALID(DQS_INT0,how)) {
	bzero(str,sizeof(str));
	sprintf(str,"%u\t",sp->int0);
	strcat(long_str,str);
      }
      if (VALID(DQS_INT1,how)) {
	bzero(str,sizeof(str));
	sprintf(str,"%u\t",sp->int1);
	strcat(long_str,str);
      }
      if (VALID(DQS_INT2,how)) {
	bzero(str,sizeof(str));
	sprintf(str,"%u\t",sp->int2);
	strcat(long_str,str);
      }
      if (VALID(DQS_INT3,how)) {
	bzero(str,sizeof(str));
	sprintf(str,"%u\t",sp->int3);
	strcat(long_str,str);
      }
      if (long_str[0]) 
	{
	  DPRINTF((DQS_EVENT,"%s",long_str));
	}
      
    }
    if (VALID(DQS_CHAIN,how))
      {
	if (sp->chain)
	  {
	    dqs_showlist(sp->chain,how,indent+indent);
	  }
      }
    
    sp = sp->next;
  } /* while */
  
  DEXIT;
  return;
  
} /* dqs_showlist */

/************************************************************************/
dqs_list_type *dqs_sort_queues(head)
     dqs_list_type *head;           
     
     /*
       dqs_sort_queues - sorts queues based on scheduling policy
     */
     
{
  
  dqs_list_type *travptr;
  dqs_list_type *newhead=NULL;
  dqs_list_type *insertsort();
  
  DENTER((DQS_EVENT,"dqs_sort_queues"));
  
  /* hajnal: this is removed. QUEUES WITH SAME SEQUENCE NO.
   *         need also be sorted by load!
   if (conf.sort_seq_no) 
   {
   if (sorted)
   {
   DEXIT;
   return(head);
   }
   else
   {
   sorted=TRUE;
   }
   }
  */
  
  for (travptr=head;travptr;head=travptr) 
    {
      travptr=travptr->next;
      if (!conf.sort_seq_no)
	newhead=dqs_insert_sort_queue_x_load(head,newhead);
      else
	newhead=dqs_insert_sort_queue_x_seq_no(head,newhead);
    } 
  
  DEXIT;
  return(newhead);
  
} /* dqs_sort_queues */

/************************************************************************/
dqs_list_type *dqs_insert_sort_queue_x_load(element,head)
     dqs_list_type *element;
     dqs_list_type *head;
     
     /*
       dqs_insert_sort_queue_x_load - used by dqs_sort_queues()
     */
     
{
  dqs_list_type *travptr;
  dqs_list_type *prevptr=NULL;
  
  DENTER((DQS_EVENT,"dqs_insert_sort_queue_x_load"));
  
  if (!head) 
    {
      head=element;
      head->next=NULL;
    }
  else 
    {
      for(travptr=head;travptr;travptr=travptr->next) 
	{
	  if ((*element->queue->load_avg_ptr*element->queue->load_massage) <=
	      (*travptr->queue->load_avg_ptr*travptr->queue->load_massage)) 
	    { /* Insert in middle of list */
	      if (prevptr) 
		{
		  element->next=prevptr->next;
		  prevptr->next=element;
		}
	      else
		{ /* Insert at the beginning */
		  element->next=head;
		  head=element;
		}
	      break;
	    }
	  prevptr=travptr;
	}
      if (!travptr) 
	{ /* Insert at the end */
	  element->next=NULL;
	  prevptr->next=element;
	}
    }
  
  DEXIT;
  return(head);
  
} /* dqs_insert_sort_queue_x_load */

/************************************************************************/
dqs_list_type *dqs_insert_sort_queue_x_seq_no(element,head)
     dqs_list_type *element;
     dqs_list_type *head;
     
     /*
       dqs_insert_sort_queue_x_seq_no - used by dqs_sort_queues()
     */
     
{
  dqs_list_type *travptr;
  dqs_list_type *prevptr=NULL;
  
  DENTER((DQS_EVENT,"dqs_insert_sort_queue_x_seq_no"));
  
  if (!head)
    {
      head=element;
      head->next=NULL;
    }
  else
    {
      for(travptr=head;travptr;travptr=travptr->next)
	{
	  /* hajnal: it was the original "if"
	     if ((element->queue->seq_no)<=(travptr->queue->seq_no))
	  */
	  if ( ((element->queue->seq_no) < (travptr->queue->seq_no)) ||
	       ( ((element->queue->seq_no)==(travptr->queue->seq_no)) &&
		 ((*element->queue->load_avg_ptr*element->queue->load_massage) <=
		  (*travptr->queue->load_avg_ptr*travptr->queue->load_massage))
		 )
	       )
	    { /* Insert in middle of list */
	      if (prevptr)
		{
		  element->next=prevptr->next;
		  prevptr->next=element;
		}
	      else
		{ /* Insert at the beginning */
		  element->next=head;
		  head=element;
		}
	      break;
	    }
	  prevptr=travptr;
	}
      if (!travptr)
	{ /* Insert at the end */
	  element->next=NULL;
	  prevptr->next=element;
	}
    }
  
  DEXIT;
  return(head);
  
}

/************************************************************************/
dqs_list_type *dqs_string2list(str)
     char *str;      
     
     /*
       dqs_string2list - converts a string to a list using whitespaces as IFS
     */
     
{
  
  int           i                 = 0;
  int           is_space          = FALSE;
  int           found_first_quote = FALSE;
  dqs_list_type *head;
  
  DENTER((DQS_EVENT,"dqs_sctring2list"));
  
  if (!str)
    {
      DEXITE;
      return((dqs_list_type *)NULL);
    }
  
  if (strlen(str)>=(MAX_STRING_SIZE-1))
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0276 string >%s< - too long",str));
      DEXITE;
      return((dqs_list_type *)NULL);
    }
  
  /* Skip linear white space */
  while (isspace (str[0])) str++;
  if (str[0] == '\0') {
    DEXIT;
    return ((dqs_list_type *)NULL);
  }
  
  /* Copy token into dynamic storage */
  head=(dqs_list_type *)dqs_malloc(sizeof(dqs_list_type));
  
  bzero ((char *)head, sizeof(dqs_list_type));
  head->str0=dqs_malloc(MAX_STRING_SIZE);/* yup, breaking a rule here */
  
  while ((str[i]) && (!is_space)) {
    if (str[i]=='"') found_first_quote=TRUE;
    head->str0[i] = str[i];
    i++;
    if (found_first_quote)
      is_space=FALSE;
    else
      is_space=isspace(str[i]);
    if ((found_first_quote) && (str[i]=='"'))
      found_first_quote=FALSE;
  } /* while */
  head->str0[i] = '\0';
  str += i;
  
  /* Process next token from string buffer */
  head->type=DQS_STR0;
  head->next=dqs_string2list (str);
  
  DEXIT;
  return (head);
  
} /* string2list */

/************************************************************************/
void dqs_show_acknak_list(head)
     dqs_list_type *head;
     
     /*
       dqs_show_acknak_list - displays ACK/NAK messages
     */
     
{
  
  DENTER_EXT((DQS_EVENT,"dqs_show_acknak_list"));
  
  while (head)
    {
      fflush(stdout);
      fflush(stderr);
      
      if (head->int0=DQS_ACK)
	{
	  if (head->str0)
	    fprintf(stdout,"%s\n",head->str0);
	  fflush(stdout);
	  dqs_showlist(head->chain,DQS_STDOUT|DQS_STR0|DQS_STR1|DQS_INT0|DQS_QUEUE|DQS_CHAIN,8);
	}
      else
	{
	  if (head->str0)
	    fprintf(stderr,"%s\n",head->str0);
	  fflush(stderr);
	  dqs_showlist(head->chain,DQS_STDERR|DQS_STR0|DQS_STR1|DQS_INT0|DQS_QUEUE|DQS_CHAIN,8);
	}
      
      if (head->queue)
	{
	  dqs_write_qconf(TRUE,NULL,NULL,head->queue);
	}
      
      if (head->conf)
	{
	  dqs_write_conf_file(TRUE,head->conf);
	}
      
      head=head->next;
    }
  
  DEXIT;
  return;
  
} /* dqs_show_acknak_list */

/*****************************************************************/
void dqs_write_list_to_disk(file_prefix,file_name,list_head,qty)
     char          *file_prefix;
     char          *file_name;
     dqs_list_type *list_head;
     int           qty;
     
     /*
       dqs_write_list_to_disk - writes up to "qty" elements to disk
       "file_prefix" is optional
       
       tpg
     */
     
{
  /*??? NC need to add transaction locking */
  
  PACK_MACRO_DEFS;
  
  string file;
  struct stat statbuf;
  char   *buf_ptr=NULL;
  char   *cur_buf_ptr=NULL;
  dqs_list_type *err_rpt;
  int    bytes_packed=0;
  int    mem_size=0;
  int    nibbles=0;
  int    fd;
  int    total_bytes_packed=0;
  
  DENTER_EXT((DQS_EVENT,"dqs_write_list_to_disk"));
  
  dqs_pack_list(&buf_ptr,&cur_buf_ptr,list_head,&bytes_packed,&mem_size,qty);
  nibbles=NIBBLE_SIZE(bytes_packed);
  dqs_pack_header(buf_ptr,nibbles,bytes_packed);
  
  if (file_prefix)
    {
      sprintf(file,"%s/%s",file_prefix,file_name);
    }
  else
    {
      sprintf(file,"%s",file_name);
    }
  
  if (stat(file,&statbuf))
    {
      close(creat(file,0755));
    }
  
  close(creat(file,0755));
  
  if ((fd=open(file,O_WRONLY))<0)
    {
      CRITICAL((DQS_EVENT,"DQS_ERROR_0277 can't open %s for writing",file));
      abort();
    }
  
  if (dqs_writenbytes(fd,buf_ptr,nibbles)!=nibbles)
    {
      CRITICAL((DQS_EVENT,"DQS_ERROR_0278 error writting %s in dqs_write_list_to_disk()",file));
      if(me.who==DQS_EXECD){
	err_rpt=(dqs_list_type *)dqs_malloc(sizeof(dqs_list_type));
	bzero(&err_rpt,sizeof(err_rpt));
	err_rpt->chain= list_head;
	err_rpt->str1= dqs_string_insert(NULL,
					 " error writing list to disk");
	dqs_report_problem(err_rpt, TRUE);      
      }
      abort();
    }
  
  close(fd);
  
  FREE(buf_ptr);
  
  DEXIT;
  
  return;
  
} /* dqs_write_list_to_disk */

/*****************************************************************/
void dqs_write_queue_to_disk(queue)
     dqs_queue_type *queue;
     
     /*
       dqs_write_queue_to_disk - writes dqs_queue_type to disk
     */
     
{
  
  dqs_list_type listel;
  
  DENTER((DQS_EVENT,"dqs_write_queue_to_disk"));
  
  bzero(&listel,sizeof(listel));
  listel.str0=queue->qname;
  listel.queue=queue;
  dqs_write_list_to_disk(QUEUE_DIR,listel.str0,&listel,1);
  
  DEXIT;
  
}

/*****************************************************************/
void dqs_write_job_to_disk(job)
     dqs_job_type *job;
     
     /*
       dqs_write_job_to_disk - writes dqs_job_type to disk
     */
     
{
  
  dqs_list_type listel;
  
  DENTER((DQS_EVENT,"dqs_write_job_to_disk"));
  
  bzero(&listel,sizeof(listel));
  listel.job=job;
  listel.str0=job->dqs_job_name;
  dqs_write_list_to_disk(JOB_DIR,listel.str0,&listel,1);
  
  DEXIT;
  
}

/*****************************************************************/
dqs_list_type *dqs_read_list_from_disk(file_prefix,file_name)
     char *file_prefix;
     char *file_name;
     
     /*
       dqs_read_list_from_disk - reads a dqs_list_type from disk.
       
       follows chains as necessary.
       
       returns bytes written
       returns (-1) on error
     */
     
{
  
  int fd;
  int mem_size=0;
  int bytes_written;
  char *buf_ptr=NULL;
  char *cur_ptr=NULL;
  int bytes_packed=OFFSET;
  int bytes_unpacked=0;
  int bytes_packed2disk=0;
  string file;
  dqs_list_type *head=NULL;
  dqs_list_type listel;
  
  DENTER_EXT((DQS_EVENT,"dqs_read_list_from_disk"));
  
  if (file_prefix)
    {
      sprintf(file,"%s/%s",file_prefix,file_name);
    }
  else
    {
      sprintf(file,"%s",file_name);
    }
  
  if ((fd=open(file,O_RDONLY))<0)
    {
      DPRINTF((DQS_EVENT,"can't open %s for reading",file));
      DEXITE;
      return(NULL);
    }
  
  buf_ptr=dqs_malloc(OFFSET);
  if (dqs_readnbytes(fd,buf_ptr,OFFSET)!=OFFSET)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0279 error reading %s",file));
      close(fd);
      FREE(buf_ptr);
      DEXITE;
      return(NULL);
    }
  
  dqs_unpack_header(buf_ptr,&mem_size,&bytes_packed2disk);
  DPRINTF((DQS_EVENT,"========>mem_size %d bytes_packed2disk %d",mem_size,bytes_packed2disk));
  
  buf_ptr=dqs_realloc(buf_ptr,mem_size);
  cur_ptr=buf_ptr;
  cur_ptr+=OFFSET;
  bytes_unpacked=OFFSET;
  
  if (dqs_readnbytes(fd,cur_ptr,mem_size-OFFSET)!=mem_size-OFFSET)
    {
      CRITICAL((DQS_EVENT,"DQS_ERROR_0280 error reading %s",file));
      close(fd);
      FREE(buf_ptr);
      DEXITE;
      return(NULL);
    }
  
  close(fd);
  head=dqs_unpack_list(buf_ptr,&cur_ptr,&bytes_unpacked,bytes_packed2disk);
  DPRINTF((DQS_EVENT,"%d bytes_unpacked   %d bytes_packed2disk",bytes_unpacked,bytes_packed2disk));
  
  FREE(buf_ptr);
  
  DEXIT;
  return(head);
  
} /* dqs_read_list_from_disk */

/************************************************************************/
int dqs_length_of_list(head)
     dqs_list_type *head;              
     
     /*
       dqs_length_of_list - compute number of entries on linked list
     */
     
{
  
  int count = 0;                     /* count of entries on list */
  dqs_list_type *sp = head;        /* pointer to simple list entry */
  
  DENTER_EXT((DQS_EVENT,"dqs_length_of_list"));
  
  /* Traverse linked list and display contents to stdout */
  while (sp != (dqs_list_type *)NULL) {
    count++;
    sp = sp->next;
  } /* while */
  
  DEXIT;
  return (count);
  
} /* length_of_list */

/************************************************************************/
void dqs_update_queue_state()
     
     /*
       dqs_update_queue_state - update the queues state based on lt_heard_from
     */
     
{
  
  u_long32      now;
  dqs_list_type *lp;
  
  DENTER_EXT((DQS_EVENT,"dqs_update_queue_state"));
  
  now=dqs_get_gmt();
  
  lp=Queue_head;
  while (lp)
    {
      if (now > *lp->queue->lt_heard_from_ptr+conf.max_unheard)
	{
	  SETBIT(UNKNOWN,lp->queue->state);
	}
      else
	{
	  CLEARBIT(UNKNOWN,lp->queue->state);
	}
      lp=lp->next;
    }
  
  DEXIT;
  return;
  
} /* dqs_update_queue_state */

