/[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.23, Tue Jul 16 09:30:34 2002 UTC revision 1.30, Sun Mar 9 22:36:50 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 55  Line 56 
56    
57  /*#define DEBUG         1*/  /*#define DEBUG         1*/
58  /*#define NOGDFILL      1*/  /*#define NOGDFILL      1*/
59    /*#define DEBUG_IMAGEMAP        1*/
60    
61  #define LOOPSAFEGUARD   100     /* Max itterations in possible infinite loops */  #define LOOPSAFEGUARD   100     /* Max itterations in possible infinite loops */
62    
# Line 86  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 628  Line 642 
642          return r;          return r;
643  }  }
644    
645    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  int assign_tags(rcsfile_t *rcs)  int assign_tags(rcsfile_t *rcs)
683  {  {
684          int i;          int i;
685          int nr;          int nr;
686            int err;
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            {
693                    refrom = xmalloc(sizeof(*refrom));
694                    reto = xmalloc(sizeof(*reto));
695    
696                    /* Compile the 'from' regex match for merge identification */
697                    err = regcomp(refrom, conf.merge_from, REG_EXTENDED | (conf.merge_nocase ? REG_ICASE : 0));
698                    if(err)
699                    {
700                            if(!quiet)
701                            {
702                                    char *msg;
703                                    i = regerror(err, refrom, NULL, 0);
704                                    msg = xmalloc(i+1);
705                                    regerror(err, refrom, msg, i+1);
706                                    fprintf(stderr, "%s\n", msg);
707                                    xfree(msg);
708                            }
709                            xfree(refrom);
710                            xfree(reto);
711                            refrom = NULL;
712                            reto = NULL;
713                    }
714                    else
715                            matchfrom = xmalloc((refrom->re_nsub+1) * sizeof(*matchfrom));
716            }
717    
718          for(i = nr = 0; i < rcs->nbranches; i++)          for(i = nr = 0; i < rcs->nbranches; i++)
719                  nr += rcs->branches[i]->nrevs;                  nr += rcs->branches[i]->nrevs;
# Line 723  Line 805 
805                          else                          else
806                          {                          {
807                                  revision_t *rr = *r;                                  revision_t *rr = *r;
808                                  rr->tags = xrealloc(rr->tags, (rr->ntags+1)*sizeof(rr->tags[0]));                                  t->logrev = rr;
809                                  rr->tags[rr->ntags] = t;                                  if(!conf.rev_maxtags || rr->ntags <= conf.rev_maxtags)
810                                  rr->ntags++;                                  {
811                                            rr->tags = xrealloc(rr->tags, (rr->ntags+1)*sizeof(rr->tags[0]));
812                                            if(conf.rev_maxtags && rr->ntags == conf.rev_maxtags)
813                                            {
814                                                    rr->tags[rr->ntags] = xmalloc(sizeof(tag_t));
815                                                    rr->tags[rr->ntags]->tag = xstrdup("...");
816                                                    rr->tags[rr->ntags]->rev = t->rev;
817                                            }
818                                            else
819                                                    rr->tags[rr->ntags] = t;
820                                            rr->ntags++;
821                                    }
822    
823                                    /* Try to find merge tag matches */
824                                    if(refrom && !regexec(refrom, t->tag, refrom->re_nsub+1, matchfrom, 0))
825                                    {
826                                            int n;
827                                            char *to;
828    
829                                            to = build_regex(refrom->re_nsub+1, matchfrom, t->tag);
830                                            if(to)
831                                            {
832                                                    err = regcomp(reto, to, REG_EXTENDED | (conf.merge_nocase ? REG_ICASE : 0));
833                                                    if(err && !quiet)
834                                                    {
835                                                            char *msg;
836                                                            i = regerror(err, reto, NULL, 0);
837                                                            msg = xmalloc(i+1);
838                                                            regerror(err, reto, msg, i+1);
839                                                            fprintf(stderr, "%s\n", msg);
840                                                    }
841                                                    else if(!err)
842                                                    {
843                                                            for(n = 0; n < rcs->tags->ntags; n++)
844                                                            {
845                                                                    /* From and To never should match the same tag */
846                                                                    if(n == i)
847                                                                            continue;
848    
849                                                                    if(!regexec(reto, rcs->tags->tags[n]->tag, 0, NULL, REG_NOSUB))
850                                                                    {
851                                                                            /* Tag matches */
852                                                                            rcs->merges = xrealloc(rcs->merges,
853                                                                                            sizeof(rcs->merges[0]) * (rcs->nmerges+1));
854                                                                            rcs->merges[rcs->nmerges].to = rcs->tags->tags[n];
855                                                                            rcs->merges[rcs->nmerges].from = t;
856                                                                            rcs->nmerges++;
857                                                                            /* We cannot (should not) match multiple times */
858                                                                            n = rcs->tags->ntags;
859                                                                    }
860                                                            }
861                                                            regfree(reto);
862                                                    }
863                                                    xfree(to);
864                                            }
865                                    }
866                          }                          }
867                  }                  }
868          }          }
# Line 742  Line 879 
879                  *b = rcs->branches[0];                  *b = rcs->branches[0];
880                  rcs->branches[0] = t;                  rcs->branches[0] = t;
881          }          }
882            if(matchfrom)   xfree(matchfrom);
883            if(refrom)      { regfree(refrom); xfree(refrom); }
884            if(reto)        xfree(reto);
885          return 1;          return 1;
886  }  }
887    
# Line 754  Line 894 
894  static int _nstring;  static int _nstring;
895  static int _nastring;  static int _nastring;
896    
897    static void zap_string(void)
898    {
899            _nstring = 0;
900            if(_string)
901                    _string[0] = '\0';
902    }
903    
904    static char *dup_string(void)
905    {
906            if(_string)
907                    return xstrdup(_string);
908            else
909                    return "";
910    }
911    
912  static void add_string_str(const char *s)  static void add_string_str(const char *s)
913  {  {
914          int l = strlen(s) + 1;          int l = strlen(s) + 1;
915          if(_nstring + l > _nastring)          if(_nstring + l > _nastring)
916          {          {
917                  _nastring += 128;                  _nastring += MAX(128, l);
918                  _string = xrealloc(_string, _nastring * sizeof(_string[0]));                  _string = xrealloc(_string, _nastring * sizeof(_string[0]));
919          }          }
920          memcpy(_string+_nstring, s, l);          memcpy(_string+_nstring, s, l);
# Line 826  Line 981 
981                                          cptr += sprintf(cptr, "<br>");                                          cptr += sprintf(cptr, "<br>");
982                          }                          }
983                  }                  }
984                  else if(*s >= 0x7f)                  else if(*s >= 0x7f || *s == '"')
985                          cptr += sprintf(cptr, "&#%d;", (int)(unsigned char)*s);                          cptr += sprintf(cptr, "&#%d;", (int)(unsigned char)*s);
986                  else if(*s == '<')                  else if(*s == '<')
987                          cptr += sprintf(cptr, "&lt;");                          cptr += sprintf(cptr, "&lt;");
# Line 857  Line 1012 
1012          char nb[32];          char nb[32];
1013          char nr[32];          char nr[32];
1014          char *base;          char *base;
1015            char *exp;
1016          int l;          int l;
1017          char ch;          char ch;
1018    
1019          if(!s)          if(!s)
1020                  return xstrdup("");                  return xstrdup("");
1021    
1022          _nstring = 0;          zap_string();
         if(_string)  
                 _string[0] = '\0';  
