+ (** apply a transformation "string list -> string list" to file lines *)
+let mangle_file ~fname f =
+ let ic = open_in fname in
+ let lines = Zack.input_lines ic in
+ close_in ic;
+ let oc = open_out fname in
+ Zack.output_lines (f lines) oc;
+ close_out oc
+;;
+
+let add_line ~fname ?position line =
+ mangle_file ~fname
+ (fun lines ->
+ match position with
+ | None -> lines @ [line]
+ | Some i ->
+ assert (i >= 0);
+ let rec add_after i = function
+ | (acc, []) -> acc @ [line] (* eof *)
+ | (acc, ((hd::tl) as l)) ->
+ if i = 0 then
+ acc @ [line] @ l
+ else
+ add_after (i-1) (acc @ [hd], tl)
+ in
+ add_after i ([], lines))
+;;
+
+let remove_line ~fname position =
+ mangle_file ~fname
+ (fun lines ->
+ assert (position >= 0);
+ let rec remove i = function
+ | (acc, []) -> acc (* eof *)
+ | (acc, ((hd::tl) as l)) ->
+ if i = 0 then
+ acc @ tl
+ else
+ remove (i-1) (acc @ [hd], tl)
+ in
+ remove position ([], lines))
+;;
+
+let is_blank_line =
+ let blank_line_RE = Pcre.regexp "(^#)|(^\\s*$)" in
+ fun line ->
+ Pcre.pmatch ~rex:blank_line_RE line
+;;
+