diff --git a/src/filesrch.c b/src/filesrch.c index acc176d6a..b90123d4b 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -31,6 +31,7 @@ #include "filesrch.h" #include "d_netfil.h" #include "m_misc.h" +#include "z_zone.h" #if (defined (_WIN32) && !defined (_WIN32_WCE)) && defined (_MSC_VER) && !defined (_XBOX) @@ -39,7 +40,7 @@ #include #define SUFFIX "*" -#define SLASH "\\" +#define SLASH PATHSEP #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #ifndef INVALID_FILE_ATTRIBUTES @@ -285,6 +286,15 @@ closedir (DIR * dirp) return rc; } #endif + +char menupath[1024]; +size_t menupathindex[20]; +size_t menudepthleft = 20; + +char **dirmenu; +size_t sizedirmenu; +size_t dir_on; + #if defined (_XBOX) && defined (_MSC_VER) filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth) @@ -296,6 +306,12 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want completepath = false; return FS_NOTFOUND; } + +boolean preparefilemenu(void) +{ + return false; +} + #elif defined (_WIN32_WCE) filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth) @@ -346,6 +362,11 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want #endif return FS_NOTFOUND; } + +boolean preparefilemenu(void) +{ + return false; +} #else filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth) { @@ -387,25 +408,29 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want { searchpath[searchpathindex[depthleft]]=0; dent = readdir(dirhandle[depthleft]); - if (dent) - strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name); if (!dent) + { closedir(dirhandle[depthleft++]); - else if (dent->d_name[0]=='.' && + continue; + } + + if (dent->d_name[0]=='.' && (dent->d_name[1]=='\0' || (dent->d_name[1]=='.' && dent->d_name[2]=='\0'))) { // we don't want to scan uptree + continue; } - else if (stat(searchpath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat - { - // was the file (re)moved? can't stat it - } + + // okay, now we actually want searchpath to incorporate d_name + strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name); + + if (stat(searchpath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat + ; // was the file (re)moved? can't stat it else if (S_ISDIR(fsstat.st_mode) && depthleft) { - strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name); searchpathindex[--depthleft] = strlen(searchpath) + 1; dirhandle[depthleft] = opendir(searchpath); if (!dirhandle[depthleft]) @@ -444,6 +469,135 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want free(searchname); free(searchpathindex); free(dirhandle); + return retval; } + +#define MAXEXT 5 +char ext[MAXEXT][5] = { + ".txt", ".cfg", // exec + ".wad", ".soc", ".lua"}; // addfile + +boolean preparefilemenu(void) +{ + DIR *dirhandle; + struct dirent *dent; + struct stat fsstat; + size_t pos, folderpos = 0, numfolders = 0; + + for (pos = 0; pos < sizedirmenu; pos++) + { + Z_Free(dirmenu[pos]); + dirmenu[pos] = NULL; + } + + sizedirmenu = dir_on = pos = 0; + + dirhandle = opendir(menupath); + + if (dirhandle == NULL) + return false; + + while (true) + { + menupath[menupathindex[menudepthleft]] = 0; + dent = readdir(dirhandle); + + if (!dent) + break; + else if (dent->d_name[0]=='.' && + (dent->d_name[1]=='\0' || + (dent->d_name[1]=='.' && + dent->d_name[2]=='\0'))) + continue; // we don't want to scan uptree + + strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name); + + if (stat(menupath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat + ; // was the file (re)moved? can't stat it + else // is a file or directory + { + if (!S_ISDIR(fsstat.st_mode)) + { + size_t len = strlen(dent->d_name)+1; + UINT8 i; + for (i = 0; i < MAXEXT; i++) + if (!strcasecmp(ext[i], dent->d_name+len-5)) break; + if (i == MAXEXT) continue; // not an addfile-able (or exec-able) file + } + else + numfolders++; + sizedirmenu++; + } + } + + closedir(dirhandle); // I don't know how to go back to the start of the folder without just opening and closing... if there's a way, it doesn't appear to be easily manipulatable + + if (!sizedirmenu) + return false; + + if (!(dirmenu = Z_Realloc(dirmenu, sizedirmenu*sizeof(char *), PU_STATIC, NULL))) + I_Error("Ran out of memory whilst preparing add-ons menu"); + + dirhandle = opendir(menupath); + + while ((pos+folderpos) < sizedirmenu) + { + menupath[menupathindex[menudepthleft]] = 0; + dent = readdir(dirhandle); + + if (!dent) + break; + else if (dent->d_name[0]=='.' && + (dent->d_name[1]=='\0' || + (dent->d_name[1]=='.' && + dent->d_name[2]=='\0'))) + continue; // we don't want to scan uptree + + strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name); + + if (stat(menupath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat + ; // was the file (re)moved? can't stat it + else // is a file or directory + { + char *temp; + size_t len = strlen(dent->d_name)+1; + UINT8 i = 0; + size_t folder; + + if (!S_ISDIR(fsstat.st_mode)) // file + { + for (; i < MAXEXT; i++) + if (!strcasecmp(ext[i], dent->d_name+len-5)) break; + if (i == MAXEXT) continue; // not an addfile-able (or exec-able) file + i++; // i goes up so zero-index is directory instead of .txt + folder = 0; + } + else + len += (folder = 1); + + if (len > 255) + len = 255; + + if (!(temp = Z_Malloc((len+2+folder) * sizeof (char), PU_STATIC, NULL))) + I_Error("Ran out of memory whilst preparing add-ons menu"); + temp[0] = i; + temp[1] = (UINT8)(len); + strlcpy(temp+2, dent->d_name, len); + if (folder) + { + strcpy(temp+len, "/"); + dirmenu[folderpos++] = temp; + } + else + dirmenu[numfolders + pos++] = temp; + } + } + + menupath[menupathindex[menudepthleft]] = 0; + sizedirmenu = (pos+folderpos); // crash prevention if things change between openings somehow + + closedir(dirhandle); + return true; +} #endif diff --git a/src/filesrch.h b/src/filesrch.h index 33b148d4b..c6d161597 100644 --- a/src/filesrch.h +++ b/src/filesrch.h @@ -25,4 +25,14 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth); +extern char menupath[1024]; +extern size_t menupathindex[20]; +extern size_t menudepthleft; + +extern char **dirmenu; +extern size_t sizedirmenu; +extern size_t dir_on; + +boolean preparefilemenu(void); + #endif // __FILESRCH_H__ diff --git a/src/m_menu.c b/src/m_menu.c index fb8aeedad..a3ee63ecb 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -33,6 +33,9 @@ #include "s_sound.h" #include "i_system.h" +// Addfile +#include "filesrch.h" + #include "v_video.h" #include "i_video.h" #include "keys.h" @@ -330,10 +333,12 @@ menu_t OP_NetgameOptionsDef, OP_GametypeOptionsDef; menu_t OP_MonitorToggleDef; static void M_ScreenshotOptions(INT32 choice); static void M_EraseData(INT32 choice); +static void M_Addons(INT32 choice); // Drawing functions static void M_DrawGenericMenu(void); static void M_DrawCenteredMenu(void); +static void M_DrawAddons(void); static void M_DrawSkyRoom(void); static void M_DrawChecklist(void); static void M_DrawEmblemHints(void); @@ -369,6 +374,7 @@ static boolean M_CancelConnect(void); #endif static boolean M_ExitPandorasBox(void); static boolean M_QuitMultiPlayerMenu(void); +static void M_HandleAddons(INT32 choice); static void M_HandleLevelPlatter(INT32 choice); static void M_HandleSoundTest(INT32 choice); static void M_HandleImageDef(INT32 choice); @@ -476,10 +482,11 @@ static consvar_t cv_dummymares = {"dummymares", "Overall", CV_HIDEN|CV_CALL, dum // --------- static menuitem_t MainMenu[] = { - {IT_CALL |IT_STRING, NULL, "Secrets", M_SecretsMenu, 84}, - {IT_CALL |IT_STRING, NULL, "1 player", M_SinglePlayerMenu, 92}, - {IT_SUBMENU|IT_STRING, NULL, "multiplayer", &MP_MainDef, 100}, - {IT_CALL |IT_STRING, NULL, "options", M_Options, 108}, + {IT_CALL |IT_STRING, NULL, "Secrets", M_SecretsMenu, 76}, + {IT_CALL |IT_STRING, NULL, "1 player", M_SinglePlayerMenu, 84}, + {IT_SUBMENU|IT_STRING, NULL, "multiplayer", &MP_MainDef, 92}, + {IT_CALL |IT_STRING, NULL, "options", M_Options, 100}, + {IT_CALL |IT_STRING, NULL, "addons", M_Addons, 108}, {IT_CALL |IT_STRING, NULL, "quit game", M_QuitSRB2, 116}, }; @@ -489,9 +496,15 @@ typedef enum singleplr, multiplr, options, + addons, quitdoom } main_e; +static menuitem_t MISC_AddonsMenu[] = +{ + {IT_KEYHANDLER | IT_NOTHING, NULL, "", M_HandleAddons, 0}, // dummy menuitem for the control func +}; + // --------------------------------- // Pause Menu Mode Attacking Edition // --------------------------------- @@ -1432,6 +1445,18 @@ static menuitem_t OP_MonitorToggleMenu[] = // Main Menu and related menu_t MainDef = CENTERMENUSTYLE(NULL, MainMenu, NULL, 72); +menu_t MISC_AddonsDef = +{ + NULL, + sizeof (MISC_AddonsMenu)/sizeof (menuitem_t), + &MainDef, + MISC_AddonsMenu, + M_DrawAddons, + 0, 0, + 0, + NULL +}; + menu_t MAPauseDef = PAUSEMENUSTYLE(MAPauseMenu, 40, 72); menu_t SPauseDef = PAUSEMENUSTYLE(SPauseMenu, 40, 72); menu_t MPauseDef = PAUSEMENUSTYLE(MPauseMenu, 40, 72); @@ -4414,6 +4439,123 @@ static void M_HandleImageDef(INT32 choice) // MISC MAIN MENU OPTIONS // ====================== +static void M_Addons(INT32 choice) +{ + (void)choice; + + strlcpy(menupath, srb2home, 1024); + menupathindex[(menudepthleft = 19)] = strlen(menupath) + 1; + + if (menupath[menupathindex[menudepthleft]-2] != '/') + { + menupath[menupathindex[menudepthleft]-1] = '/'; + menupath[menupathindex[menudepthleft]] = 0; + } + else + --menupathindex[menudepthleft]; + + if (!preparefilemenu()) + { + M_StartMessage(M_GetText("No files/folders found.\n\n(Press a key)\n"),NULL,MM_NOTHING); + return; + } + + MISC_AddonsDef.prevMenu = currentMenu; + M_SetupNextMenu(&MISC_AddonsDef); +} + +static void M_DrawAddons(void) +{ + INT32 x, y; + size_t i; + + // DRAW MENU + x = currentMenu->x; + y = currentMenu->y; + + V_DrawString(x, y, 0, menupath); + y += 2*SMALLLINEHEIGHT; + + for (i = dir_on; i < sizedirmenu; i++) + { + if (y > BASEVIDHEIGHT) break; + V_DrawString(x, y, 0, dirmenu[i]+2); + y += SMALLLINEHEIGHT; + } +} + +static void M_HandleAddons(INT32 choice) +{ + boolean exitmenu = false; // exit to previous menu + + switch (choice) + { + case KEY_DOWNARROW: + if (dir_on < sizedirmenu-1) + dir_on++; + S_StartSound(NULL, sfx_menu1); + break; + case KEY_UPARROW: + if (dir_on) + dir_on--; + S_StartSound(NULL, sfx_menu1); + break; + case KEY_ENTER: + if (dirmenu[dir_on][0] == 0) // folder + { + S_StartSound(NULL, sfx_strpst); + strcpy(&menupath[menupathindex[menudepthleft--]],dirmenu[dir_on]+2); + menupathindex[menudepthleft] = strlen(menupath); + menupath[menupathindex[menudepthleft]] = 0; + + if (!preparefilemenu()) + { + M_StartMessage(M_GetText("Folder is empty.\n\n(Press a key)\n"),NULL,MM_NOTHING); + menupath[menupathindex[++menudepthleft]] = 0; + if (!preparefilemenu()) + { + M_StartMessage(M_GetText("Folder no longer exists!\n\n(Press a key)\n"),NULL,MM_NOTHING); + M_SetupNextMenu(MISC_AddonsDef.prevMenu); + return; + } + } + } + else if (dirmenu[dir_on][0] >= 3) // wad/soc/lua + { + S_StartSound(NULL, sfx_strpst); + COM_BufAddText(va("addfile %s%s", menupath, dirmenu[dir_on]+2)); + } + else + S_StartSound(NULL, sfx_lose); + break; + case KEY_BACKSPACE: + if (menudepthleft < 19) + { + menupath[menupathindex[++menudepthleft]] = 0; + if (!preparefilemenu()) + { + M_StartMessage(M_GetText("Folder no longer exists!\n\n(Press a key)\n"),NULL,MM_NOTHING); + M_SetupNextMenu(MISC_AddonsDef.prevMenu); + return; + } + break; + } + case KEY_ESCAPE: + exitmenu = true; + break; + + default: + break; + } + if (exitmenu) + { + if (currentMenu->prevMenu) + M_SetupNextMenu(currentMenu->prevMenu); + else + M_ClearMenus(true); + } +} + static void M_PandorasBox(INT32 choice) { (void)choice;