This file is indexed.

/usr/lib/ocaml/cmdliner/cmdliner.mli is in libcmdliner-ocaml-dev 0.9.8-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
(*---------------------------------------------------------------------------
   Copyright (c) 2011 Daniel C. Bünzli. All rights reserved.
   Distributed under a BSD3 license, see license at the end of the file.
   cmdliner release 0.9.8
  ---------------------------------------------------------------------------*)

(** Declarative definition of command line interfaces.

    [Cmdliner] provides a simple and compositional mechanism
    to convert command line arguments to OCaml values and pass them to
    your functions. The module automatically handles syntax errors,
    help messages and UNIX man page generation. It supports programs
    with single or multiple commands
    (like [darcs] or [git]) and respect most of the
    {{:http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html}
    POSIX} and
    {{:http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html}
    GNU} conventions.

    Consult the {{!basics}basics}, details about the supported
    {{!cmdline}command line syntax} and {{!examples} examples} of
    use. Open the module to use it, it defines only three modules in
    your scope.

    {e Release 0.9.8 - Daniel Bünzli <daniel.buenzl i\@erratique.ch> } *)

(** {1:top Interface} *)

(** Man page specification.

    Man page generation is automatically handled by [Cmdliner]. The
    {!block} type is used to define a man page's content.

    The {!print} function can be useful if the client wants to define
    other man pages (e.g. to implement a help command). *)
module Manpage : sig

  (** {1:man Man pages} *)

  type block =
    [ `S of string | `P of string | `Pre of string | `I of string * string
    | `Noblank ]
  (** The type for a block of man page text.

      {ul
      {- [`S s] introduces a new section [s].}
      {- [`P t] is a new paragraph with text [t].}
      {- [`Pre t] is a new preformatted paragraph with text [t].}
      {- [`I (l,t)] is an indented paragraph with label
      [l] and text [t].}
      {- [`Noblank] suppresses the blank line introduced between two blocks.}}

      Except in [`Pre], whitespace and newlines are not significant
      and are all collapsed to a single space. In labels [l] and text
      strings [t], the syntax ["$(i,italic text)"] and ["$(b,bold
      text)"] can be used to respectively produce italic and bold
      text. *)

  type title = string * int * string * string * string
  (** The type for man page titles. Describes the man page
      [title], [section], [center_footer], [left_footer], [center_header]. *)

  type t = title * block list
  (** The type for a man page. A title and the page text as a list of blocks. *)

  val print : ?subst:(string -> string) ->
    [`Pager | `Plain | `Groff ] -> Format.formatter -> t -> unit
  (** [print ~subst fmt ppf page] prints [page] on [ppf] in the format [fmt].
      If [fmt] is [`Pager] the function tries to write the formatted
      result in a pager, if that fails the format [`Plain] is written
      on [ppf]. [subst] can be used to perform variable substitution,
      see {!Buffer.add_substitute} (defaults to the identity). *)
end

(** Terms.

    A term is evaluated by a program to produce a {{!result}result}.
    A term made of terms referring to {{!Arg}command line arguments}
    implicitly defines a command line syntax. *)
