bug-cflow
[Top][All Lists]
Advanced

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

[Bug-cflow] [Suggestion] Integration of cflow and GLOBAL


From: Shigio YAMAGUCHI
Subject: [Bug-cflow] [Suggestion] Integration of cflow and GLOBAL
Date: Tue, 11 Jul 2006 14:26:19 +0900

Hello,
I have written a piece of code to integrate cflow with GNU GLOBAL.
With the patch attached to this mail, the source browser of htags(1)
becomes available from cflow.

For example, invoking modified cflow in cflow-1.1 directory like this:

   $ cflow --format=html --output=index.html src/*.[ch]
                    ~~~~
Cflow invokes gtags(1) and htags(1) which are part of GLOBAL
to generate source code browser.  They traverse under the current
directory, make tag files and generates hypertext of source code.

        GPATH, GTAGS, GRTAGS, GSYMS     ... tag files
        HTML/                           ... hypertext

Cflow continuously generates HTML output with buring links to
the hypertext like follows:

   [index.html]
   +---------------------------------------
   |main: () <int main (int argc,char **argv) at src/main.c:745>:
   |~~~~
   |    fprintf: ()
   |    exit: ()
   |    atoi: ()
   |    htags_load_filemap: () <int htags_load_filemap (const char *filemap) ...
   |    ~~~~~~~~~~~~~~~~~~
   |        load_filemap_contents: () <int load_filemap_contents (const char ...
   |        ~~~~~~~~~~~~~~~~~~~~~
   |            open: ()
   | .....

   * xxxxx means a link to 'HTML/...'.
     ~~~~~

Of course, this facility requires GNU GLOBAL installed in your machine.

Though I don't know whether you like this idea or not,
I hope GLOBAL to be available in all profitable environment.

What do you think?
If there is something problem, please tell me.

Thank you for your excellent cflow!

================================================================================

[How to apply the patch]

$ tar xzvf cflow-1.1.tar.gz
$ cd cflow-1.1
$ patch -p1 < [THIS MAIL]
$ autoreconf
$ ./configure
$ make

html.c is based on gnu.c.
htags_path2url.c is in the public domain.

[How to install GLOBAL]

(Download tarball from http://www.gnu.org/software/global/download.html)

$ tar xzvf global-5.1.tar.gz
$ cd global-5.1
$ ./configure
$ make
# make install

[Patch for new facility]

diff -Ncr cflow-1.1/src/Makefile.am cflow-1.1-html/src/Makefile.am
*** cflow-1.1/src/Makefile.am   Mon Oct  3 23:08:04 2005
--- cflow-1.1-html/src/Makefile.am      Tue Jul 11 11:11:42 2006
***************
*** 31,37 ****
   cflow.h\
   parser.h\
   gnu.c\
!  posix.c
  
  localedir = $(datadir)/locale
  
--- 31,39 ----
   cflow.h\
   parser.h\
   gnu.c\
!  posix.c\
!  html.c\
!  htags_path2url.c
  
  localedir = $(datadir)/locale
  
diff -Ncr cflow-1.1/src/cflow.h cflow-1.1-html/src/cflow.h
*** cflow-1.1/src/cflow.h       Fri Oct  7 16:14:50 2005
--- cflow-1.1-html/src/cflow.h  Tue Jul 11 11:11:42 2006
***************
*** 184,189 ****
--- 184,193 ----
  
  void sourcerc(int *, char ***);
  
+ int htags_load_filemap(const char *);
+ void htags_unload_filemap(void);
+ int htags_path2url(const char *, int, char *, int);
+ 
  typedef enum {
       cflow_output_init,
       cflow_output_begin,
***************
*** 215,218 ****
  int posix_output_handler(cflow_output_command cmd,
                         FILE *outfile, int line,
                         void *data, void *handler_data);
! 
--- 219,224 ----
  int posix_output_handler(cflow_output_command cmd,
                         FILE *outfile, int line,
                         void *data, void *handler_data);
! int html_output_handler(cflow_output_command cmd,
!                        FILE *outfile, int line,
!                        void *data, void *handler_data);
diff -Ncr cflow-1.1/src/htags_path2url.c cflow-1.1-html/src/htags_path2url.c
*** cflow-1.1/src/htags_path2url.c      Thu Jan  1 09:00:00 1970
--- cflow-1.1-html/src/htags_path2url.c Tue Jul 11 11:11:42 2006
***************
*** 0 ****
--- 1,321 ----
+ /*
+  * Htags Hyper-text Reference Kit.
+  *
+  * This file is placed into the public domain by the author,
+  * 2005, 2006 Tama Communications Corporation.
+  *
+  * Two library function, qsort(3) and bsearch(3), are requried.
+  */
+ #include <fcntl.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <sys/param.h>
+ #include <sys/stat.h>
+ 
+ int htags_load_filemap(const char *);
+ void htags_unload_filemap(void);
+ int htags_path2url(const char *, int, char *, int);
+ 
+ /*
+  * Usage by example.
+  *
+  * Getting the URL of "i386/i386/identcpu.c" at 120, in variable url.
+  *
+  *    char url[MAXPATHLEN+1];
+  *    -- Load filemap generated by htags(1).
+  *    ret = htags_load_filemap("HTML/FILEMAP");
+  *    if (ret != 0)
+  *            ERROR;
+  *    -- Get URL of the specified file name and line number.
+  *    ret = htags_path2url("i386/i386/identcpu.c", 120, url, sizeof(url));
+  *    if (ret != 0)
+  *            ERROR;
+  *    url == 'S/1238.html#L120'
+  *    -- release resource
+  *    htags_unload_filemap();
+  *
+  * Since the URL is a relative path from the HTML directory, you should
+  * modify it so that your application program works well.
+  */
+ /*
+  * in memory FILEMAP
+  *
+  * Alphabetical sorted table.
+  */
+ struct map
+ {
+       const char *name;
+       const char *path;
+ };
+ /*
+  * Global variables.
+  *
+  * These variables are set by htags_load_filemap(), and referred by
+  * htags_path2url() and htags_unload_filemap().
+  */
+ static char *global_contents;         /* filemap contents             */
+ static struct map *global_map;                /* file -> url mapping table    
*/
+ static int global_maplines;           /* the lines of global_map      */
+ 
+ /*----------------------------------------------------------------------*/
+ /* Local functions                                                    */
+ /*----------------------------------------------------------------------*/
+ /*
+  * load contents of FILEMAP into the memory.
+  *
+  *    i)      file    path of FILEMAP
+  *    o)      area    file contents (malloced)
+  *    o)      size    size of area
+  *    r)      0 succesful
+  *            -1: out of memory.
+  *            -2: FILEMAP not found.
+  *            -3: cannot fstat FILEMAP.
+  *            -4: cannot read FILEMAP.
+  */
+ static int
+ load_filemap_contents(const char *file, char **area, int *size)
+ {
+       struct stat st;
+       char *p = NULL;
+       int status = 0;
+       int fd = -1;
+ 
+       /* Load FILEMAP contents */
+       status = -2;
+       if ((fd = open(file, 0)) < 0)
+               goto err;
+       status = -3;
+       if (fstat(fd, &st) < 0)
+               goto err;
+       status = -1;
+       if ((p = (char *)malloc(st.st_size)) == NULL)
+               goto err;
+       status = -4;
+       if (read(fd, p, st.st_size) != st.st_size)
+               goto err;
+       close(fd);
+       *area = p;
+       *size = st.st_size;
+       return 0;
+ err:
+       if (fd != -1)
+               close(fd);
+       if (p != NULL)
+               free(p);
+       return status;
+ }
+ 
+ /*
+  * comparison function for bsearch().
+  */
+ static int
+ cmp(const void *s1, const void *s2)
+ {
+       return strcmp(((struct map *)s1)->name, ((struct map *)s2)->name);
+ }
+ /*
+  * creates index for in core FILEMAP.
+  *
+  *    i)      area    filemap contents
+  *    i)      size    size of area
+  *    o)      map     map structure
+  *    o)      lines   map lines
+  *    r)       0: succesful
+  *            -1: out of memory.
+  *            -5: illegal format.
+  */
+ static int
+ create_filemap_index(char *area, int size, struct map **map, int *lines)
+ {
+       char *p, *endp = area + size;
+       struct map *m;
+       int n = 0;
+       int status;
+       int i;
+ 
+       /* Count line number */
+       for (p = area; p < endp; p++)
+               if (*p == '\n')
+                       n++; 
+       status = -1;
+       if ((m = (struct map *)malloc(sizeof(struct map) * n)) == NULL)
+               return -1;
+       /*
+        * FILEMAP format:
+        * <NAME>\t<PATH>\n
+        */
+       p = area;
+       for (i = 0; i < n; i++) {
+               m[i].name = p;
+               while (*p && *p != '\t')
+                       p++;
+               if (*p == '\0')
+                       goto ferr;
+               *p++ = '\0';
+               m[i].path = p;
+               while (*p && *p != '\r' && *p != '\n')
+                       p++;
+               if (*p == '\0')
+                       goto ferr;
+               if (*p == '\r')
+                       *p++ = '\0';
+               if (*p == '\n')
+                       *p++ = '\0';
+       }
+       qsort(m, n, sizeof(struct map), cmp);
+       *map = m;
+       *lines = n;
+       return 0;
+ ferr:
+       free(m);
+       return -5;
+ }
+ 
+ /*
+  * unloads FILEMAP.
+  */
+ static void
+ unload_filemap(void)
+ {
+       (void)free(global_map);
+       global_map = NULL;
+       (void)free(global_contents);
+       global_contents = NULL;
+ }
+ /*----------------------------------------------------------------------*/
+ /* Global functions                                                   */
+ /*----------------------------------------------------------------------*/
+ /*
+  * loads FILEMAP.
+  *
+  *    i)      filemap FILEMAP file
+  *    go)     global_contents filemap contents (for free)
+  *    go)     global_map      filemap index.
+  *    go)     global_maplines lines of filemap index.
+  *    r)               0: succesful
+  *                    -1: out of memory.
+  *                    -2: FILEMAP not found.
+  *                    -3: cannot fstat FILEMAP.
+  *                    -4: cannot read FILEMAP.
+  *                    -5: format error.
+  */
+ int
+ htags_load_filemap(const char *filemap)
+ {
+       int status = 0;
+       char *area;
+       int size, lines;
+       struct map *map;
+ 
+       status = load_filemap_contents(filemap, &area, &size);
+       if (status < 0)
+               return status;
+       status = create_filemap_index(area, size, &map, &lines);
+       if (status < 0) {
+               (void)free(area);
+               return status;
+       }
+       global_contents = area;
+       global_map = map;
+       global_maplines = lines;
+       return 0;
+ }
+ /*
+  * unloads FILEMAP.
+  */
+ void
+ htags_unload_filemap(void)
+ {
+       unload_filemap();
+ }
+ 
+ /*
+  * convert file path name into the URL in the hypertext.
+  *
+  *    i)      path    path name in the filesystem.
+  *    i)      line    0: ignored, !=0: line number in path.
+  *    o)      url     result url
+  *    i)      size    size of url
+  *    gi)     global_contents filemap contents (for free)
+  *    gi)     global_map      filemap index.
+  *    gi)     global_maplines lines of filemap index.
+  *    r)              0: succesful
+  *                    1: path not found
+  *                    -1: filemap not loaded yet
+  *
+  * URL: S/<file id>.html#<line number>
+  */
+ int
+ htags_path2url(const char *path, int line, char *url, int size)
+ {
+       struct map tmp;
+       struct map *result;
+ 
+       if (global_contents == NULL || global_map == NULL)
+               return -1;
+       tmp.name = path;
+       result = (struct map *)bsearch(&tmp, global_map, global_maplines, 
sizeof(struct map), cmp);
+       if (result == NULL)
+               return 1;
+       if (line > 0)
+               snprintf(url, size, "%s#L%d", result->path, line);
+       else
+               snprintf(url, size, "%s", result->path);
+       return 0;
+ }
+ 
+ #ifdef TEST
+ 
+ /*
+  * Usage: htags_path2url <html directory> <path name> [<line number>]
+  *
+  * $ htags_path2url HTML/FILEMAP i386/i386/identcpu.c 120
+  * i386/i386/identcpu.c, line 120 => S/1238.html#L120
+  * $ _
+  */
+ int
+ main(int argc, char **argv)
+ {
+       char url[MAXPATHLEN];
+       char *path, *html;
+       int line = 0;
+       int ret;
+ 
+       if (argc < 3) {
+               fprintf(stderr, "Usage: path2url HTML path [line]\n");
+               exit(1);
+       }
+       html = argv[1];
+       path = argv[2];
+       if (argc > 3)
+               line = atoi(argv[3]);
+       ret = htags_load_filemap(html);
+       if (ret != 0) {
+               fprintf(stderr, "htags_load_filemap failed.(");
+               switch (ret) {
+               case -1: fprintf(stderr, "out of memory"); break;
+               case -2: fprintf(stderr, "FILEMAP not found."); break;
+               case -3: fprintf(stderr, "cannot fstat FILEMAP."); break;
+               case -4: fprintf(stderr, "cannot read FILEMAP."); break;
+               case -5: fprintf(stderr, "format error."); break;
+               default: fprintf(stderr, "unknown error."); break;
+               }
+               fprintf(stderr, ")\n");
+               exit(1);
+       }
+       ret = htags_path2url(path, line, url, sizeof(url));
+       if (ret != 0) {
+               fprintf(stderr, "htags_path2url failed.(");
+               switch (ret) {
+               case  1: fprintf(stderr, "path not found."); break;
+               case -1: fprintf(stderr, "out of memory."); break;
+               }
+               fprintf(stderr, ")\n");
+               exit(1);
+       }
+       fprintf(stdout, "%s, line %d => %s\n", path, line, url);
+       htags_unload_filemap();
+       return 0;
+ }
+ #endif
diff -Ncr cflow-1.1/src/html.c cflow-1.1-html/src/html.c
*** cflow-1.1/src/html.c        Thu Jan  1 09:00:00 1970
--- cflow-1.1-html/src/html.c   Tue Jul 11 11:11:42 2006
***************
*** 0 ****
--- 1,112 ----
+ /* This file is part of GNU cflow
+    Copyright (C) 1997,2005 Sergey Poznyakoff
+  
+    GNU cflow is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+  
+    GNU cflow is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+ 
+    You should have received a copy of the GNU General Public
+    License along with GNU cflow; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA */
+ 
+ #include <cflow.h>
+ 
+ static void
+ print_function_name(Symbol *sym, int has_subtree)
+ {
+      char url[1024];
+ 
+      url[0] = '\0';
+      /*
+       * Get URL of the definition in source browser.
+       */
+      if (sym && sym->source && sym->def_line)
+           htags_path2url(sym->source, sym->def_line, url, sizeof(url));
+ 
+      if (url[0])
+         fprintf(outfile, "<a href='HTML/%s'>%s</a>: ", url, sym->name);
+      else
+         fprintf(outfile, "%s: ", sym->name);
+      if (sym->arity >= 0)
+         fprintf(outfile, "()");
+      if (sym->decl)
+         fprintf(outfile, " &lt;%s at %s:%d&gt;",
+                 sym->decl,
+                 sym->source,
+                 sym->def_line);
+      if (sym->active) {
+         fprintf(outfile, " (recursive: see %d)", sym->active-1);
+         return;
+      }
+      if (sym->recursive)
+         fprintf(outfile, " (R)");
+      if (!print_as_tree && has_subtree)
+         fprintf(outfile, ":");
+ }
+ 
+ 
+ static int
+ print_symbol(FILE *outfile, int line, struct output_symbol *s)
+ {
+      int has_subtree = s->direct ? 
+                         s->sym->callee != NULL :
+                         s->sym->caller != NULL;
+      
+      print_level(s->level, s->last);
+      print_function_name(s->sym, has_subtree);
+         
+      if (brief_listing) {
+         if (s->sym->expand_line) {
+              fprintf(outfile, " [see %d]", s->sym->expand_line);
+              return 1;
+         } else if (s->sym->callee)
+              s->sym->expand_line = line;
+      }
+      return 0;
+ }
+ 
+ int
+ html_output_handler(cflow_output_command cmd,
+                  FILE *outfile, int line,
+                  void *data, void *handler_data)
+ {
+      switch (cmd) {
+      case cflow_output_begin:
+           fprintf(outfile, "<html><body><pre>\n");
+           newline();
+         break;
+      case cflow_output_init:
+           /*
+            * Make hypertext of source tree in HTML.
+            */
+           if (system("htags -sanogv") != 0)
+               error(1, 0, _("Failed executing htags"));
+           /*
+            * Load mapping table (path name => URL).
+            */
+           if (htags_load_filemap("HTML/FILEMAP") != 0)
+               error(1, 0, _("Cannot load FILEMAP"));
+           break;
+      case cflow_output_end:
+           fprintf(outfile, "</pre></body></html>\n");
+           break;
+      case cflow_output_separator:
+         break;
+      case cflow_output_newline:
+         fprintf(outfile, "\n");
+         break;
+      case cflow_output_text:
+         fprintf(outfile, "%s", (char*) data);
+         break;
+      case cflow_output_symbol:
+         return print_symbol(outfile, line, data);
+      }
+      return 0;
+ }
diff -Ncr cflow-1.1/src/main.c cflow-1.1-html/src/main.c
*** cflow-1.1/src/main.c        Fri Oct  7 16:14:50 2005
--- cflow-1.1-html/src/main.c   Tue Jul 11 11:11:42 2006
***************
*** 59,65 ****
       { "include", 'i', N_("CLASSES"), 0,
         N_("Include specified classes of symbols (see below). Prepend CLASSES 
with ^ or - to exclude them from the output"), GROUP_ID+1 },
       { "format", 'f', N_("NAME"), 0,
!        N_("Use given output format NAME. Valid names are `gnu' (default) and 
`posix'"),
         GROUP_ID+1 },
       { "reverse", 'r', NULL, 0,
         N_("* Print reverse call tree"), GROUP_ID+1 },
--- 59,65 ----
       { "include", 'i', N_("CLASSES"), 0,
         N_("Include specified classes of symbols (see below). Prepend CLASSES 
with ^ or - to exclude them from the output"), GROUP_ID+1 },
       { "format", 'f', N_("NAME"), 0,
!        N_("Use given output format NAME. Valid names are `gnu' (default), 
`posix' and `html'"),
         GROUP_ID+1 },
       { "reverse", 'r', NULL, 0,
         N_("* Print reverse call tree"), GROUP_ID+1 },
***************
*** 752,757 ****
--- 752,758 ----
       
       register_output("gnu", gnu_output_handler, NULL);
       register_output("posix", posix_output_handler, NULL);
+      register_output("html", html_output_handler, NULL);
  
       symbol_map = SM_FUNCTIONS|SM_STATIC;
  
--
Shigio YAMAGUCHI <address@hidden> - Tama Communications Corporation
PGP fingerprint: D1CB 0B89 B346 4AB6 5663  C4B6 3CA5 BBB3 57BE DDA3




reply via email to

[Prev in Thread] Current Thread [Next in Thread]