Man page speedup



Here is the updated patch I promised for man page speedups.  It should
also be attached to bug #322195

As of right now, it handles three cases:

1) no index file exists at ~/.gnome2/yelp.d/manindex.xml

Yelp will traverse the directory structure and create an index file
at this location.  This is the most time intensive case - but I would
say that it is an order of magnitude faster than current yelp HEAD
since with the patch it only takes about 1.5 seconds for 46,000 man
pages on cold start, where as yelp HEAD takes about 9-10 seconds.

2) index file exists at ~/.gnome2/yelp.d/manindex.xml and is up
   to date

Yelp pulls the location for each man page from the index file and
stores it in the TOC.  This is the fastest case since yelp doesn't
have to touch the disk (except for checking mtimes of directories,
see next case)

3) index file exists at ~/.gnome2/yelp.d/manindex.xml, but it is
   out of date

Yelp compares the modified times for the directories specified
in the file to those on disk.  If the time on disk is newer,
yelp will reindex that directory and update the index file.
While it does this, it also stores the location of each man page
in the TOC.

I would ask that people please test this patch and make sure that
it performs correctly, doesn't crash, etc.  I would like to
commit to head before the 2.13.3 release which is on Monday at
23:59 UTC so as to get maximum testing from the community (yeah,
I know man pages aren't turned on by default but I'm trying to
change that).

Specifically, the following would be a good test case:
1) compile with --enable-man
2) run yelp once to create the index at ~/.gnome2/yelp.d/manindex.xml
3) install/modify a man page somewhere on your system
4) run yelp once again to create the updated index. Yelp will also
   backup the old index to manindex.xml.<mtime> - this will be removed
   before committing to HEAD.
5) run a diff -u manindex.xml.<mtime> manindex.xml to make sure that
   a) the directory mtime is updated
   b) the man page that you installed is added to the index (this
      won't happen if you just modified a man page in step 3)
6) Let me know of any problems!

There are still some minor considerations I would like some
feedback on:

1) Is ~/.gnome2/yelp.d/manindex.xml an appropriate location for
   the index?  I think this is the mozilla profile directory, so
   I'm not sure if it makes sense to put it in there.  Yelp
   stores bookmarks, printing, and geometry files in ~/.gnome2/
   so maybe it makes more sense to put it in there, or create a
   new directory ~/.gnome2/yelp/ for all these files...

2) In the XML file each man page name is enclosed in <page></page>
   tags.  Should the tag name be something smaller, like <p></p>
   in the interest of saving space?  With 46,000 man pages, using
   <page></page> over <p></p> is an extra 6 bytes per man page.
   This is 276,000 byte overhead for the index file... not sure if
   this is significant.

3) ... I'm sure I'll think of more.

Other notes:
 * All the timing stuff needs to be removed before committing to head.
 * ditto for creating a backup of the index file when writing a new one

Thanks,

--
Brent Smith <gnome nextreality net>
IRC: smitten
? m4/intltool.m4
Index: src/yelp-toc-pager.c
===================================================================
RCS file: /cvs/gnome/yelp/src/yelp-toc-pager.c,v
retrieving revision 1.52
diff -u -r1.52 yelp-toc-pager.c
--- src/yelp-toc-pager.c	2 Nov 2005 21:49:48 -0000	1.52
+++ src/yelp-toc-pager.c	10 Dec 2005 20:34:58 -0000
@@ -24,8 +24,13 @@
 #include <config.h>
 #endif
 
+#include <unistd.h>
 #include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
 #include <glib.h>
+#include <glib/gstdio.h>
 #include <glib/gi18n.h>
 #include <libgnomevfs/gnome-vfs.h>
 #include <libxml/parser.h>
@@ -68,11 +73,13 @@
     GSList       *omf_pending;
 
 #ifdef ENABLE_MAN
-    gint    mandirs_i;
-    gint    langs_i;
-    gint    manpaths_i;
-    gchar **manpaths;
-
+    gint manpage_count;
+    xmlNodePtr root;
+    xmlNodePtr ins;
+    xmlDocPtr manindex_xml;
+    GSList *mandir_list;
+    GSList *mandir_ptr;          /* ptr to current entry in mandir_list */
+    GSList *mandir_langpath;     /* ptr to current entry in mandir_ptr */
     GHashTable *man_secthash;
     GHashTable *man_manhash;
 #endif
@@ -151,6 +158,39 @@
 
 static YelpTocPager   *toc_pager;
 
