From 91b39a095b1860bf5446251de184bfb94c32eb1a Mon Sep 17 00:00:00 2001 From: Pau Ruiz Safont Date: Mon, 20 May 2024 15:38:37 +0100 Subject: [PATCH 1/8] xapi-stdext-std: String.split's ~limit is not optional Users can instead opt for Astring.String's or stdlib's functions. Signed-off-by: Pau Ruiz Safont Signed-off-by: Pau Ruiz Safont --- doc/content/xapi/cli/_index.md | 2 +- ocaml/database/parse_db_conf.ml | 4 +-- .../lib/xapi-stdext-std/xstringext.ml | 25 +++++++-------- .../lib/xapi-stdext-std/xstringext.mli | 2 +- .../lib/xapi-stdext-std/xstringext_test.ml | 31 +++++-------------- ocaml/quicktest/quicktest_http.ml | 2 +- ocaml/rrd2csv/src/rrd2csv.ml | 4 +-- ocaml/xapi/authx.ml | 4 ++- ocaml/xapi/config_file_sync.ml | 3 +- ocaml/xapi/dbsync_slave.ml | 6 ++-- ocaml/xapi/gpg.ml | 4 +-- ocaml/xapi/map_check.ml | 2 +- ocaml/xapi/nm.ml | 2 +- ocaml/xapi/vhd_tool_wrapper.ml | 4 +-- ocaml/xapi/xapi_globs.ml | 5 +-- ocaml/xapi/xapi_pif.ml | 6 ++-- ocaml/xapi/xapi_pool_update.ml | 2 +- ocaml/xapi/xapi_xenops.ml | 12 ++++--- ocaml/xcp-rrdd/bin/rrdp-iostat/rrdp_iostat.ml | 2 +- .../bin/rrdp-squeezed/rrdp_squeezed.ml | 4 ++- ocaml/xe-cli/newcli.ml | 2 +- 21 files changed, 61 insertions(+), 67 deletions(-) diff --git a/doc/content/xapi/cli/_index.md b/doc/content/xapi/cli/_index.md index 6715e7288c0..093e1576aaf 100644 --- a/doc/content/xapi/cli/_index.md +++ b/doc/content/xapi/cli/_index.md @@ -156,7 +156,7 @@ So each function receives a printer for sending text output to the xe client, an let mac = List.assoc_default "mac" params "" in let network = Client.Network.get_by_uuid rpc session_id network in let pifs = List.assoc "pif-uuids" params in - let uuids = String.split ',' pifs in + let uuids = String.split_on_char ',' pifs in let pifs = List.map (fun uuid -> Client.PIF.get_by_uuid rpc session_id uuid) uuids in let mode = Record_util.bond_mode_of_string (List.assoc_default "mode" params "") in let properties = read_map_params "properties" params in diff --git a/ocaml/database/parse_db_conf.ml b/ocaml/database/parse_db_conf.ml index 67aa5c70d80..76deca97e42 100644 --- a/ocaml/database/parse_db_conf.ml +++ b/ocaml/database/parse_db_conf.ml @@ -110,7 +110,7 @@ let parse_db_conf s = let conf = Unixext.string_of_file s in let lines : string list ref = ref [] in let consume_line () = lines := List.tl !lines in - lines := String.split '\n' conf ; + lines := String.split_on_char '\n' conf ; List.iter (fun line -> debug "%s" line) !lines ; let read_block () = let path_line = List.hd !lines in @@ -120,7 +120,7 @@ let parse_db_conf s = while !lines <> [] && List.hd !lines <> "" do let line = List.hd !lines in key_values := - ( match String.split ':' line with + ( match String.split_on_char ':' line with | k :: vs -> ( String.lowercase_ascii k , String.lowercase_ascii (String.concat ":" vs) diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml index 4e5379d7b36..6c759498def 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml @@ -76,15 +76,18 @@ module String = struct in loop 0 - let rec split ?(limit = -1) c s = - let i = match index_opt s c with Some x -> x | None -> -1 in - let nlimit = if limit = -1 || limit = 0 then limit else limit - 1 in - if i = -1 || nlimit = 0 then - [s] - else - let a = String.sub s 0 i - and b = String.sub s (i + 1) (String.length s - i - 1) in - a :: split ~limit:nlimit c b + let sub_to_end s start = + let length = String.length s in + String.sub s start (length - start) + + let rec split ~limit sep s = + match (String.index_opt s sep, limit < 2) with + | None, _ | _, true -> + [s] + | Some pos, false -> + let first = String.sub s 0 pos in + let rest = sub_to_end s (pos + 1) in + first :: split ~limit:(limit - 1) sep rest let rtrim s = let n = String.length s in @@ -185,10 +188,6 @@ module String = struct | Some rules -> map_unlikely s (fun c -> List.assoc_opt c rules) - let sub_to_end s start = - let length = String.length s in - String.sub s start (length - start) - let sub_before c s = String.sub s 0 (String.index s c) let sub_after c s = sub_to_end s (String.index s c + 1) diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli index 1f27490493d..d68e3f524f8 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli @@ -42,7 +42,7 @@ module String : sig runs of characters where the predicate was true. Avoid if possible, it's very costly to execute. *) - val split : ?limit:int -> char -> string -> string list + val split : limit:int -> char -> string -> string list (** split a string on a single char *) val rtrim : string -> string diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext_test.ml b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext_test.ml index 9b7eb2674a1..4a70eb31899 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext_test.ml +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext_test.ml @@ -44,30 +44,13 @@ let test_rev_map = ("rev_map", tests) let test_split = - let test ?limit (splitter, splitted, expected) = - let split, name = - match limit with - | None -> - let name = Printf.sprintf {|'%c' splits "%s"|} splitter splitted in - (* limit being set to -1 is the same as not using the parameter *) - let split = XString.split ~limit:(-1) in - (split, name) - | Some limit -> - let name = - Printf.sprintf {|'%c' splits "%s" with limit %i|} splitter splitted - limit - in - let split = XString.split ~limit in - (split, name) + let test limit (splitter, splitted, expected) = + let split = XString.split ~limit in + let name = + Printf.sprintf {|'%c' splits "%s" with limit %i|} splitter splitted limit in test_list (split splitter) (name, splitted, expected) in - let specs_no_limit = - [ - ('.', "...", [""; ""; ""; ""]); ('.', "foo.bar.baz", ["foo"; "bar"; "baz"]) - ] - in - let tests_no_limit = List.map test specs_no_limit in let specs_limit = [ (0, [('.', "...", ["..."]); ('.', "foo.bar.baz", ["foo.bar.baz"])]) @@ -82,12 +65,12 @@ let test_split = ; (4, [('.', "...", [""; ""; ""; ""])]) ] in - let tests_limit = + let tests = List.concat_map - (fun (limit, spec) -> List.map (test ~limit) spec) + (fun (limit, spec) -> List.map (test limit) spec) specs_limit in - ("split", List.concat [tests_no_limit; tests_limit]) + ("split", tests) let test_split_f = let specs = diff --git a/ocaml/quicktest/quicktest_http.ml b/ocaml/quicktest/quicktest_http.ml index 0320cf12ab3..09cccbc3e60 100644 --- a/ocaml/quicktest/quicktest_http.ml +++ b/ocaml/quicktest/quicktest_http.ml @@ -34,7 +34,7 @@ module Uds = struct with_channel_aux fd func let http_response_code d = - match Xapi_stdext_std.Xstringext.String.split ' ' d with + match Xapi_stdext_std.Xstringext.String.split_on_char ' ' d with | _ :: code :: _ -> int_of_string code | _ -> diff --git a/ocaml/rrd2csv/src/rrd2csv.ml b/ocaml/rrd2csv/src/rrd2csv.ml index 37e00f8148d..1cfadb61983 100644 --- a/ocaml/rrd2csv/src/rrd2csv.ml +++ b/ocaml/rrd2csv/src/rrd2csv.ml @@ -149,10 +149,10 @@ module Ds_selector = struct let of_string str = let open Rrd in - let splitted = Xstringext.String.split ',' str in + let splitted = String.split_on_char ',' str in match splitted with | without_trailing_comma :: _ -> ( - let splitted = Xstringext.String.split ':' without_trailing_comma in + let splitted = String.split_on_char ':' without_trailing_comma in match splitted with | [cf; owner; uuid; metric] -> { diff --git a/ocaml/xapi/authx.ml b/ocaml/xapi/authx.ml index 87d85e40332..92f085648aa 100644 --- a/ocaml/xapi/authx.ml +++ b/ocaml/xapi/authx.ml @@ -65,7 +65,9 @@ module AuthX : Auth_signature.AUTH_MODULE = struct | [] -> raise Not_found | line :: lines -> ( - let recs = Xapi_stdext_std.Xstringext.String.split ':' line in + let recs = + Xapi_stdext_std.Xstringext.String.split_on_char ':' line + in let username = List.nth recs 0 in let uid = List.nth recs 2 in match fn username uid recs with diff --git a/ocaml/xapi/config_file_sync.ml b/ocaml/xapi/config_file_sync.ml index b765f1ceae6..c291ebcd841 100644 --- a/ocaml/xapi/config_file_sync.ml +++ b/ocaml/xapi/config_file_sync.ml @@ -58,7 +58,8 @@ let config_file_sync_handler (req : Http.Request.t) s _ = Xapi_http.with_context "Syncing dom0 config files over HTTP" req s (fun __context -> let uri = - String.split '/' req.Http.Request.path |> List.filter (fun x -> x <> "") + String.split_on_char '/' req.Http.Request.path + |> List.filter (fun x -> x <> "") in req.Http.Request.close <- true ; debug "sending headers" ; diff --git a/ocaml/xapi/dbsync_slave.ml b/ocaml/xapi/dbsync_slave.ml index ff325b7259e..bbd83451af8 100644 --- a/ocaml/xapi/dbsync_slave.ml +++ b/ocaml/xapi/dbsync_slave.ml @@ -75,9 +75,9 @@ let get_start_time () = match Unixext.string_of_file "/proc/stat" |> String.trim - |> String.split '\n' + |> String.split_on_char '\n' |> List.find (fun s -> String.starts_with ~prefix:"btime" s) - |> String.split ' ' + |> String.split_on_char ' ' with | _ :: btime :: _ -> let boot_time = Date.of_unix_time (float_of_string btime) in @@ -111,7 +111,7 @@ let refresh_localhost_info ~__context info = | None -> [] | Some {capabilities; _} -> - String.split ' ' capabilities + String.split_on_char ' ' capabilities in Db.Host.set_capabilities ~__context ~self:host ~value:caps ; Db.Host.set_address ~__context ~self:host ~value:(get_my_ip_addr ~__context) ; diff --git a/ocaml/xapi/gpg.ml b/ocaml/xapi/gpg.ml index 1dd5c8141c8..6589ea7c321 100644 --- a/ocaml/xapi/gpg.ml +++ b/ocaml/xapi/gpg.ml @@ -26,7 +26,7 @@ let gpg_binary_path = "/usr/bin/gpg" exception InvalidSignature let parse_gpg_status status_data = - let lines = String.split '\n' status_data in + let lines = String.split_on_char '\n' status_data in let status_contains substr = List.exists (fun s -> String.starts_with ~prefix:substr s) lines in @@ -42,7 +42,7 @@ let parse_gpg_status status_data = let validsigline = List.find (fun s -> String.starts_with ~prefix:validsig s) lines in - match String.split ' ' validsigline with + match String.split_on_char ' ' validsigline with | _ :: _ :: fingerprint :: _ -> Some fingerprint | _ -> diff --git a/ocaml/xapi/map_check.ml b/ocaml/xapi/map_check.ml index 0cb2d97e37f..01de88d4290 100644 --- a/ocaml/xapi/map_check.ml +++ b/ocaml/xapi/map_check.ml @@ -104,7 +104,7 @@ let assert_value ~field ~key ~attr ~value = ) | EnumSet range -> (* enumset is a comma-separated string *) - let vs = Xapi_stdext_std.Xstringext.String.split ',' value in + let vs = Xapi_stdext_std.Xstringext.String.split_on_char ',' value in List.fold_right (fun v acc -> match mem v range with diff --git a/ocaml/xapi/nm.ml b/ocaml/xapi/nm.ml index fa86a6f08e7..735bdbe98a8 100644 --- a/ocaml/xapi/nm.ml +++ b/ocaml/xapi/nm.ml @@ -470,7 +470,7 @@ let determine_static_routes net_rc = if List.mem_assoc "static-routes" net_rc.API.network_other_config then try let routes = - String.split ',' + String.split_on_char ',' (List.assoc "static-routes" net_rc.API.network_other_config) in List.map diff --git a/ocaml/xapi/vhd_tool_wrapper.ml b/ocaml/xapi/vhd_tool_wrapper.ml index f3f791fe251..049d8effdf2 100644 --- a/ocaml/xapi/vhd_tool_wrapper.ml +++ b/ocaml/xapi/vhd_tool_wrapper.ml @@ -125,7 +125,7 @@ let find_backend_device path = let link = Unix.readlink (Printf.sprintf "/sys/dev/block/%d:%d/device" major minor) in - match List.rev (String.split '/' link) with + match List.rev (String.split_on_char '/' link) with | id :: "xen" :: "devices" :: _ when Astring.String.is_prefix ~affix:"vbd-" id -> let id = int_of_string (String.sub id 4 (String.length id - 4)) in @@ -135,7 +135,7 @@ let find_backend_device path = xs.Xs.read (Printf.sprintf "device/vbd/%d/backend" id) in let params = xs.Xs.read (Printf.sprintf "%s/params" backend) in - match String.split '/' backend with + match String.split_on_char '/' backend with | "local" :: "domain" :: bedomid :: _ -> if not (self = bedomid) then Helpers.internal_error diff --git a/ocaml/xapi/xapi_globs.ml b/ocaml/xapi/xapi_globs.ml index 161273c83f9..1d3f3d2687f 100644 --- a/ocaml/xapi/xapi_globs.ml +++ b/ocaml/xapi/xapi_globs.ml @@ -1466,7 +1466,7 @@ let other_options = (fun s -> s) disable_dbsync_for ; ( "xenopsd-queues" - , Arg.String (fun x -> xenopsd_queues := String.split ',' x) + , Arg.String (fun x -> xenopsd_queues := String.split_on_char ',' x) , (fun () -> String.concat "," !xenopsd_queues) , "list of xenopsd instances to manage" ) @@ -1553,7 +1553,8 @@ let other_options = ; ( "nvidia_multi_vgpu_enabled_driver_versions" , Arg.String (fun x -> - nvidia_multi_vgpu_enabled_driver_versions := String.split ',' x + nvidia_multi_vgpu_enabled_driver_versions := + String.split_on_char ',' x ) , (fun () -> String.concat "," !nvidia_multi_vgpu_enabled_driver_versions) , "list of nvidia host driver versions with multiple vGPU supported.\n\ diff --git a/ocaml/xapi/xapi_pif.ml b/ocaml/xapi/xapi_pif.ml index 881c51091fb..56bdb49e565 100644 --- a/ocaml/xapi/xapi_pif.ml +++ b/ocaml/xapi/xapi_pif.ml @@ -216,7 +216,9 @@ let refresh_all ~__context ~host = pifs let read_bridges_from_inventory () = - try String.split ' ' (Xapi_inventory.lookup Xapi_inventory._current_interfaces) + try + String.split_on_char ' ' + (Xapi_inventory.lookup Xapi_inventory._current_interfaces) with _ -> [] (* Ensure the PIF is not a bond slave. *) @@ -716,7 +718,7 @@ let scan ~__context ~host = let output, _ = Forkhelpers.execute_command_get_output !Xapi_globs.non_managed_pifs [] in - let dsplit = String.split '\n' output in + let dsplit = String.split_on_char '\n' output in match dsplit with | [] | [""] | "" :: "" :: _ -> debug "No boot from SAN interface found" ; diff --git a/ocaml/xapi/xapi_pool_update.ml b/ocaml/xapi/xapi_pool_update.ml index 6aa1ea0fd71..4338cfe37fe 100644 --- a/ocaml/xapi/xapi_pool_update.ml +++ b/ocaml/xapi/xapi_pool_update.ml @@ -376,7 +376,7 @@ let parse_update_info xml = | "" -> [] | s -> - List.map guidance_from_string (String.split ',' s) + List.map guidance_from_string (String.split_on_char ',' s) with _ -> [] in let enforce_homogeneity = diff --git a/ocaml/xapi/xapi_xenops.ml b/ocaml/xapi/xapi_xenops.ml index 0ea29ea4cf7..880fd58a54f 100644 --- a/ocaml/xapi/xapi_xenops.ml +++ b/ocaml/xapi/xapi_xenops.ml @@ -1182,8 +1182,8 @@ module MD = struct let affinity = try List.map - (fun x -> List.map int_of_string (String.split ',' x)) - (String.split ';' (List.assoc "mask" vm.API.vM_VCPUs_params)) + (fun x -> List.map int_of_string (String.split_on_char ',' x)) + (String.split_on_char ';' (List.assoc "mask" vm.API.vM_VCPUs_params)) with _ -> [] in let localhost = Helpers.get_localhost ~__context in @@ -1193,7 +1193,9 @@ module MD = struct let host_cpu_mask = try List.map int_of_string - (String.split ',' (List.assoc "mask" host_guest_VCPUs_params)) + (String.split_on_char ',' + (List.assoc "mask" host_guest_VCPUs_params) + ) with _ -> [] in let affinity = @@ -1981,7 +1983,9 @@ let update_vm_internal ~__context ~id ~self ~previous ~info ~localhost = String.sub path (String.length dir) (String.length path - String.length dir) in - match List.filter (fun x -> x <> "") (String.split '/' rest) with + match + List.filter (fun x -> x <> "") (String.split_on_char '/' rest) + with | x :: _ -> Some x | _ -> diff --git a/ocaml/xcp-rrdd/bin/rrdp-iostat/rrdp_iostat.ml b/ocaml/xcp-rrdd/bin/rrdp-iostat/rrdp_iostat.ml index 6141090eae7..f60b825b16d 100644 --- a/ocaml/xcp-rrdd/bin/rrdp-iostat/rrdp_iostat.ml +++ b/ocaml/xcp-rrdd/bin/rrdp-iostat/rrdp_iostat.ml @@ -437,7 +437,7 @@ let exec_tap_ctl_list () : ((string * string) * int) list = let minor_of_tapdev_unsafe tapdev = int_of_string (Unixext.file_lines_fold - (fun acc l -> acc ^ List.nth (Xstringext.String.split ':' l) 1) + (fun acc l -> acc ^ List.nth (Xstringext.String.split_on_char ':' l) 1) "" ("/sys/block/" ^ tapdev ^ "/dev") ) diff --git a/ocaml/xcp-rrdd/bin/rrdp-squeezed/rrdp_squeezed.ml b/ocaml/xcp-rrdd/bin/rrdp-squeezed/rrdp_squeezed.ml index df49dca259f..ec5b783f3da 100644 --- a/ocaml/xcp-rrdd/bin/rrdp-squeezed/rrdp_squeezed.ml +++ b/ocaml/xcp-rrdd/bin/rrdp-squeezed/rrdp_squeezed.ml @@ -81,7 +81,9 @@ module MemoryActions = struct path domid ; current_memory_values := IntMap.remove domid !current_memory_values in - match List.filter (fun x -> x <> "") (Xstringext.String.split '/' path) with + match + List.filter (fun x -> x <> "") (Xstringext.String.split_on_char '/' path) + with | ["local"; "domain"; domid; "memory"; "dynamic-max"] -> read_new_value domid current_dynamic_max_values | ["local"; "domain"; domid; "memory"; "dynamic-min"] -> diff --git a/ocaml/xe-cli/newcli.ml b/ocaml/xe-cli/newcli.ml index 60ecce2a47d..c027a9b2e41 100644 --- a/ocaml/xe-cli/newcli.ml +++ b/ocaml/xe-cli/newcli.ml @@ -389,7 +389,7 @@ let with_open_channels f = match result with Ok r -> r | Error e -> raise e let http_response_code x = - match String.split ' ' x with + match String.split_on_char ' ' x with | _ :: code :: _ -> int_of_string code | _ -> From 8ae7840dce051405fffeade39078ad013922e2d6 Mon Sep 17 00:00:00 2001 From: Pau Ruiz Safont Date: Mon, 20 May 2024 16:26:56 +0100 Subject: [PATCH 2/8] xapi-stdext-std: Do not include String functions in XStringext Also remove all indiscriminate opens against it Signed-off-by: Pau Ruiz Safont Signed-off-by: Pau Ruiz Safont --- ocaml/database/parse_db_conf.ml | 1 - ocaml/database/redo_log.ml | 1 - ocaml/doc/dune | 3 +- ocaml/doc/jsapi.ml | 1 - ocaml/idl/ocaml_backend/gen_rbac.ml | 5 ++-- .../lib/xapi-stdext-std/xstringext.ml | 21 +++---------- .../lib/xapi-stdext-std/xstringext.mli | 2 -- ocaml/quicktest/quicktest_http.ml | 2 +- ocaml/xapi/authx.ml | 9 ++---- ocaml/xapi/config_file_sync.ml | 1 - ocaml/xapi/dbsync_slave.ml | 1 - ocaml/xapi/extauth_plugin_ADpbis.ml | 30 ++++++++++--------- ocaml/xapi/extauth_plugin_ADwinbind.ml | 1 - ocaml/xapi/fileserver.ml | 4 +-- ocaml/xapi/gpg.ml | 1 - ocaml/xapi/import.ml | 1 - ocaml/xapi/map_check.ml | 2 +- ocaml/xapi/nm.ml | 4 +-- ocaml/xapi/sm.ml | 1 - ocaml/xapi/storage_mux.ml | 4 +-- ocaml/xapi/vgpuops.ml | 1 - ocaml/xapi/vhd_tool_wrapper.ml | 1 - ocaml/xapi/wlb_reports.ml | 1 - ocaml/xapi/workload_balancing.ml | 5 ++-- ocaml/xapi/xapi_dr_task.ml | 1 - ocaml/xapi/xapi_globs.ml | 4 +-- ocaml/xapi/xapi_network.ml | 1 - ocaml/xapi/xapi_pif.ml | 6 ++-- ocaml/xapi/xapi_pool.ml | 1 - ocaml/xapi/xapi_pool_update.ml | 7 +++-- ocaml/xapi/xapi_secret.ml | 2 -- ocaml/xapi/xapi_vbd_helpers.ml | 1 - ocaml/xapi/xapi_vif_helpers.ml | 2 -- ocaml/xapi/xapi_vusb_helpers.ml | 2 -- ocaml/xapi/xapi_xenops.ml | 4 +-- ocaml/xapi/xha_interface.ml | 5 ++-- ocaml/xcp-rrdd/bin/rrdp-iostat/rrdp_iostat.ml | 2 +- .../bin/rrdp-squeezed/rrdp_squeezed.ml | 5 +--- ocaml/xe-cli/newcli.ml | 4 +-- 39 files changed, 54 insertions(+), 96 deletions(-) diff --git a/ocaml/database/parse_db_conf.ml b/ocaml/database/parse_db_conf.ml index 76deca97e42..d1c7482c080 100644 --- a/ocaml/database/parse_db_conf.ml +++ b/ocaml/database/parse_db_conf.ml @@ -13,7 +13,6 @@ *) (* !!! This needs to be moved out of xapi and into the database directory; probably being merged with db_connections !!! *) -open Xapi_stdext_std.Xstringext open Xapi_stdext_unix module D = Debug.Make (struct let name = "parse_db_conf" end) diff --git a/ocaml/database/redo_log.ml b/ocaml/database/redo_log.ml index 8c2c95928d7..42175580f83 100644 --- a/ocaml/database/redo_log.ml +++ b/ocaml/database/redo_log.ml @@ -12,7 +12,6 @@ * GNU Lesser General Public License for more details. *) open Xapi_stdext_pervasives.Pervasiveext -open Xapi_stdext_std.Xstringext open Xapi_stdext_unix let with_lock = Xapi_stdext_threads.Threadext.Mutex.execute diff --git a/ocaml/doc/dune b/ocaml/doc/dune index 061ba778232..618de9e30fb 100644 --- a/ocaml/doc/dune +++ b/ocaml/doc/dune @@ -1,7 +1,7 @@ (executable (modes exe) (name jsapi) - (libraries + (libraries mustache rpclib.core rpclib.json @@ -10,7 +10,6 @@ xapi-consts xapi-datamodel xapi-stdext-pervasives - xapi-stdext-std xapi-stdext-unix ) (preprocess (pps ppx_deriving_rpc)) diff --git a/ocaml/doc/jsapi.ml b/ocaml/doc/jsapi.ml index fa891e57743..1fef7fabf00 100644 --- a/ocaml/doc/jsapi.ml +++ b/ocaml/doc/jsapi.ml @@ -12,7 +12,6 @@ * GNU Lesser General Public License for more details. *) -open Xapi_stdext_std.Xstringext open Xapi_stdext_pervasives.Pervasiveext module Unixext = Xapi_stdext_unix.Unixext open Datamodel_types diff --git a/ocaml/idl/ocaml_backend/gen_rbac.ml b/ocaml/idl/ocaml_backend/gen_rbac.ml index 7914dba96dd..6934d691a3f 100644 --- a/ocaml/idl/ocaml_backend/gen_rbac.ml +++ b/ocaml/idl/ocaml_backend/gen_rbac.ml @@ -70,11 +70,10 @@ let role_uuid name = Option.get (hash2uuid name) let permission_description = "A basic permission" let permission_name wire_name = - let open Xapi_stdext_std in let s1 = replace_char (Printf.sprintf "permission_%s" wire_name) '.' '_' in let s2 = replace_char s1 '/' '_' in - let s3 = Xstringext.String.replace "*" "WILDCHAR" s2 in - Xstringext.String.replace ":" "_" s3 + let s3 = Xapi_stdext_std.Xstringext.String.replace "*" "WILDCHAR" s2 in + replace_char s3 ':' '_' let permission_index = ref 0 diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml index 6c759498def..0512cc35dc5 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml @@ -12,29 +12,27 @@ * GNU Lesser General Public License for more details. *) module String = struct - include String - let of_char c = String.make 1 c let rev_map f string = - let n = length string in + let n = String.length string in String.init n (fun i -> f string.[n - i - 1]) let rev_iter f string = - for i = length string - 1 downto 0 do + for i = String.length string - 1 downto 0 do f string.[i] done let fold_left f accu string = let accu = ref accu in - for i = 0 to length string - 1 do + for i = 0 to String.length string - 1 do accu := f !accu string.[i] done ; !accu let fold_right f string accu = let accu = ref accu in - for i = length string - 1 downto 0 do + for i = String.length string - 1 downto 0 do accu := f string.[i] !accu done ; !accu @@ -65,17 +63,6 @@ module String = struct |> List.of_seq |> List.rev - let index_opt s c = - let rec loop i = - if String.length s = i then - None - else if s.[i] = c then - Some i - else - loop (i + 1) - in - loop 0 - let sub_to_end s start = let length = String.length s in String.sub s start (length - start) diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli index d68e3f524f8..a890537c1de 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli @@ -12,8 +12,6 @@ * GNU Lesser General Public License for more details. *) module String : sig - include module type of String - val of_char : char -> string val rev_map : (char -> char) -> string -> string diff --git a/ocaml/quicktest/quicktest_http.ml b/ocaml/quicktest/quicktest_http.ml index 09cccbc3e60..86f9660e7ce 100644 --- a/ocaml/quicktest/quicktest_http.ml +++ b/ocaml/quicktest/quicktest_http.ml @@ -34,7 +34,7 @@ module Uds = struct with_channel_aux fd func let http_response_code d = - match Xapi_stdext_std.Xstringext.String.split_on_char ' ' d with + match String.split_on_char ' ' d with | _ :: code :: _ -> int_of_string code | _ -> diff --git a/ocaml/xapi/authx.ml b/ocaml/xapi/authx.ml index 92f085648aa..7236c793fb4 100644 --- a/ocaml/xapi/authx.ml +++ b/ocaml/xapi/authx.ml @@ -65,9 +65,7 @@ module AuthX : Auth_signature.AUTH_MODULE = struct | [] -> raise Not_found | line :: lines -> ( - let recs = - Xapi_stdext_std.Xstringext.String.split_on_char ':' line - in + let recs = String.split_on_char ':' line in let username = List.nth recs 0 in let uid = List.nth recs 2 in match fn username uid recs with @@ -293,9 +291,8 @@ module AuthX : Auth_signature.AUTH_MODULE = struct | _ -> raise Not_found - (* - In addition, there are some event hooks that auth modules implement as follows: -*) + (* In addition, there are some event hooks that auth modules implement as + follows: *) (* unit on_enable(((string*string) list) config_params) diff --git a/ocaml/xapi/config_file_sync.ml b/ocaml/xapi/config_file_sync.ml index c291ebcd841..cf877745290 100644 --- a/ocaml/xapi/config_file_sync.ml +++ b/ocaml/xapi/config_file_sync.ml @@ -15,7 +15,6 @@ module D = Debug.Make (struct let name = "config_file_sync" end) open D -open Xapi_stdext_std.Xstringext let superuser = "root" diff --git a/ocaml/xapi/dbsync_slave.ml b/ocaml/xapi/dbsync_slave.ml index bbd83451af8..ea5dddf8f82 100644 --- a/ocaml/xapi/dbsync_slave.ml +++ b/ocaml/xapi/dbsync_slave.ml @@ -17,7 +17,6 @@ *) module Rrdd = Rrd_client.Client -open Xapi_stdext_std.Xstringext module Unixext = Xapi_stdext_unix.Unixext module Date = Clock.Date open Create_misc diff --git a/ocaml/xapi/extauth_plugin_ADpbis.ml b/ocaml/xapi/extauth_plugin_ADpbis.ml index ea2dedfccc6..6c532c8eb70 100644 --- a/ocaml/xapi/extauth_plugin_ADpbis.ml +++ b/ocaml/xapi/extauth_plugin_ADpbis.ml @@ -18,7 +18,7 @@ module D = Debug.Make (struct let name = "extauth_plugin_ADpbis" end) open D -open Xapi_stdext_std.Xstringext +module Stringext = Xapi_stdext_std.Xstringext.String let ( let@ ) = ( @@ ) @@ -106,7 +106,7 @@ let match_error_tag (lines : string list) = in let split_to_words str = let seps = ['('; ')'; ' '; '\t'; '.'] in - String.split_f (fun s -> List.exists (fun sep -> sep = s) seps) str + Stringext.split_f (fun s -> List.exists (fun sep -> sep = s) seps) str in let rec has_err lines err_pattern = match lines with @@ -131,9 +131,9 @@ let match_error_tag (lines : string list) = let extract_sid_from_group_list group_list = List.map (fun (_, v) -> - let v = String.replace ")" "" v in - let v = String.replace "sid =" "|" v in - let vs = String.split_f (fun c -> c = '|') v in + let v = Stringext.replace ")" "" v in + let v = Stringext.replace "sid =" "|" v in + let vs = Stringext.split_f (fun c -> c = '|') v in let sid = String.trim (List.nth vs 1) in debug "extract_sid_from_group_list get sid=[%s]" sid ; sid @@ -166,7 +166,7 @@ module AuthADlw : Auth_signature.AUTH_MODULE = struct Locking_helpers.Named_mutex.create "IS_SERVER_AVAILABLE" let splitlines s = - String.split_f (fun c -> c = '\n') (String.replace "#012" "\n" s) + Stringext.split_f (fun c -> c = '\n') (Stringext.replace "#012" "\n" s) let pbis_common_with_password (password : string) (pbis_cmd : string) (pbis_args : string list) = @@ -238,7 +238,7 @@ module AuthADlw : Auth_signature.AUTH_MODULE = struct pbis_cmd ^ " " ^ List.fold_left (fun p pp -> p ^ " " ^ pp) " " pbis_args in let debug_cmd = - if String.has_substr debug_cmd "--password" then + if Stringext.has_substr debug_cmd "--password" then "(omitted for security)" else debug_cmd @@ -348,9 +348,11 @@ module AuthADlw : Auth_signature.AUTH_MODULE = struct if !exited_code <> 0 then ( error "execute '%s': exit_code=[%d] output=[%s]" debug_cmd !exited_code - (String.replace "\n" ";" !output) ; + (Stringext.replace "\n" ";" !output) ; let split_to_words s = - String.split_f (fun c -> c = '(' || c = ')' || c = '.' || c = ' ') s + Stringext.split_f + (fun c -> c = '(' || c = ')' || c = '.' || c = ' ') + s in let revlines = List.rev @@ -416,7 +418,7 @@ module AuthADlw : Auth_signature.AUTH_MODULE = struct List.filter (fun l -> String.length l > 0) (splitlines !output) in let parse_line (acc, currkey) line = - let slices = String.split ~limit:2 ':' line in + let slices = Stringext.split ~limit:2 ':' line in debug "parse %s: currkey=[%s] line=[%s]" debug_cmd currkey line ; if List.length slices > 1 then ( let key = String.trim (List.hd slices) in @@ -619,7 +621,7 @@ module AuthADlw : Auth_signature.AUTH_MODULE = struct (* first, we try to authenticated user against our external user database *) (* pbis_common will raise an Auth_failure if external authentication fails *) let domain, user = - match String.split_f (fun c -> c = '\\') username with + match Stringext.split_f (fun c -> c = '\\') username with | [domain; user] -> (domain, user) | [user] -> @@ -976,7 +978,7 @@ module AuthADlw : Auth_signature.AUTH_MODULE = struct | "" -> [] | disabled_modules_string -> - String.split_f (fun c -> c = ',') disabled_modules_string + Stringext.split_f (fun c -> c = ',') disabled_modules_string with Not_found -> [] in let disabled_module_params = @@ -1113,8 +1115,8 @@ module AuthADlw : Auth_signature.AUTH_MODULE = struct in debug "execute %s: stdout=[%s],stderr=[%s]" pbis_force_domain_leave_script - (String.replace "\n" ";" output) - (String.replace "\n" ";" stderr) + (Stringext.replace "\n" ";" output) + (Stringext.replace "\n" ";" stderr) with e -> debug "exception executing %s: %s" pbis_force_domain_leave_script (ExnHelper.string_of_exn e) diff --git a/ocaml/xapi/extauth_plugin_ADwinbind.ml b/ocaml/xapi/extauth_plugin_ADwinbind.ml index 837dc429ca2..86d0e8c25b2 100644 --- a/ocaml/xapi/extauth_plugin_ADwinbind.ml +++ b/ocaml/xapi/extauth_plugin_ADwinbind.ml @@ -20,7 +20,6 @@ module D = Debug.Make (struct end) open D -open Xapi_stdext_std.Xstringext open Auth_signature module Scheduler = Xapi_stdext_threads_scheduler.Scheduler diff --git a/ocaml/xapi/fileserver.ml b/ocaml/xapi/fileserver.ml index 9820a55d5ce..7c29441df35 100644 --- a/ocaml/xapi/fileserver.ml +++ b/ocaml/xapi/fileserver.ml @@ -16,14 +16,14 @@ *) open Http -open Xapi_stdext_std.Xstringext +module Xstringext = Xapi_stdext_std.Xstringext.String module D = Debug.Make (struct let name = "fileserver" end) open D let escape uri = - String.escaped + Xstringext.escaped ~rules: [ ('<', "<") diff --git a/ocaml/xapi/gpg.ml b/ocaml/xapi/gpg.ml index 6589ea7c321..def89c7890b 100644 --- a/ocaml/xapi/gpg.ml +++ b/ocaml/xapi/gpg.ml @@ -13,7 +13,6 @@ *) (** Wrapper around gpg *) -open Xapi_stdext_std.Xstringext open Xapi_stdext_pervasives.Pervasiveext module Unixext = Xapi_stdext_unix.Unixext diff --git a/ocaml/xapi/import.ml b/ocaml/xapi/import.ml index 04306cff5f6..c854ed1807d 100644 --- a/ocaml/xapi/import.ml +++ b/ocaml/xapi/import.ml @@ -19,7 +19,6 @@ module D = Debug.Make (struct let name = "import" end) open D module Listext = Xapi_stdext_std.Listext -module Xstringext = Xapi_stdext_std.Xstringext module Unixext = Xapi_stdext_unix.Unixext open Http open Importexport diff --git a/ocaml/xapi/map_check.ml b/ocaml/xapi/map_check.ml index 01de88d4290..503ccd2ce8a 100644 --- a/ocaml/xapi/map_check.ml +++ b/ocaml/xapi/map_check.ml @@ -104,7 +104,7 @@ let assert_value ~field ~key ~attr ~value = ) | EnumSet range -> (* enumset is a comma-separated string *) - let vs = Xapi_stdext_std.Xstringext.String.split_on_char ',' value in + let vs = String.split_on_char ',' value in List.fold_right (fun v acc -> match mem v range with diff --git a/ocaml/xapi/nm.ml b/ocaml/xapi/nm.ml index 735bdbe98a8..4df9bf233f9 100644 --- a/ocaml/xapi/nm.ml +++ b/ocaml/xapi/nm.ml @@ -14,7 +14,7 @@ module D = Debug.Make (struct let name = "nm" end) open D -open Xapi_stdext_std.Xstringext +module Stringext = Xapi_stdext_std.Xstringext.String module Listext = Xapi_stdext_std.Listext.List open Xapi_database.Db_filter_types open Network @@ -216,7 +216,7 @@ let create_bond ~__context bond mtu persistent = List.filter_map (fun (k, v) -> if String.starts_with ~prefix:"bond-" k then - Some (String.sub_to_end k 5, v) + Some (Stringext.sub_to_end k 5, v) else None ) diff --git a/ocaml/xapi/sm.ml b/ocaml/xapi/sm.ml index 1d198cf3f98..532f6fb44b1 100644 --- a/ocaml/xapi/sm.ml +++ b/ocaml/xapi/sm.ml @@ -15,7 +15,6 @@ * @group Storage *) -open Xapi_stdext_std.Xstringext open Smint open Printf diff --git a/ocaml/xapi/storage_mux.ml b/ocaml/xapi/storage_mux.ml index 0427f76ca54..ac8b0680f43 100644 --- a/ocaml/xapi/storage_mux.ml +++ b/ocaml/xapi/storage_mux.ml @@ -780,9 +780,9 @@ module Mux = struct (* Assume it has either the format: SR/VDI -- for a particular SR and VDI content_id -- for a particular content *) - let open Xapi_stdext_std.Xstringext in + let split = Xapi_stdext_std.Xstringext.String.split in with_dbg ~name:"get_by_name" ~dbg @@ fun di -> - match List.filter (fun x -> x <> "") (String.split ~limit:2 '/' name) with + match List.filter (fun x -> x <> "") (split ~limit:2 '/' name) with | [sr; name] -> let sr = Storage_interface.Sr.of_string sr in let module C = StorageAPI (Idl.Exn.GenClient (struct diff --git a/ocaml/xapi/vgpuops.ml b/ocaml/xapi/vgpuops.ml index e47b0896ab3..248ec2839a1 100644 --- a/ocaml/xapi/vgpuops.ml +++ b/ocaml/xapi/vgpuops.ml @@ -15,7 +15,6 @@ module D = Debug.Make (struct let name = "vgpuops" end) open D module Listext = Xapi_stdext_std.Listext.List -open Xapi_stdext_std.Xstringext type vgpu_t = { vgpu_ref: API.ref_VGPU diff --git a/ocaml/xapi/vhd_tool_wrapper.ml b/ocaml/xapi/vhd_tool_wrapper.ml index 049d8effdf2..e8c051c0ef7 100644 --- a/ocaml/xapi/vhd_tool_wrapper.ml +++ b/ocaml/xapi/vhd_tool_wrapper.ml @@ -18,7 +18,6 @@ module D = Debug.Make (struct let name = "vhd_tool_wrapper" end) open D -open Xapi_stdext_std.Xstringext (* .vhds on XenServer are sometimes found via /dev/mapper *) let vhd_search_path = "/dev/mapper:." diff --git a/ocaml/xapi/wlb_reports.ml b/ocaml/xapi/wlb_reports.ml index e466bf959f5..8de0e80b298 100644 --- a/ocaml/xapi/wlb_reports.ml +++ b/ocaml/xapi/wlb_reports.ml @@ -92,7 +92,6 @@ open Printf open Http -open Xapi_stdext_std.Xstringext module D = Debug.Make (struct let name = "wlb_reports" end) diff --git a/ocaml/xapi/workload_balancing.ml b/ocaml/xapi/workload_balancing.ml index 7108032dbf7..47124c1f355 100644 --- a/ocaml/xapi/workload_balancing.ml +++ b/ocaml/xapi/workload_balancing.ml @@ -16,7 +16,6 @@ *) open Printf -open Xapi_stdext_std.Xstringext module D = Debug.Make (struct let name = "workload_balancing" end) @@ -87,7 +86,9 @@ let split_host_port url = in (host, int_of_string port) ) else - match String.split_f (fun a -> a = ':') url with + match + Xapi_stdext_std.Xstringext.String.split_f (fun a -> a = ':') url + with | [host; port] -> (host, int_of_string port) | _ -> diff --git a/ocaml/xapi/xapi_dr_task.ml b/ocaml/xapi/xapi_dr_task.ml index de7d15e0523..56626ea1368 100644 --- a/ocaml/xapi/xapi_dr_task.ml +++ b/ocaml/xapi/xapi_dr_task.ml @@ -13,7 +13,6 @@ *) open Client -open Xapi_stdext_std.Xstringext module D = Debug.Make (struct let name = "xapi_dr_task" end) diff --git a/ocaml/xapi/xapi_globs.ml b/ocaml/xapi/xapi_globs.ml index 1d3f3d2687f..38700758b0b 100644 --- a/ocaml/xapi/xapi_globs.ml +++ b/ocaml/xapi/xapi_globs.ml @@ -14,8 +14,6 @@ (** A central location for settings related to xapi *) -module String_plain = String (* For when we don't want the Xstringext version *) -open Xapi_stdext_std.Xstringext module StringSet = Set.Make (String) module D = Debug.Make (struct let name = "xapi_globs" end) @@ -1370,7 +1368,7 @@ let gen_list_option name desc of_string string_of opt = let parse s = opt := [] ; try - String.split_f String.isspace s + Xapi_stdext_std.Xstringext.String.(split_f isspace s) |> List.iter (fun x -> opt := of_string x :: !opt) with e -> D.error "Unable to parse %s=%s (expected space-separated list) error: %s" diff --git a/ocaml/xapi/xapi_network.ml b/ocaml/xapi/xapi_network.ml index 73a59fd698c..dd937ad5784 100644 --- a/ocaml/xapi/xapi_network.ml +++ b/ocaml/xapi/xapi_network.ml @@ -14,7 +14,6 @@ let with_lock = Xapi_stdext_threads.Threadext.Mutex.execute open Client -open Xapi_stdext_std.Xstringext module D = Debug.Make (struct let name = "xapi_network" end) diff --git a/ocaml/xapi/xapi_pif.ml b/ocaml/xapi/xapi_pif.ml index 56bdb49e565..0e730bda514 100644 --- a/ocaml/xapi/xapi_pif.ml +++ b/ocaml/xapi/xapi_pif.ml @@ -19,7 +19,7 @@ module L = Debug.Make (struct let name = "license" end) open Xapi_database.Db_filter_types module Listext = Xapi_stdext_std.Listext.List -open Xapi_stdext_std.Xstringext +module Stringext = Xapi_stdext_std.Xstringext.String module Date = Clock.Date open Network @@ -724,9 +724,9 @@ let scan ~__context ~host = debug "No boot from SAN interface found" ; ([], []) | m :: u :: _ -> - (String.split_f String.isspace m, String.split_f String.isspace u) + Stringext.(split_f isspace m, split_f isspace u) | m :: _ -> - (String.split_f String.isspace m, []) + Stringext.(split_f isspace m, []) with e -> warn "Error when executing script %s: %s; ignoring" !Xapi_globs.non_managed_pifs diff --git a/ocaml/xapi/xapi_pool.ml b/ocaml/xapi/xapi_pool.ml index 752d822135f..89e656ec8e2 100644 --- a/ocaml/xapi/xapi_pool.ml +++ b/ocaml/xapi/xapi_pool.ml @@ -16,7 +16,6 @@ open Client module Date = Clock.Date module Listext = Xapi_stdext_std.Listext module Unixext = Xapi_stdext_unix.Unixext -module Xstringext = Xapi_stdext_std.Xstringext module Pkgs = (val Pkg_mgr.get_pkg_mgr) diff --git a/ocaml/xapi/xapi_pool_update.ml b/ocaml/xapi/xapi_pool_update.ml index 4338cfe37fe..a0b0534628a 100644 --- a/ocaml/xapi/xapi_pool_update.ml +++ b/ocaml/xapi/xapi_pool_update.ml @@ -12,7 +12,7 @@ * GNU Lesser General Public License for more details. *) -open Xapi_stdext_std.Xstringext +module Stringext = Xapi_stdext_std.Xstringext.String module Unixext = Xapi_stdext_unix.Unixext open Http open Helpers @@ -770,9 +770,10 @@ let resync_host ~__context ~host = let path_and_host_from_uri uri = (* remove any dodgy use of "." or ".." NB we don't prevent the use of symlinks *) let host_and_path = - String.sub_to_end uri (String.length Constants.get_pool_update_download_uri) + Stringext.sub_to_end uri + (String.length Constants.get_pool_update_download_uri) in - match String.split ~limit:2 '/' host_and_path with + match Stringext.split ~limit:2 '/' host_and_path with | [host; untrusted_path] -> let resolved_path = untrusted_path diff --git a/ocaml/xapi/xapi_secret.ml b/ocaml/xapi/xapi_secret.ml index 57492840ead..9ca6eb88276 100644 --- a/ocaml/xapi/xapi_secret.ml +++ b/ocaml/xapi/xapi_secret.ml @@ -15,8 +15,6 @@ * @group XenAPI functions *) -open Xapi_stdext_std.Xstringext - module D = Debug.Make (struct let name = "xapi_secret" end) open D diff --git a/ocaml/xapi/xapi_vbd_helpers.ml b/ocaml/xapi/xapi_vbd_helpers.ml index 07d6b012da2..7fe8f32aa50 100644 --- a/ocaml/xapi/xapi_vbd_helpers.ml +++ b/ocaml/xapi/xapi_vbd_helpers.ml @@ -15,7 +15,6 @@ * @group Storage *) -open Xapi_stdext_std.Xstringext module Listext = Xapi_stdext_std.Listext module Date = Clock.Date diff --git a/ocaml/xapi/xapi_vif_helpers.ml b/ocaml/xapi/xapi_vif_helpers.ml index 37de1b77770..9bc87f3a553 100644 --- a/ocaml/xapi/xapi_vif_helpers.ml +++ b/ocaml/xapi/xapi_vif_helpers.ml @@ -12,8 +12,6 @@ * GNU Lesser General Public License for more details. *) -open Xapi_stdext_std.Xstringext - module D = Debug.Make (struct let name = "xapi_vif_helpers" end) open D diff --git a/ocaml/xapi/xapi_vusb_helpers.ml b/ocaml/xapi/xapi_vusb_helpers.ml index 19298735a06..0cf59fa5167 100644 --- a/ocaml/xapi/xapi_vusb_helpers.ml +++ b/ocaml/xapi/xapi_vusb_helpers.ml @@ -12,8 +12,6 @@ * GNU Lesser General Public License for more details. *) -open Xapi_stdext_std.Xstringext - module D = Debug.Make (struct let name = "xapi_vusb_helpers" end) (**************************************************************************************) diff --git a/ocaml/xapi/xapi_xenops.ml b/ocaml/xapi/xapi_xenops.ml index 880fd58a54f..a39a9983c86 100644 --- a/ocaml/xapi/xapi_xenops.ml +++ b/ocaml/xapi/xapi_xenops.ml @@ -17,9 +17,9 @@ module D = Debug.Make (struct let name = "xenops" end) open D module StringSet = Set.Make (String) open Network -open Xapi_stdext_std.Xstringext module Date = Clock.Date module Listext = Xapi_stdext_std.Listext.List +module Stringext = Xapi_stdext_std.Xstringext.String let with_lock = Xapi_stdext_threads.Threadext.Mutex.execute @@ -129,7 +129,7 @@ let disk_of_vdi ~__context ~self = let vdi_of_disk ~__context x = let@ __context = Context.with_tracing ~__context __FUNCTION__ in - match String.split ~limit:2 '/' x with + match Stringext.split ~limit:2 '/' x with | [sr_uuid; location] -> ( let open Xapi_database.Db_filter_types in let sr = Db.SR.get_by_uuid ~__context ~uuid:sr_uuid in diff --git a/ocaml/xapi/xha_interface.ml b/ocaml/xapi/xha_interface.ml index 82ac381519d..a42107a63a6 100644 --- a/ocaml/xapi/xha_interface.ml +++ b/ocaml/xapi/xha_interface.ml @@ -12,7 +12,6 @@ * GNU Lesser General Public License for more details. *) open API -open Xapi_stdext_std.Xstringext let hashtbl_of_list xs = let tbl = Hashtbl.create (List.length xs) in @@ -350,7 +349,9 @@ module LiveSetInformation = struct | Some u -> u in - let set f x = List.map f (String.split_f String.isspace x) in + let set f x = + List.map f Xapi_stdext_std.Xstringext.String.(split_f isspace x) + in Some { id= uuid (find "HostID") diff --git a/ocaml/xcp-rrdd/bin/rrdp-iostat/rrdp_iostat.ml b/ocaml/xcp-rrdd/bin/rrdp-iostat/rrdp_iostat.ml index f60b825b16d..cad87fc6614 100644 --- a/ocaml/xcp-rrdd/bin/rrdp-iostat/rrdp_iostat.ml +++ b/ocaml/xcp-rrdd/bin/rrdp-iostat/rrdp_iostat.ml @@ -437,7 +437,7 @@ let exec_tap_ctl_list () : ((string * string) * int) list = let minor_of_tapdev_unsafe tapdev = int_of_string (Unixext.file_lines_fold - (fun acc l -> acc ^ List.nth (Xstringext.String.split_on_char ':' l) 1) + (fun acc l -> acc ^ List.nth (String.split_on_char ':' l) 1) "" ("/sys/block/" ^ tapdev ^ "/dev") ) diff --git a/ocaml/xcp-rrdd/bin/rrdp-squeezed/rrdp_squeezed.ml b/ocaml/xcp-rrdd/bin/rrdp-squeezed/rrdp_squeezed.ml index ec5b783f3da..55a190b8988 100644 --- a/ocaml/xcp-rrdd/bin/rrdp-squeezed/rrdp_squeezed.ml +++ b/ocaml/xcp-rrdd/bin/rrdp-squeezed/rrdp_squeezed.ml @@ -12,7 +12,6 @@ * GNU Lesser General Public License for more details. *) -open Xapi_stdext_std open Rrdd_plugin module Process = Process (struct let name = "xcp-rrdd-squeezed" end) @@ -81,9 +80,7 @@ module MemoryActions = struct path domid ; current_memory_values := IntMap.remove domid !current_memory_values in - match - List.filter (fun x -> x <> "") (Xstringext.String.split_on_char '/' path) - with + match List.filter (fun x -> x <> "") (String.split_on_char '/' path) with | ["local"; "domain"; domid; "memory"; "dynamic-max"] -> read_new_value domid current_dynamic_max_values | ["local"; "domain"; domid; "memory"; "dynamic-min"] -> diff --git a/ocaml/xe-cli/newcli.ml b/ocaml/xe-cli/newcli.ml index c027a9b2e41..e8b7179e372 100644 --- a/ocaml/xe-cli/newcli.ml +++ b/ocaml/xe-cli/newcli.ml @@ -13,7 +13,7 @@ *) (* New cli talking to the in-server cli interface *) -open Xapi_stdext_std.Xstringext +module Stringext = Xapi_stdext_std.Xstringext.String open Xapi_stdext_pervasives open Cli_protocol @@ -306,7 +306,7 @@ let parse_args = || (extra_args.[!i] = ',' && extra_args.[!i - 1] <> '\\') then ( let seg = String.sub extra_args !pos (!i - !pos) in - l := String.filter_chars seg (( <> ) '\\') :: !l ; + l := Stringext.filter_chars seg (( <> ) '\\') :: !l ; incr i ; pos := !i ) else From 81fb38651ebd47059a00c0a04835876419c75bac Mon Sep 17 00:00:00 2001 From: Pau Ruiz Safont Date: Mon, 20 May 2024 16:37:30 +0100 Subject: [PATCH 3/8] xapi-stdext-std: Delete unused xstringext methods Signed-off-by: Pau Ruiz Safont Signed-off-by: Pau Ruiz Safont --- .../lib/xapi-stdext-std/xstringext.ml | 29 ------------------- .../lib/xapi-stdext-std/xstringext.mli | 24 --------------- .../lib/xapi-stdext-std/xstringext_test.ml | 25 +--------------- 3 files changed, 1 insertion(+), 77 deletions(-) diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml index 0512cc35dc5..0ef46aaf17a 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml @@ -12,31 +12,6 @@ * GNU Lesser General Public License for more details. *) module String = struct - let of_char c = String.make 1 c - - let rev_map f string = - let n = String.length string in - String.init n (fun i -> f string.[n - i - 1]) - - let rev_iter f string = - for i = String.length string - 1 downto 0 do - f string.[i] - done - - let fold_left f accu string = - let accu = ref accu in - for i = 0 to String.length string - 1 do - accu := f !accu string.[i] - done ; - !accu - - let fold_right f string accu = - let accu = ref accu in - for i = String.length string - 1 downto 0 do - accu := f string.[i] !accu - done ; - !accu - (** Returns true for whitespace characters, false otherwise *) let isspace = function ' ' | '\n' | '\r' | '\t' -> true | _ -> false @@ -174,8 +149,4 @@ module String = struct String.escaped s | Some rules -> map_unlikely s (fun c -> List.assoc_opt c rules) - - let sub_before c s = String.sub s 0 (String.index s c) - - let sub_after c s = sub_to_end s (String.index s c + 1) end diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli index a890537c1de..356c59a5719 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli @@ -12,21 +12,6 @@ * GNU Lesser General Public License for more details. *) module String : sig - val of_char : char -> string - - val rev_map : (char -> char) -> string -> string - (** Map a string to a string, applying the given function in reverse - order. *) - - val rev_iter : (char -> unit) -> string -> unit - (** Iterate over the characters in a string in reverse order. *) - - val fold_left : ('a -> char -> 'a) -> 'a -> string -> 'a - (** Fold over the characters in a string. *) - - val fold_right : (char -> 'a -> 'a) -> string -> 'a -> 'a - (** Iterate over the characters in a string in reverse order. *) - val isspace : char -> bool (** True if the character is whitespace *) @@ -49,9 +34,6 @@ module String : sig val has_substr : string -> string -> bool (** True if sub is a substr of str *) - val find_all : string -> string -> int list - (** find all occurences of needle in haystack and return all their respective index *) - val replace : string -> string -> string -> string (** replace all [f] substring in [s] by [t] *) @@ -63,10 +45,4 @@ module String : sig val sub_to_end : string -> int -> string (** a substring from the specified position to the end of the string *) - - val sub_before : char -> string -> string - (** a substring from the start of the string to the first occurrence of a given character, excluding the character *) - - val sub_after : char -> string -> string - (** a substring from the first occurrence of a given character to the end of the string, excluding the character *) end diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext_test.ml b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext_test.ml index 4a70eb31899..dac312a92aa 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext_test.ml +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext_test.ml @@ -27,22 +27,6 @@ let test_list tested_f (name, case, expected) = in (name, `Quick, check) -let test_rev_map = - let spec_rev = [("", ""); ("foo bar", "rab oof")] in - let spec_func = [("id", Fun.id); ("uppercase_ascii", Char.uppercase_ascii)] in - let test (f_name, f) (case, expected) = - let expected = String.map f expected in - let name = - Printf.sprintf {|"%s" produces "%s" (%s)|} case expected f_name - in - test_string (XString.rev_map f) (name, case, expected) - in - let tests = - (* Generate the product of the two lists to generate the tests *) - List.concat_map (fun func -> List.map (test func) spec_rev) spec_func - in - ("rev_map", tests) - let test_split = let test limit (splitter, splitted, expected) = let split = XString.split ~limit in @@ -168,11 +152,4 @@ let test_escaped = let () = Alcotest.run "Xstringext" - [ - test_rev_map - ; test_split - ; test_split_f - ; test_has_substr - ; test_rtrim - ; test_escaped - ] + [test_split; test_split_f; test_has_substr; test_rtrim; test_escaped] From 1174f3a86f48512adac5a0fffe02725016a82ce3 Mon Sep 17 00:00:00 2001 From: Pau Ruiz Safont Date: Fri, 12 Dec 2025 15:37:44 +0000 Subject: [PATCH 4/8] xapi-stdext-std: Remove String.escaped, add String.replaced MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit String.replaced is an alias of map_unlikely. This names makes the intent of the function clearer. Because a function to replace the characters is exposed, users are less likely to fall into the pitfall of using lists. Lists not only are very slow, but allow users to have more than one replacement rule per character, possibly introducing mistakes. If a plain match function cannot be produced and a list needs to be used, users can convert it to a Char.Map and do the match with a find_opt. This approach ends up being ~60-70% faster than using plain lists. The benchmark comparing the new approach with the old one: String size 100: Optimized: 236.556 μs Reference: 1861.600 μs Improvement: 87.3% faster String size 500: Optimized: 1099.030 μs Reference: 9665.405 μs Improvement: 88.6% faster String size 1000: Optimized: 2198.777 μs Reference: 19115.019 μs Improvement: 88.5% faster Signed-off-by: Pau Ruiz Safont --- ocaml/idl/markdown_backend.ml | 38 +++++------ ocaml/libs/http-lib/dune | 1 + ocaml/libs/http-lib/http_svr.ml | 40 +++++------- ocaml/libs/http-lib/http_svr.mli | 3 + .../xapi-stdext-std/bench/bench_xstringext.ml | 64 +++++++++++-------- .../lib/xapi-stdext-std/xstringext.ml | 7 +- .../lib/xapi-stdext-std/xstringext.mli | 8 +-- .../lib/xapi-stdext-std/xstringext_test.ml | 38 +---------- ocaml/xapi-cli-server/cli_printer.ml | 12 +++- ocaml/xapi/fileserver.ml | 14 +--- 10 files changed, 92 insertions(+), 133 deletions(-) diff --git a/ocaml/idl/markdown_backend.ml b/ocaml/idl/markdown_backend.ml index ca067ef9dcb..3125d850b85 100644 --- a/ocaml/idl/markdown_backend.ml +++ b/ocaml/idl/markdown_backend.ml @@ -43,41 +43,41 @@ let compare_case_ins x y = compare (String.lowercase_ascii x) (String.lowercase_ascii y) let escape s = - let esc_char = function + let replace = function | '\\' -> - "\" + Some "\" | '*' -> - "*" + Some "*" | '_' -> - "_" + Some "_" | '{' -> - "{" + Some "{" | '}' -> - "}" + Some "}" | '[' -> - "[" + Some "[" | ']' -> - "]" + Some "]" | '(' -> - "(" + Some "(" | ')' -> - ")" + Some ")" | '>' -> - ">" + Some ">" | '<' -> - "<" + Some "<" | '#' -> - "#" + Some "#" | '+' -> - "+" + Some "+" | '-' -> - "-" + Some "-" | '!' -> - "!" - | c -> - String.make 1 c + Some "!" + | _ -> + None in - String.to_seq s |> Seq.map esc_char |> List.of_seq |> String.concat "" + Xapi_stdext_std.Xstringext.String.replaced ~replace s let rec of_ty_verbatim = function | SecretString | String -> diff --git a/ocaml/libs/http-lib/dune b/ocaml/libs/http-lib/dune index 4e8d255b6bd..ac6db1b23d4 100644 --- a/ocaml/libs/http-lib/dune +++ b/ocaml/libs/http-lib/dune @@ -63,6 +63,7 @@ xapi-backtrace xapi-log xapi-stdext-pervasives + xapi-stdext-std xapi-stdext-threads xapi-stdext-unix)) diff --git a/ocaml/libs/http-lib/http_svr.ml b/ocaml/libs/http-lib/http_svr.ml index 7c5ecc393d1..6271c5ad987 100644 --- a/ocaml/libs/http-lib/http_svr.ml +++ b/ocaml/libs/http-lib/http_svr.ml @@ -331,28 +331,22 @@ module Server = struct x.handlers [] end -let escape uri = - (* from xapi-stdext-std xstringext *) - let escaped ~rules string = - let aux h t = - ( if List.mem_assoc h rules then - List.assoc h rules - else - Astring.String.of_char h +let escape_html uri = + Xapi_stdext_std.Xstringext.String.replaced + ~replace:(function + | '<' -> + Some "<" + | '>' -> + Some ">" + | '\'' -> + Some "'" + | '"' -> + Some """ + | '&' -> + Some "&" + | _ -> + None ) - :: t - in - String.concat "" (Astring.String.fold_right aux string []) - in - escaped - ~rules: - [ - ('<', "<") - ; ('>', ">") - ; ('\'', "'") - ; ('"', """) - ; ('&', "&") - ] uri exception Generic_error of string @@ -508,7 +502,7 @@ let read_request ?proxy_seen ~read_timeout ~total_timeout ~max_length fd = ) | exc -> response_internal_error exc fd - ~extra:(escape (Printexc.to_string exc)) + ~extra:(escape_html (Printexc.to_string exc)) ) ; (None, None) @@ -557,7 +551,7 @@ let handle_one (x : 'a Server.t) ss context req = ) | exc -> response_internal_error ~req exc ss - ~extra:(escape (Printexc.to_string exc)) + ~extra:(escape_html (Printexc.to_string exc)) ) ; !finished diff --git a/ocaml/libs/http-lib/http_svr.mli b/ocaml/libs/http-lib/http_svr.mli index 61b49e7b3f2..cf335592d7b 100644 --- a/ocaml/libs/http-lib/http_svr.mli +++ b/ocaml/libs/http-lib/http_svr.mli @@ -68,6 +68,9 @@ val start : val handle_one : 'a Server.t -> Unix.file_descr -> 'a -> Http.Request.t -> bool +val escape_html : string -> string +(** Escapes HTML: replaces characters with their character references *) + exception Socket_not_found val stop : socket -> unit diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/bench/bench_xstringext.ml b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/bench/bench_xstringext.ml index 52897ee2a0c..d302737b1b1 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/bench/bench_xstringext.ml +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/bench/bench_xstringext.ml @@ -8,36 +8,42 @@ let make_string len = String.init len (fun i -> Char.chr (33 + (i mod 94))) let escape_rules = [('a', "[A]"); ('e', "[E]"); ('i', "[I]"); ('o', "[O]"); ('u', "[U]")] -(* Reference implementation from xstringext_test.ml *) -let escaped_spec ?rules string = - match rules with - | None -> - String.escaped string - | Some rules -> - let apply_rules char = - match List.assoc_opt char rules with - | None -> - Seq.return char - | Some replacement -> - String.to_seq replacement - in - string |> String.to_seq |> Seq.concat_map apply_rules |> String.of_seq +let replace = function + | 'a' -> + Some "[A]" + | 'e' -> + Some "[E]" + | 'i' -> + Some "[I]" + | 'o' -> + Some "[O]" + | 'u' -> + Some "[U]" + | _ -> + None + +(* Reference implementation using lists *) +let replaced_spec ~rules string = + let apply_rules char = List.assoc_opt char rules in + XString.replaced ~replace:apply_rules string -let escaped_benchmark n = +let replaced ~rules string = XString.replaced ~replace:rules string + +let replaced_benchmark n = let s = make_string n in - Staged.stage @@ fun () -> ignore (XString.escaped ~rules:escape_rules s) + Staged.stage @@ fun () -> ignore (replaced ~rules:replace s) -let escaped_spec_benchmark n = +let replaced_spec_benchmark n = let s = make_string n in - Staged.stage @@ fun () -> ignore (escaped_spec ~rules:escape_rules s) + Staged.stage @@ fun () -> ignore (replaced_spec ~rules:escape_rules s) -let test_escaped = - Test.make_indexed ~name:"escaped" ~fmt:"%s %d" ~args:[100; 500; 1000] - escaped_benchmark +let test_replaced = + Test.make_indexed ~name:"replaced" ~fmt:"%s %d" ~args:[100; 500; 1000] + replaced_benchmark -let test_escaped_spec = - Test.make_indexed ~name:"escaped-spec" ~fmt:"%s %d" ~args:[100; 500; 1000] - escaped_spec_benchmark +let test_replaced_spec = + Test.make_indexed ~name:"replaced-spec" ~fmt:"%s %d" ~args:[100; 500; 1000] + replaced_spec_benchmark let benchmark () = let ols = @@ -50,8 +56,8 @@ let benchmark () = Benchmark.cfg ~limit:2000 ~quota:(Time.second 0.5) ~kde:(Some 1000) () in let test = - Test.make_grouped ~name:"escaped-comparison" - [test_escaped; test_escaped_spec] + Test.make_grouped ~name:"replaced-comparison" + [test_replaced; test_replaced_spec] in let raw_results = Benchmark.all cfg instances test in let results = @@ -97,8 +103,10 @@ let () = List.iter (fun size -> Printf.printf "String size %s:\n" size ; - let opt_test = Printf.sprintf "escaped-comparison/escaped %s" size in - let ref_test = Printf.sprintf "escaped-comparison/escaped-spec %s" size in + let opt_test = Printf.sprintf "replaced-comparison/replaced %s" size in + let ref_test = + Printf.sprintf "replaced-comparison/replaced-spec %s" size + in match (get_timing opt_test, get_timing ref_test) with | Some opt_time, Some ref_time -> let improvement = (ref_time -. opt_time) /. ref_time *. 100.0 in diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml index 0ef46aaf17a..75746417e40 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml @@ -143,10 +143,5 @@ module String = struct ) else s - let escaped ?rules s = - match rules with - | None -> - String.escaped s - | Some rules -> - map_unlikely s (fun c -> List.assoc_opt c rules) + let replaced ~replace s = map_unlikely s replace end diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli index 356c59a5719..ab123eb5c98 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli @@ -15,10 +15,10 @@ module String : sig val isspace : char -> bool (** True if the character is whitespace *) - val escaped : ?rules:(char * string) list -> string -> string - (** Backward-compatible string escaping, defaulting to the built-in - OCaml string escaping but allowing an arbitrary mapping from characters - to strings. *) + val replaced : replace:(char -> string option) -> string -> string + (** [replaced ~replacement str] applies [replace] to all characters in [str] + and when it returns [Some rep] the character is replaced with [rep] in + the resulting string *) val split_f : (char -> bool) -> string -> string list (** Take a predicate and a string, return a list of strings separated by diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext_test.ml b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext_test.ml index dac312a92aa..13eb45c6c01 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext_test.ml +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext_test.ml @@ -114,42 +114,6 @@ let test_rtrim = in ("rtrim", List.map test spec) -(** Simple implementation of escaped for testing against *) -let escaped_spec ?rules string = - match rules with - | None -> - String.escaped string - | Some rules -> - let apply_rules char = - match List.assoc_opt char rules with - | None -> - Seq.return char - | Some replacement -> - String.to_seq replacement - in - string |> String.to_seq |> Seq.concat_map apply_rules |> String.of_seq - -let test_escaped = - let open QCheck2 in - (* Generator for escape rules: list of (char, string) mappings *) - let gen_rules = - let open Gen in - let gen_rule = pair char (string_size (int_range 0 5) ~gen:char) in - list gen_rule - in - (* Generator for test input: string and optional rules *) - let gen_input = Gen.pair Gen.string (Gen.opt gen_rules) in - let property (s, rules) = - let expected = escaped_spec ?rules s in - let actual = XString.escaped ?rules s in - String.equal expected actual - in - let test = - Test.make ~name:"escaped matches reference implementation" ~count:1000 - gen_input property - in - ("escaped", [QCheck_alcotest.to_alcotest test]) - let () = Alcotest.run "Xstringext" - [test_split; test_split_f; test_has_substr; test_rtrim; test_escaped] + [test_split; test_split_f; test_has_substr; test_rtrim] diff --git a/ocaml/xapi-cli-server/cli_printer.ml b/ocaml/xapi-cli-server/cli_printer.ml index 1fc1d5586fd..bb627812924 100644 --- a/ocaml/xapi-cli-server/cli_printer.ml +++ b/ocaml/xapi-cli-server/cli_printer.ml @@ -47,9 +47,15 @@ let rec multi_line_record r = (* Used to escape commas in --minimal mode *) let escape_commas x = - (* Escaping rules: *) - let rules = [(',', "\\,"); (* , -> \, *) ('\\', "\\\\") (* \ -> \\ *)] in - Xapi_stdext_std.Xstringext.String.escaped ~rules x + let replace = function + | ',' -> + Some "\\," + | '\\' -> + Some "\\\\" + | _ -> + None + in + Xapi_stdext_std.Xstringext.String.replaced ~replace x let make_printer sock minimal = let buffer = ref [] in diff --git a/ocaml/xapi/fileserver.ml b/ocaml/xapi/fileserver.ml index 7c29441df35..8c83dac57f3 100644 --- a/ocaml/xapi/fileserver.ml +++ b/ocaml/xapi/fileserver.ml @@ -22,23 +22,11 @@ module D = Debug.Make (struct let name = "fileserver" end) open D -let escape uri = - Xstringext.escaped - ~rules: - [ - ('<', "<") - ; ('>', ">") - ; ('\'', "'") - ; ('"', """) - ; ('&', "&") - ] - uri - let missing uri = " \ 404 Not Found

Not Found

The \ requested URL " - ^ escape uri + ^ Http_svr.escape_html uri ^ " was not found on this server.


Xapi \ Server
" From e41ce966bb31b0ec14d14cd0e5b1e94e05ea84e7 Mon Sep 17 00:00:00 2001 From: Pau Ruiz Safont Date: Tue, 21 May 2024 16:27:58 +0100 Subject: [PATCH 5/8] xapi-stdext-std: Replace String.has_substr with Astring's is_infix Not only it's more efficient, but it's also more ergonomic Signed-off-by: Pau Ruiz Safont Signed-off-by: Pau Ruiz Safont --- ocaml/libs/sexpr/sExpr.ml | 2 +- .../lib/xapi-stdext-std/xstringext.ml | 11 -------- .../lib/xapi-stdext-std/xstringext.mli | 3 --- .../lib/xapi-stdext-std/xstringext_test.ml | 27 +------------------ ocaml/quicktest/quicktest_http.ml | 6 ++--- ocaml/xapi/extauth_plugin_ADpbis.ml | 2 +- ocaml/xapi/map_check.ml | 2 +- ocaml/xapi/rbac_audit.ml | 5 ++-- 8 files changed, 8 insertions(+), 50 deletions(-) diff --git a/ocaml/libs/sexpr/sExpr.ml b/ocaml/libs/sexpr/sExpr.ml index 3637ac6abf5..c9794265d49 100644 --- a/ocaml/libs/sexpr/sExpr.ml +++ b/ocaml/libs/sexpr/sExpr.ml @@ -28,7 +28,7 @@ let is_escape_char = function '\\' | '\'' -> true | _ -> false (* XXX: This escapes "'c'" and "\'c\'" to "\\'c\\'". * They are both unescaped as "'c'". They have been ported * to make sure that this corner case is left unchanged. - * It is worth investigating the use of + * It is worth investigating the use of * - Astring.String.Ascii.escape_string * - Astring.String.Ascii.unescape * that have guaranteed invariants and optimised performances *) diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml index 75746417e40..f23bfbe0fb0 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml @@ -58,17 +58,6 @@ module String = struct else s - (** has_substr str sub returns true if sub is a substring of str. Simple, naive, slow. *) - let has_substr str sub = - if String.length sub > String.length str then - false - else - let result = ref false in - for start = 0 to String.length str - String.length sub do - if String.sub str start (String.length sub) = sub then result := true - done ; - !result - (** find all occurences of needle in haystack and return all their respective index *) let find_all needle haystack = let m = String.length needle and n = String.length haystack in diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli index ab123eb5c98..31292bd69d5 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli @@ -31,9 +31,6 @@ module String : sig val rtrim : string -> string (** FIXME document me|remove me if similar to strip *) - val has_substr : string -> string -> bool - (** True if sub is a substr of str *) - val replace : string -> string -> string -> string (** replace all [f] substring in [s] by [t] *) diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext_test.ml b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext_test.ml index 13eb45c6c01..a603fb1d365 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext_test.ml +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext_test.ml @@ -13,10 +13,6 @@ module XString = Xapi_stdext_std.Xstringext.String -let test_boolean tested_f (name, case, expected) = - let check () = Alcotest.(check bool) name expected (tested_f case) in - (name, `Quick, check) - let test_string tested_f (name, case, expected) = let check () = Alcotest.(check string) name expected (tested_f case) in (name, `Quick, check) @@ -74,26 +70,6 @@ let test_split_f = let tests = List.map test specs in ("split_f", tests) -let test_has_substr = - let spec = - [ - ("", "", true) - ; ("", "foo bar", true) - ; ("f", "foof", true) - ; ("foofo", "foof", false) - ; ("foof", "foof", true) - ; ("f", "foof", true) - ; ("fo", "foof", true) - ; ("of", "foof", true) - ; ("ff", "foof", false) - ] - in - let test (contained, container, expected) = - let name = Printf.sprintf {|"%s" in "%s"|} contained container in - test_boolean (XString.has_substr container) (name, contained, expected) - in - ("has_substr", List.map test spec) - let test_rtrim = let spec = [ @@ -115,5 +91,4 @@ let test_rtrim = ("rtrim", List.map test spec) let () = - Alcotest.run "Xstringext" - [test_split; test_split_f; test_has_substr; test_rtrim] + Alcotest.run "Xstringext" [test_split; test_split_f; test_rtrim] diff --git a/ocaml/quicktest/quicktest_http.ml b/ocaml/quicktest/quicktest_http.ml index 86f9660e7ce..d718a61a9e7 100644 --- a/ocaml/quicktest/quicktest_http.ml +++ b/ocaml/quicktest/quicktest_http.ml @@ -99,7 +99,7 @@ module Cookies = struct match body with | first_line :: _ -> D.warn "expected = [%s]; received = [%s]" expected first_line ; - Xapi_stdext_std.Xstringext.String.has_substr first_line expected + Astring.String.is_infix ~affix:first_line expected | _ -> false in @@ -210,9 +210,7 @@ module HTML_Escaping = struct let bad_command_exp = "<>'\\"&" let html_escaping expected cmd = - let check_result b = - Xapi_stdext_std.Xstringext.String.has_substr b expected - in + let check_result = Astring.String.is_infix ~affix:expected in let _, _, _, body = Uds.http_command Xapi_globs.unix_domain_socket cmd in match body with | first_line :: _ -> diff --git a/ocaml/xapi/extauth_plugin_ADpbis.ml b/ocaml/xapi/extauth_plugin_ADpbis.ml index 6c532c8eb70..070d2a8a8c4 100644 --- a/ocaml/xapi/extauth_plugin_ADpbis.ml +++ b/ocaml/xapi/extauth_plugin_ADpbis.ml @@ -238,7 +238,7 @@ module AuthADlw : Auth_signature.AUTH_MODULE = struct pbis_cmd ^ " " ^ List.fold_left (fun p pp -> p ^ " " ^ pp) " " pbis_args in let debug_cmd = - if Stringext.has_substr debug_cmd "--password" then + if Astring.String.is_infix ~affix:"--password" debug_cmd then "(omitted for security)" else debug_cmd diff --git a/ocaml/xapi/map_check.ml b/ocaml/xapi/map_check.ml index 503ccd2ce8a..3737b3f00bf 100644 --- a/ocaml/xapi/map_check.ml +++ b/ocaml/xapi/map_check.ml @@ -113,7 +113,7 @@ let assert_value ~field ~key ~attr ~value = | Some v -> if acc = "" then v - else if Xapi_stdext_std.Xstringext.String.has_substr acc v then + else if Astring.String.is_infix ~affix:v acc then err value else v ^ "," ^ acc diff --git a/ocaml/xapi/rbac_audit.ml b/ocaml/xapi/rbac_audit.ml index bbc5a7a6fc9..d0f94f6775b 100644 --- a/ocaml/xapi/rbac_audit.ml +++ b/ocaml/xapi/rbac_audit.ml @@ -362,8 +362,7 @@ and let has_to_audit action = let has_side_effect action = - not (Xapi_stdext_std.Xstringext.String.has_substr action ".get") - (* TODO: a bit slow? *) + not (Astring.String.is_infix ~affix:".get" action) in (!Xapi_globs.log_getter || has_side_effect action) && not @@ -471,7 +470,7 @@ let allowed_pre_fn ~__context ~action ?args () = if has_to_audit action (* for now, we only cache arg results for destroy actions *) - && Xapi_stdext_std.Xstringext.String.has_substr action ".destroy" + && Astring.String.is_infix ~affix:".destroy" action then let args' = add_dummy_args __context action args in Some (sexpr_of_parameters __context action args') From dd040a9f59718a3507367b316e3a0991a585d439 Mon Sep 17 00:00:00 2001 From: Pau Ruiz Safont Date: Tue, 21 May 2024 16:34:22 +0100 Subject: [PATCH 6/8] xapi-stdext-std: replace String.filter_chars with Astring.filter The former didn't have any tests and the performance is unknown Signed-off-by: Pau Ruiz Safont Signed-off-by: Pau Ruiz Safont --- ocaml/libs/tgroup/dune | 2 +- ocaml/libs/tgroup/tgroup.ml | 3 +-- .../xapi-stdext/lib/xapi-stdext-std/xstringext.ml | 14 -------------- .../xapi-stdext/lib/xapi-stdext-std/xstringext.mli | 3 --- ocaml/xe-cli/dune | 1 - ocaml/xe-cli/newcli.ml | 3 +-- 6 files changed, 3 insertions(+), 23 deletions(-) diff --git a/ocaml/libs/tgroup/dune b/ocaml/libs/tgroup/dune index 6c152a5c2ef..12070176651 100644 --- a/ocaml/libs/tgroup/dune +++ b/ocaml/libs/tgroup/dune @@ -2,7 +2,7 @@ (name tgroup) (modules tgroup) (public_name tgroup) - (libraries unix xapi-log xapi-stdext-unix xapi-stdext-std)) + (libraries astring unix xapi-log xapi-stdext-unix)) (test (name test_tgroup) diff --git a/ocaml/libs/tgroup/tgroup.ml b/ocaml/libs/tgroup/tgroup.ml index 071a9dfe0d2..e5b163fea60 100644 --- a/ocaml/libs/tgroup/tgroup.ml +++ b/ocaml/libs/tgroup/tgroup.ml @@ -70,8 +70,7 @@ module Group = struct | _ -> false - let sanitize s = - Xapi_stdext_std.Xstringext.String.filter_chars s is_alphanum + let sanitize s = Astring.String.filter is_alphanum s let make ?user_agent subject_sid = let user_agent = diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml index f23bfbe0fb0..07370794b15 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml @@ -98,20 +98,6 @@ module String = struct ) else s - let filter_chars s valid = - let badchars = ref false in - let buf = Buffer.create 0 in - for i = 0 to String.length s - 1 do - if !badchars then ( - if valid s.[i] then - Buffer.add_char buf s.[i] - ) else if not (valid s.[i]) then ( - Buffer.add_substring buf s 0 i ; - badchars := true - ) - done ; - if !badchars then Buffer.contents buf else s - let map_unlikely s f = let changed = ref false in let m = ref 0 in diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli index 31292bd69d5..17339e3321b 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli @@ -34,9 +34,6 @@ module String : sig val replace : string -> string -> string -> string (** replace all [f] substring in [s] by [t] *) - val filter_chars : string -> (char -> bool) -> string - (** filter chars from a string *) - val map_unlikely : string -> (char -> string option) -> string (** map a string trying to fill the buffer by chunk *) diff --git a/ocaml/xe-cli/dune b/ocaml/xe-cli/dune index b61ec3cde63..3aed1017987 100644 --- a/ocaml/xe-cli/dune +++ b/ocaml/xe-cli/dune @@ -17,7 +17,6 @@ xapi-backtrace xapi-cli-protocol xapi-stdext-pervasives - xapi-stdext-std xapi-stdext-unix ) ) diff --git a/ocaml/xe-cli/newcli.ml b/ocaml/xe-cli/newcli.ml index e8b7179e372..0b18d57dd18 100644 --- a/ocaml/xe-cli/newcli.ml +++ b/ocaml/xe-cli/newcli.ml @@ -13,7 +13,6 @@ *) (* New cli talking to the in-server cli interface *) -module Stringext = Xapi_stdext_std.Xstringext.String open Xapi_stdext_pervasives open Cli_protocol @@ -306,7 +305,7 @@ let parse_args = || (extra_args.[!i] = ',' && extra_args.[!i - 1] <> '\\') then ( let seg = String.sub extra_args !pos (!i - !pos) in - l := Stringext.filter_chars seg (( <> ) '\\') :: !l ; + l := Astring.String.filter (( <> ) '\\') seg :: !l ; incr i ; pos := !i ) else From 8648ebba94a5bdce4c9401cfc284c66963d75570 Mon Sep 17 00:00:00 2001 From: Pau Ruiz Safont Date: Tue, 21 May 2024 17:16:09 +0100 Subject: [PATCH 7/8] xapi-stdext-std: replace String.split_f with Astring functions This also allows to drop String.isspace Signed-off-by: Pau Ruiz Safont Signed-off-by: Pau Ruiz Safont --- .../lib/xapi-stdext-std/xstringext.ml | 26 ------------------- .../lib/xapi-stdext-std/xstringext.mli | 8 ------ .../lib/xapi-stdext-std/xstringext_test.ml | 21 +-------------- ocaml/tests/test_guest_agent.ml | 20 ++++---------- ocaml/xapi/extauth_plugin_ADpbis.ml | 18 ++++++------- ocaml/xapi/workload_balancing.ml | 26 +++++-------------- ocaml/xapi/xapi_globs.ml | 6 ++--- ocaml/xapi/xapi_host_crashdump.ml | 7 +++-- ocaml/xapi/xapi_pif.ml | 7 ++--- ocaml/xapi/xha_interface.ml | 5 ++-- 10 files changed, 34 insertions(+), 110 deletions(-) diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml index 07370794b15..1c205b31faa 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml @@ -12,32 +12,6 @@ * GNU Lesser General Public License for more details. *) module String = struct - (** Returns true for whitespace characters, false otherwise *) - let isspace = function ' ' | '\n' | '\r' | '\t' -> true | _ -> false - - let split_f p str = - let split_one seq = - let not_p c = not (p c) in - let a = Seq.take_while not_p seq in - let b = Seq.drop_while not_p seq in - (a, b) - in - let drop seq = Seq.drop_while p seq in - let rec split acc chars = - if Seq.is_empty chars then - acc - else - let a, b = split_one chars in - let b = drop b in - let acc = if Seq.is_empty a then acc else Seq.cons a acc in - split acc b - in - String.to_seq str - |> split Seq.empty - |> Seq.map String.of_seq - |> List.of_seq - |> List.rev - let sub_to_end s start = let length = String.length s in String.sub s start (length - start) diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli index 17339e3321b..e2ba23e0139 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli @@ -12,19 +12,11 @@ * GNU Lesser General Public License for more details. *) module String : sig - val isspace : char -> bool - (** True if the character is whitespace *) - val replaced : replace:(char -> string option) -> string -> string (** [replaced ~replacement str] applies [replace] to all characters in [str] and when it returns [Some rep] the character is replaced with [rep] in the resulting string *) - val split_f : (char -> bool) -> string -> string list - (** Take a predicate and a string, return a list of strings separated by - runs of characters where the predicate was true. Avoid if possible, it's - very costly to execute. *) - val split : limit:int -> char -> string -> string list (** split a string on a single char *) diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext_test.ml b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext_test.ml index a603fb1d365..4fe39225785 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext_test.ml +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext_test.ml @@ -52,24 +52,6 @@ let test_split = in ("split", tests) -let test_split_f = - let specs = - [ - (XString.isspace, "foo bar", ["foo"; "bar"]) - ; (XString.isspace, "foo bar", ["foo"; "bar"]) - ; (XString.isspace, "foo \n\t\r bar", ["foo"; "bar"]) - ; (XString.isspace, " foo bar ", ["foo"; "bar"]) - ; (XString.isspace, "", []) - ; (XString.isspace, " ", []) - ] - in - let test (splitter, splitted, expected) = - let name = Printf.sprintf {|"%s"|} (String.escaped splitted) in - test_list (XString.split_f splitter) (name, splitted, expected) - in - let tests = List.map test specs in - ("split_f", tests) - let test_rtrim = let spec = [ @@ -90,5 +72,4 @@ let test_rtrim = in ("rtrim", List.map test spec) -let () = - Alcotest.run "Xstringext" [test_split; test_split_f; test_rtrim] +let () = Alcotest.run "Xstringext" [test_split; test_rtrim] diff --git a/ocaml/tests/test_guest_agent.ml b/ocaml/tests/test_guest_agent.ml index 6bc0f227c7b..94774ac10c7 100644 --- a/ocaml/tests/test_guest_agent.ml +++ b/ocaml/tests/test_guest_agent.ml @@ -42,9 +42,7 @@ module Networks = Generic.MakeStateless (struct ) let construct_tree tree path = - let nodes = - Xapi_stdext_std.Xstringext.String.split_f (fun s -> s = '/') path - in + let nodes = Astring.String.cuts ~empty:false ~sep:"/" path in add_path_to_tree tree nodes let rec list_helper children = function @@ -60,9 +58,7 @@ module Networks = Generic.MakeStateless (struct ) let list (T (_root, children)) path = - let nodes = - Xapi_stdext_std.Xstringext.String.split_f (fun s -> s = '/') path - in + let nodes = Astring.String.cuts ~empty:false ~sep:"/" path in list_helper children nodes let transform input = @@ -231,9 +227,7 @@ module Initial_guest_metrics = Generic.MakeStateless (struct ) let construct_mtree mtree (path, leaf_value) = - let nodes = - Xapi_stdext_std.Xstringext.String.split_f (fun s -> s = '/') path - in + let nodes = Astring.String.cuts ~empty:false ~sep:"/" path in add_leaf_to_mtree nodes leaf_value mtree let rec list_helper children = function @@ -254,9 +248,7 @@ module Initial_guest_metrics = Generic.MakeStateless (struct | Lf (_, _) -> [] | Mt (_, children) -> - let nodes = - Xapi_stdext_std.Xstringext.String.split_f (fun s -> s = '/') path - in + let nodes = Astring.String.cuts ~empty:false ~sep:"/" path in list_helper children nodes let rec lookup_helper mtree = function @@ -274,9 +266,7 @@ module Initial_guest_metrics = Generic.MakeStateless (struct ) let lookup mtree path = - let nodes = - Xapi_stdext_std.Xstringext.String.split_f (fun s -> s = '/') path - in + let nodes = Astring.String.cuts ~empty:false ~sep:"/" path in lookup_helper mtree nodes let transform input = diff --git a/ocaml/xapi/extauth_plugin_ADpbis.ml b/ocaml/xapi/extauth_plugin_ADpbis.ml index 070d2a8a8c4..dac47414b33 100644 --- a/ocaml/xapi/extauth_plugin_ADpbis.ml +++ b/ocaml/xapi/extauth_plugin_ADpbis.ml @@ -92,6 +92,8 @@ module Lwsmd = struct ) end +let is_word_sep = function '(' | ')' | ' ' | '\t' | '.' -> true | _ -> false + let match_error_tag (lines : string list) = let err_catch_list = [ @@ -105,8 +107,7 @@ let match_error_tag (lines : string list) = ] in let split_to_words str = - let seps = ['('; ')'; ' '; '\t'; '.'] in - Stringext.split_f (fun s -> List.exists (fun sep -> sep = s) seps) str + Astring.String.fields ~empty:false ~is_sep:is_word_sep str in let rec has_err lines err_pattern = match lines with @@ -133,7 +134,7 @@ let extract_sid_from_group_list group_list = (fun (_, v) -> let v = Stringext.replace ")" "" v in let v = Stringext.replace "sid =" "|" v in - let vs = Stringext.split_f (fun c -> c = '|') v in + let vs = Astring.String.cuts ~empty:false ~sep:"|" v in let sid = String.trim (List.nth vs 1) in debug "extract_sid_from_group_list get sid=[%s]" sid ; sid @@ -166,7 +167,7 @@ module AuthADlw : Auth_signature.AUTH_MODULE = struct Locking_helpers.Named_mutex.create "IS_SERVER_AVAILABLE" let splitlines s = - Stringext.split_f (fun c -> c = '\n') (Stringext.replace "#012" "\n" s) + Astring.String.cuts ~empty:false ~sep:"\n" (Stringext.replace "#012" "\n" s) let pbis_common_with_password (password : string) (pbis_cmd : string) (pbis_args : string list) = @@ -350,9 +351,7 @@ module AuthADlw : Auth_signature.AUTH_MODULE = struct !exited_code (Stringext.replace "\n" ";" !output) ; let split_to_words s = - Stringext.split_f - (fun c -> c = '(' || c = ')' || c = '.' || c = ' ') - s + Astring.String.fields ~empty:false ~is_sep:is_word_sep s in let revlines = List.rev @@ -621,7 +620,7 @@ module AuthADlw : Auth_signature.AUTH_MODULE = struct (* first, we try to authenticated user against our external user database *) (* pbis_common will raise an Auth_failure if external authentication fails *) let domain, user = - match Stringext.split_f (fun c -> c = '\\') username with + match Astring.String.cuts ~empty:false ~sep:"\\" username with | [domain; user] -> (domain, user) | [user] -> @@ -978,7 +977,8 @@ module AuthADlw : Auth_signature.AUTH_MODULE = struct | "" -> [] | disabled_modules_string -> - Stringext.split_f (fun c -> c = ',') disabled_modules_string + Astring.String.cuts ~empty:false ~sep:"," + disabled_modules_string with Not_found -> [] in let disabled_module_params = diff --git a/ocaml/xapi/workload_balancing.ml b/ocaml/xapi/workload_balancing.ml index 47124c1f355..136aa2c8985 100644 --- a/ocaml/xapi/workload_balancing.ml +++ b/ocaml/xapi/workload_balancing.ml @@ -74,26 +74,12 @@ let raise_internal_error args = raise (Api_errors.Server_error (Api_errors.wlb_internal_error, args)) let split_host_port url = - try - if url.[0] = '[' then ( - (* IPv6 *) - let host_end = String.rindex url ']' in - if url.[host_end + 1] <> ':' then - raise_url_invalid url ; - let host = String.sub url 1 (host_end - 1) in - let port = - String.sub url (host_end + 2) (String.length url - host_end - 2) - in - (host, int_of_string port) - ) else - match - Xapi_stdext_std.Xstringext.String.split_f (fun a -> a = ':') url - with - | [host; port] -> - (host, int_of_string port) - | _ -> - raise_url_invalid url - with _ -> raise_url_invalid url + let uri = Uri.of_string ("//" ^ url) in + match (Uri.host uri, Uri.port uri) with + | None, _ | _, None -> + raise_url_invalid url + | Some host, Some port -> + (host, port) let wlb_host_port ~__context = let pool = Helpers.get_pool ~__context in diff --git a/ocaml/xapi/xapi_globs.ml b/ocaml/xapi/xapi_globs.ml index 38700758b0b..8a062edbf29 100644 --- a/ocaml/xapi/xapi_globs.ml +++ b/ocaml/xapi/xapi_globs.ml @@ -1364,12 +1364,12 @@ let citrix_patch_key = let trusted_patch_key = ref citrix_patch_key +let fields_of = Astring.(String.fields ~empty:false ~is_sep:Char.Ascii.is_white) + let gen_list_option name desc of_string string_of opt = let parse s = opt := [] ; - try - Xapi_stdext_std.Xstringext.String.(split_f isspace s) - |> List.iter (fun x -> opt := of_string x :: !opt) + try fields_of s |> List.iter (fun x -> opt := of_string x :: !opt) with e -> D.error "Unable to parse %s=%s (expected space-separated list) error: %s" name s (Printexc.to_string e) diff --git a/ocaml/xapi/xapi_host_crashdump.ml b/ocaml/xapi/xapi_host_crashdump.ml index b7e9eedd74e..f9c66de62c8 100644 --- a/ocaml/xapi/xapi_host_crashdump.ml +++ b/ocaml/xapi/xapi_host_crashdump.ml @@ -16,7 +16,6 @@ *) module Listext = Xapi_stdext_std.Listext -module Xstringext = Xapi_stdext_std.Xstringext module Date = Clock.Date open Xapi_stdext_pervasives.Pervasiveext open Xapi_support @@ -50,6 +49,8 @@ let delete_crashdump_dir filename = (ExnHelper.string_of_exn e) ; raise e +let fields_of = Astring.(String.fields ~empty:false ~is_sep:Char.Ascii.is_white) + (* Called once on host boot to resync the crash directory with the database *) let resynchronise ~__context ~host = debug "Xapi_host_crashdump.resynchronise" ; @@ -103,9 +104,7 @@ let resynchronise ~__context ~host = debug "Adding record corresponding to new crashdump %s" filename ; let cmd = Printf.sprintf "%s --bytes -s %s/%s" du crash_dir filename in let size = - match - Xstringext.String.(split_f isspace (Helpers.get_process_output cmd)) - with + match fields_of (Helpers.get_process_output cmd) with | size :: _ -> Int64.of_string size | _ -> diff --git a/ocaml/xapi/xapi_pif.ml b/ocaml/xapi/xapi_pif.ml index 0e730bda514..ccebf243816 100644 --- a/ocaml/xapi/xapi_pif.ml +++ b/ocaml/xapi/xapi_pif.ml @@ -19,7 +19,6 @@ module L = Debug.Make (struct let name = "license" end) open Xapi_database.Db_filter_types module Listext = Xapi_stdext_std.Listext.List -module Stringext = Xapi_stdext_std.Xstringext.String module Date = Clock.Date open Network @@ -709,6 +708,8 @@ let forget ~__context ~self = let scan_m = Mutex.create () +let fields_of = Astring.(String.fields ~empty:false ~is_sep:Char.Ascii.is_white) + let scan ~__context ~host = let dbg = Context.string_of_task __context in refresh_all ~__context ~host ; @@ -724,9 +725,9 @@ let scan ~__context ~host = debug "No boot from SAN interface found" ; ([], []) | m :: u :: _ -> - Stringext.(split_f isspace m, split_f isspace u) + (fields_of m, fields_of u) | m :: _ -> - Stringext.(split_f isspace m, []) + (fields_of m, []) with e -> warn "Error when executing script %s: %s; ignoring" !Xapi_globs.non_managed_pifs diff --git a/ocaml/xapi/xha_interface.ml b/ocaml/xapi/xha_interface.ml index a42107a63a6..dee90350575 100644 --- a/ocaml/xapi/xha_interface.ml +++ b/ocaml/xapi/xha_interface.ml @@ -349,9 +349,10 @@ module LiveSetInformation = struct | Some u -> u in - let set f x = - List.map f Xapi_stdext_std.Xstringext.String.(split_f isspace x) + let fields_of = + Astring.(String.fields ~empty:false ~is_sep:Char.Ascii.is_white) in + let set f x = List.map f (fields_of x) in Some { id= uuid (find "HostID") From aebedca1bd722bfe1a6855ab28c7b50e4255f06e Mon Sep 17 00:00:00 2001 From: Pau Ruiz Safont Date: Wed, 22 May 2024 10:48:06 +0100 Subject: [PATCH 8/8] xapi-stdext-std: change String.replace to replace characters The few users that needed to replace strings, have been replaced with Astring's cuts, as most of them were already segmenting strings, or they are run in very specific, infrequent codepaths for efficiency to not matter. Others have been replaced by Astring's filter as they were removing characters, and the rest have been converted to the new String.replace. map_unlikely can be removed from the interface and only have String.replaced and String.replace Signed-off-by: Pau Ruiz Safont Signed-off-by: Pau Ruiz Safont --- ocaml/idl/ocaml_backend/gen_rbac.ml | 2 +- .../lib/xapi-stdext-std/xstringext.ml | 45 +++---------------- .../lib/xapi-stdext-std/xstringext.mli | 10 ++--- ocaml/rrd2csv/src/rrd2csv.ml | 9 +--- ocaml/xapi/audit_log.ml | 8 +--- ocaml/xapi/extauth_plugin_ADpbis.ml | 17 ++++--- ocaml/xapi/pciops.ml | 3 +- ocaml/xapi/pvs_proxy_control.ml | 4 +- ocaml/xapi/rbac_audit.ml | 4 +- ocaml/xapi/storage_mux.ml | 3 +- 10 files changed, 32 insertions(+), 73 deletions(-) diff --git a/ocaml/idl/ocaml_backend/gen_rbac.ml b/ocaml/idl/ocaml_backend/gen_rbac.ml index 6934d691a3f..ad17e10db5f 100644 --- a/ocaml/idl/ocaml_backend/gen_rbac.ml +++ b/ocaml/idl/ocaml_backend/gen_rbac.ml @@ -72,7 +72,7 @@ let permission_description = "A basic permission" let permission_name wire_name = let s1 = replace_char (Printf.sprintf "permission_%s" wire_name) '.' '_' in let s2 = replace_char s1 '/' '_' in - let s3 = Xapi_stdext_std.Xstringext.String.replace "*" "WILDCHAR" s2 in + let s3 = Xapi_stdext_std.Xstringext.String.replace '*' ~by:"WILDCHAR" s2 in replace_char s3 ':' '_' let permission_index = ref 0 diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml index 1c205b31faa..854245b9b6d 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.ml @@ -32,46 +32,6 @@ module String = struct else s - (** find all occurences of needle in haystack and return all their respective index *) - let find_all needle haystack = - let m = String.length needle and n = String.length haystack in - if m > n then - [] - else - let i = ref 0 and found = ref [] in - while !i < n - m + 1 do - if String.sub haystack !i m = needle then ( - found := !i :: !found ; - i := !i + m - ) else - incr i - done ; - List.rev !found - - (* replace all @f substring in @s by @t *) - let replace f t s = - let indexes = find_all f s in - let n = List.length indexes in - if n > 0 then ( - let len_f = String.length f and len_t = String.length t in - let new_len = String.length s + (n * len_t) - (n * len_f) in - let new_b = Bytes.make new_len '\000' in - let orig_offset = ref 0 and dest_offset = ref 0 in - List.iter - (fun h -> - let len = h - !orig_offset in - Bytes.blit_string s !orig_offset new_b !dest_offset len ; - Bytes.blit_string t 0 new_b (!dest_offset + len) len_t ; - orig_offset := !orig_offset + len + len_f ; - dest_offset := !dest_offset + len + len_t - ) - indexes ; - Bytes.blit_string s !orig_offset new_b !dest_offset - (String.length s - !orig_offset) ; - Bytes.unsafe_to_string new_b - ) else - s - let map_unlikely s f = let changed = ref false in let m = ref 0 in @@ -92,5 +52,10 @@ module String = struct ) else s + let replace char ~by s = + let replaceable = Stdlib.Char.equal char in + let get_replacement c = if replaceable c then Some by else None in + map_unlikely s get_replacement + let replaced ~replace s = map_unlikely s replace end diff --git a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli index e2ba23e0139..62a1053d883 100644 --- a/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli +++ b/ocaml/libs/xapi-stdext/lib/xapi-stdext-std/xstringext.mli @@ -17,18 +17,16 @@ module String : sig and when it returns [Some rep] the character is replaced with [rep] in the resulting string *) + val replace : char -> by:string -> string -> string + (** [replace ch ~by s] replaces all the occurrences of [ch] in [s] by [~by] + *) + val split : limit:int -> char -> string -> string list (** split a string on a single char *) val rtrim : string -> string (** FIXME document me|remove me if similar to strip *) - val replace : string -> string -> string -> string - (** replace all [f] substring in [s] by [t] *) - - val map_unlikely : string -> (char -> string option) -> string - (** map a string trying to fill the buffer by chunk *) - val sub_to_end : string -> int -> string (** a substring from the specified position to the end of the string *) end diff --git a/ocaml/rrd2csv/src/rrd2csv.ml b/ocaml/rrd2csv/src/rrd2csv.ml index 1cfadb61983..bb57fbbb8d3 100644 --- a/ocaml/rrd2csv/src/rrd2csv.ml +++ b/ocaml/rrd2csv/src/rrd2csv.ml @@ -185,14 +185,7 @@ module Ds_selector = struct let escape_metric s = let quote s = Printf.sprintf "\"%s\"" s in if String.contains s '"' then - quote - (Xstringext.String.map_unlikely s (function - | '\"' -> - Some "\"\"" - | _ -> - None - ) - ) + quote (Xstringext.String.replace '"' ~by:{|""|} s) else if String.contains s ',' || String.contains s '\n' then quote s else diff --git a/ocaml/xapi/audit_log.ml b/ocaml/xapi/audit_log.ml index 0563b2c4fe3..473df72f39e 100644 --- a/ocaml/xapi/audit_log.ml +++ b/ocaml/xapi/audit_log.ml @@ -102,12 +102,8 @@ let transfer_all_audit_files fd_out ?filter since = atransfer_try_gz "" (* map the ISO8601 timestamp format into the one in our logs *) -let log_timestamp_of_iso8601 iso8601_timestamp = - let module Xstringext = Xapi_stdext_std.Xstringext in - let step1 = iso8601_timestamp in - let step2 = Xstringext.String.replace "-" "" step1 in - let step3 = Xstringext.String.replace "Z" "" step2 in - step3 +let log_timestamp_of_iso8601 iso8601 = + Astring.String.filter (function '-' | 'Z' -> false | _ -> true) iso8601 (* Assume that RBAC access for the session_id already verified by xapi_http.ml diff --git a/ocaml/xapi/extauth_plugin_ADpbis.ml b/ocaml/xapi/extauth_plugin_ADpbis.ml index dac47414b33..b57b2c91cae 100644 --- a/ocaml/xapi/extauth_plugin_ADpbis.ml +++ b/ocaml/xapi/extauth_plugin_ADpbis.ml @@ -132,9 +132,11 @@ let match_error_tag (lines : string list) = let extract_sid_from_group_list group_list = List.map (fun (_, v) -> - let v = Stringext.replace ")" "" v in - let v = Stringext.replace "sid =" "|" v in - let vs = Astring.String.cuts ~empty:false ~sep:"|" v in + let vs = + Astring.String.filter (function ')' -> false | _ -> true) v + |> Astring.String.cuts ~empty:false ~sep:"sid =" + |> List.concat_map (Astring.String.cuts ~empty:false ~sep:"|") + in let sid = String.trim (List.nth vs 1) in debug "extract_sid_from_group_list get sid=[%s]" sid ; sid @@ -167,7 +169,8 @@ module AuthADlw : Auth_signature.AUTH_MODULE = struct Locking_helpers.Named_mutex.create "IS_SERVER_AVAILABLE" let splitlines s = - Astring.String.cuts ~empty:false ~sep:"\n" (Stringext.replace "#012" "\n" s) + Astring.String.cuts ~empty:false ~sep:"#012" s + |> List.concat_map (Astring.String.cuts ~empty:false ~sep:"\n") let pbis_common_with_password (password : string) (pbis_cmd : string) (pbis_args : string list) = @@ -349,7 +352,7 @@ module AuthADlw : Auth_signature.AUTH_MODULE = struct if !exited_code <> 0 then ( error "execute '%s': exit_code=[%d] output=[%s]" debug_cmd !exited_code - (Stringext.replace "\n" ";" !output) ; + (Stringext.replace '\n' ~by:";" !output) ; let split_to_words s = Astring.String.fields ~empty:false ~is_sep:is_word_sep s in @@ -1115,8 +1118,8 @@ module AuthADlw : Auth_signature.AUTH_MODULE = struct in debug "execute %s: stdout=[%s],stderr=[%s]" pbis_force_domain_leave_script - (Stringext.replace "\n" ";" output) - (Stringext.replace "\n" ";" stderr) + (Stringext.replace '\n' ~by:";" output) + (Stringext.replace '\n' ~by:";" stderr) with e -> debug "exception executing %s: %s" pbis_force_domain_leave_script (ExnHelper.string_of_exn e) diff --git a/ocaml/xapi/pciops.ml b/ocaml/xapi/pciops.ml index 2126185474e..46cfdf377cc 100644 --- a/ocaml/xapi/pciops.ml +++ b/ocaml/xapi/pciops.ml @@ -126,7 +126,8 @@ let _unhide_pci ~__context pci = Printf.sprintf "(%s)" (Db.PCI.get_pci_id ~__context ~self:pci) in let new_value = - Xapi_stdext_std.Xstringext.String.replace bdf_paren "" raw_value + Astring.String.cuts ~empty:false ~sep:bdf_paren raw_value + |> String.concat "" in let cmd = match new_value with diff --git a/ocaml/xapi/pvs_proxy_control.ml b/ocaml/xapi/pvs_proxy_control.ml index 8597166fe7b..8a64cb2c051 100644 --- a/ocaml/xapi/pvs_proxy_control.ml +++ b/ocaml/xapi/pvs_proxy_control.ml @@ -21,7 +21,9 @@ open D let proxy_port_name vif = (* Interface names in Linux are at most 15 characters. We derive a name from the MAC address to ensure uniqueness, and make it fit. *) - let mac = Xapi_stdext_std.Xstringext.String.replace ":" "" vif.API.vIF_MAC in + let mac = + Astring.String.filter (function ':' -> false | _ -> true) vif.API.vIF_MAC + in Printf.sprintf "pvs%s" mac (** [proxies] returns all currently attached proxies *) diff --git a/ocaml/xapi/rbac_audit.ml b/ocaml/xapi/rbac_audit.ml index d0f94f6775b..7f86ba31030 100644 --- a/ocaml/xapi/rbac_audit.ml +++ b/ocaml/xapi/rbac_audit.ml @@ -453,9 +453,9 @@ let audit_line_of __context session_id allowed_denied ok_error result_error ?sexpr_of_args action permission ) in - let line = Xapi_stdext_std.Xstringext.String.replace "\n" " " _line in + let line = Xapi_stdext_std.Xstringext.String.replace '\n' ~by:" " _line in (* no \n in line *) - let line = Xapi_stdext_std.Xstringext.String.replace "\r" " " line in + let line = Xapi_stdext_std.Xstringext.String.replace '\r' ~by:" " line in (* no \r in line *) let audit_line = append_line "%s" line in (*D.debug "line=%s, audit_line=%s" line audit_line;*) diff --git a/ocaml/xapi/storage_mux.ml b/ocaml/xapi/storage_mux.ml index ac8b0680f43..f2091c896d0 100644 --- a/ocaml/xapi/storage_mux.ml +++ b/ocaml/xapi/storage_mux.ml @@ -97,7 +97,8 @@ module Mux = struct let m = Mutex.create () - let filename_of dp = Xapi_stdext_std.Xstringext.String.replace "/" "-" dp + let filename_of dp = + Xapi_stdext_std.Xstringext.String.replace '/' ~by:"-" dp let write dp info = let filename = filename_of dp in