diff --git a/Makefile.in b/Makefile.in index fef71397..9afbc4cf 100644 --- a/Makefile.in +++ b/Makefile.in @@ -18,6 +18,7 @@ include cpiface/Makefile-static include devp/Makefile-static include filesel/Makefile-static include filesel/cdfs/Makefile-static +include filesel/modland.com/Makefile-static include stuff/Makefile-static include dev/Makefile-static include help/Makefile-static diff --git a/boot/pmain.c b/boot/pmain.c index 6f208fe7..a4e89cb7 100644 --- a/boot/pmain.c +++ b/boot/pmain.c @@ -1010,7 +1010,26 @@ static int init_modules(int argc, char *argv[]) cfSetProfileInt ("fscolors", "UNKN", 7, 10); } - if (epoch < 20240211) + if (epoch < 20240510) + { + fprintf (stderr, "ocp.ini update (0.2.110) add [modland.com] mirror=https://ftp.modland.com\n"); +#ifdef _WIN32 + fprintf (stderr, "ocp.ini update (0.2.110) add [modland.com] cachedir=$OCPDATAHOME\\modland.com\\\n"); +#else + fprintf (stderr, "ocp.ini update (0.2.110) add [modland.com] cachedir=$OCPDATAHOME/modland.com/\n"); +#endif + fprintf (stderr, "ocp.ini update (0.2.110) add [modland.com] showrelevantdirectoriesonly=1\n"); + + cfSetProfileString ("modland.com", "mirror", "https://ftp.modland.com"); +#ifdef _WIN32 + cfSetProfileString ("modland.com", "cachedir", "$OCPDATAHOME\\modland.com\\"); +#else + cfSetProfileString ("modland.com", "cachedir", "$OCPDATAHOME/modland.com/"); +#endif + cfSetProfileBool ("modland.com", "showrelevantdirectoriesonly", 1); + } + + if (epoch < 20240510) { fprintf(stderr, "ocp.ini update (0.2.107) add [libsidplayfp] filterrange6581=0.5\n"); cfSetProfileString ("libsidplayfp", "filterrange6581", "0.5"); @@ -1018,9 +1037,9 @@ static int init_modules(int argc, char *argv[]) cfSetProfileString ("libsidplayfp", "combinedwaveforms", "Average"); } - if (epoch < 20240211) + if (epoch < 20240510) { - cfSetProfileInt("version", "epoch", 20240211, 10); + cfSetProfileInt("version", "epoch", 20240510, 10); cfStoreConfig(); if (isatty(2)) { @@ -1031,14 +1050,14 @@ static int init_modules(int argc, char *argv[]) sleep(5); } } - if (cfGetProfileInt("version", "epoch", 0, 10) != 20240211) + if (cfGetProfileInt("version", "epoch", 0, 10) != 20240510) { if (isatty(2)) { - fprintf(stderr,"\n\033[1m\033[31mWARNING, ocp.ini [version] epoch != 20240211\033[0m\n\n"); + fprintf(stderr,"\n\033[1m\033[31mWARNING, ocp.ini [version] epoch != 20240510\033[0m\n\n"); sleep(5); } else { - fprintf(stderr,"\nWARNING, ocp.ini [version] epoch != 20240211\n\n"); + fprintf(stderr,"\nWARNING, ocp.ini [version] epoch != 20240510\n\n"); } } diff --git a/configure b/configure index 28396ecf..9fa1f572 100755 --- a/configure +++ b/configure @@ -776,6 +776,7 @@ PTHREAD_LIBS EXE_SUFFIX LIB_SUFFIX SHARED_FLAGS +DIRSEPARATOR UPDATE_DESKTOP_DATABASE DESKTOP_FILE_INSTALL UPDATE_MIME_DATABASE @@ -7756,6 +7757,7 @@ printf "%s\n" "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h +DIRSEPARATOR="/" target=`$CC -dumpmachine` case $target in #( *-darwin*) : @@ -7778,6 +7780,7 @@ case $target in #( *-mingw*) : WINDOWS=1 + DIRSEPARATOR=\\ SHARED_FLAGS="-shared -pthread" # clock_gettime() is provided via -pthread when using mingw LIB_SUFFIX=.dll EXE_SUFFIX=.exe diff --git a/configure.ac b/configure.ac index 72fb6ee8..5c1d3479 100644 --- a/configure.ac +++ b/configure.ac @@ -51,7 +51,7 @@ AC_SUBST(DESKTOP_FILE_INSTALL) AC_SUBST(UPDATE_DESKTOP_DATABASE) AC_C_BIGENDIAN - +AC_SUBST(DIRSEPARATOR) AC_SUBST(SHARED_FLAGS) AC_SUBST(LIB_SUFFIX) AC_SUBST(EXE_SUFFIX) @@ -59,6 +59,7 @@ AC_SUBST(PTHREAD_LIBS) AC_SUBST(HAIKU) AC_SUBST(WINDOWS) AC_SUBST(WINDRES) +DIRSEPARATOR="/" target=`$CC -dumpmachine` AS_CASE([$target], [*-darwin*],[ @@ -78,6 +79,7 @@ AS_CASE([$target], ], [*-mingw*],[ WINDOWS=1 + DIRSEPARATOR=\\ SHARED_FLAGS="-shared -pthread" # clock_gettime() is provided via -pthread when using mingw LIB_SUFFIX=.dll EXE_SUFFIX=.exe diff --git a/filesel/Makefile b/filesel/Makefile index 947c767a..67765166 100644 --- a/filesel/Makefile +++ b/filesel/Makefile @@ -8,6 +8,7 @@ else all: $(CDROM_SO) pfilesel$(LIB_SUFFIX) endif $(MAKE) -C cdfs TOPDIR=../$(TOPDIR) + $(MAKE) -C modland.com TOPDIR=../$(TOPDIR) test: adbmeta-test$(EXE_SUFFIX) dirdb-test$(EXE_SUFFIX) filesystem-bzip2-test$(EXE_SUFFIX) filesystem-filehandle-cache-test$(EXE_SUFFIX) filesystem-gzip-test$(EXE_SUFFIX) filesystem-tar-test$(EXE_SUFFIX) filesystem-textfile-test$(EXE_SUFFIX) mdb-test$(EXE_SUFFIX) @echo "" && echo "adbmeta-test:" && ./adbmeta-test @@ -27,6 +28,7 @@ pfilesel$(LIB_SUFFIX): $(pfilesel_so) clean: $(MAKE) -C cdfs TOPDIR=../$(TOPDIR) clean + $(MAKE) -C modland.com TOPDIR=../$(TOPDIR) clean rm -f *.o *$(LIB_SUFFIX) adbmeta-test$(EXE_SUFFIX) dirdb-test$(EXE_SUFFIX) filesystem-bzip2-test$(EXE_SUFFIX) filesystem-filehandle-cache-test$(EXE_SUFFIX) filesystem-gzip-test$(EXE_SUFFIX) filesystem-tar-test$(EXE_SUFFIX) filesystem-textfile-test$(EXE_SUFFIX) mdb-test$(EXE_SUFFIX) ifeq ($(STATIC_CORE),1) @@ -39,10 +41,12 @@ ifeq ($(CDROM_SUPPORT),1) $(CP) $(CDROM_SO) "$(DESTDIR)$(LIBDIROCP)/autoload/30-cdrom$(LIB_SUFFIX)" endif $(MAKE) -C cdfs TOPDIR=../$(TOPDIR) install + $(MAKE) -C modland.com TOPDIR=../$(TOPDIR) install uninstall: rm -f "$(DESTDIR)$(LIBDIROCP)/autoload/25-pfilesel$(LIB_SUFFIX)" rm -f "$(DESTDIR)$(LIBDIROCP)/autoload/30-cdrom$(LIB_SUFFIX)" $(MAKE) -C cdfs TOPDIR=../$(TOPDIR) uninstall + $(MAKE) -C modland.com TOPDIR=../$(TOPDIR) uninstall endif adbmeta.o: adbmeta.c adbmeta.h \ diff --git a/filesel/modland.com/Makefile b/filesel/modland.com/Makefile new file mode 100644 index 00000000..574b370b --- /dev/null +++ b/filesel/modland.com/Makefile @@ -0,0 +1,55 @@ +TOPDIR=../../ +include $(TOPDIR)Rules.make +include Makefile-static + +ifeq ($(STATIC_CORE),1) +all: $(modland_com_so) +else +all: modland_com$(LIB_SUFFIX) +endif + +clean: + rm -f modland_com$(LIB_SUFFIX) *.o + +ifeq ($(STATIC_CORE),1) +install: +uninstall: +else +install: + $(CP) modland_com$(LIB_SUFFIX) "$(DESTDIR)$(LIBDIROCP)/autoload/60-modland_com$(LIB_SUFFIX)" +uninstall: + rm -f "$(DESTDIR)$(LIBDIROCP)/autoload/60-modland_com$(LIB_SUFFIX)" +endif + +.PHONY: all clean install uninstall + +modland_com$(LIB_SUFFIX): $(modland_com_so) + $(CC) $(SHARED_FLAGS) -o $@ $^ + +modland-com.o: \ + modland-com.c \ + modland-com-cachedir.c \ + modland-com-dir.c \ + modland-com-file.c \ + modland-com-filedb.c \ + modland-com-filehandle.c \ + modland-com-initialize.c \ + modland-com-mirrors.c \ + modland-com-removecache.c \ + modland-com-setup.c \ + ../download.h \ + ../../config.h \ + ../../types.h \ + ../../boot/plinkman.h \ + ../../boot/psetting.h \ + ../../filesel/dirdb.h \ + ../../filesel/filesystem.h \ + ../../filesel/filesystem-dir-mem.h \ + ../../filesel/filesystem-drive.h \ + ../../filesel/filesystem-file-dev.h \ + ../../filesel/filesystem-textfile.h \ + ../../stuff/err.h \ + ../../stuff/file.h \ + ../../stuff/framelock.h \ + ../../stuff/poutput.h + $(CC) $< -o $@ -c diff --git a/filesel/modland.com/Makefile-static b/filesel/modland.com/Makefile-static new file mode 100644 index 00000000..c0dd1d06 --- /dev/null +++ b/filesel/modland.com/Makefile-static @@ -0,0 +1,5 @@ +modland_com_so=modland-com.o + +ifeq ($(STATIC_CORE),1) + STATIC_OBJECTS += $(patsubst %.o,filesel/modland.com/%.o,$(modland_com_so)) +endif diff --git a/filesel/modland.com/modland-com-cachedir.c b/filesel/modland.com/modland-com-cachedir.c new file mode 100644 index 00000000..17496300 --- /dev/null +++ b/filesel/modland.com/modland-com-cachedir.c @@ -0,0 +1,365 @@ +#ifndef MAX +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif + +static void modland_com_cachedir_Draw ( + struct console_t *console, + const int origselected, + const int selected, + const char *ocpdatahome_modland_com, + const char *home_modland_com, + const char *ocpdata_modland_com, + const char *temp_modland_com, + const char *custom_modland_com, + char **cacheconfigcustom, + int *editcacheconfigquit +) +{ +/* +********************* modland.com: select cachedir *********************** +* * +* Select a cachedir with , and . * +* Edit custom with . Exit dialog with . * +* * +************************************************************************** +* * +* ( ) $OCPDATAHOME/modland.com (default) * +* => /home/stian/.local/share/ocp/modland.com * +* * +* ( ) $HOME/modland.com * +* => /home/stian/tmp/modland.com * +* * +* ( ) $OCPDATA/modland.com (might not be writable) * +* => /usr/local/share/ocp/modland.com * +* * +* ( ) $TEMP/modland.com (might not be system uniqe and writable) * +* => /tmp/modland.com * +* * +* ( ) custom * +* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX * +* * +**************************************************************************/ + int mlHeight = 23; + int mlWidth = MAX(74, plScrWidth - 30); + int mlTop = (plScrHeight - mlHeight) / 2; + int mlLeft = (plScrWidth - mlWidth) / 2; + + console->DisplayFrame (mlTop++, mlLeft++, mlHeight, mlWidth, DIALOG_COLOR_FRAME, "modland.com: select cachedir ", 0, 5, 0); + mlHeight -= 2; + mlWidth -= 2; + + mlTop++; + + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " Select a cachedir with %.15o%.7o, %.15o%.7o and %.15o%.7o."); + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " Edit custom with %.15o%.7o. Exit dialog with %.15o%.7o."); + + mlTop++; + + mlTop++; // 5: horizontal line + + mlTop++; + + console->DisplayPrintf (mlTop++, mlLeft, 0x09, mlWidth, " (%.2o%c%.9o) " "%*.*o" "$OCPDATAHOME/modland.com" "%0.7o (default)", + (0==origselected) ? '*' : ' ', + (0==selected) ? 7 : 0, + (0==selected) ? 1 : 3); + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " => %*S", mlWidth - 8, ocpdatahome_modland_com); + + mlTop++; + + console->DisplayPrintf (mlTop++, mlLeft, 0x09, mlWidth, " (%.2o%c%.9o) " "%*.*o" "$HOME/modland.com%0.7o", + (1==origselected) ? '*' : ' ', + (1==selected) ? 7 : 0, + (1==selected) ? 1 : 3); + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " => %*S", mlWidth - 8, home_modland_com); + + mlTop++; + + console->DisplayPrintf (mlTop++, mlLeft, 0x09, mlWidth, " (%.2o%c%.9o) " "%*.*o" "$OCPDATA/modland.com" "%0.7o (might not be writable)", + (2==origselected) ? '*' : ' ', + (2==selected) ? 7 : 0, + (2==selected) ? 1 : 3); + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " => %*S", mlWidth - 8, ocpdata_modland_com); + + mlTop++; + + console->DisplayPrintf (mlTop++, mlLeft, 0x09, mlWidth, " (%.2o%c%.9o) " "%*.*o" "$TEMP/modland.com" "%0.7o (might not be system uniqe and writable)", + (3==origselected) ? '*' : ' ', + (3==selected) ? 7 : 0, + (3==selected) ? 1 : 3); + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " => %*S", mlWidth - 8, temp_modland_com); + + mlTop++; + + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " custom:"); + + if (editcacheconfigquit) + { + console->DisplayPrintf (mlTop, mlLeft, 0x09, 4, " (%.2o%c%.9o)", + (4==origselected) ? '*' : ' '); + switch (console->EditStringUTF8(mlTop++, mlLeft + 5, mlWidth - 10, cacheconfigcustom)) + { + case -1: + case 0: + *editcacheconfigquit = 1; + break; + default: + case 1: + break; + } + } else { + console->DisplayPrintf (mlTop++, mlLeft, 0x09, mlWidth, " (%.2o%c%.9o) " "%*.*o" "%*S" "%0.9o ", + (4==origselected) ? '*' : ' ', + (4==selected) ? 7 : 0, + (4==selected) ? 1 : 3, + mlWidth - 10, + *cacheconfigcustom); + } + + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " => %*s", mlWidth - 8, custom_modland_com); +} + +static char *modland_com_resolve_cachedir3 (const char *src) +{ + char *retval = malloc (strlen (src) + 2); + char *iter; + if (!retval) + { + return 0; + } + sprintf (retval, "%s/", src); /* ensure that it ends with a slash */ + + for (iter = retval; *iter;) + { /* check for double slash */ + if ((!strncmp (iter, "//", 2)) || + (!strncmp (iter, "\\\\", 2)) || + (!strncmp (iter, "/\\", 2)) || + (!strncmp (iter, "\\/", 2))) + { + memmove (iter, iter+1, strlen (iter + 1) + 1); + } else { /* flip slashes if they are the wrong direction */ +#ifdef _WIN32 + if (*iter == '/') + { + *iter = '\\'; + } +#else + if (*iter == '\\') + { + *iter = '/'; + } +#endif + iter++; + } + } + return retval; +} + +static char *modland_com_resolve_cachedir2 (const char *src1, const char *src2) +{ + int len = strlen (src1) + strlen (src2) + 1; + char *temp = malloc (len); + char *retval; + if (!temp) + { + return 0; + } + + snprintf (temp, len, "%s%s", src1, src2); + retval = modland_com_resolve_cachedir3 (temp); + free (temp); + return retval; +} + +static char *modland_com_resolve_cachedir (const struct configAPI_t *configAPI, const char *src) +{ + if ((!strncmp (src, "~\\", 2)) || + (!strncmp (src, "~/", 2))) + { + return modland_com_resolve_cachedir2 (configAPI->HomePath, src+2); + } else if ((!strncmp (src, "$HOME\\", 6)) || + (!strncmp (src, "$HOME/", 6))) + { + return modland_com_resolve_cachedir2 (configAPI->HomePath, src+6); + + } else if ((!strncmp (src, "$OCPDATAHOME\\", 13)) || + (!strncmp (src, "$OCPDATAHOME/", 13))) + { + return modland_com_resolve_cachedir2 (configAPI->DataHomePath, src+13); + } else if ((!strncmp (src, "$OCPDATA\\", 9)) || + (!strncmp (src, "$OCPDATA/", 9))) + { + return modland_com_resolve_cachedir2 (configAPI->DataPath, src+9); + } else if ((!strncmp (src, "$TEMP\\", 6)) || + (!strncmp (src, "$TEMP/", 6))) + { + return modland_com_resolve_cachedir2 (configAPI->TempPath, src+6); + } else { + return modland_com_resolve_cachedir3 (src); + } +} + +static void modland_com_cachedir_Save (const struct DevInterfaceAPI_t *API, int selected, char **custom_modland_com) +{ + free (modland_com.cacheconfig); + switch (selected) + { + case 0: modland_com.cacheconfig = modland_com_strdup_slash ("$OCPDATAHOME/modland.com/"); break; + case 1: modland_com.cacheconfig = modland_com_strdup_slash ("$HOME/modland.com/"); break; + case 2: modland_com.cacheconfig = modland_com_strdup_slash ("$OCPDATA/modland.com/"); break; + case 3: modland_com.cacheconfig = modland_com_strdup_slash ("$TEMP/modland.com/"); break; + + default: + case 4: + { + char *t = modland_com.cacheconfigcustom; + modland_com.cacheconfig = modland_com_strdup_slash (t); + modland_com.cacheconfigcustom = modland_com_strdup_slash (t); + free (t); + + free (*custom_modland_com); + *custom_modland_com = modland_com_resolve_cachedir (API->configAPI, modland_com.cacheconfigcustom); + } + } + + API->configAPI->SetProfileString ("modland.com", "cachedir", modland_com.cacheconfig); + API->configAPI->SetProfileString ("modland.com", "cachedircustom", modland_com.cacheconfigcustom); + API->configAPI->SetProfileComment ("modland.com", "cachedircustom", "; If a non-standard cachedir has been used in the past, it is stored here"); + + API->configAPI->StoreConfig(); + + free (modland_com.cachepath); + modland_com.cachepath = 0; + modland_com.cachepath = modland_com_resolve_cachedir (API->configAPI, modland_com.cacheconfig); + + free (modland_com.cachepathcustom); + modland_com.cachepathcustom = 0; + modland_com.cachepathcustom = modland_com_resolve_cachedir (API->configAPI, modland_com.cacheconfigcustom); +} + +static void modland_com_cachedir_Run (const struct DevInterfaceAPI_t *API) +{ + char *home_modland_com = modland_com_resolve_cachedir2 (API->configAPI->HomePath, "modland.com"); + char *ocpdatahome_modland_com = modland_com_resolve_cachedir2 (API->configAPI->DataHomePath, "modland.com"); + char *ocpdata_modland_com = modland_com_resolve_cachedir2 (API->configAPI->DataPath, "modland.com"); + char *temp_modland_com = modland_com_resolve_cachedir2 (API->configAPI->TempPath, "modland.com"); + char *custom_modland_com = modland_com_resolve_cachedir (API->configAPI, modland_com.cacheconfigcustom); + int selected; + int origselected; + int quit = 0; + + if (((!strncmp (modland_com.cacheconfig, "~\\", 2)) || + (!strncmp (modland_com.cacheconfig, "~/" , 2))) && + (!strcmp (modland_com.cacheconfig + 2, "modland.com"))) + { + selected = 1; + } else if (((!strncmp (modland_com.cacheconfig, "$HOME\\", 6)) || + (!strncmp (modland_com.cacheconfig, "$HOME/" , 6))) && + (!strcmp (modland_com.cacheconfig + 6, "modland.com/"))) + { + selected = 1; + + } else if (((!strncmp (modland_com.cacheconfig, "$OCPDATAHOME\\", 13)) || + (!strncmp (modland_com.cacheconfig, "$OCPDATAHOME/", 13))) && + (!strcmp (modland_com.cacheconfig + 13, "modland.com/"))) + { + selected = 0; + } else if (((!strncmp (modland_com.cacheconfig, "$OCPDATA\\", 9)) || + (!strncmp (modland_com.cacheconfig, "$OCPDATA/", 9))) && + (!strcmp (modland_com.cacheconfig + 9, "modland.com/"))) + { + selected = 2; + } else if (((!strncmp (modland_com.cacheconfig, "$TEMP\\", 6)) || + (!strncmp (modland_com.cacheconfig, "$TEMP/", 6))) && + (!strcmp (modland_com.cacheconfig + 9, "modland.com/"))) + { + selected = 3; + } else { + selected = 4; + free (modland_com.cacheconfigcustom); + modland_com.cacheconfigcustom = strdup (modland_com.cacheconfig); + } + + origselected = selected; + + while (!quit) + { + API->fsDraw(); + modland_com_cachedir_Draw ( + API->console, + origselected, + selected, + ocpdatahome_modland_com, + home_modland_com, + ocpdata_modland_com, + temp_modland_com, + custom_modland_com, + &modland_com.cacheconfigcustom, + 0 + ); + + while (API->console->KeyboardHit() && !quit) + { + int key = API->console->KeyboardGetChar(); + switch (key) + { + case KEY_EXIT: + goto free_return; + return; + case KEY_ESC: + quit = 1; + break; + case KEY_UP: + if (selected) + { + selected--; + } + break; + case KEY_DOWN: + if (selected < 4) + { + selected++; + } + break; + case ' ': + origselected = selected; + modland_com_cachedir_Save (API, selected, &custom_modland_com); + break; + case _KEY_ENTER: + origselected = selected; + if (selected == 4) + { + int innerquit = 0; + while (!innerquit) + { + modland_com_cachedir_Draw ( + API->console, + origselected, + selected, + ocpdatahome_modland_com, + home_modland_com, + ocpdata_modland_com, + temp_modland_com, + custom_modland_com, + &modland_com.cacheconfigcustom, + &innerquit + ); + + API->console->FrameLock(); + } + } + modland_com_cachedir_Save (API, selected, &custom_modland_com); + break; + } + } + API->console->FrameLock(); + } + + +free_return: + free (home_modland_com); + free (ocpdatahome_modland_com); + free (ocpdata_modland_com); + free (temp_modland_com); + free (custom_modland_com); +} diff --git a/filesel/modland.com/modland-com-dir.c b/filesel/modland.com/modland-com-dir.c new file mode 100644 index 00000000..e5be1f56 --- /dev/null +++ b/filesel/modland.com/modland-com-dir.c @@ -0,0 +1,775 @@ +static const char *known_adlib_directories[] = +{ + "ADL", + "AMusic", + "AMusic XMS", + "AdLib Tracker", + "AdLib Tracker 2", + "Apogee", + "Beni Tracker", + "Bob's AdLib Music", + "Boom Tracker", + "Creative Music File", + /* "DOSBox", should have worked, 2 of 2 fails to load */ + "DeFy AdLib Tracker", + "Digital FM", + "EdLib D00", + /* "Edlib D01", includes PCM audio */ + /* "EdLib Packed", includes PCM audio */ + "Exotic AdLib", + "Extra Simple Music", + // "FM Tracker", + // "FM-Kingtracker", + "Faust Music Creator" + "HSC AdLib Composer", + "Herad Music System", + "Johannes Bjerregard Module", + "Ken's AdLib Music", + "Loudness Sound System", + "LucasArts", + "MK-Jamz", + "MPU-401 Trakker", + // "MUS", detected as IMS, fails to load + "Martin Fernandez", /* These are actually Apogee IMF files */ + "Master Tracker", + "Mlat Adlib Tracker", + // "Palladix", + // "Pixel Painters FMF", + // "Pixel Painters FTF", + "Raw OPL Capture", + "Reality AdLib Tracker", + "SNG Player", + "Screamtracker 3 AdLib", + // "Shadowlands", + "Sierra", + // "Sound Images Generation 2", + // "Sound Interface System", + "Surprise! AdLib Tracker", + "Surprise! AdLib Tracker 2.0", + "Twin TrackPlayer", + "Ultima 6", + // "Vibrants", + "Visual Composer", +}; + +static const char *known_root_directories[] = +{ + "AHX", /* HVL */ + // "AM Composer", + // "AND XSynth", + // "AProSys", + // "AXS", + // "AY Amadeus", + "AY Emul", /* AY */ + // "AY STRC", + // "Ace Tracker", + // "Actionamics", + // "Activision Pro", + "Ad Lib", + // "Aero Studio", + // "All Sound Tracker", + // "Anders Oland", + // "ArkosTracker", + // "Arpeggiator", + // "Art And Magic", + // "Art Of Noise", + // "Astroidea XMF", + // "Asylum", + "Atari Digi-Mix", /* YM*/ + // "Athtune", + // "Audio Sculpture", + // "BP SoundMon 2", + // "BP SoundMon 3", + // "BeRoTracker", + // "Beathoven Synthesizer", + // "Beaver Sweeper", + // "Beepola", + // "Ben Daglish", + // "Ben Daglish SID", + // "BoyScout", + // "Buzz", + // "Buzzic", + // "Buzzic 2", + // "CBA", + // "Capcom Q-Sound Format", + // "Composer 667", + "Composer 669", /* 669 */ + // "Composer 670 (CDFM)", + // "Compoz", + // "Core Design", + "Cubic Tiny XM", /* MXM 1 of 2 files are a broken, perhaps version 1.0 had different sample headers than laters versions? */ + // "CustomMade", + // "Cybertracker", + // "Cybertracker C64", + // "DSMI Compact", + // "Darius Zendeh", + // "DarkWave Studio", + // "Dave Lowe", + // "Dave Lowe New", + // "David Hanney", + // "David Whittaker", + // "Deflemask", + // "Delitracker Custom", + // "Delta Music", + // "Delta Music 2", + // "Delta Packer", + // "Desire", + // "Digibooster", + // "Digibooster Pro", + // "Digital Mugician", + // "Digital Mugician 2", + // "Digital Sonix And Chrome", + // "Digital Sound And Music Interface", + // "Digital Sound Interface Kit", + // "Digital Sound Interface Kit RIFF", + // "Digital Sound Studio", + // "Digital Symphony", + // "Digital Tracker DTM", + "Digital Tracker MOD", /* MOD */ + "Digitrakker", /* MDL */ + // "Digitrekker", + // "Dirk Bialluch", + // "Disorder Tracker 2", + // "DreamStation", + // "Dreamcast Sound Format", + // "Dynamic Studio Professional", + // "Dynamic Synthesizer", + // "EarAche", + // "Electronic Music System", + // "Electronic Music System v6", + // "Epic Megagames MASI", + // "Euphony", + "Extreme Tracker", /* AMS */ + // "FAC SoundTracker", + // "FM Tracker", + // "Face The Music", + // "FamiTracker", + // "Farandole Composer", + // "Fashion Tracker", + "Fasttracker", /* MOD */ + "Fasttracker 2", /* XM */ + // "Follin Player II", + // "Forgotten Worlds", + // "Fred Gray", + // "FredMon", + // "FuchsTracker", + // "Funktracker", + // "Future Composer 1.3", + // "Future Composer 1.4", + // "Future Composer BSI", + // "Future Player", + // "GT Game Systems", + // "Game Music Creator", + // "Gameboy Sound Format", /* <-- Should have been blaarg ? */ + "Gameboy Sound System", /* GBS (Blaarg's game music emulator) */ + // "Gameboy Sound System GBR", + // "Gameboy Tracker", + // "General DigiMusic", + // "GlueMon", + // "GoatTracker", + // "GoatTracker 2", + // "Graoumf Tracker", + // "Graoumf Tracker 2", + "HES", /* HES (Blaarg's game music emulator) */ + "HVSC", /* SID, mirror of "The High Voltage SID Collection" */ + // "Hippel", + // "Hippel 7V", + // "Hippel COSO", + // "Hippel ST", + // "Hippel ST COSO", + "His Master's Noise", /* MOD/MODt */ + "HivelyTracker", /* HVL */ + // "Howie Davies", + // "IFF-SMUS", + // "Images Music System", + // "Imago Orpheus", + "Impulsetracker", /* IT */ + // "InStereo!", + // "InStereo! 2.0", + // "Infogrames", + // "Ixalance", + // "JamCracker", + // "Janko Mrsic-Flogel", + // "Jason Brooke", + // "Jason Page", + // "Jason Page Old", + // "JayTrax", + // "Jeroen Tel", + // "Jesper Olsen", + // "KSS", /* KSS (Blaarg's game music emulator) <- only supports SEGA, and MSX that uses the internal AY chip. No support for ram-module, stereo, FM-PAC, MSX-AUDIO, etc. Only some few tunes inside "- unknown" works */ + // "Ken's Digital Music"; + // "Klystrack", + // "Kris Hatlelid", + // "Leggless Music Editor", + // "Lionheart", + // "Liquid Tracker", + // "MCMD", + // "MDX", + // "MO3", + // "MVS Tracker", + // "MVX Module", + // "Mad Tracker 2", + // "Magnetic Fields Packer", + // "Maniacs Of Noise", + // "Mark Cooksey", + // "Mark Cooksey Old", + // "Mark II", + // "MaxTrax", + // "Medley", + // "MegaStation", + // "MegaStation MIDI", + // "Megadrive CYM", + "Megadrive GYM", /* GYM (Blaarg's game music emulator) */ + "Multitracker", /* MTM */ + // "MikMod UNITRK", + // "Mike Davies", + // "Monotone", + // "MoonBlaster", + // "MoonBlaster (edit mode)", + // "MultiMedia Sound", + // "Multitracker", + // "Music Assembler", + // "Music Editor", + // "MusicMaker V8", + // "MusicMaker V8 Old", + // "Musicline Editor", + // "NerdTracker 2", + // "Nintendo DS Sound Format", + "Nintendo SPC", /* SPC (Blaarg's game music emulator) */ + "Nintendo Sound Format", /* NSF (Blaarg's game music emulator) */ + // "NoiseTrekker", + // "NoiseTrekker 2", + // "NovoTrade Packer", + // "OctaMED MMD0", + // "OctaMED MMD1", + // "OctaMED MMD2", + // "OctaMED MMD3", + // "OctaMED MMDC", + "Octalyser", /* MOD */ + "Oktalyzer", /* OKT */ + // "Onyx Music File", + // "OpenMPT MPTM", + // "Organya", + // "Organya 2", + // "PMD", + // "Paul Robotham", + // "Paul Shields", + // "Paul Summers", + // "Peter Verswyvelen", + // "Picatune", + // "Picatune2", + // "Pierre Adane Packer", + // "Piston Collage", + // "Piston Collage Protected", + "PlaySID", /* SID */ + // "PlayerPro", + // "Playstation 2 Sound Format", + // "Playstation Sound Format", + // "PokeyNoise", + // "Pollytracker", + "Polytracker", /* PTM */ + // "Powertracker", + // "Pretracker", + // "ProTrekkr", + // "ProTrekkr 2.0", + // "Professional Sound Artists", + "Protracker", /* MOD */ + // "Protracker IFF", + // "Psycle", + // "Pumatracker", + // "Quadra Composer", + // "Quartet PSG", + // "Quartet ST", + // "RamTracker", + // "Real Tracker", + "RealSID", /* SID */ + // "Renoise", + // "Renoise Old", + // "Richard Joseph", + // "Riff Raff", + // "Rob Hubbard", + // "Rob Hubbard ST", + // "Ron Klaren", + // "S98", + // "SBStudio", + // "SC68", /* <-- https://github.com/Zeinok/sc68 */ + // "SCC-Musixx", + // "SCUMM", + // "SNDH", + // "SPU", + // "SVAr Tracker", + // "Sam Coupe COP"; + // "Sam Coupe SNG", + // "Saturn Sound Format", + "Screamtracker 2", /* STM */ + "Screamtracker 3", /* S3M */ + // "Sean Connolly", + // "Sean Conran", + // "Shroom", + // "SidMon 1", /* <-- should have been SID */ + // "SidMon 2", /* <-- should have been SID? */ + "Sidplayer", /* SID */ + // "Silmarils", + // "Skale Tracker", + "Slight Atari Player", /* SAP (Blaarg's game music emulator) */ + // "Sonic Arranger", + // "Sound Club", + // "Sound Club 2", + // "Sound Images", + // "Sound Master", + // "Sound Master II v1", + // "Sound Master II v3", + // "Sound Programming Language", + // "SoundControl", + // "SoundFX", + // "SoundFactory", + // "SoundPlayer", + "Soundtracker", /* M15 */ + // "Soundtracker 2.6", /* <- different file format, just looks similiar to .MOD */ + // "Soundtracker Pro II", /* <- different file format, just looks similiar to .MOD */ + // "Special FX", + // "Special FX ST", + // "Spectrum", /* This is bucket, just like Adlib */ + // "Speedy A1 System", + // "Speedy System", + // "Starkos", + // "Startrekker AM", /* <- Contains (potential) AM (OPL3) instruments via external mod.nt file. Has normal FLT4 signature */ + // "Startrekker FLT8", /* <- Could be loaded as regular MOD files, but contains a hack: two and two 4-channels patterns should be merged into a 8-channel pattern */ + "Stereo Sidplayer", /* SID, unsure if they actually contain stereo files */ + // "Steve Barrett", + // "Stonetracker", + // "SunTronic", + // "SunVox", + // "Super Nintendo Sound Format", /* <-- not in blaargh ? */ + // "Symphonie", + // "SynTracker", + // "Synder SNG-Player", + // "Synder SNG-Player Stereo", + // "Synder Tracker", + // "Synth Dream", + // "Synth Pack", + // "Synthesis", + // "TCB Tracker", + // "TFM Music Maker", + // "TFMX", + // "TFMX ST", + // "TSS", + // "The 0ok Amazing Synth Tracker", + // "The Musical Enlightenment", + // "Thomas Hermann", + // "Tomy Tracker", + // "Tunefish", + // "Ultra64 Sound Format", + "Ultratracker", /* ULT */ + "Unis 669", /* 669 */ + // "V2", + // "VGM Music Maker", + "Velvet Studio", /* AMS */ + // "Vic-Tracker", + "Video Game Music", /* VGM (can be OPL too) */ + // "Voodoo Supreme Synthesizer", + // "Wally Beben", + // "Westwood SND", + // "WonderSwan", + "X-Tracker", /* DMF */ + "YM", /* YM */ + // "YMST", /* <- Furher development of YM fileformat, unable to find documentation. UADE can play these via YM-2149 / MYST */ + // "Zoundmonitor", +}; + +struct modland_com_ocpdir_t +{ + struct ocpdir_t head; + char *dirname; /* survives main database changes */ +}; + +static void modland_com_ocpdir_ref (struct ocpdir_t *d) +{ + struct modland_com_ocpdir_t *self = (struct modland_com_ocpdir_t *)d; + self->head.refcount++; +} + +static void modland_com_ocpdir_unref (struct ocpdir_t *d) +{ + struct modland_com_ocpdir_t *self = (struct modland_com_ocpdir_t *)d; + if (!--self->head.refcount) + { + if (self->head.parent) + { + self->head.parent->unref (self->head.parent); + self->head.parent = 0; + } + dirdbUnref (self->head.dirdb_ref, dirdb_use_dir); + free (self->dirname); + free (self); + } +} + +struct modland_com_readdir_t +{ + struct modland_com_ocpdir_t *dir; + int isroot; + int isadlib; + unsigned int fileoffset; + unsigned int diroffset; + unsigned int dirmax; // used by flatdir + unsigned int direxact; + unsigned int dirnamelength; /* cache for strncmp */ + int flatdir; + int sentdevs; + void(*callback_file)(void *token, struct ocpfile_t *); + void(*callback_dir )(void *token, struct ocpdir_t *); + void *token; +}; + +static ocpdirhandle_pt modland_com_ocpdir_readdir_start_common (struct ocpdir_t *d, + void(*callback_file)(void *token, struct ocpfile_t *), + void(*callback_dir )(void *token, struct ocpdir_t *), + void *token, + int flatdir) +{ + struct modland_com_ocpdir_t *self = (struct modland_com_ocpdir_t *)d; + struct modland_com_readdir_t *iter = calloc (sizeof (*iter), 1); + + if (!iter) + { + return 0; + } + iter->dir = self; + iter->dirnamelength = strlen (self->dirname); + iter->callback_file = callback_file; + iter->callback_dir = callback_dir; + iter->token = token; + iter->flatdir = flatdir; + + /* perform binary search for the exact directory entry */ + if (modland_com.database.direntries_n) + { + unsigned long start = 0; + unsigned long stop = modland_com.database.direntries_n; + + iter->isroot = !strcasecmp (self->dirname, ""); + iter->isadlib = !strcasecmp (self->dirname, "Ad Lib"); + + if (!strcmp (modland_com.database.direntries[start], self->dirname)) + { /* we only need to strcmp the start entry once, after this start can only be transfered from "half", which is strcompared */ + iter->direxact = start; + } else { + while (1) + { + unsigned long distance = stop - start; + unsigned long half; + int res; + + if (distance <= 1) /* we can't have a direct hit, since entry does not match start which is the only possible entry in the list */ + { + iter->direxact = UINT_MAX; + break; + } + + half = (stop - start) / 2 + start; + + res = modland_com_dir_strcmp (modland_com.database.direntries[half], self->dirname); + if (!res) + { + iter->direxact = half; + break; + } else if (res > 0) + { + stop = half; + } else { + start = half; + } + } + } + } else { + iter->direxact = UINT_MAX; + } + + iter->diroffset = iter->direxact; + if (iter->diroffset != UINT_MAX) + { + if (flatdir) + { /* need to find dirlimit */ + iter->dirmax = iter->diroffset + 1; + while ((iter->dirmax < modland_com.database.direntries_n) && + (!strncmp (modland_com.database.direntries[iter->dirmax], self->dirname, iter->dirnamelength)) && + (modland_com.database.direntries[iter->dirmax][iter->dirnamelength]=='/')) + { + iter->dirmax++; + } + } else { /* need to skip first directory, it is "." */ + iter->diroffset++; + if ((iter->diroffset >= modland_com.database.direntries_n) || + strncmp (modland_com.database.direntries[iter->diroffset], self->dirname, iter->dirnamelength)) + { + iter->diroffset = UINT_MAX; + } + } + } + + /* perform binary search for the first file with the correct dirindex */ + if (iter->direxact != UINT_MAX) + { + unsigned long start = 0; + unsigned long stop = modland_com.database.fileentries_n; + + while (1) + { + unsigned long distance = stop - start; + unsigned long half = distance / 2 + start; + + if (distance <= 1) + { + iter->fileoffset = start; + break; + } + + if (modland_com.database.fileentries[half].dirindex == iter->direxact) + { + if (modland_com.database.fileentries[half-1].dirindex >= iter->direxact) + { + stop = half; + } else { + start = half; + } + } else { + if (modland_com.database.fileentries[half].dirindex >= iter->direxact) + { + stop = half; + } else { + start = half; + } + } + } + /* if fileoffset did not find exact match, it will point to one or more directories too early */ + while ((iter->fileoffset < modland_com.database.fileentries_n) && (modland_com.database.fileentries[iter->fileoffset].dirindex < iter->direxact)) + { + iter->fileoffset++; + } + } else { + iter->fileoffset=UINT_MAX; + } + + self->head.ref (&self->head); + return iter; +} + +static ocpdirhandle_pt modland_com_ocpdir_readdir_start (struct ocpdir_t *d, + void(*callback_file)(void *token, struct ocpfile_t *), + void(*callback_dir )(void *token, struct ocpdir_t *), + void *token) +{ + return modland_com_ocpdir_readdir_start_common (d, callback_file, callback_dir, token, 0); +} + +static ocpdirhandle_pt modland_com_ocpdir_readflatdir_start (struct ocpdir_t *d, + void(*callback_file)(void *token, struct ocpfile_t *), + void *token) +{ + return modland_com_ocpdir_readdir_start_common (d, callback_file, 0, token, 1); +} + +static void modland_com_ocpdir_readdir_cancel (ocpdirhandle_pt v) +{ + struct modland_com_readdir_t *iter = (struct modland_com_readdir_t *)v; + iter->dir->head.unref (&iter->dir->head); + free (iter); +} + +static int modland_com_ocpdir_readdir_iterate (ocpdirhandle_pt v) +{ + struct modland_com_readdir_t *iter = (struct modland_com_readdir_t *)v; + + if ((!iter->sentdevs) && + (!iter->dirnamelength)) + { + iter->callback_file (iter->token, modland_com.modland_com_setup); + iter->sentdevs = 1; + } + + if (iter->flatdir) + { + int n = 0; + + while (n < 1000) + { + struct ocpfile_t *f; + + if ((iter->fileoffset >= modland_com.database.fileentries_n) || + (modland_com.database.fileentries[iter->fileoffset].dirindex >= iter->dirmax)) + { + iter->fileoffset = UINT_MAX; + return 0; + } + + f = modland_com_file_spawn (&iter->dir->head, iter->fileoffset); + if (f) + { + iter->callback_file (iter->token, f); + f->unref (f); + } + iter->fileoffset++; + n++; + } + return 1; + } + + if (iter->diroffset != UINT_MAX) + { + if ((iter->diroffset >= modland_com.database.direntries_n) || + (strncmp (modland_com.database.direntries[iter->diroffset], iter->dir->dirname, iter->dirnamelength)) || + (iter->dirnamelength && (modland_com.database.direntries[iter->diroffset][iter->dirnamelength] != '/'))) + { + iter->diroffset = UINT_MAX; + } else { + char *ptr = strchr (modland_com.database.direntries[iter->diroffset] + iter->dirnamelength + (iter->dirnamelength?1:0), '/'); + unsigned long len; + unsigned long next; + if (ptr) + { /* this should not be reachable */ + iter->diroffset++; + return 1; + } + len = strlen (modland_com.database.direntries[iter->diroffset]); + if (iter->isroot) + { + const int max = sizeof (known_root_directories) / sizeof (known_root_directories[0]); + int i; + for (i=0; i < max; i++) + { + if (!strcasecmp (known_root_directories[i], modland_com.database.direntries[iter->diroffset])) + { + break; + } + } + if (i == max) + { + goto skipdir; + } + } else if (iter->isadlib) + { + const int max = sizeof (known_adlib_directories) / sizeof (known_adlib_directories[0]); + int i; + for (i=0; i < max; i++) + { + if (!strcasecmp (known_adlib_directories[i], modland_com.database.direntries[iter->diroffset] + 7 /* strlen("Ad Lib/") */)) + { + break; + } + } + if (i == max) + { + goto skipdir; + } + } + { + struct modland_com_ocpdir_t *d = calloc (sizeof (*d), 1); + if (d) + { + iter->dir->head.ref (&iter->dir->head); + ocpdir_t_fill ( + &d->head, + modland_com_ocpdir_ref, + modland_com_ocpdir_unref, + &iter->dir->head, /* parent */ + modland_com_ocpdir_readdir_start, + modland_com_ocpdir_readflatdir_start, + modland_com_ocpdir_readdir_cancel, + modland_com_ocpdir_readdir_iterate, + 0, /* readdir_dir */ + 0, /* readdir_file */ + 0, /* charset_override_API */ + dirdbFindAndRef (iter->dir->head.dirdb_ref, modland_com.database.direntries[iter->diroffset] + iter->dirnamelength + (iter->dirnamelength?1:0), dirdb_use_dir), + 1, /* refcount */ + 0, /* is_archive */ + 0, /* is_playlist */ + 0 /* compression */ + ); + d->dirname = strdup (modland_com.database.direntries[iter->diroffset]); + if (d->dirname) + { + iter->callback_dir (iter->token, &d->head); + } + modland_com_ocpdir_unref (&d->head); + } + } + +skipdir: + next = iter->diroffset; + while (1) + { + next++; + if (next >= modland_com.database.direntries_n) + { + next = UINT_MAX; + break; + } + if ((strncmp (modland_com.database.direntries[iter->diroffset], modland_com.database.direntries[next], len)) || (modland_com.database.direntries[next][len] != '/')) + { + break; + } + } + iter->diroffset = next; + return 1; + } + } + + if (iter->fileoffset != UINT_MAX) + { + struct ocpfile_t *f; + + if ((iter->fileoffset >= modland_com.database.fileentries_n) || + (modland_com.database.fileentries[iter->fileoffset].dirindex != iter->direxact)) + { /* no more files */ + iter->fileoffset = UINT_MAX; + return 1; + } + + f = modland_com_file_spawn (&iter->dir->head, iter->fileoffset); + if (f) + { + iter->callback_file (iter->token, f); + f->unref (f); + } + + iter->fileoffset++; + return 1; + } + + return 0; +} + +static struct ocpdir_t *modland_com_init_root(void) +{ + struct modland_com_ocpdir_t *retval = calloc (sizeof (*retval), 1); + if (!retval) + { + return 0; + } + ocpdir_t_fill ( + &retval->head, + modland_com_ocpdir_ref, + modland_com_ocpdir_unref, + 0, /* parent */ + modland_com_ocpdir_readdir_start, + modland_com_ocpdir_readflatdir_start, + modland_com_ocpdir_readdir_cancel, + modland_com_ocpdir_readdir_iterate, + 0, /* readdir_dir */ + 0, /* readdir_file */ + 0, /* charset_override_API */ + dirdbFindAndRef (DIRDB_NOPARENT, "modland.com:", dirdb_use_dir), + 1, /* refcount */ + 0, /* is_archive */ + 0, /* is_playlist */ + 0 /* compression */ + ); + retval->dirname = strdup (""); + if (!retval->dirname) + { + modland_com_ocpdir_unref (&retval->head); + return 0; + } + return &retval->head; +} diff --git a/filesel/modland.com/modland-com-file.c b/filesel/modland.com/modland-com-file.c new file mode 100644 index 00000000..0559bcf4 --- /dev/null +++ b/filesel/modland.com/modland-com-file.c @@ -0,0 +1,368 @@ +struct modland_com_ocpfile_t +{ + struct ocpfile_t head; + char *filename; /* survives main database changes */ + uint32_t filesize; +}; + +static void modland_com_ocpfile_ref (struct ocpfile_t *_f) +{ + struct modland_com_ocpfile_t *f = (struct modland_com_ocpfile_t *)_f; + f->head.refcount++; +} + +static void modland_com_ocpfile_unref (struct ocpfile_t *_f) +{ + struct modland_com_ocpfile_t *f = (struct modland_com_ocpfile_t *)_f; + if (!--f->head.refcount) + { + if (f->head.parent) + { + f->head.parent->unref (f->head.parent); + f->head.parent = 0; + } + dirdbUnref (f->head.dirdb_ref, dirdb_use_file); + free (f->filename); + free (f); + } +} + +static int modland_com_ocpfile_mkdir_except_file (const char *path) +{ + char *temp = strdup (path); + char *next; + + if (!temp) + { + return -1; + } + +#ifdef _WIN32 + next = strchr (temp + 3, '\\'); + while (next) /* guards about first iteration missing the slash */ + { + struct st; + DWORD D; + if (!next[1]) + { /* should not be reachable */ + break; + } + next = strchr (next + 1, '\\'); + if (!next) + { /* last item is a file, do not create it */ + break; + } + *next = 0; + D = GetFileAttributes (temp); + if (D == INVALID_FILE_ATTRIBUTES) + { + DWORD e = GetLastError(); + if ((e != ERROR_PATH_NOT_FOUND) && (e != ERROR_FILE_NOT_FOUND)) + { + char *lpMsgBuf = NULL; + if (FormatMessage ( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, /* dwFlags */ + NULL, /* lpSource */ + e, /* dwMessageId */ + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* dwLanguageId */ + (LPSTR) &lpMsgBuf, /* lpBuffer */ + 0, /* nSize */ + NULL /* Arguments */ + )) + { + fprintf(stderr, "GetFileAttributes(%s): %s", temp, lpMsgBuf); + LocalFree (lpMsgBuf); + } + free (temp); + return -1; + } + if (!CreateDirectory (temp, 0)) + { + char *lpMsgBuf = NULL; + if (FormatMessage ( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, /* dwFlags */ + NULL, /* lpSource */ + GetLastError(), /* dwMessageId */ + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* dwLanguageId */ + (LPSTR) &lpMsgBuf, /* lpBuffer */ + 0, /* nSize */ + NULL /* Arguments */ + )) + { + fprintf(stderr, "CreateDirectory(%s): %s", temp, lpMsgBuf); + LocalFree (lpMsgBuf); + } + free (temp); + return -1; + } + } else { + if (!(D & FILE_ATTRIBUTE_DIRECTORY)) + { + fprintf (stderr, "GetFileAttributes(%s) & FILE_ATTRIBUTE_DIRECTORY failed\n", temp); + free (temp); + return -1; + } + } + *next = '\\'; + } +#else + next = strchr (temp + 1, '/'); + while (next) /* guards if initial search fails */ + { + struct stat st; + if (!next[1]) + { /* should not be reachable */ + break; + } + next = strchr (next + 1, '/'); + if (!next) + { /* last item is a file, do not create it */ + break; + } + *next = 0; + + if (stat(temp, &st)) + { + if (errno != ENOENT) + { + fprintf (stderr, "stat(%s): %s\n", temp, strerror(errno)); + free (temp); + return -1; + } + if (mkdir (temp, S_IXUSR | S_IWUSR | S_IRUSR | S_IXGRP | S_IWGRP | S_IRGRP | S_IXOTH | S_IROTH)) + { + fprintf (stderr, "mkdir(%s): %s\n", temp, strerror(errno)); + free (temp); + return -1; + } + } else { + if (!S_ISDIR(st.st_mode)) + { + fprintf (stderr, "stat(%s) => S_ISDIR failed\n", temp); + free (temp); + return -1; + } + } + *next = '/'; + } +#endif + + + free (temp); + return 0; +} + +static int curl_download_magic (const char *targetfilename, const char *sourcepath) +{ + char *url; + char *escaped; + struct download_request_t *request; + struct ocpfilehandle_t *temp_filehandle; + struct osfile_t *target; + char buffer[65536]; + int fill; + size_t len; + + escaped = urlencode (sourcepath); + if (!escaped) + { + return -1; + } + len = strlen (modland_com.mirror ? modland_com.mirror : "") + 12 + strlen (escaped) + 1; + url = malloc (len); + if (!url) + { + free (escaped); + return -1; + } + snprintf (url, len, "%spub/modules/%s", modland_com.mirror ? modland_com.mirror : "", escaped); + free (escaped); + escaped = 0; + + request = download_request_spawn (&configAPI, 0, url); + free (url); + if (!request) + { + return -1; + } + while (download_request_iterate (request)) + { + usleep (10000); + } + if (request->errmsg) + { + fprintf (stderr, "download failed: %s\n", request->errmsg); + download_request_free (request); + return -1; + } + temp_filehandle = download_request_getfilehandle (request); + download_request_free (request); + request = 0; + if (!temp_filehandle) + { + fprintf (stderr, "open download failed #2\n"); + return -1; + } + target = osfile_open_readwrite (targetfilename, 0, 0); + if (!target) + { + fprintf (stderr, "open target failed\n"); + temp_filehandle->unref (temp_filehandle); + return -1; + } + while ((fill = temp_filehandle->read (temp_filehandle, buffer, sizeof (buffer)))) + { + osfile_write (target, buffer, fill); + } + osfile_close (target); + target = 0; + + temp_filehandle->unref (temp_filehandle); + + return 0; +} + +static struct ocpfilehandle_t *modland_com_ocpfile_open (struct ocpfile_t *_f) +{ + struct modland_com_ocpfile_t *f = (struct modland_com_ocpfile_t *)_f; + struct modland_com_ocpfilehandle_t *h; + char *cachefilename; + + cachefilename = malloc (strlen (modland_com.cachepath) + 3 + 1 + 7 + 1 + strlen (f->filename) + 1); + if (!cachefilename) + { + return 0; + } + sprintf (cachefilename, "%spub/modules/%s", modland_com.cachepath, f->filename); + +#ifdef _WIN32 + { + char *tmp; + while ((tmp = strchr (cachefilename + strlen (modland_com.cachepath), '/'))) + { + *tmp = '\\'; + } + } +#else + { + char *tmp; + while ((tmp = strchr (cachefilename + strlen (modland_com.cachepath), '\\'))) + { + *tmp = '/'; + } + } +#endif + + if (modland_com_ocpfile_mkdir_except_file (cachefilename)) + { + return 0; + } + + h = calloc (sizeof (*h), 1); + if (!h) + { + free (cachefilename); + return 0; + } + + h->handle = modland_com_ocpfile_tryopen (cachefilename, f->filesize); + if (!h->handle) + { + if (curl_download_magic (cachefilename, f->filename)) + { + free (h); + free (cachefilename); + return 0; + } + h->handle = modland_com_ocpfile_tryopen (cachefilename, f->filesize); + if (!h->handle) + { + free (h); + free (cachefilename); + return 0; + } + } + free (cachefilename); + + _f->ref (_f); + dirdbRef (_f->dirdb_ref, dirdb_use_filehandle); + ocpfilehandle_t_fill + ( + &h->head, + modland_com_ocpfilehandle_ref, + modland_com_ocpfilehandle_unref, + _f, + modland_com_ocpfilehandle_seek_set, + modland_com_ocpfilehandle_getpos, + modland_com_ocpfilehandle_eof, + modland_com_ocpfilehandle_error, + modland_com_ocpfilehandle_read, + 0, /* ioctl */ + modland_com_ocpfilehandle_filesize, + modland_com_ocpfilehandle_filesize_ready, + 0, /* filename_override */ + _f->dirdb_ref, + 1 + ); + h->filesize = f->filesize; + return &h->head; +} + +static uint64_t modland_com_ocpfile_filesize (struct ocpfile_t *_f) +{ + struct modland_com_ocpfile_t *f = (struct modland_com_ocpfile_t *)_f; + return f->filesize; +} + +static int modland_com_ocpfile_filesize_ready (struct ocpfile_t *_f) +{ + return 1; +} + + +static struct ocpfile_t *modland_com_file_spawn (struct ocpdir_t *parent, unsigned int fileindex) +{ + struct modland_com_ocpfile_t *retval; + char *filename; + + filename = malloc (strlen (modland_com.database.direntries[modland_com.database.fileentries[fileindex].dirindex]) + 1 + strlen (modland_com.database.fileentries[fileindex].name) + 1); + if (!filename) + { + return 0; + } + sprintf (filename, "%s%s%s", modland_com.database.direntries[modland_com.database.fileentries[fileindex].dirindex], modland_com.database.fileentries[fileindex].dirindex ? "/":"", modland_com.database.fileentries[fileindex].name); + + retval = calloc (sizeof (*retval), 1); + if (!retval) + { + free (filename); + return 0; + } + + if (parent) + { + parent->ref (parent); + } + + ocpfile_t_fill ( + &retval->head, + modland_com_ocpfile_ref, + modland_com_ocpfile_unref, + parent, + modland_com_ocpfile_open, + modland_com_ocpfile_filesize, + modland_com_ocpfile_filesize_ready, + 0, /* filename_override */ + dirdbFindAndRef (parent ? parent->dirdb_ref : DIRDB_NOPARENT, modland_com.database.fileentries[fileindex].name, dirdb_use_file), + 1, /* refcount */ + 0, /* is_nodetect */ + COMPRESSION_REMOTE + ); + retval->filename = filename; + retval->filesize = modland_com.database.fileentries[fileindex].size; + return &retval->head; +} diff --git a/filesel/modland.com/modland-com-filedb.c b/filesel/modland.com/modland-com-filedb.c new file mode 100644 index 00000000..bb25287d --- /dev/null +++ b/filesel/modland.com/modland-com-filedb.c @@ -0,0 +1,235 @@ +#define MCDBDATAHOMEDIR configAPI->DataHomePath + +static struct osfile_t *modland_com_filedb_File = 0; + +struct __attribute__((packed)) modland_com_filedb_header_t +{ + char sig[60]; + uint8_t year_msb; + uint8_t year_lsb; + uint8_t month; + uint8_t day; +}; +static const char dbsig[60] = "Cubic Player modland.com Cache Data Base\x1B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; + +static unsigned int modland_com_filedb_save_d; +static unsigned int modland_com_filedb_save_f; + +#define d modland_com_filedb_save_d +#define f modland_com_filedb_save_f + + +static int modland_com_filedb_save_start (void) +{ + struct modland_com_filedb_header_t header; + + if (!modland_com_filedb_File) + { + return -1; + } + osfile_setpos (modland_com_filedb_File, 0); + memcpy (header.sig, dbsig, 60); + header.year_msb = modland_com.database.year >> 8; + header.year_lsb = modland_com.database.year; + header.month = modland_com.database.month; + header.day = modland_com.database.day; + if (osfile_write (modland_com_filedb_File, &header, sizeof(header)) < 0) + { + return -1; + } + + d = 0; + f = 0; + + return 0; +} + +static void modland_com_filedb_save_abort (void) +{ + osfile_purge_writeback_cache (modland_com_filedb_File); + osfile_setpos (modland_com_filedb_File, 0); + osfile_truncate_at (modland_com_filedb_File, 0); +} + +/* return values: + * -1: error + * 0: success + * 1: call again + */ +static int modland_com_filedb_save_iterate (void) +{ + for (;(d> 8; + b3[1] = (f2-f); + b3[2] = strlen (modland_com.database.direntries[d]); + if ((osfile_write (modland_com_filedb_File, b3, 3) < 0) || + (osfile_write (modland_com_filedb_File, modland_com.database.direntries[d], b3[2]) < 0)) + { + return -1; + } + for (f2=f; (f2> 24; + b4[1] = modland_com.database.fileentries[f2].size >> 16; + b4[2] = modland_com.database.fileentries[f2].size >> 8; + b4[3] = modland_com.database.fileentries[f2].size; + b1[0] = strlen(modland_com.database.fileentries[f2].name); + if ((osfile_write (modland_com_filedb_File, b4, 4) < 0) || + (osfile_write (modland_com_filedb_File, b1, 1) < 0) || + (osfile_write (modland_com_filedb_File, modland_com.database.fileentries[f2].name, b1[0]) < 0)) + { + return -1; + } + } + f=f2; + return 1; + } + + { + uint8_t b2[2]; + b2[0] = 0; + b2[1] = 0; + if (osfile_write (modland_com_filedb_File, b2, 2) < 0) + { + return -1; + } + } + + osfile_truncate_at (modland_com_filedb_File, osfile_getpos (modland_com_filedb_File)); + return 0; +} + +#undef d +#undef f + +static void modland_com_filedb_close (void) +{ + if (modland_com_filedb_File) + { + osfile_close (modland_com_filedb_File); + modland_com_filedb_File = 0; + } +} + +static int modland_com_filedb_load (const struct configAPI_t *configAPI) +{ + struct modland_com_filedb_header_t header; + char *path; + size_t len; + struct modland_com_initialize_t s = {0}; + int ok = 0; + + if (modland_com_filedb_File) + { + fprintf (stderr, "modland_com_filedb_load: Already loaded\n"); + return 1; + } + + len = strlen (MCDBDATAHOMEDIR) + strlen ("CPMDLAND.DAT") + 1; + path = malloc (len); + if (!path) + { + fprintf (stderr, "modland_com_filedb_load: malloc() failed\n"); + return 0; + } + snprintf (path, len, "%sCPMDLAND.DAT", MCDBDATAHOMEDIR); + fprintf (stderr, "Loading %s .. ", path); + + modland_com_filedb_File = osfile_open_readwrite (path, 1, 0); + free (path); + path = 0; + if (!modland_com_filedb_File) + { + fprintf (stderr, "Unable to open file\n"); + return 0; + } + + if ((len=osfile_read(modland_com_filedb_File, &header, sizeof(header))) != sizeof(header)) + { + fprintf (stderr, "No header\n"); + return 0; + } + + if (memcmp(header.sig, dbsig, sizeof(dbsig))) + { + fprintf (stderr, "Invalid header\n"); + return 0; + } + + modland_com.database.year = (header.year_msb << 8) | header.year_lsb; + modland_com.database.month = header.month; + modland_com.database.day = header.day; + + while (1) + { + uint8_t b2[2]; + uint8_t b4[4]; + uint8_t d[255+1+255+1]; + uint16_t num; + int i; + if (osfile_read (modland_com_filedb_File, b2, 2) != 2) + { + break; + } + num = (b2[0] << 8) | b2[1]; + if (!num) + { + ok = 1; + break; + } + + /* read dir stored as a pascal string */ + if (osfile_read (modland_com_filedb_File, b2, 1) != 1) + { + break; + } + if (osfile_read (modland_com_filedb_File, d, b2[0]) != b2[0]) + { + break; + } + d[b2[0]] = '/'; + + for (i=0; ihead.refcount++; +} + +static void modland_com_ocpfilehandle_unref (struct ocpfilehandle_t *_h) +{ + struct modland_com_ocpfilehandle_t *h = (struct modland_com_ocpfilehandle_t *)_h; + if (!--h->head.refcount) + { + dirdbUnref (h->head.dirdb_ref, dirdb_use_filehandle); + + if (h->head.origin) + { + h->head.origin->unref (h->head.origin); + h->head.origin = 0; + } + + if (h->handle) + { + osfile_close (h->handle); + } + free (h); + } +} + +static int modland_com_ocpfilehandle_seek_set (struct ocpfilehandle_t *_h, int64_t pos) +{ + struct modland_com_ocpfilehandle_t *h = (struct modland_com_ocpfilehandle_t *)_h; + h->error = 0; + osfile_setpos (h->handle, pos); + h->error = (osfile_getpos (h->handle) == pos) ? 0 : 1; + h->eof = h->filepos >= h->filesize; + return h->error ? -1 : 0; +} + +static uint64_t modland_com_ocpfilehandle_getpos (struct ocpfilehandle_t *_h) +{ + struct modland_com_ocpfilehandle_t *h = (struct modland_com_ocpfilehandle_t *)_h; + // return osfile_getpos (h->handle); + return h->filepos; +} + +static uint64_t modland_com_ocpfilehandle_filesize (struct ocpfilehandle_t *_h) +{ + struct modland_com_ocpfilehandle_t *h = (struct modland_com_ocpfilehandle_t *)_h; + return h->filesize; +} + +static int modland_com_ocpfilehandle_filesize_ready (struct ocpfilehandle_t *_h) +{ + return 1; +} + +static int modland_com_ocpfilehandle_read (struct ocpfilehandle_t *_h, void *dst, int len) +{ + struct modland_com_ocpfilehandle_t *h = (struct modland_com_ocpfilehandle_t *)_h; + int got; + int retval = 0; + + if (h->error) + { + return 0; + } + if (h->filepos >= h->filesize) + { + return 0; + } + if ((uint64_t)h->filepos + len > h->filesize) + { + len = h->filesize - h->filepos; + } + while (len) + { + got = osfile_read (h->handle, dst, len); + if (!got) + { + h->eof = 1; + break; + } + h->filepos += got; + len -= got; + retval += got; + } + return retval; +} + +static int modland_com_ocpfilehandle_error (struct ocpfilehandle_t *_h) +{ + struct modland_com_ocpfilehandle_t *h = (struct modland_com_ocpfilehandle_t *)_h; + + return h->error; +} + +static int modland_com_ocpfilehandle_eof (struct ocpfilehandle_t *_h) +{ + struct modland_com_ocpfilehandle_t *h = (struct modland_com_ocpfilehandle_t *)_h; + + return h->eof || (h->filepos >= h->filesize); +} + +static struct osfile_t *modland_com_ocpfile_tryopen (const char *pathname, long filesize) +{ + struct osfile_t *retval = osfile_open_readonly (pathname, 0); + + if (!retval) + { + return NULL; + } + if (osfile_getfilesize (retval) != filesize) + { + osfile_close (retval); + return NULL; + } + return retval; +} diff --git a/filesel/modland.com/modland-com-initialize.c b/filesel/modland.com/modland-com-initialize.c new file mode 100644 index 00000000..8defe98b --- /dev/null +++ b/filesel/modland.com/modland-com-initialize.c @@ -0,0 +1,520 @@ +/******************************************************************************** 1 + * 2 + * 3 + * 4 + * 5 + ######################### modland.com: intialize ######################### * 6 + # # * 7 + # [ ] Download allmods.zip metafile. # * 8 + # HTTP/2 error. A problem was detected in the HTTP2 framing layer. # * 9 + # This is somewhat generic and can be one out of several problems, # * 10 + # see the error message for details. # * 11 + + # Successfully downloaded 10000KB of data, datestamped 2024-03-04 # * 9 + # # * 10 + # # * 11 + # [ ] Parsing allmods.txt inside allmods.zip. # * 12 + # Failed to locate allmods.txt # * 13 + # # * 14 + + # Located 123456 files-entries in 12345 directories. # * 13 + # 0 invalid entries # * 14 + + # [ ] Save cache to disk # * 15 + # # * 16 + # # * 17 + # < CANCEL > < OK > # * 18 + # # * 19 + ########################################################################## * 20 + * 21 + * 22 + * 23 + * 24 +*********************************************************************************/ + + + +static void modland_com_initialize_Draw ( + struct console_t *console, + int download, /* 1 = in process, 2 = OK, 3 = Failed, see message */ + const char *download_message, + int download_size, + int year, int month, int day, + int parsing, /* 1 = in process, 2 = OK, 3 = Failed, see message */ + const char *parsing_message, + int parsing_files, + int parsing_directories, + int parsing_invalid, + int save, + const char *save_message, + int cancel, int ok +) +{ + int mlHeight = 15; + int mlWidth = 74; + + const char *download_string[3]; + int download_length[3]; + + int mlTop = (plScrHeight - mlHeight) / 2; + int mlLeft = (plScrWidth - mlWidth) / 2; + + console->DisplayFrame (mlTop++, mlLeft++, mlHeight, mlWidth, DIALOG_COLOR_FRAME, "modland.com: initialize", 0, 0, 0); + mlHeight -= 2; + mlWidth -= 2; + + mlTop++; + + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " [" "%.*o" "%c" "%.7o" "] Download allmods.zip metafile.", + download==1 ? /* WHITE */ 15 : download==2 ? /* GREEN */ 10 : /* RED */ 12, + download==1 ? '*' : download==2 ? 'v' : download==3 ? 'x' : ' '); + + if ((download == 1) && (download_size)) + { + char temp[70]; + snprintf (temp, sizeof (temp), "Downloaded %dKB", (download_size + 512 )/ 1024); + console->DisplayPrintf (mlTop++, mlLeft, 0x02, mlWidth, " %67s", temp); + mlTop++; + mlTop++; + } else if (download == 2) + { + char temp[70]; + snprintf (temp, sizeof (temp), "Successfully downloaded %dKB of data, datestamped %04d-%02d-%02d", (download_size + 512 )/ 1024, year, month, day); + console->DisplayPrintf (mlTop++, mlLeft, 0x02, mlWidth, " %67s" "%.9o", temp); + mlTop++; + mlTop++; + } else if (download == 3) + { + const char *temp = download_message ? download_message : ""; + int i; + + /* Split the download message up into 3 lines (or less) */ + + for (i = 0; i < 3; i++) + { + if (strlen (temp) <= 66) + { + download_string[i] = temp; + download_length[i] = strlen (temp); + temp += download_length[i]; + } else { + const char *iter; + for (iter = temp + 66; iter >= temp; iter--) + { + if (*iter == ' ') + { + iter++; + download_string[i] = temp; + download_length[i] = iter - temp - 1; + temp += iter - temp; + break; + } + } + } + } + + console->DisplayPrintf (mlTop++, mlLeft, 0x04, mlWidth, " %67.*s", download_length[0], download_string[0]); + console->DisplayPrintf (mlTop++, mlLeft, 0x04, mlWidth, " %67.*s", download_length[1], download_string[1]); + console->DisplayPrintf (mlTop++, mlLeft, 0x04, mlWidth, " %67.*s", download_length[2], download_string[2]); + } else { + mlTop++; + mlTop++; + mlTop++; + } + + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " [" "%.*o" "%c" "%.7o" "] Parsing allmods.txt inside allmods.zip.", + parsing==1 ? /* WHITE */ 15 : parsing==2 ? /* GREEN */ 10 : /* RED */ 12, + parsing==1 ? '*' : parsing==2 ? 'v' : parsing==3 ? 'x' : ' '); + + if ((parsing == 2) || (parsing == 1)) + { + console->DisplayPrintf (mlTop++, mlLeft, 0x02, mlWidth, " Located %d file-entries in %d directories.", parsing_files, parsing_directories); + console->DisplayPrintf (mlTop++, mlLeft, parsing_invalid ? 0x04:0x02, mlWidth, " %d invalid entries.", parsing_invalid); + } else if (parsing == 3) + { + console->DisplayPrintf (mlTop++, mlLeft, 0x02, mlWidth, " %67s", parsing_message); + mlTop++; + } else { + mlTop++; + mlTop++; + } + + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " [" "%.*o" "%c" "%.7o" "] Save cache to disk.", + save==1 ? /* WHITE */ 15 : save==2 ? /* GREEN */ 10 : /* RED */ 12, + save==1 ? '*' : save==2 ? 'v' : save==3 ? 'x' : ' '); + + if (save == 3) + { + console->DisplayPrintf (mlTop++, mlLeft, 0x02, mlWidth, " %67s", save_message); + } else { + mlTop++; + } + + mlTop++; + + console->DisplayPrintf (mlTop++, mlLeft+20, 0x07, mlWidth - 20, "%*.*o" "%s" "%0.7o" "%16C ""%*.*o" "%s" "%0.7o ", + (cancel == 2) ? 7 : 0, + (cancel == 2) ? 0 : 1, + cancel ? "< CANCEL >" : " ", + (ok == 2) ? 7 : 0, + (ok == 2) ? 0 : 1, + ok ? "< OK >" : " "); + + mlTop++; +} + +static void modland_com_initialize_Draw_Until_Enter_Or_Exit ( + const struct DevInterfaceAPI_t *API, + int download, /* 1 = in process, 2 = OK, 3 = Failed, see message */ + const char *download_message, + int download_size, + int year, int month, int day, + int parsing, /* 1 = in process, 2 = OK, 3 = Failed, see message */ + const char *parsing_message, + int parsing_files, + int parsing_directories, + int parsing_invalid, + int save, + const char *save_message +) +{ + while (1) + { + API->console->FrameLock(); + API->fsDraw(); + modland_com_initialize_Draw (API->console, download, download_message, download_size, year, month, day, + parsing, parsing_message, parsing_files, parsing_directories, parsing_invalid, + save, save_message, + 0, 2); + while (API->console->KeyboardHit()) + { + int key = API->console->KeyboardGetChar(); + switch (key) + { + case KEY_EXIT: + case KEY_ESC: + case _KEY_ENTER: + return; + } + } + } +} + +static void modland_com_initialize_Run (void **token, const struct DevInterfaceAPI_t *API) +{ + struct download_request_t *download_allmods_zip; /* do not free until done parsing, due to file being open locks the file in Windows */ + struct ocpfilehandle_t *allmods_zip_filehandle; + struct ocpdir_t *allmods_zip_dir; + uint32_t allmods_txt_dirdb_ref; + struct ocpfile_t *allmods_txt_file; + struct ocpfilehandle_t *allmods_txt; + struct textfile_t *allmods_txt_textfile; + int save_complete = 0; + const char *save_message = 0; + char save_message_buffer[50]; + + struct modland_com_initialize_t s; + + API->fsForceNextRescan(); + + memset (&s, 0, sizeof (s)); + + /* create request */ + + { + int len = strlen (modland_com.mirror ? modland_com.mirror : "") + 11 + 1; + char *url = malloc (len); + if (!url) + { + modland_com_initialize_Draw_Until_Enter_Or_Exit (API, 3, "malloc() URL failed", 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0); + return; + } + snprintf (url, len, "%sallmods.zip", modland_com.mirror ? modland_com.mirror : ""); + download_allmods_zip = download_request_spawn (API->configAPI, 0, url); + free (url); + } + if (!download_allmods_zip) + { + modland_com_initialize_Draw_Until_Enter_Or_Exit (API, 3, "Failed to create process", 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0); + return; + } + + /* wait for request to finish */ + + while (1) + { + API->console->FrameLock(); + if (!download_request_iterate (download_allmods_zip)) + { + break; + } + API->fsDraw(); + modland_com_initialize_Draw (API->console, 1, 0, download_allmods_zip->ContentLength, 0, 0, 0, /* pre-liminary size is available */ + 0, 0, 0, 0, 0, + 0, 0, + 2, 0); + while (API->console->KeyboardHit()) + { + int key = API->console->KeyboardGetChar(); + + switch (key) + { + case KEY_EXIT: + case KEY_ESC: + case _KEY_ENTER: + download_request_cancel (download_allmods_zip); + download_request_free (download_allmods_zip); + download_allmods_zip = 0; + return; + } + } + } + + /* did the request fail? */ + if (download_allmods_zip->errmsg) + { + modland_com_initialize_Draw_Until_Enter_Or_Exit (API, 3, download_allmods_zip->errmsg, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0); + download_request_free (download_allmods_zip); + download_allmods_zip = 0; + return; + } + + /* get the file */ + allmods_zip_filehandle = download_request_getfilehandle (download_allmods_zip); + if (!allmods_zip_filehandle) + { + modland_com_initialize_Draw_Until_Enter_Or_Exit (API, 2, 0, download_allmods_zip->ContentLength, download_allmods_zip->Year, download_allmods_zip->Month, download_allmods_zip->Day, + 3, "Unable to open the .ZIP file", 0, 0, 0, + 0, 0); + download_request_free (download_allmods_zip); + download_allmods_zip = 0; + return; + } + + /* open the ZIP file */ + + allmods_zip_dir = ocpdirdecompressor_check (allmods_zip_filehandle->origin, ".zip"); + allmods_zip_filehandle->unref (allmods_zip_filehandle); + allmods_zip_filehandle = 0; + + if (!allmods_zip_dir) + { + modland_com_initialize_Draw_Until_Enter_Or_Exit (API, 2, 0, download_allmods_zip->ContentLength, download_allmods_zip->Year, download_allmods_zip->Month, download_allmods_zip->Day, + 3, "File is not a valid .ZIP file", 0, 0, 0, + 0, 0); + download_request_free (download_allmods_zip); + download_allmods_zip = 0; + return; + } + + /* locate allmods.txt inside ZIP file */ + + allmods_txt_dirdb_ref = dirdbFindAndRef (allmods_zip_dir->dirdb_ref, "allmods.txt", dirdb_use_file); + allmods_txt_file = allmods_zip_dir->readdir_file (allmods_zip_dir, allmods_txt_dirdb_ref); + allmods_zip_dir->unref (allmods_zip_dir); + allmods_zip_dir = 0; + dirdbUnref (allmods_txt_dirdb_ref, dirdb_use_file); + if (!allmods_txt_file) + { + modland_com_initialize_Draw_Until_Enter_Or_Exit (API, 2, 0, download_allmods_zip->ContentLength, download_allmods_zip->Year, download_allmods_zip->Month, download_allmods_zip->Day, + 3, "Failed to locate allmods.txt inside allmods.zip", 0, 0, 0, + 0, 0); + download_request_free (download_allmods_zip); + download_allmods_zip = 0; + return; + } + + /* open allmods.txt */ + + allmods_txt = allmods_txt_file->open (allmods_txt_file); + allmods_txt_file->unref (allmods_txt_file); + allmods_txt_file = 0; + if (!allmods_txt) + { + modland_com_initialize_Draw_Until_Enter_Or_Exit (API, 2, 0, download_allmods_zip->ContentLength, download_allmods_zip->Year, download_allmods_zip->Month, download_allmods_zip->Day, + 3, "Failed to open allmods.txt inside allmods.zip", 0, 0, 0, + 0, 0); + download_request_free (download_allmods_zip); + download_allmods_zip = 0; + return; + } + + modland_com_database_clear(); + modland_com.database.year = download_allmods_zip->Year; + modland_com.database.month = download_allmods_zip->Month; + modland_com.database.day = download_allmods_zip->Day; + + /* and start to parse it as lines of text */ + + allmods_txt_textfile = textfile_start (allmods_txt); + allmods_txt->unref (allmods_txt); + allmods_txt = 0; + if (!allmods_txt_textfile) + { + modland_com_initialize_Draw_Until_Enter_Or_Exit (API, 2, 0, download_allmods_zip->ContentLength, download_allmods_zip->Year, download_allmods_zip->Month, download_allmods_zip->Day, + 3, "Failed to open allmods.txt inside allmods.zip as textfile", 0, 0, 0, + 0, 0); + download_request_free (download_allmods_zip); + download_allmods_zip = 0; + return; + } + + /* parse the text */ + + { + int n = 0; + const char *line; + int maxcount = 1000; + int nodec = 0; + + while ((line = textfile_fgets (allmods_txt_textfile))) + { + char *end; + long filesize; + + if (!strlen (line)) + { + continue; + } + + /* before ending with number */ + filesize = strtol (line, &end, 10); + if (end == line) + { + continue; + } + if (filesize <= 0) + { + continue; + } + line = end; + while ((*line == '\t') || (*line == ' ')) line++; + + modland_com_add_data_line (&s, line, filesize); + + n++; + if (n >= maxcount) + { + n = 0; + if (API->console->PollFrameLock()) + { + if ((maxcount >= 200) && (!nodec)) + { + maxcount -= 100; + } + nodec = 0; + API->fsDraw(); + + modland_com_initialize_Draw (API->console, 2, 0, download_allmods_zip->ContentLength, download_allmods_zip->Year, download_allmods_zip->Month, download_allmods_zip->Day, + 1, 0, modland_com.database.fileentries_n, modland_com.database.direntries_n, s.invalid_entries, + 0, 0, + 2, 0); + while (API->console->KeyboardHit()) + { + int key = API->console->KeyboardGetChar(); + + switch (key) + { + case KEY_EXIT: + case KEY_ESC: + case _KEY_ENTER: + textfile_stop (allmods_txt_textfile); + allmods_txt_textfile = 0; + + download_request_free (download_allmods_zip); + download_allmods_zip = 0; + + modland_com_database_clear (); + + return; + } + } + } else { + maxcount += 100; + nodec = 1; + } + } + } + } + textfile_stop (allmods_txt_textfile); + allmods_txt_textfile = 0; + + /* sort the database and finalize the database */ + + if (modland_com_sort ()) + { + modland_com_initialize_Draw_Until_Enter_Or_Exit (API, 2, 0, download_allmods_zip->ContentLength, download_allmods_zip->Year, download_allmods_zip->Month, download_allmods_zip->Day, + 2, 0, 0, 0, 0, + 3, "Out of memory"); + modland_com_database_clear (); + + download_request_free (download_allmods_zip); + download_allmods_zip = 0; + return; + } + + if (modland_com_filedb_save_start()) + { + save_complete = 2; + save_message = "Failed to initialize saving"; + } + + while (!save_complete) + { + if (API->console->PollFrameLock()) + { + API->fsDraw(); + + save_message = save_message_buffer; + snprintf (save_message_buffer, sizeof (save_message_buffer), "Written %lu of %lu file names", (unsigned long)(modland_com_filedb_save_f + 1), (unsigned long)(modland_com.database.fileentries_n)); + + modland_com_initialize_Draw (API->console, 2, 0, download_allmods_zip->ContentLength, download_allmods_zip->Year, download_allmods_zip->Month, download_allmods_zip->Day, + 1, 0, modland_com.database.fileentries_n, modland_com.database.direntries_n, s.invalid_entries, + save_complete + 1, save_message, + 2, 0); + while (API->console->KeyboardHit()) + { + int key = API->console->KeyboardGetChar(); + + switch (key) + { + case KEY_EXIT: + case KEY_ESC: + case _KEY_ENTER: + modland_com_filedb_save_abort(); + save_complete = 2; + save_message = "Save aborted"; + return; + } + } + } + switch (modland_com_filedb_save_iterate()) + { + default: + case -1: + save_message = "Writing data failed"; + save_complete = 2; + break; + case 0: + save_message = "Completed successfully"; + save_complete = 1; + break; + case 1: + break; + } + } + + /* we are finished */ + + modland_com_initialize_Draw_Until_Enter_Or_Exit (API, 2, 0, download_allmods_zip->ContentLength, download_allmods_zip->Year, download_allmods_zip->Month, download_allmods_zip->Day, + 2, 0, modland_com.database.fileentries_n, modland_com.database.direntries_n, s.invalid_entries, + save_complete + 1, save_message); + download_request_free (download_allmods_zip); + download_allmods_zip = 0; +} diff --git a/filesel/modland.com/modland-com-mirrors.c b/filesel/modland.com/modland-com-mirrors.c new file mode 100644 index 00000000..a924bae1 --- /dev/null +++ b/filesel/modland.com/modland-com-mirrors.c @@ -0,0 +1,188 @@ +static const char *modland_com_official_mirror[] = +{ + /* "https://modland.com/", not the correct name */ + /* "http://modland.com/", not the correct name */ + "https://ftp.modland.com/", /* master */ + "http://ftp.modland.com/", + "ftp://ftp.modland.com/", + "https://ftp.amigascne.org/mirrors/ftp.modland.com/", /* not announced */ + "http://ftp.amigascne.org/mirrors/ftp.modland.com/", /* not announced */ + "ftp://ftp.amigascne.org/mirrors/ftp.modland.com/", /* very slow */ + /* "https://aero.exotica.org.uk/pub/mirrors/modland/", not announced, certificate not valid, data not present */ + "http://aero.exotica.org.uk/pub/mirrors/modland/", /* not announced */ + /* ftp://aero.exotica.org.uk/pub/mirrors/modland/", unable to connect */ + /* "https://modland.antarctica.no/", not announced, certificate not valid, data IS present */ + "http://modland.antarctica.no/", +}; + +#define NUM_MIRRORS (sizeof(modland_com_official_mirror)/sizeof(modland_com_official_mirror[0])) + +static void modland_com_mirror_Draw ( + struct console_t *console, + const int origselected, + const int selected, + char **mirrorcustom, + int *editmirrorquit +) +{ +/* +********************** modland.com select mirror ************************* +* * +* Select a mirror with , and . * +* Edit custom with . Exit dialog with . * +* * +************************************************************************** +* * +* (*) https://ftp.modland.com/ * +* ( ) http://ftp.modland.com/ * +* ( ) ftp://ftp.modland.com/ * +* * +* ( ) custom: * +* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX * +* * +**************************************************************************/ + int mlHeight = 12 + NUM_MIRRORS; + int mlWidth = 74; + + int mlTop = (plScrHeight - mlHeight) / 2; + int mlLeft = (plScrWidth - mlWidth) / 2; + int i; + + console->DisplayFrame (mlTop++, mlLeft++, mlHeight, mlWidth, DIALOG_COLOR_FRAME, "modland.com: select mirror", 0, 5, 0); + mlWidth -= 2; + mlHeight -= 2; + mlTop++; + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, "Select a mirror with %.15o%.7o, %.15o%.7o and %.15o%.7o."); + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " Edit custom with %.15o%.7o. Exit dialog with %.15o%.7o."); + mlTop++; + mlTop++; // 5: horizontal line + mlTop++; + for (i=0; i < NUM_MIRRORS; i++) + { + char mirror_padded[63]; + snprintf (mirror_padded, sizeof (mirror_padded), "%s%s", + (!strncasecmp(modland_com_official_mirror[i], "ftp:", 4)) ? " " : (!strncasecmp(modland_com_official_mirror[i], "http:", 5)) ? " " : "", + modland_com_official_mirror[i]); + console->DisplayPrintf (mlTop++, mlLeft, 0x09, mlWidth, " (%.2o%c%.9o) " "%*.*o" "%*s" "%0.7o ", + (i==origselected) ? '*' : ' ', + (i==selected) ? 7 : 0, + (i==selected) ? 1 : 3, + 62, mirror_padded); + } + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " custom: "); + + if (editmirrorquit) + { + console->DisplayPrintf (mlTop, mlLeft, 0x09, 6, " (%.2o%c%.9o) ", + (origselected==NUM_MIRRORS) ? '*' : ' '); + switch (console->EditStringASCII(mlTop++, mlLeft + 6, mlWidth - 12, mirrorcustom)) + { + case -1: + case 0: + *editmirrorquit = 1; + break; + default: + case 1: + break; + } + } else { + console->DisplayPrintf (mlTop++, mlLeft, 0x09, mlWidth, " " "(%.2o%c%.9o) " "%*.*o" "%*s" "%0.7o ", + (origselected==NUM_MIRRORS) ? '*' : ' ', + (selected == NUM_MIRRORS) ? 7 : 0, + (selected == NUM_MIRRORS) ? 1 : 3, + mlWidth - 10, + *mirrorcustom); + } + + mlTop++; +} + +static void modland_com_mirror_Save (const struct DevInterfaceAPI_t *API, int selected) +{ + if (selected < NUM_MIRRORS) + { + free (modland_com.mirror); + modland_com.mirror = modland_com_strdup_slash (modland_com_official_mirror[selected]); + } else { + char *t = modland_com.mirrorcustom; + free (modland_com.mirror); + modland_com.mirror = modland_com_strdup_slash (t); + modland_com.mirrorcustom = modland_com_strdup_slash (t); + free (t); + } + + API->configAPI->SetProfileString ("modland.com", "mirror", modland_com.mirror); + API->configAPI->SetProfileString ("modland.com", "mirrorcustom", modland_com.mirrorcustom); + API->configAPI->SetProfileComment ("modland.com", "mirrorcustom", "; If a non-standard mirror has been used in the past, it is stored here"); + + API->configAPI->StoreConfig(); +} + +static void modland_com_mirror_Run (const struct DevInterfaceAPI_t *API) +{ + int selected = 0; + int origselected; + int quit = 0; + + for (selected = 0; selected < NUM_MIRRORS; selected++) + { + if (!strcasecmp (modland_com.mirror, modland_com_official_mirror[selected])) + { + break; + } + } + if (selected >= NUM_MIRRORS) + { + free (modland_com.mirrorcustom); + modland_com.mirrorcustom = strdup (modland_com.mirror); + } + origselected = selected; + + while (!quit) + { + API->fsDraw(); + modland_com_mirror_Draw (API->console, origselected, selected, &modland_com.mirrorcustom, 0); + while (API->console->KeyboardHit() && !quit) + { + int key = API->console->KeyboardGetChar(); + switch (key) + { + case KEY_EXIT: + return; + case KEY_ESC: + quit = 1; + break; + case KEY_UP: + if (selected) + { + selected--; + } + break; + case KEY_DOWN: + if (selected < NUM_MIRRORS) + { + selected++; + } + break; + case ' ': + origselected = selected; + modland_com_mirror_Save (API, selected); + break; + case _KEY_ENTER: + origselected = selected; + if (selected == NUM_MIRRORS) + { + int innerquit = 0; + while (!innerquit) + { + modland_com_mirror_Draw (API->console, origselected, selected, &modland_com.mirrorcustom, &innerquit); + API->console->FrameLock(); + } + } + modland_com_mirror_Save (API, selected); + break; + } + } + API->console->FrameLock(); + } +} diff --git a/filesel/modland.com/modland-com-removecache.c b/filesel/modland.com/modland-com-removecache.c new file mode 100644 index 00000000..2b3028f5 --- /dev/null +++ b/filesel/modland.com/modland-com-removecache.c @@ -0,0 +1,387 @@ +/* +*************** modland.com: wipe/remove cachedir ************************ +* * +* $OCPDATAHOME/modland.com (default) * +* => /home/stian/.local/share/ocp/modland.com * +* * +* 123 directories * +* 12345 files * +* 12345 KBytes * +* (and still counting) * +* * +* [remove directory] [move to recycle bin] [abort] * +* * +************************************************************************** + +*************** modland.com: wiping/removing cachedir ******************** +* * +* $OCPDATAHOME/modland.com (default) * +* => /home/stian/.local/share/ocp/modland.com * +* * +* 123 directories (and 123 failed) * +* 12345 files (and 123 failed) * +* * +* Finished * +* * +* [abort] [ok] * +* * +**************************************************************************/ + +static void modland_com_wipecache_Draw ( + struct console_t *console, + const int selected, + const char *configured_path, + const char *resolved_path, + const uint_fast32_t directories_n, + const uint_fast32_t files_n, + const uint64_t datasize, + const int stillcounting, + const int display_recycle +) +{ + int mlHeight = 13; + int mlWidth = 74; + + int mlTop = (plScrHeight - mlHeight) / 2; + int mlLeft = (plScrWidth - mlWidth) / 2; + + console->DisplayFrame (mlTop++, mlLeft++, mlHeight, mlWidth, DIALOG_COLOR_FRAME, "modland.com: wipe/remove cachedir", 0, 0, 0); + mlWidth -= 2; + mlHeight -= 2; + + mlTop++; + + console->DisplayPrintf (mlTop++, mlLeft, 0x03, mlWidth, " %71S", configured_path); + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " => %67S", resolved_path); + + mlTop++; + + console->DisplayPrintf (mlTop++, mlLeft, 0x03, mlWidth, " %"PRIuFAST32 "%.7o" " directories", directories_n); + + console->DisplayPrintf (mlTop++, mlLeft, 0x03, mlWidth, " %"PRIuFAST32 "%.7o" " files", files_n); + + if (datasize >= 4194304) + { + console->DisplayPrintf (mlTop++, mlLeft, 0x03, mlWidth, " %"PRIu64 "%.7o" " MBytes", datasize >> 20); + } else if (datasize >= 65536) + { + console->DisplayPrintf (mlTop++, mlLeft, 0x03, mlWidth, " %"PRIu64 "%.7o" " KBytes", datasize >> 10); + } else { + console->DisplayPrintf (mlTop++, mlLeft, 0x03, mlWidth, " %"PRIu64 "%.7o" " Bytes", datasize); + } + + if (stillcounting) + { + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " (and still counting)"); + } else { + mlTop++; + } + + mlTop++; + + if (stillcounting) + { + console->DisplayPrintf (mlTop++, mlLeft, 0x08, mlWidth, " " "< REMOVE DIRECTORY >" " " "< MOVE TO RECYCLE BIN >" " " "< ABORT >"); + } else { + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " " "%*.*o" "< REMOVE DIRECTORY >" "%0.7o" " " "%*.*o" "< MOVE TO RECYCLE BIN >" "%0.7o" " " "%*.*o" "< ABORT >" "%0.7o" " ", + (selected == 0) ? 7 : 0, + (selected == 0) ? 1 : 3, + (selected == 1) ? 7 : (display_recycle ? 0 : 0), + (selected == 1) ? 1 : (display_recycle ? 3 : 8), + (selected == 2) ? 7 : 0, + (selected == 2) ? 1 : 3 + ); + } + + mlTop++; +} + +static void modland_com_dowipecache_Draw ( + struct console_t *console, + const char *configured_path, + const char *resolved_path, + const uint_fast32_t directories_n, + const uint_fast32_t directories_target_n, + const uint_fast32_t directories_failed_n, + const uint_fast32_t files_n, + const uint_fast32_t files_target_n, + const uint_fast32_t files_failed_n, + const int stillremoving +) +{ + int mlHeight = 13; + int mlWidth = 74; + + int mlTop = (plScrHeight - mlHeight) / 2; + int mlLeft = (plScrWidth - mlWidth) / 2; + + console->DisplayFrame (mlTop++, mlLeft++, mlHeight, mlWidth, DIALOG_COLOR_FRAME, "modland.com: wiping/removing cachedir", 0, 0, 0); + mlHeight -= 2; + mlWidth -= 2; + + mlTop++; + + console->DisplayPrintf (mlTop++, mlLeft, 0x03, mlWidth, " %71S", configured_path); + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " %.7o=> %67S", resolved_path); + + mlTop++; + + if (directories_failed_n) + { + console->DisplayPrintf (mlTop++, mlLeft, 0x03, mlWidth, " %"PRIuFAST32 "%.7o" " of " "%.3o" "%"PRIuFAST32 "%.7o" " directories (%"PRIuFAST32" failed)", directories_n, directories_target_n, directories_failed_n); + } else { + console->DisplayPrintf (mlTop++, mlLeft, 0x03, mlWidth, " %"PRIuFAST32 "%.7o" " of " "%.3o" "%"PRIuFAST32 "%.7o" " directories", directories_n, directories_target_n); + } + + if (files_failed_n) + { + console->DisplayPrintf (mlTop++, mlLeft, 0x03, mlWidth, " %"PRIuFAST32 "%.7o" " of ""%.3o" "%"PRIuFAST32 "%.7o" " files (%"PRIuFAST32" failed)", files_n, files_target_n, files_failed_n); + } else { + console->DisplayPrintf (mlTop++, mlLeft, 0x03, mlWidth, " %"PRIuFAST32 "%.7o" " of ""%.3o" "%"PRIuFAST32 "%.7o" " files", files_n, files_target_n); + } + + mlTop++; + + if (stillremoving) + { + mlTop++; + } else { + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " Finished"); + } + + mlTop++; + + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, "%10C " "%*.*o" "[ ABORT ]" "%0.9o" "%37C " "%*.*o" "[ OK ]" "%0.7o ", + stillremoving ? 7 : 0, + stillremoving ? 1 : 8, + stillremoving ? 0 : 7, + stillremoving ? 8 : 1); + + mlTop++; +} + +/* actual delete the data */ +static void modland_com_dowipecache_Run (const struct DevInterfaceAPI_t *API, uint_fast32_t directories_target_n, uint_fast32_t files_target_n) +{ + int quit = 0; + struct osdir_delete_t d = {0}; + + if (osdir_delete_start (&d, modland_com.cachepath)) + { + goto removefilescomplete; + } + + while (!quit) + { + API->fsDraw(); + modland_com_dowipecache_Draw ( + API->console, + modland_com.cacheconfig, + modland_com.cachepath, + d.removed_directories_n + d.failed_directories_n, + directories_target_n, + d.failed_directories_n, + d.removed_files_n + d.failed_files_n, + files_target_n, + d.failed_files_n, + 1 + ); + + while (API->console->KeyboardHit() && !quit) + { + int key = API->console->KeyboardGetChar(); + switch (key) + { + case KEY_EXIT: + case KEY_ESC: + osdir_delete_cancel (&d); + return; + } + } + + if (!quit) + { + do + { + if (!osdir_delete_iterate (&d)) + { + quit = 1; + break; + } + } while (!API->console->PollFrameLock()); + } + } + +removefilescomplete: + quit = 0; + while (!quit) + { + API->fsDraw(); + modland_com_dowipecache_Draw ( + API->console, + modland_com.cacheconfig, + modland_com.cachepath, + d.removed_directories_n + d.failed_directories_n, + directories_target_n, + d.failed_directories_n, + d.removed_files_n + d.failed_files_n, + files_target_n, + d.failed_files_n, + 0 + ); + + while (API->console->KeyboardHit() && !quit) + { + int key = API->console->KeyboardGetChar(); + switch (key) + { + case _KEY_ENTER: + case KEY_EXIT: + case KEY_ESC: + quit = 1; + break; + } + } + API->console->FrameLock(); + } +} + +/* calculate */ +static void modland_com_wipecache_Run (const struct DevInterfaceAPI_t *API) +{ + int quit = 0; + int selected = 2; + int can_recycle = osdir_trash_available (modland_com.cachepath); + struct osdir_size_t s = {0}; + + if (osdir_size_start (&s, modland_com.cachepath)) + { + goto displaymenu; + } + + while (!quit) + { + API->fsDraw(); + modland_com_wipecache_Draw ( + API->console, + selected, + modland_com.cacheconfig, + modland_com.cachepath, + s.directories_n, + s.files_n, + s.files_size, + 1, + can_recycle + ); + + while (API->console->KeyboardHit() && !quit) + { + int key = API->console->KeyboardGetChar(); + switch (key) + { + case KEY_EXIT: + case KEY_ESC: + osdir_size_cancel (&s); + return; + case KEY_LEFT: + if (selected) + { + selected--; + if ((!can_recycle) && (selected == 1)) + { + selected--; + } + } + break; + case KEY_RIGHT: + if (selected < 2) + { + selected++; + if ((!can_recycle) && (selected == 1)) + { + selected++; + } + } + break; + } + } + + if (!quit) + { + do + { + if (!osdir_size_iterate (&s)) + { + quit = 1; + break; + } + } while (!API->console->PollFrameLock()); + } + } + +displaymenu: + + quit = 0; + while (!quit) + { + API->fsDraw(); + modland_com_wipecache_Draw ( + API->console, + selected, + modland_com.cacheconfig, + modland_com.cachepath, + s.directories_n, + s.files_n, + s.files_size, + 0, + can_recycle + ); + + while (API->console->KeyboardHit() && !quit) + { + int key = API->console->KeyboardGetChar(); + switch (key) + { + case KEY_EXIT: + case KEY_ESC: + quit = 1; + break; + case KEY_LEFT: + if (selected) + { + selected--; + if ((!can_recycle) && (selected == 1)) + { + selected--; + } + } + break; + case KEY_RIGHT: + if (selected < 2) + { + selected++; + if ((!can_recycle) && (selected == 1)) + { + selected++; + } + } + break; + case _KEY_ENTER: + if (selected == 0) + { + modland_com_dowipecache_Run (API, s.directories_n, s.files_n); + quit = 1; + } else if (selected == 1) + { + osdir_trash_perform (modland_com.cachepath); /* we ignore errors..... */ + quit = 1; + } else if (selected == 2) + { + quit = 1; + } + break; + } + } + API->console->FrameLock(); + } +} diff --git a/filesel/modland.com/modland-com-setup.c b/filesel/modland.com/modland-com-setup.c new file mode 100644 index 00000000..a955d6f0 --- /dev/null +++ b/filesel/modland.com/modland-com-setup.c @@ -0,0 +1,178 @@ +#if 0 + +**************************************************************************** 1 +* Use arrow keys and to navigate. to close. * 2 +* * 3 +* Current mirror: https://modland.com/ * 4 +* * 5 +* 123456 File-entries stored in database * 6 +* * 7 +* File cache is stored in $OCPDATA/modland.com => * 8 +* /home/stian/.local/share/ocp/modland.com * 9 +* * 10 +* OCP currently only shows relevant directories * 11 +* * 12 +* 1. Select mirror * 13 +* 2. Fetch database * 14 +* 2. Refresh database * 14 +* 3. Remove database * 15 +* 4. Select cache directory * 16 +* 5. Wipe cache directory * 17 +* 6. Show all directories * 18 +* 6. Show only relevant directories * 18 +**************************************************************************** 19 + +#endif + +static void modland_com_setup_Draw +( + struct console_t *console, + const int selected, + + const char *currentmirror, + const int numfileentries, + const int year, const int month, const int day, + const char *symbolicstore, + const char *resolvedstore, + const int showrelevantdirectoriesonly +) +{ + int mlHeight = 20; + int mlWidth = 74; + + int mlTop = (plScrHeight - mlHeight) / 2; + int mlLeft = (plScrWidth - mlWidth) / 2; + + console->DisplayFrame (mlTop++, mlLeft++, mlHeight, mlWidth, DIALOG_COLOR_FRAME, "modland.com: setup", 0, 0, 0); + mlWidth -= 2; + mlHeight -= 2; + + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " Use arrow keys and %.15o%.7o to navigate. %.15o%.7o to close."); + + mlTop++; + + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " Current mirror: %.2o%55S", currentmirror); + + mlTop++; + + if (numfileentries) + { + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " Database datestamp is %0.2o%04d-%02d-%02d.", year, month, day); + console->DisplayPrintf (mlTop++, mlLeft, 0x02, mlWidth, " %d" "%.7o" " file-entries stored in the database.", numfileentries); + } else { + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " No database loaded"); + mlTop++; + } + + mlTop++; + + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " File cache is stored in %.2o%S%.7o =>", symbolicstore); + console->DisplayPrintf (mlTop++, mlLeft, 0x02, mlWidth, " %71S", resolvedstore); + + mlTop++; + + if (showrelevantdirectoriesonly) + { + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " OCP currently %.2oonly shows relevant%.7o directories"); + } else { + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " OCP currently %.2oshows all%.7o directories"); + } + + mlTop++; + + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " %*.*o1.%.*o Select mirror %30C %0.7o ", (selected == 0) ? 7 : 0, (selected == 0) ? 1 : 7, (selected == 0) ? 1 : 3); + if (!numfileentries) + { + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " %*.*o2.%.*o Fetch database %30C %0.7o ", (selected == 1) ? 7 : 0, (selected == 1) ? 1 : 7, (selected == 1) ? 1 : 3); + } else { + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " %*.*o2.%.*o Refresh database %30C %0.7o ", (selected == 1) ? 7 : 0, (selected == 1) ? 1 : 7, (selected == 1) ? 1 : 3); + } + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " %*.*o3.%.*o Remove database %30C %0.7o ", (selected == 2) ? 7 : 0, (selected == 2) ? 1 : 7, (selected == 2) ? 1 : 3); + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " %*.*o4.%.*o Select cache directory %30C %0.7o ", (selected == 3) ? 7 : 0, (selected == 3) ? 1 : 7, (selected == 3) ? 1 : 3); + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " %*.*o5.%.*o Wipe cache directory %30C %0.7o ", (selected == 4) ? 7 : 0, (selected == 4) ? 1 : 7, (selected == 4) ? 1 : 3); + console->DisplayPrintf (mlTop++, mlLeft, 0x07, mlWidth, " %*.*o6.%.*o Toggle only show relevant directories%30C %0.7o ", (selected == 5) ? 7 : 0, (selected == 5) ? 1 : 7, (selected == 5) ? 1 : 3); +} + +static void modland_com_setup_Run (void **token, const struct DevInterfaceAPI_t *API) +{ + int selected = 0; + int quit = 0; + + while (!quit) + { + API->fsDraw(); + modland_com_setup_Draw (API->console, selected, modland_com.mirror, modland_com.database.fileentries_n, + modland_com.database.year, modland_com.database.month, modland_com.database.day, + modland_com.cacheconfig, modland_com.cachepath, modland_com.showrelevantdirectoriesonly); + while (API->console->KeyboardHit() && !quit) + { + int key = API->console->KeyboardGetChar(); + switch (key) + { + case KEY_EXIT: + case KEY_ESC: + quit = 1; + break; + case KEY_UP: + if (selected) + { + selected--; + } + break; + case KEY_DOWN: + if (selected < 5) + { + selected++; + } + break; + case '1': selected = 0; break; + case '2': selected = 1; break; + case '3': selected = 2; break; + case '4': selected = 3; break; + case '5': selected = 4; break; + case '6': selected = 5; break; + case _KEY_ENTER: + switch (selected) + { + case 0: + modland_com_mirror_Run (API); + break; + case 1: + { + void **innertoken = 0; + modland_com_initialize_Run (innertoken, API); + break; + } + + case 2: + { + API->fsForceNextRescan(); + modland_com_database_clear (); + if (!modland_com_filedb_save_start ()) + { + while (modland_com_filedb_save_iterate () == 1); + } + break; + } + + case 3: + modland_com_cachedir_Run (API); + break; + + case 4: + modland_com_wipecache_Run (API); + break; + + case 5: + { + modland_com.showrelevantdirectoriesonly = !modland_com.showrelevantdirectoriesonly; + API->configAPI->SetProfileBool ("modland.com", "showrelevantdirectoriesonly", modland_com.showrelevantdirectoriesonly); + API->configAPI->StoreConfig(); + break; + } + } + break; + } + } + } +} diff --git a/filesel/modland.com/modland-com.c b/filesel/modland.com/modland-com.c new file mode 100644 index 00000000..cb6bc18a --- /dev/null +++ b/filesel/modland.com/modland-com.c @@ -0,0 +1,698 @@ +#include "config.h" +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +# include +# include +#endif +#include "types.h" + +#include "boot/plinkman.h" +#include "boot/psetting.h" +#include "filesel/dirdb.h" +#include "filesel/download.h" +#include "filesel/filesystem.h" +#include "filesel/filesystem-drive.h" +#include "filesel/filesystem-file-dev.h" +#include "filesel/filesystem-textfile.h" +#include "stuff/err.h" +#include "stuff/file.h" +#include "stuff/framelock.h" +#include "stuff/poutput.h" + +struct modland_com_fileentry_t +{ + char *name; + uint32_t size; + int dirindex; +}; + +struct modland_com_database_t +{ + char *namestrings; + unsigned int namestrings_c; + unsigned int namestrings_n; + unsigned int namestrings_size; + + uint16_t year; + uint8_t month; + uint8_t day; + + unsigned int direntries_n; + unsigned int direntries_size; + char **direntries; + + unsigned int fileentries_n; + unsigned int fileentries_size; + struct modland_com_fileentry_t *fileentries; +}; + +struct modland_com_initialize_t +{ + int invalid_entries; +}; + +struct modland_com_t +{ + char *cachepath; + char *cachepathcustom; + char *cacheconfig; + char *cacheconfigcustom; + char *mirror; + char *mirrorcustom; + struct dmDrive *drive; + struct ocpdir_t *root; + struct ocpfile_t *modland_com_setup; + struct ocpfile_t *setup_modland_com; + + struct modland_com_database_t database; + + int showrelevantdirectoriesonly; +}; +struct modland_com_t modland_com; + +#define MODLAND_COM_MAXDIRLENGTH 256 /* 146 is the actual need per 1st of march 2024 */ + +static char *modland_filename_strdup (const char *src) +{ + size_t srclen = strlen (src); + char *retval; + + if (srclen >= 4096) + { + return 0; + } + + if ((modland_com.database.namestrings_n + srclen + 1) >= modland_com.database.namestrings_size) + { + unsigned int i; + char *temp = realloc (modland_com.database.namestrings, modland_com.database.namestrings_size + 65536); + if (!temp) + { + return 0; + } + modland_com.database.namestrings_size += 65536; + for (i = 0; i < modland_com.database.fileentries_n; i++) + { + modland_com.database.fileentries[i].name = temp + (modland_com.database.fileentries[i].name - modland_com.database.namestrings); + } + for (i = 0; i < modland_com.database.direntries_n; i++) + { + modland_com.database.direntries[i] = temp + (modland_com.database.direntries[i] - modland_com.database.namestrings); + } + modland_com.database.namestrings = temp; + } + retval = modland_com.database.namestrings + modland_com.database.namestrings_n; + modland_com.database.namestrings_n += srclen + 1; + modland_com.database.namestrings_c++; + strcpy (retval, src); + return retval; +} + +static void modland_com_database_clear (void) +{ + free (modland_com.database.namestrings); + modland_com.database.namestrings = 0; + modland_com.database.namestrings_c = 0; + modland_com.database.namestrings_n = 0; + modland_com.database.namestrings_size = 0; + + free (modland_com.database.fileentries); + modland_com.database.fileentries = 0; + + free (modland_com.database.direntries); + modland_com.database.direntries = 0; + + memset (&modland_com.database, 0, sizeof (modland_com.database)); +} + +static int modland_com_dir_grow (void) +{ + char **tmp = realloc (modland_com.database.direntries, (modland_com.database.direntries_size + 1024) * sizeof (char *)); + if (!tmp) + { + return -1; + } + modland_com.database.direntries_size += 1024; + modland_com.database.direntries = tmp; + return 0; +} + +#if 0 +static int modland_com_find_or_add_dir (const char *dir) +{ + int i; + for (i=0; i < modland_com.database.direntries_n; i++) + { + if (!strcmp (modland_com.database.direntries[i], dir)) + { + return i; + } + } + + if ((modland_com.database.direntries_n >= modland_com.database.direntries_size) && + modland_com_dir_grow ()) + { + return -1; + } + + modland_com.database.direntries [ modland_com.database.direntries_n ] = strdup (dir); + if (!modland_com.database.direntries [ modland_com.database.direntries_n ]) + { + return -1; + } + + return modland_com.database.direntries_n++; +} +#endif + +/* optimization, assume list is appended somewhat-sorted */ +static int modland_com_last_or_new_dir (const char *dir) +{ + if (modland_com.database.direntries_n) + { + if (!strcmp (modland_com.database.direntries[modland_com.database.direntries_n - 1], dir)) + { + return modland_com.database.direntries_n - 1; + } + } + + if ((modland_com.database.direntries_n >= modland_com.database.direntries_size) && + modland_com_dir_grow ()) + { + return -1; + } + + modland_com.database.direntries [ modland_com.database.direntries_n ] = modland_filename_strdup (dir); + if (!modland_com.database.direntries [ modland_com.database.direntries_n ]) + { + return -1; + } + + return modland_com.database.direntries_n++; +} + +static int modland_com_dir_strcmp (const char *a, const char *b) +{ + while (1) + { + if (*a == *b) + { + if (*a == 0) return 0; + a++; + b++; + continue; + } + + if (!*a) return -1; + if (!*b) return 1; + + if (*a == '/') return -1; + if (*b == '/') return 1; + + if (*a > *b) return 1; + + return -1; + } +} + +static int modland_com_sort_dir_helper(const void *__a, const void *__b) +{ + const unsigned int *_a = __a; + const unsigned int *_b = __b; + + const char *a = modland_com.database.direntries[*_a]; + const char *b = modland_com.database.direntries[*_b]; + + return modland_com_dir_strcmp (a, b); +} + +static int modland_com_sort_dir (void) +{ + unsigned int *sortindex; + unsigned int *reverseindex; + char **sortholder; + + unsigned int i; + if (modland_com.database.direntries_n <= 1) + { + return 0; + } + sortindex = malloc (modland_com.database.direntries_n * sizeof (unsigned int)); + reverseindex = malloc (modland_com.database.direntries_n * sizeof (unsigned int)); + sortholder = malloc (modland_com.database.direntries_size * sizeof (char *)); + if ((!sortindex) || (!reverseindex) || (!sortholder)) + { + free (sortindex); + free (reverseindex); + free (sortholder); + return -1; + } + + for (i=0; i < modland_com.database.direntries_n; i++) + { + sortindex[i] = i; + } + qsort (sortindex, modland_com.database.direntries_n, sizeof (unsigned int), modland_com_sort_dir_helper); + + for (i=0; i < modland_com.database.direntries_n; i++) + { + sortholder[i] = modland_com.database.direntries[sortindex[i]]; + } + free (modland_com.database.direntries); + modland_com.database.direntries = sortholder; + sortholder = 0; + + for (i=0; i < modland_com.database.direntries_n; i++) + { + reverseindex[sortindex[i]] = i; + } + + free (sortindex); + sortindex = 0; + + for (i=0; i < modland_com.database.fileentries_n; i++) + { + modland_com.database.fileentries[i].dirindex = reverseindex[modland_com.database.fileentries[i].dirindex]; + } + + free (reverseindex); + + return 0; +} + +static int modland_com_sort_file_helper(const void *_a, const void *_b) +{ + const struct modland_com_fileentry_t *a = _a; + const struct modland_com_fileentry_t *b = _b; + + if (a->dirindex > b->dirindex) return 1; + if (a->dirindex < b->dirindex) return -1; + + return 0; +} + +static int modland_com_sort_file (void) +{ + if (modland_com.database.fileentries_n <= 1) + { + return 0; + } + qsort (modland_com.database.fileentries, modland_com.database.fileentries_n, sizeof (modland_com.database.fileentries[0]), modland_com_sort_file_helper); + + return 0; +} + +static int modland_com_addparent (unsigned int offset, const int length) +{ + char *temp; + char *str; + + if ((modland_com.database.direntries_n >= modland_com.database.direntries_size) && + modland_com_dir_grow ()) + { + return -1; + } + + temp = strdup (modland_com.database.direntries[offset]); + if (!temp) + { + return -1; + } + temp [length] = 0; + str = modland_filename_strdup (temp); /* not safe to use cache string directly, since cache might reallocate, and source would be invalid */ + free (temp); + + if (!str) + { + return -1; + } + + memmove (&modland_com.database.direntries[offset+1], &modland_com.database.direntries[offset], (modland_com.database.direntries_n - offset) * sizeof (modland_com.database.direntries[0])); + modland_com.database.direntries[offset] = str; + modland_com.database.direntries_n++; + + return 0; +} + +static int modland_com_check_dir_parents (void) +{ + unsigned int curr_dir, curr_file = 0, old_dir = 0, dirs_added = 0, next_dir; + + if (!modland_com.database.direntries_n) /* empty database */ + { + return 0; + } + + for (curr_dir = 0; curr_dir < modland_com.database.direntries_n; curr_dir = next_dir) + { + int level = 0; + char *last = strrchr (modland_com.database.direntries[curr_dir], '/'); + next_dir = curr_dir + 1; + while (1) + { + if (!curr_dir) + { /* for the first entry, ensure parents, and the empty root */ + if (last) + { + long int pos = last - modland_com.database.direntries[curr_dir]; + modland_com_addparent (curr_dir, pos); + level++; + dirs_added++; + last = strrchr (modland_com.database.direntries[curr_dir], '/'); /* string cache might be relocated */ + continue; + } else if (modland_com.database.direntries[curr_dir][0]) + { + modland_com_addparent (curr_dir, 0); + level++; + dirs_added++; + last = 0; + continue; + } + } else if (last) + { /* if last is not set, root it our parent, special case that we ignore */ + long int pos = last - modland_com.database.direntries[curr_dir]; + + if (strncmp (modland_com.database.direntries[curr_dir], modland_com.database.direntries[curr_dir-1], pos) || + ((modland_com.database.direntries[curr_dir-1][pos] != 0) && (modland_com.database.direntries[curr_dir-1][pos] != '/'))) /* directory infront of this one should have same prefix, or be our parent */ + { + modland_com_addparent (curr_dir, pos); + level++; + dirs_added++; + + last = strrchr (modland_com.database.direntries[curr_dir], '/'); /* string cache might be relocated */ + continue; + } + } + break; + } + next_dir += level; + for (; (curr_file < modland_com.database.fileentries_n) && modland_com.database.fileentries[curr_file].dirindex <= old_dir; curr_file++) + { + modland_com.database.fileentries[curr_file].dirindex += dirs_added; + } + old_dir++; + } + + return 0; +} + +/* this is faster, than checking each directory when using modland_com_last_or_new_dir() */ +static void modland_com_deduplicate_dir (void) +{ + unsigned int curr_dir, curr_file = 0, old_dir = 0; + + if (!modland_com.database.direntries_n) /* empty database */ + { + return; + } + + for (curr_dir=0; curr_dir < modland_com.database.direntries_n; curr_dir++) + { + int level = 1; + while ((curr_dir < (modland_com.database.direntries_n - 1)) && + (!strcmp (modland_com.database.direntries[curr_dir], modland_com.database.direntries[curr_dir+1]))) + { + memmove (&modland_com.database.direntries[curr_dir], &modland_com.database.direntries[curr_dir+1], (modland_com.database.direntries_n - curr_dir) * sizeof (modland_com.database.direntries[0])); // here we intentionally "leak" memory from the string cache pool, since this cache does not have a free functionality + modland_com.database.direntries_n--; + level++; + } + old_dir += level; + for (; (curr_file < modland_com.database.fileentries_n) && modland_com.database.fileentries[curr_file].dirindex < old_dir; curr_file++) + { + modland_com.database.fileentries[curr_file].dirindex = curr_dir; + } + } +} + +static int modland_com_sort (void) +{ + if (modland_com_sort_dir()) + { + return -1; + } + + if (modland_com_sort_file()) + { + return -1; + } + + modland_com_deduplicate_dir(); + + if (modland_com_check_dir_parents ()) + { + return -1; + } + + return 0; +} + +static int modland_com_add_data_fileentry (struct modland_com_initialize_t *s, const char *dir, const char *filename, long filesize) +{ + int dirindex; + + dirindex = modland_com_last_or_new_dir (dir); + if (dirindex < 0) + { + return -1; + } + + if (modland_com.database.fileentries_n >= modland_com.database.fileentries_size) + { + struct modland_com_fileentry_t *tmp = realloc (modland_com.database.fileentries, (modland_com.database.fileentries_size + 4096) * sizeof (struct modland_com_fileentry_t)); + if (!tmp) + { + return -1; + } + modland_com.database.fileentries_size += 4096; + modland_com.database.fileentries = tmp; + } + + modland_com.database.fileentries[modland_com.database.fileentries_n].name = modland_filename_strdup (filename); + if (!modland_com.database.fileentries[modland_com.database.fileentries_n].name) + { + return -1; + } + modland_com.database.fileentries[modland_com.database.fileentries_n].size = filesize; + modland_com.database.fileentries[modland_com.database.fileentries_n].dirindex = dirindex; + modland_com.database.fileentries_n++; + + return 0; +} + +static int modland_com_add_data_line (struct modland_com_initialize_t *s, const char *path, long filesize) +{ + const char *last = strrchr (path, '/'); + char dir[MODLAND_COM_MAXDIRLENGTH]; + + if ((filesize <= 0) || + (path[0] == '/') || /* path starts with / */ + (!last) || /* no / in path, modland.com does not have files in the root-directory */ + (!last[1]) || /* no more data after */ + (((last - path) + 1) >= MODLAND_COM_MAXDIRLENGTH)) + { + s->invalid_entries++; + return 0; + } + + strncpy (dir, path, last - path); + dir[(last-path)] = 0; + + return modland_com_add_data_fileentry (s, dir, last + 1, filesize); +} + +static char *modland_com_strdup_slash(const char *src) +{ + char *retval; + char *e; + size_t len; + + if (!src) + { + fprintf (stderr, "modland_com_strdup_slash(src): src is NULL\n"); + return 0; + } + e = strrchr (src, +#ifdef _WIN32 + '\\' +#else + '/' +#endif + ); + + if (e && e[1]) + { + e = 0; + } + len = strlen(src) + !e + 1; + retval = malloc (len); + if (!retval) + { + fprintf (stderr, "modland_com_strdup_slash(): malloc() failed\n"); + } + snprintf (retval, len, "%s%s", src, !e ? +#ifdef _WIN32 + "\\" +#else + "/" +#endif + : ""); + return retval; +} +#include "modland-com-cachedir.c" +#include "modland-com-filehandle.c" +#include "modland-com-file.c" +#include "modland-com-filedb.c" +#include "modland-com-dir.c" +#include "modland-com-initialize.c" +#include "modland-com-mirrors.c" +#include "modland-com-removecache.c" +#include "modland-com-setup.c" + + +static int modland_com_init (struct PluginInitAPI_t *API) +{ + modland_com.cacheconfig = strdup (API->configAPI->GetProfileString ("modland.com", "cachedir", +#ifdef _WIN32 + "$OCPHOMEDATA\\modland.com\\" +#else + "$OCPHOMEDATA/modland.com/" +#endif + )); + if (!modland_com.cacheconfig) + { + return errAllocMem; + } + + modland_com.cachepath = modland_com_resolve_cachedir (API->configAPI, modland_com.cacheconfig); + if (!modland_com.cachepath) + { + return errAllocMem; + } + + modland_com.cacheconfigcustom = strdup (API->configAPI->GetProfileString ("modland.com", "cachedircustom", modland_com.cacheconfig)); + if (!modland_com.cacheconfigcustom) + { + return errAllocMem; + } + + modland_com.cachepathcustom = modland_com_resolve_cachedir (API->configAPI, modland_com.cacheconfigcustom); + if (!modland_com.cachepathcustom) + { + return errAllocMem; + } + + modland_com.showrelevantdirectoriesonly = API->configAPI->GetProfileBool ("modland.com", "showrelevantdirectoriesonly", 1, 1); + + modland_com.root = modland_com_init_root (); + modland_com.drive = RegisterDrive("modland.com:", modland_com.root, modland_com.root); + + if (!modland_com.drive) + { + return errAllocMem; + } + + modland_com_filedb_load (API->configAPI); + fprintf (stderr, "Sort CPMDLAND.DAT data .."); + modland_com_sort (); + fprintf (stderr, "Done\n"); + + modland_com.modland_com_setup = dev_file_create ( + modland_com.root, /* parent-dir */ + "setup.dev", + "setup modland.com: drive", + "", + 0, /* token */ + 0, /* Init */ + modland_com_setup_Run, + 0, /* Close */ + 0 /* Destructor */ + ); + + modland_com.setup_modland_com = dev_file_create ( + API->dmSetup->basedir, /* parent-dir */ + "modland.com.dev", + "setup modland.com: drive", + "", + 0, /* token */ + 0, /* Init */ + modland_com_setup_Run, + 0, /* Close */ + 0 /* Destructor */ + ); + API->filesystem_setup_register_file (modland_com.setup_modland_com); + + { + const char *temp = API->configAPI->GetProfileString ("modland.com", "mirror", "https://modland.com/"); + modland_com.mirror = modland_com_strdup_slash (temp); + if (!modland_com.mirror) + { + return errAllocMem; + } + + temp = API->configAPI->GetProfileString ("modland.com", "mirrorcustom", modland_com.mirror); + modland_com.mirrorcustom = modland_com_strdup_slash (temp); + if (!modland_com.mirrorcustom) + { + return errAllocMem; + } + } + + return errOk; +} + +static void modland_com_done (struct PluginCloseAPI_t *API) +{ + modland_com_filedb_close (); + + modland_com_database_clear(); + + if (modland_com.setup_modland_com) + { + API->filesystem_setup_unregister_file (modland_com.setup_modland_com); + modland_com.setup_modland_com->unref (modland_com.setup_modland_com); + modland_com.setup_modland_com = 0; + } + + if (modland_com.modland_com_setup) + { + modland_com.modland_com_setup->unref (modland_com.modland_com_setup); + modland_com.modland_com_setup = 0; + } + + if (modland_com.root) + { + modland_com.root->unref (modland_com.root); + modland_com.root = 0; + } + + if (modland_com.drive) + { + UnregisterDrive (modland_com.drive); + modland_com.drive = 0; + } + + free (modland_com.cacheconfig); + modland_com.cacheconfig = 0; + + free (modland_com.cachepath); + modland_com.cachepath = 0; + + free (modland_com.cacheconfigcustom); + modland_com.cacheconfigcustom = 0; + + free (modland_com.cachepathcustom); + modland_com.cachepathcustom = 0; + + free (modland_com.mirror); + modland_com.mirror = 0; + + free (modland_com.mirrorcustom); + modland_com.mirrorcustom = 0; +} + +DLLEXTINFO_CORE_PREFIX struct linkinfostruct dllextinfo = {.name = "modland-com", .desc = "OpenCP virtual modland.com filebrowser (c) 2024 Stian Skjelstad", .ver = DLLVERSION, .sortindex = 60, .PluginInit = modland_com_init, .PluginClose = modland_com_done}; diff --git a/ocp.ini.in b/ocp.ini.in index abbc79ce..c6708dd0 100644 --- a/ocp.ini.in +++ b/ocp.ini.in @@ -1,5 +1,5 @@ [version] - epoch=20240211 + epoch=20240510 [general] ;link= @@ -236,3 +236,8 @@ delaymode=-1 ; -1=disable 0=left 1=right 2=both delay=25 ; a number between 0 and 1000 - How much delay in ms, if delaymode is enabled chorusenabled=1 ; 0=disable 1=enable + +[modland.com] + mirror=https://ftp.modland.com + cachedir=$OCPDATAHOME@DIRSEPARATOR@modland.com@DIRSEPARATOR@ ; Can be prefixed with ~ $OCPDATAHOME $OCPDATA or $TEMP + showrelevantdirectoriesonly=1 diff --git a/playay/aytype.c b/playay/aytype.c index 06b66c68..b1c3460b 100644 --- a/playay/aytype.c +++ b/playay/aytype.c @@ -120,6 +120,7 @@ OCP_INTERNAL int ay_type_init (struct PluginInitAPI_t *API) struct moduletype mt; API->fsRegisterExt("ay"); + API->fsRegisterExt("emul"); /* modland.com */ mt.integer.i = MODULETYPE("AY"); API->fsTypeRegister (mt, AY_description, "plOpenCP", &ayPlayer);