/*static char *SCCSID = "@(#)createq.c	6.3 91/03/29";*/
/****************************************************************************/
/*                                                                          */
/*                       IBM/Microsoft Confidential                         */
/*                                                                          */
/*                 Copyright (c) IBM Corporation  1987, 1990                */
/*                 Copyright (c) Microsoft Corp.  1987, 1990                */
/*                           All Rights Reserved                            */
/*                                                                          */
/****************************************************************************/

/*
 *      This code will implement DosCreateQueue
 */

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

unsigned int F_Syntax(char far *, char far *);
unsigned int Q_Tbl(char far *, int, unsigned char);
unsigned far pascal w_DOSCREATEQUEUE(unsigned far *, unsigned, char far *, unsigned short);

/********************** START OF SPECIFICATIONS **********************/
/*                                                                   */
/* SOURCE FILE NAME: createq.c                                       */
/*                                                                   */
/* DESCRIPTIVE NAME: DosCreateQueue                                  */
/*                                                                   */
/* STATUS: RELEASE 1 LEVEL 0                                         */
/*                                                                   */
/* FUNCTION: DosCreateQueue will create a queue owned by the         */
/*           requesting process.                                     */
/*                                                                   */
/* NOTES:                                                            */
/*    DEPENDENCIES:                                                  */
/*    RESTRICTIONS:                                                  */
/*                                                                   */
/* ENTRY POINTS:        DOSCREATEQUEUE                               */
/*                                                                   */
/* INTERNAL REFERENCES:                                              */
/*    ROUTINES:                                                      */
/*                      w_DOSCREATEQUEUE:FAR                         */
/*                      F_Syntax:NEAR                                */
/*                      Q_Tbl:NEAR                                   */
/*                                                                   */
/* EXTERNAL REFERENCES:                                              */
/*             DOSICANONICALIZE:FAR                                  */
/*             queues_sys_trace:NEAR                                 */
/*             FindMem:near                                          */
/*             FuncFree:near                                         */
/*             FuncInit:near                                         */
/*             Q_Scan:near                                           */
/*             ScanQname:near                                        */
/*             strlen:near                                           */
/*             strncmp:near                                          */
/*                                                                   */
/*********************** END OF SPECIFICATIONS ***********************/

#if defined(MMIOPH)
extern void queues_sys_trace(
unsigned,                                       /* que_major_code */
unsigned,                                       /* int que_data_len */
unsigned,                                       /* que_minor_code */
char far *);                                    /* que_data */
#endif

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SUBROUTINE NAME:    F_Syntax                                     */
/*                                                                  */
/* DESCRIPTIVE NAME:   F_Syntax                                     */
/*                                                                  */
/* FUNCTION:   Insures that a queue name is unique and valid        */
/*                                                                  */
/* NOTES:                                                           */
/*                                                                  */
/* ENTRY POINT:        F_Syntax                                     */
/*    LINKAGE:         near at pl 2                                 */
/*                                                                  */
/* INPUT:                                                           */
/*             DD      @Input Name                                  */
/*             DW      @Output buffer                               */
/*                                                                  */
/* EXIT-NORMAL:                                                     */
/*             AX = 0                                               */
/*                                                                  */
/* EXIT-ERROR:                                                      */
/*             AX != 0                                              */
/*                     'INVALID NAME'                               */
/*                     'DUPLICATE NAME'                             */
/*                                                                  */
/* EFFECTS:                                                         */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             DOSICANONICALIZE:FAR                                 */
/*             ScanQname:near                                       */
/*             strlen:near                                          */
/*             strncmp:near                                         */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

/*      F_Syntax:                                                   */
/*                                                                  */
/*      if (name string is too short or too long)                   */
/*        return with         'INVALID NAME'                        */
/*      else                                                        */
/*        if (beginning of name != '\QUEUES\')                      */
/*          return with       'INVALID NAME'                        */
/*        else                                                      */
/*          call ScanQname                                          */
/*          if (ScanQname returns ok) then                          */
/*            return with           'DUPLICATE NAME'                */
/*          else                                                    */
/*            return                'NO ERROR'                      */
/*          endif                                                   */
/*        endif                                                     */
/*      endif                                                       */
/*      return                                                      */

char    list1[] = "\\QUEUES\\";

extern unsigned far pascal DOSICANONICALIZE (char far *, char far *, char near *, char near *, unsigned);

