monotone

monotone Mtn Source Tree

Root/monotone.cc

1// Copyright (C) 2002 Graydon Hoare <graydon@pobox.com>
2//
3// This program is made available under the GNU GPL version 2.0 or
4// greater. See the accompanying file COPYING for details.
5//
6// This program is distributed WITHOUT ANY WARRANTY; without even the
7// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8// PURPOSE.
9
10#include "config.h"
11
12#include "popt/popt.h"
13#include <cstdio>
14#ifndef _MSC_VER
15#include <strings.h>
16#endif
17#include <iterator>
18#include <iostream>
19#include <fstream>
20#include <sstream>
21#include <locale.h>
22
23#include <stdlib.h>
24
25#include <boost/filesystem/convenience.hpp>
26#include <boost/filesystem/path.hpp>
27
28#include "botan/botan.h"
29
30#include "i18n.h"
31
32#include "app_state.hh"
33#include "commands.hh"
34#include "sanity.hh"
35#include "cleanup.hh"
36#include "file_io.hh"
37#include "charset.hh"
38#include "ui.hh"
39#include "mt_version.hh"
40#include "options.hh"
41#include "paths.hh"
42
43using std::cout;
44using std::endl;
45using std::ios_base;
46using std::ostringstream;
47using std::set;
48using std::string;
49using std::vector;
50
51// main option processing and exception handling code
52
53char * argstr = NULL;
54long arglong = 0;
55
56// Options are split between two tables. The first one is command-specific
57// options (hence the `c' in `coptions'). The second is the global one
58// with options that aren't tied to specific commands.
59//
60// the intent is to ensure that any command specific options mean the same
61// thing to all commands that use them
62
63struct poptOption coptions[] =
64 {
65 {"branch", 'b', POPT_ARG_STRING, &argstr, OPT_BRANCH_NAME, gettext_noop("select branch cert for operation"), NULL},
66 {"revision", 'r', POPT_ARG_STRING, &argstr, OPT_REVISION, gettext_noop("select revision id for operation"), NULL},
67 {"message", 'm', POPT_ARG_STRING, &argstr, OPT_MESSAGE, gettext_noop("set commit changelog message"), NULL},
68 {"message-file", 0, POPT_ARG_STRING, &argstr, OPT_MSGFILE, gettext_noop("set filename containing commit changelog message"), NULL},
69 {"date", 0, POPT_ARG_STRING, &argstr, OPT_DATE, gettext_noop("override date/time for commit"), NULL},
70 {"author", 0, POPT_ARG_STRING, &argstr, OPT_AUTHOR, gettext_noop("override author for commit"), NULL},
71 {"depth", 0, POPT_ARG_LONG, &arglong, OPT_DEPTH, gettext_noop("limit the number of levels of directories to descend"), NULL},
72 {"last", 0, POPT_ARG_LONG, &arglong, OPT_LAST, gettext_noop("limit log output to the last number of entries"), NULL},
73 {"next", 0, POPT_ARG_LONG, &arglong, OPT_NEXT, gettext_noop("limit log output to the next number of entries"), NULL},
74 {"pid-file", 0, POPT_ARG_STRING, &argstr, OPT_PIDFILE, gettext_noop("record process id of server"), NULL},
75 {"brief", 0, POPT_ARG_NONE, NULL, OPT_BRIEF, gettext_noop("print a brief version of the normal output"), NULL},
76 {"diffs", 0, POPT_ARG_NONE, NULL, OPT_DIFFS, gettext_noop("print diffs along with logs"), NULL},
77 {"no-merges", 0, POPT_ARG_NONE, NULL, OPT_NO_MERGES, gettext_noop("exclude merges when printing logs"), NULL},
78 {"set-default", 0, POPT_ARG_NONE, NULL, OPT_SET_DEFAULT, gettext_noop("use the current arguments as the future default"), NULL},
79 {"exclude", 0, POPT_ARG_STRING, &argstr, OPT_EXCLUDE, gettext_noop("leave out anything described by its argument"), NULL},
80 {"unified", 'u', POPT_ARG_NONE, NULL, OPT_UNIFIED_DIFF, gettext_noop("use unified diff format"), NULL},
81 {"context", 'c', POPT_ARG_NONE, NULL, OPT_CONTEXT_DIFF, gettext_noop("use context diff format"), NULL},
82 {"external", 0, POPT_ARG_NONE, NULL, OPT_EXTERNAL_DIFF, gettext_noop("use external diff hook for generating diffs"), NULL},
83 {"diff-args", 0, POPT_ARG_STRING, &argstr, OPT_EXTERNAL_DIFF_ARGS, gettext_noop("argument to pass external diff hook"), NULL},
84 {"no-show-encloser", 0, POPT_ARG_NONE, NULL, OPT_NO_SHOW_ENCLOSER, gettext_noop("do not show the function containing each block of changes"), NULL},
85 {"no-show-c-function", 0, POPT_ARG_NONE, NULL, OPT_NO_SHOW_ENCLOSER, gettext_noop("another name for --no-show-encloser (for compatibility with GNU diff)"), NULL},
86 {"execute", 'e', POPT_ARG_NONE, NULL, OPT_EXECUTE, gettext_noop("perform the associated file operation"), NULL},
87 {"bind", 0, POPT_ARG_STRING, &argstr, OPT_BIND, gettext_noop("address:port to listen on (default :4691)"), NULL},
88 {"missing", 0, POPT_ARG_NONE, NULL, OPT_MISSING, gettext_noop("perform the operations for files missing from workspace"), NULL},
89 {"unknown", 0, POPT_ARG_NONE, NULL, OPT_UNKNOWN, gettext_noop("perform the operations for unknown files from workspace"), NULL},
90 {"key-to-push", 0, POPT_ARG_STRING, &argstr, OPT_KEY_TO_PUSH, gettext_noop("push the specified key even if it hasn't signed anything"), NULL},
91 {"stdio", 0, POPT_ARG_NONE, NULL, OPT_STDIO, gettext_noop("serve netsync on stdio"), NULL},
92 {"no-transport-auth", 0, POPT_ARG_NONE, NULL, OPT_NO_TRANSPORT_AUTH, gettext_noop("disable transport authentication"), NULL},
93 {"drop-attr", 0, POPT_ARG_STRING, &argstr, OPT_DROP_ATTR, gettext_noop("when rosterifying, drop attrs entries with the given key"), NULL},
94 {"no-files", 0, POPT_ARG_NONE, NULL, OPT_NO_FILES, gettext_noop("exclude files when printing logs"), NULL},
95 {"recursive", 'R', POPT_ARG_NONE, NULL, OPT_RECURSIVE, gettext_noop("also operate on the contents of any listed directories"), NULL},
96 { NULL, 0, 0, NULL, 0, NULL, NULL }
97 };
98
99struct poptOption options[] =
100 {
101 // Use the coptions table as well.
102 { NULL, 0, POPT_ARG_INCLUDE_TABLE, coptions, 0, NULL, NULL },
103
104 {"debug", 0, POPT_ARG_NONE, NULL, OPT_DEBUG, gettext_noop("print debug log to stderr while running"), NULL},
105 {"dump", 0, POPT_ARG_STRING, &argstr, OPT_DUMP, gettext_noop("file to dump debugging log to, on failure"), NULL},
106 {"log", 0, POPT_ARG_STRING, &argstr, OPT_LOG, gettext_noop("file to write the log to"), NULL},
107 {"quiet", 0, POPT_ARG_NONE, NULL, OPT_QUIET, gettext_noop("suppress verbose, informational and progress messages"), NULL},
108 {"reallyquiet", 0, POPT_ARG_NONE, NULL, OPT_REALLYQUIET, gettext_noop("suppress warning, verbose, informational and progress messages"), NULL},
109 {"help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, gettext_noop("display help message"), NULL},
110 {"version", 0, POPT_ARG_NONE, NULL, OPT_VERSION, gettext_noop("print version number, then exit"), NULL},
111 {"full-version", 0, POPT_ARG_NONE, NULL, OPT_FULL_VERSION, gettext_noop("print detailed version number, then exit"), NULL},
112 {"xargs", '@', POPT_ARG_STRING, &argstr, OPT_ARGFILE, gettext_noop("insert command line arguments taken from the given file"), NULL},
113 {"ticker", 0, POPT_ARG_STRING, &argstr, OPT_TICKER, gettext_noop("set ticker style (count|dot|none)"), NULL},
114 {"nostd", 0, POPT_ARG_NONE, NULL, OPT_NOSTD, gettext_noop("do not load standard lua hooks"), NULL},
115 {"norc", 0, POPT_ARG_NONE, NULL, OPT_NORC, gettext_noop("do not load ~/.monotone/monotonerc or _MTN/monotonerc lua files"), NULL},
116 {"rcfile", 0, POPT_ARG_STRING, &argstr, OPT_RCFILE, gettext_noop("load extra rc file"), NULL},
117 {"key", 'k', POPT_ARG_STRING, &argstr, OPT_KEY_NAME, gettext_noop("set key for signatures"), NULL},
118 {"db", 'd', POPT_ARG_STRING, &argstr, OPT_DB_NAME, gettext_noop("set name of database"), NULL},
119 {"root", 0, POPT_ARG_STRING, &argstr, OPT_ROOT, gettext_noop("limit search for workspace to specified root"), NULL},
120 {"verbose", 'v', POPT_ARG_NONE, NULL, OPT_VERBOSE, gettext_noop("verbose completion output"), NULL},
121 {"keydir", 0, POPT_ARG_STRING, &argstr, OPT_KEY_DIR, gettext_noop("set location of key store"), NULL},
122 {"confdir", 0, POPT_ARG_STRING, &argstr, OPT_CONF_DIR, gettext_noop("set location of configuration directory"), NULL},
123 { NULL, 0, 0, NULL, 0, NULL, NULL }
124 };
125
126// there are 3 variables which serve as roots for our system.
127//
128// "global_sanity" is a global object, which contains the error logging
129// system, which is constructed once and used by any nana logging actions.
130// see cleanup.hh for it
131//
132// "cmds" is a static table in commands.cc which associates top-level
133// commands, given on the command-line, to various version control tasks.
134//
135// "app_state" is a non-static object type which contains all the
136// application state (filesystem, database, network, lua interpreter,
137// etc). you can make more than one of these, and feed them to a command in
138// the command table.
139
140// our main function is run inside a boost execution monitor. this monitor
141// portably sets up handlers for various fatal conditions (signals, win32
142// structured exceptions, etc) and provides a uniform reporting interface
143// to any exceptions it catches. we augment this with a helper atexit()
144// which will also dump our internal logs when an explicit clean shutdown
145// flag is not set.
146//
147// in other words, this program should *never* unexpectedly terminate
148// without dumping some diagnostics.
149
150void
151dumper()
152{
153 if (!global_sanity.clean_shutdown)
154 global_sanity.dump_buffer();
155
156 Botan::Init::deinitialize();
157}
158
159
160struct
161utf8_argv
162{
163 int argc;
164 char **argv;
165
166 explicit utf8_argv(int ac, char **av)
167 : argc(ac),
168 argv(static_cast<char **>(malloc(ac * sizeof(char *))))
169 {
170 I(argv != NULL);
171 for (int i = 0; i < argc; ++i)
172 {
173 external ext(av[i]);
174 utf8 utf;
175 system_to_utf8(ext, utf);
176 argv[i] = static_cast<char *>(malloc(utf().size() + 1));
177 I(argv[i] != NULL);
178 memcpy(argv[i], utf().data(), utf().size());
179 argv[i][utf().size()] = static_cast<char>(0);
180 }
181 }
182
183 ~utf8_argv()
184 {
185 if (argv != NULL)
186 {
187 for (int i = 0; i < argc; ++i)
188 if (argv[i] != NULL)
189 free(argv[i]);
190 free(argv);
191 }
192 }
193};
194
195// Stupid type system tricks: to use a cleanup_ptr, we need to know the return
196// type of the cleanup function. But popt silently changed the return type of
197// poptFreeContext at some point, I guess because they thought it would be
198// "backwards compatible". We don't actually _use_ the return value of
199// poptFreeContext, so this little wrapper works.
200static void
201my_poptFreeContext(poptContext con)
202{
203 poptFreeContext(con);
204}
205
206// Read arguments from a file. The special file '-' means stdin.
207// Returned value must be free()'d, after arg parsing has completed.
208static void
209my_poptStuffArgFile(poptContext con, utf8 const & filename)
210{
211 utf8 argstr;
212 {
213 data dat;
214 read_data_for_command_line(filename, dat);
215 external ext(dat());
216 system_to_utf8(ext, argstr);
217 }
218
219 const char **argv = 0;
220 int argc = 0;
221 int rc;
222
223 // Parse the string. It's OK if there are no arguments.
224 rc = poptParseArgvString(argstr().c_str(), &argc, &argv);
225 N(rc >= 0 || rc == POPT_ERROR_NOARG,
226 F("problem parsing arguments from file %s: %s")
227 % filename % poptStrerror(rc));
228
229 if (rc != POPT_ERROR_NOARG)
230 {
231 // poptStuffArgs does not take an argc argument, but rather requires that
232 // the argv array be null-terminated.
233 I(argv[argc] == NULL);
234 N((rc = poptStuffArgs(con, argv)) >= 0,
235 F("weird error when stuffing arguments read from %s: %s\n")
236 % filename % poptStrerror(rc));
237 }
238
239 free(argv);
240}
241
242static string
243coption_string(int o)
244{
245 char buf[2] = { 0,0 };
246 for(struct poptOption *opt = coptions; opt->val; opt++)
247 if (o == opt->val)
248 {
249 buf[0] = opt->shortName;
250 return opt->longName
251 ? string("--") + string(opt->longName)
252 : string("-") + string(buf);
253 }
254 return string();
255}
256
257int
258cpp_main(int argc, char ** argv)
259{
260 int ret = 0;
261
262 atexit(&dumper);
263
264 // go-go gadget i18n
265
266 setlocale(LC_ALL, "");
267 bindtextdomain(PACKAGE, LOCALEDIR);
268 textdomain(PACKAGE);
269
270
271 // we want to catch any early informative_failures due to charset
272 // conversion etc
273 try
274 {
275
276 // set up some marked strings, so even if our logbuf overflows, we'll get
277 // this data in a crash.
278 string cmdline_string;
279 {
280 ostringstream cmdline_ss;
281 for (int i = 0; i < argc; ++i)
282 {
283 if (i)
284 cmdline_ss << ", ";
285 cmdline_ss << "'" << argv[i] << "'";
286 }
287 cmdline_string = cmdline_ss.str();
288 }
289 MM(cmdline_string);
290 L(FL("command line: %s") % cmdline_string);
291
292 string locale_string = (setlocale(LC_ALL, NULL) == NULL ? "n/a" : setlocale(LC_ALL, NULL));
293 MM(locale_string);
294 L(FL("set locale: LC_ALL=%s") % locale_string);
295
296 string full_version_string;
297 get_full_version(full_version_string);
298 MM(full_version_string);
299
300 Botan::paranoid_memory_clearing = false;
301 // Set up secure memory allocation etc
302 Botan::Init::initialize();
303 Botan::set_default_allocator("malloc");
304
305 // decode all argv values into a UTF-8 array
306
307 save_initial_path();
308 utf8_argv uv(argc, argv);
309
310 // find base name of executable
311
312 string prog_path = fs::path(uv.argv[0]).leaf();
313 if (prog_path.rfind(".exe") == prog_path.size() - 4)
314 prog_path = prog_path.substr(0, prog_path.size() - 4);
315 utf8 prog_name(prog_path);
316
317 // prepare for arg parsing
318
319 cleanup_ptr<poptContext, void>
320 ctx(poptGetContext(NULL, argc, (char const **) uv.argv, options, 0),
321 &my_poptFreeContext);
322
323 set<int> local_options;
324 for (poptOption *opt = coptions; opt->val; opt++)
325 local_options.insert(opt->val);
326
327 // process main program options
328
329 int opt;
330 set<int> used_local_options;
331
332 poptSetOtherOptionHelp(ctx(), _("[OPTION...] command [ARGS...]\n"));
333
334 app_state app;
335 try
336 {
337
338 app.set_prog_name(prog_name);
339
340 while ((opt = poptGetNextOpt(ctx())) > 0)
341 {
342 if (local_options.find(opt) != local_options.end())
343 used_local_options.insert(opt);
344
345 switch(opt)
346 {
347 case OPT_DEBUG:
348 global_sanity.set_debug();
349 break;
350
351 case OPT_QUIET:
352 global_sanity.set_quiet();
353 ui.set_tick_writer(new tick_write_nothing);
354 break;
355
356 case OPT_REALLYQUIET:
357 global_sanity.set_reallyquiet();
358 ui.set_tick_writer(new tick_write_nothing);
359 break;
360
361 case OPT_NOSTD:
362 app.set_stdhooks(false);
363 break;
364
365 case OPT_NORC:
366 app.set_rcfiles(false);
367 break;
368
369 case OPT_VERBOSE:
370 app.set_verbose(true);
371 break;
372
373 case OPT_RCFILE:
374 app.add_rcfile(string(argstr));
375 break;
376
377 case OPT_DUMP:
378 global_sanity.filename = system_path(argstr);
379 break;
380
381 case OPT_LOG:
382 ui.redirect_log_to(system_path(argstr));
383 break;
384
385 case OPT_DB_NAME:
386 app.set_database(system_path(argstr));
387 break;
388
389 case OPT_KEY_DIR:
390 app.set_key_dir(system_path(argstr));
391 break;
392
393 case OPT_CONF_DIR:
394 app.set_confdir(system_path(argstr));
395 break;
396
397 case OPT_TICKER:
398 if (string(argstr) == "none" || global_sanity.quiet)
399 ui.set_tick_writer(new tick_write_nothing);
400 else if (string(argstr) == "dot")
401 ui.set_tick_writer(new tick_write_dot);
402 else if (string(argstr) == "count")
403 ui.set_tick_writer(new tick_write_count);
404 else
405 app.requested_help = true;
406 break;
407
408 case OPT_KEY_NAME:
409 app.set_signing_key(string(argstr));
410 break;
411
412 case OPT_BRANCH_NAME:
413 app.set_branch(string(argstr));
414 app.set_is_explicit_option(OPT_BRANCH_NAME);
415 break;
416
417 case OPT_VERSION:
418 print_version();
419 global_sanity.clean_shutdown = true;
420 return 0;
421
422 case OPT_FULL_VERSION:
423 print_full_version();
424 global_sanity.clean_shutdown = true;
425 return 0;
426
427 case OPT_REVISION:
428 app.add_revision(string(argstr));
429 break;
430
431 case OPT_MESSAGE:
432 app.set_message(string(argstr));
433 app.set_is_explicit_option(OPT_MESSAGE);
434 break;
435
436 case OPT_MSGFILE:
437 app.set_message_file(string(argstr));
438 app.set_is_explicit_option(OPT_MSGFILE);
439 break;
440
441 case OPT_DATE:
442 app.set_date(string(argstr));
443 break;
444
445 case OPT_AUTHOR:
446 app.set_author(string(argstr));
447 break;
448
449 case OPT_ROOT:
450 app.set_root(system_path(argstr));
451 break;
452
453 case OPT_LAST:
454 app.set_last(arglong);
455 break;
456
457 case OPT_NEXT:
458 app.set_next(arglong);
459 break;
460
461 case OPT_DEPTH:
462 app.set_depth(arglong);
463 break;
464
465 case OPT_BRIEF:
466 global_sanity.set_brief();
467 break;
468
469 case OPT_DIFFS:
470 app.diffs = true;
471 break;
472
473 case OPT_NO_MERGES:
474 app.no_merges = true;
475 break;
476
477 case OPT_SET_DEFAULT:
478 app.set_default = true;
479 break;
480
481 case OPT_EXCLUDE:
482 app.add_exclude(utf8(string(argstr)));
483 break;
484
485 case OPT_PIDFILE:
486 app.set_pidfile(system_path(argstr));
487 break;
488
489 case OPT_ARGFILE:
490 my_poptStuffArgFile(ctx(), utf8(string(argstr)));
491 break;
492
493 case OPT_UNIFIED_DIFF:
494 app.set_diff_format(unified_diff);
495 break;
496
497 case OPT_CONTEXT_DIFF:
498 app.set_diff_format(context_diff);
499 break;
500
501 case OPT_EXTERNAL_DIFF:
502 app.set_diff_format(external_diff);
503 break;
504
505 case OPT_EXTERNAL_DIFF_ARGS:
506 app.set_diff_args(utf8(string(argstr)));
507 break;
508
509 case OPT_NO_SHOW_ENCLOSER:
510 app.diff_show_encloser = false;
511 break;
512
513 case OPT_EXECUTE:
514 app.execute = true;
515 break;
516
517 case OPT_STDIO:
518 app.bind_stdio = true;
519 break;
520
521 case OPT_NO_TRANSPORT_AUTH:
522 app.use_transport_auth = false;
523 break;
524
525 case OPT_BIND:
526 {
527 string arg(argstr);
528 string addr_part, port_part;
529 size_t l_colon = arg.find(':');
530 size_t r_colon = arg.rfind(':');
531
532 // not an ipv6 address, as that would have at least two colons
533 if (l_colon == r_colon)
534 {
535 addr_part = (r_colon == string::npos ? arg : arg.substr(0, r_colon));
536 port_part = (r_colon == string::npos ? "" : arg.substr(r_colon+1, arg.size() - r_colon));
537 }
538 else
539 {
540 // IPv6 addresses have a port specified in the style: [2001:388:0:13::]:80
541 size_t squareb = arg.rfind(']');
542 if ((arg.find('[') == 0) && (squareb != string::npos))
543 {
544 if (squareb < r_colon)
545 port_part = (r_colon == string::npos ? "" : arg.substr(r_colon+1, arg.size() - r_colon));
546 else
547 port_part = "";
548 addr_part = (squareb == string::npos ? arg.substr(1, arg.size()) : arg.substr(1, squareb-1));
549 }
550 else
551 {
552 addr_part = arg;
553 port_part = "";
554 }
555 }
556 app.bind_stdio = false;
557 app.bind_address = utf8(addr_part);
558 app.bind_port = utf8(port_part);
559 }
560 app.set_is_explicit_option(OPT_BIND);
561 break;
562
563 case OPT_MISSING:
564 app.missing = true;
565 break;
566
567 case OPT_UNKNOWN:
568 app.unknown = true;
569 break;
570
571 case OPT_KEY_TO_PUSH:
572 {
573 app.add_key_to_push(string(argstr));
574 }
575 break;
576
577 case OPT_DROP_ATTR:
578 app.attrs_to_drop.insert(string(argstr));
579 break;
580
581 case OPT_NO_FILES:
582 app.no_files = true;
583 break;
584
585 case OPT_RECURSIVE:
586 app.set_recursive();
587 break;
588
589 case OPT_HELP:
590 app.requested_help = true;
591 break;
592
593 default:
594 break;
595 }
596 }
597
598 // verify that there are no errors in the command line
599
600 N(opt == -1,
601 F("syntax error near the \"%s\" option: %s") %
602 poptBadOption(ctx(), POPT_BADOPTION_NOALIAS) % poptStrerror(opt));
603
604 // complete the command if necessary
605
606 if (!poptPeekArg(ctx()))
607 // no command given
608 throw usage("");
609 // poptPeekArg returned true, so we can call poptGetArg
610 string cmd = commands::complete_command(poptGetArg(ctx()));
611
612 // stop here if they asked for help
613
614 if (app.requested_help)
615 {
616 throw usage(cmd); // cmd may be empty, and that's fine.
617 }
618
619 // at this point we allow a workspace (meaning search for it
620 // and if found read _MTN/options, but don't use the data quite
621 // yet, and read all the monotonercs). Processing the data
622 // from _MTN/options happens later.
623 // Certain commands may subsequently require a workspace or fail
624 // if we didn't find one at this point.
625
626 app.allow_workspace();
627
628 if (!app.found_workspace && global_sanity.filename.empty())
629 global_sanity.filename = (app.get_confdir() / "dump").as_external();
630
631 // main options processed, now invoke the
632 // sub-command w/ remaining args
633
634 // Make sure the local options used are really used by the
635 // given command.
636 set<int> command_options = commands::command_options(cmd);
637 for (set<int>::const_iterator i = used_local_options.begin();
638 i != used_local_options.end(); ++i)
639 N(command_options.find(*i) != command_options.end(),
640 F("%s %s doesn't use the option %s")
641 % prog_name % cmd % coption_string(*i));
642
643 vector<utf8> args;
644 while(poptPeekArg(ctx()))
645 {
646 args.push_back(utf8(string(poptGetArg(ctx()))));
647 }
648 ret = commands::process(app, cmd, args);
649 }
650 catch (usage & u)
651 {
652 // Make sure to hide documentation that's not part of
653 // the current command.
654 set<int> command_options = commands::command_options(u.which);
655 int count = 0;
656 for (poptOption *o = coptions; o->val != 0; o++)
657 {
658 if (command_options.find(o->val) != command_options.end())
659 {
660 o->argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
661 L(FL("Removed 'hidden' from option # %d") % o->argInfo);
662 count++;
663 }
664 else
665 {
666 o->argInfo |= POPT_ARGFLAG_DOC_HIDDEN;
667 L(FL("Added 'hidden' to option # %d") % o->argInfo);
668 }
669 }
670 free((void *)options[0].descrip); options[0].descrip = NULL;
671 if (count != 0)
672 {
673 ostringstream sstr;
674 sstr << F("Options specific to '%s %s':")
675 % prog_name % u.which;
676 options[0].descrip = strdup(sstr.str().c_str());
677
678 options[0].argInfo |= POPT_ARGFLAG_DOC_HIDDEN;
679 L(FL("Added 'hidden' to option # %d") % options[0].argInfo);
680 }
681
682 poptPrintHelp(ctx(), stdout, 0);
683 cout << endl;
684 commands::explain_usage(u.which, cout);
685 global_sanity.clean_shutdown = true;
686 if (app.requested_help)
687 return 0;
688 else
689 return 2;
690 }
691 }
692 catch (informative_failure & inf)
693 {
694 ui.inform(inf.what);
695 global_sanity.clean_shutdown = true;
696 return 1;
697 }
698 catch (ios_base::failure const & ex)
699 {
700 global_sanity.clean_shutdown = true;
701 return 1;
702 }
703
704 global_sanity.clean_shutdown = true;
705 return ret;
706}
707
708// Local Variables:
709// mode: C++
710// fill-column: 76
711// c-file-style: "gnu"
712// indent-tabs-mode: nil
713// End:
714// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status