/****************************************************************************
**
**  Name:  listw.c
**
**  Description:
**     Routines to access generic linked list data structure.
**
**  Status:  PRELIMINARY
**
**  $Log:   S:/tbird/mt2_186/sds/listw.c_v  $
** 
**    Rev 1.0   16 Dec 1996 13:46:04   Judy
** Initial revision.
** 
**    Rev 1.0   27 Aug 1996 15:12:10   Judy
** Initial revision.
** 
**    Rev 1.0   27 Aug 1996 15:06:54   Judy
** Initial revision.
** 
**    Rev 1.0   14 Jun 1996 13:51:00   Judy
** Initial revision.
** 
**    Rev 1.6   28 Mar 1994 12:49:10   tom
** Removed invalid global handle problem shown in debug kernel output.
** 
**    Rev 1.5   16 Jul 1993 11:59:36   ernie
** Removed obsolete includes error.h and sdserror.h
** 
**    Rev 1.4   14 Aug 1992 15:58:58   doug
** removed warnings
** 
**    Rev 1.3   30 Jul 1992 15:22:50   doug
** new name for error header
** 
**    Rev 1.2   13 May 1992 16:45:00   mindy
** redid error numbers/names
** 
**    Rev 1.1   18 Feb 1992 17:47:30   courtney
** Revised RemoveList to check for null callback before calling
** RemoveEntry (nothing to remove).
** 
**    Rev 1.0   29 Jul 1991 08:53:14   jim
** Initial revision.
**
**  $Header:   S:/tbird/mt2_186/sds/listw.c_v   1.0   16 Dec 1996 13:46:04   Judy  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#ifndef _BASEWIND_    /* !!! Windows */
#include "basewind.h"
#endif

#ifndef _LISTW_
#include "listw.h"
#endif

#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif

#include <dos.h>


                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/

/* Local Macros - to eliminate Windows dependencies */
#define MemAlloc(item) GlobalAlloc(GMEM_MOVEABLE, sizeof(item))
#define MemFree(item) GlobalFree(item)
#define MemLock(handle) (handle) ? GlobalLock(handle) : (LPSTR)NULL
#define MemUnlock(handle) GlobalUnlock(handle)
#define IsDescriptor(pointer) (U16)GlobalHandle(FP_SEG(pointer))
#define NumLock(handle) (GlobalFlags(handle) & GMEM_LOCKCOUNT)

/* Entry structure of list */
typedef struct LENTRY {
   DESCRIPTOR lNext;
   CALLBACK lData;  /* Registerred callback function */
} LENTRY;

                        /****************************
                         *                          *
                         *    EXTERNAL VARIABLES    *
                         *                          *
                         ****************************/

                        /****************************
                         *                          *
                         *     LOCAL PROTOTYPES     *
                         *                          *
                         ****************************/
RETCODE RemoveEntry(LIST FAR *list, DESCRIPTOR curDesc, LENTRY FAR *prevEntry,
   CALLBACK data);

                        /****************************
                         *                          *
                         *      EXECUTABLE CODE     *
                         *                          *
                         ****************************/

/*****************************************************************************
**
**    AppendList
**
*****************************************************************************/
RETCODE EXPORT AppendList(LIST FAR *list, CALLBACK data){
   DESCRIPTOR hEntry;
   LENTRY FAR *entry;
   RETCODE err = (!GOOD);

   /* Allocate memory for the new entry and add to head of list */
   if((hEntry = (DESCRIPTOR) MemAlloc(*entry)) != NULL) {
      if ((entry = (LENTRY FAR *) MemLock((HANDLE)hEntry)) != NULL) {
         err = GOOD;
         entry->lData = (CALLBACK) data;
         entry->lNext = list->head;
         list->head = (DESCRIPTOR) hEntry;
      }
   }
   MemUnlock((HANDLE)hEntry);
   return((err == GOOD) ? GOOD : ER_OUT_OF_MEMORY);
}

/*****************************************************************************
**
**    RemoveList
**
*****************************************************************************/
RETCODE EXPORT RemoveList(LIST FAR *list, CALLBACK data){
   LENTRY FAR *headEntry;

   if ((headEntry = (LENTRY FAR *) MemLock((HANDLE)list->head)) == NULL)
      return(!GOOD);
   /* remove a callback entry, only if this is a valid callback */
   if (data)
       RemoveEntry(list, list->head, headEntry, data);
   return(GOOD);
}

/*****************************************************************************
**
**    GetList
**
*****************************************************************************/
CALLBACK EXPORT GetList(LIST FAR *list) {
    LENTRY FAR *currEntry;
    CALLBACK data = NULL;

    if (list->current != NULL) {
       if ((currEntry = (LENTRY FAR *) MemLock((HANDLE)list->current))!=NULL){
          data = (CALLBACK) currEntry->lData;
          MemUnlock((HANDLE)list->current);
       }
    }
    return(data);
}

/*****************************************************************************
**
**    NextList
**
*****************************************************************************/
DESCRIPTOR EXPORT NextList(LIST FAR *list) {
   LENTRY FAR *curEntry;

   if (list->current != NULL) {
      if ((curEntry = (LENTRY FAR *) MemLock((HANDLE)list->current))!=NULL) {
         list->current = curEntry->lNext;
         MemUnlock((HANDLE)list->current);
      }
      return(NULL); /* !!! ERROR */
   }
   else
      list->current = NULL;
   return(list->current);
}

/*****************************************************************************
**
**    InitListRoutines
**
*****************************************************************************/
RETCODE InitListRoutines(VOID) {
   return(GOOD);
}

/****************************************************************************
**
**  RemoveEntry
**
**  Description:
**     Routine to remove an entry from the callback functions list.
**
**  Parameters:
**     input:
**        list:         List of callback function entries.
**        curDesc:      Current descriptor of entry.
**        prevEntry:
**     output:
**        none
**
*****************************************************************************/
RETCODE RemoveEntry(LIST FAR *list, DESCRIPTOR currDesc,LENTRY FAR *prevEntry,
   CALLBACK data) {
   LENTRY FAR *curEntry;
   RETCODE err;

   if ((curEntry = (LENTRY FAR *) MemLock((HANDLE)currDesc)) != NULL) {
      if (curEntry->lData == data) { /* Remove entry */
         if (IsDescriptor(curEntry) == list->head)
            list->head = curEntry->lNext;
         else
            prevEntry->lNext = curEntry->lNext;
         if (IsDescriptor(curEntry) == list->current)
            NextList(list);
         /* remove entry from the list */
         FreeProcInstance(curEntry->lData);   /* Windows */
         curEntry->lData = NULL;
         MemUnlock((HANDLE)currDesc);
         MemFree((HANDLE)currDesc);
         return(GOOD);
      }
      else {  /* Next Entry - recursive calling to lock the currDesc */
         if (RemoveEntry(list, curEntry->lNext, curEntry, data) == GOOD)
            err = GOOD;
         MemUnlock((HANDLE)currDesc);
         return(err);
      }
   }
   else
      return(ER_WINDOWS_MEMLOCK);

}
/******************************** E O F ***********************************/

