Application for GSoC 2015 - Implement findstr.exe for Wine.

Kaipeng Zeng kaipeng94 at gmail.com
Sun Apr 19 08:05:56 CDT 2015


Hi folks Hi Stefan,

Thanks for your suggestions. I have imporved it in the new
version.Attachmentes are my new patches.
In 0001, there are more tests for findstr. 0002 is an initial
implementation of findstr. Though it can deal
with some cases it is still very very simple.

I will try to improve it for much work.
Should I send the first patch to wine-devel first?

Any comment will be appreciated!
Thanks again!

2015-03-25 19:42 GMT+08:00 KaiPeng Zeng <kaipeng94 at gmail.com>:

> Hi folks,
>
> I’m Kaipeng Zeng who is a Linux user and Wine/CrossOver user from China. I
> am major
> in Biomedical Engineering in Guangdong Pharmaceutical University.
>
> I’d like to apply GSoC to work for Wine Project this year. My proposal is
> "Implementing
> findstr.exe for Wine".
>
> Though findstr is a quite independent program in Wine, I think it is
> valuable to implement.
> As far as I knew, there are some bugs about findstr in Bugzilla[1]. Any
> other programs
> in Chinese depend on it too. The implementation of findstr will help these
> programs and
> all the programs will also be good tests for our implementation. Besides,
> I think the code
> of grep will be helpful for implementing findstr.
>
> There are three parts in my plan:
> === Part 1: Add more tests for findstr.exe ===
> I have submitted a patch for findstr’s test to wine-patches[2]. I will add
> more tests to
> prepare for the implementation.
>
> === Part 2: Implement an initial findstr.exe ===
> With enough tests, I will try to implement the findstr gradually. My
> middle goal is having
> an initial implementation of findstr which can handle some simple work.
> Bug 35254[3] may
> be fixed after this part is finished.
>
> === Part 3: Add more parameters implementation ===
> In this part, I will add more tests and try to implement more arguments
> for findstr, let it
> solve more things.
>
>
> [1] https://bugs.winehq.org/buglist.cgi?quicksearch=findstr&list_id=178519
> [2] http://source.winehq.org/patches/data/110182
> [3] https://bugs.winehq.org/show_bug.cgi
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.winehq.org/pipermail/wine-devel/attachments/20150419/7a1e97cb/attachment-0001.html>
-------------- next part --------------
From a189a411dc1fa0b326d0d281c3a7f1f40be1c3a8 Mon Sep 17 00:00:00 2001
From: Kaipeng Zeng <kaipeng94 at gmail.com>
Date: Sun, 19 Apr 2015 10:35:58 +0800
Subject: [PATCH 1/2] findstr: Added tests for findstr.

---
 configure.ac                       |   1 +
 programs/findstr/tests/Makefile.in |   5 ++
 programs/findstr/tests/findstr.c   | 164 +++++++++++++++++++++++++++++++++++++
 3 files changed, 170 insertions(+)
 create mode 100644 programs/findstr/tests/Makefile.in
 create mode 100644 programs/findstr/tests/findstr.c

diff --git a/configure.ac b/configure.ac
index d23227a..822affe 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3432,6 +3432,7 @@ WINE_CONFIG_PROGRAM(expand,,[install])
 WINE_CONFIG_PROGRAM(explorer,,[install,po])
 WINE_CONFIG_PROGRAM(extrac32,,[install])
 WINE_CONFIG_PROGRAM(findstr,,[install])
+WINE_CONFIG_TEST(programs/findstr/tests)
 WINE_CONFIG_PROGRAM(hh,,[install])
 WINE_CONFIG_PROGRAM(hostname,,[install,po])
 WINE_CONFIG_PROGRAM(icinfo,,[install])
