mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 09:58:01 +00:00
210 lines
5.7 KiB
C
210 lines
5.7 KiB
C
|
/*
|
||
|
* Implementation of the CmdlineArg abstraction for Windows
|
||
|
*/
|
||
|
|
||
|
#include <wchar.h>
|
||
|
#include "putty.h"
|
||
|
|
||
|
typedef struct CmdlineArgWin CmdlineArgWin;
|
||
|
struct CmdlineArgWin {
|
||
|
/*
|
||
|
* The original wide-character argument.
|
||
|
*/
|
||
|
wchar_t *wide;
|
||
|
|
||
|
/*
|
||
|
* Two translations of the wide-character argument into UTF-8
|
||
|
* (maximally faithful to the original) and CP_ACP (the normal
|
||
|
* system code page).
|
||
|
*/
|
||
|
char *utf8, *acp;
|
||
|
|
||
|
/*
|
||
|
* Our index in the CmdlineArgList, or (size_t)-1 if we don't have
|
||
|
* one and are an argument invented later.
|
||
|
*/
|
||
|
size_t index;
|
||
|
|
||
|
/*
|
||
|
* Public part of the structure.
|
||
|
*/
|
||
|
CmdlineArg argp;
|
||
|
};
|
||
|
|
||
|
typedef struct CmdlineArgListWin CmdlineArgListWin;
|
||
|
struct CmdlineArgListWin {
|
||
|
/*
|
||
|
* Wide string pointer returned from GetCommandLineW. This points
|
||
|
* to the 'official' version of the command line, in the sense
|
||
|
* that overwriting it causes different text to show up in the
|
||
|
* Task Manager display of the process's command line. (So this is
|
||
|
* what we'll need to overwrite _on purpose_ for cmdline_arg_wipe.)
|
||
|
*/
|
||
|
wchar_t *cmdline;
|
||
|
|
||
|
/*
|
||
|
* Data returned from split_into_argv_w.
|
||
|
*/
|
||
|
size_t argc;
|
||
|
wchar_t **argv, **argstart;
|
||
|
|
||
|
/*
|
||
|
* Public part of the structure.
|
||
|
*/
|
||
|
CmdlineArgList listp;
|
||
|
};
|
||
|
|
||
|
static CmdlineArgWin *cmdline_arg_new_in_list(CmdlineArgList *listp)
|
||
|
{
|
||
|
CmdlineArgWin *arg = snew(CmdlineArgWin);
|
||
|
arg->wide = NULL;
|
||
|
arg->utf8 = arg->acp = NULL;
|
||
|
arg->index = (size_t)-1;
|
||
|
arg->argp.list = listp;
|
||
|
sgrowarray(listp->args, listp->argssize, listp->nargs);
|
||
|
listp->args[listp->nargs++] = &arg->argp;
|
||
|
return arg;
|
||
|
}
|
||
|
|
||
|
static CmdlineArg *cmdline_arg_from_wide_argv_word(
|
||
|
CmdlineArgList *list, wchar_t *word)
|
||
|
{
|
||
|
CmdlineArgWin *arg = cmdline_arg_new_in_list(list);
|
||
|
arg->wide = dupwcs(word);
|
||
|
arg->utf8 = dup_wc_to_mb(CP_UTF8, word, "");
|
||
|
arg->acp = dup_wc_to_mb(CP_ACP, word, "");
|
||
|
return &arg->argp;
|
||
|
}
|
||
|
|
||
|
CmdlineArgList *cmdline_arg_list_from_GetCommandLineW(void)
|
||
|
{
|
||
|
CmdlineArgListWin *list = snew(CmdlineArgListWin);
|
||
|
CmdlineArgList *listp = &list->listp;
|
||
|
|
||
|
list->cmdline = GetCommandLineW();
|
||
|
|
||
|
int argc;
|
||
|
split_into_argv_w(list->cmdline, true,
|
||
|
&argc, &list->argv, &list->argstart);
|
||
|
list->argc = (size_t)argc;
|
||
|
|
||
|
listp->args = NULL;
|
||
|
listp->nargs = listp->argssize = 0;
|
||
|
for (size_t i = 1; i < list->argc; i++) {
|
||
|
CmdlineArg *argp = cmdline_arg_from_wide_argv_word(
|
||
|
listp, list->argv[i]);
|
||
|
CmdlineArgWin *arg = container_of(argp, CmdlineArgWin, argp);
|
||
|
arg->index = i - 1; /* index in list->args[], not in argv[] */
|
||
|
}
|
||
|
sgrowarray(listp->args, listp->argssize, listp->nargs);
|
||
|
listp->args[listp->nargs++] = NULL;
|
||
|
return listp;
|
||
|
}
|
||
|
|
||
|
void cmdline_arg_free(CmdlineArg *argp)
|
||
|
{
|
||
|
if (!argp)
|
||
|
return;
|
||
|
|
||
|
CmdlineArgWin *arg = container_of(argp, CmdlineArgWin, argp);
|
||
|
burnwcs(arg->wide);
|
||
|
burnstr(arg->utf8);
|
||
|
burnstr(arg->acp);
|
||
|
sfree(arg);
|
||
|
}
|
||
|
|
||
|
void cmdline_arg_list_free(CmdlineArgList *listp)
|
||
|
{
|
||
|
CmdlineArgListWin *list = container_of(listp, CmdlineArgListWin, listp);
|
||
|
for (size_t i = 0; i < listp->nargs; i++)
|
||
|
cmdline_arg_free(listp->args[i]);
|
||
|
/* list->argv[0] points at the start of the string allocated by
|
||
|
* split_into_argv_w */
|
||
|
sfree(list->argv[0]);
|
||
|
sfree(list->argv);
|
||
|
sfree(list->argstart);
|
||
|
sfree(list);
|
||
|
}
|
||
|
|
||
|
CmdlineArg *cmdline_arg_from_str(CmdlineArgList *listp, const char *string)
|
||
|
{
|
||
|
CmdlineArgWin *arg = cmdline_arg_new_in_list(listp);
|
||
|
arg->acp = dupstr(string);
|
||
|
arg->wide = dup_mb_to_wc(CP_ACP, string);
|
||
|
arg->utf8 = dup_wc_to_mb(CP_UTF8, arg->wide, "");
|
||
|
return &arg->argp;
|
||
|
}
|
||
|
|
||
|
CmdlineArg *cmdline_arg_from_utf8(CmdlineArgList *listp, const char *string)
|
||
|
{
|
||
|
CmdlineArgWin *arg = cmdline_arg_new_in_list(listp);
|
||
|
arg->acp = dupstr(string);
|
||
|
arg->wide = dup_mb_to_wc(CP_UTF8, string);
|
||
|
arg->utf8 = dup_wc_to_mb(CP_ACP, arg->wide, "");
|
||
|
return &arg->argp;
|
||
|
}
|
||
|
|
||
|
const char *cmdline_arg_to_str(CmdlineArg *argp)
|
||
|
{
|
||
|
if (!argp)
|
||
|
return NULL;
|
||
|
|
||
|
CmdlineArgWin *arg = container_of(argp, CmdlineArgWin, argp);
|
||
|
return arg->acp;
|
||
|
}
|
||
|
|
||
|
const char *cmdline_arg_to_utf8(CmdlineArg *argp)
|
||
|
{
|
||
|
if (!argp)
|
||
|
return NULL;
|
||
|
|
||
|
CmdlineArgWin *arg = container_of(argp, CmdlineArgWin, argp);
|
||
|
return arg->utf8;
|
||
|
}
|
||
|
|
||
|
void cmdline_arg_wipe(CmdlineArg *argp)
|
||
|
{
|
||
|
if (!argp)
|
||
|
return;
|
||
|
|
||
|
CmdlineArgWin *arg = container_of(argp, CmdlineArgWin, argp);
|
||
|
if (arg->index != (size_t)-1) {
|
||
|
CmdlineArgList *listp = argp->list;
|
||
|
CmdlineArgListWin *list = container_of(
|
||
|
listp, CmdlineArgListWin, listp);
|
||
|
|
||
|
/* arg->index starts from the first argument _after_ program
|
||
|
* name, whereas argstart is indexed from argv[0] */
|
||
|
wchar_t *p = list->argstart[arg->index + 1];
|
||
|
wchar_t *end = (arg->index + 2 < list->argc ?
|
||
|
list->argstart[arg->index + 2] :
|
||
|
p + wcslen(p));
|
||
|
while (p < end)
|
||
|
*p++ = L' ';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const wchar_t *cmdline_arg_remainder_wide(CmdlineArg *argp)
|
||
|
{
|
||
|
CmdlineArgWin *arg = container_of(argp, CmdlineArgWin, argp);
|
||
|
CmdlineArgList *listp = argp->list;
|
||
|
CmdlineArgListWin *list = container_of(listp, CmdlineArgListWin, listp);
|
||
|
|
||
|
size_t index = arg->index;
|
||
|
assert(index != (size_t)-1);
|
||
|
|
||
|
/* arg->index starts from the first argument _after_ program
|
||
|
* name, whereas argstart is indexed from argv[0] */
|
||
|
return list->argstart[index + 1];
|
||
|
}
|
||
|
|
||
|
char *cmdline_arg_remainder_acp(CmdlineArg *argp)
|
||
|
{
|
||
|
return dup_wc_to_mb(CP_ACP, cmdline_arg_remainder_wide(argp), "");
|
||
|
}
|
||
|
|
||
|
char *cmdline_arg_remainder_utf8(CmdlineArg *argp)
|
||
|
{
|
||
|
return dup_wc_to_mb(CP_UTF8, cmdline_arg_remainder_wide(argp), "");
|
||
|
}
|