source: trunk/lib/Trac.cc @ 465

Last change on this file since 465 was 465, checked in by Peter Johansson, 14 years ago

fixes #217. Moving functors to a Functor.h and Functor.cc

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 15.4 KB
Line 
1// $Id: Trac.cc 465 2007-08-24 13:28:24Z peter $
2
3/*
4  Copyright (C) 2007 Jari Häkkinen, Peter Johansson
5
6  This file is part of svndigest, http://trac.thep.lu.se/trac/svndigest
7
8  svndigest is free software; you can redistribute it and/or modify it
9  under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12
13  svndigest is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21  02111-1307, USA.
22*/
23
24#include "Trac.h"
25
26#include "Configuration.h"
27#include "Functor.h"
28#include "HtmlStream.h"
29#include "html_utility.h"
30//#include "utility.h"
31
32namespace theplu{
33namespace svndigest{
34
35  Trac::Trac(HtmlStream& hs)
36    : hs_(hs) 
37  {}
38
39  std::string Trac::anchor_text(std::string::const_iterator first,
40                                std::string::const_iterator last,
41                                std::string::const_iterator last_trunc)
42  {
43    if (last>last_trunc) { // truncate
44      std::string str(first, last_trunc);
45      str+="...";
46      return str;
47    }
48    return std::string(first, last);
49  }
50
51
52  bool Trac::changeset(std::string::const_iterator& first, 
53                       const std::string::const_iterator& last,
54                       const std::string::const_iterator& last_trunc)
55  {
56    if (changeset1(first, last, last_trunc))
57      return true;
58    if (changeset2(first, last, last_trunc))
59      return true;
60    if (changeset3(first, last, last_trunc))
61      return true;
62    return false;
63  }
64
65
66  bool Trac::changeset1(std::string::const_iterator& first, 
67                        const std::string::const_iterator& last,
68                        const std::string::const_iterator& last_trunc)
69  {
70    if (first==last)
71      return false;
72    if (*first != 'r')
73      return false;
74    const std::string::const_iterator first_orig(first);
75    ++first;
76    std::string rev = match(first, last, Digit());
77    if (rev.empty()){
78      first = first_orig;
79      return false;
80    }
81    std::string href(Configuration::instance().trac_root()+"changeset/"+rev);
82    hs_.stream() << anchor(href, anchor_text(first_orig, first, last_trunc)); 
83    return true;
84  }
85
86
87  bool Trac::changeset2(std::string::const_iterator& first, 
88                        const std::string::const_iterator& last,
89                        const std::string::const_iterator& last_trunc)
90  {
91    if (first==last)
92      return false;
93    if (*first != '[')
94      return false;
95    const std::string::const_iterator first_orig(first);
96    ++first;
97    std::string rev = match(first, last, Digit());
98    if (rev.empty() || first==last || *first!=']'){
99      first = first_orig;
100      return false;
101    }
102    ++first;
103    std::string href(Configuration::instance().trac_root()+"changeset/"+rev);
104    hs_.stream() << anchor(href, anchor_text(first_orig,first, last_trunc)); 
105    return true;
106  }
107
108
109  bool Trac::changeset3(std::string::const_iterator& first, 
110                        const std::string::const_iterator& last,
111                        const std::string::const_iterator& last_trunc)
112  {
113    if (first==last)
114      return false;
115    const std::string::const_iterator first_orig(first);
116    if (match(first, last, std::string("changeset:")).empty()){
117      first = first_orig;
118      return false;
119    }
120    std::string rev = match(first, last, Digit());
121    if (rev.empty()){
122      first = first_orig;
123      return false;
124    }
125    std::string href(Configuration::instance().trac_root()+"changeset/"+rev);
126    hs_.stream() << anchor(href, anchor_text(first_orig,first, last_trunc)); 
127    return true;
128  }
129
130
131  bool Trac::comment(std::string::const_iterator& first, 
132                     const std::string::const_iterator& last,
133                     const std::string::const_iterator& last_trunc)
134  {
135    if (first==last)
136      return false;
137
138    const std::string::const_iterator first_orig(first);
139    if (match(first, last, std::string("comment:ticket:")).empty()){
140      first = first_orig;
141      return false;
142    }
143     
144    std::string ticket = match(first, last, AlNum());
145    if (ticket.empty() || first == last || *first != ':') {
146      first = first_orig;
147      return false;
148    }
149    ++first;
150    std::string comment = match(first, last, Digit());
151    if (comment.empty() ) {
152      first = first_orig;
153      return false;
154    }
155    std::string href(Configuration::instance().trac_root()+"ticket/"+ticket+
156                     "#comment:"+comment);
157    hs_.stream() << anchor(href, anchor_text(first_orig,first, last_trunc)); 
158    return true;
159  }
160
161
162  bool Trac::diff(std::string::const_iterator& first, 
163                  const std::string::const_iterator& last,
164                  const std::string::const_iterator& last_trunc)
165  {
166    if (diff3(first, last, last_trunc))
167      return true;
168    if (diff1(first, last, last_trunc))
169      return true;
170    if (diff2(first, last, last_trunc))
171      return true;
172    return false;
173  }
174
175
176  bool Trac::diff1(std::string::const_iterator& first, 
177                   const std::string::const_iterator& last,
178                   const std::string::const_iterator& last_trunc)
179  {
180    if (first==last)
181      return false;
182
183    const std::string::const_iterator first_orig(first);
184    if (match(first, last, std::string("diff:")).empty()){
185      first = first_orig;
186      return false;
187    }
188    std::string node = match(first, last, notChar('@'));
189    if (first==last){
190      first = first_orig;
191      return false;
192    }
193    ++first; 
194    std::string old_rev = match(first, last, AlNum());
195    if (old_rev.empty() || first == last || *first != ':') {
196      first = first_orig;
197      return false;
198    }
199    ++first;
200    std::string new_rev = match(first, last, AlNum());
201    if (new_rev.empty() ) {
202      first = first_orig;
203      return false;
204    }
205    std::string href;
206    if (node.empty())
207      href = std::string(Configuration::instance().trac_root()+
208                         "changeset?new="+new_rev+"&amp;old="+old_rev);
209    else
210      href = std::string(Configuration::instance().trac_root()+
211                         "changeset?new="+new_rev+"&amp;new_path="+node+
212                         "&amp;old="+old_rev+"&amp;old_path="+node);
213    hs_.stream() << anchor(href, anchor_text(first_orig,first, last_trunc)); 
214    return true;
215  }
216
217
218  bool Trac::diff2(std::string::const_iterator& first, 
219                   const std::string::const_iterator& last,
220                   const std::string::const_iterator& last_trunc)
221  {
222    if (first==last)
223      return false;
224
225    const std::string::const_iterator first_orig(first);
226    if (match(first, last, std::string("diff:")).empty()){
227      first = first_orig;
228      return false;
229    }
230    std::string old_path(match(first, last, not2Str("//", " ")));
231    std::string new_path;
232    if (first==last || *first==' ')
233      new_path = old_path;
234    else {
235      first += 2;
236      new_path = match(first, last, notChar(' '));
237    }
238    if (new_path.empty() || old_path.empty()){
239      first = first_orig;
240      return false;
241    }
242    std::string href(Configuration::instance().trac_root()+
243                     "changeset?new_path="+new_path+"&amp;old_path="+old_path);
244    hs_.stream() << anchor(href, anchor_text(first_orig,first, last_trunc)); 
245    return true;
246  }
247
248
249  bool Trac::diff3(std::string::const_iterator& first, 
250                   const std::string::const_iterator& last,
251                   const std::string::const_iterator& last_trunc)
252  {
253    if (first==last)
254      return false;
255
256    const std::string::const_iterator first_orig(first);
257    if (match(first, last, std::string("diff:")).empty()){
258      first = first_orig;
259      return false;
260    }
261    std::string old_path(match(first, last, not2Char('@', ' ')));
262    if (*first!='@'){
263      first = first_orig;
264      return false;
265    }
266    ++first;
267    std::string old_rev(match(first, last, AlNum()));
268    if (match(first, last, std::string("//")).empty()) {
269      first = first_orig;
270      return false;
271    }
272    std::string new_path = match(first, last, not2Char('@', ' '));
273    if (*first!='@'){
274      first = first_orig;
275      return false;
276    }
277    ++first;
278    std::string new_rev(match(first, last, AlNum()));
279    if (new_rev.empty()){
280      first = first_orig;
281      return false;
282    }
283   
284    std::string href(Configuration::instance().trac_root()+
285                     "changeset?new="+new_rev+"&amp;new_path="+new_path+
286                     "&amp;old="+old_rev+"&amp;old_path="+old_path);
287    hs_.stream() << anchor(href, anchor_text(first_orig,first, last_trunc)); 
288    return true;
289  }
290
291
292  bool Trac::log(std::string::const_iterator& first, 
293                 const std::string::const_iterator& last,
294                 const std::string::const_iterator& last_trunc)
295  {
296    if (log1(first, last, last_trunc))
297      return true;
298    if (log2(first, last, last_trunc))
299      return true;
300    if (log3(first, last, last_trunc))
301      return true;
302    return false;
303  }
304
305
306  bool Trac::log1(std::string::const_iterator& first, 
307                  const std::string::const_iterator& last,
308                  const std::string::const_iterator& last_trunc)
309  {
310    if (first==last)
311      return false;
312
313    const std::string::const_iterator first_orig(first);
314    if (*first != 'r')
315      return false;
316    ++first;
317
318    std::string stop_rev = match(first, last, AlNum());
319    if (stop_rev.empty() || first == last || *first != ':') {
320      first = first_orig;
321      return false;
322    }
323    ++first;
324    std::string rev = match(first, last, AlNum());
325    if (rev.empty() ) {
326      first = first_orig;
327      return false;
328    }
329    std::string href(Configuration::instance().trac_root()+"log/?rev="+
330                     rev+"&amp;stop_rev="+stop_rev);
331    hs_.stream() << anchor(href, anchor_text(first_orig,first, last_trunc)); 
332    return true;
333  }
334
335
336  bool Trac::log2(std::string::const_iterator& first, 
337                  const std::string::const_iterator& last,
338                  const std::string::const_iterator& last_trunc)
339  {
340    if (first==last)
341      return false;
342
343    const std::string::const_iterator first_orig(first);
344    if (*first != '[')
345      return false;
346    ++first;
347
348    std::string stop_rev = match(first, last, AlNum());
349    if (stop_rev.empty() || first == last || *first != ':') {
350      first = first_orig;
351      return false;
352    }
353    ++first;
354    std::string rev = match(first, last, AlNum());
355    if (rev.empty() || first == last || *first != ']') {
356      first = first_orig;
357      return false;
358    }
359    ++first; // eating ']'
360    std::string href(Configuration::instance().trac_root()+"log/?rev="+
361                     rev+"&amp;stop_rev="+stop_rev);
362    hs_.stream() << anchor(href, anchor_text(first_orig,first, last_trunc)); 
363    return true;
364  }
365
366
367  bool Trac::log3(std::string::const_iterator& first, 
368                  const std::string::const_iterator& last,
369                  const std::string::const_iterator& last_trunc)
370  {
371    if (first==last)
372      return false;
373
374    const std::string::const_iterator first_orig(first);
375
376    const std::string log_str("log:"); 
377    if (!match_begin(first, last, log_str)) {
378      first = first_orig;
379      return false;
380    }
381    first += log_str.size();
382    std::string node = match(first, last, not2Char('#', '@'));
383    ++first;
384    std::string stop_rev = match(first, last, AlNum());
385    if (stop_rev.empty() || first == last || *first != ':') {
386      first = first_orig;
387      return false;
388    }
389    ++first;
390    std::string rev = match(first, last, AlNum());
391    if (rev.empty() ) {
392      first = first_orig;
393      return false;
394    }
395    std::string href;
396    if (!node.empty() && node[0]=='/')
397      href = std::string(Configuration::instance().trac_root()+"log"+node+
398                         "?rev="+rev+"&amp;stop_rev="+stop_rev);
399    else
400      href = std::string(Configuration::instance().trac_root()+"log/"+node+
401                         "?rev="+rev+"&amp;stop_rev="+stop_rev);
402     
403    hs_.stream() << anchor(href, anchor_text(first_orig,first, last_trunc)); 
404    return true;
405  }
406
407
408  bool Trac::milestone(std::string::const_iterator& first, 
409                       const std::string::const_iterator& last,
410                       const std::string::const_iterator& last_trunc)
411  {
412    if (first==last)
413      return false;
414
415    const std::string::const_iterator first_orig(first);
416
417    if (match(first, last, std::string("milestone:")).empty()){
418      first = first_orig;
419      return false;
420    }
421
422    const std::string::const_iterator milestone_begin(first);
423
424    // find the last alphanumerical char before next space (or last)
425    for (std::string::const_iterator i(first); i!=last && *i!=' '; ++i)
426      if (isalnum(*i)) 
427        first = i+1;
428
429    std::string milestone(milestone_begin, first);
430    if (milestone.empty()){
431      first = first_orig;
432      return false;
433    }
434
435    const Configuration& conf = Configuration::instance();
436    std::string href(conf.trac_root()+"milestone/"+milestone);
437    hs_.stream() << anchor(href, anchor_text(first_orig,first, last_trunc)); 
438    return true;
439  }
440
441
442  void Trac::print(std::string str, size_t width)
443  {
444    std::string::const_iterator first(str.begin());
445    std::string::const_iterator last_trunc(str.end());
446    if (width<=str.size()) // truncate
447      last_trunc = first+width;
448    while (first<last_trunc) {
449      if (log(first, str.end(), last_trunc))
450        continue;
451      if (comment(first, str.end(), last_trunc))
452        continue;
453      if (ticket(first, str.end(), last_trunc))
454        continue;
455      if (changeset(first, str.end(), last_trunc))
456        continue;
457      if (diff(first, str.end(), last_trunc))
458        continue;
459      if (milestone(first, str.end(), last_trunc))
460        continue;
461      if (source(first, str.end(), last_trunc))
462        continue;
463      hs_ << *first;
464      ++first;
465    }
466    if (last_trunc!=str.end())
467      hs_ << "...";
468  }
469
470
471  bool Trac::source(std::string::const_iterator& first, 
472                    const std::string::const_iterator& last,
473                    const std::string::const_iterator& last_trunc)
474  {
475    if (first==last)
476      return false;
477
478    const std::string::const_iterator first_orig(first);
479
480    if (match(first, last, std::string("source:")).empty()){
481      first = first_orig;
482      return false;
483    }
484
485    std::string node;
486    std::string rev;
487    std::string line;
488    const std::string::const_iterator node_begin(first);
489
490    node = match(first, last, not2Char('@', ' '));
491    if (!node.empty() && node[0]=='/')
492      node = node.substr(1, node.size()-1); 
493 
494    if (*first == '@'){
495      ++first;
496      rev = match(first, last, AlNum());
497      if (*first == '#') {
498        ++first;
499        line = match(first, last, notChar(' '));
500      }
501    }
502
503    const Configuration& conf = Configuration::instance();
504    std::string href(conf.trac_root()+"browser/"+node);
505    if (!rev.empty()) {
506      href += "?rev="+rev;
507      if (!line.empty())
508        href += "#"+line;
509    }
510    hs_.stream() << anchor(href, anchor_text(first_orig,first, last_trunc)); 
511    return true;
512  }
513
514
515  bool Trac::ticket(std::string::const_iterator& first, 
516                    const std::string::const_iterator& last,
517                    const std::string::const_iterator& last_trunc)
518  {
519    if (ticket1(first, last, last_trunc))
520      return true;
521    if (ticket2(first, last, last_trunc))
522      return true;
523    return false;
524  }
525
526
527  bool Trac::ticket1(std::string::const_iterator& first, 
528                     const std::string::const_iterator& last,
529                     const std::string::const_iterator& last_trunc)
530  {
531    if (first==last)
532      return false;
533
534    const std::string::const_iterator first_orig(first);
535    if (*first != '#')
536      return false;
537    ++first;
538    std::string ticket = match(first, last, Digit());
539
540    if (ticket.empty()) {
541      first = first_orig;
542      return false;
543    }
544
545    const Configuration& conf = Configuration::instance();
546    hs_.stream() << anchor(conf.trac_root()+"ticket/"+ticket,
547                           anchor_text(first_orig,first, last_trunc)); 
548    return true;
549  }
550
551
552  bool Trac::ticket2(std::string::const_iterator& first, 
553                     const std::string::const_iterator& last,
554                     const std::string::const_iterator& last_trunc)
555  {
556    if (first==last)
557      return false;
558
559    const std::string::const_iterator first_orig(first);
560
561    if (match(first, last, std::string("ticket:")).empty()){
562      first = first_orig; 
563      return false;
564    }
565    std::string ticket = match(first, last, Digit());
566
567    const Configuration& conf = Configuration::instance();
568    std::string href(conf.trac_root()+"ticket/"+ticket);
569    hs_.stream() << anchor(href, anchor_text(first_orig,first, last_trunc)); 
570    return true;
571  }
572
573
574}} // end of namespace svndigest and namespace theplu
Note: See TracBrowser for help on using the repository browser.