Merge lp:~nha/widelands/fixes into lp:widelands

Proposed by Nicolai Hähnle
Status: Merged
Merged at revision: not available
Proposed branch: lp:~nha/widelands/fixes
Merge into: lp:widelands
Diff against target: 700 lines (+225/-79)
14 files modified
src/log.cc (+2/-2)
src/log.h (+2/-0)
src/logic/bob.cc (+0/-8)
src/logic/bob.h (+7/-1)
src/logic/immovable.cc (+25/-3)
src/logic/immovable.h (+9/-0)
src/logic/instances.cc (+3/-0)
src/logic/map.cc (+2/-0)
src/logic/soldier.cc (+64/-55)
src/logic/worker.cc (+41/-9)
src/logic/worker.h (+3/-0)
src/ui_basic/editbox.cc (+58/-1)
src/ui_basic/editbox.h (+2/-0)
src/wlapplication.cc (+7/-0)
To merge this branch: bzr merge lp:~nha/widelands/fixes
Reviewer Review Type Date Requested Status
Widelands Developers Pending
Review via email: mp+22326@code.launchpad.net

Description of the change

Various small fixes and behavior changes that I suggest for merging after the release of build15.

To post a comment you must log in.
Revision history for this message
SirVer (sirver) wrote :

Nicolai, most of these are no brainers and i agree of merging them.

However about the reserved thing please see my comment on the bug report.

Revision history for this message
Raul Ferriz (raul.ferriz) wrote :

I have checked the code, but not try to compile and run. It is safe, some clean up and longer waiting checks for soldiers when waiting a signal.
The only but is that I think that this can break replays.

Revision history for this message
Nicolai Hähnle (nha) wrote :

Yes, it does break replays. I don't think this is a problem, since we have never guaranteed compatibility of replays.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/log.cc'
2--- src/log.cc 2010-03-27 23:50:23 +0000
3+++ src/log.cc 2010-04-13 18:44:39 +0000
4@@ -25,6 +25,8 @@
5
6 extern std::ostream & wout;
7
8+bool g_verbose = false;
9+
10 void log(const char * const fmt, ...) {
11 char buffer[2048];
12 va_list va;
13@@ -33,8 +35,6 @@
14 vsnprintf(buffer, sizeof(buffer), fmt, va);
15 va_end(va);
16
17- //TODO: use iostreams instead of vprintf because other parts of
18- // Widelands use iostreams
19 wout << buffer;
20 wout.flush();
21 }
22
23=== modified file 'src/log.h'
24--- src/log.h 2010-03-27 23:50:23 +0000
25+++ src/log.h 2010-04-13 18:44:39 +0000
26@@ -33,4 +33,6 @@
27 // wout is either std::cout or specified logfile.
28 void log(const char *, ...) PRINTF_FORMAT(1, 2);
29
30+extern bool g_verbose;
31+
32 #endif
33
34=== modified file 'src/logic/bob.cc'
35--- src/logic/bob.cc 2010-04-04 12:32:35 +0000
36+++ src/logic/bob.cc 2010-04-13 18:44:39 +0000
37@@ -692,10 +692,6 @@
38 void Bob::movepath_update(Game & game, State & state)
39 {
40 if (get_signal().size()) {
41- if (serial() == 3755)
42- molog
43- ("[movepath_update] signal '%s'; popping task\n",
44- get_signal().c_str());
45 return pop_task(game);
46 }
47
48@@ -919,10 +915,6 @@
49 m_walkstart = game.get_gametime();
50 m_walkend = m_walkstart + tdelta;
51
52- if (serial() == 3755)
53- molog
54- ("[start_walk]: changint position from (%i, %i) to (%i, %i)\n",
55- get_position().x, get_position().y, newnode.x, newnode.y);
56 set_position(game, newnode);
57 set_animation(game, a);
58
59
60=== modified file 'src/logic/bob.h'
61--- src/logic/bob.h 2010-04-03 16:44:44 +0000
62+++ src/logic/bob.h 2010-04-13 18:44:39 +0000
63@@ -323,11 +323,17 @@
64 bool is_walking() {return m_walking != IDLE;}
65
66
67+ /**
68+ * This is a hack that should not be used, if possible.
69+ * It is only introduced here because profiling showed
70+ * that soldiers spend a lot of time in the node blocked check.
71+ */
72+ Bob * get_next_on_field() const {return m_linknext;}
73+
74 protected:
75 Bob(const Descr & descr);
76 virtual ~Bob();
77
78-
79 private:
80 void do_act(Game &);
81 void do_pop_task(Game &);
82
83=== modified file 'src/logic/immovable.cc'
84--- src/logic/immovable.cc 2010-04-01 11:19:48 +0000
85+++ src/logic/immovable.cc 2010-04-13 18:44:39 +0000
86@@ -337,7 +337,8 @@
87 m_anim (0),
88 m_program (0),
89 m_program_ptr (0),
90-m_program_step(0)
91+m_program_step(0),
92+m_reserved_by_worker(false)
93 {}
94
95
96@@ -471,6 +472,22 @@
97 dst.drawanim(pos, m_anim, game.get_gametime() - m_animstart, 0);
98 }
99
100+/**
101+ * Returns whether this immovable was reserved by a worker.
102+ */
103+bool Immovable::is_reserved_by_worker() const
104+{
105+ return m_reserved_by_worker;
106+}
107+
108+/**
109+ * Change whether this immovable is marked as reserved by a worker.
110+ */
111+void Immovable::set_reserved_by_worker(bool reserve)
112+{
113+ m_reserved_by_worker = reserve;
114+}
115+
116
117 /*
118 ==============================
119@@ -480,7 +497,7 @@
120 ==============================
121 */
122
123-#define IMMOVABLE_SAVEGAME_VERSION 2
124+#define IMMOVABLE_SAVEGAME_VERSION 3
125
126 void Immovable::Loader::load(FileRead & fr, uint8_t const version)
127 {
128@@ -537,6 +554,9 @@
129 }
130
131 imm.m_program_step = fr.Signed32();
132+
133+ if (version >= 3)
134+ imm.m_reserved_by_worker = fr.Unsigned8();
135 }
136
137 void Immovable::Loader::load_pointers()
138@@ -560,7 +580,7 @@
139 void Immovable::save
140 (Editor_Game_Base & egbase, Map_Map_Object_Saver & mos, FileWrite & fw)
141 {
142- // This is in front because it is required to obtain the descriptiong
143+ // This is in front because it is required to obtain the description
144 // necessary to create the Immovable
145 fw.Unsigned8(header_Immovable);
146 fw.Unsigned8(IMMOVABLE_SAVEGAME_VERSION);
147@@ -586,6 +606,8 @@
148
149 fw.Unsigned32(m_program_ptr);
150 fw.Signed32(m_program_step);
151+
152+ fw.Unsigned8(m_reserved_by_worker);
153 }
154
155 Map_Object::Loader * Immovable::load
156
157=== modified file 'src/logic/immovable.h'
158--- src/logic/immovable.h 2010-02-28 18:40:36 +0000
159+++ src/logic/immovable.h 2010-04-13 18:44:39 +0000
160@@ -153,6 +153,9 @@
161 return descr().get_owner_tribe();
162 }
163
164+ bool is_reserved_by_worker() const;
165+ void set_reserved_by_worker(bool reserve);
166+
167 protected:
168 Coords m_position;
169
170@@ -163,6 +166,12 @@
171 uint32_t m_program_ptr; ///< index of next instruction to execute
172 int32_t m_program_step; ///< time of next step
173
174+ /**
175+ * Immovables like trees are reserved by a worker that is walking
176+ * towards them, so that e.g. two lumberjacks don't attempt to
177+ * work on the same tree simultaneously.
178+ */
179+ bool m_reserved_by_worker;
180
181 // Load/save support
182 protected:
183
184=== modified file 'src/logic/instances.cc'
185--- src/logic/instances.cc 2010-03-27 23:50:23 +0000
186+++ src/logic/instances.cc 2010-04-13 18:44:39 +0000
187@@ -437,6 +437,9 @@
188 */
189 void Map_Object::molog(char const * fmt, ...) const
190 {
191+ if (!g_verbose && !m_logsink)
192+ return;
193+
194 va_list va;
195 char buffer[2048];
196
197
198=== modified file 'src/logic/map.cc'
199--- src/logic/map.cc 2010-04-03 16:44:44 +0000
200+++ src/logic/map.cc 2010-04-13 18:44:39 +0000
201@@ -1892,6 +1892,7 @@
202
203 // Recursively check integrity
204 void debug(uint32_t const node, char const * const str) {
205+#if 0
206 uint32_t l = node * 2 + 1;
207 uint32_t r = node * 2 + 2;
208 if (m_data[node]->heap_index != static_cast<int32_t>(node)) {
209@@ -1912,6 +1913,7 @@
210 }
211 debug(r, str);
212 }
213+#endif
214 }
215
216 private:
217
218=== modified file 'src/logic/soldier.cc'
219--- src/logic/soldier.cc 2010-04-04 12:32:35 +0000
220+++ src/logic/soldier.cc 2010-04-13 18:44:39 +0000
221@@ -781,7 +781,9 @@
222 if (signal == "blocked")
223 // Wait before we try again. Note that this must come *after*
224 // we check for a battle
225- return start_task_idle(game, get_animation("idle"), 250);
226+ // Note that we *should* be woken via sendSpaceSignals,
227+ // so the timeout is just an additional safety net.
228+ return start_task_idle(game, get_animation("idle"), 5000);
229
230 if (!location) {
231 molog("[attack] our location disappeared during a battle\n");
232@@ -854,7 +856,7 @@
233 (start_task_movepath
234 (game,
235 baseflag.get_position(),
236- 0,
237+ 4, // use larger persist when returning home
238 descr().get_right_walk_anims(does_carry_ware())))
239 return;
240 else {
241@@ -870,7 +872,7 @@
242 (start_task_movepath
243 (game,
244 enemy->base_flag().get_position(),
245- 2,
246+ 3,
247 descr().get_right_walk_anims(does_carry_ware())))
248 return;
249 else {
250@@ -1015,7 +1017,9 @@
251 if (signal == "blocked")
252 // Wait before we try again. Note that this must come *after*
253 // we check for a battle
254- return start_task_idle(game, get_animation("idle"), 250);
255+ // Note that we *should* be woken via sendSpaceSignals,
256+ // so the timeout is just an additional safety net.
257+ return start_task_idle(game, get_animation("idle"), 5000);
258
259 // If we only are defending our home ...
260 if (state.ivar1 & CF_DEFEND_STAYHOME) {
261@@ -1103,7 +1107,7 @@
262 (start_task_movepath
263 (game,
264 baseflag.get_position(),
265- 0,
266+ 4, // use larger persist when returning home
267 descr().get_right_walk_anims(does_carry_ware())))
268 return;
269
270@@ -1153,7 +1157,7 @@
271 (start_task_movepath
272 (game,
273 target.s->get_position(),
274- 1,
275+ 3,
276 descr().get_right_walk_anims(does_carry_ware()),
277 false,
278 1))
279@@ -1506,62 +1510,67 @@
280 bool Soldier::checkNodeBlocked
281 (Game & game, FCoords const & field, bool const commit)
282 {
283- if (!isOnBattlefield())
284- return false;
285-
286- if (upcast(Building, building, get_location(game))) {
287- if (field == building->get_position()) {
288- if (commit)
289- sendSpaceSignals(game);
290- return false; // we can always walk home
291- }
292- }
293-
294- std::vector<Bob *> soldiers;
295- game.map().find_bobs
296- (Area<FCoords>(field, 0), &soldiers, FindBobSoldierOnBattlefield());
297+ State * attackdefense = get_state(taskAttack);
298+
299+ if (!attackdefense)
300+ attackdefense = get_state(taskDefense);
301
302 if
303- (soldiers.size() &&
304- (!m_battle ||
305- std::find(soldiers.begin(), soldiers.end(), m_battle->opponent(*this))
306- ==
307- soldiers.end()))
308+ (!attackdefense ||
309+ (attackdefense->ivar1 & CF_RETREAT_WHEN_INJURED and
310+ attackdefense->ui32var3 > get_current_hitpoints()))
311 {
312- if (commit && soldiers.size() == 1) {
313- Soldier & soldier = ref_cast<Soldier, Bob>(*soldiers[0]);
314- if (soldier.get_owner() != get_owner() && soldier.canBeChallenged()) {
315+ // Retreating or non-combatant soldiers act like normal bobs
316+ return Bob::checkNodeBlocked(game, field, commit);
317+ }
318+
319+ if (field.field->get_immovable() && field.field->get_immovable() == get_location(game)) {
320+ if (commit)
321+ sendSpaceSignals(game);
322+ return false; // we can always walk home
323+ }
324+
325+ Soldier * foundsoldier = 0;
326+ bool foundbattle = false;
327+ bool foundopponent = false;
328+ bool multiplesoldiers = false;
329+
330+ for (Bob * bob = field.field->get_first_bob(); bob; bob = bob->get_next_on_field()) {
331+ if (upcast(Soldier, soldier, bob)) {
332+ if (!soldier->isOnBattlefield() || !soldier->get_current_hitpoints())
333+ continue;
334+
335+ if (!foundsoldier) {
336+ foundsoldier = soldier;
337+ } else {
338+ multiplesoldiers = true;
339+ }
340+
341+ if (soldier->getBattle()) {
342+ foundbattle = true;
343+
344+ if (m_battle && m_battle->opponent(*this) == soldier)
345+ foundopponent = true;
346+ }
347+ }
348+ }
349+
350+ if (!foundopponent && (foundbattle || foundsoldier)) {
351+ if (commit && !foundbattle && !multiplesoldiers) {
352+ if (foundsoldier->get_owner() != get_owner() && foundsoldier->canBeChallenged()) {
353 molog
354 ("[checkNodeBlocked] attacking a soldier (%u)\n",
355- soldier.serial());
356- new Battle(game, *this, soldier);
357- }
358- }
359-
360- /// Only battles block retreating soldiers
361- State * state = 0;
362-
363- if (get_state(taskAttack)) {
364- state = get_state(taskAttack);
365- }
366- if (get_state(taskDefense)) {
367- state = get_state(taskDefense);
368- }
369- if (state) {
370- if
371- (state->ivar1 & CF_RETREAT_WHEN_INJURED and
372- state->ui32var3 > get_current_hitpoints())
373- {
374- // Retreating soldiers act like normal bobs
375- return Bob::checkNodeBlocked(game, field, commit);
376- }
377- }
378+ foundsoldier->serial());
379+ new Battle(game, *this, *foundsoldier);
380+ }
381+ }
382+
383 return true;
384+ } else {
385+ if (commit)
386+ sendSpaceSignals(game);
387+ return false;
388 }
389-
390- if (commit)
391- sendSpaceSignals(game);
392- return false;
393 }
394
395
396
397=== modified file 'src/logic/worker.cc'
398--- src/logic/worker.cc 2010-03-21 20:09:51 +0000
399+++ src/logic/worker.cc 2010-04-13 18:44:39 +0000
400@@ -453,15 +453,18 @@
401
402 Map & map = game.map();
403 Area<FCoords> area (map.get_fcoords(get_position()), 0);
404- if (action.sparam1 == "immovable")
405+ if (action.sparam1 == "immovable") {
406+ bool found_reserved = false;
407+
408 for (;; ++area.radius) {
409 if (action.iparam1 < area.radius) {
410 send_signal(game, "fail"); // no object found, cannot run program
411 pop_task(game);
412- informPlayer
413- (game,
414- ref_cast<Building, PlayerImmovable>(*get_location(game)),
415- Map_Object_Descr::get_attribute_name(action.iparam2));
416+ if (!found_reserved)
417+ informPlayer
418+ (game,
419+ ref_cast<Building, PlayerImmovable>(*get_location(game)),
420+ Map_Object_Descr::get_attribute_name(action.iparam2));
421 return true;
422 }
423 std::vector<ImmovableFound> list;
424@@ -472,12 +475,21 @@
425 map.find_reachable_immovables
426 (area, &list, cstep, FindImmovableAttribute(action.iparam2));
427
428+ for (int idx = list.size() - 1; idx >= 0; idx--) {
429+ if (upcast(Immovable, imm, list[idx].object)) {
430+ if (imm->is_reserved_by_worker()) {
431+ found_reserved = true;
432+ list.erase(list.begin() + idx);
433+ }
434+ }
435+ }
436+
437 if (list.size()) {
438- state.objvar1 = list[game.logic_rand() % list.size()].object;
439+ set_program_objvar(game, state, list[game.logic_rand() % list.size()].object);
440 break;
441 }
442 }
443- else
444+ } else {
445 for (;; ++area.radius) {
446 if (action.iparam1 < area.radius) {
447 send_signal(game, "fail"); // no object found, cannot run program
448@@ -497,10 +509,11 @@
449 (area, &list, cstep, FindBobAttribute(action.iparam2));
450
451 if (list.size()) {
452- state.objvar1 = list[game.logic_rand() % list.size()];
453+ set_program_objvar(game, state, list[game.logic_rand() % list.size()]);
454 break;
455 }
456 }
457+ }
458
459 ++state.ivar1;
460 schedule_act(game, 10);
461@@ -1701,7 +1714,7 @@
462 "program",
463 static_cast<Bob::Ptr>(&Worker::program_update),
464 0,
465- 0,
466+ static_cast<Bob::Ptr>(&Worker::program_pop),
467 false
468 };
469
470@@ -1739,6 +1752,25 @@
471 }
472 }
473
474+void Worker::program_pop(Game & game, State & state)
475+{
476+ set_program_objvar(game, state, 0);
477+}
478+
479+void Worker::set_program_objvar(Game & game, State & state, Map_Object * obj)
480+{
481+ assert(state.task == &taskProgram);
482+
483+ if (upcast(Immovable, imm, state.objvar1.get(game))) {
484+ imm->set_reserved_by_worker(false);
485+ }
486+
487+ state.objvar1 = obj;
488+
489+ if (upcast(Immovable, imm, obj)) {
490+ imm->set_reserved_by_worker(true);
491+ }
492+}
493
494 const Bob::Task Worker::taskGowarehouse = {
495 "gowarehouse",
496
497=== modified file 'src/logic/worker.h'
498--- src/logic/worker.h 2010-02-28 18:40:36 +0000
499+++ src/logic/worker.h 2010-04-13 18:44:39 +0000
500@@ -181,6 +181,8 @@
501
502 bool does_carry_ware() {return m_carried_item.is_set();}
503
504+ void set_program_objvar(Game &, State &, Map_Object * obj);
505+
506 public:
507 static const Task taskTransfer;
508 static const Task taskBuildingwork;
509@@ -203,6 +205,7 @@
510 void buildingwork_update(Game &, State &);
511 void return_update(Game &, State &);
512 void program_update(Game &, State &);
513+ void program_pop(Game &, State &);
514 void gowarehouse_update(Game &, State &);
515 void gowarehouse_signalimmediate
516 (Game &,
517
518=== modified file 'src/ui_basic/editbox.cc'
519--- src/ui_basic/editbox.cc 2010-03-27 23:50:23 +0000
520+++ src/ui_basic/editbox.cc 2010-04-13 18:44:39 +0000
521@@ -46,6 +46,9 @@
522 /// Position of the caret.
523 uint32_t caret;
524
525+ /// Current scrolling offset to the text anchor position, in pixels
526+ int32_t scrolloffset;
527+
528 /// Alignment of the text. Vertical alignment is always centered.
529 Align align;
530 };
531@@ -69,8 +72,9 @@
532
533 m->id = id;
534 m->align = static_cast<Align>((_align & Align_Horizontal) | Align_VCenter);
535+ m->caret = 0;
536+ m->scrolloffset = 0;
537 // yes, use *signed* max as maximum length; just a small safe-guard.
538- m->caret = 0;
539 m->maxLength = std::numeric_limits<int32_t>::max();
540
541 set_handle_mouse(true);
542@@ -138,6 +142,7 @@
543 if (m->caret > m->text.size())
544 m->caret = m->text.size();
545
546+ check_caret();
547 update();
548 }
549 }
550@@ -163,6 +168,8 @@
551 _align = static_cast<Align>((_align & Align_Horizontal) | Align_VCenter);
552 if (_align != m->align) {
553 m->align = _align;
554+ m->scrolloffset = 0;
555+ check_caret();
556 update();
557 }
558 }
559@@ -220,6 +227,7 @@
560 while ((m->text[--m->caret] & 0xc0) == 0x80)
561 m->text.erase(m->text.begin() + m->caret);
562 m->text.erase(m->text.begin() + m->caret);
563+ check_caret();
564 changed.call();
565 changedid.call(m->id);
566 update();
567@@ -233,6 +241,7 @@
568 for (uint32_t new_caret = m->caret;; m->caret = new_caret)
569 if (0 == new_caret or isspace(m->text[--new_caret]))
570 break;
571+ check_caret();
572 update();
573 }
574 return true;
575@@ -250,6 +259,7 @@
576 m->caret = new_caret;
577 break;
578 }
579+ check_caret();
580 update();
581 }
582 return true;
583@@ -257,6 +267,7 @@
584 case SDLK_HOME:
585 if (m->caret != 0) {
586 m->caret = 0;
587+ check_caret();
588 update();
589 }
590 return true;
591@@ -264,6 +275,7 @@
592 case SDLK_END:
593 if (m->caret != m->text.size()) {
594 m->caret = m->text.size();
595+ check_caret();
596 update();
597 }
598 return true;
599@@ -296,6 +308,7 @@
600 (m->text.begin() + m->caret++,
601 ((code.unicode & 0x3f) | 0x80));
602 }
603+ check_caret();
604 changed.call();
605 changedid.call(m->id);
606 update();
607@@ -354,6 +367,8 @@
608 break;
609 }
610
611+ pos.x += m->scrolloffset;
612+
613 UI::g_fh->draw_string
614 (dst,
615 m_fontname, m_fontsize, m_fontcolor, UI_FONT_CLR_BG,
616@@ -367,4 +382,46 @@
617 std::numeric_limits<uint32_t>::max());
618 }
619
620+/**
621+ * Check the caret's position and scroll it into view if necessary.
622+ */
623+void EditBox::check_caret()
624+{
625+ std::string leftstr(m->text, 0, m->caret);
626+ std::string rightstr(m->text, m->caret, std::string::npos);
627+ uint32_t leftw;
628+ uint32_t rightw;
629+ uint32_t tmp;
630+
631+ UI::g_fh->get_size(m_fontname, m_fontsize, leftstr, leftw, tmp);
632+ UI::g_fh->get_size(m_fontname, m_fontsize, rightstr, rightw, tmp);
633+
634+ int32_t caretpos;
635+
636+ switch (m->align & Align_Horizontal) {
637+ case Align_HCenter:
638+ caretpos = (get_w() - static_cast<int32_t>(leftw + rightw)) / 2 + m->scrolloffset + leftw;
639+ break;
640+ case Align_Right:
641+ caretpos = get_w() - 4 + m->scrolloffset - rightw;
642+ break;
643+ default:
644+ caretpos = 4 + m->scrolloffset + leftw;
645+ break;
646+ }
647+
648+ if (caretpos < 4)
649+ m->scrolloffset += 4 - caretpos + get_w()/5;
650+ else if (caretpos > get_w() - 4)
651+ m->scrolloffset -= caretpos - get_w() + 4 + get_w()/5;
652+
653+ if ((m->align & Align_Horizontal) == Align_Left) {
654+ if (m->scrolloffset > 0)
655+ m->scrolloffset = 0;
656+ } else if ((m->align & Align_Horizontal) == Align_Right) {
657+ if (m->scrolloffset < 0)
658+ m->scrolloffset = 0;
659+ }
660+}
661+
662 }
663
664=== modified file 'src/ui_basic/editbox.h'
665--- src/ui_basic/editbox.h 2010-03-27 23:50:23 +0000
666+++ src/ui_basic/editbox.h 2010-04-13 18:44:39 +0000
667@@ -74,6 +74,8 @@
668 RGBColor m_fontcolor;
669
670 boost::scoped_ptr<EditBoxImpl> m;
671+
672+ void check_caret();
673 };
674
675 }
676
677=== modified file 'src/wlapplication.cc'
678--- src/wlapplication.cc 2010-04-12 09:11:24 +0000
679+++ src/wlapplication.cc 2010-04-13 18:44:39 +0000
680@@ -1116,6 +1116,12 @@
681 m_commandline.erase("double");
682 }
683
684+ if (m_commandline.count("verbose")) {
685+ g_verbose = true;
686+
687+ m_commandline.erase("verbose");
688+ }
689+
690 if (m_commandline.count("editor")) {
691 m_filename = m_commandline["editor"];
692 if (m_filename.size() and *m_filename.rbegin() == '/')
693@@ -1332,6 +1338,7 @@
694 " testing)\n\n");
695 #endif
696 #endif
697+ wout << _(" --verbose Enable verbose debug messages\n") << endl;
698 wout << _(" --help Show this help\n") << endl;
699 wout
700 <<

Subscribers

People subscribed via source and target branches

to status/vote changes: