Parse string into argv/argc

前端 未结 13 875
生来不讨喜
生来不讨喜 2020-11-28 07:45

Is there a way in C to parse a piece of text and obtain values for argv and argc, as if the text had been passed to an application on the command line?

This doesn\'

13条回答
  •  挽巷
    挽巷 (楼主)
    2020-11-28 08:12

    Here's a solution for both Windows and Unix (tested on Linux, OSX and Windows). Tested with Valgrind and Dr. Memory.

    It uses wordexp for POSIX systems, and CommandLineToArgvW for Windows.

    Note that for the Windows solution, most of the code is converting between char ** and wchar_t ** with the beautiful Win32 API, since there is no CommandLineToArgvA available (ANSI-version).

    #ifdef _WIN32
    #include 
    #else
    #include 
    #endif
    
    char **split_commandline(const char *cmdline, int *argc)
    {
        int i;
        char **argv = NULL;
        assert(argc);
    
        if (!cmdline)
        {
            return NULL;
        }
    
        // Posix.
        #ifndef _WIN32
        {
            wordexp_t p;
    
            // Note! This expands shell variables.
            if (wordexp(cmdline, &p, 0))
            {
                return NULL;
            }
    
            *argc = p.we_wordc;
    
            if (!(argv = calloc(*argc, sizeof(char *))))
            {
                goto fail;
            }
    
            for (i = 0; i < p.we_wordc; i++)
            {
                if (!(argv[i] = strdup(p.we_wordv[i])))
                {
                    goto fail;
                }
            }
    
            wordfree(&p);
    
            return argv;
        fail:
            wordfree(&p);
        }
        #else // WIN32
        {
            wchar_t **wargs = NULL;
            size_t needed = 0;
            wchar_t *cmdlinew = NULL;
            size_t len = strlen(cmdline) + 1;
    
            if (!(cmdlinew = calloc(len, sizeof(wchar_t))))
                goto fail;
    
            if (!MultiByteToWideChar(CP_ACP, 0, cmdline, -1, cmdlinew, len))
                goto fail;
    
            if (!(wargs = CommandLineToArgvW(cmdlinew, argc)))
                goto fail;
    
            if (!(argv = calloc(*argc, sizeof(char *))))
                goto fail;
    
            // Convert from wchar_t * to ANSI char *
            for (i = 0; i < *argc; i++)
            {
                // Get the size needed for the target buffer.
                // CP_ACP = Ansi Codepage.
                needed = WideCharToMultiByte(CP_ACP, 0, wargs[i], -1,
                                            NULL, 0, NULL, NULL);
    
                if (!(argv[i] = malloc(needed)))
                    goto fail;
    
                // Do the conversion.
                needed = WideCharToMultiByte(CP_ACP, 0, wargs[i], -1,
                                            argv[i], needed, NULL, NULL);
            }
    
            if (wargs) LocalFree(wargs);
            if (cmdlinew) free(cmdlinew);
            return argv;
    
        fail:
            if (wargs) LocalFree(wargs);
            if (cmdlinew) free(cmdlinew);
        }
        #endif // WIN32
    
        if (argv)
        {
            for (i = 0; i < *argc; i++)
            {
                if (argv[i])
                {
                    free(argv[i]);
                }
            }
    
            free(argv);
        }
    
        return NULL;
    }
    

提交回复
热议问题