+ let rec aux stack key =
+ key_is_valid key;
+ if List.mem key stack then begin
+ let msg = (String.concat " -> " (List.rev stack)) ^ " -> " ^ key in
+ raise (Cyclic_definition msg)
+ end;
+ let registry_value = (* internal value *)
+ try
+ Some (Hashtbl.find registry key)
+ with Not_found -> None
+ in
+ let env_value = (* environment value *)
+ try
+ Some (Sys.getenv (env_var_of_key key))
+ with Not_found -> None
+ in
+ let value = (* resulting value *)
+ match (registry_value, env_value) with
+ | Some reg, Some env -> env
+ | Some reg, None -> reg
+ | None, Some env -> env
+ | None, None -> raise (Key_not_found key)
+ in
+ interpolate (key :: stack) value
+ and interpolate stack value =
+ Str.global_substitute interpolated_key_rex
+ (fun s ->
+ let matched = Str.matched_string s in
+ (* "$(var)" -> "var" *)
+ let key = String.sub matched 2 (String.length matched - 3) in
+ aux stack key)
+ value