/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  Functions to set up argc and argv parameters of main(), etc.
*
****************************************************************************/
#define __NETWARE__

#ifdef __NETWARE__
    void __Init_Argv( void ) { }
    void __Fini_Argv( void ) { }
#else
//#include "dll.h"        // needs to be first
#include "variety.h"
#include "widechar.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
//#include "liballoc.h"
#include "initarg.h"

extern  int         __historical_splitparms;
extern  void        _Not_Enough_Memory( void );             /* 25-jul-89 */
static  unsigned    _SplitParms(int, CHAR_TYPE *, CHAR_TYPE **, CHAR_TYPE ** );
_WCRTLINKD static CHAR_TYPE  *__F_NAME(__CmdLine,__wCmdLine);       /* cmdline buffer */

_WCRTLINK void *__F_NAME( _getargv, _wgetargv )(
        int historical, CHAR_TYPE *exe, CHAR_TYPE *cmd,
        int *pargc, CHAR_TYPE ***pargv );

void __F_NAME(__Init_Argv,__wInit_Argv)( void )
{
    __F_NAME( __CmdLine, __wCmdLine ) = __F_NAME( _getargv, _wgetargv )(
        __historical_splitparms,
        __F_NAME( _LpPgmName, _LpwPgmName ), __F_NAME( _LpCmdLine, _LpwCmdLine ),
        &__F_NAME( _argc, _wargc ), &__F_NAME( _argv, _wargv ) );

    __F_NAME( __argc, __wargc )   = __F_NAME( _argc, _wargc );
    __F_NAME( ___Argc, ___wArgc ) = __F_NAME( _argc, _wargc );
    __F_NAME( __argv, __wargv )   = __F_NAME( _argv, _wargv );
    __F_NAME( ___Argv, ___wArgv ) = __F_NAME( _argv, _wargv );
}

_WCRTLINK void *__F_NAME( _getargv, _wgetargv )(
        int historical, CHAR_TYPE *exe, CHAR_TYPE *cmd,
        int *pargc, CHAR_TYPE ***pargv )
{
    unsigned    argc;           /* argument count */
    CHAR_TYPE   **argv;         /* Actual arguments */
    CHAR_TYPE   *endptr;        /* ptr to end of command line */
    unsigned    len;            /* length of command line */
    CHAR_TYPE   *cmdline;       /* copy of command line */
    unsigned    size;           /* amount to allocate */
    unsigned    argv_offset;    /* offset of argv in storage */

    argc = _SplitParms( historical, cmd, NULL, &endptr ) + 1;
    len = (unsigned) ( endptr - cmd ) + 1;
    argv_offset = __ALIGN_SIZE(len * sizeof(CHAR_TYPE));
    size = argv_offset + (argc+1) * sizeof(CHAR_TYPE *);
    // round up size for alignment of argv pointer
    size = __ALIGN_SIZE( size );

    #if defined(__REAL_MODE__) && defined(__BIG_DATA__)
        #if defined(__OS2_286__)
            if( _osmode == DOS_MODE ) {
                cmdline = lib_nmalloc( size );
                if( (void _WCI86NEAR *) cmdline == NULL ) {
                    cmdline = lib_malloc( size );
                }
            } else {
                cmdline = lib_malloc( size );
            }
        #else
            cmdline = lib_nmalloc( size );
            if( (void _WCI86NEAR *) cmdline == NULL ) {
                cmdline = lib_malloc( size );
            }
        #endif
    #else
        cmdline = lib_malloc( size );
    #endif
    argv = NULL;
    argc = 0;
    if( cmdline ) {
        memcpy( cmdline, cmd, len * sizeof(CHAR_TYPE) );
        argv = (void *) ( ( ( char*) cmdline ) + argv_offset );
        argv[0] = exe;
        argc = _SplitParms( historical, cmdline, argv + 1, &endptr ) + 1;
        argv[argc] = NULL;
    }
    *pargc = argc;
    *pargv = argv;
    return( cmdline );
}


static unsigned _SplitParms( int historical, CHAR_TYPE *p, CHAR_TYPE **argv, CHAR_TYPE **endptr )
{
    register unsigned argc;
    register CHAR_TYPE *start;
    register CHAR_TYPE *new;
    enum QUOTE_STATE {
        QUOTE_NONE,             /* no " active in current parm */
        QUOTE_DELIMITER,        /* " was first char and must be last */
        QUOTE_STARTED   /* " was seen, look for a match */
    };
    register enum QUOTE_STATE state;

    argc = 0;
    for(;;) {
        while( *p == ' ' || *p == '\t' ) {
            ++p; /* skip over blanks or tabs */
        }
        if( *p == '\0' ) break;
        /* we are at the start of a parm */
        state = QUOTE_NONE;
        if( *p == '\"' ) {
            p++;
            state = QUOTE_DELIMITER;
        }
        new = start = p;
        for(;;) {
            if( *p == '\"' ) {
                if( !historical ) {
                    p++;
                    if( state == QUOTE_NONE ) {
                        state = QUOTE_STARTED;
                    } else {
                        state = QUOTE_NONE;
                    }
                    continue;
                } else {
                    if( state == QUOTE_DELIMITER ) {
                        break;
                    }
                }
            }
            if( *p == ' ' || *p == '\t' ) {
                if( state == QUOTE_NONE ) {
                    break;
                }
            }
            if( *p == '\0' ) break;
            if( *p == '\\' ) {
                if( !historical ) {
                    if( p[1] == '\"' ) {
                        ++p;
                        if( p[-2] == '\\' ) {
                            continue;
                        }
                    }
                } else {
                    if( p[1] == '\"' || p[1] == '\\' && state == QUOTE_DELIMITER ) {
                        ++p;
                    }
                }
            }
            if( argv ) {
                *(new++) = *p;
            }
            ++p;
        }
        if( argv ) {
            argv[ argc ] = start;
            ++argc;

            /*
              The *new = '\0' is req'd in case there was a \" to "
              translation. It must be after the *p check against
              '\0' because new and p could point to the same char
              in which case the scan would be terminated too soon.
            */

            if( *p == '\0' ) {
                *new = '\0';
                break;
            }
            *new = '\0';
            ++p;
        } else {
            ++argc;
            if( *p == '\0' ) {
                break;
            }
            ++p;
        }
    }
    *endptr = p;
    return( argc );
}

void __F_NAME(__Fini_Argv,__wFini_Argv)( void )
{
    if( __F_NAME(__CmdLine,__wCmdLine) != NULL ) {
        lib_free( __F_NAME(__CmdLine,__wCmdLine) );
    }
}
#endif