/[CvsGraph]/cvsgraph/cvsgraph.c
ViewVC logotype

Diff of /cvsgraph/cvsgraph.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph | View Patch Patch

revision 1.43, Thu Aug 5 09:48:32 2004 UTC revision 1.44, Sun Aug 15 16:58:22 2004 UTC
# Line 23  Line 23 
23    
24  #include <stdio.h>  #include <stdio.h>
25  #include <stdlib.h>  #include <stdlib.h>
26    #include <stdarg.h>
27  #include <unistd.h>  #include <unistd.h>
28  #include <string.h>  #include <string.h>
29  #include <assert.h>  #include <assert.h>
# Line 94  Line 95 
95    
96  config_t conf;  config_t conf;
97  int debuglevel;  int debuglevel;
98  color_t white_color = {255, 255, 255, 0};  
99  color_t black_color = {0, 0, 0, 0};  static color_t white_color = {255, 255, 255, 0};
100    static color_t black_color = {0, 0, 0, 0};
101    
102    static branch_t *subtree_branch = NULL;         /* Set to the (first) subtree branch that we want to show */
103    static revision_t *subtree_rev = NULL;          /* Set to the subtree revision which branches we want to show */
104    
105    static msg_stack_t *msg_stack = NULL;           /* Messages that would otherwise be sent to stderr goto the image */
106    static int nmsg_stack = 0;
107    
108  /*  /*
109   **************************************************************************   **************************************************************************
# Line 110  Line 118 
118  static void add_string_str_html(const char *s, int maxlen);  static void add_string_str_html(const char *s, int maxlen);
119  static void add_string_str_len(const char *s, int maxlen);  static void add_string_str_len(const char *s, int maxlen);
120    
121    static void calc_subtree_size(branch_t *b, int *x, int *y, int *w, int *h);
122    
123  /*  /*
124   **************************************************************************   **************************************************************************
125   * Debug routines   * Debug routines
# Line 216  Line 226 
226    
227  /*  /*
228   **************************************************************************   **************************************************************************
229     * Error/Warning Message helpers
230     **************************************************************************
231     */
232    #define MSGBUFSIZE      256
233    void stack_msg(int severity, const char *fmt, ...)
234    {
235            va_list va;
236            int i;
237            char *buf = xmalloc(MSGBUFSIZE);
238            switch(severity)
239            {
240            case MSG_WARN:  sprintf(buf, "Warning: "); break;
241            case MSG_ERR:   sprintf(buf, "Error: "); break;
242            default:        sprintf(buf, "Unqualified error: "); break;
243            }
244            i = strlen(buf);
245            assert(i < MSGBUFSIZE);
246            va_start(va, fmt);
247            vsnprintf(buf+i, MSGBUFSIZE-i, fmt, va);
248            va_end(va);
249            if(!msg_stack)
250                    msg_stack = xmalloc(sizeof(*msg_stack));
251            else
252            {
253                    msg_stack = xrealloc(msg_stack, (nmsg_stack+1)*sizeof(*msg_stack));
254            }
255            msg_stack[nmsg_stack].msg = buf;
256            msg_stack[nmsg_stack].severity = severity;
257            nmsg_stack++;
258    }
259    
260    /*
261     **************************************************************************
262   * Read the rcs file   * Read the rcs file
263   **************************************************************************   **************************************************************************
264   */   */
265  rcsfile_t *get_rcsfile(const char *cvsroot, const char *module, const char *file)  static rcsfile_t *get_rcsfile(const char *cvsroot, const char *module, const char *file)
266  {  {
267          char *cmd = NULL;          char *cmd = NULL;
268          int rv;          int rv;
# Line 270  Line 313 
313   * Sort and find helpers   * Sort and find helpers
314   **************************************************************************   **************************************************************************
315   */   */
316  int count_dots(const char *s)  static int count_dots(const char *s)
317  {  {
318          int i;          int i;
319          for(i = 0; *s; s++)          for(i = 0; *s; s++)
# Line 281  Line 324 
324          return i;          return i;
325  }  }
326    
327  int compare_rev(int bcmp, const rev_t *r1, const rev_t *r2)  static int compare_rev(int bcmp, const rev_t *r1, const rev_t *r2)
328  {  {
329          int d1, d2;          int d1, d2;
330          char *c1, *c2;          char *c1, *c2;
# Line 447  Line 490 
490          return r;          return r;
491  }  }
492    
493  void build_branch(branch_t ***bl, int *nbl, delta_t **sdl, int nsdl, dtext_t **sdt, int nsdt, delta_t *head)  static void build_branch(branch_t ***bl, int *nbl, delta_t **sdl, int nsdl, dtext_t **sdt, int nsdt, delta_t *head)
494  {  {
495          branch_t *b;          branch_t *b;
496          dtext_t *text;          dtext_t *text;
# Line 457  Line 500 
500    
501          if(head->flag)          if(head->flag)
502          {          {
503                  fprintf(stderr, "Circular reference on '%s' in branchpoint\n", head->rev->rev);                  stack_msg(MSG_ERR, "Circular reference on '%s' in branchpoint\n", head->rev->rev);
504                  return;                  return;
505          }          }
506          head->flag++;          head->flag++;
# Line 500  Line 543 
543                  head = find_delta(sdl, nsdl, head->next);                  head = find_delta(sdl, nsdl, head->next);
544                  if(!head)                  if(!head)
545                  {                  {
546                          fprintf(stderr, "Next revision (%s) not found in deltalist\n", head->next->rev);                          stack_msg(MSG_ERR, "Next revision (%s) not found in deltalist\n", head->next->rev);
547                          return;                          return;
548                  }                  }
549                  if(head->flag)                  if(head->flag)
550                  {                  {
551                          fprintf(stderr, "Circular reference on '%s'\n", head->rev->rev);                          stack_msg(MSG_ERR, "Circular reference on '%s'\n", head->rev->rev);
552                          return;                          return;
553                  }                  }
554                  head->flag++;                  head->flag++;
# Line 552  Line 595 
595          head = find_delta(sdelta, nsdelta, rcs->head);          head = find_delta(sdelta, nsdelta, rcs->head);
596          if(!head)          if(!head)
597          {          {
598                  fprintf(stderr, "Head revision (%s) not found in deltalist\n", rcs->head->rev);                  stack_msg(MSG_ERR, "Head revision (%s) not found in deltalist\n", rcs->head->rev);
599                  return 0;                  return 0;
600          }          }
601          bl = NULL;          bl = NULL;
# Line 619  Line 662 
662          char *r;          char *r;
663          if(!dots)          if(!dots)
664          {          {
665                  fprintf(stderr, "FIXME: previous_rev(\"%s\"): Cannot determine parent branch revision\n", c);                  stack_msg(MSG_ERR, "FIXME: previous_rev(\"%s\"): Cannot determine parent branch revision\n", c);
666                  return xstrdup("1.0");  /* FIXME: don't know what the parent is */                  return xstrdup("1.0");  /* FIXME: don't know what the parent is */
667          }          }
668          if(dots & 1)          if(dots & 1)
# Line 630  Line 673 
673                  assert(cptr != NULL);                  assert(cptr != NULL);
674                  if(dots == 1)                  if(dots == 1)
675                  {                  {
676                          fprintf(stderr, "FIXME: previous_rev(\"%s\"): Going beyond top-level?\n", c);                          stack_msg(MSG_ERR, "FIXME: previous_rev(\"%s\"): Going beyond top-level?\n", c);
677                          /* FIXME: What is the parent of 1.1? */                          /* FIXME: What is the parent of 1.1? */
678                          cptr[1] = '\0';                          cptr[1] = '\0';
679                          strcat(r, "0");                          strcat(r, "0");
# Line 707  Line 750 
750          err = regcomp(refrom, conf.merge_from, rcflags);          err = regcomp(refrom, conf.merge_from, rcflags);
751          if(err)          if(err)
752          {          {
753                  if(!quiet)                  char *msg;
754                  {                  i = regerror(err, refrom, NULL, 0);
755                          char *msg;                  msg = xmalloc(i+1);
756                          i = regerror(err, refrom, NULL, 0);                  regerror(err, refrom, msg, i+1);
757                          msg = xmalloc(i+1);                  stack_msg(MSG_WARN, "%s", msg);
758                          regerror(err, refrom, msg, i+1);                  xfree(msg);
                         fprintf(stderr, "%s\n", msg);  
                         xfree(msg);  
                 }  
759                  xfree(refrom);                  xfree(refrom);
760                  xfree(reto);                  xfree(reto);
761                  return;                  return;
# Line 741  Line 781 
781                          if(to)                          if(to)
782                          {                          {
783                                  err = regcomp(reto, to, rcflags);                                  err = regcomp(reto, to, rcflags);
784                                  if(err && !quiet)                                  if(err)
785                                  {                                  {
786                                          char *msg;                                          char *msg;
787                                          i = regerror(err, reto, NULL, 0);                                          i = regerror(err, reto, NULL, 0);
788                                          msg = xmalloc(i+1);                                          msg = xmalloc(i+1);
789                                          regerror(err, reto, msg, i+1);                                          regerror(err, reto, msg, i+1);
790                                          fprintf(stderr, "%s\n", msg);                                          stack_msg(MSG_WARN, "%s", msg);
791                                            xfree(msg);
792                                  }                                  }
793                                  else if(!err)                                  else if(!err)
794                                  {                                  {
# Line 797  Line 838 
838                  err = regcomp(regextag, conf.tag_ignore, REG_EXTENDED | REG_NOSUB | (conf.tag_nocase ? REG_ICASE : 0));                  err = regcomp(regextag, conf.tag_ignore, REG_EXTENDED | REG_NOSUB | (conf.tag_nocase ? REG_ICASE : 0));
839                  if(err)                  if(err)
840                  {                  {
841                          if(!quiet)                          char *msg;
842                          {                          i = regerror(err, regextag, NULL, 0);
843                                  char *msg;                          msg = xmalloc(i+1);
844                                  i = regerror(err, regextag, NULL, 0);                          regerror(err, regextag, msg, i+1);
845                                  msg = xmalloc(i+1);                          stack_msg(MSG_WARN, "%s", msg);
846                                  regerror(err, regextag, msg, i+1);                          xfree(msg);
                                 fprintf(stderr, "%s\n", msg);  
                                 xfree(msg);  
                         }  
847                          xfree(regextag);                          xfree(regextag);
848                          regextag = NULL;                          regextag = NULL;
849                  }                  }
# Line 839  Line 877 
877          }          }
878    
879          /* We should have at least two tags (HEAD and MAIN) */          /* We should have at least two tags (HEAD and MAIN) */
880          assert(rcs->tags != 0);          assert(rcs->tags != NULL);
881    
882          for(i = 0; i < rcs->tags->ntags; i++)          for(i = 0; i < rcs->tags->ntags; i++)
883          {          {
# Line 864  Line 902 
902                                  xfree(rev.rev);                                  xfree(rev.rev);
903                                  if(!r)                                  if(!r)
904                                  {                                  {
905                                          if(!quiet)                                          stack_msg(MSG_WARN, "No branch found for tag '%s:%s'", t->tag, t->rev->branch);
                                                 fprintf(stderr, "No branch found for tag '%s:%s'\n", t->tag, t->rev->branch);  
906                                  }                                  }
907                                  else                                  else
908                                  {                                  {
# Line 895  Line 932 
932                          revision_t **r = bsearch(t->rev, rcs->srev, rcs->nsrev, sizeof(rcs->srev[0]), search_revision);                          revision_t **r = bsearch(t->rev, rcs->srev, rcs->nsrev, sizeof(rcs->srev[0]), search_revision);
933                          if(!r)                          if(!r)
934                          {                          {
935                                  if(!quiet)                                  stack_msg(MSG_WARN, "No revision found for tag '%s:%s'\n", t->tag, t->rev->rev);
                                         fprintf(stderr, "No revision found for tag '%s:%s'\n", t->tag, t->rev->rev);  
936                          }                          }
937                          else                          else
938                          {                          {
# Line 1076  Line 1112 
1112          xfree(str);          xfree(str);
1113  }  }
1114    
1115  char *expand_string(const char *s, rcsfile_t *rcs, revision_t *r, rev_t *rev, rev_t *prev, tag_t *tag)  static char *expand_string(const char *s, rcsfile_t *rcs, revision_t *r, rev_t *rev, rev_t *prev, tag_t *tag)
1116  {  {
1117          char nb[32];          char nb[32];
1118          char nr[32];          char nr[32];
# Line 1218  Line 1254 
1254                                  if(!*s)                                  if(!*s)
1255                                  {                                  {
1256                                          s--;    /* To end outer loop */                                          s--;    /* To end outer loop */
1257                                          if(!quiet)                                          stack_msg(MSG_WARN, "string expand: Missing %%) in expansion");
                                                 fprintf(stderr, "string expand: Missing %%) in expansion\n");  
1258                                  }                                  }
1259                                  break;                                  break;
1260                          case ')':                          case ')':
# Line 1307  Line 1342 
1342  static void draw_rbox(gdImagePtr im, int x1, int y1, int x2, int y2, int r, color_t *color, color_t *bgcolor)  static void draw_rbox(gdImagePtr im, int x1, int y1, int x2, int y2, int r, color_t *color, color_t *bgcolor)
1343  {  {
1344          int r2 = 2*r;          int r2 = 2*r;
1345            if(!r)
1346                    gdImageFilledRectangle(im, x1, y1, x2, y2, bgcolor->id);
1347    #ifdef HAVE_GDIMAGEFILLEDARC
1348            else
1349            {
1350                    gdImageFilledArc(im, x1+r, y1+r, r2, r2, 180, 270, bgcolor->id, gdArc);
1351                    gdImageFilledArc(im, x2-r, y1+r, r2, r2, 270, 360, bgcolor->id, gdArc);
1352                    gdImageFilledArc(im, x1+r, y2-r, r2, r2,  90, 180, bgcolor->id, gdArc);
1353                    gdImageFilledArc(im, x2-r, y2-r, r2, r2,   0,  90, bgcolor->id, gdArc);
1354                    gdImageFilledRectangle(im, x1+r, y1, x2-r, y1+r, bgcolor->id);
1355                    gdImageFilledRectangle(im, x1, y1+r, x2, y2-r, bgcolor->id);
1356                    gdImageFilledRectangle(im, x1+r, y2-r, x2-r, y2, bgcolor->id);
1357            }
1358    #endif
1359          gdImageLine(im, x1+r, y1, x2-r, y1, color->id);          gdImageLine(im, x1+r, y1, x2-r, y1, color->id);
1360          gdImageLine(im, x1+r, y2, x2-r, y2, color->id);          gdImageLine(im, x1+r, y2, x2-r, y2, color->id);
1361          gdImageLine(im, x1, y1+r, x1, y2-r, color->id);          gdImageLine(im, x1, y1+r, x1, y2-r, color->id);
# Line 1329  Line 1378 
1378                          gdImageArc(im, x2-r, y2-r+1, r2, r2,   0,  90, black_color.id);                          gdImageArc(im, x2-r, y2-r+1, r2, r2,   0,  90, black_color.id);
1379                  }                  }
1380                  gdImageArc(im, x2-r, y2-r, r2, r2,   0,  90, color->id);                  gdImageArc(im, x2-r, y2-r, r2, r2,   0,  90, color->id);
1381          }  #if !defined(NOGDFILL) && !defined(HAVE_GDIMAGEFILLEDARC)
1382  #ifndef NOGDFILL                  /* BUG: We clip manually because libgd segfaults on out of bound values */
1383          gdImageFillToBorder(im, (x1+x2)/2, (y1+y2)/2, color->id, bgcolor->id);                  if((x1+x2)/2 >= 0 && (x1+x2)/2 < gdImageSX(im) && (y1+y2)/2 >= 0 && (y1+y2)/2 < gdImageSY(im))
1384                            gdImageFillToBorder(im, (x1+x2)/2, (y1+y2)/2, color->id, bgcolor->id);
1385  #endif  #endif
1386            }
1387  }  }
1388    
1389  static void draw_string(gdImagePtr im, char *s, font_t *f, int x, int y, int align, color_t *c)  static void draw_string(gdImagePtr im, char *s, font_t *f, int x, int y, int align, color_t *c)
# Line 1490  Line 1541 
1541          line[1] = gdTransparent;          line[1] = gdTransparent;
1542          line[3] = conf.rev_color.id;          line[3] = conf.rev_color.id;
1543    
1544            /* Trivial clip the branch */
1545            if(conf.left_right)
1546            {
1547                    if(b->cx > gdImageSX(im) || b->cx+b->tw < 0 || b->y-b->th/2 > gdImageSY(im) || b->y+b->th/2 < 0)
1548                            return;
1549            }
1550            else
1551            {
1552                    if(b->cx-b->tw/2 > gdImageSX(im) || b->cx+b->tw/2 < 0 || b->y > gdImageSY(im) || b->y+b->th < 0)
1553                            return;
1554            }
1555    
1556          draw_branch_box(im, b, 0, conf.left_right ? b->y - b->h/2 : b->y);          draw_branch_box(im, b, 0, conf.left_right ? b->y - b->h/2 : b->y);
1557    
1558          if(conf.left_right)          if(conf.left_right)
# Line 1719  Line 1782 
1782                  {                  {
1783                          int o = conf.left_right ? 1 : 0;                          int o = conf.left_right ? 1 : 0;
1784                          gdImageArc(im, x2, y2+o, 8, 8, 0, 360, conf.merge_color.id);                          gdImageArc(im, x2, y2+o, 8, 8, 0, 360, conf.merge_color.id);
1785                          gdImageFillToBorder(im, x2+1, y2+o+1, conf.merge_color.id, conf.merge_color.id);                          /* BUG: We clip manually because libgd segfaults on out of bound values */
1786                            if(x2+1 >= 0 && x2+1 < gdImageSX(im) && y2+o+1 >= 0 && y2+o+1 < gdImageSY(im))
1787                                    gdImageFillToBorder(im, x2+1, y2+o+1, conf.merge_color.id, conf.merge_color.id);
1788                  }                  }
1789                  else if(dot && conf.merge_arrows)                  else if(dot && conf.merge_arrows)
1790                  {                  {
# Line 1859  Line 1924 
1924          }          }
1925  }  }
1926    
1927    static void draw_messages(gdImagePtr im, int offset)
1928    {
1929            int i;
1930    
1931            for(i = 0; i < nmsg_stack; i++)
1932            {
1933                    draw_stringnl(im, msg_stack[i].msg, &conf.msg_font, conf.margin_left, offset, ALIGN_HL|ALIGN_VT, &conf.msg_color);
1934                    offset += msg_stack[i].h;
1935            }
1936    }
1937    
1938  static void alloc_color(gdImagePtr im, color_t *c)  static void alloc_color(gdImagePtr im, color_t *c)
1939  {  {
1940          c->id = gdImageColorAllocate(im, c->r, c->g, c->b);          c->id = gdImageColorAllocate(im, c->r, c->g, c->b);
1941  }  }
1942    
1943  gdImagePtr make_image(rcsfile_t *rcs)  static gdImagePtr make_image(rcsfile_t *rcs)
1944  {  {
1945          gdImagePtr im;          gdImagePtr im;
1946          int i;          int i;
1947          char *cptr;          char *cptr;
1948            int w, h;
1949            int subx = 0, suby = 0;
1950            int subw, subh;
1951            int msgh = 0;
1952    
1953            if(subtree_branch)
1954            {
1955                    subw = 0;
1956                    subh = 0;
1957                    if(subtree_rev)
1958                    {
1959                            for(i = 0; i < subtree_rev->nbranches; i++)
1960                                    calc_subtree_size(subtree_rev->branches[i], &subx, &suby, &subw, &subh);
1961                    }
1962                    else
1963                            calc_subtree_size(subtree_branch, &subx, &suby, &subw, &subh);
1964            }
1965            else
1966            {
1967                    subw = rcs->tw;
1968                    subh = rcs->th;
1969            }
1970    
1971          cptr = expand_string(conf.title, rcs, NULL, NULL, NULL, NULL);          cptr = expand_string(conf.title, rcs, NULL, NULL, NULL, NULL);
1972            w = subw + conf.margin_left + conf.margin_right;
1973            h = subh + conf.margin_top + conf.margin_bottom;
1974          i = get_swidth(cptr, &conf.title_font);          i = get_swidth(cptr, &conf.title_font);
1975          if(rcs->tw+conf.margin_left+conf.margin_right > i)          if(i > w)
1976                  i = rcs->tw+conf.margin_left+conf.margin_right;                  w = i;
1977          im = gdImageCreate(i, rcs->th+conf.margin_top+conf.margin_bottom);  
1978            if(!quiet && nmsg_stack)
1979            {
1980                    int msgw = 0;
1981                    for(i = 0; i < nmsg_stack; i++)
1982                    {
1983                            int ww = msg_stack[i].w = get_swidth(msg_stack[i].msg, &conf.msg_font);
1984                            int hh = msg_stack[i].h = get_sheight(msg_stack[i].msg, &conf.msg_font);
1985                            msgh += hh;
1986                            h += hh;
1987                            if(ww > msgw)
1988                                    msgw = ww;
1989                    }
1990                    if(msgw > w)
1991                            w = msgw;
1992            }
1993    
1994            im = gdImageCreate(w, h);
1995          alloc_color(im, &conf.color_bg);          alloc_color(im, &conf.color_bg);
1996          alloc_color(im, &conf.tag_color);          alloc_color(im, &conf.tag_color);
1997          alloc_color(im, &conf.rev_color);          alloc_color(im, &conf.rev_color);
# Line 1885  Line 2002 
2002          alloc_color(im, &conf.branch_bgcolor);          alloc_color(im, &conf.branch_bgcolor);
2003          alloc_color(im, &conf.title_color);          alloc_color(im, &conf.title_color);
2004          alloc_color(im, &conf.merge_color);          alloc_color(im, &conf.merge_color);
2005            alloc_color(im, &conf.msg_color);
2006          alloc_color(im, &black_color);          alloc_color(im, &black_color);
2007          alloc_color(im, &white_color);          alloc_color(im, &white_color);
2008    
# Line 1896  Line 2014 
2014    
2015          for(i = 0; i < rcs->nbranches; i++)          for(i = 0; i < rcs->nbranches; i++)
2016          {          {
2017                  if(!rcs->branches[i]->folded)                  if(!rcs->branches[i]->folded && !(subtree_branch && !rcs->branches[i]->subtree_draw))
2018                          draw_branch(im, rcs->branches[i]);                          draw_branch(im, rcs->branches[i]);
2019          }          }
2020    
# Line 1907  Line 2025 
2025                  if(rcs->branches[i]->branchpoint)                  if(rcs->branches[i]->branchpoint)
2026                          draw_connector(im, rcs->branches[i]);                          draw_connector(im, rcs->branches[i]);
2027          }          }
2028    
2029            /* Clear the margins if we have a partial tree */
2030            if(subtree_branch)
2031            {
2032                    gdImageFilledRectangle(im, 0, 0, w-1, conf.margin_top-1, conf.color_bg.id);
2033                    gdImageFilledRectangle(im, 0, 0, conf.margin_left-1, h-1, conf.color_bg.id);
2034                    gdImageFilledRectangle(im, 0, h-conf.margin_bottom, w-1, h-1, conf.color_bg.id);
2035                    gdImageFilledRectangle(im, w-conf.margin_right, 0, w-1, h-1, conf.color_bg.id);
2036            }
2037    
2038          draw_stringnl(im, cptr, &conf.title_font, conf.title_x, conf.title_y, conf.title_align, &conf.title_color);          draw_stringnl(im, cptr, &conf.title_font, conf.title_x, conf.title_y, conf.title_align, &conf.title_color);
2039          xfree(cptr);          xfree(cptr);
2040    
2041          if(conf.merge_front)          if(conf.merge_front)
2042                  draw_merges(im, rcs, 0);                  draw_merges(im, rcs, 0);
2043    
2044            if(!quiet)
2045                    draw_messages(im, h - conf.margin_bottom/2 - msgh);
2046    
2047          return im;          return im;
2048  }  }
2049    
# Line 2038  Line 2169 
2169          *h = y2 - y1;          *h = y2 - y1;
2170  }  }
2171    
2172    static void calc_subtree_size(branch_t *b, int *x, int *y, int *w, int *h)
2173    {
2174            int i, j;
2175    
2176            rect_union(x, y, w, h, b);
2177    
2178            for(i = 0; i < b->nrevs; i++)
2179            {
2180                    for(j = 0; j < b->revs[i]->nbranches; j++)
2181                            calc_subtree_size(b->revs[i]->branches[j], x, y, w, h);
2182            }
2183    }
2184    
2185  static int branch_intersects(int top, int bottom, int left, branch_t *b)  static int branch_intersects(int top, int bottom, int left, branch_t *b)
2186  {  {
2187          int br = b->cx + b->tw/2;          int br = b->cx + b->tw/2;
# Line 2131  Line 2275 
2275                  fprintf(stderr, "kern_tree: moved=%d\n", moved);                  fprintf(stderr, "kern_tree: moved=%d\n", moved);
2276  #endif  #endif
2277          }          }
2278          if(!quiet && !safeguard)          if(!safeguard)
2279                  fprintf(stderr, "kern_tree: safeguard terminated possible infinite loop; please report.\n");                  stack_msg(MSG_WARN, "kern_tree: safeguard terminated possible infinite loop; please report.");
2280          return totalmoved;          return totalmoved;
2281  }  }
2282    
# Line 2145  Line 2289 
2289                  if(r == b->revs[i])                  if(r == b->revs[i])
2290                          return i;                          return i;
2291          }          }
2292          fprintf(stderr, "index_of_revision: Cannot find revision in branch\n");          stack_msg(MSG_ERR, "index_of_revision: Cannot find revision in branch\n");
2293          return 0;          return 0;
2294  }  }
2295    
# Line 2306  Line 2450 
2450    
2451          if(!tagbr->branchpoint || !colbr->branchpoint)          if(!tagbr->branchpoint || !colbr->branchpoint)
2452          {          {
2453                  if(!quiet)                  stack_msg(MSG_WARN, "space_available: Trying to stretch the top?");
                         fprintf(stderr, "space_available: Trying to stretch the top?\n");  
2454                  return 0;                  return 0;
2455          }          }
2456    
# Line 2352  Line 2495 
2495                          branchpoint = ancestor->branchpoint;                          branchpoint = ancestor->branchpoint;
2496                          if(!branchpoint)                          if(!branchpoint)
2497                          {                          {
2498                                  if(!quiet)                                  stack_msg(MSG_WARN, "space_available: No common ancestor?");
                                         fprintf(stderr, "space_available: No common ancestor?\n");  
2499                                  return 0;                                  return 0;
2500                          }                          }
2501                          ancestor = branchpoint->branch;                          ancestor = branchpoint->branch;
# Line 2454  Line 2596 
2596          return col;          return col;
2597  }  }
2598    
2599  void auto_stretch(rcsfile_t *rcs)  static void auto_stretch(rcsfile_t *rcs)
2600  {  {
2601          int i;          int i;
2602          int safeguard;          int safeguard;
# Line 2507  Line 2649 
2649                          }                          }
2650                  }                  }
2651          }          }
2652          if(!quiet && !safeguard)          if(!safeguard)
2653                  fprintf(stderr, "auto_stretch: safeguard terminated possible infinite loop; please report.\n");                  stack_msg(MSG_ERR, "auto_stretch: safeguard terminated possible infinite loop; please report.");
2654  }  }
2655    
2656  static void fold_branch(rcsfile_t *rcs, revision_t *r)  static void fold_branch(rcsfile_t *rcs, revision_t *r)
# Line 2516  Line 2658 
2658          int i, j;          int i, j;
2659          branch_t *btag = NULL;          branch_t *btag = NULL;
2660    
         if(r->nbranches < 2)  
                 return;         /* Should not happen... */  
   
