/[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.56, Tue Jun 21 00:02:48 2005 UTC revision 1.64, Wed May 21 01:41:18 2008 UTC
# Line 2  Line 2 
2   * CvsGraph graphical representation generator of brances and revisions   * CvsGraph graphical representation generator of brances and revisions
3   * of a file in cvs/rcs.   * of a file in cvs/rcs.
4   *   *
5   * Copyright (C) 2001,2002,2003,2004  B. Stultiens   * Copyright (C) 2001,2002,2003,2004,2005,2006  B. Stultiens
6   *   *
7   * This program is free software; you can redistribute it and/or modify   * This program is free software; you can redistribute it and/or modify
8   * it under the terms of the GNU General Public License as published by   * it under the terms of the GNU General Public License as published by
# Line 38  Line 38 
38  #include <ctype.h>  #include <ctype.h>
39  #include <time.h>  #include <time.h>
40  #include <limits.h>  #include <limits.h>
 #include <regex.h>  
41  #include <math.h>  #include <math.h>
42    
43  #ifdef HAVE_GETOPT_H  #ifdef HAVE_GETOPT_H
# Line 98  Line 97 
97  config_t conf;  config_t conf;
98  int debuglevel;  int debuglevel;
99    
100  static color_t white_color = {255, 255, 255, 0};  static color_t white_color = {255, 255, 255, 0, NULL};
101  static color_t black_color = {0, 0, 0, 0};  static color_t black_color = {0, 0, 0, 0, NULL};
102    
103  static branch_t *subtree_branch = NULL;         /* Set to the (first) subtree branch that we want to show */  static branch_t *subtree_branch = NULL;         /* Set to the (first) subtree branch that we want to show */
104  static revision_t *subtree_rev = NULL;          /* Set to the subtree revision which branches we want to show */  static revision_t *subtree_rev = NULL;          /* Set to the subtree revision which branches we want to show */
# Line 703  Line 702 
702          return r;          return r;
703  }  }
704    
705  static char *build_regex(size_t n, regmatch_t *m, const char *ms)  static char *build_regex(size_t n, regmatch_t *m, const char *ms, int idx)
706  {  {
707          char *cptr;          char *cptr;
708          int i;          int i;
709    
710          if(!conf.merge_to || !conf.merge_to[0])          if(!conf.merge_to.strs[idx])
711                  return NULL;                  return NULL;
712    
713          zap_string();          zap_string();
714          for(cptr = conf.merge_to; *cptr; cptr++)          for(cptr = conf.merge_to.strs[idx]; *cptr; cptr++)
715          {          {
716                  if(*cptr == '%')                  if(*cptr == '%')
717                  {                  {
# Line 761  Line 760 
760                  rcs->merges[rcs->nmerges].type = TR_REVISION;                  rcs->merges[rcs->nmerges].type = TR_REVISION;
761                  rcs->merges[rcs->nmerges].from.rev = *r;                  rcs->merges[rcs->nmerges].from.rev = *r;
762                  rcs->merges[rcs->nmerges].to.rev = rcs->srev[i];                  rcs->merges[rcs->nmerges].to.rev = rcs->srev[i];
763                    rcs->merges[rcs->nmerges].clr = -1;
764                  rcs->nmerges++;                  rcs->nmerges++;
765                  (*r)->stripped = -1;                  (*r)->mergetarget = 1;
766                  rcs->srev[i]->stripped = -1;                  rcs->srev[i]->mergetarget = 1;
767          }          }
768  }  }
769    
770  static void find_merges(rcsfile_t *rcs)  static void find_merges(rcsfile_t *rcs)
771  {  {
772          int i;          int i, j;
773          int err;          int err;
774          int rcflags = REG_EXTENDED | (conf.merge_nocase ? REG_ICASE : 0);          int rcflags = REG_EXTENDED | (conf.merge_nocase ? REG_ICASE : 0);
775          regex_t *refrom = NULL;          regex_t *refrom = NULL;
776          regex_t *reto = NULL;          regex_t *reto = NULL;
777          regmatch_t *matchfrom = NULL;          regmatch_t *matchfrom = NULL;
778    
779          if(!conf.merge_from || !conf.merge_from[0] || !conf.merge_to || !conf.merge_to[0])          if(!conf.merge_from.n || !conf.merge_to.n)
                 return;  
   
         refrom = xmalloc(sizeof(*refrom));  
         reto = xmalloc(sizeof(*reto));  
   
         /* Compile the 'from' regex match for merge identification */  
         err = regcomp(refrom, conf.merge_from, rcflags);  
         if(err)  
         {  
                 char *msg;  
                 i = regerror(err, refrom, NULL, 0);  
                 msg = xmalloc(i+1);  
                 regerror(err, refrom, msg, i+1);  
                 stack_msg(MSG_WARN, "%s", msg);  
                 xfree(msg);  
                 xfree(refrom);  
                 xfree(reto);  
780                  return;                  return;
         }  
         else  
                 matchfrom = xmalloc((refrom->re_nsub+1) * sizeof(*matchfrom));  
781    
782          for(i = 0; i < rcs->tags->ntags; i++)          for(j = 0; j < conf.merge_from.n; j++)
783          {          {
784                  tag_t *t = rcs->tags->tags[i];                  if(!conf.merge_from.strs[0] || !conf.merge_to.strs[0])
   
                 /* Must be revision tags and not detached */  
                 if(t->rev->isbranch || !t->logrev)  
785                          continue;                          continue;
786    
787                  /* Try to find merge tag matches */                  refrom = xmalloc(sizeof(*refrom));
788                  if(!regexec(refrom, t->tag, refrom->re_nsub+1, matchfrom, 0))                  reto = xmalloc(sizeof(*reto));
789    
790                    /* Compile the 'from' regex match for merge identification */
791                    err = regcomp(refrom, conf.merge_from.strs[j], rcflags);
792                    if(err)
793                  {                  {
794                          int n;                          char *msg;
795                          char *to;                          i = regerror(err, refrom, NULL, 0);
796                            msg = xmalloc(i+1);
797                            regerror(err, refrom, msg, i+1);
798                            stack_msg(MSG_WARN, "%s", msg);
799                            xfree(msg);
800                            xfree(refrom);
801                            xfree(reto);
802                            return;
803                    }
804                    else
805                            matchfrom = xmalloc((refrom->re_nsub+1) * sizeof(*matchfrom));
806    
807                    for(i = 0; i < rcs->tags->ntags; i++)
808                    {
809                            tag_t *t = rcs->tags->tags[i];
810    
811                            /* Must be revision tags and not detached */
812                            if(t->rev->isbranch || !t->logrev)
813                                    continue;
814    
815                          to = build_regex(refrom->re_nsub+1, matchfrom, t->tag);                          /* Try to find merge tag matches */
816                          if(to)                          if(!regexec(refrom, t->tag, refrom->re_nsub+1, matchfrom, 0))
817                          {                          {
818                                  err = regcomp(reto, to, rcflags);                                  int n;
819                                  if(err)                                  char *to;
820                                  {  
821                                          char *msg;                                  to = build_regex(refrom->re_nsub+1, matchfrom, t->tag, j);
822                                          i = regerror(err, reto, NULL, 0);                                  if(to)
                                         msg = xmalloc(i+1);  
                                         regerror(err, reto, msg, i+1);  
                                         stack_msg(MSG_WARN, "%s", msg);  
                                         xfree(msg);  
                                 }  
                                 else if(!err)  
823                                  {                                  {
824                                          for(n = 0; n < rcs->tags->ntags; n++)                                          err = regcomp(reto, to, rcflags);
825                                            if(err)
826                                          {                                          {
827                                                  tag_t *nt = rcs->tags->tags[n];                                                  char *msg;
828                                                  /* From and To never should match the same tag or belong to a branch */                                                  i = regerror(err, reto, NULL, 0);
829                                                  if(n == i || nt->rev->isbranch || !nt->logrev)                                                  msg = xmalloc(i+1);
830                                                          continue;                                                  regerror(err, reto, msg, i+1);
831                                                    stack_msg(MSG_WARN, "%s", msg);
832                                                  if(!regexec(reto, nt->tag, 0, NULL, 0))                                                  xfree(msg);
833                                            }
834                                            else if(!err)
835                                            {
836                                                    for(n = 0; n < rcs->tags->ntags; n++)
837                                                  {                                                  {
838                                                          /* Tag matches */                                                          tag_t *nt = rcs->tags->tags[n];
839                                                          rcs->merges = xrealloc(rcs->merges,                                                          /* From and To never should match the same tag or belong to a branch */
840                                                                          sizeof(rcs->merges[0]) * (rcs->nmerges+1));                                                          if(n == i || nt->rev->isbranch || !nt->logrev)
841                                                          rcs->merges[rcs->nmerges].type = TR_TAG;                                                                  continue;
842                                                          rcs->merges[rcs->nmerges].to.tag = nt;  
843                                                          rcs->merges[rcs->nmerges].from.tag = t;                                                          if(!regexec(reto, nt->tag, 0, NULL, 0))
                                                         rcs->nmerges++;  
                                                         if(!conf.tag_ignore_merge)  
844                                                          {                                                          {
845                                                                  nt->ignore = 0;                                                                  /* Tag matches */
846                                                                  t->ignore = 0;                                                                  rcs->merges = xrealloc(rcs->merges,
847                                                                                    sizeof(rcs->merges[0]) * (rcs->nmerges+1));
848                                                                    rcs->merges[rcs->nmerges].type = TR_TAG;
849                                                                    rcs->merges[rcs->nmerges].to.tag = nt;
850                                                                    rcs->merges[rcs->nmerges].from.tag = t;
851                                                                    rcs->merges[rcs->nmerges].clr = j;
852                                                                    rcs->nmerges++;
853                                                                    if(!conf.tag_ignore_merge)
854                                                                    {
855                                                                            nt->ignore = 0;
856                                                                            t->ignore = 0;
857                                                                    }
858                                                                    /* We cannot (should not) match multiple times */
859                                                                    if(!conf.merge_findall)
860                                                                            break;
861                                                          }                                                          }
                                                         /* We cannot (should not) match multiple times */  
                                                         if(!conf.merge_findall)  
                                                                 break;  
862                                                  }                                                  }
863                                                    regfree(reto);
864                                          }                                          }
865                                          regfree(reto);                                          xfree(to);
866                                  }                                  }
                                 xfree(to);  
867                          }                          }
868                  }                  }
869                    if(matchfrom)   xfree(matchfrom);
870                    if(refrom)      { regfree(refrom); xfree(refrom); }
871                    if(reto)        xfree(reto);
872                    refrom = NULL;
873                    reto = NULL;
874                    matchfrom = NULL;
875          }          }
         if(matchfrom)   xfree(matchfrom);  
         if(refrom)      { regfree(refrom); xfree(refrom); }  
         if(reto)        xfree(reto);  
876  }  }
877    
878  static void assign_tags(rcsfile_t *rcs)  static void assign_tags(rcsfile_t *rcs)
# Line 1333  Line 1343 
1343  static color_t *clr_id = NULL;  static color_t *clr_id = NULL;
1344  static int nclr_id = 0;  static int nclr_id = 0;
1345    
1346  static color_t *clr(gdImagePtr im, const char *s, revision_t *r, branch_t *b)  static int rexpr_eval(const char *key, const char *content, int flags)
1347    {
1348            int res;
1349            regex_t re;
1350            if(regcomp(&re, content, flags | REG_EXTENDED | REG_NOSUB))
1351                    return 0;
1352            res = regexec(&re, key, 0, NULL, 0);
1353            regfree(&re);
1354            return res == 0;
1355    }
1356    
1357    static int expr_eval(const char *key, int op, const char *content)
1358    {
1359            switch(op)
1360            {
1361            case OP_CONTAINED:      return rexpr_eval(key, content, 0);
1362            case OP_CONTAINEDI:     return rexpr_eval(key, content, REG_ICASE);
1363            case OP_NCONTAINED:     return !rexpr_eval(key, content, 0);
1364            case OP_NCONTAINEDI:    return !rexpr_eval(key, content, REG_ICASE);
1365            case OP_EQ:     return strcmp(key, content) == 0;
1366            case OP_NE:     return strcmp(key, content) != 0;
1367            case OP_GE:     return strcmp(key, content) >= 0;
1368            case OP_GT:     return strcmp(key, content) > 0;
1369            case OP_LE:     return strcmp(key, content) <= 0;
1370            case OP_LT:     return strcmp(key, content) < 0;
1371            }
1372            return 0;
1373    }
1374    
1375    static char *eval_string(node_t *node, revision_t *r)
1376    {
1377            int i;
1378            assert(node != NULL);
1379            switch(node->key)
1380            {
1381            default:
1382            case TYPE_COLOR:
1383                    return "";      /* This should not happen */
1384            case TYPE_STRING:
1385                    return node->value.str;
1386            case KEY_STATE:
1387                    if(r && expr_eval(r->delta->state, node->op, node->content))
1388                            return eval_string(node->tcase, r);
1389                    else
1390                            return eval_string(node->fcase, r);
1391            case KEY_AUTHOR:
1392                    if(r && expr_eval(r->delta->author, node->op, node->content))
1393                            return eval_string(node->tcase, r);
1394                    else
1395                            return eval_string(node->fcase, r);
1396            case KEY_TAG:
1397                    for(i = 0; r && i < r->ntags; i++)
1398                    {
1399                            if(expr_eval(r->tags[i]->tag, node->op, node->content))
1400                                    return eval_string(node->tcase, r);
1401                    }
1402                    return eval_string(node->fcase, r);
1403            case KEY_DATE:
1404                    if(r && expr_eval(r->delta->date, node->op, node->content))
1405                            return eval_string(node->tcase, r);
1406                    else
1407                            return eval_string(node->fcase, r);
1408            case KEY_REV:
1409                    if(r && expr_eval(r->rev->rev, node->op, node->content))
1410                            return eval_string(node->tcase, r);
1411                    else
1412                            return eval_string(node->fcase, r);
1413            }
1414            return "";
1415    }
1416    static color_t *eval_color(node_t *node, revision_t *r, branch_t *b)
1417  {  {
1418          int i;          int i;
1419          color_t *c = get_colorref(s);          assert(node != NULL);
1420            switch(node->key)
1421            {
1422            default:
1423            case TYPE_STRING:
1424                    return &black_color;    /* This should not happen */
1425            case TYPE_COLOR:
1426                    return &node->value.clr;
1427            case KEY_STATE:
1428                    if(r && expr_eval(r->delta->state, node->op, node->content))
1429                            return eval_color(node->tcase, r, b);
1430                    else
1431                            return eval_color(node->fcase, r, b);
1432            case KEY_AUTHOR:
1433                    if(r && expr_eval(r->delta->author, node->op, node->content))
1434                            return eval_color(node->tcase, r, b);
1435                    else
1436                            return eval_color(node->fcase, r, b);
1437            case KEY_TAG:
1438                    for(i = 0; r && i < r->ntags; i++)
1439                    {
1440                            if(expr_eval(r->tags[i]->tag, node->op, node->content))
1441                                    return eval_color(node->tcase, r, b);
1442                    }
1443                    return eval_color(node->fcase, r, b);
1444            case KEY_DATE:
1445                    if(r && expr_eval(r->delta->date, node->op, node->content))
1446                            return eval_color(node->tcase, r, b);
1447                    else
1448                            return eval_color(node->fcase, r, b);
1449            case KEY_REV:
1450                    if(r && expr_eval(r->rev->rev, node->op, node->content))
1451                            return eval_color(node->tcase, r, b);
1452                    if(b && expr_eval(b->branch->branch, node->op, node->content))
1453                            return eval_color(node->tcase, r, b);
1454                    return eval_color(node->fcase, r, b);
1455            }
1456            return &black_color;
1457    }
1458    
1459    static color_t *clr(gdImagePtr im, const char *s, revision_t *r, branch_t *b, int idx)
1460    {
1461            int i;
1462            color_t *c = get_colorref(s, idx);
1463          if(!c)          if(!c)
1464                  c = &black_color;                  c = &black_color;
1465            if(c->node)
1466                    c = eval_color(c->node, r, b);
1467          for(i = 0; i < nclr_id; i++)          for(i = 0; i < nclr_id; i++)
1468          {          {
1469                  if(c->r == clr_id[i].r && c->g == clr_id[i].g && c->b == clr_id[i].b)                  if(c->r == clr_id[i].r && c->g == clr_id[i].g && c->b == clr_id[i].b)
1470                          return &clr_id[i];                          return &clr_id[i];
1471          }          }
         /* FIXME: Do color evaluation */  
1472          clr_id = xrealloc(clr_id, (nclr_id+1) * sizeof(*clr_id));          clr_id = xrealloc(clr_id, (nclr_id+1) * sizeof(*clr_id));
1473          clr_id[nclr_id] = *c;          clr_id[nclr_id] = *c;
1474          clr_id[nclr_id].id = gdImageColorAllocate(im, c->r, c->g, c->b);          clr_id[nclr_id].id = gdImageColorAllocate(im, c->r, c->g, c->b);
1475          return &clr_id[nclr_id++];          return &clr_id[nclr_id++];
1476  }  }
1477    
1478    static void zap_clr(void)
1479    {
1480            if(clr_id)
1481                    xfree(clr_id);
1482            clr_id = NULL;
1483            nclr_id = 0;
1484    }
1485    
1486  static int get_swidth(const char *s, font_t *f)  static int get_swidth(const char *s, font_t *f)
1487  {  {
1488          int n;          int n;
# Line 1437  Line 1569 
1569          gdImageLine(im, x2, y1+r, x2, y2-r, color->id);          gdImageLine(im, x2, y1+r, x2, y2-r, color->id);
1570          if(conf.box_shadow)          if(conf.box_shadow)
1571          {          {
1572                  gdImageLine(im, x1+r+1, y2+1, x2-r, y2+1, black_color.id);                  gdImageLine(im, x1+r+1, y2+1, x2-r, y2+1, clr(im, NULL, NULL, NULL, 0)->id);
1573                  gdImageLine(im, x2+1, y1+r+1, x2+1, y2-r, black_color.id);                  gdImageLine(im, x2+1, y1+r+1, x2+1, y2-r, clr(im, NULL, NULL, NULL, 0)->id);
1574          }          }
1575          if(r)          if(r)
1576          {          {
# Line 1448  Line 1580 
1580                  gdImageArc(im, x1+r, y2-r, r2, r2,  90, 180, color->id);                  gdImageArc(im, x1+r, y2-r, r2, r2,  90, 180, color->id);
1581                  if(conf.box_shadow)                  if(conf.box_shadow)
1582                  {                  {
1583                          gdImageArc(im, x2-r+1, y2-r+1, r2, r2,   0,  90, black_color.id);                          gdImageArc(im, x2-r+1, y2-r+1, r2, r2,   0,  90, clr(im, NULL, NULL, NULL, 0)->id);
1584                          gdImageArc(im, x2-r+1, y2-r, r2, r2,   0,  90, black_color.id);                          gdImageArc(im, x2-r+1, y2-r, r2, r2,   0,  90, clr(im, NULL, NULL, NULL, 0)->id);
1585                          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, clr(im, NULL, NULL, NULL, 0)->id);
1586                  }                  }
1587                  gdImageArc(im, x2-r, y2-r, r2, r2,   0,  90, color->id);                  gdImageArc(im, x2-r, y2-r, r2, r2,   0,  90, color->id);
1588  #if !defined(NOGDFILL) && !defined(HAVE_GDIMAGEFILLEDARC)  #if !defined(NOGDFILL) && !defined(HAVE_GDIMAGEFILLEDARC)
# Line 1495  Line 1627 
1627          }          }
1628  #endif  #endif
1629          yy = -yy;          yy = -yy;
1630          gdImageString(im, f->gdfont, x+xx+1, y+yy, s, c->id);          gdImageString(im, f->gdfont, x+xx+1, y+yy, (unsigned char *)s, c->id);
1631  }  }
1632    
1633  static void draw_stringnl(gdImagePtr im, char *s, font_t *f, int x, int y, int align, color_t *c)  static void draw_stringnl(gdImagePtr im, char *s, font_t *f, int x, int y, int align, color_t *c)
# Line 1537  Line 1669 
1669                  ty = r->y;                  ty = r->y;
1670                  x2 = r->cx;                  x2 = r->cx;
1671          }          }
1672          draw_rbox(im, lx, ty, rx, ty+r->h, 0, clr(im, "rev_color", r, NULL), clr(im, "rev_bgcolor", r, NULL));          draw_rbox(im, lx, ty, rx, ty+r->h, 0, clr(im, "rev_color", r, NULL, 0), clr(im, "rev_bgcolor", r, NULL, 0));
1673          ty += conf.rev_tspace;          ty += conf.rev_tspace;
1674          if(!conf.rev_hidenumber)          if(!conf.rev_hidenumber)
1675          {          {
1676                  draw_string(im, r->rev->rev, &conf.rev_font, x2, ty, ALIGN_HC, clr(im, "rev_color", r, NULL));                  draw_string(im, r->revidtext, &conf.rev_font, x2, ty, ALIGN_HC, clr(im, "rev_color", r, NULL, 0));
1677                  ty += get_sheight(r->rev->rev, &conf.rev_font);                  ty += get_sheight(r->revidtext, &conf.rev_font);
1678          }          }
1679          draw_stringnl(im, r->revtext, &conf.rev_text_font, x2, ty, ALIGN_HC, clr(im, "rev_text_color", r, NULL));          draw_stringnl(im, r->revtext, &conf.rev_text_font, x2, ty, ALIGN_HC, clr(im, "rev_text_color", r, NULL, 0));
1680          ty += get_sheight(r->revtext, &conf.rev_text_font);          ty += get_sheight(r->revtext, &conf.rev_text_font);
1681          for(i = 0; i < r->ntags; i++)          for(i = 0; i < r->ntags; i++)
1682          {          {
1683                  draw_string(im, r->tags[i]->tag, &conf.tag_font, x2, ty, ALIGN_HC, clr(im, "tag_color", r, NULL));                  draw_string(im, r->tags[i]->tag, &conf.tag_font, x2, ty, ALIGN_HC, clr(im, "tag_color", r, NULL, 0));
1684                  ty += get_sheight(r->tags[i]->tag, &conf.tag_font) + conf.rev_separator;                  ty += get_sheight(r->tags[i]->tag, &conf.tag_font) + conf.rev_separator;
1685          }          }
1686  }  }
# Line 1573  Line 1705 
1705                  rx = lx + b->w;                  rx = lx + b->w;
1706                  x2 = b->cx;                  x2 = b->cx;
1707          }          }
1708          draw_rbox(im, lx+xp, yp, rx+xp, yp+b->h, 5, clr(im, "branch_color", NULL, b), clr(im, "branch_bgcolor", NULL, b));          draw_rbox(im, lx+xp, yp, rx+xp, yp+b->h, 5, clr(im, "branch_color", NULL, b, 0), clr(im, "branch_bgcolor", NULL, b, 0));
1709          yy = conf.branch_tspace;          yy = conf.branch_tspace;
1710          if(!b->nfolds)          if(!b->nfolds)
1711          {          {
1712                  if(!conf.rev_hidenumber)                  if(!conf.rev_hidenumber)
1713                  {                  {
1714                          draw_string(im, b->branch->branch, &conf.branch_font, x2+xp, yp+yy, ALIGN_HC, clr(im, "branch_color", NULL, b));                          draw_string(im, b->branch->branch, &conf.branch_font, x2+xp, yp+yy, ALIGN_HC, clr(im, "branch_color", NULL, b, 0));
1715                          yy += get_sheight(b->branch->branch, &conf.branch_font);                          yy += get_sheight(b->branch->branch, &conf.branch_font);
1716                  }                  }
1717                  for(i = 0; i < b->ntags; i++)                  for(i = 0; i < b->ntags; i++)
1718                  {                  {
1719                          draw_string(im, b->tags[i]->tag, &conf.branch_tag_font, x2+xp, yp+yy, ALIGN_HC, clr(im, "branch_tag_color", NULL, b));                          draw_string(im, b->tags[i]->tag, &conf.branch_tag_font, x2+xp, yp+yy, ALIGN_HC, clr(im, "branch_tag_color", NULL, b, 0));
1720                          yy += get_sheight(b->tags[i]->tag, &conf.branch_tag_font);                          yy += get_sheight(b->tags[i]->tag, &conf.branch_tag_font);
1721                  }                  }
1722          }          }
# Line 1593  Line 1725 
1725                  int y1, y2;                  int y1, y2;
1726                  int tx = lx + b->fw + conf.branch_lspace;                  int tx = lx + b->fw + conf.branch_lspace;
1727                  int nx = tx - get_swidth(" ", &conf.branch_font);                  int nx = tx - get_swidth(" ", &conf.branch_font);
1728                  draw_string(im, b->branch->branch, &conf.branch_font, nx+xp, yp+yy, ALIGN_HR, clr(im, "branch_color", NULL, b));                  draw_string(im, b->branch->branch, &conf.branch_font, nx+xp, yp+yy, ALIGN_HR, clr(im, "branch_color", NULL, b, 0));
1729                  y1 = get_sheight(b->branch->branch, &conf.branch_font);                  y1 = get_sheight(b->branch->branch, &conf.branch_font);
1730                  draw_string(im, b->tags[0]->tag, &conf.branch_tag_font, tx+xp, yp+yy, ALIGN_HL, clr(im, "branch_tag_color", NULL, b));                  draw_string(im, b->tags[0]->tag, &conf.branch_tag_font, tx+xp, yp+yy, ALIGN_HL, clr(im, "branch_tag_color", NULL, b, 0));
1731                  y2 = get_sheight(b->tags[0]->tag, &conf.branch_font);                  y2 = get_sheight(b->tags[0]->tag, &conf.branch_font);
1732                  yy += MAX(y1, y2);                  yy += MAX(y1, y2);
1733                  for(i = 0; i < b->nfolds; i++)                  for(i = 0; i < b->nfolds; i++)
1734                  {                  {
1735                          draw_string(im, b->folds[i]->branch->branch, &conf.branch_font, nx+xp, yp+yy, ALIGN_HR, clr(im, "branch_color", NULL, b));                          draw_string(im, b->folds[i]->branch->branch, &conf.branch_font, nx+xp, yp+yy, ALIGN_HR, clr(im, "branch_color", NULL, b, 0));
1736                          y1 = get_sheight(b->folds[i]->branch->branch, &conf.branch_font);                          y1 = get_sheight(b->folds[i]->branch->branch, &conf.branch_font);
1737                          draw_string(im, b->folds[i]->tags[0]->tag, &conf.branch_tag_font, tx+xp, yp+yy, ALIGN_HL, clr(im, "branch_tag_color", NULL, b));                          draw_string(im, b->folds[i]->tags[0]->tag, &conf.branch_tag_font, tx+xp, yp+yy, ALIGN_HL, clr(im, "branch_tag_color", NULL, b, 0));
1738                          y2 = get_sheight(b->folds[i]->tags[0]->tag, &conf.branch_tag_font);                          y2 = get_sheight(b->folds[i]->tags[0]->tag, &conf.branch_tag_font);
1739                          yy += MAX(y1, y2);                          yy += MAX(y1, y2);
1740                  }                  }
# Line 1641  Line 1773 
1773                          for(i = 0; i < b->nrevs; i++)                          for(i = 0; i < b->nrevs; i++)
1774                          {                          {
1775                                  revision_t *r = b->revs[i];                                  revision_t *r = b->revs[i];
1776                                  line[0] = line[3] = clr(im, "rev_color", r, b)->id;                                  line[0] = line[3] = clr(im, "rev_color", r, b, 0)->id;
1777                                  gdImageSetStyle(im, line, r->stripped > 0 ? 4 : 1);                                  gdImageSetStyle(im, line, r->stripped > 0 ? 4 : 1);
1778                                  gdImageLine(im, xx, r->y, r->cx+r->w, r->y, gdStyled);                                  gdImageLine(im, xx, r->y, r->cx+r->w, r->y, gdStyled);
1779                                  for(sign = l = 1; l < conf.thick_lines; l++)                                  for(sign = l = 1; l < conf.thick_lines; l++)
# Line 1656  Line 1788 
1788                          if(conf.branch_dupbox && b->nrevs)                          if(conf.branch_dupbox && b->nrevs)
1789                          {                          {
1790                                  i = b->cx - b->tw + b->w;                                  i = b->cx - b->tw + b->w;
1791                                  gdImageLine(im, xx, b->y, i+b->w, b->y, clr(im, "rev_color", NULL, b)->id);                                  gdImageLine(im, xx, b->y, i+b->w, b->y, clr(im, "rev_color", NULL, b, 0)->id);
1792                                  for(sign = l = 1; l < conf.thick_lines; l++)                                  for(sign = l = 1; l < conf.thick_lines; l++)
1793                                  {                                  {
1794                                          int pp = (l+1)/2*sign;                                          int pp = (l+1)/2*sign;
1795                                          gdImageLine(im, xx, b->y+pp, i+b->w, b->y+pp, clr(im, "rev_color", NULL, b)->id);                                          gdImageLine(im, xx, b->y+pp, i+b->w, b->y+pp, clr(im, "rev_color", NULL, b, 0)->id);
1796                                          sign *= -1;                                          sign *= -1;
1797                                  }                                  }
1798                                  draw_branch_box(im, b, i - b->cx, b->y - b->h/2);                                  draw_branch_box(im, b, i - b->cx, b->y - b->h/2);
# Line 1672  Line 1804 
1804                          for(i = 0; i < b->nrevs; i++)                          for(i = 0; i < b->nrevs; i++)
1805                          {                          {
1806                                  revision_t *r = b->revs[i];                                  revision_t *r = b->revs[i];
1807                                  line[0] = line[3] = clr(im, "rev_color", r, b)->id;                                  line[0] = line[3] = clr(im, "rev_color", r, b, 0)->id;
1808                                  gdImageSetStyle(im, line, r->stripped > 0 ? 4 : 1);                                  gdImageSetStyle(im, line, r->stripped > 0 ? 4 : 1);
1809                                  gdImageLine(im, xx, r->y, r->cx, r->y, gdStyled);                                  gdImageLine(im, xx, r->y, r->cx, r->y, gdStyled);
1810                                  for(sign = l = 1; l < conf.thick_lines; l++)                                  for(sign = l = 1; l < conf.thick_lines; l++)
# Line 1687  Line 1819 
1819                          if(conf.branch_dupbox && b->nrevs)                          if(conf.branch_dupbox && b->nrevs)
1820                          {                          {
1821                                  i = b->cx + b->tw - b->w;                                  i = b->cx + b->tw - b->w;
1822                                  gdImageLine(im, xx, b->y, i, b->y, clr(im, "rev_color", NULL, b)->id);                                  gdImageLine(im, xx, b->y, i, b->y, clr(im, "rev_color", NULL, b, 0)->id);
1823                                  for(sign = l = 1; l < conf.thick_lines; l++)                                  for(sign = l = 1; l < conf.thick_lines; l++)
1824                                  {                                  {
1825                                          int pp = (l+1)/2*sign;                                          int pp = (l+1)/2*sign;
1826                                          gdImageLine(im, xx, b->y+pp, i, b->y+pp, clr(im, "rev_color", NULL, b)->id);                                          gdImageLine(im, xx, b->y+pp, i, b->y+pp, clr(im, "rev_color", NULL, b, 0)->id);
1827                                          sign *= -1;                                          sign *= -1;
1828                                  }                                  }
1829                                  draw_branch_box(im, b, i - b->cx, b->y - b->h/2);                                  draw_branch_box(im, b, i - b->cx, b->y - b->h/2);
# Line 1706  Line 1838 
1838                          for(i = 0; i < b->nrevs; i++)                          for(i = 0; i < b->nrevs; i++)
1839                          {                          {
1840                                  revision_t *r = b->revs[i];                                  revision_t *r = b->revs[i];
1841                                  line[0] = line[3] = clr(im, "rev_color", r, b)->id;                                  line[0] = line[3] = clr(im, "rev_color", r, b, 0)->id;
1842                                  gdImageSetStyle(im, line, r->stripped > 0 ? 4 : 1);                                  gdImageSetStyle(im, line, r->stripped > 0 ? 4 : 1);
1843                                  gdImageLine(im, r->cx, yy, r->cx, r->y+r->h, gdStyled);                                  gdImageLine(im, r->cx, yy, r->cx, r->y+r->h, gdStyled);
1844                                  for(sign = l = 1; l < conf.thick_lines; l++)                                  for(sign = l = 1; l < conf.thick_lines; l++)
# Line 1721  Line 1853 
1853                          if(conf.branch_dupbox && b->nrevs)                          if(conf.branch_dupbox && b->nrevs)
1854                          {                          {
1855                                  i = b->y - b->th + b->h;                                  i = b->y - b->th + b->h;
1856                                  gdImageLine(im, b->cx, yy, b->cx, i, clr(im, "rev_color", NULL, b)->id);                                  gdImageLine(im, b->cx, yy, b->cx, i, clr(im, "rev_color", NULL, b, 0)->id);
1857                                  for(sign = l = 1; l < conf.thick_lines; l++)                                  for(sign = l = 1; l < conf.thick_lines; l++)
1858                                  {                                  {
1859                                          int pp = (l+1)/2*sign;                                          int pp = (l+1)/2*sign;
1860                                          gdImageLine(im, b->cx+pp, yy, b->cx+pp, i, clr(im, "rev_color", NULL, b)->id);                                          gdImageLine(im, b->cx+pp, yy, b->cx+pp, i, clr(im, "rev_color", NULL, b, 0)->id);
1861                                          sign *= -1;                                          sign *= -1;
1862                                  }                                  }
1863                                  draw_branch_box(im, b, 0, i);                                  draw_branch_box(im, b, 0, i);
# Line 1737  Line 1869 
1869                          for(i = 0; i < b->nrevs; i++)                          for(i = 0; i < b->nrevs; i++)
1870                          {                          {
1871                                  revision_t *r = b->revs[i];                                  revision_t *r = b->revs[i];
1872                                  line[0] = line[3] = clr(im, "rev_color", r, b)->id;                                  line[0] = line[3] = clr(im, "rev_color", r, b, 0)->id;
1873                                  gdImageSetStyle(im, line, r->stripped > 0 ? 4 : 1);                                  gdImageSetStyle(im, line, r->stripped > 0 ? 4 : 1);
1874                                  gdImageLine(im, r->cx, yy, r->cx, r->y, gdStyled);                                  gdImageLine(im, r->cx, yy, r->cx, r->y, gdStyled);
1875                                  for(sign = l = 1; l < conf.thick_lines; l++)                                  for(sign = l = 1; l < conf.thick_lines; l++)
# Line 1752  Line 1884 
1884                          if(conf.branch_dupbox && b->nrevs)                          if(conf.branch_dupbox && b->nrevs)
1885                          {                          {
1886                                  i = b->y + b->th - b->h;                                  i = b->y + b->th - b->h;
1887                                  gdImageLine(im, b->cx, yy, b->cx, i, clr(im, "rev_color", NULL, b)->id);                                  gdImageLine(im, b->cx, yy, b->cx, i, clr(im, "rev_color", NULL, b, 0)->id);
1888                                  for(sign = l = 1; l < conf.thick_lines; l++)                                  for(sign = l = 1; l < conf.thick_lines; l++)
1889                                  {                                  {
1890                                          int pp = (l+1)/2*sign;                                          int pp = (l+1)/2*sign;
1891                                          gdImageLine(im, b->cx+pp, yy, b->cx+pp, i, clr(im, "rev_color", NULL, b)->id);                                          gdImageLine(im, b->cx+pp, yy, b->cx+pp, i, clr(im, "rev_color", NULL, b, 0)->id);
1892                                          sign *= -1;                                          sign *= -1;
1893                                  }                                  }
1894                                  draw_branch_box(im, b, 0, i);                                  draw_branch_box(im, b, 0, i);
# Line 1793  Line 1925 
1925                  if(conf.upside_down)                  if(conf.upside_down)
1926                          y2 += b->h;                          y2 += b->h;
1927          }          }
1928          gdImageLine(im, x1, y1, x2, y1, clr(im, "branch_color", NULL, b)->id);          gdImageLine(im, x1, y1, x2, y1, clr(im, "branch_color", NULL, b, 0)->id);
1929          gdImageLine(im, x2, y1, x2, y2, clr(im, "branch_color", NULL, b)->id);          gdImageLine(im, x2, y1, x2, y2, clr(im, "branch_color", NULL, b, 0)->id);
1930          for(sign = l = 1; l < conf.thick_lines; l++)          for(sign = l = 1; l < conf.thick_lines; l++)
1931          {          {
1932                  int pp = (l+1)/2*sign;                  int pp = (l+1)/2*sign;
1933                  gdImageLine(im, x1, y1+pp, x2, y1+pp, clr(im, "branch_color", NULL, b)->id);                  gdImageLine(im, x1, y1+pp, x2, y1+pp, clr(im, "branch_color", NULL, b, 0)->id);
1934                  gdImageLine(im, x2+pp, y1, x2+pp, y2, clr(im, "branch_color", NULL, b)->id);                  gdImageLine(im, x2+pp, y1, x2+pp, y2, clr(im, "branch_color", NULL, b, 0)->id);
1935                  sign *= -1;                  sign *= -1;
1936          }          }
1937  }  }
1938    
1939  static void draw_merges(gdImagePtr im, rcsfile_t *rcs, int dot)  static void calc_merge_coords(merge_t *mt, revision_t *fr, revision_t *tr, int *x1, int *x2, int *y1, int *y2, int *sx1, int *sx2, int *sy1, int *sy2)
1940  {  {
1941          int i;          int shadow = conf.box_shadow ? 1 : 0;
1942          for(i = 0; i < rcs->nmerges; i++)          assert(mt != NULL);
1943          {          assert(fr != NULL);
1944                  revision_t *fr;          assert(tr != NULL);
1945                  revision_t *tr;          assert(x1 != NULL);
1946                  int colorid;          assert(x2 != NULL);
1947                  int x1, x2, y1, y2;          assert(y1 != NULL);
1948                  switch(rcs->merges[i].type)          assert(y2 != NULL);
1949                  {          assert(sx1 != NULL);
1950                  case TR_TAG:          assert(sx2 != NULL);
1951                          fr = rcs->merges[i].from.tag->logrev;          assert(sy1 != NULL);
1952                          tr = rcs->merges[i].to.tag->logrev;          assert(sy2 != NULL);
1953                          colorid = clr(im, "merge_color.id", NULL, NULL)->id;          if(conf.left_right && !conf.merge_on_tag)
1954                          break;          {
1955                  case TR_REVISION:                  if(fr->branch == tr->branch)
1956                          fr = rcs->merges[i].from.rev;                  {
1957                          tr = rcs->merges[i].to.rev;                          *y1 = fr->y - (fr->h+1)/2;
1958                          colorid = clr(im, "merge_cvsnt_color", NULL, NULL)->id;                          *y2 = tr->y - (tr->h+1)/2;
1959                          break;                          *sy1 = *sy2 = -1;
                 default:  
                         continue;  
1960                  }                  }
1961                  if(!fr || !tr || fr == tr)                  else
                         continue;       /* This can happen with detached tags and self-references */  
                 if(conf.left_right)  
1962                  {                  {
1963                          if(fr->branch == tr->branch)                          /* See comment below on shortest path */
1964                            int y1a = fr->y + (fr->h+1)/2 + shadow;
1965                            int y1b = fr->y - (fr->h+1)/2;
1966                            int y2a = tr->y + (tr->h+1)/2 + shadow;
1967                            int y2b = tr->y - (tr->h+1)/2;
1968                            int laa = abs(y2a - y1a);
1969                            int lba = abs(y2a - y1b);
1970                            int lab = abs(y2b - y1a);
1971                            int lbb = abs(y2b - y1b);
1972                            if(laa < lab)
1973                          {                          {
1974                                  y1 = fr->y - fr->h/2;                                  if(laa < lba)
1975                                  y2 = tr->y - tr->h/2;                                  {
1976                                            if(laa < lbb)
1977                                            {
1978                                                    *y1 = y1a;
1979                                                    *y2 = y2a;
1980                                                    *sy1 = *sy2 = 1;
1981                                            }
1982                                            else
1983                                            {
1984    ybb:
1985                                                    *y1 = y1b;
1986                                                    *y2 = y2b;
1987                                                    *sy1 = *sy2 = -1;
1988                                            }
1989                                    }
1990                                    else
1991                                    {
1992    yba:
1993                                            if(lba < lbb)
1994                                            {
1995                                                    *y1 = y1b;
1996                                                    *y2 = y2a;
1997                                                    *sy1 = -1;
1998                                                    *sy2 = 1;
1999                                            }
2000                                            else
2001                                                    goto ybb;
2002                                    }
2003                          }                          }
2004                          else                          else
2005                          {                          {
2006                                  if(fr->y < tr->y)                                  if(lab < lba)
2007                                  {                                  {
2008                                          y1 = fr->y + fr->h/2;                                          if(lab < lbb)
2009                                          y2 = tr->y - tr->h/2;                                          {
2010                                                    *y1 = y1a;
2011                                                    *y2 = y2b;
2012                                                    *sy1 = 1;
2013                                                    *sy2 = -1;
2014                                            }
2015                                            else
2016                                                    goto ybb;
2017                                  }                                  }
2018                                  else                                  else
2019                                  {                                          goto yba;
                                         y1 = fr->y - fr->h/2;  
                                         y2 = tr->y + tr->h/2;  
                                 }  
2020                          }                          }
2021                          x1 = fr->cx + fr->w/2;                  }
2022                          x2 = tr->cx + tr->w/2;                  *x1 = fr->cx + fr->w/2;
2023                    *x2 = tr->cx + tr->w/2;
2024                    *sx1 = *sx2 = 1;
2025            }
2026            else
2027            {
2028                    if(fr->branch == tr->branch)
2029                    {
2030                            /* Line on same branch always on left side */
2031                            *x1 = fr->cx - fr->w/2;
2032                            *x2 = tr->cx - tr->w/2;
2033                            *sx1 = *sx2 = -1;
2034                  }                  }
2035                  else                  else
2036                  {                  {
2037                          if(fr->branch == tr->branch)                          /* Find the shortest route from the two revisions
2038                          {                           * to determine which sides of the revision box
2039                                  x1 = fr->cx - fr->w/2;                           * should be used. The basics are:
2040                                  x2 = tr->cx - tr->w/2;                           * l = (x2 -x1)^2 + (y2 - y1)^2
2041                          }                           * However, (y2 -y1) is constant and hence the
2042                          else                           * determination of the shortest path is already
2043                             * clear from |x2 -x1| for each permutation of left
2044                             * and right x.
2045                             * This strategy is still not perfect because it can
2046                             * happen that a source/destination is overlayed by
2047                             * the revision box. To prevent this, we need to do
2048                             * a very deep analysis and I'm not prepared to do
2049                             * that right now...
2050                             */
2051                            int x1a = fr->cx + (fr->w+1)/2 + shadow;
2052                            int x1b = fr->cx - (fr->w+1)/2;
2053                            int x2a = tr->cx + (tr->w+1)/2 + shadow;
2054                            int x2b = tr->cx - (tr->w+1)/2;
2055                            int laa = abs(x2a - x1a);
2056                            int lba = abs(x2a - x1b);
2057                            int lab = abs(x2b - x1a);
2058                            int lbb = abs(x2b - x1b);
2059                            if(laa < lab)
2060                          {                          {
2061                                  if(fr->cx < tr->cx)                                  if(laa < lba)
2062                                  {                                  {
2063                                          x1 = fr->cx + fr->w/2;                                          if(laa < lbb)
2064                                          x2 = tr->cx - tr->w/2;                                          {
2065                                                    *x1 = x1a;
2066                                                    *x2 = x2a;
2067                                                    *sx1 = *sx2 = 1;
2068                                            }
2069                                            else
2070                                            {
2071    xbb:
2072                                                    *x1 = x1b;
2073                                                    *x2 = x2b;
2074                                                    *sx1 = *sx2 = -1;
2075                                            }
2076                                  }                                  }
2077                                  else                                  else
2078                                  {                                  {
2079                                          x1 = fr->cx - fr->w/2;  xba:
2080                                          x2 = tr->cx + tr->w/2;                                          if(lba < lbb)
2081                                            {
2082                                                    *x1 = x1b;
2083                                                    *x2 = x2a;
2084                                                    *sx1 = -1;
2085                                                    *sx2 = 1;
2086                                            }
2087                                            else
2088                                                    goto xbb;
2089                                  }                                  }
2090                          }                          }
2091                          if(rcs->merges[i].type == TR_TAG)                          else
2092                          {                          {
2093                                  y1 = fr->y + rcs->merges[i].from.tag->yofs;                                  if(lab < lba)
2094                                  y2 = tr->y + rcs->merges[i].to.tag->yofs;                                  {
2095                                            if(lab < lbb)
2096                                            {
2097                                                    *x1 = x1a;
2098                                                    *x2 = x2b;
2099                                                    *sx1 = 1;
2100                                                    *sx2 = -1;
2101                                            }
2102                                            else
2103                                                    goto xbb;
2104                                    }
2105                                    else
2106                                            goto xba;
2107                          }                          }
2108                          else                  }
2109                    if(mt->type == TR_TAG)
2110                    {
2111                            *y1 = fr->y + mt->from.tag->yofs;
2112                            *y2 = tr->y + mt->to.tag->yofs;
2113                            if(conf.left_right && conf.merge_on_tag)
2114                          {                          {
2115                                  y1 = fr->y + fr->h/2;                                  *y1 -= fr->h/2;
2116                                  y2 = tr->y + tr->h/2;                                  *y2 -= tr->h/2;
2117                          }                          }
2118                  }                  }
2119                    else
2120                    {
2121                            *y1 = fr->y + fr->h/2;
2122                            *y2 = tr->y + tr->h/2;
2123                    }
2124                    *sy1 = *sy2 = 1;
2125                    if(conf.left_right && conf.merge_on_tag)
2126                    {
2127                            *x1 += fr->w/2;
2128                            *x2 += tr->w/2;
2129                    }
2130            }
2131    }
2132    
2133    static void draw_merges(gdImagePtr im, rcsfile_t *rcs, int dot)
2134    {
2135            int i;
2136            for(i = 0; i < rcs->nmerges; i++)
2137            {
2138                    revision_t *fr;
2139                    revision_t *tr;
2140                    int colorid;
2141                    int x1, x2, y1, y2;             /* Edge position on revision box */
2142                    int sx1, sx2, sy1, sy2;         /* Direction for mergeline -1 = left/up, +1 = right/down */
2143                    switch(rcs->merges[i].type)
2144                    {
2145                    case TR_TAG:
2146                            fr = rcs->merges[i].from.tag->logrev;
2147                            tr = rcs->merges[i].to.tag->logrev;
2148                            colorid = clr(im, "merge_color", NULL, NULL, rcs->merges[i].clr)->id;
2149                            break;
2150                    case TR_REVISION:
2151                            fr = rcs->merges[i].from.rev;
2152                            tr = rcs->merges[i].to.rev;
2153                            colorid = clr(im, "merge_cvsnt_color", NULL, NULL, 0)->id;
2154                            break;
2155                    default:
2156                            continue;
2157                    }
2158                    if(!fr || !tr || fr == tr)
2159                            continue;       /* This can happen with detached tags and self-references */
2160    
2161                    calc_merge_coords(&rcs->merges[i], fr, tr, &x1, &x2, &y1, &y2, &sx1, &sx2, &sy1, &sy2);
2162    
2163                  if(dot && !conf.merge_arrows)                  if(dot && !conf.merge_arrows)
2164                  {                  {
2165                          int o = conf.left_right ? 1 : 0;                          int o = conf.left_right ? 1 : 0;
# Line 1906  Line 2182 
2182    
2183                          sx = x1; sy = y1;                          sx = x1; sy = y1;
2184                          ex = x2; ey = y2;                          ex = x2; ey = y2;
2185                          if(conf.left_right)                          if(conf.left_right && !conf.merge_on_tag)
2186                          {                          {
2187                                  if(fr->branch == tr->branch)                                  if(fr->branch == tr->branch)
2188                                  {                                  {
# Line 1916  Line 2192 
2192                                  }                                  }
2193                                  else                                  else
2194                                  {                                  {
2195                                          if(y1 > y2)                                          sy = y1 + 3 * sy1;
2196                                          {                                          ey = y2 + 3 * sy2;
                                                 /* line from (x1,y1-3) to (x2,y2+3+1) */  
                                                 sy = y1-3;  
                                                 ey = y2+3+1;  
                                         }  
                                         else  
                                         {  
                                                 /* line from (x1,y1+3+1) to (x2,y2-3) */  
                                                 sy = y1+3+1;  
                                                 ey = y2-3;  
                                         }  
2197                                  }                                  }
2198                          }                          }
2199                          else                          else
# Line 1940  Line 2206 
2206                                  }                                  }
2207                                  else                                  else
2208                                  {                                  {
2209                                          if(x1 > x2)                                          sx = x1 + 3 * sx1;
2210                                          {                                          ex = x2 + 3 * sx2;
                                                 /* line from (x1-3,y1) to (x2+3,y2) */  
                                                 sx = x1-3;  
                                                 ex = x2+3;  
                                         }  
                                         else  
                                         {  
                                                 /* line from (x1+3,y1) to (x2-3,y2) */  
                                                 sx = x1+3;  
                                                 ex = x2-3;  
                                         }  
2211                                  }                                  }
2212                          }                          }
2213                          /*                          /*
# Line 1976  Line 2232 
2232                  }                  }
2233                  else                  else
2234                  {                  {
2235                          if(conf.left_right)                          if(conf.left_right && !conf.merge_on_tag)
2236                          {                          {
2237                                  if(fr->branch == tr->branch)                                  if(fr->branch == tr->branch)
2238                                  {                                  {
# Line 1987  Line 2243 
2243                                  }                                  }
2244                                  else                                  else
2245                                  {                                  {
2246                                          if(y1 > y2)                                          gdImageLine(im, x1, y1, x1, y1+3*sy1, colorid);
2247                                          {                                          gdImageLine(im, x2, y2, x2, y2+3*sy2, colorid);
2248                                                  gdImageLine(im, x1, y1, x1, y1-3, colorid);                                          gdImageLine(im, x1, y1+3*sy1, x2, y2+3*sy2, colorid);
                                                 gdImageLine(im, x2, y2+1, x2, y2+3+1, colorid);  
                                                 gdImageLine(im, x1, y1-3, x2, y2+3+1, colorid);  
                                         }  
                                         else  
                                         {  
                                                 gdImageLine(im, x1, y1+1, x1, y1+3+1, colorid);  
                                                 gdImageLine(im, x2, y2, x2, y2-3, colorid);  
                                                 gdImageLine(im, x1, y1+3+1, x2, y2-3, colorid);  
                                         }  
2249                                  }                                  }
2250                          }                          }
2251                          else                          else
# Line 2012  Line 2259 
2259                                  }                                  }
2260                                  else                                  else
2261                                  {                                  {
2262                                          if(x1 > x2)                                          gdImageLine(im, x1, y1, x1+3*sx1, y1, colorid);
2263                                          {                                          gdImageLine(im, x2, y2, x2+3*sx2, y2, colorid);
2264                                                  gdImageLine(im, x1, y1, x1-3, y1, colorid);                                          gdImageLine(im, x1+3*sx1, y1, x2+3*sx2, y2, colorid);
                                                 gdImageLine(im, x2, y2, x2+3, y2, colorid);  
                                                 gdImageLine(im, x1-3, y1, x2+3, y2, colorid);  
                                         }  
                                         else  
                                         {  
                                                 gdImageLine(im, x1, y1, x1+3, y1, colorid);  
                                                 gdImageLine(im, x2, y2, x2-3, y2, colorid);  
                                                 gdImageLine(im, x1+3, y1, x2-3, y2, colorid);  
                                         }  
2265                                  }                                  }
2266                          }                          }
2267                  }                  }
# Line 2036  Line 2274 
2274    
2275          for(i = 0; i < nmsg_stack; i++)          for(i = 0; i < nmsg_stack; i++)
2276          {          {
2277                  draw_stringnl(im, msg_stack[i].msg, &conf.msg_font, conf.margin_left, offset, ALIGN_HL|ALIGN_VT, clr(im, "msg_color", NULL, NULL));                  draw_stringnl(im, msg_stack[i].msg, &conf.msg_font, conf.margin_left, offset, ALIGN_HL|ALIGN_VT, clr(im, "msg_color", NULL, NULL, 0));
2278                  offset += msg_stack[i].h;                  offset += msg_stack[i].h;
2279          }          }
2280  }  }
2281    
 static void alloc_color(gdImagePtr im, color_t *c)  
 {  
         c->id = gdImageColorAllocate(im, c->r, c->g, c->b);  
 }  
   
2282  static gdImagePtr make_image(rcsfile_t *rcs)  static gdImagePtr make_image(rcsfile_t *rcs)
2283  {  {
2284          gdImagePtr im;          gdImagePtr im;
2285          int i;          int i;
2286            int bgid;
2287          char *cptr;          char *cptr;
2288          int w, h;          int w, h;
2289          int subx = 0, suby = 0;          int subx = 0, suby = 0;
         int subw, subh;  
2290          int msgh = 0;          int msgh = 0;
2291    
2292          if(subtree_branch)          if(subtree_branch)
2293          {          {
2294                  subw = 0;                  w = 0;
2295                  subh = 0;                  h = 0;
2296                  if(subtree_rev)                  if(subtree_rev)
2297                  {                  {
2298                          for(i = 0; i < subtree_rev->nbranches; i++)                          for(i = 0; i < subtree_rev->nbranches; i++)
2299                                  calc_subtree_size(subtree_rev->branches[i], &subx, &suby, &subw, &subh);                                  calc_subtree_size(subtree_rev->branches[i], &subx, &suby, &w, &h);
2300                  }                  }
2301                  else                  else
2302                          calc_subtree_size(subtree_branch, &subx, &suby, &subw, &subh);                          calc_subtree_size(subtree_branch, &subx, &suby, &w, &h);
2303          }          }
2304          else          else
2305          {          {
2306                  subw = rcs->tw;                  w = rcs->tw;
2307                  subh = rcs->th;                  h = rcs->th;
2308          }          }
2309    
2310          cptr = expand_string(conf.title, rcs, NULL, NULL, NULL, NULL);          cptr = expand_string(conf.title, rcs, NULL, NULL, NULL, NULL);
         w = subw + conf.margin_left + conf.margin_right;  
         h = subh + conf.margin_top + conf.margin_bottom;  
2311          i = get_swidth(cptr, &conf.title_font);          i = get_swidth(cptr, &conf.title_font);
2312          if(i > w)          if(i > w)
2313                  w = i;                  w = i;
# Line 2097  Line 2328 
2328                          w = msgw;                          w = msgw;
2329          }          }
2330    
2331            w += conf.margin_left + conf.margin_right;
2332            h += conf.margin_top + conf.margin_bottom;
2333    
2334          im = gdImageCreate(w, h);          im = gdImageCreate(w, h);
2335          alloc_color(im, &conf.color_bg);        /* The background is always a unique color */          bgid = clr(im, "color_bg", NULL, NULL, 0)->id;  /* The background is always a unique color, */
2336          clr(im, "__black_color__", NULL, NULL);          zap_clr();                                      /* so clear the color ref table */
2337            clr(im, NULL, NULL, NULL, 0);
2338    
2339          if(conf.transparent_bg)          if(conf.transparent_bg)
2340                  gdImageColorTransparent(im, conf.color_bg.id);                  gdImageColorTransparent(im, bgid);
2341    
2342          if(!conf.merge_front)          if(!conf.merge_front)
2343                  draw_merges(im, rcs, 0);                  draw_merges(im, rcs, 0);
# Line 2124  Line 2359 
2359          /* Clear the margins if we have a partial tree */          /* Clear the margins if we have a partial tree */
2360          if(subtree_branch)          if(subtree_branch)
2361          {          {
2362                  gdImageFilledRectangle(im, 0, 0, w-1, conf.margin_top-1, conf.color_bg.id);                  gdImageFilledRectangle(im, 0, 0, w-1, conf.margin_top-1, bgid);
2363                  gdImageFilledRectangle(im, 0, 0, conf.margin_left-1, h-1, conf.color_bg.id);                  gdImageFilledRectangle(im, 0, 0, conf.margin_left-1, h-1, bgid);
2364                  gdImageFilledRectangle(im, 0, h-conf.margin_bottom, w-1, h-1, conf.color_bg.id);                  gdImageFilledRectangle(im, 0, h-conf.margin_bottom, w-1, h-1, bgid);
2365                  gdImageFilledRectangle(im, w-conf.margin_right, 0, w-1, h-1, conf.color_bg.id);                  gdImageFilledRectangle(im, w-conf.margin_right, 0, w-1, h-1, bgid);
2366          }          }
2367    
2368          draw_stringnl(im, cptr, &conf.title_font, conf.title_x, conf.title_y, conf.title_align, clr(im, "title_color", NULL, NULL));          draw_stringnl(im, cptr, &conf.title_font, conf.title_x, conf.title_y, conf.title_align, clr(im, "title_color", NULL, NULL, 0));
2369          xfree(cptr);          xfree(cptr);
2370    
2371          if(conf.merge_front)          if(conf.merge_front)
# Line 2616  Line 2851 
2851          branch_t *b;          branch_t *b;
2852          int i;          int i;
2853          int space;          int space;
2854          int nlinks;          int nlinks = 0;
2855          int dy;          int dy;
2856          int rest;          int rest;
2857    
# Line 2828  Line 3063 
3063                          branch_t *bp = rcs->branches[i];                          branch_t *bp = rcs->branches[i];
3064                          for(j = fr; j < bp->nrevs-1; j++)                          for(j = fr; j < bp->nrevs-1; j++)
3065                          {                          {
3066                                  if(!bp->revs[j]->ntags && bp->revs[j]->stripped >= 0 && !bp->revs[j]->nbranches)                                  if(!bp->revs[j]->ntags && bp->revs[j]->stripped >= 0 && !bp->revs[j]->mergetarget && !bp->revs[j]->nbranches)
3067                                  {                                  {
3068                                          bp->revs[j]->stripped = 1;                                          bp->revs[j+1]->stripped = 1;
3069                                          memmove(&bp->revs[j], &bp->revs[j+1], (bp->nrevs-j-1) * sizeof(bp->revs[0]));                                          memmove(&bp->revs[j], &bp->revs[j+1], (bp->nrevs-j-1) * sizeof(bp->revs[0]));
3070                                          bp->nrevs--;                                          bp->nrevs--;
3071                                          j--;                                          j--;
# Line 2949  Line 3184 
3184                  int w;                  int w;
3185                  int h;                  int h;
3186                  rp = rcs->srev[i];                  rp = rcs->srev[i];
3187                  rp->revtext = expand_string(conf.rev_text, rcs, rp, rp->rev, NULL, rp->ntags ? rp->tags[0] : NULL);                  rp->revtext = expand_string(conf.rev_text.node ? eval_string(conf.rev_text.node, rp) : conf.rev_text.str, rcs, rp, rp->rev, NULL, rp->ntags ? rp->tags[0] : NULL);
3188                    rp->revidtext = expand_string(conf.rev_idtext.node ? eval_string(conf.rev_idtext.node, rp) : conf.rev_idtext.str, rcs, rp, rp->rev, NULL, rp->ntags ? rp->tags[0] : NULL);
3189                  w = get_swidth(rp->revtext, &conf.rev_text_font);                  w = get_swidth(rp->revtext, &conf.rev_text_font);
3190                  j = get_swidth(rp->rev->rev, &conf.rev_font);                  j = get_swidth(rp->revidtext, &conf.rev_font);
3191                  if(j > w)                  if(j > w)
3192                          w = j;                          w = j;
3193                  h = get_sheight(rp->revtext, &conf.rev_text_font);                  h = get_sheight(rp->revtext, &conf.rev_text_font);
3194                  if(!conf.rev_hidenumber)                  if(!conf.rev_hidenumber)
3195                          h += get_sheight(rp->rev->rev, &conf.rev_font);                          h += get_sheight(rp->revidtext, &conf.rev_font);
3196                  for(j = 0; j < rp->ntags; j++)                  for(j = 0; j < rp->ntags; j++)
3197                  {                  {
3198                          int ww = get_swidth(rp->tags[j]->tag, &conf.tag_font);                          int ww = get_swidth(rp->tags[j]->tag, &conf.tag_font);
# Line 3209  Line 3445 
3445    
3446          if(im)          if(im)
3447          {          {
3448                  gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, clr(im, "title_color", NULL, NULL)->id);                  gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, clr(im, "title_color", NULL, NULL, 0)->id);
3449                  gdImageFilledRectangle(im, x2-2, y2-2, x2+2, y2+2, clr(im, "tag_color.id", NULL, NULL)->id);                  gdImageFilledRectangle(im, x2-2, y2-2, x2+2, y2+2, clr(im, "tag_color.id", NULL, NULL, 0)->id);
3450                  gdImageLine(im, x1, y1, x2, y2, clr(im, "title_color", NULL, NULL)->id);                  gdImageLine(im, x1, y1, x2, y2, clr(im, "title_color", NULL, NULL, 0)->id);
3451          }          }
3452  }  }
3453    
# Line 3225  Line 3461 
3461          {          {
3462                  revision_t *fr;                  revision_t *fr;
3463                  revision_t *tr;                  revision_t *tr;
3464                  int x1, x2, y1, y2;                  int x1, x2, y1, y2;             /* Edge position on revision box */
3465                    int sx1, sx2, sy1, sy2;         /* Direction for mergeline -1 = left/up, +1 = right/down */
3466                  switch(rcs->merges[i].type)                  switch(rcs->merges[i].type)
3467                  {                  {
3468                  case TR_TAG:                  case TR_TAG:
# Line 3241  Line 3478 
3478                  }                  }
3479                  if(!fr || !tr || fr == tr)                  if(!fr || !tr || fr == tr)
3480                          continue;       /* This can happen with detached tags and self-references */                          continue;       /* This can happen with detached tags and self-references */
                 if(conf.left_right)  
                 {  
                         if(fr->branch == tr->branch)  
                         {  
                                 y1 = fr->y - fr->h/2;  
                                 y2 = tr->y - tr->h/2;  
                         }  
                         else  
                         {  
                                 if(fr->y < tr->y)  
                                 {  
                                         y1 = fr->y + fr->h/2;  
                                         y2 = tr->y - tr->h/2;  
                                 }  
                                 else  
                                 {  
                                         y1 = fr->y - fr->h/2;  
                                         y2 = tr->y + tr->h/2;  
                                 }  
                         }  
                         x1 = fr->cx + fr->w/2;  
                         x2 = tr->cx + tr->w/2;  
                 }  
                 else  
                 {  
                         if(fr->branch == tr->branch)  
                         {  
                                 x1 = fr->cx - fr->w/2;  
                                 x2 = tr->cx - tr->w/2;  
                         }  
                         else  
                         {  
                                 if(fr->cx < tr->cx)  
                                 {  
                                         x1 = fr->cx + fr->w/2;  
                                         x2 = tr->cx - tr->w/2;  
                                 }  
                                 else  
                                 {  
                                         x1 = fr->cx - fr->w/2;  
                                         x2 = tr->cx + tr->w/2;  
                                 }  
                         }  
                         if(rcs->merges[i].type == TR_TAG)  
                         {  
                                 y1 = fr->y + rcs->merges[i].from.tag->yofs;  
                                 y2 = tr->y + rcs->merges[i].to.tag->yofs;  
                         }  
                         else  
                         {  
                                 y1 = fr->y + fr->h/2;  
                                 y2 = tr->y + tr->h/2;  
                         }  
                 }  
3481    
3482                  if(conf.left_right)                  calc_merge_coords(&rcs->merges[i], fr, tr, &x1, &x2, &y1, &y2, &sx1, &sx2, &sy1, &sy2);
3483    
3484                    if(conf.left_right && !conf.merge_on_tag)
3485                  {                  {
3486                          if(fr->branch == tr->branch)                          if(fr->branch == tr->branch)
3487                          {                          {
# Line 3305  Line 3490 
3490                          }                          }
3491                          else                          else
3492                          {                          {
3493                                  if(y1 > y2)                                  if(sy1 < 0)
                                 {  
3494                                          map_merge_box(rcs, fp, fr, tr, im, x1-bm, y1-bm, x1+bm, y1);                                          map_merge_box(rcs, fp, fr, tr, im, x1-bm, y1-bm, x1+bm, y1);
                                         map_merge_box(rcs, fp, fr, tr, im, x2-bm, y2, x2+bm, y2+bm);  
                                 }  
3495                                  else                                  else
                                 {  
3496                                          map_merge_box(rcs, fp, fr, tr, im, x1-bm, y1, x1+bm, y1+bm);                                          map_merge_box(rcs, fp, fr, tr, im, x1-bm, y1, x1+bm, y1+bm);
3497                                    if(sy2 < 0)
3498                                          map_merge_box(rcs, fp, fr, tr, im, x2-bm, y2-bm, x2+bm, y2);                                          map_merge_box(rcs, fp, fr, tr, im, x2-bm, y2-bm, x2+bm, y2);
3499                                  }                                  else
3500                                            map_merge_box(rcs, fp, fr, tr, im, x2-bm, y2, x2+bm, y2+bm);
3501                          }                          }
3502                  }                  }
3503                  else                  else
# Line 3326  Line 3509 
3509                          }                          }
3510                          else                          else
3511                          {                          {
3512                                  if(x1 > x2)                                  if(sx1 < 0)
                                 {  
3513                                          map_merge_box(rcs, fp, fr, tr, im, x1-bm, y1-tagh2, x1, y1+tagh2);                                          map_merge_box(rcs, fp, fr, tr, im, x1-bm, y1-tagh2, x1, y1+tagh2);
                                         map_merge_box(rcs, fp, fr, tr, im, x2, y2-tagh2, x2+bm, y2+tagh2);  
                                 }  
3514                                  else                                  else
                                 {  
3515                                          map_merge_box(rcs, fp, fr, tr, im, x1, y1-tagh2, x1+bm, y1+tagh2);                                          map_merge_box(rcs, fp, fr, tr, im, x1, y1-tagh2, x1+bm, y1+tagh2);
3516                                    if(sx2 < 0)
3517                                          map_merge_box(rcs, fp, fr, tr, im, x2-bm, y2-tagh2, x2, y2+tagh2);                                          map_merge_box(rcs, fp, fr, tr, im, x2-bm, y2-tagh2, x2, y2+tagh2);
3518                                  }                                  else
3519                                            map_merge_box(rcs, fp, fr, tr, im, x2, y2-tagh2, x2+bm, y2+tagh2);
3520                          }                          }
3521                  }                  }
3522          }          }
# Line 3395  Line 3576 
3576                                          bhref, x1, y1, x2, y2, balt, htp);                                          bhref, x1, y1, x2, y2, balt, htp);
3577                          if(im)                          if(im)
3578                          {                          {
3579                                  gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, clr(im, "title_color", NULL, NULL)->id);                                  gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, clr(im, "title_color", NULL, NULL, 0)->id);
3580                                  gdImageFilledRectangle(im, x2-2, y2-2, x2+2, y2+2, clr(im, "tag_color", NULL, NULL)->id);                                  gdImageFilledRectangle(im, x2-2, y2-2, x2+2, y2+2, clr(im, "tag_color", NULL, NULL, 0)->id);
3581                                  gdImageLine(im, x1, y1, x2, y2, clr(im, "title_color", NULL, NULL)->id);                                  gdImageLine(im, x1, y1, x2, y2, clr(im, "title_color", NULL, NULL, 0)->id);
3582                          }                          }
3583                  }                  }
3584                  else                  else
# Line 3472  Line 3653 
3653                                  href, x1, y1, x2, y2, alt, htp);                                  href, x1, y1, x2, y2, alt, htp);
3654                          if(im)                          if(im)
3655                          {                          {
3656                                  gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, clr(im, "title_color", NULL, NULL)->id);                                  gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, clr(im, "title_color", NULL, NULL, 0)->id);
3657                                  gdImageFilledRectangle(im, x2-2, y2-2, x2+2, y2+2, clr(im, "tag_color", NULL, NULL)->id);                                  gdImageFilledRectangle(im, x2-2, y2-2, x2+2, y2+2, clr(im, "tag_color", NULL, NULL, 0)->id);
3658                                  gdImageLine(im, x1, y1, x2, y2, clr(im, "title_color", NULL, NULL)->id);                                  gdImageLine(im, x1, y1, x2, y2, clr(im, "title_color", NULL, NULL, 0)->id);
3659                          }                          }
3660                          xfree(href);                          xfree(href);
3661                          xfree(alt);                          xfree(alt);
# Line 3542  Line 3723 
3723                                          alt, htp);                                          alt, htp);
3724                                  if(im)                                  if(im)
3725                                  {                                  {
3726                                          gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, clr(im, "title_color", NULL, NULL)->id);                                          gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, clr(im, "title_color", NULL, NULL, 0)->id);
3727                                          gdImageFilledRectangle(im, x2-2, y2-2, x2+2, y2+2, clr(im, "tag_color", NULL, NULL)->id);                                          gdImageFilledRectangle(im, x2-2, y2-2, x2+2, y2+2, clr(im, "tag_color", NULL, NULL, 0)->id);
3728                                          gdImageLine(im, x1, y1, x2, y2, clr(im, "title_color", NULL, NULL)->id);                                          gdImageLine(im, x1, y1, x2, y2, clr(im, "title_color", NULL, NULL, 0)->id);
3729                                  }                                  }
3730                                  xfree(href);                                  xfree(href);
3731                                  xfree(alt);                                  xfree(alt);
# Line 3570  Line 3751 
3751                                          bhref, x1, y1, x2, y2, balt, htp);                                          bhref, x1, y1, x2, y2, balt, htp);
3752                          if(im)                          if(im)
3753                          {                          {
3754                                  gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, clr(im, "title_color", NULL, NULL)->id);                                  gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, clr(im, "title_color", NULL, NULL, 0)->id);
3755                                  gdImageFilledRectangle(im, x2-2, y2-2, x2+2, y2+2, clr(im, "tag_color", NULL, NULL)->id);                                  gdImageFilledRectangle(im, x2-2, y2-2, x2+2, y2+2, clr(im, "tag_color", NULL, NULL, 0)->id);
3756                                  gdImageLine(im, x1, y1, x2, y2, clr(im, "title_color", NULL, NULL)->id);                                  gdImageLine(im, x1, y1, x2, y2, clr(im, "title_color", NULL, NULL, 0)->id);
3757                          }                          }
3758                  }                  }
3759                  xfree(bhref);                  xfree(bhref);
# Line 3612  Line 3793 
3793          "  -[0-9] <txt> Use <txt> for expansion\n"          "  -[0-9] <txt> Use <txt> for expansion\n"
3794          ;          ;
3795    
3796  #define VERSION_STR     "1.5.2"  #define VERSION_STR     "1.6.2"
3797  #define NOTICE_STR      "Copyright (c) 2001,2002,2003,2004 B.Stultiens"  #define NOTICE_STR      "Copyright (c) 2001-2008 B.Stultiens"
3798    
3799  static void append_slash(char **path)  static void append_slash(char **path)
3800  {  {
# Line 3773  Line 3954 
3954          conf.map_diff_alt       = xstrdup("alt=\"%P &lt;-&gt; %R\"");          conf.map_diff_alt       = xstrdup("alt=\"%P &lt;-&gt; %R\"");
3955          conf.map_merge_href     = xstrdup("href=\"unset: conf.map_merge_href\"");          conf.map_merge_href     = xstrdup("href=\"unset: conf.map_merge_href\"");
3956          conf.map_merge_alt      = xstrdup("alt=\"%P &lt;-&gt; %R\"");          conf.map_merge_alt      = xstrdup("alt=\"%P &lt;-&gt; %R\"");
3957          conf.rev_text           = xstrdup("%d");          conf.rev_text.str       = xstrdup("%d");
3958            conf.rev_idtext.str     = xstrdup("%R");
3959          conf.branch_subtree     = xstrdup("");          conf.branch_subtree     = xstrdup("");
3960          conf.tag_ignore         = xstrdup("");          conf.tag_ignore         = xstrdup("");
3961          conf.merge_from         = xstrdup("");          conf.merge_from.n       = 0;
3962          conf.merge_to           = xstrdup("");          conf.merge_from.strs    = NULL;
3963            conf.merge_to.n         = 0;
3964            conf.merge_to.strs      = NULL;
3965          conf.merge_arrows       = 1;          conf.merge_arrows       = 1;
3966            conf.merge_cvsnt        = 1;
3967          conf.arrow_width        = ARROW_WIDTH;          conf.arrow_width        = ARROW_WIDTH;
3968          conf.arrow_length       = ARROW_LENGTH;          conf.arrow_length       = ARROW_LENGTH;
3969    
# Line 3788  Line 3973 
3973          conf.branch_tag_color   = black_color;          conf.branch_tag_color   = black_color;
3974          conf.rev_color          = black_color;          conf.rev_color          = black_color;
3975          conf.rev_bgcolor        = white_color;          conf.rev_bgcolor        = white_color;
3976          conf.merge_color        = black_color;          conf.merge_color.n      = 0;
3977            conf.merge_color.clrs   = NULL;
3978          conf.merge_cvsnt_color  = black_color;          conf.merge_cvsnt_color  = black_color;
3979          conf.tag_color          = black_color;          conf.tag_color          = black_color;
3980          conf.title_color        = black_color;          conf.title_color        = black_color;

Legend:
Removed from v.1.56  
changed lines
  Added in v.1.64

  ViewVC Help
Powered by ViewVC 1.1.0 with CvsGraph 1.7.0