module Term : sig

  (** {1:terms Terms} *)

  type +'a t
  (** The type for terms evaluating to values of type 'a. *)

  val const : 'a -> 'a t
  (** [const v] is a term that evaluates to [v]. *)

  (**/**)
  val pure : 'a -> 'a t
  (** @deprecated use {!const} instead. *)
  (**/**)

  val ( $ ) : ('a -> 'b) t -> 'a t -> 'b t
  (** [f $ v] is a term that evaluates to the result of applying
      the evaluation of [v] to the one of [f]. *)

  val app : ('a -> 'b) t -> 'a t -> 'b t
  (** [app] is {!($)}. *)

  type 'a ret =
    [ `Help of [`Pager | `Plain | `Groff] * string option
    | `Error of (bool * string)
    | `Ok of 'a ]
  (** The type for command return values. See {!ret}. *)

  val ret : 'a ret t -> 'a t
  (** [ret v] is a term whose evaluation depends on the case
      to which [v] evaluates. With :
      {ul
      {- [`Ok r], it evaluates to [r].}
      {- [`Error (usage,e)], the evaluation fails and [Cmdliner] prints
         the error [e] and the term's usage if [usage] is [true].}
      {- [`Help (format, name)], the evaluation fails and [Cmdliner] prints the
         term's man page in the given [format] (or the man page for a
         specific [name] term in case of multiple term evaluation).}}   *)

  val main_name : string t
  (** [main_name] is a term that evaluates to the "main" term's name. *)

  val choice_names : string list t
  (** [choice_names] is a term that evaluates to the names of the terms
      to choose from. *)

  val man_format : [`Pager | `Plain | `Groff] t
  (** [man_format] is a term that defines a [--man-format] option and
      evaluates to a value that can be used with {!Manpage.print}. *)

  (** {1:tinfo Term information}

      Term information defines the name and man page of a term.
      For simple evaluation this is the name of the program and its
      man page. For multiple term evaluation, this is
      the name of a command and its man page. *)

  type info
  (** The type for term information. *)

  val info : ?sdocs:string -> ?man:Manpage.block list ->
    ?docs:string -> ?doc:string -> ?version:string -> string -> info
  (** [info sdocs man docs doc version name] is a term information
      such that:
      {ul
      {- [name] is the name of the program or the command.}
      {- [version] is the version string of the program, ignored
         for commands.}
      {- [doc] is a one line description of the program or command used
         for the [NAME] section of the term's man page. For commands this
         description is also used in the list of commands of the main
         term's man page.}
      {- [docs], only for commands, the title of the section of the main
         term's man page where it should be listed (defaults to ["COMMANDS"]).}
      {- [man] is the text of the man page for the term. In the text,
         the variables ["$(tname)"] and ["$(mname)"] can respectively be
         used to refer to the value of [name] and the main term's name.
      }
      {- [sdocs] defines the title of the section in which the
         standard [--help] and [--version] arguments are listed.}} *)

  val name : info -> string
  (** [name ti] is the name of the term information. *)

 (** {1:evaluation Evaluation} *)

  type 'a result = [
    | `Ok of 'a | `Error of [`Parse | `Term | `Exn ] | `Version | `Help ]
  (** The type for evaluation results.
      {ul
      {- [`Ok v], the term evaluated successfully and [v] is the result.}
      {- [`Version], the version string of the main term was printed
       on the help formatter.}
      {- [`Help], man page about the term was printed on the help formatter.}
      {- [`Error `Parse], a command line parse error occured and was
         reported on the error formatter.}
      {- [`Error `Term], a term evaluation error occured and was reported
         on the error formatter (see {!Term.ret}).}
      {- [`Error `Exn], an exception [e] was caught and reported
         on the error formatter (see the [~catch] parameter of {!eval}).}} *)

  val eval : ?help:Format.formatter ->
    ?err:Format.formatter -> ?catch:bool ->
    ?env:(string -> string option) ->
    ?argv:string array -> ('a t * info) -> 'a result
  (** [eval help err catch argv (t,i)]  is the evaluation result
      of [t] with command line arguments [argv] (defaults to {!Sys.argv}).

      If [catch] is [true] (default) uncaught exeptions
      are intercepted and their stack trace is written to the [err]
      formatter.

      [help] is the formatter used to print help or version messages
      (defaults to {!Format.std_formatter}). [err] is the formatter
      used to print error messages (defaults to {!Format.err_formatter}).

      [env] is used for environment variable lookup, the default
      uses {!Sys.getenv}. *)

  val eval_choice : ?help:Format.formatter ->
    ?err:Format.formatter -> ?catch:bool ->
    ?env:(string -> string option) ->
    ?argv:string array -> 'a t * info -> ('a t * info) list ->
    'a result
  (** [eval_choice help err catch argv default (t,i) choices] is like {!eval}
      except that if the first argument on the command line is not an option
      name it will look in [choices] for a term whose information has this
      name and evaluate it.

      If the command name is unknown an error is reported. If the name
      is unspecified the "main" term [t] is evaluated. [i] defines the
      name and man page of the program. *)

  val eval_peek_opts : ?version_opt:bool ->
    ?env:(string -> string option) ->
    ?argv:string array -> 'a t ->
    'a option * 'a result
  (** [eval_peek_opts version_opt argv t] evaluates [t], a term made
      of optional arguments only, with the command line [argv]
      (defaults to {!Sys.argv}). In this evaluation, unknown optional
      arguments and positional arguments are ignored.

      The evaluation returns a pair. The first component is
      the result of parsing the command line [argv] stripped from
      any help and version option if [version_opt] is [true] (defaults
      to [false]). It results in:
      {ul
      {- [Some _] if the command line would be parsed correctly given the
         {e partial} knowledge in [t].}
      {- [None] if a parse error would occur on the options of [t]}}

      The second component is the result of parsing the command line
      [argv] without stripping the help and version options. It
      indicates what the evaluation would result in on [argv] given
      the partial knowledge in [t] (for example it would return
      [`Help] if there's a help option in [argv]). However in
      contrasts to {!eval} and {!eval_choice} no side effects like
      error reporting or help output occurs.

      {b Note.} Positional arguments can't be peeked without the full
      specification of the command line: we can't tell apart a
      positional argument from the value of an unknown optional
      argument.  *)
end

(** Terms for command line arguments.

    This module provides functions to define terms that evaluate
    to the arguments provided on the command line.

    Basic constraints, like the argument type or repeatability, are
    specified by defining a value of type {!t}. Further contraints can
    be specified during the {{!argterms}conversion} to a term. *)
module Arg : sig

(** {1:argconv Argument converters}

    An argument converter transforms a string argument of the command
    line to an OCaml value. {{!converters}Predefined converters}
    are provided for many types of the standard library. *)

  type 'a parser = string -> [ `Ok of 'a | `Error of string ]
  (** The type for argument parsers. *)

  type 'a printer = Format.formatter -> 'a -> unit
  (** The type for converted argument printers. *)

  type 'a converter = 'a parser * 'a printer
  (** The type for argument converters. *)

  val some : ?none:string -> 'a converter -> 'a option converter
  (** [some none c] is like the converter [c] except it returns
      [Some] value. It is used for command line arguments
      that default to [None] when absent. [none] is what to print to
      document the absence (defaults to [""]). *)

(** {1:arginfo Arguments and their information}

    Argument information defines the man page information of an
    argument and, for optional arguments, its names. An environment
    variable can also be specified to read the argument value from
    if the argument is absent from the command line and the variable
    is defined. *)

  type env
  (** The type for environment variables and their documentation. *)

  val env_var : ?docs:string -> ?doc:string -> string -> env
  (** [env_var docs doc var] is an environment variables [var]. [doc]
      is the man page information of the environment variable; the
      variables mentioned in {!info} can be used in this documentation
      string. [doc] defaults to ["See option $(opt)."]. [docs] is the
      title of the man page section in which the environment variable
      will be listed, it defaults to ["ENVIRONMENT VARIABLES"]. *)

  type 'a t
  (** The type for arguments holding data of type ['a]. *)

  type info
  (** The type for information about command line arguments. *)

  val info : ?docs:string -> ?docv:string -> ?doc:string -> ?env:env ->
    string list -> info
  (** [info docs docv doc env names] defines information for
      an argument.

      [names] defines the names under which an optional argument
      can be referred to. Strings of length [1] (["c"]) define short
      option names (["-c"]), longer strings (["count"]) define long
      option names (["--count"]). [names] must be empty for positional
      arguments.

      [env] defines the name of an environment variable which is
      looked up for defining the argument if it is absent from the
      command line. See {{!envlookup}environment variables} for
      details.
      {ul
      {- [doc] is the man page information of the argument. The
         variable ["$(docv)"] can be used to refer to the value of
         [docv] (see below). The variable ["$(opt)"] will refer to a
         long option of [names] or a short one if there is no long
         option. The variable ["$(env)"] will refer to the environment
         variable specified by [env] (if any).  {{!doc_helpers}These
         functions} can help with formatting argument values.}
      {- [docv] is for positional and non-flag optional arguments.
         It is a variable name used in the man page to stand for their value.}
      {- [docs] is the title of the man page section in which the argument
         will be listed. For optional arguments this defaults
         to ["OPTIONS"]. For positional arguments this defaults
         to ["ARGUMENTS"]. However a positional argument is only listed
         if it has both a [doc] and [docv] specified.}} *)

  val ( & ) : ('a -> 'b) -> 'a -> 'b
  (** [f & v] is [f v], a right associative composition operator for
      specifying argument terms. *)

(** {1:optargs Optional arguments}

    The information of an optional argument must have at least
    one name or [Invalid_argument] is raised. *)

  val flag : info -> bool t
  (** [flag i] is a [bool] argument defined by an optional flag
      that may appear {e at most} once on the command line under one of
      the names specified by [i]. The argument holds [true] if the
      flag is present on the command line and [false] otherwise. *)

  val flag_all : info -> bool list t
  (** [flag_all] is like {!flag} except the flag may appear more than
      once. The argument holds a list that contains one [true] value per
      occurence of the flag. It holds the empty list if the flag
      is absent from the command line. *)

  val vflag : 'a -> ('a * info) list -> 'a t
  (** [vflag v \[v]{_0}[,i]{_0}[;...\]] is an ['a] argument defined
      by an optional flag that may appear {e at most} once on
      the command line under one of the names specified in the [i]{_k}
      values. The argument holds [v] if the flag is absent from the
      command line and the value [v]{_k} if the name under which it appears
      is in [i]{_k}.

      {b Note.} Environment variable lookup is unsupported for
      for these arguments. *)

  val vflag_all : 'a list -> ('a * info) list -> 'a list t
  (** [vflag_all v l] is like {!vflag} except the flag may appear more
      than once. The argument holds the list [v] if the flag is absent
      from the command line. Otherwise it holds a list that contains one
      corresponding value per occurence of the flag, in the order found on
      the command line.

      {b Note.} Environment variable lookup is unsupported for
      for these arguments. *)

  val opt : ?vopt:'a -> 'a converter -> 'a -> info -> 'a t
  (** [opt vopt c v i] is an ['a] argument defined by the value of
      an optional argument that may appear {e at most} once on the command
      line under one of the names specified by [i]. The argument holds
      [v] if the option is absent from the command line. Otherwise
      it has the value of the option as converted by [c].

      If [vopt] is provided the value of the optional argument is itself
      optional, taking the value [vopt] if unspecified on the command line. *)

  val opt_all : ?vopt:'a -> 'a converter -> 'a list -> info -> 'a list t
  (** [opt_all vopt c v i] is like {!opt} except the optional argument may
      appear more than once. The argument holds a list that contains one value
      per occurence of the flag in the order found on the command line.
      It holds the list [v] if the flag is absent from the command line. *)

  (** {1:posargs Positional arguments}

      The information of a positional argument must have no name
      or [Invalid_argument] is raised. Positional arguments indexing
      is zero-based. *)

  val pos : ?rev:bool -> int -> 'a converter -> 'a -> info -> 'a t
  (** [pos rev n c v i] is an ['a] argument defined by the [n]th
      positional argument of the command line as converted by [c].
      If the positional argument is absent from the command line
      the argument is [v].

      If [rev] is [true] (defaults to [false]), the computed
      position is [max-n] where [max] is the position of
      the last positional argument present on the command line. *)

  val pos_all : 'a converter -> 'a list -> info -> 'a list t
  (** [pos_all c v i] is an ['a list] argument that holds
      all the positional arguments of the command line as converted
      by [c] or [v] if there are none. *)

  val pos_left : ?rev:bool -> int -> 'a converter -> 'a list -> info ->
    'a list t
  (** [pos_left rev n c v i] is an ['a list] argument that holds
      all the positional arguments as converted by [c] found on the left
      of the [n]th positional argument or [v] if there are none.

      If [rev] is [true] (defaults to [false]), the computed
      position is [max-n] where [max] is the position of
      the last positional argument present on the command line. *)

  val pos_right : ?rev:bool -> int -> 'a converter -> 'a list -> info ->
    'a list t
  (** [pos_right] is like {!pos_left} except it holds all the positional
      arguments found on the right of the specified positional argument. *)

  (** {1:argterms Arguments as terms} *)

  val value : 'a t -> 'a Term.t
  (** [value a] is a term that evaluates to [a]'s value. *)

  val required : 'a option t -> 'a Term.t
  (** [required a] is a term that fails if [a]'s value is [None] and
      evaluates to the value of [Some] otherwise. Use this for required
      positional arguments (it can also be used for defining required
      optional arguments, but from a user interface perspective this
      shouldn't be done, it is a contradiction in terms). *)

  val non_empty : 'a list t -> 'a list Term.t
  (** [non_empty a] is term that fails if [a]'s list is empty and
      evaluates to [a]'s list otherwise. Use this for non empty lists
      of positional arguments. *)

  val last : 'a list t -> 'a Term.t
  (** [last a] is a term that fails if [a]'s list is empty and evaluates
      to the value of the last element of the list otherwise. Use this
      for lists of flags or options where the last occurence takes precedence
      over the others. *)

  (** {1:converters Predefined converters} *)

  val bool : bool converter
  (** [bool] converts values with {!bool_of_string}. *)

  val char : char converter
  (** [char] converts values by ensuring the argument has a single char. *)

  val int : int converter
  (** [int] converts values with {!int_of_string}. *)

  val nativeint : nativeint converter
  (** [nativeint] converts values with {!Nativeint.of_string}. *)

  val int32 : int32 converter
  (** [int32] converts values with {!Int32.of_string}. *)

  val int64 : int64 converter
  (** [int64] converts values with {!Int64.of_string}. *)

  val float : float converter
  (** [float] converts values with {!float_of_string}. *)

  val string : string converter
  (** [string] converts values with the identity function. *)

  val enum : (string * 'a) list -> 'a converter
  (** [enum l p] converts values such that unambiguous prefixes of string names
      in [l] map to the corresponding value of type ['a].

      {b Warning.} The type ['a] must be comparable with {!Pervasives.compare}.

      @raise Invalid_argument if [l] is empty. *)

  val file : string converter
  (** [file] converts a value with the identity function and
      checks with {!Sys.file_exists} that a file with that name exists. *)

  val dir : string converter
  (** [dir] converts a value with the identity function and checks
      with {!Sys.file_exists} and {!Sys.is_directory}
      that a directory with that name exists. *)

  val non_dir_file : string converter
  (** [non_dir_file] converts a value with the identity function and checks
      with {!Sys.file_exists} and {!Sys.is_directory}
      that a non directory file with that name exists. *)

  val list : ?sep:char -> 'a converter -> 'a list converter
  (** [list sep c] splits the argument at each [sep] (defaults to [','])
      character and converts each substrings with [c]. *)

  val array : ?sep:char -> 'a converter -> 'a array converter
  (** [array sep c] splits the argument at each [sep] (defaults to [','])
      character and converts each substring with [c]. *)

  val pair : ?sep:char -> 'a converter -> 'b converter -> ('a * 'b) converter
  (** [pair sep c0 c1] splits the argument at the {e first} [sep] character
      (defaults to [',']) and respectively converts the substrings with
      [c0] and [c1]. *)

  val t2 : ?sep:char -> 'a converter -> 'b converter -> ('a * 'b) converter
  (** {!t2} is {!pair}. *)

  val t3 : ?sep:char -> 'a converter ->'b converter -> 'c converter ->
    ('a * 'b * 'c) converter
  (** [t3 sep c0 c1 c2] splits the argument at the {e first} two [sep]
      characters (defaults to [',']) and respectively converts the
      substrings with [c0], [c1] and [c2]. *)

  val t4 : ?sep:char -> 'a converter ->'b converter -> 'c converter ->
    'd converter -> ('a * 'b * 'c * 'd) converter
  (** [t4 sep c0 c1 c2 c3] splits the argument at the {e first} three [sep]
      characters (defaults to [',']) respectively converts the substrings
      with [c0], [c1], [c2] and [c3]. *)

  (** {1:doc_helpers Documentation formatting helpers} *)

  val doc_quote : string -> string
  (** [doc_quote s] quotes the string [s]. *)

  val doc_alts : ?quoted:bool -> string list -> string
  (** [doc_alts alts] documents the alternative tokens [alts] according
      the number of alternatives. If [quoted] is [true] (default)
      the tokens are quoted. The resulting string can be used in
      sentences of the form ["$(docv) must be %s"].

      @raise Invalid_argument if [alts] is the empty string.  *)

  val doc_alts_enum : ?quoted:bool -> (string * 'a) list -> string
  (** [doc_alts_enum quoted alts] is [doc_alts quoted (List.map fst alts)]. *)
end

(**
    {1:basics Basics}

    With [Cmdliner] your program evaluates a term. A {e term}
    is a value of type {!Term.t}. The type parameter indicates
    the type of the result of the evaluation.

    One way to create terms is by lifting regular OCaml values with
    {!Term.const}. Terms can be applied to terms evaluating to
    functional values with {!Term.( $ )}. For example for the function:
{[let revolt () = print_endline "Revolt!"]}
    the term :
{[
open Cmdliner;;

let revolt_t = Term.(const revolt $ const ())]}
    is a term that evaluates to the result (and effect) of the [revolt]
    function.
    Terms are evaluated with {!Term.eval}:
{[let () = match Term.eval (revolt_t, Term.info "revolt") with
| `Error _ -> exit 1 | _ -> exit 0]}
    This defines a command line program named ["revolt"], without command line
    arguments arguments, that just prints ["Revolt!"] on [stdout].
{[> ./revolt
Revolt!]}
    The combinators in the {!Arg} module allow to extract command
    line argument data as terms. These terms can then be applied to
    lifted OCaml functions to be evaluated by the program.

    Terms corresponding to command line argument data that are part of
    a term evaluation implicitly define a command line syntax.  We
    show this on an concrete example.

    Consider the [chorus] function that prints repeatedly a
    given message :
{[let chorus count msg =
  for i = 1 to count do print_endline msg done]}
    we want to make it available from the command line
    with the synopsis:
{[chorus [-c COUNT | --count=COUNT] [MSG]]}
    where [COUNT] defaults to [10] and [MSG] defaults to ["Revolt!"].
    We first define a term corresponding to the [--count]
    option:
{[
let count =
  let doc = "Repeat the message $(docv) times." in
  Arg.(value & opt int 10 & info ["c"; "count"] ~docv:"COUNT" ~doc)
]}
    This says that [count] is a term that evaluates to the
    value of an optional argument of type [int] that
    defaults to [10] if unspecified and whose option name is
    either [-c] or [--count]. The arguments [doc] and [docv] are used to
    generate the option's man page information.

    The term for the positional argument [MSG] is:
{[
let msg =
  let doc = "Overrides the default message to print."
  let env = Arg.env "CHORUS_MSG" ~doc in
  let doc = "The message to print." in
  Arg.(value & pos 0 string "Revolt!" & info [] ~env ~docv:"MSG" ~doc)
]}
    which says that [msg] is a term whose value is the positional
    argument at index [0] of type [string] and defaults to ["Revolt!"]
    or the value of the environment variable [CHORUS_MSG] if the
    argument is unspecified on the command line. Here again [doc] and
    [docv] are used for the man page information.

    The term for executing [chorus] with these command line arguments
    is :
{[
let chorus_t = Term.(const chorus $ count $ msg)
]}
    and we are now ready to define our program:
{[
let info =
  let doc = "print a customizable message repeatedly" in
  let man = [ `S "BUGS"; `P "Email bug reports to <hehey at example.org>.";] in
  Term.info "chorus" ~version:"1.6.1" ~doc ~man

let () = match Term.eval (chorus_t, info) with `Error _ -> exit 1 | _ -> exit 0
]}
    The [info] value created with {!Term.info} gives more information
    about the term we execute and is used to generate the program's
    man page. Since we provided a [~version] string, the program will
    automatically respond to the [--version] option by printing this
    string.

    A program using {!Term.eval} always responds to the
    [--help] option by showing the man page about the program generated
    using the information you provided with {!Term.info} and {!Arg.info}.
    Here is the output generated by our example :
{v > ./chorus --help
NAME
       chorus - print a customizable message repeatedly

SYNOPSIS
       chorus [OPTION]... [MSG]

ARGUMENTS
       MSG (absent=Revolt! or CHORUS_MSG env)
           The message to print.

OPTIONS
       -c COUNT, --count=COUNT (absent=10)
           Repeat the message COUNT times.

       --help[=FMT] (default=pager)
           Show this help in format FMT (pager, plain or groff).

       --version
           Show version information.

BUGS
       Email bug reports to <hehey at example.org>.
v}

    If a pager is available, this output is written to a pager.
    This help is also available in plain text or in the
    {{:http://www.gnu.org/software/groff/groff.html}groff} man page format by
    invoking the program with the option [--help=plain] or [--help=groff].

    For examples of more complex command line definitions look and
    run the {{!examples}examples}.

    {2:multiterms Multiple terms}

    [Cmdliner] also provides support for programs like [darcs] or
    [git] that have multiple commands each with their own syntax:
    {[prog COMMAND [OPTION]... ARG...]}
    A command is defined by coupling a term with
    {{!Term.tinfo}term information}. The term information defines the
    command name and its man page. Given a list of commands the function
    {!Term.eval_choice} will execute the term corresponding to the
    [COMMAND] argument or or a specific "main" term if there is
    no [COMMAND] argument.

    {2:manual Manual}

    Man page sections are printed in the order specified by
    {!Term.info}. The man page information of an argument is listed in
    alphabetical order at the end of the text of the section specified
    by its {{!Arg.info}argument information}. Positional arguments are
    also listed iff both the [docv] and [doc] string is specified in
    their argument information.

    If an argument information mentions a section not specified in
    {!Term.info}, an empty section is created for it. This section is
    inserted just after the ["SYNOPSIS"] section or after a section
    named ["DESCRIPTION"] if there is one.

    The ["SYNOPSIS"] section of a man page is generated automatically
    from a term's information and its arguments. To substitute your
    own instead, start the term's information man page with
    a ["SYNOPSIS"] section.

    Ideally all manual strings should be UTF-8 encoded. However at the
    moment Groff (at least [1.19.2]) doesn't seem to cope with UTF-8
    input and UTF-8 characters beyond the ASCII set will look garbled.
    Regarding UTF-8 output, generating the man page with [-Tutf8] maps
    the hyphen-minus [U+002D] to the minus sign [U+2212] which makes it
    difficult to search it in the pager, so [-Tascii] is used for now.
    Conclusion is that it may be better to stick to the ASCII set for now.
    Please contact the author if something seems wrong in this reasoning
    or if you know a work around this.

    {2:misc Miscellaneous}

    {ul
    {- The option name [--help], (and [--version] if you specify a
       version string) is reserved by the module. Using it as a term or
       option name may result in undefined behaviour.}
    {- The evaluation of a term in which the same option name is defined
       by more than one argument is undefined.}}

    {1:cmdline Command line syntax}

    For programs evaluating a single term the most general form of invocation
    is:
    {ul{- [prog [OPTION]... [ARG]...]}}
    The program automatically reponds to the [--help] option by
    printing the help. If a version string is provided in
    the {{!Term.tinfo}term information}, it also automatically responds
    to the [--version] option by printing this string.

    Command line arguments are either {{!optargs}{e optional}} or
    {{!posargs}{e positional}}. Both can be freely interleaved but
    since [Cmdliner] accepts many optional forms this may result in
    ambiguities. The special {{!posargs} token [--]} can be used to resolve
    them.

    Programs evaluating multiple terms also add this form of invocation:
    {ul{- [prog COMMAND [OPTION]... [ARG]...]}}
    Commands automatically respond to the [--help] option
    by printing their help. The [COMMAND] string must
    be the first string following the program name and may be specified
    by a prefix as long as it is not ambiguous.

    {2:optargs Optional arguments}

    An optional argument is specified on the command line by a {e
    name} possibly followed by a {e value}.

    The name of an option can be short or long.
    {ul
    {- A {e short} name is a dash followed by a single alphanumeric
       character: ["-h"], ["-q"], ["-I"].}
    {- A {e long} name is two dashes followed by alphanumeric
       characters and dashes: ["--help"], ["--silent"], ["--ignore-case"].}}

    More than one name may refer to the same optional argument.  For
    example in a given program the names ["-q"], ["--quiet"] and
    ["--silent"] may all stand for the same boolean argument
    indicating the program to be quiet.  Long names
    can be specified by any non ambiguous prefix.

    The value of an option can be specified in three different ways.
    {ul
    {- As the next token on the command line: ["-o a.out"],
       ["--output a.out"].}
    {- Glued to a short name: ["-oa.out"].}
    {- Glued to a long name after an equal character:
    ["--output=a.out"].}}
    Glued forms are especially useful if
    the value itself starts with a dash as is the case for negative numbers,
    ["--min=-10"].

    An optional argument without a value is either a {e flag}
    (see {!Arg.flag}, {!Arg.vflag}) or an optional argument with an optional
    value (see the [~vopt] argument of {!Arg.opt}).

    Short flags can be grouped together to share a single dash and the group
    can end with a short option. For example assuming ["-v"] and ["-x"]
    are flags and ["-f"] is a short option:
    {ul
      {- ["-vx"] will be parsed as ["-v -x"].}
      {- ["-vxfopt"] will be parsed as ["-v -x -fopt"].}
      {- ["-vxf opt"] will be parsed as ["-v -x -fopt"].}
      {- ["-fvx"] will be parsed as ["-f=vx"].}}

    {2:posargs Positional arguments}

    Positional arguments are tokens on the command line that are not
    option names and are not the value of an optional argument. They
    are numbered from left to right starting with zero.

    Since positional arguments may be mistaken as the optional value
    of an optional argument or they may need to look like option
    names, anything that follows the special token ["--"] on the command
    line is considered to be a positional argument.

    {2:envlookup Environment variables}

    Non-required command line arguments can be backed up by an environment
    variable.  If the argument is absent from the command line and
    that the environment variable is defined, its value is parsed
    using the argument converter and defines the value of the
    argument.

    For {!Arg.flag} and {!Arg.flag_all} that do not have an argument
    converter a boolean is parsed from the lowercased variable value
    as follows:
    {ul
    {- [""], ["false"], ["no"], ["n"] or ["0"] is [false].}
    {- ["true"], ["yes"], ["y"] or ["1"] is [true].}
    {- Any other string is an error.}}

    Note that environment variables are not supported for {!Arg.vflag}
    and {!Arg.vflag_all}.

    {1:examples Examples}

    These examples are in the [test] directory of the distribution.

 {2:exrm A [rm] command}

    We define the command line interface of a
    [rm] command with the synopsis:
{[
rm [OPTION]... FILE...
]}
    The [-f], [-i] and [-I] flags define the prompt behaviour of [rm],
    represented in our program by the [prompt] type. If more than one
    of these flags is present on the command line the last one takes
    precedence.

    To implement this behaviour we map the presence of these flags
    to values of the [prompt] type by using {!Arg.vflag_all}.  This
    argument will contain all occurences of the flag on the command
    line and we just take the {!Arg.last} one to define our term value
    (if there's no occurence the last value of the default list [[Always]] is
    taken, i.e. the default is [Always]).
{[
(* Implementation of the command, we just print the args. *)

type prompt = Always | Once | Never
let prompt_str = function
| Always -> "always" | Once -> "once" | Never -> "never"

let rm prompt recurse files =
  Printf.printf "prompt = %s\nrecurse = %b\nfiles = %s\n"
    (prompt_str prompt) recurse (String.concat ", " files)

(* Command line interface *)

open Cmdliner;;

let files = Arg.(non_empty & pos_all file [] & info [] ~docv:"FILE")
let prompt =
  let doc = "Prompt before every removal." in
  let always = Always, Arg.info ["i"] ~doc in
  let doc = "Ignore nonexistent files and never prompt." in
  let never = Never, Arg.info ["f"; "force"] ~doc in
  let doc = "Prompt once before removing more than three files, or when
             removing recursively. Less intrusive than $(b,-i), while
             still giving protection against most mistakes."
  in
  let once = Once, Arg.info ["I"] ~doc in
  Arg.(last & vflag_all [Always] [always; never; once])

let recursive =
  let doc = "Remove directories and their contents recursively." in
  Arg.(value & flag & info ["r"; "R"; "recursive"] ~doc)

let cmd =
  let doc = "remove files or directories" in
  let man = [
    `S "DESCRIPTION";
    `P "$(tname) removes each specified $(i,FILE). By default it does not
        remove directories, to also remove them and their contents, use the
        option $(b,--recursive) ($(b,-r) or $(b,-R)).";
    `P "To remove a file whose name starts with a `-', for example
        `-foo', use one of these commands:";
    `P "rm -- -foo"; `Noblank;
    `P "rm ./-foo";
    `P "$(tname) removes symbolic links, not the files referenced by the
        links.";
    `S "BUGS"; `P "Report bugs to <hehey at example.org>.";
    `S "SEE ALSO"; `P "$(b,rmdir)(1), $(b,unlink)(2)" ]
  in
  Term.(const rm $ prompt $ recursive $ files),
  Term.info "rm" ~version:"1.6.1" ~doc ~man

let () = match Term.eval cmd with `Error _ -> exit 1 | _ -> exit 0
]}
    {2:excp A [cp] command}

    We define the command line interface of a
    [cp] command with the synopsis:
{[cp [OPTION]... SOURCE... DEST ]}
    The [DEST] argument must be a directory if there is more than
    one [SOURCE]. This constraint is too complex to be expressed by the
    combinators of {!Arg}. Hence we just give it the {!Arg.string} type
    and verify the constraint at the beginning of the [cp]
    implementation. If unsatisfied we return an [`Error] and
    by using {!Term.ret} on the lifted result [cp_t] of [cp],
    [Cmdliner] handles the error reporting.
{[
(* Implementation, we check the dest argument and print the args *)

let cp verbose recurse force srcs dest =
  if List.length srcs > 1 &&
  (not (Sys.file_exists dest) || not (Sys.is_directory dest))
  then
    `Error (false, dest ^ " is not a directory")
  else
    `Ok (Printf.printf
     "verbose = %b\nrecurse = %b\nforce = %b\nsrcs = %s\ndest = %s\n"
      verbose recurse force (String.concat ", " srcs) dest)

(* Command line interface *)

open Cmdliner;;

let verbose =
  let doc = "Print file names as they are copied." in
  Arg.(value & flag & info ["v"; "verbose"] ~doc)

let recurse =
  let doc = "Copy directories recursively." in
  Arg.(value & flag & info ["r"; "R"; "recursive"] ~doc)

let force =
  let doc = "If a destination file cannot be opened, remove it and try again."in
  Arg.(value & flag & info ["f"; "force"] ~doc)

let srcs =
  let doc = "Source file(s) to copy." in
  Arg.(non_empty & pos_left ~rev:true 0 file [] & info [] ~docv:"SOURCE" ~doc)

let dest =
  let doc = "Destination of the copy. Must be a directory if there is more
             than one $(i,SOURCE)." in
  Arg.(required & pos ~rev:true 0 (some string) None & info [] ~docv:"DEST"
         ~doc)

let cmd =
  let doc = "copy files" in
  let man = [
    `S "BUGS";
    `P "Email them to <hehey at example.org>.";
    `S "SEE ALSO";
    `P "$(b,mv)(1), $(b,scp)(1), $(b,umask)(2), $(b,symlink)(7)" ]
  in
  Term.(ret (const cp $ verbose $ recurse $ force $ srcs $ dest)),
  Term.info "cp" ~version:"1.6.1" ~doc ~man

let () = match Term.eval cmd with `Error _ -> exit 1 | _ -> exit 0
]}

{2:extail A [tail] command}

We define the command line interface of a [tail] command with the
synopsis:
{[tail [OPTION]... [FILE]...]}

The [--lines] option whose value specifies the number of last lines to
print has a special syntax where a [+] prefix indicates to start
printing from that line number. In the program this is represented by
the [loc] type. We define a custom [loc] {{!Arg.argconv}argument converter}
for this option.

The [--follow] option has an optional enumerated value. The argument
converter [follow], created with {!Arg.enum} parses the option value
into the enumeration. By using {!Arg.some} and the [~vopt] argument of
{!Arg.opt}, the term corresponding to the option [--follow] evaluates to
[None] if [--follow] is absent from the command line, to [Some Descriptor]
if present but without a value and to [Some v] if present with a value
[v] specified.

{[
(* Implementation of the command, we just print the args. *)

type loc = bool * int
type verb = Verbose | Quiet
type follow = Name | Descriptor

let str = Printf.sprintf
let opt_str sv = function None -> "None" | Some v -> str "Some(%s)" (sv v)
let loc_str (rev, k) = if rev then str "%d" k else str "+%d" k
let follow_str = function Name -> "name" | Descriptor -> "descriptor"
let verb_str = function Verbose -> "verbose" | Quiet -> "quiet"

let tail lines follow verb pid files =
  Printf.printf "lines = %s\nfollow = %s\nverb = %s\npid = %s\nfiles = %s\n"
    (loc_str lines) (opt_str follow_str follow) (verb_str verb)
    (opt_str string_of_int pid) (String.concat ", " files)

(* Command line interface *)

open Cmdliner;;

let lines =
  let loc =
    let parse s = try
      if s <> "" && s.[0] <> '+' then `Ok (true, int_of_string s) else
      `Ok (false, int_of_string (String.sub s 1 (String.length s - 1)))
    with Failure _ -> `Error "unable to parse integer"
    in
    parse, fun ppf p -> Format.fprintf ppf "%s" (loc_str p)
  in
  Arg.(value & opt loc (true, 10) & info ["n"; "lines"] ~docv:"N"
   ~doc:"Output the last $(docv) lines or use $(i,+)$(docv) to start
         output after the $(i,N)-1th line.")
let follow =
  let doc = "Output appended data as the file grows. $(docv) specifies how the
             file should be tracked, by its `name' or by its `descriptor'." in
  let follow = Arg.enum ["name", Name; "descriptor", Descriptor] in
  Arg.(value & opt (some follow) ~vopt:(Some Descriptor) None &
       info ["f"; "follow"] ~docv:"ID" ~doc)

let verb =
  let doc = "Never output headers giving file names." in
  let quiet = Quiet, Arg.info ["q"; "quiet"; "silent"] ~doc in
  let doc = "Always output headers giving file names." in
  let verbose = Verbose, Arg.info ["v"; "verbose"] ~doc in
  Arg.(last & vflag_all [Quiet] [quiet; verbose])

let pid =
  let doc = "With -f, terminate after process $(docv) dies." in
  Arg.(value & opt (some int) None & info ["pid"] ~docv:"PID" ~doc)

let files = Arg.(value & (pos_all non_dir_file []) & info [] ~docv:"FILE")

let cmd =
  let doc = "display the last part of a file" in
  let man = [
    `S "DESCRIPTION";
    `P "$(tname) prints the last lines of each $(i,FILE) to standard output. If
        no file is specified reads standard input. The number of printed
        lines can be  specified with the $(b,-n) option.";
    `S "BUGS";
    `P "Report them to <hehey at example.org>.";
    `S "SEE ALSO";
    `P "$(b,cat)(1), $(b,head)(1)" ]
  in
  Term.(const tail $ lines $ follow $ verb $ pid $ files),
  Term.info "tail" ~version:"1.6.1" ~doc ~man

let () = match Term.eval cmd with `Error _ -> exit 1 | _ -> exit 0
]}

{2:exdarcs A [darcs] command}

We define the command line interface of a [darcs] command with the synopsis:
{[darcs [COMMAND] ...]}

The [--debug], [-q], [-v] and [--prehook] options are available in
each command.  To avoid having to pass them individually to each
command we gather them in a record of type [copts]. By lifting the
record constructor [copts] into the term [copts_t] we now have a term
that we can pass to the commands to stand for an argument of type
[copts]. These options are documented in a section called [COMMON
OPTIONS], since we also want to put [--help] and [--version] in this
section, the term information of commands makes a judicious use of the
[sdocs] parameter of {!Term.info}.

The [help] command shows help about commands or other topics. The help
shown for commands is generated by [Cmdliner] by making an approriate
use of {!Term.ret} on the lifted [help] function.

If the program is invoked without a command we just want to show the
help of the program as printed by [Cmdliner] with [--help]. This is
done by the [no_cmd] term.

{[
(* Implementations, just print the args. *)

type verb = Normal | Quiet | Verbose
type copts = { debug : bool; verb : verb; prehook : string option }

let str = Printf.sprintf
let opt_str sv = function None -> "None" | Some v -> str "Some(%s)" (sv v)
let opt_str_str = opt_str (fun s -> s)
let verb_str = function
  | Normal -> "normal" | Quiet -> "quiet" | Verbose -> "verbose"

let pr_copts oc copts = Printf.fprintf oc
    "debug = %b\nverbosity = %s\nprehook = %s\n"
    copts.debug (verb_str copts.verb) (opt_str_str copts.prehook)

let initialize copts repodir = Printf.printf
    "%arepodir = %s\n" pr_copts copts repodir

let record copts name email all ask_deps files = Printf.printf
    "%aname = %s\nemail = %s\nall = %b\nask-deps = %b\nfiles = %s\n"
    pr_copts copts (opt_str_str name) (opt_str_str email) all ask_deps
    (String.concat ", " files)

let help copts man_format cmds topic = match topic with
| None -> `Help (`Pager, None) (* help about the program. *)
| Some topic ->
    let topics = "topics" :: "patterns" :: "environment" :: cmds in
    let conv, _ = Cmdliner.Arg.enum (List.rev_map (fun s -> (s, s)) topics) in
    match conv topic with
    | `Error e -> `Error (false, e)
    | `Ok t when t = "topics" -> List.iter print_endline topics; `Ok ()
    | `Ok t when List.mem t cmds -> `Help (man_format, Some t)
    | `Ok t ->
        let page = (topic, 7, "", "", ""), [`S topic; `P "Say something";] in
        `Ok (Cmdliner.Manpage.print man_format Format.std_formatter page)

open Cmdliner;;

(* Help sections common to all commands *)

let copts_sect = "COMMON OPTIONS"
let help_secs = [
 `S copts_sect;
 `P "These options are common to all commands.";
 `S "MORE HELP";
 `P "Use `$(mname) $(i,COMMAND) --help' for help on a single command.";`Noblank;
 `P "Use `$(mname) help patterns' for help on patch matching."; `Noblank;
 `P "Use `$(mname) help environment' for help on environment variables.";
 `S "BUGS"; `P "Check bug reports at http://bugs.example.org.";]

(* Options common to all commands *)

let copts debug verb prehook = { debug; verb; prehook }
let copts_t =
  let docs = copts_sect in
  let debug =
    let doc = "Give only debug output." in
    Arg.(value & flag & info ["debug"] ~docs ~doc)
  in
  let verb =
    let doc = "Suppress informational output." in
    let quiet = Quiet, Arg.info ["q"; "quiet"] ~docs ~doc in
    let doc = "Give verbose output." in
    let verbose = Verbose, Arg.info ["v"; "verbose"] ~docs ~doc in
    Arg.(last & vflag_all [Normal] [quiet; verbose])
  in
  let prehook =
    let doc = "Specify command to run before this $(mname) command." in
    Arg.(value & opt (some string) None & info ["prehook"] ~docs ~doc)
  in
  Term.(const copts $ debug $ verb $ prehook)

(* Commands *)

let initialize_cmd =
  let repodir =
    let doc = "Run the program in repository directory $(docv)." in
    Arg.(value & opt file Filename.current_dir_name & info ["repodir"]
           ~docv:"DIR" ~doc)
  in
  let doc = "make the current directory a repository" in
  let man = [
    `S "DESCRIPTION";
    `P "Turns the current directory into a Darcs repository. Any
       existing files and subdirectories become ..."] @ help_secs
  in
  Term.(const initialize $ copts_t $ repodir),
  Term.info "initialize" ~sdocs:copts_sect ~doc ~man

let record_cmd =
  let pname =
    let doc = "Name of the patch." in
    Arg.(value & opt (some string) None & info ["m"; "patch-name"] ~docv:"NAME"
         ~doc)
  in
  let author =
    let doc = "Specifies the author's identity." in
    Arg.(value & opt (some string) None & info ["A"; "author"] ~docv:"EMAIL"
         ~doc)
  in
  let all =
    let doc = "Answer yes to all patches." in
    Arg.(value & flag & info ["a"; "all"] ~doc)
  in
  let ask_deps =
    let doc = "Ask for extra dependencies." in
    Arg.(value & flag & info ["ask-deps"] ~doc)
  in
  let files = Arg.(value & (pos_all file) [] & info [] ~docv:"FILE or DIR") in
  let doc = "create a patch from unrecorded changes" in
  let man =
    [`S "DESCRIPTION";
     `P "Creates a patch from changes in the working tree. If you specify
      a set of files ..."] @ help_secs
  in
  Term.(const record $ copts_t $ pname $ author $ all $ ask_deps $ files),
  Term.info "record" ~doc ~sdocs:copts_sect ~man

let help_cmd =
  let topic =
    let doc = "The topic to get help on. `topics' lists the topics." in
    Arg.(value & pos 0 (some string) None & info [] ~docv:"TOPIC" ~doc)
  in
  let doc = "display help about darcs and darcs commands" in
  let man =
    [`S "DESCRIPTION";
     `P "Prints help about darcs commands and other subjects..."] @ help_secs
  in
  Term.(ret
          (const help $ copts_t $ Term.man_format $ Term.choice_names $topic)),
  Term.info "help" ~doc ~man

let default_cmd =
  let doc = "a revision control system" in
  let man = help_secs in
  Term.(ret (const (fun _ -> `Help (`Pager, None)) $ copts_t)),
  Term.info "darcs" ~version:"1.6.1" ~sdocs:copts_sect ~doc ~man

let cmds = [initialize_cmd; record_cmd; help_cmd]

let () = match Term.eval_choice default_cmd cmds with
| `Error _ -> exit 1 | _ -> exit 0
]}
*)

(*---------------------------------------------------------------------------
   Copyright (c) 2011 Daniel C. Bünzli
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:

   1. Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

   2. Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.

   3. Neither the name of Daniel C. Bünzli nor the names of
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  ---------------------------------------------------------------------------*)