unsigned int
F_Syntax(q_name,nu_name)
char far *q_name;                               /* Pointer to Queue Name   */
char far *nu_name;
{

        extern  struct  STATDATA        statseg;
        extern  char  list1[];
        struct  Q_ENTRY far *qoff;
        struct  Q_ENTRY far *qprv;

        register unsigned int    length;

        length = farstrlen(nu_name);
        if ((length > MAX_QUE_NAME_LENGTH) || (length <= strlen(list1)))
                return(ERROR_QUE_INVALID_NAME);
        else
        {
                if (strncmp(nu_name,list1,strlen(list1)) != 0)
                        return(ERROR_QUE_INVALID_NAME);
                else
                {
                        if ((ScanQname((char far *) nu_name,(struct  Q_ENTRY far * far *) &qoff,(struct  Q_ENTRY far * far *) &qprv))
                                == NO_ERROR)
                                return(ERROR_QUE_DUPLICATE);
                        else
                                return(NO_ERROR);
                }
        }
}

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SUBROUTINE NAME:    Q_Tbl                                        */
/*                                                                  */
/* DESCRIPTIVE NAME:   Q_Tbl                                        */
/*                                                                  */
/* FUNCTION:   Create a queue entry in the queue segment            */
/*                                                                  */
/* NOTES:                                                           */
/*                                                                  */
/* ENTRY POINT:        Q_Tbl                                        */
/*    LINKAGE:         near at pl 2                                 */
/*                                                                  */
/* INPUT:                                                           */
/*             DW      Queue Name Address                           */
/*             DW      Queue Priority                               */
/*             DB      Flags from 32-bit app                        */
/*                                                                  */
/* EXIT-NORMAL:                                                     */
/*             AX = 0                                               */
/*                                                                  */
/* EXIT-ERROR:                                                      */
/*             AX != 0                                              */
/*             'INSUFFICIENT MEMORY'                                */
/*             'SYS ERROR'                                          */
/*                                                                  */
/* EFFECTS:                                                         */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             FindMem:near                                         */
/*             Q_Scan:near                                          */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

/*      Q_Tbl:                                                      */
/*                                                                  */
/*      call FindMem                                                */
/*      if (FindMem returns in error) then                          */
/*        return with           'NO MEMORY'                         */
/*      else                                                        */
/*        repeat                                                    */
/*          increment static.nu_hnd                                 */
/*          if (static.nu_hnd = 0) then                             */
/*            increment static.nu_hnd                               */
/*          endif                                                   */
/*          call Q_Scan on contents of static.nu_hnd                */
/*        until (Q_Scan returns in error)                           */
/*        initialize exitlist action variables                      */
/*        set exitlist action flag = ACT_ADD_QUE                    */
/*        initialize q_table entry                                  */
/*        set exitlist action flag off                              */
/*        update queue chain                                        */
/*        return with           'NO ERROR'                          */
/*      endif                                                       */

unsigned int
Q_Tbl(qname,qu_prio,flags)
char far *qname;                                    /* Pointer to Queue Name   */
register int     qu_prio;
unsigned char flags;
{
        extern  struct  STATDATA        statseg;
        extern  struct Q_ENTRY far *que1;
        extern  struct Q_ENTRY far *que2;
        extern  unsigned char   action;

        struct  Q_ENTRY far *qpresent;
        struct  Q_ENTRY far *qlast;
        struct  Q_ENTRY far *qptr;
        register unsigned int    rc;

        if ((FindMem((sizeof(struct Q_ENTRY)+farstrlen(qname)),(unsigned char far * far *) &qptr)) != NO_ERROR)
        {
                return(ERROR_QUE_NO_MEMORY);
        }
        else
        {
                do
                {
                        statseg.nu_hnd++;
                        if (statseg.nu_hnd == NULL)
                                statseg.nu_hnd++;
                        rc = Q_Scan((struct Q_ENTRY far * far *) &qpresent,(struct Q_ENTRY far * far *) &qlast,statseg.nu_hnd);
                }
                while (rc == NO_ERROR);
                (*qptr).q_flags = flags;
                (*qptr).q_l_cnt = NULL;
                (*qptr).q_cnt = NULL;
                (*qptr).q_fst = NULL;
                (*qptr).q_lst = NULL;
                (*qptr).q_ramsem = NULL;
                (*qptr).q_semhnd = NULL;
                (*qptr).q_prio = qu_prio;
                (*qptr).q_hndl = statseg.nu_hnd;
                (*qptr).q_pid = statseg.st_pid;
                (*qptr).q_chain = statseg.fst_q;
                strcpy((char far *)(*qptr).q_name,qname);
                que1 = qptr;
                que2 = statseg.fst_q;
                action = ACT_ADD_QUE;
                statseg.fst_q = qptr;
                action = 0;
                return(NO_ERROR);
        }
}

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SUBROUTINE NAME: w_DosCreateQueue                                */
/*                                                                  */
/* DESCRIPTIVE NAME: DosCreateQueue Worker                          */
/*                                                                  */
/* FUNCTION: Main Worker routine for DosCreateQueue                 */
/*                                                                  */
/* NOTES:                                                           */
/*                                                                  */
/* ENTRY POINT: w_DOSCREATEQUEUE                                    */
/*    LINKAGE:  far at pl 2                                         */
/*                                                                  */
/* INPUT:                                                           */
/*             @DW     RWHandle        ;Address to put handle       */
/*              DW     QueuePrty       ;Ordering to use             */
/*             @DW     QueueName       ;Pointer to Qname string     */
/*              DW     flags           ;Flags from 32-bit app       */
/*                                                                  */
/* EXIT-NORMAL:                                                     */
/*             AX = 0                                               */
/*             @DW     RWHandle                                     */
/*                                                                  */
/* EXIT-ERROR: AX != 0                                              */
/*                     'DUPLICATE NAME'                             */
/*                     'INVALID NAME'                               */
/*                     'INVALID PRIORITY PARAMETER'                 */
/*                     'INSUFFICIENT MEMORY'                        */
/*                     'SYS ERROR'                                  */
/*                                                                  */
/* EFFECTS:                                                         */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             F_Syntax:NEAR                                        */
/*             Q_Tbl:NEAR                                           */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             queues_sys_trace:NEAR                                */
/*             FuncFree:near                                        */
/*             FuncInit:near                                        */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

