/*static char *SCCSID = "@(#)subq1.c    6.4 91/06/07";*/
/****************************************************************************/
/*                                                                          */
/*                       IBM/Microsoft Confidential                         */
/*                                                                          */
/*                 Copyright (c) IBM Corporation  1987, 1990                */
/*                 Copyright (c) Microsoft Corp.  1987, 1990                */
/*                           All Rights Reserved                            */
/*                                                                          */
/****************************************************************************/

#include        <dos.h>
#include        <doscalls.h>
#include        <drt.h>
#include        <error.h>
#include        <error2.h>
#include        <infoseg.h>
#include        <ipcqueue.h>

/********************** START OF SPECIFICATIONS **********************/
/*                                                                   */
/* SOURCE FILE NAME: subq1.c                                         */
/*                                                                   */
/* DESCRIPTIVE NAME: Common Subroutines for IPC Queues which are     */
/*                   the most frequently used                        */
/*                                                                   */
/* COPYRIGHT: (TOP MODULE ONLY)                                      */
/*                                                                   */
/* STATUS: RELEASE 1 LEVEL 0                                         */
/*                                                                   */
/* FUNCTION:                                                         */
/*                                                                   */
/* NOTES:                                                            */
/*    DEPENDENCIES:                                                  */
/*    RESTRICTIONS:                                                  */
/*    PATCH LABEL: (TOP MODULE ONLY)                                 */
/*                                                                   */
/* ENTRY POINTS:                                                     */
/*             FuncFree                                              */
/*             FuncInit                                              */
/*             Q_Scan                                                */
/*             FindMem                                               */
/*                                                                   */
/* INTERNAL REFERENCES:                                              */
/*    ROUTINES:                                                      */
/*                                                                   */
/* EXTERNAL REFERENCES:                                              */
/*             DOSHOLDSIGNAL:FAR                                     */
/*             DOSSEMCLEAR:FAR                                       */
/*             DOSCREATESEM:FAR                                      */
/*             DOSENTERCRITSEC:FAR                                   */
/*             DOSEXITCRITSEC:FAR                                    */
/*             DOSEXITLIST:FAR                                       */
/*             DOSGETINFOSEG:FAR                                     */
/*             DOSOPENSEM:FAR                                        */
/*             DOSSEMREQUEST:FAR                                     */
/*             DOSSUBFREE:FAR                                        */
/*             DOSREALLOCSEG:FAR                                     */
/*             DOSSUBALLOC:FAR                                       */
/*             DOSSUBSET:FAR                                         */
/*                                                                   */
/*                   Modification Log                                */
/*  Date   Name   Description                                        */
/* 4/4/10  ChangeTeam Added check for ERROR_TOO_MANY_POSTS           */
/*                    Defect : 118139                                */
/*                                                                   */
/*********************** END OF SPECIFICATIONS ***********************/

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SUBROUTINE NAME:    FuncFree                                     */
/*                                                                  */
/* DESCRIPTIVE NAME:   FuncFree                                     */
/*                                                                  */
/* FUNCTION:   FuncFree                                             */
/*                                                                  */
/* NOTES:                                                           */
/*                                                                  */
/* ENTRY POINT:        FuncFree                                     */
/*    LINKAGE:         near at pl 2                                 */
/*                                                                  */
/* INPUT:                                                           */
/*                                                                  */
/* EXIT-NORMAL:                                                     */
/*                     AX = 0                                       */
/*                                                                  */
/* EXIT-ERROR:                                                      */
/*                     AX != 0                                      */
/*                     'SYS ERROR'                                  */
/*                                                                  */
/* EFFECTS:    Semaphore cleared, signals re-enabled, PID field     */
/*             cleared                                              */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             DOSHOLDSIGNAL:FAR                                    */
/*             DOSSEMCLEAR:FAR                                      */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

/*      FuncFree:                                                   */
/*                                                                  */
/*      clear static.st_pid                                         */
/*      release static.st_sem via DosSemClear                       */
/*      if (DosSemClear returns in error) then                      */
/*        return error code     'SYS ERROR'                         */
/*      endif                                                       */
/*      return                  'NO ERROR'                          */

unsigned int
FuncFree()
{
int rc;
        extern  struct  STATDATA statseg;
        extern  struct  Q_INST  far *ISEG;

        statseg.st_pid = NULL;
        rc = DOSSEMCLEAR((*ISEG).inst_semhnd);
        DOSHOLDSIGNAL(0);
        if (rc != NO_ERROR)
                return(ERROR_SYS_INTERNAL);
        else
                return(NO_ERROR);
}

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SUBROUTINE NAME:    FuncInit                                     */
/*                                                                  */
/* DESCRIPTIVE NAME:   FuncInit                                     */
/*                                                                  */
/* FUNCTION:   Common initialization for all queue system calls     */
/*                                                                  */
/* NOTES:                                                           */
/*                                                                  */
/* ENTRY POINT:        FuncInit                                     */
/*    LINKAGE:         near at pl 2                                 */
/*                                                                  */
/* INPUT:                                                           */
/*                                                                  */
/* EXIT-NORMAL:                                                     */
/*                     AX = 0                                       */
/*                                                                  */
/* EXIT-ERROR:                                                      */
/*                     AX != 0                                      */
/*                     'SYS ERROR'                                  */
/*                                                                  */
/* EFFECTS:                                                         */
/*                     Adjusts Signals                              */
/*                     Create/Open Semaphore                        */
/*                     Adjusts Static Data                          */
/*                     Semaphore Blocked Upon                       */
/*                     Insure exitlist set                          */
/*                     Clears action flag                           */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             DOSCREATESEM:FAR                                     */
/*             DOSENTERCRITSEC:FAR                                   */
/*             DOSEXITCRITSEC:FAR                                    */
/*             DOSEXITLIST:FAR                                      */
/*             DOSGETINFOSEG:FAR                                    */
/*             DOSHOLDSIGNAL:FAR                                    */
/*             DOSOPENSEM:FAR                                       */
/*             DOSSEMCLEAR:FAR                                      */
/*             DOSSEMREQUEST:FAR                                    */
/*             DOSSUBFREE:FAR                                       */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

/*                                                                  */
/*      FuncInit:                                                   */
/*                                                                  */
/*      initialize error                'NO ERROR'                  */
/*      obtain variables from Instance Segment                      */
/*      if (semaphore handle not set for this process)              */
/*        call GetInfoSeg to obtain access to local info seg.       */
/*        obtain, set current pid                                   */
/*        call DosCreateSem                                         */
/*        if (DosCreateSem returns 'already exists' error or        */
/*            'too many sempahores' error)                          */
/*          call DosOpenSem                                         */
/*          if (DosOpenSem returns error) then                      */
/*            set error code            'ERROR_SYS_INTERNAL'        */
/*          endif                                                   */
/*        elseif (DosCreateSem returns error)                       */
/*          set error                   'ERROR SYS INTERNAL'        */
/*        endif                                                     */
/*        if (exitlistq not set for this process)                   */
/*          call DosExitList, add first routine function            */
/*          if (DosExitList returns no error)                       */
/*             call DosExitList, add second routine function        */
/*             if (DosExitList returns no error)                    */
/*                set instance segment exitlist flag                */
/*          else                                                    */
/*            set error code            'ERROR_SYS_INTERNAL'        */
/*          endif                                                   */
/*        endif                                                     */
/*      endif                                                       */
/*      if (no error) then                                          */
/*        repeat                                                    */
/*          call DosSemRequest                                      */
/*          switch (on error code from DosSemRequest)               */
/*            case 'NO_ERROR'                                       */
/*              statseg.st_pid = current pid                        */
/*              break                                               */
/*            case 'ERROR_INTERRUPT'                                */
/*              break                                               */
/*            case 'ERROR_SEM_OWNER_DIED'                           */
/*              set error code =        'NO_ERROR'                  */
/*              statseg.st_pid = current pid                        */
/*              case select appropriate action cleanup              */
/*              action = 0                                          */
/*              break                                               */
/*            default                                               */
/*              set error code          'ERROR_SYS_INTERNAL'        */
/*              clear statseg.st_pid                                */
/*              break                                               */
/*          endswitch                                               */
/*          if (error code =            'ERROR_SYS_INTERNAL')       */
/*            break                                                 */
/*          endif                                                   */
/*        until (error code !=          'ERROR_INTERRUPT')          */
/*      else                                                        */
/*        clear statseg.st_pid                                      */
/*      endif                                                       */
/*      return                                                      */

        char name_sem[] = "\\SEM\\IPCQUEUE.SEM";

