From: Zhiyi Zhang zzhang@codeweavers.com
Some filters such as STATUS and CPUTIME are not implemented.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48596 --- programs/tasklist/tasklist.c | 173 ++++++++++++++++++++++++++++- programs/tasklist/tasklist.h | 32 ++++++ programs/tasklist/tasklist.rc | 1 + programs/tasklist/tests/tasklist.c | 97 ++++++++++++++++ 4 files changed, 298 insertions(+), 5 deletions(-)
diff --git a/programs/tasklist/tasklist.c b/programs/tasklist/tasklist.c index ce2028726c9..7c477806142 100644 --- a/programs/tasklist/tasklist.c +++ b/programs/tasklist/tasklist.c @@ -217,6 +217,9 @@ static BOOL tasklist_get_process_info(DWORD pid, struct tasklist_process_info *i wcscpy(info->memory_usage, L"N/A"); }
+ info->pid_value = pid; + info->memory_usage_value = memory_counters.WorkingSetSize / 1024; + info->session_id_value = session_id; swprintf(info->pid, ARRAY_SIZE(info->pid), L"%u", pid); wcscpy(info->session_name, session_id == 0 ? L"Services" : L"Console"); swprintf(info->session_number, ARRAY_SIZE(info->session_number), L"%u", session_id); @@ -227,6 +230,67 @@ done: return ret; }
+static BOOL tasklist_check_filters(const struct tasklist_filter *filter, + const struct tasklist_process_info *info) +{ + DWORD left_dword_operand, right_dword_operand; + const WCHAR *left_string_operand = NULL; + BOOL eval; + + while (filter) + { + left_string_operand = NULL; + left_dword_operand = 0; + eval = FALSE; + + if (filter->name == IMAGENAME) + left_string_operand = info->image_name; + else if (filter->name == SESSIONNAME) + left_string_operand = info->session_name; + else if (filter->name == PID) + left_dword_operand = info->pid_value; + else if (filter->name == SESSION) + left_dword_operand = info->session_id_value; + else if (filter->name == MEMUSAGE) + left_dword_operand = info->memory_usage_value; + + if (left_string_operand) + { + eval = wcsicmp(left_string_operand, filter->value); + if (filter->op == EQ) + eval = !eval; + } + else + { + if (swscanf(filter->value, L"%lu", &right_dword_operand) != 1) + { + WINE_ERR("Invalid filter operand %s.\n", wine_dbgstr_w(filter->value)); + return FALSE; + } + + if (filter->op == EQ) + eval = left_dword_operand == right_dword_operand; + else if (filter->op == NE) + eval = left_dword_operand != right_dword_operand; + else if (filter->op == GT) + eval = left_dword_operand > right_dword_operand; + else if (filter->op == LT) + eval = left_dword_operand < right_dword_operand; + else if (filter->op == GE) + eval = left_dword_operand >= right_dword_operand; + else if (filter->op == LE) + eval = left_dword_operand <= right_dword_operand; + } + + if (!eval) + return FALSE; + + filter = filter->next; + } + + return TRUE; +} + static void tasklist_print(const struct tasklist_options *options) { struct tasklist_process_info header, info; @@ -254,6 +318,9 @@ static void tasklist_print(const struct tasklist_options *options) if (!tasklist_get_process_info(pid_list[i], &info)) continue;
+ if (!tasklist_check_filters(options->filters, &info)) + continue; + if (options->format == TABLE) tasklist_printfW(GetStdHandle(STD_OUTPUT_HANDLE), L"%-25.25s %8.8s %-16.16s %11.11s %12s\r\n", @@ -282,7 +349,9 @@ static void tasklist_print(const struct tasklist_options *options) int __cdecl wmain(int argc, WCHAR *argv[]) { struct tasklist_options options = {0}; - int i; + struct tasklist_filter *filter, *next, **filter_ptr = &options.filters; + WCHAR *filter_name, *filter_op, *buffer; + int i, ret = 0;
for (i = 0; i < argc; i++) WINE_TRACE("%s ", wine_dbgstr_w(argv[i])); @@ -293,7 +362,7 @@ int __cdecl wmain(int argc, WCHAR *argv[]) if (!wcscmp(argv[i], L"/?")) { tasklist_message(STRING_USAGE); - return 0; + goto done; } else if (!wcsicmp(argv[i], L"/nh")) { @@ -304,7 +373,8 @@ int __cdecl wmain(int argc, WCHAR *argv[]) if (i + 1 >= argc) { tasklist_error(STRING_INVALID_SYNTAX); - return 1; + ret = 1; + goto done; } else if (!wcsicmp(argv[i + 1], L"TABLE")) { @@ -321,8 +391,92 @@ int __cdecl wmain(int argc, WCHAR *argv[]) else { tasklist_error(STRING_INVALID_SYNTAX); - return 1; + ret = 1; + goto done; + } + } + else if (!wcsicmp(argv[i], L"/fi")) + { + if (i + 1 >= argc || !(filter_name = wcstok(argv[i + 1], L" ", &buffer))) + { + tasklist_error(STRING_INVALID_SYNTAX); + ret = 1; + goto done; } + + filter = calloc(1, sizeof(*filter)); + if (!filter) + { + WINE_ERR("Out of memory.\n"); + ret = 1; + goto done; + } + + if (!wcsicmp(filter_name, L"IMAGENAME")) + filter->name = IMAGENAME; + else if (!wcsicmp(filter_name, L"PID")) + filter->name = PID; + else if (!wcsicmp(filter_name, L"SESSION")) + filter->name = SESSION; + else if (!wcsicmp(filter_name, L"SESSIONNAME")) + filter->name = SESSIONNAME; + else if (!wcsicmp(filter_name, L"MEMUSAGE")) + filter->name = MEMUSAGE; + else + { + WINE_WARN("Ignoring filter %s.\n", wine_dbgstr_w(filter_name)); + free(filter); + continue; + } + + filter_op = wcstok(NULL, L" ", &buffer); + if (!filter_op) + { + tasklist_error(STRING_FILTER_NOT_RECOGNIZED); + free(filter); + ret = 1; + goto done; + } + + if (!wcsicmp(filter_op, L"EQ")) + filter->op = EQ; + else if (!wcsicmp(filter_op, L"NE")) + filter->op = NE; + else if (!wcsicmp(filter_op, L"GT")) + filter->op = GT; + else if (!wcsicmp(filter_op, L"LT")) + filter->op = LT; + else if (!wcsicmp(filter_op, L"GE")) + filter->op = GE; + else if (!wcsicmp(filter_op, L"LE")) + filter->op = LE; + else + { + tasklist_error(STRING_FILTER_NOT_RECOGNIZED); + free(filter); + ret = 1; + goto done; + } + + if (filter->op >= GT && filter->name != PID && filter->name != SESSION && filter->name != MEMUSAGE) + { + tasklist_error(STRING_FILTER_NOT_RECOGNIZED); + free(filter); + ret = 1; + goto done; + } + + filter->value = wcstok(NULL, L" ", &buffer); + if (!filter->value) + { + tasklist_error(STRING_FILTER_NOT_RECOGNIZED); + free(filter); + ret = 1; + goto done; + } + + *filter_ptr = filter; + filter_ptr = &filter->next; } else { @@ -331,5 +485,14 @@ int __cdecl wmain(int argc, WCHAR *argv[]) }
tasklist_print(&options); - return 0; + +done: + next = options.filters; + while (next) + { + filter = next->next; + free(next); + next = filter; + } + return ret; } diff --git a/programs/tasklist/tasklist.h b/programs/tasklist/tasklist.h index 5e4e90960ea..7b05224757f 100644 --- a/programs/tasklist/tasklist.h +++ b/programs/tasklist/tasklist.h @@ -28,6 +28,7 @@ #define STRING_MEM_USAGE 106 #define STRING_K 107 #define STRING_INVALID_SYNTAX 108 +#define STRING_FILTER_NOT_RECOGNIZED 109
enum tasklist_format { @@ -36,8 +37,38 @@ enum tasklist_format LIST = 2, };
+enum tasklist_filter_name +{ + IMAGENAME = 1, + PID = 2, + SESSION = 3, + SESSIONNAME = 4, + MEMUSAGE = 5, +}; + +enum tasklist_filter_operator +{ + EQ = 0, + NE = 1, + GT = 2, + LT = 3, + GE = 4, + LE = 5, +}; + +struct tasklist_filter +{ + enum tasklist_filter_name name; + enum tasklist_filter_operator op; + WCHAR *value; + struct tasklist_filter *next; +}; + struct tasklist_process_info { + DWORD pid_value; + DWORD memory_usage_value; + DWORD session_id_value; WCHAR image_name[32]; WCHAR pid[32]; WCHAR session_name[32]; @@ -49,4 +80,5 @@ struct tasklist_options { BOOL no_header; enum tasklist_format format; + struct tasklist_filter *filters; }; diff --git a/programs/tasklist/tasklist.rc b/programs/tasklist/tasklist.rc index 10bb965318c..a9ca3f15e91 100644 --- a/programs/tasklist/tasklist.rc +++ b/programs/tasklist/tasklist.rc @@ -33,6 +33,7 @@ STRINGTABLE STRING_MEM_USAGE, "Mem Usage" STRING_K, "K" STRING_INVALID_SYNTAX, "ERROR: Invalid syntax\r\n" + STRING_FILTER_NOT_RECOGNIZED, "ERROR: The search filter cannot be recognized.\r\n" }
#define WINE_FILEDESCRIPTION_STR "Wine tasklist" diff --git a/programs/tasklist/tests/tasklist.c b/programs/tasklist/tests/tasklist.c index 011bfdeb382..d75f361748d 100644 --- a/programs/tasklist/tests/tasklist.c +++ b/programs/tasklist/tests/tasklist.c @@ -164,6 +164,102 @@ static void test_format(void) ok(!!pos, "Failed to list tasklist.exe.\n"); }
+static void test_filter(void) +{ + char options[256], *pos; + DWORD current_pid; + + current_pid = GetCurrentProcessId(); + + /* /fi */ + /* no value for fi */ + run_tasklist("/fi", 1); + ok(stdout_size == 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size > 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + + /* IMAGENAME eq */ + run_tasklist("/fi "IMAGENAME eq tasklist.exe"", 0); + ok(stdout_size > 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size == 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + pos = strstr(stdout_buffer, "tasklist.exe"); + ok(!!pos, "Failed to list tasklist.exe.\n"); + + /* IMAGENAME ne */ + run_tasklist("/fi "IMAGENAME ne explorer.exe"", 0); + ok(stdout_size > 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size == 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + pos = strstr(stdout_buffer, "explorer.exe"); + ok(!pos, "Got explorer.exe.\n"); + pos = strstr(stdout_buffer, "tasklist.exe"); + ok(!!pos, "Failed to list tasklist.exe.\n"); + + /* PID eq */ + sprintf(options, "/fi "PID eq %ld"", current_pid); + run_tasklist(options, 0); + ok(stdout_size > 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size == 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + pos = strstr(stdout_buffer, "tasklist.exe_test.exe"); + ok(!!pos, "Failed to list tasklist.exe_test.exe.\n"); + + /* PID ne */ + sprintf(options, "/fi "PID ne %ld"", current_pid); + run_tasklist(options, 0); + ok(stdout_size > 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size == 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + pos = strstr(stdout_buffer, "tasklist.exe_test.exe"); + ok(!pos, "Got tasklist.exe_test.exe.\n"); + pos = strstr(stdout_buffer, "explorer.exe"); + ok(!!pos, "Failed to list explorer.exe.\n"); + + /* PID gt */ + sprintf(options, "/fi "PID gt %ld"", current_pid - 1); + run_tasklist(options, 0); + ok(stdout_size > 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size == 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + pos = strstr(stdout_buffer, "tasklist.exe_test.exe"); + ok(!!pos, "Failed to list tasklist.exe_test.exe.\n"); + + /* PID lt */ + sprintf(options, "/fi "PID lt %ld"", current_pid + 1); + run_tasklist(options, 0); + ok(stdout_size > 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size == 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + pos = strstr(stdout_buffer, "tasklist.exe_test.exe"); + ok(!!pos, "Failed to list tasklist.exe_test.exe.\n"); + + /* PID ge */ + sprintf(options, "/fi "PID ge %ld"", current_pid); + run_tasklist(options, 0); + ok(stdout_size > 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size == 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + pos = strstr(stdout_buffer, "tasklist.exe_test.exe"); + ok(!!pos, "Failed to list tasklist.exe_test.exe.\n"); + + /* PID le */ + sprintf(options, "/fi "PID le %ld"", current_pid); + run_tasklist(options, 0); + ok(stdout_size > 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size == 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + pos = strstr(stdout_buffer, "tasklist.exe_test.exe"); + ok(!!pos, "Failed to list tasklist.exe_test.exe.\n"); + + /* IMAGENAME eq + PID eq */ + sprintf(options, "/fi "IMAGENAME eq tasklist.exe_test.exe" /fi "PID eq %ld"", current_pid); + run_tasklist(options, 0); + ok(stdout_size > 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size == 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + pos = strstr(stdout_buffer, "tasklist.exe_test.exe"); + ok(!!pos, "Failed to list tasklist.exe_test.exe.\n"); + + /* IMAGENAME eq + PID eq with wrong PID */ + sprintf(options, "/fi "IMAGENAME eq tasklist.exe_test.exe" /fi "PID eq %ld"", current_pid + 1); + run_tasklist(options, 0); + ok(stdout_size > 0, "Unexpected stdout buffer size %ld.\n", stdout_size); + ok(stderr_size == 0, "Unexpected stderr buffer size %ld.\n", stderr_size); + pos = strstr(stdout_buffer, "tasklist.exe_test.exe"); + ok(!pos, "Got tasklist.exe_test.exe.\n"); +} + START_TEST(tasklist) { if (PRIMARYLANGID(GetUserDefaultUILanguage()) != LANG_ENGLISH) @@ -175,4 +271,5 @@ START_TEST(tasklist) test_basic(); test_no_header(); test_format(); + test_filter(); }