/*                                                                  */
/* w_DosCreateQueue:                                                */
/*                                                                  */
/*      initialize error                'NO ERROR'                  */
/*      if (tracing active)                                         */
/*        call queues_sys_trace                                     */
/*      endif                                                       */
/*      call DosICanonicalize                                       */
/*      if (DosICanonicalize returns in error)                      */
/*        set error code      'INVALID NAME'                        */
/*      else                                                        */
/*         call FuncInit                                            */
/*         if (FuncInit returns in error) then                      */
/*           set error code        'SYS ERROR'                      */
/*         else                                                     */
/*           if (priority parameter out of bounds) then             */
/*             set error code      'INVALID PRIORITY'               */
/*           else                                                   */
/*             call F_Syntax                                        */
/*             if (F_Syntax returns in error) then                  */
/*               set error code    from F_Syntax                    */
/*             else                                                 */
/*               call Q_Tbl                                         */
/*               if (Q_Tbl returns in error) then                   */
/*                 set error code  from Q_Tbl                       */
/*               else                                               */
/*                 put queue handle in specified address            */
/*                 set error       'NO ERROR'                       */
/*               endif                                              */
/*             endif                                                */
/*           endif                                                  */
/*           call FuncFree                                          */
/*           if (FuncFree returns in error and error not set)       */
/*             set error             'SYS ERROR'                    */
/*           endif                                                  */
/*         endif                                                    */
/*      endif                                                       */
/*      if (tracing active)                                         */
/*        call queues_sys_trace                                     */
/*      endif                                                       */
/*      return                                                      */