diff --git a/programs/findstr/tests/Makefile.in b/programs/findstr/tests/Makefile.in
new file mode 100644
index 0000000..b5195d0
--- /dev/null
+++ b/programs/findstr/tests/Makefile.in
@@ -0,0 +1,5 @@
+TESTDLL   = findstr.exe
+
+C_SRCS = \
+       findstr.c
+
diff --git a/programs/findstr/tests/findstr.c b/programs/findstr/tests/findstr.c
new file mode 100644
index 0000000..705fd89
--- /dev/null
+++ b/programs/findstr/tests/findstr.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2015 Kaipeng Zeng
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <windows.h>
+
+#include "wine/test.h"
+
+
+static DWORD runcmd(const char *cmd, LPCSTR *output)
+{
+    char *wcmd;
+    SECURITY_ATTRIBUTES sa = {sizeof(sa), 0, TRUE};
+    HANDLE outfile, hRead;
+    STARTUPINFOA si = {sizeof(si)};
+    PROCESS_INFORMATION pi;
+    DWORD filesize, result, bytesRead;
+
+    wcmd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, strlen(cmd) + 1);
+    if(!wcmd)
+        return 260;
+    strcpy(wcmd, cmd);
+
+    outfile = CreateFileA("test.out", GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, &sa,
+                          CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    ok(outfile != INVALID_HANDLE_VALUE, "CreateFile failed.\n");
+    if(outfile == INVALID_HANDLE_VALUE)
+        return 260;
+
+    si.hStdOutput = outfile;
+    si.dwFlags = STARTF_USESTDHANDLES;
+    if(!CreateProcessA(NULL, wcmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
+    {
+        HeapFree(GetProcessHeap(), 0, wcmd);
+        CloseHandle(outfile);
+        return 260;
+    }
+    HeapFree(GetProcessHeap(), 0, wcmd);
+
+    WaitForSingleObject(pi.hProcess, INFINITE);
+    GetExitCodeProcess(pi.hProcess, &result);
+    CloseHandle(outfile);
+    CloseHandle(pi.hThread);
+    CloseHandle(pi.hProcess);
+
+    hRead = CreateFileA("test.out", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
+    ok(hRead != INVALID_HANDLE_VALUE, "CreateFile failed.\n");
+    if(hRead == INVALID_HANDLE_VALUE)
+        return 260;
+    filesize = GetFileSize(hRead, NULL);
+    *output = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, filesize + 1);
+    if(!*output)
+        return 260;
+    ReadFile(hRead, (LPVOID)*output, filesize, &bytesRead, NULL);
+    CloseHandle(hRead);
+
+    return result;
+}
+
+static void create_file(char *buffer)
+{
+    char text_for_test[] = "Wine Is Not an Emulator.\n"
+                           "Wine will always be free software.\n"
+                           "Wine is heavily reliant on its user community too.";
+    HANDLE file;
+    DWORD dwBytesWritten = 0;
+    char path[1024],filename[1024];
+
+    GetTempPathA(1024, path);
+    GetTempFileNameA(path, "fst", 9, filename);
+    strcpy(buffer, filename);
+    file = CreateFileA(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL,
+                       CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    ok(file != INVALID_HANDLE_VALUE, "CreateFile failed.\n");
+    ok(WriteFile(file, text_for_test, strlen(text_for_test) * sizeof(CHAR),
+                 &dwBytesWritten, NULL), "WriteFile failed: 0x%08x\n.", GetLastError());
+    CloseHandle(file);
+}
+
+static LPCSTR generate_cmdline(const char *keyword, char *filename)
+{
+    char *cmdline;
+
+    cmdline = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, strlen(keyword) + strlen(filename) + 11);
+    strcat(cmdline, "findstr ");
+    strcat(cmdline, keyword);
+    strcat(cmdline, " ");
+    strcat(cmdline, filename);
+    return cmdline;
+}
+
+static void cleanup(LPCSTR *buffer, LPCSTR *cmdline)
+{
+    HeapFree(GetProcessHeap(), 0, (LPVOID)*buffer);
+    HeapFree(GetProcessHeap(), 0, (LPVOID)*cmdline);
+    DeleteFileA("test.out");
+}
+
+static void test_without_arg(void)
+{
+    char filename[MAX_PATH];
+    LPCSTR buffer;
+    LPCSTR cmdline;
+    int res;
+
+    create_file(filename);
+
+    cmdline = generate_cmdline("free", filename);
+    res = runcmd(cmdline, &buffer);
+    todo_wine ok(!res, "Return %d expected 0.\n", res);
+    todo_wine ok(!strcmp(buffer, "Wine will always be free software.\n"),
+       "Return wrong string: %s.\n", buffer);
+    cleanup(&buffer, &cmdline);
+
+    cmdline = generate_cmdline("", filename);
+    res = runcmd(cmdline, &buffer);
+    todo_wine ok(res == 1, "Return %d expected 1.\n", res);
+    todo_wine ok(!strcmp(buffer, ""),
+       "Return wrong string: %s.\n", buffer);
+    cleanup(&buffer, &cmdline);
+
+    cmdline = generate_cmdline("Free", filename);
+    res = runcmd(cmdline, &buffer);
+    todo_wine ok(res == 1, "Return %d expected 1.\n", res);
+    todo_wine ok(!strcmp(buffer, ""),
+       "Return wrong string: %s.\n", buffer);
+    cleanup(&buffer, &cmdline);
+
+    cmdline = generate_cmdline("omg", filename);
+    res = runcmd(cmdline, &buffer);
+    todo_wine ok(res == 1, "Return %d expected 1.\n", res);
+    todo_wine ok(!strcmp(buffer, ""),
+       "Return wrong string: %s.\n", buffer);
+    cleanup(&buffer, &cmdline);
+
+    cmdline = generate_cmdline("Wine", filename);
+    res = runcmd(cmdline, &buffer);
+    todo_wine ok(!res, "Return %d expected 0.\n", res);
+    todo_wine ok(!strcmp(buffer, "Wine Is Not an Emulator.\nWine will always be free software.\n"
+               "Wine is heavily reliant on its user community too."),
+       "Return wrong string: %s.\n", buffer);
+    cleanup(&buffer, &cmdline);
+
+    DeleteFileA(filename);
+}
+
+START_TEST(findstr)
+{
+    test_without_arg();
+}
-- 
2.1.0

-------------- next part --------------
From 985e187fdbd1d9331c87118f863d7e69e578f6a8 Mon Sep 17 00:00:00 2001
From: Kaipeng Zeng <kaipeng94 at gmail.com>
Date: Sun, 19 Apr 2015 10:40:11 +0800
Subject: [PATCH 2/2] findstr: Added initial implementation.

---
 programs/findstr/Makefile.in     |   2 +-
 programs/findstr/findstr.h       |  26 ++++++++
 programs/findstr/main.c          | 137 ++++++++++++++++++++++++++++++++++++---
 programs/findstr/tests/findstr.c |  20 +++---
 4 files changed, 166 insertions(+), 19 deletions(-)
 create mode 100644 programs/findstr/findstr.h

diff --git a/programs/findstr/Makefile.in b/programs/findstr/Makefile.in
index 10875af..a919538 100644
--- a/programs/findstr/Makefile.in
+++ b/programs/findstr/Makefile.in
@@ -1,5 +1,5 @@
 MODULE    = findstr.exe
-APPMODE   = -mconsole -municode
+APPMODE   = -mconsole -municode -mno-cygwin
 
 C_SRCS = \
 	main.c
diff --git a/programs/findstr/findstr.h b/programs/findstr/findstr.h
new file mode 100644
index 0000000..0f0289b
--- /dev/null
+++ b/programs/findstr/findstr.h
@@ -0,0 +1,26 @@
+#include <windef.h>
+
+#define OPT_B       0x00000001
+#define OPT_E       0x00000002
+#define OPT_L       0x00000004
+#define OPT_R       0x00000008
+#define OPT_P       0x00000010
+#define OPT_S       0x00000020
+#define OPT_I       0x00000040
+#define OPT_X       0x00000080
+#define OPT_V       0x00000100
+#define OPT_N       0x00000200
+#define OPT_M       0x00000400
+#define OPT_O       0x00000800
+#define OPT_OF      0x00001000
+#define OPT_A       0x00002000
+#define OPT_DEFAULT 0x00004000
+
+#define MAXSTRING 8192
+
+typedef struct {
+    LPWSTR words;
+    LPWSTR *files;
+    LONG file_count;
+    DWORD flags;
+} findstr_cmd;
diff --git a/programs/findstr/main.c b/programs/findstr/main.c
index de5de33..af0af18 100644
--- a/programs/findstr/main.c
+++ b/programs/findstr/main.c
@@ -1,5 +1,6 @@
 /*
  * Copyright 2012 Qian Hong
+ * Copyright 2015 Kaipeng Zeng
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -16,18 +17,138 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#include "wine/debug.h"
+#include <stdio.h>
+#include <windows.h>
+#include <wine/debug.h>
+#include <wine/unicode.h>
+#include <windows.h>
+#include "findstr.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(findstr);
 
-int wmain(int argc, WCHAR *argv[])
+
+static int findstr_wprintf(const WCHAR *format, ...)
+{
+    static char output_bufA[65536];
+    static WCHAR output_bufW[sizeof(output_bufA) / sizeof(WCHAR)];
+    va_list parms;
+    DWORD nOut;
+    BOOL res = FALSE;
+    HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
+
+    va_start(parms, format);
+    vsnprintfW(output_bufW, sizeof(output_bufW), format, parms);
+    va_end(parms);
+
+    /* Try to write as unicode whenever we think it's a console */
+    if(((DWORD_PTR)hout & 3) == 3)
+    {
+        res = WriteConsoleW(hout, output_bufW, strlenW(output_bufW), &nOut, NULL);
+    }
+    else
+    {
+        DWORD convertedChars;
+
+        /* Convert to OEM, then output */
+        convertedChars = WideCharToMultiByte(GetConsoleOutputCP(), 0, output_bufW, -1,
+                                             output_bufA, sizeof(output_bufA),
+                                             NULL, NULL);
+        res = WriteFile(hout, output_bufA, convertedChars, &nOut, FALSE);
+    }
+
+    return res ? nOut : 0;
+}
+
+int match_pattern(findstr_cmd cmd)
 {
-    int i;
+    FILE *read_file;
+    WCHAR line[MAXSTRING] = {0};
+    int i = 0,ret = 1;
+    WCHAR readTextMode[] = {'r','t',0};
+    WCHAR fileNoExistErr[] = {'C', 'a', 'n', '\'', 't', ' ', 'f', 'i', 'n', 'd', ' ',
+                              'f', 'i', 'l', 'e', ' ', ':', ' ', 0};
+    WCHAR newline[] = {'\n', 0};
+    WCHAR *output;
 
-    WINE_FIXME("stub:");
-    for (i = 0; i < argc; i++)
-        WINE_FIXME(" %s", wine_dbgstr_w(argv[i]));
-    WINE_FIXME("\n");
+    output =  HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 65535);
+    for(i = 0; i < cmd.file_count; i++)
+    {
+        if(!(read_file = _wfopen(cmd.files[i], readTextMode)))
+        {
+            lstrcatW(output, fileNoExistErr);
+            lstrcatW(output, cmd.files[i]);
+            lstrcatW(output, newline);
+            continue;
+        }
+        while(fgetws(line, MAXSTRING, read_file ) != NULL)
+        {
+            if(wcsstr(line, cmd.words) != NULL)
+            {
+                TRACE("%s\n", debugstr_w(line));
+                lstrcatW(output, line);
+                ret = 0;
+            }
+        }
+    }
+    findstr_wprintf(output);
+    HeapFree(GetProcessHeap(), 0, output);
+    return ret;
+}
+
+static findstr_cmd parse_cmd(int argc, WCHAR *argv[])
+{
+    int  i, j;
+    findstr_cmd cmd;
+
+    cmd.flags = OPT_DEFAULT;
+    cmd.words = NULL;
+    cmd.files = NULL;
+    cmd.file_count = argc - 1;
+
+    for(i = 1; i < argc; i++)
+    {
+        if(argv[i][0] == '/')
+        {
+            cmd.file_count--;
+            for(j = 1; j < lstrlenW(argv[i]); j++)
+            {
+                switch(argv[i][j])
+                {
+                    case 'B':case 'b': cmd.flags |= OPT_B; break;
+                    case 'E':case 'e': cmd.flags |= OPT_E; break;
+                    case 'L':case 'l': cmd.flags |= OPT_L; break;
+                    case 'R':case 'r': cmd.flags |= OPT_R; break;
+                    case 'P':case 'p': cmd.flags |= OPT_P; break;
+                    case 'S':case 's': cmd.flags |= OPT_S; break;
+                    case 'I':case 'i': cmd.flags |= OPT_I; break;
+                    case 'X':case 'x': cmd.flags |= OPT_X; break;
+                    case 'V':case 'v': cmd.flags |= OPT_V; break;
+                    case 'N':case 'n': cmd.flags |= OPT_N; break;
+                    case 'M':case 'm': cmd.flags |= OPT_M; break;
+                    case 'O':case 'o': cmd.flags |= OPT_O; break;
+                    case 'A':case 'a': cmd.flags |= OPT_A; break;
+                }
+            }
+        }
+        else if(!cmd.words)
+        {
+            cmd.file_count--;
+            cmd.words = &argv[i][0];
+        }
+        else if(!cmd.files)
+            cmd.files = &argv[i];
+    }
+    TRACE("Option flags is 0x%08x, words: %s, intput files: ", cmd.flags, debugstr_w(cmd.words));
+    for(i = 0; i < cmd.file_count; i++)
+        TRACE("%s ", debugstr_w(cmd.files[i]));
+    TRACE("\n");
+    return cmd;
+}
+
+int wmain(int argc, WCHAR *argv[])
+{
+    findstr_cmd cmd;
 
-    return 0;
+    cmd = parse_cmd(argc, &argv[0]);
+    return match_pattern(cmd);
 }
