···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+---------------------------------------------------------------------------*)
55+66+open Cmdliner
77+88+let psl = lazy (Publicsuffix.create ())
99+1010+let print_error e =
1111+ Printf.printf "ERROR: %s\n" (Publicsuffix.error_to_string e)
1212+1313+let print_result = function
1414+ | Ok s -> print_endline s
1515+ | Error e -> print_error e
1616+1717+let print_bool_result = function
1818+ | Ok b -> print_endline (string_of_bool b)
1919+ | Error e -> print_error e
2020+2121+let print_result_with_section = function
2222+ | Ok (s, sec) ->
2323+ let sec_str = match sec with
2424+ | Publicsuffix.ICANN -> "ICANN"
2525+ | Publicsuffix.Private -> "PRIVATE"
2626+ in
2727+ Printf.printf "%s (%s)\n" s sec_str
2828+ | Error e -> print_error e
2929+3030+(* Common arguments *)
3131+3232+let domain_arg =
3333+ let doc = "The domain name to query." in
3434+ Arg.(required & pos 0 (some string) None & info [] ~docv:"DOMAIN" ~doc)
3535+3636+(* Commands *)
3737+3838+let registrable_cmd =
3939+ let doc = "Get the registrable domain for a given domain" in
4040+ let info = Cmd.info "registrable" ~doc in
4141+ let term =
4242+ Term.(const (fun domain ->
4343+ print_result (Publicsuffix.registrable_domain (Lazy.force psl) domain))
4444+ $ domain_arg)
4545+ in
4646+ Cmd.v info term
4747+4848+let suffix_cmd =
4949+ let doc = "Get the public suffix for a given domain" in
5050+ let info = Cmd.info "suffix" ~doc in
5151+ let term =
5252+ Term.(const (fun domain ->
5353+ print_result (Publicsuffix.public_suffix (Lazy.force psl) domain))
5454+ $ domain_arg)
5555+ in
5656+ Cmd.v info term
5757+5858+let is_suffix_cmd =
5959+ let doc = "Check if a domain is a public suffix" in
6060+ let info = Cmd.info "is_suffix" ~doc in
6161+ let term =
6262+ Term.(const (fun domain ->
6363+ print_bool_result (Publicsuffix.is_public_suffix (Lazy.force psl) domain))
6464+ $ domain_arg)
6565+ in
6666+ Cmd.v info term
6767+6868+let is_registrable_cmd =
6969+ let doc = "Check if a domain is a registrable domain" in
7070+ let info = Cmd.info "is_registrable" ~doc in
7171+ let term =
7272+ Term.(const (fun domain ->
7373+ print_bool_result (Publicsuffix.is_registrable_domain (Lazy.force psl) domain))
7474+ $ domain_arg)
7575+ in
7676+ Cmd.v info term
7777+7878+let registrable_section_cmd =
7979+ let doc = "Get the registrable domain with section information" in
8080+ let info = Cmd.info "registrable_section" ~doc in
8181+ let term =
8282+ Term.(const (fun domain ->
8383+ print_result_with_section (Publicsuffix.registrable_domain_with_section (Lazy.force psl) domain))
8484+ $ domain_arg)
8585+ in
8686+ Cmd.v info term
8787+8888+let suffix_section_cmd =
8989+ let doc = "Get the public suffix with section information" in
9090+ let info = Cmd.info "suffix_section" ~doc in
9191+ let term =
9292+ Term.(const (fun domain ->
9393+ print_result_with_section (Publicsuffix.public_suffix_with_section (Lazy.force psl) domain))
9494+ $ domain_arg)
9595+ in
9696+ Cmd.v info term
9797+9898+let stats_cmd =
9999+ let doc = "Print statistics about the Public Suffix List" in
100100+ let info = Cmd.info "stats" ~doc in
101101+ let term =
102102+ Term.(const (fun () ->
103103+ let psl = Lazy.force psl in
104104+ Printf.printf "Total rules: %d\n" (Publicsuffix.rule_count psl);
105105+ Printf.printf "ICANN rules: %d\n" (Publicsuffix.icann_rule_count psl);
106106+ Printf.printf "Private rules: %d\n" (Publicsuffix.private_rule_count psl))
107107+ $ const ())
108108+ in
109109+ Cmd.v info term
110110+111111+let default_cmd =
112112+ let doc = "Query the Public Suffix List" in
113113+ let sdocs = Manpage.s_common_options in
114114+ let info = Cmd.info "publicsuffix" ~version:"%%VERSION%%" ~doc ~sdocs in
115115+ Cmd.group info [
116116+ registrable_cmd;
117117+ suffix_cmd;
118118+ is_suffix_cmd;
119119+ is_registrable_cmd;
120120+ registrable_section_cmd;
121121+ suffix_section_cmd;
122122+ stats_cmd;
123123+ ]
+35
lib/cmd/publicsuffix_cmd.mli
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+---------------------------------------------------------------------------*)
55+66+(** Command-line interface terms for the publicsuffix library.
77+88+ This module provides Cmdliner terms that can be used to build
99+ command-line tools that work with the Public Suffix List. *)
1010+1111+(** {1 Command terms} *)
1212+1313+val registrable_cmd : unit Cmdliner.Cmd.t
1414+(** Command to get the registrable domain for a given domain. *)
1515+1616+val suffix_cmd : unit Cmdliner.Cmd.t
1717+(** Command to get the public suffix for a given domain. *)
1818+1919+val is_suffix_cmd : unit Cmdliner.Cmd.t
2020+(** Command to check if a domain is a public suffix. *)
2121+2222+val is_registrable_cmd : unit Cmdliner.Cmd.t
2323+(** Command to check if a domain is a registrable domain. *)
2424+2525+val registrable_section_cmd : unit Cmdliner.Cmd.t
2626+(** Command to get the registrable domain with section information. *)
2727+2828+val suffix_section_cmd : unit Cmdliner.Cmd.t
2929+(** Command to get the public suffix with section information. *)
3030+3131+val stats_cmd : unit Cmdliner.Cmd.t
3232+(** Command to print statistics about the Public Suffix List. *)
3333+3434+val default_cmd : unit Cmdliner.Cmd.t
3535+(** The default command that groups all subcommands. *)
+32
publicsuffix-cmd.opam
···11+# This file is generated by dune, edit dune-project instead
22+opam-version: "2.0"
33+synopsis: "Command-line interface library for publicsuffix"
44+description:
55+ "Provides Cmdliner terms for building command-line tools that query the Public Suffix List. Can be used to build custom CLIs that need PSL functionality."
66+maintainer: ["Anil Madhavapeddy <anil@recoil.org>"]
77+authors: ["Anil Madhavapeddy"]
88+license: "ISC"
99+homepage: "https://tangled.org/@anil.recoil.org/ocaml-publicsuffix"
1010+bug-reports: "https://tangled.org/@anil.recoil.org/ocaml-publicsuffix/issues"
1111+depends: [
1212+ "ocaml" {>= "4.14.0"}
1313+ "dune" {>= "3.18" & >= "3.0"}
1414+ "publicsuffix"
1515+ "cmdliner" {>= "1.3.0"}
1616+ "odoc" {with-doc}
1717+]
1818+build: [
1919+ ["dune" "subst"] {dev}
2020+ [
2121+ "dune"
2222+ "build"
2323+ "-p"
2424+ name
2525+ "-j"
2626+ jobs
2727+ "@install"
2828+ "@runtest" {with-test}
2929+ "@doc" {with-doc}
3030+ ]
3131+]
3232+x-maintenance-intent: ["(latest)"]