/[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.28, Sat Jul 20 20:41:40 2002 UTC revision 1.34, Mon Mar 17 01:33:44 2003 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  B. Stultiens   * Copyright (C) 2001,2002,2003  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 35  Line 35 
35  #include <ctype.h>  #include <ctype.h>
36  #include <time.h>  #include <time.h>
37  #include <limits.h>  #include <limits.h>
38    #include <regex.h>
39    
40  #ifdef HAVE_GETOPT_H  #ifdef HAVE_GETOPT_H
41  # include <getopt.h>  # include <getopt.h>
# Line 57  Line 58 
58  /*#define NOGDFILL      1*/  /*#define NOGDFILL      1*/
59  /*#define DEBUG_IMAGEMAP        1*/  /*#define DEBUG_IMAGEMAP        1*/
60    
61  #define LOOPSAFEGUARD   100     /* Max itterations in possible infinite loops */  #define LOOPSAFEGUARD   10000   /* Max itterations in possible infinite loops */
62    
63  #ifndef MAX  #ifndef MAX
64  # define MAX(a,b)       ((a) > (b) ? (a) : (b))  # define MAX(a,b)       ((a) > (b) ? (a) : (b))
# Line 87  Line 88 
88  color_t white_color = {255, 255, 255, 0};  color_t white_color = {255, 255, 255, 0};
89  color_t black_color = {0, 0, 0, 0};  color_t black_color = {0, 0, 0, 0};
90    
91    /*
92     **************************************************************************
93     * Forwards
94     **************************************************************************
95     */
96    static void zap_string(void);
97    static char *dup_string(void);
98    static void add_string_str(const char *s);
99    static void add_string_ch(int ch);
100    static void add_string_date(const char *d);
101    static void add_string_str_html(const char *s, int maxlen);
102    static void add_string_str_len(const char *s, int maxlen);
103    
104  /*  /*
105   **************************************************************************   **************************************************************************
# Line 629  Line 642 
642          return r;          return r;
643  }  }
644    
645  int assign_tags(rcsfile_t *rcs)  static char *build_regex(size_t n, regmatch_t *m, const char *ms)
646    {
647            char *cptr;
648            int i;
649    
650            if(!conf.merge_to || !conf.merge_to[0])
651                    return NULL;
652    
653            zap_string();
654            for(cptr = conf.merge_to; *cptr; cptr++)
655            {
656                    if(*cptr == '%')
657                    {
658                            if(cptr[1] >= '1' && cptr[1] <= '9')
659                            {
660                                    int idx = cptr[1] - '0';
661                                    regmatch_t *p = &m[idx];
662                                    if(idx < n && !(p->rm_so == -1 || p->rm_so >= p->rm_eo))
663                                    {
664                                            for(i = p->rm_so; i < p->rm_eo; i++)
665                                            {
666                                                    if(strchr("^$.*+\\[{()", ms[i]))
667                                                            add_string_ch('\\');
668                                                    add_string_ch(ms[i]);
669                                            }
670                                    }
671                                    cptr++;
672                            }
673                            else
674                                    add_string_ch('%');
675                    }
676                    else
677                            add_string_ch(*cptr);
678            }
679            return dup_string();
680    }
681    
682    static void find_merges(rcsfile_t *rcs)
683    {
684            int i;
685            int err;
686            int rcflags = REG_EXTENDED | (conf.merge_nocase ? REG_ICASE : 0);
687            regex_t *refrom = NULL;
688            regex_t *reto = NULL;
689            regmatch_t *matchfrom = NULL;
690    
691            if(!conf.merge_from || !conf.merge_from[0] || !conf.merge_to || !conf.merge_to[0])
692                    return;
693    
694            refrom = xmalloc(sizeof(*refrom));
695            reto = xmalloc(sizeof(*reto));
696    
697            /* Compile the 'from' regex match for merge identification */
698            err = regcomp(refrom, conf.merge_from, rcflags);
699            if(err)
700            {
701                    if(!quiet)
702                    {
703                            char *msg;
704                            i = regerror(err, refrom, NULL, 0);
705                            msg = xmalloc(i+1);
706                            regerror(err, refrom, msg, i+1);
707                            fprintf(stderr, "%s\n", msg);
708                            xfree(msg);
709                    }
710                    xfree(refrom);
711                    xfree(reto);
712                    return;
713            }
714            else
715                    matchfrom = xmalloc((refrom->re_nsub+1) * sizeof(*matchfrom));
716    
717            for(i = 0; i < rcs->tags->ntags; i++)
718            {
719                    tag_t *t = rcs->tags->tags[i];
720    
721                    /* Must be revision tags and not detached */
722                    if(t->rev->isbranch || !t->logrev)
723                            continue;
724    
725                    /* Try to find merge tag matches */
726                    if(!regexec(refrom, t->tag, refrom->re_nsub+1, matchfrom, 0))
727                    {
728                            int n;
729                            char *to;
730    
731                            to = build_regex(refrom->re_nsub+1, matchfrom, t->tag);
732                            if(to)
733                            {
734                                    err = regcomp(reto, to, rcflags);
735                                    if(err && !quiet)
736                                    {
737                                            char *msg;
738                                            i = regerror(err, reto, NULL, 0);
739                                            msg = xmalloc(i+1);
740                                            regerror(err, reto, msg, i+1);
741                                            fprintf(stderr, "%s\n", msg);
742                                    }
743                                    else if(!err)
744                                    {
745                                            for(n = 0; n < rcs->tags->ntags; n++)
746                                            {
747                                                    tag_t *nt = rcs->tags->tags[n];
748                                                    /* From and To never should match the same tag or belong to a branch */
749                                                    if(n == i || nt->rev->isbranch || !nt->logrev)
750                                                            continue;
751    
752                                                    if(!regexec(reto, nt->tag, 0, NULL, REG_NOSUB))
753                                                    {
754                                                            /* Tag matches */
755                                                            rcs->merges = xrealloc(rcs->merges,
756                                                                            sizeof(rcs->merges[0]) * (rcs->nmerges+1));
757                                                            rcs->merges[rcs->nmerges].to = nt;
758                                                            rcs->merges[rcs->nmerges].from = t;
759                                                            rcs->nmerges++;
760                                                            /* We cannot (should not) match multiple times */
761                                                            break;
762                                                    }
763                                            }
764                                            regfree(reto);
765                                    }
766                                    xfree(to);
767                            }
768                    }
769            }
770            if(matchfrom)   xfree(matchfrom);
771            if(refrom)      { regfree(refrom); xfree(refrom); }
772            if(reto)        xfree(reto);
773    }
774    
775    static void assign_tags(rcsfile_t *rcs)
776  {  {
777          int i;          int i;
778          int nr;          int nr;
# Line 724  Line 867 
867                          else                          else
868                          {                          {
869                                  revision_t *rr = *r;                                  revision_t *rr = *r;
870                                    t->logrev = rr;
871                                  if(!conf.rev_maxtags || rr->ntags <= conf.rev_maxtags)                                  if(!conf.rev_maxtags || rr->ntags <= conf.rev_maxtags)
872                                  {                                  {
873                                          rr->tags = xrealloc(rr->tags, (rr->ntags+1)*sizeof(rr->tags[0]));                                          rr->tags = xrealloc(rr->tags, (rr->ntags+1)*sizeof(rr->tags[0]));
# Line 753  Line 897 
897                  *b = rcs->branches[0];                  *b = rcs->branches[0];
898                  rcs->branches[0] = t;                  rcs->branches[0] = t;
899          }          }
         return 1;  
900  }  }
901    
902  /*  /*
# Line 765  Line 908 
908  static int _nstring;  static int _nstring;
909  static int _nastring;  static int _nastring;
910    
911    static void zap_string(void)
912    {
913            _nstring = 0;
914            if(_string)
915                    _string[0] = '\0';
916    }
917    
918    static char *dup_string(void)
919    {
920            if(_string)
921                    return xstrdup(_string);
922            else
923                    return "";
924    }
925    
926  static void add_string_str(const char *s)  static void add_string_str(const char *s)
927  {  {
928          int l = strlen(s) + 1;          int l = strlen(s) + 1;
# Line 837  Line 995 
995                                          cptr += sprintf(cptr, "<br>");                                          cptr += sprintf(cptr, "<br>");
996                          }                          }
997                  }                  }
998                  else if(*s >= 0x7f)                  else if(*s >= 0x7f || *s == '"')
999                          cptr += sprintf(cptr, "&#%d;", (int)(unsigned char)*s);                          cptr += sprintf(cptr, "&#%d;", (int)(unsigned char)*s);
1000                  else if(*s == '<')                  else if(*s == '<')
1001                          cptr += sprintf(cptr, "&lt;");                          cptr += sprintf(cptr, "&lt;");
# Line 868  Line 1026 
1026          char nb[32];          char nb[32];
1027          char nr[32];          char nr[32];
1028          char *base;          char *base;
1029            char *exp;
1030          int l;          int l;
1031          char ch;          char ch;
1032    
1033          if(!s)          if(!s)
1034                  return xstrdup("");                  return xstrdup("");
1035    
1036          _nstring = 0;          zap_string();
         if(_string)  
                 _string[0] = '\0';  
1037    
1038          sprintf(nb, "%d", rcs->nbranches);          sprintf(nb, "%d", rcs->nbranches);
1039          sprintf(nr, "%d", rcs->nsrev);          sprintf(nr, "%d", rcs->nsrev);
# Line 986  Line 1143 
1143                                                  add_string_str_len(r->dtext->log, abs(l));                                                  add_string_str_len(r->dtext->log, abs(l));
1144                                  }                                  }
1145                                  break;                                  break;
1146                            case '(':
1147                                    base = dup_string();
1148                                    exp = expand_string(s+1, rcs, r, rev, prev, tag);
1149                                    zap_string();
1150                                    add_string_str(base);
1151                                    add_string_str_html(exp, 0);
1152                                    xfree(base);
1153                                    xfree(exp);
1154                                    /* Find the %) in this recursion level */
1155                                    for(; *s; s++)
1156                                    {
1157                                            if(*s == '%' && s[1] == ')')
1158                                            {
1159                                                    s++;
1160                                                    break;
1161                                            }
1162                                    }
1163                                    if(!*s)
1164                                    {
1165                                            s--;    /* To end outer loop */
1166                                            if(!quiet)
1167                                                    fprintf(stderr, "string expand: Missing %%) in expansion\n");
1168                                    }
1169                                    break;
1170                            case ')':
1171                                    return dup_string();
1172                          default:                          default:
1173                                  add_string_ch('%');                                  add_string_ch('%');
1174                                  add_string_ch(*s);                                  add_string_ch(*s);
# Line 995  Line 1178 
1178                  else                  else
1179                          add_string_ch(*s);                          add_string_ch(*s);
1180          }          }
1181          return xstrdup(_string);          return dup_string();
1182  }  }
1183    
1184  /*  /*
# Line 1208  Line 1391 
1391          }          }
1392          draw_rbox(im, lx+xp, yp, rx+xp, yp+b->h, 5, &conf.branch_color, &conf.branch_bgcolor);          draw_rbox(im, lx+xp, yp, rx+xp, yp+b->h, 5, &conf.branch_color, &conf.branch_bgcolor);
1393          yy = conf.branch_tspace;          yy = conf.branch_tspace;
1394          draw_string(im, b->branch->branch, &conf.branch_font, x2+xp, yp+yy, ALIGN_HC, &conf.branch_color);          if(!b->nfolds)
1395          yy += get_sheight(b->branch->branch, &conf.branch_font);          {
1396          for(i = 0; i < b->ntags; i++)                  draw_string(im, b->branch->branch, &conf.branch_font, x2+xp, yp+yy, ALIGN_HC, &conf.branch_color);
1397                    yy += get_sheight(b->branch->branch, &conf.branch_font);
1398                    for(i = 0; i < b->ntags; i++)
1399                    {
1400                            draw_string(im, b->tags[i]->tag, &conf.branch_tag_font, x2+xp, yp+yy, ALIGN_HC, &conf.branch_tag_color);
1401                            yy += get_sheight(b->tags[i]->tag, &conf.branch_tag_font);
1402                    }
1403            }
1404            else
1405          {          {
1406                  draw_string(im, b->tags[i]->tag, &conf.branch_tag_font, x2+xp, yp+yy, ALIGN_HC, &conf.branch_tag_color);                  int y1, y2;
1407                  yy += get_sheight(b->tags[i]->tag, &conf.branch_font);                  int tx = lx + b->fw + conf.branch_lspace;
1408                    int nx = tx - get_swidth(" ", &conf.branch_font);
1409                    draw_string(im, b->branch->branch, &conf.branch_font, nx+xp, yp+yy, ALIGN_HR, &conf.branch_color);
1410                    y1 = get_sheight(b->branch->branch, &conf.branch_font);
1411                    draw_string(im, b->tags[0]->tag, &conf.branch_tag_font, tx+xp, yp+yy, ALIGN_HL, &conf.branch_tag_color);
1412                    y2 = get_sheight(b->tags[0]->tag, &conf.branch_font);
1413                    yy += MAX(y1, y2);
1414                    for(i = 0; i < b->nfolds; i++)
1415                    {
1416                            draw_string(im, b->folds[i]->branch->branch, &conf.branch_font, nx+xp, yp+yy, ALIGN_HR, &conf.branch_color);
1417                            y1 = get_sheight(b->folds[i]->branch->branch, &conf.branch_font);
1418                            draw_string(im, b->folds[i]->tags[0]->tag, &conf.branch_tag_font, tx+xp, yp+yy, ALIGN_HL, &conf.branch_tag_color);
1419                            y2 = get_sheight(b->folds[i]->tags[0]->tag, &conf.branch_tag_font);
1420                            yy += MAX(y1, y2);
1421                    }
1422          }          }
1423  }  }
1424    
# Line 1251  Line 1456 
1456                                  draw_rev(im, r);                                  draw_rev(im, r);
1457                                  xx = r->cx;                                  xx = r->cx;
1458                          }                          }
1459                          if(conf.branch_dupbox)                          if(conf.branch_dupbox && b->nrevs)
1460                          {                          {
1461                                  i = b->cx - b->tw + b->w;                                  i = b->cx - b->tw + b->w;
1462                                  gdImageLine(im, xx, b->y, i+b->w, b->y, conf.rev_color.id);                                  gdImageLine(im, xx, b->y, i+b->w, b->y, conf.rev_color.id);
# Line 1281  Line 1486 
1486                                  draw_rev(im, r);                                  draw_rev(im, r);
1487                                  xx = r->cx + r->w;                                  xx = r->cx + r->w;
1488                          }                          }
1489                          if(conf.branch_dupbox)                          if(conf.branch_dupbox && b->nrevs)
1490                          {                          {
1491                                  i = b->cx + b->tw - b->w;                                  i = b->cx + b->tw - b->w;
1492                                  gdImageLine(im, xx, b->y, i, b->y, conf.rev_color.id);                                  gdImageLine(im, xx, b->y, i, b->y, conf.rev_color.id);
# Line 1314  Line 1519 
1519                                  draw_rev(im, r);                                  draw_rev(im, r);
1520                                  yy = r->y;                                  yy = r->y;
1521                          }                          }
1522                          if(conf.branch_dupbox)                          if(conf.branch_dupbox && b->nrevs)
1523                          {                          {
1524                                  i = b->y - b->th + b->h;                                  i = b->y - b->th + b->h;
1525                                  gdImageLine(im, b->cx, yy, b->cx, i, conf.rev_color.id);                                  gdImageLine(im, b->cx, yy, b->cx, i, conf.rev_color.id);
# Line 1344  Line 1549 
1549                                  draw_rev(im, r);                                  draw_rev(im, r);
1550                                  yy = r->y + r->h;                                  yy = r->y + r->h;
1551                          }                          }
1552                          if(conf.branch_dupbox)                          if(conf.branch_dupbox && b->nrevs)
1553                          {                          {
1554                                  i = b->y + b->th - b->h;                                  i = b->y + b->th - b->h;
1555                                  gdImageLine(im, b->cx, yy, b->cx, i, conf.rev_color.id);                                  gdImageLine(im, b->cx, yy, b->cx, i, conf.rev_color.id);
# Line 1399  Line 1604 
1604          }          }
1605  }  }
1606    
1607    static void draw_merges(gdImagePtr im, rcsfile_t *rcs, int dot)
1608    {
1609            int i;
1610            for(i = 0; i < rcs->nmerges; i++)
1611            {
1612                    revision_t *fr = rcs->merges[i].from->logrev;
1613                    revision_t *tr = rcs->merges[i].to->logrev;
1614                    int x1, x2, y1, y2;
1615                    if(!fr || !tr || fr == tr)
1616                            continue;       /* This can happen with detached tags and self-references */
1617                    if(conf.left_right)
1618                    {
1619                            if(fr->branch == tr->branch)
1620                            {
1621                                    y1 = fr->y - fr->h/2;
1622                                    y2 = tr->y - tr->h/2;
1623                            }
1624                            else
1625                            {
1626                                    if(fr->y < tr->y)
1627                                    {
1628                                            y1 = fr->y + fr->h/2;
1629                                            y2 = tr->y - tr->h/2;
1630                                    }
1631                                    else
1632                                    {
1633                                            y1 = fr->y - fr->h/2;
1634                                            y2 = tr->y + tr->h/2;
1635                                    }
1636                            }
1637                            x1 = fr->cx + fr->w/2;
1638                            x2 = tr->cx + tr->w/2;
1639                    }
1640                    else
1641                    {
1642                            if(fr->branch == tr->branch)
1643                            {
1644                                    x1 = fr->cx - fr->w/2;
1645                                    x2 = tr->cx - tr->w/2;
1646                            }
1647                            else
1648                            {
1649                                    if(fr->cx < tr->cx)
1650                                    {
1651                                            x1 = fr->cx + fr->w/2;
1652                                            x2 = tr->cx - tr->w/2;
1653                                    }
1654                                    else
1655                                    {
1656                                            x1 = fr->cx - fr->w/2;
1657                                            x2 = tr->cx + tr->w/2;
1658                                    }
1659                            }
1660                            y1 = fr->y + rcs->merges[i].from->yofs;
1661                            y2 = tr->y + rcs->merges[i].to->yofs;
1662                    }
1663                    if(dot)
1664                    {
1665                            int o = conf.left_right ? 1 : 0;
1666                            gdImageArc(im, x2, y2+o, 8, 8, 0, 360, conf.merge_color.id);
1667                            gdImageFillToBorder(im, x2+1, y2+o+1, conf.merge_color.id, conf.merge_color.id);
1668                    }
1669                    else
1670                    {
1671                            if(conf.left_right)
1672                            {
1673                                    if(fr->branch == tr->branch)
1674                                    {
1675                                            int yy = (y1 < y2 ? y1 : y2) - 5;
1676                                            gdImageLine(im, x1, y1, x1, yy, conf.merge_color.id);
1677                                            gdImageLine(im, x2, y2, x2, yy, conf.merge_color.id);
1678                                            gdImageLine(im, x1, yy, x2, yy, conf.merge_color.id);
1679                                    }
1680                                    else
1681                                    {
1682                                            if(y1 > y2)
1683                                            {
1684                                                    gdImageLine(im, x1, y1, x1, y1-3, conf.merge_color.id);
1685                                                    gdImageLine(im, x2, y2+1, x2, y2+3+1, conf.merge_color.id);
1686                                                    gdImageLine(im, x1, y1-3, x2, y2+3+1, conf.merge_color.id);
1687                                            }
1688                                            else
1689                                            {
1690                                                    gdImageLine(im, x1, y1+1, x1, y1+3+1, conf.merge_color.id);
1691                                                    gdImageLine(im, x2, y2, x2, y2-3, conf.merge_color.id);
1692                                                    gdImageLine(im, x1, y1+3+1, x2, y2-3, conf.merge_color.id);
1693                                            }
1694                                    }
1695                            }
1696                            else
1697                            {
1698                                    if(fr->branch == tr->branch)
1699                                    {
1700                                            int xx = (x1 < x2 ? x1 : x2) - 5;
1701                                            gdImageLine(im, xx, y1, x1, y1, conf.merge_color.id);
1702                                            gdImageLine(im, xx, y2, x2, y2, conf.merge_color.id);
1703                                            gdImageLine(im, xx, y1, xx, y2, conf.merge_color.id);
1704                                    }
1705                                    else
1706                                    {
1707                                            if(x1 > x2)
1708                                            {
1709                                                    gdImageLine(im, x1, y1, x1-3, y1, conf.merge_color.id);
1710                                                    gdImageLine(im, x2, y2, x2+3, y2, conf.merge_color.id);
1711                                                    gdImageLine(im, x1-3, y1, x2+3, y2, conf.merge_color.id);
1712                                            }
1713                                            else
1714                                            {
1715                                                    gdImageLine(im, x1, y1, x1+3, y1, conf.merge_color.id);
1716                                                    gdImageLine(im, x2, y2, x2-3, y2, conf.merge_color.id);
1717                                                    gdImageLine(im, x1+3, y1, x2-3, y2, conf.merge_color.id);
1718                                            }
1719                                    }
1720                            }
1721                    }
1722            }
1723    }
1724    
1725  static void alloc_color(gdImagePtr im, color_t *c)  static void alloc_color(gdImagePtr im, color_t *c)
1726  {  {
1727          c->id = gdImageColorAllocate(im, c->r, c->g, c->b);          c->id = gdImageColorAllocate(im, c->r, c->g, c->b);
# Line 1424  Line 1747 
1747          alloc_color(im, &conf.branch_tag_color);          alloc_color(im, &conf.branch_tag_color);
1748          alloc_color(im, &conf.branch_bgcolor);          alloc_color(im, &conf.branch_bgcolor);
1749          alloc_color(im, &conf.title_color);          alloc_color(im, &conf.title_color);
1750            alloc_color(im, &conf.merge_color);
1751          alloc_color(im, &black_color);          alloc_color(im, &black_color);
1752          alloc_color(im, &white_color);          alloc_color(im, &white_color);
1753    
1754          if(conf.transparent_bg)          if(conf.transparent_bg)
1755                  gdImageColorTransparent(im, conf.color_bg.id);                  gdImageColorTransparent(im, conf.color_bg.id);
1756    
1757            if(!conf.merge_front)
1758                    draw_merges(im, rcs, 0);
1759    
1760          for(i = 0; i < rcs->nbranches; i++)          for(i = 0; i < rcs->nbranches; i++)
1761                  draw_branch(im, rcs->branches[i]);          {
1762                    if(!rcs->branches[i]->folded)
1763                            draw_branch(im, rcs->branches[i]);
1764            }
1765    
1766            draw_merges(im, rcs, 1);        /* The dots of the merge dest */
1767    
1768          for(i = 0; i < rcs->nbranches; i++)          for(i = 0; i < rcs->nbranches; i++)
1769          {          {
1770                  if(rcs->branches[i]->branchpoint)                  if(rcs->branches[i]->branchpoint)
# Line 1440  Line 1773 
1773          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);
1774          xfree(cptr);          xfree(cptr);
1775    
1776            if(conf.merge_front)
1777                    draw_merges(im, rcs, 0);
1778    
1779          return im;          return im;
1780  }  }
1781    
# Line 1526  Line 1862 
1862                  /* Recurse to move branches of branched revisions */                  /* Recurse to move branches of branched revisions */
1863                  for(i = b->nrevs-1; i >= 0; i--)                  for(i = b->nrevs-1; i >= 0; i--)
1864                  {                  {
1865                          initial_reposition_branch(b->revs[i], y, h);                          initial_reposition_branch_lr(b->revs[i], y, h);
1866                  }                  }
1867          }          }
1868  }  }
# Line 1681  Line 2017 
2017          if(l)   *l = br->cx - br->tw/2;          if(l)   *l = br->cx - br->tw/2;
2018          if(r)   *r = br->cx + br->tw/2;          if(r)   *r = br->cx + br->tw/2;
2019          if(t)   *t = br->y;          if(t)   *t = br->y;
2020          if(b)   *b = br->y + br->th + (conf.branch_dupbox ? conf.rev_minline + br->h : 0);          if(b)   *b = br->y + br->th + ((conf.branch_dupbox && br->nrevs) ? conf.rev_minline + br->h : 0);
2021  }  }
2022    
2023  static void branch_ext_bbox(branch_t *br, int *l, int *r, int *t, int *b)  static void branch_ext_bbox(branch_t *br, int *l, int *r, int *t, int *b)
# Line 2038  Line 2374 
2374                  fprintf(stderr, "auto_stretch: safeguard terminated possible infinite loop; please report.\n");                  fprintf(stderr, "auto_stretch: safeguard terminated possible infinite loop; please report.\n");
2375  }  }
2376    
2377    static void fold_branch(rcsfile_t *rcs, revision_t *r)
2378    {
2379            int i, j;
2380            branch_t *btag = NULL;
2381    
2382            if(r->nbranches < 2)
2383                    return;         /* Should not happen... */
2384    
2385            for(i = 0; i < r->nbranches; i++)
2386            {
2387                    branch_t *b = r->branches[i];
2388                    if(!b->nrevs && b->ntags < 2)
2389                    {
2390                            /* No commits in this branch and no duplicate tags */
2391                            if(!btag)
2392                                    btag = b;
2393                            else
2394                            {
2395                                    /* We have consecutive empty branches, fold */
2396                                    b->folded = 1;
2397                                    for(j = 0; j < rcs->nbranches; j++)
2398                                    {
2399                                            if(b == rcs->branches[j])
2400                                            {
2401                                                    /* Zap the branch from the admin */
2402                                                    memmove(&rcs->branches[j],
2403                                                            &rcs->branches[j+1],
2404                                                            (rcs->nbranches - j - 1)*sizeof(rcs->branches[0]));
2405                                                    rcs->nbranches--;
2406                                                    break;
2407                                            }
2408    
2409                                    }
2410                                    memmove(&r->branches[i], &r->branches[i+1], (r->nbranches - i - 1)*sizeof(r->branches[0]));
2411                                    r->nbranches--;
2412                                    i--;    /* We have one less now */
2413    
2414                                    /* Add to the fold-list */
2415                                    btag->folds = xrealloc(btag->folds, (btag->nfolds+1) * sizeof(btag->folds[0]));
2416                                    btag->folds[btag->nfolds] = b;
2417                                    btag->nfolds++;
2418                            }
2419                    }
2420                    else
2421                    {
2422                            if(!conf.branch_foldall)
2423                                    btag = NULL;    /* Start a new box */
2424                            /* Recursively fold sub-branches */
2425                            for(j = 0; j < b->nrevs; j++)
2426                                    fold_branch(rcs, b->revs[j]);
2427                    }
2428            }
2429    }
2430    
2431  void make_layout(rcsfile_t *rcs)  void make_layout(rcsfile_t *rcs)
2432  {  {
2433          int i, j;          int i, j;
# Line 2065  Line 2455 
2455                  }                  }
2456          }          }
2457    
2458            /* Fold all empty branched in one box on the same branchpoint */
2459            if(conf.branch_fold)
2460            {
2461                    for(i = 0; i < rcs->branches[0]->nrevs; i++)
2462                    {
2463                            if(rcs->branches[0]->revs[i]->nbranches > 1)
2464                                    fold_branch(rcs, rcs->branches[0]->revs[i]);
2465                    }
2466            }
2467    
2468          /* Calculate the box-sizes of the revisions */          /* Calculate the box-sizes of the revisions */
2469          for(i = 0; i < rcs->nsrev; i++)          for(i = 0; i < rcs->nsrev; i++)
2470          {          {
# Line 2081  Line 2481 
2481                  for(j = 0; j < rp->ntags; j++)                  for(j = 0; j < rp->ntags; j++)
2482                  {                  {
2483                          int ww = get_swidth(rp->tags[j]->tag, &conf.tag_font);                          int ww = get_swidth(rp->tags[j]->tag, &conf.tag_font);
2484                            int th;
2485                          if(ww > w) w = ww;                          if(ww > w) w = ww;
2486                          h += get_sheight(rp->tags[j]->tag, &conf.tag_font) + conf.rev_separator;                          th = get_sheight(rp->tags[j]->tag, &conf.tag_font) + conf.rev_separator;
2487                            rp->tags[j]->yofs = h + th/2 + conf.rev_tspace;
2488                            h += th;
2489                  }                  }
2490                  rp->w = w + conf.rev_lspace + conf.rev_rspace;                  rp->w = w + conf.rev_lspace + conf.rev_rspace;
2491                  rp->h = h + conf.rev_tspace + conf.rev_bspace;                  rp->h = h + conf.rev_tspace + conf.rev_bspace;
# Line 2094  Line 2497 
2497                  branch_t *bp = rcs->branches[i];                  branch_t *bp = rcs->branches[i];
2498                  int w;                  int w;
2499                  int h;                  int h;
2500                  w = get_swidth(bp->branch->branch, &conf.branch_font);                  if(!bp->nfolds)
                 h = get_sheight(bp->branch->branch, &conf.branch_font);  
                 for(j = 0; j < bp->ntags; j++)  
2501                  {                  {
2502                          int ww = get_swidth(bp->tags[j]->tag, &conf.branch_tag_font);                          w = get_swidth(bp->branch->branch, &conf.branch_font);
2503                          if(ww > w) w = ww;                          h = get_sheight(bp->branch->branch, &conf.branch_font);
2504                          h += get_sheight(bp->tags[j]->tag, &conf.branch_tag_font);                          for(j = 0; j < bp->ntags; j++)
2505                            {
2506                                    int ww = get_swidth(bp->tags[j]->tag, &conf.branch_tag_font);
2507                                    if(ww > w) w = ww;
2508                                    h += get_sheight(bp->tags[j]->tag, &conf.branch_tag_font);
2509                            }
2510                    }
2511                    else
2512                    {
2513                            int h1, h2;
2514                            int w1, w2;
2515                            int fw;
2516                            w1 = get_swidth(bp->branch->branch, &conf.branch_font);
2517                            w1 += get_swidth(" ", &conf.branch_font);
2518                            w2 = get_swidth(bp->tags[0]->tag, &conf.branch_tag_font);
2519                            fw = w1;
2520                            w = w1 + w2;
2521                            h1 = get_sheight(bp->branch->branch, &conf.branch_font);
2522                            h2 = get_sheight(bp->tags[0]->tag, &conf.branch_tag_font);
2523                            h = MAX(h1, h2);
2524                            for(j = 0; j < bp->nfolds; j++)
2525                            {
2526                                    w1 = get_swidth(bp->folds[j]->branch->branch, &conf.branch_font);
2527                                    w1 += get_swidth(" ", &conf.branch_font);
2528                                    w2 = get_swidth(bp->folds[j]->tags[0]->tag, &conf.branch_tag_font);
2529                                    if(w1 > fw)
2530                                            fw = w1;
2531                                    if(w1 + w2 > w)
2532                                            w = w1 + w2;
2533                                    h1 = get_sheight(bp->folds[j]->branch->branch, &conf.branch_font);
2534                                    h2 = get_sheight(bp->folds[j]->tags[0]->tag, &conf.branch_tag_font);
2535                                    h += MAX(h1, h2);
2536                            }
2537                            bp->fw = fw;
2538                  }                  }
2539                  w += conf.branch_lspace + conf.branch_rspace;                  w += conf.branch_lspace + conf.branch_rspace;
2540                  h += conf.branch_tspace + conf.branch_bspace;                  h += conf.branch_tspace + conf.branch_bspace;
# Line 2114  Line 2548 
2548                                          h = bp->revs[j]->h;                                          h = bp->revs[j]->h;
2549                                  w += bp->revs[j]->w + conf.rev_minline;                                  w += bp->revs[j]->w + conf.rev_minline;
2550                          }                          }
2551                          if(conf.branch_dupbox)                          if(conf.branch_dupbox && bp->nrevs)
2552                                  w += bp->w + conf.rev_minline;                                  w += bp->w + conf.rev_minline;
2553                  }                  }
2554                  else                  else
# Line 2125  Line 2559 
2559                                          w = bp->revs[j]->w;                                          w = bp->revs[j]->w;
2560                                  h += bp->revs[j]->h + conf.rev_minline;                                  h += bp->revs[j]->h + conf.rev_minline;
2561                          }                          }
2562                          if(conf.branch_dupbox)                          if(conf.branch_dupbox && bp->nrevs)
2563                                  h += bp->h + conf.rev_minline;                                  h += bp->h + conf.rev_minline;
2564                  }                  }
2565                  bp->th = h;                  bp->th = h;
# Line 2261  Line 2695 
2695  void make_imagemap(rcsfile_t *rcs, FILE *fp, gdImagePtr im)  void make_imagemap(rcsfile_t *rcs, FILE *fp, gdImagePtr im)
2696  {  {
2697          int i, j;          int i, j;
2698          fprintf(fp, "<map name=\"%s\">\n", conf.map_name);          const char *htp = conf.html_level == HTMLLEVEL_X ? " /" : "";
2699    
2700            switch(conf.html_level)
2701            {
2702            case HTMLLEVEL_4:
2703                    fprintf(fp, "<map name=\"%s\" id=\"%s\">\n", conf.map_name, conf.map_name);
2704                    break;
2705            case HTMLLEVEL_X:
2706                    fprintf(fp, "<map id=\"%s\">\n", conf.map_name);
2707                    break;
2708            default:
2709                    fprintf(fp, "<map name=\"%s\">\n", conf.map_name);
2710            }
2711    
2712          for(i = 0; i < rcs->nbranches; i++)          for(i = 0; i < rcs->nbranches; i++)
2713          {          {
2714                  branch_t *b = rcs->branches[i];                  branch_t *b = rcs->branches[i];
# Line 2273  Line 2720 
2720                  int y1;                  int y1;
2721                  int y2;                  int y2;
2722    
2723                  if(conf.left_right)                  if(!b->nfolds)
2724                  {                  {
2725                          x1 = b->cx;                          if(conf.left_right)
2726                          y1 = b->y - b->h/2;                          {
2727                          x2 = b->cx + b->w;                                  x1 = b->cx;
2728                          y2 = b->y + b->h/2;                                  y1 = b->y - b->h/2;
2729                                    x2 = b->cx + b->w;
2730                                    y2 = b->y + b->h/2;
2731                            }
2732                            else
2733                            {
2734                                    x1 = b->cx - b->w/2;
2735                                    y1 = b->y;
2736                                    x2 = b->cx + b->w/2;
2737                                    y2 = b->y + b->h;
2738                            }
2739                            fprintf(fp, "\t<area shape=\"rect\" %s coords=\"%d,%d,%d,%d\" %s%s>\n",
2740                                            bhref, x1, y1, x2, y2, balt, htp);
2741                            if(im)
2742                            {
2743                                    gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, conf.title_color.id);
2744                                    gdImageFilledRectangle(im, x2-2, y2-2, x2+2, y2+2, conf.tag_color.id);
2745                                    gdImageLine(im, x1, y1, x2, y2, conf.title_color.id);
2746                            }
2747                  }                  }
2748                  else                  else
2749                  {                  {
2750                          x1 = b->cx - b->w/2;                          int yy1, yy2, yy;
2751                          y1 = b->y;                          if(conf.left_right)
2752                          x2 = b->cx + b->w/2;                          {
2753                          y2 = b->y + b->h;                                  x1 = b->cx + conf.branch_lspace;
2754                  }                                  y1 = b->y - b->h/2 + conf.branch_tspace;
2755                  fprintf(fp, "\t<area shape=\"rect\" %s coords=\"%d,%d,%d,%d\" %s>\n",                          }
2756                                  bhref, x1, y1, x2, y2, balt);                          else
2757                  if(im)                          {
2758                  {                                  x1 = b->cx - b->w/2 + conf.branch_lspace;
2759                          gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, conf.title_color.id);                                  y1 = b->y + conf.branch_tspace;
2760                          gdImageFilledRectangle(im, x2-2, y2-2, x2+2, y2+2, conf.tag_color.id);                          }
2761                          gdImageLine(im, x1, y1, x2, y2, conf.title_color.id);                          x2 = x1 + b->w - conf.branch_rspace;
2762    
2763                            yy1 = get_sheight(b->branch->branch, &conf.branch_font);
2764                            yy2 = get_sheight(b->tags[0]->tag, &conf.branch_tag_font);
2765                            yy = MAX(yy1, yy2);
2766                            y2 = y1 + yy;
2767                            fprintf(fp, "\t<area shape=\"rect\" %s coords=\"%d,%d,%d,%d\" %s%s>\n",
2768                                            bhref, x1, y1, x2, y2, balt, htp);
2769    
2770                            y1 += yy;
2771                            y2 += yy;
2772                            for(j = 0; j < b->nfolds; j++)
2773                            {
2774                                    branch_t *fb = b->folds[j];
2775                                    tag_t *t = fb->tags[0];
2776                                    xfree(bhref);
2777                                    xfree(balt);
2778                                    bhref = expand_string(conf.map_branch_href, rcs, NULL, fb->branch, NULL, t);
2779                                    balt = expand_string(conf.map_branch_alt, rcs, NULL, fb->branch, NULL, t);
2780                                    fprintf(fp, "\t<area shape=\"rect\" %s coords=\"%d,%d,%d,%d\" %s%s>\n",
2781                                                    bhref, x1, y1, x2, y2, balt, htp);
2782                                    yy1 = get_sheight(fb->branch->branch, &conf.branch_font);
2783                                    yy2 = get_sheight(fb->tags[0]->tag, &conf.branch_tag_font);
2784                                    yy = MAX(yy1, yy2);
2785                                    y1 += yy;
2786                                    y2 += yy;
2787                            }
2788                  }                  }
2789    
2790                  for(j = 0; j < b->nrevs; j++)                  for(j = 0; j < b->nrevs; j++)
2791                  {                  {
2792                          revision_t *r = b->revs[j];                          revision_t *r = b->revs[j];
# Line 2321  Line 2813 
2813                                  x2 = r->cx + r->w/2;                                  x2 = r->cx + r->w/2;
2814                                  y2 = r->y + r->h;                                  y2 = r->y + r->h;
2815                          }                          }
2816                          fprintf(fp, "\t<area shape=\"rect\" %s coords=\"%d,%d,%d,%d\" %s>\n",                          fprintf(fp, "\t<area shape=\"rect\" %s coords=\"%d,%d,%d,%d\" %s%s>\n",
2817                                  href, x1, y1, x2, y2, alt);                                  href, x1, y1, x2, y2, alt, htp);
2818                          if(im)                          if(im)
2819                          {                          {
2820                                  gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, conf.title_color.id);                                  gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, conf.title_color.id);
# Line 2389  Line 2881 
2881                                  }                                  }
2882                                  href = expand_string(conf.map_diff_href, rcs, r, r->rev, r1->rev, tag);                                  href = expand_string(conf.map_diff_href, rcs, r, r->rev, r1->rev, tag);
2883                                  alt = expand_string(conf.map_diff_alt, rcs, r, r->rev, r1->rev, tag);                                  alt = expand_string(conf.map_diff_alt, rcs, r, r->rev, r1->rev, tag);
2884                                  fprintf(fp, "\t<area shape=\"rect\" %s coords=\"%d,%d,%d,%d\" %s>\n",                                  fprintf(fp, "\t<area shape=\"rect\" %s coords=\"%d,%d,%d,%d\" %s%s>\n",
2885                                          href,                                          href,
2886                                          x1+xoff, y1+yoff, x2-xoff, y2-yoff,                                          x1+xoff, y1+yoff, x2-xoff, y2-yoff,
2887                                          alt);                                          alt, htp);
2888                                  if(im)                                  if(im)
2889                                  {                                  {
2890                                          gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, conf.title_color.id);                                          gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, conf.title_color.id);
# Line 2403  Line 2895 
2895                                  xfree(alt);                                  xfree(alt);
2896                          }                          }
2897                  }                  }
2898                  if(conf.branch_dupbox)                  if(conf.branch_dupbox && b->nrevs)
2899                  {                  {
2900                          if(conf.left_right)                          if(conf.left_right)
2901                          {                          {
# Line 2419  Line 2911 
2911                                  x2 = b->cx + b->w/2;                                  x2 = b->cx + b->w/2;
2912                                  y2 = y1 + b->h;                                  y2 = y1 + b->h;
2913                          }                          }
2914                          fprintf(fp, "\t<area shape=\"rect\" %s coords=\"%d,%d,%d,%d\" %s>\n",                          fprintf(fp, "\t<area shape=\"rect\" %s coords=\"%d,%d,%d,%d\" %s%s>\n",
2915                                          bhref, x1, y1, x2, y2, balt);                                          bhref, x1, y1, x2, y2, balt, htp);
2916                          if(im)                          if(im)
2917                          {                          {
2918                                  gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, conf.title_color.id);                                  gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, conf.title_color.id);
# Line 2458  Line 2950 
2950          "  -S           Also strip the first revision (config value is negated)\n"          "  -S           Also strip the first revision (config value is negated)\n"
2951          "  -u           Upside down image (mirror vertically; config value is negated)\n"          "  -u           Upside down image (mirror vertically; config value is negated)\n"
2952          "  -V           Print version and exit\n"          "  -V           Print version and exit\n"
2953            "  -x [34x]     Specify level of HTML 3.2 (default), 4.0 or XHTML\n"
2954          "  -[0-9] <txt> Use <txt> for expansion\n"          "  -[0-9] <txt> Use <txt> for expansion\n"
2955          ;          ;
2956    
2957  #define VERSION_STR     "1.3.0"  #define VERSION_STR     "1.4.0"
2958  #define NOTICE_STR      "Copyright (c) 2001,2002 B.Stultiens"  #define NOTICE_STR      "Copyright (c) 2001,2002,2003 B.Stultiens"
2959    
2960  static void append_slash(char **path)  static void append_slash(char **path)
2961  {  {
# Line 2491  Line 2984 
2984          int stripuntag = 0;          int stripuntag = 0;
2985          int stripfirst = 0;          int stripfirst = 0;
2986          int autostretch = 0;          int autostretch = 0;
2987            int htmllevel = 0;
2988          char *imgmapname = NULL;          char *imgmapname = NULL;
2989          char *imgmapfile = NULL;          char *imgmapfile = NULL;
2990          int lose = 0;          int lose = 0;
# Line 2499  Line 2993 
2993          rcsfile_t *rcs;          rcsfile_t *rcs;
2994          gdImagePtr im;          gdImagePtr im;
2995    
2996          while((optc = getopt(argc, argv, "0:1:2:3:4:5:6:7:8:9:bc:d:hI:ikM:m:O:o:qr:SsuV")) != EOF)          while((optc = getopt(argc, argv, "0:1:2:3:4:5:6:7:8:9:bc:d:hI:ikM:m:O:o:qr:SsuVx:")) != EOF)
2997          {          {
2998                  switch(optc)                  switch(optc)
2999                  {                  {
# Line 2551  Line 3045 
3045                  case 'V':                  case 'V':
3046                          fprintf(stdout, "cvsgraph v%s, %s\n", VERSION_STR, NOTICE_STR);                          fprintf(stdout, "cvsgraph v%s, %s\n", VERSION_STR, NOTICE_STR);
3047                          return 0;                          return 0;
3048                    case 'x':
3049                            switch(optarg[0])
3050                            {
3051                            case '3':
3052                                    htmllevel = HTMLLEVEL_3;
3053                                    break;
3054                            case '4':
3055                                    htmllevel = HTMLLEVEL_4;
3056                                    break;
3057                            case 'x':
3058                                    htmllevel = HTMLLEVEL_X;
3059                                    break;
3060                            default:
3061                                    fprintf(stderr, "Invalid HTML level in -x\n");
3062                                    lose++;
3063                            }
3064                            break;
3065                  case 'h':                  case 'h':
3066                          fprintf(stdout, "%s", usage_str);                          fprintf(stdout, "%s", usage_str);
3067                          return 0;                          return 0;
# Line 2588  Line 3099 
3099    
3100          conf.anti_alias         = 1;          conf.anti_alias         = 1;
3101          conf.thick_lines        = 1;          conf.thick_lines        = 1;
3102            conf.branch_fold        = 1;
3103    
3104          conf.cvsroot            = xstrdup("");          conf.cvsroot            = xstrdup("");
3105          conf.cvsmodule          = xstrdup("");          conf.cvsmodule          = xstrdup("");
# Line 2601  Line 3113 
3113          conf.map_diff_href      = xstrdup("href=\"unset: conf.map_diff_href\"");          conf.map_diff_href      = xstrdup("href=\"unset: conf.map_diff_href\"");
3114          conf.map_diff_alt       = xstrdup("alt=\"%P &lt;-&gt; %R\"");          conf.map_diff_alt       = xstrdup("alt=\"%P &lt;-&gt; %R\"");
3115          conf.rev_text           = xstrdup("%d");          conf.rev_text           = xstrdup("%d");
3116            conf.merge_from         = xstrdup("");
3117            conf.merge_to           = xstrdup("");
3118    
3119          conf.color_bg           = white_color;          conf.color_bg           = white_color;
3120          conf.branch_bgcolor     = white_color;          conf.branch_bgcolor     = white_color;
# Line 2608  Line 3122 
3122          conf.branch_tag_color   = black_color;          conf.branch_tag_color   = black_color;
3123          conf.rev_color          = black_color;          conf.rev_color          = black_color;
3124          conf.rev_bgcolor        = white_color;          conf.rev_bgcolor        = white_color;
3125            conf.merge_color        = black_color;
3126          conf.tag_color          = black_color;          conf.tag_color          = black_color;
3127          conf.title_color        = black_color;          conf.title_color        = black_color;
3128          conf.rev_text_color     = black_color;          conf.rev_text_color     = black_color;
# Line 2628  Line 3143 
3143          if(stripuntag)  conf.strip_untagged = !conf.strip_untagged;          if(stripuntag)  conf.strip_untagged = !conf.strip_untagged;
3144          if(stripfirst)  conf.strip_first_rev = !conf.strip_first_rev;          if(stripfirst)  conf.strip_first_rev = !conf.strip_first_rev;
3145          if(autostretch) conf.auto_stretch = !conf.auto_stretch;          if(autostretch) conf.auto_stretch = !conf.auto_stretch;
3146            if(htmllevel)   conf.html_level = htmllevel;
3147    
3148          if(conf.rev_minline >= conf.rev_maxline)          if(conf.rev_minline >= conf.rev_maxline)
3149          {          {
# Line 2669  Line 3185 
3185          if(!reorganise_branches(rcs))          if(!reorganise_branches(rcs))
3186                  return 1;                  return 1;
3187    
3188          if(!assign_tags(rcs))          assign_tags(rcs);
3189                  return 1;          find_merges(rcs);
3190    
3191          if(outfile)          if(outfile)
3192          {          {

Legend:
Removed from v.1.28  
changed lines
  Added in v.1.34

  ViewVC Help
Powered by ViewVC 1.1.0 with CvsGraph 1.7.0