[Tux4kids-commits] r276 - tuxmath/trunk/src

tholy-guest at alioth.debian.org tholy-guest at alioth.debian.org
Thu Sep 27 15:50:09 UTC 2007


Author: tholy-guest
Date: 2007-09-27 15:50:09 +0000 (Thu, 27 Sep 2007)
New Revision: 276

Modified:
   tuxmath/trunk/src/Makefile.in
   tuxmath/trunk/src/fileops.c
   tuxmath/trunk/src/setup.c
   tuxmath/trunk/src/titlescreen.c
   tuxmath/trunk/src/titlescreen.h
   tuxmath/trunk/src/tuxmath.c
   tuxmath/trunk/src/tuxmath.h
Log:
Cleanups. From biggest to smallest (only the first is "big"):

1. Beginning of a generalized menu traversing function
(choose_menu_item) in titlescreen.c.  Right now this only works with
the "lessons" menu, but the intention is to generalize it to all the
menus in titlescreen.  When completed, this should considerably reduce
the number of lines in titlescreen, and hopefully centralize
bug-stomping.  This should also fix one likely bug in handling mouse
events; details can be seen in a comment just before the main loop for
the new variable "mouse_rects_are_valid."  Of course, given its size
this patch may also introduce some new bugs...

2. Some changes in fileops (in the parsing of the lesson files)
intended to avoid buffer overflows, etc. Probably no bugs were
actually fixed here, though. I worry that the change to snprintf might
break the Windows build?

3. Register the cleanup function through atexit() so that it runs even
in case of a crash. I'm hoping this will fix cases where the video
mode gets borked on crash-exit, leaving me with a 800x640 screen.




Modified: tuxmath/trunk/src/Makefile.in
===================================================================
--- tuxmath/trunk/src/Makefile.in	2007-09-26 11:27:20 UTC (rev 275)
+++ tuxmath/trunk/src/Makefile.in	2007-09-27 15:50:09 UTC (rev 276)
@@ -1,8 +1,8 @@
-# Makefile.in generated by automake 1.10 from Makefile.am.
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
+# 2003, 2004, 2005  Free Software Foundation, Inc.
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
@@ -15,11 +15,15 @@
 @SET_MAKE@
 
 
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
 VPATH = @srcdir@
 pkgdatadir = $(datadir)/@PACKAGE@
 pkglibdir = $(libdir)/@PACKAGE@
 pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
 am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
 install_sh_DATA = $(install_sh) -c -m 644
 install_sh_PROGRAM = $(install_sh) -c
 install_sh_SCRIPT = $(install_sh) -c
@@ -66,7 +70,7 @@
 	fileops.$(OBJEXT) ConvertUTF.$(OBJEXT) SDL_extras.$(OBJEXT)
 tuxmath_OBJECTS = $(am_tuxmath_OBJECTS)
 tuxmath_LDADD = $(LDADD)
-DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
 depcomp = $(SHELL) $(top_srcdir)/depcomp
 am__depfiles_maybe = depfiles
 COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
@@ -77,24 +81,25 @@
 DIST_SOURCES = $(TuxMath_SOURCES) $(tuxmath_SOURCES)
 RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
 	html-recursive info-recursive install-data-recursive \
-	install-dvi-recursive install-exec-recursive \
-	install-html-recursive install-info-recursive \
-	install-pdf-recursive install-ps-recursive install-recursive \
-	installcheck-recursive installdirs-recursive pdf-recursive \
-	ps-recursive uninstall-recursive
+	install-exec-recursive install-info-recursive \
+	install-recursive installcheck-recursive installdirs-recursive \
+	pdf-recursive ps-recursive uninstall-info-recursive \
+	uninstall-recursive
 HEADERS = $(noinst_HEADERS)
-RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
-  distclean-recursive maintainer-clean-recursive
 ETAGS = etags
 CTAGS = ctags
 DIST_SUBDIRS = $(SUBDIRS)
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
 AMTAR = @AMTAR@
 AUTOCONF = @AUTOCONF@
 AUTOHEADER = @AUTOHEADER@
 AUTOMAKE = @AUTOMAKE@
 AWK = @AWK@
+BUILD_MINGW32_FALSE = @BUILD_MINGW32_FALSE@
+BUILD_MINGW32_TRUE = @BUILD_MINGW32_TRUE@
 CC = @CC@
 CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
@@ -109,7 +114,6 @@
 EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 GREP = @GREP@
-INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
 INSTALL_SCRIPT = @INSTALL_SCRIPT@
@@ -119,12 +123,15 @@
 LIBS = @LIBS@
 LTLIBOBJS = @LTLIBOBJS@
 MAKEINFO = @MAKEINFO@
-MKDIR_P = @MKDIR_P@
 NAME_VERSION = @NAME_VERSION@
 NSIS = @NSIS@
+NSI_BUILD_FALSE = @NSI_BUILD_FALSE@
+NSI_BUILD_TRUE = @NSI_BUILD_TRUE@
 NSI_DLL_DIR = @NSI_DLL_DIR@
 NSI_INSTALL_DIR = @NSI_INSTALL_DIR@
 NSI_TUXMATH_CONF_DIR = @NSI_TUXMATH_CONF_DIR@
+NSI_USE_TUXMATH_CONF_FALSE = @NSI_USE_TUXMATH_CONF_FALSE@
+NSI_USE_TUXMATH_CONF_TRUE = @NSI_USE_TUXMATH_CONF_TRUE@
 OBJEXT = @OBJEXT@
 PACKAGE = @PACKAGE@
 PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
@@ -145,11 +152,9 @@
 
 # SUBDIRS = po
 WINDRES = @WINDRES@
-abs_builddir = @abs_builddir@
-abs_srcdir = @abs_srcdir@
-abs_top_builddir = @abs_top_builddir@
-abs_top_srcdir = @abs_top_srcdir@
 ac_ct_CC = @ac_ct_CC@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
 am__include = @am__include@
 am__leading_dot = @am__leading_dot@
 am__quote = @am__quote@
@@ -161,7 +166,6 @@
 build_cpu = @build_cpu@
 build_os = @build_os@
 build_vendor = @build_vendor@
-builddir = @builddir@
 datadir = @datadir@
 datarootdir = @datarootdir@
 docdir = @docdir@
@@ -189,15 +193,12 @@
 psdir = @psdir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
-srcdir = @srcdir@
 sysconfdir = @sysconfdir@
 target = @target@
 target_alias = @target_alias@
 target_cpu = @target_cpu@
 target_os = @target_os@
 target_vendor = @target_vendor@
-top_builddir = @top_builddir@
-top_srcdir = @top_srcdir@
 SUBDIRS = po
 @BUILD_MINGW32_FALSE at TUXMATHRC = 
 TuxMath_SOURCES = tuxmath.c setup.c titlescreen.c game.c \
@@ -264,7 +265,7 @@
 	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
 install-binPROGRAMS: $(bin_PROGRAMS)
 	@$(NORMAL_INSTALL)
-	test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+	test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
 	@list='$(bin_PROGRAMS)'; for p in $$list; do \
 	  p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
 	  if test -f $$p \
@@ -287,10 +288,10 @@
 	-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
 TuxMath$(EXEEXT): $(TuxMath_OBJECTS) $(TuxMath_DEPENDENCIES) 
 	@rm -f TuxMath$(EXEEXT)
-	$(LINK) $(TuxMath_OBJECTS) $(TuxMath_LDADD) $(LIBS)
+	$(LINK) $(TuxMath_LDFLAGS) $(TuxMath_OBJECTS) $(TuxMath_LDADD) $(LIBS)
 tuxmath$(EXEEXT): $(tuxmath_OBJECTS) $(tuxmath_DEPENDENCIES) 
 	@rm -f tuxmath$(EXEEXT)
-	$(LINK) $(tuxmath_OBJECTS) $(tuxmath_LDADD) $(LIBS)
+	$(LINK) $(tuxmath_LDFLAGS) $(tuxmath_OBJECTS) $(tuxmath_LDADD) $(LIBS)
 
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
@@ -317,18 +318,19 @@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tuxmath.Po at am__quote@
 
 .c.o:
- at am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
- at am__fastdepCC_TRUE@	mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(COMPILE) -c $<
 
 .c.obj:
- at am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
- at am__fastdepCC_TRUE@	mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+ at am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ at am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+uninstall-info-am:
 
 # This directory's subdirectories are mostly independent; you can cd
 # into them and run `make' without going through this Makefile.
@@ -361,7 +363,8 @@
 	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
 	fi; test -z "$$fail"
 
-$(RECURSIVE_CLEAN_TARGETS):
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
 	@failcom='exit 1'; \
 	for f in x $$MAKEFLAGS; do \
 	  case $$f in \
@@ -462,21 +465,22 @@
 	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
 
 distdir: $(DISTFILES)
-	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-	list='$(DISTFILES)'; \
-	  dist_files=`for file in $$list; do echo $$file; done | \
-	  sed -e "s|^$$srcdirstrip/||;t" \
-	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
-	case $$dist_files in \
-	  */*) $(MKDIR_P) `echo "$$dist_files" | \
-			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
-			   sort -u` ;; \
-	esac; \
-	for file in $$dist_files; do \
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
 	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
 	  if test -d $$d/$$file; then \
-	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
 	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
 	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
 	    fi; \
@@ -490,7 +494,7 @@
 	list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
 	  if test "$$subdir" = .; then :; else \
 	    test -d "$(distdir)/$$subdir" \
-	    || $(MKDIR_P) "$(distdir)/$$subdir" \
+	    || $(mkdir_p) "$(distdir)/$$subdir" \
 	    || exit 1; \
 	    distdir=`$(am__cd) $(distdir) && pwd`; \
 	    top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
@@ -498,8 +502,6 @@
 	      $(MAKE) $(AM_MAKEFLAGS) \
 	        top_distdir="$$top_distdir" \
 	        distdir="$$distdir/$$subdir" \
-		am__remove_distdir=: \
-		am__skip_length_check=: \
 	        distdir) \
 	      || exit 1; \
 	  fi; \
@@ -510,7 +512,7 @@
 installdirs: installdirs-recursive
 installdirs-am:
 	for dir in "$(DESTDIR)$(bindir)"; do \
-	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
 	done
 install: install-recursive
 install-exec: install-exec-recursive
@@ -558,20 +560,12 @@
 
 install-data-am:
 
-install-dvi: install-dvi-recursive
-
 install-exec-am: install-binPROGRAMS
 
-install-html: install-html-recursive
-
 install-info: install-info-recursive
 
 install-man:
 
-install-pdf: install-pdf-recursive
-
-install-ps: install-ps-recursive
-
 installcheck-am:
 
 maintainer-clean: maintainer-clean-recursive
@@ -591,25 +585,23 @@
 
 ps-am:
 
-uninstall-am: uninstall-binPROGRAMS
+uninstall-am: uninstall-binPROGRAMS uninstall-info-am
 
-.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \
-	install-strip
+uninstall-info: uninstall-info-recursive
 
-.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
-	all all-am check check-am clean clean-binPROGRAMS \
-	clean-generic ctags ctags-recursive distclean \
-	distclean-compile distclean-generic distclean-tags distdir dvi \
-	dvi-am html html-am info info-am install install-am \
-	install-binPROGRAMS install-data install-data-am install-dvi \
-	install-dvi-am install-exec install-exec-am install-html \
-	install-html-am install-info install-info-am install-man \
-	install-pdf install-pdf-am install-ps install-ps-am \
-	install-strip installcheck installcheck-am installdirs \
-	installdirs-am maintainer-clean maintainer-clean-generic \
-	mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \
-	ps ps-am tags tags-recursive uninstall uninstall-am \
-	uninstall-binPROGRAMS
+.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \
+	clean clean-binPROGRAMS clean-generic clean-recursive ctags \
+	ctags-recursive distclean distclean-compile distclean-generic \
+	distclean-recursive distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-binPROGRAMS \
+	install-data install-data-am install-exec install-exec-am \
+	install-info install-info-am install-man install-strip \
+	installcheck installcheck-am installdirs installdirs-am \
+	maintainer-clean maintainer-clean-generic \
+	maintainer-clean-recursive mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-recursive pdf pdf-am ps ps-am \
+	tags tags-recursive uninstall uninstall-am \
+	uninstall-binPROGRAMS uninstall-info-am
 
 
 # How to make an RC file

Modified: tuxmath/trunk/src/fileops.c
===================================================================
--- tuxmath/trunk/src/fileops.c	2007-09-26 11:27:20 UTC (rev 275)
+++ tuxmath/trunk/src/fileops.c	2007-09-27 15:50:09 UTC (rev 276)
@@ -615,17 +615,24 @@
   unsigned char lesson_path[PATH_MAX];             //Path to lesson directory
   char* fgets_return_val;
   unsigned char name_buf[NAME_BUF_SIZE];
+  int nchars;
 
-  struct dirent **lesson_list_dirents;
+  struct dirent **lesson_list_dirents = NULL;
   FILE* tempFile = NULL;
 
   int i = 0;
-  int lessonIterator = 0;
+  int lessonIterator = 0;  //Iterator over matching files in lesson dir
   int length = 0;
-  int lessons = 0;
+  int lessons = 0;         //Iterator over accepted (& parsed) lesson files
 
+  num_lessons = 0;
+
   /* find the directory containing the lesson files:  */
-  sprintf(lesson_path, "%s/missions/lessons", DATA_PREFIX);
+  nchars = snprintf(lesson_path, PATH_MAX, "%s/missions/lessons", DATA_PREFIX);
+  if (nchars < 0 || nchars >= PATH_MAX) {
+    perror("formatting lesson directory");
+    return 0;
+  }
 
 #ifdef TUXMATH_DEBUG
   fprintf(stderr, "lesson_path is: %s\n", lesson_path);
@@ -644,36 +651,49 @@
     return 0;
   }
 
-  /* Allocate storage for lessons */
-  lesson_list = (lesson_entry *) malloc(num_lessons * sizeof(lesson_entry));
-  if (lesson_list == NULL) {
+  /* Allocate storage for lesson list */
+  lesson_list_titles = (unsigned char**) malloc(num_lessons * sizeof(unsigned char*));
+  lesson_list_filenames = (unsigned char**) malloc(num_lessons * sizeof(unsigned char*));
+  if (lesson_list_titles == NULL || lesson_list_filenames == NULL) {
     perror("allocating memory for lesson list");
     return 0;
   }
+  for (lessonIterator = 0; lessonIterator < num_lessons; lessonIterator++) {
+    lesson_list_titles[lessonIterator] = (unsigned char*) malloc(NAME_BUF_SIZE * sizeof(unsigned char));
+    lesson_list_filenames[lessonIterator] = (unsigned char*) malloc(NAME_BUF_SIZE * sizeof(unsigned char));
+    if (lesson_list_titles[lessonIterator] == NULL || lesson_list_filenames[lessonIterator] == NULL) {
+      perror("allocating memory for lesson filenames or titles");
+      return 0;
+    }
+  }
 
-  /* lessonIterator indexes the direntries, lessons indexes the correctly-parsed files.  If successful in parsing, lessons gets incremented */
+  /* lessonIterator indexes the direntries, lessons indexes */
+  /* the correctly-parsed files.  If successful in parsing, */
+  /* lessons gets incremented. In case of problems, we can  */
+  /* just continue onto the next entry without incrementing */
+  /* lessons, and the bad entry will get overwritten by the */
+  /* next one (or simply never used, if it was the last).   */
   for (lessonIterator = 0, lessons = 0; lessonIterator < num_lessons; lessonIterator++) {
-    /* Copy over the filename */
-    sprintf(lesson_list[lessons].filename, "%s/%s", lesson_path, lesson_list_dirents[lessonIterator]->d_name);
+    /* Copy over the filename (as a full pathname) */
+    nchars = snprintf(lesson_list_filenames[lessons], NAME_BUF_SIZE, "%s/%s", lesson_path, lesson_list_dirents[lessonIterator]->d_name);
+    if (nchars < 0 || nchars >= NAME_BUF_SIZE)
+      continue;
 
 #ifdef TUXMATH_DEBUG
-    fprintf(stderr, "Found lesson file %d:\t%s\n", lessons, lesson_list[lessons].filename);
+    fprintf(stderr, "Found lesson file %d:\t%s\n", lessons, lesson_list_filenames[lessons]);
 #endif
 
     /* load the name for the lesson from the file ... (1st line) */
-    tempFile = fopen(lesson_list[lessons].filename, "r");
-
+    tempFile = fopen(lesson_list_filenames[lessons], "r");
     if (tempFile==NULL)
     {
-      /* By leaving the current iteration without incrementing 'lessons', */
-      /* the bad file name will get clobbered next time through: */
       continue;
     }
-
     fgets_return_val = fgets(name_buf, NAME_BUF_SIZE, tempFile);
     if (fgets_return_val == NULL) {
       continue;
     }
+    fclose(tempFile);
 
 
     /* check to see if it has a \r at the end of it (dos format!) */
@@ -696,20 +716,23 @@
     }
     /* Now copy the rest of the first line into the list: */
     /* Note that "length + 1" is needed so that the final \0 is copied! */
-    memmove(&lesson_list[lessons].display_name, &name_buf[i], length + 1); 
-    fclose(tempFile);
+    memmove(lesson_list_titles[lessons], &name_buf[i], length + 1); 
 
-    free(lesson_list_dirents[lessonIterator]);
 
     /* Increment the iterator for correctly-parsed lesson files */
     lessons++;
   }
-  /* In case we didn't keep all of them, revise our estimate of how many there are */
+  /* Now free the individual dirents. We do this on a second pass */
+  /* because of the "continue" approach used to error handling.   */
+  for (lessonIterator = 0; lessonIterator < num_lessons; lessonIterator++)
+    free(lesson_list_dirents[lessonIterator]);
+  free(lesson_list_dirents);
+
+  /* In case we didn't keep all of them, revise our count of how */
+  /* many there are */
   num_lessons = lessons;
 
-  free(lesson_list_dirents);
-
-  return 1;
+  return (num_lessons > 0);  /* Success! */
 }
 
 /* Look for a high score table file in the user's homedir */

Modified: tuxmath/trunk/src/setup.c
===================================================================
--- tuxmath/trunk/src/setup.c	2007-09-26 11:27:20 UTC (rev 275)
+++ tuxmath/trunk/src/setup.c	2007-09-27 15:50:09 UTC (rev 276)
@@ -637,8 +637,14 @@
     musics[i] = NULL;
   }
 
-  free(lesson_list);
-  lesson_list = NULL;
+  for (i = 0; i < num_lessons; i++) {
+    free(lesson_list_titles[i]);
+    free(lesson_list_filenames[i]);
+  }
+  free(lesson_list_titles);
+  free(lesson_list_filenames);
+  lesson_list_titles = NULL;
+  lesson_list_filenames = NULL;
 
   // Close the audio mixer. We have to do this at least as many times
   // as it was opened.

Modified: tuxmath/trunk/src/titlescreen.c
===================================================================
--- tuxmath/trunk/src/titlescreen.c	2007-09-26 11:27:20 UTC (rev 275)
+++ tuxmath/trunk/src/titlescreen.c	2007-09-27 15:50:09 UTC (rev 276)
@@ -51,7 +51,8 @@
 } blits[MAX_UPDATES];
 
 // Lessons available for play
-lesson_entry* lesson_list = NULL;
+unsigned char **lesson_list_titles;
+unsigned char **lesson_list_filenames;
 int num_lessons = 0;
 
 // globals from tuxtype's globals.h defined outside of titlescreen.c (in tuxtype):
@@ -1415,74 +1416,135 @@
 
 
 
-/* choose_config_file() - adapted from chooseWordlist() from tuxtype. */
 /* Display a list of tuxmath config files in the missions directory   */
 /* and allow the player to pick one (AKA "Lessons").                  */
 
-/* returns 0 if user pressed escape (or if dir not found)
+/* returns 0 if user pressed escape
  *         1 if config was set correctly
  */
 int choose_config_file(void)
 {
-  SDL_Surface **titles = NULL;
-  SDL_Surface **select = NULL;
+  int chosen_lesson = -1;
+  menu_options menu_opts;
 
-  SDL_Rect leftRect, rightRect;
-  SDL_Rect titleRects[8];               //8 lessons displayed per page 
-  SDL_Rect lesson_menu_button[8];      // Translucent mouse "buttons"
+  menu_opts.n_entries_per_screen = 8;
+  menu_opts.starting_entry = 0;
 
-  Uint32 frame = 0;                             //For keeping frame rate constant 
-  Uint32 frame_start = 0;
+  chosen_lesson = choose_menu_item(lesson_list_titles,num_lessons,menu_opts);
+  while (chosen_lesson >= 0) {
+    if (Opts_MenuSound())
+      {tuxtype_playsound(sounds[SND_POP]);}
+    
+    /* Re-read global settings first in case any settings were */
+    /* clobbered by other lesson or arcade games this session: */
+    read_global_config_file();
+    
+    /* Now read the selected file and play the "mission": */ 
+    if (read_named_config_file(lesson_list_filenames[chosen_lesson]))
+      {
+	if (Opts_MenuMusic())  //Turn menu music off for game
+	  {audioMusicUnload();}
+	
+	game();
+	
+	if (Opts_MenuMusic()) //Turn menu music back on
+	  {audioMusicLoad( "tuxi.ogg", -1 );}
+      }
+    else  // Something went wrong - could not read config file:
+      {
+	fprintf(stderr, "\nCould not find file: %s\n", lesson_list_filenames[chosen_lesson]);
+	chosen_lesson = -1;
+      }
+    // Let the user choose another lesson; start with the screen and
+    // selection that we ended with
+    menu_opts.starting_entry = chosen_lesson;
+    chosen_lesson = choose_menu_item(lesson_list_titles,num_lessons,menu_opts);
+  }
+  if (chosen_lesson < 0)
+    return 0;
+  else
+    return 1;
+}
+
+
+/****************************************************************/
+/* choose_menu_item: menu navigation utility function           */
+/****************************************************************/
+int choose_menu_item(const unsigned char** menu_text,int n_menu_entries,menu_options menu_opts)
+{
+  // Pixel renderings of menu text choices
+  SDL_Surface **menu_item_unselected = NULL;
+  SDL_Surface **menu_item_selected = NULL;
+  // Display region for menu choices
+  SDL_Rect *menu_text_rect = NULL;
+  // Translucent mouse "buttons" around menu text
+  SDL_Rect *menu_mouse_button_rect = NULL;
+
+  SDL_Rect left_arrow_rect, right_arrow_rect;
+
+  Uint32 frame_counter = 0;
+  Uint32 frame_start = 0;       //For keeping frame rate constant 
+  Uint32 frame_now = 0;
   int stop = 0;
-  int loc = 0;                                  //The currently selected lesson file
+  int loc = 0;                  //The currently selected menu item
   int old_loc = 1;
+  int loc_screen_start;         //The number of the top entry on current screen
   int redraw = 0;
   int i = 0;
+  int imod = 0;                 // i % n_entries_per_screen
   int tux_frame = 0;
   int click_flag = 1;
+  int mouse_rects_are_valid = 0;
 
+#ifdef TUXMATH_DEBUG
+  fprintf(stderr, "Entering choose_menu_item():\n");
+#endif
 
 #ifdef TUXMATH_DEBUG
-  fprintf(stderr, "Entering choose_config_file():\n");
+  fprintf(stderr,"%d menu entries:\n",n_menu_entries);
+  for (i = 0; i < n_menu_entries; i++)
+    fprintf(stderr,"%s\n",menu_text[i]);
 #endif
 
-  /* Display the list of lessons for the player to select: */
-  titles = (SDL_Surface**)malloc(num_lessons * sizeof(SDL_Surface*));
-  select = (SDL_Surface**)malloc(num_lessons * sizeof(SDL_Surface*));
+  /**** Memory allocation                                     ****/
+  menu_item_unselected = (SDL_Surface**)malloc(n_menu_entries * sizeof(SDL_Surface*));
+  menu_item_selected = (SDL_Surface**)malloc(n_menu_entries * sizeof(SDL_Surface*));
+  menu_text_rect = (SDL_Rect*) malloc(menu_opts.n_entries_per_screen*sizeof(SDL_Rect));
+  menu_mouse_button_rect = (SDL_Rect*) malloc(menu_opts.n_entries_per_screen*sizeof(SDL_Rect));
 
-  if (titles == NULL || select == NULL) {
-    free(titles);
-    free(select);
-    return 0;
+  if (menu_item_unselected == NULL || menu_item_selected == NULL
+      || menu_text_rect == NULL || menu_mouse_button_rect == NULL) {
+    free(menu_item_unselected);
+    free(menu_item_selected);
+    free(menu_text_rect);
+    free(menu_mouse_button_rect);
+    return -2;  // error
   }
-  for (i = 0; i < num_lessons; i++)
+
+  /**** Render the menu choices                               ****/
+  for (i = 0; i < n_menu_entries; i++)
   {
-    titles[i] = BlackOutline( _(lesson_list[i].display_name), default_font, &white );
-    select[i] = BlackOutline( _(lesson_list[i].display_name), default_font, &yellow);
+    menu_item_unselected[i] = BlackOutline( _(menu_text[i]), default_font, &white );
+    menu_item_selected[i] = BlackOutline( _(menu_text[i]), default_font, &yellow);
   }
 
-//   if (images[IMG_MENU_BKG])
-//   {
-//     SDL_FreeSurface(images[IMG_MENU_BKG]);
-//   }
-//   bkg = LoadImage("title/main_bkg.jpg", IMG_REGULAR);
-
-  /* Put arrow buttons in right lower corner, inset by 20 pixels */
+  /**** Define the locations of graphical elements on the screen ****/
+  /* Arrow buttons in right lower corner, inset by 20 pixels     */
   /* with a 10 pixel space between:                              */
   if (images[IMG_RIGHT])
   {
-    rightRect.w = images[IMG_RIGHT]->w;
-    rightRect.h = images[IMG_RIGHT]->h;
-    rightRect.x = screen->w - images[IMG_RIGHT]->w - 20;
-    rightRect.y = screen->h - images[IMG_RIGHT]->h - 20;
+    right_arrow_rect.w = images[IMG_RIGHT]->w;
+    right_arrow_rect.h = images[IMG_RIGHT]->h;
+    right_arrow_rect.x = screen->w - images[IMG_RIGHT]->w - 20;
+    right_arrow_rect.y = screen->h - images[IMG_RIGHT]->h - 20;
   }
 
   if (images[IMG_LEFT])
   {
-    leftRect.w = images[IMG_LEFT]->w;
-    leftRect.h = images[IMG_LEFT]->h;
-    leftRect.x = rightRect.x - 10 - images[IMG_LEFT]->w;
-    leftRect.y = screen->h - images[IMG_LEFT]->h - 20;
+    left_arrow_rect.w = images[IMG_LEFT]->w;
+    left_arrow_rect.h = images[IMG_LEFT]->h;
+    left_arrow_rect.x = right_arrow_rect.x - 10 - images[IMG_LEFT]->w;
+    left_arrow_rect.y = screen->h - images[IMG_LEFT]->h - 20;
   }
   /* Red "Stop" circle in upper right corner to go back to main menu: */
   if (images[IMG_STOP])
@@ -1493,17 +1555,18 @@
     stopRect.y = 0;
   }
 
-  /* set initial title rect sizes */
-  titleRects[0].y = 20;
-  titleRects[0].w = titleRects[0].h = titleRects[0].x = 0;
+  /* Set initial menu text rect sizes. The widths will change depending */
+  /* on the size of the text displayed in each rect.                    */
+  menu_text_rect[0].y = 20;
+  menu_text_rect[0].w = menu_text_rect[0].h = menu_text_rect[0].x = 0;
 
-  for (i = 1; i < 8; i++)
+  for (i = 1; i < menu_opts.n_entries_per_screen; i++)
   { 
-    titleRects[i].y = titleRects[i - 1].y + 55;
-    titleRects[i].w = titleRects[i].h = titleRects[i].x = 0;
+    menu_text_rect[i].y = menu_text_rect[i - 1].y + 55;
+    menu_text_rect[i].w = menu_text_rect[i].h = menu_text_rect[i].x = 0;
   }
 
-  /* Set up background, title, and Tux: */
+  /**** Draw background, title, and Tux:                            ****/
   if (images[IMG_MENU_BKG])
     SDL_BlitSurface(images[IMG_MENU_BKG], NULL, screen, NULL);
   if (images[IMG_MENU_TITLE])
@@ -1513,15 +1576,30 @@
   SDL_UpdateRect(screen, 0, 0, 0 ,0);
 
 //   /* Move mouse to top button: */
-//   cursor.x = screen->w/2; //titleRects[1].x + (menu_button[1].w / 2);
-//   cursor.y = titleRects[0].y + 20; //+ (3 * menu_button[1].h / 4);
+//   cursor.x = screen->w/2; //menu_text_rect[1].x + (menu_button[1].w / 2);
+//   cursor.y = menu_text_rect[0].y + 20; //+ (3 * menu_button[1].h / 4);
 //   SDL_WarpMouse(cursor.x, cursor.y);
 //   SDL_WM_GrabInput(SDL_GRAB_OFF);
 
+
+
+  /* Remaining initialization */
+  loc = menu_opts.starting_entry;  // Choose initial selected item
+  // On the first pass through, various rectangles will not yet
+  // have been customized for the proper text size, although they
+  // will be set after the first frame. However, some of the mouse
+  // handling needs these rectangles. The simplest approach is to
+  // ignore those mouse events on the first frame
+  mouse_rects_are_valid = 0;
+
+
+  /******** Main loop:                                *********/
   while (!stop)
   {
-    frame_start = SDL_GetTicks();         /* For keeping frame rate constant. */
+    frame_start = SDL_GetTicks();         /* For keeping frame rate constant.*/
 
+    loc_screen_start = loc - (loc % menu_opts.n_entries_per_screen);
+
     while (SDL_PollEvent(&event))
     {
       switch (event.type)
@@ -1535,24 +1613,24 @@
  
         case SDL_MOUSEMOTION:
         {
-          for (i = 0; (i < 8) && (loc -(loc % 8) + i < num_lessons); i++)
+          for (i = 0; (i < menu_opts.n_entries_per_screen) && (loc_screen_start + i < n_menu_entries); i++)
           {
-            if (inRect(lesson_menu_button[i], event.motion.x, event.motion.y))
+            if (mouse_rects_are_valid && inRect(menu_mouse_button_rect[i], event.motion.x, event.motion.y))
             {
               // Play sound if loc is being changed:
-              if (Opts_MenuSound() && (loc != loc - (loc % 8) + i)) 
+              if (Opts_MenuSound() && (loc != loc_screen_start + i)) 
               {
                 tuxtype_playsound(sounds[SND_TOCK]);
               }
-              loc = loc - (loc % 8) + i;
+              loc = loc_screen_start + i;
               break;
             }
           }
 
           /* "Left" button - make click if button active: */
-          if (inRect(leftRect, event.motion.x, event.motion.y))
+          if (inRect(left_arrow_rect, event.motion.x, event.motion.y))
           {
-            if (loc - (loc % 8) - 8 >= 0)
+            if (loc_screen_start - menu_opts.n_entries_per_screen >= 0)
             {
               if (Opts_MenuSound() && click_flag)
               {
@@ -1564,9 +1642,9 @@
           }
 
           /* "Right" button - go to next page: */
-          else if (inRect( rightRect, event.motion.x, event.motion.y ))
+          else if (inRect(right_arrow_rect, event.motion.x, event.motion.y ))
           {
-            if (loc - (loc % 8) + 8 < num_lessons)
+            if (loc_screen_start + menu_opts.n_entries_per_screen < n_menu_entries)
             {
               if (Opts_MenuSound() && click_flag)
               {
@@ -1585,53 +1663,30 @@
 
         case SDL_MOUSEBUTTONDOWN:
         {
-          /* Lesson buttons - play game with corresponding lesson file: */
-          for (i = 0; (i < 8) && (loc - (loc % 8) + i < num_lessons); i++)
+          /* Choose a menu entry by mouse click */
+          for (i = 0; (i < menu_opts.n_entries_per_screen) && (loc_screen_start + i < n_menu_entries); i++)
           {
-            if (inRect(lesson_menu_button[i], event.button.x, event.button.y))
+            if (mouse_rects_are_valid && inRect(menu_mouse_button_rect[i], event.button.x, event.button.y))
             {
               if (Opts_MenuSound())
               {
                   tuxtype_playsound(sounds[SND_POP]);
               }
 
-              loc = loc - (loc % 8) + i;
-
-              /* Re-read global settings first in case any settings were */
-              /* clobbered by other lesson or arcade games this session: */
-              read_global_config_file();
-
-              /* Now read the selected file and play the "mission": */ 
-              if (read_named_config_file(lesson_list[loc].filename))
-              {
-                if (Opts_MenuMusic())  //Turn menu music off for game
-                {
-                  audioMusicUnload();
-                }
-
-                game();
-
-                if (Opts_MenuMusic()) //Turn menu music back on
-                {
-                  audioMusicLoad( "tuxi.ogg", -1 );
-                }
-                redraw = 1;
-              }
-              else  // Something went wrong - could not read config file:
-              {
-                fprintf(stderr, "\nCould not find file: %s\n", lesson_list[loc].filename);
-                stop = 1;
-              }
-              break;
+              loc = loc_screen_start + i;
+	      stop = 1;
+	      break;
             }
           }
         
           /* "Left" button - go to previous page: */
-          if (inRect(leftRect, event.button.x, event.button.y))
+          if (inRect(left_arrow_rect, event.button.x, event.button.y))
           {
-            if (loc - (loc % 8) - 8 >= 0)
+            if (loc_screen_start - menu_opts.n_entries_per_screen >= 0)
             {
-              loc = loc - (loc % 8) - 8;
+	      fprintf(stderr,"Old loc: %d",loc);
+              loc = loc_screen_start - menu_opts.n_entries_per_screen;
+	      fprintf(stderr,"    New loc: %d\n",loc);
               if (Opts_MenuSound())
               {
                 tuxtype_playsound(sounds[SND_TOCK]);
@@ -1641,11 +1696,13 @@
           }
 
           /* "Right" button - go to next page: */
-          if (inRect( rightRect, event.button.x, event.button.y ))
+          if (inRect( right_arrow_rect, event.button.x, event.button.y ))
           {
-            if (loc - (loc % 8) + 8 < num_lessons)
+            if (loc_screen_start + menu_opts.n_entries_per_screen < n_menu_entries)
             {
-              loc = loc - (loc % 8) + 8;
+	      fprintf(stderr,"Old loc: %d",loc);
+              loc = loc_screen_start + menu_opts.n_entries_per_screen;
+	      fprintf(stderr,"    New loc: %d\n",loc);
               if (Opts_MenuSound())
               {
                 tuxtype_playsound(sounds[SND_TOCK]);
@@ -1681,28 +1738,7 @@
             {
               if (Opts_MenuSound())
                 {tuxtype_playsound(sounds[SND_POP]);}
-
-              /* Re-read global settings first in case any settings were */
-              /* clobbered by other lesson or arcade games this session: */
-              read_global_config_file();
-
-              /* Now read the selected file and play the "mission": */ 
-              if (read_named_config_file(lesson_list[loc].filename))
-              {
-                if (Opts_MenuMusic())  //Turn menu music off for game
-                  {audioMusicUnload();}
-
-                game();
-
-                if (Opts_MenuMusic()) //Turn menu music back on
-                  {audioMusicLoad( "tuxi.ogg", -1 );}
-                redraw = 1;
-              }
-              else  // Something went wrong - could not read config file:
-              {
-                fprintf(stderr, "\nCould not find file: %s\n", lesson_list[loc].filename);
-                stop = 1;
-              }
+	      stop = 1;
               break;
             }
 
@@ -1713,8 +1749,8 @@
             {
               if (Opts_MenuSound())
                 {tuxtype_playsound(sounds[SND_TOCK]);}
-              if (loc - (loc % 8) - 8 >= 0)
-                {loc = loc - (loc % 8) - 8;}
+              if (loc_screen_start - menu_opts.n_entries_per_screen >= 0)
+                {loc = loc_screen_start - menu_opts.n_entries_per_screen;}
               break;
             }
 
@@ -1725,8 +1761,8 @@
             {
               if (Opts_MenuSound())
                 {tuxtype_playsound(sounds[SND_TOCK]);}
-              if (loc - (loc % 8) + 8 < num_lessons)
-                {loc = (loc - (loc % 8) + 8);}
+              if (loc_screen_start + menu_opts.n_entries_per_screen < n_menu_entries)
+                {loc = (loc_screen_start + menu_opts.n_entries_per_screen);}
               break; 
             }
 
@@ -1746,7 +1782,7 @@
             {
               if (Opts_MenuSound())
                 {tuxtype_playsound(sounds[SND_TOCK]);}
-              if (loc + 1 < num_lessons)
+              if (loc + 1 < n_menu_entries)
                 {loc++;}
               break; 
            }
@@ -1793,8 +1829,7 @@
 
     if (redraw)
     {
-      int start;
-      start = loc - (loc % 8);
+      loc_screen_start = loc - (loc % menu_opts.n_entries_per_screen);
       /* FIXME could use some segfault prevention if()s here: */
       /* Redraw background, title, stop button, and Tux: */
       SDL_BlitSurface(images[IMG_MENU_BKG], NULL, screen, NULL);
@@ -1802,51 +1837,51 @@
       SDL_BlitSurface(images[IMG_STOP], NULL, screen, &stopRect);
       SDL_BlitSurface(Tux->frame[0], NULL, screen, &Tuxdest);
 
-      /* FIXME get rid of "evil" macro ;)       */
-      for (i = start; i < MIN(start+8,num_lessons); i++)
+      for (i = loc_screen_start, imod = 0; i < loc_screen_start+menu_opts.n_entries_per_screen && i < n_menu_entries; i++, imod++)
       {
-        titleRects[i % 8].x = 240;     //Like main menu
-        titleRects[i % 8].w = titles[i]->w;
-        titleRects[i % 8].h = titles[i]->h;
+        menu_text_rect[imod].x = 240;     //Like main menu
+        menu_text_rect[imod].w = menu_item_unselected[i]->w;
+        menu_text_rect[imod].h = menu_item_unselected[i]->h;
 
         /* Now set up mouse button rects: */
-        lesson_menu_button[i % 8].x = titleRects[i % 8].x - 15;
-        lesson_menu_button[i % 8].y = titleRects[i % 8].y;
-        lesson_menu_button[i % 8].h = titleRects[i % 8].h;
-        lesson_menu_button[i % 8].w = titleRects[i % 8].w + 30;
+        menu_mouse_button_rect[imod].x = menu_text_rect[imod].x - 15;
+        menu_mouse_button_rect[imod].y = menu_text_rect[imod].y;
+        menu_mouse_button_rect[imod].h = menu_text_rect[imod].h;
+        menu_mouse_button_rect[imod].w = menu_text_rect[imod].w + 30;
+	mouse_rects_are_valid = 1;
 
         if (i == loc)  //Draw text in yellow
         {
-          DrawButton(&lesson_menu_button[i % 8], 15, SEL_RGBA);
-          SDL_BlitSurface(select[loc], NULL, screen, &titleRects[i % 8]);
+          DrawButton(&menu_mouse_button_rect[imod], 15, SEL_RGBA);
+          SDL_BlitSurface(menu_item_selected[loc], NULL, screen, &menu_text_rect[imod]);
         }
         else           //Draw text in white
         {
-          DrawButton(&lesson_menu_button[i % 8], 15, REG_RGBA);
-          SDL_BlitSurface(titles[i], NULL, screen, &titleRects[i % 8]);
+          DrawButton(&menu_mouse_button_rect[imod], 15, REG_RGBA);
+          SDL_BlitSurface(menu_item_unselected[i], NULL, screen, &menu_text_rect[imod]);
         }
       }
-
+    
       /* --- draw 'left' and 'right' buttons --- */
-      if (start > 0)        // i.e. not on first page
-      {
-        SDL_BlitSurface(images[IMG_LEFT], NULL, screen, &leftRect);
-      }
-      else  /* Draw grayed-out left button: */
-      {
-        SDL_BlitSurface(images[IMG_LEFT_GRAY], NULL, screen, &leftRect);
-      }
+      if (n_menu_entries > menu_opts.n_entries_per_screen) {
+	if (loc_screen_start > 0)        // i.e. not on first page
+	{
+	    SDL_BlitSurface(images[IMG_LEFT], NULL, screen, &left_arrow_rect);
+	}
+	else  /* Draw grayed-out left button: */
+        {
+	  SDL_BlitSurface(images[IMG_LEFT_GRAY], NULL, screen, &left_arrow_rect);
+	}
 
-      if (start + 8 < num_lessons)  // not on last page
-      {
-        SDL_BlitSurface(images[IMG_RIGHT], NULL, screen, &rightRect);
+	if (loc_screen_start + menu_opts.n_entries_per_screen < n_menu_entries)  // not on last page
+        {
+	  SDL_BlitSurface(images[IMG_RIGHT], NULL, screen, &right_arrow_rect);
+	}
+	else  /* Draw grayed-out right button: */
+	{
+	  SDL_BlitSurface(images[IMG_RIGHT_GRAY], NULL, screen, &right_arrow_rect);
+	}
       }
-      else  /* Draw grayed-out right button: */
-      {
-        SDL_BlitSurface(images[IMG_RIGHT_GRAY], NULL, screen, &rightRect);
-      }
-
-
       SDL_UpdateRect(screen, 0, 0, 0 ,0);
     }
     redraw = 0;
@@ -1854,7 +1889,7 @@
 
 
     /* --- make Tux blink --- */
-    switch (frame % TUX6)
+    switch (frame_counter % TUX6)
     {
       case 0:    tux_frame = 1; break;
       case TUX1: tux_frame = 2; break;
@@ -1874,37 +1909,36 @@
     }
 
     /* Wait so we keep frame rate constant: */
-    while ((SDL_GetTicks() - frame_start) < 33)
-    {
-      SDL_Delay(20);
-    }
-    frame++;
+    frame_now = SDL_GetTicks();
+    if (frame_now - frame_start < 33)
+      SDL_Delay(33-(frame_now-frame_start));
+
+    frame_counter++;
   }  // End !stop while loop
 
+
+  /***** User made a choice, clean up and return the choice.   ******/
+
   /* --- clear graphics before leaving function --- */ 
-  for (i = 0; i < num_lessons; i++)
+  for (i = 0; i < n_menu_entries; i++)
   {
-    SDL_FreeSurface(titles[i]);
-    SDL_FreeSurface(select[i]);
+    SDL_FreeSurface(menu_item_unselected[i]);
+    SDL_FreeSurface(menu_item_selected[i]);
   }
-  free(titles);
-  free(select);
+  free(menu_item_unselected);
+  free(menu_item_selected);
+  free(menu_text_rect);
+  free(menu_mouse_button_rect);
 
-
-#ifdef TUXMATH_DEBUG
-  fprintf( stderr, "Leaving choose_config_file();\n" );
-#endif
-
-  if (stop == 2)  // Means player pressed ESC
-    return 0;
-
-  return 1;
+  /* Return the value of the chosen item (-1 indicates escape) */
+  if (stop == 2)
+    return -1;
+  else
+    return loc;
 }
 
 
 
-
-
 // Was in playgame.c in tuxtype:
 
 /*************************************************/

Modified: tuxmath/trunk/src/titlescreen.h
===================================================================
--- tuxmath/trunk/src/titlescreen.h	2007-09-26 11:27:20 UTC (rev 275)
+++ tuxmath/trunk/src/titlescreen.h	2007-09-27 15:50:09 UTC (rev 276)
@@ -77,6 +77,12 @@
 	int cur;
 } sprite;
 
+// Options that affect how menus are presented
+typedef struct {
+  int n_entries_per_screen;
+  int starting_entry;
+} menu_options;
+
 /* LOGGING works as such:
  *
  * - Use LOG if you want to output a string LOG( "Hello World");
@@ -232,6 +238,7 @@
 void TitleScreen( void );
 void switch_screen_mode( void );
 int choose_config_file(void);  //FIXME really should be in fileops.c
+int choose_menu_item(const unsigned char**,int,menu_options);
 
 /* in theme.c (from tuxtype): */
 void chooseTheme(void);

Modified: tuxmath/trunk/src/tuxmath.c
===================================================================
--- tuxmath/trunk/src/tuxmath.c	2007-09-26 11:27:20 UTC (rev 275)
+++ tuxmath/trunk/src/tuxmath.c	2007-09-27 15:50:09 UTC (rev 276)
@@ -48,8 +48,8 @@
 #endif
 
   setup(argc, argv);
+  atexit(cleanup);  // register it so we clean up even if there is a crash
   TitleScreen();
-  cleanup();
   return 0;
 }
 

Modified: tuxmath/trunk/src/tuxmath.h
===================================================================
--- tuxmath/trunk/src/tuxmath.h	2007-09-26 11:27:20 UTC (rev 275)
+++ tuxmath/trunk/src/tuxmath.h	2007-09-27 15:50:09 UTC (rev 276)
@@ -49,7 +49,7 @@
 #endif
 
 //#define NOSOUND
-#define TUXMATH_DEBUG   /* for conditional compilation of debugging output */
+//#define TUXMATH_DEBUG   /* for conditional compilation of debugging output */
 //#define FEEDBACK_DEBUG  /* for Tim's feedback speed control code           */
 
 /* Maximum length of file path: */
@@ -174,11 +174,8 @@
 extern int opers[NUM_OPERS], range_enabled[NUM_Q_RANGES];
 
 #define NAME_BUF_SIZE 200
-typedef struct lesson_entry {
-  char filename[NAME_BUF_SIZE];  //List of lesson file names
-  char display_name[NAME_BUF_SIZE]; //List of lesson names for display
-} lesson_entry;
-extern lesson_entry *lesson_list;
+extern unsigned char **lesson_list_titles;
+extern unsigned char **lesson_list_filenames;
 extern int num_lessons;
 
 /* NOTE: default values for math options are now in mathcards.h */




More information about the Tux4kids-commits mailing list