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