2661          for(i = 0; i < r->nbranches; i++)          for(i = 0; i < r->nbranches; i++)
2662          {          {
2663                  branch_t *b = r->branches[i];                  branch_t *b = r->branches[i];
# Line 2531  Line 2670 
2670                          {                          {
2671                                  /* We have consecutive empty branches, fold */                                  /* We have consecutive empty branches, fold */
2672                                  b->folded = 1;                                  b->folded = 1;
2673                                    b->folded_to = btag;
2674                                  for(j = 0; j < rcs->nbranches; j++)                                  for(j = 0; j < rcs->nbranches; j++)
2675                                  {                                  {
2676                                          if(b == rcs->branches[j])                                          if(b == rcs->branches[j])
# Line 2565  Line 2705 
2705          }          }
2706  }  }
2707    
2708  void make_layout(rcsfile_t *rcs)  static void mark_subtree(branch_t *b)
2709    {
2710            int i, j;
2711            b->subtree_draw = 1;
2712            for(i = 0; i < b->nrevs; i++)
2713            {
2714                    for(j = 0; j < b->revs[i]->nbranches; j++)
2715                            mark_subtree(b->revs[i]->branches[j]);
2716            }
2717    }
2718    
2719    static void make_layout(rcsfile_t *rcs)
2720  {  {
2721          int i, j;          int i, j;
2722          int x, y;          int x, y;
# Line 2592  Line 2743 
2743                  }                  }
2744          }          }
2745    
2746          /* Fold all empty branched in one box on the same branchpoint */          /* Find the sub-tree(s) we want to see */
2747            if(conf.branch_subtree && conf.branch_subtree[0])
2748            {
2749                    branch_t **b;
2750                    revision_t **r;
2751                    rev_t rev;
2752                    int k;
2753                    char *tag = conf.branch_subtree;
2754    
2755                    /* First translate any symbolic tag to a real branch/revision number */
2756                    if(rcs->tags)
2757                    {
2758                            for(k = 0; k < rcs->tags->ntags; k++)
2759                            {
2760                                    if(!strcmp(conf.branch_subtree, rcs->tags->tags[k]->tag))
2761                                    {
2762                                            if(rcs->tags->tags[k]->rev->isbranch)
2763                                                    tag = rcs->tags->tags[k]->rev->branch;
2764                                            else
2765                                                    tag = rcs->tags->tags[k]->rev->rev;
2766                                            break;
2767                                    }
2768                            }
2769                    }
2770    
2771                    /* Find the corresponding branch */
2772                    rev.branch = tag;
2773                    rev.rev = NULL;
2774                    rev.isbranch = 1;
2775                    b = bsearch(&rev, rcs->branches, rcs->nbranches, sizeof(rcs->branches[0]), search_branch);
2776                    if(b)
2777                    {
2778                            if((*b)->branchpoint)
2779                            {
2780                                    subtree_branch = *b;
2781                                    for(k = 0; k < (*b)->branchpoint->nbranches; k++)
2782                                            mark_subtree((*b)->branchpoint->branches[k]);
2783                            }
2784                            /*
2785                             * else -> we want everything.
2786                             * This happens for the top level branch because it has no
2787                             * branchpoint. We do not set the subtree_branch, which then
2788                             * results in drawing the whole tree as if we did not select a
2789                             * particular branch.
2790                             */
2791                    }
2792                    else
2793                    {
2794                            /* Maybe it is a revision we want all subtrees from */
2795                            rev.rev = tag;
2796                            rev.branch = NULL;
2797                            rev.isbranch = 0;
2798                            r = bsearch(&rev, rcs->srev, rcs->nsrev, sizeof(rcs->srev[0]), search_revision);
2799                            if(r)
2800                            {
2801                                    if((*r)->nbranches)
2802                                    {
2803                                            subtree_branch = (*r)->branches[0];
2804                                            subtree_rev = *r;
2805                                            for(k = 0; k < (*r)->nbranches; k++)
2806                                                    mark_subtree((*r)->branches[k]);
2807                                    }
2808                                    /*
2809                                     * else -> we select everything.
2810                                     * This happens for the any revision that has no branches.
2811                                     * We do not set the subtree_branch, which then results in
2812                                     * drawing the whole tree as if we did not select a
2813                                     * particular revision's branches.
2814                                     */
2815                            }
2816                    }
2817            }
2818    
2819            /* Fold all empty branches in one box on the same branchpoint */
2820          if(conf.branch_fold)          if(conf.branch_fold)
2821          {          {
2822                  for(i = 0; i < rcs->branches[0]->nrevs; i++)                  for(i = 0; i < rcs->branches[0]->nrevs; i++)
2823                  {                  {
2824                          if(rcs->branches[0]->revs[i]->nbranches > 1)                          if(rcs->branches[0]->revs[i]->nbranches > 0)
2825                                  fold_branch(rcs, rcs->branches[0]->revs[i]);                                  fold_branch(rcs, rcs->branches[0]->revs[i]);
2826                  }                  }
2827          }          }
# Line 2788  Line 3012 
3012          if(conf.auto_stretch && !conf.left_right)          if(conf.auto_stretch && !conf.left_right)
3013                  auto_stretch(rcs);                  auto_stretch(rcs);
3014    
         /* Move everything w.r.t. the top-left margin */  
         for(i = 0; i < rcs->nbranches; i++)  
                 move_branch(rcs->branches[i], conf.margin_left, conf.margin_top);  
   
