Andrew Eikum : regedit: Process reg files which use \r line endings.

Alexandre Julliard julliard at winehq.org
Mon Aug 2 11:03:54 CDT 2010


Module: wine
Branch: master
Commit: 8851a4eb1f51fa56e5ac55d4a1d4a762abb21e3b
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=8851a4eb1f51fa56e5ac55d4a1d4a762abb21e3b

Author: Andrew Eikum <aeikum at codeweavers.com>
Date:   Fri Jul 30 16:02:36 2010 -0500

regedit: Process reg files which use \r line endings.

---

 programs/regedit/regproc.c       |   94 ++++++++++++++++++++++----------------
 programs/regedit/tests/regedit.c |   18 +++++++
 2 files changed, 72 insertions(+), 40 deletions(-)

diff --git a/programs/regedit/regproc.c b/programs/regedit/regproc.c
index f210879..122d678 100644
--- a/programs/regedit/regproc.c
+++ b/programs/regedit/regproc.c
@@ -623,7 +623,6 @@ static void processRegLinesA(FILE *in, char* first_chars)
 
     while (!feof(in)) {
         LPSTR s; /* The pointer into line for where the current fgets should read */
-        LPSTR check;
         WCHAR* lineW;
         s = line;
 
@@ -635,7 +634,7 @@ static void processRegLinesA(FILE *in, char* first_chars)
 
         for (;;) {
             size_t size_remaining;
-            int size_to_get;
+            int size_to_get, i;
             char *s_eol; /* various local uses */
 
             /* Do we need to expand the buffer ? */
@@ -661,27 +660,46 @@ static void processRegLinesA(FILE *in, char* first_chars)
              */
             size_to_get = (size_remaining > INT_MAX ? INT_MAX : size_remaining);
 
-            check = fgets (s, size_to_get, in);
-
-            if (check == NULL) {
-                if (ferror(in)) {
-                    perror ("While reading input");
-                    exit (IO_ERROR);
-                } else {
-                    assert (feof(in));
-                    *s = '\0';
-                    /* It is not clear to me from the definition that the
-                     * contents of the buffer are well defined on detecting
-                     * an eof without managing to read anything.
-                     */
+            /* get a single line. note that `i' must be one past the last
+             * meaningful character in `s' when this loop exits */
+            for(i = 0; i < size_to_get-1; ++i){
+                s[i] = fgetc(in);
+                if(s[i] == EOF){
+                    if(ferror(in)){
+                        perror("While reading input");
+                        exit(IO_ERROR);
+                    }else
+                        assert(feof(in));
+                    break;
+                }
+                if(s[i] == '\r'){
+                    /* read the next character iff it's \n */
+                    s[i+1] = fgetc(in);
+                    if(s[i+1] != '\n'){
+                        ungetc(s[i+1], in);
+                        i = i+1;
+                    }else{
+                        if(i+2 >= size_to_get){
+                            /* buffer too short, so put back the EOL chars to
+                             * read next cycle */
+                            ungetc('\n', in);
+                            ungetc('\r', in);
+                        }else
+                            i = i+2;
+                    }
+                    break;
+                }
+                if(s[i] == '\n'){
+                    i = i+1;
+                    break;
                 }
             }
+            s[i] = '\0';
 
             /* If we didn't read the eol nor the eof go around for the rest */
-            s_eol = strchr (s, '\n');
+            s_eol = strpbrk (s, "\r\n");
             if (!feof (in) && !s_eol) {
                 s = strchr (s, '\0');
-                /* It should be s + size_to_get - 1 but this is safer */
                 continue;
             }
 
@@ -691,11 +709,11 @@ static void processRegLinesA(FILE *in, char* first_chars)
                 continue;
             }
 
-            /* Remove any line feed.  Leave s_eol on the \0 */
+            /* Remove any line feed.  Leave s_eol on the first \0 */
             if (s_eol) {
-                *s_eol = '\0';
-                if (s_eol > line && *(s_eol-1) == '\r')
-                    *--s_eol = '\0';
+               if (*s_eol == '\r' && *(s_eol+1) == '\n')
+                   *(s_eol+1) = '\0';
+               *s_eol = '\0';
             } else
                 s_eol = strchr (s, '\0');
 
@@ -799,7 +817,8 @@ static void processRegLinesW(FILE *in)
         /* If we didn't read the eol nor the eof go around for the rest */
         while(1)
         {
-            s_eol = strchrW(line, '\n');
+            const WCHAR line_endings[] = {'\r','\n',0};
+            s_eol = strpbrkW(line, line_endings);
 
             if(!s_eol) {
                 /* Move the stub of the line to the start of the buffer so
@@ -813,22 +832,22 @@ static void processRegLinesW(FILE *in)
 
             /* If it is a comment line then discard it and go around again */
             if (*line == '#') {
-                line = s_eol + 1;
+                if (*s_eol == '\r' && *(s_eol+1) == '\n')
+                    line = s_eol + 2;
+                else
+                    line = s_eol + 1;
                 continue;
             }
 
             /* If there is a concatenating \\ then go around again */
-            if ((*(s_eol-1) == '\\') ||
-                (*(s_eol-1) == '\r' && *(s_eol-2) == '\\')) {
-                WCHAR* NextLine = s_eol;
+            if (*(s_eol-1) == '\\') {
+                WCHAR* NextLine = s_eol + 1;
 
-                while(*(NextLine+1) == ' ' || *(NextLine+1) == '\t')
+                if(*s_eol == '\r' && *(s_eol+1) == '\n')
                     NextLine++;
 
-                NextLine++;
-
-                if(*(s_eol-1) == '\r')
-                    s_eol--;
+                while(*(NextLine+1) == ' ' || *(NextLine+1) == '\t')
+                    NextLine++;
 
                 MoveMemory(s_eol - 1, NextLine, (CharsInBuf - (NextLine - s) + 1)*sizeof(WCHAR));
                 CharsInBuf -= NextLine - s_eol + 1;
@@ -836,15 +855,10 @@ static void processRegLinesW(FILE *in)
                 continue;
             }
 
-            /* Remove any line feed.  Leave s_eol on the \0 */
-            if (s_eol) {
-                *s_eol = '\0';
-                if (s_eol > buf && *(s_eol-1) == '\r')
-                    *(s_eol-1) = '\0';
-            }
-
-            if(!s_eol)
-                break;
+            /* Remove any line feed.  Leave s_eol on the last \0 */
+            if (*s_eol == '\r' && *(s_eol + 1) == '\n')
+                *s_eol++ = '\0';
+            *s_eol = '\0';
 
             processRegEntry(line, TRUE);
             line = s_eol + 1;
diff --git a/programs/regedit/tests/regedit.c b/programs/regedit/tests/regedit.c
index 43be689..6fc1305 100644
--- a/programs/regedit/tests/regedit.c
+++ b/programs/regedit/tests/regedit.c
@@ -230,6 +230,14 @@ static void test_basic_import(void)
         'r','e','g','e','d','i','t','_','t','e','s','t',']','\n',
         '"','T','e','s','t','V','a','l','u','e','3','"','=','"',0x3041,'V','a',
         'l','u','e','"','\n',0};
+    WCHAR wide_test_r[] = {0xFEFF,'W','i','n','d','o','w','s',' ','R','e','g',
+        'i','s','t','r','y',' ','E','d','i','t','o','r',' ','V','e','r','s',
+        'i','o','n',' ','5','.','0','0','\r','\r',
+        '[','H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E',
+        'R','\\','S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
+        'r','e','g','e','d','i','t','_','t','e','s','t',']','\r',
+        '"','T','e','s','t','V','a','l','u','e','5','"','=','"',0x3041,'V','a',
+        'l','u','e','"','\r',0};
     WCHAR wide_exp[] = {0x3041,'V','a','l','u','e',0};
     LONG lr;
 
@@ -253,9 +261,19 @@ static void test_basic_import(void)
         exec_import_wstr(wide_test);
         verify_reg_wsz(HKEY_CURRENT_USER, "Software\\Wine\\regedit_test",
                 "TestValue3", wide_exp);
+
+        exec_import_wstr(wide_test_r);
+        verify_reg_wsz(HKEY_CURRENT_USER, "Software\\Wine\\regedit_test",
+                "TestValue5", wide_exp);
     }else
         win_skip("Some WCHAR tests skipped\n");
 
+    exec_import_str("REGEDIT4\r\r"
+                "[HKEY_CURRENT_USER\\Software\\Wine\\regedit_test]\r"
+                "\"TestValue4\"=\"DValue\"\r");
+    verify_reg_sz(HKEY_CURRENT_USER, "Software\\Wine\\regedit_test",
+            "TestValue4", "DValue");
+
     exec_import_str("REGEDIT4\n\n"
                 "[HKEY_CURRENT_USER\\Software\\Wine\\regedit_test]\n"
                 "\"TestDword\"=dword:00000017\n");




More information about the wine-cvs mailing list