Source

ocaml-pkgbuild / bashexpand.ml

Full commit
juster a4622fb 
juster 09947d5 








juster 632c202 
juster 09947d5 


juster 42c4021 
juster 09947d5 
juster 42c4021 

juster 09947d5 
juster 42c4021 
juster 81306fa 
juster 42c4021 


juster 81306fa 







juster 42c4021 
juster 81306fa 
juster 42c4021 
juster 81306fa 

juster 42c4021 

juster 81306fa 








juster 42c4021 
juster 81306fa 
juster 42c4021 
juster e2937f6 
juster 81306fa 






juster 09947d5 
juster e2937f6 
juster 42c4021 
juster 81306fa 
juster 42c4021 
juster 09947d5 
juster 42c4021 
juster 09947d5 










juster a4622fb 
juster e2937f6 
juster 09947d5 



juster 42c4021 
juster 09947d5 


juster 42c4021 
juster e2937f6 
juster 09947d5 






juster 42c4021 
juster 09947d5 
juster 42c4021 
juster 09947d5 






juster 42c4021 
juster 09947d5 
juster 42c4021 
juster 09947d5 



juster a4622fb 

juster 81306fa 
juster 42c4021 
open Bashparam
open Printf

module Bashexpand =
  struct

    (** Our error stores the index of the character where parsing failed. *)
    exception ExpandError       of int
    exception UnbalancedBracket of int

    (** Search and destroy parameters ($VARs) in a string. **)
    let parameter_expand str params =

      (* Recursive helper function for parameter_expand. *)
      let rec expand_at idx =

        (* Point expand_name to the index after a $. *)
        let rec expand_name idx =

          let expand_inbraces = function (idx, name) ->

            (* Similiar to expand_at. *)
            (* Expand everything until closing bracket. *)
            let rec expand_until_curly idx =
              try
                (* Look ahead for the next } and $. *)
                let brckidx = String.index_from str idx '}' in
                begin
                  try
                    let sigidx = String.index_from str idx '$' in
                    if sigidx > brckidx then raise Not_found
                    else
                      (* XXX: Copy/pasted from expand_at below. Refactor? *)
                      let donechunk = String.sub str idx (sigidx - idx) in
                      match expand_name (sigidx + 1)
                      with (nextidx, expanded) ->
                        (* Repeat because the bracket could be gone now. *)
                        match (expand_until_curly nextidx)
                        with (newidx, fin) ->
                          (newidx, donechunk ^ expanded ^ fin)
                  with Not_found ->
                    (* No $ was found or it comes after the closing bracket. *)
                    (brckidx + 1, String.sub str idx (brckidx - idx))
                end
              (* If no } was found we have a problem. *)
              with Not_found -> raise (ExpandError idx)
            in

            let expand_param_subst name idx =
              (* XXX: What about badly formed input? *)
              match expand_until_curly (idx + 1) with (newidx, subst) ->
                let pval = assoc_str name params in
                let expstr =
                  match str.[idx] with
                  | '-' -> if "" = pval then subst else pval
                  |  _  -> ""
                in (newidx, expstr)
            in

            match str.[idx] with
            | '}' -> (idx+1, assoc_str name params)
            | ':' -> expand_param_subst name (idx+1)
            |  _  -> raise Not_found
          in (* end of expand_inbraces *)

          let extract_name idx =
            if Str.string_match (Str.regexp "[a-zA-Z_-]+") str idx then
              (Str.match_end (), Str.matched_string str)
            else
              raise (ExpandError idx)
          in

          printf "*DBG* str=%s idx=%d\n" str idx ;
          
          match str.[idx] with
          | '$' ->
              begin
                try match expand_name (idx+1) with (newidx, name) ->
                  (newidx, assoc_str name params)
                with Invalid_argument(_) -> raise (ExpandError idx)
              end
          | '{' ->
              begin
                try expand_inbraces (expand_name (idx+1))
                with Invalid_argument(_) -> raise (UnbalancedBracket idx)
              end
          | _ ->
              match extract_name idx with (newidx, name) ->
                (newidx, assoc_str name params)
        in (* end of expand_name *)

        try
          let sigidx = String.index_from str idx '$' in
          begin
            try
              let donechunk = String.sub str idx (sigidx - idx) in
              match expand_name (sigidx+1)
              with (nextidx, expanded) ->
                donechunk ^ expanded ^ (expand_at nextidx)

            (* This exception means the $ is at the end of the string. *)
            with Invalid_argument(_) -> raise (ExpandError sigidx)
          end
        with Not_found ->
          (* There are no more $'s we are done. *)
          let len = String.length str in String.sub str idx (len - idx)
      in (* end of expand_at *)

      expand_at 0

  end

let _ =
  let paramslist = [ ("FOO", Param("BAR")) ;
                     ("BAR", Param("Hello, World!")) ] in
  print_endline (Bashexpand.parameter_expand
                   "Substitutions${BAZ:- IS WORKING}!" paramslist)