|
|
1.1 root 1: #include <stdlib.h> /* getenv()/exit()/atexit() */
2: #include <stdio.h> /* NULL */
3: #ifdef __unix__
4: #include <dlfcn.h>
5: #endif
6:
7: #include <SDL.h>
8: #ifndef main
9: #define USE_REAL_MAIN
10: #endif
11: #include "gen_defs.h"
12: #ifdef USE_REAL_MAIN
13: #undef main
14: #endif
15: #include "sdlfuncs.h"
16:
17: #ifndef _WIN32
18: struct sdlfuncs sdl;
19: #endif
20:
21: static int sdl_funcs_loaded=0;
22: static int sdl_initialized=0;
23: static int sdl_audio_initialized=0;
24: static int sdl_video_initialized=0;
25: static int (*sdl_drawing_thread)(void *data)=NULL;
26: static void (*sdl_exit_drawing_thread)(void)=NULL;
27: static int main_returned=0;
28: static SDL_sem *sdl_main_sem;
29: SDL_sem *sdl_exit_sem;
30:
31: int XPDEV_main(int argc, char **argv, char **enviro);
32:
33: #ifdef STATIC_SDL
34: int load_sdl_funcs(struct sdlfuncs *sdlf)
35: {
36: sdlf->gotfuncs=0;
37: sdlf->Init=SDL_Init;
38: sdlf->Quit=SDL_Quit;
39: #ifdef _WIN32
40: sdlf->SetModuleHandle=SDL_SetModuleHandle;
41: #endif
42: sdlf->mutexP=SDL_mutexP;
43: sdlf->mutexV=SDL_mutexV;
44: sdlf->PeepEvents=SDL_PeepEvents;
45: sdlf->VideoDriverName=SDL_VideoDriverName;
46: sdlf->SemWait=SDL_SemWait;
47: sdlf->SemPost=SDL_SemPost;
48: sdlf->EventState=SDL_EventState;
49: sdlf->CreateRGBSurface=SDL_CreateRGBSurface;
50: sdlf->FillRect=SDL_FillRect;
51: sdlf->SetColors=SDL_SetColors;
52: sdlf->BlitSurface=SDL_UpperBlit;
53: sdlf->UpdateRects=SDL_UpdateRects;
54: sdlf->SDL_CreateSemaphore=SDL_CreateSemaphore;
55: sdlf->SDL_DestroySemaphore=SDL_DestroySemaphore;
56: sdlf->SDL_CreateMutex=SDL_CreateMutex;
57: sdlf->CreateThread=SDL_CreateThread;
58: sdlf->KillThread=SDL_KillThread;
59: sdlf->WaitThread=SDL_WaitThread;
60: sdlf->WaitEvent=SDL_WaitEvent;
61: sdlf->SetVideoMode=SDL_SetVideoMode;
62: sdlf->FreeSurface=SDL_FreeSurface;
63: sdlf->WM_SetCaption=SDL_WM_SetCaption;
64: sdlf->ShowCursor=SDL_ShowCursor;
65: sdlf->WasInit=SDL_WasInit;
66: sdlf->EnableUNICODE=SDL_EnableUNICODE;
67: sdlf->EnableKeyRepeat=SDL_EnableKeyRepeat;
68: sdlf->GetWMInfo=SDL_GetWMInfo;
69: sdlf->GetError=SDL_GetError;
70: sdlf->InitSubSystem=SDL_InitSubSystem;
71: sdlf->QuitSubSystem=SDL_QuitSubSystem;
72: sdlf->OpenAudio=SDL_OpenAudio;
73: sdlf->CloseAudio=SDL_CloseAudio;
74: sdlf->PauseAudio=SDL_PauseAudio;
75: sdlf->LockAudio=SDL_LockAudio;
76: sdlf->UnlockAudio=SDL_UnlockAudio;
77: sdlf->GetAudioStatus=SDL_GetAudioStatus;
78: sdlf->gotfuncs=1;
79: sdl_funcs_loaded=1;
80: return(0);
81: }
82: #else
83:
84: #if defined(_WIN32)
85: #include <Windows.h>
86:
87: int load_sdl_funcs(struct sdlfuncs *sdlf)
88: {
89: HMODULE sdl_dll;
90:
91: sdlf->gotfuncs=0;
92: if((sdl_dll=LoadLibrary("SDL.dll"))==NULL)
93: if((sdl_dll=LoadLibrary("SDL-1.2.dll"))==NULL)
94: if((sdl_dll=LoadLibrary("SDL-1.1.dll"))==NULL)
95: return(-1);
96:
97: if((sdlf->Init=GetProcAddress(sdl_dll, "SDL_Init"))==NULL) {
98: FreeLibrary(sdl_dll);
99: return(-1);
100: }
101: if((sdlf->Quit=GetProcAddress(sdl_dll, "SDL_Quit"))==NULL) {
102: FreeLibrary(sdl_dll);
103: return(-1);
104: }
105: if((sdlf->SetModuleHandle=GetProcAddress(sdl_dll, "SDL_SetModuleHandle"))==NULL) {
106: FreeLibrary(sdl_dll);
107: return(-1);
108: }
109: if((sdlf->mutexP=GetProcAddress(sdl_dll, "SDL_mutexP"))==NULL) {
110: FreeLibrary(sdl_dll);
111: return(-1);
112: }
113: if((sdlf->mutexV=GetProcAddress(sdl_dll, "SDL_mutexV"))==NULL) {
114: FreeLibrary(sdl_dll);
115: return(-1);
116: }
117: if((sdlf->PeepEvents=GetProcAddress(sdl_dll, "SDL_PeepEvents"))==NULL) {
118: FreeLibrary(sdl_dll);
119: return(-1);
120: }
121: if((sdlf->VideoDriverName=GetProcAddress(sdl_dll, "SDL_VideoDriverName"))==NULL) {
122: FreeLibrary(sdl_dll);
123: return(-1);
124: }
125: if((sdlf->SemWait=GetProcAddress(sdl_dll, "SDL_SemWait"))==NULL) {
126: FreeLibrary(sdl_dll);
127: return(-1);
128: }
129: if((sdlf->SemPost=GetProcAddress(sdl_dll, "SDL_SemPost"))==NULL) {
130: FreeLibrary(sdl_dll);
131: return(-1);
132: }
133: if((sdlf->EventState=GetProcAddress(sdl_dll, "SDL_EventState"))==NULL) {
134: FreeLibrary(sdl_dll);
135: return(-1);
136: }
137: if((sdlf->CreateRGBSurface=GetProcAddress(sdl_dll, "SDL_CreateRGBSurface"))==NULL) {
138: FreeLibrary(sdl_dll);
139: return(-1);
140: }
141: if((sdlf->FillRect=GetProcAddress(sdl_dll, "SDL_FillRect"))==NULL) {
142: FreeLibrary(sdl_dll);
143: return(-1);
144: }
145: if((sdlf->SetColors=GetProcAddress(sdl_dll, "SDL_SetColors"))==NULL) {
146: FreeLibrary(sdl_dll);
147: return(-1);
148: }
149: if((sdlf->BlitSurface=GetProcAddress(sdl_dll, "SDL_UpperBlit"))==NULL) {
150: FreeLibrary(sdl_dll);
151: return(-1);
152: }
153: if((sdlf->UpdateRects=GetProcAddress(sdl_dll, "SDL_UpdateRects"))==NULL) {
154: FreeLibrary(sdl_dll);
155: return(-1);
156: }
157: if((sdlf->SDL_CreateSemaphore=GetProcAddress(sdl_dll, "SDL_CreateSemaphore"))==NULL) {
158: FreeLibrary(sdl_dll);
159: return(-1);
160: }
161: if((sdlf->SDL_DestroySemaphore=GetProcAddress(sdl_dll, "SDL_DestroySemaphore"))==NULL) {
162: FreeLibrary(sdl_dll);
163: return(-1);
164: }
165: if((sdlf->SDL_CreateMutex=GetProcAddress(sdl_dll, "SDL_CreateMutex"))==NULL) {
166: FreeLibrary(sdl_dll);
167: return(-1);
168: }
169: if((sdlf->CreateThread=GetProcAddress(sdl_dll, "SDL_CreateThread"))==NULL) {
170: FreeLibrary(sdl_dll);
171: return(-1);
172: }
173: if((sdlf->KillThread=GetProcAddress(sdl_dll, "SDL_KillThread"))==NULL) {
174: FreeLibrary(sdl_dll);
175: return(-1);
176: }
177: if((sdlf->WaitThread=GetProcAddress(sdl_dll, "SDL_WaitThread"))==NULL) {
178: FreeLibrary(sdl_dll);
179: return(-1);
180: }
181: if((sdlf->WaitEvent=GetProcAddress(sdl_dll, "SDL_WaitEvent"))==NULL) {
182: FreeLibrary(sdl_dll);
183: return(-1);
184: }
185: if((sdlf->SetVideoMode=GetProcAddress(sdl_dll, "SDL_SetVideoMode"))==NULL) {
186: FreeLibrary(sdl_dll);
187: return(-1);
188: }
189: if((sdlf->FreeSurface=GetProcAddress(sdl_dll, "SDL_FreeSurface"))==NULL) {
190: FreeLibrary(sdl_dll);
191: return(-1);
192: }
193: if((sdlf->WM_SetCaption=GetProcAddress(sdl_dll, "SDL_WM_SetCaption"))==NULL) {
194: FreeLibrary(sdl_dll);
195: return(-1);
196: }
197: if((sdlf->ShowCursor=GetProcAddress(sdl_dll, "SDL_ShowCursor"))==NULL) {
198: FreeLibrary(sdl_dll);
199: return(-1);
200: }
201: if((sdlf->WasInit=GetProcAddress(sdl_dll, "SDL_WasInit"))==NULL) {
202: FreeLibrary(sdl_dll);
203: return(-1);
204: }
205: if((sdlf->EnableUNICODE=GetProcAddress(sdl_dll, "SDL_EnableUNICODE"))==NULL) {
206: FreeLibrary(sdl_dll);
207: return(-1);
208: }
209: if((sdlf->EnableKeyRepeat=GetProcAddress(sdl_dll, "SDL_EnableKeyRepeat"))==NULL) {
210: FreeLibrary(sdl_dll);
211: return(-1);
212: }
213: if((sdlf->GetWMInfo=GetProcAddress(sdl_dll, "SDL_GetWMInfo"))==NULL) {
214: FreeLibrary(sdl_dll);
215: return(-1);
216: }
217: if((sdlf->GetError=GetProcAddress(sdl_dll, "SDL_GetError"))==NULL) {
218: FreeLibrary(sdl_dll);
219: return(-1);
220: }
221: if((sdlf->InitSubSystem=GetProcAddress(sdl_dll, "SDL_InitSubSystem"))==NULL) {
222: FreeLibrary(sdl_dll);
223: return(-1);
224: }
225: if((sdlf->QuitSubSystem=GetProcAddress(sdl_dll, "SDL_QuitSubSystem"))==NULL) {
226: FreeLibrary(sdl_dll);
227: return(-1);
228: }
229: if((sdlf->OpenAudio=GetProcAddress(sdl_dll, "SDL_OpenAudio"))==NULL) {
230: FreeLibrary(sdl_dll);
231: return(-1);
232: }
233: if((sdlf->CloseAudio=GetProcAddress(sdl_dll, "SDL_CloseAudio"))==NULL) {
234: FreeLibrary(sdl_dll);
235: return(-1);
236: }
237: if((sdlf->PauseAudio=GetProcAddress(sdl_dll, "SDL_PauseAudio"))==NULL) {
238: FreeLibrary(sdl_dll);
239: return(-1);
240: }
241: if((sdlf->LockAudio=GetProcAddress(sdl_dll, "SDL_LockAudio"))==NULL) {
242: FreeLibrary(sdl_dll);
243: return(-1);
244: }
245: if((sdlf->UnlockAudio=GetProcAddress(sdl_dll, "SDL_UnlockAudio"))==NULL) {
246: FreeLibrary(sdl_dll);
247: return(-1);
248: }
249: if((sdlf->GetAudioStatus=GetProcAddress(sdl_dll, "SDL_GetAudioStatus"))==NULL) {
250: FreeLibrary(sdl_dll);
251: return(-1);
252: }
253: sdlf->gotfuncs=1;
254: sdl_funcs_loaded=1;
255: return(0);
256: }
257: #elif defined(__unix__)
258: #include <dlfcn.h>
259:
260: int load_sdl_funcs(struct sdlfuncs *sdlf)
261: {
262: void *sdl_dll;
263:
264: sdlf->gotfuncs=0;
265: if((sdl_dll=dlopen("libSDL.so",RTLD_LAZY|RTLD_GLOBAL))==NULL)
266: if((sdl_dll=dlopen("libSDL-1.2.so",RTLD_LAZY|RTLD_GLOBAL))==NULL)
267: if((sdl_dll=dlopen("libSDL-1.1.so",RTLD_LAZY|RTLD_GLOBAL))==NULL)
268: return(-1);
269:
270: if((sdlf->Init=dlsym(sdl_dll, "SDL_Init"))==NULL) {
271: dlclose(sdl_dll);
272: return(-1);
273: }
274: if((sdlf->Quit=dlsym(sdl_dll, "SDL_Quit"))==NULL) {
275: dlclose(sdl_dll);
276: return(-1);
277: }
278: if((sdlf->mutexP=dlsym(sdl_dll, "SDL_mutexP"))==NULL) {
279: dlclose(sdl_dll);
280: return(-1);
281: }
282: if((sdlf->mutexV=dlsym(sdl_dll, "SDL_mutexV"))==NULL) {
283: dlclose(sdl_dll);
284: return(-1);
285: }
286: if((sdlf->PeepEvents=dlsym(sdl_dll, "SDL_PeepEvents"))==NULL) {
287: dlclose(sdl_dll);
288: return(-1);
289: }
290: if((sdlf->VideoDriverName=dlsym(sdl_dll, "SDL_VideoDriverName"))==NULL) {
291: dlclose(sdl_dll);
292: return(-1);
293: }
294: if((sdlf->SemWait=dlsym(sdl_dll, "SDL_SemWait"))==NULL) {
295: dlclose(sdl_dll);
296: return(-1);
297: }
298: if((sdlf->SemPost=dlsym(sdl_dll, "SDL_SemPost"))==NULL) {
299: dlclose(sdl_dll);
300: return(-1);
301: }
302: if((sdlf->EventState=dlsym(sdl_dll, "SDL_EventState"))==NULL) {
303: dlclose(sdl_dll);
304: return(-1);
305: }
306: if((sdlf->CreateRGBSurface=dlsym(sdl_dll, "SDL_CreateRGBSurface"))==NULL) {
307: dlclose(sdl_dll);
308: return(-1);
309: }
310: if((sdlf->FillRect=dlsym(sdl_dll, "SDL_FillRect"))==NULL) {
311: dlclose(sdl_dll);
312: return(-1);
313: }
314: if((sdlf->SetColors=dlsym(sdl_dll, "SDL_SetColors"))==NULL) {
315: dlclose(sdl_dll);
316: return(-1);
317: }
318: if((sdlf->BlitSurface=dlsym(sdl_dll, "SDL_UpperBlit"))==NULL) {
319: dlclose(sdl_dll);
320: return(-1);
321: }
322: if((sdlf->UpdateRects=dlsym(sdl_dll, "SDL_UpdateRects"))==NULL) {
323: dlclose(sdl_dll);
324: return(-1);
325: }
326: if((sdlf->SDL_CreateSemaphore=dlsym(sdl_dll, "SDL_CreateSemaphore"))==NULL) {
327: dlclose(sdl_dll);
328: return(-1);
329: }
330: if((sdlf->SDL_DestroySemaphore=dlsym(sdl_dll, "SDL_DestroySemaphore"))==NULL) {
331: dlclose(sdl_dll);
332: return(-1);
333: }
334: if((sdlf->SDL_CreateMutex=dlsym(sdl_dll, "SDL_CreateMutex"))==NULL) {
335: dlclose(sdl_dll);
336: return(-1);
337: }
338: if((sdlf->CreateThread=dlsym(sdl_dll, "SDL_CreateThread"))==NULL) {
339: dlclose(sdl_dll);
340: return(-1);
341: }
342: if((sdlf->KillThread=dlsym(sdl_dll, "SDL_KillThread"))==NULL) {
343: dlclose(sdl_dll);
344: return(-1);
345: }
346: if((sdlf->WaitThread=dlsym(sdl_dll, "SDL_WaitThread"))==NULL) {
347: dlclose(sdl_dll);
348: return(-1);
349: }
350: if((sdlf->WaitEvent=dlsym(sdl_dll, "SDL_WaitEvent"))==NULL) {
351: dlclose(sdl_dll);
352: return(-1);
353: }
354: if((sdlf->SetVideoMode=dlsym(sdl_dll, "SDL_SetVideoMode"))==NULL) {
355: dlclose(sdl_dll);
356: return(-1);
357: }
358: if((sdlf->FreeSurface=dlsym(sdl_dll, "SDL_FreeSurface"))==NULL) {
359: dlclose(sdl_dll);
360: return(-1);
361: }
362: if((sdlf->WM_SetCaption=dlsym(sdl_dll, "SDL_WM_SetCaption"))==NULL) {
363: dlclose(sdl_dll);
364: return(-1);
365: }
366: if((sdlf->ShowCursor=dlsym(sdl_dll, "SDL_ShowCursor"))==NULL) {
367: dlclose(sdl_dll);
368: return(-1);
369: }
370: if((sdlf->WasInit=dlsym(sdl_dll, "SDL_WasInit"))==NULL) {
371: dlclose(sdl_dll);
372: return(-1);
373: }
374: if((sdlf->EnableUNICODE=dlsym(sdl_dll, "SDL_EnableUNICODE"))==NULL) {
375: dlclose(sdl_dll);
376: return(-1);
377: }
378: if((sdlf->EnableKeyRepeat=dlsym(sdl_dll, "SDL_EnableKeyRepeat"))==NULL) {
379: dlclose(sdl_dll);
380: return(-1);
381: }
382: if((sdlf->GetWMInfo=dlsym(sdl_dll, "SDL_GetWMInfo"))==NULL) {
383: dlclose(sdl_dll);
384: return(-1);
385: }
386: if((sdlf->GetError=dlsym(sdl_dll, "SDL_GetError"))==NULL) {
387: dlclose(sdl_dll);
388: return(-1);
389: }
390: if((sdlf->InitSubSystem=dlsym(sdl_dll, "SDL_InitSubSystem"))==NULL) {
391: dlclose(sdl_dll);
392: return(-1);
393: }
394: if((sdlf->QuitSubSystem=dlsym(sdl_dll, "SDL_QuitSubSystem"))==NULL) {
395: dlclose(sdl_dll);
396: return(-1);
397: }
398: if((sdlf->OpenAudio=dlsym(sdl_dll, "SDL_OpenAudio"))==NULL) {
399: dlclose(sdl_dll);
400: return(-1);
401: }
402: if((sdlf->CloseAudio=dlsym(sdl_dll, "SDL_CloseAudio"))==NULL) {
403: dlclose(sdl_dll);
404: return(-1);
405: }
406: if((sdlf->PauseAudio=dlsym(sdl_dll, "SDL_PauseAudio"))==NULL) {
407: dlclose(sdl_dll);
408: return(-1);
409: }
410: if((sdlf->LockAudio=dlsym(sdl_dll, "SDL_LockAudio"))==NULL) {
411: dlclose(sdl_dll);
412: return(-1);
413: }
414: if((sdlf->UnlockAudio=dlsym(sdl_dll, "SDL_UnlockAudio"))==NULL) {
415: dlclose(sdl_dll);
416: return(-1);
417: }
418: if((sdlf->GetAudioStatus=dlsym(sdl_dll, "SDL_GetAudioStatus"))==NULL) {
419: dlclose(sdl_dll);
420: return(-1);
421: }
422: sdlf->gotfuncs=1;
423: sdl_funcs_loaded=1;
424: return(0);
425: }
426: #endif
427:
428: #endif
429:
430: int init_sdl_video(void)
431: {
432: /* This is all handled in SDL_main_env() */
433: if(sdl_video_initialized)
434: return(0);
435: else
436: return(-1);
437: }
438:
439: int init_sdl_audio(void)
440: {
441: if(!sdl_initialized)
442: return(-1);
443: if(sdl_audio_initialized)
444: return(0);
445: if(sdl.InitSubSystem(SDL_INIT_AUDIO)==0) {
446: sdl_audio_initialized=TRUE;
447: return(0);
448: }
449: return(-1);
450: }
451:
452: struct main_args {
453: int argc;
454: char **argv;
455: char **enviro;
456: };
457:
458: static int sdl_run_main(void *data)
459: {
460: struct main_args *args;
461: int ret;
462:
463: args=data;
464: ret=XPDEV_main(args->argc, args->argv, args->enviro);
465: main_returned=1;
466: sdl.SemPost(sdl_main_sem);
467: if(sdl_exit_drawing_thread!=NULL)
468: sdl_exit_drawing_thread();
469: sdl.SemPost(sdl_exit_sem);
470: return(ret);
471: }
472:
473: void run_sdl_drawing_thread(int (*drawing_thread)(void *data), void (*exit_drawing_thread)(void))
474: {
475: sdl_drawing_thread=drawing_thread;
476: sdl_exit_drawing_thread=exit_drawing_thread;
477: sdl.SemPost(sdl_main_sem);
478: }
479:
480: #ifndef main
481: int main(int argc, char **argv, char **env)
482: #else
483: int SDL_main_env(int argc, char **argv, char **env)
484: #endif
485: {
486: unsigned int i;
487: SDL_Event ev;
488: char drivername[64];
489: struct main_args ma;
490: SDL_Thread *main_thread;
491: int main_ret;
492: int use_sdl_video=FALSE;
493:
494: ma.argc=argc;
495: ma.argv=argv;
496: ma.enviro=env;
497: #ifndef _WIN32
498: load_sdl_funcs(&sdl);
499: #endif
500:
501: if(sdl.gotfuncs) {
502: use_sdl_video=TRUE;
503:
504: #ifdef _WIN32
505: /* Fail to windib (ie: No mouse attached) */
506: if(sdl.Init(SDL_INIT_VIDEO)) {
507: if(getenv("SDL_VIDEODRIVER")==NULL) {
508: putenv("SDL_VIDEODRIVER=windib");
509: WinExec(GetCommandLine(), SW_SHOWDEFAULT);
510: return(0);
511: }
512: /* Sure ,we can't use video, but audio is still valid! */
513: if(sdl.Init(0)==0)
514: sdl_initialized=TRUE;
515: }
516: else {
517: sdl_video_initialized=TRUE;
518: sdl_initialized=TRUE;
519: }
520: #else
521: /*
522: * On Linux, SDL doesn't properly detect availability of the
523: * framebuffer apparently. This results in remote connections
524: * displaying on the local framebuffer... a definate no-no.
525: * This ugly hack attempts to prevent this... of course, remote X11
526: * connections must still be allowed.
527: */
528: if((!use_sdl_video) || getenv("REMOTEHOST")!=NULL && getenv("DISPLAY")==NULL) {
529: /* Sure ,we can't use video, but audio is still valid! */
530: if(sdl.Init(0)==0)
531: sdl_initialized=TRUE;
532: }
533: else {
534: if(sdl.Init(SDL_INIT_VIDEO)==0) {
535: sdl_initialized=TRUE;
536: sdl_video_initialized=TRUE;
537: }
538: else {
539: /* Sure ,we can't use video, but audio is still valid! */
540: if(sdl.Init(0)==0)
541: sdl_initialized=TRUE;
542: }
543: }
544: #endif
545: if(sdl_video_initialized && sdl.VideoDriverName(drivername, sizeof(drivername))!=NULL) {
546: /* Unacceptable drivers */
547: if((!strcmp(drivername, "caca")) || (!strcmp(drivername,"aalib")) || (!strcmp(drivername,"dummy"))) {
548: sdl.QuitSubSystem(SDL_INIT_VIDEO);
549: sdl_video_initialized=FALSE;
550: }
551: else {
552: sdl_video_initialized=TRUE;
553: }
554: }
555: }
556: if(sdl_video_initialized) {
557: atexit(sdl.Quit);
558: sdl_main_sem=sdl.SDL_CreateSemaphore(0);
559: sdl_exit_sem=sdl.SDL_CreateSemaphore(0);
560: main_thread=sdl.CreateThread(sdl_run_main,&ma);
561: sdl.SemWait(sdl_main_sem);
562: if(sdl_drawing_thread!=NULL) {
563: sdl_drawing_thread(NULL);
564: sdl_exit_drawing_thread=NULL;
565: if(!main_returned) {
566: main_ret=0;
567: }
568: }
569: sdl.SemWait(sdl_exit_sem);
570: if(main_returned)
571: sdl.WaitThread(main_thread, &main_ret);
572: }
573: else
574: main_ret=XPDEV_main(argc, argv, env);
575: return(main_ret);
576: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.