1023    
1024          sprintf(nb, "%d", rcs->nbranches);          sprintf(nb, "%d", rcs->nbranches);
1025          sprintf(nr, "%d", rcs->nsrev);          sprintf(nr, "%d", rcs->nsrev);
# Line 975  Line 1129 
1129                                                  add_string_str_len(r->dtext->log, abs(l));                                                  add_string_str_len(r->dtext->log, abs(l));
1130                                  }                                  }
1131                                  break;                                  break;
1132                            case '(':
1133                                    base = dup_string();
1134                                    exp = expand_string(s+1, rcs, r, rev, prev, tag);
1135                                    zap_string();
1136                                    add_string_str(base);
1137                                    add_string_str_html(exp, 0);
1138                                    xfree(base);
1139                                    xfree(exp);
1140                                    /* Find the %) in this recursion level */
1141                                    for(; *s; s++)
1142                                    {
1143                                            if(*s == '%' && s[1] == ')')
1144                                                    break;
1145                                    }
1146                                    if(!*s)
1147                                    {
1148                                            s--;    /* To end outer loop */
1149                                            if(!quiet)
1150                                                    fprintf(stderr, "string expand: Missing %%) in expansion\n");
1151                                    }
1152                                    break;
1153                            case ')':
1154                                    return dup_string();
1155                          default:                          default:
1156                                  add_string_ch('%');                                  add_string_ch('%');
1157                                  add_string_ch(*s);                                  add_string_ch(*s);
# Line 984  Line 1161 
1161                  else                  else
1162                          add_string_ch(*s);                          add_string_ch(*s);
1163          }          }
1164          return xstrdup(_string);          return dup_string();
1165  }  }
1166    
1167  /*  /*
# Line 1142  Line 1319 
1319    
1320  static void draw_rev(gdImagePtr im, revision_t *r)  static void draw_rev(gdImagePtr im, revision_t *r)
1321  {  {
1322          int lx = r->cx - r->w/2;          int lx;
1323          int rx = lx + r->w;          int rx;
1324            int x2;
1325          int i;          int i;
1326          int ty = r->y;          int ty;
1327    
1328            if(conf.left_right)
1329            {
1330                    lx = r->cx;
1331                    rx = r->cx + r->w;
1332                    ty = r->y - r->h/2;
1333                    x2 = r->cx + r->w/2;
1334            }
1335            else
1336            {
1337                    lx = r->cx - r->w/2;
1338                    rx = lx + r->w;
1339                    ty = r->y;
1340                    x2 = r->cx;
1341            }
1342          draw_rbox(im, lx, ty, rx, ty+r->h, 0, &conf.rev_color, &conf.rev_bgcolor);          draw_rbox(im, lx, ty, rx, ty+r->h, 0, &conf.rev_color, &conf.rev_bgcolor);
1343          ty += conf.rev_tspace;          ty += conf.rev_tspace;
1344          draw_string(im, r->rev->rev, &conf.rev_font, r->cx, ty, ALIGN_HC, &conf.rev_color);          draw_string(im, r->rev->rev, &conf.rev_font, x2, ty, ALIGN_HC, &conf.rev_color);
1345          ty += get_sheight(r->rev->rev, &conf.rev_font);          ty += get_sheight(r->rev->rev, &conf.rev_font);
1346          draw_stringnl(im, r->revtext, &conf.rev_text_font, r->cx, ty, ALIGN_HC, &conf.rev_text_color);          draw_stringnl(im, r->revtext, &conf.rev_text_font, x2, ty, ALIGN_HC, &conf.rev_text_color);
1347          ty += get_sheight(r->revtext, &conf.rev_text_font);          ty += get_sheight(r->revtext, &conf.rev_text_font);
1348          for(i = 0; i < r->ntags; i++)          for(i = 0; i < r->ntags; i++)
1349          {          {
1350                  draw_string(im, r->tags[i]->tag, &conf.tag_font, r->cx, ty, ALIGN_HC, &conf.tag_color);                  draw_string(im, r->tags[i]->tag, &conf.tag_font, x2, ty, ALIGN_HC, &conf.tag_color);
1351                  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;
1352          }          }
1353  }  }
1354    
1355  static void draw_branch_box(gdImagePtr im, branch_t *b, int ypos)  static void draw_branch_box(gdImagePtr im, branch_t *b, int xp, int yp)
1356  {  {
1357          int lx = b->cx - b->w/2;          int lx;
1358          int rx = lx + b->w;          int rx;
1359          int i;          int i;
1360          int yy;          int yy;
1361            int x2;
1362    
1363          draw_rbox(im, lx, ypos, rx, ypos+b->h, 5, &conf.branch_color, &conf.branch_bgcolor);          if(conf.left_right)
1364            {
1365                    lx = b->cx;
1366                    rx = lx + b->w;
1367                    x2 = b->cx + b->w/2;
1368            }
1369            else
1370            {
1371                    lx = b->cx - b->w/2;
1372                    rx = lx + b->w;
1373                    x2 = b->cx;
1374            }
1375            draw_rbox(im, lx+xp, yp, rx+xp, yp+b->h, 5, &conf.branch_color, &conf.branch_bgcolor);
1376          yy = conf.branch_tspace;          yy = conf.branch_tspace;
1377          draw_string(im, b->branch->branch, &conf.branch_font, b->cx, ypos+yy, ALIGN_HC, &conf.branch_color);          draw_string(im, b->branch->branch, &conf.branch_font, x2+xp, yp+yy, ALIGN_HC, &conf.branch_color);
1378          yy += get_sheight(b->branch->branch, &conf.branch_font);          yy += get_sheight(b->branch->branch, &conf.branch_font);
1379          for(i = 0; i < b->ntags; i++)          for(i = 0; i < b->ntags; i++)
1380          {          {
1381                  draw_string(im, b->tags[i]->tag, &conf.branch_tag_font, b->cx, ypos+yy, ALIGN_HC, &conf.branch_tag_color);                  draw_string(im, b->tags[i]->tag, &conf.branch_tag_font, x2+xp, yp+yy, ALIGN_HC, &conf.branch_tag_color);
1382                  yy += get_sheight(b->tags[i]->tag, &conf.branch_font);                  yy += get_sheight(b->tags[i]->tag, &conf.branch_font);
1383          }          }
1384  }  }
1385    
1386  static void draw_branch(gdImagePtr im, branch_t *b)  static void draw_branch(gdImagePtr im, branch_t *b)
1387  {  {
1388          int yy;          int yy, xx;
1389          int i;          int i;
1390          int line[4];          int line[4];
1391          int l;          int l;
# Line 1190  Line 1396 
1396          line[1] = gdTransparent;          line[1] = gdTransparent;
1397          line[3] = conf.rev_color.id;          line[3] = conf.rev_color.id;
1398    
1399          draw_branch_box(im, b, b->y);          draw_branch_box(im, b, 0, conf.left_right ? b->y - b->h/2 : b->y);
1400    
1401          if(conf.upside_down)          if(conf.left_right)
1402          {          {
1403                  yy = b->y;                  if(conf.upside_down)
                 for(i = 0; i < b->nrevs; i++)  
1404                  {                  {
1405                          revision_t *r = b->revs[i];                          xx = b->cx;
1406                          gdImageSetStyle(im, line, r->stripped ? 4 : 1);                          for(i = 0; i < b->nrevs; i++)
1407                          gdImageLine(im, r->cx, yy, r->cx, r->y+r->h, gdStyled);                          {
1408                          for(sign = l = 1; l < conf.thick_lines; l++)                                  revision_t *r = b->revs[i];
1409                          {                                  gdImageSetStyle(im, line, r->stripped ? 4 : 1);
1410                                  int pp = (l+1)/2*sign;                                  gdImageLine(im, xx, r->y, r->cx+r->w, r->y, gdStyled);
1411                                  gdImageLine(im, r->cx+pp, yy, r->cx+pp, r->y+r->h, gdStyled);                                  for(sign = l = 1; l < conf.thick_lines; l++)
1412                                  sign *= -1;                                  {
1413                                            int pp = (l+1)/2*sign;
1414                                            gdImageLine(im, xx, r->y+pp, r->cx+r->w, r->y+pp, gdStyled);
1415                                            sign *= -1;
1416                                    }
1417                                    draw_rev(im, r);
1418                                    xx = r->cx;
1419                            }
1420                            if(conf.branch_dupbox)
1421                            {
1422                                    i = b->cx - b->tw + b->w;
1423                                    gdImageLine(im, xx, b->y, i+b->w, b->y, conf.rev_color.id);
1424                                    for(sign = l = 1; l < conf.thick_lines; l++)
1425                                    {
1426                                            int pp = (l+1)/2*sign;
1427                                            gdImageLine(im, xx, b->y+pp, i+b->w, b->y+pp, conf.rev_color.id);
1428                                            sign *= -1;
1429                                    }
1430                                    draw_branch_box(im, b, i - b->cx, b->y - b->h/2);
1431                          }                          }
                         draw_rev(im, r);  
                         yy = r->y;  
1432                  }                  }
1433                  if(conf.branch_dupbox)                  else
1434                  {                  {
1435                          i = b->y - b->th + b->h;                          xx = b->cx + b->w;
1436                          gdImageLine(im, b->cx, yy, b->cx, i, conf.rev_color.id);                          for(i = 0; i < b->nrevs; i++)
                         for(sign = l = 1; l < conf.thick_lines; l++)  
1437                          {                          {
1438                                  int pp = (l+1)/2*sign;                                  revision_t *r = b->revs[i];
1439                                  gdImageLine(im, b->cx+pp, yy, b->cx+pp, i, conf.rev_color.id);                                  gdImageSetStyle(im, line, r->stripped ? 4 : 1);
1440                                  sign *= -1;                                  gdImageLine(im, xx, r->y, r->cx, r->y, gdStyled);
1441                                    for(sign = l = 1; l < conf.thick_lines; l++)
1442                                    {
1443                                            int pp = (l+1)/2*sign;
1444                                            gdImageLine(im, xx, r->y+pp, r->cx, r->y+pp, gdStyled);
1445                                            sign *= -1;
1446                                    }
1447                                    draw_rev(im, r);
1448                                    xx = r->cx + r->w;
1449                            }
1450                            if(conf.branch_dupbox)
1451                            {
1452                                    i = b->cx + b->tw - b->w;
1453                                    gdImageLine(im, xx, b->y, i, b->y, conf.rev_color.id);
1454                                    for(sign = l = 1; l < conf.thick_lines; l++)
1455                                    {
1456                                            int pp = (l+1)/2*sign;
1457                                            gdImageLine(im, xx, b->y+pp, i, b->y+pp, conf.rev_color.id);
1458                                            sign *= -1;
1459                                    }
1460                                    draw_branch_box(im, b, i - b->cx, b->y - b->h/2);
1461                          }                          }
                         draw_branch_box(im, b, i);  
1462                  }                  }
1463          }          }
1464          else          else
1465          {          {
1466                  yy = b->y + b->h;                  if(conf.upside_down)
                 for(i = 0; i < b->nrevs; i++)  
1467                  {                  {
1468                          revision_t *r = b->revs[i];                          yy = b->y;
1469                          gdImageSetStyle(im, line, r->stripped ? 4 : 1);                          for(i = 0; i < b->nrevs; i++)
1470                          gdImageLine(im, r->cx, yy, r->cx, r->y, gdStyled);                          {
1471                          for(sign = l = 1; l < conf.thick_lines; l++)                                  revision_t *r = b->revs[i];
1472                                    gdImageSetStyle(im, line, r->stripped ? 4 : 1);
1473                                    gdImageLine(im, r->cx, yy, r->cx, r->y+r->h, gdStyled);
1474                                    for(sign = l = 1; l < conf.thick_lines; l++)
1475                                    {
1476                                            int pp = (l+1)/2*sign;
1477                                            gdImageLine(im, r->cx+pp, yy, r->cx+pp, r->y+r->h, gdStyled);
1478                                            sign *= -1;
1479                                    }
1480                                    draw_rev(im, r);
1481                                    yy = r->y;
1482                            }
1483                            if(conf.branch_dupbox)
1484                          {                          {
1485                                  int pp = (l+1)/2*sign;                                  i = b->y - b->th + b->h;
1486                                  gdImageLine(im, r->cx+pp, yy, r->cx+pp, r->y, gdStyled);                                  gdImageLine(im, b->cx, yy, b->cx, i, conf.rev_color.id);
1487                                  sign *= -1;                                  for(sign = l = 1; l < conf.thick_lines; l++)
1488                                    {
1489                                            int pp = (l+1)/2*sign;
1490                                            gdImageLine(im, b->cx+pp, yy, b->cx+pp, i, conf.rev_color.id);
1491                                            sign *= -1;
1492                                    }
1493                                    draw_branch_box(im, b, 0, i);
1494                          }                          }
                         draw_rev(im, r);  
                         yy = r->y + r->h;  
1495                  }                  }
1496                  if(conf.branch_dupbox)                  else
1497                  {                  {
1498                          i = b->y + b->th - b->h;                          yy = b->y + b->h;
1499                          gdImageLine(im, b->cx, yy, b->cx, i, conf.rev_color.id);                          for(i = 0; i < b->nrevs; i++)
1500                          for(sign = l = 1; l < conf.thick_lines; l++)                          {
1501                          {                                  revision_t *r = b->revs[i];
1502                                  int pp = (l+1)/2*sign;                                  gdImageSetStyle(im, line, r->stripped ? 4 : 1);
1503                                  gdImageLine(im, b->cx+pp, yy, b->cx+pp, i, conf.rev_color.id);                                  gdImageLine(im, r->cx, yy, r->cx, r->y, gdStyled);
1504                                  sign *= -1;                                  for(sign = l = 1; l < conf.thick_lines; l++)
1505                                    {
1506                                            int pp = (l+1)/2*sign;
1507                                            gdImageLine(im, r->cx+pp, yy, r->cx+pp, r->y, gdStyled);
1508                                            sign *= -1;
1509                                    }
1510                                    draw_rev(im, r);
1511                                    yy = r->y + r->h;
1512                            }
1513                            if(conf.branch_dupbox)
1514                            {
1515                                    i = b->y + b->th - b->h;
1516                                    gdImageLine(im, b->cx, yy, b->cx, i, conf.rev_color.id);
1517                                    for(sign = l = 1; l < conf.thick_lines; l++)
1518                                    {
1519                                            int pp = (l+1)/2*sign;
1520                                            gdImageLine(im, b->cx+pp, yy, b->cx+pp, i, conf.rev_color.id);
1521                                            sign *= -1;
1522                                    }
1523                                    draw_branch_box(im, b, 0, i);
1524                          }                          }
                         draw_branch_box(im, b, i);  
1525                  }                  }
1526          }          }
1527  }  }
# Line 1263  Line 1535 
1535          int y1 = r->y + r->h/2;          int y1 = r->y + r->h/2;
1536          int x2 = b->cx;          int x2 = b->cx;
1537          int y2 = b->y;          int y2 = b->y;
1538          if(conf.upside_down)  
1539                  y2 += b->h;          if(conf.left_right)
1540            {
1541                    x2 = r->cx + r->w/2;
1542                    y2 = r->y + r->h/2 + 3;
1543                    x1 = b->cx;
1544                    y1 = b->y;
1545                    if(conf.upside_down)
1546                            x1 += b->w;
1547            }
1548            else
1549            {
1550                    x1 = r->cx + r->w/2 + 2;
1551                    y1 = r->y + r->h/2;
1552                    x2 = b->cx;
1553                    y2 = b->y;
1554                    if(conf.upside_down)
1555                            y2 += b->h;
1556            }
1557          gdImageLine(im, x1, y1, x2, y1, conf.branch_color.id);          gdImageLine(im, x1, y1, x2, y1, conf.branch_color.id);
1558          gdImageLine(im, x2, y1, x2, y2, conf.branch_color.id);          gdImageLine(im, x2, y1, x2, y2, conf.branch_color.id);
1559          for(sign = l = 1; l < conf.thick_lines; l++)          for(sign = l = 1; l < conf.thick_lines; l++)
1560          {          {
1561                  int pp = (l+1)/2*sign;                  int pp = (l+1)/2*sign;
1562                  gdImageLine(im, x1, y1+pp, x2-pp, y1+pp, conf.branch_color.id);                  gdImageLine(im, x1, y1+pp, x2, y1+pp, conf.branch_color.id);
1563                  gdImageLine(im, x2+pp, y1-pp, x2+pp, y2, conf.branch_color.id);                  gdImageLine(im, x2+pp, y1, x2+pp, y2, conf.branch_color.id);
1564                  sign *= -1;                  sign *= -1;
1565          }          }
1566  }  }
1567    
1568    static void draw_merges(gdImagePtr im, rcsfile_t *rcs)
1569    {
1570            int i;
1571            for(i = 0; i < rcs->nmerges; i++)
1572            {
1573                    revision_t *fr = rcs->merges[i].from->logrev;
1574                    revision_t *tr = rcs->merges[i].to->logrev;
1575                    int x1, x2, y1, y2;
1576                    if(!fr || !tr)
1577                            continue;       /* This can happen with detached tags */
1578                    if(conf.left_right)
1579                    {
1580                            if(fr->y < tr->y)
1581                            {
1582                                    y1 = fr->y + fr->h/2;
1583                                    y2 = tr->y - tr->h/2;
1584                            }
1585                            else
1586                            {
1587                                    y1 = fr->y - fr->h/2;
1588                                    y2 = tr->y + tr->h/2;
1589                            }
1590                            x1 = fr->cx + fr->w/2;
1591                            x2 = tr->cx + tr->w/2;
1592                    }
1593                    else
1594                    {
1595                            if(fr->cx < tr->cx)
1596                            {
1597                                    x1 = fr->cx + fr->w/2;
1598                                    x2 = tr->cx - tr->w/2;
1599                            }
1600                            else
1601                            {
1602                                    x1 = fr->cx - fr->w/2;
1603                                    x2 = tr->cx + tr->w/2;
1604                            }
1605                            y1 = fr->y + fr->h/2;
1606                            y2 = tr->y + tr->h/2;
1607                    }
1608                    gdImageArc(im, x2, y2, 8, 8, 0, 360, conf.merge_color.id);
1609                    gdImageFillToBorder(im, x2, y2, conf.merge_color.id, conf.merge_color.id);
1610                    if(conf.left_right)
1611                    {
1612                            if(y1 > y2)
1613                            {
1614                                    gdImageLine(im, x1, y1, x1, y1-3, conf.merge_color.id);
1615                                    gdImageLine(im, x2, y2+1, x2, y2+3+1, conf.merge_color.id);
1616                                    gdImageLine(im, x1, y1-3, x2, y2+3+1, conf.merge_color.id);
1617                            }
1618                            else
1619                            {
1620                                    gdImageLine(im, x1, y1+1, x1, y1+3+1, conf.merge_color.id);
1621                                    gdImageLine(im, x2, y2, x2, y2-3, conf.merge_color.id);
1622                                    gdImageLine(im, x1, y1+3+1, x2, y2-3, conf.merge_color.id);
1623                            }
1624                    }
1625                    else
1626                    {
1627                            if(x1 > x2)
1628                            {
1629                                    gdImageLine(im, x1, y1, x1-3, y1, conf.merge_color.id);
1630                                    gdImageLine(im, x2, y2, x2+3, y2, conf.merge_color.id);
1631                                    gdImageLine(im, x1-3, y1, x2+3, y2, conf.merge_color.id);
1632                            }
1633                            else
1634                            {
1635                                    gdImageLine(im, x1, y1, x1+3, y1, conf.merge_color.id);
1636                                    gdImageLine(im, x2, y2, x2-3, y2, conf.merge_color.id);
1637                                    gdImageLine(im, x1+3, y1, x2-3, y2, conf.merge_color.id);
1638                            }
1639                    }
1640            }
1641    }
1642    
1643  static void alloc_color(gdImagePtr im, color_t *c)  static void alloc_color(gdImagePtr im, color_t *c)
1644  {  {
1645          c->id = gdImageColorAllocate(im, c->r, c->g, c->b);          c->id = gdImageColorAllocate(im, c->r, c->g, c->b);
# Line 1301  Line 1665 
1665          alloc_color(im, &conf.branch_tag_color);          alloc_color(im, &conf.branch_tag_color);
1666          alloc_color(im, &conf.branch_bgcolor);          alloc_color(im, &conf.branch_bgcolor);
1667          alloc_color(im, &conf.title_color);          alloc_color(im, &conf.title_color);
1668            alloc_color(im, &conf.merge_color);
1669          alloc_color(im, &black_color);          alloc_color(im, &black_color);
1670          alloc_color(im, &white_color);          alloc_color(im, &white_color);
1671    
1672          if(conf.transparent_bg)          if(conf.transparent_bg)
1673                  gdImageColorTransparent(im, conf.color_bg.id);                  gdImageColorTransparent(im, conf.color_bg.id);
1674    
1675            if(!conf.merge_front)
1676                    draw_merges(im, rcs);
1677    
1678          for(i = 0; i < rcs->nbranches; i++)          for(i = 0; i < rcs->nbranches; i++)
1679                  draw_branch(im, rcs->branches[i]);                  draw_branch(im, rcs->branches[i]);
1680          for(i = 0; i < rcs->nbranches; i++)          for(i = 0; i < rcs->nbranches; i++)
# Line 1317  Line 1685 
1685          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);
1686          xfree(cptr);          xfree(cptr);
1687    
1688            if(conf.merge_front)
1689                    draw_merges(im, rcs);
1690    
1691          return im;          return im;
1692  }  }
1693    
# Line 1390  Line 1761 
1761          }          }
1762  }  }
1763    
1764    static void initial_reposition_branch_lr(revision_t *r, int *y, int *h)
1765    {
1766            int i, j;
1767            for(j = 0; j < r->nbranches; j++)
1768            {
1769                    branch_t *b = r->branches[j];
1770                    *y += *h + conf.rev_minline + b->th/2 - b->y;
1771                    *h = b->th/2;
1772                    move_branch(b, r->cx + r->w/2 + conf.branch_connect, *y);
1773                    *y = b->y;
1774                    /* Recurse to move branches of branched revisions */
1775                    for(i = b->nrevs-1; i >= 0; i--)
1776                    {
1777                            initial_reposition_branch(b->revs[i], y, h);
1778                    }
1779            }
1780    }
1781    
1782  static void rect_union(int *x, int *y, int *w, int *h, branch_t *b)  static void rect_union(int *x, int *y, int *w, int *h, branch_t *b)
1783  {  {
1784          int x1 = *x;          int x1 = *x;
1785          int x2 = x1 + *w;          int x2 = x1 + *w;
1786          int y1 = *y;          int y1 = *y;
1787          int y2 = y1 + *h;          int y2 = y1 + *h;
1788          int xx1 = b->cx - b->tw/2;          int xx1;
1789          int xx2 = xx1 + b->tw;          int xx2;
1790          int yy1 = b->y;          int yy1;
1791          int yy2 = yy1 + b->th;          int yy2;
1792    
1793            if(conf.left_right)
1794            {
1795                    xx1 = b->cx;
1796                    yy1 = b->y - b->th/2;
1797            }
1798            else
1799            {
1800                    xx1 = b->cx - b->tw/2;
1801                    yy1 = b->y;
1802            }
1803            xx2 = xx1 + b->tw;
1804            yy2 = yy1 + b->th;
1805    
1806          x1 = MIN(x1, xx1);          x1 = MIN(x1, xx1);
1807          x2 = MAX(x2, xx2);          x2 = MAX(x2, xx2);
1808          y1 = MIN(y1, yy1);          y1 = MIN(y1, yy1);
# Line 1418  Line 1821 
1821          return !(bt > bottom || bb < top || br >= left);          return !(bt > bottom || bb < top || br >= left);
1822  }  }
1823    
1824    static int branch_intersects_lr(int left, int right, int top, branch_t *b)
1825    {
1826            int bt = b->y + b->th/2;
1827            int bl = b->cx - conf.branch_connect - conf.branch_margin/2;
1828            int br = b->cx + b->tw + conf.branch_margin/2;
1829            return !(bl > right || br < left || bt >= top);
1830    }
1831    
1832  static int kern_branch(rcsfile_t *rcs, branch_t *b)  static int kern_branch(rcsfile_t *rcs, branch_t *b)
1833  {  {
1834          int left = b->cx - b->tw/2;          int left = b->cx - b->tw/2;
# Line 1446  Line 1857 
1857          return 0;          return 0;
1858  }  }
1859    
1860    static int kern_branch_lr(rcsfile_t *rcs, branch_t *b)
1861    {
1862            int top = b->y - b->th/2;
1863            int left = b->cx - conf.branch_connect - conf.branch_margin/2;
1864            int right = b->cx + b->tw + conf.branch_margin/2;
1865            int i;
1866            int ypos = 0;
1867    
1868            for(i = 0; i < rcs->nbranches; i++)
1869            {
1870                    branch_t *bp = rcs->branches[i];
1871                    if(bp == b)
1872                            continue;
1873                    if(branch_intersects_lr(left, right, top, bp))
1874                    {
1875                            int m = bp->y + bp->th/2 + conf.branch_margin;
1876                            if(m > ypos)
1877                                    ypos = m;
1878                    }
1879            }
1880            if(ypos && (b->y - b->th/2) - ypos > 0)
1881            {
1882                    move_branch(b, 0, ypos - (b->y - b->th/2));
1883                    return 1;
1884            }
1885            return 0;
1886    }
1887    
1888  static int kern_tree(rcsfile_t *rcs)  static int kern_tree(rcsfile_t *rcs)
1889  {  {
1890          int i;          int i;
# Line 1457  Line 1896 
1896                  moved = 0;                  moved = 0;
1897                  for(i = 1; i < rcs->nbranches; i++)                  for(i = 1; i < rcs->nbranches; i++)
1898                  {                  {
1899                          moved += kern_branch(rcs, rcs->branches[i]);                          if(conf.left_right)
1900                                    moved += kern_branch_lr(rcs, rcs->branches[i]);
1901                            else
1902                                    moved += kern_branch(rcs, rcs->branches[i]);
1903                  }                  }
1904                  totalmoved += moved;                  totalmoved += moved;
1905  #ifdef DEBUG  #ifdef DEBUG
# Line 1912  Line 2354 
2354                  h += conf.branch_tspace + conf.branch_bspace;                  h += conf.branch_tspace + conf.branch_bspace;
2355                  bp->w = w;                  bp->w = w;
2356                  bp->h = h;                  bp->h = h;
2357                  for(j = 0; j < bp->nrevs; j++)                  if(conf.left_right)
2358                    {
2359                            for(j = 0; j < bp->nrevs; j++)
2360                            {
2361                                    if(bp->revs[j]->h > h)
2362                                            h = bp->revs[j]->h;
2363                                    w += bp->revs[j]->w + conf.rev_minline;
2364                            }
2365                            if(conf.branch_dupbox)
2366                                    w += bp->w + conf.rev_minline;
2367                    }
2368                    else
2369                  {                  {
2370                          if(bp->revs[j]->w > w)                          for(j = 0; j < bp->nrevs; j++)
2371                                  w = bp->revs[j]->w;                          {
2372                          h += bp->revs[j]->h + conf.rev_minline;                                  if(bp->revs[j]->w > w)
2373                                            w = bp->revs[j]->w;
2374                                    h += bp->revs[j]->h + conf.rev_minline;
2375                            }
2376                            if(conf.branch_dupbox)
2377                                    h += bp->h + conf.rev_minline;
2378                  }                  }
                 if(conf.branch_dupbox)  
                         h += bp->h + conf.rev_minline;  
2379                  bp->th = h;                  bp->th = h;
2380                  bp->tw = w;                  bp->tw = w;
2381          }          }
2382    
2383          /* Calculate the relative positions of revs in a branch */          /* Calculate the relative positions of revs in a branch */
2384          for(i = 0; i < rcs->nbranches; i++)          if(conf.left_right)
2385          {          {
2386                  branch_t *b = rcs->branches[i];                  for(i = 0; i < rcs->nbranches; i++)
2387                  x = b->tw/2;                  {
2388                  y = b->h;                          branch_t *b = rcs->branches[i];
2389                  b->cx = x;                          y = b->th/2;
2390                  b->y = 0;                          x = b->w;
2391                  for(j = 0; j < b->nrevs; j++)                          b->y = y;
2392                            b->cx = 0;
2393                            for(j = 0; j < b->nrevs; j++)
2394                            {
2395                                    x += conf.rev_minline;
2396                                    b->revs[j]->y = y;
2397                                    b->revs[j]->cx = x;
2398                                    x += b->revs[j]->w;
2399                            }
2400                    }
2401            }
2402            else
2403            {
2404                    for(i = 0; i < rcs->nbranches; i++)
2405                  {                  {
2406                          y += conf.rev_minline;                          branch_t *b = rcs->branches[i];
2407                          b->revs[j]->cx = x;                          x = b->tw/2;
2408                          b->revs[j]->y = y;                          y = b->h;
2409                          y += b->revs[j]->h;                          b->cx = x;
2410                            b->y = 0;
2411                            for(j = 0; j < b->nrevs; j++)
2412                            {
2413                                    y += conf.rev_minline;
2414                                    b->revs[j]->cx = x;
2415                                    b->revs[j]->y = y;
2416                                    y += b->revs[j]->h;
2417                            }
2418                  }                  }
2419          }          }
2420    
2421          /* Initially reposition the branches from bottom to top progressively right */          /* Initially reposition the branches from bottom to top progressively right */
2422          x = rcs->branches[0]->cx;          if(conf.left_right)
2423          w2 = rcs->branches[0]->tw / 2;          {
2424          for(i = rcs->branches[0]->nrevs-1; i >= 0; i--)                  x = rcs->branches[0]->y;
2425                    w2 = rcs->branches[0]->th / 2;
2426                    for(i = rcs->branches[0]->nrevs-1; i >= 0; i--)
2427                    {
2428                            initial_reposition_branch_lr(rcs->branches[0]->revs[i], &x, &w2);
2429                    }
2430            }
2431            else
2432          {          {
2433                  initial_reposition_branch(rcs->branches[0]->revs[i], &x, &w2);                  x = rcs->branches[0]->cx;
2434                    w2 = rcs->branches[0]->tw / 2;
2435                    for(i = rcs->branches[0]->nrevs-1; i >= 0; i--)
2436                    {
2437                            initial_reposition_branch(rcs->branches[0]->revs[i], &x, &w2);
2438                    }
2439          }          }
2440    
2441          /* Initially move branches left if there is room */          /* Initially move branches left if there is room */
2442          kern_tree(rcs);          kern_tree(rcs);
2443    
2444          /* Try to kern the branches more by expanding the inter-revision spacing */          /* Try to kern the branches more by expanding the inter-revision spacing */
2445          if(conf.auto_stretch)          if(conf.auto_stretch && !conf.left_right)
2446                  auto_stretch(rcs);                  auto_stretch(rcs);
2447    
2448          /* Move everything w.r.t. the top-left margin */          /* Move everything w.r.t. the top-left margin */
# Line 1961  Line 2450 
2450                  move_branch(rcs->branches[i], conf.margin_left, conf.margin_top);                  move_branch(rcs->branches[i], conf.margin_left, conf.margin_top);
2451    
2452          /* Calculate overall image size */          /* Calculate overall image size */
2453          x = rcs->branches[0]->cx - rcs->branches[0]->tw/2;          if(conf.left_right)
2454          y = rcs->branches[0]->y;          {
2455                    x = rcs->branches[0]->cx;
2456                    y = rcs->branches[0]->y - rcs->branches[0]->th/2;
2457            }
2458            else
2459            {
2460                    x = rcs->branches[0]->cx - rcs->branches[0]->tw/2;
2461                    y = rcs->branches[0]->y;
2462            }
2463          w = rcs->branches[0]->tw;          w = rcs->branches[0]->tw;
2464          h = rcs->branches[0]->th;          h = rcs->branches[0]->th;
2465          for(i = 1; i < rcs->nbranches; i++)          for(i = 1; i < rcs->nbranches; i++)
# Line 1973  Line 2470 
2470          /* Flip the entire tree */          /* Flip the entire tree */
2471          if(conf.upside_down)          if(conf.upside_down)
2472          {          {
2473                  y += rcs->th;                  if(conf.left_right)
                 for(i = 0; i < rcs->nbranches; i++)  
2474                  {                  {
2475                          branch_t *b = rcs->branches[i];                          x += rcs->tw;
2476                          for(j = 0; j < b->nrevs; j++)                          for(i = 0; i < rcs->nbranches; i++)
2477                            {
2478                                    branch_t *b = rcs->branches[i];
2479                                    for(j = 0; j < b->nrevs; j++)
2480                                    {
2481                                            revision_t *r = b->revs[j];
2482                                            r->cx = x - r->cx - r->w + conf.margin_left;
2483                                    }
2484                                    b->cx = x - b->cx - b->w + conf.margin_left;
2485                            }
2486                    }
2487                    else
2488                    {
2489                            y += rcs->th;
2490                            for(i = 0; i < rcs->nbranches; i++)
2491                          {                          {
2492                                  revision_t *r = b->revs[j];                                  branch_t *b = rcs->branches[i];
2493                                  r->y = y - r->y - r->h + conf.margin_top;                                  for(j = 0; j < b->nrevs; j++)
2494                                    {
2495                                            revision_t *r = b->revs[j];
2496                                            r->y = y - r->y - r->h + conf.margin_top;
2497                                    }
2498                                    b->y = y - b->y - b->h + conf.margin_top;
2499                          }                          }
                         b->y = y - b->y - b->h + conf.margin_top;  
2500                  }                  }
2501          }          }
2502  }  }
# Line 1992  Line 2506 
2506   * Imagemap functions   * Imagemap functions
2507   **************************************************************************   **************************************************************************
2508   */   */
2509  void make_imagemap(rcsfile_t *rcs, FILE *fp)  void make_imagemap(rcsfile_t *rcs, FILE *fp, gdImagePtr im)
2510  {  {
2511          int i, j;          int i, j;
2512          fprintf(fp, "<map name=\"%s\">\n", conf.map_name);          const char *htp = conf.html_level == HTMLLEVEL_X ? " /" : "";
2513    
2514            switch(conf.html_level)
2515            {
2516            case HTMLLEVEL_4:
2517                    fprintf(fp, "<map name=\"%s\" id=\"%s\">\n", conf.map_name, conf.map_name);
2518                    break;
2519            case HTMLLEVEL_X:
2520                    fprintf(fp, "<map id=\"%s\">\n", conf.map_name);
2521                    break;
2522            default:
2523                    fprintf(fp, "<map name=\"%s\">\n", conf.map_name);
2524            }
2525    
2526          for(i = 0; i < rcs->nbranches; i++)          for(i = 0; i < rcs->nbranches; i++)
2527          {          {
2528                  branch_t *b = rcs->branches[i];                  branch_t *b = rcs->branches[i];
2529                  tag_t *tag = b->ntags ? b->tags[0] : NULL;                  tag_t *tag = b->ntags ? b->tags[0] : NULL;
2530                  char *bhref = expand_string(conf.map_branch_href, rcs, NULL, b->branch, NULL, tag);                  char *bhref = expand_string(conf.map_branch_href, rcs, NULL, b->branch, NULL, tag);
2531                  char *balt = expand_string(conf.map_branch_alt, rcs, NULL, b->branch, NULL, tag);                  char *balt = expand_string(conf.map_branch_alt, rcs, NULL, b->branch, NULL, tag);
2532                  fprintf(fp, "\t<area shape=\"rect\" %s coords=\"%d,%d,%d,%d\" %s>\n",                  int x1;
2533                                  bhref,                  int x2;
2534                                  b->cx - b->w/2, b->y, b->cx + b->w/2, b->y + b->h,                  int y1;
2535                                  balt);                  int y2;
2536    
2537                    if(conf.left_right)
2538                    {
2539                            x1 = b->cx;
2540                            y1 = b->y - b->h/2;
2541                            x2 = b->cx + b->w;
2542                            y2 = b->y + b->h/2;
2543                    }
2544                    else
2545                    {
2546                            x1 = b->cx - b->w/2;
2547                            y1 = b->y;
2548                            x2 = b->cx + b->w/2;
2549                            y2 = b->y + b->h;
2550                    }
2551                    fprintf(fp, "\t<area shape=\"rect\" %s coords=\"%d,%d,%d,%d\" %s%s>\n",
2552                                    bhref, x1, y1, x2, y2, balt, htp);
2553                    if(im)
2554                    {
2555                            gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, conf.title_color.id);
2556                            gdImageFilledRectangle(im, x2-2, y2-2, x2+2, y2+2, conf.tag_color.id);
2557                            gdImageLine(im, x1, y1, x2, y2, conf.title_color.id);
2558                    }
2559                  for(j = 0; j < b->nrevs; j++)                  for(j = 0; j < b->nrevs; j++)
2560                  {                  {
2561                          revision_t *r = b->revs[j];                          revision_t *r = b->revs[j];
2562                          revision_t* r1;                          revision_t* r1;
2563                          int xoff;                          int xoff = 1;
2564                          int x1;                          int yoff = 1;
                         int x2;  
                         int y1;  
                         int y2;  
2565                          char *href;                          char *href;
2566                          char *alt;                          char *alt;
2567    
2568                          tag = r->ntags ? r->tags[0] : NULL;                          tag = r->ntags ? r->tags[0] : NULL;
2569                          href = expand_string(conf.map_rev_href, rcs, r, r->rev, NULL, tag);                          href = expand_string(conf.map_rev_href, rcs, r, r->rev, NULL, tag);
2570                          alt = expand_string(conf.map_rev_alt, rcs, r, r->rev, NULL, tag);                          alt = expand_string(conf.map_rev_alt, rcs, r, r->rev, NULL, tag);
2571                          fprintf(fp, "\t<area shape=\"rect\" %s coords=\"%d,%d,%d,%d\" %s>\n",                          if(conf.left_right)
2572                                  href,                          {
2573                                  r->cx - r->w/2, r->y, r->cx + r->w/2, r->y + r->h,                                  x1 = r->cx;
2574                                  alt);                                  y1 = r->y - r->h/2;
2575                                    x2 = r->cx + r->w;
2576                                    y2 = r->y + r->h/2;
2577                            }
2578                            else
2579                            {
2580                                    x1 = r->cx - r->w/2;
2581                                    y1 = r->y;
2582                                    x2 = r->cx + r->w/2;
2583                                    y2 = r->y + r->h;
2584                            }
2585                            fprintf(fp, "\t<area shape=\"rect\" %s coords=\"%d,%d,%d,%d\" %s%s>\n",
2586                                    href, x1, y1, x2, y2, alt, htp);
2587                            if(im)
2588                            {
2589                                    gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, conf.title_color.id);
2590                                    gdImageFilledRectangle(im, x2-2, y2-2, x2+2, y2+2, conf.tag_color.id);
2591                                    gdImageLine(im, x1, y1, x2, y2, conf.title_color.id);
2592                            }
2593                          xfree(href);                          xfree(href);
2594                          xfree(alt);                          xfree(alt);
2595                          if(j > 0 || b->branchpoint)                          if(j > 0 || b->branchpoint)
# Line 2032  Line 2597 
2597                                  if(j > 0)                                  if(j > 0)
2598                                  {                                  {
2599                                          r1 = b->revs[j-1];                                          r1 = b->revs[j-1];
2600                                          xoff = MIN(r->w, r1->w)/4;                                          if(conf.left_right)
2601                                          y1 = conf.upside_down ? r1->y : r1->y + r1->h;                                          {
2602                                                    yoff = MIN(r->h, r1->h)/4;
2603                                                    x1 = conf.upside_down ? r1->cx : r1->cx + r1->w;
2604                                            }
2605                                            else
2606                                            {
2607                                                    xoff = MIN(r->w, r1->w)/4;
2608                                                    y1 = conf.upside_down ? r1->y : r1->y + r1->h;
2609                                            }
2610                                  }                                  }
2611                                  else                                  else
2612                                  {                                  {
2613                                          r1 = b->branchpoint;                                          r1 = b->branchpoint;
2614                                          xoff = MIN(r->w, b->w)/4;                                          if(conf.left_right)
2615                                          y1 = conf.upside_down ? b->y : b->y + b->h;                                          {
2616                                                    yoff = MIN(r->h, b->h)/4;
2617                                                    x1 = conf.upside_down ? b->cx : b->cx + b->w;
2618                                            }
2619                                            else
2620                                            {
2621                                                    xoff = MIN(r->w, b->w)/4;
2622                                                    y1 = conf.upside_down ? b->y : b->y + b->h;
2623                                            }
2624                                    }
2625                                    if(conf.left_right)
2626                                    {
2627                                            y1 = r->y - yoff;
2628                                            y2 = r->y + yoff;
2629                                            x2 = conf.upside_down ? r->cx + r->w : r->cx;
2630                                            yoff = 0;
2631                                    }
2632                                    else
2633                                    {
2634                                            x1 = r->cx - xoff;
2635                                            x2 = r->cx + xoff;
2636                                            y2 = conf.upside_down ? r->y + r->h : r->y;
2637                                            xoff = 0;
2638                                    }
2639                                    if(x1 > x2)
2640                                    {
2641                                            int tt = x1;
2642                                            x1 = x2;
2643                                            x2 = tt;
2644                                    }
2645                                    if(y1 > y2)
2646                                    {
2647                                            int tt = y1;
2648                                            y1 = y2;
2649                                            y2 = tt;
2650                                  }                                  }
                                 x1 = r->cx - xoff;  
                                 x2 = r->cx + xoff;  
                                 y2 = conf.upside_down ? r->y + r->h : r->y;  
2651                                  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);
2652                                  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);
2653                                  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",
2654                                          href,                                          href,
2655                                          x1, (conf.upside_down ? y2 : y1) + 1, x2, (conf.upside_down ? y1 : y2) - 1,                                          x1+xoff, y1+yoff, x2-xoff, y2-yoff,
2656                                          alt);                                          alt, htp);
2657                                    if(im)
2658                                    {
2659                                            gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, conf.title_color.id);
2660                                            gdImageFilledRectangle(im, x2-2, y2-2, x2+2, y2+2, conf.tag_color.id);
2661                                            gdImageLine(im, x1, y1, x2, y2, conf.title_color.id);
2662                                    }
2663                                  xfree(href);                                  xfree(href);
2664                                  xfree(alt);                                  xfree(alt);
2665                          }                          }
2666                  }                  }
2667                  if(conf.branch_dupbox)                  if(conf.branch_dupbox)
2668                  {                  {
2669                          int y;                          if(conf.left_right)
2670                          if(conf.upside_down)                          {
2671                                  y = b->y + b->h - b->th;                                  x1 = conf.upside_down ? b->cx + b->w - b->tw : b->cx - b->w + b->tw;
2672                                    y1 = b->y - b->h/2;
2673                                    x2 = x1 + b->w;
2674                                    y2 = b->y + b->h/2;
2675                            }
2676                          else                          else
2677                                  y = b->y - b->h + b->th;                          {
2678                          fprintf(fp, "\t<area shape=\"rect\" %s coords=\"%d,%d,%d,%d\" %s>\n",                                  x1 = b->cx - b->w/2;
2679                                          bhref,                                  y1 = conf.upside_down ? b->y + b->h - b->th : b->y - b->h + b->th;
2680                                          b->cx - b->w/2, y, b->cx + b->w/2, y + b->h,                                  x2 = b->cx + b->w/2;
2681                                          balt);                                  y2 = y1 + b->h;
2682                            }
2683                            fprintf(fp, "\t<area shape=\"rect\" %s coords=\"%d,%d,%d,%d\" %s%s>\n",
2684                                            bhref, x1, y1, x2, y2, balt, htp);
2685                            if(im)
2686                            {
2687                                    gdImageFilledRectangle(im, x1-2, y1-2, x1+2, y1+2, conf.title_color.id);
2688                                    gdImageFilledRectangle(im, x2-2, y2-2, x2+2, y2+2, conf.tag_color.id);
2689                                    gdImageLine(im, x1, y1, x2, y2, conf.title_color.id);
2690                            }
2691                  }                  }
2692                  xfree(bhref);                  xfree(bhref);
2693                  xfree(balt);                  xfree(balt);
# Line 2096  Line 2719 
2719          "  -S           Also strip the first revision (config value is negated)\n"          "  -S           Also strip the first revision (config value is negated)\n"
2720          "  -u           Upside down image (mirror vertically; config value is negated)\n"          "  -u           Upside down image (mirror vertically; config value is negated)\n"
2721          "  -V           Print version and exit\n"          "  -V           Print version and exit\n"
2722            "  -x [34x]     Specify level of HTML 3.2 (default), 4.0 or XHTML\n"
2723          "  -[0-9] <txt> Use <txt> for expansion\n"          "  -[0-9] <txt> Use <txt> for expansion\n"
2724          ;          ;
2725    
2726  #define VERSION_STR     "1.2.1"  #define VERSION_STR     "1.3.1"
2727  #define NOTICE_STR      "Copyright (c) 2001,2002 B.Stultiens"  #define NOTICE_STR      "Copyright (c) 2001,2002,2003 B.Stultiens"
2728    
2729  static void append_slash(char **path)  static void append_slash(char **path)
2730  {  {
# Line 2129  Line 2753 
2753          int stripuntag = 0;          int stripuntag = 0;
2754          int stripfirst = 0;          int stripfirst = 0;
2755          int autostretch = 0;          int autostretch = 0;
2756            int htmllevel = 0;
2757          char *imgmapname = NULL;          char *imgmapname = NULL;
2758          char *imgmapfile = NULL;          char *imgmapfile = NULL;
2759          int lose = 0;          int lose = 0;
# Line 2137  Line 2762 
2762          rcsfile_t *rcs;          rcsfile_t *rcs;
2763          gdImagePtr im;          gdImagePtr im;
2764    
2765          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)
2766          {          {
2767                  switch(optc)                  switch(optc)
2768                  {                  {
# Line 2189  Line 2814 
2814                  case 'V':                  case 'V':
2815                          fprintf(stdout, "cvsgraph v%s, %s\n", VERSION_STR, NOTICE_STR);                          fprintf(stdout, "cvsgraph v%s, %s\n", VERSION_STR, NOTICE_STR);
2816                          return 0;                          return 0;
2817                    case 'x':
2818                            switch(optarg[0])
2819                            {
2820                            case '3':
2821                                    htmllevel = HTMLLEVEL_3;
2822                                    break;
2823                            case '4':
2824                                    htmllevel = HTMLLEVEL_4;
2825                                    break;
2826                            case 'x':
2827                                    htmllevel = HTMLLEVEL_X;
2828                                    break;
2829                            default:
2830                                    fprintf(stderr, "Invalid HTML level in -x\n");
2831                                    lose++;
2832                            }
2833                            break;
2834                  case 'h':                  case 'h':
2835                          fprintf(stdout, "%s", usage_str);                          fprintf(stdout, "%s", usage_str);
2836                          return 0;                          return 0;
# Line 2239  Line 2881 
2881          conf.map_diff_href      = xstrdup("href=\"unset: conf.map_diff_href\"");          conf.map_diff_href      = xstrdup("href=\"unset: conf.map_diff_href\"");
2882          conf.map_diff_alt       = xstrdup("alt=\"%P &lt;-&gt; %R\"");          conf.map_diff_alt       = xstrdup("alt=\"%P &lt;-&gt; %R\"");
2883          conf.rev_text           = xstrdup("%d");          conf.rev_text           = xstrdup("%d");
2884            conf.merge_from         = xstrdup("");
2885            conf.merge_to           = xstrdup("");
2886    
2887          conf.color_bg           = white_color;          conf.color_bg           = white_color;
2888          conf.branch_bgcolor     = white_color;          conf.branch_bgcolor     = white_color;
# Line 2246  Line 2890 
2890          conf.branch_tag_color   = black_color;          conf.branch_tag_color   = black_color;
2891          conf.rev_color          = black_color;          conf.rev_color          = black_color;
2892          conf.rev_bgcolor        = white_color;          conf.rev_bgcolor        = white_color;
2893            conf.merge_color        = black_color;
2894          conf.tag_color          = black_color;          conf.tag_color          = black_color;
2895          conf.title_color        = black_color;          conf.title_color        = black_color;
2896          conf.rev_text_color     = black_color;          conf.rev_text_color     = black_color;
# Line 2266  Line 2911 
2911          if(stripuntag)  conf.strip_untagged = !conf.strip_untagged;          if(stripuntag)  conf.strip_untagged = !conf.strip_untagged;
2912          if(stripfirst)  conf.strip_first_rev = !conf.strip_first_rev;          if(stripfirst)  conf.strip_first_rev = !conf.strip_first_rev;
2913          if(autostretch) conf.auto_stretch = !conf.auto_stretch;          if(autostretch) conf.auto_stretch = !conf.auto_stretch;
2914            if(htmllevel)   conf.html_level = htmllevel;
2915    
2916          if(conf.rev_minline >= conf.rev_maxline)          if(conf.rev_minline >= conf.rev_maxline)
2917          {          {
# Line 2337  Line 2983 
2983          {          {
2984                  /* Create an image */                  /* Create an image */
2985                  im = make_image(rcs);                  im = make_image(rcs);
2986    #ifdef DEBUG_IMAGEMAP
2987                    {
2988                            FILE *nulfile = fopen("/dev/null", "w");
2989                            make_imagemap(rcs, nulfile, im);
2990                            fclose(nulfile);
2991                    }
2992    #endif
2993                  switch(conf.image_type)                  switch(conf.image_type)
2994                  {                  {
2995  #ifdef HAVE_IMAGE_GIF  #ifdef HAVE_IMAGE_GIF
# Line 2369  Line 3021 
3021          else          else
3022          {          {
3023                  /* Create an imagemap */                  /* Create an imagemap */
3024                  make_imagemap(rcs, fp);                  make_imagemap(rcs, fp, NULL);
3025          }          }
3026    
3027          /* Also create imagemap to file if requested */          /* Also create imagemap to file if requested */
# Line 2381  Line 3033 
3033                          perror(imgmapfile);                          perror(imgmapfile);
3034                          return 1;                          return 1;
3035                  }                  }
3036                  make_imagemap(rcs, ifp);                  make_imagemap(rcs, ifp, NULL);
3037                  fclose(ifp);                  fclose(ifp);
3038          }          }
3039    

Legend:
Removed from v.1.23  
changed lines
  Added in v.1.30

  ViewVC Help
Powered by ViewVC 1.1.0 with CvsGraph 1.7.0