static char dqs_list_rcsid[]="$Id: dqs_list.c,v 1.2 1997/04/11 14:42:15 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.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) {
          old_pointer=dqs_malloc(i+1);
          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"));

     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)
          {
               if ((element->queue->seq_no)<=(travptr->queue->seq_no))
               { /* 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 */

