Add the "pr_wrap_cstr" function, for wrapping C string literals.
Bugzilla:
https://bugzilla.redhat.com/show_bug.cgi?id=2172516
Signed-off-by: Laszlo Ersek <lersek(a)redhat.com>
---
generator/utils.mli | 1 +
generator/utils.ml | 54 ++++++++++++++++++++
2 files changed, 55 insertions(+)
diff --git a/generator/utils.mli b/generator/utils.mli
index 5bbb188fe934..9d6640c87842 100644
--- a/generator/utils.mli
+++ b/generator/utils.mli
@@ -53,6 +53,7 @@ val
val output_to : string -> (unit -> 'a) -> unit
val pr : ('a, unit, string, unit) format4 -> 'a
val pr_wrap : ?maxcol:int -> char -> (unit -> 'a) -> unit
+val pr_wrap_cstr : ?maxcol:int -> (unit -> 'a) -> unit
val output_lineno : unit -> int
val output_column : unit -> int
diff --git a/generator/utils.ml b/generator/utils.ml
index 919572b73557..ff1e8a72f7aa 100644
--- a/generator/utils.ml
+++ b/generator/utils.ml
@@ -213,6 +213,60 @@ let
*)
pr "%s" (String.concat "\n" rest)
+(* Wrap the C string literal output at ‘maxcol’, breaking up lines when a space
+ * character occurs. For example:
+ * foobar = "a b c d e f g h i j k"
+ * └── pr_wrap_cstr ───┘
+ * becomes:
+ * foobar = "a b c d "
+ * "e f g h "
+ * "i j k"
+ *
+ * Note that:
+ * - ‘code’ MUST NOT produce the surrounding quotes,
+ * - ‘code’ MUST NOT produce multiple lines,
+ * - ‘code’ MUST do its own quoting,
+ * - space characters produced by ‘code’ cannot be escaped from wrapping.
+ *)
+let pr_wrap_cstr ?(maxcol = 76) code =
+ (* Just before entering ‘pr_wrap_cstr’, a leading quote must have been
+ * produced.
+ *)
+ let wrapping_col = !col - 1 in
+ assert (wrapping_col >= 0);
+
+ let b = pr_buf code in
+ let lines = nsplit "\n" (Buffer.contents b) in
+ match lines with
+ | [] -> ()
+ | line :: [] ->
+ let fields = nsplit " " line in
+ let nfields = List.length fields in
+ let indent = spaces wrapping_col in
+ List.iteri
+ (fun i field ->
+ (* Append a space character to each field except the last. *)
+ let f = if i < nfields - 1 then field ^ " " else field in
+
+ (* Terminate the string literal, insert a line break, and start a
+ * properly indented new string literal, before printing the field, if
+ * (a) the field is not the first one in this string literal, and (b)
+ * printing the field plus a literal-terminating quote would not fit
+ * in ‘maxcol’.
+ *
+ * Note that this way, the literal-terminating quote will always fit
+ * in ‘maxcol’, except when the *sole* field in the literal is too
+ * long.
+ *)
+ if !col > wrapping_col + 1 &&
+ !col + (String.length f) + 1 > maxcol then
+ pr "\"\n%s\"" indent;
+
+ (* Print the field. *)
+ pr "%s" f
+ ) fields
+ | _ -> assert false
+
let output_lineno () = !lineno
let output_column () = !col