unsigned far pascal w_DOSCREATEQUEUE(RWHnd, QPrio, QName, flags)
unsigned  far *RWHnd;                           /* Address to place handle */
register unsigned QPrio;                        /* Ordering to use for el. */
char far *QName;                                /* Pointer to Queue Name   */
unsigned short flags;                           /* Flags from 32-bit app   */
{
        extern  struct  InfoSegGDT far  *globptr;
        extern  struct  STATDATA        statseg;
        extern  struct  Q_INST  far *ISEG;

        struct  Q_ENTRY far *nu_q;
        register unsigned int    rc;
        unsigned int    len;
        char    new_name[MAX_QUE_NAME_LENGTH];

#if defined(MMIOPH)
        struct RAS_PRE_CREATE {
                unsigned long rp_prio;
                          char rp_name[MAX_QUE_NAME_LENGTH];
        } ras_pre_create;
        struct RAS_POST_CREATE {
                unsigned long rp_rc;
                unsigned long rp_hnd;
        } ras_post_create;
#endif
        PUSHALL_DS();
        rc = NO_ERROR;
        #if (cdbug)
        krnldbug();
        #endif

/***DT DosCreateQueue - Pre-Invocation Dynamic Trace
 *
 *    TRACE MINOR =0x0002,
 *          TP=@
 *          TYPE  =(PRE,API),
 *          DESC  ="(OS) DosCreateQueue Pre-Invocation",
 *          FMT   ="Priority=%pw  Queue name=%ps",
 *          MEM   =(.QPrio,d,2),
 *          ASCIIZ=(.QName,i,260)
 */

#if defined(MMIOPH)
        if (((*globptr).mec_table[17] & 0x80) != NULL)
        {
                ras_pre_create.rp_prio = (unsigned long)QPrio;
                rascpy((char far *) ras_pre_create.rp_name,QName,(unsigned far *) &len);
                len += sizeof(ras_pre_create.rp_prio);
                if (len > RASBUFLEN)
                        len = RASBUFLEN;
                queues_sys_trace(((unsigned) 0x88),len,((unsigned) 2),(char far *) &ras_pre_create);
        }
#endif

        if ((DOSICANONICALIZE(QName,(char far *) new_name,(char near *) new_name,(char near *) new_name+MAX_QUE_NAME_LENGTH, 2)) != NO_ERROR)
                rc = ERROR_QUE_INVALID_NAME;
        else
        {
           if ((FuncInit()) != NO_ERROR)
                   rc = ERROR_SYS_INTERNAL;
           else
           {
                   if (QPrio > MAX_PRIO)
                           rc = ERROR_QUE_INVALID_PRIORITY;
                   else
                   {
                           if ((rc = F_Syntax(QName,(char far *)new_name)) == NO_ERROR)
                           {
                                   if ((rc = Q_Tbl((char far *)new_name,QPrio,(unsigned char)flags)) == NO_ERROR)
                                   {
                                           *RWHnd = statseg.nu_hnd;
                                   }
                           }
                   }
                   if ((FuncFree() != NO_ERROR) && (rc == NO_ERROR))
                           rc = ERROR_SYS_INTERNAL;
           }
        }

/***DT DosCreateQueue - Post-Invocation Dynamic Trace
 *
 *    TRACE MINOR =0x8002,
 *          TP=@
 *          TYPE  =(POST,API),
 *          DESC  ="(OS) DosCreateQueue Post-Invocation",
 *          FMT   ="Return Code=%pw  Handle=%pw",
 *          MEM   =(.rc,d,2),
 *          MEM   =(.RWHnd,i,2)
 */

#if defined(MMIOPH)
        if (((*globptr).mec_table[17] & 0x80) != NULL)
        {
                ras_post_create.rp_rc = (unsigned long)rc;
                ras_post_create.rp_hnd = (unsigned long)*RWHnd;
                queues_sys_trace(((unsigned) 0x88),sizeof(struct RAS_POST_CREATE),((unsigned) 0x82),(char far *) &ras_post_create);
        }
#endif

        return(POPALL(rc));
}

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SUBROUTINE NAME: DosCreateQueue                                  */
/*                                                                  */
/* DESCRIPTIVE NAME: DosCreateQueue                                 */
/*                                                                  */
/* FUNCTION: Parent routine for 16 bit DosCreateQueue               */
/*                                                                  */
/* NOTES:                                                           */
/*                                                                  */
/* ENTRY POINT: DOSCREATEQUEUE                                      */
/*    LINKAGE:  far at pl 2                                         */
/*                                                                  */
/* INPUT:                                                           */
/*             @DW     RWHandle        ;Address to put handle       */
/*              DW     QueuePrty       ;Ordering to use             */
/*             @DW     QueueName       ;Pointer to Qname string     */
/*                                                                  */
/* EXIT-NORMAL:                                                     */
/*             AX = 0                                               */
/*             @DW     RWHandle                                     */
/*                                                                  */
/* EXIT-ERROR: AX != 0                                              */
/*                     'DUPLICATE NAME'                             */
/*                     'INVALID NAME'                               */
/*                     'INVALID PRIORITY PARAMETER'                 */
/*                     'INSUFFICIENT MEMORY'                        */
/*                     'SYS ERROR'                                  */
/*                                                                  */
/* EFFECTS:                                                         */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             w_DOSCREATEQUEUE:FAR                                 */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

/*                                                                  */
/* DosCreateQueue:                                                  */
/*                                                                  */
/* call w_DosCreateQueue                                            */
/* return                                                           */

unsigned far pascal
DOSCREATEQUEUE(RWHnd, QPrio, QName)
unsigned  far *RWHnd;                           /* Address to place handle */
unsigned QPrio;                                 /* Ordering to use for el. */
char far *QName;                                /* Pointer to Queue Name   */
{
unsigned rc;
PUSHALL_DS();
rc=w_DOSCREATEQUEUE(RWHnd,QPrio,QName,(unsigned short)0);
        return(POPALL(rc));
}
