[PATCH 2 of 2] osutil.c added proper support for unicode

Petr Kodl petrkodl at gmail.com
Thu Sep 4 11:27:47 CDT 2008


# HG changeset patch
# User Petr Kodl<petrkodl at gmail.com>
# Date 1220544667 14400
# Node ID bbfc523b12ff1a813dc0e3b687e76b93985b697e
# Parent  e150128b40c0f80871799c2d8de3684d767729f2
osutil.c added proper support for unicode

diff -r e150128b40c0 -r bbfc523b12ff mercurial/osutil.c
--- a/mercurial/osutil.c	Wed Sep 03 19:52:29 2008 -0400
+++ b/mercurial/osutil.c	Thu Sep 04 12:11:07 2008 -0400
@@ -14,6 +14,7 @@
 
 #ifdef _WIN32
 #include <windows.h>
+#include <malloc.h>   /* for _alloca */
 #else
 #include <dirent.h>
 #include <fcntl.h>
@@ -131,113 +132,170 @@
 };
 
 #ifdef _WIN32 
-
-static __int64 a0 = (__int64)134774L*(__int64)24L*(__int64)3600L*(__int64)1000L*(__int64)1000L*(__int64)10L;
-static __int64 a1 = 1000*1000*10;
 
 static int to_python_time(FILETIME* ms_time)
 {
+    static __int64 a0 = (__int64)134774L*(__int64)24L*(__int64)3600L*(__int64)1000L*(__int64)1000L*(__int64)10L;
+    static __int64 a1 = 1000*1000*10;
     __int64 tmp; 
     memcpy(&tmp,ms_time,sizeof(__int64));
     return (int)((tmp-a0)/a1);
 }
 