unsigned int
FuncInit()
{
        extern  unsigned far POST16EVENTSEM(unsigned long);
        extern  void far EXITLISTQUEUE1 (void);
        extern  void far EXITLISTQUEUE2 (void);
        extern  struct  STATDATA statseg;
        extern  struct  Q_INST  far *ISEG;
        extern  char name_sem[];
        extern  unsigned char   action;
        extern  unsigned count;
        extern  struct  Q_ENTRY far *prev_fst_q;
        extern  struct  L_ENTRY far *prev_fst_link;
        extern  struct  Q_ENTRY far *que1;
        extern  struct  Q_ENTRY far *que2;
        extern  struct  Q_ENTRY far *que3;
        extern  struct  L_ENTRY far *lnk1;
        extern  struct  L_ENTRY far *lnk2;
        extern  struct  L_ENTRY far *lnk3;
        extern  struct  E_ENTRY far *emt1;
        extern  struct  E_ENTRY far *emt2;
        extern  struct  E_ENTRY far *emt3;

        unsigned int    GSeg,LSeg;
        register unsigned int    rc;
        unsigned long fi_semhnd;
        unsigned long hsem_temp;
        register unsigned int fi_pid;
        struct  InfoSegLDT far  *locptr = NULL;

/*      krnldbug();     */

        rc = NO_ERROR;
        fi_semhnd = (*ISEG).inst_semhnd;
        fi_pid = (*ISEG).inst_pid;
        if (fi_semhnd == NULL)
        {
                DOSGETINFOSEG((unsigned far *) &GSeg,(unsigned far *) &LSeg);
                        PUT_SEG(locptr,LSeg);
                        (*ISEG).inst_pid = (*locptr).CurProcID;
                        fi_pid = (*ISEG).inst_pid;
                        rc = DOSCREATESEM(((unsigned) 0),(unsigned long far *) &hsem_temp,(char far *) name_sem);
                        switch(rc)
                        {
                                case NO_ERROR:
                                        DOSENTERCRITSEC();
                                        (*ISEG).inst_semhnd = hsem_temp;
                                        DOSEXITCRITSEC();
                                        break;
                                case ERROR_TOO_MANY_SEMAPHORES:
                                case ERROR_ALREADY_EXISTS:
                                        if ((rc = DOSOPENSEM((unsigned long far *) &hsem_temp,(char far *) name_sem)) != NO_ERROR)
                                                rc = ERROR_SYS_INTERNAL;
                                        else
                                        {
                                                DOSENTERCRITSEC();
                                                (*ISEG).inst_semhnd = hsem_temp;
                                                DOSEXITCRITSEC();
                                        }
                                        break;
                                default:
                                        rc = ERROR_SYS_INTERNAL;
                                        break;
                        }
                        fi_semhnd = (*ISEG).inst_semhnd;
                        if ((*ISEG).inst_exlst == NULL)         /* prevent exitlistqueue from being invoked multiple times */
                        {
                                if ((DOSEXITLIST(((unsigned) 0xD081),EXITLISTQUEUE1)) == NO_ERROR)
                                {
                                   if ((DOSEXITLIST(((unsigned) 0xD001),EXITLISTQUEUE2)) == NO_ERROR)
                                   {
                                        (*ISEG).inst_exlst = 0xff;
                                   }
                                }
                                else if (rc == NO_ERROR)
                                        rc = ERROR_SYS_INTERNAL;
                        }
        }
        if (rc == NO_ERROR)
        {
                DOSHOLDSIGNAL(1);
                do
                {
                        rc = DOSSEMREQUEST(fi_semhnd,((unsigned long) -1));
                        switch (rc)
                        {
                                case NO_ERROR:
                                        statseg.st_pid = fi_pid;
                                        break;
                                case ERROR_INTERRUPT:
                                        break;
                                case ERROR_SEM_OWNER_DIED:
                                        rc = NO_ERROR;
                                        statseg.st_pid = fi_pid;
                                        switch(action)
                                        {
                                                case ACT_ADD_QUE:
                                                        statseg.fst_q = que1;
                                                        break;
                                                case ACT_ADD_LNK:
                                                        (*que1).q_flags |= Q_LINKS;
                                                        statseg.fst_link = lnk1;
                                                        break;
                                                case ACT_DEL_ONLY_EMT:
                                                        (*que1).q_fst = NULL;
                                                        (*que1).q_lst = NULL;
                                                        (*que1).q_cnt = NULL;
                                                        DOSSUBFREE(FP_SEG(emt1),FP_OFF(emt1),sizeof(struct E_ENTRY));
                                                        break;
                                                case ACT_DEL_FST_EMT:
                                                        (*que1).q_fst = emt3;
                                                        (*emt3).e_prev = NULL;
                                                        if ((*que1).q_cnt == count)
                                                                (*que1).q_cnt--;
                                                        DOSSUBFREE(FP_SEG(emt1),FP_OFF(emt1),sizeof(struct E_ENTRY));
                                                        break;
                                                case ACT_DEL_LST_EMT:
                                                        (*que1).q_lst = emt2;
                                                        (*emt2).e_next = NULL;
                                                        if ((*que1).q_cnt == count)
                                                                (*que1).q_cnt--;
                                                        DOSSUBFREE(FP_SEG(emt1),FP_OFF(emt1),sizeof(struct E_ENTRY));
                                                        break;
                                                case ACT_DEL_MID_EMT:
                                                        (*emt2).e_next = emt3;
                                                        (*emt3).e_prev = emt2;
                                                        if ((*que1).q_cnt == count)
                                                                (*que1).q_cnt--;
                                                        DOSSUBFREE(FP_SEG(emt1),FP_OFF(emt1),sizeof(struct E_ENTRY));
                                                        break;
                                                case ACT_DEL_LNK:
                                                        if (prev_fst_link == lnk1)
                                                                statseg.fst_link = lnk3;
                                                        else
                                                                (*lnk2).l_chain = lnk3;
                                                        DOSSUBFREE(FP_SEG(lnk1),FP_OFF(lnk1),sizeof(struct L_ENTRY));
                                                        break;
                                                case ACT_ADD_ONLY_EMT:
                                                        (*que1).q_fst = emt1;
                                                        (*que1).q_lst = emt1;
                                                        if ((*que1).q_cnt == count)
                                                                (*que1).q_cnt++;

                                                        if (DOSSEMWAIT((unsigned long)&((*que1).q_ramsem),0l)==NO_ERROR)   /*no one waiting, clear the wait sem*/
                                                        {
                                                            if ((*que1).q_semhnd != 0)
                                                            {
                                                                /* if function called from 16-bit code */
                                                                if (((*que1).q_flags & Q_BIT32) == 0)
                                                                {
                                                                  if ((DOSSEMCLEAR((*que1).q_semhnd)) != NO_ERROR)
                                                                  {
                                                                      rc = ERROR_SYS_INTERNAL;
                                                                  } /* endif */
                                                                } /* endif */
                                                                /* else function was called from 32-bit code */
                                                                else
                                                                {
                                                                   /* call thunk to call Dos32PostEventSem */
                                                                   rc = POST16EVENTSEM((*que1).q_semhnd);
                                                                   if (rc != NO_ERROR)
                                                                   {
                                                                      /* if semaphore had already been posted (cleared) */
                                                                      /* if rc == ERROR_ALREADY_POSTED                       D118139 - commented out */
                                                                      if ( ( rc == ERROR_ALREADY_POSTED ) || ( rc == ERROR_TOO_MANY_POSTS ) )   /* D118139 */
                                                                      {
                                                                         /* that is not an error */
                                                                         rc = NO_ERROR;
                                                                      }
                                                                      else
                                                                      {
                                                                         rc = ERROR_SYS_INTERNAL;
                                                                      } /* endif */
                                                                   }
                                                                } /* end elseif */
                                                            }
                                                        }

                                                        break;
                                                case ACT_ADD_LST_EMT:
                                                        (*que1).q_lst = emt1;
                                                        (*emt2).e_next = emt1;
                                                        if ((*que1).q_cnt == count)
                                                                (*que1).q_cnt++;
                                                        break;
                                                case ACT_ADD_FST_EMT:
                                                        (*que1).q_fst = emt1;
                                                        (*emt2).e_prev = emt1;
                                                        if ((*que1).q_cnt == count)
                                                                (*que1).q_cnt++;
                                                        break;
                                                case ACT_ADD_MID_EMT:
                                                        (*emt3).e_prev = emt1;
                                                        (*emt2).e_next = emt1;
                                                        if ((*que1).q_cnt == count)
                                                                (*que1).q_cnt++;
                                                        break;
                                                case ACT_DEL_QUE:
                                                        if (prev_fst_q == que1)
                                                                statseg.fst_q = que3;
                                                        else
                                                                (*que2).q_chain = que3;
                                                        DOSSUBFREE(FP_SEG(que1),FP_OFF(que1),(sizeof(struct Q_ENTRY)+farstrlen((*que1).q_name)));
                                                        break;
                                                case 0:
                                                default:
                                                        break;
                                        }
                                        action = 0;
                                        break;
                                default:
                                        rc = ERROR_SYS_INTERNAL;
                                        statseg.st_pid = NULL;
                                        break;
                        }
                        if (rc == ERROR_SYS_INTERNAL)
                                break;
                }
                while (rc == ERROR_INTERRUPT);
        }
        else
                statseg.st_pid = NULL;
        return(rc);
}

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SUBROUTINE NAME:    Q_Scan                                       */
/*                                                                  */
/* DESCRIPTIVE NAME:   Q_Scan                                       */
/*                                                                  */
/* FUNCTION:   Scans the queue chain for the queue handle.          */
/*                                                                  */
/* NOTES:                                                           */
/*                                                                  */
/* ENTRY POINT:        Q_Scan                                       */
/*    LINKAGE:         near at pl 2                                 */
/*                                                                  */
/* INPUT:                                                           */
/*             DD       address of queue                            */
/*             DD       address of prev queue                       */
/*             DW       Queue handle                                */
/*                                                                  */
/* EXIT-NORMAL:                                                     */
/*             AX = 0                                               */
/*             queue                                                */
/*             prev queue                                           */
/*                                                                  */
/* EXIT-ERROR:                                                      */
/*             AX != 0                                              */
/*             'QUEUE HANDLE NOT FOUND'                             */
/*                                                                  */
/* EFFECTS:                                                         */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*                                                                  */
/* EXTERNAL REFERENCES                                              */
/*    ROUTINES:                                                     */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

