- Fix memory leaks in the server start menu by not

creating the maplist each time it's called, but
  preserve it across several calls.

- Fix M_PushMenu a second time by taking a corner
  case into account when the requested menu is 
  opened and on the stack but not on top.
This commit is contained in:
Daniel Gibson 2012-02-26 20:21:40 +00:00
parent 32377a6b57
commit b70dc11672

View file

@ -108,8 +108,27 @@ void M_PopMenu (void) {
M_ForceMenuOff (); M_ForceMenuOff ();
} }
/*
* This crappy function maintaines a stack of opened menus.
* The steps in this horrible mess are:
*
* 1. But the game into pause if a menu is opened
*
* 2. If the requested menu is already open, close it.
*
* 3. If the requested menu is already open but not
* on top, close all menus above it and the menu
* itself. This is necessary since an instance of
* the reqeuested menu is in flight and will be
* displayed.
*
* 4. Save the previous menu on top (which was in flight)
* to the stack and make the requested menu the menu in
* flight.
*/
static void M_PushMenu ( void (*draw) (void), const char *(*key) (int) ) { static void M_PushMenu ( void (*draw) (void), const char *(*key) (int) ) {
int i; int i;
int alreadyPresent = 0;
if (Cvar_VariableValue ("maxclients") == 1 if (Cvar_VariableValue ("maxclients") == 1
&& Com_ServerState ()) && Com_ServerState ())
@ -124,16 +143,16 @@ static void M_PushMenu ( void (*draw) (void), const char *(*key) (int) ) {
/* if this menu is already present, drop back to that level /* if this menu is already present, drop back to that level
to avoid stacking menus by hotkeys */ to avoid stacking menus by hotkeys */
for (i=0 ; i<m_menudepth ; i++) for (i=0 ; i<m_menudepth ; i++)
{ {
if (m_layers[i].draw == draw && if (m_layers[i].draw == draw &&
m_layers[i].key == key) { m_layers[i].key == key) {
alreadyPresent = 1;
break; break;
} }
} }
while(i < m_menudepth) { // menu was already opened further down the stack while(alreadyPresent && i <= m_menudepth) { // menu was already opened further down the stack
// pop until we are at the point where this menu was opened the last time // pop everything above the old instance of this menu and that instance itself
M_PopMenu(); // decrements m_menudepth M_PopMenu(); // decrements m_menudepth
} }
@ -2296,8 +2315,8 @@ static void M_Menu_JoinServer_f (void) {
* ================= * =================
*/ */
static menuframework_s s_startserver_menu; static menuframework_s s_startserver_menu;
static char **mapnames; static char **mapnames = NULL;
static int nummaps; static int nummaps = 0;
static menuaction_s s_startserver_start_action; static menuaction_s s_startserver_start_action;
static menuaction_s s_startserver_dmoptions_action; static menuaction_s s_startserver_dmoptions_action;
@ -2415,67 +2434,70 @@ static void StartServer_MenuInit( void ) {
int i; int i;
FILE *fp; FILE *fp;
/* load the list of map names */ if(mapnames == NULL) { // initialize list of maps once, reuse it afterwards (=> it isn't freed)
Com_sprintf( mapsname, sizeof( mapsname ), "%s/maps.lst", FS_Gamedir() ); /* load the list of map names */
Com_sprintf( mapsname, sizeof( mapsname ), "%s/maps.lst", FS_Gamedir() );
if ( ( fp = fopen( mapsname, "rb" ) ) == 0 ) { if ( ( fp = fopen( mapsname, "rb" ) ) == 0 ) {
if ( ( length = FS_LoadFile( "maps.lst", ( void ** ) &buffer ) ) == -1 ) if ( ( length = FS_LoadFile( "maps.lst", ( void ** ) &buffer ) ) == -1 )
Com_Error( ERR_DROP, "couldn't find maps.lst\n" ); Com_Error( ERR_DROP, "couldn't find maps.lst\n" );
} else { } else {
fseek(fp, 0, SEEK_END); fseek(fp, 0, SEEK_END);
length = ftell(fp); length = ftell(fp);
fseek(fp, 0, SEEK_SET); fseek(fp, 0, SEEK_SET);
buffer = malloc( length ); buffer = malloc( length );
fread( buffer, length, 1, fp ); fread( buffer, length, 1, fp );
} }
s = buffer; s = buffer;
i = 0; i = 0;
while ( i < length ) { while ( i < length ) {
if ( s[i] == '\r' ) if ( s[i] == '\r' )
nummaps++; nummaps++;
i++; i++;
} }
if ( nummaps == 0 ) if ( nummaps == 0 )
Com_Error( ERR_DROP, "no maps in maps.lst\n" ); Com_Error( ERR_DROP, "no maps in maps.lst\n" );
mapnames = malloc( sizeof( char * ) * ( nummaps + 1 ) ); mapnames = malloc( sizeof( char * ) * ( nummaps + 1 ) );
memset( mapnames, 0, sizeof( char * ) * ( nummaps + 1 ) ); memset( mapnames, 0, sizeof( char * ) * ( nummaps + 1 ) );
s = buffer; s = buffer;
for ( i = 0; i < nummaps; i++ ) { for ( i = 0; i < nummaps; i++ ) {
char shortname[MAX_TOKEN_CHARS]; char shortname[MAX_TOKEN_CHARS];
char longname[MAX_TOKEN_CHARS]; char longname[MAX_TOKEN_CHARS];
char scratch[200]; char scratch[200];
int j, l; int j, l;
strcpy( shortname, COM_Parse( &s ) ); strcpy( shortname, COM_Parse( &s ) );
l = strlen(shortname); l = strlen(shortname);
for (j=0 ; j<l ; j++) for (j=0 ; j<l ; j++)
shortname[j] = toupper(shortname[j]); shortname[j] = toupper(shortname[j]);
strcpy( longname, COM_Parse( &s ) ); strcpy( longname, COM_Parse( &s ) );
Com_sprintf( scratch, sizeof( scratch ), "%s\n%s", longname, shortname ); Com_sprintf( scratch, sizeof( scratch ), "%s\n%s", longname, shortname );
mapnames[i] = malloc( strlen( scratch ) + 1 ); mapnames[i] = malloc( strlen( scratch ) + 1 );
strcpy( mapnames[i], scratch ); strcpy( mapnames[i], scratch );
} }
mapnames[nummaps] = 0; mapnames[nummaps] = 0;
if ( fp != 0 ) { if ( fp != 0 ) {
fp = 0; fclose(fp);
free( buffer ); fp = 0;
free( buffer );
} else { } else {
FS_FreeFile( buffer ); FS_FreeFile( buffer );
}
} }
/* initialize the menu stuff */ /* initialize the menu stuff */
@ -2592,20 +2614,6 @@ static void StartServer_MenuDraw(void) {
} }
static const char *StartServer_MenuKey( int key ) { static const char *StartServer_MenuKey( int key ) {
if ( key == K_ESCAPE ) {
if ( mapnames ) {
int i;
for ( i = 0; i < nummaps; i++ )
free( mapnames[i] );
free( mapnames );
}
mapnames = 0;
nummaps = 0;
}
return Default_MenuKey( &s_startserver_menu, key ); return Default_MenuKey( &s_startserver_menu, key );
} }