diff --git a/programs/findstr/tests/findstr.c b/programs/findstr/tests/findstr.c
index 705fd89..2b46d14 100644
--- a/programs/findstr/tests/findstr.c
+++ b/programs/findstr/tests/findstr.c
@@ -121,36 +121,36 @@ static void test_without_arg(void)
 
     cmdline = generate_cmdline("free", filename);
     res = runcmd(cmdline, &buffer);
-    todo_wine ok(!res, "Return %d expected 0.\n", res);
-    todo_wine ok(!strcmp(buffer, "Wine will always be free software.\n"),
+    ok(!res, "Return %d expected 0.\n", res);
+    ok(!strcmp(buffer, "Wine will always be free software.\n"),
        "Return wrong string: %s.\n", buffer);
     cleanup(&buffer, &cmdline);
 
     cmdline = generate_cmdline("", filename);
     res = runcmd(cmdline, &buffer);
-    todo_wine ok(res == 1, "Return %d expected 1.\n", res);
-    todo_wine ok(!strcmp(buffer, ""),
+    ok(res == 1, "Return %d expected 1.\n", res);
+    ok(!strcmp(buffer, ""),
        "Return wrong string: %s.\n", buffer);
     cleanup(&buffer, &cmdline);
 
     cmdline = generate_cmdline("Free", filename);
     res = runcmd(cmdline, &buffer);
-    todo_wine ok(res == 1, "Return %d expected 1.\n", res);
-    todo_wine ok(!strcmp(buffer, ""),
+    ok(res == 1, "Return %d expected 1.\n", res);
+    ok(!strcmp(buffer, ""),
        "Return wrong string: %s.\n", buffer);
     cleanup(&buffer, &cmdline);
 
     cmdline = generate_cmdline("omg", filename);
     res = runcmd(cmdline, &buffer);
-    todo_wine ok(res == 1, "Return %d expected 1.\n", res);
-    todo_wine ok(!strcmp(buffer, ""),
+    ok(res == 1, "Return %d expected 1.\n", res);
+    ok(!strcmp(buffer, ""),
        "Return wrong string: %s.\n", buffer);
     cleanup(&buffer, &cmdline);
 
     cmdline = generate_cmdline("Wine", filename);
     res = runcmd(cmdline, &buffer);
-    todo_wine ok(!res, "Return %d expected 0.\n", res);
-    todo_wine ok(!strcmp(buffer, "Wine Is Not an Emulator.\nWine will always be free software.\n"
+    ok(!res, "Return %d expected 0.\n", res);
+    ok(!strcmp(buffer, "Wine Is Not an Emulator.\nWine will always be free software.\n"
                "Wine is heavily reliant on its user community too."),
        "Return wrong string: %s.\n", buffer);
     cleanup(&buffer, &cmdline);
-- 
2.1.0



More information about the wine-devel mailing list