gravatar
alpar (Alpar Juttner)
alpar@cs.elte.hu
Merge
0 4 0
merge default
1 file changed with 27 insertions and 17 deletions:
↑ Collapse diff ↑
Show white space 1024 line context
1 1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2 2
 *
3 3
 * This file is a part of LEMON, a generic C++ optimization library.
4 4
 *
5 5
 * Copyright (C) 2003-2008
6 6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8 8
 *
9 9
 * Permission to use, modify and distribute this software is granted
10 10
 * provided that this copyright notice appears in all copies. For
11 11
 * precise terms see the accompanying LICENSE file.
12 12
 *
13 13
 * This software is provided "AS IS" with no warranty of any kind,
14 14
 * express or implied, and with no claim as to its suitability for any
15 15
 * purpose.
16 16
 *
17 17
 */
18 18

	
19 19
#ifndef LEMON_BFS_H
20 20
#define LEMON_BFS_H
21 21

	
22 22
///\ingroup search
23 23
///\file
24 24
///\brief BFS algorithm.
25 25

	
26 26
#include <lemon/list_graph.h>
27 27
#include <lemon/bits/path_dump.h>
28 28
#include <lemon/core.h>
29 29
#include <lemon/error.h>
30 30
#include <lemon/maps.h>
31 31
#include <lemon/path.h>
32 32

	
33 33
namespace lemon {
34 34

	
35 35
  ///Default traits class of Bfs class.
36 36

	
37 37
  ///Default traits class of Bfs class.
38 38
  ///\tparam GR Digraph type.
39 39
  template<class GR>
40 40
  struct BfsDefaultTraits
41 41
  {
42 42
    ///The type of the digraph the algorithm runs on.
43 43
    typedef GR Digraph;
44 44

	
45 45
    ///\brief The type of the map that stores the predecessor
46 46
    ///arcs of the shortest paths.
47 47
    ///
48 48
    ///The type of the map that stores the predecessor
49 49
    ///arcs of the shortest paths.
50 50
    ///It must meet the \ref concepts::WriteMap "WriteMap" concept.
51 51
    typedef typename Digraph::template NodeMap<typename Digraph::Arc> PredMap;
52 52
    ///Instantiates a PredMap.
53 53

	
54 54
    ///This function instantiates a PredMap.
55 55
    ///\param g is the digraph, to which we would like to define the
56 56
    ///PredMap.
57 57
    static PredMap *createPredMap(const Digraph &g)
58 58
    {
59 59
      return new PredMap(g);
60 60
    }
61 61

	
62 62
    ///The type of the map that indicates which nodes are processed.
63 63

	
64 64
    ///The type of the map that indicates which nodes are processed.
65 65
    ///It must meet the \ref concepts::WriteMap "WriteMap" concept.
66 66
    typedef NullMap<typename Digraph::Node,bool> ProcessedMap;
67 67
    ///Instantiates a ProcessedMap.
68 68

	
69 69
    ///This function instantiates a ProcessedMap.
70 70
    ///\param g is the digraph, to which
71 71
    ///we would like to define the ProcessedMap
72 72
#ifdef DOXYGEN
73 73
    static ProcessedMap *createProcessedMap(const Digraph &g)
74 74
#else
75 75
    static ProcessedMap *createProcessedMap(const Digraph &)
76 76
#endif
77 77
    {
78 78
      return new ProcessedMap();
79 79
    }
80 80

	
81 81
    ///The type of the map that indicates which nodes are reached.
82 82

	
83
    ///The type of the map that indicates which nodes are reached.
84
    ///It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept.
83
    ///The type of the map that indicates which nodes are reached.///It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept.
85 84
    typedef typename Digraph::template NodeMap<bool> ReachedMap;
86 85
    ///Instantiates a ReachedMap.
87 86

	
88 87
    ///This function instantiates a ReachedMap.
89 88
    ///\param g is the digraph, to which
90 89
    ///we would like to define the ReachedMap.
91 90
    static ReachedMap *createReachedMap(const Digraph &g)
92 91
    {
93 92
      return new ReachedMap(g);
94 93
    }
95 94

	
96 95
    ///The type of the map that stores the distances of the nodes.
97 96

	
98 97
    ///The type of the map that stores the distances of the nodes.
99 98
    ///It must meet the \ref concepts::WriteMap "WriteMap" concept.
100 99
    typedef typename Digraph::template NodeMap<int> DistMap;
101 100
    ///Instantiates a DistMap.
102 101

	
103 102
    ///This function instantiates a DistMap.
104 103
    ///\param g is the digraph, to which we would like to define the
105 104
    ///DistMap.
106 105
    static DistMap *createDistMap(const Digraph &g)
107 106
    {
108 107
      return new DistMap(g);
109 108
    }
110 109
  };
111 110

	
112 111
  ///%BFS algorithm class.
113 112

	
114 113
  ///\ingroup search
115 114
  ///This class provides an efficient implementation of the %BFS algorithm.
116 115
  ///
117 116
  ///There is also a \ref bfs() "function-type interface" for the BFS
118 117
  ///algorithm, which is convenient in the simplier cases and it can be
119 118
  ///used easier.
120 119
  ///
121 120
  ///\tparam GR The type of the digraph the algorithm runs on.
122 121
  ///The default value is \ref ListDigraph. The value of GR is not used
123 122
  ///directly by \ref Bfs, it is only passed to \ref BfsDefaultTraits.
124 123
  ///\tparam TR Traits class to set various data types used by the algorithm.
125 124
  ///The default traits class is
126 125
  ///\ref BfsDefaultTraits "BfsDefaultTraits<GR>".
127 126
  ///See \ref BfsDefaultTraits for the documentation of
128 127
  ///a Bfs traits class.
129 128
#ifdef DOXYGEN
130 129
  template <typename GR,
131 130
            typename TR>
132 131
#else
133 132
  template <typename GR=ListDigraph,
134 133
            typename TR=BfsDefaultTraits<GR> >
135 134
#endif
136 135
  class Bfs {
137 136
  public:
138 137

	
139 138
    ///The type of the digraph the algorithm runs on.
140 139
    typedef typename TR::Digraph Digraph;
141 140

	
142 141
    ///\brief The type of the map that stores the predecessor arcs of the
143 142
    ///shortest paths.
144 143
    typedef typename TR::PredMap PredMap;
145 144
    ///The type of the map that stores the distances of the nodes.
146 145
    typedef typename TR::DistMap DistMap;
147 146
    ///The type of the map that indicates which nodes are reached.
148 147
    typedef typename TR::ReachedMap ReachedMap;
149 148
    ///The type of the map that indicates which nodes are processed.
150 149
    typedef typename TR::ProcessedMap ProcessedMap;
151 150
    ///The type of the paths.
152 151
    typedef PredMapPath<Digraph, PredMap> Path;
153 152

	
154 153
    ///The traits class.
155 154
    typedef TR Traits;
156 155

	
157 156
  private:
158 157

	
159 158
    typedef typename Digraph::Node Node;
160 159
    typedef typename Digraph::NodeIt NodeIt;
161 160
    typedef typename Digraph::Arc Arc;
162 161
    typedef typename Digraph::OutArcIt OutArcIt;
163 162

	
164 163
    //Pointer to the underlying digraph.
165 164
    const Digraph *G;
166 165
    //Pointer to the map of predecessor arcs.
167 166
    PredMap *_pred;
168 167
    //Indicates if _pred is locally allocated (true) or not.
169 168
    bool local_pred;
170 169
    //Pointer to the map of distances.
171 170
    DistMap *_dist;
172 171
    //Indicates if _dist is locally allocated (true) or not.
173 172
    bool local_dist;
174 173
    //Pointer to the map of reached status of the nodes.
175 174
    ReachedMap *_reached;
176 175
    //Indicates if _reached is locally allocated (true) or not.
177 176
    bool local_reached;
178 177
    //Pointer to the map of processed status of the nodes.
179 178
    ProcessedMap *_processed;
180 179
    //Indicates if _processed is locally allocated (true) or not.
181 180
    bool local_processed;
182 181

	
183 182
    std::vector<typename Digraph::Node> _queue;
184 183
    int _queue_head,_queue_tail,_queue_next_dist;
185 184
    int _curr_dist;
186 185

	
187 186
    //Creates the maps if necessary.
188 187
    void create_maps()
189 188
    {
190 189
      if(!_pred) {
191 190
        local_pred = true;
192 191
        _pred = Traits::createPredMap(*G);
193 192
      }
194 193
      if(!_dist) {
195 194
        local_dist = true;
196 195
        _dist = Traits::createDistMap(*G);
197 196
      }
198 197
      if(!_reached) {
199 198
        local_reached = true;
200 199
        _reached = Traits::createReachedMap(*G);
201 200
      }
202 201
      if(!_processed) {
203 202
        local_processed = true;
204 203
        _processed = Traits::createProcessedMap(*G);
205 204
      }
206 205
    }
207 206

	
208 207
  protected:
209 208

	
210 209
    Bfs() {}
211 210

	
212 211
  public:
213 212

	
214 213
    typedef Bfs Create;
215 214

	
216 215
    ///\name Named template parameters
217 216

	
218 217
    ///@{
219 218

	
220 219
    template <class T>
221 220
    struct SetPredMapTraits : public Traits {
222 221
      typedef T PredMap;
223 222
      static PredMap *createPredMap(const Digraph &)
224 223
      {
225 224
        LEMON_ASSERT(false, "PredMap is not initialized");
226 225
        return 0; // ignore warnings
227 226
      }
228 227
    };
229 228
    ///\brief \ref named-templ-param "Named parameter" for setting
230 229
    ///PredMap type.
231 230
    ///
232 231
    ///\ref named-templ-param "Named parameter" for setting
233 232
    ///PredMap type.
234 233
    template <class T>
235 234
    struct SetPredMap : public Bfs< Digraph, SetPredMapTraits<T> > {
236 235
      typedef Bfs< Digraph, SetPredMapTraits<T> > Create;
237 236
    };
238 237

	
239 238
    template <class T>
240 239
    struct SetDistMapTraits : public Traits {
241 240
      typedef T DistMap;
242 241
      static DistMap *createDistMap(const Digraph &)
243 242
      {
244 243
        LEMON_ASSERT(false, "DistMap is not initialized");
245 244
        return 0; // ignore warnings
246 245
      }
247 246
    };
248 247
    ///\brief \ref named-templ-param "Named parameter" for setting
249 248
    ///DistMap type.
250 249
    ///
251 250
    ///\ref named-templ-param "Named parameter" for setting
252 251
    ///DistMap type.
253 252
    template <class T>
254 253
    struct SetDistMap : public Bfs< Digraph, SetDistMapTraits<T> > {
255 254
      typedef Bfs< Digraph, SetDistMapTraits<T> > Create;
256 255
    };
257 256

	
258 257
    template <class T>
259 258
    struct SetReachedMapTraits : public Traits {
260 259
      typedef T ReachedMap;
261 260
      static ReachedMap *createReachedMap(const Digraph &)
262 261
      {
263 262
        LEMON_ASSERT(false, "ReachedMap is not initialized");
264 263
        return 0; // ignore warnings
265 264
      }
266 265
    };
267 266
    ///\brief \ref named-templ-param "Named parameter" for setting
268 267
    ///ReachedMap type.
269 268
    ///
270 269
    ///\ref named-templ-param "Named parameter" for setting
271 270
    ///ReachedMap type.
272 271
    template <class T>
273 272
    struct SetReachedMap : public Bfs< Digraph, SetReachedMapTraits<T> > {
274 273
      typedef Bfs< Digraph, SetReachedMapTraits<T> > Create;
275 274
    };
276 275

	
277 276
    template <class T>
278 277
    struct SetProcessedMapTraits : public Traits {
279 278
      typedef T ProcessedMap;
280 279
      static ProcessedMap *createProcessedMap(const Digraph &)
281 280
      {
282 281
        LEMON_ASSERT(false, "ProcessedMap is not initialized");
283 282
        return 0; // ignore warnings
284 283
      }
285 284
    };
286 285
    ///\brief \ref named-templ-param "Named parameter" for setting
287 286
    ///ProcessedMap type.
288 287
    ///
289 288
    ///\ref named-templ-param "Named parameter" for setting
290 289
    ///ProcessedMap type.
291 290
    template <class T>
292 291
    struct SetProcessedMap : public Bfs< Digraph, SetProcessedMapTraits<T> > {
293 292
      typedef Bfs< Digraph, SetProcessedMapTraits<T> > Create;
294 293
    };
295 294

	
296 295
    struct SetStandardProcessedMapTraits : public Traits {
297 296
      typedef typename Digraph::template NodeMap<bool> ProcessedMap;
298 297
      static ProcessedMap *createProcessedMap(const Digraph &g)
299 298
      {
300 299
        return new ProcessedMap(g);
301 300
        return 0; // ignore warnings
302 301
      }
303 302
    };
304 303
    ///\brief \ref named-templ-param "Named parameter" for setting
305 304
    ///ProcessedMap type to be <tt>Digraph::NodeMap<bool></tt>.
306 305
    ///
307 306
    ///\ref named-templ-param "Named parameter" for setting
308 307
    ///ProcessedMap type to be <tt>Digraph::NodeMap<bool></tt>.
309 308
    ///If you don't set it explicitly, it will be automatically allocated.
310 309
    struct SetStandardProcessedMap :
311 310
      public Bfs< Digraph, SetStandardProcessedMapTraits > {
312 311
      typedef Bfs< Digraph, SetStandardProcessedMapTraits > Create;
313 312
    };
314 313

	
315 314
    ///@}
316 315

	
317 316
  public:
318 317

	
319 318
    ///Constructor.
320 319

	
321 320
    ///Constructor.
322 321
    ///\param g The digraph the algorithm runs on.
323 322
    Bfs(const Digraph &g) :
324 323
      G(&g),
325 324
      _pred(NULL), local_pred(false),
326 325
      _dist(NULL), local_dist(false),
327 326
      _reached(NULL), local_reached(false),
328 327
      _processed(NULL), local_processed(false)
329 328
    { }
330 329

	
331 330
    ///Destructor.
332 331
    ~Bfs()
333 332
    {
334 333
      if(local_pred) delete _pred;
335 334
      if(local_dist) delete _dist;
336 335
      if(local_reached) delete _reached;
337 336
      if(local_processed) delete _processed;
338 337
    }
339 338

	
340 339
    ///Sets the map that stores the predecessor arcs.
341 340

	
342 341
    ///Sets the map that stores the predecessor arcs.
343 342
    ///If you don't use this function before calling \ref run(),
344 343
    ///it will allocate one. The destructor deallocates this
345 344
    ///automatically allocated map, of course.
346 345
    ///\return <tt> (*this) </tt>
347 346
    Bfs &predMap(PredMap &m)
348 347
    {
349 348
      if(local_pred) {
350 349
        delete _pred;
351 350
        local_pred=false;
352 351
      }
353 352
      _pred = &m;
354 353
      return *this;
355 354
    }
356 355

	
357 356
    ///Sets the map that indicates which nodes are reached.
358 357

	
359 358
    ///Sets the map that indicates which nodes are reached.
360 359
    ///If you don't use this function before calling \ref run(),
361 360
    ///it will allocate one. The destructor deallocates this
362 361
    ///automatically allocated map, of course.
363 362
    ///\return <tt> (*this) </tt>
364 363
    Bfs &reachedMap(ReachedMap &m)
365 364
    {
366 365
      if(local_reached) {
367 366
        delete _reached;
368 367
        local_reached=false;
369 368
      }
370 369
      _reached = &m;
371 370
      return *this;
372 371
    }
373 372

	
374 373
    ///Sets the map that indicates which nodes are processed.
375 374

	
376 375
    ///Sets the map that indicates which nodes are processed.
377 376
    ///If you don't use this function before calling \ref run(),
378 377
    ///it will allocate one. The destructor deallocates this
379 378
    ///automatically allocated map, of course.
380 379
    ///\return <tt> (*this) </tt>
381 380
    Bfs &processedMap(ProcessedMap &m)
382 381
    {
383 382
      if(local_processed) {
384 383
        delete _processed;
385 384
        local_processed=false;
386 385
      }
387 386
      _processed = &m;
388 387
      return *this;
389 388
    }
390 389

	
391 390
    ///Sets the map that stores the distances of the nodes.
392 391

	
393 392
    ///Sets the map that stores the distances of the nodes calculated by
394 393
    ///the algorithm.
395 394
    ///If you don't use this function before calling \ref run(),
396 395
    ///it will allocate one. The destructor deallocates this
397 396
    ///automatically allocated map, of course.
398 397
    ///\return <tt> (*this) </tt>
399 398
    Bfs &distMap(DistMap &m)
400 399
    {
401 400
      if(local_dist) {
402 401
        delete _dist;
403 402
        local_dist=false;
404 403
      }
405 404
      _dist = &m;
406 405
      return *this;
407 406
    }
408 407

	
409 408
  public:
410 409

	
411 410
    ///\name Execution control
412 411
    ///The simplest way to execute the algorithm is to use
413 412
    ///one of the member functions called \ref lemon::Bfs::run() "run()".
414 413
    ///\n
415 414
    ///If you need more control on the execution, first you must call
416 415
    ///\ref lemon::Bfs::init() "init()", then you can add several source
417 416
    ///nodes with \ref lemon::Bfs::addSource() "addSource()".
418 417
    ///Finally \ref lemon::Bfs::start() "start()" will perform the
419 418
    ///actual path computation.
420 419

	
421 420
    ///@{
422 421

	
423 422
    ///Initializes the internal data structures.
424 423

	
425 424
    ///Initializes the internal data structures.
426 425
    ///
427 426
    void init()
428 427
    {
429 428
      create_maps();
430 429
      _queue.resize(countNodes(*G));
431 430
      _queue_head=_queue_tail=0;
432 431
      _curr_dist=1;
433 432
      for ( NodeIt u(*G) ; u!=INVALID ; ++u ) {
434 433
        _pred->set(u,INVALID);
435 434
        _reached->set(u,false);
436 435
        _processed->set(u,false);
437 436
      }
438 437
    }
439 438

	
440 439
    ///Adds a new source node.
441 440

	
442 441
    ///Adds a new source node to the set of nodes to be processed.
443 442
    ///
444 443
    void addSource(Node s)
445 444
    {
446 445
      if(!(*_reached)[s])
447 446
        {
448 447
          _reached->set(s,true);
449 448
          _pred->set(s,INVALID);
450 449
          _dist->set(s,0);
451 450
          _queue[_queue_head++]=s;
452 451
          _queue_next_dist=_queue_head;
453 452
        }
454 453
    }
455 454

	
456 455
    ///Processes the next node.
457 456

	
458 457
    ///Processes the next node.
459 458
    ///
460 459
    ///\return The processed node.
461 460
    ///
462 461
    ///\pre The queue must not be empty.
463 462
    Node processNextNode()
464 463
    {
465 464
      if(_queue_tail==_queue_next_dist) {
466 465
        _curr_dist++;
467 466
        _queue_next_dist=_queue_head;
468 467
      }
469 468
      Node n=_queue[_queue_tail++];
470 469
      _processed->set(n,true);
471 470
      Node m;
472 471
      for(OutArcIt e(*G,n);e!=INVALID;++e)
473 472
        if(!(*_reached)[m=G->target(e)]) {
474 473
          _queue[_queue_head++]=m;
475 474
          _reached->set(m,true);
476 475
          _pred->set(m,e);
477 476
          _dist->set(m,_curr_dist);
478 477
        }
479 478
      return n;
480 479
    }
481 480

	
482 481
    ///Processes the next node.
483 482

	
484 483
    ///Processes the next node and checks if the given target node
485 484
    ///is reached. If the target node is reachable from the processed
486 485
    ///node, then the \c reach parameter will be set to \c true.
487 486
    ///
488 487
    ///\param target The target node.
489 488
    ///\retval reach Indicates if the target node is reached.
490 489
    ///It should be initially \c false.
491 490
    ///
492 491
    ///\return The processed node.
493 492
    ///
494 493
    ///\pre The queue must not be empty.
495 494
    Node processNextNode(Node target, bool& reach)
496 495
    {
497 496
      if(_queue_tail==_queue_next_dist) {
498 497
        _curr_dist++;
499 498
        _queue_next_dist=_queue_head;
500 499
      }
501 500
      Node n=_queue[_queue_tail++];
502 501
      _processed->set(n,true);
503 502
      Node m;
504 503
      for(OutArcIt e(*G,n);e!=INVALID;++e)
505 504
        if(!(*_reached)[m=G->target(e)]) {
506 505
          _queue[_queue_head++]=m;
507 506
          _reached->set(m,true);
508 507
          _pred->set(m,e);
509 508
          _dist->set(m,_curr_dist);
510 509
          reach = reach || (target == m);
511 510
        }
512 511
      return n;
513 512
    }
514 513

	
515 514
    ///Processes the next node.
516 515

	
517 516
    ///Processes the next node and checks if at least one of reached
518 517
    ///nodes has \c true value in the \c nm node map. If one node
519 518
    ///with \c true value is reachable from the processed node, then the
520 519
    ///\c rnode parameter will be set to the first of such nodes.
521 520
    ///
522 521
    ///\param nm A \c bool (or convertible) node map that indicates the
523 522
    ///possible targets.
524 523
    ///\retval rnode The reached target node.
525 524
    ///It should be initially \c INVALID.
526 525
    ///
527 526
    ///\return The processed node.
528 527
    ///
529 528
    ///\pre The queue must not be empty.
530 529
    template<class NM>
531 530
    Node processNextNode(const NM& nm, Node& rnode)
532 531
    {
533 532
      if(_queue_tail==_queue_next_dist) {
534 533
        _curr_dist++;
535 534
        _queue_next_dist=_queue_head;
536 535
      }
537 536
      Node n=_queue[_queue_tail++];
538 537
      _processed->set(n,true);
539 538
      Node m;
540 539
      for(OutArcIt e(*G,n);e!=INVALID;++e)
541 540
        if(!(*_reached)[m=G->target(e)]) {
542 541
          _queue[_queue_head++]=m;
543 542
          _reached->set(m,true);
544 543
          _pred->set(m,e);
545 544
          _dist->set(m,_curr_dist);
546 545
          if (nm[m] && rnode == INVALID) rnode = m;
547 546
        }
548 547
      return n;
549 548
    }
550 549

	
551 550
    ///The next node to be processed.
552 551

	
553 552
    ///Returns the next node to be processed or \c INVALID if the queue
554 553
    ///is empty.
555 554
    Node nextNode() const
556 555
    {
557 556
      return _queue_tail<_queue_head?_queue[_queue_tail]:INVALID;
558 557
    }
559 558

	
560 559
    ///\brief Returns \c false if there are nodes
561 560
    ///to be processed.
562 561
    ///
563 562
    ///Returns \c false if there are nodes
564 563
    ///to be processed in the queue.
565 564
    bool emptyQueue() const { return _queue_tail==_queue_head; }
566 565

	
567 566
    ///Returns the number of the nodes to be processed.
568 567

	
569 568
    ///Returns the number of the nodes to be processed in the queue.
570 569
    int queueSize() const { return _queue_head-_queue_tail; }
571 570

	
572 571
    ///Executes the algorithm.
573 572

	
574 573
    ///Executes the algorithm.
575 574
    ///
576 575
    ///This method runs the %BFS algorithm from the root node(s)
577 576
    ///in order to compute the shortest path to each node.
578 577
    ///
579 578
    ///The algorithm computes
580 579
    ///- the shortest path tree (forest),
581 580
    ///- the distance of each node from the root(s).
582 581
    ///
583 582
    ///\pre init() must be called and at least one root node should be
584 583
    ///added with addSource() before using this function.
585 584
    ///
586 585
    ///\note <tt>b.start()</tt> is just a shortcut of the following code.
587 586
    ///\code
588 587
    ///  while ( !b.emptyQueue() ) {
589 588
    ///    b.processNextNode();
590 589
    ///  }
591 590
    ///\endcode
592 591
    void start()
593 592
    {
594 593
      while ( !emptyQueue() ) processNextNode();
595 594
    }
596 595

	
Show white space 1024 line context
1 1
#!/bin/bash
2 2

	
3 3
YEAR=`date +2003-%Y`
4 4
HGROOT=`hg root`
5 5

	
6 6
# file enumaration modes
7 7

	
8 8
function all_files() {
9 9
    hg status -a -m -c |
10 10
    cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' |
11 11
    while read file; do echo $HGROOT/$file; done
12 12
}
13 13

	
14 14
function modified_files() {
15 15
    hg status -a -m |
16 16
    cut -d ' ' -f 2 | grep -E  '(\.(cc|h|dox)$|Makefile\.am$)' |
17 17
    while read file; do echo $HGROOT/$file; done
18 18
}
19 19

	
20 20
function changed_files() {
21 21
    {
22 22
        if [ -n "$HG_PARENT1" ]
23 23
        then
24 24
            hg status --rev $HG_PARENT1:$HG_NODE -a -m
25 25
        fi
26 26
        if [ -n "$HG_PARENT2" ]
27 27
        then
28 28
            hg status --rev $HG_PARENT2:$HG_NODE -a -m
29 29
        fi
30 30
    } | cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' | 
31 31
    sort | uniq |
32 32
    while read file; do echo $HGROOT/$file; done
33 33
}
34 34

	
35 35
function given_files() {
36 36
    for file in $GIVEN_FILES
37 37
    do
38 38
	echo $file
39 39
    done
40 40
}
41 41

	
42 42
# actions
43 43

	
44 44
function update_action() {
45 45
    if ! diff -q $1 $2 >/dev/null
46 46
    then
47 47
	echo -n " [$3 updated]"
48 48
	rm $2
49 49
	mv $1 $2
50 50
	CHANGED=YES
51 51
    fi
52 52
}
53 53

	
54 54
function update_warning() {
55 55
    echo -n " [$2 warning]"
56 56
    WARNED=YES
57 57
}
58 58

	
59 59
function update_init() {
60 60
    echo Update source files...
61 61
    TOTAL_FILES=0
62 62
    CHANGED_FILES=0
63 63
    WARNED_FILES=0
64 64
}
65 65

	
66 66
function update_done() {
67 67
    echo $CHANGED_FILES out of $TOTAL_FILES files has been changed.
68 68
    echo $WARNED_FILES out of $TOTAL_FILES files triggered warnings.
69 69
}
70 70

	
71 71
function update_begin() {
72 72
    ((TOTAL_FILES++))
73 73
    CHANGED=NO
74 74
    WARNED=NO
75 75
}
76 76

	
77 77
function update_end() {
78 78
    if [ $CHANGED == YES ]
79 79
    then
80 80
	((++CHANGED_FILES))
81 81
    fi
82 82
    if [ $WARNED == YES ]
83 83
    then
84 84
	((++WARNED_FILES))
85 85
    fi
86 86
}
87 87

	
88 88
function check_action() {
89 89
    if ! diff -q $1 $2 >/dev/null
90 90
    then
91
	echo -n " [$3 failed]"
91
	echo
92
	echo -n "      $3 failed at line(s): "
93
	echo -n $(diff $1 $2 | grep '^[0-9]' | sed "s/^\(.*\)c.*$/ \1/g" | 
94
	          sed "s/,/-/g" | paste -s -d',')
92 95
	FAILED=YES
93 96
    fi
94 97
}
95 98

	
96 99
function check_warning() {
97
    echo -n " [$2 warning]"
100
    echo
101
    if [ "$2" == 'long lines' ]
102
    then
103
        echo -n "      $2 warning at line(s): "
104
        echo -n $(grep -n -E '.{81,}' $1 | sed "s/^\([0-9]*\)/ \1\t/g" | 
105
                  cut -f 1 | paste -s -d',')
106
    else
107
        echo -n "      $2 warning"
108
    fi
98 109
    WARNED=YES
99 110
}
100 111

	
101 112
function check_init() {
102 113
    echo Check source files...
103 114
    FAILED_FILES=0
104 115
    WARNED_FILES=0
105 116
    TOTAL_FILES=0
106 117
}
107 118

	
108 119
function check_done() {
109 120
    echo $FAILED_FILES out of $TOTAL_FILES files has been failed.
110 121
    echo $WARNED_FILES out of $TOTAL_FILES files triggered warnings.
111 122

	
112 123
    if [ $FAILED_FILES -gt 0 ]
113 124
    then
114 125
	return 1
115 126
    elif [ $WARNED_FILES -gt 0 ]
116 127
    then
117 128
	if [ "$WARNING" == 'INTERACTIVE' ]
118 129
	then
119 130
	    echo -n "Are the files with warnings acceptable? (yes/no) "
120 131
	    while read answer
121 132
	    do
122 133
		if [ "$answer" == 'yes' ]
123 134
		then
124 135
		    return 0
125 136
		elif [ "$answer" == 'no' ]
126 137
		then
127 138
		    return 1
128 139
		fi
129 140
		echo -n "Are the files with warnings acceptable? (yes/no) "
130 141
	    done
131 142
	elif [ "$WARNING" == 'WERROR' ]
132 143
	then
133 144
	    return 1
134 145
	fi
135 146
    fi
136 147
}
137 148

	
138 149
function check_begin() {
139 150
    ((TOTAL_FILES++))
140 151
    FAILED=NO
141 152
    WARNED=NO
142 153
}
143 154

	
144 155
function check_end() {
145 156
    if [ $FAILED == YES ]
146 157
    then
147 158
	((++FAILED_FILES))
148 159
    fi
149 160
    if [ $WARNED == YES ]
150 161
    then
151 162
	((++WARNED_FILES))
152 163
    fi
153 164
}
154 165

	
155 166

	
156 167

	
157 168
# checks
158 169

	
159 170
function header_check() {
160 171
    if echo $1 | grep -q -E 'Makefile\.am$'
161 172
    then
162 173
	return
163 174
    fi
164 175

	
165 176
    TMP_FILE=`mktemp`
166 177

	
167 178
    (echo "/* -*- mode: C++; indent-tabs-mode: nil; -*-
168 179
 *
169 180
 * This file is a part of LEMON, a generic C++ optimization library.
170 181
 *
171 182
 * Copyright (C) "$YEAR"
172 183
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
173 184
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
174 185
 *
175 186
 * Permission to use, modify and distribute this software is granted
176 187
 * provided that this copyright notice appears in all copies. For
177 188
 * precise terms see the accompanying LICENSE file.
178 189
 *
179 190
 * This software is provided \"AS IS\" with no warranty of any kind,
180 191
 * express or implied, and with no claim as to its suitability for any
181 192
 * purpose.
182 193
 *
183 194
 */
184 195
"
185 196
    awk 'BEGIN { pm=0; }
186 197
     pm==3 { print }
187 198
     /\/\* / && pm==0 { pm=1;}
188 199
     /[^:blank:]/ && (pm==0 || pm==2) { pm=3; print;}
189 200
     /\*\// && pm==1 { pm=2;}
190 201
    ' $1
191 202
    ) >$TMP_FILE
192 203

	
193 204
    "$ACTION"_action "$TMP_FILE" "$1" header
194 205
}
195 206

	
196 207
function tabs_check() {
197 208
    if echo $1 | grep -q -v -E 'Makefile\.am$'
198 209
    then
199 210
        OLD_PATTERN=$(echo -e '\t')
200 211
        NEW_PATTERN='        '
201 212
    else
202 213
        OLD_PATTERN='        '
203 214
        NEW_PATTERN=$(echo -e '\t')
204 215
    fi
205 216
    TMP_FILE=`mktemp`
206 217
    cat $1 | sed -e "s/$OLD_PATTERN/$NEW_PATTERN/g" >$TMP_FILE
207 218

	
208 219
    "$ACTION"_action "$TMP_FILE" "$1" 'tabs'
209 220
}
210 221

	
211 222
function spaces_check() {
212 223
    TMP_FILE=`mktemp`
213 224
    cat $1 | sed -e 's/ \+$//g' >$TMP_FILE
214 225

	
215
    "$ACTION"_action "$TMP_FILE" "$1" 'spaces'
226
    "$ACTION"_action "$TMP_FILE" "$1" 'trailing spaces'
216 227
}
217 228

	
218 229
function long_lines_check() {
219 230
    if cat $1 | grep -q -E '.{81,}'
220 231
    then
221 232
	"$ACTION"_warning $1 'long lines'
222 233
    fi
223 234
}
224 235

	
225 236
# process the file
226 237

	
227 238
function process_file() {
228
    echo -n "    $ACTION " $1...
239
    echo -n "    $ACTION $1..."
229 240

	
230 241
    CHECKING="header tabs spaces long_lines"
231 242

	
232 243
    "$ACTION"_begin $1
233 244
    for check in $CHECKING
234 245
    do
235 246
	"$check"_check $1
236 247
    done
237 248
    "$ACTION"_end $1
238 249
    echo
239 250
}
240 251

	
241 252
function process_all {
242 253
    "$ACTION"_init
243 254
    while read file
244 255
    do
245 256
	process_file $file
246 257
    done < <($FILES)
247 258
    "$ACTION"_done
248 259
}
249 260

	
250 261
while [ $# -gt 0 ]
251 262
do
252 263
    
253 264
    if [ "$1" == '--help' ] || [ "$1" == '-h' ]
254 265
    then
255 266
	echo -n \
256 267
"Usage:
257 268
  $0 [OPTIONS] [files]
258 269
Options:
259 270
  --dry-run|-n
260 271
     Check the files, but do not modify them.
261 272
  --interactive|-i
262 273
     If --dry-run is specified and the checker emits warnings,
263 274
     then the user is asked if the warnings should be considered
264 275
     errors.
265 276
  --werror|-w
266 277
     Make all warnings into errors.
267 278
  --all|-a
268
     All files in the repository will be checked.
279
     Check all source files in the repository.
269 280
  --modified|-m
270 281
     Check only the modified (and new) source files. This option is
271 282
     useful to check the modification before making a commit.
272 283
  --changed|-c
273 284
     Check only the changed source files compared to the parent(s) of
274 285
     the current hg node.  This option is useful as hg hook script.
275 286
     To automatically check all your changes before making a commit,
276 287
     add the following section to the appropriate .hg/hgrc file.
277 288

	
278 289
       [hooks]
279 290
       pretxncommit.checksources = scripts/unify-sources.sh -c -n -i
280 291

	
281 292
  --help|-h
282 293
     Print this help message.
283 294
  files
284
     The files to check/unify. If no file names are given, the
285
     modified source will be checked/unified
286

	
295
     The files to check/unify. If no file names are given, the modified
296
     source files will be checked/unified (just like using the
297
     --modified|-m option).
287 298
"
288 299
        exit 0
289 300
    elif [ "$1" == '--dry-run' ] || [ "$1" == '-n' ]
290 301
    then
291
	[ -n "$ACTION" ] && echo "Invalid option $1" >&2 && exit 1
302
	[ -n "$ACTION" ] && echo "Conflicting action options" >&2 && exit 1
292 303
	ACTION=check
293 304
    elif [ "$1" == "--all" ] || [ "$1" == '-a' ]
294 305
    then
295
	[ -n "$FILES" ] && echo "Invalid option $1" >&2 && exit 1
306
	[ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1
296 307
	FILES=all_files
297 308
    elif [ "$1" == "--changed" ] || [ "$1" == '-c' ]
298 309
    then
299
	[ -n "$FILES" ] && echo "Invalid option $1" >&2 && exit 1
310
	[ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1
300 311
	FILES=changed_files
301 312
    elif [ "$1" == "--modified" ] || [ "$1" == '-m' ]
302 313
    then
303
	[ -n "$FILES" ] && echo "Invalid option $1" >&2 && exit 1
314
	[ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1
304 315
	FILES=modified_files
305 316
    elif [ "$1" == "--interactive" ] || [ "$1" == "-i" ]
306 317
    then
307
	[ -n "$WARNING" ] && echo "Invalid option $1" >&2 && exit 1
318
	[ -n "$WARNING" ] && echo "Conflicting warning options" >&2 && exit 1
308 319
	WARNING='INTERACTIVE'
309 320
    elif [ "$1" == "--werror" ] || [ "$1" == "-w" ]
310 321
    then
311
	[ -n "$WARNING" ] && echo "Invalid option $1" >&2 && exit 1
322
	[ -n "$WARNING" ] && echo "Conflicting warning options" >&2 && exit 1
312 323
	WARNING='WERROR'
313
    elif [ $(echo $1 | cut -c 1) == '-' ]
324
    elif [ $(echo x$1 | cut -c 2) == '-' ]
314 325
    then
315 326
	echo "Invalid option $1" >&2 && exit 1
316 327
    else
317 328
	[ -n "$FILES" ] && echo "Invalid option $1" >&2 && exit 1
318 329
	GIVEN_FILES=$@
319 330
	FILES=given_files
320 331
	break
321 332
    fi
322 333
    
323 334
    shift
324 335
done
325 336

	
326 337
if [ -z $FILES ]
327 338
then
328 339
    FILES=modified_files
329 340
fi
330 341

	
331 342
if [ -z $ACTION ]
332 343
then
333 344
    ACTION=update
334 345
fi
335 346

	
336 347
process_all
0 comments (0 inline)