Plasma GitLab Archive
Projects Blog Knowledge

(*
 * <COPYRIGHT>
 * Copyright 2002 Joachim Schrod Network and Publication Consultance GmbH,
 *                Gerd Stolpmann
 *
 * <GPL>
 * This file is part of WDialog.
 *
 * WDialog is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * WDialog is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with WDialog; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * </>
 *)

(* $Id: stubs.ml,v 3.4 2002-02-28 22:55:10 stolpmann Exp $
 * ----------------------------------------------------------------------
 *
 *)

open Wd_types;;
open Perlvalues;;

(* NOTE: We still use the old names here. The term "uiobject" has the
 * same meaning as "dialog".
 *)

(* Perl reference counters: The procedure call conventions are as follows:
 *
 * - Arguments: It is the responsibility of the callee to increase the
 *   counter if another reference to the value is created. If you simply
 *   read the value of the argument, it is not necessary to increase the
 *   counter. If you put the value into a variable that survives the call,
 *   the counter must be increased. This is also necessary if you simply return
 *   the argument to the caller.
 *   It is the responsibility of the caller to decrease the counter if
 *   the reference is freed.
 * - Result values: It is the responsibility of the caller to decrease the
 *   counter if the referencing variable is freed.
 *   It is the responsibility of the callee to increase the counter if
 *   values are extracted from variables that survive the call.
 *   Note: the newSV* functions create new values with a counter of 1, so
 *   if you pass them back as result you need not to first increase the
 *   counter.
 *)

let empty_universe() =
  new Wd_universe.universe
    (new Wd_application.application
       (new Pxp_dtd.dtd
	  (new Pxp_types.drop_warnings)
	  `Enc_iso88591
       ))
;;

let global_universe = ref (empty_universe()) ;;
  (* The universe the Perl script uses. It will be initialized later *)

let global_universe_ready = ref false;;
  (* Will be set to [true] when [global_universe] is initialized *)

let global_universe_deferred_registrations = ref [] ;;
  (* Deferred [register] invocations for [global_universe] *)

let check_init() =
  (* Call this function every time you access [global_universe] *)
  if not !global_universe_ready then
    failwith "WDialog is not yet initialized" ;;

let global_env = ref None ;;
  (* The environment of the current CGI request. This variable is initialized
   * by the class [special_universe] below. Okay, it's a trick.
   *)


let get_global_env() =
  match !global_env with
      None -> assert false
    | Some e -> e
;;


let global_cgi = ref None ;;
  (* The current CGI activation *)


class special_universe app =
  object
    inherit Wd_universe.universe app as super
    method create env name =
      global_env := Some env;
      super # create env name
  end
;;


let uiobjects_list = ref [];;
let uiobjects_array = ref None;;
let uiobjects_number = ref 0;;
let uiobjects_offset = ref 0;;
  (* The dialog objects that are referenced by Perl code. As reference
   * an int is used. uiobjects_number contains the next free int.
   * uiobjects_array contains the same as uiobjects_list, or None,
   * if it is not yet initialized.
   *)


let get_uiobj k =
  (* Get the uiobject for an ID *)
  begin match !uiobjects_array with
      None ->
	uiobjects_array := Some(Array.of_list(List.rev !uiobjects_list))
    | Some a ->
	()
  end;
  begin match !uiobjects_array with
      None ->
	assert false
    | Some a ->
	let n = k - !uiobjects_offset in
	if n >= 0 && n < Array.length a then
	  fst(a.(n))
	else
	  assert false
  end
;;


let get_perlobj obj =
  (* Get the Perl object of an uiobject, or raise Not_found *)
  List.assoc obj !uiobjects_list
;;


class perl_uiobject init_prepare_closure_sv init_handle_closure_sv
                    init_self_sv
		    universe name env
  =
  object (self)
    inherit Wd_dialog.dialog universe name env
    val prepare_closure_sv = (init_prepare_closure_sv : scalar_value)
    val handle_closure_sv  = (init_handle_closure_sv  : scalar_value)
    val self_sv            = (init_self_sv            : scalar_value)

    method prepare_page() =
      pl_callback_1arg_noresult prepare_closure_sv self_sv;


    method handle() =
      let sv = pl_callback_1arg_scalar handle_closure_sv self_sv in
      (* The return value is either 'undef' or the ID of the next object *)
      if x_sviok sv then begin
	let k = x_sviv sv in
	let obj' = get_uiobj k in
	svREFCNT_dec sv;
	raise (Change_dialog obj')
      end

    (* WDialog never calls the [copy] method, so nobody calls it, so it is
     * not necessary to redefine it here. (We would have to copy the Perl
     * object, too.)
     *)
    method copy = assert false

  end
;;


let make_string_sv s =
  newSVpvn s (String.length s)
;;


let dest_string_sv sv =
  fst(x_svpv sv)
;;


let array_of_av av =
  let l = av_len av + 1 in
  let init_sv = newSViv 0 in
  let a = Array.create l init_sv in
  for k = 0 to l-1 do
    a.(k) <-
      match av_fetch av k 0 with
	  None -> assert false
	| Some x -> x
  done;
  svREFCNT_dec init_sv;
  a
;;


let obj_id x =
  string_of_int (Obj.obj ( Obj.field (Obj.repr x) 1 ) : int)
;;

let finalize_sv sv =
(* DEBUG *)
(* ( match svREFCNT sv with
	0 -> prerr_endline ("Finalize: refcnt already 0 ???");
      | 1 -> prerr_endline ("Finalize: expected");
      | n -> prerr_endline ("Finalize: refcnt = " ^ string_of_int n)
  );
*)
  svREFCNT_dec sv
;;


let perl_universe_register name_sv prepare_closure_sv handle_closure_sv
                           create_closure_sv
  =
  (* Increment the ref counters because we store these values permanently in OCaml objects.
   * The finalisers will decrement the counters automatically if the values are no longer
   * reachable from OCaml.
   *)
  ignore(svREFCNT_inc(prepare_closure_sv));
  ignore(svREFCNT_inc(handle_closure_sv));
  ignore(svREFCNT_inc(create_closure_sv));
  Gc.finalise finalize_sv prepare_closure_sv;
  Gc.finalise finalize_sv handle_closure_sv;
  Gc.finalise finalize_sv create_closure_sv;

  let name, _ = x_svpv name_sv in

  let obj_creator universe name env =
    let id = !uiobjects_number in
    incr uiobjects_number;
    let id_sv = newSViv id in
    let self_sv = pl_callback_1arg_scalar create_closure_sv id_sv in
    svREFCNT_dec id_sv;
    Gc.finalise finalize_sv self_sv;
    let obj = new perl_uiobject prepare_closure_sv handle_closure_sv self_sv
	 	    universe name env in
    uiobjects_list := (obj,self_sv) :: !uiobjects_list;
    uiobjects_array := None;
    obj
  in

  (* If [global_universe] is not yet initialized, simply put the arguments of [register]
   * into [global_universe_deferred_registrations] - these [register] calls will be done
   * later. This makes it possible that Perl code can register dialogs before the rest
   * of the module is initialized.
   *)
  if !global_universe_ready then
    !global_universe # register name obj_creator
  else
    global_universe_deferred_registrations :=
      (name, obj_creator) :: !global_universe_deferred_registrations;

  newSViv 1
;;


let perl_universe_create name_sv =
  check_init();
  let name, _ = x_svpv name_sv in
  let obj = !global_universe # create (get_global_env()) name in
  let sv =
    try get_perlobj obj
    with Not_found ->
      failwith("WDialog(perl_universe_create): Cannot return the perl object of a non-Perl dialog object")
  in
  (* Because this sv is just another pointer, increment the counter *)
  ignore(svREFCNT_inc(sv));
  sv
;;


let perl_uiobject_name descr_sv =
  let obj = get_uiobj (x_sviv descr_sv) in
  make_string_sv(obj # name)
;;


let perl_uiobject_page_name descr_sv =
  let obj = get_uiobj (x_sviv descr_sv) in
  make_string_sv(obj # page_name)
;;


let perl_uiobject_next_page descr_sv =
  let obj = get_uiobj (x_sviv descr_sv) in
  make_string_sv(obj # next_page)
;;


let perl_uiobject_set_next_page descr_sv pg_sv =
  let obj = get_uiobj (x_sviv descr_sv) in
  let pg, _ = x_svpv pg_sv in
  obj # set_next_page pg;
  newSViv 1
;;


let av_make_dec elements =
  (* Because av_make copies the passed array of elements
   * the counter of the elements should be decremented
   *)
  let av = av_make (Array.length elements) elements in
  Array.iter
    (fun el -> ignore(svREFCNT_dec el))
    elements;
  av
;;


let perl_uiobject_page_names descr_sv =
  let obj = get_uiobj (x_sviv descr_sv) in
  let l = obj # page_names in
  let a = Array.of_list l in
  let av = av_make_dec
	     (Array.map make_string_sv a) in
  newRV_noinc_from_av av
;;


let perl_uiobject_variable descr_sv name_sv =
  let rec make_UI_Variable v =
    match v with
      	String_value s ->
	  let a =
	    [| make_string_sv "UI::Variable::String";
	       make_string_sv s
	    |] in
	  newRV_noinc_from_av (av_make_dec a)
      | Enum_value l ->
	  let a =
	    Array.of_list
	      ((make_string_sv "UI::Variable::Enum")
	       :: (List.map make_string_sv l)) in
	  newRV_noinc_from_av (av_make_dec a)
      | Dyn_enum_value l ->
	  let l' =
	    List.map
	      (fun (intern,extern) ->
		 let intern' = make_string_sv intern in
		 let extern' = make_string_sv extern in
		 newRV_noinc_from_av (av_make_dec [| intern'; extern' |]))
	      l
	  in
	  let a =
	    Array.of_list
	      ((make_string_sv "UI::Variable::DynEnum")
	       :: l') in
	  newRV_noinc_from_av (av_make_dec a)
      | Dialog_value None ->
	  let a =
	    [| make_string_sv "UI::Variable::Dialog";
	       x_sv_undef();
	    |] in
	  newRV_noinc_from_av (av_make_dec a)
      | Dialog_value (Some obj) ->
	  let obj_sv =
	    try get_perlobj obj
	    with Not_found ->
	      failwith("WDialog(perl_uiobject_variablt): Cannot return the perl object of a non-Perl dialog object")
	  in
	  ignore(svREFCNT_inc(obj_sv));
	  let a =
	    [| make_string_sv "UI::Variable::Dialog";
	       obj_sv
	    |] in
	  newRV_noinc_from_av (av_make_dec a)
      | Alist_value l ->
	  let l' =
	    List.map
	      (fun (key,value) ->
		 let key' = make_string_sv key in
		 let value' = make_UI_Variable value in
		 newRV_noinc_from_av (av_make_dec [| key'; value' |]))
	      l
	  in
	  let a =
	    Array.of_list
	      ((make_string_sv "UI::Variable::Alist")
	       :: l') in
	  newRV_noinc_from_av (av_make_dec a)
      | _ ->
	  failwith "perl_uiobject_variable"
  in
  let obj = get_uiobj (x_sviv descr_sv) in
  let name, _ = x_svpv name_sv in
  make_UI_Variable (obj # variable name)
;;


let perl_uiobject_string_variable descr_sv name_sv =
  let obj = get_uiobj (x_sviv descr_sv) in
  let name, _ = x_svpv name_sv in
  make_string_sv(obj # string_variable name)
;;


(* Get variables of other types:
 * There is no real advantage for special stubs; use the general-purpose
 * perl_uiobject_variable instead.
 *)


let perl_uiobject_set_variable descr_sv name_sv repr_sv =
  let rec mkvalue r_sv =
    let get av n =
      let l = av_len av in
      if n < 0 or n > l then
	failwith "perl_uiobject_set_variable"
      else
      	match av_fetch av n 0 with
	    None ->
	      failwith "perl_uiobject_set_variable"
	  | Some x ->
	      x
    in
    let av = x_AvRV r_sv in
    let sv = get av 0 in
    let kind = x_sviv sv in
    if kind < 0 or kind > 4 then failwith "perl_uiobject_set_variable";
    match kind with
	0 ->
	  (* String *)
	  let rv = get av 1 in
	  String_value (dest_string_sv (x_SvRV rv))
      | 1 ->
	  (* Enum *)
	  let av1 = x_AvRV(get av 1) in
	  let a = array_of_av av1 in
	  Enum_value
	    (List.map dest_string_sv (Array.to_list a))
      | 2 ->
	  (* DynEnum *)
	  let av1 = x_AvRV(get av 1) in
	  let a = array_of_av av1 in
	  Dyn_enum_value
	    (List.map
	       (fun pair_rv ->
		  let pair_av = x_AvRV pair_rv in
		  dest_string_sv (get pair_av 0),
		  dest_string_sv (get pair_av 1))
	       (Array.to_list a))
      | 3 ->
	  (* Dialog *)
	  let sv = get av 1 in
	  if x_sviok sv then begin
	    let id = x_sviv sv in
	    Dialog_value (Some (get_uiobj id))
	  end
	  else Dialog_value None
      | 4 ->
	  (* Alist *)
	  let av1 = x_AvRV(get av 1) in
	  let a = array_of_av av1 in
	  Alist_value
	    (List.map
	       (fun pair_rv ->
		  let pair_av = x_AvRV pair_rv in
		  dest_string_sv (get pair_av 0),
		  mkvalue (get pair_av 1))
	       (Array.to_list a))
      | _ ->
	  assert false
  in

  let obj = get_uiobj (x_sviv descr_sv) in
  let name, _ = x_svpv name_sv in
  let v =
    try
      mkvalue repr_sv
    with
      	Not_found -> failwith "perl_uiobject_set_variable"
  in
  obj # set_variable name v;
  newSViv 1
;;


let perl_uiobject_unset_variable descr_sv name_sv =
  let obj = get_uiobj (x_sviv descr_sv) in
  let name, _ = x_svpv name_sv in
  obj # unset_variable name;
  newSViv 1
;;


let perl_uiobject_set_string_variable descr_sv name_sv value_sv =
  let obj = get_uiobj (x_sviv descr_sv) in
  let name, _ = x_svpv name_sv in
  let value, _ = x_svpv value_sv in
  obj # set_variable name (String_value value);
  newSViv 1
;;


let perl_uiobject_event descr_sv =
  let obj = get_uiobj (x_sviv descr_sv) in
  let e = obj # event in
  let a =
    match e with
	Button s ->
	  [| "BUTTON"; s |]
      | Indexed_button(s,idx) ->
	  [| "INDEXED_BUTTON"; s; idx |]
      | Image_button(s,x,y) ->
	  [| "IMAGE_BUTTON"; s; string_of_int x; string_of_int y |]
      | Indexed_image_button(s,idx,x,y) ->
	  [| "INDEXED_IMAGE_BUTTON"; s; idx; string_of_int x; string_of_int y |]
      | No_event ->
	  [| "NO_EVENT" |]
      | Popup_request s ->
          [| "POPUP_REQUEST"; s |]
  in
  let av = av_make_dec
	     (Array.map make_string_sv a) in
  newRV_noinc_from_av av
;;


let perl_uiobject_set_event descr_sv e_sv =
  let obj = get_uiobj (x_sviv descr_sv) in
  let av = x_AvRV e_sv in
  let a = Array.map dest_string_sv (array_of_av av) in
  begin match a with
      [| "BUTTON"; s |] ->
	obj # set_event (Button s)
    | [| "INDEXED_BUTTON"; s; idx |] ->
	obj # set_event (Indexed_button(s,idx));
    | [| "IMAGE_BUTTON"; s; x; y |] ->
	obj # set_event (Image_button(s,int_of_string x,int_of_string y));
    | [| "INDEXED_IMAGE_BUTTON"; s; idx; x; y |] ->
	obj # set_event (Indexed_image_button
			   (s,idx,int_of_string x,int_of_string y));
    | [| "NO_EVENT" |] ->
	obj # set_event No_event;
    | [| "POPUP_REQUEST"; s |] ->
	obj # set_event (Popup_request s);
    | _ ->
	failwith "perl_uiobject_set_event"
  end;
  newSViv 1
;;


let perl_uiobject_init descr_sv page_sv =
  let obj = get_uiobj (x_sviv descr_sv) in
  let page, _ = x_svpv page_sv in
  obj # init page;
  newSViv 1
;;


let perl_uiobject_upload_filename descr_sv name_sv =
  let obj = get_uiobj (x_sviv descr_sv) in
  let name = dest_string_sv name_sv in
  try
    let argopt = obj # lookup_uploaded_file name in    (* or raise Not_found *)
    match argopt with
	None -> make_string_sv ""
      | Some arg ->
	  begin match arg # filename with
	      None   -> make_string_sv ""
	    | Some x -> make_string_sv x
	  end
  with
	Not_found -> make_string_sv ""
;;


let perl_uiobject_upload_mimetype descr_sv name_sv =
  let obj = get_uiobj (x_sviv descr_sv) in
  let name = dest_string_sv name_sv in
  try
    let argopt = obj # lookup_uploaded_file name in    (* or raise Not_found *)
    match argopt with
	None -> make_string_sv ""
      | Some arg ->
	  make_string_sv (arg # content_type)
  with
      Not_found -> make_string_sv ""
;;


let perl_uiobject_upload_sysname descr_sv name_sv =
  let obj = get_uiobj (x_sviv descr_sv) in
  let name = dest_string_sv name_sv in
  try
    let argopt = obj # lookup_uploaded_file name in    (* or raise Not_found *)
    match argopt with
	None -> make_string_sv ""
      | Some arg ->
	  begin match arg # store with
	      `Memory -> make_string_sv ""
	    | `File x -> make_string_sv x
	  end
  with
	Not_found -> make_string_sv ""
;;


(* ---------------------------------------------------------------------- *)

type tt =
    Tree of Wd_template.tree
  | Tmpl of Wd_template.template
;;

let tt_list = ref [];;
let tt_array = ref None;;
let tt_number = ref 0;;
let tt_offset = ref 0


let perl_template_get name_sv =
  check_init();
  let name = dest_string_sv name_sv in
  let tmpl = Wd_template.get (!global_universe#application) name in
  tt_list := (Tmpl tmpl) :: !tt_list;
  tt_array := None;
  let k = !tt_number in
  incr tt_number;
  newSViv k
;;


let new_tree tr =
  tt_list := (Tree tr) :: !tt_list;
  tt_array := None;
  let k = !tt_number in
  incr tt_number;
  k
;;


let get_tt k =
  begin match !tt_array with
      None ->
	tt_array := Some(Array.of_list(List.rev !tt_list))
    | Some a ->
	()
  end;
  begin match !tt_array with
      None ->
	assert false
    | Some a ->
	let n = k - !tt_offset in
	if n >= 0 && n < Array.length a then
	  a.(n)
	else
	  assert false
  end
;;


(* CHANGE: new descr_sv *)
let perl_template_apply descr_sv tt_id_sv params_rv =
  let obj = get_uiobj (x_sviv descr_sv) in
  let tt = get_tt (x_sviv tt_id_sv) in
  match tt with
      Tmpl tmpl ->
	if x_svrok params_rv = 0 then
	  failwith "perl_template_apply";
	let hv = x_HvRV params_rv in
	let params = ref [] in
	ignore(hv_iterinit hv);
	begin try
	  while true do
	    let he = hv_iternext hv in    (* or raise Not_found *)
	    let key,_ = hv_iterkey he in
	    let rv = hv_iterval hv he in
	    if x_svrok rv = 0 then
	      failwith "perl_template_apply";
	    let id = x_sviv (x_SvRV rv) in
	    let tt_el = get_tt id in
	    match tt_el with
		Tmpl _ -> failwith "perl_template_apply";
	      | Tree tr ->
		  params := (key, tr) :: !params
	  done
	with
	    Not_found -> ()
	end;
	let result = Wd_template.apply obj tmpl !params in
	let k = new_tree result in
	newSViv k

    | Tree _ ->
	failwith "perl_template_apply"
;;

let perl_template_concat sep_sv args_rv =
  check_init();
  let sep_tt = get_tt (x_sviv sep_sv) in
  if x_svrok args_rv = 0 then
    failwith "perl_template_concat";
  let args_a = array_of_av (x_AvRV args_rv) in
  let args =
    List.map
      (fun rv ->
	 if x_svrok rv = 0 then
	   failwith "perl_template_apply";
	 let id = x_sviv (x_SvRV rv) in
	 let tt = get_tt id in
	 match tt with
	     Tmpl _ -> failwith "perl_template_concat"
	   | Tree tr -> tr
      )
      (Array.to_list args_a) in
  match sep_tt with
      Tmpl _ -> failwith "perl_template_concat"
    | Tree tr ->
	let result =
	  Wd_template.concat (!global_universe#application) tr args in
	let k = new_tree result in
	newSViv k
;;

let perl_template_empty dummy =
  check_init();
  let result = Wd_template.empty (!global_universe#application) in
  let k = new_tree result in
  newSViv k
;;

let perl_template_text sv =
  check_init();
  let result =
    Wd_template.text (!global_universe#application) (dest_string_sv sv) in
  let k = new_tree result in
  newSViv k
;;

let perl_template_html sv =
  check_init();
  let result =
    Wd_template.html (!global_universe#application) (dest_string_sv sv) in
  let k = new_tree result in
  newSViv k
;;

let perl_template_to_string descr_sv tr_sv =
  let obj = get_uiobj (x_sviv descr_sv) in
  let tt = get_tt (x_sviv tr_sv) in
  match tt with
      Tmpl _ -> failwith "perl_template_to_string"
    | Tree tr ->
	let s = Wd_template.to_string obj tr in
	make_string_sv s
;;

(* ---------------------------------------------------------------------- *)

let perl_cgi_param sv =
  let name = dest_string_sv sv in
  try
    let value =
      match !global_cgi with
	  None -> failwith "perl_cgi_param: CGI parameters not available"
	| Some cgi -> (cgi # argument name) # value in
    make_string_sv value
  with
      Not_found ->
	(* x_sv_undef() *)
	make_string_sv ""          (* TODO: Cannot return undef *)
;;



let collect_arguments = ref [];;
let use_collected_arguments = ref false;;

let perl_cgi_add_param name_sv value_sv =
  let name = dest_string_sv name_sv in
  let value = dest_string_sv value_sv in
  collect_arguments :=
      new Netcgi.simple_argument ~ro:true name value :: !collect_arguments;
  newSViv 1
;;


let perl_cgi_add_upload name_sv filename_sv mimetype_sv sysname_sv =
  let name = dest_string_sv name_sv in
  let filename = dest_string_sv filename_sv in
  let mimetype = dest_string_sv mimetype_sv in
  let sysname = dest_string_sv sysname_sv in
  let qfn_buffer = Buffer.create 128 in
  let qfn_ch = new Netchannels.output_buffer qfn_buffer in
  Mimestring.write_value qfn_ch [ Mimestring.QString filename ];
  let hdr = [ "Content-Type", mimetype;
	      "Content-Disposition", ("form-data; filename=" ^ Buffer.contents qfn_buffer)
	    ] in
  collect_arguments := new Netcgi.mime_argument
                         ~work_around_backslash_bug:false
                         name
			 (new Netmime.basic_mime_header ~ro:true hdr,
			  `Body (new Netmime.file_mime_body ~ro:true sysname))
                       :: !collect_arguments;
  newSViv 1
;;

let perl_cgi_set _ =
  use_collected_arguments := true;  (* this will remind us to use collect_arguments *)
  newSViv 1
;;


(* ---------------------------------------------------------------------- *)

let perl_reset dummy_sv =
  (* Forget the connections to Perl objects: *)
  uiobjects_offset := !uiobjects_number;
  uiobjects_list := [];
  uiobjects_array := None;
  tt_offset := !tt_number;
  tt_list := [];
  tt_array := None;
  collect_arguments := [];
  use_collected_arguments := false;
  global_universe_ready := false;
  global_universe := empty_universe();
  global_universe_deferred_registrations := [];
  global_env := None;
  global_cgi := None;

  (* DEBUG *)
(*  Gc.full_major();
  (* Output statistics: *)
  Gc.print_stat stdout;
*)
  newSViv 1
;;


let perl_setup uifile_sv =
  (* Set the ui file to parse, i.e. set global_universe *)

  let uifile = dest_string_sv uifile_sv in

  let app =
    if Filename.check_suffix uifile ".ui" then
      Wd_transform.parse_uiapplication uifile
    else if Filename.check_suffix uifile ".ui.bin" then
      Wd_transform.load_uiapplication uifile
    else
      failwith "perl_setup";
  in
  global_universe_ready := true;
  global_universe := new special_universe app;
    (* Use special_universe such that global_env will be initialized *)

  (* Do now the deferred registrations: *)
  List.iter
    (fun (name, create) ->
       !global_universe # register name create
    )
    (List.rev !global_universe_deferred_registrations);
  global_universe_deferred_registrations := [];

  newSViv 1
;;


let processing name header = `Automatic ;;
  (* Use the MIME header to decide whether to use `Memory or `File,
   * but not the parameter name
   *)
(*
  let upload = "upload_" in
  let l = String.length upload in
  if String.length name >= l && String.sub name 0 l = upload then
    `File
  else
    `Memory
;;
*)


let operating_type = Netcgi.buffered_transactional_optype;;


let process_request (cgi:Netcgi_types.cgi_activation)
                    error_closure_sv self_url_sv nocache_sv =
  check_init();
  let no_cache = x_sviv nocache_sv <> 0 in
  let self_url = dest_string_sv self_url_sv in

  let error_page estring =
    let sv = pl_callback_1arg_scalar error_closure_sv
	       (make_string_sv estring)
    in
    let out = dest_string_sv sv in
    svREFCNT_dec sv;
    out
  in

  begin try

    global_cgi := Some cgi;

    let cache =
    match cgi # request_method with
        `GET  -> `No_cache
      | `POST -> if no_cache then `No_cache else `Unspecified
      | _     -> assert false
    in

    cgi # set_header (*~fields:header*) ~cache ();

    Wd_cycle.process_request ~self_url !global_universe cgi;

  with
    exc ->
      cgi # output # rollback_work();
      cgi # set_header ~cache:`No_cache ();
      let s = error_page (Printexc.to_string exc) in
      cgi # output # output_string s;
  end;

  cgi # output # commit_work();
  cgi # finalize()
;;


let special_env() =
  let env = new Netcgi_env.custom_environment() in
  env # set_output_ch (new Netchannels.output_channel stdout);
  env # set_input_state `Received_body;
  env # setup_finished();
  (env :> Netcgi_env.cgi_environment)
;;


let perl_process_request error_closure_sv self_url_sv nocache_sv =
  let cgi =
    if !use_collected_arguments then
      let env = special_env() in
      new Netcgi.custom_activation ~env ~args:!collect_arguments ~meth:`POST ~operating_type ()
    else
      new Netcgi.std_activation ~processing ~operating_type ()
  in
  process_request cgi error_closure_sv self_url_sv nocache_sv;
  newSViv 1
;;


class my_output buf : Netchannels.trans_out_obj_channel =
  object
    inherit Netchannels.output_buffer buf
    val buf = buf

    method commit_work() = ()

    method rollback_work() = Buffer.clear buf
  end
;;


let perl_process_request_noprint error_closure_sv self_url_sv dummy_sv =
  let buf = Buffer.create 65536 in
  let operating_type =
    `Transactional (fun _ _ -> new my_output buf) in
  let cgi =
    if !use_collected_arguments then
      let env = special_env() in
      new Netcgi.custom_activation ~env ~args:!collect_arguments ~meth:`POST ~operating_type ()
    else
      new Netcgi.std_activation ~processing ~operating_type ()
  in
  cgi # environment # set_output_state `Sent_header;
    (* This prevents that netcgi sends the header *)
  process_request cgi error_closure_sv self_url_sv dummy_sv;
  make_string_sv (Buffer.contents buf)
;;


(* ---------------------------------------------------------------------- *)

let r1 name (f : scalar_value -> scalar_value) =
  Callback.register name f;;
let r2 name (f : scalar_value -> scalar_value -> scalar_value) =
  Callback.register name f;;
let r3 name (f : scalar_value -> scalar_value -> scalar_value -> scalar_value)
  =
  Callback.register name f;;
let r4 name (f : scalar_value -> scalar_value -> scalar_value -> scalar_value
		 -> scalar_value
	    )
  =
  Callback.register name f;;
let r5 name (f : scalar_value -> scalar_value -> scalar_value -> scalar_value
		 -> scalar_value -> scalar_value
	    )
  =
  Callback.register name f;;


r1 "perl_caml_reset"           perl_reset;
r1 "perl_setup"                perl_setup;
r3 "perl_process_request"      perl_process_request;  (* CHANGED *)
r3 "perl_process_request_noprint"  perl_process_request_noprint; (* CHANGED *)
r1 "perl_uiobject_name"        perl_uiobject_name;;
r1 "perl_uiobject_page_name"   perl_uiobject_page_name;;
r1 "perl_uiobject_page_names"  perl_uiobject_page_names;;
r1 "perl_uiobject_next_page"   perl_uiobject_next_page;;
r2 "perl_uiobject_set_next_page" perl_uiobject_set_next_page;;
r2 "perl_uiobject_variable"    perl_uiobject_variable;;
r2 "perl_uiobject_string_variable"  perl_uiobject_string_variable;;
r3 "perl_uiobject_set_variable" perl_uiobject_set_variable;;
r3 "perl_uiobject_set_string_variable"  perl_uiobject_set_string_variable;;
r2 "perl_uiobject_unset_variable" perl_uiobject_unset_variable;;
r1 "perl_uiobject_event"       perl_uiobject_event;;
r2 "perl_uiobject_set_event"   perl_uiobject_set_event;;
r2 "perl_uiobject_init"        perl_uiobject_init;;
r2 "perl_uiobject_upload_filename"  perl_uiobject_upload_filename;;
r2 "perl_uiobject_upload_mimetype"  perl_uiobject_upload_mimetype;;
r2 "perl_uiobject_upload_sysname"   perl_uiobject_upload_sysname;;
r4 "perl_universe_register"    perl_universe_register;  (* CHANGED *)
r1 "perl_universe_create"      perl_universe_create;;   (* CHANGED *)
r1 "perl_template_get"         perl_template_get;;
r3 "perl_template_apply"       perl_template_apply;;    (* CHANGED *)
r2 "perl_template_concat"      perl_template_concat;;
r1 "perl_template_empty"       perl_template_empty;;
r1 "perl_template_text"        perl_template_text;;
r1 "perl_template_html"        perl_template_html;;
r2 "perl_template_to_string"   perl_template_to_string;;
r1 "perl_cgi_param"            perl_cgi_param;;
r2 "perl_cgi_add_param"        perl_cgi_add_param;;
r4 "perl_cgi_add_upload"       perl_cgi_add_upload;;
r1 "perl_cgi_set"              perl_cgi_set;;

(* ======================================================================
 * History:
 *
 * $Log: stubs.ml,v $
 * Revision 3.4  2002-02-28 22:55:10  stolpmann
 * 	New: global_cgi stores the CGI activation object.
 *
 * Revision 3.3  2002/02/28 18:50:44  stolpmann
 * 	Continued with perlapi (lots of bugfixes)
 *
 * Revision 3.2  2002/02/14 16:24:13  stolpmann
 * 	Added copyright notice
 *
 * Revision 3.1  2002/02/12 23:11:25  stolpmann
 * 	Initial revision at sourceforge
 *
 * Revision 1.8  2002/01/22 17:35:32  gerd
 * 	Fixed a lot of memory leaks.
 *
 * Revision 1.7  2002/01/21 14:25:36  gerd
 * 	Changed for upcoming WDialog 2
 *
 * Revision 1.6  2000/12/21 15:03:26  gerd
 * 	Updated to support the Popup_request parameter.
 *
 * Revision 1.5  2000/12/06 17:53:36  gerd
 * 	Updated.
 *
 * Revision 1.4  2000/12/04 18:28:31  gerd
 * 	Added the Popup_request event.
 *
 * Revision 1.3  2000/09/21 15:12:30  gerd
 * 	Updated for O'Caml 3 and PXP
 *
 * Revision 1.2  2000/04/17 10:12:55  gerd
 * 	Improved file upload.
 * 	Furthermore, the traditional CGI.pm package can be used,
 * if the user prefers this.
 *
 * Revision 1.1  2000/04/13 17:42:53  gerd
 * 	Initial revision.
 *
 *
 *)

This web site is published by Informatikbüro Gerd Stolpmann
Powered by Caml