SDL: Sort joystick entries in /dev/input

From ba8bc143c1691a837a9265d1911ea737d7bb8002 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 26 Jul 2021 12:09:33 -0700
Subject: [PATCH] Sort joystick entries in /dev/input

This fixes https://github.com/libsdl-org/SDL/issues/4430
---
 src/joystick/linux/SDL_sysjoystick.c | 36 +++++++++++++++++-----------
 1 file changed, 22 insertions(+), 14 deletions(-)

diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c
index c7de6e5f3e..eeaf6c81f9 100644
--- a/src/joystick/linux/SDL_sysjoystick.c
+++ b/src/joystick/linux/SDL_sysjoystick.c
@@ -589,6 +589,18 @@ LINUX_InotifyJoystickDetect(void)
  * have to do this the first time, to detect devices that already existed
  * before we started; in the non-inotify code path we do this repeatedly
  * (polling). */
+static int
+filter_entries(const struct dirent *entry)
+{
+    return (SDL_strlen(entry->d_name) > 5 && SDL_strncmp(entry->d_name, "event", 5) == 0);
+}
+static int
+sort_entries(const struct dirent **a, const struct dirent **b)
+{
+    int numA = SDL_atoi((*a)->d_name+5);
+    int numB = SDL_atoi((*b)->d_name+5);
+    return (numA - numB);
+}
 static void
 LINUX_FallbackJoystickDetect(void)
 {
@@ -600,22 +612,18 @@ LINUX_FallbackJoystickDetect(void)
 
         /* Opening input devices can generate synchronous device I/O, so avoid it if we can */
         if (stat("/dev/input", &sb) == 0 && sb.st_mtime != last_input_dir_mtime) {
-            DIR *folder;
-            struct dirent *dent;
-
-            folder = opendir("/dev/input");
-            if (folder) {
-                while ((dent = readdir(folder))) {
-                    int len = SDL_strlen(dent->d_name);
-                    if (len > 5 && SDL_strncmp(dent->d_name, "event", 5) == 0) {
-                        char path[PATH_MAX];
-                        SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", dent->d_name);
-                        MaybeAddDevice(path);
-                    }
-                }
+            int i, count;
+            struct dirent **entries;
+            char path[PATH_MAX];
+
+            count = scandir("/dev/input", &entries, filter_entries, sort_entries);
+            for (i = 0; i < count; ++i) {
+                SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", entries[i]->d_name);
+                MaybeAddDevice(path);
 
-                closedir(folder);
+                free(entries[i]); /* This should NOT be SDL_free() */
             }
+            free(entries); /* This should NOT be SDL_free() */
 
             last_input_dir_mtime = sb.st_mtime;
         }