+static gboolean
+do_timing  (void)
+{
+    static gboolean first_call = TRUE;
+    static struct timeval before;
+    static struct timeval after;
+
+    
+    if (first_call) {
+	gettimeofday (&before, NULL);
+	first_call = FALSE;
+    } else {
+	gint sec=0, usec=0;
+	
+	gettimeofday (&after, NULL);
+
+	sec = after.tv_sec - before.tv_sec;
+	if (after.tv_sec > before.tv_sec) {
+	    if (after.tv_usec < before.tv_usec) {
+		usec = (1000000 - before.tv_usec) + after.tv_usec;
+	        sec--;
+	    } else usec = after.tv_usec - before.tv_usec;
+	} else usec = after.tv_usec - before.tv_usec;
+    	
+	g_print ("before : sec=%d, usec=%d\n", (int)before.tv_sec, (int)before.tv_usec);
+    	g_print ("after  : sec=%d, usec=%d\n", (int)after.tv_sec,  (int)after.tv_usec);
+    	g_print ("elapsed: sec=%d, usec=%d\n", (int)sec, (int)usec);
+    }
+
+    /* needed to indicate we are done processing */
+    return FALSE;
+}
+
 GType
 yelp_toc_pager_get_type (void)
 {
@@ -232,7 +272,7 @@
 {
     YelpDocInfo *doc_info;
 
-    doc_info = yelp_doc_info_get ("x-yelp-toc:");
+    doc_info = yelp_doc_info_get ("x-yelp-toc:", FALSE);
     
     toc_pager = (YelpTocPager *) g_object_new (YELP_TYPE_TOC_PAGER,
 					       "document-info", doc_info,
@@ -356,7 +396,9 @@
 	process_omf_pending,
 	process_xslt,
 #ifdef ENABLE_MAN
+	do_timing,
 	process_mandir_pending,
+	do_timing,
 	process_xslt,
 #endif
 #ifdef ENABLE_INFO
@@ -509,7 +551,7 @@
     omf_seriesid =
 	xmlXPathEvalExpression (BAD_CAST "string(/omf/resource/relation/@seriesid)", omf_xpath);
 
-    doc_info = yelp_doc_info_get ((const gchar *) omf_url->stringval);
+    doc_info = yelp_doc_info_get ((const gchar *) omf_url->stringval, FALSE);
     if (!doc_info)
 	goto done;
     yelp_doc_info_set_title (doc_info, (gchar *) omf_title->stringval);
@@ -561,24 +603,264 @@
 }
 
 #ifdef ENABLE_MAN
+static void
+add_man_page_to_toc (YelpTocPager *pager, gchar *dirname, gchar *filename)
+{
+    xmlNodePtr tmp = NULL;
+    gchar *manname = NULL;
+    gchar *mansect = NULL;
+    gchar *manman = NULL;
+    gchar *c1 = NULL;
+    gchar *c2 = NULL;
+    
+    YelpTocPagerPriv *priv  = YELP_TOC_PAGER (pager)->priv;
+		    
+    c1 = g_strrstr (filename, ".bz2");
+  
+    if (c1 && strlen (c1) != 4)
+	c1 = NULL;
+
+    if (!c1) {
+	c1 = g_strrstr (filename, ".gz");
+	if (c1 && strlen (c1) != 3)
+	    c1 = NULL;
+    }
+
+    if (c1)
+	c2 = g_strrstr_len (filename, c1 - filename, ".");
+    else
+	c2 = g_strrstr (filename, ".");
+
+    if (c2) {
+	manname = g_strndup (filename, c2 - filename);
+	if (c1)
+	    mansect = g_strndup (c2 + 1, c1 - c2 - 1);
+	else
+	    mansect = g_strdup (c2 + 1);
+    }
+
+    /* if filename has no period in it, we have no idea what man
+     * section to place it in.  So just ignore it. */
+    else return;
+
+    manman = g_strconcat (manname, ".", mansect, NULL);
+    
+    if (g_hash_table_lookup (priv->man_manhash, manman) == NULL) {
+	tmp = g_hash_table_lookup (priv->man_secthash, mansect);
+
+	if (tmp == NULL && strlen (mansect) > 1) {
+	    gchar *mansect0 = g_strndup (mansect, 1);
+	    tmp = g_hash_table_lookup (priv->man_secthash, mansect0);
+	    g_free (mansect0);
+	}
+
+	if (tmp) {
+	    gchar *tooltip, *url_full, *url_short;
+	    YelpDocInfo *info;
+
+	    url_full = g_strconcat ("man:", dirname, "/", filename, NULL);
+	    url_short = g_strconcat ("man:", manname, ".", mansect, NULL);
+	    info = yelp_doc_info_get (url_full, TRUE);
+
+	    if (info) {
+		yelp_doc_info_add_uri (info, url_short, YELP_URI_TYPE_MAN);
+		tmp = xmlNewChild (tmp, NULL, "doc", NULL);
+		xmlNewNsProp (tmp, NULL, "href", url_full);
+		xmlNewChild (tmp, NULL, "title", manname);
+		tooltip = g_strdup_printf (_("Read man page for %s"), manname);
+		xmlNewChild (tmp, NULL, "tooltip", tooltip);
+
+		g_free (tooltip);
+	    }
+
+	    g_free (url_full);
+	    g_free (url_short);
+	} else {
+	    d (g_warning ("Could not locate section %s for %s\n", mansect, manman));
+	}
+
+	g_hash_table_insert (priv->man_manhash, g_strdup (manman), priv);
+    }
+
+    g_free (manname);
+    g_free (mansect);
+    g_free (manman);
+}
+
+static void
+create_manindex_file (gchar *index_file, xmlDocPtr xmldoc)
+{
+    FILE *newindex = NULL;
+
+    /* TODO: comment this out before committing to HEAD */    
+    /* check to see if the file already exists, if so rename it */
+    if (g_file_test (index_file, G_FILE_TEST_EXISTS)) {
+	struct stat buff;
+	gchar *backup_file = NULL;
+
+	if (g_stat (index_file, &buff) < 0)
+	    g_warning ("Unable to stat file \"%s\"\n", index_file);
+
+	backup_file = g_strdup_printf ("%s.%d", index_file, (int) buff.st_mtime);
+	
+	if (g_rename (index_file, backup_file) < 0)
+	    g_warning ("Unable to rename \"%s\" to \"%s\"\n", index_file, backup_file);
+	
+	g_free (backup_file);
+    }
+		
+    if (!(newindex = g_fopen (index_file, "w")))
+	g_warning ("Unable to create '%s'\n", index_file);
+    else {
+	xmlDocDump (newindex, xmldoc);
+	fclose (newindex);
+    }
+}
+
+/* returns 0 on error, 1 otherwise */
+static int
+create_toc_from_index (YelpTocPager *pager, gchar *index_file)
+{
+    xmlXPathContextPtr xpath = NULL;
+    xmlXPathObjectPtr objsect = NULL;
+    xmlDocPtr manindex_xml = NULL;
+    gint update_flag = 0;
+    gint i, j, k;
+    
+    YelpTocPagerPriv *priv  = YELP_TOC_PAGER (pager)->priv;
+
+    manindex_xml = xmlReadFile (index_file, NULL, XML_PARSE_NOCDATA | 
+		                XML_PARSE_NOERROR | XML_PARSE_NONET);
+
+    if (manindex_xml == NULL) {
+	g_warning ("Unable to parse index file \"%s\"\n", index_file);
+	return 0;
+    }
+    
+    xpath = xmlXPathNewContext (manindex_xml);
+    objsect = xmlXPathEvalExpression ("/manindex/mansect", xpath);
+
+    for (i=0; i < objsect->nodesetval->nodeNr; i++) {
+	xmlXPathObjectPtr objdirs;
+
+	if (!priv->man_manhash)
+	    priv->man_manhash = g_hash_table_new_full (g_str_hash, g_str_equal,
+		                                       g_free, NULL);
+
+	xpath->node = objsect->nodesetval->nodeTab[i];
+	objdirs = xmlXPathEvalExpression ("dir", xpath);
+
+	for (j=0; j < objdirs->nodesetval->nodeNr; j++) {
+	    xmlXPathObjectPtr objdirname;
+	    xmlXPathObjectPtr objdirmtime;
+	    xmlXPathObjectPtr objmanpages;
+	    xmlNodePtr dirnode = objdirs->nodesetval->nodeTab[j];
+	    xmlNodePtr node = NULL;
+	    xmlChar *dirname = NULL;
+	    xmlChar *dirmtime = NULL;
+	    time_t mtime;
+	    struct stat buf;
+	    
+	    xpath->node = dirnode;
+	    objdirmtime = xmlXPathEvalExpression ("@mtime", xpath);
+	    
+	    node = objdirmtime->nodesetval->nodeTab[0];
+	    dirmtime = xmlNodeListGetString (manindex_xml, 
+	                                     node->xmlChildrenNode, 1);
+	    
+	    objdirname = xmlXPathEvalExpression ("name[1]", xpath);
+
+	    node = objdirname->nodesetval->nodeTab[0];
+	    dirname = xmlNodeListGetString (manindex_xml, 
+	                                    node->xmlChildrenNode, 1);
+	    
+	    if (g_stat (dirname, &buf) < 0)
+		g_warning ("Unable to stat dir: \"%s\"\n", dirname);
+	    
+	    /* FIXME: need some error checking */
+	    mtime = (time_t) atoi (dirmtime);
+	    
+	    /* see if directory mtime has changed - if so recreate
+	     * the directory node */
+	    if (buf.st_mtime > mtime) {
+		GDir *dir;
+		xmlNodePtr newNode = NULL;
+		gchar mtime_str[20];
+		gchar *filename = NULL;
+		
+		/* this means we will rewrite the cache file at the end */
+		update_flag = 1;
+		
+		if ((dir = g_dir_open (dirname, 0, NULL))) {
+		    g_snprintf (mtime_str, 20, "%u", (guint) buf.st_mtime);
+
+		    newNode = xmlNewNode (NULL, "dir");
+		    xmlNewProp (newNode, "mtime", mtime_str);
+		    xmlAddChild (newNode, xmlNewText ("\n      "));
+		    xmlNewChild (newNode, NULL, "name", dirname);
+		    xmlAddChild (newNode, xmlNewText ("\n      "));
+
+		    while ((filename = (gchar *) g_dir_read_name (dir))) {
+
+			xmlNewChild (newNode, NULL, "page", filename);
+			xmlAddChild (newNode, xmlNewText ("\n      "));
+
+			add_man_page_to_toc (pager, dirname, filename);
+			priv->manpage_count++;
+		    }
+		}
+
+		/* we replace the node in the tree */
+		xmlReplaceNode (dirnode, newNode);
+
+		g_dir_close (dir);
+	    
+	    /* otherwise just read from the index file */
+	    } else {
+	    
+		objmanpages = xmlXPathEvalExpression ("page", xpath);
+
+		for (k=0; k < objmanpages->nodesetval->nodeNr; k++) {
+		    xmlNodePtr node = objmanpages->nodesetval->nodeTab[k];
+		    xmlChar *manpage = NULL;
+
+		    manpage = xmlNodeListGetString (manindex_xml,
+		                                    node->xmlChildrenNode, 1);
+
+		    add_man_page_to_toc (pager, dirname, manpage);
+		    priv->manpage_count++;
+	        }
+	    }
+	}
+
+	if (priv->man_manhash) {
+	    g_hash_table_destroy (priv->man_manhash);
+	    priv->man_manhash = NULL;
+	}
+    }
+
+    if (update_flag) {
+	create_manindex_file (index_file, manindex_xml);
+    }
+
+    return 1;
+}
+
 static gboolean
 process_mandir_pending (YelpTocPager *pager)
 {
-    xmlNodePtr tmp;
-    gchar *manpath;
-
-    gchar *dirname = NULL; 
+    static gchar *index_file = NULL;
     gchar *filename = NULL;
-    GDir  *dir;
-
-    const gchar * const * langs = g_get_language_names ();
+    gchar *dirname = NULL;
+    GDir  *dir = NULL; 
+    gint i, j, k;
 
     YelpTocPagerPriv *priv  = YELP_TOC_PAGER (pager)->priv;
 
     if (!priv->toc_doc) {
 	xmlXPathContextPtr xpath;
 	xmlXPathObjectPtr  obj;
-	gint i;
+
 	priv->toc_doc = xmlCtxtReadFile (priv->parser, DATADIR "/yelp/man.xml", NULL,
 					 XML_PARSE_NOBLANKS | XML_PARSE_NOCDATA  |
 					 XML_PARSE_NOENT    | XML_PARSE_NOERROR  |
@@ -587,6 +869,7 @@
 
 	xpath = xmlXPathNewContext (priv->toc_doc);
 	obj = xmlXPathEvalExpression (BAD_CAST "//toc", xpath);
+
 	for (i = 0; i < obj->nodesetval->nodeNr; i++) {
 	    xmlNodePtr node = obj->nodesetval->nodeTab[i];
 	    xmlChar *sect = xmlGetProp (node, BAD_CAST "sect");
@@ -597,145 +880,153 @@
 	}
     }
 
-    if (priv->langs_i == 0 && priv->manpaths_i == 0) {
-	if (priv->man_manhash)
-	    g_hash_table_destroy (priv->man_manhash);
-	priv->man_manhash = g_hash_table_new_full (g_str_hash, g_str_equal,
-						   g_free,     NULL);
-    }
+    if (!index_file)
+	index_file = g_build_filename (yelp_dot_dir(), "manindex.xml", NULL);
+  
+    /* On first call to this function, create a list of directories that we 
+     * need to process: we actually make a linked list (mandir_list) whose 
+     * members who are linked lists containing directories for a particular 
+     * man directory such as "man1", "man2", etc..  We do this because we 
+     * need a separate hash for every mandir */
+    if (!priv->mandir_list) {
+	const gchar * const * langs = g_get_language_names ();
+	gchar *manpath = NULL;
+	gchar **manpaths = NULL;
+
+	/* check for the existence of the xml cache file in ~/.gnome2/yelp.d/
+	 * if it exists, use it as the source for man pages instead of 
+	 * searching the hard disk for them - should make startup much faster */
+	if (g_file_test (index_file, G_FILE_TEST_EXISTS) &&
+	    create_toc_from_index (pager, index_file)) {
+
+	    /* we are done.. */
+	    g_print ("number of manpages added to toc: %d\n", priv->manpage_count);
+	    return FALSE;
+	} else {
+	    priv->manindex_xml = xmlNewDoc (BAD_CAST "1.0");
+	    priv->root = xmlNewNode (NULL, BAD_CAST "manindex");
+	    priv->ins  = priv->root;
+
+	    xmlDocSetRootElement (priv->manindex_xml, priv->root);
+
+	    xmlAddChild (priv->root, xmlNewText ("\n  "));
+
+	    if (!g_spawn_command_line_sync ("manpath", &manpath, NULL, NULL, NULL))
+		manpath = g_strdup (g_getenv ("MANPATH"));
 
-    if (!priv->manpaths) {
-	if (!g_spawn_command_line_sync ("manpath", &manpath, NULL, NULL, NULL))
-	    manpath = g_strdup (g_getenv ("MANPATH"));
+	    if (!manpath) {
+		manpath = g_strdup ("/usr/share/man");
+	    }
 
-	if (manpath) {
 	    g_strstrip (manpath);
-	    priv->manpaths = g_strsplit (manpath, G_SEARCHPATH_SEPARATOR_S, -1);
+	    manpaths = g_strsplit (manpath, G_SEARCHPATH_SEPARATOR_S, -1);
 	    g_free (manpath);
-	} else {
-	    goto done;
+
+	    for (i=0; mandirs[i] != NULL; i++) {
+		GSList *tmplist = NULL;
+
+		for (j=0; langs[j] != NULL; j++) {
+		    for (k=0; manpaths[k] != NULL; k++) { 
+			if (g_str_equal (langs[j], "C"))
+			    dirname = g_build_filename (manpaths[k], mandirs[i], NULL);
+			else
+			    dirname = g_build_filename (manpaths[k], langs[j], 
+			                                mandirs[i],
+			                                NULL);
+
+			tmplist = g_slist_prepend (tmplist, dirname);
+		    }
+		}
+
+		priv->mandir_list = g_slist_prepend (priv->mandir_list, tmplist);
+	    }
+ 
+	    priv->mandir_ptr = priv->mandir_list;
+	    if (priv->mandir_list && priv->mandir_list->data) {
+		priv->mandir_langpath = priv->mandir_list->data;
+	    }
 	}
     }
+    /* iterate through our previously created linked lists and create the
+     * table of contents from them */
+    else {
+	if (!priv->man_manhash) {
+	    priv->man_manhash = g_hash_table_new_full (g_str_hash, g_str_equal,
+	                                               g_free,     NULL);
 
-    if (g_str_equal (langs[priv->langs_i], "C"))
-	dirname = g_build_filename (priv->manpaths[priv->manpaths_i],
-				    mandirs[priv->mandirs_i],
-				    NULL);
-    else
-	dirname = g_build_filename (priv->manpaths[priv->manpaths_i],
-				    langs[priv->langs_i],
-				    mandirs[priv->mandirs_i],
-				    NULL);
-    dir = g_dir_open (dirname, 0, NULL);
-    if (dir) {
-	while ((filename = (gchar *) g_dir_read_name (dir))) {
-	    gchar *c1 = NULL, *c2 = NULL, *manname, *mansect, *manman;
-
-	    c1 = g_strrstr (filename, ".bz2");
-	    if (c1 && strlen (c1) != 4)
-		c1 = NULL;
-
-	    if (!c1) {
-		c1 = g_strrstr (filename, ".gz");
-		if (c1 && strlen (c1) != 3)
-		    c1 = NULL;
-	    }
+            priv->ins = xmlNewChild (priv->root, NULL, "mansect", NULL);
+	    xmlAddChild (priv->ins, xmlNewText ("\n    "));			    
+	}
 
-	    if (c1)
-		c2 = g_strrstr_len (filename, c1 - filename, ".");
-	    else
-		c2 = g_strrstr (filename, ".");
-
-	    if (c2) {
-		manname = g_strndup (filename, c2 - filename);
-		if (c1)
-		    mansect = g_strndup (c2 + 1, c1 - c2 - 1);
-		else
-		    mansect = g_strdup (c2 + 1);
-	    } else {
-		mansect = g_strdup (mandirs[priv->mandirs_i] + 3);
-		if (c1)
-		    manname = g_strndup (filename, c1 - filename);
-		else
-		    manname = g_strdup (filename);
-	    }
+	if (priv->mandir_langpath && priv->mandir_langpath->data) {
+	    dirname = priv->mandir_langpath->data;
 
-	    manman = g_strconcat (manname, ".", mansect, NULL);
+	    if ((dir = g_dir_open (dirname, 0, NULL))) {
+		struct stat buf;
+		gchar mtime_str[20];
 
-	    if (g_hash_table_lookup (priv->man_manhash, manman) == NULL) {
-		tmp = g_hash_table_lookup (priv->man_secthash, mansect);
-		if (tmp == NULL && strlen (mansect) > 1) {
-		    gchar *mansect0 = g_strndup (mansect, 1);
-		    tmp = g_hash_table_lookup (priv->man_secthash, mansect0);
-		}
+		if (g_stat (dirname, &buf) < 0)
+		    g_warning ("Unable to stat dir: \"%s\"\n", dirname);
 
-		if (tmp) {
-		    gchar *tooltip, *url_full, *url_short;
-		    YelpDocInfo *info;
-
-		    url_full = g_strconcat ("man:", dirname, "/", filename, NULL);
-		    url_short = g_strconcat ("man:", manname, ".", mansect, NULL);
-		    info = yelp_doc_info_get (url_full);
-
-		    if (info) {
-			yelp_doc_info_add_uri (info, url_short, YELP_URI_TYPE_MAN);
-			tmp = xmlNewChild (tmp, NULL, BAD_CAST "doc", NULL);
-			xmlNewNsProp (tmp, NULL, BAD_CAST "href", 
-				      BAD_CAST url_full);
-
-			xmlNewChild (tmp, NULL, BAD_CAST "title", 
-				     BAD_CAST manname);
-			tooltip = g_strdup_printf (_("Read man page for %s"), manname);
-			xmlNewChild (tmp, NULL, BAD_CAST "tooltip", 
-				     BAD_CAST tooltip);
-			g_free (tooltip);
-		    }
+		g_snprintf (mtime_str, 20, "%u", (guint) buf.st_mtime);
+
+		priv->ins = xmlNewChild (priv->ins, NULL, "dir", NULL);
+		xmlNewProp (priv->ins, "mtime", mtime_str);
+		xmlAddChild (priv->ins, xmlNewText ("\n      "));
+		xmlNewChild (priv->ins, NULL, "name", dirname);
+		xmlAddChild (priv->ins, xmlNewText ("\n      "));
+		xmlAddChild (priv->ins->parent, xmlNewText ("\n    "));
+
+		while ((filename = (gchar *) g_dir_read_name (dir))) {
+
+		    xmlNewChild (priv->ins, NULL, "page", filename);
+		    xmlAddChild (priv->ins, xmlNewText ("\n      "));
 
-		    g_free (url_full);
-		    g_free (url_short);
-		} else {
-		    g_warning ("Could not locate section %s for %s\n",
-			       mansect, manman);
+		    add_man_page_to_toc (pager, dirname, filename);
+		    priv->manpage_count++;
 		}
 
-		g_hash_table_insert (priv->man_manhash, g_strdup (manman), priv);
+		priv->ins = priv->ins->parent;
+
+		g_dir_close (dir);
 	    }
 
-	    g_free (manman);
-	    g_free (manname);
-	    g_free (mansect);
-	}
-	g_dir_close (dir);
-    }
+	    priv->mandir_langpath = g_slist_next (priv->mandir_langpath);
 
- done:
-    g_free (dirname);
+	} else {
+	    priv->mandir_ptr = g_slist_next (priv->mandir_ptr);
 
-    if (priv->manpaths) {
-	priv->manpaths_i++;
-	if (priv->manpaths[priv->manpaths_i] == NULL) {
-	    priv->manpaths_i = 0;
-	    priv->langs_i++;
-	}
-    }
-    if (langs[priv->langs_i] == NULL) {
-	priv->langs_i = 0;
-	priv->mandirs_i++;
-	if (priv->man_manhash) {
-	    g_hash_table_destroy (priv->man_manhash);
-	    priv->man_manhash = NULL;
-	}
-    }
-    if (mandirs[priv->mandirs_i] == NULL) {
-	if (priv->manpaths) {
-	    g_strfreev (priv->manpaths);
-	    priv->manpaths = NULL;
-	}
-	if (priv->man_secthash) {
-	    g_hash_table_destroy (priv->man_secthash);
-	    priv->man_secthash = NULL;
+	    if (priv->mandir_ptr && priv->mandir_ptr->data) {
+		priv->mandir_langpath = priv->mandir_ptr->data;
+
+		if (priv->man_manhash) {
+		    g_hash_table_destroy (priv->man_manhash);
+		    priv->man_manhash = NULL;
+		}
+	    } else {   /* no more entries to prcoess, write file & cleanup */
+		GSList *listptr = priv->mandir_list;
+
+		while (listptr && listptr->data)  {
+		    GSList *langptr = listptr->data;
+
+		    while (langptr && langptr->data) {
+		    	g_free (langptr->data);
+			langptr = g_slist_next (langptr);
+		    }
+		    g_slist_free (listptr->data);
+		    
+		    listptr = g_slist_next (listptr);
+		}
+
+		g_slist_free (priv->mandir_list);
+
+		create_manindex_file (index_file, priv->manindex_xml);
+		
+		/* done processing */
+		g_print ("number of manpages added to toc: %d\n", priv->manpage_count);
+		return FALSE;
+	    }
 	}
-	return FALSE;
     }
 
     return TRUE;
Index: src/yelp-utils.c
===================================================================
RCS file: /cvs/gnome/yelp/src/yelp-utils.c,v
retrieving revision 1.28
diff -u -r1.28 yelp-utils.c
--- src/yelp-utils.c	10 Dec 2005 15:14:42 -0000	1.28
+++ src/yelp-utils.c	10 Dec 2005 20:34:58 -0000
@@ -17,7 +17,8 @@
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  *
- * Author: Shaun McCance  <shaunm gnome org>
+ * Authors: Shaun McCance  <shaunm gnome org>
+ *          Brent Smith  <gnome nextreality net>
  */
 
 #ifdef HAVE_CONFIG_H
@@ -29,6 +30,7 @@
 #include <libgnomevfs/gnome-vfs.h>
 #include <libgnomevfs/gnome-vfs-mime-utils.h>
 #include <libgnome/gnome-program.h>
+#include <libgnome/gnome-init.h>
 
 #include "yelp-utils.h"
 
@@ -69,11 +71,34 @@
 static YelpDocType  get_doc_type       (gchar   *uri);
 static gchar *      convert_ghelp_uri  (gchar   *uri);
 
-static gchar *      convert_man_uri    (gchar   *uri);
+static gchar *      convert_man_uri    (gchar   *uri, gboolean trust_uri);
 static gchar *      convert_info_uri   (gchar   *uri);
 
+static gchar *dot_dir = NULL;
+
+const char *
+yelp_dot_dir (void)
+{
+    if (dot_dir == NULL) {
+	dot_dir = g_build_filename (g_get_home_dir(), GNOME_DOT_GNOME,
+	                            "yelp.d", NULL);
+	
+	if (!g_file_test (dot_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
+	    mkdir (dot_dir, 0750);		
+    }
+
+    return dot_dir;
+}
+
+/* @uri:       the uri to interpret for the new YelpDocInfo struct 
+ * @trust_uri: if the uri is absolute and is known to exist,
+ *             then this should be set.  Only makes sense for local
+ *             files.  This is here for performance reasons, adding
+ *             40,000 man pages and accessing the disk for each one
+ *             can get pretty expensive.
+ */
 YelpDocInfo *
-yelp_doc_info_new (const gchar *uri)
+yelp_doc_info_new (const gchar *uri, gboolean trust_uri)
 {
     YelpDocInfo *doc;
     gchar       *doc_uri  = NULL;
@@ -87,10 +112,13 @@
     d (g_print ("yelp_doc_info_new\n"));
     d (g_print ("  uri      = \"%s\"\n", uri));
 
-    full_uri =
+    if (trust_uri)
+	full_uri = gnome_vfs_make_uri_from_input (uri);
+    else
+	full_uri =
 	gnome_vfs_make_uri_from_input_with_dirs	(uri,
 						 GNOME_VFS_MAKE_URI_DIR_CURRENT);
-
+    
     if (g_str_has_prefix (full_uri, "file:")) {
 	if ((cur = strchr (full_uri, '#')))
 	    doc_uri = g_strndup (full_uri, cur - full_uri);
@@ -107,7 +135,7 @@
 	uri_type = YELP_URI_TYPE_GHELP;
     }
     else if (g_str_has_prefix (full_uri, "man:")) {
-	doc_uri  = convert_man_uri (full_uri);
+	doc_uri  = convert_man_uri (full_uri, trust_uri);
 	doc_type = YELP_DOC_TYPE_MAN;
 	uri_type = YELP_URI_TYPE_MAN;
     }
@@ -157,7 +185,7 @@
 }
 
 YelpDocInfo *
-yelp_doc_info_get (const gchar *uri)
+yelp_doc_info_get (const gchar *uri, gboolean trust_uri)
 {
     YelpDocInfo *doc;
     gint i;
@@ -187,7 +215,7 @@
     doc = (YelpDocInfo *) g_hash_table_lookup (doc_info_table, doc_uri);
 
     if (!doc) {
-	doc = yelp_doc_info_new (doc_uri);
+	doc = yelp_doc_info_new (doc_uri, trust_uri);
 	if (doc && doc->type != YELP_DOC_TYPE_EXTERNAL) {
 	    YelpDocInfo *old_doc = NULL;
 
@@ -690,7 +718,7 @@
 }
 
 static gchar *
-convert_man_uri (gchar *uri)
+convert_man_uri (gchar *uri, gboolean trust_uri)
 {
     gchar *path, *cur;
     gchar *doc_uri  = NULL;
@@ -716,7 +744,9 @@
 
     /* An absolute file path after man: */
     if (path[0] == '/') {
-	if (g_file_test (path, G_FILE_TEST_IS_REGULAR))
+	if (trust_uri)
+	    doc_uri = g_strconcat ("file://", path, NULL);
+	else if (g_file_test (path, G_FILE_TEST_IS_REGULAR))
 	    doc_uri = g_strconcat ("file://", path, NULL);
 	goto done;
     }
Index: src/yelp-utils.h
===================================================================
RCS file: /cvs/gnome/yelp/src/yelp-utils.h,v
retrieving revision 1.12
diff -u -r1.12 yelp-utils.h
--- src/yelp-utils.h	28 Oct 2005 20:37:37 -0000	1.12
+++ src/yelp-utils.h	10 Dec 2005 20:34:58 -0000
@@ -93,8 +93,11 @@
     gchar *toc_id;
 };
 
-YelpDocInfo *       yelp_doc_info_new           (const gchar   *uri);
-YelpDocInfo *       yelp_doc_info_get           (const gchar   *uri);
+const char *        yelp_dot_dir                (void);
+YelpDocInfo *       yelp_doc_info_new           (const gchar   *uri,
+                                                 gboolean trust_uri);
+YelpDocInfo *       yelp_doc_info_get           (const gchar   *uri,
+                                                 gboolean trust_uri);
 void                yelp_doc_info_add_uri       (YelpDocInfo   *doc_info,
 						 const gchar   *uri,
 						 YelpURIType    type);
Index: src/yelp-window.c
===================================================================
RCS file: /cvs/gnome/yelp/src/yelp-window.c,v
retrieving revision 1.184
diff -u -r1.184 yelp-window.c
--- src/yelp-window.c	8 Dec 2005 16:41:24 -0000	1.184
+++ src/yelp-window.c	10 Dec 2005 20:35:00 -0000
@@ -740,7 +740,7 @@
 
     priv = window->priv;
 
-    doc_info = yelp_doc_info_get (uri);
+    doc_info = yelp_doc_info_get (uri, FALSE);
     if (!doc_info) {
 	GError *error = NULL;
 	g_set_error (&error, YELP_ERROR, YELP_ERROR_NO_DOC,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]