summaryrefslogtreecommitdiff
path: root/src/contrib/SDL-3.2.20/build-scripts
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-08-30 16:53:58 -0700
committer3gg <3gg@shellblade.net>2025-08-30 16:53:58 -0700
commit6aaedb813fa11ba0679c3051bc2eb28646b9506c (patch)
tree34acbfc9840e02cb4753e6306ea7ce978bf8b58e /src/contrib/SDL-3.2.20/build-scripts
parent8f228ade99dd3d4c8da9b78ade1815c9adf85c8f (diff)
Update to SDL3
Diffstat (limited to 'src/contrib/SDL-3.2.20/build-scripts')
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/SDL_migration.cocci3836
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/add-source-to-projects.pl599
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/androidbuildlibs.sh85
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/build-release.py1556
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/build-web-examples.pl420
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/casefolding.txt1627
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/check_android_jni.py172
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/check_stdlib_usage.py262
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/clang-format-src.sh39
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/cmake-toolchain-mingw64-i686.cmake18
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/cmake-toolchain-mingw64-x86_64.cmake18
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/cmake-toolchain-qnx-aarch64le.cmake14
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/cmake-toolchain-qnx-x86_64.cmake14
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/codechecker-buildbot.sh59
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/create-android-project.py241
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/create-release.py45
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/fnsince.pl169
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/gen_audio_channel_conversion.c461
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/git-pre-push-hook.pl78
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/makecasefoldhashtable.pl322
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/mkinstalldirs162
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/pkg-support/android/INSTALL.md.in91
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/pkg-support/android/aar/__main__.py.in104
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/pkg-support/android/aar/cmake/SDL3ConfigVersion.cmake.in38
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/pkg-support/android/aar/description.json.in5
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/pkg-support/mingw/INSTALL.md.in53
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/pkg-support/mingw/Makefile39
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/Directory.Build.props8
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/INSTALL.md.in45
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/arm64/INSTALL.md.in13
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/cmake/SDL3Config.cmake.in135
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/cmake/SDL3ConfigVersion.cmake.in38
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/x64/INSTALL.md.in13
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/x86/INSTALL.md.in13
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/pkg-support/source/SDL_revision.h.cmake.in41
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/pkg-support/source/SDL_revision.h.in56
-rw-r--r--src/contrib/SDL-3.2.20/build-scripts/release-info.json210
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/rename_api.py254
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/rename_headers.py75
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/rename_macros.py382
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/rename_symbols.py130
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/rename_types.py80
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/setup-gdk-desktop.py303
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/showrev.sh48
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/strip_fPIC.sh21
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/test-versioning.sh170
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/update-copyright.sh15
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/update-version.sh81
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/updaterev.sh48
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/wikiheaders.pl3408
50 files changed, 16114 insertions, 0 deletions
diff --git a/src/contrib/SDL-3.2.20/build-scripts/SDL_migration.cocci b/src/contrib/SDL-3.2.20/build-scripts/SDL_migration.cocci
new file mode 100644
index 0000000..38655af
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/SDL_migration.cocci
@@ -0,0 +1,3836 @@
1//
2// This is a coccinelle semantic patch to ease migration of your project from SDL2 to SDL3.
3//
4// It generates a patch that you can apply to your project to build for SDL3. It does not
5// handle conceptual API changes, but it automates API name changes and function parameter
6// transformations.
7//
8// To install (native Ubuntu or using WSL on Windows):
9// sudo apt install coccinelle
10//
11// Apply the semantic patch to generate a patch file:
12// cd path/to/your/code
13// spatch --sp-file path/to/SDL_migration.cocci . >patch.txt
14//
15// A few options:
16// --c++=11 to parse cpp file
17// --max-width 200 to increase line width of generated source
18//
19// Apply the patch to your project:
20// patch -p1 <patch.txt
21//
22//
23// #############
24// In very short, a semantic patch is composed of two sub-blocks, like
25//
26// @@
27// declaration
28// @@
29// rule / transformation
30//
31// So this file is a set of many semantic patches, mostly independent.
32
33@ rule_audio_open @
34expression e1, e2;
35@@
36- SDL_OpenAudio(e1, e2)
37+ (g_audio_id = SDL_OpenAudioDevice(NULL, 0, e1, e2, 0)) > 0 ? 0 : -1
38
39@ depends on rule_audio_open @
40@@
41{
42+ /* FIXME MIGRATION: maybe move this to a global scope ? */
43+ SDL_AudioDeviceID g_audio_id = -1;
44...
45SDL_OpenAudioDevice(...)
46...
47}
48
49@@
50@@
51- SDL_LockAudio()
52+ SDL_LockAudioDevice(g_audio_id)
53
54@@
55@@
56- SDL_UnlockAudio()
57+ SDL_UnlockAudioDevice(g_audio_id)
58
59@@
60@@
61- SDL_CloseAudio(void)
62+ SDL_CloseAudioDevice(g_audio_id)
63
64@@
65expression e;
66@@
67- SDL_PauseAudio(e)
68+ e ? SDL_PauseAudioDevice(g_audio_id) : SDL_PlayAudioDevice(g_audio_id)
69
70@@
71@@
72- SDL_GetAudioStatus()
73+ SDL_GetAudioDeviceStatus(g_audio_id)
74
75@@
76@@
77- SDL_GetQueuedAudioSize(1)
78+ SDL_GetQueuedAudioSize(g_audio_id)
79
80@@
81expression e1, e2;
82@@
83- SDL_QueueAudio(1, e1, e2)
84+ SDL_QueueAudio(g_audio_id, e1, e2)
85
86
87
88
89// SDL_EventState() - replaced with SDL_SetEventEnabled()
90@@
91expression e1;
92@@
93(
94- SDL_EventState(e1, SDL_IGNORE)
95+ SDL_SetEventEnabled(e1, false)
96|
97- SDL_EventState(e1, SDL_DISABLE)
98+ SDL_SetEventEnabled(e1, false)
99|
100- SDL_EventState(e1, SDL_ENABLE)
101+ SDL_SetEventEnabled(e1, true)
102|
103- SDL_EventState(e1, SDL_QUERY)
104+ SDL_EventEnabled(e1)
105)
106
107// SDL_GetEventState() - replaced with SDL_EventEnabled()
108@@
109expression e1;
110@@
111- SDL_GetEventState(e1)
112+ SDL_EventEnabled(e1)
113
114@@
115expression e;
116@@
117- SDL_JoystickGetDevicePlayerIndex(e)
118+ /* FIXME MIGRATION: check for valid instance */
119+ SDL_GetJoystickInstancePlayerIndex(GetJoystickInstanceFromIndex(e))
120
121@@
122expression e;
123@@
124- SDL_JoystickIsVirtual(e)
125+ /* FIXME MIGRATION: check for valid instance */
126+ SDL_IsJoystickVirtual(GetJoystickInstanceFromIndex(e))
127
128@@
129expression e;
130@@
131- SDL_JoystickPathForIndex(e)
132+ /* FIXME MIGRATION: check for valid instance */
133+ SDL_GetJoystickInstancePath(GetJoystickInstanceFromIndex(e))
134
135@@
136expression e;
137@@
138- SDL_IsGameController(e)
139+ /* FIXME MIGRATION: check for valid instance */
140+ SDL_IsGamepad(GetJoystickInstanceFromIndex(e))
141
142@@
143expression e;
144@@
145- SDL_GameControllerMappingForDeviceIndex(e)
146+ /* FIXME MIGRATION: check for valid instance */
147+ SDL_GetGamepadInstanceMapping(GetJoystickInstanceFromIndex(e))
148
149@@
150expression e;
151@@
152- SDL_GameControllerNameForIndex(e)
153+ /* FIXME MIGRATION: check for valid instance */
154+ SDL_GetGamepadInstanceName(GetJoystickInstanceFromIndex(e))
155
156@@
157expression e;
158@@
159- SDL_GameControllerPathForIndex(e)
160+ /* FIXME MIGRATION: check for valid instance */
161+ SDL_GetGamepadInstancePath(GetJoystickInstanceFromIndex(e))
162
163@@
164expression e;
165@@
166- SDL_GameControllerTypeForIndex(e)
167+ /* FIXME MIGRATION: check for valid instance */
168+ SDL_GetGamepadInstanceType(GetJoystickInstanceFromIndex(e))
169
170
171// SDL_Has3DNow() has been removed; there is no replacement.
172@@
173@@
174+ /* FIXME MIGRATION: SDL_Has3DNow() has been removed; there is no replacement. */ 0
175- SDL_Has3DNow()
176
177// SDL_HasRDTSC() has been removed; there is no replacement.
178@@
179@@
180+ /* FIXME MIGRATION: SDL_HasRDTSC() has been removed; there is no replacement. */ 0
181- SDL_HasRDTSC()
182
183// SDL_HINT_VIDEO_X11_XINERAMA (Xinerama no longer supported by the X11 backend)
184@@
185@@
186+ /* FIXME MIGRATION: no longer support by the X11 backend */ NULL
187- SDL_HINT_VIDEO_X11_XINERAMA
188
189// SDL_HINT_VIDEO_X11_XVIDMODE (Xvidmode no longer supported by the X11 backend)
190@@
191@@
192+ /* FIXME MIGRATION: no longer support by the X11 backend */ NULL
193- SDL_HINT_VIDEO_X11_XVIDMODE
194
195// SDL_HINT_VIDEO_X11_FORCE_EGL (use SDL_HINT_VIDEO_FORCE_EGL instead)
196@@
197@@
198- SDL_HINT_VIDEO_X11_FORCE_EGL
199+ SDL_HINT_VIDEO_FORCE_EGL
200
201@@
202@@
203- SDL_HINT_AUDIODRIVER
204+ SDL_HINT_AUDIO_DRIVER
205
206@@
207@@
208- SDL_HINT_VIDEODRIVER
209+ SDL_HINT_VIDEO_DRIVER
210
211// SDL_GetRevisionNumber() has been removed from the API, it always returned 0 in SDL 2.0.
212@@
213@@
214+ /* FIXME MIGRATION: SDL_GetRevisionNumber() removed */ 0
215- SDL_GetRevisionNumber()
216
217// SDL_RWread
218@ rule_rwread @
219expression e1, e2, e3, e4;
220identifier i;
221@@
222(
223 i = SDL_RWread(e1, e2,
224- e3, e4);
225+ e3 * e4);
226+ i = (i <= 0) ? 0 : i / e3;
227|
228 SDL_RWread(e1, e2,
229- e3, e4);
230+ e3 * e4);
231|
232+ /* FIXME MIGRATION: double-check if you use the returned value of SDL_RWread() */
233 SDL_RWread(e1, e2,
234- e3, e4)
235+ e3 * e4)
236
237)
238
239// SDL_RWwrite
240@ rule_rwwrite @
241expression e1, e2, e3, e4;
242identifier i;
243@@
244(
245 i = SDL_RWwrite(e1, e2,
246- e3, e4);
247+ e3 * e4);
248+ i = (i <= 0) ? 0 : i / e3;
249|
250 SDL_RWwrite(e1, e2,
251- e3, e4);
252+ e3 * e4);
253|
254+ /* FIXME MIGRATION: double-check if you use the returned value of SDL_RWwrite() */
255 SDL_RWwrite(e1, e2,
256- e3, e4)
257+ e3 * e4)
258)
259
260@ depends on rule_rwread || rule_rwwrite @
261expression e;
262@@
263(
264- e * 1
265+ e
266|
267- e / 1
268+ e
269)
270
271// SDL_SIMDAlloc(), SDL_SIMDFree() have been removed.
272@@
273expression e1;
274@@
275- SDL_SIMDAlloc(e1)
276+ SDL_aligned_alloc(SDL_SIMDGetAlignment(), e1)
277
278@@
279expression e1;
280@@
281- SDL_SIMDFree(
282+ SDL_aligned_free(
283 e1)
284
285// SDL_Vulkan_GetInstanceExtensions() no longer takes a window parameter.
286@@
287expression e1, e2, e3;
288@@
289 SDL_Vulkan_GetInstanceExtensions(
290- e1,
291 e2, e3)
292
293// SDL_Vulkan_GetVkGetInstanceProcAddr() now returns `SDL_FunctionPointer` instead of `void *`, and should be cast to PFN_vkGetInstanceProcAddr.
294@@
295typedef PFN_vkGetInstanceProcAddr;
296@@
297(
298 (PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr()
299|
300+ (PFN_vkGetInstanceProcAddr)
301 SDL_Vulkan_GetVkGetInstanceProcAddr()
302)
303
304// SDL_PauseAudioDevice / SDL_PlayAudioDevice
305@@
306expression e;
307@@
308(
309- SDL_PauseAudioDevice(e, 1)
310+ SDL_PauseAudioDevice(e)
311|
312- SDL_PauseAudioDevice(e, SDL_TRUE)
313+ SDL_PauseAudioDevice(e)
314|
315- SDL_PauseAudioDevice(e, 0)
316+ SDL_ResumeAudioDevice(e)
317|
318- SDL_PauseAudioDevice(e, SDL_FALSE)
319+ SDL_ResumeAudioDevice(e)
320)
321
322@@
323expression e, pause_on;
324@@
325- SDL_PauseAudioDevice(e, pause_on);
326+ if (pause_on) {
327+ SDL_PauseAudioDevice(e);
328+ } else {
329+ SDL_ResumeAudioDevice(e);
330+ }
331
332
333// Remove SDL_WINDOW_SHOWN
334@@
335expression e;
336@@
337(
338- SDL_WINDOW_SHOWN | e
339+ e
340|
341- SDL_WINDOW_SHOWN
342+ 0
343)
344
345
346@@
347// Remove parameter from SDL_ConvertSurface
348expression e1, e2, e3;
349@@
350SDL_ConvertSurface(e1, e2
351- ,e3)
352+ )
353
354
355@@
356// Remove parameter from SDL_ConvertSurfaceFormat
357expression e1, e2, e3;
358@@
359SDL_ConvertSurfaceFormat(e1, e2
360- ,e3)
361+ )
362
363
364@@
365// SDL_CreateRGBSurfaceWithFormat
366// remove 'flags'
367// remove 'depth'
368// rename to SDL_CreateSurface
369expression e1, e2, e3, e4, e5;
370@@
371- SDL_CreateRGBSurfaceWithFormat(e1, e2, e3, e4, e5)
372+ SDL_CreateSurface(e2, e3, e5)
373
374
375@@
376// SDL_CreateRGBSurfaceWithFormat:
377// remove 'depth'
378// rename to SDL_CreateSurfaceFrom
379expression e1, e2, e3, e4, e5, e6;
380@@
381- SDL_CreateRGBSurfaceWithFormatFrom(e1, e2, e3, e4, e5, e6)
382+ SDL_CreateSurfaceFrom(e1, e2, e3, e5, e6)
383
384
385
386@@
387// SDL_CreateRGBSurface : convert Masks to format
388expression e1, e2, e3, e4, e5, e6, e7, e8, e9;
389
390@@
391
392(
393
394// Generated for all formats:
395
396- SDL_CreateRGBSurface(e1, e2, e3, 1, 0x00000000, 0x00000000, 0x00000000, 0x00000000)
397+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_INDEX1LSB)
398
399|
400
401- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 1, e4, 0x00000000, 0x00000000, 0x00000000, 0x00000000)
402+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_INDEX1LSB)
403
404|
405
406- SDL_CreateRGBSurface(e1, e2, e3, 1, 0x00000000, 0x00000000, 0x00000000, 0x00000000)
407+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_INDEX1MSB)
408
409|
410
411- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 1, e4, 0x00000000, 0x00000000, 0x00000000, 0x00000000)
412+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_INDEX1MSB)
413
414|
415
416- SDL_CreateRGBSurface(e1, e2, e3, 4, 0x00000000, 0x00000000, 0x00000000, 0x00000000)
417+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_INDEX4LSB)
418
419|
420
421- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 4, e4, 0x00000000, 0x00000000, 0x00000000, 0x00000000)
422+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_INDEX4LSB)
423
424|
425
426- SDL_CreateRGBSurface(e1, e2, e3, 4, 0x00000000, 0x00000000, 0x00000000, 0x00000000)
427+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_INDEX4MSB)
428
429|
430
431- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 4, e4, 0x00000000, 0x00000000, 0x00000000, 0x00000000)
432+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_INDEX4MSB)
433
434|
435
436- SDL_CreateRGBSurface(e1, e2, e3, 8, 0x00000000, 0x00000000, 0x00000000, 0x00000000)
437+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_INDEX8)
438
439|
440
441- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 8, e4, 0x00000000, 0x00000000, 0x00000000, 0x00000000)
442+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_INDEX8)
443
444|
445
446- SDL_CreateRGBSurface(e1, e2, e3, 8, 0x000000E0, 0x0000001C, 0x00000003, 0x00000000)
447+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_RGB332)
448
449|
450
451- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 8, e4, 0x000000E0, 0x0000001C, 0x00000003, 0x00000000)
452+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_RGB332)
453
454|
455
456- SDL_CreateRGBSurface(e1, e2, e3, 12, 0x00000F00, 0x000000F0, 0x0000000F, 0x00000000)
457+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_RGB444)
458
459|
460
461- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 12, e4, 0x00000F00, 0x000000F0, 0x0000000F, 0x00000000)
462+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_RGB444)
463
464|
465
466- SDL_CreateRGBSurface(e1, e2, e3, 15, 0x00007C00, 0x000003E0, 0x0000001F, 0x00000000)
467+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_RGB555)
468
469|
470
471- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 15, e4, 0x00007C00, 0x000003E0, 0x0000001F, 0x00000000)
472+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_RGB555)
473
474|
475
476- SDL_CreateRGBSurface(e1, e2, e3, 15, 0x0000001F, 0x000003E0, 0x00007C00, 0x00000000)
477+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_BGR555)
478
479|
480
481- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 15, e4, 0x0000001F, 0x000003E0, 0x00007C00, 0x00000000)
482+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_BGR555)
483
484|
485
486- SDL_CreateRGBSurface(e1, e2, e3, 16, 0x00000F00, 0x000000F0, 0x0000000F, 0x0000F000)
487+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_ARGB4444)
488
489|
490
491- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 16, e4, 0x00000F00, 0x000000F0, 0x0000000F, 0x0000F000)
492+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_ARGB4444)
493
494|
495
496- SDL_CreateRGBSurface(e1, e2, e3, 16, 0x0000F000, 0x00000F00, 0x000000F0, 0x0000000F)
497+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_RGBA4444)
498
499|
500
501- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 16, e4, 0x0000F000, 0x00000F00, 0x000000F0, 0x0000000F)
502+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_RGBA4444)
503
504|
505
506- SDL_CreateRGBSurface(e1, e2, e3, 16, 0x0000000F, 0x000000F0, 0x00000F00, 0x0000F000)
507+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_ABGR4444)
508
509|
510
511- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 16, e4, 0x0000000F, 0x000000F0, 0x00000F00, 0x0000F000)
512+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_ABGR4444)
513
514|
515
516- SDL_CreateRGBSurface(e1, e2, e3, 16, 0x000000F0, 0x00000F00, 0x0000F000, 0x0000000F)
517+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_BGRA4444)
518
519|
520
521- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 16, e4, 0x000000F0, 0x00000F00, 0x0000F000, 0x0000000F)
522+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_BGRA4444)
523
524|
525
526- SDL_CreateRGBSurface(e1, e2, e3, 16, 0x00007C00, 0x000003E0, 0x0000001F, 0x00008000)
527+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_ARGB1555)
528
529|
530
531- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 16, e4, 0x00007C00, 0x000003E0, 0x0000001F, 0x00008000)
532+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_ARGB1555)
533
534|
535
536- SDL_CreateRGBSurface(e1, e2, e3, 16, 0x0000F800, 0x000007C0, 0x0000003E, 0x00000001)
537+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_RGBA5551)
538
539|
540
541- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 16, e4, 0x0000F800, 0x000007C0, 0x0000003E, 0x00000001)
542+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_RGBA5551)
543
544|
545
546- SDL_CreateRGBSurface(e1, e2, e3, 16, 0x0000001F, 0x000003E0, 0x00007C00, 0x00008000)
547+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_ABGR1555)
548
549|
550
551- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 16, e4, 0x0000001F, 0x000003E0, 0x00007C00, 0x00008000)
552+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_ABGR1555)
553
554|
555
556- SDL_CreateRGBSurface(e1, e2, e3, 16, 0x0000003E, 0x000007C0, 0x0000F800, 0x00000001)
557+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_BGRA5551)
558
559|
560
561- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 16, e4, 0x0000003E, 0x000007C0, 0x0000F800, 0x00000001)
562+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_BGRA5551)
563
564|
565
566- SDL_CreateRGBSurface(e1, e2, e3, 16, 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000)
567+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_RGB565)
568
569|
570
571- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 16, e4, 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000)
572+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_RGB565)
573
574|
575
576- SDL_CreateRGBSurface(e1, e2, e3, 16, 0x0000001F, 0x000007E0, 0x0000F800, 0x00000000)
577+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_BGR565)
578
579|
580
581- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 16, e4, 0x0000001F, 0x000007E0, 0x0000F800, 0x00000000)
582+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_BGR565)
583
584|
585
586- SDL_CreateRGBSurface(e1, e2, e3, 24, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000)
587+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_RGB24)
588
589|
590
591- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 24, e4, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000)
592+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_RGB24)
593
594|
595
596- SDL_CreateRGBSurface(e1, e2, e3, 24, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000)
597+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_BGR24)
598
599|
600
601- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 24, e4, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000)
602+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_BGR24)
603
604|
605
606- SDL_CreateRGBSurface(e1, e2, e3, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000)
607+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_XRGB8888)
608
609|
610
611- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 32, e4, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000)
612+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_XRGB8888)
613
614|
615
616- SDL_CreateRGBSurface(e1, e2, e3, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x00000000)
617+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_RGBX8888)
618
619|
620
621- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 32, e4, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x00000000)
622+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_RGBX8888)
623
624|
625
626- SDL_CreateRGBSurface(e1, e2, e3, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000)
627+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_XBGR8888)
628
629|
630
631- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 32, e4, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000)
632+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_XBGR8888)
633
634|
635
636- SDL_CreateRGBSurface(e1, e2, e3, 32, 0x0000FF00, 0x00FF0000, 0xFF000000, 0x00000000)
637+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_BGRX8888)
638
639|
640
641- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 32, e4, 0x0000FF00, 0x00FF0000, 0xFF000000, 0x00000000)
642+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_BGRX8888)
643
644|
645
646- SDL_CreateRGBSurface(e1, e2, e3, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000)
647+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_ARGB8888)
648
649|
650
651- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 32, e4, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000)
652+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_ARGB8888)
653
654|
655
656- SDL_CreateRGBSurface(e1, e2, e3, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF)
657+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_RGBA8888)
658
659|
660
661- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 32, e4, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF)
662+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_RGBA8888)
663
664|
665
666- SDL_CreateRGBSurface(e1, e2, e3, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000)
667+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_ABGR8888)
668
669|
670
671- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 32, e4, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000)
672+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_ABGR8888)
673
674|
675
676- SDL_CreateRGBSurface(e1, e2, e3, 32, 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF)
677+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_BGRA8888)
678
679|
680
681- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 32, e4, 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF)
682+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_BGRA8888)
683
684|
685
686- SDL_CreateRGBSurface(e1, e2, e3, 32, 0x3FF00000, 0x000FFC00, 0x000003FF, 0xC0000000)
687+ SDL_CreateSurface(e2, e3, SDL_PIXELFORMAT_ARGB2101010)
688
689|
690
691- SDL_CreateRGBSurfaceFrom(e1, e2, e3, 32, e4, 0x3FF00000, 0x000FFC00, 0x000003FF, 0xC0000000)
692+ SDL_CreateSurfaceFrom(e1, e2, e3, e4, SDL_PIXELFORMAT_ARGB2101010)
693
694|
695
696// End Generated
697
698
699- SDL_CreateRGBSurface(e1, e2, e3, e4->BitsPerPixel, e4->Rmask, e4->Gmask, e4->Bmask, e4->Amask)
700+ SDL_CreateSurface(e2, e3, e4->format)
701
702|
703
704- SDL_CreateRGBSurfaceFrom(e1, e2, e3, e4->BitsPerPixel, e5, e4->Rmask, e4->Gmask, e4->Bmask, e4->Amask)
705+ SDL_CreateSurfaceFrom(e1, e2, e3, e5, e4->format)
706
707|
708
709-SDL_CreateRGBSurface(e1, e2, e3, e4, e5, e6, e7, e8)
710+SDL_CreateSurface(e2, e3, SDL_MasksToPixelFormatEnum(e4, e5, e6, e7, e8))
711
712|
713
714-SDL_CreateRGBSurfaceFrom(e1, e2, e3, e4, e5, e6, e7, e8, e9)
715+SDL_CreateSurfaceFrom(e1, e2, e3, e5, SDL_MasksToPixelFormatEnum(e4, e6, e7, e8, e9))
716
717)
718
719@@
720// SDL_CreateRenderer:
721// 2nd argument changed from int (default=-1) to const char* (default=NULL)
722expression e1, e3;
723int e2;
724@@
725
726(
727
728-SDL_CreateRenderer(e1, -1, e3)
729+SDL_CreateRenderer(e1, NULL, e3)
730
731|
732
733-SDL_CreateRenderer(e1, e2, e3)
734+SDL_CreateRenderer(e1, SDL_GetRenderDriver(e2), e3)
735
736)
737
738// Renaming of SDL_oldnames.h
739
740@@
741@@
742- SDL_AudioStreamAvailable
743+ SDL_GetAudioStreamAvailable
744 (...)
745@@
746@@
747- SDL_AudioStreamClear
748+ SDL_ClearAudioStream
749 (...)
750@@
751@@
752- SDL_AudioStreamFlush
753+ SDL_FlushAudioStream
754 (...)
755@@
756@@
757- SDL_AudioStreamGet
758+ SDL_GetAudioStreamData
759 (...)
760@@
761@@
762- SDL_AudioStreamPut
763+ SDL_PutAudioStreamData
764 (...)
765@@
766@@
767- SDL_FreeAudioStream
768+ SDL_DestroyAudioStream
769 (...)
770@@
771@@
772- SDL_FreeWAV
773+ SDL_free
774 (...)
775@@
776@@
777- SDL_NewAudioStream
778+ SDL_CreateAudioStream
779 (...)
780@@
781@@
782- SDL_CONTROLLERAXISMOTION
783+ SDL_EVENT_GAMEPAD_AXIS_MOTION
784@@
785@@
786- SDL_CONTROLLERBUTTONDOWN
787+ SDL_EVENT_GAMEPAD_BUTTON_DOWN
788@@
789@@
790- SDL_CONTROLLERBUTTONUP
791+ SDL_EVENT_GAMEPAD_BUTTON_UP
792@@
793@@
794- SDL_CONTROLLERDEVICEADDED
795+ SDL_EVENT_GAMEPAD_ADDED
796@@
797@@
798- SDL_CONTROLLERDEVICEREMAPPED
799+ SDL_EVENT_GAMEPAD_REMAPPED
800@@
801@@
802- SDL_CONTROLLERDEVICEREMOVED
803+ SDL_EVENT_GAMEPAD_REMOVED
804@@
805@@
806- SDL_CONTROLLERSENSORUPDATE
807+ SDL_EVENT_GAMEPAD_SENSOR_UPDATE
808@@
809@@
810- SDL_CONTROLLERTOUCHPADDOWN
811+ SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN
812@@
813@@
814- SDL_CONTROLLERTOUCHPADMOTION
815+ SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION
816@@
817@@
818- SDL_CONTROLLERTOUCHPADUP
819+ SDL_EVENT_GAMEPAD_TOUCHPAD_UP
820@@
821typedef SDL_ControllerAxisEvent, SDL_GamepadAxisEvent;
822@@
823- SDL_ControllerAxisEvent
824+ SDL_GamepadAxisEvent
825@@
826typedef SDL_ControllerButtonEvent, SDL_GamepadButtonEvent;
827@@
828- SDL_ControllerButtonEvent
829+ SDL_GamepadButtonEvent
830@@
831typedef SDL_ControllerDeviceEvent, SDL_GamepadDeviceEvent;
832@@
833- SDL_ControllerDeviceEvent
834+ SDL_GamepadDeviceEvent
835@@
836typedef SDL_ControllerSensorEvent, SDL_GamepadSensorEvent;
837@@
838- SDL_ControllerSensorEvent
839+ SDL_GamepadSensorEvent
840@@
841typedef SDL_ControllerTouchpadEvent, SDL_GamepadTouchpadEvent;
842@@
843- SDL_ControllerTouchpadEvent
844+ SDL_GamepadTouchpadEvent
845@@
846@@
847- SDL_CONTROLLER_AXIS_INVALID
848+ SDL_GAMEPAD_AXIS_INVALID
849@@
850@@
851- SDL_CONTROLLER_AXIS_LEFTX
852+ SDL_GAMEPAD_AXIS_LEFTX
853@@
854@@
855- SDL_CONTROLLER_AXIS_LEFTY
856+ SDL_GAMEPAD_AXIS_LEFTY
857@@
858@@
859- SDL_CONTROLLER_AXIS_MAX
860+ SDL_GAMEPAD_AXIS_COUNT
861@@
862@@
863- SDL_CONTROLLER_AXIS_RIGHTX
864+ SDL_GAMEPAD_AXIS_RIGHTX
865@@
866@@
867- SDL_CONTROLLER_AXIS_RIGHTY
868+ SDL_GAMEPAD_AXIS_RIGHTY
869@@
870@@
871- SDL_CONTROLLER_AXIS_TRIGGERLEFT
872+ SDL_GAMEPAD_AXIS_LEFT_TRIGGER
873@@
874@@
875- SDL_CONTROLLER_AXIS_TRIGGERRIGHT
876+ SDL_GAMEPAD_AXIS_RIGHT_TRIGGER
877@@
878@@
879- SDL_CONTROLLER_BINDTYPE_AXIS
880+ SDL_GAMEPAD_BINDTYPE_AXIS
881@@
882@@
883- SDL_CONTROLLER_BINDTYPE_BUTTON
884+ SDL_GAMEPAD_BINDTYPE_BUTTON
885@@
886@@
887- SDL_CONTROLLER_BINDTYPE_HAT
888+ SDL_GAMEPAD_BINDTYPE_HAT
889@@
890@@
891- SDL_CONTROLLER_BINDTYPE_NONE
892+ SDL_GAMEPAD_BINDTYPE_NONE
893@@
894@@
895- SDL_CONTROLLER_BUTTON_A
896+ SDL_GAMEPAD_BUTTON_SOUTH
897@@
898@@
899- SDL_CONTROLLER_BUTTON_B
900+ SDL_GAMEPAD_BUTTON_EAST
901@@
902@@
903- SDL_CONTROLLER_BUTTON_BACK
904+ SDL_GAMEPAD_BUTTON_BACK
905@@
906@@
907- SDL_CONTROLLER_BUTTON_DPAD_DOWN
908+ SDL_GAMEPAD_BUTTON_DPAD_DOWN
909@@
910@@
911- SDL_CONTROLLER_BUTTON_DPAD_LEFT
912+ SDL_GAMEPAD_BUTTON_DPAD_LEFT
913@@
914@@
915- SDL_CONTROLLER_BUTTON_DPAD_RIGHT
916+ SDL_GAMEPAD_BUTTON_DPAD_RIGHT
917@@
918@@
919- SDL_CONTROLLER_BUTTON_DPAD_UP
920+ SDL_GAMEPAD_BUTTON_DPAD_UP
921@@
922@@
923- SDL_CONTROLLER_BUTTON_GUIDE
924+ SDL_GAMEPAD_BUTTON_GUIDE
925@@
926@@
927- SDL_CONTROLLER_BUTTON_INVALID
928+ SDL_GAMEPAD_BUTTON_INVALID
929@@
930@@
931- SDL_CONTROLLER_BUTTON_LEFTSHOULDER
932+ SDL_GAMEPAD_BUTTON_LEFT_SHOULDER
933@@
934@@
935- SDL_CONTROLLER_BUTTON_LEFTSTICK
936+ SDL_GAMEPAD_BUTTON_LEFT_STICK
937@@
938@@
939- SDL_CONTROLLER_BUTTON_MAX
940+ SDL_GAMEPAD_BUTTON_COUNT
941@@
942@@
943- SDL_CONTROLLER_BUTTON_MISC1
944+ SDL_GAMEPAD_BUTTON_MISC1
945@@
946@@
947- SDL_CONTROLLER_BUTTON_PADDLE1
948+ SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1
949@@
950@@
951- SDL_CONTROLLER_BUTTON_PADDLE2
952+ SDL_GAMEPAD_BUTTON_LEFT_PADDLE1
953@@
954@@
955- SDL_CONTROLLER_BUTTON_PADDLE3
956+ SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2
957@@
958@@
959- SDL_CONTROLLER_BUTTON_PADDLE4
960+ SDL_GAMEPAD_BUTTON_LEFT_PADDLE2
961@@
962@@
963- SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
964+ SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER
965@@
966@@
967- SDL_CONTROLLER_BUTTON_RIGHTSTICK
968+ SDL_GAMEPAD_BUTTON_RIGHT_STICK
969@@
970@@
971- SDL_CONTROLLER_BUTTON_START
972+ SDL_GAMEPAD_BUTTON_START
973@@
974@@
975- SDL_CONTROLLER_BUTTON_TOUCHPAD
976+ SDL_GAMEPAD_BUTTON_TOUCHPAD
977@@
978@@
979- SDL_CONTROLLER_BUTTON_X
980+ SDL_GAMEPAD_BUTTON_WEST
981@@
982@@
983- SDL_CONTROLLER_BUTTON_Y
984+ SDL_GAMEPAD_BUTTON_NORTH
985@@
986@@
987- SDL_CONTROLLER_TYPE_AMAZON_LUNA
988+ SDL_GAMEPAD_TYPE_AMAZON_LUNA
989@@
990@@
991- SDL_CONTROLLER_TYPE_GOOGLE_STADIA
992+ SDL_GAMEPAD_TYPE_GOOGLE_STADIA
993@@
994@@
995- SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT
996+ SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT
997@@
998@@
999- SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR
1000+ SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR
1001@@
1002@@
1003- SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT
1004+ SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT
1005@@
1006@@
1007- SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO
1008+ SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO
1009@@
1010@@
1011- SDL_CONTROLLER_TYPE_NVIDIA_SHIELD
1012+ SDL_GAMEPAD_TYPE_NVIDIA_SHIELD
1013@@
1014@@
1015- SDL_CONTROLLER_TYPE_PS3
1016+ SDL_GAMEPAD_TYPE_PS3
1017@@
1018@@
1019- SDL_CONTROLLER_TYPE_PS4
1020+ SDL_GAMEPAD_TYPE_PS4
1021@@
1022@@
1023- SDL_CONTROLLER_TYPE_PS5
1024+ SDL_GAMEPAD_TYPE_PS5
1025@@
1026@@
1027- SDL_CONTROLLER_TYPE_UNKNOWN
1028+ SDL_GAMEPAD_TYPE_UNKNOWN
1029@@
1030@@
1031- SDL_CONTROLLER_TYPE_VIRTUAL
1032+ SDL_GAMEPAD_TYPE_VIRTUAL
1033@@
1034@@
1035- SDL_CONTROLLER_TYPE_XBOX360
1036+ SDL_GAMEPAD_TYPE_XBOX360
1037@@
1038@@
1039- SDL_CONTROLLER_TYPE_XBOXONE
1040+ SDL_GAMEPAD_TYPE_XBOXONE
1041@@
1042typedef SDL_GameController, SDL_Gamepad;
1043@@
1044- SDL_GameController
1045+ SDL_Gamepad
1046@@
1047@@
1048- SDL_GameControllerAddMapping
1049+ SDL_AddGamepadMapping
1050 (...)
1051@@
1052@@
1053- SDL_GameControllerAddMappingsFromFile
1054+ SDL_AddGamepadMappingsFromFile
1055 (...)
1056@@
1057@@
1058- SDL_GameControllerAddMappingsFromRW
1059+ SDL_AddGamepadMappingsFromIO
1060 (...)
1061@@
1062typedef SDL_GameControllerAxis, SDL_GamepadAxis;
1063@@
1064- SDL_GameControllerAxis
1065+ SDL_GamepadAxis
1066@@
1067typedef SDL_GameControllerBindType, SDL_GamepadBindingType;
1068@@
1069- SDL_GameControllerBindType
1070+ SDL_GamepadBindingType
1071@@
1072typedef SDL_GameControllerButton, SDL_GamepadButton;
1073@@
1074- SDL_GameControllerButton
1075+ SDL_GamepadButton
1076@@
1077@@
1078- SDL_GameControllerClose
1079+ SDL_CloseGamepad
1080 (...)
1081@@
1082@@
1083- SDL_GameControllerFromInstanceID
1084+ SDL_GetGamepadFromID
1085 (...)
1086@@
1087@@
1088- SDL_GameControllerFromPlayerIndex
1089+ SDL_GetGamepadFromPlayerIndex
1090 (...)
1091@@
1092@@
1093- SDL_GameControllerGetAppleSFSymbolsNameForAxis
1094+ SDL_GetGamepadAppleSFSymbolsNameForAxis
1095 (...)
1096@@
1097@@
1098- SDL_GameControllerGetAppleSFSymbolsNameForButton
1099+ SDL_GetGamepadAppleSFSymbolsNameForButton
1100 (...)
1101@@
1102@@
1103- SDL_GameControllerGetAttached
1104+ SDL_GamepadConnected
1105 (...)
1106@@
1107@@
1108- SDL_GameControllerGetAxis
1109+ SDL_GetGamepadAxis
1110 (...)
1111@@
1112@@
1113- SDL_GameControllerGetAxisFromString
1114+ SDL_GetGamepadAxisFromString
1115 (...)
1116@@
1117@@
1118- SDL_GameControllerGetButton
1119+ SDL_GetGamepadButton
1120 (...)
1121@@
1122@@
1123- SDL_GameControllerGetButtonFromString
1124+ SDL_GetGamepadButtonFromString
1125 (...)
1126@@
1127@@
1128- SDL_GameControllerGetFirmwareVersion
1129+ SDL_GetGamepadFirmwareVersion
1130 (...)
1131@@
1132@@
1133- SDL_GameControllerGetJoystick
1134+ SDL_GetGamepadJoystick
1135 (...)
1136@@
1137@@
1138- SDL_GameControllerGetNumTouchpadFingers
1139+ SDL_GetNumGamepadTouchpadFingers
1140 (...)
1141@@
1142@@
1143- SDL_GameControllerGetNumTouchpads
1144+ SDL_GetNumGamepadTouchpads
1145 (...)
1146@@
1147@@
1148- SDL_GameControllerGetPlayerIndex
1149+ SDL_GetGamepadPlayerIndex
1150 (...)
1151@@
1152@@
1153- SDL_GameControllerGetProduct
1154+ SDL_GetGamepadProduct
1155 (...)
1156@@
1157@@
1158- SDL_GameControllerGetProductVersion
1159+ SDL_GetGamepadProductVersion
1160 (...)
1161@@
1162@@
1163- SDL_GameControllerGetSensorData
1164+ SDL_GetGamepadSensorData
1165 (...)
1166@@
1167@@
1168- SDL_GameControllerGetSensorDataRate
1169+ SDL_GetGamepadSensorDataRate
1170 (...)
1171@@
1172@@
1173- SDL_GameControllerGetSerial
1174+ SDL_GetGamepadSerial
1175 (...)
1176@@
1177@@
1178- SDL_GameControllerGetStringForAxis
1179+ SDL_GetGamepadStringForAxis
1180 (...)
1181@@
1182@@
1183- SDL_GameControllerGetStringForButton
1184+ SDL_GetGamepadStringForButton
1185 (...)
1186@@
1187@@
1188- SDL_GameControllerGetTouchpadFinger
1189+ SDL_GetGamepadTouchpadFinger
1190 (...)
1191@@
1192@@
1193- SDL_GameControllerGetType
1194+ SDL_GetGamepadType
1195 (...)
1196@@
1197@@
1198- SDL_GameControllerGetVendor
1199+ SDL_GetGamepadVendor
1200 (...)
1201@@
1202@@
1203- SDL_GameControllerHasAxis
1204+ SDL_GamepadHasAxis
1205 (...)
1206@@
1207@@
1208- SDL_GameControllerHasButton
1209+ SDL_GamepadHasButton
1210 (...)
1211@@
1212@@
1213- SDL_GameControllerHasSensor
1214+ SDL_GamepadHasSensor
1215 (...)
1216@@
1217@@
1218- SDL_GameControllerIsSensorEnabled
1219+ SDL_GamepadSensorEnabled
1220 (...)
1221@@
1222@@
1223- SDL_GameControllerMapping
1224+ SDL_GetGamepadMapping
1225 (...)
1226@@
1227@@
1228- SDL_GameControllerMappingForGUID
1229+ SDL_GetGamepadMappingForGUID
1230 (...)
1231@@
1232@@
1233- SDL_GameControllerName
1234+ SDL_GetGamepadName
1235 (...)
1236@@
1237@@
1238- SDL_GameControllerOpen
1239+ SDL_OpenGamepad
1240 (...)
1241@@
1242@@
1243- SDL_GameControllerPath
1244+ SDL_GetGamepadPath
1245 (...)
1246@@
1247@@
1248- SDL_GameControllerRumble
1249+ SDL_RumbleGamepad
1250 (...)
1251@@
1252@@
1253- SDL_GameControllerRumbleTriggers
1254+ SDL_RumbleGamepadTriggers
1255 (...)
1256@@
1257@@
1258- SDL_GameControllerSendEffect
1259+ SDL_SendGamepadEffect
1260 (...)
1261@@
1262@@
1263- SDL_GameControllerSetLED
1264+ SDL_SetGamepadLED
1265 (...)
1266@@
1267@@
1268- SDL_GameControllerSetPlayerIndex
1269+ SDL_SetGamepadPlayerIndex
1270 (...)
1271@@
1272@@
1273- SDL_GameControllerSetSensorEnabled
1274+ SDL_SetGamepadSensorEnabled
1275 (...)
1276@@
1277@@
1278- SDL_GameControllerType
1279+ SDL_GamepadType
1280 (...)
1281@@
1282@@
1283- SDL_GameControllerUpdate
1284+ SDL_UpdateGamepads
1285 (...)
1286@@
1287@@
1288- SDL_INIT_GAMECONTROLLER
1289+ SDL_INIT_GAMEPAD
1290@ rule_init_noparachute @
1291@@
1292- SDL_INIT_NOPARACHUTE
1293+ 0
1294@@
1295@@
1296- SDL_JOYSTICK_TYPE_GAMECONTROLLER
1297+ SDL_JOYSTICK_TYPE_GAMEPAD
1298@@
1299@@
1300- SDL_JoystickAttachVirtualEx
1301+ SDL_AttachVirtualJoystick
1302 (...)
1303@@
1304@@
1305- SDL_JoystickClose
1306+ SDL_CloseJoystick
1307 (...)
1308@@
1309@@
1310- SDL_JoystickCurrentPowerLevel
1311+ SDL_GetJoystickPowerLevel
1312 (...)
1313@@
1314@@
1315- SDL_JoystickDetachVirtual
1316+ SDL_DetachVirtualJoystick
1317 (...)
1318@@
1319@@
1320- SDL_JoystickFromInstanceID
1321+ SDL_GetJoystickFromID
1322 (...)
1323@@
1324@@
1325- SDL_JoystickFromPlayerIndex
1326+ SDL_GetJoystickFromPlayerIndex
1327 (...)
1328@@
1329@@
1330- SDL_JoystickGetAttached
1331+ SDL_JoystickConnected
1332 (...)
1333@@
1334@@
1335- SDL_JoystickGetAxis
1336+ SDL_GetJoystickAxis
1337 (...)
1338@@
1339@@
1340- SDL_JoystickGetAxisInitialState
1341+ SDL_GetJoystickAxisInitialState
1342 (...)
1343@@
1344@@
1345- SDL_JoystickGetButton
1346+ SDL_GetJoystickButton
1347 (...)
1348@@
1349@@
1350- SDL_JoystickGetFirmwareVersion
1351+ SDL_GetJoystickFirmwareVersion
1352 (...)
1353@@
1354@@
1355- SDL_JoystickGetGUID
1356+ SDL_GetJoystickGUID
1357 (...)
1358@@
1359@@
1360- SDL_JoystickGetGUIDFromString
1361+ SDL_StringToGUID
1362 (...)
1363@@
1364@@
1365- SDL_JoystickGetHat
1366+ SDL_GetJoystickHat
1367 (...)
1368@@
1369@@
1370- SDL_JoystickGetPlayerIndex
1371+ SDL_GetJoystickPlayerIndex
1372 (...)
1373@@
1374@@
1375- SDL_JoystickGetProduct
1376+ SDL_GetJoystickProduct
1377 (...)
1378@@
1379@@
1380- SDL_JoystickGetProductVersion
1381+ SDL_GetJoystickProductVersion
1382 (...)
1383@@
1384@@
1385- SDL_JoystickGetSerial
1386+ SDL_GetJoystickSerial
1387 (...)
1388@@
1389@@
1390- SDL_JoystickGetType
1391+ SDL_GetJoystickType
1392 (...)
1393@@
1394@@
1395- SDL_JoystickGetVendor
1396+ SDL_GetJoystickVendor
1397 (...)
1398@@
1399@@
1400- SDL_JoystickInstanceID
1401+ SDL_GetJoystickID
1402 (...)
1403@@
1404@@
1405- SDL_JoystickName
1406+ SDL_GetJoystickName
1407 (...)
1408@@
1409@@
1410- SDL_JoystickNumAxes
1411+ SDL_GetNumJoystickAxes
1412 (...)
1413@@
1414@@
1415- SDL_JoystickNumButtons
1416+ SDL_GetNumJoystickButtons
1417 (...)
1418@@
1419@@
1420- SDL_JoystickNumHats
1421+ SDL_GetNumJoystickHats
1422 (...)
1423@@
1424@@
1425- SDL_JoystickOpen
1426+ SDL_OpenJoystick
1427 (...)
1428@@
1429@@
1430- SDL_JoystickPath
1431+ SDL_GetJoystickPath
1432 (...)
1433@@
1434@@
1435- SDL_JoystickRumble
1436+ SDL_RumbleJoystick
1437 (...)
1438@@
1439@@
1440- SDL_JoystickRumbleTriggers
1441+ SDL_RumbleJoystickTriggers
1442 (...)
1443@@
1444@@
1445- SDL_JoystickSendEffect
1446+ SDL_SendJoystickEffect
1447 (...)
1448@@
1449@@
1450- SDL_JoystickSetLED
1451+ SDL_SetJoystickLED
1452 (...)
1453@@
1454@@
1455- SDL_JoystickSetPlayerIndex
1456+ SDL_SetJoystickPlayerIndex
1457 (...)
1458@@
1459@@
1460- SDL_JoystickSetVirtualAxis
1461+ SDL_SetJoystickVirtualAxis
1462 (...)
1463@@
1464@@
1465- SDL_JoystickSetVirtualButton
1466+ SDL_SetJoystickVirtualButton
1467 (...)
1468@@
1469@@
1470- SDL_JoystickSetVirtualHat
1471+ SDL_SetJoystickVirtualHat
1472 (...)
1473@@
1474@@
1475- SDL_JoystickUpdate
1476+ SDL_UpdateJoysticks
1477 (...)
1478@@
1479@@
1480- SDL_IsScreenKeyboardShown
1481+ SDL_ScreenKeyboardShown
1482 (...)
1483@@
1484@@
1485- SDL_IsTextInputActive
1486+ SDL_TextInputActive
1487 (...)
1488@@
1489@@
1490- SDL_IsTextInputShown
1491+ SDL_TextInputShown
1492 (...)
1493@@
1494SDL_Event e1;
1495@@
1496- e1.key.keysym.mod
1497+ e1.key.mod
1498@@
1499SDL_Event *e1;
1500@@
1501- e1->key.keysym.mod
1502+ e1->key.mod
1503@@
1504SDL_KeyboardEvent *e1;
1505@@
1506- e1->keysym.mod
1507+ e1->mod
1508@@
1509SDL_Event e1;
1510@@
1511- e1.key.keysym.sym
1512+ e1.key.key
1513@@
1514SDL_Event *e1;
1515@@
1516- e1->key.keysym.sym
1517+ e1->key.key
1518@@
1519SDL_KeyboardEvent *e1;
1520@@
1521- e1->keysym.sym
1522+ e1->key
1523@@
1524SDL_Event e1;
1525@@
1526- e1.key.keysym.scancode
1527+ e1.key.scancode
1528@@
1529SDL_Event *e1;
1530@@
1531- e1->key.keysym.scancode
1532+ e1->key.scancode
1533@@
1534SDL_KeyboardEvent *e1;
1535@@
1536- e1->keysym.scancode
1537+ e1->scancode
1538@@
1539@@
1540- KMOD_ALT
1541+ SDL_KMOD_ALT
1542@@
1543@@
1544- KMOD_CAPS
1545+ SDL_KMOD_CAPS
1546@@
1547@@
1548- KMOD_CTRL
1549+ SDL_KMOD_CTRL
1550@@
1551@@
1552- KMOD_GUI
1553+ SDL_KMOD_GUI
1554@@
1555@@
1556- KMOD_LALT
1557+ SDL_KMOD_LALT
1558@@
1559@@
1560- KMOD_LCTRL
1561+ SDL_KMOD_LCTRL
1562@@
1563@@
1564- KMOD_LGUI
1565+ SDL_KMOD_LGUI
1566@@
1567@@
1568- KMOD_LSHIFT
1569+ SDL_KMOD_LSHIFT
1570@@
1571@@
1572- KMOD_MODE
1573+ SDL_KMOD_MODE
1574@@
1575@@
1576- KMOD_NONE
1577+ SDL_KMOD_NONE
1578@@
1579@@
1580- KMOD_NUM
1581+ SDL_KMOD_NUM
1582@@
1583@@
1584- KMOD_RALT
1585+ SDL_KMOD_RALT
1586@@
1587@@
1588- KMOD_RCTRL
1589+ SDL_KMOD_RCTRL
1590@@
1591@@
1592- KMOD_RGUI
1593+ SDL_KMOD_RGUI
1594@@
1595@@
1596- KMOD_RSHIFT
1597+ SDL_KMOD_RSHIFT
1598@@
1599@@
1600- KMOD_SCROLL
1601+ SDL_KMOD_SCROLL
1602@@
1603@@
1604- KMOD_SHIFT
1605+ SDL_KMOD_SHIFT
1606@@
1607@@
1608- SDL_FreeCursor
1609+ SDL_DestroyCursor
1610 (...)
1611@@
1612@@
1613- SDL_AllocFormat
1614+ SDL_GetPixelFormatDetails
1615 (...)
1616@@
1617@@
1618- SDL_AllocPalette
1619+ SDL_CreatePalette
1620 (...)
1621@@
1622@@
1623- SDL_FreePalette
1624+ SDL_DestroyPalette
1625 (...)
1626@@
1627@@
1628- SDL_MasksToPixelFormatEnum
1629+ SDL_GetPixelFormatForMasks
1630 (...)
1631@@
1632@@
1633- SDL_PixelFormatEnumToMasks
1634+ SDL_GetMasksForPixelFormat
1635 (...)
1636@@
1637@@
1638- SDL_EncloseFPoints
1639+ SDL_GetRectEnclosingPointsFloat
1640 (...)
1641@@
1642@@
1643- SDL_EnclosePoints
1644+ SDL_GetRectEnclosingPoints
1645 (...)
1646@@
1647@@
1648- SDL_FRectEmpty
1649+ SDL_RectEmptyFloat
1650 (...)
1651@@
1652@@
1653- SDL_FRectEquals
1654+ SDL_RectsEqualFloat
1655 (...)
1656@@
1657@@
1658- SDL_FRectEqualsEpsilon
1659+ SDL_RectsEqualEpsilon
1660 (...)
1661@@
1662@@
1663- SDL_HasIntersection
1664+ SDL_HasRectIntersection
1665 (...)
1666@@
1667@@
1668- SDL_HasIntersectionF
1669+ SDL_HasRectIntersectionFloat
1670 (...)
1671@@
1672@@
1673- SDL_IntersectFRect
1674+ SDL_GetRectIntersectionFloat
1675 (...)
1676@@
1677@@
1678- SDL_IntersectFRectAndLine
1679+ SDL_GetRectAndLineIntersectionFloat
1680 (...)
1681@@
1682@@
1683- SDL_IntersectRect
1684+ SDL_GetRectIntersection
1685 (...)
1686@@
1687@@
1688- SDL_IntersectRectAndLine
1689+ SDL_GetRectAndLineIntersection
1690 (...)
1691@@
1692@@
1693- SDL_PointInFRect
1694+ SDL_PointInRectFloat
1695 (...)
1696@@
1697@@
1698- SDL_RectEquals
1699+ SDL_RectsEqual
1700 (...)
1701@@
1702@@
1703- SDL_UnionFRect
1704+ SDL_GetRectUnionFloat
1705 (...)
1706@@
1707@@
1708- SDL_UnionRect
1709+ SDL_GetRectUnion
1710 (...)
1711@@
1712@@
1713- SDL_RenderCopyExF
1714+ SDL_RenderTextureRotated
1715 (...)
1716@@
1717@@
1718- SDL_RenderCopyF
1719+ SDL_RenderTexture
1720 (...)
1721@@
1722@@
1723- SDL_RenderDrawLineF
1724+ SDL_RenderLine
1725 (...)
1726@@
1727@@
1728- SDL_RenderDrawLinesF
1729+ SDL_RenderLines
1730 (...)
1731@@
1732@@
1733- SDL_RenderDrawPointF
1734+ SDL_RenderPoint
1735 (...)
1736@@
1737@@
1738- SDL_RenderDrawPointsF
1739+ SDL_RenderPoints
1740 (...)
1741@@
1742@@
1743- SDL_RenderDrawRectF
1744+ SDL_RenderRect
1745 (...)
1746@@
1747@@
1748- SDL_RenderDrawRectsF
1749+ SDL_RenderRects
1750 (...)
1751@@
1752@@
1753- SDL_RenderFillRectF
1754+ SDL_RenderFillRect
1755 (...)
1756@@
1757@@
1758- SDL_RenderFillRectsF
1759+ SDL_RenderFillRects
1760 (...)
1761@@
1762@@
1763- SDL_RenderGetClipRect
1764+ SDL_GetRenderClipRect
1765 (...)
1766@@
1767SDL_Renderer *renderer;
1768int *e1;
1769int *e2;
1770@@
1771- SDL_RenderGetLogicalSize(renderer, e1, e2)
1772+ SDL_GetRenderLogicalPresentation(renderer, e1, e2, NULL, NULL)
1773@@
1774@@
1775- SDL_RenderGetMetalCommandEncoder
1776+ SDL_GetRenderMetalCommandEncoder
1777 (...)
1778@@
1779@@
1780- SDL_RenderGetMetalLayer
1781+ SDL_GetRenderMetalLayer
1782 (...)
1783@@
1784@@
1785- SDL_RenderGetScale
1786+ SDL_GetRenderScale
1787 (...)
1788@@
1789@@
1790- SDL_RenderGetViewport
1791+ SDL_GetRenderViewport
1792 (...)
1793@@
1794@@
1795- SDL_RenderGetWindow
1796+ SDL_GetRenderWindow
1797 (...)
1798@@
1799@@
1800- SDL_RenderIsClipEnabled
1801+ SDL_RenderClipEnabled
1802 (...)
1803@@
1804@@
1805- SDL_RenderSetClipRect
1806+ SDL_SetRenderClipRect
1807 (...)
1808@@
1809SDL_Renderer *renderer;
1810expression e1;
1811expression e2;
1812@@
1813(
1814- SDL_RenderSetLogicalSize(renderer, 0, 0)
1815+ SDL_SetRenderLogicalPresentation(renderer, 0, 0, SDL_LOGICAL_PRESENTATION_DISABLED)
1816|
1817- SDL_RenderSetLogicalSize(renderer, e1, e2)
1818+ SDL_SetRenderLogicalPresentation(renderer, e1, e2, SDL_LOGICAL_PRESENTATION_LETTERBOX)
1819)
1820@@
1821@@
1822- SDL_RenderSetScale
1823+ SDL_SetRenderScale
1824 (...)
1825@@
1826@@
1827- SDL_RenderSetVSync
1828+ SDL_SetRenderVSync
1829 (...)
1830@@
1831@@
1832- SDL_RenderSetViewport
1833+ SDL_SetRenderViewport
1834 (...)
1835@@
1836@@
1837- RW_SEEK_CUR
1838+ SDL_IO_SEEK_CUR
1839@@
1840@@
1841- RW_SEEK_END
1842+ SDL_IO_SEEK_END
1843@@
1844@@
1845- RW_SEEK_SET
1846+ SDL_IO_SEEK_SET
1847@@
1848@@
1849- SDL_SensorClose
1850+ SDL_CloseSensor
1851 (...)
1852@@
1853@@
1854- SDL_SensorFromInstanceID
1855+ SDL_GetSensorFromID
1856 (...)
1857@@
1858@@
1859- SDL_SensorGetData
1860+ SDL_GetSensorData
1861 (...)
1862@@
1863@@
1864- SDL_SensorGetInstanceID
1865+ SDL_GetSensorID
1866 (...)
1867@@
1868@@
1869- SDL_SensorGetName
1870+ SDL_GetSensorName
1871 (...)
1872@@
1873@@
1874- SDL_SensorGetNonPortableType
1875+ SDL_GetSensorNonPortableType
1876 (...)
1877@@
1878@@
1879- SDL_SensorGetType
1880+ SDL_GetSensorType
1881 (...)
1882@@
1883@@
1884- SDL_SensorOpen
1885+ SDL_OpenSensor
1886 (...)
1887@@
1888@@
1889- SDL_SensorUpdate
1890+ SDL_UpdateSensors
1891 (...)
1892@@
1893@@
1894- SDL_FillRect
1895+ SDL_FillSurfaceRect
1896 (...)
1897@@
1898@@
1899- SDL_FillRects
1900+ SDL_FillSurfaceRects
1901 (...)
1902@@
1903@@
1904- SDL_FreeSurface
1905+ SDL_DestroySurface
1906 (...)
1907@@
1908@@
1909- SDL_GetClipRect
1910+ SDL_GetSurfaceClipRect
1911 (...)
1912@@
1913@@
1914- SDL_GetColorKey
1915+ SDL_GetSurfaceColorKey
1916 (...)
1917@@
1918@@
1919- SDL_HasColorKey
1920+ SDL_SurfaceHasColorKey
1921 (...)
1922@@
1923@@
1924- SDL_HasSurfaceRLE
1925+ SDL_SurfaceHasRLE
1926 (...)
1927@@
1928@@
1929- SDL_LowerBlit
1930+ SDL_BlitSurfaceUnchecked
1931 (...)
1932@@
1933expression e1, e2, e3, e4;
1934@@
1935- SDL_LowerBlitScaled(e1, e2, e3, e4)
1936+ SDL_BlitSurfaceUncheckedScaled(e1, e2, e3, e4, SDL_SCALEMODE_NEAREST)
1937@@
1938@@
1939- SDL_SetClipRect
1940+ SDL_SetSurfaceClipRect
1941 (...)
1942@@
1943@@
1944- SDL_SetColorKey
1945+ SDL_SetSurfaceColorKey
1946 (...)
1947@@
1948@@
1949- SDL_UpperBlit
1950+ SDL_BlitSurface
1951 (...)
1952@@
1953expression e1, e2, e3, e4;
1954@@
1955- SDL_UpperBlitScaled(e1, e2, e3, e4)
1956+ SDL_BlitSurfaceScaled(e1, e2, e3, e4, SDL_SCALEMODE_NEAREST)
1957@@
1958@@
1959- SDL_RenderGetD3D11Device
1960+ SDL_GetRenderD3D11Device
1961 (...)
1962@@
1963@@
1964- SDL_RenderGetD3D9Device
1965+ SDL_GetRenderD3D9Device
1966 (...)
1967@@
1968@@
1969- SDL_GetTicks64
1970+ SDL_GetTicks
1971 (...)
1972@@
1973@@
1974- SDL_GetPointDisplayIndex
1975+ SDL_GetDisplayForPoint
1976 (...)
1977@@
1978@@
1979- SDL_GetRectDisplayIndex
1980+ SDL_GetDisplayForRect
1981 (...)
1982@ depends on rule_init_noparachute @
1983expression e;
1984@@
1985- e | 0
1986+ e
1987@@
1988@@
1989- SDL_FIRSTEVENT
1990+ SDL_EVENT_FIRST
1991@@
1992@@
1993- SDL_QUIT
1994+ SDL_EVENT_QUIT
1995@@
1996@@
1997- SDL_APP_TERMINATING
1998+ SDL_EVENT_TERMINATING
1999@@
2000@@
2001- SDL_APP_LOWMEMORY
2002+ SDL_EVENT_LOW_MEMORY
2003@@
2004@@
2005- SDL_APP_WILLENTERBACKGROUND
2006+ SDL_EVENT_WILL_ENTER_BACKGROUND
2007@@
2008@@
2009- SDL_APP_DIDENTERBACKGROUND
2010+ SDL_EVENT_DID_ENTER_BACKGROUND
2011@@
2012@@
2013- SDL_APP_WILLENTERFOREGROUND
2014+ SDL_EVENT_WILL_ENTER_FOREGROUND
2015@@
2016@@
2017- SDL_APP_DIDENTERFOREGROUND
2018+ SDL_EVENT_DID_ENTER_FOREGROUND
2019@@
2020@@
2021- SDL_LOCALECHANGED
2022+ SDL_EVENT_LOCALE_CHANGED
2023@@
2024@@
2025- SDL_DISPLAYEVENT_ORIENTATION
2026+ SDL_EVENT_DISPLAY_ORIENTATION
2027@@
2028@@
2029- SDL_DISPLAYEVENT_CONNECTED
2030+ SDL_EVENT_DISPLAY_CONNECTED
2031@@
2032@@
2033- SDL_DISPLAYEVENT_DISCONNECTED
2034+ SDL_EVENT_DISPLAY_DISCONNECTED
2035@@
2036@@
2037- SDL_DISPLAYEVENT_MOVED
2038+ SDL_EVENT_DISPLAY_MOVED
2039@@
2040@@
2041- SDL_DISPLAYEVENT_FIRST
2042+ SDL_EVENT_DISPLAY_FIRST
2043@@
2044@@
2045- SDL_DISPLAYEVENT_LAST
2046+ SDL_EVENT_DISPLAY_LAST
2047@@
2048@@
2049- SDL_SYSWMEVENT
2050+ SDL_EVENT_SYSWM
2051@@
2052@@
2053- SDL_WINDOWEVENT_SHOWN
2054+ SDL_EVENT_WINDOW_SHOWN
2055@@
2056@@
2057- SDL_WINDOWEVENT_HIDDEN
2058+ SDL_EVENT_WINDOW_HIDDEN
2059@@
2060@@
2061- SDL_WINDOWEVENT_EXPOSED
2062+ SDL_EVENT_WINDOW_EXPOSED
2063@@
2064@@
2065- SDL_WINDOWEVENT_MOVED
2066+ SDL_EVENT_WINDOW_MOVED
2067@@
2068@@
2069- SDL_WINDOWEVENT_RESIZED
2070+ SDL_EVENT_WINDOW_RESIZED
2071@@
2072@@
2073- SDL_WINDOWEVENT_SIZE_CHANGED
2074+ SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED
2075@@
2076@@
2077- SDL_WINDOWEVENT_MINIMIZED
2078+ SDL_EVENT_WINDOW_MINIMIZED
2079@@
2080@@
2081- SDL_WINDOWEVENT_MAXIMIZED
2082+ SDL_EVENT_WINDOW_MAXIMIZED
2083@@
2084@@
2085- SDL_WINDOWEVENT_RESTORED
2086+ SDL_EVENT_WINDOW_RESTORED
2087@@
2088@@
2089- SDL_WINDOWEVENT_ENTER
2090+ SDL_EVENT_WINDOW_MOUSE_ENTER
2091@@
2092@@
2093- SDL_WINDOWEVENT_LEAVE
2094+ SDL_EVENT_WINDOW_MOUSE_LEAVE
2095@@
2096@@
2097- SDL_WINDOWEVENT_FOCUS_GAINED
2098+ SDL_EVENT_WINDOW_FOCUS_GAINED
2099@@
2100@@
2101- SDL_WINDOWEVENT_FOCUS_LOST
2102+ SDL_EVENT_WINDOW_FOCUS_LOST
2103@@
2104@@
2105- SDL_WINDOWEVENT_CLOSE
2106+ SDL_EVENT_WINDOW_CLOSE_REQUESTED
2107@@
2108@@
2109- SDL_WINDOWEVENT_TAKE_FOCUS
2110+ /* FIXME MIGRATION: SDL_WINDOWEVENT_TAKE_FOCUS has been removed; there is no replacement. */ 0
2111@@
2112@@
2113- SDL_WINDOWEVENT_HIT_TEST
2114+ SDL_EVENT_WINDOW_HIT_TEST
2115@@
2116@@
2117- SDL_WINDOWEVENT_ICCPROF_CHANGED
2118+ SDL_EVENT_WINDOW_ICCPROF_CHANGED
2119@@
2120@@
2121- SDL_WINDOWEVENT_DISPLAY_CHANGED
2122+ SDL_EVENT_WINDOW_DISPLAY_CHANGED
2123@@
2124@@
2125- SDL_WINDOWEVENT_FIRST
2126+ SDL_EVENT_WINDOW_FIRST
2127@@
2128@@
2129- SDL_WINDOWEVENT_LAST
2130+ SDL_EVENT_WINDOW_LAST
2131@@
2132@@
2133- SDL_KEYDOWN
2134+ SDL_EVENT_KEY_DOWN
2135@@
2136@@
2137- SDL_KEYUP
2138+ SDL_EVENT_KEY_UP
2139@@
2140@@
2141- SDL_TEXTEDITING
2142+ SDL_EVENT_TEXT_EDITING
2143@@
2144@@
2145- SDL_TEXTINPUT
2146+ SDL_EVENT_TEXT_INPUT
2147@@
2148@@
2149- SDL_KEYMAPCHANGED
2150+ SDL_EVENT_KEYMAP_CHANGED
2151@@
2152@@
2153- SDL_TEXTEDITING_EXT
2154+ SDL_EVENT_TEXT_EDITING_EXT
2155@@
2156@@
2157- SDL_MOUSEMOTION
2158+ SDL_EVENT_MOUSE_MOTION
2159@@
2160@@
2161- SDL_MOUSEBUTTONDOWN
2162+ SDL_EVENT_MOUSE_BUTTON_DOWN
2163@@
2164@@
2165- SDL_MOUSEBUTTONUP
2166+ SDL_EVENT_MOUSE_BUTTON_UP
2167@@
2168@@
2169- SDL_MOUSEWHEEL
2170+ SDL_EVENT_MOUSE_WHEEL
2171@@
2172@@
2173- SDL_JOYAXISMOTION
2174+ SDL_EVENT_JOYSTICK_AXIS_MOTION
2175@@
2176@@
2177- SDL_JOYBALLMOTION
2178+ SDL_EVENT_JOYSTICK_BALL_MOTION
2179@@
2180@@
2181- SDL_JOYHATMOTION
2182+ SDL_EVENT_JOYSTICK_HAT_MOTION
2183@@
2184@@
2185- SDL_JOYBUTTONDOWN
2186+ SDL_EVENT_JOYSTICK_BUTTON_DOWN
2187@@
2188@@
2189- SDL_JOYBUTTONUP
2190+ SDL_EVENT_JOYSTICK_BUTTON_UP
2191@@
2192@@
2193- SDL_JOYDEVICEADDED
2194+ SDL_EVENT_JOYSTICK_ADDED
2195@@
2196@@
2197- SDL_JOYDEVICEREMOVED
2198+ SDL_EVENT_JOYSTICK_REMOVED
2199@@
2200@@
2201- SDL_JOYBATTERYUPDATED
2202+ SDL_EVENT_JOYSTICK_BATTERY_UPDATED
2203@@
2204@@
2205- SDL_FINGERDOWN
2206+ SDL_EVENT_FINGER_DOWN
2207@@
2208@@
2209- SDL_FINGERUP
2210+ SDL_EVENT_FINGER_UP
2211@@
2212@@
2213- SDL_FINGERMOTION
2214+ SDL_EVENT_FINGER_MOTION
2215@@
2216@@
2217- SDL_CLIPBOARDUPDATE
2218+ SDL_EVENT_CLIPBOARD_UPDATE
2219@@
2220@@
2221- SDL_DROPFILE
2222+ SDL_EVENT_DROP_FILE
2223@@
2224@@
2225- SDL_DROPTEXT
2226+ SDL_EVENT_DROP_TEXT
2227@@
2228@@
2229- SDL_DROPBEGIN
2230+ SDL_EVENT_DROP_BEGIN
2231@@
2232@@
2233- SDL_DROPCOMPLETE
2234+ SDL_EVENT_DROP_COMPLETE
2235@@
2236@@
2237- SDL_AUDIODEVICEADDED
2238+ SDL_EVENT_AUDIO_DEVICE_ADDED
2239@@
2240@@
2241- SDL_AUDIODEVICEREMOVED
2242+ SDL_EVENT_AUDIO_DEVICE_REMOVED
2243@@
2244@@
2245- SDL_SENSORUPDATE
2246+ SDL_EVENT_SENSOR_UPDATE
2247@@
2248@@
2249- SDL_RENDER_TARGETS_RESET
2250+ SDL_EVENT_RENDER_TARGETS_RESET
2251@@
2252@@
2253- SDL_RENDER_DEVICE_RESET
2254+ SDL_EVENT_RENDER_DEVICE_RESET
2255@@
2256@@
2257- SDL_POLLSENTINEL
2258+ SDL_EVENT_POLL_SENTINEL
2259@@
2260@@
2261- SDL_USEREVENT
2262+ SDL_EVENT_USER
2263@@
2264@@
2265- SDL_LASTEVENT
2266+ SDL_EVENT_LAST
2267@@
2268@@
2269- SDL_WINDOW_INPUT_GRABBED
2270+ SDL_WINDOW_MOUSE_GRABBED
2271@@
2272@@
2273- SDL_GetWindowDisplayIndex
2274+ SDL_GetDisplayForWindow
2275 (...)
2276@@
2277@@
2278- SDL_SetWindowDisplayMode
2279+ SDL_SetWindowFullscreenMode
2280 (...)
2281@@
2282@@
2283- SDL_GetWindowDisplayMode
2284+ SDL_GetWindowFullscreenMode
2285 (...)
2286@@
2287@@
2288- SDL_GetClosestDisplayMode
2289+ SDL_GetClosestFullscreenDisplayMode
2290 (...)
2291@@
2292@@
2293- SDL_GetRendererOutputSize
2294+ SDL_GetCurrentRenderOutputSize
2295 (...)
2296@@
2297@@
2298- SDL_RenderWindowToLogical
2299+ SDL_RenderCoordinatesFromWindow
2300 (...)
2301@@
2302@@
2303- SDL_RenderLogicalToWindow
2304+ SDL_RenderCoordinatesToWindow
2305 (...)
2306@@
2307symbol SDL_ScaleModeNearest;
2308@@
2309- SDL_ScaleModeNearest
2310+ SDL_SCALEMODE_NEAREST
2311@@
2312symbol SDL_ScaleModeLinear;
2313@@
2314- SDL_ScaleModeLinear
2315+ SDL_SCALEMODE_LINEAR
2316@@
2317@@
2318- SDL_RenderCopy
2319+ SDL_RenderTexture
2320 (...)
2321@@
2322@@
2323- SDL_RenderCopyEx
2324+ SDL_RenderTextureRotated
2325 (...)
2326@@
2327SDL_Renderer *renderer;
2328constant c1;
2329constant c2;
2330constant c3;
2331constant c4;
2332expression e1;
2333expression e2;
2334expression e3;
2335expression e4;
2336@@
2337- SDL_RenderDrawLine(renderer,
2338+ SDL_RenderLine(renderer,
2339(
2340 c1
2341|
2342- e1
2343+ (float)e1
2344)
2345 ,
2346(
2347 c2
2348|
2349- e2
2350+ (float)e2
2351)
2352 ,
2353(
2354 c3
2355|
2356- e3
2357+ (float)e3
2358)
2359 ,
2360(
2361 c4
2362|
2363- e4
2364+ (float)e4
2365)
2366 )
2367@@
2368@@
2369- SDL_RenderDrawLines
2370+ SDL_RenderLines
2371 (...)
2372@@
2373SDL_Renderer *renderer;
2374constant c1;
2375constant c2;
2376expression e1;
2377expression e2;
2378@@
2379- SDL_RenderDrawPoint(renderer,
2380+ SDL_RenderPoint(renderer,
2381(
2382 c1
2383|
2384- e1
2385+ (float)e1
2386)
2387 ,
2388(
2389 c2
2390|
2391- e2
2392+ (float)e2
2393)
2394 )
2395@@
2396@@
2397- SDL_RenderDrawPoints
2398+ SDL_RenderPoints
2399 (...)
2400@@
2401@@
2402- SDL_RenderDrawRect
2403+ SDL_RenderRect
2404 (...)
2405@@
2406@@
2407- SDL_RenderDrawRects
2408+ SDL_RenderRects
2409 (...)
2410@@
2411@@
2412- SDL_GL_GetDrawableSize
2413+ SDL_GetWindowSizeInPixels
2414 (...)
2415@@
2416@@
2417- SDL_Metal_GetDrawableSize
2418+ SDL_GetWindowSizeInPixels
2419 (...)
2420@@
2421@@
2422- SDL_Vulkan_GetDrawableSize
2423+ SDL_GetWindowSizeInPixels
2424 (...)
2425@@
2426@@
2427- SDL_IsScreenSaverEnabled
2428+ SDL_ScreenSaverEnabled
2429 (...)
2430@@
2431SDL_Event e1;
2432@@
2433- e1.caxis
2434+ e1.gaxis
2435@@
2436SDL_Event *e1;
2437@@
2438- e1->caxis
2439+ e1->gaxis
2440@@
2441SDL_Event e1;
2442@@
2443- e1.cbutton
2444+ e1.gbutton
2445@@
2446SDL_Event *e1;
2447@@
2448- e1->cbutton
2449+ e1->gbutton
2450@@
2451SDL_Event e1;
2452@@
2453- e1.cdevice
2454+ e1.gdevice
2455@@
2456SDL_Event *e1;
2457@@
2458- e1->cdevice
2459+ e1->gdevice
2460@@
2461SDL_Event e1;
2462@@
2463- e1.ctouchpad
2464+ e1.gtouchpad
2465@@
2466SDL_Event *e1;
2467@@
2468- e1->ctouchpad
2469+ e1->gtouchpad
2470@@
2471SDL_Event e1;
2472@@
2473- e1.csensor
2474+ e1.gsensor
2475@@
2476SDL_Event *e1;
2477@@
2478- e1->csensor
2479+ e1->gsensor
2480@@
2481SDL_Event e1;
2482@@
2483- e1.wheel.mouseX
2484+ e1.wheel.mouse_x
2485@@
2486SDL_Event *e1;
2487@@
2488- e1->wheel.mouseX
2489+ e1->wheel.mouse_x
2490@@
2491SDL_MouseWheelEvent *e1;
2492@@
2493- e1->mouseX
2494+ e1->mouse_x
2495@@
2496SDL_Event e1;
2497@@
2498- e1.wheel.mouseY
2499+ e1.wheel.mouse_y
2500@@
2501SDL_Event *e1;
2502@@
2503- e1->wheel.mouseY
2504+ e1->wheel.mouse_y
2505@@
2506SDL_MouseWheelEvent *e1;
2507@@
2508- e1->mouseY
2509+ e1->mouse_y
2510@@
2511SDL_Event e1;
2512@@
2513- e1.wheel.preciseX
2514+ e1.wheel.x
2515@@
2516SDL_Event *e1;
2517@@
2518- e1->wheel.preciseX
2519+ e1->wheel.x
2520@@
2521SDL_MouseWheelEvent *e1;
2522@@
2523- e1->preciseX
2524+ e1->x
2525@@
2526SDL_Event e1;
2527@@
2528- e1.wheel.preciseY
2529+ e1.wheel.y
2530@@
2531SDL_Event *e1;
2532@@
2533- e1->wheel.preciseY
2534+ e1->wheel.y
2535@@
2536SDL_MouseWheelEvent *e1;
2537@@
2538- e1->preciseY
2539+ e1->y
2540@@
2541SDL_Event e1;
2542@@
2543- e1.tfinger.touchId
2544+ e1.tfinger.touchID
2545@@
2546SDL_Event *e1;
2547@@
2548- e1->tfinger.touchId
2549+ e1->tfinger.touchID
2550@@
2551SDL_TouchFingerEvent *e1;
2552@@
2553- e1->touchId
2554+ e1->touchID
2555@@
2556SDL_Event e1;
2557@@
2558- e1.tfinger.fingerId
2559+ e1.tfinger.fingerID
2560@@
2561SDL_Event *e1;
2562@@
2563- e1->tfinger.fingerId
2564+ e1->tfinger.fingerID
2565@@
2566SDL_TouchFingerEvent *e1;
2567@@
2568- e1->fingerId
2569+ e1->fingerID
2570@@
2571expression e1, e2, e3, e4;
2572@@
2573- SDL_CreateWindow(e1, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, e2, e3, e4)
2574+ SDL_CreateWindow(e1, e2, e3, e4)
2575@@
2576expression e1, e2, e3, e4;
2577constant c1, c2;
2578@@
2579- SDL_CreateShapedWindow(e1, c1, c2, e2, e3, e4)
2580+ SDL_CreateShapedWindow(e1, e2, e3, e4)
2581@@
2582typedef SDL_atomic_t, SDL_AtomicInt;
2583@@
2584- SDL_atomic_t
2585+ SDL_AtomicInt
2586@@
2587@@
2588- SDL_SemWait
2589+ SDL_WaitSemaphore
2590 (...)
2591@@
2592@@
2593- SDL_SemTryWait
2594+ SDL_TryWaitSemaphore
2595 (...)
2596@@
2597@@
2598- SDL_SemWaitTimeout
2599+ SDL_WaitSemaphoreTimeout
2600 (...)
2601@@
2602@@
2603- SDL_SemPost
2604+ SDL_SignalSemaphore
2605 (...)
2606@@
2607@@
2608- SDL_SemValue
2609+ SDL_GetSemaphoreValue
2610 (...)
2611@@
2612@@
2613- SDL_CreateCond
2614+ SDL_CreateCondition
2615 (...)
2616@@
2617@@
2618- SDL_DestroyCond
2619+ SDL_DestroyCondition
2620 (...)
2621@@
2622@@
2623- SDL_CondSignal
2624+ SDL_SignalCondition
2625 (...)
2626@@
2627@@
2628- SDL_CondBroadcast
2629+ SDL_BroadcastCondition
2630 (...)
2631@@
2632@@
2633- SDL_CondWait
2634+ SDL_WaitCondition
2635 (...)
2636@@
2637@@
2638- SDL_CondWaitTimeout
2639+ SDL_WaitConditionTimeout
2640 (...)
2641@@
2642typedef SDL_mutex, SDL_Mutex;
2643@@
2644- SDL_mutex
2645+ SDL_Mutex
2646@@
2647typedef SDL_sem, SDL_Semaphore;
2648@@
2649- SDL_sem
2650+ SDL_Semaphore
2651@@
2652typedef SDL_cond, SDL_Condition;
2653@@
2654- SDL_cond
2655+ SDL_Condition
2656@@
2657@@
2658- AUDIO_F32
2659+ SDL_AUDIO_F32LE
2660@@
2661@@
2662- AUDIO_F32LSB
2663+ SDL_AUDIO_F32LE
2664@@
2665@@
2666- AUDIO_F32MSB
2667+ SDL_AUDIO_F32BE
2668@@
2669@@
2670- AUDIO_F32SYS
2671+ SDL_AUDIO_F32
2672@@
2673@@
2674- AUDIO_S16
2675+ SDL_AUDIO_S16LE
2676@@
2677@@
2678- AUDIO_S16LSB
2679+ SDL_AUDIO_S16LE
2680@@
2681@@
2682- AUDIO_S16MSB
2683+ SDL_AUDIO_S16BE
2684@@
2685@@
2686- AUDIO_S16SYS
2687+ SDL_AUDIO_S16
2688@@
2689@@
2690- AUDIO_S32
2691+ SDL_AUDIO_S32LE
2692@@
2693@@
2694- AUDIO_S32LSB
2695+ SDL_AUDIO_S32LE
2696@@
2697@@
2698- AUDIO_S32MSB
2699+ SDL_AUDIO_S32BE
2700@@
2701@@
2702- AUDIO_S32SYS
2703+ SDL_AUDIO_S32
2704@@
2705@@
2706- AUDIO_S8
2707+ SDL_AUDIO_S8
2708@@
2709@@
2710- AUDIO_U8
2711+ SDL_AUDIO_U8
2712@@
2713@@
2714- SDL_WINDOW_ALLOW_HIGHDPI
2715+ SDL_WINDOW_HIGH_PIXEL_DENSITY
2716@@
2717@@
2718- SDL_TLSGet
2719+ SDL_GetTLS
2720 (...)
2721@@
2722@@
2723- SDL_TLSSet
2724+ SDL_SetTLS
2725 (...)
2726@@
2727@@
2728- SDL_TLSCleanup
2729+ SDL_CleanupTLS
2730 (...)
2731@@
2732@@
2733- SDL_GetDisplayOrientation
2734+ SDL_GetDisplayCurrentOrientation
2735 (...)
2736@@
2737@@
2738- SDL_WINDOW_SKIP_TASKBAR
2739+ SDL_WINDOW_UTILITY
2740@@
2741@@
2742- SDL_PIXELFORMAT_BGR444
2743+ SDL_PIXELFORMAT_XBGR4444
2744@@
2745@@
2746- SDL_PIXELFORMAT_BGR555
2747+ SDL_PIXELFORMAT_XBGR1555
2748@@
2749@@
2750- SDL_PIXELFORMAT_BGR888
2751+ SDL_PIXELFORMAT_XBGR8888
2752@@
2753@@
2754- SDL_PIXELFORMAT_RGB444
2755+ SDL_PIXELFORMAT_XRGB4444
2756@@
2757@@
2758- SDL_PIXELFORMAT_RGB555
2759+ SDL_PIXELFORMAT_XRGB1555
2760@@
2761@@
2762- SDL_PIXELFORMAT_RGB888
2763+ SDL_PIXELFORMAT_XRGB8888
2764@@
2765@@
2766- SDL_strtokr
2767+ SDL_strtok_r
2768 (...)
2769@@
2770@@
2771- SDL_ReadLE16
2772+ SDL_ReadU16LE
2773 (...)
2774@@
2775@@
2776- SDL_ReadLE32
2777+ SDL_ReadU32LE
2778 (...)
2779@@
2780@@
2781- SDL_ReadBE32
2782+ SDL_ReadU32BE
2783 (...)
2784@@
2785@@
2786- SDL_ReadBE16
2787+ SDL_ReadU16BE
2788 (...)
2789@@
2790@@
2791- SDL_ReadLE64
2792+ SDL_ReadU64LE
2793 (...)
2794@@
2795@@
2796- SDL_ReadBE64
2797+ SDL_ReadU64BE
2798 (...)
2799@@
2800@@
2801- SDL_WriteLE16
2802+ SDL_WriteU16LE
2803 (...)
2804@@
2805@@
2806- SDL_WriteBE16
2807+ SDL_WriteU16BE
2808 (...)
2809@@
2810@@
2811- SDL_WriteLE32
2812+ SDL_WriteU32LE
2813 (...)
2814@@
2815@@
2816- SDL_WriteBE32
2817+ SDL_WriteU32BE
2818 (...)
2819@@
2820@@
2821- SDL_WriteLE64
2822+ SDL_WriteU64LE
2823 (...)
2824@@
2825@@
2826- SDL_WriteBE64
2827+ SDL_WriteU64BE
2828 (...)
2829@@
2830expression e, n;
2831@@
2832- SDL_GetWindowData(e, n)
2833+ SDL_GetProperty(SDL_GetWindowProperties(e), n)
2834@@
2835expression e, n, v;
2836@@
2837- SDL_SetWindowData(e, n, v)
2838+ SDL_SetProperty(SDL_GetWindowProperties(e), n, v, NULL, NULL)
2839@@
2840expression w, i, s;
2841@@
2842- SDL_Vulkan_CreateSurface(w, i, s)
2843+ SDL_Vulkan_CreateSurface(w, i, NULL, s)
2844@@
2845@@
2846- SDL_RenderFlush
2847+ SDL_FlushRenderer
2848 (...)
2849@@
2850@@
2851- SDL_CONTROLLERSTEAMHANDLEUPDATED
2852+ SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED
2853@@
2854@@
2855- SDL_GameControllerGetSteamHandle
2856+ SDL_GetGamepadSteamHandle
2857 (...)
2858@@
2859expression e1, e2, e3, e4;
2860@@
2861- SDL_SoftStretch(e1, e2, e3, e4)
2862+ SDL_SoftStretch(e1, e2, e3, e4, SDL_SCALEMODE_NEAREST)
2863@@
2864expression e1, e2, e3, e4;
2865@@
2866- SDL_SoftStretchLinear(e1, e2, e3, e4)
2867+ SDL_SoftStretch(e1, e2, e3, e4, SDL_SCALEMODE_LINEAR)
2868@@
2869@@
2870- SDL_HapticClose
2871+ SDL_CloseHaptic
2872 (...)
2873@@
2874@@
2875- SDL_HapticOpen
2876+ SDL_OpenHaptic
2877 (...)
2878@@
2879@@
2880- SDL_HapticOpenFromMouse
2881+ SDL_OpenHapticFromMouse
2882 (...)
2883@@
2884@@
2885- SDL_HapticOpenFromJoystick
2886+ SDL_OpenHapticFromJoystick
2887 (...)
2888@@
2889@@
2890- SDL_MouseIsHaptic
2891+ SDL_IsMouseHaptic
2892 (...)
2893@@
2894@@
2895- SDL_JoystickIsHaptic
2896+ SDL_IsJoystickHaptic
2897 (...)
2898@@
2899@@
2900- SDL_HapticNumEffects
2901+ SDL_GetMaxHapticEffects
2902 (...)
2903@@
2904@@
2905- SDL_HapticNumEffectsPlaying
2906+ SDL_GetMaxHapticEffectsPlaying
2907 (...)
2908@@
2909@@
2910- SDL_HapticQuery
2911+ SDL_GetHapticFeatures
2912 (...)
2913@@
2914@@
2915- SDL_HapticNumAxes
2916+ SDL_GetNumHapticAxes
2917 (...)
2918@@
2919@@
2920- SDL_HapticNewEffect
2921+ SDL_CreateHapticEffect
2922 (...)
2923@@
2924@@
2925- SDL_HapticUpdateEffect
2926+ SDL_UpdateHapticEffect
2927 (...)
2928@@
2929@@
2930- SDL_HapticRunEffect
2931+ SDL_RunHapticEffect
2932 (...)
2933@@
2934@@
2935- SDL_HapticStopEffect
2936+ SDL_StopHapticEffect
2937 (...)
2938@@
2939@@
2940- SDL_HapticDestroyEffect
2941+ SDL_DestroyHapticEffect
2942 (...)
2943@@
2944@@
2945- SDL_HapticGetEffectStatus
2946+ SDL_GetHapticEffectStatus
2947 (...)
2948@@
2949@@
2950- SDL_HapticSetGain
2951+ SDL_SetHapticGain
2952 (...)
2953@@
2954@@
2955- SDL_HapticSetAutocenter
2956+ SDL_SetHapticAutocenter
2957 (...)
2958@@
2959@@
2960- SDL_HapticPause
2961+ SDL_PauseHaptic
2962 (...)
2963@@
2964@@
2965- SDL_HapticUnpause
2966+ SDL_ResumeHaptic
2967 (...)
2968@@
2969@@
2970- SDL_HapticStopAll
2971+ SDL_StopHapticEffects
2972 (...)
2973@@
2974@@
2975- SDL_HapticRumbleInit
2976+ SDL_InitHapticRumble
2977 (...)
2978@@
2979@@
2980- SDL_HapticRumblePlay
2981+ SDL_PlayHapticRumble
2982 (...)
2983@@
2984@@
2985- SDL_HapticRumbleStop
2986+ SDL_StopHapticRumble
2987 (...)
2988@@
2989@@
2990- SDL_AtomicTryLock
2991+ SDL_TryLockSpinlock
2992 (...)
2993@@
2994@@
2995- SDL_AtomicLock
2996+ SDL_LockSpinlock
2997 (...)
2998@@
2999@@
3000- SDL_AtomicUnlock
3001+ SDL_UnlockSpinlock
3002 (...)
3003@@
3004@@
3005- SDL_AtomicCAS
3006+ SDL_CompareAndSwapAtomicInt
3007 (...)
3008@@
3009@@
3010- SDL_AtomicSet
3011+ SDL_SetAtomicInt
3012 (...)
3013@@
3014@@
3015- SDL_AtomicGet
3016+ SDL_GetAtomicInt
3017 (...)
3018@@
3019@@
3020- SDL_AtomicAdd
3021+ SDL_AddAtomicInt
3022 (...)
3023@@
3024@@
3025- SDL_AtomicCASPtr
3026+ SDL_CompareAndSwapAtomicPointer
3027 (...)
3028@@
3029@@
3030- SDL_AtomicSetPtr
3031+ SDL_SetAtomicPointer
3032 (...)
3033@@
3034@@
3035- SDL_AtomicGetPtr
3036+ SDL_GetAtomicPointer
3037 (...)
3038@@
3039@@
3040- SDL_ThreadID
3041+ SDL_GetCurrentThreadID
3042 (...)
3043@@
3044@@
3045- SDL_threadID
3046+ SDL_ThreadID
3047 (...)
3048@@
3049@@
3050- SDL_HasWindowSurface
3051+ SDL_WindowHasSurface
3052 (...)
3053@@
3054SDL_PixelFormat e1;
3055@@
3056- e1.BitsPerPixel
3057+ e1.bits_per_pixel
3058@@
3059SDL_PixelFormat *e1;
3060@@
3061- e1->BitsPerPixel
3062+ e1->bits_per_pixel
3063@@
3064SDL_PixelFormat e1;
3065@@
3066- e1.BytesPerPixel
3067+ e1.bytes_per_pixel
3068@@
3069SDL_PixelFormat *e1;
3070@@
3071- e1->BytesPerPixel
3072+ e1->bytes_per_pixel
3073@@
3074SDL_MessageBoxButtonData e1;
3075@@
3076- e1.buttonid
3077+ e1.buttonID
3078@@
3079SDL_MessageBoxButtonData *e1;
3080@@
3081- e1->buttonid
3082+ e1->buttonID
3083@@
3084SDL_GamepadBinding e1;
3085@@
3086- e1.inputType
3087+ e1.input_type
3088@@
3089SDL_GamepadBinding *e1;
3090@@
3091- e1->inputType
3092+ e1->input_type
3093@@
3094SDL_GamepadBinding e1;
3095@@
3096- e1.outputType
3097+ e1.output_type
3098@@
3099SDL_GamepadBinding *e1;
3100@@
3101- e1->outputType
3102+ e1->output_type
3103@@
3104@@
3105- SDL_HINT_ALLOW_TOPMOST
3106+ SDL_HINT_WINDOW_ALLOW_TOPMOST
3107@@
3108@@
3109- SDL_HINT_DIRECTINPUT_ENABLED
3110+ SDL_HINT_JOYSTICK_DIRECTINPUT
3111@@
3112@@
3113- SDL_HINT_GDK_TEXTINPUT_DEFAULT
3114+ SDL_HINT_GDK_TEXTINPUT_DEFAULT_TEXT
3115@@
3116@@
3117- SDL_HINT_JOYSTICK_GAMECUBE_RUMBLE_BRAKE
3118+ SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE_RUMBLE_BRAKE
3119@@
3120@@
3121- SDL_HINT_LINUX_DIGITAL_HATS
3122+ SDL_HINT_JOYSTICK_LINUX_DIGITAL_HATS
3123@@
3124@@
3125- SDL_HINT_LINUX_HAT_DEADZONES
3126+ SDL_HINT_JOYSTICK_LINUX_HAT_DEADZONES
3127@@
3128@@
3129- SDL_HINT_LINUX_JOYSTICK_CLASSIC
3130+ SDL_HINT_JOYSTICK_LINUX_CLASSIC
3131@@
3132@@
3133- SDL_HINT_LINUX_JOYSTICK_DEADZONES
3134+ SDL_HINT_JOYSTICK_LINUX_DEADZONES
3135@@
3136@@
3137- SDL_HINT_PS2_DYNAMIC_VSYNC
3138+ SDL_HINT_RENDER_PS2_DYNAMIC_VSYNC
3139@@
3140@@
3141- SDL_JoystickNumBalls
3142+ SDL_GetNumJoystickBalls
3143 (...)
3144@@
3145@@
3146- SDL_JoystickGetBall
3147+ SDL_GetJoystickBall
3148 (...)
3149@@
3150@@
3151- SDL_RWclose
3152+ SDL_CloseIO
3153 (...)
3154@@
3155@@
3156- SDL_RWread
3157+ SDL_ReadIO
3158 (...)
3159@@
3160@@
3161- SDL_RWwrite
3162+ SDL_WriteIO
3163 (...)
3164@@
3165@@
3166- SDL_RWtell
3167+ SDL_TellIO
3168 (...)
3169@@
3170@@
3171- SDL_RWsize
3172+ SDL_SizeIO
3173 (...)
3174@@
3175@@
3176- SDL_RWseek
3177+ SDL_SeekIO
3178 (...)
3179@@
3180@@
3181- SDL_LoadBMP_RW
3182+ SDL_LoadBMP_IO
3183 (...)
3184@@
3185@@
3186- SDL_LoadWAV_RW
3187+ SDL_LoadWAV_IO
3188 (...)
3189@@
3190@@
3191- SDL_SaveBMP_RW
3192+ SDL_SaveBMP_IO
3193 (...)
3194@@
3195@@
3196- SDL_RWFromFile
3197+ SDL_IOFromFile
3198 (...)
3199@@
3200@@
3201- SDL_RWFromMem
3202+ SDL_IOFromMem
3203 (...)
3204@@
3205@@
3206- SDL_RWFromConstMem
3207+ SDL_IOFromConstMem
3208 (...)
3209@@
3210typedef SDL_RWops, SDL_IOStream;
3211@@
3212- SDL_RWops
3213+ SDL_IOStream
3214@@
3215@@
3216- SDL_LogGetOutputFunction
3217+ SDL_GetLogOutputFunction
3218 (...)
3219@@
3220@@
3221- SDL_LogSetOutputFunction
3222+ SDL_SetLogOutputFunction
3223 (...)
3224@@
3225typedef SDL_eventaction, SDL_EventAction;
3226@@
3227- SDL_eventaction
3228+ SDL_EventAction
3229@@
3230typedef SDL_RendererFlip, SDL_FlipMode;
3231@@
3232- SDL_RendererFlip
3233+ SDL_FlipMode
3234@@
3235typedef SDL_Colour, SDL_Color;
3236@@
3237- SDL_Colour
3238+ SDL_Color
3239@@
3240@@
3241- SDL_iPhoneSetAnimationCallback
3242+ SDL_SetiOSAnimationCallback
3243 (...)
3244@@
3245@@
3246- SDL_iPhoneSetEventPump
3247+ SDL_SetiOSEventPump
3248 (...)
3249@@
3250@@
3251- SDL_COMPILEDVERSION
3252+ SDL_VERSION
3253@@
3254@@
3255- SDL_PATCHLEVEL
3256+ SDL_MICRO_VERSION
3257@@
3258@@
3259- SDL_TABLESIZE
3260+ SDL_arraysize
3261@@
3262@@
3263- SDLK_QUOTE
3264+ SDLK_APOSTROPHE
3265@@
3266@@
3267- SDLK_BACKQUOTE
3268+ SDLK_GRAVE
3269@@
3270@@
3271- SDLK_QUOTEDBL
3272+ SDLK_DBLAPOSTROPHE
3273@@
3274@@
3275- SDL_LogSetAllPriority
3276+ SDL_SetLogPriorities
3277 (...)
3278@@
3279@@
3280- SDL_LogSetPriority
3281+ SDL_SetLogPriority
3282 (...)
3283@@
3284@@
3285- SDL_LogGetPriority
3286+ SDL_GetLogPriority
3287 (...)
3288@@
3289@@
3290- SDL_LogResetPriorities
3291+ SDL_ResetLogPriorities
3292 (...)
3293@@
3294@@
3295- SDL_SIMDGetAlignment
3296+ SDL_GetSIMDAlignment
3297 (...)
3298@@
3299@@
3300- SDL_MixAudioFormat
3301+ SDL_MixAudio
3302 (...)
3303@@
3304@@
3305- SDL_BlitScaled
3306+ SDL_BlitSurfaceScaled
3307 (...)
3308@@
3309@@
3310- SDL_SYSTEM_CURSOR_ARROW
3311+ SDL_SYSTEM_CURSOR_DEFAULT
3312@@
3313@@
3314- SDL_SYSTEM_CURSOR_IBEAM
3315+ SDL_SYSTEM_CURSOR_TEXT
3316@@
3317@@
3318- SDL_SYSTEM_CURSOR_WAITARROW
3319+ SDL_SYSTEM_CURSOR_PROGRESS
3320@@
3321@@
3322- SDL_SYSTEM_CURSOR_SIZENWSE
3323+ SDL_SYSTEM_CURSOR_NWSE_RESIZE
3324@@
3325@@
3326- SDL_SYSTEM_CURSOR_SIZENESW
3327+ SDL_SYSTEM_CURSOR_NESW_RESIZE
3328@@
3329@@
3330- SDL_SYSTEM_CURSOR_SIZEWE
3331+ SDL_SYSTEM_CURSOR_EW_RESIZE
3332@@
3333@@
3334- SDL_SYSTEM_CURSOR_SIZENS
3335+ SDL_SYSTEM_CURSOR_NS_RESIZE
3336@@
3337@@
3338- SDL_SYSTEM_CURSOR_SIZEALL
3339+ SDL_SYSTEM_CURSOR_MOVE
3340@@
3341@@
3342- SDL_SYSTEM_CURSOR_NO
3343+ SDL_SYSTEM_CURSOR_NOT_ALLOWED
3344@@
3345@@
3346- SDL_SYSTEM_CURSOR_HAND
3347+ SDL_SYSTEM_CURSOR_POINTER
3348@@
3349@@
3350- SDL_SYSTEM_CURSOR_WINDOW_TOPLEFT
3351+ SDL_SYSTEM_CURSOR_NW_RESIZE
3352@@
3353@@
3354- SDL_SYSTEM_CURSOR_WINDOW_TOP
3355+ SDL_SYSTEM_CURSOR_N_RESIZE
3356@@
3357@@
3358- SDL_SYSTEM_CURSOR_WINDOW_TOPRIGHT
3359+ SDL_SYSTEM_CURSOR_NE_RESIZE
3360@@
3361@@
3362- SDL_SYSTEM_CURSOR_WINDOW_RIGHT
3363+ SDL_SYSTEM_CURSOR_E_RESIZE
3364@@
3365@@
3366- SDL_SYSTEM_CURSOR_WINDOW_BOTTOMRIGHT
3367+ SDL_SYSTEM_CURSOR_SE_RESIZE
3368@@
3369@@
3370- SDL_SYSTEM_CURSOR_WINDOW_BOTTOM
3371+ SDL_SYSTEM_CURSOR_S_RESIZE
3372@@
3373@@
3374- SDL_SYSTEM_CURSOR_WINDOW_BOTTOMLEFT
3375+ SDL_SYSTEM_CURSOR_SW_RESIZE
3376@@
3377@@
3378- SDL_SYSTEM_CURSOR_WINDOW_LEFT
3379+ SDL_SYSTEM_CURSOR_W_RESIZE
3380@@
3381@@
3382- SDL_SwapLE16
3383+ SDL_Swap16LE
3384 (...)
3385@@
3386@@
3387- SDL_SwapLE32
3388+ SDL_Swap32LE
3389 (...)
3390@@
3391@@
3392- SDL_SwapBE16
3393+ SDL_Swap16BE
3394 (...)
3395@@
3396@@
3397- SDL_SwapBE32
3398+ SDL_Swap32BE
3399 (...)
3400@@
3401@@
3402- SDL_SwapLE64
3403+ SDL_Swap64LE
3404 (...)
3405@@
3406@@
3407- SDL_SwapBE64
3408+ SDL_Swap64BE
3409 (...)
3410@@
3411@@
3412- SDL_SCANCODE_AUDIOMUTE
3413+ SDL_SCANCODE_MUTE
3414@@
3415@@
3416- SDLK_AUDIOMUTE
3417+ SDLK_MUTE
3418@@
3419@@
3420- SDL_SCANCODE_EJECT
3421+ SDL_SCANCODE_MEDIA_EJECT
3422@@
3423@@
3424- SDLK_EJECT
3425+ SDLK_MEDIA_EJECT
3426@@
3427@@
3428- SDL_SCANCODE_AUDIONEXT
3429+ SDL_SCANCODE_MEDIA_NEXT_TRACK
3430@@
3431@@
3432- SDLK_AUDIONEXT
3433+ SDLK_MEDIA_NEXT_TRACK
3434@@
3435@@
3436- SDL_SCANCODE_AUDIOPREV
3437+ SDL_SCANCODE_MEDIA_PREVIOUS_TRACK
3438@@
3439@@
3440- SDLK_AUDIOPREV
3441+ SDLK_MEDIA_PREVIOUS_TRACK
3442@@
3443@@
3444- SDL_SCANCODE_AUDIOSTOP
3445+ SDL_SCANCODE_MEDIA_STOP
3446@@
3447@@
3448- SDLK_AUDIOSTOP
3449+ SDLK_MEDIA_STOP
3450@@
3451@@
3452- SDL_SCANCODE_AUDIOPLAY
3453+ SDL_SCANCODE_MEDIA_PLAY
3454@@
3455@@
3456- SDLK_AUDIOPLAY
3457+ SDLK_MEDIA_PLAY
3458@@
3459@@
3460- SDL_SCANCODE_AUDIOREWIND
3461+ SDL_SCANCODE_MEDIA_REWIND
3462@@
3463@@
3464- SDLK_AUDIOREWIND
3465+ SDLK_MEDIA_REWIND
3466@@
3467@@
3468- SDL_SCANCODE_AUDIOFASTFORWARD
3469+ SDL_SCANCODE_MEDIA_FAST_FORWARD
3470@@
3471@@
3472- SDLK_AUDIOFASTFORWARD
3473+ SDLK_MEDIA_FAST_FORWARD
3474@@
3475@@
3476- SDL_SCANCODE_MEDIASELECT
3477+ SDL_SCANCODE_MEDIA_SELECT
3478@@
3479@@
3480- SDLK_MEDIASELECT
3481+ SDLK_MEDIA_SELECT
3482@@
3483@@
3484- SDLK_a
3485+ SDLK_A
3486@@
3487@@
3488- SDLK_b
3489+ SDLK_B
3490@@
3491@@
3492- SDLK_c
3493+ SDLK_C
3494@@
3495@@
3496- SDLK_d
3497+ SDLK_D
3498@@
3499@@
3500- SDLK_e
3501+ SDLK_E
3502@@
3503@@
3504- SDLK_f
3505+ SDLK_F
3506@@
3507@@
3508- SDLK_g
3509+ SDLK_G
3510@@
3511@@
3512- SDLK_h
3513+ SDLK_H
3514@@
3515@@
3516- SDLK_i
3517+ SDLK_I
3518@@
3519@@
3520- SDLK_j
3521+ SDLK_J
3522@@
3523@@
3524- SDLK_k
3525+ SDLK_K
3526@@
3527@@
3528- SDLK_l
3529+ SDLK_L
3530@@
3531@@
3532- SDLK_m
3533+ SDLK_M
3534@@
3535@@
3536- SDLK_n
3537+ SDLK_N
3538@@
3539@@
3540- SDLK_o
3541+ SDLK_O
3542@@
3543@@
3544- SDLK_p
3545+ SDLK_P
3546@@
3547@@
3548- SDLK_q
3549+ SDLK_Q
3550@@
3551@@
3552- SDLK_r
3553+ SDLK_R
3554@@
3555@@
3556- SDLK_s
3557+ SDLK_S
3558@@
3559@@
3560- SDLK_t
3561+ SDLK_T
3562@@
3563@@
3564- SDLK_u
3565+ SDLK_U
3566@@
3567@@
3568- SDLK_v
3569+ SDLK_V
3570@@
3571@@
3572- SDLK_w
3573+ SDLK_W
3574@@
3575@@
3576- SDLK_x
3577+ SDLK_X
3578@@
3579@@
3580- SDLK_y
3581+ SDLK_Y
3582@@
3583@@
3584- SDLK_z
3585+ SDLK_Z
3586@@
3587@@
3588- SDL_ConvertSurfaceFormat
3589+ SDL_ConvertSurface
3590 (...)
3591@@
3592@@
3593- SDL_PREALLOC
3594+ SDL_SURFACE_PREALLOCATED
3595@@
3596@@
3597- SDL_SIMD_ALIGNED
3598+ SDL_SURFACE_SIMD_ALIGNED
3599@@
3600@@
3601- SDL_GL_DeleteContext
3602+ SDL_GL_DestroyContext
3603 (...)
3604@@
3605@@
3606- SDL_AndroidGetActivity
3607+ SDL_GetAndroidActivity
3608 (...)
3609@@
3610@@
3611- SDL_AndroidGetExternalStoragePath
3612+ SDL_GetAndroidExternalStoragePath
3613 (...)
3614@@
3615@@
3616- SDL_AndroidGetExternalStorageState
3617+ SDL_GetAndroidExternalStorageState
3618 (...)
3619@@
3620@@
3621- SDL_AndroidGetInternalStoragePath
3622+ SDL_GetAndroidInternalStoragePath
3623 (...)
3624@@
3625@@
3626- SDL_AndroidGetJNIEnv
3627+ SDL_GetAndroidJNIEnv
3628 (...)
3629@@
3630@@
3631- SDL_Direct3D9GetAdapterIndex
3632+ SDL_GetDirect3D9AdapterIndex
3633 (...)
3634@@
3635@@
3636- SDL_GDKGetDefaultUser
3637+ SDL_GetGDKDefaultUser
3638 (...)
3639@@
3640@@
3641- SDL_GDKGetTaskQueue
3642+ SDL_GetGDKTaskQueue
3643 (...)
3644@@
3645@@
3646- SDL_LinuxSetThreadPriority
3647+ SDL_SetLinuxThreadPriority
3648 (...)
3649@@
3650@@
3651- SDL_LinuxSetThreadPriorityAndPolicy
3652+ SDL_SetLinuxThreadPriorityAndPolicy
3653 (...)
3654@@
3655@@
3656- SDL_DXGIGetOutputInfo
3657+ SDL_GetDXGIOutputInfo
3658 (...)
3659@@
3660@@
3661- SDL_AndroidBackButton
3662+ SDL_TriggerAndroidBackButton
3663 (...)
3664@@
3665@@
3666- SDL_AndroidRequestPermission
3667+ SDL_RequestAndroidPermission
3668 (...)
3669@@
3670@@
3671- SDL_AndroidRequestPermissionCallback
3672+ SDL_RequestAndroidPermissionCallback
3673 (...)
3674@@
3675@@
3676- SDL_AndroidShowToast
3677+ SDL_ShowAndroidToast
3678 (...)
3679@@
3680@@
3681- SDL_AndroidSendMessage
3682+ SDL_SendAndroidMessage
3683 (...)
3684@@
3685typedef SDL_JoystickGUID, SDL_GUID;
3686@@
3687- SDL_JoystickGUID
3688+ SDL_GUID
3689@@
3690@@
3691- SDL_GUIDFromString
3692+ SDL_StringToGUID
3693 (...)
3694@@
3695@@
3696- SDL_OnApplicationWillResignActive
3697+ SDL_OnApplicationWillEnterBackground
3698 (...)
3699@@
3700@@
3701- SDL_OnApplicationDidBecomeActive
3702+ SDL_OnApplicationDidEnterForeground
3703 (...)
3704@@
3705@@
3706- SDL_HINT_VIDEO_WAYLAND_EMULATE_MOUSE_WARP
3707+ SDL_HINT_MOUSE_EMULATE_WARP_WITH_RELATIVE
3708@@
3709@@
3710- SDL_DelEventWatch
3711+ SDL_RemoveEventWatch
3712 (...)
3713@@
3714@@
3715- SDL_DelHintCallback
3716+ SDL_RemoveHintCallback
3717 (...)
3718@@
3719@@
3720- SDL_size_mul_overflow
3721+ SDL_size_mul_check_overflow
3722 (...)
3723@@
3724@@
3725- SDL_size_add_overflow
3726+ SDL_size_add_check_overflow
3727 (...)
3728@@
3729@@
3730- SDL_PRESSED
3731+ true
3732@@
3733@@
3734- SDL_RELEASED
3735+ false
3736
3737// This should be the last rule in the file, since it works on SDL3 functions and previous rules may have renamed old functions.
3738@ bool_return_type @
3739identifier func =~ "^(SDL_AddEventWatch|SDL_AddHintCallback|SDL_AddSurfaceAlternateImage|SDL_AddVulkanRenderSemaphores|SDL_BindAudioStream|SDL_BindAudioStreams|SDL_BlitSurface|SDL_BlitSurface9Grid|SDL_BlitSurfaceScaled|SDL_BlitSurfaceTiled|SDL_BlitSurfaceTiledWithScale|SDL_BlitSurfaceUnchecked|SDL_BlitSurfaceUncheckedScaled|SDL_CaptureMouse|SDL_ClearAudioStream|SDL_ClearClipboardData|SDL_ClearComposition|SDL_ClearError|SDL_ClearProperty|SDL_ClearSurface|SDL_CloseIO|SDL_CloseStorage|SDL_ConvertAudioSamples|SDL_ConvertEventToRenderCoordinates|SDL_ConvertPixels|SDL_ConvertPixelsAndColorspace|SDL_CopyFile|SDL_CopyProperties|SDL_CopyStorageFile|SDL_CreateDirectory|SDL_CreateStorageDirectory|SDL_CreateWindowAndRenderer|SDL_DateTimeToTime|SDL_DestroyWindowSurface|SDL_DetachVirtualJoystick|SDL_DisableScreenSaver|SDL_EnableScreenSaver|SDL_EnumerateDirectory|SDL_EnumerateProperties|SDL_EnumerateStorageDirectory|SDL_FillSurfaceRect|SDL_FillSurfaceRects|SDL_FlashWindow|SDL_FlipSurface|SDL_FlushAudioStream|SDL_FlushRenderer|SDL_GL_DestroyContext|SDL_GL_GetAttribute|SDL_GL_GetSwapInterval|SDL_GL_LoadLibrary|SDL_GL_MakeCurrent|SDL_GL_SetAttribute|SDL_GL_SetSwapInterval|SDL_GL_SwapWindow|SDL_GetAudioDeviceFormat|SDL_GetAudioStreamFormat|SDL_GetCameraFormat|SDL_GetClosestFullscreenDisplayMode|SDL_GetCurrentRenderOutputSize|SDL_GetCurrentTime|SDL_GetDXGIOutputInfo|SDL_GetDateTimeLocalePreferences|SDL_GetDisplayBounds|SDL_GetDisplayUsableBounds|SDL_GetGDKDefaultUser|SDL_GetGDKTaskQueue|SDL_GetGamepadSensorData|SDL_GetGamepadTouchpadFinger|SDL_GetHapticEffectStatus|SDL_GetJoystickBall|SDL_GetMasksForPixelFormat|SDL_GetPathInfo|SDL_GetRectUnion|SDL_GetRectUnionFloat|SDL_GetRenderClipRect|SDL_GetRenderColorScale|SDL_GetRenderDrawBlendMode|SDL_GetRenderDrawColor|SDL_GetRenderDrawColorFloat|SDL_GetRenderLogicalPresentation|SDL_GetRenderLogicalPresentationRect|SDL_GetRenderOutputSize|SDL_GetRenderSafeArea|SDL_GetRenderScale|SDL_GetRenderVSync|SDL_GetRenderViewport|SDL_GetSensorData|SDL_GetStorageFileSize|SDL_GetStoragePathInfo|SDL_GetSurfaceAlphaMod|SDL_GetSurfaceBlendMode|SDL_GetSurfaceClipRect|SDL_GetSurfaceColorKey|SDL_GetSurfaceColorMod|SDL_GetTextInputArea|SDL_GetTextureAlphaMod|SDL_GetTextureAlphaModFloat|SDL_GetTextureBlendMode|SDL_GetTextureColorMod|SDL_GetTextureColorModFloat|SDL_GetTextureScaleMode|SDL_GetTextureSize|SDL_GetWindowAspectRatio|SDL_GetWindowBordersSize|SDL_GetWindowMaximumSize|SDL_GetWindowMinimumSize|SDL_GetWindowPosition|SDL_GetWindowRelativeMouseMode|SDL_GetWindowSafeArea|SDL_GetWindowSize|SDL_GetWindowSizeInPixels|SDL_GetWindowSurfaceVSync|SDL_HideCursor|SDL_HideWindow|SDL_Init|SDL_InitHapticRumble|SDL_InitSubSystem|SDL_LoadWAV|SDL_LoadWAV_IO|SDL_LockAudioStream|SDL_LockProperties|SDL_LockSurface|SDL_LockTexture|SDL_LockTextureToSurface|SDL_MaximizeWindow|SDL_MinimizeWindow|SDL_MixAudio|SDL_OpenURL|SDL_OutOfMemory|SDL_PauseAudioDevice|SDL_PauseAudioStreamDevice|SDL_PauseHaptic|SDL_PlayHapticRumble|SDL_PremultiplyAlpha|SDL_PremultiplySurfaceAlpha|SDL_PushEvent|SDL_PutAudioStreamData|SDL_RaiseWindow|SDL_ReadStorageFile|SDL_ReadSurfacePixel|SDL_ReadSurfacePixelFloat|SDL_RegisterApp|SDL_ReloadGamepadMappings|SDL_RemovePath|SDL_RemoveStoragePath|SDL_RemoveTimer|SDL_RenamePath|SDL_RenameStoragePath|SDL_RenderClear|SDL_RenderCoordinatesFromWindow|SDL_RenderCoordinatesToWindow|SDL_RenderFillRect|SDL_RenderFillRects|SDL_RenderGeometry|SDL_RenderGeometryRaw|SDL_RenderLine|SDL_RenderLines|SDL_RenderPoint|SDL_RenderPoints|SDL_RenderPresent|SDL_RenderRect|SDL_RenderRects|SDL_RenderTexture|SDL_RenderTexture9Grid|SDL_RenderTextureRotated|SDL_RenderTextureTiled|SDL_RequestAndroidPermission|SDL_RestoreWindow|SDL_ResumeAudioDevice|SDL_ResumeAudioStreamDevice|SDL_ResumeHaptic|SDL_RumbleGamepad|SDL_RumbleGamepadTriggers|SDL_RumbleJoystick|SDL_RumbleJoystickTriggers|SDL_RunHapticEffect|SDL_SaveBMP|SDL_SaveBMP_IO|SDL_SendAndroidMessage|SDL_SendGamepadEffect|SDL_SendJoystickEffect|SDL_SendJoystickVirtualSensorData|SDL_SetAppMetadata|SDL_SetAppMetadataProperty|SDL_SetAudioDeviceGain|SDL_SetAudioPostmixCallback|SDL_SetAudioStreamFormat|SDL_SetAudioStreamFrequencyRatio|SDL_SetAudioStreamGain|SDL_SetAudioStreamGetCallback|SDL_SetAudioStreamInputChannelMap|SDL_SetAudioStreamOutputChannelMap|SDL_SetAudioStreamPutCallback|SDL_SetBooleanProperty|SDL_SetClipboardData|SDL_SetClipboardText|SDL_SetCursor|SDL_SetFloatProperty|SDL_SetGamepadLED|SDL_SetGamepadMapping|SDL_SetGamepadPlayerIndex|SDL_SetGamepadSensorEnabled|SDL_SetHapticAutocenter|SDL_SetHapticGain|SDL_SetJoystickLED|SDL_SetJoystickPlayerIndex|SDL_SetJoystickVirtualAxis|SDL_SetJoystickVirtualBall|SDL_SetJoystickVirtualButton|SDL_SetJoystickVirtualHat|SDL_SetJoystickVirtualTouchpad|SDL_SetLinuxThreadPriority|SDL_SetLinuxThreadPriorityAndPolicy|SDL_SetLogPriorityPrefix|SDL_SetMemoryFunctions|SDL_SetNumberProperty|SDL_SetPaletteColors|SDL_SetPointerProperty|SDL_SetPointerPropertyWithCleanup|SDL_SetPrimarySelectionText|SDL_SetRenderClipRect|SDL_SetRenderColorScale|SDL_SetRenderDrawBlendMode|SDL_SetRenderDrawColor|SDL_SetRenderDrawColorFloat|SDL_SetRenderLogicalPresentation|SDL_SetRenderScale|SDL_SetRenderTarget|SDL_SetRenderVSync|SDL_SetRenderViewport|SDL_SetScancodeName|SDL_SetStringProperty|SDL_SetSurfaceAlphaMod|SDL_SetSurfaceBlendMode|SDL_SetSurfaceColorKey|SDL_SetSurfaceColorMod|SDL_SetSurfaceColorspace|SDL_SetSurfacePalette|SDL_SetSurfaceRLE|SDL_SetTLS|SDL_SetTextInputArea|SDL_SetTextureAlphaMod|SDL_SetTextureAlphaModFloat|SDL_SetTextureBlendMode|SDL_SetTextureColorMod|SDL_SetTextureColorModFloat|SDL_SetTextureScaleMode|SDL_SetThreadPriority|SDL_SetWindowAlwaysOnTop|SDL_SetWindowAspectRatio|SDL_SetWindowBordered|SDL_SetWindowFocusable|SDL_SetWindowFullscreen|SDL_SetWindowFullscreenMode|SDL_SetWindowHitTest|SDL_SetWindowIcon|SDL_SetWindowKeyboardGrab|SDL_SetWindowMaximumSize|SDL_SetWindowMinimumSize|SDL_SetWindowModalFor|SDL_SetWindowMouseGrab|SDL_SetWindowMouseRect|SDL_SetWindowOpacity|SDL_SetWindowPosition|SDL_SetWindowRelativeMouseMode|SDL_SetWindowResizable|SDL_SetWindowShape|SDL_SetWindowSize|SDL_SetWindowSurfaceVSync|SDL_SetWindowTitle|SDL_SetiOSAnimationCallback|SDL_ShowAndroidToast|SDL_ShowCursor|SDL_ShowMessageBox|SDL_ShowSimpleMessageBox|SDL_ShowWindow|SDL_ShowWindowSystemMenu|SDL_StartTextInput|SDL_StartTextInputWithProperties|SDL_StopHapticEffect|SDL_StopHapticEffects|SDL_StopHapticRumble|SDL_StopTextInput|SDL_SyncWindow|SDL_TimeToDateTime|SDL_TryLockMutex|SDL_TryLockRWLockForReading|SDL_TryLockRWLockForWriting|SDL_TryWaitSemaphore|SDL_UnlockAudioStream|SDL_UpdateHapticEffect|SDL_UpdateNVTexture|SDL_UpdateTexture|SDL_UpdateWindowSurface|SDL_UpdateWindowSurfaceRects|SDL_UpdateYUVTexture|SDL_Vulkan_CreateSurface|SDL_Vulkan_LoadLibrary|SDL_WaitConditionTimeout|SDL_WaitSemaphoreTimeout|SDL_WarpMouseGlobal|SDL_WriteStorageFile|SDL_WriteSurfacePixel|SDL_WriteSurfacePixelFloat|SDL_size_mul_check_overflow|SDL_size_add_check_overflow|TTF_GlyphMetrics|TTF_GlyphMetrics32|TTF_Init|TTF_MeasureText|TTF_MeasureUNICODE|TTF_MeasureUTF8|TTF_SetFontDirection|TTF_SetFontLanguage|TTF_SetFontScriptName|TTF_SetFontSDF|TTF_SetFontSize|TTF_SetFontSizeDPI|TTF_SizeText|TTF_SizeUNICODE|TTF_SizeUTF8|IMG_SaveAVIF|IMG_SaveAVIF_IO|IMG_SaveJPG|IMG_SaveJPG_IO|IMG_SavePNG|IMG_SavePNG_IO|Mix_FadeInMusic|Mix_FadeInMusicPos|Mix_GroupChannels|Mix_ModMusicJumpToOrder|Mix_OpenAudio|Mix_PlayMusic|Mix_SetMusicCMD|Mix_SetMusicPosition|Mix_SetSoundFonts|Mix_StartTrack)$";
3740@@
3741(
3742 func(
3743 ...
3744 )
3745- == 0
3746|
3747- func(
3748+ !func(
3749 ...
3750 )
3751- < 0
3752|
3753- func(
3754+ !func(
3755 ...
3756 )
3757- != 0
3758|
3759- func(
3760+ !func(
3761 ...
3762 )
3763- == -1
3764)
3765@@
3766@@
3767- SDL_NUM_LOG_PRIORITIES
3768+ SDL_LOG_PRIORITY_COUNT
3769@@
3770@@
3771- SDL_MESSAGEBOX_COLOR_MAX
3772+ SDL_MESSAGEBOX_COLOR_COUNT
3773@@
3774@@
3775- SDL_NUM_SYSTEM_CURSORS
3776+ SDL_SYSTEM_CURSOR_COUNT
3777@@
3778@@
3779- SDL_NUM_SCANCODES
3780+ SDL_SCANCODE_COUNT
3781@@
3782@@
3783- SDL_GetCPUCount
3784+ SDL_GetNumLogicalCPUCores
3785 (...)
3786@@
3787typedef SDL_bool, bool;
3788@@
3789- SDL_bool
3790+ bool
3791@@
3792@@
3793- SDL_TRUE
3794+ true
3795@@
3796@@
3797- SDL_FALSE
3798+ false
3799@@
3800@@
3801- SDL_IsAndroidTV
3802+ SDL_IsTV
3803 (...)
3804@@
3805@@
3806- SDL_SetThreadPriority
3807+ SDL_SetCurrentThreadPriority
3808 (...)
3809@@
3810@@
3811- SDL_BUTTON
3812+ SDL_BUTTON_MASK
3813@@
3814@@
3815- SDL_GLprofile
3816+ SDL_GLProfile
3817@@
3818@@
3819- SDL_GLcontextFlag
3820+ SDL_GLContextFlag
3821@@
3822@@
3823- SDL_GLcontextReleaseFlag
3824+ SDL_GLContextReleaseFlag
3825@@
3826@@
3827- SDL_GLattr
3828+ SDL_GLAttr
3829@@
3830@@
3831- SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE
3832+ SDL_HINT_JOYSTICK_ENHANCED_REPORTS
3833@@
3834@@
3835- SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE
3836+ SDL_HINT_JOYSTICK_ENHANCED_REPORTS
diff --git a/src/contrib/SDL-3.2.20/build-scripts/add-source-to-projects.pl b/src/contrib/SDL-3.2.20/build-scripts/add-source-to-projects.pl
new file mode 100755
index 0000000..5ba0a69
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/add-source-to-projects.pl
@@ -0,0 +1,599 @@
1#!/usr/bin/perl -w
2
3# Add source files and headers to Xcode and Visual Studio projects.
4# THIS IS NOT ROBUST, THIS IS JUST RYAN AVOIDING RUNNING BETWEEN
5# THREE COMPUTERS AND A BUNCH OF DEVELOPMENT ENVIRONMENTS TO ADD
6# A STUPID FILE TO THE BUILD.
7
8
9use warnings;
10use strict;
11use File::Basename;
12
13
14my %xcode_references = ();
15sub generate_xcode_id {
16 my @chars = ('0'..'9', 'A'..'F');
17 my $str;
18
19 do {
20 my $len = 16;
21 $str = '0000'; # start and end with '0000' so we know we added it.
22 while ($len--) {
23 $str .= $chars[rand @chars]
24 };
25 $str .= '0000'; # start and end with '0000' so we know we added it.
26 } while (defined($xcode_references{$str}));
27
28 $xcode_references{$str} = 1; # so future calls can't generate this one.
29
30 return $str;
31}
32
33sub process_xcode {
34 my $addpath = shift;
35 my $pbxprojfname = shift;
36 my $lineno;
37
38 %xcode_references = ();
39
40 my $addfname = basename($addpath);
41 my $addext = '';
42 if ($addfname =~ /\.(.*?)\Z/) {
43 $addext = $1;
44 }
45
46 my $is_public_header = ($addpath =~ /\Ainclude\/SDL3\//) ? 1 : 0;
47 my $filerefpath = $is_public_header ? "SDL3/$addfname" : $addfname;
48
49 my $srcs_or_headers = '';
50 my $addfiletype = '';
51
52 if ($addext eq 'c') {
53 $srcs_or_headers = 'Sources';
54 $addfiletype = 'sourcecode.c.c';
55 } elsif ($addext eq 'm') {
56 $srcs_or_headers = 'Sources';
57 $addfiletype = 'sourcecode.c.objc';
58 } elsif ($addext eq 'h') {
59 $srcs_or_headers = 'Headers';
60 $addfiletype = 'sourcecode.c.h';
61 } else {
62 die("Unexpected file extension '$addext'\n");
63 }
64
65 my $fh;
66
67 open $fh, '<', $pbxprojfname or die("Failed to open '$pbxprojfname': $!\n");
68 chomp(my @pbxproj = <$fh>);
69 close($fh);
70
71 # build a table of all ids, in case we duplicate one by some miracle.
72 $lineno = 0;
73 foreach (@pbxproj) {
74 $lineno++;
75
76 # like "F3676F582A7885080091160D /* SDL3.dmg */ = {"
77 if (/\A\t\t([A-F0-9]{24}) \/\* (.*?) \*\/ \= \{\Z/) {
78 $xcode_references{$1} = $2;
79 }
80 }
81
82 # build out of a tree of PBXGroup items.
83 my %pbxgroups = ();
84 my $thispbxgroup;
85 my $pbxgroup_children;
86 my $pbxgroup_state = 0;
87 my $pubheaders_group_hash = '';
88 my $libsrc_group_hash = '';
89 $lineno = 0;
90 foreach (@pbxproj) {
91 $lineno++;
92 if ($pbxgroup_state == 0) {
93 $pbxgroup_state++ if /\A\/\* Begin PBXGroup section \*\/\Z/;
94 } elsif ($pbxgroup_state == 1) {
95 # like "F3676F582A7885080091160D /* SDL3.dmg */ = {"
96 if (/\A\t\t([A-F0-9]{24}) \/\* (.*?) \*\/ \= \{\Z/) {
97 my %newhash = ();
98 $pbxgroups{$1} = \%newhash;
99 $thispbxgroup = \%newhash;
100 $pubheaders_group_hash = $1 if $2 eq 'Public Headers';
101 $libsrc_group_hash = $1 if $2 eq 'Library Source';
102 $pbxgroup_state++;
103 } elsif (/\A\/\* End PBXGroup section \*\/\Z/) {
104 last;
105 } else {
106 die("Expected pbxgroup obj on '$pbxprojfname' line $lineno\n");
107 }
108 } elsif ($pbxgroup_state == 2) {
109 if (/\A\t\t\tisa \= PBXGroup;\Z/) {
110 $pbxgroup_state++;
111 } else {
112 die("Expected pbxgroup obj's isa field on '$pbxprojfname' line $lineno\n");
113 }
114 } elsif ($pbxgroup_state == 3) {
115 if (/\A\t\t\tchildren \= \(\Z/) {
116 my %newhash = ();
117 $$thispbxgroup{'children'} = \%newhash;
118 $pbxgroup_children = \%newhash;
119 $pbxgroup_state++;
120 } else {
121 die("Expected pbxgroup obj's children field on '$pbxprojfname' line $lineno\n");
122 }
123 } elsif ($pbxgroup_state == 4) {
124 if (/\A\t\t\t\t([A-F0-9]{24}) \/\* (.*?) \*\/,\Z/) {
125 $$pbxgroup_children{$1} = $2;
126 } elsif (/\A\t\t\t\);\Z/) {
127 $pbxgroup_state++;
128 } else {
129 die("Expected pbxgroup obj's children element on '$pbxprojfname' line $lineno\n");
130 }
131 } elsif ($pbxgroup_state == 5) {
132 if (/\A\t\t\t(.*?) \= (.*?);\Z/) {
133 $$thispbxgroup{$1} = $2;
134 } elsif (/\A\t\t\};\Z/) {
135 $pbxgroup_state = 1;
136 } else {
137 die("Expected pbxgroup obj field on '$pbxprojfname' line $lineno\n");
138 }
139 } else {
140 die("bug in this script.");
141 }
142 }
143
144 die("Didn't see PBXGroup section in '$pbxprojfname'. Bug?\n") if $pbxgroup_state == 0;
145 die("Didn't see Public Headers PBXGroup in '$pbxprojfname'. Bug?\n") if $pubheaders_group_hash eq '';
146 die("Didn't see Library Source PBXGroup in '$pbxprojfname'. Bug?\n") if $libsrc_group_hash eq '';
147
148 # Some debug log dumping...
149 if (0) {
150 foreach (keys %pbxgroups) {
151 my $k = $_;
152 my $g = $pbxgroups{$k};
153 print("$_:\n");
154 foreach (keys %$g) {
155 print(" $_:\n");
156 if ($_ eq 'children') {
157 my $kids = $$g{$_};
158 foreach (keys %$kids) {
159 print(" $_ -> " . $$kids{$_} . "\n");
160 }
161 } else {
162 print(' ' . $$g{$_} . "\n");
163 }
164 }
165 print("\n");
166 }
167 }
168
169 # Get some unique IDs for our new thing.
170 my $fileref = generate_xcode_id();
171 my $buildfileref = generate_xcode_id();
172
173
174 # Figure out what group to insert this into (or what groups to make)
175 my $add_to_group_fileref = $fileref;
176 my $add_to_group_addfname = $addfname;
177 my $newgrptext = '';
178 my $grphash = '';
179 if ($is_public_header) {
180 $grphash = $pubheaders_group_hash; # done!
181 } else {
182 $grphash = $libsrc_group_hash;
183 my @splitpath = split(/\//, dirname($addpath));
184 if ($splitpath[0] eq 'src') {
185 shift @splitpath;
186 }
187 while (my $elem = shift(@splitpath)) {
188 my $g = $pbxgroups{$grphash};
189 my $kids = $$g{'children'};
190 my $found = 0;
191 foreach (keys %$kids) {
192 my $hash = $_;
193 my $fname = $$kids{$hash};
194 if (uc($fname) eq uc($elem)) {
195 $grphash = $hash;
196 $found = 1;
197 last;
198 }
199 }
200 unshift(@splitpath, $elem), last if (not $found);
201 }
202
203 if (@splitpath) { # still elements? We need to build groups.
204 my $newgroupref = generate_xcode_id();
205
206 $add_to_group_fileref = $newgroupref;
207 $add_to_group_addfname = $splitpath[0];
208
209 while (my $elem = shift(@splitpath)) {
210 my $lastelem = @splitpath ? 0 : 1;
211 my $childhash = $lastelem ? $fileref : generate_xcode_id();
212 my $childpath = $lastelem ? $addfname : $splitpath[0];
213 $newgrptext .= "\t\t$newgroupref /* $elem */ = {\n";
214 $newgrptext .= "\t\t\tisa = PBXGroup;\n";
215 $newgrptext .= "\t\t\tchildren = (\n";
216 $newgrptext .= "\t\t\t\t$childhash /* $childpath */,\n";
217 $newgrptext .= "\t\t\t);\n";
218 $newgrptext .= "\t\t\tpath = $elem;\n";
219 $newgrptext .= "\t\t\tsourceTree = \"<group>\";\n";
220 $newgrptext .= "\t\t};\n";
221 $newgroupref = $childhash;
222 }
223 }
224 }
225
226 my $tmpfname = "$pbxprojfname.tmp";
227 open $fh, '>', $tmpfname or die("Failed to open '$tmpfname': $!\n");
228
229 my $add_to_this_group = 0;
230 $pbxgroup_state = 0;
231 $lineno = 0;
232 foreach (@pbxproj) {
233 $lineno++;
234 if ($pbxgroup_state == 0) {
235 # Drop in new references at the end of their sections...
236 if (/\A\/\* End PBXBuildFile section \*\/\Z/) {
237 print $fh "\t\t$buildfileref /* $addfname in $srcs_or_headers */ = {isa = PBXBuildFile; fileRef = $fileref /* $addfname */;";
238 if ($is_public_header) {
239 print $fh " settings = {ATTRIBUTES = (Public, ); };";
240 }
241 print $fh " };\n";
242 } elsif (/\A\/\* End PBXFileReference section \*\/\Z/) {
243 print $fh "\t\t$fileref /* $addfname */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = $addfiletype; name = $addfname; path = $filerefpath; sourceTree = \"<group>\"; };\n";
244 } elsif (/\A\/\* Begin PBXGroup section \*\/\Z/) {
245 $pbxgroup_state = 1;
246 } elsif (/\A\/\* Begin PBXSourcesBuildPhase section \*\/\Z/) {
247 $pbxgroup_state = 5;
248 }
249 } elsif ($pbxgroup_state == 1) {
250 if (/\A\t\t([A-F0-9]{24}) \/\* (.*?) \*\/ \= \{\Z/) {
251 $pbxgroup_state++;
252 $add_to_this_group = $1 eq $grphash;
253 } elsif (/\A\/\* End PBXGroup section \*\/\Z/) {
254 print $fh $newgrptext;
255 $pbxgroup_state = 0;
256 }
257 } elsif ($pbxgroup_state == 2) {
258 if (/\A\t\t\tchildren \= \(\Z/) {
259 $pbxgroup_state++;
260 }
261 } elsif ($pbxgroup_state == 3) {
262 if (/\A\t\t\t\);\Z/) {
263 if ($add_to_this_group) {
264 print $fh "\t\t\t\t$add_to_group_fileref /* $add_to_group_addfname */,\n";
265 }
266 $pbxgroup_state++;
267 }
268 } elsif ($pbxgroup_state == 4) {
269 if (/\A\t\t\};\Z/) {
270 $add_to_this_group = 0;
271 }
272 $pbxgroup_state = 1;
273 } elsif ($pbxgroup_state == 5) {
274 if (/\A\t\t\t\);\Z/) {
275 if ($srcs_or_headers eq 'Sources') {
276 print $fh "\t\t\t\t$buildfileref /* $addfname in $srcs_or_headers */,\n";
277 }
278 $pbxgroup_state = 0;
279 }
280 }
281
282 print $fh "$_\n";
283 }
284
285 close($fh);
286 rename($tmpfname, $pbxprojfname);
287}
288
289my %visualc_references = ();
290sub generate_visualc_id { # these are just standard Windows GUIDs.
291 my @chars = ('0'..'9', 'a'..'f');
292 my $str;
293
294 do {
295 my $len = 24;
296 $str = '0000'; # start and end with '0000' so we know we added it.
297 while ($len--) {
298 $str .= $chars[rand @chars]
299 };
300 $str .= '0000'; # start and end with '0000' so we know we added it.
301 $str =~ s/\A(........)(....)(....)(............)\Z/$1-$2-$3-$4/; # add dashes in the appropriate places.
302 } while (defined($visualc_references{$str}));
303
304 $visualc_references{$str} = 1; # so future calls can't generate this one.
305
306 return $str;
307}
308
309
310sub process_visualstudio {
311 my $addpath = shift;
312 my $vcxprojfname = shift;
313 my $lineno;
314
315 %visualc_references = ();
316
317 my $is_public_header = ($addpath =~ /\Ainclude\/SDL3\//) ? 1 : 0;
318
319 my $addfname = basename($addpath);
320 my $addext = '';
321 if ($addfname =~ /\.(.*?)\Z/) {
322 $addext = $1;
323 }
324
325 my $isheader = 0;
326 if ($addext eq 'c') {
327 $isheader = 0;
328 } elsif ($addext eq 'm') {
329 return; # don't add Objective-C files to Visual Studio projects!
330 } elsif ($addext eq 'h') {
331 $isheader = 1;
332 } else {
333 die("Unexpected file extension '$addext'\n");
334 }
335
336 my $fh;
337
338 open $fh, '<', $vcxprojfname or die("Failed to open '$vcxprojfname': $!\n");
339 chomp(my @vcxproj = <$fh>);
340 close($fh);
341
342 my $vcxgroup_state;
343
344 my $rawaddvcxpath = "$addpath";
345 $rawaddvcxpath =~ s/\//\\/g;
346
347 # Figure out relative path from vcxproj file...
348 my $addvcxpath = '';
349 my @subdirs = split(/\//, $vcxprojfname);
350 pop @subdirs;
351 foreach (@subdirs) {
352 $addvcxpath .= "..\\";
353 }
354 $addvcxpath .= $rawaddvcxpath;
355
356 my $prevname = undef;
357
358 my $tmpfname;
359
360 $tmpfname = "$vcxprojfname.tmp";
361 open $fh, '>', $tmpfname or die("Failed to open '$tmpfname': $!\n");
362
363 my $added = 0;
364
365 $added = 0;
366 $vcxgroup_state = 0;
367 $prevname = undef;
368 $lineno = 0;
369 foreach (@vcxproj) {
370 $lineno++;
371 if ($vcxgroup_state == 0) {
372 if (/\A \<ItemGroup\>\Z/) {
373 $vcxgroup_state = 1;
374 $prevname = undef;
375 }
376 } elsif ($vcxgroup_state == 1) {
377 if (/\A \<ClInclude .*\Z/) {
378 $vcxgroup_state = 2 if $isheader;
379 } elsif (/\A \<ClCompile .*\Z/) {
380 $vcxgroup_state = 3 if not $isheader;
381 } elsif (/\A \<\/ItemGroup\>\Z/) {
382 $vcxgroup_state = 0;
383 $prevname = undef;
384 }
385 }
386
387 # Don't do elsif, we need to check this line again.
388 if ($vcxgroup_state == 2) {
389 if (/\A <ClInclude Include="(.*?)" \/\>\Z/) {
390 my $nextname = $1;
391 if ((not $added) && (((not defined $prevname) || (uc($prevname) lt uc($addvcxpath))) && (uc($nextname) gt uc($addvcxpath)))) {
392 print $fh " <ClInclude Include=\"$addvcxpath\" />\n";
393 $vcxgroup_state = 0;
394 $added = 1;
395 }
396 $prevname = $nextname;
397 } elsif (/\A \<\/ItemGroup\>\Z/) {
398 if ((not $added) && ((not defined $prevname) || (uc($prevname) lt uc($addvcxpath)))) {
399 print $fh " <ClInclude Include=\"$addvcxpath\" />\n";
400 $vcxgroup_state = 0;
401 $added = 1;
402 }
403 }
404 } elsif ($vcxgroup_state == 3) {
405 if (/\A <ClCompile Include="(.*?)" \/\>\Z/) {
406 my $nextname = $1;
407 if ((not $added) && (((not defined $prevname) || (uc($prevname) lt uc($addvcxpath))) && (uc($nextname) gt uc($addvcxpath)))) {
408 print $fh " <ClCompile Include=\"$addvcxpath\" />\n";
409 $vcxgroup_state = 0;
410 $added = 1;
411 }
412 $prevname = $nextname;
413 } elsif (/\A \<\/ItemGroup\>\Z/) {
414 if ((not $added) && ((not defined $prevname) || (uc($prevname) lt uc($addvcxpath)))) {
415 print $fh " <ClCompile Include=\"$addvcxpath\" />\n";
416 $vcxgroup_state = 0;
417 $added = 1;
418 }
419 }
420 }
421
422 print $fh "$_\n";
423 }
424
425 close($fh);
426 rename($tmpfname, $vcxprojfname);
427
428 my $vcxfiltersfname = "$vcxprojfname.filters";
429 open $fh, '<', $vcxfiltersfname or die("Failed to open '$vcxfiltersfname': $!\n");
430 chomp(my @vcxfilters = <$fh>);
431 close($fh);
432
433 my $newgrptext = '';
434 my $filter = '';
435 if ($is_public_header) {
436 $filter = 'API Headers';
437 } else {
438 $filter = lc(dirname($addpath));
439 $filter =~ s/\Asrc\///; # there's no filter for the base "src/" dir, where SDL.c and friends live.
440 $filter =~ s/\//\\/g;
441 $filter = '' if $filter eq 'src';
442
443 if ($filter ne '') {
444 # see if the filter already exists, otherwise add it.
445 my %existing_filters = ();
446 my $current_filter = '';
447 my $found = 0;
448 foreach (@vcxfilters) {
449 # These lines happen to be unique, so we don't have to parse down to find this section.
450 if (/\A \<Filter Include\="(.*?)"\>\Z/) {
451 $current_filter = lc($1);
452 if ($current_filter eq $filter) {
453 $found = 1;
454 }
455 } elsif (/\A \<UniqueIdentifier\>\{(.*?)\}\<\/UniqueIdentifier\>\Z/) {
456 $visualc_references{$1} = $current_filter; # gather up existing GUIDs to avoid duplicates.
457 $existing_filters{$current_filter} = $1;
458 }
459 }
460
461 if (not $found) { # didn't find it? We need to build filters.
462 my $subpath = '';
463 my @splitpath = split(/\\/, $filter);
464 while (my $elem = shift(@splitpath)) {
465 $subpath .= "\\" if ($subpath ne '');
466 $subpath .= $elem;
467 if (not $existing_filters{$subpath}) {
468 my $newgroupref = generate_visualc_id();
469 $newgrptext .= " <Filter Include=\"$subpath\">\n";
470 $newgrptext .= " <UniqueIdentifier>{$newgroupref}</UniqueIdentifier>\n";
471 $newgrptext .= " </Filter>\n"
472 }
473 }
474 }
475 }
476 }
477
478 $tmpfname = "$vcxfiltersfname.tmp";
479 open $fh, '>', $tmpfname or die("Failed to open '$tmpfname': $!\n");
480
481 $added = 0;
482 $vcxgroup_state = 0;
483 $prevname = undef;
484 $lineno = 0;
485 foreach (@vcxfilters) {
486 $lineno++;
487
488 # We cheat here, because these lines are unique, we don't have to fully parse this file.
489 if ($vcxgroup_state == 0) {
490 if (/\A \<Filter Include\="(.*?)"\>\Z/) {
491 if ($newgrptext ne '') {
492 $vcxgroup_state = 1;
493 $prevname = undef;
494 }
495 } elsif (/\A \<ClInclude .*\Z/) {
496 if ($isheader) {
497 $vcxgroup_state = 2;
498 $prevname = undef;
499 }
500 } elsif (/\A \<ClCompile .*\Z/) {
501 if (not $isheader) {
502 $vcxgroup_state = 3;
503 $prevname = undef;
504 }
505 }
506 }
507
508 # Don't do elsif, we need to check this line again.
509 if ($vcxgroup_state == 1) {
510 if (/\A \<\/ItemGroup\>\Z/) {
511 print $fh $newgrptext;
512 $newgrptext = '';
513 $vcxgroup_state = 0;
514 }
515 } elsif ($vcxgroup_state == 2) {
516 if (/\A <ClInclude Include="(.*?)"/) {
517 my $nextname = $1;
518 if ((not $added) && (((not defined $prevname) || (uc($prevname) lt uc($addvcxpath))) && (uc($nextname) gt uc($addvcxpath)))) {
519 print $fh " <ClInclude Include=\"$addvcxpath\"";
520 if ($filter ne '') {
521 print $fh ">\n";
522 print $fh " <Filter>$filter</Filter>\n";
523 print $fh " </ClInclude>\n";
524 } else {
525 print $fh " />\n";
526 }
527 $added = 1;
528 }
529 $prevname = $nextname;
530 } elsif (/\A \<\/ItemGroup\>\Z/) {
531 if ((not $added) && ((not defined $prevname) || (uc($prevname) lt uc($addvcxpath)))) {
532 print $fh " <ClInclude Include=\"$addvcxpath\"";
533 if ($filter ne '') {
534 print $fh ">\n";
535 print $fh " <Filter>$filter</Filter>\n";
536 print $fh " </ClInclude>\n";
537 } else {
538 print $fh " />\n";
539 }
540 $added = 1;
541 }
542 $vcxgroup_state = 0;
543 }
544 } elsif ($vcxgroup_state == 3) {
545 if (/\A <ClCompile Include="(.*?)"/) {
546 my $nextname = $1;
547 if ((not $added) && (((not defined $prevname) || (uc($prevname) lt uc($addvcxpath))) && (uc($nextname) gt uc($addvcxpath)))) {
548 print $fh " <ClCompile Include=\"$addvcxpath\"";
549 if ($filter ne '') {
550 print $fh ">\n";
551 print $fh " <Filter>$filter</Filter>\n";
552 print $fh " </ClCompile>\n";
553 } else {
554 print $fh " />\n";
555 }
556 $added = 1;
557 }
558 $prevname = $nextname;
559 } elsif (/\A \<\/ItemGroup\>\Z/) {
560 if ((not $added) && ((not defined $prevname) || (uc($prevname) lt uc($addvcxpath)))) {
561 print $fh " <ClCompile Include=\"$addvcxpath\"";
562 if ($filter ne '') {
563 print $fh ">\n";
564 print $fh " <Filter>$filter</Filter>\n";
565 print $fh " </ClCompile>\n";
566 } else {
567 print $fh " />\n";
568 }
569 $added = 1;
570 }
571 $vcxgroup_state = 0;
572 }
573 }
574
575 print $fh "$_\n";
576 }
577
578 close($fh);
579 rename($tmpfname, $vcxfiltersfname);
580}
581
582
583# Mainline!
584
585chdir(dirname($0)); # assumed to be in build-scripts
586chdir('..'); # head to root of source tree.
587
588foreach (@ARGV) {
589 s/\A\.\///; # Turn "./path/to/file.txt" into "path/to/file.txt"
590 my $arg = $_;
591 process_xcode($arg, 'Xcode/SDL/SDL.xcodeproj/project.pbxproj');
592 process_visualstudio($arg, 'VisualC/SDL/SDL.vcxproj');
593 process_visualstudio($arg, 'VisualC-GDK/SDL/SDL.vcxproj');
594}
595
596print("Done. Please run `git diff` and make sure this looks okay!\n");
597
598exit(0);
599
diff --git a/src/contrib/SDL-3.2.20/build-scripts/androidbuildlibs.sh b/src/contrib/SDL-3.2.20/build-scripts/androidbuildlibs.sh
new file mode 100755
index 0000000..1004a98
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/androidbuildlibs.sh
@@ -0,0 +1,85 @@
1#!/bin/bash
2#
3# Build the Android libraries without needing a project
4# (AndroidManifest.xml, jni/{Application,Android}.mk, etc.)
5#
6# Usage: androidbuildlibs.sh [arg for ndk-build ...]"
7#
8# Useful NDK arguments:
9#
10# NDK_DEBUG=1 - build debug version
11# NDK_LIBS_OUT=<dest> - specify alternate destination for installable
12# modules.
13#
14
15
16# Android.mk is in srcdir
17srcdir=`dirname $0`/..
18srcdir=`cd $srcdir && pwd`
19cd $srcdir
20
21
22#
23# Create the build directories
24#
25
26build=build
27buildandroid=$build/android
28platform=android-21
29abi="arm64-v8a" # "armeabi-v7a arm64-v8a x86 x86_64"
30obj=
31lib=
32ndk_args=
33flexpage=true
34
35# Allow an external caller to specify locations and platform.
36while [ $# -gt 0 ]; do
37 arg=$1
38 if [ "${arg:0:8}" == "NDK_OUT=" ]; then
39 obj=${arg#NDK_OUT=}
40 elif [ "${arg:0:13}" == "NDK_LIBS_OUT=" ]; then
41 lib=${arg#NDK_LIBS_OUT=}
42 elif [ "${arg:0:13}" == "APP_PLATFORM=" ]; then
43 platform=${arg#APP_PLATFORM=}
44 elif [ "${arg:0:8}" == "APP_ABI=" ]; then
45 abi=${arg#APP_ABI=}
46 elif [ "${arg:0:32}" == "APP_SUPPORT_FLEXIBLE_PAGE_SIZES=" ]; then
47 flexpage=${arg#APP_SUPPORT_FLEXIBLE_PAGE_SIZES=}
48 else
49 ndk_args="$ndk_args $arg"
50 fi
51 shift
52done
53
54if [ -z $obj ]; then
55 obj=$buildandroid/obj
56fi
57if [ -z $lib ]; then
58 lib=$buildandroid/lib
59fi
60
61for dir in $build $buildandroid $obj $lib; do
62 if test -d $dir; then
63 :
64 else
65 mkdir $dir || exit 1
66 fi
67done
68
69
70# APP_* variables set in the environment here will not be seen by the
71# ndk-build makefile segments that use them, e.g., default-application.mk.
72# For consistency, pass all values on the command line.
73#
74# Add support for Google Play 16 KB Page size requirement:
75# https://developer.android.com/guide/practices/page-sizes#ndk-build
76ndk-build \
77 NDK_PROJECT_PATH=null \
78 NDK_OUT=$obj \
79 NDK_LIBS_OUT=$lib \
80 APP_BUILD_SCRIPT=Android.mk \
81 APP_ABI="$abi" \
82 APP_PLATFORM="$platform" \
83 APP_MODULES="SDL3" \
84 APP_SUPPORT_FLEXIBLE_PAGE_SIZES="$flexpage" \
85 $ndk_args
diff --git a/src/contrib/SDL-3.2.20/build-scripts/build-release.py b/src/contrib/SDL-3.2.20/build-scripts/build-release.py
new file mode 100755
index 0000000..f3faa06
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/build-release.py
@@ -0,0 +1,1556 @@
1#!/usr/bin/env python3
2
3"""
4This script is shared between SDL2, SDL3, and all satellite libraries.
5Don't specialize this script for doing project-specific modifications.
6Rather, modify release-info.json.
7"""
8
9import argparse
10import collections
11import dataclasses
12from collections.abc import Callable
13import contextlib
14import datetime
15import fnmatch
16import glob
17import io
18import json
19import logging
20import multiprocessing
21import os
22from pathlib import Path
23import platform
24import re
25import shlex
26import shutil
27import subprocess
28import sys
29import tarfile
30import tempfile
31import textwrap
32import typing
33import zipfile
34
35
36logger = logging.getLogger(__name__)
37GIT_HASH_FILENAME = ".git-hash"
38REVISION_TXT = "REVISION.txt"
39
40RE_ILLEGAL_MINGW_LIBRARIES = re.compile(r"(?:lib)?(?:gcc|(?:std)?c[+][+]|(?:win)?pthread).*", flags=re.I)
41
42
43def safe_isotime_to_datetime(str_isotime: str) -> datetime.datetime:
44 try:
45 return datetime.datetime.fromisoformat(str_isotime)
46 except ValueError:
47 pass
48 logger.warning("Invalid iso time: %s", str_isotime)
49 if str_isotime[-6:-5] in ("+", "-"):
50 # Commits can have isotime with invalid timezone offset (e.g. "2021-07-04T20:01:40+32:00")
51 modified_str_isotime = str_isotime[:-6] + "+00:00"
52 try:
53 return datetime.datetime.fromisoformat(modified_str_isotime)
54 except ValueError:
55 pass
56 raise ValueError(f"Invalid isotime: {str_isotime}")
57
58
59def arc_join(*parts: list[str]) -> str:
60 assert all(p[:1] != "/" and p[-1:] != "/" for p in parts), f"None of {parts} may start or end with '/'"
61 return "/".join(p for p in parts if p)
62
63
64@dataclasses.dataclass(frozen=True)
65class VsArchPlatformConfig:
66 arch: str
67 configuration: str
68 platform: str
69
70 def extra_context(self):
71 return {
72 "ARCH": self.arch,
73 "CONFIGURATION": self.configuration,
74 "PLATFORM": self.platform,
75 }
76
77
78@contextlib.contextmanager
79def chdir(path):
80 original_cwd = os.getcwd()
81 try:
82 os.chdir(path)
83 yield
84 finally:
85 os.chdir(original_cwd)
86
87
88class Executer:
89 def __init__(self, root: Path, dry: bool=False):
90 self.root = root
91 self.dry = dry
92
93 def run(self, cmd, cwd=None, env=None):
94 logger.info("Executing args=%r", cmd)
95 sys.stdout.flush()
96 if not self.dry:
97 subprocess.check_call(cmd, cwd=cwd or self.root, env=env, text=True)
98
99 def check_output(self, cmd, cwd=None, dry_out=None, env=None, text=True):
100 logger.info("Executing args=%r", cmd)
101 sys.stdout.flush()
102 if self.dry:
103 return dry_out
104 return subprocess.check_output(cmd, cwd=cwd or self.root, env=env, text=text)
105
106
107class SectionPrinter:
108 @contextlib.contextmanager
109 def group(self, title: str):
110 print(f"{title}:")
111 yield
112
113
114class GitHubSectionPrinter(SectionPrinter):
115 def __init__(self):
116 super().__init__()
117 self.in_group = False
118
119 @contextlib.contextmanager
120 def group(self, title: str):
121 print(f"::group::{title}")
122 assert not self.in_group, "Can enter a group only once"
123 self.in_group = True
124 yield
125 self.in_group = False
126 print("::endgroup::")
127
128
129class VisualStudio:
130 def __init__(self, executer: Executer, year: typing.Optional[str]=None):
131 self.executer = executer
132 self.vsdevcmd = self.find_vsdevcmd(year)
133 self.msbuild = self.find_msbuild()
134
135 @property
136 def dry(self) -> bool:
137 return self.executer.dry
138
139 VS_YEAR_TO_VERSION = {
140 "2022": 17,
141 "2019": 16,
142 "2017": 15,
143 "2015": 14,
144 "2013": 12,
145 }
146
147 def find_vsdevcmd(self, year: typing.Optional[str]=None) -> typing.Optional[Path]:
148 vswhere_spec = ["-latest"]
149 if year is not None:
150 try:
151 version = self.VS_YEAR_TO_VERSION[year]
152 except KeyError:
153 logger.error("Invalid Visual Studio year")
154 return None
155 vswhere_spec.extend(["-version", f"[{version},{version+1})"])
156 vswhere_cmd = ["vswhere"] + vswhere_spec + ["-property", "installationPath"]
157 vs_install_path = Path(self.executer.check_output(vswhere_cmd, dry_out="/tmp").strip())
158 logger.info("VS install_path = %s", vs_install_path)
159 assert vs_install_path.is_dir(), "VS installation path does not exist"
160 vsdevcmd_path = vs_install_path / "Common7/Tools/vsdevcmd.bat"
161 logger.info("vsdevcmd path = %s", vsdevcmd_path)
162 if self.dry:
163 vsdevcmd_path.parent.mkdir(parents=True, exist_ok=True)
164 vsdevcmd_path.touch(exist_ok=True)
165 assert vsdevcmd_path.is_file(), "vsdevcmd.bat batch file does not exist"
166 return vsdevcmd_path
167
168 def find_msbuild(self) -> typing.Optional[Path]:
169 vswhere_cmd = ["vswhere", "-latest", "-requires", "Microsoft.Component.MSBuild", "-find", r"MSBuild\**\Bin\MSBuild.exe"]
170 msbuild_path = Path(self.executer.check_output(vswhere_cmd, dry_out="/tmp/MSBuild.exe").strip())
171 logger.info("MSBuild path = %s", msbuild_path)
172 if self.dry:
173 msbuild_path.parent.mkdir(parents=True, exist_ok=True)
174 msbuild_path.touch(exist_ok=True)
175 assert msbuild_path.is_file(), "MSBuild.exe does not exist"
176 return msbuild_path
177
178 def build(self, arch_platform: VsArchPlatformConfig, projects: list[Path]):
179 assert projects, "Need at least one project to build"
180
181 vsdev_cmd_str = f"\"{self.vsdevcmd}\" -arch={arch_platform.arch}"
182 msbuild_cmd_str = " && ".join([f"\"{self.msbuild}\" \"{project}\" /m /p:BuildInParallel=true /p:Platform={arch_platform.platform} /p:Configuration={arch_platform.configuration}" for project in projects])
183 bat_contents = f"{vsdev_cmd_str} && {msbuild_cmd_str}\n"
184 bat_path = Path(tempfile.gettempdir()) / "cmd.bat"
185 with bat_path.open("w") as f:
186 f.write(bat_contents)
187
188 logger.info("Running cmd.exe script (%s): %s", bat_path, bat_contents)
189 cmd = ["cmd.exe", "/D", "/E:ON", "/V:OFF", "/S", "/C", f"CALL {str(bat_path)}"]
190 self.executer.run(cmd)
191
192
193class Archiver:
194 def __init__(self, zip_path: typing.Optional[Path]=None, tgz_path: typing.Optional[Path]=None, txz_path: typing.Optional[Path]=None):
195 self._zip_files = []
196 self._tar_files = []
197 self._added_files = set()
198 if zip_path:
199 self._zip_files.append(zipfile.ZipFile(zip_path, "w", compression=zipfile.ZIP_DEFLATED))
200 if tgz_path:
201 self._tar_files.append(tarfile.open(tgz_path, "w:gz"))
202 if txz_path:
203 self._tar_files.append(tarfile.open(txz_path, "w:xz"))
204
205 @property
206 def added_files(self) -> set[str]:
207 return self._added_files
208
209 def add_file_data(self, arcpath: str, data: bytes, mode: int, time: datetime.datetime):
210 for zf in self._zip_files:
211 file_data_time = (time.year, time.month, time.day, time.hour, time.minute, time.second)
212 zip_info = zipfile.ZipInfo(filename=arcpath, date_time=file_data_time)
213 zip_info.external_attr = mode << 16
214 zip_info.compress_type = zipfile.ZIP_DEFLATED
215 zf.writestr(zip_info, data=data)
216 for tf in self._tar_files:
217 tar_info = tarfile.TarInfo(arcpath)
218 tar_info.type = tarfile.REGTYPE
219 tar_info.mode = mode
220 tar_info.size = len(data)
221 tar_info.mtime = int(time.timestamp())
222 tf.addfile(tar_info, fileobj=io.BytesIO(data))
223
224 self._added_files.add(arcpath)
225
226 def add_symlink(self, arcpath: str, target: str, time: datetime.datetime, files_for_zip):
227 logger.debug("Adding symlink (target=%r) -> %s", target, arcpath)
228 for zf in self._zip_files:
229 file_data_time = (time.year, time.month, time.day, time.hour, time.minute, time.second)
230 for f in files_for_zip:
231 zip_info = zipfile.ZipInfo(filename=f["arcpath"], date_time=file_data_time)
232 zip_info.external_attr = f["mode"] << 16
233 zip_info.compress_type = zipfile.ZIP_DEFLATED
234 zf.writestr(zip_info, data=f["data"])
235 for tf in self._tar_files:
236 tar_info = tarfile.TarInfo(arcpath)
237 tar_info.type = tarfile.SYMTYPE
238 tar_info.mode = 0o777
239 tar_info.mtime = int(time.timestamp())
240 tar_info.linkname = target
241 tf.addfile(tar_info)
242
243 self._added_files.update(f["arcpath"] for f in files_for_zip)
244
245 def add_git_hash(self, arcdir: str, commit: str, time: datetime.datetime):
246 arcpath = arc_join(arcdir, GIT_HASH_FILENAME)
247 data = f"{commit}\n".encode()
248 self.add_file_data(arcpath=arcpath, data=data, mode=0o100644, time=time)
249
250 def add_file_path(self, arcpath: str, path: Path):
251 assert path.is_file(), f"{path} should be a file"
252 logger.debug("Adding %s -> %s", path, arcpath)
253 for zf in self._zip_files:
254 zf.write(path, arcname=arcpath)
255 for tf in self._tar_files:
256 tf.add(path, arcname=arcpath)
257
258 def add_file_directory(self, arcdirpath: str, dirpath: Path):
259 assert dirpath.is_dir()
260 if arcdirpath and arcdirpath[-1:] != "/":
261 arcdirpath += "/"
262 for f in dirpath.iterdir():
263 if f.is_file():
264 arcpath = f"{arcdirpath}{f.name}"
265 logger.debug("Adding %s to %s", f, arcpath)
266 self.add_file_path(arcpath=arcpath, path=f)
267
268 def close(self):
269 # Archiver is intentionally made invalid after this function
270 del self._zip_files
271 self._zip_files = None
272 del self._tar_files
273 self._tar_files = None
274
275 def __enter__(self):
276 return self
277
278 def __exit__(self, type, value, traceback):
279 self.close()
280
281
282class NodeInArchive:
283 def __init__(self, arcpath: str, path: typing.Optional[Path]=None, data: typing.Optional[bytes]=None, mode: typing.Optional[int]=None, symtarget: typing.Optional[str]=None, time: typing.Optional[datetime.datetime]=None, directory: bool=False):
284 self.arcpath = arcpath
285 self.path = path
286 self.data = data
287 self.mode = mode
288 self.symtarget = symtarget
289 self.time = time
290 self.directory = directory
291
292 @classmethod
293 def from_fs(cls, arcpath: str, path: Path, mode: int=0o100644, time: typing.Optional[datetime.datetime]=None) -> "NodeInArchive":
294 if time is None:
295 time = datetime.datetime.fromtimestamp(os.stat(path).st_mtime)
296 return cls(arcpath=arcpath, path=path, mode=mode)
297
298 @classmethod
299 def from_data(cls, arcpath: str, data: bytes, time: datetime.datetime) -> "NodeInArchive":
300 return cls(arcpath=arcpath, data=data, time=time, mode=0o100644)
301
302 @classmethod
303 def from_text(cls, arcpath: str, text: str, time: datetime.datetime) -> "NodeInArchive":
304 return cls.from_data(arcpath=arcpath, data=text.encode(), time=time)
305
306 @classmethod
307 def from_symlink(cls, arcpath: str, symtarget: str) -> "NodeInArchive":
308 return cls(arcpath=arcpath, symtarget=symtarget)
309
310 @classmethod
311 def from_directory(cls, arcpath: str) -> "NodeInArchive":
312 return cls(arcpath=arcpath, directory=True)
313
314 def __repr__(self) -> str:
315 return f"<{type(self).__name__}:arcpath={self.arcpath},path='{str(self.path)}',len(data)={len(self.data) if self.data else 'n/a'},directory={self.directory},symtarget={self.symtarget}>"
316
317
318def configure_file(path: Path, context: dict[str, str]) -> bytes:
319 text = path.read_text()
320 return configure_text(text, context=context).encode()
321
322
323def configure_text(text: str, context: dict[str, str]) -> str:
324 original_text = text
325 for txt, repl in context.items():
326 text = text.replace(f"@<@{txt}@>@", repl)
327 success = all(thing not in text for thing in ("@<@", "@>@"))
328 if not success:
329 raise ValueError(f"Failed to configure {repr(original_text)}")
330 return text
331
332
333def configure_text_list(text_list: list[str], context: dict[str, str]) -> list[str]:
334 return [configure_text(text=e, context=context) for e in text_list]
335
336
337class ArchiveFileTree:
338 def __init__(self):
339 self._tree: dict[str, NodeInArchive] = {}
340
341 def add_file(self, file: NodeInArchive):
342 self._tree[file.arcpath] = file
343
344 def __iter__(self) -> typing.Iterable[NodeInArchive]:
345 yield from self._tree.values()
346
347 def __contains__(self, value: str) -> bool:
348 return value in self._tree
349
350 def get_latest_mod_time(self) -> datetime.datetime:
351 return max(item.time for item in self._tree.values() if item.time)
352
353 def add_to_archiver(self, archive_base: str, archiver: Archiver):
354 remaining_symlinks = set()
355 added_files = dict()
356
357 def calculate_symlink_target(s: NodeInArchive) -> str:
358 dest_dir = os.path.dirname(s.arcpath)
359 if dest_dir:
360 dest_dir += "/"
361 target = dest_dir + s.symtarget
362 while True:
363 new_target, n = re.subn(r"([^/]+/+[.]{2}/)", "", target)
364 target = new_target
365 if not n:
366 break
367 return target
368
369 # Add files in first pass
370 for arcpath, node in self._tree.items():
371 assert node is not None, f"{arcpath} -> node"
372 if node.data is not None:
373 archiver.add_file_data(arcpath=arc_join(archive_base, arcpath), data=node.data, time=node.time, mode=node.mode)
374 assert node.arcpath is not None, f"{node=}"
375 added_files[node.arcpath] = node
376 elif node.path is not None:
377 archiver.add_file_path(arcpath=arc_join(archive_base, arcpath), path=node.path)
378 assert node.arcpath is not None, f"{node=}"
379 added_files[node.arcpath] = node
380 elif node.symtarget is not None:
381 remaining_symlinks.add(node)
382 elif node.directory:
383 pass
384 else:
385 raise ValueError(f"Invalid Archive Node: {repr(node)}")
386
387 assert None not in added_files
388
389 # Resolve symlinks in second pass: zipfile does not support symlinks, so add files to zip archive
390 while True:
391 if not remaining_symlinks:
392 break
393 symlinks_this_time = set()
394 extra_added_files = {}
395 for symlink in remaining_symlinks:
396 symlink_files_for_zip = {}
397 symlink_target_path = calculate_symlink_target(symlink)
398 if symlink_target_path in added_files:
399 symlink_files_for_zip[symlink.arcpath] = added_files[symlink_target_path]
400 else:
401 symlink_target_path_slash = symlink_target_path + "/"
402 for added_file in added_files:
403 if added_file.startswith(symlink_target_path_slash):
404 path_in_symlink = symlink.arcpath + "/" + added_file.removeprefix(symlink_target_path_slash)
405 symlink_files_for_zip[path_in_symlink] = added_files[added_file]
406 if symlink_files_for_zip:
407 symlinks_this_time.add(symlink)
408 extra_added_files.update(symlink_files_for_zip)
409 files_for_zip = [{"arcpath": f"{archive_base}/{sym_path}", "data": sym_info.data, "mode": sym_info.mode} for sym_path, sym_info in symlink_files_for_zip.items()]
410 archiver.add_symlink(arcpath=f"{archive_base}/{symlink.arcpath}", target=symlink.symtarget, time=symlink.time, files_for_zip=files_for_zip)
411 # if not symlinks_this_time:
412 # logger.info("files added: %r", set(path for path in added_files.keys()))
413 assert symlinks_this_time, f"No targets found for symlinks: {remaining_symlinks}"
414 remaining_symlinks.difference_update(symlinks_this_time)
415 added_files.update(extra_added_files)
416
417 def add_directory_tree(self, arc_dir: str, path: Path, time: datetime.datetime):
418 assert path.is_dir()
419 for files_dir, _, filenames in os.walk(path):
420 files_dir_path = Path(files_dir)
421 rel_files_path = files_dir_path.relative_to(path)
422 for filename in filenames:
423 self.add_file(NodeInArchive.from_fs(arcpath=arc_join(arc_dir, str(rel_files_path), filename), path=files_dir_path / filename, time=time))
424
425 def _add_files_recursively(self, arc_dir: str, paths: list[Path], time: datetime.datetime):
426 logger.debug(f"_add_files_recursively({arc_dir=} {paths=})")
427 for path in paths:
428 arcpath = arc_join(arc_dir, path.name)
429 if path.is_file():
430 logger.debug("Adding %s as %s", path, arcpath)
431 self.add_file(NodeInArchive.from_fs(arcpath=arcpath, path=path, time=time))
432 elif path.is_dir():
433 self._add_files_recursively(arc_dir=arc_join(arc_dir, path.name), paths=list(path.iterdir()), time=time)
434 else:
435 raise ValueError(f"Unsupported file type to add recursively: {path}")
436
437 def add_file_mapping(self, arc_dir: str, file_mapping: dict[str, list[str]], file_mapping_root: Path, context: dict[str, str], time: datetime.datetime):
438 for meta_rel_destdir, meta_file_globs in file_mapping.items():
439 rel_destdir = configure_text(meta_rel_destdir, context=context)
440 assert "@" not in rel_destdir, f"archive destination should not contain an @ after configuration ({repr(meta_rel_destdir)}->{repr(rel_destdir)})"
441 for meta_file_glob in meta_file_globs:
442 file_glob = configure_text(meta_file_glob, context=context)
443 assert "@" not in rel_destdir, f"archive glob should not contain an @ after configuration ({repr(meta_file_glob)}->{repr(file_glob)})"
444 if ":" in file_glob:
445 original_path, new_filename = file_glob.rsplit(":", 1)
446 assert ":" not in original_path, f"Too many ':' in {repr(file_glob)}"
447 assert "/" not in new_filename, f"New filename cannot contain a '/' in {repr(file_glob)}"
448 path = file_mapping_root / original_path
449 arcpath = arc_join(arc_dir, rel_destdir, new_filename)
450 if path.suffix == ".in":
451 data = configure_file(path, context=context)
452 logger.debug("Adding processed %s -> %s", path, arcpath)
453 self.add_file(NodeInArchive.from_data(arcpath=arcpath, data=data, time=time))
454 else:
455 logger.debug("Adding %s -> %s", path, arcpath)
456 self.add_file(NodeInArchive.from_fs(arcpath=arcpath, path=path, time=time))
457 else:
458 relative_file_paths = glob.glob(file_glob, root_dir=file_mapping_root)
459 assert relative_file_paths, f"Glob '{file_glob}' does not match any file"
460 self._add_files_recursively(arc_dir=arc_join(arc_dir, rel_destdir), paths=[file_mapping_root / p for p in relative_file_paths], time=time)
461
462
463class SourceCollector:
464 # TreeItem = collections.namedtuple("TreeItem", ("path", "mode", "data", "symtarget", "directory", "time"))
465 def __init__(self, root: Path, commit: str, filter: typing.Optional[Callable[[str], bool]], executer: Executer):
466 self.root = root
467 self.commit = commit
468 self.filter = filter
469 self.executer = executer
470
471 def get_archive_file_tree(self) -> ArchiveFileTree:
472 git_archive_args = ["git", "archive", "--format=tar.gz", self.commit, "-o", "/dev/stdout"]
473 logger.info("Executing args=%r", git_archive_args)
474 contents_tgz = subprocess.check_output(git_archive_args, cwd=self.root, text=False)
475 tar_archive = tarfile.open(fileobj=io.BytesIO(contents_tgz), mode="r:gz")
476 filenames = tuple(m.name for m in tar_archive if (m.isfile() or m.issym()))
477
478 file_times = self._get_file_times(paths=filenames)
479 git_contents = ArchiveFileTree()
480 for ti in tar_archive:
481 if self.filter and not self.filter(ti.name):
482 continue
483 data = None
484 symtarget = None
485 directory = False
486 file_time = None
487 if ti.isfile():
488 contents_file = tar_archive.extractfile(ti.name)
489 data = contents_file.read()
490 file_time = file_times[ti.name]
491 elif ti.issym():
492 symtarget = ti.linkname
493 file_time = file_times[ti.name]
494 elif ti.isdir():
495 directory = True
496 else:
497 raise ValueError(f"{ti.name}: unknown type")
498 node = NodeInArchive(arcpath=ti.name, data=data, mode=ti.mode, symtarget=symtarget, time=file_time, directory=directory)
499 git_contents.add_file(node)
500 return git_contents
501
502 def _get_file_times(self, paths: tuple[str, ...]) -> dict[str, datetime.datetime]:
503 dry_out = textwrap.dedent("""\
504 time=2024-03-14T15:40:25-07:00
505
506 M\tCMakeLists.txt
507 """)
508 git_log_out = self.executer.check_output(["git", "log", "--name-status", '--pretty=time=%cI', self.commit], dry_out=dry_out, cwd=self.root).splitlines(keepends=False)
509 current_time = None
510 set_paths = set(paths)
511 path_times: dict[str, datetime.datetime] = {}
512 for line in git_log_out:
513 if not line:
514 continue
515 if line.startswith("time="):
516 current_time = safe_isotime_to_datetime(line.removeprefix("time="))
517 continue
518 mod_type, file_paths = line.split(maxsplit=1)
519 assert current_time is not None
520 for file_path in file_paths.split("\t"):
521 if file_path in set_paths and file_path not in path_times:
522 path_times[file_path] = current_time
523
524 # FIXME: find out why some files are not shown in "git log"
525 # assert set(path_times.keys()) == set_paths
526 if set(path_times.keys()) != set_paths:
527 found_times = set(path_times.keys())
528 paths_without_times = set_paths.difference(found_times)
529 logger.warning("No times found for these paths: %s", paths_without_times)
530 max_time = max(time for time in path_times.values())
531 for path in paths_without_times:
532 path_times[path] = max_time
533
534 return path_times
535
536
537class AndroidApiVersion:
538 def __init__(self, name: str, ints: tuple[int, ...]):
539 self.name = name
540 self.ints = ints
541
542 def __repr__(self) -> str:
543 return f"<{self.name} ({'.'.join(str(v) for v in self.ints)})>"
544
545
546class Releaser:
547 def __init__(self, release_info: dict, commit: str, revision: str, root: Path, dist_path: Path, section_printer: SectionPrinter, executer: Executer, cmake_generator: str, deps_path: Path, overwrite: bool, github: bool, fast: bool):
548 self.release_info = release_info
549 self.project = release_info["name"]
550 self.version = self.extract_sdl_version(root=root, release_info=release_info)
551 self.root = root
552 self.commit = commit
553 self.revision = revision
554 self.dist_path = dist_path
555 self.section_printer = section_printer
556 self.executer = executer
557 self.cmake_generator = cmake_generator
558 self.cpu_count = multiprocessing.cpu_count()
559 self.deps_path = deps_path
560 self.overwrite = overwrite
561 self.github = github
562 self.fast = fast
563 self.arc_time = datetime.datetime.now()
564
565 self.artifacts: dict[str, Path] = {}
566
567 def get_context(self, extra_context: typing.Optional[dict[str, str]]=None) -> dict[str, str]:
568 ctx = {
569 "PROJECT_NAME": self.project,
570 "PROJECT_VERSION": self.version,
571 "PROJECT_COMMIT": self.commit,
572 "PROJECT_REVISION": self.revision,
573 "PROJECT_ROOT": str(self.root),
574 }
575 if extra_context:
576 ctx.update(extra_context)
577 return ctx
578
579 @property
580 def dry(self) -> bool:
581 return self.executer.dry
582
583 def prepare(self):
584 logger.debug("Creating dist folder")
585 self.dist_path.mkdir(parents=True, exist_ok=True)
586
587 @classmethod
588 def _path_filter(cls, path: str) -> bool:
589 if ".gitmodules" in path:
590 return True
591 if path.startswith(".git"):
592 return False
593 return True
594
595 @classmethod
596 def _external_repo_path_filter(cls, path: str) -> bool:
597 if not cls._path_filter(path):
598 return False
599 if path.startswith("test/") or path.startswith("tests/"):
600 return False
601 return True
602
603 def create_source_archives(self) -> None:
604 source_collector = SourceCollector(root=self.root, commit=self.commit, executer=self.executer, filter=self._path_filter)
605 print(f"Collecting sources of {self.project}...")
606 archive_tree: ArchiveFileTree = source_collector.get_archive_file_tree()
607 latest_mod_time = archive_tree.get_latest_mod_time()
608 archive_tree.add_file(NodeInArchive.from_text(arcpath=REVISION_TXT, text=f"{self.revision}\n", time=latest_mod_time))
609 archive_tree.add_file(NodeInArchive.from_text(arcpath=f"{GIT_HASH_FILENAME}", text=f"{self.commit}\n", time=latest_mod_time))
610 archive_tree.add_file_mapping(arc_dir="", file_mapping=self.release_info["source"].get("files", {}), file_mapping_root=self.root, context=self.get_context(), time=latest_mod_time)
611
612 if "Makefile.am" in archive_tree:
613 patched_time = latest_mod_time + datetime.timedelta(minutes=1)
614 print(f"Makefile.am detected -> touching aclocal.m4, */Makefile.in, configure")
615 for node_data in archive_tree:
616 arc_name = os.path.basename(node_data.arcpath)
617 arc_name_we, arc_name_ext = os.path.splitext(arc_name)
618 if arc_name in ("aclocal.m4", "configure", "Makefile.in"):
619 print(f"Bumping time of {node_data.arcpath}")
620 node_data.time = patched_time
621
622 archive_base = f"{self.project}-{self.version}"
623 zip_path = self.dist_path / f"{archive_base}.zip"
624 tgz_path = self.dist_path / f"{archive_base}.tar.gz"
625 txz_path = self.dist_path / f"{archive_base}.tar.xz"
626
627 logger.info("Creating zip/tgz/txz source archives ...")
628 if self.dry:
629 zip_path.touch()
630 tgz_path.touch()
631 txz_path.touch()
632 else:
633 with Archiver(zip_path=zip_path, tgz_path=tgz_path, txz_path=txz_path) as archiver:
634 print(f"Adding source files of {self.project}...")
635 archive_tree.add_to_archiver(archive_base=archive_base, archiver=archiver)
636
637 for extra_repo in self.release_info["source"].get("extra-repos", []):
638 extra_repo_root = self.root / extra_repo
639 assert (extra_repo_root / ".git").exists(), f"{extra_repo_root} must be a git repo"
640 extra_repo_commit = self.executer.check_output(["git", "rev-parse", "HEAD"], dry_out=f"gitsha-extra-repo-{extra_repo}", cwd=extra_repo_root).strip()
641 extra_repo_source_collector = SourceCollector(root=extra_repo_root, commit=extra_repo_commit, executer=self.executer, filter=self._external_repo_path_filter)
642 print(f"Collecting sources of {extra_repo} ...")
643 extra_repo_archive_tree = extra_repo_source_collector.get_archive_file_tree()
644 print(f"Adding source files of {extra_repo} ...")
645 extra_repo_archive_tree.add_to_archiver(archive_base=f"{archive_base}/{extra_repo}", archiver=archiver)
646
647 for file in self.release_info["source"]["checks"]:
648 assert f"{archive_base}/{file}" in archiver.added_files, f"'{archive_base}/{file}' must exist"
649
650 logger.info("... done")
651
652 self.artifacts["src-zip"] = zip_path
653 self.artifacts["src-tar-gz"] = tgz_path
654 self.artifacts["src-tar-xz"] = txz_path
655
656 if not self.dry:
657 with tgz_path.open("r+b") as f:
658 # Zero the embedded timestamp in the gzip'ed tarball
659 f.seek(4, 0)
660 f.write(b"\x00\x00\x00\x00")
661
662 def create_dmg(self, configuration: str="Release") -> None:
663 dmg_in = self.root / self.release_info["dmg"]["path"]
664 xcode_project = self.root / self.release_info["dmg"]["project"]
665 assert xcode_project.is_dir(), f"{xcode_project} must be a directory"
666 assert (xcode_project / "project.pbxproj").is_file, f"{xcode_project} must contain project.pbxproj"
667 if not self.fast:
668 dmg_in.unlink(missing_ok=True)
669 build_xcconfig = self.release_info["dmg"].get("build-xcconfig")
670 if build_xcconfig:
671 shutil.copy(self.root / build_xcconfig, xcode_project.parent / "build.xcconfig")
672
673 xcode_scheme = self.release_info["dmg"].get("scheme")
674 xcode_target = self.release_info["dmg"].get("target")
675 assert xcode_scheme or xcode_target, "dmg needs scheme or target"
676 assert not (xcode_scheme and xcode_target), "dmg cannot have both scheme and target set"
677 if xcode_scheme:
678 scheme_or_target = "-scheme"
679 target_like = xcode_scheme
680 else:
681 scheme_or_target = "-target"
682 target_like = xcode_target
683 self.executer.run(["xcodebuild", "ONLY_ACTIVE_ARCH=NO", "-project", xcode_project, scheme_or_target, target_like, "-configuration", configuration])
684 if self.dry:
685 dmg_in.parent.mkdir(parents=True, exist_ok=True)
686 dmg_in.touch()
687
688 assert dmg_in.is_file(), f"{self.project}.dmg was not created by xcodebuild"
689
690 dmg_out = self.dist_path / f"{self.project}-{self.version}.dmg"
691 shutil.copy(dmg_in, dmg_out)
692 self.artifacts["dmg"] = dmg_out
693
694 @property
695 def git_hash_data(self) -> bytes:
696 return f"{self.commit}\n".encode()
697
698 def verify_mingw_library(self, triplet: str, path: Path):
699 objdump_output = self.executer.check_output([f"{triplet}-objdump", "-p", str(path)])
700 libraries = re.findall(r"DLL Name: ([^\n]+)", objdump_output)
701 logger.info("%s (%s) libraries: %r", path, triplet, libraries)
702 illegal_libraries = list(filter(RE_ILLEGAL_MINGW_LIBRARIES.match, libraries))
703 logger.error("Detected 'illegal' libraries: %r", illegal_libraries)
704 if illegal_libraries:
705 raise Exception(f"{path} links to illegal libraries: {illegal_libraries}")
706
707 def create_mingw_archives(self) -> None:
708 build_type = "Release"
709 build_parent_dir = self.root / "build-mingw"
710 ARCH_TO_GNU_ARCH = {
711 # "arm64": "aarch64",
712 "x86": "i686",
713 "x64": "x86_64",
714 }
715 ARCH_TO_TRIPLET = {
716 # "arm64": "aarch64-w64-mingw32",
717 "x86": "i686-w64-mingw32",
718 "x64": "x86_64-w64-mingw32",
719 }
720
721 new_env = dict(os.environ)
722
723 cmake_prefix_paths = []
724 mingw_deps_path = self.deps_path / "mingw-deps"
725
726 if "dependencies" in self.release_info["mingw"]:
727 shutil.rmtree(mingw_deps_path, ignore_errors=True)
728 mingw_deps_path.mkdir()
729
730 for triplet in ARCH_TO_TRIPLET.values():
731 (mingw_deps_path / triplet).mkdir()
732
733 def extract_filter(member: tarfile.TarInfo, path: str, /):
734 if member.name.startswith("SDL"):
735 member.name = "/".join(Path(member.name).parts[1:])
736 return member
737 for dep in self.release_info.get("dependencies", {}):
738 extract_path = mingw_deps_path / f"extract-{dep}"
739 extract_path.mkdir()
740 with chdir(extract_path):
741 tar_path = self.deps_path / glob.glob(self.release_info["mingw"]["dependencies"][dep]["artifact"], root_dir=self.deps_path)[0]
742 logger.info("Extracting %s to %s", tar_path, mingw_deps_path)
743 assert tar_path.suffix in (".gz", ".xz")
744 with tarfile.open(tar_path, mode=f"r:{tar_path.suffix.strip('.')}") as tarf:
745 tarf.extractall(filter=extract_filter)
746 for arch, triplet in ARCH_TO_TRIPLET.items():
747 install_cmd = self.release_info["mingw"]["dependencies"][dep]["install-command"]
748 extra_configure_data = {
749 "ARCH": ARCH_TO_GNU_ARCH[arch],
750 "TRIPLET": triplet,
751 "PREFIX": str(mingw_deps_path / triplet),
752 }
753 install_cmd = configure_text(install_cmd, context=self.get_context(extra_configure_data))
754 self.executer.run(shlex.split(install_cmd), cwd=str(extract_path))
755
756 dep_binpath = mingw_deps_path / triplet / "bin"
757 assert dep_binpath.is_dir(), f"{dep_binpath} for PATH should exist"
758 dep_pkgconfig = mingw_deps_path / triplet / "lib/pkgconfig"
759 assert dep_pkgconfig.is_dir(), f"{dep_pkgconfig} for PKG_CONFIG_PATH should exist"
760
761 new_env["PATH"] = os.pathsep.join([str(dep_binpath), new_env["PATH"]])
762 new_env["PKG_CONFIG_PATH"] = str(dep_pkgconfig)
763 cmake_prefix_paths.append(mingw_deps_path)
764
765 new_env["CFLAGS"] = f"-O2 -ffile-prefix-map={self.root}=/src/{self.project}"
766 new_env["CXXFLAGS"] = f"-O2 -ffile-prefix-map={self.root}=/src/{self.project}"
767
768 assert any(system in self.release_info["mingw"] for system in ("autotools", "cmake"))
769 assert not all(system in self.release_info["mingw"] for system in ("autotools", "cmake"))
770
771 mingw_archs = set()
772 arc_root = f"{self.project}-{self.version}"
773 archive_file_tree = ArchiveFileTree()
774
775 if "autotools" in self.release_info["mingw"]:
776 for arch in self.release_info["mingw"]["autotools"]["archs"]:
777 triplet = ARCH_TO_TRIPLET[arch]
778 new_env["CC"] = f"{triplet}-gcc"
779 new_env["CXX"] = f"{triplet}-g++"
780 new_env["RC"] = f"{triplet}-windres"
781
782 assert arch not in mingw_archs
783 mingw_archs.add(arch)
784
785 build_path = build_parent_dir / f"build-{triplet}"
786 install_path = build_parent_dir / f"install-{triplet}"
787 shutil.rmtree(install_path, ignore_errors=True)
788 build_path.mkdir(parents=True, exist_ok=True)
789 context = self.get_context({
790 "ARCH": arch,
791 "DEP_PREFIX": str(mingw_deps_path / triplet),
792 })
793 extra_args = configure_text_list(text_list=self.release_info["mingw"]["autotools"]["args"], context=context)
794
795 with self.section_printer.group(f"Configuring MinGW {triplet} (autotools)"):
796 assert "@" not in " ".join(extra_args), f"@ should not be present in extra arguments ({extra_args})"
797 self.executer.run([
798 self.root / "configure",
799 f"--prefix={install_path}",
800 f"--includedir=${{prefix}}/include",
801 f"--libdir=${{prefix}}/lib",
802 f"--bindir=${{prefix}}/bin",
803 f"--host={triplet}",
804 f"--build=x86_64-none-linux-gnu",
805 "CFLAGS=-O2",
806 "CXXFLAGS=-O2",
807 "LDFLAGS=-Wl,-s",
808 ] + extra_args, cwd=build_path, env=new_env)
809 with self.section_printer.group(f"Build MinGW {triplet} (autotools)"):
810 self.executer.run(["make", f"-j{self.cpu_count}"], cwd=build_path, env=new_env)
811 with self.section_printer.group(f"Install MinGW {triplet} (autotools)"):
812 self.executer.run(["make", "install"], cwd=build_path, env=new_env)
813 self.verify_mingw_library(triplet=ARCH_TO_TRIPLET[arch], path=install_path / "bin" / f"{self.project}.dll")
814 archive_file_tree.add_directory_tree(arc_dir=arc_join(arc_root, triplet), path=install_path, time=self.arc_time)
815
816 print("Recording arch-dependent extra files for MinGW development archive ...")
817 extra_context = {
818 "TRIPLET": ARCH_TO_TRIPLET[arch],
819 }
820 archive_file_tree.add_file_mapping(arc_dir=arc_root, file_mapping=self.release_info["mingw"]["autotools"].get("files", {}), file_mapping_root=self.root, context=self.get_context(extra_context=extra_context), time=self.arc_time)
821
822 if "cmake" in self.release_info["mingw"]:
823 assert self.release_info["mingw"]["cmake"]["shared-static"] in ("args", "both")
824 for arch in self.release_info["mingw"]["cmake"]["archs"]:
825 triplet = ARCH_TO_TRIPLET[arch]
826 new_env["CC"] = f"{triplet}-gcc"
827 new_env["CXX"] = f"{triplet}-g++"
828 new_env["RC"] = f"{triplet}-windres"
829
830 assert arch not in mingw_archs
831 mingw_archs.add(arch)
832
833 context = self.get_context({
834 "ARCH": arch,
835 "DEP_PREFIX": str(mingw_deps_path / triplet),
836 })
837 extra_args = configure_text_list(text_list=self.release_info["mingw"]["cmake"]["args"], context=context)
838
839 build_path = build_parent_dir / f"build-{triplet}"
840 install_path = build_parent_dir / f"install-{triplet}"
841 shutil.rmtree(install_path, ignore_errors=True)
842 build_path.mkdir(parents=True, exist_ok=True)
843 if self.release_info["mingw"]["cmake"]["shared-static"] == "args":
844 args_for_shared_static = ([], )
845 elif self.release_info["mingw"]["cmake"]["shared-static"] == "both":
846 args_for_shared_static = (["-DBUILD_SHARED_LIBS=ON"], ["-DBUILD_SHARED_LIBS=OFF"])
847 for arg_for_shared_static in args_for_shared_static:
848 with self.section_printer.group(f"Configuring MinGW {triplet} (CMake)"):
849 assert "@" not in " ".join(extra_args), f"@ should not be present in extra arguments ({extra_args})"
850 self.executer.run([
851 f"cmake",
852 f"-S", str(self.root), "-B", str(build_path),
853 f"-DCMAKE_BUILD_TYPE={build_type}",
854 f'''-DCMAKE_C_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''',
855 f'''-DCMAKE_CXX_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''',
856 f"-DCMAKE_PREFIX_PATH={mingw_deps_path / triplet}",
857 f"-DCMAKE_INSTALL_PREFIX={install_path}",
858 f"-DCMAKE_INSTALL_INCLUDEDIR=include",
859 f"-DCMAKE_INSTALL_LIBDIR=lib",
860 f"-DCMAKE_INSTALL_BINDIR=bin",
861 f"-DCMAKE_INSTALL_DATAROOTDIR=share",
862 f"-DCMAKE_TOOLCHAIN_FILE={self.root}/build-scripts/cmake-toolchain-mingw64-{ARCH_TO_GNU_ARCH[arch]}.cmake",
863 f"-G{self.cmake_generator}",
864 ] + extra_args + ([] if self.fast else ["--fresh"]) + arg_for_shared_static, cwd=build_path, env=new_env)
865 with self.section_printer.group(f"Build MinGW {triplet} (CMake)"):
866 self.executer.run(["cmake", "--build", str(build_path), "--verbose", "--config", build_type], cwd=build_path, env=new_env)
867 with self.section_printer.group(f"Install MinGW {triplet} (CMake)"):
868 self.executer.run(["cmake", "--install", str(build_path)], cwd=build_path, env=new_env)
869 self.verify_mingw_library(triplet=ARCH_TO_TRIPLET[arch], path=install_path / "bin" / f"{self.project}.dll")
870 archive_file_tree.add_directory_tree(arc_dir=arc_join(arc_root, triplet), path=install_path, time=self.arc_time)
871
872 print("Recording arch-dependent extra files for MinGW development archive ...")
873 extra_context = {
874 "TRIPLET": ARCH_TO_TRIPLET[arch],
875 }
876 archive_file_tree.add_file_mapping(arc_dir=arc_root, file_mapping=self.release_info["mingw"]["cmake"].get("files", {}), file_mapping_root=self.root, context=self.get_context(extra_context=extra_context), time=self.arc_time)
877 print("... done")
878
879 print("Recording extra files for MinGW development archive ...")
880 archive_file_tree.add_file_mapping(arc_dir=arc_root, file_mapping=self.release_info["mingw"].get("files", {}), file_mapping_root=self.root, context=self.get_context(), time=self.arc_time)
881 print("... done")
882
883 print("Creating zip/tgz/txz development archives ...")
884 zip_path = self.dist_path / f"{self.project}-devel-{self.version}-mingw.zip"
885 tgz_path = self.dist_path / f"{self.project}-devel-{self.version}-mingw.tar.gz"
886 txz_path = self.dist_path / f"{self.project}-devel-{self.version}-mingw.tar.xz"
887
888 with Archiver(zip_path=zip_path, tgz_path=tgz_path, txz_path=txz_path) as archiver:
889 archive_file_tree.add_to_archiver(archive_base="", archiver=archiver)
890 archiver.add_git_hash(arcdir=arc_root, commit=self.commit, time=self.arc_time)
891 print("... done")
892
893 self.artifacts["mingw-devel-zip"] = zip_path
894 self.artifacts["mingw-devel-tar-gz"] = tgz_path
895 self.artifacts["mingw-devel-tar-xz"] = txz_path
896
897 def _detect_android_api(self, android_home: str) -> typing.Optional[AndroidApiVersion]:
898 platform_dirs = list(Path(p) for p in glob.glob(f"{android_home}/platforms/android-*"))
899 re_platform = re.compile("^android-([0-9]+)(?:-ext([0-9]+))?$")
900 platform_versions: list[AndroidApiVersion] = []
901 for platform_dir in platform_dirs:
902 logger.debug("Found Android Platform SDK: %s", platform_dir)
903 if not (platform_dir / "android.jar").is_file():
904 logger.debug("Skipping SDK, missing android.jar")
905 continue
906 if m:= re_platform.match(platform_dir.name):
907 platform_versions.append(AndroidApiVersion(name=platform_dir.name, ints=(int(m.group(1)), int(m.group(2) or 0))))
908 platform_versions.sort(key=lambda v: v.ints)
909 logger.info("Available platform versions: %s", platform_versions)
910 platform_versions = list(filter(lambda v: v.ints >= self._android_api_minimum.ints, platform_versions))
911 logger.info("Valid platform versions (>=%s): %s", self._android_api_minimum.ints, platform_versions)
912 if not platform_versions:
913 return None
914 android_api = platform_versions[0]
915 logger.info("Selected API version %s", android_api)
916 return android_api
917
918 def _get_prefab_json_text(self) -> str:
919 return textwrap.dedent(f"""\
920 {{
921 "schema_version": 2,
922 "name": "{self.project}",
923 "version": "{self.version}",
924 "dependencies": []
925 }}
926 """)
927
928 def _get_prefab_module_json_text(self, library_name: typing.Optional[str], export_libraries: list[str]) -> str:
929 for lib in export_libraries:
930 assert isinstance(lib, str), f"{lib} must be a string"
931 module_json_dict = {
932 "export_libraries": export_libraries,
933 }
934 if library_name:
935 module_json_dict["library_name"] = f"lib{library_name}"
936 return json.dumps(module_json_dict, indent=4)
937
938 @property
939 def _android_api_minimum(self) -> AndroidApiVersion:
940 value = self.release_info["android"]["api-minimum"]
941 if isinstance(value, int):
942 ints = (value, )
943 elif isinstance(value, str):
944 ints = tuple(split("."))
945 else:
946 raise ValueError("Invalid android.api-minimum: must be X or X.Y")
947 match len(ints):
948 case 1: name = f"android-{ints[0]}"
949 case 2: name = f"android-{ints[0]}-ext-{ints[1]}"
950 case _: raise ValueError("Invalid android.api-minimum: must be X or X.Y")
951 return AndroidApiVersion(name=name, ints=ints)
952
953 @property
954 def _android_api_target(self):
955 return self.release_info["android"]["api-target"]
956
957 @property
958 def _android_ndk_minimum(self):
959 return self.release_info["android"]["ndk-minimum"]
960
961 def _get_prefab_abi_json_text(self, abi: str, cpp: bool, shared: bool) -> str:
962 abi_json_dict = {
963 "abi": abi,
964 "api": self._android_api_minimum.ints[0],
965 "ndk": self._android_ndk_minimum,
966 "stl": "c++_shared" if cpp else "none",
967 "static": not shared,
968 }
969 return json.dumps(abi_json_dict, indent=4)
970
971 def _get_android_manifest_text(self) -> str:
972 return textwrap.dedent(f"""\
973 <manifest
974 xmlns:android="http://schemas.android.com/apk/res/android"
975 package="org.libsdl.android.{self.project}" android:versionCode="1"
976 android:versionName="1.0">
977 <uses-sdk android:minSdkVersion="{self._android_api_minimum.ints[0]}"
978 android:targetSdkVersion="{self._android_api_target}" />
979 </manifest>
980 """)
981
982 def create_android_archives(self, android_api: int, android_home: Path, android_ndk_home: Path) -> None:
983 cmake_toolchain_file = Path(android_ndk_home) / "build/cmake/android.toolchain.cmake"
984 if not cmake_toolchain_file.exists():
985 logger.error("CMake toolchain file does not exist (%s)", cmake_toolchain_file)
986 raise SystemExit(1)
987 aar_path = self.root / "build-android" / f"{self.project}-{self.version}.aar"
988 android_dist_path = self.dist_path / f"{self.project}-devel-{self.version}-android.zip"
989 android_abis = self.release_info["android"]["abis"]
990 java_jars_added = False
991 module_data_added = False
992 android_deps_path = self.deps_path / "android-deps"
993 shutil.rmtree(android_deps_path, ignore_errors=True)
994
995 for dep, depinfo in self.release_info["android"].get("dependencies", {}).items():
996 dep_devel_zip = self.deps_path / glob.glob(depinfo["artifact"], root_dir=self.deps_path)[0]
997
998 dep_extract_path = self.deps_path / f"extract/android/{dep}"
999 shutil.rmtree(dep_extract_path, ignore_errors=True)
1000 dep_extract_path.mkdir(parents=True, exist_ok=True)
1001
1002 with self.section_printer.group(f"Extracting Android dependency {dep} ({dep_devel_zip})"):
1003 with zipfile.ZipFile(dep_devel_zip, "r") as zf:
1004 zf.extractall(dep_extract_path)
1005
1006 dep_devel_aar = dep_extract_path / glob.glob("*.aar", root_dir=dep_extract_path)[0]
1007 self.executer.run([sys.executable, str(dep_devel_aar), "-o", str(android_deps_path)])
1008
1009 for module_name, module_info in self.release_info["android"]["modules"].items():
1010 assert "type" in module_info and module_info["type"] in ("interface", "library"), f"module {module_name} must have a valid type"
1011
1012 aar_file_tree = ArchiveFileTree()
1013 android_devel_file_tree = ArchiveFileTree()
1014
1015 for android_abi in android_abis:
1016 with self.section_printer.group(f"Building for Android {android_api} {android_abi}"):
1017 build_dir = self.root / "build-android" / f"{android_abi}-build"
1018 install_dir = self.root / "install-android" / f"{android_abi}-install"
1019 shutil.rmtree(install_dir, ignore_errors=True)
1020 assert not install_dir.is_dir(), f"{install_dir} should not exist prior to build"
1021 build_type = "Release"
1022 cmake_args = [
1023 "cmake",
1024 "-S", str(self.root),
1025 "-B", str(build_dir),
1026 f'''-DCMAKE_C_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''',
1027 f'''-DCMAKE_CXX_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''',
1028 f"-DCMAKE_TOOLCHAIN_FILE={cmake_toolchain_file}",
1029 f"-DCMAKE_PREFIX_PATH={str(android_deps_path)}",
1030 f"-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH",
1031 f"-DANDROID_HOME={android_home}",
1032 f"-DANDROID_PLATFORM={android_api}",
1033 f"-DANDROID_ABI={android_abi}",
1034 "-DCMAKE_POSITION_INDEPENDENT_CODE=ON",
1035 f"-DCMAKE_INSTALL_PREFIX={install_dir}",
1036 "-DCMAKE_INSTALL_INCLUDEDIR=include ",
1037 "-DCMAKE_INSTALL_LIBDIR=lib",
1038 "-DCMAKE_INSTALL_DATAROOTDIR=share",
1039 f"-DCMAKE_BUILD_TYPE={build_type}",
1040 f"-G{self.cmake_generator}",
1041 ] + self.release_info["android"]["cmake"]["args"] + ([] if self.fast else ["--fresh"])
1042 build_args = [
1043 "cmake",
1044 "--build", str(build_dir),
1045 "--verbose",
1046 "--config", build_type,
1047 ]
1048 install_args = [
1049 "cmake",
1050 "--install", str(build_dir),
1051 "--config", build_type,
1052 ]
1053 self.executer.run(cmake_args)
1054 self.executer.run(build_args)
1055 self.executer.run(install_args)
1056
1057 for module_name, module_info in self.release_info["android"]["modules"].items():
1058 arcdir_prefab_module = f"prefab/modules/{module_name}"
1059 if module_info["type"] == "library":
1060 library = install_dir / module_info["library"]
1061 assert library.suffix in (".so", ".a")
1062 assert library.is_file(), f"CMake should have built library '{library}' for module {module_name}"
1063 arcdir_prefab_libs = f"{arcdir_prefab_module}/libs/android.{android_abi}"
1064 aar_file_tree.add_file(NodeInArchive.from_fs(arcpath=f"{arcdir_prefab_libs}/{library.name}", path=library, time=self.arc_time))
1065 aar_file_tree.add_file(NodeInArchive.from_text(arcpath=f"{arcdir_prefab_libs}/abi.json", text=self._get_prefab_abi_json_text(abi=android_abi, cpp=False, shared=library.suffix == ".so"), time=self.arc_time))
1066
1067 if not module_data_added:
1068 library_name = None
1069 if module_info["type"] == "library":
1070 library_name = Path(module_info["library"]).stem.removeprefix("lib")
1071 export_libraries = module_info.get("export-libraries", [])
1072 aar_file_tree.add_file(NodeInArchive.from_text(arcpath=arc_join(arcdir_prefab_module, "module.json"), text=self._get_prefab_module_json_text(library_name=library_name, export_libraries=export_libraries), time=self.arc_time))
1073 arcdir_prefab_include = f"prefab/modules/{module_name}/include"
1074 if "includes" in module_info:
1075 aar_file_tree.add_file_mapping(arc_dir=arcdir_prefab_include, file_mapping=module_info["includes"], file_mapping_root=install_dir, context=self.get_context(), time=self.arc_time)
1076 else:
1077 aar_file_tree.add_file(NodeInArchive.from_text(arcpath=arc_join(arcdir_prefab_include, ".keep"), text="\n", time=self.arc_time))
1078 module_data_added = True
1079
1080 if not java_jars_added:
1081 java_jars_added = True
1082 if "jars" in self.release_info["android"]:
1083 classes_jar_path = install_dir / configure_text(text=self.release_info["android"]["jars"]["classes"], context=self.get_context())
1084 sources_jar_path = install_dir / configure_text(text=self.release_info["android"]["jars"]["sources"], context=self.get_context())
1085 doc_jar_path = install_dir / configure_text(text=self.release_info["android"]["jars"]["doc"], context=self.get_context())
1086 assert classes_jar_path.is_file(), f"CMake should have compiled the java sources and archived them into a JAR ({classes_jar_path})"
1087 assert sources_jar_path.is_file(), f"CMake should have archived the java sources into a JAR ({sources_jar_path})"
1088 assert doc_jar_path.is_file(), f"CMake should have archived javadoc into a JAR ({doc_jar_path})"
1089
1090 aar_file_tree.add_file(NodeInArchive.from_fs(arcpath="classes.jar", path=classes_jar_path, time=self.arc_time))
1091 aar_file_tree.add_file(NodeInArchive.from_fs(arcpath="classes-sources.jar", path=sources_jar_path, time=self.arc_time))
1092 aar_file_tree.add_file(NodeInArchive.from_fs(arcpath="classes-doc.jar", path=doc_jar_path, time=self.arc_time))
1093
1094 assert ("jars" in self.release_info["android"] and java_jars_added) or "jars" not in self.release_info["android"], "Must have archived java JAR archives"
1095
1096 aar_file_tree.add_file_mapping(arc_dir="", file_mapping=self.release_info["android"]["aar-files"], file_mapping_root=self.root, context=self.get_context(), time=self.arc_time)
1097
1098 aar_file_tree.add_file(NodeInArchive.from_text(arcpath="prefab/prefab.json", text=self._get_prefab_json_text(), time=self.arc_time))
1099 aar_file_tree.add_file(NodeInArchive.from_text(arcpath="AndroidManifest.xml", text=self._get_android_manifest_text(), time=self.arc_time))
1100
1101 with Archiver(zip_path=aar_path) as archiver:
1102 aar_file_tree.add_to_archiver(archive_base="", archiver=archiver)
1103 archiver.add_git_hash(arcdir="", commit=self.commit, time=self.arc_time)
1104
1105 android_devel_file_tree.add_file(NodeInArchive.from_fs(arcpath=aar_path.name, path=aar_path))
1106 android_devel_file_tree.add_file_mapping(arc_dir="", file_mapping=self.release_info["android"]["files"], file_mapping_root=self.root, context=self.get_context(), time=self.arc_time)
1107 with Archiver(zip_path=android_dist_path) as archiver:
1108 android_devel_file_tree.add_to_archiver(archive_base="", archiver=archiver)
1109 archiver.add_git_hash(arcdir="", commit=self.commit, time=self.arc_time)
1110
1111 self.artifacts[f"android-aar"] = android_dist_path
1112
1113 def download_dependencies(self):
1114 shutil.rmtree(self.deps_path, ignore_errors=True)
1115 self.deps_path.mkdir(parents=True)
1116
1117 if self.github:
1118 with open(os.environ["GITHUB_OUTPUT"], "a") as f:
1119 f.write(f"dep-path={self.deps_path.absolute()}\n")
1120
1121 for dep, depinfo in self.release_info.get("dependencies", {}).items():
1122 startswith = depinfo["startswith"]
1123 dep_repo = depinfo["repo"]
1124 # FIXME: dropped "--exclude-pre-releases"
1125 dep_string_data = self.executer.check_output(["gh", "-R", dep_repo, "release", "list", "--exclude-drafts", "--json", "name,createdAt,tagName", "--jq", f'[.[]|select(.name|startswith("{startswith}"))]|max_by(.createdAt)']).strip()
1126 dep_data = json.loads(dep_string_data)
1127 dep_tag = dep_data["tagName"]
1128 dep_version = dep_data["name"]
1129 logger.info("Download dependency %s version %s (tag=%s) ", dep, dep_version, dep_tag)
1130 self.executer.run(["gh", "-R", dep_repo, "release", "download", dep_tag], cwd=self.deps_path)
1131 if self.github:
1132 with open(os.environ["GITHUB_OUTPUT"], "a") as f:
1133 f.write(f"dep-{dep.lower()}-version={dep_version}\n")
1134
1135 def verify_dependencies(self):
1136 for dep, depinfo in self.release_info.get("dependencies", {}).items():
1137 if "mingw" in self.release_info:
1138 mingw_matches = glob.glob(self.release_info["mingw"]["dependencies"][dep]["artifact"], root_dir=self.deps_path)
1139 assert len(mingw_matches) == 1, f"Exactly one archive matches mingw {dep} dependency: {mingw_matches}"
1140 if "dmg" in self.release_info:
1141 dmg_matches = glob.glob(self.release_info["dmg"]["dependencies"][dep]["artifact"], root_dir=self.deps_path)
1142 assert len(dmg_matches) == 1, f"Exactly one archive matches dmg {dep} dependency: {dmg_matches}"
1143 if "msvc" in self.release_info:
1144 msvc_matches = glob.glob(self.release_info["msvc"]["dependencies"][dep]["artifact"], root_dir=self.deps_path)
1145 assert len(msvc_matches) == 1, f"Exactly one archive matches msvc {dep} dependency: {msvc_matches}"
1146 if "android" in self.release_info:
1147 android_matches = glob.glob(self.release_info["android"]["dependencies"][dep]["artifact"], root_dir=self.deps_path)
1148 assert len(android_matches) == 1, f"Exactly one archive matches msvc {dep} dependency: {android_matches}"
1149
1150 @staticmethod
1151 def _arch_to_vs_platform(arch: str, configuration: str="Release") -> VsArchPlatformConfig:
1152 ARCH_TO_VS_PLATFORM = {
1153 "x86": VsArchPlatformConfig(arch="x86", platform="Win32", configuration=configuration),
1154 "x64": VsArchPlatformConfig(arch="x64", platform="x64", configuration=configuration),
1155 "arm64": VsArchPlatformConfig(arch="arm64", platform="ARM64", configuration=configuration),
1156 }
1157 return ARCH_TO_VS_PLATFORM[arch]
1158
1159 def build_msvc(self):
1160 with self.section_printer.group("Find Visual Studio"):
1161 vs = VisualStudio(executer=self.executer)
1162 for arch in self.release_info["msvc"].get("msbuild", {}).get("archs", []):
1163 self._build_msvc_msbuild(arch_platform=self._arch_to_vs_platform(arch=arch), vs=vs)
1164 if "cmake" in self.release_info["msvc"]:
1165 deps_path = self.root / "msvc-deps"
1166 shutil.rmtree(deps_path, ignore_errors=True)
1167 dep_roots = []
1168 for dep, depinfo in self.release_info["msvc"].get("dependencies", {}).items():
1169 dep_extract_path = deps_path / f"extract-{dep}"
1170 msvc_zip = self.deps_path / glob.glob(depinfo["artifact"], root_dir=self.deps_path)[0]
1171 with zipfile.ZipFile(msvc_zip, "r") as zf:
1172 zf.extractall(dep_extract_path)
1173 contents_msvc_zip = glob.glob(str(dep_extract_path / "*"))
1174 assert len(contents_msvc_zip) == 1, f"There must be exactly one root item in the root directory of {dep}"
1175 dep_roots.append(contents_msvc_zip[0])
1176
1177 for arch in self.release_info["msvc"].get("cmake", {}).get("archs", []):
1178 self._build_msvc_cmake(arch_platform=self._arch_to_vs_platform(arch=arch), dep_roots=dep_roots)
1179 with self.section_printer.group("Create SDL VC development zip"):
1180 self._build_msvc_devel()
1181
1182 def _build_msvc_msbuild(self, arch_platform: VsArchPlatformConfig, vs: VisualStudio):
1183 platform_context = self.get_context(arch_platform.extra_context())
1184 for dep, depinfo in self.release_info["msvc"].get("dependencies", {}).items():
1185 msvc_zip = self.deps_path / glob.glob(depinfo["artifact"], root_dir=self.deps_path)[0]
1186
1187 src_globs = [configure_text(instr["src"], context=platform_context) for instr in depinfo["copy"]]
1188 with zipfile.ZipFile(msvc_zip, "r") as zf:
1189 for member in zf.namelist():
1190 member_path = "/".join(Path(member).parts[1:])
1191 for src_i, src_glob in enumerate(src_globs):
1192 if fnmatch.fnmatch(member_path, src_glob):
1193 dst = (self.root / configure_text(depinfo["copy"][src_i]["dst"], context=platform_context)).resolve() / Path(member_path).name
1194 zip_data = zf.read(member)
1195 if dst.exists():
1196 identical = False
1197 if dst.is_file():
1198 orig_bytes = dst.read_bytes()
1199 if orig_bytes == zip_data:
1200 identical = True
1201 if not identical:
1202 logger.warning("Extracting dependency %s, will cause %s to be overwritten", dep, dst)
1203 if not self.overwrite:
1204 raise RuntimeError("Run with --overwrite to allow overwriting")
1205 logger.debug("Extracting %s -> %s", member, dst)
1206
1207 dst.parent.mkdir(exist_ok=True, parents=True)
1208 dst.write_bytes(zip_data)
1209
1210 prebuilt_paths = set(self.root / full_prebuilt_path for prebuilt_path in self.release_info["msvc"]["msbuild"].get("prebuilt", []) for full_prebuilt_path in glob.glob(configure_text(prebuilt_path, context=platform_context), root_dir=self.root))
1211 msbuild_paths = set(self.root / configure_text(f, context=platform_context) for file_mapping in (self.release_info["msvc"]["msbuild"]["files-lib"], self.release_info["msvc"]["msbuild"]["files-devel"]) for files_list in file_mapping.values() for f in files_list)
1212 assert prebuilt_paths.issubset(msbuild_paths), f"msvc.msbuild.prebuilt must be a subset of (msvc.msbuild.files-lib, msvc.msbuild.files-devel)"
1213 built_paths = msbuild_paths.difference(prebuilt_paths)
1214 logger.info("MSbuild builds these files, to be included in the package: %s", built_paths)
1215 if not self.fast:
1216 for b in built_paths:
1217 b.unlink(missing_ok=True)
1218
1219 rel_projects: list[str] = self.release_info["msvc"]["msbuild"]["projects"]
1220 projects = list(self.root / p for p in rel_projects)
1221
1222 directory_build_props_src_relpath = self.release_info["msvc"]["msbuild"].get("directory-build-props")
1223 for project in projects:
1224 dir_b_props = project.parent / "Directory.Build.props"
1225 dir_b_props.unlink(missing_ok = True)
1226 if directory_build_props_src_relpath:
1227 src = self.root / directory_build_props_src_relpath
1228 logger.debug("Copying %s -> %s", src, dir_b_props)
1229 shutil.copy(src=src, dst=dir_b_props)
1230
1231 with self.section_printer.group(f"Build {arch_platform.arch} VS binary"):
1232 vs.build(arch_platform=arch_platform, projects=projects)
1233
1234 if self.dry:
1235 for b in built_paths:
1236 b.parent.mkdir(parents=True, exist_ok=True)
1237 b.touch()
1238
1239 for b in built_paths:
1240 assert b.is_file(), f"{b} has not been created"
1241 b.parent.mkdir(parents=True, exist_ok=True)
1242 b.touch()
1243
1244 zip_path = self.dist_path / f"{self.project}-{self.version}-win32-{arch_platform.arch}.zip"
1245 zip_path.unlink(missing_ok=True)
1246
1247 logger.info("Collecting files...")
1248 archive_file_tree = ArchiveFileTree()
1249 archive_file_tree.add_file_mapping(arc_dir="", file_mapping=self.release_info["msvc"]["msbuild"]["files-lib"], file_mapping_root=self.root, context=platform_context, time=self.arc_time)
1250 archive_file_tree.add_file_mapping(arc_dir="", file_mapping=self.release_info["msvc"]["files-lib"], file_mapping_root=self.root, context=platform_context, time=self.arc_time)
1251
1252 logger.info("Writing to %s", zip_path)
1253 with Archiver(zip_path=zip_path) as archiver:
1254 arc_root = f""
1255 archive_file_tree.add_to_archiver(archive_base=arc_root, archiver=archiver)
1256 archiver.add_git_hash(arcdir=arc_root, commit=self.commit, time=self.arc_time)
1257 self.artifacts[f"VC-{arch_platform.arch}"] = zip_path
1258
1259 for p in built_paths:
1260 assert p.is_file(), f"{p} should exist"
1261
1262 def _arch_platform_to_build_path(self, arch_platform: VsArchPlatformConfig) -> Path:
1263 return self.root / f"build-vs-{arch_platform.arch}"
1264
1265 def _arch_platform_to_install_path(self, arch_platform: VsArchPlatformConfig) -> Path:
1266 return self._arch_platform_to_build_path(arch_platform) / "prefix"
1267
1268 def _build_msvc_cmake(self, arch_platform: VsArchPlatformConfig, dep_roots: list[Path]):
1269 build_path = self._arch_platform_to_build_path(arch_platform)
1270 install_path = self._arch_platform_to_install_path(arch_platform)
1271 platform_context = self.get_context(extra_context=arch_platform.extra_context())
1272
1273 build_type = "Release"
1274 extra_context = {
1275 "ARCH": arch_platform.arch,
1276 "PLATFORM": arch_platform.platform,
1277 }
1278
1279 built_paths = set(install_path / configure_text(f, context=platform_context) for file_mapping in (self.release_info["msvc"]["cmake"]["files-lib"], self.release_info["msvc"]["cmake"]["files-devel"]) for files_list in file_mapping.values() for f in files_list)
1280 logger.info("CMake builds these files, to be included in the package: %s", built_paths)
1281 if not self.fast:
1282 for b in built_paths:
1283 b.unlink(missing_ok=True)
1284
1285 shutil.rmtree(install_path, ignore_errors=True)
1286 build_path.mkdir(parents=True, exist_ok=True)
1287 with self.section_printer.group(f"Configure VC CMake project for {arch_platform.arch}"):
1288 self.executer.run([
1289 "cmake", "-S", str(self.root), "-B", str(build_path),
1290 "-A", arch_platform.platform,
1291 "-DCMAKE_INSTALL_BINDIR=bin",
1292 "-DCMAKE_INSTALL_DATAROOTDIR=share",
1293 "-DCMAKE_INSTALL_INCLUDEDIR=include",
1294 "-DCMAKE_INSTALL_LIBDIR=lib",
1295 f"-DCMAKE_BUILD_TYPE={build_type}",
1296 f"-DCMAKE_INSTALL_PREFIX={install_path}",
1297 # MSVC debug information format flags are selected by an abstraction
1298 "-DCMAKE_POLICY_DEFAULT_CMP0141=NEW",
1299 # MSVC debug information format
1300 "-DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=ProgramDatabase",
1301 # Linker flags for executables
1302 "-DCMAKE_EXE_LINKER_FLAGS=-INCREMENTAL:NO -DEBUG -OPT:REF -OPT:ICF",
1303 # Linker flag for shared libraries
1304 "-DCMAKE_SHARED_LINKER_FLAGS=-INCREMENTAL:NO -DEBUG -OPT:REF -OPT:ICF",
1305 # MSVC runtime library flags are selected by an abstraction
1306 "-DCMAKE_POLICY_DEFAULT_CMP0091=NEW",
1307 # Use statically linked runtime (-MT) (ideally, should be "MultiThreaded$<$<CONFIG:Debug>:Debug>")
1308 "-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded",
1309 f"-DCMAKE_PREFIX_PATH={';'.join(str(s) for s in dep_roots)}",
1310 ] + self.release_info["msvc"]["cmake"]["args"] + ([] if self.fast else ["--fresh"]))
1311
1312 with self.section_printer.group(f"Build VC CMake project for {arch_platform.arch}"):
1313 self.executer.run(["cmake", "--build", str(build_path), "--verbose", "--config", build_type])
1314 with self.section_printer.group(f"Install VC CMake project for {arch_platform.arch}"):
1315 self.executer.run(["cmake", "--install", str(build_path), "--config", build_type])
1316
1317 if self.dry:
1318 for b in built_paths:
1319 b.parent.mkdir(parents=True, exist_ok=True)
1320 b.touch()
1321
1322 zip_path = self.dist_path / f"{self.project}-{self.version}-win32-{arch_platform.arch}.zip"
1323 zip_path.unlink(missing_ok=True)
1324
1325 logger.info("Collecting files...")
1326 archive_file_tree = ArchiveFileTree()
1327 archive_file_tree.add_file_mapping(arc_dir="", file_mapping=self.release_info["msvc"]["cmake"]["files-lib"], file_mapping_root=install_path, context=platform_context, time=self.arc_time)
1328 archive_file_tree.add_file_mapping(arc_dir="", file_mapping=self.release_info["msvc"]["files-lib"], file_mapping_root=self.root, context=self.get_context(extra_context=extra_context), time=self.arc_time)
1329
1330 logger.info("Creating %s", zip_path)
1331 with Archiver(zip_path=zip_path) as archiver:
1332 arc_root = f""
1333 archive_file_tree.add_to_archiver(archive_base=arc_root, archiver=archiver)
1334 archiver.add_git_hash(arcdir=arc_root, commit=self.commit, time=self.arc_time)
1335
1336 for p in built_paths:
1337 assert p.is_file(), f"{p} should exist"
1338
1339 def _build_msvc_devel(self) -> None:
1340 zip_path = self.dist_path / f"{self.project}-devel-{self.version}-VC.zip"
1341 arc_root = f"{self.project}-{self.version}"
1342
1343 def copy_files_devel(ctx):
1344 archive_file_tree.add_file_mapping(arc_dir=arc_root, file_mapping=self.release_info["msvc"]["files-devel"], file_mapping_root=self.root, context=ctx, time=self.arc_time)
1345
1346
1347 logger.info("Collecting files...")
1348 archive_file_tree = ArchiveFileTree()
1349 if "msbuild" in self.release_info["msvc"]:
1350 for arch in self.release_info["msvc"]["msbuild"]["archs"]:
1351 arch_platform = self._arch_to_vs_platform(arch=arch)
1352 platform_context = self.get_context(arch_platform.extra_context())
1353 archive_file_tree.add_file_mapping(arc_dir=arc_root, file_mapping=self.release_info["msvc"]["msbuild"]["files-devel"], file_mapping_root=self.root, context=platform_context, time=self.arc_time)
1354 copy_files_devel(ctx=platform_context)
1355 if "cmake" in self.release_info["msvc"]:
1356 for arch in self.release_info["msvc"]["cmake"]["archs"]:
1357 arch_platform = self._arch_to_vs_platform(arch=arch)
1358 platform_context = self.get_context(arch_platform.extra_context())
1359 archive_file_tree.add_file_mapping(arc_dir=arc_root, file_mapping=self.release_info["msvc"]["cmake"]["files-devel"], file_mapping_root=self._arch_platform_to_install_path(arch_platform), context=platform_context, time=self.arc_time)
1360 copy_files_devel(ctx=platform_context)
1361
1362 with Archiver(zip_path=zip_path) as archiver:
1363 archive_file_tree.add_to_archiver(archive_base="", archiver=archiver)
1364 archiver.add_git_hash(arcdir=arc_root, commit=self.commit, time=self.arc_time)
1365 self.artifacts["VC-devel"] = zip_path
1366
1367 @classmethod
1368 def extract_sdl_version(cls, root: Path, release_info: dict) -> str:
1369 with open(root / release_info["version"]["file"], "r") as f:
1370 text = f.read()
1371 major = next(re.finditer(release_info["version"]["re_major"], text, flags=re.M)).group(1)
1372 minor = next(re.finditer(release_info["version"]["re_minor"], text, flags=re.M)).group(1)
1373 micro = next(re.finditer(release_info["version"]["re_micro"], text, flags=re.M)).group(1)
1374 return f"{major}.{minor}.{micro}"
1375
1376
1377def main(argv=None) -> int:
1378 if sys.version_info < (3, 11):
1379 logger.error("This script needs at least python 3.11")
1380 return 1
1381
1382 parser = argparse.ArgumentParser(allow_abbrev=False, description="Create SDL release artifacts")
1383 parser.add_argument("--root", metavar="DIR", type=Path, default=Path(__file__).absolute().parents[1], help="Root of project")
1384 parser.add_argument("--release-info", metavar="JSON", dest="path_release_info", type=Path, default=Path(__file__).absolute().parent / "release-info.json", help="Path of release-info.json")
1385 parser.add_argument("--dependency-folder", metavar="FOLDER", dest="deps_path", type=Path, default="deps", help="Directory containing pre-built archives of dependencies (will be removed when downloading archives)")
1386 parser.add_argument("--out", "-o", metavar="DIR", dest="dist_path", type=Path, default="dist", help="Output directory")
1387 parser.add_argument("--github", action="store_true", help="Script is running on a GitHub runner")
1388 parser.add_argument("--commit", default="HEAD", help="Git commit/tag of which a release should be created")
1389 parser.add_argument("--actions", choices=["download", "source", "android", "mingw", "msvc", "dmg"], required=True, nargs="+", dest="actions", help="What to do?")
1390 parser.set_defaults(loglevel=logging.INFO)
1391 parser.add_argument('--vs-year', dest="vs_year", help="Visual Studio year")
1392 parser.add_argument('--android-api', dest="android_api", help="Android API version")
1393 parser.add_argument('--android-home', dest="android_home", default=os.environ.get("ANDROID_HOME"), help="Android Home folder")
1394 parser.add_argument('--android-ndk-home', dest="android_ndk_home", default=os.environ.get("ANDROID_NDK_HOME"), help="Android NDK Home folder")
1395 parser.add_argument('--cmake-generator', dest="cmake_generator", default="Ninja", help="CMake Generator")
1396 parser.add_argument('--debug', action='store_const', const=logging.DEBUG, dest="loglevel", help="Print script debug information")
1397 parser.add_argument('--dry-run', action='store_true', dest="dry", help="Don't execute anything")
1398 parser.add_argument('--force', action='store_true', dest="force", help="Ignore a non-clean git tree")
1399 parser.add_argument('--overwrite', action='store_true', dest="overwrite", help="Allow potentially overwriting other projects")
1400 parser.add_argument('--fast', action='store_true', dest="fast", help="Don't do a rebuild")
1401
1402 args = parser.parse_args(argv)
1403 logging.basicConfig(level=args.loglevel, format='[%(levelname)s] %(message)s')
1404 args.deps_path = args.deps_path.absolute()
1405 args.dist_path = args.dist_path.absolute()
1406 args.root = args.root.absolute()
1407 args.dist_path = args.dist_path.absolute()
1408 if args.dry:
1409 args.dist_path = args.dist_path / "dry"
1410
1411 if args.github:
1412 section_printer: SectionPrinter = GitHubSectionPrinter()
1413 else:
1414 section_printer = SectionPrinter()
1415
1416 if args.github and "GITHUB_OUTPUT" not in os.environ:
1417 os.environ["GITHUB_OUTPUT"] = "/tmp/github_output.txt"
1418
1419 executer = Executer(root=args.root, dry=args.dry)
1420
1421 root_git_hash_path = args.root / GIT_HASH_FILENAME
1422 root_is_maybe_archive = root_git_hash_path.is_file()
1423 if root_is_maybe_archive:
1424 logger.warning("%s detected: Building from archive", GIT_HASH_FILENAME)
1425 archive_commit = root_git_hash_path.read_text().strip()
1426 if args.commit != archive_commit:
1427 logger.warning("Commit argument is %s, but archive commit is %s. Using %s.", args.commit, archive_commit, archive_commit)
1428 args.commit = archive_commit
1429 revision = (args.root / REVISION_TXT).read_text().strip()
1430 else:
1431 args.commit = executer.check_output(["git", "rev-parse", args.commit], dry_out="e5812a9fd2cda317b503325a702ba3c1c37861d9").strip()
1432 revision = executer.check_output(["git", "describe", "--always", "--tags", "--long", args.commit], dry_out="preview-3.1.3-96-g9512f2144").strip()
1433 logger.info("Using commit %s", args.commit)
1434
1435 try:
1436 with args.path_release_info.open() as f:
1437 release_info = json.load(f)
1438 except FileNotFoundError:
1439 logger.error(f"Could not find {args.path_release_info}")
1440
1441 releaser = Releaser(
1442 release_info=release_info,
1443 commit=args.commit,
1444 revision=revision,
1445 root=args.root,
1446 dist_path=args.dist_path,
1447 executer=executer,
1448 section_printer=section_printer,
1449 cmake_generator=args.cmake_generator,
1450 deps_path=args.deps_path,
1451 overwrite=args.overwrite,
1452 github=args.github,
1453 fast=args.fast,
1454 )
1455
1456 if root_is_maybe_archive:
1457 logger.warning("Building from archive. Skipping clean git tree check.")
1458 else:
1459 porcelain_status = executer.check_output(["git", "status", "--ignored", "--porcelain"], dry_out="\n").strip()
1460 if porcelain_status:
1461 print(porcelain_status)
1462 logger.warning("The tree is dirty! Do not publish any generated artifacts!")
1463 if not args.force:
1464 raise Exception("The git repo contains modified and/or non-committed files. Run with --force to ignore.")
1465
1466 if args.fast:
1467 logger.warning("Doing fast build! Do not publish generated artifacts!")
1468
1469 with section_printer.group("Arguments"):
1470 print(f"project = {releaser.project}")
1471 print(f"version = {releaser.version}")
1472 print(f"revision = {revision}")
1473 print(f"commit = {args.commit}")
1474 print(f"out = {args.dist_path}")
1475 print(f"actions = {args.actions}")
1476 print(f"dry = {args.dry}")
1477 print(f"force = {args.force}")
1478 print(f"overwrite = {args.overwrite}")
1479 print(f"cmake_generator = {args.cmake_generator}")
1480
1481 releaser.prepare()
1482
1483 if "download" in args.actions:
1484 releaser.download_dependencies()
1485
1486 if set(args.actions).intersection({"msvc", "mingw", "android"}):
1487 print("Verifying presence of dependencies (run 'download' action to download) ...")
1488 releaser.verify_dependencies()
1489 print("... done")
1490
1491 if "source" in args.actions:
1492 if root_is_maybe_archive:
1493 raise Exception("Cannot build source archive from source archive")
1494 with section_printer.group("Create source archives"):
1495 releaser.create_source_archives()
1496
1497 if "dmg" in args.actions:
1498 if platform.system() != "Darwin" and not args.dry:
1499 parser.error("framework artifact(s) can only be built on Darwin")
1500
1501 releaser.create_dmg()
1502
1503 if "msvc" in args.actions:
1504 if platform.system() != "Windows" and not args.dry:
1505 parser.error("msvc artifact(s) can only be built on Windows")
1506 releaser.build_msvc()
1507
1508 if "mingw" in args.actions:
1509 releaser.create_mingw_archives()
1510
1511 if "android" in args.actions:
1512 if args.android_home is None or not Path(args.android_home).is_dir():
1513 parser.error("Invalid $ANDROID_HOME or --android-home: must be a directory containing the Android SDK")
1514 if args.android_ndk_home is None or not Path(args.android_ndk_home).is_dir():
1515 parser.error("Invalid $ANDROID_NDK_HOME or --android_ndk_home: must be a directory containing the Android NDK")
1516 if args.android_api is None:
1517 with section_printer.group("Detect Android APIS"):
1518 args.android_api = releaser._detect_android_api(android_home=args.android_home)
1519 else:
1520 try:
1521 android_api_ints = tuple(int(v) for v in args.android_api.split("."))
1522 match len(android_api_ints):
1523 case 1: android_api_name = f"android-{android_api_ints[0]}"
1524 case 2: android_api_name = f"android-{android_api_ints[0]}-ext-{android_api_ints[1]}"
1525 case _: raise ValueError
1526 except ValueError:
1527 logger.error("Invalid --android-api, must be a 'X' or 'X.Y' version")
1528 args.android_api = AndroidApiVersion(ints=android_api_ints, name=android_api_name)
1529 if args.android_api is None:
1530 parser.error("Invalid --android-api, and/or could not be detected")
1531 android_api_path = Path(args.android_home) / f"platforms/{args.android_api.name}"
1532 if not android_api_path.is_dir():
1533 parser.error(f"Android API directory does not exist ({android_api_path})")
1534 with section_printer.group("Android arguments"):
1535 print(f"android_home = {args.android_home}")
1536 print(f"android_ndk_home = {args.android_ndk_home}")
1537 print(f"android_api = {args.android_api}")
1538 releaser.create_android_archives(
1539 android_api=args.android_api.ints[0],
1540 android_home=args.android_home,
1541 android_ndk_home=args.android_ndk_home,
1542 )
1543 with section_printer.group("Summary"):
1544 print(f"artifacts = {releaser.artifacts}")
1545
1546 if args.github:
1547 with open(os.environ["GITHUB_OUTPUT"], "a") as f:
1548 f.write(f"project={releaser.project}\n")
1549 f.write(f"version={releaser.version}\n")
1550 for k, v in releaser.artifacts.items():
1551 f.write(f"{k}={v.name}\n")
1552 return 0
1553
1554
1555if __name__ == "__main__":
1556 raise SystemExit(main())
diff --git a/src/contrib/SDL-3.2.20/build-scripts/build-web-examples.pl b/src/contrib/SDL-3.2.20/build-scripts/build-web-examples.pl
new file mode 100755
index 0000000..c255ea3
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/build-web-examples.pl
@@ -0,0 +1,420 @@
1#!/usr/bin/perl -w
2
3# Simple DirectMedia Layer
4# Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
5#
6# This software is provided 'as-is', without any express or implied
7# warranty. In no event will the authors be held liable for any damages
8# arising from the use of this software.
9#
10# Permission is granted to anyone to use this software for any purpose,
11# including commercial applications, and to alter it and redistribute it
12# freely, subject to the following restrictions:
13#
14# 1. The origin of this software must not be misrepresented; you must not
15# claim that you wrote the original software. If you use this software
16# in a product, an acknowledgment in the product documentation would be
17# appreciated but is not required.
18# 2. Altered source versions must be plainly marked as such, and must not be
19# misrepresented as being the original software.
20# 3. This notice may not be removed or altered from any source distribution.
21
22use warnings;
23use strict;
24use File::Basename;
25use File::Copy;
26use Cwd qw(abs_path);
27use IPC::Open2;
28
29my $examples_dir = abs_path(dirname(__FILE__) . "/../examples");
30my $project = undef;
31my $emsdk_dir = undef;
32my $compile_dir = undef;
33my $cmake_flags = undef;
34my $output_dir = undef;
35
36sub usage {
37 die("USAGE: $0 <project_name> <emsdk_dir> <compiler_output_directory> <cmake_flags> <html_output_directory>\n\n");
38}
39
40sub do_system {
41 my $cmd = shift;
42 $cmd = "exec /bin/bash -c \"$cmd\"";
43 print("$cmd\n");
44 return system($cmd);
45}
46
47sub do_mkdir {
48 my $d = shift;
49 if ( ! -d $d ) {
50 print("mkdir '$d'\n");
51 mkdir($d) or die("Couldn't mkdir('$d'): $!\n");
52 }
53}
54
55sub do_copy {
56 my $src = shift;
57 my $dst = shift;
58 print("cp '$src' '$dst'\n");
59 copy($src, $dst) or die("Failed to copy '$src' to '$dst': $!\n");
60}
61
62sub build_latest {
63 # Try to build just the latest without re-running cmake, since that is SLOW.
64 print("Building latest version of $project ...\n");
65 if (do_system("EMSDK_QUIET=1 source '$emsdk_dir/emsdk_env.sh' && cd '$compile_dir' && ninja") != 0) {
66 # Build failed? Try nuking the build dir and running CMake from scratch.
67 print("\n\nBuilding latest version of $project FROM SCRATCH ...\n");
68 if (do_system("EMSDK_QUIET=1 source '$emsdk_dir/emsdk_env.sh' && rm -rf '$compile_dir' && mkdir '$compile_dir' && cd '$compile_dir' && emcmake cmake -G Ninja -DCMAKE_BUILD_TYPE=MinSizeRel $cmake_flags '$examples_dir/..' && ninja") != 0) {
69 die("Failed to build latest version of $project!\n"); # oh well.
70 }
71 }
72}
73
74sub get_category_description {
75 my $category = shift;
76 my $retval = ucfirst($category);
77
78 if (open(my $fh, '<', "$examples_dir/$category/description.txt")) {
79 $retval = <$fh>;
80 chomp($retval);
81 close($fh);
82 }
83
84 return $retval;
85}
86
87sub get_categories {
88 my @categories = ();
89
90 if (open(my $fh, '<', "$examples_dir/categories.txt")) {
91 while (<$fh>) {
92 chomp;
93 s/\A\s+//;
94 s/\s+\Z//;
95 next if $_ eq '';
96 next if /\A\#/;
97 push @categories, $_;
98 }
99 close($fh);
100 } else {
101 opendir(my $dh, $examples_dir) or die("Couldn't opendir '$examples_dir': $!\n");
102 foreach my $dir (sort readdir $dh) {
103 next if ($dir eq '.') || ($dir eq '..'); # obviously skip current and parent entries.
104 next if not -d "$examples_dir/$dir"; # only care about subdirectories.
105 push @categories, $dir;
106 }
107 closedir($dh);
108 }
109
110 return @categories;
111}
112
113sub get_examples_for_category {
114 my $category = shift;
115
116 my @examples = ();
117
118 opendir(my $dh, "$examples_dir/$category") or die("Couldn't opendir '$examples_dir/$category': $!\n");
119 foreach my $dir (sort readdir $dh) {
120 next if ($dir eq '.') || ($dir eq '..'); # obviously skip current and parent entries.
121 next if not -d "$examples_dir/$category/$dir"; # only care about subdirectories.
122
123 push @examples, $dir;
124 }
125 closedir($dh);
126
127 return @examples;
128}
129
130sub handle_example_dir {
131 my $category = shift;
132 my $example = shift;
133
134 my @files = ();
135 my $files_str = '';
136 opendir(my $dh, "$examples_dir/$category/$example") or die("Couldn't opendir '$examples_dir/$category/$example': $!\n");
137 my $spc = '';
138 while (readdir($dh)) {
139 my $path = "$examples_dir/$category/$example/$_";
140 next if not -f $path; # only care about files.
141 push @files, $path if /\.[ch]\Z/; # add .c and .h files to source code.
142 if (/\.c\Z/) { # only care about .c files for compiling.
143 $files_str .= "$spc$path";
144 $spc = ' ';
145 }
146 }
147 closedir($dh);
148
149 my $dst = "$output_dir/$category/$example";
150
151 print("Building $category/$example ...\n");
152
153 my $basefname = "$example";
154 $basefname =~ s/\A\d+\-//;
155 $basefname = "$category-$basefname";
156 my $jsfname = "$basefname.js";
157 my $wasmfname = "$basefname.wasm";
158 my $thumbnailfname = 'thumbnail.png';
159 my $onmouseoverfname = 'onmouseover.webp';
160 my $jssrc = "$compile_dir/examples/$jsfname";
161 my $wasmsrc = "$compile_dir/examples/$wasmfname";
162 my $thumbnailsrc = "$examples_dir/$category/$example/$thumbnailfname";
163 my $onmouseoversrc = "$examples_dir/$category/$example/$onmouseoverfname";
164 my $jsdst = "$dst/$jsfname";
165 my $wasmdst = "$dst/$wasmfname";
166 my $thumbnaildst = "$dst/$thumbnailfname";
167 my $onmouseoverdst = "$dst/$onmouseoverfname";
168
169 my $description = '';
170 my $has_paragraph = 0;
171 if (open(my $readmetxth, '<', "$examples_dir/$category/$example/README.txt")) {
172 while (<$readmetxth>) {
173 chomp;
174 s/\A\s+//;
175 s/\s+\Z//;
176 if (($_ eq '') && ($description ne '')) {
177 $has_paragraph = 1;
178 } else {
179 if ($has_paragraph) {
180 $description .= "\n<br/>\n<br/>\n";
181 $has_paragraph = 0;
182 }
183 $description .= "$_ ";
184 }
185 }
186 close($readmetxth);
187 $description =~ s/\s+\Z//;
188 }
189
190 do_mkdir($dst);
191 do_copy($jssrc, $jsdst);
192 do_copy($wasmsrc, $wasmdst);
193 do_copy($thumbnailsrc, $thumbnaildst) if ( -f $thumbnailsrc );
194 do_copy($onmouseoversrc, $onmouseoverdst) if ( -f $onmouseoversrc );
195
196 my $highlight_cmd = "highlight '--outdir=$dst' --style-outfile=highlight.css --fragment --enclose-pre --stdout --syntax=c '--plug-in=$examples_dir/highlight-plugin.lua'";
197 print("$highlight_cmd\n");
198 my $pid = open2(my $child_out, my $child_in, $highlight_cmd);
199
200 my $htmlified_source_code = '';
201 foreach (sort(@files)) {
202 my $path = $_;
203 open my $srccode, '<', $path or die("Couldn't open '$path': $!\n");
204 my $fname = "$path";
205 $fname =~ s/\A.*\///;
206 print $child_in "/* $fname ... */\n\n";
207 while (<$srccode>) {
208 print $child_in $_;
209 }
210 print $child_in "\n\n\n";
211 close($srccode);
212 }
213
214 close($child_in);
215
216 while (<$child_out>) {
217 $htmlified_source_code .= $_;
218 }
219 close($child_out);
220
221 waitpid($pid, 0);
222
223 my $other_examples_html = "<ul>";
224 foreach my $example (get_examples_for_category($category)) {
225 $other_examples_html .= "<li><a href='/$project/$category/$example'>$category/$example</a></li>";
226 }
227 $other_examples_html .= "</ul>";
228
229 my $category_description = get_category_description($category);
230 my $preview_image = get_example_thumbnail($project, $category, $example);
231
232 my $html = '';
233 open my $htmltemplate, '<', "$examples_dir/template.html" or die("Couldn't open '$examples_dir/template.html': $!\n");
234 while (<$htmltemplate>) {
235 s/\@project_name\@/$project/g;
236 s/\@category_name\@/$category/g;
237 s/\@category_description\@/$category_description/g;
238 s/\@example_name\@/$example/g;
239 s/\@javascript_file\@/$jsfname/g;
240 s/\@htmlified_source_code\@/$htmlified_source_code/g;
241 s/\@description\@/$description/g;
242 s/\@preview_image\@/$preview_image/g;
243 s/\@other_examples_html\@/$other_examples_html/g;
244 $html .= $_;
245 }
246 close($htmltemplate);
247
248 open my $htmloutput, '>', "$dst/index.html" or die("Couldn't open '$dst/index.html': $!\n");
249 print $htmloutput $html;
250 close($htmloutput);
251}
252
253sub get_example_thumbnail {
254 my $project = shift;
255 my $category = shift;
256 my $example = shift;
257
258 if ( -f "$examples_dir/$category/$example/thumbnail.png" ) {
259 return "/$project/$category/$example/thumbnail.png";
260 } elsif ( -f "$examples_dir/$category/thumbnail.png" ) {
261 return "/$project/$category/thumbnail.png";
262 }
263
264 return "/$project/thumbnail.png";
265}
266
267sub generate_example_thumbnail {
268 my $project = shift;
269 my $category = shift;
270 my $example = shift;
271
272 my $example_no_num = "$example";
273 $example_no_num =~ s/\A\d+\-//;
274
275 my $example_image_url = get_example_thumbnail($project, $category, $example);
276
277 my $example_mouseover_html = '';
278 if ( -f "$examples_dir/$category/$example/onmouseover.webp" ) {
279 $example_mouseover_html = "onmouseover=\"this.src='/$project/$category/$example/onmouseover.webp'\" onmouseout=\"this.src='$example_image_url';\"";
280 } elsif ( -f "$examples_dir/$category/onmouseover.webp" ) {
281 $example_mouseover_html = "onmouseover=\"this.src='/$project/$category/onmouseover.webp'\" onmouseout=\"this.src='$example_image_url';\"";
282 }
283
284 return "
285 <a href='/$project/$category/$example'>
286 <div>
287 <img src='$example_image_url' $example_mouseover_html />
288 <div>$example_no_num</div>
289 </div>
290 </a>"
291 ;
292}
293
294sub generate_example_thumbnails_for_category {
295 my $project = shift;
296 my $category = shift;
297 my @examples = get_examples_for_category($category);
298 my $retval = '';
299 foreach my $example (@examples) {
300 $retval .= generate_example_thumbnail($project, $category, $example);
301 }
302 return $retval;
303}
304
305sub handle_category_dir {
306 my $category = shift;
307
308 print("Category $category ...\n");
309
310 do_mkdir("$output_dir/$category");
311
312 opendir(my $dh, "$examples_dir/$category") or die("Couldn't opendir '$examples_dir/$category': $!\n");
313
314 while (readdir($dh)) {
315 next if ($_ eq '.') || ($_ eq '..'); # obviously skip current and parent entries.
316 next if not -d "$examples_dir/$category/$_"; # only care about subdirectories.
317 handle_example_dir($category, $_);
318 }
319
320 closedir($dh);
321
322 my $examples_list_html = generate_example_thumbnails_for_category($project, $category);
323
324 my $dst = "$output_dir/$category";
325
326 do_copy("$examples_dir/$category/thumbnail.png", "$dst/thumbnail.png") if ( -f "$examples_dir/$category/thumbnail.png" );
327 do_copy("$examples_dir/$category/onmouseover.webp", "$dst/onmouseover.webp") if ( -f "$examples_dir/$category/onmouseover.webp" );
328
329 my $category_description = get_category_description($category);
330 my $preview_image = "/$project/thumbnail.png";
331 if ( -f "$examples_dir/$category/thumbnail.png" ) {
332 $preview_image = "/$project/$category/thumbnail.png";
333 }
334
335 # write category page
336 my $html = '';
337 open my $htmltemplate, '<', "$examples_dir/template-category.html" or die("Couldn't open '$examples_dir/template-category.html': $!\n");
338 while (<$htmltemplate>) {
339 s/\@project_name\@/$project/g;
340 s/\@category_name\@/$category/g;
341 s/\@category_description\@/$category_description/g;
342 s/\@examples_list_html\@/$examples_list_html/g;
343 s/\@preview_image\@/$preview_image/g;
344 $html .= $_;
345 }
346 close($htmltemplate);
347
348 open my $htmloutput, '>', "$dst/index.html" or die("Couldn't open '$dst/index.html': $!\n");
349 print $htmloutput $html;
350 close($htmloutput);
351}
352
353
354# Mainline!
355
356foreach (@ARGV) {
357 $project = $_, next if not defined $project;
358 $emsdk_dir = $_, next if not defined $emsdk_dir;
359 $compile_dir = $_, next if not defined $compile_dir;
360 $cmake_flags = $_, next if not defined $cmake_flags;
361 $output_dir = $_, next if not defined $output_dir;
362 usage(); # too many arguments.
363}
364
365usage() if not defined $output_dir;
366
367print("Examples dir: $examples_dir\n");
368print("emsdk dir: $emsdk_dir\n");
369print("Compile dir: $compile_dir\n");
370print("CMake flags: $cmake_flags\n");
371print("Output dir: $output_dir\n");
372
373do_system("rm -rf '$output_dir'");
374do_mkdir($output_dir);
375
376build_latest();
377
378do_copy("$examples_dir/template.css", "$output_dir/examples.css");
379do_copy("$examples_dir/template-placeholder.png", "$output_dir/thumbnail.png");
380
381opendir(my $dh, $examples_dir) or die("Couldn't opendir '$examples_dir': $!\n");
382
383while (readdir($dh)) {
384 next if ($_ eq '.') || ($_ eq '..'); # obviously skip current and parent entries.
385 next if not -d "$examples_dir/$_"; # only care about subdirectories.
386 # !!! FIXME: this needs to generate a preview page for all the categories.
387 handle_category_dir($_);
388}
389
390closedir($dh);
391
392# write homepage
393my $homepage_list_html = "";
394foreach my $category (get_categories()) {
395 my $category_description = get_category_description($category);
396 $homepage_list_html .= "<h2>$category_description</h2>";
397 $homepage_list_html .= "<div class='list'>";
398 $homepage_list_html .= generate_example_thumbnails_for_category($project, $category);
399 $homepage_list_html .= "</div>";
400}
401
402my $preview_image = "/$project/thumbnail.png";
403
404my $dst = "$output_dir/";
405my $html = '';
406open my $htmltemplate, '<', "$examples_dir/template-homepage.html" or die("Couldn't open '$examples_dir/template-category.html': $!\n");
407while (<$htmltemplate>) {
408 s/\@project_name\@/$project/g;
409 s/\@homepage_list_html\@/$homepage_list_html/g;
410 s/\@preview_image\@/$preview_image/g;
411 $html .= $_;
412}
413close($htmltemplate);
414
415open my $htmloutput, '>', "$dst/index.html" or die("Couldn't open '$dst/index.html': $!\n");
416print $htmloutput $html;
417close($htmloutput);
418
419print("All examples built successfully!\n");
420exit(0); # success!
diff --git a/src/contrib/SDL-3.2.20/build-scripts/casefolding.txt b/src/contrib/SDL-3.2.20/build-scripts/casefolding.txt
new file mode 100644
index 0000000..69c5c64
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/casefolding.txt
@@ -0,0 +1,1627 @@
1# CaseFolding-15.1.0.txt
2# Date: 2023-05-12, 21:53:10 GMT
3# © 2023 Unicode®, Inc.
4# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
5# For terms of use, see https://www.unicode.org/terms_of_use.html
6#
7# Unicode Character Database
8# For documentation, see https://www.unicode.org/reports/tr44/
9#
10# Case Folding Properties
11#
12# This file is a supplement to the UnicodeData file.
13# It provides a case folding mapping generated from the Unicode Character Database.
14# If all characters are mapped according to the full mapping below, then
15# case differences (according to UnicodeData.txt and SpecialCasing.txt)
16# are eliminated.
17#
18# The data supports both implementations that require simple case foldings
19# (where string lengths don't change), and implementations that allow full case folding
20# (where string lengths may grow). Note that where they can be supported, the
21# full case foldings are superior: for example, they allow "MASSE" and "Maße" to match.
22#
23# All code points not listed in this file map to themselves.
24#
25# NOTE: case folding does not preserve normalization formats!
26#
27# For information on case folding, including how to have case folding
28# preserve normalization formats, see Section 3.13 Default Case Algorithms in
29# The Unicode Standard.
30#
31# ================================================================================
32# Format
33# ================================================================================
34# The entries in this file are in the following machine-readable format:
35#
36# <code>; <status>; <mapping>; # <name>
37#
38# The status field is:
39# C: common case folding, common mappings shared by both simple and full mappings.
40# F: full case folding, mappings that cause strings to grow in length. Multiple characters are separated by spaces.
41# S: simple case folding, mappings to single characters where different from F.
42# T: special case for uppercase I and dotted uppercase I
43# - For non-Turkic languages, this mapping is normally not used.
44# - For Turkic languages (tr, az), this mapping can be used instead of the normal mapping for these characters.
45# Note that the Turkic mappings do not maintain canonical equivalence without additional processing.
46# See the discussions of case mapping in the Unicode Standard for more information.
47#
48# Usage:
49# A. To do a simple case folding, use the mappings with status C + S.
50# B. To do a full case folding, use the mappings with status C + F.
51#
52# The mappings with status T can be used or omitted depending on the desired case-folding
53# behavior. (The default option is to exclude them.)
54#
55# =================================================================
56
57# Property: Case_Folding
58
59# All code points not explicitly listed for Case_Folding
60# have the value C for the status field, and the code point itself for the mapping field.
61
62# =================================================================
630041; C; 0061; # LATIN CAPITAL LETTER A
640042; C; 0062; # LATIN CAPITAL LETTER B
650043; C; 0063; # LATIN CAPITAL LETTER C
660044; C; 0064; # LATIN CAPITAL LETTER D
670045; C; 0065; # LATIN CAPITAL LETTER E
680046; C; 0066; # LATIN CAPITAL LETTER F
690047; C; 0067; # LATIN CAPITAL LETTER G
700048; C; 0068; # LATIN CAPITAL LETTER H
710049; C; 0069; # LATIN CAPITAL LETTER I
720049; T; 0131; # LATIN CAPITAL LETTER I
73004A; C; 006A; # LATIN CAPITAL LETTER J
74004B; C; 006B; # LATIN CAPITAL LETTER K
75004C; C; 006C; # LATIN CAPITAL LETTER L
76004D; C; 006D; # LATIN CAPITAL LETTER M
77004E; C; 006E; # LATIN CAPITAL LETTER N
78004F; C; 006F; # LATIN CAPITAL LETTER O
790050; C; 0070; # LATIN CAPITAL LETTER P
800051; C; 0071; # LATIN CAPITAL LETTER Q
810052; C; 0072; # LATIN CAPITAL LETTER R
820053; C; 0073; # LATIN CAPITAL LETTER S
830054; C; 0074; # LATIN CAPITAL LETTER T
840055; C; 0075; # LATIN CAPITAL LETTER U
850056; C; 0076; # LATIN CAPITAL LETTER V
860057; C; 0077; # LATIN CAPITAL LETTER W
870058; C; 0078; # LATIN CAPITAL LETTER X
880059; C; 0079; # LATIN CAPITAL LETTER Y
89005A; C; 007A; # LATIN CAPITAL LETTER Z
9000B5; C; 03BC; # MICRO SIGN
9100C0; C; 00E0; # LATIN CAPITAL LETTER A WITH GRAVE
9200C1; C; 00E1; # LATIN CAPITAL LETTER A WITH ACUTE
9300C2; C; 00E2; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX
9400C3; C; 00E3; # LATIN CAPITAL LETTER A WITH TILDE
9500C4; C; 00E4; # LATIN CAPITAL LETTER A WITH DIAERESIS
9600C5; C; 00E5; # LATIN CAPITAL LETTER A WITH RING ABOVE
9700C6; C; 00E6; # LATIN CAPITAL LETTER AE
9800C7; C; 00E7; # LATIN CAPITAL LETTER C WITH CEDILLA
9900C8; C; 00E8; # LATIN CAPITAL LETTER E WITH GRAVE
10000C9; C; 00E9; # LATIN CAPITAL LETTER E WITH ACUTE
10100CA; C; 00EA; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX
10200CB; C; 00EB; # LATIN CAPITAL LETTER E WITH DIAERESIS
10300CC; C; 00EC; # LATIN CAPITAL LETTER I WITH GRAVE
10400CD; C; 00ED; # LATIN CAPITAL LETTER I WITH ACUTE
10500CE; C; 00EE; # LATIN CAPITAL LETTER I WITH CIRCUMFLEX
10600CF; C; 00EF; # LATIN CAPITAL LETTER I WITH DIAERESIS
10700D0; C; 00F0; # LATIN CAPITAL LETTER ETH
10800D1; C; 00F1; # LATIN CAPITAL LETTER N WITH TILDE
10900D2; C; 00F2; # LATIN CAPITAL LETTER O WITH GRAVE
11000D3; C; 00F3; # LATIN CAPITAL LETTER O WITH ACUTE
11100D4; C; 00F4; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX
11200D5; C; 00F5; # LATIN CAPITAL LETTER O WITH TILDE
11300D6; C; 00F6; # LATIN CAPITAL LETTER O WITH DIAERESIS
11400D8; C; 00F8; # LATIN CAPITAL LETTER O WITH STROKE
11500D9; C; 00F9; # LATIN CAPITAL LETTER U WITH GRAVE
11600DA; C; 00FA; # LATIN CAPITAL LETTER U WITH ACUTE
11700DB; C; 00FB; # LATIN CAPITAL LETTER U WITH CIRCUMFLEX
11800DC; C; 00FC; # LATIN CAPITAL LETTER U WITH DIAERESIS
11900DD; C; 00FD; # LATIN CAPITAL LETTER Y WITH ACUTE
12000DE; C; 00FE; # LATIN CAPITAL LETTER THORN
12100DF; F; 0073 0073; # LATIN SMALL LETTER SHARP S
1220100; C; 0101; # LATIN CAPITAL LETTER A WITH MACRON
1230102; C; 0103; # LATIN CAPITAL LETTER A WITH BREVE
1240104; C; 0105; # LATIN CAPITAL LETTER A WITH OGONEK
1250106; C; 0107; # LATIN CAPITAL LETTER C WITH ACUTE
1260108; C; 0109; # LATIN CAPITAL LETTER C WITH CIRCUMFLEX
127010A; C; 010B; # LATIN CAPITAL LETTER C WITH DOT ABOVE
128010C; C; 010D; # LATIN CAPITAL LETTER C WITH CARON
129010E; C; 010F; # LATIN CAPITAL LETTER D WITH CARON
1300110; C; 0111; # LATIN CAPITAL LETTER D WITH STROKE
1310112; C; 0113; # LATIN CAPITAL LETTER E WITH MACRON
1320114; C; 0115; # LATIN CAPITAL LETTER E WITH BREVE
1330116; C; 0117; # LATIN CAPITAL LETTER E WITH DOT ABOVE
1340118; C; 0119; # LATIN CAPITAL LETTER E WITH OGONEK
135011A; C; 011B; # LATIN CAPITAL LETTER E WITH CARON
136011C; C; 011D; # LATIN CAPITAL LETTER G WITH CIRCUMFLEX
137011E; C; 011F; # LATIN CAPITAL LETTER G WITH BREVE
1380120; C; 0121; # LATIN CAPITAL LETTER G WITH DOT ABOVE
1390122; C; 0123; # LATIN CAPITAL LETTER G WITH CEDILLA
1400124; C; 0125; # LATIN CAPITAL LETTER H WITH CIRCUMFLEX
1410126; C; 0127; # LATIN CAPITAL LETTER H WITH STROKE
1420128; C; 0129; # LATIN CAPITAL LETTER I WITH TILDE
143012A; C; 012B; # LATIN CAPITAL LETTER I WITH MACRON
144012C; C; 012D; # LATIN CAPITAL LETTER I WITH BREVE
145012E; C; 012F; # LATIN CAPITAL LETTER I WITH OGONEK
1460130; F; 0069 0307; # LATIN CAPITAL LETTER I WITH DOT ABOVE
1470130; T; 0069; # LATIN CAPITAL LETTER I WITH DOT ABOVE
1480132; C; 0133; # LATIN CAPITAL LIGATURE IJ
1490134; C; 0135; # LATIN CAPITAL LETTER J WITH CIRCUMFLEX
1500136; C; 0137; # LATIN CAPITAL LETTER K WITH CEDILLA
1510139; C; 013A; # LATIN CAPITAL LETTER L WITH ACUTE
152013B; C; 013C; # LATIN CAPITAL LETTER L WITH CEDILLA
153013D; C; 013E; # LATIN CAPITAL LETTER L WITH CARON
154013F; C; 0140; # LATIN CAPITAL LETTER L WITH MIDDLE DOT
1550141; C; 0142; # LATIN CAPITAL LETTER L WITH STROKE
1560143; C; 0144; # LATIN CAPITAL LETTER N WITH ACUTE
1570145; C; 0146; # LATIN CAPITAL LETTER N WITH CEDILLA
1580147; C; 0148; # LATIN CAPITAL LETTER N WITH CARON
1590149; F; 02BC 006E; # LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
160014A; C; 014B; # LATIN CAPITAL LETTER ENG
161014C; C; 014D; # LATIN CAPITAL LETTER O WITH MACRON
162014E; C; 014F; # LATIN CAPITAL LETTER O WITH BREVE
1630150; C; 0151; # LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
1640152; C; 0153; # LATIN CAPITAL LIGATURE OE
1650154; C; 0155; # LATIN CAPITAL LETTER R WITH ACUTE
1660156; C; 0157; # LATIN CAPITAL LETTER R WITH CEDILLA
1670158; C; 0159; # LATIN CAPITAL LETTER R WITH CARON
168015A; C; 015B; # LATIN CAPITAL LETTER S WITH ACUTE
169015C; C; 015D; # LATIN CAPITAL LETTER S WITH CIRCUMFLEX
170015E; C; 015F; # LATIN CAPITAL LETTER S WITH CEDILLA
1710160; C; 0161; # LATIN CAPITAL LETTER S WITH CARON
1720162; C; 0163; # LATIN CAPITAL LETTER T WITH CEDILLA
1730164; C; 0165; # LATIN CAPITAL LETTER T WITH CARON
1740166; C; 0167; # LATIN CAPITAL LETTER T WITH STROKE
1750168; C; 0169; # LATIN CAPITAL LETTER U WITH TILDE
176016A; C; 016B; # LATIN CAPITAL LETTER U WITH MACRON
177016C; C; 016D; # LATIN CAPITAL LETTER U WITH BREVE
178016E; C; 016F; # LATIN CAPITAL LETTER U WITH RING ABOVE
1790170; C; 0171; # LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
1800172; C; 0173; # LATIN CAPITAL LETTER U WITH OGONEK
1810174; C; 0175; # LATIN CAPITAL LETTER W WITH CIRCUMFLEX
1820176; C; 0177; # LATIN CAPITAL LETTER Y WITH CIRCUMFLEX
1830178; C; 00FF; # LATIN CAPITAL LETTER Y WITH DIAERESIS
1840179; C; 017A; # LATIN CAPITAL LETTER Z WITH ACUTE
185017B; C; 017C; # LATIN CAPITAL LETTER Z WITH DOT ABOVE
186017D; C; 017E; # LATIN CAPITAL LETTER Z WITH CARON
187017F; C; 0073; # LATIN SMALL LETTER LONG S
1880181; C; 0253; # LATIN CAPITAL LETTER B WITH HOOK
1890182; C; 0183; # LATIN CAPITAL LETTER B WITH TOPBAR
1900184; C; 0185; # LATIN CAPITAL LETTER TONE SIX
1910186; C; 0254; # LATIN CAPITAL LETTER OPEN O
1920187; C; 0188; # LATIN CAPITAL LETTER C WITH HOOK
1930189; C; 0256; # LATIN CAPITAL LETTER AFRICAN D
194018A; C; 0257; # LATIN CAPITAL LETTER D WITH HOOK
195018B; C; 018C; # LATIN CAPITAL LETTER D WITH TOPBAR
196018E; C; 01DD; # LATIN CAPITAL LETTER REVERSED E
197018F; C; 0259; # LATIN CAPITAL LETTER SCHWA
1980190; C; 025B; # LATIN CAPITAL LETTER OPEN E
1990191; C; 0192; # LATIN CAPITAL LETTER F WITH HOOK
2000193; C; 0260; # LATIN CAPITAL LETTER G WITH HOOK
2010194; C; 0263; # LATIN CAPITAL LETTER GAMMA
2020196; C; 0269; # LATIN CAPITAL LETTER IOTA
2030197; C; 0268; # LATIN CAPITAL LETTER I WITH STROKE
2040198; C; 0199; # LATIN CAPITAL LETTER K WITH HOOK
205019C; C; 026F; # LATIN CAPITAL LETTER TURNED M
206019D; C; 0272; # LATIN CAPITAL LETTER N WITH LEFT HOOK
207019F; C; 0275; # LATIN CAPITAL LETTER O WITH MIDDLE TILDE
20801A0; C; 01A1; # LATIN CAPITAL LETTER O WITH HORN
20901A2; C; 01A3; # LATIN CAPITAL LETTER OI
21001A4; C; 01A5; # LATIN CAPITAL LETTER P WITH HOOK
21101A6; C; 0280; # LATIN LETTER YR
21201A7; C; 01A8; # LATIN CAPITAL LETTER TONE TWO
21301A9; C; 0283; # LATIN CAPITAL LETTER ESH
21401AC; C; 01AD; # LATIN CAPITAL LETTER T WITH HOOK
21501AE; C; 0288; # LATIN CAPITAL LETTER T WITH RETROFLEX HOOK
21601AF; C; 01B0; # LATIN CAPITAL LETTER U WITH HORN
21701B1; C; 028A; # LATIN CAPITAL LETTER UPSILON
21801B2; C; 028B; # LATIN CAPITAL LETTER V WITH HOOK
21901B3; C; 01B4; # LATIN CAPITAL LETTER Y WITH HOOK
22001B5; C; 01B6; # LATIN CAPITAL LETTER Z WITH STROKE
22101B7; C; 0292; # LATIN CAPITAL LETTER EZH
22201B8; C; 01B9; # LATIN CAPITAL LETTER EZH REVERSED
22301BC; C; 01BD; # LATIN CAPITAL LETTER TONE FIVE
22401C4; C; 01C6; # LATIN CAPITAL LETTER DZ WITH CARON
22501C5; C; 01C6; # LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON
22601C7; C; 01C9; # LATIN CAPITAL LETTER LJ
22701C8; C; 01C9; # LATIN CAPITAL LETTER L WITH SMALL LETTER J
22801CA; C; 01CC; # LATIN CAPITAL LETTER NJ
22901CB; C; 01CC; # LATIN CAPITAL LETTER N WITH SMALL LETTER J
23001CD; C; 01CE; # LATIN CAPITAL LETTER A WITH CARON
23101CF; C; 01D0; # LATIN CAPITAL LETTER I WITH CARON
23201D1; C; 01D2; # LATIN CAPITAL LETTER O WITH CARON
23301D3; C; 01D4; # LATIN CAPITAL LETTER U WITH CARON
23401D5; C; 01D6; # LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON
23501D7; C; 01D8; # LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE
23601D9; C; 01DA; # LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON
23701DB; C; 01DC; # LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE
23801DE; C; 01DF; # LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON
23901E0; C; 01E1; # LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON
24001E2; C; 01E3; # LATIN CAPITAL LETTER AE WITH MACRON
24101E4; C; 01E5; # LATIN CAPITAL LETTER G WITH STROKE
24201E6; C; 01E7; # LATIN CAPITAL LETTER G WITH CARON
24301E8; C; 01E9; # LATIN CAPITAL LETTER K WITH CARON
24401EA; C; 01EB; # LATIN CAPITAL LETTER O WITH OGONEK
24501EC; C; 01ED; # LATIN CAPITAL LETTER O WITH OGONEK AND MACRON
24601EE; C; 01EF; # LATIN CAPITAL LETTER EZH WITH CARON
24701F0; F; 006A 030C; # LATIN SMALL LETTER J WITH CARON
24801F1; C; 01F3; # LATIN CAPITAL LETTER DZ
24901F2; C; 01F3; # LATIN CAPITAL LETTER D WITH SMALL LETTER Z
25001F4; C; 01F5; # LATIN CAPITAL LETTER G WITH ACUTE
25101F6; C; 0195; # LATIN CAPITAL LETTER HWAIR
25201F7; C; 01BF; # LATIN CAPITAL LETTER WYNN
25301F8; C; 01F9; # LATIN CAPITAL LETTER N WITH GRAVE
25401FA; C; 01FB; # LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE
25501FC; C; 01FD; # LATIN CAPITAL LETTER AE WITH ACUTE
25601FE; C; 01FF; # LATIN CAPITAL LETTER O WITH STROKE AND ACUTE
2570200; C; 0201; # LATIN CAPITAL LETTER A WITH DOUBLE GRAVE
2580202; C; 0203; # LATIN CAPITAL LETTER A WITH INVERTED BREVE
2590204; C; 0205; # LATIN CAPITAL LETTER E WITH DOUBLE GRAVE
2600206; C; 0207; # LATIN CAPITAL LETTER E WITH INVERTED BREVE
2610208; C; 0209; # LATIN CAPITAL LETTER I WITH DOUBLE GRAVE
262020A; C; 020B; # LATIN CAPITAL LETTER I WITH INVERTED BREVE
263020C; C; 020D; # LATIN CAPITAL LETTER O WITH DOUBLE GRAVE
264020E; C; 020F; # LATIN CAPITAL LETTER O WITH INVERTED BREVE
2650210; C; 0211; # LATIN CAPITAL LETTER R WITH DOUBLE GRAVE
2660212; C; 0213; # LATIN CAPITAL LETTER R WITH INVERTED BREVE
2670214; C; 0215; # LATIN CAPITAL LETTER U WITH DOUBLE GRAVE
2680216; C; 0217; # LATIN CAPITAL LETTER U WITH INVERTED BREVE
2690218; C; 0219; # LATIN CAPITAL LETTER S WITH COMMA BELOW
270021A; C; 021B; # LATIN CAPITAL LETTER T WITH COMMA BELOW
271021C; C; 021D; # LATIN CAPITAL LETTER YOGH
272021E; C; 021F; # LATIN CAPITAL LETTER H WITH CARON
2730220; C; 019E; # LATIN CAPITAL LETTER N WITH LONG RIGHT LEG
2740222; C; 0223; # LATIN CAPITAL LETTER OU
2750224; C; 0225; # LATIN CAPITAL LETTER Z WITH HOOK
2760226; C; 0227; # LATIN CAPITAL LETTER A WITH DOT ABOVE
2770228; C; 0229; # LATIN CAPITAL LETTER E WITH CEDILLA
278022A; C; 022B; # LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON
279022C; C; 022D; # LATIN CAPITAL LETTER O WITH TILDE AND MACRON
280022E; C; 022F; # LATIN CAPITAL LETTER O WITH DOT ABOVE
2810230; C; 0231; # LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON
2820232; C; 0233; # LATIN CAPITAL LETTER Y WITH MACRON
283023A; C; 2C65; # LATIN CAPITAL LETTER A WITH STROKE
284023B; C; 023C; # LATIN CAPITAL LETTER C WITH STROKE
285023D; C; 019A; # LATIN CAPITAL LETTER L WITH BAR
286023E; C; 2C66; # LATIN CAPITAL LETTER T WITH DIAGONAL STROKE
2870241; C; 0242; # LATIN CAPITAL LETTER GLOTTAL STOP
2880243; C; 0180; # LATIN CAPITAL LETTER B WITH STROKE
2890244; C; 0289; # LATIN CAPITAL LETTER U BAR
2900245; C; 028C; # LATIN CAPITAL LETTER TURNED V
2910246; C; 0247; # LATIN CAPITAL LETTER E WITH STROKE
2920248; C; 0249; # LATIN CAPITAL LETTER J WITH STROKE
293024A; C; 024B; # LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL
294024C; C; 024D; # LATIN CAPITAL LETTER R WITH STROKE
295024E; C; 024F; # LATIN CAPITAL LETTER Y WITH STROKE
2960345; C; 03B9; # COMBINING GREEK YPOGEGRAMMENI
2970370; C; 0371; # GREEK CAPITAL LETTER HETA
2980372; C; 0373; # GREEK CAPITAL LETTER ARCHAIC SAMPI
2990376; C; 0377; # GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA
300037F; C; 03F3; # GREEK CAPITAL LETTER YOT
3010386; C; 03AC; # GREEK CAPITAL LETTER ALPHA WITH TONOS
3020388; C; 03AD; # GREEK CAPITAL LETTER EPSILON WITH TONOS
3030389; C; 03AE; # GREEK CAPITAL LETTER ETA WITH TONOS
304038A; C; 03AF; # GREEK CAPITAL LETTER IOTA WITH TONOS
305038C; C; 03CC; # GREEK CAPITAL LETTER OMICRON WITH TONOS
306038E; C; 03CD; # GREEK CAPITAL LETTER UPSILON WITH TONOS
307038F; C; 03CE; # GREEK CAPITAL LETTER OMEGA WITH TONOS
3080390; F; 03B9 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
3090391; C; 03B1; # GREEK CAPITAL LETTER ALPHA
3100392; C; 03B2; # GREEK CAPITAL LETTER BETA
3110393; C; 03B3; # GREEK CAPITAL LETTER GAMMA
3120394; C; 03B4; # GREEK CAPITAL LETTER DELTA
3130395; C; 03B5; # GREEK CAPITAL LETTER EPSILON
3140396; C; 03B6; # GREEK CAPITAL LETTER ZETA
3150397; C; 03B7; # GREEK CAPITAL LETTER ETA
3160398; C; 03B8; # GREEK CAPITAL LETTER THETA
3170399; C; 03B9; # GREEK CAPITAL LETTER IOTA
318039A; C; 03BA; # GREEK CAPITAL LETTER KAPPA
319039B; C; 03BB; # GREEK CAPITAL LETTER LAMDA
320039C; C; 03BC; # GREEK CAPITAL LETTER MU
321039D; C; 03BD; # GREEK CAPITAL LETTER NU
322039E; C; 03BE; # GREEK CAPITAL LETTER XI
323039F; C; 03BF; # GREEK CAPITAL LETTER OMICRON
32403A0; C; 03C0; # GREEK CAPITAL LETTER PI
32503A1; C; 03C1; # GREEK CAPITAL LETTER RHO
32603A3; C; 03C3; # GREEK CAPITAL LETTER SIGMA
32703A4; C; 03C4; # GREEK CAPITAL LETTER TAU
32803A5; C; 03C5; # GREEK CAPITAL LETTER UPSILON
32903A6; C; 03C6; # GREEK CAPITAL LETTER PHI
33003A7; C; 03C7; # GREEK CAPITAL LETTER CHI
33103A8; C; 03C8; # GREEK CAPITAL LETTER PSI
33203A9; C; 03C9; # GREEK CAPITAL LETTER OMEGA
33303AA; C; 03CA; # GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
33403AB; C; 03CB; # GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
33503B0; F; 03C5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
33603C2; C; 03C3; # GREEK SMALL LETTER FINAL SIGMA
33703CF; C; 03D7; # GREEK CAPITAL KAI SYMBOL
33803D0; C; 03B2; # GREEK BETA SYMBOL
33903D1; C; 03B8; # GREEK THETA SYMBOL
34003D5; C; 03C6; # GREEK PHI SYMBOL
34103D6; C; 03C0; # GREEK PI SYMBOL
34203D8; C; 03D9; # GREEK LETTER ARCHAIC KOPPA
34303DA; C; 03DB; # GREEK LETTER STIGMA
34403DC; C; 03DD; # GREEK LETTER DIGAMMA
34503DE; C; 03DF; # GREEK LETTER KOPPA
34603E0; C; 03E1; # GREEK LETTER SAMPI
34703E2; C; 03E3; # COPTIC CAPITAL LETTER SHEI
34803E4; C; 03E5; # COPTIC CAPITAL LETTER FEI
34903E6; C; 03E7; # COPTIC CAPITAL LETTER KHEI
35003E8; C; 03E9; # COPTIC CAPITAL LETTER HORI
35103EA; C; 03EB; # COPTIC CAPITAL LETTER GANGIA
35203EC; C; 03ED; # COPTIC CAPITAL LETTER SHIMA
35303EE; C; 03EF; # COPTIC CAPITAL LETTER DEI
35403F0; C; 03BA; # GREEK KAPPA SYMBOL
35503F1; C; 03C1; # GREEK RHO SYMBOL
35603F4; C; 03B8; # GREEK CAPITAL THETA SYMBOL
35703F5; C; 03B5; # GREEK LUNATE EPSILON SYMBOL
35803F7; C; 03F8; # GREEK CAPITAL LETTER SHO
35903F9; C; 03F2; # GREEK CAPITAL LUNATE SIGMA SYMBOL
36003FA; C; 03FB; # GREEK CAPITAL LETTER SAN
36103FD; C; 037B; # GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL
36203FE; C; 037C; # GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL
36303FF; C; 037D; # GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL
3640400; C; 0450; # CYRILLIC CAPITAL LETTER IE WITH GRAVE
3650401; C; 0451; # CYRILLIC CAPITAL LETTER IO
3660402; C; 0452; # CYRILLIC CAPITAL LETTER DJE
3670403; C; 0453; # CYRILLIC CAPITAL LETTER GJE
3680404; C; 0454; # CYRILLIC CAPITAL LETTER UKRAINIAN IE
3690405; C; 0455; # CYRILLIC CAPITAL LETTER DZE
3700406; C; 0456; # CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
3710407; C; 0457; # CYRILLIC CAPITAL LETTER YI
3720408; C; 0458; # CYRILLIC CAPITAL LETTER JE
3730409; C; 0459; # CYRILLIC CAPITAL LETTER LJE
374040A; C; 045A; # CYRILLIC CAPITAL LETTER NJE
375040B; C; 045B; # CYRILLIC CAPITAL LETTER TSHE
376040C; C; 045C; # CYRILLIC CAPITAL LETTER KJE
377040D; C; 045D; # CYRILLIC CAPITAL LETTER I WITH GRAVE
378040E; C; 045E; # CYRILLIC CAPITAL LETTER SHORT U
379040F; C; 045F; # CYRILLIC CAPITAL LETTER DZHE
3800410; C; 0430; # CYRILLIC CAPITAL LETTER A
3810411; C; 0431; # CYRILLIC CAPITAL LETTER BE
3820412; C; 0432; # CYRILLIC CAPITAL LETTER VE
3830413; C; 0433; # CYRILLIC CAPITAL LETTER GHE
3840414; C; 0434; # CYRILLIC CAPITAL LETTER DE
3850415; C; 0435; # CYRILLIC CAPITAL LETTER IE
3860416; C; 0436; # CYRILLIC CAPITAL LETTER ZHE
3870417; C; 0437; # CYRILLIC CAPITAL LETTER ZE
3880418; C; 0438; # CYRILLIC CAPITAL LETTER I
3890419; C; 0439; # CYRILLIC CAPITAL LETTER SHORT I
390041A; C; 043A; # CYRILLIC CAPITAL LETTER KA
391041B; C; 043B; # CYRILLIC CAPITAL LETTER EL
392041C; C; 043C; # CYRILLIC CAPITAL LETTER EM
393041D; C; 043D; # CYRILLIC CAPITAL LETTER EN
394041E; C; 043E; # CYRILLIC CAPITAL LETTER O
395041F; C; 043F; # CYRILLIC CAPITAL LETTER PE
3960420; C; 0440; # CYRILLIC CAPITAL LETTER ER
3970421; C; 0441; # CYRILLIC CAPITAL LETTER ES
3980422; C; 0442; # CYRILLIC CAPITAL LETTER TE
3990423; C; 0443; # CYRILLIC CAPITAL LETTER U
4000424; C; 0444; # CYRILLIC CAPITAL LETTER EF
4010425; C; 0445; # CYRILLIC CAPITAL LETTER HA
4020426; C; 0446; # CYRILLIC CAPITAL LETTER TSE
4030427; C; 0447; # CYRILLIC CAPITAL LETTER CHE
4040428; C; 0448; # CYRILLIC CAPITAL LETTER SHA
4050429; C; 0449; # CYRILLIC CAPITAL LETTER SHCHA
406042A; C; 044A; # CYRILLIC CAPITAL LETTER HARD SIGN
407042B; C; 044B; # CYRILLIC CAPITAL LETTER YERU
408042C; C; 044C; # CYRILLIC CAPITAL LETTER SOFT SIGN
409042D; C; 044D; # CYRILLIC CAPITAL LETTER E
410042E; C; 044E; # CYRILLIC CAPITAL LETTER YU
411042F; C; 044F; # CYRILLIC CAPITAL LETTER YA
4120460; C; 0461; # CYRILLIC CAPITAL LETTER OMEGA
4130462; C; 0463; # CYRILLIC CAPITAL LETTER YAT
4140464; C; 0465; # CYRILLIC CAPITAL LETTER IOTIFIED E
4150466; C; 0467; # CYRILLIC CAPITAL LETTER LITTLE YUS
4160468; C; 0469; # CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS
417046A; C; 046B; # CYRILLIC CAPITAL LETTER BIG YUS
418046C; C; 046D; # CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS
419046E; C; 046F; # CYRILLIC CAPITAL LETTER KSI
4200470; C; 0471; # CYRILLIC CAPITAL LETTER PSI
4210472; C; 0473; # CYRILLIC CAPITAL LETTER FITA
4220474; C; 0475; # CYRILLIC CAPITAL LETTER IZHITSA
4230476; C; 0477; # CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT
4240478; C; 0479; # CYRILLIC CAPITAL LETTER UK
425047A; C; 047B; # CYRILLIC CAPITAL LETTER ROUND OMEGA
426047C; C; 047D; # CYRILLIC CAPITAL LETTER OMEGA WITH TITLO
427047E; C; 047F; # CYRILLIC CAPITAL LETTER OT
4280480; C; 0481; # CYRILLIC CAPITAL LETTER KOPPA
429048A; C; 048B; # CYRILLIC CAPITAL LETTER SHORT I WITH TAIL
430048C; C; 048D; # CYRILLIC CAPITAL LETTER SEMISOFT SIGN
431048E; C; 048F; # CYRILLIC CAPITAL LETTER ER WITH TICK
4320490; C; 0491; # CYRILLIC CAPITAL LETTER GHE WITH UPTURN
4330492; C; 0493; # CYRILLIC CAPITAL LETTER GHE WITH STROKE
4340494; C; 0495; # CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK
4350496; C; 0497; # CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER
4360498; C; 0499; # CYRILLIC CAPITAL LETTER ZE WITH DESCENDER
437049A; C; 049B; # CYRILLIC CAPITAL LETTER KA WITH DESCENDER
438049C; C; 049D; # CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE
439049E; C; 049F; # CYRILLIC CAPITAL LETTER KA WITH STROKE
44004A0; C; 04A1; # CYRILLIC CAPITAL LETTER BASHKIR KA
44104A2; C; 04A3; # CYRILLIC CAPITAL LETTER EN WITH DESCENDER
44204A4; C; 04A5; # CYRILLIC CAPITAL LIGATURE EN GHE
44304A6; C; 04A7; # CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK
44404A8; C; 04A9; # CYRILLIC CAPITAL LETTER ABKHASIAN HA
44504AA; C; 04AB; # CYRILLIC CAPITAL LETTER ES WITH DESCENDER
44604AC; C; 04AD; # CYRILLIC CAPITAL LETTER TE WITH DESCENDER
44704AE; C; 04AF; # CYRILLIC CAPITAL LETTER STRAIGHT U
44804B0; C; 04B1; # CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE
44904B2; C; 04B3; # CYRILLIC CAPITAL LETTER HA WITH DESCENDER
45004B4; C; 04B5; # CYRILLIC CAPITAL LIGATURE TE TSE
45104B6; C; 04B7; # CYRILLIC CAPITAL LETTER CHE WITH DESCENDER
45204B8; C; 04B9; # CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE
45304BA; C; 04BB; # CYRILLIC CAPITAL LETTER SHHA
45404BC; C; 04BD; # CYRILLIC CAPITAL LETTER ABKHASIAN CHE
45504BE; C; 04BF; # CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER
45604C0; C; 04CF; # CYRILLIC LETTER PALOCHKA
45704C1; C; 04C2; # CYRILLIC CAPITAL LETTER ZHE WITH BREVE
45804C3; C; 04C4; # CYRILLIC CAPITAL LETTER KA WITH HOOK
45904C5; C; 04C6; # CYRILLIC CAPITAL LETTER EL WITH TAIL
46004C7; C; 04C8; # CYRILLIC CAPITAL LETTER EN WITH HOOK
46104C9; C; 04CA; # CYRILLIC CAPITAL LETTER EN WITH TAIL
46204CB; C; 04CC; # CYRILLIC CAPITAL LETTER KHAKASSIAN CHE
46304CD; C; 04CE; # CYRILLIC CAPITAL LETTER EM WITH TAIL
46404D0; C; 04D1; # CYRILLIC CAPITAL LETTER A WITH BREVE
46504D2; C; 04D3; # CYRILLIC CAPITAL LETTER A WITH DIAERESIS
46604D4; C; 04D5; # CYRILLIC CAPITAL LIGATURE A IE
46704D6; C; 04D7; # CYRILLIC CAPITAL LETTER IE WITH BREVE
46804D8; C; 04D9; # CYRILLIC CAPITAL LETTER SCHWA
46904DA; C; 04DB; # CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS
47004DC; C; 04DD; # CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS
47104DE; C; 04DF; # CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS
47204E0; C; 04E1; # CYRILLIC CAPITAL LETTER ABKHASIAN DZE
47304E2; C; 04E3; # CYRILLIC CAPITAL LETTER I WITH MACRON
47404E4; C; 04E5; # CYRILLIC CAPITAL LETTER I WITH DIAERESIS
47504E6; C; 04E7; # CYRILLIC CAPITAL LETTER O WITH DIAERESIS
47604E8; C; 04E9; # CYRILLIC CAPITAL LETTER BARRED O
47704EA; C; 04EB; # CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS
47804EC; C; 04ED; # CYRILLIC CAPITAL LETTER E WITH DIAERESIS
47904EE; C; 04EF; # CYRILLIC CAPITAL LETTER U WITH MACRON
48004F0; C; 04F1; # CYRILLIC CAPITAL LETTER U WITH DIAERESIS
48104F2; C; 04F3; # CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE
48204F4; C; 04F5; # CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS
48304F6; C; 04F7; # CYRILLIC CAPITAL LETTER GHE WITH DESCENDER
48404F8; C; 04F9; # CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS
48504FA; C; 04FB; # CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK
48604FC; C; 04FD; # CYRILLIC CAPITAL LETTER HA WITH HOOK
48704FE; C; 04FF; # CYRILLIC CAPITAL LETTER HA WITH STROKE
4880500; C; 0501; # CYRILLIC CAPITAL LETTER KOMI DE
4890502; C; 0503; # CYRILLIC CAPITAL LETTER KOMI DJE
4900504; C; 0505; # CYRILLIC CAPITAL LETTER KOMI ZJE
4910506; C; 0507; # CYRILLIC CAPITAL LETTER KOMI DZJE
4920508; C; 0509; # CYRILLIC CAPITAL LETTER KOMI LJE
493050A; C; 050B; # CYRILLIC CAPITAL LETTER KOMI NJE
494050C; C; 050D; # CYRILLIC CAPITAL LETTER KOMI SJE
495050E; C; 050F; # CYRILLIC CAPITAL LETTER KOMI TJE
4960510; C; 0511; # CYRILLIC CAPITAL LETTER REVERSED ZE
4970512; C; 0513; # CYRILLIC CAPITAL LETTER EL WITH HOOK
4980514; C; 0515; # CYRILLIC CAPITAL LETTER LHA
4990516; C; 0517; # CYRILLIC CAPITAL LETTER RHA
5000518; C; 0519; # CYRILLIC CAPITAL LETTER YAE
501051A; C; 051B; # CYRILLIC CAPITAL LETTER QA
502051C; C; 051D; # CYRILLIC CAPITAL LETTER WE
503051E; C; 051F; # CYRILLIC CAPITAL LETTER ALEUT KA
5040520; C; 0521; # CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK
5050522; C; 0523; # CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK
5060524; C; 0525; # CYRILLIC CAPITAL LETTER PE WITH DESCENDER
5070526; C; 0527; # CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER
5080528; C; 0529; # CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK
509052A; C; 052B; # CYRILLIC CAPITAL LETTER DZZHE
510052C; C; 052D; # CYRILLIC CAPITAL LETTER DCHE
511052E; C; 052F; # CYRILLIC CAPITAL LETTER EL WITH DESCENDER
5120531; C; 0561; # ARMENIAN CAPITAL LETTER AYB
5130532; C; 0562; # ARMENIAN CAPITAL LETTER BEN
5140533; C; 0563; # ARMENIAN CAPITAL LETTER GIM
5150534; C; 0564; # ARMENIAN CAPITAL LETTER DA
5160535; C; 0565; # ARMENIAN CAPITAL LETTER ECH
5170536; C; 0566; # ARMENIAN CAPITAL LETTER ZA
5180537; C; 0567; # ARMENIAN CAPITAL LETTER EH
5190538; C; 0568; # ARMENIAN CAPITAL LETTER ET
5200539; C; 0569; # ARMENIAN CAPITAL LETTER TO
521053A; C; 056A; # ARMENIAN CAPITAL LETTER ZHE
522053B; C; 056B; # ARMENIAN CAPITAL LETTER INI
523053C; C; 056C; # ARMENIAN CAPITAL LETTER LIWN
524053D; C; 056D; # ARMENIAN CAPITAL LETTER XEH
525053E; C; 056E; # ARMENIAN CAPITAL LETTER CA
526053F; C; 056F; # ARMENIAN CAPITAL LETTER KEN
5270540; C; 0570; # ARMENIAN CAPITAL LETTER HO
5280541; C; 0571; # ARMENIAN CAPITAL LETTER JA
5290542; C; 0572; # ARMENIAN CAPITAL LETTER GHAD
5300543; C; 0573; # ARMENIAN CAPITAL LETTER CHEH
5310544; C; 0574; # ARMENIAN CAPITAL LETTER MEN
5320545; C; 0575; # ARMENIAN CAPITAL LETTER YI
5330546; C; 0576; # ARMENIAN CAPITAL LETTER NOW
5340547; C; 0577; # ARMENIAN CAPITAL LETTER SHA
5350548; C; 0578; # ARMENIAN CAPITAL LETTER VO
5360549; C; 0579; # ARMENIAN CAPITAL LETTER CHA
537054A; C; 057A; # ARMENIAN CAPITAL LETTER PEH
538054B; C; 057B; # ARMENIAN CAPITAL LETTER JHEH
539054C; C; 057C; # ARMENIAN CAPITAL LETTER RA
540054D; C; 057D; # ARMENIAN CAPITAL LETTER SEH
541054E; C; 057E; # ARMENIAN CAPITAL LETTER VEW
542054F; C; 057F; # ARMENIAN CAPITAL LETTER TIWN
5430550; C; 0580; # ARMENIAN CAPITAL LETTER REH
5440551; C; 0581; # ARMENIAN CAPITAL LETTER CO
5450552; C; 0582; # ARMENIAN CAPITAL LETTER YIWN
5460553; C; 0583; # ARMENIAN CAPITAL LETTER PIWR
5470554; C; 0584; # ARMENIAN CAPITAL LETTER KEH
5480555; C; 0585; # ARMENIAN CAPITAL LETTER OH
5490556; C; 0586; # ARMENIAN CAPITAL LETTER FEH
5500587; F; 0565 0582; # ARMENIAN SMALL LIGATURE ECH YIWN
55110A0; C; 2D00; # GEORGIAN CAPITAL LETTER AN
55210A1; C; 2D01; # GEORGIAN CAPITAL LETTER BAN
55310A2; C; 2D02; # GEORGIAN CAPITAL LETTER GAN
55410A3; C; 2D03; # GEORGIAN CAPITAL LETTER DON
55510A4; C; 2D04; # GEORGIAN CAPITAL LETTER EN
55610A5; C; 2D05; # GEORGIAN CAPITAL LETTER VIN
55710A6; C; 2D06; # GEORGIAN CAPITAL LETTER ZEN
55810A7; C; 2D07; # GEORGIAN CAPITAL LETTER TAN
55910A8; C; 2D08; # GEORGIAN CAPITAL LETTER IN
56010A9; C; 2D09; # GEORGIAN CAPITAL LETTER KAN
56110AA; C; 2D0A; # GEORGIAN CAPITAL LETTER LAS
56210AB; C; 2D0B; # GEORGIAN CAPITAL LETTER MAN
56310AC; C; 2D0C; # GEORGIAN CAPITAL LETTER NAR
56410AD; C; 2D0D; # GEORGIAN CAPITAL LETTER ON
56510AE; C; 2D0E; # GEORGIAN CAPITAL LETTER PAR
56610AF; C; 2D0F; # GEORGIAN CAPITAL LETTER ZHAR
56710B0; C; 2D10; # GEORGIAN CAPITAL LETTER RAE
56810B1; C; 2D11; # GEORGIAN CAPITAL LETTER SAN
56910B2; C; 2D12; # GEORGIAN CAPITAL LETTER TAR
57010B3; C; 2D13; # GEORGIAN CAPITAL LETTER UN
57110B4; C; 2D14; # GEORGIAN CAPITAL LETTER PHAR
57210B5; C; 2D15; # GEORGIAN CAPITAL LETTER KHAR
57310B6; C; 2D16; # GEORGIAN CAPITAL LETTER GHAN
57410B7; C; 2D17; # GEORGIAN CAPITAL LETTER QAR
57510B8; C; 2D18; # GEORGIAN CAPITAL LETTER SHIN
57610B9; C; 2D19; # GEORGIAN CAPITAL LETTER CHIN
57710BA; C; 2D1A; # GEORGIAN CAPITAL LETTER CAN
57810BB; C; 2D1B; # GEORGIAN CAPITAL LETTER JIL
57910BC; C; 2D1C; # GEORGIAN CAPITAL LETTER CIL
58010BD; C; 2D1D; # GEORGIAN CAPITAL LETTER CHAR
58110BE; C; 2D1E; # GEORGIAN CAPITAL LETTER XAN
58210BF; C; 2D1F; # GEORGIAN CAPITAL LETTER JHAN
58310C0; C; 2D20; # GEORGIAN CAPITAL LETTER HAE
58410C1; C; 2D21; # GEORGIAN CAPITAL LETTER HE
58510C2; C; 2D22; # GEORGIAN CAPITAL LETTER HIE
58610C3; C; 2D23; # GEORGIAN CAPITAL LETTER WE
58710C4; C; 2D24; # GEORGIAN CAPITAL LETTER HAR
58810C5; C; 2D25; # GEORGIAN CAPITAL LETTER HOE
58910C7; C; 2D27; # GEORGIAN CAPITAL LETTER YN
59010CD; C; 2D2D; # GEORGIAN CAPITAL LETTER AEN
59113F8; C; 13F0; # CHEROKEE SMALL LETTER YE
59213F9; C; 13F1; # CHEROKEE SMALL LETTER YI
59313FA; C; 13F2; # CHEROKEE SMALL LETTER YO
59413FB; C; 13F3; # CHEROKEE SMALL LETTER YU
59513FC; C; 13F4; # CHEROKEE SMALL LETTER YV
59613FD; C; 13F5; # CHEROKEE SMALL LETTER MV
5971C80; C; 0432; # CYRILLIC SMALL LETTER ROUNDED VE
5981C81; C; 0434; # CYRILLIC SMALL LETTER LONG-LEGGED DE
5991C82; C; 043E; # CYRILLIC SMALL LETTER NARROW O
6001C83; C; 0441; # CYRILLIC SMALL LETTER WIDE ES
6011C84; C; 0442; # CYRILLIC SMALL LETTER TALL TE
6021C85; C; 0442; # CYRILLIC SMALL LETTER THREE-LEGGED TE
6031C86; C; 044A; # CYRILLIC SMALL LETTER TALL HARD SIGN
6041C87; C; 0463; # CYRILLIC SMALL LETTER TALL YAT
6051C88; C; A64B; # CYRILLIC SMALL LETTER UNBLENDED UK
6061C90; C; 10D0; # GEORGIAN MTAVRULI CAPITAL LETTER AN
6071C91; C; 10D1; # GEORGIAN MTAVRULI CAPITAL LETTER BAN
6081C92; C; 10D2; # GEORGIAN MTAVRULI CAPITAL LETTER GAN
6091C93; C; 10D3; # GEORGIAN MTAVRULI CAPITAL LETTER DON
6101C94; C; 10D4; # GEORGIAN MTAVRULI CAPITAL LETTER EN
6111C95; C; 10D5; # GEORGIAN MTAVRULI CAPITAL LETTER VIN
6121C96; C; 10D6; # GEORGIAN MTAVRULI CAPITAL LETTER ZEN
6131C97; C; 10D7; # GEORGIAN MTAVRULI CAPITAL LETTER TAN
6141C98; C; 10D8; # GEORGIAN MTAVRULI CAPITAL LETTER IN
6151C99; C; 10D9; # GEORGIAN MTAVRULI CAPITAL LETTER KAN
6161C9A; C; 10DA; # GEORGIAN MTAVRULI CAPITAL LETTER LAS
6171C9B; C; 10DB; # GEORGIAN MTAVRULI CAPITAL LETTER MAN
6181C9C; C; 10DC; # GEORGIAN MTAVRULI CAPITAL LETTER NAR
6191C9D; C; 10DD; # GEORGIAN MTAVRULI CAPITAL LETTER ON
6201C9E; C; 10DE; # GEORGIAN MTAVRULI CAPITAL LETTER PAR
6211C9F; C; 10DF; # GEORGIAN MTAVRULI CAPITAL LETTER ZHAR
6221CA0; C; 10E0; # GEORGIAN MTAVRULI CAPITAL LETTER RAE
6231CA1; C; 10E1; # GEORGIAN MTAVRULI CAPITAL LETTER SAN
6241CA2; C; 10E2; # GEORGIAN MTAVRULI CAPITAL LETTER TAR
6251CA3; C; 10E3; # GEORGIAN MTAVRULI CAPITAL LETTER UN
6261CA4; C; 10E4; # GEORGIAN MTAVRULI CAPITAL LETTER PHAR
6271CA5; C; 10E5; # GEORGIAN MTAVRULI CAPITAL LETTER KHAR
6281CA6; C; 10E6; # GEORGIAN MTAVRULI CAPITAL LETTER GHAN
6291CA7; C; 10E7; # GEORGIAN MTAVRULI CAPITAL LETTER QAR
6301CA8; C; 10E8; # GEORGIAN MTAVRULI CAPITAL LETTER SHIN
6311CA9; C; 10E9; # GEORGIAN MTAVRULI CAPITAL LETTER CHIN
6321CAA; C; 10EA; # GEORGIAN MTAVRULI CAPITAL LETTER CAN
6331CAB; C; 10EB; # GEORGIAN MTAVRULI CAPITAL LETTER JIL
6341CAC; C; 10EC; # GEORGIAN MTAVRULI CAPITAL LETTER CIL
6351CAD; C; 10ED; # GEORGIAN MTAVRULI CAPITAL LETTER CHAR
6361CAE; C; 10EE; # GEORGIAN MTAVRULI CAPITAL LETTER XAN
6371CAF; C; 10EF; # GEORGIAN MTAVRULI CAPITAL LETTER JHAN
6381CB0; C; 10F0; # GEORGIAN MTAVRULI CAPITAL LETTER HAE
6391CB1; C; 10F1; # GEORGIAN MTAVRULI CAPITAL LETTER HE
6401CB2; C; 10F2; # GEORGIAN MTAVRULI CAPITAL LETTER HIE
6411CB3; C; 10F3; # GEORGIAN MTAVRULI CAPITAL LETTER WE
6421CB4; C; 10F4; # GEORGIAN MTAVRULI CAPITAL LETTER HAR
6431CB5; C; 10F5; # GEORGIAN MTAVRULI CAPITAL LETTER HOE
6441CB6; C; 10F6; # GEORGIAN MTAVRULI CAPITAL LETTER FI
6451CB7; C; 10F7; # GEORGIAN MTAVRULI CAPITAL LETTER YN
6461CB8; C; 10F8; # GEORGIAN MTAVRULI CAPITAL LETTER ELIFI
6471CB9; C; 10F9; # GEORGIAN MTAVRULI CAPITAL LETTER TURNED GAN
6481CBA; C; 10FA; # GEORGIAN MTAVRULI CAPITAL LETTER AIN
6491CBD; C; 10FD; # GEORGIAN MTAVRULI CAPITAL LETTER AEN
6501CBE; C; 10FE; # GEORGIAN MTAVRULI CAPITAL LETTER HARD SIGN
6511CBF; C; 10FF; # GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN
6521E00; C; 1E01; # LATIN CAPITAL LETTER A WITH RING BELOW
6531E02; C; 1E03; # LATIN CAPITAL LETTER B WITH DOT ABOVE
6541E04; C; 1E05; # LATIN CAPITAL LETTER B WITH DOT BELOW
6551E06; C; 1E07; # LATIN CAPITAL LETTER B WITH LINE BELOW
6561E08; C; 1E09; # LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE
6571E0A; C; 1E0B; # LATIN CAPITAL LETTER D WITH DOT ABOVE
6581E0C; C; 1E0D; # LATIN CAPITAL LETTER D WITH DOT BELOW
6591E0E; C; 1E0F; # LATIN CAPITAL LETTER D WITH LINE BELOW
6601E10; C; 1E11; # LATIN CAPITAL LETTER D WITH CEDILLA
6611E12; C; 1E13; # LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW
6621E14; C; 1E15; # LATIN CAPITAL LETTER E WITH MACRON AND GRAVE
6631E16; C; 1E17; # LATIN CAPITAL LETTER E WITH MACRON AND ACUTE
6641E18; C; 1E19; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW
6651E1A; C; 1E1B; # LATIN CAPITAL LETTER E WITH TILDE BELOW
6661E1C; C; 1E1D; # LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE
6671E1E; C; 1E1F; # LATIN CAPITAL LETTER F WITH DOT ABOVE
6681E20; C; 1E21; # LATIN CAPITAL LETTER G WITH MACRON
6691E22; C; 1E23; # LATIN CAPITAL LETTER H WITH DOT ABOVE
6701E24; C; 1E25; # LATIN CAPITAL LETTER H WITH DOT BELOW
6711E26; C; 1E27; # LATIN CAPITAL LETTER H WITH DIAERESIS
6721E28; C; 1E29; # LATIN CAPITAL LETTER H WITH CEDILLA
6731E2A; C; 1E2B; # LATIN CAPITAL LETTER H WITH BREVE BELOW
6741E2C; C; 1E2D; # LATIN CAPITAL LETTER I WITH TILDE BELOW
6751E2E; C; 1E2F; # LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE
6761E30; C; 1E31; # LATIN CAPITAL LETTER K WITH ACUTE
6771E32; C; 1E33; # LATIN CAPITAL LETTER K WITH DOT BELOW
6781E34; C; 1E35; # LATIN CAPITAL LETTER K WITH LINE BELOW
6791E36; C; 1E37; # LATIN CAPITAL LETTER L WITH DOT BELOW
6801E38; C; 1E39; # LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON
6811E3A; C; 1E3B; # LATIN CAPITAL LETTER L WITH LINE BELOW
6821E3C; C; 1E3D; # LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW
6831E3E; C; 1E3F; # LATIN CAPITAL LETTER M WITH ACUTE
6841E40; C; 1E41; # LATIN CAPITAL LETTER M WITH DOT ABOVE
6851E42; C; 1E43; # LATIN CAPITAL LETTER M WITH DOT BELOW
6861E44; C; 1E45; # LATIN CAPITAL LETTER N WITH DOT ABOVE
6871E46; C; 1E47; # LATIN CAPITAL LETTER N WITH DOT BELOW
6881E48; C; 1E49; # LATIN CAPITAL LETTER N WITH LINE BELOW
6891E4A; C; 1E4B; # LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW
6901E4C; C; 1E4D; # LATIN CAPITAL LETTER O WITH TILDE AND ACUTE
6911E4E; C; 1E4F; # LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS
6921E50; C; 1E51; # LATIN CAPITAL LETTER O WITH MACRON AND GRAVE
6931E52; C; 1E53; # LATIN CAPITAL LETTER O WITH MACRON AND ACUTE
6941E54; C; 1E55; # LATIN CAPITAL LETTER P WITH ACUTE
6951E56; C; 1E57; # LATIN CAPITAL LETTER P WITH DOT ABOVE
6961E58; C; 1E59; # LATIN CAPITAL LETTER R WITH DOT ABOVE
6971E5A; C; 1E5B; # LATIN CAPITAL LETTER R WITH DOT BELOW
6981E5C; C; 1E5D; # LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON
6991E5E; C; 1E5F; # LATIN CAPITAL LETTER R WITH LINE BELOW
7001E60; C; 1E61; # LATIN CAPITAL LETTER S WITH DOT ABOVE
7011E62; C; 1E63; # LATIN CAPITAL LETTER S WITH DOT BELOW
7021E64; C; 1E65; # LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE
7031E66; C; 1E67; # LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE
7041E68; C; 1E69; # LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE
7051E6A; C; 1E6B; # LATIN CAPITAL LETTER T WITH DOT ABOVE
7061E6C; C; 1E6D; # LATIN CAPITAL LETTER T WITH DOT BELOW
7071E6E; C; 1E6F; # LATIN CAPITAL LETTER T WITH LINE BELOW
7081E70; C; 1E71; # LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW
7091E72; C; 1E73; # LATIN CAPITAL LETTER U WITH DIAERESIS BELOW
7101E74; C; 1E75; # LATIN CAPITAL LETTER U WITH TILDE BELOW
7111E76; C; 1E77; # LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW
7121E78; C; 1E79; # LATIN CAPITAL LETTER U WITH TILDE AND ACUTE
7131E7A; C; 1E7B; # LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS
7141E7C; C; 1E7D; # LATIN CAPITAL LETTER V WITH TILDE
7151E7E; C; 1E7F; # LATIN CAPITAL LETTER V WITH DOT BELOW
7161E80; C; 1E81; # LATIN CAPITAL LETTER W WITH GRAVE
7171E82; C; 1E83; # LATIN CAPITAL LETTER W WITH ACUTE
7181E84; C; 1E85; # LATIN CAPITAL LETTER W WITH DIAERESIS
7191E86; C; 1E87; # LATIN CAPITAL LETTER W WITH DOT ABOVE
7201E88; C; 1E89; # LATIN CAPITAL LETTER W WITH DOT BELOW
7211E8A; C; 1E8B; # LATIN CAPITAL LETTER X WITH DOT ABOVE
7221E8C; C; 1E8D; # LATIN CAPITAL LETTER X WITH DIAERESIS
7231E8E; C; 1E8F; # LATIN CAPITAL LETTER Y WITH DOT ABOVE
7241E90; C; 1E91; # LATIN CAPITAL LETTER Z WITH CIRCUMFLEX
7251E92; C; 1E93; # LATIN CAPITAL LETTER Z WITH DOT BELOW
7261E94; C; 1E95; # LATIN CAPITAL LETTER Z WITH LINE BELOW
7271E96; F; 0068 0331; # LATIN SMALL LETTER H WITH LINE BELOW
7281E97; F; 0074 0308; # LATIN SMALL LETTER T WITH DIAERESIS
7291E98; F; 0077 030A; # LATIN SMALL LETTER W WITH RING ABOVE
7301E99; F; 0079 030A; # LATIN SMALL LETTER Y WITH RING ABOVE
7311E9A; F; 0061 02BE; # LATIN SMALL LETTER A WITH RIGHT HALF RING
7321E9B; C; 1E61; # LATIN SMALL LETTER LONG S WITH DOT ABOVE
7331E9E; F; 0073 0073; # LATIN CAPITAL LETTER SHARP S
7341E9E; S; 00DF; # LATIN CAPITAL LETTER SHARP S
7351EA0; C; 1EA1; # LATIN CAPITAL LETTER A WITH DOT BELOW
7361EA2; C; 1EA3; # LATIN CAPITAL LETTER A WITH HOOK ABOVE
7371EA4; C; 1EA5; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE
7381EA6; C; 1EA7; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE
7391EA8; C; 1EA9; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
7401EAA; C; 1EAB; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE
7411EAC; C; 1EAD; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW
7421EAE; C; 1EAF; # LATIN CAPITAL LETTER A WITH BREVE AND ACUTE
7431EB0; C; 1EB1; # LATIN CAPITAL LETTER A WITH BREVE AND GRAVE
7441EB2; C; 1EB3; # LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE
7451EB4; C; 1EB5; # LATIN CAPITAL LETTER A WITH BREVE AND TILDE
7461EB6; C; 1EB7; # LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW
7471EB8; C; 1EB9; # LATIN CAPITAL LETTER E WITH DOT BELOW
7481EBA; C; 1EBB; # LATIN CAPITAL LETTER E WITH HOOK ABOVE
7491EBC; C; 1EBD; # LATIN CAPITAL LETTER E WITH TILDE
7501EBE; C; 1EBF; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE
7511EC0; C; 1EC1; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE
7521EC2; C; 1EC3; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
7531EC4; C; 1EC5; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE
7541EC6; C; 1EC7; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW
7551EC8; C; 1EC9; # LATIN CAPITAL LETTER I WITH HOOK ABOVE
7561ECA; C; 1ECB; # LATIN CAPITAL LETTER I WITH DOT BELOW
7571ECC; C; 1ECD; # LATIN CAPITAL LETTER O WITH DOT BELOW
7581ECE; C; 1ECF; # LATIN CAPITAL LETTER O WITH HOOK ABOVE
7591ED0; C; 1ED1; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE
7601ED2; C; 1ED3; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE
7611ED4; C; 1ED5; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
7621ED6; C; 1ED7; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE
7631ED8; C; 1ED9; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW
7641EDA; C; 1EDB; # LATIN CAPITAL LETTER O WITH HORN AND ACUTE
7651EDC; C; 1EDD; # LATIN CAPITAL LETTER O WITH HORN AND GRAVE
7661EDE; C; 1EDF; # LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE
7671EE0; C; 1EE1; # LATIN CAPITAL LETTER O WITH HORN AND TILDE
7681EE2; C; 1EE3; # LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW
7691EE4; C; 1EE5; # LATIN CAPITAL LETTER U WITH DOT BELOW
7701EE6; C; 1EE7; # LATIN CAPITAL LETTER U WITH HOOK ABOVE
7711EE8; C; 1EE9; # LATIN CAPITAL LETTER U WITH HORN AND ACUTE
7721EEA; C; 1EEB; # LATIN CAPITAL LETTER U WITH HORN AND GRAVE
7731EEC; C; 1EED; # LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE
7741EEE; C; 1EEF; # LATIN CAPITAL LETTER U WITH HORN AND TILDE
7751EF0; C; 1EF1; # LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW
7761EF2; C; 1EF3; # LATIN CAPITAL LETTER Y WITH GRAVE
7771EF4; C; 1EF5; # LATIN CAPITAL LETTER Y WITH DOT BELOW
7781EF6; C; 1EF7; # LATIN CAPITAL LETTER Y WITH HOOK ABOVE
7791EF8; C; 1EF9; # LATIN CAPITAL LETTER Y WITH TILDE
7801EFA; C; 1EFB; # LATIN CAPITAL LETTER MIDDLE-WELSH LL
7811EFC; C; 1EFD; # LATIN CAPITAL LETTER MIDDLE-WELSH V
7821EFE; C; 1EFF; # LATIN CAPITAL LETTER Y WITH LOOP
7831F08; C; 1F00; # GREEK CAPITAL LETTER ALPHA WITH PSILI
7841F09; C; 1F01; # GREEK CAPITAL LETTER ALPHA WITH DASIA
7851F0A; C; 1F02; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA
7861F0B; C; 1F03; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA
7871F0C; C; 1F04; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA
7881F0D; C; 1F05; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA
7891F0E; C; 1F06; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI
7901F0F; C; 1F07; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI
7911F18; C; 1F10; # GREEK CAPITAL LETTER EPSILON WITH PSILI
7921F19; C; 1F11; # GREEK CAPITAL LETTER EPSILON WITH DASIA
7931F1A; C; 1F12; # GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA
7941F1B; C; 1F13; # GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA
7951F1C; C; 1F14; # GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA
7961F1D; C; 1F15; # GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
7971F28; C; 1F20; # GREEK CAPITAL LETTER ETA WITH PSILI
7981F29; C; 1F21; # GREEK CAPITAL LETTER ETA WITH DASIA
7991F2A; C; 1F22; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA
8001F2B; C; 1F23; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA
8011F2C; C; 1F24; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA
8021F2D; C; 1F25; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA
8031F2E; C; 1F26; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI
8041F2F; C; 1F27; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI
8051F38; C; 1F30; # GREEK CAPITAL LETTER IOTA WITH PSILI
8061F39; C; 1F31; # GREEK CAPITAL LETTER IOTA WITH DASIA
8071F3A; C; 1F32; # GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA
8081F3B; C; 1F33; # GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA
8091F3C; C; 1F34; # GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA
8101F3D; C; 1F35; # GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA
8111F3E; C; 1F36; # GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI
8121F3F; C; 1F37; # GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI
8131F48; C; 1F40; # GREEK CAPITAL LETTER OMICRON WITH PSILI
8141F49; C; 1F41; # GREEK CAPITAL LETTER OMICRON WITH DASIA
8151F4A; C; 1F42; # GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA
8161F4B; C; 1F43; # GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA
8171F4C; C; 1F44; # GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA
8181F4D; C; 1F45; # GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
8191F50; F; 03C5 0313; # GREEK SMALL LETTER UPSILON WITH PSILI
8201F52; F; 03C5 0313 0300; # GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA
8211F54; F; 03C5 0313 0301; # GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA
8221F56; F; 03C5 0313 0342; # GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI
8231F59; C; 1F51; # GREEK CAPITAL LETTER UPSILON WITH DASIA
8241F5B; C; 1F53; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
8251F5D; C; 1F55; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
8261F5F; C; 1F57; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI
8271F68; C; 1F60; # GREEK CAPITAL LETTER OMEGA WITH PSILI
8281F69; C; 1F61; # GREEK CAPITAL LETTER OMEGA WITH DASIA
8291F6A; C; 1F62; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA
8301F6B; C; 1F63; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA
8311F6C; C; 1F64; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA
8321F6D; C; 1F65; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA
8331F6E; C; 1F66; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI
8341F6F; C; 1F67; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI
8351F80; F; 1F00 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI
8361F81; F; 1F01 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI
8371F82; F; 1F02 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI
8381F83; F; 1F03 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI
8391F84; F; 1F04 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI
8401F85; F; 1F05 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI
8411F86; F; 1F06 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
8421F87; F; 1F07 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
8431F88; F; 1F00 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI
8441F88; S; 1F80; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI
8451F89; F; 1F01 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI
8461F89; S; 1F81; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI
8471F8A; F; 1F02 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI
8481F8A; S; 1F82; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI
8491F8B; F; 1F03 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI
8501F8B; S; 1F83; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI
8511F8C; F; 1F04 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI
8521F8C; S; 1F84; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI
8531F8D; F; 1F05 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI
8541F8D; S; 1F85; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI
8551F8E; F; 1F06 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
8561F8E; S; 1F86; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
8571F8F; F; 1F07 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
8581F8F; S; 1F87; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
8591F90; F; 1F20 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI
8601F91; F; 1F21 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI
8611F92; F; 1F22 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI
8621F93; F; 1F23 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI
8631F94; F; 1F24 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI
8641F95; F; 1F25 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI
8651F96; F; 1F26 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
8661F97; F; 1F27 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
8671F98; F; 1F20 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI
8681F98; S; 1F90; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI
8691F99; F; 1F21 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI
8701F99; S; 1F91; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI
8711F9A; F; 1F22 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI
8721F9A; S; 1F92; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI
8731F9B; F; 1F23 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI
8741F9B; S; 1F93; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI
8751F9C; F; 1F24 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI
8761F9C; S; 1F94; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI
8771F9D; F; 1F25 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI
8781F9D; S; 1F95; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI
8791F9E; F; 1F26 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
8801F9E; S; 1F96; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
8811F9F; F; 1F27 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
8821F9F; S; 1F97; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
8831FA0; F; 1F60 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI
8841FA1; F; 1F61 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI
8851FA2; F; 1F62 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI
8861FA3; F; 1F63 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI
8871FA4; F; 1F64 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI
8881FA5; F; 1F65 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI
8891FA6; F; 1F66 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
8901FA7; F; 1F67 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
8911FA8; F; 1F60 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI
8921FA8; S; 1FA0; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI
8931FA9; F; 1F61 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI
8941FA9; S; 1FA1; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI
8951FAA; F; 1F62 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI
8961FAA; S; 1FA2; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI
8971FAB; F; 1F63 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI
8981FAB; S; 1FA3; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI
8991FAC; F; 1F64 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI
9001FAC; S; 1FA4; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI
9011FAD; F; 1F65 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI
9021FAD; S; 1FA5; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI
9031FAE; F; 1F66 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
9041FAE; S; 1FA6; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
9051FAF; F; 1F67 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
9061FAF; S; 1FA7; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
9071FB2; F; 1F70 03B9; # GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI
9081FB3; F; 03B1 03B9; # GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI
9091FB4; F; 03AC 03B9; # GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
9101FB6; F; 03B1 0342; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI
9111FB7; F; 03B1 0342 03B9; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI
9121FB8; C; 1FB0; # GREEK CAPITAL LETTER ALPHA WITH VRACHY
9131FB9; C; 1FB1; # GREEK CAPITAL LETTER ALPHA WITH MACRON
9141FBA; C; 1F70; # GREEK CAPITAL LETTER ALPHA WITH VARIA
9151FBB; C; 1F71; # GREEK CAPITAL LETTER ALPHA WITH OXIA
9161FBC; F; 03B1 03B9; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
9171FBC; S; 1FB3; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
9181FBE; C; 03B9; # GREEK PROSGEGRAMMENI
9191FC2; F; 1F74 03B9; # GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI
9201FC3; F; 03B7 03B9; # GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI
9211FC4; F; 03AE 03B9; # GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
9221FC6; F; 03B7 0342; # GREEK SMALL LETTER ETA WITH PERISPOMENI
9231FC7; F; 03B7 0342 03B9; # GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI
9241FC8; C; 1F72; # GREEK CAPITAL LETTER EPSILON WITH VARIA
9251FC9; C; 1F73; # GREEK CAPITAL LETTER EPSILON WITH OXIA
9261FCA; C; 1F74; # GREEK CAPITAL LETTER ETA WITH VARIA
9271FCB; C; 1F75; # GREEK CAPITAL LETTER ETA WITH OXIA
9281FCC; F; 03B7 03B9; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
9291FCC; S; 1FC3; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
9301FD2; F; 03B9 0308 0300; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA
9311FD3; F; 03B9 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
9321FD3; S; 0390; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
9331FD6; F; 03B9 0342; # GREEK SMALL LETTER IOTA WITH PERISPOMENI
9341FD7; F; 03B9 0308 0342; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI
9351FD8; C; 1FD0; # GREEK CAPITAL LETTER IOTA WITH VRACHY
9361FD9; C; 1FD1; # GREEK CAPITAL LETTER IOTA WITH MACRON
9371FDA; C; 1F76; # GREEK CAPITAL LETTER IOTA WITH VARIA
9381FDB; C; 1F77; # GREEK CAPITAL LETTER IOTA WITH OXIA
9391FE2; F; 03C5 0308 0300; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA
9401FE3; F; 03C5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA
9411FE3; S; 03B0; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA
9421FE4; F; 03C1 0313; # GREEK SMALL LETTER RHO WITH PSILI
9431FE6; F; 03C5 0342; # GREEK SMALL LETTER UPSILON WITH PERISPOMENI
9441FE7; F; 03C5 0308 0342; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI
9451FE8; C; 1FE0; # GREEK CAPITAL LETTER UPSILON WITH VRACHY
9461FE9; C; 1FE1; # GREEK CAPITAL LETTER UPSILON WITH MACRON
9471FEA; C; 1F7A; # GREEK CAPITAL LETTER UPSILON WITH VARIA
9481FEB; C; 1F7B; # GREEK CAPITAL LETTER UPSILON WITH OXIA
9491FEC; C; 1FE5; # GREEK CAPITAL LETTER RHO WITH DASIA
9501FF2; F; 1F7C 03B9; # GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI
9511FF3; F; 03C9 03B9; # GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI
9521FF4; F; 03CE 03B9; # GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
9531FF6; F; 03C9 0342; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI
9541FF7; F; 03C9 0342 03B9; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI
9551FF8; C; 1F78; # GREEK CAPITAL LETTER OMICRON WITH VARIA
9561FF9; C; 1F79; # GREEK CAPITAL LETTER OMICRON WITH OXIA
9571FFA; C; 1F7C; # GREEK CAPITAL LETTER OMEGA WITH VARIA
9581FFB; C; 1F7D; # GREEK CAPITAL LETTER OMEGA WITH OXIA
9591FFC; F; 03C9 03B9; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
9601FFC; S; 1FF3; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
9612126; C; 03C9; # OHM SIGN
962212A; C; 006B; # KELVIN SIGN
963212B; C; 00E5; # ANGSTROM SIGN
9642132; C; 214E; # TURNED CAPITAL F
9652160; C; 2170; # ROMAN NUMERAL ONE
9662161; C; 2171; # ROMAN NUMERAL TWO
9672162; C; 2172; # ROMAN NUMERAL THREE
9682163; C; 2173; # ROMAN NUMERAL FOUR
9692164; C; 2174; # ROMAN NUMERAL FIVE
9702165; C; 2175; # ROMAN NUMERAL SIX
9712166; C; 2176; # ROMAN NUMERAL SEVEN
9722167; C; 2177; # ROMAN NUMERAL EIGHT
9732168; C; 2178; # ROMAN NUMERAL NINE
9742169; C; 2179; # ROMAN NUMERAL TEN
975216A; C; 217A; # ROMAN NUMERAL ELEVEN
976216B; C; 217B; # ROMAN NUMERAL TWELVE
977216C; C; 217C; # ROMAN NUMERAL FIFTY
978216D; C; 217D; # ROMAN NUMERAL ONE HUNDRED
979216E; C; 217E; # ROMAN NUMERAL FIVE HUNDRED
980216F; C; 217F; # ROMAN NUMERAL ONE THOUSAND
9812183; C; 2184; # ROMAN NUMERAL REVERSED ONE HUNDRED
98224B6; C; 24D0; # CIRCLED LATIN CAPITAL LETTER A
98324B7; C; 24D1; # CIRCLED LATIN CAPITAL LETTER B
98424B8; C; 24D2; # CIRCLED LATIN CAPITAL LETTER C
98524B9; C; 24D3; # CIRCLED LATIN CAPITAL LETTER D
98624BA; C; 24D4; # CIRCLED LATIN CAPITAL LETTER E
98724BB; C; 24D5; # CIRCLED LATIN CAPITAL LETTER F
98824BC; C; 24D6; # CIRCLED LATIN CAPITAL LETTER G
98924BD; C; 24D7; # CIRCLED LATIN CAPITAL LETTER H
99024BE; C; 24D8; # CIRCLED LATIN CAPITAL LETTER I
99124BF; C; 24D9; # CIRCLED LATIN CAPITAL LETTER J
99224C0; C; 24DA; # CIRCLED LATIN CAPITAL LETTER K
99324C1; C; 24DB; # CIRCLED LATIN CAPITAL LETTER L
99424C2; C; 24DC; # CIRCLED LATIN CAPITAL LETTER M
99524C3; C; 24DD; # CIRCLED LATIN CAPITAL LETTER N
99624C4; C; 24DE; # CIRCLED LATIN CAPITAL LETTER O
99724C5; C; 24DF; # CIRCLED LATIN CAPITAL LETTER P
99824C6; C; 24E0; # CIRCLED LATIN CAPITAL LETTER Q
99924C7; C; 24E1; # CIRCLED LATIN CAPITAL LETTER R
100024C8; C; 24E2; # CIRCLED LATIN CAPITAL LETTER S
100124C9; C; 24E3; # CIRCLED LATIN CAPITAL LETTER T
100224CA; C; 24E4; # CIRCLED LATIN CAPITAL LETTER U
100324CB; C; 24E5; # CIRCLED LATIN CAPITAL LETTER V
100424CC; C; 24E6; # CIRCLED LATIN CAPITAL LETTER W
100524CD; C; 24E7; # CIRCLED LATIN CAPITAL LETTER X
100624CE; C; 24E8; # CIRCLED LATIN CAPITAL LETTER Y
100724CF; C; 24E9; # CIRCLED LATIN CAPITAL LETTER Z
10082C00; C; 2C30; # GLAGOLITIC CAPITAL LETTER AZU
10092C01; C; 2C31; # GLAGOLITIC CAPITAL LETTER BUKY
10102C02; C; 2C32; # GLAGOLITIC CAPITAL LETTER VEDE
10112C03; C; 2C33; # GLAGOLITIC CAPITAL LETTER GLAGOLI
10122C04; C; 2C34; # GLAGOLITIC CAPITAL LETTER DOBRO
10132C05; C; 2C35; # GLAGOLITIC CAPITAL LETTER YESTU
10142C06; C; 2C36; # GLAGOLITIC CAPITAL LETTER ZHIVETE
10152C07; C; 2C37; # GLAGOLITIC CAPITAL LETTER DZELO
10162C08; C; 2C38; # GLAGOLITIC CAPITAL LETTER ZEMLJA
10172C09; C; 2C39; # GLAGOLITIC CAPITAL LETTER IZHE
10182C0A; C; 2C3A; # GLAGOLITIC CAPITAL LETTER INITIAL IZHE
10192C0B; C; 2C3B; # GLAGOLITIC CAPITAL LETTER I
10202C0C; C; 2C3C; # GLAGOLITIC CAPITAL LETTER DJERVI
10212C0D; C; 2C3D; # GLAGOLITIC CAPITAL LETTER KAKO
10222C0E; C; 2C3E; # GLAGOLITIC CAPITAL LETTER LJUDIJE
10232C0F; C; 2C3F; # GLAGOLITIC CAPITAL LETTER MYSLITE
10242C10; C; 2C40; # GLAGOLITIC CAPITAL LETTER NASHI
10252C11; C; 2C41; # GLAGOLITIC CAPITAL LETTER ONU
10262C12; C; 2C42; # GLAGOLITIC CAPITAL LETTER POKOJI
10272C13; C; 2C43; # GLAGOLITIC CAPITAL LETTER RITSI
10282C14; C; 2C44; # GLAGOLITIC CAPITAL LETTER SLOVO
10292C15; C; 2C45; # GLAGOLITIC CAPITAL LETTER TVRIDO
10302C16; C; 2C46; # GLAGOLITIC CAPITAL LETTER UKU
10312C17; C; 2C47; # GLAGOLITIC CAPITAL LETTER FRITU
10322C18; C; 2C48; # GLAGOLITIC CAPITAL LETTER HERU
10332C19; C; 2C49; # GLAGOLITIC CAPITAL LETTER OTU
10342C1A; C; 2C4A; # GLAGOLITIC CAPITAL LETTER PE
10352C1B; C; 2C4B; # GLAGOLITIC CAPITAL LETTER SHTA
10362C1C; C; 2C4C; # GLAGOLITIC CAPITAL LETTER TSI
10372C1D; C; 2C4D; # GLAGOLITIC CAPITAL LETTER CHRIVI
10382C1E; C; 2C4E; # GLAGOLITIC CAPITAL LETTER SHA
10392C1F; C; 2C4F; # GLAGOLITIC CAPITAL LETTER YERU
10402C20; C; 2C50; # GLAGOLITIC CAPITAL LETTER YERI
10412C21; C; 2C51; # GLAGOLITIC CAPITAL LETTER YATI
10422C22; C; 2C52; # GLAGOLITIC CAPITAL LETTER SPIDERY HA
10432C23; C; 2C53; # GLAGOLITIC CAPITAL LETTER YU
10442C24; C; 2C54; # GLAGOLITIC CAPITAL LETTER SMALL YUS
10452C25; C; 2C55; # GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL
10462C26; C; 2C56; # GLAGOLITIC CAPITAL LETTER YO
10472C27; C; 2C57; # GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS
10482C28; C; 2C58; # GLAGOLITIC CAPITAL LETTER BIG YUS
10492C29; C; 2C59; # GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS
10502C2A; C; 2C5A; # GLAGOLITIC CAPITAL LETTER FITA
10512C2B; C; 2C5B; # GLAGOLITIC CAPITAL LETTER IZHITSA
10522C2C; C; 2C5C; # GLAGOLITIC CAPITAL LETTER SHTAPIC
10532C2D; C; 2C5D; # GLAGOLITIC CAPITAL LETTER TROKUTASTI A
10542C2E; C; 2C5E; # GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
10552C2F; C; 2C5F; # GLAGOLITIC CAPITAL LETTER CAUDATE CHRIVI
10562C60; C; 2C61; # LATIN CAPITAL LETTER L WITH DOUBLE BAR
10572C62; C; 026B; # LATIN CAPITAL LETTER L WITH MIDDLE TILDE
10582C63; C; 1D7D; # LATIN CAPITAL LETTER P WITH STROKE
10592C64; C; 027D; # LATIN CAPITAL LETTER R WITH TAIL
10602C67; C; 2C68; # LATIN CAPITAL LETTER H WITH DESCENDER
10612C69; C; 2C6A; # LATIN CAPITAL LETTER K WITH DESCENDER
10622C6B; C; 2C6C; # LATIN CAPITAL LETTER Z WITH DESCENDER
10632C6D; C; 0251; # LATIN CAPITAL LETTER ALPHA
10642C6E; C; 0271; # LATIN CAPITAL LETTER M WITH HOOK
10652C6F; C; 0250; # LATIN CAPITAL LETTER TURNED A
10662C70; C; 0252; # LATIN CAPITAL LETTER TURNED ALPHA
10672C72; C; 2C73; # LATIN CAPITAL LETTER W WITH HOOK
10682C75; C; 2C76; # LATIN CAPITAL LETTER HALF H
10692C7E; C; 023F; # LATIN CAPITAL LETTER S WITH SWASH TAIL
10702C7F; C; 0240; # LATIN CAPITAL LETTER Z WITH SWASH TAIL
10712C80; C; 2C81; # COPTIC CAPITAL LETTER ALFA
10722C82; C; 2C83; # COPTIC CAPITAL LETTER VIDA
10732C84; C; 2C85; # COPTIC CAPITAL LETTER GAMMA
10742C86; C; 2C87; # COPTIC CAPITAL LETTER DALDA
10752C88; C; 2C89; # COPTIC CAPITAL LETTER EIE
10762C8A; C; 2C8B; # COPTIC CAPITAL LETTER SOU
10772C8C; C; 2C8D; # COPTIC CAPITAL LETTER ZATA
10782C8E; C; 2C8F; # COPTIC CAPITAL LETTER HATE
10792C90; C; 2C91; # COPTIC CAPITAL LETTER THETHE
10802C92; C; 2C93; # COPTIC CAPITAL LETTER IAUDA
10812C94; C; 2C95; # COPTIC CAPITAL LETTER KAPA
10822C96; C; 2C97; # COPTIC CAPITAL LETTER LAULA
10832C98; C; 2C99; # COPTIC CAPITAL LETTER MI
10842C9A; C; 2C9B; # COPTIC CAPITAL LETTER NI
10852C9C; C; 2C9D; # COPTIC CAPITAL LETTER KSI
10862C9E; C; 2C9F; # COPTIC CAPITAL LETTER O
10872CA0; C; 2CA1; # COPTIC CAPITAL LETTER PI
10882CA2; C; 2CA3; # COPTIC CAPITAL LETTER RO
10892CA4; C; 2CA5; # COPTIC CAPITAL LETTER SIMA
10902CA6; C; 2CA7; # COPTIC CAPITAL LETTER TAU
10912CA8; C; 2CA9; # COPTIC CAPITAL LETTER UA
10922CAA; C; 2CAB; # COPTIC CAPITAL LETTER FI
10932CAC; C; 2CAD; # COPTIC CAPITAL LETTER KHI
10942CAE; C; 2CAF; # COPTIC CAPITAL LETTER PSI
10952CB0; C; 2CB1; # COPTIC CAPITAL LETTER OOU
10962CB2; C; 2CB3; # COPTIC CAPITAL LETTER DIALECT-P ALEF
10972CB4; C; 2CB5; # COPTIC CAPITAL LETTER OLD COPTIC AIN
10982CB6; C; 2CB7; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE
10992CB8; C; 2CB9; # COPTIC CAPITAL LETTER DIALECT-P KAPA
11002CBA; C; 2CBB; # COPTIC CAPITAL LETTER DIALECT-P NI
11012CBC; C; 2CBD; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI
11022CBE; C; 2CBF; # COPTIC CAPITAL LETTER OLD COPTIC OOU
11032CC0; C; 2CC1; # COPTIC CAPITAL LETTER SAMPI
11042CC2; C; 2CC3; # COPTIC CAPITAL LETTER CROSSED SHEI
11052CC4; C; 2CC5; # COPTIC CAPITAL LETTER OLD COPTIC SHEI
11062CC6; C; 2CC7; # COPTIC CAPITAL LETTER OLD COPTIC ESH
11072CC8; C; 2CC9; # COPTIC CAPITAL LETTER AKHMIMIC KHEI
11082CCA; C; 2CCB; # COPTIC CAPITAL LETTER DIALECT-P HORI
11092CCC; C; 2CCD; # COPTIC CAPITAL LETTER OLD COPTIC HORI
11102CCE; C; 2CCF; # COPTIC CAPITAL LETTER OLD COPTIC HA
11112CD0; C; 2CD1; # COPTIC CAPITAL LETTER L-SHAPED HA
11122CD2; C; 2CD3; # COPTIC CAPITAL LETTER OLD COPTIC HEI
11132CD4; C; 2CD5; # COPTIC CAPITAL LETTER OLD COPTIC HAT
11142CD6; C; 2CD7; # COPTIC CAPITAL LETTER OLD COPTIC GANGIA
11152CD8; C; 2CD9; # COPTIC CAPITAL LETTER OLD COPTIC DJA
11162CDA; C; 2CDB; # COPTIC CAPITAL LETTER OLD COPTIC SHIMA
11172CDC; C; 2CDD; # COPTIC CAPITAL LETTER OLD NUBIAN SHIMA
11182CDE; C; 2CDF; # COPTIC CAPITAL LETTER OLD NUBIAN NGI
11192CE0; C; 2CE1; # COPTIC CAPITAL LETTER OLD NUBIAN NYI
11202CE2; C; 2CE3; # COPTIC CAPITAL LETTER OLD NUBIAN WAU
11212CEB; C; 2CEC; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI
11222CED; C; 2CEE; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIA
11232CF2; C; 2CF3; # COPTIC CAPITAL LETTER BOHAIRIC KHEI
1124A640; C; A641; # CYRILLIC CAPITAL LETTER ZEMLYA
1125A642; C; A643; # CYRILLIC CAPITAL LETTER DZELO
1126A644; C; A645; # CYRILLIC CAPITAL LETTER REVERSED DZE
1127A646; C; A647; # CYRILLIC CAPITAL LETTER IOTA
1128A648; C; A649; # CYRILLIC CAPITAL LETTER DJERV
1129A64A; C; A64B; # CYRILLIC CAPITAL LETTER MONOGRAPH UK
1130A64C; C; A64D; # CYRILLIC CAPITAL LETTER BROAD OMEGA
1131A64E; C; A64F; # CYRILLIC CAPITAL LETTER NEUTRAL YER
1132A650; C; A651; # CYRILLIC CAPITAL LETTER YERU WITH BACK YER
1133A652; C; A653; # CYRILLIC CAPITAL LETTER IOTIFIED YAT
1134A654; C; A655; # CYRILLIC CAPITAL LETTER REVERSED YU
1135A656; C; A657; # CYRILLIC CAPITAL LETTER IOTIFIED A
1136A658; C; A659; # CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS
1137A65A; C; A65B; # CYRILLIC CAPITAL LETTER BLENDED YUS
1138A65C; C; A65D; # CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS
1139A65E; C; A65F; # CYRILLIC CAPITAL LETTER YN
1140A660; C; A661; # CYRILLIC CAPITAL LETTER REVERSED TSE
1141A662; C; A663; # CYRILLIC CAPITAL LETTER SOFT DE
1142A664; C; A665; # CYRILLIC CAPITAL LETTER SOFT EL
1143A666; C; A667; # CYRILLIC CAPITAL LETTER SOFT EM
1144A668; C; A669; # CYRILLIC CAPITAL LETTER MONOCULAR O
1145A66A; C; A66B; # CYRILLIC CAPITAL LETTER BINOCULAR O
1146A66C; C; A66D; # CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O
1147A680; C; A681; # CYRILLIC CAPITAL LETTER DWE
1148A682; C; A683; # CYRILLIC CAPITAL LETTER DZWE
1149A684; C; A685; # CYRILLIC CAPITAL LETTER ZHWE
1150A686; C; A687; # CYRILLIC CAPITAL LETTER CCHE
1151A688; C; A689; # CYRILLIC CAPITAL LETTER DZZE
1152A68A; C; A68B; # CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK
1153A68C; C; A68D; # CYRILLIC CAPITAL LETTER TWE
1154A68E; C; A68F; # CYRILLIC CAPITAL LETTER TSWE
1155A690; C; A691; # CYRILLIC CAPITAL LETTER TSSE
1156A692; C; A693; # CYRILLIC CAPITAL LETTER TCHE
1157A694; C; A695; # CYRILLIC CAPITAL LETTER HWE
1158A696; C; A697; # CYRILLIC CAPITAL LETTER SHWE
1159A698; C; A699; # CYRILLIC CAPITAL LETTER DOUBLE O
1160A69A; C; A69B; # CYRILLIC CAPITAL LETTER CROSSED O
1161A722; C; A723; # LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF
1162A724; C; A725; # LATIN CAPITAL LETTER EGYPTOLOGICAL AIN
1163A726; C; A727; # LATIN CAPITAL LETTER HENG
1164A728; C; A729; # LATIN CAPITAL LETTER TZ
1165A72A; C; A72B; # LATIN CAPITAL LETTER TRESILLO
1166A72C; C; A72D; # LATIN CAPITAL LETTER CUATRILLO
1167A72E; C; A72F; # LATIN CAPITAL LETTER CUATRILLO WITH COMMA
1168A732; C; A733; # LATIN CAPITAL LETTER AA
1169A734; C; A735; # LATIN CAPITAL LETTER AO
1170A736; C; A737; # LATIN CAPITAL LETTER AU
1171A738; C; A739; # LATIN CAPITAL LETTER AV
1172A73A; C; A73B; # LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR
1173A73C; C; A73D; # LATIN CAPITAL LETTER AY
1174A73E; C; A73F; # LATIN CAPITAL LETTER REVERSED C WITH DOT
1175A740; C; A741; # LATIN CAPITAL LETTER K WITH STROKE
1176A742; C; A743; # LATIN CAPITAL LETTER K WITH DIAGONAL STROKE
1177A744; C; A745; # LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE
1178A746; C; A747; # LATIN CAPITAL LETTER BROKEN L
1179A748; C; A749; # LATIN CAPITAL LETTER L WITH HIGH STROKE
1180A74A; C; A74B; # LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY
1181A74C; C; A74D; # LATIN CAPITAL LETTER O WITH LOOP
1182A74E; C; A74F; # LATIN CAPITAL LETTER OO
1183A750; C; A751; # LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER
1184A752; C; A753; # LATIN CAPITAL LETTER P WITH FLOURISH
1185A754; C; A755; # LATIN CAPITAL LETTER P WITH SQUIRREL TAIL
1186A756; C; A757; # LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER
1187A758; C; A759; # LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE
1188A75A; C; A75B; # LATIN CAPITAL LETTER R ROTUNDA
1189A75C; C; A75D; # LATIN CAPITAL LETTER RUM ROTUNDA
1190A75E; C; A75F; # LATIN CAPITAL LETTER V WITH DIAGONAL STROKE
1191A760; C; A761; # LATIN CAPITAL LETTER VY
1192A762; C; A763; # LATIN CAPITAL LETTER VISIGOTHIC Z
1193A764; C; A765; # LATIN CAPITAL LETTER THORN WITH STROKE
1194A766; C; A767; # LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER
1195A768; C; A769; # LATIN CAPITAL LETTER VEND
1196A76A; C; A76B; # LATIN CAPITAL LETTER ET
1197A76C; C; A76D; # LATIN CAPITAL LETTER IS
1198A76E; C; A76F; # LATIN CAPITAL LETTER CON
1199A779; C; A77A; # LATIN CAPITAL LETTER INSULAR D
1200A77B; C; A77C; # LATIN CAPITAL LETTER INSULAR F
1201A77D; C; 1D79; # LATIN CAPITAL LETTER INSULAR G
1202A77E; C; A77F; # LATIN CAPITAL LETTER TURNED INSULAR G
1203A780; C; A781; # LATIN CAPITAL LETTER TURNED L
1204A782; C; A783; # LATIN CAPITAL LETTER INSULAR R
1205A784; C; A785; # LATIN CAPITAL LETTER INSULAR S
1206A786; C; A787; # LATIN CAPITAL LETTER INSULAR T
1207A78B; C; A78C; # LATIN CAPITAL LETTER SALTILLO
1208A78D; C; 0265; # LATIN CAPITAL LETTER TURNED H
1209A790; C; A791; # LATIN CAPITAL LETTER N WITH DESCENDER
1210A792; C; A793; # LATIN CAPITAL LETTER C WITH BAR
1211A796; C; A797; # LATIN CAPITAL LETTER B WITH FLOURISH
1212A798; C; A799; # LATIN CAPITAL LETTER F WITH STROKE
1213A79A; C; A79B; # LATIN CAPITAL LETTER VOLAPUK AE
1214A79C; C; A79D; # LATIN CAPITAL LETTER VOLAPUK OE
1215A79E; C; A79F; # LATIN CAPITAL LETTER VOLAPUK UE
1216A7A0; C; A7A1; # LATIN CAPITAL LETTER G WITH OBLIQUE STROKE
1217A7A2; C; A7A3; # LATIN CAPITAL LETTER K WITH OBLIQUE STROKE
1218A7A4; C; A7A5; # LATIN CAPITAL LETTER N WITH OBLIQUE STROKE
1219A7A6; C; A7A7; # LATIN CAPITAL LETTER R WITH OBLIQUE STROKE
1220A7A8; C; A7A9; # LATIN CAPITAL LETTER S WITH OBLIQUE STROKE
1221A7AA; C; 0266; # LATIN CAPITAL LETTER H WITH HOOK
1222A7AB; C; 025C; # LATIN CAPITAL LETTER REVERSED OPEN E
1223A7AC; C; 0261; # LATIN CAPITAL LETTER SCRIPT G
1224A7AD; C; 026C; # LATIN CAPITAL LETTER L WITH BELT
1225A7AE; C; 026A; # LATIN CAPITAL LETTER SMALL CAPITAL I
1226A7B0; C; 029E; # LATIN CAPITAL LETTER TURNED K
1227A7B1; C; 0287; # LATIN CAPITAL LETTER TURNED T
1228A7B2; C; 029D; # LATIN CAPITAL LETTER J WITH CROSSED-TAIL
1229A7B3; C; AB53; # LATIN CAPITAL LETTER CHI
1230A7B4; C; A7B5; # LATIN CAPITAL LETTER BETA
1231A7B6; C; A7B7; # LATIN CAPITAL LETTER OMEGA
1232A7B8; C; A7B9; # LATIN CAPITAL LETTER U WITH STROKE
1233A7BA; C; A7BB; # LATIN CAPITAL LETTER GLOTTAL A
1234A7BC; C; A7BD; # LATIN CAPITAL LETTER GLOTTAL I
1235A7BE; C; A7BF; # LATIN CAPITAL LETTER GLOTTAL U
1236A7C0; C; A7C1; # LATIN CAPITAL LETTER OLD POLISH O
1237A7C2; C; A7C3; # LATIN CAPITAL LETTER ANGLICANA W
1238A7C4; C; A794; # LATIN CAPITAL LETTER C WITH PALATAL HOOK
1239A7C5; C; 0282; # LATIN CAPITAL LETTER S WITH HOOK
1240A7C6; C; 1D8E; # LATIN CAPITAL LETTER Z WITH PALATAL HOOK
1241A7C7; C; A7C8; # LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY
1242A7C9; C; A7CA; # LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY
1243A7D0; C; A7D1; # LATIN CAPITAL LETTER CLOSED INSULAR G
1244A7D6; C; A7D7; # LATIN CAPITAL LETTER MIDDLE SCOTS S
1245A7D8; C; A7D9; # LATIN CAPITAL LETTER SIGMOID S
1246A7F5; C; A7F6; # LATIN CAPITAL LETTER REVERSED HALF H
1247AB70; C; 13A0; # CHEROKEE SMALL LETTER A
1248AB71; C; 13A1; # CHEROKEE SMALL LETTER E
1249AB72; C; 13A2; # CHEROKEE SMALL LETTER I
1250AB73; C; 13A3; # CHEROKEE SMALL LETTER O
1251AB74; C; 13A4; # CHEROKEE SMALL LETTER U
1252AB75; C; 13A5; # CHEROKEE SMALL LETTER V
1253AB76; C; 13A6; # CHEROKEE SMALL LETTER GA
1254AB77; C; 13A7; # CHEROKEE SMALL LETTER KA
1255AB78; C; 13A8; # CHEROKEE SMALL LETTER GE
1256AB79; C; 13A9; # CHEROKEE SMALL LETTER GI
1257AB7A; C; 13AA; # CHEROKEE SMALL LETTER GO
1258AB7B; C; 13AB; # CHEROKEE SMALL LETTER GU
1259AB7C; C; 13AC; # CHEROKEE SMALL LETTER GV
1260AB7D; C; 13AD; # CHEROKEE SMALL LETTER HA
1261AB7E; C; 13AE; # CHEROKEE SMALL LETTER HE
1262AB7F; C; 13AF; # CHEROKEE SMALL LETTER HI
1263AB80; C; 13B0; # CHEROKEE SMALL LETTER HO
1264AB81; C; 13B1; # CHEROKEE SMALL LETTER HU
1265AB82; C; 13B2; # CHEROKEE SMALL LETTER HV
1266AB83; C; 13B3; # CHEROKEE SMALL LETTER LA
1267AB84; C; 13B4; # CHEROKEE SMALL LETTER LE
1268AB85; C; 13B5; # CHEROKEE SMALL LETTER LI
1269AB86; C; 13B6; # CHEROKEE SMALL LETTER LO
1270AB87; C; 13B7; # CHEROKEE SMALL LETTER LU
1271AB88; C; 13B8; # CHEROKEE SMALL LETTER LV
1272AB89; C; 13B9; # CHEROKEE SMALL LETTER MA
1273AB8A; C; 13BA; # CHEROKEE SMALL LETTER ME
1274AB8B; C; 13BB; # CHEROKEE SMALL LETTER MI
1275AB8C; C; 13BC; # CHEROKEE SMALL LETTER MO
1276AB8D; C; 13BD; # CHEROKEE SMALL LETTER MU
1277AB8E; C; 13BE; # CHEROKEE SMALL LETTER NA
1278AB8F; C; 13BF; # CHEROKEE SMALL LETTER HNA
1279AB90; C; 13C0; # CHEROKEE SMALL LETTER NAH
1280AB91; C; 13C1; # CHEROKEE SMALL LETTER NE
1281AB92; C; 13C2; # CHEROKEE SMALL LETTER NI
1282AB93; C; 13C3; # CHEROKEE SMALL LETTER NO
1283AB94; C; 13C4; # CHEROKEE SMALL LETTER NU
1284AB95; C; 13C5; # CHEROKEE SMALL LETTER NV
1285AB96; C; 13C6; # CHEROKEE SMALL LETTER QUA
1286AB97; C; 13C7; # CHEROKEE SMALL LETTER QUE
1287AB98; C; 13C8; # CHEROKEE SMALL LETTER QUI
1288AB99; C; 13C9; # CHEROKEE SMALL LETTER QUO
1289AB9A; C; 13CA; # CHEROKEE SMALL LETTER QUU
1290AB9B; C; 13CB; # CHEROKEE SMALL LETTER QUV
1291AB9C; C; 13CC; # CHEROKEE SMALL LETTER SA
1292AB9D; C; 13CD; # CHEROKEE SMALL LETTER S
1293AB9E; C; 13CE; # CHEROKEE SMALL LETTER SE
1294AB9F; C; 13CF; # CHEROKEE SMALL LETTER SI
1295ABA0; C; 13D0; # CHEROKEE SMALL LETTER SO
1296ABA1; C; 13D1; # CHEROKEE SMALL LETTER SU
1297ABA2; C; 13D2; # CHEROKEE SMALL LETTER SV
1298ABA3; C; 13D3; # CHEROKEE SMALL LETTER DA
1299ABA4; C; 13D4; # CHEROKEE SMALL LETTER TA
1300ABA5; C; 13D5; # CHEROKEE SMALL LETTER DE
1301ABA6; C; 13D6; # CHEROKEE SMALL LETTER TE
1302ABA7; C; 13D7; # CHEROKEE SMALL LETTER DI
1303ABA8; C; 13D8; # CHEROKEE SMALL LETTER TI
1304ABA9; C; 13D9; # CHEROKEE SMALL LETTER DO
1305ABAA; C; 13DA; # CHEROKEE SMALL LETTER DU
1306ABAB; C; 13DB; # CHEROKEE SMALL LETTER DV
1307ABAC; C; 13DC; # CHEROKEE SMALL LETTER DLA
1308ABAD; C; 13DD; # CHEROKEE SMALL LETTER TLA
1309ABAE; C; 13DE; # CHEROKEE SMALL LETTER TLE
1310ABAF; C; 13DF; # CHEROKEE SMALL LETTER TLI
1311ABB0; C; 13E0; # CHEROKEE SMALL LETTER TLO
1312ABB1; C; 13E1; # CHEROKEE SMALL LETTER TLU
1313ABB2; C; 13E2; # CHEROKEE SMALL LETTER TLV
1314ABB3; C; 13E3; # CHEROKEE SMALL LETTER TSA
1315ABB4; C; 13E4; # CHEROKEE SMALL LETTER TSE
1316ABB5; C; 13E5; # CHEROKEE SMALL LETTER TSI
1317ABB6; C; 13E6; # CHEROKEE SMALL LETTER TSO
1318ABB7; C; 13E7; # CHEROKEE SMALL LETTER TSU
1319ABB8; C; 13E8; # CHEROKEE SMALL LETTER TSV
1320ABB9; C; 13E9; # CHEROKEE SMALL LETTER WA
1321ABBA; C; 13EA; # CHEROKEE SMALL LETTER WE
1322ABBB; C; 13EB; # CHEROKEE SMALL LETTER WI
1323ABBC; C; 13EC; # CHEROKEE SMALL LETTER WO
1324ABBD; C; 13ED; # CHEROKEE SMALL LETTER WU
1325ABBE; C; 13EE; # CHEROKEE SMALL LETTER WV
1326ABBF; C; 13EF; # CHEROKEE SMALL LETTER YA
1327FB00; F; 0066 0066; # LATIN SMALL LIGATURE FF
1328FB01; F; 0066 0069; # LATIN SMALL LIGATURE FI
1329FB02; F; 0066 006C; # LATIN SMALL LIGATURE FL
1330FB03; F; 0066 0066 0069; # LATIN SMALL LIGATURE FFI
1331FB04; F; 0066 0066 006C; # LATIN SMALL LIGATURE FFL
1332FB05; F; 0073 0074; # LATIN SMALL LIGATURE LONG S T
1333FB05; S; FB06; # LATIN SMALL LIGATURE LONG S T
1334FB06; F; 0073 0074; # LATIN SMALL LIGATURE ST
1335FB13; F; 0574 0576; # ARMENIAN SMALL LIGATURE MEN NOW
1336FB14; F; 0574 0565; # ARMENIAN SMALL LIGATURE MEN ECH
1337FB15; F; 0574 056B; # ARMENIAN SMALL LIGATURE MEN INI
1338FB16; F; 057E 0576; # ARMENIAN SMALL LIGATURE VEW NOW
1339FB17; F; 0574 056D; # ARMENIAN SMALL LIGATURE MEN XEH
1340FF21; C; FF41; # FULLWIDTH LATIN CAPITAL LETTER A
1341FF22; C; FF42; # FULLWIDTH LATIN CAPITAL LETTER B
1342FF23; C; FF43; # FULLWIDTH LATIN CAPITAL LETTER C
1343FF24; C; FF44; # FULLWIDTH LATIN CAPITAL LETTER D
1344FF25; C; FF45; # FULLWIDTH LATIN CAPITAL LETTER E
1345FF26; C; FF46; # FULLWIDTH LATIN CAPITAL LETTER F
1346FF27; C; FF47; # FULLWIDTH LATIN CAPITAL LETTER G
1347FF28; C; FF48; # FULLWIDTH LATIN CAPITAL LETTER H
1348FF29; C; FF49; # FULLWIDTH LATIN CAPITAL LETTER I
1349FF2A; C; FF4A; # FULLWIDTH LATIN CAPITAL LETTER J
1350FF2B; C; FF4B; # FULLWIDTH LATIN CAPITAL LETTER K
1351FF2C; C; FF4C; # FULLWIDTH LATIN CAPITAL LETTER L
1352FF2D; C; FF4D; # FULLWIDTH LATIN CAPITAL LETTER M
1353FF2E; C; FF4E; # FULLWIDTH LATIN CAPITAL LETTER N
1354FF2F; C; FF4F; # FULLWIDTH LATIN CAPITAL LETTER O
1355FF30; C; FF50; # FULLWIDTH LATIN CAPITAL LETTER P
1356FF31; C; FF51; # FULLWIDTH LATIN CAPITAL LETTER Q
1357FF32; C; FF52; # FULLWIDTH LATIN CAPITAL LETTER R
1358FF33; C; FF53; # FULLWIDTH LATIN CAPITAL LETTER S
1359FF34; C; FF54; # FULLWIDTH LATIN CAPITAL LETTER T
1360FF35; C; FF55; # FULLWIDTH LATIN CAPITAL LETTER U
1361FF36; C; FF56; # FULLWIDTH LATIN CAPITAL LETTER V
1362FF37; C; FF57; # FULLWIDTH LATIN CAPITAL LETTER W
1363FF38; C; FF58; # FULLWIDTH LATIN CAPITAL LETTER X
1364FF39; C; FF59; # FULLWIDTH LATIN CAPITAL LETTER Y
1365FF3A; C; FF5A; # FULLWIDTH LATIN CAPITAL LETTER Z
136610400; C; 10428; # DESERET CAPITAL LETTER LONG I
136710401; C; 10429; # DESERET CAPITAL LETTER LONG E
136810402; C; 1042A; # DESERET CAPITAL LETTER LONG A
136910403; C; 1042B; # DESERET CAPITAL LETTER LONG AH
137010404; C; 1042C; # DESERET CAPITAL LETTER LONG O
137110405; C; 1042D; # DESERET CAPITAL LETTER LONG OO
137210406; C; 1042E; # DESERET CAPITAL LETTER SHORT I
137310407; C; 1042F; # DESERET CAPITAL LETTER SHORT E
137410408; C; 10430; # DESERET CAPITAL LETTER SHORT A
137510409; C; 10431; # DESERET CAPITAL LETTER SHORT AH
13761040A; C; 10432; # DESERET CAPITAL LETTER SHORT O
13771040B; C; 10433; # DESERET CAPITAL LETTER SHORT OO
13781040C; C; 10434; # DESERET CAPITAL LETTER AY
13791040D; C; 10435; # DESERET CAPITAL LETTER OW
13801040E; C; 10436; # DESERET CAPITAL LETTER WU
13811040F; C; 10437; # DESERET CAPITAL LETTER YEE
138210410; C; 10438; # DESERET CAPITAL LETTER H
138310411; C; 10439; # DESERET CAPITAL LETTER PEE
138410412; C; 1043A; # DESERET CAPITAL LETTER BEE
138510413; C; 1043B; # DESERET CAPITAL LETTER TEE
138610414; C; 1043C; # DESERET CAPITAL LETTER DEE
138710415; C; 1043D; # DESERET CAPITAL LETTER CHEE
138810416; C; 1043E; # DESERET CAPITAL LETTER JEE
138910417; C; 1043F; # DESERET CAPITAL LETTER KAY
139010418; C; 10440; # DESERET CAPITAL LETTER GAY
139110419; C; 10441; # DESERET CAPITAL LETTER EF
13921041A; C; 10442; # DESERET CAPITAL LETTER VEE
13931041B; C; 10443; # DESERET CAPITAL LETTER ETH
13941041C; C; 10444; # DESERET CAPITAL LETTER THEE
13951041D; C; 10445; # DESERET CAPITAL LETTER ES
13961041E; C; 10446; # DESERET CAPITAL LETTER ZEE
13971041F; C; 10447; # DESERET CAPITAL LETTER ESH
139810420; C; 10448; # DESERET CAPITAL LETTER ZHEE
139910421; C; 10449; # DESERET CAPITAL LETTER ER
140010422; C; 1044A; # DESERET CAPITAL LETTER EL
140110423; C; 1044B; # DESERET CAPITAL LETTER EM
140210424; C; 1044C; # DESERET CAPITAL LETTER EN
140310425; C; 1044D; # DESERET CAPITAL LETTER ENG
140410426; C; 1044E; # DESERET CAPITAL LETTER OI
140510427; C; 1044F; # DESERET CAPITAL LETTER EW
1406104B0; C; 104D8; # OSAGE CAPITAL LETTER A
1407104B1; C; 104D9; # OSAGE CAPITAL LETTER AI
1408104B2; C; 104DA; # OSAGE CAPITAL LETTER AIN
1409104B3; C; 104DB; # OSAGE CAPITAL LETTER AH
1410104B4; C; 104DC; # OSAGE CAPITAL LETTER BRA
1411104B5; C; 104DD; # OSAGE CAPITAL LETTER CHA
1412104B6; C; 104DE; # OSAGE CAPITAL LETTER EHCHA
1413104B7; C; 104DF; # OSAGE CAPITAL LETTER E
1414104B8; C; 104E0; # OSAGE CAPITAL LETTER EIN
1415104B9; C; 104E1; # OSAGE CAPITAL LETTER HA
1416104BA; C; 104E2; # OSAGE CAPITAL LETTER HYA
1417104BB; C; 104E3; # OSAGE CAPITAL LETTER I
1418104BC; C; 104E4; # OSAGE CAPITAL LETTER KA
1419104BD; C; 104E5; # OSAGE CAPITAL LETTER EHKA
1420104BE; C; 104E6; # OSAGE CAPITAL LETTER KYA
1421104BF; C; 104E7; # OSAGE CAPITAL LETTER LA
1422104C0; C; 104E8; # OSAGE CAPITAL LETTER MA
1423104C1; C; 104E9; # OSAGE CAPITAL LETTER NA
1424104C2; C; 104EA; # OSAGE CAPITAL LETTER O
1425104C3; C; 104EB; # OSAGE CAPITAL LETTER OIN
1426104C4; C; 104EC; # OSAGE CAPITAL LETTER PA
1427104C5; C; 104ED; # OSAGE CAPITAL LETTER EHPA
1428104C6; C; 104EE; # OSAGE CAPITAL LETTER SA
1429104C7; C; 104EF; # OSAGE CAPITAL LETTER SHA
1430104C8; C; 104F0; # OSAGE CAPITAL LETTER TA
1431104C9; C; 104F1; # OSAGE CAPITAL LETTER EHTA
1432104CA; C; 104F2; # OSAGE CAPITAL LETTER TSA
1433104CB; C; 104F3; # OSAGE CAPITAL LETTER EHTSA
1434104CC; C; 104F4; # OSAGE CAPITAL LETTER TSHA
1435104CD; C; 104F5; # OSAGE CAPITAL LETTER DHA
1436104CE; C; 104F6; # OSAGE CAPITAL LETTER U
1437104CF; C; 104F7; # OSAGE CAPITAL LETTER WA
1438104D0; C; 104F8; # OSAGE CAPITAL LETTER KHA
1439104D1; C; 104F9; # OSAGE CAPITAL LETTER GHA
1440104D2; C; 104FA; # OSAGE CAPITAL LETTER ZA
1441104D3; C; 104FB; # OSAGE CAPITAL LETTER ZHA
144210570; C; 10597; # VITHKUQI CAPITAL LETTER A
144310571; C; 10598; # VITHKUQI CAPITAL LETTER BBE
144410572; C; 10599; # VITHKUQI CAPITAL LETTER BE
144510573; C; 1059A; # VITHKUQI CAPITAL LETTER CE
144610574; C; 1059B; # VITHKUQI CAPITAL LETTER CHE
144710575; C; 1059C; # VITHKUQI CAPITAL LETTER DE
144810576; C; 1059D; # VITHKUQI CAPITAL LETTER DHE
144910577; C; 1059E; # VITHKUQI CAPITAL LETTER EI
145010578; C; 1059F; # VITHKUQI CAPITAL LETTER E
145110579; C; 105A0; # VITHKUQI CAPITAL LETTER FE
14521057A; C; 105A1; # VITHKUQI CAPITAL LETTER GA
14531057C; C; 105A3; # VITHKUQI CAPITAL LETTER HA
14541057D; C; 105A4; # VITHKUQI CAPITAL LETTER HHA
14551057E; C; 105A5; # VITHKUQI CAPITAL LETTER I
14561057F; C; 105A6; # VITHKUQI CAPITAL LETTER IJE
145710580; C; 105A7; # VITHKUQI CAPITAL LETTER JE
145810581; C; 105A8; # VITHKUQI CAPITAL LETTER KA
145910582; C; 105A9; # VITHKUQI CAPITAL LETTER LA
146010583; C; 105AA; # VITHKUQI CAPITAL LETTER LLA
146110584; C; 105AB; # VITHKUQI CAPITAL LETTER ME
146210585; C; 105AC; # VITHKUQI CAPITAL LETTER NE
146310586; C; 105AD; # VITHKUQI CAPITAL LETTER NJE
146410587; C; 105AE; # VITHKUQI CAPITAL LETTER O
146510588; C; 105AF; # VITHKUQI CAPITAL LETTER PE
146610589; C; 105B0; # VITHKUQI CAPITAL LETTER QA
14671058A; C; 105B1; # VITHKUQI CAPITAL LETTER RE
14681058C; C; 105B3; # VITHKUQI CAPITAL LETTER SE
14691058D; C; 105B4; # VITHKUQI CAPITAL LETTER SHE
14701058E; C; 105B5; # VITHKUQI CAPITAL LETTER TE
14711058F; C; 105B6; # VITHKUQI CAPITAL LETTER THE
147210590; C; 105B7; # VITHKUQI CAPITAL LETTER U
147310591; C; 105B8; # VITHKUQI CAPITAL LETTER VE
147410592; C; 105B9; # VITHKUQI CAPITAL LETTER XE
147510594; C; 105BB; # VITHKUQI CAPITAL LETTER Y
147610595; C; 105BC; # VITHKUQI CAPITAL LETTER ZE
147710C80; C; 10CC0; # OLD HUNGARIAN CAPITAL LETTER A
147810C81; C; 10CC1; # OLD HUNGARIAN CAPITAL LETTER AA
147910C82; C; 10CC2; # OLD HUNGARIAN CAPITAL LETTER EB
148010C83; C; 10CC3; # OLD HUNGARIAN CAPITAL LETTER AMB
148110C84; C; 10CC4; # OLD HUNGARIAN CAPITAL LETTER EC
148210C85; C; 10CC5; # OLD HUNGARIAN CAPITAL LETTER ENC
148310C86; C; 10CC6; # OLD HUNGARIAN CAPITAL LETTER ECS
148410C87; C; 10CC7; # OLD HUNGARIAN CAPITAL LETTER ED
148510C88; C; 10CC8; # OLD HUNGARIAN CAPITAL LETTER AND
148610C89; C; 10CC9; # OLD HUNGARIAN CAPITAL LETTER E
148710C8A; C; 10CCA; # OLD HUNGARIAN CAPITAL LETTER CLOSE E
148810C8B; C; 10CCB; # OLD HUNGARIAN CAPITAL LETTER EE
148910C8C; C; 10CCC; # OLD HUNGARIAN CAPITAL LETTER EF
149010C8D; C; 10CCD; # OLD HUNGARIAN CAPITAL LETTER EG
149110C8E; C; 10CCE; # OLD HUNGARIAN CAPITAL LETTER EGY
149210C8F; C; 10CCF; # OLD HUNGARIAN CAPITAL LETTER EH
149310C90; C; 10CD0; # OLD HUNGARIAN CAPITAL LETTER I
149410C91; C; 10CD1; # OLD HUNGARIAN CAPITAL LETTER II
149510C92; C; 10CD2; # OLD HUNGARIAN CAPITAL LETTER EJ
149610C93; C; 10CD3; # OLD HUNGARIAN CAPITAL LETTER EK
149710C94; C; 10CD4; # OLD HUNGARIAN CAPITAL LETTER AK
149810C95; C; 10CD5; # OLD HUNGARIAN CAPITAL LETTER UNK
149910C96; C; 10CD6; # OLD HUNGARIAN CAPITAL LETTER EL
150010C97; C; 10CD7; # OLD HUNGARIAN CAPITAL LETTER ELY
150110C98; C; 10CD8; # OLD HUNGARIAN CAPITAL LETTER EM
150210C99; C; 10CD9; # OLD HUNGARIAN CAPITAL LETTER EN
150310C9A; C; 10CDA; # OLD HUNGARIAN CAPITAL LETTER ENY
150410C9B; C; 10CDB; # OLD HUNGARIAN CAPITAL LETTER O
150510C9C; C; 10CDC; # OLD HUNGARIAN CAPITAL LETTER OO
150610C9D; C; 10CDD; # OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG OE
150710C9E; C; 10CDE; # OLD HUNGARIAN CAPITAL LETTER RUDIMENTA OE
150810C9F; C; 10CDF; # OLD HUNGARIAN CAPITAL LETTER OEE
150910CA0; C; 10CE0; # OLD HUNGARIAN CAPITAL LETTER EP
151010CA1; C; 10CE1; # OLD HUNGARIAN CAPITAL LETTER EMP
151110CA2; C; 10CE2; # OLD HUNGARIAN CAPITAL LETTER ER
151210CA3; C; 10CE3; # OLD HUNGARIAN CAPITAL LETTER SHORT ER
151310CA4; C; 10CE4; # OLD HUNGARIAN CAPITAL LETTER ES
151410CA5; C; 10CE5; # OLD HUNGARIAN CAPITAL LETTER ESZ
151510CA6; C; 10CE6; # OLD HUNGARIAN CAPITAL LETTER ET
151610CA7; C; 10CE7; # OLD HUNGARIAN CAPITAL LETTER ENT
151710CA8; C; 10CE8; # OLD HUNGARIAN CAPITAL LETTER ETY
151810CA9; C; 10CE9; # OLD HUNGARIAN CAPITAL LETTER ECH
151910CAA; C; 10CEA; # OLD HUNGARIAN CAPITAL LETTER U
152010CAB; C; 10CEB; # OLD HUNGARIAN CAPITAL LETTER UU
152110CAC; C; 10CEC; # OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG UE
152210CAD; C; 10CED; # OLD HUNGARIAN CAPITAL LETTER RUDIMENTA UE
152310CAE; C; 10CEE; # OLD HUNGARIAN CAPITAL LETTER EV
152410CAF; C; 10CEF; # OLD HUNGARIAN CAPITAL LETTER EZ
152510CB0; C; 10CF0; # OLD HUNGARIAN CAPITAL LETTER EZS
152610CB1; C; 10CF1; # OLD HUNGARIAN CAPITAL LETTER ENT-SHAPED SIGN
152710CB2; C; 10CF2; # OLD HUNGARIAN CAPITAL LETTER US
1528118A0; C; 118C0; # WARANG CITI CAPITAL LETTER NGAA
1529118A1; C; 118C1; # WARANG CITI CAPITAL LETTER A
1530118A2; C; 118C2; # WARANG CITI CAPITAL LETTER WI
1531118A3; C; 118C3; # WARANG CITI CAPITAL LETTER YU
1532118A4; C; 118C4; # WARANG CITI CAPITAL LETTER YA
1533118A5; C; 118C5; # WARANG CITI CAPITAL LETTER YO
1534118A6; C; 118C6; # WARANG CITI CAPITAL LETTER II
1535118A7; C; 118C7; # WARANG CITI CAPITAL LETTER UU
1536118A8; C; 118C8; # WARANG CITI CAPITAL LETTER E
1537118A9; C; 118C9; # WARANG CITI CAPITAL LETTER O
1538118AA; C; 118CA; # WARANG CITI CAPITAL LETTER ANG
1539118AB; C; 118CB; # WARANG CITI CAPITAL LETTER GA
1540118AC; C; 118CC; # WARANG CITI CAPITAL LETTER KO
1541118AD; C; 118CD; # WARANG CITI CAPITAL LETTER ENY
1542118AE; C; 118CE; # WARANG CITI CAPITAL LETTER YUJ
1543118AF; C; 118CF; # WARANG CITI CAPITAL LETTER UC
1544118B0; C; 118D0; # WARANG CITI CAPITAL LETTER ENN
1545118B1; C; 118D1; # WARANG CITI CAPITAL LETTER ODD
1546118B2; C; 118D2; # WARANG CITI CAPITAL LETTER TTE
1547118B3; C; 118D3; # WARANG CITI CAPITAL LETTER NUNG
1548118B4; C; 118D4; # WARANG CITI CAPITAL LETTER DA
1549118B5; C; 118D5; # WARANG CITI CAPITAL LETTER AT
1550118B6; C; 118D6; # WARANG CITI CAPITAL LETTER AM
1551118B7; C; 118D7; # WARANG CITI CAPITAL LETTER BU
1552118B8; C; 118D8; # WARANG CITI CAPITAL LETTER PU
1553118B9; C; 118D9; # WARANG CITI CAPITAL LETTER HIYO
1554118BA; C; 118DA; # WARANG CITI CAPITAL LETTER HOLO
1555118BB; C; 118DB; # WARANG CITI CAPITAL LETTER HORR
1556118BC; C; 118DC; # WARANG CITI CAPITAL LETTER HAR
1557118BD; C; 118DD; # WARANG CITI CAPITAL LETTER SSUU
1558118BE; C; 118DE; # WARANG CITI CAPITAL LETTER SII
1559118BF; C; 118DF; # WARANG CITI CAPITAL LETTER VIYO
156016E40; C; 16E60; # MEDEFAIDRIN CAPITAL LETTER M
156116E41; C; 16E61; # MEDEFAIDRIN CAPITAL LETTER S
156216E42; C; 16E62; # MEDEFAIDRIN CAPITAL LETTER V
156316E43; C; 16E63; # MEDEFAIDRIN CAPITAL LETTER W
156416E44; C; 16E64; # MEDEFAIDRIN CAPITAL LETTER ATIU
156516E45; C; 16E65; # MEDEFAIDRIN CAPITAL LETTER Z
156616E46; C; 16E66; # MEDEFAIDRIN CAPITAL LETTER KP
156716E47; C; 16E67; # MEDEFAIDRIN CAPITAL LETTER P
156816E48; C; 16E68; # MEDEFAIDRIN CAPITAL LETTER T
156916E49; C; 16E69; # MEDEFAIDRIN CAPITAL LETTER G
157016E4A; C; 16E6A; # MEDEFAIDRIN CAPITAL LETTER F
157116E4B; C; 16E6B; # MEDEFAIDRIN CAPITAL LETTER I
157216E4C; C; 16E6C; # MEDEFAIDRIN CAPITAL LETTER K
157316E4D; C; 16E6D; # MEDEFAIDRIN CAPITAL LETTER A
157416E4E; C; 16E6E; # MEDEFAIDRIN CAPITAL LETTER J
157516E4F; C; 16E6F; # MEDEFAIDRIN CAPITAL LETTER E
157616E50; C; 16E70; # MEDEFAIDRIN CAPITAL LETTER B
157716E51; C; 16E71; # MEDEFAIDRIN CAPITAL LETTER C
157816E52; C; 16E72; # MEDEFAIDRIN CAPITAL LETTER U
157916E53; C; 16E73; # MEDEFAIDRIN CAPITAL LETTER YU
158016E54; C; 16E74; # MEDEFAIDRIN CAPITAL LETTER L
158116E55; C; 16E75; # MEDEFAIDRIN CAPITAL LETTER Q
158216E56; C; 16E76; # MEDEFAIDRIN CAPITAL LETTER HP
158316E57; C; 16E77; # MEDEFAIDRIN CAPITAL LETTER NY
158416E58; C; 16E78; # MEDEFAIDRIN CAPITAL LETTER X
158516E59; C; 16E79; # MEDEFAIDRIN CAPITAL LETTER D
158616E5A; C; 16E7A; # MEDEFAIDRIN CAPITAL LETTER OE
158716E5B; C; 16E7B; # MEDEFAIDRIN CAPITAL LETTER N
158816E5C; C; 16E7C; # MEDEFAIDRIN CAPITAL LETTER R
158916E5D; C; 16E7D; # MEDEFAIDRIN CAPITAL LETTER O
159016E5E; C; 16E7E; # MEDEFAIDRIN CAPITAL LETTER AI
159116E5F; C; 16E7F; # MEDEFAIDRIN CAPITAL LETTER Y
15921E900; C; 1E922; # ADLAM CAPITAL LETTER ALIF
15931E901; C; 1E923; # ADLAM CAPITAL LETTER DAALI
15941E902; C; 1E924; # ADLAM CAPITAL LETTER LAAM
15951E903; C; 1E925; # ADLAM CAPITAL LETTER MIIM
15961E904; C; 1E926; # ADLAM CAPITAL LETTER BA
15971E905; C; 1E927; # ADLAM CAPITAL LETTER SINNYIIYHE
15981E906; C; 1E928; # ADLAM CAPITAL LETTER PE
15991E907; C; 1E929; # ADLAM CAPITAL LETTER BHE
16001E908; C; 1E92A; # ADLAM CAPITAL LETTER RA
16011E909; C; 1E92B; # ADLAM CAPITAL LETTER E
16021E90A; C; 1E92C; # ADLAM CAPITAL LETTER FA
16031E90B; C; 1E92D; # ADLAM CAPITAL LETTER I
16041E90C; C; 1E92E; # ADLAM CAPITAL LETTER O
16051E90D; C; 1E92F; # ADLAM CAPITAL LETTER DHA
16061E90E; C; 1E930; # ADLAM CAPITAL LETTER YHE
16071E90F; C; 1E931; # ADLAM CAPITAL LETTER WAW
16081E910; C; 1E932; # ADLAM CAPITAL LETTER NUN
16091E911; C; 1E933; # ADLAM CAPITAL LETTER KAF
16101E912; C; 1E934; # ADLAM CAPITAL LETTER YA
16111E913; C; 1E935; # ADLAM CAPITAL LETTER U
16121E914; C; 1E936; # ADLAM CAPITAL LETTER JIIM
16131E915; C; 1E937; # ADLAM CAPITAL LETTER CHI
16141E916; C; 1E938; # ADLAM CAPITAL LETTER HA
16151E917; C; 1E939; # ADLAM CAPITAL LETTER QAAF
16161E918; C; 1E93A; # ADLAM CAPITAL LETTER GA
16171E919; C; 1E93B; # ADLAM CAPITAL LETTER NYA
16181E91A; C; 1E93C; # ADLAM CAPITAL LETTER TU
16191E91B; C; 1E93D; # ADLAM CAPITAL LETTER NHA
16201E91C; C; 1E93E; # ADLAM CAPITAL LETTER VA
16211E91D; C; 1E93F; # ADLAM CAPITAL LETTER KHA
16221E91E; C; 1E940; # ADLAM CAPITAL LETTER GBE
16231E91F; C; 1E941; # ADLAM CAPITAL LETTER ZAL
16241E920; C; 1E942; # ADLAM CAPITAL LETTER KPO
16251E921; C; 1E943; # ADLAM CAPITAL LETTER SHA
1626#
1627# EOF
diff --git a/src/contrib/SDL-3.2.20/build-scripts/check_android_jni.py b/src/contrib/SDL-3.2.20/build-scripts/check_android_jni.py
new file mode 100755
index 0000000..9e519fb
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/check_android_jni.py
@@ -0,0 +1,172 @@
1#!/usr/bin/env python
2
3import argparse
4import dataclasses
5import os
6import pathlib
7import re
8
9ROOT = pathlib.Path(__file__).resolve().parents[1]
10SDL_ANDROID_C = ROOT / "src/core/android/SDL_android.c"
11METHOD_SOURCE_PATHS = (
12 SDL_ANDROID_C,
13 ROOT / "src/hidapi/android/hid.cpp",
14)
15JAVA_ROOT = ROOT / "android-project/app/src/main/java"
16
17
18BASIC_TYPE_SPEC_LUT = {
19 "char": "C",
20 "byte": "B",
21 "short": "S",
22 "int": "I",
23 "long": "J",
24 "float": "F",
25 "double": "D",
26 "void": "V",
27 "boolean": "Z",
28 "Object": "Ljava/lang/Object;",
29 "String": "Ljava/lang/String;",
30}
31
32
33@dataclasses.dataclass(frozen=True)
34class JniType:
35 typ: str
36 array: int
37
38
39def java_type_to_jni_spec_internal(type_str: str) -> tuple[int, str]:
40 for basic_type_str, basic_type_spec in BASIC_TYPE_SPEC_LUT.items():
41 if type_str.startswith(basic_type_str):
42 return len(basic_type_str), basic_type_spec
43 raise ValueError(f"Don't know how to convert {repr(type_str)} to its equivalent jni spec")
44
45
46def java_type_to_jni_spec(type_str: str) -> str:
47 end, type_spec = java_type_to_jni_spec_internal(type_str)
48 suffix_str = type_str[end:]
49 assert(all(c in "[] \t" for c in suffix_str))
50 suffix_str = "".join(filter(lambda v: v in "[]", suffix_str))
51 assert len(suffix_str) % 2 == 0
52 array_spec = "[" * (len(suffix_str) // 2)
53 return array_spec + type_spec
54
55
56def java_method_to_jni_spec(ret: str, args: list[str]) -> str:
57 return "(" + "".join(java_type_to_jni_spec(a) for a in args) +")" + java_type_to_jni_spec(ret)
58
59
60@dataclasses.dataclass(frozen=True)
61class JniMethodBinding:
62 name: str
63 spec: str
64
65
66def collect_jni_bindings_from_c() -> dict[str, set[JniMethodBinding]]:
67 bindings = {}
68
69 sdl_android_text = SDL_ANDROID_C.read_text()
70 for m in re.finditer(r"""register_methods\((?:[A-Za-z0-9]+),\s*"(?P<class>[a-zA-Z0-9_/]+)",\s*(?P<table>[a-zA-Z0-9_]+),\s*SDL_arraysize\((?P=table)\)\)""", sdl_android_text):
71 kls = m["class"]
72 table = m["table"]
73 methods = set()
74 in_struct = False
75 for method_source_path in METHOD_SOURCE_PATHS:
76 method_source = method_source_path.read_text()
77 for line in method_source.splitlines(keepends=False):
78 if re.match(f"(static )?JNINativeMethod {table}" + r"\[([0-9]+)?\] = \{", line):
79 in_struct = True
80 continue
81 if in_struct:
82 if re.match(r"\};", line):
83 in_struct = False
84 break
85 n = re.match(r"""\s*\{\s*"(?P<method>[a-zA-Z0-9_]+)"\s*,\s*"(?P<spec>[()A-Za-z0-9_/;[]+)"\s*,\s*(\(void\*\))?(HID|SDL)[_A-Z]*_JAVA_[_A-Z]*INTERFACE[_A-Z]*\((?P=method)\)\s*\},?""", line)
86 assert n, f"'{line}' does not match regex"
87 methods.add(JniMethodBinding(name=n["method"], spec=n["spec"]))
88 continue
89 if methods:
90 break
91 if methods:
92 break
93 assert methods, f"Could not find methods for {kls} (table={table})"
94
95 assert not in_struct
96
97 assert kls not in bindings, f"{kls} must be unique in C sources"
98 bindings[kls] = methods
99 return bindings
100
101def collect_jni_bindings_from_java() -> dict[str, set[JniMethodBinding]]:
102 bindings = {}
103
104 for root, _, files in os.walk(JAVA_ROOT):
105 for file in files:
106 file_path = pathlib.Path(root) / file
107 java_text = file_path.read_text()
108 methods = set()
109 for m in re.finditer(r"(?:(?:public|private)\s+)?(?:static\s+)?native\s+(?P<ret>[A-Za-z0-9_]+)\s+(?P<method>[a-zA-Z0-9_]+)\s*\(\s*(?P<args>[^)]*)\);", java_text):
110 name = m["method"]
111 ret = m["ret"]
112 args = []
113 args_str = m["args"].strip()
114 if args_str:
115 for a_s in args_str.split(","):
116 atype_str, _ = a_s.strip().rsplit(" ")
117 args.append(atype_str.strip())
118
119 spec = java_method_to_jni_spec(ret=ret, args=args)
120 methods.add(JniMethodBinding(name=name, spec=spec))
121 if methods:
122 relative_java_path = file_path.relative_to(JAVA_ROOT)
123 relative_java_path_without_suffix = relative_java_path.with_suffix("")
124 kls = "/".join(relative_java_path_without_suffix.parts)
125 assert kls not in bindings, f"{kls} must be unique in JAVA sources"
126 bindings[kls] = methods
127 return bindings
128
129
130def print_error(*args):
131 print("ERROR:", *args)
132
133
134def main():
135 parser = argparse.ArgumentParser(allow_abbrev=False, description="Verify Android JNI bindings")
136 args = parser.parse_args()
137
138 bindings_from_c = collect_jni_bindings_from_c()
139 bindings_from_java = collect_jni_bindings_from_java()
140
141 all_ok = bindings_from_c == bindings_from_java
142 if all_ok:
143 print("OK")
144 else:
145 print("NOT OK")
146 kls_c = set(bindings_from_c.keys())
147 kls_java = set(bindings_from_java.keys())
148 if kls_c != kls_java:
149 only_c = kls_c - kls_java
150 for c in only_c:
151 print_error(f"Missing class in JAVA sources: {c}")
152 only_java = kls_java - kls_c
153 for c in only_java:
154 print_error(f"Missing class in C sources: {c}")
155
156 klasses = kls_c.union(kls_java)
157 for kls in klasses:
158 m_c = bindings_from_c.get(kls)
159 m_j = bindings_from_java.get(kls)
160 if m_c and m_j and m_c != m_j:
161 m_only_c = m_c - m_j
162 for c in m_only_c:
163 print_error(f"{kls}: Binding only in C source: {c.name} {c.spec}")
164 m_only_j = m_j - m_c
165 for c in m_only_j:
166 print_error(f"{kls}: Binding only in JAVA source: {c.name} {c.spec}")
167
168 return 0 if all_ok else 1
169
170
171if __name__ == "__main__":
172 raise SystemExit(main())
diff --git a/src/contrib/SDL-3.2.20/build-scripts/check_stdlib_usage.py b/src/contrib/SDL-3.2.20/build-scripts/check_stdlib_usage.py
new file mode 100755
index 0000000..0994130
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/check_stdlib_usage.py
@@ -0,0 +1,262 @@
1#!/usr/bin/env python3
2#
3# Simple DirectMedia Layer
4# Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
5#
6# This software is provided 'as-is', without any express or implied
7# warranty. In no event will the authors be held liable for any damages
8# arising from the use of this software.
9#
10# Permission is granted to anyone to use this software for any purpose,
11# including commercial applications, and to alter it and redistribute it
12# freely, subject to the following restrictions:
13#
14# 1. The origin of this software must not be misrepresented; you must not
15# claim that you wrote the original software. If you use this software
16# in a product, an acknowledgment in the product documentation would be
17# appreciated but is not required.
18# 2. Altered source versions must be plainly marked as such, and must not be
19# misrepresented as being the original software.
20# 3. This notice may not be removed or altered from any source distribution.
21#
22# This script detects use of stdlib function in SDL code
23
24import argparse
25import os
26import pathlib
27import re
28import sys
29
30SDL_ROOT = pathlib.Path(__file__).resolve().parents[1]
31
32STDLIB_SYMBOLS = [
33 'abs',
34 'acos',
35 'acosf',
36 'asin',
37 'asinf',
38 'asprintf',
39 'atan',
40 'atan2',
41 'atan2f',
42 'atanf',
43 'atof',
44 'atoi',
45 'bsearch',
46 'calloc',
47 'ceil',
48 'ceilf',
49 'copysign',
50 'copysignf',
51 'cos',
52 'cosf',
53 'crc32',
54 'exp',
55 'expf',
56 'fabs',
57 'fabsf',
58 'floor',
59 'floorf',
60 'fmod',
61 'fmodf',
62 'free',
63 'getenv',
64 'isalnum',
65 'isalpha',
66 'isblank',
67 'iscntrl',
68 'isdigit',
69 'isgraph',
70 'islower',
71 'isprint',
72 'ispunct',
73 'isspace',
74 'isupper',
75 'isxdigit',
76 'itoa',
77 'lltoa',
78 'log10',
79 'log10f',
80 'logf',
81 'lround',
82 'lroundf',
83 'ltoa',
84 'malloc',
85 'memalign',
86 'memcmp',
87 'memcpy',
88 'memcpy4',
89 'memmove',
90 'memset',
91 'pow',
92 'powf',
93 'qsort',
94 'qsort_r',
95 'qsort_s',
96 'realloc',
97 'round',
98 'roundf',
99 'scalbn',
100 'scalbnf',
101 'setenv',
102 'sin',
103 'sinf',
104 'snprintf',
105 'sqrt',
106 'sqrtf',
107 'sscanf',
108 'strcasecmp',
109 'strchr',
110 'strcmp',
111 'strdup',
112 'strlcat',
113 'strlcpy',
114 'strlen',
115 'strlwr',
116 'strncasecmp',
117 'strncmp',
118 'strrchr',
119 'strrev',
120 'strstr',
121 'strtod',
122 'strtokr',
123 'strtol',
124 'strtoll',
125 'strtoul',
126 'strupr',
127 'tan',
128 'tanf',
129 'tolower',
130 'toupper',
131 'trunc',
132 'truncf',
133 'uitoa',
134 'ulltoa',
135 'ultoa',
136 'utf8strlcpy',
137 'utf8strlen',
138 'vasprintf',
139 'vsnprintf',
140 'vsscanf',
141 'wcscasecmp',
142 'wcscmp',
143 'wcsdup',
144 'wcslcat',
145 'wcslcpy',
146 'wcslen',
147 'wcsncasecmp',
148 'wcsncmp',
149 'wcsstr',
150]
151RE_STDLIB_SYMBOL = re.compile(rf"\b(?P<symbol>{'|'.join(STDLIB_SYMBOLS)})\b\(")
152
153
154def find_symbols_in_file(file: pathlib.Path) -> int:
155 match_count = 0
156
157 allowed_extensions = [ ".c", ".cpp", ".m", ".h", ".hpp", ".cc" ]
158
159 excluded_paths = [
160 "src/stdlib",
161 "src/libm",
162 "src/hidapi",
163 "src/video/khronos",
164 "src/video/stb_image.h",
165 "include/SDL3",
166 "build-scripts/gen_audio_resampler_filter.c",
167 "build-scripts/gen_audio_channel_conversion.c",
168 "test/win32/sdlprocdump.c",
169 ]
170
171 filename = pathlib.Path(file)
172
173 for ep in excluded_paths:
174 if ep in filename.as_posix():
175 # skip
176 return 0
177
178 if filename.suffix not in allowed_extensions:
179 # skip
180 return 0
181
182 # print("Parse %s" % file)
183
184 try:
185 with file.open("r", encoding="UTF-8", newline="") as rfp:
186 parsing_comment = False
187 for line_i, original_line in enumerate(rfp, start=1):
188 line = original_line.strip()
189
190 line_comment = ""
191
192 # Get the comment block /* ... */ across several lines
193 while True:
194 if parsing_comment:
195 pos_end_comment = line.find("*/")
196 if pos_end_comment >= 0:
197 line = line[pos_end_comment+2:]
198 parsing_comment = False
199 else:
200 break
201 else:
202 pos_start_comment = line.find("/*")
203 if pos_start_comment >= 0:
204 pos_end_comment = line.find("*/", pos_start_comment+2)
205 if pos_end_comment >= 0:
206 line_comment += line[pos_start_comment:pos_end_comment+2]
207 line = line[:pos_start_comment] + line[pos_end_comment+2:]
208 else:
209 line_comment += line[pos_start_comment:]
210 line = line[:pos_start_comment]
211 parsing_comment = True
212 break
213 else:
214 break
215 if parsing_comment:
216 continue
217 pos_line_comment = line.find("//")
218 if pos_line_comment >= 0:
219 line_comment += line[pos_line_comment:]
220 line = line[:pos_line_comment]
221
222 if m := RE_STDLIB_SYMBOL.match(line):
223 override_string = f"This should NOT be SDL_{m['symbol']}()"
224 if override_string not in line_comment:
225 print(f"{filename}:{line_i}")
226 print(f" {line}")
227 print(f"")
228 match_count += 1
229
230 except UnicodeDecodeError:
231 print(f"{file} is not text, skipping", file=sys.stderr)
232
233 return match_count
234
235def find_symbols_in_dir(path: pathlib.Path) -> int:
236 match_count = 0
237 for entry in path.glob("*"):
238 if entry.is_dir():
239 match_count += find_symbols_in_dir(entry)
240 else:
241 match_count += find_symbols_in_file(entry)
242 return match_count
243
244def main():
245 parser = argparse.ArgumentParser(fromfile_prefix_chars="@")
246 parser.add_argument("path", default=SDL_ROOT, nargs="?", type=pathlib.Path, help="Path to look for stdlib symbols")
247 args = parser.parse_args()
248
249 print(f"Looking for stdlib usage in {args.path}...")
250
251 match_count = find_symbols_in_dir(args.path)
252
253 if match_count:
254 print("If the stdlib usage is intentional, add a '// This should NOT be SDL_<symbol>()' line comment.")
255 print("")
256 print("NOT OK")
257 else:
258 print("OK")
259 return 1 if match_count else 0
260
261if __name__ == "__main__":
262 raise SystemExit(main())
diff --git a/src/contrib/SDL-3.2.20/build-scripts/clang-format-src.sh b/src/contrib/SDL-3.2.20/build-scripts/clang-format-src.sh
new file mode 100755
index 0000000..bc0defc
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/clang-format-src.sh
@@ -0,0 +1,39 @@
1#!/bin/sh
2
3cd "$(dirname $0)/../src"
4
5echo "Running clang-format in $(pwd)"
6
7find . -regex '.*\.[chm]p*' -exec clang-format -i {} \;
8
9# Revert third-party code
10git checkout \
11 events/imKStoUCS.* \
12 hidapi \
13 joystick/controller_type.c \
14 joystick/controller_type.h \
15 joystick/hidapi/steam/controller_constants.h \
16 joystick/hidapi/steam/controller_structs.h \
17 libm \
18 stdlib/SDL_malloc.c \
19 stdlib/SDL_qsort.c \
20 stdlib/SDL_strtokr.c \
21 video/khronos \
22 video/x11/edid.h \
23 video/x11/edid-parse.c \
24 video/x11/xsettings-client.* \
25 video/yuv2rgb
26clang-format -i hidapi/SDL_hidapi.c
27
28# Revert generated code
29git checkout \
30 dynapi/SDL_dynapi_overrides.h \
31 dynapi/SDL_dynapi_procs.h \
32 render/*/*Shader*.h \
33 render/metal/SDL_shaders_metal_*.h \
34 render/vitagxm/SDL_render_vita_gxm_shaders.h \
35 video/directx/SDL_d3d12_xbox_cmacros.h \
36 video/directx/d3d12.h \
37 video/directx/d3d12sdklayers.h \
38
39echo "clang-format complete!"
diff --git a/src/contrib/SDL-3.2.20/build-scripts/cmake-toolchain-mingw64-i686.cmake b/src/contrib/SDL-3.2.20/build-scripts/cmake-toolchain-mingw64-i686.cmake
new file mode 100644
index 0000000..8be7b3a
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/cmake-toolchain-mingw64-i686.cmake
@@ -0,0 +1,18 @@
1set(CMAKE_SYSTEM_NAME Windows)
2set(CMAKE_SYSTEM_PROCESSOR x86)
3
4find_program(CMAKE_C_COMPILER NAMES i686-w64-mingw32-gcc)
5find_program(CMAKE_CXX_COMPILER NAMES i686-w64-mingw32-g++)
6find_program(CMAKE_RC_COMPILER NAMES i686-w64-mingw32-windres windres)
7
8if(NOT CMAKE_C_COMPILER)
9 message(FATAL_ERROR "Failed to find CMAKE_C_COMPILER.")
10endif()
11
12if(NOT CMAKE_CXX_COMPILER)
13 message(FATAL_ERROR "Failed to find CMAKE_CXX_COMPILER.")
14endif()
15
16if(NOT CMAKE_RC_COMPILER)
17 message(FATAL_ERROR "Failed to find CMAKE_RC_COMPILER.")
18endif()
diff --git a/src/contrib/SDL-3.2.20/build-scripts/cmake-toolchain-mingw64-x86_64.cmake b/src/contrib/SDL-3.2.20/build-scripts/cmake-toolchain-mingw64-x86_64.cmake
new file mode 100644
index 0000000..8bf4366
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/cmake-toolchain-mingw64-x86_64.cmake
@@ -0,0 +1,18 @@
1set(CMAKE_SYSTEM_NAME Windows)
2set(CMAKE_SYSTEM_PROCESSOR x86_64)
3
4find_program(CMAKE_C_COMPILER NAMES x86_64-w64-mingw32-gcc)
5find_program(CMAKE_CXX_COMPILER NAMES x86_64-w64-mingw32-g++)
6find_program(CMAKE_RC_COMPILER NAMES x86_64-w64-mingw32-windres windres)
7
8if(NOT CMAKE_C_COMPILER)
9 message(FATAL_ERROR "Failed to find CMAKE_C_COMPILER.")
10endif()
11
12if(NOT CMAKE_CXX_COMPILER)
13 message(FATAL_ERROR "Failed to find CMAKE_CXX_COMPILER.")
14endif()
15
16if(NOT CMAKE_RC_COMPILER)
17 message(FATAL_ERROR "Failed to find CMAKE_RC_COMPILER.")
18endif()
diff --git a/src/contrib/SDL-3.2.20/build-scripts/cmake-toolchain-qnx-aarch64le.cmake b/src/contrib/SDL-3.2.20/build-scripts/cmake-toolchain-qnx-aarch64le.cmake
new file mode 100644
index 0000000..26f5da4
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/cmake-toolchain-qnx-aarch64le.cmake
@@ -0,0 +1,14 @@
1set(CMAKE_SYSTEM_NAME QNX)
2
3set(arch gcc_ntoaarch64le)
4
5set(CMAKE_C_COMPILER qcc)
6set(CMAKE_C_COMPILER_TARGET ${arch})
7set(CMAKE_CXX_COMPILER q++)
8set(CMAKE_CXX_COMPILER_TARGET ${arch})
9
10set(CMAKE_SYSROOT $ENV{QNX_TARGET})
11
12set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
13set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
14set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
diff --git a/src/contrib/SDL-3.2.20/build-scripts/cmake-toolchain-qnx-x86_64.cmake b/src/contrib/SDL-3.2.20/build-scripts/cmake-toolchain-qnx-x86_64.cmake
new file mode 100644
index 0000000..29f795a
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/cmake-toolchain-qnx-x86_64.cmake
@@ -0,0 +1,14 @@
1set(CMAKE_SYSTEM_NAME QNX)
2
3set(arch gcc_ntox86_64)
4
5set(CMAKE_C_COMPILER qcc)
6set(CMAKE_C_COMPILER_TARGET ${arch})
7set(CMAKE_CXX_COMPILER q++)
8set(CMAKE_CXX_COMPILER_TARGET ${arch})
9
10set(CMAKE_SYSROOT $ENV{QNX_TARGET})
11
12set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
13set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
14set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
diff --git a/src/contrib/SDL-3.2.20/build-scripts/codechecker-buildbot.sh b/src/contrib/SDL-3.2.20/build-scripts/codechecker-buildbot.sh
new file mode 100755
index 0000000..76b7853
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/codechecker-buildbot.sh
@@ -0,0 +1,59 @@
1#!/bin/bash
2
3# This is a script used by some Buildbot build workers to push the project
4# through Clang's static analyzer and prepare the output to be uploaded
5# back to the buildmaster. You might find it useful too.
6
7# Install Clang (you already have it on macOS, apt-get install clang
8# on Ubuntu, etc), install CMake, and pip3 install codechecker.
9
10FINALDIR="$1"
11
12set -x
13set -e
14
15cd `dirname "$0"`
16cd ..
17
18rm -rf codechecker-buildbot
19if [ ! -z "$FINALDIR" ]; then
20 rm -rf "$FINALDIR"
21fi
22
23mkdir codechecker-buildbot
24cd codechecker-buildbot
25
26# We turn off deprecated declarations, because we don't care about these warnings during static analysis.
27cmake -Wno-dev -DSDL_STATIC=OFF -DCMAKE_BUILD_TYPE=Debug -DSDL_ASSERTIONS=enabled -DCMAKE_C_FLAGS="-Wno-deprecated-declarations" -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ..
28
29# CMake on macOS adds "-arch arm64" or whatever is appropriate, but this confuses CodeChecker, so strip it out.
30perl -w -pi -e 's/\-arch\s+.*?\s+//g;' compile_commands.json
31
32rm -rf ../analysis
33CodeChecker analyze compile_commands.json -o ./reports
34
35# "parse" returns 2 if there was a static analysis issue to report, but this
36# does not signify an error in the parsing (that would be error code 1). Turn
37# off the abort-on-error flag.
38set +e
39CodeChecker parse ./reports -e html -o ../analysis
40set -e
41
42cd ..
43chmod -R a+r analysis
44chmod -R go-w analysis
45find analysis -type d -exec chmod a+x {} \;
46if [ -x /usr/bin/xattr ]; then find analysis -exec /usr/bin/xattr -d com.apple.quarantine {} \; 2>/dev/null ; fi
47
48if [ ! -z "$FINALDIR" ]; then
49 mv analysis "$FINALDIR"
50else
51 FINALDIR=analysis
52fi
53
54rm -rf codechecker-buildbot
55
56echo "Done. Final output is in '$FINALDIR' ..."
57
58# end of codechecker-buildbot.sh ...
59
diff --git a/src/contrib/SDL-3.2.20/build-scripts/create-android-project.py b/src/contrib/SDL-3.2.20/build-scripts/create-android-project.py
new file mode 100755
index 0000000..0b8994f
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/create-android-project.py
@@ -0,0 +1,241 @@
1#!/usr/bin/env python3
2import os
3from argparse import ArgumentParser
4from pathlib import Path
5import re
6import shutil
7import sys
8import textwrap
9
10
11SDL_ROOT = Path(__file__).resolve().parents[1]
12
13def extract_sdl_version() -> str:
14 """
15 Extract SDL version from SDL3/SDL_version.h
16 """
17
18 with open(SDL_ROOT / "include/SDL3/SDL_version.h") as f:
19 data = f.read()
20
21 major = int(next(re.finditer(r"#define\s+SDL_MAJOR_VERSION\s+([0-9]+)", data)).group(1))
22 minor = int(next(re.finditer(r"#define\s+SDL_MINOR_VERSION\s+([0-9]+)", data)).group(1))
23 micro = int(next(re.finditer(r"#define\s+SDL_MICRO_VERSION\s+([0-9]+)", data)).group(1))
24 return f"{major}.{minor}.{micro}"
25
26def replace_in_file(path: Path, regex_what: str, replace_with: str) -> None:
27 with path.open("r") as f:
28 data = f.read()
29
30 new_data, count = re.subn(regex_what, replace_with, data)
31
32 assert count > 0, f"\"{regex_what}\" did not match anything in \"{path}\""
33
34 with open(path, "w") as f:
35 f.write(new_data)
36
37
38def android_mk_use_prefab(path: Path) -> None:
39 """
40 Replace relative SDL inclusion with dependency on prefab package
41 """
42
43 with path.open() as f:
44 data = "".join(line for line in f.readlines() if "# SDL" not in line)
45
46 data, _ = re.subn("[\n]{3,}", "\n\n", data)
47
48 data, count = re.subn(r"(LOCAL_SHARED_LIBRARIES\s*:=\s*SDL3)", "LOCAL_SHARED_LIBRARIES := SDL3 SDL3-Headers", data)
49 assert count == 1, f"Must have injected SDL3-Headers in {path} exactly once"
50
51 newdata = data + textwrap.dedent("""
52 # https://google.github.io/prefab/build-systems.html
53
54 # Add the prefab modules to the import path.
55 $(call import-add-path,/out)
56
57 # Import SDL3 so we can depend on it.
58 $(call import-module,prefab/SDL3)
59 """)
60
61 with path.open("w") as f:
62 f.write(newdata)
63
64
65def cmake_mk_no_sdl(path: Path) -> None:
66 """
67 Don't add the source directories of SDL/SDL_image/SDL_mixer/...
68 """
69
70 with path.open() as f:
71 lines = f.readlines()
72
73 newlines: list[str] = []
74 for line in lines:
75 if "add_subdirectory(SDL" in line:
76 while newlines[-1].startswith("#"):
77 newlines = newlines[:-1]
78 continue
79 newlines.append(line)
80
81 newdata, _ = re.subn("[\n]{3,}", "\n\n", "".join(newlines))
82
83 with path.open("w") as f:
84 f.write(newdata)
85
86
87def gradle_add_prefab_and_aar(path: Path, aar: str) -> None:
88 with path.open() as f:
89 data = f.read()
90
91 data, count = re.subn("android {", textwrap.dedent("""
92 android {
93 buildFeatures {
94 prefab true
95 }"""), data)
96 assert count == 1
97
98 data, count = re.subn("dependencies {", textwrap.dedent(f"""
99 dependencies {{
100 implementation files('libs/{aar}')"""), data)
101 assert count == 1
102
103 with path.open("w") as f:
104 f.write(data)
105
106
107def gradle_add_package_name(path: Path, package_name: str) -> None:
108 with path.open() as f:
109 data = f.read()
110
111 data, count = re.subn("org.libsdl.app", package_name, data)
112 assert count >= 1
113
114 with path.open("w") as f:
115 f.write(data)
116
117
118def main() -> int:
119 description = "Create a simple Android gradle project from input sources."
120 epilog = textwrap.dedent("""\
121 You need to manually copy a prebuilt SDL3 Android archive into the project tree when using the aar variant.
122
123 Any changes you have done to the sources in the Android project will be lost
124 """)
125 parser = ArgumentParser(description=description, epilog=epilog, allow_abbrev=False)
126 parser.add_argument("package_name", metavar="PACKAGENAME", help="Android package name (e.g. com.yourcompany.yourapp)")
127 parser.add_argument("sources", metavar="SOURCE", nargs="*", help="Source code of your application. The files are copied to the output directory.")
128 parser.add_argument("--variant", choices=["copy", "symlink", "aar"], default="copy", help="Choose variant of SDL project (copy: copy SDL sources, symlink: symlink SDL sources, aar: use Android aar archive)")
129 parser.add_argument("--output", "-o", default=SDL_ROOT / "build", type=Path, help="Location where to store the Android project")
130 parser.add_argument("--version", default=None, help="SDL3 version to use as aar dependency (only used for aar variant)")
131
132 args = parser.parse_args()
133 if not args.sources:
134 print("Reading source file paths from stdin (press CTRL+D to stop)")
135 args.sources = [path for path in sys.stdin.read().strip().split() if path]
136 if not args.sources:
137 parser.error("No sources passed")
138
139 if not os.getenv("ANDROID_HOME"):
140 print("WARNING: ANDROID_HOME environment variable not set", file=sys.stderr)
141 if not os.getenv("ANDROID_NDK_HOME"):
142 print("WARNING: ANDROID_NDK_HOME environment variable not set", file=sys.stderr)
143
144 args.sources = [Path(src) for src in args.sources]
145
146 build_path = args.output / args.package_name
147
148 # Remove the destination folder
149 shutil.rmtree(build_path, ignore_errors=True)
150
151 # Copy the Android project
152 shutil.copytree(SDL_ROOT / "android-project", build_path)
153
154 # Add the source files to the ndk-build and cmake projects
155 replace_in_file(build_path / "app/jni/src/Android.mk", r"YourSourceHere\.c", " \\\n ".join(src.name for src in args.sources))
156 replace_in_file(build_path / "app/jni/src/CMakeLists.txt", r"YourSourceHere\.c", "\n ".join(src.name for src in args.sources))
157
158 # Remove placeholder source "YourSourceHere.c"
159 (build_path / "app/jni/src/YourSourceHere.c").unlink()
160
161 # Copy sources to output folder
162 for src in args.sources:
163 if not src.is_file():
164 parser.error(f"\"{src}\" is not a file")
165 shutil.copyfile(src, build_path / "app/jni/src" / src.name)
166
167 sdl_project_files = (
168 SDL_ROOT / "src",
169 SDL_ROOT / "include",
170 SDL_ROOT / "LICENSE.txt",
171 SDL_ROOT / "README.md",
172 SDL_ROOT / "Android.mk",
173 SDL_ROOT / "CMakeLists.txt",
174 SDL_ROOT / "cmake",
175 )
176 if args.variant == "copy":
177 (build_path / "app/jni/SDL").mkdir(exist_ok=True, parents=True)
178 for sdl_project_file in sdl_project_files:
179 # Copy SDL project files and directories
180 if sdl_project_file.is_dir():
181 shutil.copytree(sdl_project_file, build_path / "app/jni/SDL" / sdl_project_file.name)
182 elif sdl_project_file.is_file():
183 shutil.copyfile(sdl_project_file, build_path / "app/jni/SDL" / sdl_project_file.name)
184 elif args.variant == "symlink":
185 (build_path / "app/jni/SDL").mkdir(exist_ok=True, parents=True)
186 # Create symbolic links for all SDL project files
187 for sdl_project_file in sdl_project_files:
188 os.symlink(sdl_project_file, build_path / "app/jni/SDL" / sdl_project_file.name)
189 elif args.variant == "aar":
190 if not args.version:
191 args.version = extract_sdl_version()
192
193 major = args.version.split(".")[0]
194 aar = f"SDL{ major }-{ args.version }.aar"
195
196 # Remove all SDL java classes
197 shutil.rmtree(build_path / "app/src/main/java")
198
199 # Use prefab to generate include-able files
200 gradle_add_prefab_and_aar(build_path / "app/build.gradle", aar=aar)
201
202 # Make sure to use the prefab-generated files and not SDL sources
203 android_mk_use_prefab(build_path / "app/jni/src/Android.mk")
204 cmake_mk_no_sdl(build_path / "app/jni/CMakeLists.txt")
205
206 aar_libs_folder = build_path / "app/libs"
207 aar_libs_folder.mkdir(parents=True)
208 with (aar_libs_folder / "copy-sdl-aars-here.txt").open("w") as f:
209 f.write(f"Copy {aar} to this folder.\n")
210
211 print(f"WARNING: copy { aar } to { aar_libs_folder }", file=sys.stderr)
212
213 # Add the package name to build.gradle
214 gradle_add_package_name(build_path / "app/build.gradle", args.package_name)
215
216 # Create entry activity, subclassing SDLActivity
217 activity = args.package_name[args.package_name.rfind(".") + 1:].capitalize() + "Activity"
218 activity_path = build_path / "app/src/main/java" / args.package_name.replace(".", "/") / f"{activity}.java"
219 activity_path.parent.mkdir(parents=True)
220 with activity_path.open("w") as f:
221 f.write(textwrap.dedent(f"""
222 package {args.package_name};
223
224 import org.libsdl.app.SDLActivity;
225
226 public class {activity} extends SDLActivity
227 {{
228 }}
229 """))
230
231 # Add the just-generated activity to the Android manifest
232 replace_in_file(build_path / "app/src/main/AndroidManifest.xml", 'name="SDLActivity"', f'name="{activity}"')
233
234 # Update project and build
235 print("To build and install to a device for testing, run the following:")
236 print(f"cd {build_path}")
237 print("./gradlew installDebug")
238 return 0
239
240if __name__ == "__main__":
241 raise SystemExit(main())
diff --git a/src/contrib/SDL-3.2.20/build-scripts/create-release.py b/src/contrib/SDL-3.2.20/build-scripts/create-release.py
new file mode 100755
index 0000000..14916fa
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/create-release.py
@@ -0,0 +1,45 @@
1#!/usr/bin/env python3
2
3import argparse
4from pathlib import Path
5import json
6import logging
7import re
8import subprocess
9
10ROOT = Path(__file__).resolve().parents[1]
11
12
13def determine_remote() -> str:
14 text = (ROOT / "build-scripts/release-info.json").read_text()
15 release_info = json.loads(text)
16 if "remote" in release_info:
17 return release_info["remote"]
18 project_with_version = release_info["name"]
19 project, _ = re.subn("([^a-zA-Z_])", "", project_with_version)
20 return f"libsdl-org/{project}"
21
22
23def main():
24 default_remote = determine_remote()
25
26 parser = argparse.ArgumentParser(allow_abbrev=False)
27 parser.add_argument("--ref", required=True, help=f"Name of branch or tag containing release.yml")
28 parser.add_argument("--remote", "-R", default=default_remote, help=f"Remote repo (default={default_remote})")
29 parser.add_argument("--commit", help=f"Input 'commit' of release.yml (default is the hash of the ref)")
30 args = parser.parse_args()
31
32 if args.commit is None:
33 args.commit = subprocess.check_output(["git", "rev-parse", args.ref], cwd=ROOT, text=True).strip()
34
35
36 print(f"Running release.yml workflow:")
37 print(f" remote = {args.remote}")
38 print(f" ref = {args.ref}")
39 print(f" commit = {args.commit}")
40
41 subprocess.check_call(["gh", "-R", args.remote, "workflow", "run", "release.yml", "--ref", args.ref, "-f", f"commit={args.commit}"], cwd=ROOT)
42
43
44if __name__ == "__main__":
45 raise SystemExit(main())
diff --git a/src/contrib/SDL-3.2.20/build-scripts/fnsince.pl b/src/contrib/SDL-3.2.20/build-scripts/fnsince.pl
new file mode 100755
index 0000000..9d987fc
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/fnsince.pl
@@ -0,0 +1,169 @@
1#!/usr/bin/perl -w
2
3use warnings;
4use strict;
5use File::Basename;
6use Cwd qw(abs_path);
7
8my $wikipath = undef;
9foreach (@ARGV) {
10 $wikipath = abs_path($_), next if not defined $wikipath;
11}
12
13chdir(dirname(__FILE__));
14chdir('..');
15
16my %fulltags = ();
17my @unsorted_releases = ();
18open(PIPEFH, '-|', 'git tag -l') or die "Failed to read git release tags: $!\n";
19
20while (<PIPEFH>) {
21 chomp;
22 my $fulltag = $_;
23 if ($fulltag =~ /\A(prerelease|preview|release)\-(\d+)\.(\d+)\.(\d+)\Z/) {
24 # Ignore anything that isn't a x.y.0 release.
25 # Make sure new APIs are assigned to the next minor version and ignore the patch versions, but we'll make an except for the prereleases.
26 my $release_type = $1;
27 my $major = int($2);
28 my $minor = int($3);
29 my $patch = int($4);
30 next if ($major != 3); # Ignore anything that isn't an SDL3 release.
31 next if ($patch != 0) && ($minor >= 2); # Ignore anything that is a patch release (unless it was between the preview release and the official release).
32
33 # Consider this release version.
34 my $ver = "${major}.${minor}.${patch}";
35 push @unsorted_releases, $ver;
36 $fulltags{$ver} = $fulltag;
37 }
38}
39close(PIPEFH);
40
41#print("\n\nUNSORTED\n");
42#foreach (@unsorted_releases) {
43# print "$_\n";
44#}
45
46my @releases = sort {
47 my @asplit = split /\./, $a;
48 my @bsplit = split /\./, $b;
49 my $rc;
50 for (my $i = 0; $i < scalar(@asplit); $i++) {
51 return 1 if (scalar(@bsplit) <= $i); # a is "2.0.1" and b is "2.0", or whatever.
52 my $aseg = $asplit[$i];
53 my $bseg = $bsplit[$i];
54 $rc = int($aseg) <=> int($bseg);
55 return $rc if ($rc != 0); # found the difference.
56 }
57 return 0; # still here? They matched completely?!
58} @unsorted_releases;
59
60my $current_release = $releases[-1];
61my $next_release;
62
63if (scalar(@releases) > 0) {
64 # this happens to work for how SDL versions things at the moment.
65 $current_release = $releases[-1];
66
67 my @current_release_segments = split /\./, $current_release;
68 # if we're still in the 3.1.x prereleases, call the "next release" 3.2.0 even if we do more prereleases.
69 if (($current_release_segments[0] == '3') && ($current_release_segments[1] == '1')) {
70 $next_release = '3.2.0';
71 } else {
72 @current_release_segments[1] = '' . (int($current_release_segments[1]) + 2);
73 $next_release = join('.', @current_release_segments);
74 }
75}
76
77#print("\n\nSORTED\n");
78#foreach (@releases) {
79# print "$_\n";
80#}
81#print("\nCURRENT RELEASE: $current_release\n");
82#print("NEXT RELEASE: $next_release\n\n");
83
84push @releases, 'HEAD';
85$fulltags{'HEAD'} = 'HEAD';
86
87my %funcs = ();
88foreach my $release (@releases) {
89 #print("Checking $release...\n");
90 my $tag = $fulltags{$release};
91 my $blobname = "$tag:src/dynapi/SDL_dynapi_overrides.h";
92
93 if ($release =~ /\A3\.[01]\.\d+\Z/) { # make everything up to the first SDL3 official release look like 3.2.0.
94 $release = '3.2.0';
95 }
96
97 open(PIPEFH, '-|', "git show '$blobname'") or die "Failed to read git blob '$blobname': $!\n";
98 while (<PIPEFH>) {
99 chomp;
100 if (/\A\#define\s+(SDL_.*?)\s+SDL_.*?_REAL\Z/) {
101 my $fn = $1;
102 $funcs{$fn} = $release if not defined $funcs{$fn};
103 }
104 }
105 close(PIPEFH);
106}
107
108if (not defined $wikipath) {
109 foreach my $release (@releases) {
110 foreach my $fn (sort keys %funcs) {
111 print("$fn: $funcs{$fn}\n") if $funcs{$fn} eq $release;
112 }
113 }
114} else {
115 if (defined $wikipath) {
116 chdir($wikipath);
117 foreach my $fn (keys %funcs) {
118 next if $fn eq 'SDL_ThreadID'; # this was a function early on (it's now called SDL_GetThreadID), but now it's a datatype (which originally had a different capitalization).
119 my $revision = $funcs{$fn};
120 $revision = $next_release if $revision eq 'HEAD';
121 my $fname = "$fn.md";
122 if ( ! -f $fname ) {
123 #print STDERR "No such file: $fname\n";
124 next;
125 }
126
127 my @lines = ();
128 open(FH, '<', $fname) or die("Can't open $fname for read: $!\n");
129 my $added = 0;
130 while (<FH>) {
131 chomp;
132 if ((/\A\-\-\-\-/) && (!$added)) {
133 push @lines, "## Version";
134 push @lines, "";
135 push @lines, "This function is available since SDL $revision.";
136 push @lines, "";
137 $added = 1;
138 }
139 push @lines, $_;
140 next if not /\A\#\#\s+Version/;
141 $added = 1;
142 push @lines, "";
143 push @lines, "This function is available since SDL $revision.";
144 push @lines, "";
145 while (<FH>) {
146 chomp;
147 next if not (/\A\#\#\s+/ || /\A\-\-\-\-/);
148 push @lines, $_;
149 last;
150 }
151 }
152 close(FH);
153
154 if (!$added) {
155 push @lines, "## Version";
156 push @lines, "";
157 push @lines, "This function is available since SDL $revision.";
158 push @lines, "";
159 }
160
161 open(FH, '>', $fname) or die("Can't open $fname for write: $!\n");
162 foreach (@lines) {
163 print FH "$_\n";
164 }
165 close(FH);
166 }
167 }
168}
169
diff --git a/src/contrib/SDL-3.2.20/build-scripts/gen_audio_channel_conversion.c b/src/contrib/SDL-3.2.20/build-scripts/gen_audio_channel_conversion.c
new file mode 100644
index 0000000..85a856e
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/gen_audio_channel_conversion.c
@@ -0,0 +1,461 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21
22#include <stdio.h>
23
24/*
25
26Built with:
27
28gcc -o genchancvt build-scripts/gen_audio_channel_conversion.c -lm && ./genchancvt > src/audio/SDL_audio_channel_converters.h
29
30*/
31
32#define NUM_CHANNELS 8
33
34static const char *layout_names[NUM_CHANNELS] = {
35 "Mono", "Stereo", "2.1", "Quad", "4.1", "5.1", "6.1", "7.1"
36};
37
38static const char *channel_names[NUM_CHANNELS][NUM_CHANNELS] = {
39 /* mono */ { "FC" },
40 /* stereo */ { "FL", "FR" },
41 /* 2.1 */ { "FL", "FR", "LFE" },
42 /* quad */ { "FL", "FR", "BL", "BR" },
43 /* 4.1 */ { "FL", "FR", "LFE", "BL", "BR" },
44 /* 5.1 */ { "FL", "FR", "FC", "LFE", "BL", "BR" },
45 /* 6.1 */ { "FL", "FR", "FC", "LFE", "BC", "SL", "SR" },
46 /* 7.1 */ { "FL", "FR", "FC", "LFE", "BL", "BR", "SL", "SR" },
47};
48
49
50/*
51 * This table is from FAudio:
52 *
53 * https://raw.githubusercontent.com/FNA-XNA/FAudio/master/src/matrix_defaults.inl
54 */
55static const float channel_conversion_matrix[8][8][64] = {
56{
57 /* 1 x 1 */
58 { 1.000000000f },
59 /* 1 x 2 */
60 { 1.000000000f, 1.000000000f },
61 /* 1 x 3 */
62 { 1.000000000f, 1.000000000f, 0.000000000f },
63 /* 1 x 4 */
64 { 1.000000000f, 1.000000000f, 0.000000000f, 0.000000000f },
65 /* 1 x 5 */
66 { 1.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
67 /* 1 x 6 */
68 { 1.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
69 /* 1 x 7 */
70 { 1.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
71 /* 1 x 8 */
72 { 1.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f }
73},
74{
75 /* 2 x 1 */
76 { 0.500000000f, 0.500000000f },
77 /* 2 x 2 */
78 { 1.000000000f, 0.000000000f, 0.000000000f, 1.000000000f },
79 /* 2 x 3 */
80 { 1.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f },
81 /* 2 x 4 */
82 { 1.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
83 /* 2 x 5 */
84 { 1.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
85 /* 2 x 6 */
86 { 1.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
87 /* 2 x 7 */
88 { 1.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
89 /* 2 x 8 */
90 { 1.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f }
91},
92{
93 /* 3 x 1 */
94 { 0.333333343f, 0.333333343f, 0.333333343f },
95 /* 3 x 2 */
96 { 0.800000012f, 0.000000000f, 0.200000003f, 0.000000000f, 0.800000012f, 0.200000003f },
97 /* 3 x 3 */
98 { 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f },
99 /* 3 x 4 */
100 { 0.888888896f, 0.000000000f, 0.111111112f, 0.000000000f, 0.888888896f, 0.111111112f, 0.000000000f, 0.000000000f, 0.111111112f, 0.000000000f, 0.000000000f, 0.111111112f },
101 /* 3 x 5 */
102 { 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
103 /* 3 x 6 */
104 { 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
105 /* 3 x 7 */
106 { 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
107 /* 3 x 8 */
108 { 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f }
109},
110{
111 /* 4 x 1 */
112 { 0.250000000f, 0.250000000f, 0.250000000f, 0.250000000f },
113 /* 4 x 2 */
114 { 0.421000004f, 0.000000000f, 0.358999997f, 0.219999999f, 0.000000000f, 0.421000004f, 0.219999999f, 0.358999997f },
115 /* 4 x 3 */
116 { 0.421000004f, 0.000000000f, 0.358999997f, 0.219999999f, 0.000000000f, 0.421000004f, 0.219999999f, 0.358999997f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
117 /* 4 x 4 */
118 { 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f },
119 /* 4 x 5 */
120 { 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f },
121 /* 4 x 6 */
122 { 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f },
123 /* 4 x 7 */
124 { 0.939999998f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.939999998f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.500000000f, 0.500000000f, 0.000000000f, 0.000000000f, 0.796000004f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.796000004f },
125 /* 4 x 8 */
126 { 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f }
127},
128{
129 /* 5 x 1 */
130 { 0.200000003f, 0.200000003f, 0.200000003f, 0.200000003f, 0.200000003f },
131 /* 5 x 2 */
132 { 0.374222219f, 0.000000000f, 0.111111112f, 0.319111109f, 0.195555553f, 0.000000000f, 0.374222219f, 0.111111112f, 0.195555553f, 0.319111109f },
133 /* 5 x 3 */
134 { 0.421000004f, 0.000000000f, 0.000000000f, 0.358999997f, 0.219999999f, 0.000000000f, 0.421000004f, 0.000000000f, 0.219999999f, 0.358999997f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f },
135 /* 5 x 4 */
136 { 0.941176474f, 0.000000000f, 0.058823530f, 0.000000000f, 0.000000000f, 0.000000000f, 0.941176474f, 0.058823530f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.058823530f, 0.941176474f, 0.000000000f, 0.000000000f, 0.000000000f, 0.058823530f, 0.000000000f, 0.941176474f },
137 /* 5 x 5 */
138 { 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f },
139 /* 5 x 6 */
140 { 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f },
141 /* 5 x 7 */
142 { 0.939999998f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.939999998f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.500000000f, 0.500000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.796000004f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.796000004f },
143 /* 5 x 8 */
144 { 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f }
145},
146{
147 /* 6 x 1 */
148 { 0.166666672f, 0.166666672f, 0.166666672f, 0.166666672f, 0.166666672f, 0.166666672f },
149 /* 6 x 2 */
150 { 0.294545442f, 0.000000000f, 0.208181813f, 0.090909094f, 0.251818180f, 0.154545456f, 0.000000000f, 0.294545442f, 0.208181813f, 0.090909094f, 0.154545456f, 0.251818180f },
151 /* 6 x 3 */
152 { 0.324000001f, 0.000000000f, 0.229000002f, 0.000000000f, 0.277000010f, 0.170000002f, 0.000000000f, 0.324000001f, 0.229000002f, 0.000000000f, 0.170000002f, 0.277000010f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f },
153 /* 6 x 4 */
154 { 0.558095276f, 0.000000000f, 0.394285709f, 0.047619049f, 0.000000000f, 0.000000000f, 0.000000000f, 0.558095276f, 0.394285709f, 0.047619049f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.047619049f, 0.558095276f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.047619049f, 0.000000000f, 0.558095276f },
155 /* 6 x 5 */
156 { 0.586000025f, 0.000000000f, 0.414000005f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.586000025f, 0.414000005f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.586000025f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.586000025f },
157 /* 6 x 6 */
158 { 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f },
159 /* 6 x 7 */
160 { 0.939999998f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.939999998f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.939999998f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.500000000f, 0.500000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.796000004f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.796000004f },
161 /* 6 x 8 */
162 { 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f }
163},
164{
165 /* 7 x 1 */
166 { 0.143142849f, 0.143142849f, 0.143142849f, 0.142857149f, 0.143142849f, 0.143142849f, 0.143142849f },
167 /* 7 x 2 */
168 { 0.247384623f, 0.000000000f, 0.174461529f, 0.076923080f, 0.174461529f, 0.226153851f, 0.100615382f, 0.000000000f, 0.247384623f, 0.174461529f, 0.076923080f, 0.174461529f, 0.100615382f, 0.226153851f },
169 /* 7 x 3 */
170 { 0.268000007f, 0.000000000f, 0.188999996f, 0.000000000f, 0.188999996f, 0.245000005f, 0.108999997f, 0.000000000f, 0.268000007f, 0.188999996f, 0.000000000f, 0.188999996f, 0.108999997f, 0.245000005f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
171 /* 7 x 4 */
172 { 0.463679999f, 0.000000000f, 0.327360004f, 0.040000003f, 0.000000000f, 0.168960005f, 0.000000000f, 0.000000000f, 0.463679999f, 0.327360004f, 0.040000003f, 0.000000000f, 0.000000000f, 0.168960005f, 0.000000000f, 0.000000000f, 0.000000000f, 0.040000003f, 0.327360004f, 0.431039989f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.040000003f, 0.327360004f, 0.000000000f, 0.431039989f },
173 /* 7 x 5 */
174 { 0.483000010f, 0.000000000f, 0.340999991f, 0.000000000f, 0.000000000f, 0.175999999f, 0.000000000f, 0.000000000f, 0.483000010f, 0.340999991f, 0.000000000f, 0.000000000f, 0.000000000f, 0.175999999f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.340999991f, 0.449000001f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.340999991f, 0.000000000f, 0.449000001f },
175 /* 7 x 6 */
176 { 0.611000001f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.223000005f, 0.000000000f, 0.000000000f, 0.611000001f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.223000005f, 0.000000000f, 0.000000000f, 0.611000001f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.432000011f, 0.568000019f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.432000011f, 0.000000000f, 0.568000019f },
177 /* 7 x 7 */
178 { 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f },
179 /* 7 x 8 */
180 { 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.707000017f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.707000017f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f }
181},
182{
183 /* 8 x 1 */
184 { 0.125125006f, 0.125125006f, 0.125125006f, 0.125000000f, 0.125125006f, 0.125125006f, 0.125125006f, 0.125125006f },
185 /* 8 x 2 */
186 { 0.211866662f, 0.000000000f, 0.150266662f, 0.066666670f, 0.181066677f, 0.111066669f, 0.194133341f, 0.085866667f, 0.000000000f, 0.211866662f, 0.150266662f, 0.066666670f, 0.111066669f, 0.181066677f, 0.085866667f, 0.194133341f },
187 /* 8 x 3 */
188 { 0.226999998f, 0.000000000f, 0.160999998f, 0.000000000f, 0.194000006f, 0.119000003f, 0.208000004f, 0.092000000f, 0.000000000f, 0.226999998f, 0.160999998f, 0.000000000f, 0.119000003f, 0.194000006f, 0.092000000f, 0.208000004f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
189 /* 8 x 4 */
190 { 0.466344833f, 0.000000000f, 0.329241365f, 0.034482758f, 0.000000000f, 0.000000000f, 0.169931039f, 0.000000000f, 0.000000000f, 0.466344833f, 0.329241365f, 0.034482758f, 0.000000000f, 0.000000000f, 0.000000000f, 0.169931039f, 0.000000000f, 0.000000000f, 0.000000000f, 0.034482758f, 0.466344833f, 0.000000000f, 0.433517247f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.034482758f, 0.000000000f, 0.466344833f, 0.000000000f, 0.433517247f },
191 /* 8 x 5 */
192 { 0.483000010f, 0.000000000f, 0.340999991f, 0.000000000f, 0.000000000f, 0.000000000f, 0.175999999f, 0.000000000f, 0.000000000f, 0.483000010f, 0.340999991f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.175999999f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.483000010f, 0.000000000f, 0.449000001f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.483000010f, 0.000000000f, 0.449000001f },
193 /* 8 x 6 */
194 { 0.518000007f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.188999996f, 0.000000000f, 0.000000000f, 0.518000007f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.188999996f, 0.000000000f, 0.000000000f, 0.518000007f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.518000007f, 0.000000000f, 0.481999993f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.518000007f, 0.000000000f, 0.481999993f },
195 /* 8 x 7 */
196 { 0.541000009f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.541000009f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.541000009f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.287999988f, 0.287999988f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.458999991f, 0.000000000f, 0.541000009f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.458999991f, 0.000000000f, 0.541000009f },
197 /* 8 x 8 */
198 { 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f }
199}
200};
201
202static char *remove_dots(const char *str) /* this is NOT robust. */
203{
204 static char retval1[32];
205 static char retval2[32];
206 static int idx = 0;
207 char *retval = (idx++ & 1) ? retval1 : retval2;
208 char *ptr = retval;
209 while (*str) {
210 if (*str != '.') {
211 *(ptr++) = *str;
212 }
213 str++;
214 }
215 *ptr = '\0';
216 return retval;
217}
218
219static char *lowercase(const char *str) /* this is NOT robust. */
220{
221 static char retval1[32];
222 static char retval2[32];
223 static int idx = 0;
224 char *retval = (idx++ & 1) ? retval1 : retval2;
225 char *ptr = retval;
226 while (*str) {
227 const char ch = *(str++);
228 *(ptr++) = ((ch >= 'A') && (ch <= 'Z')) ? (ch - ('A' - 'a')) : ch;
229 }
230 *ptr = '\0';
231 return retval;
232}
233
234static void write_converter(const int fromchans, const int tochans)
235{
236 const char *fromstr = layout_names[fromchans-1];
237 const char *tostr = layout_names[tochans-1];
238 const float *cvtmatrix = channel_conversion_matrix[fromchans-1][tochans-1];
239 const float *fptr;
240 const int convert_backwards = (tochans > fromchans);
241 int input_channel_used[NUM_CHANNELS];
242 int i, j;
243
244 if (tochans == fromchans) {
245 return; /* nothing to convert, don't generate a converter. */
246 }
247
248 for (i = 0; i < fromchans; i++) {
249 input_channel_used[i] = 0;
250 }
251
252 fptr = cvtmatrix;
253 for (j = 0; j < tochans; j++) {
254 for (i = 0; i < fromchans; i++) {
255 #if 0
256 printf("to=%d, from=%d, coeff=%f\n", j, i, *fptr);
257 #endif
258 if (*(fptr++) != 0.0f) {
259 input_channel_used[i]++;
260 }
261 }
262 }
263
264 printf("static void SDL_Convert%sTo%s(float *dst, const float *src, int num_frames)\n{\n", remove_dots(fromstr), remove_dots(tostr));
265
266 printf(" int i;\n"
267 "\n"
268 " LOG_DEBUG_AUDIO_CONVERT(\"%s\", \"%s\");\n"
269 "\n", lowercase(fromstr), lowercase(tostr));
270
271 if (convert_backwards) { /* must convert backwards when growing the output in-place. */
272 printf(" // convert backwards, since output is growing in-place.\n");
273 printf(" src += (num_frames-1)");
274 if (fromchans != 1) {
275 printf(" * %d", fromchans);
276 }
277 printf(";\n");
278
279 printf(" dst += (num_frames-1)");
280 if (tochans != 1) {
281 printf(" * %d", tochans);
282 }
283 printf(";\n");
284 printf(" for (i = num_frames; i; i--, ");
285 if (fromchans == 1) {
286 printf("src--");
287 } else {
288 printf("src -= %d", fromchans);
289 }
290 printf(", ");
291 if (tochans == 1) {
292 printf("dst--");
293 } else {
294 printf("dst -= %d", tochans);
295 }
296 printf(") {\n");
297 fptr = cvtmatrix;
298 for (i = 0; i < fromchans; i++) {
299 if (input_channel_used[i] > 1) { /* don't read it from src more than once. */
300 printf(" const float src%s = src[%d];\n", channel_names[fromchans-1][i], i);
301 }
302 }
303
304 for (j = tochans - 1; j >= 0; j--) {
305 int has_input = 0;
306 fptr = cvtmatrix + (fromchans * j);
307 printf(" dst[%d] /* %s */ =", j, channel_names[tochans-1][j]);
308 for (i = fromchans - 1; i >= 0; i--) {
309 const float coefficient = fptr[i];
310 char srcname[32];
311 if (coefficient == 0.0f) {
312 continue;
313 } else if (input_channel_used[i] > 1) {
314 snprintf(srcname, sizeof (srcname), "src%s", channel_names[fromchans-1][i]);
315 } else {
316 snprintf(srcname, sizeof (srcname), "src[%d]", i);
317 }
318
319 if (has_input) {
320 printf(" +");
321 }
322
323 has_input = 1;
324
325 if (coefficient == 1.0f) {
326 printf(" %s", srcname);
327 } else {
328 printf(" (%s * %.9ff)", srcname, coefficient);
329 }
330 }
331
332 if (!has_input) {
333 printf(" 0.0f");
334 }
335
336 printf(";\n");
337 }
338
339 printf(" }\n");
340 } else {
341 printf(" for (i = num_frames; i; i--, ");
342 if (fromchans == 1) {
343 printf("src++");
344 } else {
345 printf("src += %d", fromchans);
346 }
347 printf(", ");
348 if (tochans == 1) {
349 printf("dst++");
350 } else {
351 printf("dst += %d", tochans);
352 }
353 printf(") {\n");
354
355 fptr = cvtmatrix;
356 for (i = 0; i < fromchans; i++) {
357 if (input_channel_used[i] > 1) { /* don't read it from src more than once. */
358 printf(" const float src%s = src[%d];\n", channel_names[fromchans-1][i], i);
359 }
360 }
361
362 for (j = 0; j < tochans; j++) {
363 int has_input = 0;
364 fptr = cvtmatrix + (fromchans * j);
365 printf(" dst[%d] /* %s */ =", j, channel_names[tochans-1][j]);
366 for (i = 0; i < fromchans; i++) {
367 const float coefficient = fptr[i];
368 char srcname[32];
369 if (coefficient == 0.0f) {
370 continue;
371 } else if (input_channel_used[i] > 1) {
372 snprintf(srcname, sizeof (srcname), "src%s", channel_names[fromchans-1][i]);
373 } else {
374 snprintf(srcname, sizeof (srcname), "src[%d]", i);
375 }
376
377 if (has_input) {
378 printf(" +");
379 }
380
381 has_input = 1;
382
383 if (coefficient == 1.0f) {
384 printf(" %s", srcname);
385 } else {
386 printf(" (%s * %.9ff)", srcname, coefficient);
387 }
388 }
389
390 if (!has_input) {
391 printf(" 0.0f");
392 }
393
394 printf(";\n");
395 }
396 printf(" }\n");
397 }
398
399 printf("\n}\n\n");
400}
401
402int main(void)
403{
404 int ini, outi;
405
406 printf(
407 "/*\n"
408 " Simple DirectMedia Layer\n"
409 " Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>\n"
410 "\n"
411 " This software is provided 'as-is', without any express or implied\n"
412 " warranty. In no event will the authors be held liable for any damages\n"
413 " arising from the use of this software.\n"
414 "\n"
415 " Permission is granted to anyone to use this software for any purpose,\n"
416 " including commercial applications, and to alter it and redistribute it\n"
417 " freely, subject to the following restrictions:\n"
418 "\n"
419 " 1. The origin of this software must not be misrepresented; you must not\n"
420 " claim that you wrote the original software. If you use this software\n"
421 " in a product, an acknowledgment in the product documentation would be\n"
422 " appreciated but is not required.\n"
423 " 2. Altered source versions must be plainly marked as such, and must not be\n"
424 " misrepresented as being the original software.\n"
425 " 3. This notice may not be removed or altered from any source distribution.\n"
426 "*/\n"
427 "\n"
428 "// DO NOT EDIT, THIS FILE WAS GENERATED BY build-scripts/gen_audio_channel_conversion.c\n"
429 "\n"
430 "\n"
431 "typedef void (*SDL_AudioChannelConverter)(float *dst, const float *src, int num_frames);\n"
432 "\n"
433 );
434
435 for (ini = 1; ini <= NUM_CHANNELS; ini++) {
436 for (outi = 1; outi <= NUM_CHANNELS; outi++) {
437 write_converter(ini, outi);
438 }
439 }
440
441 printf("static const SDL_AudioChannelConverter channel_converters[%d][%d] = { /* [from][to] */\n", NUM_CHANNELS, NUM_CHANNELS);
442 for (ini = 1; ini <= NUM_CHANNELS; ini++) {
443 const char *comma = "";
444 printf(" {");
445 for (outi = 1; outi <= NUM_CHANNELS; outi++) {
446 const char *fromstr = layout_names[ini-1];
447 const char *tostr = layout_names[outi-1];
448 if (ini == outi) {
449 printf("%s NULL", comma);
450 } else {
451 printf("%s SDL_Convert%sTo%s", comma, remove_dots(fromstr), remove_dots(tostr));
452 }
453 comma = ",";
454 }
455 printf(" }%s\n", (ini == NUM_CHANNELS) ? "" : ",");
456 }
457
458 printf("};\n\n");
459
460 return 0;
461}
diff --git a/src/contrib/SDL-3.2.20/build-scripts/git-pre-push-hook.pl b/src/contrib/SDL-3.2.20/build-scripts/git-pre-push-hook.pl
new file mode 100755
index 0000000..63596b6
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/git-pre-push-hook.pl
@@ -0,0 +1,78 @@
1#!/usr/bin/perl -w
2
3# To use this script: symlink it to .git/hooks/pre-push, then "git push"
4#
5# This script is called by "git push" after it has checked the remote status,
6# but before anything has been pushed. If this script exits with a non-zero
7# status nothing will be pushed.
8#
9# This hook is called with the following parameters:
10#
11# $1 -- Name of the remote to which the push is being done
12# $2 -- URL to which the push is being done
13#
14# If pushing without using a named remote those arguments will be equal.
15#
16# Information about the commits which are being pushed is supplied as lines to
17# the standard input in the form:
18#
19# <local ref> <local sha1> <remote ref> <remote sha1>
20
21use warnings;
22use strict;
23
24my $remote = $ARGV[0];
25my $url = $ARGV[1];
26
27#print("remote: $remote\n");
28#print("url: $url\n");
29
30$url =~ s/\.git$//; # change myorg/myproject.git to myorg/myproject
31$url =~ s#^git\@github\.com\:#https://github.com/#i;
32my $commiturl = $url =~ /\Ahttps?:\/\/github.com\// ? "$url/commit/" : '';
33
34my $z40 = '0000000000000000000000000000000000000000';
35my $reported = 0;
36
37while (<STDIN>) {
38 chomp;
39 my ($local_ref, $local_sha, $remote_ref, $remote_sha) = split / /;
40 #print("local_ref: $local_ref\n");
41 #print("local_sha: $local_sha\n");
42 #print("remote_ref: $remote_ref\n");
43 #print("remote_sha: $remote_sha\n");
44
45 my $range = '';
46 if ($remote_sha eq $z40) { # New branch, examine all commits
47 $range = $local_sha;
48 } else { # Update to existing branch, examine new commits
49 $range = "$remote_sha..$local_sha";
50 }
51
52 my $gitcmd = "git log --reverse --oneline --no-abbrev-commit '$range'";
53 open(GITPIPE, '-|', $gitcmd) or die("\n\n$0: Failed to run '$gitcmd': $!\n\nAbort push!\n\n");
54 while (<GITPIPE>) {
55 chomp;
56 if (/\A([a-fA-F0-9]+)\s+(.*?)\Z/) {
57 my $hash = $1;
58 my $msg = $2;
59
60 if (!$reported) {
61 print("\nCommits expected to be pushed:\n");
62 $reported = 1;
63 }
64
65 #print("hash: $hash\n");
66 #print("msg: $msg\n");
67
68 print("$commiturl$hash -- $msg\n");
69 } else {
70 die("$0: Unexpected output from '$gitcmd'!\n\nAbort push!\n\n");
71 }
72 }
73 die("\n\n$0: Failing exit code from running '$gitcmd'!\n\nAbort push!\n\n") if !close(GITPIPE);
74}
75
76print("\n") if $reported;
77
78exit(0); # Let the push go forward.
diff --git a/src/contrib/SDL-3.2.20/build-scripts/makecasefoldhashtable.pl b/src/contrib/SDL-3.2.20/build-scripts/makecasefoldhashtable.pl
new file mode 100755
index 0000000..efe3534
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/makecasefoldhashtable.pl
@@ -0,0 +1,322 @@
1#!/usr/bin/perl -w
2
3# Simple DirectMedia Layer
4# Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
5#
6# This software is provided 'as-is', without any express or implied
7# warranty. In no event will the authors be held liable for any damages
8# arising from the use of this software.
9#
10# Permission is granted to anyone to use this software for any purpose,
11# including commercial applications, and to alter it and redistribute it
12# freely, subject to the following restrictions:
13#
14# 1. The origin of this software must not be misrepresented; you must not
15# claim that you wrote the original software. If you use this software
16# in a product, an acknowledgment in the product documentation would be
17# appreciated but is not required.
18# 2. Altered source versions must be plainly marked as such, and must not be
19# misrepresented as being the original software.
20# 3. This notice may not be removed or altered from any source distribution.
21
22# This script was originally written by Ryan C. Gordon for PhysicsFS
23# ( https://icculus.org/physfs/ ), under the zlib license: the same license
24# that SDL itself uses).
25
26use warnings;
27use strict;
28
29my $HASHBUCKETS1_16 = 256;
30my $HASHBUCKETS1_32 = 16;
31my $HASHBUCKETS2_16 = 16;
32my $HASHBUCKETS3_16 = 4;
33
34my $mem_used = 0;
35
36print <<__EOF__;
37/*
38 Simple DirectMedia Layer
39 Copyright (C) 1997-2025 Sam Lantinga <slouken\@libsdl.org>
40
41 This software is provided 'as-is', without any express or implied
42 warranty. In no event will the authors be held liable for any damages
43 arising from the use of this software.
44
45 Permission is granted to anyone to use this software for any purpose,
46 including commercial applications, and to alter it and redistribute it
47 freely, subject to the following restrictions:
48
49 1. The origin of this software must not be misrepresented; you must not
50 claim that you wrote the original software. If you use this software
51 in a product, an acknowledgment in the product documentation would be
52 appreciated but is not required.
53 2. Altered source versions must be plainly marked as such, and must not be
54 misrepresented as being the original software.
55 3. This notice may not be removed or altered from any source distribution.
56*/
57
58/*
59 * This data was generated by SDL/build-scripts/makecasefoldhashtable.pl
60 *
61 * Do not manually edit this file!
62 */
63
64#ifndef SDL_casefolding_h_
65#define SDL_casefolding_h_
66
67/* We build three simple hashmaps here: one that maps Unicode codepoints to
68a one, two, or three lowercase codepoints. To retrieve this info: look at
69case_fold_hashX, where X is 1, 2, or 3. Most foldable codepoints fold to one,
70a few dozen fold to two, and a handful fold to three. If the codepoint isn't
71in any of these hashes, it doesn't fold (no separate upper and lowercase).
72
73Almost all these codepoints fit into 16 bits, so we hash them as such to save
74memory. If a codepoint is > 0xFFFF, we have separate hashes for them,
75since there are (currently) only about 120 of them and (currently) all of them
76map to a single lowercase codepoint. */
77
78typedef struct CaseFoldMapping1_32
79{
80 Uint32 from;
81 Uint32 to0;
82} CaseFoldMapping1_32;
83
84typedef struct CaseFoldMapping1_16
85{
86 Uint16 from;
87 Uint16 to0;
88} CaseFoldMapping1_16;
89
90typedef struct CaseFoldMapping2_16
91{
92 Uint16 from;
93 Uint16 to0;
94 Uint16 to1;
95} CaseFoldMapping2_16;
96
97typedef struct CaseFoldMapping3_16
98{
99 Uint16 from;
100 Uint16 to0;
101 Uint16 to1;
102 Uint16 to2;
103} CaseFoldMapping3_16;
104
105typedef struct CaseFoldHashBucket1_16
106{
107 const CaseFoldMapping1_16 *list;
108 const Uint8 count;
109} CaseFoldHashBucket1_16;
110
111typedef struct CaseFoldHashBucket1_32
112{
113 const CaseFoldMapping1_32 *list;
114 const Uint8 count;
115} CaseFoldHashBucket1_32;
116
117typedef struct CaseFoldHashBucket2_16
118{
119 const CaseFoldMapping2_16 *list;
120 const Uint8 count;
121} CaseFoldHashBucket2_16;
122
123typedef struct CaseFoldHashBucket3_16
124{
125 const CaseFoldMapping3_16 *list;
126 const Uint8 count;
127} CaseFoldHashBucket3_16;
128
129__EOF__
130
131
132my @foldPairs1_16;
133my @foldPairs2_16;
134my @foldPairs3_16;
135my @foldPairs1_32;
136
137for (my $i = 0; $i < $HASHBUCKETS1_16; $i++) {
138 $foldPairs1_16[$i] = '';
139}
140
141for (my $i = 0; $i < $HASHBUCKETS1_32; $i++) {
142 $foldPairs1_32[$i] = '';
143}
144
145for (my $i = 0; $i < $HASHBUCKETS2_16; $i++) {
146 $foldPairs2_16[$i] = '';
147}
148
149for (my $i = 0; $i < $HASHBUCKETS3_16; $i++) {
150 $foldPairs3_16[$i] = '';
151}
152
153open(FH,'<','casefolding.txt') or die("failed to open casefolding.txt: $!\n");
154while (<FH>) {
155 chomp;
156 # strip comments from textfile...
157 s/\#.*\Z//;
158
159 # strip whitespace...
160 s/\A\s+//;
161 s/\s+\Z//;
162
163 next if not /\A([a-fA-F0-9]+)\;\s*(.)\;\s*(.+)\;/;
164 my ($code, $status, $mapping) = ($1, $2, $3);
165
166 my $hexxed = hex($code);
167 #print("// code '$code' status '$status' mapping '$mapping'\n");
168
169 if (($status eq 'C') or ($status eq 'F')) {
170 my ($map1, $map2, $map3) = (undef, undef, undef);
171 $map1 = $1 if $mapping =~ s/\A([a-fA-F0-9]+)(\s*|\Z)//;
172 $map2 = $1 if $mapping =~ s/\A([a-fA-F0-9]+)(\s*|\Z)//;
173 $map3 = $1 if $mapping =~ s/\A([a-fA-F0-9]+)(\s*|\Z)//;
174 die("mapping space too small for '$code'\n") if ($mapping ne '');
175 die("problem parsing mapping for '$code'\n") if (not defined($map1));
176
177 if ($hexxed < 128) {
178 # Just ignore these, we'll handle the low-ASCII ones ourselves.
179 } elsif ($hexxed > 0xFFFF) {
180 # We just need to add the 32-bit 2 and/or 3 codepoint maps if this die()'s here.
181 die("Uhoh, a codepoint > 0xFFFF that folds to multiple codepoints! Fixme.") if defined($map2);
182 my $hashed = (($hexxed ^ ($hexxed >> 8)) & ($HASHBUCKETS1_32-1));
183 #print("// hexxed '$hexxed' hashed1 '$hashed'\n");
184 $foldPairs1_32[$hashed] .= " { 0x$code, 0x$map1 },\n";
185 $mem_used += 8;
186 } elsif (not defined($map2)) {
187 my $hashed = (($hexxed ^ ($hexxed >> 8)) & ($HASHBUCKETS1_16-1));
188 #print("// hexxed '$hexxed' hashed1 '$hashed'\n");
189 $foldPairs1_16[$hashed] .= " { 0x$code, 0x$map1 },\n";
190 $mem_used += 4;
191 } elsif (not defined($map3)) {
192 my $hashed = (($hexxed ^ ($hexxed >> 8)) & ($HASHBUCKETS2_16-1));
193 #print("// hexxed '$hexxed' hashed2 '$hashed'\n");
194 $foldPairs2_16[$hashed] .= " { 0x$code, 0x$map1, 0x$map2 },\n";
195 $mem_used += 6;
196 } else {
197 my $hashed = (($hexxed ^ ($hexxed >> 8)) & ($HASHBUCKETS3_16-1));
198 #print("// hexxed '$hexxed' hashed3 '$hashed'\n");
199 $foldPairs3_16[$hashed] .= " { 0x$code, 0x$map1, 0x$map2, 0x$map3 },\n";
200 $mem_used += 8;
201 }
202 }
203}
204close(FH);
205
206for (my $i = 0; $i < $HASHBUCKETS1_16; $i++) {
207 $foldPairs1_16[$i] =~ s/,\n\Z//;
208 my $str = $foldPairs1_16[$i];
209 next if $str eq '';
210 my $num = '000' . $i;
211 $num =~ s/\A.*?(\d\d\d)\Z/$1/;
212 my $sym = "case_fold1_16_${num}";
213 print("static const CaseFoldMapping1_16 ${sym}[] = {\n$str\n};\n\n");
214}
215
216for (my $i = 0; $i < $HASHBUCKETS1_32; $i++) {
217 $foldPairs1_32[$i] =~ s/,\n\Z//;
218 my $str = $foldPairs1_32[$i];
219 next if $str eq '';
220 my $num = '000' . $i;
221 $num =~ s/\A.*?(\d\d\d)\Z/$1/;
222 my $sym = "case_fold1_32_${num}";
223 print("static const CaseFoldMapping1_32 ${sym}[] = {\n$str\n};\n\n");
224}
225
226for (my $i = 0; $i < $HASHBUCKETS2_16; $i++) {
227 $foldPairs2_16[$i] =~ s/,\n\Z//;
228 my $str = $foldPairs2_16[$i];
229 next if $str eq '';
230 my $num = '000' . $i;
231 $num =~ s/\A.*?(\d\d\d)\Z/$1/;
232 my $sym = "case_fold2_16_${num}";
233 print("static const CaseFoldMapping2_16 ${sym}[] = {\n$str\n};\n\n");
234}
235
236for (my $i = 0; $i < $HASHBUCKETS3_16; $i++) {
237 $foldPairs3_16[$i] =~ s/,\n\Z//;
238 my $str = $foldPairs3_16[$i];
239 next if $str eq '';
240 my $num = '000' . $i;
241 $num =~ s/\A.*?(\d\d\d)\Z/$1/;
242 my $sym = "case_fold3_16_${num}";
243 print("static const CaseFoldMapping3_16 ${sym}[] = {\n$str\n};\n\n");
244}
245
246print("static const CaseFoldHashBucket1_16 case_fold_hash1_16[] = {\n");
247
248for (my $i = 0; $i < $HASHBUCKETS1_16; $i++) {
249 my $str = $foldPairs1_16[$i];
250 if ($str eq '') {
251 print(" { NULL, 0 },\n");
252 } else {
253 my $num = '000' . $i;
254 $num =~ s/\A.*?(\d\d\d)\Z/$1/;
255 my $sym = "case_fold1_16_${num}";
256 print(" { $sym, SDL_arraysize($sym) },\n");
257 }
258 $mem_used += 12;
259}
260print("};\n\n");
261
262
263print("static const CaseFoldHashBucket1_32 case_fold_hash1_32[] = {\n");
264
265for (my $i = 0; $i < $HASHBUCKETS1_32; $i++) {
266 my $str = $foldPairs1_32[$i];
267 if ($str eq '') {
268 print(" { NULL, 0 },\n");
269 } else {
270 my $num = '000' . $i;
271 $num =~ s/\A.*?(\d\d\d)\Z/$1/;
272 my $sym = "case_fold1_32_${num}";
273 print(" { $sym, SDL_arraysize($sym) },\n");
274 }
275 $mem_used += 12;
276}
277print("};\n\n");
278
279
280print("static const CaseFoldHashBucket2_16 case_fold_hash2_16[] = {\n");
281
282for (my $i = 0; $i < $HASHBUCKETS2_16; $i++) {
283 my $str = $foldPairs2_16[$i];
284 if ($str eq '') {
285 print(" { NULL, 0 },\n");
286 } else {
287 my $num = '000' . $i;
288 $num =~ s/\A.*?(\d\d\d)\Z/$1/;
289 my $sym = "case_fold2_16_${num}";
290 print(" { $sym, SDL_arraysize($sym) },\n");
291 }
292 $mem_used += 12;
293}
294print("};\n\n");
295
296print("static const CaseFoldHashBucket3_16 case_fold_hash3_16[] = {\n");
297
298for (my $i = 0; $i < $HASHBUCKETS3_16; $i++) {
299 my $str = $foldPairs3_16[$i];
300 if ($str eq '') {
301 print(" { NULL, 0 },\n");
302 } else {
303 my $num = '000' . $i;
304 $num =~ s/\A.*?(\d\d\d)\Z/$1/;
305 my $sym = "case_fold3_16_${num}";
306 print(" { $sym, SDL_arraysize($sym) },\n");
307 }
308 $mem_used += 12;
309}
310print("};\n\n");
311
312print <<__EOF__;
313#endif /* SDL_casefolding_h_ */
314
315__EOF__
316
317print STDERR "Memory required for case-folding hashtable: $mem_used bytes\n";
318
319exit 0;
320
321# end of makecashfoldhashtable.pl ...
322
diff --git a/src/contrib/SDL-3.2.20/build-scripts/mkinstalldirs b/src/contrib/SDL-3.2.20/build-scripts/mkinstalldirs
new file mode 100755
index 0000000..c364f3d
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/mkinstalldirs
@@ -0,0 +1,162 @@
1#! /bin/sh
2# mkinstalldirs --- make directory hierarchy
3
4scriptversion=2020-07-26.22; # UTC
5
6# Original author: Noah Friedman <friedman@prep.ai.mit.edu>
7# Created: 1993-05-16
8# Public domain.
9#
10# This file is maintained in Automake, please report
11# bugs to <bug-automake@gnu.org> or send patches to
12# <automake-patches@gnu.org>.
13
14nl='
15'
16IFS=" "" $nl"
17errstatus=0
18dirmode=
19
20usage="\
21Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ...
22
23Create each directory DIR (with mode MODE, if specified), including all
24leading file name components.
25
26Report bugs to <bug-automake@gnu.org>."
27
28# process command line arguments
29while test $# -gt 0 ; do
30 case $1 in
31 -h | --help | --h*) # -h for help
32 echo "$usage"
33 exit $?
34 ;;
35 -m) # -m PERM arg
36 shift
37 test $# -eq 0 && { echo "$usage" 1>&2; exit 1; }
38 dirmode=$1
39 shift
40 ;;
41 --version)
42 echo "$0 $scriptversion"
43 exit $?
44 ;;
45 --) # stop option processing
46 shift
47 break
48 ;;
49 -*) # unknown option
50 echo "$usage" 1>&2
51 exit 1
52 ;;
53 *) # first non-opt arg
54 break
55 ;;
56 esac
57done
58
59for file
60do
61 if test -d "$file"; then
62 shift
63 else
64 break
65 fi
66done
67
68case $# in
69 0) exit 0 ;;
70esac
71
72# Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and
73# mkdir -p a/c at the same time, both will detect that a is missing,
74# one will create a, then the other will try to create a and die with
75# a "File exists" error. This is a problem when calling mkinstalldirs
76# from a parallel make. We use --version in the probe to restrict
77# ourselves to GNU mkdir, which is thread-safe.
78case $dirmode in
79 '')
80 if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
81 echo "mkdir -p -- $*"
82 exec mkdir -p -- "$@"
83 else
84 # On NextStep and OpenStep, the 'mkdir' command does not
85 # recognize any option. It will interpret all options as
86 # directories to create, and then abort because '.' already
87 # exists.
88 test -d ./-p && rmdir ./-p
89 test -d ./--version && rmdir ./--version
90 fi
91 ;;
92 *)
93 if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 &&
94 test ! -d ./--version; then
95 echo "umask 22"
96 umask 22
97 echo "mkdir -m $dirmode -p -- $*"
98 exec mkdir -m "$dirmode" -p -- "$@"
99 else
100 # Clean up after NextStep and OpenStep mkdir.
101 for d in ./-m ./-p ./--version "./$dirmode";
102 do
103 test -d $d && rmdir $d
104 done
105 fi
106 ;;
107esac
108
109echo "umask 22"
110umask 22
111
112for file
113do
114 case $file in
115 /*) pathcomp=/ ;;
116 *) pathcomp= ;;
117 esac
118 oIFS=$IFS
119 IFS=/
120 set fnord $file
121 shift
122 IFS=$oIFS
123
124 for d
125 do
126 test "x$d" = x && continue
127
128 pathcomp=$pathcomp$d
129 case $pathcomp in
130 -*) pathcomp=./$pathcomp ;;
131 esac
132
133 if test ! -d "$pathcomp"; then
134 echo "mkdir $pathcomp"
135
136 mkdir "$pathcomp" || lasterr=$?
137
138 if test ! -d "$pathcomp"; then
139 errstatus=$lasterr
140 fi
141 fi
142
143 pathcomp=$pathcomp/
144 done
145
146 if test ! -z "$dirmode"; then
147 echo "chmod $dirmode $file"
148 chmod "$dirmode" "$file" || errstatus=$?
149 fi
150done
151
152exit $errstatus
153
154# Local Variables:
155# mode: shell-script
156# sh-indentation: 2
157# eval: (add-hook 'before-save-hook 'time-stamp)
158# time-stamp-start: "scriptversion="
159# time-stamp-format: "%:y-%02m-%02d.%02H"
160# time-stamp-time-zone: "UTC0"
161# time-stamp-end: "; # UTC"
162# End:
diff --git a/src/contrib/SDL-3.2.20/build-scripts/pkg-support/android/INSTALL.md.in b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/android/INSTALL.md.in
new file mode 100644
index 0000000..80321c2
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/android/INSTALL.md.in
@@ -0,0 +1,91 @@
1
2# Using this package
3
4This package contains @<@PROJECT_NAME@>@ built for the Android platform.
5
6## Gradle integration
7
8For integration with CMake/ndk-build, it uses [prefab](https://google.github.io/prefab/).
9
10Copy the aar archive (@<@PROJECT_NAME@>@-@<@PROJECT_VERSION@>@.aar) to a `app/libs` directory of your project.
11
12In `app/build.gradle` of your Android project, add:
13```
14android {
15 /* ... */
16 buildFeatures {
17 prefab true
18 }
19}
20dependencies {
21 implementation files('libs/@<@PROJECT_NAME@>@-@<@PROJECT_VERSION@>@.aar')
22 /* ... */
23}
24```
25
26If you're using CMake, add the following to your CMakeLists.txt:
27```
28find_package(@<@PROJECT_NAME@>@ REQUIRED CONFIG)
29target_link_libraries(yourgame PRIVATE @<@PROJECT_NAME@>@::@<@PROJECT_NAME@>@)
30```
31
32If you use ndk-build, add the following before `include $(BUILD_SHARED_LIBRARY)` to your `Android.mk`:
33```
34LOCAL_SHARED_LIBARARIES := SDL3 SDL3-Headers
35```
36And add the following at the bottom:
37```
38# https://google.github.io/prefab/build-systems.html
39
40# Add the prefab modules to the import path.
41$(call import-add-path,/out)
42
43# Import @<@PROJECT_NAME@>@ so we can depend on it.
44$(call import-module,prefab/@<@PROJECT_NAME@>@)
45```
46
47---
48
49## Other build systems (advanced)
50
51If you want to build a project without Gradle,
52running the following command will extract the Android archive into a more common directory structure.
53```
54python @<@PROJECT_NAME@>@-@<@PROJECT_VERSION@>@.aar -o android_prefix
55```
56Add `--help` for a list of all available options.
57
58# Documentation
59
60An API reference, tutorials, and additional documentation is available at:
61
62https://wiki.libsdl.org/@<@PROJECT_NAME@>@
63
64# Example code
65
66There are simple example programs available at:
67
68https://examples.libsdl.org/SDL3
69
70# Discussions
71
72## Discord
73
74You can join the official Discord server at:
75
76https://discord.com/invite/BwpFGBWsv8
77
78## Forums/mailing lists
79
80You can join SDL development discussions at:
81
82https://discourse.libsdl.org/
83
84Once you sign up, you can use the forum through the website or as a mailing list from your email client.
85
86## Announcement list
87
88You can sign up for the low traffic announcement list at:
89
90https://www.libsdl.org/mailing-list.php
91
diff --git a/src/contrib/SDL-3.2.20/build-scripts/pkg-support/android/aar/__main__.py.in b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/android/aar/__main__.py.in
new file mode 100755
index 0000000..344cf71
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/android/aar/__main__.py.in
@@ -0,0 +1,104 @@
1#!/usr/bin/env python
2
3"""
4Create a @<@PROJECT_NAME@>@ SDK prefix from an Android archive
5This file is meant to be placed in a the root of an android .aar archive
6
7Example usage:
8```sh
9python @<@PROJECT_NAME@>@-@<@PROJECT_VERSION@>@.aar -o /usr/opt/android-sdks
10cmake -S my-project \
11 -DCMAKE_PREFIX_PATH=/usr/opt/android-sdks \
12 -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake \
13 -B build-arm64 -DANDROID_ABI=arm64-v8a \
14 -DCMAKE_BUILD_TYPE=Releaase
15cmake --build build-arm64
16```
17"""
18import argparse
19import io
20import json
21import os
22import pathlib
23import re
24import stat
25import zipfile
26
27
28AAR_PATH = pathlib.Path(__file__).resolve().parent
29ANDROID_ARCHS = { "armeabi-v7a", "arm64-v8a", "x86", "x86_64" }
30
31
32def main():
33 parser = argparse.ArgumentParser(
34 description="Convert a @<@PROJECT_NAME@>@ Android .aar archive into a SDK",
35 allow_abbrev=False,
36 )
37 parser.add_argument("--version", action="version", version="@<@PROJECT_NAME@>@ @<@PROJECT_VERSION@>@")
38 parser.add_argument("-o", dest="output", type=pathlib.Path, required=True, help="Folder where to store the SDK")
39 args = parser.parse_args()
40
41 print(f"Creating a @<@PROJECT_NAME@>@ SDK at {args.output}...")
42
43 prefix = args.output
44 incdir = prefix / "include"
45 libdir = prefix / "lib"
46
47 RE_LIB_MODULE_ARCH = re.compile(r"prefab/modules/(?P<module>[A-Za-z0-9_-]+)/libs/android\.(?P<arch>[a-zA-Z0-9_-]+)/(?P<filename>lib[A-Za-z0-9_]+\.(?:so|a))")
48 RE_INC_MODULE_ARCH = re.compile(r"prefab/modules/(?P<module>[A-Za-z0-9_-]+)/include/(?P<header>[a-zA-Z0-9_./-]+)")
49 RE_LICENSE = re.compile(r"(?:.*/)?(?P<filename>(?:license|copying)(?:\.md|\.txt)?)", flags=re.I)
50 RE_PROGUARD = re.compile(r"(?:.*/)?(?P<filename>proguard.*\.(?:pro|txt))", flags=re.I)
51 RE_CMAKE = re.compile(r"(?:.*/)?(?P<filename>.*\.cmake)", flags=re.I)
52
53 with zipfile.ZipFile(AAR_PATH) as zf:
54 project_description = json.loads(zf.read("description.json"))
55 project_name = project_description["name"]
56 project_version = project_description["version"]
57 licensedir = prefix / "share/licenses" / project_name
58 cmakedir = libdir / "cmake" / project_name
59 javadir = prefix / "share/java" / project_name
60 javadocdir = prefix / "share/javadoc" / project_name
61
62 def read_zipfile_and_write(path: pathlib.Path, zippath: str):
63 data = zf.read(zippath)
64 path.parent.mkdir(parents=True, exist_ok=True)
65 path.write_bytes(data)
66
67 for zip_info in zf.infolist():
68 zippath = zip_info.filename
69 if m := RE_LIB_MODULE_ARCH.match(zippath):
70 lib_path = libdir / m["arch"] / m["filename"]
71 read_zipfile_and_write(lib_path, zippath)
72 if m["filename"].endswith(".so"):
73 os.chmod(lib_path, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
74
75 elif m := RE_INC_MODULE_ARCH.match(zippath):
76 header_path = incdir / m["header"]
77 read_zipfile_and_write(header_path, zippath)
78 elif m:= RE_LICENSE.match(zippath):
79 license_path = licensedir / m["filename"]
80 read_zipfile_and_write(license_path, zippath)
81 elif m:= RE_PROGUARD.match(zippath):
82 proguard_path = javadir / m["filename"]
83 read_zipfile_and_write(proguard_path, zippath)
84 elif m:= RE_CMAKE.match(zippath):
85 cmake_path = cmakedir / m["filename"]
86 read_zipfile_and_write(cmake_path, zippath)
87 elif zippath == "classes.jar":
88 versioned_jar_path = javadir / f"{project_name}-{project_version}.jar"
89 unversioned_jar_path = javadir / f"{project_name}.jar"
90 read_zipfile_and_write(versioned_jar_path, zippath)
91 os.symlink(src=versioned_jar_path.name, dst=unversioned_jar_path)
92 elif zippath == "classes-sources.jar":
93 jarpath = javadir / f"{project_name}-{project_version}-sources.jar"
94 read_zipfile_and_write(jarpath, zippath)
95 elif zippath == "classes-doc.jar":
96 jarpath = javadocdir / f"{project_name}-{project_version}-javadoc.jar"
97 read_zipfile_and_write(jarpath, zippath)
98
99 print("... done")
100 return 0
101
102
103if __name__ == "__main__":
104 raise SystemExit(main())
diff --git a/src/contrib/SDL-3.2.20/build-scripts/pkg-support/android/aar/cmake/SDL3ConfigVersion.cmake.in b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/android/aar/cmake/SDL3ConfigVersion.cmake.in
new file mode 100644
index 0000000..3268da7
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/android/aar/cmake/SDL3ConfigVersion.cmake.in
@@ -0,0 +1,38 @@
1# @<@PROJECT_NAME@>@ CMake version configuration file:
2# This file is meant to be placed in a lib/cmake/@<@PROJECT_NAME@>@ subfolder of a reconstructed Android SDL3 SDK
3
4set(PACKAGE_VERSION "@<@PROJECT_VERSION@>@")
5
6if(PACKAGE_FIND_VERSION_RANGE)
7 # Package version must be in the requested version range
8 if ((PACKAGE_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MIN)
9 OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_MAX)
10 OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION_MAX)))
11 set(PACKAGE_VERSION_COMPATIBLE FALSE)
12 else()
13 set(PACKAGE_VERSION_COMPATIBLE TRUE)
14 endif()
15else()
16 if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
17 set(PACKAGE_VERSION_COMPATIBLE FALSE)
18 else()
19 set(PACKAGE_VERSION_COMPATIBLE TRUE)
20 if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
21 set(PACKAGE_VERSION_EXACT TRUE)
22 endif()
23 endif()
24endif()
25
26# if the using project doesn't have CMAKE_SIZEOF_VOID_P set, fail.
27if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "")
28 set(PACKAGE_VERSION_UNSUITABLE TRUE)
29endif()
30
31include("${CMAKE_CURRENT_LIST_DIR}/sdlcpu.cmake")
32SDL_DetectTargetCPUArchitectures(_detected_archs)
33
34# check that the installed version has a compatible architecture as the one which is currently searching:
35if(NOT(SDL_CPU_X86 OR SDL_CPU_X64 OR SDL_CPU_ARM32 OR SDL_CPU_ARM64))
36 set(PACKAGE_VERSION "${PACKAGE_VERSION} (X86,X64,ARM32,ARM64)")
37 set(PACKAGE_VERSION_UNSUITABLE TRUE)
38endif()
diff --git a/src/contrib/SDL-3.2.20/build-scripts/pkg-support/android/aar/description.json.in b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/android/aar/description.json.in
new file mode 100644
index 0000000..e75ef38
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/android/aar/description.json.in
@@ -0,0 +1,5 @@
1{
2 "name": "@<@PROJECT_NAME@>@",
3 "version": "@<@PROJECT_VERSION@>@",
4 "git-hash": "@<@PROJECT_COMMIT@>@"
5}
diff --git a/src/contrib/SDL-3.2.20/build-scripts/pkg-support/mingw/INSTALL.md.in b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/mingw/INSTALL.md.in
new file mode 100644
index 0000000..f1a6a78
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/mingw/INSTALL.md.in
@@ -0,0 +1,53 @@
1
2# Using this package
3
4This package contains @<@PROJECT_NAME@>@ built for the mingw-w64 toolchain.
5
6The files for 32-bit architecture are in i686-w64-mingw32
7The files for 64-bit architecture are in x86_64-w64-mingw32
8
9You can install them to another location, just type `make` for help.
10
11To use this package, point your include path at _arch_/include and your library path at _arch_/lib, link with the @<@PROJECT_NAME@>@ library and copy _arch_/bin/@<@PROJECT_NAME@>@.dll next to your executable.
12
13e.g.
14```sh
15gcc -o hello.exe hello.c -Ix86_64-w64-mingw32/include -Lx86_64-w64-mingw32/lib -l@<@PROJECT_NAME@>@
16cp x86_64-w64-mingw32/bin/@<@PROJECT_NAME@>@.dll .
17./hello.exe
18```
19
20# Documentation
21
22An API reference, tutorials, and additional documentation is available at:
23
24https://wiki.libsdl.org/@<@PROJECT_NAME@>@
25
26# Example code
27
28There are simple example programs available at:
29
30https://examples.libsdl.org/SDL3
31
32# Discussions
33
34## Discord
35
36You can join the official Discord server at:
37
38https://discord.com/invite/BwpFGBWsv8
39
40## Forums/mailing lists
41
42You can join SDL development discussions at:
43
44https://discourse.libsdl.org/
45
46Once you sign up, you can use the forum through the website or as a mailing list from your email client.
47
48## Announcement list
49
50You can sign up for the low traffic announcement list at:
51
52https://www.libsdl.org/mailing-list.php
53
diff --git a/src/contrib/SDL-3.2.20/build-scripts/pkg-support/mingw/Makefile b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/mingw/Makefile
new file mode 100644
index 0000000..9b6cd55
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/mingw/Makefile
@@ -0,0 +1,39 @@
1#
2# Makefile for installing the mingw32 version of the SDL library
3
4DESTDIR = /usr/local
5ARCHITECTURES := i686-w64-mingw32 x86_64-w64-mingw32
6
7default:
8 @echo "Run \"make install-i686\" to install 32-bit"
9 @echo "Run \"make install-x86_64\" to install 64-bit"
10 @echo "Run \"make install-all\" to install both"
11 @echo "Add DESTDIR=/custom/path to change the destination folder"
12
13install:
14 @if test -d $(ARCH) && test -d $(DESTDIR); then \
15 (cd $(ARCH) && cp -rv bin include lib share $(DESTDIR)/); \
16 else \
17 echo "*** ERROR: $(ARCH) or $(DESTDIR) does not exist!"; \
18 exit 1; \
19 fi
20
21install-i686:
22 $(MAKE) install ARCH=i686-w64-mingw32
23
24install-x86_64:
25 $(MAKE) install ARCH=x86_64-w64-mingw32
26
27install-all:
28 @if test -d $(DESTDIR); then \
29 mkdir -p $(DESTDIR)/cmake; \
30 cp -rv cmake/* $(DESTDIR)/cmake; \
31 for arch in $(ARCHITECTURES); do \
32 $(MAKE) install ARCH=$$arch DESTDIR=$(DESTDIR)/$$arch; \
33 done \
34 else \
35 echo "*** ERROR: $(DESTDIR) does not exist!"; \
36 exit 1; \
37 fi
38
39.PHONY: default install install-i686 install-x86_64 install-all
diff --git a/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/Directory.Build.props b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/Directory.Build.props
new file mode 100644
index 0000000..24033f4
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/Directory.Build.props
@@ -0,0 +1,8 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <ItemDefinitionGroup>
4 <ClCompile>
5 <PreprocessorDefinitions>SDL_VENDOR_INFO="libsdl.org";%(PreprocessorDefinitions)</PreprocessorDefinitions>
6 </ClCompile>
7 </ItemDefinitionGroup>
8</Project>
diff --git a/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/INSTALL.md.in b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/INSTALL.md.in
new file mode 100644
index 0000000..671f524
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/INSTALL.md.in
@@ -0,0 +1,45 @@
1
2# Using this package
3
4This package contains @<@PROJECT_NAME@>@ built for Visual Studio.
5
6To use this package, edit your project properties:
7- Add the include directory to "VC++ Directories" -> "Include Directories"
8- Add the lib/_arch_ directory to "VC++ Directories" -> "Library Directories"
9- Add @<@PROJECT_NAME@>@.lib to Linker -> Input -> "Additional Dependencies"
10- Copy lib/_arch_/@<@PROJECT_NAME@>@.dll to your project directory.
11
12# Documentation
13
14An API reference, tutorials, and additional documentation is available at:
15
16https://wiki.libsdl.org/@<@PROJECT_NAME@>@
17
18# Example code
19
20There are simple example programs available at:
21
22https://examples.libsdl.org/SDL3
23
24# Discussions
25
26## Discord
27
28You can join the official Discord server at:
29
30https://discord.com/invite/BwpFGBWsv8
31
32## Forums/mailing lists
33
34You can join SDL development discussions at:
35
36https://discourse.libsdl.org/
37
38Once you sign up, you can use the forum through the website or as a mailing list from your email client.
39
40## Announcement list
41
42You can sign up for the low traffic announcement list at:
43
44https://www.libsdl.org/mailing-list.php
45
diff --git a/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/arm64/INSTALL.md.in b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/arm64/INSTALL.md.in
new file mode 100644
index 0000000..c185171
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/arm64/INSTALL.md.in
@@ -0,0 +1,13 @@
1
2# Using this package
3
4This package contains @<@PROJECT_NAME@>@ built for arm64 Windows.
5
6To use this package, simply replace an existing 64-bit ARM @<@PROJECT_NAME@>@.dll with the one included here.
7
8# Development packages
9
10If you're looking for packages with headers and libraries, you can download one of these:
11- @<@PROJECT_NAME@>@-devel-@<@PROJECT_VERSION@>@-VC.zip, for development using Visual Studio
12- @<@PROJECT_NAME@>@-devel-@<@PROJECT_VERSION@>@-mingw.zip, for development using mingw-w64
13
diff --git a/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/cmake/SDL3Config.cmake.in b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/cmake/SDL3Config.cmake.in
new file mode 100644
index 0000000..6387376
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/cmake/SDL3Config.cmake.in
@@ -0,0 +1,135 @@
1# @<@PROJECT_NAME@>@ CMake configuration file:
2# This file is meant to be placed in a cmake subfolder of @<@PROJECT_NAME@>@-devel-@<@PROJECT_VERSION@>@-VC.zip
3
4cmake_minimum_required(VERSION 3.0...3.28)
5
6include(FeatureSummary)
7set_package_properties(SDL3 PROPERTIES
8 URL "https://www.libsdl.org/"
9 DESCRIPTION "low level access to audio, keyboard, mouse, joystick, and graphics hardware"
10)
11
12# Copied from `configure_package_config_file`
13macro(set_and_check _var _file)
14 set(${_var} "${_file}")
15 if(NOT EXISTS "${_file}")
16 message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
17 endif()
18endmacro()
19
20# Copied from `configure_package_config_file`
21macro(check_required_components _NAME)
22 foreach(comp ${${_NAME}_FIND_COMPONENTS})
23 if(NOT ${_NAME}_${comp}_FOUND)
24 if(${_NAME}_FIND_REQUIRED_${comp})
25 set(${_NAME}_FOUND FALSE)
26 endif()
27 endif()
28 endforeach()
29endmacro()
30
31set(SDL3_FOUND TRUE)
32
33if(SDL_CPU_X86)
34 set(_sdl_arch_subdir "x86")
35elseif(SDL_CPU_X64 OR SDL_CPU_ARM64EC)
36 set(_sdl_arch_subdir "x64")
37elseif(SDL_CPU_ARM64)
38 set(_sdl_arch_subdir "arm64")
39else()
40 set(SDL3_FOUND FALSE)
41 return()
42endif()
43
44get_filename_component(_sdl3_prefix "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
45set_and_check(_sdl3_prefix "${_sdl3_prefix}")
46set(_sdl3_include_dirs "${_sdl3_prefix}/include")
47
48set(_sdl3_implib "${_sdl3_prefix}/lib/${_sdl_arch_subdir}/SDL3.lib")
49set(_sdl3_dll "${_sdl3_prefix}/lib/${_sdl_arch_subdir}/SDL3.dll")
50set(_sdl3test_lib "${_sdl3_prefix}/lib/${_sdl_arch_subdir}/SDL3_test.lib")
51
52unset(_sdl_arch_subdir)
53unset(_sdl3_prefix)
54
55# All targets are created, even when some might not be requested though COMPONENTS.
56# This is done for compatibility with CMake generated SDL3-target.cmake files.
57
58if(NOT TARGET SDL3::Headers)
59 add_library(SDL3::Headers INTERFACE IMPORTED)
60 set_target_properties(SDL3::Headers
61 PROPERTIES
62 INTERFACE_INCLUDE_DIRECTORIES "${_sdl3_include_dirs}"
63 )
64endif()
65set(SDL3_Headers_FOUND TRUE)
66unset(_sdl3_include_dirs)
67
68if(EXISTS "${_sdl3_implib}" AND EXISTS "${_sdl3_dll}")
69 if(NOT TARGET SDL3::SDL3-shared)
70 add_library(SDL3::SDL3-shared SHARED IMPORTED)
71 set_target_properties(SDL3::SDL3-shared
72 PROPERTIES
73 INTERFACE_LINK_LIBRARIES "SDL3::Headers"
74 IMPORTED_IMPLIB "${_sdl3_implib}"
75 IMPORTED_LOCATION "${_sdl3_dll}"
76 COMPATIBLE_INTERFACE_BOOL "SDL3_SHARED"
77 INTERFACE_SDL3_SHARED "ON"
78 COMPATIBLE_INTERFACE_STRING "SDL_VERSION"
79 INTERFACE_SDL_VERSION "SDL3"
80 )
81 endif()
82 set(SDL3_SDL3-shared_FOUND TRUE)
83else()
84 set(SDL3_SDL3-shared_FOUND FALSE)
85endif()
86unset(_sdl3_implib)
87unset(_sdl3_dll)
88
89set(SDL3_SDL3-static_FOUND FALSE)
90
91if(EXISTS "${_sdl3test_lib}")
92 if(NOT TARGET SDL3::SDL3_test)
93 add_library(SDL3::SDL3_test STATIC IMPORTED)
94 set_target_properties(SDL3::SDL3_test
95 PROPERTIES
96 INTERFACE_LINK_LIBRARIES "SDL3::Headers"
97 IMPORTED_LOCATION "${_sdl3test_lib}"
98 COMPATIBLE_INTERFACE_STRING "SDL_VERSION"
99 INTERFACE_SDL_VERSION "SDL3"
100 )
101 endif()
102 set(SDL3_SDL3_test_FOUND TRUE)
103else()
104 set(SDL3_SDL3_test_FOUND FALSE)
105endif()
106unset(_sdl3test_lib)
107
108if(SDL3_SDL3-shared_FOUND OR SDL3_SDL3-static_FOUND)
109 set(SDL3_SDL3_FOUND TRUE)
110endif()
111
112function(_sdl_create_target_alias_compat NEW_TARGET TARGET)
113 if(CMAKE_VERSION VERSION_LESS "3.18")
114 # Aliasing local targets is not supported on CMake < 3.18, so make it global.
115 add_library(${NEW_TARGET} INTERFACE IMPORTED)
116 set_target_properties(${NEW_TARGET} PROPERTIES INTERFACE_LINK_LIBRARIES "${TARGET}")
117 else()
118 add_library(${NEW_TARGET} ALIAS ${TARGET})
119 endif()
120endfunction()
121
122# Make sure SDL3::SDL3 always exists
123if(NOT TARGET SDL3::SDL3)
124 if(TARGET SDL3::SDL3-shared)
125 _sdl_create_target_alias_compat(SDL3::SDL3 SDL3::SDL3-shared)
126 endif()
127endif()
128
129check_required_components(SDL3)
130
131set(SDL3_LIBRARIES SDL3::SDL3)
132set(SDL3_STATIC_LIBRARIES SDL3::SDL3-static)
133set(SDL3_STATIC_PRIVATE_LIBS)
134
135set(SDL3TEST_LIBRARY SDL3::SDL3_test)
diff --git a/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/cmake/SDL3ConfigVersion.cmake.in b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/cmake/SDL3ConfigVersion.cmake.in
new file mode 100644
index 0000000..82b6af0
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/cmake/SDL3ConfigVersion.cmake.in
@@ -0,0 +1,38 @@
1# @<@PROJECT_NAME@>@ CMake version configuration file:
2# This file is meant to be placed in a cmake subfolder of @<@PROJECT_NAME@>@-devel-@<@PROJECT_VERSION@>@-VC.zip
3
4set(PACKAGE_VERSION "@<@PROJECT_VERSION@>@")
5
6if(PACKAGE_FIND_VERSION_RANGE)
7 # Package version must be in the requested version range
8 if ((PACKAGE_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MIN)
9 OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_MAX)
10 OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION_MAX)))
11 set(PACKAGE_VERSION_COMPATIBLE FALSE)
12 else()
13 set(PACKAGE_VERSION_COMPATIBLE TRUE)
14 endif()
15else()
16 if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
17 set(PACKAGE_VERSION_COMPATIBLE FALSE)
18 else()
19 set(PACKAGE_VERSION_COMPATIBLE TRUE)
20 if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
21 set(PACKAGE_VERSION_EXACT TRUE)
22 endif()
23 endif()
24endif()
25
26# if the using project doesn't have CMAKE_SIZEOF_VOID_P set, fail.
27if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "")
28 set(PACKAGE_VERSION_UNSUITABLE TRUE)
29endif()
30
31include("${CMAKE_CURRENT_LIST_DIR}/sdlcpu.cmake")
32SDL_DetectTargetCPUArchitectures(_detected_archs)
33
34# check that the installed version has a compatible architecture as the one which is currently searching:
35if(NOT(SDL_CPU_X86 OR SDL_CPU_X64 OR SDL_CPU_ARM64 OR SDL_CPU_ARM64EC))
36 set(PACKAGE_VERSION "${PACKAGE_VERSION} (X86,X64,ARM64)")
37 set(PACKAGE_VERSION_UNSUITABLE TRUE)
38endif()
diff --git a/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/x64/INSTALL.md.in b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/x64/INSTALL.md.in
new file mode 100644
index 0000000..74cd678
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/x64/INSTALL.md.in
@@ -0,0 +1,13 @@
1
2# Using this package
3
4This package contains @<@PROJECT_NAME@>@ built for x64 Windows.
5
6To use this package, simply replace an existing 64-bit @<@PROJECT_NAME@>@.dll with the one included here.
7
8# Development packages
9
10If you're looking for packages with headers and libraries, you can download one of these:
11- @<@PROJECT_NAME@>@-devel-@<@PROJECT_VERSION@>@-VC.zip, for development using Visual Studio
12- @<@PROJECT_NAME@>@-devel-@<@PROJECT_VERSION@>@-mingw.zip, for development using mingw-w64
13
diff --git a/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/x86/INSTALL.md.in b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/x86/INSTALL.md.in
new file mode 100644
index 0000000..041c116
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/msvc/x86/INSTALL.md.in
@@ -0,0 +1,13 @@
1
2# Using this package
3
4This package contains @<@PROJECT_NAME@>@ built for x86 Windows.
5
6To use this package, simply replace an existing 32-bit @<@PROJECT_NAME@>@.dll with the one included here.
7
8# Development packages
9
10If you're looking for packages with headers and libraries, you can download one of these:
11- @<@PROJECT_NAME@>@-devel-@<@PROJECT_VERSION@>@-VC.zip, for development using Visual Studio
12- @<@PROJECT_NAME@>@-devel-@<@PROJECT_VERSION@>@-mingw.zip, for development using mingw-w64
13
diff --git a/src/contrib/SDL-3.2.20/build-scripts/pkg-support/source/SDL_revision.h.cmake.in b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/source/SDL_revision.h.cmake.in
new file mode 100644
index 0000000..99e9f80
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/source/SDL_revision.h.cmake.in
@@ -0,0 +1,41 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21
22/* WIKI CATEGORY: Version */
23
24/*
25 * SDL_revision.h contains the SDL revision, which might be defined on the
26 * compiler command line, or generated right into the header itself by the
27 * build system.
28 */
29
30#ifndef SDL_revision_h_
31#define SDL_revision_h_
32
33#cmakedefine SDL_VENDOR_INFO "@SDL_VENDOR_INFO@"
34
35#if defined(SDL_VENDOR_INFO)
36#define SDL_REVISION "@<@PROJECT_REVISION@>@ (" SDL_VENDOR_INFO ")"
37#else
38#define SDL_REVISION "@<@PROJECT_REVISION@>@"
39#endif
40
41#endif /* SDL_revision_h_ */
diff --git a/src/contrib/SDL-3.2.20/build-scripts/pkg-support/source/SDL_revision.h.in b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/source/SDL_revision.h.in
new file mode 100644
index 0000000..7dd6bc1
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/pkg-support/source/SDL_revision.h.in
@@ -0,0 +1,56 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21
22/* WIKI CATEGORY: Version */
23
24/*
25 * SDL_revision.h contains the SDL revision, which might be defined on the
26 * compiler command line, or generated right into the header itself by the
27 * build system.
28 */
29
30#ifndef SDL_revision_h_
31#define SDL_revision_h_
32
33#ifdef SDL_WIKI_DOCUMENTATION_SECTION
34
35/**
36 * This macro is a string describing the source at a particular point in
37 * development.
38 *
39 * This string is often generated from revision control's state at build time.
40 *
41 * This string can be quite complex and does not follow any standard. For
42 * example, it might be something like "SDL-prerelease-3.1.1-47-gf687e0732".
43 * It might also be user-defined at build time, so it's best to treat it as a
44 * clue in debugging forensics and not something the app will parse in any
45 * way.
46 *
47 * \since This macro is available since SDL 3.0.0.
48 */
49#define SDL_REVISION "Some arbitrary string decided at SDL build time"
50#elif defined(SDL_VENDOR_INFO)
51#define SDL_REVISION "@<@PROJECT_REVISION@>@ (" SDL_VENDOR_INFO ")"
52#else
53#define SDL_REVISION "@<@PROJECT_REVISION@>@"
54#endif
55
56#endif /* SDL_revision_h_ */
diff --git a/src/contrib/SDL-3.2.20/build-scripts/release-info.json b/src/contrib/SDL-3.2.20/build-scripts/release-info.json
new file mode 100644
index 0000000..8ba213a
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/release-info.json
@@ -0,0 +1,210 @@
1{
2 "name": "SDL3",
3 "remote": "libsdl-org/SDL",
4 "version": {
5 "file": "include/SDL3/SDL_version.h",
6 "re_major": "^#define SDL_MAJOR_VERSION\\s+([0-9]+)$",
7 "re_minor": "^#define SDL_MINOR_VERSION\\s+([0-9]+)$",
8 "re_micro": "^#define SDL_MICRO_VERSION\\s+([0-9]+)$"
9 },
10 "source": {
11 "checks": [
12 "src/SDL.c",
13 "include/SDL3/SDL.h",
14 "test/testsprite.c",
15 "android-project/app/src/main/java/org/libsdl/app/SDLActivity.java"
16 ],
17 "files": {
18 "include/SDL3": [
19 "build-scripts/pkg-support/source/SDL_revision.h.in:SDL_revision.h"
20 ],
21 "include/build_config": [
22 "build-scripts/pkg-support/source/SDL_revision.h.cmake.in:SDL_revision.h.cmake"
23 ]
24 }
25 },
26 "dmg": {
27 "project": "Xcode/SDL/SDL.xcodeproj",
28 "path": "Xcode/SDL/build/SDL3.dmg",
29 "target": "SDL3.dmg",
30 "build-xcconfig": "Xcode/SDL/pkg-support/build.xcconfig"
31 },
32 "mingw": {
33 "cmake": {
34 "archs": ["x86", "x64"],
35 "args": [
36 "-DSDL_SHARED=ON",
37 "-DSDL_STATIC=OFF",
38 "-DSDL_DISABLE_INSTALL_DOCS=ON",
39 "-DSDL_RELOCATABLE=ON",
40 "-DSDL_TEST_LIBRARY=ON",
41 "-DSDL_TESTS=OFF",
42 "-DSDL_VENDOR_INFO=libsdl.org"
43 ],
44 "shared-static": "args"
45 },
46 "files": {
47 "": [
48 "build-scripts/pkg-support/mingw/INSTALL.md.in:INSTALL.md",
49 "build-scripts/pkg-support/mingw/Makefile",
50 "LICENSE.txt",
51 "README.md"
52 ],
53 "cmake": [
54 "build-scripts/pkg-support/mingw/cmake/SDL3Config.cmake",
55 "build-scripts/pkg-support/mingw/cmake/SDL3ConfigVersion.cmake"
56 ]
57 }
58 },
59 "msvc": {
60 "msbuild": {
61 "archs": [
62 "x86",
63 "x64"
64 ],
65 "directory-build-props": "build-scripts/pkg-support/msvc/Directory.Build.props",
66 "projects": [
67 "VisualC/SDL/SDL.vcxproj",
68 "VisualC/SDL_test/SDL_test.vcxproj"
69 ],
70 "files-lib": {
71 "": [
72 "VisualC/SDL/@<@PLATFORM@>@/@<@CONFIGURATION@>@/SDL3.dll"
73 ]
74 },
75 "files-devel": {
76 "lib/@<@ARCH@>@": [
77 "VisualC/SDL/@<@PLATFORM@>@/@<@CONFIGURATION@>@/SDL3.dll",
78 "VisualC/SDL/@<@PLATFORM@>@/@<@CONFIGURATION@>@/SDL3.lib",
79 "VisualC/SDL/@<@PLATFORM@>@/@<@CONFIGURATION@>@/SDL3.pdb",
80 "VisualC/SDL_test/@<@PLATFORM@>@/@<@CONFIGURATION@>@/SDL3_test.lib"
81 ]
82 }
83 },
84 "cmake": {
85 "archs": [
86 "arm64"
87 ],
88 "args": [
89 "-DSDL_SHARED=ON",
90 "-DSDL_STATIC=OFF",
91 "-DSDL_TEST_LIBRARY=ON",
92 "-DSDL_TESTS=OFF",
93 "-DSDL_DISABLE_INSTALL_DOCS=ON",
94 "-DSDL_RELOCATABLE=ON",
95 "-DSDL_VENDOR_INFO=libsdl.org"
96 ],
97 "files-lib": {
98 "": [
99 "bin/SDL3.dll"
100 ]
101 },
102 "files-devel": {
103 "lib/@<@ARCH@>@": [
104 "bin/SDL3.dll",
105 "bin/SDL3.pdb",
106 "lib/SDL3.lib",
107 "lib/SDL3_test.lib"
108 ]
109 }
110 },
111 "files-lib": {
112 "": [
113 "build-scripts/pkg-support/msvc/@<@ARCH@>@/INSTALL.md.in:INSTALL.md",
114 "LICENSE.txt",
115 "README.md"
116 ]
117 },
118 "files-devel": {
119 "": [
120 "build-scripts/pkg-support/msvc/INSTALL.md.in:INSTALL.md",
121 "LICENSE.txt",
122 "README.md"
123 ],
124 "cmake": [
125 "build-scripts/pkg-support/msvc/cmake/SDL3Config.cmake.in:SDL3Config.cmake",
126 "build-scripts/pkg-support/msvc/cmake/SDL3ConfigVersion.cmake.in:SDL3ConfigVersion.cmake",
127 "cmake/sdlcpu.cmake"
128 ],
129 "include/SDL3": [
130 "include/SDL3/*.h"
131 ]
132 }
133 },
134 "android": {
135 "cmake": {
136 "args": [
137 "-DSDL_SHARED=ON",
138 "-DSDL_STATIC=OFF",
139 "-DSDL_TEST_LIBRARY=ON",
140 "-DSDL_TESTS=OFF",
141 "-DSDL_ANDROID_JAR=ON",
142 "-DSDL_INSTALL=ON",
143 "-DSDL_INSTALL_DOCS=ON",
144 "-DSDL_VENDOR_INFO=libsdl.org"
145 ]
146 },
147 "modules": {
148 "SDL3-Headers": {
149 "type": "interface",
150 "includes": {
151 "SDL3": ["include/SDL3/*.h"]
152 }
153 },
154 "Headers": {
155 "type": "interface",
156 "export-libraries": [":SDL3-Headers"]
157 },
158 "SDL3_test": {
159 "type": "library",
160 "library": "lib/libSDL3_test.a",
161 "export-libraries": [":Headers"]
162 },
163 "SDL3-shared": {
164 "type": "library",
165 "library": "lib/libSDL3.so",
166 "export-libraries": [":Headers"]
167 },
168 "SDL3": {
169 "type": "interface",
170 "export-libraries": [":SDL3-shared"]
171 }
172 },
173 "jars": {
174 "classes": "share/java/@<@PROJECT_NAME@>@/@<@PROJECT_NAME@>@-@<@PROJECT_VERSION@>@.jar",
175 "sources": "share/java/@<@PROJECT_NAME@>@/@<@PROJECT_NAME@>@-@<@PROJECT_VERSION@>@-sources.jar",
176 "doc": "share/javadoc/@<@PROJECT_NAME@>@/@<@PROJECT_NAME@>@-@<@PROJECT_VERSION@>@-javadoc.jar"
177 },
178 "abis": [
179 "armeabi-v7a",
180 "arm64-v8a",
181 "x86",
182 "x86_64"
183 ],
184 "api-minimum": 21,
185 "api-target": 35,
186 "ndk-minimum": 21,
187 "aar-files": {
188 "": [
189 "android-project/app/proguard-rules.pro:proguard.txt",
190 "build-scripts/pkg-support/android/aar/__main__.py.in:__main__.py",
191 "build-scripts/pkg-support/android/aar/description.json.in:description.json"
192 ],
193 "META-INF": [
194 "LICENSE.txt"
195 ],
196 "cmake": [
197 "cmake/sdlcpu.cmake",
198 "build-scripts/pkg-support/android/aar/cmake/SDL3Config.cmake",
199 "build-scripts/pkg-support/android/aar/cmake/SDL3ConfigVersion.cmake.in:SDL3ConfigVersion.cmake"
200 ]
201 },
202 "files": {
203 "": [
204 "build-scripts/pkg-support/android/INSTALL.md.in:INSTALL.md",
205 "LICENSE.txt",
206 "README.md"
207 ]
208 }
209 }
210}
diff --git a/src/contrib/SDL-3.2.20/build-scripts/rename_api.py b/src/contrib/SDL-3.2.20/build-scripts/rename_api.py
new file mode 100755
index 0000000..605ffa0
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/rename_api.py
@@ -0,0 +1,254 @@
1#!/usr/bin/env python3
2#
3# This script renames symbols in the API, updating SDL_oldnames.h and
4# adding documentation for the change.
5
6import argparse
7import os
8import pathlib
9import pprint
10import re
11import sys
12from rename_symbols import create_regex_from_replacements, replace_symbols_in_path
13
14SDL_ROOT = pathlib.Path(__file__).resolve().parents[1]
15
16SDL_INCLUDE_DIR = SDL_ROOT / "include/SDL3"
17SDL_BUILD_SCRIPTS = SDL_ROOT / "build-scripts"
18
19
20def main():
21 if len(args.args) == 0 or (len(args.args) % 2) != 0:
22 print("Usage: %s [-h] [--skip-header-check] header {enum,function,hint,structure,symbol} [old new ...]" % sys.argv[0])
23 exit(1)
24
25 # Check whether we can still modify the ABI
26 version_header = pathlib.Path( SDL_INCLUDE_DIR / "SDL_version.h" ).read_text()
27 if not re.search(r"SDL_MINOR_VERSION\s+[01]\s", version_header):
28 raise Exception("ABI is frozen, symbols cannot be renamed")
29
30 # Find the symbol in the headers
31 if pathlib.Path(args.header).is_file():
32 header = pathlib.Path(args.header)
33 else:
34 header = pathlib.Path(SDL_INCLUDE_DIR / args.header)
35
36 if not header.exists():
37 raise Exception("Couldn't find header %s" % header)
38
39 header_name = header.name
40 if (header.name == "SDL_gamepad.h"):
41 header_name = "SDL_gamecontroller.h"
42
43 header_text = header.read_text()
44
45 # Replace the symbols in source code
46 replacements = {}
47 i = 0
48 while i < len(args.args):
49 oldname = args.args[i + 0]
50 newname = args.args[i + 1]
51
52 if not args.skip_header_check and not re.search((r"\b%s\b" % oldname), header_text):
53 raise Exception("Couldn't find %s in %s" % (oldname, header))
54
55 replacements[ oldname ] = newname
56 replacements[ oldname + "_REAL" ] = newname + "_REAL"
57 i += 2
58
59 regex = create_regex_from_replacements(replacements)
60 for dir in ["src", "test", "examples", "include", "docs", "cmake/test"]:
61 replace_symbols_in_path(SDL_ROOT / dir, regex, replacements)
62
63 # Replace the symbols in documentation
64 i = 0
65 while i < len(args.args):
66 oldname = args.args[i + 0]
67 newname = args.args[i + 1]
68
69 add_symbol_to_oldnames(header_name, oldname, newname)
70 add_symbol_to_migration(header_name, args.type, oldname, newname)
71 add_symbol_to_coccinelle(args.type, oldname, newname)
72 i += 2
73
74
75def add_line(lines, i, section):
76 lines.insert(i, section)
77 i += 1
78 return i
79
80
81def add_content(lines, i, content, add_trailing_line):
82 if lines[i - 1] == "":
83 lines[i - 1] = content
84 else:
85 i = add_line(lines, i, content)
86
87 if add_trailing_line:
88 i = add_line(lines, i, "")
89 return i
90
91
92def add_symbol_to_coccinelle(symbol_type, oldname, newname):
93 file = open(SDL_BUILD_SCRIPTS / "SDL_migration.cocci", "a")
94 # Append-adds at last
95
96 if symbol_type == "function":
97 file.write("@@\n")
98 file.write("@@\n")
99 file.write("- %s\n" % oldname)
100 file.write("+ %s\n" % newname)
101 file.write(" (...)\n")
102
103 if symbol_type == "symbol":
104 file.write("@@\n")
105 file.write("@@\n")
106 file.write("- %s\n" % oldname)
107 file.write("+ %s\n" % newname)
108
109 # double check ?
110 if symbol_type == "hint":
111 file.write("@@\n")
112 file.write("@@\n")
113 file.write("- %s\n" % oldname)
114 file.write("+ %s\n" % newname)
115
116 if symbol_type == "enum" or symbol_type == "structure":
117 file.write("@@\n")
118 file.write("typedef %s, %s;\n" % (oldname, newname))
119 file.write("@@\n")
120 file.write("- %s\n" % oldname)
121 file.write("+ %s\n" % newname)
122
123 file.close()
124
125
126def add_symbol_to_oldnames(header, oldname, newname):
127 file = (SDL_INCLUDE_DIR / "SDL_oldnames.h")
128 lines = file.read_text().splitlines()
129 mode = 0
130 i = 0
131 while i < len(lines):
132 line = lines[i]
133 if line == "#ifdef SDL_ENABLE_OLD_NAMES":
134 if mode == 0:
135 mode = 1
136 section = ("/* ##%s */" % header)
137 section_added = False
138 content = ("#define %s %s" % (oldname, newname))
139 content_added = False
140 else:
141 raise Exception("add_symbol_to_oldnames(): expected mode 0")
142 elif line == "#elif !defined(SDL_DISABLE_OLD_NAMES)":
143 if mode == 1:
144 if not section_added:
145 i = add_line(lines, i, section)
146
147 if not content_added:
148 i = add_content(lines, i, content, True)
149
150 mode = 2
151 section = ("/* ##%s */" % header)
152 section_added = False
153 content = ("#define %s %s_renamed_%s" % (oldname, oldname, newname))
154 content_added = False
155 else:
156 raise Exception("add_symbol_to_oldnames(): expected mode 1")
157 elif line == "#endif /* SDL_ENABLE_OLD_NAMES */":
158 if mode == 2:
159 if not section_added:
160 i = add_line(lines, i, section)
161
162 if not content_added:
163 i = add_content(lines, i, content, True)
164
165 mode = 3
166 else:
167 raise Exception("add_symbol_to_oldnames(): expected mode 2")
168 elif line != "" and (mode == 1 or mode == 2):
169 if line.startswith("/* ##"):
170 if section_added:
171 if not content_added:
172 i = add_content(lines, i, content, True)
173 content_added = True
174 elif line == section:
175 section_added = True
176 elif section < line:
177 i = add_line(lines, i, section)
178 section_added = True
179 i = add_content(lines, i, content, True)
180 content_added = True
181 elif line != "" and section_added and not content_added:
182 if content == line:
183 content_added = True
184 elif content < line:
185 i = add_content(lines, i, content, False)
186 content_added = True
187 i += 1
188
189 file.write_text("\n".join(lines) + "\n")
190
191
192def add_symbol_to_migration(header, symbol_type, oldname, newname):
193 file = (SDL_ROOT / "docs/README-migration.md")
194 lines = file.read_text().splitlines()
195 section = ("## %s" % header)
196 section_added = False
197 note = ("The following %ss have been renamed:" % symbol_type)
198 note_added = False
199 if symbol_type == "function":
200 content = ("* %s() => %s()" % (oldname, newname))
201 else:
202 content = ("* %s => %s" % (oldname, newname))
203 content_added = False
204 mode = 0
205 i = 0
206 while i < len(lines):
207 line = lines[i]
208 if line.startswith("##") and line.endswith(".h"):
209 if line == section:
210 section_added = True
211 elif section < line:
212 break
213
214 elif section_added and not note_added:
215 if note == line:
216 note_added = True
217 elif note_added and not content_added:
218 if content == line:
219 content_added = True
220 elif line == "" or content < line:
221 i = add_line(lines, i, content)
222 content_added = True
223 i += 1
224
225 if not section_added:
226 i = add_line(lines, i, section)
227 i = add_line(lines, i, "")
228
229 if not note_added:
230 i = add_line(lines, i, note)
231
232 if not content_added:
233 i = add_content(lines, i, content, True)
234
235 file.write_text("\n".join(lines) + "\n")
236
237
238if __name__ == "__main__":
239
240 parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
241 parser.add_argument("--skip-header-check", action="store_true")
242 parser.add_argument("header")
243 parser.add_argument("type", choices=["enum", "function", "hint", "structure", "symbol"])
244 parser.add_argument("args", nargs="*")
245 args = parser.parse_args()
246
247 try:
248 main()
249 except Exception as e:
250 print(e)
251 exit(-1)
252
253 exit(0)
254
diff --git a/src/contrib/SDL-3.2.20/build-scripts/rename_headers.py b/src/contrib/SDL-3.2.20/build-scripts/rename_headers.py
new file mode 100755
index 0000000..b61e477
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/rename_headers.py
@@ -0,0 +1,75 @@
1#!/usr/bin/env python3
2#
3# This script renames SDL headers in the specified paths
4
5import argparse
6import pathlib
7import re
8
9
10def do_include_replacements(paths):
11 replacements = [
12 ( re.compile(r"(?:[\"<])(?:SDL2/)?SDL_image.h(?:[\">])"), r"<SDL3_image/SDL_image.h>" ),
13 ( re.compile(r"(?:[\"<])(?:SDL2/)?SDL_mixer.h(?:[\">])"), r"<SDL3_mixer/SDL_mixer.h>" ),
14 ( re.compile(r"(?:[\"<])(?:SDL2/)?SDL_net.h(?:[\">])"), r"<SDL3_net/SDL_net.h>" ),
15 ( re.compile(r"(?:[\"<])(?:SDL2/)?SDL_rtf.h(?:[\">])"), r"<SDL3_rtf/SDL_rtf.h>" ),
16 ( re.compile(r"(?:[\"<])(?:SDL2/)?SDL_ttf.h(?:[\">])"), r"<SDL3_ttf/SDL_ttf.h>" ),
17 ( re.compile(r"(?:[\"<])(?:SDL2/)?SDL_gamecontroller.h(?:[\">])"), r"<SDL3/SDL_gamepad.h>" ),
18 ( re.compile(r"(?:[\"<])(?:SDL2/)?begin_code.h(?:[\">])"), r"<SDL3/SDL_begin_code.h>" ),
19 ( re.compile(r"(?:[\"<])(?:SDL2/)?close_code.h(?:[\">])"), r"<SDL3/SDL_close_code.h>" ),
20 ( re.compile(r"(?:[\"<])(?:SDL2/)?(SDL[_a-z0-9]*\.h)(?:[\">])"), r"<SDL3/\1>" )
21 ]
22 for entry in paths:
23 path = pathlib.Path(entry)
24 if not path.exists():
25 print("{} does not exist, skipping".format(entry))
26 continue
27
28 replace_headers_in_path(path, replacements)
29
30
31def replace_headers_in_file(file, replacements):
32 try:
33 with file.open("r", encoding="UTF-8", newline="") as rfp:
34 original = rfp.read()
35 contents = original
36 for regex, replacement in replacements:
37 contents = regex.sub(replacement, contents)
38 if contents != original:
39 with file.open("w", encoding="UTF-8", newline="") as wfp:
40 wfp.write(contents)
41 except UnicodeDecodeError:
42 print("%s is not text, skipping" % file)
43 except Exception as err:
44 print("%s" % err)
45
46
47def replace_headers_in_dir(path, replacements):
48 for entry in path.glob("*"):
49 if entry.is_dir():
50 replace_headers_in_dir(entry, replacements)
51 else:
52 print("Processing %s" % entry)
53 replace_headers_in_file(entry, replacements)
54
55
56def replace_headers_in_path(path, replacements):
57 if path.is_dir():
58 replace_headers_in_dir(path, replacements)
59 else:
60 replace_headers_in_file(path, replacements)
61
62
63def main():
64 parser = argparse.ArgumentParser(fromfile_prefix_chars='@', description="Rename #include's for SDL3.")
65 parser.add_argument("args", metavar="PATH", nargs="*", help="Input source file")
66 args = parser.parse_args()
67
68 try:
69 do_include_replacements(args.args)
70 except Exception as e:
71 print(e)
72 return 1
73
74if __name__ == "__main__":
75 raise SystemExit(main())
diff --git a/src/contrib/SDL-3.2.20/build-scripts/rename_macros.py b/src/contrib/SDL-3.2.20/build-scripts/rename_macros.py
new file mode 100755
index 0000000..978120c
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/rename_macros.py
@@ -0,0 +1,382 @@
1#!/usr/bin/env python3
2#
3# This script renames SDL macros in the specified paths
4
5import argparse
6import pathlib
7import re
8
9
10class TextReplacer:
11 def __init__(self, macros, repl_format):
12 if isinstance(macros, dict):
13 macros_keys = macros.keys()
14 else:
15 macros_keys = macros
16 self.macros = macros
17 self.re_macros = re.compile(r"\W(" + "|".join(macros_keys) + r")(?:\W|$)")
18 self.repl_format = repl_format
19
20 def apply(self, contents):
21 def cb(m):
22 macro = m.group(1)
23 original = m.group(0)
24 match_start, _ = m.span(0)
25 platform_start, platform_end = m.span(1)
26 if isinstance(self.macros, dict):
27 repl_args = (macro, self.macros[macro])
28 else:
29 repl_args = macro,
30 new_text = self.repl_format.format(*repl_args)
31 r = original[:(platform_start-match_start)] + new_text + original[platform_end-match_start:]
32 return r
33 contents, _ = self.re_macros.subn(cb, contents)
34
35 return contents
36
37
38class MacrosCheck:
39 def __init__(self):
40 self.renamed_platform_macros = TextReplacer(RENAMED_MACROS, "{1}")
41 self.deprecated_platform_macros = TextReplacer(DEPRECATED_PLATFORM_MACROS, "{0} /* {0} has been removed in SDL3 */")
42
43 def run(self, contents):
44 contents = self.renamed_platform_macros.apply(contents)
45 contents = self.deprecated_platform_macros.apply(contents)
46 return contents
47
48
49def apply_checks(paths):
50 checks = (
51 MacrosCheck(),
52 )
53
54 for entry in paths:
55 path = pathlib.Path(entry)
56 if not path.exists():
57 print("{} does not exist, skipping".format(entry))
58 continue
59 apply_checks_in_path(path, checks)
60
61
62def apply_checks_in_file(file, checks):
63 try:
64 with file.open("r", encoding="UTF-8", newline="") as rfp:
65 original = rfp.read()
66 contents = original
67 for check in checks:
68 contents = check.run(contents)
69 if contents != original:
70 with file.open("w", encoding="UTF-8", newline="") as wfp:
71 wfp.write(contents)
72 except UnicodeDecodeError:
73 print("%s is not text, skipping" % file)
74 except Exception as err:
75 print("%s" % err)
76
77
78def apply_checks_in_dir(path, checks):
79 for entry in path.glob("*"):
80 if entry.is_dir():
81 apply_checks_in_dir(entry, checks)
82 else:
83 print("Processing %s" % entry)
84 apply_checks_in_file(entry, checks)
85
86
87def apply_checks_in_path(path, checks):
88 if path.is_dir():
89 apply_checks_in_dir(path, checks)
90 else:
91 apply_checks_in_file(path, checks)
92
93
94def main():
95 parser = argparse.ArgumentParser(fromfile_prefix_chars='@', description="Rename macros for SDL3")
96 parser.add_argument("args", nargs="*", help="Input source files")
97 args = parser.parse_args()
98
99 try:
100 apply_checks(args.args)
101 except Exception as e:
102 print(e)
103 return 1
104
105
106RENAMED_MACROS = {
107 "__AIX__": "SDL_PLATFORM_AIX",
108 "__HAIKU__": "SDL_PLATFORM_HAIKU",
109 "__BSDI__": "SDL_PLATFORM_BSDI",
110 "__FREEBSD__": "SDL_PLATFORM_FREEBSD",
111 "__HPUX__": "SDL_PLATFORM_HPUX",
112 "__IRIX__": "SDL_PLATFORM_IRIX",
113 "__LINUX__": "SDL_PLATFORM_LINUX",
114 "__OS2__": "SDL_PLATFORM_OS2",
115 # "__ANDROID__": "SDL_PLATFORM_ANDROID,
116 "__APPLE__": "SDL_PLATFORM_APPLE",
117 "__TVOS__": "SDL_PLATFORM_TVOS",
118 "__IPHONEOS__": "SDL_PLATFORM_IOS",
119 "__MACOSX__": "SDL_PLATFORM_MACOS",
120 "__NETBSD__": "SDL_PLATFORM_NETBSD",
121 "__OPENBSD__": "SDL_PLATFORM_OPENBSD",
122 "__OSF__": "SDL_PLATFORM_OSF",
123 "__QNXNTO__": "SDL_PLATFORM_QNXNTO",
124 "__RISCOS__": "SDL_PLATFORM_RISCOS",
125 "__SOLARIS__": "SDL_PLATFORM_SOLARIS",
126 "__PSP__": "SDL_PLATFORM_PSP",
127 "__PS2__": "SDL_PLATFORM_PS2",
128 "__VITA__": "SDL_PLATFORM_VITA",
129 "__3DS__": "SDL_PLATFORM_3DS",
130 # "__unix__": "SDL_PLATFORM_UNIX,
131 "__XBOXSERIES__": "SDL_PLATFORM_XBOXSERIES",
132 "__XBOXONE__": "SDL_PLATFORM_XBOXONE",
133 "__WINDOWS__": "SDL_PLATFORM_WINDOWS",
134 "__WIN32__": "SDL_PLATFORM_WIN32",
135 # "__CYGWIN_": "SDL_PLATFORM_CYGWIN",
136 "__WINGDK__": "SDL_PLATFORM_WINGDK",
137 "__GDK__": "SDL_PLATFORM_GDK",
138 # "__EMSCRIPTEN__": "SDL_PLATFORM_EMSCRIPTEN",
139}
140
141DEPRECATED_PLATFORM_MACROS = {
142 "__DREAMCAST__",
143 "__NACL__",
144 "__PNACL__",
145 "__WINDOWS__",
146 "__WINRT__",
147 "SDL_ALTIVEC_BLITTERS",
148 "SDL_ARM_NEON_BLITTERS",
149 "SDL_ARM_SIMD_BLITTERS",
150 "SDL_ATOMIC_DISABLED",
151 "SDL_AUDIO_DISABLED",
152 "SDL_AUDIO_DRIVER_AAUDIO",
153 "SDL_AUDIO_DRIVER_ALSA",
154 "SDL_AUDIO_DRIVER_ALSA_DYNAMIC",
155 "SDL_AUDIO_DRIVER_ANDROID",
156 "SDL_AUDIO_DRIVER_ARTS",
157 "SDL_AUDIO_DRIVER_ARTS_DYNAMIC",
158 "SDL_AUDIO_DRIVER_COREAUDIO",
159 "SDL_AUDIO_DRIVER_DISK",
160 "SDL_AUDIO_DRIVER_DSOUND",
161 "SDL_AUDIO_DRIVER_DUMMY",
162 "SDL_AUDIO_DRIVER_EMSCRIPTEN",
163 "SDL_AUDIO_DRIVER_ESD",
164 "SDL_AUDIO_DRIVER_ESD_DYNAMIC",
165 "SDL_AUDIO_DRIVER_FUSIONSOUND",
166 "SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC",
167 "SDL_AUDIO_DRIVER_HAIKU",
168 "SDL_AUDIO_DRIVER_JACK",
169 "SDL_AUDIO_DRIVER_JACK_DYNAMIC",
170 "SDL_AUDIO_DRIVER_N3DS",
171 "SDL_AUDIO_DRIVER_NAS",
172 "SDL_AUDIO_DRIVER_NAS_DYNAMIC",
173 "SDL_AUDIO_DRIVER_NETBSD",
174 "SDL_AUDIO_DRIVER_OPENSLES",
175 "SDL_AUDIO_DRIVER_OS2",
176 "SDL_AUDIO_DRIVER_OSS",
177 "SDL_AUDIO_DRIVER_PAUDIO",
178 "SDL_AUDIO_DRIVER_PIPEWIRE",
179 "SDL_AUDIO_DRIVER_PIPEWIRE_DYNAMIC",
180 "SDL_AUDIO_DRIVER_PS2",
181 "SDL_AUDIO_DRIVER_PSP",
182 "SDL_AUDIO_DRIVER_PULSEAUDIO",
183 "SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC",
184 "SDL_AUDIO_DRIVER_QSA",
185 "SDL_AUDIO_DRIVER_SNDIO",
186 "SDL_AUDIO_DRIVER_SNDIO_DYNAMIC",
187 "SDL_AUDIO_DRIVER_SUNAUDIO",
188 "SDL_AUDIO_DRIVER_VITA",
189 "SDL_AUDIO_DRIVER_WASAPI",
190 "SDL_AUDIO_DRIVER_WINMM",
191 "SDL_CPUINFO_DISABLED",
192 "SDL_DEFAULT_ASSERT_LEVEL",
193 "SDL_EVENTS_DISABLED",
194 "SDL_FILESYSTEM_ANDROID",
195 "SDL_FILESYSTEM_COCOA",
196 "SDL_FILESYSTEM_DISABLED",
197 "SDL_FILESYSTEM_DUMMY",
198 "SDL_FILESYSTEM_EMSCRIPTEN",
199 "SDL_FILESYSTEM_HAIKU",
200 "SDL_FILESYSTEM_N3DS",
201 "SDL_FILESYSTEM_OS2",
202 "SDL_FILESYSTEM_PS2",
203 "SDL_FILESYSTEM_PSP",
204 "SDL_FILESYSTEM_RISCOS",
205 "SDL_FILESYSTEM_UNIX",
206 "SDL_FILESYSTEM_VITA",
207 "SDL_FILESYSTEM_WINDOWS",
208 "SDL_FILE_DISABLED",
209 "SDL_HAPTIC_ANDROID",
210 "SDL_HAPTIC_DINPUT",
211 "SDL_HAPTIC_DISABLED",
212 "SDL_HAPTIC_DUMMY",
213 "SDL_HAPTIC_IOKIT",
214 "SDL_HAPTIC_LINUX",
215 "SDL_HAPTIC_XINPUT",
216 "SDL_HAVE_LIBDECOR_GET_MIN_MAX",
217 "SDL_HAVE_MACHINE_JOYSTICK_H",
218 "SDL_HIDAPI_DISABLED",
219 "SDL_INPUT_FBSDKBIO",
220 "SDL_INPUT_LINUXEV",
221 "SDL_INPUT_LINUXKD",
222 "SDL_INPUT_WSCONS",
223 "SDL_IPHONE_KEYBOARD",
224 "SDL_IPHONE_LAUNCHSCREEN",
225 "SDL_JOYSTICK_ANDROID",
226 "SDL_JOYSTICK_DINPUT",
227 "SDL_JOYSTICK_DISABLED",
228 "SDL_JOYSTICK_DUMMY",
229 "SDL_JOYSTICK_EMSCRIPTEN",
230 "SDL_JOYSTICK_HAIKU",
231 "SDL_JOYSTICK_HIDAPI",
232 "SDL_JOYSTICK_IOKIT",
233 "SDL_JOYSTICK_LINUX",
234 "SDL_JOYSTICK_MFI",
235 "SDL_JOYSTICK_N3DS",
236 "SDL_JOYSTICK_OS2",
237 "SDL_JOYSTICK_PS2",
238 "SDL_JOYSTICK_PSP",
239 "SDL_JOYSTICK_RAWINPUT",
240 "SDL_JOYSTICK_USBHID",
241 "SDL_JOYSTICK_VIRTUAL",
242 "SDL_JOYSTICK_VITA",
243 "SDL_JOYSTICK_WGI",
244 "SDL_JOYSTICK_XINPUT",
245 "SDL_LIBSAMPLERATE_DYNAMIC",
246 "SDL_LIBUSB_DYNAMIC",
247 "SDL_LOADSO_DISABLED",
248 "SDL_LOADSO_DLOPEN",
249 "SDL_LOADSO_DUMMY",
250 "SDL_LOADSO_LDG",
251 "SDL_LOADSO_OS2",
252 "SDL_LOADSO_WINDOWS",
253 "SDL_LOCALE_DISABLED",
254 "SDL_LOCALE_DUMMY",
255 "SDL_MISC_DISABLED",
256 "SDL_MISC_DUMMY",
257 "SDL_POWER_ANDROID",
258 "SDL_POWER_DISABLED",
259 "SDL_POWER_EMSCRIPTEN",
260 "SDL_POWER_HAIKU",
261 "SDL_POWER_HARDWIRED",
262 "SDL_POWER_LINUX",
263 "SDL_POWER_MACOSX",
264 "SDL_POWER_N3DS",
265 "SDL_POWER_PSP",
266 "SDL_POWER_UIKIT",
267 "SDL_POWER_VITA",
268 "SDL_POWER_WINDOWS",
269 "SDL_POWER_WINRT",
270 "SDL_RENDER_DISABLED",
271 "SDL_SENSOR_ANDROID",
272 "SDL_SENSOR_COREMOTION",
273 "SDL_SENSOR_DISABLED",
274 "SDL_SENSOR_DUMMY",
275 "SDL_SENSOR_N3DS",
276 "SDL_SENSOR_VITA",
277 "SDL_SENSOR_WINDOWS",
278 "SDL_THREADS_DISABLED",
279 "SDL_THREAD_GENERIC_COND_SUFFIX",
280 "SDL_THREAD_N3DS",
281 "SDL_THREAD_OS2",
282 "SDL_THREAD_PS2",
283 "SDL_THREAD_PSP",
284 "SDL_THREAD_PTHREAD",
285 "SDL_THREAD_PTHREAD_RECURSIVE_MUTEX",
286 "SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP",
287 "SDL_THREAD_VITA",
288 "SDL_THREAD_WINDOWS",
289 "SDL_TIMERS_DISABLED",
290 "SDL_TIMER_DUMMY",
291 "SDL_TIMER_HAIKU",
292 "SDL_TIMER_N3DS",
293 "SDL_TIMER_OS2",
294 "SDL_TIMER_PS2",
295 "SDL_TIMER_PSP",
296 "SDL_TIMER_UNIX",
297 "SDL_TIMER_VITA",
298 "SDL_TIMER_WINDOWS",
299 "SDL_UDEV_DYNAMIC",
300 "SDL_USE_IME",
301 "SDL_USE_LIBICONV",
302 "SDL_VIDEO_DISABLED",
303 "SDL_VIDEO_DRIVER_ANDROID",
304 "SDL_VIDEO_DRIVER_COCOA",
305 "SDL_VIDEO_DRIVER_DIRECTFB",
306 "SDL_VIDEO_DRIVER_DIRECTFB_DYNAMIC",
307 "SDL_VIDEO_DRIVER_DUMMY",
308 "SDL_VIDEO_DRIVER_EMSCRIPTEN",
309 "SDL_VIDEO_DRIVER_HAIKU",
310 "SDL_VIDEO_DRIVER_KMSDRM",
311 "SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC",
312 "SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC_GBM",
313 "SDL_VIDEO_DRIVER_N3DS",
314 "SDL_VIDEO_DRIVER_OFFSCREEN",
315 "SDL_VIDEO_DRIVER_OS2",
316 "SDL_VIDEO_DRIVER_PS2",
317 "SDL_VIDEO_DRIVER_PSP",
318 "SDL_VIDEO_DRIVER_QNX",
319 "SDL_VIDEO_DRIVER_RISCOS",
320 "SDL_VIDEO_DRIVER_RPI",
321 "SDL_VIDEO_DRIVER_UIKIT",
322 "SDL_VIDEO_DRIVER_VITA",
323 "SDL_VIDEO_DRIVER_VIVANTE",
324 "SDL_VIDEO_DRIVER_VIVANTE_VDK",
325 "SDL_VIDEO_DRIVER_WAYLAND",
326 "SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC",
327 "SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR",
328 "SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL",
329 "SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR",
330 "SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON",
331 "SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH",
332 "SDL_VIDEO_DRIVER_WINDOWS",
333 "SDL_VIDEO_DRIVER_WINRT",
334 "SDL_VIDEO_DRIVER_X11",
335 "SDL_VIDEO_DRIVER_X11_DYNAMIC",
336 "SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR",
337 "SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT",
338 "SDL_VIDEO_DRIVER_X11_DYNAMIC_XFIXES",
339 "SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2",
340 "SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR",
341 "SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS",
342 "SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM",
343 "SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS",
344 "SDL_VIDEO_DRIVER_X11_XCURSOR",
345 "SDL_VIDEO_DRIVER_X11_XDBE",
346 "SDL_VIDEO_DRIVER_X11_XFIXES",
347 "SDL_VIDEO_DRIVER_X11_XINPUT2",
348 "SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH",
349 "SDL_VIDEO_DRIVER_X11_XRANDR",
350 "SDL_VIDEO_DRIVER_X11_XSCRNSAVER",
351 "SDL_VIDEO_DRIVER_X11_XSHAPE",
352 "SDL_VIDEO_METAL",
353 "SDL_VIDEO_OPENGL",
354 "SDL_VIDEO_OPENGL_BGL",
355 "SDL_VIDEO_OPENGL_CGL",
356 "SDL_VIDEO_OPENGL_EGL",
357 "SDL_VIDEO_OPENGL_ES",
358 "SDL_VIDEO_OPENGL_ES2",
359 "SDL_VIDEO_OPENGL_GLX",
360 "SDL_VIDEO_OPENGL_OSMESA",
361 "SDL_VIDEO_OPENGL_OSMESA_DYNAMIC",
362 "SDL_VIDEO_OPENGL_WGL",
363 "SDL_VIDEO_RENDER_D3D",
364 "SDL_VIDEO_RENDER_D3D11",
365 "SDL_VIDEO_RENDER_D3D12",
366 "SDL_VIDEO_RENDER_DIRECTFB",
367 "SDL_VIDEO_RENDER_METAL",
368 "SDL_VIDEO_RENDER_OGL",
369 "SDL_VIDEO_RENDER_OGL_ES",
370 "SDL_VIDEO_RENDER_OGL_ES2",
371 "SDL_VIDEO_RENDER_PS2",
372 "SDL_VIDEO_RENDER_PSP",
373 "SDL_VIDEO_RENDER_VITA_GXM",
374 "SDL_VIDEO_VITA_PIB",
375 "SDL_VIDEO_VITA_PVR",
376 "SDL_VIDEO_VITA_PVR_OGL",
377 "SDL_VIDEO_VULKAN",
378}
379
380if __name__ == "__main__":
381 raise SystemExit(main())
382
diff --git a/src/contrib/SDL-3.2.20/build-scripts/rename_symbols.py b/src/contrib/SDL-3.2.20/build-scripts/rename_symbols.py
new file mode 100755
index 0000000..33a92dd
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/rename_symbols.py
@@ -0,0 +1,130 @@
1#!/usr/bin/env python3
2#
3# This script renames symbols in the specified paths
4
5import argparse
6import os
7import pathlib
8import re
9import sys
10
11
12SDL_ROOT = pathlib.Path(__file__).resolve().parents[1]
13
14SDL_INCLUDE_DIR = SDL_ROOT / "include/SDL3"
15
16
17def main():
18 if args.all_symbols:
19 if len(args.args) < 1:
20 print("Usage: %s --all-symbols files_or_directories ..." % sys.argv[0])
21 exit(1)
22
23 replacements = get_all_replacements()
24 entries = args.args
25
26 else:
27 if len(args.args) < 3:
28 print("Usage: %s [--substring] oldname newname files_or_directories ..." % sys.argv[0])
29 exit(1)
30
31 replacements = { args.args[0]: args.args[1] }
32 entries = args.args[2:]
33
34 if args.substring:
35 regex = create_substring_regex_from_replacements(replacements)
36 else:
37 regex = create_regex_from_replacements(replacements)
38
39 for entry in entries:
40 path = pathlib.Path(entry)
41 if not path.exists():
42 print("%s doesn't exist, skipping" % entry)
43 continue
44
45 replace_symbols_in_path(path, regex, replacements)
46
47
48def get_all_replacements():
49 replacements = {}
50 file = (SDL_INCLUDE_DIR / "SDL_oldnames.h")
51 mode = 0
52 for line in file.read_text().splitlines():
53 if line == "#ifdef SDL_ENABLE_OLD_NAMES":
54 if mode == 0:
55 mode = 1
56 else:
57 raise Exception("get_all_replacements(): expected mode 0")
58 elif line == "#elif !defined(SDL_DISABLE_OLD_NAMES)":
59 if mode == 1:
60 mode = 2
61 else:
62 raise Exception("get_all_replacements(): expected mode 1")
63 elif line == "#endif /* SDL_ENABLE_OLD_NAMES */":
64 if mode == 2:
65 mode = 3
66 else:
67 raise Exception("add_symbol_to_oldnames(): expected mode 2")
68 elif mode == 1 and line.startswith("#define "):
69 words = line.split()
70 replacements[words[1]] = words[2]
71 # In case things are accidentally renamed to the "X_renamed_Y" symbol
72 #replacements[words[1] + "_renamed_" + words[2]] = words[2]
73
74 return replacements
75
76
77def create_regex_from_replacements(replacements):
78 return re.compile(r"\b(%s)\b" % "|".join(map(re.escape, replacements.keys())))
79
80
81def create_substring_regex_from_replacements(replacements):
82 return re.compile(r"(%s)" % "|".join(map(re.escape, replacements.keys())))
83
84
85def replace_symbols_in_file(file, regex, replacements):
86 try:
87 with file.open("r", encoding="UTF-8", newline="") as rfp:
88 original = rfp.read()
89 contents = regex.sub(lambda mo: replacements[mo.string[mo.start():mo.end()]], original)
90 if contents != original:
91 with file.open("w", encoding="UTF-8", newline="") as wfp:
92 wfp.write(contents)
93 except UnicodeDecodeError:
94 print("%s is not text, skipping" % file)
95 except Exception as err:
96 print("%s" % err)
97
98
99def replace_symbols_in_dir(path, regex, replacements):
100 for entry in path.glob("*"):
101 if entry.is_dir():
102 replace_symbols_in_dir(entry, regex, replacements)
103 else:
104 print("Processing %s" % entry)
105 replace_symbols_in_file(entry, regex, replacements)
106
107
108def replace_symbols_in_path(path, regex, replacements):
109 if path.is_dir():
110 replace_symbols_in_dir(path, regex, replacements)
111 else:
112 replace_symbols_in_file(path, regex, replacements)
113
114
115if __name__ == "__main__":
116
117 parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
118 parser.add_argument("--all-symbols", action="store_true")
119 parser.add_argument("--substring", action="store_true")
120 parser.add_argument("args", nargs="*")
121 args = parser.parse_args()
122
123 try:
124 main()
125 except Exception as e:
126 print(e)
127 exit(-1)
128
129 exit(0)
130
diff --git a/src/contrib/SDL-3.2.20/build-scripts/rename_types.py b/src/contrib/SDL-3.2.20/build-scripts/rename_types.py
new file mode 100755
index 0000000..137b409
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/rename_types.py
@@ -0,0 +1,80 @@
1#!/usr/bin/env python3
2#
3# This script renames symbols in the specified paths
4
5import argparse
6import os
7import pathlib
8import re
9import sys
10
11
12def main():
13 if len(args.args) < 1:
14 print("Usage: %s files_or_directories ..." % sys.argv[0])
15 exit(1)
16
17 replacements = {
18 "SDL_bool": "bool",
19 "SDL_TRUE": "true",
20 "SDL_FALSE": "false",
21 }
22 entries = args.args[0:]
23
24 regex = create_regex_from_replacements(replacements)
25
26 for entry in entries:
27 path = pathlib.Path(entry)
28 if not path.exists():
29 print("%s doesn't exist, skipping" % entry)
30 continue
31
32 replace_symbols_in_path(path, regex, replacements)
33
34def create_regex_from_replacements(replacements):
35 return re.compile(r"\b(%s)\b" % "|".join(map(re.escape, replacements.keys())))
36
37def replace_symbols_in_file(file, regex, replacements):
38 try:
39 with file.open("r", encoding="UTF-8", newline="") as rfp:
40 original = rfp.read()
41 contents = regex.sub(lambda mo: replacements[mo.string[mo.start():mo.end()]], original)
42 if contents != original:
43 with file.open("w", encoding="UTF-8", newline="") as wfp:
44 wfp.write(contents)
45 except UnicodeDecodeError:
46 print("%s is not text, skipping" % file)
47 except Exception as err:
48 print("%s" % err)
49
50
51def replace_symbols_in_dir(path, regex, replacements):
52 for entry in path.glob("*"):
53 if entry.is_dir():
54 replace_symbols_in_dir(entry, regex, replacements)
55 else:
56 print("Processing %s" % entry)
57 replace_symbols_in_file(entry, regex, replacements)
58
59
60def replace_symbols_in_path(path, regex, replacements):
61 if path.is_dir():
62 replace_symbols_in_dir(path, regex, replacements)
63 else:
64 replace_symbols_in_file(path, regex, replacements)
65
66
67if __name__ == "__main__":
68
69 parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
70 parser.add_argument("args", nargs="*")
71 args = parser.parse_args()
72
73 try:
74 main()
75 except Exception as e:
76 print(e)
77 exit(-1)
78
79 exit(0)
80
diff --git a/src/contrib/SDL-3.2.20/build-scripts/setup-gdk-desktop.py b/src/contrib/SDL-3.2.20/build-scripts/setup-gdk-desktop.py
new file mode 100755
index 0000000..d2309a0
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/setup-gdk-desktop.py
@@ -0,0 +1,303 @@
1#!/usr/bin/env python
2
3import argparse
4import functools
5import logging
6import os
7from pathlib import Path
8import re
9import shutil
10import subprocess
11import tempfile
12import textwrap
13import urllib.request
14import zipfile
15
16# Update both variables when updating the GDK
17GIT_REF = "June_2024_Update_1"
18GDK_EDITION = "240601" # YYMMUU
19
20logger = logging.getLogger(__name__)
21
22class GdDesktopConfigurator:
23 def __init__(self, gdk_path, arch, vs_folder, vs_version=None, vs_toolset=None, temp_folder=None, git_ref=None, gdk_edition=None):
24 self.git_ref = git_ref or GIT_REF
25 self.gdk_edition = gdk_edition or GDK_EDITION
26 self.gdk_path = gdk_path
27 self.temp_folder = temp_folder or Path(tempfile.gettempdir())
28 self.dl_archive_path = Path(self.temp_folder) / f"{ self.git_ref }.zip"
29 self.gdk_extract_path = Path(self.temp_folder) / f"GDK-{ self.git_ref }"
30 self.arch = arch
31 self.vs_folder = vs_folder
32 self._vs_version = vs_version
33 self._vs_toolset = vs_toolset
34
35 def download_archive(self) -> None:
36 gdk_url = f"https://github.com/microsoft/GDK/archive/refs/tags/{ GIT_REF }.zip"
37 logger.info("Downloading %s to %s", gdk_url, self.dl_archive_path)
38 urllib.request.urlretrieve(gdk_url, self.dl_archive_path)
39 assert self.dl_archive_path.is_file()
40
41 def extract_zip_archive(self) -> None:
42 extract_path = self.gdk_extract_path.parent
43 assert self.dl_archive_path.is_file()
44 logger.info("Extracting %s to %s", self.dl_archive_path, extract_path)
45 with zipfile.ZipFile(self.dl_archive_path) as zf:
46 zf.extractall(extract_path)
47 assert self.gdk_extract_path.is_dir(), f"{self.gdk_extract_path} must exist"
48
49 def extract_development_kit(self) -> None:
50 extract_dks_cmd = self.gdk_extract_path / "SetupScripts/ExtractXboxOneDKs.cmd"
51 assert extract_dks_cmd.is_file()
52 logger.info("Extracting GDK Development Kit: running %s", extract_dks_cmd)
53 cmd = ["cmd.exe", "/C", str(extract_dks_cmd), str(self.gdk_extract_path), str(self.gdk_path)]
54 logger.debug("Running %r", cmd)
55 subprocess.check_call(cmd)
56
57 def detect_vs_version(self) -> str:
58 vs_regex = re.compile("VS([0-9]{4})")
59 supported_vs_versions = []
60 for p in self.gaming_grdk_build_path.iterdir():
61 if not p.is_dir():
62 continue
63 if m := vs_regex.match(p.name):
64 supported_vs_versions.append(m.group(1))
65 logger.info(f"Supported Visual Studio versions: {supported_vs_versions}")
66 vs_versions = set(self.vs_folder.parts).intersection(set(supported_vs_versions))
67 if not vs_versions:
68 raise RuntimeError("Visual Studio version is incompatible")
69 if len(vs_versions) > 1:
70 raise RuntimeError(f"Too many compatible VS versions found ({vs_versions})")
71 vs_version = vs_versions.pop()
72 logger.info(f"Used Visual Studio version: {vs_version}")
73 return vs_version
74
75 def detect_vs_toolset(self) -> str:
76 toolset_paths = []
77 for ts_path in self.gdk_toolset_parent_path.iterdir():
78 if not ts_path.is_dir():
79 continue
80 ms_props = ts_path / "Microsoft.Cpp.props"
81 if not ms_props.is_file():
82 continue
83 toolset_paths.append(ts_path.name)
84 logger.info("Detected Visual Studio toolsets: %s", toolset_paths)
85 assert toolset_paths, "Have we detected at least one toolset?"
86
87 def toolset_number(toolset: str) -> int:
88 if m:= re.match("[^0-9]*([0-9]+).*", toolset):
89 return int(m.group(1))
90 return -9
91
92 return max(toolset_paths, key=toolset_number)
93
94 @property
95 def vs_version(self) -> str:
96 if self._vs_version is None:
97 self._vs_version = self.detect_vs_version()
98 return self._vs_version
99
100 @property
101 def vs_toolset(self) -> str:
102 if self._vs_toolset is None:
103 self._vs_toolset = self.detect_vs_toolset()
104 return self._vs_toolset
105
106 @staticmethod
107 def copy_files_and_merge_into(srcdir: Path, dstdir: Path) -> None:
108 logger.info(f"Copy {srcdir} to {dstdir}")
109 for root, _, files in os.walk(srcdir):
110 dest_root = dstdir / Path(root).relative_to(srcdir)
111 if not dest_root.is_dir():
112 dest_root.mkdir()
113 for file in files:
114 srcfile = Path(root) / file
115 dstfile = dest_root / file
116 shutil.copy(srcfile, dstfile)
117
118 def copy_msbuild(self) -> None:
119 vc_toolset_parent_path = self.vs_folder / "MSBuild/Microsoft/VC"
120 if 1:
121 logger.info(f"Detected compatible Visual Studio version: {self.vs_version}")
122 srcdir = vc_toolset_parent_path
123 dstdir = self.gdk_toolset_parent_path
124 assert srcdir.is_dir(), "Source directory must exist"
125 assert dstdir.is_dir(), "Destination directory must exist"
126
127 self.copy_files_and_merge_into(srcdir=srcdir, dstdir=dstdir)
128
129 @property
130 def game_dk_path(self) -> Path:
131 return self.gdk_path / "Microsoft GDK"
132
133 @property
134 def game_dk_latest_path(self) -> Path:
135 return self.game_dk_path / self.gdk_edition
136
137 @property
138 def windows_sdk_path(self) -> Path:
139 return self.gdk_path / "Windows Kits/10"
140
141 @property
142 def gaming_grdk_build_path(self) -> Path:
143 return self.game_dk_latest_path / "GRDK"
144
145 @property
146 def gdk_toolset_parent_path(self) -> Path:
147 return self.gaming_grdk_build_path / f"VS{self.vs_version}/flatDeployment/MSBuild/Microsoft/VC"
148
149 @property
150 def env(self) -> dict[str, str]:
151 game_dk = self.game_dk_path
152 game_dk_latest = self.game_dk_latest_path
153 windows_sdk_dir = self.windows_sdk_path
154 gaming_grdk_build = self.gaming_grdk_build_path
155
156 return {
157 "GRDKEDITION": f"{self.gdk_edition}",
158 "GameDK": f"{game_dk}\\",
159 "GameDKLatest": f"{ game_dk_latest }\\",
160 "WindowsSdkDir": f"{ windows_sdk_dir }\\",
161 "GamingGRDKBuild": f"{ gaming_grdk_build }\\",
162 "VSInstallDir": f"{ self.vs_folder }\\",
163 }
164
165 def create_user_props(self, path: Path) -> None:
166 vc_targets_path = self.gaming_grdk_build_path / f"VS{ self.vs_version }/flatDeployment/MSBuild/Microsoft/VC/{ self.vs_toolset }"
167 vc_targets_path16 = self.gaming_grdk_build_path / f"VS2019/flatDeployment/MSBuild/Microsoft/VC/{ self.vs_toolset }"
168 vc_targets_path17 = self.gaming_grdk_build_path / f"VS2022/flatDeployment/MSBuild/Microsoft/VC/{ self.vs_toolset }"
169 additional_include_directories = ";".join(str(p) for p in self.gdk_include_paths)
170 additional_library_directories = ";".join(str(p) for p in self.gdk_library_paths)
171 durango_xdk_install_path = self.gdk_path / "Microsoft GDK"
172 with path.open("w") as f:
173 f.write(textwrap.dedent(f"""\
174 <?xml version="1.0" encoding="utf-8"?>
175 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
176 <PropertyGroup>
177 <VCTargetsPath>{ vc_targets_path }\\</VCTargetsPath>
178 <VCTargetsPath16>{ vc_targets_path16 }\\</VCTargetsPath16>
179 <VCTargetsPath17>{ vc_targets_path17 }\\</VCTargetsPath17>
180 <BWOI_GDK_Path>{ self.gaming_grdk_build_path }\\</BWOI_GDK_Path>
181 <Platform Condition="'$(Platform)' == ''">Gaming.Desktop.x64</Platform>
182 <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
183 <XdkEditionTarget>{ self.gdk_edition }</XdkEditionTarget>
184 <DurangoXdkInstallPath>{ durango_xdk_install_path }</DurangoXdkInstallPath>
185
186 <DefaultXdkEditionRootVS2019>$(DurangoXdkInstallPath)\\{self.gdk_edition}\\GRDK\\VS2019\\flatDeployment\\MSBuild\\Microsoft\\VC\\{self.vs_toolset}\\Platforms\\$(Platform)\\</DefaultXdkEditionRootVS2019>
187 <XdkEditionRootVS2019>$(DurangoXdkInstallPath)\\{self.gdk_edition}\\GRDK\\VS2019\\flatDeployment\\MSBuild\\Microsoft\\VC\\{self.vs_toolset}\\Platforms\\$(Platform)\\</XdkEditionRootVS2019>
188 <DefaultXdkEditionRootVS2022>$(DurangoXdkInstallPath)\\{self.gdk_edition}\\GRDK\\VS2022\\flatDeployment\\MSBuild\\Microsoft\\VC\\{self.vs_toolset}\\Platforms\\$(Platform)\\</DefaultXdkEditionRootVS2022>
189 <XdkEditionRootVS2022>$(DurangoXdkInstallPath)\\{self.gdk_edition}\\GRDK\\VS2022\\flatDeployment\\MSBuild\\Microsoft\\VC\\{self.vs_toolset}\\Platforms\\$(Platform)\\</XdkEditionRootVS2022>
190
191 <Deterministic>true</Deterministic>
192 <DisableInstalledVCTargetsUse>true</DisableInstalledVCTargetsUse>
193 <ClearDevCommandPromptEnvVars>true</ClearDevCommandPromptEnvVars>
194 </PropertyGroup>
195 <ItemDefinitionGroup Condition="'$(Platform)' == 'Gaming.Desktop.x64'">
196 <ClCompile>
197 <AdditionalIncludeDirectories>{ additional_include_directories };%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
198 </ClCompile>
199 <Link>
200 <AdditionalLibraryDirectories>{ additional_library_directories };%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
201 </Link>
202 </ItemDefinitionGroup>
203 </Project>
204 """))
205
206 @property
207 def gdk_include_paths(self) -> list[Path]:
208 return [
209 self.gaming_grdk_build_path / "gamekit/include",
210 ]
211
212 @property
213 def gdk_library_paths(self) -> list[Path]:
214 return [
215 self.gaming_grdk_build_path / f"gamekit/lib/{self.arch}",
216 ]
217
218 @property
219 def gdk_binary_path(self) -> list[Path]:
220 return [
221 self.gaming_grdk_build_path / "bin",
222 self.game_dk_path / "bin",
223 ]
224
225 @property
226 def build_env(self) -> dict[str, str]:
227 gdk_include = ";".join(str(p) for p in self.gdk_include_paths)
228 gdk_lib = ";".join(str(p) for p in self.gdk_library_paths)
229 gdk_path = ";".join(str(p) for p in self.gdk_binary_path)
230 return {
231 "GDK_INCLUDE": gdk_include,
232 "GDK_LIB": gdk_lib,
233 "GDK_PATH": gdk_path,
234 }
235
236 def print_env(self) -> None:
237 for k, v in self.env.items():
238 print(f"set \"{k}={v}\"")
239 print()
240 for k, v in self.build_env.items():
241 print(f"set \"{k}={v}\"")
242 print()
243 print(f"set \"PATH=%GDK_PATH%;%PATH%\"")
244 print(f"set \"LIB=%GDK_LIB%;%LIB%\"")
245 print(f"set \"INCLUDE=%GDK_INCLUDE%;%INCLUDE%\"")
246
247
248def main():
249 logging.basicConfig(level=logging.INFO)
250 parser = argparse.ArgumentParser(allow_abbrev=False)
251 parser.add_argument("--arch", choices=["amd64"], default="amd64", help="Architecture")
252 parser.add_argument("--download", action="store_true", help="Download GDK")
253 parser.add_argument("--extract", action="store_true", help="Extract downloaded GDK")
254 parser.add_argument("--copy-msbuild", action="store_true", help="Copy MSBuild files")
255 parser.add_argument("--temp-folder", help="Temporary folder where to download and extract GDK")
256 parser.add_argument("--gdk-path", required=True, type=Path, help="Folder where to store the GDK")
257 parser.add_argument("--ref-edition", type=str, help="Git ref and GDK edition separated by comma")
258 parser.add_argument("--vs-folder", required=True, type=Path, help="Installation folder of Visual Studio")
259 parser.add_argument("--vs-version", required=False, type=int, help="Visual Studio version")
260 parser.add_argument("--vs-toolset", required=False, help="Visual Studio toolset (e.g. v150)")
261 parser.add_argument("--props-folder", required=False, type=Path, default=Path(), help="Visual Studio toolset (e.g. v150)")
262 parser.add_argument("--no-user-props", required=False, dest="user_props", action="store_false", help="Don't ")
263 args = parser.parse_args()
264
265 logging.basicConfig(level=logging.INFO)
266
267 git_ref = None
268 gdk_edition = None
269 if args.ref_edition is not None:
270 git_ref, gdk_edition = args.ref_edition.split(",", 1)
271 try:
272 int(gdk_edition)
273 except ValueError:
274 parser.error("Edition should be an integer (YYMMUU) (Y=year M=month U=update)")
275
276 configurator = GdDesktopConfigurator(
277 arch=args.arch,
278 git_ref=git_ref,
279 gdk_edition=gdk_edition,
280 vs_folder=args.vs_folder,
281 vs_version=args.vs_version,
282 vs_toolset=args.vs_toolset,
283 gdk_path=args.gdk_path,
284 temp_folder=args.temp_folder,
285 )
286
287 if args.download:
288 configurator.download_archive()
289
290 if args.extract:
291 configurator.extract_zip_archive()
292
293 configurator.extract_development_kit()
294
295 if args.copy_msbuild:
296 configurator.copy_msbuild()
297
298 if args.user_props:
299 configurator.print_env()
300 configurator.create_user_props(args.props_folder / "Directory.Build.props")
301
302if __name__ == "__main__":
303 raise SystemExit(main())
diff --git a/src/contrib/SDL-3.2.20/build-scripts/showrev.sh b/src/contrib/SDL-3.2.20/build-scripts/showrev.sh
new file mode 100755
index 0000000..764d3a4
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/showrev.sh
@@ -0,0 +1,48 @@
1#!/bin/sh
2#
3# Print the current source revision, if available
4
5SDL_ROOT=$(dirname $0)/..
6cd $SDL_ROOT
7
8if [ -e ./VERSION.txt ]; then
9 cat ./VERSION.txt
10 exit 0
11fi
12
13major=$(sed -ne 's/^#define SDL_MAJOR_VERSION *//p' include/SDL3/SDL_version.h)
14minor=$(sed -ne 's/^#define SDL_MINOR_VERSION *//p' include/SDL3/SDL_version.h)
15micro=$(sed -ne 's/^#define SDL_MICRO_VERSION *//p' include/SDL3/SDL_version.h)
16version="${major}.${minor}.${micro}"
17
18if [ -x "$(command -v git)" ]; then
19 rev="$(git describe --tags --long 2>/dev/null)"
20 if [ -n "$rev" ]; then
21 # e.g. release-2.24.0-542-g96361fc47
22 # or release-2.24.1-5-g36b987dab
23 # or prerelease-2.23.2-0-gcb46e1b3f
24 echo "$rev"
25 exit 0
26 fi
27
28 rev="$(git describe --always --tags --long 2>/dev/null)"
29 if [ -n "$rev" ]; then
30 # Just a truncated sha1, e.g. 96361fc47.
31 # Turn it into e.g. 2.25.0-g96361fc47
32 echo "${version}-g${rev}"
33 exit 0
34 fi
35fi
36
37if [ -x "$(command -v p4)" ]; then
38 rev="$(p4 changes -m1 ./...\#have 2>/dev/null| awk '{print $2}')"
39 if [ $? = 0 ]; then
40 # e.g. 2.25.0-p7511446
41 echo "${version}-p${rev}"
42 exit 0
43 fi
44fi
45
46# best we can do
47echo "${version}-no-vcs"
48exit 0
diff --git a/src/contrib/SDL-3.2.20/build-scripts/strip_fPIC.sh b/src/contrib/SDL-3.2.20/build-scripts/strip_fPIC.sh
new file mode 100755
index 0000000..8719b89
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/strip_fPIC.sh
@@ -0,0 +1,21 @@
1#!/bin/sh
2#
3# libtool assumes that the compiler can handle the -fPIC flag
4# This isn't always true (for example, nasm can't handle it)
5command=""
6while [ $# -gt 0 ]; do
7 case "$1" in
8 -?PIC)
9 # Ignore -fPIC and -DPIC options
10 ;;
11 -fno-common)
12 # Ignore -fPIC and -DPIC options
13 ;;
14 *)
15 command="$command $1"
16 ;;
17 esac
18 shift
19done
20echo $command
21exec $command
diff --git a/src/contrib/SDL-3.2.20/build-scripts/test-versioning.sh b/src/contrib/SDL-3.2.20/build-scripts/test-versioning.sh
new file mode 100755
index 0000000..55e29a3
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/test-versioning.sh
@@ -0,0 +1,170 @@
1#!/bin/sh
2# Copyright 2022 Collabora Ltd.
3# SPDX-License-Identifier: Zlib
4
5set -eu
6
7cd `dirname $0`/..
8
9ref_major=$(sed -ne 's/^#define SDL_MAJOR_VERSION *//p' include/SDL3/SDL_version.h)
10ref_minor=$(sed -ne 's/^#define SDL_MINOR_VERSION *//p' include/SDL3/SDL_version.h)
11ref_micro=$(sed -ne 's/^#define SDL_MICRO_VERSION *//p' include/SDL3/SDL_version.h)
12ref_version="${ref_major}.${ref_minor}.${ref_micro}"
13
14tests=0
15failed=0
16
17ok () {
18 tests=$(( tests + 1 ))
19 echo "ok - $*"
20}
21
22not_ok () {
23 tests=$(( tests + 1 ))
24 echo "not ok - $*"
25 failed=1
26}
27
28version=$(sed -Ene 's/^.* version ([0-9.]*)$/\1/p' include/SDL3/SDL.h)
29
30if [ "$ref_version" = "$version" ]; then
31 ok "SDL.h $version"
32else
33 not_ok "SDL.h $version disagrees with SDL_version.h $ref_version"
34fi
35
36version=$(sed -Ene 's/^project\(SDL[0-9]+ LANGUAGES C VERSION "([0-9.]*)"\)$/\1/p' CMakeLists.txt)
37
38if [ "$ref_version" = "$version" ]; then
39 ok "CMakeLists.txt $version"
40else
41 not_ok "CMakeLists.txt $version disagrees with SDL_version.h $ref_version"
42fi
43
44major=$(sed -ne 's/.*SDL_MAJOR_VERSION = \([0-9]*\);/\1/p' android-project/app/src/main/java/org/libsdl/app/SDLActivity.java)
45minor=$(sed -ne 's/.*SDL_MINOR_VERSION = \([0-9]*\);/\1/p' android-project/app/src/main/java/org/libsdl/app/SDLActivity.java)
46micro=$(sed -ne 's/.*SDL_MICRO_VERSION = \([0-9]*\);/\1/p' android-project/app/src/main/java/org/libsdl/app/SDLActivity.java)
47version="${major}.${minor}.${micro}"
48
49if [ "$ref_version" = "$version" ]; then
50 ok "SDLActivity.java $version"
51else
52 not_ok "android-project/app/src/main/java/org/libsdl/app/SDLActivity.java $version disagrees with SDL_version.h $ref_version"
53fi
54
55tuple=$(sed -ne 's/^ *FILEVERSION *//p' src/core/windows/version.rc | tr -d '\r')
56ref_tuple="${ref_major},${ref_minor},${ref_micro},0"
57
58if [ "$ref_tuple" = "$tuple" ]; then
59 ok "version.rc FILEVERSION $tuple"
60else
61 not_ok "version.rc FILEVERSION $tuple disagrees with SDL_version.h $ref_tuple"
62fi
63
64tuple=$(sed -ne 's/^ *PRODUCTVERSION *//p' src/core/windows/version.rc | tr -d '\r')
65
66if [ "$ref_tuple" = "$tuple" ]; then
67 ok "version.rc PRODUCTVERSION $tuple"
68else
69 not_ok "version.rc PRODUCTVERSION $tuple disagrees with SDL_version.h $ref_tuple"
70fi
71
72tuple=$(sed -Ene 's/^ *VALUE "FileVersion", "([0-9, ]*)\\0"\r?$/\1/p' src/core/windows/version.rc | tr -d '\r')
73ref_tuple="${ref_major}, ${ref_minor}, ${ref_micro}, 0"
74
75if [ "$ref_tuple" = "$tuple" ]; then
76 ok "version.rc FileVersion $tuple"
77else
78 not_ok "version.rc FileVersion $tuple disagrees with SDL_version.h $ref_tuple"
79fi
80
81tuple=$(sed -Ene 's/^ *VALUE "ProductVersion", "([0-9, ]*)\\0"\r?$/\1/p' src/core/windows/version.rc | tr -d '\r')
82
83if [ "$ref_tuple" = "$tuple" ]; then
84 ok "version.rc ProductVersion $tuple"
85else
86 not_ok "version.rc ProductVersion $tuple disagrees with SDL_version.h $ref_tuple"
87fi
88
89version=$(sed -Ene '/CFBundleShortVersionString/,+1 s/.*<string>(.*)<\/string>.*/\1/p' Xcode/SDL/Info-Framework.plist)
90
91if [ "$ref_version" = "$version" ]; then
92 ok "Info-Framework.plist CFBundleShortVersionString $version"
93else
94 not_ok "Info-Framework.plist CFBundleShortVersionString $version disagrees with SDL_version.h $ref_version"
95fi
96
97version=$(sed -Ene '/CFBundleVersion/,+1 s/.*<string>(.*)<\/string>.*/\1/p' Xcode/SDL/Info-Framework.plist)
98
99if [ "$ref_version" = "$version" ]; then
100 ok "Info-Framework.plist CFBundleVersion $version"
101else
102 not_ok "Info-Framework.plist CFBundleVersion $version disagrees with SDL_version.h $ref_version"
103fi
104
105version=$(sed -Ene 's/Title SDL (.*)/\1/p' Xcode/SDL/pkg-support/SDL.info)
106
107if [ "$ref_version" = "$version" ]; then
108 ok "SDL.info Title $version"
109else
110 not_ok "SDL.info Title $version disagrees with SDL_version.h $ref_version"
111fi
112
113marketing=$(sed -Ene 's/.*MARKETING_VERSION = (.*);/\1/p' Xcode/SDL/SDL.xcodeproj/project.pbxproj)
114
115ref="$ref_version
116$ref_version"
117
118if [ "$ref" = "$marketing" ]; then
119 ok "project.pbxproj MARKETING_VERSION is consistent"
120else
121 not_ok "project.pbxproj MARKETING_VERSION is inconsistent, expected $ref, got $marketing"
122fi
123
124# For simplicity this assumes we'll never break ABI before SDL 3.
125dylib_compat=$(sed -Ene 's/.*DYLIB_COMPATIBILITY_VERSION = (.*);$/\1/p' Xcode/SDL/SDL.xcodeproj/project.pbxproj)
126
127case "$ref_minor" in
128 (*[02468])
129 major="$(( ref_minor * 100 + 1 ))"
130 minor="0"
131 ;;
132 (*)
133 major="$(( ref_minor * 100 + ref_micro + 1 ))"
134 minor="0"
135 ;;
136esac
137
138ref="${major}.${minor}.0
139${major}.${minor}.0"
140
141if [ "$ref" = "$dylib_compat" ]; then
142 ok "project.pbxproj DYLIB_COMPATIBILITY_VERSION is consistent"
143else
144 not_ok "project.pbxproj DYLIB_COMPATIBILITY_VERSION is inconsistent, expected $ref, got $dylib_compat"
145fi
146
147dylib_cur=$(sed -Ene 's/.*DYLIB_CURRENT_VERSION = (.*);$/\1/p' Xcode/SDL/SDL.xcodeproj/project.pbxproj)
148
149case "$ref_minor" in
150 (*[02468])
151 major="$(( ref_minor * 100 + 1 ))"
152 minor="$ref_micro"
153 ;;
154 (*)
155 major="$(( ref_minor * 100 + ref_micro + 1 ))"
156 minor="0"
157 ;;
158esac
159
160ref="${major}.${minor}.0
161${major}.${minor}.0"
162
163if [ "$ref" = "$dylib_cur" ]; then
164 ok "project.pbxproj DYLIB_CURRENT_VERSION is consistent"
165else
166 not_ok "project.pbxproj DYLIB_CURRENT_VERSION is inconsistent, expected $ref, got $dylib_cur"
167fi
168
169echo "1..$tests"
170exit "$failed"
diff --git a/src/contrib/SDL-3.2.20/build-scripts/update-copyright.sh b/src/contrib/SDL-3.2.20/build-scripts/update-copyright.sh
new file mode 100755
index 0000000..9bb46ea
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/update-copyright.sh
@@ -0,0 +1,15 @@
1#!/bin/sh
2
3if [ "$SED" = "" ]; then
4 if type gsed >/dev/null; then
5 SED=gsed
6 else
7 SED=sed
8 fi
9fi
10
11find . -type f \
12| grep -v \.git \
13| while read file; do \
14 LC_ALL=C $SED -b -i "s/\(.*Copyright.*\)[0-9]\{4\}\( *Sam Lantinga\)/\1`date +%Y`\2/" "$file"; \
15done
diff --git a/src/contrib/SDL-3.2.20/build-scripts/update-version.sh b/src/contrib/SDL-3.2.20/build-scripts/update-version.sh
new file mode 100755
index 0000000..86ae816
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/update-version.sh
@@ -0,0 +1,81 @@
1#!/bin/sh
2
3#set -x
4
5cd `dirname $0`/..
6
7ARGSOKAY=1
8if [ -z $1 ]; then
9 ARGSOKAY=0
10fi
11if [ -z $2 ]; then
12 ARGSOKAY=0
13fi
14if [ -z $3 ]; then
15 ARGSOKAY=0
16fi
17
18if [ "x$ARGSOKAY" = "x0" ]; then
19 echo "USAGE: $0 <major> <minor> <patch>" 1>&2
20 exit 1
21fi
22
23MAJOR="$1"
24MINOR="$2"
25MICRO="$3"
26NEWVERSION="$MAJOR.$MINOR.$MICRO"
27
28echo "Updating version to '$NEWVERSION' ..."
29
30perl -w -pi -e 's/\A(.* version )[0-9.]+/${1}'$NEWVERSION'/;' include/SDL3/SDL.h
31
32# !!! FIXME: This first one is a kinda scary search/replace that might fail later if another X.Y.Z version is added to the file.
33perl -w -pi -e 's/(\<string\>)\d+\.\d+\.\d+/${1}'$NEWVERSION'/;' Xcode/SDL/Info-Framework.plist
34
35perl -w -pi -e 's/(Title SDL )\d+\.\d+\.\d+/${1}'$NEWVERSION'/;' Xcode/SDL/pkg-support/SDL.info
36
37perl -w -pi -e 's/(MARKETING_VERSION\s*=\s*)\d+\.\d+\.\d+/${1}'$NEWVERSION'/;' Xcode/SDL/SDL.xcodeproj/project.pbxproj
38
39DYVER=`expr $MINOR \* 100 + 1`
40perl -w -pi -e 's/(DYLIB_CURRENT_VERSION\s*=\s*)\d+\.\d+\.\d+/${1}'$DYVER'.0.0/;' Xcode/SDL/SDL.xcodeproj/project.pbxproj
41
42# Set compat to major.minor.0 by default.
43perl -w -pi -e 's/(DYLIB_COMPATIBILITY_VERSION\s*=\s*)\d+\.\d+\.\d+/${1}'$DYVER'.0.0/;' Xcode/SDL/SDL.xcodeproj/project.pbxproj
44
45# non-zero patch?
46if [ "x$MICRO" != "x0" ]; then
47 if [ `expr $MINOR % 2` = "0" ]; then
48 # If patch is not zero, but minor is even, it's a bugfix release.
49 perl -w -pi -e 's/(DYLIB_CURRENT_VERSION\s*=\s*)\d+\.\d+\.\d+/${1}'$DYVER'.'$MICRO'.0/;' Xcode/SDL/SDL.xcodeproj/project.pbxproj
50
51 else
52 # If patch is not zero, but minor is odd, it's a development prerelease.
53 DYVER=`expr $MINOR \* 100 + $MICRO + 1`
54 perl -w -pi -e 's/(DYLIB_CURRENT_VERSION\s*=\s*)\d+\.\d+\.\d+/${1}'$DYVER'.0.0/;' Xcode/SDL/SDL.xcodeproj/project.pbxproj
55 perl -w -pi -e 's/(DYLIB_COMPATIBILITY_VERSION\s*=\s*)\d+\.\d+\.\d+/${1}'$DYVER'.0.0/;' Xcode/SDL/SDL.xcodeproj/project.pbxproj
56 fi
57fi
58
59perl -w -pi -e 's/\A(project\(SDL[0-9]+ LANGUAGES C VERSION ")[0-9.]+/${1}'$NEWVERSION'/;' CMakeLists.txt
60
61perl -w -pi -e 's/\A(.* SDL_MAJOR_VERSION = )\d+/${1}'$MAJOR'/;' android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
62perl -w -pi -e 's/\A(.* SDL_MINOR_VERSION = )\d+/${1}'$MINOR'/;' android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
63perl -w -pi -e 's/\A(.* SDL_MICRO_VERSION = )\d+/${1}'$MICRO'/;' android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
64
65perl -w -pi -e 's/(\#define SDL_MAJOR_VERSION\s+)\d+/${1}'$MAJOR'/;' include/SDL3/SDL_version.h
66perl -w -pi -e 's/(\#define SDL_MINOR_VERSION\s+)\d+/${1}'$MINOR'/;' include/SDL3/SDL_version.h
67perl -w -pi -e 's/(\#define SDL_MICRO_VERSION\s+)\d+/${1}'$MICRO'/;' include/SDL3/SDL_version.h
68
69perl -w -pi -e 's/(FILEVERSION\s+)\d+,\d+,\d+/${1}'$MAJOR','$MINOR','$MICRO'/;' src/core/windows/version.rc
70perl -w -pi -e 's/(PRODUCTVERSION\s+)\d+,\d+,\d+/${1}'$MAJOR','$MINOR','$MICRO'/;' src/core/windows/version.rc
71perl -w -pi -e 's/(VALUE "FileVersion", ")\d+, \d+, \d+/${1}'$MAJOR', '$MINOR', '$MICRO'/;' src/core/windows/version.rc
72perl -w -pi -e 's/(VALUE "ProductVersion", ")\d+, \d+, \d+/${1}'$MAJOR', '$MINOR', '$MICRO'/;' src/core/windows/version.rc
73
74echo "Running build-scripts/test-versioning.sh to verify changes..."
75./build-scripts/test-versioning.sh
76
77echo "All done."
78echo "Run 'git diff' and make sure this looks correct, before 'git commit'."
79
80exit 0
81
diff --git a/src/contrib/SDL-3.2.20/build-scripts/updaterev.sh b/src/contrib/SDL-3.2.20/build-scripts/updaterev.sh
new file mode 100755
index 0000000..508c6dd
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/updaterev.sh
@@ -0,0 +1,48 @@
1#!/bin/sh
2#
3# Generate a header file with the current source revision
4
5outdir=`pwd`
6cd `dirname $0`
7srcdir=..
8header=$outdir/include/SDL3/SDL_revision.h
9dist=
10vendor=
11
12while [ "$#" -gt 0 ]; do
13 case "$1" in
14 (--dist)
15 dist=yes
16 shift
17 ;;
18 (--vendor)
19 vendor="$2"
20 shift 2
21 ;;
22 (*)
23 echo "$0: Unknown option: $1" >&2
24 exit 2
25 ;;
26 esac
27done
28
29rev=`sh showrev.sh 2>/dev/null`
30if [ "$rev" != "" ]; then
31 if [ -n "$dist" ]; then
32 echo "$rev" > "$outdir/VERSION.txt"
33 fi
34 echo "/* Generated by updaterev.sh, do not edit */" >"$header.new"
35 if [ -n "$vendor" ]; then
36 echo "#define SDL_VENDOR_INFO \"$vendor\"" >>"$header.new"
37 fi
38 echo "#ifdef SDL_VENDOR_INFO" >>"$header.new"
39 echo "#define SDL_REVISION \"SDL-$rev (\" SDL_VENDOR_INFO \")\"" >>"$header.new"
40 echo "#else" >>"$header.new"
41 echo "#define SDL_REVISION \"SDL-$rev\"" >>"$header.new"
42 echo "#endif" >>"$header.new"
43 if diff $header $header.new >/dev/null 2>&1; then
44 rm "$header.new"
45 else
46 mv "$header.new" "$header"
47 fi
48fi
diff --git a/src/contrib/SDL-3.2.20/build-scripts/wikiheaders.pl b/src/contrib/SDL-3.2.20/build-scripts/wikiheaders.pl
new file mode 100755
index 0000000..d4205b8
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/wikiheaders.pl
@@ -0,0 +1,3408 @@
1#!/usr/bin/perl -w
2
3# Simple DirectMedia Layer
4# Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
5#
6# This software is provided 'as-is', without any express or implied
7# warranty. In no event will the authors be held liable for any damages
8# arising from the use of this software.
9#
10# Permission is granted to anyone to use this software for any purpose,
11# including commercial applications, and to alter it and redistribute it
12# freely, subject to the following restrictions:
13#
14# 1. The origin of this software must not be misrepresented; you must not
15# claim that you wrote the original software. If you use this software
16# in a product, an acknowledgment in the product documentation would be
17# appreciated but is not required.
18# 2. Altered source versions must be plainly marked as such, and must not be
19# misrepresented as being the original software.
20# 3. This notice may not be removed or altered from any source distribution.
21
22use warnings;
23use strict;
24use File::Path;
25use Text::Wrap;
26
27$Text::Wrap::huge = 'overflow';
28
29my $projectfullname = 'Simple Directmedia Layer';
30my $projectshortname = 'SDL';
31my $wikisubdir = '';
32my $incsubdir = 'include';
33my $readmesubdir = undef;
34my $apiprefixregex = undef;
35my $versionfname = 'include/SDL_version.h';
36my $versionmajorregex = '\A\#define\s+SDL_MAJOR_VERSION\s+(\d+)\Z';
37my $versionminorregex = '\A\#define\s+SDL_MINOR_VERSION\s+(\d+)\Z';
38my $versionmicroregex = '\A\#define\s+SDL_MICRO_VERSION\s+(\d+)\Z';
39my $mainincludefname = 'SDL.h';
40my $selectheaderregex = '\ASDL.*?\.h\Z';
41my $projecturl = 'https://libsdl.org/';
42my $wikiurl = 'https://wiki.libsdl.org';
43my $bugreporturl = 'https://github.com/libsdl-org/sdlwiki/issues/new';
44my $srcpath = undef;
45my $wikipath = undef;
46my $wikireadmesubdir = 'README';
47my $warn_about_missing = 0;
48my $copy_direction = 0;
49my $optionsfname = undef;
50my $wikipreamble = undef;
51my $wikiheaderfiletext = 'Defined in %fname%';
52my $manpageheaderfiletext = 'Defined in %fname%';
53my $manpagesymbolfilterregex = undef;
54my $headercategoryeval = undef;
55my $quickrefenabled = 0;
56my @quickrefcategoryorder;
57my $quickreftitle = undef;
58my $quickrefurl = undef;
59my $quickrefdesc = undef;
60my $quickrefmacroregex = undef;
61my $changeformat = undef;
62my $manpath = undef;
63my $gitrev = undef;
64
65foreach (@ARGV) {
66 $warn_about_missing = 1, next if $_ eq '--warn-about-missing';
67 $copy_direction = 1, next if $_ eq '--copy-to-headers';
68 $copy_direction = 1, next if $_ eq '--copy-to-header';
69 $copy_direction = -1, next if $_ eq '--copy-to-wiki';
70 $copy_direction = -2, next if $_ eq '--copy-to-manpages';
71 $copy_direction = -3, next if $_ eq '--report-coverage-gaps';
72 $copy_direction = -4, next if $_ eq '--copy-to-latex';
73 if (/\A--options=(.*)\Z/) {
74 $optionsfname = $1;
75 next;
76 } elsif (/\A--changeformat=(.*)\Z/) {
77 $changeformat = $1;
78 next;
79 } elsif (/\A--manpath=(.*)\Z/) {
80 $manpath = $1;
81 next;
82 } elsif (/\A--rev=(.*)\Z/) {
83 $gitrev = $1;
84 next;
85 }
86 $srcpath = $_, next if not defined $srcpath;
87 $wikipath = $_, next if not defined $wikipath;
88}
89
90my $default_optionsfname = '.wikiheaders-options';
91$default_optionsfname = "$srcpath/$default_optionsfname" if defined $srcpath;
92
93if ((not defined $optionsfname) && (-f $default_optionsfname)) {
94 $optionsfname = $default_optionsfname;
95}
96
97if (defined $optionsfname) {
98 open OPTIONS, '<', $optionsfname or die("Failed to open options file '$optionsfname': $!\n");
99 while (<OPTIONS>) {
100 next if /\A\s*\#/; # Skip lines that start with (optional whitespace, then) '#' as comments.
101
102 chomp;
103 if (/\A(.*?)\=(.*)\Z/) {
104 my $key = $1;
105 my $val = $2;
106 $key =~ s/\A\s+//;
107 $key =~ s/\s+\Z//;
108 $val =~ s/\A\s+//;
109 $val =~ s/\s+\Z//;
110 $warn_about_missing = int($val), next if $key eq 'warn_about_missing';
111 $srcpath = $val, next if $key eq 'srcpath';
112 $wikipath = $val, next if $key eq 'wikipath';
113 $apiprefixregex = $val, next if $key eq 'apiprefixregex';
114 $projectfullname = $val, next if $key eq 'projectfullname';
115 $projectshortname = $val, next if $key eq 'projectshortname';
116 $wikisubdir = $val, next if $key eq 'wikisubdir';
117 $incsubdir = $val, next if $key eq 'incsubdir';
118 $readmesubdir = $val, next if $key eq 'readmesubdir';
119 $versionmajorregex = $val, next if $key eq 'versionmajorregex';
120 $versionminorregex = $val, next if $key eq 'versionminorregex';
121 $versionmicroregex = $val, next if $key eq 'versionmicroregex';
122 $versionfname = $val, next if $key eq 'versionfname';
123 $mainincludefname = $val, next if $key eq 'mainincludefname';
124 $selectheaderregex = $val, next if $key eq 'selectheaderregex';
125 $projecturl = $val, next if $key eq 'projecturl';
126 $wikiurl = $val, next if $key eq 'wikiurl';
127 $bugreporturl = $val, next if $key eq 'bugreporturl';
128 $wikipreamble = $val, next if $key eq 'wikipreamble';
129 $wikiheaderfiletext = $val, next if $key eq 'wikiheaderfiletext';
130 $manpageheaderfiletext = $val, next if $key eq 'manpageheaderfiletext';
131 $manpagesymbolfilterregex = $val, next if $key eq 'manpagesymbolfilterregex';
132 $headercategoryeval = $val, next if $key eq 'headercategoryeval';
133 $quickrefenabled = int($val), next if $key eq 'quickrefenabled';
134 @quickrefcategoryorder = split(/,/, $val), next if $key eq 'quickrefcategoryorder';
135 $quickreftitle = $val, next if $key eq 'quickreftitle';
136 $quickrefurl = $val, next if $key eq 'quickrefurl';
137 $quickrefdesc = $val, next if $key eq 'quickrefdesc';
138 $quickrefmacroregex = $val, next if $key eq 'quickrefmacroregex';
139 }
140 }
141 close(OPTIONS);
142}
143
144sub escLaTeX {
145 my $str = shift;
146 $str =~ s/([_\#\&\^])/\\$1/g;
147 return $str;
148}
149
150my $wordwrap_mode = 'mediawiki';
151sub wordwrap_atom { # don't call this directly.
152 my $str = shift;
153 my $retval = '';
154
155 # wordwrap but leave links intact, even if they overflow.
156 if ($wordwrap_mode eq 'mediawiki') {
157 while ($str =~ s/(.*?)\s*(\[https?\:\/\/.*?\s+.*?\])\s*//ms) {
158 $retval .= fill('', '', $1); # wrap it.
159 $retval .= "\n$2\n"; # don't wrap it.
160 }
161 } elsif ($wordwrap_mode eq 'md') {
162 while ($str =~ s/(.*?)\s*(\[.*?\]\(https?\:\/\/.*?\))\s*//ms) {
163 $retval .= fill('', '', $1); # wrap it.
164 $retval .= "\n$2\n"; # don't wrap it.
165 }
166 }
167
168 return $retval . fill('', '', $str);
169}
170
171sub wordwrap_with_bullet_indent { # don't call this directly.
172 my $bullet = shift;
173 my $str = shift;
174 my $retval = '';
175
176 #print("WORDWRAP BULLET ('$bullet'):\n\n$str\n\n");
177
178 # You _can't_ (at least with Pandoc) have a bullet item with a newline in
179 # MediaWiki, so _remove_ wrapping!
180 if ($wordwrap_mode eq 'mediawiki') {
181 $retval = "$bullet$str";
182 $retval =~ s/\n/ /gms;
183 $retval =~ s/\s+$//gms;
184 #print("WORDWRAP BULLET DONE:\n\n$retval\n\n");
185 return "$retval\n";
186 }
187
188 my $bulletlen = length($bullet);
189
190 # wrap it and then indent each line to be under the bullet.
191 $Text::Wrap::columns -= $bulletlen;
192 my @wrappedlines = split /\n/, wordwrap_atom($str);
193 $Text::Wrap::columns += $bulletlen;
194
195 my $prefix = $bullet;
196 my $usual_prefix = ' ' x $bulletlen;
197
198 foreach (@wrappedlines) {
199 s/\s*\Z//;
200 $retval .= "$prefix$_\n";
201 $prefix = $usual_prefix;
202 }
203
204 return $retval;
205}
206
207sub wordwrap_one_paragraph { # don't call this directly.
208 my $retval = '';
209 my $p = shift;
210 #print "\n\n\nPARAGRAPH: [$p]\n\n\n";
211 if ($p =~ s/\A([\*\-] )//) { # bullet list, starts with "* " or "- ".
212 my $bullet = $1;
213 my $item = '';
214 my @items = split /\n/, $p;
215 foreach (@items) {
216 if (s/\A([\*\-] )//) {
217 $retval .= wordwrap_with_bullet_indent($bullet, $item);
218 $item = '';
219 }
220 s/\A\s*//;
221 $item .= "$_\n"; # accumulate lines until we hit the end or another bullet.
222 }
223 if ($item ne '') {
224 $retval .= wordwrap_with_bullet_indent($bullet, $item);
225 }
226 } elsif ($p =~ /\A\s*\|.*\|\s*\n/) { # Markdown table
227 $retval = "$p\n"; # don't wrap it (!!! FIXME: but maybe parse by lines until we run out of table...)
228 } else {
229 $retval = wordwrap_atom($p) . "\n";
230 }
231
232 return $retval;
233}
234
235sub wordwrap_paragraphs { # don't call this directly.
236 my $str = shift;
237 my $retval = '';
238 my @paragraphs = split /\n\n/, $str;
239 foreach (@paragraphs) {
240 next if $_ eq '';
241 $retval .= wordwrap_one_paragraph($_);
242 $retval .= "\n";
243 }
244 return $retval;
245}
246
247my $wordwrap_default_columns = 76;
248sub wordwrap {
249 my $str = shift;
250 my $columns = shift;
251
252 $columns = $wordwrap_default_columns if not defined $columns;
253 $columns += $wordwrap_default_columns if $columns < 0;
254 $Text::Wrap::columns = $columns;
255
256 my $retval = '';
257
258 #print("\n\nWORDWRAP:\n\n$str\n\n\n");
259
260 $str =~ s/\A\n+//ms;
261
262 while ($str =~ s/(.*?)(\`\`\`.*?\`\`\`|\<syntaxhighlight.*?\<\/syntaxhighlight\>)//ms) {
263 #print("\n\nWORDWRAP BLOCK:\n\n$1\n\n ===\n\n$2\n\n\n");
264 $retval .= wordwrap_paragraphs($1); # wrap it.
265 $retval .= "$2\n\n"; # don't wrap it.
266 }
267
268 $retval .= wordwrap_paragraphs($str); # wrap what's left.
269 $retval =~ s/\n+\Z//ms;
270
271 #print("\n\nWORDWRAP DONE:\n\n$retval\n\n\n");
272 return $retval;
273}
274
275# This assumes you're moving from Markdown (in the Doxygen data) to Wiki, which
276# is why the 'md' section is so sparse.
277sub wikify_chunk {
278 my $wikitype = shift;
279 my $str = shift;
280 my $codelang = shift;
281 my $code = shift;
282
283 #print("\n\nWIKIFY CHUNK:\n\n$str\n\n\n");
284
285 if ($wikitype eq 'mediawiki') {
286 # convert `code` things first, so they aren't mistaken for other markdown items.
287 my $codedstr = '';
288 while ($str =~ s/\A(.*?)\`(.*?)\`//ms) {
289 my $codeblock = $2;
290 $codedstr .= wikify_chunk($wikitype, $1, undef, undef);
291 if (defined $apiprefixregex) {
292 # Convert obvious API things to wikilinks, even inside `code` blocks.
293 $codeblock =~ s/(\A|[^\/a-zA-Z0-9_])($apiprefixregex[a-zA-Z0-9_]+)/$1\[\[$2\]\]/gms;
294 }
295 $codedstr .= "<code>$codeblock</code>";
296 }
297
298 # Convert obvious API things to wikilinks.
299 if (defined $apiprefixregex) {
300 $str =~ s/(\A|[^\/a-zA-Z0-9_])($apiprefixregex[a-zA-Z0-9_]+)/$1\[\[$2\]\]/gms;
301 }
302
303 # Make some Markdown things into MediaWiki...
304
305 # links
306 $str =~ s/\[(.*?)\]\((https?\:\/\/.*?)\)/\[$2 $1\]/g;
307
308 # bold+italic
309 $str =~ s/\*\*\*(.*?)\*\*\*/'''''$1'''''/gms;
310
311 # bold
312 $str =~ s/\*\*(.*?)\*\*/'''$1'''/gms;
313
314 # italic
315 $str =~ s/\*(.*?)\*/''$1''/gms;
316
317 # bullets
318 $str =~ s/^\- /* /gm;
319
320 $str = $codedstr . $str;
321
322 if (defined $code) {
323 $str .= "<syntaxhighlight lang='$codelang'>$code<\/syntaxhighlight>";
324 }
325 } elsif ($wikitype eq 'md') {
326 # convert `code` things first, so they aren't mistaken for other markdown items.
327 my $codedstr = '';
328 while ($str =~ s/\A(.*?)(\`.*?\`)//ms) {
329 my $codeblock = $2;
330 $codedstr .= wikify_chunk($wikitype, $1, undef, undef);
331 if (defined $apiprefixregex) {
332 # Convert obvious API things to wikilinks, even inside `code` blocks,
333 # BUT ONLY IF the entire code block is the API thing,
334 # So something like "just call `SDL_Whatever`" will become
335 # "just call [`SDL_Whatever`](SDL_Whatever)", but
336 # "just call `SDL_Whatever(7)`" will not. It's just the safest
337 # way to do this without resorting to wrapping things in html <code> tags.
338 $codeblock =~ s/\A\`($apiprefixregex[a-zA-Z0-9_]+)\`\Z/[`$1`]($1)/gms;
339 }
340 $codedstr .= $codeblock;
341 }
342
343 # Convert obvious API things to wikilinks.
344 if (defined $apiprefixregex) {
345 $str =~ s/(\A|[^\/a-zA-Z0-9_])($apiprefixregex[a-zA-Z0-9_]+)/$1\[$2\]\($2\)/gms;
346 }
347
348 $str = $codedstr . $str;
349
350 if (defined $code) {
351 $str .= "```$codelang\n$code\n```\n";
352 }
353 }
354
355 #print("\n\nWIKIFY CHUNK DONE:\n\n$str\n\n\n");
356
357 return $str;
358}
359
360sub wikify {
361 my $wikitype = shift;
362 my $str = shift;
363 my $retval = '';
364
365 #print("WIKIFY WHOLE:\n\n$str\n\n\n");
366
367 while ($str =~ s/\A(.*?)\`\`\`(.*?)\n(.*?)\n\`\`\`(\n|\Z)//ms) {
368 $retval .= wikify_chunk($wikitype, $1, $2, $3);
369 }
370 $retval .= wikify_chunk($wikitype, $str, undef, undef);
371
372 #print("WIKIFY WHOLE DONE:\n\n$retval\n\n\n");
373
374 return $retval;
375}
376
377
378my $dewikify_mode = 'md';
379my $dewikify_manpage_code_indent = 1;
380
381sub dewikify_chunk {
382 my $wikitype = shift;
383 my $str = shift;
384 my $codelang = shift;
385 my $code = shift;
386
387 #print("\n\nDEWIKIFY CHUNK:\n\n$str\n\n\n");
388
389 if ($dewikify_mode eq 'md') {
390 if ($wikitype eq 'mediawiki') {
391 # Doxygen supports Markdown (and it just simply looks better than MediaWiki
392 # when looking at the raw headers), so do some conversions here as necessary.
393
394 # Dump obvious wikilinks.
395 if (defined $apiprefixregex) {
396 $str =~ s/\[\[($apiprefixregex[a-zA-Z0-9_]+)\]\]/$1/gms;
397 }
398
399 # links
400 $str =~ s/\[(https?\:\/\/.*?)\s+(.*?)\]/\[$2\]\($1\)/g;
401
402 # <code></code> is also popular. :/
403 $str =~ s/\<code>(.*?)<\/code>/`$1`/gms;
404
405 # bold+italic
406 $str =~ s/'''''(.*?)'''''/***$1***/gms;
407
408 # bold
409 $str =~ s/'''(.*?)'''/**$1**/gms;
410
411 # italic
412 $str =~ s/''(.*?)''/*$1*/gms;
413
414 # bullets
415 $str =~ s/^\* /- /gm;
416 } elsif ($wikitype eq 'md') {
417 # Dump obvious wikilinks. The rest can just passthrough.
418 if (defined $apiprefixregex) {
419 $str =~ s/\[(\`?$apiprefixregex[a-zA-Z0-9_]+\`?)\]\($apiprefixregex[a-zA-Z0-9_]+\)/$1/gms;
420 }
421 }
422
423 if (defined $code) {
424 $str .= "\n```$codelang\n$code\n```\n";
425 }
426 } elsif ($dewikify_mode eq 'manpage') {
427 # make sure these can't become part of roff syntax.
428 $str =~ s/\./\\[char46]/gms;
429 $str =~ s/"/\\(dq/gms;
430 $str =~ s/'/\\(aq/gms;
431
432 if ($wikitype eq 'mediawiki') {
433 # Dump obvious wikilinks.
434 if (defined $apiprefixregex) {
435 $str =~ s/\s*\[\[($apiprefixregex[a-zA-Z0-9_]+)\]\]\s*/\n.BR $1\n/gms;
436 }
437
438 # links
439 $str =~ s/\[(https?\:\/\/.*?)\s+(.*?)\]/\n.URL "$1" "$2"\n/g;
440
441 # <code></code> is also popular. :/
442 $str =~ s/\s*\<code>(.*?)<\/code>\s*/\n.BR $1\n/gms;
443
444 # bold+italic (this looks bad, just make it bold).
445 $str =~ s/\s*'''''(.*?)'''''\s*/\n.B $1\n/gms;
446
447 # bold
448 $str =~ s/\s*'''(.*?)'''\s*/\n.B $1\n/gms;
449
450 # italic
451 $str =~ s/\s*''(.*?)''\s*/\n.I $1\n/gms;
452
453 # bullets
454 $str =~ s/^\* /\n\\\(bu /gm;
455 } elsif ($wikitype eq 'md') {
456 # bullets
457 $str =~ s/^\- /\n\\(bu /gm;
458 # merge paragraphs
459 $str =~ s/^[ \t]+//gm;
460 $str =~ s/([^\-\n])\n([^\-\n])/$1 $2/g;
461 $str =~ s/\n\n/\n.PP\n/g;
462
463 # Dump obvious wikilinks.
464 if (defined $apiprefixregex) {
465 my $apr = $apiprefixregex;
466 if(!($apr =~ /\A\(.*\)\Z/s)) {
467 # we're relying on the apiprefixregex having a capturing group.
468 $apr = "(" . $apr . ")";
469 }
470 $str =~ s/(\S*?)\[\`?($apr[a-zA-Z0-9_]+)\`?\]\($apr[a-zA-Z0-9_]+\)(\S*)\s*/\n.BR "" "$1" "$2" "$5"\n/gm;
471 # handle cases like "[x](x), [y](y), [z](z)" being separated.
472 while($str =~ s/(\.BR[^\n]*)\n\n\.BR/$1\n.BR/gm) {}
473 }
474
475 # links
476 $str =~ s/\[(.*?)]\((https?\:\/\/.*?)\)/\n.URL "$2" "$1"\n/g;
477
478 # <code></code> is also popular. :/
479 $str =~ s/\s*(\S*?)\`([^\n]*?)\`(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
480
481 # bold+italic (this looks bad, just make it bold).
482 $str =~ s/\s*(\S*?)\*\*\*([^\n]*?)\*\*\*(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
483
484 # bold
485 $str =~ s/\s*(\S*?)\*\*([^\n]*?)\*\*(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
486
487 # italic
488 $str =~ s/\s*(\S*?)\*([^\n]*?)\*(\S*)\s*/\n.IR "" "$1" "$2" "$3"\n/gms;
489 }
490
491 # cleanup unnecessary quotes
492 $str =~ s/(\.[IB]R?)(.*?) ""\n/$1$2\n/gm;
493 $str =~ s/(\.[IB]R?) "" ""(.*?)\n/$1$2\n/gm;
494 $str =~ s/"(\S+)"/$1/gm;
495 # cleanup unnecessary whitespace
496 $str =~ s/ +\n/\n/gm;
497
498 if (defined $code) {
499 $code =~ s/\A\n+//gms;
500 $code =~ s/\n+\Z//gms;
501 $code =~ s/\\/\\(rs/gms;
502 if ($dewikify_manpage_code_indent) {
503 $str .= "\n.IP\n"
504 } else {
505 $str .= "\n.PP\n"
506 }
507 $str .= ".EX\n$code\n.EE\n.PP\n";
508 }
509 } elsif ($dewikify_mode eq 'LaTeX') {
510 if ($wikitype eq 'mediawiki') {
511 # Dump obvious wikilinks.
512 if (defined $apiprefixregex) {
513 $str =~ s/\s*\[\[($apiprefixregex[a-zA-Z0-9_]+)\]\]/$1/gms;
514 }
515
516 # links
517 $str =~ s/\[(https?\:\/\/.*?)\s+(.*?)\]/\\href{$1}{$2}/g;
518
519 # <code></code> is also popular. :/
520 $str =~ s/\s*\<code>(.*?)<\/code>/ \\texttt{$1}/gms;
521
522 # bold+italic
523 $str =~ s/\s*'''''(.*?)'''''/ \\textbf{\\textit{$1}}/gms;
524
525 # bold
526 $str =~ s/\s*'''(.*?)'''/ \\textbf{$1}/gms;
527
528 # italic
529 $str =~ s/\s*''(.*?)''/ \\textit{$1}/gms;
530
531 # bullets
532 $str =~ s/^\*\s+/ \\item /gm;
533 } elsif ($wikitype eq 'md') {
534 # Dump obvious wikilinks.
535 if (defined $apiprefixregex) {
536 $str =~ s/\[(\`?$apiprefixregex[a-zA-Z0-9_]+\`?)\]\($apiprefixregex[a-zA-Z0-9_]+\)/$1/gms;
537 }
538
539 # links
540 $str =~ s/\[(.*?)]\((https?\:\/\/.*?)\)/\\href{$2}{$1}/g;
541
542 # <code></code> is also popular. :/
543 $str =~ s/\s*\`(.*?)\`/ \\texttt{$1}/gms;
544
545 # bold+italic
546 $str =~ s/\s*\*\*\*(.*?)\*\*\*/ \\textbf{\\textit{$1}}/gms;
547
548 # bold
549 $str =~ s/\s*\*\*(.*?)\*\*/ \\textbf{$1}/gms;
550
551 # italic
552 $str =~ s/\s*\*(.*?)\*/ \\textit{$1}/gms;
553
554 # bullets
555 $str =~ s/^\-\s+/ \\item /gm;
556 }
557
558 # Wrap bullet lists in itemize blocks...
559 $str =~ s/^(\s*\\item .*?)(\n\n|\Z)/\n\\begin{itemize}\n$1$2\n\\end{itemize}\n\n/gms;
560
561 $str = escLaTeX($str);
562
563 if (defined $code) {
564 $code =~ s/\A\n+//gms;
565 $code =~ s/\n+\Z//gms;
566
567 if (($codelang eq '') || ($codelang eq 'output')) {
568 $str .= "\\begin{verbatim}\n$code\n\\end{verbatim}\n";
569 } else {
570 if ($codelang eq 'c') {
571 $codelang = 'C';
572 } elsif ($codelang eq 'c++') {
573 $codelang = 'C++';
574 } else {
575 die("Unexpected codelang '$codelang'");
576 }
577 $str .= "\n\\lstset{language=$codelang}\n";
578 $str .= "\\begin{lstlisting}\n$code\n\\end{lstlisting}\n";
579 }
580 }
581 } else {
582 die("Unexpected dewikify_mode");
583 }
584
585 #print("\n\nDEWIKIFY CHUNK DONE:\n\n$str\n\n\n");
586
587 return $str;
588}
589
590sub dewikify {
591 my $wikitype = shift;
592 my $str = shift;
593 return '' if not defined $str;
594
595 #print("DEWIKIFY WHOLE:\n\n$str\n\n\n");
596
597 $str =~ s/\A[\s\n]*\= .*? \=\s*?\n+//ms;
598 $str =~ s/\A[\s\n]*\=\= .*? \=\=\s*?\n+//ms;
599
600 my $retval = '';
601 if ($wikitype eq 'mediawiki') {
602 while ($str =~ s/\A(.*?)<syntaxhighlight lang='?(.*?)'?>(.*?)<\/syntaxhighlight\>//ms) {
603 $retval .= dewikify_chunk($wikitype, $1, $2, $3);
604 }
605 } elsif ($wikitype eq 'md') {
606 while ($str =~ s/\A(.*?)\n?```(.*?)\n(.*?)\n```\n//ms) {
607 $retval .= dewikify_chunk($wikitype, $1, $2, $3);
608 }
609 }
610 $retval .= dewikify_chunk($wikitype, $str, undef, undef);
611
612 #print("DEWIKIFY WHOLE DONE:\n\n$retval\n\n\n");
613
614 return $retval;
615}
616
617sub filecopy {
618 my $src = shift;
619 my $dst = shift;
620 my $endline = shift;
621 $endline = "\n" if not defined $endline;
622
623 open(COPYIN, '<', $src) or die("Failed to open '$src' for reading: $!\n");
624 open(COPYOUT, '>', $dst) or die("Failed to open '$dst' for writing: $!\n");
625 while (<COPYIN>) {
626 chomp;
627 s/[ \t\r\n]*\Z//;
628 print COPYOUT "$_$endline";
629 }
630 close(COPYOUT);
631 close(COPYIN);
632}
633
634sub usage {
635 die("USAGE: $0 <source code git clone path> <wiki git clone path> [--copy-to-headers|--copy-to-wiki|--copy-to-manpages] [--warn-about-missing] [--manpath=<man path>]\n\n");
636}
637
638usage() if not defined $srcpath;
639usage() if not defined $wikipath;
640#usage() if $copy_direction == 0;
641
642if (not defined $manpath) {
643 $manpath = "$srcpath/man";
644}
645
646my @standard_wiki_sections = (
647 'Draft',
648 '[Brief]',
649 'Deprecated',
650 'Header File',
651 'Syntax',
652 'Function Parameters',
653 'Macro Parameters',
654 'Fields',
655 'Values',
656 'Return Value',
657 'Remarks',
658 'Thread Safety',
659 'Version',
660 'Code Examples',
661 'See Also'
662);
663
664# Sections that only ever exist in the wiki and shouldn't be deleted when
665# not found in the headers.
666my %only_wiki_sections = ( # The ones don't mean anything, I just need to check for key existence.
667 'Draft', 1,
668 'Code Examples', 1,
669 'Header File', 1
670);
671
672
673my %headers = (); # $headers{"SDL_audio.h"} -> reference to an array of all lines of text in SDL_audio.h.
674my %headersyms = (); # $headersyms{"SDL_OpenAudio"} -> string of header documentation for SDL_OpenAudio, with comment '*' bits stripped from the start. Newlines embedded!
675my %headerdecls = ();
676my %headersymslocation = (); # $headersymslocation{"SDL_OpenAudio"} -> name of header holding SDL_OpenAudio define ("SDL_audio.h" in this case).
677my %headersymschunk = (); # $headersymschunk{"SDL_OpenAudio"} -> offset in array in %headers that should be replaced for this symbol.
678my %headersymshasdoxygen = (); # $headersymshasdoxygen{"SDL_OpenAudio"} -> 1 if there was no existing doxygen for this function.
679my %headersymstype = (); # $headersymstype{"SDL_OpenAudio"} -> 1 (function), 2 (macro), 3 (struct), 4 (enum), 5 (other typedef)
680my %headersymscategory = (); # $headersymscategory{"SDL_OpenAudio"} -> 'Audio' ... this is set with a `/* WIKI CATEGEORY: Audio */` comment in the headers that sets it on all symbols until a new comment changes it. So usually, once at the top of the header file.
681my %headercategorydocs = (); # $headercategorydocs{"Audio"} -> (fake) symbol for this category's documentation. Undefined if not documented.
682my %headersymsparaminfo = (); # $headersymsparaminfo{"SDL_OpenAudio"} -> reference to array of parameters, pushed by name, then C type string, repeating. Undef'd if void params, or not a function.
683my %headersymsrettype = (); # $headersymsrettype{"SDL_OpenAudio"} -> string of C datatype of return value. Undef'd if not a function.
684my %wikitypes = (); # contains string of wiki page extension, like $wikitypes{"SDL_OpenAudio"} == 'mediawiki'
685my %wikisyms = (); # contains references to hash of strings, each string being the full contents of a section of a wiki page, like $wikisyms{"SDL_OpenAudio"}{"Remarks"}.
686my %wikisectionorder = (); # contains references to array, each array item being a key to a wikipage section in the correct order, like $wikisectionorder{"SDL_OpenAudio"}[2] == 'Remarks'
687my %quickreffuncorder = (); # contains references to array, each array item being a key to a category with functions in the order they appear in the headers, like $quickreffuncorder{"Audio"}[0] == 'SDL_GetNumAudioDrivers'
688
689my %referenceonly = (); # $referenceonly{"Y"} -> symbol name that this symbol is bound to. This makes wiki pages that say "See X" where "X" is a typedef and "Y" is a define attached to it. These pages are generated in the wiki only and do not bridge to the headers or manpages.
690
691my @coverage_gap = (); # array of strings that weren't part of documentation, or blank, or basic preprocessor logic. Lets you see what this script is missing!
692
693sub add_coverage_gap {
694 if ($copy_direction == -3) { # --report-coverage-gaps
695 my $text = shift;
696 my $dent = shift;
697 my $lineno = shift;
698 return if $text =~ /\A\s*\Z/; # skip blank lines
699 return if $text =~ /\A\s*\#\s*(if|el|endif|include)/; # skip preprocessor floof.
700 push @coverage_gap, "$dent:$lineno: $text";
701 }
702}
703
704sub print_undocumented_section {
705 my $fh = shift;
706 my $typestr = shift;
707 my $typeval = shift;
708
709 print $fh "## $typestr defined in the headers, but not in the wiki\n\n";
710 my $header_only_sym = 0;
711 foreach (sort keys %headersyms) {
712 my $sym = $_;
713 if ((not defined $wikisyms{$sym}) && ($headersymstype{$sym} == $typeval)) {
714 print $fh "- [$sym]($sym)\n";
715 $header_only_sym = 1;
716 }
717 }
718 if (!$header_only_sym) {
719 print $fh "(none)\n";
720 }
721 print $fh "\n";
722
723 if (0) { # !!! FIXME: this lists things that _shouldn't_ be in the headers, like MigrationGuide, etc, but also we don't know if they're functions, macros, etc at this point (can we parse that from the wiki page, though?)
724 print $fh "## $typestr defined in the wiki, but not in the headers\n\n";
725
726 my $wiki_only_sym = 0;
727 foreach (sort keys %wikisyms) {
728 my $sym = $_;
729 if ((not defined $headersyms{$sym}) && ($headersymstype{$sym} == $typeval)) {
730 print $fh "- [$sym]($sym)\n";
731 $wiki_only_sym = 1;
732 }
733 }
734 if (!$wiki_only_sym) {
735 print $fh "(none)\n";
736 }
737 print $fh "\n";
738 }
739}
740
741sub strip_fn_declaration_metadata {
742 my $decl = shift;
743 $decl =~ s/SDL_(PRINTF|SCANF)_FORMAT_STRING\s*//; # don't want this metadata as part of the documentation.
744 $decl =~ s/SDL_ALLOC_SIZE2?\(.*?\)\s*//; # don't want this metadata as part of the documentation.
745 $decl =~ s/SDL_MALLOC\s*//; # don't want this metadata as part of the documentation.
746 $decl =~ s/SDL_(IN|OUT|INOUT)_.*?CAP\s*\(.*?\)\s*//g; # don't want this metadata as part of the documentation.
747 $decl =~ s/\)(\s*SDL_[a-zA-Z_]+(\(.*?\)|))*;/);/; # don't want this metadata as part of the documentation.
748 return $decl;
749}
750
751sub sanitize_c_typename {
752 my $str = shift;
753 $str =~ s/\A\s+//;
754 $str =~ s/\s+\Z//;
755 $str =~ s/const\s*(\*+)/const $1/g; # one space between `const` and pointer stars: `char const* const *` becomes `char const * const *`.
756 $str =~ s/\*\s+\*/**/g; # drop spaces between pointers: `void * *` becomes `void **`.
757 $str =~ s/\s*(\*+)\Z/ $1/; # one space between pointer stars and what it points to: `void**` becomes `void **`.
758 return $str;
759}
760
761my %big_ascii = (
762 'A' => [ "\x{20}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}\x{20}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{255A}\x{2550}\x{255D}\x{20}\x{20}\x{255A}\x{2550}\x{255D}" ],
763 'B' => [ "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}\x{20}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}\x{20}" ],
764 'C' => [ "\x{20}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}\x{20}\x{20}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}\x{20}\x{20}", "\x{255A}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}", "\x{20}\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}" ],
765 'D' => [ "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}\x{20}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}\x{20}" ],
766 'E' => [ "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}\x{20}\x{20}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{255D}\x{20}\x{20}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}", "\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}" ],
767 'F' => [ "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}\x{20}\x{20}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{255D}\x{20}\x{20}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}\x{20}\x{20}", "\x{255A}\x{2550}\x{255D}\x{20}\x{20}\x{20}\x{20}\x{20}" ],
768 'G' => [ "\x{20}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}\x{20}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}\x{20}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{2588}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{255A}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{20}\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}\x{20}" ],
769 'H' => [ "\x{2588}\x{2588}\x{2557}\x{20}\x{20}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{255A}\x{2550}\x{255D}\x{20}\x{20}\x{255A}\x{2550}\x{255D}" ],
770 'I' => [ "\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2551}", "\x{255A}\x{2550}\x{255D}" ],
771 'J' => [ "\x{20}\x{20}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2557}", "\x{20}\x{20}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{20}\x{20}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{255A}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{20}\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}\x{20}" ],
772 'K' => [ "\x{2588}\x{2588}\x{2557}\x{20}\x{20}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2551}\x{20}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}\x{20}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2588}\x{2588}\x{2557}\x{20}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{2588}\x{2588}\x{2557}", "\x{255A}\x{2550}\x{255D}\x{20}\x{20}\x{255A}\x{2550}\x{255D}" ],
773 'L' => [ "\x{2588}\x{2588}\x{2557}\x{20}\x{20}\x{20}\x{20}\x{20}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}\x{20}\x{20}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}\x{20}\x{20}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}\x{20}\x{20}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}", "\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}" ],
774 'M' => [ "\x{2588}\x{2588}\x{2588}\x{2557}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}\x{20}\x{2588}\x{2588}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2554}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2551}\x{255A}\x{2588}\x{2588}\x{2554}\x{255D}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2551}\x{20}\x{255A}\x{2550}\x{255D}\x{20}\x{2588}\x{2588}\x{2551}", "\x{255A}\x{2550}\x{255D}\x{20}\x{20}\x{20}\x{20}\x{20}\x{255A}\x{2550}\x{255D}" ],
775 'N' => [ "\x{2588}\x{2588}\x{2588}\x{2557}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2554}\x{2588}\x{2588}\x{2557}\x{20}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2551}\x{255A}\x{2588}\x{2588}\x{2557}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2551}\x{20}\x{255A}\x{2588}\x{2588}\x{2588}\x{2588}\x{2551}", "\x{255A}\x{2550}\x{255D}\x{20}\x{20}\x{255A}\x{2550}\x{2550}\x{2550}\x{255D}" ],
776 'O' => [ "\x{20}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}\x{20}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2550}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{255A}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{20}\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}\x{20}" ],
777 'P' => [ "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}\x{20}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2550}\x{255D}\x{20}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}\x{20}\x{20}", "\x{255A}\x{2550}\x{255D}\x{20}\x{20}\x{20}\x{20}\x{20}" ],
778 'Q' => [ "\x{20}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2550}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2551}\x{2584}\x{2584}\x{20}\x{2588}\x{2588}\x{2551}", "\x{255A}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{20}\x{255A}\x{2550}\x{2550}\x{2580}\x{2580}\x{2550}\x{255D}\x{20}" ],
779 'R' => [ "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}\x{20}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{255A}\x{2550}\x{255D}\x{20}\x{20}\x{255A}\x{2550}\x{255D}" ],
780 'S' => [ "\x{20}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}", "\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}\x{20}" ],
781 'T' => [ "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}", "\x{255A}\x{2550}\x{2550}\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{255D}", "\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}", "\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}", "\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}", "\x{20}\x{20}\x{20}\x{255A}\x{2550}\x{255D}\x{20}\x{20}\x{20}" ],
782 'U' => [ "\x{2588}\x{2588}\x{2557}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{255A}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{20}\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}\x{20}" ],
783 'V' => [ "\x{2588}\x{2588}\x{2557}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{255A}\x{2588}\x{2588}\x{2557}\x{20}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{20}\x{255A}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}\x{20}", "\x{20}\x{20}\x{255A}\x{2550}\x{2550}\x{2550}\x{255D}\x{20}\x{20}" ],
784 'W' => [ "\x{2588}\x{2588}\x{2557}\x{20}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2551}\x{20}\x{2588}\x{2557}\x{20}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2551}\x{2588}\x{2588}\x{2588}\x{2557}\x{2588}\x{2588}\x{2551}", "\x{255A}\x{2588}\x{2588}\x{2588}\x{2554}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{20}\x{255A}\x{2550}\x{2550}\x{255D}\x{255A}\x{2550}\x{2550}\x{255D}\x{20}" ],
785 'X' => [ "\x{2588}\x{2588}\x{2557}\x{20}\x{20}\x{2588}\x{2588}\x{2557}", "\x{255A}\x{2588}\x{2588}\x{2557}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{20}\x{255A}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}\x{20}", "\x{20}\x{2588}\x{2588}\x{2554}\x{2588}\x{2588}\x{2557}\x{20}", "\x{2588}\x{2588}\x{2554}\x{255D}\x{20}\x{2588}\x{2588}\x{2557}", "\x{255A}\x{2550}\x{255D}\x{20}\x{20}\x{255A}\x{2550}\x{255D}" ],
786 'Y' => [ "\x{2588}\x{2588}\x{2557}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2557}", "\x{255A}\x{2588}\x{2588}\x{2557}\x{20}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{20}\x{255A}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}\x{20}", "\x{20}\x{20}\x{255A}\x{2588}\x{2588}\x{2554}\x{255D}\x{20}\x{20}", "\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{20}", "\x{20}\x{20}\x{20}\x{255A}\x{2550}\x{255D}\x{20}\x{20}\x{20}" ],
787 'Z' => [ "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}", "\x{255A}\x{2550}\x{2550}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{20}\x{20}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}\x{20}", "\x{20}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}\x{20}\x{20}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}", "\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}" ],
788 ' ' => [ "\x{20}\x{20}\x{20}\x{20}", "\x{20}\x{20}\x{20}\x{20}", "\x{20}\x{20}\x{20}\x{20}", "\x{20}\x{20}\x{20}\x{20}", "\x{20}\x{20}\x{20}\x{20}", "\x{20}\x{20}\x{20}\x{20}" ],
789 '.' => [ "\x{20}\x{20}\x{20}", "\x{20}\x{20}\x{20}", "\x{20}\x{20}\x{20}", "\x{20}\x{20}\x{20}", "\x{2588}\x{2588}\x{2557}", "\x{255A}\x{2550}\x{255D}" ],
790 ',' => [ "\x{20}\x{20}\x{20}", "\x{20}\x{20}\x{20}", "\x{20}\x{20}\x{20}", "\x{20}\x{20}\x{20}", "\x{2584}\x{2588}\x{2557}", "\x{255A}\x{2550}\x{255D}" ],
791 '/' => [ "\x{20}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2557}", "\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{20}\x{20}\x{2588}\x{2588}\x{2554}\x{255D}\x{20}", "\x{20}\x{2588}\x{2588}\x{2554}\x{255D}\x{20}\x{20}", "\x{2588}\x{2588}\x{2554}\x{255D}\x{20}\x{20}\x{20}", "\x{255A}\x{2550}\x{255D}\x{20}\x{20}\x{20}\x{20}" ],
792 '!' => [ "\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2551}", "\x{255A}\x{2550}\x{255D}", "\x{2588}\x{2588}\x{2557}", "\x{255A}\x{2550}\x{255D}" ],
793 '_' => [ "\x{20}\x{20}\x{20}\x{20}\x{20}\x{20}\x{20}\x{20}", "\x{20}\x{20}\x{20}\x{20}\x{20}\x{20}\x{20}\x{20}", "\x{20}\x{20}\x{20}\x{20}\x{20}\x{20}\x{20}\x{20}", "\x{20}\x{20}\x{20}\x{20}\x{20}\x{20}\x{20}\x{20}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}", "\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}" ],
794 '0' => [ "\x{20}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}\x{20}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2551}\x{2588}\x{2588}\x{2554}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}\x{2588}\x{2588}\x{2551}", "\x{255A}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{20}\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}\x{20}" ],
795 '1' => [ "\x{20}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2588}\x{2551}", "\x{255A}\x{2588}\x{2588}\x{2551}", "\x{20}\x{2588}\x{2588}\x{2551}", "\x{20}\x{2588}\x{2588}\x{2551}", "\x{20}\x{255A}\x{2550}\x{255D}" ],
796 '2' => [ "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}\x{20}", "\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2588}\x{2588}\x{2557}", "\x{20}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2550}\x{255D}\x{20}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}", "\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}" ],
797 '3' => [ "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}\x{20}", "\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2588}\x{2588}\x{2557}", "\x{20}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{20}\x{255A}\x{2550}\x{2550}\x{2550}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}\x{20}" ],
798 '4' => [ "\x{2588}\x{2588}\x{2557}\x{20}\x{20}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2551}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2551}", "\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2588}\x{2588}\x{2551}", "\x{20}\x{20}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2551}", "\x{20}\x{20}\x{20}\x{20}\x{20}\x{255A}\x{2550}\x{255D}" ],
799 '5' => [ "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}", "\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2588}\x{2588}\x{2551}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2551}", "\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}" ],
800 '6' => [ "\x{20}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}\x{20}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}\x{20}", "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}\x{20}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2550}\x{2588}\x{2588}\x{2557}", "\x{255A}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{20}\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}\x{20}" ],
801 '7' => [ "\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}", "\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{2588}\x{2588}\x{2551}", "\x{20}\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2554}\x{255D}\x{20}", "\x{20}\x{20}\x{20}\x{2588}\x{2588}\x{2551}\x{20}\x{20}", "\x{20}\x{20}\x{20}\x{255A}\x{2550}\x{255D}\x{20}\x{20}" ],
802 '8' => [ "\x{20}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}\x{20}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2588}\x{2588}\x{2557}", "\x{255A}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2588}\x{2588}\x{2557}", "\x{255A}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{20}\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}\x{20}" ],
803 '9' => [ "\x{20}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2557}\x{20}", "\x{2588}\x{2588}\x{2554}\x{2550}\x{2550}\x{2588}\x{2588}\x{2557}", "\x{255A}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2551}", "\x{20}\x{255A}\x{2550}\x{2550}\x{2550}\x{2588}\x{2588}\x{2551}", "\x{20}\x{2588}\x{2588}\x{2588}\x{2588}\x{2588}\x{2554}\x{255D}", "\x{20}\x{255A}\x{2550}\x{2550}\x{2550}\x{2550}\x{255D}\x{20}" ],
804);
805
806sub print_big_ascii_string {
807 my $fh = shift;
808 my $str = shift;
809 my $comment = shift;
810 my $lowascii = shift;
811 $comment = '' if not defined $comment;
812 $lowascii = 0 if not defined $lowascii;
813
814 my @chars = split //, $str;
815 my $charcount = scalar(@chars);
816
817 binmode($fh, ":utf8");
818
819 my $maxrows = $lowascii ? 5 : 6;
820
821 for(my $rownum = 0; $rownum < $maxrows; $rownum++){
822 print $fh $comment;
823 my $charidx = 0;
824 foreach my $ch (@chars) {
825 my $rowsref = $big_ascii{uc($ch)};
826 die("Don't have a big ascii entry for '$ch'!\n") if not defined $rowsref;
827 my $row = @$rowsref[$rownum];
828
829 if ($lowascii) {
830 my @x = split //, $row;
831 foreach (@x) {
832 my $v = ($_ eq "\x{2588}") ? 'X' : ' ';
833 print $fh $v;
834 }
835 } else {
836 print $fh $row;
837 }
838
839 $charidx++;
840
841 if ($charidx < $charcount) {
842 print $fh " ";
843 }
844 }
845 print $fh "\n";
846 }
847}
848
849sub generate_quickref {
850 my $briefsref = shift;
851 my $path = shift;
852 my $lowascii = shift;
853
854 # !!! FIXME: this gitrev and majorver/etc stuff is copy/pasted a few times now.
855 if (!$gitrev) {
856 $gitrev = `cd "$srcpath" ; git rev-list HEAD~..`;
857 chomp($gitrev);
858 }
859
860 # !!! FIXME
861 open(FH, '<', "$srcpath/$versionfname") or die("Can't open '$srcpath/$versionfname': $!\n");
862 my $majorver = 0;
863 my $minorver = 0;
864 my $microver = 0;
865 while (<FH>) {
866 chomp;
867 if (/$versionmajorregex/) {
868 $majorver = int($1);
869 } elsif (/$versionminorregex/) {
870 $minorver = int($1);
871 } elsif (/$versionmicroregex/) {
872 $microver = int($1);
873 }
874 }
875 close(FH);
876 my $fullversion = "$majorver.$minorver.$microver";
877
878 my $tmppath = "$path.tmp";
879 open(my $fh, '>', $tmppath) or die("Can't open '$tmppath': $!\n");
880
881 if (not @quickrefcategoryorder) {
882 @quickrefcategoryorder = sort keys %headercategorydocs;
883 }
884
885 #my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime(time);
886 #my $datestr = sprintf("%04d-%02d-%02d %02d:%02d:%02d GMT", $year+1900, $mon+1, $mday, $hour, $min, $sec);
887
888 print $fh "<!-- DO NOT EDIT THIS PAGE ON THE WIKI. IT WILL BE OVERWRITTEN BY WIKIHEADERS AND CHANGES WILL BE LOST! -->\n\n";
889
890 # Just something to test big_ascii output.
891 #print_big_ascii_string($fh, "ABCDEFGHIJ", '', $lowascii);
892 #print_big_ascii_string($fh, "KLMNOPQRST", '', $lowascii);
893 #print_big_ascii_string($fh, "UVWXYZ0123", '', $lowascii);
894 #print_big_ascii_string($fh, "456789JT3A", '', $lowascii);
895 #print_big_ascii_string($fh, "hello, _a.b/c_!!", '', $lowascii);
896
897 # Dan Bechard's work was on an SDL2 cheatsheet:
898 # https://blog.theprogrammingjunkie.com/post/sdl2-cheatsheet/
899
900 if ($lowascii) {
901 print $fh "# QuickReferenceNoUnicode\n\n";
902 print $fh "If you want to paste this into a text editor that can handle\n";
903 print $fh "fancy Unicode section headers, try using\n";
904 print $fh "[QuickReference](QuickReference) instead.\n\n";
905 } else {
906 print $fh "# QuickReference\n\n";
907 print $fh "If you want to paste this into a text editor that can't handle\n";
908 print $fh "the fancy Unicode section headers, try using\n";
909 print $fh "[QuickReferenceNoUnicode](QuickReferenceNoUnicode) instead.\n\n";
910 }
911
912 print $fh "```c\n";
913 print $fh "// $quickreftitle\n" if defined $quickreftitle;
914 print $fh "//\n";
915 print $fh "// $quickrefurl\n//\n" if defined $quickrefurl;
916 print $fh "// $quickrefdesc\n" if defined $quickrefdesc;
917 #print $fh "// When this document was written: $datestr\n";
918 print $fh "// Based on $projectshortname version $fullversion\n";
919 #print $fh "// git revision $gitrev\n";
920 print $fh "//\n";
921 print $fh "// This can be useful in an IDE with search and syntax highlighting.\n";
922 print $fh "//\n";
923 print $fh "// Original idea for this document came from Dan Bechard (thanks!)\n";
924 print $fh "// ASCII art generated by: https://patorjk.com/software/taag/#p=display&f=ANSI%20Shadow (with modified 'S' for readability)\n\n";
925
926 foreach (@quickrefcategoryorder) {
927 my $cat = $_;
928 my $maxlen = 0;
929 my @csigs = ();
930 my $funcorderref = $quickreffuncorder{$cat};
931 next if not defined $funcorderref;
932
933 foreach (@$funcorderref) {
934 my $sym = $_;
935 my $csig = '';
936
937 if ($headersymstype{$sym} == 1) { # function
938 $csig = "${headersymsrettype{$sym}} $sym";
939 my $fnsigparams = $headersymsparaminfo{$sym};
940 if (not defined($fnsigparams)) {
941 $csig .= '(void);';
942 } else {
943 my $sep = '(';
944 for (my $i = 0; $i < scalar(@$fnsigparams); $i += 2) {
945 my $paramname = @$fnsigparams[$i];
946 my $paramtype = @$fnsigparams[$i+1];
947 my $spc = ($paramtype =~ /\*\Z/) ? '' : ' ';
948 $csig .= "$sep$paramtype$spc$paramname";
949 $sep = ', ';
950 }
951 $csig .= ");";
952 }
953 } elsif ($headersymstype{$sym} == 2) { # macro
954 next if defined $quickrefmacroregex && not $sym =~ /$quickrefmacroregex/;
955
956 $csig = (split /\n/, $headerdecls{$sym})[0]; # get the first line from a multiline string.
957 if (not $csig =~ s/\A(\#define [a-zA-Z0-9_]*\(.*?\))(\s+.*)?\Z/$1/) {
958 $csig =~ s/\A(\#define [a-zA-Z0-9_]*)(\s+.*)?\Z/$1/;
959 }
960 chomp($csig);
961 }
962
963 my $len = length($csig);
964 $maxlen = $len if $len > $maxlen;
965
966 push @csigs, $sym;
967 push @csigs, $csig;
968 }
969
970 $maxlen += 2;
971
972 next if (not @csigs);
973
974 print $fh "\n";
975 print_big_ascii_string($fh, $cat, '// ', $lowascii);
976 print $fh "\n";
977
978 while (@csigs) {
979 my $sym = shift @csigs;
980 my $csig = shift @csigs;
981 my $brief = $$briefsref{$sym};
982 if (defined $brief) {
983 $brief = "$brief";
984 chomp($brief);
985 my $thiswikitype = defined $wikitypes{$sym} ? $wikitypes{$sym} : 'md'; # default to MarkDown for new stuff.
986 $brief = dewikify($thiswikitype, $brief);
987 my $spaces = ' ' x ($maxlen - length($csig));
988 $brief = "$spaces// $brief";
989 } else {
990 $brief = '';
991 }
992 print $fh "$csig$brief\n";
993 }
994 }
995
996 print $fh "```\n\n";
997
998 close($fh);
999
1000# # Don't overwrite the file if nothing has changed besides the timestamp
1001# # and git revision.
1002# my $matches = 1;
1003# if ( not -f $path ) {
1004# $matches = 0; # always write if the file hasn't been created yet.
1005# } else {
1006# open(my $fh_a, '<', $tmppath) or die("Can't open '$tmppath': $!\n");
1007# open(my $fh_b, '<', $path) or die("Can't open '$path': $!\n");
1008# while (1) {
1009# my $a = <$fh_a>;
1010# my $b = <$fh_b>;
1011# $matches = 0, last if ((not defined $a) != (not defined $b));
1012# last if ((not defined $a) || (not defined $b));
1013# if ($a ne $b) {
1014# next if ($a =~ /\A\/\/ When this document was written:/);
1015# next if ($a =~ /\A\/\/ git revision /);
1016# $matches = 0;
1017# last;
1018# }
1019# }
1020#
1021# close($fh_a);
1022# close($fh_b);
1023# }
1024#
1025# if ($matches) {
1026# unlink($tmppath); # it's the same file except maybe the date/gitrev. Don't overwrite it.
1027# } else {
1028# rename($tmppath, $path) or die("Can't rename '$tmppath' to '$path': $!\n");
1029# }
1030 rename($tmppath, $path) or die("Can't rename '$tmppath' to '$path': $!\n");
1031}
1032
1033
1034my $incpath = "$srcpath";
1035$incpath .= "/$incsubdir" if $incsubdir ne '';
1036
1037my $wikireadmepath = "$wikipath/$wikireadmesubdir";
1038my $readmepath = undef;
1039if (defined $readmesubdir) {
1040 $readmepath = "$srcpath/$readmesubdir";
1041}
1042
1043opendir(DH, $incpath) or die("Can't opendir '$incpath': $!\n");
1044while (my $d = readdir(DH)) {
1045 my $dent = $d;
1046 next if not $dent =~ /$selectheaderregex/; # just selected headers.
1047 open(FH, '<', "$incpath/$dent") or die("Can't open '$incpath/$dent': $!\n");
1048
1049 # You can optionally set a wiki category with Perl code in .wikiheaders-options that gets eval()'d per-header,
1050 # and also if you put `/* WIKI CATEGORY: blah */` on a line by itself, it'll change the category for any symbols
1051 # below it in the same file. If no category is set, one won't be added for the symbol (beyond the standard CategoryFunction, etc)
1052 my $current_wiki_category = undef;
1053 if (defined $headercategoryeval) {
1054 $_ = $dent;
1055 $current_wiki_category = eval($headercategoryeval);
1056 if (($current_wiki_category eq '') || ($current_wiki_category eq '-')) {
1057 $current_wiki_category = undef;
1058 }
1059 #print("CATEGORY FOR '$dent' IS " . (defined($current_wiki_category) ? "'$current_wiki_category'" : '(undef)') . "\n");
1060 }
1061
1062 my @contents = ();
1063 my @function_order = ();
1064 my $ignoring_lines = 0;
1065 my $header_comment = -1;
1066 my $saw_category_doxygen = -1;
1067 my $lineno = 0;
1068
1069 while (<FH>) {
1070 chomp;
1071 $lineno++;
1072 my $symtype = 0; # nothing, yet.
1073 my $decl;
1074 my @templines;
1075 my $str;
1076 my $has_doxygen = 1;
1077
1078 # Since a lot of macros are just preprocessor logic spam and not all macros are worth documenting anyhow, we only pay attention to them when they have a Doxygen comment attached.
1079 # Functions and other things are a different story, though!
1080
1081 if ($header_comment == -1) {
1082 $header_comment = /\A\/\*\s*\Z/ ? 1 : 0;
1083 } elsif (($header_comment == 1) && (/\A\*\/\s*\Z/)) {
1084 $header_comment = 0;
1085 }
1086
1087 if ($ignoring_lines && /\A\s*\#\s*endif\s*\Z/) {
1088 $ignoring_lines = 0;
1089 push @contents, $_;
1090 next;
1091 } elsif ($ignoring_lines) {
1092 push @contents, $_;
1093 next;
1094 } elsif (/\A\s*\#\s*ifndef\s+SDL_WIKI_DOCUMENTATION_SECTION\s*\Z/) {
1095 $ignoring_lines = 1;
1096 push @contents, $_;
1097 next;
1098 } elsif (/\A\s*\/\*\s*WIKI CATEGORY:\s*(.*?)\s*\*\/\s*\Z/) {
1099 $current_wiki_category = (($1 eq '') || ($1 eq '-')) ? undef : $1;
1100 #print("CATEGORY FOR '$dent' CHANGED TO " . (defined($current_wiki_category) ? "'$current_wiki_category'" : '(undef)') . "\n");
1101 push @contents, $_;
1102 next;
1103 } elsif (/\A\s*extern\s+(SDL_DEPRECATED\s+|)(SDLMAIN_|SDL_)?DECLSPEC/) { # a function declaration without a doxygen comment?
1104 $symtype = 1; # function declaration
1105 @templines = ();
1106 $decl = $_;
1107 $str = '';
1108 $has_doxygen = 0;
1109 } elsif (/\A\s*SDL_FORCE_INLINE/) { # a (forced-inline) function declaration without a doxygen comment?
1110 $symtype = 1; # function declaration
1111 @templines = ();
1112 $decl = $_;
1113 $str = '';
1114 $has_doxygen = 0;
1115 } elsif (not /\A\/\*\*\s*\Z/) { # not doxygen comment start?
1116 push @contents, $_;
1117 add_coverage_gap($_, $dent, $lineno) if ($header_comment == 0);
1118 next;
1119 } else { # Start of a doxygen comment, parse it out.
1120 my $is_category_doxygen = 0;
1121
1122 @templines = ( $_ );
1123 while (<FH>) {
1124 chomp;
1125 $lineno++;
1126 push @templines, $_;
1127 last if /\A\s*\*\/\Z/;
1128 if (s/\A\s*\*\s*\`\`\`/```/) { # this is a hack, but a lot of other code relies on the whitespace being trimmed, but we can't trim it in code blocks...
1129 $str .= "$_\n";
1130 while (<FH>) {
1131 chomp;
1132 $lineno++;
1133 push @templines, $_;
1134 s/\A\s*\*\s?//;
1135 if (s/\A\s*\`\`\`/```/) {
1136 $str .= "$_\n";
1137 last;
1138 } else {
1139 $str .= "$_\n";
1140 }
1141 }
1142 } else {
1143 s/\A\s*\*\s*//; # Strip off the " * " at the start of the comment line.
1144
1145 # To add documentation to Category Pages, the rule is it has to
1146 # be the first Doxygen comment in the header, and it must start with `# CategoryX`
1147 # (otherwise we'll treat it as documentation for whatever's below it). `X` is
1148 # the category name, which doesn't _necessarily_ have to match
1149 # $current_wiki_category, but it probably should.
1150 #
1151 # For compatibility with Doxygen, if there's a `\file` here instead of
1152 # `# CategoryName`, we'll accept it and use the $current_wiki_category if set.
1153 if ($saw_category_doxygen == -1) {
1154 $saw_category_doxygen = defined($current_wiki_category) && /\A\\file\s+/;
1155 if ($saw_category_doxygen) {
1156 $_ = "# Category$current_wiki_category";
1157 } else {
1158 $saw_category_doxygen = /\A\# Category/;
1159 }
1160 $is_category_doxygen = $saw_category_doxygen;
1161 }
1162
1163 $str .= "$_\n";
1164 }
1165 }
1166
1167 if ($is_category_doxygen) {
1168 $str =~ s/\s*\Z//;
1169 $decl = '';
1170 $symtype = -1; # not a symbol at all.
1171 } else {
1172 $decl = <FH>;
1173 $lineno++ if defined $decl;
1174 $decl = '' if not defined $decl;
1175 chomp($decl);
1176 if ($decl =~ /\A\s*extern\s+(SDL_DEPRECATED\s+|)(SDLMAIN_|SDL_)?DECLSPEC/) {
1177 $symtype = 1; # function declaration
1178 } elsif ($decl =~ /\A\s*SDL_FORCE_INLINE/) {
1179 $symtype = 1; # (forced-inline) function declaration
1180 } elsif ($decl =~ /\A\s*\#\s*define\s+/) {
1181 $symtype = 2; # macro
1182 } elsif ($decl =~ /\A\s*(typedef\s+|)(struct|union)\s*([a-zA-Z0-9_]*?)\s*(\n|\{|\Z)/) {
1183 $symtype = 3; # struct or union
1184 } elsif ($decl =~ /\A\s*(typedef\s+|)enum\s*([a-zA-Z0-9_]*?)\s*(\n|\{|\Z)/) {
1185 $symtype = 4; # enum
1186 } elsif ($decl =~ /\A\s*typedef\s+.*\Z/) {
1187 $symtype = 5; # other typedef
1188 } else {
1189 #print "Found doxygen but no function sig:\n$str\n\n";
1190 foreach (@templines) {
1191 push @contents, $_;
1192 add_coverage_gap($_, $dent, $lineno);
1193 }
1194 push @contents, $decl;
1195 add_coverage_gap($decl, $dent, $lineno);
1196 next;
1197 }
1198 }
1199 }
1200
1201 my @paraminfo = ();
1202 my $rettype = undef;
1203 my @decllines = ( $decl );
1204 my $sym = '';
1205
1206 if ($symtype == -1) { # category documentation with no symbol attached.
1207 @decllines = ();
1208 if ($str =~ /^#\s*Category(.*?)\s*$/m) {
1209 $sym = "[category documentation] $1"; # make a fake, unique symbol that's not valid C.
1210 } else {
1211 die("Unexpected category documentation line '$str' in '$incpath/$dent' ...?");
1212 }
1213 $headercategorydocs{$current_wiki_category} = $sym;
1214 } elsif ($symtype == 1) { # a function
1215 my $is_forced_inline = ($decl =~ /\A\s*SDL_FORCE_INLINE/);
1216
1217 if ($is_forced_inline) {
1218 if (not $decl =~ /\)\s*(\{.*|)\s*\Z/) {
1219 while (<FH>) {
1220 chomp;
1221 $lineno++;
1222 push @decllines, $_;
1223 s/\A\s+//;
1224 s/\s+\Z//;
1225 $decl .= " $_";
1226 last if /\)\s*(\{.*|)\s*\Z/;
1227 }
1228 }
1229 $decl =~ s/\s*\)\s*(\{.*|)\s*\Z/);/;
1230 } else {
1231 if (not $decl =~ /;/) {
1232 while (<FH>) {
1233 chomp;
1234 $lineno++;
1235 push @decllines, $_;
1236 s/\A\s+//;
1237 s/\s+\Z//;
1238 $decl .= " $_";
1239 last if /;/;
1240 }
1241 }
1242 $decl =~ s/\s+\);\Z/);/;
1243 $decl =~ s/\s+;\Z/;/;
1244 }
1245
1246 $decl =~ s/\s+\Z//;
1247
1248 $decl = strip_fn_declaration_metadata($decl);
1249
1250 my $paramsstr = undef;
1251
1252 if (!$is_forced_inline && $decl =~ /\A\s*extern\s+(SDL_DEPRECATED\s+|)(SDLMAIN_|SDL_)?DECLSPEC\w*\s+(const\s+|)(unsigned\s+|)(.*?)([\*\s]+)(\*?)\s*SDLCALL\s+(.*?)\s*\((.*?)\);/) {
1253 $sym = $8;
1254 $rettype = "$3$4$5$6";
1255 $paramsstr = $9;
1256 } elsif ($is_forced_inline && $decl =~ /\A\s*SDL_FORCE_INLINE\s+(SDL_DEPRECATED\s+|)(const\s+|)(unsigned\s+|)(.*?)([\*\s]+)(.*?)\s*\((.*?)\);/) {
1257 $sym = $6;
1258 $rettype = "$2$3$4$5";
1259 $paramsstr = $7;
1260 } else {
1261 #print "Found doxygen but no function sig:\n$str\n\n";
1262 foreach (@templines) {
1263 push @contents, $_;
1264 }
1265 foreach (@decllines) {
1266 push @contents, $_;
1267 }
1268 next;
1269 }
1270
1271 $rettype = sanitize_c_typename($rettype);
1272
1273 if ($paramsstr =~ /\(/) {
1274 die("\n\n$0 FAILURE!\n" .
1275 "There's a '(' in the parameters for function '$sym' '$incpath/$dent'.\n" .
1276 "This usually means there's a parameter that's a function pointer type.\n" .
1277 "This causes problems for wikiheaders.pl and is less readable, too.\n" .
1278 "Please put that function pointer into a typedef,\n" .
1279 "and use the new type in this function's signature instead!\n\n");
1280 }
1281
1282 my @params = split(/,/, $paramsstr);
1283 my $dotdotdot = 0;
1284 foreach (@params) {
1285 my $p = $_;
1286 $p =~ s/\A\s+//;
1287 $p =~ s/\s+\Z//;
1288 if (($p eq 'void') || ($p eq '')) {
1289 die("Void parameter in a function with multiple params?! ('$sym' in '$incpath/$dent')") if (scalar(@params) != 1);
1290 } elsif ($p eq '...') {
1291 die("Mutiple '...' params?! ('$sym' in '$incpath/$dent')") if ($dotdotdot);
1292 $dotdotdot = 1;
1293 push @paraminfo, '...';
1294 push @paraminfo, '...';
1295 } elsif ($p =~ /\A(.*)\s+([a-zA-Z0-9_\*\[\]]+)\Z/) {
1296 die("Parameter after '...' param?! ('$sym' in '$incpath/$dent')") if ($dotdotdot);
1297 my $t = $1;
1298 my $n = $2;
1299 if ($n =~ s/\A(\*+)//) {
1300 $t .= $1; # move any `*` that stuck to the name over.
1301 }
1302 if ($n =~ s/\[\]\Z//) {
1303 $t = "$t*"; # move any `[]` that stuck to the name over, as a pointer.
1304 }
1305 $t = sanitize_c_typename($t);
1306 #print("$t\n");
1307 #print("$n\n");
1308 push @paraminfo, $n;
1309 push @paraminfo, $t;
1310 } else {
1311 die("Unexpected parameter '$p' in function '$sym' in '$incpath/$dent'!");
1312 }
1313 }
1314
1315 if (!$is_forced_inline) { # don't do with forced-inline because we don't want the implementation inserted in the wiki.
1316 my $shrink_length = 0;
1317
1318 $decl = ''; # rebuild this with the line breaks, since it looks better for syntax highlighting.
1319 foreach (@decllines) {
1320 if ($decl eq '') {
1321 my $temp;
1322
1323 $decl = $_;
1324 $temp = $decl;
1325 $temp =~ s/\Aextern\s+(SDL_DEPRECATED\s+|)(SDLMAIN_|SDL_)?DECLSPEC\w*\s+(.*?)\s+(\*?)SDLCALL\s+/$3$4 /;
1326 $shrink_length = length($decl) - length($temp);
1327 $decl = $temp;
1328 } else {
1329 my $trimmed = $_;
1330 $trimmed =~ s/\A\s{$shrink_length}//; # shrink to match the removed "extern SDL_DECLSPEC SDLCALL "
1331 $decl .= $trimmed;
1332 }
1333 $decl .= "\n";
1334 }
1335 }
1336
1337 $decl = strip_fn_declaration_metadata($decl);
1338
1339 # !!! FIXME: code duplication with typedef processing, below.
1340 # We assume any `#define`s directly after the function are related to it: probably bitflags for an integer typedef.
1341 # We'll also allow some other basic preprocessor lines.
1342 # Blank lines are allowed, anything else, even comments, are not.
1343 my $blank_lines = 0;
1344 my $lastpos = tell(FH);
1345 my $lastlineno = $lineno;
1346 my $additional_decl = '';
1347 my $saw_define = 0;
1348 while (<FH>) {
1349 chomp;
1350
1351 $lineno++;
1352
1353 if (/\A\s*\Z/) {
1354 $blank_lines++;
1355 } elsif (/\A\s*\#\s*(define|if|else|elif|endif)(\s+|\Z)/) {
1356 if (/\A\s*\#\s*define\s+([a-zA-Z0-9_]*)/) {
1357 $referenceonly{$1} = $sym;
1358 $saw_define = 1;
1359 } elsif (!$saw_define) {
1360 # if the first non-blank thing isn't a #define, assume we're done.
1361 seek(FH, $lastpos, 0); # re-read eaten lines again next time.
1362 $lineno = $lastlineno;
1363 last;
1364 }
1365
1366 # update strings now that we know everything pending is to be applied to this declaration. Add pending blank lines and the new text.
1367
1368 # At Sam's request, don't list property defines with functions. (See #9440)
1369 my $is_property = /\A\s*\#\s*define\s+SDL_PROP_/;
1370 if (!$is_property) {
1371 if ($blank_lines > 0) {
1372 while ($blank_lines > 0) {
1373 $additional_decl .= "\n";
1374 push @decllines, '';
1375 $blank_lines--;
1376 }
1377 }
1378 $additional_decl .= "\n$_";
1379 push @decllines, $_;
1380 $lastpos = tell(FH);
1381 }
1382 } else {
1383 seek(FH, $lastpos, 0); # re-read eaten lines again next time.
1384 $lineno = $lastlineno;
1385 last;
1386 }
1387 }
1388 $decl .= $additional_decl;
1389 } elsif ($symtype == 2) { # a macro
1390 if ($decl =~ /\A\s*\#\s*define\s+(.*?)(\(.*?\)|)\s+/) {
1391 $sym = $1;
1392 } else {
1393 #print "Found doxygen but no macro:\n$str\n\n";
1394 foreach (@templines) {
1395 push @contents, $_;
1396 }
1397 foreach (@decllines) {
1398 push @contents, $_;
1399 }
1400 next;
1401 }
1402
1403 while ($decl =~ /\\\Z/) {
1404 my $l = <FH>;
1405 last if not $l;
1406 $lineno++;
1407 chomp($l);
1408 push @decllines, $l;
1409 #$l =~ s/\A\s+//;
1410 $l =~ s/\s+\Z//;
1411 $decl .= "\n$l";
1412 }
1413 } elsif (($symtype == 3) || ($symtype == 4)) { # struct or union or enum
1414 my $has_definition = 0;
1415 if ($decl =~ /\A\s*(typedef\s+|)(struct|union|enum)\s*([a-zA-Z0-9_]*?)\s*(\n|\{|\;|\Z)/) {
1416 my $ctype = $2;
1417 my $origsym = $3;
1418 my $ending = $4;
1419 $sym = $origsym;
1420 if ($sym =~ s/\A(.*?)(\s+)(.*?)\Z/$1/) {
1421 die("Failed to parse '$origsym' correctly!") if ($sym ne $1); # Thought this was "typedef struct MySym MySym;" ... it was not. :( This is a hack!
1422 }
1423 if ($sym eq '') {
1424 die("\n\n$0 FAILURE!\n" .
1425 "There's a 'typedef $ctype' in $incpath/$dent without a name at the top.\n" .
1426 "Instead of `typedef $ctype {} x;`, this should be `typedef $ctype x {} x;`.\n" .
1427 "This causes problems for wikiheaders.pl and scripting language bindings.\n" .
1428 "Please fix it!\n\n");
1429 }
1430 $has_definition = ($ending ne ';');
1431 } else {
1432 #print "Found doxygen but no datatype:\n$str\n\n";
1433 foreach (@templines) {
1434 push @contents, $_;
1435 }
1436 foreach (@decllines) {
1437 push @contents, $_;
1438 }
1439 next;
1440 }
1441
1442 # This block attempts to find the whole struct/union/enum definition by counting matching brackets. Kind of yucky.
1443 # It also "parses" enums enough to find out the elements of it.
1444 if ($has_definition) {
1445 my $started = 0;
1446 my $brackets = 0;
1447 my $pending = $decl;
1448 my $skipping_comment = 0;
1449
1450 $decl = '';
1451 while (!$started || ($brackets != 0)) {
1452 foreach my $seg (split(/([{}])/, $pending)) { # (this will pick up brackets in comments! Be careful!)
1453 $decl .= $seg;
1454 if ($seg eq '{') {
1455 $started = 1;
1456 $brackets++;
1457 } elsif ($seg eq '}') {
1458 die("Something is wrong with header $incpath/$dent while parsing $sym; is a bracket missing?\n") if ($brackets <= 0);
1459 $brackets--;
1460 }
1461 }
1462
1463 if ($skipping_comment) {
1464 if ($pending =~ s/\A.*?\*\///) {
1465 $skipping_comment = 0;
1466 }
1467 }
1468
1469 if (!$skipping_comment && $started && ($symtype == 4)) { # Pick out elements of an enum.
1470 my $stripped = "$pending";
1471 $stripped =~ s/\/\*.*?\*\///g; # dump /* comments */ that exist fully on one line.
1472 if ($stripped =~ /\/\*/) { # uhoh, a /* comment */ that crosses newlines.
1473 $skipping_comment = 1;
1474 } elsif ($stripped =~ /\A\s*([a-zA-Z0-9_]+)(.*)\Z/) { #\s*(\=\s*.*?|)\s*,?(.*?)\Z/) {
1475 if ($1 ne 'typedef') { # make sure we didn't just eat the first line by accident. :/
1476 #print("ENUM [$1] $incpath/$dent:$lineno\n");
1477 $referenceonly{$1} = $sym;
1478 }
1479 }
1480 }
1481
1482 if (!$started || ($brackets != 0)) {
1483 $pending = <FH>;
1484 die("EOF/error reading $incpath/$dent while parsing $sym\n") if not $pending;
1485 $lineno++;
1486 chomp($pending);
1487 push @decllines, $pending;
1488 $decl .= "\n";
1489 }
1490 }
1491 # this currently assumes the struct/union/enum ends on the line with the final bracket. I'm not writing a C parser here, fix the header!
1492 }
1493 } elsif ($symtype == 5) { # other typedef
1494 if ($decl =~ /\A\s*typedef\s+(.*)\Z/) {
1495 my $tdstr = $1;
1496
1497 if (not $decl =~ /;/) {
1498 while (<FH>) {
1499 chomp;
1500 $lineno++;
1501 push @decllines, $_;
1502 s/\A\s+//;
1503 s/\s+\Z//;
1504 $decl .= " $_";
1505 last if /;/;
1506 }
1507 }
1508 $decl =~ s/\s+(\))?;\Z/$1;/;
1509
1510 $tdstr =~ s/;\s*\Z//;
1511
1512 #my $datatype;
1513 if ($tdstr =~ /\A(.*?)\s*\((.*?)\s*\*\s*(.*?)\)\s*\((.*?)(\))?/) { # a function pointer type
1514 $sym = $3;
1515 #$datatype = "$1 ($2 *$sym)($4)";
1516 } elsif ($tdstr =~ /\A(.*[\s\*]+)(.*?)\s*\Z/) {
1517 $sym = $2;
1518 #$datatype = $1;
1519 } else {
1520 die("Failed to parse typedef '$tdstr' in $incpath/$dent!\n"); # I'm hitting a C grammar nail with a regexp hammer here, y'all.
1521 }
1522
1523 $sym =~ s/\A\s+//;
1524 $sym =~ s/\s+\Z//;
1525 #$datatype =~ s/\A\s+//;
1526 #$datatype =~ s/\s+\Z//;
1527 } else {
1528 #print "Found doxygen but no datatype:\n$str\n\n";
1529 foreach (@templines) {
1530 push @contents, $_;
1531 }
1532 foreach (@decllines) {
1533 push @contents, $_;
1534 }
1535 next;
1536 }
1537
1538 # We assume any `#define`s directly after the typedef are related to it: probably bitflags for an integer typedef.
1539 # We'll also allow some other basic preprocessor lines.
1540 # Blank lines are allowed, anything else, even comments, are not.
1541 my $blank_lines = 0;
1542 my $lastpos = tell(FH);
1543 my $lastlineno = $lineno;
1544 my $additional_decl = '';
1545 my $saw_define = 0;
1546 while (<FH>) {
1547 chomp;
1548
1549 $lineno++;
1550
1551 if (/\A\s*\Z/) {
1552 $blank_lines++;
1553 } elsif (/\A\s*\#\s*(define|if|else|elif|endif)(\s+|\Z)/) {
1554 if (/\A\s*\#\s*define\s+([a-zA-Z0-9_]*)/) {
1555 $referenceonly{$1} = $sym;
1556 $saw_define = 1;
1557 } elsif (!$saw_define) {
1558 # if the first non-blank thing isn't a #define, assume we're done.
1559 seek(FH, $lastpos, 0); # re-read eaten lines again next time.
1560 $lineno = $lastlineno;
1561 last;
1562 }
1563 # update strings now that we know everything pending is to be applied to this declaration. Add pending blank lines and the new text.
1564 if ($blank_lines > 0) {
1565 while ($blank_lines > 0) {
1566 $additional_decl .= "\n";
1567 push @decllines, '';
1568 $blank_lines--;
1569 }
1570 }
1571 $additional_decl .= "\n$_";
1572 push @decllines, $_;
1573 $lastpos = tell(FH);
1574 } else {
1575 seek(FH, $lastpos, 0); # re-read eaten lines again next time.
1576 $lineno = $lastlineno;
1577 last;
1578 }
1579 }
1580 $decl .= $additional_decl;
1581 } else {
1582 die("Unexpected symtype $symtype");
1583 }
1584
1585 #print("DECL: [$decl]\n");
1586
1587 #print("$sym:\n$str\n\n");
1588
1589 # There might be multiple declarations of a function due to #ifdefs,
1590 # and only one of them will have documentation. If we hit an
1591 # undocumented one before, delete the placeholder line we left for
1592 # it so it doesn't accumulate a new blank line on each run.
1593 my $skipsym = 0;
1594 if (defined $headersymshasdoxygen{$sym}) {
1595 if ($headersymshasdoxygen{$sym} == 0) { # An undocumented declaration already exists, nuke its placeholder line.
1596 delete $contents[$headersymschunk{$sym}]; # delete DOES NOT RENUMBER existing elements!
1597 } else { # documented function already existed?
1598 $skipsym = 1; # don't add this copy to the list of functions.
1599 if ($has_doxygen) {
1600 print STDERR "WARNING: Symbol '$sym' appears to be documented in multiple locations. Only keeping the first one we saw!\n";
1601 }
1602 push @contents, join("\n", @decllines) if (scalar(@decllines) > 0); # just put the existing declation in as-is.
1603 }
1604 }
1605
1606 if (!$skipsym) {
1607 $headersymscategory{$sym} = $current_wiki_category if defined $current_wiki_category;
1608 $headersyms{$sym} = $str;
1609 $headerdecls{$sym} = $decl;
1610 $headersymslocation{$sym} = $dent;
1611 $headersymschunk{$sym} = scalar(@contents);
1612 $headersymshasdoxygen{$sym} = $has_doxygen;
1613 $headersymstype{$sym} = $symtype;
1614 $headersymsparaminfo{$sym} = \@paraminfo if (scalar(@paraminfo) > 0);
1615 $headersymsrettype{$sym} = $rettype if (defined($rettype));
1616 push @function_order, $sym if ($symtype == 1) || ($symtype == 2);
1617 push @contents, join("\n", @templines);
1618 push @contents, join("\n", @decllines) if (scalar(@decllines) > 0);
1619 }
1620
1621 }
1622 close(FH);
1623
1624 $headers{$dent} = \@contents;
1625 $quickreffuncorder{$current_wiki_category} = \@function_order if defined $current_wiki_category;
1626}
1627closedir(DH);
1628
1629
1630opendir(DH, $wikipath) or die("Can't opendir '$wikipath': $!\n");
1631while (my $d = readdir(DH)) {
1632 my $dent = $d;
1633 my $type = '';
1634 if ($dent =~ /\.(md|mediawiki)\Z/) {
1635 $type = $1;
1636 } else {
1637 next; # only dealing with wiki pages.
1638 }
1639
1640 my $sym = $dent;
1641 $sym =~ s/\..*\Z//;
1642
1643 # (There are other pages to ignore, but these are known ones to not bother parsing.)
1644 # Ignore FrontPage.
1645 next if $sym eq 'FrontPage';
1646
1647 open(FH, '<', "$wikipath/$dent") or die("Can't open '$wikipath/$dent': $!\n");
1648
1649 if ($sym =~ /\ACategory(.*?)\Z/) { # Special case for Category pages.
1650 # Find the end of the category documentation in the existing file and append everything else to the new file.
1651 my $cat = $1;
1652 my $docstr = '';
1653 my $notdocstr = '';
1654 my $docs = 1;
1655 while (<FH>) {
1656 chomp;
1657 if ($docs) {
1658 $docs = 0 if /\A\-\-\-\-\Z/; # Hit a footer? We're done.
1659 $docs = 0 if /\A<!\-\-/; # Hit an HTML comment? We're done.
1660 }
1661 if ($docs) {
1662 $docstr .= "$_\n";
1663 } else {
1664 $notdocstr .= "$_\n";
1665 }
1666 }
1667 close(FH);
1668
1669 $docstr =~ s/\s*\Z//;
1670
1671 $sym = "[category documentation] $cat"; # make a fake, unique symbol that's not valid C.
1672 $wikitypes{$sym} = $type;
1673 my %sections = ();
1674 $sections{'Remarks'} = $docstr;
1675 $sections{'[footer]'} = $notdocstr;
1676 $wikisyms{$sym} = \%sections;
1677 my @section_order = ( 'Remarks', '[footer]' );
1678 $wikisectionorder{$sym} = \@section_order;
1679 next;
1680 }
1681
1682 my $current_section = '[start]';
1683 my @section_order = ( $current_section );
1684 my %sections = ();
1685 $sections{$current_section} = '';
1686
1687 my $firstline = 1;
1688
1689 while (<FH>) {
1690 chomp;
1691 my $orig = $_;
1692 s/\A\s*//;
1693 s/\s*\Z//;
1694
1695 if ($type eq 'mediawiki') {
1696 if (defined($wikipreamble) && $firstline && /\A\=\=\=\=\=\= (.*?) \=\=\=\=\=\=\Z/ && ($1 eq $wikipreamble)) {
1697 $firstline = 0; # skip this.
1698 next;
1699 } elsif (/\A\= (.*?) \=\Z/) {
1700 $firstline = 0;
1701 $current_section = ($1 eq $sym) ? '[Brief]' : $1;
1702 die("Doubly-defined section '$current_section' in '$dent'!\n") if defined $sections{$current_section};
1703 push @section_order, $current_section;
1704 $sections{$current_section} = '';
1705 } elsif (/\A\=\= (.*?) \=\=\Z/) {
1706 $firstline = 0;
1707 $current_section = ($1 eq $sym) ? '[Brief]' : $1;
1708 die("Doubly-defined section '$current_section' in '$dent'!\n") if defined $sections{$current_section};
1709 push @section_order, $current_section;
1710 $sections{$current_section} = '';
1711 next;
1712 } elsif (/\A\-\-\-\-\Z/) {
1713 $firstline = 0;
1714 $current_section = '[footer]';
1715 die("Doubly-defined section '$current_section' in '$dent'!\n") if defined $sections{$current_section};
1716 push @section_order, $current_section;
1717 $sections{$current_section} = '';
1718 next;
1719 }
1720 } elsif ($type eq 'md') {
1721 if (defined($wikipreamble) && $firstline && /\A\#\#\#\#\#\# (.*?)\Z/ && ($1 eq $wikipreamble)) {
1722 $firstline = 0; # skip this.
1723 next;
1724 } elsif (/\A\#+ (.*?)\Z/) {
1725 $firstline = 0;
1726 $current_section = ($1 eq $sym) ? '[Brief]' : $1;
1727 die("Doubly-defined section '$current_section' in '$dent'!\n") if defined $sections{$current_section};
1728 push @section_order, $current_section;
1729 $sections{$current_section} = '';
1730 next;
1731 } elsif (/\A\-\-\-\-\Z/) {
1732 $firstline = 0;
1733 $current_section = '[footer]';
1734 die("Doubly-defined section '$current_section' in '$dent'!\n") if defined $sections{$current_section};
1735 push @section_order, $current_section;
1736 $sections{$current_section} = '';
1737 next;
1738 }
1739 } else {
1740 die("Unexpected wiki file type. Fixme!");
1741 }
1742
1743 if ($firstline) {
1744 $firstline = ($_ ne '');
1745 }
1746 if (!$firstline) {
1747 $sections{$current_section} .= "$orig\n";
1748 }
1749 }
1750 close(FH);
1751
1752 foreach (keys %sections) {
1753 $sections{$_} =~ s/\A\n+//;
1754 $sections{$_} =~ s/\n+\Z//;
1755 $sections{$_} .= "\n";
1756 }
1757
1758 # older section name we used, migrate over from it.
1759 if (defined $sections{'Related Functions'}) {
1760 if (not defined $sections{'See Also'}) {
1761 $sections{'See Also'} = $sections{'Related Functions'};
1762 }
1763 delete $sections{'Related Functions'};
1764 }
1765
1766 if (0) {
1767 foreach (@section_order) {
1768 print("$sym SECTION '$_':\n");
1769 print($sections{$_});
1770 print("\n\n");
1771 }
1772 }
1773
1774 $wikitypes{$sym} = $type;
1775 $wikisyms{$sym} = \%sections;
1776 $wikisectionorder{$sym} = \@section_order;
1777}
1778closedir(DH);
1779
1780delete $wikisyms{"Undocumented"};
1781
1782{
1783 my $path = "$wikipath/Undocumented.md";
1784 open(my $fh, '>', $path) or die("Can't open '$path': $!\n");
1785
1786 print $fh "# Undocumented\n\n";
1787 print_undocumented_section($fh, 'Functions', 1);
1788 #print_undocumented_section($fh, 'Macros', 2);
1789
1790 close($fh);
1791}
1792
1793if ($warn_about_missing) {
1794 foreach (keys %wikisyms) {
1795 my $sym = $_;
1796 if (not defined $headersyms{$sym}) {
1797 print STDERR "WARNING: $sym defined in the wiki but not the headers!\n";
1798 }
1799 }
1800
1801 foreach (keys %headersyms) {
1802 my $sym = $_;
1803 if (not defined $wikisyms{$sym}) {
1804 print STDERR "WARNING: $sym defined in the headers but not the wiki!\n";
1805 }
1806 }
1807}
1808
1809if ($copy_direction == 1) { # --copy-to-headers
1810 my %changed_headers = ();
1811
1812 $dewikify_mode = 'md';
1813 $wordwrap_mode = 'md'; # the headers use Markdown format.
1814
1815 foreach (keys %headersyms) {
1816 my $sym = $_;
1817 next if not defined $wikisyms{$sym}; # don't have a page for that function, skip it.
1818 my $symtype = $headersymstype{$sym};
1819 my $wikitype = $wikitypes{$sym};
1820 my $sectionsref = $wikisyms{$sym};
1821 my $remarks = $sectionsref->{'Remarks'};
1822 my $returns = $sectionsref->{'Return Value'};
1823 my $threadsafety = $sectionsref->{'Thread Safety'};
1824 my $version = $sectionsref->{'Version'};
1825 my $related = $sectionsref->{'See Also'};
1826 my $deprecated = $sectionsref->{'Deprecated'};
1827 my $brief = $sectionsref->{'[Brief]'};
1828 my $addblank = 0;
1829 my $str = '';
1830
1831 my $params = undef;
1832 my $paramstr = undef;
1833
1834 if ($symtype == -1) { # category documentation block.
1835 # nothing to be done here.
1836 } elsif (($symtype == 1) || (($symtype == 5))) { # we'll assume a typedef (5) with a \param is a function pointer typedef.
1837 $params = $sectionsref->{'Function Parameters'};
1838 $paramstr = '\param';
1839 } elsif ($symtype == 2) {
1840 $params = $sectionsref->{'Macro Parameters'};
1841 $paramstr = '\param';
1842 } elsif ($symtype == 3) {
1843 $params = $sectionsref->{'Fields'};
1844 $paramstr = '\field';
1845 } elsif ($symtype == 4) {
1846 $params = $sectionsref->{'Values'};
1847 $paramstr = '\value';
1848 } else {
1849 die("Unexpected symtype $symtype");
1850 }
1851
1852 $headersymshasdoxygen{$sym} = 1; # Added/changed doxygen for this header.
1853
1854 $brief = dewikify($wikitype, $brief);
1855 $brief =~ s/\A(.*?\.) /$1\n/; # \brief should only be one sentence, delimited by a period+space. Split if necessary.
1856 my @briefsplit = split /\n/, $brief;
1857 $brief = shift @briefsplit;
1858
1859 if (defined $remarks) {
1860 $remarks = join("\n", @briefsplit) . dewikify($wikitype, $remarks);
1861 }
1862
1863 if (defined $brief) {
1864 $str .= "\n" if $addblank; $addblank = 1;
1865 $str .= wordwrap($brief) . "\n";
1866 }
1867
1868 if (defined $remarks) {
1869 $str .= "\n" if $addblank; $addblank = 1;
1870 $str .= wordwrap($remarks) . "\n";
1871 }
1872
1873 if (defined $deprecated) {
1874 # !!! FIXME: lots of code duplication in all of these.
1875 $str .= "\n" if $addblank; $addblank = 1;
1876 my $v = dewikify($wikitype, $deprecated);
1877 my $whitespacelen = length("\\deprecated") + 1;
1878 my $whitespace = ' ' x $whitespacelen;
1879 $v = wordwrap($v, -$whitespacelen);
1880 my @desclines = split /\n/, $v;
1881 my $firstline = shift @desclines;
1882 $str .= "\\deprecated $firstline\n";
1883 foreach (@desclines) {
1884 $str .= "${whitespace}$_\n";
1885 }
1886 }
1887
1888 if (defined $params) {
1889 $str .= "\n" if $addblank; $addblank = (defined $returns) ? 0 : 1;
1890 my @lines = split /\n/, dewikify($wikitype, $params);
1891 if ($wikitype eq 'mediawiki') {
1892 die("Unexpected data parsing MediaWiki table") if (shift @lines ne '{|'); # Dump the '{|' start
1893 while (scalar(@lines) >= 3) {
1894 my $c_datatype = shift @lines;
1895 my $name = shift @lines;
1896 my $desc = shift @lines;
1897 my $terminator; # the '|-' or '|}' line.
1898
1899 if (($desc eq '|-') or ($desc eq '|}') or (not $desc =~ /\A\|/)) { # we seem to be out of cells, which means there was no datatype column on this one.
1900 $terminator = $desc;
1901 $desc = $name;
1902 $name = $c_datatype;
1903 $c_datatype = '';
1904 } else {
1905 $terminator = shift @lines;
1906 }
1907
1908 last if ($terminator ne '|-') and ($terminator ne '|}'); # we seem to have run out of table.
1909 $name =~ s/\A\|\s*//;
1910 $name =~ s/\A\*\*(.*?)\*\*/$1/;
1911 $name =~ s/\A\'\'\'(.*?)\'\'\'/$1/;
1912 $desc =~ s/\A\|\s*//;
1913 #print STDERR "SYM: $sym CDATATYPE: $c_datatype NAME: $name DESC: $desc TERM: $terminator\n";
1914 my $whitespacelen = length($name) + 8;
1915 my $whitespace = ' ' x $whitespacelen;
1916 $desc = wordwrap($desc, -$whitespacelen);
1917 my @desclines = split /\n/, $desc;
1918 my $firstline = shift @desclines;
1919 $str .= "$paramstr $name $firstline\n";
1920 foreach (@desclines) {
1921 $str .= "${whitespace}$_\n";
1922 }
1923 }
1924 } elsif ($wikitype eq 'md') {
1925 my $l;
1926 $l = shift @lines;
1927 die("Unexpected data parsing Markdown table") if (not $l =~ /\A(\s*\|)?\s*\|\s*\|\s*\|\s*\Z/);
1928 $l = shift @lines;
1929 die("Unexpected data parsing Markdown table") if (not $l =~ /\A\s*(\|\s*\-*\s*)?\|\s*\-*\s*\|\s*\-*\s*\|\s*\Z/);
1930 while (scalar(@lines) >= 1) {
1931 $l = shift @lines;
1932 my $name;
1933 my $desc;
1934 if ($l =~ /\A\s*\|\s*(.*?)\s*\|\s*(.*?)\s*\|\s*(.*?)\s*\|\s*\Z/) {
1935 # c datatype is $1, but we don't care about it here.
1936 $name = $2;
1937 $desc = $3;
1938 } elsif ($l =~ /\A\s*\|\s*(.*?)\s*\|\s*(.*?)\s*\|\s*\Z/) {
1939 $name = $1;
1940 $desc = $2;
1941 } else {
1942 last; # we seem to have run out of table.
1943 }
1944
1945 $name =~ s/\A\*\*(.*?)\*\*/$1/;
1946 $name =~ s/\A\'\'\'(.*?)\'\'\'/$1/;
1947 #print STDERR "SYM: $sym NAME: $name DESC: $desc\n";
1948 my $whitespacelen = length($name) + 8;
1949 my $whitespace = ' ' x $whitespacelen;
1950 $desc = wordwrap($desc, -$whitespacelen);
1951 my @desclines = split /\n/, $desc;
1952 my $firstline = shift @desclines;
1953 $str .= "$paramstr $name $firstline\n";
1954 foreach (@desclines) {
1955 $str .= "${whitespace}$_\n";
1956 }
1957 }
1958 } else {
1959 die("write me");
1960 }
1961 }
1962
1963 if (defined $returns) {
1964 $str .= "\n" if $addblank; $addblank = 1;
1965 my $r = dewikify($wikitype, $returns);
1966 $r =~ s/\A\(.*?\)\s*//; # Chop datatype in parentheses off the front.
1967 my $retstr = "\\returns";
1968 if ($r =~ s/\AReturn(s?)\s+//) {
1969 $retstr = "\\return$1";
1970 }
1971
1972 my $whitespacelen = length($retstr) + 1;
1973 my $whitespace = ' ' x $whitespacelen;
1974 $r = wordwrap($r, -$whitespacelen);
1975 my @desclines = split /\n/, $r;
1976 my $firstline = shift @desclines;
1977 $str .= "$retstr $firstline\n";
1978 foreach (@desclines) {
1979 $str .= "${whitespace}$_\n";
1980 }
1981 }
1982
1983 if (defined $threadsafety) {
1984 # !!! FIXME: lots of code duplication in all of these.
1985 $str .= "\n" if $addblank; $addblank = 1;
1986 my $v = dewikify($wikitype, $threadsafety);
1987 my $whitespacelen = length("\\threadsafety") + 1;
1988 my $whitespace = ' ' x $whitespacelen;
1989 $v = wordwrap($v, -$whitespacelen);
1990 my @desclines = split /\n/, $v;
1991 my $firstline = shift @desclines;
1992 $str .= "\\threadsafety $firstline\n";
1993 foreach (@desclines) {
1994 $str .= "${whitespace}$_\n";
1995 }
1996 }
1997
1998 if (defined $version) {
1999 # !!! FIXME: lots of code duplication in all of these.
2000 $str .= "\n" if $addblank; $addblank = 1;
2001 my $v = dewikify($wikitype, $version);
2002 my $whitespacelen = length("\\since") + 1;
2003 my $whitespace = ' ' x $whitespacelen;
2004 $v = wordwrap($v, -$whitespacelen);
2005 my @desclines = split /\n/, $v;
2006 my $firstline = shift @desclines;
2007 $str .= "\\since $firstline\n";
2008 foreach (@desclines) {
2009 $str .= "${whitespace}$_\n";
2010 }
2011 }
2012
2013 if (defined $related) {
2014 # !!! FIXME: lots of code duplication in all of these.
2015 $str .= "\n" if $addblank; $addblank = 1;
2016 my $v = dewikify($wikitype, $related);
2017 my @desclines = split /\n/, $v;
2018 foreach (@desclines) {
2019 s/\(\)\Z//; # Convert "SDL_Func()" to "SDL_Func"
2020 s/\[\[(.*?)\]\]/$1/; # in case some wikilinks remain.
2021 s/\[(.*?)\]\(.*?\)/$1/; # in case some wikilinks remain.
2022 s/\A\/*//;
2023 s/\A\s*[\:\*\-]\s*//;
2024 s/\A\s+//;
2025 s/\s+\Z//;
2026 $str .= "\\sa $_\n";
2027 }
2028 }
2029
2030 my $header = $headersymslocation{$sym};
2031 my $contentsref = $headers{$header};
2032 my $chunk = $headersymschunk{$sym};
2033
2034 my @lines = split /\n/, $str;
2035
2036 my $addnewline = (($chunk > 0) && ($$contentsref[$chunk-1] ne '')) ? "\n" : '';
2037
2038 my $output = "$addnewline/**\n";
2039 foreach (@lines) {
2040 chomp;
2041 s/\s*\Z//;
2042 if ($_ eq '') {
2043 $output .= " *\n";
2044 } else {
2045 $output .= " * $_\n";
2046 }
2047 }
2048 $output .= " */";
2049
2050 #print("$sym:\n[$output]\n\n");
2051
2052 $$contentsref[$chunk] = $output;
2053 #$$contentsref[$chunk+1] = $headerdecls{$sym};
2054
2055 $changed_headers{$header} = 1;
2056 }
2057
2058 foreach (keys %changed_headers) {
2059 my $header = $_;
2060
2061 # this is kinda inefficient, but oh well.
2062 my @removelines = ();
2063 foreach (keys %headersymslocation) {
2064 my $sym = $_;
2065 next if $headersymshasdoxygen{$sym};
2066 next if $headersymslocation{$sym} ne $header;
2067 # the index of the blank line we put before the function declaration in case we needed to replace it with new content from the wiki.
2068 push @removelines, $headersymschunk{$sym};
2069 }
2070
2071 my $contentsref = $headers{$header};
2072 foreach (@removelines) {
2073 delete $$contentsref[$_]; # delete DOES NOT RENUMBER existing elements!
2074 }
2075
2076 my $path = "$incpath/$header.tmp";
2077 open(FH, '>', $path) or die("Can't open '$path': $!\n");
2078 foreach (@$contentsref) {
2079 print FH "$_\n" if defined $_;
2080 }
2081 close(FH);
2082 rename($path, "$incpath/$header") or die("Can't rename '$path' to '$incpath/$header': $!\n");
2083 }
2084
2085 if (defined $readmepath) {
2086 if ( -d $wikireadmepath ) {
2087 mkdir($readmepath); # just in case
2088 opendir(DH, $wikireadmepath) or die("Can't opendir '$wikireadmepath': $!\n");
2089 while (readdir(DH)) {
2090 my $dent = $_;
2091 if ($dent =~ /\A(.*?)\.md\Z/) { # we only bridge Markdown files here.
2092 next if $1 eq 'FrontPage';
2093 filecopy("$wikireadmepath/$dent", "$readmepath/README-$dent", "\n");
2094 }
2095 }
2096 closedir(DH);
2097 }
2098 }
2099
2100} elsif ($copy_direction == -1) { # --copy-to-wiki
2101
2102 my %briefs = (); # $briefs{'SDL_OpenAudio'} -> the \brief string for the function.
2103
2104 if (defined $changeformat) {
2105 $dewikify_mode = $changeformat;
2106 $wordwrap_mode = $changeformat;
2107 }
2108
2109 foreach (keys %headersyms) {
2110 my $sym = $_;
2111 next if not $headersymshasdoxygen{$sym};
2112 next if $sym =~ /\A\[category documentation\]/; # not real symbols, we handle this elsewhere.
2113 my $symtype = $headersymstype{$sym};
2114 my $origwikitype = defined $wikitypes{$sym} ? $wikitypes{$sym} : 'md'; # default to MarkDown for new stuff.
2115 my $wikitype = (defined $changeformat) ? $changeformat : $origwikitype;
2116 die("Unexpected wikitype '$wikitype'") if (($wikitype ne 'mediawiki') and ($wikitype ne 'md') and ($wikitype ne 'manpage'));
2117
2118 #print("$sym\n"); next;
2119
2120 $wordwrap_mode = $wikitype;
2121
2122 my $raw = $headersyms{$sym}; # raw doxygen text with comment characters stripped from start/end and start of each line.
2123 next if not defined $raw;
2124 $raw =~ s/\A\s*\\brief\s+//; # Technically we don't need \brief (please turn on JAVADOC_AUTOBRIEF if you use Doxygen), so just in case one is present, strip it.
2125
2126 my @doxygenlines = split /\n/, $raw;
2127 my $brief = '';
2128 while (@doxygenlines) {
2129 last if $doxygenlines[0] =~ /\A\\/; # some sort of doxygen command, assume we're past the general remarks.
2130 last if $doxygenlines[0] =~ /\A\s*\Z/; # blank line? End of paragraph, done.
2131 my $l = shift @doxygenlines;
2132 chomp($l);
2133 $l =~ s/\A\s*//;
2134 $l =~ s/\s*\Z//;
2135 $brief .= "$l ";
2136 }
2137
2138 $brief =~ s/\s+\Z//;
2139 $brief =~ s/\A(.*?\.) /$1\n\n/; # \brief should only be one sentence, delimited by a period+space. Split if necessary.
2140 my @briefsplit = split /\n/, $brief;
2141
2142 next if not defined $briefsplit[0]; # No brief text? Probably a bogus Doxygen comment, skip it.
2143
2144 $brief = wikify($wikitype, shift @briefsplit) . "\n";
2145 @doxygenlines = (@briefsplit, @doxygenlines);
2146
2147 my $remarks = '';
2148 while (@doxygenlines) {
2149 last if $doxygenlines[0] =~ /\A\\/; # some sort of doxygen command, assume we're past the general remarks.
2150 my $l = shift @doxygenlines;
2151 $remarks .= "$l\n";
2152 }
2153
2154 #print("REMARKS:\n\n $remarks\n\n");
2155
2156 $remarks = wordwrap(wikify($wikitype, $remarks));
2157 $remarks =~ s/\A\s*//;
2158 $remarks =~ s/\s*\Z//;
2159
2160 my $decl = $headerdecls{$sym};
2161
2162 my $syntax = '';
2163 if ($wikitype eq 'mediawiki') {
2164 $syntax = "<syntaxhighlight lang='c'>\n$decl</syntaxhighlight>\n";
2165 } elsif ($wikitype eq 'md') {
2166 $decl =~ s/\n+\Z//;
2167 $syntax = "```c\n$decl\n```\n";
2168 } else { die("Expected wikitype '$wikitype'"); }
2169
2170 my %sections = ();
2171 $sections{'[Brief]'} = $brief; # include this section even if blank so we get a title line.
2172 $sections{'Remarks'} = "$remarks\n" if $remarks ne '';
2173 $sections{'Syntax'} = $syntax;
2174
2175 $briefs{$sym} = $brief;
2176
2177 my %params = (); # have to parse these and build up the wiki tables after, since Markdown needs to know the length of the largest string. :/
2178 my @paramsorder = ();
2179 my $fnsigparams = $headersymsparaminfo{$sym};
2180 my $has_returns = 0;
2181 my $has_threadsafety = 0;
2182
2183 while (@doxygenlines) {
2184 my $l = shift @doxygenlines;
2185 # We allow param/field/value interchangeably, even if it doesn't make sense. The next --copy-to-headers will correct it anyhow.
2186 if ($l =~ /\A\\(param|field|value)\s+(.*?)\s+(.*)\Z/) {
2187 my $arg = $2;
2188 my $desc = $3;
2189 while (@doxygenlines) {
2190 my $subline = $doxygenlines[0];
2191 $subline =~ s/\A\s*//;
2192 last if $subline =~ /\A\\/; # some sort of doxygen command, assume we're past this thing.
2193 shift @doxygenlines; # dump this line from the array; we're using it.
2194 if ($subline eq '') { # empty line, make sure it keeps the newline char.
2195 $desc .= "\n";
2196 } else {
2197 $desc .= " $subline";
2198 }
2199 }
2200
2201 $desc =~ s/[\s\n]+\Z//ms;
2202
2203 if (0) { # !!! FIXME: disabled because it's not currently suitable for general use, but for manually inspecting the output, it can be useful.
2204 if (($desc =~ /\A[A-Z]/) && (not $desc =~ /\ASDL_/)) {
2205 print STDERR "WARNING: $sym\'s '\\param $arg' text starts with a capital letter: '$desc'. Fixing.\n";
2206 $desc = lcfirst($desc);
2207 }
2208 }
2209
2210 if (not $desc =~ /[\.\!]\Z/) {
2211 print STDERR "WARNING: $sym\'s '\\param $arg' text doesn't end with punctuation: '$desc'. Fixing.\n";
2212 $desc .= '.';
2213 }
2214
2215 # Validate this param.
2216 if (defined($params{$arg})) {
2217 print STDERR "WARNING: Symbol '$sym' has multiple '\\param $arg' declarations! Only keeping the first one!\n";
2218 } elsif (defined $fnsigparams) {
2219 my $found = 0;
2220 for (my $i = 0; $i < scalar(@$fnsigparams); $i += 2) {
2221 $found = 1, last if (@$fnsigparams[$i] eq $arg);
2222 }
2223 if (!$found) {
2224 print STDERR "WARNING: Symbol '$sym' has a '\\param $arg' for a param that doesn't exist. It will be removed!\n";
2225 }
2226 }
2227
2228 # We need to know the length of the longest string to make Markdown tables, so we just store these off until everything is parsed.
2229 $params{$arg} = $desc;
2230 push @paramsorder, $arg;
2231 } elsif ($l =~ /\A\\r(eturns?)\s+(.*)\Z/) {
2232 $has_returns = 1;
2233 # !!! FIXME: complain if this isn't a function or macro.
2234 my $retstr = "R$1"; # "Return" or "Returns"
2235 my $desc = $2;
2236
2237 while (@doxygenlines) {
2238 my $subline = $doxygenlines[0];
2239 $subline =~ s/\A\s*//;
2240 last if $subline =~ /\A\\/; # some sort of doxygen command, assume we're past this thing.
2241 shift @doxygenlines; # dump this line from the array; we're using it.
2242 if ($subline eq '') { # empty line, make sure it keeps the newline char.
2243 $desc .= "\n";
2244 } else {
2245 $desc .= " $subline";
2246 }
2247 }
2248 $desc =~ s/[\s\n]+\Z//ms;
2249
2250 if (0) { # !!! FIXME: disabled because it's not currently suitable for general use, but for manually inspecting the output, it can be useful.
2251 if (($desc =~ /\A[A-Z]/) && (not $desc =~ /\ASDL_/)) {
2252 print STDERR "WARNING: $sym\'s '\\returns' text starts with a capital letter: '$desc'. Fixing.\n";
2253 $desc = lcfirst($desc);
2254 }
2255 }
2256
2257 if (not $desc =~ /[\.\!]\Z/) {
2258 print STDERR "WARNING: $sym\'s '\\returns' text doesn't end with punctuation: '$desc'. Fixing.\n";
2259 $desc .= '.';
2260 }
2261
2262 # Make sure the \returns info is valid.
2263 my $rettype = $headersymsrettype{$sym};
2264 die("Don't have a rettype for '$sym' for some reason!") if (($symtype == 1) && (not defined($rettype)));
2265 if (defined($sections{'Return Value'})) {
2266 print STDERR "WARNING: Symbol '$sym' has multiple '\\return' declarations! Only keeping the first one!\n";
2267 } elsif (($symtype != 1) && ($symtype != 2) && ($symtype != 5)) { # !!! FIXME: if 5, make sure it's a function pointer typedef!
2268 print STDERR "WARNING: Symbol '$sym' has a '\\return' declaration but isn't a function or macro! Removing it!\n";
2269 } elsif (($symtype == 1) && ($headersymsrettype{$sym} eq 'void')) {
2270 print STDERR "WARNING: Function '$sym' has a '\\returns' declaration but function returns void! Removing it!\n";
2271 } else {
2272 my $rettypestr = defined($rettype) ? ('(' . wikify($wikitype, $rettype) . ') ') : '';
2273 $sections{'Return Value'} = wordwrap("$rettypestr$retstr ". wikify($wikitype, $desc)) . "\n";
2274 }
2275 } elsif ($l =~ /\A\\deprecated\s+(.*)\Z/) {
2276 my $desc = $1;
2277 while (@doxygenlines) {
2278 my $subline = $doxygenlines[0];
2279 $subline =~ s/\A\s*//;
2280 last if $subline =~ /\A\\/; # some sort of doxygen command, assume we're past this thing.
2281 shift @doxygenlines; # dump this line from the array; we're using it.
2282 if ($subline eq '') { # empty line, make sure it keeps the newline char.
2283 $desc .= "\n";
2284 } else {
2285 $desc .= " $subline";
2286 }
2287 }
2288 $desc =~ s/[\s\n]+\Z//ms;
2289 $sections{'Deprecated'} = wordwrap(wikify($wikitype, $desc)) . "\n";
2290 } elsif ($l =~ /\A\\since\s+(.*)\Z/) {
2291 my $desc = $1;
2292 while (@doxygenlines) {
2293 my $subline = $doxygenlines[0];
2294 $subline =~ s/\A\s*//;
2295 last if $subline =~ /\A\\/; # some sort of doxygen command, assume we're past this thing.
2296 shift @doxygenlines; # dump this line from the array; we're using it.
2297 if ($subline eq '') { # empty line, make sure it keeps the newline char.
2298 $desc .= "\n";
2299 } else {
2300 $desc .= " $subline";
2301 }
2302 }
2303 $desc =~ s/[\s\n]+\Z//ms;
2304 $sections{'Version'} = wordwrap(wikify($wikitype, $desc)) . "\n";
2305 } elsif ($l =~ /\A\\threadsafety\s+(.*)\Z/) {
2306 my $desc = $1;
2307 while (@doxygenlines) {
2308 my $subline = $doxygenlines[0];
2309 $subline =~ s/\A\s*//;
2310 last if $subline =~ /\A\\/; # some sort of doxygen command, assume we're past this thing.
2311 shift @doxygenlines; # dump this line from the array; we're using it.
2312 if ($subline eq '') { # empty line, make sure it keeps the newline char.
2313 $desc .= "\n";
2314 } else {
2315 $desc .= " $subline";
2316 }
2317 }
2318 $desc =~ s/[\s\n]+\Z//ms;
2319 $sections{'Thread Safety'} = wordwrap(wikify($wikitype, $desc)) . "\n";
2320 $has_threadsafety = 1;
2321 } elsif ($l =~ /\A\\sa\s+(.*)\Z/) {
2322 my $sa = $1;
2323 $sa =~ s/\(\)\Z//; # Convert "SDL_Func()" to "SDL_Func"
2324 $sections{'See Also'} = '' if not defined $sections{'See Also'};
2325 if ($wikitype eq 'mediawiki') {
2326 $sections{'See Also'} .= ":[[$sa]]\n";
2327 } elsif ($wikitype eq 'md') {
2328 $sections{'See Also'} .= "- [$sa]($sa)\n";
2329 } else { die("Expected wikitype '$wikitype'"); }
2330 }
2331 }
2332
2333 if (($symtype == 1) && ($headersymsrettype{$sym} ne 'void') && !$has_returns) {
2334 print STDERR "WARNING: Function '$sym' has a non-void return type but no '\\returns' declaration\n";
2335 }
2336
2337 # !!! FIXME: uncomment this when we're trying to clean this up in the headers.
2338 #if (($symtype == 1) && !$has_threadsafety) {
2339 # print STDERR "WARNING: Function '$sym' doesn't have a '\\threadsafety' declaration\n";
2340 #}
2341
2342 # Make sure %params is in the same order as the actual function signature and add C datatypes...
2343 my $params_has_c_datatype = 0;
2344 my @final_params = ();
2345 if (($symtype == 1) && (defined($headersymsparaminfo{$sym}))) { # is a function and we have param info for it...
2346 my $fnsigparams = $headersymsparaminfo{$sym};
2347 for (my $i = 0; $i < scalar(@$fnsigparams); $i += 2) {
2348 my $paramname = @$fnsigparams[$i];
2349 my $paramdesc = $params{$paramname};
2350 if (defined($paramdesc)) {
2351 push @final_params, $paramname; # name
2352 push @final_params, @$fnsigparams[$i+1]; # C datatype
2353 push @final_params, $paramdesc; # description
2354 $params_has_c_datatype = 1 if (defined(@$fnsigparams[$i+1]));
2355 } else {
2356 print STDERR "WARNING: Symbol '$sym' is missing a '\\param $paramname' declaration!\n";
2357 }
2358 }
2359 } else {
2360 foreach (@paramsorder) {
2361 my $paramname = $_;
2362 my $paramdesc = $params{$paramname};
2363 if (defined($paramdesc)) {
2364 push @final_params, $_;
2365 push @final_params, undef;
2366 push @final_params, $paramdesc;
2367 }
2368 }
2369 }
2370
2371 my $hfiletext = $wikiheaderfiletext;
2372 $hfiletext =~ s/\%fname\%/$headersymslocation{$sym}/g;
2373 $sections{'Header File'} = "$hfiletext\n";
2374
2375 # Make sure this ends with a double-newline.
2376 $sections{'See Also'} .= "\n" if defined $sections{'See Also'};
2377
2378 if (0) { # !!! FIXME: this was a useful hack, but this needs to be generalized if we're going to do this always.
2379 # Plug in a \since section if one wasn't listed.
2380 if (not defined $sections{'Version'}) {
2381 my $symtypename;
2382 if ($symtype == 1) {
2383 $symtypename = 'function';
2384 } elsif ($symtype == 2) {
2385 $symtypename = 'macro';
2386 } elsif ($symtype == 3) {
2387 $symtypename = 'struct';
2388 } elsif ($symtype == 4) {
2389 $symtypename = 'enum';
2390 } elsif ($symtype == 5) {
2391 $symtypename = 'datatype';
2392 } else {
2393 die("Unexpected symbol type $symtype!");
2394 }
2395 my $str = "This $symtypename is available since SDL 3.0.0.";
2396 $sections{'Version'} = wordwrap(wikify($wikitype, $str)) . "\n";
2397 }
2398 }
2399
2400 # We can build the wiki table now that we have all the data.
2401 if (scalar(@final_params) > 0) {
2402 my $str = '';
2403 if ($wikitype eq 'mediawiki') {
2404 while (scalar(@final_params) > 0) {
2405 my $arg = shift @final_params;
2406 my $c_datatype = shift @final_params;
2407 my $desc = wikify($wikitype, shift @final_params);
2408 $c_datatype = '' if not defined $c_datatype;
2409 $str .= ($str eq '') ? "{|\n" : "|-\n";
2410 $str .= "|$c_datatype\n" if $params_has_c_datatype;
2411 $str .= "|'''$arg'''\n";
2412 $str .= "|$desc\n";
2413 }
2414 $str .= "|}\n";
2415 } elsif ($wikitype eq 'md') {
2416 my $longest_arg = 0;
2417 my $longest_c_datatype = 0;
2418 my $longest_desc = 0;
2419 my $which = 0;
2420 foreach (@final_params) {
2421 if ($which == 0) {
2422 my $len = length($_);
2423 $longest_arg = $len if ($len > $longest_arg);
2424 $which = 1;
2425 } elsif ($which == 1) {
2426 if (defined($_)) {
2427 my $len = length(wikify($wikitype, $_));
2428 $longest_c_datatype = $len if ($len > $longest_c_datatype);
2429 }
2430 $which = 2;
2431 } else {
2432 my $len = length(wikify($wikitype, $_));
2433 $longest_desc = $len if ($len > $longest_desc);
2434 $which = 0;
2435 }
2436 }
2437
2438 # Markdown tables are sort of obnoxious.
2439 my $c_datatype_cell;
2440 $c_datatype_cell = ($longest_c_datatype > 0) ? ('| ' . (' ' x ($longest_c_datatype)) . ' ') : '';
2441 $str .= $c_datatype_cell . '| ' . (' ' x ($longest_arg+4)) . ' | ' . (' ' x $longest_desc) . " |\n";
2442 $c_datatype_cell = ($longest_c_datatype > 0) ? ('| ' . ('-' x ($longest_c_datatype)) . ' ') : '';
2443 $str .= $c_datatype_cell . '| ' . ('-' x ($longest_arg+4)) . ' | ' . ('-' x $longest_desc) . " |\n";
2444
2445 while (@final_params) {
2446 my $arg = shift @final_params;
2447 my $c_datatype = shift @final_params;
2448 $c_datatype_cell = '';
2449 if ($params_has_c_datatype) {
2450 $c_datatype = defined($c_datatype) ? wikify($wikitype, $c_datatype) : '';
2451 $c_datatype_cell = ($longest_c_datatype > 0) ? ("| $c_datatype " . (' ' x ($longest_c_datatype - length($c_datatype)))) : '';
2452 }
2453 my $desc = wikify($wikitype, shift @final_params);
2454 $str .= $c_datatype_cell . "| **$arg** " . (' ' x ($longest_arg - length($arg))) . "| $desc" . (' ' x ($longest_desc - length($desc))) . " |\n";
2455 }
2456 } else {
2457 die("Unexpected wikitype!"); # should have checked this elsewhere.
2458 }
2459 $sections{'Function Parameters'} = $str;
2460 }
2461
2462 my $path = "$wikipath/$sym.${wikitype}.tmp";
2463 open(FH, '>', $path) or die("Can't open '$path': $!\n");
2464
2465 my $sectionsref = $wikisyms{$sym};
2466
2467 foreach (@standard_wiki_sections) {
2468 # drop sections we either replaced or removed from the original wiki's contents.
2469 if (not defined $only_wiki_sections{$_}) {
2470 delete($$sectionsref{$_});
2471 }
2472 }
2473
2474 my $wikisectionorderref = $wikisectionorder{$sym};
2475
2476 # Make sure there's a footer in the wiki that puts this function in CategoryAPI...
2477 if (not $$sectionsref{'[footer]'}) {
2478 $$sectionsref{'[footer]'} = '';
2479 push @$wikisectionorderref, '[footer]';
2480 }
2481
2482 # If changing format, convert things that otherwise are passed through unmolested.
2483 if (defined $changeformat) {
2484 if (($dewikify_mode eq 'md') and ($origwikitype eq 'mediawiki')) {
2485 $$sectionsref{'[footer]'} =~ s/\[\[(Category[a-zA-Z0-9_]+)\]\]/[$1]($1)/g;
2486 } elsif (($dewikify_mode eq 'mediawiki') and ($origwikitype eq 'md')) {
2487 $$sectionsref{'[footer]'} =~ s/\[(Category[a-zA-Z0-9_]+)\]\(.*?\)/[[$1]]/g;
2488 }
2489
2490 foreach (keys %only_wiki_sections) {
2491 my $sect = $_;
2492 if (defined $$sectionsref{$sect}) {
2493 $$sectionsref{$sect} = wikify($wikitype, dewikify($origwikitype, $$sectionsref{$sect}));
2494 }
2495 }
2496 }
2497
2498 if ($symtype != -1) { # Don't do these in category documentation block
2499 my $footer = $$sectionsref{'[footer]'};
2500
2501 my $symtypename;
2502 if ($symtype == 1) {
2503 $symtypename = 'Function';
2504 } elsif ($symtype == 2) {
2505 $symtypename = 'Macro';
2506 } elsif ($symtype == 3) {
2507 $symtypename = 'Struct';
2508 } elsif ($symtype == 4) {
2509 $symtypename = 'Enum';
2510 } elsif ($symtype == 5) {
2511 $symtypename = 'Datatype';
2512 } else {
2513 die("Unexpected symbol type $symtype!");
2514 }
2515
2516 my $symcategory = $headersymscategory{$sym};
2517 if ($wikitype eq 'mediawiki') {
2518 $footer =~ s/\[\[CategoryAPI\]\],?\s*//g;
2519 $footer =~ s/\[\[CategoryAPI${symtypename}\]\],?\s*//g;
2520 $footer =~ s/\[\[Category${symcategory}\]\],?\s*//g if defined $symcategory;
2521 $footer = "[[CategoryAPI]], [[CategoryAPI$symtypename]]" . (defined $symcategory ? ", [[Category$symcategory]]" : '') . (($footer eq '') ? "\n" : ", $footer");
2522 } elsif ($wikitype eq 'md') {
2523 $footer =~ s/\[CategoryAPI\]\(CategoryAPI\),?\s*//g;
2524 $footer =~ s/\[CategoryAPI${symtypename}\]\(CategoryAPI${symtypename}\),?\s*//g;
2525 $footer =~ s/\[Category${symcategory}\]\(Category${symcategory}\),?\s*//g if defined $symcategory;
2526 $footer = "[CategoryAPI](CategoryAPI), [CategoryAPI$symtypename](CategoryAPI$symtypename)" . (defined $symcategory ? ", [Category$symcategory](Category$symcategory)" : '') . (($footer eq '') ? '' : ', ') . $footer;
2527 } else { die("Unexpected wikitype '$wikitype'"); }
2528 $$sectionsref{'[footer]'} = $footer;
2529
2530 if (defined $wikipreamble) {
2531 my $wikified_preamble = wikify($wikitype, $wikipreamble);
2532 if ($wikitype eq 'mediawiki') {
2533 print FH "====== $wikified_preamble ======\n";
2534 } elsif ($wikitype eq 'md') {
2535 print FH "###### $wikified_preamble\n";
2536 } else { die("Unexpected wikitype '$wikitype'"); }
2537 }
2538 }
2539
2540 my $prevsectstr = '';
2541 my @ordered_sections = (@standard_wiki_sections, defined $wikisectionorderref ? @$wikisectionorderref : ()); # this copies the arrays into one.
2542 foreach (@ordered_sections) {
2543 my $sect = $_;
2544 next if $sect eq '[start]';
2545 next if (not defined $sections{$sect} and not defined $$sectionsref{$sect});
2546 my $section = defined $sections{$sect} ? $sections{$sect} : $$sectionsref{$sect};
2547
2548 if ($sect eq '[footer]') {
2549 # Make sure previous section ends with two newlines.
2550 if (substr($prevsectstr, -1) ne "\n") {
2551 print FH "\n\n";
2552 } elsif (substr($prevsectstr, -2) ne "\n\n") {
2553 print FH "\n";
2554 }
2555 print FH "----\n"; # It's the same in Markdown and MediaWiki.
2556 } elsif ($sect eq '[Brief]') {
2557 if ($wikitype eq 'mediawiki') {
2558 print FH "= $sym =\n\n";
2559 } elsif ($wikitype eq 'md') {
2560 print FH "# $sym\n\n";
2561 } else { die("Unexpected wikitype '$wikitype'"); }
2562 } else {
2563 my $sectname = $sect;
2564 if ($sectname eq 'Function Parameters') { # We use this same table for different things depending on what we're documenting, so rename it now.
2565 if (($symtype == 1) || ($symtype == 5)) { # function (or typedef, in case it's a function pointer type).
2566 } elsif ($symtype == 2) { # macro
2567 $sectname = 'Macro Parameters';
2568 } elsif ($symtype == 3) { # struct/union
2569 $sectname = 'Fields';
2570 } elsif ($symtype == 4) { # enum
2571 $sectname = 'Values';
2572 } else {
2573 die("Unexpected symtype $symtype");
2574 }
2575 }
2576
2577 if ($symtype != -1) { # Not for category documentation block
2578 if ($wikitype eq 'mediawiki') {
2579 print FH "\n== $sectname ==\n\n";
2580 } elsif ($wikitype eq 'md') {
2581 print FH "\n## $sectname\n\n";
2582 } else { die("Unexpected wikitype '$wikitype'"); }
2583 }
2584 }
2585
2586 my $sectstr = defined $sections{$sect} ? $sections{$sect} : $$sectionsref{$sect};
2587 print FH $sectstr;
2588
2589 $prevsectstr = $sectstr;
2590
2591 # make sure these don't show up twice.
2592 delete($sections{$sect});
2593 delete($$sectionsref{$sect});
2594 }
2595
2596 print FH "\n\n";
2597 close(FH);
2598
2599 if (defined $changeformat and ($origwikitype ne $wikitype)) {
2600 system("cd '$wikipath' ; git mv '$_.${origwikitype}' '$_.${wikitype}'");
2601 unlink("$wikipath/$_.${origwikitype}");
2602 }
2603
2604 rename($path, "$wikipath/$_.${wikitype}") or die("Can't rename '$path' to '$wikipath/$_.${wikitype}': $!\n");
2605 }
2606
2607 # Write out simple redirector pages if they don't already exist.
2608 foreach (keys %referenceonly) {
2609 my $sym = $_;
2610 my $refersto = $referenceonly{$sym};
2611 my $path = "$wikipath/$sym.md"; # we only do Markdown for these.
2612 next if (-f $path); # don't overwrite if it already exists. Delete the file if you need a rebuild!
2613 open(FH, '>', $path) or die("Can't open '$path': $!\n");
2614
2615 if (defined $wikipreamble) {
2616 my $wikified_preamble = wikify('md', $wikipreamble);
2617 print FH "###### $wikified_preamble\n";
2618 }
2619
2620 my $category = 'CategoryAPIMacro';
2621 if ($headersymstype{$refersto} == 4) {
2622 $category = 'CategoryAPIEnumerators'; # NOT CategoryAPIEnum!
2623 }
2624
2625 print FH "# $sym\n\nPlease refer to [$refersto]($refersto) for details.\n\n";
2626 print FH "----\n";
2627 print FH "[CategoryAPI](CategoryAPI), [$category]($category)\n\n";
2628
2629 close(FH);
2630 }
2631
2632 # Write out Category pages...
2633 foreach (keys %headercategorydocs) {
2634 my $cat = $_;
2635 my $sym = $headercategorydocs{$cat}; # fake symbol
2636 my $raw = $headersyms{$sym}; # raw doxygen text with comment characters stripped from start/end and start of each line.
2637 my $wikitype = defined($wikitypes{$sym}) ? $wikitypes{$sym} : 'md';
2638 my $path = "$wikipath/Category$cat.$wikitype";
2639
2640 $raw = wordwrap(wikify($wikitype, $raw));
2641
2642 my $tmppath = "$path.tmp";
2643 open(FH, '>', $tmppath) or die("Can't open '$tmppath': $!\n");
2644 print FH "$raw\n\n";
2645
2646 if (! -f $path) { # Doesn't exist at all? Write out a template file.
2647 # If writing from scratch, it's always a Markdown file.
2648 die("Unexpected wikitype '$wikitype'!") if $wikitype ne 'md';
2649 print FH <<__EOF__
2650
2651<!-- END CATEGORY DOCUMENTATION -->
2652
2653## Functions
2654
2655<!-- DO NOT HAND-EDIT CATEGORY LISTS, THEY ARE AUTOGENERATED AND WILL BE OVERWRITTEN, BASED ON TAGS IN INDIVIDUAL PAGE FOOTERS. EDIT THOSE INSTEAD. -->
2656<!-- BEGIN CATEGORY LIST: Category$cat, CategoryAPIFunction -->
2657<!-- END CATEGORY LIST -->
2658
2659## Datatypes
2660
2661<!-- DO NOT HAND-EDIT CATEGORY LISTS, THEY ARE AUTOGENERATED AND WILL BE OVERWRITTEN, BASED ON TAGS IN INDIVIDUAL PAGE FOOTERS. EDIT THOSE INSTEAD. -->
2662<!-- BEGIN CATEGORY LIST: Category$cat, CategoryAPIDatatype -->
2663<!-- END CATEGORY LIST -->
2664
2665## Structs
2666
2667<!-- DO NOT HAND-EDIT CATEGORY LISTS, THEY ARE AUTOGENERATED AND WILL BE OVERWRITTEN, BASED ON TAGS IN INDIVIDUAL PAGE FOOTERS. EDIT THOSE INSTEAD. -->
2668<!-- BEGIN CATEGORY LIST: Category$cat, CategoryAPIStruct -->
2669<!-- END CATEGORY LIST -->
2670
2671## Enums
2672
2673<!-- DO NOT HAND-EDIT CATEGORY LISTS, THEY ARE AUTOGENERATED AND WILL BE OVERWRITTEN, BASED ON TAGS IN INDIVIDUAL PAGE FOOTERS. EDIT THOSE INSTEAD. -->
2674<!-- BEGIN CATEGORY LIST: Category$cat, CategoryAPIEnum -->
2675<!-- END CATEGORY LIST -->
2676
2677## Macros
2678
2679<!-- DO NOT HAND-EDIT CATEGORY LISTS, THEY ARE AUTOGENERATED AND WILL BE OVERWRITTEN, BASED ON TAGS IN INDIVIDUAL PAGE FOOTERS. EDIT THOSE INSTEAD. -->
2680<!-- BEGIN CATEGORY LIST: Category$cat, CategoryAPIMacro -->
2681<!-- END CATEGORY LIST -->
2682
2683----
2684[CategoryAPICategory](CategoryAPICategory)
2685
2686__EOF__
2687;
2688 } else {
2689 my $endstr = $wikisyms{$sym}->{'[footer]'};
2690 if (defined($endstr)) {
2691 print FH $endstr;
2692 }
2693 }
2694
2695 close(FH);
2696 rename($tmppath, $path) or die("Can't rename '$tmppath' to '$path': $!\n");
2697 }
2698
2699 # Write out READMEs...
2700 if (defined $readmepath) {
2701 if ( -d $readmepath ) {
2702 mkdir($wikireadmepath); # just in case
2703 opendir(DH, $readmepath) or die("Can't opendir '$readmepath': $!\n");
2704 while (my $d = readdir(DH)) {
2705 my $dent = $d;
2706 if ($dent =~ /\AREADME\-(.*?\.md)\Z/) { # we only bridge Markdown files here.
2707 my $wikifname = $1;
2708 next if $wikifname eq 'FrontPage.md';
2709 filecopy("$readmepath/$dent", "$wikireadmepath/$wikifname", "\n");
2710 }
2711 }
2712 closedir(DH);
2713
2714 my @pages = ();
2715 opendir(DH, $wikireadmepath) or die("Can't opendir '$wikireadmepath': $!\n");
2716 while (my $d = readdir(DH)) {
2717 my $dent = $d;
2718 if ($dent =~ /\A(.*?)\.(mediawiki|md)\Z/) {
2719 my $wikiname = $1;
2720 next if $wikiname eq 'FrontPage';
2721 push @pages, $wikiname;
2722 }
2723 }
2724 closedir(DH);
2725
2726 open(FH, '>', "$wikireadmepath/FrontPage.md") or die("Can't open '$wikireadmepath/FrontPage.md': $!\n");
2727 print FH "# All READMEs available here\n\n";
2728 foreach (sort @pages) {
2729 my $wikiname = $_;
2730 print FH "- [$wikiname]($wikiname)\n";
2731 }
2732 close(FH);
2733 }
2734 }
2735
2736 # Write out quick reference pages...
2737 if ($quickrefenabled) {
2738 generate_quickref(\%briefs, "$wikipath/QuickReference.md", 0);
2739 generate_quickref(\%briefs, "$wikipath/QuickReferenceNoUnicode.md", 1);
2740 }
2741} elsif ($copy_direction == -2) { # --copy-to-manpages
2742 # This only takes from the wiki data, since it has sections we omit from the headers, like code examples.
2743
2744 File::Path::make_path("$manpath/man3");
2745
2746 $dewikify_mode = 'manpage';
2747 $wordwrap_mode = 'manpage';
2748
2749 my $introtxt = '';
2750 if (0) {
2751 open(FH, '<', "$srcpath/LICENSE.txt") or die("Can't open '$srcpath/LICENSE.txt': $!\n");
2752 while (<FH>) {
2753 chomp;
2754 $introtxt .= ".\\\" $_\n";
2755 }
2756 close(FH);
2757 }
2758
2759 if (!$gitrev) {
2760 $gitrev = `cd "$srcpath" ; git rev-list HEAD~..`;
2761 chomp($gitrev);
2762 }
2763
2764 # !!! FIXME
2765 open(FH, '<', "$srcpath/$versionfname") or die("Can't open '$srcpath/$versionfname': $!\n");
2766 my $majorver = 0;
2767 my $minorver = 0;
2768 my $microver = 0;
2769 while (<FH>) {
2770 chomp;
2771 if (/$versionmajorregex/) {
2772 $majorver = int($1);
2773 } elsif (/$versionminorregex/) {
2774 $minorver = int($1);
2775 } elsif (/$versionmicroregex/) {
2776 $microver = int($1);
2777 }
2778 }
2779 close(FH);
2780 my $fullversion = "$majorver.$minorver.$microver";
2781
2782 foreach (keys %headersyms) {
2783 my $sym = $_;
2784 next if not defined $wikisyms{$sym}; # don't have a page for that function, skip it.
2785 next if $sym =~ /\A\[category documentation\]/; # not real symbols
2786 next if (defined $manpagesymbolfilterregex) && ($sym =~ /$manpagesymbolfilterregex/);
2787 my $symtype = $headersymstype{$sym};
2788 my $wikitype = $wikitypes{$sym};
2789 my $sectionsref = $wikisyms{$sym};
2790 my $remarks = $sectionsref->{'Remarks'};
2791 my $returns = $sectionsref->{'Return Value'};
2792 my $version = $sectionsref->{'Version'};
2793 my $threadsafety = $sectionsref->{'Thread Safety'};
2794 my $related = $sectionsref->{'See Also'};
2795 my $examples = $sectionsref->{'Code Examples'};
2796 my $deprecated = $sectionsref->{'Deprecated'};
2797 my $headerfile = $manpageheaderfiletext;
2798
2799 my $params = undef;
2800
2801 if ($symtype == -1) { # category documentation block.
2802 # nothing to be done here.
2803 } elsif (($symtype == 1) || (($symtype == 5))) { # we'll assume a typedef (5) with a \param is a function pointer typedef.
2804 $params = $sectionsref->{'Function Parameters'};
2805 } elsif ($symtype == 2) {
2806 $params = $sectionsref->{'Macro Parameters'};
2807 } elsif ($symtype == 3) {
2808 $params = $sectionsref->{'Fields'};
2809 } elsif ($symtype == 4) {
2810 $params = $sectionsref->{'Values'};
2811 } else {
2812 die("Unexpected symtype $symtype");
2813 }
2814
2815 $headerfile =~ s/\%fname\%/$headersymslocation{$sym}/g;
2816 $headerfile .= "\n";
2817
2818 my $mansection;
2819 my $mansectionname;
2820 if (($symtype == 1) || ($symtype == 2)) { # functions or macros
2821 $mansection = '3';
2822 $mansectionname = 'FUNCTIONS';
2823 } elsif (($symtype >= 3) && ($symtype <= 5)) { # struct/union/enum/typedef
2824 $mansection = '3type';
2825 $mansectionname = 'DATATYPES';
2826 } else {
2827 die("Unexpected symtype $symtype");
2828 }
2829
2830 my $brief = $sectionsref->{'[Brief]'};
2831 my $decl = $headerdecls{$sym};
2832 my $str = '';
2833
2834 # the "$brief" makes sure this is a copy of the string, which is doing some weird reference thing otherwise.
2835 $brief = defined $brief ? "$brief" : '';
2836 $brief =~ s/\A[\s\n]*\= .*? \=\s*?\n+//ms;
2837 $brief =~ s/\A[\s\n]*\=\= .*? \=\=\s*?\n+//ms;
2838 $brief =~ s/\A(.*?\.) /$1\n/; # \brief should only be one sentence, delimited by a period+space. Split if necessary.
2839 my @briefsplit = split /\n/, $brief;
2840 $brief = shift @briefsplit;
2841 $brief = dewikify($wikitype, $brief);
2842
2843 if (defined $remarks) {
2844 $remarks = dewikify($wikitype, join("\n", @briefsplit) . $remarks);
2845 }
2846
2847 $str .= $introtxt;
2848
2849 $str .= ".\\\" This manpage content is licensed under Creative Commons\n";
2850 $str .= ".\\\" Attribution 4.0 International (CC BY 4.0)\n";
2851 $str .= ".\\\" https://creativecommons.org/licenses/by/4.0/\n";
2852 $str .= ".\\\" This manpage was generated from ${projectshortname}'s wiki page for $sym:\n";
2853 $str .= ".\\\" $wikiurl/$sym\n";
2854 $str .= ".\\\" Generated with SDL/build-scripts/wikiheaders.pl\n";
2855 $str .= ".\\\" revision $gitrev\n" if $gitrev ne '';
2856 $str .= ".\\\" Please report issues in this manpage's content at:\n";
2857 $str .= ".\\\" $bugreporturl\n";
2858 $str .= ".\\\" Please report issues in the generation of this manpage from the wiki at:\n";
2859 $str .= ".\\\" https://github.com/libsdl-org/SDL/issues/new?title=Misgenerated%20manpage%20for%20$sym\n";
2860 $str .= ".\\\" $projectshortname can be found at $projecturl\n";
2861
2862 # Define a .URL macro. The "www.tmac" thing decides if we're using GNU roff (which has a .URL macro already), and if so, overrides the macro we just created.
2863 # This wizadry is from https://web.archive.org/web/20060102165607/http://people.debian.org/~branden/talks/wtfm/wtfm.pdf
2864 $str .= ".de URL\n";
2865 $str .= '\\$2 \(laURL: \\$1 \(ra\\$3' . "\n";
2866 $str .= "..\n";
2867 $str .= '.if \n[.g] .mso www.tmac' . "\n";
2868
2869 $str .= ".TH $sym $mansection \"$projectshortname $fullversion\" \"$projectfullname\" \"$projectshortname$majorver $mansectionname\"\n";
2870 $str .= ".SH NAME\n";
2871
2872 $str .= "$sym";
2873 $str .= " \\- $brief" if (defined $brief);
2874 $str .= "\n";
2875
2876 if (defined $deprecated) {
2877 $str .= ".SH DEPRECATED\n";
2878 $str .= dewikify($wikitype, $deprecated) . "\n";
2879 }
2880
2881 my $incfile = $mainincludefname;
2882 if (defined $headerfile) {
2883 if($headerfile =~ /Defined in (.*)/) {
2884 $incfile = $1;
2885 }
2886 }
2887
2888 $str .= ".SH SYNOPSIS\n";
2889 $str .= ".nf\n";
2890 $str .= ".B #include <$incfile>\n";
2891 $str .= ".PP\n";
2892
2893 my @decllines = split /\n/, $decl;
2894 foreach (@decllines) {
2895 $_ =~ s/\\/\\(rs/g; # fix multiline macro defs
2896 $_ =~ s/"/\\(dq/g;
2897 $str .= ".BI \"$_\n";
2898 }
2899 $str .= ".fi\n";
2900
2901 if (defined $remarks) {
2902 $str .= ".SH DESCRIPTION\n";
2903 $str .= $remarks . "\n";
2904 }
2905
2906 if (defined $params) {
2907 if (($symtype == 1) || ($symtype == 5)) {
2908 $str .= ".SH FUNCTION PARAMETERS\n";
2909 } elsif ($symtype == 2) { # macro
2910 $str .= ".SH MACRO PARAMETERS\n";
2911 } elsif ($symtype == 3) { # struct/union
2912 $str .= ".SH FIELDS\n";
2913 } elsif ($symtype == 4) { # enum
2914 $str .= ".SH VALUES\n";
2915 } else {
2916 die("Unexpected symtype $symtype");
2917 }
2918
2919 my @lines = split /\n/, $params;
2920 if ($wikitype eq 'mediawiki') {
2921 die("Unexpected data parsing MediaWiki table") if (shift @lines ne '{|'); # Dump the '{|' start
2922 while (scalar(@lines) >= 3) {
2923 my $c_datatype = shift @lines;
2924 my $name = shift @lines;
2925 my $desc = shift @lines;
2926 my $terminator; # the '|-' or '|}' line.
2927
2928 if (($desc eq '|-') or ($desc eq '|}') or (not $desc =~ /\A\|/)) { # we seem to be out of cells, which means there was no datatype column on this one.
2929 $terminator = $desc;
2930 $desc = $name;
2931 $name = $c_datatype;
2932 $c_datatype = '';
2933 } else {
2934 $terminator = shift @lines;
2935 }
2936
2937 last if ($terminator ne '|-') and ($terminator ne '|}'); # we seem to have run out of table.
2938 $name =~ s/\A\|\s*//;
2939 $name =~ s/\A\*\*(.*?)\*\*/$1/;
2940 $name =~ s/\A\'\'\'(.*?)\'\'\'/$1/;
2941 $desc =~ s/\A\|\s*//;
2942 $desc = dewikify($wikitype, $desc);
2943 #print STDERR "SYM: $sym CDATATYPE: $c_datatype NAME: $name DESC: $desc TERM: $terminator\n";
2944
2945 $str .= ".TP\n";
2946 $str .= ".I $name\n";
2947 $str .= "$desc\n";
2948 }
2949 } elsif ($wikitype eq 'md') {
2950 my $l;
2951 $l = shift @lines;
2952 die("Unexpected data parsing Markdown table") if (not $l =~ /\A(\s*\|)?\s*\|\s*\|\s*\|\s*\Z/);
2953 $l = shift @lines;
2954 die("Unexpected data parsing Markdown table") if (not $l =~ /\A\s*(\|\s*\-*\s*)?\|\s*\-*\s*\|\s*\-*\s*\|\s*\Z/);
2955 while (scalar(@lines) >= 1) {
2956 $l = shift @lines;
2957 my $name;
2958 my $desc;
2959 if ($l =~ /\A\s*\|\s*(.*?)\s*\|\s*(.*?)\s*\|\s*(.*?)\s*\|\s*\Z/) {
2960 # c datatype is $1, but we don't care about it here.
2961 $name = $2;
2962 $desc = $3;
2963 } elsif ($l =~ /\A\s*\|\s*(.*?)\s*\|\s*(.*?)\s*\|\s*\Z/) {
2964 $name = $1;
2965 $desc = $2;
2966 } else {
2967 last; # we seem to have run out of table.
2968 }
2969
2970 $name =~ s/\A\*\*(.*?)\*\*/$1/;
2971 $name =~ s/\A\'\'\'(.*?)\'\'\'/$1/;
2972 $desc = dewikify($wikitype, $desc);
2973
2974 $str .= ".TP\n";
2975 $str .= ".I $name\n";
2976 $str .= "$desc\n";
2977 }
2978 } else {
2979 die("write me");
2980 }
2981 }
2982
2983 if (defined $returns) {
2984 # Chop datatype in parentheses off the front.
2985 if(!($returns =~ s/\A\([^\[]*\[[^\]]*\]\([^\)]*\)[^\)]*\) //ms)) {
2986 $returns =~ s/\A\([^\)]*\) //ms;
2987 }
2988 $returns = dewikify($wikitype, $returns);
2989 $str .= ".SH RETURN VALUE\n";
2990 $str .= "$returns\n";
2991 }
2992
2993 if (defined $examples) {
2994 $str .= ".SH CODE EXAMPLES\n";
2995 $dewikify_manpage_code_indent = 0;
2996 $str .= dewikify($wikitype, $examples) . "\n";
2997 $dewikify_manpage_code_indent = 1;
2998 }
2999
3000 if (defined $threadsafety) {
3001 $str .= ".SH THREAD SAFETY\n";
3002 $str .= dewikify($wikitype, $threadsafety) . "\n";
3003 }
3004
3005 if (defined $version) {
3006 $str .= ".SH AVAILABILITY\n";
3007 $str .= dewikify($wikitype, $version) . "\n";
3008 }
3009
3010 if (defined $related) {
3011 $str .= ".SH SEE ALSO\n";
3012 # !!! FIXME: lots of code duplication in all of these.
3013 my $v = dewikify($wikitype, $related);
3014 my @desclines = split /\n/, $v;
3015 my $nextstr = '';
3016 foreach (@desclines) {
3017 s/\(\)\Z//; # Convert "SDL_Func()" to "SDL_Func"
3018 s/\[\[(.*?)\]\]/$1/; # in case some wikilinks remain.
3019 s/\[(.*?)\]\(.*?\)/$1/; # in case some wikilinks remain.
3020 s/\A\*\s*\Z//;
3021 s/\A\/*//;
3022 s/\A\.BR\s+//; # dewikify added this, but we want to handle it.
3023 s/\A\.I\s+//; # dewikify added this, but we want to handle it.
3024 s/\A\.PP\s*//; # dewikify added this, but we want to handle it.
3025 s/\\\(bu//; # dewikify added this, but we want to handle it.
3026 s/\A\s*[\:\*\-]\s*//;
3027 s/\A\s+//;
3028 s/\s+\Z//;
3029 next if $_ eq '';
3030 my $seealso_symtype = $headersymstype{$_};
3031 my $seealso_mansection = '3';
3032 if (defined($seealso_symtype) && ($seealso_symtype >= 3) && ($seealso_symtype <= 5)) { # struct/union/enum/typedef
3033 $seealso_mansection = '3type';
3034 }
3035 $str .= "$nextstr.BR $_ ($seealso_mansection)";
3036 $nextstr = ",\n";
3037 }
3038 $str .= "\n";
3039 }
3040
3041 if (0) {
3042 $str .= ".SH COPYRIGHT\n";
3043 $str .= "This manpage is licensed under\n";
3044 $str .= ".UR https://creativecommons.org/licenses/by/4.0/\n";
3045 $str .= "Creative Commons Attribution 4.0 International (CC BY 4.0)\n";
3046 $str .= ".UE\n";
3047 $str .= ".PP\n";
3048 $str .= "This manpage was generated from\n";
3049 $str .= ".UR $wikiurl/$sym\n";
3050 $str .= "${projectshortname}'s wiki\n";
3051 $str .= ".UE\n";
3052 $str .= "using SDL/build-scripts/wikiheaders.pl";
3053 $str .= " revision $gitrev" if $gitrev ne '';
3054 $str .= ".\n";
3055 $str .= "Please report issues in this manpage at\n";
3056 $str .= ".UR $bugreporturl\n";
3057 $str .= "our bugtracker!\n";
3058 $str .= ".UE\n";
3059 }
3060
3061 my $path = "$manpath/man3/$_.$mansection";
3062 my $tmppath = "$path.tmp";
3063 open(FH, '>', $tmppath) or die("Can't open '$tmppath': $!\n");
3064 print FH $str;
3065 close(FH);
3066 rename($tmppath, $path) or die("Can't rename '$tmppath' to '$path': $!\n");
3067 }
3068
3069} elsif ($copy_direction == -4) { # --copy-to-latex
3070 # This only takes from the wiki data, since it has sections we omit from the headers, like code examples.
3071
3072 print STDERR "\n(The --copy-to-latex code is known to not be ready for serious use; send patches, not bug reports, please.)\n\n";
3073
3074 $dewikify_mode = 'LaTeX';
3075 $wordwrap_mode = 'LaTeX';
3076
3077 # !!! FIXME: code duplication with --copy-to-manpages section.
3078
3079 my $introtxt = '';
3080 if (0) {
3081 open(FH, '<', "$srcpath/LICENSE.txt") or die("Can't open '$srcpath/LICENSE.txt': $!\n");
3082 while (<FH>) {
3083 chomp;
3084 $introtxt .= ".\\\" $_\n";
3085 }
3086 close(FH);
3087 }
3088
3089 if (!$gitrev) {
3090 $gitrev = `cd "$srcpath" ; git rev-list HEAD~..`;
3091 chomp($gitrev);
3092 }
3093
3094 # !!! FIXME
3095 open(FH, '<', "$srcpath/$versionfname") or die("Can't open '$srcpath/$versionfname': $!\n");
3096 my $majorver = 0;
3097 my $minorver = 0;
3098 my $microver = 0;
3099 while (<FH>) {
3100 chomp;
3101 if (/$versionmajorregex/) {
3102 $majorver = int($1);
3103 } elsif (/$versionminorregex/) {
3104 $minorver = int($1);
3105 } elsif (/$versionmicroregex/) {
3106 $microver = int($1);
3107 }
3108 }
3109 close(FH);
3110 my $fullversion = "$majorver.$minorver.$microver";
3111
3112 my $latex_fname = "$srcpath/$projectshortname.tex";
3113 my $latex_tmpfname = "$latex_fname.tmp";
3114 open(TEXFH, '>', "$latex_tmpfname") or die("Can't open '$latex_tmpfname' for writing: $!\n");
3115
3116 print TEXFH <<__EOF__
3117\\documentclass{book}
3118
3119\\usepackage{listings}
3120\\usepackage{color}
3121\\usepackage{hyperref}
3122
3123\\definecolor{dkgreen}{rgb}{0,0.6,0}
3124\\definecolor{gray}{rgb}{0.5,0.5,0.5}
3125\\definecolor{mauve}{rgb}{0.58,0,0.82}
3126
3127\\setcounter{secnumdepth}{0}
3128
3129\\lstset{frame=tb,
3130 language=C,
3131 aboveskip=3mm,
3132 belowskip=3mm,
3133 showstringspaces=false,
3134 columns=flexible,
3135 basicstyle={\\small\\ttfamily},
3136 numbers=none,
3137 numberstyle=\\tiny\\color{gray},
3138 keywordstyle=\\color{blue},
3139 commentstyle=\\color{dkgreen},
3140 stringstyle=\\color{mauve},
3141 breaklines=true,
3142 breakatwhitespace=true,
3143 tabsize=3
3144}
3145
3146\\begin{document}
3147\\frontmatter
3148
3149\\title{$projectfullname $majorver.$minorver.$microver Reference Manual}
3150\\author{The $projectshortname Developers}
3151\\maketitle
3152
3153\\mainmatter
3154
3155__EOF__
3156;
3157
3158 # !!! FIXME: Maybe put this in the book intro? print TEXFH $introtxt;
3159
3160 # Sort symbols by symbol type, then alphabetically.
3161 my @headersymskeys = sort {
3162 my $symtypea = $headersymstype{$a};
3163 my $symtypeb = $headersymstype{$b};
3164 $symtypea = 3 if ($symtypea > 3);
3165 $symtypeb = 3 if ($symtypeb > 3);
3166 my $rc = $symtypea <=> $symtypeb;
3167 if ($rc == 0) {
3168 $rc = lc($a) cmp lc($b);
3169 }
3170 return $rc;
3171 } keys %headersyms;
3172
3173 my $current_symtype = 0;
3174 my $current_chapter = '';
3175
3176 foreach (@headersymskeys) {
3177 my $sym = $_;
3178 next if not defined $wikisyms{$sym}; # don't have a page for that function, skip it.
3179 next if $sym =~ /\A\[category documentation\]/; # not real symbols.
3180 my $symtype = $headersymstype{$sym};
3181 my $wikitype = $wikitypes{$sym};
3182 my $sectionsref = $wikisyms{$sym};
3183 my $remarks = $sectionsref->{'Remarks'};
3184 my $params = $sectionsref->{'Function Parameters'};
3185 my $returns = $sectionsref->{'Return Value'};
3186 my $version = $sectionsref->{'Version'};
3187 my $threadsafety = $sectionsref->{'Thread Safety'};
3188 my $related = $sectionsref->{'See Also'};
3189 my $examples = $sectionsref->{'Code Examples'};
3190 my $deprecated = $sectionsref->{'Deprecated'};
3191 my $headerfile = $manpageheaderfiletext;
3192 $headerfile =~ s/\%fname\%/$headersymslocation{$sym}/g;
3193 $headerfile .= "\n";
3194
3195 my $brief = $sectionsref->{'[Brief]'};
3196 my $decl = $headerdecls{$sym};
3197 my $str = '';
3198
3199 if ($current_symtype != $symtype) {
3200 my $newchapter = '';
3201 if ($symtype == 1) {
3202 $newchapter = 'Functions';
3203 } elsif ($symtype == 2) {
3204 $newchapter = 'Macros';
3205 } else {
3206 $newchapter = 'Datatypes';
3207 }
3208
3209 if ($current_chapter ne $newchapter) {
3210 $str .= "\n\n\\chapter{$projectshortname $newchapter}\n\n\\clearpage\n\n";
3211 $current_chapter = $newchapter;
3212 }
3213 $current_symtype = $symtype;
3214 }
3215
3216 $brief = "$brief";
3217 $brief =~ s/\A[\s\n]*\= .*? \=\s*?\n+//ms;
3218 $brief =~ s/\A[\s\n]*\=\= .*? \=\=\s*?\n+//ms;
3219 $brief =~ s/\A(.*?\.) /$1\n/; # \brief should only be one sentence, delimited by a period+space. Split if necessary.
3220 my @briefsplit = split /\n/, $brief;
3221 $brief = shift @briefsplit;
3222 $brief = dewikify($wikitype, $brief);
3223
3224 if (defined $remarks) {
3225 $remarks = dewikify($wikitype, join("\n", @briefsplit) . $remarks);
3226 }
3227
3228 my $escapedsym = escLaTeX($sym);
3229 $str .= "\\hypertarget{$sym}{%\n\\section{$escapedsym}\\label{$sym}}\n\n";
3230 $str .= $brief if (defined $brief);
3231 $str .= "\n\n";
3232
3233 if (defined $deprecated) {
3234 $str .= "\\subsection{Deprecated}\n\n";
3235 $str .= dewikify($wikitype, $deprecated) . "\n";
3236 }
3237
3238 if (defined $headerfile) {
3239 $str .= "\\subsection{Header File}\n\n";
3240 $str .= dewikify($wikitype, $headerfile) . "\n";
3241 }
3242
3243 $str .= "\\subsection{Syntax}\n\n";
3244 $str .= "\\begin{lstlisting}\n$decl\n\\end{lstlisting}\n";
3245
3246 if (defined $params) {
3247 if (($symtype == 1) || ($symtype == 5)) {
3248 $str .= "\\subsection{Function Parameters}\n\n";
3249 } elsif ($symtype == 2) { # macro
3250 $str .= "\\subsection{Macro Parameters}\n\n";
3251 } elsif ($symtype == 3) { # struct/union
3252 $str .= "\\subsection{Fields}\n\n";
3253 } elsif ($symtype == 4) { # enum
3254 $str .= "\\subsection{Values}\n\n";
3255 } else {
3256 die("Unexpected symtype $symtype");
3257 }
3258
3259 $str .= "\\begin{center}\n";
3260 $str .= " \\begin{tabular}{ | l | p{0.75\\textwidth} |}\n";
3261 $str .= " \\hline\n";
3262
3263 # !!! FIXME: this table parsing has gotten complicated and is pasted three times in this file; move it to a subroutine!
3264 my @lines = split /\n/, $params;
3265 if ($wikitype eq 'mediawiki') {
3266 die("Unexpected data parsing MediaWiki table") if (shift @lines ne '{|'); # Dump the '{|' start
3267 while (scalar(@lines) >= 3) {
3268 my $name = shift @lines;
3269 my $desc = shift @lines;
3270 my $terminator = shift @lines; # the '|-' or '|}' line.
3271 last if ($terminator ne '|-') and ($terminator ne '|}'); # we seem to have run out of table.
3272 $name =~ s/\A\|\s*//;
3273 $name =~ s/\A\*\*(.*?)\*\*/$1/;
3274 $name =~ s/\A\'\'\'(.*?)\'\'\'/$1/;
3275 $name = escLaTeX($name);
3276 $desc =~ s/\A\|\s*//;
3277 $desc = dewikify($wikitype, $desc);
3278 #print STDERR "FN: $sym NAME: $name DESC: $desc TERM: $terminator\n";
3279 $str .= " \\textbf{$name} & $desc \\\\ \\hline\n";
3280 }
3281 } elsif ($wikitype eq 'md') {
3282 my $l;
3283 $l = shift @lines;
3284 die("Unexpected data parsing Markdown table") if (not $l =~ /\A(\s*\|)?\s*\|\s*\|\s*\|\s*\Z/);
3285 $l = shift @lines;
3286 die("Unexpected data parsing Markdown table") if (not $l =~ /\A\s*(\|\s*\-*\s*)?\|\s*\-*\s*\|\s*\-*\s*\|\s*\Z/);
3287 while (scalar(@lines) >= 1) {
3288 $l = shift @lines;
3289 my $name;
3290 my $desc;
3291 if ($l =~ /\A\s*\|\s*(.*?)\s*\|\s*(.*?)\s*\|\s*(.*?)\s*\|\s*\Z/) {
3292 # c datatype is $1, but we don't care about it here.
3293 $name = $2;
3294 $desc = $3;
3295 } elsif ($l =~ /\A\s*\|\s*(.*?)\s*\|\s*(.*?)\s*\|\s*\Z/) {
3296 $name = $1;
3297 $desc = $2;
3298 } else {
3299 last; # we seem to have run out of table.
3300 }
3301
3302 $name =~ s/\A\*\*(.*?)\*\*/$1/;
3303 $name =~ s/\A\'\'\'(.*?)\'\'\'/$1/;
3304 $name = escLaTeX($name);
3305 $desc = dewikify($wikitype, $desc);
3306 $str .= " \\textbf{$name} & $desc \\\\ \\hline\n";
3307 }
3308 } else {
3309 die("write me");
3310 }
3311
3312 $str .= " \\end{tabular}\n";
3313 $str .= "\\end{center}\n";
3314 }
3315
3316 if (defined $returns) {
3317 $returns = dewikify($wikitype, $returns);
3318 $returns =~ s/\A\(.*?\)\s*//; # Chop datatype in parentheses off the front.
3319 $str .= "\\subsection{Return Value}\n\n";
3320 $str .= "$returns\n";
3321 }
3322
3323 if (defined $remarks) {
3324 $str .= "\\subsection{Remarks}\n\n";
3325 $str .= $remarks . "\n";
3326 }
3327
3328 if (defined $examples) {
3329 $str .= "\\subsection{Code Examples}\n\n";
3330 $dewikify_manpage_code_indent = 0;
3331 $str .= dewikify($wikitype, $examples) . "\n";
3332 $dewikify_manpage_code_indent = 1;
3333 }
3334
3335 if (defined $threadsafety) {
3336 $str .= "\\subsection{Thread Safety}\n\n";
3337 $str .= dewikify($wikitype, $threadsafety) . "\n";
3338 }
3339
3340 if (defined $version) {
3341 $str .= "\\subsection{Version}\n\n";
3342 $str .= dewikify($wikitype, $version) . "\n";
3343 }
3344
3345 if (defined $related) {
3346 $str .= "\\subsection{See Also}\n\n";
3347 $str .= "\\begin{itemize}\n";
3348 # !!! FIXME: lots of code duplication in all of these.
3349 my $v = dewikify($wikitype, $related);
3350 my @desclines = split /\n/, $v;
3351 my $nextstr = '';
3352 foreach (@desclines) {
3353 s/\(\)\Z//; # Convert "SDL_Func()" to "SDL_Func"
3354 s/\[\[(.*?)\]\]/$1/; # in case some wikilinks remain.
3355 s/\[(.*?)\]\(.*?\)/$1/; # in case some wikilinks remain.
3356 s/\A\*\s*\Z//;
3357 s/\A\s*\\item\s*//;
3358 s/\A\/*//;
3359 s/\A\s*[\:\*\-]\s*//;
3360 s/\A\s+//;
3361 s/\s+\Z//;
3362 next if $_ eq '';
3363 next if $_ eq '\begin{itemize}';
3364 next if $_ eq '\end{itemize}';
3365 $str .= " \\item $_\n";
3366 }
3367 $str .= "\\end{itemize}\n";
3368 $str .= "\n";
3369 }
3370
3371 # !!! FIXME: Maybe put copyright in the book intro?
3372 if (0) {
3373 $str .= ".SH COPYRIGHT\n";
3374 $str .= "This manpage is licensed under\n";
3375 $str .= ".UR https://creativecommons.org/licenses/by/4.0/\n";
3376 $str .= "Creative Commons Attribution 4.0 International (CC BY 4.0)\n";
3377 $str .= ".UE\n";
3378 $str .= ".PP\n";
3379 $str .= "This manpage was generated from\n";
3380 $str .= ".UR $wikiurl/$sym\n";
3381 $str .= "${projectshortname}'s wiki\n";
3382 $str .= ".UE\n";
3383 $str .= "using SDL/build-scripts/wikiheaders.pl";
3384 $str .= " revision $gitrev" if $gitrev ne '';
3385 $str .= ".\n";
3386 $str .= "Please report issues in this manpage at\n";
3387 $str .= ".UR $bugreporturl\n";
3388 $str .= "our bugtracker!\n";
3389 $str .= ".UE\n";
3390 }
3391
3392 $str .= "\\clearpage\n\n";
3393
3394 print TEXFH $str;
3395 }
3396
3397 print TEXFH "\\end{document}\n\n";
3398 close(TEXFH);
3399 rename($latex_tmpfname, $latex_fname) or die("Can't rename '$latex_tmpfname' to '$latex_fname': $!\n");
3400
3401} elsif ($copy_direction == -3) { # --report-coverage-gaps
3402 foreach (@coverage_gap) {
3403 print("$_\n");
3404 }
3405}
3406
3407# end of wikiheaders.pl ...
3408