mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-30 05:31:39 +00:00
cmd: Split parsing from executing FOR loops for numbers (/L).
Introducing CMD_FOR_CONTROL structure to store parsing output for consumption in execution. Signed-off-by: Eric Pouech <epouech@codeweavers.com>
This commit is contained in:
parent
4a3365daff
commit
9ba05f5e5b
|
@ -1546,8 +1546,8 @@ void WCMD_echo (const WCHAR *args)
|
|||
* first command to be executed may not be at the front of the
|
||||
* commands->thiscommand string (eg. it may point after a DO or ELSE)
|
||||
*/
|
||||
static void WCMD_part_execute(CMD_NODE **cmdList, const WCHAR *firstcmd,
|
||||
BOOL isIF, BOOL executecmds)
|
||||
void WCMD_part_execute(CMD_NODE **cmdList, const WCHAR *firstcmd,
|
||||
BOOL isIF, BOOL executecmds)
|
||||
{
|
||||
CMD_NODE *curPosition = *cmdList;
|
||||
int myDepth = CMD_node_get_depth(*cmdList);
|
||||
|
@ -1850,11 +1850,11 @@ static void WCMD_add_dirstowalk(DIRECTORY_STACK *dirsToWalk)
|
|||
* are recursively passed. If any have duplicates, then the * token should
|
||||
* not be honoured.
|
||||
*/
|
||||
static int WCMD_for_nexttoken(int lasttoken, WCHAR *tokenstr,
|
||||
int *totalfound, BOOL *doall,
|
||||
BOOL *duplicates)
|
||||
int WCMD_for_nexttoken(int lasttoken, const WCHAR *tokenstr,
|
||||
int *totalfound, BOOL *doall,
|
||||
BOOL *duplicates)
|
||||
{
|
||||
WCHAR *pos = tokenstr;
|
||||
const WCHAR *pos = tokenstr;
|
||||
int nexttoken = -1;
|
||||
|
||||
if (totalfound) *totalfound = 0;
|
||||
|
@ -2136,7 +2136,7 @@ static FILE *WCMD_forf_getinput(BOOL usebackq, WCHAR *itemstr, BOOL iscmd)
|
|||
*
|
||||
*/
|
||||
|
||||
void WCMD_for (WCHAR *p, CMD_NODE **cmdList) {
|
||||
static void WCMD_for_OLD (WCHAR *p, CMD_NODE **cmdList) {
|
||||
|
||||
WIN32_FIND_DATAW fd;
|
||||
HANDLE hff;
|
||||
|
@ -2541,6 +2541,32 @@ void WCMD_for (WCHAR *p, CMD_NODE **cmdList) {
|
|||
if (cmdEnd && CMD_node_get_command(cmdEnd)->command == NULL) *cmdList = CMD_node_next(cmdEnd);
|
||||
}
|
||||
|
||||
void WCMD_for(WCHAR *p, CMD_NODE **cmdList)
|
||||
{
|
||||
CMD_FOR_CONTROL *for_ctrl;
|
||||
|
||||
for_ctrl = for_control_parse(p);
|
||||
if (!for_ctrl)
|
||||
{
|
||||
/* temporary code: use OLD code for non migrated FOR constructs */
|
||||
WCMD_for_OLD(p, cmdList);
|
||||
return;
|
||||
}
|
||||
|
||||
for (*cmdList = CMD_node_next(*cmdList); /* swallow options */
|
||||
*cmdList && CMD_node_get_command(*cmdList)->command != NULL;
|
||||
*cmdList = CMD_node_next(*cmdList))
|
||||
{
|
||||
for_control_append_set(for_ctrl, CMD_node_get_command(*cmdList)->command);
|
||||
}
|
||||
|
||||
/* step over terminating NULL CMD_NODE of set */
|
||||
*cmdList = CMD_node_next(*cmdList);
|
||||
|
||||
for_control_execute(for_ctrl, cmdList);
|
||||
for_control_dispose(for_ctrl);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* WCMD_give_help
|
||||
*
|
||||
|
|
|
@ -83,6 +83,14 @@ typedef struct _CMD_IF_CONDITION
|
|||
};
|
||||
} CMD_IF_CONDITION;
|
||||
|
||||
typedef struct _CMD_FOR_CONTROL
|
||||
{
|
||||
enum for_control_operator {CMD_FOR_NUMBERS /* /L */} operator;
|
||||
unsigned flags; /* |-ed CMD_FOR_FLAG_* */
|
||||
int variable_index;
|
||||
const WCHAR *set;
|
||||
} CMD_FOR_CONTROL;
|
||||
|
||||
typedef struct _CMD_COMMAND
|
||||
{
|
||||
WCHAR *command; /* Command string to execute */
|
||||
|
@ -129,6 +137,18 @@ void if_condition_dispose(CMD_IF_CONDITION *);
|
|||
BOOL if_condition_evaluate(CMD_IF_CONDITION *cond, int *test);
|
||||
const char *debugstr_if_condition(const CMD_IF_CONDITION *cond);
|
||||
|
||||
void for_control_create(enum for_control_operator for_op, unsigned flags, const WCHAR *options, int var_idx, CMD_FOR_CONTROL *for_ctrl);
|
||||
CMD_FOR_CONTROL *for_control_parse(WCHAR *opts_var);
|
||||
void for_control_append_set(CMD_FOR_CONTROL *for_ctrl, const WCHAR *string);
|
||||
void for_control_dump(const CMD_FOR_CONTROL *for_ctrl);
|
||||
void for_control_dispose(CMD_FOR_CONTROL *for_ctrl);
|
||||
void for_control_execute(CMD_FOR_CONTROL *for_ctrl, CMD_NODE **cmdList);
|
||||
int WCMD_for_nexttoken(int lasttoken, const WCHAR *tokenstr,
|
||||
int *totalfound, BOOL *doall,
|
||||
BOOL *duplicates);
|
||||
void WCMD_part_execute(CMD_NODE **cmdList, const WCHAR *firstcmd,
|
||||
BOOL isIF, BOOL executecmds);
|
||||
|
||||
void WCMD_assoc (const WCHAR *, BOOL);
|
||||
void WCMD_batch (WCHAR *, WCHAR *, BOOL, WCHAR *, HANDLE);
|
||||
void WCMD_call (WCHAR *command);
|
||||
|
|
|
@ -991,6 +991,65 @@ static void command_dispose(CMD_COMMAND *cmd)
|
|||
}
|
||||
}
|
||||
|
||||
void for_control_dispose(CMD_FOR_CONTROL *for_ctrl)
|
||||
{
|
||||
free((void*)for_ctrl->set);
|
||||
switch (for_ctrl->operator)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char *debugstr_for_control(const CMD_FOR_CONTROL *for_ctrl)
|
||||
{
|
||||
static const char* for_ctrl_strings[] = {"numbers"};
|
||||
const char *flags, *options;
|
||||
|
||||
if (for_ctrl->operator >= ARRAY_SIZE(for_ctrl_strings))
|
||||
{
|
||||
FIXME("Unexpected operator\n");
|
||||
return wine_dbg_sprintf("<<%u>>", for_ctrl->operator);
|
||||
}
|
||||
|
||||
flags = "";
|
||||
switch (for_ctrl->operator)
|
||||
{
|
||||
default:
|
||||
options = "";
|
||||
break;
|
||||
}
|
||||
return wine_dbg_sprintf("[FOR] %s %s%s%%%c (%ls)",
|
||||
for_ctrl_strings[for_ctrl->operator], flags, options,
|
||||
for_var_index_to_char(for_ctrl->variable_index), for_ctrl->set);
|
||||
}
|
||||
|
||||
void for_control_create(enum for_control_operator for_op, unsigned flags, const WCHAR *options, int var_idx, CMD_FOR_CONTROL *for_ctrl)
|
||||
{
|
||||
for_ctrl->operator = for_op;
|
||||
for_ctrl->flags = flags;
|
||||
for_ctrl->variable_index = var_idx;
|
||||
for_ctrl->set = NULL;
|
||||
switch (for_ctrl->operator)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void for_control_append_set(CMD_FOR_CONTROL *for_ctrl, const WCHAR *set)
|
||||
{
|
||||
if (for_ctrl->set)
|
||||
{
|
||||
for_ctrl->set = xrealloc((void*)for_ctrl->set,
|
||||
(wcslen(for_ctrl->set) + 1 + wcslen(set) + 1) * sizeof(WCHAR));
|
||||
wcscat((WCHAR*)for_ctrl->set, L" ");
|
||||
wcscat((WCHAR*)for_ctrl->set, set);
|
||||
}
|
||||
else
|
||||
for_ctrl->set = xstrdupW(set);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* node_dispose_tree
|
||||
*
|
||||
|
@ -2093,6 +2152,70 @@ static BOOL WCMD_IsEndQuote(const WCHAR *quote, int quoteIndex)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
CMD_FOR_CONTROL *for_control_parse(WCHAR *opts_var)
|
||||
{
|
||||
CMD_FOR_CONTROL *for_ctrl;
|
||||
enum for_control_operator for_op;
|
||||
WCHAR mode = L' ', option;
|
||||
WCHAR options[MAXSTRING];
|
||||
WCHAR *arg;
|
||||
unsigned flags = 0;
|
||||
int arg_index;
|
||||
int var_idx;
|
||||
|
||||
options[0] = L'\0';
|
||||
/* native allows two options only in the /D /R case, a repetition of the option
|
||||
* and prints an error otherwise
|
||||
*/
|
||||
for (arg_index = 0; ; arg_index++)
|
||||
{
|
||||
arg = WCMD_parameter(opts_var, arg_index, NULL, FALSE, FALSE);
|
||||
|
||||
if (!arg || *arg != L'/') break;
|
||||
option = towupper(arg[1]);
|
||||
if (mode != L' ' && (mode != L'D' || option != 'R') && mode != option)
|
||||
break;
|
||||
switch (option)
|
||||
{
|
||||
case L'R':
|
||||
if (mode == L'D')
|
||||
{
|
||||
mode = L'X';
|
||||
break;
|
||||
}
|
||||
/* fall thru */
|
||||
case L'D':
|
||||
case L'L':
|
||||
case L'F':
|
||||
mode = option;
|
||||
break;
|
||||
default:
|
||||
/* error unexpected 'arg' at this time */
|
||||
WARN("for qualifier '%c' unhandled\n", *arg);
|
||||
goto syntax_error;
|
||||
}
|
||||
}
|
||||
switch (mode)
|
||||
{
|
||||
case L'L':
|
||||
for_op = CMD_FOR_NUMBERS;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Ensure line continues with variable */
|
||||
arg = WCMD_parameter(opts_var, arg_index++, NULL, FALSE, FALSE);
|
||||
if (!arg || *arg != L'%' || (var_idx = for_var_char_to_index(arg[1])) == -1)
|
||||
goto syntax_error; /* FIXME native prints the offending token "%<whatever>" was unexpected at this time */
|
||||
for_ctrl = xalloc(sizeof(*for_ctrl));
|
||||
for_control_create(for_op, flags, options, var_idx, for_ctrl);
|
||||
return for_ctrl;
|
||||
syntax_error:
|
||||
WCMD_output_stderr(WCMD_LoadMessage(WCMD_SYNTAXERR));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* WCMD_ReadAndParseLine
|
||||
*
|
||||
|
@ -2748,6 +2871,61 @@ void WCMD_set_for_loop_variable(int var_idx, const WCHAR *value)
|
|||
forloopcontext->variable[var_idx] = xstrdupW(value);
|
||||
}
|
||||
|
||||
static CMD_NODE *for_control_execute_numbers(CMD_FOR_CONTROL *for_ctrl, CMD_NODE *cmdList)
|
||||
{
|
||||
WCHAR set[MAXSTRING];
|
||||
CMD_NODE *body = NULL;
|
||||
int numbers[3] = {0, 0, 0}, var;
|
||||
int i;
|
||||
|
||||
wcscpy(set, for_ctrl->set);
|
||||
|
||||
/* Note: native doesn't check the actual number of parameters, and set
|
||||
* them by default to 0.
|
||||
* so (-10 1) is interpreted as (-10 1 0)
|
||||
* and (10) loops for ever !!!
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(numbers); i++)
|
||||
{
|
||||
WCHAR *element = WCMD_parameter(set, i, NULL, FALSE, FALSE);
|
||||
if (!element || !*element) break;
|
||||
/* native doesn't no error handling */
|
||||
numbers[i] = wcstol(element, NULL, 0);
|
||||
}
|
||||
|
||||
for (var = numbers[0];
|
||||
(numbers[1] < 0) ? var >= numbers[2] : var <= numbers[2];
|
||||
var += numbers[1])
|
||||
{
|
||||
WCHAR tmp[32];
|
||||
|
||||
body = cmdList;
|
||||
swprintf(tmp, ARRAY_SIZE(tmp), L"%d", var);
|
||||
WCMD_set_for_loop_variable(for_ctrl->variable_index, tmp);
|
||||
TRACE("Processing FOR number %s\n", wine_dbgstr_w(tmp));
|
||||
WCMD_part_execute(&body, CMD_node_get_command(cmdList)->command + 3, FALSE, TRUE);
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
void for_control_execute(CMD_FOR_CONTROL *for_ctrl, CMD_NODE **cmdList)
|
||||
{
|
||||
CMD_NODE *last;
|
||||
WCMD_save_for_loop_context(FALSE);
|
||||
|
||||
switch (for_ctrl->operator)
|
||||
{
|
||||
case CMD_FOR_NUMBERS:
|
||||
last = for_control_execute_numbers(for_ctrl, *cmdList);
|
||||
break;
|
||||
default:
|
||||
last = NULL;
|
||||
break;
|
||||
}
|
||||
WCMD_restore_for_loop_context();
|
||||
*cmdList = last;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* WCMD_process_commands
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue