[Tux4kids-commits] r343 - in tuxmath/trunk: doc src

tholy-guest at alioth.debian.org tholy-guest at alioth.debian.org
Mon Nov 26 06:29:31 UTC 2007


Author: tholy-guest
Date: 2007-11-26 06:29:31 +0000 (Mon, 26 Nov 2007)
New Revision: 343

Modified:
   tuxmath/trunk/doc/README.txt
   tuxmath/trunk/doc/TODO.txt
   tuxmath/trunk/doc/changelog
   tuxmath/trunk/src/fileops.c
   tuxmath/trunk/src/setup.c
   tuxmath/trunk/src/setup.h
   tuxmath/trunk/src/titlescreen.c
Log:
Add the possibility of a user login at the beginning of the game.


Modified: tuxmath/trunk/doc/README.txt
===================================================================
--- tuxmath/trunk/doc/README.txt	2007-11-23 11:02:43 UTC (rev 342)
+++ tuxmath/trunk/doc/README.txt	2007-11-26 06:29:31 UTC (rev 343)
@@ -23,7 +23,13 @@
   please read the "INSTALL.txt" file.
 
 
+Configuration
+-------------
+  School-type settings in which all students have a single username
+  may benefit from additional configuration---see below under
+  "Configuring multiple users."
 
+
 Running The Program
 -------------------
   Linux/Unix
@@ -353,7 +359,52 @@
   [ UNDER CONSTRUCTION ]
 
 
+Configuring Multiple Users
+--------------------------
 
+  In some cases, the user's log-in name is not very informative: an
+  example is when schools use a single username "student" for all
+  students in the school.  It is possible to set up Tuxmath so that it
+  asks students to "log in" (without any password) when they first
+  start the game.  This will insure that all gold stars, options, and
+  game summary files will be stored in a location specific to each
+  user.
+
+  Setting this up is fairly simple:
+
+     1. Decide where you want this information stored.  You might want
+        to put it on a central server.  In the appropriate place
+        (let's say it's "/servervolume/"), create a directory which
+        we'll call "tuxmath_users" for current purposes.
+
+     2. Create subdirectories of "tuxmath_users." The basic idea is
+        that you'll create a directory tree that mirrors how you want
+        students to select themselves.  For example, a large school
+        with many classrooms might create directories called
+        "Kindergarten," "1st grade," and so on.  Then inside
+        "Kindergarten" you might want to create directories for each
+        classroom, say "Mrs. Smith" and "Mr. Jones."  A smaller school
+        might choose to skip the by-grade organization and go straight
+        to each classroom; a single computer in a single classroom
+        might skip these altogether.
+
+     3. At the finest level, create one subdirectory for each student.
+
+     4. Finally, adjust the launch command for tuxmath to pass the
+        command line option "--homedir /severvolume/tuxmath_users"
+        (along with any other options) upon launching tuxmath.  Note
+        that an individual classroom could make use of this
+        school-wide service by specifying "--homedir
+        /servervolume/tuxmath_users/2nd\ grade/Mrs.\ Johnson" so that
+        students in a particular classroom only have to choose among
+        their own class.
+
+  You have to make sure that all the write permissions are set
+  correctly.
+
+  Note there is no security insuring that students select themselves.
+
+
 License
 -------
   "Tux, of Math Command" is Free Software, distributable under the

Modified: tuxmath/trunk/doc/TODO.txt
===================================================================
--- tuxmath/trunk/doc/TODO.txt	2007-11-23 11:02:43 UTC (rev 342)
+++ tuxmath/trunk/doc/TODO.txt	2007-11-26 06:29:31 UTC (rev 343)
@@ -44,6 +44,8 @@
   * Admin options screen / files
   * Command-line options based on grade-level (?)
   * Internationalization - use gettext() for all strings
+  * Install some kind of security on --homedir, to make sure that
+    tuxmath can write but that students can't edit the files by hand?
 
 Code:
   * Optimize graphics blitting!!!

Modified: tuxmath/trunk/doc/changelog
===================================================================
--- tuxmath/trunk/doc/changelog	2007-11-23 11:02:43 UTC (rev 342)
+++ tuxmath/trunk/doc/changelog	2007-11-26 06:29:31 UTC (rev 343)
@@ -1,3 +1,9 @@
+2007.Nov.26 (svn.debian.org/tux4kids - revision 342)
+  Options:
+      * Added support for user login. This should be helpful in school
+	settings where all students log in with the same username.  See
+	the README for details.
+	
 2007.Nov.18 (svn.debian.org/tux4kids - revision 327)
 
   Build:

Modified: tuxmath/trunk/src/fileops.c
===================================================================
--- tuxmath/trunk/src/fileops.c	2007-11-23 11:02:43 UTC (rev 342)
+++ tuxmath/trunk/src/fileops.c	2007-11-26 06:29:31 UTC (rev 343)
@@ -410,6 +410,7 @@
 
 /* This functions keep and returns the user data directory application path */
 static char* user_data_dir = NULL;
+static int add_subdir = 1;
 
 char *get_user_data_dir ()
 { 
@@ -423,6 +424,36 @@
   return user_data_dir;  
 }
 
+/* This function sets the user data directory, and also sets a flag
+   indicating that this should function as a .tuxmath directory, and
+   thus doesn't need the subdir appended. */
+void set_user_data_dir(const char *dirname)
+{
+  int len;
+
+  if (user_data_dir != NULL)
+    free(user_data_dir);   // clear the previous setting
+
+  user_data_dir = strdup(dirname);
+
+  // Check to see that dirname is properly terminated
+  len = strlen(user_data_dir);
+  if (user_data_dir[len-1] != '/')
+    strcat(user_data_dir,"/");
+
+  // If the user supplies a homedir, interpret it literally and don't
+  // add .tuxmath
+  add_subdir = 0;
+}
+
+/* This gets the user data directory including the .tuxmath, if applicable */
+void get_user_data_dir_with_subdir(char *opt_path)
+{
+  strcpy(opt_path, get_user_data_dir());
+  if (add_subdir)
+    strcat(opt_path, OPTIONS_SUBDIR "/");
+}
+  
 /* FIXME should have better file path (/etc or /usr/local/etc) and name */
 int read_global_config_file(void)
 {
@@ -447,8 +478,8 @@
   char opt_path[PATH_MAX];
 
   /* find $HOME and tack on file name: */
-  strcpy(opt_path, get_user_data_dir());
-  strcat(opt_path, OPTIONS_SUBDIR "/" OPTIONS_FILENAME);
+  get_user_data_dir_with_subdir(opt_path);
+  strcat(opt_path, OPTIONS_FILENAME);
 
   #ifdef TUXMATH_DEBUG
   printf("\nIn read_user_config_file() full path to config file is: = %s\n", opt_path);
@@ -650,8 +681,7 @@
 
   /* Look in user's hidden .tuxmath directory  */
   /* find $HOME and tack on file name: */
-  strcpy(opt_path, get_user_data_dir());
-  strcat(opt_path, OPTIONS_SUBDIR "/");
+  get_user_data_dir_with_subdir(opt_path);
   strcat(opt_path, filename);
 
   #ifdef TUXMATH_DEBUG
@@ -889,8 +919,8 @@
   char opt_path[PATH_MAX];
 
   /* find $HOME and tack on file name: */
-  strcpy(opt_path, get_user_data_dir());
-  strcat(opt_path, OPTIONS_SUBDIR "/" GOLDSTAR_FILENAME);
+  get_user_data_dir_with_subdir(opt_path);
+  strcat(opt_path, GOLDSTAR_FILENAME);
 
   #ifdef TUXMATH_DEBUG
   printf("\nIn read_goldstars() full path to file is: = %s\n", opt_path);
@@ -925,8 +955,8 @@
   }
 
   /* find $HOME and add rest of path to config file: */
-  strcpy(opt_path, get_user_data_dir());
-  strcat(opt_path, OPTIONS_SUBDIR "/" GOLDSTAR_FILENAME);
+  get_user_data_dir_with_subdir(opt_path);
+  strcat(opt_path, GOLDSTAR_FILENAME);
 
   #ifdef TUXMATH_DEBUG
   printf("\nIn write_goldstars() full path to file is: = %s\n", opt_path);
@@ -957,8 +987,8 @@
   char opt_path[PATH_MAX];
 
   /* find $HOME and tack on file name: */
-  strcpy(opt_path, get_user_data_dir());
-  strcat(opt_path, OPTIONS_SUBDIR "/" HIGHSCORE_FILENAME);
+  get_user_data_dir_with_subdir(opt_path);
+  strcat(opt_path, HIGHSCORE_FILENAME);
 
   #ifdef TUXMATH_DEBUG
   printf("\nIn read_high_scores() full path to file is: = %s\n", opt_path);
@@ -994,8 +1024,8 @@
   }
 
   /* find $HOME and add rest of path to config file: */
-  strcpy(opt_path, get_user_data_dir());
-  strcat(opt_path, OPTIONS_SUBDIR "/" HIGHSCORE_FILENAME);
+  get_user_data_dir_with_subdir(opt_path);
+  strcat(opt_path, HIGHSCORE_FILENAME);
 
   #ifdef TUXMATH_DEBUG
   printf("\nIn write_high_scores() full path to file is: = %s\n", opt_path);
@@ -1654,8 +1684,8 @@
   }
 
   /* find $HOME and add rest of path to config file: */
-  strcpy(opt_path, get_user_data_dir());
-  strcat(opt_path, OPTIONS_SUBDIR "/" OPTIONS_FILENAME);
+  get_user_data_dir_with_subdir(opt_path);
+  strcat(opt_path, OPTIONS_FILENAME);
 
   #ifdef TUXMATH_DEBUG
   printf("\nIn write_user_config_file() full path to config file is: = %s\n", opt_path);
@@ -2369,8 +2399,7 @@
   /* and leaving summary1 available for current game:             */
 
   /* find $HOME and tack on file name: */
-  strcpy(filepath1, get_user_data_dir());
-  strcat(filepath1, OPTIONS_SUBDIR "/");
+  get_user_data_dir_with_subdir(filepath1);
   strcat(filepath1, summary_filenames[NUM_SUMMARIES - 1]);
 
   fp = fopen(filepath1, "r");
@@ -2390,20 +2419,17 @@
   for (i = NUM_SUMMARIES - 1; i > 0; i--)
   {
     /* old filename: */
-    strcpy(filepath1, get_user_data_dir());
-    strcat(filepath1, OPTIONS_SUBDIR "/");
+    get_user_data_dir_with_subdir(filepath1);
+    strcpy(filepath2,filepath1);
     strcat(filepath1, summary_filenames[i - 1]);
     /* new filename: */
-    strcpy(filepath2, get_user_data_dir());
-    strcat(filepath2, OPTIONS_SUBDIR "/");
     strcat(filepath2, summary_filenames[i]);
     /* now change the name: */
     rename(filepath1, filepath2);
   } 
 
   /* summary_filenames[0] (i.e. 'summary1') should now be vacant:     */
-  strcpy(filepath1, get_user_data_dir());
-  strcat(filepath1, OPTIONS_SUBDIR "/");
+  get_user_data_dir_with_subdir(filepath1);
   strcat(filepath1, summary_filenames[0]);
 
   fp = fopen(filepath1, "w"); /* "w" means start writing with empty file */
@@ -2435,8 +2461,7 @@
   char filepath1[PATH_MAX];
   int total_answered;
 
-  strcpy(filepath1, get_user_data_dir());
-  strcat(filepath1, OPTIONS_SUBDIR "/");
+  get_user_data_dir_with_subdir(filepath1);
   strcat(filepath1, summary_filenames[0]);
 
   fp = fopen(filepath1, "a"); /* "a" means append to end of file */
@@ -2493,16 +2518,9 @@
   DIR* dir_ptr;
 
   /* find $HOME */
-  strcpy(opt_path, get_user_data_dir());
+  get_user_data_dir_with_subdir(opt_path);
 
   #ifdef TUXMATH_DEBUG
-  printf("\nIn find_tuxmath_dir() home directory is: = %s\n", opt_path);
-  #endif
-
-  /* add rest of path to user's tuxmath dir: */
-  strcat(opt_path, OPTIONS_SUBDIR);
-
-  #ifdef TUXMATH_DEBUG
   printf("\nIn find_tuxmath_dir() tuxmath dir is: = %s\n", opt_path);
   #endif
 
@@ -2522,6 +2540,9 @@
     FILE* fp;
     int status;
 
+    if (!add_subdir)
+      return 0;      // fail if the user specified a directory, but it doesn't exist
+
     /* if user's home has a _file_ named .tuxmath (as from previous version */
     /* of program), need to get rid of it or directory creation will fail:  */
     fp = fopen(opt_path, "r");
@@ -2566,6 +2587,85 @@
 }
 
 
+/* Utility function to test whether a given dirent represents a directory */
+/* Note this assumes a base of the user's current data directory, it's
+   not a general function. */
+int isdir(const struct dirent *dirEntry)
+{
+  struct stat fileStat;
+  char opt_path[PATH_MAX];
+
+  // Exclude "." from consideration
+  if (strcmp(dirEntry->d_name,".") == 0)
+    return 0;
+  // Exclude ".." from consideration
+  if (strcmp(dirEntry->d_name,"..") == 0)
+    return 0;
+
+  // Prepend the pathname
+  get_user_data_dir_with_subdir(opt_path);
+  strncat(opt_path, dirEntry->d_name,PATH_MAX-strlen(opt_path));
+
+  if (stat(opt_path, &fileStat) < 0) {
+    printf("error parsing %s\n",opt_path);
+    return 0;
+  }
+  printf("Entry: %s, IsDir: %d\n",opt_path, S_ISDIR(fileStat.st_mode));
+  if (S_ISDIR(fileStat.st_mode))
+    return 1;
+  else
+    return 0;
+}
+
+
+/* Checks to see if the current data dir has subdirectories, and if so  */
+/* returns their names. This is used in cases where users must select   */
+/* their login information. Returns the number of subdirectories (0 if  */
+/* there are none), and sets the input argument to a malloc-ed array    */
+/* names (sets to NULL if there are no subdirectories).                 */
+int tuxmath_dir_subdirs(char ***subdir_names)
+{
+  struct dirent **namelist;
+  int n_entries,i;
+  char opt_path[PATH_MAX];
+
+  get_user_data_dir_with_subdir(opt_path);
+  n_entries = scandir(opt_path, &namelist, isdir, alphasort);
+  if (n_entries > 0) {
+    *subdir_names = (char **) malloc(n_entries*sizeof(char*));
+    for (i = 0; i < n_entries; i++)
+      (*subdir_names)[i] = strdup(namelist[i]->d_name);
+    free(namelist);
+    return n_entries;
+  }
+  else {
+    *subdir_names = NULL;
+    return 0;
+  }
+}
+
+/* A utility function to go up one level in a directory hierarchy */
+void dirname_up(char *dirname)
+{
+  int len;
+
+  len = strlen(dirname);
+  printf("up1: len = %d\n",len);
+  // Pass over all trailing "/"
+  while (len > 0 && dirname[len-1] == '/')
+    len--;
+  printf("up2: len = %d\n",len);
+
+  // Now pass over all non-"/" characters at the end
+  while (len > 0 && dirname[len-1] != '/')
+    len--;
+  printf("up3: len = %d\n",len);
+  
+  // Terminate the string after that next-to-last "/"
+  dirname[len] = '\0';
+}
+
+
 /* Allows use of "true", "YES", T, etc. in text file for boolean values. */
 /* Return value of -1 means value string is not recognized.              */
 static int str_to_bool(const char* val)

Modified: tuxmath/trunk/src/setup.c
===================================================================
--- tuxmath/trunk/src/setup.c	2007-11-23 11:02:43 UTC (rev 342)
+++ tuxmath/trunk/src/setup.c	2007-11-26 06:29:31 UTC (rev 343)
@@ -97,6 +97,7 @@
 void setup(int argc, char * argv[])
 {
   /* initialize settings and read in config files: */
+  /* Note this now only does the global settings   */
   initialize_options();
   /* Command-line code now in own function: */
   handle_command_args(argc, argv);
@@ -108,6 +109,8 @@
   generate_flipped_images();
   /* Generate blended images (e.g., igloos) */
   generate_blended_images();
+  /* Note that the per-user options will be set after the call to
+     titlescreen, to allow for user-login to occur. */
 }
 
 
@@ -115,8 +118,7 @@
 
 /* Set up mathcards with default values for math question options, */
 /* set up game_options with defaults for general game options,     */
-/* then read in global config file, followed if desired by user's  */
-/* own config file:                                                */
+/* then read in global config file                                 */
 void initialize_options(void)
 {
   /* Initialize MathCards backend for math questions: */
@@ -143,8 +145,14 @@
     fprintf(stderr, "\nCould not find global config file.\n");
     /* can still proceed using hard-coded defaults.         */
   }
+}
 
-  /* Now read in user-specific settings, if desired.  By    */
+/* Read in the user-specific options (if desired)              */
+/* This has been split from the above to allow it to be called */
+/* from titlescreen, to allow for user-login to occur.         */
+void initialize_options_user(void)
+{
+  /* Read in user-specific settings, if desired.  By    */  
   /* default, this restores settings from the player's last */
   /* game:                                                  */
   if (Opts_PerUserConfig())
@@ -210,6 +218,12 @@
              "to configure the behavior of Tuxmath.\n\n");
 
       printf("Run the game with:\n"
+	"--homedir dirname      - seek for user home director(ies) in the specified\n"
+	"                         location, rather than the user's actual home\n"
+	"                         directory.  You can set up a user directory tree in\n"
+	"                         this location (see README).  This option is\n"
+	"                         especially useful for schools where all students log\n"
+	"                         in with a single user name.\n"
         "--optionfile filename  - read config settings from named file. The locations\n"
         "                         searched for a file with a matching name are the\n"
         "                         current working directory, the absolute path of the\n"
@@ -262,7 +276,23 @@
 	    
       usage(0, argv[0]);
     }
-    /* TODO implement --optionfile filename */
+    else if (0 == strcmp(argv[i], "--homedir"))
+    {
+      // Parse the user choice of a non-default home directory
+      if (i >= argc -1)
+      {
+	fprintf(stderr, "%s option requires an argument (dirname)\n", argv[i]);
+	usage(1, argv[0]);
+      }
+      else // see whether the specified name is a directory
+      {
+	if (opendir(argv[i+1]) == NULL)
+	  fprintf(stderr,"homedir: %s is not a directory, or it could not be read\n", argv[i+1]);
+	else
+	  set_user_data_dir(argv[i+1]);  // copy the homedir setting
+	i++;   // to pass over the next argument, so remaining options parsed
+      }
+    }
     else if (0 == strcmp(argv[i], "--optionfile"))
     {
       if (i >= argc - 1)

Modified: tuxmath/trunk/src/setup.h
===================================================================
--- tuxmath/trunk/src/setup.h	2007-11-23 11:02:43 UTC (rev 342)
+++ tuxmath/trunk/src/setup.h	2007-11-26 06:29:31 UTC (rev 343)
@@ -33,5 +33,6 @@
 void setup(int argc, char * argv[]);
 void cleanup(void);
 void cleanup_on_error(void);
+extern void initialize_options_user(void);
 
 #endif

Modified: tuxmath/trunk/src/titlescreen.c
===================================================================
--- tuxmath/trunk/src/titlescreen.c	2007-11-23 11:02:43 UTC (rev 342)
+++ tuxmath/trunk/src/titlescreen.c	2007-11-26 06:29:31 UTC (rev 343)
@@ -161,6 +161,8 @@
   Uint32 start = 0;
 
   int i; 
+  int n_subdirs;
+  char **subdir_names;
 
 
   if (Opts_UsingSound())
@@ -311,8 +313,13 @@
     audioMusicLoad("tuxi.ogg", -1);
   }
 
-  /* Start the main menu */
-  run_main_menu();
+  /* If necessary, have the user log in */
+  if (run_login_menu() != -1) {
+    /* Finish parsing user options */
+    initialize_options_user();
+    /* Start the main menu */
+    run_main_menu();
+  }
 
   /* User has selected quit, clean up */
 
@@ -909,9 +916,64 @@
 }
 
 
+/* Sets the user home directory in a tree of possible users     */
+/* -1 indicates that the user wants to quit without logging in, */
+/* 0 indicates that a choice has been made.                     */
+int run_login_menu(void)
+{
+  menu_options menu_opts;
+  int chosen_login = -1;
+  char *user_home;
+  char **subdir_names;
+  int n_subdirs;
+  int level;
+  char opt_path[PATH_MAX];
+
+  set_default_menu_options(&menu_opts);
+  level = 0;
+  // Get current home directory
+  user_home = get_user_data_dir();
+
+  n_subdirs = tuxmath_dir_subdirs(&subdir_names);
+  while (n_subdirs) {
+    // Get the user choice
+    chosen_login = choose_menu_item(subdir_names, NULL, n_subdirs, menu_opts);
+    if (chosen_login == -1) {
+      // User pressed escape, handle by quitting or going up a level
+      free(subdir_names);
+      if (level == 0)
+	return -1;   // Indicate that the user is quitting without logging in
+      else {
+	// Go back up one level of the directory tree
+	printf("Going up a level\n");
+	printf("Previous home: %s\n",user_home);
+	dirname_up(user_home);
+	level--;
+	printf("New home: %s\n",user_home);
+	n_subdirs = tuxmath_dir_subdirs(&subdir_names);
+      }
+    }
+    else {
+      // User chose an entry, set it up
+      strcat(user_home,subdir_names[chosen_login]);
+      strcat(user_home,"/");
+      level++;
+      free(subdir_names);
+      // Keep checking to see if we need to descend further
+      n_subdirs = tuxmath_dir_subdirs(&subdir_names);
+    }
+  }
+  get_user_data_dir_with_subdir(opt_path);
+  printf("User data directory: %s\n", opt_path);
+
+  return 0;
+}
+
+
 /****************************************************************/
 /* choose_menu_item: menu navigation utility function           */
 /* (the function returns the index for the selected menu item)  */
+/* -1 indicates that the user pressed escape                    */
 /****************************************************************/
 int choose_menu_item(const unsigned char **menu_text, sprite **menu_sprites, int n_menu_entries, menu_options menu_opts)
 {




More information about the Tux4kids-commits mailing list