+static int allow_unicode()
+{
+    static int allow = -1;
+    if(allow==-1) allow = (GetVersion() < 0x80000000) ? 1 : 0; /* unicode supported for NT */
+	return allow;
+}
+
 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
 {
-	static char *kwlist[] = { "path", "stat", NULL };
-	PyObject *list        = NULL;
-    PyObject* item        = NULL;
-    PyObject *py_st       = NULL;
-    PyObject *statobj     = NULL;
-    PyObject *ctor_args   = PyTuple_New(0);
-    struct non_posix_stat* stp = 0;
-    char  *path;
-	int   path_len;
-	int   keep_stat;
-    WIN32_FIND_DATA fd;
-    HANDLE  fh=NULL;
-    char full_path[_MAX_PATH+10];
-
-    if(!PyArg_ParseTupleAndKeywords(args,kwargs,"s#|O:listdir",kwlist,&path,&path_len,&statobj))
-		goto end;
-	
-    keep_stat = statobj && PyObject_IsTrue(statobj);
-
-    strncpy(full_path,path,path_len); 
-    strncpy(full_path+path_len,"\\*.*",5);
-
-    fh = FindFirstFile(full_path,&fd); 
-    if(INVALID_HANDLE_VALUE!=fh) 
+    PyObject *pathobj     = NULL,
+             *statobj     = NULL,
+             *list        = NULL,
+             *items       = NULL, 
+             *ctor_args   = NULL,
+             *item0       = NULL,
+             *item1       = NULL,
+             *py_st       = NULL;
+    HANDLE    fh = 0;
+    struct non_posix_stat* stp=0;
+    static char *kwlist[] = { "path", "stat", NULL };
+    if(PyArg_ParseTupleAndKeywords(args,kwargs,"O|O:listdir",kwlist,&pathobj,&statobj))
     {
-        list = PyList_New(0);
-        if(!list) 
+	    int         keepstat= statobj && PyObject_IsTrue(statobj);
+        int         unicode = allow_unicode() && PyUnicode_CheckExact(pathobj);
+        WIN32_FIND_DATAA fd_a;
+        WIN32_FIND_DATAW fd_w;
+        if(unicode) 
         {
-            PyErr_NoMemory();
-            goto end;
+            Py_ssize_t len = PyUnicode_GET_SIZE(pathobj); 
+            wchar_t *wpath = _alloca((len+5)*sizeof(wchar_t));
+            memset(wpath,0,(len+5)*sizeof(wchar_t));
+            if(PyUnicode_AsWideChar((PyUnicodeObject*)pathobj,wpath,len)!=len) return 0; 
+            if(len>0 && wpath[len-1]!=L':' && wpath[len-1]!=L'/' && wpath[len-1]!='\\') wpath[len++]=L'\\';
+            wcscpy(wpath+len,L"*.*");
+            fh = FindFirstFileW(wpath,&fd_w); 
         }
-        do
+        else if(PyString_CheckExact(pathobj))
         {
-            int isdir = (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
-            int isro  = (fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY);
-            if(!isdir || (strcmp(fd.cFileName,".") && strcmp(fd.cFileName,"..") ))
+            Py_ssize_t  len = PyString_GET_SIZE(pathobj);
+            char path[_MAX_PATH]; 
+            strncpy(path,PyString_AS_STRING(pathobj),_MAX_PATH);
+            if(len>0 && path[len-1]!=':' && path[len-1]!='/' && path[len-1]!='\\') path[len++]='\\';
+            strcpy(path+len,"*.*");
+            fh = FindFirstFileA(path,&fd_a); 
+        }
+        else
+        {
+            PyErr_SetString(PyExc_TypeError,"listdir - expected string or unicode as first argument"); 
+            goto error;
+        }
+        if(INVALID_HANDLE_VALUE!=fh) 
+        {
+            list      = PyList_New(0);
+            ctor_args = PyTuple_New(0);
+            if(!list || !ctor_args) 
             {
-                PyObject* item = PyTuple_New(keep_stat ? 3 : 2);
-                if(!item) 
+                PyErr_NoMemory();
+                goto error;
+            }
+            do
+            {
+                #define FD(NAME) (unicode ? fd_w.NAME : fd_a.NAME)
+                int isdir = (FD(dwFileAttributes) & FILE_ATTRIBUTE_DIRECTORY);
+                int isro  = (FD(dwFileAttributes) & FILE_ATTRIBUTE_READONLY);
+                if(     !isdir 
+                    ||  (unicode && wcscmp(fd_w.cFileName,L".") && wcscmp(fd_w.cFileName,L".."))
+                    ||  (!unicode&& strcmp(fd_a.cFileName,".")  && strcmp(fd_a.cFileName,"..")))
                 {
-                    PyErr_NoMemory();
-                    goto end;
+                    items = PyTuple_New(keepstat ? 3 : 2);
+                    item0 = unicode ? PyUnicode_FromWideChar(fd_w.cFileName,wcslen(fd_w.cFileName)) : PyString_FromString(fd_a.cFileName);
+                    item1 = PyInt_FromLong(isdir ? _S_IFDIR : _S_IFREG);
+                    if(!items || !item0 || !item1) 
+                    {
+                        PyErr_NoMemory();
+                        goto error;
+                    }
+                    PyTuple_SetItem(items,0,item0);
+                    PyTuple_SetItem(items,1,item1);
+                    item0 = item1 = 0;
+                    if(keepstat) 
+                    {
+                        py_st = PyObject_CallObject((PyObject *)&listdir_stat_type,ctor_args);
+                        if(!py_st) 
+                        {
+                            PyErr_NoMemory();
+                            goto error;
+                        }
+                        stp = &((struct listdir_stat *)py_st)->st;
+                        stp->st_mtime = to_python_time(unicode ? &fd_w.ftLastWriteTime : &fd_a.ftLastWriteTime);
+                        stp->st_ctime = to_python_time(unicode ? &fd_w.ftCreationTime  : &fd_a.ftLastWriteTime);
+                        stp->st_dev   = 0;
+                        stp->st_size  = 0;
+                        stp->st_mode  = (isdir ? (S_IFDIR | 0111) : S_IFREG) | (isro ? 0444 : 0666); 
+                        if(!isdir) 
+                        {
+                            stp->st_size = (__int64)(FD(nFileSizeHigh)<<32) + FD(nFileSizeLow);
+                            if(!unicode)
+                            {
+                                char* dot = strrchr(fd_a.cFileName,'.');
+	                            if (dot) 
+                                {
+		                            if(     !stricmp(dot,".bat") 
+                                        ||  !stricmp(dot,".cmd")
+		                                ||  !stricmp(dot,".exe")
+		                                ||  !stricmp(dot,".com"))
+		                            stp->st_mode |= 0111;
+                                }
+                            }
+                            else
+                            {
+                                wchar_t* dot = wcsrchr(fd_w.cFileName,L'.');
+	                            if (dot) 
+                                {
+		                            if(     !_wcsicmp(dot,L".bat") 
+                                        ||  !_wcsicmp(dot,L".cmd")
+		                                ||  !_wcsicmp(dot,L".exe")
+		                                ||  !_wcsicmp(dot,L".com"))
+		                            stp->st_mode |= 0111;
+                                }
+                            }
+                        }
+                        PyTuple_SET_ITEM(items,2,py_st); py_st = 0;
+                    }
+                    if(-1==PyList_Append(list,items)) 
+                    {
+                        goto error;
+                    }
+                    Py_XDECREF(items); items = 0;
                 }
-                PyTuple_SetItem(item,0,PyString_FromString(fd.cFileName));
-                PyTuple_SetItem(item,1,PyInt_FromLong(isdir ? _S_IFDIR : _S_IFREG));
-                if(keep_stat) 
-                {
-                    py_st = PyObject_CallObject((PyObject *)&listdir_stat_type,ctor_args);
-                    if(!py_st) 
-                    {
-                        PyErr_NoMemory();
-                        goto end;
-                    }
-			        stp = &((struct listdir_stat *)py_st)->st;
-                    stp->st_mtime = to_python_time(&fd.ftLastWriteTime);
-                    stp->st_ctime = to_python_time(&fd.ftCreationTime);
-                    stp->st_dev   = 0;
-                    stp->st_size  = 0;
-                    stp->st_mode  = (isdir ? (S_IFDIR | 0111) : S_IFREG) | (isro ? 0444 : 0666); 
-                    if(!isdir) 
-                    {
-                        char* dot = strrchr(fd.cFileName,'.');
-	                    if (dot) 
-                        {
-		                    if(     !stricmp(dot,".bat") 
-                                ||  !stricmp(dot,".cmd")
-		                        ||  !stricmp(dot,".exe")
-		                        ||  !stricmp(dot,".com"))
-		                    stp->st_mode |= 0111;
-                        }
-                        stp->st_size = (__int64)(fd.nFileSizeHigh<<32) + fd.nFileSizeLow;
-                    }
-                    PyTuple_SetItem(item,2,py_st);
-                    py_st = NULL;
-                }
-                PyList_Append(list,item);
-                Py_XDECREF(item);
-                item=NULL;
+                #undef FD
             }
+            while(unicode ? FindNextFileW(fh,&fd_w) : FindNextFileA(fh,&fd_a));
+            Py_XDECREF(ctor_args); ctor_args=0;
+            if(GetLastError()!=ERROR_NO_MORE_FILES || !FindClose(fh)) 
+            {
+                PyErr_SetExcFromWindowsErr(PyExc_OSError,GetLastError());
+                goto error;
+            }
+            fh = 0;
+            PyList_Sort(list);
+            return list;
         }
-        while(FindNextFile(fh,&fd)); 
-        FindClose(fh); 
+        else
+            PyErr_SetExcFromWindowsErr(PyExc_OSError,GetLastError());
     }
-    else
-    {
-        PyErr_SetExcFromWindowsErrWithFilename(PyExc_OSError,GetLastError(),path);
-    }
-end:
+error:
+    Py_XDECREF(list);
     Py_XDECREF(ctor_args);
-    Py_XDECREF(item);
-    Py_XDECREF(py_st);
-    if(list) PyList_Sort(list);
-    return list;
-}
+    Py_XDECREF(items);
+    Py_XDECREF(item0);    
+    Py_XDECREF(item1);
+    if(fh) FindClose(fh);
+    return 0;
+}
 
 #else
 


More information about the Mercurial-devel mailing list