3015          /* Calculate overall image size */          /* Calculate overall image size */
3016          if(conf.left_right)          if(conf.left_right)
3017          {          {
# Line 2822  Line 3042 
3042                                  for(j = 0; j < b->nrevs; j++)                                  for(j = 0; j < b->nrevs; j++)
3043                                  {                                  {
3044                                          revision_t *r = b->revs[j];                                          revision_t *r = b->revs[j];
3045                                          r->cx = x - r->cx - r->w + conf.margin_left;                                          r->cx = x - r->cx - r->w;
3046                                  }                                  }
3047                                  b->cx = x - b->cx - b->w + conf.margin_left;                                  b->cx = x - b->cx - b->w;
3048                          }                          }
3049                  }                  }
3050                  else                  else
# Line 2836  Line 3056 
3056                                  for(j = 0; j < b->nrevs; j++)                                  for(j = 0; j < b->nrevs; j++)
3057                                  {                                  {
3058                                          revision_t *r = b->revs[j];                                          revision_t *r = b->revs[j];
3059                                          r->y = y - r->y - r->h + conf.margin_top;                                          r->y = y - r->y - r->h;
3060                                  }                                  }
3061                                  b->y = y - b->y - b->h + conf.margin_top;                                  b->y = y - b->y - b->h;
3062                          }                          }
3063                  }                  }
3064          }          }
3065    
3066            /* Relocate the lot if we only draw a sub-tree */
3067            if(subtree_branch)
3068            {
3069                    int xx, yy;
3070    
3071                    if(subtree_branch->folded)      /* Fix the reference if the branch got folded */
3072                            subtree_branch = subtree_branch->folded_to;
3073    
3074                    xx = conf.left_right ? subtree_branch->cx : subtree_branch->cx - subtree_branch->tw/2;
3075                    yy = conf.left_right ? subtree_branch->y - subtree_branch->th/2 : subtree_branch->y;
3076                    if(subtree_branch != rcs->branches[0])
3077                    {
3078                            if(conf.left_right)
3079                                    xx -= conf.branch_connect;
3080                            else
3081                                    yy -= conf.branch_connect;
3082                    }
3083                    for(i = 0; i < rcs->nbranches; i++)
3084                            move_branch(rcs->branches[i], -xx, -yy);
3085            }
3086    
3087            /* Move everything w.r.t. the top-left margin */
3088            for(i = 0; i < rcs->nbranches; i++)
3089                    move_branch(rcs->branches[i], conf.margin_left, conf.margin_top);
3090  }  }
3091    
3092  /*  /*
# Line 2849  Line 3094 
3094   * Imagemap functions   * Imagemap functions
3095   **************************************************************************   **************************************************************************
3096   */   */
3097  void make_imagemap(rcsfile_t *rcs, FILE *fp, gdImagePtr im)  static void map_merge_box(rcsfile_t *rcs, FILE *fp, revision_t *fr, revision_t *tr, gdImagePtr im, int x1, int y1, int x2, int y2)
3098    {
3099            char *href = expand_string(conf.map_merge_href, rcs, tr, tr->rev, fr->rev, NULL);
3100            char *alt = expand_string(conf.map_merge_alt, rcs, tr, tr->rev, fr->rev, NULL);
3101            const char *htp = conf.html_level == HTMLLEVEL_X ? " /" : "";
3102    
3103            if(x1 > 0 && x2 > 0 && y1 > 0 && y2 > 0)
3104                    fprintf(fp, "\t<area shape=\"rect\" %s coords=\"%d,%d,%d,%d\" %s%s>\n",
3105                                            href, x1, y1, x2, y2, alt, htp);
3106            xfree(alt);
3107            xfree(href);
3108    
3109            if(im)
3110            {
3111                    gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, conf.title_color.id);
3112                    gdImageFilledRectangle(im, x2-2, y2-2, x2+2, y2+2, conf.tag_color.id);
3113                    gdImageLine(im, x1, y1, x2, y2, conf.title_color.id);
3114            }
3115    }
3116    
3117    static void map_merges(rcsfile_t *rcs, FILE *fp, gdImagePtr im)
3118    {
3119            int i;
3120            int tagh2 = get_sheight("Hg", &conf.tag_font) / 2;
3121            int bm = conf.branch_margin / 2;
3122    
3123            for(i = 0; i < rcs->nmerges; i++)
3124            {
3125                    revision_t *fr = rcs->merges[i].from->logrev;
3126                    revision_t *tr = rcs->merges[i].to->logrev;
3127                    int x1, x2, y1, y2;
3128                    if(!fr || !tr || fr == tr)
3129                            continue;       /* This can happen with detached tags and self-references */
3130                    if(conf.left_right)
3131                    {
3132                            if(fr->branch == tr->branch)
3133                            {
3134                                    y1 = fr->y - fr->h/2;
3135                                    y2 = tr->y - tr->h/2;
3136                            }
3137                            else
3138                            {
3139                                    if(fr->y < tr->y)
3140                                    {
3141                                            y1 = fr->y + fr->h/2;
3142                                            y2 = tr->y - tr->h/2;
3143                                    }
3144                                    else
3145                                    {
3146                                            y1 = fr->y - fr->h/2;
3147                                            y2 = tr->y + tr->h/2;
3148                                    }
3149                            }
3150                            x1 = fr->cx + fr->w/2;
3151                            x2 = tr->cx + tr->w/2;
3152                    }
3153                    else
3154                    {
3155                            if(fr->branch == tr->branch)
3156                            {
3157                                    x1 = fr->cx - fr->w/2;
3158                                    x2 = tr->cx - tr->w/2;
3159                            }
3160                            else
3161                            {
3162                                    if(fr->cx < tr->cx)
3163                                    {
3164                                            x1 = fr->cx + fr->w/2;
3165                                            x2 = tr->cx - tr->w/2;
3166                                    }
3167                                    else
3168                                    {
3169                                            x1 = fr->cx - fr->w/2;
3170                                            x2 = tr->cx + tr->w/2;
3171                                    }
3172                            }
3173                            y1 = fr->y + rcs->merges[i].from->yofs;
3174                            y2 = tr->y + rcs->merges[i].to->yofs;
3175                    }
3176    
3177                    if(conf.left_right)
3178                    {
3179                            if(fr->branch == tr->branch)
3180                            {
3181                                    map_merge_box(rcs, fp, fr, tr, im, x1-bm, y1-bm, x1+bm, y1);
3182                                    map_merge_box(rcs, fp, fr, tr, im, x2-bm, y2-bm, x2+bm, y2);
3183                            }
3184                            else
3185                            {
3186                                    if(y1 > y2)
3187                                    {
3188                                            map_merge_box(rcs, fp, fr, tr, im, x1-bm, y1-bm, x1+bm, y1);
3189                                            map_merge_box(rcs, fp, fr, tr, im, x2-bm, y2, x2+bm, y2+bm);
3190                                    }
3191                                    else
3192                                    {
3193                                            map_merge_box(rcs, fp, fr, tr, im, x1-bm, y1, x1+bm, y1+bm);
3194                                            map_merge_box(rcs, fp, fr, tr, im, x2-bm, y2-bm, x2+bm, y2);
3195                                    }
3196                            }
3197                    }
3198                    else
3199                    {
3200                            if(fr->branch == tr->branch)
3201                            {
3202                                    map_merge_box(rcs, fp, fr, tr, im, x1-bm, y1-tagh2, x1, y1+tagh2);
3203                                    map_merge_box(rcs, fp, fr, tr, im, x2-bm, y2-tagh2, x2, y2+tagh2);
3204                            }
3205                            else
3206                            {
3207                                    if(x1 > x2)
3208                                    {
3209                                            map_merge_box(rcs, fp, fr, tr, im, x1-bm, y1-tagh2, x1, y1+tagh2);
3210                                            map_merge_box(rcs, fp, fr, tr, im, x2, y2-tagh2, x2+bm, y2+tagh2);
3211                                    }
3212                                    else
3213                                    {
3214                                            map_merge_box(rcs, fp, fr, tr, im, x1, y1-tagh2, x1+bm, y1+tagh2);
3215                                            map_merge_box(rcs, fp, fr, tr, im, x2-bm, y2-tagh2, x2, y2+tagh2);
3216                                    }
3217                            }
3218                    }
3219            }
3220    }
3221    
3222    static void make_imagemap(rcsfile_t *rcs, FILE *fp, gdImagePtr im)
3223  {  {
3224          int i, j;          int i, j;
3225          const char *htp = conf.html_level == HTMLLEVEL_X ? " /" : "";          const char *htp = conf.html_level == HTMLLEVEL_X ? " /" : "";
# Line 2870  Line 3240 
3240          {          {
3241                  branch_t *b = rcs->branches[i];                  branch_t *b = rcs->branches[i];
3242                  tag_t *tag = b->ntags ? b->tags[0] : NULL;                  tag_t *tag = b->ntags ? b->tags[0] : NULL;
3243                  char *bhref = expand_string(conf.map_branch_href, rcs, NULL, b->branch, NULL, tag);                  char *bhref;
3244                  char *balt = expand_string(conf.map_branch_alt, rcs, NULL, b->branch, NULL, tag);                  char *balt;
3245                  int x1;                  int x1;
3246                  int x2;                  int x2;
3247                  int y1;                  int y1;
3248                  int y2;                  int y2;
3249    
3250                    if(subtree_branch && !b->subtree_draw)
3251                            continue;
3252    
3253                    bhref = expand_string(conf.map_branch_href, rcs, NULL, b->branch, NULL, tag);
3254                    balt = expand_string(conf.map_branch_alt, rcs, NULL, b->branch, NULL, tag);
3255    
3256                  if(!b->nfolds)                  if(!b->nfolds)
3257                  {                  {
3258                          if(conf.left_right)                          if(conf.left_right)
# Line 3080  Line 3456 
3456                  xfree(bhref);                  xfree(bhref);
3457                  xfree(balt);                  xfree(balt);
3458          }          }
3459    
3460            map_merges(rcs, fp, im);
3461    
3462          fprintf(fp, "</map>\n");          fprintf(fp, "</map>\n");
3463  }  }
3464    
# Line 3111  Line 3490 
3490          "  -[0-9] <txt> Use <txt> for expansion\n"          "  -[0-9] <txt> Use <txt> for expansion\n"
3491          ;          ;
3492    
3493  #define VERSION_STR     "1.4.2"  #define VERSION_STR     "1.5.0"
3494  #define NOTICE_STR      "Copyright (c) 2001,2002,2003,2004 B.Stultiens"  #define NOTICE_STR      "Copyright (c) 2001,2002,2003,2004 B.Stultiens"
3495    
3496  static void append_slash(char **path)  static void append_slash(char **path)
# Line 3253  Line 3632 
3632          conf.branch_tag_font.gdfont     = gdFontTiny;          conf.branch_tag_font.gdfont     = gdFontTiny;
3633          conf.title_font.gdfont          = gdFontTiny;          conf.title_font.gdfont          = gdFontTiny;
3634          conf.rev_text_font.gdfont       = gdFontTiny;          conf.rev_text_font.gdfont       = gdFontTiny;
3635            conf.msg_font.gdfont            = gdFontTiny;
3636    
3637          conf.anti_alias         = 1;          conf.anti_alias         = 1;
3638          conf.thick_lines        = 1;          conf.thick_lines        = 1;
# Line 3269  Line 3649 
3649          conf.map_rev_alt        = xstrdup("alt=\"%R\"");          conf.map_rev_alt        = xstrdup("alt=\"%R\"");
3650          conf.map_diff_href      = xstrdup("href=\"unset: conf.map_diff_href\"");          conf.map_diff_href      = xstrdup("href=\"unset: conf.map_diff_href\"");
3651          conf.map_diff_alt       = xstrdup("alt=\"%P &lt;-&gt; %R\"");          conf.map_diff_alt       = xstrdup("alt=\"%P &lt;-&gt; %R\"");
3652            conf.map_merge_href     = xstrdup("href=\"unset: conf.map_merge_href\"");
3653            conf.map_merge_alt      = xstrdup("alt=\"%P &lt;-&gt; %R\"");
3654          conf.rev_text           = xstrdup("%d");          conf.rev_text           = xstrdup("%d");
3655            conf.branch_subtree     = xstrdup("");
3656            conf.tag_ignore         = xstrdup("");
3657          conf.merge_from         = xstrdup("");          conf.merge_from         = xstrdup("");
3658          conf.merge_to           = xstrdup("");          conf.merge_to           = xstrdup("");
3659          conf.merge_arrows       = 1;          conf.merge_arrows       = 1;
# Line 3286  Line 3670 
3670          conf.tag_color          = black_color;          conf.tag_color          = black_color;
3671          conf.title_color        = black_color;          conf.title_color        = black_color;
3672          conf.rev_text_color     = black_color;          conf.rev_text_color     = black_color;
3673            conf.msg_color          = black_color;
3674    
3675          conf.image_quality      = 100;          conf.image_quality      = 100;
3676          conf.rev_maxline        = -1;   /* Checked later to set to default */          conf.rev_maxline        = -1;   /* Checked later to set to default */
# Line 3307  Line 3692 
3692    
3693          if(conf.rev_minline >= conf.rev_maxline)          if(conf.rev_minline >= conf.rev_maxline)
3694          {          {
3695                  if(conf.auto_stretch && !quiet)                  if(conf.auto_stretch)
3696                          fprintf(stderr, "Auto stretch is only possible if rev_minline < rev_maxline\n");                          stack_msg(MSG_WARN, "Auto stretch is only possible if rev_minline < rev_maxline");
3697                  conf.auto_stretch = 0;                  conf.auto_stretch = 0;
3698          }          }
3699    

Legend:
Removed from v.1.43  
changed lines
  Added in v.1.44

  ViewVC Help
Powered by ViewVC 1.1.0 with CvsGraph 1.7.0