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
|
(* hey emacs, this is OCaml code: -*- tuareg -*- *)
(* nbd client library in userspace: generate the C API and documentation
* Copyright Red Hat
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*)
open Printf
open API
open Utils
(* We generate a fragment of Makefile.am containing the list
* of generated functions, used in rules for building the manual
* pages. We exploit GNU make's sinclude to use this file without
* upsetting automake.
*)
let generate_docs_Makefile_inc () =
generate_header HashStyle;
pr "api_built += \\\n";
List.iter (
fun (name, _) ->
pr "\tnbd_%s \\\n" name;
) handle_calls;
pr "\t$(NULL)\n"
let generate_docs_api_links_pod () =
let pages =
List.map (fun (name, _) -> sprintf "nbd_%s(3)" name) handle_calls in
let pages =
"nbd_create(3)" ::
"nbd_close(3)" ::
"nbd_get_error(3)" ::
"nbd_get_errno(3)" ::
pages in
let pages = List.sort compare pages in
List.iteri (
fun i page ->
if i > 0 then pr ",\n";
pr "L<%s>" page
) pages;
pr ".\n"
let generate_docs_api_flag_links_pod () =
let pages =
filter_map (
fun (name, _) ->
if (is_prefix name "is_" && name <> "is_uri") ||
is_prefix name "can_" then
Some (sprintf "nbd_%s(3)" name)
else
None
) handle_calls in
let pages = List.sort compare pages in
List.iteri (
fun i page ->
if i > 0 then pr ",\n";
pr "L<%s>" page
) pages;
pr ".\n"
let print_docs_closure { cbname; cbargs } =
pr " typedef struct {\n";
pr " int (*callback) ";
C.print_cbarg_list ~wrap:true ~maxcol:60 cbargs;
pr ";\n";
pr " void *user_data;\n";
pr " void (*free) (void *user_data);\n";
pr " } nbd_%s_callback;\n" cbname
let generate_docs_nbd_pod name { args; optargs; ret;
shortdesc; longdesc; example; see_also;
permitted_states; may_set_error;
first_version = (major, minor) } () =
pr "=head1 NAME\n";
pr "\n";
pr "nbd_%s -" name;
(* Don't use pr_wrap here because it leaves trailing whitespace. *)
let words = nsplit " " shortdesc in
List.iter (
fun word ->
if output_column () + String.length word > 70 then pr "\n%s" word
else pr " %s" word
) words;
pr "\n";
pr "\n";
pr "=head1 SYNOPSIS\n";
pr "\n";
pr " #include <libnbd.h>\n";
pr "\n";
List.iter (
function
| Closure cb -> print_docs_closure cb; pr "\n"
| _ -> ()
) args;
List.iter (
function
| OClosure cb -> print_docs_closure cb; pr "\n"
| _ -> ()
) optargs;
pr " ";
C.print_call ~wrap:true ~maxcol:60 name args optargs ret;
pr ";\n";
pr "\n";
pr "=head1 DESCRIPTION\n";
pr "\n";
pr "%s\n" longdesc;
pr "\n";
pr "=head1 RETURN VALUE\n";
pr "\n";
let errcode = C.errcode_of_ret ret in
(match ret with
| RBool ->
pr "This call returns a boolean value.\n"
| RStaticString ->
pr "This call returns a statically allocated string, valid for the\n";
pr "lifetime of the process or until libnbd is unloaded by\n";
pr "L<dlclose(3)>. You B<must not> try to free the string.\n"
| RErr ->
pr "If the call is successful the function returns C<0>.\n"
| RFd ->
pr "This call returns a file descriptor.\n"
| RInt ->
pr "This call returns an integer E<ge> C<0>.\n";
| RInt64 ->
pr "This call returns a 64 bit signed integer E<ge> C<0>.\n";
| RCookie ->
pr "This call returns the 64 bit cookie of the command.\n";
pr "The cookie is E<ge> C<1>.\n";
pr "Cookies are unique (per libnbd handle, not globally).\n"
| RSizeT ->
pr "This call returns an integer size E<ge> C<0>.\n";
| RString ->
pr "This call returns a string. The caller must free the\n";
pr "returned string to avoid a memory leak.\n";
| RUInt ->
pr "This call returns a bitmask.\n";
| RUIntPtr ->
pr "This call returns a C<uintptr_t>.\n";
| RUInt64 ->
pr "This call returns a counter.\n";
| REnum { enum_prefix } ->
pr "This call returns one of the LIBNBD_%s_* values.\n" enum_prefix;
| RFlags { flag_prefix } ->
pr "This call returns a bitmask of LIBNBD_%s_* values.\n" flag_prefix;
);
pr "\n";
pr "=head1 ERRORS\n";
pr "\n";
if may_set_error then (
let value = match errcode with
| Some value -> value
| None -> assert false in
pr "On error C<%s> is returned.\n" value;
pr "\n";
pr "Refer to L<libnbd(3)/ERROR HANDLING>\n";
pr "for how to get further details of the error.\n"
)
else
pr "This function does not fail.\n";
pr "\n";
pr "The following parameters must not be NULL: C<h>";
List.iter (
fun arg ->
let nns = C.arg_attr_nonnull arg in
if List.mem true nns then pr ", C<%s>" (List.hd (C.name_of_arg arg))
) args;
List.iter (
fun arg ->
let nns = C.optarg_attr_nonnull arg in
if List.mem true nns then pr ", C<%s>" (C.name_of_optarg arg)
) optargs;
pr ".\n";
pr "For more information see L<libnbd(3)/Non-NULL parameters>.\n";
pr "\n";
if permitted_states <> [] then (
pr "=head1 HANDLE STATE\n";
pr "\n";
pr "nbd_%s\ncan be called when the handle is in the following %s:\n"
name (if List.length permitted_states = 1 then "state" else "states");
pr "\n";
pr " ┌─────────────────────────────────────┬─────────────────────────┐\n";
let row ps description =
let permitted = List.mem ps permitted_states in
pr " │ %-35s │ %s %-20s │\n" description
(if permitted then "✅" else "❌")
(if permitted then "allowed" else "error")
in
List.iter (
fun ps ->
match ps with
| Created -> row ps "Handle created, before connecting"
| Connecting -> row ps "Connecting"
| Negotiating -> row ps "Connecting & handshaking (opt_mode)"
| Connected -> row ps "Connected to the server"
| Closed -> row ps "Connection shut down"
| Dead -> row ps "Handle dead"
) all_permitted_states;
pr " └─────────────────────────────────────┴─────────────────────────┘\n";
pr "\n"
);
pr "=head1 VERSION\n";
pr "\n";
pr "This function first appeared in libnbd %d.%d.\n" major minor;
pr "\n";
pr "If you need to test if this function is available at compile time\n";
pr "check if the following macro is defined:\n";
pr "\n";
pr " #define LIBNBD_HAVE_NBD_%s 1\n" (String.uppercase_ascii name);
pr "\n";
(match example with
| None -> ()
| Some filename ->
pr "=head1 EXAMPLE\n";
pr "\n";
pr "This example is also available as F<%s>\n" filename;
pr "in the libnbd source code.\n";
pr "\n";
let chan = open_in filename in
(try
while true do
let line = input_line chan in
let len = String.length line in
if len > 60 then
failwithf "%s: %s: line too long in example" name filename;
if len = 0 then pr "\n" else pr " %s\n" line
done
with End_of_file -> ()
);
close_in chan;
pr "\n"
);
let () =
pr "=head1 SEE ALSO\n";
pr "\n";
let other_links = extract_links longdesc in
let std_links = [MainPageLink; Link "create"] in
let links = see_also @ other_links @ std_links in
let links = sort_uniq_links links in
List.iter verify_link links;
let links = List.map pod_of_link links in
let comma = ref false in
List.iter (
fun pod ->
if !comma then pr ",\n"; comma := true;
pr "%s" pod
) links;
pr ".\n\n" in
pr "\
=head1 AUTHORS
Eric Blake
Richard W.M. Jones
=head1 COPYRIGHT
Copyright Red Hat
"
|