/*      Q_Scan:                                                     */
/*                                                                  */
/*      off = static.fst_q                                          */
/*      prev = NULL                                                 */
/*      if (off = NULL) then                                        */
/*        while (off.q_hndl != handle and off.q_chain != 0) do      */
/*          prev = offset                                           */
/*          offset = offset.q_chain                                 */
/*        endwhile                                                  */
/*        qoffset = off                                             */
/*        qprev = prev                                              */
/*      endif                                                       */
/*      if ((offset = NULL) or (wrong queue handle)) then           */
/*        set error code        'QUEUE HANDLE NOT FOUND'            */
/*      else                                                        */
/*        set good return code                                      */
/*      endif                                                       */
/*      return                                                      */

unsigned int
Q_Scan(qoffset,qprev,qhandl)
struct  Q_ENTRY far * far *qoffset;
struct  Q_ENTRY far * far *qprev;
register unsigned int    qhandl;
{
        extern  struct  STATDATA        statseg;
        struct  Q_ENTRY far     *off;
        struct  Q_ENTRY far     *prev;

        off = statseg.fst_q;
        prev = NULL;
        if (statseg.fst_q != NULL)
        {
                while (((*off).q_hndl != qhandl) && ((*off).q_chain != NULL))
                {
                        prev = off;
                        off = (*off).q_chain;
                }
                *qoffset = off;
                *qprev = prev;
        }
        if ((off == NULL) || ((*off).q_hndl != qhandl))
                return(ERROR_QUE_INVALID_HANDLE);
        else
                return(NO_ERROR);
}

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SUBROUTINE NAME:    FindMem                                      */
/*                                                                  */
/* DESCRIPTIVE NAME:   FindMem                                      */
/*                                                                  */
/* FUNCTION:   Used to enter new records into one of the two        */
/*             available queue segments                             */
/*                                                                  */
/* NOTES:                                                           */
/*                                                                  */
/* ENTRY POINT:        FindMem                                      */
/*    LINKAGE:         near at pl 2                                 */
/*                                                                  */
/* INPUT                                                            */
/*             DW      Size of record                               */
/*             @DD     Address of New Record                        */
/*                                                                  */
/* EXIT-NORMAL:                                                     */
/*             AX = 0                                               */
/*             Address of New Record                                */
/*                                                                  */
/* EXIT-ERROR:                                                      */
/*             AX != 0                                              */
/*             'INSUFFICIENT MEMORY'                                */
/*             'SYS ERROR'                                          */
/*                                                                  */
/* EFFECTS:    Allocates - and if necessary grows - the queue segs. */
/*             set segment size variable                            */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             DOSREALLOCSEG:FAR                                    */
/*             DOSSUBALLOC:FAR                                      */
/*             DOSSUBSET:FAR                                        */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

/*      FindMem:                                                    */
/*                                                                  */
/*      do                                                          */
/*        allocate table memory via DosSubAlloc                     */
/*        if (DosSubAlloc returns in error) then                    */
/*          if (static.segsize != 64k (0)) then                     */
/*            attempt to grow segment via DosReallocSeg             */
/*            if (DosReallocSeg returns in error) then              */
/*              return with         'INSUFFICIENT MEMORY'           */
/*            endif                                                 */
/*            adjust static.size                                    */
/*            reinitialize segment via DosSubSet                    */
/*            if (DosSubSet returns in error) then                  */
/*              return with         'SYS ERROR'                     */
/*            endif                                                 */
/*            allocate table memory via DosSubAlloc                 */
/*            if (DosSubAlloc returns in error) then                */
/*              return with         'SYS ERROR'                     */
/*            endif                                                 */
/*          else if (first loop)                                    */
/*            switch segments                                       */
/*            if (first switch to second segment) then              */
/*              initialize Second Queue Segment via DosSubSet       */
/*              if (DosSubSet returns in error) then                */
/*                return with       'SYS ERROR'                     */
/*              else                                                */
/*                change static.segsize to 1k for new segment       */
/*              endif                                               */
/*            endif                                                 */
/*          else                                                    */
/*            return with           'INSUFFICIENT MEMORY'           */
/*          endif                                                   */
/*        else                                                      */
/*          set far pointer                                         */
/*          return with             'NO ERROR'                      */
/*      while incrementing loop                                     */

