#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

static int _makeargv(char const* s, char const*** argv);
static char * _test( char * );

static int trace = 1;

int main( int argc, char * argv[] )
{
  _test( "sh -c '\"perl g:\\vol1\\bin\\dos\\this\\perl.perl\"'" );
  while ( --argc > 0 ) 
    {
      _test( argv[argc] );
    }
}

static char * _test( char * command )
{
    char const** argv;
    char* args;

    if ((args = strdup(command)) == NULL) return NULL;
    if (_makeargv(args, &argv) < 0) return NULL;

    if (trace) 
    {
      int argc;

      fprintf( stdout, "(trace) os2_popen( '%s', '%s' ) -> _makeargv() will mangle\n", command, "mode" );
      fprintf( stdout, "(trace) results of _makeargv()\n" );
      for (argc=1; argv[argc]; argc++ )
        {
          fprintf( stdout, "argv[%d] -> '%s'\n", argc, argv[argc] );
        }
    }
    return NULL;
}



static int _makeargv(char const* s, char const*** argv)
{
    int inquote = 0;
    int argc = 1, maxargc = 0;
    char* q;
    char const* p;

    if ((q = strdup(s)) == NULL) {
        errno = ENOMEM;
        return -1;
    }
    *argv = NULL;
    for (p = s; *p != '\0'; ) {
        char const* arg;
        while (isspace(*p))
            ++p;

        /* Eat One Argv */
        for (arg = q; *p != '\0' && (inquote || !isspace(*p)); p++) 
        {
            if (*p == '\"' || *p == '\'' || *p == '`') /* Begin quote */
            {
                inquote ^= *p;
                /* !first_quote&&!last_quote */
                if (inquote != *p && inquote) *q++ = *p; /* keep quote */
            }
            else if (inquote == '\"' && *p == '\\') 
            {
                /* Perl 'style' only handle \\ replacement if 
                   inside ", otherwise treat as a literal     */
                switch (*++p) 
                {
                  case 'a':  *q++ = '\a'; break;
                  case 'b':  *q++ = '\b'; break;
                  case 'f':  *q++ = '\f'; break;
                  case 'n':  *q++ = '\n'; break;
                  case 'r':  *q++ = '\r'; break;
                  case 't':  *q++ = '\t'; break;
                  case 'v':  *q++ = '\v'; break;
                  case '\\': *q++ = '\\'; break;
                  case '\'': *q++ = '\''; break;
                  case '\"': *q++ = '\"'; break;
                  default:   *q++ = '\\'; /* copy it forward, bogus escape */
                             *q++ = *p;   break;
                }
            }
            else
            {
                *q++ = *p;
            }

#if 0
            if (*p == '"' || *p == '\'') 
            {
                if (*p == inquote)
                    inquote = 0;
                else if (!inquote)
                    inquote = *p;
                else
                    *q++ = '"' /**p*/;
            }
            else if (*p == '\\') {
                if (*++p == '\\')
                    *q++ = '\\', ++p;
                else if (*p == inquote)
                    *q++ = inquote, ++p;
                else switch (*p) {
                    case 'a': *q++ = '\a'; break;
                    case 'b': *q++ = '\b'; break;
                    case 'f': *q++ = '\f'; break;
                    case 'n': *q++ = '\n'; break;
                    case 'r': *q++ = '\r'; break;
                    case 't': *q++ = '\t'; break;
                    case 'v': *q++ = '\v'; break;
                    default:
                            if (!inquote || *p != inquote)
                                    *q++ = '\\';
                            *q++ = *p;
                            break;
                }
            }
            else
                *q++ = *p;
#endif
        }
        *q++ = '\0';
        if (argc+1 >= maxargc) {
            char const** newargv;
            maxargc += 10;
            newargv = realloc(*argv, maxargc*sizeof(char const*));
            if (newargv == NULL) {
                if (argc > 1)
                    free((void*)(*argv)[0]);
                errno = ENOMEM;
                return -1;
            }
            *argv = newargv;
        }
        (*argv)[argc++] = arg;
    }
    (*argv)[0] = (*argv)[argc] = NULL;
    return argc;
}

