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

Annotate of /cvsgraph/cvsgraph.c

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


Revision 1.7 - (hide annotations)
Sun Mar 4 01:38:23 2001 UTC (16 years, 8 months ago) by bertho
Branch: MAIN
Changes since 1.6: +667 -687 lines
File MIME type: text/plain
Major update of the code.
- Complete new method of getting the revision structure by directly
  reading the rcs/cvs file. This should also speed things a bit
  because no external program needs to be called anymore.
  This also means that "remote-graphs" are no longer a possible
  extension of the program. But, who cares.
- Implemented branch-kerning to save place. The images are now
  much smaller in width, dependent on the settings of the exterior
  margins.
- Fixed disjoint braches by reading the structure direct from the
  rcs/cvs file. The revision/branch structure is no longer determined
  from the revision numbers, but solely from the rcs/cvs file structure.
- Fixed display of branches with no revisions attached to them. These
  only have a tag describing the new branch.
1 bertho 1.1 /*
2     * CvsGraph graphical representation generator of brances and revisions
3     * of a file in cvs/rcs.
4     *
5     * Copyright (C) 2001 B. Stultiens
6     *
7     * 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
9     * the Free Software Foundation; either version 2 of the License, or
10     * (at your option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20     */
21    
22     #include <stdio.h>
23     #include <stdlib.h>
24     #include <unistd.h>
25     #include <string.h>
26     #include <assert.h>
27     #include <sys/types.h>
28     #include <sys/stat.h>
29     #include <sys/wait.h>
30     #include <fcntl.h>
31     #include <regex.h>
32     #include <errno.h>
33     #include <getopt.h>
34    
35     #include <gd.h>
36     #include <gdfontt.h>
37    
38 bertho 1.5 #include "config.h"
39 bertho 1.1 #include "cvsgraph.h"
40     #include "utils.h"
41     #include "readconf.h"
42 bertho 1.7 #include "rcs.h"
43 bertho 1.1
44 bertho 1.5 #if !defined(HAVE_IMAGE_GIF) && !defined(HAVE_IMAGE_PNG) && !defined(HAVE_IMAGE_JPEG)
45     # error No image output format available. Check libgd
46     #endif
47    
48    
49 bertho 1.1 /*#define DEBUG 1*/
50    
51     #define CONFFILENAME "cvsgraph.conf"
52    
53     #ifndef ETCDIR
54     # define ETCDIR "/usr/local/etc"
55     #endif
56    
57     #ifndef MAX
58     # define MAX(a,b) ((a) > (b) ? (a) : (b))
59     #endif
60    
61     #ifndef MIN
62     # define MIN(a,b) ((a) < (b) ? (a) : (b))
63     #endif
64    
65     #define ALIGN_HL 0x00
66     #define ALIGN_HC 0x01
67     #define ALIGN_HR 0x02
68     #define ALIGN_HX 0x0f
69     #define ALIGN_VT 0x00
70     #define ALIGN_VC 0x10
71     #define ALIGN_VB 0x20
72     #define ALIGN_VX 0xf0
73    
74     /*
75     **************************************************************************
76     * Globals
77     **************************************************************************
78     */
79    
80     config_t conf;
81 bertho 1.7 int debuglevel;
82 bertho 1.1
83     /*
84     **************************************************************************
85 bertho 1.7 * Dubug routines
86 bertho 1.1 **************************************************************************
87     */
88 bertho 1.7 void dump_rev(char *p, rev_t *r)
89 bertho 1.1 {
90 bertho 1.7 printf("%s", p);
91     if(r)
92     printf("'%s', '%s', %d\n", r->rev, r->branch, r->isbranch);
93     else
94     printf("<null>\n");
95 bertho 1.1 }
96    
97 bertho 1.7 void dump_id(char *p, char *d)
98 bertho 1.1 {
99 bertho 1.7 printf("%s", p);
100     if(d)
101     printf("'%s'\n", d);
102     else
103     printf("<null>\n");
104 bertho 1.1 }
105    
106 bertho 1.7 void dump_idrev(char *p, idrev_t *t)
107 bertho 1.1 {
108 bertho 1.7 printf("%s", p);
109     if(t)
110 bertho 1.1 {
111 bertho 1.7 printf("'%s' -> ", t->id);
112     dump_rev("", t->rev);
113 bertho 1.1 }
114     else
115 bertho 1.7 printf("<null>\n");
116 bertho 1.1 }
117    
118 bertho 1.7 void dump_tag(char *p, tag_t *t)
119 bertho 1.1 {
120 bertho 1.7 printf("%s", p);
121     if(t)
122 bertho 1.1 {
123 bertho 1.7 printf("'%s' -> ", t->tag);
124     dump_rev("", t->rev);
125 bertho 1.1 }
126 bertho 1.7 else
127     printf("<null>\n");
128 bertho 1.1 }
129    
130 bertho 1.7 void dump_delta(char *p, delta_t *d)
131 bertho 1.1 {
132 bertho 1.7 int i;
133     printf("%sdelta.rev : ", p);
134     dump_rev("", d->rev);
135     printf("%sdelta.date : %s\n", p, d->date);
136     printf("%sdelta.author: %s\n", p, d->author);
137     printf("%sdelta.state : %s\n", p, d->state);
138     for(i = 0; d->branches && i < d->branches->nrevs; i++)
139 bertho 1.1 {
140 bertho 1.7 printf("%sdelta.branch: ", p);
141     dump_rev("", d->branches->revs[i]);
142 bertho 1.1 }
143 bertho 1.7 printf("%sdelta.next : ", p);
144     dump_rev("", d->next);
145     printf("\n");
146 bertho 1.1 }
147    
148 bertho 1.7 void dump_dtext(char *p, dtext_t *d)
149 bertho 1.1 {
150 bertho 1.7 printf("%sdtext.rev : ", p);
151     dump_rev("", d->rev);
152     printf("%sdtext.log : %d bytes\n", p, d->log ? strlen(d->log) : -1);
153     printf("%sdtext.text : %d bytes\n", p, d->text ? strlen(d->text) : -1);
154     printf("\n");
155 bertho 1.1 }
156    
157 bertho 1.7 void dump_rcsfile(rcsfile_t *rcs)
158 bertho 1.1 {
159 bertho 1.7 int i;
160     printf("root : '%s'\n", rcs->root);
161     printf("module : '%s'\n", rcs->module);
162     printf("file : '%s'\n", rcs->file);
163     dump_rev("head : ", rcs->head);
164     dump_rev("branch : ", rcs->branch);
165     printf("access :\n");
166     for(i = 0; rcs->access && i < rcs->access->nids; i++)
167     dump_id("\t", rcs->access->ids[i]);
168     printf("tags :\n");
169     for(i = 0; rcs->tags && i < rcs->tags->ntags; i++)
170     dump_tag("\t", rcs->tags->tags[i]);
171     printf("locks :%s\n", rcs->strict ? " (strict)" : "");
172     for(i = 0; rcs->locks && i < rcs->locks->nidrevs; i++)
173     dump_idrev("\t", rcs->locks->idrevs[i]);
174     printf("comment: '%s'\n", rcs->comment);
175     printf("expand : '%s'\n", rcs->expand ? rcs->expand : "(default -kv)");
176     printf("deltas :\n");
177     for(i = 0; rcs->deltas && i < rcs->deltas->ndeltas; i++)
178     dump_delta("\t", rcs->deltas->deltas[i]);
179     printf("desc : '%s'\n", rcs->desc);
180     printf("dtexts :\n");
181     for(i = 0; rcs->dtexts && i < rcs->dtexts->ndtexts; i++)
182     dump_dtext("\t", rcs->dtexts->dtexts[i]);
183    
184     fflush(stdout);
185 bertho 1.1 }
186    
187 bertho 1.7 /*
188     **************************************************************************
189     * Read the rcs file
190     **************************************************************************
191     */
192     rcsfile_t *get_rcsfile(const char *cvsroot, const char *module, const char *file)
193 bertho 1.1 {
194 bertho 1.7 char *cmd = NULL;
195     int rv;
196 bertho 1.1
197 bertho 1.7 cmd = xmalloc(strlen(cvsroot) + strlen(module) + strlen(file) + 2 + 1);
198     sprintf(cmd, "%s/%s/%s", cvsroot, module, file);
199     if(!(rcsin = fopen(cmd, "r")))
200 bertho 1.1 return NULL;
201 bertho 1.7 input_file = cmd;
202     line_number = 1;
203     rv = rcsparse();
204     fclose(rcsin);
205     if(rv)
206 bertho 1.1 return NULL;
207 bertho 1.7 xfree(cmd);
208     input_file = NULL;
209     rcsfile->root = xstrdup(cvsroot);
210     rcsfile->module = xstrdup(module);
211     rcsfile->file = xstrdup(file);
212     return rcsfile;
213 bertho 1.1 }
214    
215     /*
216     **************************************************************************
217     * Sort and find helpers
218     **************************************************************************
219     */
220 bertho 1.5 int count_dots(const char *s)
221     {
222     int i;
223     for(i = 0; *s; s++)
224     {
225     if(*s == '.')
226     i++;
227     }
228     return i;
229     }
230    
231 bertho 1.7 int compare_rev(int bcmp, const rev_t *r1, const rev_t *r2)
232 bertho 1.5 {
233     int d1, d2;
234 bertho 1.7 char *c1, *c2;
235 bertho 1.5 char *v1, *v2;
236     char *s1, *s2;
237     int retval = 0;
238     assert(r1 != NULL);
239     assert(r2 != NULL);
240 bertho 1.7 if(bcmp)
241     {
242     assert(r1->branch != NULL);
243     assert(r2->branch != NULL);
244     c1 = r1->branch;
245     c2 = r2->branch;
246     }
247     else
248     {
249     assert(r1->rev != NULL);
250     assert(r2->rev != NULL);
251     c1 = r1->rev;
252     c2 = r2->rev;
253     }
254 bertho 1.5
255 bertho 1.7 d1 = count_dots(c1);
256     d2 = count_dots(c2);
257 bertho 1.5 if(d1 != d2)
258     {
259     return d1 - d2;
260     }
261    
262 bertho 1.7 s1 = v1 = xstrdup(c1);
263     s2 = v2 = xstrdup(c2);
264 bertho 1.5 while(1)
265     {
266     char *vc1 = strchr(s1, '.');
267     char *vc2 = strchr(s2, '.');
268     if(vc1 && vc2)
269     *vc1 = *vc2 = '\0';
270     if(*s1 && *s2)
271     {
272     d1 = atoi(s1);
273     d2 = atoi(s2);
274     if(d1 != d2)
275     {
276     retval = d1 - d2;
277     break;
278     }
279     }
280     if(!vc1 || !vc2)
281     break;
282     s1 = vc1 + 1;
283     s2 = vc2 + 1;
284     }
285     xfree(v1);
286     xfree(v2);
287     return retval;
288     }
289    
290 bertho 1.7 /*
291     **************************************************************************
292     * Reorganise the rcsfile for the branches
293     *
294     * Basically, we have a list of deltas (i.e. administrative info on
295     * revisions) and a list of delta text (the actual logs and diffs).
296     * The deltas are linked through the 'next' and the 'branches' fields
297     * which describe the tree-structure of revisions.
298     * The reorganisation means that we put each delta and corresponding
299     * delta text in a revision structure and assign it to a specific
300     * branch. This is required because we want to be able to calculate
301     * the bounding boxes of each branch. The revisions expand vertically
302     * and the branches expand horizontally.
303     * The reorganisation is performed in these steps:
304     * 1 - sort deltas and detla text on revision number for quick lookup
305     * 2 - start at the denoted head revision:
306     * * create a branch structure and add this revision
307     * * for each 'branches' in the delta do:
308     * - walk all 'branches' of the delta and recursively goto 2
309     * with the denoted branch delta as new head
310     * - backlink the newly create sub-branch to the head revision
311     * so that we can draw them recursively
312     * * set head to the 'next' field and goto 2 until no next is
313     * available
314     * 3 - update the administration
315     **************************************************************************
316     */
317     int sort_delta(const void *d1, const void *d2)
318     {
319     return compare_rev(0, (*(delta_t **)d1)->rev, (*(delta_t **)d2)->rev);
320     }
321    
322     int search_delta(const void *r, const void *d)
323 bertho 1.1 {
324 bertho 1.7 return compare_rev(0, (rev_t *)r, (*(delta_t **)d)->rev);
325 bertho 1.1 }
326    
327 bertho 1.7 delta_t *find_delta(delta_t **dl, int n, rev_t *r)
328 bertho 1.1 {
329 bertho 1.7 delta_t **d;
330     d = bsearch(r, dl, n, sizeof(*dl), search_delta);
331     if(!d)
332     return NULL;
333     return *d;
334 bertho 1.1 }
335    
336 bertho 1.7 int sort_dtext(const void *d1, const void *d2)
337 bertho 1.1 {
338 bertho 1.7 return compare_rev(0, (*(dtext_t **)d1)->rev, (*(dtext_t **)d2)->rev);
339 bertho 1.1 }
340    
341 bertho 1.7 int search_dtext(const void *r, const void *d)
342 bertho 1.1 {
343 bertho 1.7 return compare_rev(0, (rev_t *)r, (*(dtext_t **)d)->rev);
344 bertho 1.1 }
345    
346 bertho 1.7 dtext_t *find_dtext(dtext_t **dl, int n, rev_t *r)
347 bertho 1.1 {
348 bertho 1.7 dtext_t **d;
349     d = bsearch(r, dl, n, sizeof(*dl), search_dtext);
350     if(!d)
351 bertho 1.1 return NULL;
352 bertho 1.7 return *d;
353     }
354    
355     rev_t *dup_rev(const rev_t *r)
356     {
357     rev_t *t = xmalloc(sizeof(*t));
358     t->rev = xstrdup(r->rev);
359     t->branch = xstrdup(r->branch);
360     t->isbranch = r->isbranch;
361     return t;
362     }
363    
364     branch_t *new_branch(delta_t *d, dtext_t *t)
365     {
366     branch_t *b = xmalloc(sizeof(*b));
367     revision_t *r = xmalloc(sizeof(*r));
368     r->delta = d;
369     r->dtext = t;
370     r->rev = d->rev;
371     r->branch = b;
372     b->branch = dup_rev(d->rev);
373     b->branch->isbranch = 1;
374     b->nrevs = 1;
375     b->revs = xmalloc(sizeof(b->revs[0]));
376     b->revs[0] = r;
377     return b;
378     }
379    
380     revision_t *add_to_branch(branch_t *b, delta_t *d, dtext_t *t)
381     {
382     revision_t *r = xmalloc(sizeof(*r));
383     r->delta = d;
384     r->dtext = t;
385     r->rev = d->rev;
386     r->branch = b;
387     b->revs = xrealloc(b->revs, (b->nrevs+1) * sizeof(b->revs[0]));
388     b->revs[b->nrevs] = r;
389     b->nrevs++;
390     return r;
391     }
392    
393     void build_branch(branch_t ***bl, int *nbl, delta_t **sdl, int nsdl, dtext_t **sdt, int nsdt, delta_t *head)
394     {
395     branch_t *b;
396     dtext_t *text;
397     revision_t *currev;
398    
399     assert(head != NULL);
400    
401     if(head->flag)
402     {
403     fprintf(stderr, "Circular reference on '%s' in branchpoint\n", head->rev->rev);
404     return;
405     }
406     head->flag++;
407     text = find_dtext(sdt, nsdt, head->rev);
408    
409     /* Create a new branch for this head */
410     b = new_branch(head, text);
411     *bl = xrealloc(*bl, (*nbl+1)*sizeof((*bl)[0]));
412     (*bl)[*nbl] = b;
413     (*nbl)++;
414     currev = b->revs[0];
415     while(1)
416     {
417     /* Process all sub-branches */
418     if(head->branches)
419     {
420     int i;
421     for(i = 0; i < head->branches->nrevs; i++)
422     {
423     delta_t *d = find_delta(sdl, nsdl, head->branches->revs[i]);
424     int btag = *nbl;
425     if(!d)
426     continue;
427     build_branch(bl, nbl, sdl, nsdl, sdt, nsdt, d);
428    
429     /* Set the new branch's origin */
430     (*bl)[btag]->branchpoint = currev;
431    
432     /* Add branch to this revision */
433     currev->branches = xrealloc(currev->branches, (currev->nbranches+1)*sizeof(currev->branches[0]));
434     currev->branches[currev->nbranches] = (*bl)[btag];
435     currev->nbranches++;
436     }
437     }
438    
439     /* Walk through the next list */
440     if(!head->next)
441     return;
442    
443     head = find_delta(sdl, nsdl, head->next);
444     if(!head)
445     {
446     fprintf(stderr, "Next revision (%s) not found in deltalist\n", head->next->rev);
447     return;
448     }
449     if(head->flag)
450     {
451     fprintf(stderr, "Circular reference on '%s'\n", head->rev->rev);
452     return;
453     }
454     head->flag++;
455     text = find_dtext(sdt, nsdt, head->rev);
456     currev = add_to_branch(b, head, text);
457     }
458     }
459    
460     int reorganise_branches(rcsfile_t *rcs)
461     {
462     delta_t **sdelta;
463     int nsdelta;
464     dtext_t **sdtext;
465     int nsdtext;
466     delta_t *head;
467     branch_t **bl;
468     int nbl;
469     int i;
470    
471     assert(rcs->deltas != NULL);
472     assert(rcs->head != NULL);
473    
474     /* Make a new list for quick lookup */
475     nsdelta = rcs->deltas->ndeltas;
476     sdelta = xmalloc(nsdelta * sizeof(sdelta[0]));
477     memcpy(sdelta, rcs->deltas->deltas, nsdelta * sizeof(sdelta[0]));
478     qsort(sdelta, nsdelta, sizeof(sdelta[0]), sort_delta);
479    
480     /* Do the same for the delta text */
481     nsdtext = rcs->dtexts->ndtexts;
482     sdtext = xmalloc(nsdtext * sizeof(sdtext[0]));
483     memcpy(sdtext, rcs->dtexts->dtexts, nsdtext * sizeof(sdtext[0]));
484     qsort(sdtext, nsdtext, sizeof(sdtext[0]), sort_dtext);
485    
486     /* Start from the head of the trunk */
487     head = find_delta(sdelta, nsdelta, rcs->head);
488     if(!head)
489     {
490     fprintf(stderr, "Head revision (%s) not found in deltalist\n", rcs->head->rev);
491     return 0;
492     }
493     bl = NULL;
494     nbl = 0;
495     build_branch(&bl, &nbl, sdelta, nsdelta, sdtext, nsdtext, head);
496    
497     /* Reverse the head branch */
498     for(i = 0; i < bl[0]->nrevs/2; i++)
499     {
500     revision_t *r;
501     r = bl[0]->revs[i];
502     bl[0]->revs[i] = bl[0]->revs[bl[0]->nrevs-i-1];
503     bl[0]->revs[bl[0]->nrevs-i-1] = r;
504     }
505    
506     /* Update the branch-number of the head because it was reversed */
507     xfree(bl[0]->branch->branch);
508     bl[0]->branch->branch = xstrdup(bl[0]->revs[0]->rev->branch);
509    
510     /* Keep the admin */
511     rcs->branches = bl;
512     rcs->nbranches = nbl;
513     rcs->sdelta = sdelta;
514     rcs->nsdelta = nsdelta;
515     rcs->sdtext = sdtext;
516     rcs->nsdtext = nsdtext;
517     rcs->active = bl[0];
518     return 1;
519     }
520    
521     /*
522     **************************************************************************
523     * Assign the symbolic tags to the revisions and branches
524     *
525     * The tags point to revision numbers somewhere in the tree structure
526     * of branches and revisions. First we make a sorted list of all
527     * revisions and then we assign each tag to the proper revision.
528     **************************************************************************
529     */
530     int sort_revision(const void *r1, const void *r2)
531     {
532     return compare_rev(0, (*(revision_t **)r1)->delta->rev, (*(revision_t **)r2)->delta->rev);
533     }
534    
535     int search_revision(const void *t, const void *r)
536     {
537     return compare_rev(0, (rev_t *)t, (*(revision_t **)r)->delta->rev);
538     }
539    
540     int sort_branch(const void *b1, const void *b2)
541     {
542     return compare_rev(1, (*(branch_t **)b1)->branch, (*(branch_t **)b2)->branch);
543 bertho 1.1 }
544    
545 bertho 1.7 int search_branch(const void *t, const void *b)
546 bertho 1.1 {
547 bertho 1.7 return compare_rev(1, (rev_t *)t, (*(branch_t **)b)->branch);
548 bertho 1.1 }
549    
550 bertho 1.7 char *previous_rev(const char *c)
551 bertho 1.1 {
552 bertho 1.7 int dots = count_dots(c);
553     char *cptr;
554     char *r;
555     if(!dots)
556     return xstrdup("1.0"); /* FIXME: don't know what the parent is */
557     if(dots & 1)
558     {
559     /* Is is a revision we want the parent of */
560     r = xstrdup(c);
561     cptr = strrchr(r, '.');
562     assert(cptr != NULL);
563     if(dots == 1)
564     {
565     /* FIXME: What is the parent of 1.1? */
566     cptr[1] = '\0';
567     strcat(r, "0");
568     return r;
569     }
570     /* Here we have a "x.x[.x.x]+" case */
571     *cptr = '\0';
572     cptr = strrchr(r, '.');
573     assert(cptr != NULL);
574     *cptr = '\0';
575     return r;
576     }
577     /* It is a branch we want the parent of */
578     r = xstrdup(c);
579     cptr = strrchr(r, '.');
580     assert(cptr != NULL);
581     *cptr = '\0';
582     return r;
583 bertho 1.1 }
584    
585 bertho 1.7 int assign_tags(rcsfile_t *rcs)
586 bertho 1.1 {
587     int i;
588 bertho 1.7 int nr;
589    
590     for(i = nr = 0; i < rcs->nbranches; i++)
591     nr += rcs->branches[i]->nrevs;
592    
593     rcs->srev = xmalloc(nr * sizeof(rcs->srev[0]));
594     rcs->nsrev = nr;
595     for(i = nr = 0; i < rcs->nbranches; i++)
596     {
597     memcpy(&rcs->srev[nr], rcs->branches[i]->revs, rcs->branches[i]->nrevs * sizeof(rcs->branches[i]->revs[0]));
598     nr += rcs->branches[i]->nrevs;
599     }
600    
601     qsort(rcs->srev, rcs->nsrev, sizeof(rcs->srev[0]), sort_revision);
602     qsort(rcs->branches, rcs->nbranches, sizeof(rcs->branches[0]), sort_branch);
603    
604     if(!rcs->branch)
605     {
606     /* The main trunk is the active trunk */
607     rcs->tags->tags = xrealloc(rcs->tags->tags, (rcs->tags->ntags+1)*sizeof(rcs->tags->tags[0]));
608     rcs->tags->tags[rcs->tags->ntags] = xmalloc(sizeof(tag_t));
609     rcs->tags->tags[rcs->tags->ntags]->tag = xstrdup("MAIN");
610     rcs->tags->tags[rcs->tags->ntags]->rev = xmalloc(sizeof(rev_t));
611     rcs->tags->tags[rcs->tags->ntags]->rev->rev = xstrdup(rcs->active->branch->rev);
612     rcs->tags->tags[rcs->tags->ntags]->rev->branch = xstrdup(rcs->active->branch->branch);
613     rcs->tags->tags[rcs->tags->ntags]->rev->isbranch = 1;
614     rcs->tags->ntags++;
615     }
616    
617     /* We should have at least two tags (HEAD and MAIN) */
618     assert(rcs->tags != 0);
619    
620     for(i = 0; i < rcs->tags->ntags; i++)
621     {
622     tag_t *t = rcs->tags->tags[i];
623     if(t->rev->isbranch)
624     {
625     branch_t **b;
626     add_btag:
627     b = bsearch(t->rev, rcs->branches, rcs->nbranches, sizeof(rcs->branches[0]), search_branch);
628     if(!b)
629     {
630     rev_t rev;
631     revision_t **r;
632     /* This happens for the magic branch numbers if there are
633     * no commits withing the new branch yet. So, we add the
634     * branch and try continue.
635     */
636     rev.rev = previous_rev(t->rev->branch);
637     rev.branch = NULL;
638     rev.isbranch = 0;
639     r = bsearch(&rev, rcs->srev, rcs->nsrev, sizeof(rcs->srev[0]), search_revision);
640     xfree(rev.rev);
641     if(!r)
642     {
643     fprintf(stderr, "No branch found for tag '%s:%s'\n", t->tag, t->rev->branch);
644     }
645     else
646     {
647     rcs->branches = xrealloc(rcs->branches, (rcs->nbranches+1)*sizeof(rcs->branches[0]));
648     rcs->branches[rcs->nbranches] = xmalloc(sizeof(branch_t));
649     rcs->branches[rcs->nbranches]->branch = dup_rev(t->rev);
650     rcs->branches[rcs->nbranches]->branchpoint = *r;
651     (*r)->branches = xrealloc((*r)->branches, ((*r)->nbranches+1)*sizeof((*r)->branches[0]));
652     (*r)->branches[(*r)->nbranches] = rcs->branches[rcs->nbranches];
653     (*r)->nbranches++;
654     rcs->nbranches++;
655     /* Resort the branches */
656     qsort(rcs->branches, rcs->nbranches, sizeof(rcs->branches[0]), sort_branch);
657     goto add_btag;
658     }
659     }
660     else
661     {
662     branch_t *bb = *b;
663     bb->tags = xrealloc(bb->tags, (bb->ntags+1)*sizeof(bb->tags[0]));
664     bb->tags[bb->ntags] = t;
665     bb->ntags++;
666     }
667     }
668     else
669     {
670     revision_t **r = bsearch(t->rev, rcs->srev, rcs->nsrev, sizeof(rcs->srev[0]), search_revision);
671     if(!r)
672     fprintf(stderr, "No revision found for tag '%s:%s'\n", t->tag, t->rev->rev);
673     else
674     {
675     revision_t *rr = *r;
676     rr->tags = xrealloc(rr->tags, (rr->ntags+1)*sizeof(rr->tags[0]));
677     rr->tags[rr->ntags] = t;
678     rr->ntags++;
679     }
680     }
681     }
682    
683     /* We need to reset the first in the list of branches to the
684     * active branch to ensure the drawing of all
685     */
686     if(rcs->active != rcs->branches[0])
687 bertho 1.1 {
688 bertho 1.7 branch_t **b = bsearch(rcs->active->branch, rcs->branches, rcs->nbranches, sizeof(rcs->branches[0]), search_branch);
689     branch_t *t;
690     assert(b != NULL);
691     t = *b;
692     *b = rcs->branches[0];
693     rcs->branches[0] = t;
694 bertho 1.1 }
695 bertho 1.7 return 1;
696 bertho 1.1 }
697    
698     /*
699     **************************************************************************
700     * Drawing routines
701     **************************************************************************
702     */
703     int get_swidth(const char *s, font_t *f)
704     {
705     if(!s)
706     return 0;
707     return strlen(s) * (*f)->w;
708     }
709    
710     int get_sheight(const char *s, font_t *f)
711     {
712     int nl;
713     if(!s)
714     return 0;
715     for(nl = 1; *s; s++)
716     {
717     if(*s == '\n' && s[1])
718     nl++;
719     }
720     return nl * (*f)->h;
721     }
722    
723     void draw_rbox(gdImagePtr im, int x1, int y1, int x2, int y2, int r, color_t *color)
724     {
725     int r2 = 2*r;
726     gdImageLine(im, x1+r, y1, x2-r, y1, color->id);
727     gdImageLine(im, x1+r, y2, x2-r, y2, color->id);
728     gdImageLine(im, x1, y1+r, x1, y2-r, color->id);
729     gdImageLine(im, x2, y1+r, x2, y2-r, color->id);
730     if(r)
731     {
732     gdImageArc(im, x1+r, y1+r, r2, r2, 180, 270, color->id);
733     gdImageArc(im, x2-r, y1+r, r2, r2, 270, 360, color->id);
734     gdImageArc(im, x1+r, y2-r, r2, r2, 90, 180, color->id);
735     gdImageArc(im, x2-r, y2-r, r2, r2, 0, 90, color->id);
736     }
737     }
738    
739     void draw_string(gdImagePtr im, char *s, font_t *f, int x, int y, int align, color_t *c)
740     {
741     int xx, yy;
742     switch(align & ALIGN_HX)
743     {
744     default:
745     case ALIGN_HL: xx = 0; break;
746     case ALIGN_HC: xx = -get_swidth(s, f)/2; break;
747     case ALIGN_HR: xx = -get_swidth(s, f); break;
748     }
749     switch(align & ALIGN_VX)
750     {
751     default:
752     case ALIGN_VT: yy = 0; break;
753     case ALIGN_VC: yy = -get_sheight(s, f)/2; break;
754     case ALIGN_VB: yy = -get_sheight(s, f); break;
755     }
756     gdImageString(im, *f, x+xx+1, y+yy, s, c->id);
757     }
758    
759     void draw_rev(gdImagePtr im, int cx, int ty, revision_t *r)
760     {
761     int lx = cx - r->w/2;
762     int rx = lx + r->w;
763     int i;
764     draw_rbox(im, lx, ty, rx, ty+r->h, 0, &conf.rev_color);
765     ty += conf.rev_tspace;
766     draw_string(im, r->rev->rev, &conf.rev_font, cx, ty, ALIGN_HC, &conf.rev_color);
767     ty += get_sheight(r->rev->rev, &conf.rev_font);
768     for(i = 0; i < r->ntags; i++)
769     {
770     draw_string(im, r->tags[i]->tag, &conf.tag_font, cx, ty, ALIGN_HC, &conf.tag_color);
771     ty += get_sheight(r->tags[i]->tag, &conf.tag_font);
772     }
773     }
774    
775     void draw_branch(gdImagePtr im, int cx, int ty, branch_t *b)
776     {
777     int lx = cx - b->w/2;
778     int rx = lx + b->w;
779     int yy;
780     int i;
781 bertho 1.7 /*draw_rbox(im, cx-b->tw/2-1, ty-1, cx+b->tw/2+1, ty+b->th+1, 0, &conf.title_color);*/
782 bertho 1.1 draw_rbox(im, lx, ty, rx, ty+b->h, 5, &conf.branch_color);
783     yy = conf.branch_tspace;
784 bertho 1.7 draw_string(im, b->branch->branch, &conf.branch_font, cx, ty+yy, ALIGN_HC, &conf.branch_color);
785     yy += get_sheight(b->branch->branch, &conf.branch_font);
786     for(i = 0; i < b->ntags; i++)
787 bertho 1.1 {
788 bertho 1.7 draw_string(im, b->tags[i]->tag, &conf.branch_font, cx, ty+yy, ALIGN_HC, &conf.branch_color);
789     yy += get_sheight(b->tags[i]->tag, &conf.branch_font);
790 bertho 1.1 }
791    
792     ty += b->h;
793     for(i = 0; i < b->nrevs; i++)
794     {
795     gdImageLine(im, cx, ty, cx, ty+conf.rev_minline, conf.rev_color.id);
796     ty += conf.rev_minline;
797     draw_rev(im, cx, ty, b->revs[i]);
798     ty += b->revs[i]->h;
799     }
800     }
801    
802     static char *_title;
803     static int _ntitle;
804     static int _natitle;
805    
806     void add_title_str(const char *s)
807     {
808     int l = strlen(s) + 1;
809     if(_ntitle + l > _natitle)
810     {
811     _natitle += 128;
812     _title = xrealloc(_title, _natitle * sizeof(_title[0]));
813     }
814     memcpy(_title+_ntitle, s, l);
815     _ntitle += l-1;
816     }
817    
818     void add_title_ch(int ch)
819     {
820     char buf[2];
821     buf[0] = ch;
822     buf[1] = '\0';
823     add_title_str(buf);
824     }
825    
826 bertho 1.7 char *expand_title(rcsfile_t *rcs)
827 bertho 1.1 {
828     char nb[32];
829     char nr[32];
830     char *cptr;
831    
832     sprintf(nb, "%d", rcs->nbranches);
833 bertho 1.7 sprintf(nr, "%d", rcs->nsrev);
834 bertho 1.1 for(cptr = conf.title; *cptr; cptr++)
835     {
836     if(*cptr == '%')
837     {
838     switch(*++cptr)
839     {
840     case 'c': add_title_str(conf.cvsroot); break;
841 bertho 1.7 case 'f': add_title_str(rcs->file); break;
842 bertho 1.1 case 'm': add_title_str(conf.cvsmodule); break;
843     case 'r': add_title_str(nr); break;
844     case 'b': add_title_str(nb); break;
845     case '%': add_title_ch('%'); break;
846     default:
847     add_title_ch('%');
848     add_title_ch(*cptr);
849     break;
850     }
851     }
852     else
853     add_title_ch(*cptr);
854     }
855     return _title;
856     }
857    
858     void draw_title(gdImagePtr im, char *title)
859     {
860     char *t;
861     char *s = title;
862     int x = conf.title_x;
863     int y = conf.title_y;
864     do
865     {
866     t = strchr(s, '\n');
867     if(t)
868     *t = '\0';
869     draw_string(im, s, &conf.title_font, x, y, conf.title_align, &conf.title_color);
870     y += get_sheight(s, &conf.title_font);
871     s = t+1;
872     } while(t);
873     }
874    
875     void draw_connector(gdImagePtr im, branch_t *b)
876     {
877     revision_t *r = b->branchpoint;
878 bertho 1.7 int x1 = r->cx + r->w/2 + 2;
879 bertho 1.1 int y1 = r->y + r->h/2;
880 bertho 1.7 int x2 = b->cx;
881 bertho 1.1 int y2 = b->y;
882     gdImageLine(im, x1, y1, x2, y1, conf.branch_color.id);
883     gdImageLine(im, x2, y1, x2, y2, conf.branch_color.id);
884     }
885    
886 bertho 1.7 gdImagePtr make_image(rcsfile_t *rcs)
887 bertho 1.1 {
888     gdImagePtr im;
889     int i;
890    
891     im = gdImageCreate(rcs->tw+conf.margin_left+conf.margin_right, rcs->th+conf.margin_top+conf.margin_bottom);
892     conf.color_bg.id = gdImageColorAllocate(im, conf.color_bg.r, conf.color_bg.g, conf.color_bg.b);
893     conf.tag_color.id = gdImageColorAllocate(im, conf.tag_color.r, conf.tag_color.g, conf.tag_color.b);
894     conf.rev_color.id = gdImageColorAllocate(im, conf.rev_color.r, conf.rev_color.g, conf.rev_color.b);
895     conf.branch_color.id = gdImageColorAllocate(im, conf.branch_color.r, conf.branch_color.g, conf.branch_color.b);
896     conf.branch_bgcolor.id = gdImageColorAllocate(im, conf.branch_bgcolor.r, conf.branch_bgcolor.g, conf.branch_bgcolor.b);
897     conf.title_color.id = gdImageColorAllocate(im, conf.title_color.r, conf.title_color.g, conf.title_color.b);
898    
899     for(i = 0; i < rcs->nbranches; i++)
900 bertho 1.7 draw_branch(im, rcs->branches[i]->cx, rcs->branches[i]->y, rcs->branches[i]);
901 bertho 1.1 for(i = 0; i < rcs->nbranches; i++)
902     {
903     if(rcs->branches[i]->branchpoint)
904     draw_connector(im, rcs->branches[i]);
905     }
906     draw_title(im, expand_title(rcs));
907    
908     return im;
909     }
910    
911 bertho 1.7 /*
912     **************************************************************************
913     * Layout routines
914     **************************************************************************
915     */
916 bertho 1.1 void move_branch(branch_t *b, int x, int y)
917     {
918     int i;
919 bertho 1.7 b->cx += x;
920 bertho 1.1 b->y += y;
921     for(i = 0; i < b->nrevs; i++)
922     {
923 bertho 1.7 b->revs[i]->cx += x;
924 bertho 1.1 b->revs[i]->y += y;
925     }
926     }
927    
928 bertho 1.6 void reposition_branch(revision_t *r, int *x, int *w)
929     {
930     int i, j;
931     for(j = 0; j < r->nbranches; j++)
932     {
933     branch_t *b = r->branches[j];
934 bertho 1.7 *x += *w + conf.rev_minline + b->tw/2 - b->cx;
935 bertho 1.6 *w = b->tw/2;
936 bertho 1.7 move_branch(b, *x, r->y + r->h/2 + conf.branch_connect);
937     *x = b->cx;
938 bertho 1.6 /* Recurse to move branches of branched revisions */
939     for(i = b->nrevs-1; i >= 0; i--)
940     {
941     reposition_branch(b->revs[i], x, w);
942     }
943     }
944     }
945    
946 bertho 1.1 void rect_union(int *x, int *y, int *w, int *h, branch_t *b)
947     {
948     int x1 = *x;
949     int x2 = x1 + *w;
950     int y1 = *y;
951     int y2 = y1 + *h;
952 bertho 1.7 int xx1 = b->cx - b->tw/2;
953 bertho 1.1 int xx2 = xx1 + b->tw;
954     int yy1 = b->y;
955     int yy2 = yy1 + b->th;
956     x1 = MIN(x1, xx1);
957     x2 = MAX(x2, xx2);
958     y1 = MIN(y1, yy1);
959     y2 = MAX(y2, yy2);
960     *x = x1;
961     *y = y1;
962     *w = x2 - x1;
963     *h = y2 - y1;
964     }
965    
966 bertho 1.7 int branch_intersects(int top, int bottom, int left, branch_t *b)
967     {
968     int br = b->cx + b->tw/2;
969     int bt = b->y - conf.branch_connect - conf.branch_margin/2;
970     int bb = b->y + b->th + conf.branch_margin/2;
971     return !(bt > bottom || bb < top || br >= left);
972     }
973    
974     int kern_branch(rcsfile_t *rcs, branch_t *b)
975     {
976     int left = b->cx - b->tw/2;
977     int top = b->y - conf.branch_connect - conf.branch_margin/2;
978     int bottom = b->y + b->th + conf.branch_margin/2;
979     int i;
980     int xpos = 0;
981    
982     for(i = 0; i < rcs->nbranches; i++)
983     {
984     branch_t *bp = rcs->branches[i];
985     if(bp == b)
986     continue;
987     if(branch_intersects(top, bottom, left, bp))
988     {
989     int m = bp->cx + bp->tw/2 + conf.branch_margin;
990     if(m > xpos)
991     xpos = m;
992     }
993     }
994     if(xpos && (b->cx - b->tw/2) - xpos > 0)
995     {
996     move_branch(b, xpos - (b->cx - b->tw/2), 0);
997     return 1;
998     }
999     return 0;
1000     }
1001    
1002     void make_layout(rcsfile_t *rcs)
1003 bertho 1.1 {
1004     int i, j;
1005     int x, y;
1006     int w, h;
1007     int w2;
1008 bertho 1.7 int moved;
1009 bertho 1.1
1010     /* Calculate the box-sizes of the revisions */
1011 bertho 1.7 for(i = 0; i < rcs->nsrev; i++)
1012 bertho 1.1 {
1013     revision_t *rp;
1014     int w;
1015     int h;
1016 bertho 1.7 rp = rcs->srev[i];
1017 bertho 1.1 w = get_swidth(rp->rev->rev, &conf.rev_font);
1018     h = get_sheight(rp->rev->rev, &conf.rev_font);
1019     for(j = 0; j < rp->ntags; j++)
1020     {
1021     int ww = get_swidth(rp->tags[j]->tag, &conf.tag_font);
1022     if(ww > w) w = ww;
1023     h += get_sheight(rp->tags[j]->tag, &conf.tag_font) + conf.rev_separator;
1024     }
1025     rp->w = w + conf.rev_lspace + conf.rev_rspace;
1026     rp->h = h + conf.rev_tspace + conf.rev_bspace;
1027     }
1028    
1029     /* Calculate the box-sizes of the branches */
1030     for(i = 0; i < rcs->nbranches; i++)
1031     {
1032     branch_t *bp = rcs->branches[i];
1033     int w;
1034     int h;
1035 bertho 1.7 w = get_swidth(bp->branch->branch, &conf.branch_font);
1036     h = get_sheight(bp->branch->branch, &conf.branch_font);
1037     for(j = 0; j < bp->ntags; j++)
1038 bertho 1.1 {
1039 bertho 1.7 int ww = get_swidth(bp->tags[j]->tag, &conf.branch_font);
1040 bertho 1.1 if(ww > w) w = ww;
1041 bertho 1.7 h += get_sheight(bp->tags[j]->tag, &conf.branch_font);
1042 bertho 1.1 }
1043     w += conf.branch_lspace + conf.branch_rspace;
1044     h += conf.branch_tspace + conf.branch_bspace;
1045     bp->w = w;
1046     bp->h = h;
1047     for(j = 0; j < bp->nrevs; j++)
1048     {
1049     if(bp->revs[j]->w > w)
1050     w = bp->revs[j]->w;
1051     h += bp->revs[j]->h + conf.rev_minline;
1052     }
1053     bp->th = h;
1054     bp->tw = w;
1055     }
1056    
1057     /* Calculate the relative positions of revs in a branch */
1058     for(i = 0; i < rcs->nbranches; i++)
1059     {
1060     branch_t *b = rcs->branches[i];
1061     x = b->tw/2;
1062     y = b->h;
1063 bertho 1.7 b->cx = x;
1064 bertho 1.1 b->y = 0;
1065     for(j = 0; j < b->nrevs; j++)
1066     {
1067     y += conf.rev_minline;
1068 bertho 1.7 b->revs[j]->cx = x;
1069 bertho 1.1 b->revs[j]->y = y;
1070     y += b->revs[j]->h;
1071     }
1072     }
1073    
1074 bertho 1.6 /* Reposition the branches */
1075 bertho 1.7 x = rcs->branches[0]->cx;
1076 bertho 1.1 w2 = rcs->branches[0]->tw / 2;
1077     for(i = rcs->branches[0]->nrevs-1; i >= 0; i--)
1078     {
1079 bertho 1.6 reposition_branch(rcs->branches[0]->revs[i], &x, &w2);
1080 bertho 1.1 }
1081    
1082 bertho 1.7 /* Try to move branches left if there is room (kerning) */
1083     for(moved = 1; moved; )
1084     {
1085     moved = 0;
1086     for(i = 1; i < rcs->nbranches; i++)
1087     {
1088     moved += kern_branch(rcs, rcs->branches[i]);
1089     }
1090     }
1091    
1092     /* Move everything w.r.t. the top-left margin */
1093 bertho 1.1 for(i = 0; i < rcs->nbranches; i++)
1094     move_branch(rcs->branches[i], conf.margin_left, conf.margin_top);
1095    
1096     /* Calculate overall image size */
1097 bertho 1.7 x = rcs->branches[0]->cx - rcs->branches[0]->tw/2;
1098 bertho 1.1 y = rcs->branches[0]->y;
1099     w = rcs->branches[0]->tw;
1100     h = rcs->branches[0]->th;
1101     for(i = 1; i < rcs->nbranches; i++)
1102     rect_union(&x, &y, &w, &h, rcs->branches[i]);
1103     rcs->tw = w;
1104     rcs->th = h;
1105     }
1106    
1107     /*
1108     **************************************************************************
1109 bertho 1.6 * Imagemap functions
1110     **************************************************************************
1111     */
1112 bertho 1.7 void make_imagemap(rcsfile_t *rcs, FILE *fp)
1113 bertho 1.6 {
1114     int i, j;
1115     fprintf(fp, "<map name=\"%s\">\n", conf.map_name);
1116     for(i = 0; i < rcs->nbranches; i++)
1117     {
1118     branch_t *b = rcs->branches[i];
1119     fprintf(fp, "<area shape=\"rect\" href=\"branch_%s\" coords=\"%d,%d,%d,%d\" alt=\"Branch %s\">\n",
1120 bertho 1.7 b->branch->branch,
1121     b->cx - b->w/2, b->y, b->cx + b->w/2, b->y + b->h,
1122     b->branch->branch);
1123 bertho 1.6 for(j = 0; j < b->nrevs; j++)
1124     {
1125     revision_t *r = b->revs[j];
1126     fprintf(fp, "<area shape=\"rect\" href=\"rev_%s\" coords=\"%d,%d,%d,%d\" alt=\"Revision %s\">\n",
1127     r->rev->rev,
1128 bertho 1.7 r->cx - r->w/2, r->y, r->cx + r->w/2, r->y + r->h,
1129 bertho 1.6 r->rev->rev);
1130     }
1131     }
1132     fprintf(fp, "</map>\n");
1133     }
1134    
1135     /*
1136     **************************************************************************
1137 bertho 1.1 * Configuration
1138     **************************************************************************
1139     */
1140     int read_config(const char *path)
1141     {
1142     FILE *fp;
1143     int r;
1144 bertho 1.7
1145 bertho 1.1 if(path)
1146     {
1147     if((fp = fopen(path, "r")) == NULL)
1148     {
1149     return 0;
1150     }
1151 bertho 1.7 else
1152     input_file = path;
1153 bertho 1.1 }
1154     else
1155     {
1156     if((fp = fopen("./" CONFFILENAME, "r")) == NULL)
1157     {
1158     if((fp = fopen(ETCDIR "/" CONFFILENAME, "r")) == NULL)
1159     {
1160     return 0;
1161     }
1162 bertho 1.7 else
1163     input_file = ETCDIR "/" CONFFILENAME;
1164 bertho 1.1 }
1165 bertho 1.7 else
1166     input_file = "./" CONFFILENAME;
1167 bertho 1.1 }
1168    
1169     yyin = fp;
1170     r = yyparse();
1171     fclose(fp);
1172 bertho 1.7 input_file = NULL;
1173 bertho 1.1 return r == 0;
1174     }
1175    
1176     /*
1177     **************************************************************************
1178     * Program entry
1179     **************************************************************************
1180     */
1181     static const char usage_str[] =
1182     "Usage: cvsgraph [options] <file>\n"
1183     " -c <file> Read alternative config from <file>\n"
1184 bertho 1.7 " -d <level> Enable debug mode at <level>\n"
1185 bertho 1.1 " -h This message\n"
1186 bertho 1.7 " -i Generate an imagemap instead of image\n"
1187     " -M <name> Use <name> as imagemap name\n"
1188 bertho 1.1 " -m <mod> Use <mod> as cvs module\n"
1189     " -o <file> Output to <file>\n"
1190 bertho 1.7 " -q Be quiet (i.e. no warnings)\n"
1191 bertho 1.1 " -r <path> Use <path> as cvsroot path\n"
1192     " -V Print version and exit\n"
1193     ;
1194    
1195 bertho 1.7 #define VERSION_STR "1.1.0"
1196 bertho 1.1 #define NOTICE_STR "Copyright (c) 2001 B.Stultiens"
1197    
1198     int main(int argc, char *argv[])
1199     {
1200 bertho 1.7 extern int yy_flex_debug;
1201     extern int rcs_flex_debug;
1202     extern int yydebug;
1203     extern int rcsdebug;
1204 bertho 1.1 int optc;
1205     char *confpath = NULL;
1206     char *outfile = NULL;
1207     char *cvsroot = NULL;
1208     char *cvsmodule = NULL;
1209 bertho 1.7 int imagemap = 0;
1210     char *imgmapname = NULL;
1211 bertho 1.1 int lose = 0;
1212     FILE *fp;
1213 bertho 1.7 rcsfile_t *rcs;
1214 bertho 1.1 gdImagePtr im;
1215    
1216 bertho 1.7 while((optc = getopt(argc, argv, "c:d:hiM:m:o:qr:V")) != EOF)
1217 bertho 1.1 {
1218     switch(optc)
1219     {
1220     case 'c':
1221     confpath = xstrdup(optarg);
1222     break;
1223 bertho 1.7 case 'd':
1224     debuglevel = strtol(optarg, NULL, 0);
1225     break;
1226 bertho 1.6 case 'i':
1227 bertho 1.7 imagemap = 1;
1228     break;
1229     case 'M':
1230     imgmapname = xstrdup(optarg);
1231 bertho 1.6 break;
1232 bertho 1.1 case 'm':
1233     cvsmodule = xstrdup(optarg);
1234     break;
1235     case 'o':
1236     outfile = xstrdup(optarg);
1237     break;
1238 bertho 1.7 case 'q':
1239     quiet = 1;
1240     break;
1241 bertho 1.1 case 'r':
1242     cvsroot = xstrdup(optarg);
1243     break;
1244     case 'V':
1245     fprintf(stdout, "cvsgraph v%s, %s\n", VERSION_STR, NOTICE_STR);
1246     return 0;
1247     case 'h':
1248     fprintf(stdout, "%s", usage_str);
1249     return 0;
1250     default:
1251     lose++;
1252     }
1253     }
1254    
1255     if(optind >= argc)
1256     {
1257     fprintf(stderr, "Missing inputfile\n");
1258     lose++;
1259     }
1260    
1261     if(lose)
1262     {
1263     fprintf(stderr, "%s", usage_str);
1264     return 1;
1265     }
1266    
1267 bertho 1.7 if(debuglevel)
1268     {
1269     setvbuf(stdout, NULL, 0, _IONBF);
1270     setvbuf(stderr, NULL, 0, _IONBF);
1271     }
1272     yy_flex_debug = (debuglevel & DEBUG_CONF_LEX) != 0;
1273     rcs_flex_debug = (debuglevel & DEBUG_RCS_LEX) != 0;
1274     yydebug = (debuglevel & DEBUG_CONF_YACC) != 0;
1275     rcsdebug = (debuglevel & DEBUG_RCS_YACC) != 0;
1276    
1277 bertho 1.1 /* Set defaults */
1278     if(!conf.tag_font) conf.tag_font = gdFontTiny;
1279     if(!conf.rev_font) conf.rev_font = gdFontTiny;
1280     if(!conf.branch_font) conf.branch_font = gdFontTiny;
1281     if(!conf.title_font) conf.title_font = gdFontTiny;
1282    
1283     if(!read_config(confpath))
1284     {
1285     fprintf(stderr, "Error reading config file\n");
1286     return 1;
1287     }
1288    
1289     /* Set overrides */
1290 bertho 1.7 if(cvsroot) conf.cvsroot = cvsroot;
1291     if(cvsmodule) conf.cvsmodule = cvsmodule;
1292     if(imgmapname) conf.map_name = imgmapname;
1293 bertho 1.1
1294 bertho 1.7 rcs = get_rcsfile(conf.cvsroot, conf.cvsmodule, argv[optind]);
1295 bertho 1.1 if(!rcs)
1296     {
1297 bertho 1.7 fprintf(stderr, "Error reading rcs-file\n");
1298 bertho 1.1 return 1;
1299     }
1300    
1301 bertho 1.7 if(debuglevel & DEBUG_RCS_FILE)
1302     dump_rcsfile(rcs);
1303 bertho 1.1
1304 bertho 1.7 if(!reorganise_branches(rcs))
1305     return 1;
1306 bertho 1.1
1307 bertho 1.7 if(!assign_tags(rcs))
1308     return 1;
1309 bertho 1.1
1310     if(outfile)
1311     {
1312     if((fp = fopen(outfile, "w")) == NULL)
1313     {
1314     perror(outfile);
1315     return 1;
1316     }
1317     }
1318     else
1319     fp = stdout;
1320 bertho 1.5
1321 bertho 1.7 make_layout(rcs);
1322    
1323     if(!imagemap)
1324 bertho 1.5 {
1325 bertho 1.7 /* Create an image */
1326     im = make_image(rcs);
1327    
1328     switch(conf.image_type)
1329     {
1330 bertho 1.5 #ifdef HAVE_IMAGE_GIF
1331 bertho 1.7 # ifndef HAVE_IMAGE_PNG
1332     default:
1333     # endif
1334     case IMAGE_GIF:
1335     gdImageGif(im, fp);
1336     break;
1337 bertho 1.5 #endif
1338     #ifdef HAVE_IMAGE_PNG
1339 bertho 1.7 default:
1340     case IMAGE_PNG:
1341     gdImagePng(im, fp);
1342     break;
1343 bertho 1.5 #endif
1344     #ifdef HAVE_IMAGE_JPEG
1345     # if !defined(HAVE_IMAGE_GIF) && !defined(HAVE_IMAGE_PNG)
1346 bertho 1.7 default:
1347 bertho 1.5 # endif
1348 bertho 1.7 case IMAGE_JPEG:
1349     gdImageJpeg(im, fp, conf.image_quality);
1350     break;
1351 bertho 1.5 #endif
1352 bertho 1.7 }
1353    
1354     gdImageDestroy(im);
1355     }
1356     else
1357     {
1358     /* Create an imagemap */
1359     make_imagemap(rcs, fp);
1360 bertho 1.5 }
1361    
1362 bertho 1.1 if(outfile)
1363     fclose(fp);
1364 bertho 1.6
1365 bertho 1.1 return 0;
1366     }
1367    

  ViewVC Help
Powered by ViewVC 1.1.0 with CvsGraph 1.7.0