unsigned int
FindMem(size,addr)
register unsigned int size;
unsigned char far * far * addr;
{
        extern struct STATDATA statseg;
        extern int QSEG, QSEG1, QSEG2;
        unsigned char far * temp;
        register unsigned int segsiz;
        unsigned int offset;
        static int first_QSEG2_use = 1;
        register unsigned int loop = 1;

        do
        {
                if ((DOSSUBALLOC(QSEG,(unsigned far *) &offset,size)) != NO_ERROR)
                {
                        if (statseg.seg_size != NULL)
                        {
                                segsiz = QSEGSIZ + statseg.seg_size;
                                if ((DOSREALLOCSEG(segsiz,QSEG)) != NO_ERROR)
                                        return(ERROR_QUE_NO_MEMORY);
                                statseg.seg_size = segsiz;
                                if (DOSSUBSET(QSEG,((unsigned) 0),statseg.seg_size) != NO_ERROR ||
                                    DOSSUBALLOC(QSEG,(unsigned far *) &offset,size) != NO_ERROR)
                                        return(ERROR_SYS_INTERNAL);
                        }
                        else if (loop == 1)
                        {
                                QSEG = (QSEG == QSEG2 ? QSEG1 : QSEG2);
                                if (QSEG == QSEG2 && first_QSEG2_use)
                                {
                                        if (DOSSUBSET(QSEG2,((unsigned) 1),QSEGSIZ) != NO_ERROR)
                                                return(ERROR_SYS_INTERNAL);
                                        statseg.seg_size = QSEGSIZ;
                                        first_QSEG2_use = 0;
                                }
                        }
                        else
                                return(ERROR_QUE_NO_MEMORY);
                }
                else
                {
                        PUT_SEG(temp,QSEG);
                        PUT_OFF(temp,offset);
                        *addr = temp;
                        return(NO_ERROR);
                }
        } while (loop++);
}
