@@ -772,12 +772,157 @@ gethandle(PyObject* obj, const char* name)
772772 return ret ;
773773}
774774
775+ static PyObject *
776+ sortenvironmentkey (PyObject * module , PyObject * item )
777+ {
778+ return _winapi_LCMapStringEx_impl (NULL , LOCALE_NAME_INVARIANT ,
779+ LCMAP_UPPERCASE , item );
780+ }
781+
782+ static PyMethodDef sortenvironmentkey_def = {
783+ "sortenvironmentkey" , _PyCFunction_CAST (sortenvironmentkey ), METH_O , "" ,
784+ };
785+
786+ static int
787+ sort_environment_keys (PyObject * keys )
788+ {
789+ PyObject * keyfunc = PyCFunction_New (& sortenvironmentkey_def , NULL );
790+ if (keyfunc == NULL ) {
791+ return -1 ;
792+ }
793+ PyObject * kwnames = Py_BuildValue ("(s)" , "key" );
794+ if (kwnames == NULL ) {
795+ Py_DECREF (keyfunc );
796+ return -1 ;
797+ }
798+ PyObject * args [] = { keys , keyfunc };
799+ PyObject * ret = PyObject_VectorcallMethod (& _Py_ID (sort ), args , 1 , kwnames );
800+ Py_DECREF (keyfunc );
801+ Py_DECREF (kwnames );
802+ if (ret == NULL ) {
803+ return -1 ;
804+ }
805+ Py_DECREF (ret );
806+
807+ return 0 ;
808+ }
809+
810+ static int
811+ compare_string_ordinal (PyObject * str1 , PyObject * str2 , int * result )
812+ {
813+ wchar_t * s1 = PyUnicode_AsWideCharString (str1 , NULL );
814+ if (s1 == NULL ) {
815+ return -1 ;
816+ }
817+ wchar_t * s2 = PyUnicode_AsWideCharString (str2 , NULL );
818+ if (s2 == NULL ) {
819+ PyMem_Free (s1 );
820+ return -1 ;
821+ }
822+ * result = CompareStringOrdinal (s1 , -1 , s2 , -1 , TRUE);
823+ PyMem_Free (s1 );
824+ PyMem_Free (s2 );
825+ return 0 ;
826+ }
827+
828+ static PyObject *
829+ dedup_environment_keys (PyObject * keys )
830+ {
831+ PyObject * result = PyList_New (0 );
832+ if (result == NULL ) {
833+ return NULL ;
834+ }
835+
836+ // Iterate over the pre-ordered keys, check whether the current key is equal
837+ // to the next key (ignoring case), if different, insert the current value
838+ // into the result list. If they are equal, do nothing because we always
839+ // want to keep the last inserted one.
840+ for (Py_ssize_t i = 0 ; i < PyList_GET_SIZE (keys ); i ++ ) {
841+ PyObject * key = PyList_GET_ITEM (keys , i );
842+
843+ // The last key will always be kept.
844+ if (i + 1 == PyList_GET_SIZE (keys )) {
845+ if (PyList_Append (result , key ) < 0 ) {
846+ Py_DECREF (result );
847+ return NULL ;
848+ }
849+ continue ;
850+ }
851+
852+ PyObject * next_key = PyList_GET_ITEM (keys , i + 1 );
853+ int compare_result ;
854+ if (compare_string_ordinal (key , next_key , & compare_result ) < 0 ) {
855+ Py_DECREF (result );
856+ return NULL ;
857+ }
858+ if (compare_result == CSTR_EQUAL ) {
859+ continue ;
860+ }
861+ if (PyList_Append (result , key ) < 0 ) {
862+ Py_DECREF (result );
863+ return NULL ;
864+ }
865+ }
866+
867+ return result ;
868+ }
869+
870+ static PyObject *
871+ normalize_environment (PyObject * environment )
872+ {
873+ PyObject * keys = PyMapping_Keys (environment );
874+ if (keys == NULL ) {
875+ return NULL ;
876+ }
877+
878+ if (sort_environment_keys (keys ) < 0 ) {
879+ Py_DECREF (keys );
880+ return NULL ;
881+ }
882+
883+ PyObject * normalized_keys = dedup_environment_keys (keys );
884+ Py_DECREF (keys );
885+ if (normalized_keys == NULL ) {
886+ return NULL ;
887+ }
888+
889+ PyObject * result = PyDict_New ();
890+ if (result == NULL ) {
891+ Py_DECREF (normalized_keys );
892+ return NULL ;
893+ }
894+
895+ for (int i = 0 ; i < PyList_GET_SIZE (normalized_keys ); i ++ ) {
896+ PyObject * key = PyList_GET_ITEM (normalized_keys , i );
897+ PyObject * value = PyObject_GetItem (environment , key );
898+ if (value == NULL ) {
899+ Py_DECREF (normalized_keys );
900+ Py_DECREF (result );
901+ return NULL ;
902+ }
903+
904+ int ret = PyObject_SetItem (result , key , value );
905+ Py_DECREF (value );
906+ if (ret < 0 ) {
907+ Py_DECREF (normalized_keys );
908+ Py_DECREF (result );
909+ return NULL ;
910+ }
911+ }
912+
913+ Py_DECREF (normalized_keys );
914+
915+ return result ;
916+ }
917+
775918static wchar_t *
776919getenvironment (PyObject * environment )
777920{
778921 Py_ssize_t i , envsize , totalsize ;
779922 wchar_t * buffer = NULL , * p , * end ;
780- PyObject * keys , * values ;
923+ PyObject * normalized_environment = NULL ;
924+ PyObject * keys = NULL ;
925+ PyObject * values = NULL ;
781926
782927 /* convert environment dictionary to windows environment string */
783928 if (! PyMapping_Check (environment )) {
@@ -786,11 +931,16 @@ getenvironment(PyObject* environment)
786931 return NULL ;
787932 }
788933
789- keys = PyMapping_Keys (environment );
790- if (! keys ) {
934+ normalized_environment = normalize_environment (environment );
935+ if (normalize_environment == NULL ) {
791936 return NULL ;
792937 }
793- values = PyMapping_Values (environment );
938+
939+ keys = PyMapping_Keys (normalized_environment );
940+ if (!keys ) {
941+ goto error ;
942+ }
943+ values = PyMapping_Values (normalized_environment );
794944 if (!values ) {
795945 goto error ;
796946 }
@@ -882,6 +1032,7 @@ getenvironment(PyObject* environment)
8821032
8831033cleanup :
8841034error :
1035+ Py_XDECREF (normalized_environment );
8851036 Py_XDECREF (keys );
8861037 Py_XDECREF (values );
8871038 return buffer ;
0 commit comments